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