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 (sa->l2cap_len != sizeof(struct sockaddr_l2cap_compat))) 672 return (EINVAL); 673 674 if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, 675 sizeof(sa->l2cap_bdaddr)) != 0) { 676 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx); 677 678 LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) { 679 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook)) 680 continue; 681 682 if (bcmp(&sa->l2cap_bdaddr, &rt->src, 683 sizeof(rt->src)) == 0) 684 break; 685 } 686 687 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx); 688 689 if (rt == NULL) 690 return (ENETDOWN); 691 } else 692 rt = NULL; 693 694 mtx_lock(&pcb->pcb_mtx); 695 bcopy(&sa->l2cap_bdaddr, &pcb->src, sizeof(pcb->src)); 696 pcb->rt = rt; 697 mtx_unlock(&pcb->pcb_mtx); 698 699 return (0); 700 } /* ng_btsocket_l2cap_raw_bind */ 701 702 /* 703 * Connect socket 704 */ 705 706 int 707 ng_btsocket_l2cap_raw_connect(struct socket *so, struct sockaddr *nam, 708 struct thread *td) 709 { 710 ng_btsocket_l2cap_raw_pcb_t *pcb = so2l2cap_raw_pcb(so); 711 struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *) nam; 712 ng_btsocket_l2cap_rtentry_t *rt = NULL; 713 int error; 714 715 if (pcb == NULL) 716 return (EINVAL); 717 if (ng_btsocket_l2cap_raw_node == NULL) 718 return (EINVAL); 719 720 if (sa == NULL) 721 return (EINVAL); 722 if (sa->l2cap_family != AF_BLUETOOTH) 723 return (EAFNOSUPPORT); 724 if((sa->l2cap_len != sizeof(*sa))&& 725 (sa->l2cap_len != sizeof(struct sockaddr_l2cap_compat))) 726 return (EINVAL); 727 728 if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) 729 return (EINVAL); 730 731 mtx_lock(&pcb->pcb_mtx); 732 733 bcopy(&sa->l2cap_bdaddr, &pcb->dst, sizeof(pcb->dst)); 734 735 if (bcmp(&pcb->src, &pcb->dst, sizeof(pcb->src)) == 0) { 736 mtx_unlock(&pcb->pcb_mtx); 737 738 return (EADDRNOTAVAIL); 739 } 740 741 /* 742 * If there is route already - use it 743 */ 744 745 if (pcb->rt != NULL) { 746 soisconnected(so); 747 mtx_unlock(&pcb->pcb_mtx); 748 749 return (0); 750 } 751 752 /* 753 * Find the first hook that does not match specified destination address 754 */ 755 756 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx); 757 758 LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) { 759 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook)) 760 continue; 761 762 if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0) 763 break; 764 } 765 766 if (rt != NULL) { 767 soisconnected(so); 768 769 pcb->rt = rt; 770 bcopy(&rt->src, &pcb->src, sizeof(pcb->src)); 771 772 error = 0; 773 } else 774 error = ENETDOWN; 775 776 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx); 777 mtx_unlock(&pcb->pcb_mtx); 778 779 return (error); 780 } /* ng_btsocket_l2cap_raw_connect */ 781 782 /* 783 * Process ioctl's calls on socket 784 */ 785 786 int 787 ng_btsocket_l2cap_raw_control(struct socket *so, u_long cmd, caddr_t data, 788 struct ifnet *ifp, struct thread *td) 789 { 790 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 791 struct ng_mesg *msg = NULL; 792 int error = 0; 793 794 if (pcb == NULL) 795 return (EINVAL); 796 if (ng_btsocket_l2cap_raw_node == NULL) 797 return (EINVAL); 798 799 mtx_lock(&pcb->pcb_mtx); 800 801 /* Check if we route info */ 802 if (pcb->rt == NULL) { 803 mtx_unlock(&pcb->pcb_mtx); 804 return (EHOSTUNREACH); 805 } 806 807 /* Check if we have pending ioctl() */ 808 if (pcb->token != 0) { 809 mtx_unlock(&pcb->pcb_mtx); 810 return (EBUSY); 811 } 812 813 switch (cmd) { 814 case SIOC_L2CAP_NODE_GET_FLAGS: { 815 struct ng_btsocket_l2cap_raw_node_flags *p = 816 (struct ng_btsocket_l2cap_raw_node_flags *) data; 817 818 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb, 819 NGM_L2CAP_NODE_GET_FLAGS, 820 &p->flags, sizeof(p->flags)); 821 } break; 822 823 case SIOC_L2CAP_NODE_GET_DEBUG: { 824 struct ng_btsocket_l2cap_raw_node_debug *p = 825 (struct ng_btsocket_l2cap_raw_node_debug *) data; 826 827 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb, 828 NGM_L2CAP_NODE_GET_DEBUG, 829 &p->debug, sizeof(p->debug)); 830 } break; 831 832 case SIOC_L2CAP_NODE_SET_DEBUG: { 833 struct ng_btsocket_l2cap_raw_node_debug *p = 834 (struct ng_btsocket_l2cap_raw_node_debug *) data; 835 836 if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED) 837 error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook, 838 NGM_L2CAP_NODE_SET_DEBUG, 839 &p->debug, sizeof(p->debug)); 840 else 841 error = EPERM; 842 } break; 843 844 case SIOC_L2CAP_NODE_GET_CON_LIST: { 845 struct ng_btsocket_l2cap_raw_con_list *p = 846 (struct ng_btsocket_l2cap_raw_con_list *) data; 847 ng_l2cap_node_con_list_ep *p1 = NULL; 848 ng_l2cap_node_con_ep *p2 = NULL; 849 850 if (p->num_connections == 0 || 851 p->num_connections > NG_L2CAP_MAX_CON_NUM || 852 p->connections == NULL) { 853 error = EINVAL; 854 break; 855 } 856 857 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_GET_CON_LIST, 858 0, M_NOWAIT); 859 if (msg == NULL) { 860 error = ENOMEM; 861 break; 862 } 863 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 864 pcb->token = msg->header.token; 865 pcb->msg = NULL; 866 867 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 868 pcb->rt->hook, 0); 869 if (error != 0) { 870 pcb->token = 0; 871 break; 872 } 873 874 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl", 875 ng_btsocket_l2cap_raw_ioctl_timeout * hz); 876 pcb->token = 0; 877 878 if (error != 0) 879 break; 880 881 if (pcb->msg != NULL && 882 pcb->msg->header.cmd == NGM_L2CAP_NODE_GET_CON_LIST) { 883 /* Return data back to user space */ 884 p1 = (ng_l2cap_node_con_list_ep *)(pcb->msg->data); 885 p2 = (ng_l2cap_node_con_ep *)(p1 + 1); 886 887 p->num_connections = min(p->num_connections, 888 p1->num_connections); 889 if (p->num_connections > 0) 890 error = copyout((caddr_t) p2, 891 (caddr_t) p->connections, 892 p->num_connections * sizeof(*p2)); 893 } else 894 error = EINVAL; 895 896 NG_FREE_MSG(pcb->msg); /* checks for != NULL */ 897 } break; 898 899 case SIOC_L2CAP_NODE_GET_CHAN_LIST: { 900 struct ng_btsocket_l2cap_raw_chan_list *p = 901 (struct ng_btsocket_l2cap_raw_chan_list *) data; 902 ng_l2cap_node_chan_list_ep *p1 = NULL; 903 ng_l2cap_node_chan_ep *p2 = NULL; 904 905 if (p->num_channels == 0 || 906 p->num_channels > NG_L2CAP_MAX_CHAN_NUM || 907 p->channels == NULL) { 908 error = EINVAL; 909 break; 910 } 911 912 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, 913 NGM_L2CAP_NODE_GET_CHAN_LIST, 0, M_NOWAIT); 914 if (msg == NULL) { 915 error = ENOMEM; 916 break; 917 } 918 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 919 pcb->token = msg->header.token; 920 pcb->msg = NULL; 921 922 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 923 pcb->rt->hook, 0); 924 if (error != 0) { 925 pcb->token = 0; 926 break; 927 } 928 929 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl", 930 ng_btsocket_l2cap_raw_ioctl_timeout * hz); 931 pcb->token = 0; 932 933 if (error != 0) 934 break; 935 936 if (pcb->msg != NULL && 937 pcb->msg->header.cmd == NGM_L2CAP_NODE_GET_CHAN_LIST) { 938 /* Return data back to user space */ 939 p1 = (ng_l2cap_node_chan_list_ep *)(pcb->msg->data); 940 p2 = (ng_l2cap_node_chan_ep *)(p1 + 1); 941 942 p->num_channels = min(p->num_channels, 943 p1->num_channels); 944 if (p->num_channels > 0) 945 error = copyout((caddr_t) p2, 946 (caddr_t) p->channels, 947 p->num_channels * sizeof(*p2)); 948 } else 949 error = EINVAL; 950 951 NG_FREE_MSG(pcb->msg); /* checks for != NULL */ 952 } break; 953 954 case SIOC_L2CAP_L2CA_PING: { 955 struct ng_btsocket_l2cap_raw_ping *p = 956 (struct ng_btsocket_l2cap_raw_ping *) data; 957 ng_l2cap_l2ca_ping_ip *ip = NULL; 958 ng_l2cap_l2ca_ping_op *op = NULL; 959 960 if ((p->echo_size != 0 && p->echo_data == NULL) || 961 p->echo_size > NG_L2CAP_MAX_ECHO_SIZE) { 962 error = EINVAL; 963 break; 964 } 965 966 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, 967 NGM_L2CAP_L2CA_PING, sizeof(*ip) + p->echo_size, 968 M_NOWAIT); 969 if (msg == NULL) { 970 error = ENOMEM; 971 break; 972 } 973 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 974 pcb->token = msg->header.token; 975 pcb->msg = NULL; 976 977 ip = (ng_l2cap_l2ca_ping_ip *)(msg->data); 978 bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr)); 979 ip->echo_size = p->echo_size; 980 981 if (ip->echo_size > 0) { 982 error = copyin(p->echo_data, ip + 1, p->echo_size); 983 if (error != 0) { 984 NG_FREE_MSG(msg); 985 pcb->token = 0; 986 break; 987 } 988 } 989 990 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 991 pcb->rt->hook, 0); 992 if (error != 0) { 993 pcb->token = 0; 994 break; 995 } 996 997 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl", 998 bluetooth_l2cap_rtx_timeout()); 999 pcb->token = 0; 1000 1001 if (error != 0) 1002 break; 1003 1004 if (pcb->msg != NULL && 1005 pcb->msg->header.cmd == NGM_L2CAP_L2CA_PING) { 1006 /* Return data back to the user space */ 1007 op = (ng_l2cap_l2ca_ping_op *)(pcb->msg->data); 1008 p->result = op->result; 1009 p->echo_size = min(p->echo_size, op->echo_size); 1010 1011 if (p->echo_size > 0) 1012 error = copyout(op + 1, p->echo_data, 1013 p->echo_size); 1014 } else 1015 error = EINVAL; 1016 1017 NG_FREE_MSG(pcb->msg); /* checks for != NULL */ 1018 } break; 1019 1020 case SIOC_L2CAP_L2CA_GET_INFO: { 1021 struct ng_btsocket_l2cap_raw_get_info *p = 1022 (struct ng_btsocket_l2cap_raw_get_info *) data; 1023 ng_l2cap_l2ca_get_info_ip *ip = NULL; 1024 ng_l2cap_l2ca_get_info_op *op = NULL; 1025 1026 if (!(pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)) { 1027 error = EPERM; 1028 break; 1029 } 1030 1031 if (p->info_size != 0 && p->info_data == NULL) { 1032 error = EINVAL; 1033 break; 1034 } 1035 1036 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, 1037 NGM_L2CAP_L2CA_GET_INFO, sizeof(*ip) + p->info_size, 1038 M_NOWAIT); 1039 if (msg == NULL) { 1040 error = ENOMEM; 1041 break; 1042 } 1043 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 1044 pcb->token = msg->header.token; 1045 pcb->msg = NULL; 1046 1047 ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data); 1048 bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr)); 1049 ip->info_type = p->info_type; 1050 1051 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 1052 pcb->rt->hook, 0); 1053 if (error != 0) { 1054 pcb->token = 0; 1055 break; 1056 } 1057 1058 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl", 1059 bluetooth_l2cap_rtx_timeout()); 1060 pcb->token = 0; 1061 1062 if (error != 0) 1063 break; 1064 1065 if (pcb->msg != NULL && 1066 pcb->msg->header.cmd == NGM_L2CAP_L2CA_GET_INFO) { 1067 /* Return data back to the user space */ 1068 op = (ng_l2cap_l2ca_get_info_op *)(pcb->msg->data); 1069 p->result = op->result; 1070 p->info_size = min(p->info_size, op->info_size); 1071 1072 if (p->info_size > 0) 1073 error = copyout(op + 1, p->info_data, 1074 p->info_size); 1075 } else 1076 error = EINVAL; 1077 1078 NG_FREE_MSG(pcb->msg); /* checks for != NULL */ 1079 } break; 1080 1081 case SIOC_L2CAP_NODE_GET_AUTO_DISCON_TIMO: { 1082 struct ng_btsocket_l2cap_raw_auto_discon_timo *p = 1083 (struct ng_btsocket_l2cap_raw_auto_discon_timo *) data; 1084 1085 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb, 1086 NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO, 1087 &p->timeout, sizeof(p->timeout)); 1088 } break; 1089 1090 case SIOC_L2CAP_NODE_SET_AUTO_DISCON_TIMO: { 1091 struct ng_btsocket_l2cap_raw_auto_discon_timo *p = 1092 (struct ng_btsocket_l2cap_raw_auto_discon_timo *) data; 1093 1094 if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED) 1095 error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook, 1096 NGM_L2CAP_NODE_SET_AUTO_DISCON_TIMO, 1097 &p->timeout, sizeof(p->timeout)); 1098 else 1099 error = EPERM; 1100 } break; 1101 1102 default: 1103 error = EINVAL; 1104 break; 1105 } 1106 1107 mtx_unlock(&pcb->pcb_mtx); 1108 1109 return (error); 1110 } /* ng_btsocket_l2cap_raw_control */ 1111 1112 /* 1113 * Detach and destroy socket 1114 */ 1115 1116 void 1117 ng_btsocket_l2cap_raw_detach(struct socket *so) 1118 { 1119 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 1120 1121 KASSERT(pcb != NULL, ("nt_btsocket_l2cap_raw_detach: pcb == NULL")); 1122 if (ng_btsocket_l2cap_raw_node == NULL) 1123 return; 1124 1125 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx); 1126 mtx_lock(&pcb->pcb_mtx); 1127 1128 LIST_REMOVE(pcb, next); 1129 1130 mtx_unlock(&pcb->pcb_mtx); 1131 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx); 1132 1133 mtx_destroy(&pcb->pcb_mtx); 1134 1135 bzero(pcb, sizeof(*pcb)); 1136 free(pcb, M_NETGRAPH_BTSOCKET_L2CAP_RAW); 1137 1138 so->so_pcb = NULL; 1139 } /* ng_btsocket_l2cap_raw_detach */ 1140 1141 /* 1142 * Disconnect socket 1143 */ 1144 1145 int 1146 ng_btsocket_l2cap_raw_disconnect(struct socket *so) 1147 { 1148 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 1149 1150 if (pcb == NULL) 1151 return (EINVAL); 1152 if (ng_btsocket_l2cap_raw_node == NULL) 1153 return (EINVAL); 1154 1155 mtx_lock(&pcb->pcb_mtx); 1156 pcb->rt = NULL; 1157 soisdisconnected(so); 1158 mtx_unlock(&pcb->pcb_mtx); 1159 1160 return (0); 1161 } /* ng_btsocket_l2cap_raw_disconnect */ 1162 1163 /* 1164 * Get peer address 1165 */ 1166 1167 int 1168 ng_btsocket_l2cap_raw_peeraddr(struct socket *so, struct sockaddr **nam) 1169 { 1170 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 1171 struct sockaddr_l2cap sa; 1172 1173 if (pcb == NULL) 1174 return (EINVAL); 1175 if (ng_btsocket_l2cap_raw_node == NULL) 1176 return (EINVAL); 1177 1178 mtx_lock(&pcb->pcb_mtx); 1179 bcopy(&pcb->dst, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr)); 1180 mtx_unlock(&pcb->pcb_mtx); 1181 1182 sa.l2cap_psm = 0; 1183 sa.l2cap_len = sizeof(sa); 1184 sa.l2cap_family = AF_BLUETOOTH; 1185 sa.l2cap_cid = 0; 1186 sa.l2cap_bdaddr_type = BDADDR_BREDR; 1187 1188 *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT); 1189 1190 return ((*nam == NULL)? ENOMEM : 0); 1191 } /* ng_btsocket_l2cap_raw_peeraddr */ 1192 1193 /* 1194 * Send data to socket 1195 */ 1196 1197 int 1198 ng_btsocket_l2cap_raw_send(struct socket *so, int flags, struct mbuf *m, 1199 struct sockaddr *nam, struct mbuf *control, struct thread *td) 1200 { 1201 NG_FREE_M(m); /* Checks for m != NULL */ 1202 NG_FREE_M(control); 1203 1204 return (EOPNOTSUPP); 1205 } /* ng_btsocket_l2cap_raw_send */ 1206 1207 /* 1208 * Get socket address 1209 */ 1210 1211 int 1212 ng_btsocket_l2cap_raw_sockaddr(struct socket *so, struct sockaddr **nam) 1213 { 1214 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so); 1215 struct sockaddr_l2cap sa; 1216 1217 if (pcb == NULL) 1218 return (EINVAL); 1219 if (ng_btsocket_l2cap_raw_node == NULL) 1220 return (EINVAL); 1221 1222 mtx_lock(&pcb->pcb_mtx); 1223 bcopy(&pcb->src, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr)); 1224 mtx_unlock(&pcb->pcb_mtx); 1225 1226 sa.l2cap_psm = 0; 1227 sa.l2cap_len = sizeof(sa); 1228 sa.l2cap_family = AF_BLUETOOTH; 1229 sa.l2cap_cid = 0; 1230 sa.l2cap_bdaddr_type = BDADDR_BREDR; 1231 *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT); 1232 1233 return ((*nam == NULL)? ENOMEM : 0); 1234 } /* ng_btsocket_l2cap_raw_sockaddr */ 1235 1236 /* 1237 * Get next token 1238 */ 1239 1240 static void 1241 ng_btsocket_l2cap_raw_get_token(u_int32_t *token) 1242 { 1243 mtx_lock(&ng_btsocket_l2cap_raw_token_mtx); 1244 1245 if (++ ng_btsocket_l2cap_raw_token == 0) 1246 ng_btsocket_l2cap_raw_token = 1; 1247 1248 *token = ng_btsocket_l2cap_raw_token; 1249 1250 mtx_unlock(&ng_btsocket_l2cap_raw_token_mtx); 1251 } /* ng_btsocket_l2cap_raw_get_token */ 1252 1253 /* 1254 * Send Netgraph message to the node - do not expect reply 1255 */ 1256 1257 static int 1258 ng_btsocket_l2cap_raw_send_ngmsg(hook_p hook, int cmd, void *arg, int arglen) 1259 { 1260 struct ng_mesg *msg = NULL; 1261 int error = 0; 1262 1263 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, arglen, M_NOWAIT); 1264 if (msg == NULL) 1265 return (ENOMEM); 1266 1267 if (arg != NULL && arglen > 0) 1268 bcopy(arg, msg->data, arglen); 1269 1270 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, hook, 0); 1271 1272 return (error); 1273 } /* ng_btsocket_l2cap_raw_send_ngmsg */ 1274 1275 /* 1276 * Send Netgraph message to the node (no data) and wait for reply 1277 */ 1278 1279 static int 1280 ng_btsocket_l2cap_raw_send_sync_ngmsg(ng_btsocket_l2cap_raw_pcb_p pcb, 1281 int cmd, void *rsp, int rsplen) 1282 { 1283 struct ng_mesg *msg = NULL; 1284 int error = 0; 1285 1286 mtx_assert(&pcb->pcb_mtx, MA_OWNED); 1287 1288 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, 0, M_NOWAIT); 1289 if (msg == NULL) 1290 return (ENOMEM); 1291 1292 ng_btsocket_l2cap_raw_get_token(&msg->header.token); 1293 pcb->token = msg->header.token; 1294 pcb->msg = NULL; 1295 1296 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, 1297 pcb->rt->hook, 0); 1298 if (error != 0) { 1299 pcb->token = 0; 1300 return (error); 1301 } 1302 1303 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl", 1304 ng_btsocket_l2cap_raw_ioctl_timeout * hz); 1305 pcb->token = 0; 1306 1307 if (error != 0) 1308 return (error); 1309 1310 if (pcb->msg != NULL && pcb->msg->header.cmd == cmd) 1311 bcopy(pcb->msg->data, rsp, rsplen); 1312 else 1313 error = EINVAL; 1314 1315 NG_FREE_MSG(pcb->msg); /* checks for != NULL */ 1316 1317 return (0); 1318 } /* ng_btsocket_l2cap_raw_send_sync_ngmsg */ 1319 1320