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 $
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/kernel.h>
37 #include <sys/endian.h>
38 #include <sys/malloc.h>
40 #include <sys/queue.h>
41 #include <netgraph/ng_message.h>
42 #include <netgraph/netgraph.h>
43 #include <netgraph/bluetooth/include/ng_bluetooth.h>
44 #include <netgraph/bluetooth/include/ng_hci.h>
45 #include <netgraph/bluetooth/include/ng_l2cap.h>
46 #include <netgraph/bluetooth/l2cap/ng_l2cap_var.h>
47 #include <netgraph/bluetooth/l2cap/ng_l2cap_cmds.h>
48 #include <netgraph/bluetooth/l2cap/ng_l2cap_evnt.h>
49 #include <netgraph/bluetooth/l2cap/ng_l2cap_llpi.h>
50 #include <netgraph/bluetooth/l2cap/ng_l2cap_ulpi.h>
51 #include <netgraph/bluetooth/l2cap/ng_l2cap_misc.h>
53 /******************************************************************************
54 ******************************************************************************
55 ** Lower Layer Protocol (HCI) Interface module
56 ******************************************************************************
57 ******************************************************************************/
60 * Send LP_ConnectReq event to the lower layer protocol. Create new connection
61 * descriptor and initialize it. Create LP_ConnectReq event and send it to the
62 * lower layer, then adjust connection state and start timer. The function WILL
63 * FAIL if connection to the remote unit already exists.
67 ng_l2cap_lp_con_req(ng_l2cap_p l2cap, bdaddr_p bdaddr)
69 struct ng_mesg *msg = NULL;
70 ng_hci_lp_con_req_ep *ep = NULL;
71 ng_l2cap_con_p con = NULL;
74 /* Verify that we DO NOT have connection to the remote unit */
75 con = ng_l2cap_con_by_addr(l2cap, bdaddr);
78 "%s: %s - unexpected LP_ConnectReq event. " \
79 "Connection already exists, state=%d, con_handle=%d\n",
80 __func__, NG_NODE_NAME(l2cap->node), con->state,
86 /* Check if lower layer protocol is still connected */
87 if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
89 "%s: %s - hook \"%s\" is not connected or valid\n",
90 __func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);
95 /* Create and intialize new connection descriptor */
96 con = ng_l2cap_new_con(l2cap, bdaddr);
100 /* Create and send LP_ConnectReq event */
101 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_CON_REQ,
102 sizeof(*ep), M_NOWAIT);
104 ng_l2cap_free_con(con);
109 ep = (ng_hci_lp_con_req_ep *) (msg->data);
110 bcopy(bdaddr, &ep->bdaddr, sizeof(ep->bdaddr));
111 ep->link_type = NG_HCI_LINK_ACL;
113 con->flags |= NG_L2CAP_CON_OUTGOING;
114 con->state = NG_L2CAP_W4_LP_CON_CFM;
115 ng_l2cap_lp_timeout(con);
117 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->hci, 0);
119 if (ng_l2cap_lp_untimeout(con) == 0)
120 ng_l2cap_free_con(con);
123 * Do not free connection if ng_l2cap_lp_untimeout() failed
124 * let timeout handler deal with it. Always return error to
130 } /* ng_l2cap_lp_con_req */
133 * Process LP_ConnectCfm event from the lower layer protocol. It could be
134 * positive or negative. Verify remote unit address then stop the timer and
139 ng_l2cap_lp_con_cfm(ng_l2cap_p l2cap, struct ng_mesg *msg)
141 ng_hci_lp_con_cfm_ep *ep = NULL;
142 ng_l2cap_con_p con = NULL;
146 if (msg->header.arglen != sizeof(*ep)) {
148 "%s: %s - invalid LP_ConnectCfm[Neg] message size\n",
149 __func__, NG_NODE_NAME(l2cap->node));
154 ep = (ng_hci_lp_con_cfm_ep *) (msg->data);
156 /* Check if we have requested/accepted this connection */
157 con = ng_l2cap_con_by_addr(l2cap, &ep->bdaddr);
160 "%s: %s - unexpected LP_ConnectCfm event. Connection does not exist\n",
161 __func__, NG_NODE_NAME(l2cap->node));
166 /* Check connection state */
167 if (con->state != NG_L2CAP_W4_LP_CON_CFM) {
169 "%s: %s - unexpected LP_ConnectCfm event. " \
170 "Invalid connection state, state=%d, con_handle=%d\n",
171 __func__, NG_NODE_NAME(l2cap->node), con->state,
178 * Looks like it is our confirmation. It is safe now to cancel
179 * connection timer and notify upper layer. If timeout already
180 * happened then ignore connection confirmation and let timeout
184 if ((error = ng_l2cap_lp_untimeout(con)) != 0)
187 if (ep->status == 0) {
188 con->state = NG_L2CAP_CON_OPEN;
189 con->con_handle = ep->con_handle;
190 ng_l2cap_lp_deliver(con);
191 } else /* Negative confirmation - remove connection descriptor */
192 ng_l2cap_con_fail(con, ep->status);
195 } /* ng_l2cap_lp_con_cfm */
198 * Process LP_ConnectInd event from the lower layer protocol. This is a good
199 * place to put some extra check on remote unit address and/or class. We could
200 * even forward this information to control hook (or check against internal
201 * black list) and thus implement some kind of firewall. But for now be simple
202 * and create new connection descriptor, start timer and send LP_ConnectRsp
203 * event (i.e. accept connection).
207 ng_l2cap_lp_con_ind(ng_l2cap_p l2cap, struct ng_mesg *msg)
209 ng_hci_lp_con_ind_ep *ep = NULL;
210 ng_hci_lp_con_rsp_ep *rp = NULL;
211 struct ng_mesg *rsp = NULL;
212 ng_l2cap_con_p con = NULL;
216 if (msg->header.arglen != sizeof(*ep)) {
218 "%s: %s - invalid LP_ConnectInd message size\n",
219 __func__, NG_NODE_NAME(l2cap->node));
224 ep = (ng_hci_lp_con_ind_ep *) (msg->data);
226 /* Make sure we have only one connection to the remote unit */
227 con = ng_l2cap_con_by_addr(l2cap, &ep->bdaddr);
230 "%s: %s - unexpected LP_ConnectInd event. " \
231 "Connection already exists, state=%d, con_handle=%d\n",
232 __func__, NG_NODE_NAME(l2cap->node), con->state,
238 /* Check if lower layer protocol is still connected */
239 if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
241 "%s: %s - hook \"%s\" is not connected or valid",
242 __func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);
247 /* Create and intialize new connection descriptor */
248 con = ng_l2cap_new_con(l2cap, &ep->bdaddr);
252 /* Create and send LP_ConnectRsp event */
253 NG_MKMESSAGE(rsp, NGM_HCI_COOKIE, NGM_HCI_LP_CON_RSP,
254 sizeof(*rp), M_NOWAIT);
256 ng_l2cap_free_con(con);
261 rp = (ng_hci_lp_con_rsp_ep *)(rsp->data);
262 rp->status = 0x00; /* accept connection */
263 rp->link_type = NG_HCI_LINK_ACL;
264 bcopy(&ep->bdaddr, &rp->bdaddr, sizeof(rp->bdaddr));
266 con->state = NG_L2CAP_W4_LP_CON_CFM;
267 ng_l2cap_lp_timeout(con);
269 NG_SEND_MSG_HOOK(error, l2cap->node, rsp, l2cap->hci, 0);
271 if (ng_l2cap_lp_untimeout(con) == 0)
272 ng_l2cap_free_con(con);
275 * Do not free connection if ng_l2cap_lp_untimeout() failed
276 * let timeout handler deal with it. Always return error to
282 } /* ng_l2cap_lp_con_ind */
285 * Process LP_DisconnectInd event from the lower layer protocol. We have been
286 * disconnected from the remote unit. So notify the upper layer protocol.
290 ng_l2cap_lp_discon_ind(ng_l2cap_p l2cap, struct ng_mesg *msg)
292 ng_hci_lp_discon_ind_ep *ep = NULL;
293 ng_l2cap_con_p con = NULL;
297 if (msg->header.arglen != sizeof(*ep)) {
299 "%s: %s - invalid LP_DisconnectInd message size\n",
300 __func__, NG_NODE_NAME(l2cap->node));
305 ep = (ng_hci_lp_discon_ind_ep *) (msg->data);
307 /* Check if we have this connection */
308 con = ng_l2cap_con_by_handle(l2cap, ep->con_handle);
311 "%s: %s - unexpected LP_DisconnectInd event. " \
312 "Connection does not exist, con_handle=%d\n",
313 __func__, NG_NODE_NAME(l2cap->node), ep->con_handle);
318 /* XXX Verify connection state -- do we need to check this? */
319 if (con->state != NG_L2CAP_CON_OPEN) {
321 "%s: %s - unexpected LP_DisconnectInd event. " \
322 "Invalid connection state, state=%d, con_handle=%d\n",
323 __func__, NG_NODE_NAME(l2cap->node), con->state,
330 * Notify upper layer and remove connection
331 * Note: The connection could have auto disconnect timeout set. Try
332 * to remove it. If auto disconnect timeout happened then ignore
333 * disconnect indication and let timeout handle that.
336 if (con->flags & NG_L2CAP_CON_AUTO_DISCON_TIMO)
337 if ((error = ng_l2cap_discon_untimeout(con)) != 0)
340 ng_l2cap_con_fail(con, ep->reason);
343 } /* ng_l2cap_lp_discon_ind */
346 * Send LP_QoSSetupReq event to the lower layer protocol
350 ng_l2cap_lp_qos_req(ng_l2cap_p l2cap, u_int16_t con_handle,
351 ng_l2cap_flow_p flow)
353 struct ng_mesg *msg = NULL;
354 ng_hci_lp_qos_req_ep *ep = NULL;
355 ng_l2cap_con_p con = NULL;
358 /* Verify that we have this connection */
359 con = ng_l2cap_con_by_handle(l2cap, con_handle);
362 "%s: %s - unexpected LP_QoSSetupReq event. " \
363 "Connection does not exist, con_handle=%d\n",
364 __func__, NG_NODE_NAME(l2cap->node), con_handle);
369 /* Verify connection state */
370 if (con->state != NG_L2CAP_CON_OPEN) {
372 "%s: %s - unexpected LP_QoSSetupReq event. " \
373 "Invalid connection state, state=%d, con_handle=%d\n",
374 __func__, NG_NODE_NAME(l2cap->node), con->state,
380 /* Check if lower layer protocol is still connected */
381 if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
383 "%s: %s - hook \"%s\" is not connected or valid",
384 __func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);
389 /* Create and send LP_QoSSetupReq event */
390 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_QOS_REQ,
391 sizeof(*ep), M_NOWAIT);
395 ep = (ng_hci_lp_qos_req_ep *) (msg->data);
396 ep->con_handle = con_handle;
397 ep->flags = flow->flags;
398 ep->service_type = flow->service_type;
399 ep->token_rate = flow->token_rate;
400 ep->peak_bandwidth = flow->peak_bandwidth;
401 ep->latency = flow->latency;
402 ep->delay_variation = flow->delay_variation;
404 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->hci, 0);
407 } /* ng_l2cap_lp_con_req */
410 * Process LP_QoSSetupCfm from the lower layer protocol
414 ng_l2cap_lp_qos_cfm(ng_l2cap_p l2cap, struct ng_mesg *msg)
416 ng_hci_lp_qos_cfm_ep *ep = NULL;
420 if (msg->header.arglen != sizeof(*ep)) {
422 "%s: %s - invalid LP_QoSSetupCfm[Neg] message size\n",
423 __func__, NG_NODE_NAME(l2cap->node));
428 ep = (ng_hci_lp_qos_cfm_ep *) (msg->data);
429 /* XXX FIXME do something */
432 } /* ng_l2cap_lp_qos_cfm */
435 * Process LP_QoSViolationInd event from the lower layer protocol. Lower
436 * layer protocol has detected QoS Violation, so we MUST notify the
441 ng_l2cap_lp_qos_ind(ng_l2cap_p l2cap, struct ng_mesg *msg)
443 ng_hci_lp_qos_ind_ep *ep = NULL;
444 ng_l2cap_con_p con = NULL;
448 if (msg->header.arglen != sizeof(*ep)) {
450 "%s: %s - invalid LP_QoSViolation message size\n",
451 __func__, NG_NODE_NAME(l2cap->node));
456 ep = (ng_hci_lp_qos_ind_ep *) (msg->data);
458 /* Check if we have this connection */
459 con = ng_l2cap_con_by_handle(l2cap, ep->con_handle);
462 "%s: %s - unexpected LP_QoSViolationInd event. " \
463 "Connection does not exist, con_handle=%d\n",
464 __func__, NG_NODE_NAME(l2cap->node), ep->con_handle);
469 /* Verify connection state */
470 if (con->state != NG_L2CAP_CON_OPEN) {
472 "%s: %s - unexpected LP_QoSViolationInd event. " \
473 "Invalid connection state, state=%d, con_handle=%d\n",
474 __func__, NG_NODE_NAME(l2cap->node), con->state,
480 /* XXX FIXME Notify upper layer and terminate channels if required */
483 } /* ng_l2cap_qos_ind */
486 * Prepare L2CAP packet. Prepend packet with L2CAP packet header and then
487 * segment it according to HCI MTU.
491 ng_l2cap_lp_send(ng_l2cap_con_p con, u_int16_t dcid, struct mbuf *m0)
493 ng_l2cap_p l2cap = con->l2cap;
494 ng_l2cap_hdr_t *l2cap_hdr = NULL;
495 ng_hci_acldata_pkt_t *acl_hdr = NULL;
496 struct mbuf *m_last = NULL, *m = NULL;
497 int len, flag = NG_HCI_PACKET_START;
499 KASSERT((con->tx_pkt == NULL),
500 ("%s: %s - another packet pending?!\n", __func__, NG_NODE_NAME(l2cap->node)));
501 KASSERT((l2cap->pkt_size > 0),
502 ("%s: %s - invalid l2cap->pkt_size?!\n", __func__, NG_NODE_NAME(l2cap->node)));
504 /* Prepend mbuf with L2CAP header */
505 m0 = ng_l2cap_prepend(m0, sizeof(*l2cap_hdr));
508 "%s: %s - ng_l2cap_prepend(%zd) failed\n",
509 __func__, NG_NODE_NAME(l2cap->node),
515 l2cap_hdr = mtod(m0, ng_l2cap_hdr_t *);
516 l2cap_hdr->length = htole16(m0->m_pkthdr.len - sizeof(*l2cap_hdr));
517 l2cap_hdr->dcid = htole16(dcid);
520 * Segment single L2CAP packet according to the HCI layer MTU. Convert
521 * each segment into ACL data packet and prepend it with ACL data packet
522 * header. Link all segments together via m_nextpkt link.
524 * XXX BC (Broadcast flag) will always be 0 (zero).
528 /* Check length of the packet against HCI MTU */
529 len = m0->m_pkthdr.len;
530 if (len > l2cap->pkt_size) {
531 m = m_split(m0, l2cap->pkt_size, M_DONTWAIT);
534 "%s: %s - m_split(%d) failed\n", __func__, NG_NODE_NAME(l2cap->node),
539 len = l2cap->pkt_size;
542 /* Convert packet fragment into ACL data packet */
543 m0 = ng_l2cap_prepend(m0, sizeof(*acl_hdr));
546 "%s: %s - ng_l2cap_prepend(%zd) failed\n",
547 __func__, NG_NODE_NAME(l2cap->node),
552 acl_hdr = mtod(m0, ng_hci_acldata_pkt_t *);
553 acl_hdr->type = NG_HCI_ACL_DATA_PKT;
554 acl_hdr->length = htole16(len);
555 acl_hdr->con_handle = htole16(NG_HCI_MK_CON_HANDLE(
556 con->con_handle, flag, 0));
558 /* Add fragment to the chain */
559 m0->m_nextpkt = NULL;
561 if (con->tx_pkt == NULL)
562 con->tx_pkt = m_last = m0;
564 m_last->m_nextpkt = m0;
569 "%s: %s - attaching ACL packet, con_handle=%d, PB=%#x, length=%d\n",
570 __func__, NG_NODE_NAME(l2cap->node), con->con_handle,
575 flag = NG_HCI_PACKET_FRAGMENT;
583 while (con->tx_pkt != NULL) {
584 m = con->tx_pkt->m_nextpkt;
585 m_freem(con->tx_pkt);
590 } /* ng_l2cap_lp_send */
593 * Receive ACL data packet from the HCI layer. First strip ACL packet header
594 * and get connection handle, PB (Packet Boundary) flag and payload length.
595 * Then find connection descriptor and verify its state. Then process ACL
598 * 1) If we got first segment (pb == NG_HCI_PACKET_START) then extract L2CAP
599 * header and get total length of the L2CAP packet. Then start new L2CAP
602 * 2) If we got other (then first :) segment (pb == NG_HCI_PACKET_FRAGMENT)
603 * then add segment to the packet.
607 ng_l2cap_lp_receive(ng_l2cap_p l2cap, struct mbuf *m)
609 ng_hci_acldata_pkt_t *acl_hdr = NULL;
610 ng_l2cap_hdr_t *l2cap_hdr = NULL;
611 ng_l2cap_con_p con = NULL;
612 u_int16_t con_handle, length, pb;
615 /* Check ACL data packet */
616 if (m->m_pkthdr.len < sizeof(*acl_hdr)) {
618 "%s: %s - invalid ACL data packet. Packet too small, length=%d\n",
619 __func__, NG_NODE_NAME(l2cap->node), m->m_pkthdr.len);
624 /* Strip ACL data packet header */
625 NG_L2CAP_M_PULLUP(m, sizeof(*acl_hdr));
629 acl_hdr = mtod(m, ng_hci_acldata_pkt_t *);
630 m_adj(m, sizeof(*acl_hdr));
632 /* Get ACL connection handle, PB flag and payload length */
633 acl_hdr->con_handle = le16toh(acl_hdr->con_handle);
634 con_handle = NG_HCI_CON_HANDLE(acl_hdr->con_handle);
635 pb = NG_HCI_PB_FLAG(acl_hdr->con_handle);
636 length = le16toh(acl_hdr->length);
639 "%s: %s - got ACL data packet, con_handle=%d, PB=%#x, length=%d\n",
640 __func__, NG_NODE_NAME(l2cap->node), con_handle, pb, length);
642 /* Get connection descriptor */
643 con = ng_l2cap_con_by_handle(l2cap, con_handle);
646 "%s: %s - unexpected ACL data packet. " \
647 "Connection does not exist, con_handle=%d\n",
648 __func__, NG_NODE_NAME(l2cap->node), con_handle);
653 /* Verify connection state */
654 if (con->state != NG_L2CAP_CON_OPEN) {
656 "%s: %s - unexpected ACL data packet. Invalid connection state=%d\n",
657 __func__, NG_NODE_NAME(l2cap->node), con->state);
663 if (pb == NG_HCI_PACKET_START) {
664 if (con->rx_pkt != NULL) {
666 "%s: %s - dropping incomplete L2CAP packet, got %d bytes, want %d bytes\n",
667 __func__, NG_NODE_NAME(l2cap->node),
668 con->rx_pkt->m_pkthdr.len, con->rx_pkt_len);
669 NG_FREE_M(con->rx_pkt);
673 /* Get L2CAP header */
674 if (m->m_pkthdr.len < sizeof(*l2cap_hdr)) {
676 "%s: %s - invalid L2CAP packet start fragment. Packet too small, length=%d\n",
677 __func__, NG_NODE_NAME(l2cap->node),
683 NG_L2CAP_M_PULLUP(m, sizeof(*l2cap_hdr));
687 l2cap_hdr = mtod(m, ng_l2cap_hdr_t *);
690 "%s: %s - staring new L2CAP packet, con_handle=%d, length=%d\n",
691 __func__, NG_NODE_NAME(l2cap->node), con_handle,
692 le16toh(l2cap_hdr->length));
694 /* Start new L2CAP packet */
696 con->rx_pkt_len = le16toh(l2cap_hdr->length)+sizeof(*l2cap_hdr);
697 } else if (pb == NG_HCI_PACKET_FRAGMENT) {
698 if (con->rx_pkt == NULL) {
700 "%s: %s - unexpected ACL data packet fragment, con_handle=%d\n",
701 __func__, NG_NODE_NAME(l2cap->node),
706 /* Add fragment to the L2CAP packet */
707 m_cat(con->rx_pkt, m);
708 con->rx_pkt->m_pkthdr.len += length;
711 "%s: %s - invalid ACL data packet. Invalid PB flag=%#x\n",
712 __func__, NG_NODE_NAME(l2cap->node), pb);
717 con->rx_pkt_len -= length;
718 if (con->rx_pkt_len < 0) {
720 "%s: %s - packet length mismatch. Got %d bytes, offset %d bytes\n",
721 __func__, NG_NODE_NAME(l2cap->node),
722 con->rx_pkt->m_pkthdr.len, con->rx_pkt_len);
723 NG_FREE_M(con->rx_pkt);
725 } else if (con->rx_pkt_len == 0) {
726 /* OK, we have got complete L2CAP packet, so process it */
727 error = ng_l2cap_receive(con);
738 } /* ng_l2cap_lp_receive */
741 * Send queued ACL packets to the HCI layer
745 ng_l2cap_lp_deliver(ng_l2cap_con_p con)
747 ng_l2cap_p l2cap = con->l2cap;
748 struct mbuf *m = NULL;
751 /* Check connection */
752 if (con->state != NG_L2CAP_CON_OPEN)
755 if (con->tx_pkt == NULL)
756 ng_l2cap_con_wakeup(con);
758 if (con->tx_pkt == NULL)
761 /* Check if lower layer protocol is still connected */
762 if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
764 "%s: %s - hook \"%s\" is not connected or valid",
765 __func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);
767 goto drop; /* XXX what to do with "pending"? */
770 /* Send ACL data packets */
771 while (con->pending < con->l2cap->num_pkts && con->tx_pkt != NULL) {
773 con->tx_pkt = con->tx_pkt->m_nextpkt;
777 "%s: %s - sending ACL packet, con_handle=%d, len=%d\n",
778 __func__, NG_NODE_NAME(l2cap->node), con->con_handle,
781 NG_SEND_DATA_ONLY(error, l2cap->hci, m);
784 "%s: %s - could not send ACL data packet, con_handle=%d, error=%d\n",
785 __func__, NG_NODE_NAME(l2cap->node),
786 con->con_handle, error);
788 goto drop; /* XXX what to do with "pending"? */
795 "%s: %s - %d ACL packets have been sent, con_handle=%d\n",
796 __func__, NG_NODE_NAME(l2cap->node), con->pending,
802 while (con->tx_pkt != NULL) {
803 m = con->tx_pkt->m_nextpkt;
804 m_freem(con->tx_pkt);
807 } /* ng_l2cap_lp_deliver */
810 * Process connection timeout. Remove connection from the list. If there
811 * are any channels that wait for the connection then notify them. Free
812 * connection descriptor.
816 ng_l2cap_process_lp_timeout(node_p node, hook_p hook, void *arg1, int con_handle)
818 ng_l2cap_p l2cap = NULL;
819 ng_l2cap_con_p con = NULL;
821 if (NG_NODE_NOT_VALID(node)) {
822 printf("%s: Netgraph node is not valid\n", __func__);
826 l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
827 con = ng_l2cap_con_by_handle(l2cap, con_handle);
831 "%s: %s - could not find connection, con_handle=%d\n",
832 __func__, NG_NODE_NAME(node), con_handle);
836 if (!(con->flags & NG_L2CAP_CON_LP_TIMO)) {
838 "%s: %s - no pending LP timeout, con_handle=%d, state=%d, flags=%#x\n",
839 __func__, NG_NODE_NAME(node), con_handle, con->state,
845 * Notify channels that connection has timed out. This will remove
846 * connection, channels and pending commands.
849 con->flags &= ~NG_L2CAP_CON_LP_TIMO;
850 ng_l2cap_con_fail(con, NG_L2CAP_TIMEOUT);
851 } /* ng_l2cap_process_lp_timeout */
854 * Process auto disconnect timeout and send LP_DisconReq event to the
855 * lower layer protocol
859 ng_l2cap_process_discon_timeout(node_p node, hook_p hook, void *arg1, int con_handle)
861 ng_l2cap_p l2cap = NULL;
862 ng_l2cap_con_p con = NULL;
863 struct ng_mesg *msg = NULL;
864 ng_hci_lp_discon_req_ep *ep = NULL;
867 if (NG_NODE_NOT_VALID(node)) {
868 printf("%s: Netgraph node is not valid\n", __func__);
872 l2cap = (ng_l2cap_p) NG_NODE_PRIVATE(node);
873 con = ng_l2cap_con_by_handle(l2cap, con_handle);
877 "%s: %s - could not find connection, con_handle=%d\n",
878 __func__, NG_NODE_NAME(node), con_handle);
882 if (!(con->flags & NG_L2CAP_CON_AUTO_DISCON_TIMO)) {
884 "%s: %s - no pending disconnect timeout, con_handle=%d, state=%d, flags=%#x\n",
885 __func__, NG_NODE_NAME(node), con_handle, con->state,
890 con->flags &= ~NG_L2CAP_CON_AUTO_DISCON_TIMO;
892 /* Check if lower layer protocol is still connected */
893 if (l2cap->hci == NULL || NG_HOOK_NOT_VALID(l2cap->hci)) {
895 "%s: %s - hook \"%s\" is not connected or valid\n",
896 __func__, NG_NODE_NAME(l2cap->node), NG_L2CAP_HOOK_HCI);
900 /* Create and send LP_DisconReq event */
901 NG_MKMESSAGE(msg, NGM_HCI_COOKIE, NGM_HCI_LP_DISCON_REQ,
902 sizeof(*ep), M_NOWAIT);
906 ep = (ng_hci_lp_discon_req_ep *) (msg->data);
907 ep->con_handle = con->con_handle;
908 ep->reason = 0x13; /* User Ended Connection */
910 NG_SEND_MSG_HOOK(error, l2cap->node, msg, l2cap->hci, 0);
911 } /* ng_l2cap_process_discon_timeout */