int ng_l2cap_lp_con_cfm(ng_l2cap_p l2cap, struct ng_mesg *msg) { ng_hci_lp_con_cfm_ep *ep = NULL; ng_l2cap_con_p con = NULL; int error = 0; /* Check message */ if (msg->header.arglen != sizeof(*ep)) { NG_L2CAP_ALERT( "%s: %s - invalid LP_ConnectCfm[Neg] message size\n", __func__, NG_NODE_NAME(l2cap->node)); error = EMSGSIZE; goto out; } ep = (ng_hci_lp_con_cfm_ep *) (msg->data); /* Check if we have requested/accepted this connection */ con = ng_l2cap_con_by_addr(l2cap, &ep->bdaddr); if (con == NULL) { NG_L2CAP_ERR( "%s: %s - unexpected LP_ConnectCfm event. Connection does not exist\n", __func__, NG_NODE_NAME(l2cap->node)); error = ENOENT; goto out; } /* Check connection state */ if (con->state != NG_L2CAP_W4_LP_CON_CFM) { NG_L2CAP_ALERT( "%s: %s - unexpected LP_ConnectCfm event. " \ "Invalid connection state, state=%d, con_handle=%d\n", __func__, NG_NODE_NAME(l2cap->node), con->state, con->con_handle); error = EINVAL; goto out; } /* * Looks like it is our confirmation. It is safe now to cancel * connection timer and notify upper layer. If timeout already * happened then ignore connection confirmation and let timeout * handle that. */ if ((error = ng_l2cap_lp_untimeout(con)) != 0) goto out; if (ep->status == 0) { con->state = NG_L2CAP_CON_OPEN; con->con_handle = ep->con_handle; ng_l2cap_lp_deliver(con); } else /* Negative confirmation - remove connection descriptor */ ng_l2cap_con_fail(con, ep->status); out: return (error); } /* ng_l2cap_lp_con_cfm */
int ng_l2cap_lp_con_req(ng_l2cap_p l2cap, bdaddr_p bdaddr) { struct ng_mesg *msg = NULL; ng_hci_lp_con_req_ep *ep = NULL; ng_l2cap_con_p con = NULL; int error = 0; /* Verify that we DO NOT have connection to the remote unit */ con = ng_l2cap_con_by_addr(l2cap, bdaddr); if (con != NULL) { NG_L2CAP_ALERT( "%s: %s - unexpected LP_ConnectReq event. " \ "Connection already exists, state=%d, con_handle=%d\n", __func__, NG_NODE_NAME(l2cap->node), con->state, con->con_handle); return (EEXIST); } /* Check if lower layer protocol is still connected */ if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) { NG_L2CAP_ERR( "%s: %s - hook \"%s\" is not connected or valid\n", __func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI); return (ENOTCONN); } /* Create and intialize new connection descriptor */ con = ng_l2cap_new_con(l2cap, bdaddr); if (con == NULL) return (ENOMEM); /* Create and send LP_ConnectReq event */ NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_REQ, sizeof(*ep), M_NOWAIT); if (msg == NULL) { ng_l2cap_free_con(con); return (ENOMEM); } ep = (ng_hci_lp_con_req_ep *) (msg->data); bcopy(bdaddr, &ep->bdaddr, sizeof(ep->bdaddr)); ep->link_type = NG_HCI_LINK_ACL; con->state = NG_L2CAP_W4_LP_CON_CFM; ng_l2cap_lp_timeout(con); NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->hci, NULL); if (error != 0) ng_l2cap_free_con(con); /* will remove timeout */ return (error); } /* ng_l2cap_lp_con_req */
int ng_l2cap_lp_discon_ind(ng_l2cap_p l2cap, struct ng_mesg *msg) { ng_hci_lp_discon_ind_ep *ep = NULL; ng_l2cap_con_p con = NULL; int error = 0; /* Check message */ if (msg->header.arglen != sizeof(*ep)) { NG_L2CAP_ALERT( "%s: %s - invalid LP_DisconnectInd message size\n", __func__, NG_NODE_NAME(l2cap->node)); error = EMSGSIZE; goto out; } ep = (ng_hci_lp_discon_ind_ep *) (msg->data); /* Check if we have this connection */ con = ng_l2cap_con_by_handle(l2cap, ep->con_handle); if (con == NULL) { NG_L2CAP_ERR( "%s: %s - unexpected LP_DisconnectInd event. " \ "Connection does not exist, con_handle=%d\n", __func__, NG_NODE_NAME(l2cap->node), ep->con_handle); error = ENOENT; goto out; } /* XXX Verify connection state -- do we need to check this? */ if (con->state != NG_L2CAP_CON_OPEN) { NG_L2CAP_ERR( "%s: %s - unexpected LP_DisconnectInd event. " \ "Invalid connection state, state=%d, con_handle=%d\n", __func__, NG_NODE_NAME(l2cap->node), con->state, con->con_handle); error = EINVAL; goto out; } /* * Notify upper layer and remove connection * Note: The connection could have auto disconnect timeout set. Try * to remove it. If auto disconnect timeout happened then ignore * disconnect indication and let timeout handle that. */ if (con->flags & NG_L2CAP_CON_AUTO_DISCON_TIMO) if ((error = ng_l2cap_discon_untimeout(con)) != 0) return (error); ng_l2cap_con_fail(con, ep->reason); out: return (error); } /* ng_l2cap_lp_discon_ind */
int ng_hci_lp_con_req(ng_hci_unit_p unit, item_p item, hook_p hook) { int link_type; if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) { NG_HCI_WARN( "%s: %s - unit is not ready, state=%#x\n", __func__, NG_NODE_NAME(unit->node), unit->state); NG_FREE_ITEM(item); return (ENXIO); } if (NGI_MSG(item)->header.arglen != sizeof(ng_hci_lp_con_req_ep)) { NG_HCI_ALERT( "%s: %s - invalid LP_ConnectReq message size=%d\n", __func__, NG_NODE_NAME(unit->node), NGI_MSG(item)->header.arglen); NG_FREE_ITEM(item); return (EMSGSIZE); } link_type = ((ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data))->link_type; switch(link_type){ case NG_HCI_LINK_ACL: return (ng_hci_lp_acl_con_req(unit, item, hook)); case NG_HCI_LINK_SCO: if (hook != unit->sco ) { NG_HCI_WARN( "%s: %s - LP_ConnectReq for SCO connection came from wrong hook=%p\n", __func__, NG_NODE_NAME(unit->node), hook); NG_FREE_ITEM(item); return (EINVAL); } return (ng_hci_lp_sco_con_req(unit, item, hook)); case NG_HCI_LINK_LE_PUBLIC: case NG_HCI_LINK_LE_RANDOM: return (ng_hci_lp_le_con_req(unit, item, hook, link_type)); default: panic("%s: link_type invalid.", __func__); } return (EINVAL); } /* ng_hci_lp_con_req */
int ng_hci_lp_enc_change(ng_hci_unit_con_p con, int status) { ng_hci_unit_p unit = con->unit; struct ng_mesg *msg = NULL; ng_hci_lp_enc_change_ep *ep = NULL; int error; if (con->link_type != NG_HCI_LINK_SCO) { if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) { NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_ENC_CHG, sizeof(*ep), M_NOWAIT); if (msg != NULL) { ep = (ng_hci_lp_enc_change_ep *) msg->data; ep->status = status; ep->link_type = con->link_type; ep->con_handle = con->con_handle; NG_SEND_MSG_HOOK(error, unit->node, msg, unit->acl, 0); } } else NG_HCI_INFO( "%s: %s - ACL hook not valid, hook=%p\n", __func__, NG_NODE_NAME(unit->node), unit->acl); } return (0); } /* ng_hci_lp_con_cfm */
int ng_l2cap_l2ca_cfg_ind(ng_l2cap_chan_p ch) { ng_l2cap_p l2cap = ch->con->l2cap; struct ng_mesg *msg = NULL; ng_l2cap_l2ca_cfg_ind_ip *ip = NULL; int error = 0; /* Check if upstream hook is connected and valid */ if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { NG_L2CAP_ERR( "%s: %s - Unable to send L2CA_ConfigInd message. " \ "Hook is not connected or valid, psm=%d\n", __func__, NG_NODE_NAME(l2cap->node), ch->psm); return (ENOTCONN); } /* Create and send L2CA_ConnectInd message */ NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_IND, sizeof(*ip), M_NOWAIT); if (msg == NULL) error = ENOMEM; else { ip = (ng_l2cap_l2ca_cfg_ind_ip *)(msg->data); ip->lcid = ch->scid; ip->omtu = ch->omtu; bcopy(&ch->iflow, &ip->iflow, sizeof(ip->iflow)); ip->flush_timo = ch->flush_timo; NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); } return (error); } /* ng_l2cap_l2ca_cfg_ind */
int ng_l2cap_l2ca_cfg_rsp_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result) { ng_l2cap_p l2cap = ch->con->l2cap; struct ng_mesg *msg = NULL; ng_l2cap_l2ca_cfg_rsp_op *op = NULL; int error = 0; /* Check if upstream hook is connected and valid */ if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { NG_L2CAP_ERR( "%s: %s - unable to send L2CA_ConfigRsp response message. " \ "Hook is not connected or valid, psm=%d\n", __func__, NG_NODE_NAME(l2cap->node), ch->psm); return (ENOTCONN); } /* Create and send L2CA_ConfigRsp response message */ NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_RSP, sizeof(*op), M_NOWAIT); if (msg == NULL) error = ENOMEM; else { msg->header.token = token; msg->header.flags |= NGF_RESP; op = (ng_l2cap_l2ca_cfg_rsp_op *)(msg->data); op->result = result; NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); } return (error); } /* ng_l2cap_l2ca_cfg_rsp_rsp */
int ng_l2cap_l2ca_qos_ind(ng_l2cap_chan_p ch) { ng_l2cap_p l2cap = ch->con->l2cap; struct ng_mesg *msg = NULL; ng_l2cap_l2ca_qos_ind_ip *ip = NULL; int error = 0; /* Check if upstream hook is connected and valid */ if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { NG_L2CAP_ERR( "%s: %s - unable to send L2CA_QoSViolationInd message. " \ "Hook is not connected or valid, psm=%d\n", __func__, NG_NODE_NAME(l2cap->node), ch->psm); return (ENOTCONN); } /* Create and send L2CA_QoSViolationInd message */ NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_QOS_IND, sizeof(*ip), M_NOWAIT); if (msg == NULL) error = ENOMEM; else { ip = (ng_l2cap_l2ca_qos_ind_ip *)(msg->data); bcopy(&ch->con->remote, &ip->bdaddr, sizeof(ip->bdaddr)); NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); } return (error); } /* ng_l2cap_l2ca_qos_ind */
int ng_l2cap_lp_discon_ind(ng_l2cap_p l2cap, struct ng_mesg *msg) { ng_hci_lp_discon_ind_ep *ep = NULL; ng_l2cap_con_p con = NULL; int error = 0; /* Check message */ if (msg->header.arglen != sizeof(*ep)) { NG_L2CAP_ALERT( "%s: %s - invalid LP_DisconnectInd message size\n", __func__, NG_NODE_NAME(l2cap->node)); error = EMSGSIZE; goto out; } ep = (ng_hci_lp_discon_ind_ep *) (msg->data); /* Check if we have this connection */ con = ng_l2cap_con_by_handle(l2cap, ep->con_handle); if (con == NULL) { NG_L2CAP_ERR( "%s: %s - unexpected LP_DisconnectInd event. " \ "Connection does not exist, con_handle=%d\n", __func__, NG_NODE_NAME(l2cap->node), ep->con_handle); error = ENOENT; goto out; } /* XXX Verify connection state -- do we need to check this? */ if (con->state != NG_L2CAP_CON_OPEN) { NG_L2CAP_ERR( "%s: %s - unexpected LP_DisconnectInd event. " \ "Invalid connection state, state=%d, con_handle=%d\n", __func__, NG_NODE_NAME(l2cap->node), con->state, con->con_handle); error = EINVAL; goto out; } /* Notify upper layer and remove connection */ con->state = NG_L2CAP_CON_CLOSED; ng_l2cap_con_fail(con, ep->reason); out: return (error); } /* ng_l2cap_lp_discon_ind */
/* * Used for both data and control sockets */ static void ng_getsockaddr(netmsg_t msg) { struct socket *so = msg->sockaddr.base.nm_so; struct sockaddr **addr = msg->sockaddr.nm_nam; struct ngpcb *pcbp; struct sockaddr_ng *sg; int sg_len; int error = 0; /* Why isn't sg_data a `char[1]' ? :-( */ sg_len = sizeof(struct sockaddr_ng) - sizeof(sg->sg_data) + 1; pcbp = sotongpcb(so); if ((pcbp == NULL) || (pcbp->sockdata == NULL)) { /* XXXGL: can this still happen? */ error = EINVAL; goto replymsg; } mtx_lock(&pcbp->sockdata->mtx); if (pcbp->sockdata->node != NULL) { node_p node = pcbp->sockdata->node; int namelen = 0; /* silence compiler! */ if (NG_NODE_HAS_NAME(node)) sg_len += namelen = strlen(NG_NODE_NAME(node)); sg = kmalloc(sg_len, M_SONAME, M_WAITOK | M_ZERO); if (NG_NODE_HAS_NAME(node)) bcopy(NG_NODE_NAME(node), sg->sg_data, namelen); sg->sg_len = sg_len; sg->sg_family = AF_NETGRAPH; *addr = (struct sockaddr *)sg; mtx_unlock(&pcbp->sockdata->mtx); } else { mtx_unlock(&pcbp->sockdata->mtx); error = EINVAL; } replymsg: lwkt_replymsg(&msg->sockaddr.base.lmsg, error); }
int ng_l2cap_lp_qos_ind(ng_l2cap_p l2cap, struct ng_mesg *msg) { ng_hci_lp_qos_ind_ep *ep = NULL; ng_l2cap_con_p con = NULL; int error = 0; /* Check message */ if (msg->header.arglen != sizeof(*ep)) { NG_L2CAP_ALERT( "%s: %s - invalid LP_QoSViolation message size\n", __func__, NG_NODE_NAME(l2cap->node)); error = EMSGSIZE; goto out; } ep = (ng_hci_lp_qos_ind_ep *) (msg->data); /* Check if we have this connection */ con = ng_l2cap_con_by_handle(l2cap, ep->con_handle); if (con == NULL) { NG_L2CAP_ERR( "%s: %s - unexpected LP_QoSViolationInd event. " \ "Connection does not exist, con_handle=%d\n", __func__, NG_NODE_NAME(l2cap->node), ep->con_handle); error = ENOENT; goto out; } /* Verify connection state */ if (con->state != NG_L2CAP_CON_OPEN) { NG_L2CAP_ERR( "%s: %s - unexpected LP_QoSViolationInd event. " \ "Invalid connection state, state=%d, con_handle=%d\n", __func__, NG_NODE_NAME(l2cap->node), con->state, con->con_handle); error = EINVAL; goto out; } /* XXX FIXME Notify upper layer and terminate channels if required */ out: return (error); } /* ng_l2cap_qos_ind */
int ng_l2cap_l2ca_con_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result, u_int16_t status) { ng_l2cap_p l2cap = ch->con->l2cap; struct ng_mesg *msg = NULL; ng_l2cap_l2ca_con_op *op = NULL; int error = 0; /* Check if upstream hook is connected and valid */ if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { NG_L2CAP_ERR( "%s: %s - unable to send L2CA_Connect response message. " \ "Hook is not connected or valid, psm=%d\n", __func__, NG_NODE_NAME(l2cap->node), ch->psm); return (ENOTCONN); } /* Create and send L2CA_Connect response message */ NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON, sizeof(*op), M_NOWAIT); if (msg == NULL) error = ENOMEM; else { msg->header.token = token; msg->header.flags |= NGF_RESP; op = (ng_l2cap_l2ca_con_op *)(msg->data); /* * XXX Spec. says we should only populate LCID when result == 0 * What about PENDING? What the heck, for now always populate * LCID :) */ if(ch->scid == NG_L2CAP_ATT_CID){ op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT; op->lcid = ch->con->con_handle; }else if(ch->scid == NG_L2CAP_SMP_CID){ op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP; op->lcid = ch->con->con_handle; }else{ op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)? NG_L2CAP_L2CA_IDTYPE_BREDR : NG_L2CAP_L2CA_IDTYPE_LE; op->lcid = ch->scid; } op->encryption = ch->con->encryption; op->result = result; op->status = status; NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); } return (error); } /* ng_l2cap_l2ca_con_rsp */
int ng_hci_lp_con_req(ng_hci_unit_p unit, item_p item, hook_p hook) { if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) { NG_HCI_WARN( "%s: %s - unit is not ready, state=%#x\n", __func__, NG_NODE_NAME(unit->node), unit->state); NG_FREE_ITEM(item); return (ENXIO); } if (NGI_MSG(item)->header.arglen != sizeof(ng_hci_lp_con_req_ep)) { NG_HCI_ALERT( "%s: %s - invalid LP_ConnectReq message size=%d\n", __func__, NG_NODE_NAME(unit->node), NGI_MSG(item)->header.arglen); NG_FREE_ITEM(item); return (EMSGSIZE); } if (((ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data))->link_type == NG_HCI_LINK_ACL) return (ng_hci_lp_acl_con_req(unit, item, hook)); if (hook != unit->sco) { NG_HCI_WARN( "%s: %s - LP_ConnectReq for SCO connection came from wrong hook=%p\n", __func__, NG_NODE_NAME(unit->node), hook); NG_FREE_ITEM(item); return (EINVAL); } return (ng_hci_lp_sco_con_req(unit, item, hook)); } /* ng_hci_lp_con_req */
int ng_hci_command_timeout(ng_hci_unit_p unit) { if (unit->state & NG_HCI_UNIT_COMMAND_PENDING) panic( "%s: %s - Duplicated command timeout!\n", __func__, NG_NODE_NAME(unit->node)); unit->state |= NG_HCI_UNIT_COMMAND_PENDING; ng_callout(&unit->cmd_timo, unit->node, NULL, bluetooth_hci_command_timeout(), ng_hci_process_command_timeout, NULL, 0); return (0); } /* ng_hci_command_timeout */
int ng_hci_con_untimeout(ng_hci_unit_con_p con) { if (!(con->flags & NG_HCI_CON_TIMEOUT_PENDING)) panic( "%s: %s - No connection timeout!\n", __func__, NG_NODE_NAME(con->unit->node)); if (ng_uncallout(&con->con_timo, con->unit->node) == 0) return (ETIMEDOUT); con->flags &= ~NG_HCI_CON_TIMEOUT_PENDING; return (0); } /* ng_hci_con_untimeout */
int ng_hci_command_untimeout(ng_hci_unit_p unit) { if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) panic( "%s: %s - No command timeout!\n", __func__, NG_NODE_NAME(unit->node)); if (ng_uncallout(&unit->cmd_timo, unit->node) == 0) return (ETIMEDOUT); unit->state &= ~NG_HCI_UNIT_COMMAND_PENDING; return (0); } /* ng_hci_command_untimeout */
int ng_l2cap_l2ca_write_rsp(ng_l2cap_chan_p ch, u_int32_t token, u_int16_t result, u_int16_t length) { ng_l2cap_p l2cap = ch->con->l2cap; struct ng_mesg *msg = NULL; ng_l2cap_l2ca_write_op *op = NULL; int error = 0; /* Check if upstream hook is connected and valid */ if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { NG_L2CAP_ERR( "%s: %s - unable to send L2CA_WriteRsp message. " \ "Hook is not connected or valid, psm=%d\n", __func__, NG_NODE_NAME(l2cap->node), ch->psm); return (ENOTCONN); } /* Create and send L2CA_WriteRsp message */ NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_WRITE, sizeof(*op), M_NOWAIT); if (msg == NULL) error = ENOMEM; else { msg->header.token = token; msg->header.flags |= NGF_RESP; op = (ng_l2cap_l2ca_write_op *)(msg->data); op->result = result; op->length = length; if(ch->scid == NG_L2CAP_ATT_CID){ op->idtype = NG_L2CAP_L2CA_IDTYPE_ATT; op->lcid = ch->con->con_handle; }else if(ch->scid == NG_L2CAP_SMP_CID){ op->idtype = NG_L2CAP_L2CA_IDTYPE_SMP; op->lcid = ch->con->con_handle; }else{ op->idtype = (ch->con->linktype == NG_HCI_LINK_ACL)? NG_L2CAP_L2CA_IDTYPE_BREDR : NG_L2CAP_L2CA_IDTYPE_LE; op->lcid = ch->scid; } NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); } return (error); } /* ng_l2cap_l2ca_write_rsp */
int ng_hci_con_timeout(ng_hci_unit_con_p con) { if (con->flags & NG_HCI_CON_TIMEOUT_PENDING) panic( "%s: %s - Duplicated connection timeout!\n", __func__, NG_NODE_NAME(con->unit->node)); con->flags |= NG_HCI_CON_TIMEOUT_PENDING; ng_callout(&con->con_timo, con->unit->node, NULL, bluetooth_hci_connect_timeout(), ng_hci_process_con_timeout, NULL, con->con_handle); return (0); } /* ng_hci_con_timeout */
void ng_hci_mtap(ng_hci_unit_p unit, struct mbuf *m0) { struct mbuf *m = NULL; int error = 0; if (unit->raw != NULL && NG_HOOK_IS_VALID(unit->raw)) { m = m_dup(m0, M_DONTWAIT); if (m != NULL) NG_SEND_DATA_ONLY(error, unit->raw, m); if (error != 0) NG_HCI_INFO( "%s: %s - Could not forward packet, error=%d\n", __func__, NG_NODE_NAME(unit->node), error); } } /* ng_hci_mtap */
int ng_l2cap_l2ca_ping_rsp(ng_l2cap_con_p con, u_int32_t token, u_int16_t result, struct mbuf *data) { ng_l2cap_p l2cap = con->l2cap; struct ng_mesg *msg = NULL; ng_l2cap_l2ca_ping_op *op = NULL; int error = 0, size = 0; /* Check if control hook is connected and valid */ if (l2cap->ctl == NULL || NG_HOOK_NOT_VALID(l2cap->ctl)) { NG_L2CAP_WARN( "%s: %s - unable to send L2CA_Ping response message. " \ "Hook is not connected or valid\n", __func__, NG_NODE_NAME(l2cap->node)); error = ENOTCONN; goto out; } size = (data == NULL)? 0 : data->m_pkthdr.len; /* Create and send L2CA_Ping response message */ NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_PING, sizeof(*op) + size, M_NOWAIT); if (msg == NULL) error = ENOMEM; else { msg->header.token = token; msg->header.flags |= NGF_RESP; op = (ng_l2cap_l2ca_ping_op *)(msg->data); op->result = result; bcopy(&con->remote, &op->bdaddr, sizeof(op->bdaddr)); if (data != NULL && size > 0) { op->echo_size = size; m_copydata(data, 0, size, (caddr_t) op + sizeof(*op)); } NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->ctl, 0); } out: NG_FREE_M(data); return (error); } /* ng_l2cap_l2ca_ping_rsp */
void ng_hci_node_is_up(node_p node, hook_p hook, void *arg1, int arg2) { ng_hci_unit_p unit = NULL; struct ng_mesg *msg = NULL; ng_hci_node_up_ep *ep = NULL; int error; if (node == NULL || NG_NODE_NOT_VALID(node) || hook == NULL || NG_HOOK_NOT_VALID(hook)) return; unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node); if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) return; if (hook != unit->acl && hook != unit->sco) return; NG_MKMESSAGE(msg,NGM_HCI_COOKIE,NGM_HCI_NODE_UP,sizeof(*ep),M_NOWAIT); if (msg != NULL) { ep = (ng_hci_node_up_ep *)(msg->data); if (hook == unit->acl) { NG_HCI_BUFF_ACL_SIZE(unit->buffer, ep->pkt_size); NG_HCI_BUFF_ACL_TOTAL(unit->buffer, ep->num_pkts); } else { NG_HCI_BUFF_SCO_SIZE(unit->buffer, ep->pkt_size); NG_HCI_BUFF_SCO_TOTAL(unit->buffer, ep->num_pkts); } bcopy(&unit->bdaddr, &ep->bdaddr, sizeof(ep->bdaddr)); NG_SEND_MSG_HOOK(error, node, msg, hook, 0); } else error = ENOMEM; if (error != 0) NG_HCI_INFO( "%s: %s - failed to send NODE_UP message to hook \"%s\", error=%d\n", __func__, NG_NODE_NAME(unit->node), NG_HOOK_NAME(hook), error); } /* ng_hci_node_is_up */
int ng_l2cap_lp_qos_cfm(ng_l2cap_p l2cap, struct ng_mesg *msg) { ng_hci_lp_qos_cfm_ep *ep = NULL; int error = 0; /* Check message */ if (msg->header.arglen != sizeof(*ep)) { NG_L2CAP_ALERT( "%s: %s - invalid LP_QoSSetupCfm[Neg] message size\n", __func__, NG_NODE_NAME(l2cap->node)); error = EMSGSIZE; goto out; } ep = (ng_hci_lp_qos_cfm_ep *) (msg->data); /* XXX FIXME do something */ out: return (error); } /* ng_l2cap_lp_qos_cfm */
int ng_hci_lp_con_ind(ng_hci_unit_con_p con, u_int8_t *uclass) { ng_hci_unit_p unit = con->unit; struct ng_mesg *msg = NULL; ng_hci_lp_con_ind_ep *ep = NULL; hook_p hook = NULL; int error = 0; /* * Connection_Request event is generated for specific link type. * Use link_type to select upstream hook. */ if (con->link_type == NG_HCI_LINK_ACL) hook = unit->acl; else hook = unit->sco; if (hook != NULL && NG_HOOK_IS_VALID(hook)) { NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_IND, sizeof(*ep), M_NOWAIT); if (msg == NULL) return (ENOMEM); ep = (ng_hci_lp_con_ind_ep *)(msg->data); ep->link_type = con->link_type; bcopy(uclass, ep->uclass, sizeof(ep->uclass)); bcopy(&con->bdaddr, &ep->bdaddr, sizeof(ep->bdaddr)); NG_SEND_MSG_HOOK(error, unit->node, msg, hook, 0); } else { NG_HCI_WARN( "%s: %s - Upstream hook is not connected or not valid, hook=%p\n", __func__, NG_NODE_NAME(unit->node), hook); error = ENOTCONN; } return (error); } /* ng_hci_lp_con_ind */
int ng_l2cap_l2ca_discon_ind(ng_l2cap_chan_p ch) { ng_l2cap_p l2cap = ch->con->l2cap; struct ng_mesg *msg = NULL; ng_l2cap_l2ca_discon_ind_ip *ip = NULL; int error = 0; /* Check if upstream hook is connected and valid */ if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { NG_L2CAP_ERR( "%s: %s - unable to send L2CA_DisconnectInd message. " \ "Hook is not connected or valid, psm=%d\n", __func__, NG_NODE_NAME(l2cap->node), ch->psm); return (ENOTCONN); } /* Create and send L2CA_DisconnectInd message */ NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON_IND, sizeof(*ip), M_NOWAIT); if (msg == NULL) error = ENOMEM; else { ip = (ng_l2cap_l2ca_discon_ind_ip *)(msg->data); ip->idtype = ch->idtype; if(ch->idtype == NG_L2CAP_L2CA_IDTYPE_ATT|| ch->idtype == NG_L2CAP_L2CA_IDTYPE_SMP) ip->lcid = ch->con->con_handle; else ip->lcid = ch->scid; NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->l2c, 0); } return (error); } /* ng_l2cap_l2ca_discon_ind */
int ng_l2cap_l2ca_clt_receive(ng_l2cap_con_p con) { struct _clt_pkt { ng_l2cap_hdr_t h; ng_l2cap_clt_hdr_t c_h; } __attribute__ ((packed)) *hdr = NULL; ng_l2cap_p l2cap = con->l2cap; int length, error = 0; NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr)); if (con->rx_pkt == NULL) return (ENOBUFS); hdr = mtod(con->rx_pkt, struct _clt_pkt *); /* Check packet */ length = con->rx_pkt->m_pkthdr.len - sizeof(*hdr); if (length < 0) { NG_L2CAP_ERR( "%s: %s - invalid L2CAP CLT data packet. Packet too small, length=%d\n", __func__, NG_NODE_NAME(l2cap->node), length); error = EMSGSIZE; goto drop; } /* Check payload size against CLT MTU */ if (length > NG_L2CAP_MTU_DEFAULT) { NG_L2CAP_ERR( "%s: %s - invalid L2CAP CLT data packet. Packet too big, length=%d, mtu=%d\n", __func__, NG_NODE_NAME(l2cap->node), length, NG_L2CAP_MTU_DEFAULT); error = EMSGSIZE; goto drop; } hdr->c_h.psm = le16toh(hdr->c_h.psm); /* * If we got here then everything looks good and we can sent packet * to the upper layer protocol. */ /* Select upstream hook based on PSM */ switch (hdr->c_h.psm) { case NG_L2CAP_PSM_SDP: if (l2cap->flags & NG_L2CAP_CLT_SDP_DISABLED) goto drop; break; case NG_L2CAP_PSM_RFCOMM: if (l2cap->flags & NG_L2CAP_CLT_RFCOMM_DISABLED) goto drop; break; case NG_L2CAP_PSM_TCP: if (l2cap->flags & NG_L2CAP_CLT_TCP_DISABLED) goto drop; break; } /* Check if upstream hook is connected and valid */ if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { NG_L2CAP_ERR( "%s: %s - unable to send L2CAP CLT data packet. " \ "Hook is not connected or valid, psm=%d\n", __func__, NG_NODE_NAME(l2cap->node), hdr->c_h.psm); error = ENOTCONN; goto drop; } NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt); con->rx_pkt = NULL; drop: NG_FREE_M(con->rx_pkt); /* checks for != NULL */ return (error); } /* ng_l2cap_l2ca_clt_receive */
int ng_l2cap_l2ca_receive(ng_l2cap_con_p con) { ng_l2cap_p l2cap = con->l2cap; ng_l2cap_hdr_t *hdr = NULL; ng_l2cap_chan_p ch = NULL; int error = 0; NG_L2CAP_M_PULLUP(con->rx_pkt, sizeof(*hdr)); if (con->rx_pkt == NULL) return (ENOBUFS); hdr = mtod(con->rx_pkt, ng_l2cap_hdr_t *); /* Check channel */ ch = ng_l2cap_chan_by_scid(l2cap, hdr->dcid); if (ch == NULL) { NG_L2CAP_ERR( "%s: %s - unexpected L2CAP data packet. Channel does not exist, cid=%d\n", __func__, NG_NODE_NAME(l2cap->node), hdr->dcid); error = ENOENT; goto drop; } /* Check channel state */ if (ch->state != NG_L2CAP_OPEN) { NG_L2CAP_WARN( "%s: %s - unexpected L2CAP data packet. " \ "Invalid channel state, cid=%d, state=%d\n", __func__, NG_NODE_NAME(l2cap->node), ch->scid, ch->state); error = EHOSTDOWN; /* XXX not always - re-configuration */ goto drop; } /* Check payload size and channel's MTU */ if (hdr->length > ch->imtu) { NG_L2CAP_ERR( "%s: %s - invalid L2CAP data packet. " \ "Packet too big, length=%d, imtu=%d, cid=%d\n", __func__, NG_NODE_NAME(l2cap->node), hdr->length, ch->imtu, ch->scid); error = EMSGSIZE; goto drop; } /* * If we got here then everything looks good and we can sent packet * to the upper layer protocol. */ /* Check if upstream hook is connected and valid */ if (l2cap->l2c == NULL || NG_HOOK_NOT_VALID(l2cap->l2c)) { NG_L2CAP_ERR( "%s: %s - unable to send L2CAP data packet. " \ "Hook is not connected or valid, psm=%d\n", __func__, NG_NODE_NAME(l2cap->node), ch->psm); error = ENOTCONN; goto drop; } NG_SEND_DATA_ONLY(error, l2cap->l2c, con->rx_pkt); con->rx_pkt = NULL; drop: NG_FREE_M(con->rx_pkt); /* checks for != NULL */ return (error); } /* ng_l2cap_receive */
int ng_l2cap_l2ca_write_req(ng_l2cap_p l2cap, struct mbuf *m) { ng_l2cap_l2ca_hdr_t *l2ca_hdr = NULL; ng_l2cap_chan_p ch = NULL; ng_l2cap_cmd_p cmd = NULL; int error = 0; u_int32_t token = 0; /* Make sure we can access L2CA data packet header */ if (m->m_pkthdr.len < sizeof(*l2ca_hdr)) { NG_L2CAP_ERR( "%s: %s - L2CA Data packet too small, len=%d\n", __func__,NG_NODE_NAME(l2cap->node),m->m_pkthdr.len); error = EMSGSIZE; goto drop; } /* Get L2CA data packet header */ NG_L2CAP_M_PULLUP(m, sizeof(*l2ca_hdr)); if (m == NULL) return (ENOBUFS); l2ca_hdr = mtod(m, ng_l2cap_l2ca_hdr_t *); token = l2ca_hdr->token; m_adj(m, sizeof(*l2ca_hdr)); /* Verify payload size */ if (l2ca_hdr->length != m->m_pkthdr.len) { NG_L2CAP_ERR( "%s: %s - invalid L2CA Data packet. " \ "Payload length does not match, length=%d, len=%d\n", __func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->length, m->m_pkthdr.len); error = EMSGSIZE; goto drop; } /* Check channel ID */ if (l2ca_hdr->lcid < NG_L2CAP_FIRST_CID) { NG_L2CAP_ERR( "%s: %s - invalid L2CA Data packet. Inavlid channel ID, cid=%d\n", __func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->lcid); error = EINVAL; goto drop; } /* Verify that we have the channel and make sure it is open */ ch = ng_l2cap_chan_by_scid(l2cap, l2ca_hdr->lcid); if (ch == NULL) { NG_L2CAP_ERR( "%s: %s - invalid L2CA Data packet. Channel does not exist, cid=%d\n", __func__, NG_NODE_NAME(l2cap->node), l2ca_hdr->lcid); error = ENOENT; goto drop; } if (ch->state != NG_L2CAP_OPEN) { NG_L2CAP_ERR( "%s: %s - invalid L2CA Data packet. Invalid channel state, scid=%d, state=%d\n", __func__, NG_NODE_NAME(l2cap->node), ch->scid, ch->state); error = EHOSTDOWN; goto drop; /* XXX not always - re-configure */ } /* Create L2CAP command descriptor */ cmd = ng_l2cap_new_cmd(ch->con, ch, 0, NGM_L2CAP_L2CA_WRITE, token); if (cmd == NULL) { error = ENOMEM; goto drop; } /* Attach data packet and link command to the queue */ cmd->aux = m; ng_l2cap_link_cmd(ch->con, cmd); ng_l2cap_lp_deliver(ch->con); return (error); drop: NG_FREE_M(m); return (error); } /* ng_l2cap_l2ca_write_req */
int ng_l2cap_l2ca_cfg_req(ng_l2cap_p l2cap, struct ng_mesg *msg) { ng_l2cap_l2ca_cfg_ip *ip = NULL; ng_l2cap_chan_p ch = NULL; ng_l2cap_cmd_p cmd = NULL; struct mbuf *opt = NULL; u_int16_t *mtu = NULL, *flush_timo = NULL; ng_l2cap_flow_p flow = NULL; int error = 0; /* Check message */ if (msg->header.arglen != sizeof(*ip)) { NG_L2CAP_ALERT( "%s: %s - Invalid L2CA_Config request message size, size=%d\n", __func__, NG_NODE_NAME(l2cap->node), msg->header.arglen); error = EMSGSIZE; goto out; } ip = (ng_l2cap_l2ca_cfg_ip *)(msg->data); /* Check if we have this channel */ ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid); if (ch == NULL) { NG_L2CAP_ERR( "%s: %s - unexpected L2CA_Config request message. " \ "Channel does not exist, lcid=%d\n", __func__, NG_NODE_NAME(l2cap->node), ip->lcid); error = ENOENT; goto out; } /* Check channel state */ if (ch->state != NG_L2CAP_OPEN && ch->state != NG_L2CAP_CONFIG) { NG_L2CAP_ERR( "%s: %s - unexpected L2CA_Config request message. " \ "Invalid channel state, state=%d, lcid=%d\n", __func__, NG_NODE_NAME(l2cap->node), ch->state, ch->scid); error = EINVAL; goto out; } /* Set requested channel configuration options */ ch->imtu = ip->imtu; bcopy(&ip->oflow, &ch->oflow, sizeof(ch->oflow)); ch->flush_timo = ip->flush_timo; ch->link_timo = ip->link_timo; /* Compare channel settings with defaults */ if (ch->imtu != NG_L2CAP_MTU_DEFAULT) mtu = &ch->imtu; if (ch->flush_timo != NG_L2CAP_FLUSH_TIMO_DEFAULT) flush_timo = &ch->flush_timo; if (bcmp(ng_l2cap_default_flow(), &ch->oflow, sizeof(ch->oflow)) != 0) flow = &ch->oflow; /* Create configuration options */ _ng_l2cap_build_cfg_options(opt, mtu, flush_timo, flow); if (opt == NULL) { error = ENOBUFS; goto out; } /* Create L2CAP command descriptor */ cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(ch->con), NG_L2CAP_CFG_REQ, msg->header.token); if (cmd == NULL) { NG_FREE_M(opt); error = ENOMEM; goto out; } if (cmd->ident == NG_L2CAP_NULL_IDENT) { ng_l2cap_free_cmd(cmd); NG_FREE_M(opt); error = EIO; goto out; } /* Create L2CAP command packet */ _ng_l2cap_cfg_req(cmd->aux, cmd->ident, ch->dcid, 0, opt); if (cmd->aux == NULL) { ng_l2cap_free_cmd(cmd); error = ENOBUFS; goto out; } /* Adjust channel state for re-configuration */ if (ch->state == NG_L2CAP_OPEN) { ch->state = NG_L2CAP_CONFIG; ch->cfg_state = 0; } /* Link command to the queue */ ng_l2cap_link_cmd(ch->con, cmd); ng_l2cap_lp_deliver(ch->con); out: return (error); } /* ng_l2cap_l2ca_cfg_req */
int ng_l2cap_l2ca_cfg_rsp_req(ng_l2cap_p l2cap, struct ng_mesg *msg) { ng_l2cap_l2ca_cfg_rsp_ip *ip = NULL; ng_l2cap_chan_p ch = NULL; ng_l2cap_cmd_p cmd = NULL; struct mbuf *opt = NULL; u_int16_t *mtu = NULL; ng_l2cap_flow_p flow = NULL; int error = 0; /* Check message */ if (msg->header.arglen != sizeof(*ip)) { NG_L2CAP_ALERT( "%s: %s - invalid L2CA_ConfigRsp request message size, size=%d\n", __func__, NG_NODE_NAME(l2cap->node), msg->header.arglen); error = EMSGSIZE; goto out; } ip = (ng_l2cap_l2ca_cfg_rsp_ip *)(msg->data); /* Check if we have this channel */ ch = ng_l2cap_chan_by_scid(l2cap, ip->lcid); if (ch == NULL) { NG_L2CAP_ERR( "%s: %s - unexpected L2CA_ConfigRsp request message. " \ "Channel does not exist, lcid=%d\n", __func__, NG_NODE_NAME(l2cap->node), ip->lcid); error = ENOENT; goto out; } /* Check channel state */ if (ch->state != NG_L2CAP_CONFIG) { NG_L2CAP_ERR( "%s: %s - unexpected L2CA_ConfigRsp request message. " \ "Invalid channel state, state=%d, lcid=%d\n", __func__, NG_NODE_NAME(l2cap->node), ch->state, ch->scid); error = EINVAL; goto out; } /* Set channel settings */ if (ip->omtu != ch->omtu) { ch->omtu = ip->omtu; mtu = &ch->omtu; } if (bcmp(&ip->iflow, &ch->iflow, sizeof(ch->iflow)) != 0) { bcopy(&ip->iflow, &ch->iflow, sizeof(ch->iflow)); flow = &ch->iflow; } if (mtu != NULL || flow != NULL) { _ng_l2cap_build_cfg_options(opt, mtu, NULL, flow); if (opt == NULL) { error = ENOBUFS; goto out; } } /* Create L2CAP command */ cmd = ng_l2cap_new_cmd(ch->con, ch, ch->ident, NG_L2CAP_CFG_RSP, msg->header.token); if (cmd == NULL) { NG_FREE_M(opt); error = ENOMEM; goto out; } _ng_l2cap_cfg_rsp(cmd->aux,cmd->ident,ch->dcid,0,NG_L2CAP_SUCCESS,opt); if (cmd->aux == NULL) { ng_l2cap_free_cmd(cmd); error = ENOBUFS; goto out; } /* XXX FIXME - not here ??? */ ch->cfg_state |= NG_L2CAP_CFG_OUT; if (ch->cfg_state == NG_L2CAP_CFG_BOTH) ch->state = NG_L2CAP_OPEN; /* Link command to the queue */ ng_l2cap_link_cmd(ch->con, cmd); ng_l2cap_lp_deliver(ch->con); out: return (error); } /* ng_l2cap_l2ca_cfg_rsp_req */
int ng_l2cap_l2ca_con_req(ng_l2cap_p l2cap, struct ng_mesg *msg) { ng_l2cap_l2ca_con_ip *ip = NULL; ng_l2cap_con_p con = NULL; ng_l2cap_chan_p ch = NULL; ng_l2cap_cmd_p cmd = NULL; int error = 0; /* Check message */ if (msg->header.arglen != sizeof(*ip)) { NG_L2CAP_ALERT( "%s: %s - invalid L2CA_Connect request message size, size=%d\n", __func__, NG_NODE_NAME(l2cap->node), msg->header.arglen); error = EMSGSIZE; goto out; } ip = (ng_l2cap_l2ca_con_ip *)(msg->data); /* Check if we have connection to the remote unit */ con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr); if (con == NULL) { /* Submit LP_ConnectReq to the lower layer */ error = ng_l2cap_lp_con_req(l2cap, &ip->bdaddr); if (error != 0) { NG_L2CAP_ERR( "%s: %s - unable to send LP_ConnectReq message, error=%d\n", __func__, NG_NODE_NAME(l2cap->node), error); goto out; } /* This should not fail */ con = ng_l2cap_con_by_addr(l2cap, &ip->bdaddr); KASSERT((con != NULL), ("%s: %s - could not find connection!\n", __func__, NG_NODE_NAME(l2cap->node))); } /* * Create new empty channel descriptor. In case of any failure do * not touch connection descriptor. */ ch = ng_l2cap_new_chan(l2cap, con, ip->psm); if (ch == NULL) { error = ENOMEM; goto out; } /* Now create L2CAP_ConnectReq command */ cmd = ng_l2cap_new_cmd(ch->con, ch, ng_l2cap_get_ident(con), NG_L2CAP_CON_REQ, msg->header.token); if (cmd == NULL) { ng_l2cap_free_chan(ch); error = ENOMEM; goto out; } if (cmd->ident == NG_L2CAP_NULL_IDENT) { ng_l2cap_free_cmd(cmd); ng_l2cap_free_chan(ch); error = EIO; goto out; } /* Create L2CAP command packet */ _ng_l2cap_con_req(cmd->aux, cmd->ident, ch->psm, ch->scid); if (cmd->aux == NULL) { ng_l2cap_free_cmd(cmd); ng_l2cap_free_chan(ch); error = ENOBUFS; goto out; } ch->state = NG_L2CAP_W4_L2CAP_CON_RSP; /* Link command to the queue */ ng_l2cap_link_cmd(ch->con, cmd); ng_l2cap_lp_deliver(ch->con); out: return (error); } /* ng_l2cap_l2ca_con_req */