1107120Sjulian/* 2107120Sjulian * ng_hci_cmds.c 3139823Simp */ 4139823Simp 5139823Simp/*- 6107120Sjulian * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com> 7107120Sjulian * All rights reserved. 8107120Sjulian * 9107120Sjulian * Redistribution and use in source and binary forms, with or without 10107120Sjulian * modification, are permitted provided that the following conditions 11107120Sjulian * are met: 12107120Sjulian * 1. Redistributions of source code must retain the above copyright 13107120Sjulian * notice, this list of conditions and the following disclaimer. 14107120Sjulian * 2. Redistributions in binary form must reproduce the above copyright 15107120Sjulian * notice, this list of conditions and the following disclaimer in the 16107120Sjulian * documentation and/or other materials provided with the distribution. 17107120Sjulian * 18107120Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19107120Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20107120Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21107120Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22107120Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23107120Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24107120Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25107120Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26107120Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27107120Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28107120Sjulian * SUCH DAMAGE. 29107120Sjulian * 30121054Semax * $Id: ng_hci_cmds.c,v 1.4 2003/09/08 18:57:51 max Exp $ 31107120Sjulian * $FreeBSD$ 32107120Sjulian */ 33107120Sjulian 34107120Sjulian#include <sys/param.h> 35107120Sjulian#include <sys/systm.h> 36107120Sjulian#include <sys/kernel.h> 37107120Sjulian#include <sys/endian.h> 38107120Sjulian#include <sys/malloc.h> 39107120Sjulian#include <sys/mbuf.h> 40107120Sjulian#include <sys/queue.h> 41107120Sjulian#include <netgraph/ng_message.h> 42107120Sjulian#include <netgraph/netgraph.h> 43128688Semax#include <netgraph/bluetooth/include/ng_bluetooth.h> 44128688Semax#include <netgraph/bluetooth/include/ng_hci.h> 45128688Semax#include <netgraph/bluetooth/hci/ng_hci_var.h> 46128688Semax#include <netgraph/bluetooth/hci/ng_hci_cmds.h> 47128688Semax#include <netgraph/bluetooth/hci/ng_hci_evnt.h> 48128688Semax#include <netgraph/bluetooth/hci/ng_hci_ulpi.h> 49128688Semax#include <netgraph/bluetooth/hci/ng_hci_misc.h> 50107120Sjulian 51107120Sjulian/****************************************************************************** 52107120Sjulian ****************************************************************************** 53107120Sjulian ** HCI commands processing module 54107120Sjulian ****************************************************************************** 55107120Sjulian ******************************************************************************/ 56107120Sjulian 57107120Sjulian#undef min 58107120Sjulian#define min(a, b) ((a) < (b))? (a) : (b) 59107120Sjulian 60107120Sjulianstatic int complete_command (ng_hci_unit_p, int, struct mbuf **); 61107120Sjulian 62107120Sjulianstatic int process_link_control_params 63107120Sjulian (ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *); 64107120Sjulianstatic int process_link_policy_params 65107120Sjulian (ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *); 66107120Sjulianstatic int process_hc_baseband_params 67107120Sjulian (ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *); 68107120Sjulianstatic int process_info_params 69107120Sjulian (ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *); 70107120Sjulianstatic int process_status_params 71107120Sjulian (ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *); 72107120Sjulianstatic int process_testing_params 73107120Sjulian (ng_hci_unit_p, u_int16_t, struct mbuf *, struct mbuf *); 74107120Sjulian 75107120Sjulianstatic int process_link_control_status 76107120Sjulian (ng_hci_unit_p, ng_hci_command_status_ep *, struct mbuf *); 77107120Sjulianstatic int process_link_policy_status 78107120Sjulian (ng_hci_unit_p, ng_hci_command_status_ep *, struct mbuf *); 79107120Sjulian 80107120Sjulian/* 81107120Sjulian * Send HCI command to the driver. 82107120Sjulian */ 83107120Sjulian 84107120Sjulianint 85107120Sjulianng_hci_send_command(ng_hci_unit_p unit) 86107120Sjulian{ 87107120Sjulian struct mbuf *m0 = NULL, *m = NULL; 88107120Sjulian int free, error = 0; 89107120Sjulian 90107120Sjulian /* Check if other command is pending */ 91107120Sjulian if (unit->state & NG_HCI_UNIT_COMMAND_PENDING) 92107120Sjulian return (0); 93107120Sjulian 94107120Sjulian /* Check if unit can accept our command */ 95107120Sjulian NG_HCI_BUFF_CMD_GET(unit->buffer, free); 96107120Sjulian if (free == 0) 97107120Sjulian return (0); 98107120Sjulian 99107120Sjulian /* Check if driver hook is still ok */ 100107120Sjulian if (unit->drv == NULL || NG_HOOK_NOT_VALID(unit->drv)) { 101107120Sjulian NG_HCI_WARN( 102107120Sjulian"%s: %s - hook \"%s\" is not connected or valid\n", 103107120Sjulian __func__, NG_NODE_NAME(unit->node), NG_HCI_HOOK_DRV); 104107120Sjulian 105107120Sjulian NG_BT_MBUFQ_DRAIN(&unit->cmdq); 106107120Sjulian 107107120Sjulian return (ENOTCONN); 108107120Sjulian } 109107120Sjulian 110107120Sjulian /* 111107120Sjulian * Get first command from queue, give it to RAW hook then 112107120Sjulian * make copy of it and send it to the driver 113107120Sjulian */ 114107120Sjulian 115107120Sjulian m0 = NG_BT_MBUFQ_FIRST(&unit->cmdq); 116107120Sjulian if (m0 == NULL) 117107120Sjulian return (0); 118107120Sjulian 119107120Sjulian ng_hci_mtap(unit, m0); 120107120Sjulian 121243882Sglebius m = m_dup(m0, M_NOWAIT); 122107120Sjulian if (m != NULL) 123107120Sjulian NG_SEND_DATA_ONLY(error, unit->drv, m); 124107120Sjulian else 125107120Sjulian error = ENOBUFS; 126107120Sjulian 127107120Sjulian if (error != 0) 128107120Sjulian NG_HCI_ERR( 129107120Sjulian"%s: %s - could not send HCI command, error=%d\n", 130107120Sjulian __func__, NG_NODE_NAME(unit->node), error); 131107120Sjulian 132107120Sjulian /* 133107120Sjulian * Even if we were not able to send command we still pretend 134107120Sjulian * that everything is OK and let timeout handle that. 135107120Sjulian */ 136107120Sjulian 137107120Sjulian NG_HCI_BUFF_CMD_USE(unit->buffer, 1); 138107120Sjulian NG_HCI_STAT_CMD_SENT(unit->stat); 139107120Sjulian NG_HCI_STAT_BYTES_SENT(unit->stat, m0->m_pkthdr.len); 140107120Sjulian 141107120Sjulian /* 142107120Sjulian * Note: ng_hci_command_timeout() will set 143107120Sjulian * NG_HCI_UNIT_COMMAND_PENDING flag 144107120Sjulian */ 145107120Sjulian 146107120Sjulian ng_hci_command_timeout(unit); 147107120Sjulian 148107120Sjulian return (0); 149107120Sjulian} /* ng_hci_send_command */ 150107120Sjulian 151107120Sjulian/* 152107120Sjulian * Process HCI Command_Compete event. Complete HCI command, and do post 153107120Sjulian * processing on the command parameters (cp) and command return parameters 154107120Sjulian * (e) if required (for example adjust state). 155107120Sjulian */ 156107120Sjulian 157107120Sjulianint 158107120Sjulianng_hci_process_command_complete(ng_hci_unit_p unit, struct mbuf *e) 159107120Sjulian{ 160107120Sjulian ng_hci_command_compl_ep *ep = NULL; 161107120Sjulian struct mbuf *cp = NULL; 162107120Sjulian int error = 0; 163107120Sjulian 164107120Sjulian /* Get event packet and update command buffer info */ 165107120Sjulian NG_HCI_M_PULLUP(e, sizeof(*ep)); 166107120Sjulian if (e == NULL) 167107120Sjulian return (ENOBUFS); /* XXX this is bad */ 168107120Sjulian 169107120Sjulian ep = mtod(e, ng_hci_command_compl_ep *); 170107120Sjulian NG_HCI_BUFF_CMD_SET(unit->buffer, ep->num_cmd_pkts); 171107120Sjulian 172107120Sjulian /* Check for special NOOP command */ 173107120Sjulian if (ep->opcode == 0x0000) { 174107120Sjulian NG_FREE_M(e); 175107120Sjulian goto out; 176107120Sjulian } 177107120Sjulian 178107120Sjulian /* Try to match first command item in the queue */ 179107120Sjulian error = complete_command(unit, ep->opcode, &cp); 180107120Sjulian if (error != 0) { 181107120Sjulian NG_FREE_M(e); 182107120Sjulian goto out; 183107120Sjulian } 184107120Sjulian 185107120Sjulian /* 186107120Sjulian * Perform post processing on command parameters and return parameters 187107120Sjulian * do it only if status is OK (status == 0). Status is the first byte 188107120Sjulian * of any command return parameters. 189107120Sjulian */ 190107120Sjulian 191107120Sjulian ep->opcode = le16toh(ep->opcode); 192107120Sjulian m_adj(e, sizeof(*ep)); 193107120Sjulian 194107120Sjulian if (*mtod(e, u_int8_t *) == 0) { /* XXX m_pullup here? */ 195107120Sjulian switch (NG_HCI_OGF(ep->opcode)) { 196107120Sjulian case NG_HCI_OGF_LINK_CONTROL: 197107120Sjulian error = process_link_control_params(unit, 198107120Sjulian NG_HCI_OCF(ep->opcode), cp, e); 199107120Sjulian break; 200107120Sjulian 201107120Sjulian case NG_HCI_OGF_LINK_POLICY: 202107120Sjulian error = process_link_policy_params(unit, 203107120Sjulian NG_HCI_OCF(ep->opcode), cp, e); 204107120Sjulian break; 205107120Sjulian 206107120Sjulian case NG_HCI_OGF_HC_BASEBAND: 207107120Sjulian error = process_hc_baseband_params(unit, 208107120Sjulian NG_HCI_OCF(ep->opcode), cp, e); 209107120Sjulian break; 210107120Sjulian 211107120Sjulian case NG_HCI_OGF_INFO: 212107120Sjulian error = process_info_params(unit, 213107120Sjulian NG_HCI_OCF(ep->opcode), cp, e); 214107120Sjulian break; 215107120Sjulian 216107120Sjulian case NG_HCI_OGF_STATUS: 217107120Sjulian error = process_status_params(unit, 218107120Sjulian NG_HCI_OCF(ep->opcode), cp, e); 219107120Sjulian break; 220107120Sjulian 221107120Sjulian case NG_HCI_OGF_TESTING: 222107120Sjulian error = process_testing_params(unit, 223107120Sjulian NG_HCI_OCF(ep->opcode), cp, e); 224107120Sjulian break; 225107120Sjulian 226107120Sjulian case NG_HCI_OGF_BT_LOGO: 227107120Sjulian case NG_HCI_OGF_VENDOR: 228107120Sjulian NG_FREE_M(cp); 229107120Sjulian NG_FREE_M(e); 230107120Sjulian break; 231107120Sjulian 232107120Sjulian default: 233107120Sjulian NG_FREE_M(cp); 234107120Sjulian NG_FREE_M(e); 235107120Sjulian error = EINVAL; 236107120Sjulian break; 237107120Sjulian } 238107120Sjulian } else { 239107120Sjulian NG_HCI_ERR( 240107120Sjulian"%s: %s - HCI command failed, OGF=%#x, OCF=%#x, status=%#x\n", 241107120Sjulian __func__, NG_NODE_NAME(unit->node), 242107120Sjulian NG_HCI_OGF(ep->opcode), NG_HCI_OCF(ep->opcode), 243107120Sjulian *mtod(e, u_int8_t *)); 244107120Sjulian 245107120Sjulian NG_FREE_M(cp); 246107120Sjulian NG_FREE_M(e); 247107120Sjulian } 248107120Sjulianout: 249107120Sjulian ng_hci_send_command(unit); 250107120Sjulian 251107120Sjulian return (error); 252107120Sjulian} /* ng_hci_process_command_complete */ 253107120Sjulian 254107120Sjulian/* 255107120Sjulian * Process HCI Command_Status event. Check the status (mst) and do post 256107120Sjulian * processing (if required). 257107120Sjulian */ 258107120Sjulian 259107120Sjulianint 260107120Sjulianng_hci_process_command_status(ng_hci_unit_p unit, struct mbuf *e) 261107120Sjulian{ 262107120Sjulian ng_hci_command_status_ep *ep = NULL; 263107120Sjulian struct mbuf *cp = NULL; 264107120Sjulian int error = 0; 265107120Sjulian 266107120Sjulian /* Update command buffer info */ 267107120Sjulian NG_HCI_M_PULLUP(e, sizeof(*ep)); 268107120Sjulian if (e == NULL) 269107120Sjulian return (ENOBUFS); /* XXX this is bad */ 270107120Sjulian 271107120Sjulian ep = mtod(e, ng_hci_command_status_ep *); 272107120Sjulian NG_HCI_BUFF_CMD_SET(unit->buffer, ep->num_cmd_pkts); 273107120Sjulian 274107120Sjulian /* Check for special NOOP command */ 275107120Sjulian if (ep->opcode == 0x0000) 276107120Sjulian goto out; 277107120Sjulian 278107120Sjulian /* Try to match first command item in the queue */ 279107120Sjulian error = complete_command(unit, ep->opcode, &cp); 280107120Sjulian if (error != 0) 281107120Sjulian goto out; 282107120Sjulian 283107120Sjulian /* 284107120Sjulian * Perform post processing on HCI Command_Status event 285107120Sjulian */ 286107120Sjulian 287107120Sjulian ep->opcode = le16toh(ep->opcode); 288107120Sjulian 289107120Sjulian switch (NG_HCI_OGF(ep->opcode)) { 290107120Sjulian case NG_HCI_OGF_LINK_CONTROL: 291107120Sjulian error = process_link_control_status(unit, ep, cp); 292107120Sjulian break; 293107120Sjulian 294107120Sjulian case NG_HCI_OGF_LINK_POLICY: 295107120Sjulian error = process_link_policy_status(unit, ep, cp); 296107120Sjulian break; 297107120Sjulian 298107120Sjulian case NG_HCI_OGF_BT_LOGO: 299107120Sjulian case NG_HCI_OGF_VENDOR: 300107120Sjulian NG_FREE_M(cp); 301107120Sjulian break; 302107120Sjulian 303107120Sjulian case NG_HCI_OGF_HC_BASEBAND: 304107120Sjulian case NG_HCI_OGF_INFO: 305107120Sjulian case NG_HCI_OGF_STATUS: 306107120Sjulian case NG_HCI_OGF_TESTING: 307107120Sjulian default: 308107120Sjulian NG_FREE_M(cp); 309107120Sjulian error = EINVAL; 310107120Sjulian break; 311107120Sjulian } 312107120Sjulianout: 313107120Sjulian NG_FREE_M(e); 314107120Sjulian ng_hci_send_command(unit); 315107120Sjulian 316107120Sjulian return (error); 317107120Sjulian} /* ng_hci_process_command_status */ 318107120Sjulian 319107120Sjulian/* 320107120Sjulian * Complete queued HCI command. 321107120Sjulian */ 322107120Sjulian 323107120Sjulianstatic int 324107120Sjuliancomplete_command(ng_hci_unit_p unit, int opcode, struct mbuf **cp) 325107120Sjulian{ 326107120Sjulian struct mbuf *m = NULL; 327107120Sjulian 328107120Sjulian /* Check unit state */ 329107120Sjulian if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) { 330107120Sjulian NG_HCI_ALERT( 331107120Sjulian"%s: %s - no pending command, state=%#x\n", 332107120Sjulian __func__, NG_NODE_NAME(unit->node), unit->state); 333107120Sjulian 334107120Sjulian return (EINVAL); 335107120Sjulian } 336107120Sjulian 337107120Sjulian /* Get first command in the queue */ 338107120Sjulian m = NG_BT_MBUFQ_FIRST(&unit->cmdq); 339107120Sjulian if (m == NULL) { 340107120Sjulian NG_HCI_ALERT( 341107120Sjulian"%s: %s - empty command queue?!\n", __func__, NG_NODE_NAME(unit->node)); 342107120Sjulian 343107120Sjulian return (EINVAL); 344107120Sjulian } 345107120Sjulian 346107120Sjulian /* 347107120Sjulian * Match command opcode, if does not match - do nothing and 348107120Sjulian * let timeout handle that. 349107120Sjulian */ 350107120Sjulian 351107120Sjulian if (mtod(m, ng_hci_cmd_pkt_t *)->opcode != opcode) { 352107120Sjulian NG_HCI_ALERT( 353107120Sjulian"%s: %s - command queue is out of sync\n", __func__, NG_NODE_NAME(unit->node)); 354107120Sjulian 355107120Sjulian return (EINVAL); 356107120Sjulian } 357107120Sjulian 358107120Sjulian /* 359107120Sjulian * Now we can remove command timeout, dequeue completed command 360121054Semax * and return command parameters. ng_hci_command_untimeout will 361121054Semax * drop NG_HCI_UNIT_COMMAND_PENDING flag. 362121054Semax * Note: if ng_hci_command_untimeout() fails (returns non-zero) 363121054Semax * then timeout aready happened and timeout message went info node 364121054Semax * queue. In this case we ignore command completion and pretend 365121054Semax * there is a timeout. 366107120Sjulian */ 367107120Sjulian 368121054Semax if (ng_hci_command_untimeout(unit) != 0) 369121054Semax return (ETIMEDOUT); 370121054Semax 371107120Sjulian NG_BT_MBUFQ_DEQUEUE(&unit->cmdq, *cp); 372107120Sjulian m_adj(*cp, sizeof(ng_hci_cmd_pkt_t)); 373107120Sjulian 374107120Sjulian return (0); 375107120Sjulian} /* complete_command */ 376107120Sjulian 377107120Sjulian/* 378107120Sjulian * Process HCI command timeout 379107120Sjulian */ 380107120Sjulian 381107120Sjulianvoid 382107120Sjulianng_hci_process_command_timeout(node_p node, hook_p hook, void *arg1, int arg2) 383107120Sjulian{ 384121054Semax ng_hci_unit_p unit = NULL; 385107120Sjulian struct mbuf *m = NULL; 386107120Sjulian u_int16_t opcode; 387107120Sjulian 388121054Semax if (NG_NODE_NOT_VALID(node)) { 389121054Semax printf("%s: Netgraph node is not valid\n", __func__); 390121054Semax return; 391121054Semax } 392121054Semax 393121054Semax unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node); 394121054Semax 395107120Sjulian if (unit->state & NG_HCI_UNIT_COMMAND_PENDING) { 396121054Semax unit->state &= ~NG_HCI_UNIT_COMMAND_PENDING; 397121054Semax 398107120Sjulian NG_BT_MBUFQ_DEQUEUE(&unit->cmdq, m); 399107120Sjulian if (m == NULL) { 400121054Semax NG_HCI_ALERT( 401121054Semax"%s: %s - command queue is out of sync!\n", __func__, NG_NODE_NAME(unit->node)); 402107120Sjulian 403107120Sjulian return; 404107120Sjulian } 405107120Sjulian 406107120Sjulian opcode = le16toh(mtod(m, ng_hci_cmd_pkt_t *)->opcode); 407107120Sjulian NG_FREE_M(m); 408107120Sjulian 409107120Sjulian NG_HCI_ERR( 410107120Sjulian"%s: %s - unable to complete HCI command OGF=%#x, OCF=%#x. Timeout\n", 411107120Sjulian __func__, NG_NODE_NAME(unit->node), NG_HCI_OGF(opcode), 412107120Sjulian NG_HCI_OCF(opcode)); 413107120Sjulian 414121054Semax /* Try to send more commands */ 415107120Sjulian NG_HCI_BUFF_CMD_SET(unit->buffer, 1); 416107120Sjulian ng_hci_send_command(unit); 417107120Sjulian } else 418121054Semax NG_HCI_ALERT( 419121054Semax"%s: %s - no pending command\n", __func__, NG_NODE_NAME(unit->node)); 420107120Sjulian} /* ng_hci_process_command_timeout */ 421107120Sjulian 422107120Sjulian/* 423107120Sjulian * Process link command return parameters 424107120Sjulian */ 425107120Sjulian 426107120Sjulianstatic int 427107120Sjulianprocess_link_control_params(ng_hci_unit_p unit, u_int16_t ocf, 428107120Sjulian struct mbuf *mcp, struct mbuf *mrp) 429107120Sjulian{ 430107120Sjulian int error = 0; 431107120Sjulian 432107120Sjulian switch (ocf) { 433107120Sjulian case NG_HCI_OCF_INQUIRY_CANCEL: 434107120Sjulian case NG_HCI_OCF_PERIODIC_INQUIRY: 435107120Sjulian case NG_HCI_OCF_EXIT_PERIODIC_INQUIRY: 436107120Sjulian case NG_HCI_OCF_LINK_KEY_REP: 437107120Sjulian case NG_HCI_OCF_LINK_KEY_NEG_REP: 438107120Sjulian case NG_HCI_OCF_PIN_CODE_REP: 439107120Sjulian case NG_HCI_OCF_PIN_CODE_NEG_REP: 440107120Sjulian /* These do not need post processing */ 441107120Sjulian break; 442107120Sjulian 443107120Sjulian case NG_HCI_OCF_INQUIRY: 444107120Sjulian case NG_HCI_OCF_CREATE_CON: 445107120Sjulian case NG_HCI_OCF_DISCON: 446107120Sjulian case NG_HCI_OCF_ADD_SCO_CON: 447107120Sjulian case NG_HCI_OCF_ACCEPT_CON: 448107120Sjulian case NG_HCI_OCF_REJECT_CON: 449107120Sjulian case NG_HCI_OCF_CHANGE_CON_PKT_TYPE: 450107120Sjulian case NG_HCI_OCF_AUTH_REQ: 451107120Sjulian case NG_HCI_OCF_SET_CON_ENCRYPTION: 452107120Sjulian case NG_HCI_OCF_CHANGE_CON_LINK_KEY: 453107120Sjulian case NG_HCI_OCF_MASTER_LINK_KEY: 454107120Sjulian case NG_HCI_OCF_REMOTE_NAME_REQ: 455107120Sjulian case NG_HCI_OCF_READ_REMOTE_FEATURES: 456107120Sjulian case NG_HCI_OCF_READ_REMOTE_VER_INFO: 457107120Sjulian case NG_HCI_OCF_READ_CLOCK_OFFSET: 458107120Sjulian default: 459107120Sjulian 460107120Sjulian /* 461107120Sjulian * None of these command was supposed to generate 462107120Sjulian * Command_Complete event. Instead Command_Status event 463107120Sjulian * should have been generated and then appropriate event 464107120Sjulian * should have been sent to indicate the final result. 465107120Sjulian */ 466107120Sjulian 467107120Sjulian error = EINVAL; 468107120Sjulian break; 469107120Sjulian } 470107120Sjulian 471107120Sjulian NG_FREE_M(mcp); 472107120Sjulian NG_FREE_M(mrp); 473107120Sjulian 474107120Sjulian return (error); 475107120Sjulian} /* process_link_control_params */ 476107120Sjulian 477107120Sjulian/* 478107120Sjulian * Process link policy command return parameters 479107120Sjulian */ 480107120Sjulian 481107120Sjulianstatic int 482107120Sjulianprocess_link_policy_params(ng_hci_unit_p unit, u_int16_t ocf, 483107120Sjulian struct mbuf *mcp, struct mbuf *mrp) 484107120Sjulian{ 485107120Sjulian int error = 0; 486107120Sjulian 487107120Sjulian switch (ocf){ 488107120Sjulian case NG_HCI_OCF_ROLE_DISCOVERY: { 489107120Sjulian ng_hci_role_discovery_rp *rp = NULL; 490107120Sjulian ng_hci_unit_con_t *con = NULL; 491107120Sjulian u_int16_t h; 492107120Sjulian 493107120Sjulian NG_HCI_M_PULLUP(mrp, sizeof(*rp)); 494107120Sjulian if (mrp != NULL) { 495107120Sjulian rp = mtod(mrp, ng_hci_role_discovery_rp *); 496107120Sjulian 497107120Sjulian h = NG_HCI_CON_HANDLE(le16toh(rp->con_handle)); 498107120Sjulian con = ng_hci_con_by_handle(unit, h); 499107120Sjulian if (con == NULL) { 500107120Sjulian NG_HCI_ALERT( 501107120Sjulian"%s: %s - invalid connection handle=%d\n", 502107120Sjulian __func__, NG_NODE_NAME(unit->node), h); 503107120Sjulian error = ENOENT; 504107120Sjulian } else if (con->link_type != NG_HCI_LINK_ACL) { 505107120Sjulian NG_HCI_ALERT( 506107120Sjulian"%s: %s - invalid link type=%d\n", __func__, NG_NODE_NAME(unit->node), 507107120Sjulian con->link_type); 508107120Sjulian error = EINVAL; 509107120Sjulian } else 510107120Sjulian con->role = rp->role; 511107120Sjulian } else 512107120Sjulian error = ENOBUFS; 513107120Sjulian } break; 514107120Sjulian 515107120Sjulian case NG_HCI_OCF_READ_LINK_POLICY_SETTINGS: 516107120Sjulian case NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS: 517107120Sjulian /* These do not need post processing */ 518107120Sjulian break; 519107120Sjulian 520107120Sjulian case NG_HCI_OCF_HOLD_MODE: 521107120Sjulian case NG_HCI_OCF_SNIFF_MODE: 522107120Sjulian case NG_HCI_OCF_EXIT_SNIFF_MODE: 523107120Sjulian case NG_HCI_OCF_PARK_MODE: 524107120Sjulian case NG_HCI_OCF_EXIT_PARK_MODE: 525107120Sjulian case NG_HCI_OCF_QOS_SETUP: 526107120Sjulian case NG_HCI_OCF_SWITCH_ROLE: 527107120Sjulian default: 528107120Sjulian 529107120Sjulian /* 530107120Sjulian * None of these command was supposed to generate 531107120Sjulian * Command_Complete event. Instead Command_Status event 532107120Sjulian * should have been generated and then appropriate event 533107120Sjulian * should have been sent to indicate the final result. 534107120Sjulian */ 535107120Sjulian 536107120Sjulian error = EINVAL; 537107120Sjulian break; 538107120Sjulian } 539107120Sjulian 540107120Sjulian NG_FREE_M(mcp); 541107120Sjulian NG_FREE_M(mrp); 542107120Sjulian 543107120Sjulian return (error); 544107120Sjulian} /* process_link_policy_params */ 545107120Sjulian 546107120Sjulian/* 547107120Sjulian * Process HC and baseband command return parameters 548107120Sjulian */ 549107120Sjulian 550107120Sjulianint 551107120Sjulianprocess_hc_baseband_params(ng_hci_unit_p unit, u_int16_t ocf, 552107120Sjulian struct mbuf *mcp, struct mbuf *mrp) 553107120Sjulian{ 554107120Sjulian int error = 0; 555107120Sjulian 556107120Sjulian switch (ocf) { 557107120Sjulian case NG_HCI_OCF_SET_EVENT_MASK: 558107120Sjulian case NG_HCI_OCF_SET_EVENT_FILTER: 559107120Sjulian case NG_HCI_OCF_FLUSH: /* XXX Do we need to handle that? */ 560107120Sjulian case NG_HCI_OCF_READ_PIN_TYPE: 561107120Sjulian case NG_HCI_OCF_WRITE_PIN_TYPE: 562107120Sjulian case NG_HCI_OCF_CREATE_NEW_UNIT_KEY: 563107120Sjulian case NG_HCI_OCF_WRITE_STORED_LINK_KEY: 564107120Sjulian case NG_HCI_OCF_WRITE_CON_ACCEPT_TIMO: 565107120Sjulian case NG_HCI_OCF_WRITE_PAGE_TIMO: 566107120Sjulian case NG_HCI_OCF_READ_SCAN_ENABLE: 567107120Sjulian case NG_HCI_OCF_WRITE_SCAN_ENABLE: 568107120Sjulian case NG_HCI_OCF_WRITE_PAGE_SCAN_ACTIVITY: 569107120Sjulian case NG_HCI_OCF_WRITE_INQUIRY_SCAN_ACTIVITY: 570107120Sjulian case NG_HCI_OCF_READ_AUTH_ENABLE: 571107120Sjulian case NG_HCI_OCF_WRITE_AUTH_ENABLE: 572107120Sjulian case NG_HCI_OCF_READ_ENCRYPTION_MODE: 573107120Sjulian case NG_HCI_OCF_WRITE_ENCRYPTION_MODE: 574107120Sjulian case NG_HCI_OCF_WRITE_VOICE_SETTINGS: 575107120Sjulian case NG_HCI_OCF_READ_NUM_BROADCAST_RETRANS: 576107120Sjulian case NG_HCI_OCF_WRITE_NUM_BROADCAST_RETRANS: 577107120Sjulian case NG_HCI_OCF_READ_HOLD_MODE_ACTIVITY: 578107120Sjulian case NG_HCI_OCF_WRITE_HOLD_MODE_ACTIVITY: 579107120Sjulian case NG_HCI_OCF_READ_SCO_FLOW_CONTROL: 580107120Sjulian case NG_HCI_OCF_WRITE_SCO_FLOW_CONTROL: 581107120Sjulian case NG_HCI_OCF_H2HC_FLOW_CONTROL: /* XXX Not supported this time */ 582107120Sjulian case NG_HCI_OCF_HOST_BUFFER_SIZE: 583107120Sjulian case NG_HCI_OCF_READ_IAC_LAP: 584107120Sjulian case NG_HCI_OCF_WRITE_IAC_LAP: 585107120Sjulian case NG_HCI_OCF_READ_PAGE_SCAN_PERIOD: 586107120Sjulian case NG_HCI_OCF_WRITE_PAGE_SCAN_PERIOD: 587107120Sjulian case NG_HCI_OCF_READ_PAGE_SCAN: 588107120Sjulian case NG_HCI_OCF_WRITE_PAGE_SCAN: 589107120Sjulian case NG_HCI_OCF_READ_LINK_SUPERVISION_TIMO: 590107120Sjulian case NG_HCI_OCF_WRITE_LINK_SUPERVISION_TIMO: 591107120Sjulian case NG_HCI_OCF_READ_SUPPORTED_IAC_NUM: 592107120Sjulian case NG_HCI_OCF_READ_STORED_LINK_KEY: 593107120Sjulian case NG_HCI_OCF_DELETE_STORED_LINK_KEY: 594107120Sjulian case NG_HCI_OCF_READ_CON_ACCEPT_TIMO: 595107120Sjulian case NG_HCI_OCF_READ_PAGE_TIMO: 596107120Sjulian case NG_HCI_OCF_READ_PAGE_SCAN_ACTIVITY: 597107120Sjulian case NG_HCI_OCF_READ_INQUIRY_SCAN_ACTIVITY: 598107120Sjulian case NG_HCI_OCF_READ_VOICE_SETTINGS: 599107120Sjulian case NG_HCI_OCF_READ_AUTO_FLUSH_TIMO: 600107120Sjulian case NG_HCI_OCF_WRITE_AUTO_FLUSH_TIMO: 601107120Sjulian case NG_HCI_OCF_READ_XMIT_LEVEL: 602107120Sjulian case NG_HCI_OCF_HOST_NUM_COMPL_PKTS: /* XXX Can get here? */ 603107120Sjulian case NG_HCI_OCF_CHANGE_LOCAL_NAME: 604107120Sjulian case NG_HCI_OCF_READ_LOCAL_NAME: 605107120Sjulian case NG_HCI_OCF_READ_UNIT_CLASS: 606107120Sjulian case NG_HCI_OCF_WRITE_UNIT_CLASS: 607107120Sjulian /* These do not need post processing */ 608107120Sjulian break; 609107120Sjulian 610107120Sjulian case NG_HCI_OCF_RESET: { 611107120Sjulian ng_hci_unit_con_p con = NULL; 612107120Sjulian int size; 613107120Sjulian 614107120Sjulian /* 615107120Sjulian * XXX 616107120Sjulian * 617107120Sjulian * After RESET command unit goes into standby mode 618107120Sjulian * and all operational state is lost. Host controller 619107120Sjulian * will revert to default values for all parameters. 620107120Sjulian * 621107120Sjulian * For now we shall terminate all connections and drop 622107120Sjulian * inited bit. After RESET unit must be re-initialized. 623107120Sjulian */ 624107120Sjulian 625107120Sjulian while (!LIST_EMPTY(&unit->con_list)) { 626107120Sjulian con = LIST_FIRST(&unit->con_list); 627107120Sjulian 628121054Semax /* Remove all timeouts (if any) */ 629121054Semax if (con->flags & NG_HCI_CON_TIMEOUT_PENDING) 630121054Semax ng_hci_con_untimeout(con); 631121054Semax 632107120Sjulian /* Connection terminated by local host */ 633107120Sjulian ng_hci_lp_discon_ind(con, 0x16); 634107120Sjulian ng_hci_free_con(con); 635107120Sjulian } 636107120Sjulian 637107120Sjulian NG_HCI_BUFF_ACL_TOTAL(unit->buffer, size); 638107120Sjulian NG_HCI_BUFF_ACL_FREE(unit->buffer, size); 639107120Sjulian 640107120Sjulian NG_HCI_BUFF_SCO_TOTAL(unit->buffer, size); 641107120Sjulian NG_HCI_BUFF_SCO_FREE(unit->buffer, size); 642107120Sjulian 643107120Sjulian unit->state &= ~NG_HCI_UNIT_INITED; 644107120Sjulian } break; 645107120Sjulian 646107120Sjulian default: 647107120Sjulian error = EINVAL; 648107120Sjulian break; 649107120Sjulian } 650107120Sjulian 651107120Sjulian NG_FREE_M(mcp); 652107120Sjulian NG_FREE_M(mrp); 653107120Sjulian 654107120Sjulian return (error); 655107120Sjulian} /* process_hc_baseband_params */ 656107120Sjulian 657107120Sjulian/* 658107120Sjulian * Process info command return parameters 659107120Sjulian */ 660107120Sjulian 661107120Sjulianstatic int 662107120Sjulianprocess_info_params(ng_hci_unit_p unit, u_int16_t ocf, struct mbuf *mcp, 663107120Sjulian struct mbuf *mrp) 664107120Sjulian{ 665107120Sjulian int error = 0, len; 666107120Sjulian 667107120Sjulian switch (ocf) { 668107120Sjulian case NG_HCI_OCF_READ_LOCAL_VER: 669107120Sjulian case NG_HCI_OCF_READ_COUNTRY_CODE: 670107120Sjulian break; 671107120Sjulian 672107120Sjulian case NG_HCI_OCF_READ_LOCAL_FEATURES: 673107120Sjulian m_adj(mrp, sizeof(u_int8_t)); 674107120Sjulian len = min(mrp->m_pkthdr.len, sizeof(unit->features)); 675107120Sjulian m_copydata(mrp, 0, len, (caddr_t) unit->features); 676107120Sjulian break; 677107120Sjulian 678107120Sjulian case NG_HCI_OCF_READ_BUFFER_SIZE: { 679107120Sjulian ng_hci_read_buffer_size_rp *rp = NULL; 680107120Sjulian 681107120Sjulian /* Do not update buffer descriptor if node was initialized */ 682107120Sjulian if ((unit->state & NG_HCI_UNIT_READY) == NG_HCI_UNIT_READY) 683107120Sjulian break; 684107120Sjulian 685107120Sjulian NG_HCI_M_PULLUP(mrp, sizeof(*rp)); 686107120Sjulian if (mrp != NULL) { 687107120Sjulian rp = mtod(mrp, ng_hci_read_buffer_size_rp *); 688107120Sjulian 689107120Sjulian NG_HCI_BUFF_ACL_SET( 690107120Sjulian unit->buffer, 691107120Sjulian le16toh(rp->num_acl_pkt), /* number */ 692107120Sjulian le16toh(rp->max_acl_size), /* size */ 693107120Sjulian le16toh(rp->num_acl_pkt) /* free */ 694107120Sjulian ); 695107120Sjulian 696107120Sjulian NG_HCI_BUFF_SCO_SET( 697107120Sjulian unit->buffer, 698107120Sjulian le16toh(rp->num_sco_pkt), /* number */ 699107120Sjulian rp->max_sco_size, /* size */ 700107120Sjulian le16toh(rp->num_sco_pkt) /* free */ 701107120Sjulian ); 702107120Sjulian 703107120Sjulian /* Let upper layers know */ 704107120Sjulian ng_hci_node_is_up(unit->node, unit->acl, NULL, 0); 705107120Sjulian ng_hci_node_is_up(unit->node, unit->sco, NULL, 0); 706107120Sjulian } else 707107120Sjulian error = ENOBUFS; 708107120Sjulian } break; 709107120Sjulian 710107120Sjulian case NG_HCI_OCF_READ_BDADDR: 711107120Sjulian /* Do not update BD_ADDR if node was initialized */ 712107120Sjulian if ((unit->state & NG_HCI_UNIT_READY) == NG_HCI_UNIT_READY) 713107120Sjulian break; 714107120Sjulian 715107120Sjulian m_adj(mrp, sizeof(u_int8_t)); 716107120Sjulian len = min(mrp->m_pkthdr.len, sizeof(unit->bdaddr)); 717107120Sjulian m_copydata(mrp, 0, len, (caddr_t) &unit->bdaddr); 718107120Sjulian 719107120Sjulian /* Let upper layers know */ 720107120Sjulian ng_hci_node_is_up(unit->node, unit->acl, NULL, 0); 721107120Sjulian ng_hci_node_is_up(unit->node, unit->sco, NULL, 0); 722107120Sjulian break; 723107120Sjulian 724107120Sjulian default: 725107120Sjulian error = EINVAL; 726107120Sjulian break; 727107120Sjulian } 728107120Sjulian 729107120Sjulian NG_FREE_M(mcp); 730107120Sjulian NG_FREE_M(mrp); 731107120Sjulian 732107120Sjulian return (error); 733107120Sjulian} /* process_info_params */ 734107120Sjulian 735107120Sjulian/* 736107120Sjulian * Process status command return parameters 737107120Sjulian */ 738107120Sjulian 739107120Sjulianstatic int 740107120Sjulianprocess_status_params(ng_hci_unit_p unit, u_int16_t ocf, struct mbuf *mcp, 741107120Sjulian struct mbuf *mrp) 742107120Sjulian{ 743107120Sjulian int error = 0; 744107120Sjulian 745107120Sjulian switch (ocf) { 746107120Sjulian case NG_HCI_OCF_READ_FAILED_CONTACT_CNTR: 747107120Sjulian case NG_HCI_OCF_RESET_FAILED_CONTACT_CNTR: 748107120Sjulian case NG_HCI_OCF_GET_LINK_QUALITY: 749107120Sjulian case NG_HCI_OCF_READ_RSSI: 750107120Sjulian /* These do not need post processing */ 751107120Sjulian break; 752107120Sjulian 753107120Sjulian default: 754107120Sjulian error = EINVAL; 755107120Sjulian break; 756107120Sjulian } 757107120Sjulian 758107120Sjulian NG_FREE_M(mcp); 759107120Sjulian NG_FREE_M(mrp); 760107120Sjulian 761107120Sjulian return (error); 762107120Sjulian} /* process_status_params */ 763107120Sjulian 764107120Sjulian/* 765107120Sjulian * Process testing command return parameters 766107120Sjulian */ 767107120Sjulian 768107120Sjulianint 769107120Sjulianprocess_testing_params(ng_hci_unit_p unit, u_int16_t ocf, struct mbuf *mcp, 770107120Sjulian struct mbuf *mrp) 771107120Sjulian{ 772107120Sjulian int error = 0; 773107120Sjulian 774107120Sjulian switch (ocf) { 775107120Sjulian 776107120Sjulian /* 777107120Sjulian * XXX FIXME 778107120Sjulian * We do not support these features at this time. However, 779107120Sjulian * HCI node could support this and do something smart. At least 780107120Sjulian * node can change unit state. 781107120Sjulian */ 782107120Sjulian 783107120Sjulian case NG_HCI_OCF_READ_LOOPBACK_MODE: 784107120Sjulian case NG_HCI_OCF_WRITE_LOOPBACK_MODE: 785107120Sjulian case NG_HCI_OCF_ENABLE_UNIT_UNDER_TEST: 786107120Sjulian break; 787107120Sjulian 788107120Sjulian default: 789107120Sjulian error = EINVAL; 790107120Sjulian break; 791107120Sjulian } 792107120Sjulian 793107120Sjulian NG_FREE_M(mcp); 794107120Sjulian NG_FREE_M(mrp); 795107120Sjulian 796107120Sjulian return (error); 797107120Sjulian} /* process_testing_params */ 798107120Sjulian 799107120Sjulian/* 800107120Sjulian * Process link control command status 801107120Sjulian */ 802107120Sjulian 803107120Sjulianstatic int 804107120Sjulianprocess_link_control_status(ng_hci_unit_p unit, ng_hci_command_status_ep *ep, 805107120Sjulian struct mbuf *mcp) 806107120Sjulian{ 807107120Sjulian int error = 0; 808107120Sjulian 809107120Sjulian switch (NG_HCI_OCF(ep->opcode)) { 810107120Sjulian case NG_HCI_OCF_INQUIRY: 811107120Sjulian case NG_HCI_OCF_DISCON: /* XXX */ 812107120Sjulian case NG_HCI_OCF_REJECT_CON: /* XXX */ 813107120Sjulian case NG_HCI_OCF_CHANGE_CON_PKT_TYPE: 814107120Sjulian case NG_HCI_OCF_AUTH_REQ: 815107120Sjulian case NG_HCI_OCF_SET_CON_ENCRYPTION: 816107120Sjulian case NG_HCI_OCF_CHANGE_CON_LINK_KEY: 817107120Sjulian case NG_HCI_OCF_MASTER_LINK_KEY: 818107120Sjulian case NG_HCI_OCF_REMOTE_NAME_REQ: 819107120Sjulian case NG_HCI_OCF_READ_REMOTE_FEATURES: 820107120Sjulian case NG_HCI_OCF_READ_REMOTE_VER_INFO: 821107120Sjulian case NG_HCI_OCF_READ_CLOCK_OFFSET: 822107120Sjulian /* These do not need post processing */ 823107120Sjulian break; 824107120Sjulian 825107120Sjulian case NG_HCI_OCF_CREATE_CON: 826107120Sjulian break; 827107120Sjulian 828107120Sjulian case NG_HCI_OCF_ADD_SCO_CON: 829107120Sjulian break; 830107120Sjulian 831107120Sjulian case NG_HCI_OCF_ACCEPT_CON: 832107120Sjulian break; 833107120Sjulian 834107120Sjulian case NG_HCI_OCF_INQUIRY_CANCEL: 835107120Sjulian case NG_HCI_OCF_PERIODIC_INQUIRY: 836107120Sjulian case NG_HCI_OCF_EXIT_PERIODIC_INQUIRY: 837107120Sjulian case NG_HCI_OCF_LINK_KEY_REP: 838107120Sjulian case NG_HCI_OCF_LINK_KEY_NEG_REP: 839107120Sjulian case NG_HCI_OCF_PIN_CODE_REP: 840107120Sjulian case NG_HCI_OCF_PIN_CODE_NEG_REP: 841107120Sjulian default: 842107120Sjulian 843107120Sjulian /* 844107120Sjulian * None of these command was supposed to generate 845107120Sjulian * Command_Status event. Instead Command_Complete event 846107120Sjulian * should have been sent. 847107120Sjulian */ 848107120Sjulian 849107120Sjulian error = EINVAL; 850107120Sjulian break; 851107120Sjulian } 852107120Sjulian 853107120Sjulian NG_FREE_M(mcp); 854107120Sjulian 855107120Sjulian return (error); 856107120Sjulian} /* process_link_control_status */ 857107120Sjulian 858107120Sjulian/* 859107120Sjulian * Process link policy command status 860107120Sjulian */ 861107120Sjulian 862107120Sjulianstatic int 863107120Sjulianprocess_link_policy_status(ng_hci_unit_p unit, ng_hci_command_status_ep *ep, 864107120Sjulian struct mbuf *mcp) 865107120Sjulian{ 866107120Sjulian int error = 0; 867107120Sjulian 868107120Sjulian switch (NG_HCI_OCF(ep->opcode)) { 869107120Sjulian case NG_HCI_OCF_HOLD_MODE: 870107120Sjulian case NG_HCI_OCF_SNIFF_MODE: 871107120Sjulian case NG_HCI_OCF_EXIT_SNIFF_MODE: 872107120Sjulian case NG_HCI_OCF_PARK_MODE: 873107120Sjulian case NG_HCI_OCF_EXIT_PARK_MODE: 874107120Sjulian case NG_HCI_OCF_SWITCH_ROLE: 875107120Sjulian /* These do not need post processing */ 876107120Sjulian break; 877107120Sjulian 878107120Sjulian case NG_HCI_OCF_QOS_SETUP: 879107120Sjulian break; 880107120Sjulian 881107120Sjulian case NG_HCI_OCF_ROLE_DISCOVERY: 882107120Sjulian case NG_HCI_OCF_READ_LINK_POLICY_SETTINGS: 883107120Sjulian case NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS: 884107120Sjulian default: 885107120Sjulian 886107120Sjulian /* 887107120Sjulian * None of these command was supposed to generate 888107120Sjulian * Command_Status event. Instead Command_Complete event 889107120Sjulian * should have been sent. 890107120Sjulian */ 891107120Sjulian 892107120Sjulian error = EINVAL; 893107120Sjulian break; 894107120Sjulian } 895107120Sjulian 896107120Sjulian NG_FREE_M(mcp); 897107120Sjulian 898107120Sjulian return (error); 899107120Sjulian} /* process_link_policy_status */ 900107120Sjulian 901