1 /* 2 * ng_hci_ulpi.c 3 */ 4 5 /*- 6 * SPDX-License-Identifier: BSD-2-Clause 7 * 8 * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com> 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $Id: ng_hci_ulpi.c,v 1.7 2003/09/08 18:57:51 max Exp $ 33 */ 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 #include <sys/endian.h> 39 #include <sys/malloc.h> 40 #include <sys/mbuf.h> 41 #include <sys/queue.h> 42 #include <netgraph/ng_message.h> 43 #include <netgraph/netgraph.h> 44 #include <netgraph/bluetooth/include/ng_bluetooth.h> 45 #include <netgraph/bluetooth/include/ng_hci.h> 46 #include <netgraph/bluetooth/hci/ng_hci_var.h> 47 #include <netgraph/bluetooth/hci/ng_hci_cmds.h> 48 #include <netgraph/bluetooth/hci/ng_hci_evnt.h> 49 #include <netgraph/bluetooth/hci/ng_hci_ulpi.h> 50 #include <netgraph/bluetooth/hci/ng_hci_misc.h> 51 52 /****************************************************************************** 53 ****************************************************************************** 54 ** Upper Layer Protocol Interface module 55 ****************************************************************************** 56 ******************************************************************************/ 57 58 static int ng_hci_lp_acl_con_req (ng_hci_unit_p, item_p, hook_p); 59 static int ng_hci_lp_sco_con_req (ng_hci_unit_p, item_p, hook_p); 60 static int ng_hci_lp_le_con_req (ng_hci_unit_p, item_p, hook_p, int); 61 62 /* 63 * Process LP_ConnectReq event from the upper layer protocol 64 */ 65 66 int 67 ng_hci_lp_con_req(ng_hci_unit_p unit, item_p item, hook_p hook) 68 { 69 int link_type; 70 71 if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) { 72 NG_HCI_WARN( 73 "%s: %s - unit is not ready, state=%#x\n", 74 __func__, NG_NODE_NAME(unit->node), unit->state); 75 76 NG_FREE_ITEM(item); 77 78 return (ENXIO); 79 } 80 81 if (NGI_MSG(item)->header.arglen != sizeof(ng_hci_lp_con_req_ep)) { 82 NG_HCI_ALERT( 83 "%s: %s - invalid LP_ConnectReq message size=%d\n", 84 __func__, NG_NODE_NAME(unit->node), 85 NGI_MSG(item)->header.arglen); 86 87 NG_FREE_ITEM(item); 88 89 return (EMSGSIZE); 90 } 91 link_type = ((ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data))->link_type; 92 switch(link_type){ 93 case NG_HCI_LINK_ACL: 94 return (ng_hci_lp_acl_con_req(unit, item, hook)); 95 case NG_HCI_LINK_SCO: 96 if (hook != unit->sco ) { 97 NG_HCI_WARN( 98 "%s: %s - LP_ConnectReq for SCO connection came from wrong hook=%p\n", 99 __func__, NG_NODE_NAME(unit->node), hook); 100 101 NG_FREE_ITEM(item); 102 103 return (EINVAL); 104 } 105 106 return (ng_hci_lp_sco_con_req(unit, item, hook)); 107 case NG_HCI_LINK_LE_PUBLIC: 108 case NG_HCI_LINK_LE_RANDOM: 109 return (ng_hci_lp_le_con_req(unit, item, hook, link_type)); 110 default: 111 panic("%s: link_type invalid.", __func__); 112 } 113 114 return (EINVAL); 115 } /* ng_hci_lp_con_req */ 116 117 /* 118 * Request to create new ACL connection 119 */ 120 121 static int 122 ng_hci_lp_acl_con_req(ng_hci_unit_p unit, item_p item, hook_p hook) 123 { 124 struct acl_con_req { 125 ng_hci_cmd_pkt_t hdr; 126 ng_hci_create_con_cp cp; 127 } __attribute__ ((packed)) *req = NULL; 128 ng_hci_lp_con_req_ep *ep = NULL; 129 ng_hci_unit_con_p con = NULL; 130 ng_hci_neighbor_t *n = NULL; 131 struct mbuf *m = NULL; 132 int error = 0; 133 134 ep = (ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data); 135 136 /* 137 * Only one ACL connection can exist between each pair of units. 138 * So try to find ACL connection descriptor (in any state) that 139 * has requested remote BD_ADDR. 140 * 141 * Two cases: 142 * 143 * 1) We do not have connection to the remote unit. This is simple. 144 * Just create new connection descriptor and send HCI command to 145 * create new connection. 146 * 147 * 2) We do have connection descriptor. We need to check connection 148 * state: 149 * 150 * 2.1) NG_HCI_CON_W4_LP_CON_RSP means that we are in the middle of 151 * accepting connection from the remote unit. This is a race 152 * condition. We will ignore this message. 153 * 154 * 2.2) NG_HCI_CON_W4_CONN_COMPLETE means that upper layer already 155 * requested connection or we just accepted it. In any case 156 * all we need to do here is set appropriate notification bit 157 * and wait. 158 * 159 * 2.3) NG_HCI_CON_OPEN means connection is open. Just reply back 160 * and let upper layer know that we have connection already. 161 */ 162 163 con = ng_hci_con_by_bdaddr(unit, &ep->bdaddr, NG_HCI_LINK_ACL); 164 if (con != NULL) { 165 switch (con->state) { 166 case NG_HCI_CON_W4_LP_CON_RSP: /* XXX */ 167 error = EALREADY; 168 break; 169 170 case NG_HCI_CON_W4_CONN_COMPLETE: 171 if (hook == unit->acl) 172 con->flags |= NG_HCI_CON_NOTIFY_ACL; 173 else 174 con->flags |= NG_HCI_CON_NOTIFY_SCO; 175 break; 176 177 case NG_HCI_CON_OPEN: { 178 struct ng_mesg *msg = NULL; 179 ng_hci_lp_con_cfm_ep *cfm = NULL; 180 181 if (hook != NULL && NG_HOOK_IS_VALID(hook)) { 182 NGI_GET_MSG(item, msg); 183 NG_FREE_MSG(msg); 184 185 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, 186 NGM_HCI_LP_CON_CFM, sizeof(*cfm), 187 M_NOWAIT); 188 if (msg != NULL) { 189 cfm = (ng_hci_lp_con_cfm_ep *)msg->data; 190 cfm->status = 0; 191 cfm->link_type = con->link_type; 192 cfm->con_handle = con->con_handle; 193 bcopy(&con->bdaddr, &cfm->bdaddr, 194 sizeof(cfm->bdaddr)); 195 196 /* 197 * This will forward item back to 198 * sender and set item to NULL 199 */ 200 201 _NGI_MSG(item) = msg; 202 NG_FWD_ITEM_HOOK(error, item, hook); 203 } else 204 error = ENOMEM; 205 } else 206 NG_HCI_INFO( 207 "%s: %s - Source hook is not valid, hook=%p\n", 208 __func__, NG_NODE_NAME(unit->node), 209 hook); 210 } break; 211 212 default: 213 panic( 214 "%s: %s - Invalid connection state=%d\n", 215 __func__, NG_NODE_NAME(unit->node), con->state); 216 break; 217 } 218 219 goto out; 220 } 221 222 /* 223 * If we got here then we need to create new ACL connection descriptor 224 * and submit HCI command. First create new connection desriptor, set 225 * bdaddr and notification flags. 226 */ 227 228 con = ng_hci_new_con(unit, NG_HCI_LINK_ACL); 229 if (con == NULL) { 230 error = ENOMEM; 231 goto out; 232 } 233 234 bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr)); 235 236 /* 237 * Create HCI command 238 */ 239 240 MGETHDR(m, M_NOWAIT, MT_DATA); 241 if (m == NULL) { 242 ng_hci_free_con(con); 243 error = ENOBUFS; 244 goto out; 245 } 246 247 m->m_pkthdr.len = m->m_len = sizeof(*req); 248 req = mtod(m, struct acl_con_req *); 249 req->hdr.type = NG_HCI_CMD_PKT; 250 req->hdr.length = sizeof(req->cp); 251 req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, 252 NG_HCI_OCF_CREATE_CON)); 253 254 bcopy(&ep->bdaddr, &req->cp.bdaddr, sizeof(req->cp.bdaddr)); 255 256 req->cp.pkt_type = (NG_HCI_PKT_DM1|NG_HCI_PKT_DH1); 257 if (unit->features[0] & NG_HCI_LMP_3SLOT) 258 req->cp.pkt_type |= (NG_HCI_PKT_DM3|NG_HCI_PKT_DH3); 259 if (unit->features[0] & NG_HCI_LMP_5SLOT) 260 req->cp.pkt_type |= (NG_HCI_PKT_DM5|NG_HCI_PKT_DH5); 261 262 req->cp.pkt_type &= unit->packet_mask; 263 if ((req->cp.pkt_type & (NG_HCI_PKT_DM1|NG_HCI_PKT_DH1| 264 NG_HCI_PKT_DM3|NG_HCI_PKT_DH3| 265 NG_HCI_PKT_DM5|NG_HCI_PKT_DH5)) == 0) 266 req->cp.pkt_type = (NG_HCI_PKT_DM1|NG_HCI_PKT_DH1); 267 268 req->cp.pkt_type = htole16(req->cp.pkt_type); 269 270 if ((unit->features[0] & NG_HCI_LMP_SWITCH) && unit->role_switch) 271 req->cp.accept_role_switch = 1; 272 else 273 req->cp.accept_role_switch = 0; 274 275 /* 276 * We may speed up connect by specifying valid parameters. 277 * So check the neighbor cache. 278 */ 279 280 n = ng_hci_get_neighbor(unit, &ep->bdaddr, NG_HCI_LINK_ACL); 281 if (n == NULL) { 282 req->cp.page_scan_rep_mode = 0; 283 req->cp.page_scan_mode = 0; 284 req->cp.clock_offset = 0; 285 } else { 286 req->cp.page_scan_rep_mode = n->page_scan_rep_mode; 287 req->cp.page_scan_mode = n->page_scan_mode; 288 req->cp.clock_offset = htole16(n->clock_offset); 289 } 290 291 /* 292 * Adust connection state 293 */ 294 295 if (hook == unit->acl) 296 con->flags |= NG_HCI_CON_NOTIFY_ACL; 297 else 298 con->flags |= NG_HCI_CON_NOTIFY_SCO; 299 300 con->state = NG_HCI_CON_W4_CONN_COMPLETE; 301 ng_hci_con_timeout(con); 302 303 /* 304 * Queue and send HCI command 305 */ 306 307 NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); 308 if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) 309 error = ng_hci_send_command(unit); 310 out: 311 if (item != NULL) 312 NG_FREE_ITEM(item); 313 314 return (error); 315 } /* ng_hci_lp_acl_con_req */ 316 317 /* 318 * Request to create new SCO connection 319 */ 320 321 static int 322 ng_hci_lp_sco_con_req(ng_hci_unit_p unit, item_p item, hook_p hook) 323 { 324 struct sco_con_req { 325 ng_hci_cmd_pkt_t hdr; 326 ng_hci_add_sco_con_cp cp; 327 } __attribute__ ((packed)) *req = NULL; 328 ng_hci_lp_con_req_ep *ep = NULL; 329 ng_hci_unit_con_p acl_con = NULL, sco_con = NULL; 330 struct mbuf *m = NULL; 331 int error = 0; 332 333 ep = (ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data); 334 335 /* 336 * SCO connection without ACL link 337 * 338 * If upper layer requests SCO connection and there is no open ACL 339 * connection to the desired remote unit, we will reject the request. 340 */ 341 342 LIST_FOREACH(acl_con, &unit->con_list, next) 343 if (acl_con->link_type == NG_HCI_LINK_ACL && 344 acl_con->state == NG_HCI_CON_OPEN && 345 bcmp(&acl_con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0) 346 break; 347 348 if (acl_con == NULL) { 349 NG_HCI_INFO( 350 "%s: %s - No open ACL connection to bdaddr=%x:%x:%x:%x:%x:%x\n", 351 __func__, NG_NODE_NAME(unit->node), 352 ep->bdaddr.b[5], ep->bdaddr.b[4], ep->bdaddr.b[3], 353 ep->bdaddr.b[2], ep->bdaddr.b[1], ep->bdaddr.b[0]); 354 355 error = ENOENT; 356 goto out; 357 } 358 359 /* 360 * Multiple SCO connections can exist between the same pair of units. 361 * We assume that multiple SCO connections have to be opened one after 362 * another. 363 * 364 * Try to find SCO connection descriptor that matches the following: 365 * 366 * 1) sco_con->link_type == NG_HCI_LINK_SCO 367 * 368 * 2) sco_con->state == NG_HCI_CON_W4_LP_CON_RSP || 369 * sco_con->state == NG_HCI_CON_W4_CONN_COMPLETE 370 * 371 * 3) sco_con->bdaddr == ep->bdaddr 372 * 373 * Two cases: 374 * 375 * 1) We do not have connection descriptor. This is simple. Just 376 * create new connection and submit Add_SCO_Connection command. 377 * 378 * 2) We do have connection descriptor. We need to check the state. 379 * 380 * 2.1) NG_HCI_CON_W4_LP_CON_RSP means we in the middle of accepting 381 * connection from the remote unit. This is a race condition and 382 * we will ignore the request. 383 * 384 * 2.2) NG_HCI_CON_W4_CONN_COMPLETE means upper layer already requested 385 * connection or we just accepted it. 386 */ 387 388 LIST_FOREACH(sco_con, &unit->con_list, next) 389 if (sco_con->link_type == NG_HCI_LINK_SCO && 390 (sco_con->state == NG_HCI_CON_W4_LP_CON_RSP || 391 sco_con->state == NG_HCI_CON_W4_CONN_COMPLETE) && 392 bcmp(&sco_con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0) 393 break; 394 395 if (sco_con != NULL) { 396 switch (sco_con->state) { 397 case NG_HCI_CON_W4_LP_CON_RSP: /* XXX */ 398 error = EALREADY; 399 break; 400 401 case NG_HCI_CON_W4_CONN_COMPLETE: 402 sco_con->flags |= NG_HCI_CON_NOTIFY_SCO; 403 break; 404 405 default: 406 panic( 407 "%s: %s - Invalid connection state=%d\n", 408 __func__, NG_NODE_NAME(unit->node), 409 sco_con->state); 410 break; 411 } 412 413 goto out; 414 } 415 416 /* 417 * If we got here then we need to create new SCO connection descriptor 418 * and submit HCI command. 419 */ 420 421 sco_con = ng_hci_new_con(unit, NG_HCI_LINK_SCO); 422 if (sco_con == NULL) { 423 error = ENOMEM; 424 goto out; 425 } 426 427 bcopy(&ep->bdaddr, &sco_con->bdaddr, sizeof(sco_con->bdaddr)); 428 429 /* 430 * Create HCI command 431 */ 432 433 MGETHDR(m, M_NOWAIT, MT_DATA); 434 if (m == NULL) { 435 ng_hci_free_con(sco_con); 436 error = ENOBUFS; 437 goto out; 438 } 439 440 m->m_pkthdr.len = m->m_len = sizeof(*req); 441 req = mtod(m, struct sco_con_req *); 442 req->hdr.type = NG_HCI_CMD_PKT; 443 req->hdr.length = sizeof(req->cp); 444 req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, 445 NG_HCI_OCF_ADD_SCO_CON)); 446 447 req->cp.con_handle = htole16(acl_con->con_handle); 448 449 req->cp.pkt_type = NG_HCI_PKT_HV1; 450 if (unit->features[1] & NG_HCI_LMP_HV2_PKT) 451 req->cp.pkt_type |= NG_HCI_PKT_HV2; 452 if (unit->features[1] & NG_HCI_LMP_HV3_PKT) 453 req->cp.pkt_type |= NG_HCI_PKT_HV3; 454 455 req->cp.pkt_type &= unit->packet_mask; 456 if ((req->cp.pkt_type & (NG_HCI_PKT_HV1| 457 NG_HCI_PKT_HV2| 458 NG_HCI_PKT_HV3)) == 0) 459 req->cp.pkt_type = NG_HCI_PKT_HV1; 460 461 req->cp.pkt_type = htole16(req->cp.pkt_type); 462 463 /* 464 * Adust connection state 465 */ 466 467 sco_con->flags |= NG_HCI_CON_NOTIFY_SCO; 468 469 sco_con->state = NG_HCI_CON_W4_CONN_COMPLETE; 470 ng_hci_con_timeout(sco_con); 471 472 /* 473 * Queue and send HCI command 474 */ 475 476 NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); 477 if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) 478 error = ng_hci_send_command(unit); 479 out: 480 NG_FREE_ITEM(item); 481 482 return (error); 483 } /* ng_hci_lp_sco_con_req */ 484 485 static int 486 ng_hci_lp_le_con_req(ng_hci_unit_p unit, item_p item, hook_p hook, int link_type) 487 { 488 struct acl_con_req { 489 ng_hci_cmd_pkt_t hdr; 490 ng_hci_le_create_connection_cp cp; 491 } __attribute__ ((packed)) *req = NULL; 492 ng_hci_lp_con_req_ep *ep = NULL; 493 ng_hci_unit_con_p con = NULL; 494 struct mbuf *m = NULL; 495 int error = 0; 496 497 ep = (ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data); 498 if((link_type != NG_HCI_LINK_LE_PUBLIC)&& 499 (link_type != NG_HCI_LINK_LE_RANDOM)){ 500 printf("%s: Link type %d Cannot be here \n", __func__, 501 link_type); 502 } 503 /* 504 * Only one ACL connection can exist between each pair of units. 505 * So try to find ACL connection descriptor (in any state) that 506 * has requested remote BD_ADDR. 507 * 508 * Two cases: 509 * 510 * 1) We do not have connection to the remote unit. This is simple. 511 * Just create new connection descriptor and send HCI command to 512 * create new connection. 513 * 514 * 2) We do have connection descriptor. We need to check connection 515 * state: 516 * 517 * 2.1) NG_HCI_CON_W4_LP_CON_RSP means that we are in the middle of 518 * accepting connection from the remote unit. This is a race 519 * condition. We will ignore this message. 520 * 521 * 2.2) NG_HCI_CON_W4_CONN_COMPLETE means that upper layer already 522 * requested connection or we just accepted it. In any case 523 * all we need to do here is set appropriate notification bit 524 * and wait. 525 * 526 * 2.3) NG_HCI_CON_OPEN means connection is open. Just reply back 527 * and let upper layer know that we have connection already. 528 */ 529 530 con = ng_hci_con_by_bdaddr(unit, &ep->bdaddr, link_type); 531 if (con != NULL) { 532 switch (con->state) { 533 case NG_HCI_CON_W4_LP_CON_RSP: /* XXX */ 534 error = EALREADY; 535 break; 536 537 case NG_HCI_CON_W4_CONN_COMPLETE: 538 if (hook != unit->sco) 539 con->flags |= NG_HCI_CON_NOTIFY_ACL; 540 else 541 con->flags |= NG_HCI_CON_NOTIFY_SCO; 542 break; 543 544 case NG_HCI_CON_OPEN: { 545 struct ng_mesg *msg = NULL; 546 ng_hci_lp_con_cfm_ep *cfm = NULL; 547 548 if (hook != NULL && NG_HOOK_IS_VALID(hook)) { 549 NGI_GET_MSG(item, msg); 550 NG_FREE_MSG(msg); 551 552 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, 553 NGM_HCI_LP_CON_CFM, sizeof(*cfm), 554 M_NOWAIT); 555 if (msg != NULL) { 556 cfm = (ng_hci_lp_con_cfm_ep *)msg->data; 557 cfm->status = 0; 558 cfm->link_type = con->link_type; 559 cfm->con_handle = con->con_handle; 560 bcopy(&con->bdaddr, &cfm->bdaddr, 561 sizeof(cfm->bdaddr)); 562 563 /* 564 * This will forward item back to 565 * sender and set item to NULL 566 */ 567 568 _NGI_MSG(item) = msg; 569 NG_FWD_ITEM_HOOK(error, item, hook); 570 } else 571 error = ENOMEM; 572 } else 573 NG_HCI_INFO( 574 "%s: %s - Source hook is not valid, hook=%p\n", 575 __func__, NG_NODE_NAME(unit->node), 576 hook); 577 } break; 578 579 default: 580 panic( 581 "%s: %s - Invalid connection state=%d\n", 582 __func__, NG_NODE_NAME(unit->node), con->state); 583 break; 584 } 585 586 goto out; 587 } 588 589 /* 590 * If we got here then we need to create new ACL connection descriptor 591 * and submit HCI command. First create new connection desriptor, set 592 * bdaddr and notification flags. 593 */ 594 595 con = ng_hci_new_con(unit, link_type); 596 if (con == NULL) { 597 error = ENOMEM; 598 goto out; 599 } 600 601 bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr)); 602 603 /* 604 * Create HCI command 605 */ 606 607 MGETHDR(m, M_NOWAIT, MT_DATA); 608 if (m == NULL) { 609 ng_hci_free_con(con); 610 error = ENOBUFS; 611 goto out; 612 } 613 614 m->m_pkthdr.len = m->m_len = sizeof(*req); 615 req = mtod(m, struct acl_con_req *); 616 req->hdr.type = NG_HCI_CMD_PKT; 617 req->hdr.length = sizeof(req->cp); 618 req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LE, 619 NG_HCI_OCF_LE_CREATE_CONNECTION)); 620 621 bcopy(&ep->bdaddr, &req->cp.peer_addr, sizeof(req->cp.peer_addr)); 622 req->cp.own_address_type = 0; 623 req->cp.peer_addr_type = (link_type == NG_HCI_LINK_LE_RANDOM)? 1:0; 624 req->cp.scan_interval = htole16(4); 625 req->cp.scan_window = htole16(4); 626 req->cp.filter_policy = 0; 627 req->cp.conn_interval_min = htole16(0xf); 628 req->cp.conn_interval_max = htole16(0xf); 629 req->cp.conn_latency = htole16(0); 630 req->cp.supervision_timeout = htole16(0xc80); 631 req->cp.min_ce_length = htole16(1); 632 req->cp.max_ce_length = htole16(1); 633 /* 634 * Adust connection state 635 */ 636 637 if (hook != unit->sco) 638 con->flags |= NG_HCI_CON_NOTIFY_ACL; 639 else 640 con->flags |= NG_HCI_CON_NOTIFY_SCO; 641 642 con->state = NG_HCI_CON_W4_CONN_COMPLETE; 643 ng_hci_con_timeout(con); 644 645 /* 646 * Queue and send HCI command 647 */ 648 649 NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); 650 if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) 651 error = ng_hci_send_command(unit); 652 out: 653 if (item != NULL) 654 NG_FREE_ITEM(item); 655 656 return (error); 657 } /* ng_hci_lp_acl_con_req */ 658 659 /* 660 * Process LP_DisconnectReq event from the upper layer protocol 661 */ 662 663 int 664 ng_hci_lp_discon_req(ng_hci_unit_p unit, item_p item, hook_p hook) 665 { 666 struct discon_req { 667 ng_hci_cmd_pkt_t hdr; 668 ng_hci_discon_cp cp; 669 } __attribute__ ((packed)) *req = NULL; 670 ng_hci_lp_discon_req_ep *ep = NULL; 671 ng_hci_unit_con_p con = NULL; 672 struct mbuf *m = NULL; 673 int error = 0; 674 675 /* Check if unit is ready */ 676 if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) { 677 NG_HCI_WARN( 678 "%s: %s - unit is not ready, state=%#x\n", 679 __func__, NG_NODE_NAME(unit->node), unit->state); 680 681 error = ENXIO; 682 goto out; 683 } 684 685 if (NGI_MSG(item)->header.arglen != sizeof(*ep)) { 686 NG_HCI_ALERT( 687 "%s: %s - invalid LP_DisconnectReq message size=%d\n", 688 __func__, NG_NODE_NAME(unit->node), 689 NGI_MSG(item)->header.arglen); 690 691 error = EMSGSIZE; 692 goto out; 693 } 694 695 ep = (ng_hci_lp_discon_req_ep *)(NGI_MSG(item)->data); 696 697 con = ng_hci_con_by_handle(unit, ep->con_handle); 698 if (con == NULL) { 699 NG_HCI_ERR( 700 "%s: %s - invalid connection handle=%d\n", 701 __func__, NG_NODE_NAME(unit->node), ep->con_handle); 702 703 error = ENOENT; 704 goto out; 705 } 706 707 if (con->state != NG_HCI_CON_OPEN) { 708 NG_HCI_ERR( 709 "%s: %s - invalid connection state=%d, handle=%d\n", 710 __func__, NG_NODE_NAME(unit->node), con->state, 711 ep->con_handle); 712 713 error = EINVAL; 714 goto out; 715 } 716 717 /* 718 * Create HCI command 719 */ 720 721 MGETHDR(m, M_NOWAIT, MT_DATA); 722 if (m == NULL) { 723 error = ENOBUFS; 724 goto out; 725 } 726 727 m->m_pkthdr.len = m->m_len = sizeof(*req); 728 req = mtod(m, struct discon_req *); 729 req->hdr.type = NG_HCI_CMD_PKT; 730 req->hdr.length = sizeof(req->cp); 731 req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, 732 NG_HCI_OCF_DISCON)); 733 734 req->cp.con_handle = htole16(ep->con_handle); 735 req->cp.reason = ep->reason; 736 737 /* 738 * Queue and send HCI command 739 */ 740 741 NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); 742 if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) 743 error = ng_hci_send_command(unit); 744 out: 745 NG_FREE_ITEM(item); 746 747 return (error); 748 } /* ng_hci_lp_discon_req */ 749 750 /* 751 * Send LP_ConnectCfm event to the upper layer protocol 752 */ 753 754 int 755 ng_hci_lp_con_cfm(ng_hci_unit_con_p con, int status) 756 { 757 ng_hci_unit_p unit = con->unit; 758 struct ng_mesg *msg = NULL; 759 ng_hci_lp_con_cfm_ep *ep = NULL; 760 int error; 761 762 /* 763 * Check who wants to be notified. For ACL links both ACL and SCO 764 * upstream hooks will be notified (if required). For SCO links 765 * only SCO upstream hook will receive notification 766 */ 767 768 if (con->link_type != NG_HCI_LINK_SCO && 769 con->flags & NG_HCI_CON_NOTIFY_ACL) { 770 if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) { 771 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_CFM, 772 sizeof(*ep), M_NOWAIT); 773 if (msg != NULL) { 774 ep = (ng_hci_lp_con_cfm_ep *) msg->data; 775 ep->status = status; 776 ep->link_type = con->link_type; 777 ep->con_handle = con->con_handle; 778 bcopy(&con->bdaddr, &ep->bdaddr, 779 sizeof(ep->bdaddr)); 780 781 NG_SEND_MSG_HOOK(error, unit->node, msg, 782 unit->acl, 0); 783 } 784 } else 785 NG_HCI_INFO( 786 "%s: %s - ACL hook not valid, hook=%p\n", 787 __func__, NG_NODE_NAME(unit->node), unit->acl); 788 789 con->flags &= ~NG_HCI_CON_NOTIFY_ACL; 790 } 791 792 if (con->flags & NG_HCI_CON_NOTIFY_SCO) { 793 if (unit->sco != NULL && NG_HOOK_IS_VALID(unit->sco)) { 794 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_CFM, 795 sizeof(*ep), M_NOWAIT); 796 if (msg != NULL) { 797 ep = (ng_hci_lp_con_cfm_ep *) msg->data; 798 ep->status = status; 799 ep->link_type = con->link_type; 800 ep->con_handle = con->con_handle; 801 bcopy(&con->bdaddr, &ep->bdaddr, 802 sizeof(ep->bdaddr)); 803 804 NG_SEND_MSG_HOOK(error, unit->node, msg, 805 unit->sco, 0); 806 } 807 } else 808 NG_HCI_INFO( 809 "%s: %s - SCO hook not valid, hook=%p\n", 810 __func__, NG_NODE_NAME(unit->node), unit->acl); 811 812 con->flags &= ~NG_HCI_CON_NOTIFY_SCO; 813 } 814 815 return (0); 816 } /* ng_hci_lp_con_cfm */ 817 818 int 819 ng_hci_lp_enc_change(ng_hci_unit_con_p con, int status) 820 { 821 ng_hci_unit_p unit = con->unit; 822 struct ng_mesg *msg = NULL; 823 ng_hci_lp_enc_change_ep *ep = NULL; 824 int error; 825 826 if (con->link_type != NG_HCI_LINK_SCO) { 827 if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) { 828 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_ENC_CHG, 829 sizeof(*ep), M_NOWAIT); 830 if (msg != NULL) { 831 ep = (ng_hci_lp_enc_change_ep *) msg->data; 832 ep->status = status; 833 ep->link_type = con->link_type; 834 ep->con_handle = con->con_handle; 835 836 NG_SEND_MSG_HOOK(error, unit->node, msg, 837 unit->acl, 0); 838 } 839 } else 840 NG_HCI_INFO( 841 "%s: %s - ACL hook not valid, hook=%p\n", 842 __func__, NG_NODE_NAME(unit->node), unit->acl); 843 } 844 return (0); 845 } /* ng_hci_lp_con_cfm */ 846 847 /* 848 * Send LP_ConnectInd event to the upper layer protocol 849 */ 850 851 int 852 ng_hci_lp_con_ind(ng_hci_unit_con_p con, u_int8_t *uclass) 853 { 854 ng_hci_unit_p unit = con->unit; 855 struct ng_mesg *msg = NULL; 856 ng_hci_lp_con_ind_ep *ep = NULL; 857 hook_p hook = NULL; 858 int error = 0; 859 860 /* 861 * Connection_Request event is generated for specific link type. 862 * Use link_type to select upstream hook. 863 */ 864 865 if (con->link_type != NG_HCI_LINK_SCO) 866 hook = unit->acl; 867 else 868 hook = unit->sco; 869 870 if (hook != NULL && NG_HOOK_IS_VALID(hook)) { 871 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_IND, 872 sizeof(*ep), M_NOWAIT); 873 if (msg == NULL) 874 return (ENOMEM); 875 876 ep = (ng_hci_lp_con_ind_ep *)(msg->data); 877 ep->link_type = con->link_type; 878 bcopy(uclass, ep->uclass, sizeof(ep->uclass)); 879 bcopy(&con->bdaddr, &ep->bdaddr, sizeof(ep->bdaddr)); 880 881 NG_SEND_MSG_HOOK(error, unit->node, msg, hook, 0); 882 } else { 883 NG_HCI_WARN( 884 "%s: %s - Upstream hook is not connected or not valid, hook=%p\n", 885 __func__, NG_NODE_NAME(unit->node), hook); 886 887 error = ENOTCONN; 888 } 889 890 return (error); 891 } /* ng_hci_lp_con_ind */ 892 893 /* 894 * Process LP_ConnectRsp event from the upper layer protocol 895 */ 896 897 int 898 ng_hci_lp_con_rsp(ng_hci_unit_p unit, item_p item, hook_p hook) 899 { 900 struct con_rsp_req { 901 ng_hci_cmd_pkt_t hdr; 902 union { 903 ng_hci_accept_con_cp acc; 904 ng_hci_reject_con_cp rej; 905 } __attribute__ ((packed)) cp; 906 } __attribute__ ((packed)) *req = NULL; 907 ng_hci_lp_con_rsp_ep *ep = NULL; 908 ng_hci_unit_con_p con = NULL; 909 struct mbuf *m = NULL; 910 int error = 0; 911 912 /* Check if unit is ready */ 913 if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) { 914 NG_HCI_WARN( 915 "%s: %s - unit is not ready, state=%#x\n", 916 __func__, NG_NODE_NAME(unit->node), unit->state); 917 918 error = ENXIO; 919 goto out; 920 } 921 922 if (NGI_MSG(item)->header.arglen != sizeof(*ep)) { 923 NG_HCI_ALERT( 924 "%s: %s - invalid LP_ConnectRsp message size=%d\n", 925 __func__, NG_NODE_NAME(unit->node), 926 NGI_MSG(item)->header.arglen); 927 928 error = EMSGSIZE; 929 goto out; 930 } 931 932 ep = (ng_hci_lp_con_rsp_ep *)(NGI_MSG(item)->data); 933 934 /* 935 * Here we have to deal with race. Upper layers might send conflicting 936 * requests. One might send Accept and other Reject. We will not try 937 * to solve all the problems, so first request will always win. 938 * 939 * Try to find connection that matches the following: 940 * 941 * 1) con->link_type == ep->link_type 942 * 943 * 2) con->state == NG_HCI_CON_W4_LP_CON_RSP || 944 * con->state == NG_HCI_CON_W4_CONN_COMPLETE 945 * 946 * 3) con->bdaddr == ep->bdaddr 947 * 948 * Two cases: 949 * 950 * 1) We do not have connection descriptor. Could be bogus request or 951 * we have rejected connection already. 952 * 953 * 2) We do have connection descriptor. Then we need to check state: 954 * 955 * 2.1) NG_HCI_CON_W4_LP_CON_RSP means upper layer has requested 956 * connection and it is a first response from the upper layer. 957 * if "status == 0" (Accept) then we will send Accept_Connection 958 * command and change connection state to W4_CONN_COMPLETE, else 959 * send reject and delete connection. 960 * 961 * 2.2) NG_HCI_CON_W4_CONN_COMPLETE means that we already accepted 962 * connection. If "status == 0" we just need to link request 963 * and wait, else ignore Reject request. 964 */ 965 966 LIST_FOREACH(con, &unit->con_list, next) 967 if (con->link_type == ep->link_type && 968 (con->state == NG_HCI_CON_W4_LP_CON_RSP || 969 con->state == NG_HCI_CON_W4_CONN_COMPLETE) && 970 bcmp(&con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0) 971 break; 972 973 if (con == NULL) { 974 /* Reject for non-existing connection is fine */ 975 error = (ep->status == 0)? ENOENT : 0; 976 goto out; 977 } 978 979 /* 980 * Remove connection timeout and check connection state. 981 * Note: if ng_hci_con_untimeout() fails (returns non-zero value) then 982 * timeout already happened and event went into node's queue. 983 */ 984 985 if ((error = ng_hci_con_untimeout(con)) != 0) 986 goto out; 987 988 switch (con->state) { 989 case NG_HCI_CON_W4_LP_CON_RSP: 990 991 /* 992 * Create HCI command 993 */ 994 995 MGETHDR(m, M_NOWAIT, MT_DATA); 996 if (m == NULL) { 997 error = ENOBUFS; 998 goto out; 999 } 1000 1001 req = mtod(m, struct con_rsp_req *); 1002 req->hdr.type = NG_HCI_CMD_PKT; 1003 1004 if (ep->status == 0) { 1005 req->hdr.length = sizeof(req->cp.acc); 1006 req->hdr.opcode = htole16(NG_HCI_OPCODE( 1007 NG_HCI_OGF_LINK_CONTROL, 1008 NG_HCI_OCF_ACCEPT_CON)); 1009 1010 bcopy(&ep->bdaddr, &req->cp.acc.bdaddr, 1011 sizeof(req->cp.acc.bdaddr)); 1012 1013 /* 1014 * We are accepting connection, so if we support role 1015 * switch and role switch was enabled then set role to 1016 * NG_HCI_ROLE_MASTER and let LM perform role switch. 1017 * Otherwise we remain slave. In this case LM WILL NOT 1018 * perform role switch. 1019 */ 1020 1021 if ((unit->features[0] & NG_HCI_LMP_SWITCH) && 1022 unit->role_switch) 1023 req->cp.acc.role = NG_HCI_ROLE_MASTER; 1024 else 1025 req->cp.acc.role = NG_HCI_ROLE_SLAVE; 1026 1027 /* 1028 * Adjust connection state 1029 */ 1030 1031 if (hook == unit->acl) 1032 con->flags |= NG_HCI_CON_NOTIFY_ACL; 1033 else 1034 con->flags |= NG_HCI_CON_NOTIFY_SCO; 1035 1036 con->state = NG_HCI_CON_W4_CONN_COMPLETE; 1037 ng_hci_con_timeout(con); 1038 } else { 1039 req->hdr.length = sizeof(req->cp.rej); 1040 req->hdr.opcode = htole16(NG_HCI_OPCODE( 1041 NG_HCI_OGF_LINK_CONTROL, 1042 NG_HCI_OCF_REJECT_CON)); 1043 1044 bcopy(&ep->bdaddr, &req->cp.rej.bdaddr, 1045 sizeof(req->cp.rej.bdaddr)); 1046 1047 req->cp.rej.reason = ep->status; 1048 1049 /* 1050 * Free connection descritor 1051 * Item will be deleted just before return. 1052 */ 1053 1054 ng_hci_free_con(con); 1055 } 1056 1057 m->m_pkthdr.len = m->m_len = sizeof(req->hdr) + req->hdr.length; 1058 1059 /* Queue and send HCI command */ 1060 NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); 1061 if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) 1062 error = ng_hci_send_command(unit); 1063 break; 1064 1065 case NG_HCI_CON_W4_CONN_COMPLETE: 1066 if (ep->status == 0) { 1067 if (hook == unit->acl) 1068 con->flags |= NG_HCI_CON_NOTIFY_ACL; 1069 else 1070 con->flags |= NG_HCI_CON_NOTIFY_SCO; 1071 } else 1072 error = EPERM; 1073 break; 1074 1075 default: 1076 panic( 1077 "%s: %s - Invalid connection state=%d\n", 1078 __func__, NG_NODE_NAME(unit->node), con->state); 1079 break; 1080 } 1081 out: 1082 NG_FREE_ITEM(item); 1083 1084 return (error); 1085 } /* ng_hci_lp_con_rsp */ 1086 1087 /* 1088 * Send LP_DisconnectInd to the upper layer protocol 1089 */ 1090 1091 int 1092 ng_hci_lp_discon_ind(ng_hci_unit_con_p con, int reason) 1093 { 1094 ng_hci_unit_p unit = con->unit; 1095 struct ng_mesg *msg = NULL; 1096 ng_hci_lp_discon_ind_ep *ep = NULL; 1097 int error = 0; 1098 1099 /* 1100 * Disconnect_Complete event is generated for specific connection 1101 * handle. For ACL connection handles both ACL and SCO upstream 1102 * hooks will receive notification. For SCO connection handles 1103 * only SCO upstream hook will receive notification. 1104 */ 1105 1106 if (con->link_type != NG_HCI_LINK_SCO) { 1107 if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) { 1108 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, 1109 NGM_HCI_LP_DISCON_IND, sizeof(*ep), M_NOWAIT); 1110 if (msg == NULL) 1111 return (ENOMEM); 1112 1113 ep = (ng_hci_lp_discon_ind_ep *) msg->data; 1114 ep->reason = reason; 1115 ep->link_type = con->link_type; 1116 ep->con_handle = con->con_handle; 1117 1118 NG_SEND_MSG_HOOK(error,unit->node,msg,unit->acl,0); 1119 } else 1120 NG_HCI_INFO( 1121 "%s: %s - ACL hook is not connected or not valid, hook=%p\n", 1122 __func__, NG_NODE_NAME(unit->node), unit->acl); 1123 } 1124 1125 if (unit->sco != NULL && NG_HOOK_IS_VALID(unit->sco)) { 1126 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_DISCON_IND, 1127 sizeof(*ep), M_NOWAIT); 1128 if (msg == NULL) 1129 return (ENOMEM); 1130 1131 ep = (ng_hci_lp_discon_ind_ep *) msg->data; 1132 ep->reason = reason; 1133 ep->link_type = con->link_type; 1134 ep->con_handle = con->con_handle; 1135 1136 NG_SEND_MSG_HOOK(error, unit->node, msg, unit->sco, 0); 1137 } else 1138 NG_HCI_INFO( 1139 "%s: %s - SCO hook is not connected or not valid, hook=%p\n", 1140 __func__, NG_NODE_NAME(unit->node), unit->sco); 1141 1142 return (0); 1143 } /* ng_hci_lp_discon_ind */ 1144 1145 /* 1146 * Process LP_QoSReq action from the upper layer protocol 1147 */ 1148 1149 int 1150 ng_hci_lp_qos_req(ng_hci_unit_p unit, item_p item, hook_p hook) 1151 { 1152 struct qos_setup_req { 1153 ng_hci_cmd_pkt_t hdr; 1154 ng_hci_qos_setup_cp cp; 1155 } __attribute__ ((packed)) *req = NULL; 1156 ng_hci_lp_qos_req_ep *ep = NULL; 1157 ng_hci_unit_con_p con = NULL; 1158 struct mbuf *m = NULL; 1159 int error = 0; 1160 1161 /* Check if unit is ready */ 1162 if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) { 1163 NG_HCI_WARN( 1164 "%s: %s - unit is not ready, state=%#x\n", 1165 __func__, NG_NODE_NAME(unit->node), unit->state); 1166 1167 error = ENXIO; 1168 goto out; 1169 } 1170 1171 if (NGI_MSG(item)->header.arglen != sizeof(*ep)) { 1172 NG_HCI_ALERT( 1173 "%s: %s - invalid LP_QoSSetupReq message size=%d\n", 1174 __func__, NG_NODE_NAME(unit->node), 1175 NGI_MSG(item)->header.arglen); 1176 1177 error = EMSGSIZE; 1178 goto out; 1179 } 1180 1181 ep = (ng_hci_lp_qos_req_ep *)(NGI_MSG(item)->data); 1182 1183 con = ng_hci_con_by_handle(unit, ep->con_handle); 1184 if (con == NULL) { 1185 NG_HCI_ERR( 1186 "%s: %s - invalid connection handle=%d\n", 1187 __func__, NG_NODE_NAME(unit->node), ep->con_handle); 1188 1189 error = EINVAL; 1190 goto out; 1191 } 1192 1193 if (con->link_type != NG_HCI_LINK_ACL) { 1194 NG_HCI_ERR("%s: %s - invalid link type=%d\n", 1195 __func__, NG_NODE_NAME(unit->node), con->link_type); 1196 1197 error = EINVAL; 1198 goto out; 1199 } 1200 1201 if (con->state != NG_HCI_CON_OPEN) { 1202 NG_HCI_ERR( 1203 "%s: %s - invalid connection state=%d, handle=%d\n", 1204 __func__, NG_NODE_NAME(unit->node), con->state, 1205 con->con_handle); 1206 1207 error = EINVAL; 1208 goto out; 1209 } 1210 1211 /* 1212 * Create HCI command 1213 */ 1214 1215 MGETHDR(m, M_NOWAIT, MT_DATA); 1216 if (m == NULL) { 1217 error = ENOBUFS; 1218 goto out; 1219 } 1220 1221 m->m_pkthdr.len = m->m_len = sizeof(*req); 1222 req = mtod(m, struct qos_setup_req *); 1223 req->hdr.type = NG_HCI_CMD_PKT; 1224 req->hdr.length = sizeof(req->cp); 1225 req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY, 1226 NG_HCI_OCF_QOS_SETUP)); 1227 1228 req->cp.con_handle = htole16(ep->con_handle); 1229 req->cp.flags = ep->flags; 1230 req->cp.service_type = ep->service_type; 1231 req->cp.token_rate = htole32(ep->token_rate); 1232 req->cp.peak_bandwidth = htole32(ep->peak_bandwidth); 1233 req->cp.latency = htole32(ep->latency); 1234 req->cp.delay_variation = htole32(ep->delay_variation); 1235 1236 /* 1237 * Adjust connection state 1238 */ 1239 1240 if (hook == unit->acl) 1241 con->flags |= NG_HCI_CON_NOTIFY_ACL; 1242 else 1243 con->flags |= NG_HCI_CON_NOTIFY_SCO; 1244 1245 /* 1246 * Queue and send HCI command 1247 */ 1248 1249 NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); 1250 if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) 1251 error = ng_hci_send_command(unit); 1252 out: 1253 NG_FREE_ITEM(item); 1254 1255 return (error); 1256 } /* ng_hci_lp_qos_req */ 1257 1258 /* 1259 * Send LP_QoSCfm event to the upper layer protocol 1260 */ 1261 1262 int 1263 ng_hci_lp_qos_cfm(ng_hci_unit_con_p con, int status) 1264 { 1265 ng_hci_unit_p unit = con->unit; 1266 struct ng_mesg *msg = NULL; 1267 ng_hci_lp_qos_cfm_ep *ep = NULL; 1268 int error; 1269 1270 if (con->flags & NG_HCI_CON_NOTIFY_ACL) { 1271 if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) { 1272 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_CFM, 1273 sizeof(*ep), M_NOWAIT); 1274 if (msg != NULL) { 1275 ep = (ng_hci_lp_qos_cfm_ep *) msg->data; 1276 ep->status = status; 1277 ep->con_handle = con->con_handle; 1278 1279 NG_SEND_MSG_HOOK(error, unit->node, msg, 1280 unit->acl, 0); 1281 } 1282 } else 1283 NG_HCI_INFO( 1284 "%s: %s - ACL hook not valid, hook=%p\n", 1285 __func__, NG_NODE_NAME(unit->node), unit->acl); 1286 1287 con->flags &= ~NG_HCI_CON_NOTIFY_ACL; 1288 } 1289 1290 if (con->flags & NG_HCI_CON_NOTIFY_SCO) { 1291 if (unit->sco != NULL && NG_HOOK_IS_VALID(unit->sco)) { 1292 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_CFM, 1293 sizeof(*ep), M_NOWAIT); 1294 if (msg != NULL) { 1295 ep = (ng_hci_lp_qos_cfm_ep *) msg->data; 1296 ep->status = status; 1297 ep->con_handle = con->con_handle; 1298 1299 NG_SEND_MSG_HOOK(error, unit->node, msg, 1300 unit->sco, 0); 1301 } 1302 } else 1303 NG_HCI_INFO( 1304 "%s: %s - SCO hook not valid, hook=%p\n", 1305 __func__, NG_NODE_NAME(unit->node), unit->sco); 1306 1307 con->flags &= ~NG_HCI_CON_NOTIFY_SCO; 1308 } 1309 1310 return (0); 1311 } /* ng_hci_lp_qos_cfm */ 1312 1313 /* 1314 * Send LP_QoSViolationInd event to the upper layer protocol 1315 */ 1316 1317 int 1318 ng_hci_lp_qos_ind(ng_hci_unit_con_p con) 1319 { 1320 ng_hci_unit_p unit = con->unit; 1321 struct ng_mesg *msg = NULL; 1322 ng_hci_lp_qos_ind_ep *ep = NULL; 1323 int error; 1324 1325 /* 1326 * QoS Violation can only be generated for ACL connection handles. 1327 * Both ACL and SCO upstream hooks will receive notification. 1328 */ 1329 1330 if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) { 1331 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_IND, 1332 sizeof(*ep), M_NOWAIT); 1333 if (msg == NULL) 1334 return (ENOMEM); 1335 1336 ep = (ng_hci_lp_qos_ind_ep *) msg->data; 1337 ep->con_handle = con->con_handle; 1338 1339 NG_SEND_MSG_HOOK(error, unit->node, msg, unit->acl, 0); 1340 } else 1341 NG_HCI_INFO( 1342 "%s: %s - ACL hook is not connected or not valid, hook=%p\n", 1343 __func__, NG_NODE_NAME(unit->node), unit->acl); 1344 1345 if (unit->sco != NULL && NG_HOOK_IS_VALID(unit->sco)) { 1346 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_IND, 1347 sizeof(*ep), M_NOWAIT); 1348 if (msg == NULL) 1349 return (ENOMEM); 1350 1351 ep = (ng_hci_lp_qos_ind_ep *) msg->data; 1352 ep->con_handle = con->con_handle; 1353 1354 NG_SEND_MSG_HOOK(error, unit->node, msg, unit->sco, 0); 1355 } else 1356 NG_HCI_INFO( 1357 "%s: %s - SCO hook is not connected or not valid, hook=%p\n", 1358 __func__, NG_NODE_NAME(unit->node), unit->sco); 1359 1360 return (0); 1361 } /* ng_hci_lp_qos_ind */ 1362 1363 /* 1364 * Process connection timeout 1365 */ 1366 1367 void 1368 ng_hci_process_con_timeout(node_p node, hook_p hook, void *arg1, int con_handle) 1369 { 1370 ng_hci_unit_p unit = NULL; 1371 ng_hci_unit_con_p con = NULL; 1372 1373 if (NG_NODE_NOT_VALID(node)) { 1374 printf("%s: Netgraph node is not valid\n", __func__); 1375 return; 1376 } 1377 1378 unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node); 1379 con = ng_hci_con_by_handle(unit, con_handle); 1380 1381 if (con == NULL) { 1382 NG_HCI_ALERT( 1383 "%s: %s - could not find connection, handle=%d\n", 1384 __func__, NG_NODE_NAME(node), con_handle); 1385 return; 1386 } 1387 1388 if (!(con->flags & NG_HCI_CON_TIMEOUT_PENDING)) { 1389 NG_HCI_ALERT( 1390 "%s: %s - no pending connection timeout, handle=%d, state=%d, flags=%#x\n", 1391 __func__, NG_NODE_NAME(node), con_handle, con->state, 1392 con->flags); 1393 return; 1394 } 1395 1396 con->flags &= ~NG_HCI_CON_TIMEOUT_PENDING; 1397 1398 /* 1399 * We expect to receive connection timeout in one of the following 1400 * states: 1401 * 1402 * 1) NG_HCI_CON_W4_LP_CON_RSP means that upper layer has not responded 1403 * to our LP_CON_IND. Do nothing and destroy connection. Remote peer 1404 * most likely already gave up on us. 1405 * 1406 * 2) NG_HCI_CON_W4_CONN_COMPLETE means upper layer requested connection 1407 * (or we in the process of accepting it) and baseband has timedout 1408 * on us. Inform upper layers and send LP_CON_CFM. 1409 */ 1410 1411 switch (con->state) { 1412 case NG_HCI_CON_W4_LP_CON_RSP: 1413 break; 1414 1415 case NG_HCI_CON_W4_CONN_COMPLETE: 1416 ng_hci_lp_con_cfm(con, 0xee); 1417 break; 1418 1419 default: 1420 panic( 1421 "%s: %s - Invalid connection state=%d\n", 1422 __func__, NG_NODE_NAME(node), con->state); 1423 break; 1424 } 1425 1426 ng_hci_free_con(con); 1427 } /* ng_hci_process_con_timeout */ 1428