6 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
8 * Copyright (c) Maksim Yevmenkin <m_evmenkin@yahoo.com>
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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
32 * $Id: ng_hci_ulpi.c,v 1.7 2003/09/08 18:57:51 max Exp $
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/endian.h>
40 #include <sys/malloc.h>
42 #include <sys/queue.h>
43 #include <netgraph/ng_message.h>
44 #include <netgraph/netgraph.h>
45 #include <netgraph/bluetooth/include/ng_bluetooth.h>
46 #include <netgraph/bluetooth/include/ng_hci.h>
47 #include <netgraph/bluetooth/hci/ng_hci_var.h>
48 #include <netgraph/bluetooth/hci/ng_hci_cmds.h>
49 #include <netgraph/bluetooth/hci/ng_hci_evnt.h>
50 #include <netgraph/bluetooth/hci/ng_hci_ulpi.h>
51 #include <netgraph/bluetooth/hci/ng_hci_misc.h>
53 /******************************************************************************
54 ******************************************************************************
55 ** Upper Layer Protocol Interface module
56 ******************************************************************************
57 ******************************************************************************/
59 static int ng_hci_lp_acl_con_req (ng_hci_unit_p, item_p, hook_p);
60 static int ng_hci_lp_sco_con_req (ng_hci_unit_p, item_p, hook_p);
61 static int ng_hci_lp_le_con_req (ng_hci_unit_p, item_p, hook_p, int);
64 * Process LP_ConnectReq event from the upper layer protocol
68 ng_hci_lp_con_req(ng_hci_unit_p unit, item_p item, hook_p hook)
72 if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) {
74 "%s: %s - unit is not ready, state=%#x\n",
75 __func__, NG_NODE_NAME(unit->node), unit->state);
82 if (NGI_MSG(item)->header.arglen != sizeof(ng_hci_lp_con_req_ep)) {
84 "%s: %s - invalid LP_ConnectReq message size=%d\n",
85 __func__, NG_NODE_NAME(unit->node),
86 NGI_MSG(item)->header.arglen);
92 link_type = ((ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data))->link_type;
95 return (ng_hci_lp_acl_con_req(unit, item, hook));
97 if (hook != unit->sco ) {
99 "%s: %s - LP_ConnectReq for SCO connection came from wrong hook=%p\n",
100 __func__, NG_NODE_NAME(unit->node), hook);
107 return (ng_hci_lp_sco_con_req(unit, item, hook));
108 case NG_HCI_LINK_LE_PUBLIC:
109 case NG_HCI_LINK_LE_RANDOM:
110 return (ng_hci_lp_le_con_req(unit, item, hook, link_type));
112 panic("%s: link_type invalid.", __func__);
116 } /* ng_hci_lp_con_req */
119 * Request to create new ACL connection
123 ng_hci_lp_acl_con_req(ng_hci_unit_p unit, item_p item, hook_p hook)
126 ng_hci_cmd_pkt_t hdr;
127 ng_hci_create_con_cp cp;
128 } __attribute__ ((packed)) *req = NULL;
129 ng_hci_lp_con_req_ep *ep = NULL;
130 ng_hci_unit_con_p con = NULL;
131 ng_hci_neighbor_t *n = NULL;
132 struct mbuf *m = NULL;
135 ep = (ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data);
138 * Only one ACL connection can exist between each pair of units.
139 * So try to find ACL connection descriptor (in any state) that
140 * has requested remote BD_ADDR.
144 * 1) We do not have connection to the remote unit. This is simple.
145 * Just create new connection descriptor and send HCI command to
146 * create new connection.
148 * 2) We do have connection descriptor. We need to check connection
151 * 2.1) NG_HCI_CON_W4_LP_CON_RSP means that we are in the middle of
152 * accepting connection from the remote unit. This is a race
153 * condition. We will ignore this message.
155 * 2.2) NG_HCI_CON_W4_CONN_COMPLETE means that upper layer already
156 * requested connection or we just accepted it. In any case
157 * all we need to do here is set appropriate notification bit
160 * 2.3) NG_HCI_CON_OPEN means connection is open. Just reply back
161 * and let upper layer know that we have connection already.
164 con = ng_hci_con_by_bdaddr(unit, &ep->bdaddr, NG_HCI_LINK_ACL);
166 switch (con->state) {
167 case NG_HCI_CON_W4_LP_CON_RSP: /* XXX */
171 case NG_HCI_CON_W4_CONN_COMPLETE:
172 if (hook == unit->acl)
173 con->flags |= NG_HCI_CON_NOTIFY_ACL;
175 con->flags |= NG_HCI_CON_NOTIFY_SCO;
178 case NG_HCI_CON_OPEN: {
179 struct ng_mesg *msg = NULL;
180 ng_hci_lp_con_cfm_ep *cfm = NULL;
182 if (hook != NULL && NG_HOOK_IS_VALID(hook)) {
183 NGI_GET_MSG(item, msg);
186 NG_MKMESSAGE(msg, NGM_HCI_COOKIE,
187 NGM_HCI_LP_CON_CFM, sizeof(*cfm),
190 cfm = (ng_hci_lp_con_cfm_ep *)msg->data;
192 cfm->link_type = con->link_type;
193 cfm->con_handle = con->con_handle;
194 bcopy(&con->bdaddr, &cfm->bdaddr,
195 sizeof(cfm->bdaddr));
198 * This will forward item back to
199 * sender and set item to NULL
202 _NGI_MSG(item) = msg;
203 NG_FWD_ITEM_HOOK(error, item, hook);
208 "%s: %s - Source hook is not valid, hook=%p\n",
209 __func__, NG_NODE_NAME(unit->node),
215 "%s: %s - Invalid connection state=%d\n",
216 __func__, NG_NODE_NAME(unit->node), con->state);
224 * If we got here then we need to create new ACL connection descriptor
225 * and submit HCI command. First create new connection desriptor, set
226 * bdaddr and notification flags.
229 con = ng_hci_new_con(unit, NG_HCI_LINK_ACL);
235 bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr));
241 MGETHDR(m, M_NOWAIT, MT_DATA);
243 ng_hci_free_con(con);
248 m->m_pkthdr.len = m->m_len = sizeof(*req);
249 req = mtod(m, struct acl_con_req *);
250 req->hdr.type = NG_HCI_CMD_PKT;
251 req->hdr.length = sizeof(req->cp);
252 req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
253 NG_HCI_OCF_CREATE_CON));
255 bcopy(&ep->bdaddr, &req->cp.bdaddr, sizeof(req->cp.bdaddr));
257 req->cp.pkt_type = (NG_HCI_PKT_DM1|NG_HCI_PKT_DH1);
258 if (unit->features[0] & NG_HCI_LMP_3SLOT)
259 req->cp.pkt_type |= (NG_HCI_PKT_DM3|NG_HCI_PKT_DH3);
260 if (unit->features[0] & NG_HCI_LMP_5SLOT)
261 req->cp.pkt_type |= (NG_HCI_PKT_DM5|NG_HCI_PKT_DH5);
263 req->cp.pkt_type &= unit->packet_mask;
264 if ((req->cp.pkt_type & (NG_HCI_PKT_DM1|NG_HCI_PKT_DH1|
265 NG_HCI_PKT_DM3|NG_HCI_PKT_DH3|
266 NG_HCI_PKT_DM5|NG_HCI_PKT_DH5)) == 0)
267 req->cp.pkt_type = (NG_HCI_PKT_DM1|NG_HCI_PKT_DH1);
269 req->cp.pkt_type = htole16(req->cp.pkt_type);
271 if ((unit->features[0] & NG_HCI_LMP_SWITCH) && unit->role_switch)
272 req->cp.accept_role_switch = 1;
274 req->cp.accept_role_switch = 0;
277 * We may speed up connect by specifying valid parameters.
278 * So check the neighbor cache.
281 n = ng_hci_get_neighbor(unit, &ep->bdaddr, NG_HCI_LINK_ACL);
283 req->cp.page_scan_rep_mode = 0;
284 req->cp.page_scan_mode = 0;
285 req->cp.clock_offset = 0;
287 req->cp.page_scan_rep_mode = n->page_scan_rep_mode;
288 req->cp.page_scan_mode = n->page_scan_mode;
289 req->cp.clock_offset = htole16(n->clock_offset);
293 * Adust connection state
296 if (hook == unit->acl)
297 con->flags |= NG_HCI_CON_NOTIFY_ACL;
299 con->flags |= NG_HCI_CON_NOTIFY_SCO;
301 con->state = NG_HCI_CON_W4_CONN_COMPLETE;
302 ng_hci_con_timeout(con);
305 * Queue and send HCI command
308 NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m);
309 if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING))
310 error = ng_hci_send_command(unit);
316 } /* ng_hci_lp_acl_con_req */
319 * Request to create new SCO connection
323 ng_hci_lp_sco_con_req(ng_hci_unit_p unit, item_p item, hook_p hook)
326 ng_hci_cmd_pkt_t hdr;
327 ng_hci_add_sco_con_cp cp;
328 } __attribute__ ((packed)) *req = NULL;
329 ng_hci_lp_con_req_ep *ep = NULL;
330 ng_hci_unit_con_p acl_con = NULL, sco_con = NULL;
331 struct mbuf *m = NULL;
334 ep = (ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data);
337 * SCO connection without ACL link
339 * If upper layer requests SCO connection and there is no open ACL
340 * connection to the desired remote unit, we will reject the request.
343 LIST_FOREACH(acl_con, &unit->con_list, next)
344 if (acl_con->link_type == NG_HCI_LINK_ACL &&
345 acl_con->state == NG_HCI_CON_OPEN &&
346 bcmp(&acl_con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0)
349 if (acl_con == NULL) {
351 "%s: %s - No open ACL connection to bdaddr=%x:%x:%x:%x:%x:%x\n",
352 __func__, NG_NODE_NAME(unit->node),
353 ep->bdaddr.b[5], ep->bdaddr.b[4], ep->bdaddr.b[3],
354 ep->bdaddr.b[2], ep->bdaddr.b[1], ep->bdaddr.b[0]);
361 * Multiple SCO connections can exist between the same pair of units.
362 * We assume that multiple SCO connections have to be opened one after
365 * Try to find SCO connection descriptor that matches the following:
367 * 1) sco_con->link_type == NG_HCI_LINK_SCO
369 * 2) sco_con->state == NG_HCI_CON_W4_LP_CON_RSP ||
370 * sco_con->state == NG_HCI_CON_W4_CONN_COMPLETE
372 * 3) sco_con->bdaddr == ep->bdaddr
376 * 1) We do not have connection descriptor. This is simple. Just
377 * create new connection and submit Add_SCO_Connection command.
379 * 2) We do have connection descriptor. We need to check the state.
381 * 2.1) NG_HCI_CON_W4_LP_CON_RSP means we in the middle of accepting
382 * connection from the remote unit. This is a race condition and
383 * we will ignore the request.
385 * 2.2) NG_HCI_CON_W4_CONN_COMPLETE means upper layer already requested
386 * connection or we just accepted it.
389 LIST_FOREACH(sco_con, &unit->con_list, next)
390 if (sco_con->link_type == NG_HCI_LINK_SCO &&
391 (sco_con->state == NG_HCI_CON_W4_LP_CON_RSP ||
392 sco_con->state == NG_HCI_CON_W4_CONN_COMPLETE) &&
393 bcmp(&sco_con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0)
396 if (sco_con != NULL) {
397 switch (sco_con->state) {
398 case NG_HCI_CON_W4_LP_CON_RSP: /* XXX */
402 case NG_HCI_CON_W4_CONN_COMPLETE:
403 sco_con->flags |= NG_HCI_CON_NOTIFY_SCO;
408 "%s: %s - Invalid connection state=%d\n",
409 __func__, NG_NODE_NAME(unit->node),
418 * If we got here then we need to create new SCO connection descriptor
419 * and submit HCI command.
422 sco_con = ng_hci_new_con(unit, NG_HCI_LINK_SCO);
423 if (sco_con == NULL) {
428 bcopy(&ep->bdaddr, &sco_con->bdaddr, sizeof(sco_con->bdaddr));
434 MGETHDR(m, M_NOWAIT, MT_DATA);
436 ng_hci_free_con(sco_con);
441 m->m_pkthdr.len = m->m_len = sizeof(*req);
442 req = mtod(m, struct sco_con_req *);
443 req->hdr.type = NG_HCI_CMD_PKT;
444 req->hdr.length = sizeof(req->cp);
445 req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
446 NG_HCI_OCF_ADD_SCO_CON));
448 req->cp.con_handle = htole16(acl_con->con_handle);
450 req->cp.pkt_type = NG_HCI_PKT_HV1;
451 if (unit->features[1] & NG_HCI_LMP_HV2_PKT)
452 req->cp.pkt_type |= NG_HCI_PKT_HV2;
453 if (unit->features[1] & NG_HCI_LMP_HV3_PKT)
454 req->cp.pkt_type |= NG_HCI_PKT_HV3;
456 req->cp.pkt_type &= unit->packet_mask;
457 if ((req->cp.pkt_type & (NG_HCI_PKT_HV1|
459 NG_HCI_PKT_HV3)) == 0)
460 req->cp.pkt_type = NG_HCI_PKT_HV1;
462 req->cp.pkt_type = htole16(req->cp.pkt_type);
465 * Adust connection state
468 sco_con->flags |= NG_HCI_CON_NOTIFY_SCO;
470 sco_con->state = NG_HCI_CON_W4_CONN_COMPLETE;
471 ng_hci_con_timeout(sco_con);
474 * Queue and send HCI command
477 NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m);
478 if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING))
479 error = ng_hci_send_command(unit);
484 } /* ng_hci_lp_sco_con_req */
487 ng_hci_lp_le_con_req(ng_hci_unit_p unit, item_p item, hook_p hook, int link_type)
490 ng_hci_cmd_pkt_t hdr;
491 ng_hci_le_create_connection_cp cp;
492 } __attribute__ ((packed)) *req = NULL;
493 ng_hci_lp_con_req_ep *ep = NULL;
494 ng_hci_unit_con_p con = NULL;
495 struct mbuf *m = NULL;
498 ep = (ng_hci_lp_con_req_ep *)(NGI_MSG(item)->data);
499 if((link_type != NG_HCI_LINK_LE_PUBLIC)&&
500 (link_type != NG_HCI_LINK_LE_RANDOM)){
501 printf("%s: Link type %d Cannot be here \n", __func__,
505 * Only one ACL connection can exist between each pair of units.
506 * So try to find ACL connection descriptor (in any state) that
507 * has requested remote BD_ADDR.
511 * 1) We do not have connection to the remote unit. This is simple.
512 * Just create new connection descriptor and send HCI command to
513 * create new connection.
515 * 2) We do have connection descriptor. We need to check connection
518 * 2.1) NG_HCI_CON_W4_LP_CON_RSP means that we are in the middle of
519 * accepting connection from the remote unit. This is a race
520 * condition. We will ignore this message.
522 * 2.2) NG_HCI_CON_W4_CONN_COMPLETE means that upper layer already
523 * requested connection or we just accepted it. In any case
524 * all we need to do here is set appropriate notification bit
527 * 2.3) NG_HCI_CON_OPEN means connection is open. Just reply back
528 * and let upper layer know that we have connection already.
531 con = ng_hci_con_by_bdaddr(unit, &ep->bdaddr, link_type);
533 switch (con->state) {
534 case NG_HCI_CON_W4_LP_CON_RSP: /* XXX */
538 case NG_HCI_CON_W4_CONN_COMPLETE:
539 if (hook != unit->sco)
540 con->flags |= NG_HCI_CON_NOTIFY_ACL;
542 con->flags |= NG_HCI_CON_NOTIFY_SCO;
545 case NG_HCI_CON_OPEN: {
546 struct ng_mesg *msg = NULL;
547 ng_hci_lp_con_cfm_ep *cfm = NULL;
549 if (hook != NULL && NG_HOOK_IS_VALID(hook)) {
550 NGI_GET_MSG(item, msg);
553 NG_MKMESSAGE(msg, NGM_HCI_COOKIE,
554 NGM_HCI_LP_CON_CFM, sizeof(*cfm),
557 cfm = (ng_hci_lp_con_cfm_ep *)msg->data;
559 cfm->link_type = con->link_type;
560 cfm->con_handle = con->con_handle;
561 bcopy(&con->bdaddr, &cfm->bdaddr,
562 sizeof(cfm->bdaddr));
565 * This will forward item back to
566 * sender and set item to NULL
569 _NGI_MSG(item) = msg;
570 NG_FWD_ITEM_HOOK(error, item, hook);
575 "%s: %s - Source hook is not valid, hook=%p\n",
576 __func__, NG_NODE_NAME(unit->node),
582 "%s: %s - Invalid connection state=%d\n",
583 __func__, NG_NODE_NAME(unit->node), con->state);
591 * If we got here then we need to create new ACL connection descriptor
592 * and submit HCI command. First create new connection desriptor, set
593 * bdaddr and notification flags.
596 con = ng_hci_new_con(unit, link_type);
602 bcopy(&ep->bdaddr, &con->bdaddr, sizeof(con->bdaddr));
608 MGETHDR(m, M_NOWAIT, MT_DATA);
610 ng_hci_free_con(con);
615 m->m_pkthdr.len = m->m_len = sizeof(*req);
616 req = mtod(m, struct acl_con_req *);
617 req->hdr.type = NG_HCI_CMD_PKT;
618 req->hdr.length = sizeof(req->cp);
619 req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LE,
620 NG_HCI_OCF_LE_CREATE_CONNECTION));
622 bcopy(&ep->bdaddr, &req->cp.peer_addr, sizeof(req->cp.peer_addr));
623 req->cp.own_address_type = 0;
624 req->cp.peer_addr_type = (link_type == NG_HCI_LINK_LE_RANDOM)? 1:0;
625 req->cp.scan_interval = htole16(4);
626 req->cp.scan_window = htole16(4);
627 req->cp.filter_policy = 0;
628 req->cp.conn_interval_min = htole16(0xf);
629 req->cp.conn_interval_max = htole16(0xf);
630 req->cp.conn_latency = htole16(0);
631 req->cp.supervision_timeout = htole16(0xc80);
632 req->cp.min_ce_length = htole16(1);
633 req->cp.max_ce_length = htole16(1);
635 * Adust connection state
638 if (hook != unit->sco)
639 con->flags |= NG_HCI_CON_NOTIFY_ACL;
641 con->flags |= NG_HCI_CON_NOTIFY_SCO;
643 con->state = NG_HCI_CON_W4_CONN_COMPLETE;
644 ng_hci_con_timeout(con);
647 * Queue and send HCI command
650 NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m);
651 if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING))
652 error = ng_hci_send_command(unit);
658 } /* ng_hci_lp_acl_con_req */
661 * Process LP_DisconnectReq event from the upper layer protocol
665 ng_hci_lp_discon_req(ng_hci_unit_p unit, item_p item, hook_p hook)
668 ng_hci_cmd_pkt_t hdr;
670 } __attribute__ ((packed)) *req = NULL;
671 ng_hci_lp_discon_req_ep *ep = NULL;
672 ng_hci_unit_con_p con = NULL;
673 struct mbuf *m = NULL;
676 /* Check if unit is ready */
677 if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) {
679 "%s: %s - unit is not ready, state=%#x\n",
680 __func__, NG_NODE_NAME(unit->node), unit->state);
686 if (NGI_MSG(item)->header.arglen != sizeof(*ep)) {
688 "%s: %s - invalid LP_DisconnectReq message size=%d\n",
689 __func__, NG_NODE_NAME(unit->node),
690 NGI_MSG(item)->header.arglen);
696 ep = (ng_hci_lp_discon_req_ep *)(NGI_MSG(item)->data);
698 con = ng_hci_con_by_handle(unit, ep->con_handle);
701 "%s: %s - invalid connection handle=%d\n",
702 __func__, NG_NODE_NAME(unit->node), ep->con_handle);
708 if (con->state != NG_HCI_CON_OPEN) {
710 "%s: %s - invalid connection state=%d, handle=%d\n",
711 __func__, NG_NODE_NAME(unit->node), con->state,
722 MGETHDR(m, M_NOWAIT, MT_DATA);
728 m->m_pkthdr.len = m->m_len = sizeof(*req);
729 req = mtod(m, struct discon_req *);
730 req->hdr.type = NG_HCI_CMD_PKT;
731 req->hdr.length = sizeof(req->cp);
732 req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_CONTROL,
735 req->cp.con_handle = htole16(ep->con_handle);
736 req->cp.reason = ep->reason;
739 * Queue and send HCI command
742 NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m);
743 if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING))
744 error = ng_hci_send_command(unit);
749 } /* ng_hci_lp_discon_req */
752 * Send LP_ConnectCfm event to the upper layer protocol
756 ng_hci_lp_con_cfm(ng_hci_unit_con_p con, int status)
758 ng_hci_unit_p unit = con->unit;
759 struct ng_mesg *msg = NULL;
760 ng_hci_lp_con_cfm_ep *ep = NULL;
764 * Check who wants to be notified. For ACL links both ACL and SCO
765 * upstream hooks will be notified (if required). For SCO links
766 * only SCO upstream hook will receive notification
769 if (con->link_type != NG_HCI_LINK_SCO &&
770 con->flags & NG_HCI_CON_NOTIFY_ACL) {
771 if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) {
772 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_CFM,
773 sizeof(*ep), M_NOWAIT);
775 ep = (ng_hci_lp_con_cfm_ep *) msg->data;
777 ep->link_type = con->link_type;
778 ep->con_handle = con->con_handle;
779 bcopy(&con->bdaddr, &ep->bdaddr,
782 NG_SEND_MSG_HOOK(error, unit->node, msg,
787 "%s: %s - ACL hook not valid, hook=%p\n",
788 __func__, NG_NODE_NAME(unit->node), unit->acl);
790 con->flags &= ~NG_HCI_CON_NOTIFY_ACL;
793 if (con->flags & NG_HCI_CON_NOTIFY_SCO) {
794 if (unit->sco != NULL && NG_HOOK_IS_VALID(unit->sco)) {
795 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_CFM,
796 sizeof(*ep), M_NOWAIT);
798 ep = (ng_hci_lp_con_cfm_ep *) msg->data;
800 ep->link_type = con->link_type;
801 ep->con_handle = con->con_handle;
802 bcopy(&con->bdaddr, &ep->bdaddr,
805 NG_SEND_MSG_HOOK(error, unit->node, msg,
810 "%s: %s - SCO hook not valid, hook=%p\n",
811 __func__, NG_NODE_NAME(unit->node), unit->acl);
813 con->flags &= ~NG_HCI_CON_NOTIFY_SCO;
817 } /* ng_hci_lp_con_cfm */
820 ng_hci_lp_enc_change(ng_hci_unit_con_p con, int status)
822 ng_hci_unit_p unit = con->unit;
823 struct ng_mesg *msg = NULL;
824 ng_hci_lp_enc_change_ep *ep = NULL;
828 if (con->link_type != NG_HCI_LINK_SCO) {
829 if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) {
830 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_ENC_CHG,
831 sizeof(*ep), M_NOWAIT);
833 ep = (ng_hci_lp_enc_change_ep *) msg->data;
835 ep->link_type = con->link_type;
836 ep->con_handle = con->con_handle;
838 NG_SEND_MSG_HOOK(error, unit->node, msg,
843 "%s: %s - ACL hook not valid, hook=%p\n",
844 __func__, NG_NODE_NAME(unit->node), unit->acl);
848 } /* ng_hci_lp_con_cfm */
851 * Send LP_ConnectInd event to the upper layer protocol
855 ng_hci_lp_con_ind(ng_hci_unit_con_p con, u_int8_t *uclass)
857 ng_hci_unit_p unit = con->unit;
858 struct ng_mesg *msg = NULL;
859 ng_hci_lp_con_ind_ep *ep = NULL;
864 * Connection_Request event is generated for specific link type.
865 * Use link_type to select upstream hook.
868 if (con->link_type != NG_HCI_LINK_SCO)
873 if (hook != NULL && NG_HOOK_IS_VALID(hook)) {
874 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_IND,
875 sizeof(*ep), M_NOWAIT);
879 ep = (ng_hci_lp_con_ind_ep *)(msg->data);
880 ep->link_type = con->link_type;
881 bcopy(uclass, ep->uclass, sizeof(ep->uclass));
882 bcopy(&con->bdaddr, &ep->bdaddr, sizeof(ep->bdaddr));
884 NG_SEND_MSG_HOOK(error, unit->node, msg, hook, 0);
887 "%s: %s - Upstream hook is not connected or not valid, hook=%p\n",
888 __func__, NG_NODE_NAME(unit->node), hook);
894 } /* ng_hci_lp_con_ind */
897 * Process LP_ConnectRsp event from the upper layer protocol
901 ng_hci_lp_con_rsp(ng_hci_unit_p unit, item_p item, hook_p hook)
904 ng_hci_cmd_pkt_t hdr;
906 ng_hci_accept_con_cp acc;
907 ng_hci_reject_con_cp rej;
908 } __attribute__ ((packed)) cp;
909 } __attribute__ ((packed)) *req = NULL;
910 ng_hci_lp_con_rsp_ep *ep = NULL;
911 ng_hci_unit_con_p con = NULL;
912 struct mbuf *m = NULL;
915 /* Check if unit is ready */
916 if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) {
918 "%s: %s - unit is not ready, state=%#x\n",
919 __func__, NG_NODE_NAME(unit->node), unit->state);
925 if (NGI_MSG(item)->header.arglen != sizeof(*ep)) {
927 "%s: %s - invalid LP_ConnectRsp message size=%d\n",
928 __func__, NG_NODE_NAME(unit->node),
929 NGI_MSG(item)->header.arglen);
935 ep = (ng_hci_lp_con_rsp_ep *)(NGI_MSG(item)->data);
938 * Here we have to deal with race. Upper layers might send conflicting
939 * requests. One might send Accept and other Reject. We will not try
940 * to solve all the problems, so first request will always win.
942 * Try to find connection that matches the following:
944 * 1) con->link_type == ep->link_type
946 * 2) con->state == NG_HCI_CON_W4_LP_CON_RSP ||
947 * con->state == NG_HCI_CON_W4_CONN_COMPLETE
949 * 3) con->bdaddr == ep->bdaddr
953 * 1) We do not have connection descriptor. Could be bogus request or
954 * we have rejected connection already.
956 * 2) We do have connection descriptor. Then we need to check state:
958 * 2.1) NG_HCI_CON_W4_LP_CON_RSP means upper layer has requested
959 * connection and it is a first response from the upper layer.
960 * if "status == 0" (Accept) then we will send Accept_Connection
961 * command and change connection state to W4_CONN_COMPLETE, else
962 * send reject and delete connection.
964 * 2.2) NG_HCI_CON_W4_CONN_COMPLETE means that we already accepted
965 * connection. If "status == 0" we just need to link request
966 * and wait, else ignore Reject request.
969 LIST_FOREACH(con, &unit->con_list, next)
970 if (con->link_type == ep->link_type &&
971 (con->state == NG_HCI_CON_W4_LP_CON_RSP ||
972 con->state == NG_HCI_CON_W4_CONN_COMPLETE) &&
973 bcmp(&con->bdaddr, &ep->bdaddr, sizeof(bdaddr_t)) == 0)
977 /* Reject for non-existing connection is fine */
978 error = (ep->status == 0)? ENOENT : 0;
983 * Remove connection timeout and check connection state.
984 * Note: if ng_hci_con_untimeout() fails (returns non-zero value) then
985 * timeout already happened and event went into node's queue.
988 if ((error = ng_hci_con_untimeout(con)) != 0)
991 switch (con->state) {
992 case NG_HCI_CON_W4_LP_CON_RSP:
998 MGETHDR(m, M_NOWAIT, MT_DATA);
1004 req = mtod(m, struct con_rsp_req *);
1005 req->hdr.type = NG_HCI_CMD_PKT;
1007 if (ep->status == 0) {
1008 req->hdr.length = sizeof(req->cp.acc);
1009 req->hdr.opcode = htole16(NG_HCI_OPCODE(
1010 NG_HCI_OGF_LINK_CONTROL,
1011 NG_HCI_OCF_ACCEPT_CON));
1013 bcopy(&ep->bdaddr, &req->cp.acc.bdaddr,
1014 sizeof(req->cp.acc.bdaddr));
1017 * We are accepting connection, so if we support role
1018 * switch and role switch was enabled then set role to
1019 * NG_HCI_ROLE_MASTER and let LM peform role switch.
1020 * Otherwise we remain slave. In this case LM WILL NOT
1021 * perform role switch.
1024 if ((unit->features[0] & NG_HCI_LMP_SWITCH) &&
1026 req->cp.acc.role = NG_HCI_ROLE_MASTER;
1028 req->cp.acc.role = NG_HCI_ROLE_SLAVE;
1031 * Adjust connection state
1034 if (hook == unit->acl)
1035 con->flags |= NG_HCI_CON_NOTIFY_ACL;
1037 con->flags |= NG_HCI_CON_NOTIFY_SCO;
1039 con->state = NG_HCI_CON_W4_CONN_COMPLETE;
1040 ng_hci_con_timeout(con);
1042 req->hdr.length = sizeof(req->cp.rej);
1043 req->hdr.opcode = htole16(NG_HCI_OPCODE(
1044 NG_HCI_OGF_LINK_CONTROL,
1045 NG_HCI_OCF_REJECT_CON));
1047 bcopy(&ep->bdaddr, &req->cp.rej.bdaddr,
1048 sizeof(req->cp.rej.bdaddr));
1050 req->cp.rej.reason = ep->status;
1053 * Free connection descritor
1054 * Item will be deleted just before return.
1057 ng_hci_free_con(con);
1060 m->m_pkthdr.len = m->m_len = sizeof(req->hdr) + req->hdr.length;
1062 /* Queue and send HCI command */
1063 NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m);
1064 if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING))
1065 error = ng_hci_send_command(unit);
1068 case NG_HCI_CON_W4_CONN_COMPLETE:
1069 if (ep->status == 0) {
1070 if (hook == unit->acl)
1071 con->flags |= NG_HCI_CON_NOTIFY_ACL;
1073 con->flags |= NG_HCI_CON_NOTIFY_SCO;
1080 "%s: %s - Invalid connection state=%d\n",
1081 __func__, NG_NODE_NAME(unit->node), con->state);
1088 } /* ng_hci_lp_con_rsp */
1091 * Send LP_DisconnectInd to the upper layer protocol
1095 ng_hci_lp_discon_ind(ng_hci_unit_con_p con, int reason)
1097 ng_hci_unit_p unit = con->unit;
1098 struct ng_mesg *msg = NULL;
1099 ng_hci_lp_discon_ind_ep *ep = NULL;
1103 * Disconnect_Complete event is generated for specific connection
1104 * handle. For ACL connection handles both ACL and SCO upstream
1105 * hooks will receive notification. For SCO connection handles
1106 * only SCO upstream hook will receive notification.
1109 if (con->link_type != NG_HCI_LINK_SCO) {
1110 if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) {
1111 NG_MKMESSAGE(msg, NGM_HCI_COOKIE,
1112 NGM_HCI_LP_DISCON_IND, sizeof(*ep), M_NOWAIT);
1116 ep = (ng_hci_lp_discon_ind_ep *) msg->data;
1117 ep->reason = reason;
1118 ep->link_type = con->link_type;
1119 ep->con_handle = con->con_handle;
1121 NG_SEND_MSG_HOOK(error,unit->node,msg,unit->acl,0);
1124 "%s: %s - ACL hook is not connected or not valid, hook=%p\n",
1125 __func__, NG_NODE_NAME(unit->node), unit->acl);
1128 if (unit->sco != NULL && NG_HOOK_IS_VALID(unit->sco)) {
1129 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_DISCON_IND,
1130 sizeof(*ep), M_NOWAIT);
1134 ep = (ng_hci_lp_discon_ind_ep *) msg->data;
1135 ep->reason = reason;
1136 ep->link_type = con->link_type;
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_discon_ind */
1149 * Process LP_QoSReq action from the upper layer protocol
1153 ng_hci_lp_qos_req(ng_hci_unit_p unit, item_p item, hook_p hook)
1155 struct qos_setup_req {
1156 ng_hci_cmd_pkt_t hdr;
1157 ng_hci_qos_setup_cp cp;
1158 } __attribute__ ((packed)) *req = NULL;
1159 ng_hci_lp_qos_req_ep *ep = NULL;
1160 ng_hci_unit_con_p con = NULL;
1161 struct mbuf *m = NULL;
1164 /* Check if unit is ready */
1165 if ((unit->state & NG_HCI_UNIT_READY) != NG_HCI_UNIT_READY) {
1167 "%s: %s - unit is not ready, state=%#x\n",
1168 __func__, NG_NODE_NAME(unit->node), unit->state);
1174 if (NGI_MSG(item)->header.arglen != sizeof(*ep)) {
1176 "%s: %s - invalid LP_QoSSetupReq message size=%d\n",
1177 __func__, NG_NODE_NAME(unit->node),
1178 NGI_MSG(item)->header.arglen);
1184 ep = (ng_hci_lp_qos_req_ep *)(NGI_MSG(item)->data);
1186 con = ng_hci_con_by_handle(unit, ep->con_handle);
1189 "%s: %s - invalid connection handle=%d\n",
1190 __func__, NG_NODE_NAME(unit->node), ep->con_handle);
1196 if (con->link_type != NG_HCI_LINK_ACL) {
1197 NG_HCI_ERR("%s: %s - invalid link type=%d\n",
1198 __func__, NG_NODE_NAME(unit->node), con->link_type);
1204 if (con->state != NG_HCI_CON_OPEN) {
1206 "%s: %s - invalid connection state=%d, handle=%d\n",
1207 __func__, NG_NODE_NAME(unit->node), con->state,
1215 * Create HCI command
1218 MGETHDR(m, M_NOWAIT, MT_DATA);
1224 m->m_pkthdr.len = m->m_len = sizeof(*req);
1225 req = mtod(m, struct qos_setup_req *);
1226 req->hdr.type = NG_HCI_CMD_PKT;
1227 req->hdr.length = sizeof(req->cp);
1228 req->hdr.opcode = htole16(NG_HCI_OPCODE(NG_HCI_OGF_LINK_POLICY,
1229 NG_HCI_OCF_QOS_SETUP));
1231 req->cp.con_handle = htole16(ep->con_handle);
1232 req->cp.flags = ep->flags;
1233 req->cp.service_type = ep->service_type;
1234 req->cp.token_rate = htole32(ep->token_rate);
1235 req->cp.peak_bandwidth = htole32(ep->peak_bandwidth);
1236 req->cp.latency = htole32(ep->latency);
1237 req->cp.delay_variation = htole32(ep->delay_variation);
1240 * Adjust connection state
1243 if (hook == unit->acl)
1244 con->flags |= NG_HCI_CON_NOTIFY_ACL;
1246 con->flags |= NG_HCI_CON_NOTIFY_SCO;
1249 * Queue and send HCI command
1252 NG_BT_MBUFQ_ENQUEUE(&unit->cmdq, m);
1253 if (!(unit->state & NG_HCI_UNIT_COMMAND_PENDING))
1254 error = ng_hci_send_command(unit);
1259 } /* ng_hci_lp_qos_req */
1262 * Send LP_QoSCfm event to the upper layer protocol
1266 ng_hci_lp_qos_cfm(ng_hci_unit_con_p con, int status)
1268 ng_hci_unit_p unit = con->unit;
1269 struct ng_mesg *msg = NULL;
1270 ng_hci_lp_qos_cfm_ep *ep = NULL;
1273 if (con->flags & NG_HCI_CON_NOTIFY_ACL) {
1274 if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) {
1275 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_CFM,
1276 sizeof(*ep), M_NOWAIT);
1278 ep = (ng_hci_lp_qos_cfm_ep *) msg->data;
1279 ep->status = status;
1280 ep->con_handle = con->con_handle;
1282 NG_SEND_MSG_HOOK(error, unit->node, msg,
1287 "%s: %s - ACL hook not valid, hook=%p\n",
1288 __func__, NG_NODE_NAME(unit->node), unit->acl);
1290 con->flags &= ~NG_HCI_CON_NOTIFY_ACL;
1293 if (con->flags & NG_HCI_CON_NOTIFY_SCO) {
1294 if (unit->sco != NULL && NG_HOOK_IS_VALID(unit->sco)) {
1295 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_CFM,
1296 sizeof(*ep), M_NOWAIT);
1298 ep = (ng_hci_lp_qos_cfm_ep *) msg->data;
1299 ep->status = status;
1300 ep->con_handle = con->con_handle;
1302 NG_SEND_MSG_HOOK(error, unit->node, msg,
1307 "%s: %s - SCO hook not valid, hook=%p\n",
1308 __func__, NG_NODE_NAME(unit->node), unit->sco);
1310 con->flags &= ~NG_HCI_CON_NOTIFY_SCO;
1314 } /* ng_hci_lp_qos_cfm */
1317 * Send LP_QoSViolationInd event to the upper layer protocol
1321 ng_hci_lp_qos_ind(ng_hci_unit_con_p con)
1323 ng_hci_unit_p unit = con->unit;
1324 struct ng_mesg *msg = NULL;
1325 ng_hci_lp_qos_ind_ep *ep = NULL;
1329 * QoS Violation can only be generated for ACL connection handles.
1330 * Both ACL and SCO upstream hooks will receive notification.
1333 if (unit->acl != NULL && NG_HOOK_IS_VALID(unit->acl)) {
1334 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_IND,
1335 sizeof(*ep), M_NOWAIT);
1339 ep = (ng_hci_lp_qos_ind_ep *) msg->data;
1340 ep->con_handle = con->con_handle;
1342 NG_SEND_MSG_HOOK(error, unit->node, msg, unit->acl, 0);
1345 "%s: %s - ACL hook is not connected or not valid, hook=%p\n",
1346 __func__, NG_NODE_NAME(unit->node), unit->acl);
1348 if (unit->sco != NULL && NG_HOOK_IS_VALID(unit->sco)) {
1349 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_IND,
1350 sizeof(*ep), M_NOWAIT);
1354 ep = (ng_hci_lp_qos_ind_ep *) msg->data;
1355 ep->con_handle = con->con_handle;
1357 NG_SEND_MSG_HOOK(error, unit->node, msg, unit->sco, 0);
1360 "%s: %s - SCO hook is not connected or not valid, hook=%p\n",
1361 __func__, NG_NODE_NAME(unit->node), unit->sco);
1364 } /* ng_hci_lp_qos_ind */
1367 * Process connection timeout
1371 ng_hci_process_con_timeout(node_p node, hook_p hook, void *arg1, int con_handle)
1373 ng_hci_unit_p unit = NULL;
1374 ng_hci_unit_con_p con = NULL;
1376 if (NG_NODE_NOT_VALID(node)) {
1377 printf("%s: Netgraph node is not valid\n", __func__);
1381 unit = (ng_hci_unit_p) NG_NODE_PRIVATE(node);
1382 con = ng_hci_con_by_handle(unit, con_handle);
1386 "%s: %s - could not find connection, handle=%d\n",
1387 __func__, NG_NODE_NAME(node), con_handle);
1391 if (!(con->flags & NG_HCI_CON_TIMEOUT_PENDING)) {
1393 "%s: %s - no pending connection timeout, handle=%d, state=%d, flags=%#x\n",
1394 __func__, NG_NODE_NAME(node), con_handle, con->state,
1399 con->flags &= ~NG_HCI_CON_TIMEOUT_PENDING;
1402 * We expect to receive connection timeout in one of the following
1405 * 1) NG_HCI_CON_W4_LP_CON_RSP means that upper layer has not responded
1406 * to our LP_CON_IND. Do nothing and destroy connection. Remote peer
1407 * most likely already gave up on us.
1409 * 2) NG_HCI_CON_W4_CONN_COMPLETE means upper layer requested connection
1410 * (or we in the process of accepting it) and baseband has timedout
1411 * on us. Inform upper layers and send LP_CON_CFM.
1414 switch (con->state) {
1415 case NG_HCI_CON_W4_LP_CON_RSP:
1418 case NG_HCI_CON_W4_CONN_COMPLETE:
1419 ng_hci_lp_con_cfm(con, 0xee);
1424 "%s: %s - Invalid connection state=%d\n",
1425 __func__, NG_NODE_NAME(node), con->state);
1429 ng_hci_free_con(con);
1430 } /* ng_hci_process_con_timeout */