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_ulpi.c,v 1.7 2003/09/08 18:57:51 max Exp $
31 * $FreeBSD: src/sys/netgraph/bluetooth/hci/ng_hci_ulpi.c,v 1.8 2005/01/07 01:45:43 imp Exp $
32 * $DragonFly: src/sys/netgraph7/bluetooth/hci/ng_hci_ulpi.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"
44 #include "bluetooth/include/ng_bluetooth.h"
45 #include "bluetooth/include/ng_hci.h"
46 #include "bluetooth/hci/ng_hci_var.h"
47 #include "bluetooth/hci/ng_hci_cmds.h"
48 #include "bluetooth/hci/ng_hci_evnt.h"
49 #include "bluetooth/hci/ng_hci_ulpi.h"
50 #include "bluetooth/hci/ng_hci_misc.h"
52 /******************************************************************************
53 ******************************************************************************
54 ** Upper Layer Protocol Interface module
55 ******************************************************************************
56 ******************************************************************************/
58 static int ng_hci_lp_acl_con_req (ng_hci_unit_p
, item_p
, hook_p
);
59 static int ng_hci_lp_sco_con_req (ng_hci_unit_p
, item_p
, hook_p
);
62 * Process LP_ConnectReq event from the upper layer protocol
66 ng_hci_lp_con_req(ng_hci_unit_p unit
, item_p item
, hook_p hook
)
68 if ((unit
->state
& NG_HCI_UNIT_READY
) != NG_HCI_UNIT_READY
) {
70 "%s: %s - unit is not ready, state=%#x\n",
71 __func__
, NG_NODE_NAME(unit
->node
), unit
->state
);
78 if (NGI_MSG(item
)->header
.arglen
!= sizeof(ng_hci_lp_con_req_ep
)) {
80 "%s: %s - invalid LP_ConnectReq message size=%d\n",
81 __func__
, NG_NODE_NAME(unit
->node
),
82 NGI_MSG(item
)->header
.arglen
);
89 if (((ng_hci_lp_con_req_ep
*)(NGI_MSG(item
)->data
))->link_type
== NG_HCI_LINK_ACL
)
90 return (ng_hci_lp_acl_con_req(unit
, item
, hook
));
92 if (hook
!= unit
->sco
) {
94 "%s: %s - LP_ConnectReq for SCO connection came from wrong hook=%p\n",
95 __func__
, NG_NODE_NAME(unit
->node
), hook
);
102 return (ng_hci_lp_sco_con_req(unit
, item
, hook
));
103 } /* ng_hci_lp_con_req */
106 * Request to create new ACL connection
110 ng_hci_lp_acl_con_req(ng_hci_unit_p unit
, item_p item
, hook_p hook
)
113 ng_hci_cmd_pkt_t hdr
;
114 ng_hci_create_con_cp cp
;
115 } __attribute__ ((packed
)) *req
= NULL
;
116 ng_hci_lp_con_req_ep
*ep
= NULL
;
117 ng_hci_unit_con_p con
= NULL
;
118 ng_hci_neighbor_t
*n
= NULL
;
119 struct mbuf
*m
= NULL
;
122 ep
= (ng_hci_lp_con_req_ep
*)(NGI_MSG(item
)->data
);
125 * Only one ACL connection can exist between each pair of units.
126 * So try to find ACL connection descriptor (in any state) that
127 * has requested remote BD_ADDR.
131 * 1) We do not have connection to the remote unit. This is simple.
132 * Just create new connection descriptor and send HCI command to
133 * create new connection.
135 * 2) We do have connection descriptor. We need to check connection
138 * 2.1) NG_HCI_CON_W4_LP_CON_RSP means that we are in the middle of
139 * accepting connection from the remote unit. This is a race
140 * condition. We will ignore this message.
142 * 2.2) NG_HCI_CON_W4_CONN_COMPLETE means that upper layer already
143 * requested connection or we just accepted it. In any case
144 * all we need to do here is set appropriate notification bit
147 * 2.3) NG_HCI_CON_OPEN means connection is open. Just reply back
148 * and let upper layer know that we have connection already.
151 con
= ng_hci_con_by_bdaddr(unit
, &ep
->bdaddr
, NG_HCI_LINK_ACL
);
153 switch (con
->state
) {
154 case NG_HCI_CON_W4_LP_CON_RSP
: /* XXX */
158 case NG_HCI_CON_W4_CONN_COMPLETE
:
159 if (hook
== unit
->acl
)
160 con
->flags
|= NG_HCI_CON_NOTIFY_ACL
;
162 con
->flags
|= NG_HCI_CON_NOTIFY_SCO
;
165 case NG_HCI_CON_OPEN
: {
166 struct ng_mesg
*msg
= NULL
;
167 ng_hci_lp_con_cfm_ep
*cfm
= NULL
;
169 if (hook
!= NULL
&& NG_HOOK_IS_VALID(hook
)) {
170 NGI_GET_MSG(item
, msg
);
173 NG_MKMESSAGE(msg
, NGM_HCI_COOKIE
,
174 NGM_HCI_LP_CON_CFM
, sizeof(*cfm
),
175 M_WAITOK
| M_NULLOK
);
177 cfm
= (ng_hci_lp_con_cfm_ep
*)msg
->data
;
179 cfm
->link_type
= con
->link_type
;
180 cfm
->con_handle
= con
->con_handle
;
181 bcopy(&con
->bdaddr
, &cfm
->bdaddr
,
182 sizeof(cfm
->bdaddr
));
185 * This will forward item back to
186 * sender and set item to NULL
189 _NGI_MSG(item
) = msg
;
190 NG_FWD_ITEM_HOOK(error
, item
, hook
);
195 "%s: %s - Source hook is not valid, hook=%p\n",
196 __func__
, NG_NODE_NAME(unit
->node
),
202 "%s: %s - Invalid connection state=%d\n",
203 __func__
, NG_NODE_NAME(unit
->node
), con
->state
);
211 * If we got here then we need to create new ACL connection descriptor
212 * and submit HCI command. First create new connection desriptor, set
213 * bdaddr and notification flags.
216 con
= ng_hci_new_con(unit
, NG_HCI_LINK_ACL
);
222 bcopy(&ep
->bdaddr
, &con
->bdaddr
, sizeof(con
->bdaddr
));
228 MGETHDR(m
, MB_DONTWAIT
, MT_DATA
);
230 ng_hci_free_con(con
);
235 m
->m_pkthdr
.len
= m
->m_len
= sizeof(*req
);
236 req
= mtod(m
, struct acl_con_req
*);
237 req
->hdr
.type
= NG_HCI_CMD_PKT
;
238 req
->hdr
.length
= sizeof(req
->cp
);
239 req
->hdr
.opcode
= htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL
,
240 NG_HCI_OCF_CREATE_CON
));
242 bcopy(&ep
->bdaddr
, &req
->cp
.bdaddr
, sizeof(req
->cp
.bdaddr
));
244 req
->cp
.pkt_type
= (NG_HCI_PKT_DM1
|NG_HCI_PKT_DH1
);
245 if (unit
->features
[0] & NG_HCI_LMP_3SLOT
)
246 req
->cp
.pkt_type
|= (NG_HCI_PKT_DM3
|NG_HCI_PKT_DH3
);
247 if (unit
->features
[0] & NG_HCI_LMP_5SLOT
)
248 req
->cp
.pkt_type
|= (NG_HCI_PKT_DM5
|NG_HCI_PKT_DH5
);
250 req
->cp
.pkt_type
&= unit
->packet_mask
;
251 if ((req
->cp
.pkt_type
& (NG_HCI_PKT_DM1
|NG_HCI_PKT_DH1
|
252 NG_HCI_PKT_DM3
|NG_HCI_PKT_DH3
|
253 NG_HCI_PKT_DM5
|NG_HCI_PKT_DH5
)) == 0)
254 req
->cp
.pkt_type
= (NG_HCI_PKT_DM1
|NG_HCI_PKT_DH1
);
256 req
->cp
.pkt_type
= htole16(req
->cp
.pkt_type
);
258 if ((unit
->features
[0] & NG_HCI_LMP_SWITCH
) && unit
->role_switch
)
259 req
->cp
.accept_role_switch
= 1;
261 req
->cp
.accept_role_switch
= 0;
264 * We may speed up connect by specifying valid parameters.
265 * So check the neighbor cache.
268 n
= ng_hci_get_neighbor(unit
, &ep
->bdaddr
);
270 req
->cp
.page_scan_rep_mode
= 0;
271 req
->cp
.page_scan_mode
= 0;
272 req
->cp
.clock_offset
= 0;
274 req
->cp
.page_scan_rep_mode
= n
->page_scan_rep_mode
;
275 req
->cp
.page_scan_mode
= n
->page_scan_mode
;
276 req
->cp
.clock_offset
= htole16(n
->clock_offset
);
280 * Adust connection state
283 if (hook
== unit
->acl
)
284 con
->flags
|= NG_HCI_CON_NOTIFY_ACL
;
286 con
->flags
|= NG_HCI_CON_NOTIFY_SCO
;
288 con
->state
= NG_HCI_CON_W4_CONN_COMPLETE
;
289 ng_hci_con_timeout(con
);
292 * Queue and send HCI command
295 NG_BT_MBUFQ_ENQUEUE(&unit
->cmdq
, m
);
296 if (!(unit
->state
& NG_HCI_UNIT_COMMAND_PENDING
))
297 error
= ng_hci_send_command(unit
);
303 } /* ng_hci_lp_acl_con_req */
306 * Request to create new SCO connection
310 ng_hci_lp_sco_con_req(ng_hci_unit_p unit
, item_p item
, hook_p hook
)
313 ng_hci_cmd_pkt_t hdr
;
314 ng_hci_add_sco_con_cp cp
;
315 } __attribute__ ((packed
)) *req
= NULL
;
316 ng_hci_lp_con_req_ep
*ep
= NULL
;
317 ng_hci_unit_con_p acl_con
= NULL
, sco_con
= NULL
;
318 struct mbuf
*m
= NULL
;
321 ep
= (ng_hci_lp_con_req_ep
*)(NGI_MSG(item
)->data
);
324 * SCO connection without ACL link
326 * If upper layer requests SCO connection and there is no open ACL
327 * connection to the desired remote unit, we will reject the request.
330 LIST_FOREACH(acl_con
, &unit
->con_list
, next
)
331 if (acl_con
->link_type
== NG_HCI_LINK_ACL
&&
332 acl_con
->state
== NG_HCI_CON_OPEN
&&
333 bcmp(&acl_con
->bdaddr
, &ep
->bdaddr
, sizeof(bdaddr_t
)) == 0)
336 if (acl_con
== NULL
) {
338 "%s: %s - No open ACL connection to bdaddr=%x:%x:%x:%x:%x:%x\n",
339 __func__
, NG_NODE_NAME(unit
->node
),
340 ep
->bdaddr
.b
[5], ep
->bdaddr
.b
[4], ep
->bdaddr
.b
[3],
341 ep
->bdaddr
.b
[2], ep
->bdaddr
.b
[1], ep
->bdaddr
.b
[0]);
348 * Multiple SCO connections can exist between the same pair of units.
349 * We assume that multiple SCO connections have to be opened one after
352 * Try to find SCO connection descriptor that matches the following:
354 * 1) sco_con->link_type == NG_HCI_LINK_SCO
356 * 2) sco_con->state == NG_HCI_CON_W4_LP_CON_RSP ||
357 * sco_con->state == NG_HCI_CON_W4_CONN_COMPLETE
359 * 3) sco_con->bdaddr == ep->bdaddr
363 * 1) We do not have connection descriptor. This is simple. Just
364 * create new connection and submit Add_SCO_Connection command.
366 * 2) We do have connection descriptor. We need to check the state.
368 * 2.1) NG_HCI_CON_W4_LP_CON_RSP means we in the middle of accepting
369 * connection from the remote unit. This is a race condition and
370 * we will ignore the request.
372 * 2.2) NG_HCI_CON_W4_CONN_COMPLETE means upper layer already requested
373 * connection or we just accepted it.
376 LIST_FOREACH(sco_con
, &unit
->con_list
, next
)
377 if (sco_con
->link_type
== NG_HCI_LINK_SCO
&&
378 (sco_con
->state
== NG_HCI_CON_W4_LP_CON_RSP
||
379 sco_con
->state
== NG_HCI_CON_W4_CONN_COMPLETE
) &&
380 bcmp(&sco_con
->bdaddr
, &ep
->bdaddr
, sizeof(bdaddr_t
)) == 0)
383 if (sco_con
!= NULL
) {
384 switch (sco_con
->state
) {
385 case NG_HCI_CON_W4_LP_CON_RSP
: /* XXX */
389 case NG_HCI_CON_W4_CONN_COMPLETE
:
390 sco_con
->flags
|= NG_HCI_CON_NOTIFY_SCO
;
395 "%s: %s - Inavalid connection state=%d\n",
396 __func__
, NG_NODE_NAME(unit
->node
),
405 * If we got here then we need to create new SCO connection descriptor
406 * and submit HCI command.
409 sco_con
= ng_hci_new_con(unit
, NG_HCI_LINK_SCO
);
410 if (sco_con
== NULL
) {
415 bcopy(&ep
->bdaddr
, &sco_con
->bdaddr
, sizeof(sco_con
->bdaddr
));
421 MGETHDR(m
, MB_DONTWAIT
, MT_DATA
);
423 ng_hci_free_con(sco_con
);
428 m
->m_pkthdr
.len
= m
->m_len
= sizeof(*req
);
429 req
= mtod(m
, struct sco_con_req
*);
430 req
->hdr
.type
= NG_HCI_CMD_PKT
;
431 req
->hdr
.length
= sizeof(req
->cp
);
432 req
->hdr
.opcode
= htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL
,
433 NG_HCI_OCF_ADD_SCO_CON
));
435 req
->cp
.con_handle
= htole16(acl_con
->con_handle
);
437 req
->cp
.pkt_type
= NG_HCI_PKT_HV1
;
438 if (unit
->features
[1] & NG_HCI_LMP_HV2_PKT
)
439 req
->cp
.pkt_type
|= NG_HCI_PKT_HV2
;
440 if (unit
->features
[1] & NG_HCI_LMP_HV3_PKT
)
441 req
->cp
.pkt_type
|= NG_HCI_PKT_HV3
;
443 req
->cp
.pkt_type
&= unit
->packet_mask
;
444 if ((req
->cp
.pkt_type
& (NG_HCI_PKT_HV1
|
446 NG_HCI_PKT_HV3
)) == 0)
447 req
->cp
.pkt_type
= NG_HCI_PKT_HV1
;
449 req
->cp
.pkt_type
= htole16(req
->cp
.pkt_type
);
452 * Adust connection state
455 sco_con
->flags
|= NG_HCI_CON_NOTIFY_SCO
;
457 sco_con
->state
= NG_HCI_CON_W4_CONN_COMPLETE
;
458 ng_hci_con_timeout(sco_con
);
461 * Queue and send HCI command
464 NG_BT_MBUFQ_ENQUEUE(&unit
->cmdq
, m
);
465 if (!(unit
->state
& NG_HCI_UNIT_COMMAND_PENDING
))
466 error
= ng_hci_send_command(unit
);
471 } /* ng_hci_lp_sco_con_req */
474 * Process LP_DisconnectReq event from the upper layer protocol
478 ng_hci_lp_discon_req(ng_hci_unit_p unit
, item_p item
, hook_p hook
)
481 ng_hci_cmd_pkt_t hdr
;
483 } __attribute__ ((packed
)) *req
= NULL
;
484 ng_hci_lp_discon_req_ep
*ep
= NULL
;
485 ng_hci_unit_con_p con
= NULL
;
486 struct mbuf
*m
= NULL
;
489 /* Check if unit is ready */
490 if ((unit
->state
& NG_HCI_UNIT_READY
) != NG_HCI_UNIT_READY
) {
492 "%s: %s - unit is not ready, state=%#x\n",
493 __func__
, NG_NODE_NAME(unit
->node
), unit
->state
);
499 if (NGI_MSG(item
)->header
.arglen
!= sizeof(*ep
)) {
501 "%s: %s - invalid LP_DisconnectReq message size=%d\n",
502 __func__
, NG_NODE_NAME(unit
->node
),
503 NGI_MSG(item
)->header
.arglen
);
509 ep
= (ng_hci_lp_discon_req_ep
*)(NGI_MSG(item
)->data
);
511 con
= ng_hci_con_by_handle(unit
, ep
->con_handle
);
514 "%s: %s - invalid connection handle=%d\n",
515 __func__
, NG_NODE_NAME(unit
->node
), ep
->con_handle
);
521 if (con
->state
!= NG_HCI_CON_OPEN
) {
523 "%s: %s - invalid connection state=%d, handle=%d\n",
524 __func__
, NG_NODE_NAME(unit
->node
), con
->state
,
535 MGETHDR(m
, MB_DONTWAIT
, MT_DATA
);
541 m
->m_pkthdr
.len
= m
->m_len
= sizeof(*req
);
542 req
= mtod(m
, struct discon_req
*);
543 req
->hdr
.type
= NG_HCI_CMD_PKT
;
544 req
->hdr
.length
= sizeof(req
->cp
);
545 req
->hdr
.opcode
= htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL
,
548 req
->cp
.con_handle
= htole16(ep
->con_handle
);
549 req
->cp
.reason
= ep
->reason
;
552 * Queue and send HCI command
555 NG_BT_MBUFQ_ENQUEUE(&unit
->cmdq
, m
);
556 if (!(unit
->state
& NG_HCI_UNIT_COMMAND_PENDING
))
557 error
= ng_hci_send_command(unit
);
562 } /* ng_hci_lp_discon_req */
565 * Send LP_ConnectCfm event to the upper layer protocol
569 ng_hci_lp_con_cfm(ng_hci_unit_con_p con
, int status
)
571 ng_hci_unit_p unit
= con
->unit
;
572 struct ng_mesg
*msg
= NULL
;
573 ng_hci_lp_con_cfm_ep
*ep
= NULL
;
577 * Check who wants to be notified. For ACL links both ACL and SCO
578 * upstream hooks will be notified (if required). For SCO links
579 * only SCO upstream hook will receive notification
582 if (con
->link_type
== NG_HCI_LINK_ACL
&&
583 con
->flags
& NG_HCI_CON_NOTIFY_ACL
) {
584 if (unit
->acl
!= NULL
&& NG_HOOK_IS_VALID(unit
->acl
)) {
585 NG_MKMESSAGE(msg
, NGM_HCI_COOKIE
, NGM_HCI_LP_CON_CFM
,
586 sizeof(*ep
), M_WAITOK
| M_NULLOK
);
588 ep
= (ng_hci_lp_con_cfm_ep
*) msg
->data
;
590 ep
->link_type
= con
->link_type
;
591 ep
->con_handle
= con
->con_handle
;
592 bcopy(&con
->bdaddr
, &ep
->bdaddr
,
595 NG_SEND_MSG_HOOK(error
, unit
->node
, msg
,
600 "%s: %s - ACL hook not valid, hook=%p\n",
601 __func__
, NG_NODE_NAME(unit
->node
), unit
->acl
);
603 con
->flags
&= ~NG_HCI_CON_NOTIFY_ACL
;
606 if (con
->flags
& NG_HCI_CON_NOTIFY_SCO
) {
607 if (unit
->sco
!= NULL
&& NG_HOOK_IS_VALID(unit
->sco
)) {
608 NG_MKMESSAGE(msg
, NGM_HCI_COOKIE
, NGM_HCI_LP_CON_CFM
,
609 sizeof(*ep
), M_WAITOK
| M_NULLOK
);
611 ep
= (ng_hci_lp_con_cfm_ep
*) msg
->data
;
613 ep
->link_type
= con
->link_type
;
614 ep
->con_handle
= con
->con_handle
;
615 bcopy(&con
->bdaddr
, &ep
->bdaddr
,
618 NG_SEND_MSG_HOOK(error
, unit
->node
, msg
,
623 "%s: %s - SCO hook not valid, hook=%p\n",
624 __func__
, NG_NODE_NAME(unit
->node
), unit
->acl
);
626 con
->flags
&= ~NG_HCI_CON_NOTIFY_SCO
;
630 } /* ng_hci_lp_con_cfm */
633 * Send LP_ConnectInd event to the upper layer protocol
637 ng_hci_lp_con_ind(ng_hci_unit_con_p con
, u_int8_t
*uclass
)
639 ng_hci_unit_p unit
= con
->unit
;
640 struct ng_mesg
*msg
= NULL
;
641 ng_hci_lp_con_ind_ep
*ep
= NULL
;
646 * Connection_Request event is generated for specific link type.
647 * Use link_type to select upstream hook.
650 if (con
->link_type
== NG_HCI_LINK_ACL
)
655 if (hook
!= NULL
&& NG_HOOK_IS_VALID(hook
)) {
656 NG_MKMESSAGE(msg
, NGM_HCI_COOKIE
, NGM_HCI_LP_CON_IND
,
657 sizeof(*ep
), M_WAITOK
| M_NULLOK
);
661 ep
= (ng_hci_lp_con_ind_ep
*)(msg
->data
);
662 ep
->link_type
= con
->link_type
;
663 bcopy(uclass
, ep
->uclass
, sizeof(ep
->uclass
));
664 bcopy(&con
->bdaddr
, &ep
->bdaddr
, sizeof(ep
->bdaddr
));
666 NG_SEND_MSG_HOOK(error
, unit
->node
, msg
, hook
, 0);
669 "%s: %s - Upstream hook is not connected or not valid, hook=%p\n",
670 __func__
, NG_NODE_NAME(unit
->node
), hook
);
676 } /* ng_hci_lp_con_ind */
679 * Process LP_ConnectRsp event from the upper layer protocol
683 ng_hci_lp_con_rsp(ng_hci_unit_p unit
, item_p item
, hook_p hook
)
686 ng_hci_cmd_pkt_t hdr
;
688 ng_hci_accept_con_cp acc
;
689 ng_hci_reject_con_cp rej
;
690 } __attribute__ ((packed
)) cp
;
691 } __attribute__ ((packed
)) *req
= NULL
;
692 ng_hci_lp_con_rsp_ep
*ep
= NULL
;
693 ng_hci_unit_con_p con
= NULL
;
694 struct mbuf
*m
= NULL
;
697 /* Check if unit is ready */
698 if ((unit
->state
& NG_HCI_UNIT_READY
) != NG_HCI_UNIT_READY
) {
700 "%s: %s - unit is not ready, state=%#x\n",
701 __func__
, NG_NODE_NAME(unit
->node
), unit
->state
);
707 if (NGI_MSG(item
)->header
.arglen
!= sizeof(*ep
)) {
709 "%s: %s - invalid LP_ConnectRsp message size=%d\n",
710 __func__
, NG_NODE_NAME(unit
->node
),
711 NGI_MSG(item
)->header
.arglen
);
717 ep
= (ng_hci_lp_con_rsp_ep
*)(NGI_MSG(item
)->data
);
720 * Here we have to deal with race. Upper layers might send conflicting
721 * requests. One might send Accept and other Reject. We will not try
722 * to solve all the problems, so first request will always win.
724 * Try to find connection that matches the following:
726 * 1) con->link_type == ep->link_type
728 * 2) con->state == NG_HCI_CON_W4_LP_CON_RSP ||
729 * con->state == NG_HCI_CON_W4_CONN_COMPLETE
731 * 3) con->bdaddr == ep->bdaddr
735 * 1) We do not have connection descriptor. Could be bogus request or
736 * we have rejected connection already.
738 * 2) We do have connection descriptor. Then we need to check state:
740 * 2.1) NG_HCI_CON_W4_LP_CON_RSP means upper layer has requested
741 * connection and it is a first response from the upper layer.
742 * if "status == 0" (Accept) then we will send Accept_Connection
743 * command and change connection state to W4_CONN_COMPLETE, else
744 * send reject and delete connection.
746 * 2.2) NG_HCI_CON_W4_CONN_COMPLETE means that we already accepted
747 * connection. If "status == 0" we just need to link request
748 * and wait, else ignore Reject request.
751 LIST_FOREACH(con
, &unit
->con_list
, next
)
752 if (con
->link_type
== ep
->link_type
&&
753 (con
->state
== NG_HCI_CON_W4_LP_CON_RSP
||
754 con
->state
== NG_HCI_CON_W4_CONN_COMPLETE
) &&
755 bcmp(&con
->bdaddr
, &ep
->bdaddr
, sizeof(bdaddr_t
)) == 0)
759 /* Reject for non-existing connection is fine */
760 error
= (ep
->status
== 0)? ENOENT
: 0;
765 * Remove connection timeout and check connection state.
766 * Note: if ng_hci_con_untimeout() fails (returns non-zero value) then
767 * timeout already happened and event went into node's queue.
770 if ((error
= ng_hci_con_untimeout(con
)) != 0)
773 switch (con
->state
) {
774 case NG_HCI_CON_W4_LP_CON_RSP
:
780 MGETHDR(m
, MB_DONTWAIT
, MT_DATA
);
786 req
= mtod(m
, struct con_rsp_req
*);
787 req
->hdr
.type
= NG_HCI_CMD_PKT
;
789 if (ep
->status
== 0) {
790 req
->hdr
.length
= sizeof(req
->cp
.acc
);
791 req
->hdr
.opcode
= htole16(NG_HCI_OPCODE(
792 NG_HCI_OGF_LINK_CONTROL
,
793 NG_HCI_OCF_ACCEPT_CON
));
795 bcopy(&ep
->bdaddr
, &req
->cp
.acc
.bdaddr
,
796 sizeof(req
->cp
.acc
.bdaddr
));
799 * We are accepting connection, so if we support role
800 * switch and role switch was enabled then set role to
801 * NG_HCI_ROLE_MASTER and let LM peform role switch.
802 * Otherwise we remain slave. In this case LM WILL NOT
803 * perform role switch.
806 if ((unit
->features
[0] & NG_HCI_LMP_SWITCH
) &&
808 req
->cp
.acc
.role
= NG_HCI_ROLE_MASTER
;
810 req
->cp
.acc
.role
= NG_HCI_ROLE_SLAVE
;
813 * Adjust connection state
816 if (hook
== unit
->acl
)
817 con
->flags
|= NG_HCI_CON_NOTIFY_ACL
;
819 con
->flags
|= NG_HCI_CON_NOTIFY_SCO
;
821 con
->state
= NG_HCI_CON_W4_CONN_COMPLETE
;
822 ng_hci_con_timeout(con
);
824 req
->hdr
.length
= sizeof(req
->cp
.rej
);
825 req
->hdr
.opcode
= htole16(NG_HCI_OPCODE(
826 NG_HCI_OGF_LINK_CONTROL
,
827 NG_HCI_OCF_REJECT_CON
));
829 bcopy(&ep
->bdaddr
, &req
->cp
.rej
.bdaddr
,
830 sizeof(req
->cp
.rej
.bdaddr
));
832 req
->cp
.rej
.reason
= ep
->status
;
835 * Free connection descritor
836 * Item will be deleted just before return.
839 ng_hci_free_con(con
);
842 m
->m_pkthdr
.len
= m
->m_len
= sizeof(req
->hdr
) + req
->hdr
.length
;
844 /* Queue and send HCI command */
845 NG_BT_MBUFQ_ENQUEUE(&unit
->cmdq
, m
);
846 if (!(unit
->state
& NG_HCI_UNIT_COMMAND_PENDING
))
847 error
= ng_hci_send_command(unit
);
850 case NG_HCI_CON_W4_CONN_COMPLETE
:
851 if (ep
->status
== 0) {
852 if (hook
== unit
->acl
)
853 con
->flags
|= NG_HCI_CON_NOTIFY_ACL
;
855 con
->flags
|= NG_HCI_CON_NOTIFY_SCO
;
862 "%s: %s - Invalid connection state=%d\n",
863 __func__
, NG_NODE_NAME(unit
->node
), con
->state
);
870 } /* ng_hci_lp_con_rsp */
873 * Send LP_DisconnectInd to the upper layer protocol
877 ng_hci_lp_discon_ind(ng_hci_unit_con_p con
, int reason
)
879 ng_hci_unit_p unit
= con
->unit
;
880 struct ng_mesg
*msg
= NULL
;
881 ng_hci_lp_discon_ind_ep
*ep
= NULL
;
885 * Disconnect_Complete event is generated for specific connection
886 * handle. For ACL connection handles both ACL and SCO upstream
887 * hooks will receive notification. For SCO connection handles
888 * only SCO upstream hook will receive notification.
891 if (con
->link_type
== NG_HCI_LINK_ACL
) {
892 if (unit
->acl
!= NULL
&& NG_HOOK_IS_VALID(unit
->acl
)) {
893 NG_MKMESSAGE(msg
, NGM_HCI_COOKIE
,
894 NGM_HCI_LP_DISCON_IND
, sizeof(*ep
), M_WAITOK
| M_NULLOK
);
898 ep
= (ng_hci_lp_discon_ind_ep
*) msg
->data
;
900 ep
->link_type
= con
->link_type
;
901 ep
->con_handle
= con
->con_handle
;
903 NG_SEND_MSG_HOOK(error
,unit
->node
,msg
,unit
->acl
,0);
906 "%s: %s - ACL hook is not connected or not valid, hook=%p\n",
907 __func__
, NG_NODE_NAME(unit
->node
), unit
->acl
);
910 if (unit
->sco
!= NULL
&& NG_HOOK_IS_VALID(unit
->sco
)) {
911 NG_MKMESSAGE(msg
, NGM_HCI_COOKIE
, NGM_HCI_LP_DISCON_IND
,
912 sizeof(*ep
), M_WAITOK
| M_NULLOK
);
916 ep
= (ng_hci_lp_discon_ind_ep
*) msg
->data
;
918 ep
->link_type
= con
->link_type
;
919 ep
->con_handle
= con
->con_handle
;
921 NG_SEND_MSG_HOOK(error
, unit
->node
, msg
, unit
->sco
, 0);
924 "%s: %s - SCO hook is not connected or not valid, hook=%p\n",
925 __func__
, NG_NODE_NAME(unit
->node
), unit
->sco
);
928 } /* ng_hci_lp_discon_ind */
931 * Process LP_QoSReq action from the upper layer protocol
935 ng_hci_lp_qos_req(ng_hci_unit_p unit
, item_p item
, hook_p hook
)
937 struct qos_setup_req
{
938 ng_hci_cmd_pkt_t hdr
;
939 ng_hci_qos_setup_cp cp
;
940 } __attribute__ ((packed
)) *req
= NULL
;
941 ng_hci_lp_qos_req_ep
*ep
= NULL
;
942 ng_hci_unit_con_p con
= NULL
;
943 struct mbuf
*m
= NULL
;
946 /* Check if unit is ready */
947 if ((unit
->state
& NG_HCI_UNIT_READY
) != NG_HCI_UNIT_READY
) {
949 "%s: %s - unit is not ready, state=%#x\n",
950 __func__
, NG_NODE_NAME(unit
->node
), unit
->state
);
956 if (NGI_MSG(item
)->header
.arglen
!= sizeof(*ep
)) {
958 "%s: %s - invalid LP_QoSSetupReq message size=%d\n",
959 __func__
, NG_NODE_NAME(unit
->node
),
960 NGI_MSG(item
)->header
.arglen
);
966 ep
= (ng_hci_lp_qos_req_ep
*)(NGI_MSG(item
)->data
);
968 con
= ng_hci_con_by_handle(unit
, ep
->con_handle
);
971 "%s: %s - invalid connection handle=%d\n",
972 __func__
, NG_NODE_NAME(unit
->node
), ep
->con_handle
);
978 if (con
->link_type
!= NG_HCI_LINK_ACL
) {
979 NG_HCI_ERR("%s: %s - invalid link type=%d\n",
980 __func__
, NG_NODE_NAME(unit
->node
), con
->link_type
);
986 if (con
->state
!= NG_HCI_CON_OPEN
) {
988 "%s: %s - invalid connection state=%d, handle=%d\n",
989 __func__
, NG_NODE_NAME(unit
->node
), con
->state
,
1000 MGETHDR(m
, MB_DONTWAIT
, MT_DATA
);
1006 m
->m_pkthdr
.len
= m
->m_len
= sizeof(*req
);
1007 req
= mtod(m
, struct qos_setup_req
*);
1008 req
->hdr
.type
= NG_HCI_CMD_PKT
;
1009 req
->hdr
.length
= sizeof(req
->cp
);
1010 req
->hdr
.opcode
= htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY
,
1011 NG_HCI_OCF_QOS_SETUP
));
1013 req
->cp
.con_handle
= htole16(ep
->con_handle
);
1014 req
->cp
.flags
= ep
->flags
;
1015 req
->cp
.service_type
= ep
->service_type
;
1016 req
->cp
.token_rate
= htole32(ep
->token_rate
);
1017 req
->cp
.peak_bandwidth
= htole32(ep
->peak_bandwidth
);
1018 req
->cp
.latency
= htole32(ep
->latency
);
1019 req
->cp
.delay_variation
= htole32(ep
->delay_variation
);
1022 * Adjust connection state
1025 if (hook
== unit
->acl
)
1026 con
->flags
|= NG_HCI_CON_NOTIFY_ACL
;
1028 con
->flags
|= NG_HCI_CON_NOTIFY_SCO
;
1031 * Queue and send HCI command
1034 NG_BT_MBUFQ_ENQUEUE(&unit
->cmdq
, m
);
1035 if (!(unit
->state
& NG_HCI_UNIT_COMMAND_PENDING
))
1036 error
= ng_hci_send_command(unit
);
1041 } /* ng_hci_lp_qos_req */
1044 * Send LP_QoSCfm event to the upper layer protocol
1048 ng_hci_lp_qos_cfm(ng_hci_unit_con_p con
, int status
)
1050 ng_hci_unit_p unit
= con
->unit
;
1051 struct ng_mesg
*msg
= NULL
;
1052 ng_hci_lp_qos_cfm_ep
*ep
= NULL
;
1055 if (con
->flags
& NG_HCI_CON_NOTIFY_ACL
) {
1056 if (unit
->acl
!= NULL
&& NG_HOOK_IS_VALID(unit
->acl
)) {
1057 NG_MKMESSAGE(msg
, NGM_HCI_COOKIE
, NGM_HCI_LP_QOS_CFM
,
1058 sizeof(*ep
), M_WAITOK
| M_NULLOK
);
1060 ep
= (ng_hci_lp_qos_cfm_ep
*) msg
->data
;
1061 ep
->status
= status
;
1062 ep
->con_handle
= con
->con_handle
;
1064 NG_SEND_MSG_HOOK(error
, unit
->node
, msg
,
1069 "%s: %s - ACL hook not valid, hook=%p\n",
1070 __func__
, NG_NODE_NAME(unit
->node
), unit
->acl
);
1072 con
->flags
&= ~NG_HCI_CON_NOTIFY_ACL
;
1075 if (con
->flags
& NG_HCI_CON_NOTIFY_SCO
) {
1076 if (unit
->sco
!= NULL
&& NG_HOOK_IS_VALID(unit
->sco
)) {
1077 NG_MKMESSAGE(msg
, NGM_HCI_COOKIE
, NGM_HCI_LP_QOS_CFM
,
1078 sizeof(*ep
), M_WAITOK
| M_NULLOK
);
1080 ep
= (ng_hci_lp_qos_cfm_ep
*) msg
->data
;
1081 ep
->status
= status
;
1082 ep
->con_handle
= con
->con_handle
;
1084 NG_SEND_MSG_HOOK(error
, unit
->node
, msg
,
1089 "%s: %s - SCO hook not valid, hook=%p\n",
1090 __func__
, NG_NODE_NAME(unit
->node
), unit
->sco
);
1092 con
->flags
&= ~NG_HCI_CON_NOTIFY_SCO
;
1096 } /* ng_hci_lp_qos_cfm */
1099 * Send LP_QoSViolationInd event to the upper layer protocol
1103 ng_hci_lp_qos_ind(ng_hci_unit_con_p con
)
1105 ng_hci_unit_p unit
= con
->unit
;
1106 struct ng_mesg
*msg
= NULL
;
1107 ng_hci_lp_qos_ind_ep
*ep
= NULL
;
1111 * QoS Violation can only be generated for ACL connection handles.
1112 * Both ACL and SCO upstream hooks will receive notification.
1115 if (unit
->acl
!= NULL
&& NG_HOOK_IS_VALID(unit
->acl
)) {
1116 NG_MKMESSAGE(msg
, NGM_HCI_COOKIE
, NGM_HCI_LP_QOS_IND
,
1117 sizeof(*ep
), M_WAITOK
| M_NULLOK
);
1121 ep
= (ng_hci_lp_qos_ind_ep
*) msg
->data
;
1122 ep
->con_handle
= con
->con_handle
;
1124 NG_SEND_MSG_HOOK(error
, unit
->node
, msg
, unit
->acl
, 0);
1127 "%s: %s - ACL hook is not connected or not valid, hook=%p\n",
1128 __func__
, NG_NODE_NAME(unit
->node
), unit
->acl
);
1130 if (unit
->sco
!= NULL
&& NG_HOOK_IS_VALID(unit
->sco
)) {
1131 NG_MKMESSAGE(msg
, NGM_HCI_COOKIE
, NGM_HCI_LP_QOS_IND
,
1132 sizeof(*ep
), M_WAITOK
| M_NULLOK
);
1136 ep
= (ng_hci_lp_qos_ind_ep
*) msg
->data
;
1137 ep
->con_handle
= con
->con_handle
;
1139 NG_SEND_MSG_HOOK(error
, unit
->node
, msg
, unit
->sco
, 0);
1142 "%s: %s - SCO hook is not connected or not valid, hook=%p\n",
1143 __func__
, NG_NODE_NAME(unit
->node
), unit
->sco
);
1146 } /* ng_hci_lp_qos_ind */
1149 * Process connection timeout
1153 ng_hci_process_con_timeout(node_p node
, hook_p hook
, void *arg1
, int con_handle
)
1155 ng_hci_unit_p unit
= NULL
;
1156 ng_hci_unit_con_p con
= NULL
;
1158 if (NG_NODE_NOT_VALID(node
)) {
1159 printf("%s: Netgraph node is not valid\n", __func__
);
1163 unit
= (ng_hci_unit_p
) NG_NODE_PRIVATE(node
);
1164 con
= ng_hci_con_by_handle(unit
, con_handle
);
1168 "%s: %s - could not find connection, handle=%d\n",
1169 __func__
, NG_NODE_NAME(node
), con_handle
);
1173 if (!(con
->flags
& NG_HCI_CON_TIMEOUT_PENDING
)) {
1175 "%s: %s - no pending connection timeout, handle=%d, state=%d, flags=%#x\n",
1176 __func__
, NG_NODE_NAME(node
), con_handle
, con
->state
,
1181 con
->flags
&= ~NG_HCI_CON_TIMEOUT_PENDING
;
1184 * We expect to receive connection timeout in one of the following
1187 * 1) NG_HCI_CON_W4_LP_CON_RSP means that upper layer has not responded
1188 * to our LP_CON_IND. Do nothing and destroy connection. Remote peer
1189 * most likely already gave up on us.
1191 * 2) NG_HCI_CON_W4_CONN_COMPLETE means upper layer requested connection
1192 * (or we in the process of accepting it) and baseband has timedout
1193 * on us. Inform upper layers and send LP_CON_CFM.
1196 switch (con
->state
) {
1197 case NG_HCI_CON_W4_LP_CON_RSP
:
1200 case NG_HCI_CON_W4_CONN_COMPLETE
:
1201 ng_hci_lp_con_cfm(con
, 0xee);
1206 "%s: %s - Invalid connection state=%d\n",
1207 __func__
, NG_NODE_NAME(node
), con
->state
);
1211 ng_hci_free_con(con
);
1212 } /* ng_hci_process_con_timeout */