1 /* 2 * ng_btsocket_l2cap_raw.c 3 * 4 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $Id: ng_btsocket_l2cap_raw.c,v 1.12 2003/09/14 23:29:06 max Exp $ 29 * $FreeBSD$ 30 */ 31 32 #include <sys/param.h> 33 #include <sys/systm.h> 34 #include <sys/bitstring.h> 35 #include <sys/domain.h> 36 #include <sys/errno.h> 37 #include <sys/filedesc.h> 38 #include <sys/ioccom.h> 39 #include <sys/kernel.h> 40 #include <sys/lock.h> 41 #include <sys/malloc.h> 42 #include <sys/mbuf.h> 43 #include <sys/mutex.h> 44 #include <sys/protosw.h> 45 #include <sys/queue.h> 46 #include <sys/socket.h> 47 #include <sys/socketvar.h> 48 #include <sys/sysctl.h> 49 #include <sys/taskqueue.h> 50 #include <netgraph/ng_message.h> 51 #include <netgraph/netgraph.h> 52 #include <netgraph/bluetooth/include/ng_bluetooth.h> 53 #include <netgraph/bluetooth/include/ng_hci.h> 54 #include <netgraph/bluetooth/include/ng_l2cap.h> 55 #include <netgraph/bluetooth/include/ng_btsocket.h> 56 #include <netgraph/bluetooth/include/ng_btsocket_l2cap.h> 57 58 /* MALLOC define */ 59 #ifdef NG_SEPARATE_MALLOC 60 MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_L2CAP_RAW, "netgraph_btsocks_l2cap_raw", 61 "Netgraph Bluetooth raw L2CAP sockets"); 62 #else 63 #define M_NETGRAPH_BTSOCKET_L2CAP_RAW M_NETGRAPH 64 #endif /* NG_SEPARATE_MALLOC */ 65 66 /* Netgraph node methods */ 67 static ng_constructor_t ng_btsocket_l2cap_raw_node_constructor; 68 static ng_rcvmsg_t ng_btsocket_l2cap_raw_node_rcvmsg; 69 static ng_shutdown_t ng_btsocket_l2cap_raw_node_shutdown; 70 static ng_newhook_t ng_btsocket_l2cap_raw_node_newhook; 71 static ng_connect_t ng_btsocket_l2cap_raw_node_connect; 72 static ng_rcvdata_t ng_btsocket_l2cap_raw_node_rcvdata; 73 static ng_disconnect_t ng_btsocket_l2cap_raw_node_disconnect; 74 75 static void ng_btsocket_l2cap_raw_input (void *, int); 76 static void ng_btsocket_l2cap_raw_rtclean (void *, int); 77 static void ng_btsocket_l2cap_raw_get_token (u_int32_t *); 78 79 static int ng_btsocket_l2cap_raw_send_ngmsg 80 (hook_p, int, void *, int); 81 static int ng_btsocket_l2cap_raw_send_sync_ngmsg 82 (ng_btsocket_l2cap_raw_pcb_p, int, void *, int); 83 84 #define ng_btsocket_l2cap_raw_wakeup_input_task() \ 85 taskqueue_enqueue(taskqueue_swi_giant, &ng_btsocket_l2cap_raw_queue_task) 86 87 #define ng_btsocket_l2cap_raw_wakeup_route_task() \ 88 taskqueue_enqueue(taskqueue_swi_giant, &ng_btsocket_l2cap_raw_rt_task) 89 90 /* Netgraph type descriptor */ 91 static struct ng_type typestruct = { 92 NG_ABI_VERSION, 93 NG_BTSOCKET_L2CAP_RAW_NODE_TYPE, /* typename */ 94 NULL, /* modevent */ 95 ng_btsocket_l2cap_raw_node_constructor, /* constructor */ 96 ng_btsocket_l2cap_raw_node_rcvmsg, /* control message */ 97 ng_btsocket_l2cap_raw_node_shutdown, /* destructor */ 98 ng_btsocket_l2cap_raw_node_newhook, /* new hook */ 99 NULL, /* find hook */ 100 ng_btsocket_l2cap_raw_node_connect, /* connect hook */ 101 ng_btsocket_l2cap_raw_node_rcvdata, /* data */ 102 ng_btsocket_l2cap_raw_node_disconnect, /* disconnect hook */ 103 NULL /* node command list */ 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 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx); 372 373 rt = (ng_btsocket_l2cap_rtentry_t *) 374 NG_HOOK_PRIVATE(hook); 375 if (rt == NULL) { 376 MALLOC(rt, ng_btsocket_l2cap_rtentry_p, 377 sizeof(*rt), 378 M_NETGRAPH_BTSOCKET_L2CAP_RAW, 379 M_NOWAIT|M_ZERO); 380 if (rt == NULL) { 381 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx); 382 break; 383 } 384 385 LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_rt, 386 rt, next); 387 388 NG_HOOK_SET_PRIVATE(hook, rt); 389 } 390 391 bcopy(msg->data, &rt->src, sizeof(rt->src)); 392 rt->hook = hook; 393 394 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx); 395 396 NG_BTSOCKET_L2CAP_RAW_INFO( 397 "%s: Updating hook \"%s\", src bdaddr=%x:%x:%x:%x:%x:%x\n", 398 __func__, NG_HOOK_NAME(hook), 399 rt->src.b[5], rt->src.b[4], rt->src.b[3], 400 rt->src.b[2], rt->src.b[1], rt->src.b[0]); 401 } break; 402 403 case NGM_L2CAP_NODE_GET_FLAGS: 404 case NGM_L2CAP_NODE_GET_DEBUG: 405 case NGM_L2CAP_NODE_GET_CON_LIST: 406 case NGM_L2CAP_NODE_GET_CHAN_LIST: 407 case NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO: 408 case NGM_L2CAP_L2CA_PING: 409 case NGM_L2CAP_L2CA_GET_INFO: { 410 ng_btsocket_l2cap_raw_pcb_p pcb = NULL; 411 412 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx); 413 414 LIST_FOREACH(pcb,&ng_btsocket_l2cap_raw_sockets,next) { 415 mtx_lock(&pcb->pcb_mtx); 416 417 if (pcb->token == msg->header.token) { 418 pcb->msg = msg; 419 msg = NULL; 420 wakeup(&pcb->msg); 421 mtx_unlock(&pcb->pcb_mtx); 422 break; 423 } 424 425 mtx_unlock(&pcb->pcb_mtx); 426 } 427 428 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx); 429 } break; 430 431 default: 432 NG_BTSOCKET_L2CAP_RAW_WARN( 433 "%s: Unknown message, cmd=%d\n", __func__, msg->header.cmd); 434 break; 435 } 436 437 if (hook != NULL) 438 NG_HOOK_UNREF(hook); /* remove extra reference */ 439 440 NG_FREE_MSG(msg); /* Checks for msg != NULL */ 441 } 442 } /* ng_btsocket_l2cap_raw_input */ 443 444 /* 445 * Route cleanup task. Gets scheduled when hook is disconnected. Here we 446 * will find all sockets that use "invalid" hook and disconnect them. 447 */ 448 449 static void 450 ng_btsocket_l2cap_raw_rtclean(void *context, int pending) 451 { 452 ng_btsocket_l2cap_raw_pcb_p pcb = NULL; 453 ng_btsocket_l2cap_rtentry_p rt = NULL; 454 455 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx); 456 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx); 457 458 /* 459 * First disconnect all sockets that use "invalid" hook 460 */ 461 462 LIST_FOREACH(pcb, &ng_btsocket_l2cap_raw_sockets, next) { 463 mtx_lock(&pcb->pcb_mtx); 464 465 if (pcb->rt != NULL && 466 pcb->rt->hook != NULL && NG_HOOK_NOT_VALID(pcb->rt->hook)) { 467 if (pcb->so != NULL && 468 pcb->so->so_state & SS_ISCONNECTED) 469 soisdisconnected(pcb->so); 470 471 pcb->rt = NULL; 472 } 473 474 mtx_unlock(&pcb->pcb_mtx); 475 } 476 477 /* 478 * Now cleanup routing table 479 */ 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 FREE(rt, M_NETGRAPH_BTSOCKET_L2CAP_RAW); 492 } 493 494 rt = rt_next; 495 } 496 497 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx); 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_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_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_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_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 int 576 ng_btsocket_l2cap_raw_abort(struct socket *so) 577 { 578 return (ng_btsocket_l2cap_raw_detach(so)); 579 } /* ng_btsocket_l2cap_raw_abort */ 580 581 /* 582 * Create and attach new socket 583 */ 584 585 int 586 ng_btsocket_l2cap_raw_attach(struct socket *so, int proto, struct thread *td) 587 { 588 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 589 int error; 590 591 if (pcb != NULL) 592 return (EISCONN); 593 594 if (ng_btsocket_l2cap_raw_node == NULL) 595 return (EPROTONOSUPPORT); 596 if (so->so_type != SOCK_RAW) 597 return (ESOCKTNOSUPPORT); 598 599 /* Reserve send and receive space if it is not reserved yet */ 600 error = soreserve(so, NG_BTSOCKET_L2CAP_RAW_SENDSPACE, 601 NG_BTSOCKET_L2CAP_RAW_RECVSPACE); 602 if (error != 0) 603 return (error); 604 605 /* Allocate the PCB */ 606 MALLOC(pcb, ng_btsocket_l2cap_raw_pcb_p, sizeof(*pcb), 607 M_NETGRAPH_BTSOCKET_L2CAP_RAW, M_NOWAIT|M_ZERO); 608 if (pcb == NULL) 609 return (ENOMEM); 610 611 /* Link the PCB and the socket */ 612 so->so_pcb = (caddr_t) pcb; 613 pcb->so = so; 614 615 if (suser(td) == 0) 616 pcb->flags |= NG_BTSOCKET_L2CAP_RAW_PRIVILEGED; 617 618 mtx_init(&pcb->pcb_mtx, "btsocks_l2cap_raw_pcb_mtx", NULL, MTX_DEF); 619 620 /* Add the PCB to the list */ 621 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx); 622 LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_sockets, pcb, next); 623 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx); 624 625 return (0); 626 } /* ng_btsocket_l2cap_raw_attach */ 627 628 /* 629 * Bind socket 630 */ 631 632 int 633 ng_btsocket_l2cap_raw_bind(struct socket *so, struct sockaddr *nam, 634 struct thread *td) 635 { 636 ng_btsocket_l2cap_raw_pcb_t *pcb = so2l2cap_raw_pcb(so); 637 struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *) nam; 638 ng_btsocket_l2cap_rtentry_t *rt = NULL; 639 int error; 640 641 if (pcb == NULL) 642 return (EINVAL); 643 if (ng_btsocket_l2cap_raw_node == NULL) 644 return (EINVAL); 645 646 if (sa == NULL) 647 return (EINVAL); 648 if (sa->l2cap_family != AF_BLUETOOTH) 649 return (EAFNOSUPPORT); 650 if (sa->l2cap_len != sizeof(*sa)) 651 return (EINVAL); 652 653 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx); 654 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx); 655 mtx_lock(&pcb->pcb_mtx); 656 657 pcb->rt = NULL; 658 bcopy(&sa->l2cap_bdaddr, &pcb->src, sizeof(pcb->src)); 659 660 if (bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(pcb->src)) == 0) { 661 mtx_unlock(&pcb->pcb_mtx); 662 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx); 663 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx); 664 665 return (0); 666 } 667 668 LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) { 669 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook)) 670 continue; 671 672 if (bcmp(&pcb->src, &rt->src, sizeof(rt->src)) == 0) 673 break; 674 } 675 676 if (rt != NULL) { 677 pcb->rt = rt; 678 error = 0; 679 } else 680 error = ENETDOWN; 681 682 mtx_unlock(&pcb->pcb_mtx); 683 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx); 684 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx); 685 686 return (error); 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(&ng_btsocket_l2cap_raw_rt_mtx); 717 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx); 718 mtx_lock(&pcb->pcb_mtx); 719 720 bcopy(&sa->l2cap_bdaddr, &pcb->dst, sizeof(pcb->dst)); 721 722 if (bcmp(&pcb->src, &pcb->dst, sizeof(pcb->src)) == 0) { 723 mtx_unlock(&pcb->pcb_mtx); 724 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx); 725 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx); 726 727 return (EADDRNOTAVAIL); 728 } 729 730 /* 731 * If there is route already - use it 732 */ 733 734 if (pcb->rt != NULL) { 735 soisconnected(so); 736 737 mtx_unlock(&pcb->pcb_mtx); 738 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx); 739 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx); 740 741 return (0); 742 } 743 744 /* 745 * Find the first hook that does not match specified destination address 746 */ 747 748 LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) { 749 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook)) 750 continue; 751 752 if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0) 753 break; 754 } 755 756 if (rt != NULL) { 757 soisconnected(so); 758 759 pcb->rt = rt; 760 bcopy(&rt->src, &pcb->src, sizeof(pcb->src)); 761 762 error = 0; 763 } else 764 error = ENETDOWN; 765 766 mtx_unlock(&pcb->pcb_mtx); 767 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx); 768 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx); 769 770 return (error); 771 } /* ng_btsocket_l2cap_raw_connect */ 772 773 /* 774 * Process ioctl's calls on socket 775 */ 776 777 int 778 ng_btsocket_l2cap_raw_control(struct socket *so, u_long cmd, caddr_t data, 779 struct ifnet *ifp, struct thread *td) 780 { 781 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 782 struct ng_mesg *msg = NULL; 783 int error = 0; 784 785 if (pcb == NULL) 786 return (EINVAL); 787 if (ng_btsocket_l2cap_raw_node == NULL) 788 return (EINVAL); 789 790 mtx_lock(&pcb->pcb_mtx); 791 792 /* Check if we route info */ 793 if (pcb->rt == NULL) { 794 mtx_unlock(&pcb->pcb_mtx); 795 return (EHOSTUNREACH); 796 } 797 798 /* Check if we have pending ioctl() */ 799 if (pcb->token != 0) { 800 mtx_unlock(&pcb->pcb_mtx); 801 return (EBUSY); 802 } 803 804 switch (cmd) { 805 case SIOC_L2CAP_NODE_GET_FLAGS: { 806 struct ng_btsocket_l2cap_raw_node_flags *p = 807 (struct ng_btsocket_l2cap_raw_node_flags *) data; 808 809 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb, 810 NGM_L2CAP_NODE_GET_FLAGS, 811 &p->flags, sizeof(p->flags)); 812 } break; 813 814 case SIOC_L2CAP_NODE_GET_DEBUG: { 815 struct ng_btsocket_l2cap_raw_node_debug *p = 816 (struct ng_btsocket_l2cap_raw_node_debug *) data; 817 818 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb, 819 NGM_L2CAP_NODE_GET_DEBUG, 820 &p->debug, sizeof(p->debug)); 821 } break; 822 823 case SIOC_L2CAP_NODE_SET_DEBUG: { 824 struct ng_btsocket_l2cap_raw_node_debug *p = 825 (struct ng_btsocket_l2cap_raw_node_debug *) data; 826 827 if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED) 828 error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook, 829 NGM_L2CAP_NODE_SET_DEBUG, 830 &p->debug, sizeof(p->debug)); 831 else 832 error = EPERM; 833 } break; 834 835 case SIOC_L2CAP_NODE_GET_CON_LIST: { 836 struct ng_btsocket_l2cap_raw_con_list *p = 837 (struct ng_btsocket_l2cap_raw_con_list *) data; 838 ng_l2cap_node_con_list_ep *p1 = NULL; 839 ng_l2cap_node_con_ep *p2 = NULL; 840 841 if (p->num_connections == 0 || 842 p->num_connections > NG_L2CAP_MAX_CON_NUM || 843 p->connections == NULL) { 844 error = EINVAL; 845 break; 846 } 847 848 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_GET_CON_LIST, 849 0, M_NOWAIT); 850 if (msg == NULL) { 851 error = ENOMEM; 852 break; 853 } 854 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 855 pcb->token = msg->header.token; 856 pcb->msg = NULL; 857 858 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 859 pcb->rt->hook, 0); 860 if (error != 0) { 861 pcb->token = 0; 862 break; 863 } 864 865 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl", 866 ng_btsocket_l2cap_raw_ioctl_timeout * hz); 867 pcb->token = 0; 868 869 if (error != 0) 870 break; 871 872 if (pcb->msg != NULL && 873 pcb->msg->header.cmd == NGM_L2CAP_NODE_GET_CON_LIST) { 874 /* Return data back to user space */ 875 p1 = (ng_l2cap_node_con_list_ep *)(pcb->msg->data); 876 p2 = (ng_l2cap_node_con_ep *)(p1 + 1); 877 878 p->num_connections = min(p->num_connections, 879 p1->num_connections); 880 if (p->num_connections > 0) 881 error = copyout((caddr_t) p2, 882 (caddr_t) p->connections, 883 p->num_connections * sizeof(*p2)); 884 } else 885 error = EINVAL; 886 887 NG_FREE_MSG(pcb->msg); /* checks for != NULL */ 888 } break; 889 890 case SIOC_L2CAP_NODE_GET_CHAN_LIST: { 891 struct ng_btsocket_l2cap_raw_chan_list *p = 892 (struct ng_btsocket_l2cap_raw_chan_list *) data; 893 ng_l2cap_node_chan_list_ep *p1 = NULL; 894 ng_l2cap_node_chan_ep *p2 = NULL; 895 896 if (p->num_channels == 0 || 897 p->num_channels > NG_L2CAP_MAX_CHAN_NUM || 898 p->channels == NULL) { 899 error = EINVAL; 900 break; 901 } 902 903 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, 904 NGM_L2CAP_NODE_GET_CHAN_LIST, 0, M_NOWAIT); 905 if (msg == NULL) { 906 error = ENOMEM; 907 break; 908 } 909 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 910 pcb->token = msg->header.token; 911 pcb->msg = NULL; 912 913 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 914 pcb->rt->hook, 0); 915 if (error != 0) { 916 pcb->token = 0; 917 break; 918 } 919 920 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl", 921 ng_btsocket_l2cap_raw_ioctl_timeout * hz); 922 pcb->token = 0; 923 924 if (error != 0) 925 break; 926 927 if (pcb->msg != NULL && 928 pcb->msg->header.cmd == NGM_L2CAP_NODE_GET_CHAN_LIST) { 929 /* Return data back to user space */ 930 p1 = (ng_l2cap_node_chan_list_ep *)(pcb->msg->data); 931 p2 = (ng_l2cap_node_chan_ep *)(p1 + 1); 932 933 p->num_channels = min(p->num_channels, 934 p1->num_channels); 935 if (p->num_channels > 0) 936 error = copyout((caddr_t) p2, 937 (caddr_t) p->channels, 938 p->num_channels * sizeof(*p2)); 939 } else 940 error = EINVAL; 941 942 NG_FREE_MSG(pcb->msg); /* checks for != NULL */ 943 } break; 944 945 case SIOC_L2CAP_L2CA_PING: { 946 struct ng_btsocket_l2cap_raw_ping *p = 947 (struct ng_btsocket_l2cap_raw_ping *) data; 948 ng_l2cap_l2ca_ping_ip *ip = NULL; 949 ng_l2cap_l2ca_ping_op *op = NULL; 950 951 if (!(pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)) { 952 error = EPERM; 953 break; 954 } 955 956 if ((p->echo_size != 0 && p->echo_data == NULL) || 957 p->echo_size > NG_L2CAP_MAX_ECHO_SIZE) { 958 error = EINVAL; 959 break; 960 } 961 962 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, 963 NGM_L2CAP_L2CA_PING, sizeof(*ip) + p->echo_size, 964 M_NOWAIT); 965 if (msg == NULL) { 966 error = ENOMEM; 967 break; 968 } 969 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 970 pcb->token = msg->header.token; 971 pcb->msg = NULL; 972 973 ip = (ng_l2cap_l2ca_ping_ip *)(msg->data); 974 bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr)); 975 ip->echo_size = p->echo_size; 976 977 if (ip->echo_size > 0) { 978 error = copyin(p->echo_data, ip + 1, p->echo_size); 979 if (error != 0) { 980 NG_FREE_MSG(msg); 981 pcb->token = 0; 982 break; 983 } 984 } 985 986 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 987 pcb->rt->hook, 0); 988 if (error != 0) { 989 pcb->token = 0; 990 break; 991 } 992 993 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl", 994 bluetooth_l2cap_rtx_timeout()); 995 pcb->token = 0; 996 997 if (error != 0) 998 break; 999 1000 if (pcb->msg != NULL && 1001 pcb->msg->header.cmd == NGM_L2CAP_L2CA_PING) { 1002 /* Return data back to the user space */ 1003 op = (ng_l2cap_l2ca_ping_op *)(pcb->msg->data); 1004 p->result = op->result; 1005 p->echo_size = min(p->echo_size, op->echo_size); 1006 1007 if (p->echo_size > 0) 1008 error = copyout(op + 1, p->echo_data, 1009 p->echo_size); 1010 } else 1011 error = EINVAL; 1012 1013 NG_FREE_MSG(pcb->msg); /* checks for != NULL */ 1014 } break; 1015 1016 case SIOC_L2CAP_L2CA_GET_INFO: { 1017 struct ng_btsocket_l2cap_raw_get_info *p = 1018 (struct ng_btsocket_l2cap_raw_get_info *) data; 1019 ng_l2cap_l2ca_get_info_ip *ip = NULL; 1020 ng_l2cap_l2ca_get_info_op *op = NULL; 1021 1022 if (!(pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)) { 1023 error = EPERM; 1024 break; 1025 } 1026 1027 if (p->info_size != 0 && p->info_data == NULL) { 1028 error = EINVAL; 1029 break; 1030 } 1031 1032 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, 1033 NGM_L2CAP_L2CA_GET_INFO, sizeof(*ip) + p->info_size, 1034 M_NOWAIT); 1035 if (msg == NULL) { 1036 error = ENOMEM; 1037 break; 1038 } 1039 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 1040 pcb->token = msg->header.token; 1041 pcb->msg = NULL; 1042 1043 ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data); 1044 bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr)); 1045 ip->info_type = p->info_type; 1046 1047 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 1048 pcb->rt->hook, 0); 1049 if (error != 0) { 1050 pcb->token = 0; 1051 break; 1052 } 1053 1054 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl", 1055 bluetooth_l2cap_rtx_timeout()); 1056 pcb->token = 0; 1057 1058 if (error != 0) 1059 break; 1060 1061 if (pcb->msg != NULL && 1062 pcb->msg->header.cmd == NGM_L2CAP_L2CA_GET_INFO) { 1063 /* Return data back to the user space */ 1064 op = (ng_l2cap_l2ca_get_info_op *)(pcb->msg->data); 1065 p->result = op->result; 1066 p->info_size = min(p->info_size, op->info_size); 1067 1068 if (p->info_size > 0) 1069 error = copyout(op + 1, p->info_data, 1070 p->info_size); 1071 } else 1072 error = EINVAL; 1073 1074 NG_FREE_MSG(pcb->msg); /* checks for != NULL */ 1075 } break; 1076 1077 case SIOC_L2CAP_NODE_GET_AUTO_DISCON_TIMO: { 1078 struct ng_btsocket_l2cap_raw_auto_discon_timo *p = 1079 (struct ng_btsocket_l2cap_raw_auto_discon_timo *) data; 1080 1081 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb, 1082 NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO, 1083 &p->timeout, sizeof(p->timeout)); 1084 } break; 1085 1086 case SIOC_L2CAP_NODE_SET_AUTO_DISCON_TIMO: { 1087 struct ng_btsocket_l2cap_raw_auto_discon_timo *p = 1088 (struct ng_btsocket_l2cap_raw_auto_discon_timo *) data; 1089 1090 if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED) 1091 error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook, 1092 NGM_L2CAP_NODE_SET_AUTO_DISCON_TIMO, 1093 &p->timeout, sizeof(p->timeout)); 1094 else 1095 error = EPERM; 1096 } break; 1097 1098 default: 1099 error = EINVAL; 1100 break; 1101 } 1102 1103 mtx_unlock(&pcb->pcb_mtx); 1104 1105 return (error); 1106 } /* ng_btsocket_l2cap_raw_control */ 1107 1108 /* 1109 * Detach and destroy socket 1110 */ 1111 1112 int 1113 ng_btsocket_l2cap_raw_detach(struct socket *so) 1114 { 1115 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 1116 1117 if (pcb == NULL) 1118 return (EINVAL); 1119 if (ng_btsocket_l2cap_raw_node == NULL) 1120 return (EINVAL); 1121 1122 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx); 1123 mtx_lock(&pcb->pcb_mtx); 1124 1125 LIST_REMOVE(pcb, next); 1126 1127 mtx_unlock(&pcb->pcb_mtx); 1128 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx); 1129 1130 mtx_destroy(&pcb->pcb_mtx); 1131 1132 bzero(pcb, sizeof(*pcb)); 1133 FREE(pcb, M_NETGRAPH_BTSOCKET_L2CAP_RAW); 1134 1135 so->so_pcb = NULL; 1136 sotryfree(so); 1137 1138 return (0); 1139 } /* ng_btsocket_l2cap_raw_detach */ 1140 1141 /* 1142 * Disconnect socket 1143 */ 1144 1145 int 1146 ng_btsocket_l2cap_raw_disconnect(struct socket *so) 1147 { 1148 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 1149 1150 if (pcb == NULL) 1151 return (EINVAL); 1152 if (ng_btsocket_l2cap_raw_node == NULL) 1153 return (EINVAL); 1154 1155 mtx_lock(&pcb->pcb_mtx); 1156 pcb->rt = NULL; 1157 soisdisconnected(so); 1158 mtx_unlock(&pcb->pcb_mtx); 1159 1160 return (0); 1161 } /* ng_btsocket_l2cap_raw_disconnect */ 1162 1163 /* 1164 * Get peer address 1165 */ 1166 1167 int 1168 ng_btsocket_l2cap_raw_peeraddr(struct socket *so, struct sockaddr **nam) 1169 { 1170 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 1171 struct sockaddr_l2cap sa; 1172 1173 if (pcb == NULL) 1174 return (EINVAL); 1175 if (ng_btsocket_l2cap_raw_node == NULL) 1176 return (EINVAL); 1177 1178 bcopy(&pcb->dst, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr)); 1179 sa.l2cap_psm = 0; 1180 sa.l2cap_len = sizeof(sa); 1181 sa.l2cap_family = AF_BLUETOOTH; 1182 1183 *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT); 1184 1185 return ((*nam == NULL)? ENOMEM : 0); 1186 } /* ng_btsocket_l2cap_raw_peeraddr */ 1187 1188 /* 1189 * Send data to socket 1190 */ 1191 1192 int 1193 ng_btsocket_l2cap_raw_send(struct socket *so, int flags, struct mbuf *m, 1194 struct sockaddr *nam, struct mbuf *control, struct thread *td) 1195 { 1196 NG_FREE_M(m); /* Checks for m != NULL */ 1197 NG_FREE_M(control); 1198 1199 return (EOPNOTSUPP); 1200 } /* ng_btsocket_l2cap_raw_send */ 1201 1202 /* 1203 * Get socket address 1204 */ 1205 1206 int 1207 ng_btsocket_l2cap_raw_sockaddr(struct socket *so, struct sockaddr **nam) 1208 { 1209 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 1210 struct sockaddr_l2cap sa; 1211 1212 if (pcb == NULL) 1213 return (EINVAL); 1214 if (ng_btsocket_l2cap_raw_node == NULL) 1215 return (EINVAL); 1216 1217 bcopy(&pcb->src, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr)); 1218 sa.l2cap_psm = 0; 1219 sa.l2cap_len = sizeof(sa); 1220 sa.l2cap_family = AF_BLUETOOTH; 1221 1222 *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT); 1223 1224 return ((*nam == NULL)? ENOMEM : 0); 1225 } /* ng_btsocket_l2cap_raw_sockaddr */ 1226 1227 /* 1228 * Get next token 1229 */ 1230 1231 static void 1232 ng_btsocket_l2cap_raw_get_token(u_int32_t *token) 1233 { 1234 mtx_lock(&ng_btsocket_l2cap_raw_token_mtx); 1235 1236 if (++ ng_btsocket_l2cap_raw_token == 0) 1237 ng_btsocket_l2cap_raw_token = 1; 1238 1239 *token = ng_btsocket_l2cap_raw_token; 1240 1241 mtx_unlock(&ng_btsocket_l2cap_raw_token_mtx); 1242 } /* ng_btsocket_l2cap_raw_get_token */ 1243 1244 /* 1245 * Send Netgraph message to the node - do not expect reply 1246 */ 1247 1248 static int 1249 ng_btsocket_l2cap_raw_send_ngmsg(hook_p hook, int cmd, void *arg, int arglen) 1250 { 1251 struct ng_mesg *msg = NULL; 1252 int error = 0; 1253 1254 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, arglen, M_NOWAIT); 1255 if (msg == NULL) 1256 return (ENOMEM); 1257 1258 if (arg != NULL && arglen > 0) 1259 bcopy(arg, msg->data, arglen); 1260 1261 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, hook, 0); 1262 1263 return (error); 1264 } /* ng_btsocket_l2cap_raw_send_ngmsg */ 1265 1266 /* 1267 * Send Netgraph message to the node (no data) and wait for reply 1268 */ 1269 1270 static int 1271 ng_btsocket_l2cap_raw_send_sync_ngmsg(ng_btsocket_l2cap_raw_pcb_p pcb, 1272 int cmd, void *rsp, int rsplen) 1273 { 1274 struct ng_mesg *msg = NULL; 1275 int error = 0; 1276 1277 mtx_assert(&pcb->pcb_mtx, MA_OWNED); 1278 1279 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, 0, M_NOWAIT); 1280 if (msg == NULL) 1281 return (ENOMEM); 1282 1283 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 1284 pcb->token = msg->header.token; 1285 pcb->msg = NULL; 1286 1287 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 1288 pcb->rt->hook, 0); 1289 if (error != 0) { 1290 pcb->token = 0; 1291 return (error); 1292 } 1293 1294 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl", 1295 ng_btsocket_l2cap_raw_ioctl_timeout * hz); 1296 pcb->token = 0; 1297 1298 if (error != 0) 1299 return (error); 1300 1301 if (pcb->msg != NULL && pcb->msg->header.cmd == cmd) 1302 bcopy(pcb->msg->data, rsp, rsplen); 1303 else 1304 error = EINVAL; 1305 1306 NG_FREE_MSG(pcb->msg); /* checks for != NULL */ 1307 1308 return (0); 1309 } /* ng_btsocket_l2cap_raw_send_sync_ngmsg */ 1310 1311