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