Deleted Added
full compact
ng_btsocket_hci_raw.c (107120) ng_btsocket_hci_raw.c (108107)
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 $
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 107120 2002-11-20 23:01:59Z julian $
29 * $FreeBSD: head/sys/netgraph/bluetooth/socket/ng_btsocket_hci_raw.c 108107 2002-12-19 22:58:27Z bmilekic $
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_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,
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 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_DONTWAIT);
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_WAITOK | 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, M_WAITOK);
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, M_WAITOK);
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
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_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,
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 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_DONTWAIT);
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_WAITOK | 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, M_WAITOK);
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, M_WAITOK);
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, M_WAITOK, MT_SONAME);
1274 MGET(nam, M_TRYWAIT, 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
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