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