1 /* 2 * ng_btsocket_l2cap.c 3 */ 4 5 /*- 6 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 7 * 8 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com> 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $Id: ng_btsocket_l2cap.c,v 1.16 2003/09/14 23:29:06 max Exp $ 33 * $FreeBSD$ 34 */ 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/bitstring.h> 39 #include <sys/domain.h> 40 #include <sys/endian.h> 41 #include <sys/errno.h> 42 #include <sys/filedesc.h> 43 #include <sys/ioccom.h> 44 #include <sys/kernel.h> 45 #include <sys/lock.h> 46 #include <sys/malloc.h> 47 #include <sys/mbuf.h> 48 #include <sys/mutex.h> 49 #include <sys/protosw.h> 50 #include <sys/queue.h> 51 #include <sys/socket.h> 52 #include <sys/socketvar.h> 53 #include <sys/sysctl.h> 54 #include <sys/taskqueue.h> 55 56 #include <net/vnet.h> 57 58 #include <netgraph/ng_message.h> 59 #include <netgraph/netgraph.h> 60 #include <netgraph/bluetooth/include/ng_bluetooth.h> 61 #include <netgraph/bluetooth/include/ng_hci.h> 62 #include <netgraph/bluetooth/include/ng_l2cap.h> 63 #include <netgraph/bluetooth/include/ng_btsocket.h> 64 #include <netgraph/bluetooth/include/ng_btsocket_l2cap.h> 65 66 /* MALLOC define */ 67 #ifdef NG_SEPARATE_MALLOC 68 static MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_L2CAP, "netgraph_btsocks_l2cap", 69 "Netgraph Bluetooth L2CAP sockets"); 70 #else 71 #define M_NETGRAPH_BTSOCKET_L2CAP M_NETGRAPH 72 #endif /* NG_SEPARATE_MALLOC */ 73 74 /* Netgraph node methods */ 75 static ng_constructor_t ng_btsocket_l2cap_node_constructor; 76 static ng_rcvmsg_t ng_btsocket_l2cap_node_rcvmsg; 77 static ng_shutdown_t ng_btsocket_l2cap_node_shutdown; 78 static ng_newhook_t ng_btsocket_l2cap_node_newhook; 79 static ng_connect_t ng_btsocket_l2cap_node_connect; 80 static ng_rcvdata_t ng_btsocket_l2cap_node_rcvdata; 81 static ng_disconnect_t ng_btsocket_l2cap_node_disconnect; 82 83 static void ng_btsocket_l2cap_input (void *, int); 84 static void ng_btsocket_l2cap_rtclean (void *, int); 85 86 /* Netgraph type descriptor */ 87 static struct ng_type typestruct = { 88 .version = NG_ABI_VERSION, 89 .name = NG_BTSOCKET_L2CAP_NODE_TYPE, 90 .constructor = ng_btsocket_l2cap_node_constructor, 91 .rcvmsg = ng_btsocket_l2cap_node_rcvmsg, 92 .shutdown = ng_btsocket_l2cap_node_shutdown, 93 .newhook = ng_btsocket_l2cap_node_newhook, 94 .connect = ng_btsocket_l2cap_node_connect, 95 .rcvdata = ng_btsocket_l2cap_node_rcvdata, 96 .disconnect = ng_btsocket_l2cap_node_disconnect, 97 }; 98 99 /* Globals */ 100 extern int ifqmaxlen; 101 static u_int32_t ng_btsocket_l2cap_debug_level; 102 static node_p ng_btsocket_l2cap_node; 103 static struct ng_bt_itemq ng_btsocket_l2cap_queue; 104 static struct mtx ng_btsocket_l2cap_queue_mtx; 105 static struct task ng_btsocket_l2cap_queue_task; 106 static LIST_HEAD(, ng_btsocket_l2cap_pcb) ng_btsocket_l2cap_sockets; 107 static struct mtx ng_btsocket_l2cap_sockets_mtx; 108 static LIST_HEAD(, ng_btsocket_l2cap_rtentry) ng_btsocket_l2cap_rt; 109 static struct mtx ng_btsocket_l2cap_rt_mtx; 110 static struct task ng_btsocket_l2cap_rt_task; 111 static struct timeval ng_btsocket_l2cap_lasttime; 112 static int ng_btsocket_l2cap_curpps; 113 114 /* Sysctl tree */ 115 SYSCTL_DECL(_net_bluetooth_l2cap_sockets); 116 static SYSCTL_NODE(_net_bluetooth_l2cap_sockets, OID_AUTO, seq, 117 CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 118 "Bluetooth SEQPACKET L2CAP sockets family"); 119 SYSCTL_UINT(_net_bluetooth_l2cap_sockets_seq, OID_AUTO, debug_level, 120 CTLFLAG_RW, 121 &ng_btsocket_l2cap_debug_level, NG_BTSOCKET_WARN_LEVEL, 122 "Bluetooth SEQPACKET L2CAP sockets debug level"); 123 SYSCTL_UINT(_net_bluetooth_l2cap_sockets_seq, OID_AUTO, queue_len, 124 CTLFLAG_RD, 125 &ng_btsocket_l2cap_queue.len, 0, 126 "Bluetooth SEQPACKET L2CAP sockets input queue length"); 127 SYSCTL_UINT(_net_bluetooth_l2cap_sockets_seq, OID_AUTO, queue_maxlen, 128 CTLFLAG_RD, 129 &ng_btsocket_l2cap_queue.maxlen, 0, 130 "Bluetooth SEQPACKET L2CAP sockets input queue max. length"); 131 SYSCTL_UINT(_net_bluetooth_l2cap_sockets_seq, OID_AUTO, queue_drops, 132 CTLFLAG_RD, 133 &ng_btsocket_l2cap_queue.drops, 0, 134 "Bluetooth SEQPACKET L2CAP sockets input queue drops"); 135 136 /* Debug */ 137 #define NG_BTSOCKET_L2CAP_INFO \ 138 if (ng_btsocket_l2cap_debug_level >= NG_BTSOCKET_INFO_LEVEL && \ 139 ppsratecheck(&ng_btsocket_l2cap_lasttime, &ng_btsocket_l2cap_curpps, 1)) \ 140 printf 141 142 #define NG_BTSOCKET_L2CAP_WARN \ 143 if (ng_btsocket_l2cap_debug_level >= NG_BTSOCKET_WARN_LEVEL && \ 144 ppsratecheck(&ng_btsocket_l2cap_lasttime, &ng_btsocket_l2cap_curpps, 1)) \ 145 printf 146 147 #define NG_BTSOCKET_L2CAP_ERR \ 148 if (ng_btsocket_l2cap_debug_level >= NG_BTSOCKET_ERR_LEVEL && \ 149 ppsratecheck(&ng_btsocket_l2cap_lasttime, &ng_btsocket_l2cap_curpps, 1)) \ 150 printf 151 152 #define NG_BTSOCKET_L2CAP_ALERT \ 153 if (ng_btsocket_l2cap_debug_level >= NG_BTSOCKET_ALERT_LEVEL && \ 154 ppsratecheck(&ng_btsocket_l2cap_lasttime, &ng_btsocket_l2cap_curpps, 1)) \ 155 printf 156 157 /* 158 * Netgraph message processing routines 159 */ 160 161 static int ng_btsocket_l2cap_process_l2ca_con_req_rsp 162 (struct ng_mesg *, ng_btsocket_l2cap_rtentry_p); 163 static int ng_btsocket_l2cap_process_l2ca_con_rsp_rsp 164 (struct ng_mesg *, ng_btsocket_l2cap_rtentry_p); 165 static int ng_btsocket_l2cap_process_l2ca_con_ind 166 (struct ng_mesg *, ng_btsocket_l2cap_rtentry_p); 167 168 static int ng_btsocket_l2cap_process_l2ca_cfg_req_rsp 169 (struct ng_mesg *, ng_btsocket_l2cap_rtentry_p); 170 static int ng_btsocket_l2cap_process_l2ca_cfg_rsp_rsp 171 (struct ng_mesg *, ng_btsocket_l2cap_rtentry_p); 172 static int ng_btsocket_l2cap_process_l2ca_cfg_ind 173 (struct ng_mesg *, ng_btsocket_l2cap_rtentry_p); 174 175 static int ng_btsocket_l2cap_process_l2ca_discon_rsp 176 (struct ng_mesg *, ng_btsocket_l2cap_rtentry_p); 177 static int ng_btsocket_l2cap_process_l2ca_discon_ind 178 (struct ng_mesg *, ng_btsocket_l2cap_rtentry_p); 179 180 static int ng_btsocket_l2cap_process_l2ca_write_rsp 181 (struct ng_mesg *, ng_btsocket_l2cap_rtentry_p); 182 183 /* 184 * Send L2CA_xxx messages to the lower layer 185 */ 186 187 static int ng_btsocket_l2cap_send_l2ca_con_req 188 (ng_btsocket_l2cap_pcb_p); 189 static int ng_btsocket_l2cap_send_l2ca_con_rsp_req 190 (u_int32_t, ng_btsocket_l2cap_rtentry_p, bdaddr_p, int, int, int, int); 191 static int ng_btsocket_l2cap_send_l2ca_cfg_req 192 (ng_btsocket_l2cap_pcb_p); 193 static int ng_btsocket_l2cap_send_l2ca_cfg_rsp 194 (ng_btsocket_l2cap_pcb_p); 195 static int ng_btsocket_l2cap_send_l2ca_discon_req 196 (u_int32_t, ng_btsocket_l2cap_pcb_p); 197 198 static int ng_btsocket_l2cap_send2 199 (ng_btsocket_l2cap_pcb_p); 200 201 /* 202 * Timeout processing routines 203 */ 204 205 static void ng_btsocket_l2cap_timeout (ng_btsocket_l2cap_pcb_p); 206 static void ng_btsocket_l2cap_untimeout (ng_btsocket_l2cap_pcb_p); 207 static void ng_btsocket_l2cap_process_timeout (void *); 208 209 /* 210 * Other stuff 211 */ 212 213 static ng_btsocket_l2cap_pcb_p ng_btsocket_l2cap_pcb_by_addr(bdaddr_p, int); 214 static ng_btsocket_l2cap_pcb_p ng_btsocket_l2cap_pcb_by_token(u_int32_t); 215 static ng_btsocket_l2cap_pcb_p ng_btsocket_l2cap_pcb_by_cid (bdaddr_p, int,int); 216 static int ng_btsocket_l2cap_result2errno(int); 217 218 static int ng_btsock_l2cap_addrtype_to_linktype(int addrtype); 219 220 #define ng_btsocket_l2cap_wakeup_input_task() \ 221 taskqueue_enqueue(taskqueue_swi_giant, &ng_btsocket_l2cap_queue_task) 222 223 #define ng_btsocket_l2cap_wakeup_route_task() \ 224 taskqueue_enqueue(taskqueue_swi_giant, &ng_btsocket_l2cap_rt_task) 225 226 227 228 int ng_btsock_l2cap_addrtype_to_linktype(int addrtype) 229 { 230 switch(addrtype){ 231 case BDADDR_LE_PUBLIC: 232 return NG_HCI_LINK_LE_PUBLIC; 233 case BDADDR_LE_RANDOM: 234 return NG_HCI_LINK_LE_RANDOM; 235 default: 236 return NG_HCI_LINK_ACL; 237 } 238 } 239 240 241 /***************************************************************************** 242 ***************************************************************************** 243 ** Netgraph node interface 244 ***************************************************************************** 245 *****************************************************************************/ 246 247 /* 248 * Netgraph node constructor. Do not allow to create node of this type. 249 */ 250 251 static int 252 ng_btsocket_l2cap_node_constructor(node_p node) 253 { 254 return (EINVAL); 255 } /* ng_btsocket_l2cap_node_constructor */ 256 257 /* 258 * Do local shutdown processing. Let old node go and create new fresh one. 259 */ 260 261 static int 262 ng_btsocket_l2cap_node_shutdown(node_p node) 263 { 264 int error = 0; 265 266 NG_NODE_UNREF(node); 267 268 /* Create new node */ 269 error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_node); 270 if (error != 0) { 271 NG_BTSOCKET_L2CAP_ALERT( 272 "%s: Could not create Netgraph node, error=%d\n", __func__, error); 273 274 ng_btsocket_l2cap_node = NULL; 275 276 return (error); 277 } 278 279 error = ng_name_node(ng_btsocket_l2cap_node, 280 NG_BTSOCKET_L2CAP_NODE_TYPE); 281 if (error != 0) { 282 NG_BTSOCKET_L2CAP_ALERT( 283 "%s: Could not name Netgraph node, error=%d\n", __func__, error); 284 285 NG_NODE_UNREF(ng_btsocket_l2cap_node); 286 ng_btsocket_l2cap_node = NULL; 287 288 return (error); 289 } 290 291 return (0); 292 } /* ng_btsocket_l2cap_node_shutdown */ 293 294 /* 295 * We allow any hook to be connected to the node. 296 */ 297 298 static int 299 ng_btsocket_l2cap_node_newhook(node_p node, hook_p hook, char const *name) 300 { 301 return (0); 302 } /* ng_btsocket_l2cap_node_newhook */ 303 304 /* 305 * Just say "YEP, that's OK by me!" 306 */ 307 308 static int 309 ng_btsocket_l2cap_node_connect(hook_p hook) 310 { 311 NG_HOOK_SET_PRIVATE(hook, NULL); 312 NG_HOOK_REF(hook); /* Keep extra reference to the hook */ 313 314 #if 0 315 NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); 316 NG_HOOK_FORCE_QUEUE(hook); 317 #endif 318 319 return (0); 320 } /* ng_btsocket_l2cap_node_connect */ 321 322 /* 323 * Hook disconnection. Schedule route cleanup task 324 */ 325 326 static int 327 ng_btsocket_l2cap_node_disconnect(hook_p hook) 328 { 329 /* 330 * If hook has private information than we must have this hook in 331 * the routing table and must schedule cleaning for the routing table. 332 * Otherwise hook was connected but we never got "hook_info" message, 333 * so we have never added this hook to the routing table and it save 334 * to just delete it. 335 */ 336 337 if (NG_HOOK_PRIVATE(hook) != NULL) 338 return (ng_btsocket_l2cap_wakeup_route_task()); 339 340 NG_HOOK_UNREF(hook); /* Remove extra reference */ 341 342 return (0); 343 } /* ng_btsocket_l2cap_node_disconnect */ 344 345 /* 346 * Process incoming messages 347 */ 348 349 static int 350 ng_btsocket_l2cap_node_rcvmsg(node_p node, item_p item, hook_p hook) 351 { 352 struct ng_mesg *msg = NGI_MSG(item); /* item still has message */ 353 int error = 0; 354 355 if (msg != NULL && msg->header.typecookie == NGM_L2CAP_COOKIE) { 356 mtx_lock(&ng_btsocket_l2cap_queue_mtx); 357 if (NG_BT_ITEMQ_FULL(&ng_btsocket_l2cap_queue)) { 358 NG_BTSOCKET_L2CAP_ERR( 359 "%s: Input queue is full (msg)\n", __func__); 360 361 NG_BT_ITEMQ_DROP(&ng_btsocket_l2cap_queue); 362 NG_FREE_ITEM(item); 363 error = ENOBUFS; 364 } else { 365 if (hook != NULL) { 366 NG_HOOK_REF(hook); 367 NGI_SET_HOOK(item, hook); 368 } 369 370 NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_l2cap_queue, item); 371 error = ng_btsocket_l2cap_wakeup_input_task(); 372 } 373 mtx_unlock(&ng_btsocket_l2cap_queue_mtx); 374 } else { 375 NG_FREE_ITEM(item); 376 error = EINVAL; 377 } 378 379 return (error); 380 } /* ng_btsocket_l2cap_node_rcvmsg */ 381 382 /* 383 * Receive data on a hook 384 */ 385 386 static int 387 ng_btsocket_l2cap_node_rcvdata(hook_p hook, item_p item) 388 { 389 int error = 0; 390 391 mtx_lock(&ng_btsocket_l2cap_queue_mtx); 392 if (NG_BT_ITEMQ_FULL(&ng_btsocket_l2cap_queue)) { 393 NG_BTSOCKET_L2CAP_ERR( 394 "%s: Input queue is full (data)\n", __func__); 395 396 NG_BT_ITEMQ_DROP(&ng_btsocket_l2cap_queue); 397 NG_FREE_ITEM(item); 398 error = ENOBUFS; 399 } else { 400 NG_HOOK_REF(hook); 401 NGI_SET_HOOK(item, hook); 402 403 NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_l2cap_queue, item); 404 error = ng_btsocket_l2cap_wakeup_input_task(); 405 } 406 mtx_unlock(&ng_btsocket_l2cap_queue_mtx); 407 408 return (error); 409 } /* ng_btsocket_l2cap_node_rcvdata */ 410 411 /* 412 * Process L2CA_Connect respose. Socket layer must have initiated connection, 413 * so we have to have a socket associated with message token. 414 */ 415 416 static int 417 ng_btsocket_l2cap_process_l2ca_con_req_rsp(struct ng_mesg *msg, 418 ng_btsocket_l2cap_rtentry_p rt) 419 { 420 ng_l2cap_l2ca_con_op *op = NULL; 421 ng_btsocket_l2cap_pcb_t *pcb = NULL; 422 int error = 0; 423 424 if (msg->header.arglen != sizeof(*op)) 425 return (EMSGSIZE); 426 427 op = (ng_l2cap_l2ca_con_op *)(msg->data); 428 429 mtx_lock(&ng_btsocket_l2cap_sockets_mtx); 430 431 /* Look for the socket with the token */ 432 pcb = ng_btsocket_l2cap_pcb_by_token(msg->header.token); 433 if (pcb == NULL) { 434 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 435 return (ENOENT); 436 } 437 438 mtx_lock(&pcb->pcb_mtx); 439 440 NG_BTSOCKET_L2CAP_INFO( 441 "%s: Got L2CA_Connect response, token=%d, src bdaddr=%x:%x:%x:%x:%x:%x, " \ 442 "dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, result=%d, status=%d, " \ 443 "state=%d\n", __func__, msg->header.token, 444 pcb->src.b[5], pcb->src.b[4], pcb->src.b[3], 445 pcb->src.b[2], pcb->src.b[1], pcb->src.b[0], 446 pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3], 447 pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0], 448 pcb->psm, op->lcid, op->result, op->status, 449 pcb->state); 450 451 if (pcb->state != NG_BTSOCKET_L2CAP_CONNECTING) { 452 mtx_unlock(&pcb->pcb_mtx); 453 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 454 455 return (ENOENT); 456 } 457 458 ng_btsocket_l2cap_untimeout(pcb); 459 460 if (op->result == NG_L2CAP_PENDING) { 461 ng_btsocket_l2cap_timeout(pcb); 462 mtx_unlock(&pcb->pcb_mtx); 463 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 464 465 return (0); 466 } 467 468 if (op->result == NG_L2CAP_SUCCESS){ 469 if((pcb->idtype == NG_L2CAP_L2CA_IDTYPE_ATT)|| 470 (pcb->idtype == NG_L2CAP_L2CA_IDTYPE_SMP)){ 471 pcb->encryption = op->encryption; pcb->cid = op->lcid; 472 if(pcb->need_encrypt && !(pcb->encryption)){ 473 ng_btsocket_l2cap_timeout(pcb); 474 pcb->state = NG_BTSOCKET_L2CAP_W4_ENC_CHANGE; 475 }else{ 476 pcb->state = NG_BTSOCKET_L2CAP_OPEN; 477 soisconnected(pcb->so); 478 } 479 }else{ 480 /* 481 * Channel is now open, so update local channel ID and 482 * start configuration process. Source and destination 483 * addresses as well as route must be already set. 484 */ 485 486 pcb->cid = op->lcid; 487 pcb->encryption = op->encryption; 488 error = ng_btsocket_l2cap_send_l2ca_cfg_req(pcb); 489 if (error != 0) { 490 /* Send disconnect request with "zero" token */ 491 ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb); 492 493 /* ... and close the socket */ 494 pcb->state = NG_BTSOCKET_L2CAP_CLOSED; 495 soisdisconnected(pcb->so); 496 } else { 497 pcb->cfg_state = NG_BTSOCKET_L2CAP_CFG_IN_SENT; 498 pcb->state = NG_BTSOCKET_L2CAP_CONFIGURING; 499 500 ng_btsocket_l2cap_timeout(pcb); 501 } 502 } 503 } else { 504 /* 505 * We have failed to open connection, so convert result 506 * code to "errno" code and disconnect the socket. Channel 507 * already has been closed. 508 */ 509 510 pcb->so->so_error = ng_btsocket_l2cap_result2errno(op->result); 511 pcb->state = NG_BTSOCKET_L2CAP_CLOSED; 512 soisdisconnected(pcb->so); 513 } 514 mtx_unlock(&pcb->pcb_mtx); 515 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 516 517 return (error); 518 } /* ng_btsocket_l2cap_process_l2ca_con_req_rsp */ 519 520 /* 521 * Process L2CA_ConnectRsp response 522 */ 523 524 static int 525 ng_btsocket_l2cap_process_l2ca_con_rsp_rsp(struct ng_mesg *msg, 526 ng_btsocket_l2cap_rtentry_p rt) 527 { 528 ng_l2cap_l2ca_con_rsp_op *op = NULL; 529 ng_btsocket_l2cap_pcb_t *pcb = NULL; 530 531 if (msg->header.arglen != sizeof(*op)) 532 return (EMSGSIZE); 533 534 op = (ng_l2cap_l2ca_con_rsp_op *)(msg->data); 535 536 mtx_lock(&ng_btsocket_l2cap_sockets_mtx); 537 538 /* Look for the socket with the token */ 539 pcb = ng_btsocket_l2cap_pcb_by_token(msg->header.token); 540 if (pcb == NULL) { 541 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 542 return (ENOENT); 543 } 544 545 mtx_lock(&pcb->pcb_mtx); 546 547 NG_BTSOCKET_L2CAP_INFO( 548 "%s: Got L2CA_ConnectRsp response, token=%d, src bdaddr=%x:%x:%x:%x:%x:%x, " \ 549 "dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, result=%d, state=%d\n", 550 __func__, msg->header.token, 551 pcb->src.b[5], pcb->src.b[4], pcb->src.b[3], 552 pcb->src.b[2], pcb->src.b[1], pcb->src.b[0], 553 pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3], 554 pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0], 555 pcb->psm, pcb->cid, op->result, pcb->state); 556 557 if (pcb->state != NG_BTSOCKET_L2CAP_CONNECTING) { 558 mtx_unlock(&pcb->pcb_mtx); 559 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 560 561 return (ENOENT); 562 } 563 564 ng_btsocket_l2cap_untimeout(pcb); 565 566 /* Check the result and disconnect the socket on failure */ 567 if (op->result != NG_L2CAP_SUCCESS) { 568 /* Close the socket - channel already closed */ 569 pcb->so->so_error = ng_btsocket_l2cap_result2errno(op->result); 570 pcb->state = NG_BTSOCKET_L2CAP_CLOSED; 571 soisdisconnected(pcb->so); 572 } else { 573 /* Move to CONFIGURING state and wait for CONFIG_IND */ 574 pcb->cfg_state = 0; 575 pcb->state = NG_BTSOCKET_L2CAP_CONFIGURING; 576 ng_btsocket_l2cap_timeout(pcb); 577 } 578 579 mtx_unlock(&pcb->pcb_mtx); 580 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 581 582 return (0); 583 } /* ng_btsocket_process_l2ca_con_rsp_rsp */ 584 585 /* 586 * Process L2CA_Connect indicator. Find socket that listens on address 587 * and PSM. Find exact or closest match. Create new socket and initiate 588 * connection. 589 */ 590 591 static int 592 ng_btsocket_l2cap_process_l2ca_con_ind(struct ng_mesg *msg, 593 ng_btsocket_l2cap_rtentry_p rt) 594 { 595 ng_l2cap_l2ca_con_ind_ip *ip = NULL; 596 ng_btsocket_l2cap_pcb_t *pcb = NULL, *pcb1 = NULL; 597 int error = 0; 598 u_int32_t token = 0; 599 u_int16_t result = 0; 600 601 if (msg->header.arglen != sizeof(*ip)) 602 return (EMSGSIZE); 603 604 ip = (ng_l2cap_l2ca_con_ind_ip *)(msg->data); 605 606 NG_BTSOCKET_L2CAP_INFO( 607 "%s: Got L2CA_Connect indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \ 608 "dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, ident=%d\n", 609 __func__, 610 rt->src.b[5], rt->src.b[4], rt->src.b[3], 611 rt->src.b[2], rt->src.b[1], rt->src.b[0], 612 ip->bdaddr.b[5], ip->bdaddr.b[4], ip->bdaddr.b[3], 613 ip->bdaddr.b[2], ip->bdaddr.b[1], ip->bdaddr.b[0], 614 ip->psm, ip->lcid, ip->ident); 615 616 mtx_lock(&ng_btsocket_l2cap_sockets_mtx); 617 618 pcb = ng_btsocket_l2cap_pcb_by_addr(&rt->src, ip->psm); 619 if (pcb != NULL) { 620 struct socket *so1; 621 622 mtx_lock(&pcb->pcb_mtx); 623 624 CURVNET_SET(pcb->so->so_vnet); 625 so1 = sonewconn(pcb->so, 0); 626 CURVNET_RESTORE(); 627 if (so1 == NULL) { 628 result = NG_L2CAP_NO_RESOURCES; 629 goto respond; 630 } 631 632 /* 633 * If we got here than we have created new socket. So complete 634 * connection. If we we listening on specific address then copy 635 * source address from listening socket, otherwise copy source 636 * address from hook's routing information. 637 */ 638 639 pcb1 = so2l2cap_pcb(so1); 640 KASSERT((pcb1 != NULL), 641 ("%s: pcb1 == NULL\n", __func__)); 642 643 mtx_lock(&pcb1->pcb_mtx); 644 645 if (bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(pcb->src)) != 0) 646 bcopy(&pcb->src, &pcb1->src, sizeof(pcb1->src)); 647 else 648 bcopy(&rt->src, &pcb1->src, sizeof(pcb1->src)); 649 650 pcb1->flags &= ~NG_BTSOCKET_L2CAP_CLIENT; 651 652 bcopy(&ip->bdaddr, &pcb1->dst, sizeof(pcb1->dst)); 653 pcb1->psm = ip->psm; 654 pcb1->cid = ip->lcid; 655 pcb1->rt = rt; 656 657 /* Copy socket settings */ 658 pcb1->imtu = pcb->imtu; 659 bcopy(&pcb->oflow, &pcb1->oflow, sizeof(pcb1->oflow)); 660 pcb1->flush_timo = pcb->flush_timo; 661 662 token = pcb1->token; 663 } else 664 /* Nobody listens on requested BDADDR/PSM */ 665 result = NG_L2CAP_PSM_NOT_SUPPORTED; 666 667 respond: 668 error = ng_btsocket_l2cap_send_l2ca_con_rsp_req(token, rt, 669 &ip->bdaddr, 670 ip->ident, ip->lcid, 671 result,ip->linktype); 672 if (pcb1 != NULL) { 673 if (error != 0) { 674 pcb1->so->so_error = error; 675 pcb1->state = NG_BTSOCKET_L2CAP_CLOSED; 676 soisdisconnected(pcb1->so); 677 } else { 678 pcb1->state = NG_BTSOCKET_L2CAP_CONNECTING; 679 soisconnecting(pcb1->so); 680 681 ng_btsocket_l2cap_timeout(pcb1); 682 } 683 684 mtx_unlock(&pcb1->pcb_mtx); 685 } 686 687 if (pcb != NULL) 688 mtx_unlock(&pcb->pcb_mtx); 689 690 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 691 692 return (error); 693 } /* ng_btsocket_l2cap_process_l2ca_con_ind */ 694 /*Encryption Change*/ 695 static int ng_btsocket_l2cap_process_l2ca_enc_change(struct ng_mesg *msg, ng_btsocket_l2cap_rtentry_p rt) 696 { 697 ng_l2cap_l2ca_enc_chg_op *op = NULL; 698 ng_btsocket_l2cap_pcb_t *pcb = NULL; 699 700 701 if (msg->header.arglen != sizeof(*op)) 702 return (EMSGSIZE); 703 704 op = (ng_l2cap_l2ca_enc_chg_op *)(msg->data); 705 706 mtx_lock(&ng_btsocket_l2cap_sockets_mtx); 707 708 pcb = ng_btsocket_l2cap_pcb_by_cid(&rt->src, op->lcid, 709 op->idtype); 710 if (pcb == NULL) { 711 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 712 return (ENOENT); 713 } 714 715 mtx_lock(&pcb->pcb_mtx); 716 pcb->encryption = op->result; 717 718 if(pcb->need_encrypt){ 719 ng_btsocket_l2cap_untimeout(pcb); 720 if(pcb->state != NG_BTSOCKET_L2CAP_W4_ENC_CHANGE){ 721 NG_BTSOCKET_L2CAP_WARN("%s: Invalid pcb status %d", 722 __func__, pcb->state); 723 }else if(pcb->encryption){ 724 pcb->state = NG_BTSOCKET_L2CAP_OPEN; 725 soisconnected(pcb->so); 726 }else{ 727 pcb->so->so_error = EPERM; 728 ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb); 729 pcb->state = NG_BTSOCKET_L2CAP_CLOSED; 730 soisdisconnected(pcb->so); 731 } 732 } 733 mtx_unlock(&pcb->pcb_mtx); 734 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 735 736 return 0; 737 } 738 /* 739 * Process L2CA_Config response 740 */ 741 742 static int 743 ng_btsocket_l2cap_process_l2ca_cfg_req_rsp(struct ng_mesg *msg, 744 ng_btsocket_l2cap_rtentry_p rt) 745 { 746 ng_l2cap_l2ca_cfg_op *op = NULL; 747 ng_btsocket_l2cap_pcb_p pcb = NULL; 748 749 if (msg->header.arglen != sizeof(*op)) 750 return (EMSGSIZE); 751 752 op = (ng_l2cap_l2ca_cfg_op *)(msg->data); 753 754 mtx_lock(&ng_btsocket_l2cap_sockets_mtx); 755 756 /* 757 * Socket must have issued a Configure request, so we must have a 758 * socket that wants to be configured. Use Netgraph message token 759 * to find it 760 */ 761 762 pcb = ng_btsocket_l2cap_pcb_by_token(msg->header.token); 763 if (pcb == NULL) { 764 /* 765 * XXX FIXME what to do here? We could not find a 766 * socket with requested token. We even can not send 767 * Disconnect, because we do not know channel ID 768 */ 769 770 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 771 return (ENOENT); 772 } 773 774 mtx_lock(&pcb->pcb_mtx); 775 776 NG_BTSOCKET_L2CAP_INFO( 777 "%s: Got L2CA_Config response, token=%d, src bdaddr=%x:%x:%x:%x:%x:%x, " \ 778 "dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, result=%d, state=%d, " \ 779 "cfg_state=%x\n", 780 __func__, msg->header.token, 781 pcb->src.b[5], pcb->src.b[4], pcb->src.b[3], 782 pcb->src.b[2], pcb->src.b[1], pcb->src.b[0], 783 pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3], 784 pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0], 785 pcb->psm, pcb->cid, op->result, pcb->state, pcb->cfg_state); 786 787 if (pcb->state != NG_BTSOCKET_L2CAP_CONFIGURING) { 788 mtx_unlock(&pcb->pcb_mtx); 789 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 790 791 return (ENOENT); 792 } 793 794 if (op->result == NG_L2CAP_SUCCESS) { 795 /* 796 * XXX FIXME Actually set flush and link timeout. 797 * Set QoS here if required. Resolve conficts (flush_timo). 798 * Save incoming MTU (peer's outgoing MTU) and outgoing flow 799 * spec. 800 */ 801 802 pcb->imtu = op->imtu; 803 bcopy(&op->oflow, &pcb->oflow, sizeof(pcb->oflow)); 804 pcb->flush_timo = op->flush_timo; 805 806 /* 807 * We have configured incoming side, so record it and check 808 * if configuration is complete. If complete then mark socket 809 * as connected, otherwise wait for the peer. 810 */ 811 812 pcb->cfg_state &= ~NG_BTSOCKET_L2CAP_CFG_IN_SENT; 813 pcb->cfg_state |= NG_BTSOCKET_L2CAP_CFG_IN; 814 815 if (pcb->cfg_state == NG_BTSOCKET_L2CAP_CFG_BOTH) { 816 /* Configuration complete - mark socket as open */ 817 ng_btsocket_l2cap_untimeout(pcb); 818 pcb->state = NG_BTSOCKET_L2CAP_OPEN; 819 soisconnected(pcb->so); 820 } 821 } else { 822 /* 823 * Something went wrong. Could be unacceptable parameters, 824 * reject or unknown option. That's too bad, but we will 825 * not negotiate. Send Disconnect and close the channel. 826 */ 827 828 ng_btsocket_l2cap_untimeout(pcb); 829 830 switch (op->result) { 831 case NG_L2CAP_UNACCEPTABLE_PARAMS: 832 case NG_L2CAP_UNKNOWN_OPTION: 833 pcb->so->so_error = EINVAL; 834 break; 835 836 default: 837 pcb->so->so_error = ECONNRESET; 838 break; 839 } 840 841 /* Send disconnect with "zero" token */ 842 ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb); 843 844 /* ... and close the socket */ 845 pcb->state = NG_BTSOCKET_L2CAP_CLOSED; 846 soisdisconnected(pcb->so); 847 } 848 849 mtx_unlock(&pcb->pcb_mtx); 850 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 851 852 return (0); 853 } /* ng_btsocket_l2cap_process_l2ca_cfg_req_rsp */ 854 855 /* 856 * Process L2CA_ConfigRsp response 857 */ 858 859 static int 860 ng_btsocket_l2cap_process_l2ca_cfg_rsp_rsp(struct ng_mesg *msg, 861 ng_btsocket_l2cap_rtentry_p rt) 862 { 863 ng_l2cap_l2ca_cfg_rsp_op *op = NULL; 864 ng_btsocket_l2cap_pcb_t *pcb = NULL; 865 int error = 0; 866 867 if (msg->header.arglen != sizeof(*op)) 868 return (EMSGSIZE); 869 870 op = (ng_l2cap_l2ca_cfg_rsp_op *)(msg->data); 871 872 mtx_lock(&ng_btsocket_l2cap_sockets_mtx); 873 874 /* Look for the socket with the token */ 875 pcb = ng_btsocket_l2cap_pcb_by_token(msg->header.token); 876 if (pcb == NULL) { 877 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 878 return (ENOENT); 879 } 880 881 mtx_lock(&pcb->pcb_mtx); 882 883 NG_BTSOCKET_L2CAP_INFO( 884 "%s: Got L2CA_ConfigRsp response, token=%d, src bdaddr=%x:%x:%x:%x:%x:%x, " \ 885 "dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, result=%d, state=%d, " \ 886 "cfg_state=%x\n", 887 __func__, msg->header.token, 888 pcb->src.b[5], pcb->src.b[4], pcb->src.b[3], 889 pcb->src.b[2], pcb->src.b[1], pcb->src.b[0], 890 pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3], 891 pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0], 892 pcb->psm, pcb->cid, op->result, pcb->state, pcb->cfg_state); 893 894 if (pcb->state != NG_BTSOCKET_L2CAP_CONFIGURING) { 895 mtx_unlock(&pcb->pcb_mtx); 896 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 897 898 return (ENOENT); 899 } 900 901 /* Check the result and disconnect socket of failure */ 902 if (op->result != NG_L2CAP_SUCCESS) 903 goto disconnect; 904 905 /* 906 * Now we done with remote side configuration. Configure local 907 * side if we have not done it yet. 908 */ 909 910 pcb->cfg_state &= ~NG_BTSOCKET_L2CAP_CFG_OUT_SENT; 911 pcb->cfg_state |= NG_BTSOCKET_L2CAP_CFG_OUT; 912 913 if (pcb->cfg_state == NG_BTSOCKET_L2CAP_CFG_BOTH) { 914 /* Configuration complete - mask socket as open */ 915 ng_btsocket_l2cap_untimeout(pcb); 916 pcb->state = NG_BTSOCKET_L2CAP_OPEN; 917 soisconnected(pcb->so); 918 } else { 919 if (!(pcb->cfg_state & NG_BTSOCKET_L2CAP_CFG_IN_SENT)) { 920 /* Send L2CA_Config request - incoming path */ 921 error = ng_btsocket_l2cap_send_l2ca_cfg_req(pcb); 922 if (error != 0) 923 goto disconnect; 924 925 pcb->cfg_state |= NG_BTSOCKET_L2CAP_CFG_IN_SENT; 926 } 927 } 928 929 mtx_unlock(&pcb->pcb_mtx); 930 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 931 932 return (error); 933 934 disconnect: 935 ng_btsocket_l2cap_untimeout(pcb); 936 937 /* Send disconnect with "zero" token */ 938 ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb); 939 940 /* ... and close the socket */ 941 pcb->state = NG_BTSOCKET_L2CAP_CLOSED; 942 soisdisconnected(pcb->so); 943 944 mtx_unlock(&pcb->pcb_mtx); 945 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 946 947 return (error); 948 } /* ng_btsocket_l2cap_process_l2ca_cfg_rsp_rsp */ 949 950 /* 951 * Process L2CA_Config indicator 952 */ 953 954 static int 955 ng_btsocket_l2cap_process_l2ca_cfg_ind(struct ng_mesg *msg, 956 ng_btsocket_l2cap_rtentry_p rt) 957 { 958 ng_l2cap_l2ca_cfg_ind_ip *ip = NULL; 959 ng_btsocket_l2cap_pcb_t *pcb = NULL; 960 int error = 0; 961 962 if (msg->header.arglen != sizeof(*ip)) 963 return (EMSGSIZE); 964 965 ip = (ng_l2cap_l2ca_cfg_ind_ip *)(msg->data); 966 967 mtx_lock(&ng_btsocket_l2cap_sockets_mtx); 968 969 /* Check for the open socket that has given channel ID */ 970 pcb = ng_btsocket_l2cap_pcb_by_cid(&rt->src, ip->lcid, 971 NG_L2CAP_L2CA_IDTYPE_BREDR); 972 if (pcb == NULL) { 973 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 974 return (ENOENT); 975 } 976 977 mtx_lock(&pcb->pcb_mtx); 978 979 NG_BTSOCKET_L2CAP_INFO( 980 "%s: Got L2CA_Config indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \ 981 "dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, state=%d, cfg_state=%x\n", 982 __func__, 983 pcb->src.b[5], pcb->src.b[4], pcb->src.b[3], 984 pcb->src.b[2], pcb->src.b[1], pcb->src.b[0], 985 pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3], 986 pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0], 987 pcb->psm, pcb->cid, pcb->state, pcb->cfg_state); 988 989 /* XXX FIXME re-configuration on open socket */ 990 if (pcb->state != NG_BTSOCKET_L2CAP_CONFIGURING) { 991 mtx_unlock(&pcb->pcb_mtx); 992 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 993 994 return (ENOENT); 995 } 996 997 /* 998 * XXX FIXME Actually set flush and link timeout. Set QoS here if 999 * required. Resolve conficts (flush_timo). Note outgoing MTU (peer's 1000 * incoming MTU) and incoming flow spec. 1001 */ 1002 1003 pcb->omtu = ip->omtu; 1004 bcopy(&ip->iflow, &pcb->iflow, sizeof(pcb->iflow)); 1005 pcb->flush_timo = ip->flush_timo; 1006 1007 /* 1008 * Send L2CA_Config response to our peer and check for the errors, 1009 * if any send disconnect to close the channel. 1010 */ 1011 1012 if (!(pcb->cfg_state & NG_BTSOCKET_L2CAP_CFG_OUT_SENT)) { 1013 error = ng_btsocket_l2cap_send_l2ca_cfg_rsp(pcb); 1014 if (error != 0) { 1015 ng_btsocket_l2cap_untimeout(pcb); 1016 1017 pcb->so->so_error = error; 1018 1019 /* Send disconnect with "zero" token */ 1020 ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb); 1021 1022 /* ... and close the socket */ 1023 pcb->state = NG_BTSOCKET_L2CAP_CLOSED; 1024 soisdisconnected(pcb->so); 1025 } else 1026 pcb->cfg_state |= NG_BTSOCKET_L2CAP_CFG_OUT_SENT; 1027 } 1028 1029 mtx_unlock(&pcb->pcb_mtx); 1030 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 1031 1032 return (error); 1033 } /* ng_btsocket_l2cap_process_l2cap_cfg_ind */ 1034 1035 /* 1036 * Process L2CA_Disconnect response 1037 */ 1038 1039 static int 1040 ng_btsocket_l2cap_process_l2ca_discon_rsp(struct ng_mesg *msg, 1041 ng_btsocket_l2cap_rtentry_p rt) 1042 { 1043 ng_l2cap_l2ca_discon_op *op = NULL; 1044 ng_btsocket_l2cap_pcb_t *pcb = NULL; 1045 1046 /* Check message */ 1047 if (msg->header.arglen != sizeof(*op)) 1048 return (EMSGSIZE); 1049 1050 op = (ng_l2cap_l2ca_discon_op *)(msg->data); 1051 1052 mtx_lock(&ng_btsocket_l2cap_sockets_mtx); 1053 1054 /* 1055 * Socket layer must have issued L2CA_Disconnect request, so there 1056 * must be a socket that wants to be disconnected. Use Netgraph 1057 * message token to find it. 1058 */ 1059 1060 pcb = ng_btsocket_l2cap_pcb_by_token(msg->header.token); 1061 if (pcb == NULL) { 1062 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 1063 return (0); 1064 } 1065 1066 mtx_lock(&pcb->pcb_mtx); 1067 1068 /* XXX Close socket no matter what op->result says */ 1069 if (pcb->state != NG_BTSOCKET_L2CAP_CLOSED) { 1070 NG_BTSOCKET_L2CAP_INFO( 1071 "%s: Got L2CA_Disconnect response, token=%d, src bdaddr=%x:%x:%x:%x:%x:%x, " \ 1072 "dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, result=%d, state=%d\n", 1073 __func__, msg->header.token, 1074 pcb->src.b[5], pcb->src.b[4], pcb->src.b[3], 1075 pcb->src.b[2], pcb->src.b[1], pcb->src.b[0], 1076 pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3], 1077 pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0], 1078 pcb->psm, pcb->cid, op->result, pcb->state); 1079 1080 ng_btsocket_l2cap_untimeout(pcb); 1081 1082 pcb->state = NG_BTSOCKET_L2CAP_CLOSED; 1083 soisdisconnected(pcb->so); 1084 } 1085 1086 mtx_unlock(&pcb->pcb_mtx); 1087 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 1088 1089 return (0); 1090 } /* ng_btsocket_l2cap_process_l2ca_discon_rsp */ 1091 1092 /* 1093 * Process L2CA_Disconnect indicator 1094 */ 1095 1096 static int 1097 ng_btsocket_l2cap_process_l2ca_discon_ind(struct ng_mesg *msg, 1098 ng_btsocket_l2cap_rtentry_p rt) 1099 { 1100 ng_l2cap_l2ca_discon_ind_ip *ip = NULL; 1101 ng_btsocket_l2cap_pcb_t *pcb = NULL; 1102 1103 /* Check message */ 1104 if (msg->header.arglen != sizeof(*ip)) 1105 return (EMSGSIZE); 1106 1107 ip = (ng_l2cap_l2ca_discon_ind_ip *)(msg->data); 1108 1109 mtx_lock(&ng_btsocket_l2cap_sockets_mtx); 1110 1111 /* Look for the socket with given channel ID */ 1112 pcb = ng_btsocket_l2cap_pcb_by_cid(&rt->src, ip->lcid, 1113 ip->idtype); 1114 if (pcb == NULL) { 1115 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 1116 return (0); 1117 } 1118 1119 /* 1120 * Channel has already been destroyed, so disconnect the socket 1121 * and be done with it. If there was any pending request we can 1122 * not do anything here anyway. 1123 */ 1124 1125 mtx_lock(&pcb->pcb_mtx); 1126 1127 NG_BTSOCKET_L2CAP_INFO( 1128 "%s: Got L2CA_Disconnect indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \ 1129 "dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, state=%d\n", 1130 __func__, 1131 pcb->src.b[5], pcb->src.b[4], pcb->src.b[3], 1132 pcb->src.b[2], pcb->src.b[1], pcb->src.b[0], 1133 pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3], 1134 pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0], 1135 pcb->psm, pcb->cid, pcb->state); 1136 1137 if (pcb->flags & NG_BTSOCKET_L2CAP_TIMO) 1138 ng_btsocket_l2cap_untimeout(pcb); 1139 1140 pcb->state = NG_BTSOCKET_L2CAP_CLOSED; 1141 soisdisconnected(pcb->so); 1142 1143 mtx_unlock(&pcb->pcb_mtx); 1144 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 1145 1146 return (0); 1147 } /* ng_btsocket_l2cap_process_l2ca_discon_ind */ 1148 1149 /* 1150 * Process L2CA_Write response 1151 */ 1152 1153 static int 1154 ng_btsocket_l2cap_process_l2ca_write_rsp(struct ng_mesg *msg, 1155 ng_btsocket_l2cap_rtentry_p rt) 1156 { 1157 ng_l2cap_l2ca_write_op *op = NULL; 1158 ng_btsocket_l2cap_pcb_t *pcb = NULL; 1159 1160 /* Check message */ 1161 if (msg->header.arglen != sizeof(*op)) 1162 return (EMSGSIZE); 1163 1164 op = (ng_l2cap_l2ca_write_op *)(msg->data); 1165 1166 mtx_lock(&ng_btsocket_l2cap_sockets_mtx); 1167 1168 /* Look for the socket with given token */ 1169 pcb = ng_btsocket_l2cap_pcb_by_token(msg->header.token); 1170 if (pcb == NULL) { 1171 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 1172 return (ENOENT); 1173 } 1174 1175 mtx_lock(&pcb->pcb_mtx); 1176 1177 NG_BTSOCKET_L2CAP_INFO( 1178 "%s: Got L2CA_Write response, src bdaddr=%x:%x:%x:%x:%x:%x, " \ 1179 "dst bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, lcid=%d, result=%d, length=%d, " \ 1180 "state=%d\n", __func__, 1181 pcb->src.b[5], pcb->src.b[4], pcb->src.b[3], 1182 pcb->src.b[2], pcb->src.b[1], pcb->src.b[0], 1183 pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3], 1184 pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0], 1185 pcb->psm, pcb->cid, op->result, op->length, 1186 pcb->state); 1187 1188 if (pcb->state != NG_BTSOCKET_L2CAP_OPEN) { 1189 mtx_unlock(&pcb->pcb_mtx); 1190 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 1191 1192 return (ENOENT); 1193 } 1194 1195 ng_btsocket_l2cap_untimeout(pcb); 1196 1197 /* 1198 * Check if we have more data to send 1199 */ 1200 sbdroprecord(&pcb->so->so_snd); 1201 if (sbavail(&pcb->so->so_snd) > 0) { 1202 if (ng_btsocket_l2cap_send2(pcb) == 0) 1203 ng_btsocket_l2cap_timeout(pcb); 1204 else 1205 sbdroprecord(&pcb->so->so_snd); /* XXX */ 1206 } 1207 1208 /* 1209 * Now set the result, drop packet from the socket send queue and 1210 * ask for more (wakeup sender) 1211 */ 1212 1213 pcb->so->so_error = ng_btsocket_l2cap_result2errno(op->result); 1214 sowwakeup(pcb->so); 1215 1216 mtx_unlock(&pcb->pcb_mtx); 1217 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 1218 1219 return (0); 1220 } /* ng_btsocket_l2cap_process_l2ca_write_rsp */ 1221 1222 /* 1223 * Send L2CA_Connect request 1224 */ 1225 1226 static int 1227 ng_btsocket_l2cap_send_l2ca_con_req(ng_btsocket_l2cap_pcb_p pcb) 1228 { 1229 struct ng_mesg *msg = NULL; 1230 ng_l2cap_l2ca_con_ip *ip = NULL; 1231 int error = 0; 1232 1233 mtx_assert(&pcb->pcb_mtx, MA_OWNED); 1234 1235 if (pcb->rt == NULL || 1236 pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook)) 1237 return (ENETDOWN); 1238 1239 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON, 1240 sizeof(*ip), M_NOWAIT); 1241 if (msg == NULL) 1242 return (ENOMEM); 1243 1244 msg->header.token = pcb->token; 1245 1246 ip = (ng_l2cap_l2ca_con_ip *)(msg->data); 1247 bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr)); 1248 ip->psm = pcb->psm; 1249 ip->linktype = ng_btsock_l2cap_addrtype_to_linktype(pcb->dsttype); 1250 ip->idtype = pcb->idtype; 1251 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_node, msg,pcb->rt->hook, 0); 1252 1253 return (error); 1254 } /* ng_btsocket_l2cap_send_l2ca_con_req */ 1255 1256 /* 1257 * Send L2CA_Connect response 1258 */ 1259 1260 static int 1261 ng_btsocket_l2cap_send_l2ca_con_rsp_req(u_int32_t token, 1262 ng_btsocket_l2cap_rtentry_p rt, bdaddr_p dst, int ident, 1263 int lcid, int result, int linktype) 1264 { 1265 struct ng_mesg *msg = NULL; 1266 ng_l2cap_l2ca_con_rsp_ip *ip = NULL; 1267 int error = 0; 1268 1269 if (rt == NULL || rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook)) 1270 return (ENETDOWN); 1271 1272 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CON_RSP, 1273 sizeof(*ip), M_NOWAIT); 1274 if (msg == NULL) 1275 return (ENOMEM); 1276 1277 msg->header.token = token; 1278 1279 ip = (ng_l2cap_l2ca_con_rsp_ip *)(msg->data); 1280 bcopy(dst, &ip->bdaddr, sizeof(ip->bdaddr)); 1281 ip->ident = ident; 1282 ip->lcid = lcid; 1283 ip->linktype = linktype; 1284 ip->result = result; 1285 ip->status = 0; 1286 1287 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_node, msg, rt->hook, 0); 1288 1289 return (error); 1290 } /* ng_btsocket_l2cap_send_l2ca_con_rsp_req */ 1291 1292 /* 1293 * Send L2CA_Config request 1294 */ 1295 1296 static int 1297 ng_btsocket_l2cap_send_l2ca_cfg_req(ng_btsocket_l2cap_pcb_p pcb) 1298 { 1299 struct ng_mesg *msg = NULL; 1300 ng_l2cap_l2ca_cfg_ip *ip = NULL; 1301 int error = 0; 1302 1303 mtx_assert(&pcb->pcb_mtx, MA_OWNED); 1304 1305 if (pcb->rt == NULL || 1306 pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook)) 1307 return (ENETDOWN); 1308 1309 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG, 1310 sizeof(*ip), M_NOWAIT); 1311 if (msg == NULL) 1312 return (ENOMEM); 1313 1314 msg->header.token = pcb->token; 1315 1316 ip = (ng_l2cap_l2ca_cfg_ip *)(msg->data); 1317 ip->lcid = pcb->cid; 1318 ip->imtu = pcb->imtu; 1319 bcopy(&pcb->oflow, &ip->oflow, sizeof(ip->oflow)); 1320 ip->flush_timo = pcb->flush_timo; 1321 ip->link_timo = pcb->link_timo; 1322 1323 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_node, msg,pcb->rt->hook, 0); 1324 1325 return (error); 1326 } /* ng_btsocket_l2cap_send_l2ca_cfg_req */ 1327 1328 /* 1329 * Send L2CA_Config response 1330 */ 1331 1332 static int 1333 ng_btsocket_l2cap_send_l2ca_cfg_rsp(ng_btsocket_l2cap_pcb_p pcb) 1334 { 1335 struct ng_mesg *msg = NULL; 1336 ng_l2cap_l2ca_cfg_rsp_ip *ip = NULL; 1337 int error = 0; 1338 1339 mtx_assert(&pcb->pcb_mtx, MA_OWNED); 1340 1341 if (pcb->rt == NULL || 1342 pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook)) 1343 return (ENETDOWN); 1344 1345 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_CFG_RSP, 1346 sizeof(*ip), M_NOWAIT); 1347 if (msg == NULL) 1348 return (ENOMEM); 1349 1350 msg->header.token = pcb->token; 1351 1352 ip = (ng_l2cap_l2ca_cfg_rsp_ip *)(msg->data); 1353 ip->lcid = pcb->cid; 1354 ip->omtu = pcb->omtu; 1355 bcopy(&pcb->iflow, &ip->iflow, sizeof(ip->iflow)); 1356 1357 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_node, msg, pcb->rt->hook, 0); 1358 1359 return (error); 1360 } /* ng_btsocket_l2cap_send_l2ca_cfg_rsp */ 1361 1362 /* 1363 * Send L2CA_Disconnect request 1364 */ 1365 1366 static int 1367 ng_btsocket_l2cap_send_l2ca_discon_req(u_int32_t token, 1368 ng_btsocket_l2cap_pcb_p pcb) 1369 { 1370 struct ng_mesg *msg = NULL; 1371 ng_l2cap_l2ca_discon_ip *ip = NULL; 1372 int error = 0; 1373 1374 mtx_assert(&pcb->pcb_mtx, MA_OWNED); 1375 1376 if (pcb->rt == NULL || 1377 pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook)) 1378 return (ENETDOWN); 1379 1380 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_L2CA_DISCON, 1381 sizeof(*ip), M_NOWAIT); 1382 if (msg == NULL) 1383 return (ENOMEM); 1384 1385 msg->header.token = token; 1386 1387 ip = (ng_l2cap_l2ca_discon_ip *)(msg->data); 1388 ip->lcid = pcb->cid; 1389 ip->idtype = pcb->idtype; 1390 1391 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_node, msg,pcb->rt->hook, 0); 1392 1393 return (error); 1394 } /* ng_btsocket_l2cap_send_l2ca_discon_req */ 1395 1396 /***************************************************************************** 1397 ***************************************************************************** 1398 ** Socket interface 1399 ***************************************************************************** 1400 *****************************************************************************/ 1401 1402 /* 1403 * L2CAP sockets data input routine 1404 */ 1405 1406 static void 1407 ng_btsocket_l2cap_data_input(struct mbuf *m, hook_p hook) 1408 { 1409 ng_l2cap_hdr_t *hdr = NULL; 1410 ng_l2cap_clt_hdr_t *clt_hdr = NULL; 1411 ng_btsocket_l2cap_pcb_t *pcb = NULL; 1412 ng_btsocket_l2cap_rtentry_t *rt = NULL; 1413 uint16_t idtype; 1414 1415 if (hook == NULL) { 1416 NG_BTSOCKET_L2CAP_ALERT( 1417 "%s: Invalid source hook for L2CAP data packet\n", __func__); 1418 goto drop; 1419 } 1420 1421 rt = (ng_btsocket_l2cap_rtentry_t *) NG_HOOK_PRIVATE(hook); 1422 if (rt == NULL) { 1423 NG_BTSOCKET_L2CAP_ALERT( 1424 "%s: Could not find out source bdaddr for L2CAP data packet\n", __func__); 1425 goto drop; 1426 } 1427 1428 m = m_pullup(m, sizeof(uint16_t)); 1429 idtype = *mtod(m, uint16_t *); 1430 m_adj(m, sizeof(uint16_t)); 1431 1432 /* Make sure we can access header */ 1433 if (m->m_pkthdr.len < sizeof(*hdr)) { 1434 NG_BTSOCKET_L2CAP_ERR( 1435 "%s: L2CAP data packet too small, len=%d\n", __func__, m->m_pkthdr.len); 1436 goto drop; 1437 } 1438 1439 if (m->m_len < sizeof(*hdr)) { 1440 m = m_pullup(m, sizeof(*hdr)); 1441 if (m == NULL) 1442 goto drop; 1443 } 1444 1445 /* Strip L2CAP packet header and verify packet length */ 1446 hdr = mtod(m, ng_l2cap_hdr_t *); 1447 m_adj(m, sizeof(*hdr)); 1448 1449 if (hdr->length != m->m_pkthdr.len) { 1450 NG_BTSOCKET_L2CAP_ERR( 1451 "%s: Bad L2CAP data packet length, len=%d, length=%d\n", 1452 __func__, m->m_pkthdr.len, hdr->length); 1453 goto drop; 1454 } 1455 1456 /* 1457 * Now process packet. Two cases: 1458 * 1459 * 1) Normal packet (cid != 2) then find connected socket and append 1460 * mbuf to the socket queue. Wakeup socket. 1461 * 1462 * 2) Broadcast packet (cid == 2) then find all sockets that connected 1463 * to the given PSM and have SO_BROADCAST bit set and append mbuf 1464 * to the socket queue. Wakeup socket. 1465 */ 1466 1467 NG_BTSOCKET_L2CAP_INFO( 1468 "%s: Received L2CAP data packet: src bdaddr=%x:%x:%x:%x:%x:%x, " \ 1469 "dcid=%d, length=%d\n", 1470 __func__, 1471 rt->src.b[5], rt->src.b[4], rt->src.b[3], 1472 rt->src.b[2], rt->src.b[1], rt->src.b[0], 1473 hdr->dcid, hdr->length); 1474 1475 if ((hdr->dcid >= NG_L2CAP_FIRST_CID) || 1476 (idtype == NG_L2CAP_L2CA_IDTYPE_ATT)|| 1477 (idtype == NG_L2CAP_L2CA_IDTYPE_SMP) 1478 ){ 1479 1480 mtx_lock(&ng_btsocket_l2cap_sockets_mtx); 1481 1482 /* Normal packet: find connected socket */ 1483 pcb = ng_btsocket_l2cap_pcb_by_cid(&rt->src, hdr->dcid,idtype); 1484 if (pcb == NULL) { 1485 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 1486 goto drop; 1487 } 1488 1489 mtx_lock(&pcb->pcb_mtx); 1490 1491 if (pcb->state != NG_BTSOCKET_L2CAP_OPEN) { 1492 NG_BTSOCKET_L2CAP_ERR( 1493 "%s: No connected socket found, src bdaddr=%x:%x:%x:%x:%x:%x, dcid=%d, " \ 1494 "state=%d\n", __func__, 1495 rt->src.b[5], rt->src.b[4], rt->src.b[3], 1496 rt->src.b[2], rt->src.b[1], rt->src.b[0], 1497 hdr->dcid, pcb->state); 1498 1499 mtx_unlock(&pcb->pcb_mtx); 1500 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 1501 goto drop; 1502 } 1503 1504 /* Check packet size against socket's incoming MTU */ 1505 if (hdr->length > pcb->imtu) { 1506 NG_BTSOCKET_L2CAP_ERR( 1507 "%s: L2CAP data packet too big, src bdaddr=%x:%x:%x:%x:%x:%x, " \ 1508 "dcid=%d, length=%d, imtu=%d\n", 1509 __func__, 1510 rt->src.b[5], rt->src.b[4], rt->src.b[3], 1511 rt->src.b[2], rt->src.b[1], rt->src.b[0], 1512 hdr->dcid, hdr->length, pcb->imtu); 1513 1514 mtx_unlock(&pcb->pcb_mtx); 1515 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 1516 goto drop; 1517 } 1518 1519 /* Check if we have enough space in socket receive queue */ 1520 if (m->m_pkthdr.len > sbspace(&pcb->so->so_rcv)) { 1521 1522 /* 1523 * This is really bad. Receive queue on socket does 1524 * not have enough space for the packet. We do not 1525 * have any other choice but drop the packet. L2CAP 1526 * does not provide any flow control. 1527 */ 1528 1529 NG_BTSOCKET_L2CAP_ERR( 1530 "%s: Not enough space in socket receive queue. Dropping L2CAP data packet, " \ 1531 "src bdaddr=%x:%x:%x:%x:%x:%x, dcid=%d, len=%d, space=%ld\n", 1532 __func__, 1533 rt->src.b[5], rt->src.b[4], rt->src.b[3], 1534 rt->src.b[2], rt->src.b[1], rt->src.b[0], 1535 hdr->dcid, m->m_pkthdr.len, 1536 sbspace(&pcb->so->so_rcv)); 1537 1538 mtx_unlock(&pcb->pcb_mtx); 1539 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 1540 goto drop; 1541 } 1542 1543 /* Append packet to the socket receive queue and wakeup */ 1544 sbappendrecord(&pcb->so->so_rcv, m); 1545 m = NULL; 1546 1547 sorwakeup(pcb->so); 1548 1549 mtx_unlock(&pcb->pcb_mtx); 1550 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 1551 } else if (hdr->dcid == NG_L2CAP_CLT_CID) { 1552 /* Broadcast packet: give packet to all sockets */ 1553 1554 /* Check packet size against connectionless MTU */ 1555 if (hdr->length > NG_L2CAP_MTU_DEFAULT) { 1556 NG_BTSOCKET_L2CAP_ERR( 1557 "%s: Connectionless L2CAP data packet too big, " \ 1558 "src bdaddr=%x:%x:%x:%x:%x:%x, length=%d\n", 1559 __func__, 1560 rt->src.b[5], rt->src.b[4], rt->src.b[3], 1561 rt->src.b[2], rt->src.b[1], rt->src.b[0], 1562 hdr->length); 1563 goto drop; 1564 } 1565 1566 /* Make sure we can access connectionless header */ 1567 if (m->m_pkthdr.len < sizeof(*clt_hdr)) { 1568 NG_BTSOCKET_L2CAP_ERR( 1569 "%s: Can not get L2CAP connectionless packet header, " \ 1570 "src bdaddr=%x:%x:%x:%x:%x:%x, length=%d\n", 1571 __func__, 1572 rt->src.b[5], rt->src.b[4], rt->src.b[3], 1573 rt->src.b[2], rt->src.b[1], rt->src.b[0], 1574 hdr->length); 1575 goto drop; 1576 } 1577 1578 if (m->m_len < sizeof(*clt_hdr)) { 1579 m = m_pullup(m, sizeof(*clt_hdr)); 1580 if (m == NULL) 1581 goto drop; 1582 } 1583 1584 /* Strip connectionless header and deliver packet */ 1585 clt_hdr = mtod(m, ng_l2cap_clt_hdr_t *); 1586 m_adj(m, sizeof(*clt_hdr)); 1587 1588 NG_BTSOCKET_L2CAP_INFO( 1589 "%s: Got L2CAP connectionless data packet, " \ 1590 "src bdaddr=%x:%x:%x:%x:%x:%x, psm=%d, length=%d\n", 1591 __func__, 1592 rt->src.b[5], rt->src.b[4], rt->src.b[3], 1593 rt->src.b[2], rt->src.b[1], rt->src.b[0], 1594 clt_hdr->psm, hdr->length); 1595 1596 mtx_lock(&ng_btsocket_l2cap_sockets_mtx); 1597 1598 LIST_FOREACH(pcb, &ng_btsocket_l2cap_sockets, next) { 1599 struct mbuf *copy = NULL; 1600 1601 mtx_lock(&pcb->pcb_mtx); 1602 1603 if (bcmp(&rt->src, &pcb->src, sizeof(pcb->src)) != 0 || 1604 pcb->psm != clt_hdr->psm || 1605 pcb->state != NG_BTSOCKET_L2CAP_OPEN || 1606 (pcb->so->so_options & SO_BROADCAST) == 0 || 1607 m->m_pkthdr.len > sbspace(&pcb->so->so_rcv)) 1608 goto next; 1609 1610 /* 1611 * Create a copy of the packet and append it to the 1612 * socket's queue. If m_dup() failed - no big deal 1613 * it is a broadcast traffic after all 1614 */ 1615 1616 copy = m_dup(m, M_NOWAIT); 1617 if (copy != NULL) { 1618 sbappendrecord(&pcb->so->so_rcv, copy); 1619 sorwakeup(pcb->so); 1620 } 1621 next: 1622 mtx_unlock(&pcb->pcb_mtx); 1623 } 1624 1625 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 1626 } 1627 drop: 1628 NG_FREE_M(m); /* checks for m != NULL */ 1629 } /* ng_btsocket_l2cap_data_input */ 1630 1631 /* 1632 * L2CAP sockets default message input routine 1633 */ 1634 1635 static void 1636 ng_btsocket_l2cap_default_msg_input(struct ng_mesg *msg, hook_p hook) 1637 { 1638 switch (msg->header.cmd) { 1639 case NGM_L2CAP_NODE_HOOK_INFO: { 1640 ng_btsocket_l2cap_rtentry_t *rt = NULL; 1641 ng_l2cap_node_hook_info_ep *ep = 1642 (ng_l2cap_node_hook_info_ep *)msg->data; 1643 if (hook == NULL || msg->header.arglen != sizeof(*ep)) 1644 break; 1645 1646 if (bcmp(&ep->addr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) 1647 break; 1648 1649 mtx_lock(&ng_btsocket_l2cap_rt_mtx); 1650 1651 rt = (ng_btsocket_l2cap_rtentry_t *) NG_HOOK_PRIVATE(hook); 1652 if (rt == NULL) { 1653 rt = malloc(sizeof(*rt), 1654 M_NETGRAPH_BTSOCKET_L2CAP, M_NOWAIT|M_ZERO); 1655 if (rt == NULL) { 1656 mtx_unlock(&ng_btsocket_l2cap_rt_mtx); 1657 break; 1658 } 1659 1660 LIST_INSERT_HEAD(&ng_btsocket_l2cap_rt, rt, next); 1661 1662 NG_HOOK_SET_PRIVATE(hook, rt); 1663 } 1664 1665 bcopy(&ep->addr, &rt->src, sizeof(rt->src)); 1666 rt->hook = hook; 1667 1668 mtx_unlock(&ng_btsocket_l2cap_rt_mtx); 1669 1670 NG_BTSOCKET_L2CAP_INFO( 1671 "%s: Updating hook \"%s\", src bdaddr=%x:%x:%x:%x:%x:%x\n", 1672 __func__, NG_HOOK_NAME(hook), 1673 rt->src.b[5], rt->src.b[4], rt->src.b[3], 1674 rt->src.b[2], rt->src.b[1], rt->src.b[0]); 1675 } break; 1676 1677 default: 1678 NG_BTSOCKET_L2CAP_WARN( 1679 "%s: Unknown message, cmd=%d\n", __func__, msg->header.cmd); 1680 break; 1681 } 1682 1683 NG_FREE_MSG(msg); /* Checks for msg != NULL */ 1684 } /* ng_btsocket_l2cap_default_msg_input */ 1685 1686 /* 1687 * L2CAP sockets L2CA message input routine 1688 */ 1689 1690 static void 1691 ng_btsocket_l2cap_l2ca_msg_input(struct ng_mesg *msg, hook_p hook) 1692 { 1693 ng_btsocket_l2cap_rtentry_p rt = NULL; 1694 1695 if (hook == NULL) { 1696 NG_BTSOCKET_L2CAP_ALERT( 1697 "%s: Invalid source hook for L2CA message\n", __func__); 1698 goto drop; 1699 } 1700 1701 rt = (ng_btsocket_l2cap_rtentry_p) NG_HOOK_PRIVATE(hook); 1702 if (rt == NULL) { 1703 NG_BTSOCKET_L2CAP_ALERT( 1704 "%s: Could not find out source bdaddr for L2CA message\n", __func__); 1705 goto drop; 1706 } 1707 1708 switch (msg->header.cmd) { 1709 case NGM_L2CAP_L2CA_CON: /* L2CA_Connect response */ 1710 ng_btsocket_l2cap_process_l2ca_con_req_rsp(msg, rt); 1711 break; 1712 1713 case NGM_L2CAP_L2CA_CON_RSP: /* L2CA_ConnectRsp response */ 1714 ng_btsocket_l2cap_process_l2ca_con_rsp_rsp(msg, rt); 1715 break; 1716 1717 case NGM_L2CAP_L2CA_CON_IND: /* L2CA_Connect indicator */ 1718 ng_btsocket_l2cap_process_l2ca_con_ind(msg, rt); 1719 break; 1720 1721 case NGM_L2CAP_L2CA_CFG: /* L2CA_Config response */ 1722 ng_btsocket_l2cap_process_l2ca_cfg_req_rsp(msg, rt); 1723 break; 1724 1725 case NGM_L2CAP_L2CA_CFG_RSP: /* L2CA_ConfigRsp response */ 1726 ng_btsocket_l2cap_process_l2ca_cfg_rsp_rsp(msg, rt); 1727 break; 1728 1729 case NGM_L2CAP_L2CA_CFG_IND: /* L2CA_Config indicator */ 1730 ng_btsocket_l2cap_process_l2ca_cfg_ind(msg, rt); 1731 break; 1732 1733 case NGM_L2CAP_L2CA_DISCON: /* L2CA_Disconnect response */ 1734 ng_btsocket_l2cap_process_l2ca_discon_rsp(msg, rt); 1735 break; 1736 1737 case NGM_L2CAP_L2CA_DISCON_IND: /* L2CA_Disconnect indicator */ 1738 ng_btsocket_l2cap_process_l2ca_discon_ind(msg, rt); 1739 break; 1740 1741 case NGM_L2CAP_L2CA_WRITE: /* L2CA_Write response */ 1742 ng_btsocket_l2cap_process_l2ca_write_rsp(msg, rt); 1743 break; 1744 case NGM_L2CAP_L2CA_ENC_CHANGE: 1745 ng_btsocket_l2cap_process_l2ca_enc_change(msg, rt); 1746 1747 break; 1748 /* XXX FIXME add other L2CA messages */ 1749 1750 default: 1751 NG_BTSOCKET_L2CAP_WARN( 1752 "%s: Unknown L2CA message, cmd=%d\n", __func__, msg->header.cmd); 1753 break; 1754 } 1755 drop: 1756 NG_FREE_MSG(msg); 1757 } /* ng_btsocket_l2cap_l2ca_msg_input */ 1758 1759 /* 1760 * L2CAP sockets input routine 1761 */ 1762 1763 static void 1764 ng_btsocket_l2cap_input(void *context, int pending) 1765 { 1766 item_p item = NULL; 1767 hook_p hook = NULL; 1768 1769 for (;;) { 1770 mtx_lock(&ng_btsocket_l2cap_queue_mtx); 1771 NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_l2cap_queue, item); 1772 mtx_unlock(&ng_btsocket_l2cap_queue_mtx); 1773 1774 if (item == NULL) 1775 break; 1776 1777 NGI_GET_HOOK(item, hook); 1778 if (hook != NULL && NG_HOOK_NOT_VALID(hook)) 1779 goto drop; 1780 1781 switch(item->el_flags & NGQF_TYPE) { 1782 case NGQF_DATA: { 1783 struct mbuf *m = NULL; 1784 1785 NGI_GET_M(item, m); 1786 ng_btsocket_l2cap_data_input(m, hook); 1787 } break; 1788 1789 case NGQF_MESG: { 1790 struct ng_mesg *msg = NULL; 1791 1792 NGI_GET_MSG(item, msg); 1793 1794 switch (msg->header.cmd) { 1795 case NGM_L2CAP_L2CA_CON: 1796 case NGM_L2CAP_L2CA_CON_RSP: 1797 case NGM_L2CAP_L2CA_CON_IND: 1798 case NGM_L2CAP_L2CA_CFG: 1799 case NGM_L2CAP_L2CA_CFG_RSP: 1800 case NGM_L2CAP_L2CA_CFG_IND: 1801 case NGM_L2CAP_L2CA_DISCON: 1802 case NGM_L2CAP_L2CA_DISCON_IND: 1803 case NGM_L2CAP_L2CA_WRITE: 1804 case NGM_L2CAP_L2CA_ENC_CHANGE: 1805 /* XXX FIXME add other L2CA messages */ 1806 ng_btsocket_l2cap_l2ca_msg_input(msg, hook); 1807 break; 1808 1809 default: 1810 ng_btsocket_l2cap_default_msg_input(msg, hook); 1811 break; 1812 } 1813 } break; 1814 1815 default: 1816 KASSERT(0, 1817 ("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE))); 1818 break; 1819 } 1820 drop: 1821 if (hook != NULL) 1822 NG_HOOK_UNREF(hook); 1823 1824 NG_FREE_ITEM(item); 1825 } 1826 } /* ng_btsocket_l2cap_input */ 1827 1828 /* 1829 * Route cleanup task. Gets scheduled when hook is disconnected. Here we 1830 * will find all sockets that use "invalid" hook and disconnect them. 1831 */ 1832 1833 static void 1834 ng_btsocket_l2cap_rtclean(void *context, int pending) 1835 { 1836 ng_btsocket_l2cap_pcb_p pcb = NULL, pcb_next = NULL; 1837 ng_btsocket_l2cap_rtentry_p rt = NULL; 1838 1839 mtx_lock(&ng_btsocket_l2cap_rt_mtx); 1840 mtx_lock(&ng_btsocket_l2cap_sockets_mtx); 1841 1842 /* 1843 * First disconnect all sockets that use "invalid" hook 1844 */ 1845 1846 for (pcb = LIST_FIRST(&ng_btsocket_l2cap_sockets); pcb != NULL; ) { 1847 mtx_lock(&pcb->pcb_mtx); 1848 pcb_next = LIST_NEXT(pcb, next); 1849 1850 if (pcb->rt != NULL && 1851 pcb->rt->hook != NULL && NG_HOOK_NOT_VALID(pcb->rt->hook)) { 1852 if (pcb->flags & NG_BTSOCKET_L2CAP_TIMO) 1853 ng_btsocket_l2cap_untimeout(pcb); 1854 1855 pcb->so->so_error = ENETDOWN; 1856 pcb->state = NG_BTSOCKET_L2CAP_CLOSED; 1857 soisdisconnected(pcb->so); 1858 1859 pcb->token = 0; 1860 pcb->cid = 0; 1861 pcb->rt = NULL; 1862 } 1863 1864 mtx_unlock(&pcb->pcb_mtx); 1865 pcb = pcb_next; 1866 } 1867 1868 /* 1869 * Now cleanup routing table 1870 */ 1871 1872 for (rt = LIST_FIRST(&ng_btsocket_l2cap_rt); rt != NULL; ) { 1873 ng_btsocket_l2cap_rtentry_p rt_next = LIST_NEXT(rt, next); 1874 1875 if (rt->hook != NULL && NG_HOOK_NOT_VALID(rt->hook)) { 1876 LIST_REMOVE(rt, next); 1877 1878 NG_HOOK_SET_PRIVATE(rt->hook, NULL); 1879 NG_HOOK_UNREF(rt->hook); /* Remove extra reference */ 1880 1881 bzero(rt, sizeof(*rt)); 1882 free(rt, M_NETGRAPH_BTSOCKET_L2CAP); 1883 } 1884 1885 rt = rt_next; 1886 } 1887 1888 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 1889 mtx_unlock(&ng_btsocket_l2cap_rt_mtx); 1890 } /* ng_btsocket_l2cap_rtclean */ 1891 1892 /* 1893 * Initialize everything 1894 */ 1895 1896 void 1897 ng_btsocket_l2cap_init(void) 1898 { 1899 int error = 0; 1900 1901 /* Skip initialization of globals for non-default instances. */ 1902 if (!IS_DEFAULT_VNET(curvnet)) 1903 return; 1904 1905 ng_btsocket_l2cap_node = NULL; 1906 ng_btsocket_l2cap_debug_level = NG_BTSOCKET_WARN_LEVEL; 1907 1908 /* Register Netgraph node type */ 1909 error = ng_newtype(&typestruct); 1910 if (error != 0) { 1911 NG_BTSOCKET_L2CAP_ALERT( 1912 "%s: Could not register Netgraph node type, error=%d\n", __func__, error); 1913 1914 return; 1915 } 1916 1917 /* Create Netgrapg node */ 1918 error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_node); 1919 if (error != 0) { 1920 NG_BTSOCKET_L2CAP_ALERT( 1921 "%s: Could not create Netgraph node, error=%d\n", __func__, error); 1922 1923 ng_btsocket_l2cap_node = NULL; 1924 1925 return; 1926 } 1927 1928 error = ng_name_node(ng_btsocket_l2cap_node, 1929 NG_BTSOCKET_L2CAP_NODE_TYPE); 1930 if (error != 0) { 1931 NG_BTSOCKET_L2CAP_ALERT( 1932 "%s: Could not name Netgraph node, error=%d\n", __func__, error); 1933 1934 NG_NODE_UNREF(ng_btsocket_l2cap_node); 1935 ng_btsocket_l2cap_node = NULL; 1936 1937 return; 1938 } 1939 1940 /* Create input queue */ 1941 NG_BT_ITEMQ_INIT(&ng_btsocket_l2cap_queue, ifqmaxlen); 1942 mtx_init(&ng_btsocket_l2cap_queue_mtx, 1943 "btsocks_l2cap_queue_mtx", NULL, MTX_DEF); 1944 TASK_INIT(&ng_btsocket_l2cap_queue_task, 0, 1945 ng_btsocket_l2cap_input, NULL); 1946 1947 /* Create list of sockets */ 1948 LIST_INIT(&ng_btsocket_l2cap_sockets); 1949 mtx_init(&ng_btsocket_l2cap_sockets_mtx, 1950 "btsocks_l2cap_sockets_mtx", NULL, MTX_DEF); 1951 1952 /* Routing table */ 1953 LIST_INIT(&ng_btsocket_l2cap_rt); 1954 mtx_init(&ng_btsocket_l2cap_rt_mtx, 1955 "btsocks_l2cap_rt_mtx", NULL, MTX_DEF); 1956 TASK_INIT(&ng_btsocket_l2cap_rt_task, 0, 1957 ng_btsocket_l2cap_rtclean, NULL); 1958 } /* ng_btsocket_l2cap_init */ 1959 1960 /* 1961 * Abort connection on socket 1962 */ 1963 1964 void 1965 ng_btsocket_l2cap_abort(struct socket *so) 1966 { 1967 so->so_error = ECONNABORTED; 1968 1969 (void)ng_btsocket_l2cap_disconnect(so); 1970 } /* ng_btsocket_l2cap_abort */ 1971 1972 void 1973 ng_btsocket_l2cap_close(struct socket *so) 1974 { 1975 1976 (void)ng_btsocket_l2cap_disconnect(so); 1977 } /* ng_btsocket_l2cap_close */ 1978 1979 /* 1980 * Accept connection on socket. Nothing to do here, socket must be connected 1981 * and ready, so just return peer address and be done with it. 1982 */ 1983 1984 int 1985 ng_btsocket_l2cap_accept(struct socket *so, struct sockaddr **nam) 1986 { 1987 if (ng_btsocket_l2cap_node == NULL) 1988 return (EINVAL); 1989 1990 return (ng_btsocket_l2cap_peeraddr(so, nam)); 1991 } /* ng_btsocket_l2cap_accept */ 1992 1993 /* 1994 * Create and attach new socket 1995 */ 1996 1997 int 1998 ng_btsocket_l2cap_attach(struct socket *so, int proto, struct thread *td) 1999 { 2000 static u_int32_t token = 0; 2001 ng_btsocket_l2cap_pcb_p pcb = so2l2cap_pcb(so); 2002 int error; 2003 2004 /* Check socket and protocol */ 2005 if (ng_btsocket_l2cap_node == NULL) 2006 return (EPROTONOSUPPORT); 2007 if (so->so_type != SOCK_SEQPACKET) 2008 return (ESOCKTNOSUPPORT); 2009 2010 #if 0 /* XXX sonewconn() calls "pru_attach" with proto == 0 */ 2011 if (proto != 0) 2012 if (proto != BLUETOOTH_PROTO_L2CAP) 2013 return (EPROTONOSUPPORT); 2014 #endif /* XXX */ 2015 2016 if (pcb != NULL) 2017 return (EISCONN); 2018 2019 /* Reserve send and receive space if it is not reserved yet */ 2020 if ((so->so_snd.sb_hiwat == 0) || (so->so_rcv.sb_hiwat == 0)) { 2021 error = soreserve(so, NG_BTSOCKET_L2CAP_SENDSPACE, 2022 NG_BTSOCKET_L2CAP_RECVSPACE); 2023 if (error != 0) 2024 return (error); 2025 } 2026 2027 /* Allocate the PCB */ 2028 pcb = malloc(sizeof(*pcb), 2029 M_NETGRAPH_BTSOCKET_L2CAP, M_NOWAIT | M_ZERO); 2030 if (pcb == NULL) 2031 return (ENOMEM); 2032 2033 /* Link the PCB and the socket */ 2034 so->so_pcb = (caddr_t) pcb; 2035 pcb->so = so; 2036 pcb->state = NG_BTSOCKET_L2CAP_CLOSED; 2037 2038 /* Initialize PCB */ 2039 pcb->imtu = pcb->omtu = NG_L2CAP_MTU_DEFAULT; 2040 2041 /* Default flow */ 2042 pcb->iflow.flags = 0x0; 2043 pcb->iflow.service_type = NG_HCI_SERVICE_TYPE_BEST_EFFORT; 2044 pcb->iflow.token_rate = 0xffffffff; /* maximum */ 2045 pcb->iflow.token_bucket_size = 0xffffffff; /* maximum */ 2046 pcb->iflow.peak_bandwidth = 0x00000000; /* maximum */ 2047 pcb->iflow.latency = 0xffffffff; /* don't care */ 2048 pcb->iflow.delay_variation = 0xffffffff; /* don't care */ 2049 2050 bcopy(&pcb->iflow, &pcb->oflow, sizeof(pcb->oflow)); 2051 2052 pcb->flush_timo = NG_L2CAP_FLUSH_TIMO_DEFAULT; 2053 pcb->link_timo = NG_L2CAP_LINK_TIMO_DEFAULT; 2054 2055 /* 2056 * XXX Mark PCB mutex as DUPOK to prevent "duplicated lock of 2057 * the same type" message. When accepting new L2CAP connection 2058 * ng_btsocket_l2cap_process_l2ca_con_ind() holds both PCB mutexes 2059 * for "old" (accepting) PCB and "new" (created) PCB. 2060 */ 2061 2062 mtx_init(&pcb->pcb_mtx, "btsocks_l2cap_pcb_mtx", NULL, 2063 MTX_DEF|MTX_DUPOK); 2064 callout_init_mtx(&pcb->timo, &pcb->pcb_mtx, 0); 2065 2066 /* 2067 * Add the PCB to the list 2068 * 2069 * XXX FIXME VERY IMPORTANT! 2070 * 2071 * This is totally FUBAR. We could get here in two cases: 2072 * 2073 * 1) When user calls socket() 2074 * 2) When we need to accept new incoming connection and call 2075 * sonewconn() 2076 * 2077 * In the first case we must acquire ng_btsocket_l2cap_sockets_mtx. 2078 * In the second case we hold ng_btsocket_l2cap_sockets_mtx already. 2079 * So we now need to distinguish between these cases. From reading 2080 * /sys/kern/uipc_socket.c we can find out that sonewconn() calls 2081 * pru_attach with proto == 0 and td == NULL. For now use this fact 2082 * to figure out if we were called from socket() or from sonewconn(). 2083 */ 2084 2085 if (td != NULL) 2086 mtx_lock(&ng_btsocket_l2cap_sockets_mtx); 2087 else 2088 mtx_assert(&ng_btsocket_l2cap_sockets_mtx, MA_OWNED); 2089 2090 /* Set PCB token. Use ng_btsocket_l2cap_sockets_mtx for protection */ 2091 if (++ token == 0) 2092 token ++; 2093 2094 pcb->token = token; 2095 2096 LIST_INSERT_HEAD(&ng_btsocket_l2cap_sockets, pcb, next); 2097 2098 if (td != NULL) 2099 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 2100 2101 return (0); 2102 } /* ng_btsocket_l2cap_attach */ 2103 2104 /* 2105 * Bind socket 2106 */ 2107 2108 int 2109 ng_btsocket_l2cap_bind(struct socket *so, struct sockaddr *nam, 2110 struct thread *td) 2111 { 2112 ng_btsocket_l2cap_pcb_t *pcb = NULL; 2113 struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *) nam; 2114 int psm, error = 0; 2115 2116 if (ng_btsocket_l2cap_node == NULL) 2117 return (EINVAL); 2118 2119 /* Verify address */ 2120 if (sa == NULL) 2121 return (EINVAL); 2122 if (sa->l2cap_family != AF_BLUETOOTH) 2123 return (EAFNOSUPPORT); 2124 /*For the time being, Not support LE binding.*/ 2125 if ((sa->l2cap_len != sizeof(*sa))&& 2126 (sa->l2cap_len != sizeof(struct sockaddr_l2cap_compat))) 2127 return (EINVAL); 2128 2129 psm = le16toh(sa->l2cap_psm); 2130 2131 /* 2132 * Check if other socket has this address already (look for exact 2133 * match PSM and bdaddr) and assign socket address if it's available. 2134 * 2135 * Note: socket can be bound to ANY PSM (zero) thus allowing several 2136 * channels with the same PSM between the same pair of BD_ADDR'es. 2137 */ 2138 2139 mtx_lock(&ng_btsocket_l2cap_sockets_mtx); 2140 2141 LIST_FOREACH(pcb, &ng_btsocket_l2cap_sockets, next) 2142 if (psm != 0 && psm == pcb->psm && 2143 bcmp(&pcb->src, &sa->l2cap_bdaddr, sizeof(bdaddr_t)) == 0) 2144 break; 2145 2146 if (pcb == NULL) { 2147 /* Set socket address */ 2148 pcb = so2l2cap_pcb(so); 2149 if (pcb != NULL) { 2150 bcopy(&sa->l2cap_bdaddr, &pcb->src, sizeof(pcb->src)); 2151 pcb->psm = psm; 2152 } else 2153 error = EINVAL; 2154 } else 2155 error = EADDRINUSE; 2156 2157 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 2158 2159 return (error); 2160 } /* ng_btsocket_l2cap_bind */ 2161 2162 /* 2163 * Connect socket 2164 */ 2165 2166 int 2167 ng_btsocket_l2cap_connect(struct socket *so, struct sockaddr *nam, 2168 struct thread *td) 2169 { 2170 ng_btsocket_l2cap_pcb_t *pcb = so2l2cap_pcb(so); 2171 struct sockaddr_l2cap_compat *sal = (struct sockaddr_l2cap_compat *) nam; 2172 struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *)nam; 2173 struct sockaddr_l2cap ba; 2174 ng_btsocket_l2cap_rtentry_t *rt = NULL; 2175 int have_src, error = 0; 2176 int idtype = NG_L2CAP_L2CA_IDTYPE_BREDR; 2177 /* Check socket */ 2178 if (pcb == NULL) 2179 return (EINVAL); 2180 if (ng_btsocket_l2cap_node == NULL) 2181 return (EINVAL); 2182 if (pcb->state == NG_BTSOCKET_L2CAP_CONNECTING) 2183 return (EINPROGRESS); 2184 2185 /* Verify address */ 2186 if (sa == NULL) 2187 return (EINVAL); 2188 if (sa->l2cap_family != AF_BLUETOOTH) 2189 return (EAFNOSUPPORT); 2190 if (sa->l2cap_len == sizeof(*sal)){ 2191 bcopy(sal, &ba, sizeof(*sal)); 2192 sa = &ba; 2193 sa->l2cap_len = sizeof(*sa); 2194 sa->l2cap_bdaddr_type = BDADDR_BREDR; 2195 } 2196 if (sa->l2cap_len != sizeof(*sa)) 2197 return (EINVAL); 2198 if ((sa->l2cap_psm && sa->l2cap_cid)) 2199 return EINVAL; 2200 if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) 2201 return (EDESTADDRREQ); 2202 if((sa->l2cap_bdaddr_type == BDADDR_BREDR)&& 2203 (sa->l2cap_psm == 0)) 2204 return EDESTADDRREQ; 2205 if(sa->l2cap_bdaddr_type != BDADDR_BREDR){ 2206 if(sa->l2cap_cid == NG_L2CAP_ATT_CID){ 2207 idtype = NG_L2CAP_L2CA_IDTYPE_ATT; 2208 }else if (sa->l2cap_cid == NG_L2CAP_SMP_CID){ 2209 idtype =NG_L2CAP_L2CA_IDTYPE_SMP; 2210 }else{ 2211 //if cid == 0 idtype = NG_L2CAP_L2CA_IDTYPE_LE; 2212 // Not supported yet 2213 return EINVAL; 2214 } 2215 } 2216 if (pcb->psm != 0 && pcb->psm != le16toh(sa->l2cap_psm)) 2217 return (EINVAL); 2218 /* 2219 * Routing. Socket should be bound to some source address. The source 2220 * address can be ANY. Destination address must be set and it must not 2221 * be ANY. If source address is ANY then find first rtentry that has 2222 * src != dst. 2223 */ 2224 2225 mtx_lock(&ng_btsocket_l2cap_rt_mtx); 2226 mtx_lock(&ng_btsocket_l2cap_sockets_mtx); 2227 mtx_lock(&pcb->pcb_mtx); 2228 2229 /* Send destination address and PSM */ 2230 bcopy(&sa->l2cap_bdaddr, &pcb->dst, sizeof(pcb->dst)); 2231 pcb->psm = le16toh(sa->l2cap_psm); 2232 pcb->dsttype = sa->l2cap_bdaddr_type; 2233 pcb->cid = 0; 2234 pcb->idtype = idtype; 2235 pcb->rt = NULL; 2236 have_src = bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(pcb->src)); 2237 2238 LIST_FOREACH(rt, &ng_btsocket_l2cap_rt, next) { 2239 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook)) 2240 continue; 2241 2242 /* Match src and dst */ 2243 if (have_src) { 2244 if (bcmp(&pcb->src, &rt->src, sizeof(rt->src)) == 0) 2245 break; 2246 } else { 2247 if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0) 2248 break; 2249 } 2250 } 2251 2252 if (rt != NULL) { 2253 pcb->rt = rt; 2254 2255 if (!have_src){ 2256 bcopy(&rt->src, &pcb->src, sizeof(pcb->src)); 2257 pcb->srctype = 2258 (sa->l2cap_bdaddr_type == BDADDR_BREDR)? 2259 BDADDR_BREDR : BDADDR_LE_PUBLIC; 2260 } 2261 } else 2262 error = EHOSTUNREACH; 2263 2264 /* 2265 * Send L2CA_Connect request 2266 */ 2267 2268 if (error == 0) { 2269 error = ng_btsocket_l2cap_send_l2ca_con_req(pcb); 2270 if (error == 0) { 2271 pcb->flags |= NG_BTSOCKET_L2CAP_CLIENT; 2272 pcb->state = NG_BTSOCKET_L2CAP_CONNECTING; 2273 soisconnecting(pcb->so); 2274 2275 ng_btsocket_l2cap_timeout(pcb); 2276 } 2277 } 2278 2279 mtx_unlock(&pcb->pcb_mtx); 2280 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 2281 mtx_unlock(&ng_btsocket_l2cap_rt_mtx); 2282 2283 return (error); 2284 } /* ng_btsocket_l2cap_connect */ 2285 2286 /* 2287 * Process ioctl's calls on socket 2288 */ 2289 2290 int 2291 ng_btsocket_l2cap_control(struct socket *so, u_long cmd, caddr_t data, 2292 struct ifnet *ifp, struct thread *td) 2293 { 2294 return (EINVAL); 2295 } /* ng_btsocket_l2cap_control */ 2296 2297 /* 2298 * Process getsockopt/setsockopt system calls 2299 */ 2300 2301 int 2302 ng_btsocket_l2cap_ctloutput(struct socket *so, struct sockopt *sopt) 2303 { 2304 ng_btsocket_l2cap_pcb_p pcb = so2l2cap_pcb(so); 2305 int error = 0; 2306 ng_l2cap_cfg_opt_val_t v; 2307 2308 if (pcb == NULL) 2309 return (EINVAL); 2310 if (ng_btsocket_l2cap_node == NULL) 2311 return (EINVAL); 2312 2313 if (sopt->sopt_level != SOL_L2CAP) 2314 return (0); 2315 2316 mtx_lock(&pcb->pcb_mtx); 2317 2318 switch (sopt->sopt_dir) { 2319 case SOPT_GET: 2320 switch (sopt->sopt_name) { 2321 case SO_L2CAP_IMTU: /* get incoming MTU */ 2322 error = sooptcopyout(sopt, &pcb->imtu, 2323 sizeof(pcb->imtu)); 2324 break; 2325 2326 case SO_L2CAP_OMTU: /* get outgoing (peer incoming) MTU */ 2327 error = sooptcopyout(sopt, &pcb->omtu, 2328 sizeof(pcb->omtu)); 2329 break; 2330 2331 case SO_L2CAP_IFLOW: /* get incoming flow spec. */ 2332 error = sooptcopyout(sopt, &pcb->iflow, 2333 sizeof(pcb->iflow)); 2334 break; 2335 2336 case SO_L2CAP_OFLOW: /* get outgoing flow spec. */ 2337 error = sooptcopyout(sopt, &pcb->oflow, 2338 sizeof(pcb->oflow)); 2339 break; 2340 2341 case SO_L2CAP_FLUSH: /* get flush timeout */ 2342 error = sooptcopyout(sopt, &pcb->flush_timo, 2343 sizeof(pcb->flush_timo)); 2344 break; 2345 case SO_L2CAP_ENCRYPTED: /* get encrypt required */ 2346 error = sooptcopyout(sopt, &pcb->need_encrypt, 2347 sizeof(pcb->need_encrypt)); 2348 break; 2349 2350 2351 default: 2352 error = ENOPROTOOPT; 2353 break; 2354 } 2355 break; 2356 2357 case SOPT_SET: 2358 /* 2359 * XXX 2360 * We do not allow to change these parameters while socket is 2361 * connected or we are in the process of creating a connection. 2362 * May be this should indicate re-configuration of the open 2363 * channel? 2364 */ 2365 2366 if (pcb->state != NG_BTSOCKET_L2CAP_CLOSED) { 2367 error = EACCES; 2368 break; 2369 } 2370 2371 switch (sopt->sopt_name) { 2372 case SO_L2CAP_IMTU: /* set incoming MTU */ 2373 error = sooptcopyin(sopt, &v, sizeof(v), sizeof(v.mtu)); 2374 if (error == 0) 2375 pcb->imtu = v.mtu; 2376 break; 2377 2378 case SO_L2CAP_OFLOW: /* set outgoing flow spec. */ 2379 error = sooptcopyin(sopt, &v, sizeof(v),sizeof(v.flow)); 2380 if (error == 0) 2381 bcopy(&v.flow, &pcb->oflow, sizeof(pcb->oflow)); 2382 break; 2383 2384 case SO_L2CAP_FLUSH: /* set flush timeout */ 2385 error = sooptcopyin(sopt, &v, sizeof(v), 2386 sizeof(v.flush_timo)); 2387 if (error == 0) 2388 pcb->flush_timo = v.flush_timo; 2389 break; 2390 case SO_L2CAP_ENCRYPTED: /*set connect encryption opt*/ 2391 if((pcb->state != NG_BTSOCKET_L2CAP_OPEN) && 2392 (pcb->state != NG_BTSOCKET_L2CAP_W4_ENC_CHANGE)){ 2393 error = sooptcopyin(sopt, &v, sizeof(v), 2394 sizeof(v.encryption)); 2395 if(error == 0) 2396 pcb->need_encrypt = (v.encryption)?1:0; 2397 }else{ 2398 error = EINVAL; 2399 } 2400 break; 2401 default: 2402 error = ENOPROTOOPT; 2403 break; 2404 } 2405 break; 2406 2407 default: 2408 error = EINVAL; 2409 break; 2410 } 2411 2412 mtx_unlock(&pcb->pcb_mtx); 2413 2414 return (error); 2415 } /* ng_btsocket_l2cap_ctloutput */ 2416 2417 /* 2418 * Detach and destroy socket 2419 */ 2420 2421 void 2422 ng_btsocket_l2cap_detach(struct socket *so) 2423 { 2424 ng_btsocket_l2cap_pcb_p pcb = so2l2cap_pcb(so); 2425 2426 KASSERT(pcb != NULL, ("ng_btsocket_l2cap_detach: pcb == NULL")); 2427 2428 if (ng_btsocket_l2cap_node == NULL) 2429 return; 2430 2431 mtx_lock(&ng_btsocket_l2cap_sockets_mtx); 2432 mtx_lock(&pcb->pcb_mtx); 2433 2434 /* XXX what to do with pending request? */ 2435 if (pcb->flags & NG_BTSOCKET_L2CAP_TIMO) 2436 ng_btsocket_l2cap_untimeout(pcb); 2437 2438 if (pcb->state != NG_BTSOCKET_L2CAP_CLOSED && 2439 pcb->state != NG_BTSOCKET_L2CAP_DISCONNECTING) 2440 /* Send disconnect request with "zero" token */ 2441 ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb); 2442 2443 pcb->state = NG_BTSOCKET_L2CAP_CLOSED; 2444 2445 LIST_REMOVE(pcb, next); 2446 2447 mtx_unlock(&pcb->pcb_mtx); 2448 mtx_unlock(&ng_btsocket_l2cap_sockets_mtx); 2449 2450 mtx_destroy(&pcb->pcb_mtx); 2451 bzero(pcb, sizeof(*pcb)); 2452 free(pcb, M_NETGRAPH_BTSOCKET_L2CAP); 2453 2454 soisdisconnected(so); 2455 so->so_pcb = NULL; 2456 } /* ng_btsocket_l2cap_detach */ 2457 2458 /* 2459 * Disconnect socket 2460 */ 2461 2462 int 2463 ng_btsocket_l2cap_disconnect(struct socket *so) 2464 { 2465 ng_btsocket_l2cap_pcb_p pcb = so2l2cap_pcb(so); 2466 int error = 0; 2467 2468 if (pcb == NULL) 2469 return (EINVAL); 2470 if (ng_btsocket_l2cap_node == NULL) 2471 return (EINVAL); 2472 2473 mtx_lock(&pcb->pcb_mtx); 2474 2475 if (pcb->state == NG_BTSOCKET_L2CAP_DISCONNECTING) { 2476 mtx_unlock(&pcb->pcb_mtx); 2477 return (EINPROGRESS); 2478 } 2479 2480 if (pcb->state != NG_BTSOCKET_L2CAP_CLOSED) { 2481 /* XXX FIXME what to do with pending request? */ 2482 if (pcb->flags & NG_BTSOCKET_L2CAP_TIMO) 2483 ng_btsocket_l2cap_untimeout(pcb); 2484 2485 error = ng_btsocket_l2cap_send_l2ca_discon_req(pcb->token, pcb); 2486 if (error == 0) { 2487 pcb->state = NG_BTSOCKET_L2CAP_DISCONNECTING; 2488 soisdisconnecting(so); 2489 2490 ng_btsocket_l2cap_timeout(pcb); 2491 } 2492 2493 /* XXX FIXME what to do if error != 0 */ 2494 } 2495 2496 mtx_unlock(&pcb->pcb_mtx); 2497 2498 return (error); 2499 } /* ng_btsocket_l2cap_disconnect */ 2500 2501 /* 2502 * Listen on socket 2503 */ 2504 2505 int 2506 ng_btsocket_l2cap_listen(struct socket *so, int backlog, struct thread *td) 2507 { 2508 ng_btsocket_l2cap_pcb_p pcb = so2l2cap_pcb(so); 2509 int error; 2510 2511 SOCK_LOCK(so); 2512 error = solisten_proto_check(so); 2513 if (error != 0) 2514 goto out; 2515 if (pcb == NULL) { 2516 error = EINVAL; 2517 goto out; 2518 } 2519 if (ng_btsocket_l2cap_node == NULL) { 2520 error = EINVAL; 2521 goto out; 2522 } 2523 if (pcb->psm == 0) { 2524 error = EADDRNOTAVAIL; 2525 goto out; 2526 } 2527 solisten_proto(so, backlog); 2528 out: 2529 SOCK_UNLOCK(so); 2530 return (error); 2531 } /* ng_btsocket_listen */ 2532 2533 /* 2534 * Get peer address 2535 */ 2536 2537 int 2538 ng_btsocket_l2cap_peeraddr(struct socket *so, struct sockaddr **nam) 2539 { 2540 ng_btsocket_l2cap_pcb_p pcb = so2l2cap_pcb(so); 2541 struct sockaddr_l2cap sa; 2542 2543 if (pcb == NULL) 2544 return (EINVAL); 2545 if (ng_btsocket_l2cap_node == NULL) 2546 return (EINVAL); 2547 2548 bcopy(&pcb->dst, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr)); 2549 sa.l2cap_psm = htole16(pcb->psm); 2550 sa.l2cap_len = sizeof(sa); 2551 sa.l2cap_family = AF_BLUETOOTH; 2552 switch(pcb->idtype){ 2553 case NG_L2CAP_L2CA_IDTYPE_ATT: 2554 sa.l2cap_cid = NG_L2CAP_ATT_CID; 2555 break; 2556 case NG_L2CAP_L2CA_IDTYPE_SMP: 2557 sa.l2cap_cid = NG_L2CAP_SMP_CID; 2558 break; 2559 default: 2560 sa.l2cap_cid = 0; 2561 break; 2562 } 2563 sa.l2cap_bdaddr_type = pcb->dsttype; 2564 *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT); 2565 2566 return ((*nam == NULL)? ENOMEM : 0); 2567 } /* ng_btsocket_l2cap_peeraddr */ 2568 2569 /* 2570 * Send data to socket 2571 */ 2572 2573 int 2574 ng_btsocket_l2cap_send(struct socket *so, int flags, struct mbuf *m, 2575 struct sockaddr *nam, struct mbuf *control, struct thread *td) 2576 { 2577 ng_btsocket_l2cap_pcb_t *pcb = so2l2cap_pcb(so); 2578 int error = 0; 2579 2580 if (ng_btsocket_l2cap_node == NULL) { 2581 error = ENETDOWN; 2582 goto drop; 2583 } 2584 2585 /* Check socket and input */ 2586 if (pcb == NULL || m == NULL || control != NULL) { 2587 error = EINVAL; 2588 goto drop; 2589 } 2590 2591 mtx_lock(&pcb->pcb_mtx); 2592 2593 /* Make sure socket is connected */ 2594 if (pcb->state != NG_BTSOCKET_L2CAP_OPEN) { 2595 mtx_unlock(&pcb->pcb_mtx); 2596 error = ENOTCONN; 2597 goto drop; 2598 } 2599 2600 /* Check route */ 2601 if (pcb->rt == NULL || 2602 pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook)) { 2603 mtx_unlock(&pcb->pcb_mtx); 2604 error = ENETDOWN; 2605 goto drop; 2606 } 2607 2608 /* Check packet size against outgoing (peer's incoming) MTU) */ 2609 if (m->m_pkthdr.len > pcb->omtu) { 2610 NG_BTSOCKET_L2CAP_ERR( 2611 "%s: Packet too big, len=%d, omtu=%d\n", __func__, m->m_pkthdr.len, pcb->omtu); 2612 2613 mtx_unlock(&pcb->pcb_mtx); 2614 error = EMSGSIZE; 2615 goto drop; 2616 } 2617 2618 /* 2619 * First put packet on socket send queue. Then check if we have 2620 * pending timeout. If we do not have timeout then we must send 2621 * packet and schedule timeout. Otherwise do nothing and wait for 2622 * L2CA_WRITE_RSP. 2623 */ 2624 2625 sbappendrecord(&pcb->so->so_snd, m); 2626 m = NULL; 2627 2628 if (!(pcb->flags & NG_BTSOCKET_L2CAP_TIMO)) { 2629 error = ng_btsocket_l2cap_send2(pcb); 2630 if (error == 0) 2631 ng_btsocket_l2cap_timeout(pcb); 2632 else 2633 sbdroprecord(&pcb->so->so_snd); /* XXX */ 2634 } 2635 2636 mtx_unlock(&pcb->pcb_mtx); 2637 drop: 2638 NG_FREE_M(m); /* checks for != NULL */ 2639 NG_FREE_M(control); 2640 2641 return (error); 2642 } /* ng_btsocket_l2cap_send */ 2643 2644 /* 2645 * Send first packet in the socket queue to the L2CAP layer 2646 */ 2647 2648 static int 2649 ng_btsocket_l2cap_send2(ng_btsocket_l2cap_pcb_p pcb) 2650 { 2651 struct mbuf *m = NULL; 2652 ng_l2cap_l2ca_hdr_t *hdr = NULL; 2653 int error = 0; 2654 2655 mtx_assert(&pcb->pcb_mtx, MA_OWNED); 2656 2657 if (sbavail(&pcb->so->so_snd) == 0) 2658 return (EINVAL); /* XXX */ 2659 2660 m = m_dup(pcb->so->so_snd.sb_mb, M_NOWAIT); 2661 if (m == NULL) 2662 return (ENOBUFS); 2663 2664 /* Create L2CA packet header */ 2665 M_PREPEND(m, sizeof(*hdr), M_NOWAIT); 2666 if (m != NULL) 2667 if (m->m_len < sizeof(*hdr)) 2668 m = m_pullup(m, sizeof(*hdr)); 2669 2670 if (m == NULL) { 2671 NG_BTSOCKET_L2CAP_ERR( 2672 "%s: Failed to create L2CA packet header\n", __func__); 2673 2674 return (ENOBUFS); 2675 } 2676 2677 hdr = mtod(m, ng_l2cap_l2ca_hdr_t *); 2678 hdr->token = pcb->token; 2679 hdr->length = m->m_pkthdr.len - sizeof(*hdr); 2680 hdr->lcid = pcb->cid; 2681 hdr->idtype = pcb->idtype; 2682 NG_BTSOCKET_L2CAP_INFO( 2683 "%s: Sending packet: len=%d, length=%d, lcid=%d, token=%d, state=%d\n", 2684 __func__, m->m_pkthdr.len, hdr->length, hdr->lcid, 2685 hdr->token, pcb->state); 2686 2687 /* 2688 * If we got here than we have successfully creates new L2CAP 2689 * data packet and now we can send it to the L2CAP layer 2690 */ 2691 2692 NG_SEND_DATA_ONLY(error, pcb->rt->hook, m); 2693 2694 return (error); 2695 } /* ng_btsocket_l2cap_send2 */ 2696 2697 /* 2698 * Get socket address 2699 */ 2700 2701 int 2702 ng_btsocket_l2cap_sockaddr(struct socket *so, struct sockaddr **nam) 2703 { 2704 ng_btsocket_l2cap_pcb_p pcb = so2l2cap_pcb(so); 2705 struct sockaddr_l2cap sa; 2706 2707 if (pcb == NULL) 2708 return (EINVAL); 2709 if (ng_btsocket_l2cap_node == NULL) 2710 return (EINVAL); 2711 2712 bcopy(&pcb->src, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr)); 2713 sa.l2cap_psm = htole16(pcb->psm); 2714 sa.l2cap_len = sizeof(sa); 2715 sa.l2cap_family = AF_BLUETOOTH; 2716 sa.l2cap_cid = 0; 2717 sa.l2cap_bdaddr_type = pcb->srctype; 2718 2719 *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT); 2720 2721 return ((*nam == NULL)? ENOMEM : 0); 2722 } /* ng_btsocket_l2cap_sockaddr */ 2723 2724 /***************************************************************************** 2725 ***************************************************************************** 2726 ** Misc. functions 2727 ***************************************************************************** 2728 *****************************************************************************/ 2729 2730 /* 2731 * Look for the socket that listens on given PSM and bdaddr. Returns exact or 2732 * close match (if any). Caller must hold ng_btsocket_l2cap_sockets_mtx. 2733 */ 2734 2735 static ng_btsocket_l2cap_pcb_p 2736 ng_btsocket_l2cap_pcb_by_addr(bdaddr_p bdaddr, int psm) 2737 { 2738 ng_btsocket_l2cap_pcb_p p = NULL, p1 = NULL; 2739 2740 mtx_assert(&ng_btsocket_l2cap_sockets_mtx, MA_OWNED); 2741 2742 LIST_FOREACH(p, &ng_btsocket_l2cap_sockets, next) { 2743 if (p->so == NULL || !(p->so->so_options & SO_ACCEPTCONN) || 2744 p->psm != psm) 2745 continue; 2746 2747 if (bcmp(&p->src, bdaddr, sizeof(p->src)) == 0) 2748 break; 2749 2750 if (bcmp(&p->src, NG_HCI_BDADDR_ANY, sizeof(p->src)) == 0) 2751 p1 = p; 2752 } 2753 2754 return ((p != NULL)? p : p1); 2755 } /* ng_btsocket_l2cap_pcb_by_addr */ 2756 2757 /* 2758 * Look for the socket that has given token. 2759 * Caller must hold ng_btsocket_l2cap_sockets_mtx. 2760 */ 2761 2762 static ng_btsocket_l2cap_pcb_p 2763 ng_btsocket_l2cap_pcb_by_token(u_int32_t token) 2764 { 2765 ng_btsocket_l2cap_pcb_p p = NULL; 2766 2767 if (token == 0) 2768 return (NULL); 2769 2770 mtx_assert(&ng_btsocket_l2cap_sockets_mtx, MA_OWNED); 2771 2772 LIST_FOREACH(p, &ng_btsocket_l2cap_sockets, next) 2773 if (p->token == token) 2774 break; 2775 2776 return (p); 2777 } /* ng_btsocket_l2cap_pcb_by_token */ 2778 2779 /* 2780 * Look for the socket that assigned to given source address and channel ID. 2781 * Caller must hold ng_btsocket_l2cap_sockets_mtx 2782 */ 2783 2784 static ng_btsocket_l2cap_pcb_p 2785 ng_btsocket_l2cap_pcb_by_cid(bdaddr_p src, int cid, int idtype) 2786 { 2787 ng_btsocket_l2cap_pcb_p p = NULL; 2788 2789 mtx_assert(&ng_btsocket_l2cap_sockets_mtx, MA_OWNED); 2790 2791 LIST_FOREACH(p, &ng_btsocket_l2cap_sockets, next){ 2792 if (p->cid == cid && 2793 bcmp(src, &p->src, sizeof(p->src)) == 0&& 2794 p->idtype == idtype) 2795 break; 2796 2797 } 2798 return (p); 2799 } /* ng_btsocket_l2cap_pcb_by_cid */ 2800 2801 /* 2802 * Set timeout on socket 2803 */ 2804 2805 static void 2806 ng_btsocket_l2cap_timeout(ng_btsocket_l2cap_pcb_p pcb) 2807 { 2808 mtx_assert(&pcb->pcb_mtx, MA_OWNED); 2809 2810 if (!(pcb->flags & NG_BTSOCKET_L2CAP_TIMO)) { 2811 pcb->flags |= NG_BTSOCKET_L2CAP_TIMO; 2812 callout_reset(&pcb->timo, bluetooth_l2cap_ertx_timeout(), 2813 ng_btsocket_l2cap_process_timeout, pcb); 2814 } else 2815 KASSERT(0, 2816 ("%s: Duplicated socket timeout?!\n", __func__)); 2817 } /* ng_btsocket_l2cap_timeout */ 2818 2819 /* 2820 * Unset timeout on socket 2821 */ 2822 2823 static void 2824 ng_btsocket_l2cap_untimeout(ng_btsocket_l2cap_pcb_p pcb) 2825 { 2826 mtx_assert(&pcb->pcb_mtx, MA_OWNED); 2827 2828 if (pcb->flags & NG_BTSOCKET_L2CAP_TIMO) { 2829 callout_stop(&pcb->timo); 2830 pcb->flags &= ~NG_BTSOCKET_L2CAP_TIMO; 2831 } else 2832 KASSERT(0, 2833 ("%s: No socket timeout?!\n", __func__)); 2834 } /* ng_btsocket_l2cap_untimeout */ 2835 2836 /* 2837 * Process timeout on socket 2838 */ 2839 2840 static void 2841 ng_btsocket_l2cap_process_timeout(void *xpcb) 2842 { 2843 ng_btsocket_l2cap_pcb_p pcb = (ng_btsocket_l2cap_pcb_p) xpcb; 2844 2845 mtx_assert(&pcb->pcb_mtx, MA_OWNED); 2846 2847 pcb->flags &= ~NG_BTSOCKET_L2CAP_TIMO; 2848 pcb->so->so_error = ETIMEDOUT; 2849 2850 switch (pcb->state) { 2851 case NG_BTSOCKET_L2CAP_CONNECTING: 2852 case NG_BTSOCKET_L2CAP_CONFIGURING: 2853 case NG_BTSOCKET_L2CAP_W4_ENC_CHANGE: 2854 /* Send disconnect request with "zero" token */ 2855 if (pcb->cid != 0) 2856 ng_btsocket_l2cap_send_l2ca_discon_req(0, pcb); 2857 2858 /* ... and close the socket */ 2859 pcb->state = NG_BTSOCKET_L2CAP_CLOSED; 2860 soisdisconnected(pcb->so); 2861 break; 2862 2863 case NG_BTSOCKET_L2CAP_OPEN: 2864 /* Send timeout - drop packet and wakeup sender */ 2865 sbdroprecord(&pcb->so->so_snd); 2866 sowwakeup(pcb->so); 2867 break; 2868 2869 case NG_BTSOCKET_L2CAP_DISCONNECTING: 2870 /* Disconnect timeout - disconnect the socket anyway */ 2871 pcb->state = NG_BTSOCKET_L2CAP_CLOSED; 2872 soisdisconnected(pcb->so); 2873 break; 2874 2875 default: 2876 NG_BTSOCKET_L2CAP_ERR( 2877 "%s: Invalid socket state=%d\n", __func__, pcb->state); 2878 break; 2879 } 2880 } /* ng_btsocket_l2cap_process_timeout */ 2881 2882 /* 2883 * Translate HCI/L2CAP error code into "errno" code 2884 * XXX Note: Some L2CAP and HCI error codes have the same value, but 2885 * different meaning 2886 */ 2887 2888 static int 2889 ng_btsocket_l2cap_result2errno(int result) 2890 { 2891 switch (result) { 2892 case 0x00: /* No error */ 2893 return (0); 2894 2895 case 0x01: /* Unknown HCI command */ 2896 return (ENODEV); 2897 2898 case 0x02: /* No connection */ 2899 return (ENOTCONN); 2900 2901 case 0x03: /* Hardware failure */ 2902 return (EIO); 2903 2904 case 0x04: /* Page timeout */ 2905 return (EHOSTDOWN); 2906 2907 case 0x05: /* Authentication failure */ 2908 case 0x06: /* Key missing */ 2909 case 0x18: /* Pairing not allowed */ 2910 case 0x21: /* Role change not allowed */ 2911 case 0x24: /* LMP PSU not allowed */ 2912 case 0x25: /* Encryption mode not acceptable */ 2913 case 0x26: /* Unit key used */ 2914 return (EACCES); 2915 2916 case 0x07: /* Memory full */ 2917 return (ENOMEM); 2918 2919 case 0x08: /* Connection timeout */ 2920 case 0x10: /* Host timeout */ 2921 case 0x22: /* LMP response timeout */ 2922 case 0xee: /* HCI timeout */ 2923 case 0xeeee: /* L2CAP timeout */ 2924 return (ETIMEDOUT); 2925 2926 case 0x09: /* Max number of connections */ 2927 case 0x0a: /* Max number of SCO connections to a unit */ 2928 return (EMLINK); 2929 2930 case 0x0b: /* ACL connection already exists */ 2931 return (EEXIST); 2932 2933 case 0x0c: /* Command disallowed */ 2934 return (EBUSY); 2935 2936 case 0x0d: /* Host rejected due to limited resources */ 2937 case 0x0e: /* Host rejected due to securiity reasons */ 2938 case 0x0f: /* Host rejected due to remote unit is a personal unit */ 2939 case 0x1b: /* SCO offset rejected */ 2940 case 0x1c: /* SCO interval rejected */ 2941 case 0x1d: /* SCO air mode rejected */ 2942 return (ECONNREFUSED); 2943 2944 case 0x11: /* Unsupported feature or parameter value */ 2945 case 0x19: /* Unknown LMP PDU */ 2946 case 0x1a: /* Unsupported remote feature */ 2947 case 0x20: /* Unsupported LMP parameter value */ 2948 case 0x27: /* QoS is not supported */ 2949 case 0x29: /* Paring with unit key not supported */ 2950 return (EOPNOTSUPP); 2951 2952 case 0x12: /* Invalid HCI command parameter */ 2953 case 0x1e: /* Invalid LMP parameters */ 2954 return (EINVAL); 2955 2956 case 0x13: /* Other end terminated connection: User ended connection */ 2957 case 0x14: /* Other end terminated connection: Low resources */ 2958 case 0x15: /* Other end terminated connection: About to power off */ 2959 return (ECONNRESET); 2960 2961 case 0x16: /* Connection terminated by local host */ 2962 return (ECONNABORTED); 2963 2964 #if 0 /* XXX not yet */ 2965 case 0x17: /* Repeated attempts */ 2966 case 0x1f: /* Unspecified error */ 2967 case 0x23: /* LMP error transaction collision */ 2968 case 0x28: /* Instant passed */ 2969 #endif 2970 } 2971 2972 return (ENOSYS); 2973 } /* ng_btsocket_l2cap_result2errno */ 2974 2975