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 <m_evmenkin@yahoo.com>
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
ng_btsocket_l2cap_raw_node_constructor(node_p node)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
ng_btsocket_l2cap_raw_node_shutdown(node_p node)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
ng_btsocket_l2cap_raw_node_newhook(node_p node,hook_p hook,char const * name)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
ng_btsocket_l2cap_raw_node_connect(hook_p hook)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
ng_btsocket_l2cap_raw_node_disconnect(hook_p hook)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
ng_btsocket_l2cap_raw_node_rcvmsg(node_p node,item_p item,hook_p hook)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
ng_btsocket_l2cap_raw_node_rcvdata(hook_p hook,item_p item)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
ng_btsocket_l2cap_raw_input(void * context,int pending)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
ng_btsocket_l2cap_raw_rtclean(void * context,int pending)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
ng_btsocket_l2cap_raw_init(void * arg __unused)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
ng_btsocket_l2cap_raw_abort(struct socket * so)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
ng_btsocket_l2cap_raw_close(struct socket * so)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
ng_btsocket_l2cap_raw_attach(struct socket * so,int proto,struct thread * td)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
ng_btsocket_l2cap_raw_bind(struct socket * so,struct sockaddr * nam,struct thread * td)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
ng_btsocket_l2cap_raw_connect(struct socket * so,struct sockaddr * nam,struct thread * td)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
ng_btsocket_l2cap_raw_control(struct socket * so,u_long cmd,void * data,struct ifnet * ifp,struct thread * td)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
ng_btsocket_l2cap_raw_detach(struct socket * so)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
ng_btsocket_l2cap_raw_disconnect(struct socket * so)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
ng_btsocket_l2cap_raw_peeraddr(struct socket * so,struct sockaddr * sa)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
ng_btsocket_l2cap_raw_send(struct socket * so,int flags,struct mbuf * m,struct sockaddr * nam,struct mbuf * control,struct thread * td)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
ng_btsocket_l2cap_raw_sockaddr(struct socket * so,struct sockaddr * sa)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
ng_btsocket_l2cap_raw_get_token(u_int32_t * token)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
ng_btsocket_l2cap_raw_send_ngmsg(hook_p hook,int cmd,void * arg,int arglen)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
ng_btsocket_l2cap_raw_send_sync_ngmsg(ng_btsocket_l2cap_raw_pcb_p pcb,int cmd,void * rsp,int rsplen)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