1 /* 2 * ng_hci_evnt.c 3 */ 4 5 /*- 6 * SPDX-License-Identifier: BSD-2-Clause 7 * 8 * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com> 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $Id: ng_hci_evnt.c,v 1.6 2003/09/08 18:57:51 max Exp $ 33 */ 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 #include <sys/endian.h> 39 #include <sys/malloc.h> 40 #include <sys/mbuf.h> 41 #include <sys/queue.h> 42 #include <netgraph/ng_message.h> 43 #include <netgraph/netgraph.h> 44 #include <netgraph/bluetooth/include/ng_bluetooth.h> 45 #include <netgraph/bluetooth/include/ng_hci.h> 46 #include <netgraph/bluetooth/hci/ng_hci_var.h> 47 #include <netgraph/bluetooth/hci/ng_hci_cmds.h> 48 #include <netgraph/bluetooth/hci/ng_hci_evnt.h> 49 #include <netgraph/bluetooth/hci/ng_hci_ulpi.h> 50 #include <netgraph/bluetooth/hci/ng_hci_misc.h> 51 52 /****************************************************************************** 53 ****************************************************************************** 54 ** HCI event processing module 55 ****************************************************************************** 56 ******************************************************************************/ 57 58 /* 59 * Event processing routines 60 */ 61 62 static int inquiry_result (ng_hci_unit_p, struct mbuf *); 63 static int con_compl (ng_hci_unit_p, struct mbuf *); 64 static int con_req (ng_hci_unit_p, struct mbuf *); 65 static int discon_compl (ng_hci_unit_p, struct mbuf *); 66 static int encryption_change (ng_hci_unit_p, struct mbuf *); 67 static int read_remote_features_compl (ng_hci_unit_p, struct mbuf *); 68 static int qos_setup_compl (ng_hci_unit_p, struct mbuf *); 69 static int hardware_error (ng_hci_unit_p, struct mbuf *); 70 static int role_change (ng_hci_unit_p, struct mbuf *); 71 static int num_compl_pkts (ng_hci_unit_p, struct mbuf *); 72 static int mode_change (ng_hci_unit_p, struct mbuf *); 73 static int data_buffer_overflow (ng_hci_unit_p, struct mbuf *); 74 static int read_clock_offset_compl (ng_hci_unit_p, struct mbuf *); 75 static int qos_violation (ng_hci_unit_p, struct mbuf *); 76 static int page_scan_mode_change (ng_hci_unit_p, struct mbuf *); 77 static int page_scan_rep_mode_change (ng_hci_unit_p, struct mbuf *); 78 static int sync_con_queue (ng_hci_unit_p, ng_hci_unit_con_p, int); 79 static int send_data_packets (ng_hci_unit_p, int, int); 80 static int le_event (ng_hci_unit_p, struct mbuf *); 81 82 /* 83 * Process HCI event packet 84 */ 85 86 int 87 ng_hci_process_event(ng_hci_unit_p unit, struct mbuf *event) 88 { 89 ng_hci_event_pkt_t *hdr = NULL; 90 int error = 0; 91 92 /* Get event packet header */ 93 NG_HCI_M_PULLUP(event, sizeof(*hdr)); 94 if (event == NULL) 95 return (ENOBUFS); 96 97 hdr = mtod(event, ng_hci_event_pkt_t *); 98 99 NG_HCI_INFO( 100 "%s: %s - got HCI event=%#x, length=%d\n", 101 __func__, NG_NODE_NAME(unit->node), hdr->event, hdr->length); 102 103 /* Get rid of event header and process event */ 104 m_adj(event, sizeof(*hdr)); 105 106 switch (hdr->event) { 107 case NG_HCI_EVENT_INQUIRY_COMPL: 108 case NG_HCI_EVENT_RETURN_LINK_KEYS: 109 case NG_HCI_EVENT_PIN_CODE_REQ: 110 case NG_HCI_EVENT_LINK_KEY_REQ: 111 case NG_HCI_EVENT_LINK_KEY_NOTIFICATION: 112 case NG_HCI_EVENT_LOOPBACK_COMMAND: 113 case NG_HCI_EVENT_AUTH_COMPL: 114 case NG_HCI_EVENT_CHANGE_CON_LINK_KEY_COMPL: 115 case NG_HCI_EVENT_MASTER_LINK_KEY_COMPL: 116 case NG_HCI_EVENT_FLUSH_OCCUR: /* XXX Do we have to handle it? */ 117 case NG_HCI_EVENT_MAX_SLOT_CHANGE: 118 case NG_HCI_EVENT_CON_PKT_TYPE_CHANGED: 119 case NG_HCI_EVENT_BT_LOGO: 120 case NG_HCI_EVENT_VENDOR: 121 case NG_HCI_EVENT_REMOTE_NAME_REQ_COMPL: 122 case NG_HCI_EVENT_READ_REMOTE_VER_INFO_COMPL: 123 /* These do not need post processing */ 124 NG_FREE_M(event); 125 break; 126 case NG_HCI_EVENT_LE: 127 error = le_event(unit, event); 128 break; 129 130 case NG_HCI_EVENT_INQUIRY_RESULT: 131 error = inquiry_result(unit, event); 132 break; 133 134 case NG_HCI_EVENT_CON_COMPL: 135 error = con_compl(unit, event); 136 break; 137 138 case NG_HCI_EVENT_CON_REQ: 139 error = con_req(unit, event); 140 break; 141 142 case NG_HCI_EVENT_DISCON_COMPL: 143 error = discon_compl(unit, event); 144 break; 145 146 case NG_HCI_EVENT_ENCRYPTION_CHANGE: 147 error = encryption_change(unit, event); 148 break; 149 150 case NG_HCI_EVENT_READ_REMOTE_FEATURES_COMPL: 151 error = read_remote_features_compl(unit, event); 152 break; 153 154 case NG_HCI_EVENT_QOS_SETUP_COMPL: 155 error = qos_setup_compl(unit, event); 156 break; 157 158 case NG_HCI_EVENT_COMMAND_COMPL: 159 error = ng_hci_process_command_complete(unit, event); 160 break; 161 162 case NG_HCI_EVENT_COMMAND_STATUS: 163 error = ng_hci_process_command_status(unit, event); 164 break; 165 166 case NG_HCI_EVENT_HARDWARE_ERROR: 167 error = hardware_error(unit, event); 168 break; 169 170 case NG_HCI_EVENT_ROLE_CHANGE: 171 error = role_change(unit, event); 172 break; 173 174 case NG_HCI_EVENT_NUM_COMPL_PKTS: 175 error = num_compl_pkts(unit, event); 176 break; 177 178 case NG_HCI_EVENT_MODE_CHANGE: 179 error = mode_change(unit, event); 180 break; 181 182 case NG_HCI_EVENT_DATA_BUFFER_OVERFLOW: 183 error = data_buffer_overflow(unit, event); 184 break; 185 186 case NG_HCI_EVENT_READ_CLOCK_OFFSET_COMPL: 187 error = read_clock_offset_compl(unit, event); 188 break; 189 190 case NG_HCI_EVENT_QOS_VIOLATION: 191 error = qos_violation(unit, event); 192 break; 193 194 case NG_HCI_EVENT_PAGE_SCAN_MODE_CHANGE: 195 error = page_scan_mode_change(unit, event); 196 break; 197 198 case NG_HCI_EVENT_PAGE_SCAN_REP_MODE_CHANGE: 199 error = page_scan_rep_mode_change(unit, event); 200 break; 201 202 default: 203 NG_FREE_M(event); 204 error = EINVAL; 205 break; 206 } 207 208 return (error); 209 } /* ng_hci_process_event */ 210 211 /* 212 * Send ACL and/or SCO data to the unit driver 213 */ 214 215 void 216 ng_hci_send_data(ng_hci_unit_p unit) 217 { 218 int count; 219 220 /* Send ACL data */ 221 NG_HCI_BUFF_ACL_AVAIL(unit->buffer, count); 222 223 NG_HCI_INFO( 224 "%s: %s - sending ACL data packets, count=%d\n", 225 __func__, NG_NODE_NAME(unit->node), count); 226 227 if (count > 0) { 228 count = send_data_packets(unit, NG_HCI_LINK_ACL, count); 229 NG_HCI_STAT_ACL_SENT(unit->stat, count); 230 NG_HCI_BUFF_ACL_USE(unit->buffer, count); 231 } 232 233 /* Send SCO data */ 234 NG_HCI_BUFF_SCO_AVAIL(unit->buffer, count); 235 236 NG_HCI_INFO( 237 "%s: %s - sending SCO data packets, count=%d\n", 238 __func__, NG_NODE_NAME(unit->node), count); 239 240 if (count > 0) { 241 count = send_data_packets(unit, NG_HCI_LINK_SCO, count); 242 NG_HCI_STAT_SCO_SENT(unit->stat, count); 243 NG_HCI_BUFF_SCO_USE(unit->buffer, count); 244 } 245 } /* ng_hci_send_data */ 246 247 /* 248 * Send data packets to the lower layer. 249 */ 250 251 static int 252 send_data_packets(ng_hci_unit_p unit, int link_type, int limit) 253 { 254 ng_hci_unit_con_p con = NULL, winner = NULL; 255 int reallink_type; 256 item_p item = NULL; 257 int min_pending, total_sent, sent, error, v; 258 259 for (total_sent = 0; limit > 0; ) { 260 min_pending = 0x0fffffff; 261 winner = NULL; 262 263 /* 264 * Find the connection that has has data to send 265 * and the smallest number of pending packets 266 */ 267 268 LIST_FOREACH(con, &unit->con_list, next) { 269 reallink_type = (con->link_type == NG_HCI_LINK_SCO)? 270 NG_HCI_LINK_SCO: NG_HCI_LINK_ACL; 271 if (reallink_type != link_type){ 272 continue; 273 } 274 if (NG_BT_ITEMQ_LEN(&con->conq) == 0) 275 continue; 276 277 if (con->pending < min_pending) { 278 winner = con; 279 min_pending = con->pending; 280 } 281 } 282 283 if (winner == NULL) 284 break; 285 286 /* 287 * OK, we have a winner now send as much packets as we can 288 * Count the number of packets we have sent and then sync 289 * winner connection queue. 290 */ 291 292 for (sent = 0; limit > 0; limit --, total_sent ++, sent ++) { 293 NG_BT_ITEMQ_DEQUEUE(&winner->conq, item); 294 if (item == NULL) 295 break; 296 297 NG_HCI_INFO( 298 "%s: %s - sending data packet, handle=%d, len=%d\n", 299 __func__, NG_NODE_NAME(unit->node), 300 winner->con_handle, NGI_M(item)->m_pkthdr.len); 301 302 /* Check if driver hook still there */ 303 v = (unit->drv != NULL && NG_HOOK_IS_VALID(unit->drv)); 304 if (!v || (unit->state & NG_HCI_UNIT_READY) != 305 NG_HCI_UNIT_READY) { 306 NG_HCI_ERR( 307 "%s: %s - could not send data. Hook \"%s\" is %svalid, state=%#x\n", 308 __func__, NG_NODE_NAME(unit->node), 309 NG_HCI_HOOK_DRV, ((v)? "" : "not "), 310 unit->state); 311 312 NG_FREE_ITEM(item); 313 error = ENOTCONN; 314 } else { 315 v = NGI_M(item)->m_pkthdr.len; 316 317 /* Give packet to raw hook */ 318 ng_hci_mtap(unit, NGI_M(item)); 319 320 /* ... and forward item to the driver */ 321 NG_FWD_ITEM_HOOK(error, item, unit->drv); 322 } 323 324 if (error != 0) { 325 NG_HCI_ERR( 326 "%s: %s - could not send data packet, handle=%d, error=%d\n", 327 __func__, NG_NODE_NAME(unit->node), 328 winner->con_handle, error); 329 break; 330 } 331 332 winner->pending ++; 333 NG_HCI_STAT_BYTES_SENT(unit->stat, v); 334 } 335 336 /* 337 * Sync connection queue for the winner 338 */ 339 sync_con_queue(unit, winner, sent); 340 } 341 342 return (total_sent); 343 } /* send_data_packets */ 344 345 /* 346 * Send flow control messages to the upper layer 347 */ 348 349 static int 350 sync_con_queue(ng_hci_unit_p unit, ng_hci_unit_con_p con, int completed) 351 { 352 hook_p hook = NULL; 353 struct ng_mesg *msg = NULL; 354 ng_hci_sync_con_queue_ep *state = NULL; 355 int error; 356 357 hook = (con->link_type != NG_HCI_LINK_SCO)? unit->acl : unit->sco; 358 if (hook == NULL || NG_HOOK_NOT_VALID(hook)) 359 return (ENOTCONN); 360 361 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_SYNC_CON_QUEUE, 362 sizeof(*state), M_NOWAIT); 363 if (msg == NULL) 364 return (ENOMEM); 365 366 state = (ng_hci_sync_con_queue_ep *)(msg->data); 367 state->con_handle = con->con_handle; 368 state->completed = completed; 369 370 NG_SEND_MSG_HOOK(error, unit->node, msg, hook, 0); 371 372 return (error); 373 } /* sync_con_queue */ 374 /* le meta event */ 375 /* Inquiry result event */ 376 static int 377 le_advertizing_report(ng_hci_unit_p unit, struct mbuf *event) 378 { 379 ng_hci_le_advertising_report_ep *ep = NULL; 380 ng_hci_neighbor_p n = NULL; 381 bdaddr_t bdaddr; 382 int error = 0; 383 int num_reports = 0; 384 u_int8_t addr_type; 385 386 NG_HCI_M_PULLUP(event, sizeof(*ep)); 387 if (event == NULL) 388 return (ENOBUFS); 389 390 ep = mtod(event, ng_hci_le_advertising_report_ep *); 391 num_reports = ep->num_reports; 392 m_adj(event, sizeof(*ep)); 393 ep = NULL; 394 395 for (; num_reports > 0; num_reports --) { 396 /* event_type */ 397 m_adj(event, sizeof(u_int8_t)); 398 399 /* Get remote unit address */ 400 NG_HCI_M_PULLUP(event, sizeof(u_int8_t)); 401 if (event == NULL) { 402 error = ENOBUFS; 403 goto out; 404 } 405 addr_type = *mtod(event, u_int8_t *); 406 m_adj(event, sizeof(u_int8_t)); 407 408 m_copydata(event, 0, sizeof(bdaddr), (caddr_t) &bdaddr); 409 m_adj(event, sizeof(bdaddr)); 410 411 /* Lookup entry in the cache */ 412 n = ng_hci_get_neighbor(unit, &bdaddr, (addr_type) ? NG_HCI_LINK_LE_RANDOM:NG_HCI_LINK_LE_PUBLIC); 413 if (n == NULL) { 414 /* Create new entry */ 415 n = ng_hci_new_neighbor(unit); 416 if (n == NULL) { 417 error = ENOMEM; 418 break; 419 } 420 bcopy(&bdaddr, &n->bdaddr, sizeof(n->bdaddr)); 421 n->addrtype = (addr_type)? NG_HCI_LINK_LE_RANDOM : 422 NG_HCI_LINK_LE_PUBLIC; 423 424 } else 425 getmicrotime(&n->updated); 426 427 { 428 /* 429 * TODO: Make these information 430 * Available from userland. 431 */ 432 u_int8_t length_data; 433 434 event = m_pullup(event, sizeof(u_int8_t)); 435 if(event == NULL){ 436 NG_HCI_WARN("%s: Event datasize Pullup Failed\n", __func__); 437 goto out; 438 } 439 length_data = *mtod(event, u_int8_t *); 440 m_adj(event, sizeof(u_int8_t)); 441 n->extinq_size = (length_data < NG_HCI_EXTINQ_MAX)? 442 length_data : NG_HCI_EXTINQ_MAX; 443 444 /*Advertizement data*/ 445 event = m_pullup(event, n->extinq_size); 446 if(event == NULL){ 447 NG_HCI_WARN("%s: Event data pullup Failed\n", __func__); 448 goto out; 449 } 450 m_copydata(event, 0, n->extinq_size, n->extinq_data); 451 m_adj(event, n->extinq_size); 452 event = m_pullup(event, sizeof(char )); 453 /*Get RSSI*/ 454 if(event == NULL){ 455 NG_HCI_WARN("%s: Event rssi pull up Failed\n", __func__); 456 457 goto out; 458 } 459 n->page_scan_mode = *mtod(event, char *); 460 m_adj(event, sizeof(u_int8_t)); 461 } 462 } 463 out: 464 NG_FREE_M(event); 465 466 return (error); 467 } /* inquiry_result */ 468 469 static int le_connection_complete(ng_hci_unit_p unit, struct mbuf *event) 470 { 471 int error = 0; 472 473 ng_hci_le_connection_complete_ep *ep = NULL; 474 ng_hci_unit_con_p con = NULL; 475 int link_type; 476 uint8_t uclass[3] = {0,0,0};//dummy uclass 477 478 NG_HCI_M_PULLUP(event, sizeof(*ep)); 479 if (event == NULL) 480 return (ENOBUFS); 481 482 ep = mtod(event, ng_hci_le_connection_complete_ep *); 483 link_type = (ep->address_type)? NG_HCI_LINK_LE_RANDOM : 484 NG_HCI_LINK_LE_PUBLIC; 485 /* 486 * Find the first connection descriptor that matches the following: 487 * 488 * 1) con->link_type == link_type 489 * 2) con->state == NG_HCI_CON_W4_CONN_COMPLETE 490 * 3) con->bdaddr == ep->address 491 */ 492 LIST_FOREACH(con, &unit->con_list, next) 493 if (con->link_type == link_type && 494 con->state == NG_HCI_CON_W4_CONN_COMPLETE && 495 bcmp(&con->bdaddr, &ep->address, sizeof(bdaddr_t)) == 0) 496 break; 497 498 /* 499 * Two possible cases: 500 * 501 * 1) We have found connection descriptor. That means upper layer has 502 * requested this connection via LP_CON_REQ message. In this case 503 * connection must have timeout set. If ng_hci_con_untimeout() fails 504 * then timeout message already went into node's queue. In this case 505 * ignore Connection_Complete event and let timeout deal with it. 506 * 507 * 2) We do not have connection descriptor. That means upper layer 508 * nas not requested this connection , (less likely) we gave up 509 * on this connection (timeout) or as node act as slave role. 510 * The most likely scenario is that 511 * we have received LE_Create_Connection command 512 * from the RAW hook 513 */ 514 515 if (con == NULL) { 516 if (ep->status != 0) 517 goto out; 518 519 con = ng_hci_new_con(unit, link_type); 520 if (con == NULL) { 521 error = ENOMEM; 522 goto out; 523 } 524 525 con->state = NG_HCI_CON_W4_LP_CON_RSP; 526 ng_hci_con_timeout(con); 527 528 bcopy(&ep->address, &con->bdaddr, sizeof(con->bdaddr)); 529 error = ng_hci_lp_con_ind(con, uclass); 530 if (error != 0) { 531 ng_hci_con_untimeout(con); 532 ng_hci_free_con(con); 533 goto out; 534 } 535 536 } else if ((error = ng_hci_con_untimeout(con)) != 0) 537 goto out; 538 539 /* 540 * Update connection descriptor and send notification 541 * to the upper layers. 542 */ 543 544 con->con_handle = NG_HCI_CON_HANDLE(le16toh(ep->handle)); 545 con->encryption_mode = NG_HCI_ENCRYPTION_MODE_NONE; 546 547 ng_hci_lp_con_cfm(con, ep->status); 548 549 /* Adjust connection state */ 550 if (ep->status != 0) 551 ng_hci_free_con(con); 552 else { 553 con->state = NG_HCI_CON_OPEN; 554 555 /* 556 * Change link policy for the ACL connections. Enable all 557 * supported link modes. Enable Role switch as well if 558 * device supports it. 559 */ 560 } 561 562 out: 563 NG_FREE_M(event); 564 565 return (error); 566 567 } 568 569 static int le_connection_update(ng_hci_unit_p unit, struct mbuf *event) 570 { 571 int error = 0; 572 /*TBD*/ 573 574 NG_FREE_M(event); 575 return error; 576 577 } 578 static int 579 le_event(ng_hci_unit_p unit, struct mbuf *event) 580 { 581 int error = 0; 582 ng_hci_le_ep *lep; 583 584 NG_HCI_M_PULLUP(event, sizeof(*lep)); 585 if(event ==NULL){ 586 return ENOBUFS; 587 } 588 lep = mtod(event, ng_hci_le_ep *); 589 m_adj(event, sizeof(*lep)); 590 switch(lep->subevent_code){ 591 case NG_HCI_LEEV_CON_COMPL: 592 le_connection_complete(unit, event); 593 break; 594 case NG_HCI_LEEV_ADVREP: 595 le_advertizing_report(unit, event); 596 break; 597 case NG_HCI_LEEV_CON_UPDATE_COMPL: 598 le_connection_update(unit, event); 599 break; 600 case NG_HCI_LEEV_READ_REMOTE_FEATURES_COMPL: 601 //TBD 602 /*FALLTHROUGH*/ 603 case NG_HCI_LEEV_LONG_TERM_KEY_REQUEST: 604 //TBD 605 /*FALLTHROUGH*/ 606 default: 607 NG_FREE_M(event); 608 } 609 return error; 610 } 611 612 /* Inquiry result event */ 613 static int 614 inquiry_result(ng_hci_unit_p unit, struct mbuf *event) 615 { 616 ng_hci_inquiry_result_ep *ep = NULL; 617 ng_hci_neighbor_p n = NULL; 618 bdaddr_t bdaddr; 619 int error = 0; 620 621 NG_HCI_M_PULLUP(event, sizeof(*ep)); 622 if (event == NULL) 623 return (ENOBUFS); 624 625 ep = mtod(event, ng_hci_inquiry_result_ep *); 626 m_adj(event, sizeof(*ep)); 627 628 for (; ep->num_responses > 0; ep->num_responses --) { 629 /* Get remote unit address */ 630 m_copydata(event, 0, sizeof(bdaddr), (caddr_t) &bdaddr); 631 m_adj(event, sizeof(bdaddr)); 632 633 /* Lookup entry in the cache */ 634 n = ng_hci_get_neighbor(unit, &bdaddr, NG_HCI_LINK_ACL); 635 if (n == NULL) { 636 /* Create new entry */ 637 n = ng_hci_new_neighbor(unit); 638 if (n == NULL) { 639 error = ENOMEM; 640 break; 641 } 642 } else 643 getmicrotime(&n->updated); 644 645 bcopy(&bdaddr, &n->bdaddr, sizeof(n->bdaddr)); 646 n->addrtype = NG_HCI_LINK_ACL; 647 648 /* XXX call m_pullup here? */ 649 650 n->page_scan_rep_mode = *mtod(event, u_int8_t *); 651 m_adj(event, sizeof(u_int8_t)); 652 653 /* page_scan_period_mode */ 654 m_adj(event, sizeof(u_int8_t)); 655 656 n->page_scan_mode = *mtod(event, u_int8_t *); 657 m_adj(event, sizeof(u_int8_t)); 658 659 /* class */ 660 m_adj(event, NG_HCI_CLASS_SIZE); 661 662 /* clock offset */ 663 m_copydata(event, 0, sizeof(n->clock_offset), 664 (caddr_t) &n->clock_offset); 665 n->clock_offset = le16toh(n->clock_offset); 666 } 667 668 NG_FREE_M(event); 669 670 return (error); 671 } /* inquiry_result */ 672 673 /* Connection complete event */ 674 static int 675 con_compl(ng_hci_unit_p unit, struct mbuf *event) 676 { 677 ng_hci_con_compl_ep *ep = NULL; 678 ng_hci_unit_con_p con = NULL; 679 int error = 0; 680 681 NG_HCI_M_PULLUP(event, sizeof(*ep)); 682 if (event == NULL) 683 return (ENOBUFS); 684 685 ep = mtod(event, ng_hci_con_compl_ep *); 686 687 /* 688 * Find the first connection descriptor that matches the following: 689 * 690 * 1) con->link_type == ep->link_type 691 * 2) con->state == NG_HCI_CON_W4_CONN_COMPLETE 692 * 3) con->bdaddr == ep->bdaddr 693 */ 694 695 LIST_FOREACH(con, &unit->con_list, next) 696 if (con->link_type == ep->link_type && 697 con->state == NG_HCI_CON_W4_CONN_COMPLETE && 698 bcmp(&con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0) 699 break; 700 701 /* 702 * Two possible cases: 703 * 704 * 1) We have found connection descriptor. That means upper layer has 705 * requested this connection via LP_CON_REQ message. In this case 706 * connection must have timeout set. If ng_hci_con_untimeout() fails 707 * then timeout message already went into node's queue. In this case 708 * ignore Connection_Complete event and let timeout deal with it. 709 * 710 * 2) We do not have connection descriptor. That means upper layer 711 * nas not requested this connection or (less likely) we gave up 712 * on this connection (timeout). The most likely scenario is that 713 * we have received Create_Connection/Add_SCO_Connection command 714 * from the RAW hook 715 */ 716 717 if (con == NULL) { 718 if (ep->status != 0) 719 goto out; 720 721 con = ng_hci_new_con(unit, ep->link_type); 722 if (con == NULL) { 723 error = ENOMEM; 724 goto out; 725 } 726 727 bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr)); 728 } else if ((error = ng_hci_con_untimeout(con)) != 0) 729 goto out; 730 731 /* 732 * Update connection descriptor and send notification 733 * to the upper layers. 734 */ 735 736 con->con_handle = NG_HCI_CON_HANDLE(le16toh(ep->con_handle)); 737 con->encryption_mode = ep->encryption_mode; 738 739 ng_hci_lp_con_cfm(con, ep->status); 740 741 /* Adjust connection state */ 742 if (ep->status != 0) 743 ng_hci_free_con(con); 744 else { 745 con->state = NG_HCI_CON_OPEN; 746 747 /* 748 * Change link policy for the ACL connections. Enable all 749 * supported link modes. Enable Role switch as well if 750 * device supports it. 751 */ 752 753 if (ep->link_type == NG_HCI_LINK_ACL) { 754 struct __link_policy { 755 ng_hci_cmd_pkt_t hdr; 756 ng_hci_write_link_policy_settings_cp cp; 757 } __attribute__ ((packed)) *lp; 758 struct mbuf *m; 759 760 MGETHDR(m, M_NOWAIT, MT_DATA); 761 if (m != NULL) { 762 m->m_pkthdr.len = m->m_len = sizeof(*lp); 763 lp = mtod(m, struct __link_policy *); 764 765 lp->hdr.type = NG_HCI_CMD_PKT; 766 lp->hdr.opcode = htole16(NG_HCI_OPCODE( 767 NG_HCI_OGF_LINK_POLICY, 768 NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS)); 769 lp->hdr.length = sizeof(lp->cp); 770 771 lp->cp.con_handle = ep->con_handle; 772 773 lp->cp.settings = 0; 774 if ((unit->features[0] & NG_HCI_LMP_SWITCH) && 775 unit->role_switch) 776 lp->cp.settings |= 0x1; 777 if (unit->features[0] & NG_HCI_LMP_HOLD_MODE) 778 lp->cp.settings |= 0x2; 779 if (unit->features[0] & NG_HCI_LMP_SNIFF_MODE) 780 lp->cp.settings |= 0x4; 781 if (unit->features[1] & NG_HCI_LMP_PARK_MODE) 782 lp->cp.settings |= 0x8; 783 784 lp->cp.settings &= unit->link_policy_mask; 785 lp->cp.settings = htole16(lp->cp.settings); 786 787 NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); 788 if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) 789 ng_hci_send_command(unit); 790 } 791 } 792 } 793 out: 794 NG_FREE_M(event); 795 796 return (error); 797 } /* con_compl */ 798 799 /* Connection request event */ 800 static int 801 con_req(ng_hci_unit_p unit, struct mbuf *event) 802 { 803 ng_hci_con_req_ep *ep = NULL; 804 ng_hci_unit_con_p con = NULL; 805 int error = 0; 806 807 NG_HCI_M_PULLUP(event, sizeof(*ep)); 808 if (event == NULL) 809 return (ENOBUFS); 810 811 ep = mtod(event, ng_hci_con_req_ep *); 812 813 /* 814 * Find the first connection descriptor that matches the following: 815 * 816 * 1) con->link_type == ep->link_type 817 * 818 * 2) con->state == NG_HCI_CON_W4_LP_CON_RSP || 819 * con->state == NG_HCI_CON_W4_CONN_COMPL 820 * 821 * 3) con->bdaddr == ep->bdaddr 822 * 823 * Possible cases: 824 * 825 * 1) We do not have connection descriptor. This is simple. Create 826 * new fresh connection descriptor and send notification to the 827 * appropriate upstream hook (based on link_type). 828 * 829 * 2) We found connection handle. This is more complicated. 830 * 831 * 2.1) ACL links 832 * 833 * Since only one ACL link can exist between each pair of 834 * units then we have a race. Our upper layer has requested 835 * an ACL connection to the remote unit, but we did not send 836 * command yet. At the same time the remote unit has requested 837 * an ACL connection from us. In this case we will ignore 838 * Connection_Request event. This probably will cause connect 839 * failure on both units. 840 * 841 * 2.2) SCO links 842 * 843 * The spec on page 45 says : 844 * 845 * "The master can support up to three SCO links to the same 846 * slave or to different slaves. A slave can support up to 847 * three SCO links from the same master, or two SCO links if 848 * the links originate from different masters." 849 * 850 * The only problem is how to handle multiple SCO links between 851 * matster and slave. For now we will assume that multiple SCO 852 * links MUST be opened one after another. 853 */ 854 855 LIST_FOREACH(con, &unit->con_list, next) 856 if (con->link_type == ep->link_type && 857 (con->state == NG_HCI_CON_W4_LP_CON_RSP || 858 con->state == NG_HCI_CON_W4_CONN_COMPLETE) && 859 bcmp(&con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0) 860 break; 861 862 if (con == NULL) { 863 con = ng_hci_new_con(unit, ep->link_type); 864 if (con != NULL) { 865 bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr)); 866 867 con->state = NG_HCI_CON_W4_LP_CON_RSP; 868 ng_hci_con_timeout(con); 869 870 error = ng_hci_lp_con_ind(con, ep->uclass); 871 if (error != 0) { 872 ng_hci_con_untimeout(con); 873 ng_hci_free_con(con); 874 } 875 } else 876 error = ENOMEM; 877 } 878 879 NG_FREE_M(event); 880 881 return (error); 882 } /* con_req */ 883 884 /* Disconnect complete event */ 885 static int 886 discon_compl(ng_hci_unit_p unit, struct mbuf *event) 887 { 888 ng_hci_discon_compl_ep *ep = NULL; 889 ng_hci_unit_con_p con = NULL; 890 int error = 0; 891 u_int16_t h; 892 893 NG_HCI_M_PULLUP(event, sizeof(*ep)); 894 if (event == NULL) 895 return (ENOBUFS); 896 897 ep = mtod(event, ng_hci_discon_compl_ep *); 898 899 /* 900 * XXX 901 * Do we have to send notification if ep->status != 0? 902 * For now we will send notification for both ACL and SCO connections 903 * ONLY if ep->status == 0. 904 */ 905 906 if (ep->status == 0) { 907 h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle)); 908 con = ng_hci_con_by_handle(unit, h); 909 if (con != NULL) { 910 error = ng_hci_lp_discon_ind(con, ep->reason); 911 912 /* Remove all timeouts (if any) */ 913 if (con->flags & NG_HCI_CON_TIMEOUT_PENDING) 914 ng_hci_con_untimeout(con); 915 916 ng_hci_free_con(con); 917 } else { 918 NG_HCI_ALERT( 919 "%s: %s - invalid connection handle=%d\n", 920 __func__, NG_NODE_NAME(unit->node), h); 921 error = ENOENT; 922 } 923 } 924 925 NG_FREE_M(event); 926 927 return (error); 928 } /* discon_compl */ 929 930 /* Encryption change event */ 931 static int 932 encryption_change(ng_hci_unit_p unit, struct mbuf *event) 933 { 934 ng_hci_encryption_change_ep *ep = NULL; 935 ng_hci_unit_con_p con = NULL; 936 int error = 0; 937 u_int16_t h; 938 939 NG_HCI_M_PULLUP(event, sizeof(*ep)); 940 if (event == NULL) 941 return (ENOBUFS); 942 943 ep = mtod(event, ng_hci_encryption_change_ep *); 944 h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle)); 945 con = ng_hci_con_by_handle(unit, h); 946 947 if (ep->status == 0) { 948 if (con == NULL) { 949 NG_HCI_ALERT( 950 "%s: %s - invalid connection handle=%d\n", 951 __func__, NG_NODE_NAME(unit->node), h); 952 error = ENOENT; 953 } else if (con->link_type == NG_HCI_LINK_SCO) { 954 NG_HCI_ALERT( 955 "%s: %s - invalid link type=%d\n", 956 __func__, NG_NODE_NAME(unit->node), 957 con->link_type); 958 error = EINVAL; 959 } else if (ep->encryption_enable) 960 /* XXX is that true? */ 961 con->encryption_mode = NG_HCI_ENCRYPTION_MODE_P2P; 962 else 963 con->encryption_mode = NG_HCI_ENCRYPTION_MODE_NONE; 964 } else 965 NG_HCI_ERR( 966 "%s: %s - failed to change encryption mode, status=%d\n", 967 __func__, NG_NODE_NAME(unit->node), ep->status); 968 969 /*Anyway, propagete encryption status to upper layer*/ 970 ng_hci_lp_enc_change(con, con->encryption_mode); 971 972 NG_FREE_M(event); 973 974 return (error); 975 } /* encryption_change */ 976 977 /* Read remote feature complete event */ 978 static int 979 read_remote_features_compl(ng_hci_unit_p unit, struct mbuf *event) 980 { 981 ng_hci_read_remote_features_compl_ep *ep = NULL; 982 ng_hci_unit_con_p con = NULL; 983 ng_hci_neighbor_p n = NULL; 984 u_int16_t h; 985 int error = 0; 986 987 NG_HCI_M_PULLUP(event, sizeof(*ep)); 988 if (event == NULL) 989 return (ENOBUFS); 990 991 ep = mtod(event, ng_hci_read_remote_features_compl_ep *); 992 993 if (ep->status == 0) { 994 /* Check if we have this connection handle */ 995 h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle)); 996 con = ng_hci_con_by_handle(unit, h); 997 if (con == NULL) { 998 NG_HCI_ALERT( 999 "%s: %s - invalid connection handle=%d\n", 1000 __func__, NG_NODE_NAME(unit->node), h); 1001 error = ENOENT; 1002 goto out; 1003 } 1004 1005 /* Update cache entry */ 1006 n = ng_hci_get_neighbor(unit, &con->bdaddr, NG_HCI_LINK_ACL); 1007 if (n == NULL) { 1008 n = ng_hci_new_neighbor(unit); 1009 if (n == NULL) { 1010 error = ENOMEM; 1011 goto out; 1012 } 1013 1014 bcopy(&con->bdaddr, &n->bdaddr, sizeof(n->bdaddr)); 1015 n->addrtype = NG_HCI_LINK_ACL; 1016 } else 1017 getmicrotime(&n->updated); 1018 1019 bcopy(ep->features, n->features, sizeof(n->features)); 1020 } else 1021 NG_HCI_ERR( 1022 "%s: %s - failed to read remote unit features, status=%d\n", 1023 __func__, NG_NODE_NAME(unit->node), ep->status); 1024 out: 1025 NG_FREE_M(event); 1026 1027 return (error); 1028 } /* read_remote_features_compl */ 1029 1030 /* QoS setup complete event */ 1031 static int 1032 qos_setup_compl(ng_hci_unit_p unit, struct mbuf *event) 1033 { 1034 ng_hci_qos_setup_compl_ep *ep = NULL; 1035 ng_hci_unit_con_p con = NULL; 1036 u_int16_t h; 1037 int error = 0; 1038 1039 NG_HCI_M_PULLUP(event, sizeof(*ep)); 1040 if (event == NULL) 1041 return (ENOBUFS); 1042 1043 ep = mtod(event, ng_hci_qos_setup_compl_ep *); 1044 1045 /* Check if we have this connection handle */ 1046 h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle)); 1047 con = ng_hci_con_by_handle(unit, h); 1048 if (con == NULL) { 1049 NG_HCI_ALERT( 1050 "%s: %s - invalid connection handle=%d\n", 1051 __func__, NG_NODE_NAME(unit->node), h); 1052 error = ENOENT; 1053 } else if (con->link_type != NG_HCI_LINK_ACL) { 1054 NG_HCI_ALERT( 1055 "%s: %s - invalid link type=%d, handle=%d\n", 1056 __func__, NG_NODE_NAME(unit->node), con->link_type, h); 1057 error = EINVAL; 1058 } else if (con->state != NG_HCI_CON_OPEN) { 1059 NG_HCI_ALERT( 1060 "%s: %s - invalid connection state=%d, handle=%d\n", 1061 __func__, NG_NODE_NAME(unit->node), 1062 con->state, h); 1063 error = EINVAL; 1064 } else /* Notify upper layer */ 1065 error = ng_hci_lp_qos_cfm(con, ep->status); 1066 1067 NG_FREE_M(event); 1068 1069 return (error); 1070 } /* qos_setup_compl */ 1071 1072 /* Hardware error event */ 1073 static int 1074 hardware_error(ng_hci_unit_p unit, struct mbuf *event) 1075 { 1076 NG_HCI_ALERT( 1077 "%s: %s - hardware error %#x\n", 1078 __func__, NG_NODE_NAME(unit->node), *mtod(event, u_int8_t *)); 1079 1080 NG_FREE_M(event); 1081 1082 return (0); 1083 } /* hardware_error */ 1084 1085 /* Role change event */ 1086 static int 1087 role_change(ng_hci_unit_p unit, struct mbuf *event) 1088 { 1089 ng_hci_role_change_ep *ep = NULL; 1090 ng_hci_unit_con_p con = NULL; 1091 1092 NG_HCI_M_PULLUP(event, sizeof(*ep)); 1093 if (event == NULL) 1094 return (ENOBUFS); 1095 1096 ep = mtod(event, ng_hci_role_change_ep *); 1097 1098 if (ep->status == 0) { 1099 /* XXX shoud we also change "role" for SCO connections? */ 1100 con = ng_hci_con_by_bdaddr(unit, &ep->bdaddr, NG_HCI_LINK_ACL); 1101 if (con != NULL) 1102 con->role = ep->role; 1103 else 1104 NG_HCI_ALERT( 1105 "%s: %s - ACL connection does not exist, bdaddr=%x:%x:%x:%x:%x:%x\n", 1106 __func__, NG_NODE_NAME(unit->node), 1107 ep->bdaddr.b[5], ep->bdaddr.b[4], 1108 ep->bdaddr.b[3], ep->bdaddr.b[2], 1109 ep->bdaddr.b[1], ep->bdaddr.b[0]); 1110 } else 1111 NG_HCI_ERR( 1112 "%s: %s - failed to change role, status=%d, bdaddr=%x:%x:%x:%x:%x:%x\n", 1113 __func__, NG_NODE_NAME(unit->node), ep->status, 1114 ep->bdaddr.b[5], ep->bdaddr.b[4], ep->bdaddr.b[3], 1115 ep->bdaddr.b[2], ep->bdaddr.b[1], ep->bdaddr.b[0]); 1116 1117 NG_FREE_M(event); 1118 1119 return (0); 1120 } /* role_change */ 1121 1122 /* Number of completed packets event */ 1123 static int 1124 num_compl_pkts(ng_hci_unit_p unit, struct mbuf *event) 1125 { 1126 ng_hci_num_compl_pkts_ep *ep = NULL; 1127 ng_hci_unit_con_p con = NULL; 1128 u_int16_t h, p; 1129 1130 NG_HCI_M_PULLUP(event, sizeof(*ep)); 1131 if (event == NULL) 1132 return (ENOBUFS); 1133 1134 ep = mtod(event, ng_hci_num_compl_pkts_ep *); 1135 m_adj(event, sizeof(*ep)); 1136 1137 for (; ep->num_con_handles > 0; ep->num_con_handles --) { 1138 /* Get connection handle */ 1139 m_copydata(event, 0, sizeof(h), (caddr_t) &h); 1140 m_adj(event, sizeof(h)); 1141 h = NG_HCI_CON_HANDLE(le16toh(h)); 1142 1143 /* Get number of completed packets */ 1144 m_copydata(event, 0, sizeof(p), (caddr_t) &p); 1145 m_adj(event, sizeof(p)); 1146 p = le16toh(p); 1147 1148 /* Check if we have this connection handle */ 1149 con = ng_hci_con_by_handle(unit, h); 1150 if (con != NULL) { 1151 con->pending -= p; 1152 if (con->pending < 0) { 1153 NG_HCI_WARN( 1154 "%s: %s - pending packet counter is out of sync! " \ 1155 "handle=%d, pending=%d, ncp=%d\n", __func__, NG_NODE_NAME(unit->node), 1156 con->con_handle, con->pending, p); 1157 1158 con->pending = 0; 1159 } 1160 1161 /* Update buffer descriptor */ 1162 if (con->link_type != NG_HCI_LINK_SCO) 1163 NG_HCI_BUFF_ACL_FREE(unit->buffer, p); 1164 else 1165 NG_HCI_BUFF_SCO_FREE(unit->buffer, p); 1166 } else 1167 NG_HCI_ALERT( 1168 "%s: %s - invalid connection handle=%d\n", 1169 __func__, NG_NODE_NAME(unit->node), h); 1170 } 1171 1172 NG_FREE_M(event); 1173 1174 /* Send more data */ 1175 ng_hci_send_data(unit); 1176 1177 return (0); 1178 } /* num_compl_pkts */ 1179 1180 /* Mode change event */ 1181 static int 1182 mode_change(ng_hci_unit_p unit, struct mbuf *event) 1183 { 1184 ng_hci_mode_change_ep *ep = NULL; 1185 ng_hci_unit_con_p con = NULL; 1186 int error = 0; 1187 1188 NG_HCI_M_PULLUP(event, sizeof(*ep)); 1189 if (event == NULL) 1190 return (ENOBUFS); 1191 1192 ep = mtod(event, ng_hci_mode_change_ep *); 1193 1194 if (ep->status == 0) { 1195 u_int16_t h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle)); 1196 1197 con = ng_hci_con_by_handle(unit, h); 1198 if (con == NULL) { 1199 NG_HCI_ALERT( 1200 "%s: %s - invalid connection handle=%d\n", 1201 __func__, NG_NODE_NAME(unit->node), h); 1202 error = ENOENT; 1203 } else if (con->link_type != NG_HCI_LINK_ACL) { 1204 NG_HCI_ALERT( 1205 "%s: %s - invalid link type=%d\n", 1206 __func__, NG_NODE_NAME(unit->node), 1207 con->link_type); 1208 error = EINVAL; 1209 } else 1210 con->mode = ep->unit_mode; 1211 } else 1212 NG_HCI_ERR( 1213 "%s: %s - failed to change mode, status=%d\n", 1214 __func__, NG_NODE_NAME(unit->node), ep->status); 1215 1216 NG_FREE_M(event); 1217 1218 return (error); 1219 } /* mode_change */ 1220 1221 /* Data buffer overflow event */ 1222 static int 1223 data_buffer_overflow(ng_hci_unit_p unit, struct mbuf *event) 1224 { 1225 NG_HCI_ALERT( 1226 "%s: %s - %s data buffer overflow\n", 1227 __func__, NG_NODE_NAME(unit->node), 1228 (*mtod(event, u_int8_t *) == NG_HCI_LINK_ACL)? "ACL" : "SCO"); 1229 1230 NG_FREE_M(event); 1231 1232 return (0); 1233 } /* data_buffer_overflow */ 1234 1235 /* Read clock offset complete event */ 1236 static int 1237 read_clock_offset_compl(ng_hci_unit_p unit, struct mbuf *event) 1238 { 1239 ng_hci_read_clock_offset_compl_ep *ep = NULL; 1240 ng_hci_unit_con_p con = NULL; 1241 ng_hci_neighbor_p n = NULL; 1242 int error = 0; 1243 1244 NG_HCI_M_PULLUP(event, sizeof(*ep)); 1245 if (event == NULL) 1246 return (ENOBUFS); 1247 1248 ep = mtod(event, ng_hci_read_clock_offset_compl_ep *); 1249 1250 if (ep->status == 0) { 1251 u_int16_t h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle)); 1252 1253 con = ng_hci_con_by_handle(unit, h); 1254 if (con == NULL) { 1255 NG_HCI_ALERT( 1256 "%s: %s - invalid connection handle=%d\n", 1257 __func__, NG_NODE_NAME(unit->node), h); 1258 error = ENOENT; 1259 goto out; 1260 } 1261 1262 /* Update cache entry */ 1263 n = ng_hci_get_neighbor(unit, &con->bdaddr, NG_HCI_LINK_ACL); 1264 if (n == NULL) { 1265 n = ng_hci_new_neighbor(unit); 1266 if (n == NULL) { 1267 error = ENOMEM; 1268 goto out; 1269 } 1270 1271 bcopy(&con->bdaddr, &n->bdaddr, sizeof(n->bdaddr)); 1272 n->addrtype = NG_HCI_LINK_ACL; 1273 } else 1274 getmicrotime(&n->updated); 1275 1276 n->clock_offset = le16toh(ep->clock_offset); 1277 } else 1278 NG_HCI_ERR( 1279 "%s: %s - failed to Read Remote Clock Offset, status=%d\n", 1280 __func__, NG_NODE_NAME(unit->node), ep->status); 1281 out: 1282 NG_FREE_M(event); 1283 1284 return (error); 1285 } /* read_clock_offset_compl */ 1286 1287 /* QoS violation event */ 1288 static int 1289 qos_violation(ng_hci_unit_p unit, struct mbuf *event) 1290 { 1291 ng_hci_qos_violation_ep *ep = NULL; 1292 ng_hci_unit_con_p con = NULL; 1293 u_int16_t h; 1294 int error = 0; 1295 1296 NG_HCI_M_PULLUP(event, sizeof(*ep)); 1297 if (event == NULL) 1298 return (ENOBUFS); 1299 1300 ep = mtod(event, ng_hci_qos_violation_ep *); 1301 1302 /* Check if we have this connection handle */ 1303 h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle)); 1304 con = ng_hci_con_by_handle(unit, h); 1305 if (con == NULL) { 1306 NG_HCI_ALERT( 1307 "%s: %s - invalid connection handle=%d\n", 1308 __func__, NG_NODE_NAME(unit->node), h); 1309 error = ENOENT; 1310 } else if (con->link_type != NG_HCI_LINK_ACL) { 1311 NG_HCI_ALERT( 1312 "%s: %s - invalid link type=%d\n", 1313 __func__, NG_NODE_NAME(unit->node), con->link_type); 1314 error = EINVAL; 1315 } else if (con->state != NG_HCI_CON_OPEN) { 1316 NG_HCI_ALERT( 1317 "%s: %s - invalid connection state=%d, handle=%d\n", 1318 __func__, NG_NODE_NAME(unit->node), con->state, h); 1319 error = EINVAL; 1320 } else /* Notify upper layer */ 1321 error = ng_hci_lp_qos_ind(con); 1322 1323 NG_FREE_M(event); 1324 1325 return (error); 1326 } /* qos_violation */ 1327 1328 /* Page scan mode change event */ 1329 static int 1330 page_scan_mode_change(ng_hci_unit_p unit, struct mbuf *event) 1331 { 1332 ng_hci_page_scan_mode_change_ep *ep = NULL; 1333 ng_hci_neighbor_p n = NULL; 1334 int error = 0; 1335 1336 NG_HCI_M_PULLUP(event, sizeof(*ep)); 1337 if (event == NULL) 1338 return (ENOBUFS); 1339 1340 ep = mtod(event, ng_hci_page_scan_mode_change_ep *); 1341 1342 /* Update cache entry */ 1343 n = ng_hci_get_neighbor(unit, &ep->bdaddr, NG_HCI_LINK_ACL); 1344 if (n == NULL) { 1345 n = ng_hci_new_neighbor(unit); 1346 if (n == NULL) { 1347 error = ENOMEM; 1348 goto out; 1349 } 1350 1351 bcopy(&ep->bdaddr, &n->bdaddr, sizeof(n->bdaddr)); 1352 n->addrtype = NG_HCI_LINK_ACL; 1353 } else 1354 getmicrotime(&n->updated); 1355 1356 n->page_scan_mode = ep->page_scan_mode; 1357 out: 1358 NG_FREE_M(event); 1359 1360 return (error); 1361 } /* page_scan_mode_change */ 1362 1363 /* Page scan repetition mode change event */ 1364 static int 1365 page_scan_rep_mode_change(ng_hci_unit_p unit, struct mbuf *event) 1366 { 1367 ng_hci_page_scan_rep_mode_change_ep *ep = NULL; 1368 ng_hci_neighbor_p n = NULL; 1369 int error = 0; 1370 1371 NG_HCI_M_PULLUP(event, sizeof(*ep)); 1372 if (event == NULL) 1373 return (ENOBUFS); 1374 1375 ep = mtod(event, ng_hci_page_scan_rep_mode_change_ep *); 1376 1377 /* Update cache entry */ 1378 n = ng_hci_get_neighbor(unit, &ep->bdaddr, NG_HCI_LINK_ACL); 1379 if (n == NULL) { 1380 n = ng_hci_new_neighbor(unit); 1381 if (n == NULL) { 1382 error = ENOMEM; 1383 goto out; 1384 } 1385 1386 bcopy(&ep->bdaddr, &n->bdaddr, sizeof(n->bdaddr)); 1387 n->addrtype = NG_HCI_LINK_ACL; 1388 } else 1389 getmicrotime(&n->updated); 1390 1391 n->page_scan_rep_mode = ep->page_scan_rep_mode; 1392 out: 1393 NG_FREE_M(event); 1394 1395 return (error); 1396 } /* page_scan_rep_mode_change */ 1397