ng_hci_main.c revision 107120
1107120Sjulian/* 2107120Sjulian * ng_hci_main.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 * 28107120Sjulian * $Id: ng_hci_main.c,v 1.28 2002/11/12 22:35:40 max Exp $ 29107120Sjulian * $FreeBSD: head/sys/netgraph/bluetooth/hci/ng_hci_main.c 107120 2002-11-20 23:01:59Z julian $ 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 <netgraph/ng_parse.h> 42107120Sjulian#include "ng_bluetooth.h" 43107120Sjulian#include "ng_hci.h" 44107120Sjulian#include "ng_hci_var.h" 45107120Sjulian#include "ng_hci_prse.h" 46107120Sjulian#include "ng_hci_cmds.h" 47107120Sjulian#include "ng_hci_evnt.h" 48107120Sjulian#include "ng_hci_ulpi.h" 49107120Sjulian#include "ng_hci_misc.h" 50107120Sjulian 51107120Sjulian/****************************************************************************** 52107120Sjulian ****************************************************************************** 53107120Sjulian ** This node implements Bluetooth Host Controller Interface (HCI) 54107120Sjulian ****************************************************************************** 55107120Sjulian ******************************************************************************/ 56107120Sjulian 57107120Sjulian/* MALLOC define */ 58107120Sjulian#ifdef NG_SEPARATE_MALLOC 59107120SjulianMALLOC_DEFINE(M_NETGRAPH_HCI, "netgraph_hci", "Netgraph Bluetooth HCI node"); 60107120Sjulian#else 61107120Sjulian#define M_NETGRAPH_HCI M_NETGRAPH 62107120Sjulian#endif /* NG_SEPARATE_MALLOC */ 63107120Sjulian 64107120Sjulian/* Netgraph node methods */ 65107120Sjulianstatic ng_constructor_t ng_hci_constructor; 66107120Sjulianstatic ng_shutdown_t ng_hci_shutdown; 67107120Sjulianstatic ng_newhook_t ng_hci_newhook; 68107120Sjulianstatic ng_connect_t ng_hci_connect; 69107120Sjulianstatic ng_disconnect_t ng_hci_disconnect; 70107120Sjulianstatic ng_rcvmsg_t ng_hci_default_rcvmsg; 71107120Sjulianstatic ng_rcvmsg_t ng_hci_upper_rcvmsg; 72107120Sjulianstatic ng_rcvdata_t ng_hci_drv_rcvdata; 73107120Sjulianstatic ng_rcvdata_t ng_hci_acl_rcvdata; 74107120Sjulianstatic ng_rcvdata_t ng_hci_sco_rcvdata; 75107120Sjulianstatic ng_rcvdata_t ng_hci_raw_rcvdata; 76107120Sjulian 77107120Sjulian/* Netgraph node type descriptor */ 78107120Sjulianstatic struct ng_type typestruct = { 79107120Sjulian NG_ABI_VERSION, 80107120Sjulian NG_HCI_NODE_TYPE, /* typename */ 81107120Sjulian NULL, /* modevent */ 82107120Sjulian ng_hci_constructor, /* constructor */ 83107120Sjulian ng_hci_default_rcvmsg, /* control message */ 84107120Sjulian ng_hci_shutdown, /* destructor */ 85107120Sjulian ng_hci_newhook, /* new hook */ 86107120Sjulian NULL, /* findhook */ 87107120Sjulian ng_hci_connect, /* connect hook */ 88107120Sjulian ng_hci_drv_rcvdata, /* data */ 89107120Sjulian ng_hci_disconnect, /* disconnect hook */ 90107120Sjulian ng_hci_cmdlist /* node command list */ 91107120Sjulian}; 92107120SjulianNETGRAPH_INIT(hci, &typestruct); 93107120SjulianMODULE_VERSION(ng_hci, NG_BLUETOOTH_VERSION); 94107120SjulianMODULE_DEPEND(ng_hci, ng_bluetooth, NG_BLUETOOTH_VERSION, 95107120Sjulian NG_BLUETOOTH_VERSION, NG_BLUETOOTH_VERSION); 96107120Sjulian 97107120Sjulian/***************************************************************************** 98107120Sjulian ***************************************************************************** 99107120Sjulian ** Netgraph methods implementation 100107120Sjulian ***************************************************************************** 101107120Sjulian *****************************************************************************/ 102107120Sjulian 103107120Sjulian/* 104107120Sjulian * Create new instance of HCI node (new unit) 105107120Sjulian */ 106107120Sjulian 107107120Sjulianstatic int 108107120Sjulianng_hci_constructor(node_p node) 109107120Sjulian{ 110107120Sjulian ng_hci_unit_p unit = NULL; 111107120Sjulian 112107120Sjulian MALLOC(unit, ng_hci_unit_p, sizeof(*unit), M_NETGRAPH_HCI, 113107120Sjulian M_NOWAIT | M_ZERO); 114107120Sjulian if (unit == NULL) 115107120Sjulian return (ENOMEM); 116107120Sjulian 117107120Sjulian unit->node = node; 118107120Sjulian unit->debug = NG_HCI_WARN_LEVEL; 119107120Sjulian 120107120Sjulian unit->link_policy_mask = 0xffff; /* Enable all supported modes */ 121107120Sjulian unit->packet_mask = 0xffff; /* Enable all packet types */ 122107120Sjulian 123107120Sjulian /* 124107120Sjulian * Set default buffer info 125107120Sjulian * 126107120Sjulian * One HCI command 127107120Sjulian * One ACL packet with max. size of 17 bytes (1 DM1 packet) 128107120Sjulian * One SCO packet with max. size of 10 bytes (1 HV1 packet) 129107120Sjulian */ 130107120Sjulian 131107120Sjulian NG_HCI_BUFF_CMD_SET(unit->buffer, 1); 132107120Sjulian NG_HCI_BUFF_ACL_SET(unit->buffer, 1, 17, 1); 133107120Sjulian NG_HCI_BUFF_SCO_SET(unit->buffer, 1, 10, 1); 134107120Sjulian 135107120Sjulian /* Init command queue & command timeout handler */ 136107120Sjulian callout_handle_init(&unit->cmd_timo); 137107120Sjulian NG_BT_MBUFQ_INIT(&unit->cmdq, NG_HCI_CMD_QUEUE_LEN); 138107120Sjulian 139107120Sjulian /* Init lists */ 140107120Sjulian LIST_INIT(&unit->con_list); 141107120Sjulian LIST_INIT(&unit->neighbors); 142107120Sjulian 143107120Sjulian /* 144107120Sjulian * This node has to be a WRITER because both data and messages 145107120Sjulian * can change node state. 146107120Sjulian */ 147107120Sjulian 148107120Sjulian NG_NODE_FORCE_WRITER(node); 149107120Sjulian NG_NODE_SET_PRIVATE(node, unit); 150107120Sjulian 151107120Sjulian return (0); 152107120Sjulian} /* ng_hci_constructor */ 153107120Sjulian 154107120Sjulian/* 155107120Sjulian * Destroy the node 156107120Sjulian */ 157107120Sjulian 158107120Sjulianstatic int 159107120Sjulianng_hci_shutdown(node_p node) 160107120Sjulian{ 161107120Sjulian ng_hci_unit_p unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node); 162107120Sjulian 163107120Sjulian NG_NODE_SET_PRIVATE(node, NULL); 164107120Sjulian NG_NODE_UNREF(node); 165107120Sjulian 166107120Sjulian unit->node = NULL; 167107120Sjulian ng_hci_unit_clean(unit, 0x16 /* Connection terminated by local host */); 168107120Sjulian 169107120Sjulian NG_BT_MBUFQ_DESTROY(&unit->cmdq); 170107120Sjulian 171107120Sjulian bzero(unit, sizeof(*unit)); 172107120Sjulian FREE(unit, M_NETGRAPH_HCI); 173107120Sjulian 174107120Sjulian return (0); 175107120Sjulian} /* ng_hci_shutdown */ 176107120Sjulian 177107120Sjulian/* 178107120Sjulian * Give our OK for a hook to be added. Unit driver is connected to the driver 179107120Sjulian * (NG_HCI_HOOK_DRV) hook. Upper layer protocols are connected to appropriate 180107120Sjulian * (NG_HCI_HOOK_ACL or NG_HCI_HOOK_SCO) hooks. 181107120Sjulian */ 182107120Sjulian 183107120Sjulianstatic int 184107120Sjulianng_hci_newhook(node_p node, hook_p hook, char const *name) 185107120Sjulian{ 186107120Sjulian ng_hci_unit_p unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node); 187107120Sjulian hook_p *h = NULL; 188107120Sjulian 189107120Sjulian if (strcmp(name, NG_HCI_HOOK_DRV) == 0) 190107120Sjulian h = &unit->drv; 191107120Sjulian else if (strcmp(name, NG_HCI_HOOK_ACL) == 0) 192107120Sjulian h = &unit->acl; 193107120Sjulian else if (strcmp(name, NG_HCI_HOOK_SCO) == 0) 194107120Sjulian h = &unit->sco; 195107120Sjulian else if (strcmp(name, NG_HCI_HOOK_RAW) == 0) 196107120Sjulian h = &unit->raw; 197107120Sjulian else 198107120Sjulian return (EINVAL); 199107120Sjulian 200107120Sjulian if (*h != NULL) 201107120Sjulian return (EISCONN); 202107120Sjulian 203107120Sjulian *h = hook; 204107120Sjulian 205107120Sjulian return (0); 206107120Sjulian} /* ng_hci_newhook */ 207107120Sjulian 208107120Sjulian/* 209107120Sjulian * Give our final OK to connect hook 210107120Sjulian */ 211107120Sjulian 212107120Sjulianstatic int 213107120Sjulianng_hci_connect(hook_p hook) 214107120Sjulian{ 215107120Sjulian ng_hci_unit_p unit = (ng_hci_unit_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 216107120Sjulian 217107120Sjulian if (hook != unit->drv) { 218107120Sjulian if (hook == unit->acl) { 219107120Sjulian NG_HOOK_SET_RCVMSG(hook, ng_hci_upper_rcvmsg); 220107120Sjulian NG_HOOK_SET_RCVDATA(hook, ng_hci_acl_rcvdata); 221107120Sjulian } else if (hook == unit->sco) { 222107120Sjulian NG_HOOK_SET_RCVMSG(hook, ng_hci_upper_rcvmsg); 223107120Sjulian NG_HOOK_SET_RCVDATA(hook, ng_hci_sco_rcvdata); 224107120Sjulian } else 225107120Sjulian NG_HOOK_SET_RCVDATA(hook, ng_hci_raw_rcvdata); 226107120Sjulian 227107120Sjulian /* Send delayed notification to the upper layers */ 228107120Sjulian if (hook != unit->raw) 229107120Sjulian ng_send_fn(unit->node, hook, ng_hci_node_is_up, NULL,0); 230107120Sjulian } else 231107120Sjulian unit->state |= NG_HCI_UNIT_CONNECTED; 232107120Sjulian 233107120Sjulian return (0); 234107120Sjulian} /* ng_hci_connect */ 235107120Sjulian 236107120Sjulian/* 237107120Sjulian * Disconnect the hook 238107120Sjulian */ 239107120Sjulian 240107120Sjulianstatic int 241107120Sjulianng_hci_disconnect(hook_p hook) 242107120Sjulian{ 243107120Sjulian ng_hci_unit_p unit = (ng_hci_unit_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 244107120Sjulian 245107120Sjulian if (hook == unit->acl) 246107120Sjulian unit->acl = NULL; 247107120Sjulian else if (hook == unit->sco) 248107120Sjulian unit->sco = NULL; 249107120Sjulian else if (hook == unit->raw) 250107120Sjulian unit->raw = NULL; 251107120Sjulian else if (hook == unit->drv) { 252107120Sjulian unit->drv = NULL; 253107120Sjulian 254107120Sjulian /* Connection terminated by local host */ 255107120Sjulian ng_hci_unit_clean(unit, 0x16); 256107120Sjulian unit->state &= ~(NG_HCI_UNIT_CONNECTED|NG_HCI_UNIT_INITED); 257107120Sjulian } else 258107120Sjulian return (EINVAL); 259107120Sjulian 260107120Sjulian /* Shutdown when all hooks are disconnected */ 261107120Sjulian if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) && 262107120Sjulian (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) 263107120Sjulian ng_rmnode_self(NG_HOOK_NODE(hook)); 264107120Sjulian 265107120Sjulian return (0); 266107120Sjulian} /* ng_hci_disconnect */ 267107120Sjulian 268107120Sjulian/* 269107120Sjulian * Default control message processing routine. Control message could be: 270107120Sjulian * 271107120Sjulian * 1) GENERIC Netgraph messages 272107120Sjulian * 273107120Sjulian * 2) Control message directed to the node itself. 274107120Sjulian */ 275107120Sjulian 276107120Sjulianstatic int 277107120Sjulianng_hci_default_rcvmsg(node_p node, item_p item, hook_p lasthook) 278107120Sjulian{ 279107120Sjulian ng_hci_unit_p unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node); 280107120Sjulian struct ng_mesg *msg = NULL, *rsp = NULL; 281107120Sjulian int error = 0; 282107120Sjulian 283107120Sjulian NGI_GET_MSG(item, msg); 284107120Sjulian 285107120Sjulian switch (msg->header.typecookie) { 286107120Sjulian case NGM_GENERIC_COOKIE: 287107120Sjulian switch (msg->header.cmd) { 288107120Sjulian case NGM_TEXT_STATUS: { 289107120Sjulian int cmd_avail, 290107120Sjulian acl_total, acl_avail, acl_size, 291107120Sjulian sco_total, sco_avail, sco_size; 292107120Sjulian 293107120Sjulian NG_MKRESPONSE(rsp, msg, NG_TEXTRESPONSE, M_NOWAIT); 294107120Sjulian if (rsp == NULL) { 295107120Sjulian error = ENOMEM; 296107120Sjulian break; 297107120Sjulian } 298107120Sjulian 299107120Sjulian NG_HCI_BUFF_CMD_GET(unit->buffer, cmd_avail); 300107120Sjulian 301107120Sjulian NG_HCI_BUFF_ACL_AVAIL(unit->buffer, acl_avail); 302107120Sjulian NG_HCI_BUFF_ACL_TOTAL(unit->buffer, acl_total); 303107120Sjulian NG_HCI_BUFF_ACL_SIZE(unit->buffer, acl_size); 304107120Sjulian 305107120Sjulian NG_HCI_BUFF_SCO_AVAIL(unit->buffer, sco_avail); 306107120Sjulian NG_HCI_BUFF_SCO_TOTAL(unit->buffer, sco_total); 307107120Sjulian NG_HCI_BUFF_SCO_SIZE(unit->buffer, sco_size); 308107120Sjulian 309107120Sjulian snprintf(rsp->data, NG_TEXTRESPONSE, 310107120Sjulian "bdaddr %x:%x:%x:%x:%x:%x\n" \ 311107120Sjulian "Hooks %s %s %s %s\n" \ 312107120Sjulian "State %#x\n" \ 313107120Sjulian "Queue cmd:%d\n" \ 314107120Sjulian "Buffer cmd:%d,acl:%d,%d,%d,sco:%d,%d,%d", 315107120Sjulian unit->bdaddr.b[5], unit->bdaddr.b[4], 316107120Sjulian unit->bdaddr.b[3], unit->bdaddr.b[2], 317107120Sjulian unit->bdaddr.b[1], unit->bdaddr.b[0], 318107120Sjulian (unit->drv != NULL)? NG_HCI_HOOK_DRV : "", 319107120Sjulian (unit->acl != NULL)? NG_HCI_HOOK_ACL : "", 320107120Sjulian (unit->sco != NULL)? NG_HCI_HOOK_SCO : "", 321107120Sjulian (unit->raw != NULL)? NG_HCI_HOOK_RAW : "", 322107120Sjulian unit->state, 323107120Sjulian NG_BT_MBUFQ_LEN(&unit->cmdq), 324107120Sjulian cmd_avail, 325107120Sjulian acl_avail, acl_total, acl_size, 326107120Sjulian sco_avail, sco_total, sco_size); 327107120Sjulian } break; 328107120Sjulian 329107120Sjulian default: 330107120Sjulian error = EINVAL; 331107120Sjulian break; 332107120Sjulian } 333107120Sjulian break; 334107120Sjulian 335107120Sjulian case NGM_HCI_COOKIE: 336107120Sjulian switch (msg->header.cmd) { 337107120Sjulian /* Get current node state */ 338107120Sjulian case NGM_HCI_NODE_GET_STATE: 339107120Sjulian NG_MKRESPONSE(rsp, msg, sizeof(unit->state), M_NOWAIT); 340107120Sjulian if (rsp == NULL) { 341107120Sjulian error = ENOMEM; 342107120Sjulian break; 343107120Sjulian } 344107120Sjulian 345107120Sjulian *((ng_hci_node_state_ep *)(rsp->data)) = unit->state; 346107120Sjulian break; 347107120Sjulian 348107120Sjulian /* Turn INITED bit - node initialized */ 349107120Sjulian case NGM_HCI_NODE_INIT: 350107120Sjulian if (bcmp(&unit->bdaddr, NG_HCI_BDADDR_ANY, 351107120Sjulian sizeof(bdaddr_t)) == 0) { 352107120Sjulian error = ENXIO; 353107120Sjulian break; 354107120Sjulian } 355107120Sjulian 356107120Sjulian unit->state |= NG_HCI_UNIT_INITED; 357107120Sjulian 358107120Sjulian ng_hci_node_is_up(unit->node, unit->acl, NULL, 0); 359107120Sjulian ng_hci_node_is_up(unit->node, unit->sco, NULL, 0); 360107120Sjulian break; 361107120Sjulian 362107120Sjulian /* Get node debug level */ 363107120Sjulian case NGM_HCI_NODE_GET_DEBUG: 364107120Sjulian NG_MKRESPONSE(rsp, msg, sizeof(unit->debug), M_NOWAIT); 365107120Sjulian if (rsp == NULL) { 366107120Sjulian error = ENOMEM; 367107120Sjulian break; 368107120Sjulian } 369107120Sjulian 370107120Sjulian *((ng_hci_node_debug_ep *)(rsp->data)) = unit->debug; 371107120Sjulian break; 372107120Sjulian 373107120Sjulian /* Set node debug level */ 374107120Sjulian case NGM_HCI_NODE_SET_DEBUG: 375107120Sjulian if (msg->header.arglen != sizeof(ng_hci_node_debug_ep)){ 376107120Sjulian error = EMSGSIZE; 377107120Sjulian break; 378107120Sjulian } 379107120Sjulian 380107120Sjulian unit->debug = *((ng_hci_node_debug_ep *)(msg->data)); 381107120Sjulian break; 382107120Sjulian 383107120Sjulian /* Get buffer info */ 384107120Sjulian case NGM_HCI_NODE_GET_BUFFER: { 385107120Sjulian ng_hci_node_buffer_ep *ep = NULL; 386107120Sjulian 387107120Sjulian NG_MKRESPONSE(rsp, msg, sizeof(ng_hci_node_buffer_ep), 388107120Sjulian M_NOWAIT); 389107120Sjulian if (rsp == NULL) { 390107120Sjulian error = ENOMEM; 391107120Sjulian break; 392107120Sjulian } 393107120Sjulian 394107120Sjulian ep = (ng_hci_node_buffer_ep *)(rsp->data); 395107120Sjulian 396107120Sjulian NG_HCI_BUFF_CMD_GET(unit->buffer, ep->cmd_free); 397107120Sjulian NG_HCI_BUFF_ACL_AVAIL(unit->buffer, ep->acl_free); 398107120Sjulian NG_HCI_BUFF_ACL_TOTAL(unit->buffer, ep->acl_pkts); 399107120Sjulian NG_HCI_BUFF_ACL_SIZE(unit->buffer, ep->acl_size); 400107120Sjulian NG_HCI_BUFF_SCO_AVAIL(unit->buffer, ep->sco_free); 401107120Sjulian NG_HCI_BUFF_SCO_TOTAL(unit->buffer, ep->sco_pkts); 402107120Sjulian NG_HCI_BUFF_SCO_SIZE(unit->buffer, ep->sco_size); 403107120Sjulian } break; 404107120Sjulian 405107120Sjulian /* Get BDADDR */ 406107120Sjulian case NGM_HCI_NODE_GET_BDADDR: 407107120Sjulian NG_MKRESPONSE(rsp, msg, sizeof(bdaddr_t), M_NOWAIT); 408107120Sjulian if (rsp == NULL) { 409107120Sjulian error = ENOMEM; 410107120Sjulian break; 411107120Sjulian } 412107120Sjulian 413107120Sjulian bcopy(&unit->bdaddr, rsp->data, sizeof(bdaddr_t)); 414107120Sjulian break; 415107120Sjulian 416107120Sjulian /* Get features */ 417107120Sjulian case NGM_HCI_NODE_GET_FEATURES: 418107120Sjulian NG_MKRESPONSE(rsp,msg,sizeof(unit->features),M_NOWAIT); 419107120Sjulian if (rsp == NULL) { 420107120Sjulian error = ENOMEM; 421107120Sjulian break; 422107120Sjulian } 423107120Sjulian 424107120Sjulian bcopy(&unit->features,rsp->data,sizeof(unit->features)); 425107120Sjulian break; 426107120Sjulian 427107120Sjulian /* Get stat */ 428107120Sjulian case NGM_HCI_NODE_GET_STAT: 429107120Sjulian NG_MKRESPONSE(rsp, msg, sizeof(unit->stat), M_NOWAIT); 430107120Sjulian if (rsp == NULL) { 431107120Sjulian error = ENOMEM; 432107120Sjulian break; 433107120Sjulian } 434107120Sjulian 435107120Sjulian bcopy(&unit->stat, rsp->data, sizeof(unit->stat)); 436107120Sjulian break; 437107120Sjulian 438107120Sjulian /* Reset stat */ 439107120Sjulian case NGM_HCI_NODE_RESET_STAT: 440107120Sjulian NG_HCI_STAT_RESET(unit->stat); 441107120Sjulian break; 442107120Sjulian 443107120Sjulian /* Clean up neighbors list */ 444107120Sjulian case NGM_HCI_NODE_FLUSH_NEIGHBOR_CACHE: 445107120Sjulian ng_hci_flush_neighbor_cache(unit); 446107120Sjulian break; 447107120Sjulian 448107120Sjulian /* Get neighbor cache entries */ 449107120Sjulian case NGM_HCI_NODE_GET_NEIGHBOR_CACHE: { 450107120Sjulian ng_hci_neighbor_p n = NULL; 451107120Sjulian ng_hci_node_get_neighbor_cache_ep *e1 = NULL; 452107120Sjulian ng_hci_node_neighbor_cache_entry_ep *e2 = NULL; 453107120Sjulian int s = 0; 454107120Sjulian 455107120Sjulian /* Look for the fresh entries in the cache */ 456107120Sjulian for (n = LIST_FIRST(&unit->neighbors); n != NULL; ) { 457107120Sjulian ng_hci_neighbor_p nn = LIST_NEXT(n, next); 458107120Sjulian 459107120Sjulian if (ng_hci_neighbor_stale(n)) 460107120Sjulian ng_hci_free_neighbor(n); 461107120Sjulian else 462107120Sjulian s ++; 463107120Sjulian 464107120Sjulian n = nn; 465107120Sjulian } 466107120Sjulian if (s > NG_HCI_MAX_NEIGHBOR_NUM) 467107120Sjulian s = NG_HCI_MAX_NEIGHBOR_NUM; 468107120Sjulian 469107120Sjulian /* Prepare response */ 470107120Sjulian NG_MKRESPONSE(rsp, msg, sizeof(*e1) + s * sizeof(*e2), 471107120Sjulian M_NOWAIT); 472107120Sjulian if (rsp == NULL) { 473107120Sjulian error = ENOMEM; 474107120Sjulian break; 475107120Sjulian } 476107120Sjulian 477107120Sjulian e1 = (ng_hci_node_get_neighbor_cache_ep *)(rsp->data); 478107120Sjulian e2 = (ng_hci_node_neighbor_cache_entry_ep *)(e1 + 1); 479107120Sjulian 480107120Sjulian e1->num_entries = s; 481107120Sjulian 482107120Sjulian LIST_FOREACH(n, &unit->neighbors, next) { 483107120Sjulian e2->page_scan_rep_mode = n->page_scan_rep_mode; 484107120Sjulian e2->page_scan_mode = n->page_scan_mode; 485107120Sjulian e2->clock_offset = n->clock_offset; 486107120Sjulian bcopy(&n->bdaddr, &e2->bdaddr, 487107120Sjulian sizeof(e2->bdaddr)); 488107120Sjulian bcopy(&n->features, &e2->features, 489107120Sjulian sizeof(e2->features)); 490107120Sjulian 491107120Sjulian e2 ++; 492107120Sjulian if (--s <= 0) 493107120Sjulian break; 494107120Sjulian } 495107120Sjulian } break; 496107120Sjulian 497107120Sjulian /* Get connection list */ 498107120Sjulian case NGM_HCI_NODE_GET_CON_LIST: { 499107120Sjulian ng_hci_unit_con_p c = NULL; 500107120Sjulian ng_hci_node_con_list_ep *e1 = NULL; 501107120Sjulian ng_hci_node_con_ep *e2 = NULL; 502107120Sjulian int s = 0; 503107120Sjulian 504107120Sjulian /* Count number of connections in the list */ 505107120Sjulian LIST_FOREACH(c, &unit->con_list, next) 506107120Sjulian s ++; 507107120Sjulian if (s > NG_HCI_MAX_CON_NUM) 508107120Sjulian s = NG_HCI_MAX_CON_NUM; 509107120Sjulian 510107120Sjulian /* Prepare response */ 511107120Sjulian NG_MKRESPONSE(rsp, msg, sizeof(*e1) + s * sizeof(*e2), 512107120Sjulian M_NOWAIT); 513107120Sjulian if (rsp == NULL) { 514107120Sjulian error = ENOMEM; 515107120Sjulian break; 516107120Sjulian } 517107120Sjulian 518107120Sjulian e1 = (ng_hci_node_con_list_ep *)(rsp->data); 519107120Sjulian e2 = (ng_hci_node_con_ep *)(e1 + 1); 520107120Sjulian 521107120Sjulian e1->num_connections = s; 522107120Sjulian 523107120Sjulian LIST_FOREACH(c, &unit->con_list, next) { 524107120Sjulian e2->link_type = c->link_type; 525107120Sjulian e2->encryption_mode= c->encryption_mode; 526107120Sjulian e2->mode = c->mode; 527107120Sjulian e2->role = c->role; 528107120Sjulian 529107120Sjulian e2->state = c->state; 530107120Sjulian 531107120Sjulian e2->pending = c->pending; 532107120Sjulian e2->queue_len = NG_BT_ITEMQ_LEN(&c->conq); 533107120Sjulian 534107120Sjulian e2->con_handle = c->con_handle; 535107120Sjulian bcopy(&c->bdaddr, &e2->bdaddr, 536107120Sjulian sizeof(e2->bdaddr)); 537107120Sjulian 538107120Sjulian 539107120Sjulian e2 ++; 540107120Sjulian if (--s <= 0) 541107120Sjulian break; 542107120Sjulian } 543107120Sjulian } break; 544107120Sjulian 545107120Sjulian /* Get link policy settings mask */ 546107120Sjulian case NGM_HCI_NODE_GET_LINK_POLICY_SETTINGS_MASK: 547107120Sjulian NG_MKRESPONSE(rsp, msg, sizeof(unit->link_policy_mask), 548107120Sjulian M_NOWAIT); 549107120Sjulian if (rsp == NULL) { 550107120Sjulian error = ENOMEM; 551107120Sjulian break; 552107120Sjulian } 553107120Sjulian 554107120Sjulian *((ng_hci_node_link_policy_mask_ep *)(rsp->data)) = 555107120Sjulian unit->link_policy_mask; 556107120Sjulian break; 557107120Sjulian 558107120Sjulian /* Set link policy settings mask */ 559107120Sjulian case NGM_HCI_NODE_SET_LINK_POLICY_SETTINGS_MASK: 560107120Sjulian if (msg->header.arglen != 561107120Sjulian sizeof(ng_hci_node_link_policy_mask_ep)) { 562107120Sjulian error = EMSGSIZE; 563107120Sjulian break; 564107120Sjulian } 565107120Sjulian 566107120Sjulian unit->link_policy_mask = 567107120Sjulian *((ng_hci_node_link_policy_mask_ep *) 568107120Sjulian (msg->data)); 569107120Sjulian break; 570107120Sjulian 571107120Sjulian /* Get packet mask */ 572107120Sjulian case NGM_HCI_NODE_GET_PACKET_MASK: 573107120Sjulian NG_MKRESPONSE(rsp, msg, sizeof(unit->packet_mask), 574107120Sjulian M_NOWAIT); 575107120Sjulian if (rsp == NULL) { 576107120Sjulian error = ENOMEM; 577107120Sjulian break; 578107120Sjulian } 579107120Sjulian 580107120Sjulian *((ng_hci_node_packet_mask_ep *)(rsp->data)) = 581107120Sjulian unit->packet_mask; 582107120Sjulian break; 583107120Sjulian 584107120Sjulian /* Set packet mask */ 585107120Sjulian case NGM_HCI_NODE_SET_PACKET_MASK: 586107120Sjulian if (msg->header.arglen != 587107120Sjulian sizeof(ng_hci_node_packet_mask_ep)) { 588107120Sjulian error = EMSGSIZE; 589107120Sjulian break; 590107120Sjulian } 591107120Sjulian 592107120Sjulian unit->packet_mask = 593107120Sjulian *((ng_hci_node_packet_mask_ep *)(msg->data)); 594107120Sjulian break; 595107120Sjulian 596107120Sjulian default: 597107120Sjulian error = EINVAL; 598107120Sjulian break; 599107120Sjulian } 600107120Sjulian break; 601107120Sjulian 602107120Sjulian default: 603107120Sjulian error = EINVAL; 604107120Sjulian break; 605107120Sjulian } 606107120Sjulian 607107120Sjulian /* NG_RESPOND_MSG should take care of "item" and "rsp" */ 608107120Sjulian NG_RESPOND_MSG(error, node, item, rsp); 609107120Sjulian NG_FREE_MSG(msg); 610107120Sjulian 611107120Sjulian return (error); 612107120Sjulian} /* ng_hci_default_rcvmsg */ 613107120Sjulian 614107120Sjulian/* 615107120Sjulian * Process control message from upstream hooks (ACL and SCO). 616107120Sjulian * Handle LP_xxx messages here, give everything else to default routine. 617107120Sjulian */ 618107120Sjulian 619107120Sjulianstatic int 620107120Sjulianng_hci_upper_rcvmsg(node_p node, item_p item, hook_p lasthook) 621107120Sjulian{ 622107120Sjulian ng_hci_unit_p unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node); 623107120Sjulian int error = 0; 624107120Sjulian 625107120Sjulian switch (NGI_MSG(item)->header.typecookie) { 626107120Sjulian case NGM_HCI_COOKIE: 627107120Sjulian switch (NGI_MSG(item)->header.cmd) { 628107120Sjulian case NGM_HCI_LP_CON_REQ: 629107120Sjulian error = ng_hci_lp_con_req(unit, item, lasthook); 630107120Sjulian break; 631107120Sjulian 632107120Sjulian case NGM_HCI_LP_DISCON_REQ: /* XXX not defined by specs */ 633107120Sjulian error = ng_hci_lp_discon_req(unit, item, lasthook); 634107120Sjulian break; 635107120Sjulian 636107120Sjulian case NGM_HCI_LP_CON_RSP: 637107120Sjulian error = ng_hci_lp_con_rsp(unit, item, lasthook); 638107120Sjulian break; 639107120Sjulian 640107120Sjulian case NGM_HCI_LP_QOS_REQ: 641107120Sjulian error = ng_hci_lp_qos_req(unit, item, lasthook); 642107120Sjulian break; 643107120Sjulian 644107120Sjulian default: 645107120Sjulian error = ng_hci_default_rcvmsg(node, item, lasthook); 646107120Sjulian break; 647107120Sjulian } 648107120Sjulian break; 649107120Sjulian 650107120Sjulian default: 651107120Sjulian error = ng_hci_default_rcvmsg(node, item, lasthook); 652107120Sjulian break; 653107120Sjulian } 654107120Sjulian 655107120Sjulian return (error); 656107120Sjulian} /* ng_hci_upper_rcvmsg */ 657107120Sjulian 658107120Sjulian/* 659107120Sjulian * Process data packet from the driver hook. 660107120Sjulian * We expect HCI events, ACL or SCO data packets. 661107120Sjulian */ 662107120Sjulian 663107120Sjulianstatic int 664107120Sjulianng_hci_drv_rcvdata(hook_p hook, item_p item) 665107120Sjulian{ 666107120Sjulian ng_hci_unit_p unit = (ng_hci_unit_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 667107120Sjulian struct mbuf *m = NULL; 668107120Sjulian int error = 0; 669107120Sjulian 670107120Sjulian /* Process packet */ 671107120Sjulian m = NGI_M(item); /* item still has mbuf, just peeking */ 672107120Sjulian m->m_flags |= M_PROTO1; /* mark as incoming packet */ 673107120Sjulian 674107120Sjulian NG_HCI_STAT_BYTES_RECV(unit->stat, m->m_pkthdr.len); 675107120Sjulian 676107120Sjulian /* Give copy packet to RAW hook */ 677107120Sjulian ng_hci_mtap(unit, m); 678107120Sjulian 679107120Sjulian /* 680107120Sjulian * XXX XXX XXX 681107120Sjulian * Lower layer drivers MUST NOT send mbuf chain with empty mbuf at 682107120Sjulian * the beginning of the chain. HCI layer WILL NOT call m_pullup() here. 683107120Sjulian */ 684107120Sjulian 685107120Sjulian switch (*mtod(m, u_int8_t *)) { 686107120Sjulian case NG_HCI_ACL_DATA_PKT: 687107120Sjulian NG_HCI_STAT_ACL_RECV(unit->stat); 688107120Sjulian 689107120Sjulian if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY || 690107120Sjulian unit->acl == NULL || NG_HOOK_NOT_VALID(unit->acl)) { 691107120Sjulian NG_HCI_WARN( 692107120Sjulian"%s: %s - could not forward HCI ACL data packet, state=%#x, hook=%p\n", 693107120Sjulian __func__, NG_NODE_NAME(unit->node), 694107120Sjulian unit->state, unit->acl); 695107120Sjulian 696107120Sjulian NG_FREE_ITEM(item); 697107120Sjulian } else 698107120Sjulian NG_FWD_ITEM_HOOK(error, item, unit->acl); 699107120Sjulian break; 700107120Sjulian 701107120Sjulian case NG_HCI_SCO_DATA_PKT: 702107120Sjulian NG_HCI_STAT_SCO_RECV(unit->stat); 703107120Sjulian 704107120Sjulian if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY || 705107120Sjulian unit->sco == NULL || NG_HOOK_NOT_VALID(unit->sco)) { 706107120Sjulian NG_HCI_WARN( 707107120Sjulian"%s: %s - could not forward HCI SCO data packet, state=%#x, hook=%p\n", 708107120Sjulian __func__, NG_NODE_NAME(unit->node), 709107120Sjulian unit->state, unit->sco); 710107120Sjulian 711107120Sjulian NG_FREE_ITEM(item); 712107120Sjulian } else 713107120Sjulian NG_FWD_ITEM_HOOK(error, item, unit->sco); 714107120Sjulian break; 715107120Sjulian 716107120Sjulian case NG_HCI_EVENT_PKT: 717107120Sjulian NG_HCI_STAT_EVNT_RECV(unit->stat); 718107120Sjulian 719107120Sjulian /* Detach mbuf, discard item and process event */ 720107120Sjulian NGI_GET_M(item, m); 721107120Sjulian NG_FREE_ITEM(item); 722107120Sjulian 723107120Sjulian error = ng_hci_process_event(unit, m); 724107120Sjulian break; 725107120Sjulian 726107120Sjulian default: 727107120Sjulian NG_HCI_ALERT( 728107120Sjulian"%s: %s - got unknown HCI packet type=%#x\n", 729107120Sjulian __func__, NG_NODE_NAME(unit->node), 730107120Sjulian *mtod(m, u_int8_t *)); 731107120Sjulian 732107120Sjulian NG_FREE_ITEM(item); 733107120Sjulian 734107120Sjulian error = EINVAL; 735107120Sjulian break; 736107120Sjulian } 737107120Sjulian 738107120Sjulian return (error); 739107120Sjulian} /* ng_hci_drv_rcvdata */ 740107120Sjulian 741107120Sjulian/* 742107120Sjulian * Process data packet from ACL upstream hook. 743107120Sjulian * We expect valid HCI ACL data packets. 744107120Sjulian */ 745107120Sjulian 746107120Sjulianstatic int 747107120Sjulianng_hci_acl_rcvdata(hook_p hook, item_p item) 748107120Sjulian{ 749107120Sjulian ng_hci_unit_p unit = (ng_hci_unit_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 750107120Sjulian struct mbuf *m = NULL; 751107120Sjulian ng_hci_unit_con_p con = NULL; 752107120Sjulian u_int16_t con_handle; 753107120Sjulian int size, error = 0; 754107120Sjulian 755107120Sjulian NG_HCI_BUFF_ACL_SIZE(unit->buffer, size); 756107120Sjulian 757107120Sjulian /* Check packet */ 758107120Sjulian NGI_GET_M(item, m); 759107120Sjulian 760107120Sjulian if (*mtod(m, u_int8_t *) != NG_HCI_ACL_DATA_PKT) { 761107120Sjulian NG_HCI_ALERT( 762107120Sjulian"%s: %s - invalid HCI data packet type=%#x\n", 763107120Sjulian __func__, NG_NODE_NAME(unit->node), 764107120Sjulian *mtod(m, u_int8_t *)); 765107120Sjulian 766107120Sjulian error = EINVAL; 767107120Sjulian goto drop; 768107120Sjulian } 769107120Sjulian 770107120Sjulian if (m->m_pkthdr.len < sizeof(ng_hci_acldata_pkt_t) || 771107120Sjulian m->m_pkthdr.len > sizeof(ng_hci_acldata_pkt_t) + size) { 772107120Sjulian NG_HCI_ALERT( 773107120Sjulian"%s: %s - invalid HCI ACL data packet, len=%d, mtu=%d\n", 774107120Sjulian __func__, NG_NODE_NAME(unit->node), 775107120Sjulian m->m_pkthdr.len, size); 776107120Sjulian 777107120Sjulian error = EMSGSIZE; 778107120Sjulian goto drop; 779107120Sjulian } 780107120Sjulian 781107120Sjulian NG_HCI_M_PULLUP(m, sizeof(ng_hci_acldata_pkt_t)); 782107120Sjulian if (m == NULL) { 783107120Sjulian error = ENOBUFS; 784107120Sjulian goto drop; 785107120Sjulian } 786107120Sjulian 787107120Sjulian con_handle = NG_HCI_CON_HANDLE(le16toh( 788107120Sjulian mtod(m, ng_hci_acldata_pkt_t *)->con_handle)); 789107120Sjulian size = le16toh(mtod(m, ng_hci_acldata_pkt_t *)->length); 790107120Sjulian 791107120Sjulian if (m->m_pkthdr.len != sizeof(ng_hci_acldata_pkt_t) + size) { 792107120Sjulian NG_HCI_ALERT( 793107120Sjulian"%s: %s - invalid HCI ACL data packet size, len=%d, length=%d\n", 794107120Sjulian __func__, NG_NODE_NAME(unit->node), 795107120Sjulian m->m_pkthdr.len, size); 796107120Sjulian 797107120Sjulian error = EMSGSIZE; 798107120Sjulian goto drop; 799107120Sjulian } 800107120Sjulian 801107120Sjulian /* Queue packet */ 802107120Sjulian con = ng_hci_con_by_handle(unit, con_handle); 803107120Sjulian if (con == NULL) { 804107120Sjulian NG_HCI_ERR( 805107120Sjulian"%s: %s - unexpected HCI ACL data packet. Connection does not exists, " \ 806107120Sjulian"con_handle=%d\n", __func__, NG_NODE_NAME(unit->node), con_handle); 807107120Sjulian 808107120Sjulian error = ENOENT; 809107120Sjulian goto drop; 810107120Sjulian } 811107120Sjulian 812107120Sjulian if (con->link_type != NG_HCI_LINK_ACL) { 813107120Sjulian NG_HCI_ERR( 814107120Sjulian"%s: %s - unexpected HCI ACL data packet. Not ACL link, con_handle=%d, " \ 815107120Sjulian"link_type=%d\n", __func__, NG_NODE_NAME(unit->node), 816107120Sjulian con_handle, con->link_type); 817107120Sjulian 818107120Sjulian error = EINVAL; 819107120Sjulian goto drop; 820107120Sjulian } 821107120Sjulian 822107120Sjulian if (con->state != NG_HCI_CON_OPEN) { 823107120Sjulian NG_HCI_ERR( 824107120Sjulian"%s: %s - unexpected HCI ACL data packet. Invalid connection state=%d, " \ 825107120Sjulian"con_handle=%d\n", __func__, NG_NODE_NAME(unit->node), 826107120Sjulian con->state, con_handle); 827107120Sjulian 828107120Sjulian error = EHOSTDOWN; 829107120Sjulian goto drop; 830107120Sjulian } 831107120Sjulian 832107120Sjulian if (NG_BT_ITEMQ_FULL(&con->conq)) { 833107120Sjulian NG_HCI_ALERT( 834107120Sjulian"%s: %s - dropping HCI ACL data packet, con_handle=%d, len=%d, queue_len=%d\n", 835107120Sjulian __func__, NG_NODE_NAME(unit->node), con_handle, 836107120Sjulian m->m_pkthdr.len, NG_BT_ITEMQ_LEN(&con->conq)); 837107120Sjulian 838107120Sjulian NG_BT_ITEMQ_DROP(&con->conq); 839107120Sjulian 840107120Sjulian error = ENOBUFS; 841107120Sjulian goto drop; 842107120Sjulian } 843107120Sjulian 844107120Sjulian /* Queue item and schedule data transfer */ 845107120Sjulian NGI_M(item) = m; 846107120Sjulian NG_BT_ITEMQ_ENQUEUE(&con->conq, item); 847107120Sjulian item = NULL; 848107120Sjulian m = NULL; 849107120Sjulian 850107120Sjulian ng_hci_send_data(unit); 851107120Sjuliandrop: 852107120Sjulian if (item != NULL) 853107120Sjulian NG_FREE_ITEM(item); 854107120Sjulian 855107120Sjulian NG_FREE_M(m); /* NG_FREE_M() checks for m != NULL */ 856107120Sjulian 857107120Sjulian return (error); 858107120Sjulian} /* ng_hci_acl_rcvdata */ 859107120Sjulian 860107120Sjulian/* 861107120Sjulian * Process data packet from SCO upstream hook. 862107120Sjulian * We expect valid HCI SCO data packets 863107120Sjulian */ 864107120Sjulian 865107120Sjulianstatic int 866107120Sjulianng_hci_sco_rcvdata(hook_p hook, item_p item) 867107120Sjulian{ 868107120Sjulian ng_hci_unit_p unit = (ng_hci_unit_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 869107120Sjulian struct mbuf *m = NULL; 870107120Sjulian ng_hci_unit_con_p con = NULL; 871107120Sjulian u_int16_t con_handle; 872107120Sjulian int size, error = 0; 873107120Sjulian 874107120Sjulian NG_HCI_BUFF_SCO_SIZE(unit->buffer, size); 875107120Sjulian 876107120Sjulian /* Check packet */ 877107120Sjulian NGI_GET_M(item, m); 878107120Sjulian 879107120Sjulian if (*mtod(m, u_int8_t *) != NG_HCI_SCO_DATA_PKT) { 880107120Sjulian NG_HCI_ALERT( 881107120Sjulian"%s: %s - invalid HCI data packet type=%#x\n", 882107120Sjulian __func__, NG_NODE_NAME(unit->node), 883107120Sjulian *mtod(m, u_int8_t *)); 884107120Sjulian 885107120Sjulian error = EINVAL; 886107120Sjulian goto drop; 887107120Sjulian } 888107120Sjulian 889107120Sjulian if (m->m_pkthdr.len < sizeof(ng_hci_scodata_pkt_t) || 890107120Sjulian m->m_pkthdr.len > sizeof(ng_hci_scodata_pkt_t) + size) { 891107120Sjulian NG_HCI_ALERT( 892107120Sjulian"%s: %s - invalid HCI SCO data packet, len=%d, mtu=%d\n", 893107120Sjulian __func__, NG_NODE_NAME(unit->node), 894107120Sjulian m->m_pkthdr.len, size); 895107120Sjulian 896107120Sjulian error = EMSGSIZE; 897107120Sjulian goto drop; 898107120Sjulian } 899107120Sjulian 900107120Sjulian NG_HCI_M_PULLUP(m, sizeof(ng_hci_scodata_pkt_t)); 901107120Sjulian if (m == NULL) { 902107120Sjulian error = ENOBUFS; 903107120Sjulian goto drop; 904107120Sjulian } 905107120Sjulian 906107120Sjulian con_handle = NG_HCI_CON_HANDLE(le16toh( 907107120Sjulian mtod(m, ng_hci_scodata_pkt_t *)->con_handle)); 908107120Sjulian size = mtod(m, ng_hci_scodata_pkt_t *)->length; 909107120Sjulian 910107120Sjulian if (m->m_pkthdr.len != sizeof(ng_hci_scodata_pkt_t) + size) { 911107120Sjulian NG_HCI_ALERT( 912107120Sjulian"%s: %s - invalid HCI SCO data packet size, len=%d, length=%d\n", 913107120Sjulian __func__, NG_NODE_NAME(unit->node), 914107120Sjulian m->m_pkthdr.len, size); 915107120Sjulian 916107120Sjulian error = EMSGSIZE; 917107120Sjulian goto drop; 918107120Sjulian } 919107120Sjulian 920107120Sjulian /* Queue packet */ 921107120Sjulian con = ng_hci_con_by_handle(unit, con_handle); 922107120Sjulian if (con == NULL) { 923107120Sjulian NG_HCI_ERR( 924107120Sjulian"%s: %s - unexpected HCI SCO data packet. Connection does not exists, " \ 925107120Sjulian"con_handle=%d\n", __func__, NG_NODE_NAME(unit->node), con_handle); 926107120Sjulian 927107120Sjulian error = ENOENT; 928107120Sjulian goto drop; 929107120Sjulian } 930107120Sjulian 931107120Sjulian if (con->link_type != NG_HCI_LINK_SCO) { 932107120Sjulian NG_HCI_ERR( 933107120Sjulian"%s: %s - unexpected HCI SCO data packet. Not SCO link, con_handle=%d, " \ 934107120Sjulian"link_type=%d\n", __func__, NG_NODE_NAME(unit->node), 935107120Sjulian con_handle, con->link_type); 936107120Sjulian 937107120Sjulian error = EINVAL; 938107120Sjulian goto drop; 939107120Sjulian } 940107120Sjulian 941107120Sjulian if (con->state != NG_HCI_CON_OPEN) { 942107120Sjulian NG_HCI_ERR( 943107120Sjulian"%s: %s - unexpected HCI SCO data packet. Invalid connection state=%d, " \ 944107120Sjulian"con_handle=%d\n", __func__, NG_NODE_NAME(unit->node), 945107120Sjulian con->state, con_handle); 946107120Sjulian 947107120Sjulian error = EHOSTDOWN; 948107120Sjulian goto drop; 949107120Sjulian } 950107120Sjulian 951107120Sjulian if (NG_BT_ITEMQ_FULL(&con->conq)) { 952107120Sjulian NG_HCI_ALERT( 953107120Sjulian"%s: %s - dropping HCI SCO data packet, con_handle=%d, len=%d, queue_len=%d\n", 954107120Sjulian __func__, NG_NODE_NAME(unit->node), con_handle, 955107120Sjulian m->m_pkthdr.len, NG_BT_ITEMQ_LEN(&con->conq)); 956107120Sjulian 957107120Sjulian NG_BT_ITEMQ_DROP(&con->conq); 958107120Sjulian 959107120Sjulian error = ENOBUFS; 960107120Sjulian goto drop; 961107120Sjulian } 962107120Sjulian 963107120Sjulian /* Queue item and schedule data transfer */ 964107120Sjulian NGI_M(item) = m; 965107120Sjulian NG_BT_ITEMQ_ENQUEUE(&con->conq, item); 966107120Sjulian item = NULL; 967107120Sjulian m = NULL; 968107120Sjulian 969107120Sjulian ng_hci_send_data(unit); 970107120Sjuliandrop: 971107120Sjulian if (item != NULL) 972107120Sjulian NG_FREE_ITEM(item); 973107120Sjulian 974107120Sjulian NG_FREE_M(m); /* NG_FREE_M() checks for m != NULL */ 975107120Sjulian 976107120Sjulian return (error); 977107120Sjulian} /* ng_hci_sco_rcvdata */ 978107120Sjulian 979107120Sjulian/* 980107120Sjulian * Process data packet from uptream RAW hook. 981107120Sjulian * We expect valid HCI command packets. 982107120Sjulian */ 983107120Sjulian 984107120Sjulianstatic int 985107120Sjulianng_hci_raw_rcvdata(hook_p hook, item_p item) 986107120Sjulian{ 987107120Sjulian ng_hci_unit_p unit = (ng_hci_unit_p) NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); 988107120Sjulian struct mbuf *m = NULL; 989107120Sjulian int error = 0; 990107120Sjulian 991107120Sjulian NGI_GET_M(item, m); 992107120Sjulian NG_FREE_ITEM(item); 993107120Sjulian 994107120Sjulian /* Check packet */ 995107120Sjulian if (*mtod(m, u_int8_t *) != NG_HCI_CMD_PKT) { 996107120Sjulian NG_HCI_ALERT( 997107120Sjulian"%s: %s - invalid HCI command packet type=%#x\n", 998107120Sjulian __func__, NG_NODE_NAME(unit->node), 999107120Sjulian *mtod(m, u_int8_t *)); 1000107120Sjulian 1001107120Sjulian error = EINVAL; 1002107120Sjulian goto drop; 1003107120Sjulian } 1004107120Sjulian 1005107120Sjulian if (m->m_pkthdr.len < sizeof(ng_hci_cmd_pkt_t)) { 1006107120Sjulian NG_HCI_ALERT( 1007107120Sjulian"%s: %s - invalid HCI command packet len=%d\n", 1008107120Sjulian __func__, NG_NODE_NAME(unit->node), m->m_pkthdr.len); 1009107120Sjulian 1010107120Sjulian error = EMSGSIZE; 1011107120Sjulian goto drop; 1012107120Sjulian } 1013107120Sjulian 1014107120Sjulian NG_HCI_M_PULLUP(m, sizeof(ng_hci_cmd_pkt_t)); 1015107120Sjulian if (m == NULL) { 1016107120Sjulian error = ENOBUFS; 1017107120Sjulian goto drop; 1018107120Sjulian } 1019107120Sjulian 1020107120Sjulian if (m->m_pkthdr.len != 1021107120Sjulian mtod(m, ng_hci_cmd_pkt_t *)->length + sizeof(ng_hci_cmd_pkt_t)) { 1022107120Sjulian NG_HCI_ALERT( 1023107120Sjulian"%s: %s - invalid HCI command packet size, len=%d, length=%d\n", 1024107120Sjulian __func__, NG_NODE_NAME(unit->node), m->m_pkthdr.len, 1025107120Sjulian mtod(m, ng_hci_cmd_pkt_t *)->length); 1026107120Sjulian 1027107120Sjulian error = EMSGSIZE; 1028107120Sjulian goto drop; 1029107120Sjulian } 1030107120Sjulian 1031107120Sjulian if (mtod(m, ng_hci_cmd_pkt_t *)->opcode == 0) { 1032107120Sjulian NG_HCI_ALERT( 1033107120Sjulian"%s: %s - invalid HCI command opcode\n", 1034107120Sjulian __func__, NG_NODE_NAME(unit->node)); 1035107120Sjulian 1036107120Sjulian error = EINVAL; 1037107120Sjulian goto drop; 1038107120Sjulian } 1039107120Sjulian 1040107120Sjulian if (NG_BT_MBUFQ_FULL(&unit->cmdq)) { 1041107120Sjulian NG_HCI_ALERT( 1042107120Sjulian"%s: %s - dropping HCI command packet, len=%d, queue_len=%d\n", 1043107120Sjulian __func__, NG_NODE_NAME(unit->node), m->m_pkthdr.len, 1044107120Sjulian NG_BT_MBUFQ_LEN(&unit->cmdq)); 1045107120Sjulian 1046107120Sjulian NG_BT_MBUFQ_DROP(&unit->cmdq); 1047107120Sjulian 1048107120Sjulian error = ENOBUFS; 1049107120Sjulian goto drop; 1050107120Sjulian } 1051107120Sjulian 1052107120Sjulian /* Queue and send command */ 1053107120Sjulian NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); 1054107120Sjulian m = NULL; 1055107120Sjulian 1056107120Sjulian if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) 1057107120Sjulian error = ng_hci_send_command(unit); 1058107120Sjuliandrop: 1059107120Sjulian NG_FREE_M(m); /* NG_FREE_M() checks for m != NULL */ 1060107120Sjulian 1061107120Sjulian return (error); 1062107120Sjulian} /* ng_hci_raw_rcvdata */ 1063107120Sjulian 1064