[BACK]Return to l2cap_lower.c CVS log [TXT][DIR] Up to [local] / sys / netbt

Annotation of sys/netbt/l2cap_lower.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: l2cap_lower.c,v 1.1 2007/05/30 03:42:53 uwe Exp $     */
        !             2: /*     $NetBSD: l2cap_lower.c,v 1.6 2007/04/21 06:15:23 plunky Exp $   */
        !             3:
        !             4: /*-
        !             5:  * Copyright (c) 2005 Iain Hibbert.
        !             6:  * Copyright (c) 2006 Itronix Inc.
        !             7:  * All rights reserved.
        !             8:  *
        !             9:  * Redistribution and use in source and binary forms, with or without
        !            10:  * modification, are permitted provided that the following conditions
        !            11:  * are met:
        !            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.
        !            17:  * 3. The name of Itronix Inc. may not be used to endorse
        !            18:  *    or promote products derived from this software without specific
        !            19:  *    prior written permission.
        !            20:  *
        !            21:  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
        !            22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            23:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            24:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
        !            25:  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
        !            26:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
        !            27:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
        !            28:  * ON ANY THEORY OF LIABILITY, WHETHER IN
        !            29:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            30:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            31:  * POSSIBILITY OF SUCH DAMAGE.
        !            32:  */
        !            33:
        !            34: #include <sys/cdefs.h>
        !            35:
        !            36: #include <sys/param.h>
        !            37: #include <sys/kernel.h>
        !            38: #include <sys/malloc.h>
        !            39: #include <sys/mbuf.h>
        !            40: #include <sys/proc.h>
        !            41: #include <sys/queue.h>
        !            42: #include <sys/systm.h>
        !            43:
        !            44: #include <netbt/bluetooth.h>
        !            45: #include <netbt/hci.h>
        !            46: #include <netbt/l2cap.h>
        !            47:
        !            48: /****************************************************************************
        !            49:  *
        !            50:  *     L2CAP Channel Lower Layer interface
        !            51:  */
        !            52:
        !            53: /*
        !            54:  * L2CAP channel is disconnected, could be:
        !            55:  *
        !            56:  * HCI layer received "Disconnect Complete" event for ACL link
        !            57:  * some Request timed out
        !            58:  * Config failed
        !            59:  * Other end reported invalid CID
        !            60:  * Normal disconnection
        !            61:  * Change link mode failed
        !            62:  */
        !            63: void
        !            64: l2cap_close(struct l2cap_channel *chan, int err)
        !            65: {
        !            66:        struct l2cap_pdu *pdu;
        !            67:        struct l2cap_req *req, *n;
        !            68:
        !            69:        if (chan->lc_state == L2CAP_CLOSED)
        !            70:                return;
        !            71:
        !            72:        /*
        !            73:         * Since any potential PDU could be half sent we just let it go,
        !            74:         * but disassociate ourselves from it as links deal with ownerless
        !            75:         * PDU's in any case.  We could try harder to flush unsent packets
        !            76:         * but maybe its better to leave them in the queue?
        !            77:         */
        !            78:        TAILQ_FOREACH(pdu, &chan->lc_link->hl_txq, lp_next) {
        !            79:                if (pdu->lp_chan == chan)
        !            80:                        pdu->lp_chan = NULL;
        !            81:        }
        !            82:
        !            83:        /*
        !            84:         * and clear any outstanding requests..
        !            85:         */
        !            86:        req = TAILQ_FIRST(&chan->lc_link->hl_reqs);
        !            87:        while (req != NULL) {
        !            88:                n = TAILQ_NEXT(req, lr_next);
        !            89:                if (req->lr_chan == chan)
        !            90:                        l2cap_request_free(req);
        !            91:
        !            92:                req = n;
        !            93:        }
        !            94:
        !            95:        chan->lc_pending = 0;
        !            96:        chan->lc_state = L2CAP_CLOSED;
        !            97:        hci_acl_close(chan->lc_link, err);
        !            98:        chan->lc_link = NULL;
        !            99:
        !           100:        (*chan->lc_proto->disconnected)(chan->lc_upper, err);
        !           101: }
        !           102:
        !           103: /*
        !           104:  * Process incoming L2CAP frame from ACL link. We take off the B-Frame
        !           105:  * header (which is present in all packets), verify the data length
        !           106:  * and distribute the rest of the frame to the relevant channel
        !           107:  * handler.
        !           108:  */
        !           109: void
        !           110: l2cap_recv_frame(struct mbuf *m, struct hci_link *link)
        !           111: {
        !           112:        struct l2cap_channel *chan;
        !           113:        l2cap_hdr_t hdr;
        !           114:
        !           115:        m_copydata(m, 0, sizeof(hdr), (caddr_t)&hdr);
        !           116:        m_adj(m, sizeof(hdr));
        !           117:
        !           118:        hdr.length = letoh16(hdr.length);
        !           119:        hdr.dcid = letoh16(hdr.dcid);
        !           120:
        !           121:        DPRINTFN(5, "(%s) received packet (%d bytes)\n",
        !           122:                    link->hl_unit->hci_devname, hdr.length);
        !           123:
        !           124:        if (hdr.length != m->m_pkthdr.len)
        !           125:                goto failed;
        !           126:
        !           127:        if (hdr.dcid == L2CAP_SIGNAL_CID) {
        !           128:                l2cap_recv_signal(m, link);
        !           129:                return;
        !           130:        }
        !           131:
        !           132:        if (hdr.dcid == L2CAP_CLT_CID) {
        !           133:                m_freem(m);     /* TODO */
        !           134:                return;
        !           135:        }
        !           136:
        !           137:        chan = l2cap_cid_lookup(hdr.dcid);
        !           138:        if (chan != NULL && chan->lc_link == link
        !           139:            && chan->lc_state == L2CAP_OPEN) {
        !           140:                (*chan->lc_proto->input)(chan->lc_upper, m);
        !           141:                return;
        !           142:        }
        !           143:
        !           144:        DPRINTF("(%s) dropping %d L2CAP data bytes for unknown CID #%d\n",
        !           145:                link->hl_unit->hci_devname, hdr.length, hdr.dcid);
        !           146:
        !           147: failed:
        !           148:        m_freem(m);
        !           149: }
        !           150:
        !           151: /*
        !           152:  * Start another L2CAP packet on its way. This is called from l2cap_send
        !           153:  * (when no PDU is pending) and hci_acl_start (when PDU has been placed on
        !           154:  * device queue). Thus we can have more than one PDU waiting at the device
        !           155:  * if space is available but no single channel will hog the link.
        !           156:  */
        !           157: int
        !           158: l2cap_start(struct l2cap_channel *chan)
        !           159: {
        !           160:        struct mbuf *m;
        !           161:        int err = 0;
        !           162:
        !           163:        if (chan->lc_state != L2CAP_OPEN)
        !           164:                return 0;
        !           165:
        !           166:        if (IF_IS_EMPTY(&chan->lc_txq)) {
        !           167:                DPRINTFN(5, "no data, pending = %d\n", chan->lc_pending);
        !           168:                /*
        !           169:                 * If we are just waiting for the queue to flush
        !           170:                 * and it has, we may disconnect..
        !           171:                 */
        !           172:                if (chan->lc_flags & L2CAP_SHUTDOWN
        !           173:                    && chan->lc_pending == 0) {
        !           174:                        chan->lc_state = L2CAP_WAIT_DISCONNECT;
        !           175:                        err = l2cap_send_disconnect_req(chan);
        !           176:                        if (err)
        !           177:                                l2cap_close(chan, err);
        !           178:                }
        !           179:
        !           180:                return err;
        !           181:        }
        !           182:
        !           183:        /*
        !           184:         * We could check QoS/RFC mode here and optionally not send
        !           185:         * the packet if we are not ready for any reason
        !           186:         *
        !           187:         * Also to support flush timeout then we might want to start
        !           188:         * the timer going? (would need to keep some kind of record
        !           189:         * of packets sent, possibly change it so that we allocate
        !           190:         * the l2cap_pdu and fragment the packet, then hand it down
        !           191:         * and get it back when its completed). Hm.
        !           192:         */
        !           193:
        !           194:        IF_DEQUEUE(&chan->lc_txq, m);
        !           195:
        !           196:        KASSERT(chan->lc_link != NULL);
        !           197:        KASSERT(m != NULL);
        !           198:
        !           199:        DPRINTFN(5, "CID #%d sending packet (%d bytes)\n",
        !           200:                chan->lc_lcid, m->m_pkthdr.len);
        !           201:
        !           202:        chan->lc_pending++;
        !           203:        return hci_acl_send(m, chan->lc_link, chan);
        !           204: }

CVSweb