6 * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
30 * $Id: ng_hci_main.c,v 1.2 2003/03/18 00:09:36 max Exp $
31 * $FreeBSD: src/sys/netgraph/bluetooth/hci/ng_hci_main.c,v 1.6 2005/01/07 01:45:43 imp Exp $
32 * $DragonFly: src/sys/netgraph7/bluetooth/hci/ng_hci_main.c,v 1.2 2008/06/26 23:05:40 dillon Exp $
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/endian.h>
39 #include <sys/malloc.h>
41 #include <sys/queue.h>
42 #include "ng_message.h"
45 #include "bluetooth/include/ng_bluetooth.h"
46 #include "bluetooth/include/ng_hci.h"
47 #include "bluetooth/hci/ng_hci_var.h"
48 #include "bluetooth/hci/ng_hci_prse.h"
49 #include "bluetooth/hci/ng_hci_cmds.h"
50 #include "bluetooth/hci/ng_hci_evnt.h"
51 #include "bluetooth/hci/ng_hci_ulpi.h"
52 #include "bluetooth/hci/ng_hci_misc.h"
54 /******************************************************************************
55 ******************************************************************************
56 ** This node implements Bluetooth Host Controller Interface (HCI)
57 ******************************************************************************
58 ******************************************************************************/
61 #ifdef NG_SEPARATE_MALLOC
62 MALLOC_DEFINE(M_NETGRAPH_HCI
, "netgraph_hci", "Netgraph Bluetooth HCI node");
64 #define M_NETGRAPH_HCI M_NETGRAPH
65 #endif /* NG_SEPARATE_MALLOC */
67 /* Netgraph node methods */
68 static ng_constructor_t ng_hci_constructor
;
69 static ng_shutdown_t ng_hci_shutdown
;
70 static ng_newhook_t ng_hci_newhook
;
71 static ng_connect_t ng_hci_connect
;
72 static ng_disconnect_t ng_hci_disconnect
;
73 static ng_rcvmsg_t ng_hci_default_rcvmsg
;
74 static ng_rcvmsg_t ng_hci_upper_rcvmsg
;
75 static ng_rcvdata_t ng_hci_drv_rcvdata
;
76 static ng_rcvdata_t ng_hci_acl_rcvdata
;
77 static ng_rcvdata_t ng_hci_sco_rcvdata
;
78 static ng_rcvdata_t ng_hci_raw_rcvdata
;
80 /* Netgraph node type descriptor */
81 static struct ng_type typestruct
= {
82 .version
= NG_ABI_VERSION
,
83 .name
= NG_HCI_NODE_TYPE
,
84 .constructor
= ng_hci_constructor
,
85 .rcvmsg
= ng_hci_default_rcvmsg
,
86 .shutdown
= ng_hci_shutdown
,
87 .newhook
= ng_hci_newhook
,
88 .connect
= ng_hci_connect
,
89 .rcvdata
= ng_hci_drv_rcvdata
,
90 .disconnect
= ng_hci_disconnect
,
91 .cmdlist
= ng_hci_cmdlist
,
93 NETGRAPH_INIT(hci
, &typestruct
);
94 MODULE_VERSION(ng_hci
, NG_BLUETOOTH_VERSION
);
95 MODULE_DEPEND(ng_hci
, ng_bluetooth
, NG_BLUETOOTH_VERSION
,
96 NG_BLUETOOTH_VERSION
, NG_BLUETOOTH_VERSION
);
98 /*****************************************************************************
99 *****************************************************************************
100 ** Netgraph methods implementation
101 *****************************************************************************
102 *****************************************************************************/
105 * Create new instance of HCI node (new unit)
109 ng_hci_constructor(node_p node
)
111 ng_hci_unit_p unit
= NULL
;
113 MALLOC(unit
, ng_hci_unit_p
, sizeof(*unit
), M_NETGRAPH_HCI
,
114 M_WAITOK
| M_NULLOK
| M_ZERO
);
119 unit
->debug
= NG_HCI_WARN_LEVEL
;
121 unit
->link_policy_mask
= 0xffff; /* Enable all supported modes */
122 unit
->packet_mask
= 0xffff; /* Enable all packet types */
123 unit
->role_switch
= 1; /* Enable role switch (if device supports it) */
126 * Set default buffer info
129 * One ACL packet with max. size of 17 bytes (1 DM1 packet)
130 * One SCO packet with max. size of 10 bytes (1 HV1 packet)
133 NG_HCI_BUFF_CMD_SET(unit
->buffer
, 1);
134 NG_HCI_BUFF_ACL_SET(unit
->buffer
, 1, 17, 1);
135 NG_HCI_BUFF_SCO_SET(unit
->buffer
, 1, 10, 1);
137 /* Init command queue & command timeout handler */
138 ng_callout_init(&unit
->cmd_timo
);
139 NG_BT_MBUFQ_INIT(&unit
->cmdq
, NG_HCI_CMD_QUEUE_LEN
);
142 LIST_INIT(&unit
->con_list
);
143 LIST_INIT(&unit
->neighbors
);
146 * This node has to be a WRITER because both data and messages
147 * can change node state.
150 NG_NODE_FORCE_WRITER(node
);
151 NG_NODE_SET_PRIVATE(node
, unit
);
154 } /* ng_hci_constructor */
161 ng_hci_shutdown(node_p node
)
163 ng_hci_unit_p unit
= (ng_hci_unit_p
) NG_NODE_PRIVATE(node
);
165 NG_NODE_SET_PRIVATE(node
, NULL
);
169 ng_hci_unit_clean(unit
, 0x16 /* Connection terminated by local host */);
171 NG_BT_MBUFQ_DESTROY(&unit
->cmdq
);
173 bzero(unit
, sizeof(*unit
));
174 FREE(unit
, M_NETGRAPH_HCI
);
177 } /* ng_hci_shutdown */
180 * Give our OK for a hook to be added. Unit driver is connected to the driver
181 * (NG_HCI_HOOK_DRV) hook. Upper layer protocols are connected to appropriate
182 * (NG_HCI_HOOK_ACL or NG_HCI_HOOK_SCO) hooks.
186 ng_hci_newhook(node_p node
, hook_p hook
, char const *name
)
188 ng_hci_unit_p unit
= (ng_hci_unit_p
) NG_NODE_PRIVATE(node
);
191 if (strcmp(name
, NG_HCI_HOOK_DRV
) == 0)
193 else if (strcmp(name
, NG_HCI_HOOK_ACL
) == 0)
195 else if (strcmp(name
, NG_HCI_HOOK_SCO
) == 0)
197 else if (strcmp(name
, NG_HCI_HOOK_RAW
) == 0)
208 } /* ng_hci_newhook */
211 * Give our final OK to connect hook
215 ng_hci_connect(hook_p hook
)
217 ng_hci_unit_p unit
= (ng_hci_unit_p
) NG_NODE_PRIVATE(NG_HOOK_NODE(hook
));
219 if (hook
!= unit
->drv
) {
220 if (hook
== unit
->acl
) {
221 NG_HOOK_SET_RCVMSG(hook
, ng_hci_upper_rcvmsg
);
222 NG_HOOK_SET_RCVDATA(hook
, ng_hci_acl_rcvdata
);
223 } else if (hook
== unit
->sco
) {
224 NG_HOOK_SET_RCVMSG(hook
, ng_hci_upper_rcvmsg
);
225 NG_HOOK_SET_RCVDATA(hook
, ng_hci_sco_rcvdata
);
227 NG_HOOK_SET_RCVDATA(hook
, ng_hci_raw_rcvdata
);
229 /* Send delayed notification to the upper layers */
230 if (hook
!= unit
->raw
)
231 ng_send_fn(unit
->node
, hook
, ng_hci_node_is_up
, NULL
,0);
233 unit
->state
|= NG_HCI_UNIT_CONNECTED
;
236 } /* ng_hci_connect */
239 * Disconnect the hook
243 ng_hci_disconnect(hook_p hook
)
245 ng_hci_unit_p unit
= (ng_hci_unit_p
) NG_NODE_PRIVATE(NG_HOOK_NODE(hook
));
247 if (hook
== unit
->acl
)
249 else if (hook
== unit
->sco
)
251 else if (hook
== unit
->raw
)
253 else if (hook
== unit
->drv
) {
256 /* Connection terminated by local host */
257 ng_hci_unit_clean(unit
, 0x16);
258 unit
->state
&= ~(NG_HCI_UNIT_CONNECTED
|NG_HCI_UNIT_INITED
);
262 /* Shutdown when all hooks are disconnected */
263 if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook
)) == 0) &&
264 (NG_NODE_IS_VALID(NG_HOOK_NODE(hook
))))
265 ng_rmnode_self(NG_HOOK_NODE(hook
));
268 } /* ng_hci_disconnect */
271 * Default control message processing routine. Control message could be:
273 * 1) GENERIC Netgraph messages
275 * 2) Control message directed to the node itself.
279 ng_hci_default_rcvmsg(node_p node
, item_p item
, hook_p lasthook
)
281 ng_hci_unit_p unit
= (ng_hci_unit_p
) NG_NODE_PRIVATE(node
);
282 struct ng_mesg
*msg
= NULL
, *rsp
= NULL
;
285 NGI_GET_MSG(item
, msg
);
287 switch (msg
->header
.typecookie
) {
288 case NGM_GENERIC_COOKIE
:
289 switch (msg
->header
.cmd
) {
290 case NGM_TEXT_STATUS
: {
292 acl_total
, acl_avail
, acl_size
,
293 sco_total
, sco_avail
, sco_size
;
295 NG_MKRESPONSE(rsp
, msg
, NG_TEXTRESPONSE
, M_WAITOK
| M_NULLOK
);
301 NG_HCI_BUFF_CMD_GET(unit
->buffer
, cmd_avail
);
303 NG_HCI_BUFF_ACL_AVAIL(unit
->buffer
, acl_avail
);
304 NG_HCI_BUFF_ACL_TOTAL(unit
->buffer
, acl_total
);
305 NG_HCI_BUFF_ACL_SIZE(unit
->buffer
, acl_size
);
307 NG_HCI_BUFF_SCO_AVAIL(unit
->buffer
, sco_avail
);
308 NG_HCI_BUFF_SCO_TOTAL(unit
->buffer
, sco_total
);
309 NG_HCI_BUFF_SCO_SIZE(unit
->buffer
, sco_size
);
311 snprintf(rsp
->data
, NG_TEXTRESPONSE
,
312 "bdaddr %x:%x:%x:%x:%x:%x\n" \
313 "Hooks %s %s %s %s\n" \
316 "Buffer cmd:%d,acl:%d,%d,%d,sco:%d,%d,%d",
317 unit
->bdaddr
.b
[5], unit
->bdaddr
.b
[4],
318 unit
->bdaddr
.b
[3], unit
->bdaddr
.b
[2],
319 unit
->bdaddr
.b
[1], unit
->bdaddr
.b
[0],
320 (unit
->drv
!= NULL
)? NG_HCI_HOOK_DRV
: "",
321 (unit
->acl
!= NULL
)? NG_HCI_HOOK_ACL
: "",
322 (unit
->sco
!= NULL
)? NG_HCI_HOOK_SCO
: "",
323 (unit
->raw
!= NULL
)? NG_HCI_HOOK_RAW
: "",
325 NG_BT_MBUFQ_LEN(&unit
->cmdq
),
327 acl_avail
, acl_total
, acl_size
,
328 sco_avail
, sco_total
, sco_size
);
338 switch (msg
->header
.cmd
) {
339 /* Get current node state */
340 case NGM_HCI_NODE_GET_STATE
:
341 NG_MKRESPONSE(rsp
, msg
, sizeof(unit
->state
), M_WAITOK
| M_NULLOK
);
347 *((ng_hci_node_state_ep
*)(rsp
->data
)) = unit
->state
;
350 /* Turn INITED bit - node initialized */
351 case NGM_HCI_NODE_INIT
:
352 if (bcmp(&unit
->bdaddr
, NG_HCI_BDADDR_ANY
,
353 sizeof(bdaddr_t
)) == 0) {
358 unit
->state
|= NG_HCI_UNIT_INITED
;
360 ng_hci_node_is_up(unit
->node
, unit
->acl
, NULL
, 0);
361 ng_hci_node_is_up(unit
->node
, unit
->sco
, NULL
, 0);
364 /* Get node debug level */
365 case NGM_HCI_NODE_GET_DEBUG
:
366 NG_MKRESPONSE(rsp
, msg
, sizeof(unit
->debug
), M_WAITOK
| M_NULLOK
);
372 *((ng_hci_node_debug_ep
*)(rsp
->data
)) = unit
->debug
;
375 /* Set node debug level */
376 case NGM_HCI_NODE_SET_DEBUG
:
377 if (msg
->header
.arglen
!= sizeof(ng_hci_node_debug_ep
)){
382 unit
->debug
= *((ng_hci_node_debug_ep
*)(msg
->data
));
385 /* Get buffer info */
386 case NGM_HCI_NODE_GET_BUFFER
: {
387 ng_hci_node_buffer_ep
*ep
= NULL
;
389 NG_MKRESPONSE(rsp
, msg
, sizeof(ng_hci_node_buffer_ep
),
390 M_WAITOK
| M_NULLOK
);
396 ep
= (ng_hci_node_buffer_ep
*)(rsp
->data
);
398 NG_HCI_BUFF_CMD_GET(unit
->buffer
, ep
->cmd_free
);
399 NG_HCI_BUFF_ACL_AVAIL(unit
->buffer
, ep
->acl_free
);
400 NG_HCI_BUFF_ACL_TOTAL(unit
->buffer
, ep
->acl_pkts
);
401 NG_HCI_BUFF_ACL_SIZE(unit
->buffer
, ep
->acl_size
);
402 NG_HCI_BUFF_SCO_AVAIL(unit
->buffer
, ep
->sco_free
);
403 NG_HCI_BUFF_SCO_TOTAL(unit
->buffer
, ep
->sco_pkts
);
404 NG_HCI_BUFF_SCO_SIZE(unit
->buffer
, ep
->sco_size
);
408 case NGM_HCI_NODE_GET_BDADDR
:
409 NG_MKRESPONSE(rsp
, msg
, sizeof(bdaddr_t
), M_WAITOK
| M_NULLOK
);
415 bcopy(&unit
->bdaddr
, rsp
->data
, sizeof(bdaddr_t
));
419 case NGM_HCI_NODE_GET_FEATURES
:
420 NG_MKRESPONSE(rsp
,msg
,sizeof(unit
->features
),M_WAITOK
| M_NULLOK
);
426 bcopy(&unit
->features
,rsp
->data
,sizeof(unit
->features
));
430 case NGM_HCI_NODE_GET_STAT
:
431 NG_MKRESPONSE(rsp
, msg
, sizeof(unit
->stat
), M_WAITOK
| M_NULLOK
);
437 bcopy(&unit
->stat
, rsp
->data
, sizeof(unit
->stat
));
441 case NGM_HCI_NODE_RESET_STAT
:
442 NG_HCI_STAT_RESET(unit
->stat
);
445 /* Clean up neighbors list */
446 case NGM_HCI_NODE_FLUSH_NEIGHBOR_CACHE
:
447 ng_hci_flush_neighbor_cache(unit
);
450 /* Get neighbor cache entries */
451 case NGM_HCI_NODE_GET_NEIGHBOR_CACHE
: {
452 ng_hci_neighbor_p n
= NULL
;
453 ng_hci_node_get_neighbor_cache_ep
*e1
= NULL
;
454 ng_hci_node_neighbor_cache_entry_ep
*e2
= NULL
;
457 /* Look for the fresh entries in the cache */
458 for (n
= LIST_FIRST(&unit
->neighbors
); n
!= NULL
; ) {
459 ng_hci_neighbor_p nn
= LIST_NEXT(n
, next
);
461 if (ng_hci_neighbor_stale(n
))
462 ng_hci_free_neighbor(n
);
468 if (s
> NG_HCI_MAX_NEIGHBOR_NUM
)
469 s
= NG_HCI_MAX_NEIGHBOR_NUM
;
471 /* Prepare response */
472 NG_MKRESPONSE(rsp
, msg
, sizeof(*e1
) + s
* sizeof(*e2
),
473 M_WAITOK
| M_NULLOK
);
479 e1
= (ng_hci_node_get_neighbor_cache_ep
*)(rsp
->data
);
480 e2
= (ng_hci_node_neighbor_cache_entry_ep
*)(e1
+ 1);
484 LIST_FOREACH(n
, &unit
->neighbors
, next
) {
485 e2
->page_scan_rep_mode
= n
->page_scan_rep_mode
;
486 e2
->page_scan_mode
= n
->page_scan_mode
;
487 e2
->clock_offset
= n
->clock_offset
;
488 bcopy(&n
->bdaddr
, &e2
->bdaddr
,
490 bcopy(&n
->features
, &e2
->features
,
491 sizeof(e2
->features
));
499 /* Get connection list */
500 case NGM_HCI_NODE_GET_CON_LIST
: {
501 ng_hci_unit_con_p c
= NULL
;
502 ng_hci_node_con_list_ep
*e1
= NULL
;
503 ng_hci_node_con_ep
*e2
= NULL
;
506 /* Count number of connections in the list */
507 LIST_FOREACH(c
, &unit
->con_list
, next
)
509 if (s
> NG_HCI_MAX_CON_NUM
)
510 s
= NG_HCI_MAX_CON_NUM
;
512 /* Prepare response */
513 NG_MKRESPONSE(rsp
, msg
, sizeof(*e1
) + s
* sizeof(*e2
),
514 M_WAITOK
| M_NULLOK
);
520 e1
= (ng_hci_node_con_list_ep
*)(rsp
->data
);
521 e2
= (ng_hci_node_con_ep
*)(e1
+ 1);
523 e1
->num_connections
= s
;
525 LIST_FOREACH(c
, &unit
->con_list
, next
) {
526 e2
->link_type
= c
->link_type
;
527 e2
->encryption_mode
= c
->encryption_mode
;
531 e2
->state
= c
->state
;
533 e2
->pending
= c
->pending
;
534 e2
->queue_len
= NG_BT_ITEMQ_LEN(&c
->conq
);
536 e2
->con_handle
= c
->con_handle
;
537 bcopy(&c
->bdaddr
, &e2
->bdaddr
,
546 /* Get link policy settings mask */
547 case NGM_HCI_NODE_GET_LINK_POLICY_SETTINGS_MASK
:
548 NG_MKRESPONSE(rsp
, msg
, sizeof(unit
->link_policy_mask
),
549 M_WAITOK
| M_NULLOK
);
555 *((ng_hci_node_link_policy_mask_ep
*)(rsp
->data
)) =
556 unit
->link_policy_mask
;
559 /* Set link policy settings mask */
560 case NGM_HCI_NODE_SET_LINK_POLICY_SETTINGS_MASK
:
561 if (msg
->header
.arglen
!=
562 sizeof(ng_hci_node_link_policy_mask_ep
)) {
567 unit
->link_policy_mask
=
568 *((ng_hci_node_link_policy_mask_ep
*)
572 /* Get packet mask */
573 case NGM_HCI_NODE_GET_PACKET_MASK
:
574 NG_MKRESPONSE(rsp
, msg
, sizeof(unit
->packet_mask
),
575 M_WAITOK
| M_NULLOK
);
581 *((ng_hci_node_packet_mask_ep
*)(rsp
->data
)) =
585 /* Set packet mask */
586 case NGM_HCI_NODE_SET_PACKET_MASK
:
587 if (msg
->header
.arglen
!=
588 sizeof(ng_hci_node_packet_mask_ep
)) {
594 *((ng_hci_node_packet_mask_ep
*)(msg
->data
));
597 /* Get role switch */
598 case NGM_HCI_NODE_GET_ROLE_SWITCH
:
599 NG_MKRESPONSE(rsp
, msg
, sizeof(unit
->role_switch
),
600 M_WAITOK
| M_NULLOK
);
606 *((ng_hci_node_role_switch_ep
*)(rsp
->data
)) =
610 /* Set role switch */
611 case NGM_HCI_NODE_SET_ROLE_SWITCH
:
612 if (msg
->header
.arglen
!=
613 sizeof(ng_hci_node_role_switch_ep
)) {
619 *((ng_hci_node_role_switch_ep
*)(msg
->data
));
633 /* NG_RESPOND_MSG should take care of "item" and "rsp" */
634 NG_RESPOND_MSG(error
, node
, item
, rsp
);
638 } /* ng_hci_default_rcvmsg */
641 * Process control message from upstream hooks (ACL and SCO).
642 * Handle LP_xxx messages here, give everything else to default routine.
646 ng_hci_upper_rcvmsg(node_p node
, item_p item
, hook_p lasthook
)
648 ng_hci_unit_p unit
= (ng_hci_unit_p
) NG_NODE_PRIVATE(node
);
651 switch (NGI_MSG(item
)->header
.typecookie
) {
653 switch (NGI_MSG(item
)->header
.cmd
) {
654 case NGM_HCI_LP_CON_REQ
:
655 error
= ng_hci_lp_con_req(unit
, item
, lasthook
);
658 case NGM_HCI_LP_DISCON_REQ
: /* XXX not defined by specs */
659 error
= ng_hci_lp_discon_req(unit
, item
, lasthook
);
662 case NGM_HCI_LP_CON_RSP
:
663 error
= ng_hci_lp_con_rsp(unit
, item
, lasthook
);
666 case NGM_HCI_LP_QOS_REQ
:
667 error
= ng_hci_lp_qos_req(unit
, item
, lasthook
);
671 error
= ng_hci_default_rcvmsg(node
, item
, lasthook
);
677 error
= ng_hci_default_rcvmsg(node
, item
, lasthook
);
682 } /* ng_hci_upper_rcvmsg */
685 * Process data packet from the driver hook.
686 * We expect HCI events, ACL or SCO data packets.
690 ng_hci_drv_rcvdata(hook_p hook
, item_p item
)
692 ng_hci_unit_p unit
= (ng_hci_unit_p
) NG_NODE_PRIVATE(NG_HOOK_NODE(hook
));
693 struct mbuf
*m
= NULL
;
697 m
= NGI_M(item
); /* item still has mbuf, just peeking */
698 m
->m_flags
|= M_PROTO1
; /* mark as incoming packet */
700 NG_HCI_STAT_BYTES_RECV(unit
->stat
, m
->m_pkthdr
.len
);
702 /* Give copy packet to RAW hook */
703 ng_hci_mtap(unit
, m
);
707 * Lower layer drivers MUST NOT send mbuf chain with empty mbuf at
708 * the beginning of the chain. HCI layer WILL NOT call m_pullup() here.
711 switch (*mtod(m
, u_int8_t
*)) {
712 case NG_HCI_ACL_DATA_PKT
:
713 NG_HCI_STAT_ACL_RECV(unit
->stat
);
715 if ((unit
->state
& NG_HCI_UNIT_READY
) != NG_HCI_UNIT_READY
||
716 unit
->acl
== NULL
|| NG_HOOK_NOT_VALID(unit
->acl
)) {
718 "%s: %s - could not forward HCI ACL data packet, state=%#x, hook=%p\n",
719 __func__
, NG_NODE_NAME(unit
->node
),
720 unit
->state
, unit
->acl
);
724 NG_FWD_ITEM_HOOK(error
, item
, unit
->acl
);
727 case NG_HCI_SCO_DATA_PKT
:
728 NG_HCI_STAT_SCO_RECV(unit
->stat
);
730 if ((unit
->state
& NG_HCI_UNIT_READY
) != NG_HCI_UNIT_READY
||
731 unit
->sco
== NULL
|| NG_HOOK_NOT_VALID(unit
->sco
)) {
733 "%s: %s - could not forward HCI SCO data packet, state=%#x, hook=%p\n",
734 __func__
, NG_NODE_NAME(unit
->node
),
735 unit
->state
, unit
->sco
);
739 NG_FWD_ITEM_HOOK(error
, item
, unit
->sco
);
742 case NG_HCI_EVENT_PKT
:
743 NG_HCI_STAT_EVNT_RECV(unit
->stat
);
745 /* Detach mbuf, discard item and process event */
749 error
= ng_hci_process_event(unit
, m
);
754 "%s: %s - got unknown HCI packet type=%#x\n",
755 __func__
, NG_NODE_NAME(unit
->node
),
756 *mtod(m
, u_int8_t
*));
765 } /* ng_hci_drv_rcvdata */
768 * Process data packet from ACL upstream hook.
769 * We expect valid HCI ACL data packets.
773 ng_hci_acl_rcvdata(hook_p hook
, item_p item
)
775 ng_hci_unit_p unit
= (ng_hci_unit_p
) NG_NODE_PRIVATE(NG_HOOK_NODE(hook
));
776 struct mbuf
*m
= NULL
;
777 ng_hci_unit_con_p con
= NULL
;
778 u_int16_t con_handle
;
781 NG_HCI_BUFF_ACL_SIZE(unit
->buffer
, size
);
786 if (*mtod(m
, u_int8_t
*) != NG_HCI_ACL_DATA_PKT
) {
788 "%s: %s - invalid HCI data packet type=%#x\n",
789 __func__
, NG_NODE_NAME(unit
->node
),
790 *mtod(m
, u_int8_t
*));
796 if (m
->m_pkthdr
.len
< sizeof(ng_hci_acldata_pkt_t
) ||
797 m
->m_pkthdr
.len
> sizeof(ng_hci_acldata_pkt_t
) + size
) {
799 "%s: %s - invalid HCI ACL data packet, len=%d, mtu=%d\n",
800 __func__
, NG_NODE_NAME(unit
->node
),
801 m
->m_pkthdr
.len
, size
);
807 NG_HCI_M_PULLUP(m
, sizeof(ng_hci_acldata_pkt_t
));
813 con_handle
= NG_HCI_CON_HANDLE(le16toh(
814 mtod(m
, ng_hci_acldata_pkt_t
*)->con_handle
));
815 size
= le16toh(mtod(m
, ng_hci_acldata_pkt_t
*)->length
);
817 if (m
->m_pkthdr
.len
!= sizeof(ng_hci_acldata_pkt_t
) + size
) {
819 "%s: %s - invalid HCI ACL data packet size, len=%d, length=%d\n",
820 __func__
, NG_NODE_NAME(unit
->node
),
821 m
->m_pkthdr
.len
, size
);
828 con
= ng_hci_con_by_handle(unit
, con_handle
);
831 "%s: %s - unexpected HCI ACL data packet. Connection does not exists, " \
832 "con_handle=%d\n", __func__
, NG_NODE_NAME(unit
->node
), con_handle
);
838 if (con
->link_type
!= NG_HCI_LINK_ACL
) {
840 "%s: %s - unexpected HCI ACL data packet. Not ACL link, con_handle=%d, " \
841 "link_type=%d\n", __func__
, NG_NODE_NAME(unit
->node
),
842 con_handle
, con
->link_type
);
848 if (con
->state
!= NG_HCI_CON_OPEN
) {
850 "%s: %s - unexpected HCI ACL data packet. Invalid connection state=%d, " \
851 "con_handle=%d\n", __func__
, NG_NODE_NAME(unit
->node
),
852 con
->state
, con_handle
);
858 if (NG_BT_ITEMQ_FULL(&con
->conq
)) {
860 "%s: %s - dropping HCI ACL data packet, con_handle=%d, len=%d, queue_len=%d\n",
861 __func__
, NG_NODE_NAME(unit
->node
), con_handle
,
862 m
->m_pkthdr
.len
, NG_BT_ITEMQ_LEN(&con
->conq
));
864 NG_BT_ITEMQ_DROP(&con
->conq
);
870 /* Queue item and schedule data transfer */
872 NG_BT_ITEMQ_ENQUEUE(&con
->conq
, item
);
876 ng_hci_send_data(unit
);
881 NG_FREE_M(m
); /* NG_FREE_M() checks for m != NULL */
884 } /* ng_hci_acl_rcvdata */
887 * Process data packet from SCO upstream hook.
888 * We expect valid HCI SCO data packets
892 ng_hci_sco_rcvdata(hook_p hook
, item_p item
)
894 ng_hci_unit_p unit
= (ng_hci_unit_p
) NG_NODE_PRIVATE(NG_HOOK_NODE(hook
));
895 struct mbuf
*m
= NULL
;
896 ng_hci_unit_con_p con
= NULL
;
897 u_int16_t con_handle
;
900 NG_HCI_BUFF_SCO_SIZE(unit
->buffer
, size
);
905 if (*mtod(m
, u_int8_t
*) != NG_HCI_SCO_DATA_PKT
) {
907 "%s: %s - invalid HCI data packet type=%#x\n",
908 __func__
, NG_NODE_NAME(unit
->node
),
909 *mtod(m
, u_int8_t
*));
915 if (m
->m_pkthdr
.len
< sizeof(ng_hci_scodata_pkt_t
) ||
916 m
->m_pkthdr
.len
> sizeof(ng_hci_scodata_pkt_t
) + size
) {
918 "%s: %s - invalid HCI SCO data packet, len=%d, mtu=%d\n",
919 __func__
, NG_NODE_NAME(unit
->node
),
920 m
->m_pkthdr
.len
, size
);
926 NG_HCI_M_PULLUP(m
, sizeof(ng_hci_scodata_pkt_t
));
932 con_handle
= NG_HCI_CON_HANDLE(le16toh(
933 mtod(m
, ng_hci_scodata_pkt_t
*)->con_handle
));
934 size
= mtod(m
, ng_hci_scodata_pkt_t
*)->length
;
936 if (m
->m_pkthdr
.len
!= sizeof(ng_hci_scodata_pkt_t
) + size
) {
938 "%s: %s - invalid HCI SCO data packet size, len=%d, length=%d\n",
939 __func__
, NG_NODE_NAME(unit
->node
),
940 m
->m_pkthdr
.len
, size
);
947 con
= ng_hci_con_by_handle(unit
, con_handle
);
950 "%s: %s - unexpected HCI SCO data packet. Connection does not exists, " \
951 "con_handle=%d\n", __func__
, NG_NODE_NAME(unit
->node
), con_handle
);
957 if (con
->link_type
!= NG_HCI_LINK_SCO
) {
959 "%s: %s - unexpected HCI SCO data packet. Not SCO link, con_handle=%d, " \
960 "link_type=%d\n", __func__
, NG_NODE_NAME(unit
->node
),
961 con_handle
, con
->link_type
);
967 if (con
->state
!= NG_HCI_CON_OPEN
) {
969 "%s: %s - unexpected HCI SCO data packet. Invalid connection state=%d, " \
970 "con_handle=%d\n", __func__
, NG_NODE_NAME(unit
->node
),
971 con
->state
, con_handle
);
977 if (NG_BT_ITEMQ_FULL(&con
->conq
)) {
979 "%s: %s - dropping HCI SCO data packet, con_handle=%d, len=%d, queue_len=%d\n",
980 __func__
, NG_NODE_NAME(unit
->node
), con_handle
,
981 m
->m_pkthdr
.len
, NG_BT_ITEMQ_LEN(&con
->conq
));
983 NG_BT_ITEMQ_DROP(&con
->conq
);
989 /* Queue item and schedule data transfer */
991 NG_BT_ITEMQ_ENQUEUE(&con
->conq
, item
);
995 ng_hci_send_data(unit
);
1000 NG_FREE_M(m
); /* NG_FREE_M() checks for m != NULL */
1003 } /* ng_hci_sco_rcvdata */
1006 * Process data packet from uptream RAW hook.
1007 * We expect valid HCI command packets.
1011 ng_hci_raw_rcvdata(hook_p hook
, item_p item
)
1013 ng_hci_unit_p unit
= (ng_hci_unit_p
) NG_NODE_PRIVATE(NG_HOOK_NODE(hook
));
1014 struct mbuf
*m
= NULL
;
1021 if (*mtod(m
, u_int8_t
*) != NG_HCI_CMD_PKT
) {
1023 "%s: %s - invalid HCI command packet type=%#x\n",
1024 __func__
, NG_NODE_NAME(unit
->node
),
1025 *mtod(m
, u_int8_t
*));
1031 if (m
->m_pkthdr
.len
< sizeof(ng_hci_cmd_pkt_t
)) {
1033 "%s: %s - invalid HCI command packet len=%d\n",
1034 __func__
, NG_NODE_NAME(unit
->node
), m
->m_pkthdr
.len
);
1040 NG_HCI_M_PULLUP(m
, sizeof(ng_hci_cmd_pkt_t
));
1046 if (m
->m_pkthdr
.len
!=
1047 mtod(m
, ng_hci_cmd_pkt_t
*)->length
+ sizeof(ng_hci_cmd_pkt_t
)) {
1049 "%s: %s - invalid HCI command packet size, len=%d, length=%d\n",
1050 __func__
, NG_NODE_NAME(unit
->node
), m
->m_pkthdr
.len
,
1051 mtod(m
, ng_hci_cmd_pkt_t
*)->length
);
1057 if (mtod(m
, ng_hci_cmd_pkt_t
*)->opcode
== 0) {
1059 "%s: %s - invalid HCI command opcode\n",
1060 __func__
, NG_NODE_NAME(unit
->node
));
1066 if (NG_BT_MBUFQ_FULL(&unit
->cmdq
)) {
1068 "%s: %s - dropping HCI command packet, len=%d, queue_len=%d\n",
1069 __func__
, NG_NODE_NAME(unit
->node
), m
->m_pkthdr
.len
,
1070 NG_BT_MBUFQ_LEN(&unit
->cmdq
));
1072 NG_BT_MBUFQ_DROP(&unit
->cmdq
);
1078 /* Queue and send command */
1079 NG_BT_MBUFQ_ENQUEUE(&unit
->cmdq
, m
);
1082 if (!(unit
->state
& NG_HCI_UNIT_COMMAND_PENDING
))
1083 error
= ng_hci_send_command(unit
);
1085 NG_FREE_M(m
); /* NG_FREE_M() checks for m != NULL */
1088 } /* ng_hci_raw_rcvdata */