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