FreeBSD kernel netgraph code
ng_btsocket_sco.c
Go to the documentation of this file.
1/*
2 * ng_btsocket_sco.c
3 */
4
5/*-
6 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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_sco.c,v 1.2 2005/10/31 18:08:51 max Exp $
33 * $FreeBSD$
34 */
35
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/bitstring.h>
39#include <sys/domain.h>
40#include <sys/endian.h>
41#include <sys/errno.h>
42#include <sys/filedesc.h>
43#include <sys/ioccom.h>
44#include <sys/kernel.h>
45#include <sys/lock.h>
46#include <sys/malloc.h>
47#include <sys/mbuf.h>
48#include <sys/mutex.h>
49#include <sys/protosw.h>
50#include <sys/queue.h>
51#include <sys/socket.h>
52#include <sys/socketvar.h>
53#include <sys/sysctl.h>
54#include <sys/taskqueue.h>
55
56#include <net/vnet.h>
57
58#include <netgraph/ng_message.h>
59#include <netgraph/netgraph.h>
65
66/* MALLOC define */
67#ifdef NG_SEPARATE_MALLOC
68static MALLOC_DEFINE(M_NETGRAPH_BTSOCKET_SCO, "netgraph_btsocks_sco",
69 "Netgraph Bluetooth SCO sockets");
70#else
71#define M_NETGRAPH_BTSOCKET_SCO M_NETGRAPH
72#endif /* NG_SEPARATE_MALLOC */
73
74/* Netgraph node methods */
82
83static void ng_btsocket_sco_input (void *, int);
84static void ng_btsocket_sco_rtclean (void *, int);
85
86/* Netgraph type descriptor */
87static struct ng_type typestruct = {
97};
98
99/* Globals */
104static struct task ng_btsocket_sco_queue_task;
106static LIST_HEAD(, ng_btsocket_sco_pcb) ng_btsocket_sco_sockets;
107static LIST_HEAD(, ng_btsocket_sco_rtentry) ng_btsocket_sco_rt;
108static struct mtx ng_btsocket_sco_rt_mtx;
109static struct task ng_btsocket_sco_rt_task;
110static struct timeval ng_btsocket_sco_lasttime;
111static int ng_btsocket_sco_curpps;
112
113/* Sysctl tree */
114SYSCTL_DECL(_net_bluetooth_sco_sockets);
115static SYSCTL_NODE(_net_bluetooth_sco_sockets, OID_AUTO, seq,
116 CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
117 "Bluetooth SEQPACKET SCO sockets family");
118SYSCTL_UINT(_net_bluetooth_sco_sockets_seq, OID_AUTO, debug_level,
119 CTLFLAG_RW,
121 "Bluetooth SEQPACKET SCO sockets debug level");
122SYSCTL_UINT(_net_bluetooth_sco_sockets_seq, OID_AUTO, queue_len,
123 CTLFLAG_RD,
125 "Bluetooth SEQPACKET SCO sockets input queue length");
126SYSCTL_UINT(_net_bluetooth_sco_sockets_seq, OID_AUTO, queue_maxlen,
127 CTLFLAG_RD,
129 "Bluetooth SEQPACKET SCO sockets input queue max. length");
130SYSCTL_UINT(_net_bluetooth_sco_sockets_seq, OID_AUTO, queue_drops,
131 CTLFLAG_RD,
133 "Bluetooth SEQPACKET SCO sockets input queue drops");
134
135/* Debug */
136#define NG_BTSOCKET_SCO_INFO \
137 if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_INFO_LEVEL && \
138 ppsratecheck(&ng_btsocket_sco_lasttime, &ng_btsocket_sco_curpps, 1)) \
139 printf
140
141#define NG_BTSOCKET_SCO_WARN \
142 if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_WARN_LEVEL && \
143 ppsratecheck(&ng_btsocket_sco_lasttime, &ng_btsocket_sco_curpps, 1)) \
144 printf
145
146#define NG_BTSOCKET_SCO_ERR \
147 if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_ERR_LEVEL && \
148 ppsratecheck(&ng_btsocket_sco_lasttime, &ng_btsocket_sco_curpps, 1)) \
149 printf
150
151#define NG_BTSOCKET_SCO_ALERT \
152 if (ng_btsocket_sco_debug_level >= NG_BTSOCKET_ALERT_LEVEL && \
153 ppsratecheck(&ng_btsocket_sco_lasttime, &ng_btsocket_sco_curpps, 1)) \
154 printf
155
156/*
157 * Netgraph message processing routines
158 */
159
166
167/*
168 * Send LP messages to the lower layer
169 */
170
177
178static int ng_btsocket_sco_send2
180
181/*
182 * Timeout processing routines
183 */
184
187static void ng_btsocket_sco_process_timeout (void *);
188
189/*
190 * Other stuff
191 */
192
196
197#define ng_btsocket_sco_wakeup_input_task() \
198 taskqueue_enqueue(taskqueue_swi, &ng_btsocket_sco_queue_task)
199
200#define ng_btsocket_sco_wakeup_route_task() \
201 taskqueue_enqueue(taskqueue_swi, &ng_btsocket_sco_rt_task)
202
203/*****************************************************************************
204 *****************************************************************************
205 ** Netgraph node interface
206 *****************************************************************************
207 *****************************************************************************/
208
209/*
210 * Netgraph node constructor. Do not allow to create node of this type.
211 */
212
213static int
215{
216 return (EINVAL);
217} /* ng_btsocket_sco_node_constructor */
218
219/*
220 * Do local shutdown processing. Let old node go and create new fresh one.
221 */
222
223static int
225{
226 int error = 0;
227
228 NG_NODE_UNREF(node);
229
230 /* Create new node */
232 if (error != 0) {
234"%s: Could not create Netgraph node, error=%d\n", __func__, error);
235
237
238 return (error);
239 }
240
243 if (error != 0) {
245"%s: Could not name Netgraph node, error=%d\n", __func__, error);
246
249
250 return (error);
251 }
252
253 return (0);
254} /* ng_btsocket_sco_node_shutdown */
255
256/*
257 * We allow any hook to be connected to the node.
258 */
259
260static int
262{
263 return (0);
264} /* ng_btsocket_sco_node_newhook */
265
266/*
267 * Just say "YEP, that's OK by me!"
268 */
269
270static int
272{
273 NG_HOOK_SET_PRIVATE(hook, NULL);
274 NG_HOOK_REF(hook); /* Keep extra reference to the hook */
275
276#if 0
279#endif
280
281 return (0);
282} /* ng_btsocket_sco_node_connect */
283
284/*
285 * Hook disconnection. Schedule route cleanup task
286 */
287
288static int
290{
291 /*
292 * If hook has private information than we must have this hook in
293 * the routing table and must schedule cleaning for the routing table.
294 * Otherwise hook was connected but we never got "hook_info" message,
295 * so we have never added this hook to the routing table and it save
296 * to just delete it.
297 */
298
299 if (NG_HOOK_PRIVATE(hook) != NULL)
301
302 NG_HOOK_UNREF(hook); /* Remove extra reference */
303
304 return (0);
305} /* ng_btsocket_sco_node_disconnect */
306
307/*
308 * Process incoming messages
309 */
310
311static int
313{
314 struct ng_mesg *msg = NGI_MSG(item); /* item still has message */
315 int error = 0;
316
317 if (msg != NULL && msg->header.typecookie == NGM_HCI_COOKIE) {
318 mtx_lock(&ng_btsocket_sco_queue_mtx);
321"%s: Input queue is full (msg)\n", __func__);
322
324 NG_FREE_ITEM(item);
325 error = ENOBUFS;
326 } else {
327 if (hook != NULL) {
328 NG_HOOK_REF(hook);
329 NGI_SET_HOOK(item, hook);
330 }
331
334 }
335 mtx_unlock(&ng_btsocket_sco_queue_mtx);
336 } else {
337 NG_FREE_ITEM(item);
338 error = EINVAL;
339 }
340
341 return (error);
342} /* ng_btsocket_sco_node_rcvmsg */
343
344/*
345 * Receive data on a hook
346 */
347
348static int
350{
351 int error = 0;
352
353 mtx_lock(&ng_btsocket_sco_queue_mtx);
356"%s: Input queue is full (data)\n", __func__);
357
359 NG_FREE_ITEM(item);
360 error = ENOBUFS;
361 } else {
362 NG_HOOK_REF(hook);
363 NGI_SET_HOOK(item, hook);
364
367 }
368 mtx_unlock(&ng_btsocket_sco_queue_mtx);
369
370 return (error);
371} /* ng_btsocket_sco_node_rcvdata */
372
373/*
374 * Process LP_ConnectCfm event from the lower layer protocol
375 */
376
377static int
380{
381 ng_hci_lp_con_cfm_ep *ep = NULL;
382 ng_btsocket_sco_pcb_t *pcb = NULL;
383 int error = 0;
384
385 if (msg->header.arglen != sizeof(*ep))
386 return (EMSGSIZE);
387
388 ep = (ng_hci_lp_con_cfm_ep *)(msg->data);
389
391
392 /* Look for the socket with the token */
393 pcb = ng_btsocket_sco_pcb_by_addrs(&rt->src, &ep->bdaddr);
394 if (pcb == NULL) {
395 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
396 return (ENOENT);
397 }
398
399 /* pcb is locked */
400
402"%s: Got LP_ConnectCfm response, src bdaddr=%x:%x:%x:%x:%x:%x, " \
403"dst bdaddr=%x:%x:%x:%x:%x:%x, status=%d, handle=%d, state=%d\n",
404 __func__,
405 pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
406 pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
407 pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
408 pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
409 ep->status, ep->con_handle, pcb->state);
410
411 if (pcb->state != NG_BTSOCKET_SCO_CONNECTING) {
412 mtx_unlock(&pcb->pcb_mtx);
413 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
414
415 return (ENOENT);
416 }
417
419
420 if (ep->status == 0) {
421 /*
422 * Connection is open. Update connection handle and
423 * socket state
424 */
425
426 pcb->con_handle = ep->con_handle;
428 soisconnected(pcb->so);
429 } else {
430 /*
431 * We have failed to open connection, so disconnect the socket
432 */
433
434 pcb->so->so_error = ECONNREFUSED; /* XXX convert status ??? */
436 soisdisconnected(pcb->so);
437 }
438
439 mtx_unlock(&pcb->pcb_mtx);
440 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
441
442 return (error);
443} /* ng_btsocket_sco_process_lp_con_cfm */
444
445/*
446 * Process LP_ConnectInd indicator. Find socket that listens on address.
447 * Find exact or closest match.
448 */
449
450static int
453{
454 ng_hci_lp_con_ind_ep *ep = NULL;
455 ng_btsocket_sco_pcb_t *pcb = NULL, *pcb1 = NULL;
456 int error = 0;
457 u_int16_t status = 0;
458
459 if (msg->header.arglen != sizeof(*ep))
460 return (EMSGSIZE);
461
462 ep = (ng_hci_lp_con_ind_ep *)(msg->data);
463
465"%s: Got LP_ConnectInd indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \
466"dst bdaddr=%x:%x:%x:%x:%x:%x\n",
467 __func__,
468 rt->src.b[5], rt->src.b[4], rt->src.b[3],
469 rt->src.b[2], rt->src.b[1], rt->src.b[0],
470 ep->bdaddr.b[5], ep->bdaddr.b[4], ep->bdaddr.b[3],
471 ep->bdaddr.b[2], ep->bdaddr.b[1], ep->bdaddr.b[0]);
472
474
476 if (pcb != NULL) {
477 struct socket *so1;
478
479 /* pcb is locked */
480
481 CURVNET_SET(pcb->so->so_vnet);
482 so1 = sonewconn(pcb->so, 0);
483 CURVNET_RESTORE();
484
485 if (so1 == NULL) {
486 status = 0x0d; /* Rejected due to limited resources */
487 goto respond;
488 }
489
490 /*
491 * If we got here than we have created new socket. So complete
492 * connection. If we we listening on specific address then copy
493 * source address from listening socket, otherwise copy source
494 * address from hook's routing information.
495 */
496
497 pcb1 = so2sco_pcb(so1);
498 KASSERT((pcb1 != NULL),
499("%s: pcb1 == NULL\n", __func__));
500
501 mtx_lock(&pcb1->pcb_mtx);
502
503 if (bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(pcb->src)) != 0)
504 bcopy(&pcb->src, &pcb1->src, sizeof(pcb1->src));
505 else
506 bcopy(&rt->src, &pcb1->src, sizeof(pcb1->src));
507
508 pcb1->flags &= ~NG_BTSOCKET_SCO_CLIENT;
509
510 bcopy(&ep->bdaddr, &pcb1->dst, sizeof(pcb1->dst));
511 pcb1->rt = rt;
512 } else
513 /* Nobody listens on requested BDADDR */
514 status = 0x1f; /* Unspecified Error */
515
516respond:
518 if (pcb1 != NULL) {
519 if (error != 0) {
520 pcb1->so->so_error = error;
521 pcb1->state = NG_BTSOCKET_SCO_CLOSED;
522 soisdisconnected(pcb1->so);
523 } else {
524 pcb1->state = NG_BTSOCKET_SCO_CONNECTING;
525 soisconnecting(pcb1->so);
526
528 }
529
530 mtx_unlock(&pcb1->pcb_mtx);
531 }
532
533 if (pcb != NULL)
534 mtx_unlock(&pcb->pcb_mtx);
535
536 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
537
538 return (error);
539} /* ng_btsocket_sco_process_lp_con_ind */
540
541/*
542 * Process LP_DisconnectInd indicator
543 */
544
545static int
548{
549 ng_hci_lp_discon_ind_ep *ep = NULL;
550 ng_btsocket_sco_pcb_t *pcb = NULL;
551
552 /* Check message */
553 if (msg->header.arglen != sizeof(*ep))
554 return (EMSGSIZE);
555
556 ep = (ng_hci_lp_discon_ind_ep *)(msg->data);
557
559
560 /* Look for the socket with given channel ID */
562 if (pcb == NULL) {
563 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
564 return (0);
565 }
566
567 /*
568 * Disconnect the socket. If there was any pending request we can
569 * not do anything here anyway.
570 */
571
572 /* pcb is locked */
573
575"%s: Got LP_DisconnectInd indicator, src bdaddr=%x:%x:%x:%x:%x:%x, " \
576"dst bdaddr=%x:%x:%x:%x:%x:%x, handle=%d, state=%d\n",
577 __func__,
578 pcb->src.b[5], pcb->src.b[4], pcb->src.b[3],
579 pcb->src.b[2], pcb->src.b[1], pcb->src.b[0],
580 pcb->dst.b[5], pcb->dst.b[4], pcb->dst.b[3],
581 pcb->dst.b[2], pcb->dst.b[1], pcb->dst.b[0],
582 pcb->con_handle, pcb->state);
583
584 if (pcb->flags & NG_BTSOCKET_SCO_TIMO)
586
588 soisdisconnected(pcb->so);
589
590 mtx_unlock(&pcb->pcb_mtx);
591 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
592
593 return (0);
594} /* ng_btsocket_sco_process_lp_discon_ind */
595
596/*
597 * Send LP_ConnectReq request
598 */
599
600static int
602{
603 struct ng_mesg *msg = NULL;
604 ng_hci_lp_con_req_ep *ep = NULL;
605 int error = 0;
606
607 mtx_assert(&pcb->pcb_mtx, MA_OWNED);
608
609 if (pcb->rt == NULL ||
610 pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook))
611 return (ENETDOWN);
612
614 sizeof(*ep), M_NOWAIT);
615 if (msg == NULL)
616 return (ENOMEM);
617
618 ep = (ng_hci_lp_con_req_ep *)(msg->data);
620 bcopy(&pcb->dst, &ep->bdaddr, sizeof(ep->bdaddr));
621
622 NG_SEND_MSG_HOOK(error, ng_btsocket_sco_node, msg, pcb->rt->hook, 0);
623
624 return (error);
625} /* ng_btsocket_sco_send_lp_con_req */
626
627/*
628 * Send LP_ConnectRsp response
629 */
630
631static int
633{
634 struct ng_mesg *msg = NULL;
635 ng_hci_lp_con_rsp_ep *ep = NULL;
636 int error = 0;
637
638 if (rt == NULL || rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
639 return (ENETDOWN);
640
642 sizeof(*ep), M_NOWAIT);
643 if (msg == NULL)
644 return (ENOMEM);
645
646 ep = (ng_hci_lp_con_rsp_ep *)(msg->data);
647 ep->status = status;
649 bcopy(dst, &ep->bdaddr, sizeof(ep->bdaddr));
650
651 NG_SEND_MSG_HOOK(error, ng_btsocket_sco_node, msg, rt->hook, 0);
652
653 return (error);
654} /* ng_btsocket_sco_send_lp_con_rsp */
655
656/*
657 * Send LP_DisconReq request
658 */
659
660static int
662{
663 struct ng_mesg *msg = NULL;
664 ng_hci_lp_discon_req_ep *ep = NULL;
665 int error = 0;
666
667 mtx_assert(&pcb->pcb_mtx, MA_OWNED);
668
669 if (pcb->rt == NULL ||
670 pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook))
671 return (ENETDOWN);
672
674 sizeof(*ep), M_NOWAIT);
675 if (msg == NULL)
676 return (ENOMEM);
677
678 ep = (ng_hci_lp_discon_req_ep *)(msg->data);
679 ep->con_handle = pcb->con_handle;
680 ep->reason = 0x13; /* User Ended Connection */
681
682 NG_SEND_MSG_HOOK(error, ng_btsocket_sco_node, msg, pcb->rt->hook, 0);
683
684 return (error);
685} /* ng_btsocket_sco_send_lp_discon_req */
686
687/*****************************************************************************
688 *****************************************************************************
689 ** Socket interface
690 *****************************************************************************
691 *****************************************************************************/
692
693/*
694 * SCO sockets data input routine
695 */
696
697static void
699{
700 ng_hci_scodata_pkt_t *hdr = NULL;
701 ng_btsocket_sco_pcb_t *pcb = NULL;
702 ng_btsocket_sco_rtentry_t *rt = NULL;
703 u_int16_t con_handle;
704
705 if (hook == NULL) {
707"%s: Invalid source hook for SCO data packet\n", __func__);
708 goto drop;
709 }
710
712 if (rt == NULL) {
714"%s: Could not find out source bdaddr for SCO data packet\n", __func__);
715 goto drop;
716 }
717
718 /* Make sure we can access header */
719 if (m->m_pkthdr.len < sizeof(*hdr)) {
721"%s: SCO data packet too small, len=%d\n", __func__, m->m_pkthdr.len);
722 goto drop;
723 }
724
725 if (m->m_len < sizeof(*hdr)) {
726 m = m_pullup(m, sizeof(*hdr));
727 if (m == NULL)
728 goto drop;
729 }
730
731 /* Strip SCO packet header and verify packet length */
732 hdr = mtod(m, ng_hci_scodata_pkt_t *);
733 m_adj(m, sizeof(*hdr));
734
735 if (hdr->length != m->m_pkthdr.len) {
737"%s: Bad SCO data packet length, len=%d, length=%d\n",
738 __func__, m->m_pkthdr.len, hdr->length);
739 goto drop;
740 }
741
742 /*
743 * Now process packet
744 */
745
746 con_handle = NG_HCI_CON_HANDLE(le16toh(hdr->con_handle));
747
749"%s: Received SCO data packet: src bdaddr=%x:%x:%x:%x:%x:%x, handle=%d, " \
750"length=%d\n", __func__,
751 rt->src.b[5], rt->src.b[4], rt->src.b[3],
752 rt->src.b[2], rt->src.b[1], rt->src.b[0],
753 con_handle, hdr->length);
754
756
757 /* Find socket */
758 pcb = ng_btsocket_sco_pcb_by_handle(&rt->src, con_handle);
759 if (pcb == NULL) {
760 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
761 goto drop;
762 }
763
764 /* pcb is locked */
765
766 if (pcb->state != NG_BTSOCKET_SCO_OPEN) {
768"%s: No connected socket found, src bdaddr=%x:%x:%x:%x:%x:%x, state=%d\n",
769 __func__,
770 rt->src.b[5], rt->src.b[4], rt->src.b[3],
771 rt->src.b[2], rt->src.b[1], rt->src.b[0],
772 pcb->state);
773
774 mtx_unlock(&pcb->pcb_mtx);
775 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
776 goto drop;
777 }
778
779 /* Check if we have enough space in socket receive queue */
780 if (m->m_pkthdr.len > sbspace(&pcb->so->so_rcv)) {
782"%s: Not enough space in socket receive queue. Dropping SCO data packet, " \
783"src bdaddr=%x:%x:%x:%x:%x:%x, len=%d, space=%ld\n",
784 __func__,
785 rt->src.b[5], rt->src.b[4], rt->src.b[3],
786 rt->src.b[2], rt->src.b[1], rt->src.b[0],
787 m->m_pkthdr.len,
788 sbspace(&pcb->so->so_rcv));
789
790 mtx_unlock(&pcb->pcb_mtx);
791 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
792 goto drop;
793 }
794
795 /* Append packet to the socket receive queue and wakeup */
796 sbappendrecord(&pcb->so->so_rcv, m);
797 m = NULL;
798
799 sorwakeup(pcb->so);
800
801 mtx_unlock(&pcb->pcb_mtx);
802 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
803drop:
804 NG_FREE_M(m); /* checks for m != NULL */
805} /* ng_btsocket_sco_data_input */
806
807/*
808 * SCO sockets default message input routine
809 */
810
811static void
813{
814 ng_btsocket_sco_rtentry_t *rt = NULL;
815
816 if (hook == NULL || NG_HOOK_NOT_VALID(hook))
817 return;
818
820
821 switch (msg->header.cmd) {
822 case NGM_HCI_NODE_UP: {
823 ng_hci_node_up_ep *ep = NULL;
824
825 if (msg->header.arglen != sizeof(*ep))
826 break;
827
828 ep = (ng_hci_node_up_ep *)(msg->data);
829 if (bcmp(&ep->bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
830 break;
831
832 if (rt == NULL) {
833 rt = malloc(sizeof(*rt),
834 M_NETGRAPH_BTSOCKET_SCO, M_NOWAIT|M_ZERO);
835 if (rt == NULL)
836 break;
837
838 NG_HOOK_SET_PRIVATE(hook, rt);
839
840 mtx_lock(&ng_btsocket_sco_rt_mtx);
841
842 LIST_INSERT_HEAD(&ng_btsocket_sco_rt, rt, next);
843 } else
844 mtx_lock(&ng_btsocket_sco_rt_mtx);
845
846 bcopy(&ep->bdaddr, &rt->src, sizeof(rt->src));
847 rt->pkt_size = (ep->pkt_size == 0)? 60 : ep->pkt_size;
848 rt->num_pkts = ep->num_pkts;
849 rt->hook = hook;
850
851 mtx_unlock(&ng_btsocket_sco_rt_mtx);
852
854"%s: Updating hook \"%s\", src bdaddr=%x:%x:%x:%x:%x:%x, pkt_size=%d, " \
855"num_pkts=%d\n", __func__, NG_HOOK_NAME(hook),
856 rt->src.b[5], rt->src.b[4], rt->src.b[3],
857 rt->src.b[2], rt->src.b[1], rt->src.b[0],
858 rt->pkt_size, rt->num_pkts);
859 } break;
860
862 ng_hci_sync_con_queue_ep *ep = NULL;
863 ng_btsocket_sco_pcb_t *pcb = NULL;
864
865 if (rt == NULL || msg->header.arglen != sizeof(*ep))
866 break;
867
868 ep = (ng_hci_sync_con_queue_ep *)(msg->data);
869
870 rt->pending -= ep->completed;
871 if (rt->pending < 0) {
873"%s: Pending packet counter is out of sync! bdaddr=%x:%x:%x:%x:%x:%x, " \
874"handle=%d, pending=%d, completed=%d\n",
875 __func__,
876 rt->src.b[5], rt->src.b[4], rt->src.b[3],
877 rt->src.b[2], rt->src.b[1], rt->src.b[0],
878 ep->con_handle, rt->pending,
879 ep->completed);
880
881 rt->pending = 0;
882 }
883
885
886 /* Find socket */
888 if (pcb == NULL) {
889 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
890 break;
891 }
892
893 /* pcb is locked */
894
895 /* Check state */
896 if (pcb->state == NG_BTSOCKET_SCO_OPEN) {
897 /* Remove timeout */
899
900 /* Drop completed packets from the send queue */
901 for (; ep->completed > 0; ep->completed --)
902 sbdroprecord(&pcb->so->so_snd);
903
904 /* Send more if we have any */
905 if (sbavail(&pcb->so->so_snd) > 0)
906 if (ng_btsocket_sco_send2(pcb) == 0)
908
909 /* Wake up writers */
910 sowwakeup(pcb->so);
911 }
912
913 mtx_unlock(&pcb->pcb_mtx);
914 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
915 } break;
916
917 default:
919"%s: Unknown message, cmd=%d\n", __func__, msg->header.cmd);
920 break;
921 }
922
923 NG_FREE_MSG(msg); /* Checks for msg != NULL */
924} /* ng_btsocket_sco_default_msg_input */
925
926/*
927 * SCO sockets LP message input routine
928 */
929
930static void
932{
934
935 if (hook == NULL) {
937"%s: Invalid source hook for LP message\n", __func__);
938 goto drop;
939 }
940
942 if (rt == NULL) {
944"%s: Could not find out source bdaddr for LP message\n", __func__);
945 goto drop;
946 }
947
948 switch (msg->header.cmd) {
949 case NGM_HCI_LP_CON_CFM: /* Connection Confirmation Event */
951 break;
952
953 case NGM_HCI_LP_CON_IND: /* Connection Indication Event */
955 break;
956
957 case NGM_HCI_LP_DISCON_IND: /* Disconnection Indication Event */
959 break;
960
961 /* XXX FIXME add other LP messages */
962
963 default:
965"%s: Unknown LP message, cmd=%d\n", __func__, msg->header.cmd);
966 break;
967 }
968drop:
969 NG_FREE_MSG(msg);
970} /* ng_btsocket_sco_lp_msg_input */
971
972/*
973 * SCO sockets input routine
974 */
975
976static void
977ng_btsocket_sco_input(void *context, int pending)
978{
979 item_p item = NULL;
980 hook_p hook = NULL;
981
982 for (;;) {
983 mtx_lock(&ng_btsocket_sco_queue_mtx);
985 mtx_unlock(&ng_btsocket_sco_queue_mtx);
986
987 if (item == NULL)
988 break;
989
990 NGI_GET_HOOK(item, hook);
991 if (hook != NULL && NG_HOOK_NOT_VALID(hook))
992 goto drop;
993
994 switch(item->el_flags & NGQF_TYPE) {
995 case NGQF_DATA: {
996 struct mbuf *m = NULL;
997
998 NGI_GET_M(item, m);
1000 } break;
1001
1002 case NGQF_MESG: {
1003 struct ng_mesg *msg = NULL;
1004
1005 NGI_GET_MSG(item, msg);
1006
1007 switch (msg->header.cmd) {
1008 case NGM_HCI_LP_CON_CFM:
1009 case NGM_HCI_LP_CON_IND:
1011 /* XXX FIXME add other LP messages */
1013 break;
1014
1015 default:
1017 break;
1018 }
1019 } break;
1020
1021 default:
1022 KASSERT(0,
1023("%s: invalid item type=%ld\n", __func__, (item->el_flags & NGQF_TYPE)));
1024 break;
1025 }
1026drop:
1027 if (hook != NULL)
1028 NG_HOOK_UNREF(hook);
1029
1030 NG_FREE_ITEM(item);
1031 }
1032} /* ng_btsocket_sco_input */
1033
1034/*
1035 * Route cleanup task. Gets scheduled when hook is disconnected. Here we
1036 * will find all sockets that use "invalid" hook and disconnect them.
1037 */
1038
1039static void
1040ng_btsocket_sco_rtclean(void *context, int pending)
1041{
1042 ng_btsocket_sco_pcb_p pcb = NULL, pcb_next = NULL;
1043 ng_btsocket_sco_rtentry_p rt = NULL;
1044
1045 /*
1046 * First disconnect all sockets that use "invalid" hook
1047 */
1048
1049 mtx_lock(&ng_btsocket_sco_sockets_mtx);
1050
1051 for(pcb = LIST_FIRST(&ng_btsocket_sco_sockets); pcb != NULL; ) {
1052 mtx_lock(&pcb->pcb_mtx);
1053 pcb_next = LIST_NEXT(pcb, next);
1054
1055 if (pcb->rt != NULL &&
1056 pcb->rt->hook != NULL && NG_HOOK_NOT_VALID(pcb->rt->hook)) {
1057 if (pcb->flags & NG_BTSOCKET_SCO_TIMO)
1059
1060 pcb->rt = NULL;
1061 pcb->so->so_error = ENETDOWN;
1063 soisdisconnected(pcb->so);
1064 }
1065
1066 mtx_unlock(&pcb->pcb_mtx);
1067 pcb = pcb_next;
1068 }
1069
1070 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1071
1072 /*
1073 * Now cleanup routing table
1074 */
1075
1076 mtx_lock(&ng_btsocket_sco_rt_mtx);
1077
1078 for (rt = LIST_FIRST(&ng_btsocket_sco_rt); rt != NULL; ) {
1079 ng_btsocket_sco_rtentry_p rt_next = LIST_NEXT(rt, next);
1080
1081 if (rt->hook != NULL && NG_HOOK_NOT_VALID(rt->hook)) {
1082 LIST_REMOVE(rt, next);
1083
1084 NG_HOOK_SET_PRIVATE(rt->hook, NULL);
1085 NG_HOOK_UNREF(rt->hook); /* Remove extra reference */
1086
1087 bzero(rt, sizeof(*rt));
1088 free(rt, M_NETGRAPH_BTSOCKET_SCO);
1089 }
1090
1091 rt = rt_next;
1092 }
1093
1094 mtx_unlock(&ng_btsocket_sco_rt_mtx);
1095} /* ng_btsocket_sco_rtclean */
1096
1097/*
1098 * Initialize everything
1099 */
1100
1101static void
1102ng_btsocket_sco_init(void *arg __unused)
1103{
1104 int error = 0;
1105
1106 ng_btsocket_sco_node = NULL;
1108
1109 /* Register Netgraph node type */
1110 error = ng_newtype(&typestruct);
1111 if (error != 0) {
1113"%s: Could not register Netgraph node type, error=%d\n", __func__, error);
1114
1115 return;
1116 }
1117
1118 /* Create Netgrapg node */
1120 if (error != 0) {
1122"%s: Could not create Netgraph node, error=%d\n", __func__, error);
1123
1124 ng_btsocket_sco_node = NULL;
1125
1126 return;
1127 }
1128
1130 if (error != 0) {
1132"%s: Could not name Netgraph node, error=%d\n", __func__, error);
1133
1135 ng_btsocket_sco_node = NULL;
1136
1137 return;
1138 }
1139
1140 /* Create input queue */
1142 mtx_init(&ng_btsocket_sco_queue_mtx,
1143 "btsocks_sco_queue_mtx", NULL, MTX_DEF);
1144 TASK_INIT(&ng_btsocket_sco_queue_task, 0,
1145 ng_btsocket_sco_input, NULL);
1146
1147 /* Create list of sockets */
1148 LIST_INIT(&ng_btsocket_sco_sockets);
1150 "btsocks_sco_sockets_mtx", NULL, MTX_DEF);
1151
1152 /* Routing table */
1153 LIST_INIT(&ng_btsocket_sco_rt);
1154 mtx_init(&ng_btsocket_sco_rt_mtx,
1155 "btsocks_sco_rt_mtx", NULL, MTX_DEF);
1156 TASK_INIT(&ng_btsocket_sco_rt_task, 0,
1158} /* ng_btsocket_sco_init */
1159SYSINIT(ng_btsocket_sco_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD,
1160 ng_btsocket_sco_init, NULL);
1161
1162/*
1163 * Abort connection on socket
1164 */
1165
1166void
1167ng_btsocket_sco_abort(struct socket *so)
1168{
1169 so->so_error = ECONNABORTED;
1170
1171 (void) ng_btsocket_sco_disconnect(so);
1172} /* ng_btsocket_sco_abort */
1173
1174void
1175ng_btsocket_sco_close(struct socket *so)
1176{
1177 (void) ng_btsocket_sco_disconnect(so);
1178} /* ng_btsocket_sco_close */
1179
1180/*
1181 * Accept connection on socket. Nothing to do here, socket must be connected
1182 * and ready, so just return peer address and be done with it.
1183 */
1184
1185int
1186ng_btsocket_sco_accept(struct socket *so, struct sockaddr **nam)
1187{
1188 if (ng_btsocket_sco_node == NULL)
1189 return (EINVAL);
1190
1191 return (ng_btsocket_sco_peeraddr(so, nam));
1192} /* ng_btsocket_sco_accept */
1193
1194/*
1195 * Create and attach new socket
1196 */
1197
1198int
1199ng_btsocket_sco_attach(struct socket *so, int proto, struct thread *td)
1200{
1202 int error;
1203
1204 /* Check socket and protocol */
1205 if (ng_btsocket_sco_node == NULL)
1206 return (EPROTONOSUPPORT);
1207 if (so->so_type != SOCK_SEQPACKET)
1208 return (ESOCKTNOSUPPORT);
1209
1210#if 0 /* XXX sonewconn() calls "pru_attach" with proto == 0 */
1211 if (proto != 0)
1212 if (proto != BLUETOOTH_PROTO_SCO)
1213 return (EPROTONOSUPPORT);
1214#endif /* XXX */
1215
1216 if (pcb != NULL)
1217 return (EISCONN);
1218
1219 /* Reserve send and receive space if it is not reserved yet */
1220 if ((so->so_snd.sb_hiwat == 0) || (so->so_rcv.sb_hiwat == 0)) {
1221 error = soreserve(so, NG_BTSOCKET_SCO_SENDSPACE,
1223 if (error != 0)
1224 return (error);
1225 }
1226
1227 /* Allocate the PCB */
1228 pcb = malloc(sizeof(*pcb),
1229 M_NETGRAPH_BTSOCKET_SCO, M_NOWAIT | M_ZERO);
1230 if (pcb == NULL)
1231 return (ENOMEM);
1232
1233 /* Link the PCB and the socket */
1234 so->so_pcb = (caddr_t) pcb;
1235 pcb->so = so;
1237
1238 callout_init(&pcb->timo, 1);
1239
1240 /*
1241 * Mark PCB mutex as DUPOK to prevent "duplicated lock of
1242 * the same type" message. When accepting new SCO connection
1243 * ng_btsocket_sco_process_lp_con_ind() holds both PCB mutexes
1244 * for "old" (accepting) PCB and "new" (created) PCB.
1245 */
1246
1247 mtx_init(&pcb->pcb_mtx, "btsocks_sco_pcb_mtx", NULL,
1248 MTX_DEF|MTX_DUPOK);
1249
1250 /*
1251 * Add the PCB to the list
1252 *
1253 * XXX FIXME VERY IMPORTANT!
1254 *
1255 * This is totally FUBAR. We could get here in two cases:
1256 *
1257 * 1) When user calls socket()
1258 * 2) When we need to accept new incoming connection and call
1259 * sonewconn()
1260 *
1261 * In the first case we must acquire ng_btsocket_sco_sockets_mtx.
1262 * In the second case we hold ng_btsocket_sco_sockets_mtx already.
1263 * So we now need to distinguish between these cases. From reading
1264 * /sys/kern/uipc_socket2.c we can find out that sonewconn() calls
1265 * pru_attach with proto == 0 and td == NULL. For now use this fact
1266 * to figure out if we were called from socket() or from sonewconn().
1267 */
1268
1269 if (td != NULL)
1270 mtx_lock(&ng_btsocket_sco_sockets_mtx);
1271 else
1272 mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED);
1273
1274 LIST_INSERT_HEAD(&ng_btsocket_sco_sockets, pcb, next);
1275
1276 if (td != NULL)
1277 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1278
1279 return (0);
1280} /* ng_btsocket_sco_attach */
1281
1282/*
1283 * Bind socket
1284 */
1285
1286int
1287ng_btsocket_sco_bind(struct socket *so, struct sockaddr *nam,
1288 struct thread *td)
1289{
1290 ng_btsocket_sco_pcb_t *pcb = NULL;
1291 struct sockaddr_sco *sa = (struct sockaddr_sco *) nam;
1292
1293 if (ng_btsocket_sco_node == NULL)
1294 return (EINVAL);
1295
1296 /* Verify address */
1297 if (sa == NULL)
1298 return (EINVAL);
1299 if (sa->sco_family != AF_BLUETOOTH)
1300 return (EAFNOSUPPORT);
1301 if (sa->sco_len != sizeof(*sa))
1302 return (EINVAL);
1303
1304 mtx_lock(&ng_btsocket_sco_sockets_mtx);
1305
1306 /*
1307 * Check if other socket has this address already (look for exact
1308 * match in bdaddr) and assign socket address if it's available.
1309 */
1310
1311 if (bcmp(&sa->sco_bdaddr, NG_HCI_BDADDR_ANY, sizeof(sa->sco_bdaddr)) != 0) {
1312 LIST_FOREACH(pcb, &ng_btsocket_sco_sockets, next) {
1313 mtx_lock(&pcb->pcb_mtx);
1314
1315 if (bcmp(&pcb->src, &sa->sco_bdaddr, sizeof(bdaddr_t)) == 0) {
1316 mtx_unlock(&pcb->pcb_mtx);
1317 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1318
1319 return (EADDRINUSE);
1320 }
1321
1322 mtx_unlock(&pcb->pcb_mtx);
1323 }
1324 }
1325
1326 pcb = so2sco_pcb(so);
1327 if (pcb == NULL) {
1328 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1329 return (EINVAL);
1330 }
1331
1332 mtx_lock(&pcb->pcb_mtx);
1333 bcopy(&sa->sco_bdaddr, &pcb->src, sizeof(pcb->src));
1334 mtx_unlock(&pcb->pcb_mtx);
1335
1336 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1337
1338 return (0);
1339} /* ng_btsocket_sco_bind */
1340
1341/*
1342 * Connect socket
1343 */
1344
1345int
1346ng_btsocket_sco_connect(struct socket *so, struct sockaddr *nam,
1347 struct thread *td)
1348{
1350 struct sockaddr_sco *sa = (struct sockaddr_sco *) nam;
1351 ng_btsocket_sco_rtentry_t *rt = NULL;
1352 int have_src, error = 0;
1353
1354 /* Check socket */
1355 if (pcb == NULL)
1356 return (EINVAL);
1357 if (ng_btsocket_sco_node == NULL)
1358 return (EINVAL);
1359
1360 /* Verify address */
1361 if (sa == NULL)
1362 return (EINVAL);
1363 if (sa->sco_family != AF_BLUETOOTH)
1364 return (EAFNOSUPPORT);
1365 if (sa->sco_len != sizeof(*sa))
1366 return (EINVAL);
1367 if (bcmp(&sa->sco_bdaddr, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0)
1368 return (EDESTADDRREQ);
1369
1370 /*
1371 * Routing. Socket should be bound to some source address. The source
1372 * address can be ANY. Destination address must be set and it must not
1373 * be ANY. If source address is ANY then find first rtentry that has
1374 * src != dst.
1375 */
1376
1377 mtx_lock(&ng_btsocket_sco_rt_mtx);
1378 mtx_lock(&pcb->pcb_mtx);
1379
1380 if (pcb->state == NG_BTSOCKET_SCO_CONNECTING) {
1381 mtx_unlock(&pcb->pcb_mtx);
1382 mtx_unlock(&ng_btsocket_sco_rt_mtx);
1383
1384 return (EINPROGRESS);
1385 }
1386
1387 if (bcmp(&sa->sco_bdaddr, &pcb->src, sizeof(pcb->src)) == 0) {
1388 mtx_unlock(&pcb->pcb_mtx);
1389 mtx_unlock(&ng_btsocket_sco_rt_mtx);
1390
1391 return (EINVAL);
1392 }
1393
1394 /* Send destination address and PSM */
1395 bcopy(&sa->sco_bdaddr, &pcb->dst, sizeof(pcb->dst));
1396
1397 pcb->rt = NULL;
1398 have_src = bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(pcb->src));
1399
1400 LIST_FOREACH(rt, &ng_btsocket_sco_rt, next) {
1401 if (rt->hook == NULL || NG_HOOK_NOT_VALID(rt->hook))
1402 continue;
1403
1404 /* Match src and dst */
1405 if (have_src) {
1406 if (bcmp(&pcb->src, &rt->src, sizeof(rt->src)) == 0)
1407 break;
1408 } else {
1409 if (bcmp(&pcb->dst, &rt->src, sizeof(rt->src)) != 0)
1410 break;
1411 }
1412 }
1413
1414 if (rt != NULL) {
1415 pcb->rt = rt;
1416
1417 if (!have_src)
1418 bcopy(&rt->src, &pcb->src, sizeof(pcb->src));
1419 } else
1420 error = EHOSTUNREACH;
1421
1422 /*
1423 * Send LP_Connect request
1424 */
1425
1426 if (error == 0) {
1428 if (error == 0) {
1431 soisconnecting(pcb->so);
1432
1434 }
1435 }
1436
1437 mtx_unlock(&pcb->pcb_mtx);
1438 mtx_unlock(&ng_btsocket_sco_rt_mtx);
1439
1440 return (error);
1441} /* ng_btsocket_sco_connect */
1442
1443/*
1444 * Process ioctl's calls on socket
1445 */
1446
1447int
1448ng_btsocket_sco_control(struct socket *so, u_long cmd, caddr_t data,
1449 struct ifnet *ifp, struct thread *td)
1450{
1451 return (EINVAL);
1452} /* ng_btsocket_sco_control */
1453
1454/*
1455 * Process getsockopt/setsockopt system calls
1456 */
1457
1458int
1459ng_btsocket_sco_ctloutput(struct socket *so, struct sockopt *sopt)
1460{
1462 int error, tmp;
1463
1464 if (ng_btsocket_sco_node == NULL)
1465 return (EINVAL);
1466 if (pcb == NULL)
1467 return (EINVAL);
1468
1469 if (sopt->sopt_level != SOL_SCO)
1470 return (0);
1471
1472 mtx_lock(&pcb->pcb_mtx);
1473
1474 switch (sopt->sopt_dir) {
1475 case SOPT_GET:
1476 if (pcb->state != NG_BTSOCKET_SCO_OPEN) {
1477 error = ENOTCONN;
1478 break;
1479 }
1480
1481 switch (sopt->sopt_name) {
1482 case SO_SCO_MTU:
1483 tmp = pcb->rt->pkt_size;
1484 error = sooptcopyout(sopt, &tmp, sizeof(tmp));
1485 break;
1486
1487 case SO_SCO_CONNINFO:
1488 tmp = pcb->con_handle;
1489 error = sooptcopyout(sopt, &tmp, sizeof(tmp));
1490 break;
1491
1492 default:
1493 error = EINVAL;
1494 break;
1495 }
1496 break;
1497
1498 case SOPT_SET:
1499 error = ENOPROTOOPT;
1500 break;
1501
1502 default:
1503 error = EINVAL;
1504 break;
1505 }
1506
1507 mtx_unlock(&pcb->pcb_mtx);
1508
1509 return (error);
1510} /* ng_btsocket_sco_ctloutput */
1511
1512/*
1513 * Detach and destroy socket
1514 */
1515
1516void
1517ng_btsocket_sco_detach(struct socket *so)
1518{
1520
1521 KASSERT(pcb != NULL, ("ng_btsocket_sco_detach: pcb == NULL"));
1522
1523 if (ng_btsocket_sco_node == NULL)
1524 return;
1525
1526 mtx_lock(&ng_btsocket_sco_sockets_mtx);
1527 mtx_lock(&pcb->pcb_mtx);
1528
1529 if (pcb->flags & NG_BTSOCKET_SCO_TIMO)
1531
1532 if (pcb->state == NG_BTSOCKET_SCO_OPEN)
1534
1536
1537 LIST_REMOVE(pcb, next);
1538
1539 mtx_unlock(&pcb->pcb_mtx);
1540 mtx_unlock(&ng_btsocket_sco_sockets_mtx);
1541
1542 mtx_destroy(&pcb->pcb_mtx);
1543 bzero(pcb, sizeof(*pcb));
1544 free(pcb, M_NETGRAPH_BTSOCKET_SCO);
1545
1546 soisdisconnected(so);
1547 so->so_pcb = NULL;
1548} /* ng_btsocket_sco_detach */
1549
1550/*
1551 * Disconnect socket
1552 */
1553
1554int
1556{
1558
1559 if (pcb == NULL)
1560 return (EINVAL);
1561 if (ng_btsocket_sco_node == NULL)
1562 return (EINVAL);
1563
1564 mtx_lock(&pcb->pcb_mtx);
1565
1567 mtx_unlock(&pcb->pcb_mtx);
1568
1569 return (EINPROGRESS);
1570 }
1571
1572 if (pcb->flags & NG_BTSOCKET_SCO_TIMO)
1574
1575 if (pcb->state == NG_BTSOCKET_SCO_OPEN) {
1577
1579 soisdisconnecting(so);
1580
1582 } else {
1584 soisdisconnected(so);
1585 }
1586
1587 mtx_unlock(&pcb->pcb_mtx);
1588
1589 return (0);
1590} /* ng_btsocket_sco_disconnect */
1591
1592/*
1593 * Listen on socket
1594 */
1595
1596int
1597ng_btsocket_sco_listen(struct socket *so, int backlog, struct thread *td)
1598{
1600 int error;
1601
1602 if (pcb == NULL)
1603 return (EINVAL);
1604 if (ng_btsocket_sco_node == NULL)
1605 return (EINVAL);
1606
1607 SOCK_LOCK(so);
1608 mtx_lock(&pcb->pcb_mtx);
1609
1610 error = solisten_proto_check(so);
1611 if (error != 0)
1612 goto out;
1613#if 0
1614 if (bcmp(&pcb->src, NG_HCI_BDADDR_ANY, sizeof(bdaddr_t)) == 0) {
1615 error = EDESTADDRREQ;
1616 goto out;
1617 }
1618#endif
1619 solisten_proto(so, backlog);
1620out:
1621 mtx_unlock(&pcb->pcb_mtx);
1622 SOCK_UNLOCK(so);
1623
1624 return (error);
1625} /* ng_btsocket_listen */
1626
1627/*
1628 * Get peer address
1629 */
1630
1631int
1632ng_btsocket_sco_peeraddr(struct socket *so, struct sockaddr **nam)
1633{
1635 struct sockaddr_sco sa;
1636
1637 if (pcb == NULL)
1638 return (EINVAL);
1639 if (ng_btsocket_sco_node == NULL)
1640 return (EINVAL);
1641
1642 mtx_lock(&pcb->pcb_mtx);
1643 bcopy(&pcb->dst, &sa.sco_bdaddr, sizeof(sa.sco_bdaddr));
1644 mtx_unlock(&pcb->pcb_mtx);
1645
1646 sa.sco_len = sizeof(sa);
1647 sa.sco_family = AF_BLUETOOTH;
1648
1649 *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
1650
1651 return ((*nam == NULL)? ENOMEM : 0);
1652} /* ng_btsocket_sco_peeraddr */
1653
1654/*
1655 * Send data to socket
1656 */
1657
1658int
1659ng_btsocket_sco_send(struct socket *so, int flags, struct mbuf *m,
1660 struct sockaddr *nam, struct mbuf *control, struct thread *td)
1661{
1663 int error = 0;
1664
1665 if (ng_btsocket_sco_node == NULL) {
1666 error = ENETDOWN;
1667 goto drop;
1668 }
1669
1670 /* Check socket and input */
1671 if (pcb == NULL || m == NULL || control != NULL) {
1672 error = EINVAL;
1673 goto drop;
1674 }
1675
1676 mtx_lock(&pcb->pcb_mtx);
1677
1678 /* Make sure socket is connected */
1679 if (pcb->state != NG_BTSOCKET_SCO_OPEN) {
1680 mtx_unlock(&pcb->pcb_mtx);
1681 error = ENOTCONN;
1682 goto drop;
1683 }
1684
1685 /* Check route */
1686 if (pcb->rt == NULL ||
1687 pcb->rt->hook == NULL || NG_HOOK_NOT_VALID(pcb->rt->hook)) {
1688 mtx_unlock(&pcb->pcb_mtx);
1689 error = ENETDOWN;
1690 goto drop;
1691 }
1692
1693 /* Check packet size */
1694 if (m->m_pkthdr.len > pcb->rt->pkt_size) {
1696"%s: Packet too big, len=%d, pkt_size=%d\n",
1697 __func__, m->m_pkthdr.len, pcb->rt->pkt_size);
1698
1699 mtx_unlock(&pcb->pcb_mtx);
1700 error = EMSGSIZE;
1701 goto drop;
1702 }
1703
1704 /*
1705 * First put packet on socket send queue. Then check if we have
1706 * pending timeout. If we do not have timeout then we must send
1707 * packet and schedule timeout. Otherwise do nothing and wait for
1708 * NGM_HCI_SYNC_CON_QUEUE message.
1709 */
1710
1711 sbappendrecord(&pcb->so->so_snd, m);
1712 m = NULL;
1713
1714 if (!(pcb->flags & NG_BTSOCKET_SCO_TIMO)) {
1715 error = ng_btsocket_sco_send2(pcb);
1716 if (error == 0)
1718 else
1719 sbdroprecord(&pcb->so->so_snd); /* XXX */
1720 }
1721
1722 mtx_unlock(&pcb->pcb_mtx);
1723drop:
1724 NG_FREE_M(m); /* checks for != NULL */
1726
1727 return (error);
1728} /* ng_btsocket_sco_send */
1729
1730/*
1731 * Send first packet in the socket queue to the SCO layer
1732 */
1733
1734static int
1736{
1737 struct mbuf *m = NULL;
1738 ng_hci_scodata_pkt_t *hdr = NULL;
1739 int error = 0;
1740
1741 mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1742
1743 while (pcb->rt->pending < pcb->rt->num_pkts &&
1744 sbavail(&pcb->so->so_snd) > 0) {
1745 /* Get a copy of the first packet on send queue */
1746 m = m_dup(pcb->so->so_snd.sb_mb, M_NOWAIT);
1747 if (m == NULL) {
1748 error = ENOBUFS;
1749 break;
1750 }
1751
1752 /* Create SCO packet header */
1753 M_PREPEND(m, sizeof(*hdr), M_NOWAIT);
1754 if (m != NULL)
1755 if (m->m_len < sizeof(*hdr))
1756 m = m_pullup(m, sizeof(*hdr));
1757
1758 if (m == NULL) {
1759 error = ENOBUFS;
1760 break;
1761 }
1762
1763 /* Fill in the header */
1764 hdr = mtod(m, ng_hci_scodata_pkt_t *);
1765 hdr->type = NG_HCI_SCO_DATA_PKT;
1766 hdr->con_handle = htole16(NG_HCI_MK_CON_HANDLE(pcb->con_handle, 0, 0));
1767 hdr->length = m->m_pkthdr.len - sizeof(*hdr);
1768
1769 /* Send packet */
1770 NG_SEND_DATA_ONLY(error, pcb->rt->hook, m);
1771 if (error != 0)
1772 break;
1773
1774 pcb->rt->pending ++;
1775 }
1776
1777 return ((pcb->rt->pending > 0)? 0 : error);
1778} /* ng_btsocket_sco_send2 */
1779
1780/*
1781 * Get socket address
1782 */
1783
1784int
1785ng_btsocket_sco_sockaddr(struct socket *so, struct sockaddr **nam)
1786{
1788 struct sockaddr_sco sa;
1789
1790 if (pcb == NULL)
1791 return (EINVAL);
1792 if (ng_btsocket_sco_node == NULL)
1793 return (EINVAL);
1794
1795 mtx_lock(&pcb->pcb_mtx);
1796 bcopy(&pcb->src, &sa.sco_bdaddr, sizeof(sa.sco_bdaddr));
1797 mtx_unlock(&pcb->pcb_mtx);
1798
1799 sa.sco_len = sizeof(sa);
1800 sa.sco_family = AF_BLUETOOTH;
1801
1802 *nam = sodupsockaddr((struct sockaddr *) &sa, M_NOWAIT);
1803
1804 return ((*nam == NULL)? ENOMEM : 0);
1805} /* ng_btsocket_sco_sockaddr */
1806
1807/*****************************************************************************
1808 *****************************************************************************
1809 ** Misc. functions
1810 *****************************************************************************
1811 *****************************************************************************/
1812
1813/*
1814 * Look for the socket that listens on given bdaddr.
1815 * Returns exact or close match (if any).
1816 * Caller must hold ng_btsocket_sco_sockets_mtx.
1817 * Returns with locked pcb.
1818 */
1819
1822{
1823 ng_btsocket_sco_pcb_p p = NULL, p1 = NULL;
1824
1825 mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED);
1826
1827 LIST_FOREACH(p, &ng_btsocket_sco_sockets, next) {
1828 mtx_lock(&p->pcb_mtx);
1829
1830 if (p->so == NULL || !SOLISTENING(p->so)) {
1831 mtx_unlock(&p->pcb_mtx);
1832 continue;
1833 }
1834
1835 if (bcmp(&p->src, bdaddr, sizeof(p->src)) == 0)
1836 return (p); /* return with locked pcb */
1837
1838 if (bcmp(&p->src, NG_HCI_BDADDR_ANY, sizeof(p->src)) == 0)
1839 p1 = p;
1840
1841 mtx_unlock(&p->pcb_mtx);
1842 }
1843
1844 if (p1 != NULL)
1845 mtx_lock(&p1->pcb_mtx);
1846
1847 return (p1);
1848} /* ng_btsocket_sco_pcb_by_addr */
1849
1850/*
1851 * Look for the socket that assigned to given source address and handle.
1852 * Caller must hold ng_btsocket_sco_sockets_mtx.
1853 * Returns with locked pcb.
1854 */
1855
1858{
1859 ng_btsocket_sco_pcb_p p = NULL;
1860
1861 mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED);
1862
1863 LIST_FOREACH(p, &ng_btsocket_sco_sockets, next) {
1864 mtx_lock(&p->pcb_mtx);
1865
1866 if (p->con_handle == con_handle &&
1867 bcmp(src, &p->src, sizeof(p->src)) == 0)
1868 return (p); /* return with locked pcb */
1869
1870 mtx_unlock(&p->pcb_mtx);
1871 }
1872
1873 return (NULL);
1874} /* ng_btsocket_sco_pcb_by_handle */
1875
1876/*
1877 * Look for the socket in CONNECTING state with given source and destination
1878 * addresses. Caller must hold ng_btsocket_sco_sockets_mtx.
1879 * Returns with locked pcb.
1880 */
1881
1884{
1885 ng_btsocket_sco_pcb_p p = NULL;
1886
1887 mtx_assert(&ng_btsocket_sco_sockets_mtx, MA_OWNED);
1888
1889 LIST_FOREACH(p, &ng_btsocket_sco_sockets, next) {
1890 mtx_lock(&p->pcb_mtx);
1891
1893 bcmp(src, &p->src, sizeof(p->src)) == 0 &&
1894 bcmp(dst, &p->dst, sizeof(p->dst)) == 0)
1895 return (p); /* return with locked pcb */
1896
1897 mtx_unlock(&p->pcb_mtx);
1898 }
1899
1900 return (NULL);
1901} /* ng_btsocket_sco_pcb_by_addrs */
1902
1903/*
1904 * Set timeout on socket
1905 */
1906
1907static void
1909{
1910 mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1911
1912 if (!(pcb->flags & NG_BTSOCKET_SCO_TIMO)) {
1914 callout_reset(&pcb->timo, bluetooth_sco_rtx_timeout(),
1916 } else
1917 KASSERT(0,
1918("%s: Duplicated socket timeout?!\n", __func__));
1919} /* ng_btsocket_sco_timeout */
1920
1921/*
1922 * Unset timeout on socket
1923 */
1924
1925static void
1927{
1928 mtx_assert(&pcb->pcb_mtx, MA_OWNED);
1929
1930 if (pcb->flags & NG_BTSOCKET_SCO_TIMO) {
1931 callout_stop(&pcb->timo);
1932 pcb->flags &= ~NG_BTSOCKET_SCO_TIMO;
1933 } else
1934 KASSERT(0,
1935("%s: No socket timeout?!\n", __func__));
1936} /* ng_btsocket_sco_untimeout */
1937
1938/*
1939 * Process timeout on socket
1940 */
1941
1942static void
1944{
1946
1947 mtx_lock(&pcb->pcb_mtx);
1948
1949 pcb->flags &= ~NG_BTSOCKET_SCO_TIMO;
1950 pcb->so->so_error = ETIMEDOUT;
1951
1952 switch (pcb->state) {
1954 /* Connect timeout - close the socket */
1956 soisdisconnected(pcb->so);
1957 break;
1958
1960 /* Send timeout - did not get NGM_HCI_SYNC_CON_QUEUE */
1961 sbdroprecord(&pcb->so->so_snd);
1962 sowwakeup(pcb->so);
1963 /* XXX FIXME what to do with pcb->rt->pending??? */
1964 break;
1965
1967 /* Disconnect timeout - disconnect the socket anyway */
1969 soisdisconnected(pcb->so);
1970 break;
1971
1972 default:
1974"%s: Invalid socket state=%d\n", __func__, pcb->state);
1975 break;
1976 }
1977
1978 mtx_unlock(&pcb->pcb_mtx);
1979} /* ng_btsocket_sco_process_timeout */
uint8_t flags
Definition: netflow.h:14
#define NGI_SET_HOOK(i, h)
Definition: netgraph.h:842
int ng_connect_t(hook_p hook)
Definition: netgraph.h:104
#define NGI_MSG(i)
Definition: netgraph.h:834
#define NGI_GET_HOOK(i, h)
Definition: netgraph.h:870
#define NG_FREE_M(m)
Definition: netgraph.h:946
#define NG_HOOK_UNREF(hook)
Definition: netgraph.h:332
#define NG_HOOK_NOT_VALID(hook)
Definition: netgraph.h:337
int ng_rcvmsg_t(node_p node, item_p item, hook_p lasthook)
Definition: netgraph.h:105
#define NGQF_TYPE
Definition: netgraph.h:668
#define NGQF_DATA
Definition: netgraph.h:670
int ng_disconnect_t(hook_p hook)
Definition: netgraph.h:107
int ng_newtype(struct ng_type *tp)
Definition: ng_base.c:1272
#define NG_HOOK_PEER(hook)
Definition: netgraph.h:340
#define NG_NODE_UNREF(node)
Definition: netgraph.h:607
#define NG_HOOK_SET_PRIVATE(hook, val)
Definition: netgraph.h:333
#define NG_SEND_DATA_ONLY(error, hook, m)
Definition: netgraph.h:932
#define NGQF_MESG
Definition: netgraph.h:669
#define NG_HOOK_FORCE_QUEUE(hook)
Definition: netgraph.h:342
#define NG_HOOK_REF(hook)
Definition: netgraph.h:330
int ng_rcvdata_t(hook_p hook, item_p item)
Definition: netgraph.h:106
int ng_shutdown_t(node_p node)
Definition: netgraph.h:101
#define NG_HOOK_NAME(hook)
Definition: netgraph.h:331
#define NG_FREE_ITEM(item)
Definition: netgraph.h:847
int ng_make_node_common(struct ng_type *typep, node_p *nodep)
Definition: ng_base.c:642
int ng_name_node(node_p node, const char *name)
Definition: ng_base.c:852
int ng_constructor_t(node_p node)
Definition: netgraph.h:99
#define NGI_GET_M(i, m)
Definition: netgraph.h:852
#define NG_FREE_MSG(msg)
Definition: netgraph.h:938
#define NG_ABI_VERSION
Definition: netgraph.h:77
#define NGI_GET_MSG(i, m)
Definition: netgraph.h:858
#define NG_SEND_MSG_HOOK(error, here, msg, hook, retaddr)
Definition: netgraph.h:958
int ng_newhook_t(node_p node, hook_p hook, const char *name)
Definition: netgraph.h:102
#define NG_HOOK_PRIVATE(hook)
Definition: netgraph.h:336
SYSCTL_NODE(_net, OID_AUTO, bluetooth, CTLFLAG_RW|CTLFLAG_MPSAFE, 0, "Bluetooth family")
u_int32_t bluetooth_sco_rtx_timeout(void)
Definition: ng_bluetooth.c:215
SYSCTL_UINT(_net_bluetooth_hci, OID_AUTO, max_neighbor_age, CTLFLAG_RW, &bluetooth_hci_max_neighbor_age_value, 600, "Maximal HCI neighbor cache entry age (sec)")
#define NG_BT_ITEMQ_ENQUEUE(q, i)
Definition: ng_bluetooth.h:184
#define NG_BT_ITEMQ_FULL(q)
Definition: ng_bluetooth.h:180
#define NG_BT_ITEMQ_INIT(q, _maxlen)
Definition: ng_bluetooth.h:163
#define NG_BT_ITEMQ_DEQUEUE(q, i)
Definition: ng_bluetooth.h:190
#define NG_BT_ITEMQ_DROP(q)
Definition: ng_bluetooth.h:182
#define NG_BTSOCKET_SCO_NODE_TYPE
Definition: ng_btsocket.h:364
#define BLUETOOTH_PROTO_SCO
Definition: ng_btsocket.h:46
#define SO_SCO_CONNINFO
Definition: ng_btsocket.h:219
#define SO_SCO_MTU
Definition: ng_btsocket.h:218
#define SOL_SCO
Definition: ng_btsocket.h:216
#define NG_BTSOCKET_WARN_LEVEL
Definition: ng_btsocket.h:372
u_int8_t control
static int ng_btsocket_sco_send_lp_con_req(ng_btsocket_sco_pcb_p pcb)
static int ng_btsocket_sco_process_lp_con_ind(struct ng_mesg *msg, ng_btsocket_sco_rtentry_p rt)
#define ng_btsocket_sco_wakeup_input_task()
static ng_btsocket_sco_pcb_p ng_btsocket_sco_pcb_by_addrs(bdaddr_p src, bdaddr_p dst)
static int ng_btsocket_sco_send_lp_con_rsp(ng_btsocket_sco_rtentry_p rt, bdaddr_p dst, int status)
int ng_btsocket_sco_disconnect(struct socket *so)
static void ng_btsocket_sco_timeout(ng_btsocket_sco_pcb_p pcb)
#define ng_btsocket_sco_wakeup_route_task()
int ng_btsocket_sco_ctloutput(struct socket *so, struct sockopt *sopt)
static void ng_btsocket_sco_rtclean(void *, int)
static u_int32_t ng_btsocket_sco_debug_level
static struct mtx ng_btsocket_sco_queue_mtx
static void ng_btsocket_sco_init(void *arg __unused)
void ng_btsocket_sco_abort(struct socket *so)
static ng_btsocket_sco_pcb_p ng_btsocket_sco_pcb_by_addr(bdaddr_p bdaddr)
static LIST_HEAD(ng_btsocket_sco_pcb)
static void ng_btsocket_sco_data_input(struct mbuf *m, hook_p hook)
int ng_btsocket_sco_listen(struct socket *so, int backlog, struct thread *td)
static ng_connect_t ng_btsocket_sco_node_connect
static struct ng_type typestruct
static struct mtx ng_btsocket_sco_sockets_mtx
static int ng_btsocket_sco_send2(ng_btsocket_sco_pcb_p pcb)
void ng_btsocket_sco_close(struct socket *so)
int ng_btsocket_sco_accept(struct socket *so, struct sockaddr **nam)
static int ng_btsocket_sco_send_lp_discon_req(ng_btsocket_sco_pcb_p pcb)
static void ng_btsocket_sco_process_timeout(void *xpcb)
SYSINIT(ng_btsocket_sco_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_THIRD, ng_btsocket_sco_init, NULL)
static void ng_btsocket_sco_default_msg_input(struct ng_mesg *msg, hook_p hook)
#define NG_BTSOCKET_SCO_WARN
static int ng_btsocket_sco_process_lp_discon_ind(struct ng_mesg *msg, ng_btsocket_sco_rtentry_p rt)
int ng_btsocket_sco_attach(struct socket *so, int proto, struct thread *td)
static ng_shutdown_t ng_btsocket_sco_node_shutdown
static ng_disconnect_t ng_btsocket_sco_node_disconnect
static void ng_btsocket_sco_lp_msg_input(struct ng_mesg *msg, hook_p hook)
int ng_btsocket_sco_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *nam, struct mbuf *control, struct thread *td)
#define NG_BTSOCKET_SCO_INFO
int ng_btsocket_sco_sockaddr(struct socket *so, struct sockaddr **nam)
static ng_rcvdata_t ng_btsocket_sco_node_rcvdata
static node_p ng_btsocket_sco_node
void ng_btsocket_sco_detach(struct socket *so)
#define NG_BTSOCKET_SCO_ALERT
static void ng_btsocket_sco_untimeout(ng_btsocket_sco_pcb_p pcb)
int ng_btsocket_sco_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
#define M_NETGRAPH_BTSOCKET_SCO
static ng_rcvmsg_t ng_btsocket_sco_node_rcvmsg
static ng_constructor_t ng_btsocket_sco_node_constructor
static int ng_btsocket_sco_process_lp_con_cfm(struct ng_mesg *msg, ng_btsocket_sco_rtentry_p rt)
int ng_btsocket_sco_peeraddr(struct socket *so, struct sockaddr **nam)
static struct task ng_btsocket_sco_queue_task
static struct ng_bt_itemq ng_btsocket_sco_queue
#define NG_BTSOCKET_SCO_ERR
static ng_btsocket_sco_pcb_p ng_btsocket_sco_pcb_by_handle(bdaddr_p src, int con_handle)
int ng_btsocket_sco_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, struct thread *td)
static void ng_btsocket_sco_input(void *, int)
int ng_btsocket_sco_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
static ng_newhook_t ng_btsocket_sco_node_newhook
struct ng_btsocket_sco_pcb * ng_btsocket_sco_pcb_p
#define so2sco_pcb(so)
#define NG_BTSOCKET_SCO_CLOSED
struct ng_btsocket_sco_rtentry * ng_btsocket_sco_rtentry_p
#define NG_BTSOCKET_SCO_TIMO
#define NG_BTSOCKET_SCO_DISCONNECTING
#define NG_BTSOCKET_SCO_OPEN
#define NG_BTSOCKET_SCO_CLIENT
#define NG_BTSOCKET_SCO_SENDSPACE
#define NG_BTSOCKET_SCO_CONNECTING
#define NG_BTSOCKET_SCO_RECVSPACE
MALLOC_DEFINE(M_NG_CCATM, "ng_ccatm", "netgraph uni api node")
#define NGM_HCI_LP_CON_IND
Definition: ng_hci.h:492
#define NG_HCI_BDADDR_ANY
Definition: ng_hci.h:450
#define NGM_HCI_SYNC_CON_QUEUE
Definition: ng_hci.h:668
#define NGM_HCI_LP_CON_RSP
Definition: ng_hci.h:500
#define NGM_HCI_COOKIE
Definition: ng_hci.h:60
#define NGM_HCI_LP_CON_CFM
Definition: ng_hci.h:483
bdaddr_t * bdaddr_p
Definition: ng_hci.h:447
#define NGM_HCI_LP_DISCON_REQ
Definition: ng_hci.h:476
#define NGM_HCI_LP_DISCON_IND
Definition: ng_hci.h:508
#define NG_HCI_SCO_DATA_PKT
Definition: ng_hci.h:426
#define NGM_HCI_LP_CON_REQ
Definition: ng_hci.h:464
#define NG_HCI_CON_HANDLE(h)
Definition: ng_hci.h:389
#define NGM_HCI_NODE_UP
Definition: ng_hci.h:660
#define NG_HCI_MK_CON_HANDLE(h, pb, bc)
Definition: ng_hci.h:392
#define NG_HCI_LINK_SCO
Definition: ng_hci.h:120
#define NG_MKMESSAGE(msg, cookie, cmdid, len, how)
Definition: ng_message.h:378
char *const name
Definition: ng_ppp.c:261
cmd
Definition: ng_pppoe.h:74
uint8_t status
Definition: ng_ubt_intel.c:0
uint8_t data[]
Definition: ng_ubt_var.h:2
u_int32_t maxlen
Definition: ng_bluetooth.h:157
u_int32_t drops
Definition: ng_bluetooth.h:158
u_int32_t len
Definition: ng_bluetooth.h:156
struct socket * so
struct callout timo
ng_btsocket_sco_rtentry_p rt
struct ng_hook * hook
bdaddr_t bdaddr
Definition: ng_hci.h:488
u_int16_t con_handle
Definition: ng_hci.h:487
u_int8_t status
Definition: ng_hci.h:485
bdaddr_t bdaddr
Definition: ng_hci.h:496
bdaddr_t bdaddr
Definition: ng_hci.h:467
u_int16_t link_type
Definition: ng_hci.h:466
u_int8_t link_type
Definition: ng_hci.h:503
u_int8_t status
Definition: ng_hci.h:502
bdaddr_t bdaddr
Definition: ng_hci.h:504
u_int16_t con_handle
Definition: ng_hci.h:512
u_int16_t con_handle
Definition: ng_hci.h:478
u_int16_t num_pkts
Definition: ng_hci.h:663
u_int16_t pkt_size
Definition: ng_hci.h:662
bdaddr_t bdaddr
Definition: ng_hci.h:665
u_int16_t con_handle
Definition: ng_hci.h:670
u_long el_flags
Definition: netgraph.h:636
u_int32_t arglen
Definition: ng_message.h:62
u_int32_t typecookie
Definition: ng_message.h:66
struct ng_mesg::ng_msghdr header
char data[]
Definition: ng_message.h:69
u_int32_t version
Definition: netgraph.h:1077
bdaddr_t sco_bdaddr
Definition: ng_btsocket.h:212
u_char sco_family
Definition: ng_btsocket.h:211
u_char sco_len
Definition: ng_btsocket.h:210