1107120Sjulian/* 2107120Sjulian * ng_hci_evnt.c 3139823Simp */ 4139823Simp 5139823Simp/*- 6107120Sjulian * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com> 7107120Sjulian * All rights reserved. 8107120Sjulian * 9107120Sjulian * Redistribution and use in source and binary forms, with or without 10107120Sjulian * modification, are permitted provided that the following conditions 11107120Sjulian * are met: 12107120Sjulian * 1. Redistributions of source code must retain the above copyright 13107120Sjulian * notice, this list of conditions and the following disclaimer. 14107120Sjulian * 2. Redistributions in binary form must reproduce the above copyright 15107120Sjulian * notice, this list of conditions and the following disclaimer in the 16107120Sjulian * documentation and/or other materials provided with the distribution. 17107120Sjulian * 18107120Sjulian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19107120Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20107120Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21107120Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22107120Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23107120Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24107120Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25107120Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26107120Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27107120Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28107120Sjulian * SUCH DAMAGE. 29107120Sjulian * 30121054Semax * $Id: ng_hci_evnt.c,v 1.6 2003/09/08 18:57:51 max Exp $ 31107120Sjulian * $FreeBSD$ 32107120Sjulian */ 33107120Sjulian 34107120Sjulian#include <sys/param.h> 35107120Sjulian#include <sys/systm.h> 36107120Sjulian#include <sys/kernel.h> 37107120Sjulian#include <sys/endian.h> 38107120Sjulian#include <sys/malloc.h> 39107120Sjulian#include <sys/mbuf.h> 40107120Sjulian#include <sys/queue.h> 41107120Sjulian#include <netgraph/ng_message.h> 42107120Sjulian#include <netgraph/netgraph.h> 43128688Semax#include <netgraph/bluetooth/include/ng_bluetooth.h> 44128688Semax#include <netgraph/bluetooth/include/ng_hci.h> 45128688Semax#include <netgraph/bluetooth/hci/ng_hci_var.h> 46128688Semax#include <netgraph/bluetooth/hci/ng_hci_cmds.h> 47128688Semax#include <netgraph/bluetooth/hci/ng_hci_evnt.h> 48128688Semax#include <netgraph/bluetooth/hci/ng_hci_ulpi.h> 49128688Semax#include <netgraph/bluetooth/hci/ng_hci_misc.h> 50107120Sjulian 51107120Sjulian/****************************************************************************** 52107120Sjulian ****************************************************************************** 53107120Sjulian ** HCI event processing module 54107120Sjulian ****************************************************************************** 55107120Sjulian ******************************************************************************/ 56107120Sjulian 57107120Sjulian/* 58107120Sjulian * Event processing routines 59107120Sjulian */ 60107120Sjulian 61107120Sjulianstatic int inquiry_result (ng_hci_unit_p, struct mbuf *); 62107120Sjulianstatic int con_compl (ng_hci_unit_p, struct mbuf *); 63107120Sjulianstatic int con_req (ng_hci_unit_p, struct mbuf *); 64107120Sjulianstatic int discon_compl (ng_hci_unit_p, struct mbuf *); 65114878Sjulianstatic int encryption_change (ng_hci_unit_p, struct mbuf *); 66107120Sjulianstatic int read_remote_features_compl (ng_hci_unit_p, struct mbuf *); 67107120Sjulianstatic int qos_setup_compl (ng_hci_unit_p, struct mbuf *); 68107120Sjulianstatic int hardware_error (ng_hci_unit_p, struct mbuf *); 69107120Sjulianstatic int role_change (ng_hci_unit_p, struct mbuf *); 70107120Sjulianstatic int num_compl_pkts (ng_hci_unit_p, struct mbuf *); 71107120Sjulianstatic int mode_change (ng_hci_unit_p, struct mbuf *); 72107120Sjulianstatic int data_buffer_overflow (ng_hci_unit_p, struct mbuf *); 73107120Sjulianstatic int read_clock_offset_compl (ng_hci_unit_p, struct mbuf *); 74107120Sjulianstatic int qos_violation (ng_hci_unit_p, struct mbuf *); 75107120Sjulianstatic int page_scan_mode_change (ng_hci_unit_p, struct mbuf *); 76107120Sjulianstatic int page_scan_rep_mode_change (ng_hci_unit_p, struct mbuf *); 77107120Sjulianstatic int sync_con_queue (ng_hci_unit_p, ng_hci_unit_con_p, int); 78107120Sjulianstatic int send_data_packets (ng_hci_unit_p, int, int); 79107120Sjulian 80107120Sjulian/* 81107120Sjulian * Process HCI event packet 82107120Sjulian */ 83107120Sjulian 84107120Sjulianint 85107120Sjulianng_hci_process_event(ng_hci_unit_p unit, struct mbuf *event) 86107120Sjulian{ 87107120Sjulian ng_hci_event_pkt_t *hdr = NULL; 88107120Sjulian int error = 0; 89107120Sjulian 90107120Sjulian /* Get event packet header */ 91107120Sjulian NG_HCI_M_PULLUP(event, sizeof(*hdr)); 92107120Sjulian if (event == NULL) 93107120Sjulian return (ENOBUFS); 94107120Sjulian 95107120Sjulian hdr = mtod(event, ng_hci_event_pkt_t *); 96107120Sjulian 97107120Sjulian NG_HCI_INFO( 98107120Sjulian"%s: %s - got HCI event=%#x, length=%d\n", 99107120Sjulian __func__, NG_NODE_NAME(unit->node), hdr->event, hdr->length); 100107120Sjulian 101107120Sjulian /* Get rid of event header and process event */ 102107120Sjulian m_adj(event, sizeof(*hdr)); 103107120Sjulian 104107120Sjulian switch (hdr->event) { 105107120Sjulian case NG_HCI_EVENT_INQUIRY_COMPL: 106107120Sjulian case NG_HCI_EVENT_RETURN_LINK_KEYS: 107107120Sjulian case NG_HCI_EVENT_PIN_CODE_REQ: 108107120Sjulian case NG_HCI_EVENT_LINK_KEY_REQ: 109107120Sjulian case NG_HCI_EVENT_LINK_KEY_NOTIFICATION: 110107120Sjulian case NG_HCI_EVENT_LOOPBACK_COMMAND: 111107120Sjulian case NG_HCI_EVENT_AUTH_COMPL: 112107120Sjulian case NG_HCI_EVENT_CHANGE_CON_LINK_KEY_COMPL: 113107120Sjulian case NG_HCI_EVENT_MASTER_LINK_KEY_COMPL: 114107120Sjulian case NG_HCI_EVENT_FLUSH_OCCUR: /* XXX Do we have to handle it? */ 115107120Sjulian case NG_HCI_EVENT_MAX_SLOT_CHANGE: 116107120Sjulian case NG_HCI_EVENT_CON_PKT_TYPE_CHANGED: 117107120Sjulian case NG_HCI_EVENT_BT_LOGO: 118107120Sjulian case NG_HCI_EVENT_VENDOR: 119107120Sjulian case NG_HCI_EVENT_REMOTE_NAME_REQ_COMPL: 120107120Sjulian case NG_HCI_EVENT_READ_REMOTE_VER_INFO_COMPL: 121107120Sjulian /* These do not need post processing */ 122107120Sjulian NG_FREE_M(event); 123107120Sjulian break; 124107120Sjulian 125107120Sjulian case NG_HCI_EVENT_INQUIRY_RESULT: 126107120Sjulian error = inquiry_result(unit, event); 127107120Sjulian break; 128107120Sjulian 129107120Sjulian case NG_HCI_EVENT_CON_COMPL: 130107120Sjulian error = con_compl(unit, event); 131107120Sjulian break; 132107120Sjulian 133107120Sjulian case NG_HCI_EVENT_CON_REQ: 134107120Sjulian error = con_req(unit, event); 135107120Sjulian break; 136107120Sjulian 137107120Sjulian case NG_HCI_EVENT_DISCON_COMPL: 138107120Sjulian error = discon_compl(unit, event); 139107120Sjulian break; 140107120Sjulian 141114878Sjulian case NG_HCI_EVENT_ENCRYPTION_CHANGE: 142114878Sjulian error = encryption_change(unit, event); 143114878Sjulian break; 144114878Sjulian 145107120Sjulian case NG_HCI_EVENT_READ_REMOTE_FEATURES_COMPL: 146107120Sjulian error = read_remote_features_compl(unit, event); 147107120Sjulian break; 148107120Sjulian 149107120Sjulian case NG_HCI_EVENT_QOS_SETUP_COMPL: 150107120Sjulian error = qos_setup_compl(unit, event); 151107120Sjulian break; 152107120Sjulian 153107120Sjulian case NG_HCI_EVENT_COMMAND_COMPL: 154107120Sjulian error = ng_hci_process_command_complete(unit, event); 155107120Sjulian break; 156107120Sjulian 157107120Sjulian case NG_HCI_EVENT_COMMAND_STATUS: 158107120Sjulian error = ng_hci_process_command_status(unit, event); 159107120Sjulian break; 160107120Sjulian 161107120Sjulian case NG_HCI_EVENT_HARDWARE_ERROR: 162107120Sjulian error = hardware_error(unit, event); 163107120Sjulian break; 164107120Sjulian 165107120Sjulian case NG_HCI_EVENT_ROLE_CHANGE: 166107120Sjulian error = role_change(unit, event); 167107120Sjulian break; 168107120Sjulian 169107120Sjulian case NG_HCI_EVENT_NUM_COMPL_PKTS: 170107120Sjulian error = num_compl_pkts(unit, event); 171107120Sjulian break; 172107120Sjulian 173107120Sjulian case NG_HCI_EVENT_MODE_CHANGE: 174107120Sjulian error = mode_change(unit, event); 175107120Sjulian break; 176107120Sjulian 177107120Sjulian case NG_HCI_EVENT_DATA_BUFFER_OVERFLOW: 178107120Sjulian error = data_buffer_overflow(unit, event); 179107120Sjulian break; 180107120Sjulian 181107120Sjulian case NG_HCI_EVENT_READ_CLOCK_OFFSET_COMPL: 182107120Sjulian error = read_clock_offset_compl(unit, event); 183107120Sjulian break; 184107120Sjulian 185107120Sjulian case NG_HCI_EVENT_QOS_VIOLATION: 186107120Sjulian error = qos_violation(unit, event); 187107120Sjulian break; 188107120Sjulian 189107120Sjulian case NG_HCI_EVENT_PAGE_SCAN_MODE_CHANGE: 190107120Sjulian error = page_scan_mode_change(unit, event); 191107120Sjulian break; 192107120Sjulian 193107120Sjulian case NG_HCI_EVENT_PAGE_SCAN_REP_MODE_CHANGE: 194107120Sjulian error = page_scan_rep_mode_change(unit, event); 195107120Sjulian break; 196107120Sjulian 197107120Sjulian default: 198107120Sjulian NG_FREE_M(event); 199107120Sjulian error = EINVAL; 200107120Sjulian break; 201107120Sjulian } 202107120Sjulian 203107120Sjulian return (error); 204107120Sjulian} /* ng_hci_process_event */ 205107120Sjulian 206107120Sjulian/* 207107120Sjulian * Send ACL and/or SCO data to the unit driver 208107120Sjulian */ 209107120Sjulian 210107120Sjulianvoid 211107120Sjulianng_hci_send_data(ng_hci_unit_p unit) 212107120Sjulian{ 213107120Sjulian int count; 214107120Sjulian 215107120Sjulian /* Send ACL data */ 216107120Sjulian NG_HCI_BUFF_ACL_AVAIL(unit->buffer, count); 217107120Sjulian 218107120Sjulian NG_HCI_INFO( 219107120Sjulian"%s: %s - sending ACL data packets, count=%d\n", 220107120Sjulian __func__, NG_NODE_NAME(unit->node), count); 221107120Sjulian 222107120Sjulian if (count > 0) { 223107120Sjulian count = send_data_packets(unit, NG_HCI_LINK_ACL, count); 224107120Sjulian NG_HCI_STAT_ACL_SENT(unit->stat, count); 225107120Sjulian NG_HCI_BUFF_ACL_USE(unit->buffer, count); 226107120Sjulian } 227107120Sjulian 228107120Sjulian /* Send SCO data */ 229107120Sjulian NG_HCI_BUFF_SCO_AVAIL(unit->buffer, count); 230107120Sjulian 231107120Sjulian NG_HCI_INFO( 232107120Sjulian"%s: %s - sending SCO data packets, count=%d\n", 233107120Sjulian __func__, NG_NODE_NAME(unit->node), count); 234107120Sjulian 235107120Sjulian if (count > 0) { 236107120Sjulian count = send_data_packets(unit, NG_HCI_LINK_SCO, count); 237107120Sjulian NG_HCI_STAT_SCO_SENT(unit->stat, count); 238107120Sjulian NG_HCI_BUFF_SCO_USE(unit->buffer, count); 239107120Sjulian } 240107120Sjulian} /* ng_hci_send_data */ 241107120Sjulian 242107120Sjulian/* 243107120Sjulian * Send data packets to the lower layer. 244107120Sjulian */ 245107120Sjulian 246107120Sjulianstatic int 247107120Sjuliansend_data_packets(ng_hci_unit_p unit, int link_type, int limit) 248107120Sjulian{ 249107120Sjulian ng_hci_unit_con_p con = NULL, winner = NULL; 250107120Sjulian item_p item = NULL; 251107120Sjulian int min_pending, total_sent, sent, error, v; 252107120Sjulian 253107120Sjulian for (total_sent = 0; limit > 0; ) { 254107120Sjulian min_pending = 0x0fffffff; 255107120Sjulian winner = NULL; 256107120Sjulian 257107120Sjulian /* 258107120Sjulian * Find the connection that has has data to send 259107120Sjulian * and the smallest number of pending packets 260107120Sjulian */ 261107120Sjulian 262107120Sjulian LIST_FOREACH(con, &unit->con_list, next) { 263107120Sjulian if (con->link_type != link_type) 264107120Sjulian continue; 265107120Sjulian if (NG_BT_ITEMQ_LEN(&con->conq) == 0) 266107120Sjulian continue; 267107120Sjulian 268107120Sjulian if (con->pending < min_pending) { 269107120Sjulian winner = con; 270107120Sjulian min_pending = con->pending; 271107120Sjulian } 272107120Sjulian } 273107120Sjulian 274107120Sjulian if (winner == NULL) 275107120Sjulian break; 276107120Sjulian 277107120Sjulian /* 278107120Sjulian * OK, we have a winner now send as much packets as we can 279107120Sjulian * Count the number of packets we have sent and then sync 280107120Sjulian * winner connection queue. 281107120Sjulian */ 282107120Sjulian 283107120Sjulian for (sent = 0; limit > 0; limit --, total_sent ++, sent ++) { 284107120Sjulian NG_BT_ITEMQ_DEQUEUE(&winner->conq, item); 285107120Sjulian if (item == NULL) 286107120Sjulian break; 287107120Sjulian 288107120Sjulian NG_HCI_INFO( 289107120Sjulian"%s: %s - sending data packet, handle=%d, len=%d\n", 290107120Sjulian __func__, NG_NODE_NAME(unit->node), 291107120Sjulian winner->con_handle, NGI_M(item)->m_pkthdr.len); 292107120Sjulian 293107120Sjulian /* Check if driver hook still there */ 294107120Sjulian v = (unit->drv != NULL && NG_HOOK_IS_VALID(unit->drv)); 295107120Sjulian if (!v || (unit->state & NG_HCI_UNIT_READY) != 296107120Sjulian NG_HCI_UNIT_READY) { 297107120Sjulian NG_HCI_ERR( 298107120Sjulian"%s: %s - could not send data. Hook \"%s\" is %svalid, state=%#x\n", 299107120Sjulian __func__, NG_NODE_NAME(unit->node), 300107120Sjulian NG_HCI_HOOK_DRV, ((v)? "" : "not "), 301107120Sjulian unit->state); 302107120Sjulian 303107120Sjulian NG_FREE_ITEM(item); 304107120Sjulian error = ENOTCONN; 305107120Sjulian } else { 306107120Sjulian v = NGI_M(item)->m_pkthdr.len; 307107120Sjulian 308107120Sjulian /* Give packet to raw hook */ 309107120Sjulian ng_hci_mtap(unit, NGI_M(item)); 310107120Sjulian 311107120Sjulian /* ... and forward item to the driver */ 312107120Sjulian NG_FWD_ITEM_HOOK(error, item, unit->drv); 313107120Sjulian } 314107120Sjulian 315107120Sjulian if (error != 0) { 316107120Sjulian NG_HCI_ERR( 317107120Sjulian"%s: %s - could not send data packet, handle=%d, error=%d\n", 318107120Sjulian __func__, NG_NODE_NAME(unit->node), 319107120Sjulian winner->con_handle, error); 320107120Sjulian break; 321107120Sjulian } 322107120Sjulian 323107120Sjulian winner->pending ++; 324107120Sjulian NG_HCI_STAT_BYTES_SENT(unit->stat, v); 325107120Sjulian } 326107120Sjulian 327107120Sjulian /* 328107120Sjulian * Sync connection queue for the winner 329107120Sjulian */ 330107120Sjulian 331107120Sjulian sync_con_queue(unit, winner, sent); 332107120Sjulian } 333107120Sjulian 334107120Sjulian return (total_sent); 335107120Sjulian} /* send_data_packets */ 336107120Sjulian 337107120Sjulian/* 338107120Sjulian * Send flow control messages to the upper layer 339107120Sjulian */ 340107120Sjulian 341107120Sjulianstatic int 342107120Sjuliansync_con_queue(ng_hci_unit_p unit, ng_hci_unit_con_p con, int completed) 343107120Sjulian{ 344107120Sjulian hook_p hook = NULL; 345107120Sjulian struct ng_mesg *msg = NULL; 346107120Sjulian ng_hci_sync_con_queue_ep *state = NULL; 347107120Sjulian int error; 348107120Sjulian 349107120Sjulian hook = (con->link_type == NG_HCI_LINK_ACL)? unit->acl : unit->sco; 350107120Sjulian if (hook == NULL || NG_HOOK_NOT_VALID(hook)) 351107120Sjulian return (ENOTCONN); 352107120Sjulian 353107120Sjulian NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_SYNC_CON_QUEUE, 354107120Sjulian sizeof(*state), M_NOWAIT); 355107120Sjulian if (msg == NULL) 356107120Sjulian return (ENOMEM); 357107120Sjulian 358107120Sjulian state = (ng_hci_sync_con_queue_ep *)(msg->data); 359107120Sjulian state->con_handle = con->con_handle; 360107120Sjulian state->completed = completed; 361107120Sjulian 362128076Semax NG_SEND_MSG_HOOK(error, unit->node, msg, hook, 0); 363107120Sjulian 364107120Sjulian return (error); 365107120Sjulian} /* sync_con_queue */ 366107120Sjulian 367107120Sjulian/* Inquiry result event */ 368107120Sjulianstatic int 369107120Sjulianinquiry_result(ng_hci_unit_p unit, struct mbuf *event) 370107120Sjulian{ 371107120Sjulian ng_hci_inquiry_result_ep *ep = NULL; 372107120Sjulian ng_hci_neighbor_p n = NULL; 373107120Sjulian bdaddr_t bdaddr; 374107120Sjulian int error = 0; 375107120Sjulian 376107120Sjulian NG_HCI_M_PULLUP(event, sizeof(*ep)); 377107120Sjulian if (event == NULL) 378107120Sjulian return (ENOBUFS); 379107120Sjulian 380107120Sjulian ep = mtod(event, ng_hci_inquiry_result_ep *); 381107120Sjulian m_adj(event, sizeof(*ep)); 382107120Sjulian 383107120Sjulian for (; ep->num_responses > 0; ep->num_responses --) { 384107120Sjulian /* Get remote unit address */ 385107120Sjulian m_copydata(event, 0, sizeof(bdaddr), (caddr_t) &bdaddr); 386107120Sjulian m_adj(event, sizeof(bdaddr)); 387107120Sjulian 388107120Sjulian /* Lookup entry in the cache */ 389107120Sjulian n = ng_hci_get_neighbor(unit, &bdaddr); 390107120Sjulian if (n == NULL) { 391107120Sjulian /* Create new entry */ 392107120Sjulian n = ng_hci_new_neighbor(unit); 393107120Sjulian if (n == NULL) { 394107120Sjulian error = ENOMEM; 395107120Sjulian break; 396107120Sjulian } 397107120Sjulian } else 398107120Sjulian getmicrotime(&n->updated); 399107120Sjulian 400107120Sjulian bcopy(&bdaddr, &n->bdaddr, sizeof(n->bdaddr)); 401107120Sjulian 402107120Sjulian /* XXX call m_pullup here? */ 403107120Sjulian 404107120Sjulian n->page_scan_rep_mode = *mtod(event, u_int8_t *); 405107120Sjulian m_adj(event, sizeof(u_int8_t)); 406107120Sjulian 407107120Sjulian /* page_scan_period_mode */ 408107120Sjulian m_adj(event, sizeof(u_int8_t)); 409107120Sjulian 410107120Sjulian n->page_scan_mode = *mtod(event, u_int8_t *); 411107120Sjulian m_adj(event, sizeof(u_int8_t)); 412107120Sjulian 413107120Sjulian /* class */ 414107120Sjulian m_adj(event, NG_HCI_CLASS_SIZE); 415107120Sjulian 416107120Sjulian /* clock offset */ 417107120Sjulian m_copydata(event, 0, sizeof(n->clock_offset), 418107120Sjulian (caddr_t) &n->clock_offset); 419107120Sjulian n->clock_offset = le16toh(n->clock_offset); 420107120Sjulian } 421107120Sjulian 422107120Sjulian NG_FREE_M(event); 423107120Sjulian 424107120Sjulian return (error); 425107120Sjulian} /* inquiry_result */ 426107120Sjulian 427107120Sjulian/* Connection complete event */ 428107120Sjulianstatic int 429107120Sjuliancon_compl(ng_hci_unit_p unit, struct mbuf *event) 430107120Sjulian{ 431107120Sjulian ng_hci_con_compl_ep *ep = NULL; 432107120Sjulian ng_hci_unit_con_p con = NULL; 433107120Sjulian int error = 0; 434107120Sjulian 435107120Sjulian NG_HCI_M_PULLUP(event, sizeof(*ep)); 436107120Sjulian if (event == NULL) 437107120Sjulian return (ENOBUFS); 438107120Sjulian 439107120Sjulian ep = mtod(event, ng_hci_con_compl_ep *); 440107120Sjulian 441107120Sjulian /* 442107120Sjulian * Find the first connection descriptor that matches the following: 443107120Sjulian * 444107120Sjulian * 1) con->link_type == ep->link_type 445107120Sjulian * 2) con->state == NG_HCI_CON_W4_CONN_COMPLETE 446107120Sjulian * 3) con->bdaddr == ep->bdaddr 447107120Sjulian */ 448107120Sjulian 449107120Sjulian LIST_FOREACH(con, &unit->con_list, next) 450107120Sjulian if (con->link_type == ep->link_type && 451107120Sjulian con->state == NG_HCI_CON_W4_CONN_COMPLETE && 452107120Sjulian bcmp(&con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0) 453107120Sjulian break; 454107120Sjulian 455107120Sjulian /* 456107120Sjulian * Two possible cases: 457107120Sjulian * 458107120Sjulian * 1) We have found connection descriptor. That means upper layer has 459121054Semax * requested this connection via LP_CON_REQ message. In this case 460121054Semax * connection must have timeout set. If ng_hci_con_untimeout() fails 461121054Semax * then timeout message already went into node's queue. In this case 462121054Semax * ignore Connection_Complete event and let timeout deal with it. 463107120Sjulian * 464107120Sjulian * 2) We do not have connection descriptor. That means upper layer 465107120Sjulian * nas not requested this connection or (less likely) we gave up 466107120Sjulian * on this connection (timeout). The most likely scenario is that 467107120Sjulian * we have received Create_Connection/Add_SCO_Connection command 468107120Sjulian * from the RAW hook 469107120Sjulian */ 470107120Sjulian 471107120Sjulian if (con == NULL) { 472107120Sjulian if (ep->status != 0) 473107120Sjulian goto out; 474107120Sjulian 475107120Sjulian con = ng_hci_new_con(unit, ep->link_type); 476107120Sjulian if (con == NULL) { 477107120Sjulian error = ENOMEM; 478107120Sjulian goto out; 479107120Sjulian } 480107120Sjulian 481107120Sjulian bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr)); 482121054Semax } else if ((error = ng_hci_con_untimeout(con)) != 0) 483121054Semax goto out; 484107120Sjulian 485107120Sjulian /* 486107120Sjulian * Update connection descriptor and send notification 487107120Sjulian * to the upper layers. 488107120Sjulian */ 489107120Sjulian 490107120Sjulian con->con_handle = NG_HCI_CON_HANDLE(le16toh(ep->con_handle)); 491107120Sjulian con->encryption_mode = ep->encryption_mode; 492107120Sjulian 493107120Sjulian ng_hci_lp_con_cfm(con, ep->status); 494107120Sjulian 495107120Sjulian /* Adjust connection state */ 496107120Sjulian if (ep->status != 0) 497107120Sjulian ng_hci_free_con(con); 498107120Sjulian else { 499107120Sjulian con->state = NG_HCI_CON_OPEN; 500107120Sjulian 501107120Sjulian /* 502107120Sjulian * Change link policy for the ACL connections. Enable all 503107120Sjulian * supported link modes. Enable Role switch as well if 504107120Sjulian * device supports it. 505107120Sjulian */ 506107120Sjulian 507107120Sjulian if (ep->link_type == NG_HCI_LINK_ACL) { 508107120Sjulian struct __link_policy { 509107120Sjulian ng_hci_cmd_pkt_t hdr; 510107120Sjulian ng_hci_write_link_policy_settings_cp cp; 511107120Sjulian } __attribute__ ((packed)) *lp; 512107120Sjulian struct mbuf *m; 513107120Sjulian 514243882Sglebius MGETHDR(m, M_NOWAIT, MT_DATA); 515107120Sjulian if (m != NULL) { 516107120Sjulian m->m_pkthdr.len = m->m_len = sizeof(*lp); 517107120Sjulian lp = mtod(m, struct __link_policy *); 518107120Sjulian 519107120Sjulian lp->hdr.type = NG_HCI_CMD_PKT; 520107120Sjulian lp->hdr.opcode = htole16(NG_HCI_OPCODE( 521107120Sjulian NG_HCI_OGF_LINK_POLICY, 522107120Sjulian NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS)); 523107120Sjulian lp->hdr.length = sizeof(lp->cp); 524107120Sjulian 525107120Sjulian lp->cp.con_handle = ep->con_handle; 526107120Sjulian 527107120Sjulian lp->cp.settings = 0; 528114878Sjulian if ((unit->features[0] & NG_HCI_LMP_SWITCH) && 529114878Sjulian unit->role_switch) 530107120Sjulian lp->cp.settings |= 0x1; 531107120Sjulian if (unit->features[0] & NG_HCI_LMP_HOLD_MODE) 532107120Sjulian lp->cp.settings |= 0x2; 533107120Sjulian if (unit->features[0] & NG_HCI_LMP_SNIFF_MODE) 534107120Sjulian lp->cp.settings |= 0x4; 535107120Sjulian if (unit->features[1] & NG_HCI_LMP_PARK_MODE) 536107120Sjulian lp->cp.settings |= 0x8; 537107120Sjulian 538107120Sjulian lp->cp.settings &= unit->link_policy_mask; 539107120Sjulian lp->cp.settings = htole16(lp->cp.settings); 540107120Sjulian 541107120Sjulian NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); 542107120Sjulian if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) 543107120Sjulian ng_hci_send_command(unit); 544107120Sjulian } 545107120Sjulian } 546107120Sjulian } 547107120Sjulianout: 548107120Sjulian NG_FREE_M(event); 549107120Sjulian 550107120Sjulian return (error); 551121054Semax} /* con_compl */ 552107120Sjulian 553107120Sjulian/* Connection request event */ 554107120Sjulianstatic int 555107120Sjuliancon_req(ng_hci_unit_p unit, struct mbuf *event) 556107120Sjulian{ 557107120Sjulian ng_hci_con_req_ep *ep = NULL; 558107120Sjulian ng_hci_unit_con_p con = NULL; 559107120Sjulian int error = 0; 560107120Sjulian 561107120Sjulian NG_HCI_M_PULLUP(event, sizeof(*ep)); 562107120Sjulian if (event == NULL) 563107120Sjulian return (ENOBUFS); 564107120Sjulian 565107120Sjulian ep = mtod(event, ng_hci_con_req_ep *); 566107120Sjulian 567107120Sjulian /* 568107120Sjulian * Find the first connection descriptor that matches the following: 569107120Sjulian * 570107120Sjulian * 1) con->link_type == ep->link_type 571107120Sjulian * 572107120Sjulian * 2) con->state == NG_HCI_CON_W4_LP_CON_RSP || 573107120Sjulian * con->state == NG_HCI_CON_W4_CONN_COMPL 574107120Sjulian * 575107120Sjulian * 3) con->bdaddr == ep->bdaddr 576107120Sjulian * 577107120Sjulian * Possible cases: 578107120Sjulian * 579107120Sjulian * 1) We do not have connection descriptor. This is simple. Create 580107120Sjulian * new fresh connection descriptor and send notification to the 581107120Sjulian * appropriate upstream hook (based on link_type). 582107120Sjulian * 583107120Sjulian * 2) We found connection handle. This is more complicated. 584107120Sjulian * 585107120Sjulian * 2.1) ACL links 586107120Sjulian * 587107120Sjulian * Since only one ACL link can exist between each pair of 588107120Sjulian * units then we have a race. Our upper layer has requested 589107120Sjulian * an ACL connection to the remote unit, but we did not send 590107120Sjulian * command yet. At the same time the remote unit has requested 591107120Sjulian * an ACL connection from us. In this case we will ignore 592107120Sjulian * Connection_Request event. This probably will cause connect 593107120Sjulian * failure on both units. 594107120Sjulian * 595107120Sjulian * 2.2) SCO links 596107120Sjulian * 597107120Sjulian * The spec on page 45 says : 598107120Sjulian * 599107120Sjulian * "The master can support up to three SCO links to the same 600107120Sjulian * slave or to different slaves. A slave can support up to 601107120Sjulian * three SCO links from the same master, or two SCO links if 602107120Sjulian * the links originate from different masters." 603107120Sjulian * 604107120Sjulian * The only problem is how to handle multiple SCO links between 605107120Sjulian * matster and slave. For now we will assume that multiple SCO 606107120Sjulian * links MUST be opened one after another. 607107120Sjulian */ 608107120Sjulian 609107120Sjulian LIST_FOREACH(con, &unit->con_list, next) 610107120Sjulian if (con->link_type == ep->link_type && 611107120Sjulian (con->state == NG_HCI_CON_W4_LP_CON_RSP || 612107120Sjulian con->state == NG_HCI_CON_W4_CONN_COMPLETE) && 613107120Sjulian bcmp(&con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0) 614107120Sjulian break; 615107120Sjulian 616107120Sjulian if (con == NULL) { 617107120Sjulian con = ng_hci_new_con(unit, ep->link_type); 618107120Sjulian if (con != NULL) { 619107120Sjulian bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr)); 620107120Sjulian 621107120Sjulian con->state = NG_HCI_CON_W4_LP_CON_RSP; 622107120Sjulian ng_hci_con_timeout(con); 623107120Sjulian 624107120Sjulian error = ng_hci_lp_con_ind(con, ep->uclass); 625121054Semax if (error != 0) { 626121054Semax ng_hci_con_untimeout(con); 627107120Sjulian ng_hci_free_con(con); 628121054Semax } 629107120Sjulian } else 630107120Sjulian error = ENOMEM; 631107120Sjulian } 632107120Sjulian 633107120Sjulian NG_FREE_M(event); 634107120Sjulian 635107120Sjulian return (error); 636107120Sjulian} /* con_req */ 637107120Sjulian 638107120Sjulian/* Disconnect complete event */ 639107120Sjulianstatic int 640107120Sjuliandiscon_compl(ng_hci_unit_p unit, struct mbuf *event) 641107120Sjulian{ 642107120Sjulian ng_hci_discon_compl_ep *ep = NULL; 643107120Sjulian ng_hci_unit_con_p con = NULL; 644107120Sjulian int error = 0; 645107120Sjulian u_int16_t h; 646107120Sjulian 647107120Sjulian NG_HCI_M_PULLUP(event, sizeof(*ep)); 648107120Sjulian if (event == NULL) 649107120Sjulian return (ENOBUFS); 650107120Sjulian 651107120Sjulian ep = mtod(event, ng_hci_discon_compl_ep *); 652107120Sjulian 653107120Sjulian /* 654107120Sjulian * XXX 655107120Sjulian * Do we have to send notification if ep->status != 0? 656107120Sjulian * For now we will send notification for both ACL and SCO connections 657107120Sjulian * ONLY if ep->status == 0. 658107120Sjulian */ 659107120Sjulian 660107120Sjulian if (ep->status == 0) { 661107120Sjulian h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle)); 662107120Sjulian con = ng_hci_con_by_handle(unit, h); 663107120Sjulian if (con != NULL) { 664107120Sjulian error = ng_hci_lp_discon_ind(con, ep->reason); 665121054Semax 666121054Semax /* Remove all timeouts (if any) */ 667121054Semax if (con->flags & NG_HCI_CON_TIMEOUT_PENDING) 668121054Semax ng_hci_con_untimeout(con); 669121054Semax 670107120Sjulian ng_hci_free_con(con); 671107120Sjulian } else { 672107120Sjulian NG_HCI_ALERT( 673107120Sjulian"%s: %s - invalid connection handle=%d\n", 674107120Sjulian __func__, NG_NODE_NAME(unit->node), h); 675107120Sjulian error = ENOENT; 676107120Sjulian } 677107120Sjulian } 678107120Sjulian 679107120Sjulian NG_FREE_M(event); 680107120Sjulian 681107120Sjulian return (error); 682107120Sjulian} /* discon_compl */ 683107120Sjulian 684114878Sjulian/* Encryption change event */ 685114878Sjulianstatic int 686114878Sjulianencryption_change(ng_hci_unit_p unit, struct mbuf *event) 687114878Sjulian{ 688114878Sjulian ng_hci_encryption_change_ep *ep = NULL; 689114878Sjulian ng_hci_unit_con_p con = NULL; 690114878Sjulian int error = 0; 691114878Sjulian 692114878Sjulian NG_HCI_M_PULLUP(event, sizeof(*ep)); 693114878Sjulian if (event == NULL) 694114878Sjulian return (ENOBUFS); 695114878Sjulian 696114878Sjulian ep = mtod(event, ng_hci_encryption_change_ep *); 697114878Sjulian 698114878Sjulian if (ep->status == 0) { 699114878Sjulian u_int16_t h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle)); 700114878Sjulian 701114878Sjulian con = ng_hci_con_by_handle(unit, h); 702114878Sjulian if (con == NULL) { 703114878Sjulian NG_HCI_ALERT( 704114878Sjulian"%s: %s - invalid connection handle=%d\n", 705114878Sjulian __func__, NG_NODE_NAME(unit->node), h); 706114878Sjulian error = ENOENT; 707114878Sjulian } else if (con->link_type != NG_HCI_LINK_ACL) { 708114878Sjulian NG_HCI_ALERT( 709114878Sjulian"%s: %s - invalid link type=%d\n", 710114878Sjulian __func__, NG_NODE_NAME(unit->node), 711114878Sjulian con->link_type); 712114878Sjulian error = EINVAL; 713114878Sjulian } else if (ep->encryption_enable) 714114878Sjulian /* XXX is that true? */ 715114878Sjulian con->encryption_mode = NG_HCI_ENCRYPTION_MODE_P2P; 716114878Sjulian else 717114878Sjulian con->encryption_mode = NG_HCI_ENCRYPTION_MODE_NONE; 718114878Sjulian } else 719114878Sjulian NG_HCI_ERR( 720114878Sjulian"%s: %s - failed to change encryption mode, status=%d\n", 721114878Sjulian __func__, NG_NODE_NAME(unit->node), ep->status); 722114878Sjulian 723114878Sjulian NG_FREE_M(event); 724114878Sjulian 725114878Sjulian return (error); 726114878Sjulian} /* encryption_change */ 727114878Sjulian 728107120Sjulian/* Read remote feature complete event */ 729107120Sjulianstatic int 730107120Sjulianread_remote_features_compl(ng_hci_unit_p unit, struct mbuf *event) 731107120Sjulian{ 732107120Sjulian ng_hci_read_remote_features_compl_ep *ep = NULL; 733107120Sjulian ng_hci_unit_con_p con = NULL; 734107120Sjulian ng_hci_neighbor_p n = NULL; 735107120Sjulian u_int16_t h; 736107120Sjulian int error = 0; 737107120Sjulian 738107120Sjulian NG_HCI_M_PULLUP(event, sizeof(*ep)); 739107120Sjulian if (event == NULL) 740107120Sjulian return (ENOBUFS); 741107120Sjulian 742107120Sjulian ep = mtod(event, ng_hci_read_remote_features_compl_ep *); 743107120Sjulian 744107120Sjulian if (ep->status == 0) { 745107120Sjulian /* Check if we have this connection handle */ 746107120Sjulian h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle)); 747107120Sjulian con = ng_hci_con_by_handle(unit, h); 748107120Sjulian if (con == NULL) { 749107120Sjulian NG_HCI_ALERT( 750107120Sjulian"%s: %s - invalid connection handle=%d\n", 751107120Sjulian __func__, NG_NODE_NAME(unit->node), h); 752107120Sjulian error = ENOENT; 753107120Sjulian goto out; 754107120Sjulian } 755107120Sjulian 756107120Sjulian /* Update cache entry */ 757107120Sjulian n = ng_hci_get_neighbor(unit, &con->bdaddr); 758107120Sjulian if (n == NULL) { 759107120Sjulian n = ng_hci_new_neighbor(unit); 760107120Sjulian if (n == NULL) { 761107120Sjulian error = ENOMEM; 762107120Sjulian goto out; 763107120Sjulian } 764107120Sjulian 765107120Sjulian bcopy(&con->bdaddr, &n->bdaddr, sizeof(n->bdaddr)); 766107120Sjulian } else 767107120Sjulian getmicrotime(&n->updated); 768107120Sjulian 769107120Sjulian bcopy(ep->features, n->features, sizeof(n->features)); 770107120Sjulian } else 771107120Sjulian NG_HCI_ERR( 772107120Sjulian"%s: %s - failed to read remote unit features, status=%d\n", 773107120Sjulian __func__, NG_NODE_NAME(unit->node), ep->status); 774107120Sjulianout: 775107120Sjulian NG_FREE_M(event); 776107120Sjulian 777107120Sjulian return (error); 778107120Sjulian} /* read_remote_features_compl */ 779107120Sjulian 780107120Sjulian/* QoS setup complete event */ 781107120Sjulianstatic int 782107120Sjulianqos_setup_compl(ng_hci_unit_p unit, struct mbuf *event) 783107120Sjulian{ 784107120Sjulian ng_hci_qos_setup_compl_ep *ep = NULL; 785107120Sjulian ng_hci_unit_con_p con = NULL; 786107120Sjulian u_int16_t h; 787107120Sjulian int error = 0; 788107120Sjulian 789107120Sjulian NG_HCI_M_PULLUP(event, sizeof(*ep)); 790107120Sjulian if (event == NULL) 791107120Sjulian return (ENOBUFS); 792107120Sjulian 793107120Sjulian ep = mtod(event, ng_hci_qos_setup_compl_ep *); 794107120Sjulian 795107120Sjulian /* Check if we have this connection handle */ 796107120Sjulian h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle)); 797107120Sjulian con = ng_hci_con_by_handle(unit, h); 798107120Sjulian if (con == NULL) { 799107120Sjulian NG_HCI_ALERT( 800107120Sjulian"%s: %s - invalid connection handle=%d\n", 801107120Sjulian __func__, NG_NODE_NAME(unit->node), h); 802107120Sjulian error = ENOENT; 803107120Sjulian } else if (con->link_type != NG_HCI_LINK_ACL) { 804107120Sjulian NG_HCI_ALERT( 805107120Sjulian"%s: %s - invalid link type=%d, handle=%d\n", 806107120Sjulian __func__, NG_NODE_NAME(unit->node), con->link_type, h); 807107120Sjulian error = EINVAL; 808107120Sjulian } else if (con->state != NG_HCI_CON_OPEN) { 809107120Sjulian NG_HCI_ALERT( 810107120Sjulian"%s: %s - invalid connection state=%d, handle=%d\n", 811107120Sjulian __func__, NG_NODE_NAME(unit->node), 812107120Sjulian con->state, h); 813107120Sjulian error = EINVAL; 814107120Sjulian } else /* Notify upper layer */ 815107120Sjulian error = ng_hci_lp_qos_cfm(con, ep->status); 816107120Sjulian 817107120Sjulian NG_FREE_M(event); 818107120Sjulian 819107120Sjulian return (error); 820107120Sjulian} /* qos_setup_compl */ 821107120Sjulian 822107120Sjulian/* Hardware error event */ 823107120Sjulianstatic int 824107120Sjulianhardware_error(ng_hci_unit_p unit, struct mbuf *event) 825107120Sjulian{ 826107120Sjulian NG_HCI_ALERT( 827107120Sjulian"%s: %s - hardware error %#x\n", 828107120Sjulian __func__, NG_NODE_NAME(unit->node), *mtod(event, u_int8_t *)); 829107120Sjulian 830107120Sjulian NG_FREE_M(event); 831107120Sjulian 832107120Sjulian return (0); 833107120Sjulian} /* hardware_error */ 834107120Sjulian 835107120Sjulian/* Role change event */ 836107120Sjulianstatic int 837107120Sjulianrole_change(ng_hci_unit_p unit, struct mbuf *event) 838107120Sjulian{ 839107120Sjulian ng_hci_role_change_ep *ep = NULL; 840107120Sjulian ng_hci_unit_con_p con = NULL; 841107120Sjulian 842107120Sjulian NG_HCI_M_PULLUP(event, sizeof(*ep)); 843107120Sjulian if (event == NULL) 844107120Sjulian return (ENOBUFS); 845107120Sjulian 846107120Sjulian ep = mtod(event, ng_hci_role_change_ep *); 847107120Sjulian 848107120Sjulian if (ep->status == 0) { 849107120Sjulian /* XXX shoud we also change "role" for SCO connections? */ 850107120Sjulian con = ng_hci_con_by_bdaddr(unit, &ep->bdaddr, NG_HCI_LINK_ACL); 851107120Sjulian if (con != NULL) 852107120Sjulian con->role = ep->role; 853107120Sjulian else 854107120Sjulian NG_HCI_ALERT( 855107120Sjulian"%s: %s - ACL connection does not exist, bdaddr=%x:%x:%x:%x:%x:%x\n", 856107120Sjulian __func__, NG_NODE_NAME(unit->node), 857107120Sjulian ep->bdaddr.b[5], ep->bdaddr.b[4], 858107120Sjulian ep->bdaddr.b[3], ep->bdaddr.b[2], 859107120Sjulian ep->bdaddr.b[1], ep->bdaddr.b[0]); 860107120Sjulian } else 861107120Sjulian NG_HCI_ERR( 862107120Sjulian"%s: %s - failed to change role, status=%d, bdaddr=%x:%x:%x:%x:%x:%x\n", 863107120Sjulian __func__, NG_NODE_NAME(unit->node), ep->status, 864107120Sjulian ep->bdaddr.b[5], ep->bdaddr.b[4], ep->bdaddr.b[3], 865107120Sjulian ep->bdaddr.b[2], ep->bdaddr.b[1], ep->bdaddr.b[0]); 866107120Sjulian 867107120Sjulian NG_FREE_M(event); 868107120Sjulian 869107120Sjulian return (0); 870107120Sjulian} /* role_change */ 871107120Sjulian 872107120Sjulian/* Number of completed packets event */ 873107120Sjulianstatic int 874107120Sjuliannum_compl_pkts(ng_hci_unit_p unit, struct mbuf *event) 875107120Sjulian{ 876107120Sjulian ng_hci_num_compl_pkts_ep *ep = NULL; 877107120Sjulian ng_hci_unit_con_p con = NULL; 878107120Sjulian u_int16_t h, p; 879107120Sjulian 880107120Sjulian NG_HCI_M_PULLUP(event, sizeof(*ep)); 881107120Sjulian if (event == NULL) 882107120Sjulian return (ENOBUFS); 883107120Sjulian 884107120Sjulian ep = mtod(event, ng_hci_num_compl_pkts_ep *); 885107120Sjulian m_adj(event, sizeof(*ep)); 886107120Sjulian 887107120Sjulian for (; ep->num_con_handles > 0; ep->num_con_handles --) { 888107120Sjulian /* Get connection handle */ 889107120Sjulian m_copydata(event, 0, sizeof(h), (caddr_t) &h); 890107120Sjulian m_adj(event, sizeof(h)); 891107120Sjulian h = NG_HCI_CON_HANDLE(le16toh(h)); 892107120Sjulian 893107120Sjulian /* Get number of completed packets */ 894107120Sjulian m_copydata(event, 0, sizeof(p), (caddr_t) &p); 895107120Sjulian m_adj(event, sizeof(p)); 896107120Sjulian p = le16toh(p); 897107120Sjulian 898107120Sjulian /* Check if we have this connection handle */ 899107120Sjulian con = ng_hci_con_by_handle(unit, h); 900107120Sjulian if (con != NULL) { 901107120Sjulian con->pending -= p; 902107120Sjulian if (con->pending < 0) { 903107120Sjulian NG_HCI_WARN( 904107120Sjulian"%s: %s - pending packet counter is out of sync! " \ 905107120Sjulian"handle=%d, pending=%d, ncp=%d\n", __func__, NG_NODE_NAME(unit->node), 906107120Sjulian con->con_handle, con->pending, p); 907107120Sjulian 908107120Sjulian con->pending = 0; 909107120Sjulian } 910107120Sjulian 911107120Sjulian /* Update buffer descriptor */ 912107120Sjulian if (con->link_type == NG_HCI_LINK_ACL) 913107120Sjulian NG_HCI_BUFF_ACL_FREE(unit->buffer, p); 914107120Sjulian else 915107120Sjulian NG_HCI_BUFF_SCO_FREE(unit->buffer, p); 916107120Sjulian } else 917107120Sjulian NG_HCI_ALERT( 918107120Sjulian"%s: %s - invalid connection handle=%d\n", 919107120Sjulian __func__, NG_NODE_NAME(unit->node), h); 920107120Sjulian } 921107120Sjulian 922107120Sjulian NG_FREE_M(event); 923107120Sjulian 924107120Sjulian /* Send more data */ 925107120Sjulian ng_hci_send_data(unit); 926107120Sjulian 927107120Sjulian return (0); 928107120Sjulian} /* num_compl_pkts */ 929107120Sjulian 930107120Sjulian/* Mode change event */ 931107120Sjulianstatic int 932107120Sjulianmode_change(ng_hci_unit_p unit, struct mbuf *event) 933107120Sjulian{ 934107120Sjulian ng_hci_mode_change_ep *ep = NULL; 935107120Sjulian ng_hci_unit_con_p con = NULL; 936107120Sjulian int error = 0; 937107120Sjulian 938107120Sjulian NG_HCI_M_PULLUP(event, sizeof(*ep)); 939107120Sjulian if (event == NULL) 940107120Sjulian return (ENOBUFS); 941107120Sjulian 942107120Sjulian ep = mtod(event, ng_hci_mode_change_ep *); 943107120Sjulian 944107120Sjulian if (ep->status == 0) { 945107120Sjulian u_int16_t h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle)); 946107120Sjulian 947107120Sjulian con = ng_hci_con_by_handle(unit, h); 948107120Sjulian if (con == NULL) { 949107120Sjulian NG_HCI_ALERT( 950107120Sjulian"%s: %s - invalid connection handle=%d\n", 951107120Sjulian __func__, NG_NODE_NAME(unit->node), h); 952107120Sjulian error = ENOENT; 953107120Sjulian } else if (con->link_type != NG_HCI_LINK_ACL) { 954107120Sjulian NG_HCI_ALERT( 955107120Sjulian"%s: %s - invalid link type=%d\n", 956107120Sjulian __func__, NG_NODE_NAME(unit->node), 957107120Sjulian con->link_type); 958107120Sjulian error = EINVAL; 959107120Sjulian } else 960107120Sjulian con->mode = ep->unit_mode; 961107120Sjulian } else 962107120Sjulian NG_HCI_ERR( 963107120Sjulian"%s: %s - failed to change mode, status=%d\n", 964107120Sjulian __func__, NG_NODE_NAME(unit->node), ep->status); 965107120Sjulian 966107120Sjulian NG_FREE_M(event); 967107120Sjulian 968107120Sjulian return (error); 969107120Sjulian} /* mode_change */ 970107120Sjulian 971107120Sjulian/* Data buffer overflow event */ 972107120Sjulianstatic int 973107120Sjuliandata_buffer_overflow(ng_hci_unit_p unit, struct mbuf *event) 974107120Sjulian{ 975107120Sjulian NG_HCI_ALERT( 976107120Sjulian"%s: %s - %s data buffer overflow\n", 977107120Sjulian __func__, NG_NODE_NAME(unit->node), 978107120Sjulian (*mtod(event, u_int8_t *) == NG_HCI_LINK_ACL)? "ACL" : "SCO"); 979107120Sjulian 980107120Sjulian NG_FREE_M(event); 981107120Sjulian 982107120Sjulian return (0); 983107120Sjulian} /* data_buffer_overflow */ 984107120Sjulian 985107120Sjulian/* Read clock offset complete event */ 986107120Sjulianstatic int 987107120Sjulianread_clock_offset_compl(ng_hci_unit_p unit, struct mbuf *event) 988107120Sjulian{ 989107120Sjulian ng_hci_read_clock_offset_compl_ep *ep = NULL; 990107120Sjulian ng_hci_unit_con_p con = NULL; 991107120Sjulian ng_hci_neighbor_p n = NULL; 992107120Sjulian int error = 0; 993107120Sjulian 994107120Sjulian NG_HCI_M_PULLUP(event, sizeof(*ep)); 995107120Sjulian if (event == NULL) 996107120Sjulian return (ENOBUFS); 997107120Sjulian 998107120Sjulian ep = mtod(event, ng_hci_read_clock_offset_compl_ep *); 999107120Sjulian 1000107120Sjulian if (ep->status == 0) { 1001107120Sjulian u_int16_t h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle)); 1002107120Sjulian 1003107120Sjulian con = ng_hci_con_by_handle(unit, h); 1004107120Sjulian if (con == NULL) { 1005107120Sjulian NG_HCI_ALERT( 1006107120Sjulian"%s: %s - invalid connection handle=%d\n", 1007107120Sjulian __func__, NG_NODE_NAME(unit->node), h); 1008107120Sjulian error = ENOENT; 1009107120Sjulian goto out; 1010107120Sjulian } 1011107120Sjulian 1012107120Sjulian /* Update cache entry */ 1013107120Sjulian n = ng_hci_get_neighbor(unit, &con->bdaddr); 1014107120Sjulian if (n == NULL) { 1015107120Sjulian n = ng_hci_new_neighbor(unit); 1016107120Sjulian if (n == NULL) { 1017107120Sjulian error = ENOMEM; 1018107120Sjulian goto out; 1019107120Sjulian } 1020107120Sjulian 1021107120Sjulian bcopy(&con->bdaddr, &n->bdaddr, sizeof(n->bdaddr)); 1022107120Sjulian } else 1023107120Sjulian getmicrotime(&n->updated); 1024107120Sjulian 1025107120Sjulian n->clock_offset = le16toh(ep->clock_offset); 1026107120Sjulian } else 1027107120Sjulian NG_HCI_ERR( 1028107120Sjulian"%s: %s - failed to Read Remote Clock Offset, status=%d\n", 1029107120Sjulian __func__, NG_NODE_NAME(unit->node), ep->status); 1030107120Sjulianout: 1031107120Sjulian NG_FREE_M(event); 1032107120Sjulian 1033107120Sjulian return (error); 1034107120Sjulian} /* read_clock_offset_compl */ 1035107120Sjulian 1036107120Sjulian/* QoS violation event */ 1037107120Sjulianstatic int 1038107120Sjulianqos_violation(ng_hci_unit_p unit, struct mbuf *event) 1039107120Sjulian{ 1040107120Sjulian ng_hci_qos_violation_ep *ep = NULL; 1041107120Sjulian ng_hci_unit_con_p con = NULL; 1042107120Sjulian u_int16_t h; 1043107120Sjulian int error = 0; 1044107120Sjulian 1045107120Sjulian NG_HCI_M_PULLUP(event, sizeof(*ep)); 1046107120Sjulian if (event == NULL) 1047107120Sjulian return (ENOBUFS); 1048107120Sjulian 1049107120Sjulian ep = mtod(event, ng_hci_qos_violation_ep *); 1050107120Sjulian 1051107120Sjulian /* Check if we have this connection handle */ 1052107120Sjulian h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle)); 1053107120Sjulian con = ng_hci_con_by_handle(unit, h); 1054107120Sjulian if (con == NULL) { 1055107120Sjulian NG_HCI_ALERT( 1056107120Sjulian"%s: %s - invalid connection handle=%d\n", 1057107120Sjulian __func__, NG_NODE_NAME(unit->node), h); 1058107120Sjulian error = ENOENT; 1059107120Sjulian } else if (con->link_type != NG_HCI_LINK_ACL) { 1060107120Sjulian NG_HCI_ALERT( 1061107120Sjulian"%s: %s - invalid link type=%d\n", 1062107120Sjulian __func__, NG_NODE_NAME(unit->node), con->link_type); 1063107120Sjulian error = EINVAL; 1064107120Sjulian } else if (con->state != NG_HCI_CON_OPEN) { 1065107120Sjulian NG_HCI_ALERT( 1066107120Sjulian"%s: %s - invalid connection state=%d, handle=%d\n", 1067107120Sjulian __func__, NG_NODE_NAME(unit->node), con->state, h); 1068107120Sjulian error = EINVAL; 1069107120Sjulian } else /* Notify upper layer */ 1070107120Sjulian error = ng_hci_lp_qos_ind(con); 1071107120Sjulian 1072107120Sjulian NG_FREE_M(event); 1073107120Sjulian 1074107120Sjulian return (error); 1075107120Sjulian} /* qos_violation */ 1076107120Sjulian 1077107120Sjulian/* Page scan mode change event */ 1078107120Sjulianstatic int 1079107120Sjulianpage_scan_mode_change(ng_hci_unit_p unit, struct mbuf *event) 1080107120Sjulian{ 1081107120Sjulian ng_hci_page_scan_mode_change_ep *ep = NULL; 1082107120Sjulian ng_hci_neighbor_p n = NULL; 1083107120Sjulian int error = 0; 1084107120Sjulian 1085107120Sjulian NG_HCI_M_PULLUP(event, sizeof(*ep)); 1086107120Sjulian if (event == NULL) 1087107120Sjulian return (ENOBUFS); 1088107120Sjulian 1089107120Sjulian ep = mtod(event, ng_hci_page_scan_mode_change_ep *); 1090107120Sjulian 1091107120Sjulian /* Update cache entry */ 1092107120Sjulian n = ng_hci_get_neighbor(unit, &ep->bdaddr); 1093107120Sjulian if (n == NULL) { 1094107120Sjulian n = ng_hci_new_neighbor(unit); 1095107120Sjulian if (n == NULL) { 1096107120Sjulian error = ENOMEM; 1097107120Sjulian goto out; 1098107120Sjulian } 1099107120Sjulian 1100107120Sjulian bcopy(&ep->bdaddr, &n->bdaddr, sizeof(n->bdaddr)); 1101107120Sjulian } else 1102107120Sjulian getmicrotime(&n->updated); 1103107120Sjulian 1104107120Sjulian n->page_scan_mode = ep->page_scan_mode; 1105107120Sjulianout: 1106107120Sjulian NG_FREE_M(event); 1107107120Sjulian 1108107120Sjulian return (error); 1109107120Sjulian} /* page_scan_mode_change */ 1110107120Sjulian 1111107120Sjulian/* Page scan repetition mode change event */ 1112107120Sjulianstatic int 1113107120Sjulianpage_scan_rep_mode_change(ng_hci_unit_p unit, struct mbuf *event) 1114107120Sjulian{ 1115107120Sjulian ng_hci_page_scan_rep_mode_change_ep *ep = NULL; 1116107120Sjulian ng_hci_neighbor_p n = NULL; 1117107120Sjulian int error = 0; 1118107120Sjulian 1119107120Sjulian NG_HCI_M_PULLUP(event, sizeof(*ep)); 1120107120Sjulian if (event == NULL) 1121107120Sjulian return (ENOBUFS); 1122107120Sjulian 1123107120Sjulian ep = mtod(event, ng_hci_page_scan_rep_mode_change_ep *); 1124107120Sjulian 1125107120Sjulian /* Update cache entry */ 1126107120Sjulian n = ng_hci_get_neighbor(unit, &ep->bdaddr); 1127107120Sjulian if (n == NULL) { 1128107120Sjulian n = ng_hci_new_neighbor(unit); 1129107120Sjulian if (n == NULL) { 1130107120Sjulian error = ENOMEM; 1131107120Sjulian goto out; 1132107120Sjulian } 1133107120Sjulian 1134107120Sjulian bcopy(&ep->bdaddr, &n->bdaddr, sizeof(n->bdaddr)); 1135107120Sjulian } else 1136107120Sjulian getmicrotime(&n->updated); 1137107120Sjulian 1138107120Sjulian n->page_scan_rep_mode = ep->page_scan_rep_mode; 1139107120Sjulianout: 1140107120Sjulian NG_FREE_M(event); 1141107120Sjulian 1142107120Sjulian return (error); 1143107120Sjulian} /* page_scan_rep_mode_change */ 1144107120Sjulian 1145