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/caps.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 ng_btsocket_l2cap_raw_node_constructor(node_p node)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 ng_btsocket_l2cap_raw_node_shutdown(node_p node)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 ng_btsocket_l2cap_raw_node_newhook(node_p node,hook_p hook,char const * name)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 ng_btsocket_l2cap_raw_node_connect(hook_p hook)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 ng_btsocket_l2cap_raw_node_disconnect(hook_p hook)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 ng_btsocket_l2cap_raw_node_rcvmsg(node_p node,item_p item,hook_p hook)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 ng_btsocket_l2cap_raw_node_rcvdata(hook_p hook,item_p item)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 ng_btsocket_l2cap_raw_input(void * context,int pending)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 ng_btsocket_l2cap_raw_rtclean(void * context,int pending)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 ng_btsocket_l2cap_raw_init(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 ng_btsocket_l2cap_raw_abort(netmsg_t msg)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 ng_btsocket_l2cap_raw_attach(netmsg_t msg)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 caps_priv_check_self(SYSCAP_NONET_BT_RAW) == 0) 639 { 640 pcb->flags |= NG_BTSOCKET_L2CAP_RAW_PRIVILEGED; 641 } 642 643 lockinit(&pcb->pcb_lock, "btsocks_l2cap_raw_pcb_lock", 0, 0); 644 645 /* Add the PCB to the list */ 646 lockmgr(&ng_btsocket_l2cap_raw_sockets_lock, LK_EXCLUSIVE); 647 LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_sockets, pcb, next); 648 lockmgr(&ng_btsocket_l2cap_raw_sockets_lock, LK_RELEASE); 649 650 out: 651 lwkt_replymsg(&msg->attach.base.lmsg, error); 652 } /* ng_btsocket_l2cap_raw_attach */ 653 654 /* 655 * Bind socket 656 */ 657 658 void ng_btsocket_l2cap_raw_bind(netmsg_t msg)659 ng_btsocket_l2cap_raw_bind(netmsg_t msg) 660 { 661 struct socket *so = msg->bind.base.nm_so; 662 struct sockaddr *nam = msg->bind.nm_nam; 663 ng_btsocket_l2cap_raw_pcb_t *pcb = so2l2cap_raw_pcb(so); 664 struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *) nam; 665 ng_btsocket_l2cap_rtentry_t *rt = NULL; 666 int error = 0; 667 668 if (pcb == NULL) { 669 error = EINVAL; 670 goto out; 671 } 672 if (ng_btsocket_l2cap_raw_node == NULL) { 673 error = EINVAL; 674 goto out; 675 } 676 677 if (sa == NULL) { 678 error = EINVAL; 679 goto out; 680 } 681 if (sa->l2cap_family != AF_BLUETOOTH) { 682 error = EAFNOSUPPORT; 683 goto out; 684 } 685 if (sa->l2cap_len != sizeof(*sa)) { 686 error = EINVAL; 687 goto out; 688 } 689 690 if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, 691 sizeof(sa->l2cap_bdaddr)) != 0) { 692 lockmgr(&ng_btsocket_l2cap_raw_rt_lock, LK_EXCLUSIVE); 693 694 LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) { 695 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook)) 696 continue; 697 698 if (bcmp(&sa->l2cap_bdaddr, &rt->src, 699 sizeof(rt->src)) == 0) 700 break; 701 } 702 703 lockmgr(&ng_btsocket_l2cap_raw_rt_lock, LK_RELEASE); 704 705 if (rt == NULL) { 706 error = ENETDOWN; 707 goto out; 708 } 709 } else 710 rt = NULL; 711 712 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE); 713 bcopy(&sa->l2cap_bdaddr, &pcb->src, sizeof(pcb->src)); 714 pcb->rt = rt; 715 lockmgr(&pcb->pcb_lock, LK_RELEASE); 716 717 out: 718 lwkt_replymsg(&msg->bind.base.lmsg, error); 719 } /* ng_btsocket_l2cap_raw_bind */ 720 721 /* 722 * Connect socket 723 */ 724 725 void ng_btsocket_l2cap_raw_connect(netmsg_t msg)726 ng_btsocket_l2cap_raw_connect(netmsg_t msg) 727 { 728 struct socket *so = msg->connect.base.nm_so; 729 struct sockaddr *nam = msg->connect.nm_nam; 730 ng_btsocket_l2cap_raw_pcb_t *pcb = so2l2cap_raw_pcb(so); 731 struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *) nam; 732 ng_btsocket_l2cap_rtentry_t *rt = NULL; 733 int error = 0; 734 735 if (pcb == NULL) { 736 error = EINVAL; 737 goto out; 738 } 739 if (ng_btsocket_l2cap_raw_node == NULL) { 740 error = EINVAL; 741 goto out; 742 } 743 744 if (sa == NULL) { 745 error = EINVAL; 746 goto out; 747 } 748 if (sa->l2cap_family != AF_BLUETOOTH) { 749 error = EAFNOSUPPORT; 750 goto out; 751 } 752 if (sa->l2cap_len != sizeof(*sa)) { 753 error = EINVAL; 754 goto out; 755 } 756 if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) { 757 error = EINVAL; 758 goto out; 759 } 760 761 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE); 762 763 bcopy(&sa->l2cap_bdaddr, &pcb->dst, sizeof(pcb->dst)); 764 765 if (bcmp(&pcb->src, &pcb->dst, sizeof(pcb->src)) == 0) { 766 lockmgr(&pcb->pcb_lock, LK_RELEASE); 767 error = EADDRNOTAVAIL; 768 goto out; 769 } 770 771 /* 772 * If there is route already - use it 773 */ 774 775 if (pcb->rt != NULL) { 776 soisconnected(so); 777 lockmgr(&pcb->pcb_lock, LK_RELEASE); 778 goto out; 779 } 780 781 /* 782 * Find the first hook that does not match specified destination address 783 */ 784 785 lockmgr(&ng_btsocket_l2cap_raw_rt_lock, LK_EXCLUSIVE); 786 787 LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) { 788 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook)) 789 continue; 790 791 if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0) 792 break; 793 } 794 795 if (rt != NULL) { 796 soisconnected(so); 797 798 pcb->rt = rt; 799 bcopy(&rt->src, &pcb->src, sizeof(pcb->src)); 800 } else 801 error = ENETDOWN; 802 803 lockmgr(&ng_btsocket_l2cap_raw_rt_lock, LK_RELEASE); 804 lockmgr(&pcb->pcb_lock, LK_RELEASE); 805 806 out: 807 lwkt_replymsg(&msg->connect.base.lmsg, error); 808 } /* ng_btsocket_l2cap_raw_connect */ 809 810 /* 811 * Process ioctl's calls on socket 812 */ 813 814 void ng_btsocket_l2cap_raw_control(netmsg_t msg)815 ng_btsocket_l2cap_raw_control(netmsg_t msg) 816 { 817 struct socket *so = msg->control.base.nm_so; 818 u_long cmd = msg->control.nm_cmd; 819 caddr_t data = msg->control.nm_data; 820 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 821 struct ng_mesg *ngmsg = NULL; 822 int error = 0; 823 824 if (pcb == NULL) { 825 error = EINVAL; 826 goto out; 827 } 828 if (ng_btsocket_l2cap_raw_node == NULL) { 829 error = EINVAL; 830 goto out; 831 } 832 833 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE); 834 835 /* Check if we route info */ 836 if (pcb->rt == NULL) { 837 lockmgr(&pcb->pcb_lock, LK_RELEASE); 838 error = EHOSTUNREACH; 839 goto out; 840 } 841 842 /* Check if we have pending ioctl() */ 843 if (pcb->token != 0) { 844 lockmgr(&pcb->pcb_lock, LK_RELEASE); 845 error = EBUSY; 846 goto out; 847 } 848 849 switch (cmd) { 850 case SIOC_L2CAP_NODE_GET_FLAGS: { 851 struct ng_btsocket_l2cap_raw_node_flags *p = 852 (struct ng_btsocket_l2cap_raw_node_flags *) data; 853 854 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb, 855 NGM_L2CAP_NODE_GET_FLAGS, 856 &p->flags, sizeof(p->flags)); 857 } break; 858 859 case SIOC_L2CAP_NODE_GET_DEBUG: { 860 struct ng_btsocket_l2cap_raw_node_debug *p = 861 (struct ng_btsocket_l2cap_raw_node_debug *) data; 862 863 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb, 864 NGM_L2CAP_NODE_GET_DEBUG, 865 &p->debug, sizeof(p->debug)); 866 } break; 867 868 case SIOC_L2CAP_NODE_SET_DEBUG: { 869 struct ng_btsocket_l2cap_raw_node_debug *p = 870 (struct ng_btsocket_l2cap_raw_node_debug *) data; 871 872 if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED) 873 error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook, 874 NGM_L2CAP_NODE_SET_DEBUG, 875 &p->debug, sizeof(p->debug)); 876 else 877 error = EPERM; 878 } break; 879 880 case SIOC_L2CAP_NODE_GET_CON_LIST: { 881 struct ng_btsocket_l2cap_raw_con_list *p = 882 (struct ng_btsocket_l2cap_raw_con_list *) data; 883 ng_l2cap_node_con_list_ep *p1 = NULL; 884 ng_l2cap_node_con_ep *p2 = NULL; 885 886 if (p->num_connections == 0 || 887 p->num_connections > NG_L2CAP_MAX_CON_NUM || 888 p->connections == NULL) { 889 error = EINVAL; 890 break; 891 } 892 893 NG_MKMESSAGE(ngmsg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_GET_CON_LIST, 894 0, M_WAITOK | M_NULLOK); 895 if (ngmsg == NULL) { 896 error = ENOMEM; 897 break; 898 } 899 ng_btsocket_l2cap_raw_get_token(&ngmsg->header.token); 900 pcb->token = ngmsg->header.token; 901 pcb->msg = NULL; 902 903 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, ngmsg, 904 pcb->rt->hook, 0); 905 if (error != 0) { 906 pcb->token = 0; 907 break; 908 } 909 910 error = lksleep(&pcb->msg, &pcb->pcb_lock, PCATCH, "l2ctl", 911 ng_btsocket_l2cap_raw_ioctl_timeout * hz); 912 pcb->token = 0; 913 914 if (error != 0) 915 break; 916 917 if (pcb->msg != NULL && 918 pcb->msg->header.cmd == NGM_L2CAP_NODE_GET_CON_LIST) { 919 /* Return data back to user space */ 920 p1 = (ng_l2cap_node_con_list_ep *)(pcb->msg->data); 921 p2 = (ng_l2cap_node_con_ep *)(p1 + 1); 922 923 p->num_connections = min(p->num_connections, 924 p1->num_connections); 925 if (p->num_connections > 0) 926 error = copyout((caddr_t) p2, 927 (caddr_t) p->connections, 928 p->num_connections * sizeof(*p2)); 929 } else 930 error = EINVAL; 931 932 NG_FREE_MSG(pcb->msg); /* checks for != NULL */ 933 } break; 934 935 case SIOC_L2CAP_NODE_GET_CHAN_LIST: { 936 struct ng_btsocket_l2cap_raw_chan_list *p = 937 (struct ng_btsocket_l2cap_raw_chan_list *) data; 938 ng_l2cap_node_chan_list_ep *p1 = NULL; 939 ng_l2cap_node_chan_ep *p2 = NULL; 940 941 if (p->num_channels == 0 || 942 p->num_channels > NG_L2CAP_MAX_CHAN_NUM || 943 p->channels == NULL) { 944 error = EINVAL; 945 break; 946 } 947 948 NG_MKMESSAGE(ngmsg, NGM_L2CAP_COOKIE, 949 NGM_L2CAP_NODE_GET_CHAN_LIST, 0, M_WAITOK | M_NULLOK); 950 if (ngmsg == NULL) { 951 error = ENOMEM; 952 break; 953 } 954 ng_btsocket_l2cap_raw_get_token(&ngmsg->header.token); 955 pcb->token = ngmsg->header.token; 956 pcb->msg = NULL; 957 958 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, ngmsg, 959 pcb->rt->hook, 0); 960 if (error != 0) { 961 pcb->token = 0; 962 break; 963 } 964 965 error = lksleep(&pcb->msg, &pcb->pcb_lock, PCATCH, "l2ctl", 966 ng_btsocket_l2cap_raw_ioctl_timeout * hz); 967 pcb->token = 0; 968 969 if (error != 0) 970 break; 971 972 if (pcb->msg != NULL && 973 pcb->msg->header.cmd == NGM_L2CAP_NODE_GET_CHAN_LIST) { 974 /* Return data back to user space */ 975 p1 = (ng_l2cap_node_chan_list_ep *)(pcb->msg->data); 976 p2 = (ng_l2cap_node_chan_ep *)(p1 + 1); 977 978 p->num_channels = min(p->num_channels, 979 p1->num_channels); 980 if (p->num_channels > 0) 981 error = copyout((caddr_t) p2, 982 (caddr_t) p->channels, 983 p->num_channels * sizeof(*p2)); 984 } else 985 error = EINVAL; 986 987 NG_FREE_MSG(pcb->msg); /* checks for != NULL */ 988 } break; 989 990 case SIOC_L2CAP_L2CA_PING: { 991 struct ng_btsocket_l2cap_raw_ping *p = 992 (struct ng_btsocket_l2cap_raw_ping *) data; 993 ng_l2cap_l2ca_ping_ip *ip = NULL; 994 ng_l2cap_l2ca_ping_op *op = NULL; 995 996 if (!(pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)) { 997 error = EPERM; 998 break; 999 } 1000 1001 if ((p->echo_size != 0 && p->echo_data == NULL) || 1002 p->echo_size > NG_L2CAP_MAX_ECHO_SIZE) { 1003 error = EINVAL; 1004 break; 1005 } 1006 1007 NG_MKMESSAGE(ngmsg, NGM_L2CAP_COOKIE, 1008 NGM_L2CAP_L2CA_PING, sizeof(*ip) + p->echo_size, 1009 M_WAITOK | M_NULLOK); 1010 if (ngmsg == NULL) { 1011 error = ENOMEM; 1012 break; 1013 } 1014 ng_btsocket_l2cap_raw_get_token(&ngmsg->header.token); 1015 pcb->token = ngmsg->header.token; 1016 pcb->msg = NULL; 1017 1018 ip = (ng_l2cap_l2ca_ping_ip *)(ngmsg->data); 1019 bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr)); 1020 ip->echo_size = p->echo_size; 1021 1022 if (ip->echo_size > 0) { 1023 error = copyin(p->echo_data, ip + 1, p->echo_size); 1024 if (error != 0) { 1025 NG_FREE_MSG(ngmsg); 1026 pcb->token = 0; 1027 break; 1028 } 1029 } 1030 1031 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, ngmsg, 1032 pcb->rt->hook, 0); 1033 if (error != 0) { 1034 pcb->token = 0; 1035 break; 1036 } 1037 1038 error = lksleep(&pcb->msg, &pcb->pcb_lock, PCATCH, "l2ctl", 1039 bluetooth_l2cap_rtx_timeout()); 1040 pcb->token = 0; 1041 1042 if (error != 0) 1043 break; 1044 1045 if (pcb->msg != NULL && 1046 pcb->msg->header.cmd == NGM_L2CAP_L2CA_PING) { 1047 /* Return data back to the user space */ 1048 op = (ng_l2cap_l2ca_ping_op *)(pcb->msg->data); 1049 p->result = op->result; 1050 p->echo_size = min(p->echo_size, op->echo_size); 1051 1052 if (p->echo_size > 0) 1053 error = copyout(op + 1, p->echo_data, 1054 p->echo_size); 1055 } else 1056 error = EINVAL; 1057 1058 NG_FREE_MSG(pcb->msg); /* checks for != NULL */ 1059 } break; 1060 1061 case SIOC_L2CAP_L2CA_GET_INFO: { 1062 struct ng_btsocket_l2cap_raw_get_info *p = 1063 (struct ng_btsocket_l2cap_raw_get_info *) data; 1064 ng_l2cap_l2ca_get_info_ip *ip = NULL; 1065 ng_l2cap_l2ca_get_info_op *op = NULL; 1066 1067 if (!(pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)) { 1068 error = EPERM; 1069 break; 1070 } 1071 1072 if (p->info_size != 0 && p->info_data == NULL) { 1073 error = EINVAL; 1074 break; 1075 } 1076 1077 NG_MKMESSAGE(ngmsg, NGM_L2CAP_COOKIE, 1078 NGM_L2CAP_L2CA_GET_INFO, sizeof(*ip) + p->info_size, 1079 M_WAITOK | M_NULLOK); 1080 if (ngmsg == NULL) { 1081 error = ENOMEM; 1082 break; 1083 } 1084 ng_btsocket_l2cap_raw_get_token(&ngmsg->header.token); 1085 pcb->token = ngmsg->header.token; 1086 pcb->msg = NULL; 1087 1088 ip = (ng_l2cap_l2ca_get_info_ip *)(ngmsg->data); 1089 bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr)); 1090 ip->info_type = p->info_type; 1091 1092 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, ngmsg, 1093 pcb->rt->hook, 0); 1094 if (error != 0) { 1095 pcb->token = 0; 1096 break; 1097 } 1098 1099 error = lksleep(&pcb->msg, &pcb->pcb_lock, PCATCH, "l2ctl", 1100 bluetooth_l2cap_rtx_timeout()); 1101 pcb->token = 0; 1102 1103 if (error != 0) 1104 break; 1105 1106 if (pcb->msg != NULL && 1107 pcb->msg->header.cmd == NGM_L2CAP_L2CA_GET_INFO) { 1108 /* Return data back to the user space */ 1109 op = (ng_l2cap_l2ca_get_info_op *)(pcb->msg->data); 1110 p->result = op->result; 1111 p->info_size = min(p->info_size, op->info_size); 1112 1113 if (p->info_size > 0) 1114 error = copyout(op + 1, p->info_data, 1115 p->info_size); 1116 } else 1117 error = EINVAL; 1118 1119 NG_FREE_MSG(pcb->msg); /* checks for != NULL */ 1120 } break; 1121 1122 case SIOC_L2CAP_NODE_GET_AUTO_DISCON_TIMO: { 1123 struct ng_btsocket_l2cap_raw_auto_discon_timo *p = 1124 (struct ng_btsocket_l2cap_raw_auto_discon_timo *) data; 1125 1126 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb, 1127 NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO, 1128 &p->timeout, sizeof(p->timeout)); 1129 } break; 1130 1131 case SIOC_L2CAP_NODE_SET_AUTO_DISCON_TIMO: { 1132 struct ng_btsocket_l2cap_raw_auto_discon_timo *p = 1133 (struct ng_btsocket_l2cap_raw_auto_discon_timo *) data; 1134 1135 if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED) 1136 error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook, 1137 NGM_L2CAP_NODE_SET_AUTO_DISCON_TIMO, 1138 &p->timeout, sizeof(p->timeout)); 1139 else 1140 error = EPERM; 1141 } break; 1142 1143 default: 1144 error = EINVAL; 1145 break; 1146 } 1147 1148 lockmgr(&pcb->pcb_lock, LK_RELEASE); 1149 1150 out: 1151 lwkt_replymsg(&msg->control.base.lmsg, error); 1152 } /* ng_btsocket_l2cap_raw_control */ 1153 1154 /* 1155 * Detach and destroy socket 1156 */ 1157 1158 void ng_btsocket_l2cap_raw_detach(netmsg_t msg)1159 ng_btsocket_l2cap_raw_detach(netmsg_t msg) 1160 { 1161 struct socket *so = msg->detach.base.nm_so; 1162 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 1163 int error = 0; 1164 1165 KASSERT(pcb != NULL, ("nt_btsocket_l2cap_raw_detach: pcb == NULL")); 1166 if (ng_btsocket_l2cap_raw_node == NULL) 1167 goto out; 1168 1169 lockmgr(&ng_btsocket_l2cap_raw_sockets_lock, LK_EXCLUSIVE); 1170 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE); 1171 1172 LIST_REMOVE(pcb, next); 1173 1174 lockmgr(&pcb->pcb_lock, LK_RELEASE); 1175 lockmgr(&ng_btsocket_l2cap_raw_sockets_lock, LK_RELEASE); 1176 1177 lockuninit(&pcb->pcb_lock); 1178 1179 bzero(pcb, sizeof(*pcb)); 1180 kfree(pcb, M_NETGRAPH_BTSOCKET_L2CAP_RAW); 1181 1182 so->so_pcb = NULL; 1183 1184 out: 1185 lwkt_replymsg(&msg->detach.base.lmsg, error); 1186 } /* ng_btsocket_l2cap_raw_detach */ 1187 1188 /* 1189 * Disconnect socket 1190 */ 1191 1192 void ng_btsocket_l2cap_raw_disconnect(netmsg_t msg)1193 ng_btsocket_l2cap_raw_disconnect(netmsg_t msg) 1194 { 1195 struct socket *so = msg->disconnect.base.nm_so; 1196 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 1197 int error = 0; 1198 1199 if (pcb == NULL) { 1200 error = EINVAL; 1201 goto out; 1202 } 1203 if (ng_btsocket_l2cap_raw_node == NULL) { 1204 error = EINVAL; 1205 goto out; 1206 } 1207 1208 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE); 1209 pcb->rt = NULL; 1210 soisdisconnected(so); 1211 lockmgr(&pcb->pcb_lock, LK_RELEASE); 1212 1213 out: 1214 lwkt_replymsg(&msg->disconnect.base.lmsg, error); 1215 } /* ng_btsocket_l2cap_raw_disconnect */ 1216 1217 /* 1218 * Get peer address 1219 */ 1220 1221 void ng_btsocket_l2cap_raw_peeraddr(netmsg_t msg)1222 ng_btsocket_l2cap_raw_peeraddr(netmsg_t msg) 1223 { 1224 struct socket *so = msg->peeraddr.base.nm_so; 1225 struct sockaddr **nam = msg->peeraddr.nm_nam; 1226 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 1227 struct sockaddr_l2cap sa; 1228 int error = 0; 1229 1230 if (pcb == NULL) { 1231 error = EINVAL; 1232 goto out; 1233 } 1234 if (ng_btsocket_l2cap_raw_node == NULL) { 1235 error = EINVAL; 1236 goto out; 1237 } 1238 1239 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE); 1240 bcopy(&pcb->dst, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr)); 1241 lockmgr(&pcb->pcb_lock, LK_RELEASE); 1242 1243 sa.l2cap_psm = 0; 1244 sa.l2cap_len = sizeof(sa); 1245 sa.l2cap_family = AF_BLUETOOTH; 1246 1247 *nam = dup_sockaddr((struct sockaddr *) &sa); 1248 1249 if (*nam == NULL) 1250 error = ENOMEM; 1251 1252 out: 1253 lwkt_replymsg(&msg->peeraddr.base.lmsg, error); 1254 } /* ng_btsocket_l2cap_raw_peeraddr */ 1255 1256 /* 1257 * Send data to socket 1258 */ 1259 1260 void ng_btsocket_l2cap_raw_send(netmsg_t msg)1261 ng_btsocket_l2cap_raw_send(netmsg_t msg) 1262 { 1263 struct mbuf *control = msg->send.nm_control; 1264 struct mbuf *m = msg->send.nm_m; 1265 1266 NG_FREE_M(m); /* Checks for m != NULL */ 1267 NG_FREE_M(control); 1268 1269 lwkt_replymsg(&msg->send.base.lmsg, EOPNOTSUPP); 1270 } /* ng_btsocket_l2cap_raw_send */ 1271 1272 /* 1273 * Get socket address 1274 */ 1275 1276 void ng_btsocket_l2cap_raw_sockaddr(netmsg_t msg)1277 ng_btsocket_l2cap_raw_sockaddr(netmsg_t msg) 1278 { 1279 struct socket *so = msg->sockaddr.base.nm_so; 1280 struct sockaddr **nam = msg->sockaddr.nm_nam; 1281 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 1282 struct sockaddr_l2cap sa; 1283 int error = 0; 1284 1285 if (pcb == NULL) { 1286 error = EINVAL; 1287 goto out; 1288 } 1289 if (ng_btsocket_l2cap_raw_node == NULL) { 1290 error = EINVAL; 1291 goto out; 1292 } 1293 1294 lockmgr(&pcb->pcb_lock, LK_EXCLUSIVE); 1295 bcopy(&pcb->src, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr)); 1296 lockmgr(&pcb->pcb_lock, LK_RELEASE); 1297 1298 sa.l2cap_psm = 0; 1299 sa.l2cap_len = sizeof(sa); 1300 sa.l2cap_family = AF_BLUETOOTH; 1301 1302 *nam = dup_sockaddr((struct sockaddr *) &sa); 1303 1304 if (*nam == NULL) 1305 error = ENOMEM; 1306 1307 out: 1308 lwkt_replymsg(&msg->sockaddr.base.lmsg, error); 1309 } /* ng_btsocket_l2cap_raw_sockaddr */ 1310 1311 /* 1312 * Get next token 1313 */ 1314 1315 static void ng_btsocket_l2cap_raw_get_token(u_int32_t * token)1316 ng_btsocket_l2cap_raw_get_token(u_int32_t *token) 1317 { 1318 lockmgr(&ng_btsocket_l2cap_raw_token_lock, LK_EXCLUSIVE); 1319 1320 if (++ ng_btsocket_l2cap_raw_token == 0) 1321 ng_btsocket_l2cap_raw_token = 1; 1322 1323 *token = ng_btsocket_l2cap_raw_token; 1324 1325 lockmgr(&ng_btsocket_l2cap_raw_token_lock, LK_RELEASE); 1326 } /* ng_btsocket_l2cap_raw_get_token */ 1327 1328 /* 1329 * Send Netgraph message to the node - do not expect reply 1330 */ 1331 1332 static int ng_btsocket_l2cap_raw_send_ngmsg(hook_p hook,int cmd,void * arg,int arglen)1333 ng_btsocket_l2cap_raw_send_ngmsg(hook_p hook, int cmd, void *arg, int arglen) 1334 { 1335 struct ng_mesg *msg = NULL; 1336 int error = 0; 1337 1338 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, arglen, M_WAITOK | M_NULLOK); 1339 if (msg == NULL) 1340 return (ENOMEM); 1341 1342 if (arg != NULL && arglen > 0) 1343 bcopy(arg, msg->data, arglen); 1344 1345 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, hook, 0); 1346 1347 return (error); 1348 } /* ng_btsocket_l2cap_raw_send_ngmsg */ 1349 1350 /* 1351 * Send Netgraph message to the node (no data) and wait for reply 1352 */ 1353 1354 static int ng_btsocket_l2cap_raw_send_sync_ngmsg(ng_btsocket_l2cap_raw_pcb_p pcb,int cmd,void * rsp,int rsplen)1355 ng_btsocket_l2cap_raw_send_sync_ngmsg(ng_btsocket_l2cap_raw_pcb_p pcb, 1356 int cmd, void *rsp, int rsplen) 1357 { 1358 struct ng_mesg *msg = NULL; 1359 int error = 0; 1360 1361 KKASSERT(lockowned(&pcb->pcb_lock) != 0); 1362 1363 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, 0, M_WAITOK | M_NULLOK); 1364 if (msg == NULL) 1365 return (ENOMEM); 1366 1367 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 1368 pcb->token = msg->header.token; 1369 pcb->msg = NULL; 1370 1371 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 1372 pcb->rt->hook, 0); 1373 if (error != 0) { 1374 pcb->token = 0; 1375 return (error); 1376 } 1377 1378 error = lksleep(&pcb->msg, &pcb->pcb_lock, PCATCH, "l2ctl", 1379 ng_btsocket_l2cap_raw_ioctl_timeout * hz); 1380 pcb->token = 0; 1381 1382 if (error != 0) 1383 return (error); 1384 1385 if (pcb->msg != NULL && pcb->msg->header.cmd == cmd) 1386 bcopy(pcb->msg->data, rsp, rsplen); 1387 else 1388 error = EINVAL; 1389 1390 NG_FREE_MSG(pcb->msg); /* checks for != NULL */ 1391 1392 return (0); 1393 } /* ng_btsocket_l2cap_raw_send_sync_ngmsg */ 1394 1395