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