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