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