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_l2cap_llpi.c,v 1.5 2003/09/08 19:11:45 max Exp $
31 * $FreeBSD: src/sys/netgraph/bluetooth/l2cap/ng_l2cap_llpi.c,v 1.9 2005/07/29 14:44:17 emax Exp $
32 * $DragonFly: src/sys/netgraph7/bluetooth/l2cap/ng_l2cap_llpi.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/include/ng_l2cap.h"
47 #include "bluetooth/l2cap/ng_l2cap_var.h"
48 #include "bluetooth/l2cap/ng_l2cap_cmds.h"
49 #include "bluetooth/l2cap/ng_l2cap_evnt.h"
50 #include "bluetooth/l2cap/ng_l2cap_llpi.h"
51 #include "bluetooth/l2cap/ng_l2cap_ulpi.h"
52 #include "bluetooth/l2cap/ng_l2cap_misc.h"
54 /******************************************************************************
55 ******************************************************************************
56 ** Lower Layer Protocol (HCI) Interface module
57 ******************************************************************************
58 ******************************************************************************/
61 * Send LP_ConnectReq event to the lower layer protocol. Create new connection
62 * descriptor and initialize it. Create LP_ConnectReq event and send it to the
63 * lower layer, then adjust connection state and start timer. The function WILL
64 * FAIL if connection to the remote unit already exists.
68 ng_l2cap_lp_con_req(ng_l2cap_p l2cap, bdaddr_p bdaddr)
70 struct ng_mesg *msg = NULL;
71 ng_hci_lp_con_req_ep *ep = NULL;
72 ng_l2cap_con_p con = NULL;
75 /* Verify that we DO NOT have connection to the remote unit */
76 con = ng_l2cap_con_by_addr(l2cap, bdaddr);
79 "%s: %s - unexpected LP_ConnectReq event. " \
80 "Connection already exists, state=%d, con_handle=%d\n",
81 __func__, NG_NODE_NAME(l2cap->node), con->state,
87 /* Check if lower layer protocol is still connected */
88 if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
90 "%s: %s - hook \"%s\" is not connected or valid\n",
91 __func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);
96 /* Create and intialize new connection descriptor */
97 con = ng_l2cap_new_con(l2cap, bdaddr);
101 /* Create and send LP_ConnectReq event */
102 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_REQ,
103 sizeof(*ep), M_WAITOK | M_NULLOK);
105 ng_l2cap_free_con(con);
110 ep = (ng_hci_lp_con_req_ep *) (msg->data);
111 bcopy(bdaddr, &ep->bdaddr, sizeof(ep->bdaddr));
112 ep->link_type = NG_HCI_LINK_ACL;
114 con->flags |= NG_L2CAP_CON_OUTGOING;
115 con->state = NG_L2CAP_W4_LP_CON_CFM;
116 ng_l2cap_lp_timeout(con);
118 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->hci, 0);
120 if ((error = ng_l2cap_lp_untimeout(con)) != 0)
123 ng_l2cap_free_con(con);
127 } /* ng_l2cap_lp_con_req */
130 * Process LP_ConnectCfm event from the lower layer protocol. It could be
131 * positive or negative. Verify remote unit address then stop the timer and
136 ng_l2cap_lp_con_cfm(ng_l2cap_p l2cap, struct ng_mesg *msg)
138 ng_hci_lp_con_cfm_ep *ep = NULL;
139 ng_l2cap_con_p con = NULL;
143 if (msg->header.arglen != sizeof(*ep)) {
145 "%s: %s - invalid LP_ConnectCfm[Neg] message size\n",
146 __func__, NG_NODE_NAME(l2cap->node));
151 ep = (ng_hci_lp_con_cfm_ep *) (msg->data);
153 /* Check if we have requested/accepted this connection */
154 con = ng_l2cap_con_by_addr(l2cap, &ep->bdaddr);
157 "%s: %s - unexpected LP_ConnectCfm event. Connection does not exist\n",
158 __func__, NG_NODE_NAME(l2cap->node));
163 /* Check connection state */
164 if (con->state != NG_L2CAP_W4_LP_CON_CFM) {
166 "%s: %s - unexpected LP_ConnectCfm event. " \
167 "Invalid connection state, state=%d, con_handle=%d\n",
168 __func__, NG_NODE_NAME(l2cap->node), con->state,
175 * Looks like it is our confirmation. It is safe now to cancel
176 * connection timer and notify upper layer. If timeout already
177 * happened then ignore connection confirmation and let timeout
181 if ((error = ng_l2cap_lp_untimeout(con)) != 0)
184 if (ep->status == 0) {
185 con->state = NG_L2CAP_CON_OPEN;
186 con->con_handle = ep->con_handle;
187 ng_l2cap_lp_deliver(con);
188 } else /* Negative confirmation - remove connection descriptor */
189 ng_l2cap_con_fail(con, ep->status);
192 } /* ng_l2cap_lp_con_cfm */
195 * Process LP_ConnectInd event from the lower layer protocol. This is a good
196 * place to put some extra check on remote unit address and/or class. We could
197 * even forward this information to control hook (or check against internal
198 * black list) and thus implement some kind of firewall. But for now be simple
199 * and create new connection descriptor, start timer and send LP_ConnectRsp
200 * event (i.e. accept connection).
204 ng_l2cap_lp_con_ind(ng_l2cap_p l2cap, struct ng_mesg *msg)
206 ng_hci_lp_con_ind_ep *ep = NULL;
207 ng_hci_lp_con_rsp_ep *rp = NULL;
208 struct ng_mesg *rsp = NULL;
209 ng_l2cap_con_p con = NULL;
213 if (msg->header.arglen != sizeof(*ep)) {
215 "%s: %s - invalid LP_ConnectInd message size\n",
216 __func__, NG_NODE_NAME(l2cap->node));
221 ep = (ng_hci_lp_con_ind_ep *) (msg->data);
223 /* Make sure we have only one connection to the remote unit */
224 con = ng_l2cap_con_by_addr(l2cap, &ep->bdaddr);
227 "%s: %s - unexpected LP_ConnectInd event. " \
228 "Connection already exists, state=%d, con_handle=%d\n",
229 __func__, NG_NODE_NAME(l2cap->node), con->state,
235 /* Check if lower layer protocol is still connected */
236 if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
238 "%s: %s - hook \"%s\" is not connected or valid",
239 __func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);
244 /* Create and intialize new connection descriptor */
245 con = ng_l2cap_new_con(l2cap, &ep->bdaddr);
251 /* Create and send LP_ConnectRsp event */
252 NG_MKMESSAGE(rsp, NGM_HCI_COOKIE, NGM_HCI_LP_CON_RSP,
253 sizeof(*rp), M_WAITOK | M_NULLOK);
255 ng_l2cap_free_con(con);
260 rp = (ng_hci_lp_con_rsp_ep *)(rsp->data);
261 rp->status = 0x00; /* accept connection */
262 rp->link_type = NG_HCI_LINK_ACL;
263 bcopy(&ep->bdaddr, &rp->bdaddr, sizeof(rp->bdaddr));
265 con->state = NG_L2CAP_W4_LP_CON_CFM;
266 ng_l2cap_lp_timeout(con);
268 NG_SEND_MSG_HOOK(error, l2cap->node, rsp, l2cap->hci, 0);
270 if ((error = ng_l2cap_lp_untimeout(con)) != 0)
273 ng_l2cap_free_con(con);
277 } /* ng_hci_lp_con_ind */
280 * Process LP_DisconnectInd event from the lower layer protocol. We have been
281 * disconnected from the remote unit. So notify the upper layer protocol.
285 ng_l2cap_lp_discon_ind(ng_l2cap_p l2cap, struct ng_mesg *msg)
287 ng_hci_lp_discon_ind_ep *ep = NULL;
288 ng_l2cap_con_p con = NULL;
292 if (msg->header.arglen != sizeof(*ep)) {
294 "%s: %s - invalid LP_DisconnectInd message size\n",
295 __func__, NG_NODE_NAME(l2cap->node));
300 ep = (ng_hci_lp_discon_ind_ep *) (msg->data);
302 /* Check if we have this connection */
303 con = ng_l2cap_con_by_handle(l2cap, ep->con_handle);
306 "%s: %s - unexpected LP_DisconnectInd event. " \
307 "Connection does not exist, con_handle=%d\n",
308 __func__, NG_NODE_NAME(l2cap->node), ep->con_handle);
313 /* XXX Verify connection state -- do we need to check this? */
314 if (con->state != NG_L2CAP_CON_OPEN) {
316 "%s: %s - unexpected LP_DisconnectInd event. " \
317 "Invalid connection state, state=%d, con_handle=%d\n",
318 __func__, NG_NODE_NAME(l2cap->node), con->state,
325 * Notify upper layer and remove connection
326 * Note: The connection could have auto disconnect timeout set. Try
327 * to remove it. If auto disconnect timeout happened then ignore
328 * disconnect indication and let timeout handle that.
331 if (con->flags & NG_L2CAP_CON_AUTO_DISCON_TIMO)
332 if ((error = ng_l2cap_discon_untimeout(con)) != 0)
335 ng_l2cap_con_fail(con, ep->reason);
338 } /* ng_l2cap_lp_discon_ind */
341 * Send LP_QoSSetupReq event to the lower layer protocol
345 ng_l2cap_lp_qos_req(ng_l2cap_p l2cap, u_int16_t con_handle,
346 ng_l2cap_flow_p flow)
348 struct ng_mesg *msg = NULL;
349 ng_hci_lp_qos_req_ep *ep = NULL;
350 ng_l2cap_con_p con = NULL;
353 /* Verify that we have this connection */
354 con = ng_l2cap_con_by_handle(l2cap, con_handle);
357 "%s: %s - unexpected LP_QoSSetupReq event. " \
358 "Connection does not exist, con_handle=%d\n",
359 __func__, NG_NODE_NAME(l2cap->node), con_handle);
364 /* Verify connection state */
365 if (con->state != NG_L2CAP_CON_OPEN) {
367 "%s: %s - unexpected LP_QoSSetupReq event. " \
368 "Invalid connection state, state=%d, con_handle=%d\n",
369 __func__, NG_NODE_NAME(l2cap->node), con->state,
375 /* Check if lower layer protocol is still connected */
376 if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
378 "%s: %s - hook \"%s\" is not connected or valid",
379 __func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);
384 /* Create and send LP_QoSSetupReq event */
385 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_REQ,
386 sizeof(*ep), M_WAITOK | M_NULLOK);
390 ep = (ng_hci_lp_qos_req_ep *) (msg->data);
391 ep->con_handle = con_handle;
392 ep->flags = flow->flags;
393 ep->service_type = flow->service_type;
394 ep->token_rate = flow->token_rate;
395 ep->peak_bandwidth = flow->peak_bandwidth;
396 ep->latency = flow->latency;
397 ep->delay_variation = flow->delay_variation;
399 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->hci, 0);
402 } /* ng_l2cap_lp_con_req */
405 * Process LP_QoSSetupCfm from the lower layer protocol
409 ng_l2cap_lp_qos_cfm(ng_l2cap_p l2cap, struct ng_mesg *msg)
411 ng_hci_lp_qos_cfm_ep *ep = NULL;
415 if (msg->header.arglen != sizeof(*ep)) {
417 "%s: %s - invalid LP_QoSSetupCfm[Neg] message size\n",
418 __func__, NG_NODE_NAME(l2cap->node));
423 ep = (ng_hci_lp_qos_cfm_ep *) (msg->data);
424 /* XXX FIXME do something */
427 } /* ng_l2cap_lp_qos_cfm */
430 * Process LP_QoSViolationInd event from the lower layer protocol. Lower
431 * layer protocol has detected QoS Violation, so we MUST notify the
436 ng_l2cap_lp_qos_ind(ng_l2cap_p l2cap, struct ng_mesg *msg)
438 ng_hci_lp_qos_ind_ep *ep = NULL;
439 ng_l2cap_con_p con = NULL;
443 if (msg->header.arglen != sizeof(*ep)) {
445 "%s: %s - invalid LP_QoSViolation message size\n",
446 __func__, NG_NODE_NAME(l2cap->node));
451 ep = (ng_hci_lp_qos_ind_ep *) (msg->data);
453 /* Check if we have this connection */
454 con = ng_l2cap_con_by_handle(l2cap, ep->con_handle);
457 "%s: %s - unexpected LP_QoSViolationInd event. " \
458 "Connection does not exist, con_handle=%d\n",
459 __func__, NG_NODE_NAME(l2cap->node), ep->con_handle);
464 /* Verify connection state */
465 if (con->state != NG_L2CAP_CON_OPEN) {
467 "%s: %s - unexpected LP_QoSViolationInd event. " \
468 "Invalid connection state, state=%d, con_handle=%d\n",
469 __func__, NG_NODE_NAME(l2cap->node), con->state,
475 /* XXX FIXME Notify upper layer and terminate channels if required */
478 } /* ng_l2cap_qos_ind */
481 * Prepare L2CAP packet. Prepend packet with L2CAP packet header and then
482 * segment it according to HCI MTU.
486 ng_l2cap_lp_send(ng_l2cap_con_p con, u_int16_t dcid, struct mbuf *m0)
488 ng_l2cap_p l2cap = con->l2cap;
489 ng_l2cap_hdr_t *l2cap_hdr = NULL;
490 ng_hci_acldata_pkt_t *acl_hdr = NULL;
491 struct mbuf *m_last = NULL, *m = NULL;
492 int len, flag = NG_HCI_PACKET_START;
494 KASSERT((con->tx_pkt == NULL),
495 ("%s: %s - another packet pending?!\n", __func__, NG_NODE_NAME(l2cap->node)));
496 KASSERT((l2cap->pkt_size > 0),
497 ("%s: %s - invalid l2cap->pkt_size?!\n", __func__, NG_NODE_NAME(l2cap->node)));
499 /* Prepend mbuf with L2CAP header */
500 m0 = ng_l2cap_prepend(m0, sizeof(*l2cap_hdr));
503 "%s: %s - ng_l2cap_prepend(%zd) failed\n",
504 __func__, NG_NODE_NAME(l2cap->node),
510 l2cap_hdr = mtod(m0, ng_l2cap_hdr_t *);
511 l2cap_hdr->length = htole16(m0->m_pkthdr.len - sizeof(*l2cap_hdr));
512 l2cap_hdr->dcid = htole16(dcid);
515 * Segment single L2CAP packet according to the HCI layer MTU. Convert
516 * each segment into ACL data packet and prepend it with ACL data packet
517 * header. Link all segments together via m_nextpkt link.
519 * XXX BC (Broadcast flag) will always be 0 (zero).
523 /* Check length of the packet against HCI MTU */
524 len = m0->m_pkthdr.len;
525 if (len > l2cap->pkt_size) {
526 m = m_split(m0, l2cap->pkt_size, MB_DONTWAIT);
529 "%s: %s - m_split(%d) failed\n", __func__, NG_NODE_NAME(l2cap->node),
534 len = l2cap->pkt_size;
537 /* Convert packet fragment into ACL data packet */
538 m0 = ng_l2cap_prepend(m0, sizeof(*acl_hdr));
541 "%s: %s - ng_l2cap_prepend(%zd) failed\n",
542 __func__, NG_NODE_NAME(l2cap->node),
547 acl_hdr = mtod(m0, ng_hci_acldata_pkt_t *);
548 acl_hdr->type = NG_HCI_ACL_DATA_PKT;
549 acl_hdr->length = htole16(len);
550 acl_hdr->con_handle = htole16(NG_HCI_MK_CON_HANDLE(
551 con->con_handle, flag, 0));
553 /* Add fragment to the chain */
554 m0->m_nextpkt = NULL;
556 if (con->tx_pkt == NULL)
557 con->tx_pkt = m_last = m0;
559 m_last->m_nextpkt = m0;
564 "%s: %s - attaching ACL packet, con_handle=%d, PB=%#x, length=%d\n",
565 __func__, NG_NODE_NAME(l2cap->node), con->con_handle,
570 flag = NG_HCI_PACKET_FRAGMENT;
578 while (con->tx_pkt != NULL) {
579 m = con->tx_pkt->m_nextpkt;
580 m_freem(con->tx_pkt);
585 } /* ng_l2cap_lp_send */
588 * Receive ACL data packet from the HCI layer. First strip ACL packet header
589 * and get connection handle, PB (Packet Boundary) flag and payload length.
590 * Then find connection descriptor and verify its state. Then process ACL
593 * 1) If we got first segment (pb == NG_HCI_PACKET_START) then extract L2CAP
594 * header and get total length of the L2CAP packet. Then start new L2CAP
597 * 2) If we got other (then first :) segment (pb == NG_HCI_PACKET_FRAGMENT)
598 * then add segment to the packet.
602 ng_l2cap_lp_receive(ng_l2cap_p l2cap, struct mbuf *m)
604 ng_hci_acldata_pkt_t *acl_hdr = NULL;
605 ng_l2cap_hdr_t *l2cap_hdr = NULL;
606 ng_l2cap_con_p con = NULL;
607 u_int16_t con_handle, length, pb;
610 /* Check ACL data packet */
611 if (m->m_pkthdr.len < sizeof(*acl_hdr)) {
613 "%s: %s - invalid ACL data packet. Packet too small, length=%d\n",
614 __func__, NG_NODE_NAME(l2cap->node), m->m_pkthdr.len);
619 /* Strip ACL data packet header */
620 NG_L2CAP_M_PULLUP(m, sizeof(*acl_hdr));
624 acl_hdr = mtod(m, ng_hci_acldata_pkt_t *);
625 m_adj(m, sizeof(*acl_hdr));
627 /* Get ACL connection handle, PB flag and payload length */
628 acl_hdr->con_handle = le16toh(acl_hdr->con_handle);
629 con_handle = NG_HCI_CON_HANDLE(acl_hdr->con_handle);
630 pb = NG_HCI_PB_FLAG(acl_hdr->con_handle);
631 length = le16toh(acl_hdr->length);
634 "%s: %s - got ACL data packet, con_handle=%d, PB=%#x, length=%d\n",
635 __func__, NG_NODE_NAME(l2cap->node), con_handle, pb, length);
637 /* Get connection descriptor */
638 con = ng_l2cap_con_by_handle(l2cap, con_handle);
641 "%s: %s - unexpected ACL data packet. " \
642 "Connection does not exist, con_handle=%d\n",
643 __func__, NG_NODE_NAME(l2cap->node), con_handle);
648 /* Verify connection state */
649 if (con->state != NG_L2CAP_CON_OPEN) {
651 "%s: %s - unexpected ACL data packet. Invalid connection state=%d\n",
652 __func__, NG_NODE_NAME(l2cap->node), con->state);
658 if (pb == NG_HCI_PACKET_START) {
659 if (con->rx_pkt != NULL) {
661 "%s: %s - dropping incomplete L2CAP packet, got %d bytes, want %d bytes\n",
662 __func__, NG_NODE_NAME(l2cap->node),
663 con->rx_pkt->m_pkthdr.len, con->rx_pkt_len);
664 NG_FREE_M(con->rx_pkt);
668 /* Get L2CAP header */
669 if (m->m_pkthdr.len < sizeof(*l2cap_hdr)) {
671 "%s: %s - invalid L2CAP packet start fragment. Packet too small, length=%d\n",
672 __func__, NG_NODE_NAME(l2cap->node),
678 NG_L2CAP_M_PULLUP(m, sizeof(*l2cap_hdr));
682 l2cap_hdr = mtod(m, ng_l2cap_hdr_t *);
685 "%s: %s - staring new L2CAP packet, con_handle=%d, length=%d\n",
686 __func__, NG_NODE_NAME(l2cap->node), con_handle,
687 le16toh(l2cap_hdr->length));
689 /* Start new L2CAP packet */
691 con->rx_pkt_len = le16toh(l2cap_hdr->length)+sizeof(*l2cap_hdr);
692 } else if (pb == NG_HCI_PACKET_FRAGMENT) {
693 if (con->rx_pkt == NULL) {
695 "%s: %s - unexpected ACL data packet fragment, con_handle=%d\n",
696 __func__, NG_NODE_NAME(l2cap->node),
701 /* Add fragment to the L2CAP packet */
702 m_cat(con->rx_pkt, m);
703 con->rx_pkt->m_pkthdr.len += length;
706 "%s: %s - invalid ACL data packet. Invalid PB flag=%#x\n",
707 __func__, NG_NODE_NAME(l2cap->node), pb);
712 con->rx_pkt_len -= length;
713 if (con->rx_pkt_len < 0) {
715 "%s: %s - packet length mismatch. Got %d bytes, offset %d bytes\n",
716 __func__, NG_NODE_NAME(l2cap->node),
717 con->rx_pkt->m_pkthdr.len, con->rx_pkt_len);
718 NG_FREE_M(con->rx_pkt);
720 } else if (con->rx_pkt_len == 0) {
721 /* OK, we have got complete L2CAP packet, so process it */
722 error = ng_l2cap_receive(con);
733 } /* ng_l2cap_lp_receive */
736 * Send queued ACL packets to the HCI layer
740 ng_l2cap_lp_deliver(ng_l2cap_con_p con)
742 ng_l2cap_p l2cap = con->l2cap;
743 struct mbuf *m = NULL;
746 /* Check connection */
747 if (con->state != NG_L2CAP_CON_OPEN)
750 if (con->tx_pkt == NULL)
751 ng_l2cap_con_wakeup(con);
753 if (con->tx_pkt == NULL)
756 /* Check if lower layer protocol is still connected */
757 if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
759 "%s: %s - hook \"%s\" is not connected or valid",
760 __func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);
762 goto drop; /* XXX what to do with "pending"? */
765 /* Send ACL data packets */
766 while (con->pending < con->l2cap->num_pkts && con->tx_pkt != NULL) {
768 con->tx_pkt = con->tx_pkt->m_nextpkt;
772 "%s: %s - sending ACL packet, con_handle=%d, len=%d\n",
773 __func__, NG_NODE_NAME(l2cap->node), con->con_handle,
776 NG_SEND_DATA_ONLY(error, l2cap->hci, m);
779 "%s: %s - could not send ACL data packet, con_handle=%d, error=%d\n",
780 __func__, NG_NODE_NAME(l2cap->node),
781 con->con_handle, error);
783 goto drop; /* XXX what to do with "pending"? */
790 "%s: %s - %d ACL packets have been sent, con_handle=%d\n",
791 __func__, NG_NODE_NAME(l2cap->node), con->pending,
797 while (con->tx_pkt != NULL) {
798 m = con->tx_pkt->m_nextpkt;
799 m_freem(con->tx_pkt);
802 } /* ng_l2cap_lp_deliver */
805 * Process connection timeout. Remove connection from the list. If there
806 * are any channels that wait for the connection then notify them. Free
807 * connection descriptor.
811 ng_l2cap_process_lp_timeout(node_p node, hook_p hook, void *arg1, int con_handle)
813 ng_l2cap_p l2cap = NULL;
814 ng_l2cap_con_p con = NULL;
816 if (NG_NODE_NOT_VALID(node)) {
817 printf("%s: Netgraph node is not valid\n", __func__);
821 l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
822 con = ng_l2cap_con_by_handle(l2cap, con_handle);
826 "%s: %s - could not find connection, con_handle=%d\n",
827 __func__, NG_NODE_NAME(node), con_handle);
831 if (!(con->flags & NG_L2CAP_CON_LP_TIMO)) {
833 "%s: %s - no pending LP timeout, con_handle=%d, state=%d, flags=%#x\n",
834 __func__, NG_NODE_NAME(node), con_handle, con->state,
840 * Notify channels that connection has timed out. This will remove
841 * connection, channels and pending commands.
844 con->flags &= ~NG_L2CAP_CON_LP_TIMO;
845 ng_l2cap_con_fail(con, NG_L2CAP_TIMEOUT);
846 } /* ng_l2cap_process_lp_timeout */
849 * Process auto disconnect timeout and send LP_DisconReq event to the
850 * lower layer protocol
854 ng_l2cap_process_discon_timeout(node_p node, hook_p hook, void *arg1, int con_handle)
856 ng_l2cap_p l2cap = NULL;
857 ng_l2cap_con_p con = NULL;
858 struct ng_mesg *msg = NULL;
859 ng_hci_lp_discon_req_ep *ep = NULL;
862 if (NG_NODE_NOT_VALID(node)) {
863 printf("%s: Netgraph node is not valid\n", __func__);
867 l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
868 con = ng_l2cap_con_by_handle(l2cap, con_handle);
872 "%s: %s - could not find connection, con_handle=%d\n",
873 __func__, NG_NODE_NAME(node), con_handle);
877 if (!(con->flags & NG_L2CAP_CON_AUTO_DISCON_TIMO)) {
879 "%s: %s - no pending disconnect timeout, con_handle=%d, state=%d, flags=%#x\n",
880 __func__, NG_NODE_NAME(node), con_handle, con->state,
885 con->flags &= ~NG_L2CAP_CON_AUTO_DISCON_TIMO;
887 /* Check if lower layer protocol is still connected */
888 if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
890 "%s: %s - hook \"%s\" is not connected or valid\n",
891 __func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);
895 /* Create and send LP_DisconReq event */
896 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_DISCON_REQ,
897 sizeof(*ep), M_WAITOK | M_NULLOK);
901 ep = (ng_hci_lp_discon_req_ep *) (msg->data);
902 ep->con_handle = con->con_handle;
903 ep->reason = 0x13; /* User Ended Connection */
905 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->hci, 0);
906 } /* ng_l2cap_process_discon_timeout */