Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/netgraph/bluetooth/socket/ng_btsocket_l2cap_raw.c
34677 views
1
/*
2
* ng_btsocket_l2cap_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_l2cap_raw.c,v 1.12 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/errno.h>
40
#include <sys/filedesc.h>
41
#include <sys/ioccom.h>
42
#include <sys/kernel.h>
43
#include <sys/lock.h>
44
#include <sys/malloc.h>
45
#include <sys/mbuf.h>
46
#include <sys/mutex.h>
47
#include <sys/priv.h>
48
#include <sys/protosw.h>
49
#include <sys/queue.h>
50
#include <sys/socket.h>
51
#include <sys/socketvar.h>
52
#include <sys/sysctl.h>
53
#include <sys/taskqueue.h>
54
55
#include <net/vnet.h>
56
57
#include <netgraph/ng_message.h>
58
#include <netgraph/netgraph.h>
59
#include <netgraph/bluetooth/include/ng_bluetooth.h>
60
#include <netgraph/bluetooth/include/ng_hci.h>
61
#include <netgraph/bluetooth/include/ng_l2cap.h>
62
#include <netgraph/bluetooth/include/ng_btsocket.h>
63
#include <netgraph/bluetooth/include/ng_btsocket_l2cap.h>
64
65
/* MALLOC define */
66
#ifdef NG_SEPARATE_MALLOC
67
static MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_L2CAP_RAW,
68
"netgraph_btsocks_l2cap_raw", "Netgraph Bluetooth raw L2CAP sockets");
69
#else
70
#define M_NETGRAPH_BTSOCKET_L2CAP_RAW M_NETGRAPH
71
#endif /* NG_SEPARATE_MALLOC */
72
73
/* Netgraph node methods */
74
static ng_constructor_t ng_btsocket_l2cap_raw_node_constructor;
75
static ng_rcvmsg_t ng_btsocket_l2cap_raw_node_rcvmsg;
76
static ng_shutdown_t ng_btsocket_l2cap_raw_node_shutdown;
77
static ng_newhook_t ng_btsocket_l2cap_raw_node_newhook;
78
static ng_connect_t ng_btsocket_l2cap_raw_node_connect;
79
static ng_rcvdata_t ng_btsocket_l2cap_raw_node_rcvdata;
80
static ng_disconnect_t ng_btsocket_l2cap_raw_node_disconnect;
81
82
static void ng_btsocket_l2cap_raw_input (void *, int);
83
static void ng_btsocket_l2cap_raw_rtclean (void *, int);
84
static void ng_btsocket_l2cap_raw_get_token (u_int32_t *);
85
86
static int ng_btsocket_l2cap_raw_send_ngmsg
87
(hook_p, int, void *, int);
88
static int ng_btsocket_l2cap_raw_send_sync_ngmsg
89
(ng_btsocket_l2cap_raw_pcb_p, int, void *, int);
90
91
#define ng_btsocket_l2cap_raw_wakeup_input_task() \
92
taskqueue_enqueue(taskqueue_swi, &ng_btsocket_l2cap_raw_queue_task)
93
94
#define ng_btsocket_l2cap_raw_wakeup_route_task() \
95
taskqueue_enqueue(taskqueue_swi, &ng_btsocket_l2cap_raw_rt_task)
96
97
/* Netgraph type descriptor */
98
static struct ng_type typestruct = {
99
.version = NG_ABI_VERSION,
100
.name = NG_BTSOCKET_L2CAP_RAW_NODE_TYPE,
101
.constructor = ng_btsocket_l2cap_raw_node_constructor,
102
.rcvmsg = ng_btsocket_l2cap_raw_node_rcvmsg,
103
.shutdown = ng_btsocket_l2cap_raw_node_shutdown,
104
.newhook = ng_btsocket_l2cap_raw_node_newhook,
105
.connect = ng_btsocket_l2cap_raw_node_connect,
106
.rcvdata = ng_btsocket_l2cap_raw_node_rcvdata,
107
.disconnect = ng_btsocket_l2cap_raw_node_disconnect,
108
};
109
110
/* Globals */
111
extern int ifqmaxlen;
112
static u_int32_t ng_btsocket_l2cap_raw_debug_level;
113
static u_int32_t ng_btsocket_l2cap_raw_ioctl_timeout;
114
static node_p ng_btsocket_l2cap_raw_node;
115
static struct ng_bt_itemq ng_btsocket_l2cap_raw_queue;
116
static struct mtx ng_btsocket_l2cap_raw_queue_mtx;
117
static struct task ng_btsocket_l2cap_raw_queue_task;
118
static LIST_HEAD(, ng_btsocket_l2cap_raw_pcb) ng_btsocket_l2cap_raw_sockets;
119
static struct mtx ng_btsocket_l2cap_raw_sockets_mtx;
120
static u_int32_t ng_btsocket_l2cap_raw_token;
121
static struct mtx ng_btsocket_l2cap_raw_token_mtx;
122
static LIST_HEAD(, ng_btsocket_l2cap_rtentry) ng_btsocket_l2cap_raw_rt;
123
static struct mtx ng_btsocket_l2cap_raw_rt_mtx;
124
static struct task ng_btsocket_l2cap_raw_rt_task;
125
static struct timeval ng_btsocket_l2cap_raw_lasttime;
126
static int ng_btsocket_l2cap_raw_curpps;
127
128
/* Sysctl tree */
129
SYSCTL_DECL(_net_bluetooth_l2cap_sockets);
130
static SYSCTL_NODE(_net_bluetooth_l2cap_sockets, OID_AUTO, raw,
131
CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
132
"Bluetooth raw L2CAP sockets family");
133
SYSCTL_UINT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, debug_level,
134
CTLFLAG_RW,
135
&ng_btsocket_l2cap_raw_debug_level, NG_BTSOCKET_WARN_LEVEL,
136
"Bluetooth raw L2CAP sockets debug level");
137
SYSCTL_UINT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, ioctl_timeout,
138
CTLFLAG_RW,
139
&ng_btsocket_l2cap_raw_ioctl_timeout, 5,
140
"Bluetooth raw L2CAP sockets ioctl timeout");
141
SYSCTL_UINT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_len,
142
CTLFLAG_RD,
143
&ng_btsocket_l2cap_raw_queue.len, 0,
144
"Bluetooth raw L2CAP sockets input queue length");
145
SYSCTL_UINT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_maxlen,
146
CTLFLAG_RD,
147
&ng_btsocket_l2cap_raw_queue.maxlen, 0,
148
"Bluetooth raw L2CAP sockets input queue max. length");
149
SYSCTL_UINT(_net_bluetooth_l2cap_sockets_raw, OID_AUTO, queue_drops,
150
CTLFLAG_RD,
151
&ng_btsocket_l2cap_raw_queue.drops, 0,
152
"Bluetooth raw L2CAP sockets input queue drops");
153
154
/* Debug */
155
#define NG_BTSOCKET_L2CAP_RAW_INFO \
156
if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_INFO_LEVEL && \
157
ppsratecheck(&ng_btsocket_l2cap_raw_lasttime, &ng_btsocket_l2cap_raw_curpps, 1)) \
158
printf
159
160
#define NG_BTSOCKET_L2CAP_RAW_WARN \
161
if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_WARN_LEVEL && \
162
ppsratecheck(&ng_btsocket_l2cap_raw_lasttime, &ng_btsocket_l2cap_raw_curpps, 1)) \
163
printf
164
165
#define NG_BTSOCKET_L2CAP_RAW_ERR \
166
if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_ERR_LEVEL && \
167
ppsratecheck(&ng_btsocket_l2cap_raw_lasttime, &ng_btsocket_l2cap_raw_curpps, 1)) \
168
printf
169
170
#define NG_BTSOCKET_L2CAP_RAW_ALERT \
171
if (ng_btsocket_l2cap_raw_debug_level >= NG_BTSOCKET_ALERT_LEVEL && \
172
ppsratecheck(&ng_btsocket_l2cap_raw_lasttime, &ng_btsocket_l2cap_raw_curpps, 1)) \
173
printf
174
175
/*****************************************************************************
176
*****************************************************************************
177
** Netgraph node interface
178
*****************************************************************************
179
*****************************************************************************/
180
181
/*
182
* Netgraph node constructor. Do not allow to create node of this type.
183
*/
184
185
static int
186
ng_btsocket_l2cap_raw_node_constructor(node_p node)
187
{
188
return (EINVAL);
189
} /* ng_btsocket_l2cap_raw_node_constructor */
190
191
/*
192
* Do local shutdown processing. Let old node go and create new fresh one.
193
*/
194
195
static int
196
ng_btsocket_l2cap_raw_node_shutdown(node_p node)
197
{
198
int error = 0;
199
200
NG_NODE_UNREF(node);
201
202
/* Create new node */
203
error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_raw_node);
204
if (error != 0) {
205
NG_BTSOCKET_L2CAP_RAW_ALERT(
206
"%s: Could not create Netgraph node, error=%d\n", __func__, error);
207
208
ng_btsocket_l2cap_raw_node = NULL;
209
210
return (error);
211
}
212
213
error = ng_name_node(ng_btsocket_l2cap_raw_node,
214
NG_BTSOCKET_L2CAP_RAW_NODE_TYPE);
215
if (error != 0) {
216
NG_BTSOCKET_L2CAP_RAW_ALERT(
217
"%s: Could not name Netgraph node, error=%d\n", __func__, error);
218
219
NG_NODE_UNREF(ng_btsocket_l2cap_raw_node);
220
ng_btsocket_l2cap_raw_node = NULL;
221
222
return (error);
223
}
224
225
return (0);
226
} /* ng_btsocket_l2cap_raw_node_shutdown */
227
228
/*
229
* We allow any hook to be connected to the node.
230
*/
231
232
static int
233
ng_btsocket_l2cap_raw_node_newhook(node_p node, hook_p hook, char const *name)
234
{
235
return (0);
236
} /* ng_btsocket_l2cap_raw_node_newhook */
237
238
/*
239
* Just say "YEP, that's OK by me!"
240
*/
241
242
static int
243
ng_btsocket_l2cap_raw_node_connect(hook_p hook)
244
{
245
NG_HOOK_SET_PRIVATE(hook, NULL);
246
NG_HOOK_REF(hook); /* Keep extra reference to the hook */
247
248
return (0);
249
} /* ng_btsocket_l2cap_raw_node_connect */
250
251
/*
252
* Hook disconnection. Schedule route cleanup task
253
*/
254
255
static int
256
ng_btsocket_l2cap_raw_node_disconnect(hook_p hook)
257
{
258
/*
259
* If hook has private information than we must have this hook in
260
* the routing table and must schedule cleaning for the routing table.
261
* Otherwise hook was connected but we never got "hook_info" message,
262
* so we have never added this hook to the routing table and it save
263
* to just delete it.
264
*/
265
266
if (NG_HOOK_PRIVATE(hook) != NULL)
267
return (ng_btsocket_l2cap_raw_wakeup_route_task());
268
269
NG_HOOK_UNREF(hook); /* Remove extra reference */
270
271
return (0);
272
} /* ng_btsocket_l2cap_raw_node_disconnect */
273
274
/*
275
* Process incoming messages
276
*/
277
278
static int
279
ng_btsocket_l2cap_raw_node_rcvmsg(node_p node, item_p item, hook_p hook)
280
{
281
struct ng_mesg *msg = NGI_MSG(item); /* item still has message */
282
int error = 0;
283
284
if (msg != NULL && msg->header.typecookie == NGM_L2CAP_COOKIE) {
285
/*
286
* NGM_L2CAP_NODE_HOOK_INFO is special message initiated by
287
* L2CAP layer. Ignore all other messages if they are not
288
* replies or token is zero
289
*/
290
291
if (msg->header.cmd != NGM_L2CAP_NODE_HOOK_INFO) {
292
if (msg->header.token == 0 ||
293
!(msg->header.flags & NGF_RESP)) {
294
NG_FREE_ITEM(item);
295
return (0);
296
}
297
}
298
299
mtx_lock(&ng_btsocket_l2cap_raw_queue_mtx);
300
if (NG_BT_ITEMQ_FULL(&ng_btsocket_l2cap_raw_queue)) {
301
NG_BTSOCKET_L2CAP_RAW_ERR(
302
"%s: Input queue is full\n", __func__);
303
304
NG_BT_ITEMQ_DROP(&ng_btsocket_l2cap_raw_queue);
305
NG_FREE_ITEM(item);
306
error = ENOBUFS;
307
} else {
308
if (hook != NULL) {
309
NG_HOOK_REF(hook);
310
NGI_SET_HOOK(item, hook);
311
}
312
313
NG_BT_ITEMQ_ENQUEUE(&ng_btsocket_l2cap_raw_queue, item);
314
error = ng_btsocket_l2cap_raw_wakeup_input_task();
315
}
316
mtx_unlock(&ng_btsocket_l2cap_raw_queue_mtx);
317
} else {
318
NG_FREE_ITEM(item);
319
error = EINVAL;
320
}
321
322
return (error);
323
} /* ng_btsocket_l2cap_raw_node_rcvmsg */
324
325
/*
326
* Receive data on a hook
327
*/
328
329
static int
330
ng_btsocket_l2cap_raw_node_rcvdata(hook_p hook, item_p item)
331
{
332
NG_FREE_ITEM(item);
333
334
return (EINVAL);
335
} /* ng_btsocket_l2cap_raw_node_rcvdata */
336
337
/*****************************************************************************
338
*****************************************************************************
339
** Socket interface
340
*****************************************************************************
341
*****************************************************************************/
342
343
/*
344
* L2CAP sockets input routine
345
*/
346
347
static void
348
ng_btsocket_l2cap_raw_input(void *context, int pending)
349
{
350
item_p item = NULL;
351
hook_p hook = NULL;
352
struct ng_mesg *msg = NULL;
353
354
for (;;) {
355
mtx_lock(&ng_btsocket_l2cap_raw_queue_mtx);
356
NG_BT_ITEMQ_DEQUEUE(&ng_btsocket_l2cap_raw_queue, item);
357
mtx_unlock(&ng_btsocket_l2cap_raw_queue_mtx);
358
359
if (item == NULL)
360
break;
361
362
KASSERT((item->el_flags & NGQF_TYPE) == NGQF_MESG,
363
("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE)));
364
365
NGI_GET_MSG(item, msg);
366
NGI_GET_HOOK(item, hook);
367
NG_FREE_ITEM(item);
368
369
switch (msg->header.cmd) {
370
case NGM_L2CAP_NODE_HOOK_INFO: {
371
ng_btsocket_l2cap_rtentry_t *rt = NULL;
372
373
if (hook == NULL || NG_HOOK_NOT_VALID(hook) ||
374
msg->header.arglen != sizeof(bdaddr_t))
375
break;
376
377
if (bcmp(msg->data, NG_HCI_BDADDR_ANY,
378
sizeof(bdaddr_t)) == 0)
379
break;
380
381
rt = (ng_btsocket_l2cap_rtentry_t *)
382
NG_HOOK_PRIVATE(hook);
383
if (rt == NULL) {
384
rt = malloc(sizeof(*rt),
385
M_NETGRAPH_BTSOCKET_L2CAP_RAW,
386
M_NOWAIT|M_ZERO);
387
if (rt == NULL)
388
break;
389
390
NG_HOOK_SET_PRIVATE(hook, rt);
391
392
mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
393
394
LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_rt,
395
rt, next);
396
} else
397
mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
398
399
bcopy(msg->data, &rt->src, sizeof(rt->src));
400
rt->hook = hook;
401
402
NG_BTSOCKET_L2CAP_RAW_INFO(
403
"%s: Updating hook \"%s\", src bdaddr=%x:%x:%x:%x:%x:%x\n",
404
__func__, NG_HOOK_NAME(hook),
405
rt->src.b[5], rt->src.b[4], rt->src.b[3],
406
rt->src.b[2], rt->src.b[1], rt->src.b[0]);
407
408
mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
409
} break;
410
411
case NGM_L2CAP_NODE_GET_FLAGS:
412
case NGM_L2CAP_NODE_GET_DEBUG:
413
case NGM_L2CAP_NODE_GET_CON_LIST:
414
case NGM_L2CAP_NODE_GET_CHAN_LIST:
415
case NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO:
416
case NGM_L2CAP_L2CA_PING:
417
case NGM_L2CAP_L2CA_GET_INFO: {
418
ng_btsocket_l2cap_raw_pcb_p pcb = NULL;
419
420
mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
421
422
LIST_FOREACH(pcb,&ng_btsocket_l2cap_raw_sockets,next) {
423
mtx_lock(&pcb->pcb_mtx);
424
425
if (pcb->token == msg->header.token) {
426
pcb->msg = msg;
427
msg = NULL;
428
wakeup(&pcb->msg);
429
mtx_unlock(&pcb->pcb_mtx);
430
break;
431
}
432
433
mtx_unlock(&pcb->pcb_mtx);
434
}
435
436
mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
437
} break;
438
439
default:
440
NG_BTSOCKET_L2CAP_RAW_WARN(
441
"%s: Unknown message, cmd=%d\n", __func__, msg->header.cmd);
442
break;
443
}
444
445
if (hook != NULL)
446
NG_HOOK_UNREF(hook); /* remove extra reference */
447
448
NG_FREE_MSG(msg); /* Checks for msg != NULL */
449
}
450
} /* ng_btsocket_l2cap_raw_input */
451
452
/*
453
* Route cleanup task. Gets scheduled when hook is disconnected. Here we
454
* will find all sockets that use "invalid" hook and disconnect them.
455
*/
456
457
static void
458
ng_btsocket_l2cap_raw_rtclean(void *context, int pending)
459
{
460
ng_btsocket_l2cap_raw_pcb_p pcb = NULL;
461
ng_btsocket_l2cap_rtentry_p rt = NULL;
462
463
/*
464
* First disconnect all sockets that use "invalid" hook
465
*/
466
467
mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
468
469
LIST_FOREACH(pcb, &ng_btsocket_l2cap_raw_sockets, next) {
470
mtx_lock(&pcb->pcb_mtx);
471
472
if (pcb->rt != NULL &&
473
pcb->rt->hook != NULL && NG_HOOK_NOT_VALID(pcb->rt->hook)) {
474
if (pcb->so != NULL &&
475
pcb->so->so_state & SS_ISCONNECTED)
476
soisdisconnected(pcb->so);
477
478
pcb->rt = NULL;
479
}
480
481
mtx_unlock(&pcb->pcb_mtx);
482
}
483
484
mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
485
486
/*
487
* Now cleanup routing table
488
*/
489
490
mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
491
492
for (rt = LIST_FIRST(&ng_btsocket_l2cap_raw_rt); rt != NULL; ) {
493
ng_btsocket_l2cap_rtentry_p rt_next = LIST_NEXT(rt, next);
494
495
if (rt->hook != NULL && NG_HOOK_NOT_VALID(rt->hook)) {
496
LIST_REMOVE(rt, next);
497
498
NG_HOOK_SET_PRIVATE(rt->hook, NULL);
499
NG_HOOK_UNREF(rt->hook); /* Remove extra reference */
500
501
bzero(rt, sizeof(*rt));
502
free(rt, M_NETGRAPH_BTSOCKET_L2CAP_RAW);
503
}
504
505
rt = rt_next;
506
}
507
508
mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
509
} /* ng_btsocket_l2cap_raw_rtclean */
510
511
/*
512
* Initialize everything
513
*/
514
515
static void
516
ng_btsocket_l2cap_raw_init(void *arg __unused)
517
{
518
int error = 0;
519
520
ng_btsocket_l2cap_raw_node = NULL;
521
ng_btsocket_l2cap_raw_debug_level = NG_BTSOCKET_WARN_LEVEL;
522
ng_btsocket_l2cap_raw_ioctl_timeout = 5;
523
524
/* Register Netgraph node type */
525
error = ng_newtype(&typestruct);
526
if (error != 0) {
527
NG_BTSOCKET_L2CAP_RAW_ALERT(
528
"%s: Could not register Netgraph node type, error=%d\n", __func__, error);
529
530
return;
531
}
532
533
/* Create Netgrapg node */
534
error = ng_make_node_common(&typestruct, &ng_btsocket_l2cap_raw_node);
535
if (error != 0) {
536
NG_BTSOCKET_L2CAP_RAW_ALERT(
537
"%s: Could not create Netgraph node, error=%d\n", __func__, error);
538
539
ng_btsocket_l2cap_raw_node = NULL;
540
541
return;
542
}
543
544
error = ng_name_node(ng_btsocket_l2cap_raw_node,
545
NG_BTSOCKET_L2CAP_RAW_NODE_TYPE);
546
if (error != 0) {
547
NG_BTSOCKET_L2CAP_RAW_ALERT(
548
"%s: Could not name Netgraph node, error=%d\n", __func__, error);
549
550
NG_NODE_UNREF(ng_btsocket_l2cap_raw_node);
551
ng_btsocket_l2cap_raw_node = NULL;
552
553
return;
554
}
555
556
/* Create input queue */
557
NG_BT_ITEMQ_INIT(&ng_btsocket_l2cap_raw_queue, ifqmaxlen);
558
mtx_init(&ng_btsocket_l2cap_raw_queue_mtx,
559
"btsocks_l2cap_raw_queue_mtx", NULL, MTX_DEF);
560
TASK_INIT(&ng_btsocket_l2cap_raw_queue_task, 0,
561
ng_btsocket_l2cap_raw_input, NULL);
562
563
/* Create list of sockets */
564
LIST_INIT(&ng_btsocket_l2cap_raw_sockets);
565
mtx_init(&ng_btsocket_l2cap_raw_sockets_mtx,
566
"btsocks_l2cap_raw_sockets_mtx", NULL, MTX_DEF);
567
568
/* Tokens */
569
ng_btsocket_l2cap_raw_token = 0;
570
mtx_init(&ng_btsocket_l2cap_raw_token_mtx,
571
"btsocks_l2cap_raw_token_mtx", NULL, MTX_DEF);
572
573
/* Routing table */
574
LIST_INIT(&ng_btsocket_l2cap_raw_rt);
575
mtx_init(&ng_btsocket_l2cap_raw_rt_mtx,
576
"btsocks_l2cap_raw_rt_mtx", NULL, MTX_DEF);
577
TASK_INIT(&ng_btsocket_l2cap_raw_rt_task, 0,
578
ng_btsocket_l2cap_raw_rtclean, NULL);
579
} /* ng_btsocket_l2cap_raw_init */
580
SYSINIT(ng_btsocket_l2cap_raw_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD,
581
ng_btsocket_l2cap_raw_init, NULL);
582
583
/*
584
* Abort connection on socket
585
*/
586
587
void
588
ng_btsocket_l2cap_raw_abort(struct socket *so)
589
{
590
591
(void)ng_btsocket_l2cap_raw_disconnect(so);
592
} /* ng_btsocket_l2cap_raw_abort */
593
594
void
595
ng_btsocket_l2cap_raw_close(struct socket *so)
596
{
597
598
(void)ng_btsocket_l2cap_raw_disconnect(so);
599
} /* ng_btsocket_l2cap_raw_close */
600
601
/*
602
* Create and attach new socket
603
*/
604
605
int
606
ng_btsocket_l2cap_raw_attach(struct socket *so, int proto, struct thread *td)
607
{
608
ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
609
int error;
610
611
if (pcb != NULL)
612
return (EISCONN);
613
614
if (ng_btsocket_l2cap_raw_node == NULL)
615
return (EPROTONOSUPPORT);
616
if (so->so_type != SOCK_RAW)
617
return (ESOCKTNOSUPPORT);
618
619
/* Reserve send and receive space if it is not reserved yet */
620
error = soreserve(so, NG_BTSOCKET_L2CAP_RAW_SENDSPACE,
621
NG_BTSOCKET_L2CAP_RAW_RECVSPACE);
622
if (error != 0)
623
return (error);
624
625
/* Allocate the PCB */
626
pcb = malloc(sizeof(*pcb),
627
M_NETGRAPH_BTSOCKET_L2CAP_RAW, M_NOWAIT|M_ZERO);
628
if (pcb == NULL)
629
return (ENOMEM);
630
631
/* Link the PCB and the socket */
632
so->so_pcb = (caddr_t) pcb;
633
pcb->so = so;
634
635
if (priv_check(td, PRIV_NETBLUETOOTH_RAW) == 0)
636
pcb->flags |= NG_BTSOCKET_L2CAP_RAW_PRIVILEGED;
637
638
mtx_init(&pcb->pcb_mtx, "btsocks_l2cap_raw_pcb_mtx", NULL, MTX_DEF);
639
640
/* Add the PCB to the list */
641
mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
642
LIST_INSERT_HEAD(&ng_btsocket_l2cap_raw_sockets, pcb, next);
643
mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
644
645
return (0);
646
} /* ng_btsocket_l2cap_raw_attach */
647
648
/*
649
* Bind socket
650
*/
651
652
int
653
ng_btsocket_l2cap_raw_bind(struct socket *so, struct sockaddr *nam,
654
struct thread *td)
655
{
656
ng_btsocket_l2cap_raw_pcb_t *pcb = so2l2cap_raw_pcb(so);
657
struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *) nam;
658
ng_btsocket_l2cap_rtentry_t *rt = NULL;
659
660
if (pcb == NULL)
661
return (EINVAL);
662
if (ng_btsocket_l2cap_raw_node == NULL)
663
return (EINVAL);
664
665
if (sa == NULL)
666
return (EINVAL);
667
if (sa->l2cap_family != AF_BLUETOOTH)
668
return (EAFNOSUPPORT);
669
if((sa->l2cap_len != sizeof(*sa))&&
670
(sa->l2cap_len != sizeof(struct sockaddr_l2cap_compat)))
671
return (EINVAL);
672
673
if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY,
674
sizeof(sa->l2cap_bdaddr)) != 0) {
675
mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
676
677
LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) {
678
if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
679
continue;
680
681
if (bcmp(&sa->l2cap_bdaddr, &rt->src,
682
sizeof(rt->src)) == 0)
683
break;
684
}
685
686
mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
687
688
if (rt == NULL)
689
return (ENETDOWN);
690
} else
691
rt = NULL;
692
693
mtx_lock(&pcb->pcb_mtx);
694
bcopy(&sa->l2cap_bdaddr, &pcb->src, sizeof(pcb->src));
695
pcb->rt = rt;
696
mtx_unlock(&pcb->pcb_mtx);
697
698
return (0);
699
} /* ng_btsocket_l2cap_raw_bind */
700
701
/*
702
* Connect socket
703
*/
704
705
int
706
ng_btsocket_l2cap_raw_connect(struct socket *so, struct sockaddr *nam,
707
struct thread *td)
708
{
709
ng_btsocket_l2cap_raw_pcb_t *pcb = so2l2cap_raw_pcb(so);
710
struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *) nam;
711
ng_btsocket_l2cap_rtentry_t *rt = NULL;
712
int error;
713
714
if (pcb == NULL)
715
return (EINVAL);
716
if (ng_btsocket_l2cap_raw_node == NULL)
717
return (EINVAL);
718
719
if (sa == NULL)
720
return (EINVAL);
721
if (sa->l2cap_family != AF_BLUETOOTH)
722
return (EAFNOSUPPORT);
723
if((sa->l2cap_len != sizeof(*sa))&&
724
(sa->l2cap_len != sizeof(struct sockaddr_l2cap_compat)))
725
return (EINVAL);
726
727
if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
728
return (EINVAL);
729
730
mtx_lock(&pcb->pcb_mtx);
731
732
bcopy(&sa->l2cap_bdaddr, &pcb->dst, sizeof(pcb->dst));
733
734
if (bcmp(&pcb->src, &pcb->dst, sizeof(pcb->src)) == 0) {
735
mtx_unlock(&pcb->pcb_mtx);
736
737
return (EADDRNOTAVAIL);
738
}
739
740
/*
741
* If there is route already - use it
742
*/
743
744
if (pcb->rt != NULL) {
745
soisconnected(so);
746
mtx_unlock(&pcb->pcb_mtx);
747
748
return (0);
749
}
750
751
/*
752
* Find the first hook that does not match specified destination address
753
*/
754
755
mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
756
757
LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) {
758
if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
759
continue;
760
761
if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0)
762
break;
763
}
764
765
if (rt != NULL) {
766
soisconnected(so);
767
768
pcb->rt = rt;
769
bcopy(&rt->src, &pcb->src, sizeof(pcb->src));
770
771
error = 0;
772
} else
773
error = ENETDOWN;
774
775
mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
776
mtx_unlock(&pcb->pcb_mtx);
777
778
return (error);
779
} /* ng_btsocket_l2cap_raw_connect */
780
781
/*
782
* Process ioctl's calls on socket
783
*/
784
785
int
786
ng_btsocket_l2cap_raw_control(struct socket *so, u_long cmd, void *data,
787
struct ifnet *ifp, struct thread *td)
788
{
789
ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
790
struct ng_mesg *msg = NULL;
791
int error = 0;
792
793
if (pcb == NULL)
794
return (EINVAL);
795
if (ng_btsocket_l2cap_raw_node == NULL)
796
return (EINVAL);
797
798
mtx_lock(&pcb->pcb_mtx);
799
800
/* Check if we route info */
801
if (pcb->rt == NULL) {
802
mtx_unlock(&pcb->pcb_mtx);
803
return (EHOSTUNREACH);
804
}
805
806
/* Check if we have pending ioctl() */
807
if (pcb->token != 0) {
808
mtx_unlock(&pcb->pcb_mtx);
809
return (EBUSY);
810
}
811
812
switch (cmd) {
813
case SIOC_L2CAP_NODE_GET_FLAGS: {
814
struct ng_btsocket_l2cap_raw_node_flags *p =
815
(struct ng_btsocket_l2cap_raw_node_flags *) data;
816
817
error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
818
NGM_L2CAP_NODE_GET_FLAGS,
819
&p->flags, sizeof(p->flags));
820
} break;
821
822
case SIOC_L2CAP_NODE_GET_DEBUG: {
823
struct ng_btsocket_l2cap_raw_node_debug *p =
824
(struct ng_btsocket_l2cap_raw_node_debug *) data;
825
826
error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
827
NGM_L2CAP_NODE_GET_DEBUG,
828
&p->debug, sizeof(p->debug));
829
} break;
830
831
case SIOC_L2CAP_NODE_SET_DEBUG: {
832
struct ng_btsocket_l2cap_raw_node_debug *p =
833
(struct ng_btsocket_l2cap_raw_node_debug *) data;
834
835
if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)
836
error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook,
837
NGM_L2CAP_NODE_SET_DEBUG,
838
&p->debug, sizeof(p->debug));
839
else
840
error = EPERM;
841
} break;
842
843
case SIOC_L2CAP_NODE_GET_CON_LIST: {
844
struct ng_btsocket_l2cap_raw_con_list *p =
845
(struct ng_btsocket_l2cap_raw_con_list *) data;
846
ng_l2cap_node_con_list_ep *p1 = NULL;
847
ng_l2cap_node_con_ep *p2 = NULL;
848
849
if (p->num_connections == 0 ||
850
p->num_connections > NG_L2CAP_MAX_CON_NUM ||
851
p->connections == NULL) {
852
mtx_unlock(&pcb->pcb_mtx);
853
return (EINVAL);
854
}
855
856
NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_GET_CON_LIST,
857
0, M_NOWAIT);
858
if (msg == NULL) {
859
mtx_unlock(&pcb->pcb_mtx);
860
return (ENOMEM);
861
}
862
ng_btsocket_l2cap_raw_get_token(&msg->header.token);
863
pcb->token = msg->header.token;
864
pcb->msg = NULL;
865
866
NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
867
pcb->rt->hook, 0);
868
if (error != 0) {
869
pcb->token = 0;
870
mtx_unlock(&pcb->pcb_mtx);
871
return (error);
872
}
873
874
error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
875
ng_btsocket_l2cap_raw_ioctl_timeout * hz);
876
pcb->token = 0;
877
878
if (error != 0) {
879
mtx_unlock(&pcb->pcb_mtx);
880
return (error);
881
}
882
883
msg = pcb->msg;
884
pcb->msg = NULL;
885
886
mtx_unlock(&pcb->pcb_mtx);
887
888
if (msg != NULL &&
889
msg->header.cmd == NGM_L2CAP_NODE_GET_CON_LIST) {
890
/* Return data back to user space */
891
p1 = (ng_l2cap_node_con_list_ep *)(msg->data);
892
p2 = (ng_l2cap_node_con_ep *)(p1 + 1);
893
894
p->num_connections = min(p->num_connections,
895
p1->num_connections);
896
if (p->num_connections > 0)
897
error = copyout((caddr_t) p2,
898
(caddr_t) p->connections,
899
p->num_connections * sizeof(*p2));
900
} else
901
error = EINVAL;
902
903
NG_FREE_MSG(msg); /* checks for != NULL */
904
return (error);
905
} /* NOTREACHED */
906
907
case SIOC_L2CAP_NODE_GET_CHAN_LIST: {
908
struct ng_btsocket_l2cap_raw_chan_list *p =
909
(struct ng_btsocket_l2cap_raw_chan_list *) data;
910
ng_l2cap_node_chan_list_ep *p1 = NULL;
911
ng_l2cap_node_chan_ep *p2 = NULL;
912
913
if (p->num_channels == 0 ||
914
p->num_channels > NG_L2CAP_MAX_CHAN_NUM ||
915
p->channels == NULL) {
916
mtx_unlock(&pcb->pcb_mtx);
917
return (EINVAL);
918
}
919
920
NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,
921
NGM_L2CAP_NODE_GET_CHAN_LIST, 0, M_NOWAIT);
922
if (msg == NULL) {
923
mtx_unlock(&pcb->pcb_mtx);
924
return (ENOMEM);
925
}
926
ng_btsocket_l2cap_raw_get_token(&msg->header.token);
927
pcb->token = msg->header.token;
928
pcb->msg = NULL;
929
930
NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
931
pcb->rt->hook, 0);
932
if (error != 0) {
933
pcb->token = 0;
934
mtx_unlock(&pcb->pcb_mtx);
935
return (error);
936
}
937
938
error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
939
ng_btsocket_l2cap_raw_ioctl_timeout * hz);
940
pcb->token = 0;
941
942
if (error != 0) {
943
mtx_unlock(&pcb->pcb_mtx);
944
return (error);
945
}
946
947
msg = pcb->msg;
948
pcb->msg = NULL;
949
950
mtx_unlock(&pcb->pcb_mtx);
951
952
if (msg != NULL &&
953
msg->header.cmd == NGM_L2CAP_NODE_GET_CHAN_LIST) {
954
/* Return data back to user space */
955
p1 = (ng_l2cap_node_chan_list_ep *)(msg->data);
956
p2 = (ng_l2cap_node_chan_ep *)(p1 + 1);
957
958
p->num_channels = min(p->num_channels,
959
p1->num_channels);
960
if (p->num_channels > 0)
961
error = copyout((caddr_t) p2,
962
(caddr_t) p->channels,
963
p->num_channels * sizeof(*p2));
964
} else
965
error = EINVAL;
966
967
NG_FREE_MSG(msg); /* checks for != NULL */
968
return (error);
969
} /* NOTREACHED */
970
971
case SIOC_L2CAP_L2CA_PING: {
972
struct ng_btsocket_l2cap_raw_ping *p =
973
(struct ng_btsocket_l2cap_raw_ping *) data;
974
ng_l2cap_l2ca_ping_ip *ip = NULL;
975
ng_l2cap_l2ca_ping_op *op = NULL;
976
977
if ((p->echo_size != 0 && p->echo_data == NULL) ||
978
p->echo_size > NG_L2CAP_MAX_ECHO_SIZE) {
979
mtx_unlock(&pcb->pcb_mtx);
980
return (EINVAL);
981
}
982
983
NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,
984
NGM_L2CAP_L2CA_PING, sizeof(*ip) + p->echo_size,
985
M_NOWAIT);
986
if (msg == NULL) {
987
mtx_unlock(&pcb->pcb_mtx);
988
return (ENOMEM);
989
}
990
ng_btsocket_l2cap_raw_get_token(&msg->header.token);
991
pcb->token = msg->header.token;
992
pcb->msg = NULL;
993
994
ip = (ng_l2cap_l2ca_ping_ip *)(msg->data);
995
bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr));
996
ip->echo_size = p->echo_size;
997
998
if (ip->echo_size > 0) {
999
mtx_unlock(&pcb->pcb_mtx);
1000
error = copyin(p->echo_data, ip + 1, p->echo_size);
1001
mtx_lock(&pcb->pcb_mtx);
1002
1003
if (error != 0) {
1004
NG_FREE_MSG(msg);
1005
pcb->token = 0;
1006
mtx_unlock(&pcb->pcb_mtx);
1007
return (error);
1008
}
1009
}
1010
1011
NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
1012
pcb->rt->hook, 0);
1013
if (error != 0) {
1014
pcb->token = 0;
1015
mtx_unlock(&pcb->pcb_mtx);
1016
return (error);
1017
}
1018
1019
error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
1020
bluetooth_l2cap_rtx_timeout());
1021
pcb->token = 0;
1022
1023
if (error != 0) {
1024
mtx_unlock(&pcb->pcb_mtx);
1025
return (error);
1026
}
1027
1028
msg = pcb->msg;
1029
pcb->msg = NULL;
1030
1031
mtx_unlock(&pcb->pcb_mtx);
1032
1033
if (msg != NULL &&
1034
msg->header.cmd == NGM_L2CAP_L2CA_PING) {
1035
/* Return data back to the user space */
1036
op = (ng_l2cap_l2ca_ping_op *)(msg->data);
1037
p->result = op->result;
1038
p->echo_size = min(p->echo_size, op->echo_size);
1039
1040
if (p->echo_size > 0)
1041
error = copyout(op + 1, p->echo_data,
1042
p->echo_size);
1043
} else
1044
error = EINVAL;
1045
1046
NG_FREE_MSG(msg); /* checks for != NULL */
1047
return (error);
1048
} /* NOTREACHED */
1049
1050
case SIOC_L2CAP_L2CA_GET_INFO: {
1051
struct ng_btsocket_l2cap_raw_get_info *p =
1052
(struct ng_btsocket_l2cap_raw_get_info *) data;
1053
ng_l2cap_l2ca_get_info_ip *ip = NULL;
1054
ng_l2cap_l2ca_get_info_op *op = NULL;
1055
1056
if (!(pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)) {
1057
mtx_unlock(&pcb->pcb_mtx);
1058
return (EPERM);
1059
}
1060
1061
if (p->info_size != 0 && p->info_data == NULL) {
1062
mtx_unlock(&pcb->pcb_mtx);
1063
return (EINVAL);
1064
}
1065
1066
NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,
1067
NGM_L2CAP_L2CA_GET_INFO, sizeof(*ip) + p->info_size,
1068
M_NOWAIT);
1069
if (msg == NULL) {
1070
mtx_unlock(&pcb->pcb_mtx);
1071
return (ENOMEM);
1072
}
1073
ng_btsocket_l2cap_raw_get_token(&msg->header.token);
1074
pcb->token = msg->header.token;
1075
pcb->msg = NULL;
1076
1077
ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data);
1078
bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr));
1079
ip->info_type = p->info_type;
1080
1081
NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
1082
pcb->rt->hook, 0);
1083
if (error != 0) {
1084
pcb->token = 0;
1085
mtx_unlock(&pcb->pcb_mtx);
1086
return (error);
1087
}
1088
1089
error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
1090
bluetooth_l2cap_rtx_timeout());
1091
pcb->token = 0;
1092
1093
if (error != 0) {
1094
mtx_unlock(&pcb->pcb_mtx);
1095
return (error);
1096
}
1097
1098
msg = pcb->msg;
1099
pcb->msg = NULL;
1100
1101
mtx_unlock(&pcb->pcb_mtx);
1102
1103
if (msg != NULL &&
1104
msg->header.cmd == NGM_L2CAP_L2CA_GET_INFO) {
1105
/* Return data back to the user space */
1106
op = (ng_l2cap_l2ca_get_info_op *)(msg->data);
1107
p->result = op->result;
1108
p->info_size = min(p->info_size, op->info_size);
1109
1110
if (p->info_size > 0)
1111
error = copyout(op + 1, p->info_data,
1112
p->info_size);
1113
} else
1114
error = EINVAL;
1115
1116
NG_FREE_MSG(msg); /* checks for != NULL */
1117
return (error);
1118
} /* NOTREACHED */
1119
1120
case SIOC_L2CAP_NODE_GET_AUTO_DISCON_TIMO: {
1121
struct ng_btsocket_l2cap_raw_auto_discon_timo *p =
1122
(struct ng_btsocket_l2cap_raw_auto_discon_timo *) data;
1123
1124
error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
1125
NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO,
1126
&p->timeout, sizeof(p->timeout));
1127
} break;
1128
1129
case SIOC_L2CAP_NODE_SET_AUTO_DISCON_TIMO: {
1130
struct ng_btsocket_l2cap_raw_auto_discon_timo *p =
1131
(struct ng_btsocket_l2cap_raw_auto_discon_timo *) data;
1132
1133
if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)
1134
error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook,
1135
NGM_L2CAP_NODE_SET_AUTO_DISCON_TIMO,
1136
&p->timeout, sizeof(p->timeout));
1137
else
1138
error = EPERM;
1139
} break;
1140
1141
default:
1142
error = EINVAL;
1143
break;
1144
}
1145
1146
mtx_unlock(&pcb->pcb_mtx);
1147
1148
return (error);
1149
} /* ng_btsocket_l2cap_raw_control */
1150
1151
/*
1152
* Detach and destroy socket
1153
*/
1154
1155
void
1156
ng_btsocket_l2cap_raw_detach(struct socket *so)
1157
{
1158
ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
1159
1160
KASSERT(pcb != NULL, ("nt_btsocket_l2cap_raw_detach: pcb == NULL"));
1161
if (ng_btsocket_l2cap_raw_node == NULL)
1162
return;
1163
1164
mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
1165
mtx_lock(&pcb->pcb_mtx);
1166
1167
LIST_REMOVE(pcb, next);
1168
1169
mtx_unlock(&pcb->pcb_mtx);
1170
mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
1171
1172
mtx_destroy(&pcb->pcb_mtx);
1173
1174
bzero(pcb, sizeof(*pcb));
1175
free(pcb, M_NETGRAPH_BTSOCKET_L2CAP_RAW);
1176
1177
so->so_pcb = NULL;
1178
} /* ng_btsocket_l2cap_raw_detach */
1179
1180
/*
1181
* Disconnect socket
1182
*/
1183
1184
int
1185
ng_btsocket_l2cap_raw_disconnect(struct socket *so)
1186
{
1187
ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
1188
1189
if (pcb == NULL)
1190
return (EINVAL);
1191
if (ng_btsocket_l2cap_raw_node == NULL)
1192
return (EINVAL);
1193
1194
mtx_lock(&pcb->pcb_mtx);
1195
pcb->rt = NULL;
1196
soisdisconnected(so);
1197
mtx_unlock(&pcb->pcb_mtx);
1198
1199
return (0);
1200
} /* ng_btsocket_l2cap_raw_disconnect */
1201
1202
/*
1203
* Get peer address
1204
*/
1205
1206
int
1207
ng_btsocket_l2cap_raw_peeraddr(struct socket *so, struct sockaddr *sa)
1208
{
1209
ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
1210
struct sockaddr_l2cap *l2cap = (struct sockaddr_l2cap *)sa;
1211
1212
if (pcb == NULL)
1213
return (EINVAL);
1214
if (ng_btsocket_l2cap_raw_node == NULL)
1215
return (EINVAL);
1216
1217
*l2cap = (struct sockaddr_l2cap ){
1218
.l2cap_len = sizeof(struct sockaddr_l2cap),
1219
.l2cap_family = AF_BLUETOOTH,
1220
.l2cap_bdaddr_type = BDADDR_BREDR,
1221
};
1222
1223
mtx_lock(&pcb->pcb_mtx);
1224
bcopy(&pcb->dst, &l2cap->l2cap_bdaddr, sizeof(l2cap->l2cap_bdaddr));
1225
mtx_unlock(&pcb->pcb_mtx);
1226
1227
return (0);
1228
}
1229
1230
/*
1231
* Send data to socket
1232
*/
1233
1234
int
1235
ng_btsocket_l2cap_raw_send(struct socket *so, int flags, struct mbuf *m,
1236
struct sockaddr *nam, struct mbuf *control, struct thread *td)
1237
{
1238
NG_FREE_M(m); /* Checks for m != NULL */
1239
NG_FREE_M(control);
1240
1241
return (EOPNOTSUPP);
1242
} /* ng_btsocket_l2cap_raw_send */
1243
1244
/*
1245
* Get socket address
1246
*/
1247
1248
int
1249
ng_btsocket_l2cap_raw_sockaddr(struct socket *so, struct sockaddr *sa)
1250
{
1251
ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
1252
struct sockaddr_l2cap *l2cap = (struct sockaddr_l2cap *)sa;
1253
1254
if (pcb == NULL)
1255
return (EINVAL);
1256
if (ng_btsocket_l2cap_raw_node == NULL)
1257
return (EINVAL);
1258
1259
*l2cap = (struct sockaddr_l2cap ){
1260
.l2cap_len = sizeof(struct sockaddr_l2cap),
1261
.l2cap_family = AF_BLUETOOTH,
1262
.l2cap_bdaddr_type = BDADDR_BREDR,
1263
};
1264
1265
mtx_lock(&pcb->pcb_mtx);
1266
bcopy(&pcb->src, &l2cap->l2cap_bdaddr, sizeof(l2cap->l2cap_bdaddr));
1267
mtx_unlock(&pcb->pcb_mtx);
1268
1269
return (0);
1270
}
1271
1272
/*
1273
* Get next token
1274
*/
1275
1276
static void
1277
ng_btsocket_l2cap_raw_get_token(u_int32_t *token)
1278
{
1279
mtx_lock(&ng_btsocket_l2cap_raw_token_mtx);
1280
1281
if (++ ng_btsocket_l2cap_raw_token == 0)
1282
ng_btsocket_l2cap_raw_token = 1;
1283
1284
*token = ng_btsocket_l2cap_raw_token;
1285
1286
mtx_unlock(&ng_btsocket_l2cap_raw_token_mtx);
1287
} /* ng_btsocket_l2cap_raw_get_token */
1288
1289
/*
1290
* Send Netgraph message to the node - do not expect reply
1291
*/
1292
1293
static int
1294
ng_btsocket_l2cap_raw_send_ngmsg(hook_p hook, int cmd, void *arg, int arglen)
1295
{
1296
struct ng_mesg *msg = NULL;
1297
int error = 0;
1298
1299
NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, arglen, M_NOWAIT);
1300
if (msg == NULL)
1301
return (ENOMEM);
1302
1303
if (arg != NULL && arglen > 0)
1304
bcopy(arg, msg->data, arglen);
1305
1306
NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, hook, 0);
1307
1308
return (error);
1309
} /* ng_btsocket_l2cap_raw_send_ngmsg */
1310
1311
/*
1312
* Send Netgraph message to the node (no data) and wait for reply
1313
*/
1314
1315
static int
1316
ng_btsocket_l2cap_raw_send_sync_ngmsg(ng_btsocket_l2cap_raw_pcb_p pcb,
1317
int cmd, void *rsp, int rsplen)
1318
{
1319
struct ng_mesg *msg = NULL;
1320
int error = 0;
1321
1322
mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1323
1324
NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, 0, M_NOWAIT);
1325
if (msg == NULL)
1326
return (ENOMEM);
1327
1328
ng_btsocket_l2cap_raw_get_token(&msg->header.token);
1329
pcb->token = msg->header.token;
1330
pcb->msg = NULL;
1331
1332
NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
1333
pcb->rt->hook, 0);
1334
if (error != 0) {
1335
pcb->token = 0;
1336
return (error);
1337
}
1338
1339
error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
1340
ng_btsocket_l2cap_raw_ioctl_timeout * hz);
1341
pcb->token = 0;
1342
1343
if (error != 0)
1344
return (error);
1345
1346
if (pcb->msg != NULL && pcb->msg->header.cmd == cmd)
1347
bcopy(pcb->msg->data, rsp, rsplen);
1348
else
1349
error = EINVAL;
1350
1351
NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1352
1353
return (0);
1354
} /* ng_btsocket_l2cap_raw_send_sync_ngmsg */
1355
1356