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: stable/11/sys/netgraph/bluetooth/hci/ng_hci_evnt.c 370056 2021-06-28 04:03:43Z git2svn $ 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 61static int inquiry_result (ng_hci_unit_p, struct mbuf *); 62static int con_compl (ng_hci_unit_p, struct mbuf *); 63static int con_req (ng_hci_unit_p, struct mbuf *); 64static int discon_compl (ng_hci_unit_p, struct mbuf *); 65static int encryption_change (ng_hci_unit_p, struct mbuf *); 66static int read_remote_features_compl (ng_hci_unit_p, struct mbuf *); 67static int qos_setup_compl (ng_hci_unit_p, struct mbuf *); 68static int hardware_error (ng_hci_unit_p, struct mbuf *); 69static int role_change (ng_hci_unit_p, struct mbuf *); 70static int num_compl_pkts (ng_hci_unit_p, struct mbuf *); 71static int mode_change (ng_hci_unit_p, struct mbuf *); 72static int data_buffer_overflow (ng_hci_unit_p, struct mbuf *); 73static int read_clock_offset_compl (ng_hci_unit_p, struct mbuf *); 74static int qos_violation (ng_hci_unit_p, struct mbuf *); 75static int page_scan_mode_change (ng_hci_unit_p, struct mbuf *); 76static int page_scan_rep_mode_change (ng_hci_unit_p, struct mbuf *); 77static int sync_con_queue (ng_hci_unit_p, ng_hci_unit_con_p, int); 78static int send_data_packets (ng_hci_unit_p, int, int); 79static int le_event (ng_hci_unit_p, struct mbuf *); 80 81/* 82 * Process HCI event packet 83 */ 84 85int 86ng_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 214void 215ng_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 250static int 251send_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 348static int 349sync_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 */ 375static int 376le_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#if 0 421 { 422 /* 423 * TODO: Make these information 424 * Available from userland. 425 */ 426 u_int8_t length_data; 427 428 char *rssi; 429 430 NG_HCI_M_PULLUP(event, sizeof(u_int8_t)); 431 length_data = *mtod(event, u_int8_t *); 432 m_adj(event, sizeof(u_int8_t)); 433 /*Advertizement data*/ 434 NG_HCI_M_PULLUP(event, length_data); 435 m_adj(event, length_data); 436 NG_HCI_M_PULLUP(event, sizeof(char )); 437 /*Get RSSI*/ 438 rssi = mtod(event, char *); 439 m_adj(event, sizeof(u_int8_t)); 440 } 441#endif 442 } 443 NG_FREE_M(event); 444 445 return (error); 446} /* inquiry_result */ 447 448static int le_connection_complete(ng_hci_unit_p unit, struct mbuf *event) 449{ 450 int error = 0; 451 452 ng_hci_le_connection_complete_ep *ep = NULL; 453 ng_hci_unit_con_p con = NULL; 454 int link_type; 455 uint8_t uclass[3] = {0,0,0};//dummy uclass 456 457 NG_HCI_M_PULLUP(event, sizeof(*ep)); 458 if (event == NULL) 459 return (ENOBUFS); 460 461 ep = mtod(event, ng_hci_le_connection_complete_ep *); 462 link_type = (ep->address_type)? NG_HCI_LINK_LE_RANDOM : 463 NG_HCI_LINK_LE_PUBLIC; 464 /* 465 * Find the first connection descriptor that matches the following: 466 * 467 * 1) con->link_type == link_type 468 * 2) con->state == NG_HCI_CON_W4_CONN_COMPLETE 469 * 3) con->bdaddr == ep->address 470 */ 471 LIST_FOREACH(con, &unit->con_list, next) 472 if (con->link_type == link_type && 473 con->state == NG_HCI_CON_W4_CONN_COMPLETE && 474 bcmp(&con->bdaddr, &ep->address, sizeof(bdaddr_t)) == 0) 475 break; 476 477 /* 478 * Two possible cases: 479 * 480 * 1) We have found connection descriptor. That means upper layer has 481 * requested this connection via LP_CON_REQ message. In this case 482 * connection must have timeout set. If ng_hci_con_untimeout() fails 483 * then timeout message already went into node's queue. In this case 484 * ignore Connection_Complete event and let timeout deal with it. 485 * 486 * 2) We do not have connection descriptor. That means upper layer 487 * nas not requested this connection , (less likely) we gave up 488 * on this connection (timeout) or as node act as slave role. 489 * The most likely scenario is that 490 * we have received LE_Create_Connection command 491 * from the RAW hook 492 */ 493 494 if (con == NULL) { 495 if (ep->status != 0) 496 goto out; 497 498 con = ng_hci_new_con(unit, link_type); 499 if (con == NULL) { 500 error = ENOMEM; 501 goto out; 502 } 503 504 con->state = NG_HCI_CON_W4_LP_CON_RSP; 505 ng_hci_con_timeout(con); 506 507 bcopy(&ep->address, &con->bdaddr, sizeof(con->bdaddr)); 508 error = ng_hci_lp_con_ind(con, uclass); 509 if (error != 0) { 510 ng_hci_con_untimeout(con); 511 ng_hci_free_con(con); 512 goto out; 513 } 514 515 } else if ((error = ng_hci_con_untimeout(con)) != 0) 516 goto out; 517 518 /* 519 * Update connection descriptor and send notification 520 * to the upper layers. 521 */ 522 523 con->con_handle = NG_HCI_CON_HANDLE(le16toh(ep->handle)); 524 con->encryption_mode = NG_HCI_ENCRYPTION_MODE_NONE; 525 526 ng_hci_lp_con_cfm(con, ep->status); 527 528 /* Adjust connection state */ 529 if (ep->status != 0) 530 ng_hci_free_con(con); 531 else { 532 con->state = NG_HCI_CON_OPEN; 533 534 /* 535 * Change link policy for the ACL connections. Enable all 536 * supported link modes. Enable Role switch as well if 537 * device supports it. 538 */ 539 540 } 541 542out: 543 NG_FREE_M(event); 544 545 return (error); 546 547} 548 549static int le_connection_update(ng_hci_unit_p unit, struct mbuf *event) 550{ 551 int error = 0; 552 /*TBD*/ 553 554 NG_FREE_M(event); 555 return error; 556 557} 558static int 559le_event(ng_hci_unit_p unit, struct mbuf *event) 560{ 561 int error = 0; 562 ng_hci_le_ep *lep; 563 564 NG_HCI_M_PULLUP(event, sizeof(*lep)); 565 if(event ==NULL){ 566 return ENOBUFS; 567 } 568 lep = mtod(event, ng_hci_le_ep *); 569 m_adj(event, sizeof(*lep)); 570 switch(lep->subevent_code){ 571 case NG_HCI_LEEV_CON_COMPL: 572 le_connection_complete(unit, event); 573 break; 574 case NG_HCI_LEEV_ADVREP: 575 le_advertizing_report(unit, event); 576 break; 577 case NG_HCI_LEEV_CON_UPDATE_COMPL: 578 le_connection_update(unit, event); 579 break; 580 case NG_HCI_LEEV_READ_REMOTE_FEATURES_COMPL: 581 //TBD 582 /*FALLTHROUGH*/ 583 case NG_HCI_LEEV_LONG_TERM_KEY_REQUEST: 584 //TBD 585 /*FALLTHROUGH*/ 586 default: 587 NG_FREE_M(event); 588 } 589 return error; 590} 591 592/* Inquiry result event */ 593static int 594inquiry_result(ng_hci_unit_p unit, struct mbuf *event) 595{ 596 ng_hci_inquiry_result_ep *ep = NULL; 597 ng_hci_neighbor_p n = NULL; 598 bdaddr_t bdaddr; 599 int error = 0; 600 601 NG_HCI_M_PULLUP(event, sizeof(*ep)); 602 if (event == NULL) 603 return (ENOBUFS); 604 605 ep = mtod(event, ng_hci_inquiry_result_ep *); 606 m_adj(event, sizeof(*ep)); 607 608 for (; ep->num_responses > 0; ep->num_responses --) { 609 /* Get remote unit address */ 610 m_copydata(event, 0, sizeof(bdaddr), (caddr_t) &bdaddr); 611 m_adj(event, sizeof(bdaddr)); 612 613 /* Lookup entry in the cache */ 614 n = ng_hci_get_neighbor(unit, &bdaddr, NG_HCI_LINK_ACL); 615 if (n == NULL) { 616 /* Create new entry */ 617 n = ng_hci_new_neighbor(unit); 618 if (n == NULL) { 619 error = ENOMEM; 620 break; 621 } 622 } else 623 getmicrotime(&n->updated); 624 625 bcopy(&bdaddr, &n->bdaddr, sizeof(n->bdaddr)); 626 n->addrtype = NG_HCI_LINK_ACL; 627 628 /* XXX call m_pullup here? */ 629 630 n->page_scan_rep_mode = *mtod(event, u_int8_t *); 631 m_adj(event, sizeof(u_int8_t)); 632 633 /* page_scan_period_mode */ 634 m_adj(event, sizeof(u_int8_t)); 635 636 n->page_scan_mode = *mtod(event, u_int8_t *); 637 m_adj(event, sizeof(u_int8_t)); 638 639 /* class */ 640 m_adj(event, NG_HCI_CLASS_SIZE); 641 642 /* clock offset */ 643 m_copydata(event, 0, sizeof(n->clock_offset), 644 (caddr_t) &n->clock_offset); 645 n->clock_offset = le16toh(n->clock_offset); 646 } 647 648 NG_FREE_M(event); 649 650 return (error); 651} /* inquiry_result */ 652 653/* Connection complete event */ 654static int 655con_compl(ng_hci_unit_p unit, struct mbuf *event) 656{ 657 ng_hci_con_compl_ep *ep = NULL; 658 ng_hci_unit_con_p con = NULL; 659 int error = 0; 660 661 NG_HCI_M_PULLUP(event, sizeof(*ep)); 662 if (event == NULL) 663 return (ENOBUFS); 664 665 ep = mtod(event, ng_hci_con_compl_ep *); 666 667 /* 668 * Find the first connection descriptor that matches the following: 669 * 670 * 1) con->link_type == ep->link_type 671 * 2) con->state == NG_HCI_CON_W4_CONN_COMPLETE 672 * 3) con->bdaddr == ep->bdaddr 673 */ 674 675 LIST_FOREACH(con, &unit->con_list, next) 676 if (con->link_type == ep->link_type && 677 con->state == NG_HCI_CON_W4_CONN_COMPLETE && 678 bcmp(&con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0) 679 break; 680 681 /* 682 * Two possible cases: 683 * 684 * 1) We have found connection descriptor. That means upper layer has 685 * requested this connection via LP_CON_REQ message. In this case 686 * connection must have timeout set. If ng_hci_con_untimeout() fails 687 * then timeout message already went into node's queue. In this case 688 * ignore Connection_Complete event and let timeout deal with it. 689 * 690 * 2) We do not have connection descriptor. That means upper layer 691 * nas not requested this connection or (less likely) we gave up 692 * on this connection (timeout). The most likely scenario is that 693 * we have received Create_Connection/Add_SCO_Connection command 694 * from the RAW hook 695 */ 696 697 if (con == NULL) { 698 if (ep->status != 0) 699 goto out; 700 701 con = ng_hci_new_con(unit, ep->link_type); 702 if (con == NULL) { 703 error = ENOMEM; 704 goto out; 705 } 706 707 bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr)); 708 } else if ((error = ng_hci_con_untimeout(con)) != 0) 709 goto out; 710 711 /* 712 * Update connection descriptor and send notification 713 * to the upper layers. 714 */ 715 716 con->con_handle = NG_HCI_CON_HANDLE(le16toh(ep->con_handle)); 717 con->encryption_mode = ep->encryption_mode; 718 719 ng_hci_lp_con_cfm(con, ep->status); 720 721 /* Adjust connection state */ 722 if (ep->status != 0) 723 ng_hci_free_con(con); 724 else { 725 con->state = NG_HCI_CON_OPEN; 726 727 /* 728 * Change link policy for the ACL connections. Enable all 729 * supported link modes. Enable Role switch as well if 730 * device supports it. 731 */ 732 733 if (ep->link_type == NG_HCI_LINK_ACL) { 734 struct __link_policy { 735 ng_hci_cmd_pkt_t hdr; 736 ng_hci_write_link_policy_settings_cp cp; 737 } __attribute__ ((packed)) *lp; 738 struct mbuf *m; 739 740 MGETHDR(m, M_NOWAIT, MT_DATA); 741 if (m != NULL) { 742 m->m_pkthdr.len = m->m_len = sizeof(*lp); 743 lp = mtod(m, struct __link_policy *); 744 745 lp->hdr.type = NG_HCI_CMD_PKT; 746 lp->hdr.opcode = htole16(NG_HCI_OPCODE( 747 NG_HCI_OGF_LINK_POLICY, 748 NG_HCI_OCF_WRITE_LINK_POLICY_SETTINGS)); 749 lp->hdr.length = sizeof(lp->cp); 750 751 lp->cp.con_handle = ep->con_handle; 752 753 lp->cp.settings = 0; 754 if ((unit->features[0] & NG_HCI_LMP_SWITCH) && 755 unit->role_switch) 756 lp->cp.settings |= 0x1; 757 if (unit->features[0] & NG_HCI_LMP_HOLD_MODE) 758 lp->cp.settings |= 0x2; 759 if (unit->features[0] & NG_HCI_LMP_SNIFF_MODE) 760 lp->cp.settings |= 0x4; 761 if (unit->features[1] & NG_HCI_LMP_PARK_MODE) 762 lp->cp.settings |= 0x8; 763 764 lp->cp.settings &= unit->link_policy_mask; 765 lp->cp.settings = htole16(lp->cp.settings); 766 767 NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); 768 if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) 769 ng_hci_send_command(unit); 770 } 771 } 772 } 773out: 774 NG_FREE_M(event); 775 776 return (error); 777} /* con_compl */ 778 779/* Connection request event */ 780static int 781con_req(ng_hci_unit_p unit, struct mbuf *event) 782{ 783 ng_hci_con_req_ep *ep = NULL; 784 ng_hci_unit_con_p con = NULL; 785 int error = 0; 786 787 NG_HCI_M_PULLUP(event, sizeof(*ep)); 788 if (event == NULL) 789 return (ENOBUFS); 790 791 ep = mtod(event, ng_hci_con_req_ep *); 792 793 /* 794 * Find the first connection descriptor that matches the following: 795 * 796 * 1) con->link_type == ep->link_type 797 * 798 * 2) con->state == NG_HCI_CON_W4_LP_CON_RSP || 799 * con->state == NG_HCI_CON_W4_CONN_COMPL 800 * 801 * 3) con->bdaddr == ep->bdaddr 802 * 803 * Possible cases: 804 * 805 * 1) We do not have connection descriptor. This is simple. Create 806 * new fresh connection descriptor and send notification to the 807 * appropriate upstream hook (based on link_type). 808 * 809 * 2) We found connection handle. This is more complicated. 810 * 811 * 2.1) ACL links 812 * 813 * Since only one ACL link can exist between each pair of 814 * units then we have a race. Our upper layer has requested 815 * an ACL connection to the remote unit, but we did not send 816 * command yet. At the same time the remote unit has requested 817 * an ACL connection from us. In this case we will ignore 818 * Connection_Request event. This probably will cause connect 819 * failure on both units. 820 * 821 * 2.2) SCO links 822 * 823 * The spec on page 45 says : 824 * 825 * "The master can support up to three SCO links to the same 826 * slave or to different slaves. A slave can support up to 827 * three SCO links from the same master, or two SCO links if 828 * the links originate from different masters." 829 * 830 * The only problem is how to handle multiple SCO links between 831 * matster and slave. For now we will assume that multiple SCO 832 * links MUST be opened one after another. 833 */ 834 835 LIST_FOREACH(con, &unit->con_list, next) 836 if (con->link_type == ep->link_type && 837 (con->state == NG_HCI_CON_W4_LP_CON_RSP || 838 con->state == NG_HCI_CON_W4_CONN_COMPLETE) && 839 bcmp(&con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0) 840 break; 841 842 if (con == NULL) { 843 con = ng_hci_new_con(unit, ep->link_type); 844 if (con != NULL) { 845 bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr)); 846 847 con->state = NG_HCI_CON_W4_LP_CON_RSP; 848 ng_hci_con_timeout(con); 849 850 error = ng_hci_lp_con_ind(con, ep->uclass); 851 if (error != 0) { 852 ng_hci_con_untimeout(con); 853 ng_hci_free_con(con); 854 } 855 } else 856 error = ENOMEM; 857 } 858 859 NG_FREE_M(event); 860 861 return (error); 862} /* con_req */ 863 864/* Disconnect complete event */ 865static int 866discon_compl(ng_hci_unit_p unit, struct mbuf *event) 867{ 868 ng_hci_discon_compl_ep *ep = NULL; 869 ng_hci_unit_con_p con = NULL; 870 int error = 0; 871 u_int16_t h; 872 873 NG_HCI_M_PULLUP(event, sizeof(*ep)); 874 if (event == NULL) 875 return (ENOBUFS); 876 877 ep = mtod(event, ng_hci_discon_compl_ep *); 878 879 /* 880 * XXX 881 * Do we have to send notification if ep->status != 0? 882 * For now we will send notification for both ACL and SCO connections 883 * ONLY if ep->status == 0. 884 */ 885 886 if (ep->status == 0) { 887 h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle)); 888 con = ng_hci_con_by_handle(unit, h); 889 if (con != NULL) { 890 error = ng_hci_lp_discon_ind(con, ep->reason); 891 892 /* Remove all timeouts (if any) */ 893 if (con->flags & NG_HCI_CON_TIMEOUT_PENDING) 894 ng_hci_con_untimeout(con); 895 896 ng_hci_free_con(con); 897 } else { 898 NG_HCI_ALERT( 899"%s: %s - invalid connection handle=%d\n", 900 __func__, NG_NODE_NAME(unit->node), h); 901 error = ENOENT; 902 } 903 } 904 905 NG_FREE_M(event); 906 907 return (error); 908} /* discon_compl */ 909 910/* Encryption change event */ 911static int 912encryption_change(ng_hci_unit_p unit, struct mbuf *event) 913{ 914 ng_hci_encryption_change_ep *ep = NULL; 915 ng_hci_unit_con_p con = NULL; 916 int error = 0; 917 u_int16_t h; 918 919 NG_HCI_M_PULLUP(event, sizeof(*ep)); 920 if (event == NULL) 921 return (ENOBUFS); 922 923 ep = mtod(event, ng_hci_encryption_change_ep *); 924 h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle)); 925 con = ng_hci_con_by_handle(unit, h); 926 927 if (ep->status == 0) { 928 if (con == NULL) { 929 NG_HCI_ALERT( 930"%s: %s - invalid connection handle=%d\n", 931 __func__, NG_NODE_NAME(unit->node), h); 932 error = ENOENT; 933 } else if (con->link_type == NG_HCI_LINK_SCO) { 934 NG_HCI_ALERT( 935"%s: %s - invalid link type=%d\n", 936 __func__, NG_NODE_NAME(unit->node), 937 con->link_type); 938 error = EINVAL; 939 } else if (ep->encryption_enable) 940 /* XXX is that true? */ 941 con->encryption_mode = NG_HCI_ENCRYPTION_MODE_P2P; 942 else 943 con->encryption_mode = NG_HCI_ENCRYPTION_MODE_NONE; 944 } else 945 NG_HCI_ERR( 946"%s: %s - failed to change encryption mode, status=%d\n", 947 __func__, NG_NODE_NAME(unit->node), ep->status); 948 949 /*Anyway, propagete encryption status to upper layer*/ 950 ng_hci_lp_enc_change(con, con->encryption_mode); 951 952 NG_FREE_M(event); 953 954 return (error); 955} /* encryption_change */ 956 957/* Read remote feature complete event */ 958static int 959read_remote_features_compl(ng_hci_unit_p unit, struct mbuf *event) 960{ 961 ng_hci_read_remote_features_compl_ep *ep = NULL; 962 ng_hci_unit_con_p con = NULL; 963 ng_hci_neighbor_p n = NULL; 964 u_int16_t h; 965 int error = 0; 966 967 NG_HCI_M_PULLUP(event, sizeof(*ep)); 968 if (event == NULL) 969 return (ENOBUFS); 970 971 ep = mtod(event, ng_hci_read_remote_features_compl_ep *); 972 973 if (ep->status == 0) { 974 /* Check if we have this connection handle */ 975 h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle)); 976 con = ng_hci_con_by_handle(unit, h); 977 if (con == NULL) { 978 NG_HCI_ALERT( 979"%s: %s - invalid connection handle=%d\n", 980 __func__, NG_NODE_NAME(unit->node), h); 981 error = ENOENT; 982 goto out; 983 } 984 985 /* Update cache entry */ 986 n = ng_hci_get_neighbor(unit, &con->bdaddr, NG_HCI_LINK_ACL); 987 if (n == NULL) { 988 n = ng_hci_new_neighbor(unit); 989 if (n == NULL) { 990 error = ENOMEM; 991 goto out; 992 } 993 994 bcopy(&con->bdaddr, &n->bdaddr, sizeof(n->bdaddr)); 995 n->addrtype = NG_HCI_LINK_ACL; 996 } else 997 getmicrotime(&n->updated); 998 999 bcopy(ep->features, n->features, sizeof(n->features)); 1000 } else 1001 NG_HCI_ERR( 1002"%s: %s - failed to read remote unit features, status=%d\n", 1003 __func__, NG_NODE_NAME(unit->node), ep->status); 1004out: 1005 NG_FREE_M(event); 1006 1007 return (error); 1008} /* read_remote_features_compl */ 1009 1010/* QoS setup complete event */ 1011static int 1012qos_setup_compl(ng_hci_unit_p unit, struct mbuf *event) 1013{ 1014 ng_hci_qos_setup_compl_ep *ep = NULL; 1015 ng_hci_unit_con_p con = NULL; 1016 u_int16_t h; 1017 int error = 0; 1018 1019 NG_HCI_M_PULLUP(event, sizeof(*ep)); 1020 if (event == NULL) 1021 return (ENOBUFS); 1022 1023 ep = mtod(event, ng_hci_qos_setup_compl_ep *); 1024 1025 /* Check if we have this connection handle */ 1026 h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle)); 1027 con = ng_hci_con_by_handle(unit, h); 1028 if (con == NULL) { 1029 NG_HCI_ALERT( 1030"%s: %s - invalid connection handle=%d\n", 1031 __func__, NG_NODE_NAME(unit->node), h); 1032 error = ENOENT; 1033 } else if (con->link_type != NG_HCI_LINK_ACL) { 1034 NG_HCI_ALERT( 1035"%s: %s - invalid link type=%d, handle=%d\n", 1036 __func__, NG_NODE_NAME(unit->node), con->link_type, h); 1037 error = EINVAL; 1038 } else if (con->state != NG_HCI_CON_OPEN) { 1039 NG_HCI_ALERT( 1040"%s: %s - invalid connection state=%d, handle=%d\n", 1041 __func__, NG_NODE_NAME(unit->node), 1042 con->state, h); 1043 error = EINVAL; 1044 } else /* Notify upper layer */ 1045 error = ng_hci_lp_qos_cfm(con, ep->status); 1046 1047 NG_FREE_M(event); 1048 1049 return (error); 1050} /* qos_setup_compl */ 1051 1052/* Hardware error event */ 1053static int 1054hardware_error(ng_hci_unit_p unit, struct mbuf *event) 1055{ 1056 NG_HCI_ALERT( 1057"%s: %s - hardware error %#x\n", 1058 __func__, NG_NODE_NAME(unit->node), *mtod(event, u_int8_t *)); 1059 1060 NG_FREE_M(event); 1061 1062 return (0); 1063} /* hardware_error */ 1064 1065/* Role change event */ 1066static int 1067role_change(ng_hci_unit_p unit, struct mbuf *event) 1068{ 1069 ng_hci_role_change_ep *ep = NULL; 1070 ng_hci_unit_con_p con = NULL; 1071 1072 NG_HCI_M_PULLUP(event, sizeof(*ep)); 1073 if (event == NULL) 1074 return (ENOBUFS); 1075 1076 ep = mtod(event, ng_hci_role_change_ep *); 1077 1078 if (ep->status == 0) { 1079 /* XXX shoud we also change "role" for SCO connections? */ 1080 con = ng_hci_con_by_bdaddr(unit, &ep->bdaddr, NG_HCI_LINK_ACL); 1081 if (con != NULL) 1082 con->role = ep->role; 1083 else 1084 NG_HCI_ALERT( 1085"%s: %s - ACL connection does not exist, bdaddr=%x:%x:%x:%x:%x:%x\n", 1086 __func__, NG_NODE_NAME(unit->node), 1087 ep->bdaddr.b[5], ep->bdaddr.b[4], 1088 ep->bdaddr.b[3], ep->bdaddr.b[2], 1089 ep->bdaddr.b[1], ep->bdaddr.b[0]); 1090 } else 1091 NG_HCI_ERR( 1092"%s: %s - failed to change role, status=%d, bdaddr=%x:%x:%x:%x:%x:%x\n", 1093 __func__, NG_NODE_NAME(unit->node), ep->status, 1094 ep->bdaddr.b[5], ep->bdaddr.b[4], ep->bdaddr.b[3], 1095 ep->bdaddr.b[2], ep->bdaddr.b[1], ep->bdaddr.b[0]); 1096 1097 NG_FREE_M(event); 1098 1099 return (0); 1100} /* role_change */ 1101 1102/* Number of completed packets event */ 1103static int 1104num_compl_pkts(ng_hci_unit_p unit, struct mbuf *event) 1105{ 1106 ng_hci_num_compl_pkts_ep *ep = NULL; 1107 ng_hci_unit_con_p con = NULL; 1108 u_int16_t h, p; 1109 1110 NG_HCI_M_PULLUP(event, sizeof(*ep)); 1111 if (event == NULL) 1112 return (ENOBUFS); 1113 1114 ep = mtod(event, ng_hci_num_compl_pkts_ep *); 1115 m_adj(event, sizeof(*ep)); 1116 1117 for (; ep->num_con_handles > 0; ep->num_con_handles --) { 1118 /* Get connection handle */ 1119 m_copydata(event, 0, sizeof(h), (caddr_t) &h); 1120 m_adj(event, sizeof(h)); 1121 h = NG_HCI_CON_HANDLE(le16toh(h)); 1122 1123 /* Get number of completed packets */ 1124 m_copydata(event, 0, sizeof(p), (caddr_t) &p); 1125 m_adj(event, sizeof(p)); 1126 p = le16toh(p); 1127 1128 /* Check if we have this connection handle */ 1129 con = ng_hci_con_by_handle(unit, h); 1130 if (con != NULL) { 1131 con->pending -= p; 1132 if (con->pending < 0) { 1133 NG_HCI_WARN( 1134"%s: %s - pending packet counter is out of sync! " \ 1135"handle=%d, pending=%d, ncp=%d\n", __func__, NG_NODE_NAME(unit->node), 1136 con->con_handle, con->pending, p); 1137 1138 con->pending = 0; 1139 } 1140 1141 /* Update buffer descriptor */ 1142 if (con->link_type != NG_HCI_LINK_SCO) 1143 NG_HCI_BUFF_ACL_FREE(unit->buffer, p); 1144 else 1145 NG_HCI_BUFF_SCO_FREE(unit->buffer, p); 1146 } else 1147 NG_HCI_ALERT( 1148"%s: %s - invalid connection handle=%d\n", 1149 __func__, NG_NODE_NAME(unit->node), h); 1150 } 1151 1152 NG_FREE_M(event); 1153 1154 /* Send more data */ 1155 ng_hci_send_data(unit); 1156 1157 return (0); 1158} /* num_compl_pkts */ 1159 1160/* Mode change event */ 1161static int 1162mode_change(ng_hci_unit_p unit, struct mbuf *event) 1163{ 1164 ng_hci_mode_change_ep *ep = NULL; 1165 ng_hci_unit_con_p con = NULL; 1166 int error = 0; 1167 1168 NG_HCI_M_PULLUP(event, sizeof(*ep)); 1169 if (event == NULL) 1170 return (ENOBUFS); 1171 1172 ep = mtod(event, ng_hci_mode_change_ep *); 1173 1174 if (ep->status == 0) { 1175 u_int16_t h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle)); 1176 1177 con = ng_hci_con_by_handle(unit, h); 1178 if (con == NULL) { 1179 NG_HCI_ALERT( 1180"%s: %s - invalid connection handle=%d\n", 1181 __func__, NG_NODE_NAME(unit->node), h); 1182 error = ENOENT; 1183 } else if (con->link_type != NG_HCI_LINK_ACL) { 1184 NG_HCI_ALERT( 1185"%s: %s - invalid link type=%d\n", 1186 __func__, NG_NODE_NAME(unit->node), 1187 con->link_type); 1188 error = EINVAL; 1189 } else 1190 con->mode = ep->unit_mode; 1191 } else 1192 NG_HCI_ERR( 1193"%s: %s - failed to change mode, status=%d\n", 1194 __func__, NG_NODE_NAME(unit->node), ep->status); 1195 1196 NG_FREE_M(event); 1197 1198 return (error); 1199} /* mode_change */ 1200 1201/* Data buffer overflow event */ 1202static int 1203data_buffer_overflow(ng_hci_unit_p unit, struct mbuf *event) 1204{ 1205 NG_HCI_ALERT( 1206"%s: %s - %s data buffer overflow\n", 1207 __func__, NG_NODE_NAME(unit->node), 1208 (*mtod(event, u_int8_t *) == NG_HCI_LINK_ACL)? "ACL" : "SCO"); 1209 1210 NG_FREE_M(event); 1211 1212 return (0); 1213} /* data_buffer_overflow */ 1214 1215/* Read clock offset complete event */ 1216static int 1217read_clock_offset_compl(ng_hci_unit_p unit, struct mbuf *event) 1218{ 1219 ng_hci_read_clock_offset_compl_ep *ep = NULL; 1220 ng_hci_unit_con_p con = NULL; 1221 ng_hci_neighbor_p n = NULL; 1222 int error = 0; 1223 1224 NG_HCI_M_PULLUP(event, sizeof(*ep)); 1225 if (event == NULL) 1226 return (ENOBUFS); 1227 1228 ep = mtod(event, ng_hci_read_clock_offset_compl_ep *); 1229 1230 if (ep->status == 0) { 1231 u_int16_t h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle)); 1232 1233 con = ng_hci_con_by_handle(unit, h); 1234 if (con == NULL) { 1235 NG_HCI_ALERT( 1236"%s: %s - invalid connection handle=%d\n", 1237 __func__, NG_NODE_NAME(unit->node), h); 1238 error = ENOENT; 1239 goto out; 1240 } 1241 1242 /* Update cache entry */ 1243 n = ng_hci_get_neighbor(unit, &con->bdaddr, NG_HCI_LINK_ACL); 1244 if (n == NULL) { 1245 n = ng_hci_new_neighbor(unit); 1246 if (n == NULL) { 1247 error = ENOMEM; 1248 goto out; 1249 } 1250 1251 bcopy(&con->bdaddr, &n->bdaddr, sizeof(n->bdaddr)); 1252 n->addrtype = NG_HCI_LINK_ACL; 1253 } else 1254 getmicrotime(&n->updated); 1255 1256 n->clock_offset = le16toh(ep->clock_offset); 1257 } else 1258 NG_HCI_ERR( 1259"%s: %s - failed to Read Remote Clock Offset, status=%d\n", 1260 __func__, NG_NODE_NAME(unit->node), ep->status); 1261out: 1262 NG_FREE_M(event); 1263 1264 return (error); 1265} /* read_clock_offset_compl */ 1266 1267/* QoS violation event */ 1268static int 1269qos_violation(ng_hci_unit_p unit, struct mbuf *event) 1270{ 1271 ng_hci_qos_violation_ep *ep = NULL; 1272 ng_hci_unit_con_p con = NULL; 1273 u_int16_t h; 1274 int error = 0; 1275 1276 NG_HCI_M_PULLUP(event, sizeof(*ep)); 1277 if (event == NULL) 1278 return (ENOBUFS); 1279 1280 ep = mtod(event, ng_hci_qos_violation_ep *); 1281 1282 /* Check if we have this connection handle */ 1283 h = NG_HCI_CON_HANDLE(le16toh(ep->con_handle)); 1284 con = ng_hci_con_by_handle(unit, h); 1285 if (con == NULL) { 1286 NG_HCI_ALERT( 1287"%s: %s - invalid connection handle=%d\n", 1288 __func__, NG_NODE_NAME(unit->node), h); 1289 error = ENOENT; 1290 } else if (con->link_type != NG_HCI_LINK_ACL) { 1291 NG_HCI_ALERT( 1292"%s: %s - invalid link type=%d\n", 1293 __func__, NG_NODE_NAME(unit->node), con->link_type); 1294 error = EINVAL; 1295 } else if (con->state != NG_HCI_CON_OPEN) { 1296 NG_HCI_ALERT( 1297"%s: %s - invalid connection state=%d, handle=%d\n", 1298 __func__, NG_NODE_NAME(unit->node), con->state, h); 1299 error = EINVAL; 1300 } else /* Notify upper layer */ 1301 error = ng_hci_lp_qos_ind(con); 1302 1303 NG_FREE_M(event); 1304 1305 return (error); 1306} /* qos_violation */ 1307 1308/* Page scan mode change event */ 1309static int 1310page_scan_mode_change(ng_hci_unit_p unit, struct mbuf *event) 1311{ 1312 ng_hci_page_scan_mode_change_ep *ep = NULL; 1313 ng_hci_neighbor_p n = NULL; 1314 int error = 0; 1315 1316 NG_HCI_M_PULLUP(event, sizeof(*ep)); 1317 if (event == NULL) 1318 return (ENOBUFS); 1319 1320 ep = mtod(event, ng_hci_page_scan_mode_change_ep *); 1321 1322 /* Update cache entry */ 1323 n = ng_hci_get_neighbor(unit, &ep->bdaddr, NG_HCI_LINK_ACL); 1324 if (n == NULL) { 1325 n = ng_hci_new_neighbor(unit); 1326 if (n == NULL) { 1327 error = ENOMEM; 1328 goto out; 1329 } 1330 1331 bcopy(&ep->bdaddr, &n->bdaddr, sizeof(n->bdaddr)); 1332 n->addrtype = NG_HCI_LINK_ACL; 1333 } else 1334 getmicrotime(&n->updated); 1335 1336 n->page_scan_mode = ep->page_scan_mode; 1337out: 1338 NG_FREE_M(event); 1339 1340 return (error); 1341} /* page_scan_mode_change */ 1342 1343/* Page scan repetition mode change event */ 1344static int 1345page_scan_rep_mode_change(ng_hci_unit_p unit, struct mbuf *event) 1346{ 1347 ng_hci_page_scan_rep_mode_change_ep *ep = NULL; 1348 ng_hci_neighbor_p n = NULL; 1349 int error = 0; 1350 1351 NG_HCI_M_PULLUP(event, sizeof(*ep)); 1352 if (event == NULL) 1353 return (ENOBUFS); 1354 1355 ep = mtod(event, ng_hci_page_scan_rep_mode_change_ep *); 1356 1357 /* Update cache entry */ 1358 n = ng_hci_get_neighbor(unit, &ep->bdaddr, NG_HCI_LINK_ACL); 1359 if (n == NULL) { 1360 n = ng_hci_new_neighbor(unit); 1361 if (n == NULL) { 1362 error = ENOMEM; 1363 goto out; 1364 } 1365 1366 bcopy(&ep->bdaddr, &n->bdaddr, sizeof(n->bdaddr)); 1367 n->addrtype = NG_HCI_LINK_ACL; 1368 } else 1369 getmicrotime(&n->updated); 1370 1371 n->page_scan_rep_mode = ep->page_scan_rep_mode; 1372out: 1373 NG_FREE_M(event); 1374 1375 return (error); 1376} /* page_scan_rep_mode_change */ 1377 1378