1 /* 2 * ng_hci_ulpi.c 3 */ 4 5 /*- 6 * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com> 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * $Id: ng_hci_ulpi.c,v 1.7 2003/09/08 18:57:51 max Exp $ 31 * $FreeBSD$ 32 */ 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kernel.h> 37 #include <sys/endian.h> 38 #include <sys/malloc.h> 39 #include <sys/mbuf.h> 40 #include <sys/queue.h> 41 #include <netgraph/ng_message.h> 42 #include <netgraph/netgraph.h> 43 #include <netgraph/bluetooth/include/ng_bluetooth.h> 44 #include <netgraph/bluetooth/include/ng_hci.h> 45 #include <netgraph/bluetooth/hci/ng_hci_var.h> 46 #include <netgraph/bluetooth/hci/ng_hci_cmds.h> 47 #include <netgraph/bluetooth/hci/ng_hci_evnt.h> 48 #include <netgraph/bluetooth/hci/ng_hci_ulpi.h> 49 #include <netgraph/bluetooth/hci/ng_hci_misc.h> 50 51 /****************************************************************************** 52 ****************************************************************************** 53 ** Upper Layer Protocol Interface module 54 ****************************************************************************** 55 ******************************************************************************/ 56 57 static int ng_hci_lp_acl_con_req (ng_hci_unit_p, item_p, hook_p); 58 static int ng_hci_lp_sco_con_req (ng_hci_unit_p, item_p, hook_p); 59 static int ng_hci_lp_le_con_req (ng_hci_unit_p, item_p, hook_p, int); 60 61 /* 62 * Process LP_ConnectReq event from the upper layer protocol 63 */ 64 65 int 66 ng_hci_lp_con_req(ng_hci_unit_p unit, item_p item, hook_p hook) 67 { 68 int link_type; 69 70 if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) { 71 NG_HCI_WARN( 72 "%s: %s - unit is not ready, state=%#x\n", 73 __func__, NG_NODE_NAME(unit->node), unit->state); 74 75 NG_FREE_ITEM(item); 76 77 return (ENXIO); 78 } 79 80 if (NGI_MSG(item)->header.arglen != sizeof(ng_hci_lp_con_req_ep)) { 81 NG_HCI_ALERT( 82 "%s: %s - invalid LP_ConnectReq message size=%d\n", 83 __func__, NG_NODE_NAME(unit->node), 84 NGI_MSG(item)->header.arglen); 85 86 NG_FREE_ITEM(item); 87 88 return (EMSGSIZE); 89 } 90 link_type = ((ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data))->link_type; 91 switch(link_type){ 92 case NG_HCI_LINK_ACL: 93 return (ng_hci_lp_acl_con_req(unit, item, hook)); 94 case NG_HCI_LINK_SCO: 95 if (hook != unit->sco ) { 96 NG_HCI_WARN( 97 "%s: %s - LP_ConnectReq for SCO connection came from wrong hook=%p\n", 98 __func__, NG_NODE_NAME(unit->node), hook); 99 100 NG_FREE_ITEM(item); 101 102 return (EINVAL); 103 } 104 105 return (ng_hci_lp_sco_con_req(unit, item, hook)); 106 case NG_HCI_LINK_LE_PUBLIC: 107 case NG_HCI_LINK_LE_RANDOM: 108 return (ng_hci_lp_le_con_req(unit, item, hook, link_type)); 109 default: 110 panic("%s: link_type invalid.", __func__); 111 } 112 113 return (EINVAL); 114 } /* ng_hci_lp_con_req */ 115 116 /* 117 * Request to create new ACL connection 118 */ 119 120 static int 121 ng_hci_lp_acl_con_req(ng_hci_unit_p unit, item_p item, hook_p hook) 122 { 123 struct acl_con_req { 124 ng_hci_cmd_pkt_t hdr; 125 ng_hci_create_con_cp cp; 126 } __attribute__ ((packed)) *req = NULL; 127 ng_hci_lp_con_req_ep *ep = NULL; 128 ng_hci_unit_con_p con = NULL; 129 ng_hci_neighbor_t *n = NULL; 130 struct mbuf *m = NULL; 131 int error = 0; 132 133 ep = (ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data); 134 135 /* 136 * Only one ACL connection can exist between each pair of units. 137 * So try to find ACL connection descriptor (in any state) that 138 * has requested remote BD_ADDR. 139 * 140 * Two cases: 141 * 142 * 1) We do not have connection to the remote unit. This is simple. 143 * Just create new connection descriptor and send HCI command to 144 * create new connection. 145 * 146 * 2) We do have connection descriptor. We need to check connection 147 * state: 148 * 149 * 2.1) NG_HCI_CON_W4_LP_CON_RSP means that we are in the middle of 150 * accepting connection from the remote unit. This is a race 151 * condition. We will ignore this message. 152 * 153 * 2.2) NG_HCI_CON_W4_CONN_COMPLETE means that upper layer already 154 * requested connection or we just accepted it. In any case 155 * all we need to do here is set appropriate notification bit 156 * and wait. 157 * 158 * 2.3) NG_HCI_CON_OPEN means connection is open. Just reply back 159 * and let upper layer know that we have connection already. 160 */ 161 162 con = ng_hci_con_by_bdaddr(unit, &ep->bdaddr, NG_HCI_LINK_ACL); 163 if (con != NULL) { 164 switch (con->state) { 165 case NG_HCI_CON_W4_LP_CON_RSP: /* XXX */ 166 error = EALREADY; 167 break; 168 169 case NG_HCI_CON_W4_CONN_COMPLETE: 170 if (hook == unit->acl) 171 con->flags |= NG_HCI_CON_NOTIFY_ACL; 172 else 173 con->flags |= NG_HCI_CON_NOTIFY_SCO; 174 break; 175 176 case NG_HCI_CON_OPEN: { 177 struct ng_mesg *msg = NULL; 178 ng_hci_lp_con_cfm_ep *cfm = NULL; 179 180 if (hook != NULL && NG_HOOK_IS_VALID(hook)) { 181 NGI_GET_MSG(item, msg); 182 NG_FREE_MSG(msg); 183 184 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, 185 NGM_HCI_LP_CON_CFM, sizeof(*cfm), 186 M_NOWAIT); 187 if (msg != NULL) { 188 cfm = (ng_hci_lp_con_cfm_ep *)msg->data; 189 cfm->status = 0; 190 cfm->link_type = con->link_type; 191 cfm->con_handle = con->con_handle; 192 bcopy(&con->bdaddr, &cfm->bdaddr, 193 sizeof(cfm->bdaddr)); 194 195 /* 196 * This will forward item back to 197 * sender and set item to NULL 198 */ 199 200 _NGI_MSG(item) = msg; 201 NG_FWD_ITEM_HOOK(error, item, hook); 202 } else 203 error = ENOMEM; 204 } else 205 NG_HCI_INFO( 206 "%s: %s - Source hook is not valid, hook=%p\n", 207 __func__, NG_NODE_NAME(unit->node), 208 hook); 209 } break; 210 211 default: 212 panic( 213 "%s: %s - Invalid connection state=%d\n", 214 __func__, NG_NODE_NAME(unit->node), con->state); 215 break; 216 } 217 218 goto out; 219 } 220 221 /* 222 * If we got here then we need to create new ACL connection descriptor 223 * and submit HCI command. First create new connection desriptor, set 224 * bdaddr and notification flags. 225 */ 226 227 con = ng_hci_new_con(unit, NG_HCI_LINK_ACL); 228 if (con == NULL) { 229 error = ENOMEM; 230 goto out; 231 } 232 233 bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr)); 234 235 /* 236 * Create HCI command 237 */ 238 239 MGETHDR(m, M_NOWAIT, MT_DATA); 240 if (m == NULL) { 241 ng_hci_free_con(con); 242 error = ENOBUFS; 243 goto out; 244 } 245 246 m->m_pkthdr.len = m->m_len = sizeof(*req); 247 req = mtod(m, struct acl_con_req *); 248 req->hdr.type = NG_HCI_CMD_PKT; 249 req->hdr.length = sizeof(req->cp); 250 req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, 251 NG_HCI_OCF_CREATE_CON)); 252 253 bcopy(&ep->bdaddr, &req->cp.bdaddr, sizeof(req->cp.bdaddr)); 254 255 req->cp.pkt_type = (NG_HCI_PKT_DM1|NG_HCI_PKT_DH1); 256 if (unit->features[0] & NG_HCI_LMP_3SLOT) 257 req->cp.pkt_type |= (NG_HCI_PKT_DM3|NG_HCI_PKT_DH3); 258 if (unit->features[0] & NG_HCI_LMP_5SLOT) 259 req->cp.pkt_type |= (NG_HCI_PKT_DM5|NG_HCI_PKT_DH5); 260 261 req->cp.pkt_type &= unit->packet_mask; 262 if ((req->cp.pkt_type & (NG_HCI_PKT_DM1|NG_HCI_PKT_DH1| 263 NG_HCI_PKT_DM3|NG_HCI_PKT_DH3| 264 NG_HCI_PKT_DM5|NG_HCI_PKT_DH5)) == 0) 265 req->cp.pkt_type = (NG_HCI_PKT_DM1|NG_HCI_PKT_DH1); 266 267 req->cp.pkt_type = htole16(req->cp.pkt_type); 268 269 if ((unit->features[0] & NG_HCI_LMP_SWITCH) && unit->role_switch) 270 req->cp.accept_role_switch = 1; 271 else 272 req->cp.accept_role_switch = 0; 273 274 /* 275 * We may speed up connect by specifying valid parameters. 276 * So check the neighbor cache. 277 */ 278 279 n = ng_hci_get_neighbor(unit, &ep->bdaddr, NG_HCI_LINK_ACL); 280 if (n == NULL) { 281 req->cp.page_scan_rep_mode = 0; 282 req->cp.page_scan_mode = 0; 283 req->cp.clock_offset = 0; 284 } else { 285 req->cp.page_scan_rep_mode = n->page_scan_rep_mode; 286 req->cp.page_scan_mode = n->page_scan_mode; 287 req->cp.clock_offset = htole16(n->clock_offset); 288 } 289 290 /* 291 * Adust connection state 292 */ 293 294 if (hook == unit->acl) 295 con->flags |= NG_HCI_CON_NOTIFY_ACL; 296 else 297 con->flags |= NG_HCI_CON_NOTIFY_SCO; 298 299 con->state = NG_HCI_CON_W4_CONN_COMPLETE; 300 ng_hci_con_timeout(con); 301 302 /* 303 * Queue and send HCI command 304 */ 305 306 NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); 307 if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) 308 error = ng_hci_send_command(unit); 309 out: 310 if (item != NULL) 311 NG_FREE_ITEM(item); 312 313 return (error); 314 } /* ng_hci_lp_acl_con_req */ 315 316 /* 317 * Request to create new SCO connection 318 */ 319 320 static int 321 ng_hci_lp_sco_con_req(ng_hci_unit_p unit, item_p item, hook_p hook) 322 { 323 struct sco_con_req { 324 ng_hci_cmd_pkt_t hdr; 325 ng_hci_add_sco_con_cp cp; 326 } __attribute__ ((packed)) *req = NULL; 327 ng_hci_lp_con_req_ep *ep = NULL; 328 ng_hci_unit_con_p acl_con = NULL, sco_con = NULL; 329 struct mbuf *m = NULL; 330 int error = 0; 331 332 ep = (ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data); 333 334 /* 335 * SCO connection without ACL link 336 * 337 * If upper layer requests SCO connection and there is no open ACL 338 * connection to the desired remote unit, we will reject the request. 339 */ 340 341 LIST_FOREACH(acl_con, &unit->con_list, next) 342 if (acl_con->link_type == NG_HCI_LINK_ACL && 343 acl_con->state == NG_HCI_CON_OPEN && 344 bcmp(&acl_con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0) 345 break; 346 347 if (acl_con == NULL) { 348 NG_HCI_INFO( 349 "%s: %s - No open ACL connection to bdaddr=%x:%x:%x:%x:%x:%x\n", 350 __func__, NG_NODE_NAME(unit->node), 351 ep->bdaddr.b[5], ep->bdaddr.b[4], ep->bdaddr.b[3], 352 ep->bdaddr.b[2], ep->bdaddr.b[1], ep->bdaddr.b[0]); 353 354 error = ENOENT; 355 goto out; 356 } 357 358 /* 359 * Multiple SCO connections can exist between the same pair of units. 360 * We assume that multiple SCO connections have to be opened one after 361 * another. 362 * 363 * Try to find SCO connection descriptor that matches the following: 364 * 365 * 1) sco_con->link_type == NG_HCI_LINK_SCO 366 * 367 * 2) sco_con->state == NG_HCI_CON_W4_LP_CON_RSP || 368 * sco_con->state == NG_HCI_CON_W4_CONN_COMPLETE 369 * 370 * 3) sco_con->bdaddr == ep->bdaddr 371 * 372 * Two cases: 373 * 374 * 1) We do not have connection descriptor. This is simple. Just 375 * create new connection and submit Add_SCO_Connection command. 376 * 377 * 2) We do have connection descriptor. We need to check the state. 378 * 379 * 2.1) NG_HCI_CON_W4_LP_CON_RSP means we in the middle of accepting 380 * connection from the remote unit. This is a race condition and 381 * we will ignore the request. 382 * 383 * 2.2) NG_HCI_CON_W4_CONN_COMPLETE means upper layer already requested 384 * connection or we just accepted it. 385 */ 386 387 LIST_FOREACH(sco_con, &unit->con_list, next) 388 if (sco_con->link_type == NG_HCI_LINK_SCO && 389 (sco_con->state == NG_HCI_CON_W4_LP_CON_RSP || 390 sco_con->state == NG_HCI_CON_W4_CONN_COMPLETE) && 391 bcmp(&sco_con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0) 392 break; 393 394 if (sco_con != NULL) { 395 switch (sco_con->state) { 396 case NG_HCI_CON_W4_LP_CON_RSP: /* XXX */ 397 error = EALREADY; 398 break; 399 400 case NG_HCI_CON_W4_CONN_COMPLETE: 401 sco_con->flags |= NG_HCI_CON_NOTIFY_SCO; 402 break; 403 404 default: 405 panic( 406 "%s: %s - Invalid connection state=%d\n", 407 __func__, NG_NODE_NAME(unit->node), 408 sco_con->state); 409 break; 410 } 411 412 goto out; 413 } 414 415 /* 416 * If we got here then we need to create new SCO connection descriptor 417 * and submit HCI command. 418 */ 419 420 sco_con = ng_hci_new_con(unit, NG_HCI_LINK_SCO); 421 if (sco_con == NULL) { 422 error = ENOMEM; 423 goto out; 424 } 425 426 bcopy(&ep->bdaddr, &sco_con->bdaddr, sizeof(sco_con->bdaddr)); 427 428 /* 429 * Create HCI command 430 */ 431 432 MGETHDR(m, M_NOWAIT, MT_DATA); 433 if (m == NULL) { 434 ng_hci_free_con(sco_con); 435 error = ENOBUFS; 436 goto out; 437 } 438 439 m->m_pkthdr.len = m->m_len = sizeof(*req); 440 req = mtod(m, struct sco_con_req *); 441 req->hdr.type = NG_HCI_CMD_PKT; 442 req->hdr.length = sizeof(req->cp); 443 req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, 444 NG_HCI_OCF_ADD_SCO_CON)); 445 446 req->cp.con_handle = htole16(acl_con->con_handle); 447 448 req->cp.pkt_type = NG_HCI_PKT_HV1; 449 if (unit->features[1] & NG_HCI_LMP_HV2_PKT) 450 req->cp.pkt_type |= NG_HCI_PKT_HV2; 451 if (unit->features[1] & NG_HCI_LMP_HV3_PKT) 452 req->cp.pkt_type |= NG_HCI_PKT_HV3; 453 454 req->cp.pkt_type &= unit->packet_mask; 455 if ((req->cp.pkt_type & (NG_HCI_PKT_HV1| 456 NG_HCI_PKT_HV2| 457 NG_HCI_PKT_HV3)) == 0) 458 req->cp.pkt_type = NG_HCI_PKT_HV1; 459 460 req->cp.pkt_type = htole16(req->cp.pkt_type); 461 462 /* 463 * Adust connection state 464 */ 465 466 sco_con->flags |= NG_HCI_CON_NOTIFY_SCO; 467 468 sco_con->state = NG_HCI_CON_W4_CONN_COMPLETE; 469 ng_hci_con_timeout(sco_con); 470 471 /* 472 * Queue and send HCI command 473 */ 474 475 NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); 476 if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) 477 error = ng_hci_send_command(unit); 478 out: 479 NG_FREE_ITEM(item); 480 481 return (error); 482 } /* ng_hci_lp_sco_con_req */ 483 484 static int 485 ng_hci_lp_le_con_req(ng_hci_unit_p unit, item_p item, hook_p hook, int link_type) 486 { 487 struct acl_con_req { 488 ng_hci_cmd_pkt_t hdr; 489 ng_hci_le_create_connection_cp cp; 490 } __attribute__ ((packed)) *req = NULL; 491 ng_hci_lp_con_req_ep *ep = NULL; 492 ng_hci_unit_con_p con = NULL; 493 struct mbuf *m = NULL; 494 int error = 0; 495 496 ep = (ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data); 497 if((link_type != NG_HCI_LINK_LE_PUBLIC)&& 498 (link_type != NG_HCI_LINK_LE_RANDOM)){ 499 printf("%s: Link type %d Cannot be here \n", __func__, 500 link_type); 501 } 502 /* 503 * Only one ACL connection can exist between each pair of units. 504 * So try to find ACL connection descriptor (in any state) that 505 * has requested remote BD_ADDR. 506 * 507 * Two cases: 508 * 509 * 1) We do not have connection to the remote unit. This is simple. 510 * Just create new connection descriptor and send HCI command to 511 * create new connection. 512 * 513 * 2) We do have connection descriptor. We need to check connection 514 * state: 515 * 516 * 2.1) NG_HCI_CON_W4_LP_CON_RSP means that we are in the middle of 517 * accepting connection from the remote unit. This is a race 518 * condition. We will ignore this message. 519 * 520 * 2.2) NG_HCI_CON_W4_CONN_COMPLETE means that upper layer already 521 * requested connection or we just accepted it. In any case 522 * all we need to do here is set appropriate notification bit 523 * and wait. 524 * 525 * 2.3) NG_HCI_CON_OPEN means connection is open. Just reply back 526 * and let upper layer know that we have connection already. 527 */ 528 529 con = ng_hci_con_by_bdaddr(unit, &ep->bdaddr, link_type); 530 if (con != NULL) { 531 switch (con->state) { 532 case NG_HCI_CON_W4_LP_CON_RSP: /* XXX */ 533 error = EALREADY; 534 break; 535 536 case NG_HCI_CON_W4_CONN_COMPLETE: 537 if (hook != unit->sco) 538 con->flags |= NG_HCI_CON_NOTIFY_ACL; 539 else 540 con->flags |= NG_HCI_CON_NOTIFY_SCO; 541 break; 542 543 case NG_HCI_CON_OPEN: { 544 struct ng_mesg *msg = NULL; 545 ng_hci_lp_con_cfm_ep *cfm = NULL; 546 547 if (hook != NULL && NG_HOOK_IS_VALID(hook)) { 548 NGI_GET_MSG(item, msg); 549 NG_FREE_MSG(msg); 550 551 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, 552 NGM_HCI_LP_CON_CFM, sizeof(*cfm), 553 M_NOWAIT); 554 if (msg != NULL) { 555 cfm = (ng_hci_lp_con_cfm_ep *)msg->data; 556 cfm->status = 0; 557 cfm->link_type = con->link_type; 558 cfm->con_handle = con->con_handle; 559 bcopy(&con->bdaddr, &cfm->bdaddr, 560 sizeof(cfm->bdaddr)); 561 562 /* 563 * This will forward item back to 564 * sender and set item to NULL 565 */ 566 567 _NGI_MSG(item) = msg; 568 NG_FWD_ITEM_HOOK(error, item, hook); 569 } else 570 error = ENOMEM; 571 } else 572 NG_HCI_INFO( 573 "%s: %s - Source hook is not valid, hook=%p\n", 574 __func__, NG_NODE_NAME(unit->node), 575 hook); 576 } break; 577 578 default: 579 panic( 580 "%s: %s - Invalid connection state=%d\n", 581 __func__, NG_NODE_NAME(unit->node), con->state); 582 break; 583 } 584 585 goto out; 586 } 587 588 /* 589 * If we got here then we need to create new ACL connection descriptor 590 * and submit HCI command. First create new connection desriptor, set 591 * bdaddr and notification flags. 592 */ 593 594 con = ng_hci_new_con(unit, link_type); 595 if (con == NULL) { 596 error = ENOMEM; 597 goto out; 598 } 599 600 bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr)); 601 602 /* 603 * Create HCI command 604 */ 605 606 MGETHDR(m, M_NOWAIT, MT_DATA); 607 if (m == NULL) { 608 ng_hci_free_con(con); 609 error = ENOBUFS; 610 goto out; 611 } 612 613 m->m_pkthdr.len = m->m_len = sizeof(*req); 614 req = mtod(m, struct acl_con_req *); 615 req->hdr.type = NG_HCI_CMD_PKT; 616 req->hdr.length = sizeof(req->cp); 617 req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LE, 618 NG_HCI_OCF_LE_CREATE_CONNECTION)); 619 620 bcopy(&ep->bdaddr, &req->cp.peer_addr, sizeof(req->cp.peer_addr)); 621 req->cp.own_address_type = 0; 622 req->cp.peer_addr_type = (link_type == NG_HCI_LINK_LE_RANDOM)? 1:0; 623 req->cp.scan_interval = htole16(4); 624 req->cp.scan_window = htole16(4); 625 req->cp.filter_policy = 0; 626 req->cp.conn_interval_min = htole16(0xf); 627 req->cp.conn_interval_max = htole16(0xf); 628 req->cp.conn_latency = htole16(0); 629 req->cp.supervision_timeout = htole16(0xc80); 630 req->cp.min_ce_length = htole16(1); 631 req->cp.max_ce_length = htole16(1); 632 /* 633 * Adust connection state 634 */ 635 636 if (hook != unit->sco) 637 con->flags |= NG_HCI_CON_NOTIFY_ACL; 638 else 639 con->flags |= NG_HCI_CON_NOTIFY_SCO; 640 641 con->state = NG_HCI_CON_W4_CONN_COMPLETE; 642 ng_hci_con_timeout(con); 643 644 /* 645 * Queue and send HCI command 646 */ 647 648 NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); 649 if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) 650 error = ng_hci_send_command(unit); 651 out: 652 if (item != NULL) 653 NG_FREE_ITEM(item); 654 655 return (error); 656 } /* ng_hci_lp_acl_con_req */ 657 658 /* 659 * Process LP_DisconnectReq event from the upper layer protocol 660 */ 661 662 int 663 ng_hci_lp_discon_req(ng_hci_unit_p unit, item_p item, hook_p hook) 664 { 665 struct discon_req { 666 ng_hci_cmd_pkt_t hdr; 667 ng_hci_discon_cp cp; 668 } __attribute__ ((packed)) *req = NULL; 669 ng_hci_lp_discon_req_ep *ep = NULL; 670 ng_hci_unit_con_p con = NULL; 671 struct mbuf *m = NULL; 672 int error = 0; 673 674 /* Check if unit is ready */ 675 if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) { 676 NG_HCI_WARN( 677 "%s: %s - unit is not ready, state=%#x\n", 678 __func__, NG_NODE_NAME(unit->node), unit->state); 679 680 error = ENXIO; 681 goto out; 682 } 683 684 if (NGI_MSG(item)->header.arglen != sizeof(*ep)) { 685 NG_HCI_ALERT( 686 "%s: %s - invalid LP_DisconnectReq message size=%d\n", 687 __func__, NG_NODE_NAME(unit->node), 688 NGI_MSG(item)->header.arglen); 689 690 error = EMSGSIZE; 691 goto out; 692 } 693 694 ep = (ng_hci_lp_discon_req_ep *)(NGI_MSG(item)->data); 695 696 con = ng_hci_con_by_handle(unit, ep->con_handle); 697 if (con == NULL) { 698 NG_HCI_ERR( 699 "%s: %s - invalid connection handle=%d\n", 700 __func__, NG_NODE_NAME(unit->node), ep->con_handle); 701 702 error = ENOENT; 703 goto out; 704 } 705 706 if (con->state != NG_HCI_CON_OPEN) { 707 NG_HCI_ERR( 708 "%s: %s - invalid connection state=%d, handle=%d\n", 709 __func__, NG_NODE_NAME(unit->node), con->state, 710 ep->con_handle); 711 712 error = EINVAL; 713 goto out; 714 } 715 716 /* 717 * Create HCI command 718 */ 719 720 MGETHDR(m, M_NOWAIT, MT_DATA); 721 if (m == NULL) { 722 error = ENOBUFS; 723 goto out; 724 } 725 726 m->m_pkthdr.len = m->m_len = sizeof(*req); 727 req = mtod(m, struct discon_req *); 728 req->hdr.type = NG_HCI_CMD_PKT; 729 req->hdr.length = sizeof(req->cp); 730 req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL, 731 NG_HCI_OCF_DISCON)); 732 733 req->cp.con_handle = htole16(ep->con_handle); 734 req->cp.reason = ep->reason; 735 736 /* 737 * Queue and send HCI command 738 */ 739 740 NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m); 741 if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING)) 742 error = ng_hci_send_command(unit); 743 out: 744 NG_FREE_ITEM(item); 745 746 return (error); 747 } /* ng_hci_lp_discon_req */ 748 749 /* 750 * Send LP_ConnectCfm event to the upper layer protocol 751 */ 752 753 int 754 ng_hci_lp_con_cfm(ng_hci_unit_con_p con, int status) 755 { 756 ng_hci_unit_p unit = con->unit; 757 struct ng_mesg *msg = NULL; 758 ng_hci_lp_con_cfm_ep *ep = NULL; 759 int error; 760 761 /* 762 * Check who wants to be notified. For ACL links both ACL and SCO 763 * upstream hooks will be notified (if required). For SCO links 764 * only SCO upstream hook will receive notification 765 */ 766 767 if (con->link_type != NG_HCI_LINK_SCO && 768 con->flags & NG_HCI_CON_NOTIFY_ACL) { 769 if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) { 770 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_CFM, 771 sizeof(*ep), M_NOWAIT); 772 if (msg != NULL) { 773 ep = (ng_hci_lp_con_cfm_ep *) msg->data; 774 ep->status = status; 775 ep->link_type = con->link_type; 776 ep->con_handle = con->con_handle; 777 bcopy(&con->bdaddr, &ep->bdaddr, 778 sizeof(ep->bdaddr)); 779 780 NG_SEND_MSG_HOOK(error, unit->node, msg, 781 unit->acl, 0); 782 } 783 } else 784 NG_HCI_INFO( 785 "%s: %s - ACL hook not valid, hook=%p\n", 786 __func__, NG_NODE_NAME(unit->node), unit->acl); 787 788 con->flags &= ~NG_HCI_CON_NOTIFY_ACL; 789 } 790 791 if (con->flags & NG_HCI_CON_NOTIFY_SCO) { 792 if (unit->sco != NULL && NG_HOOK_IS_VALID(unit->sco)) { 793 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_CFM, 794 sizeof(*ep), M_NOWAIT); 795 if (msg != NULL) { 796 ep = (ng_hci_lp_con_cfm_ep *) msg->data; 797 ep->status = status; 798 ep->link_type = con->link_type; 799 ep->con_handle = con->con_handle; 800 bcopy(&con->bdaddr, &ep->bdaddr, 801 sizeof(ep->bdaddr)); 802 803 NG_SEND_MSG_HOOK(error, unit->node, msg, 804 unit->sco, 0); 805 } 806 } else 807 NG_HCI_INFO( 808 "%s: %s - SCO hook not valid, hook=%p\n", 809 __func__, NG_NODE_NAME(unit->node), unit->acl); 810 811 con->flags &= ~NG_HCI_CON_NOTIFY_SCO; 812 } 813 814 return (0); 815 } /* ng_hci_lp_con_cfm */ 816 817 int 818 ng_hci_lp_enc_change(ng_hci_unit_con_p con, int status) 819 { 820 ng_hci_unit_p unit = con->unit; 821 struct ng_mesg *msg = NULL; 822 ng_hci_lp_enc_change_ep *ep = NULL; 823 int error; 824 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 } 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 peform 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 1430