ng_btsocket_hci_raw.c revision 113255
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 113255 2003-04-08 14:25:47Z des $
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_giant,
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_DONTWAIT, 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_giant,
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, M_WAITOK);
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, M_WAITOK);
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	M_ASSERTPKTHDR(m0);
455
456	sa = mtod(nam, struct sockaddr_hci *);
457
458	mtx_lock(&ng_btsocket_hci_raw_sockets_mtx);
459
460	LIST_FOREACH(pcb, &ng_btsocket_hci_raw_sockets, next) {
461		/*
462		 * If socket was bound then check address and
463		 *  make sure it matches.
464		 */
465
466		if (pcb->addr.hci_node[0] != 0 &&
467		    strcmp(sa->hci_node, pcb->addr.hci_node) != 0)
468			continue;
469
470		/*
471		 * Check packet agains socket filter
472		 * XXX do we have to call m_pullup() here?
473		 */
474
475		switch (*mtod(m0, u_int8_t *)) {
476		case NG_HCI_CMD_PKT:
477		case NG_HCI_ACL_DATA_PKT:
478		case NG_HCI_SCO_DATA_PKT:
479			mask = pcb->filter.packet_mask;
480			bit = *mtod(m0, u_int8_t *) - 1;
481			break;
482
483		case NG_HCI_EVENT_PKT:
484			mask = pcb->filter.event_mask;
485			bit = mtod(m0, ng_hci_event_pkt_t *)->event - 1;
486			break;
487
488		default:
489			KASSERT(0,
490("%s: invalid packet type=%#x\n", __func__, *mtod(m0, u_int8_t *)));
491
492			mask = NULL;
493			bit = 0;
494			break;
495		}
496
497		if (mask == NULL || !bit_test(mask, bit))
498			continue;
499
500		/*
501		 * Make a copy of the packet, append to the socket's
502		 * receive queue and wakeup socket. sbappendaddr()
503		 * will check if socket has enough buffer space.
504		 */
505
506		m = m_dup(m0, M_DONTWAIT);
507		if (m != NULL) {
508			struct mbuf	*ctl = NULL;
509
510			ng_btsocket_hci_raw_savctl(pcb, &ctl, m);
511
512			if (sbappendaddr(&pcb->so->so_rcv,
513					(struct sockaddr *) sa, m, ctl))
514				sorwakeup(pcb->so);
515			else {
516				NG_BTSOCKET_HCI_RAW_WARN(
517"%s: sbappendadd() failed\n", __func__);
518
519				NG_FREE_M(m);
520				NG_FREE_M(ctl);
521			}
522		}
523	}
524
525	mtx_unlock(&ng_btsocket_hci_raw_sockets_mtx);
526
527	NG_FREE_M(nam);
528	NG_FREE_M(m0);
529} /* ng_btsocket_hci_raw_data_input */
530
531/*
532 * Raw HCI sockets message input routine
533 */
534
535static void
536ng_btsocket_hci_raw_msg_input(struct ng_mesg *msg)
537{
538	ng_btsocket_hci_raw_pcb_p	 pcb = NULL;
539
540	if (msg->header.token != 0) {
541		mtx_lock(&ng_btsocket_hci_raw_sockets_mtx);
542
543		LIST_FOREACH(pcb, &ng_btsocket_hci_raw_sockets, next) {
544			if (msg->header.token == pcb->token) {
545				pcb->msg = msg;
546				msg = NULL;
547				wakeup(&pcb->msg);
548				break;
549			}
550		}
551
552		mtx_unlock(&ng_btsocket_hci_raw_sockets_mtx);
553	}
554
555	NG_FREE_MSG(msg); /* checks for != NULL */
556} /* ng_btsocket_hci_raw_msg_input */
557
558/*
559 * Raw HCI sockets input routines
560 */
561
562static void
563ng_btsocket_hci_raw_input(void *context, int pending)
564{
565	item_p	item = NULL;
566
567	for (;;) {
568		mtx_lock(&ng_btsocket_hci_raw_queue_mtx);
569		NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_hci_raw_queue, item);
570		mtx_unlock(&ng_btsocket_hci_raw_queue_mtx);
571
572		if (item == NULL)
573			break;
574
575		switch(item->el_flags & NGQF_TYPE) {
576		case NGQF_DATA: {
577			struct mbuf	*m = NULL;
578
579			NGI_GET_M(item, m);
580			ng_btsocket_hci_raw_data_input(m);
581			} break;
582
583		case NGQF_MESG: {
584			struct ng_mesg	*msg = NULL;
585
586			NGI_GET_MSG(item, msg);
587			ng_btsocket_hci_raw_msg_input(msg);
588			} break;
589
590		default:
591			KASSERT(0,
592("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE)));
593			break;
594		}
595
596		NG_FREE_ITEM(item);
597	}
598} /* ng_btsocket_hci_raw_input */
599
600/*
601 * Raw HCI sockets output routine
602 */
603
604static void
605ng_btsocket_hci_raw_output(node_p node, hook_p hook, void *arg1, int arg2)
606{
607	struct mbuf		*nam = (struct mbuf *) arg1, *m = NULL;
608	struct sockaddr_hci	*sa = NULL;
609	int			 error;
610
611	m = nam->m_next;
612	nam->m_next = NULL;
613
614	KASSERT((nam->m_type == MT_SONAME),
615		("%s: m_type=%d\n", __func__, nam->m_type));
616	M_ASSERTPKTHDR(m);
617
618	sa = mtod(nam, struct sockaddr_hci *);
619
620	/*
621	 * Find downstream hook
622	 * XXX For now access node hook list directly. Should be safe because
623	 * we used ng_send_fn() and we should have exclusive lock on the node.
624	 */
625
626	LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) {
627		if (hook == NULL || NG_HOOK_NOT_VALID(hook) ||
628		    NG_NODE_NOT_VALID(NG_PEER_NODE(hook)))
629			continue;
630
631		if (strcmp(sa->hci_node, NG_PEER_NODE_NAME(hook)) == 0) {
632			NG_SEND_DATA_ONLY(error, hook, m); /* sets m to NULL */
633			break;
634		}
635	}
636
637	NG_FREE_M(nam); /* check for != NULL */
638	NG_FREE_M(m);
639} /* ng_btsocket_hci_raw_output */
640
641/*
642 * Initialize everything
643 */
644
645void
646ng_btsocket_hci_raw_init(void)
647{
648	int	error = 0;
649
650	ng_btsocket_hci_raw_node = NULL;
651	ng_btsocket_hci_raw_debug_level = NG_BTSOCKET_WARN_LEVEL;
652	ng_btsocket_hci_raw_ioctl_timeout = 5;
653
654	/* Register Netgraph node type */
655	error = ng_newtype(&typestruct);
656	if (error != 0) {
657		NG_BTSOCKET_HCI_RAW_ALERT(
658"%s: Could not register Netgraph node type, error=%d\n", __func__, error);
659
660		return;
661	}
662
663	/* Create Netgrapg node */
664	error = ng_make_node_common(&typestruct, &ng_btsocket_hci_raw_node);
665	if (error != 0) {
666		NG_BTSOCKET_HCI_RAW_ALERT(
667"%s: Could not create Netgraph node, error=%d\n", __func__, error);
668
669		ng_btsocket_hci_raw_node = NULL;
670
671		return;
672        }
673
674	error = ng_name_node(ng_btsocket_hci_raw_node,
675				NG_BTSOCKET_HCI_RAW_NODE_TYPE);
676	if (error != 0) {
677		NG_BTSOCKET_HCI_RAW_ALERT(
678"%s: Could not name Netgraph node, error=%d\n", __func__, error);
679
680		NG_NODE_UNREF(ng_btsocket_hci_raw_node);
681		ng_btsocket_hci_raw_node = NULL;
682
683		return;
684	}
685
686	/* Create input queue */
687	NG_BT_ITEMQ_INIT(&ng_btsocket_hci_raw_queue, ifqmaxlen);
688	mtx_init(&ng_btsocket_hci_raw_queue_mtx,
689		"btsocks_hci_raw_queue_mtx", NULL, MTX_DEF);
690	TASK_INIT(&ng_btsocket_hci_raw_task, 0,
691		ng_btsocket_hci_raw_input, NULL);
692
693	/* Create list of sockets */
694	LIST_INIT(&ng_btsocket_hci_raw_sockets);
695	mtx_init(&ng_btsocket_hci_raw_sockets_mtx,
696		"btsocks_hci_raw_sockets_mtx", NULL, MTX_DEF);
697
698	/* Tokens */
699	ng_btsocket_hci_raw_token = 0;
700	mtx_init(&ng_btsocket_hci_raw_token_mtx,
701		"btsocks_hci_raw_token_mtx", NULL, MTX_DEF);
702} /* ng_btsocket_hci_raw_init */
703
704/*
705 * Abort connection on socket
706 */
707
708int
709ng_btsocket_hci_raw_abort(struct socket *so)
710{
711	soisdisconnected(so);
712
713	return (ng_btsocket_hci_raw_detach(so));
714} /* ng_btsocket_hci_raw_abort */
715
716/*
717 * Create new raw HCI socket
718 */
719
720int
721ng_btsocket_hci_raw_attach(struct socket *so, int proto, struct thread *td)
722{
723	ng_btsocket_hci_raw_pcb_p	pcb = so2hci_raw_pcb(so);
724	int				error = 0;
725
726	if (pcb != NULL)
727		return (EISCONN);
728
729	if (ng_btsocket_hci_raw_node == NULL)
730		return (EPROTONOSUPPORT);
731	if (proto != BLUETOOTH_PROTO_HCI)
732		return (EPROTONOSUPPORT);
733	if (so->so_type != SOCK_RAW)
734		return (ESOCKTNOSUPPORT);
735	if ((error = suser(td)) != 0)
736		return (error);
737
738	error = soreserve(so, NG_BTSOCKET_HCI_RAW_SENDSPACE,
739				NG_BTSOCKET_HCI_RAW_RECVSPACE);
740	if (error != 0)
741		return (error);
742
743	MALLOC(pcb, ng_btsocket_hci_raw_pcb_p, sizeof(*pcb),
744		M_NETGRAPH_BTSOCKET_HCI_RAW, M_WAITOK | M_ZERO);
745	if (pcb == NULL)
746		return (ENOMEM);
747
748	so->so_pcb = (caddr_t) pcb;
749	pcb->so = so;
750
751	/*
752	 * Set default socket filter. By default socket only accepts HCI
753	 * Command_Complete and Command_Status event packets.
754	 */
755
756	bit_set(pcb->filter.event_mask, NG_HCI_EVENT_COMMAND_COMPL - 1);
757	bit_set(pcb->filter.event_mask, NG_HCI_EVENT_COMMAND_STATUS - 1);
758
759	mtx_lock(&ng_btsocket_hci_raw_sockets_mtx);
760	LIST_INSERT_HEAD(&ng_btsocket_hci_raw_sockets, pcb, next);
761	mtx_unlock(&ng_btsocket_hci_raw_sockets_mtx);
762
763	return (0);
764} /* ng_btsocket_hci_raw_attach */
765
766/*
767 * Bind raw HCI socket
768 */
769
770int
771ng_btsocket_hci_raw_bind(struct socket *so, struct sockaddr *nam,
772		struct thread *td)
773{
774	ng_btsocket_hci_raw_pcb_p	 pcb = so2hci_raw_pcb(so);
775	struct sockaddr_hci		*sa = (struct sockaddr_hci *) nam;
776
777	if (pcb == NULL)
778		return (EINVAL);
779	if (ng_btsocket_hci_raw_node == NULL)
780		return (EINVAL);
781
782	if (sa == NULL)
783		return (EINVAL);
784	if (sa->hci_family != AF_BLUETOOTH)
785		return (EAFNOSUPPORT);
786	if (sa->hci_len != sizeof(*sa))
787		return (EINVAL);
788	if (sa->hci_node[0] == 0)
789		return (EINVAL);
790
791	bcopy(sa, &pcb->addr, sizeof(pcb->addr));
792
793	return (0);
794} /* ng_btsocket_hci_raw_bind */
795
796/*
797 * Connect raw HCI socket
798 */
799
800int
801ng_btsocket_hci_raw_connect(struct socket *so, struct sockaddr *nam,
802		struct thread *td)
803{
804	ng_btsocket_hci_raw_pcb_p	 pcb = so2hci_raw_pcb(so);
805	struct sockaddr_hci		*sa = (struct sockaddr_hci *) nam;
806
807	if (pcb == NULL)
808		return (EINVAL);
809	if (ng_btsocket_hci_raw_node == NULL)
810		return (EINVAL);
811
812	if (sa == NULL)
813		return (EINVAL);
814	if (sa->hci_family != AF_BLUETOOTH)
815		return (EAFNOSUPPORT);
816	if (sa->hci_len != sizeof(*sa))
817		return (EINVAL);
818	if (sa->hci_node[0] == 0)
819		return (EDESTADDRREQ);
820	if (bcmp(sa, &pcb->addr, sizeof(pcb->addr)) != 0)
821		return (EADDRNOTAVAIL);
822
823	soisconnected(so);
824
825	return (0);
826} /* ng_btsocket_hci_raw_connect */
827
828/*
829 * Process ioctl on socket
830 */
831
832int
833ng_btsocket_hci_raw_control(struct socket *so, u_long cmd, caddr_t data,
834		struct ifnet *ifp, struct thread *td)
835{
836	ng_btsocket_hci_raw_pcb_p	 pcb = so2hci_raw_pcb(so);
837	char				 path[NG_NODELEN + 2],
838					*hci_node = (char *) data;
839	struct ng_mesg			*msg = NULL;
840	int				 error = 0;
841
842	if (pcb == NULL)
843		return (EINVAL);
844	if (ng_btsocket_hci_raw_node == NULL)
845		return (EINVAL);
846
847	/*
848	 * Make sure caller has provided HCI node name, if not try to
849	 * use addr from socket (if socket was bound)
850	 */
851
852	if (hci_node[0] == 0) {
853		if (pcb->addr.hci_node[0] == 0)
854			return (EINVAL);
855
856		bzero(hci_node, sizeof(pcb->addr.hci_node));
857		strncpy(hci_node,pcb->addr.hci_node,sizeof(pcb->addr.hci_node));
858	}
859
860	snprintf(path, sizeof(path), "%s:", hci_node);
861
862	switch (cmd) {
863	case SIOC_HCI_RAW_NODE_GET_STATE: {
864		struct ng_btsocket_hci_raw_node_state	*p =
865			(struct ng_btsocket_hci_raw_node_state *) data;
866
867		error = ng_btsocket_raw_send_sync_ngmsg(pcb, path,
868				NGM_HCI_NODE_GET_STATE,
869				&p->state, sizeof(p->state));
870		} break;
871
872	case SIOC_HCI_RAW_NODE_INIT:
873		error = ng_btsocket_raw_send_ngmsg(path, NGM_HCI_NODE_INIT,
874				NULL, 0);
875		break;
876
877	case SIOC_HCI_RAW_NODE_GET_DEBUG: {
878		struct ng_btsocket_hci_raw_node_debug	*p =
879			(struct ng_btsocket_hci_raw_node_debug *) data;
880
881		error = ng_btsocket_raw_send_sync_ngmsg(pcb, path,
882				NGM_HCI_NODE_GET_DEBUG,
883				&p->debug, sizeof(p->debug));
884		} break;
885
886	case SIOC_HCI_RAW_NODE_SET_DEBUG: {
887		struct ng_btsocket_hci_raw_node_debug	*p =
888			(struct ng_btsocket_hci_raw_node_debug *) data;
889
890		error = ng_btsocket_raw_send_ngmsg(path, NGM_HCI_NODE_SET_DEBUG,
891				&p->debug, sizeof(p->debug));
892		} break;
893
894	case SIOC_HCI_RAW_NODE_GET_BUFFER: {
895		struct ng_btsocket_hci_raw_node_buffer	*p =
896			(struct ng_btsocket_hci_raw_node_buffer *) data;
897
898		error = ng_btsocket_raw_send_sync_ngmsg(pcb, path,
899				NGM_HCI_NODE_GET_BUFFER,
900				&p->buffer, sizeof(p->buffer));
901		} break;
902
903	case SIOC_HCI_RAW_NODE_GET_BDADDR: {
904		struct ng_btsocket_hci_raw_node_bdaddr	*p =
905			(struct ng_btsocket_hci_raw_node_bdaddr *) data;
906
907		error = ng_btsocket_raw_send_sync_ngmsg(pcb, path,
908				NGM_HCI_NODE_GET_BDADDR,
909				&p->bdaddr, sizeof(p->bdaddr));
910		} break;
911
912	case SIOC_HCI_RAW_NODE_GET_FEATURES: {
913		struct ng_btsocket_hci_raw_node_features	*p =
914			(struct ng_btsocket_hci_raw_node_features *) data;
915
916		error = ng_btsocket_raw_send_sync_ngmsg(pcb, path,
917				NGM_HCI_NODE_GET_FEATURES,
918				&p->features, sizeof(p->features));
919		} break;
920
921	case SIOC_HCI_RAW_NODE_GET_STAT: {
922		struct ng_btsocket_hci_raw_node_stat	*p =
923			(struct ng_btsocket_hci_raw_node_stat *) data;
924
925		error = ng_btsocket_raw_send_sync_ngmsg(pcb, path,
926				NGM_HCI_NODE_GET_STAT,
927				&p->stat, sizeof(p->stat));
928		} break;
929
930	case SIOC_HCI_RAW_NODE_RESET_STAT:
931		error = ng_btsocket_raw_send_ngmsg(path,
932				NGM_HCI_NODE_RESET_STAT, NULL, 0);
933		break;
934
935	case SIOC_HCI_RAW_NODE_FLUSH_NEIGHBOR_CACHE:
936		error = ng_btsocket_raw_send_ngmsg(path,
937				NGM_HCI_NODE_FLUSH_NEIGHBOR_CACHE, NULL, 0);
938		break;
939
940	case SIOC_HCI_RAW_NODE_GET_NEIGHBOR_CACHE:  {
941		struct ng_btsocket_hci_raw_node_neighbor_cache	*p =
942			(struct ng_btsocket_hci_raw_node_neighbor_cache *) data;
943		ng_hci_node_get_neighbor_cache_ep		*p1 = NULL;
944		ng_hci_node_neighbor_cache_entry_ep		*p2 = NULL;
945
946		if (p->num_entries <= 0 ||
947		    p->num_entries > NG_HCI_MAX_NEIGHBOR_NUM ||
948		    p->entries == NULL) {
949			error = EINVAL;
950			break;
951		}
952
953		ng_btsocket_hci_raw_get_token(&pcb->token);
954		pcb->msg = NULL;
955
956		NG_MKMESSAGE(msg, NGM_HCI_COOKIE,
957			NGM_HCI_NODE_GET_NEIGHBOR_CACHE, 0, M_WAITOK);
958		if (msg == NULL) {
959			pcb->token = 0;
960			error = ENOMEM;
961			break;
962		}
963		msg->header.token = pcb->token;
964
965		NG_SEND_MSG_PATH(error,ng_btsocket_hci_raw_node,msg,path,NULL);
966		if (error != 0) {
967			pcb->token = 0;
968			break;
969		}
970
971		error = tsleep(&pcb->msg, PZERO|PCATCH, "hcictl",
972				ng_btsocket_hci_raw_ioctl_timeout * hz);
973		if (error != 0) {
974			pcb->token = 0;
975			break;
976		}
977
978		if (pcb->msg != NULL &&
979		    pcb->msg->header.cmd == NGM_HCI_NODE_GET_NEIGHBOR_CACHE) {
980			/* Return data back to user space */
981			p1 = (ng_hci_node_get_neighbor_cache_ep *)
982				(pcb->msg->data);
983			p2 = (ng_hci_node_neighbor_cache_entry_ep *)
984				(p1 + 1);
985
986			p->num_entries = min(p->num_entries, p1->num_entries);
987			if (p->num_entries > 0)
988				error = copyout((caddr_t) p2,
989						(caddr_t) p->entries,
990						p->num_entries * sizeof(*p2));
991		} else
992			error = EINVAL;
993
994		NG_FREE_MSG(pcb->msg); /* checks for != NULL */
995		pcb->token = 0;
996		}break;
997
998	case SIOC_HCI_RAW_NODE_GET_CON_LIST: {
999		struct ng_btsocket_hci_raw_con_list	*p =
1000			(struct ng_btsocket_hci_raw_con_list *) data;
1001		ng_hci_node_con_list_ep			*p1 = NULL;
1002		ng_hci_node_con_ep			*p2 = NULL;
1003
1004		if (p->num_connections == 0 ||
1005		    p->num_connections > NG_HCI_MAX_CON_NUM ||
1006		    p->connections == NULL) {
1007			error = EINVAL;
1008			break;
1009		}
1010
1011		ng_btsocket_hci_raw_get_token(&pcb->token);
1012		pcb->msg = NULL;
1013
1014		NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_NODE_GET_CON_LIST,
1015			0, M_WAITOK);
1016		if (msg == NULL) {
1017			pcb->token = 0;
1018			error = ENOMEM;
1019			break;
1020		}
1021		msg->header.token = pcb->token;
1022
1023		NG_SEND_MSG_PATH(error,ng_btsocket_hci_raw_node,msg,path,NULL);
1024		if (error != 0) {
1025			pcb->token = 0;
1026			break;
1027		}
1028
1029		error = tsleep(&pcb->msg, PZERO|PCATCH, "hcictl",
1030				ng_btsocket_hci_raw_ioctl_timeout * hz);
1031		if (error != 0) {
1032			pcb->token = 0;
1033			break;
1034		}
1035
1036		if (pcb->msg != NULL &&
1037		    pcb->msg->header.cmd == NGM_HCI_NODE_GET_CON_LIST) {
1038			/* Return data back to user space */
1039			p1 = (ng_hci_node_con_list_ep *)(pcb->msg->data);
1040			p2 = (ng_hci_node_con_ep *)(p1 + 1);
1041
1042			p->num_connections = min(p->num_connections,
1043						p1->num_connections);
1044			if (p->num_connections > 0)
1045				error = copyout((caddr_t) p2,
1046					(caddr_t) p->connections,
1047					p->num_connections * sizeof(*p2));
1048		} else
1049			error = EINVAL;
1050
1051		NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1052		pcb->token = 0;
1053		} break;
1054
1055	case SIOC_HCI_RAW_NODE_GET_LINK_POLICY_MASK: {
1056		struct ng_btsocket_hci_raw_node_link_policy_mask	*p =
1057			(struct ng_btsocket_hci_raw_node_link_policy_mask *)
1058				data;
1059
1060		error = ng_btsocket_raw_send_sync_ngmsg(pcb, path,
1061				NGM_HCI_NODE_GET_LINK_POLICY_SETTINGS_MASK,
1062				&p->policy_mask, sizeof(p->policy_mask));
1063		} break;
1064
1065	case SIOC_HCI_RAW_NODE_SET_LINK_POLICY_MASK: {
1066		struct ng_btsocket_hci_raw_node_link_policy_mask	*p =
1067			(struct ng_btsocket_hci_raw_node_link_policy_mask *)
1068				data;
1069
1070		error = ng_btsocket_raw_send_ngmsg(path,
1071				NGM_HCI_NODE_SET_LINK_POLICY_SETTINGS_MASK,
1072				&p->policy_mask, sizeof(p->policy_mask));
1073		} break;
1074
1075	case SIOC_HCI_RAW_NODE_GET_PACKET_MASK: {
1076		struct ng_btsocket_hci_raw_node_packet_mask	*p =
1077			(struct ng_btsocket_hci_raw_node_packet_mask *) data;
1078
1079		error = ng_btsocket_raw_send_sync_ngmsg(pcb, path,
1080				NGM_HCI_NODE_GET_PACKET_MASK,
1081				&p->packet_mask, sizeof(p->packet_mask));
1082		} break;
1083
1084	case SIOC_HCI_RAW_NODE_SET_PACKET_MASK: {
1085		struct ng_btsocket_hci_raw_node_packet_mask	*p =
1086			(struct ng_btsocket_hci_raw_node_packet_mask *) data;
1087
1088		error = ng_btsocket_raw_send_ngmsg(path,
1089				NGM_HCI_NODE_SET_PACKET_MASK,
1090				&p->packet_mask, sizeof(p->packet_mask));
1091
1092		} break;
1093
1094	default:
1095		error = EINVAL;
1096		break;
1097	}
1098
1099	return (error);
1100} /* ng_btsocket_hci_raw_control */
1101
1102/*
1103 * Process getsockopt/setsockopt system calls
1104 */
1105
1106int
1107ng_btsocket_hci_raw_ctloutput(struct socket *so, struct sockopt *sopt)
1108{
1109	ng_btsocket_hci_raw_pcb_p		pcb = so2hci_raw_pcb(so);
1110	struct ng_btsocket_hci_raw_filter	filter;
1111	int					error = 0, dir;
1112
1113	if (pcb == NULL)
1114		return (EINVAL);
1115	if (ng_btsocket_hci_raw_node == NULL)
1116		return (EINVAL);
1117
1118	if (sopt->sopt_level != SOL_HCI_RAW)
1119		return (0);
1120
1121	switch (sopt->sopt_dir) {
1122	case SOPT_GET:
1123		switch (sopt->sopt_name) {
1124		case SO_HCI_RAW_FILTER:
1125			error = sooptcopyout(sopt, &pcb->filter,
1126						sizeof(pcb->filter));
1127			break;
1128
1129		case SO_HCI_RAW_DIRECTION:
1130			dir = (pcb->flags & NG_BTSOCKET_HCI_RAW_DIRECTION)?1:0;
1131			error = sooptcopyout(sopt, &dir, sizeof(dir));
1132			break;
1133
1134		default:
1135			error = EINVAL;
1136			break;
1137		}
1138		break;
1139
1140	case SOPT_SET:
1141		switch (sopt->sopt_name) {
1142		case SO_HCI_RAW_FILTER:
1143			error = sooptcopyin(sopt, &filter, sizeof(filter),
1144						sizeof(filter));
1145			if (error == 0)
1146				bcopy(&filter, &pcb->filter,
1147						sizeof(pcb->filter));
1148			break;
1149
1150		case SO_HCI_RAW_DIRECTION:
1151			error = sooptcopyin(sopt, &dir, sizeof(dir),
1152						sizeof(dir));
1153			if (error != 0)
1154				break;
1155
1156			if (dir)
1157				pcb->flags |= NG_BTSOCKET_HCI_RAW_DIRECTION;
1158			else
1159				pcb->flags &= ~NG_BTSOCKET_HCI_RAW_DIRECTION;
1160			break;
1161
1162		default:
1163			error = EINVAL;
1164			break;
1165		}
1166		break;
1167
1168	default:
1169		error = EINVAL;
1170		break;
1171	}
1172
1173	return (error);
1174} /* ng_btsocket_hci_raw_ctloutput */
1175
1176/*
1177 * Detach raw HCI socket
1178 */
1179
1180int
1181ng_btsocket_hci_raw_detach(struct socket *so)
1182{
1183	ng_btsocket_hci_raw_pcb_p	pcb = so2hci_raw_pcb(so);
1184
1185	if (pcb == NULL)
1186		return (EINVAL);
1187	if (ng_btsocket_hci_raw_node == NULL)
1188		return (EINVAL);
1189
1190	so->so_pcb = NULL;
1191	sotryfree(so);
1192
1193	mtx_lock(&ng_btsocket_hci_raw_sockets_mtx);
1194	LIST_REMOVE(pcb, next);
1195	mtx_unlock(&ng_btsocket_hci_raw_sockets_mtx);
1196
1197	bzero(pcb, sizeof(*pcb));
1198	FREE(pcb, M_NETGRAPH_BTSOCKET_HCI_RAW);
1199
1200	return (0);
1201} /* ng_btsocket_hci_raw_detach */
1202
1203/*
1204 * Disconnect raw HCI socket
1205 */
1206
1207int
1208ng_btsocket_hci_raw_disconnect(struct socket *so)
1209{
1210	ng_btsocket_hci_raw_pcb_p	 pcb = so2hci_raw_pcb(so);
1211
1212	if (pcb == NULL)
1213		return (EINVAL);
1214	if (ng_btsocket_hci_raw_node == NULL)
1215		return (EINVAL);
1216
1217	soisdisconnected(so);
1218
1219	return (0);
1220} /* ng_btsocket_hci_raw_disconnect */
1221
1222/*
1223 * Get socket peer's address
1224 */
1225
1226int
1227ng_btsocket_hci_raw_peeraddr(struct socket *so, struct sockaddr **nam)
1228{
1229	return (EOPNOTSUPP);
1230} /* ng_btsocket_hci_raw_peeraddr */
1231
1232/*
1233 * Send data
1234 */
1235
1236int
1237ng_btsocket_hci_raw_send(struct socket *so, int flags, struct mbuf *m,
1238		struct sockaddr *sa, struct mbuf *control, struct thread *td)
1239{
1240	ng_btsocket_hci_raw_pcb_p	 pcb = so2hci_raw_pcb(so);
1241	struct mbuf			*nam = NULL;
1242	int				 error = 0;
1243
1244	if (ng_btsocket_hci_raw_node == NULL) {
1245		error = ENETDOWN;
1246		goto drop;
1247	}
1248	if (pcb == NULL) {
1249		error = EINVAL;
1250		goto drop;
1251	}
1252	if (control != NULL) {
1253		error = EINVAL;
1254		goto drop;
1255	}
1256
1257	if (m->m_pkthdr.len < sizeof(ng_hci_cmd_pkt_t) ||
1258	    m->m_pkthdr.len > sizeof(ng_hci_cmd_pkt_t) + NG_HCI_CMD_PKT_SIZE) {
1259		error = EMSGSIZE;
1260		goto drop;
1261	}
1262
1263	if (sa == NULL) {
1264		if (pcb->addr.hci_node[0] == 0) {
1265			error = EDESTADDRREQ;
1266			goto drop;
1267		}
1268
1269		sa = (struct sockaddr *) &pcb->addr;
1270	}
1271
1272	MGET(nam, M_TRYWAIT, MT_SONAME);
1273	if (nam == NULL) {
1274		error = ENOBUFS;
1275		goto drop;
1276	}
1277
1278	nam->m_len = sizeof(struct sockaddr_hci);
1279	bcopy(sa,mtod(nam, struct sockaddr_hci *),sizeof(struct sockaddr_hci));
1280
1281	nam->m_next = m;
1282	m = NULL;
1283
1284	return (ng_send_fn(ng_btsocket_hci_raw_node, NULL,
1285				ng_btsocket_hci_raw_output, nam, 0));
1286drop:
1287	NG_FREE_M(control); /* NG_FREE_M checks for != NULL */
1288	NG_FREE_M(nam);
1289	NG_FREE_M(m);
1290
1291	return (error);
1292} /* ng_btsocket_hci_raw_send */
1293
1294/*
1295 * Get socket address
1296 */
1297
1298int
1299ng_btsocket_hci_raw_sockaddr(struct socket *so, struct sockaddr **nam)
1300{
1301	ng_btsocket_hci_raw_pcb_p	pcb = so2hci_raw_pcb(so);
1302	struct sockaddr_hci		sa;
1303
1304	if (pcb == NULL)
1305		return (EINVAL);
1306	if (ng_btsocket_hci_raw_node == NULL)
1307		return (EINVAL);
1308
1309	bzero(&sa, sizeof(sa));
1310	sa.hci_len = sizeof(sa);
1311	sa.hci_family = AF_BLUETOOTH;
1312	strncpy(sa.hci_node, pcb->addr.hci_node, sizeof(sa.hci_node));
1313
1314	*nam = dup_sockaddr((struct sockaddr *) &sa, 0);
1315
1316	return ((*nam == NULL)? ENOMEM : 0);
1317} /* ng_btsocket_hci_raw_sockaddr */
1318
1319