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