1 /* 2 * ng_btsocket_sco.c 3 */ 4 5 /*- 6 * Copyright (c) 2001-2002 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_btsocket_sco.c,v 1.2 2005/10/31 18:08:51 max Exp $ 31 * $FreeBSD$ 32 */ 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/bitstring.h> 37 #include <sys/domain.h> 38 #include <sys/endian.h> 39 #include <sys/errno.h> 40 #include <sys/filedesc.h> 41 #include <sys/ioccom.h> 42 #include <sys/kernel.h> 43 #include <sys/lock.h> 44 #include <sys/malloc.h> 45 #include <sys/mbuf.h> 46 #include <sys/mutex.h> 47 #include <sys/protosw.h> 48 #include <sys/queue.h> 49 #include <sys/socket.h> 50 #include <sys/socketvar.h> 51 #include <sys/sysctl.h> 52 #include <sys/taskqueue.h> 53 #include <netgraph/ng_message.h> 54 #include <netgraph/netgraph.h> 55 #include <netgraph/bluetooth/include/ng_bluetooth.h> 56 #include <netgraph/bluetooth/include/ng_hci.h> 57 #include <netgraph/bluetooth/include/ng_l2cap.h> 58 #include <netgraph/bluetooth/include/ng_btsocket.h> 59 #include <netgraph/bluetooth/include/ng_btsocket_sco.h> 60 61 /* MALLOC define */ 62 #ifdef NG_SEPARATE_MALLOC 63 MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_SCO, "netgraph_btsocks_sco", 64 "Netgraph Bluetooth SCO sockets"); 65 #else 66 #define M_NETGRAPH_BTSOCKET_SCO M_NETGRAPH 67 #endif /* NG_SEPARATE_MALLOC */ 68 69 /* Netgraph node methods */ 70 static ng_constructor_t ng_btsocket_sco_node_constructor; 71 static ng_rcvmsg_t ng_btsocket_sco_node_rcvmsg; 72 static ng_shutdown_t ng_btsocket_sco_node_shutdown; 73 static ng_newhook_t ng_btsocket_sco_node_newhook; 74 static ng_connect_t ng_btsocket_sco_node_connect; 75 static ng_rcvdata_t ng_btsocket_sco_node_rcvdata; 76 static ng_disconnect_t ng_btsocket_sco_node_disconnect; 77 78 static void ng_btsocket_sco_input (void *, int); 79 static void ng_btsocket_sco_rtclean (void *, int); 80 81 /* Netgraph type descriptor */ 82 static struct ng_type typestruct = { 83 .version = NG_ABI_VERSION, 84 .name = NG_BTSOCKET_SCO_NODE_TYPE, 85 .constructor = ng_btsocket_sco_node_constructor, 86 .rcvmsg = ng_btsocket_sco_node_rcvmsg, 87 .shutdown = ng_btsocket_sco_node_shutdown, 88 .newhook = ng_btsocket_sco_node_newhook, 89 .connect = ng_btsocket_sco_node_connect, 90 .rcvdata = ng_btsocket_sco_node_rcvdata, 91 .disconnect = ng_btsocket_sco_node_disconnect, 92 }; 93 94 /* Globals */ 95 static u_int32_t ng_btsocket_sco_debug_level; 96 static node_p ng_btsocket_sco_node; 97 static struct ng_bt_itemq ng_btsocket_sco_queue; 98 static struct mtx ng_btsocket_sco_queue_mtx; 99 static struct task ng_btsocket_sco_queue_task; 100 static struct mtx ng_btsocket_sco_sockets_mtx; 101 static LIST_HEAD(, ng_btsocket_sco_pcb) ng_btsocket_sco_sockets; 102 static LIST_HEAD(, ng_btsocket_sco_rtentry) ng_btsocket_sco_rt; 103 static struct mtx ng_btsocket_sco_rt_mtx; 104 static struct task ng_btsocket_sco_rt_task; 105 106 /* Sysctl tree */ 107 SYSCTL_DECL(_net_bluetooth_sco_sockets); 108 SYSCTL_NODE(_net_bluetooth_sco_sockets, OID_AUTO, seq, CTLFLAG_RW, 109 0, "Bluetooth SEQPACKET SCO sockets family"); 110 SYSCTL_INT(_net_bluetooth_sco_sockets_seq, OID_AUTO, debug_level, 111 CTLFLAG_RW, 112 &ng_btsocket_sco_debug_level, NG_BTSOCKET_WARN_LEVEL, 113 "Bluetooth SEQPACKET SCO sockets debug level"); 114 SYSCTL_INT(_net_bluetooth_sco_sockets_seq, OID_AUTO, queue_len, 115 CTLFLAG_RD, 116 &ng_btsocket_sco_queue.len, 0, 117 "Bluetooth SEQPACKET SCO sockets input queue length"); 118 SYSCTL_INT(_net_bluetooth_sco_sockets_seq, OID_AUTO, queue_maxlen, 119 CTLFLAG_RD, 120 &ng_btsocket_sco_queue.maxlen, 0, 121 "Bluetooth SEQPACKET SCO sockets input queue max. length"); 122 SYSCTL_INT(_net_bluetooth_sco_sockets_seq, OID_AUTO, queue_drops, 123 CTLFLAG_RD, 124 &ng_btsocket_sco_queue.drops, 0, 125 "Bluetooth SEQPACKET SCO sockets input queue drops"); 126 127 /* Debug */ 128 #define NG_BTSOCKET_SCO_INFO \ 129 if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_INFO_LEVEL) \ 130 printf 131 132 #define NG_BTSOCKET_SCO_WARN \ 133 if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_WARN_LEVEL) \ 134 printf 135 136 #define NG_BTSOCKET_SCO_ERR \ 137 if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_ERR_LEVEL) \ 138 printf 139 140 #define NG_BTSOCKET_SCO_ALERT \ 141 if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_ALERT_LEVEL) \ 142 printf 143 144 /* 145 * Netgraph message processing routines 146 */ 147 148 static int ng_btsocket_sco_process_lp_con_cfm 149 (struct ng_mesg *, ng_btsocket_sco_rtentry_p); 150 static int ng_btsocket_sco_process_lp_con_ind 151 (struct ng_mesg *, ng_btsocket_sco_rtentry_p); 152 static int ng_btsocket_sco_process_lp_discon_ind 153 (struct ng_mesg *, ng_btsocket_sco_rtentry_p); 154 155 /* 156 * Send LP messages to the lower layer 157 */ 158 159 static int ng_btsocket_sco_send_lp_con_req 160 (ng_btsocket_sco_pcb_p); 161 static int ng_btsocket_sco_send_lp_con_rsp 162 (ng_btsocket_sco_rtentry_p, bdaddr_p, int); 163 static int ng_btsocket_sco_send_lp_discon_req 164 (ng_btsocket_sco_pcb_p); 165 166 static int ng_btsocket_sco_send2 167 (ng_btsocket_sco_pcb_p); 168 169 /* 170 * Timeout processing routines 171 */ 172 173 static void ng_btsocket_sco_timeout (ng_btsocket_sco_pcb_p); 174 static void ng_btsocket_sco_untimeout (ng_btsocket_sco_pcb_p); 175 static void ng_btsocket_sco_process_timeout (void *); 176 177 /* 178 * Other stuff 179 */ 180 181 static ng_btsocket_sco_pcb_p ng_btsocket_sco_pcb_by_addr(bdaddr_p); 182 static ng_btsocket_sco_pcb_p ng_btsocket_sco_pcb_by_handle(bdaddr_p, int); 183 static ng_btsocket_sco_pcb_p ng_btsocket_sco_pcb_by_addrs(bdaddr_p, bdaddr_p); 184 185 #define ng_btsocket_sco_wakeup_input_task() \ 186 taskqueue_enqueue(taskqueue_swi, &ng_btsocket_sco_queue_task) 187 188 #define ng_btsocket_sco_wakeup_route_task() \ 189 taskqueue_enqueue(taskqueue_swi, &ng_btsocket_sco_rt_task) 190 191 /***************************************************************************** 192 ***************************************************************************** 193 ** Netgraph node interface 194 ***************************************************************************** 195 *****************************************************************************/ 196 197 /* 198 * Netgraph node constructor. Do not allow to create node of this type. 199 */ 200 201 static int 202 ng_btsocket_sco_node_constructor(node_p node) 203 { 204 return (EINVAL); 205 } /* ng_btsocket_sco_node_constructor */ 206 207 /* 208 * Do local shutdown processing. Let old node go and create new fresh one. 209 */ 210 211 static int 212 ng_btsocket_sco_node_shutdown(node_p node) 213 { 214 int error = 0; 215 216 NG_NODE_UNREF(node); 217 218 /* Create new node */ 219 error = ng_make_node_common(&typestruct, &ng_btsocket_sco_node); 220 if (error != 0) { 221 NG_BTSOCKET_SCO_ALERT( 222 "%s: Could not create Netgraph node, error=%d\n", __func__, error); 223 224 ng_btsocket_sco_node = NULL; 225 226 return (error); 227 } 228 229 error = ng_name_node(ng_btsocket_sco_node, 230 NG_BTSOCKET_SCO_NODE_TYPE); 231 if (error != 0) { 232 NG_BTSOCKET_SCO_ALERT( 233 "%s: Could not name Netgraph node, error=%d\n", __func__, error); 234 235 NG_NODE_UNREF(ng_btsocket_sco_node); 236 ng_btsocket_sco_node = NULL; 237 238 return (error); 239 } 240 241 return (0); 242 } /* ng_btsocket_sco_node_shutdown */ 243 244 /* 245 * We allow any hook to be connected to the node. 246 */ 247 248 static int 249 ng_btsocket_sco_node_newhook(node_p node, hook_p hook, char const *name) 250 { 251 return (0); 252 } /* ng_btsocket_sco_node_newhook */ 253 254 /* 255 * Just say "YEP, that's OK by me!" 256 */ 257 258 static int 259 ng_btsocket_sco_node_connect(hook_p hook) 260 { 261 NG_HOOK_SET_PRIVATE(hook, NULL); 262 NG_HOOK_REF(hook); /* Keep extra reference to the hook */ 263 264 #if 0 265 NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); 266 NG_HOOK_FORCE_QUEUE(hook); 267 #endif 268 269 return (0); 270 } /* ng_btsocket_sco_node_connect */ 271 272 /* 273 * Hook disconnection. Schedule route cleanup task 274 */ 275 276 static int 277 ng_btsocket_sco_node_disconnect(hook_p hook) 278 { 279 /* 280 * If hook has private information than we must have this hook in 281 * the routing table and must schedule cleaning for the routing table. 282 * Otherwise hook was connected but we never got "hook_info" message, 283 * so we have never added this hook to the routing table and it save 284 * to just delete it. 285 */ 286 287 if (NG_HOOK_PRIVATE(hook) != NULL) 288 return (ng_btsocket_sco_wakeup_route_task()); 289 290 NG_HOOK_UNREF(hook); /* Remove extra reference */ 291 292 return (0); 293 } /* ng_btsocket_sco_node_disconnect */ 294 295 /* 296 * Process incoming messages 297 */ 298 299 static int 300 ng_btsocket_sco_node_rcvmsg(node_p node, item_p item, hook_p hook) 301 { 302 struct ng_mesg *msg = NGI_MSG(item); /* item still has message */ 303 int error = 0; 304 305 if (msg != NULL && msg->header.typecookie == NGM_HCI_COOKIE) { 306 mtx_lock(&ng_btsocket_sco_queue_mtx); 307 if (NG_BT_ITEMQ_FULL(&ng_btsocket_sco_queue)) { 308 NG_BTSOCKET_SCO_ERR( 309 "%s: Input queue is full (msg)\n", __func__); 310 311 NG_BT_ITEMQ_DROP(&ng_btsocket_sco_queue); 312 NG_FREE_ITEM(item); 313 error = ENOBUFS; 314 } else { 315 if (hook != NULL) { 316 NG_HOOK_REF(hook); 317 NGI_SET_HOOK(item, hook); 318 } 319 320 NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_sco_queue, item); 321 error = ng_btsocket_sco_wakeup_input_task(); 322 } 323 mtx_unlock(&ng_btsocket_sco_queue_mtx); 324 } else { 325 NG_FREE_ITEM(item); 326 error = EINVAL; 327 } 328 329 return (error); 330 } /* ng_btsocket_sco_node_rcvmsg */ 331 332 /* 333 * Receive data on a hook 334 */ 335 336 static int 337 ng_btsocket_sco_node_rcvdata(hook_p hook, item_p item) 338 { 339 int error = 0; 340 341 mtx_lock(&ng_btsocket_sco_queue_mtx); 342 if (NG_BT_ITEMQ_FULL(&ng_btsocket_sco_queue)) { 343 NG_BTSOCKET_SCO_ERR( 344 "%s: Input queue is full (data)\n", __func__); 345 346 NG_BT_ITEMQ_DROP(&ng_btsocket_sco_queue); 347 NG_FREE_ITEM(item); 348 error = ENOBUFS; 349 } else { 350 NG_HOOK_REF(hook); 351 NGI_SET_HOOK(item, hook); 352 353 NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_sco_queue, item); 354 error = ng_btsocket_sco_wakeup_input_task(); 355 } 356 mtx_unlock(&ng_btsocket_sco_queue_mtx); 357 358 return (error); 359 } /* ng_btsocket_sco_node_rcvdata */ 360 361 /* 362 * Process LP_ConnectCfm event from the lower layer protocol 363 */ 364 365 static int 366 ng_btsocket_sco_process_lp_con_cfm(struct ng_mesg *msg, 367 ng_btsocket_sco_rtentry_p rt) 368 { 369 ng_hci_lp_con_cfm_ep *ep = NULL; 370 ng_btsocket_sco_pcb_t *pcb = NULL; 371 int error = 0; 372 373 if (msg->header.arglen != sizeof(*ep)) 374 return (EMSGSIZE); 375 376 ep = (ng_hci_lp_con_cfm_ep *)(msg->data); 377 378 mtx_lock(&ng_btsocket_sco_sockets_mtx); 379 380 /* Look for the socket with the token */ 381 pcb = ng_btsocket_sco_pcb_by_addrs(&rt->src, &ep->bdaddr); 382 if (pcb == NULL) { 383 mtx_unlock(&ng_btsocket_sco_sockets_mtx); 384 return (ENOENT); 385 } 386 387 /* pcb is locked */ 388 389 NG_BTSOCKET_SCO_INFO( 390 "%s: Got LP_ConnectCfm response, src bdaddr=%x:%x:%x:%x:%x:%x, " \ 391 "dst bdaddr=%x:%x:%x:%x:%x:%x, status=%d, handle=%d, state=%d\n", 392 __func__, 393 pcb->src.b[5], pcb->src.b[4], pcb->src.b[3], 394 pcb->src.b[2], pcb->src.b[1], pcb->src.b[0], 395 pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3], 396 pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0], 397 ep->status, ep->con_handle, pcb->state); 398 399 if (pcb->state != NG_BTSOCKET_SCO_CONNECTING) { 400 mtx_unlock(&pcb->pcb_mtx); 401 mtx_unlock(&ng_btsocket_sco_sockets_mtx); 402 403 return (ENOENT); 404 } 405 406 ng_btsocket_sco_untimeout(pcb); 407 408 if (ep->status == 0) { 409 /* 410 * Connection is open. Update connection handle and 411 * socket state 412 */ 413 414 pcb->con_handle = ep->con_handle; 415 pcb->state = NG_BTSOCKET_SCO_OPEN; 416 soisconnected(pcb->so); 417 } else { 418 /* 419 * We have failed to open connection, so disconnect the socket 420 */ 421 422 pcb->so->so_error = ECONNREFUSED; /* XXX convert status ??? */ 423 pcb->state = NG_BTSOCKET_SCO_CLOSED; 424 soisdisconnected(pcb->so); 425 } 426 427 mtx_unlock(&pcb->pcb_mtx); 428 mtx_unlock(&ng_btsocket_sco_sockets_mtx); 429 430 return (error); 431 } /* ng_btsocket_sco_process_lp_con_cfm */ 432 433 /* 434 * Process LP_ConnectInd indicator. Find socket that listens on address. 435 * Find exact or closest match. 436 */ 437 438 static int 439 ng_btsocket_sco_process_lp_con_ind(struct ng_mesg *msg, 440 ng_btsocket_sco_rtentry_p rt) 441 { 442 ng_hci_lp_con_ind_ep *ep = NULL; 443 ng_btsocket_sco_pcb_t *pcb = NULL, *pcb1 = NULL; 444 int error = 0; 445 u_int16_t status = 0; 446 447 if (msg->header.arglen != sizeof(*ep)) 448 return (EMSGSIZE); 449 450 ep = (ng_hci_lp_con_ind_ep *)(msg->data); 451 452 NG_BTSOCKET_SCO_INFO( 453 "%s: Got LP_ConnectInd indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \ 454 "dst bdaddr=%x:%x:%x:%x:%x:%x\n", 455 __func__, 456 rt->src.b[5], rt->src.b[4], rt->src.b[3], 457 rt->src.b[2], rt->src.b[1], rt->src.b[0], 458 ep->bdaddr.b[5], ep->bdaddr.b[4], ep->bdaddr.b[3], 459 ep->bdaddr.b[2], ep->bdaddr.b[1], ep->bdaddr.b[0]); 460 461 mtx_lock(&ng_btsocket_sco_sockets_mtx); 462 463 pcb = ng_btsocket_sco_pcb_by_addr(&rt->src); 464 if (pcb != NULL) { 465 struct socket *so1 = NULL; 466 467 /* pcb is locked */ 468 469 /* 470 * First check the pending connections queue and if we have 471 * space then create new socket and set proper source address. 472 */ 473 474 if (pcb->so->so_qlen <= pcb->so->so_qlimit) 475 so1 = sonewconn(pcb->so, 0); 476 477 if (so1 == NULL) { 478 status = 0x0d; /* Rejected due to limited resources */ 479 goto respond; 480 } 481 482 /* 483 * If we got here than we have created new socket. So complete 484 * connection. If we we listening on specific address then copy 485 * source address from listening socket, otherwise copy source 486 * address from hook's routing information. 487 */ 488 489 pcb1 = so2sco_pcb(so1); 490 KASSERT((pcb1 != NULL), 491 ("%s: pcb1 == NULL\n", __func__)); 492 493 mtx_lock(&pcb1->pcb_mtx); 494 495 if (bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(pcb->src)) != 0) 496 bcopy(&pcb->src, &pcb1->src, sizeof(pcb1->src)); 497 else 498 bcopy(&rt->src, &pcb1->src, sizeof(pcb1->src)); 499 500 pcb1->flags &= ~NG_BTSOCKET_SCO_CLIENT; 501 502 bcopy(&ep->bdaddr, &pcb1->dst, sizeof(pcb1->dst)); 503 pcb1->rt = rt; 504 } else 505 /* Nobody listens on requested BDADDR */ 506 status = 0x1f; /* Unspecified Error */ 507 508 respond: 509 error = ng_btsocket_sco_send_lp_con_rsp(rt, &ep->bdaddr, status); 510 if (pcb1 != NULL) { 511 if (error != 0) { 512 pcb1->so->so_error = error; 513 pcb1->state = NG_BTSOCKET_SCO_CLOSED; 514 soisdisconnected(pcb1->so); 515 } else { 516 pcb1->state = NG_BTSOCKET_SCO_CONNECTING; 517 soisconnecting(pcb1->so); 518 519 ng_btsocket_sco_timeout(pcb1); 520 } 521 522 mtx_unlock(&pcb1->pcb_mtx); 523 } 524 525 if (pcb != NULL) 526 mtx_unlock(&pcb->pcb_mtx); 527 528 mtx_unlock(&ng_btsocket_sco_sockets_mtx); 529 530 return (error); 531 } /* ng_btsocket_sco_process_lp_con_ind */ 532 533 /* 534 * Process LP_DisconnectInd indicator 535 */ 536 537 static int 538 ng_btsocket_sco_process_lp_discon_ind(struct ng_mesg *msg, 539 ng_btsocket_sco_rtentry_p rt) 540 { 541 ng_hci_lp_discon_ind_ep *ep = NULL; 542 ng_btsocket_sco_pcb_t *pcb = NULL; 543 544 /* Check message */ 545 if (msg->header.arglen != sizeof(*ep)) 546 return (EMSGSIZE); 547 548 ep = (ng_hci_lp_discon_ind_ep *)(msg->data); 549 550 mtx_lock(&ng_btsocket_sco_sockets_mtx); 551 552 /* Look for the socket with given channel ID */ 553 pcb = ng_btsocket_sco_pcb_by_handle(&rt->src, ep->con_handle); 554 if (pcb == NULL) { 555 mtx_unlock(&ng_btsocket_sco_sockets_mtx); 556 return (0); 557 } 558 559 /* 560 * Disconnect the socket. If there was any pending request we can 561 * not do anything here anyway. 562 */ 563 564 /* pcb is locked */ 565 566 NG_BTSOCKET_SCO_INFO( 567 "%s: Got LP_DisconnectInd indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \ 568 "dst bdaddr=%x:%x:%x:%x:%x:%x, handle=%d, state=%d\n", 569 __func__, 570 pcb->src.b[5], pcb->src.b[4], pcb->src.b[3], 571 pcb->src.b[2], pcb->src.b[1], pcb->src.b[0], 572 pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3], 573 pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0], 574 pcb->con_handle, pcb->state); 575 576 if (pcb->flags & NG_BTSOCKET_SCO_TIMO) 577 ng_btsocket_sco_untimeout(pcb); 578 579 pcb->state = NG_BTSOCKET_SCO_CLOSED; 580 soisdisconnected(pcb->so); 581 582 mtx_unlock(&pcb->pcb_mtx); 583 mtx_unlock(&ng_btsocket_sco_sockets_mtx); 584 585 return (0); 586 } /* ng_btsocket_sco_process_lp_discon_ind */ 587 588 /* 589 * Send LP_ConnectReq request 590 */ 591 592 static int 593 ng_btsocket_sco_send_lp_con_req(ng_btsocket_sco_pcb_p pcb) 594 { 595 struct ng_mesg *msg = NULL; 596 ng_hci_lp_con_req_ep *ep = NULL; 597 int error = 0; 598 599 mtx_assert(&pcb->pcb_mtx, MA_OWNED); 600 601 if (pcb->rt == NULL || 602 pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook)) 603 return (ENETDOWN); 604 605 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_REQ, 606 sizeof(*ep), M_NOWAIT); 607 if (msg == NULL) 608 return (ENOMEM); 609 610 ep = (ng_hci_lp_con_req_ep *)(msg->data); 611 ep->link_type = NG_HCI_LINK_SCO; 612 bcopy(&pcb->dst, &ep->bdaddr, sizeof(ep->bdaddr)); 613 614 NG_SEND_MSG_HOOK(error, ng_btsocket_sco_node, msg, pcb->rt->hook, 0); 615 616 return (error); 617 } /* ng_btsocket_sco_send_lp_con_req */ 618 619 /* 620 * Send LP_ConnectRsp response 621 */ 622 623 static int 624 ng_btsocket_sco_send_lp_con_rsp(ng_btsocket_sco_rtentry_p rt, bdaddr_p dst, int status) 625 { 626 struct ng_mesg *msg = NULL; 627 ng_hci_lp_con_rsp_ep *ep = NULL; 628 int error = 0; 629 630 if (rt == NULL || rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook)) 631 return (ENETDOWN); 632 633 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_RSP, 634 sizeof(*ep), M_NOWAIT); 635 if (msg == NULL) 636 return (ENOMEM); 637 638 ep = (ng_hci_lp_con_rsp_ep *)(msg->data); 639 ep->status = status; 640 ep->link_type = NG_HCI_LINK_SCO; 641 bcopy(dst, &ep->bdaddr, sizeof(ep->bdaddr)); 642 643 NG_SEND_MSG_HOOK(error, ng_btsocket_sco_node, msg, rt->hook, 0); 644 645 return (error); 646 } /* ng_btsocket_sco_send_lp_con_rsp */ 647 648 /* 649 * Send LP_DisconReq request 650 */ 651 652 static int 653 ng_btsocket_sco_send_lp_discon_req(ng_btsocket_sco_pcb_p pcb) 654 { 655 struct ng_mesg *msg = NULL; 656 ng_hci_lp_discon_req_ep *ep = NULL; 657 int error = 0; 658 659 mtx_assert(&pcb->pcb_mtx, MA_OWNED); 660 661 if (pcb->rt == NULL || 662 pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook)) 663 return (ENETDOWN); 664 665 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_DISCON_REQ, 666 sizeof(*ep), M_NOWAIT); 667 if (msg == NULL) 668 return (ENOMEM); 669 670 ep = (ng_hci_lp_discon_req_ep *)(msg->data); 671 ep->con_handle = pcb->con_handle; 672 ep->reason = 0x13; /* User Ended Connection */ 673 674 NG_SEND_MSG_HOOK(error, ng_btsocket_sco_node, msg, pcb->rt->hook, 0); 675 676 return (error); 677 } /* ng_btsocket_sco_send_lp_discon_req */ 678 679 /***************************************************************************** 680 ***************************************************************************** 681 ** Socket interface 682 ***************************************************************************** 683 *****************************************************************************/ 684 685 /* 686 * SCO sockets data input routine 687 */ 688 689 static void 690 ng_btsocket_sco_data_input(struct mbuf *m, hook_p hook) 691 { 692 ng_hci_scodata_pkt_t *hdr = NULL; 693 ng_btsocket_sco_pcb_t *pcb = NULL; 694 ng_btsocket_sco_rtentry_t *rt = NULL; 695 u_int16_t con_handle; 696 697 if (hook == NULL) { 698 NG_BTSOCKET_SCO_ALERT( 699 "%s: Invalid source hook for SCO data packet\n", __func__); 700 goto drop; 701 } 702 703 rt = (ng_btsocket_sco_rtentry_t *) NG_HOOK_PRIVATE(hook); 704 if (rt == NULL) { 705 NG_BTSOCKET_SCO_ALERT( 706 "%s: Could not find out source bdaddr for SCO data packet\n", __func__); 707 goto drop; 708 } 709 710 /* Make sure we can access header */ 711 if (m->m_pkthdr.len < sizeof(*hdr)) { 712 NG_BTSOCKET_SCO_ERR( 713 "%s: SCO data packet too small, len=%d\n", __func__, m->m_pkthdr.len); 714 goto drop; 715 } 716 717 if (m->m_len < sizeof(*hdr)) { 718 m = m_pullup(m, sizeof(*hdr)); 719 if (m == NULL) 720 goto drop; 721 } 722 723 /* Strip SCO packet header and verify packet length */ 724 hdr = mtod(m, ng_hci_scodata_pkt_t *); 725 m_adj(m, sizeof(*hdr)); 726 727 if (hdr->length != m->m_pkthdr.len) { 728 NG_BTSOCKET_SCO_ERR( 729 "%s: Bad SCO data packet length, len=%d, length=%d\n", 730 __func__, m->m_pkthdr.len, hdr->length); 731 goto drop; 732 } 733 734 /* 735 * Now process packet 736 */ 737 738 con_handle = NG_HCI_CON_HANDLE(le16toh(hdr->con_handle)); 739 740 NG_BTSOCKET_SCO_INFO( 741 "%s: Received SCO data packet: src bdaddr=%x:%x:%x:%x:%x:%x, handle=%d, " \ 742 "length=%d\n", __func__, 743 rt->src.b[5], rt->src.b[4], rt->src.b[3], 744 rt->src.b[2], rt->src.b[1], rt->src.b[0], 745 con_handle, hdr->length); 746 747 mtx_lock(&ng_btsocket_sco_sockets_mtx); 748 749 /* Find socket */ 750 pcb = ng_btsocket_sco_pcb_by_handle(&rt->src, con_handle); 751 if (pcb == NULL) { 752 mtx_unlock(&ng_btsocket_sco_sockets_mtx); 753 goto drop; 754 } 755 756 /* pcb is locked */ 757 758 if (pcb->state != NG_BTSOCKET_SCO_OPEN) { 759 NG_BTSOCKET_SCO_ERR( 760 "%s: No connected socket found, src bdaddr=%x:%x:%x:%x:%x:%x, state=%d\n", 761 __func__, 762 rt->src.b[5], rt->src.b[4], rt->src.b[3], 763 rt->src.b[2], rt->src.b[1], rt->src.b[0], 764 pcb->state); 765 766 mtx_unlock(&pcb->pcb_mtx); 767 mtx_unlock(&ng_btsocket_sco_sockets_mtx); 768 goto drop; 769 } 770 771 /* Check if we have enough space in socket receive queue */ 772 if (m->m_pkthdr.len > sbspace(&pcb->so->so_rcv)) { 773 NG_BTSOCKET_SCO_ERR( 774 "%s: Not enough space in socket receive queue. Dropping SCO data packet, " \ 775 "src bdaddr=%x:%x:%x:%x:%x:%x, len=%d, space=%ld\n", 776 __func__, 777 rt->src.b[5], rt->src.b[4], rt->src.b[3], 778 rt->src.b[2], rt->src.b[1], rt->src.b[0], 779 m->m_pkthdr.len, 780 sbspace(&pcb->so->so_rcv)); 781 782 mtx_unlock(&pcb->pcb_mtx); 783 mtx_unlock(&ng_btsocket_sco_sockets_mtx); 784 goto drop; 785 } 786 787 /* Append packet to the socket receive queue and wakeup */ 788 sbappendrecord(&pcb->so->so_rcv, m); 789 m = NULL; 790 791 sorwakeup(pcb->so); 792 793 mtx_unlock(&pcb->pcb_mtx); 794 mtx_unlock(&ng_btsocket_sco_sockets_mtx); 795 drop: 796 NG_FREE_M(m); /* checks for m != NULL */ 797 } /* ng_btsocket_sco_data_input */ 798 799 /* 800 * SCO sockets default message input routine 801 */ 802 803 static void 804 ng_btsocket_sco_default_msg_input(struct ng_mesg *msg, hook_p hook) 805 { 806 ng_btsocket_sco_rtentry_t *rt = NULL; 807 808 if (hook == NULL || NG_HOOK_NOT_VALID(hook)) 809 return; 810 811 rt = (ng_btsocket_sco_rtentry_t *) NG_HOOK_PRIVATE(hook); 812 813 switch (msg->header.cmd) { 814 case NGM_HCI_NODE_UP: { 815 ng_hci_node_up_ep *ep = NULL; 816 817 if (msg->header.arglen != sizeof(*ep)) 818 break; 819 820 ep = (ng_hci_node_up_ep *)(msg->data); 821 if (bcmp(&ep->bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) 822 break; 823 824 if (rt == NULL) { 825 MALLOC(rt, ng_btsocket_sco_rtentry_p, sizeof(*rt), 826 M_NETGRAPH_BTSOCKET_SCO, M_NOWAIT|M_ZERO); 827 if (rt == NULL) 828 break; 829 830 NG_HOOK_SET_PRIVATE(hook, rt); 831 832 mtx_lock(&ng_btsocket_sco_rt_mtx); 833 834 LIST_INSERT_HEAD(&ng_btsocket_sco_rt, rt, next); 835 } else 836 mtx_lock(&ng_btsocket_sco_rt_mtx); 837 838 bcopy(&ep->bdaddr, &rt->src, sizeof(rt->src)); 839 rt->pkt_size = (ep->pkt_size == 0)? 60 : ep->pkt_size; 840 rt->num_pkts = ep->num_pkts; 841 rt->hook = hook; 842 843 mtx_unlock(&ng_btsocket_sco_rt_mtx); 844 845 NG_BTSOCKET_SCO_INFO( 846 "%s: Updating hook \"%s\", src bdaddr=%x:%x:%x:%x:%x:%x, pkt_size=%d, " \ 847 "num_pkts=%d\n", __func__, NG_HOOK_NAME(hook), 848 rt->src.b[5], rt->src.b[4], rt->src.b[3], 849 rt->src.b[2], rt->src.b[1], rt->src.b[0], 850 rt->pkt_size, rt->num_pkts); 851 } break; 852 853 case NGM_HCI_SYNC_CON_QUEUE: { 854 ng_hci_sync_con_queue_ep *ep = NULL; 855 ng_btsocket_sco_pcb_t *pcb = NULL; 856 857 if (rt == NULL || msg->header.arglen != sizeof(*ep)) 858 break; 859 860 ep = (ng_hci_sync_con_queue_ep *)(msg->data); 861 862 rt->pending -= ep->completed; 863 if (rt->pending < 0) { 864 NG_BTSOCKET_SCO_WARN( 865 "%s: Pending packet counter is out of sync! bdaddr=%x:%x:%x:%x:%x:%x, " \ 866 "handle=%d, pending=%d, completed=%d\n", 867 __func__, 868 rt->src.b[5], rt->src.b[4], rt->src.b[3], 869 rt->src.b[2], rt->src.b[1], rt->src.b[0], 870 ep->con_handle, rt->pending, 871 ep->completed); 872 873 rt->pending = 0; 874 } 875 876 mtx_lock(&ng_btsocket_sco_sockets_mtx); 877 878 /* Find socket */ 879 pcb = ng_btsocket_sco_pcb_by_handle(&rt->src, ep->con_handle); 880 if (pcb == NULL) { 881 mtx_unlock(&ng_btsocket_sco_sockets_mtx); 882 break; 883 } 884 885 /* pcb is locked */ 886 887 /* Check state */ 888 if (pcb->state == NG_BTSOCKET_SCO_OPEN) { 889 /* Remove timeout */ 890 ng_btsocket_sco_untimeout(pcb); 891 892 /* Drop completed packets from the send queue */ 893 for (; ep->completed > 0; ep->completed --) 894 sbdroprecord(&pcb->so->so_snd); 895 896 /* Send more if we have any */ 897 if (pcb->so->so_snd.sb_cc > 0) 898 if (ng_btsocket_sco_send2(pcb) == 0) 899 ng_btsocket_sco_timeout(pcb); 900 901 /* Wake up writers */ 902 sowwakeup(pcb->so); 903 } 904 905 mtx_unlock(&pcb->pcb_mtx); 906 mtx_unlock(&ng_btsocket_sco_sockets_mtx); 907 } break; 908 909 default: 910 NG_BTSOCKET_SCO_WARN( 911 "%s: Unknown message, cmd=%d\n", __func__, msg->header.cmd); 912 break; 913 } 914 915 NG_FREE_MSG(msg); /* Checks for msg != NULL */ 916 } /* ng_btsocket_sco_default_msg_input */ 917 918 /* 919 * SCO sockets LP message input routine 920 */ 921 922 static void 923 ng_btsocket_sco_lp_msg_input(struct ng_mesg *msg, hook_p hook) 924 { 925 ng_btsocket_sco_rtentry_p rt = NULL; 926 927 if (hook == NULL) { 928 NG_BTSOCKET_SCO_ALERT( 929 "%s: Invalid source hook for LP message\n", __func__); 930 goto drop; 931 } 932 933 rt = (ng_btsocket_sco_rtentry_p) NG_HOOK_PRIVATE(hook); 934 if (rt == NULL) { 935 NG_BTSOCKET_SCO_ALERT( 936 "%s: Could not find out source bdaddr for LP message\n", __func__); 937 goto drop; 938 } 939 940 switch (msg->header.cmd) { 941 case NGM_HCI_LP_CON_CFM: /* Connection Confirmation Event */ 942 ng_btsocket_sco_process_lp_con_cfm(msg, rt); 943 break; 944 945 case NGM_HCI_LP_CON_IND: /* Connection Indication Event */ 946 ng_btsocket_sco_process_lp_con_ind(msg, rt); 947 break; 948 949 case NGM_HCI_LP_DISCON_IND: /* Disconnection Indication Event */ 950 ng_btsocket_sco_process_lp_discon_ind(msg, rt); 951 break; 952 953 /* XXX FIXME add other LP messages */ 954 955 default: 956 NG_BTSOCKET_SCO_WARN( 957 "%s: Unknown LP message, cmd=%d\n", __func__, msg->header.cmd); 958 break; 959 } 960 drop: 961 NG_FREE_MSG(msg); 962 } /* ng_btsocket_sco_lp_msg_input */ 963 964 /* 965 * SCO sockets input routine 966 */ 967 968 static void 969 ng_btsocket_sco_input(void *context, int pending) 970 { 971 item_p item = NULL; 972 hook_p hook = NULL; 973 974 for (;;) { 975 mtx_lock(&ng_btsocket_sco_queue_mtx); 976 NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_sco_queue, item); 977 mtx_unlock(&ng_btsocket_sco_queue_mtx); 978 979 if (item == NULL) 980 break; 981 982 NGI_GET_HOOK(item, hook); 983 if (hook != NULL && NG_HOOK_NOT_VALID(hook)) 984 goto drop; 985 986 switch(item->el_flags & NGQF_TYPE) { 987 case NGQF_DATA: { 988 struct mbuf *m = NULL; 989 990 NGI_GET_M(item, m); 991 ng_btsocket_sco_data_input(m, hook); 992 } break; 993 994 case NGQF_MESG: { 995 struct ng_mesg *msg = NULL; 996 997 NGI_GET_MSG(item, msg); 998 999 switch (msg->header.cmd) { 1000 case NGM_HCI_LP_CON_CFM: 1001 case NGM_HCI_LP_CON_IND: 1002 case NGM_HCI_LP_DISCON_IND: 1003 /* XXX FIXME add other LP messages */ 1004 ng_btsocket_sco_lp_msg_input(msg, hook); 1005 break; 1006 1007 default: 1008 ng_btsocket_sco_default_msg_input(msg, hook); 1009 break; 1010 } 1011 } break; 1012 1013 default: 1014 KASSERT(0, 1015 ("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE))); 1016 break; 1017 } 1018 drop: 1019 if (hook != NULL) 1020 NG_HOOK_UNREF(hook); 1021 1022 NG_FREE_ITEM(item); 1023 } 1024 } /* ng_btsocket_sco_input */ 1025 1026 /* 1027 * Route cleanup task. Gets scheduled when hook is disconnected. Here we 1028 * will find all sockets that use "invalid" hook and disconnect them. 1029 */ 1030 1031 static void 1032 ng_btsocket_sco_rtclean(void *context, int pending) 1033 { 1034 ng_btsocket_sco_pcb_p pcb = NULL, pcb_next = NULL; 1035 ng_btsocket_sco_rtentry_p rt = NULL; 1036 1037 /* 1038 * First disconnect all sockets that use "invalid" hook 1039 */ 1040 1041 mtx_lock(&ng_btsocket_sco_sockets_mtx); 1042 1043 for(pcb = LIST_FIRST(&ng_btsocket_sco_sockets); pcb != NULL; ) { 1044 mtx_lock(&pcb->pcb_mtx); 1045 pcb_next = LIST_NEXT(pcb, next); 1046 1047 if (pcb->rt != NULL && 1048 pcb->rt->hook != NULL && NG_HOOK_NOT_VALID(pcb->rt->hook)) { 1049 if (pcb->flags & NG_BTSOCKET_SCO_TIMO) 1050 ng_btsocket_sco_untimeout(pcb); 1051 1052 pcb->rt = NULL; 1053 pcb->so->so_error = ENETDOWN; 1054 pcb->state = NG_BTSOCKET_SCO_CLOSED; 1055 soisdisconnected(pcb->so); 1056 } 1057 1058 mtx_unlock(&pcb->pcb_mtx); 1059 pcb = pcb_next; 1060 } 1061 1062 mtx_unlock(&ng_btsocket_sco_sockets_mtx); 1063 1064 /* 1065 * Now cleanup routing table 1066 */ 1067 1068 mtx_lock(&ng_btsocket_sco_rt_mtx); 1069 1070 for (rt = LIST_FIRST(&ng_btsocket_sco_rt); rt != NULL; ) { 1071 ng_btsocket_sco_rtentry_p rt_next = LIST_NEXT(rt, next); 1072 1073 if (rt->hook != NULL && NG_HOOK_NOT_VALID(rt->hook)) { 1074 LIST_REMOVE(rt, next); 1075 1076 NG_HOOK_SET_PRIVATE(rt->hook, NULL); 1077 NG_HOOK_UNREF(rt->hook); /* Remove extra reference */ 1078 1079 bzero(rt, sizeof(*rt)); 1080 FREE(rt, M_NETGRAPH_BTSOCKET_SCO); 1081 } 1082 1083 rt = rt_next; 1084 } 1085 1086 mtx_unlock(&ng_btsocket_sco_rt_mtx); 1087 } /* ng_btsocket_sco_rtclean */ 1088 1089 /* 1090 * Initialize everything 1091 */ 1092 1093 void 1094 ng_btsocket_sco_init(void) 1095 { 1096 int error = 0; 1097 1098 ng_btsocket_sco_node = NULL; 1099 ng_btsocket_sco_debug_level = NG_BTSOCKET_WARN_LEVEL; 1100 1101 /* Register Netgraph node type */ 1102 error = ng_newtype(&typestruct); 1103 if (error != 0) { 1104 NG_BTSOCKET_SCO_ALERT( 1105 "%s: Could not register Netgraph node type, error=%d\n", __func__, error); 1106 1107 return; 1108 } 1109 1110 /* Create Netgrapg node */ 1111 error = ng_make_node_common(&typestruct, &ng_btsocket_sco_node); 1112 if (error != 0) { 1113 NG_BTSOCKET_SCO_ALERT( 1114 "%s: Could not create Netgraph node, error=%d\n", __func__, error); 1115 1116 ng_btsocket_sco_node = NULL; 1117 1118 return; 1119 } 1120 1121 error = ng_name_node(ng_btsocket_sco_node, NG_BTSOCKET_SCO_NODE_TYPE); 1122 if (error != 0) { 1123 NG_BTSOCKET_SCO_ALERT( 1124 "%s: Could not name Netgraph node, error=%d\n", __func__, error); 1125 1126 NG_NODE_UNREF(ng_btsocket_sco_node); 1127 ng_btsocket_sco_node = NULL; 1128 1129 return; 1130 } 1131 1132 /* Create input queue */ 1133 NG_BT_ITEMQ_INIT(&ng_btsocket_sco_queue, 300); 1134 mtx_init(&ng_btsocket_sco_queue_mtx, 1135 "btsocks_sco_queue_mtx", NULL, MTX_DEF); 1136 TASK_INIT(&ng_btsocket_sco_queue_task, 0, 1137 ng_btsocket_sco_input, NULL); 1138 1139 /* Create list of sockets */ 1140 LIST_INIT(&ng_btsocket_sco_sockets); 1141 mtx_init(&ng_btsocket_sco_sockets_mtx, 1142 "btsocks_sco_sockets_mtx", NULL, MTX_DEF); 1143 1144 /* Routing table */ 1145 LIST_INIT(&ng_btsocket_sco_rt); 1146 mtx_init(&ng_btsocket_sco_rt_mtx, 1147 "btsocks_sco_rt_mtx", NULL, MTX_DEF); 1148 TASK_INIT(&ng_btsocket_sco_rt_task, 0, 1149 ng_btsocket_sco_rtclean, NULL); 1150 } /* ng_btsocket_sco_init */ 1151 1152 /* 1153 * Abort connection on socket 1154 */ 1155 1156 void 1157 ng_btsocket_sco_abort(struct socket *so) 1158 { 1159 so->so_error = ECONNABORTED; 1160 1161 (void) ng_btsocket_sco_disconnect(so); 1162 } /* ng_btsocket_sco_abort */ 1163 1164 void 1165 ng_btsocket_sco_close(struct socket *so) 1166 { 1167 (void) ng_btsocket_sco_disconnect(so); 1168 } /* ng_btsocket_sco_close */ 1169 1170 /* 1171 * Accept connection on socket. Nothing to do here, socket must be connected 1172 * and ready, so just return peer address and be done with it. 1173 */ 1174 1175 int 1176 ng_btsocket_sco_accept(struct socket *so, struct sockaddr **nam) 1177 { 1178 if (ng_btsocket_sco_node == NULL) 1179 return (EINVAL); 1180 1181 return (ng_btsocket_sco_peeraddr(so, nam)); 1182 } /* ng_btsocket_sco_accept */ 1183 1184 /* 1185 * Create and attach new socket 1186 */ 1187 1188 int 1189 ng_btsocket_sco_attach(struct socket *so, int proto, struct thread *td) 1190 { 1191 ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so); 1192 int error; 1193 1194 /* Check socket and protocol */ 1195 if (ng_btsocket_sco_node == NULL) 1196 return (EPROTONOSUPPORT); 1197 if (so->so_type != SOCK_SEQPACKET) 1198 return (ESOCKTNOSUPPORT); 1199 1200 #if 0 /* XXX sonewconn() calls "pru_attach" with proto == 0 */ 1201 if (proto != 0) 1202 if (proto != BLUETOOTH_PROTO_SCO) 1203 return (EPROTONOSUPPORT); 1204 #endif /* XXX */ 1205 1206 if (pcb != NULL) 1207 return (EISCONN); 1208 1209 /* Reserve send and receive space if it is not reserved yet */ 1210 if ((so->so_snd.sb_hiwat == 0) || (so->so_rcv.sb_hiwat == 0)) { 1211 error = soreserve(so, NG_BTSOCKET_SCO_SENDSPACE, 1212 NG_BTSOCKET_SCO_RECVSPACE); 1213 if (error != 0) 1214 return (error); 1215 } 1216 1217 /* Allocate the PCB */ 1218 MALLOC(pcb, ng_btsocket_sco_pcb_p, sizeof(*pcb), 1219 M_NETGRAPH_BTSOCKET_SCO, M_NOWAIT | M_ZERO); 1220 if (pcb == NULL) 1221 return (ENOMEM); 1222 1223 /* Link the PCB and the socket */ 1224 so->so_pcb = (caddr_t) pcb; 1225 pcb->so = so; 1226 pcb->state = NG_BTSOCKET_SCO_CLOSED; 1227 1228 callout_init(&pcb->timo, 1); 1229 1230 /* 1231 * Mark PCB mutex as DUPOK to prevent "duplicated lock of 1232 * the same type" message. When accepting new SCO connection 1233 * ng_btsocket_sco_process_lp_con_ind() holds both PCB mutexes 1234 * for "old" (accepting) PCB and "new" (created) PCB. 1235 */ 1236 1237 mtx_init(&pcb->pcb_mtx, "btsocks_sco_pcb_mtx", NULL, 1238 MTX_DEF|MTX_DUPOK); 1239 1240 /* 1241 * Add the PCB to the list 1242 * 1243 * XXX FIXME VERY IMPORTANT! 1244 * 1245 * This is totally FUBAR. We could get here in two cases: 1246 * 1247 * 1) When user calls socket() 1248 * 2) When we need to accept new incomming connection and call 1249 * sonewconn() 1250 * 1251 * In the first case we must aquire ng_btsocket_sco_sockets_mtx. 1252 * In the second case we hold ng_btsocket_sco_sockets_mtx already. 1253 * So we now need to distinguish between these cases. From reading 1254 * /sys/kern/uipc_socket2.c we can find out that sonewconn() calls 1255 * pru_attach with proto == 0 and td == NULL. For now use this fact 1256 * to figure out if we were called from socket() or from sonewconn(). 1257 */ 1258 1259 if (td != NULL) 1260 mtx_lock(&ng_btsocket_sco_sockets_mtx); 1261 else 1262 mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED); 1263 1264 LIST_INSERT_HEAD(&ng_btsocket_sco_sockets, pcb, next); 1265 1266 if (td != NULL) 1267 mtx_unlock(&ng_btsocket_sco_sockets_mtx); 1268 1269 return (0); 1270 } /* ng_btsocket_sco_attach */ 1271 1272 /* 1273 * Bind socket 1274 */ 1275 1276 int 1277 ng_btsocket_sco_bind(struct socket *so, struct sockaddr *nam, 1278 struct thread *td) 1279 { 1280 ng_btsocket_sco_pcb_t *pcb = NULL; 1281 struct sockaddr_sco *sa = (struct sockaddr_sco *) nam; 1282 1283 if (ng_btsocket_sco_node == NULL) 1284 return (EINVAL); 1285 1286 /* Verify address */ 1287 if (sa == NULL) 1288 return (EINVAL); 1289 if (sa->sco_family != AF_BLUETOOTH) 1290 return (EAFNOSUPPORT); 1291 if (sa->sco_len != sizeof(*sa)) 1292 return (EINVAL); 1293 1294 mtx_lock(&ng_btsocket_sco_sockets_mtx); 1295 1296 /* 1297 * Check if other socket has this address already (look for exact 1298 * match in bdaddr) and assign socket address if it's available. 1299 */ 1300 1301 if (bcmp(&sa->sco_bdaddr, NG_HCI_BDADDR_ANY, sizeof(sa->sco_bdaddr)) != 0) { 1302 LIST_FOREACH(pcb, &ng_btsocket_sco_sockets, next) { 1303 mtx_lock(&pcb->pcb_mtx); 1304 1305 if (bcmp(&pcb->src, &sa->sco_bdaddr, sizeof(bdaddr_t)) == 0) { 1306 mtx_unlock(&pcb->pcb_mtx); 1307 mtx_unlock(&ng_btsocket_sco_sockets_mtx); 1308 1309 return (EADDRINUSE); 1310 } 1311 1312 mtx_unlock(&pcb->pcb_mtx); 1313 } 1314 1315 } 1316 1317 pcb = so2sco_pcb(so); 1318 if (pcb == NULL) { 1319 mtx_unlock(&ng_btsocket_sco_sockets_mtx); 1320 return (EINVAL); 1321 } 1322 1323 mtx_lock(&pcb->pcb_mtx); 1324 bcopy(&sa->sco_bdaddr, &pcb->src, sizeof(pcb->src)); 1325 mtx_unlock(&pcb->pcb_mtx); 1326 1327 mtx_unlock(&ng_btsocket_sco_sockets_mtx); 1328 1329 return (0); 1330 } /* ng_btsocket_sco_bind */ 1331 1332 /* 1333 * Connect socket 1334 */ 1335 1336 int 1337 ng_btsocket_sco_connect(struct socket *so, struct sockaddr *nam, 1338 struct thread *td) 1339 { 1340 ng_btsocket_sco_pcb_t *pcb = so2sco_pcb(so); 1341 struct sockaddr_sco *sa = (struct sockaddr_sco *) nam; 1342 ng_btsocket_sco_rtentry_t *rt = NULL; 1343 int have_src, error = 0; 1344 1345 /* Check socket */ 1346 if (pcb == NULL) 1347 return (EINVAL); 1348 if (ng_btsocket_sco_node == NULL) 1349 return (EINVAL); 1350 1351 /* Verify address */ 1352 if (sa == NULL) 1353 return (EINVAL); 1354 if (sa->sco_family != AF_BLUETOOTH) 1355 return (EAFNOSUPPORT); 1356 if (sa->sco_len != sizeof(*sa)) 1357 return (EINVAL); 1358 if (bcmp(&sa->sco_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) 1359 return (EDESTADDRREQ); 1360 1361 /* 1362 * Routing. Socket should be bound to some source address. The source 1363 * address can be ANY. Destination address must be set and it must not 1364 * be ANY. If source address is ANY then find first rtentry that has 1365 * src != dst. 1366 */ 1367 1368 mtx_lock(&ng_btsocket_sco_rt_mtx); 1369 mtx_lock(&pcb->pcb_mtx); 1370 1371 if (pcb->state == NG_BTSOCKET_SCO_CONNECTING) { 1372 mtx_unlock(&pcb->pcb_mtx); 1373 mtx_unlock(&ng_btsocket_sco_rt_mtx); 1374 1375 return (EINPROGRESS); 1376 } 1377 1378 if (bcmp(&sa->sco_bdaddr, &pcb->src, sizeof(pcb->src)) == 0) { 1379 mtx_unlock(&pcb->pcb_mtx); 1380 mtx_unlock(&ng_btsocket_sco_rt_mtx); 1381 1382 return (EINVAL); 1383 } 1384 1385 /* Send destination address and PSM */ 1386 bcopy(&sa->sco_bdaddr, &pcb->dst, sizeof(pcb->dst)); 1387 1388 pcb->rt = NULL; 1389 have_src = bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(pcb->src)); 1390 1391 LIST_FOREACH(rt, &ng_btsocket_sco_rt, next) { 1392 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook)) 1393 continue; 1394 1395 /* Match src and dst */ 1396 if (have_src) { 1397 if (bcmp(&pcb->src, &rt->src, sizeof(rt->src)) == 0) 1398 break; 1399 } else { 1400 if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0) 1401 break; 1402 } 1403 } 1404 1405 if (rt != NULL) { 1406 pcb->rt = rt; 1407 1408 if (!have_src) 1409 bcopy(&rt->src, &pcb->src, sizeof(pcb->src)); 1410 } else 1411 error = EHOSTUNREACH; 1412 1413 /* 1414 * Send LP_Connect request 1415 */ 1416 1417 if (error == 0) { 1418 error = ng_btsocket_sco_send_lp_con_req(pcb); 1419 if (error == 0) { 1420 pcb->flags |= NG_BTSOCKET_SCO_CLIENT; 1421 pcb->state = NG_BTSOCKET_SCO_CONNECTING; 1422 soisconnecting(pcb->so); 1423 1424 ng_btsocket_sco_timeout(pcb); 1425 } 1426 } 1427 1428 mtx_unlock(&pcb->pcb_mtx); 1429 mtx_unlock(&ng_btsocket_sco_rt_mtx); 1430 1431 return (error); 1432 } /* ng_btsocket_sco_connect */ 1433 1434 /* 1435 * Process ioctl's calls on socket 1436 */ 1437 1438 int 1439 ng_btsocket_sco_control(struct socket *so, u_long cmd, caddr_t data, 1440 struct ifnet *ifp, struct thread *td) 1441 { 1442 return (EINVAL); 1443 } /* ng_btsocket_sco_control */ 1444 1445 /* 1446 * Process getsockopt/setsockopt system calls 1447 */ 1448 1449 int 1450 ng_btsocket_sco_ctloutput(struct socket *so, struct sockopt *sopt) 1451 { 1452 ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so); 1453 int error, tmp; 1454 1455 if (ng_btsocket_sco_node == NULL) 1456 return (EINVAL); 1457 if (pcb == NULL) 1458 return (EINVAL); 1459 1460 if (sopt->sopt_level != SOL_SCO) 1461 return (0); 1462 1463 mtx_lock(&pcb->pcb_mtx); 1464 1465 switch (sopt->sopt_dir) { 1466 case SOPT_GET: 1467 if (pcb->state != NG_BTSOCKET_SCO_OPEN) { 1468 error = ENOTCONN; 1469 break; 1470 } 1471 1472 switch (sopt->sopt_name) { 1473 case SO_SCO_MTU: 1474 tmp = pcb->rt->pkt_size; 1475 error = sooptcopyout(sopt, &tmp, sizeof(tmp)); 1476 break; 1477 1478 case SO_SCO_CONNINFO: 1479 tmp = pcb->con_handle; 1480 error = sooptcopyout(sopt, &tmp, sizeof(tmp)); 1481 break; 1482 1483 default: 1484 error = EINVAL; 1485 break; 1486 } 1487 break; 1488 1489 case SOPT_SET: 1490 error = ENOPROTOOPT; 1491 break; 1492 1493 default: 1494 error = EINVAL; 1495 break; 1496 } 1497 1498 mtx_unlock(&pcb->pcb_mtx); 1499 1500 return (error); 1501 } /* ng_btsocket_sco_ctloutput */ 1502 1503 /* 1504 * Detach and destroy socket 1505 */ 1506 1507 void 1508 ng_btsocket_sco_detach(struct socket *so) 1509 { 1510 ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so); 1511 1512 KASSERT(pcb != NULL, ("ng_btsocket_sco_detach: pcb == NULL")); 1513 1514 if (ng_btsocket_sco_node == NULL) 1515 return; 1516 1517 mtx_lock(&ng_btsocket_sco_sockets_mtx); 1518 mtx_lock(&pcb->pcb_mtx); 1519 1520 if (pcb->flags & NG_BTSOCKET_SCO_TIMO) 1521 ng_btsocket_sco_untimeout(pcb); 1522 1523 if (pcb->state == NG_BTSOCKET_SCO_OPEN) 1524 ng_btsocket_sco_send_lp_discon_req(pcb); 1525 1526 pcb->state = NG_BTSOCKET_SCO_CLOSED; 1527 1528 LIST_REMOVE(pcb, next); 1529 1530 mtx_unlock(&pcb->pcb_mtx); 1531 mtx_unlock(&ng_btsocket_sco_sockets_mtx); 1532 1533 mtx_destroy(&pcb->pcb_mtx); 1534 bzero(pcb, sizeof(*pcb)); 1535 FREE(pcb, M_NETGRAPH_BTSOCKET_SCO); 1536 1537 soisdisconnected(so); 1538 so->so_pcb = NULL; 1539 } /* ng_btsocket_sco_detach */ 1540 1541 /* 1542 * Disconnect socket 1543 */ 1544 1545 int 1546 ng_btsocket_sco_disconnect(struct socket *so) 1547 { 1548 ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so); 1549 1550 if (pcb == NULL) 1551 return (EINVAL); 1552 if (ng_btsocket_sco_node == NULL) 1553 return (EINVAL); 1554 1555 mtx_lock(&pcb->pcb_mtx); 1556 1557 if (pcb->state == NG_BTSOCKET_SCO_DISCONNECTING) { 1558 mtx_unlock(&pcb->pcb_mtx); 1559 1560 return (EINPROGRESS); 1561 } 1562 1563 if (pcb->flags & NG_BTSOCKET_SCO_TIMO) 1564 ng_btsocket_sco_untimeout(pcb); 1565 1566 if (pcb->state == NG_BTSOCKET_SCO_OPEN) { 1567 ng_btsocket_sco_send_lp_discon_req(pcb); 1568 1569 pcb->state = NG_BTSOCKET_SCO_DISCONNECTING; 1570 soisdisconnecting(so); 1571 1572 ng_btsocket_sco_timeout(pcb); 1573 } else { 1574 pcb->state = NG_BTSOCKET_SCO_CLOSED; 1575 soisdisconnected(so); 1576 } 1577 1578 mtx_unlock(&pcb->pcb_mtx); 1579 1580 return (0); 1581 } /* ng_btsocket_sco_disconnect */ 1582 1583 /* 1584 * Listen on socket 1585 */ 1586 1587 int 1588 ng_btsocket_sco_listen(struct socket *so, int backlog, struct thread *td) 1589 { 1590 ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so); 1591 int error; 1592 1593 if (pcb == NULL) 1594 return (EINVAL); 1595 if (ng_btsocket_sco_node == NULL) 1596 return (EINVAL); 1597 1598 SOCK_LOCK(so); 1599 mtx_lock(&pcb->pcb_mtx); 1600 1601 error = solisten_proto_check(so); 1602 if (error != 0) 1603 goto out; 1604 #if 0 1605 if (bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) { 1606 error = EDESTADDRREQ; 1607 goto out; 1608 } 1609 #endif 1610 solisten_proto(so, backlog); 1611 out: 1612 mtx_unlock(&pcb->pcb_mtx); 1613 SOCK_UNLOCK(so); 1614 1615 return (error); 1616 } /* ng_btsocket_listen */ 1617 1618 /* 1619 * Get peer address 1620 */ 1621 1622 int 1623 ng_btsocket_sco_peeraddr(struct socket *so, struct sockaddr **nam) 1624 { 1625 ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so); 1626 struct sockaddr_sco sa; 1627 1628 if (pcb == NULL) 1629 return (EINVAL); 1630 if (ng_btsocket_sco_node == NULL) 1631 return (EINVAL); 1632 1633 mtx_lock(&pcb->pcb_mtx); 1634 bcopy(&pcb->dst, &sa.sco_bdaddr, sizeof(sa.sco_bdaddr)); 1635 mtx_unlock(&pcb->pcb_mtx); 1636 1637 sa.sco_len = sizeof(sa); 1638 sa.sco_family = AF_BLUETOOTH; 1639 1640 *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT); 1641 1642 return ((*nam == NULL)? ENOMEM : 0); 1643 } /* ng_btsocket_sco_peeraddr */ 1644 1645 /* 1646 * Send data to socket 1647 */ 1648 1649 int 1650 ng_btsocket_sco_send(struct socket *so, int flags, struct mbuf *m, 1651 struct sockaddr *nam, struct mbuf *control, struct thread *td) 1652 { 1653 ng_btsocket_sco_pcb_t *pcb = so2sco_pcb(so); 1654 int error = 0; 1655 1656 if (ng_btsocket_sco_node == NULL) { 1657 error = ENETDOWN; 1658 goto drop; 1659 } 1660 1661 /* Check socket and input */ 1662 if (pcb == NULL || m == NULL || control != NULL) { 1663 error = EINVAL; 1664 goto drop; 1665 } 1666 1667 mtx_lock(&pcb->pcb_mtx); 1668 1669 /* Make sure socket is connected */ 1670 if (pcb->state != NG_BTSOCKET_SCO_OPEN) { 1671 mtx_unlock(&pcb->pcb_mtx); 1672 error = ENOTCONN; 1673 goto drop; 1674 } 1675 1676 /* Check route */ 1677 if (pcb->rt == NULL || 1678 pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook)) { 1679 mtx_unlock(&pcb->pcb_mtx); 1680 error = ENETDOWN; 1681 goto drop; 1682 } 1683 1684 /* Check packet size */ 1685 if (m->m_pkthdr.len > pcb->rt->pkt_size) { 1686 NG_BTSOCKET_SCO_ERR( 1687 "%s: Packet too big, len=%d, pkt_size=%d\n", 1688 __func__, m->m_pkthdr.len, pcb->rt->pkt_size); 1689 1690 mtx_unlock(&pcb->pcb_mtx); 1691 error = EMSGSIZE; 1692 goto drop; 1693 } 1694 1695 /* 1696 * First put packet on socket send queue. Then check if we have 1697 * pending timeout. If we do not have timeout then we must send 1698 * packet and schedule timeout. Otherwise do nothing and wait for 1699 * NGM_HCI_SYNC_CON_QUEUE message. 1700 */ 1701 1702 sbappendrecord(&pcb->so->so_snd, m); 1703 m = NULL; 1704 1705 if (!(pcb->flags & NG_BTSOCKET_SCO_TIMO)) { 1706 error = ng_btsocket_sco_send2(pcb); 1707 if (error == 0) 1708 ng_btsocket_sco_timeout(pcb); 1709 else 1710 sbdroprecord(&pcb->so->so_snd); /* XXX */ 1711 } 1712 1713 mtx_unlock(&pcb->pcb_mtx); 1714 drop: 1715 NG_FREE_M(m); /* checks for != NULL */ 1716 NG_FREE_M(control); 1717 1718 return (error); 1719 } /* ng_btsocket_sco_send */ 1720 1721 /* 1722 * Send first packet in the socket queue to the SCO layer 1723 */ 1724 1725 static int 1726 ng_btsocket_sco_send2(ng_btsocket_sco_pcb_p pcb) 1727 { 1728 struct mbuf *m = NULL; 1729 ng_hci_scodata_pkt_t *hdr = NULL; 1730 int error = 0; 1731 1732 mtx_assert(&pcb->pcb_mtx, MA_OWNED); 1733 1734 while (pcb->rt->pending < pcb->rt->num_pkts && 1735 pcb->so->so_snd.sb_cc > 0) { 1736 /* Get a copy of the first packet on send queue */ 1737 m = m_dup(pcb->so->so_snd.sb_mb, M_DONTWAIT); 1738 if (m == NULL) { 1739 error = ENOBUFS; 1740 break; 1741 } 1742 1743 /* Create SCO packet header */ 1744 M_PREPEND(m, sizeof(*hdr), M_DONTWAIT); 1745 if (m != NULL) 1746 if (m->m_len < sizeof(*hdr)) 1747 m = m_pullup(m, sizeof(*hdr)); 1748 1749 if (m == NULL) { 1750 error = ENOBUFS; 1751 break; 1752 } 1753 1754 /* Fill in the header */ 1755 hdr = mtod(m, ng_hci_scodata_pkt_t *); 1756 hdr->type = NG_HCI_SCO_DATA_PKT; 1757 hdr->con_handle = htole16(NG_HCI_MK_CON_HANDLE(pcb->con_handle, 0, 0)); 1758 hdr->length = m->m_pkthdr.len - sizeof(*hdr); 1759 1760 /* Send packet */ 1761 NG_SEND_DATA_ONLY(error, pcb->rt->hook, m); 1762 if (error != 0) 1763 break; 1764 1765 pcb->rt->pending ++; 1766 } 1767 1768 return ((pcb->rt->pending > 0)? 0 : error); 1769 } /* ng_btsocket_sco_send2 */ 1770 1771 /* 1772 * Get socket address 1773 */ 1774 1775 int 1776 ng_btsocket_sco_sockaddr(struct socket *so, struct sockaddr **nam) 1777 { 1778 ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so); 1779 struct sockaddr_sco sa; 1780 1781 if (pcb == NULL) 1782 return (EINVAL); 1783 if (ng_btsocket_sco_node == NULL) 1784 return (EINVAL); 1785 1786 mtx_lock(&pcb->pcb_mtx); 1787 bcopy(&pcb->src, &sa.sco_bdaddr, sizeof(sa.sco_bdaddr)); 1788 mtx_unlock(&pcb->pcb_mtx); 1789 1790 sa.sco_len = sizeof(sa); 1791 sa.sco_family = AF_BLUETOOTH; 1792 1793 *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT); 1794 1795 return ((*nam == NULL)? ENOMEM : 0); 1796 } /* ng_btsocket_sco_sockaddr */ 1797 1798 /***************************************************************************** 1799 ***************************************************************************** 1800 ** Misc. functions 1801 ***************************************************************************** 1802 *****************************************************************************/ 1803 1804 /* 1805 * Look for the socket that listens on given bdaddr. 1806 * Returns exact or close match (if any). 1807 * Caller must hold ng_btsocket_sco_sockets_mtx. 1808 * Returns with locked pcb. 1809 */ 1810 1811 static ng_btsocket_sco_pcb_p 1812 ng_btsocket_sco_pcb_by_addr(bdaddr_p bdaddr) 1813 { 1814 ng_btsocket_sco_pcb_p p = NULL, p1 = NULL; 1815 1816 mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED); 1817 1818 LIST_FOREACH(p, &ng_btsocket_sco_sockets, next) { 1819 mtx_lock(&p->pcb_mtx); 1820 1821 if (p->so == NULL || !(p->so->so_options & SO_ACCEPTCONN)) { 1822 mtx_unlock(&p->pcb_mtx); 1823 continue; 1824 } 1825 1826 if (bcmp(&p->src, bdaddr, sizeof(p->src)) == 0) 1827 return (p); /* return with locked pcb */ 1828 1829 if (bcmp(&p->src, NG_HCI_BDADDR_ANY, sizeof(p->src)) == 0) 1830 p1 = p; 1831 1832 mtx_unlock(&p->pcb_mtx); 1833 } 1834 1835 return (p1); 1836 } /* ng_btsocket_sco_pcb_by_addr */ 1837 1838 /* 1839 * Look for the socket that assigned to given source address and handle. 1840 * Caller must hold ng_btsocket_sco_sockets_mtx. 1841 * Returns with locked pcb. 1842 */ 1843 1844 static ng_btsocket_sco_pcb_p 1845 ng_btsocket_sco_pcb_by_handle(bdaddr_p src, int con_handle) 1846 { 1847 ng_btsocket_sco_pcb_p p = NULL; 1848 1849 mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED); 1850 1851 LIST_FOREACH(p, &ng_btsocket_sco_sockets, next) { 1852 mtx_lock(&p->pcb_mtx); 1853 1854 if (p->con_handle == con_handle && 1855 bcmp(src, &p->src, sizeof(p->src)) == 0) 1856 return (p); /* return with locked pcb */ 1857 1858 mtx_unlock(&p->pcb_mtx); 1859 } 1860 1861 return (NULL); 1862 } /* ng_btsocket_sco_pcb_by_handle */ 1863 1864 /* 1865 * Look for the socket in CONNECTING state with given source and destination 1866 * addresses. Caller must hold ng_btsocket_sco_sockets_mtx. 1867 * Returns with locked pcb. 1868 */ 1869 1870 static ng_btsocket_sco_pcb_p 1871 ng_btsocket_sco_pcb_by_addrs(bdaddr_p src, bdaddr_p dst) 1872 { 1873 ng_btsocket_sco_pcb_p p = NULL; 1874 1875 mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED); 1876 1877 LIST_FOREACH(p, &ng_btsocket_sco_sockets, next) { 1878 mtx_lock(&p->pcb_mtx); 1879 1880 if (p->state == NG_BTSOCKET_SCO_CONNECTING && 1881 bcmp(src, &p->src, sizeof(p->src)) == 0 && 1882 bcmp(dst, &p->dst, sizeof(p->dst)) == 0) 1883 return (p); /* return with locked pcb */ 1884 1885 mtx_unlock(&p->pcb_mtx); 1886 } 1887 1888 return (NULL); 1889 } /* ng_btsocket_sco_pcb_by_addrs */ 1890 1891 /* 1892 * Set timeout on socket 1893 */ 1894 1895 static void 1896 ng_btsocket_sco_timeout(ng_btsocket_sco_pcb_p pcb) 1897 { 1898 mtx_assert(&pcb->pcb_mtx, MA_OWNED); 1899 1900 if (!(pcb->flags & NG_BTSOCKET_SCO_TIMO)) { 1901 pcb->flags |= NG_BTSOCKET_SCO_TIMO; 1902 callout_reset(&pcb->timo, bluetooth_sco_rtx_timeout(), 1903 ng_btsocket_sco_process_timeout, pcb); 1904 } else 1905 KASSERT(0, 1906 ("%s: Duplicated socket timeout?!\n", __func__)); 1907 } /* ng_btsocket_sco_timeout */ 1908 1909 /* 1910 * Unset timeout on socket 1911 */ 1912 1913 static void 1914 ng_btsocket_sco_untimeout(ng_btsocket_sco_pcb_p pcb) 1915 { 1916 mtx_assert(&pcb->pcb_mtx, MA_OWNED); 1917 1918 if (pcb->flags & NG_BTSOCKET_SCO_TIMO) { 1919 callout_stop(&pcb->timo); 1920 pcb->flags &= ~NG_BTSOCKET_SCO_TIMO; 1921 } else 1922 KASSERT(0, 1923 ("%s: No socket timeout?!\n", __func__)); 1924 } /* ng_btsocket_sco_untimeout */ 1925 1926 /* 1927 * Process timeout on socket 1928 */ 1929 1930 static void 1931 ng_btsocket_sco_process_timeout(void *xpcb) 1932 { 1933 ng_btsocket_sco_pcb_p pcb = (ng_btsocket_sco_pcb_p) xpcb; 1934 1935 mtx_lock(&pcb->pcb_mtx); 1936 1937 pcb->flags &= ~NG_BTSOCKET_SCO_TIMO; 1938 pcb->so->so_error = ETIMEDOUT; 1939 1940 switch (pcb->state) { 1941 case NG_BTSOCKET_SCO_CONNECTING: 1942 /* Connect timeout - close the socket */ 1943 pcb->state = NG_BTSOCKET_SCO_CLOSED; 1944 soisdisconnected(pcb->so); 1945 break; 1946 1947 case NG_BTSOCKET_SCO_OPEN: 1948 /* Send timeout - did not get NGM_HCI_SYNC_CON_QUEUE */ 1949 sbdroprecord(&pcb->so->so_snd); 1950 sowwakeup(pcb->so); 1951 /* XXX FIXME what to do with pcb->rt->pending??? */ 1952 break; 1953 1954 case NG_BTSOCKET_SCO_DISCONNECTING: 1955 /* Disconnect timeout - disconnect the socket anyway */ 1956 pcb->state = NG_BTSOCKET_SCO_CLOSED; 1957 soisdisconnected(pcb->so); 1958 break; 1959 1960 default: 1961 NG_BTSOCKET_SCO_ERR( 1962 "%s: Invalid socket state=%d\n", __func__, pcb->state); 1963 break; 1964 } 1965 1966 mtx_unlock(&pcb->pcb_mtx); 1967 } /* ng_btsocket_sco_process_timeout */ 1968 1969