Path: blob/main/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap_raw.c
34677 views
/*1* ng_btsocket_l2cap_raw.c2*/34/*-5* SPDX-License-Identifier: BSD-2-Clause6*7* Copyright (c) 2001-2002 Maksim Yevmenkin <[email protected]>8* All rights reserved.9*10* Redistribution and use in source and binary forms, with or without11* modification, are permitted provided that the following conditions12* are met:13* 1. Redistributions of source code must retain the above copyright14* notice, this list of conditions and the following disclaimer.15* 2. Redistributions in binary form must reproduce the above copyright16* notice, this list of conditions and the following disclaimer in the17* documentation and/or other materials provided with the distribution.18*19* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND20* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE21* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE22* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE23* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL24* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS25* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)26* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT27* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY28* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF29* SUCH DAMAGE.30*31* $Id: ng_btsocket_l2cap_raw.c,v 1.12 2003/09/14 23:29:06 max Exp $32*/3334#include <sys/param.h>35#include <sys/systm.h>36#include <sys/bitstring.h>37#include <sys/domain.h>38#include <sys/errno.h>39#include <sys/filedesc.h>40#include <sys/ioccom.h>41#include <sys/kernel.h>42#include <sys/lock.h>43#include <sys/malloc.h>44#include <sys/mbuf.h>45#include <sys/mutex.h>46#include <sys/priv.h>47#include <sys/protosw.h>48#include <sys/queue.h>49#include <sys/socket.h>50#include <sys/socketvar.h>51#include <sys/sysctl.h>52#include <sys/taskqueue.h>5354#include <net/vnet.h>5556#include <netgraph/ng_message.h>57#include <netgraph/netgraph.h>58#include <netgraph/bluetooth/include/ng_bluetooth.h>59#include <netgraph/bluetooth/include/ng_hci.h>60#include <netgraph/bluetooth/include/ng_l2cap.h>61#include <netgraph/bluetooth/include/ng_btsocket.h>62#include <netgraph/bluetooth/include/ng_btsocket_l2cap.h>6364/* MALLOC define */65#ifdef NG_SEPARATE_MALLOC66static MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_L2CAP_RAW,67"netgraph_btsocks_l2cap_raw", "Netgraph Bluetooth raw L2CAP sockets");68#else69#define M_NETGRAPH_BTSOCKET_L2CAP_RAW M_NETGRAPH70#endif /* NG_SEPARATE_MALLOC */7172/* Netgraph node methods */73static ng_constructor_t ng_btsocket_l2cap_raw_node_constructor;74static ng_rcvmsg_t ng_btsocket_l2cap_raw_node_rcvmsg;75static ng_shutdown_t ng_btsocket_l2cap_raw_node_shutdown;76static ng_newhook_t ng_btsocket_l2cap_raw_node_newhook;77static ng_connect_t ng_btsocket_l2cap_raw_node_connect;78static ng_rcvdata_t ng_btsocket_l2cap_raw_node_rcvdata;79static ng_disconnect_t ng_btsocket_l2cap_raw_node_disconnect;8081static void ng_btsocket_l2cap_raw_input (void *, int);82static void ng_btsocket_l2cap_raw_rtclean (void *, int);83static void ng_btsocket_l2cap_raw_get_token (u_int32_t *);8485static int ng_btsocket_l2cap_raw_send_ngmsg86(hook_p, int, void *, int);87static int ng_btsocket_l2cap_raw_send_sync_ngmsg88(ng_btsocket_l2cap_raw_pcb_p, int, void *, int);8990#define ng_btsocket_l2cap_raw_wakeup_input_task() \91taskqueue_enqueue(taskqueue_swi, &ng_btsocket_l2cap_raw_queue_task)9293#define ng_btsocket_l2cap_raw_wakeup_route_task() \94taskqueue_enqueue(taskqueue_swi, &ng_btsocket_l2cap_raw_rt_task)9596/* Netgraph type descriptor */97static struct ng_type typestruct = {98.version = NG_ABI_VERSION,99.name = NG_BTSOCKET_L2CAP_RAW_NODE_TYPE,100.constructor = ng_btsocket_l2cap_raw_node_constructor,101.rcvmsg = ng_btsocket_l2cap_raw_node_rcvmsg,102.shutdown = ng_btsocket_l2cap_raw_node_shutdown,103.newhook = ng_btsocket_l2cap_raw_node_newhook,104.connect = ng_btsocket_l2cap_raw_node_connect,105.rcvdata = ng_btsocket_l2cap_raw_node_rcvdata,106.disconnect = ng_btsocket_l2cap_raw_node_disconnect,107};108109/* Globals */110extern int ifqmaxlen;111static u_int32_t ng_btsocket_l2cap_raw_debug_level;112static u_int32_t ng_btsocket_l2cap_raw_ioctl_timeout;113static node_p ng_btsocket_l2cap_raw_node;114static struct ng_bt_itemq ng_btsocket_l2cap_raw_queue;115static struct mtx ng_btsocket_l2cap_raw_queue_mtx;116static struct task ng_btsocket_l2cap_raw_queue_task;117static LIST_HEAD(, ng_btsocket_l2cap_raw_pcb) ng_btsocket_l2cap_raw_sockets;118static struct mtx ng_btsocket_l2cap_raw_sockets_mtx;119static u_int32_t ng_btsocket_l2cap_raw_token;120static struct mtx ng_btsocket_l2cap_raw_token_mtx;121static LIST_HEAD(, ng_btsocket_l2cap_rtentry) ng_btsocket_l2cap_raw_rt;122static struct mtx ng_btsocket_l2cap_raw_rt_mtx;123static struct task ng_btsocket_l2cap_raw_rt_task;124static struct timeval ng_btsocket_l2cap_raw_lasttime;125static int ng_btsocket_l2cap_raw_curpps;126127/* Sysctl tree */128SYSCTL_DECL(_net_bluetooth_l2cap_sockets);129static SYSCTL_NODE(_net_bluetooth_l2cap_sockets, OID_AUTO, raw,130CTLFLAG_RW | CTLFLAG_MPSAFE, 0,131"Bluetooth raw L2CAP sockets family");132SYSCTL_UINT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, debug_level,133CTLFLAG_RW,134&ng_btsocket_l2cap_raw_debug_level, NG_BTSOCKET_WARN_LEVEL,135"Bluetooth raw L2CAP sockets debug level");136SYSCTL_UINT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, ioctl_timeout,137CTLFLAG_RW,138&ng_btsocket_l2cap_raw_ioctl_timeout, 5,139"Bluetooth raw L2CAP sockets ioctl timeout");140SYSCTL_UINT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_len,141CTLFLAG_RD,142&ng_btsocket_l2cap_raw_queue.len, 0,143"Bluetooth raw L2CAP sockets input queue length");144SYSCTL_UINT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_maxlen,145CTLFLAG_RD,146&ng_btsocket_l2cap_raw_queue.maxlen, 0,147"Bluetooth raw L2CAP sockets input queue max. length");148SYSCTL_UINT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_drops,149CTLFLAG_RD,150&ng_btsocket_l2cap_raw_queue.drops, 0,151"Bluetooth raw L2CAP sockets input queue drops");152153/* Debug */154#define NG_BTSOCKET_L2CAP_RAW_INFO \155if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_INFO_LEVEL && \156ppsratecheck(&ng_btsocket_l2cap_raw_lasttime, &ng_btsocket_l2cap_raw_curpps, 1)) \157printf158159#define NG_BTSOCKET_L2CAP_RAW_WARN \160if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_WARN_LEVEL && \161ppsratecheck(&ng_btsocket_l2cap_raw_lasttime, &ng_btsocket_l2cap_raw_curpps, 1)) \162printf163164#define NG_BTSOCKET_L2CAP_RAW_ERR \165if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_ERR_LEVEL && \166ppsratecheck(&ng_btsocket_l2cap_raw_lasttime, &ng_btsocket_l2cap_raw_curpps, 1)) \167printf168169#define NG_BTSOCKET_L2CAP_RAW_ALERT \170if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_ALERT_LEVEL && \171ppsratecheck(&ng_btsocket_l2cap_raw_lasttime, &ng_btsocket_l2cap_raw_curpps, 1)) \172printf173174/*****************************************************************************175*****************************************************************************176** Netgraph node interface177*****************************************************************************178*****************************************************************************/179180/*181* Netgraph node constructor. Do not allow to create node of this type.182*/183184static int185ng_btsocket_l2cap_raw_node_constructor(node_p node)186{187return (EINVAL);188} /* ng_btsocket_l2cap_raw_node_constructor */189190/*191* Do local shutdown processing. Let old node go and create new fresh one.192*/193194static int195ng_btsocket_l2cap_raw_node_shutdown(node_p node)196{197int error = 0;198199NG_NODE_UNREF(node);200201/* Create new node */202error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_raw_node);203if (error != 0) {204NG_BTSOCKET_L2CAP_RAW_ALERT(205"%s: Could not create Netgraph node, error=%d\n", __func__, error);206207ng_btsocket_l2cap_raw_node = NULL;208209return (error);210}211212error = ng_name_node(ng_btsocket_l2cap_raw_node,213NG_BTSOCKET_L2CAP_RAW_NODE_TYPE);214if (error != 0) {215NG_BTSOCKET_L2CAP_RAW_ALERT(216"%s: Could not name Netgraph node, error=%d\n", __func__, error);217218NG_NODE_UNREF(ng_btsocket_l2cap_raw_node);219ng_btsocket_l2cap_raw_node = NULL;220221return (error);222}223224return (0);225} /* ng_btsocket_l2cap_raw_node_shutdown */226227/*228* We allow any hook to be connected to the node.229*/230231static int232ng_btsocket_l2cap_raw_node_newhook(node_p node, hook_p hook, char const *name)233{234return (0);235} /* ng_btsocket_l2cap_raw_node_newhook */236237/*238* Just say "YEP, that's OK by me!"239*/240241static int242ng_btsocket_l2cap_raw_node_connect(hook_p hook)243{244NG_HOOK_SET_PRIVATE(hook, NULL);245NG_HOOK_REF(hook); /* Keep extra reference to the hook */246247return (0);248} /* ng_btsocket_l2cap_raw_node_connect */249250/*251* Hook disconnection. Schedule route cleanup task252*/253254static int255ng_btsocket_l2cap_raw_node_disconnect(hook_p hook)256{257/*258* If hook has private information than we must have this hook in259* the routing table and must schedule cleaning for the routing table.260* Otherwise hook was connected but we never got "hook_info" message,261* so we have never added this hook to the routing table and it save262* to just delete it.263*/264265if (NG_HOOK_PRIVATE(hook) != NULL)266return (ng_btsocket_l2cap_raw_wakeup_route_task());267268NG_HOOK_UNREF(hook); /* Remove extra reference */269270return (0);271} /* ng_btsocket_l2cap_raw_node_disconnect */272273/*274* Process incoming messages275*/276277static int278ng_btsocket_l2cap_raw_node_rcvmsg(node_p node, item_p item, hook_p hook)279{280struct ng_mesg *msg = NGI_MSG(item); /* item still has message */281int error = 0;282283if (msg != NULL && msg->header.typecookie == NGM_L2CAP_COOKIE) {284/*285* NGM_L2CAP_NODE_HOOK_INFO is special message initiated by286* L2CAP layer. Ignore all other messages if they are not287* replies or token is zero288*/289290if (msg->header.cmd != NGM_L2CAP_NODE_HOOK_INFO) {291if (msg->header.token == 0 ||292!(msg->header.flags & NGF_RESP)) {293NG_FREE_ITEM(item);294return (0);295}296}297298mtx_lock(&ng_btsocket_l2cap_raw_queue_mtx);299if (NG_BT_ITEMQ_FULL(&ng_btsocket_l2cap_raw_queue)) {300NG_BTSOCKET_L2CAP_RAW_ERR(301"%s: Input queue is full\n", __func__);302303NG_BT_ITEMQ_DROP(&ng_btsocket_l2cap_raw_queue);304NG_FREE_ITEM(item);305error = ENOBUFS;306} else {307if (hook != NULL) {308NG_HOOK_REF(hook);309NGI_SET_HOOK(item, hook);310}311312NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_l2cap_raw_queue, item);313error = ng_btsocket_l2cap_raw_wakeup_input_task();314}315mtx_unlock(&ng_btsocket_l2cap_raw_queue_mtx);316} else {317NG_FREE_ITEM(item);318error = EINVAL;319}320321return (error);322} /* ng_btsocket_l2cap_raw_node_rcvmsg */323324/*325* Receive data on a hook326*/327328static int329ng_btsocket_l2cap_raw_node_rcvdata(hook_p hook, item_p item)330{331NG_FREE_ITEM(item);332333return (EINVAL);334} /* ng_btsocket_l2cap_raw_node_rcvdata */335336/*****************************************************************************337*****************************************************************************338** Socket interface339*****************************************************************************340*****************************************************************************/341342/*343* L2CAP sockets input routine344*/345346static void347ng_btsocket_l2cap_raw_input(void *context, int pending)348{349item_p item = NULL;350hook_p hook = NULL;351struct ng_mesg *msg = NULL;352353for (;;) {354mtx_lock(&ng_btsocket_l2cap_raw_queue_mtx);355NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_l2cap_raw_queue, item);356mtx_unlock(&ng_btsocket_l2cap_raw_queue_mtx);357358if (item == NULL)359break;360361KASSERT((item->el_flags & NGQF_TYPE) == NGQF_MESG,362("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE)));363364NGI_GET_MSG(item, msg);365NGI_GET_HOOK(item, hook);366NG_FREE_ITEM(item);367368switch (msg->header.cmd) {369case NGM_L2CAP_NODE_HOOK_INFO: {370ng_btsocket_l2cap_rtentry_t *rt = NULL;371372if (hook == NULL || NG_HOOK_NOT_VALID(hook) ||373msg->header.arglen != sizeof(bdaddr_t))374break;375376if (bcmp(msg->data, NG_HCI_BDADDR_ANY,377sizeof(bdaddr_t)) == 0)378break;379380rt = (ng_btsocket_l2cap_rtentry_t *)381NG_HOOK_PRIVATE(hook);382if (rt == NULL) {383rt = malloc(sizeof(*rt),384M_NETGRAPH_BTSOCKET_L2CAP_RAW,385M_NOWAIT|M_ZERO);386if (rt == NULL)387break;388389NG_HOOK_SET_PRIVATE(hook, rt);390391mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);392393LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_rt,394rt, next);395} else396mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);397398bcopy(msg->data, &rt->src, sizeof(rt->src));399rt->hook = hook;400401NG_BTSOCKET_L2CAP_RAW_INFO(402"%s: Updating hook \"%s\", src bdaddr=%x:%x:%x:%x:%x:%x\n",403__func__, NG_HOOK_NAME(hook),404rt->src.b[5], rt->src.b[4], rt->src.b[3],405rt->src.b[2], rt->src.b[1], rt->src.b[0]);406407mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);408} break;409410case NGM_L2CAP_NODE_GET_FLAGS:411case NGM_L2CAP_NODE_GET_DEBUG:412case NGM_L2CAP_NODE_GET_CON_LIST:413case NGM_L2CAP_NODE_GET_CHAN_LIST:414case NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO:415case NGM_L2CAP_L2CA_PING:416case NGM_L2CAP_L2CA_GET_INFO: {417ng_btsocket_l2cap_raw_pcb_p pcb = NULL;418419mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);420421LIST_FOREACH(pcb,&ng_btsocket_l2cap_raw_sockets,next) {422mtx_lock(&pcb->pcb_mtx);423424if (pcb->token == msg->header.token) {425pcb->msg = msg;426msg = NULL;427wakeup(&pcb->msg);428mtx_unlock(&pcb->pcb_mtx);429break;430}431432mtx_unlock(&pcb->pcb_mtx);433}434435mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);436} break;437438default:439NG_BTSOCKET_L2CAP_RAW_WARN(440"%s: Unknown message, cmd=%d\n", __func__, msg->header.cmd);441break;442}443444if (hook != NULL)445NG_HOOK_UNREF(hook); /* remove extra reference */446447NG_FREE_MSG(msg); /* Checks for msg != NULL */448}449} /* ng_btsocket_l2cap_raw_input */450451/*452* Route cleanup task. Gets scheduled when hook is disconnected. Here we453* will find all sockets that use "invalid" hook and disconnect them.454*/455456static void457ng_btsocket_l2cap_raw_rtclean(void *context, int pending)458{459ng_btsocket_l2cap_raw_pcb_p pcb = NULL;460ng_btsocket_l2cap_rtentry_p rt = NULL;461462/*463* First disconnect all sockets that use "invalid" hook464*/465466mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);467468LIST_FOREACH(pcb, &ng_btsocket_l2cap_raw_sockets, next) {469mtx_lock(&pcb->pcb_mtx);470471if (pcb->rt != NULL &&472pcb->rt->hook != NULL && NG_HOOK_NOT_VALID(pcb->rt->hook)) {473if (pcb->so != NULL &&474pcb->so->so_state & SS_ISCONNECTED)475soisdisconnected(pcb->so);476477pcb->rt = NULL;478}479480mtx_unlock(&pcb->pcb_mtx);481}482483mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);484485/*486* Now cleanup routing table487*/488489mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);490491for (rt = LIST_FIRST(&ng_btsocket_l2cap_raw_rt); rt != NULL; ) {492ng_btsocket_l2cap_rtentry_p rt_next = LIST_NEXT(rt, next);493494if (rt->hook != NULL && NG_HOOK_NOT_VALID(rt->hook)) {495LIST_REMOVE(rt, next);496497NG_HOOK_SET_PRIVATE(rt->hook, NULL);498NG_HOOK_UNREF(rt->hook); /* Remove extra reference */499500bzero(rt, sizeof(*rt));501free(rt, M_NETGRAPH_BTSOCKET_L2CAP_RAW);502}503504rt = rt_next;505}506507mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);508} /* ng_btsocket_l2cap_raw_rtclean */509510/*511* Initialize everything512*/513514static void515ng_btsocket_l2cap_raw_init(void *arg __unused)516{517int error = 0;518519ng_btsocket_l2cap_raw_node = NULL;520ng_btsocket_l2cap_raw_debug_level = NG_BTSOCKET_WARN_LEVEL;521ng_btsocket_l2cap_raw_ioctl_timeout = 5;522523/* Register Netgraph node type */524error = ng_newtype(&typestruct);525if (error != 0) {526NG_BTSOCKET_L2CAP_RAW_ALERT(527"%s: Could not register Netgraph node type, error=%d\n", __func__, error);528529return;530}531532/* Create Netgrapg node */533error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_raw_node);534if (error != 0) {535NG_BTSOCKET_L2CAP_RAW_ALERT(536"%s: Could not create Netgraph node, error=%d\n", __func__, error);537538ng_btsocket_l2cap_raw_node = NULL;539540return;541}542543error = ng_name_node(ng_btsocket_l2cap_raw_node,544NG_BTSOCKET_L2CAP_RAW_NODE_TYPE);545if (error != 0) {546NG_BTSOCKET_L2CAP_RAW_ALERT(547"%s: Could not name Netgraph node, error=%d\n", __func__, error);548549NG_NODE_UNREF(ng_btsocket_l2cap_raw_node);550ng_btsocket_l2cap_raw_node = NULL;551552return;553}554555/* Create input queue */556NG_BT_ITEMQ_INIT(&ng_btsocket_l2cap_raw_queue, ifqmaxlen);557mtx_init(&ng_btsocket_l2cap_raw_queue_mtx,558"btsocks_l2cap_raw_queue_mtx", NULL, MTX_DEF);559TASK_INIT(&ng_btsocket_l2cap_raw_queue_task, 0,560ng_btsocket_l2cap_raw_input, NULL);561562/* Create list of sockets */563LIST_INIT(&ng_btsocket_l2cap_raw_sockets);564mtx_init(&ng_btsocket_l2cap_raw_sockets_mtx,565"btsocks_l2cap_raw_sockets_mtx", NULL, MTX_DEF);566567/* Tokens */568ng_btsocket_l2cap_raw_token = 0;569mtx_init(&ng_btsocket_l2cap_raw_token_mtx,570"btsocks_l2cap_raw_token_mtx", NULL, MTX_DEF);571572/* Routing table */573LIST_INIT(&ng_btsocket_l2cap_raw_rt);574mtx_init(&ng_btsocket_l2cap_raw_rt_mtx,575"btsocks_l2cap_raw_rt_mtx", NULL, MTX_DEF);576TASK_INIT(&ng_btsocket_l2cap_raw_rt_task, 0,577ng_btsocket_l2cap_raw_rtclean, NULL);578} /* ng_btsocket_l2cap_raw_init */579SYSINIT(ng_btsocket_l2cap_raw_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD,580ng_btsocket_l2cap_raw_init, NULL);581582/*583* Abort connection on socket584*/585586void587ng_btsocket_l2cap_raw_abort(struct socket *so)588{589590(void)ng_btsocket_l2cap_raw_disconnect(so);591} /* ng_btsocket_l2cap_raw_abort */592593void594ng_btsocket_l2cap_raw_close(struct socket *so)595{596597(void)ng_btsocket_l2cap_raw_disconnect(so);598} /* ng_btsocket_l2cap_raw_close */599600/*601* Create and attach new socket602*/603604int605ng_btsocket_l2cap_raw_attach(struct socket *so, int proto, struct thread *td)606{607ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);608int error;609610if (pcb != NULL)611return (EISCONN);612613if (ng_btsocket_l2cap_raw_node == NULL)614return (EPROTONOSUPPORT);615if (so->so_type != SOCK_RAW)616return (ESOCKTNOSUPPORT);617618/* Reserve send and receive space if it is not reserved yet */619error = soreserve(so, NG_BTSOCKET_L2CAP_RAW_SENDSPACE,620NG_BTSOCKET_L2CAP_RAW_RECVSPACE);621if (error != 0)622return (error);623624/* Allocate the PCB */625pcb = malloc(sizeof(*pcb),626M_NETGRAPH_BTSOCKET_L2CAP_RAW, M_NOWAIT|M_ZERO);627if (pcb == NULL)628return (ENOMEM);629630/* Link the PCB and the socket */631so->so_pcb = (caddr_t) pcb;632pcb->so = so;633634if (priv_check(td, PRIV_NETBLUETOOTH_RAW) == 0)635pcb->flags |= NG_BTSOCKET_L2CAP_RAW_PRIVILEGED;636637mtx_init(&pcb->pcb_mtx, "btsocks_l2cap_raw_pcb_mtx", NULL, MTX_DEF);638639/* Add the PCB to the list */640mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);641LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_sockets, pcb, next);642mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);643644return (0);645} /* ng_btsocket_l2cap_raw_attach */646647/*648* Bind socket649*/650651int652ng_btsocket_l2cap_raw_bind(struct socket *so, struct sockaddr *nam,653struct thread *td)654{655ng_btsocket_l2cap_raw_pcb_t *pcb = so2l2cap_raw_pcb(so);656struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *) nam;657ng_btsocket_l2cap_rtentry_t *rt = NULL;658659if (pcb == NULL)660return (EINVAL);661if (ng_btsocket_l2cap_raw_node == NULL)662return (EINVAL);663664if (sa == NULL)665return (EINVAL);666if (sa->l2cap_family != AF_BLUETOOTH)667return (EAFNOSUPPORT);668if((sa->l2cap_len != sizeof(*sa))&&669(sa->l2cap_len != sizeof(struct sockaddr_l2cap_compat)))670return (EINVAL);671672if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY,673sizeof(sa->l2cap_bdaddr)) != 0) {674mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);675676LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) {677if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))678continue;679680if (bcmp(&sa->l2cap_bdaddr, &rt->src,681sizeof(rt->src)) == 0)682break;683}684685mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);686687if (rt == NULL)688return (ENETDOWN);689} else690rt = NULL;691692mtx_lock(&pcb->pcb_mtx);693bcopy(&sa->l2cap_bdaddr, &pcb->src, sizeof(pcb->src));694pcb->rt = rt;695mtx_unlock(&pcb->pcb_mtx);696697return (0);698} /* ng_btsocket_l2cap_raw_bind */699700/*701* Connect socket702*/703704int705ng_btsocket_l2cap_raw_connect(struct socket *so, struct sockaddr *nam,706struct thread *td)707{708ng_btsocket_l2cap_raw_pcb_t *pcb = so2l2cap_raw_pcb(so);709struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *) nam;710ng_btsocket_l2cap_rtentry_t *rt = NULL;711int error;712713if (pcb == NULL)714return (EINVAL);715if (ng_btsocket_l2cap_raw_node == NULL)716return (EINVAL);717718if (sa == NULL)719return (EINVAL);720if (sa->l2cap_family != AF_BLUETOOTH)721return (EAFNOSUPPORT);722if((sa->l2cap_len != sizeof(*sa))&&723(sa->l2cap_len != sizeof(struct sockaddr_l2cap_compat)))724return (EINVAL);725726if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)727return (EINVAL);728729mtx_lock(&pcb->pcb_mtx);730731bcopy(&sa->l2cap_bdaddr, &pcb->dst, sizeof(pcb->dst));732733if (bcmp(&pcb->src, &pcb->dst, sizeof(pcb->src)) == 0) {734mtx_unlock(&pcb->pcb_mtx);735736return (EADDRNOTAVAIL);737}738739/*740* If there is route already - use it741*/742743if (pcb->rt != NULL) {744soisconnected(so);745mtx_unlock(&pcb->pcb_mtx);746747return (0);748}749750/*751* Find the first hook that does not match specified destination address752*/753754mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);755756LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) {757if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))758continue;759760if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0)761break;762}763764if (rt != NULL) {765soisconnected(so);766767pcb->rt = rt;768bcopy(&rt->src, &pcb->src, sizeof(pcb->src));769770error = 0;771} else772error = ENETDOWN;773774mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);775mtx_unlock(&pcb->pcb_mtx);776777return (error);778} /* ng_btsocket_l2cap_raw_connect */779780/*781* Process ioctl's calls on socket782*/783784int785ng_btsocket_l2cap_raw_control(struct socket *so, u_long cmd, void *data,786struct ifnet *ifp, struct thread *td)787{788ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);789struct ng_mesg *msg = NULL;790int error = 0;791792if (pcb == NULL)793return (EINVAL);794if (ng_btsocket_l2cap_raw_node == NULL)795return (EINVAL);796797mtx_lock(&pcb->pcb_mtx);798799/* Check if we route info */800if (pcb->rt == NULL) {801mtx_unlock(&pcb->pcb_mtx);802return (EHOSTUNREACH);803}804805/* Check if we have pending ioctl() */806if (pcb->token != 0) {807mtx_unlock(&pcb->pcb_mtx);808return (EBUSY);809}810811switch (cmd) {812case SIOC_L2CAP_NODE_GET_FLAGS: {813struct ng_btsocket_l2cap_raw_node_flags *p =814(struct ng_btsocket_l2cap_raw_node_flags *) data;815816error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,817NGM_L2CAP_NODE_GET_FLAGS,818&p->flags, sizeof(p->flags));819} break;820821case SIOC_L2CAP_NODE_GET_DEBUG: {822struct ng_btsocket_l2cap_raw_node_debug *p =823(struct ng_btsocket_l2cap_raw_node_debug *) data;824825error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,826NGM_L2CAP_NODE_GET_DEBUG,827&p->debug, sizeof(p->debug));828} break;829830case SIOC_L2CAP_NODE_SET_DEBUG: {831struct ng_btsocket_l2cap_raw_node_debug *p =832(struct ng_btsocket_l2cap_raw_node_debug *) data;833834if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)835error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook,836NGM_L2CAP_NODE_SET_DEBUG,837&p->debug, sizeof(p->debug));838else839error = EPERM;840} break;841842case SIOC_L2CAP_NODE_GET_CON_LIST: {843struct ng_btsocket_l2cap_raw_con_list *p =844(struct ng_btsocket_l2cap_raw_con_list *) data;845ng_l2cap_node_con_list_ep *p1 = NULL;846ng_l2cap_node_con_ep *p2 = NULL;847848if (p->num_connections == 0 ||849p->num_connections > NG_L2CAP_MAX_CON_NUM ||850p->connections == NULL) {851mtx_unlock(&pcb->pcb_mtx);852return (EINVAL);853}854855NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_GET_CON_LIST,8560, M_NOWAIT);857if (msg == NULL) {858mtx_unlock(&pcb->pcb_mtx);859return (ENOMEM);860}861ng_btsocket_l2cap_raw_get_token(&msg->header.token);862pcb->token = msg->header.token;863pcb->msg = NULL;864865NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,866pcb->rt->hook, 0);867if (error != 0) {868pcb->token = 0;869mtx_unlock(&pcb->pcb_mtx);870return (error);871}872873error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",874ng_btsocket_l2cap_raw_ioctl_timeout * hz);875pcb->token = 0;876877if (error != 0) {878mtx_unlock(&pcb->pcb_mtx);879return (error);880}881882msg = pcb->msg;883pcb->msg = NULL;884885mtx_unlock(&pcb->pcb_mtx);886887if (msg != NULL &&888msg->header.cmd == NGM_L2CAP_NODE_GET_CON_LIST) {889/* Return data back to user space */890p1 = (ng_l2cap_node_con_list_ep *)(msg->data);891p2 = (ng_l2cap_node_con_ep *)(p1 + 1);892893p->num_connections = min(p->num_connections,894p1->num_connections);895if (p->num_connections > 0)896error = copyout((caddr_t) p2,897(caddr_t) p->connections,898p->num_connections * sizeof(*p2));899} else900error = EINVAL;901902NG_FREE_MSG(msg); /* checks for != NULL */903return (error);904} /* NOTREACHED */905906case SIOC_L2CAP_NODE_GET_CHAN_LIST: {907struct ng_btsocket_l2cap_raw_chan_list *p =908(struct ng_btsocket_l2cap_raw_chan_list *) data;909ng_l2cap_node_chan_list_ep *p1 = NULL;910ng_l2cap_node_chan_ep *p2 = NULL;911912if (p->num_channels == 0 ||913p->num_channels > NG_L2CAP_MAX_CHAN_NUM ||914p->channels == NULL) {915mtx_unlock(&pcb->pcb_mtx);916return (EINVAL);917}918919NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,920NGM_L2CAP_NODE_GET_CHAN_LIST, 0, M_NOWAIT);921if (msg == NULL) {922mtx_unlock(&pcb->pcb_mtx);923return (ENOMEM);924}925ng_btsocket_l2cap_raw_get_token(&msg->header.token);926pcb->token = msg->header.token;927pcb->msg = NULL;928929NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,930pcb->rt->hook, 0);931if (error != 0) {932pcb->token = 0;933mtx_unlock(&pcb->pcb_mtx);934return (error);935}936937error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",938ng_btsocket_l2cap_raw_ioctl_timeout * hz);939pcb->token = 0;940941if (error != 0) {942mtx_unlock(&pcb->pcb_mtx);943return (error);944}945946msg = pcb->msg;947pcb->msg = NULL;948949mtx_unlock(&pcb->pcb_mtx);950951if (msg != NULL &&952msg->header.cmd == NGM_L2CAP_NODE_GET_CHAN_LIST) {953/* Return data back to user space */954p1 = (ng_l2cap_node_chan_list_ep *)(msg->data);955p2 = (ng_l2cap_node_chan_ep *)(p1 + 1);956957p->num_channels = min(p->num_channels,958p1->num_channels);959if (p->num_channels > 0)960error = copyout((caddr_t) p2,961(caddr_t) p->channels,962p->num_channels * sizeof(*p2));963} else964error = EINVAL;965966NG_FREE_MSG(msg); /* checks for != NULL */967return (error);968} /* NOTREACHED */969970case SIOC_L2CAP_L2CA_PING: {971struct ng_btsocket_l2cap_raw_ping *p =972(struct ng_btsocket_l2cap_raw_ping *) data;973ng_l2cap_l2ca_ping_ip *ip = NULL;974ng_l2cap_l2ca_ping_op *op = NULL;975976if ((p->echo_size != 0 && p->echo_data == NULL) ||977p->echo_size > NG_L2CAP_MAX_ECHO_SIZE) {978mtx_unlock(&pcb->pcb_mtx);979return (EINVAL);980}981982NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,983NGM_L2CAP_L2CA_PING, sizeof(*ip) + p->echo_size,984M_NOWAIT);985if (msg == NULL) {986mtx_unlock(&pcb->pcb_mtx);987return (ENOMEM);988}989ng_btsocket_l2cap_raw_get_token(&msg->header.token);990pcb->token = msg->header.token;991pcb->msg = NULL;992993ip = (ng_l2cap_l2ca_ping_ip *)(msg->data);994bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr));995ip->echo_size = p->echo_size;996997if (ip->echo_size > 0) {998mtx_unlock(&pcb->pcb_mtx);999error = copyin(p->echo_data, ip + 1, p->echo_size);1000mtx_lock(&pcb->pcb_mtx);10011002if (error != 0) {1003NG_FREE_MSG(msg);1004pcb->token = 0;1005mtx_unlock(&pcb->pcb_mtx);1006return (error);1007}1008}10091010NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,1011pcb->rt->hook, 0);1012if (error != 0) {1013pcb->token = 0;1014mtx_unlock(&pcb->pcb_mtx);1015return (error);1016}10171018error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",1019bluetooth_l2cap_rtx_timeout());1020pcb->token = 0;10211022if (error != 0) {1023mtx_unlock(&pcb->pcb_mtx);1024return (error);1025}10261027msg = pcb->msg;1028pcb->msg = NULL;10291030mtx_unlock(&pcb->pcb_mtx);10311032if (msg != NULL &&1033msg->header.cmd == NGM_L2CAP_L2CA_PING) {1034/* Return data back to the user space */1035op = (ng_l2cap_l2ca_ping_op *)(msg->data);1036p->result = op->result;1037p->echo_size = min(p->echo_size, op->echo_size);10381039if (p->echo_size > 0)1040error = copyout(op + 1, p->echo_data,1041p->echo_size);1042} else1043error = EINVAL;10441045NG_FREE_MSG(msg); /* checks for != NULL */1046return (error);1047} /* NOTREACHED */10481049case SIOC_L2CAP_L2CA_GET_INFO: {1050struct ng_btsocket_l2cap_raw_get_info *p =1051(struct ng_btsocket_l2cap_raw_get_info *) data;1052ng_l2cap_l2ca_get_info_ip *ip = NULL;1053ng_l2cap_l2ca_get_info_op *op = NULL;10541055if (!(pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)) {1056mtx_unlock(&pcb->pcb_mtx);1057return (EPERM);1058}10591060if (p->info_size != 0 && p->info_data == NULL) {1061mtx_unlock(&pcb->pcb_mtx);1062return (EINVAL);1063}10641065NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,1066NGM_L2CAP_L2CA_GET_INFO, sizeof(*ip) + p->info_size,1067M_NOWAIT);1068if (msg == NULL) {1069mtx_unlock(&pcb->pcb_mtx);1070return (ENOMEM);1071}1072ng_btsocket_l2cap_raw_get_token(&msg->header.token);1073pcb->token = msg->header.token;1074pcb->msg = NULL;10751076ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data);1077bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr));1078ip->info_type = p->info_type;10791080NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,1081pcb->rt->hook, 0);1082if (error != 0) {1083pcb->token = 0;1084mtx_unlock(&pcb->pcb_mtx);1085return (error);1086}10871088error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",1089bluetooth_l2cap_rtx_timeout());1090pcb->token = 0;10911092if (error != 0) {1093mtx_unlock(&pcb->pcb_mtx);1094return (error);1095}10961097msg = pcb->msg;1098pcb->msg = NULL;10991100mtx_unlock(&pcb->pcb_mtx);11011102if (msg != NULL &&1103msg->header.cmd == NGM_L2CAP_L2CA_GET_INFO) {1104/* Return data back to the user space */1105op = (ng_l2cap_l2ca_get_info_op *)(msg->data);1106p->result = op->result;1107p->info_size = min(p->info_size, op->info_size);11081109if (p->info_size > 0)1110error = copyout(op + 1, p->info_data,1111p->info_size);1112} else1113error = EINVAL;11141115NG_FREE_MSG(msg); /* checks for != NULL */1116return (error);1117} /* NOTREACHED */11181119case SIOC_L2CAP_NODE_GET_AUTO_DISCON_TIMO: {1120struct ng_btsocket_l2cap_raw_auto_discon_timo *p =1121(struct ng_btsocket_l2cap_raw_auto_discon_timo *) data;11221123error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,1124NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO,1125&p->timeout, sizeof(p->timeout));1126} break;11271128case SIOC_L2CAP_NODE_SET_AUTO_DISCON_TIMO: {1129struct ng_btsocket_l2cap_raw_auto_discon_timo *p =1130(struct ng_btsocket_l2cap_raw_auto_discon_timo *) data;11311132if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)1133error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook,1134NGM_L2CAP_NODE_SET_AUTO_DISCON_TIMO,1135&p->timeout, sizeof(p->timeout));1136else1137error = EPERM;1138} break;11391140default:1141error = EINVAL;1142break;1143}11441145mtx_unlock(&pcb->pcb_mtx);11461147return (error);1148} /* ng_btsocket_l2cap_raw_control */11491150/*1151* Detach and destroy socket1152*/11531154void1155ng_btsocket_l2cap_raw_detach(struct socket *so)1156{1157ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);11581159KASSERT(pcb != NULL, ("nt_btsocket_l2cap_raw_detach: pcb == NULL"));1160if (ng_btsocket_l2cap_raw_node == NULL)1161return;11621163mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);1164mtx_lock(&pcb->pcb_mtx);11651166LIST_REMOVE(pcb, next);11671168mtx_unlock(&pcb->pcb_mtx);1169mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);11701171mtx_destroy(&pcb->pcb_mtx);11721173bzero(pcb, sizeof(*pcb));1174free(pcb, M_NETGRAPH_BTSOCKET_L2CAP_RAW);11751176so->so_pcb = NULL;1177} /* ng_btsocket_l2cap_raw_detach */11781179/*1180* Disconnect socket1181*/11821183int1184ng_btsocket_l2cap_raw_disconnect(struct socket *so)1185{1186ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);11871188if (pcb == NULL)1189return (EINVAL);1190if (ng_btsocket_l2cap_raw_node == NULL)1191return (EINVAL);11921193mtx_lock(&pcb->pcb_mtx);1194pcb->rt = NULL;1195soisdisconnected(so);1196mtx_unlock(&pcb->pcb_mtx);11971198return (0);1199} /* ng_btsocket_l2cap_raw_disconnect */12001201/*1202* Get peer address1203*/12041205int1206ng_btsocket_l2cap_raw_peeraddr(struct socket *so, struct sockaddr *sa)1207{1208ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);1209struct sockaddr_l2cap *l2cap = (struct sockaddr_l2cap *)sa;12101211if (pcb == NULL)1212return (EINVAL);1213if (ng_btsocket_l2cap_raw_node == NULL)1214return (EINVAL);12151216*l2cap = (struct sockaddr_l2cap ){1217.l2cap_len = sizeof(struct sockaddr_l2cap),1218.l2cap_family = AF_BLUETOOTH,1219.l2cap_bdaddr_type = BDADDR_BREDR,1220};12211222mtx_lock(&pcb->pcb_mtx);1223bcopy(&pcb->dst, &l2cap->l2cap_bdaddr, sizeof(l2cap->l2cap_bdaddr));1224mtx_unlock(&pcb->pcb_mtx);12251226return (0);1227}12281229/*1230* Send data to socket1231*/12321233int1234ng_btsocket_l2cap_raw_send(struct socket *so, int flags, struct mbuf *m,1235struct sockaddr *nam, struct mbuf *control, struct thread *td)1236{1237NG_FREE_M(m); /* Checks for m != NULL */1238NG_FREE_M(control);12391240return (EOPNOTSUPP);1241} /* ng_btsocket_l2cap_raw_send */12421243/*1244* Get socket address1245*/12461247int1248ng_btsocket_l2cap_raw_sockaddr(struct socket *so, struct sockaddr *sa)1249{1250ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);1251struct sockaddr_l2cap *l2cap = (struct sockaddr_l2cap *)sa;12521253if (pcb == NULL)1254return (EINVAL);1255if (ng_btsocket_l2cap_raw_node == NULL)1256return (EINVAL);12571258*l2cap = (struct sockaddr_l2cap ){1259.l2cap_len = sizeof(struct sockaddr_l2cap),1260.l2cap_family = AF_BLUETOOTH,1261.l2cap_bdaddr_type = BDADDR_BREDR,1262};12631264mtx_lock(&pcb->pcb_mtx);1265bcopy(&pcb->src, &l2cap->l2cap_bdaddr, sizeof(l2cap->l2cap_bdaddr));1266mtx_unlock(&pcb->pcb_mtx);12671268return (0);1269}12701271/*1272* Get next token1273*/12741275static void1276ng_btsocket_l2cap_raw_get_token(u_int32_t *token)1277{1278mtx_lock(&ng_btsocket_l2cap_raw_token_mtx);12791280if (++ ng_btsocket_l2cap_raw_token == 0)1281ng_btsocket_l2cap_raw_token = 1;12821283*token = ng_btsocket_l2cap_raw_token;12841285mtx_unlock(&ng_btsocket_l2cap_raw_token_mtx);1286} /* ng_btsocket_l2cap_raw_get_token */12871288/*1289* Send Netgraph message to the node - do not expect reply1290*/12911292static int1293ng_btsocket_l2cap_raw_send_ngmsg(hook_p hook, int cmd, void *arg, int arglen)1294{1295struct ng_mesg *msg = NULL;1296int error = 0;12971298NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, arglen, M_NOWAIT);1299if (msg == NULL)1300return (ENOMEM);13011302if (arg != NULL && arglen > 0)1303bcopy(arg, msg->data, arglen);13041305NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, hook, 0);13061307return (error);1308} /* ng_btsocket_l2cap_raw_send_ngmsg */13091310/*1311* Send Netgraph message to the node (no data) and wait for reply1312*/13131314static int1315ng_btsocket_l2cap_raw_send_sync_ngmsg(ng_btsocket_l2cap_raw_pcb_p pcb,1316int cmd, void *rsp, int rsplen)1317{1318struct ng_mesg *msg = NULL;1319int error = 0;13201321mtx_assert(&pcb->pcb_mtx, MA_OWNED);13221323NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, 0, M_NOWAIT);1324if (msg == NULL)1325return (ENOMEM);13261327ng_btsocket_l2cap_raw_get_token(&msg->header.token);1328pcb->token = msg->header.token;1329pcb->msg = NULL;13301331NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,1332pcb->rt->hook, 0);1333if (error != 0) {1334pcb->token = 0;1335return (error);1336}13371338error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",1339ng_btsocket_l2cap_raw_ioctl_timeout * hz);1340pcb->token = 0;13411342if (error != 0)1343return (error);13441345if (pcb->msg != NULL && pcb->msg->header.cmd == cmd)1346bcopy(pcb->msg->data, rsp, rsplen);1347else1348error = EINVAL;13491350NG_FREE_MSG(pcb->msg); /* checks for != NULL */13511352return (0);1353} /* ng_btsocket_l2cap_raw_send_sync_ngmsg */135413551356