1 /* 2 * ng_btsocket_l2cap_raw.c 3 */ 4 5 /*- 6 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 7 * 8 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com> 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $Id: ng_btsocket_l2cap_raw.c,v 1.12 2003/09/14 23:29:06 max Exp $ 33 * $FreeBSD$ 34 */ 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/bitstring.h> 39 #include <sys/domain.h> 40 #include <sys/errno.h> 41 #include <sys/filedesc.h> 42 #include <sys/ioccom.h> 43 #include <sys/kernel.h> 44 #include <sys/lock.h> 45 #include <sys/malloc.h> 46 #include <sys/mbuf.h> 47 #include <sys/mutex.h> 48 #include <sys/priv.h> 49 #include <sys/protosw.h> 50 #include <sys/queue.h> 51 #include <sys/socket.h> 52 #include <sys/socketvar.h> 53 #include <sys/sysctl.h> 54 #include <sys/taskqueue.h> 55 56 #include <net/vnet.h> 57 58 #include <netgraph/ng_message.h> 59 #include <netgraph/netgraph.h> 60 #include <netgraph/bluetooth/include/ng_bluetooth.h> 61 #include <netgraph/bluetooth/include/ng_hci.h> 62 #include <netgraph/bluetooth/include/ng_l2cap.h> 63 #include <netgraph/bluetooth/include/ng_btsocket.h> 64 #include <netgraph/bluetooth/include/ng_btsocket_l2cap.h> 65 66 /* MALLOC define */ 67 #ifdef NG_SEPARATE_MALLOC 68 static MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_L2CAP_RAW, 69 "netgraph_btsocks_l2cap_raw", "Netgraph Bluetooth raw L2CAP sockets"); 70 #else 71 #define M_NETGRAPH_BTSOCKET_L2CAP_RAW M_NETGRAPH 72 #endif /* NG_SEPARATE_MALLOC */ 73 74 /* Netgraph node methods */ 75 static ng_constructor_t ng_btsocket_l2cap_raw_node_constructor; 76 static ng_rcvmsg_t ng_btsocket_l2cap_raw_node_rcvmsg; 77 static ng_shutdown_t ng_btsocket_l2cap_raw_node_shutdown; 78 static ng_newhook_t ng_btsocket_l2cap_raw_node_newhook; 79 static ng_connect_t ng_btsocket_l2cap_raw_node_connect; 80 static ng_rcvdata_t ng_btsocket_l2cap_raw_node_rcvdata; 81 static ng_disconnect_t ng_btsocket_l2cap_raw_node_disconnect; 82 83 static void ng_btsocket_l2cap_raw_input (void *, int); 84 static void ng_btsocket_l2cap_raw_rtclean (void *, int); 85 static void ng_btsocket_l2cap_raw_get_token (u_int32_t *); 86 87 static int ng_btsocket_l2cap_raw_send_ngmsg 88 (hook_p, int, void *, int); 89 static int ng_btsocket_l2cap_raw_send_sync_ngmsg 90 (ng_btsocket_l2cap_raw_pcb_p, int, void *, int); 91 92 #define ng_btsocket_l2cap_raw_wakeup_input_task() \ 93 taskqueue_enqueue(taskqueue_swi, &ng_btsocket_l2cap_raw_queue_task) 94 95 #define ng_btsocket_l2cap_raw_wakeup_route_task() \ 96 taskqueue_enqueue(taskqueue_swi, &ng_btsocket_l2cap_raw_rt_task) 97 98 /* Netgraph type descriptor */ 99 static struct ng_type typestruct = { 100 .version = NG_ABI_VERSION, 101 .name = NG_BTSOCKET_L2CAP_RAW_NODE_TYPE, 102 .constructor = ng_btsocket_l2cap_raw_node_constructor, 103 .rcvmsg = ng_btsocket_l2cap_raw_node_rcvmsg, 104 .shutdown = ng_btsocket_l2cap_raw_node_shutdown, 105 .newhook = ng_btsocket_l2cap_raw_node_newhook, 106 .connect = ng_btsocket_l2cap_raw_node_connect, 107 .rcvdata = ng_btsocket_l2cap_raw_node_rcvdata, 108 .disconnect = ng_btsocket_l2cap_raw_node_disconnect, 109 }; 110 111 /* Globals */ 112 extern int ifqmaxlen; 113 static u_int32_t ng_btsocket_l2cap_raw_debug_level; 114 static u_int32_t ng_btsocket_l2cap_raw_ioctl_timeout; 115 static node_p ng_btsocket_l2cap_raw_node; 116 static struct ng_bt_itemq ng_btsocket_l2cap_raw_queue; 117 static struct mtx ng_btsocket_l2cap_raw_queue_mtx; 118 static struct task ng_btsocket_l2cap_raw_queue_task; 119 static LIST_HEAD(, ng_btsocket_l2cap_raw_pcb) ng_btsocket_l2cap_raw_sockets; 120 static struct mtx ng_btsocket_l2cap_raw_sockets_mtx; 121 static u_int32_t ng_btsocket_l2cap_raw_token; 122 static struct mtx ng_btsocket_l2cap_raw_token_mtx; 123 static LIST_HEAD(, ng_btsocket_l2cap_rtentry) ng_btsocket_l2cap_raw_rt; 124 static struct mtx ng_btsocket_l2cap_raw_rt_mtx; 125 static struct task ng_btsocket_l2cap_raw_rt_task; 126 static struct timeval ng_btsocket_l2cap_raw_lasttime; 127 static int ng_btsocket_l2cap_raw_curpps; 128 129 /* Sysctl tree */ 130 SYSCTL_DECL(_net_bluetooth_l2cap_sockets); 131 static SYSCTL_NODE(_net_bluetooth_l2cap_sockets, OID_AUTO, raw, 132 CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 133 "Bluetooth raw L2CAP sockets family"); 134 SYSCTL_UINT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, debug_level, 135 CTLFLAG_RW, 136 &ng_btsocket_l2cap_raw_debug_level, NG_BTSOCKET_WARN_LEVEL, 137 "Bluetooth raw L2CAP sockets debug level"); 138 SYSCTL_UINT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, ioctl_timeout, 139 CTLFLAG_RW, 140 &ng_btsocket_l2cap_raw_ioctl_timeout, 5, 141 "Bluetooth raw L2CAP sockets ioctl timeout"); 142 SYSCTL_UINT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_len, 143 CTLFLAG_RD, 144 &ng_btsocket_l2cap_raw_queue.len, 0, 145 "Bluetooth raw L2CAP sockets input queue length"); 146 SYSCTL_UINT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_maxlen, 147 CTLFLAG_RD, 148 &ng_btsocket_l2cap_raw_queue.maxlen, 0, 149 "Bluetooth raw L2CAP sockets input queue max. length"); 150 SYSCTL_UINT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_drops, 151 CTLFLAG_RD, 152 &ng_btsocket_l2cap_raw_queue.drops, 0, 153 "Bluetooth raw L2CAP sockets input queue drops"); 154 155 /* Debug */ 156 #define NG_BTSOCKET_L2CAP_RAW_INFO \ 157 if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_INFO_LEVEL && \ 158 ppsratecheck(&ng_btsocket_l2cap_raw_lasttime, &ng_btsocket_l2cap_raw_curpps, 1)) \ 159 printf 160 161 #define NG_BTSOCKET_L2CAP_RAW_WARN \ 162 if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_WARN_LEVEL && \ 163 ppsratecheck(&ng_btsocket_l2cap_raw_lasttime, &ng_btsocket_l2cap_raw_curpps, 1)) \ 164 printf 165 166 #define NG_BTSOCKET_L2CAP_RAW_ERR \ 167 if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_ERR_LEVEL && \ 168 ppsratecheck(&ng_btsocket_l2cap_raw_lasttime, &ng_btsocket_l2cap_raw_curpps, 1)) \ 169 printf 170 171 #define NG_BTSOCKET_L2CAP_RAW_ALERT \ 172 if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_ALERT_LEVEL && \ 173 ppsratecheck(&ng_btsocket_l2cap_raw_lasttime, &ng_btsocket_l2cap_raw_curpps, 1)) \ 174 printf 175 176 /***************************************************************************** 177 ***************************************************************************** 178 ** Netgraph node interface 179 ***************************************************************************** 180 *****************************************************************************/ 181 182 /* 183 * Netgraph node constructor. Do not allow to create node of this type. 184 */ 185 186 static int 187 ng_btsocket_l2cap_raw_node_constructor(node_p node) 188 { 189 return (EINVAL); 190 } /* ng_btsocket_l2cap_raw_node_constructor */ 191 192 /* 193 * Do local shutdown processing. Let old node go and create new fresh one. 194 */ 195 196 static int 197 ng_btsocket_l2cap_raw_node_shutdown(node_p node) 198 { 199 int error = 0; 200 201 NG_NODE_UNREF(node); 202 203 /* Create new node */ 204 error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_raw_node); 205 if (error != 0) { 206 NG_BTSOCKET_L2CAP_RAW_ALERT( 207 "%s: Could not create Netgraph node, error=%d\n", __func__, error); 208 209 ng_btsocket_l2cap_raw_node = NULL; 210 211 return (error); 212 } 213 214 error = ng_name_node(ng_btsocket_l2cap_raw_node, 215 NG_BTSOCKET_L2CAP_RAW_NODE_TYPE); 216 if (error != 0) { 217 NG_BTSOCKET_L2CAP_RAW_ALERT( 218 "%s: Could not name Netgraph node, error=%d\n", __func__, error); 219 220 NG_NODE_UNREF(ng_btsocket_l2cap_raw_node); 221 ng_btsocket_l2cap_raw_node = NULL; 222 223 return (error); 224 } 225 226 return (0); 227 } /* ng_btsocket_l2cap_raw_node_shutdown */ 228 229 /* 230 * We allow any hook to be connected to the node. 231 */ 232 233 static int 234 ng_btsocket_l2cap_raw_node_newhook(node_p node, hook_p hook, char const *name) 235 { 236 return (0); 237 } /* ng_btsocket_l2cap_raw_node_newhook */ 238 239 /* 240 * Just say "YEP, that's OK by me!" 241 */ 242 243 static int 244 ng_btsocket_l2cap_raw_node_connect(hook_p hook) 245 { 246 NG_HOOK_SET_PRIVATE(hook, NULL); 247 NG_HOOK_REF(hook); /* Keep extra reference to the hook */ 248 249 return (0); 250 } /* ng_btsocket_l2cap_raw_node_connect */ 251 252 /* 253 * Hook disconnection. Schedule route cleanup task 254 */ 255 256 static int 257 ng_btsocket_l2cap_raw_node_disconnect(hook_p hook) 258 { 259 /* 260 * If hook has private information than we must have this hook in 261 * the routing table and must schedule cleaning for the routing table. 262 * Otherwise hook was connected but we never got "hook_info" message, 263 * so we have never added this hook to the routing table and it save 264 * to just delete it. 265 */ 266 267 if (NG_HOOK_PRIVATE(hook) != NULL) 268 return (ng_btsocket_l2cap_raw_wakeup_route_task()); 269 270 NG_HOOK_UNREF(hook); /* Remove extra reference */ 271 272 return (0); 273 } /* ng_btsocket_l2cap_raw_node_disconnect */ 274 275 /* 276 * Process incoming messages 277 */ 278 279 static int 280 ng_btsocket_l2cap_raw_node_rcvmsg(node_p node, item_p item, hook_p hook) 281 { 282 struct ng_mesg *msg = NGI_MSG(item); /* item still has message */ 283 int error = 0; 284 285 if (msg != NULL && msg->header.typecookie == NGM_L2CAP_COOKIE) { 286 287 /* 288 * NGM_L2CAP_NODE_HOOK_INFO is special message initiated by 289 * L2CAP layer. Ignore all other messages if they are not 290 * replies or token is zero 291 */ 292 293 if (msg->header.cmd != NGM_L2CAP_NODE_HOOK_INFO) { 294 if (msg->header.token == 0 || 295 !(msg->header.flags & NGF_RESP)) { 296 NG_FREE_ITEM(item); 297 return (0); 298 } 299 } 300 301 mtx_lock(&ng_btsocket_l2cap_raw_queue_mtx); 302 if (NG_BT_ITEMQ_FULL(&ng_btsocket_l2cap_raw_queue)) { 303 NG_BTSOCKET_L2CAP_RAW_ERR( 304 "%s: Input queue is full\n", __func__); 305 306 NG_BT_ITEMQ_DROP(&ng_btsocket_l2cap_raw_queue); 307 NG_FREE_ITEM(item); 308 error = ENOBUFS; 309 } else { 310 if (hook != NULL) { 311 NG_HOOK_REF(hook); 312 NGI_SET_HOOK(item, hook); 313 } 314 315 NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_l2cap_raw_queue, item); 316 error = ng_btsocket_l2cap_raw_wakeup_input_task(); 317 } 318 mtx_unlock(&ng_btsocket_l2cap_raw_queue_mtx); 319 } else { 320 NG_FREE_ITEM(item); 321 error = EINVAL; 322 } 323 324 return (error); 325 } /* ng_btsocket_l2cap_raw_node_rcvmsg */ 326 327 /* 328 * Receive data on a hook 329 */ 330 331 static int 332 ng_btsocket_l2cap_raw_node_rcvdata(hook_p hook, item_p item) 333 { 334 NG_FREE_ITEM(item); 335 336 return (EINVAL); 337 } /* ng_btsocket_l2cap_raw_node_rcvdata */ 338 339 /***************************************************************************** 340 ***************************************************************************** 341 ** Socket interface 342 ***************************************************************************** 343 *****************************************************************************/ 344 345 /* 346 * L2CAP sockets input routine 347 */ 348 349 static void 350 ng_btsocket_l2cap_raw_input(void *context, int pending) 351 { 352 item_p item = NULL; 353 hook_p hook = NULL; 354 struct ng_mesg *msg = NULL; 355 356 for (;;) { 357 mtx_lock(&ng_btsocket_l2cap_raw_queue_mtx); 358 NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_l2cap_raw_queue, item); 359 mtx_unlock(&ng_btsocket_l2cap_raw_queue_mtx); 360 361 if (item == NULL) 362 break; 363 364 KASSERT((item->el_flags & NGQF_TYPE) == NGQF_MESG, 365 ("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE))); 366 367 NGI_GET_MSG(item, msg); 368 NGI_GET_HOOK(item, hook); 369 NG_FREE_ITEM(item); 370 371 switch (msg->header.cmd) { 372 case NGM_L2CAP_NODE_HOOK_INFO: { 373 ng_btsocket_l2cap_rtentry_t *rt = NULL; 374 375 if (hook == NULL || NG_HOOK_NOT_VALID(hook) || 376 msg->header.arglen != sizeof(bdaddr_t)) 377 break; 378 379 if (bcmp(msg->data, NG_HCI_BDADDR_ANY, 380 sizeof(bdaddr_t)) == 0) 381 break; 382 383 rt = (ng_btsocket_l2cap_rtentry_t *) 384 NG_HOOK_PRIVATE(hook); 385 if (rt == NULL) { 386 rt = malloc(sizeof(*rt), 387 M_NETGRAPH_BTSOCKET_L2CAP_RAW, 388 M_NOWAIT|M_ZERO); 389 if (rt == NULL) 390 break; 391 392 NG_HOOK_SET_PRIVATE(hook, rt); 393 394 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx); 395 396 LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_rt, 397 rt, next); 398 } else 399 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx); 400 401 bcopy(msg->data, &rt->src, sizeof(rt->src)); 402 rt->hook = hook; 403 404 NG_BTSOCKET_L2CAP_RAW_INFO( 405 "%s: Updating hook \"%s\", src bdaddr=%x:%x:%x:%x:%x:%x\n", 406 __func__, NG_HOOK_NAME(hook), 407 rt->src.b[5], rt->src.b[4], rt->src.b[3], 408 rt->src.b[2], rt->src.b[1], rt->src.b[0]); 409 410 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx); 411 } break; 412 413 case NGM_L2CAP_NODE_GET_FLAGS: 414 case NGM_L2CAP_NODE_GET_DEBUG: 415 case NGM_L2CAP_NODE_GET_CON_LIST: 416 case NGM_L2CAP_NODE_GET_CHAN_LIST: 417 case NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO: 418 case NGM_L2CAP_L2CA_PING: 419 case NGM_L2CAP_L2CA_GET_INFO: { 420 ng_btsocket_l2cap_raw_pcb_p pcb = NULL; 421 422 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx); 423 424 LIST_FOREACH(pcb,&ng_btsocket_l2cap_raw_sockets,next) { 425 mtx_lock(&pcb->pcb_mtx); 426 427 if (pcb->token == msg->header.token) { 428 pcb->msg = msg; 429 msg = NULL; 430 wakeup(&pcb->msg); 431 mtx_unlock(&pcb->pcb_mtx); 432 break; 433 } 434 435 mtx_unlock(&pcb->pcb_mtx); 436 } 437 438 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx); 439 } break; 440 441 default: 442 NG_BTSOCKET_L2CAP_RAW_WARN( 443 "%s: Unknown message, cmd=%d\n", __func__, msg->header.cmd); 444 break; 445 } 446 447 if (hook != NULL) 448 NG_HOOK_UNREF(hook); /* remove extra reference */ 449 450 NG_FREE_MSG(msg); /* Checks for msg != NULL */ 451 } 452 } /* ng_btsocket_l2cap_raw_input */ 453 454 /* 455 * Route cleanup task. Gets scheduled when hook is disconnected. Here we 456 * will find all sockets that use "invalid" hook and disconnect them. 457 */ 458 459 static void 460 ng_btsocket_l2cap_raw_rtclean(void *context, int pending) 461 { 462 ng_btsocket_l2cap_raw_pcb_p pcb = NULL; 463 ng_btsocket_l2cap_rtentry_p rt = NULL; 464 465 /* 466 * First disconnect all sockets that use "invalid" hook 467 */ 468 469 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx); 470 471 LIST_FOREACH(pcb, &ng_btsocket_l2cap_raw_sockets, next) { 472 mtx_lock(&pcb->pcb_mtx); 473 474 if (pcb->rt != NULL && 475 pcb->rt->hook != NULL && NG_HOOK_NOT_VALID(pcb->rt->hook)) { 476 if (pcb->so != NULL && 477 pcb->so->so_state & SS_ISCONNECTED) 478 soisdisconnected(pcb->so); 479 480 pcb->rt = NULL; 481 } 482 483 mtx_unlock(&pcb->pcb_mtx); 484 } 485 486 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx); 487 488 /* 489 * Now cleanup routing table 490 */ 491 492 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx); 493 494 for (rt = LIST_FIRST(&ng_btsocket_l2cap_raw_rt); rt != NULL; ) { 495 ng_btsocket_l2cap_rtentry_p rt_next = LIST_NEXT(rt, next); 496 497 if (rt->hook != NULL && NG_HOOK_NOT_VALID(rt->hook)) { 498 LIST_REMOVE(rt, next); 499 500 NG_HOOK_SET_PRIVATE(rt->hook, NULL); 501 NG_HOOK_UNREF(rt->hook); /* Remove extra reference */ 502 503 bzero(rt, sizeof(*rt)); 504 free(rt, M_NETGRAPH_BTSOCKET_L2CAP_RAW); 505 } 506 507 rt = rt_next; 508 } 509 510 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx); 511 } /* ng_btsocket_l2cap_raw_rtclean */ 512 513 /* 514 * Initialize everything 515 */ 516 517 void 518 ng_btsocket_l2cap_raw_init(void) 519 { 520 int error = 0; 521 522 /* Skip initialization of globals for non-default instances. */ 523 if (!IS_DEFAULT_VNET(curvnet)) 524 return; 525 526 ng_btsocket_l2cap_raw_node = NULL; 527 ng_btsocket_l2cap_raw_debug_level = NG_BTSOCKET_WARN_LEVEL; 528 ng_btsocket_l2cap_raw_ioctl_timeout = 5; 529 530 /* Register Netgraph node type */ 531 error = ng_newtype(&typestruct); 532 if (error != 0) { 533 NG_BTSOCKET_L2CAP_RAW_ALERT( 534 "%s: Could not register Netgraph node type, error=%d\n", __func__, error); 535 536 return; 537 } 538 539 /* Create Netgrapg node */ 540 error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_raw_node); 541 if (error != 0) { 542 NG_BTSOCKET_L2CAP_RAW_ALERT( 543 "%s: Could not create Netgraph node, error=%d\n", __func__, error); 544 545 ng_btsocket_l2cap_raw_node = NULL; 546 547 return; 548 } 549 550 error = ng_name_node(ng_btsocket_l2cap_raw_node, 551 NG_BTSOCKET_L2CAP_RAW_NODE_TYPE); 552 if (error != 0) { 553 NG_BTSOCKET_L2CAP_RAW_ALERT( 554 "%s: Could not name Netgraph node, error=%d\n", __func__, error); 555 556 NG_NODE_UNREF(ng_btsocket_l2cap_raw_node); 557 ng_btsocket_l2cap_raw_node = NULL; 558 559 return; 560 } 561 562 /* Create input queue */ 563 NG_BT_ITEMQ_INIT(&ng_btsocket_l2cap_raw_queue, ifqmaxlen); 564 mtx_init(&ng_btsocket_l2cap_raw_queue_mtx, 565 "btsocks_l2cap_raw_queue_mtx", NULL, MTX_DEF); 566 TASK_INIT(&ng_btsocket_l2cap_raw_queue_task, 0, 567 ng_btsocket_l2cap_raw_input, NULL); 568 569 /* Create list of sockets */ 570 LIST_INIT(&ng_btsocket_l2cap_raw_sockets); 571 mtx_init(&ng_btsocket_l2cap_raw_sockets_mtx, 572 "btsocks_l2cap_raw_sockets_mtx", NULL, MTX_DEF); 573 574 /* Tokens */ 575 ng_btsocket_l2cap_raw_token = 0; 576 mtx_init(&ng_btsocket_l2cap_raw_token_mtx, 577 "btsocks_l2cap_raw_token_mtx", NULL, MTX_DEF); 578 579 /* Routing table */ 580 LIST_INIT(&ng_btsocket_l2cap_raw_rt); 581 mtx_init(&ng_btsocket_l2cap_raw_rt_mtx, 582 "btsocks_l2cap_raw_rt_mtx", NULL, MTX_DEF); 583 TASK_INIT(&ng_btsocket_l2cap_raw_rt_task, 0, 584 ng_btsocket_l2cap_raw_rtclean, NULL); 585 } /* ng_btsocket_l2cap_raw_init */ 586 587 /* 588 * Abort connection on socket 589 */ 590 591 void 592 ng_btsocket_l2cap_raw_abort(struct socket *so) 593 { 594 595 (void)ng_btsocket_l2cap_raw_disconnect(so); 596 } /* ng_btsocket_l2cap_raw_abort */ 597 598 void 599 ng_btsocket_l2cap_raw_close(struct socket *so) 600 { 601 602 (void)ng_btsocket_l2cap_raw_disconnect(so); 603 } /* ng_btsocket_l2cap_raw_close */ 604 605 /* 606 * Create and attach new socket 607 */ 608 609 int 610 ng_btsocket_l2cap_raw_attach(struct socket *so, int proto, struct thread *td) 611 { 612 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 613 int error; 614 615 if (pcb != NULL) 616 return (EISCONN); 617 618 if (ng_btsocket_l2cap_raw_node == NULL) 619 return (EPROTONOSUPPORT); 620 if (so->so_type != SOCK_RAW) 621 return (ESOCKTNOSUPPORT); 622 623 /* Reserve send and receive space if it is not reserved yet */ 624 error = soreserve(so, NG_BTSOCKET_L2CAP_RAW_SENDSPACE, 625 NG_BTSOCKET_L2CAP_RAW_RECVSPACE); 626 if (error != 0) 627 return (error); 628 629 /* Allocate the PCB */ 630 pcb = malloc(sizeof(*pcb), 631 M_NETGRAPH_BTSOCKET_L2CAP_RAW, M_NOWAIT|M_ZERO); 632 if (pcb == NULL) 633 return (ENOMEM); 634 635 /* Link the PCB and the socket */ 636 so->so_pcb = (caddr_t) pcb; 637 pcb->so = so; 638 639 if (priv_check(td, PRIV_NETBLUETOOTH_RAW) == 0) 640 pcb->flags |= NG_BTSOCKET_L2CAP_RAW_PRIVILEGED; 641 642 mtx_init(&pcb->pcb_mtx, "btsocks_l2cap_raw_pcb_mtx", NULL, MTX_DEF); 643 644 /* Add the PCB to the list */ 645 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx); 646 LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_sockets, pcb, next); 647 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx); 648 649 return (0); 650 } /* ng_btsocket_l2cap_raw_attach */ 651 652 /* 653 * Bind socket 654 */ 655 656 int 657 ng_btsocket_l2cap_raw_bind(struct socket *so, struct sockaddr *nam, 658 struct thread *td) 659 { 660 ng_btsocket_l2cap_raw_pcb_t *pcb = so2l2cap_raw_pcb(so); 661 struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *) nam; 662 ng_btsocket_l2cap_rtentry_t *rt = NULL; 663 664 if (pcb == NULL) 665 return (EINVAL); 666 if (ng_btsocket_l2cap_raw_node == NULL) 667 return (EINVAL); 668 669 if (sa == NULL) 670 return (EINVAL); 671 if (sa->l2cap_family != AF_BLUETOOTH) 672 return (EAFNOSUPPORT); 673 if((sa->l2cap_len != sizeof(*sa))&& 674 (sa->l2cap_len != sizeof(struct sockaddr_l2cap_compat))) 675 return (EINVAL); 676 677 if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, 678 sizeof(sa->l2cap_bdaddr)) != 0) { 679 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx); 680 681 LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) { 682 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook)) 683 continue; 684 685 if (bcmp(&sa->l2cap_bdaddr, &rt->src, 686 sizeof(rt->src)) == 0) 687 break; 688 } 689 690 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx); 691 692 if (rt == NULL) 693 return (ENETDOWN); 694 } else 695 rt = NULL; 696 697 mtx_lock(&pcb->pcb_mtx); 698 bcopy(&sa->l2cap_bdaddr, &pcb->src, sizeof(pcb->src)); 699 pcb->rt = rt; 700 mtx_unlock(&pcb->pcb_mtx); 701 702 return (0); 703 } /* ng_btsocket_l2cap_raw_bind */ 704 705 /* 706 * Connect socket 707 */ 708 709 int 710 ng_btsocket_l2cap_raw_connect(struct socket *so, struct sockaddr *nam, 711 struct thread *td) 712 { 713 ng_btsocket_l2cap_raw_pcb_t *pcb = so2l2cap_raw_pcb(so); 714 struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *) nam; 715 ng_btsocket_l2cap_rtentry_t *rt = NULL; 716 int error; 717 718 if (pcb == NULL) 719 return (EINVAL); 720 if (ng_btsocket_l2cap_raw_node == NULL) 721 return (EINVAL); 722 723 if (sa == NULL) 724 return (EINVAL); 725 if (sa->l2cap_family != AF_BLUETOOTH) 726 return (EAFNOSUPPORT); 727 if((sa->l2cap_len != sizeof(*sa))&& 728 (sa->l2cap_len != sizeof(struct sockaddr_l2cap_compat))) 729 return (EINVAL); 730 731 if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) 732 return (EINVAL); 733 734 mtx_lock(&pcb->pcb_mtx); 735 736 bcopy(&sa->l2cap_bdaddr, &pcb->dst, sizeof(pcb->dst)); 737 738 if (bcmp(&pcb->src, &pcb->dst, sizeof(pcb->src)) == 0) { 739 mtx_unlock(&pcb->pcb_mtx); 740 741 return (EADDRNOTAVAIL); 742 } 743 744 /* 745 * If there is route already - use it 746 */ 747 748 if (pcb->rt != NULL) { 749 soisconnected(so); 750 mtx_unlock(&pcb->pcb_mtx); 751 752 return (0); 753 } 754 755 /* 756 * Find the first hook that does not match specified destination address 757 */ 758 759 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx); 760 761 LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) { 762 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook)) 763 continue; 764 765 if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0) 766 break; 767 } 768 769 if (rt != NULL) { 770 soisconnected(so); 771 772 pcb->rt = rt; 773 bcopy(&rt->src, &pcb->src, sizeof(pcb->src)); 774 775 error = 0; 776 } else 777 error = ENETDOWN; 778 779 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx); 780 mtx_unlock(&pcb->pcb_mtx); 781 782 return (error); 783 } /* ng_btsocket_l2cap_raw_connect */ 784 785 /* 786 * Process ioctl's calls on socket 787 */ 788 789 int 790 ng_btsocket_l2cap_raw_control(struct socket *so, u_long cmd, caddr_t data, 791 struct ifnet *ifp, struct thread *td) 792 { 793 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 794 struct ng_mesg *msg = NULL; 795 int error = 0; 796 797 if (pcb == NULL) 798 return (EINVAL); 799 if (ng_btsocket_l2cap_raw_node == NULL) 800 return (EINVAL); 801 802 mtx_lock(&pcb->pcb_mtx); 803 804 /* Check if we route info */ 805 if (pcb->rt == NULL) { 806 mtx_unlock(&pcb->pcb_mtx); 807 return (EHOSTUNREACH); 808 } 809 810 /* Check if we have pending ioctl() */ 811 if (pcb->token != 0) { 812 mtx_unlock(&pcb->pcb_mtx); 813 return (EBUSY); 814 } 815 816 switch (cmd) { 817 case SIOC_L2CAP_NODE_GET_FLAGS: { 818 struct ng_btsocket_l2cap_raw_node_flags *p = 819 (struct ng_btsocket_l2cap_raw_node_flags *) data; 820 821 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb, 822 NGM_L2CAP_NODE_GET_FLAGS, 823 &p->flags, sizeof(p->flags)); 824 } break; 825 826 case SIOC_L2CAP_NODE_GET_DEBUG: { 827 struct ng_btsocket_l2cap_raw_node_debug *p = 828 (struct ng_btsocket_l2cap_raw_node_debug *) data; 829 830 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb, 831 NGM_L2CAP_NODE_GET_DEBUG, 832 &p->debug, sizeof(p->debug)); 833 } break; 834 835 case SIOC_L2CAP_NODE_SET_DEBUG: { 836 struct ng_btsocket_l2cap_raw_node_debug *p = 837 (struct ng_btsocket_l2cap_raw_node_debug *) data; 838 839 if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED) 840 error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook, 841 NGM_L2CAP_NODE_SET_DEBUG, 842 &p->debug, sizeof(p->debug)); 843 else 844 error = EPERM; 845 } break; 846 847 case SIOC_L2CAP_NODE_GET_CON_LIST: { 848 struct ng_btsocket_l2cap_raw_con_list *p = 849 (struct ng_btsocket_l2cap_raw_con_list *) data; 850 ng_l2cap_node_con_list_ep *p1 = NULL; 851 ng_l2cap_node_con_ep *p2 = NULL; 852 853 if (p->num_connections == 0 || 854 p->num_connections > NG_L2CAP_MAX_CON_NUM || 855 p->connections == NULL) { 856 mtx_unlock(&pcb->pcb_mtx); 857 return (EINVAL); 858 } 859 860 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_GET_CON_LIST, 861 0, M_NOWAIT); 862 if (msg == NULL) { 863 mtx_unlock(&pcb->pcb_mtx); 864 return (ENOMEM); 865 } 866 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 867 pcb->token = msg->header.token; 868 pcb->msg = NULL; 869 870 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 871 pcb->rt->hook, 0); 872 if (error != 0) { 873 pcb->token = 0; 874 mtx_unlock(&pcb->pcb_mtx); 875 return (error); 876 } 877 878 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl", 879 ng_btsocket_l2cap_raw_ioctl_timeout * hz); 880 pcb->token = 0; 881 882 if (error != 0) { 883 mtx_unlock(&pcb->pcb_mtx); 884 return (error); 885 } 886 887 msg = pcb->msg; 888 pcb->msg = NULL; 889 890 mtx_unlock(&pcb->pcb_mtx); 891 892 if (msg != NULL && 893 msg->header.cmd == NGM_L2CAP_NODE_GET_CON_LIST) { 894 /* Return data back to user space */ 895 p1 = (ng_l2cap_node_con_list_ep *)(msg->data); 896 p2 = (ng_l2cap_node_con_ep *)(p1 + 1); 897 898 p->num_connections = min(p->num_connections, 899 p1->num_connections); 900 if (p->num_connections > 0) 901 error = copyout((caddr_t) p2, 902 (caddr_t) p->connections, 903 p->num_connections * sizeof(*p2)); 904 } else 905 error = EINVAL; 906 907 NG_FREE_MSG(msg); /* checks for != NULL */ 908 return (error); 909 } /* NOTREACHED */ 910 911 case SIOC_L2CAP_NODE_GET_CHAN_LIST: { 912 struct ng_btsocket_l2cap_raw_chan_list *p = 913 (struct ng_btsocket_l2cap_raw_chan_list *) data; 914 ng_l2cap_node_chan_list_ep *p1 = NULL; 915 ng_l2cap_node_chan_ep *p2 = NULL; 916 917 if (p->num_channels == 0 || 918 p->num_channels > NG_L2CAP_MAX_CHAN_NUM || 919 p->channels == NULL) { 920 mtx_unlock(&pcb->pcb_mtx); 921 return (EINVAL); 922 } 923 924 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, 925 NGM_L2CAP_NODE_GET_CHAN_LIST, 0, M_NOWAIT); 926 if (msg == NULL) { 927 mtx_unlock(&pcb->pcb_mtx); 928 return (ENOMEM); 929 } 930 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 931 pcb->token = msg->header.token; 932 pcb->msg = NULL; 933 934 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 935 pcb->rt->hook, 0); 936 if (error != 0) { 937 pcb->token = 0; 938 mtx_unlock(&pcb->pcb_mtx); 939 return (error); 940 } 941 942 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl", 943 ng_btsocket_l2cap_raw_ioctl_timeout * hz); 944 pcb->token = 0; 945 946 if (error != 0) { 947 mtx_unlock(&pcb->pcb_mtx); 948 return (error); 949 } 950 951 msg = pcb->msg; 952 pcb->msg = NULL; 953 954 mtx_unlock(&pcb->pcb_mtx); 955 956 if (msg != NULL && 957 msg->header.cmd == NGM_L2CAP_NODE_GET_CHAN_LIST) { 958 /* Return data back to user space */ 959 p1 = (ng_l2cap_node_chan_list_ep *)(msg->data); 960 p2 = (ng_l2cap_node_chan_ep *)(p1 + 1); 961 962 p->num_channels = min(p->num_channels, 963 p1->num_channels); 964 if (p->num_channels > 0) 965 error = copyout((caddr_t) p2, 966 (caddr_t) p->channels, 967 p->num_channels * sizeof(*p2)); 968 } else 969 error = EINVAL; 970 971 NG_FREE_MSG(msg); /* checks for != NULL */ 972 return (error); 973 } /* NOTREACHED */ 974 975 case SIOC_L2CAP_L2CA_PING: { 976 struct ng_btsocket_l2cap_raw_ping *p = 977 (struct ng_btsocket_l2cap_raw_ping *) data; 978 ng_l2cap_l2ca_ping_ip *ip = NULL; 979 ng_l2cap_l2ca_ping_op *op = NULL; 980 981 if ((p->echo_size != 0 && p->echo_data == NULL) || 982 p->echo_size > NG_L2CAP_MAX_ECHO_SIZE) { 983 mtx_unlock(&pcb->pcb_mtx); 984 return (EINVAL); 985 } 986 987 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, 988 NGM_L2CAP_L2CA_PING, sizeof(*ip) + p->echo_size, 989 M_NOWAIT); 990 if (msg == NULL) { 991 mtx_unlock(&pcb->pcb_mtx); 992 return (ENOMEM); 993 } 994 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 995 pcb->token = msg->header.token; 996 pcb->msg = NULL; 997 998 ip = (ng_l2cap_l2ca_ping_ip *)(msg->data); 999 bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr)); 1000 ip->echo_size = p->echo_size; 1001 1002 if (ip->echo_size > 0) { 1003 mtx_unlock(&pcb->pcb_mtx); 1004 error = copyin(p->echo_data, ip + 1, p->echo_size); 1005 mtx_lock(&pcb->pcb_mtx); 1006 1007 if (error != 0) { 1008 NG_FREE_MSG(msg); 1009 pcb->token = 0; 1010 mtx_unlock(&pcb->pcb_mtx); 1011 return (error); 1012 } 1013 } 1014 1015 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 1016 pcb->rt->hook, 0); 1017 if (error != 0) { 1018 pcb->token = 0; 1019 mtx_unlock(&pcb->pcb_mtx); 1020 return (error); 1021 } 1022 1023 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl", 1024 bluetooth_l2cap_rtx_timeout()); 1025 pcb->token = 0; 1026 1027 if (error != 0) { 1028 mtx_unlock(&pcb->pcb_mtx); 1029 return (error); 1030 } 1031 1032 msg = pcb->msg; 1033 pcb->msg = NULL; 1034 1035 mtx_unlock(&pcb->pcb_mtx); 1036 1037 if (msg != NULL && 1038 msg->header.cmd == NGM_L2CAP_L2CA_PING) { 1039 /* Return data back to the user space */ 1040 op = (ng_l2cap_l2ca_ping_op *)(msg->data); 1041 p->result = op->result; 1042 p->echo_size = min(p->echo_size, op->echo_size); 1043 1044 if (p->echo_size > 0) 1045 error = copyout(op + 1, p->echo_data, 1046 p->echo_size); 1047 } else 1048 error = EINVAL; 1049 1050 NG_FREE_MSG(msg); /* checks for != NULL */ 1051 return (error); 1052 } /* NOTREACHED */ 1053 1054 case SIOC_L2CAP_L2CA_GET_INFO: { 1055 struct ng_btsocket_l2cap_raw_get_info *p = 1056 (struct ng_btsocket_l2cap_raw_get_info *) data; 1057 ng_l2cap_l2ca_get_info_ip *ip = NULL; 1058 ng_l2cap_l2ca_get_info_op *op = NULL; 1059 1060 if (!(pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)) { 1061 mtx_unlock(&pcb->pcb_mtx); 1062 return (EPERM); 1063 } 1064 1065 if (p->info_size != 0 && p->info_data == NULL) { 1066 mtx_unlock(&pcb->pcb_mtx); 1067 return (EINVAL); 1068 } 1069 1070 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, 1071 NGM_L2CAP_L2CA_GET_INFO, sizeof(*ip) + p->info_size, 1072 M_NOWAIT); 1073 if (msg == NULL) { 1074 mtx_unlock(&pcb->pcb_mtx); 1075 return (ENOMEM); 1076 } 1077 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 1078 pcb->token = msg->header.token; 1079 pcb->msg = NULL; 1080 1081 ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data); 1082 bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr)); 1083 ip->info_type = p->info_type; 1084 1085 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 1086 pcb->rt->hook, 0); 1087 if (error != 0) { 1088 pcb->token = 0; 1089 mtx_unlock(&pcb->pcb_mtx); 1090 return (error); 1091 } 1092 1093 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl", 1094 bluetooth_l2cap_rtx_timeout()); 1095 pcb->token = 0; 1096 1097 if (error != 0) { 1098 mtx_unlock(&pcb->pcb_mtx); 1099 return (error); 1100 } 1101 1102 msg = pcb->msg; 1103 pcb->msg = NULL; 1104 1105 mtx_unlock(&pcb->pcb_mtx); 1106 1107 if (msg != NULL && 1108 msg->header.cmd == NGM_L2CAP_L2CA_GET_INFO) { 1109 /* Return data back to the user space */ 1110 op = (ng_l2cap_l2ca_get_info_op *)(msg->data); 1111 p->result = op->result; 1112 p->info_size = min(p->info_size, op->info_size); 1113 1114 if (p->info_size > 0) 1115 error = copyout(op + 1, p->info_data, 1116 p->info_size); 1117 } else 1118 error = EINVAL; 1119 1120 NG_FREE_MSG(msg); /* checks for != NULL */ 1121 return (error); 1122 } /* NOTREACHED */ 1123 1124 case SIOC_L2CAP_NODE_GET_AUTO_DISCON_TIMO: { 1125 struct ng_btsocket_l2cap_raw_auto_discon_timo *p = 1126 (struct ng_btsocket_l2cap_raw_auto_discon_timo *) data; 1127 1128 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb, 1129 NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO, 1130 &p->timeout, sizeof(p->timeout)); 1131 } break; 1132 1133 case SIOC_L2CAP_NODE_SET_AUTO_DISCON_TIMO: { 1134 struct ng_btsocket_l2cap_raw_auto_discon_timo *p = 1135 (struct ng_btsocket_l2cap_raw_auto_discon_timo *) data; 1136 1137 if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED) 1138 error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook, 1139 NGM_L2CAP_NODE_SET_AUTO_DISCON_TIMO, 1140 &p->timeout, sizeof(p->timeout)); 1141 else 1142 error = EPERM; 1143 } break; 1144 1145 default: 1146 error = EINVAL; 1147 break; 1148 } 1149 1150 mtx_unlock(&pcb->pcb_mtx); 1151 1152 return (error); 1153 } /* ng_btsocket_l2cap_raw_control */ 1154 1155 /* 1156 * Detach and destroy socket 1157 */ 1158 1159 void 1160 ng_btsocket_l2cap_raw_detach(struct socket *so) 1161 { 1162 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 1163 1164 KASSERT(pcb != NULL, ("nt_btsocket_l2cap_raw_detach: pcb == NULL")); 1165 if (ng_btsocket_l2cap_raw_node == NULL) 1166 return; 1167 1168 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx); 1169 mtx_lock(&pcb->pcb_mtx); 1170 1171 LIST_REMOVE(pcb, next); 1172 1173 mtx_unlock(&pcb->pcb_mtx); 1174 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx); 1175 1176 mtx_destroy(&pcb->pcb_mtx); 1177 1178 bzero(pcb, sizeof(*pcb)); 1179 free(pcb, M_NETGRAPH_BTSOCKET_L2CAP_RAW); 1180 1181 so->so_pcb = NULL; 1182 } /* ng_btsocket_l2cap_raw_detach */ 1183 1184 /* 1185 * Disconnect socket 1186 */ 1187 1188 int 1189 ng_btsocket_l2cap_raw_disconnect(struct socket *so) 1190 { 1191 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 1192 1193 if (pcb == NULL) 1194 return (EINVAL); 1195 if (ng_btsocket_l2cap_raw_node == NULL) 1196 return (EINVAL); 1197 1198 mtx_lock(&pcb->pcb_mtx); 1199 pcb->rt = NULL; 1200 soisdisconnected(so); 1201 mtx_unlock(&pcb->pcb_mtx); 1202 1203 return (0); 1204 } /* ng_btsocket_l2cap_raw_disconnect */ 1205 1206 /* 1207 * Get peer address 1208 */ 1209 1210 int 1211 ng_btsocket_l2cap_raw_peeraddr(struct socket *so, struct sockaddr **nam) 1212 { 1213 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 1214 struct sockaddr_l2cap sa; 1215 1216 if (pcb == NULL) 1217 return (EINVAL); 1218 if (ng_btsocket_l2cap_raw_node == NULL) 1219 return (EINVAL); 1220 1221 mtx_lock(&pcb->pcb_mtx); 1222 bcopy(&pcb->dst, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr)); 1223 mtx_unlock(&pcb->pcb_mtx); 1224 1225 sa.l2cap_psm = 0; 1226 sa.l2cap_len = sizeof(sa); 1227 sa.l2cap_family = AF_BLUETOOTH; 1228 sa.l2cap_cid = 0; 1229 sa.l2cap_bdaddr_type = BDADDR_BREDR; 1230 1231 *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT); 1232 1233 return ((*nam == NULL)? ENOMEM : 0); 1234 } /* ng_btsocket_l2cap_raw_peeraddr */ 1235 1236 /* 1237 * Send data to socket 1238 */ 1239 1240 int 1241 ng_btsocket_l2cap_raw_send(struct socket *so, int flags, struct mbuf *m, 1242 struct sockaddr *nam, struct mbuf *control, struct thread *td) 1243 { 1244 NG_FREE_M(m); /* Checks for m != NULL */ 1245 NG_FREE_M(control); 1246 1247 return (EOPNOTSUPP); 1248 } /* ng_btsocket_l2cap_raw_send */ 1249 1250 /* 1251 * Get socket address 1252 */ 1253 1254 int 1255 ng_btsocket_l2cap_raw_sockaddr(struct socket *so, struct sockaddr **nam) 1256 { 1257 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 1258 struct sockaddr_l2cap sa; 1259 1260 if (pcb == NULL) 1261 return (EINVAL); 1262 if (ng_btsocket_l2cap_raw_node == NULL) 1263 return (EINVAL); 1264 1265 mtx_lock(&pcb->pcb_mtx); 1266 bcopy(&pcb->src, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr)); 1267 mtx_unlock(&pcb->pcb_mtx); 1268 1269 sa.l2cap_psm = 0; 1270 sa.l2cap_len = sizeof(sa); 1271 sa.l2cap_family = AF_BLUETOOTH; 1272 sa.l2cap_cid = 0; 1273 sa.l2cap_bdaddr_type = BDADDR_BREDR; 1274 *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT); 1275 1276 return ((*nam == NULL)? ENOMEM : 0); 1277 } /* ng_btsocket_l2cap_raw_sockaddr */ 1278 1279 /* 1280 * Get next token 1281 */ 1282 1283 static void 1284 ng_btsocket_l2cap_raw_get_token(u_int32_t *token) 1285 { 1286 mtx_lock(&ng_btsocket_l2cap_raw_token_mtx); 1287 1288 if (++ ng_btsocket_l2cap_raw_token == 0) 1289 ng_btsocket_l2cap_raw_token = 1; 1290 1291 *token = ng_btsocket_l2cap_raw_token; 1292 1293 mtx_unlock(&ng_btsocket_l2cap_raw_token_mtx); 1294 } /* ng_btsocket_l2cap_raw_get_token */ 1295 1296 /* 1297 * Send Netgraph message to the node - do not expect reply 1298 */ 1299 1300 static int 1301 ng_btsocket_l2cap_raw_send_ngmsg(hook_p hook, int cmd, void *arg, int arglen) 1302 { 1303 struct ng_mesg *msg = NULL; 1304 int error = 0; 1305 1306 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, arglen, M_NOWAIT); 1307 if (msg == NULL) 1308 return (ENOMEM); 1309 1310 if (arg != NULL && arglen > 0) 1311 bcopy(arg, msg->data, arglen); 1312 1313 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, hook, 0); 1314 1315 return (error); 1316 } /* ng_btsocket_l2cap_raw_send_ngmsg */ 1317 1318 /* 1319 * Send Netgraph message to the node (no data) and wait for reply 1320 */ 1321 1322 static int 1323 ng_btsocket_l2cap_raw_send_sync_ngmsg(ng_btsocket_l2cap_raw_pcb_p pcb, 1324 int cmd, void *rsp, int rsplen) 1325 { 1326 struct ng_mesg *msg = NULL; 1327 int error = 0; 1328 1329 mtx_assert(&pcb->pcb_mtx, MA_OWNED); 1330 1331 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, 0, M_NOWAIT); 1332 if (msg == NULL) 1333 return (ENOMEM); 1334 1335 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 1336 pcb->token = msg->header.token; 1337 pcb->msg = NULL; 1338 1339 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 1340 pcb->rt->hook, 0); 1341 if (error != 0) { 1342 pcb->token = 0; 1343 return (error); 1344 } 1345 1346 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl", 1347 ng_btsocket_l2cap_raw_ioctl_timeout * hz); 1348 pcb->token = 0; 1349 1350 if (error != 0) 1351 return (error); 1352 1353 if (pcb->msg != NULL && pcb->msg->header.cmd == cmd) 1354 bcopy(pcb->msg->data, rsp, rsplen); 1355 else 1356 error = EINVAL; 1357 1358 NG_FREE_MSG(pcb->msg); /* checks for != NULL */ 1359 1360 return (0); 1361 } /* ng_btsocket_l2cap_raw_send_sync_ngmsg */ 1362 1363