Path: blob/main/sys/netgraph/bluetooth/hci/ng_hci_cmds.c
34814 views
/*1* ng_hci_cmds.c2*/34/*-5* SPDX-License-Identifier: BSD-2-Clause6*7* Copyright (c) Maksim Yevmenkin <[email protected]>8* All rights reserved.9*10* Redistribution and use in source and binary forms, with or without11* modification, are permitted provided that the following conditions12* are met:13* 1. Redistributions of source code must retain the above copyright14* notice, this list of conditions and the following disclaimer.15* 2. Redistributions in binary form must reproduce the above copyright16* notice, this list of conditions and the following disclaimer in the17* documentation and/or other materials provided with the distribution.18*19* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND20* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE21* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE22* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE23* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL24* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS25* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)26* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT27* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY28* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF29* SUCH DAMAGE.30*31* $Id: ng_hci_cmds.c,v 1.4 2003/09/08 18:57:51 max Exp $32*/3334#include <sys/param.h>35#include <sys/systm.h>36#include <sys/kernel.h>37#include <sys/endian.h>38#include <sys/malloc.h>39#include <sys/mbuf.h>40#include <sys/queue.h>41#include <netgraph/ng_message.h>42#include <netgraph/netgraph.h>43#include <netgraph/bluetooth/include/ng_bluetooth.h>44#include <netgraph/bluetooth/include/ng_hci.h>45#include <netgraph/bluetooth/hci/ng_hci_var.h>46#include <netgraph/bluetooth/hci/ng_hci_cmds.h>47#include <netgraph/bluetooth/hci/ng_hci_evnt.h>48#include <netgraph/bluetooth/hci/ng_hci_ulpi.h>49#include <netgraph/bluetooth/hci/ng_hci_misc.h>5051/******************************************************************************52******************************************************************************53** HCI commands processing module54******************************************************************************55******************************************************************************/5657#undef min58#define min(a, b) ((a) < (b))? (a) : (b)5960static int complete_command (ng_hci_unit_p, int, struct mbuf **);6162static int process_link_control_params63(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);64static int process_link_policy_params65(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);66static int process_hc_baseband_params67(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);68static int process_info_params69(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);70static int process_status_params71(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);72static int process_testing_params73(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);74static int process_le_params75(ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *);7677static int process_link_control_status78(ng_hci_unit_p, ng_hci_command_status_ep *, struct mbuf *);79static int process_link_policy_status80(ng_hci_unit_p, ng_hci_command_status_ep *, struct mbuf *);81static int process_le_status82(ng_hci_unit_p, ng_hci_command_status_ep *, struct mbuf *);8384/*85* Send HCI command to the driver.86*/8788int89ng_hci_send_command(ng_hci_unit_p unit)90{91struct mbuf *m0 = NULL, *m = NULL;92int free, error = 0;9394/* Check if other command is pending */95if (unit->state & NG_HCI_UNIT_COMMAND_PENDING)96return (0);9798/* Check if unit can accept our command */99NG_HCI_BUFF_CMD_GET(unit->buffer, free);100if (free == 0)101return (0);102103/* Check if driver hook is still ok */104if (unit->drv == NULL || NG_HOOK_NOT_VALID(unit->drv)) {105NG_HCI_WARN(106"%s: %s - hook \"%s\" is not connected or valid\n",107__func__, NG_NODE_NAME(unit->node), NG_HCI_HOOK_DRV);108109NG_BT_MBUFQ_DRAIN(&unit->cmdq);110111return (ENOTCONN);112}113114/*115* Get first command from queue, give it to RAW hook then116* make copy of it and send it to the driver117*/118119m0 = NG_BT_MBUFQ_FIRST(&unit->cmdq);120if (m0 == NULL)121return (0);122123ng_hci_mtap(unit, m0);124125m = m_dup(m0, M_NOWAIT);126if (m != NULL)127NG_SEND_DATA_ONLY(error, unit->drv, m);128else129error = ENOBUFS;130131if (error != 0)132NG_HCI_ERR(133"%s: %s - could not send HCI command, error=%d\n",134__func__, NG_NODE_NAME(unit->node), error);135136/*137* Even if we were not able to send command we still pretend138* that everything is OK and let timeout handle that.139*/140141NG_HCI_BUFF_CMD_USE(unit->buffer, 1);142NG_HCI_STAT_CMD_SENT(unit->stat);143NG_HCI_STAT_BYTES_SENT(unit->stat, m0->m_pkthdr.len);144145/*146* Note: ng_hci_command_timeout() will set147* NG_HCI_UNIT_COMMAND_PENDING flag148*/149150ng_hci_command_timeout(unit);151152return (0);153} /* ng_hci_send_command */154155/*156* Process HCI Command_Compete event. Complete HCI command, and do post157* processing on the command parameters (cp) and command return parameters158* (e) if required (for example adjust state).159*/160161int162ng_hci_process_command_complete(ng_hci_unit_p unit, struct mbuf *e)163{164ng_hci_command_compl_ep *ep = NULL;165struct mbuf *cp = NULL;166int error = 0;167168/* Get event packet and update command buffer info */169NG_HCI_M_PULLUP(e, sizeof(*ep));170if (e == NULL)171return (ENOBUFS); /* XXX this is bad */172173ep = mtod(e, ng_hci_command_compl_ep *);174NG_HCI_BUFF_CMD_SET(unit->buffer, ep->num_cmd_pkts);175176/* Check for special NOOP command */177if (ep->opcode == 0x0000) {178NG_FREE_M(e);179goto out;180}181182/* Try to match first command item in the queue */183error = complete_command(unit, ep->opcode, &cp);184if (error != 0) {185NG_FREE_M(e);186goto out;187}188189/*190* Perform post processing on command parameters and return parameters191* do it only if status is OK (status == 0). Status is the first byte192* of any command return parameters.193*/194195ep->opcode = le16toh(ep->opcode);196m_adj(e, sizeof(*ep));197198if (*mtod(e, u_int8_t *) == 0) { /* XXX m_pullup here? */199switch (NG_HCI_OGF(ep->opcode)) {200case NG_HCI_OGF_LINK_CONTROL:201error = process_link_control_params(unit,202NG_HCI_OCF(ep->opcode), cp, e);203break;204205case NG_HCI_OGF_LINK_POLICY:206error = process_link_policy_params(unit,207NG_HCI_OCF(ep->opcode), cp, e);208break;209210case NG_HCI_OGF_HC_BASEBAND:211error = process_hc_baseband_params(unit,212NG_HCI_OCF(ep->opcode), cp, e);213break;214215case NG_HCI_OGF_INFO:216error = process_info_params(unit,217NG_HCI_OCF(ep->opcode), cp, e);218break;219220case NG_HCI_OGF_STATUS:221error = process_status_params(unit,222NG_HCI_OCF(ep->opcode), cp, e);223break;224225case NG_HCI_OGF_TESTING:226error = process_testing_params(unit,227NG_HCI_OCF(ep->opcode), cp, e);228break;229case NG_HCI_OGF_LE:230error = process_le_params(unit,231NG_HCI_OCF(ep->opcode), cp, e);232break;233case NG_HCI_OGF_BT_LOGO:234case NG_HCI_OGF_VENDOR:235NG_FREE_M(cp);236NG_FREE_M(e);237break;238239default:240NG_FREE_M(cp);241NG_FREE_M(e);242error = EINVAL;243break;244}245} else {246NG_HCI_ERR(247"%s: %s - HCI command failed, OGF=%#x, OCF=%#x, status=%#x\n",248__func__, NG_NODE_NAME(unit->node),249NG_HCI_OGF(ep->opcode), NG_HCI_OCF(ep->opcode),250*mtod(e, u_int8_t *));251252NG_FREE_M(cp);253NG_FREE_M(e);254}255out:256ng_hci_send_command(unit);257258return (error);259} /* ng_hci_process_command_complete */260261/*262* Process HCI Command_Status event. Check the status (mst) and do post263* processing (if required).264*/265266int267ng_hci_process_command_status(ng_hci_unit_p unit, struct mbuf *e)268{269ng_hci_command_status_ep *ep = NULL;270struct mbuf *cp = NULL;271int error = 0;272273/* Update command buffer info */274NG_HCI_M_PULLUP(e, sizeof(*ep));275if (e == NULL)276return (ENOBUFS); /* XXX this is bad */277278ep = mtod(e, ng_hci_command_status_ep *);279NG_HCI_BUFF_CMD_SET(unit->buffer, ep->num_cmd_pkts);280281/* Check for special NOOP command */282if (ep->opcode == 0x0000)283goto out;284285/* Try to match first command item in the queue */286error = complete_command(unit, ep->opcode, &cp);287if (error != 0)288goto out;289290/*291* Perform post processing on HCI Command_Status event292*/293294ep->opcode = le16toh(ep->opcode);295296switch (NG_HCI_OGF(ep->opcode)) {297case NG_HCI_OGF_LINK_CONTROL:298error = process_link_control_status(unit, ep, cp);299break;300301case NG_HCI_OGF_LINK_POLICY:302error = process_link_policy_status(unit, ep, cp);303break;304case NG_HCI_OGF_LE:305error = process_le_status(unit, ep, cp);306break;307case NG_HCI_OGF_BT_LOGO:308case NG_HCI_OGF_VENDOR:309NG_FREE_M(cp);310break;311312case NG_HCI_OGF_HC_BASEBAND:313case NG_HCI_OGF_INFO:314case NG_HCI_OGF_STATUS:315case NG_HCI_OGF_TESTING:316default:317NG_FREE_M(cp);318error = EINVAL;319break;320}321out:322NG_FREE_M(e);323ng_hci_send_command(unit);324325return (error);326} /* ng_hci_process_command_status */327328/*329* Complete queued HCI command.330*/331332static int333complete_command(ng_hci_unit_p unit, int opcode, struct mbuf **cp)334{335struct mbuf *m = NULL;336337/* Check unit state */338if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) {339NG_HCI_ALERT(340"%s: %s - no pending command, state=%#x\n",341__func__, NG_NODE_NAME(unit->node), unit->state);342343return (EINVAL);344}345346/* Get first command in the queue */347m = NG_BT_MBUFQ_FIRST(&unit->cmdq);348if (m == NULL) {349NG_HCI_ALERT(350"%s: %s - empty command queue?!\n", __func__, NG_NODE_NAME(unit->node));351352return (EINVAL);353}354355/*356* Match command opcode, if does not match - do nothing and357* let timeout handle that.358*/359360if (mtod(m, ng_hci_cmd_pkt_t *)->opcode != opcode) {361NG_HCI_ALERT(362"%s: %s - command queue is out of sync\n", __func__, NG_NODE_NAME(unit->node));363364return (EINVAL);365}366367/*368* Now we can remove command timeout, dequeue completed command369* and return command parameters. ng_hci_command_untimeout will370* drop NG_HCI_UNIT_COMMAND_PENDING flag.371* Note: if ng_hci_command_untimeout() fails (returns non-zero)372* then timeout already happened and timeout message went info node373* queue. In this case we ignore command completion and pretend374* there is a timeout.375*/376377if (ng_hci_command_untimeout(unit) != 0)378return (ETIMEDOUT);379380NG_BT_MBUFQ_DEQUEUE(&unit->cmdq, *cp);381m_adj(*cp, sizeof(ng_hci_cmd_pkt_t));382383return (0);384} /* complete_command */385386/*387* Process HCI command timeout388*/389390void391ng_hci_process_command_timeout(node_p node, hook_p hook, void *arg1, int arg2)392{393ng_hci_unit_p unit = NULL;394struct mbuf *m = NULL;395u_int16_t opcode;396397if (NG_NODE_NOT_VALID(node)) {398printf("%s: Netgraph node is not valid\n", __func__);399return;400}401402unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node);403404if (unit->state & NG_HCI_UNIT_COMMAND_PENDING) {405unit->state &= ~NG_HCI_UNIT_COMMAND_PENDING;406407NG_BT_MBUFQ_DEQUEUE(&unit->cmdq, m);408if (m == NULL) {409NG_HCI_ALERT(410"%s: %s - command queue is out of sync!\n", __func__, NG_NODE_NAME(unit->node));411412return;413}414415opcode = le16toh(mtod(m, ng_hci_cmd_pkt_t *)->opcode);416NG_FREE_M(m);417418NG_HCI_ERR(419"%s: %s - unable to complete HCI command OGF=%#x, OCF=%#x. Timeout\n",420__func__, NG_NODE_NAME(unit->node), NG_HCI_OGF(opcode),421NG_HCI_OCF(opcode));422423/* Try to send more commands */424NG_HCI_BUFF_CMD_SET(unit->buffer, 1);425ng_hci_send_command(unit);426} else427NG_HCI_ALERT(428"%s: %s - no pending command\n", __func__, NG_NODE_NAME(unit->node));429} /* ng_hci_process_command_timeout */430431/*432* Process link command return parameters433*/434435static int436process_link_control_params(ng_hci_unit_p unit, u_int16_t ocf,437struct mbuf *mcp, struct mbuf *mrp)438{439int error = 0;440441switch (ocf) {442case NG_HCI_OCF_INQUIRY_CANCEL:443case NG_HCI_OCF_PERIODIC_INQUIRY:444case NG_HCI_OCF_EXIT_PERIODIC_INQUIRY:445case NG_HCI_OCF_LINK_KEY_REP:446case NG_HCI_OCF_LINK_KEY_NEG_REP:447case NG_HCI_OCF_PIN_CODE_REP:448case NG_HCI_OCF_PIN_CODE_NEG_REP:449/* These do not need post processing */450break;451452case NG_HCI_OCF_INQUIRY:453case NG_HCI_OCF_CREATE_CON:454case NG_HCI_OCF_DISCON:455case NG_HCI_OCF_ADD_SCO_CON:456case NG_HCI_OCF_ACCEPT_CON:457case NG_HCI_OCF_REJECT_CON:458case NG_HCI_OCF_CHANGE_CON_PKT_TYPE:459case NG_HCI_OCF_AUTH_REQ:460case NG_HCI_OCF_SET_CON_ENCRYPTION:461case NG_HCI_OCF_CHANGE_CON_LINK_KEY:462case NG_HCI_OCF_MASTER_LINK_KEY:463case NG_HCI_OCF_REMOTE_NAME_REQ:464case NG_HCI_OCF_READ_REMOTE_FEATURES:465case NG_HCI_OCF_READ_REMOTE_VER_INFO:466case NG_HCI_OCF_READ_CLOCK_OFFSET:467default:468469/*470* None of these command was supposed to generate471* Command_Complete event. Instead Command_Status event472* should have been generated and then appropriate event473* should have been sent to indicate the final result.474*/475476error = EINVAL;477break;478}479480NG_FREE_M(mcp);481NG_FREE_M(mrp);482483return (error);484} /* process_link_control_params */485486/*487* Process link policy command return parameters488*/489490static int491process_link_policy_params(ng_hci_unit_p unit, u_int16_t ocf,492struct mbuf *mcp, struct mbuf *mrp)493{494int error = 0;495496switch (ocf){497case NG_HCI_OCF_ROLE_DISCOVERY: {498ng_hci_role_discovery_rp *rp = NULL;499ng_hci_unit_con_t *con = NULL;500u_int16_t h;501502NG_HCI_M_PULLUP(mrp, sizeof(*rp));503if (mrp != NULL) {504rp = mtod(mrp, ng_hci_role_discovery_rp *);505506h = NG_HCI_CON_HANDLE(le16toh(rp->con_handle));507con = ng_hci_con_by_handle(unit, h);508if (con == NULL) {509NG_HCI_ALERT(510"%s: %s - invalid connection handle=%d\n",511__func__, NG_NODE_NAME(unit->node), h);512error = ENOENT;513} else if (con->link_type != NG_HCI_LINK_ACL) {514NG_HCI_ALERT(515"%s: %s - invalid link type=%d\n", __func__, NG_NODE_NAME(unit->node),516con->link_type);517error = EINVAL;518} else519con->role = rp->role;520} else521error = ENOBUFS;522} break;523524case NG_HCI_OCF_READ_LINK_POLICY_SETTINGS:525case NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS:526/* These do not need post processing */527break;528529case NG_HCI_OCF_HOLD_MODE:530case NG_HCI_OCF_SNIFF_MODE:531case NG_HCI_OCF_EXIT_SNIFF_MODE:532case NG_HCI_OCF_PARK_MODE:533case NG_HCI_OCF_EXIT_PARK_MODE:534case NG_HCI_OCF_QOS_SETUP:535case NG_HCI_OCF_SWITCH_ROLE:536default:537538/*539* None of these command was supposed to generate540* Command_Complete event. Instead Command_Status event541* should have been generated and then appropriate event542* should have been sent to indicate the final result.543*/544545error = EINVAL;546break;547}548549NG_FREE_M(mcp);550NG_FREE_M(mrp);551552return (error);553} /* process_link_policy_params */554555/*556* Process HC and baseband command return parameters557*/558559int560process_hc_baseband_params(ng_hci_unit_p unit, u_int16_t ocf,561struct mbuf *mcp, struct mbuf *mrp)562{563int error = 0;564565switch (ocf) {566case NG_HCI_OCF_SET_EVENT_MASK:567case NG_HCI_OCF_SET_EVENT_FILTER:568case NG_HCI_OCF_FLUSH: /* XXX Do we need to handle that? */569case NG_HCI_OCF_READ_PIN_TYPE:570case NG_HCI_OCF_WRITE_PIN_TYPE:571case NG_HCI_OCF_CREATE_NEW_UNIT_KEY:572case NG_HCI_OCF_WRITE_STORED_LINK_KEY:573case NG_HCI_OCF_WRITE_CON_ACCEPT_TIMO:574case NG_HCI_OCF_WRITE_PAGE_TIMO:575case NG_HCI_OCF_READ_SCAN_ENABLE:576case NG_HCI_OCF_WRITE_SCAN_ENABLE:577case NG_HCI_OCF_WRITE_PAGE_SCAN_ACTIVITY:578case NG_HCI_OCF_WRITE_INQUIRY_SCAN_ACTIVITY:579case NG_HCI_OCF_READ_AUTH_ENABLE:580case NG_HCI_OCF_WRITE_AUTH_ENABLE:581case NG_HCI_OCF_READ_ENCRYPTION_MODE:582case NG_HCI_OCF_WRITE_ENCRYPTION_MODE:583case NG_HCI_OCF_WRITE_VOICE_SETTINGS:584case NG_HCI_OCF_READ_NUM_BROADCAST_RETRANS:585case NG_HCI_OCF_WRITE_NUM_BROADCAST_RETRANS:586case NG_HCI_OCF_READ_HOLD_MODE_ACTIVITY:587case NG_HCI_OCF_WRITE_HOLD_MODE_ACTIVITY:588case NG_HCI_OCF_READ_SCO_FLOW_CONTROL:589case NG_HCI_OCF_WRITE_SCO_FLOW_CONTROL:590case NG_HCI_OCF_H2HC_FLOW_CONTROL: /* XXX Not supported this time */591case NG_HCI_OCF_HOST_BUFFER_SIZE:592case NG_HCI_OCF_READ_IAC_LAP:593case NG_HCI_OCF_WRITE_IAC_LAP:594case NG_HCI_OCF_READ_PAGE_SCAN_PERIOD:595case NG_HCI_OCF_WRITE_PAGE_SCAN_PERIOD:596case NG_HCI_OCF_READ_PAGE_SCAN:597case NG_HCI_OCF_WRITE_PAGE_SCAN:598case NG_HCI_OCF_READ_LINK_SUPERVISION_TIMO:599case NG_HCI_OCF_WRITE_LINK_SUPERVISION_TIMO:600case NG_HCI_OCF_READ_SUPPORTED_IAC_NUM:601case NG_HCI_OCF_READ_STORED_LINK_KEY:602case NG_HCI_OCF_DELETE_STORED_LINK_KEY:603case NG_HCI_OCF_READ_CON_ACCEPT_TIMO:604case NG_HCI_OCF_READ_PAGE_TIMO:605case NG_HCI_OCF_READ_PAGE_SCAN_ACTIVITY:606case NG_HCI_OCF_READ_INQUIRY_SCAN_ACTIVITY:607case NG_HCI_OCF_READ_VOICE_SETTINGS:608case NG_HCI_OCF_READ_AUTO_FLUSH_TIMO:609case NG_HCI_OCF_WRITE_AUTO_FLUSH_TIMO:610case NG_HCI_OCF_READ_XMIT_LEVEL:611case NG_HCI_OCF_HOST_NUM_COMPL_PKTS: /* XXX Can get here? */612case NG_HCI_OCF_CHANGE_LOCAL_NAME:613case NG_HCI_OCF_READ_LOCAL_NAME:614case NG_HCI_OCF_READ_UNIT_CLASS:615case NG_HCI_OCF_WRITE_UNIT_CLASS:616case NG_HCI_OCF_WRITE_SIMPLE_PAIRING:617case NG_HCI_OCF_READ_LE_HOST_SUPPORTED:618case NG_HCI_OCF_WRITE_LE_HOST_SUPPORTED:619case NG_HCI_OCF_WRITE_SECURE_CONNECTIONS_HOST_SUPPORT:620/* These do not need post processing */621break;622623case NG_HCI_OCF_RESET: {624ng_hci_unit_con_p con = NULL;625int size;626627/*628* XXX629*630* After RESET command unit goes into standby mode631* and all operational state is lost. Host controller632* will revert to default values for all parameters.633*634* For now we shall terminate all connections and drop635* inited bit. After RESET unit must be re-initialized.636*/637638while (!LIST_EMPTY(&unit->con_list)) {639con = LIST_FIRST(&unit->con_list);640641/* Remove all timeouts (if any) */642if (con->flags & NG_HCI_CON_TIMEOUT_PENDING)643ng_hci_con_untimeout(con);644645/* Connection terminated by local host */646ng_hci_lp_discon_ind(con, 0x16);647ng_hci_free_con(con);648}649650NG_HCI_BUFF_ACL_TOTAL(unit->buffer, size);651NG_HCI_BUFF_ACL_FREE(unit->buffer, size);652653NG_HCI_BUFF_SCO_TOTAL(unit->buffer, size);654NG_HCI_BUFF_SCO_FREE(unit->buffer, size);655656unit->state &= ~NG_HCI_UNIT_INITED;657} break;658659default:660error = EINVAL;661break;662}663664NG_FREE_M(mcp);665NG_FREE_M(mrp);666667return (error);668} /* process_hc_baseband_params */669670/*671* Process info command return parameters672*/673674static int675process_info_params(ng_hci_unit_p unit, u_int16_t ocf, struct mbuf *mcp,676struct mbuf *mrp)677{678int error = 0, len;679680switch (ocf) {681case NG_HCI_OCF_READ_LOCAL_VER:682case NG_HCI_OCF_READ_COUNTRY_CODE:683break;684685case NG_HCI_OCF_READ_LOCAL_FEATURES:686m_adj(mrp, sizeof(u_int8_t));687len = min(mrp->m_pkthdr.len, sizeof(unit->features));688m_copydata(mrp, 0, len, (caddr_t) unit->features);689break;690691case NG_HCI_OCF_READ_BUFFER_SIZE: {692ng_hci_read_buffer_size_rp *rp = NULL;693694/* Do not update buffer descriptor if node was initialized */695if ((unit->state & NG_HCI_UNIT_READY) == NG_HCI_UNIT_READY)696break;697698NG_HCI_M_PULLUP(mrp, sizeof(*rp));699if (mrp != NULL) {700rp = mtod(mrp, ng_hci_read_buffer_size_rp *);701702NG_HCI_BUFF_ACL_SET(703unit->buffer,704le16toh(rp->num_acl_pkt), /* number */705le16toh(rp->max_acl_size), /* size */706le16toh(rp->num_acl_pkt) /* free */707);708709NG_HCI_BUFF_SCO_SET(710unit->buffer,711le16toh(rp->num_sco_pkt), /* number */712rp->max_sco_size, /* size */713le16toh(rp->num_sco_pkt) /* free */714);715716/* Let upper layers know */717ng_hci_node_is_up(unit->node, unit->acl, NULL, 0);718ng_hci_node_is_up(unit->node, unit->sco, NULL, 0);719} else720error = ENOBUFS;721} break;722723case NG_HCI_OCF_READ_BDADDR:724/* Do not update BD_ADDR if node was initialized */725if ((unit->state & NG_HCI_UNIT_READY) == NG_HCI_UNIT_READY)726break;727728m_adj(mrp, sizeof(u_int8_t));729len = min(mrp->m_pkthdr.len, sizeof(unit->bdaddr));730m_copydata(mrp, 0, len, (caddr_t) &unit->bdaddr);731732/* Let upper layers know */733ng_hci_node_is_up(unit->node, unit->acl, NULL, 0);734ng_hci_node_is_up(unit->node, unit->sco, NULL, 0);735break;736737default:738error = EINVAL;739break;740}741742NG_FREE_M(mcp);743NG_FREE_M(mrp);744745return (error);746} /* process_info_params */747748/*749* Process status command return parameters750*/751752static int753process_status_params(ng_hci_unit_p unit, u_int16_t ocf, struct mbuf *mcp,754struct mbuf *mrp)755{756int error = 0;757758switch (ocf) {759case NG_HCI_OCF_READ_FAILED_CONTACT_CNTR:760case NG_HCI_OCF_RESET_FAILED_CONTACT_CNTR:761case NG_HCI_OCF_GET_LINK_QUALITY:762case NG_HCI_OCF_READ_RSSI:763/* These do not need post processing */764break;765766default:767error = EINVAL;768break;769}770771NG_FREE_M(mcp);772NG_FREE_M(mrp);773774return (error);775} /* process_status_params */776777/*778* Process testing command return parameters779*/780781int782process_testing_params(ng_hci_unit_p unit, u_int16_t ocf, struct mbuf *mcp,783struct mbuf *mrp)784{785int error = 0;786787switch (ocf) {788/*789* XXX FIXME790* We do not support these features at this time. However,791* HCI node could support this and do something smart. At least792* node can change unit state.793*/794795case NG_HCI_OCF_READ_LOOPBACK_MODE:796case NG_HCI_OCF_WRITE_LOOPBACK_MODE:797case NG_HCI_OCF_ENABLE_UNIT_UNDER_TEST:798break;799800default:801error = EINVAL;802break;803}804805NG_FREE_M(mcp);806NG_FREE_M(mrp);807808return (error);809} /* process_testing_params */810811/*812* Process LE command return parameters813*/814815static int816process_le_params(ng_hci_unit_p unit, u_int16_t ocf,817struct mbuf *mcp, struct mbuf *mrp)818{819int error = 0;820821switch (ocf){822case NG_HCI_OCF_LE_SET_EVENT_MASK:823case NG_HCI_OCF_LE_READ_BUFFER_SIZE:824case NG_HCI_OCF_LE_READ_LOCAL_SUPPORTED_FEATURES:825case NG_HCI_OCF_LE_SET_RANDOM_ADDRESS:826case NG_HCI_OCF_LE_SET_ADVERTISING_PARAMETERS:827case NG_HCI_OCF_LE_READ_ADVERTISING_CHANNEL_TX_POWER:828case NG_HCI_OCF_LE_SET_ADVERTISING_DATA:829case NG_HCI_OCF_LE_SET_SCAN_RESPONSE_DATA:830case NG_HCI_OCF_LE_SET_ADVERTISE_ENABLE:831case NG_HCI_OCF_LE_SET_SCAN_PARAMETERS:832case NG_HCI_OCF_LE_SET_SCAN_ENABLE:833case NG_HCI_OCF_LE_CREATE_CONNECTION_CANCEL:834case NG_HCI_OCF_LE_CLEAR_WHITE_LIST:835case NG_HCI_OCF_LE_READ_WHITE_LIST_SIZE:836case NG_HCI_OCF_LE_ADD_DEVICE_TO_WHITE_LIST:837case NG_HCI_OCF_LE_REMOVE_DEVICE_FROM_WHITE_LIST:838case NG_HCI_OCF_LE_SET_HOST_CHANNEL_CLASSIFICATION:839case NG_HCI_OCF_LE_READ_CHANNEL_MAP:840case NG_HCI_OCF_LE_ENCRYPT:841case NG_HCI_OCF_LE_RAND:842case NG_HCI_OCF_LE_LONG_TERM_KEY_REQUEST_REPLY:843case NG_HCI_OCF_LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY:844case NG_HCI_OCF_LE_READ_SUPPORTED_STATES:845case NG_HCI_OCF_LE_RECEIVER_TEST:846case NG_HCI_OCF_LE_TRANSMITTER_TEST:847case NG_HCI_OCF_LE_TEST_END:848849/* These do not need post processing */850break;851case NG_HCI_OCF_LE_CREATE_CONNECTION:852case NG_HCI_OCF_LE_CONNECTION_UPDATE:853case NG_HCI_OCF_LE_READ_REMOTE_USED_FEATURES:854case NG_HCI_OCF_LE_START_ENCRYPTION:855856default:857/*858* None of these command was supposed to generate859* Command_Complete event. Instead Command_Status event860* should have been generated and then appropriate event861* should have been sent to indicate the final result.862*/863864error = EINVAL;865break;866}867868NG_FREE_M(mcp);869NG_FREE_M(mrp);870871return (error);872873}874875static int876process_le_status(ng_hci_unit_p unit,ng_hci_command_status_ep *ep,877struct mbuf *mcp)878{879int error = 0;880881switch (NG_HCI_OCF(ep->opcode)){882case NG_HCI_OCF_LE_CREATE_CONNECTION:883case NG_HCI_OCF_LE_CONNECTION_UPDATE:884case NG_HCI_OCF_LE_READ_REMOTE_USED_FEATURES:885case NG_HCI_OCF_LE_START_ENCRYPTION:886887/* These do not need post processing */888break;889890case NG_HCI_OCF_LE_SET_EVENT_MASK:891case NG_HCI_OCF_LE_READ_BUFFER_SIZE:892case NG_HCI_OCF_LE_READ_LOCAL_SUPPORTED_FEATURES:893case NG_HCI_OCF_LE_SET_RANDOM_ADDRESS:894case NG_HCI_OCF_LE_SET_ADVERTISING_PARAMETERS:895case NG_HCI_OCF_LE_READ_ADVERTISING_CHANNEL_TX_POWER:896case NG_HCI_OCF_LE_SET_ADVERTISING_DATA:897case NG_HCI_OCF_LE_SET_SCAN_RESPONSE_DATA:898case NG_HCI_OCF_LE_SET_ADVERTISE_ENABLE:899case NG_HCI_OCF_LE_SET_SCAN_PARAMETERS:900case NG_HCI_OCF_LE_SET_SCAN_ENABLE:901case NG_HCI_OCF_LE_CREATE_CONNECTION_CANCEL:902case NG_HCI_OCF_LE_CLEAR_WHITE_LIST:903case NG_HCI_OCF_LE_READ_WHITE_LIST_SIZE:904case NG_HCI_OCF_LE_ADD_DEVICE_TO_WHITE_LIST:905case NG_HCI_OCF_LE_REMOVE_DEVICE_FROM_WHITE_LIST:906case NG_HCI_OCF_LE_SET_HOST_CHANNEL_CLASSIFICATION:907case NG_HCI_OCF_LE_READ_CHANNEL_MAP:908case NG_HCI_OCF_LE_ENCRYPT:909case NG_HCI_OCF_LE_RAND:910case NG_HCI_OCF_LE_LONG_TERM_KEY_REQUEST_REPLY:911case NG_HCI_OCF_LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY:912case NG_HCI_OCF_LE_READ_SUPPORTED_STATES:913case NG_HCI_OCF_LE_RECEIVER_TEST:914case NG_HCI_OCF_LE_TRANSMITTER_TEST:915case NG_HCI_OCF_LE_TEST_END:916917default:918/*919* None of these command was supposed to generate920* Command_Stutus event. Command Complete instead.921*/922923error = EINVAL;924break;925}926927NG_FREE_M(mcp);928929return (error);930931}932933/*934* Process link control command status935*/936937static int938process_link_control_status(ng_hci_unit_p unit, ng_hci_command_status_ep *ep,939struct mbuf *mcp)940{941int error = 0;942943switch (NG_HCI_OCF(ep->opcode)) {944case NG_HCI_OCF_INQUIRY:945case NG_HCI_OCF_DISCON: /* XXX */946case NG_HCI_OCF_REJECT_CON: /* XXX */947case NG_HCI_OCF_CHANGE_CON_PKT_TYPE:948case NG_HCI_OCF_AUTH_REQ:949case NG_HCI_OCF_SET_CON_ENCRYPTION:950case NG_HCI_OCF_CHANGE_CON_LINK_KEY:951case NG_HCI_OCF_MASTER_LINK_KEY:952case NG_HCI_OCF_REMOTE_NAME_REQ:953case NG_HCI_OCF_READ_REMOTE_FEATURES:954case NG_HCI_OCF_READ_REMOTE_VER_INFO:955case NG_HCI_OCF_READ_CLOCK_OFFSET:956/* These do not need post processing */957break;958959case NG_HCI_OCF_CREATE_CON:960break;961962case NG_HCI_OCF_ADD_SCO_CON:963break;964965case NG_HCI_OCF_ACCEPT_CON:966break;967968case NG_HCI_OCF_INQUIRY_CANCEL:969case NG_HCI_OCF_PERIODIC_INQUIRY:970case NG_HCI_OCF_EXIT_PERIODIC_INQUIRY:971case NG_HCI_OCF_LINK_KEY_REP:972case NG_HCI_OCF_LINK_KEY_NEG_REP:973case NG_HCI_OCF_PIN_CODE_REP:974case NG_HCI_OCF_PIN_CODE_NEG_REP:975default:976977/*978* None of these command was supposed to generate979* Command_Status event. Instead Command_Complete event980* should have been sent.981*/982983error = EINVAL;984break;985}986987NG_FREE_M(mcp);988989return (error);990} /* process_link_control_status */991992/*993* Process link policy command status994*/995996static int997process_link_policy_status(ng_hci_unit_p unit, ng_hci_command_status_ep *ep,998struct mbuf *mcp)999{1000int error = 0;10011002switch (NG_HCI_OCF(ep->opcode)) {1003case NG_HCI_OCF_HOLD_MODE:1004case NG_HCI_OCF_SNIFF_MODE:1005case NG_HCI_OCF_EXIT_SNIFF_MODE:1006case NG_HCI_OCF_PARK_MODE:1007case NG_HCI_OCF_EXIT_PARK_MODE:1008case NG_HCI_OCF_SWITCH_ROLE:1009/* These do not need post processing */1010break;10111012case NG_HCI_OCF_QOS_SETUP:1013break;10141015case NG_HCI_OCF_ROLE_DISCOVERY:1016case NG_HCI_OCF_READ_LINK_POLICY_SETTINGS:1017case NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS:1018default:10191020/*1021* None of these command was supposed to generate1022* Command_Status event. Instead Command_Complete event1023* should have been sent.1024*/10251026error = EINVAL;1027break;1028}10291030NG_FREE_M(mcp);10311032return (error);1033} /* process_link_policy_status */103410351036