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