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