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 */