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