ng_btsocket_hci_raw.c revision 109623
1/*
2 * ng_btsocket_hci_raw.c
3 *
4 * Copyright (c) 2001-2002 Maksim Yevmenkin <m_evmenkin@yahoo.com>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $Id: ng_btsocket_hci_raw.c,v 1.3 2002/11/12 22:31:39 max Exp $
29 * $FreeBSD: head/sys/netgraph/bluetooth/socket/ng_btsocket_hci_raw.c 109623 2003-01-21 08:56:16Z alfred $
30 */
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/domain.h>
35#include <sys/errno.h>
36#include <sys/filedesc.h>
37#include <sys/ioccom.h>
38#include <sys/kernel.h>
39#include <sys/lock.h>
40#include <sys/malloc.h>
41#include <sys/mbuf.h>
42#include <sys/mutex.h>
43#include <sys/protosw.h>
44#include <sys/queue.h>
45#include <sys/socket.h>
46#include <sys/socketvar.h>
47#include <sys/sysctl.h>
48#include <sys/taskqueue.h>
49#include <netgraph/ng_message.h>
50#include <netgraph/netgraph.h>
51#include <bitstring.h>
52#include "ng_bluetooth.h"
53#include "ng_hci.h"
54#include "ng_l2cap.h"
55#include "ng_btsocket.h"
56#include "ng_btsocket_hci_raw.h"
57
58/* MALLOC define */
59#ifdef NG_SEPARATE_MALLOC
60MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_HCI_RAW, "netgraph_btsocks_hci_raw",
61	"Netgraph Bluetooth raw HCI sockets");
62#else
63#define M_NETGRAPH_BTSOCKET_HCI_RAW M_NETGRAPH
64#endif /* NG_SEPARATE_MALLOC */
65
66/* Netgraph node methods */
67static ng_constructor_t	ng_btsocket_hci_raw_node_constructor;
68static ng_rcvmsg_t	ng_btsocket_hci_raw_node_rcvmsg;
69static ng_shutdown_t	ng_btsocket_hci_raw_node_shutdown;
70static ng_newhook_t	ng_btsocket_hci_raw_node_newhook;
71static ng_connect_t	ng_btsocket_hci_raw_node_connect;
72static ng_rcvdata_t	ng_btsocket_hci_raw_node_rcvdata;
73static ng_disconnect_t	ng_btsocket_hci_raw_node_disconnect;
74
75static void 		ng_btsocket_hci_raw_input (void *, int);
76static void 		ng_btsocket_hci_raw_output(node_p, hook_p, void *, int);
77static void		ng_btsocket_hci_raw_savctl(ng_btsocket_hci_raw_pcb_p,
78						   struct mbuf **,
79						   struct mbuf *);
80
81/* Netgraph type descriptor */
82static struct ng_type   typestruct = {
83	NG_ABI_VERSION,
84	NG_BTSOCKET_HCI_RAW_NODE_TYPE,		/* typename */
85	NULL,					/* modevent */
86	ng_btsocket_hci_raw_node_constructor,	/* constructor */
87	ng_btsocket_hci_raw_node_rcvmsg,	/* control message */
88	ng_btsocket_hci_raw_node_shutdown,	/* destructor */
89	ng_btsocket_hci_raw_node_newhook,	/* new hook */
90	NULL,					/* find hook */
91	ng_btsocket_hci_raw_node_connect,	/* connect hook */
92	ng_btsocket_hci_raw_node_rcvdata,	/* data */
93	ng_btsocket_hci_raw_node_disconnect,	/* disconnect hook */
94	NULL					/* node command list */
95};
96
97/* Globals */
98extern int					ifqmaxlen;
99static u_int32_t				ng_btsocket_hci_raw_debug_level;
100static u_int32_t				ng_btsocket_hci_raw_ioctl_timeout;
101static node_p					ng_btsocket_hci_raw_node;
102static struct ng_bt_itemq			ng_btsocket_hci_raw_queue;
103static struct mtx				ng_btsocket_hci_raw_queue_mtx;
104static struct task				ng_btsocket_hci_raw_task;
105static LIST_HEAD(, ng_btsocket_hci_raw_pcb)	ng_btsocket_hci_raw_sockets;
106static struct mtx				ng_btsocket_hci_raw_sockets_mtx;
107static u_int32_t				ng_btsocket_hci_raw_token;
108static struct mtx				ng_btsocket_hci_raw_token_mtx;
109
110/* Sysctl tree */
111SYSCTL_DECL(_net_bluetooth_hci_sockets);
112SYSCTL_NODE(_net_bluetooth_hci_sockets, OID_AUTO, raw, CTLFLAG_RW,
113        0, "Bluetooth raw HCI sockets family");
114SYSCTL_INT(_net_bluetooth_hci_sockets_raw, OID_AUTO, debug_level, CTLFLAG_RW,
115        &ng_btsocket_hci_raw_debug_level, NG_BTSOCKET_WARN_LEVEL,
116	"Bluetooth raw HCI sockets debug level");
117SYSCTL_INT(_net_bluetooth_hci_sockets_raw, OID_AUTO, ioctl_timeout, CTLFLAG_RW,
118        &ng_btsocket_hci_raw_ioctl_timeout, 5,
119	"Bluetooth raw HCI sockets ioctl timeout");
120SYSCTL_INT(_net_bluetooth_hci_sockets_raw, OID_AUTO, queue_len, CTLFLAG_RD,
121        &ng_btsocket_hci_raw_queue.len, 0,
122        "Bluetooth raw HCI sockets input queue length");
123SYSCTL_INT(_net_bluetooth_hci_sockets_raw, OID_AUTO, queue_maxlen, CTLFLAG_RD,
124        &ng_btsocket_hci_raw_queue.maxlen, 0,
125        "Bluetooth raw HCI sockets input queue max. length");
126SYSCTL_INT(_net_bluetooth_hci_sockets_raw, OID_AUTO, queue_drops, CTLFLAG_RD,
127        &ng_btsocket_hci_raw_queue.drops, 0,
128        "Bluetooth raw HCI sockets input queue drops");
129
130/* Debug */
131#define NG_BTSOCKET_HCI_RAW_INFO \
132	if (ng_btsocket_hci_raw_debug_level >= NG_BTSOCKET_INFO_LEVEL) \
133		printf
134
135#define NG_BTSOCKET_HCI_RAW_WARN \
136	if (ng_btsocket_hci_raw_debug_level >= NG_BTSOCKET_WARN_LEVEL) \
137		printf
138
139#define NG_BTSOCKET_HCI_RAW_ERR \
140	if (ng_btsocket_hci_raw_debug_level >= NG_BTSOCKET_ERR_LEVEL) \
141		printf
142
143#define NG_BTSOCKET_HCI_RAW_ALERT \
144	if (ng_btsocket_hci_raw_debug_level >= NG_BTSOCKET_ALERT_LEVEL) \
145		printf
146
147/****************************************************************************
148 ****************************************************************************
149 **                          Netgraph specific
150 ****************************************************************************
151 ****************************************************************************/
152
153/*
154 * Netgraph node constructor. Do not allow to create node of this type.
155 */
156
157static int
158ng_btsocket_hci_raw_node_constructor(node_p node)
159{
160	return (EINVAL);
161} /* ng_btsocket_hci_raw_node_constructor */
162
163/*
164 * Netgraph node destructor. Just let old node go and create new fresh one.
165 */
166
167static int
168ng_btsocket_hci_raw_node_shutdown(node_p node)
169{
170	int	error = 0;
171
172	NG_NODE_UNREF(node);
173
174	error = ng_make_node_common(&typestruct, &ng_btsocket_hci_raw_node);
175	if (error  != 0) {
176		NG_BTSOCKET_HCI_RAW_ALERT(
177"%s: Could not create Netgraph node, error=%d\n", __func__, error);
178
179		ng_btsocket_hci_raw_node = NULL;
180
181		return (ENOMEM);
182        }
183
184	error = ng_name_node(ng_btsocket_hci_raw_node,
185				NG_BTSOCKET_HCI_RAW_NODE_TYPE);
186	if (error != 0) {
187		NG_BTSOCKET_HCI_RAW_ALERT(
188"%s: Could not name Netgraph node, error=%d\n", __func__, error);
189
190		NG_NODE_UNREF(ng_btsocket_hci_raw_node);
191		ng_btsocket_hci_raw_node = NULL;
192
193		return (EINVAL);
194	}
195
196	return (0);
197} /* ng_btsocket_hci_raw_node_shutdown */
198
199/*
200 * Create new hook. Just say "yes"
201 */
202
203static int
204ng_btsocket_hci_raw_node_newhook(node_p node, hook_p hook, char const *name)
205{
206	return (0);
207} /* ng_btsocket_hci_raw_node_newhook */
208
209/*
210 * Connect hook. Just say "yes"
211 */
212
213static int
214ng_btsocket_hci_raw_node_connect(hook_p hook)
215{
216	return (0);
217} /* ng_btsocket_hci_raw_node_connect */
218
219/*
220 * Disconnect hook
221 */
222
223static int
224ng_btsocket_hci_raw_node_disconnect(hook_p hook)
225{
226	return (0);
227} /* ng_btsocket_hci_raw_node_disconnect */
228
229/*
230 * Receive control message.
231 * Make sure it is a message from HCI node and it is a response.
232 * Enqueue item and schedule input task.
233 */
234
235static int
236ng_btsocket_hci_raw_node_rcvmsg(node_p node, item_p item, hook_p lasthook)
237{
238	struct ng_mesg	*msg = NGI_MSG(item); /* item still has message */
239	int		 error = 0;
240
241	if (msg != NULL &&
242	    msg->header.typecookie == NGM_HCI_COOKIE &&
243	    msg->header.flags & NGF_RESP) {
244		mtx_lock(&ng_btsocket_hci_raw_queue_mtx);
245		if (NG_BT_ITEMQ_FULL(&ng_btsocket_hci_raw_queue)) {
246			NG_BTSOCKET_HCI_RAW_ERR(
247"%s: Input queue is full\n", __func__);
248
249			NG_BT_ITEMQ_DROP(&ng_btsocket_hci_raw_queue);
250			NG_FREE_ITEM(item);
251			error = ENOBUFS;
252		} else {
253			NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_hci_raw_queue, item);
254			error = taskqueue_enqueue(taskqueue_swi,
255						&ng_btsocket_hci_raw_task);
256		}
257		mtx_unlock(&ng_btsocket_hci_raw_queue_mtx);
258	} else {
259		NG_FREE_ITEM(item);
260		error = EINVAL;
261	}
262
263	return (error);
264} /* ng_btsocket_hci_raw_node_rcvmsg */
265
266/*
267 * Receive packet from the one of our hook.
268 * Prepend every packet with sockaddr_hci and record sender's node name.
269 * Enqueue item and schedule input task.
270 */
271
272static int
273ng_btsocket_hci_raw_node_rcvdata(hook_p hook, item_p item)
274{
275	struct mbuf	*nam = NULL;
276	int		 error;
277
278	MGET(nam, M_NOWAIT, MT_SONAME);
279	if (nam != NULL) {
280		struct sockaddr_hci	*sa = mtod(nam, struct sockaddr_hci *);
281
282		nam->m_len = sizeof(struct sockaddr_hci);
283
284		sa->hci_len = sizeof(*sa);
285		sa->hci_family = AF_BLUETOOTH;
286		strncpy(sa->hci_node, NG_PEER_NODE_NAME(hook),
287			sizeof(sa->hci_node));
288		sa->hci_node[sizeof(sa->hci_node) - 1] = 0; /* sanity */
289
290		NGI_GET_M(item, nam->m_next);
291		NGI_M(item) = nam;
292
293		mtx_lock(&ng_btsocket_hci_raw_queue_mtx);
294		if (NG_BT_ITEMQ_FULL(&ng_btsocket_hci_raw_queue)) {
295			NG_BTSOCKET_HCI_RAW_ERR(
296"%s: Input queue is full\n", __func__);
297
298			NG_BT_ITEMQ_DROP(&ng_btsocket_hci_raw_queue);
299			NG_FREE_ITEM(item);
300			error = ENOBUFS;
301		} else {
302			NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_hci_raw_queue, item);
303			error = taskqueue_enqueue(taskqueue_swi,
304						&ng_btsocket_hci_raw_task);
305		}
306		mtx_unlock(&ng_btsocket_hci_raw_queue_mtx);
307	} else {
308		NG_BTSOCKET_HCI_RAW_ERR(
309"%s: Failed to allocate address mbuf\n", __func__);
310
311		NG_FREE_ITEM(item);
312		error = ENOBUFS;
313	}
314
315	return (error);
316} /* ng_btsocket_hci_raw_node_rcvdata */
317
318/****************************************************************************
319 ****************************************************************************
320 **                              Sockets specific
321 ****************************************************************************
322 ****************************************************************************/
323
324/*
325 * Get next token
326 */
327
328static void
329ng_btsocket_hci_raw_get_token(u_int32_t *token)
330{
331	mtx_lock(&ng_btsocket_hci_raw_token_mtx);
332
333	if (++ ng_btsocket_hci_raw_token == 0)
334		ng_btsocket_hci_raw_token = 1;
335
336	*token = ng_btsocket_hci_raw_token;
337
338	mtx_unlock(&ng_btsocket_hci_raw_token_mtx);
339} /* ng_btsocket_hci_raw_token */
340
341/*
342 * Send Netgraph message to the node - do not expect reply
343 */
344
345static int
346ng_btsocket_raw_send_ngmsg(char *path, int cmd, void *arg, int arglen)
347{
348	struct ng_mesg	*msg = NULL;
349	int		 error = 0;
350
351	NG_MKMESSAGE(msg, NGM_HCI_COOKIE, cmd, arglen, 0);
352	if (msg == NULL)
353		return (ENOMEM);
354
355	if (arg != NULL && arglen > 0)
356		bcopy(arg, msg->data, arglen);
357
358	NG_SEND_MSG_PATH(error, ng_btsocket_hci_raw_node, msg, path, NULL);
359
360	return (error);
361} /* ng_btsocket_raw_send_ngmsg */
362
363/*
364 * Send Netgraph message to the node (no data) and wait for reply
365 */
366
367static int
368ng_btsocket_raw_send_sync_ngmsg(ng_btsocket_hci_raw_pcb_p pcb, char *path,
369		int cmd, void *rsp, int rsplen)
370{
371	struct ng_mesg	*msg = NULL;
372	int		 error = 0;
373
374	ng_btsocket_hci_raw_get_token(&pcb->token);
375	pcb->msg = NULL;
376
377	NG_MKMESSAGE(msg, NGM_HCI_COOKIE, cmd, 0, 0);
378	if (msg == NULL) {
379		pcb->token = 0;
380		return (ENOMEM);
381	}
382	msg->header.token = pcb->token;
383
384	NG_SEND_MSG_PATH(error, ng_btsocket_hci_raw_node, msg, path, NULL);
385	if (error != 0) {
386		pcb->token = 0;
387		return (error);
388	}
389
390	error = tsleep(&pcb->msg, PZERO|PCATCH, "hcictl",
391			ng_btsocket_hci_raw_ioctl_timeout * hz);
392	if (error != 0) {
393		pcb->token = 0;
394		return (error);
395	}
396
397	if (pcb->msg != NULL && pcb->msg->header.cmd == cmd)
398		bcopy(pcb->msg->data, rsp, rsplen);
399	else
400		error = EINVAL;
401
402	NG_FREE_MSG(pcb->msg); /* checks for != NULL */
403	pcb->token = 0;
404
405	return (0);
406} /* ng_btsocket_raw_send_sync_ngmsg */
407
408/*
409 * Create control information for the packet
410 */
411
412static void
413ng_btsocket_hci_raw_savctl(ng_btsocket_hci_raw_pcb_p pcb, struct mbuf **ctl,
414		struct mbuf *m)
415{
416	int		dir;
417	struct timeval	tv;
418
419	if (pcb->flags & NG_BTSOCKET_HCI_RAW_DIRECTION) {
420		dir = (m->m_flags & M_PROTO1)? 1 : 0;
421		*ctl = sbcreatecontrol((caddr_t) &dir, sizeof(dir),
422					SCM_HCI_RAW_DIRECTION, SOL_HCI_RAW);
423		if (*ctl != NULL)
424			ctl = &((*ctl)->m_next);
425	}
426
427	if (pcb->so->so_options & SO_TIMESTAMP) {
428		microtime(&tv);
429		*ctl = sbcreatecontrol((caddr_t) &tv, sizeof(tv),
430					SCM_TIMESTAMP, SOL_SOCKET);
431		if (*ctl != NULL)
432			ctl = &((*ctl)->m_next);
433	}
434} /* ng_btsocket_hci_raw_savctl */
435
436/*
437 * Raw HCI sockets data input routine
438 */
439
440static void
441ng_btsocket_hci_raw_data_input(struct mbuf *nam)
442{
443	ng_btsocket_hci_raw_pcb_p	 pcb = NULL;
444	struct mbuf			*m0 = NULL, *m = NULL;
445	struct sockaddr_hci		*sa = NULL;
446	bitstr_t			*mask = NULL;
447	int				 bit;
448
449	m0 = nam->m_next;
450	nam->m_next = NULL;
451
452	KASSERT((nam->m_type == MT_SONAME),
453		("%s: m_type=%d\n", __func__, nam->m_type));
454	KASSERT((m0->m_flags & M_PKTHDR),
455		("%s: m_flags=%#x\n", __func__, m0->m_flags));
456
457	sa = mtod(nam, struct sockaddr_hci *);
458
459	mtx_lock(&ng_btsocket_hci_raw_sockets_mtx);
460
461	LIST_FOREACH(pcb, &ng_btsocket_hci_raw_sockets, next) {
462		/*
463		 * If socket was bound then check address and
464		 *  make sure it matches.
465		 */
466
467		if (pcb->addr.hci_node[0] != 0 &&
468		    strcmp(sa->hci_node, pcb->addr.hci_node) != 0)
469			continue;
470
471		/*
472		 * Check packet agains socket filter
473		 * XXX do we have to call m_pullup() here?
474		 */
475
476		switch (*mtod(m0, u_int8_t *)) {
477		case NG_HCI_CMD_PKT:
478		case NG_HCI_ACL_DATA_PKT:
479		case NG_HCI_SCO_DATA_PKT:
480			mask = pcb->filter.packet_mask;
481			bit = *mtod(m0, u_int8_t *) - 1;
482			break;
483
484		case NG_HCI_EVENT_PKT:
485			mask = pcb->filter.event_mask;
486			bit = mtod(m0, ng_hci_event_pkt_t *)->event - 1;
487			break;
488
489		default:
490			KASSERT(0,
491("%s: invalid packet type=%#x\n", __func__, *mtod(m0, u_int8_t *)));
492
493			mask = NULL;
494			bit = 0;
495			break;
496		}
497
498		if (mask == NULL || !bit_test(mask, bit))
499			continue;
500
501		/*
502		 * Make a copy of the packet, append to the socket's
503		 * receive queue and wakeup socket. sbappendaddr()
504		 * will check if socket has enough buffer space.
505		 */
506
507		m = m_dup(m0, M_NOWAIT);
508		if (m != NULL) {
509			struct mbuf	*ctl = NULL;
510
511			ng_btsocket_hci_raw_savctl(pcb, &ctl, m);
512
513			if (sbappendaddr(&pcb->so->so_rcv,
514					(struct sockaddr *) sa, m, ctl))
515				sorwakeup(pcb->so);
516			else {
517				NG_BTSOCKET_HCI_RAW_WARN(
518"%s: sbappendadd() failed\n", __func__);
519
520				NG_FREE_M(m);
521				NG_FREE_M(ctl);
522			}
523		}
524	}
525
526	mtx_unlock(&ng_btsocket_hci_raw_sockets_mtx);
527
528	NG_FREE_M(nam);
529	NG_FREE_M(m0);
530} /* ng_btsocket_hci_raw_data_input */
531
532/*
533 * Raw HCI sockets message input routine
534 */
535
536static void
537ng_btsocket_hci_raw_msg_input(struct ng_mesg *msg)
538{
539	ng_btsocket_hci_raw_pcb_p	 pcb = NULL;
540
541	if (msg->header.token != 0) {
542		mtx_lock(&ng_btsocket_hci_raw_sockets_mtx);
543
544		LIST_FOREACH(pcb, &ng_btsocket_hci_raw_sockets, next) {
545			if (msg->header.token == pcb->token) {
546				pcb->msg = msg;
547				msg = NULL;
548				wakeup(&pcb->msg);
549				break;
550			}
551		}
552
553		mtx_unlock(&ng_btsocket_hci_raw_sockets_mtx);
554	}
555
556	NG_FREE_MSG(msg); /* checks for != NULL */
557} /* ng_btsocket_hci_raw_msg_input */
558
559/*
560 * Raw HCI sockets input routines
561 */
562
563static void
564ng_btsocket_hci_raw_input(void *context, int pending)
565{
566	item_p	item = NULL;
567
568	for (;;) {
569		mtx_lock(&ng_btsocket_hci_raw_queue_mtx);
570		NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_hci_raw_queue, item);
571		mtx_unlock(&ng_btsocket_hci_raw_queue_mtx);
572
573		if (item == NULL)
574			break;
575
576		switch(item->el_flags & NGQF_TYPE) {
577		case NGQF_DATA: {
578			struct mbuf	*m = NULL;
579
580			NGI_GET_M(item, m);
581			ng_btsocket_hci_raw_data_input(m);
582			} break;
583
584		case NGQF_MESG: {
585			struct ng_mesg	*msg = NULL;
586
587			NGI_GET_MSG(item, msg);
588			ng_btsocket_hci_raw_msg_input(msg);
589			} break;
590
591		default:
592			KASSERT(0,
593("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE)));
594			break;
595		}
596
597		NG_FREE_ITEM(item);
598	}
599} /* ng_btsocket_hci_raw_input */
600
601/*
602 * Raw HCI sockets output routine
603 */
604
605static void
606ng_btsocket_hci_raw_output(node_p node, hook_p hook, void *arg1, int arg2)
607{
608	struct mbuf		*nam = (struct mbuf *) arg1, *m = NULL;
609	struct sockaddr_hci	*sa = NULL;
610	int			 error;
611
612	m = nam->m_next;
613	nam->m_next = NULL;
614
615	KASSERT((nam->m_type == MT_SONAME),
616		("%s: m_type=%d\n", __func__, nam->m_type));
617	KASSERT((m->m_flags & M_PKTHDR),
618		("%s: m_flags=%#x\n", __func__, m->m_flags));
619
620	sa = mtod(nam, struct sockaddr_hci *);
621
622	/*
623	 * Find downstream hook
624	 * XXX For now access node hook list directly. Should be safe because
625	 * we used ng_send_fn() and we should have exclusive lock on the node.
626	 */
627
628	LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) {
629		if (hook == NULL || NG_HOOK_NOT_VALID(hook) ||
630		    NG_NODE_NOT_VALID(NG_PEER_NODE(hook)))
631			continue;
632
633		if (strcmp(sa->hci_node, NG_PEER_NODE_NAME(hook)) == 0) {
634			NG_SEND_DATA_ONLY(error, hook, m); /* sets m to NULL */
635			break;
636		}
637	}
638
639	NG_FREE_M(nam); /* check for != NULL */
640	NG_FREE_M(m);
641} /* ng_btsocket_hci_raw_output */
642
643/*
644 * Initialize everything
645 */
646
647void
648ng_btsocket_hci_raw_init(void)
649{
650	int	error = 0;
651
652	ng_btsocket_hci_raw_node = NULL;
653	ng_btsocket_hci_raw_debug_level = NG_BTSOCKET_WARN_LEVEL;
654	ng_btsocket_hci_raw_ioctl_timeout = 5;
655
656	/* Register Netgraph node type */
657	error = ng_newtype(&typestruct);
658	if (error != 0) {
659		NG_BTSOCKET_HCI_RAW_ALERT(
660"%s: Could not register Netgraph node type, error=%d\n", __func__, error);
661
662		return;
663	}
664
665	/* Create Netgrapg node */
666	error = ng_make_node_common(&typestruct, &ng_btsocket_hci_raw_node);
667	if (error != 0) {
668		NG_BTSOCKET_HCI_RAW_ALERT(
669"%s: Could not create Netgraph node, error=%d\n", __func__, error);
670
671		ng_btsocket_hci_raw_node = NULL;
672
673		return;
674        }
675
676	error = ng_name_node(ng_btsocket_hci_raw_node,
677				NG_BTSOCKET_HCI_RAW_NODE_TYPE);
678	if (error != 0) {
679		NG_BTSOCKET_HCI_RAW_ALERT(
680"%s: Could not name Netgraph node, error=%d\n", __func__, error);
681
682		NG_NODE_UNREF(ng_btsocket_hci_raw_node);
683		ng_btsocket_hci_raw_node = NULL;
684
685		return;
686	}
687
688	/* Create input queue */
689	NG_BT_ITEMQ_INIT(&ng_btsocket_hci_raw_queue, ifqmaxlen);
690	mtx_init(&ng_btsocket_hci_raw_queue_mtx,
691		"btsocks_hci_raw_queue_mtx", NULL, MTX_DEF);
692	TASK_INIT(&ng_btsocket_hci_raw_task, 0,
693		ng_btsocket_hci_raw_input, NULL);
694
695	/* Create list of sockets */
696	LIST_INIT(&ng_btsocket_hci_raw_sockets);
697	mtx_init(&ng_btsocket_hci_raw_sockets_mtx,
698		"btsocks_hci_raw_sockets_mtx", NULL, MTX_DEF);
699
700	/* Tokens */
701	ng_btsocket_hci_raw_token = 0;
702	mtx_init(&ng_btsocket_hci_raw_token_mtx,
703		"btsocks_hci_raw_token_mtx", NULL, MTX_DEF);
704} /* ng_btsocket_hci_raw_init */
705
706/*
707 * Abort connection on socket
708 */
709
710int
711ng_btsocket_hci_raw_abort(struct socket *so)
712{
713	soisdisconnected(so);
714
715	return (ng_btsocket_hci_raw_detach(so));
716} /* ng_btsocket_hci_raw_abort */
717
718/*
719 * Create new raw HCI socket
720 */
721
722int
723ng_btsocket_hci_raw_attach(struct socket *so, int proto, struct thread *td)
724{
725	ng_btsocket_hci_raw_pcb_p	pcb = so2hci_raw_pcb(so);
726	int				error = 0;
727
728	if (pcb != NULL)
729		return (EISCONN);
730
731	if (ng_btsocket_hci_raw_node == NULL)
732		return (EPROTONOSUPPORT);
733	if (proto != BLUETOOTH_PROTO_HCI)
734		return (EPROTONOSUPPORT);
735	if (so->so_type != SOCK_RAW)
736		return (ESOCKTNOSUPPORT);
737	if ((error = suser(td)) != 0)
738		return (error);
739
740	error = soreserve(so, NG_BTSOCKET_HCI_RAW_SENDSPACE,
741				NG_BTSOCKET_HCI_RAW_RECVSPACE);
742	if (error != 0)
743		return (error);
744
745	MALLOC(pcb, ng_btsocket_hci_raw_pcb_p, sizeof(*pcb),
746		M_NETGRAPH_BTSOCKET_HCI_RAW, M_ZERO);
747	if (pcb == NULL)
748		return (ENOMEM);
749
750	so->so_pcb = (caddr_t) pcb;
751	pcb->so = so;
752
753	/*
754	 * Set default socket filter. By default socket only accepts HCI
755	 * Command_Complete and Command_Status event packets.
756	 */
757
758	bit_set(pcb->filter.event_mask, NG_HCI_EVENT_COMMAND_COMPL - 1);
759	bit_set(pcb->filter.event_mask, NG_HCI_EVENT_COMMAND_STATUS - 1);
760
761	mtx_lock(&ng_btsocket_hci_raw_sockets_mtx);
762	LIST_INSERT_HEAD(&ng_btsocket_hci_raw_sockets, pcb, next);
763	mtx_unlock(&ng_btsocket_hci_raw_sockets_mtx);
764
765	return (0);
766} /* ng_btsocket_hci_raw_attach */
767
768/*
769 * Bind raw HCI socket
770 */
771
772int
773ng_btsocket_hci_raw_bind(struct socket *so, struct sockaddr *nam,
774		struct thread *td)
775{
776	ng_btsocket_hci_raw_pcb_p	 pcb = so2hci_raw_pcb(so);
777	struct sockaddr_hci		*sa = (struct sockaddr_hci *) nam;
778
779	if (pcb == NULL)
780		return (EINVAL);
781	if (ng_btsocket_hci_raw_node == NULL)
782		return (EINVAL);
783
784	if (sa == NULL)
785		return (EINVAL);
786	if (sa->hci_family != AF_BLUETOOTH)
787		return (EAFNOSUPPORT);
788	if (sa->hci_len != sizeof(*sa))
789		return (EINVAL);
790	if (sa->hci_node[0] == 0)
791		return (EINVAL);
792
793	bcopy(sa, &pcb->addr, sizeof(pcb->addr));
794
795	return (0);
796} /* ng_btsocket_hci_raw_bind */
797
798/*
799 * Connect raw HCI socket
800 */
801
802int
803ng_btsocket_hci_raw_connect(struct socket *so, struct sockaddr *nam,
804		struct thread *td)
805{
806	ng_btsocket_hci_raw_pcb_p	 pcb = so2hci_raw_pcb(so);
807	struct sockaddr_hci		*sa = (struct sockaddr_hci *) nam;
808
809	if (pcb == NULL)
810		return (EINVAL);
811	if (ng_btsocket_hci_raw_node == NULL)
812		return (EINVAL);
813
814	if (sa == NULL)
815		return (EINVAL);
816	if (sa->hci_family != AF_BLUETOOTH)
817		return (EAFNOSUPPORT);
818	if (sa->hci_len != sizeof(*sa))
819		return (EINVAL);
820	if (sa->hci_node[0] == 0)
821		return (EDESTADDRREQ);
822	if (bcmp(sa, &pcb->addr, sizeof(pcb->addr)) != 0)
823		return (EADDRNOTAVAIL);
824
825	soisconnected(so);
826
827	return (0);
828} /* ng_btsocket_hci_raw_connect */
829
830/*
831 * Process ioctl on socket
832 */
833
834int
835ng_btsocket_hci_raw_control(struct socket *so, u_long cmd, caddr_t data,
836		struct ifnet *ifp, struct thread *td)
837{
838	ng_btsocket_hci_raw_pcb_p	 pcb = so2hci_raw_pcb(so);
839	char				 path[NG_NODELEN + 2],
840					*hci_node = (char *) data;
841	struct ng_mesg			*msg = NULL;
842	int				 error = 0;
843
844	if (pcb == NULL)
845		return (EINVAL);
846	if (ng_btsocket_hci_raw_node == NULL)
847		return (EINVAL);
848
849	/*
850	 * Make sure caller has provided HCI node name, if not try to
851	 * use addr from socket (if socket was bound)
852	 */
853
854	if (hci_node[0] == 0) {
855		if (pcb->addr.hci_node[0] == 0)
856			return (EINVAL);
857
858		bzero(hci_node, sizeof(pcb->addr.hci_node));
859		strncpy(hci_node,pcb->addr.hci_node,sizeof(pcb->addr.hci_node));
860	}
861
862	snprintf(path, sizeof(path), "%s:", hci_node);
863
864	switch (cmd) {
865	case SIOC_HCI_RAW_NODE_GET_STATE: {
866		struct ng_btsocket_hci_raw_node_state	*p =
867			(struct ng_btsocket_hci_raw_node_state *) data;
868
869		error = ng_btsocket_raw_send_sync_ngmsg(pcb, path,
870				NGM_HCI_NODE_GET_STATE,
871				&p->state, sizeof(p->state));
872		} break;
873
874	case SIOC_HCI_RAW_NODE_INIT:
875		error = ng_btsocket_raw_send_ngmsg(path, NGM_HCI_NODE_INIT,
876				NULL, 0);
877		break;
878
879	case SIOC_HCI_RAW_NODE_GET_DEBUG: {
880		struct ng_btsocket_hci_raw_node_debug	*p =
881			(struct ng_btsocket_hci_raw_node_debug *) data;
882
883		error = ng_btsocket_raw_send_sync_ngmsg(pcb, path,
884				NGM_HCI_NODE_GET_DEBUG,
885				&p->debug, sizeof(p->debug));
886		} break;
887
888	case SIOC_HCI_RAW_NODE_SET_DEBUG: {
889		struct ng_btsocket_hci_raw_node_debug	*p =
890			(struct ng_btsocket_hci_raw_node_debug *) data;
891
892		error = ng_btsocket_raw_send_ngmsg(path, NGM_HCI_NODE_SET_DEBUG,
893				&p->debug, sizeof(p->debug));
894		} break;
895
896	case SIOC_HCI_RAW_NODE_GET_BUFFER: {
897		struct ng_btsocket_hci_raw_node_buffer	*p =
898			(struct ng_btsocket_hci_raw_node_buffer *) data;
899
900		error = ng_btsocket_raw_send_sync_ngmsg(pcb, path,
901				NGM_HCI_NODE_GET_BUFFER,
902				&p->buffer, sizeof(p->buffer));
903		} break;
904
905	case SIOC_HCI_RAW_NODE_GET_BDADDR: {
906		struct ng_btsocket_hci_raw_node_bdaddr	*p =
907			(struct ng_btsocket_hci_raw_node_bdaddr *) data;
908
909		error = ng_btsocket_raw_send_sync_ngmsg(pcb, path,
910				NGM_HCI_NODE_GET_BDADDR,
911				&p->bdaddr, sizeof(p->bdaddr));
912		} break;
913
914	case SIOC_HCI_RAW_NODE_GET_FEATURES: {
915		struct ng_btsocket_hci_raw_node_features	*p =
916			(struct ng_btsocket_hci_raw_node_features *) data;
917
918		error = ng_btsocket_raw_send_sync_ngmsg(pcb, path,
919				NGM_HCI_NODE_GET_FEATURES,
920				&p->features, sizeof(p->features));
921		} break;
922
923	case SIOC_HCI_RAW_NODE_GET_STAT: {
924		struct ng_btsocket_hci_raw_node_stat	*p =
925			(struct ng_btsocket_hci_raw_node_stat *) data;
926
927		error = ng_btsocket_raw_send_sync_ngmsg(pcb, path,
928				NGM_HCI_NODE_GET_STAT,
929				&p->stat, sizeof(p->stat));
930		} break;
931
932	case SIOC_HCI_RAW_NODE_RESET_STAT:
933		error = ng_btsocket_raw_send_ngmsg(path,
934				NGM_HCI_NODE_RESET_STAT, NULL, 0);
935		break;
936
937	case SIOC_HCI_RAW_NODE_FLUSH_NEIGHBOR_CACHE:
938		error = ng_btsocket_raw_send_ngmsg(path,
939				NGM_HCI_NODE_FLUSH_NEIGHBOR_CACHE, NULL, 0);
940		break;
941
942	case SIOC_HCI_RAW_NODE_GET_NEIGHBOR_CACHE:  {
943		struct ng_btsocket_hci_raw_node_neighbor_cache	*p =
944			(struct ng_btsocket_hci_raw_node_neighbor_cache *) data;
945		ng_hci_node_get_neighbor_cache_ep		*p1 = NULL;
946		ng_hci_node_neighbor_cache_entry_ep		*p2 = NULL;
947
948		if (p->num_entries <= 0 ||
949		    p->num_entries > NG_HCI_MAX_NEIGHBOR_NUM ||
950		    p->entries == NULL) {
951			error = EINVAL;
952			break;
953		}
954
955		ng_btsocket_hci_raw_get_token(&pcb->token);
956		pcb->msg = NULL;
957
958		NG_MKMESSAGE(msg, NGM_HCI_COOKIE,
959			NGM_HCI_NODE_GET_NEIGHBOR_CACHE, 0, 0);
960		if (msg == NULL) {
961			pcb->token = 0;
962			error = ENOMEM;
963			break;
964		}
965		msg->header.token = pcb->token;
966
967		NG_SEND_MSG_PATH(error,ng_btsocket_hci_raw_node,msg,path,NULL);
968		if (error != 0) {
969			pcb->token = 0;
970			break;
971		}
972
973		error = tsleep(&pcb->msg, PZERO|PCATCH, "hcictl",
974				ng_btsocket_hci_raw_ioctl_timeout * hz);
975		if (error != 0) {
976			pcb->token = 0;
977			break;
978		}
979
980		if (pcb->msg != NULL &&
981		    pcb->msg->header.cmd == NGM_HCI_NODE_GET_NEIGHBOR_CACHE) {
982			/* Return data back to user space */
983			p1 = (ng_hci_node_get_neighbor_cache_ep *)
984				(pcb->msg->data);
985			p2 = (ng_hci_node_neighbor_cache_entry_ep *)
986				(p1 + 1);
987
988			p->num_entries = min(p->num_entries, p1->num_entries);
989			if (p->num_entries > 0)
990				error = copyout((caddr_t) p2,
991						(caddr_t) p->entries,
992						p->num_entries * sizeof(*p2));
993		} else
994			error = EINVAL;
995
996		NG_FREE_MSG(pcb->msg); /* checks for != NULL */
997		pcb->token = 0;
998		}break;
999
1000	case SIOC_HCI_RAW_NODE_GET_CON_LIST: {
1001		struct ng_btsocket_hci_raw_con_list	*p =
1002			(struct ng_btsocket_hci_raw_con_list *) data;
1003		ng_hci_node_con_list_ep			*p1 = NULL;
1004		ng_hci_node_con_ep			*p2 = NULL;
1005
1006		if (p->num_connections == 0 ||
1007		    p->num_connections > NG_HCI_MAX_CON_NUM ||
1008		    p->connections == NULL) {
1009			error = EINVAL;
1010			break;
1011		}
1012
1013		ng_btsocket_hci_raw_get_token(&pcb->token);
1014		pcb->msg = NULL;
1015
1016		NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_NODE_GET_CON_LIST,
1017			0, 0);
1018		if (msg == NULL) {
1019			pcb->token = 0;
1020			error = ENOMEM;
1021			break;
1022		}
1023		msg->header.token = pcb->token;
1024
1025		NG_SEND_MSG_PATH(error,ng_btsocket_hci_raw_node,msg,path,NULL);
1026		if (error != 0) {
1027			pcb->token = 0;
1028			break;
1029		}
1030
1031		error = tsleep(&pcb->msg, PZERO|PCATCH, "hcictl",
1032				ng_btsocket_hci_raw_ioctl_timeout * hz);
1033		if (error != 0) {
1034			pcb->token = 0;
1035			break;
1036		}
1037
1038		if (pcb->msg != NULL &&
1039		    pcb->msg->header.cmd == NGM_HCI_NODE_GET_CON_LIST) {
1040			/* Return data back to user space */
1041			p1 = (ng_hci_node_con_list_ep *)(pcb->msg->data);
1042			p2 = (ng_hci_node_con_ep *)(p1 + 1);
1043
1044			p->num_connections = min(p->num_connections,
1045						p1->num_connections);
1046			if (p->num_connections > 0)
1047				error = copyout((caddr_t) p2,
1048					(caddr_t) p->connections,
1049					p->num_connections * sizeof(*p2));
1050		} else
1051			error = EINVAL;
1052
1053		NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1054		pcb->token = 0;
1055		} break;
1056
1057	case SIOC_HCI_RAW_NODE_GET_LINK_POLICY_MASK: {
1058		struct ng_btsocket_hci_raw_node_link_policy_mask	*p =
1059			(struct ng_btsocket_hci_raw_node_link_policy_mask *)
1060				data;
1061
1062		error = ng_btsocket_raw_send_sync_ngmsg(pcb, path,
1063				NGM_HCI_NODE_GET_LINK_POLICY_SETTINGS_MASK,
1064				&p->policy_mask, sizeof(p->policy_mask));
1065		} break;
1066
1067	case SIOC_HCI_RAW_NODE_SET_LINK_POLICY_MASK: {
1068		struct ng_btsocket_hci_raw_node_link_policy_mask	*p =
1069			(struct ng_btsocket_hci_raw_node_link_policy_mask *)
1070				data;
1071
1072		error = ng_btsocket_raw_send_ngmsg(path,
1073				NGM_HCI_NODE_SET_LINK_POLICY_SETTINGS_MASK,
1074				&p->policy_mask, sizeof(p->policy_mask));
1075		} break;
1076
1077	case SIOC_HCI_RAW_NODE_GET_PACKET_MASK: {
1078		struct ng_btsocket_hci_raw_node_packet_mask	*p =
1079			(struct ng_btsocket_hci_raw_node_packet_mask *) data;
1080
1081		error = ng_btsocket_raw_send_sync_ngmsg(pcb, path,
1082				NGM_HCI_NODE_GET_PACKET_MASK,
1083				&p->packet_mask, sizeof(p->packet_mask));
1084		} break;
1085
1086	case SIOC_HCI_RAW_NODE_SET_PACKET_MASK: {
1087		struct ng_btsocket_hci_raw_node_packet_mask	*p =
1088			(struct ng_btsocket_hci_raw_node_packet_mask *) data;
1089
1090		error = ng_btsocket_raw_send_ngmsg(path,
1091				NGM_HCI_NODE_SET_PACKET_MASK,
1092				&p->packet_mask, sizeof(p->packet_mask));
1093
1094		} break;
1095
1096	default:
1097		error = EINVAL;
1098		break;
1099	}
1100
1101	return (error);
1102} /* ng_btsocket_hci_raw_control */
1103
1104/*
1105 * Process getsockopt/setsockopt system calls
1106 */
1107
1108int
1109ng_btsocket_hci_raw_ctloutput(struct socket *so, struct sockopt *sopt)
1110{
1111	ng_btsocket_hci_raw_pcb_p		pcb = so2hci_raw_pcb(so);
1112	struct ng_btsocket_hci_raw_filter	filter;
1113	int					error = 0, dir;
1114
1115	if (pcb == NULL)
1116		return (EINVAL);
1117	if (ng_btsocket_hci_raw_node == NULL)
1118		return (EINVAL);
1119
1120	if (sopt->sopt_level != SOL_HCI_RAW)
1121		return (0);
1122
1123	switch (sopt->sopt_dir) {
1124	case SOPT_GET:
1125		switch (sopt->sopt_name) {
1126		case SO_HCI_RAW_FILTER:
1127			error = sooptcopyout(sopt, &pcb->filter,
1128						sizeof(pcb->filter));
1129			break;
1130
1131		case SO_HCI_RAW_DIRECTION:
1132			dir = (pcb->flags & NG_BTSOCKET_HCI_RAW_DIRECTION)?1:0;
1133			error = sooptcopyout(sopt, &dir, sizeof(dir));
1134			break;
1135
1136		default:
1137			error = EINVAL;
1138			break;
1139		}
1140		break;
1141
1142	case SOPT_SET:
1143		switch (sopt->sopt_name) {
1144		case SO_HCI_RAW_FILTER:
1145			error = sooptcopyin(sopt, &filter, sizeof(filter),
1146						sizeof(filter));
1147			if (error == 0)
1148				bcopy(&filter, &pcb->filter,
1149						sizeof(pcb->filter));
1150			break;
1151
1152		case SO_HCI_RAW_DIRECTION:
1153			error = sooptcopyin(sopt, &dir, sizeof(dir),
1154						sizeof(dir));
1155			if (error != 0)
1156				break;
1157
1158			if (dir)
1159				pcb->flags |= NG_BTSOCKET_HCI_RAW_DIRECTION;
1160			else
1161				pcb->flags &= ~NG_BTSOCKET_HCI_RAW_DIRECTION;
1162			break;
1163
1164		default:
1165			error = EINVAL;
1166			break;
1167		}
1168		break;
1169
1170	default:
1171		error = EINVAL;
1172		break;
1173	}
1174
1175	return (error);
1176} /* ng_btsocket_hci_raw_ctloutput */
1177
1178/*
1179 * Detach raw HCI socket
1180 */
1181
1182int
1183ng_btsocket_hci_raw_detach(struct socket *so)
1184{
1185	ng_btsocket_hci_raw_pcb_p	pcb = so2hci_raw_pcb(so);
1186
1187	if (pcb == NULL)
1188		return (EINVAL);
1189	if (ng_btsocket_hci_raw_node == NULL)
1190		return (EINVAL);
1191
1192	so->so_pcb = NULL;
1193	sotryfree(so);
1194
1195	mtx_lock(&ng_btsocket_hci_raw_sockets_mtx);
1196	LIST_REMOVE(pcb, next);
1197	mtx_unlock(&ng_btsocket_hci_raw_sockets_mtx);
1198
1199	bzero(pcb, sizeof(*pcb));
1200	FREE(pcb, M_NETGRAPH_BTSOCKET_HCI_RAW);
1201
1202	return (0);
1203} /* ng_btsocket_hci_raw_detach */
1204
1205/*
1206 * Disconnect raw HCI socket
1207 */
1208
1209int
1210ng_btsocket_hci_raw_disconnect(struct socket *so)
1211{
1212	ng_btsocket_hci_raw_pcb_p	 pcb = so2hci_raw_pcb(so);
1213
1214	if (pcb == NULL)
1215		return (EINVAL);
1216	if (ng_btsocket_hci_raw_node == NULL)
1217		return (EINVAL);
1218
1219	soisdisconnected(so);
1220
1221	return (0);
1222} /* ng_btsocket_hci_raw_disconnect */
1223
1224/*
1225 * Get socket peer's address
1226 */
1227
1228int
1229ng_btsocket_hci_raw_peeraddr(struct socket *so, struct sockaddr **nam)
1230{
1231	return (EOPNOTSUPP);
1232} /* ng_btsocket_hci_raw_peeraddr */
1233
1234/*
1235 * Send data
1236 */
1237
1238int
1239ng_btsocket_hci_raw_send(struct socket *so, int flags, struct mbuf *m,
1240		struct sockaddr *sa, struct mbuf *control, struct thread *td)
1241{
1242	ng_btsocket_hci_raw_pcb_p	 pcb = so2hci_raw_pcb(so);
1243	struct mbuf			*nam = NULL;
1244	int				 error = 0;
1245
1246	if (ng_btsocket_hci_raw_node == NULL) {
1247		error = ENETDOWN;
1248		goto drop;
1249	}
1250	if (pcb == NULL) {
1251		error = EINVAL;
1252		goto drop;
1253	}
1254	if (control != NULL) {
1255		error = EINVAL;
1256		goto drop;
1257	}
1258
1259	if (m->m_pkthdr.len < sizeof(ng_hci_cmd_pkt_t) ||
1260	    m->m_pkthdr.len > sizeof(ng_hci_cmd_pkt_t) + NG_HCI_CMD_PKT_SIZE) {
1261		error = EMSGSIZE;
1262		goto drop;
1263	}
1264
1265	if (sa == NULL) {
1266		if (pcb->addr.hci_node[0] == 0) {
1267			error = EDESTADDRREQ;
1268			goto drop;
1269		}
1270
1271		sa = (struct sockaddr *) &pcb->addr;
1272	}
1273
1274	MGET(nam, 0, MT_SONAME);
1275	if (nam == NULL) {
1276		error = ENOBUFS;
1277		goto drop;
1278	}
1279
1280	nam->m_len = sizeof(struct sockaddr_hci);
1281	bcopy(sa,mtod(nam, struct sockaddr_hci *),sizeof(struct sockaddr_hci));
1282
1283	nam->m_next = m;
1284	m = NULL;
1285
1286	return (ng_send_fn(ng_btsocket_hci_raw_node, NULL,
1287				ng_btsocket_hci_raw_output, nam, 0));
1288drop:
1289	NG_FREE_M(control); /* NG_FREE_M checks for != NULL */
1290	NG_FREE_M(nam);
1291	NG_FREE_M(m);
1292
1293	return (error);
1294} /* ng_btsocket_hci_raw_send */
1295
1296/*
1297 * Get socket address
1298 */
1299
1300int
1301ng_btsocket_hci_raw_sockaddr(struct socket *so, struct sockaddr **nam)
1302{
1303	ng_btsocket_hci_raw_pcb_p	pcb = so2hci_raw_pcb(so);
1304	struct sockaddr_hci		sa;
1305
1306	if (pcb == NULL)
1307		return (EINVAL);
1308	if (ng_btsocket_hci_raw_node == NULL)
1309		return (EINVAL);
1310
1311	bzero(&sa, sizeof(sa));
1312	sa.hci_len = sizeof(sa);
1313	sa.hci_family = AF_BLUETOOTH;
1314	strncpy(sa.hci_node, pcb->addr.hci_node, sizeof(sa.hci_node));
1315
1316	*nam = dup_sockaddr((struct sockaddr *) &sa, 0);
1317
1318	return ((*nam == NULL)? ENOMEM : 0);
1319} /* ng_btsocket_hci_raw_sockaddr */
1320
1321