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