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_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_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_hci_lp_discon_req(ng_hci_unit_p unit, item_p item, hook_p hook) { struct discon_req { ng_hci_cmd_pkt_t hdr; ng_hci_discon_cp cp; } __attribute__ ((packed)) *req = NULL; ng_hci_lp_discon_req_ep *ep = NULL; ng_hci_unit_con_p con = NULL; struct mbuf *m = NULL; int error = 0; /* Check if unit is ready */ 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); error = ENXIO; goto out; } if (NGI_MSG(item)->header.arglen != sizeof(*ep)) { NG_HCI_ALERT( "%s: %s - invalid LP_DisconnectReq message size=%d\n", __func__, NG_NODE_NAME(unit->node), NGI_MSG(item)->header.arglen); error = EMSGSIZE; goto out; } ep = (ng_hci_lp_discon_req_ep *)(NGI_MSG(item)->data); con = ng_hci_con_by_handle(unit, ep->con_handle); if (con == NULL) { NG_HCI_ERR( "%s: %s - invalid connection handle=%d\n", __func__, NG_NODE_NAME(unit->node), ep->con_handle); error = ENOENT; goto out; } if (con->state != NG_HCI_CON_OPEN) { NG_HCI_ERR( "%s: %s - invalid connection state=%d, handle=%d\n", __func__, NG_NODE_NAME(unit->node), con->state, ep->con_handle); error = EINVAL; goto out; } /* * Create HCI command */ MGETHDR(m, M_DONTWAIT, MT_DATA); if (m == NULL) { error = ENOBUFS; goto out; } m->m_pkthdr.len = m->m_len = sizeof(*req); req = mtod(m, struct discon_req *); req->hdr.type = NG_HCI_CMD_PKT; req->hdr.length = sizeof(req->cp); req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, NG_HCI_OCF_DISCON)); req->cp.con_handle = htole16(ep->con_handle); req->cp.reason = ep->reason; /* * Queue and send HCI command */ NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) error = ng_hci_send_command(unit); out: NG_FREE_ITEM(item); return (error); } /* ng_hci_lp_discon_req */
int ng_hci_send_command(ng_hci_unit_p unit) { struct mbuf *m0 = NULL, *m = NULL; int free, error = 0; /* Check if other command is pending */ if (unit->state & NG_HCI_UNIT_COMMAND_PENDING) return (0); /* Check if unit can accept our command */ NG_HCI_BUFF_CMD_GET(unit->buffer, free); if (free == 0) return (0); /* Check if driver hook is still ok */ if (unit->drv == NULL || NG_HOOK_NOT_VALID(unit->drv)) { NG_HCI_WARN( "%s: %s - hook \"%s\" is not connected or valid\n", __func__, NG_NODE_NAME(unit->node), NG_HCI_HOOK_DRV); NG_BT_MBUFQ_DRAIN(&unit->cmdq); return (ENOTCONN); } /* * Get first command from queue, give it to RAW hook then * make copy of it and send it to the driver */ m0 = NG_BT_MBUFQ_FIRST(&unit->cmdq); if (m0 == NULL) return (0); ng_hci_mtap(unit, m0); m = m_dup(m0, MB_DONTWAIT); if (m != NULL) NG_SEND_DATA_ONLY(error, unit->drv, m); else error = ENOBUFS; if (error != 0) NG_HCI_ERR( "%s: %s - could not send HCI command, error=%d\n", __func__, NG_NODE_NAME(unit->node), error); /* * Even if we were not able to send command we still pretend * that everything is OK and let timeout handle that. */ NG_HCI_BUFF_CMD_USE(unit->buffer, 1); NG_HCI_STAT_CMD_SENT(unit->stat); NG_HCI_STAT_BYTES_SENT(unit->stat, m0->m_pkthdr.len); /* * Note: ng_hci_command_timeout() will set * NG_HCI_UNIT_COMMAND_PENDING flag */ ng_hci_command_timeout(unit); return (0); } /* ng_hci_send_command */