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