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 * NGM_L2CAP_NODE_HOOK_INFO is special message initiated by 288 * L2CAP layer. Ignore all other messages if they are not 289 * replies or token is zero 290 */ 291 292 if (msg->header.cmd != NGM_L2CAP_NODE_HOOK_INFO) { 293 if (msg->header.token == 0 || 294 !(msg->header.flags & NGF_RESP)) { 295 NG_FREE_ITEM(item); 296 return (0); 297 } 298 } 299 300 mtx_lock(&ng_btsocket_l2cap_raw_queue_mtx); 301 if (NG_BT_ITEMQ_FULL(&ng_btsocket_l2cap_raw_queue)) { 302 NG_BTSOCKET_L2CAP_RAW_ERR( 303 "%s: Input queue is full\n", __func__); 304 305 NG_BT_ITEMQ_DROP(&ng_btsocket_l2cap_raw_queue); 306 NG_FREE_ITEM(item); 307 error = ENOBUFS; 308 } else { 309 if (hook != NULL) { 310 NG_HOOK_REF(hook); 311 NGI_SET_HOOK(item, hook); 312 } 313 314 NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_l2cap_raw_queue, item); 315 error = ng_btsocket_l2cap_raw_wakeup_input_task(); 316 } 317 mtx_unlock(&ng_btsocket_l2cap_raw_queue_mtx); 318 } else { 319 NG_FREE_ITEM(item); 320 error = EINVAL; 321 } 322 323 return (error); 324 } /* ng_btsocket_l2cap_raw_node_rcvmsg */ 325 326 /* 327 * Receive data on a hook 328 */ 329 330 static int 331 ng_btsocket_l2cap_raw_node_rcvdata(hook_p hook, item_p item) 332 { 333 NG_FREE_ITEM(item); 334 335 return (EINVAL); 336 } /* ng_btsocket_l2cap_raw_node_rcvdata */ 337 338 /***************************************************************************** 339 ***************************************************************************** 340 ** Socket interface 341 ***************************************************************************** 342 *****************************************************************************/ 343 344 /* 345 * L2CAP sockets input routine 346 */ 347 348 static void 349 ng_btsocket_l2cap_raw_input(void *context, int pending) 350 { 351 item_p item = NULL; 352 hook_p hook = NULL; 353 struct ng_mesg *msg = NULL; 354 355 for (;;) { 356 mtx_lock(&ng_btsocket_l2cap_raw_queue_mtx); 357 NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_l2cap_raw_queue, item); 358 mtx_unlock(&ng_btsocket_l2cap_raw_queue_mtx); 359 360 if (item == NULL) 361 break; 362 363 KASSERT((item->el_flags & NGQF_TYPE) == NGQF_MESG, 364 ("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE))); 365 366 NGI_GET_MSG(item, msg); 367 NGI_GET_HOOK(item, hook); 368 NG_FREE_ITEM(item); 369 370 switch (msg->header.cmd) { 371 case NGM_L2CAP_NODE_HOOK_INFO: { 372 ng_btsocket_l2cap_rtentry_t *rt = NULL; 373 374 if (hook == NULL || NG_HOOK_NOT_VALID(hook) || 375 msg->header.arglen != sizeof(bdaddr_t)) 376 break; 377 378 if (bcmp(msg->data, NG_HCI_BDADDR_ANY, 379 sizeof(bdaddr_t)) == 0) 380 break; 381 382 rt = (ng_btsocket_l2cap_rtentry_t *) 383 NG_HOOK_PRIVATE(hook); 384 if (rt == NULL) { 385 rt = malloc(sizeof(*rt), 386 M_NETGRAPH_BTSOCKET_L2CAP_RAW, 387 M_NOWAIT|M_ZERO); 388 if (rt == NULL) 389 break; 390 391 NG_HOOK_SET_PRIVATE(hook, rt); 392 393 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx); 394 395 LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_rt, 396 rt, next); 397 } else 398 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx); 399 400 bcopy(msg->data, &rt->src, sizeof(rt->src)); 401 rt->hook = hook; 402 403 NG_BTSOCKET_L2CAP_RAW_INFO( 404 "%s: Updating hook \"%s\", src bdaddr=%x:%x:%x:%x:%x:%x\n", 405 __func__, NG_HOOK_NAME(hook), 406 rt->src.b[5], rt->src.b[4], rt->src.b[3], 407 rt->src.b[2], rt->src.b[1], rt->src.b[0]); 408 409 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx); 410 } break; 411 412 case NGM_L2CAP_NODE_GET_FLAGS: 413 case NGM_L2CAP_NODE_GET_DEBUG: 414 case NGM_L2CAP_NODE_GET_CON_LIST: 415 case NGM_L2CAP_NODE_GET_CHAN_LIST: 416 case NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO: 417 case NGM_L2CAP_L2CA_PING: 418 case NGM_L2CAP_L2CA_GET_INFO: { 419 ng_btsocket_l2cap_raw_pcb_p pcb = NULL; 420 421 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx); 422 423 LIST_FOREACH(pcb,&ng_btsocket_l2cap_raw_sockets,next) { 424 mtx_lock(&pcb->pcb_mtx); 425 426 if (pcb->token == msg->header.token) { 427 pcb->msg = msg; 428 msg = NULL; 429 wakeup(&pcb->msg); 430 mtx_unlock(&pcb->pcb_mtx); 431 break; 432 } 433 434 mtx_unlock(&pcb->pcb_mtx); 435 } 436 437 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx); 438 } break; 439 440 default: 441 NG_BTSOCKET_L2CAP_RAW_WARN( 442 "%s: Unknown message, cmd=%d\n", __func__, msg->header.cmd); 443 break; 444 } 445 446 if (hook != NULL) 447 NG_HOOK_UNREF(hook); /* remove extra reference */ 448 449 NG_FREE_MSG(msg); /* Checks for msg != NULL */ 450 } 451 } /* ng_btsocket_l2cap_raw_input */ 452 453 /* 454 * Route cleanup task. Gets scheduled when hook is disconnected. Here we 455 * will find all sockets that use "invalid" hook and disconnect them. 456 */ 457 458 static void 459 ng_btsocket_l2cap_raw_rtclean(void *context, int pending) 460 { 461 ng_btsocket_l2cap_raw_pcb_p pcb = NULL; 462 ng_btsocket_l2cap_rtentry_p rt = NULL; 463 464 /* 465 * First disconnect all sockets that use "invalid" hook 466 */ 467 468 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx); 469 470 LIST_FOREACH(pcb, &ng_btsocket_l2cap_raw_sockets, next) { 471 mtx_lock(&pcb->pcb_mtx); 472 473 if (pcb->rt != NULL && 474 pcb->rt->hook != NULL && NG_HOOK_NOT_VALID(pcb->rt->hook)) { 475 if (pcb->so != NULL && 476 pcb->so->so_state & SS_ISCONNECTED) 477 soisdisconnected(pcb->so); 478 479 pcb->rt = NULL; 480 } 481 482 mtx_unlock(&pcb->pcb_mtx); 483 } 484 485 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx); 486 487 /* 488 * Now cleanup routing table 489 */ 490 491 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx); 492 493 for (rt = LIST_FIRST(&ng_btsocket_l2cap_raw_rt); rt != NULL; ) { 494 ng_btsocket_l2cap_rtentry_p rt_next = LIST_NEXT(rt, next); 495 496 if (rt->hook != NULL && NG_HOOK_NOT_VALID(rt->hook)) { 497 LIST_REMOVE(rt, next); 498 499 NG_HOOK_SET_PRIVATE(rt->hook, NULL); 500 NG_HOOK_UNREF(rt->hook); /* Remove extra reference */ 501 502 bzero(rt, sizeof(*rt)); 503 free(rt, M_NETGRAPH_BTSOCKET_L2CAP_RAW); 504 } 505 506 rt = rt_next; 507 } 508 509 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx); 510 } /* ng_btsocket_l2cap_raw_rtclean */ 511 512 /* 513 * Initialize everything 514 */ 515 516 static void 517 ng_btsocket_l2cap_raw_init(void *arg __unused) 518 { 519 int error = 0; 520 521 ng_btsocket_l2cap_raw_node = NULL; 522 ng_btsocket_l2cap_raw_debug_level = NG_BTSOCKET_WARN_LEVEL; 523 ng_btsocket_l2cap_raw_ioctl_timeout = 5; 524 525 /* Register Netgraph node type */ 526 error = ng_newtype(&typestruct); 527 if (error != 0) { 528 NG_BTSOCKET_L2CAP_RAW_ALERT( 529 "%s: Could not register Netgraph node type, error=%d\n", __func__, error); 530 531 return; 532 } 533 534 /* Create Netgrapg node */ 535 error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_raw_node); 536 if (error != 0) { 537 NG_BTSOCKET_L2CAP_RAW_ALERT( 538 "%s: Could not create Netgraph node, error=%d\n", __func__, error); 539 540 ng_btsocket_l2cap_raw_node = NULL; 541 542 return; 543 } 544 545 error = ng_name_node(ng_btsocket_l2cap_raw_node, 546 NG_BTSOCKET_L2CAP_RAW_NODE_TYPE); 547 if (error != 0) { 548 NG_BTSOCKET_L2CAP_RAW_ALERT( 549 "%s: Could not name Netgraph node, error=%d\n", __func__, error); 550 551 NG_NODE_UNREF(ng_btsocket_l2cap_raw_node); 552 ng_btsocket_l2cap_raw_node = NULL; 553 554 return; 555 } 556 557 /* Create input queue */ 558 NG_BT_ITEMQ_INIT(&ng_btsocket_l2cap_raw_queue, ifqmaxlen); 559 mtx_init(&ng_btsocket_l2cap_raw_queue_mtx, 560 "btsocks_l2cap_raw_queue_mtx", NULL, MTX_DEF); 561 TASK_INIT(&ng_btsocket_l2cap_raw_queue_task, 0, 562 ng_btsocket_l2cap_raw_input, NULL); 563 564 /* Create list of sockets */ 565 LIST_INIT(&ng_btsocket_l2cap_raw_sockets); 566 mtx_init(&ng_btsocket_l2cap_raw_sockets_mtx, 567 "btsocks_l2cap_raw_sockets_mtx", NULL, MTX_DEF); 568 569 /* Tokens */ 570 ng_btsocket_l2cap_raw_token = 0; 571 mtx_init(&ng_btsocket_l2cap_raw_token_mtx, 572 "btsocks_l2cap_raw_token_mtx", NULL, MTX_DEF); 573 574 /* Routing table */ 575 LIST_INIT(&ng_btsocket_l2cap_raw_rt); 576 mtx_init(&ng_btsocket_l2cap_raw_rt_mtx, 577 "btsocks_l2cap_raw_rt_mtx", NULL, MTX_DEF); 578 TASK_INIT(&ng_btsocket_l2cap_raw_rt_task, 0, 579 ng_btsocket_l2cap_raw_rtclean, NULL); 580 } /* ng_btsocket_l2cap_raw_init */ 581 SYSINIT(ng_btsocket_l2cap_raw_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, 582 ng_btsocket_l2cap_raw_init, NULL); 583 584 /* 585 * Abort connection on socket 586 */ 587 588 void 589 ng_btsocket_l2cap_raw_abort(struct socket *so) 590 { 591 592 (void)ng_btsocket_l2cap_raw_disconnect(so); 593 } /* ng_btsocket_l2cap_raw_abort */ 594 595 void 596 ng_btsocket_l2cap_raw_close(struct socket *so) 597 { 598 599 (void)ng_btsocket_l2cap_raw_disconnect(so); 600 } /* ng_btsocket_l2cap_raw_close */ 601 602 /* 603 * Create and attach new socket 604 */ 605 606 int 607 ng_btsocket_l2cap_raw_attach(struct socket *so, int proto, struct thread *td) 608 { 609 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 610 int error; 611 612 if (pcb != NULL) 613 return (EISCONN); 614 615 if (ng_btsocket_l2cap_raw_node == NULL) 616 return (EPROTONOSUPPORT); 617 if (so->so_type != SOCK_RAW) 618 return (ESOCKTNOSUPPORT); 619 620 /* Reserve send and receive space if it is not reserved yet */ 621 error = soreserve(so, NG_BTSOCKET_L2CAP_RAW_SENDSPACE, 622 NG_BTSOCKET_L2CAP_RAW_RECVSPACE); 623 if (error != 0) 624 return (error); 625 626 /* Allocate the PCB */ 627 pcb = malloc(sizeof(*pcb), 628 M_NETGRAPH_BTSOCKET_L2CAP_RAW, M_NOWAIT|M_ZERO); 629 if (pcb == NULL) 630 return (ENOMEM); 631 632 /* Link the PCB and the socket */ 633 so->so_pcb = (caddr_t) pcb; 634 pcb->so = so; 635 636 if (priv_check(td, PRIV_NETBLUETOOTH_RAW) == 0) 637 pcb->flags |= NG_BTSOCKET_L2CAP_RAW_PRIVILEGED; 638 639 mtx_init(&pcb->pcb_mtx, "btsocks_l2cap_raw_pcb_mtx", NULL, MTX_DEF); 640 641 /* Add the PCB to the list */ 642 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx); 643 LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_sockets, pcb, next); 644 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx); 645 646 return (0); 647 } /* ng_btsocket_l2cap_raw_attach */ 648 649 /* 650 * Bind socket 651 */ 652 653 int 654 ng_btsocket_l2cap_raw_bind(struct socket *so, struct sockaddr *nam, 655 struct thread *td) 656 { 657 ng_btsocket_l2cap_raw_pcb_t *pcb = so2l2cap_raw_pcb(so); 658 struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *) nam; 659 ng_btsocket_l2cap_rtentry_t *rt = NULL; 660 661 if (pcb == NULL) 662 return (EINVAL); 663 if (ng_btsocket_l2cap_raw_node == NULL) 664 return (EINVAL); 665 666 if (sa == NULL) 667 return (EINVAL); 668 if (sa->l2cap_family != AF_BLUETOOTH) 669 return (EAFNOSUPPORT); 670 if((sa->l2cap_len != sizeof(*sa))&& 671 (sa->l2cap_len != sizeof(struct sockaddr_l2cap_compat))) 672 return (EINVAL); 673 674 if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, 675 sizeof(sa->l2cap_bdaddr)) != 0) { 676 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx); 677 678 LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) { 679 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook)) 680 continue; 681 682 if (bcmp(&sa->l2cap_bdaddr, &rt->src, 683 sizeof(rt->src)) == 0) 684 break; 685 } 686 687 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx); 688 689 if (rt == NULL) 690 return (ENETDOWN); 691 } else 692 rt = NULL; 693 694 mtx_lock(&pcb->pcb_mtx); 695 bcopy(&sa->l2cap_bdaddr, &pcb->src, sizeof(pcb->src)); 696 pcb->rt = rt; 697 mtx_unlock(&pcb->pcb_mtx); 698 699 return (0); 700 } /* ng_btsocket_l2cap_raw_bind */ 701 702 /* 703 * Connect socket 704 */ 705 706 int 707 ng_btsocket_l2cap_raw_connect(struct socket *so, struct sockaddr *nam, 708 struct thread *td) 709 { 710 ng_btsocket_l2cap_raw_pcb_t *pcb = so2l2cap_raw_pcb(so); 711 struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *) nam; 712 ng_btsocket_l2cap_rtentry_t *rt = NULL; 713 int error; 714 715 if (pcb == NULL) 716 return (EINVAL); 717 if (ng_btsocket_l2cap_raw_node == NULL) 718 return (EINVAL); 719 720 if (sa == NULL) 721 return (EINVAL); 722 if (sa->l2cap_family != AF_BLUETOOTH) 723 return (EAFNOSUPPORT); 724 if((sa->l2cap_len != sizeof(*sa))&& 725 (sa->l2cap_len != sizeof(struct sockaddr_l2cap_compat))) 726 return (EINVAL); 727 728 if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) 729 return (EINVAL); 730 731 mtx_lock(&pcb->pcb_mtx); 732 733 bcopy(&sa->l2cap_bdaddr, &pcb->dst, sizeof(pcb->dst)); 734 735 if (bcmp(&pcb->src, &pcb->dst, sizeof(pcb->src)) == 0) { 736 mtx_unlock(&pcb->pcb_mtx); 737 738 return (EADDRNOTAVAIL); 739 } 740 741 /* 742 * If there is route already - use it 743 */ 744 745 if (pcb->rt != NULL) { 746 soisconnected(so); 747 mtx_unlock(&pcb->pcb_mtx); 748 749 return (0); 750 } 751 752 /* 753 * Find the first hook that does not match specified destination address 754 */ 755 756 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx); 757 758 LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) { 759 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook)) 760 continue; 761 762 if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0) 763 break; 764 } 765 766 if (rt != NULL) { 767 soisconnected(so); 768 769 pcb->rt = rt; 770 bcopy(&rt->src, &pcb->src, sizeof(pcb->src)); 771 772 error = 0; 773 } else 774 error = ENETDOWN; 775 776 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx); 777 mtx_unlock(&pcb->pcb_mtx); 778 779 return (error); 780 } /* ng_btsocket_l2cap_raw_connect */ 781 782 /* 783 * Process ioctl's calls on socket 784 */ 785 786 int 787 ng_btsocket_l2cap_raw_control(struct socket *so, u_long cmd, void *data, 788 struct ifnet *ifp, struct thread *td) 789 { 790 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 791 struct ng_mesg *msg = NULL; 792 int error = 0; 793 794 if (pcb == NULL) 795 return (EINVAL); 796 if (ng_btsocket_l2cap_raw_node == NULL) 797 return (EINVAL); 798 799 mtx_lock(&pcb->pcb_mtx); 800 801 /* Check if we route info */ 802 if (pcb->rt == NULL) { 803 mtx_unlock(&pcb->pcb_mtx); 804 return (EHOSTUNREACH); 805 } 806 807 /* Check if we have pending ioctl() */ 808 if (pcb->token != 0) { 809 mtx_unlock(&pcb->pcb_mtx); 810 return (EBUSY); 811 } 812 813 switch (cmd) { 814 case SIOC_L2CAP_NODE_GET_FLAGS: { 815 struct ng_btsocket_l2cap_raw_node_flags *p = 816 (struct ng_btsocket_l2cap_raw_node_flags *) data; 817 818 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb, 819 NGM_L2CAP_NODE_GET_FLAGS, 820 &p->flags, sizeof(p->flags)); 821 } break; 822 823 case SIOC_L2CAP_NODE_GET_DEBUG: { 824 struct ng_btsocket_l2cap_raw_node_debug *p = 825 (struct ng_btsocket_l2cap_raw_node_debug *) data; 826 827 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb, 828 NGM_L2CAP_NODE_GET_DEBUG, 829 &p->debug, sizeof(p->debug)); 830 } break; 831 832 case SIOC_L2CAP_NODE_SET_DEBUG: { 833 struct ng_btsocket_l2cap_raw_node_debug *p = 834 (struct ng_btsocket_l2cap_raw_node_debug *) data; 835 836 if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED) 837 error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook, 838 NGM_L2CAP_NODE_SET_DEBUG, 839 &p->debug, sizeof(p->debug)); 840 else 841 error = EPERM; 842 } break; 843 844 case SIOC_L2CAP_NODE_GET_CON_LIST: { 845 struct ng_btsocket_l2cap_raw_con_list *p = 846 (struct ng_btsocket_l2cap_raw_con_list *) data; 847 ng_l2cap_node_con_list_ep *p1 = NULL; 848 ng_l2cap_node_con_ep *p2 = NULL; 849 850 if (p->num_connections == 0 || 851 p->num_connections > NG_L2CAP_MAX_CON_NUM || 852 p->connections == NULL) { 853 mtx_unlock(&pcb->pcb_mtx); 854 return (EINVAL); 855 } 856 857 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_GET_CON_LIST, 858 0, M_NOWAIT); 859 if (msg == NULL) { 860 mtx_unlock(&pcb->pcb_mtx); 861 return (ENOMEM); 862 } 863 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 864 pcb->token = msg->header.token; 865 pcb->msg = NULL; 866 867 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 868 pcb->rt->hook, 0); 869 if (error != 0) { 870 pcb->token = 0; 871 mtx_unlock(&pcb->pcb_mtx); 872 return (error); 873 } 874 875 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl", 876 ng_btsocket_l2cap_raw_ioctl_timeout * hz); 877 pcb->token = 0; 878 879 if (error != 0) { 880 mtx_unlock(&pcb->pcb_mtx); 881 return (error); 882 } 883 884 msg = pcb->msg; 885 pcb->msg = NULL; 886 887 mtx_unlock(&pcb->pcb_mtx); 888 889 if (msg != NULL && 890 msg->header.cmd == NGM_L2CAP_NODE_GET_CON_LIST) { 891 /* Return data back to user space */ 892 p1 = (ng_l2cap_node_con_list_ep *)(msg->data); 893 p2 = (ng_l2cap_node_con_ep *)(p1 + 1); 894 895 p->num_connections = min(p->num_connections, 896 p1->num_connections); 897 if (p->num_connections > 0) 898 error = copyout((caddr_t) p2, 899 (caddr_t) p->connections, 900 p->num_connections * sizeof(*p2)); 901 } else 902 error = EINVAL; 903 904 NG_FREE_MSG(msg); /* checks for != NULL */ 905 return (error); 906 } /* NOTREACHED */ 907 908 case SIOC_L2CAP_NODE_GET_CHAN_LIST: { 909 struct ng_btsocket_l2cap_raw_chan_list *p = 910 (struct ng_btsocket_l2cap_raw_chan_list *) data; 911 ng_l2cap_node_chan_list_ep *p1 = NULL; 912 ng_l2cap_node_chan_ep *p2 = NULL; 913 914 if (p->num_channels == 0 || 915 p->num_channels > NG_L2CAP_MAX_CHAN_NUM || 916 p->channels == NULL) { 917 mtx_unlock(&pcb->pcb_mtx); 918 return (EINVAL); 919 } 920 921 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, 922 NGM_L2CAP_NODE_GET_CHAN_LIST, 0, M_NOWAIT); 923 if (msg == NULL) { 924 mtx_unlock(&pcb->pcb_mtx); 925 return (ENOMEM); 926 } 927 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 928 pcb->token = msg->header.token; 929 pcb->msg = NULL; 930 931 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 932 pcb->rt->hook, 0); 933 if (error != 0) { 934 pcb->token = 0; 935 mtx_unlock(&pcb->pcb_mtx); 936 return (error); 937 } 938 939 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl", 940 ng_btsocket_l2cap_raw_ioctl_timeout * hz); 941 pcb->token = 0; 942 943 if (error != 0) { 944 mtx_unlock(&pcb->pcb_mtx); 945 return (error); 946 } 947 948 msg = pcb->msg; 949 pcb->msg = NULL; 950 951 mtx_unlock(&pcb->pcb_mtx); 952 953 if (msg != NULL && 954 msg->header.cmd == NGM_L2CAP_NODE_GET_CHAN_LIST) { 955 /* Return data back to user space */ 956 p1 = (ng_l2cap_node_chan_list_ep *)(msg->data); 957 p2 = (ng_l2cap_node_chan_ep *)(p1 + 1); 958 959 p->num_channels = min(p->num_channels, 960 p1->num_channels); 961 if (p->num_channels > 0) 962 error = copyout((caddr_t) p2, 963 (caddr_t) p->channels, 964 p->num_channels * sizeof(*p2)); 965 } else 966 error = EINVAL; 967 968 NG_FREE_MSG(msg); /* checks for != NULL */ 969 return (error); 970 } /* NOTREACHED */ 971 972 case SIOC_L2CAP_L2CA_PING: { 973 struct ng_btsocket_l2cap_raw_ping *p = 974 (struct ng_btsocket_l2cap_raw_ping *) data; 975 ng_l2cap_l2ca_ping_ip *ip = NULL; 976 ng_l2cap_l2ca_ping_op *op = NULL; 977 978 if ((p->echo_size != 0 && p->echo_data == NULL) || 979 p->echo_size > NG_L2CAP_MAX_ECHO_SIZE) { 980 mtx_unlock(&pcb->pcb_mtx); 981 return (EINVAL); 982 } 983 984 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, 985 NGM_L2CAP_L2CA_PING, sizeof(*ip) + p->echo_size, 986 M_NOWAIT); 987 if (msg == NULL) { 988 mtx_unlock(&pcb->pcb_mtx); 989 return (ENOMEM); 990 } 991 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 992 pcb->token = msg->header.token; 993 pcb->msg = NULL; 994 995 ip = (ng_l2cap_l2ca_ping_ip *)(msg->data); 996 bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr)); 997 ip->echo_size = p->echo_size; 998 999 if (ip->echo_size > 0) { 1000 mtx_unlock(&pcb->pcb_mtx); 1001 error = copyin(p->echo_data, ip + 1, p->echo_size); 1002 mtx_lock(&pcb->pcb_mtx); 1003 1004 if (error != 0) { 1005 NG_FREE_MSG(msg); 1006 pcb->token = 0; 1007 mtx_unlock(&pcb->pcb_mtx); 1008 return (error); 1009 } 1010 } 1011 1012 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 1013 pcb->rt->hook, 0); 1014 if (error != 0) { 1015 pcb->token = 0; 1016 mtx_unlock(&pcb->pcb_mtx); 1017 return (error); 1018 } 1019 1020 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl", 1021 bluetooth_l2cap_rtx_timeout()); 1022 pcb->token = 0; 1023 1024 if (error != 0) { 1025 mtx_unlock(&pcb->pcb_mtx); 1026 return (error); 1027 } 1028 1029 msg = pcb->msg; 1030 pcb->msg = NULL; 1031 1032 mtx_unlock(&pcb->pcb_mtx); 1033 1034 if (msg != NULL && 1035 msg->header.cmd == NGM_L2CAP_L2CA_PING) { 1036 /* Return data back to the user space */ 1037 op = (ng_l2cap_l2ca_ping_op *)(msg->data); 1038 p->result = op->result; 1039 p->echo_size = min(p->echo_size, op->echo_size); 1040 1041 if (p->echo_size > 0) 1042 error = copyout(op + 1, p->echo_data, 1043 p->echo_size); 1044 } else 1045 error = EINVAL; 1046 1047 NG_FREE_MSG(msg); /* checks for != NULL */ 1048 return (error); 1049 } /* NOTREACHED */ 1050 1051 case SIOC_L2CAP_L2CA_GET_INFO: { 1052 struct ng_btsocket_l2cap_raw_get_info *p = 1053 (struct ng_btsocket_l2cap_raw_get_info *) data; 1054 ng_l2cap_l2ca_get_info_ip *ip = NULL; 1055 ng_l2cap_l2ca_get_info_op *op = NULL; 1056 1057 if (!(pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)) { 1058 mtx_unlock(&pcb->pcb_mtx); 1059 return (EPERM); 1060 } 1061 1062 if (p->info_size != 0 && p->info_data == NULL) { 1063 mtx_unlock(&pcb->pcb_mtx); 1064 return (EINVAL); 1065 } 1066 1067 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, 1068 NGM_L2CAP_L2CA_GET_INFO, sizeof(*ip) + p->info_size, 1069 M_NOWAIT); 1070 if (msg == NULL) { 1071 mtx_unlock(&pcb->pcb_mtx); 1072 return (ENOMEM); 1073 } 1074 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 1075 pcb->token = msg->header.token; 1076 pcb->msg = NULL; 1077 1078 ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data); 1079 bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr)); 1080 ip->info_type = p->info_type; 1081 1082 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 1083 pcb->rt->hook, 0); 1084 if (error != 0) { 1085 pcb->token = 0; 1086 mtx_unlock(&pcb->pcb_mtx); 1087 return (error); 1088 } 1089 1090 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl", 1091 bluetooth_l2cap_rtx_timeout()); 1092 pcb->token = 0; 1093 1094 if (error != 0) { 1095 mtx_unlock(&pcb->pcb_mtx); 1096 return (error); 1097 } 1098 1099 msg = pcb->msg; 1100 pcb->msg = NULL; 1101 1102 mtx_unlock(&pcb->pcb_mtx); 1103 1104 if (msg != NULL && 1105 msg->header.cmd == NGM_L2CAP_L2CA_GET_INFO) { 1106 /* Return data back to the user space */ 1107 op = (ng_l2cap_l2ca_get_info_op *)(msg->data); 1108 p->result = op->result; 1109 p->info_size = min(p->info_size, op->info_size); 1110 1111 if (p->info_size > 0) 1112 error = copyout(op + 1, p->info_data, 1113 p->info_size); 1114 } else 1115 error = EINVAL; 1116 1117 NG_FREE_MSG(msg); /* checks for != NULL */ 1118 return (error); 1119 } /* NOTREACHED */ 1120 1121 case SIOC_L2CAP_NODE_GET_AUTO_DISCON_TIMO: { 1122 struct ng_btsocket_l2cap_raw_auto_discon_timo *p = 1123 (struct ng_btsocket_l2cap_raw_auto_discon_timo *) data; 1124 1125 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb, 1126 NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO, 1127 &p->timeout, sizeof(p->timeout)); 1128 } break; 1129 1130 case SIOC_L2CAP_NODE_SET_AUTO_DISCON_TIMO: { 1131 struct ng_btsocket_l2cap_raw_auto_discon_timo *p = 1132 (struct ng_btsocket_l2cap_raw_auto_discon_timo *) data; 1133 1134 if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED) 1135 error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook, 1136 NGM_L2CAP_NODE_SET_AUTO_DISCON_TIMO, 1137 &p->timeout, sizeof(p->timeout)); 1138 else 1139 error = EPERM; 1140 } break; 1141 1142 default: 1143 error = EINVAL; 1144 break; 1145 } 1146 1147 mtx_unlock(&pcb->pcb_mtx); 1148 1149 return (error); 1150 } /* ng_btsocket_l2cap_raw_control */ 1151 1152 /* 1153 * Detach and destroy socket 1154 */ 1155 1156 void 1157 ng_btsocket_l2cap_raw_detach(struct socket *so) 1158 { 1159 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 1160 1161 KASSERT(pcb != NULL, ("nt_btsocket_l2cap_raw_detach: pcb == NULL")); 1162 if (ng_btsocket_l2cap_raw_node == NULL) 1163 return; 1164 1165 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx); 1166 mtx_lock(&pcb->pcb_mtx); 1167 1168 LIST_REMOVE(pcb, next); 1169 1170 mtx_unlock(&pcb->pcb_mtx); 1171 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx); 1172 1173 mtx_destroy(&pcb->pcb_mtx); 1174 1175 bzero(pcb, sizeof(*pcb)); 1176 free(pcb, M_NETGRAPH_BTSOCKET_L2CAP_RAW); 1177 1178 so->so_pcb = NULL; 1179 } /* ng_btsocket_l2cap_raw_detach */ 1180 1181 /* 1182 * Disconnect socket 1183 */ 1184 1185 int 1186 ng_btsocket_l2cap_raw_disconnect(struct socket *so) 1187 { 1188 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 1189 1190 if (pcb == NULL) 1191 return (EINVAL); 1192 if (ng_btsocket_l2cap_raw_node == NULL) 1193 return (EINVAL); 1194 1195 mtx_lock(&pcb->pcb_mtx); 1196 pcb->rt = NULL; 1197 soisdisconnected(so); 1198 mtx_unlock(&pcb->pcb_mtx); 1199 1200 return (0); 1201 } /* ng_btsocket_l2cap_raw_disconnect */ 1202 1203 /* 1204 * Get peer address 1205 */ 1206 1207 int 1208 ng_btsocket_l2cap_raw_peeraddr(struct socket *so, struct sockaddr **nam) 1209 { 1210 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 1211 struct sockaddr_l2cap sa; 1212 1213 if (pcb == NULL) 1214 return (EINVAL); 1215 if (ng_btsocket_l2cap_raw_node == NULL) 1216 return (EINVAL); 1217 1218 mtx_lock(&pcb->pcb_mtx); 1219 bcopy(&pcb->dst, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr)); 1220 mtx_unlock(&pcb->pcb_mtx); 1221 1222 sa.l2cap_psm = 0; 1223 sa.l2cap_len = sizeof(sa); 1224 sa.l2cap_family = AF_BLUETOOTH; 1225 sa.l2cap_cid = 0; 1226 sa.l2cap_bdaddr_type = BDADDR_BREDR; 1227 1228 *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT); 1229 1230 return ((*nam == NULL)? ENOMEM : 0); 1231 } /* ng_btsocket_l2cap_raw_peeraddr */ 1232 1233 /* 1234 * Send data to socket 1235 */ 1236 1237 int 1238 ng_btsocket_l2cap_raw_send(struct socket *so, int flags, struct mbuf *m, 1239 struct sockaddr *nam, struct mbuf *control, struct thread *td) 1240 { 1241 NG_FREE_M(m); /* Checks for m != NULL */ 1242 NG_FREE_M(control); 1243 1244 return (EOPNOTSUPP); 1245 } /* ng_btsocket_l2cap_raw_send */ 1246 1247 /* 1248 * Get socket address 1249 */ 1250 1251 int 1252 ng_btsocket_l2cap_raw_sockaddr(struct socket *so, struct sockaddr **nam) 1253 { 1254 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 1255 struct sockaddr_l2cap sa; 1256 1257 if (pcb == NULL) 1258 return (EINVAL); 1259 if (ng_btsocket_l2cap_raw_node == NULL) 1260 return (EINVAL); 1261 1262 mtx_lock(&pcb->pcb_mtx); 1263 bcopy(&pcb->src, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr)); 1264 mtx_unlock(&pcb->pcb_mtx); 1265 1266 sa.l2cap_psm = 0; 1267 sa.l2cap_len = sizeof(sa); 1268 sa.l2cap_family = AF_BLUETOOTH; 1269 sa.l2cap_cid = 0; 1270 sa.l2cap_bdaddr_type = BDADDR_BREDR; 1271 *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT); 1272 1273 return ((*nam == NULL)? ENOMEM : 0); 1274 } /* ng_btsocket_l2cap_raw_sockaddr */ 1275 1276 /* 1277 * Get next token 1278 */ 1279 1280 static void 1281 ng_btsocket_l2cap_raw_get_token(u_int32_t *token) 1282 { 1283 mtx_lock(&ng_btsocket_l2cap_raw_token_mtx); 1284 1285 if (++ ng_btsocket_l2cap_raw_token == 0) 1286 ng_btsocket_l2cap_raw_token = 1; 1287 1288 *token = ng_btsocket_l2cap_raw_token; 1289 1290 mtx_unlock(&ng_btsocket_l2cap_raw_token_mtx); 1291 } /* ng_btsocket_l2cap_raw_get_token */ 1292 1293 /* 1294 * Send Netgraph message to the node - do not expect reply 1295 */ 1296 1297 static int 1298 ng_btsocket_l2cap_raw_send_ngmsg(hook_p hook, int cmd, void *arg, int arglen) 1299 { 1300 struct ng_mesg *msg = NULL; 1301 int error = 0; 1302 1303 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, arglen, M_NOWAIT); 1304 if (msg == NULL) 1305 return (ENOMEM); 1306 1307 if (arg != NULL && arglen > 0) 1308 bcopy(arg, msg->data, arglen); 1309 1310 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, hook, 0); 1311 1312 return (error); 1313 } /* ng_btsocket_l2cap_raw_send_ngmsg */ 1314 1315 /* 1316 * Send Netgraph message to the node (no data) and wait for reply 1317 */ 1318 1319 static int 1320 ng_btsocket_l2cap_raw_send_sync_ngmsg(ng_btsocket_l2cap_raw_pcb_p pcb, 1321 int cmd, void *rsp, int rsplen) 1322 { 1323 struct ng_mesg *msg = NULL; 1324 int error = 0; 1325 1326 mtx_assert(&pcb->pcb_mtx, MA_OWNED); 1327 1328 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, 0, M_NOWAIT); 1329 if (msg == NULL) 1330 return (ENOMEM); 1331 1332 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 1333 pcb->token = msg->header.token; 1334 pcb->msg = NULL; 1335 1336 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 1337 pcb->rt->hook, 0); 1338 if (error != 0) { 1339 pcb->token = 0; 1340 return (error); 1341 } 1342 1343 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl", 1344 ng_btsocket_l2cap_raw_ioctl_timeout * hz); 1345 pcb->token = 0; 1346 1347 if (error != 0) 1348 return (error); 1349 1350 if (pcb->msg != NULL && pcb->msg->header.cmd == cmd) 1351 bcopy(pcb->msg->data, rsp, rsplen); 1352 else 1353 error = EINVAL; 1354 1355 NG_FREE_MSG(pcb->msg); /* checks for != NULL */ 1356 1357 return (0); 1358 } /* ng_btsocket_l2cap_raw_send_sync_ngmsg */ 1359