Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/netgraph/bluetooth/socket/ng_btsocket_hci_raw.c
34677 views
1
/*
2
* ng_btsocket_hci_raw.c
3
*/
4
5
/*-
6
* SPDX-License-Identifier: BSD-2-Clause
7
*
8
* Copyright (c) 2001-2002 Maksim Yevmenkin <[email protected]>
9
* All rights reserved.
10
*
11
* Redistribution and use in source and binary forms, with or without
12
* modification, are permitted provided that the following conditions
13
* are met:
14
* 1. Redistributions of source code must retain the above copyright
15
* notice, this list of conditions and the following disclaimer.
16
* 2. Redistributions in binary form must reproduce the above copyright
17
* notice, this list of conditions and the following disclaimer in the
18
* documentation and/or other materials provided with the distribution.
19
*
20
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
* SUCH DAMAGE.
31
*
32
* $Id: ng_btsocket_hci_raw.c,v 1.14 2003/09/14 23:29:06 max Exp $
33
*/
34
35
#include <sys/param.h>
36
#include <sys/systm.h>
37
#include <sys/bitstring.h>
38
#include <sys/domain.h>
39
#include <sys/endian.h>
40
#include <sys/errno.h>
41
#include <sys/filedesc.h>
42
#include <sys/ioccom.h>
43
#include <sys/kernel.h>
44
#include <sys/lock.h>
45
#include <sys/malloc.h>
46
#include <sys/mbuf.h>
47
#include <sys/mutex.h>
48
#include <sys/priv.h>
49
#include <sys/protosw.h>
50
#include <sys/queue.h>
51
#include <sys/socket.h>
52
#include <sys/socketvar.h>
53
#include <sys/sysctl.h>
54
#include <sys/taskqueue.h>
55
56
#include <net/vnet.h>
57
58
#include <netgraph/ng_message.h>
59
#include <netgraph/netgraph.h>
60
#include <netgraph/bluetooth/include/ng_bluetooth.h>
61
#include <netgraph/bluetooth/include/ng_hci.h>
62
#include <netgraph/bluetooth/include/ng_l2cap.h>
63
#include <netgraph/bluetooth/include/ng_btsocket.h>
64
#include <netgraph/bluetooth/include/ng_btsocket_hci_raw.h>
65
66
/* MALLOC define */
67
#ifdef NG_SEPARATE_MALLOC
68
static MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_HCI_RAW, "netgraph_btsocks_hci_raw",
69
"Netgraph Bluetooth raw HCI sockets");
70
#else
71
#define M_NETGRAPH_BTSOCKET_HCI_RAW M_NETGRAPH
72
#endif /* NG_SEPARATE_MALLOC */
73
74
/* Netgraph node methods */
75
static ng_constructor_t ng_btsocket_hci_raw_node_constructor;
76
static ng_rcvmsg_t ng_btsocket_hci_raw_node_rcvmsg;
77
static ng_shutdown_t ng_btsocket_hci_raw_node_shutdown;
78
static ng_newhook_t ng_btsocket_hci_raw_node_newhook;
79
static ng_connect_t ng_btsocket_hci_raw_node_connect;
80
static ng_rcvdata_t ng_btsocket_hci_raw_node_rcvdata;
81
static ng_disconnect_t ng_btsocket_hci_raw_node_disconnect;
82
83
static void ng_btsocket_hci_raw_input (void *, int);
84
static void ng_btsocket_hci_raw_output(node_p, hook_p, void *, int);
85
static void ng_btsocket_hci_raw_savctl(ng_btsocket_hci_raw_pcb_p,
86
struct mbuf **,
87
struct mbuf *);
88
static int ng_btsocket_hci_raw_filter(ng_btsocket_hci_raw_pcb_p,
89
struct mbuf *, int);
90
91
#define ng_btsocket_hci_raw_wakeup_input_task() \
92
taskqueue_enqueue(taskqueue_swi, &ng_btsocket_hci_raw_task)
93
94
/* Security filter */
95
struct ng_btsocket_hci_raw_sec_filter {
96
bitstr_t bit_decl(events, 0xff);
97
bitstr_t bit_decl(commands[0x3f], 0x3ff);
98
};
99
100
/* Netgraph type descriptor */
101
static struct ng_type typestruct = {
102
.version = NG_ABI_VERSION,
103
.name = NG_BTSOCKET_HCI_RAW_NODE_TYPE,
104
.constructor = ng_btsocket_hci_raw_node_constructor,
105
.rcvmsg = ng_btsocket_hci_raw_node_rcvmsg,
106
.shutdown = ng_btsocket_hci_raw_node_shutdown,
107
.newhook = ng_btsocket_hci_raw_node_newhook,
108
.connect = ng_btsocket_hci_raw_node_connect,
109
.rcvdata = ng_btsocket_hci_raw_node_rcvdata,
110
.disconnect = ng_btsocket_hci_raw_node_disconnect,
111
};
112
113
/* Globals */
114
static u_int32_t ng_btsocket_hci_raw_debug_level;
115
static u_int32_t ng_btsocket_hci_raw_ioctl_timeout;
116
static node_p ng_btsocket_hci_raw_node;
117
static struct ng_bt_itemq ng_btsocket_hci_raw_queue;
118
static struct mtx ng_btsocket_hci_raw_queue_mtx;
119
static struct task ng_btsocket_hci_raw_task;
120
static LIST_HEAD(, ng_btsocket_hci_raw_pcb) ng_btsocket_hci_raw_sockets;
121
static struct mtx ng_btsocket_hci_raw_sockets_mtx;
122
static u_int32_t ng_btsocket_hci_raw_token;
123
static struct mtx ng_btsocket_hci_raw_token_mtx;
124
static struct ng_btsocket_hci_raw_sec_filter *ng_btsocket_hci_raw_sec_filter;
125
static struct timeval ng_btsocket_hci_raw_lasttime;
126
static int ng_btsocket_hci_raw_curpps;
127
128
/* Sysctl tree */
129
SYSCTL_DECL(_net_bluetooth_hci_sockets);
130
static SYSCTL_NODE(_net_bluetooth_hci_sockets, OID_AUTO, raw,
131
CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
132
"Bluetooth raw HCI sockets family");
133
SYSCTL_UINT(_net_bluetooth_hci_sockets_raw, OID_AUTO, debug_level, CTLFLAG_RW,
134
&ng_btsocket_hci_raw_debug_level, NG_BTSOCKET_WARN_LEVEL,
135
"Bluetooth raw HCI sockets debug level");
136
SYSCTL_UINT(_net_bluetooth_hci_sockets_raw, OID_AUTO, ioctl_timeout, CTLFLAG_RW,
137
&ng_btsocket_hci_raw_ioctl_timeout, 5,
138
"Bluetooth raw HCI sockets ioctl timeout");
139
SYSCTL_UINT(_net_bluetooth_hci_sockets_raw, OID_AUTO, queue_len, CTLFLAG_RD,
140
&ng_btsocket_hci_raw_queue.len, 0,
141
"Bluetooth raw HCI sockets input queue length");
142
SYSCTL_UINT(_net_bluetooth_hci_sockets_raw, OID_AUTO, queue_maxlen, CTLFLAG_RD,
143
&ng_btsocket_hci_raw_queue.maxlen, 0,
144
"Bluetooth raw HCI sockets input queue max. length");
145
SYSCTL_UINT(_net_bluetooth_hci_sockets_raw, OID_AUTO, queue_drops, CTLFLAG_RD,
146
&ng_btsocket_hci_raw_queue.drops, 0,
147
"Bluetooth raw HCI sockets input queue drops");
148
149
/* Debug */
150
#define NG_BTSOCKET_HCI_RAW_INFO \
151
if (ng_btsocket_hci_raw_debug_level >= NG_BTSOCKET_INFO_LEVEL && \
152
ppsratecheck(&ng_btsocket_hci_raw_lasttime, &ng_btsocket_hci_raw_curpps, 1)) \
153
printf
154
155
#define NG_BTSOCKET_HCI_RAW_WARN \
156
if (ng_btsocket_hci_raw_debug_level >= NG_BTSOCKET_WARN_LEVEL && \
157
ppsratecheck(&ng_btsocket_hci_raw_lasttime, &ng_btsocket_hci_raw_curpps, 1)) \
158
printf
159
160
#define NG_BTSOCKET_HCI_RAW_ERR \
161
if (ng_btsocket_hci_raw_debug_level >= NG_BTSOCKET_ERR_LEVEL && \
162
ppsratecheck(&ng_btsocket_hci_raw_lasttime, &ng_btsocket_hci_raw_curpps, 1)) \
163
printf
164
165
#define NG_BTSOCKET_HCI_RAW_ALERT \
166
if (ng_btsocket_hci_raw_debug_level >= NG_BTSOCKET_ALERT_LEVEL && \
167
ppsratecheck(&ng_btsocket_hci_raw_lasttime, &ng_btsocket_hci_raw_curpps, 1)) \
168
printf
169
170
/****************************************************************************
171
****************************************************************************
172
** Netgraph specific
173
****************************************************************************
174
****************************************************************************/
175
176
/*
177
* Netgraph node constructor. Do not allow to create node of this type.
178
*/
179
180
static int
181
ng_btsocket_hci_raw_node_constructor(node_p node)
182
{
183
return (EINVAL);
184
} /* ng_btsocket_hci_raw_node_constructor */
185
186
/*
187
* Netgraph node destructor. Just let old node go and create new fresh one.
188
*/
189
190
static int
191
ng_btsocket_hci_raw_node_shutdown(node_p node)
192
{
193
int error = 0;
194
195
NG_NODE_UNREF(node);
196
197
error = ng_make_node_common(&typestruct, &ng_btsocket_hci_raw_node);
198
if (error != 0) {
199
NG_BTSOCKET_HCI_RAW_ALERT(
200
"%s: Could not create Netgraph node, error=%d\n", __func__, error);
201
202
ng_btsocket_hci_raw_node = NULL;
203
204
return (ENOMEM);
205
}
206
207
error = ng_name_node(ng_btsocket_hci_raw_node,
208
NG_BTSOCKET_HCI_RAW_NODE_TYPE);
209
if (error != 0) {
210
NG_BTSOCKET_HCI_RAW_ALERT(
211
"%s: Could not name Netgraph node, error=%d\n", __func__, error);
212
213
NG_NODE_UNREF(ng_btsocket_hci_raw_node);
214
ng_btsocket_hci_raw_node = NULL;
215
216
return (EINVAL);
217
}
218
219
return (0);
220
} /* ng_btsocket_hci_raw_node_shutdown */
221
222
/*
223
* Create new hook. Just say "yes"
224
*/
225
226
static int
227
ng_btsocket_hci_raw_node_newhook(node_p node, hook_p hook, char const *name)
228
{
229
return (0);
230
} /* ng_btsocket_hci_raw_node_newhook */
231
232
/*
233
* Connect hook. Just say "yes"
234
*/
235
236
static int
237
ng_btsocket_hci_raw_node_connect(hook_p hook)
238
{
239
return (0);
240
} /* ng_btsocket_hci_raw_node_connect */
241
242
/*
243
* Disconnect hook
244
*/
245
246
static int
247
ng_btsocket_hci_raw_node_disconnect(hook_p hook)
248
{
249
return (0);
250
} /* ng_btsocket_hci_raw_node_disconnect */
251
252
/*
253
* Receive control message.
254
* Make sure it is a message from HCI node and it is a response.
255
* Enqueue item and schedule input task.
256
*/
257
258
static int
259
ng_btsocket_hci_raw_node_rcvmsg(node_p node, item_p item, hook_p lasthook)
260
{
261
struct ng_mesg *msg = NGI_MSG(item); /* item still has message */
262
int error = 0;
263
264
/*
265
* Check for empty sockets list creates LOR when both sender and
266
* receiver device are connected to the same host, so remove it
267
* for now
268
*/
269
270
if (msg != NULL &&
271
(msg->header.typecookie == NGM_HCI_COOKIE ||
272
msg->header.typecookie == NGM_GENERIC_COOKIE) &&
273
msg->header.flags & NGF_RESP) {
274
if (msg->header.token == 0) {
275
NG_FREE_ITEM(item);
276
return (0);
277
}
278
279
mtx_lock(&ng_btsocket_hci_raw_queue_mtx);
280
if (NG_BT_ITEMQ_FULL(&ng_btsocket_hci_raw_queue)) {
281
NG_BTSOCKET_HCI_RAW_ERR(
282
"%s: Input queue is full\n", __func__);
283
284
NG_BT_ITEMQ_DROP(&ng_btsocket_hci_raw_queue);
285
NG_FREE_ITEM(item);
286
error = ENOBUFS;
287
} else {
288
NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_hci_raw_queue, item);
289
error = ng_btsocket_hci_raw_wakeup_input_task();
290
}
291
mtx_unlock(&ng_btsocket_hci_raw_queue_mtx);
292
} else {
293
NG_FREE_ITEM(item);
294
error = EINVAL;
295
}
296
297
return (error);
298
} /* ng_btsocket_hci_raw_node_rcvmsg */
299
300
/*
301
* Receive packet from the one of our hook.
302
* Prepend every packet with sockaddr_hci and record sender's node name.
303
* Enqueue item and schedule input task.
304
*/
305
306
static int
307
ng_btsocket_hci_raw_node_rcvdata(hook_p hook, item_p item)
308
{
309
struct mbuf *nam = NULL;
310
int error;
311
312
/*
313
* Check for empty sockets list creates LOR when both sender and
314
* receiver device are connected to the same host, so remove it
315
* for now
316
*/
317
318
MGET(nam, M_NOWAIT, MT_SONAME);
319
if (nam != NULL) {
320
struct sockaddr_hci *sa = mtod(nam, struct sockaddr_hci *);
321
322
nam->m_len = sizeof(struct sockaddr_hci);
323
324
sa->hci_len = sizeof(*sa);
325
sa->hci_family = AF_BLUETOOTH;
326
strlcpy(sa->hci_node, NG_PEER_NODE_NAME(hook),
327
sizeof(sa->hci_node));
328
329
NGI_GET_M(item, nam->m_next);
330
NGI_M(item) = nam;
331
332
mtx_lock(&ng_btsocket_hci_raw_queue_mtx);
333
if (NG_BT_ITEMQ_FULL(&ng_btsocket_hci_raw_queue)) {
334
NG_BTSOCKET_HCI_RAW_ERR(
335
"%s: Input queue is full\n", __func__);
336
337
NG_BT_ITEMQ_DROP(&ng_btsocket_hci_raw_queue);
338
NG_FREE_ITEM(item);
339
error = ENOBUFS;
340
} else {
341
NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_hci_raw_queue, item);
342
error = ng_btsocket_hci_raw_wakeup_input_task();
343
}
344
mtx_unlock(&ng_btsocket_hci_raw_queue_mtx);
345
} else {
346
NG_BTSOCKET_HCI_RAW_ERR(
347
"%s: Failed to allocate address mbuf\n", __func__);
348
349
NG_FREE_ITEM(item);
350
error = ENOBUFS;
351
}
352
353
return (error);
354
} /* ng_btsocket_hci_raw_node_rcvdata */
355
356
/****************************************************************************
357
****************************************************************************
358
** Sockets specific
359
****************************************************************************
360
****************************************************************************/
361
362
/*
363
* Get next token. We need token to avoid theoretical race where process
364
* submits ioctl() message then interrupts ioctl() and re-submits another
365
* ioctl() on the same socket *before* first ioctl() complete.
366
*/
367
368
static void
369
ng_btsocket_hci_raw_get_token(u_int32_t *token)
370
{
371
mtx_lock(&ng_btsocket_hci_raw_token_mtx);
372
373
if (++ ng_btsocket_hci_raw_token == 0)
374
ng_btsocket_hci_raw_token = 1;
375
376
*token = ng_btsocket_hci_raw_token;
377
378
mtx_unlock(&ng_btsocket_hci_raw_token_mtx);
379
} /* ng_btsocket_hci_raw_get_token */
380
381
/*
382
* Send Netgraph message to the node - do not expect reply
383
*/
384
385
static int
386
ng_btsocket_hci_raw_send_ngmsg(char *path, int cmd, void *arg, int arglen)
387
{
388
struct ng_mesg *msg = NULL;
389
int error = 0;
390
391
NG_MKMESSAGE(msg, NGM_HCI_COOKIE, cmd, arglen, M_NOWAIT);
392
if (msg == NULL)
393
return (ENOMEM);
394
395
if (arg != NULL && arglen > 0)
396
bcopy(arg, msg->data, arglen);
397
398
NG_SEND_MSG_PATH(error, ng_btsocket_hci_raw_node, msg, path, 0);
399
400
return (error);
401
} /* ng_btsocket_hci_raw_send_ngmsg */
402
403
/*
404
* Send Netgraph message to the node (no data) and wait for reply
405
*/
406
407
static int
408
ng_btsocket_hci_raw_send_sync_ngmsg(ng_btsocket_hci_raw_pcb_p pcb, char *path,
409
int cmd, void *rsp, int rsplen)
410
{
411
struct ng_mesg *msg = NULL;
412
int error = 0;
413
414
mtx_assert(&pcb->pcb_mtx, MA_OWNED);
415
416
NG_MKMESSAGE(msg, NGM_HCI_COOKIE, cmd, 0, M_NOWAIT);
417
if (msg == NULL)
418
return (ENOMEM);
419
420
ng_btsocket_hci_raw_get_token(&msg->header.token);
421
pcb->token = msg->header.token;
422
pcb->msg = NULL;
423
424
NG_SEND_MSG_PATH(error, ng_btsocket_hci_raw_node, msg, path, 0);
425
if (error != 0) {
426
pcb->token = 0;
427
return (error);
428
}
429
430
error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "hcictl",
431
ng_btsocket_hci_raw_ioctl_timeout * hz);
432
pcb->token = 0;
433
434
if (error != 0)
435
return (error);
436
437
if (pcb->msg != NULL && pcb->msg->header.cmd == cmd)
438
bcopy(pcb->msg->data, rsp, rsplen);
439
else
440
error = EINVAL;
441
442
NG_FREE_MSG(pcb->msg); /* checks for != NULL */
443
444
return (0);
445
} /* ng_btsocket_hci_raw_send_sync_ngmsg */
446
447
/*
448
* Create control information for the packet
449
*/
450
451
static void
452
ng_btsocket_hci_raw_savctl(ng_btsocket_hci_raw_pcb_p pcb, struct mbuf **ctl,
453
struct mbuf *m)
454
{
455
int dir;
456
struct timeval tv;
457
458
mtx_assert(&pcb->pcb_mtx, MA_OWNED);
459
460
if (pcb->flags & NG_BTSOCKET_HCI_RAW_DIRECTION) {
461
dir = (m->m_flags & M_PROTO1)? 1 : 0;
462
*ctl = sbcreatecontrol(&dir, sizeof(dir),
463
SCM_HCI_RAW_DIRECTION, SOL_HCI_RAW, M_NOWAIT);
464
if (*ctl != NULL)
465
ctl = &((*ctl)->m_next);
466
}
467
468
if (pcb->so->so_options & SO_TIMESTAMP) {
469
microtime(&tv);
470
*ctl = sbcreatecontrol(&tv, sizeof(tv), SCM_TIMESTAMP,
471
SOL_SOCKET, M_NOWAIT);
472
if (*ctl != NULL)
473
ctl = &((*ctl)->m_next);
474
}
475
} /* ng_btsocket_hci_raw_savctl */
476
477
/*
478
* Raw HCI sockets data input routine
479
*/
480
481
static void
482
ng_btsocket_hci_raw_data_input(struct mbuf *nam)
483
{
484
ng_btsocket_hci_raw_pcb_p pcb = NULL;
485
struct mbuf *m0 = NULL, *m = NULL;
486
struct sockaddr_hci *sa = NULL;
487
488
m0 = nam->m_next;
489
nam->m_next = NULL;
490
491
KASSERT((nam->m_type == MT_SONAME),
492
("%s: m_type=%d\n", __func__, nam->m_type));
493
KASSERT((m0->m_flags & M_PKTHDR),
494
("%s: m_flags=%#x\n", __func__, m0->m_flags));
495
496
sa = mtod(nam, struct sockaddr_hci *);
497
498
mtx_lock(&ng_btsocket_hci_raw_sockets_mtx);
499
500
LIST_FOREACH(pcb, &ng_btsocket_hci_raw_sockets, next) {
501
mtx_lock(&pcb->pcb_mtx);
502
503
/*
504
* If socket was bound then check address and
505
* make sure it matches.
506
*/
507
508
if (pcb->addr.hci_node[0] != 0 &&
509
strcmp(sa->hci_node, pcb->addr.hci_node) != 0)
510
goto next;
511
512
/*
513
* Check packet against filters
514
* XXX do we have to call m_pullup() here?
515
*/
516
517
if (ng_btsocket_hci_raw_filter(pcb, m0, 1) != 0)
518
goto next;
519
520
/*
521
* Make a copy of the packet, append to the socket's
522
* receive queue and wakeup socket. sbappendaddr()
523
* will check if socket has enough buffer space.
524
*/
525
526
m = m_dup(m0, M_NOWAIT);
527
if (m != NULL) {
528
struct mbuf *ctl = NULL;
529
530
ng_btsocket_hci_raw_savctl(pcb, &ctl, m);
531
532
if (sbappendaddr(&pcb->so->so_rcv,
533
(struct sockaddr *) sa, m, ctl))
534
sorwakeup(pcb->so);
535
else {
536
NG_BTSOCKET_HCI_RAW_INFO(
537
"%s: sbappendaddr() failed\n", __func__);
538
539
NG_FREE_M(m);
540
NG_FREE_M(ctl);
541
soroverflow(pcb->so);
542
}
543
}
544
next:
545
mtx_unlock(&pcb->pcb_mtx);
546
}
547
548
mtx_unlock(&ng_btsocket_hci_raw_sockets_mtx);
549
550
NG_FREE_M(nam);
551
NG_FREE_M(m0);
552
} /* ng_btsocket_hci_raw_data_input */
553
554
/*
555
* Raw HCI sockets message input routine
556
*/
557
558
static void
559
ng_btsocket_hci_raw_msg_input(struct ng_mesg *msg)
560
{
561
ng_btsocket_hci_raw_pcb_p pcb = NULL;
562
563
mtx_lock(&ng_btsocket_hci_raw_sockets_mtx);
564
565
LIST_FOREACH(pcb, &ng_btsocket_hci_raw_sockets, next) {
566
mtx_lock(&pcb->pcb_mtx);
567
568
if (msg->header.token == pcb->token) {
569
pcb->msg = msg;
570
wakeup(&pcb->msg);
571
572
mtx_unlock(&pcb->pcb_mtx);
573
mtx_unlock(&ng_btsocket_hci_raw_sockets_mtx);
574
575
return;
576
}
577
578
mtx_unlock(&pcb->pcb_mtx);
579
}
580
581
mtx_unlock(&ng_btsocket_hci_raw_sockets_mtx);
582
583
NG_FREE_MSG(msg); /* checks for != NULL */
584
} /* ng_btsocket_hci_raw_msg_input */
585
586
/*
587
* Raw HCI sockets input routines
588
*/
589
590
static void
591
ng_btsocket_hci_raw_input(void *context, int pending)
592
{
593
item_p item = NULL;
594
595
for (;;) {
596
mtx_lock(&ng_btsocket_hci_raw_queue_mtx);
597
NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_hci_raw_queue, item);
598
mtx_unlock(&ng_btsocket_hci_raw_queue_mtx);
599
600
if (item == NULL)
601
break;
602
603
switch(item->el_flags & NGQF_TYPE) {
604
case NGQF_DATA: {
605
struct mbuf *m = NULL;
606
607
NGI_GET_M(item, m);
608
ng_btsocket_hci_raw_data_input(m);
609
} break;
610
611
case NGQF_MESG: {
612
struct ng_mesg *msg = NULL;
613
614
NGI_GET_MSG(item, msg);
615
ng_btsocket_hci_raw_msg_input(msg);
616
} break;
617
618
default:
619
KASSERT(0,
620
("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE)));
621
break;
622
}
623
624
NG_FREE_ITEM(item);
625
}
626
} /* ng_btsocket_hci_raw_input */
627
628
/*
629
* Raw HCI sockets output routine
630
*/
631
632
static void
633
ng_btsocket_hci_raw_output(node_p node, hook_p hook, void *arg1, int arg2)
634
{
635
struct mbuf *nam = (struct mbuf *) arg1, *m = NULL;
636
struct sockaddr_hci *sa = NULL;
637
int error;
638
639
m = nam->m_next;
640
nam->m_next = NULL;
641
642
KASSERT((nam->m_type == MT_SONAME),
643
("%s: m_type=%d\n", __func__, nam->m_type));
644
KASSERT((m->m_flags & M_PKTHDR),
645
("%s: m_flags=%#x\n", __func__, m->m_flags));
646
647
sa = mtod(nam, struct sockaddr_hci *);
648
649
/*
650
* Find downstream hook
651
* XXX For now access node hook list directly. Should be safe because
652
* we used ng_send_fn() and we should have exclusive lock on the node.
653
*/
654
655
LIST_FOREACH(hook, &node->nd_hooks, hk_hooks) {
656
if (hook == NULL || NG_HOOK_NOT_VALID(hook) ||
657
NG_NODE_NOT_VALID(NG_PEER_NODE(hook)))
658
continue;
659
660
if (strcmp(sa->hci_node, NG_PEER_NODE_NAME(hook)) == 0) {
661
NG_SEND_DATA_ONLY(error, hook, m); /* sets m to NULL */
662
break;
663
}
664
}
665
666
NG_FREE_M(nam); /* check for != NULL */
667
NG_FREE_M(m);
668
} /* ng_btsocket_hci_raw_output */
669
670
/*
671
* Check frame against security and socket filters.
672
* d (direction bit) == 1 means incoming frame.
673
*/
674
675
static int
676
ng_btsocket_hci_raw_filter(ng_btsocket_hci_raw_pcb_p pcb, struct mbuf *m, int d)
677
{
678
int type, event, opcode;
679
680
mtx_assert(&pcb->pcb_mtx, MA_OWNED);
681
682
switch ((type = *mtod(m, u_int8_t *))) {
683
case NG_HCI_CMD_PKT:
684
if (!(pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED)) {
685
opcode = le16toh(mtod(m, ng_hci_cmd_pkt_t *)->opcode);
686
687
if (!bit_test(
688
ng_btsocket_hci_raw_sec_filter->commands[NG_HCI_OGF(opcode) - 1],
689
NG_HCI_OCF(opcode) - 1))
690
return (EPERM);
691
}
692
693
if (d && !bit_test(pcb->filter.packet_mask, NG_HCI_CMD_PKT - 1))
694
return (EPERM);
695
break;
696
697
case NG_HCI_ACL_DATA_PKT:
698
case NG_HCI_SCO_DATA_PKT:
699
if (!(pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED) ||
700
!bit_test(pcb->filter.packet_mask, type - 1) ||
701
!d)
702
return (EPERM);
703
break;
704
705
case NG_HCI_EVENT_PKT:
706
if (!d)
707
return (EINVAL);
708
709
event = mtod(m, ng_hci_event_pkt_t *)->event - 1;
710
711
if (!(pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED))
712
if (!bit_test(ng_btsocket_hci_raw_sec_filter->events, event))
713
return (EPERM);
714
715
if (!bit_test(pcb->filter.event_mask, event))
716
return (EPERM);
717
break;
718
719
default:
720
return (EINVAL);
721
}
722
723
return (0);
724
} /* ng_btsocket_hci_raw_filter */
725
726
/*
727
* Initialize everything
728
*/
729
730
static void
731
ng_btsocket_hci_raw_init(void *arg __unused)
732
{
733
bitstr_t *f = NULL;
734
int error = 0;
735
736
ng_btsocket_hci_raw_node = NULL;
737
ng_btsocket_hci_raw_debug_level = NG_BTSOCKET_WARN_LEVEL;
738
ng_btsocket_hci_raw_ioctl_timeout = 5;
739
740
/* Register Netgraph node type */
741
error = ng_newtype(&typestruct);
742
if (error != 0) {
743
NG_BTSOCKET_HCI_RAW_ALERT(
744
"%s: Could not register Netgraph node type, error=%d\n", __func__, error);
745
746
return;
747
}
748
749
/* Create Netgrapg node */
750
error = ng_make_node_common(&typestruct, &ng_btsocket_hci_raw_node);
751
if (error != 0) {
752
NG_BTSOCKET_HCI_RAW_ALERT(
753
"%s: Could not create Netgraph node, error=%d\n", __func__, error);
754
755
ng_btsocket_hci_raw_node = NULL;
756
757
return;
758
}
759
760
error = ng_name_node(ng_btsocket_hci_raw_node,
761
NG_BTSOCKET_HCI_RAW_NODE_TYPE);
762
if (error != 0) {
763
NG_BTSOCKET_HCI_RAW_ALERT(
764
"%s: Could not name Netgraph node, error=%d\n", __func__, error);
765
766
NG_NODE_UNREF(ng_btsocket_hci_raw_node);
767
ng_btsocket_hci_raw_node = NULL;
768
769
return;
770
}
771
772
/* Create input queue */
773
NG_BT_ITEMQ_INIT(&ng_btsocket_hci_raw_queue, 300);
774
mtx_init(&ng_btsocket_hci_raw_queue_mtx,
775
"btsocks_hci_raw_queue_mtx", NULL, MTX_DEF);
776
TASK_INIT(&ng_btsocket_hci_raw_task, 0,
777
ng_btsocket_hci_raw_input, NULL);
778
779
/* Create list of sockets */
780
LIST_INIT(&ng_btsocket_hci_raw_sockets);
781
mtx_init(&ng_btsocket_hci_raw_sockets_mtx,
782
"btsocks_hci_raw_sockets_mtx", NULL, MTX_DEF);
783
784
/* Tokens */
785
ng_btsocket_hci_raw_token = 0;
786
mtx_init(&ng_btsocket_hci_raw_token_mtx,
787
"btsocks_hci_raw_token_mtx", NULL, MTX_DEF);
788
789
/*
790
* Security filter
791
* XXX never free()ed
792
*/
793
ng_btsocket_hci_raw_sec_filter =
794
malloc(sizeof(struct ng_btsocket_hci_raw_sec_filter),
795
M_NETGRAPH_BTSOCKET_HCI_RAW, M_NOWAIT|M_ZERO);
796
if (ng_btsocket_hci_raw_sec_filter == NULL) {
797
printf("%s: Could not allocate security filter!\n", __func__);
798
return;
799
}
800
801
/*
802
* XXX How paranoid can we get?
803
*
804
* Initialize security filter. If bit is set in the mask then
805
* unprivileged socket is allowed to send (receive) this command
806
* (event).
807
*/
808
809
/* Enable all events */
810
memset(&ng_btsocket_hci_raw_sec_filter->events, 0xff,
811
sizeof(ng_btsocket_hci_raw_sec_filter->events));
812
813
/* Disable some critical events */
814
f = ng_btsocket_hci_raw_sec_filter->events;
815
bit_clear(f, NG_HCI_EVENT_RETURN_LINK_KEYS - 1);
816
bit_clear(f, NG_HCI_EVENT_LINK_KEY_NOTIFICATION - 1);
817
bit_clear(f, NG_HCI_EVENT_VENDOR - 1);
818
819
/* Commands - Link control */
820
f = ng_btsocket_hci_raw_sec_filter->commands[NG_HCI_OGF_LINK_CONTROL-1];
821
bit_set(f, NG_HCI_OCF_INQUIRY - 1);
822
bit_set(f, NG_HCI_OCF_INQUIRY_CANCEL - 1);
823
bit_set(f, NG_HCI_OCF_PERIODIC_INQUIRY - 1);
824
bit_set(f, NG_HCI_OCF_EXIT_PERIODIC_INQUIRY - 1);
825
bit_set(f, NG_HCI_OCF_REMOTE_NAME_REQ - 1);
826
bit_set(f, NG_HCI_OCF_READ_REMOTE_FEATURES - 1);
827
bit_set(f, NG_HCI_OCF_READ_REMOTE_VER_INFO - 1);
828
bit_set(f, NG_HCI_OCF_READ_CLOCK_OFFSET - 1);
829
830
/* Commands - Link policy */
831
f = ng_btsocket_hci_raw_sec_filter->commands[NG_HCI_OGF_LINK_POLICY-1];
832
bit_set(f, NG_HCI_OCF_ROLE_DISCOVERY - 1);
833
bit_set(f, NG_HCI_OCF_READ_LINK_POLICY_SETTINGS - 1);
834
835
/* Commands - Host controller and baseband */
836
f = ng_btsocket_hci_raw_sec_filter->commands[NG_HCI_OGF_HC_BASEBAND-1];
837
bit_set(f, NG_HCI_OCF_READ_PIN_TYPE - 1);
838
bit_set(f, NG_HCI_OCF_READ_LOCAL_NAME - 1);
839
bit_set(f, NG_HCI_OCF_READ_CON_ACCEPT_TIMO - 1);
840
bit_set(f, NG_HCI_OCF_READ_PAGE_TIMO - 1);
841
bit_set(f, NG_HCI_OCF_READ_SCAN_ENABLE - 1);
842
bit_set(f, NG_HCI_OCF_READ_PAGE_SCAN_ACTIVITY - 1);
843
bit_set(f, NG_HCI_OCF_READ_INQUIRY_SCAN_ACTIVITY - 1);
844
bit_set(f, NG_HCI_OCF_READ_AUTH_ENABLE - 1);
845
bit_set(f, NG_HCI_OCF_READ_ENCRYPTION_MODE - 1);
846
bit_set(f, NG_HCI_OCF_READ_UNIT_CLASS - 1);
847
bit_set(f, NG_HCI_OCF_READ_VOICE_SETTINGS - 1);
848
bit_set(f, NG_HCI_OCF_READ_AUTO_FLUSH_TIMO - 1);
849
bit_set(f, NG_HCI_OCF_READ_NUM_BROADCAST_RETRANS - 1);
850
bit_set(f, NG_HCI_OCF_READ_HOLD_MODE_ACTIVITY - 1);
851
bit_set(f, NG_HCI_OCF_READ_XMIT_LEVEL - 1);
852
bit_set(f, NG_HCI_OCF_READ_SCO_FLOW_CONTROL - 1);
853
bit_set(f, NG_HCI_OCF_READ_LINK_SUPERVISION_TIMO - 1);
854
bit_set(f, NG_HCI_OCF_READ_SUPPORTED_IAC_NUM - 1);
855
bit_set(f, NG_HCI_OCF_READ_IAC_LAP - 1);
856
bit_set(f, NG_HCI_OCF_READ_PAGE_SCAN_PERIOD - 1);
857
bit_set(f, NG_HCI_OCF_READ_PAGE_SCAN - 1);
858
bit_set(f, NG_HCI_OCF_READ_LE_HOST_SUPPORTED -1);
859
860
/* Commands - Informational */
861
f = ng_btsocket_hci_raw_sec_filter->commands[NG_HCI_OGF_INFO - 1];
862
bit_set(f, NG_HCI_OCF_READ_LOCAL_VER - 1);
863
bit_set(f, NG_HCI_OCF_READ_LOCAL_FEATURES - 1);
864
bit_set(f, NG_HCI_OCF_READ_BUFFER_SIZE - 1);
865
bit_set(f, NG_HCI_OCF_READ_COUNTRY_CODE - 1);
866
bit_set(f, NG_HCI_OCF_READ_BDADDR - 1);
867
868
/* Commands - Status */
869
f = ng_btsocket_hci_raw_sec_filter->commands[NG_HCI_OGF_STATUS - 1];
870
bit_set(f, NG_HCI_OCF_READ_FAILED_CONTACT_CNTR - 1);
871
bit_set(f, NG_HCI_OCF_GET_LINK_QUALITY - 1);
872
bit_set(f, NG_HCI_OCF_READ_RSSI - 1);
873
874
/* Commands - Testing */
875
f = ng_btsocket_hci_raw_sec_filter->commands[NG_HCI_OGF_TESTING - 1];
876
bit_set(f, NG_HCI_OCF_READ_LOOPBACK_MODE - 1);
877
/*Commands - LE*/
878
f = ng_btsocket_hci_raw_sec_filter->commands[NG_HCI_OGF_LE -1];
879
bit_set(f, NG_HCI_OCF_LE_SET_SCAN_ENABLE - 1);
880
bit_set(f, NG_HCI_OCF_LE_SET_SCAN_PARAMETERS - 1);
881
bit_set(f, NG_HCI_OCF_LE_READ_LOCAL_SUPPORTED_FEATURES - 1);
882
bit_set(f, NG_HCI_OCF_LE_READ_BUFFER_SIZE - 1);
883
bit_set(f, NG_HCI_OCF_LE_READ_WHITE_LIST_SIZE - 1);
884
885
} /* ng_btsocket_hci_raw_init */
886
SYSINIT(ng_btsocket_hci_raw_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD,
887
ng_btsocket_hci_raw_init, NULL);
888
889
/*
890
* Abort connection on socket
891
*/
892
893
void
894
ng_btsocket_hci_raw_abort(struct socket *so)
895
{
896
} /* ng_btsocket_hci_raw_abort */
897
898
void
899
ng_btsocket_hci_raw_close(struct socket *so)
900
{
901
} /* ng_btsocket_hci_raw_close */
902
903
/*
904
* Create new raw HCI socket
905
*/
906
907
int
908
ng_btsocket_hci_raw_attach(struct socket *so, int proto, struct thread *td)
909
{
910
ng_btsocket_hci_raw_pcb_p pcb = so2hci_raw_pcb(so);
911
int error = 0;
912
913
if (pcb != NULL)
914
return (EISCONN);
915
916
if (ng_btsocket_hci_raw_node == NULL)
917
return (EPROTONOSUPPORT);
918
if (proto != BLUETOOTH_PROTO_HCI)
919
return (EPROTONOSUPPORT);
920
if (so->so_type != SOCK_RAW)
921
return (ESOCKTNOSUPPORT);
922
923
error = soreserve(so, NG_BTSOCKET_HCI_RAW_SENDSPACE,
924
NG_BTSOCKET_HCI_RAW_RECVSPACE);
925
if (error != 0)
926
return (error);
927
928
pcb = malloc(sizeof(*pcb),
929
M_NETGRAPH_BTSOCKET_HCI_RAW, M_NOWAIT|M_ZERO);
930
if (pcb == NULL)
931
return (ENOMEM);
932
933
so->so_pcb = (caddr_t) pcb;
934
pcb->so = so;
935
936
if (priv_check(td, PRIV_NETBLUETOOTH_RAW) == 0)
937
pcb->flags |= NG_BTSOCKET_HCI_RAW_PRIVILEGED;
938
939
/*
940
* Set default socket filter. By default socket only accepts HCI
941
* Command_Complete and Command_Status event packets.
942
*/
943
944
bit_set(pcb->filter.event_mask, NG_HCI_EVENT_COMMAND_COMPL - 1);
945
bit_set(pcb->filter.event_mask, NG_HCI_EVENT_COMMAND_STATUS - 1);
946
947
mtx_init(&pcb->pcb_mtx, "btsocks_hci_raw_pcb_mtx", NULL, MTX_DEF);
948
949
mtx_lock(&ng_btsocket_hci_raw_sockets_mtx);
950
LIST_INSERT_HEAD(&ng_btsocket_hci_raw_sockets, pcb, next);
951
mtx_unlock(&ng_btsocket_hci_raw_sockets_mtx);
952
953
return (0);
954
} /* ng_btsocket_hci_raw_attach */
955
956
/*
957
* Bind raw HCI socket
958
*/
959
960
int
961
ng_btsocket_hci_raw_bind(struct socket *so, struct sockaddr *nam,
962
struct thread *td)
963
{
964
ng_btsocket_hci_raw_pcb_p pcb = so2hci_raw_pcb(so);
965
struct sockaddr_hci *sa = (struct sockaddr_hci *) nam;
966
967
if (pcb == NULL)
968
return (EINVAL);
969
if (ng_btsocket_hci_raw_node == NULL)
970
return (EINVAL);
971
972
if (sa == NULL)
973
return (EINVAL);
974
if (sa->hci_family != AF_BLUETOOTH)
975
return (EAFNOSUPPORT);
976
if (sa->hci_len != sizeof(*sa))
977
return (EINVAL);
978
if (sa->hci_node[0] == 0)
979
return (EINVAL);
980
981
mtx_lock(&pcb->pcb_mtx);
982
bcopy(sa, &pcb->addr, sizeof(pcb->addr));
983
mtx_unlock(&pcb->pcb_mtx);
984
985
return (0);
986
} /* ng_btsocket_hci_raw_bind */
987
988
/*
989
* Connect raw HCI socket
990
*/
991
992
int
993
ng_btsocket_hci_raw_connect(struct socket *so, struct sockaddr *nam,
994
struct thread *td)
995
{
996
ng_btsocket_hci_raw_pcb_p pcb = so2hci_raw_pcb(so);
997
struct sockaddr_hci *sa = (struct sockaddr_hci *) nam;
998
999
if (pcb == NULL)
1000
return (EINVAL);
1001
if (ng_btsocket_hci_raw_node == NULL)
1002
return (EINVAL);
1003
1004
if (sa == NULL)
1005
return (EINVAL);
1006
if (sa->hci_family != AF_BLUETOOTH)
1007
return (EAFNOSUPPORT);
1008
if (sa->hci_len != sizeof(*sa))
1009
return (EINVAL);
1010
if (sa->hci_node[0] == 0)
1011
return (EDESTADDRREQ);
1012
1013
mtx_lock(&pcb->pcb_mtx);
1014
1015
if (bcmp(sa, &pcb->addr, sizeof(pcb->addr)) != 0) {
1016
mtx_unlock(&pcb->pcb_mtx);
1017
return (EADDRNOTAVAIL);
1018
}
1019
1020
soisconnected(so);
1021
1022
mtx_unlock(&pcb->pcb_mtx);
1023
1024
return (0);
1025
} /* ng_btsocket_hci_raw_connect */
1026
1027
/*
1028
* Process ioctl on socket
1029
*/
1030
1031
int
1032
ng_btsocket_hci_raw_control(struct socket *so, u_long cmd, void *data,
1033
struct ifnet *ifp, struct thread *td)
1034
{
1035
ng_btsocket_hci_raw_pcb_p pcb = so2hci_raw_pcb(so);
1036
char path[NG_NODESIZ + 1];
1037
struct ng_mesg *msg = NULL;
1038
int error = 0;
1039
1040
if (pcb == NULL)
1041
return (EINVAL);
1042
if (ng_btsocket_hci_raw_node == NULL)
1043
return (EINVAL);
1044
1045
mtx_lock(&pcb->pcb_mtx);
1046
1047
/* Check if we have device name */
1048
if (pcb->addr.hci_node[0] == 0) {
1049
mtx_unlock(&pcb->pcb_mtx);
1050
return (EHOSTUNREACH);
1051
}
1052
1053
/* Check if we have pending ioctl() */
1054
if (pcb->token != 0) {
1055
mtx_unlock(&pcb->pcb_mtx);
1056
return (EBUSY);
1057
}
1058
1059
snprintf(path, sizeof(path), "%s:", pcb->addr.hci_node);
1060
1061
switch (cmd) {
1062
case SIOC_HCI_RAW_NODE_GET_STATE: {
1063
struct ng_btsocket_hci_raw_node_state *p =
1064
(struct ng_btsocket_hci_raw_node_state *) data;
1065
1066
error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path,
1067
NGM_HCI_NODE_GET_STATE,
1068
&p->state, sizeof(p->state));
1069
} break;
1070
1071
case SIOC_HCI_RAW_NODE_INIT:
1072
if (pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED)
1073
error = ng_btsocket_hci_raw_send_ngmsg(path,
1074
NGM_HCI_NODE_INIT, NULL, 0);
1075
else
1076
error = EPERM;
1077
break;
1078
1079
case SIOC_HCI_RAW_NODE_GET_DEBUG: {
1080
struct ng_btsocket_hci_raw_node_debug *p =
1081
(struct ng_btsocket_hci_raw_node_debug *) data;
1082
1083
error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path,
1084
NGM_HCI_NODE_GET_DEBUG,
1085
&p->debug, sizeof(p->debug));
1086
} break;
1087
1088
case SIOC_HCI_RAW_NODE_SET_DEBUG: {
1089
struct ng_btsocket_hci_raw_node_debug *p =
1090
(struct ng_btsocket_hci_raw_node_debug *) data;
1091
1092
if (pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED)
1093
error = ng_btsocket_hci_raw_send_ngmsg(path,
1094
NGM_HCI_NODE_SET_DEBUG, &p->debug,
1095
sizeof(p->debug));
1096
else
1097
error = EPERM;
1098
} break;
1099
1100
case SIOC_HCI_RAW_NODE_GET_BUFFER: {
1101
struct ng_btsocket_hci_raw_node_buffer *p =
1102
(struct ng_btsocket_hci_raw_node_buffer *) data;
1103
1104
error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path,
1105
NGM_HCI_NODE_GET_BUFFER,
1106
&p->buffer, sizeof(p->buffer));
1107
} break;
1108
1109
case SIOC_HCI_RAW_NODE_GET_BDADDR: {
1110
struct ng_btsocket_hci_raw_node_bdaddr *p =
1111
(struct ng_btsocket_hci_raw_node_bdaddr *) data;
1112
1113
error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path,
1114
NGM_HCI_NODE_GET_BDADDR,
1115
&p->bdaddr, sizeof(p->bdaddr));
1116
} break;
1117
1118
case SIOC_HCI_RAW_NODE_GET_FEATURES: {
1119
struct ng_btsocket_hci_raw_node_features *p =
1120
(struct ng_btsocket_hci_raw_node_features *) data;
1121
1122
error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path,
1123
NGM_HCI_NODE_GET_FEATURES,
1124
&p->features, sizeof(p->features));
1125
} break;
1126
1127
case SIOC_HCI_RAW_NODE_GET_STAT: {
1128
struct ng_btsocket_hci_raw_node_stat *p =
1129
(struct ng_btsocket_hci_raw_node_stat *) data;
1130
1131
error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path,
1132
NGM_HCI_NODE_GET_STAT,
1133
&p->stat, sizeof(p->stat));
1134
} break;
1135
1136
case SIOC_HCI_RAW_NODE_RESET_STAT:
1137
if (pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED)
1138
error = ng_btsocket_hci_raw_send_ngmsg(path,
1139
NGM_HCI_NODE_RESET_STAT, NULL, 0);
1140
else
1141
error = EPERM;
1142
break;
1143
1144
case SIOC_HCI_RAW_NODE_FLUSH_NEIGHBOR_CACHE:
1145
if (pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED)
1146
error = ng_btsocket_hci_raw_send_ngmsg(path,
1147
NGM_HCI_NODE_FLUSH_NEIGHBOR_CACHE,
1148
NULL, 0);
1149
else
1150
error = EPERM;
1151
break;
1152
1153
case SIOC_HCI_RAW_NODE_GET_NEIGHBOR_CACHE: {
1154
struct ng_btsocket_hci_raw_node_neighbor_cache *p =
1155
(struct ng_btsocket_hci_raw_node_neighbor_cache *) data;
1156
ng_hci_node_get_neighbor_cache_ep *p1 = NULL;
1157
ng_hci_node_neighbor_cache_entry_ep *p2 = NULL;
1158
1159
if (p->num_entries <= 0 ||
1160
p->num_entries > NG_HCI_MAX_NEIGHBOR_NUM ||
1161
p->entries == NULL) {
1162
mtx_unlock(&pcb->pcb_mtx);
1163
return (EINVAL);
1164
}
1165
1166
NG_MKMESSAGE(msg, NGM_HCI_COOKIE,
1167
NGM_HCI_NODE_GET_NEIGHBOR_CACHE, 0, M_NOWAIT);
1168
if (msg == NULL) {
1169
mtx_unlock(&pcb->pcb_mtx);
1170
return (ENOMEM);
1171
}
1172
ng_btsocket_hci_raw_get_token(&msg->header.token);
1173
pcb->token = msg->header.token;
1174
pcb->msg = NULL;
1175
1176
NG_SEND_MSG_PATH(error, ng_btsocket_hci_raw_node, msg, path, 0);
1177
if (error != 0) {
1178
pcb->token = 0;
1179
mtx_unlock(&pcb->pcb_mtx);
1180
return (error);
1181
}
1182
1183
error = msleep(&pcb->msg, &pcb->pcb_mtx,
1184
PZERO|PCATCH, "hcictl",
1185
ng_btsocket_hci_raw_ioctl_timeout * hz);
1186
pcb->token = 0;
1187
1188
if (error != 0) {
1189
mtx_unlock(&pcb->pcb_mtx);
1190
return (error);
1191
}
1192
1193
msg = pcb->msg;
1194
pcb->msg = NULL;
1195
1196
mtx_unlock(&pcb->pcb_mtx);
1197
1198
if (msg != NULL &&
1199
msg->header.cmd == NGM_HCI_NODE_GET_NEIGHBOR_CACHE) {
1200
/* Return data back to user space */
1201
p1 = (ng_hci_node_get_neighbor_cache_ep *)(msg->data);
1202
p2 = (ng_hci_node_neighbor_cache_entry_ep *)(p1 + 1);
1203
1204
p->num_entries = min(p->num_entries, p1->num_entries);
1205
if (p->num_entries > 0)
1206
error = copyout((caddr_t) p2,
1207
(caddr_t) p->entries,
1208
p->num_entries * sizeof(*p2));
1209
} else
1210
error = EINVAL;
1211
1212
NG_FREE_MSG(msg); /* checks for != NULL */
1213
return (error);
1214
} /* NOTREACHED */
1215
1216
case SIOC_HCI_RAW_NODE_GET_CON_LIST: {
1217
struct ng_btsocket_hci_raw_con_list *p =
1218
(struct ng_btsocket_hci_raw_con_list *) data;
1219
ng_hci_node_con_list_ep *p1 = NULL;
1220
ng_hci_node_con_ep *p2 = NULL;
1221
1222
if (p->num_connections == 0 ||
1223
p->num_connections > NG_HCI_MAX_CON_NUM ||
1224
p->connections == NULL) {
1225
mtx_unlock(&pcb->pcb_mtx);
1226
return (EINVAL);
1227
}
1228
1229
NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_NODE_GET_CON_LIST,
1230
0, M_NOWAIT);
1231
if (msg == NULL) {
1232
mtx_unlock(&pcb->pcb_mtx);
1233
return (ENOMEM);
1234
}
1235
ng_btsocket_hci_raw_get_token(&msg->header.token);
1236
pcb->token = msg->header.token;
1237
pcb->msg = NULL;
1238
1239
NG_SEND_MSG_PATH(error, ng_btsocket_hci_raw_node, msg, path, 0);
1240
if (error != 0) {
1241
pcb->token = 0;
1242
mtx_unlock(&pcb->pcb_mtx);
1243
return (error);
1244
}
1245
1246
error = msleep(&pcb->msg, &pcb->pcb_mtx,
1247
PZERO|PCATCH, "hcictl",
1248
ng_btsocket_hci_raw_ioctl_timeout * hz);
1249
pcb->token = 0;
1250
1251
if (error != 0) {
1252
mtx_unlock(&pcb->pcb_mtx);
1253
return (error);
1254
}
1255
1256
msg = pcb->msg;
1257
pcb->msg = NULL;
1258
1259
mtx_unlock(&pcb->pcb_mtx);
1260
1261
if (msg != NULL &&
1262
msg->header.cmd == NGM_HCI_NODE_GET_CON_LIST) {
1263
/* Return data back to user space */
1264
p1 = (ng_hci_node_con_list_ep *)(msg->data);
1265
p2 = (ng_hci_node_con_ep *)(p1 + 1);
1266
1267
p->num_connections = min(p->num_connections,
1268
p1->num_connections);
1269
if (p->num_connections > 0)
1270
error = copyout((caddr_t) p2,
1271
(caddr_t) p->connections,
1272
p->num_connections * sizeof(*p2));
1273
} else
1274
error = EINVAL;
1275
1276
NG_FREE_MSG(msg); /* checks for != NULL */
1277
return (error);
1278
} /* NOTREACHED */
1279
1280
case SIOC_HCI_RAW_NODE_GET_LINK_POLICY_MASK: {
1281
struct ng_btsocket_hci_raw_node_link_policy_mask *p =
1282
(struct ng_btsocket_hci_raw_node_link_policy_mask *)
1283
data;
1284
1285
error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path,
1286
NGM_HCI_NODE_GET_LINK_POLICY_SETTINGS_MASK,
1287
&p->policy_mask, sizeof(p->policy_mask));
1288
} break;
1289
1290
case SIOC_HCI_RAW_NODE_SET_LINK_POLICY_MASK: {
1291
struct ng_btsocket_hci_raw_node_link_policy_mask *p =
1292
(struct ng_btsocket_hci_raw_node_link_policy_mask *)
1293
data;
1294
1295
if (pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED)
1296
error = ng_btsocket_hci_raw_send_ngmsg(path,
1297
NGM_HCI_NODE_SET_LINK_POLICY_SETTINGS_MASK,
1298
&p->policy_mask,
1299
sizeof(p->policy_mask));
1300
else
1301
error = EPERM;
1302
} break;
1303
1304
case SIOC_HCI_RAW_NODE_GET_PACKET_MASK: {
1305
struct ng_btsocket_hci_raw_node_packet_mask *p =
1306
(struct ng_btsocket_hci_raw_node_packet_mask *) data;
1307
1308
error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path,
1309
NGM_HCI_NODE_GET_PACKET_MASK,
1310
&p->packet_mask, sizeof(p->packet_mask));
1311
} break;
1312
1313
case SIOC_HCI_RAW_NODE_SET_PACKET_MASK: {
1314
struct ng_btsocket_hci_raw_node_packet_mask *p =
1315
(struct ng_btsocket_hci_raw_node_packet_mask *) data;
1316
1317
if (pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED)
1318
error = ng_btsocket_hci_raw_send_ngmsg(path,
1319
NGM_HCI_NODE_SET_PACKET_MASK,
1320
&p->packet_mask,
1321
sizeof(p->packet_mask));
1322
else
1323
error = EPERM;
1324
} break;
1325
1326
case SIOC_HCI_RAW_NODE_GET_ROLE_SWITCH: {
1327
struct ng_btsocket_hci_raw_node_role_switch *p =
1328
(struct ng_btsocket_hci_raw_node_role_switch *) data;
1329
1330
error = ng_btsocket_hci_raw_send_sync_ngmsg(pcb, path,
1331
NGM_HCI_NODE_GET_ROLE_SWITCH,
1332
&p->role_switch, sizeof(p->role_switch));
1333
} break;
1334
1335
case SIOC_HCI_RAW_NODE_SET_ROLE_SWITCH: {
1336
struct ng_btsocket_hci_raw_node_role_switch *p =
1337
(struct ng_btsocket_hci_raw_node_role_switch *) data;
1338
1339
if (pcb->flags & NG_BTSOCKET_HCI_RAW_PRIVILEGED)
1340
error = ng_btsocket_hci_raw_send_ngmsg(path,
1341
NGM_HCI_NODE_SET_ROLE_SWITCH,
1342
&p->role_switch,
1343
sizeof(p->role_switch));
1344
else
1345
error = EPERM;
1346
} break;
1347
1348
case SIOC_HCI_RAW_NODE_LIST_NAMES: {
1349
struct ng_btsocket_hci_raw_node_list_names *nl =
1350
(struct ng_btsocket_hci_raw_node_list_names *) data;
1351
struct nodeinfo *ni = nl->names;
1352
1353
if (nl->num_names == 0) {
1354
mtx_unlock(&pcb->pcb_mtx);
1355
return (EINVAL);
1356
}
1357
1358
NG_MKMESSAGE(msg, NGM_GENERIC_COOKIE, NGM_LISTNAMES,
1359
0, M_NOWAIT);
1360
if (msg == NULL) {
1361
mtx_unlock(&pcb->pcb_mtx);
1362
return (ENOMEM);
1363
}
1364
ng_btsocket_hci_raw_get_token(&msg->header.token);
1365
pcb->token = msg->header.token;
1366
pcb->msg = NULL;
1367
1368
NG_SEND_MSG_PATH(error, ng_btsocket_hci_raw_node, msg, ".:", 0);
1369
if (error != 0) {
1370
pcb->token = 0;
1371
mtx_unlock(&pcb->pcb_mtx);
1372
return (error);
1373
}
1374
1375
error = msleep(&pcb->msg, &pcb->pcb_mtx,
1376
PZERO|PCATCH, "hcictl",
1377
ng_btsocket_hci_raw_ioctl_timeout * hz);
1378
pcb->token = 0;
1379
1380
if (error != 0) {
1381
mtx_unlock(&pcb->pcb_mtx);
1382
return (error);
1383
}
1384
1385
msg = pcb->msg;
1386
pcb->msg = NULL;
1387
1388
mtx_unlock(&pcb->pcb_mtx);
1389
1390
if (msg != NULL && msg->header.cmd == NGM_LISTNAMES) {
1391
/* Return data back to user space */
1392
struct namelist *nl1 = (struct namelist *) msg->data;
1393
struct nodeinfo *ni1 = &nl1->nodeinfo[0];
1394
1395
while (nl->num_names > 0 && nl1->numnames > 0) {
1396
if (strcmp(ni1->type, NG_HCI_NODE_TYPE) == 0) {
1397
error = copyout((caddr_t) ni1,
1398
(caddr_t) ni,
1399
sizeof(*ni));
1400
if (error != 0)
1401
break;
1402
1403
nl->num_names --;
1404
ni ++;
1405
}
1406
1407
nl1->numnames --;
1408
ni1 ++;
1409
}
1410
1411
nl->num_names = ni - nl->names;
1412
} else
1413
error = EINVAL;
1414
1415
NG_FREE_MSG(msg); /* checks for != NULL */
1416
return (error);
1417
} /* NOTREACHED */
1418
1419
default:
1420
error = EINVAL;
1421
break;
1422
}
1423
1424
mtx_unlock(&pcb->pcb_mtx);
1425
1426
return (error);
1427
} /* ng_btsocket_hci_raw_control */
1428
1429
/*
1430
* Process getsockopt/setsockopt system calls
1431
*/
1432
1433
int
1434
ng_btsocket_hci_raw_ctloutput(struct socket *so, struct sockopt *sopt)
1435
{
1436
ng_btsocket_hci_raw_pcb_p pcb = so2hci_raw_pcb(so);
1437
struct ng_btsocket_hci_raw_filter filter;
1438
int error = 0, dir;
1439
1440
if (pcb == NULL)
1441
return (EINVAL);
1442
if (ng_btsocket_hci_raw_node == NULL)
1443
return (EINVAL);
1444
1445
if (sopt->sopt_level != SOL_HCI_RAW)
1446
return (0);
1447
1448
mtx_lock(&pcb->pcb_mtx);
1449
1450
switch (sopt->sopt_dir) {
1451
case SOPT_GET:
1452
switch (sopt->sopt_name) {
1453
case SO_HCI_RAW_FILTER:
1454
error = sooptcopyout(sopt, &pcb->filter,
1455
sizeof(pcb->filter));
1456
break;
1457
1458
case SO_HCI_RAW_DIRECTION:
1459
dir = (pcb->flags & NG_BTSOCKET_HCI_RAW_DIRECTION)?1:0;
1460
error = sooptcopyout(sopt, &dir, sizeof(dir));
1461
break;
1462
1463
default:
1464
error = EINVAL;
1465
break;
1466
}
1467
break;
1468
1469
case SOPT_SET:
1470
switch (sopt->sopt_name) {
1471
case SO_HCI_RAW_FILTER:
1472
error = sooptcopyin(sopt, &filter, sizeof(filter),
1473
sizeof(filter));
1474
if (error == 0)
1475
bcopy(&filter, &pcb->filter,
1476
sizeof(pcb->filter));
1477
break;
1478
1479
case SO_HCI_RAW_DIRECTION:
1480
error = sooptcopyin(sopt, &dir, sizeof(dir),
1481
sizeof(dir));
1482
if (error != 0)
1483
break;
1484
1485
if (dir)
1486
pcb->flags |= NG_BTSOCKET_HCI_RAW_DIRECTION;
1487
else
1488
pcb->flags &= ~NG_BTSOCKET_HCI_RAW_DIRECTION;
1489
break;
1490
1491
default:
1492
error = EINVAL;
1493
break;
1494
}
1495
break;
1496
1497
default:
1498
error = EINVAL;
1499
break;
1500
}
1501
1502
mtx_unlock(&pcb->pcb_mtx);
1503
1504
return (error);
1505
} /* ng_btsocket_hci_raw_ctloutput */
1506
1507
/*
1508
* Detach raw HCI socket
1509
*/
1510
1511
void
1512
ng_btsocket_hci_raw_detach(struct socket *so)
1513
{
1514
ng_btsocket_hci_raw_pcb_p pcb = so2hci_raw_pcb(so);
1515
1516
KASSERT(pcb != NULL, ("ng_btsocket_hci_raw_detach: pcb == NULL"));
1517
1518
if (ng_btsocket_hci_raw_node == NULL)
1519
return;
1520
1521
mtx_lock(&ng_btsocket_hci_raw_sockets_mtx);
1522
mtx_lock(&pcb->pcb_mtx);
1523
1524
LIST_REMOVE(pcb, next);
1525
1526
mtx_unlock(&pcb->pcb_mtx);
1527
mtx_unlock(&ng_btsocket_hci_raw_sockets_mtx);
1528
1529
mtx_destroy(&pcb->pcb_mtx);
1530
1531
bzero(pcb, sizeof(*pcb));
1532
free(pcb, M_NETGRAPH_BTSOCKET_HCI_RAW);
1533
1534
so->so_pcb = NULL;
1535
} /* ng_btsocket_hci_raw_detach */
1536
1537
/*
1538
* Disconnect raw HCI socket
1539
*/
1540
1541
int
1542
ng_btsocket_hci_raw_disconnect(struct socket *so)
1543
{
1544
ng_btsocket_hci_raw_pcb_p pcb = so2hci_raw_pcb(so);
1545
1546
if (pcb == NULL)
1547
return (EINVAL);
1548
if (ng_btsocket_hci_raw_node == NULL)
1549
return (EINVAL);
1550
1551
mtx_lock(&pcb->pcb_mtx);
1552
soisdisconnected(so);
1553
mtx_unlock(&pcb->pcb_mtx);
1554
1555
return (0);
1556
} /* ng_btsocket_hci_raw_disconnect */
1557
1558
/*
1559
* Send data
1560
*/
1561
1562
int
1563
ng_btsocket_hci_raw_send(struct socket *so, int flags, struct mbuf *m,
1564
struct sockaddr *sa, struct mbuf *control, struct thread *td)
1565
{
1566
ng_btsocket_hci_raw_pcb_p pcb = so2hci_raw_pcb(so);
1567
struct mbuf *nam = NULL;
1568
int error = 0;
1569
1570
if (ng_btsocket_hci_raw_node == NULL) {
1571
error = ENETDOWN;
1572
goto drop;
1573
}
1574
if (pcb == NULL) {
1575
error = EINVAL;
1576
goto drop;
1577
}
1578
if (control != NULL) {
1579
error = EINVAL;
1580
goto drop;
1581
}
1582
1583
if (m->m_pkthdr.len < sizeof(ng_hci_cmd_pkt_t) ||
1584
m->m_pkthdr.len > sizeof(ng_hci_cmd_pkt_t) + NG_HCI_CMD_PKT_SIZE) {
1585
error = EMSGSIZE;
1586
goto drop;
1587
}
1588
1589
if (m->m_len < sizeof(ng_hci_cmd_pkt_t)) {
1590
if ((m = m_pullup(m, sizeof(ng_hci_cmd_pkt_t))) == NULL) {
1591
error = ENOBUFS;
1592
goto drop;
1593
}
1594
}
1595
if (*mtod(m, u_int8_t *) != NG_HCI_CMD_PKT) {
1596
error = ENOTSUP;
1597
goto drop;
1598
}
1599
1600
if (sa != NULL) {
1601
if (sa->sa_family != AF_BLUETOOTH) {
1602
error = EAFNOSUPPORT;
1603
goto drop;
1604
}
1605
if (sa->sa_len != sizeof(struct sockaddr_hci)) {
1606
error = EINVAL;
1607
goto drop;
1608
}
1609
}
1610
1611
mtx_lock(&pcb->pcb_mtx);
1612
1613
error = ng_btsocket_hci_raw_filter(pcb, m, 0);
1614
if (error != 0) {
1615
mtx_unlock(&pcb->pcb_mtx);
1616
goto drop;
1617
}
1618
1619
if (sa == NULL) {
1620
if (pcb->addr.hci_node[0] == 0) {
1621
mtx_unlock(&pcb->pcb_mtx);
1622
error = EDESTADDRREQ;
1623
goto drop;
1624
}
1625
1626
sa = (struct sockaddr *) &pcb->addr;
1627
}
1628
1629
MGET(nam, M_NOWAIT, MT_SONAME);
1630
if (nam == NULL) {
1631
mtx_unlock(&pcb->pcb_mtx);
1632
error = ENOBUFS;
1633
goto drop;
1634
}
1635
1636
nam->m_len = sizeof(struct sockaddr_hci);
1637
bcopy(sa,mtod(nam, struct sockaddr_hci *),sizeof(struct sockaddr_hci));
1638
1639
nam->m_next = m;
1640
m = NULL;
1641
1642
mtx_unlock(&pcb->pcb_mtx);
1643
1644
return (ng_send_fn(ng_btsocket_hci_raw_node, NULL,
1645
ng_btsocket_hci_raw_output, nam, 0));
1646
drop:
1647
NG_FREE_M(control); /* NG_FREE_M checks for != NULL */
1648
NG_FREE_M(nam);
1649
NG_FREE_M(m);
1650
1651
return (error);
1652
} /* ng_btsocket_hci_raw_send */
1653
1654
/*
1655
* Get socket address
1656
*/
1657
1658
int
1659
ng_btsocket_hci_raw_sockaddr(struct socket *so, struct sockaddr *sa)
1660
{
1661
ng_btsocket_hci_raw_pcb_p pcb = so2hci_raw_pcb(so);
1662
struct sockaddr_hci *hci = (struct sockaddr_hci *)sa;
1663
1664
if (pcb == NULL)
1665
return (EINVAL);
1666
if (ng_btsocket_hci_raw_node == NULL)
1667
return (EINVAL);
1668
1669
*hci = (struct sockaddr_hci ){
1670
.hci_len = sizeof(struct sockaddr_hci),
1671
.hci_family = AF_BLUETOOTH,
1672
};
1673
1674
mtx_lock(&pcb->pcb_mtx);
1675
strlcpy(hci->hci_node, pcb->addr.hci_node, sizeof(hci->hci_node));
1676
mtx_unlock(&pcb->pcb_mtx);
1677
1678
return (0);
1679
}
1680
1681