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