ng_btsocket_sco.c revision 181093
1181033Semax/* 2181033Semax * ng_btsocket_sco.c 3181033Semax */ 4181033Semax 5181033Semax/*- 6181033Semax * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com> 7181033Semax * All rights reserved. 8181033Semax * 9181033Semax * Redistribution and use in source and binary forms, with or without 10181033Semax * modification, are permitted provided that the following conditions 11181033Semax * are met: 12181033Semax * 1. Redistributions of source code must retain the above copyright 13181033Semax * notice, this list of conditions and the following disclaimer. 14181033Semax * 2. Redistributions in binary form must reproduce the above copyright 15181033Semax * notice, this list of conditions and the following disclaimer in the 16181033Semax * documentation and/or other materials provided with the distribution. 17181033Semax * 18181033Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19181033Semax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20181033Semax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21181033Semax * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22181033Semax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23181033Semax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24181033Semax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25181033Semax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26181033Semax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27181033Semax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28181033Semax * SUCH DAMAGE. 29181033Semax * 30181033Semax * $Id: ng_btsocket_sco.c,v 1.2 2005/10/31 18:08:51 max Exp $ 31181033Semax * $FreeBSD: head/sys/netgraph/bluetooth/socket/ng_btsocket_sco.c 181093 2008-08-01 00:36:43Z emax $ 32181033Semax */ 33181033Semax 34181033Semax#include <sys/param.h> 35181033Semax#include <sys/systm.h> 36181033Semax#include <sys/bitstring.h> 37181033Semax#include <sys/domain.h> 38181033Semax#include <sys/endian.h> 39181033Semax#include <sys/errno.h> 40181033Semax#include <sys/filedesc.h> 41181033Semax#include <sys/ioccom.h> 42181033Semax#include <sys/kernel.h> 43181033Semax#include <sys/lock.h> 44181033Semax#include <sys/malloc.h> 45181033Semax#include <sys/mbuf.h> 46181033Semax#include <sys/mutex.h> 47181033Semax#include <sys/protosw.h> 48181033Semax#include <sys/queue.h> 49181033Semax#include <sys/socket.h> 50181033Semax#include <sys/socketvar.h> 51181033Semax#include <sys/sysctl.h> 52181033Semax#include <sys/taskqueue.h> 53181033Semax#include <netgraph/ng_message.h> 54181033Semax#include <netgraph/netgraph.h> 55181033Semax#include <netgraph/bluetooth/include/ng_bluetooth.h> 56181033Semax#include <netgraph/bluetooth/include/ng_hci.h> 57181033Semax#include <netgraph/bluetooth/include/ng_l2cap.h> 58181033Semax#include <netgraph/bluetooth/include/ng_btsocket.h> 59181033Semax#include <netgraph/bluetooth/include/ng_btsocket_sco.h> 60181033Semax 61181033Semax/* MALLOC define */ 62181033Semax#ifdef NG_SEPARATE_MALLOC 63181033SemaxMALLOC_DEFINE(M_NETGRAPH_BTSOCKET_SCO, "netgraph_btsocks_sco", 64181033Semax "Netgraph Bluetooth SCO sockets"); 65181033Semax#else 66181033Semax#define M_NETGRAPH_BTSOCKET_SCO M_NETGRAPH 67181033Semax#endif /* NG_SEPARATE_MALLOC */ 68181033Semax 69181033Semax/* Netgraph node methods */ 70181033Semaxstatic ng_constructor_t ng_btsocket_sco_node_constructor; 71181033Semaxstatic ng_rcvmsg_t ng_btsocket_sco_node_rcvmsg; 72181033Semaxstatic ng_shutdown_t ng_btsocket_sco_node_shutdown; 73181033Semaxstatic ng_newhook_t ng_btsocket_sco_node_newhook; 74181033Semaxstatic ng_connect_t ng_btsocket_sco_node_connect; 75181033Semaxstatic ng_rcvdata_t ng_btsocket_sco_node_rcvdata; 76181033Semaxstatic ng_disconnect_t ng_btsocket_sco_node_disconnect; 77181033Semax 78181033Semaxstatic void ng_btsocket_sco_input (void *, int); 79181033Semaxstatic void ng_btsocket_sco_rtclean (void *, int); 80181033Semax 81181033Semax/* Netgraph type descriptor */ 82181033Semaxstatic struct ng_type typestruct = { 83181033Semax .version = NG_ABI_VERSION, 84181033Semax .name = NG_BTSOCKET_SCO_NODE_TYPE, 85181033Semax .constructor = ng_btsocket_sco_node_constructor, 86181033Semax .rcvmsg = ng_btsocket_sco_node_rcvmsg, 87181033Semax .shutdown = ng_btsocket_sco_node_shutdown, 88181033Semax .newhook = ng_btsocket_sco_node_newhook, 89181033Semax .connect = ng_btsocket_sco_node_connect, 90181033Semax .rcvdata = ng_btsocket_sco_node_rcvdata, 91181033Semax .disconnect = ng_btsocket_sco_node_disconnect, 92181033Semax}; 93181033Semax 94181033Semax/* Globals */ 95181033Semaxstatic u_int32_t ng_btsocket_sco_debug_level; 96181033Semaxstatic node_p ng_btsocket_sco_node; 97181033Semaxstatic struct ng_bt_itemq ng_btsocket_sco_queue; 98181033Semaxstatic struct mtx ng_btsocket_sco_queue_mtx; 99181033Semaxstatic struct task ng_btsocket_sco_queue_task; 100181033Semaxstatic struct mtx ng_btsocket_sco_sockets_mtx; 101181033Semaxstatic LIST_HEAD(, ng_btsocket_sco_pcb) ng_btsocket_sco_sockets; 102181033Semaxstatic LIST_HEAD(, ng_btsocket_sco_rtentry) ng_btsocket_sco_rt; 103181033Semaxstatic struct mtx ng_btsocket_sco_rt_mtx; 104181033Semaxstatic struct task ng_btsocket_sco_rt_task; 105181093Semaxstatic struct timeval ng_btsocket_sco_lasttime; 106181093Semaxstatic int ng_btsocket_sco_curpps; 107181033Semax 108181033Semax/* Sysctl tree */ 109181033SemaxSYSCTL_DECL(_net_bluetooth_sco_sockets); 110181033SemaxSYSCTL_NODE(_net_bluetooth_sco_sockets, OID_AUTO, seq, CTLFLAG_RW, 111181033Semax 0, "Bluetooth SEQPACKET SCO sockets family"); 112181033SemaxSYSCTL_INT(_net_bluetooth_sco_sockets_seq, OID_AUTO, debug_level, 113181033Semax CTLFLAG_RW, 114181033Semax &ng_btsocket_sco_debug_level, NG_BTSOCKET_WARN_LEVEL, 115181033Semax "Bluetooth SEQPACKET SCO sockets debug level"); 116181033SemaxSYSCTL_INT(_net_bluetooth_sco_sockets_seq, OID_AUTO, queue_len, 117181033Semax CTLFLAG_RD, 118181033Semax &ng_btsocket_sco_queue.len, 0, 119181033Semax "Bluetooth SEQPACKET SCO sockets input queue length"); 120181033SemaxSYSCTL_INT(_net_bluetooth_sco_sockets_seq, OID_AUTO, queue_maxlen, 121181033Semax CTLFLAG_RD, 122181033Semax &ng_btsocket_sco_queue.maxlen, 0, 123181033Semax "Bluetooth SEQPACKET SCO sockets input queue max. length"); 124181033SemaxSYSCTL_INT(_net_bluetooth_sco_sockets_seq, OID_AUTO, queue_drops, 125181033Semax CTLFLAG_RD, 126181033Semax &ng_btsocket_sco_queue.drops, 0, 127181033Semax "Bluetooth SEQPACKET SCO sockets input queue drops"); 128181033Semax 129181033Semax/* Debug */ 130181033Semax#define NG_BTSOCKET_SCO_INFO \ 131181093Semax if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_INFO_LEVEL && \ 132181093Semax ppsratecheck(&ng_btsocket_sco_lasttime, &ng_btsocket_sco_curpps, 1)) \ 133181033Semax printf 134181033Semax 135181033Semax#define NG_BTSOCKET_SCO_WARN \ 136181093Semax if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_WARN_LEVEL && \ 137181093Semax ppsratecheck(&ng_btsocket_sco_lasttime, &ng_btsocket_sco_curpps, 1)) \ 138181033Semax printf 139181033Semax 140181033Semax#define NG_BTSOCKET_SCO_ERR \ 141181093Semax if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_ERR_LEVEL && \ 142181093Semax ppsratecheck(&ng_btsocket_sco_lasttime, &ng_btsocket_sco_curpps, 1)) \ 143181033Semax printf 144181033Semax 145181033Semax#define NG_BTSOCKET_SCO_ALERT \ 146181093Semax if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_ALERT_LEVEL && \ 147181093Semax ppsratecheck(&ng_btsocket_sco_lasttime, &ng_btsocket_sco_curpps, 1)) \ 148181033Semax printf 149181033Semax 150181033Semax/* 151181033Semax * Netgraph message processing routines 152181033Semax */ 153181033Semax 154181033Semaxstatic int ng_btsocket_sco_process_lp_con_cfm 155181033Semax (struct ng_mesg *, ng_btsocket_sco_rtentry_p); 156181033Semaxstatic int ng_btsocket_sco_process_lp_con_ind 157181033Semax (struct ng_mesg *, ng_btsocket_sco_rtentry_p); 158181033Semaxstatic int ng_btsocket_sco_process_lp_discon_ind 159181033Semax (struct ng_mesg *, ng_btsocket_sco_rtentry_p); 160181033Semax 161181033Semax/* 162181033Semax * Send LP messages to the lower layer 163181033Semax */ 164181033Semax 165181033Semaxstatic int ng_btsocket_sco_send_lp_con_req 166181033Semax (ng_btsocket_sco_pcb_p); 167181033Semaxstatic int ng_btsocket_sco_send_lp_con_rsp 168181033Semax (ng_btsocket_sco_rtentry_p, bdaddr_p, int); 169181033Semaxstatic int ng_btsocket_sco_send_lp_discon_req 170181033Semax (ng_btsocket_sco_pcb_p); 171181033Semax 172181033Semaxstatic int ng_btsocket_sco_send2 173181033Semax (ng_btsocket_sco_pcb_p); 174181033Semax 175181033Semax/* 176181033Semax * Timeout processing routines 177181033Semax */ 178181033Semax 179181033Semaxstatic void ng_btsocket_sco_timeout (ng_btsocket_sco_pcb_p); 180181033Semaxstatic void ng_btsocket_sco_untimeout (ng_btsocket_sco_pcb_p); 181181033Semaxstatic void ng_btsocket_sco_process_timeout (void *); 182181033Semax 183181033Semax/* 184181033Semax * Other stuff 185181033Semax */ 186181033Semax 187181033Semaxstatic ng_btsocket_sco_pcb_p ng_btsocket_sco_pcb_by_addr(bdaddr_p); 188181033Semaxstatic ng_btsocket_sco_pcb_p ng_btsocket_sco_pcb_by_handle(bdaddr_p, int); 189181033Semaxstatic ng_btsocket_sco_pcb_p ng_btsocket_sco_pcb_by_addrs(bdaddr_p, bdaddr_p); 190181033Semax 191181033Semax#define ng_btsocket_sco_wakeup_input_task() \ 192181033Semax taskqueue_enqueue(taskqueue_swi, &ng_btsocket_sco_queue_task) 193181033Semax 194181033Semax#define ng_btsocket_sco_wakeup_route_task() \ 195181033Semax taskqueue_enqueue(taskqueue_swi, &ng_btsocket_sco_rt_task) 196181033Semax 197181033Semax/***************************************************************************** 198181033Semax ***************************************************************************** 199181033Semax ** Netgraph node interface 200181033Semax ***************************************************************************** 201181033Semax *****************************************************************************/ 202181033Semax 203181033Semax/* 204181033Semax * Netgraph node constructor. Do not allow to create node of this type. 205181033Semax */ 206181033Semax 207181033Semaxstatic int 208181033Semaxng_btsocket_sco_node_constructor(node_p node) 209181033Semax{ 210181033Semax return (EINVAL); 211181033Semax} /* ng_btsocket_sco_node_constructor */ 212181033Semax 213181033Semax/* 214181033Semax * Do local shutdown processing. Let old node go and create new fresh one. 215181033Semax */ 216181033Semax 217181033Semaxstatic int 218181033Semaxng_btsocket_sco_node_shutdown(node_p node) 219181033Semax{ 220181033Semax int error = 0; 221181033Semax 222181033Semax NG_NODE_UNREF(node); 223181033Semax 224181033Semax /* Create new node */ 225181033Semax error = ng_make_node_common(&typestruct, &ng_btsocket_sco_node); 226181033Semax if (error != 0) { 227181033Semax NG_BTSOCKET_SCO_ALERT( 228181033Semax"%s: Could not create Netgraph node, error=%d\n", __func__, error); 229181033Semax 230181033Semax ng_btsocket_sco_node = NULL; 231181033Semax 232181033Semax return (error); 233181033Semax } 234181033Semax 235181033Semax error = ng_name_node(ng_btsocket_sco_node, 236181033Semax NG_BTSOCKET_SCO_NODE_TYPE); 237181033Semax if (error != 0) { 238181033Semax NG_BTSOCKET_SCO_ALERT( 239181033Semax"%s: Could not name Netgraph node, error=%d\n", __func__, error); 240181033Semax 241181033Semax NG_NODE_UNREF(ng_btsocket_sco_node); 242181033Semax ng_btsocket_sco_node = NULL; 243181033Semax 244181033Semax return (error); 245181033Semax } 246181033Semax 247181033Semax return (0); 248181033Semax} /* ng_btsocket_sco_node_shutdown */ 249181033Semax 250181033Semax/* 251181033Semax * We allow any hook to be connected to the node. 252181033Semax */ 253181033Semax 254181033Semaxstatic int 255181033Semaxng_btsocket_sco_node_newhook(node_p node, hook_p hook, char const *name) 256181033Semax{ 257181033Semax return (0); 258181033Semax} /* ng_btsocket_sco_node_newhook */ 259181033Semax 260181033Semax/* 261181033Semax * Just say "YEP, that's OK by me!" 262181033Semax */ 263181033Semax 264181033Semaxstatic int 265181033Semaxng_btsocket_sco_node_connect(hook_p hook) 266181033Semax{ 267181033Semax NG_HOOK_SET_PRIVATE(hook, NULL); 268181033Semax NG_HOOK_REF(hook); /* Keep extra reference to the hook */ 269181033Semax 270181033Semax#if 0 271181033Semax NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook)); 272181033Semax NG_HOOK_FORCE_QUEUE(hook); 273181033Semax#endif 274181033Semax 275181033Semax return (0); 276181033Semax} /* ng_btsocket_sco_node_connect */ 277181033Semax 278181033Semax/* 279181033Semax * Hook disconnection. Schedule route cleanup task 280181033Semax */ 281181033Semax 282181033Semaxstatic int 283181033Semaxng_btsocket_sco_node_disconnect(hook_p hook) 284181033Semax{ 285181033Semax /* 286181033Semax * If hook has private information than we must have this hook in 287181033Semax * the routing table and must schedule cleaning for the routing table. 288181033Semax * Otherwise hook was connected but we never got "hook_info" message, 289181033Semax * so we have never added this hook to the routing table and it save 290181033Semax * to just delete it. 291181033Semax */ 292181033Semax 293181033Semax if (NG_HOOK_PRIVATE(hook) != NULL) 294181033Semax return (ng_btsocket_sco_wakeup_route_task()); 295181033Semax 296181033Semax NG_HOOK_UNREF(hook); /* Remove extra reference */ 297181033Semax 298181033Semax return (0); 299181033Semax} /* ng_btsocket_sco_node_disconnect */ 300181033Semax 301181033Semax/* 302181033Semax * Process incoming messages 303181033Semax */ 304181033Semax 305181033Semaxstatic int 306181033Semaxng_btsocket_sco_node_rcvmsg(node_p node, item_p item, hook_p hook) 307181033Semax{ 308181033Semax struct ng_mesg *msg = NGI_MSG(item); /* item still has message */ 309181033Semax int error = 0; 310181033Semax 311181033Semax if (msg != NULL && msg->header.typecookie == NGM_HCI_COOKIE) { 312181033Semax mtx_lock(&ng_btsocket_sco_queue_mtx); 313181033Semax if (NG_BT_ITEMQ_FULL(&ng_btsocket_sco_queue)) { 314181033Semax NG_BTSOCKET_SCO_ERR( 315181033Semax"%s: Input queue is full (msg)\n", __func__); 316181033Semax 317181033Semax NG_BT_ITEMQ_DROP(&ng_btsocket_sco_queue); 318181033Semax NG_FREE_ITEM(item); 319181033Semax error = ENOBUFS; 320181033Semax } else { 321181033Semax if (hook != NULL) { 322181033Semax NG_HOOK_REF(hook); 323181033Semax NGI_SET_HOOK(item, hook); 324181033Semax } 325181033Semax 326181033Semax NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_sco_queue, item); 327181033Semax error = ng_btsocket_sco_wakeup_input_task(); 328181033Semax } 329181033Semax mtx_unlock(&ng_btsocket_sco_queue_mtx); 330181033Semax } else { 331181033Semax NG_FREE_ITEM(item); 332181033Semax error = EINVAL; 333181033Semax } 334181033Semax 335181033Semax return (error); 336181033Semax} /* ng_btsocket_sco_node_rcvmsg */ 337181033Semax 338181033Semax/* 339181033Semax * Receive data on a hook 340181033Semax */ 341181033Semax 342181033Semaxstatic int 343181033Semaxng_btsocket_sco_node_rcvdata(hook_p hook, item_p item) 344181033Semax{ 345181033Semax int error = 0; 346181033Semax 347181033Semax mtx_lock(&ng_btsocket_sco_queue_mtx); 348181033Semax if (NG_BT_ITEMQ_FULL(&ng_btsocket_sco_queue)) { 349181033Semax NG_BTSOCKET_SCO_ERR( 350181033Semax"%s: Input queue is full (data)\n", __func__); 351181033Semax 352181033Semax NG_BT_ITEMQ_DROP(&ng_btsocket_sco_queue); 353181033Semax NG_FREE_ITEM(item); 354181033Semax error = ENOBUFS; 355181033Semax } else { 356181033Semax NG_HOOK_REF(hook); 357181033Semax NGI_SET_HOOK(item, hook); 358181033Semax 359181033Semax NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_sco_queue, item); 360181033Semax error = ng_btsocket_sco_wakeup_input_task(); 361181033Semax } 362181033Semax mtx_unlock(&ng_btsocket_sco_queue_mtx); 363181033Semax 364181033Semax return (error); 365181033Semax} /* ng_btsocket_sco_node_rcvdata */ 366181033Semax 367181033Semax/* 368181033Semax * Process LP_ConnectCfm event from the lower layer protocol 369181033Semax */ 370181033Semax 371181033Semaxstatic int 372181033Semaxng_btsocket_sco_process_lp_con_cfm(struct ng_mesg *msg, 373181033Semax ng_btsocket_sco_rtentry_p rt) 374181033Semax{ 375181033Semax ng_hci_lp_con_cfm_ep *ep = NULL; 376181033Semax ng_btsocket_sco_pcb_t *pcb = NULL; 377181033Semax int error = 0; 378181033Semax 379181033Semax if (msg->header.arglen != sizeof(*ep)) 380181033Semax return (EMSGSIZE); 381181033Semax 382181033Semax ep = (ng_hci_lp_con_cfm_ep *)(msg->data); 383181033Semax 384181033Semax mtx_lock(&ng_btsocket_sco_sockets_mtx); 385181033Semax 386181033Semax /* Look for the socket with the token */ 387181033Semax pcb = ng_btsocket_sco_pcb_by_addrs(&rt->src, &ep->bdaddr); 388181033Semax if (pcb == NULL) { 389181033Semax mtx_unlock(&ng_btsocket_sco_sockets_mtx); 390181033Semax return (ENOENT); 391181033Semax } 392181033Semax 393181033Semax /* pcb is locked */ 394181033Semax 395181033Semax NG_BTSOCKET_SCO_INFO( 396181033Semax"%s: Got LP_ConnectCfm response, src bdaddr=%x:%x:%x:%x:%x:%x, " \ 397181033Semax"dst bdaddr=%x:%x:%x:%x:%x:%x, status=%d, handle=%d, state=%d\n", 398181033Semax __func__, 399181033Semax pcb->src.b[5], pcb->src.b[4], pcb->src.b[3], 400181033Semax pcb->src.b[2], pcb->src.b[1], pcb->src.b[0], 401181033Semax pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3], 402181033Semax pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0], 403181033Semax ep->status, ep->con_handle, pcb->state); 404181033Semax 405181033Semax if (pcb->state != NG_BTSOCKET_SCO_CONNECTING) { 406181033Semax mtx_unlock(&pcb->pcb_mtx); 407181033Semax mtx_unlock(&ng_btsocket_sco_sockets_mtx); 408181033Semax 409181033Semax return (ENOENT); 410181033Semax } 411181033Semax 412181033Semax ng_btsocket_sco_untimeout(pcb); 413181033Semax 414181033Semax if (ep->status == 0) { 415181033Semax /* 416181033Semax * Connection is open. Update connection handle and 417181033Semax * socket state 418181033Semax */ 419181033Semax 420181033Semax pcb->con_handle = ep->con_handle; 421181033Semax pcb->state = NG_BTSOCKET_SCO_OPEN; 422181033Semax soisconnected(pcb->so); 423181033Semax } else { 424181033Semax /* 425181033Semax * We have failed to open connection, so disconnect the socket 426181033Semax */ 427181033Semax 428181033Semax pcb->so->so_error = ECONNREFUSED; /* XXX convert status ??? */ 429181033Semax pcb->state = NG_BTSOCKET_SCO_CLOSED; 430181033Semax soisdisconnected(pcb->so); 431181033Semax } 432181033Semax 433181033Semax mtx_unlock(&pcb->pcb_mtx); 434181033Semax mtx_unlock(&ng_btsocket_sco_sockets_mtx); 435181033Semax 436181033Semax return (error); 437181033Semax} /* ng_btsocket_sco_process_lp_con_cfm */ 438181033Semax 439181033Semax/* 440181033Semax * Process LP_ConnectInd indicator. Find socket that listens on address. 441181033Semax * Find exact or closest match. 442181033Semax */ 443181033Semax 444181033Semaxstatic int 445181033Semaxng_btsocket_sco_process_lp_con_ind(struct ng_mesg *msg, 446181033Semax ng_btsocket_sco_rtentry_p rt) 447181033Semax{ 448181033Semax ng_hci_lp_con_ind_ep *ep = NULL; 449181033Semax ng_btsocket_sco_pcb_t *pcb = NULL, *pcb1 = NULL; 450181033Semax int error = 0; 451181033Semax u_int16_t status = 0; 452181033Semax 453181033Semax if (msg->header.arglen != sizeof(*ep)) 454181033Semax return (EMSGSIZE); 455181033Semax 456181033Semax ep = (ng_hci_lp_con_ind_ep *)(msg->data); 457181033Semax 458181033Semax NG_BTSOCKET_SCO_INFO( 459181033Semax"%s: Got LP_ConnectInd indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \ 460181033Semax"dst bdaddr=%x:%x:%x:%x:%x:%x\n", 461181033Semax __func__, 462181033Semax rt->src.b[5], rt->src.b[4], rt->src.b[3], 463181033Semax rt->src.b[2], rt->src.b[1], rt->src.b[0], 464181033Semax ep->bdaddr.b[5], ep->bdaddr.b[4], ep->bdaddr.b[3], 465181033Semax ep->bdaddr.b[2], ep->bdaddr.b[1], ep->bdaddr.b[0]); 466181033Semax 467181033Semax mtx_lock(&ng_btsocket_sco_sockets_mtx); 468181033Semax 469181033Semax pcb = ng_btsocket_sco_pcb_by_addr(&rt->src); 470181033Semax if (pcb != NULL) { 471181033Semax struct socket *so1 = NULL; 472181033Semax 473181033Semax /* pcb is locked */ 474181033Semax 475181033Semax /* 476181033Semax * First check the pending connections queue and if we have 477181033Semax * space then create new socket and set proper source address. 478181033Semax */ 479181033Semax 480181033Semax if (pcb->so->so_qlen <= pcb->so->so_qlimit) 481181033Semax so1 = sonewconn(pcb->so, 0); 482181033Semax 483181033Semax if (so1 == NULL) { 484181033Semax status = 0x0d; /* Rejected due to limited resources */ 485181033Semax goto respond; 486181033Semax } 487181033Semax 488181033Semax /* 489181033Semax * If we got here than we have created new socket. So complete 490181033Semax * connection. If we we listening on specific address then copy 491181033Semax * source address from listening socket, otherwise copy source 492181033Semax * address from hook's routing information. 493181033Semax */ 494181033Semax 495181033Semax pcb1 = so2sco_pcb(so1); 496181033Semax KASSERT((pcb1 != NULL), 497181033Semax("%s: pcb1 == NULL\n", __func__)); 498181033Semax 499181033Semax mtx_lock(&pcb1->pcb_mtx); 500181033Semax 501181033Semax if (bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(pcb->src)) != 0) 502181033Semax bcopy(&pcb->src, &pcb1->src, sizeof(pcb1->src)); 503181033Semax else 504181033Semax bcopy(&rt->src, &pcb1->src, sizeof(pcb1->src)); 505181033Semax 506181033Semax pcb1->flags &= ~NG_BTSOCKET_SCO_CLIENT; 507181033Semax 508181033Semax bcopy(&ep->bdaddr, &pcb1->dst, sizeof(pcb1->dst)); 509181033Semax pcb1->rt = rt; 510181033Semax } else 511181033Semax /* Nobody listens on requested BDADDR */ 512181033Semax status = 0x1f; /* Unspecified Error */ 513181033Semax 514181033Semaxrespond: 515181033Semax error = ng_btsocket_sco_send_lp_con_rsp(rt, &ep->bdaddr, status); 516181033Semax if (pcb1 != NULL) { 517181033Semax if (error != 0) { 518181033Semax pcb1->so->so_error = error; 519181033Semax pcb1->state = NG_BTSOCKET_SCO_CLOSED; 520181033Semax soisdisconnected(pcb1->so); 521181033Semax } else { 522181033Semax pcb1->state = NG_BTSOCKET_SCO_CONNECTING; 523181033Semax soisconnecting(pcb1->so); 524181033Semax 525181033Semax ng_btsocket_sco_timeout(pcb1); 526181033Semax } 527181033Semax 528181033Semax mtx_unlock(&pcb1->pcb_mtx); 529181033Semax } 530181033Semax 531181033Semax if (pcb != NULL) 532181033Semax mtx_unlock(&pcb->pcb_mtx); 533181033Semax 534181033Semax mtx_unlock(&ng_btsocket_sco_sockets_mtx); 535181033Semax 536181033Semax return (error); 537181033Semax} /* ng_btsocket_sco_process_lp_con_ind */ 538181033Semax 539181033Semax/* 540181033Semax * Process LP_DisconnectInd indicator 541181033Semax */ 542181033Semax 543181033Semaxstatic int 544181033Semaxng_btsocket_sco_process_lp_discon_ind(struct ng_mesg *msg, 545181033Semax ng_btsocket_sco_rtentry_p rt) 546181033Semax{ 547181033Semax ng_hci_lp_discon_ind_ep *ep = NULL; 548181033Semax ng_btsocket_sco_pcb_t *pcb = NULL; 549181033Semax 550181033Semax /* Check message */ 551181033Semax if (msg->header.arglen != sizeof(*ep)) 552181033Semax return (EMSGSIZE); 553181033Semax 554181033Semax ep = (ng_hci_lp_discon_ind_ep *)(msg->data); 555181033Semax 556181033Semax mtx_lock(&ng_btsocket_sco_sockets_mtx); 557181033Semax 558181033Semax /* Look for the socket with given channel ID */ 559181033Semax pcb = ng_btsocket_sco_pcb_by_handle(&rt->src, ep->con_handle); 560181033Semax if (pcb == NULL) { 561181033Semax mtx_unlock(&ng_btsocket_sco_sockets_mtx); 562181033Semax return (0); 563181033Semax } 564181033Semax 565181033Semax /* 566181033Semax * Disconnect the socket. If there was any pending request we can 567181033Semax * not do anything here anyway. 568181033Semax */ 569181033Semax 570181033Semax /* pcb is locked */ 571181033Semax 572181033Semax NG_BTSOCKET_SCO_INFO( 573181033Semax"%s: Got LP_DisconnectInd indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \ 574181033Semax"dst bdaddr=%x:%x:%x:%x:%x:%x, handle=%d, state=%d\n", 575181033Semax __func__, 576181033Semax pcb->src.b[5], pcb->src.b[4], pcb->src.b[3], 577181033Semax pcb->src.b[2], pcb->src.b[1], pcb->src.b[0], 578181033Semax pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3], 579181033Semax pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0], 580181033Semax pcb->con_handle, pcb->state); 581181033Semax 582181033Semax if (pcb->flags & NG_BTSOCKET_SCO_TIMO) 583181033Semax ng_btsocket_sco_untimeout(pcb); 584181033Semax 585181033Semax pcb->state = NG_BTSOCKET_SCO_CLOSED; 586181033Semax soisdisconnected(pcb->so); 587181033Semax 588181033Semax mtx_unlock(&pcb->pcb_mtx); 589181033Semax mtx_unlock(&ng_btsocket_sco_sockets_mtx); 590181033Semax 591181033Semax return (0); 592181033Semax} /* ng_btsocket_sco_process_lp_discon_ind */ 593181033Semax 594181033Semax/* 595181033Semax * Send LP_ConnectReq request 596181033Semax */ 597181033Semax 598181033Semaxstatic int 599181033Semaxng_btsocket_sco_send_lp_con_req(ng_btsocket_sco_pcb_p pcb) 600181033Semax{ 601181033Semax struct ng_mesg *msg = NULL; 602181033Semax ng_hci_lp_con_req_ep *ep = NULL; 603181033Semax int error = 0; 604181033Semax 605181033Semax mtx_assert(&pcb->pcb_mtx, MA_OWNED); 606181033Semax 607181033Semax if (pcb->rt == NULL || 608181033Semax pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook)) 609181033Semax return (ENETDOWN); 610181033Semax 611181033Semax NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_REQ, 612181033Semax sizeof(*ep), M_NOWAIT); 613181033Semax if (msg == NULL) 614181033Semax return (ENOMEM); 615181033Semax 616181033Semax ep = (ng_hci_lp_con_req_ep *)(msg->data); 617181033Semax ep->link_type = NG_HCI_LINK_SCO; 618181033Semax bcopy(&pcb->dst, &ep->bdaddr, sizeof(ep->bdaddr)); 619181033Semax 620181033Semax NG_SEND_MSG_HOOK(error, ng_btsocket_sco_node, msg, pcb->rt->hook, 0); 621181033Semax 622181033Semax return (error); 623181033Semax} /* ng_btsocket_sco_send_lp_con_req */ 624181033Semax 625181033Semax/* 626181033Semax * Send LP_ConnectRsp response 627181033Semax */ 628181033Semax 629181033Semaxstatic int 630181033Semaxng_btsocket_sco_send_lp_con_rsp(ng_btsocket_sco_rtentry_p rt, bdaddr_p dst, int status) 631181033Semax{ 632181033Semax struct ng_mesg *msg = NULL; 633181033Semax ng_hci_lp_con_rsp_ep *ep = NULL; 634181033Semax int error = 0; 635181033Semax 636181033Semax if (rt == NULL || rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook)) 637181033Semax return (ENETDOWN); 638181033Semax 639181033Semax NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_RSP, 640181033Semax sizeof(*ep), M_NOWAIT); 641181033Semax if (msg == NULL) 642181033Semax return (ENOMEM); 643181033Semax 644181033Semax ep = (ng_hci_lp_con_rsp_ep *)(msg->data); 645181033Semax ep->status = status; 646181033Semax ep->link_type = NG_HCI_LINK_SCO; 647181033Semax bcopy(dst, &ep->bdaddr, sizeof(ep->bdaddr)); 648181033Semax 649181033Semax NG_SEND_MSG_HOOK(error, ng_btsocket_sco_node, msg, rt->hook, 0); 650181033Semax 651181033Semax return (error); 652181033Semax} /* ng_btsocket_sco_send_lp_con_rsp */ 653181033Semax 654181033Semax/* 655181033Semax * Send LP_DisconReq request 656181033Semax */ 657181033Semax 658181033Semaxstatic int 659181033Semaxng_btsocket_sco_send_lp_discon_req(ng_btsocket_sco_pcb_p pcb) 660181033Semax{ 661181033Semax struct ng_mesg *msg = NULL; 662181033Semax ng_hci_lp_discon_req_ep *ep = NULL; 663181033Semax int error = 0; 664181033Semax 665181033Semax mtx_assert(&pcb->pcb_mtx, MA_OWNED); 666181033Semax 667181033Semax if (pcb->rt == NULL || 668181033Semax pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook)) 669181033Semax return (ENETDOWN); 670181033Semax 671181033Semax NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_DISCON_REQ, 672181033Semax sizeof(*ep), M_NOWAIT); 673181033Semax if (msg == NULL) 674181033Semax return (ENOMEM); 675181033Semax 676181033Semax ep = (ng_hci_lp_discon_req_ep *)(msg->data); 677181033Semax ep->con_handle = pcb->con_handle; 678181033Semax ep->reason = 0x13; /* User Ended Connection */ 679181033Semax 680181033Semax NG_SEND_MSG_HOOK(error, ng_btsocket_sco_node, msg, pcb->rt->hook, 0); 681181033Semax 682181033Semax return (error); 683181033Semax} /* ng_btsocket_sco_send_lp_discon_req */ 684181033Semax 685181033Semax/***************************************************************************** 686181033Semax ***************************************************************************** 687181033Semax ** Socket interface 688181033Semax ***************************************************************************** 689181033Semax *****************************************************************************/ 690181033Semax 691181033Semax/* 692181033Semax * SCO sockets data input routine 693181033Semax */ 694181033Semax 695181033Semaxstatic void 696181033Semaxng_btsocket_sco_data_input(struct mbuf *m, hook_p hook) 697181033Semax{ 698181033Semax ng_hci_scodata_pkt_t *hdr = NULL; 699181033Semax ng_btsocket_sco_pcb_t *pcb = NULL; 700181033Semax ng_btsocket_sco_rtentry_t *rt = NULL; 701181033Semax u_int16_t con_handle; 702181033Semax 703181033Semax if (hook == NULL) { 704181033Semax NG_BTSOCKET_SCO_ALERT( 705181033Semax"%s: Invalid source hook for SCO data packet\n", __func__); 706181033Semax goto drop; 707181033Semax } 708181033Semax 709181033Semax rt = (ng_btsocket_sco_rtentry_t *) NG_HOOK_PRIVATE(hook); 710181033Semax if (rt == NULL) { 711181033Semax NG_BTSOCKET_SCO_ALERT( 712181033Semax"%s: Could not find out source bdaddr for SCO data packet\n", __func__); 713181033Semax goto drop; 714181033Semax } 715181033Semax 716181033Semax /* Make sure we can access header */ 717181033Semax if (m->m_pkthdr.len < sizeof(*hdr)) { 718181033Semax NG_BTSOCKET_SCO_ERR( 719181033Semax"%s: SCO data packet too small, len=%d\n", __func__, m->m_pkthdr.len); 720181033Semax goto drop; 721181033Semax } 722181033Semax 723181033Semax if (m->m_len < sizeof(*hdr)) { 724181033Semax m = m_pullup(m, sizeof(*hdr)); 725181033Semax if (m == NULL) 726181033Semax goto drop; 727181033Semax } 728181033Semax 729181033Semax /* Strip SCO packet header and verify packet length */ 730181033Semax hdr = mtod(m, ng_hci_scodata_pkt_t *); 731181033Semax m_adj(m, sizeof(*hdr)); 732181033Semax 733181033Semax if (hdr->length != m->m_pkthdr.len) { 734181033Semax NG_BTSOCKET_SCO_ERR( 735181033Semax"%s: Bad SCO data packet length, len=%d, length=%d\n", 736181033Semax __func__, m->m_pkthdr.len, hdr->length); 737181033Semax goto drop; 738181033Semax } 739181033Semax 740181033Semax /* 741181033Semax * Now process packet 742181033Semax */ 743181033Semax 744181033Semax con_handle = NG_HCI_CON_HANDLE(le16toh(hdr->con_handle)); 745181033Semax 746181033Semax NG_BTSOCKET_SCO_INFO( 747181033Semax"%s: Received SCO data packet: src bdaddr=%x:%x:%x:%x:%x:%x, handle=%d, " \ 748181033Semax"length=%d\n", __func__, 749181033Semax rt->src.b[5], rt->src.b[4], rt->src.b[3], 750181033Semax rt->src.b[2], rt->src.b[1], rt->src.b[0], 751181033Semax con_handle, hdr->length); 752181033Semax 753181033Semax mtx_lock(&ng_btsocket_sco_sockets_mtx); 754181033Semax 755181033Semax /* Find socket */ 756181033Semax pcb = ng_btsocket_sco_pcb_by_handle(&rt->src, con_handle); 757181033Semax if (pcb == NULL) { 758181033Semax mtx_unlock(&ng_btsocket_sco_sockets_mtx); 759181033Semax goto drop; 760181033Semax } 761181033Semax 762181033Semax /* pcb is locked */ 763181033Semax 764181033Semax if (pcb->state != NG_BTSOCKET_SCO_OPEN) { 765181033Semax NG_BTSOCKET_SCO_ERR( 766181033Semax"%s: No connected socket found, src bdaddr=%x:%x:%x:%x:%x:%x, state=%d\n", 767181033Semax __func__, 768181033Semax rt->src.b[5], rt->src.b[4], rt->src.b[3], 769181033Semax rt->src.b[2], rt->src.b[1], rt->src.b[0], 770181033Semax pcb->state); 771181033Semax 772181033Semax mtx_unlock(&pcb->pcb_mtx); 773181033Semax mtx_unlock(&ng_btsocket_sco_sockets_mtx); 774181033Semax goto drop; 775181033Semax } 776181033Semax 777181033Semax /* Check if we have enough space in socket receive queue */ 778181033Semax if (m->m_pkthdr.len > sbspace(&pcb->so->so_rcv)) { 779181033Semax NG_BTSOCKET_SCO_ERR( 780181033Semax"%s: Not enough space in socket receive queue. Dropping SCO data packet, " \ 781181033Semax"src bdaddr=%x:%x:%x:%x:%x:%x, len=%d, space=%ld\n", 782181033Semax __func__, 783181033Semax rt->src.b[5], rt->src.b[4], rt->src.b[3], 784181033Semax rt->src.b[2], rt->src.b[1], rt->src.b[0], 785181033Semax m->m_pkthdr.len, 786181033Semax sbspace(&pcb->so->so_rcv)); 787181033Semax 788181033Semax mtx_unlock(&pcb->pcb_mtx); 789181033Semax mtx_unlock(&ng_btsocket_sco_sockets_mtx); 790181033Semax goto drop; 791181033Semax } 792181033Semax 793181033Semax /* Append packet to the socket receive queue and wakeup */ 794181033Semax sbappendrecord(&pcb->so->so_rcv, m); 795181033Semax m = NULL; 796181033Semax 797181033Semax sorwakeup(pcb->so); 798181033Semax 799181033Semax mtx_unlock(&pcb->pcb_mtx); 800181033Semax mtx_unlock(&ng_btsocket_sco_sockets_mtx); 801181033Semaxdrop: 802181033Semax NG_FREE_M(m); /* checks for m != NULL */ 803181033Semax} /* ng_btsocket_sco_data_input */ 804181033Semax 805181033Semax/* 806181033Semax * SCO sockets default message input routine 807181033Semax */ 808181033Semax 809181033Semaxstatic void 810181033Semaxng_btsocket_sco_default_msg_input(struct ng_mesg *msg, hook_p hook) 811181033Semax{ 812181033Semax ng_btsocket_sco_rtentry_t *rt = NULL; 813181033Semax 814181033Semax if (hook == NULL || NG_HOOK_NOT_VALID(hook)) 815181033Semax return; 816181033Semax 817181033Semax rt = (ng_btsocket_sco_rtentry_t *) NG_HOOK_PRIVATE(hook); 818181033Semax 819181033Semax switch (msg->header.cmd) { 820181033Semax case NGM_HCI_NODE_UP: { 821181033Semax ng_hci_node_up_ep *ep = NULL; 822181033Semax 823181033Semax if (msg->header.arglen != sizeof(*ep)) 824181033Semax break; 825181033Semax 826181033Semax ep = (ng_hci_node_up_ep *)(msg->data); 827181033Semax if (bcmp(&ep->bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) 828181033Semax break; 829181033Semax 830181033Semax if (rt == NULL) { 831181033Semax MALLOC(rt, ng_btsocket_sco_rtentry_p, sizeof(*rt), 832181033Semax M_NETGRAPH_BTSOCKET_SCO, M_NOWAIT|M_ZERO); 833181033Semax if (rt == NULL) 834181033Semax break; 835181033Semax 836181033Semax NG_HOOK_SET_PRIVATE(hook, rt); 837181033Semax 838181033Semax mtx_lock(&ng_btsocket_sco_rt_mtx); 839181033Semax 840181033Semax LIST_INSERT_HEAD(&ng_btsocket_sco_rt, rt, next); 841181033Semax } else 842181033Semax mtx_lock(&ng_btsocket_sco_rt_mtx); 843181033Semax 844181033Semax bcopy(&ep->bdaddr, &rt->src, sizeof(rt->src)); 845181033Semax rt->pkt_size = (ep->pkt_size == 0)? 60 : ep->pkt_size; 846181033Semax rt->num_pkts = ep->num_pkts; 847181033Semax rt->hook = hook; 848181033Semax 849181033Semax mtx_unlock(&ng_btsocket_sco_rt_mtx); 850181033Semax 851181033Semax NG_BTSOCKET_SCO_INFO( 852181033Semax"%s: Updating hook \"%s\", src bdaddr=%x:%x:%x:%x:%x:%x, pkt_size=%d, " \ 853181033Semax"num_pkts=%d\n", __func__, NG_HOOK_NAME(hook), 854181033Semax rt->src.b[5], rt->src.b[4], rt->src.b[3], 855181033Semax rt->src.b[2], rt->src.b[1], rt->src.b[0], 856181033Semax rt->pkt_size, rt->num_pkts); 857181033Semax } break; 858181033Semax 859181033Semax case NGM_HCI_SYNC_CON_QUEUE: { 860181033Semax ng_hci_sync_con_queue_ep *ep = NULL; 861181033Semax ng_btsocket_sco_pcb_t *pcb = NULL; 862181033Semax 863181033Semax if (rt == NULL || msg->header.arglen != sizeof(*ep)) 864181033Semax break; 865181033Semax 866181033Semax ep = (ng_hci_sync_con_queue_ep *)(msg->data); 867181033Semax 868181033Semax rt->pending -= ep->completed; 869181033Semax if (rt->pending < 0) { 870181033Semax NG_BTSOCKET_SCO_WARN( 871181033Semax"%s: Pending packet counter is out of sync! bdaddr=%x:%x:%x:%x:%x:%x, " \ 872181033Semax"handle=%d, pending=%d, completed=%d\n", 873181033Semax __func__, 874181033Semax rt->src.b[5], rt->src.b[4], rt->src.b[3], 875181033Semax rt->src.b[2], rt->src.b[1], rt->src.b[0], 876181033Semax ep->con_handle, rt->pending, 877181033Semax ep->completed); 878181033Semax 879181033Semax rt->pending = 0; 880181033Semax } 881181033Semax 882181033Semax mtx_lock(&ng_btsocket_sco_sockets_mtx); 883181033Semax 884181033Semax /* Find socket */ 885181033Semax pcb = ng_btsocket_sco_pcb_by_handle(&rt->src, ep->con_handle); 886181033Semax if (pcb == NULL) { 887181033Semax mtx_unlock(&ng_btsocket_sco_sockets_mtx); 888181033Semax break; 889181033Semax } 890181033Semax 891181033Semax /* pcb is locked */ 892181033Semax 893181033Semax /* Check state */ 894181033Semax if (pcb->state == NG_BTSOCKET_SCO_OPEN) { 895181033Semax /* Remove timeout */ 896181033Semax ng_btsocket_sco_untimeout(pcb); 897181033Semax 898181033Semax /* Drop completed packets from the send queue */ 899181033Semax for (; ep->completed > 0; ep->completed --) 900181033Semax sbdroprecord(&pcb->so->so_snd); 901181033Semax 902181033Semax /* Send more if we have any */ 903181033Semax if (pcb->so->so_snd.sb_cc > 0) 904181033Semax if (ng_btsocket_sco_send2(pcb) == 0) 905181033Semax ng_btsocket_sco_timeout(pcb); 906181033Semax 907181033Semax /* Wake up writers */ 908181033Semax sowwakeup(pcb->so); 909181033Semax } 910181033Semax 911181033Semax mtx_unlock(&pcb->pcb_mtx); 912181033Semax mtx_unlock(&ng_btsocket_sco_sockets_mtx); 913181033Semax } break; 914181033Semax 915181033Semax default: 916181033Semax NG_BTSOCKET_SCO_WARN( 917181033Semax"%s: Unknown message, cmd=%d\n", __func__, msg->header.cmd); 918181033Semax break; 919181033Semax } 920181033Semax 921181033Semax NG_FREE_MSG(msg); /* Checks for msg != NULL */ 922181033Semax} /* ng_btsocket_sco_default_msg_input */ 923181033Semax 924181033Semax/* 925181033Semax * SCO sockets LP message input routine 926181033Semax */ 927181033Semax 928181033Semaxstatic void 929181033Semaxng_btsocket_sco_lp_msg_input(struct ng_mesg *msg, hook_p hook) 930181033Semax{ 931181033Semax ng_btsocket_sco_rtentry_p rt = NULL; 932181033Semax 933181033Semax if (hook == NULL) { 934181033Semax NG_BTSOCKET_SCO_ALERT( 935181033Semax"%s: Invalid source hook for LP message\n", __func__); 936181033Semax goto drop; 937181033Semax } 938181033Semax 939181033Semax rt = (ng_btsocket_sco_rtentry_p) NG_HOOK_PRIVATE(hook); 940181033Semax if (rt == NULL) { 941181033Semax NG_BTSOCKET_SCO_ALERT( 942181033Semax"%s: Could not find out source bdaddr for LP message\n", __func__); 943181033Semax goto drop; 944181033Semax } 945181033Semax 946181033Semax switch (msg->header.cmd) { 947181033Semax case NGM_HCI_LP_CON_CFM: /* Connection Confirmation Event */ 948181033Semax ng_btsocket_sco_process_lp_con_cfm(msg, rt); 949181033Semax break; 950181033Semax 951181033Semax case NGM_HCI_LP_CON_IND: /* Connection Indication Event */ 952181033Semax ng_btsocket_sco_process_lp_con_ind(msg, rt); 953181033Semax break; 954181033Semax 955181033Semax case NGM_HCI_LP_DISCON_IND: /* Disconnection Indication Event */ 956181033Semax ng_btsocket_sco_process_lp_discon_ind(msg, rt); 957181033Semax break; 958181033Semax 959181033Semax /* XXX FIXME add other LP messages */ 960181033Semax 961181033Semax default: 962181033Semax NG_BTSOCKET_SCO_WARN( 963181033Semax"%s: Unknown LP message, cmd=%d\n", __func__, msg->header.cmd); 964181033Semax break; 965181033Semax } 966181033Semaxdrop: 967181033Semax NG_FREE_MSG(msg); 968181033Semax} /* ng_btsocket_sco_lp_msg_input */ 969181033Semax 970181033Semax/* 971181033Semax * SCO sockets input routine 972181033Semax */ 973181033Semax 974181033Semaxstatic void 975181033Semaxng_btsocket_sco_input(void *context, int pending) 976181033Semax{ 977181033Semax item_p item = NULL; 978181033Semax hook_p hook = NULL; 979181033Semax 980181033Semax for (;;) { 981181033Semax mtx_lock(&ng_btsocket_sco_queue_mtx); 982181033Semax NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_sco_queue, item); 983181033Semax mtx_unlock(&ng_btsocket_sco_queue_mtx); 984181033Semax 985181033Semax if (item == NULL) 986181033Semax break; 987181033Semax 988181033Semax NGI_GET_HOOK(item, hook); 989181033Semax if (hook != NULL && NG_HOOK_NOT_VALID(hook)) 990181033Semax goto drop; 991181033Semax 992181033Semax switch(item->el_flags & NGQF_TYPE) { 993181033Semax case NGQF_DATA: { 994181033Semax struct mbuf *m = NULL; 995181033Semax 996181033Semax NGI_GET_M(item, m); 997181033Semax ng_btsocket_sco_data_input(m, hook); 998181033Semax } break; 999181033Semax 1000181033Semax case NGQF_MESG: { 1001181033Semax struct ng_mesg *msg = NULL; 1002181033Semax 1003181033Semax NGI_GET_MSG(item, msg); 1004181033Semax 1005181033Semax switch (msg->header.cmd) { 1006181033Semax case NGM_HCI_LP_CON_CFM: 1007181033Semax case NGM_HCI_LP_CON_IND: 1008181033Semax case NGM_HCI_LP_DISCON_IND: 1009181033Semax /* XXX FIXME add other LP messages */ 1010181033Semax ng_btsocket_sco_lp_msg_input(msg, hook); 1011181033Semax break; 1012181033Semax 1013181033Semax default: 1014181033Semax ng_btsocket_sco_default_msg_input(msg, hook); 1015181033Semax break; 1016181033Semax } 1017181033Semax } break; 1018181033Semax 1019181033Semax default: 1020181033Semax KASSERT(0, 1021181033Semax("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE))); 1022181033Semax break; 1023181033Semax } 1024181033Semaxdrop: 1025181033Semax if (hook != NULL) 1026181033Semax NG_HOOK_UNREF(hook); 1027181033Semax 1028181033Semax NG_FREE_ITEM(item); 1029181033Semax } 1030181033Semax} /* ng_btsocket_sco_input */ 1031181033Semax 1032181033Semax/* 1033181033Semax * Route cleanup task. Gets scheduled when hook is disconnected. Here we 1034181033Semax * will find all sockets that use "invalid" hook and disconnect them. 1035181033Semax */ 1036181033Semax 1037181033Semaxstatic void 1038181033Semaxng_btsocket_sco_rtclean(void *context, int pending) 1039181033Semax{ 1040181033Semax ng_btsocket_sco_pcb_p pcb = NULL, pcb_next = NULL; 1041181033Semax ng_btsocket_sco_rtentry_p rt = NULL; 1042181033Semax 1043181033Semax /* 1044181033Semax * First disconnect all sockets that use "invalid" hook 1045181033Semax */ 1046181033Semax 1047181033Semax mtx_lock(&ng_btsocket_sco_sockets_mtx); 1048181033Semax 1049181033Semax for(pcb = LIST_FIRST(&ng_btsocket_sco_sockets); pcb != NULL; ) { 1050181033Semax mtx_lock(&pcb->pcb_mtx); 1051181033Semax pcb_next = LIST_NEXT(pcb, next); 1052181033Semax 1053181033Semax if (pcb->rt != NULL && 1054181033Semax pcb->rt->hook != NULL && NG_HOOK_NOT_VALID(pcb->rt->hook)) { 1055181033Semax if (pcb->flags & NG_BTSOCKET_SCO_TIMO) 1056181033Semax ng_btsocket_sco_untimeout(pcb); 1057181033Semax 1058181033Semax pcb->rt = NULL; 1059181033Semax pcb->so->so_error = ENETDOWN; 1060181033Semax pcb->state = NG_BTSOCKET_SCO_CLOSED; 1061181033Semax soisdisconnected(pcb->so); 1062181033Semax } 1063181033Semax 1064181033Semax mtx_unlock(&pcb->pcb_mtx); 1065181033Semax pcb = pcb_next; 1066181033Semax } 1067181033Semax 1068181033Semax mtx_unlock(&ng_btsocket_sco_sockets_mtx); 1069181033Semax 1070181033Semax /* 1071181033Semax * Now cleanup routing table 1072181033Semax */ 1073181033Semax 1074181033Semax mtx_lock(&ng_btsocket_sco_rt_mtx); 1075181033Semax 1076181033Semax for (rt = LIST_FIRST(&ng_btsocket_sco_rt); rt != NULL; ) { 1077181033Semax ng_btsocket_sco_rtentry_p rt_next = LIST_NEXT(rt, next); 1078181033Semax 1079181033Semax if (rt->hook != NULL && NG_HOOK_NOT_VALID(rt->hook)) { 1080181033Semax LIST_REMOVE(rt, next); 1081181033Semax 1082181033Semax NG_HOOK_SET_PRIVATE(rt->hook, NULL); 1083181033Semax NG_HOOK_UNREF(rt->hook); /* Remove extra reference */ 1084181033Semax 1085181033Semax bzero(rt, sizeof(*rt)); 1086181033Semax FREE(rt, M_NETGRAPH_BTSOCKET_SCO); 1087181033Semax } 1088181033Semax 1089181033Semax rt = rt_next; 1090181033Semax } 1091181033Semax 1092181033Semax mtx_unlock(&ng_btsocket_sco_rt_mtx); 1093181033Semax} /* ng_btsocket_sco_rtclean */ 1094181033Semax 1095181033Semax/* 1096181033Semax * Initialize everything 1097181033Semax */ 1098181033Semax 1099181033Semaxvoid 1100181033Semaxng_btsocket_sco_init(void) 1101181033Semax{ 1102181033Semax int error = 0; 1103181033Semax 1104181033Semax ng_btsocket_sco_node = NULL; 1105181033Semax ng_btsocket_sco_debug_level = NG_BTSOCKET_WARN_LEVEL; 1106181033Semax 1107181033Semax /* Register Netgraph node type */ 1108181033Semax error = ng_newtype(&typestruct); 1109181033Semax if (error != 0) { 1110181033Semax NG_BTSOCKET_SCO_ALERT( 1111181033Semax"%s: Could not register Netgraph node type, error=%d\n", __func__, error); 1112181033Semax 1113181033Semax return; 1114181033Semax } 1115181033Semax 1116181033Semax /* Create Netgrapg node */ 1117181033Semax error = ng_make_node_common(&typestruct, &ng_btsocket_sco_node); 1118181033Semax if (error != 0) { 1119181033Semax NG_BTSOCKET_SCO_ALERT( 1120181033Semax"%s: Could not create Netgraph node, error=%d\n", __func__, error); 1121181033Semax 1122181033Semax ng_btsocket_sco_node = NULL; 1123181033Semax 1124181033Semax return; 1125181033Semax } 1126181033Semax 1127181033Semax error = ng_name_node(ng_btsocket_sco_node, NG_BTSOCKET_SCO_NODE_TYPE); 1128181033Semax if (error != 0) { 1129181033Semax NG_BTSOCKET_SCO_ALERT( 1130181033Semax"%s: Could not name Netgraph node, error=%d\n", __func__, error); 1131181033Semax 1132181033Semax NG_NODE_UNREF(ng_btsocket_sco_node); 1133181033Semax ng_btsocket_sco_node = NULL; 1134181033Semax 1135181033Semax return; 1136181033Semax } 1137181033Semax 1138181033Semax /* Create input queue */ 1139181033Semax NG_BT_ITEMQ_INIT(&ng_btsocket_sco_queue, 300); 1140181033Semax mtx_init(&ng_btsocket_sco_queue_mtx, 1141181033Semax "btsocks_sco_queue_mtx", NULL, MTX_DEF); 1142181033Semax TASK_INIT(&ng_btsocket_sco_queue_task, 0, 1143181033Semax ng_btsocket_sco_input, NULL); 1144181033Semax 1145181033Semax /* Create list of sockets */ 1146181033Semax LIST_INIT(&ng_btsocket_sco_sockets); 1147181033Semax mtx_init(&ng_btsocket_sco_sockets_mtx, 1148181033Semax "btsocks_sco_sockets_mtx", NULL, MTX_DEF); 1149181033Semax 1150181033Semax /* Routing table */ 1151181033Semax LIST_INIT(&ng_btsocket_sco_rt); 1152181033Semax mtx_init(&ng_btsocket_sco_rt_mtx, 1153181033Semax "btsocks_sco_rt_mtx", NULL, MTX_DEF); 1154181033Semax TASK_INIT(&ng_btsocket_sco_rt_task, 0, 1155181033Semax ng_btsocket_sco_rtclean, NULL); 1156181033Semax} /* ng_btsocket_sco_init */ 1157181033Semax 1158181033Semax/* 1159181033Semax * Abort connection on socket 1160181033Semax */ 1161181033Semax 1162181033Semaxvoid 1163181033Semaxng_btsocket_sco_abort(struct socket *so) 1164181033Semax{ 1165181033Semax so->so_error = ECONNABORTED; 1166181033Semax 1167181033Semax (void) ng_btsocket_sco_disconnect(so); 1168181033Semax} /* ng_btsocket_sco_abort */ 1169181033Semax 1170181033Semaxvoid 1171181033Semaxng_btsocket_sco_close(struct socket *so) 1172181033Semax{ 1173181033Semax (void) ng_btsocket_sco_disconnect(so); 1174181033Semax} /* ng_btsocket_sco_close */ 1175181033Semax 1176181033Semax/* 1177181033Semax * Accept connection on socket. Nothing to do here, socket must be connected 1178181033Semax * and ready, so just return peer address and be done with it. 1179181033Semax */ 1180181033Semax 1181181033Semaxint 1182181033Semaxng_btsocket_sco_accept(struct socket *so, struct sockaddr **nam) 1183181033Semax{ 1184181033Semax if (ng_btsocket_sco_node == NULL) 1185181033Semax return (EINVAL); 1186181033Semax 1187181033Semax return (ng_btsocket_sco_peeraddr(so, nam)); 1188181033Semax} /* ng_btsocket_sco_accept */ 1189181033Semax 1190181033Semax/* 1191181033Semax * Create and attach new socket 1192181033Semax */ 1193181033Semax 1194181033Semaxint 1195181033Semaxng_btsocket_sco_attach(struct socket *so, int proto, struct thread *td) 1196181033Semax{ 1197181033Semax ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so); 1198181033Semax int error; 1199181033Semax 1200181033Semax /* Check socket and protocol */ 1201181033Semax if (ng_btsocket_sco_node == NULL) 1202181033Semax return (EPROTONOSUPPORT); 1203181033Semax if (so->so_type != SOCK_SEQPACKET) 1204181033Semax return (ESOCKTNOSUPPORT); 1205181033Semax 1206181033Semax#if 0 /* XXX sonewconn() calls "pru_attach" with proto == 0 */ 1207181033Semax if (proto != 0) 1208181033Semax if (proto != BLUETOOTH_PROTO_SCO) 1209181033Semax return (EPROTONOSUPPORT); 1210181033Semax#endif /* XXX */ 1211181033Semax 1212181033Semax if (pcb != NULL) 1213181033Semax return (EISCONN); 1214181033Semax 1215181033Semax /* Reserve send and receive space if it is not reserved yet */ 1216181033Semax if ((so->so_snd.sb_hiwat == 0) || (so->so_rcv.sb_hiwat == 0)) { 1217181033Semax error = soreserve(so, NG_BTSOCKET_SCO_SENDSPACE, 1218181033Semax NG_BTSOCKET_SCO_RECVSPACE); 1219181033Semax if (error != 0) 1220181033Semax return (error); 1221181033Semax } 1222181033Semax 1223181033Semax /* Allocate the PCB */ 1224181033Semax MALLOC(pcb, ng_btsocket_sco_pcb_p, sizeof(*pcb), 1225181033Semax M_NETGRAPH_BTSOCKET_SCO, M_NOWAIT | M_ZERO); 1226181033Semax if (pcb == NULL) 1227181033Semax return (ENOMEM); 1228181033Semax 1229181033Semax /* Link the PCB and the socket */ 1230181033Semax so->so_pcb = (caddr_t) pcb; 1231181033Semax pcb->so = so; 1232181033Semax pcb->state = NG_BTSOCKET_SCO_CLOSED; 1233181033Semax 1234181033Semax callout_init(&pcb->timo, 1); 1235181033Semax 1236181033Semax /* 1237181033Semax * Mark PCB mutex as DUPOK to prevent "duplicated lock of 1238181033Semax * the same type" message. When accepting new SCO connection 1239181033Semax * ng_btsocket_sco_process_lp_con_ind() holds both PCB mutexes 1240181033Semax * for "old" (accepting) PCB and "new" (created) PCB. 1241181033Semax */ 1242181033Semax 1243181033Semax mtx_init(&pcb->pcb_mtx, "btsocks_sco_pcb_mtx", NULL, 1244181033Semax MTX_DEF|MTX_DUPOK); 1245181033Semax 1246181033Semax /* 1247181033Semax * Add the PCB to the list 1248181033Semax * 1249181033Semax * XXX FIXME VERY IMPORTANT! 1250181033Semax * 1251181033Semax * This is totally FUBAR. We could get here in two cases: 1252181033Semax * 1253181033Semax * 1) When user calls socket() 1254181033Semax * 2) When we need to accept new incomming connection and call 1255181033Semax * sonewconn() 1256181033Semax * 1257181033Semax * In the first case we must aquire ng_btsocket_sco_sockets_mtx. 1258181033Semax * In the second case we hold ng_btsocket_sco_sockets_mtx already. 1259181033Semax * So we now need to distinguish between these cases. From reading 1260181033Semax * /sys/kern/uipc_socket2.c we can find out that sonewconn() calls 1261181033Semax * pru_attach with proto == 0 and td == NULL. For now use this fact 1262181033Semax * to figure out if we were called from socket() or from sonewconn(). 1263181033Semax */ 1264181033Semax 1265181033Semax if (td != NULL) 1266181033Semax mtx_lock(&ng_btsocket_sco_sockets_mtx); 1267181033Semax else 1268181033Semax mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED); 1269181033Semax 1270181033Semax LIST_INSERT_HEAD(&ng_btsocket_sco_sockets, pcb, next); 1271181033Semax 1272181033Semax if (td != NULL) 1273181033Semax mtx_unlock(&ng_btsocket_sco_sockets_mtx); 1274181033Semax 1275181033Semax return (0); 1276181033Semax} /* ng_btsocket_sco_attach */ 1277181033Semax 1278181033Semax/* 1279181033Semax * Bind socket 1280181033Semax */ 1281181033Semax 1282181033Semaxint 1283181033Semaxng_btsocket_sco_bind(struct socket *so, struct sockaddr *nam, 1284181033Semax struct thread *td) 1285181033Semax{ 1286181033Semax ng_btsocket_sco_pcb_t *pcb = NULL; 1287181033Semax struct sockaddr_sco *sa = (struct sockaddr_sco *) nam; 1288181033Semax 1289181033Semax if (ng_btsocket_sco_node == NULL) 1290181033Semax return (EINVAL); 1291181033Semax 1292181033Semax /* Verify address */ 1293181033Semax if (sa == NULL) 1294181033Semax return (EINVAL); 1295181033Semax if (sa->sco_family != AF_BLUETOOTH) 1296181033Semax return (EAFNOSUPPORT); 1297181033Semax if (sa->sco_len != sizeof(*sa)) 1298181033Semax return (EINVAL); 1299181033Semax 1300181033Semax mtx_lock(&ng_btsocket_sco_sockets_mtx); 1301181033Semax 1302181033Semax /* 1303181033Semax * Check if other socket has this address already (look for exact 1304181033Semax * match in bdaddr) and assign socket address if it's available. 1305181033Semax */ 1306181033Semax 1307181033Semax if (bcmp(&sa->sco_bdaddr, NG_HCI_BDADDR_ANY, sizeof(sa->sco_bdaddr)) != 0) { 1308181033Semax LIST_FOREACH(pcb, &ng_btsocket_sco_sockets, next) { 1309181033Semax mtx_lock(&pcb->pcb_mtx); 1310181033Semax 1311181033Semax if (bcmp(&pcb->src, &sa->sco_bdaddr, sizeof(bdaddr_t)) == 0) { 1312181033Semax mtx_unlock(&pcb->pcb_mtx); 1313181033Semax mtx_unlock(&ng_btsocket_sco_sockets_mtx); 1314181033Semax 1315181033Semax return (EADDRINUSE); 1316181033Semax } 1317181033Semax 1318181033Semax mtx_unlock(&pcb->pcb_mtx); 1319181033Semax } 1320181033Semax 1321181033Semax } 1322181033Semax 1323181033Semax pcb = so2sco_pcb(so); 1324181033Semax if (pcb == NULL) { 1325181033Semax mtx_unlock(&ng_btsocket_sco_sockets_mtx); 1326181033Semax return (EINVAL); 1327181033Semax } 1328181033Semax 1329181033Semax mtx_lock(&pcb->pcb_mtx); 1330181033Semax bcopy(&sa->sco_bdaddr, &pcb->src, sizeof(pcb->src)); 1331181033Semax mtx_unlock(&pcb->pcb_mtx); 1332181033Semax 1333181033Semax mtx_unlock(&ng_btsocket_sco_sockets_mtx); 1334181033Semax 1335181033Semax return (0); 1336181033Semax} /* ng_btsocket_sco_bind */ 1337181033Semax 1338181033Semax/* 1339181033Semax * Connect socket 1340181033Semax */ 1341181033Semax 1342181033Semaxint 1343181033Semaxng_btsocket_sco_connect(struct socket *so, struct sockaddr *nam, 1344181033Semax struct thread *td) 1345181033Semax{ 1346181033Semax ng_btsocket_sco_pcb_t *pcb = so2sco_pcb(so); 1347181033Semax struct sockaddr_sco *sa = (struct sockaddr_sco *) nam; 1348181033Semax ng_btsocket_sco_rtentry_t *rt = NULL; 1349181033Semax int have_src, error = 0; 1350181033Semax 1351181033Semax /* Check socket */ 1352181033Semax if (pcb == NULL) 1353181033Semax return (EINVAL); 1354181033Semax if (ng_btsocket_sco_node == NULL) 1355181033Semax return (EINVAL); 1356181033Semax 1357181033Semax /* Verify address */ 1358181033Semax if (sa == NULL) 1359181033Semax return (EINVAL); 1360181033Semax if (sa->sco_family != AF_BLUETOOTH) 1361181033Semax return (EAFNOSUPPORT); 1362181033Semax if (sa->sco_len != sizeof(*sa)) 1363181033Semax return (EINVAL); 1364181033Semax if (bcmp(&sa->sco_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) 1365181033Semax return (EDESTADDRREQ); 1366181033Semax 1367181033Semax /* 1368181033Semax * Routing. Socket should be bound to some source address. The source 1369181033Semax * address can be ANY. Destination address must be set and it must not 1370181033Semax * be ANY. If source address is ANY then find first rtentry that has 1371181033Semax * src != dst. 1372181033Semax */ 1373181033Semax 1374181033Semax mtx_lock(&ng_btsocket_sco_rt_mtx); 1375181033Semax mtx_lock(&pcb->pcb_mtx); 1376181033Semax 1377181033Semax if (pcb->state == NG_BTSOCKET_SCO_CONNECTING) { 1378181033Semax mtx_unlock(&pcb->pcb_mtx); 1379181033Semax mtx_unlock(&ng_btsocket_sco_rt_mtx); 1380181033Semax 1381181033Semax return (EINPROGRESS); 1382181033Semax } 1383181033Semax 1384181033Semax if (bcmp(&sa->sco_bdaddr, &pcb->src, sizeof(pcb->src)) == 0) { 1385181033Semax mtx_unlock(&pcb->pcb_mtx); 1386181033Semax mtx_unlock(&ng_btsocket_sco_rt_mtx); 1387181033Semax 1388181033Semax return (EINVAL); 1389181033Semax } 1390181033Semax 1391181033Semax /* Send destination address and PSM */ 1392181033Semax bcopy(&sa->sco_bdaddr, &pcb->dst, sizeof(pcb->dst)); 1393181033Semax 1394181033Semax pcb->rt = NULL; 1395181033Semax have_src = bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(pcb->src)); 1396181033Semax 1397181033Semax LIST_FOREACH(rt, &ng_btsocket_sco_rt, next) { 1398181033Semax if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook)) 1399181033Semax continue; 1400181033Semax 1401181033Semax /* Match src and dst */ 1402181033Semax if (have_src) { 1403181033Semax if (bcmp(&pcb->src, &rt->src, sizeof(rt->src)) == 0) 1404181033Semax break; 1405181033Semax } else { 1406181033Semax if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0) 1407181033Semax break; 1408181033Semax } 1409181033Semax } 1410181033Semax 1411181033Semax if (rt != NULL) { 1412181033Semax pcb->rt = rt; 1413181033Semax 1414181033Semax if (!have_src) 1415181033Semax bcopy(&rt->src, &pcb->src, sizeof(pcb->src)); 1416181033Semax } else 1417181033Semax error = EHOSTUNREACH; 1418181033Semax 1419181033Semax /* 1420181033Semax * Send LP_Connect request 1421181033Semax */ 1422181033Semax 1423181033Semax if (error == 0) { 1424181033Semax error = ng_btsocket_sco_send_lp_con_req(pcb); 1425181033Semax if (error == 0) { 1426181033Semax pcb->flags |= NG_BTSOCKET_SCO_CLIENT; 1427181033Semax pcb->state = NG_BTSOCKET_SCO_CONNECTING; 1428181033Semax soisconnecting(pcb->so); 1429181033Semax 1430181033Semax ng_btsocket_sco_timeout(pcb); 1431181033Semax } 1432181033Semax } 1433181033Semax 1434181033Semax mtx_unlock(&pcb->pcb_mtx); 1435181033Semax mtx_unlock(&ng_btsocket_sco_rt_mtx); 1436181033Semax 1437181033Semax return (error); 1438181033Semax} /* ng_btsocket_sco_connect */ 1439181033Semax 1440181033Semax/* 1441181033Semax * Process ioctl's calls on socket 1442181033Semax */ 1443181033Semax 1444181033Semaxint 1445181033Semaxng_btsocket_sco_control(struct socket *so, u_long cmd, caddr_t data, 1446181033Semax struct ifnet *ifp, struct thread *td) 1447181033Semax{ 1448181033Semax return (EINVAL); 1449181033Semax} /* ng_btsocket_sco_control */ 1450181033Semax 1451181033Semax/* 1452181033Semax * Process getsockopt/setsockopt system calls 1453181033Semax */ 1454181033Semax 1455181033Semaxint 1456181033Semaxng_btsocket_sco_ctloutput(struct socket *so, struct sockopt *sopt) 1457181033Semax{ 1458181033Semax ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so); 1459181033Semax int error, tmp; 1460181033Semax 1461181033Semax if (ng_btsocket_sco_node == NULL) 1462181033Semax return (EINVAL); 1463181033Semax if (pcb == NULL) 1464181033Semax return (EINVAL); 1465181033Semax 1466181033Semax if (sopt->sopt_level != SOL_SCO) 1467181033Semax return (0); 1468181033Semax 1469181033Semax mtx_lock(&pcb->pcb_mtx); 1470181033Semax 1471181033Semax switch (sopt->sopt_dir) { 1472181033Semax case SOPT_GET: 1473181033Semax if (pcb->state != NG_BTSOCKET_SCO_OPEN) { 1474181033Semax error = ENOTCONN; 1475181033Semax break; 1476181033Semax } 1477181033Semax 1478181033Semax switch (sopt->sopt_name) { 1479181033Semax case SO_SCO_MTU: 1480181033Semax tmp = pcb->rt->pkt_size; 1481181033Semax error = sooptcopyout(sopt, &tmp, sizeof(tmp)); 1482181033Semax break; 1483181033Semax 1484181033Semax case SO_SCO_CONNINFO: 1485181033Semax tmp = pcb->con_handle; 1486181033Semax error = sooptcopyout(sopt, &tmp, sizeof(tmp)); 1487181033Semax break; 1488181033Semax 1489181033Semax default: 1490181033Semax error = EINVAL; 1491181033Semax break; 1492181033Semax } 1493181033Semax break; 1494181033Semax 1495181033Semax case SOPT_SET: 1496181033Semax error = ENOPROTOOPT; 1497181033Semax break; 1498181033Semax 1499181033Semax default: 1500181033Semax error = EINVAL; 1501181033Semax break; 1502181033Semax } 1503181033Semax 1504181033Semax mtx_unlock(&pcb->pcb_mtx); 1505181033Semax 1506181033Semax return (error); 1507181033Semax} /* ng_btsocket_sco_ctloutput */ 1508181033Semax 1509181033Semax/* 1510181033Semax * Detach and destroy socket 1511181033Semax */ 1512181033Semax 1513181033Semaxvoid 1514181033Semaxng_btsocket_sco_detach(struct socket *so) 1515181033Semax{ 1516181033Semax ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so); 1517181033Semax 1518181033Semax KASSERT(pcb != NULL, ("ng_btsocket_sco_detach: pcb == NULL")); 1519181033Semax 1520181033Semax if (ng_btsocket_sco_node == NULL) 1521181033Semax return; 1522181033Semax 1523181033Semax mtx_lock(&ng_btsocket_sco_sockets_mtx); 1524181033Semax mtx_lock(&pcb->pcb_mtx); 1525181033Semax 1526181033Semax if (pcb->flags & NG_BTSOCKET_SCO_TIMO) 1527181033Semax ng_btsocket_sco_untimeout(pcb); 1528181033Semax 1529181033Semax if (pcb->state == NG_BTSOCKET_SCO_OPEN) 1530181033Semax ng_btsocket_sco_send_lp_discon_req(pcb); 1531181033Semax 1532181033Semax pcb->state = NG_BTSOCKET_SCO_CLOSED; 1533181033Semax 1534181033Semax LIST_REMOVE(pcb, next); 1535181033Semax 1536181033Semax mtx_unlock(&pcb->pcb_mtx); 1537181033Semax mtx_unlock(&ng_btsocket_sco_sockets_mtx); 1538181033Semax 1539181033Semax mtx_destroy(&pcb->pcb_mtx); 1540181033Semax bzero(pcb, sizeof(*pcb)); 1541181033Semax FREE(pcb, M_NETGRAPH_BTSOCKET_SCO); 1542181033Semax 1543181033Semax soisdisconnected(so); 1544181033Semax so->so_pcb = NULL; 1545181033Semax} /* ng_btsocket_sco_detach */ 1546181033Semax 1547181033Semax/* 1548181033Semax * Disconnect socket 1549181033Semax */ 1550181033Semax 1551181033Semaxint 1552181033Semaxng_btsocket_sco_disconnect(struct socket *so) 1553181033Semax{ 1554181033Semax ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so); 1555181033Semax 1556181033Semax if (pcb == NULL) 1557181033Semax return (EINVAL); 1558181033Semax if (ng_btsocket_sco_node == NULL) 1559181033Semax return (EINVAL); 1560181033Semax 1561181033Semax mtx_lock(&pcb->pcb_mtx); 1562181033Semax 1563181033Semax if (pcb->state == NG_BTSOCKET_SCO_DISCONNECTING) { 1564181033Semax mtx_unlock(&pcb->pcb_mtx); 1565181033Semax 1566181033Semax return (EINPROGRESS); 1567181033Semax } 1568181033Semax 1569181033Semax if (pcb->flags & NG_BTSOCKET_SCO_TIMO) 1570181033Semax ng_btsocket_sco_untimeout(pcb); 1571181033Semax 1572181033Semax if (pcb->state == NG_BTSOCKET_SCO_OPEN) { 1573181033Semax ng_btsocket_sco_send_lp_discon_req(pcb); 1574181033Semax 1575181033Semax pcb->state = NG_BTSOCKET_SCO_DISCONNECTING; 1576181033Semax soisdisconnecting(so); 1577181033Semax 1578181033Semax ng_btsocket_sco_timeout(pcb); 1579181033Semax } else { 1580181033Semax pcb->state = NG_BTSOCKET_SCO_CLOSED; 1581181033Semax soisdisconnected(so); 1582181033Semax } 1583181033Semax 1584181033Semax mtx_unlock(&pcb->pcb_mtx); 1585181033Semax 1586181033Semax return (0); 1587181033Semax} /* ng_btsocket_sco_disconnect */ 1588181033Semax 1589181033Semax/* 1590181033Semax * Listen on socket 1591181033Semax */ 1592181033Semax 1593181033Semaxint 1594181033Semaxng_btsocket_sco_listen(struct socket *so, int backlog, struct thread *td) 1595181033Semax{ 1596181033Semax ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so); 1597181033Semax int error; 1598181033Semax 1599181033Semax if (pcb == NULL) 1600181033Semax return (EINVAL); 1601181033Semax if (ng_btsocket_sco_node == NULL) 1602181033Semax return (EINVAL); 1603181033Semax 1604181033Semax SOCK_LOCK(so); 1605181033Semax mtx_lock(&pcb->pcb_mtx); 1606181033Semax 1607181033Semax error = solisten_proto_check(so); 1608181033Semax if (error != 0) 1609181033Semax goto out; 1610181033Semax#if 0 1611181033Semax if (bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) { 1612181033Semax error = EDESTADDRREQ; 1613181033Semax goto out; 1614181033Semax } 1615181033Semax#endif 1616181033Semax solisten_proto(so, backlog); 1617181033Semaxout: 1618181033Semax mtx_unlock(&pcb->pcb_mtx); 1619181033Semax SOCK_UNLOCK(so); 1620181033Semax 1621181033Semax return (error); 1622181033Semax} /* ng_btsocket_listen */ 1623181033Semax 1624181033Semax/* 1625181033Semax * Get peer address 1626181033Semax */ 1627181033Semax 1628181033Semaxint 1629181033Semaxng_btsocket_sco_peeraddr(struct socket *so, struct sockaddr **nam) 1630181033Semax{ 1631181033Semax ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so); 1632181033Semax struct sockaddr_sco sa; 1633181033Semax 1634181033Semax if (pcb == NULL) 1635181033Semax return (EINVAL); 1636181033Semax if (ng_btsocket_sco_node == NULL) 1637181033Semax return (EINVAL); 1638181033Semax 1639181033Semax mtx_lock(&pcb->pcb_mtx); 1640181033Semax bcopy(&pcb->dst, &sa.sco_bdaddr, sizeof(sa.sco_bdaddr)); 1641181033Semax mtx_unlock(&pcb->pcb_mtx); 1642181033Semax 1643181033Semax sa.sco_len = sizeof(sa); 1644181033Semax sa.sco_family = AF_BLUETOOTH; 1645181033Semax 1646181033Semax *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT); 1647181033Semax 1648181033Semax return ((*nam == NULL)? ENOMEM : 0); 1649181033Semax} /* ng_btsocket_sco_peeraddr */ 1650181033Semax 1651181033Semax/* 1652181033Semax * Send data to socket 1653181033Semax */ 1654181033Semax 1655181033Semaxint 1656181033Semaxng_btsocket_sco_send(struct socket *so, int flags, struct mbuf *m, 1657181033Semax struct sockaddr *nam, struct mbuf *control, struct thread *td) 1658181033Semax{ 1659181033Semax ng_btsocket_sco_pcb_t *pcb = so2sco_pcb(so); 1660181033Semax int error = 0; 1661181033Semax 1662181033Semax if (ng_btsocket_sco_node == NULL) { 1663181033Semax error = ENETDOWN; 1664181033Semax goto drop; 1665181033Semax } 1666181033Semax 1667181033Semax /* Check socket and input */ 1668181033Semax if (pcb == NULL || m == NULL || control != NULL) { 1669181033Semax error = EINVAL; 1670181033Semax goto drop; 1671181033Semax } 1672181033Semax 1673181033Semax mtx_lock(&pcb->pcb_mtx); 1674181033Semax 1675181033Semax /* Make sure socket is connected */ 1676181033Semax if (pcb->state != NG_BTSOCKET_SCO_OPEN) { 1677181033Semax mtx_unlock(&pcb->pcb_mtx); 1678181033Semax error = ENOTCONN; 1679181033Semax goto drop; 1680181033Semax } 1681181033Semax 1682181033Semax /* Check route */ 1683181033Semax if (pcb->rt == NULL || 1684181033Semax pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook)) { 1685181033Semax mtx_unlock(&pcb->pcb_mtx); 1686181033Semax error = ENETDOWN; 1687181033Semax goto drop; 1688181033Semax } 1689181033Semax 1690181033Semax /* Check packet size */ 1691181033Semax if (m->m_pkthdr.len > pcb->rt->pkt_size) { 1692181033Semax NG_BTSOCKET_SCO_ERR( 1693181033Semax"%s: Packet too big, len=%d, pkt_size=%d\n", 1694181033Semax __func__, m->m_pkthdr.len, pcb->rt->pkt_size); 1695181033Semax 1696181033Semax mtx_unlock(&pcb->pcb_mtx); 1697181033Semax error = EMSGSIZE; 1698181033Semax goto drop; 1699181033Semax } 1700181033Semax 1701181033Semax /* 1702181033Semax * First put packet on socket send queue. Then check if we have 1703181033Semax * pending timeout. If we do not have timeout then we must send 1704181033Semax * packet and schedule timeout. Otherwise do nothing and wait for 1705181033Semax * NGM_HCI_SYNC_CON_QUEUE message. 1706181033Semax */ 1707181033Semax 1708181033Semax sbappendrecord(&pcb->so->so_snd, m); 1709181033Semax m = NULL; 1710181033Semax 1711181033Semax if (!(pcb->flags & NG_BTSOCKET_SCO_TIMO)) { 1712181033Semax error = ng_btsocket_sco_send2(pcb); 1713181033Semax if (error == 0) 1714181033Semax ng_btsocket_sco_timeout(pcb); 1715181033Semax else 1716181033Semax sbdroprecord(&pcb->so->so_snd); /* XXX */ 1717181033Semax } 1718181033Semax 1719181033Semax mtx_unlock(&pcb->pcb_mtx); 1720181033Semaxdrop: 1721181033Semax NG_FREE_M(m); /* checks for != NULL */ 1722181033Semax NG_FREE_M(control); 1723181033Semax 1724181033Semax return (error); 1725181033Semax} /* ng_btsocket_sco_send */ 1726181033Semax 1727181033Semax/* 1728181033Semax * Send first packet in the socket queue to the SCO layer 1729181033Semax */ 1730181033Semax 1731181033Semaxstatic int 1732181033Semaxng_btsocket_sco_send2(ng_btsocket_sco_pcb_p pcb) 1733181033Semax{ 1734181033Semax struct mbuf *m = NULL; 1735181033Semax ng_hci_scodata_pkt_t *hdr = NULL; 1736181033Semax int error = 0; 1737181033Semax 1738181033Semax mtx_assert(&pcb->pcb_mtx, MA_OWNED); 1739181033Semax 1740181033Semax while (pcb->rt->pending < pcb->rt->num_pkts && 1741181033Semax pcb->so->so_snd.sb_cc > 0) { 1742181033Semax /* Get a copy of the first packet on send queue */ 1743181033Semax m = m_dup(pcb->so->so_snd.sb_mb, M_DONTWAIT); 1744181033Semax if (m == NULL) { 1745181033Semax error = ENOBUFS; 1746181033Semax break; 1747181033Semax } 1748181033Semax 1749181033Semax /* Create SCO packet header */ 1750181033Semax M_PREPEND(m, sizeof(*hdr), M_DONTWAIT); 1751181033Semax if (m != NULL) 1752181033Semax if (m->m_len < sizeof(*hdr)) 1753181033Semax m = m_pullup(m, sizeof(*hdr)); 1754181033Semax 1755181033Semax if (m == NULL) { 1756181033Semax error = ENOBUFS; 1757181033Semax break; 1758181033Semax } 1759181033Semax 1760181033Semax /* Fill in the header */ 1761181033Semax hdr = mtod(m, ng_hci_scodata_pkt_t *); 1762181033Semax hdr->type = NG_HCI_SCO_DATA_PKT; 1763181033Semax hdr->con_handle = htole16(NG_HCI_MK_CON_HANDLE(pcb->con_handle, 0, 0)); 1764181033Semax hdr->length = m->m_pkthdr.len - sizeof(*hdr); 1765181033Semax 1766181033Semax /* Send packet */ 1767181033Semax NG_SEND_DATA_ONLY(error, pcb->rt->hook, m); 1768181033Semax if (error != 0) 1769181033Semax break; 1770181033Semax 1771181033Semax pcb->rt->pending ++; 1772181033Semax } 1773181033Semax 1774181033Semax return ((pcb->rt->pending > 0)? 0 : error); 1775181033Semax} /* ng_btsocket_sco_send2 */ 1776181033Semax 1777181033Semax/* 1778181033Semax * Get socket address 1779181033Semax */ 1780181033Semax 1781181033Semaxint 1782181033Semaxng_btsocket_sco_sockaddr(struct socket *so, struct sockaddr **nam) 1783181033Semax{ 1784181033Semax ng_btsocket_sco_pcb_p pcb = so2sco_pcb(so); 1785181033Semax struct sockaddr_sco sa; 1786181033Semax 1787181033Semax if (pcb == NULL) 1788181033Semax return (EINVAL); 1789181033Semax if (ng_btsocket_sco_node == NULL) 1790181033Semax return (EINVAL); 1791181033Semax 1792181033Semax mtx_lock(&pcb->pcb_mtx); 1793181033Semax bcopy(&pcb->src, &sa.sco_bdaddr, sizeof(sa.sco_bdaddr)); 1794181033Semax mtx_unlock(&pcb->pcb_mtx); 1795181033Semax 1796181033Semax sa.sco_len = sizeof(sa); 1797181033Semax sa.sco_family = AF_BLUETOOTH; 1798181033Semax 1799181033Semax *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT); 1800181033Semax 1801181033Semax return ((*nam == NULL)? ENOMEM : 0); 1802181033Semax} /* ng_btsocket_sco_sockaddr */ 1803181033Semax 1804181033Semax/***************************************************************************** 1805181033Semax ***************************************************************************** 1806181033Semax ** Misc. functions 1807181033Semax ***************************************************************************** 1808181033Semax *****************************************************************************/ 1809181033Semax 1810181033Semax/* 1811181033Semax * Look for the socket that listens on given bdaddr. 1812181033Semax * Returns exact or close match (if any). 1813181033Semax * Caller must hold ng_btsocket_sco_sockets_mtx. 1814181033Semax * Returns with locked pcb. 1815181033Semax */ 1816181033Semax 1817181033Semaxstatic ng_btsocket_sco_pcb_p 1818181033Semaxng_btsocket_sco_pcb_by_addr(bdaddr_p bdaddr) 1819181033Semax{ 1820181033Semax ng_btsocket_sco_pcb_p p = NULL, p1 = NULL; 1821181033Semax 1822181033Semax mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED); 1823181033Semax 1824181033Semax LIST_FOREACH(p, &ng_btsocket_sco_sockets, next) { 1825181033Semax mtx_lock(&p->pcb_mtx); 1826181033Semax 1827181033Semax if (p->so == NULL || !(p->so->so_options & SO_ACCEPTCONN)) { 1828181033Semax mtx_unlock(&p->pcb_mtx); 1829181033Semax continue; 1830181033Semax } 1831181033Semax 1832181033Semax if (bcmp(&p->src, bdaddr, sizeof(p->src)) == 0) 1833181033Semax return (p); /* return with locked pcb */ 1834181033Semax 1835181033Semax if (bcmp(&p->src, NG_HCI_BDADDR_ANY, sizeof(p->src)) == 0) 1836181033Semax p1 = p; 1837181033Semax 1838181033Semax mtx_unlock(&p->pcb_mtx); 1839181033Semax } 1840181033Semax 1841181088Semax if (p1 != NULL) 1842181088Semax mtx_lock(&p1->pcb_mtx); 1843181088Semax 1844181033Semax return (p1); 1845181033Semax} /* ng_btsocket_sco_pcb_by_addr */ 1846181033Semax 1847181033Semax/* 1848181033Semax * Look for the socket that assigned to given source address and handle. 1849181033Semax * Caller must hold ng_btsocket_sco_sockets_mtx. 1850181033Semax * Returns with locked pcb. 1851181033Semax */ 1852181033Semax 1853181033Semaxstatic ng_btsocket_sco_pcb_p 1854181033Semaxng_btsocket_sco_pcb_by_handle(bdaddr_p src, int con_handle) 1855181033Semax{ 1856181033Semax ng_btsocket_sco_pcb_p p = NULL; 1857181033Semax 1858181033Semax mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED); 1859181033Semax 1860181033Semax LIST_FOREACH(p, &ng_btsocket_sco_sockets, next) { 1861181033Semax mtx_lock(&p->pcb_mtx); 1862181033Semax 1863181033Semax if (p->con_handle == con_handle && 1864181033Semax bcmp(src, &p->src, sizeof(p->src)) == 0) 1865181033Semax return (p); /* return with locked pcb */ 1866181033Semax 1867181033Semax mtx_unlock(&p->pcb_mtx); 1868181033Semax } 1869181033Semax 1870181033Semax return (NULL); 1871181033Semax} /* ng_btsocket_sco_pcb_by_handle */ 1872181033Semax 1873181033Semax/* 1874181033Semax * Look for the socket in CONNECTING state with given source and destination 1875181033Semax * addresses. Caller must hold ng_btsocket_sco_sockets_mtx. 1876181033Semax * Returns with locked pcb. 1877181033Semax */ 1878181033Semax 1879181033Semaxstatic ng_btsocket_sco_pcb_p 1880181033Semaxng_btsocket_sco_pcb_by_addrs(bdaddr_p src, bdaddr_p dst) 1881181033Semax{ 1882181033Semax ng_btsocket_sco_pcb_p p = NULL; 1883181033Semax 1884181033Semax mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED); 1885181033Semax 1886181033Semax LIST_FOREACH(p, &ng_btsocket_sco_sockets, next) { 1887181033Semax mtx_lock(&p->pcb_mtx); 1888181033Semax 1889181033Semax if (p->state == NG_BTSOCKET_SCO_CONNECTING && 1890181033Semax bcmp(src, &p->src, sizeof(p->src)) == 0 && 1891181033Semax bcmp(dst, &p->dst, sizeof(p->dst)) == 0) 1892181033Semax return (p); /* return with locked pcb */ 1893181033Semax 1894181033Semax mtx_unlock(&p->pcb_mtx); 1895181033Semax } 1896181033Semax 1897181033Semax return (NULL); 1898181033Semax} /* ng_btsocket_sco_pcb_by_addrs */ 1899181033Semax 1900181033Semax/* 1901181033Semax * Set timeout on socket 1902181033Semax */ 1903181033Semax 1904181033Semaxstatic void 1905181033Semaxng_btsocket_sco_timeout(ng_btsocket_sco_pcb_p pcb) 1906181033Semax{ 1907181033Semax mtx_assert(&pcb->pcb_mtx, MA_OWNED); 1908181033Semax 1909181033Semax if (!(pcb->flags & NG_BTSOCKET_SCO_TIMO)) { 1910181033Semax pcb->flags |= NG_BTSOCKET_SCO_TIMO; 1911181033Semax callout_reset(&pcb->timo, bluetooth_sco_rtx_timeout(), 1912181033Semax ng_btsocket_sco_process_timeout, pcb); 1913181033Semax } else 1914181033Semax KASSERT(0, 1915181033Semax("%s: Duplicated socket timeout?!\n", __func__)); 1916181033Semax} /* ng_btsocket_sco_timeout */ 1917181033Semax 1918181033Semax/* 1919181033Semax * Unset timeout on socket 1920181033Semax */ 1921181033Semax 1922181033Semaxstatic void 1923181033Semaxng_btsocket_sco_untimeout(ng_btsocket_sco_pcb_p pcb) 1924181033Semax{ 1925181033Semax mtx_assert(&pcb->pcb_mtx, MA_OWNED); 1926181033Semax 1927181033Semax if (pcb->flags & NG_BTSOCKET_SCO_TIMO) { 1928181033Semax callout_stop(&pcb->timo); 1929181033Semax pcb->flags &= ~NG_BTSOCKET_SCO_TIMO; 1930181033Semax } else 1931181033Semax KASSERT(0, 1932181033Semax("%s: No socket timeout?!\n", __func__)); 1933181033Semax} /* ng_btsocket_sco_untimeout */ 1934181033Semax 1935181033Semax/* 1936181033Semax * Process timeout on socket 1937181033Semax */ 1938181033Semax 1939181033Semaxstatic void 1940181033Semaxng_btsocket_sco_process_timeout(void *xpcb) 1941181033Semax{ 1942181033Semax ng_btsocket_sco_pcb_p pcb = (ng_btsocket_sco_pcb_p) xpcb; 1943181033Semax 1944181033Semax mtx_lock(&pcb->pcb_mtx); 1945181033Semax 1946181033Semax pcb->flags &= ~NG_BTSOCKET_SCO_TIMO; 1947181033Semax pcb->so->so_error = ETIMEDOUT; 1948181033Semax 1949181033Semax switch (pcb->state) { 1950181033Semax case NG_BTSOCKET_SCO_CONNECTING: 1951181033Semax /* Connect timeout - close the socket */ 1952181033Semax pcb->state = NG_BTSOCKET_SCO_CLOSED; 1953181033Semax soisdisconnected(pcb->so); 1954181033Semax break; 1955181033Semax 1956181033Semax case NG_BTSOCKET_SCO_OPEN: 1957181033Semax /* Send timeout - did not get NGM_HCI_SYNC_CON_QUEUE */ 1958181033Semax sbdroprecord(&pcb->so->so_snd); 1959181033Semax sowwakeup(pcb->so); 1960181033Semax /* XXX FIXME what to do with pcb->rt->pending??? */ 1961181033Semax break; 1962181033Semax 1963181033Semax case NG_BTSOCKET_SCO_DISCONNECTING: 1964181033Semax /* Disconnect timeout - disconnect the socket anyway */ 1965181033Semax pcb->state = NG_BTSOCKET_SCO_CLOSED; 1966181033Semax soisdisconnected(pcb->so); 1967181033Semax break; 1968181033Semax 1969181033Semax default: 1970181033Semax NG_BTSOCKET_SCO_ERR( 1971181033Semax"%s: Invalid socket state=%d\n", __func__, pcb->state); 1972181033Semax break; 1973181033Semax } 1974181033Semax 1975181033Semax mtx_unlock(&pcb->pcb_mtx); 1976181033Semax} /* ng_btsocket_sco_process_timeout */ 1977181033Semax 1978