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 * $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 if (con->link_type != NG_HCI_LINK_SCO) { 828 if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) { 829 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_ENC_CHG, 830 sizeof(*ep), M_NOWAIT); 831 if (msg != NULL) { 832 ep = (ng_hci_lp_enc_change_ep *) msg->data; 833 ep->status = status; 834 ep->link_type = con->link_type; 835 ep->con_handle = con->con_handle; 836 837 NG_SEND_MSG_HOOK(error, unit->node, msg, 838 unit->acl, 0); 839 } 840 } else 841 NG_HCI_INFO( 842 "%s: %s - ACL hook not valid, hook=%p\n", 843 __func__, NG_NODE_NAME(unit->node), unit->acl); 844 } 845 return (0); 846 } /* ng_hci_lp_con_cfm */ 847 848 /* 849 * Send LP_ConnectInd event to the upper layer protocol 850 */ 851 852 int 853 ng_hci_lp_con_ind(ng_hci_unit_con_p con, u_int8_t *uclass) 854 { 855 ng_hci_unit_p unit = con->unit; 856 struct ng_mesg *msg = NULL; 857 ng_hci_lp_con_ind_ep *ep = NULL; 858 hook_p hook = NULL; 859 int error = 0; 860 861 /* 862 * Connection_Request event is generated for specific link type. 863 * Use link_type to select upstream hook. 864 */ 865 866 if (con->link_type != NG_HCI_LINK_SCO) 867 hook = unit->acl; 868 else 869 hook = unit->sco; 870 871 if (hook != NULL && NG_HOOK_IS_VALID(hook)) { 872 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_IND, 873 sizeof(*ep), M_NOWAIT); 874 if (msg == NULL) 875 return (ENOMEM); 876 877 ep = (ng_hci_lp_con_ind_ep *)(msg->data); 878 ep->link_type = con->link_type; 879 bcopy(uclass, ep->uclass, sizeof(ep->uclass)); 880 bcopy(&con->bdaddr, &ep->bdaddr, sizeof(ep->bdaddr)); 881 882 NG_SEND_MSG_HOOK(error, unit->node, msg, hook, 0); 883 } else { 884 NG_HCI_WARN( 885 "%s: %s - Upstream hook is not connected or not valid, hook=%p\n", 886 __func__, NG_NODE_NAME(unit->node), hook); 887 888 error = ENOTCONN; 889 } 890 891 return (error); 892 } /* ng_hci_lp_con_ind */ 893 894 /* 895 * Process LP_ConnectRsp event from the upper layer protocol 896 */ 897 898 int 899 ng_hci_lp_con_rsp(ng_hci_unit_p unit, item_p item, hook_p hook) 900 { 901 struct con_rsp_req { 902 ng_hci_cmd_pkt_t hdr; 903 union { 904 ng_hci_accept_con_cp acc; 905 ng_hci_reject_con_cp rej; 906 } __attribute__ ((packed)) cp; 907 } __attribute__ ((packed)) *req = NULL; 908 ng_hci_lp_con_rsp_ep *ep = NULL; 909 ng_hci_unit_con_p con = NULL; 910 struct mbuf *m = NULL; 911 int error = 0; 912 913 /* Check if unit is ready */ 914 if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) { 915 NG_HCI_WARN( 916 "%s: %s - unit is not ready, state=%#x\n", 917 __func__, NG_NODE_NAME(unit->node), unit->state); 918 919 error = ENXIO; 920 goto out; 921 } 922 923 if (NGI_MSG(item)->header.arglen != sizeof(*ep)) { 924 NG_HCI_ALERT( 925 "%s: %s - invalid LP_ConnectRsp message size=%d\n", 926 __func__, NG_NODE_NAME(unit->node), 927 NGI_MSG(item)->header.arglen); 928 929 error = EMSGSIZE; 930 goto out; 931 } 932 933 ep = (ng_hci_lp_con_rsp_ep *)(NGI_MSG(item)->data); 934 935 /* 936 * Here we have to deal with race. Upper layers might send conflicting 937 * requests. One might send Accept and other Reject. We will not try 938 * to solve all the problems, so first request will always win. 939 * 940 * Try to find connection that matches the following: 941 * 942 * 1) con->link_type == ep->link_type 943 * 944 * 2) con->state == NG_HCI_CON_W4_LP_CON_RSP || 945 * con->state == NG_HCI_CON_W4_CONN_COMPLETE 946 * 947 * 3) con->bdaddr == ep->bdaddr 948 * 949 * Two cases: 950 * 951 * 1) We do not have connection descriptor. Could be bogus request or 952 * we have rejected connection already. 953 * 954 * 2) We do have connection descriptor. Then we need to check state: 955 * 956 * 2.1) NG_HCI_CON_W4_LP_CON_RSP means upper layer has requested 957 * connection and it is a first response from the upper layer. 958 * if "status == 0" (Accept) then we will send Accept_Connection 959 * command and change connection state to W4_CONN_COMPLETE, else 960 * send reject and delete connection. 961 * 962 * 2.2) NG_HCI_CON_W4_CONN_COMPLETE means that we already accepted 963 * connection. If "status == 0" we just need to link request 964 * and wait, else ignore Reject request. 965 */ 966 967 LIST_FOREACH(con, &unit->con_list, next) 968 if (con->link_type == ep->link_type && 969 (con->state == NG_HCI_CON_W4_LP_CON_RSP || 970 con->state == NG_HCI_CON_W4_CONN_COMPLETE) && 971 bcmp(&con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0) 972 break; 973 974 if (con == NULL) { 975 /* Reject for non-existing connection is fine */ 976 error = (ep->status == 0)? ENOENT : 0; 977 goto out; 978 } 979 980 /* 981 * Remove connection timeout and check connection state. 982 * Note: if ng_hci_con_untimeout() fails (returns non-zero value) then 983 * timeout already happened and event went into node's queue. 984 */ 985 986 if ((error = ng_hci_con_untimeout(con)) != 0) 987 goto out; 988 989 switch (con->state) { 990 case NG_HCI_CON_W4_LP_CON_RSP: 991 992 /* 993 * Create HCI command 994 */ 995 996 MGETHDR(m, M_NOWAIT, MT_DATA); 997 if (m == NULL) { 998 error = ENOBUFS; 999 goto out; 1000 } 1001 1002 req = mtod(m, struct con_rsp_req *); 1003 req->hdr.type = NG_HCI_CMD_PKT; 1004 1005 if (ep->status == 0) { 1006 req->hdr.length = sizeof(req->cp.acc); 1007 req->hdr.opcode = htole16(NG_HCI_OPCODE( 1008 NG_HCI_OGF_LINK_CONTROL, 1009 NG_HCI_OCF_ACCEPT_CON)); 1010 1011 bcopy(&ep->bdaddr, &req->cp.acc.bdaddr, 1012 sizeof(req->cp.acc.bdaddr)); 1013 1014 /* 1015 * We are accepting connection, so if we support role 1016 * switch and role switch was enabled then set role to 1017 * NG_HCI_ROLE_MASTER and let LM perform role switch. 1018 * Otherwise we remain slave. In this case LM WILL NOT 1019 * perform role switch. 1020 */ 1021 1022 if ((unit->features[0] & NG_HCI_LMP_SWITCH) && 1023 unit->role_switch) 1024 req->cp.acc.role = NG_HCI_ROLE_MASTER; 1025 else 1026 req->cp.acc.role = NG_HCI_ROLE_SLAVE; 1027 1028 /* 1029 * Adjust connection state 1030 */ 1031 1032 if (hook == unit->acl) 1033 con->flags |= NG_HCI_CON_NOTIFY_ACL; 1034 else 1035 con->flags |= NG_HCI_CON_NOTIFY_SCO; 1036 1037 con->state = NG_HCI_CON_W4_CONN_COMPLETE; 1038 ng_hci_con_timeout(con); 1039 } else { 1040 req->hdr.length = sizeof(req->cp.rej); 1041 req->hdr.opcode = htole16(NG_HCI_OPCODE( 1042 NG_HCI_OGF_LINK_CONTROL, 1043 NG_HCI_OCF_REJECT_CON)); 1044 1045 bcopy(&ep->bdaddr, &req->cp.rej.bdaddr, 1046 sizeof(req->cp.rej.bdaddr)); 1047 1048 req->cp.rej.reason = ep->status; 1049 1050 /* 1051 * Free connection descritor 1052 * Item will be deleted just before return. 1053 */ 1054 1055 ng_hci_free_con(con); 1056 } 1057 1058 m->m_pkthdr.len = m->m_len = sizeof(req->hdr) + req->hdr.length; 1059 1060 /* Queue and send HCI command */ 1061 NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); 1062 if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) 1063 error = ng_hci_send_command(unit); 1064 break; 1065 1066 case NG_HCI_CON_W4_CONN_COMPLETE: 1067 if (ep->status == 0) { 1068 if (hook == unit->acl) 1069 con->flags |= NG_HCI_CON_NOTIFY_ACL; 1070 else 1071 con->flags |= NG_HCI_CON_NOTIFY_SCO; 1072 } else 1073 error = EPERM; 1074 break; 1075 1076 default: 1077 panic( 1078 "%s: %s - Invalid connection state=%d\n", 1079 __func__, NG_NODE_NAME(unit->node), con->state); 1080 break; 1081 } 1082 out: 1083 NG_FREE_ITEM(item); 1084 1085 return (error); 1086 } /* ng_hci_lp_con_rsp */ 1087 1088 /* 1089 * Send LP_DisconnectInd to the upper layer protocol 1090 */ 1091 1092 int 1093 ng_hci_lp_discon_ind(ng_hci_unit_con_p con, int reason) 1094 { 1095 ng_hci_unit_p unit = con->unit; 1096 struct ng_mesg *msg = NULL; 1097 ng_hci_lp_discon_ind_ep *ep = NULL; 1098 int error = 0; 1099 1100 /* 1101 * Disconnect_Complete event is generated for specific connection 1102 * handle. For ACL connection handles both ACL and SCO upstream 1103 * hooks will receive notification. For SCO connection handles 1104 * only SCO upstream hook will receive notification. 1105 */ 1106 1107 if (con->link_type != NG_HCI_LINK_SCO) { 1108 if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) { 1109 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, 1110 NGM_HCI_LP_DISCON_IND, sizeof(*ep), M_NOWAIT); 1111 if (msg == NULL) 1112 return (ENOMEM); 1113 1114 ep = (ng_hci_lp_discon_ind_ep *) msg->data; 1115 ep->reason = reason; 1116 ep->link_type = con->link_type; 1117 ep->con_handle = con->con_handle; 1118 1119 NG_SEND_MSG_HOOK(error,unit->node,msg,unit->acl,0); 1120 } else 1121 NG_HCI_INFO( 1122 "%s: %s - ACL hook is not connected or not valid, hook=%p\n", 1123 __func__, NG_NODE_NAME(unit->node), unit->acl); 1124 } 1125 1126 if (unit->sco != NULL && NG_HOOK_IS_VALID(unit->sco)) { 1127 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_DISCON_IND, 1128 sizeof(*ep), M_NOWAIT); 1129 if (msg == NULL) 1130 return (ENOMEM); 1131 1132 ep = (ng_hci_lp_discon_ind_ep *) msg->data; 1133 ep->reason = reason; 1134 ep->link_type = con->link_type; 1135 ep->con_handle = con->con_handle; 1136 1137 NG_SEND_MSG_HOOK(error, unit->node, msg, unit->sco, 0); 1138 } else 1139 NG_HCI_INFO( 1140 "%s: %s - SCO hook is not connected or not valid, hook=%p\n", 1141 __func__, NG_NODE_NAME(unit->node), unit->sco); 1142 1143 return (0); 1144 } /* ng_hci_lp_discon_ind */ 1145 1146 /* 1147 * Process LP_QoSReq action from the upper layer protocol 1148 */ 1149 1150 int 1151 ng_hci_lp_qos_req(ng_hci_unit_p unit, item_p item, hook_p hook) 1152 { 1153 struct qos_setup_req { 1154 ng_hci_cmd_pkt_t hdr; 1155 ng_hci_qos_setup_cp cp; 1156 } __attribute__ ((packed)) *req = NULL; 1157 ng_hci_lp_qos_req_ep *ep = NULL; 1158 ng_hci_unit_con_p con = NULL; 1159 struct mbuf *m = NULL; 1160 int error = 0; 1161 1162 /* Check if unit is ready */ 1163 if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) { 1164 NG_HCI_WARN( 1165 "%s: %s - unit is not ready, state=%#x\n", 1166 __func__, NG_NODE_NAME(unit->node), unit->state); 1167 1168 error = ENXIO; 1169 goto out; 1170 } 1171 1172 if (NGI_MSG(item)->header.arglen != sizeof(*ep)) { 1173 NG_HCI_ALERT( 1174 "%s: %s - invalid LP_QoSSetupReq message size=%d\n", 1175 __func__, NG_NODE_NAME(unit->node), 1176 NGI_MSG(item)->header.arglen); 1177 1178 error = EMSGSIZE; 1179 goto out; 1180 } 1181 1182 ep = (ng_hci_lp_qos_req_ep *)(NGI_MSG(item)->data); 1183 1184 con = ng_hci_con_by_handle(unit, ep->con_handle); 1185 if (con == NULL) { 1186 NG_HCI_ERR( 1187 "%s: %s - invalid connection handle=%d\n", 1188 __func__, NG_NODE_NAME(unit->node), ep->con_handle); 1189 1190 error = EINVAL; 1191 goto out; 1192 } 1193 1194 if (con->link_type != NG_HCI_LINK_ACL) { 1195 NG_HCI_ERR("%s: %s - invalid link type=%d\n", 1196 __func__, NG_NODE_NAME(unit->node), con->link_type); 1197 1198 error = EINVAL; 1199 goto out; 1200 } 1201 1202 if (con->state != NG_HCI_CON_OPEN) { 1203 NG_HCI_ERR( 1204 "%s: %s - invalid connection state=%d, handle=%d\n", 1205 __func__, NG_NODE_NAME(unit->node), con->state, 1206 con->con_handle); 1207 1208 error = EINVAL; 1209 goto out; 1210 } 1211 1212 /* 1213 * Create HCI command 1214 */ 1215 1216 MGETHDR(m, M_NOWAIT, MT_DATA); 1217 if (m == NULL) { 1218 error = ENOBUFS; 1219 goto out; 1220 } 1221 1222 m->m_pkthdr.len = m->m_len = sizeof(*req); 1223 req = mtod(m, struct qos_setup_req *); 1224 req->hdr.type = NG_HCI_CMD_PKT; 1225 req->hdr.length = sizeof(req->cp); 1226 req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY, 1227 NG_HCI_OCF_QOS_SETUP)); 1228 1229 req->cp.con_handle = htole16(ep->con_handle); 1230 req->cp.flags = ep->flags; 1231 req->cp.service_type = ep->service_type; 1232 req->cp.token_rate = htole32(ep->token_rate); 1233 req->cp.peak_bandwidth = htole32(ep->peak_bandwidth); 1234 req->cp.latency = htole32(ep->latency); 1235 req->cp.delay_variation = htole32(ep->delay_variation); 1236 1237 /* 1238 * Adjust connection state 1239 */ 1240 1241 if (hook == unit->acl) 1242 con->flags |= NG_HCI_CON_NOTIFY_ACL; 1243 else 1244 con->flags |= NG_HCI_CON_NOTIFY_SCO; 1245 1246 /* 1247 * Queue and send HCI command 1248 */ 1249 1250 NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); 1251 if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) 1252 error = ng_hci_send_command(unit); 1253 out: 1254 NG_FREE_ITEM(item); 1255 1256 return (error); 1257 } /* ng_hci_lp_qos_req */ 1258 1259 /* 1260 * Send LP_QoSCfm event to the upper layer protocol 1261 */ 1262 1263 int 1264 ng_hci_lp_qos_cfm(ng_hci_unit_con_p con, int status) 1265 { 1266 ng_hci_unit_p unit = con->unit; 1267 struct ng_mesg *msg = NULL; 1268 ng_hci_lp_qos_cfm_ep *ep = NULL; 1269 int error; 1270 1271 if (con->flags & NG_HCI_CON_NOTIFY_ACL) { 1272 if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) { 1273 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_CFM, 1274 sizeof(*ep), M_NOWAIT); 1275 if (msg != NULL) { 1276 ep = (ng_hci_lp_qos_cfm_ep *) msg->data; 1277 ep->status = status; 1278 ep->con_handle = con->con_handle; 1279 1280 NG_SEND_MSG_HOOK(error, unit->node, msg, 1281 unit->acl, 0); 1282 } 1283 } else 1284 NG_HCI_INFO( 1285 "%s: %s - ACL hook not valid, hook=%p\n", 1286 __func__, NG_NODE_NAME(unit->node), unit->acl); 1287 1288 con->flags &= ~NG_HCI_CON_NOTIFY_ACL; 1289 } 1290 1291 if (con->flags & NG_HCI_CON_NOTIFY_SCO) { 1292 if (unit->sco != NULL && NG_HOOK_IS_VALID(unit->sco)) { 1293 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_CFM, 1294 sizeof(*ep), M_NOWAIT); 1295 if (msg != NULL) { 1296 ep = (ng_hci_lp_qos_cfm_ep *) msg->data; 1297 ep->status = status; 1298 ep->con_handle = con->con_handle; 1299 1300 NG_SEND_MSG_HOOK(error, unit->node, msg, 1301 unit->sco, 0); 1302 } 1303 } else 1304 NG_HCI_INFO( 1305 "%s: %s - SCO hook not valid, hook=%p\n", 1306 __func__, NG_NODE_NAME(unit->node), unit->sco); 1307 1308 con->flags &= ~NG_HCI_CON_NOTIFY_SCO; 1309 } 1310 1311 return (0); 1312 } /* ng_hci_lp_qos_cfm */ 1313 1314 /* 1315 * Send LP_QoSViolationInd event to the upper layer protocol 1316 */ 1317 1318 int 1319 ng_hci_lp_qos_ind(ng_hci_unit_con_p con) 1320 { 1321 ng_hci_unit_p unit = con->unit; 1322 struct ng_mesg *msg = NULL; 1323 ng_hci_lp_qos_ind_ep *ep = NULL; 1324 int error; 1325 1326 /* 1327 * QoS Violation can only be generated for ACL connection handles. 1328 * Both ACL and SCO upstream hooks will receive notification. 1329 */ 1330 1331 if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) { 1332 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_IND, 1333 sizeof(*ep), M_NOWAIT); 1334 if (msg == NULL) 1335 return (ENOMEM); 1336 1337 ep = (ng_hci_lp_qos_ind_ep *) msg->data; 1338 ep->con_handle = con->con_handle; 1339 1340 NG_SEND_MSG_HOOK(error, unit->node, msg, unit->acl, 0); 1341 } else 1342 NG_HCI_INFO( 1343 "%s: %s - ACL hook is not connected or not valid, hook=%p\n", 1344 __func__, NG_NODE_NAME(unit->node), unit->acl); 1345 1346 if (unit->sco != NULL && NG_HOOK_IS_VALID(unit->sco)) { 1347 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_IND, 1348 sizeof(*ep), M_NOWAIT); 1349 if (msg == NULL) 1350 return (ENOMEM); 1351 1352 ep = (ng_hci_lp_qos_ind_ep *) msg->data; 1353 ep->con_handle = con->con_handle; 1354 1355 NG_SEND_MSG_HOOK(error, unit->node, msg, unit->sco, 0); 1356 } else 1357 NG_HCI_INFO( 1358 "%s: %s - SCO hook is not connected or not valid, hook=%p\n", 1359 __func__, NG_NODE_NAME(unit->node), unit->sco); 1360 1361 return (0); 1362 } /* ng_hci_lp_qos_ind */ 1363 1364 /* 1365 * Process connection timeout 1366 */ 1367 1368 void 1369 ng_hci_process_con_timeout(node_p node, hook_p hook, void *arg1, int con_handle) 1370 { 1371 ng_hci_unit_p unit = NULL; 1372 ng_hci_unit_con_p con = NULL; 1373 1374 if (NG_NODE_NOT_VALID(node)) { 1375 printf("%s: Netgraph node is not valid\n", __func__); 1376 return; 1377 } 1378 1379 unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node); 1380 con = ng_hci_con_by_handle(unit, con_handle); 1381 1382 if (con == NULL) { 1383 NG_HCI_ALERT( 1384 "%s: %s - could not find connection, handle=%d\n", 1385 __func__, NG_NODE_NAME(node), con_handle); 1386 return; 1387 } 1388 1389 if (!(con->flags & NG_HCI_CON_TIMEOUT_PENDING)) { 1390 NG_HCI_ALERT( 1391 "%s: %s - no pending connection timeout, handle=%d, state=%d, flags=%#x\n", 1392 __func__, NG_NODE_NAME(node), con_handle, con->state, 1393 con->flags); 1394 return; 1395 } 1396 1397 con->flags &= ~NG_HCI_CON_TIMEOUT_PENDING; 1398 1399 /* 1400 * We expect to receive connection timeout in one of the following 1401 * states: 1402 * 1403 * 1) NG_HCI_CON_W4_LP_CON_RSP means that upper layer has not responded 1404 * to our LP_CON_IND. Do nothing and destroy connection. Remote peer 1405 * most likely already gave up on us. 1406 * 1407 * 2) NG_HCI_CON_W4_CONN_COMPLETE means upper layer requested connection 1408 * (or we in the process of accepting it) and baseband has timedout 1409 * on us. Inform upper layers and send LP_CON_CFM. 1410 */ 1411 1412 switch (con->state) { 1413 case NG_HCI_CON_W4_LP_CON_RSP: 1414 break; 1415 1416 case NG_HCI_CON_W4_CONN_COMPLETE: 1417 ng_hci_lp_con_cfm(con, 0xee); 1418 break; 1419 1420 default: 1421 panic( 1422 "%s: %s - Invalid connection state=%d\n", 1423 __func__, NG_NODE_NAME(node), con->state); 1424 break; 1425 } 1426 1427 ng_hci_free_con(con); 1428 } /* ng_hci_process_con_timeout */ 1429