1878ed226SJulian Elischer /* 2878ed226SJulian Elischer * ng_hci_main.c 3c398230bSWarner Losh */ 4c398230bSWarner Losh 5c398230bSWarner Losh /*- 6*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 7fe267a55SPedro F. Giffuni * 8878ed226SJulian Elischer * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com> 9878ed226SJulian Elischer * All rights reserved. 10878ed226SJulian Elischer * 11878ed226SJulian Elischer * Redistribution and use in source and binary forms, with or without 12878ed226SJulian Elischer * modification, are permitted provided that the following conditions 13878ed226SJulian Elischer * are met: 14878ed226SJulian Elischer * 1. Redistributions of source code must retain the above copyright 15878ed226SJulian Elischer * notice, this list of conditions and the following disclaimer. 16878ed226SJulian Elischer * 2. Redistributions in binary form must reproduce the above copyright 17878ed226SJulian Elischer * notice, this list of conditions and the following disclaimer in the 18878ed226SJulian Elischer * documentation and/or other materials provided with the distribution. 19878ed226SJulian Elischer * 20878ed226SJulian Elischer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21878ed226SJulian Elischer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22878ed226SJulian Elischer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23878ed226SJulian Elischer * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24878ed226SJulian Elischer * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25878ed226SJulian Elischer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26878ed226SJulian Elischer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27878ed226SJulian Elischer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28878ed226SJulian Elischer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29878ed226SJulian Elischer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30878ed226SJulian Elischer * SUCH DAMAGE. 31878ed226SJulian Elischer * 32f2bb1caeSJulian Elischer * $Id: ng_hci_main.c,v 1.2 2003/03/18 00:09:36 max Exp $ 33878ed226SJulian Elischer * $FreeBSD$ 34878ed226SJulian Elischer */ 35878ed226SJulian Elischer 36878ed226SJulian Elischer #include <sys/param.h> 37878ed226SJulian Elischer #include <sys/systm.h> 38878ed226SJulian Elischer #include <sys/kernel.h> 39878ed226SJulian Elischer #include <sys/endian.h> 40878ed226SJulian Elischer #include <sys/malloc.h> 41878ed226SJulian Elischer #include <sys/mbuf.h> 42878ed226SJulian Elischer #include <sys/queue.h> 43878ed226SJulian Elischer #include <netgraph/ng_message.h> 44878ed226SJulian Elischer #include <netgraph/netgraph.h> 45878ed226SJulian Elischer #include <netgraph/ng_parse.h> 46b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_bluetooth.h> 47b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/include/ng_hci.h> 48b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/hci/ng_hci_var.h> 49b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/hci/ng_hci_prse.h> 50b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/hci/ng_hci_cmds.h> 51b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/hci/ng_hci_evnt.h> 52b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/hci/ng_hci_ulpi.h> 53b84b10f9SMaksim Yevmenkin #include <netgraph/bluetooth/hci/ng_hci_misc.h> 54878ed226SJulian Elischer 55878ed226SJulian Elischer /****************************************************************************** 56878ed226SJulian Elischer ****************************************************************************** 57878ed226SJulian Elischer ** This node implements Bluetooth Host Controller Interface (HCI) 58878ed226SJulian Elischer ****************************************************************************** 59878ed226SJulian Elischer ******************************************************************************/ 60878ed226SJulian Elischer 61878ed226SJulian Elischer /* MALLOC define */ 62878ed226SJulian Elischer #ifdef NG_SEPARATE_MALLOC 63878ed226SJulian Elischer MALLOC_DEFINE(M_NETGRAPH_HCI, "netgraph_hci", "Netgraph Bluetooth HCI node"); 64878ed226SJulian Elischer #else 65878ed226SJulian Elischer #define M_NETGRAPH_HCI M_NETGRAPH 66878ed226SJulian Elischer #endif /* NG_SEPARATE_MALLOC */ 67878ed226SJulian Elischer 68878ed226SJulian Elischer /* Netgraph node methods */ 69878ed226SJulian Elischer static ng_constructor_t ng_hci_constructor; 70878ed226SJulian Elischer static ng_shutdown_t ng_hci_shutdown; 71878ed226SJulian Elischer static ng_newhook_t ng_hci_newhook; 72878ed226SJulian Elischer static ng_connect_t ng_hci_connect; 73878ed226SJulian Elischer static ng_disconnect_t ng_hci_disconnect; 74878ed226SJulian Elischer static ng_rcvmsg_t ng_hci_default_rcvmsg; 75878ed226SJulian Elischer static ng_rcvmsg_t ng_hci_upper_rcvmsg; 76878ed226SJulian Elischer static ng_rcvdata_t ng_hci_drv_rcvdata; 77878ed226SJulian Elischer static ng_rcvdata_t ng_hci_acl_rcvdata; 78878ed226SJulian Elischer static ng_rcvdata_t ng_hci_sco_rcvdata; 79878ed226SJulian Elischer static ng_rcvdata_t ng_hci_raw_rcvdata; 80878ed226SJulian Elischer 81878ed226SJulian Elischer /* Netgraph node type descriptor */ 82878ed226SJulian Elischer static struct ng_type typestruct = { 83f8aae777SJulian Elischer .version = NG_ABI_VERSION, 84f8aae777SJulian Elischer .name = NG_HCI_NODE_TYPE, 85f8aae777SJulian Elischer .constructor = ng_hci_constructor, 86f8aae777SJulian Elischer .rcvmsg = ng_hci_default_rcvmsg, 87f8aae777SJulian Elischer .shutdown = ng_hci_shutdown, 88f8aae777SJulian Elischer .newhook = ng_hci_newhook, 89f8aae777SJulian Elischer .connect = ng_hci_connect, 90f8aae777SJulian Elischer .rcvdata = ng_hci_drv_rcvdata, 91f8aae777SJulian Elischer .disconnect = ng_hci_disconnect, 92f8aae777SJulian Elischer .cmdlist = ng_hci_cmdlist, 93878ed226SJulian Elischer }; 94878ed226SJulian Elischer NETGRAPH_INIT(hci, &typestruct); 95878ed226SJulian Elischer MODULE_VERSION(ng_hci, NG_BLUETOOTH_VERSION); 96878ed226SJulian Elischer MODULE_DEPEND(ng_hci, ng_bluetooth, NG_BLUETOOTH_VERSION, 97878ed226SJulian Elischer NG_BLUETOOTH_VERSION, NG_BLUETOOTH_VERSION); 984aa92fe2STakanori Watanabe static int ng_hci_linktype_to_addrtype(int linktype); 99878ed226SJulian Elischer 1004aa92fe2STakanori Watanabe static int ng_hci_linktype_to_addrtype(int linktype) 1014aa92fe2STakanori Watanabe { 1024aa92fe2STakanori Watanabe switch(linktype){ 1034aa92fe2STakanori Watanabe case NG_HCI_LINK_LE_PUBLIC: 1044aa92fe2STakanori Watanabe return BDADDR_LE_PUBLIC; 1054aa92fe2STakanori Watanabe case NG_HCI_LINK_LE_RANDOM: 1064aa92fe2STakanori Watanabe return BDADDR_LE_RANDOM; 1074aa92fe2STakanori Watanabe case NG_HCI_LINK_ACL: 1084aa92fe2STakanori Watanabe /*FALLTHROUGH*/ 1094aa92fe2STakanori Watanabe default: 1104aa92fe2STakanori Watanabe return BDADDR_BREDR; 1114aa92fe2STakanori Watanabe } 1124aa92fe2STakanori Watanabe return BDADDR_BREDR; 1134aa92fe2STakanori Watanabe } 114878ed226SJulian Elischer /***************************************************************************** 115878ed226SJulian Elischer ***************************************************************************** 116878ed226SJulian Elischer ** Netgraph methods implementation 117878ed226SJulian Elischer ***************************************************************************** 118878ed226SJulian Elischer *****************************************************************************/ 119878ed226SJulian Elischer 120878ed226SJulian Elischer /* 121878ed226SJulian Elischer * Create new instance of HCI node (new unit) 122878ed226SJulian Elischer */ 123878ed226SJulian Elischer 124878ed226SJulian Elischer static int 125878ed226SJulian Elischer ng_hci_constructor(node_p node) 126878ed226SJulian Elischer { 127878ed226SJulian Elischer ng_hci_unit_p unit = NULL; 128878ed226SJulian Elischer 129674d86bfSGleb Smirnoff unit = malloc(sizeof(*unit), M_NETGRAPH_HCI, M_WAITOK | M_ZERO); 130878ed226SJulian Elischer 131878ed226SJulian Elischer unit->node = node; 132878ed226SJulian Elischer unit->debug = NG_HCI_WARN_LEVEL; 133878ed226SJulian Elischer 134878ed226SJulian Elischer unit->link_policy_mask = 0xffff; /* Enable all supported modes */ 135878ed226SJulian Elischer unit->packet_mask = 0xffff; /* Enable all packet types */ 136f2bb1caeSJulian Elischer unit->role_switch = 1; /* Enable role switch (if device supports it) */ 137878ed226SJulian Elischer 138878ed226SJulian Elischer /* 139878ed226SJulian Elischer * Set default buffer info 140878ed226SJulian Elischer * 141878ed226SJulian Elischer * One HCI command 142878ed226SJulian Elischer * One ACL packet with max. size of 17 bytes (1 DM1 packet) 143878ed226SJulian Elischer * One SCO packet with max. size of 10 bytes (1 HV1 packet) 144878ed226SJulian Elischer */ 145878ed226SJulian Elischer 146878ed226SJulian Elischer NG_HCI_BUFF_CMD_SET(unit->buffer, 1); 147878ed226SJulian Elischer NG_HCI_BUFF_ACL_SET(unit->buffer, 1, 17, 1); 148878ed226SJulian Elischer NG_HCI_BUFF_SCO_SET(unit->buffer, 1, 10, 1); 149878ed226SJulian Elischer 150878ed226SJulian Elischer /* Init command queue & command timeout handler */ 151b81d7730SMaksim Yevmenkin ng_callout_init(&unit->cmd_timo); 152878ed226SJulian Elischer NG_BT_MBUFQ_INIT(&unit->cmdq, NG_HCI_CMD_QUEUE_LEN); 153878ed226SJulian Elischer 154878ed226SJulian Elischer /* Init lists */ 155878ed226SJulian Elischer LIST_INIT(&unit->con_list); 156878ed226SJulian Elischer LIST_INIT(&unit->neighbors); 157878ed226SJulian Elischer 158878ed226SJulian Elischer /* 159878ed226SJulian Elischer * This node has to be a WRITER because both data and messages 160878ed226SJulian Elischer * can change node state. 161878ed226SJulian Elischer */ 162878ed226SJulian Elischer 163878ed226SJulian Elischer NG_NODE_FORCE_WRITER(node); 164878ed226SJulian Elischer NG_NODE_SET_PRIVATE(node, unit); 165878ed226SJulian Elischer 166878ed226SJulian Elischer return (0); 167878ed226SJulian Elischer } /* ng_hci_constructor */ 168878ed226SJulian Elischer 169878ed226SJulian Elischer /* 170878ed226SJulian Elischer * Destroy the node 171878ed226SJulian Elischer */ 172878ed226SJulian Elischer 173878ed226SJulian Elischer static int 174878ed226SJulian Elischer ng_hci_shutdown(node_p node) 175878ed226SJulian Elischer { 176878ed226SJulian Elischer ng_hci_unit_p unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node); 177878ed226SJulian Elischer 178878ed226SJulian Elischer NG_NODE_SET_PRIVATE(node, NULL); 179878ed226SJulian Elischer NG_NODE_UNREF(node); 180878ed226SJulian Elischer 181878ed226SJulian Elischer unit->node = NULL; 182878ed226SJulian Elischer ng_hci_unit_clean(unit, 0x16 /* Connection terminated by local host */); 183878ed226SJulian Elischer 184878ed226SJulian Elischer NG_BT_MBUFQ_DESTROY(&unit->cmdq); 185878ed226SJulian Elischer 186878ed226SJulian Elischer bzero(unit, sizeof(*unit)); 1871ede983cSDag-Erling Smørgrav free(unit, M_NETGRAPH_HCI); 188878ed226SJulian Elischer 189878ed226SJulian Elischer return (0); 190878ed226SJulian Elischer } /* ng_hci_shutdown */ 191878ed226SJulian Elischer 192878ed226SJulian Elischer /* 193878ed226SJulian Elischer * Give our OK for a hook to be added. Unit driver is connected to the driver 194878ed226SJulian Elischer * (NG_HCI_HOOK_DRV) hook. Upper layer protocols are connected to appropriate 195878ed226SJulian Elischer * (NG_HCI_HOOK_ACL or NG_HCI_HOOK_SCO) hooks. 196878ed226SJulian Elischer */ 197878ed226SJulian Elischer 198878ed226SJulian Elischer static int 199878ed226SJulian Elischer ng_hci_newhook(node_p node, hook_p hook, char const *name) 200878ed226SJulian Elischer { 201878ed226SJulian Elischer ng_hci_unit_p unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node); 202878ed226SJulian Elischer hook_p *h = NULL; 203878ed226SJulian Elischer 204878ed226SJulian Elischer if (strcmp(name, NG_HCI_HOOK_DRV) == 0) 205878ed226SJulian Elischer h = &unit->drv; 206878ed226SJulian Elischer else if (strcmp(name, NG_HCI_HOOK_ACL) == 0) 207878ed226SJulian Elischer h = &unit->acl; 208878ed226SJulian Elischer else if (strcmp(name, NG_HCI_HOOK_SCO) == 0) 209878ed226SJulian Elischer h = &unit->sco; 210878ed226SJulian Elischer else if (strcmp(name, NG_HCI_HOOK_RAW) == 0) 211878ed226SJulian Elischer h = &unit->raw; 212878ed226SJulian Elischer else 213878ed226SJulian Elischer return (EINVAL); 214878ed226SJulian Elischer 215878ed226SJulian Elischer if (*h != NULL) 216878ed226SJulian Elischer return (EISCONN); 217878ed226SJulian Elischer 218878ed226SJulian Elischer *h = hook; 219878ed226SJulian Elischer 220878ed226SJulian Elischer return (0); 221878ed226SJulian Elischer } /* ng_hci_newhook */ 222878ed226SJulian Elischer 223878ed226SJulian Elischer /* 224878ed226SJulian Elischer * Give our final OK to connect hook 225878ed226SJulian Elischer */ 226878ed226SJulian Elischer 227878ed226SJulian Elischer static int 228878ed226SJulian Elischer ng_hci_connect(hook_p hook) 229878ed226SJulian Elischer { 230878ed226SJulian Elischer ng_hci_unit_p unit = (ng_hci_unit_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 231878ed226SJulian Elischer 232878ed226SJulian Elischer if (hook != unit->drv) { 233878ed226SJulian Elischer if (hook == unit->acl) { 234878ed226SJulian Elischer NG_HOOK_SET_RCVMSG(hook, ng_hci_upper_rcvmsg); 235878ed226SJulian Elischer NG_HOOK_SET_RCVDATA(hook, ng_hci_acl_rcvdata); 236878ed226SJulian Elischer } else if (hook == unit->sco) { 237878ed226SJulian Elischer NG_HOOK_SET_RCVMSG(hook, ng_hci_upper_rcvmsg); 238878ed226SJulian Elischer NG_HOOK_SET_RCVDATA(hook, ng_hci_sco_rcvdata); 239878ed226SJulian Elischer } else 240878ed226SJulian Elischer NG_HOOK_SET_RCVDATA(hook, ng_hci_raw_rcvdata); 241878ed226SJulian Elischer 242878ed226SJulian Elischer /* Send delayed notification to the upper layers */ 243878ed226SJulian Elischer if (hook != unit->raw) 244878ed226SJulian Elischer ng_send_fn(unit->node, hook, ng_hci_node_is_up, NULL,0); 245878ed226SJulian Elischer } else 246878ed226SJulian Elischer unit->state |= NG_HCI_UNIT_CONNECTED; 247878ed226SJulian Elischer 248878ed226SJulian Elischer return (0); 249878ed226SJulian Elischer } /* ng_hci_connect */ 250878ed226SJulian Elischer 251878ed226SJulian Elischer /* 252878ed226SJulian Elischer * Disconnect the hook 253878ed226SJulian Elischer */ 254878ed226SJulian Elischer 255878ed226SJulian Elischer static int 256878ed226SJulian Elischer ng_hci_disconnect(hook_p hook) 257878ed226SJulian Elischer { 258878ed226SJulian Elischer ng_hci_unit_p unit = (ng_hci_unit_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 259878ed226SJulian Elischer 260878ed226SJulian Elischer if (hook == unit->acl) 261878ed226SJulian Elischer unit->acl = NULL; 262878ed226SJulian Elischer else if (hook == unit->sco) 263878ed226SJulian Elischer unit->sco = NULL; 264878ed226SJulian Elischer else if (hook == unit->raw) 265878ed226SJulian Elischer unit->raw = NULL; 266878ed226SJulian Elischer else if (hook == unit->drv) { 267878ed226SJulian Elischer unit->drv = NULL; 268878ed226SJulian Elischer 269878ed226SJulian Elischer /* Connection terminated by local host */ 270878ed226SJulian Elischer ng_hci_unit_clean(unit, 0x16); 271878ed226SJulian Elischer unit->state &= ~(NG_HCI_UNIT_CONNECTED|NG_HCI_UNIT_INITED); 272878ed226SJulian Elischer } else 273878ed226SJulian Elischer return (EINVAL); 274878ed226SJulian Elischer 275878ed226SJulian Elischer /* Shutdown when all hooks are disconnected */ 276878ed226SJulian Elischer if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) && 277878ed226SJulian Elischer (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) 278878ed226SJulian Elischer ng_rmnode_self(NG_HOOK_NODE(hook)); 279878ed226SJulian Elischer 280878ed226SJulian Elischer return (0); 281878ed226SJulian Elischer } /* ng_hci_disconnect */ 282878ed226SJulian Elischer 283878ed226SJulian Elischer /* 284878ed226SJulian Elischer * Default control message processing routine. Control message could be: 285878ed226SJulian Elischer * 286878ed226SJulian Elischer * 1) GENERIC Netgraph messages 287878ed226SJulian Elischer * 288878ed226SJulian Elischer * 2) Control message directed to the node itself. 289878ed226SJulian Elischer */ 290878ed226SJulian Elischer 291878ed226SJulian Elischer static int 292878ed226SJulian Elischer ng_hci_default_rcvmsg(node_p node, item_p item, hook_p lasthook) 293878ed226SJulian Elischer { 294878ed226SJulian Elischer ng_hci_unit_p unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node); 295878ed226SJulian Elischer struct ng_mesg *msg = NULL, *rsp = NULL; 296878ed226SJulian Elischer int error = 0; 297878ed226SJulian Elischer 298878ed226SJulian Elischer NGI_GET_MSG(item, msg); 299878ed226SJulian Elischer 300878ed226SJulian Elischer switch (msg->header.typecookie) { 301878ed226SJulian Elischer case NGM_GENERIC_COOKIE: 302878ed226SJulian Elischer switch (msg->header.cmd) { 303878ed226SJulian Elischer case NGM_TEXT_STATUS: { 304878ed226SJulian Elischer int cmd_avail, 305878ed226SJulian Elischer acl_total, acl_avail, acl_size, 306878ed226SJulian Elischer sco_total, sco_avail, sco_size; 307878ed226SJulian Elischer 308878ed226SJulian Elischer NG_MKRESPONSE(rsp, msg, NG_TEXTRESPONSE, M_NOWAIT); 309878ed226SJulian Elischer if (rsp == NULL) { 310878ed226SJulian Elischer error = ENOMEM; 311878ed226SJulian Elischer break; 312878ed226SJulian Elischer } 313878ed226SJulian Elischer 314878ed226SJulian Elischer NG_HCI_BUFF_CMD_GET(unit->buffer, cmd_avail); 315878ed226SJulian Elischer 316878ed226SJulian Elischer NG_HCI_BUFF_ACL_AVAIL(unit->buffer, acl_avail); 317878ed226SJulian Elischer NG_HCI_BUFF_ACL_TOTAL(unit->buffer, acl_total); 318878ed226SJulian Elischer NG_HCI_BUFF_ACL_SIZE(unit->buffer, acl_size); 319878ed226SJulian Elischer 320878ed226SJulian Elischer NG_HCI_BUFF_SCO_AVAIL(unit->buffer, sco_avail); 321878ed226SJulian Elischer NG_HCI_BUFF_SCO_TOTAL(unit->buffer, sco_total); 322878ed226SJulian Elischer NG_HCI_BUFF_SCO_SIZE(unit->buffer, sco_size); 323878ed226SJulian Elischer 324878ed226SJulian Elischer snprintf(rsp->data, NG_TEXTRESPONSE, 325878ed226SJulian Elischer "bdaddr %x:%x:%x:%x:%x:%x\n" \ 326878ed226SJulian Elischer "Hooks %s %s %s %s\n" \ 327878ed226SJulian Elischer "State %#x\n" \ 328878ed226SJulian Elischer "Queue cmd:%d\n" \ 329878ed226SJulian Elischer "Buffer cmd:%d,acl:%d,%d,%d,sco:%d,%d,%d", 330878ed226SJulian Elischer unit->bdaddr.b[5], unit->bdaddr.b[4], 331878ed226SJulian Elischer unit->bdaddr.b[3], unit->bdaddr.b[2], 332878ed226SJulian Elischer unit->bdaddr.b[1], unit->bdaddr.b[0], 333878ed226SJulian Elischer (unit->drv != NULL)? NG_HCI_HOOK_DRV : "", 334878ed226SJulian Elischer (unit->acl != NULL)? NG_HCI_HOOK_ACL : "", 335878ed226SJulian Elischer (unit->sco != NULL)? NG_HCI_HOOK_SCO : "", 336878ed226SJulian Elischer (unit->raw != NULL)? NG_HCI_HOOK_RAW : "", 337878ed226SJulian Elischer unit->state, 338878ed226SJulian Elischer NG_BT_MBUFQ_LEN(&unit->cmdq), 339878ed226SJulian Elischer cmd_avail, 340878ed226SJulian Elischer acl_avail, acl_total, acl_size, 341878ed226SJulian Elischer sco_avail, sco_total, sco_size); 342878ed226SJulian Elischer } break; 343878ed226SJulian Elischer 344878ed226SJulian Elischer default: 345878ed226SJulian Elischer error = EINVAL; 346878ed226SJulian Elischer break; 347878ed226SJulian Elischer } 348878ed226SJulian Elischer break; 349878ed226SJulian Elischer 350878ed226SJulian Elischer case NGM_HCI_COOKIE: 351878ed226SJulian Elischer switch (msg->header.cmd) { 352878ed226SJulian Elischer /* Get current node state */ 353878ed226SJulian Elischer case NGM_HCI_NODE_GET_STATE: 354878ed226SJulian Elischer NG_MKRESPONSE(rsp, msg, sizeof(unit->state), M_NOWAIT); 355878ed226SJulian Elischer if (rsp == NULL) { 356878ed226SJulian Elischer error = ENOMEM; 357878ed226SJulian Elischer break; 358878ed226SJulian Elischer } 359878ed226SJulian Elischer 360878ed226SJulian Elischer *((ng_hci_node_state_ep *)(rsp->data)) = unit->state; 361878ed226SJulian Elischer break; 362878ed226SJulian Elischer 363878ed226SJulian Elischer /* Turn INITED bit - node initialized */ 364878ed226SJulian Elischer case NGM_HCI_NODE_INIT: 365878ed226SJulian Elischer if (bcmp(&unit->bdaddr, NG_HCI_BDADDR_ANY, 366878ed226SJulian Elischer sizeof(bdaddr_t)) == 0) { 367878ed226SJulian Elischer error = ENXIO; 368878ed226SJulian Elischer break; 369878ed226SJulian Elischer } 370878ed226SJulian Elischer 371878ed226SJulian Elischer unit->state |= NG_HCI_UNIT_INITED; 372878ed226SJulian Elischer 373878ed226SJulian Elischer ng_hci_node_is_up(unit->node, unit->acl, NULL, 0); 374878ed226SJulian Elischer ng_hci_node_is_up(unit->node, unit->sco, NULL, 0); 375878ed226SJulian Elischer break; 376878ed226SJulian Elischer 377878ed226SJulian Elischer /* Get node debug level */ 378878ed226SJulian Elischer case NGM_HCI_NODE_GET_DEBUG: 379878ed226SJulian Elischer NG_MKRESPONSE(rsp, msg, sizeof(unit->debug), M_NOWAIT); 380878ed226SJulian Elischer if (rsp == NULL) { 381878ed226SJulian Elischer error = ENOMEM; 382878ed226SJulian Elischer break; 383878ed226SJulian Elischer } 384878ed226SJulian Elischer 385878ed226SJulian Elischer *((ng_hci_node_debug_ep *)(rsp->data)) = unit->debug; 386878ed226SJulian Elischer break; 387878ed226SJulian Elischer 388878ed226SJulian Elischer /* Set node debug level */ 389878ed226SJulian Elischer case NGM_HCI_NODE_SET_DEBUG: 390878ed226SJulian Elischer if (msg->header.arglen != sizeof(ng_hci_node_debug_ep)){ 391878ed226SJulian Elischer error = EMSGSIZE; 392878ed226SJulian Elischer break; 393878ed226SJulian Elischer } 394878ed226SJulian Elischer 395878ed226SJulian Elischer unit->debug = *((ng_hci_node_debug_ep *)(msg->data)); 396878ed226SJulian Elischer break; 397878ed226SJulian Elischer 398878ed226SJulian Elischer /* Get buffer info */ 399878ed226SJulian Elischer case NGM_HCI_NODE_GET_BUFFER: { 400878ed226SJulian Elischer ng_hci_node_buffer_ep *ep = NULL; 401878ed226SJulian Elischer 402878ed226SJulian Elischer NG_MKRESPONSE(rsp, msg, sizeof(ng_hci_node_buffer_ep), 403878ed226SJulian Elischer M_NOWAIT); 404878ed226SJulian Elischer if (rsp == NULL) { 405878ed226SJulian Elischer error = ENOMEM; 406878ed226SJulian Elischer break; 407878ed226SJulian Elischer } 408878ed226SJulian Elischer 409878ed226SJulian Elischer ep = (ng_hci_node_buffer_ep *)(rsp->data); 410878ed226SJulian Elischer 411878ed226SJulian Elischer NG_HCI_BUFF_CMD_GET(unit->buffer, ep->cmd_free); 412878ed226SJulian Elischer NG_HCI_BUFF_ACL_AVAIL(unit->buffer, ep->acl_free); 413878ed226SJulian Elischer NG_HCI_BUFF_ACL_TOTAL(unit->buffer, ep->acl_pkts); 414878ed226SJulian Elischer NG_HCI_BUFF_ACL_SIZE(unit->buffer, ep->acl_size); 415878ed226SJulian Elischer NG_HCI_BUFF_SCO_AVAIL(unit->buffer, ep->sco_free); 416878ed226SJulian Elischer NG_HCI_BUFF_SCO_TOTAL(unit->buffer, ep->sco_pkts); 417878ed226SJulian Elischer NG_HCI_BUFF_SCO_SIZE(unit->buffer, ep->sco_size); 418878ed226SJulian Elischer } break; 419878ed226SJulian Elischer 420878ed226SJulian Elischer /* Get BDADDR */ 421878ed226SJulian Elischer case NGM_HCI_NODE_GET_BDADDR: 422878ed226SJulian Elischer NG_MKRESPONSE(rsp, msg, sizeof(bdaddr_t), M_NOWAIT); 423878ed226SJulian Elischer if (rsp == NULL) { 424878ed226SJulian Elischer error = ENOMEM; 425878ed226SJulian Elischer break; 426878ed226SJulian Elischer } 427878ed226SJulian Elischer 428878ed226SJulian Elischer bcopy(&unit->bdaddr, rsp->data, sizeof(bdaddr_t)); 429878ed226SJulian Elischer break; 430878ed226SJulian Elischer 431878ed226SJulian Elischer /* Get features */ 432878ed226SJulian Elischer case NGM_HCI_NODE_GET_FEATURES: 433878ed226SJulian Elischer NG_MKRESPONSE(rsp,msg,sizeof(unit->features),M_NOWAIT); 434878ed226SJulian Elischer if (rsp == NULL) { 435878ed226SJulian Elischer error = ENOMEM; 436878ed226SJulian Elischer break; 437878ed226SJulian Elischer } 438878ed226SJulian Elischer 439878ed226SJulian Elischer bcopy(&unit->features,rsp->data,sizeof(unit->features)); 440878ed226SJulian Elischer break; 441878ed226SJulian Elischer 442878ed226SJulian Elischer /* Get stat */ 443878ed226SJulian Elischer case NGM_HCI_NODE_GET_STAT: 444878ed226SJulian Elischer NG_MKRESPONSE(rsp, msg, sizeof(unit->stat), M_NOWAIT); 445878ed226SJulian Elischer if (rsp == NULL) { 446878ed226SJulian Elischer error = ENOMEM; 447878ed226SJulian Elischer break; 448878ed226SJulian Elischer } 449878ed226SJulian Elischer 450878ed226SJulian Elischer bcopy(&unit->stat, rsp->data, sizeof(unit->stat)); 451878ed226SJulian Elischer break; 452878ed226SJulian Elischer 453878ed226SJulian Elischer /* Reset stat */ 454878ed226SJulian Elischer case NGM_HCI_NODE_RESET_STAT: 455878ed226SJulian Elischer NG_HCI_STAT_RESET(unit->stat); 456878ed226SJulian Elischer break; 457878ed226SJulian Elischer 458878ed226SJulian Elischer /* Clean up neighbors list */ 459878ed226SJulian Elischer case NGM_HCI_NODE_FLUSH_NEIGHBOR_CACHE: 460878ed226SJulian Elischer ng_hci_flush_neighbor_cache(unit); 461878ed226SJulian Elischer break; 462878ed226SJulian Elischer 463878ed226SJulian Elischer /* Get neighbor cache entries */ 464878ed226SJulian Elischer case NGM_HCI_NODE_GET_NEIGHBOR_CACHE: { 465878ed226SJulian Elischer ng_hci_neighbor_p n = NULL; 466878ed226SJulian Elischer ng_hci_node_get_neighbor_cache_ep *e1 = NULL; 467878ed226SJulian Elischer ng_hci_node_neighbor_cache_entry_ep *e2 = NULL; 468878ed226SJulian Elischer int s = 0; 469878ed226SJulian Elischer 470878ed226SJulian Elischer /* Look for the fresh entries in the cache */ 471878ed226SJulian Elischer for (n = LIST_FIRST(&unit->neighbors); n != NULL; ) { 472878ed226SJulian Elischer ng_hci_neighbor_p nn = LIST_NEXT(n, next); 473878ed226SJulian Elischer 474878ed226SJulian Elischer if (ng_hci_neighbor_stale(n)) 475878ed226SJulian Elischer ng_hci_free_neighbor(n); 476878ed226SJulian Elischer else 477878ed226SJulian Elischer s ++; 478878ed226SJulian Elischer 479878ed226SJulian Elischer n = nn; 480878ed226SJulian Elischer } 481878ed226SJulian Elischer if (s > NG_HCI_MAX_NEIGHBOR_NUM) 482878ed226SJulian Elischer s = NG_HCI_MAX_NEIGHBOR_NUM; 483878ed226SJulian Elischer 484878ed226SJulian Elischer /* Prepare response */ 485878ed226SJulian Elischer NG_MKRESPONSE(rsp, msg, sizeof(*e1) + s * sizeof(*e2), 486878ed226SJulian Elischer M_NOWAIT); 487878ed226SJulian Elischer if (rsp == NULL) { 488878ed226SJulian Elischer error = ENOMEM; 489878ed226SJulian Elischer break; 490878ed226SJulian Elischer } 491878ed226SJulian Elischer 492878ed226SJulian Elischer e1 = (ng_hci_node_get_neighbor_cache_ep *)(rsp->data); 493878ed226SJulian Elischer e2 = (ng_hci_node_neighbor_cache_entry_ep *)(e1 + 1); 494878ed226SJulian Elischer 495878ed226SJulian Elischer e1->num_entries = s; 496878ed226SJulian Elischer 497878ed226SJulian Elischer LIST_FOREACH(n, &unit->neighbors, next) { 498878ed226SJulian Elischer e2->page_scan_rep_mode = n->page_scan_rep_mode; 499878ed226SJulian Elischer e2->page_scan_mode = n->page_scan_mode; 500878ed226SJulian Elischer e2->clock_offset = n->clock_offset; 5014aa92fe2STakanori Watanabe e2->addrtype = 5024aa92fe2STakanori Watanabe ng_hci_linktype_to_addrtype(n->addrtype); 5034aa92fe2STakanori Watanabe e2->extinq_size = n->extinq_size; 504878ed226SJulian Elischer bcopy(&n->bdaddr, &e2->bdaddr, 505878ed226SJulian Elischer sizeof(e2->bdaddr)); 506878ed226SJulian Elischer bcopy(&n->features, &e2->features, 507878ed226SJulian Elischer sizeof(e2->features)); 5084aa92fe2STakanori Watanabe bcopy(&n->extinq_data, &e2->extinq_data, 5094aa92fe2STakanori Watanabe n->extinq_size); 510878ed226SJulian Elischer e2 ++; 511878ed226SJulian Elischer if (--s <= 0) 512878ed226SJulian Elischer break; 513878ed226SJulian Elischer } 514878ed226SJulian Elischer } break; 515878ed226SJulian Elischer 516878ed226SJulian Elischer /* Get connection list */ 517878ed226SJulian Elischer case NGM_HCI_NODE_GET_CON_LIST: { 518878ed226SJulian Elischer ng_hci_unit_con_p c = NULL; 519878ed226SJulian Elischer ng_hci_node_con_list_ep *e1 = NULL; 520878ed226SJulian Elischer ng_hci_node_con_ep *e2 = NULL; 521878ed226SJulian Elischer int s = 0; 522878ed226SJulian Elischer 523878ed226SJulian Elischer /* Count number of connections in the list */ 524878ed226SJulian Elischer LIST_FOREACH(c, &unit->con_list, next) 525878ed226SJulian Elischer s ++; 526878ed226SJulian Elischer if (s > NG_HCI_MAX_CON_NUM) 527878ed226SJulian Elischer s = NG_HCI_MAX_CON_NUM; 528878ed226SJulian Elischer 529878ed226SJulian Elischer /* Prepare response */ 530878ed226SJulian Elischer NG_MKRESPONSE(rsp, msg, sizeof(*e1) + s * sizeof(*e2), 531878ed226SJulian Elischer M_NOWAIT); 532878ed226SJulian Elischer if (rsp == NULL) { 533878ed226SJulian Elischer error = ENOMEM; 534878ed226SJulian Elischer break; 535878ed226SJulian Elischer } 536878ed226SJulian Elischer 537878ed226SJulian Elischer e1 = (ng_hci_node_con_list_ep *)(rsp->data); 538878ed226SJulian Elischer e2 = (ng_hci_node_con_ep *)(e1 + 1); 539878ed226SJulian Elischer 540878ed226SJulian Elischer e1->num_connections = s; 541878ed226SJulian Elischer 542878ed226SJulian Elischer LIST_FOREACH(c, &unit->con_list, next) { 543878ed226SJulian Elischer e2->link_type = c->link_type; 544878ed226SJulian Elischer e2->encryption_mode= c->encryption_mode; 545878ed226SJulian Elischer e2->mode = c->mode; 546878ed226SJulian Elischer e2->role = c->role; 547878ed226SJulian Elischer 548878ed226SJulian Elischer e2->state = c->state; 549878ed226SJulian Elischer 550878ed226SJulian Elischer e2->pending = c->pending; 551878ed226SJulian Elischer e2->queue_len = NG_BT_ITEMQ_LEN(&c->conq); 552878ed226SJulian Elischer 553878ed226SJulian Elischer e2->con_handle = c->con_handle; 554878ed226SJulian Elischer bcopy(&c->bdaddr, &e2->bdaddr, 555878ed226SJulian Elischer sizeof(e2->bdaddr)); 556878ed226SJulian Elischer 557878ed226SJulian Elischer e2 ++; 558878ed226SJulian Elischer if (--s <= 0) 559878ed226SJulian Elischer break; 560878ed226SJulian Elischer } 561878ed226SJulian Elischer } break; 562878ed226SJulian Elischer 563878ed226SJulian Elischer /* Get link policy settings mask */ 564878ed226SJulian Elischer case NGM_HCI_NODE_GET_LINK_POLICY_SETTINGS_MASK: 565878ed226SJulian Elischer NG_MKRESPONSE(rsp, msg, sizeof(unit->link_policy_mask), 566878ed226SJulian Elischer M_NOWAIT); 567878ed226SJulian Elischer if (rsp == NULL) { 568878ed226SJulian Elischer error = ENOMEM; 569878ed226SJulian Elischer break; 570878ed226SJulian Elischer } 571878ed226SJulian Elischer 572878ed226SJulian Elischer *((ng_hci_node_link_policy_mask_ep *)(rsp->data)) = 573878ed226SJulian Elischer unit->link_policy_mask; 574878ed226SJulian Elischer break; 575878ed226SJulian Elischer 576878ed226SJulian Elischer /* Set link policy settings mask */ 577878ed226SJulian Elischer case NGM_HCI_NODE_SET_LINK_POLICY_SETTINGS_MASK: 578878ed226SJulian Elischer if (msg->header.arglen != 579878ed226SJulian Elischer sizeof(ng_hci_node_link_policy_mask_ep)) { 580878ed226SJulian Elischer error = EMSGSIZE; 581878ed226SJulian Elischer break; 582878ed226SJulian Elischer } 583878ed226SJulian Elischer 584878ed226SJulian Elischer unit->link_policy_mask = 585878ed226SJulian Elischer *((ng_hci_node_link_policy_mask_ep *) 586878ed226SJulian Elischer (msg->data)); 587878ed226SJulian Elischer break; 588878ed226SJulian Elischer 589878ed226SJulian Elischer /* Get packet mask */ 590878ed226SJulian Elischer case NGM_HCI_NODE_GET_PACKET_MASK: 591878ed226SJulian Elischer NG_MKRESPONSE(rsp, msg, sizeof(unit->packet_mask), 592878ed226SJulian Elischer M_NOWAIT); 593878ed226SJulian Elischer if (rsp == NULL) { 594878ed226SJulian Elischer error = ENOMEM; 595878ed226SJulian Elischer break; 596878ed226SJulian Elischer } 597878ed226SJulian Elischer 598878ed226SJulian Elischer *((ng_hci_node_packet_mask_ep *)(rsp->data)) = 599878ed226SJulian Elischer unit->packet_mask; 600878ed226SJulian Elischer break; 601878ed226SJulian Elischer 602878ed226SJulian Elischer /* Set packet mask */ 603878ed226SJulian Elischer case NGM_HCI_NODE_SET_PACKET_MASK: 604878ed226SJulian Elischer if (msg->header.arglen != 605878ed226SJulian Elischer sizeof(ng_hci_node_packet_mask_ep)) { 606878ed226SJulian Elischer error = EMSGSIZE; 607878ed226SJulian Elischer break; 608878ed226SJulian Elischer } 609878ed226SJulian Elischer 610878ed226SJulian Elischer unit->packet_mask = 611878ed226SJulian Elischer *((ng_hci_node_packet_mask_ep *)(msg->data)); 612878ed226SJulian Elischer break; 613878ed226SJulian Elischer 614f2bb1caeSJulian Elischer /* Get role switch */ 615f2bb1caeSJulian Elischer case NGM_HCI_NODE_GET_ROLE_SWITCH: 616f2bb1caeSJulian Elischer NG_MKRESPONSE(rsp, msg, sizeof(unit->role_switch), 617f2bb1caeSJulian Elischer M_NOWAIT); 618f2bb1caeSJulian Elischer if (rsp == NULL) { 619f2bb1caeSJulian Elischer error = ENOMEM; 620f2bb1caeSJulian Elischer break; 621f2bb1caeSJulian Elischer } 622f2bb1caeSJulian Elischer 623f2bb1caeSJulian Elischer *((ng_hci_node_role_switch_ep *)(rsp->data)) = 624f2bb1caeSJulian Elischer unit->role_switch; 625f2bb1caeSJulian Elischer break; 626f2bb1caeSJulian Elischer 627f2bb1caeSJulian Elischer /* Set role switch */ 628f2bb1caeSJulian Elischer case NGM_HCI_NODE_SET_ROLE_SWITCH: 629f2bb1caeSJulian Elischer if (msg->header.arglen != 630f2bb1caeSJulian Elischer sizeof(ng_hci_node_role_switch_ep)) { 631f2bb1caeSJulian Elischer error = EMSGSIZE; 632f2bb1caeSJulian Elischer break; 633f2bb1caeSJulian Elischer } 634f2bb1caeSJulian Elischer 635f2bb1caeSJulian Elischer unit->role_switch = 636f2bb1caeSJulian Elischer *((ng_hci_node_role_switch_ep *)(msg->data)); 637f2bb1caeSJulian Elischer break; 638f2bb1caeSJulian Elischer 639878ed226SJulian Elischer default: 640878ed226SJulian Elischer error = EINVAL; 641878ed226SJulian Elischer break; 642878ed226SJulian Elischer } 643878ed226SJulian Elischer break; 644878ed226SJulian Elischer 645878ed226SJulian Elischer default: 646878ed226SJulian Elischer error = EINVAL; 647878ed226SJulian Elischer break; 648878ed226SJulian Elischer } 649878ed226SJulian Elischer 650878ed226SJulian Elischer /* NG_RESPOND_MSG should take care of "item" and "rsp" */ 651878ed226SJulian Elischer NG_RESPOND_MSG(error, node, item, rsp); 652878ed226SJulian Elischer NG_FREE_MSG(msg); 653878ed226SJulian Elischer 654878ed226SJulian Elischer return (error); 655878ed226SJulian Elischer } /* ng_hci_default_rcvmsg */ 656878ed226SJulian Elischer 657878ed226SJulian Elischer /* 658878ed226SJulian Elischer * Process control message from upstream hooks (ACL and SCO). 659878ed226SJulian Elischer * Handle LP_xxx messages here, give everything else to default routine. 660878ed226SJulian Elischer */ 661878ed226SJulian Elischer 662878ed226SJulian Elischer static int 663878ed226SJulian Elischer ng_hci_upper_rcvmsg(node_p node, item_p item, hook_p lasthook) 664878ed226SJulian Elischer { 665878ed226SJulian Elischer ng_hci_unit_p unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node); 666878ed226SJulian Elischer int error = 0; 667878ed226SJulian Elischer 668878ed226SJulian Elischer switch (NGI_MSG(item)->header.typecookie) { 669878ed226SJulian Elischer case NGM_HCI_COOKIE: 670878ed226SJulian Elischer switch (NGI_MSG(item)->header.cmd) { 671878ed226SJulian Elischer case NGM_HCI_LP_CON_REQ: 672878ed226SJulian Elischer error = ng_hci_lp_con_req(unit, item, lasthook); 673878ed226SJulian Elischer break; 674878ed226SJulian Elischer 675878ed226SJulian Elischer case NGM_HCI_LP_DISCON_REQ: /* XXX not defined by specs */ 676878ed226SJulian Elischer error = ng_hci_lp_discon_req(unit, item, lasthook); 677878ed226SJulian Elischer break; 678878ed226SJulian Elischer 679878ed226SJulian Elischer case NGM_HCI_LP_CON_RSP: 680878ed226SJulian Elischer error = ng_hci_lp_con_rsp(unit, item, lasthook); 681878ed226SJulian Elischer break; 682878ed226SJulian Elischer 683878ed226SJulian Elischer case NGM_HCI_LP_QOS_REQ: 684878ed226SJulian Elischer error = ng_hci_lp_qos_req(unit, item, lasthook); 685878ed226SJulian Elischer break; 686878ed226SJulian Elischer 687878ed226SJulian Elischer default: 688878ed226SJulian Elischer error = ng_hci_default_rcvmsg(node, item, lasthook); 689878ed226SJulian Elischer break; 690878ed226SJulian Elischer } 691878ed226SJulian Elischer break; 692878ed226SJulian Elischer 693878ed226SJulian Elischer default: 694878ed226SJulian Elischer error = ng_hci_default_rcvmsg(node, item, lasthook); 695878ed226SJulian Elischer break; 696878ed226SJulian Elischer } 697878ed226SJulian Elischer 698878ed226SJulian Elischer return (error); 699878ed226SJulian Elischer } /* ng_hci_upper_rcvmsg */ 700878ed226SJulian Elischer 701878ed226SJulian Elischer /* 702878ed226SJulian Elischer * Process data packet from the driver hook. 703878ed226SJulian Elischer * We expect HCI events, ACL or SCO data packets. 704878ed226SJulian Elischer */ 705878ed226SJulian Elischer 706878ed226SJulian Elischer static int 707878ed226SJulian Elischer ng_hci_drv_rcvdata(hook_p hook, item_p item) 708878ed226SJulian Elischer { 709878ed226SJulian Elischer ng_hci_unit_p unit = (ng_hci_unit_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 710878ed226SJulian Elischer struct mbuf *m = NULL; 711878ed226SJulian Elischer int error = 0; 712878ed226SJulian Elischer 713878ed226SJulian Elischer /* Process packet */ 714878ed226SJulian Elischer m = NGI_M(item); /* item still has mbuf, just peeking */ 715878ed226SJulian Elischer m->m_flags |= M_PROTO1; /* mark as incoming packet */ 716878ed226SJulian Elischer 717878ed226SJulian Elischer NG_HCI_STAT_BYTES_RECV(unit->stat, m->m_pkthdr.len); 718878ed226SJulian Elischer 719878ed226SJulian Elischer /* Give copy packet to RAW hook */ 720878ed226SJulian Elischer ng_hci_mtap(unit, m); 721878ed226SJulian Elischer 722878ed226SJulian Elischer /* 723878ed226SJulian Elischer * XXX XXX XXX 724878ed226SJulian Elischer * Lower layer drivers MUST NOT send mbuf chain with empty mbuf at 725878ed226SJulian Elischer * the beginning of the chain. HCI layer WILL NOT call m_pullup() here. 726878ed226SJulian Elischer */ 727878ed226SJulian Elischer 728878ed226SJulian Elischer switch (*mtod(m, u_int8_t *)) { 729878ed226SJulian Elischer case NG_HCI_ACL_DATA_PKT: 730878ed226SJulian Elischer NG_HCI_STAT_ACL_RECV(unit->stat); 731878ed226SJulian Elischer 732878ed226SJulian Elischer if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY || 733878ed226SJulian Elischer unit->acl == NULL || NG_HOOK_NOT_VALID(unit->acl)) { 734878ed226SJulian Elischer NG_HCI_WARN( 735878ed226SJulian Elischer "%s: %s - could not forward HCI ACL data packet, state=%#x, hook=%p\n", 736878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), 737878ed226SJulian Elischer unit->state, unit->acl); 738878ed226SJulian Elischer 739878ed226SJulian Elischer NG_FREE_ITEM(item); 740878ed226SJulian Elischer } else 741878ed226SJulian Elischer NG_FWD_ITEM_HOOK(error, item, unit->acl); 742878ed226SJulian Elischer break; 743878ed226SJulian Elischer 744878ed226SJulian Elischer case NG_HCI_SCO_DATA_PKT: 745878ed226SJulian Elischer NG_HCI_STAT_SCO_RECV(unit->stat); 746878ed226SJulian Elischer 747878ed226SJulian Elischer if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY || 748878ed226SJulian Elischer unit->sco == NULL || NG_HOOK_NOT_VALID(unit->sco)) { 7498c975889SMaksim Yevmenkin NG_HCI_INFO( 750878ed226SJulian Elischer "%s: %s - could not forward HCI SCO data packet, state=%#x, hook=%p\n", 751878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), 752878ed226SJulian Elischer unit->state, unit->sco); 753878ed226SJulian Elischer 754878ed226SJulian Elischer NG_FREE_ITEM(item); 755878ed226SJulian Elischer } else 756878ed226SJulian Elischer NG_FWD_ITEM_HOOK(error, item, unit->sco); 757878ed226SJulian Elischer break; 758878ed226SJulian Elischer 759878ed226SJulian Elischer case NG_HCI_EVENT_PKT: 760878ed226SJulian Elischer NG_HCI_STAT_EVNT_RECV(unit->stat); 761878ed226SJulian Elischer 762878ed226SJulian Elischer /* Detach mbuf, discard item and process event */ 763878ed226SJulian Elischer NGI_GET_M(item, m); 764878ed226SJulian Elischer NG_FREE_ITEM(item); 765878ed226SJulian Elischer 766878ed226SJulian Elischer error = ng_hci_process_event(unit, m); 767878ed226SJulian Elischer break; 768878ed226SJulian Elischer 769878ed226SJulian Elischer default: 770878ed226SJulian Elischer NG_HCI_ALERT( 771878ed226SJulian Elischer "%s: %s - got unknown HCI packet type=%#x\n", 772878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), 773878ed226SJulian Elischer *mtod(m, u_int8_t *)); 774878ed226SJulian Elischer 775878ed226SJulian Elischer NG_FREE_ITEM(item); 776878ed226SJulian Elischer 777878ed226SJulian Elischer error = EINVAL; 778878ed226SJulian Elischer break; 779878ed226SJulian Elischer } 780878ed226SJulian Elischer 781878ed226SJulian Elischer return (error); 782878ed226SJulian Elischer } /* ng_hci_drv_rcvdata */ 783878ed226SJulian Elischer 784878ed226SJulian Elischer /* 785878ed226SJulian Elischer * Process data packet from ACL upstream hook. 786878ed226SJulian Elischer * We expect valid HCI ACL data packets. 787878ed226SJulian Elischer */ 788878ed226SJulian Elischer 789878ed226SJulian Elischer static int 790878ed226SJulian Elischer ng_hci_acl_rcvdata(hook_p hook, item_p item) 791878ed226SJulian Elischer { 792878ed226SJulian Elischer ng_hci_unit_p unit = (ng_hci_unit_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 793878ed226SJulian Elischer struct mbuf *m = NULL; 794878ed226SJulian Elischer ng_hci_unit_con_p con = NULL; 795878ed226SJulian Elischer u_int16_t con_handle; 796878ed226SJulian Elischer int size, error = 0; 797878ed226SJulian Elischer 798878ed226SJulian Elischer NG_HCI_BUFF_ACL_SIZE(unit->buffer, size); 799878ed226SJulian Elischer /* Check packet */ 800878ed226SJulian Elischer NGI_GET_M(item, m); 801878ed226SJulian Elischer 802878ed226SJulian Elischer if (*mtod(m, u_int8_t *) != NG_HCI_ACL_DATA_PKT) { 803878ed226SJulian Elischer NG_HCI_ALERT( 804878ed226SJulian Elischer "%s: %s - invalid HCI data packet type=%#x\n", 805878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), 806878ed226SJulian Elischer *mtod(m, u_int8_t *)); 807878ed226SJulian Elischer 808878ed226SJulian Elischer error = EINVAL; 809878ed226SJulian Elischer goto drop; 810878ed226SJulian Elischer } 811878ed226SJulian Elischer if (m->m_pkthdr.len < sizeof(ng_hci_acldata_pkt_t) || 812878ed226SJulian Elischer m->m_pkthdr.len > sizeof(ng_hci_acldata_pkt_t) + size) { 813878ed226SJulian Elischer NG_HCI_ALERT( 814878ed226SJulian Elischer "%s: %s - invalid HCI ACL data packet, len=%d, mtu=%d\n", 815878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), 816878ed226SJulian Elischer m->m_pkthdr.len, size); 817878ed226SJulian Elischer 818878ed226SJulian Elischer error = EMSGSIZE; 819878ed226SJulian Elischer goto drop; 820878ed226SJulian Elischer } 821878ed226SJulian Elischer 822878ed226SJulian Elischer NG_HCI_M_PULLUP(m, sizeof(ng_hci_acldata_pkt_t)); 823878ed226SJulian Elischer if (m == NULL) { 824878ed226SJulian Elischer error = ENOBUFS; 825878ed226SJulian Elischer goto drop; 826878ed226SJulian Elischer } 827878ed226SJulian Elischer 828878ed226SJulian Elischer con_handle = NG_HCI_CON_HANDLE(le16toh( 829878ed226SJulian Elischer mtod(m, ng_hci_acldata_pkt_t *)->con_handle)); 830878ed226SJulian Elischer size = le16toh(mtod(m, ng_hci_acldata_pkt_t *)->length); 831878ed226SJulian Elischer 832878ed226SJulian Elischer if (m->m_pkthdr.len != sizeof(ng_hci_acldata_pkt_t) + size) { 833878ed226SJulian Elischer NG_HCI_ALERT( 834878ed226SJulian Elischer "%s: %s - invalid HCI ACL data packet size, len=%d, length=%d\n", 835878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), 836878ed226SJulian Elischer m->m_pkthdr.len, size); 837878ed226SJulian Elischer 838878ed226SJulian Elischer error = EMSGSIZE; 839878ed226SJulian Elischer goto drop; 840878ed226SJulian Elischer } 841878ed226SJulian Elischer 842878ed226SJulian Elischer /* Queue packet */ 843878ed226SJulian Elischer con = ng_hci_con_by_handle(unit, con_handle); 844878ed226SJulian Elischer if (con == NULL) { 845878ed226SJulian Elischer NG_HCI_ERR( 846878ed226SJulian Elischer "%s: %s - unexpected HCI ACL data packet. Connection does not exists, " \ 847878ed226SJulian Elischer "con_handle=%d\n", __func__, NG_NODE_NAME(unit->node), con_handle); 848878ed226SJulian Elischer 849878ed226SJulian Elischer error = ENOENT; 850878ed226SJulian Elischer goto drop; 851878ed226SJulian Elischer } 852878ed226SJulian Elischer 853fbc48c2bSTakanori Watanabe if (con->link_type == NG_HCI_LINK_SCO) { 854878ed226SJulian Elischer NG_HCI_ERR( 855878ed226SJulian Elischer "%s: %s - unexpected HCI ACL data packet. Not ACL link, con_handle=%d, " \ 856878ed226SJulian Elischer "link_type=%d\n", __func__, NG_NODE_NAME(unit->node), 857878ed226SJulian Elischer con_handle, con->link_type); 858878ed226SJulian Elischer 859878ed226SJulian Elischer error = EINVAL; 860878ed226SJulian Elischer goto drop; 861878ed226SJulian Elischer } 862878ed226SJulian Elischer 863878ed226SJulian Elischer if (con->state != NG_HCI_CON_OPEN) { 864878ed226SJulian Elischer NG_HCI_ERR( 865878ed226SJulian Elischer "%s: %s - unexpected HCI ACL data packet. Invalid connection state=%d, " \ 866878ed226SJulian Elischer "con_handle=%d\n", __func__, NG_NODE_NAME(unit->node), 867878ed226SJulian Elischer con->state, con_handle); 868878ed226SJulian Elischer 869878ed226SJulian Elischer error = EHOSTDOWN; 870878ed226SJulian Elischer goto drop; 871878ed226SJulian Elischer } 872878ed226SJulian Elischer 873878ed226SJulian Elischer if (NG_BT_ITEMQ_FULL(&con->conq)) { 874878ed226SJulian Elischer NG_HCI_ALERT( 875878ed226SJulian Elischer "%s: %s - dropping HCI ACL data packet, con_handle=%d, len=%d, queue_len=%d\n", 876878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), con_handle, 877878ed226SJulian Elischer m->m_pkthdr.len, NG_BT_ITEMQ_LEN(&con->conq)); 878878ed226SJulian Elischer 879878ed226SJulian Elischer NG_BT_ITEMQ_DROP(&con->conq); 880878ed226SJulian Elischer 881878ed226SJulian Elischer error = ENOBUFS; 882878ed226SJulian Elischer goto drop; 883878ed226SJulian Elischer } 884878ed226SJulian Elischer 885878ed226SJulian Elischer /* Queue item and schedule data transfer */ 886878ed226SJulian Elischer NGI_M(item) = m; 887878ed226SJulian Elischer NG_BT_ITEMQ_ENQUEUE(&con->conq, item); 888878ed226SJulian Elischer item = NULL; 889878ed226SJulian Elischer m = NULL; 890878ed226SJulian Elischer 891878ed226SJulian Elischer ng_hci_send_data(unit); 892878ed226SJulian Elischer drop: 893878ed226SJulian Elischer if (item != NULL) 894878ed226SJulian Elischer NG_FREE_ITEM(item); 895878ed226SJulian Elischer 896878ed226SJulian Elischer NG_FREE_M(m); /* NG_FREE_M() checks for m != NULL */ 897878ed226SJulian Elischer 898878ed226SJulian Elischer return (error); 899878ed226SJulian Elischer } /* ng_hci_acl_rcvdata */ 900878ed226SJulian Elischer 901878ed226SJulian Elischer /* 902878ed226SJulian Elischer * Process data packet from SCO upstream hook. 903878ed226SJulian Elischer * We expect valid HCI SCO data packets 904878ed226SJulian Elischer */ 905878ed226SJulian Elischer 906878ed226SJulian Elischer static int 907878ed226SJulian Elischer ng_hci_sco_rcvdata(hook_p hook, item_p item) 908878ed226SJulian Elischer { 909878ed226SJulian Elischer ng_hci_unit_p unit = (ng_hci_unit_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 910878ed226SJulian Elischer struct mbuf *m = NULL; 911878ed226SJulian Elischer ng_hci_unit_con_p con = NULL; 912878ed226SJulian Elischer u_int16_t con_handle; 913878ed226SJulian Elischer int size, error = 0; 914878ed226SJulian Elischer 915878ed226SJulian Elischer NG_HCI_BUFF_SCO_SIZE(unit->buffer, size); 916878ed226SJulian Elischer 917878ed226SJulian Elischer /* Check packet */ 918878ed226SJulian Elischer NGI_GET_M(item, m); 919878ed226SJulian Elischer 920878ed226SJulian Elischer if (*mtod(m, u_int8_t *) != NG_HCI_SCO_DATA_PKT) { 921878ed226SJulian Elischer NG_HCI_ALERT( 922878ed226SJulian Elischer "%s: %s - invalid HCI data packet type=%#x\n", 923878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), 924878ed226SJulian Elischer *mtod(m, u_int8_t *)); 925878ed226SJulian Elischer 926878ed226SJulian Elischer error = EINVAL; 927878ed226SJulian Elischer goto drop; 928878ed226SJulian Elischer } 929878ed226SJulian Elischer 930878ed226SJulian Elischer if (m->m_pkthdr.len < sizeof(ng_hci_scodata_pkt_t) || 931878ed226SJulian Elischer m->m_pkthdr.len > sizeof(ng_hci_scodata_pkt_t) + size) { 932878ed226SJulian Elischer NG_HCI_ALERT( 933878ed226SJulian Elischer "%s: %s - invalid HCI SCO data packet, len=%d, mtu=%d\n", 934878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), 935878ed226SJulian Elischer m->m_pkthdr.len, size); 936878ed226SJulian Elischer 937878ed226SJulian Elischer error = EMSGSIZE; 938878ed226SJulian Elischer goto drop; 939878ed226SJulian Elischer } 940878ed226SJulian Elischer 941878ed226SJulian Elischer NG_HCI_M_PULLUP(m, sizeof(ng_hci_scodata_pkt_t)); 942878ed226SJulian Elischer if (m == NULL) { 943878ed226SJulian Elischer error = ENOBUFS; 944878ed226SJulian Elischer goto drop; 945878ed226SJulian Elischer } 946878ed226SJulian Elischer 947878ed226SJulian Elischer con_handle = NG_HCI_CON_HANDLE(le16toh( 948878ed226SJulian Elischer mtod(m, ng_hci_scodata_pkt_t *)->con_handle)); 949878ed226SJulian Elischer size = mtod(m, ng_hci_scodata_pkt_t *)->length; 950878ed226SJulian Elischer 951878ed226SJulian Elischer if (m->m_pkthdr.len != sizeof(ng_hci_scodata_pkt_t) + size) { 952878ed226SJulian Elischer NG_HCI_ALERT( 953878ed226SJulian Elischer "%s: %s - invalid HCI SCO data packet size, len=%d, length=%d\n", 954878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), 955878ed226SJulian Elischer m->m_pkthdr.len, size); 956878ed226SJulian Elischer 957878ed226SJulian Elischer error = EMSGSIZE; 958878ed226SJulian Elischer goto drop; 959878ed226SJulian Elischer } 960878ed226SJulian Elischer 961878ed226SJulian Elischer /* Queue packet */ 962878ed226SJulian Elischer con = ng_hci_con_by_handle(unit, con_handle); 963878ed226SJulian Elischer if (con == NULL) { 964878ed226SJulian Elischer NG_HCI_ERR( 965878ed226SJulian Elischer "%s: %s - unexpected HCI SCO data packet. Connection does not exists, " \ 966878ed226SJulian Elischer "con_handle=%d\n", __func__, NG_NODE_NAME(unit->node), con_handle); 967878ed226SJulian Elischer 968878ed226SJulian Elischer error = ENOENT; 969878ed226SJulian Elischer goto drop; 970878ed226SJulian Elischer } 971878ed226SJulian Elischer 972878ed226SJulian Elischer if (con->link_type != NG_HCI_LINK_SCO) { 973878ed226SJulian Elischer NG_HCI_ERR( 974878ed226SJulian Elischer "%s: %s - unexpected HCI SCO data packet. Not SCO link, con_handle=%d, " \ 975878ed226SJulian Elischer "link_type=%d\n", __func__, NG_NODE_NAME(unit->node), 976878ed226SJulian Elischer con_handle, con->link_type); 977878ed226SJulian Elischer 978878ed226SJulian Elischer error = EINVAL; 979878ed226SJulian Elischer goto drop; 980878ed226SJulian Elischer } 981878ed226SJulian Elischer 982878ed226SJulian Elischer if (con->state != NG_HCI_CON_OPEN) { 983878ed226SJulian Elischer NG_HCI_ERR( 984878ed226SJulian Elischer "%s: %s - unexpected HCI SCO data packet. Invalid connection state=%d, " \ 985878ed226SJulian Elischer "con_handle=%d\n", __func__, NG_NODE_NAME(unit->node), 986878ed226SJulian Elischer con->state, con_handle); 987878ed226SJulian Elischer 988878ed226SJulian Elischer error = EHOSTDOWN; 989878ed226SJulian Elischer goto drop; 990878ed226SJulian Elischer } 991878ed226SJulian Elischer 992878ed226SJulian Elischer if (NG_BT_ITEMQ_FULL(&con->conq)) { 993878ed226SJulian Elischer NG_HCI_ALERT( 994878ed226SJulian Elischer "%s: %s - dropping HCI SCO data packet, con_handle=%d, len=%d, queue_len=%d\n", 995878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), con_handle, 996878ed226SJulian Elischer m->m_pkthdr.len, NG_BT_ITEMQ_LEN(&con->conq)); 997878ed226SJulian Elischer 998878ed226SJulian Elischer NG_BT_ITEMQ_DROP(&con->conq); 999878ed226SJulian Elischer 1000878ed226SJulian Elischer error = ENOBUFS; 1001878ed226SJulian Elischer goto drop; 1002878ed226SJulian Elischer } 1003878ed226SJulian Elischer 1004878ed226SJulian Elischer /* Queue item and schedule data transfer */ 1005878ed226SJulian Elischer NGI_M(item) = m; 1006878ed226SJulian Elischer NG_BT_ITEMQ_ENQUEUE(&con->conq, item); 1007878ed226SJulian Elischer item = NULL; 1008878ed226SJulian Elischer m = NULL; 1009878ed226SJulian Elischer 1010878ed226SJulian Elischer ng_hci_send_data(unit); 1011878ed226SJulian Elischer drop: 1012878ed226SJulian Elischer if (item != NULL) 1013878ed226SJulian Elischer NG_FREE_ITEM(item); 1014878ed226SJulian Elischer 1015878ed226SJulian Elischer NG_FREE_M(m); /* NG_FREE_M() checks for m != NULL */ 1016878ed226SJulian Elischer 1017878ed226SJulian Elischer return (error); 1018878ed226SJulian Elischer } /* ng_hci_sco_rcvdata */ 1019878ed226SJulian Elischer 1020878ed226SJulian Elischer /* 1021878ed226SJulian Elischer * Process data packet from uptream RAW hook. 1022878ed226SJulian Elischer * We expect valid HCI command packets. 1023878ed226SJulian Elischer */ 1024878ed226SJulian Elischer 1025878ed226SJulian Elischer static int 1026878ed226SJulian Elischer ng_hci_raw_rcvdata(hook_p hook, item_p item) 1027878ed226SJulian Elischer { 1028878ed226SJulian Elischer ng_hci_unit_p unit = (ng_hci_unit_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 1029878ed226SJulian Elischer struct mbuf *m = NULL; 1030878ed226SJulian Elischer int error = 0; 1031878ed226SJulian Elischer 1032878ed226SJulian Elischer NGI_GET_M(item, m); 1033878ed226SJulian Elischer NG_FREE_ITEM(item); 1034878ed226SJulian Elischer 1035878ed226SJulian Elischer /* Check packet */ 1036878ed226SJulian Elischer if (*mtod(m, u_int8_t *) != NG_HCI_CMD_PKT) { 1037878ed226SJulian Elischer NG_HCI_ALERT( 1038878ed226SJulian Elischer "%s: %s - invalid HCI command packet type=%#x\n", 1039878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), 1040878ed226SJulian Elischer *mtod(m, u_int8_t *)); 1041878ed226SJulian Elischer 1042878ed226SJulian Elischer error = EINVAL; 1043878ed226SJulian Elischer goto drop; 1044878ed226SJulian Elischer } 1045878ed226SJulian Elischer 1046878ed226SJulian Elischer if (m->m_pkthdr.len < sizeof(ng_hci_cmd_pkt_t)) { 1047878ed226SJulian Elischer NG_HCI_ALERT( 1048878ed226SJulian Elischer "%s: %s - invalid HCI command packet len=%d\n", 1049878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), m->m_pkthdr.len); 1050878ed226SJulian Elischer 1051878ed226SJulian Elischer error = EMSGSIZE; 1052878ed226SJulian Elischer goto drop; 1053878ed226SJulian Elischer } 1054878ed226SJulian Elischer 1055878ed226SJulian Elischer NG_HCI_M_PULLUP(m, sizeof(ng_hci_cmd_pkt_t)); 1056878ed226SJulian Elischer if (m == NULL) { 1057878ed226SJulian Elischer error = ENOBUFS; 1058878ed226SJulian Elischer goto drop; 1059878ed226SJulian Elischer } 1060878ed226SJulian Elischer 1061878ed226SJulian Elischer if (m->m_pkthdr.len != 1062878ed226SJulian Elischer mtod(m, ng_hci_cmd_pkt_t *)->length + sizeof(ng_hci_cmd_pkt_t)) { 1063878ed226SJulian Elischer NG_HCI_ALERT( 1064878ed226SJulian Elischer "%s: %s - invalid HCI command packet size, len=%d, length=%d\n", 1065878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), m->m_pkthdr.len, 1066878ed226SJulian Elischer mtod(m, ng_hci_cmd_pkt_t *)->length); 1067878ed226SJulian Elischer 1068878ed226SJulian Elischer error = EMSGSIZE; 1069878ed226SJulian Elischer goto drop; 1070878ed226SJulian Elischer } 1071878ed226SJulian Elischer 1072878ed226SJulian Elischer if (mtod(m, ng_hci_cmd_pkt_t *)->opcode == 0) { 1073878ed226SJulian Elischer NG_HCI_ALERT( 1074878ed226SJulian Elischer "%s: %s - invalid HCI command opcode\n", 1075878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node)); 1076878ed226SJulian Elischer 1077878ed226SJulian Elischer error = EINVAL; 1078878ed226SJulian Elischer goto drop; 1079878ed226SJulian Elischer } 1080878ed226SJulian Elischer 1081878ed226SJulian Elischer if (NG_BT_MBUFQ_FULL(&unit->cmdq)) { 1082878ed226SJulian Elischer NG_HCI_ALERT( 1083878ed226SJulian Elischer "%s: %s - dropping HCI command packet, len=%d, queue_len=%d\n", 1084878ed226SJulian Elischer __func__, NG_NODE_NAME(unit->node), m->m_pkthdr.len, 1085878ed226SJulian Elischer NG_BT_MBUFQ_LEN(&unit->cmdq)); 1086878ed226SJulian Elischer 1087878ed226SJulian Elischer NG_BT_MBUFQ_DROP(&unit->cmdq); 1088878ed226SJulian Elischer 1089878ed226SJulian Elischer error = ENOBUFS; 1090878ed226SJulian Elischer goto drop; 1091878ed226SJulian Elischer } 1092878ed226SJulian Elischer 1093878ed226SJulian Elischer /* Queue and send command */ 1094878ed226SJulian Elischer NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); 1095878ed226SJulian Elischer m = NULL; 1096878ed226SJulian Elischer 1097878ed226SJulian Elischer if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) 1098878ed226SJulian Elischer error = ng_hci_send_command(unit); 1099878ed226SJulian Elischer drop: 1100878ed226SJulian Elischer NG_FREE_M(m); /* NG_FREE_M() checks for m != NULL */ 1101878ed226SJulian Elischer 1102878ed226SJulian Elischer return (error); 1103878ed226SJulian Elischer } /* ng_hci_raw_rcvdata */ 1104