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