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, CTLFLAG_RW, 132 0, "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 /* 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 void 517 ng_btsocket_l2cap_raw_init(void) 518 { 519 int error = 0; 520 521 /* Skip initialization of globals for non-default instances. */ 522 if (!IS_DEFAULT_VNET(curvnet)) 523 return; 524 525 ng_btsocket_l2cap_raw_node = NULL; 526 ng_btsocket_l2cap_raw_debug_level = NG_BTSOCKET_WARN_LEVEL; 527 ng_btsocket_l2cap_raw_ioctl_timeout = 5; 528 529 /* Register Netgraph node type */ 530 error = ng_newtype(&typestruct); 531 if (error != 0) { 532 NG_BTSOCKET_L2CAP_RAW_ALERT( 533 "%s: Could not register Netgraph node type, error=%d\n", __func__, error); 534 535 return; 536 } 537 538 /* Create Netgrapg node */ 539 error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_raw_node); 540 if (error != 0) { 541 NG_BTSOCKET_L2CAP_RAW_ALERT( 542 "%s: Could not create Netgraph node, error=%d\n", __func__, error); 543 544 ng_btsocket_l2cap_raw_node = NULL; 545 546 return; 547 } 548 549 error = ng_name_node(ng_btsocket_l2cap_raw_node, 550 NG_BTSOCKET_L2CAP_RAW_NODE_TYPE); 551 if (error != 0) { 552 NG_BTSOCKET_L2CAP_RAW_ALERT( 553 "%s: Could not name Netgraph node, error=%d\n", __func__, error); 554 555 NG_NODE_UNREF(ng_btsocket_l2cap_raw_node); 556 ng_btsocket_l2cap_raw_node = NULL; 557 558 return; 559 } 560 561 /* Create input queue */ 562 NG_BT_ITEMQ_INIT(&ng_btsocket_l2cap_raw_queue, ifqmaxlen); 563 mtx_init(&ng_btsocket_l2cap_raw_queue_mtx, 564 "btsocks_l2cap_raw_queue_mtx", NULL, MTX_DEF); 565 TASK_INIT(&ng_btsocket_l2cap_raw_queue_task, 0, 566 ng_btsocket_l2cap_raw_input, NULL); 567 568 /* Create list of sockets */ 569 LIST_INIT(&ng_btsocket_l2cap_raw_sockets); 570 mtx_init(&ng_btsocket_l2cap_raw_sockets_mtx, 571 "btsocks_l2cap_raw_sockets_mtx", NULL, MTX_DEF); 572 573 /* Tokens */ 574 ng_btsocket_l2cap_raw_token = 0; 575 mtx_init(&ng_btsocket_l2cap_raw_token_mtx, 576 "btsocks_l2cap_raw_token_mtx", NULL, MTX_DEF); 577 578 /* Routing table */ 579 LIST_INIT(&ng_btsocket_l2cap_raw_rt); 580 mtx_init(&ng_btsocket_l2cap_raw_rt_mtx, 581 "btsocks_l2cap_raw_rt_mtx", NULL, MTX_DEF); 582 TASK_INIT(&ng_btsocket_l2cap_raw_rt_task, 0, 583 ng_btsocket_l2cap_raw_rtclean, NULL); 584 } /* ng_btsocket_l2cap_raw_init */ 585 586 /* 587 * Abort connection on socket 588 */ 589 590 void 591 ng_btsocket_l2cap_raw_abort(struct socket *so) 592 { 593 594 (void)ng_btsocket_l2cap_raw_disconnect(so); 595 } /* ng_btsocket_l2cap_raw_abort */ 596 597 void 598 ng_btsocket_l2cap_raw_close(struct socket *so) 599 { 600 601 (void)ng_btsocket_l2cap_raw_disconnect(so); 602 } /* ng_btsocket_l2cap_raw_close */ 603 604 /* 605 * Create and attach new socket 606 */ 607 608 int 609 ng_btsocket_l2cap_raw_attach(struct socket *so, int proto, struct thread *td) 610 { 611 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 612 int error; 613 614 if (pcb != NULL) 615 return (EISCONN); 616 617 if (ng_btsocket_l2cap_raw_node == NULL) 618 return (EPROTONOSUPPORT); 619 if (so->so_type != SOCK_RAW) 620 return (ESOCKTNOSUPPORT); 621 622 /* Reserve send and receive space if it is not reserved yet */ 623 error = soreserve(so, NG_BTSOCKET_L2CAP_RAW_SENDSPACE, 624 NG_BTSOCKET_L2CAP_RAW_RECVSPACE); 625 if (error != 0) 626 return (error); 627 628 /* Allocate the PCB */ 629 pcb = malloc(sizeof(*pcb), 630 M_NETGRAPH_BTSOCKET_L2CAP_RAW, M_NOWAIT|M_ZERO); 631 if (pcb == NULL) 632 return (ENOMEM); 633 634 /* Link the PCB and the socket */ 635 so->so_pcb = (caddr_t) pcb; 636 pcb->so = so; 637 638 if (priv_check(td, PRIV_NETBLUETOOTH_RAW) == 0) 639 pcb->flags |= NG_BTSOCKET_L2CAP_RAW_PRIVILEGED; 640 641 mtx_init(&pcb->pcb_mtx, "btsocks_l2cap_raw_pcb_mtx", NULL, MTX_DEF); 642 643 /* Add the PCB to the list */ 644 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx); 645 LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_sockets, pcb, next); 646 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx); 647 648 return (0); 649 } /* ng_btsocket_l2cap_raw_attach */ 650 651 /* 652 * Bind socket 653 */ 654 655 int 656 ng_btsocket_l2cap_raw_bind(struct socket *so, struct sockaddr *nam, 657 struct thread *td) 658 { 659 ng_btsocket_l2cap_raw_pcb_t *pcb = so2l2cap_raw_pcb(so); 660 struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *) nam; 661 ng_btsocket_l2cap_rtentry_t *rt = NULL; 662 663 if (pcb == NULL) 664 return (EINVAL); 665 if (ng_btsocket_l2cap_raw_node == NULL) 666 return (EINVAL); 667 668 if (sa == NULL) 669 return (EINVAL); 670 if (sa->l2cap_family != AF_BLUETOOTH) 671 return (EAFNOSUPPORT); 672 if((sa->l2cap_len != sizeof(*sa))&& 673 (sa->l2cap_len != sizeof(struct sockaddr_l2cap_compat))) 674 return (EINVAL); 675 676 if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, 677 sizeof(sa->l2cap_bdaddr)) != 0) { 678 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx); 679 680 LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) { 681 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook)) 682 continue; 683 684 if (bcmp(&sa->l2cap_bdaddr, &rt->src, 685 sizeof(rt->src)) == 0) 686 break; 687 } 688 689 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx); 690 691 if (rt == NULL) 692 return (ENETDOWN); 693 } else 694 rt = NULL; 695 696 mtx_lock(&pcb->pcb_mtx); 697 bcopy(&sa->l2cap_bdaddr, &pcb->src, sizeof(pcb->src)); 698 pcb->rt = rt; 699 mtx_unlock(&pcb->pcb_mtx); 700 701 return (0); 702 } /* ng_btsocket_l2cap_raw_bind */ 703 704 /* 705 * Connect socket 706 */ 707 708 int 709 ng_btsocket_l2cap_raw_connect(struct socket *so, struct sockaddr *nam, 710 struct thread *td) 711 { 712 ng_btsocket_l2cap_raw_pcb_t *pcb = so2l2cap_raw_pcb(so); 713 struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *) nam; 714 ng_btsocket_l2cap_rtentry_t *rt = NULL; 715 int error; 716 717 if (pcb == NULL) 718 return (EINVAL); 719 if (ng_btsocket_l2cap_raw_node == NULL) 720 return (EINVAL); 721 722 if (sa == NULL) 723 return (EINVAL); 724 if (sa->l2cap_family != AF_BLUETOOTH) 725 return (EAFNOSUPPORT); 726 if((sa->l2cap_len != sizeof(*sa))&& 727 (sa->l2cap_len != sizeof(struct sockaddr_l2cap_compat))) 728 return (EINVAL); 729 730 if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) 731 return (EINVAL); 732 733 mtx_lock(&pcb->pcb_mtx); 734 735 bcopy(&sa->l2cap_bdaddr, &pcb->dst, sizeof(pcb->dst)); 736 737 if (bcmp(&pcb->src, &pcb->dst, sizeof(pcb->src)) == 0) { 738 mtx_unlock(&pcb->pcb_mtx); 739 740 return (EADDRNOTAVAIL); 741 } 742 743 /* 744 * If there is route already - use it 745 */ 746 747 if (pcb->rt != NULL) { 748 soisconnected(so); 749 mtx_unlock(&pcb->pcb_mtx); 750 751 return (0); 752 } 753 754 /* 755 * Find the first hook that does not match specified destination address 756 */ 757 758 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx); 759 760 LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) { 761 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook)) 762 continue; 763 764 if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0) 765 break; 766 } 767 768 if (rt != NULL) { 769 soisconnected(so); 770 771 pcb->rt = rt; 772 bcopy(&rt->src, &pcb->src, sizeof(pcb->src)); 773 774 error = 0; 775 } else 776 error = ENETDOWN; 777 778 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx); 779 mtx_unlock(&pcb->pcb_mtx); 780 781 return (error); 782 } /* ng_btsocket_l2cap_raw_connect */ 783 784 /* 785 * Process ioctl's calls on socket 786 */ 787 788 int 789 ng_btsocket_l2cap_raw_control(struct socket *so, u_long cmd, caddr_t data, 790 struct ifnet *ifp, struct thread *td) 791 { 792 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 793 struct ng_mesg *msg = NULL; 794 int error = 0; 795 796 if (pcb == NULL) 797 return (EINVAL); 798 if (ng_btsocket_l2cap_raw_node == NULL) 799 return (EINVAL); 800 801 mtx_lock(&pcb->pcb_mtx); 802 803 /* Check if we route info */ 804 if (pcb->rt == NULL) { 805 mtx_unlock(&pcb->pcb_mtx); 806 return (EHOSTUNREACH); 807 } 808 809 /* Check if we have pending ioctl() */ 810 if (pcb->token != 0) { 811 mtx_unlock(&pcb->pcb_mtx); 812 return (EBUSY); 813 } 814 815 switch (cmd) { 816 case SIOC_L2CAP_NODE_GET_FLAGS: { 817 struct ng_btsocket_l2cap_raw_node_flags *p = 818 (struct ng_btsocket_l2cap_raw_node_flags *) data; 819 820 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb, 821 NGM_L2CAP_NODE_GET_FLAGS, 822 &p->flags, sizeof(p->flags)); 823 } break; 824 825 case SIOC_L2CAP_NODE_GET_DEBUG: { 826 struct ng_btsocket_l2cap_raw_node_debug *p = 827 (struct ng_btsocket_l2cap_raw_node_debug *) data; 828 829 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb, 830 NGM_L2CAP_NODE_GET_DEBUG, 831 &p->debug, sizeof(p->debug)); 832 } break; 833 834 case SIOC_L2CAP_NODE_SET_DEBUG: { 835 struct ng_btsocket_l2cap_raw_node_debug *p = 836 (struct ng_btsocket_l2cap_raw_node_debug *) data; 837 838 if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED) 839 error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook, 840 NGM_L2CAP_NODE_SET_DEBUG, 841 &p->debug, sizeof(p->debug)); 842 else 843 error = EPERM; 844 } break; 845 846 case SIOC_L2CAP_NODE_GET_CON_LIST: { 847 struct ng_btsocket_l2cap_raw_con_list *p = 848 (struct ng_btsocket_l2cap_raw_con_list *) data; 849 ng_l2cap_node_con_list_ep *p1 = NULL; 850 ng_l2cap_node_con_ep *p2 = NULL; 851 852 if (p->num_connections == 0 || 853 p->num_connections > NG_L2CAP_MAX_CON_NUM || 854 p->connections == NULL) { 855 error = EINVAL; 856 break; 857 } 858 859 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_GET_CON_LIST, 860 0, M_NOWAIT); 861 if (msg == NULL) { 862 error = ENOMEM; 863 break; 864 } 865 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 866 pcb->token = msg->header.token; 867 pcb->msg = NULL; 868 869 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 870 pcb->rt->hook, 0); 871 if (error != 0) { 872 pcb->token = 0; 873 break; 874 } 875 876 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl", 877 ng_btsocket_l2cap_raw_ioctl_timeout * hz); 878 pcb->token = 0; 879 880 if (error != 0) 881 break; 882 883 if (pcb->msg != NULL && 884 pcb->msg->header.cmd == NGM_L2CAP_NODE_GET_CON_LIST) { 885 /* Return data back to user space */ 886 p1 = (ng_l2cap_node_con_list_ep *)(pcb->msg->data); 887 p2 = (ng_l2cap_node_con_ep *)(p1 + 1); 888 889 p->num_connections = min(p->num_connections, 890 p1->num_connections); 891 if (p->num_connections > 0) 892 error = copyout((caddr_t) p2, 893 (caddr_t) p->connections, 894 p->num_connections * sizeof(*p2)); 895 } else 896 error = EINVAL; 897 898 NG_FREE_MSG(pcb->msg); /* checks for != NULL */ 899 } break; 900 901 case SIOC_L2CAP_NODE_GET_CHAN_LIST: { 902 struct ng_btsocket_l2cap_raw_chan_list *p = 903 (struct ng_btsocket_l2cap_raw_chan_list *) data; 904 ng_l2cap_node_chan_list_ep *p1 = NULL; 905 ng_l2cap_node_chan_ep *p2 = NULL; 906 907 if (p->num_channels == 0 || 908 p->num_channels > NG_L2CAP_MAX_CHAN_NUM || 909 p->channels == NULL) { 910 error = EINVAL; 911 break; 912 } 913 914 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, 915 NGM_L2CAP_NODE_GET_CHAN_LIST, 0, M_NOWAIT); 916 if (msg == NULL) { 917 error = ENOMEM; 918 break; 919 } 920 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 921 pcb->token = msg->header.token; 922 pcb->msg = NULL; 923 924 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 925 pcb->rt->hook, 0); 926 if (error != 0) { 927 pcb->token = 0; 928 break; 929 } 930 931 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl", 932 ng_btsocket_l2cap_raw_ioctl_timeout * hz); 933 pcb->token = 0; 934 935 if (error != 0) 936 break; 937 938 if (pcb->msg != NULL && 939 pcb->msg->header.cmd == NGM_L2CAP_NODE_GET_CHAN_LIST) { 940 /* Return data back to user space */ 941 p1 = (ng_l2cap_node_chan_list_ep *)(pcb->msg->data); 942 p2 = (ng_l2cap_node_chan_ep *)(p1 + 1); 943 944 p->num_channels = min(p->num_channels, 945 p1->num_channels); 946 if (p->num_channels > 0) 947 error = copyout((caddr_t) p2, 948 (caddr_t) p->channels, 949 p->num_channels * sizeof(*p2)); 950 } else 951 error = EINVAL; 952 953 NG_FREE_MSG(pcb->msg); /* checks for != NULL */ 954 } break; 955 956 case SIOC_L2CAP_L2CA_PING: { 957 struct ng_btsocket_l2cap_raw_ping *p = 958 (struct ng_btsocket_l2cap_raw_ping *) data; 959 ng_l2cap_l2ca_ping_ip *ip = NULL; 960 ng_l2cap_l2ca_ping_op *op = NULL; 961 962 if ((p->echo_size != 0 && p->echo_data == NULL) || 963 p->echo_size > NG_L2CAP_MAX_ECHO_SIZE) { 964 error = EINVAL; 965 break; 966 } 967 968 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, 969 NGM_L2CAP_L2CA_PING, sizeof(*ip) + p->echo_size, 970 M_NOWAIT); 971 if (msg == NULL) { 972 error = ENOMEM; 973 break; 974 } 975 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 976 pcb->token = msg->header.token; 977 pcb->msg = NULL; 978 979 ip = (ng_l2cap_l2ca_ping_ip *)(msg->data); 980 bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr)); 981 ip->echo_size = p->echo_size; 982 983 if (ip->echo_size > 0) { 984 error = copyin(p->echo_data, ip + 1, p->echo_size); 985 if (error != 0) { 986 NG_FREE_MSG(msg); 987 pcb->token = 0; 988 break; 989 } 990 } 991 992 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 993 pcb->rt->hook, 0); 994 if (error != 0) { 995 pcb->token = 0; 996 break; 997 } 998 999 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl", 1000 bluetooth_l2cap_rtx_timeout()); 1001 pcb->token = 0; 1002 1003 if (error != 0) 1004 break; 1005 1006 if (pcb->msg != NULL && 1007 pcb->msg->header.cmd == NGM_L2CAP_L2CA_PING) { 1008 /* Return data back to the user space */ 1009 op = (ng_l2cap_l2ca_ping_op *)(pcb->msg->data); 1010 p->result = op->result; 1011 p->echo_size = min(p->echo_size, op->echo_size); 1012 1013 if (p->echo_size > 0) 1014 error = copyout(op + 1, p->echo_data, 1015 p->echo_size); 1016 } else 1017 error = EINVAL; 1018 1019 NG_FREE_MSG(pcb->msg); /* checks for != NULL */ 1020 } break; 1021 1022 case SIOC_L2CAP_L2CA_GET_INFO: { 1023 struct ng_btsocket_l2cap_raw_get_info *p = 1024 (struct ng_btsocket_l2cap_raw_get_info *) data; 1025 ng_l2cap_l2ca_get_info_ip *ip = NULL; 1026 ng_l2cap_l2ca_get_info_op *op = NULL; 1027 1028 if (!(pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)) { 1029 error = EPERM; 1030 break; 1031 } 1032 1033 if (p->info_size != 0 && p->info_data == NULL) { 1034 error = EINVAL; 1035 break; 1036 } 1037 1038 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, 1039 NGM_L2CAP_L2CA_GET_INFO, sizeof(*ip) + p->info_size, 1040 M_NOWAIT); 1041 if (msg == NULL) { 1042 error = ENOMEM; 1043 break; 1044 } 1045 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 1046 pcb->token = msg->header.token; 1047 pcb->msg = NULL; 1048 1049 ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data); 1050 bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr)); 1051 ip->info_type = p->info_type; 1052 1053 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 1054 pcb->rt->hook, 0); 1055 if (error != 0) { 1056 pcb->token = 0; 1057 break; 1058 } 1059 1060 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl", 1061 bluetooth_l2cap_rtx_timeout()); 1062 pcb->token = 0; 1063 1064 if (error != 0) 1065 break; 1066 1067 if (pcb->msg != NULL && 1068 pcb->msg->header.cmd == NGM_L2CAP_L2CA_GET_INFO) { 1069 /* Return data back to the user space */ 1070 op = (ng_l2cap_l2ca_get_info_op *)(pcb->msg->data); 1071 p->result = op->result; 1072 p->info_size = min(p->info_size, op->info_size); 1073 1074 if (p->info_size > 0) 1075 error = copyout(op + 1, p->info_data, 1076 p->info_size); 1077 } else 1078 error = EINVAL; 1079 1080 NG_FREE_MSG(pcb->msg); /* checks for != NULL */ 1081 } break; 1082 1083 case SIOC_L2CAP_NODE_GET_AUTO_DISCON_TIMO: { 1084 struct ng_btsocket_l2cap_raw_auto_discon_timo *p = 1085 (struct ng_btsocket_l2cap_raw_auto_discon_timo *) data; 1086 1087 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb, 1088 NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO, 1089 &p->timeout, sizeof(p->timeout)); 1090 } break; 1091 1092 case SIOC_L2CAP_NODE_SET_AUTO_DISCON_TIMO: { 1093 struct ng_btsocket_l2cap_raw_auto_discon_timo *p = 1094 (struct ng_btsocket_l2cap_raw_auto_discon_timo *) data; 1095 1096 if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED) 1097 error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook, 1098 NGM_L2CAP_NODE_SET_AUTO_DISCON_TIMO, 1099 &p->timeout, sizeof(p->timeout)); 1100 else 1101 error = EPERM; 1102 } break; 1103 1104 default: 1105 error = EINVAL; 1106 break; 1107 } 1108 1109 mtx_unlock(&pcb->pcb_mtx); 1110 1111 return (error); 1112 } /* ng_btsocket_l2cap_raw_control */ 1113 1114 /* 1115 * Detach and destroy socket 1116 */ 1117 1118 void 1119 ng_btsocket_l2cap_raw_detach(struct socket *so) 1120 { 1121 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 1122 1123 KASSERT(pcb != NULL, ("nt_btsocket_l2cap_raw_detach: pcb == NULL")); 1124 if (ng_btsocket_l2cap_raw_node == NULL) 1125 return; 1126 1127 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx); 1128 mtx_lock(&pcb->pcb_mtx); 1129 1130 LIST_REMOVE(pcb, next); 1131 1132 mtx_unlock(&pcb->pcb_mtx); 1133 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx); 1134 1135 mtx_destroy(&pcb->pcb_mtx); 1136 1137 bzero(pcb, sizeof(*pcb)); 1138 free(pcb, M_NETGRAPH_BTSOCKET_L2CAP_RAW); 1139 1140 so->so_pcb = NULL; 1141 } /* ng_btsocket_l2cap_raw_detach */ 1142 1143 /* 1144 * Disconnect socket 1145 */ 1146 1147 int 1148 ng_btsocket_l2cap_raw_disconnect(struct socket *so) 1149 { 1150 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 1151 1152 if (pcb == NULL) 1153 return (EINVAL); 1154 if (ng_btsocket_l2cap_raw_node == NULL) 1155 return (EINVAL); 1156 1157 mtx_lock(&pcb->pcb_mtx); 1158 pcb->rt = NULL; 1159 soisdisconnected(so); 1160 mtx_unlock(&pcb->pcb_mtx); 1161 1162 return (0); 1163 } /* ng_btsocket_l2cap_raw_disconnect */ 1164 1165 /* 1166 * Get peer address 1167 */ 1168 1169 int 1170 ng_btsocket_l2cap_raw_peeraddr(struct socket *so, struct sockaddr **nam) 1171 { 1172 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 1173 struct sockaddr_l2cap sa; 1174 1175 if (pcb == NULL) 1176 return (EINVAL); 1177 if (ng_btsocket_l2cap_raw_node == NULL) 1178 return (EINVAL); 1179 1180 mtx_lock(&pcb->pcb_mtx); 1181 bcopy(&pcb->dst, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr)); 1182 mtx_unlock(&pcb->pcb_mtx); 1183 1184 sa.l2cap_psm = 0; 1185 sa.l2cap_len = sizeof(sa); 1186 sa.l2cap_family = AF_BLUETOOTH; 1187 sa.l2cap_cid = 0; 1188 sa.l2cap_bdaddr_type = BDADDR_BREDR; 1189 1190 *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT); 1191 1192 return ((*nam == NULL)? ENOMEM : 0); 1193 } /* ng_btsocket_l2cap_raw_peeraddr */ 1194 1195 /* 1196 * Send data to socket 1197 */ 1198 1199 int 1200 ng_btsocket_l2cap_raw_send(struct socket *so, int flags, struct mbuf *m, 1201 struct sockaddr *nam, struct mbuf *control, struct thread *td) 1202 { 1203 NG_FREE_M(m); /* Checks for m != NULL */ 1204 NG_FREE_M(control); 1205 1206 return (EOPNOTSUPP); 1207 } /* ng_btsocket_l2cap_raw_send */ 1208 1209 /* 1210 * Get socket address 1211 */ 1212 1213 int 1214 ng_btsocket_l2cap_raw_sockaddr(struct socket *so, struct sockaddr **nam) 1215 { 1216 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 1217 struct sockaddr_l2cap sa; 1218 1219 if (pcb == NULL) 1220 return (EINVAL); 1221 if (ng_btsocket_l2cap_raw_node == NULL) 1222 return (EINVAL); 1223 1224 mtx_lock(&pcb->pcb_mtx); 1225 bcopy(&pcb->src, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr)); 1226 mtx_unlock(&pcb->pcb_mtx); 1227 1228 sa.l2cap_psm = 0; 1229 sa.l2cap_len = sizeof(sa); 1230 sa.l2cap_family = AF_BLUETOOTH; 1231 sa.l2cap_cid = 0; 1232 sa.l2cap_bdaddr_type = BDADDR_BREDR; 1233 *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT); 1234 1235 return ((*nam == NULL)? ENOMEM : 0); 1236 } /* ng_btsocket_l2cap_raw_sockaddr */ 1237 1238 /* 1239 * Get next token 1240 */ 1241 1242 static void 1243 ng_btsocket_l2cap_raw_get_token(u_int32_t *token) 1244 { 1245 mtx_lock(&ng_btsocket_l2cap_raw_token_mtx); 1246 1247 if (++ ng_btsocket_l2cap_raw_token == 0) 1248 ng_btsocket_l2cap_raw_token = 1; 1249 1250 *token = ng_btsocket_l2cap_raw_token; 1251 1252 mtx_unlock(&ng_btsocket_l2cap_raw_token_mtx); 1253 } /* ng_btsocket_l2cap_raw_get_token */ 1254 1255 /* 1256 * Send Netgraph message to the node - do not expect reply 1257 */ 1258 1259 static int 1260 ng_btsocket_l2cap_raw_send_ngmsg(hook_p hook, int cmd, void *arg, int arglen) 1261 { 1262 struct ng_mesg *msg = NULL; 1263 int error = 0; 1264 1265 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, arglen, M_NOWAIT); 1266 if (msg == NULL) 1267 return (ENOMEM); 1268 1269 if (arg != NULL && arglen > 0) 1270 bcopy(arg, msg->data, arglen); 1271 1272 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, hook, 0); 1273 1274 return (error); 1275 } /* ng_btsocket_l2cap_raw_send_ngmsg */ 1276 1277 /* 1278 * Send Netgraph message to the node (no data) and wait for reply 1279 */ 1280 1281 static int 1282 ng_btsocket_l2cap_raw_send_sync_ngmsg(ng_btsocket_l2cap_raw_pcb_p pcb, 1283 int cmd, void *rsp, int rsplen) 1284 { 1285 struct ng_mesg *msg = NULL; 1286 int error = 0; 1287 1288 mtx_assert(&pcb->pcb_mtx, MA_OWNED); 1289 1290 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, 0, M_NOWAIT); 1291 if (msg == NULL) 1292 return (ENOMEM); 1293 1294 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 1295 pcb->token = msg->header.token; 1296 pcb->msg = NULL; 1297 1298 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 1299 pcb->rt->hook, 0); 1300 if (error != 0) { 1301 pcb->token = 0; 1302 return (error); 1303 } 1304 1305 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl", 1306 ng_btsocket_l2cap_raw_ioctl_timeout * hz); 1307 pcb->token = 0; 1308 1309 if (error != 0) 1310 return (error); 1311 1312 if (pcb->msg != NULL && pcb->msg->header.cmd == cmd) 1313 bcopy(pcb->msg->data, rsp, rsplen); 1314 else 1315 error = EINVAL; 1316 1317 NG_FREE_MSG(pcb->msg); /* checks for != NULL */ 1318 1319 return (0); 1320 } /* ng_btsocket_l2cap_raw_send_sync_ngmsg */ 1321 1322