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