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