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