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$
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 (sa->l2cap_len != sizeof(struct sockaddr_l2cap_compat)))
672 return (EINVAL);
673
674 if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY,
675 sizeof(sa->l2cap_bdaddr)) != 0) {
676 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
677
678 LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) {
679 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
680 continue;
681
682 if (bcmp(&sa->l2cap_bdaddr, &rt->src,
683 sizeof(rt->src)) == 0)
684 break;
685 }
686
687 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
688
689 if (rt == NULL)
690 return (ENETDOWN);
691 } else
692 rt = NULL;
693
694 mtx_lock(&pcb->pcb_mtx);
695 bcopy(&sa->l2cap_bdaddr, &pcb->src, sizeof(pcb->src));
696 pcb->rt = rt;
697 mtx_unlock(&pcb->pcb_mtx);
698
699 return (0);
700 } /* ng_btsocket_l2cap_raw_bind */
701
702 /*
703 * Connect socket
704 */
705
706 int
ng_btsocket_l2cap_raw_connect(struct socket * so,struct sockaddr * nam,struct thread * td)707 ng_btsocket_l2cap_raw_connect(struct socket *so, struct sockaddr *nam,
708 struct thread *td)
709 {
710 ng_btsocket_l2cap_raw_pcb_t *pcb = so2l2cap_raw_pcb(so);
711 struct sockaddr_l2cap *sa = (struct sockaddr_l2cap *) nam;
712 ng_btsocket_l2cap_rtentry_t *rt = NULL;
713 int error;
714
715 if (pcb == NULL)
716 return (EINVAL);
717 if (ng_btsocket_l2cap_raw_node == NULL)
718 return (EINVAL);
719
720 if (sa == NULL)
721 return (EINVAL);
722 if (sa->l2cap_family != AF_BLUETOOTH)
723 return (EAFNOSUPPORT);
724 if((sa->l2cap_len != sizeof(*sa))&&
725 (sa->l2cap_len != sizeof(struct sockaddr_l2cap_compat)))
726 return (EINVAL);
727
728 if (bcmp(&sa->l2cap_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
729 return (EINVAL);
730
731 mtx_lock(&pcb->pcb_mtx);
732
733 bcopy(&sa->l2cap_bdaddr, &pcb->dst, sizeof(pcb->dst));
734
735 if (bcmp(&pcb->src, &pcb->dst, sizeof(pcb->src)) == 0) {
736 mtx_unlock(&pcb->pcb_mtx);
737
738 return (EADDRNOTAVAIL);
739 }
740
741 /*
742 * If there is route already - use it
743 */
744
745 if (pcb->rt != NULL) {
746 soisconnected(so);
747 mtx_unlock(&pcb->pcb_mtx);
748
749 return (0);
750 }
751
752 /*
753 * Find the first hook that does not match specified destination address
754 */
755
756 mtx_lock(&ng_btsocket_l2cap_raw_rt_mtx);
757
758 LIST_FOREACH(rt, &ng_btsocket_l2cap_raw_rt, next) {
759 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
760 continue;
761
762 if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0)
763 break;
764 }
765
766 if (rt != NULL) {
767 soisconnected(so);
768
769 pcb->rt = rt;
770 bcopy(&rt->src, &pcb->src, sizeof(pcb->src));
771
772 error = 0;
773 } else
774 error = ENETDOWN;
775
776 mtx_unlock(&ng_btsocket_l2cap_raw_rt_mtx);
777 mtx_unlock(&pcb->pcb_mtx);
778
779 return (error);
780 } /* ng_btsocket_l2cap_raw_connect */
781
782 /*
783 * Process ioctl's calls on socket
784 */
785
786 int
ng_btsocket_l2cap_raw_control(struct socket * so,u_long cmd,caddr_t data,struct ifnet * ifp,struct thread * td)787 ng_btsocket_l2cap_raw_control(struct socket *so, u_long cmd, caddr_t data,
788 struct ifnet *ifp, struct thread *td)
789 {
790 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
791 struct ng_mesg *msg = NULL;
792 int error = 0;
793
794 if (pcb == NULL)
795 return (EINVAL);
796 if (ng_btsocket_l2cap_raw_node == NULL)
797 return (EINVAL);
798
799 mtx_lock(&pcb->pcb_mtx);
800
801 /* Check if we route info */
802 if (pcb->rt == NULL) {
803 mtx_unlock(&pcb->pcb_mtx);
804 return (EHOSTUNREACH);
805 }
806
807 /* Check if we have pending ioctl() */
808 if (pcb->token != 0) {
809 mtx_unlock(&pcb->pcb_mtx);
810 return (EBUSY);
811 }
812
813 switch (cmd) {
814 case SIOC_L2CAP_NODE_GET_FLAGS: {
815 struct ng_btsocket_l2cap_raw_node_flags *p =
816 (struct ng_btsocket_l2cap_raw_node_flags *) data;
817
818 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
819 NGM_L2CAP_NODE_GET_FLAGS,
820 &p->flags, sizeof(p->flags));
821 } break;
822
823 case SIOC_L2CAP_NODE_GET_DEBUG: {
824 struct ng_btsocket_l2cap_raw_node_debug *p =
825 (struct ng_btsocket_l2cap_raw_node_debug *) data;
826
827 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
828 NGM_L2CAP_NODE_GET_DEBUG,
829 &p->debug, sizeof(p->debug));
830 } break;
831
832 case SIOC_L2CAP_NODE_SET_DEBUG: {
833 struct ng_btsocket_l2cap_raw_node_debug *p =
834 (struct ng_btsocket_l2cap_raw_node_debug *) data;
835
836 if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)
837 error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook,
838 NGM_L2CAP_NODE_SET_DEBUG,
839 &p->debug, sizeof(p->debug));
840 else
841 error = EPERM;
842 } break;
843
844 case SIOC_L2CAP_NODE_GET_CON_LIST: {
845 struct ng_btsocket_l2cap_raw_con_list *p =
846 (struct ng_btsocket_l2cap_raw_con_list *) data;
847 ng_l2cap_node_con_list_ep *p1 = NULL;
848 ng_l2cap_node_con_ep *p2 = NULL;
849
850 if (p->num_connections == 0 ||
851 p->num_connections > NG_L2CAP_MAX_CON_NUM ||
852 p->connections == NULL) {
853 error = EINVAL;
854 break;
855 }
856
857 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, NGM_L2CAP_NODE_GET_CON_LIST,
858 0, M_NOWAIT);
859 if (msg == NULL) {
860 error = ENOMEM;
861 break;
862 }
863 ng_btsocket_l2cap_raw_get_token(&msg->header.token);
864 pcb->token = msg->header.token;
865 pcb->msg = NULL;
866
867 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
868 pcb->rt->hook, 0);
869 if (error != 0) {
870 pcb->token = 0;
871 break;
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 break;
880
881 if (pcb->msg != NULL &&
882 pcb->msg->header.cmd == NGM_L2CAP_NODE_GET_CON_LIST) {
883 /* Return data back to user space */
884 p1 = (ng_l2cap_node_con_list_ep *)(pcb->msg->data);
885 p2 = (ng_l2cap_node_con_ep *)(p1 + 1);
886
887 p->num_connections = min(p->num_connections,
888 p1->num_connections);
889 if (p->num_connections > 0)
890 error = copyout((caddr_t) p2,
891 (caddr_t) p->connections,
892 p->num_connections * sizeof(*p2));
893 } else
894 error = EINVAL;
895
896 NG_FREE_MSG(pcb->msg); /* checks for != NULL */
897 } break;
898
899 case SIOC_L2CAP_NODE_GET_CHAN_LIST: {
900 struct ng_btsocket_l2cap_raw_chan_list *p =
901 (struct ng_btsocket_l2cap_raw_chan_list *) data;
902 ng_l2cap_node_chan_list_ep *p1 = NULL;
903 ng_l2cap_node_chan_ep *p2 = NULL;
904
905 if (p->num_channels == 0 ||
906 p->num_channels > NG_L2CAP_MAX_CHAN_NUM ||
907 p->channels == NULL) {
908 error = EINVAL;
909 break;
910 }
911
912 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,
913 NGM_L2CAP_NODE_GET_CHAN_LIST, 0, M_NOWAIT);
914 if (msg == NULL) {
915 error = ENOMEM;
916 break;
917 }
918 ng_btsocket_l2cap_raw_get_token(&msg->header.token);
919 pcb->token = msg->header.token;
920 pcb->msg = NULL;
921
922 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
923 pcb->rt->hook, 0);
924 if (error != 0) {
925 pcb->token = 0;
926 break;
927 }
928
929 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
930 ng_btsocket_l2cap_raw_ioctl_timeout * hz);
931 pcb->token = 0;
932
933 if (error != 0)
934 break;
935
936 if (pcb->msg != NULL &&
937 pcb->msg->header.cmd == NGM_L2CAP_NODE_GET_CHAN_LIST) {
938 /* Return data back to user space */
939 p1 = (ng_l2cap_node_chan_list_ep *)(pcb->msg->data);
940 p2 = (ng_l2cap_node_chan_ep *)(p1 + 1);
941
942 p->num_channels = min(p->num_channels,
943 p1->num_channels);
944 if (p->num_channels > 0)
945 error = copyout((caddr_t) p2,
946 (caddr_t) p->channels,
947 p->num_channels * sizeof(*p2));
948 } else
949 error = EINVAL;
950
951 NG_FREE_MSG(pcb->msg); /* checks for != NULL */
952 } break;
953
954 case SIOC_L2CAP_L2CA_PING: {
955 struct ng_btsocket_l2cap_raw_ping *p =
956 (struct ng_btsocket_l2cap_raw_ping *) data;
957 ng_l2cap_l2ca_ping_ip *ip = NULL;
958 ng_l2cap_l2ca_ping_op *op = NULL;
959
960 if ((p->echo_size != 0 && p->echo_data == NULL) ||
961 p->echo_size > NG_L2CAP_MAX_ECHO_SIZE) {
962 error = EINVAL;
963 break;
964 }
965
966 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,
967 NGM_L2CAP_L2CA_PING, sizeof(*ip) + p->echo_size,
968 M_NOWAIT);
969 if (msg == NULL) {
970 error = ENOMEM;
971 break;
972 }
973 ng_btsocket_l2cap_raw_get_token(&msg->header.token);
974 pcb->token = msg->header.token;
975 pcb->msg = NULL;
976
977 ip = (ng_l2cap_l2ca_ping_ip *)(msg->data);
978 bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr));
979 ip->echo_size = p->echo_size;
980
981 if (ip->echo_size > 0) {
982 error = copyin(p->echo_data, ip + 1, p->echo_size);
983 if (error != 0) {
984 NG_FREE_MSG(msg);
985 pcb->token = 0;
986 break;
987 }
988 }
989
990 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
991 pcb->rt->hook, 0);
992 if (error != 0) {
993 pcb->token = 0;
994 break;
995 }
996
997 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
998 bluetooth_l2cap_rtx_timeout());
999 pcb->token = 0;
1000
1001 if (error != 0)
1002 break;
1003
1004 if (pcb->msg != NULL &&
1005 pcb->msg->header.cmd == NGM_L2CAP_L2CA_PING) {
1006 /* Return data back to the user space */
1007 op = (ng_l2cap_l2ca_ping_op *)(pcb->msg->data);
1008 p->result = op->result;
1009 p->echo_size = min(p->echo_size, op->echo_size);
1010
1011 if (p->echo_size > 0)
1012 error = copyout(op + 1, p->echo_data,
1013 p->echo_size);
1014 } else
1015 error = EINVAL;
1016
1017 NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1018 } break;
1019
1020 case SIOC_L2CAP_L2CA_GET_INFO: {
1021 struct ng_btsocket_l2cap_raw_get_info *p =
1022 (struct ng_btsocket_l2cap_raw_get_info *) data;
1023 ng_l2cap_l2ca_get_info_ip *ip = NULL;
1024 ng_l2cap_l2ca_get_info_op *op = NULL;
1025
1026 if (!(pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)) {
1027 error = EPERM;
1028 break;
1029 }
1030
1031 if (p->info_size != 0 && p->info_data == NULL) {
1032 error = EINVAL;
1033 break;
1034 }
1035
1036 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE,
1037 NGM_L2CAP_L2CA_GET_INFO, sizeof(*ip) + p->info_size,
1038 M_NOWAIT);
1039 if (msg == NULL) {
1040 error = ENOMEM;
1041 break;
1042 }
1043 ng_btsocket_l2cap_raw_get_token(&msg->header.token);
1044 pcb->token = msg->header.token;
1045 pcb->msg = NULL;
1046
1047 ip = (ng_l2cap_l2ca_get_info_ip *)(msg->data);
1048 bcopy(&pcb->dst, &ip->bdaddr, sizeof(ip->bdaddr));
1049 ip->info_type = p->info_type;
1050
1051 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
1052 pcb->rt->hook, 0);
1053 if (error != 0) {
1054 pcb->token = 0;
1055 break;
1056 }
1057
1058 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
1059 bluetooth_l2cap_rtx_timeout());
1060 pcb->token = 0;
1061
1062 if (error != 0)
1063 break;
1064
1065 if (pcb->msg != NULL &&
1066 pcb->msg->header.cmd == NGM_L2CAP_L2CA_GET_INFO) {
1067 /* Return data back to the user space */
1068 op = (ng_l2cap_l2ca_get_info_op *)(pcb->msg->data);
1069 p->result = op->result;
1070 p->info_size = min(p->info_size, op->info_size);
1071
1072 if (p->info_size > 0)
1073 error = copyout(op + 1, p->info_data,
1074 p->info_size);
1075 } else
1076 error = EINVAL;
1077
1078 NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1079 } break;
1080
1081 case SIOC_L2CAP_NODE_GET_AUTO_DISCON_TIMO: {
1082 struct ng_btsocket_l2cap_raw_auto_discon_timo *p =
1083 (struct ng_btsocket_l2cap_raw_auto_discon_timo *) data;
1084
1085 error = ng_btsocket_l2cap_raw_send_sync_ngmsg(pcb,
1086 NGM_L2CAP_NODE_GET_AUTO_DISCON_TIMO,
1087 &p->timeout, sizeof(p->timeout));
1088 } break;
1089
1090 case SIOC_L2CAP_NODE_SET_AUTO_DISCON_TIMO: {
1091 struct ng_btsocket_l2cap_raw_auto_discon_timo *p =
1092 (struct ng_btsocket_l2cap_raw_auto_discon_timo *) data;
1093
1094 if (pcb->flags & NG_BTSOCKET_L2CAP_RAW_PRIVILEGED)
1095 error = ng_btsocket_l2cap_raw_send_ngmsg(pcb->rt->hook,
1096 NGM_L2CAP_NODE_SET_AUTO_DISCON_TIMO,
1097 &p->timeout, sizeof(p->timeout));
1098 else
1099 error = EPERM;
1100 } break;
1101
1102 default:
1103 error = EINVAL;
1104 break;
1105 }
1106
1107 mtx_unlock(&pcb->pcb_mtx);
1108
1109 return (error);
1110 } /* ng_btsocket_l2cap_raw_control */
1111
1112 /*
1113 * Detach and destroy socket
1114 */
1115
1116 void
ng_btsocket_l2cap_raw_detach(struct socket * so)1117 ng_btsocket_l2cap_raw_detach(struct socket *so)
1118 {
1119 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
1120
1121 KASSERT(pcb != NULL, ("nt_btsocket_l2cap_raw_detach: pcb == NULL"));
1122 if (ng_btsocket_l2cap_raw_node == NULL)
1123 return;
1124
1125 mtx_lock(&ng_btsocket_l2cap_raw_sockets_mtx);
1126 mtx_lock(&pcb->pcb_mtx);
1127
1128 LIST_REMOVE(pcb, next);
1129
1130 mtx_unlock(&pcb->pcb_mtx);
1131 mtx_unlock(&ng_btsocket_l2cap_raw_sockets_mtx);
1132
1133 mtx_destroy(&pcb->pcb_mtx);
1134
1135 bzero(pcb, sizeof(*pcb));
1136 free(pcb, M_NETGRAPH_BTSOCKET_L2CAP_RAW);
1137
1138 so->so_pcb = NULL;
1139 } /* ng_btsocket_l2cap_raw_detach */
1140
1141 /*
1142 * Disconnect socket
1143 */
1144
1145 int
ng_btsocket_l2cap_raw_disconnect(struct socket * so)1146 ng_btsocket_l2cap_raw_disconnect(struct socket *so)
1147 {
1148 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
1149
1150 if (pcb == NULL)
1151 return (EINVAL);
1152 if (ng_btsocket_l2cap_raw_node == NULL)
1153 return (EINVAL);
1154
1155 mtx_lock(&pcb->pcb_mtx);
1156 pcb->rt = NULL;
1157 soisdisconnected(so);
1158 mtx_unlock(&pcb->pcb_mtx);
1159
1160 return (0);
1161 } /* ng_btsocket_l2cap_raw_disconnect */
1162
1163 /*
1164 * Get peer address
1165 */
1166
1167 int
ng_btsocket_l2cap_raw_peeraddr(struct socket * so,struct sockaddr ** nam)1168 ng_btsocket_l2cap_raw_peeraddr(struct socket *so, struct sockaddr **nam)
1169 {
1170 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
1171 struct sockaddr_l2cap sa;
1172
1173 if (pcb == NULL)
1174 return (EINVAL);
1175 if (ng_btsocket_l2cap_raw_node == NULL)
1176 return (EINVAL);
1177
1178 mtx_lock(&pcb->pcb_mtx);
1179 bcopy(&pcb->dst, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr));
1180 mtx_unlock(&pcb->pcb_mtx);
1181
1182 sa.l2cap_psm = 0;
1183 sa.l2cap_len = sizeof(sa);
1184 sa.l2cap_family = AF_BLUETOOTH;
1185 sa.l2cap_cid = 0;
1186 sa.l2cap_bdaddr_type = BDADDR_BREDR;
1187
1188 *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
1189
1190 return ((*nam == NULL)? ENOMEM : 0);
1191 } /* ng_btsocket_l2cap_raw_peeraddr */
1192
1193 /*
1194 * Send data to socket
1195 */
1196
1197 int
ng_btsocket_l2cap_raw_send(struct socket * so,int flags,struct mbuf * m,struct sockaddr * nam,struct mbuf * control,struct thread * td)1198 ng_btsocket_l2cap_raw_send(struct socket *so, int flags, struct mbuf *m,
1199 struct sockaddr *nam, struct mbuf *control, struct thread *td)
1200 {
1201 NG_FREE_M(m); /* Checks for m != NULL */
1202 NG_FREE_M(control);
1203
1204 return (EOPNOTSUPP);
1205 } /* ng_btsocket_l2cap_raw_send */
1206
1207 /*
1208 * Get socket address
1209 */
1210
1211 int
ng_btsocket_l2cap_raw_sockaddr(struct socket * so,struct sockaddr ** nam)1212 ng_btsocket_l2cap_raw_sockaddr(struct socket *so, struct sockaddr **nam)
1213 {
1214 ng_btsocket_l2cap_raw_pcb_p pcb = so2l2cap_raw_pcb(so);
1215 struct sockaddr_l2cap sa;
1216
1217 if (pcb == NULL)
1218 return (EINVAL);
1219 if (ng_btsocket_l2cap_raw_node == NULL)
1220 return (EINVAL);
1221
1222 mtx_lock(&pcb->pcb_mtx);
1223 bcopy(&pcb->src, &sa.l2cap_bdaddr, sizeof(sa.l2cap_bdaddr));
1224 mtx_unlock(&pcb->pcb_mtx);
1225
1226 sa.l2cap_psm = 0;
1227 sa.l2cap_len = sizeof(sa);
1228 sa.l2cap_family = AF_BLUETOOTH;
1229 sa.l2cap_cid = 0;
1230 sa.l2cap_bdaddr_type = BDADDR_BREDR;
1231 *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
1232
1233 return ((*nam == NULL)? ENOMEM : 0);
1234 } /* ng_btsocket_l2cap_raw_sockaddr */
1235
1236 /*
1237 * Get next token
1238 */
1239
1240 static void
ng_btsocket_l2cap_raw_get_token(u_int32_t * token)1241 ng_btsocket_l2cap_raw_get_token(u_int32_t *token)
1242 {
1243 mtx_lock(&ng_btsocket_l2cap_raw_token_mtx);
1244
1245 if (++ ng_btsocket_l2cap_raw_token == 0)
1246 ng_btsocket_l2cap_raw_token = 1;
1247
1248 *token = ng_btsocket_l2cap_raw_token;
1249
1250 mtx_unlock(&ng_btsocket_l2cap_raw_token_mtx);
1251 } /* ng_btsocket_l2cap_raw_get_token */
1252
1253 /*
1254 * Send Netgraph message to the node - do not expect reply
1255 */
1256
1257 static int
ng_btsocket_l2cap_raw_send_ngmsg(hook_p hook,int cmd,void * arg,int arglen)1258 ng_btsocket_l2cap_raw_send_ngmsg(hook_p hook, int cmd, void *arg, int arglen)
1259 {
1260 struct ng_mesg *msg = NULL;
1261 int error = 0;
1262
1263 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, arglen, M_NOWAIT);
1264 if (msg == NULL)
1265 return (ENOMEM);
1266
1267 if (arg != NULL && arglen > 0)
1268 bcopy(arg, msg->data, arglen);
1269
1270 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg, hook, 0);
1271
1272 return (error);
1273 } /* ng_btsocket_l2cap_raw_send_ngmsg */
1274
1275 /*
1276 * Send Netgraph message to the node (no data) and wait for reply
1277 */
1278
1279 static int
ng_btsocket_l2cap_raw_send_sync_ngmsg(ng_btsocket_l2cap_raw_pcb_p pcb,int cmd,void * rsp,int rsplen)1280 ng_btsocket_l2cap_raw_send_sync_ngmsg(ng_btsocket_l2cap_raw_pcb_p pcb,
1281 int cmd, void *rsp, int rsplen)
1282 {
1283 struct ng_mesg *msg = NULL;
1284 int error = 0;
1285
1286 mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1287
1288 NG_MKMESSAGE(msg, NGM_L2CAP_COOKIE, cmd, 0, M_NOWAIT);
1289 if (msg == NULL)
1290 return (ENOMEM);
1291
1292 ng_btsocket_l2cap_raw_get_token(&msg->header.token);
1293 pcb->token = msg->header.token;
1294 pcb->msg = NULL;
1295
1296 NG_SEND_MSG_HOOK(error, ng_btsocket_l2cap_raw_node, msg,
1297 pcb->rt->hook, 0);
1298 if (error != 0) {
1299 pcb->token = 0;
1300 return (error);
1301 }
1302
1303 error = msleep(&pcb->msg, &pcb->pcb_mtx, PZERO|PCATCH, "l2ctl",
1304 ng_btsocket_l2cap_raw_ioctl_timeout * hz);
1305 pcb->token = 0;
1306
1307 if (error != 0)
1308 return (error);
1309
1310 if (pcb->msg != NULL && pcb->msg->header.cmd == cmd)
1311 bcopy(pcb->msg->data, rsp, rsplen);
1312 else
1313 error = EINVAL;
1314
1315 NG_FREE_MSG(pcb->msg); /* checks for != NULL */
1316
1317 return (0);
1318 } /* ng_btsocket_l2cap_raw_send_sync_ngmsg */
1319
1320