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

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

1.1     ! nbrk        1: /*     $OpenBSD: rfcomm_session.c,v 1.1 2007/06/01 02:46:12 uwe Exp $  */
        !             2: /*     $NetBSD: rfcomm_session.c,v 1.9 2007/04/21 06:15:23 plunky Exp $        */
        !             3:
        !             4: /*-
        !             5:  * Copyright (c) 2006 Itronix Inc.
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * Written by Iain Hibbert for Itronix Inc.
        !             9:  *
        !            10:  * Redistribution and use in source and binary forms, with or without
        !            11:  * modification, are permitted provided that the following conditions
        !            12:  * are met:
        !            13:  * 1. Redistributions of source code must retain the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer.
        !            15:  * 2. Redistributions in binary form must reproduce the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer in the
        !            17:  *    documentation and/or other materials provided with the distribution.
        !            18:  * 3. The name of Itronix Inc. may not be used to endorse
        !            19:  *    or promote products derived from this software without specific
        !            20:  *    prior written permission.
        !            21:  *
        !            22:  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
        !            23:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            24:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            25:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
        !            26:  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
        !            27:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
        !            28:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
        !            29:  * ON ANY THEORY OF LIABILITY, WHETHER IN
        !            30:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            31:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            32:  * POSSIBILITY OF SUCH DAMAGE.
        !            33:  */
        !            34:
        !            35: #include <sys/cdefs.h>
        !            36:
        !            37: #include <sys/param.h>
        !            38: #include <sys/kernel.h>
        !            39: #include <sys/mbuf.h>
        !            40: #include <sys/proc.h>
        !            41: #include <sys/systm.h>
        !            42: #include <sys/types.h>
        !            43:
        !            44: #include <netbt/bluetooth.h>
        !            45: #include <netbt/hci.h>
        !            46: #include <netbt/l2cap.h>
        !            47: #include <netbt/rfcomm.h>
        !            48:
        !            49: /******************************************************************************
        !            50:  *
        !            51:  * RFCOMM Multiplexer Sessions sit directly on L2CAP channels, and can
        !            52:  * multiplex up to 30 incoming and 30 outgoing connections.
        !            53:  * Only one Multiplexer is allowed between any two devices.
        !            54:  */
        !            55:
        !            56: static void rfcomm_session_timeout(void *);
        !            57: static void rfcomm_session_recv_sabm(struct rfcomm_session *, int);
        !            58: static void rfcomm_session_recv_disc(struct rfcomm_session *, int);
        !            59: static void rfcomm_session_recv_ua(struct rfcomm_session *, int);
        !            60: static void rfcomm_session_recv_dm(struct rfcomm_session *, int);
        !            61: static void rfcomm_session_recv_uih(struct rfcomm_session *, int, int, struct mbuf *, int);
        !            62: static void rfcomm_session_recv_mcc(struct rfcomm_session *, struct mbuf *);
        !            63: static void rfcomm_session_recv_mcc_test(struct rfcomm_session *, int, struct mbuf *);
        !            64: static void rfcomm_session_recv_mcc_fcon(struct rfcomm_session *, int);
        !            65: static void rfcomm_session_recv_mcc_fcoff(struct rfcomm_session *, int);
        !            66: static void rfcomm_session_recv_mcc_msc(struct rfcomm_session *, int, struct mbuf *);
        !            67: static void rfcomm_session_recv_mcc_rpn(struct rfcomm_session *, int, struct mbuf *);
        !            68: static void rfcomm_session_recv_mcc_rls(struct rfcomm_session *, int, struct mbuf *);
        !            69: static void rfcomm_session_recv_mcc_pn(struct rfcomm_session *, int, struct mbuf *);
        !            70: static void rfcomm_session_recv_mcc_nsc(struct rfcomm_session *, int, struct mbuf *);
        !            71:
        !            72: /* L2CAP callbacks */
        !            73: static void rfcomm_session_connecting(void *);
        !            74: static void rfcomm_session_connected(void *);
        !            75: static void rfcomm_session_disconnected(void *, int);
        !            76: static void *rfcomm_session_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
        !            77: static void rfcomm_session_complete(void *, int);
        !            78: static void rfcomm_session_linkmode(void *, int);
        !            79: static void rfcomm_session_input(void *, struct mbuf *);
        !            80:
        !            81: static const struct btproto rfcomm_session_proto = {
        !            82:        rfcomm_session_connecting,
        !            83:        rfcomm_session_connected,
        !            84:        rfcomm_session_disconnected,
        !            85:        rfcomm_session_newconn,
        !            86:        rfcomm_session_complete,
        !            87:        rfcomm_session_linkmode,
        !            88:        rfcomm_session_input,
        !            89: };
        !            90:
        !            91: struct rfcomm_session_list
        !            92:        rfcomm_session_active = LIST_HEAD_INITIALIZER(rfcomm_session_active);
        !            93:
        !            94: struct rfcomm_session_list
        !            95:        rfcomm_session_listen = LIST_HEAD_INITIALIZER(rfcomm_session_listen);
        !            96:
        !            97: struct pool rfcomm_credit_pool;
        !            98:
        !            99: /*
        !           100:  * RFCOMM System Parameters (see section 5.3)
        !           101:  */
        !           102: int rfcomm_mtu_default = 127;  /* bytes */
        !           103: int rfcomm_ack_timeout = 20;   /* seconds */
        !           104: int rfcomm_mcc_timeout = 20;   /* seconds */
        !           105:
        !           106: /*
        !           107:  * Reversed CRC table as per TS 07.10 Annex B.3.5
        !           108:  */
        !           109: static const uint8_t crctable[256] = { /* reversed, 8-bit, poly=0x07 */
        !           110:        0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75,
        !           111:        0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b,
        !           112:        0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69,
        !           113:        0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67,
        !           114:
        !           115:        0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d,
        !           116:        0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43,
        !           117:        0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51,
        !           118:        0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f,
        !           119:
        !           120:        0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05,
        !           121:        0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b,
        !           122:        0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19,
        !           123:        0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17,
        !           124:
        !           125:        0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d,
        !           126:        0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33,
        !           127:        0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21,
        !           128:        0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f,
        !           129:
        !           130:        0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95,
        !           131:        0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b,
        !           132:        0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89,
        !           133:        0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87,
        !           134:
        !           135:        0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad,
        !           136:        0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3,
        !           137:        0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1,
        !           138:        0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf,
        !           139:
        !           140:        0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5,
        !           141:        0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb,
        !           142:        0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9,
        !           143:        0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7,
        !           144:
        !           145:        0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd,
        !           146:        0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3,
        !           147:        0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1,
        !           148:        0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf
        !           149: };
        !           150:
        !           151: #define FCS(f, d)      crctable[(f) ^ (d)]
        !           152:
        !           153: /*
        !           154:  * rfcomm_init()
        !           155:  *
        !           156:  * initialize the "credit pool".
        !           157:  */
        !           158: void
        !           159: rfcomm_init(void)
        !           160: {
        !           161:        pool_init(&rfcomm_credit_pool, 0, 0, 0, 0, "rfcomm_credit", NULL);
        !           162: }
        !           163:
        !           164: /*
        !           165:  * rfcomm_session_alloc(list, sockaddr)
        !           166:  *
        !           167:  * allocate a new session and fill in the blanks, then
        !           168:  * attach session to front of specified list (active or listen)
        !           169:  */
        !           170: struct rfcomm_session *
        !           171: rfcomm_session_alloc(struct rfcomm_session_list *list,
        !           172:                        struct sockaddr_bt *laddr)
        !           173: {
        !           174:        struct rfcomm_session *rs;
        !           175:        int err;
        !           176:
        !           177:        rs = malloc(sizeof(*rs), M_BLUETOOTH, M_NOWAIT);
        !           178:        if (rs == NULL)
        !           179:                return NULL;
        !           180:        bzero(rs, sizeof *rs);
        !           181:
        !           182:        rs->rs_state = RFCOMM_SESSION_CLOSED;
        !           183:
        !           184:        timeout_set(&rs->rs_timeout, rfcomm_session_timeout, rs);
        !           185:
        !           186:        SIMPLEQ_INIT(&rs->rs_credits);
        !           187:        LIST_INIT(&rs->rs_dlcs);
        !           188:
        !           189:        err = l2cap_attach(&rs->rs_l2cap, &rfcomm_session_proto, rs);
        !           190:        if (err) {
        !           191:                free(rs, M_BLUETOOTH);
        !           192:                return NULL;
        !           193:        }
        !           194:
        !           195:        (void)l2cap_getopt(rs->rs_l2cap, SO_L2CAP_OMTU, &rs->rs_mtu);
        !           196:
        !           197:        if (laddr->bt_psm == L2CAP_PSM_ANY)
        !           198:                laddr->bt_psm = L2CAP_PSM_RFCOMM;
        !           199:
        !           200:        (void)l2cap_bind(rs->rs_l2cap, laddr);
        !           201:
        !           202:        LIST_INSERT_HEAD(list, rs, rs_next);
        !           203:
        !           204:        return rs;
        !           205: }
        !           206:
        !           207: /*
        !           208:  * rfcomm_session_free(rfcomm_session)
        !           209:  *
        !           210:  * release a session, including any cleanup
        !           211:  */
        !           212: void
        !           213: rfcomm_session_free(struct rfcomm_session *rs)
        !           214: {
        !           215:        struct rfcomm_credit *credit;
        !           216:
        !           217:        KASSERT(rs != NULL);
        !           218:        KASSERT(LIST_EMPTY(&rs->rs_dlcs));
        !           219:
        !           220:        rs->rs_state = RFCOMM_SESSION_CLOSED;
        !           221:
        !           222:        /*
        !           223:         * If the callout is already invoked we have no way to stop it,
        !           224:         * but it will call us back right away (there are no DLC's) so
        !           225:         * not to worry.
        !           226:         */
        !           227:        timeout_del(&rs->rs_timeout);
        !           228:        if (timeout_triggered(&rs->rs_timeout))
        !           229:                return;
        !           230:
        !           231:        /*
        !           232:         * Take care that rfcomm_session_disconnected() doesnt call
        !           233:         * us back either as it will do if the l2cap_channel has not
        !           234:         * been closed when we detach it..
        !           235:         */
        !           236:        if (rs->rs_flags & RFCOMM_SESSION_FREE)
        !           237:                return;
        !           238:
        !           239:        rs->rs_flags |= RFCOMM_SESSION_FREE;
        !           240:
        !           241:        /* throw away any remaining credit notes */
        !           242:        while ((credit = SIMPLEQ_FIRST(&rs->rs_credits)) != NULL) {
        !           243:                SIMPLEQ_REMOVE_HEAD(&rs->rs_credits, rc_next);
        !           244:                pool_put(&rfcomm_credit_pool, credit);
        !           245:        }
        !           246:
        !           247:        KASSERT(SIMPLEQ_EMPTY(&rs->rs_credits));
        !           248:
        !           249:        /* Goodbye! */
        !           250:        LIST_REMOVE(rs, rs_next);
        !           251:        l2cap_detach(&rs->rs_l2cap);
        !           252:        free(rs, M_BLUETOOTH);
        !           253: }
        !           254:
        !           255: /*
        !           256:  * rfcomm_session_lookup(sockaddr, sockaddr)
        !           257:  *
        !           258:  * Find active rfcomm session matching src and dest addresses
        !           259:  * when src is BDADDR_ANY match any local address
        !           260:  */
        !           261: struct rfcomm_session *
        !           262: rfcomm_session_lookup(struct sockaddr_bt *src, struct sockaddr_bt *dest)
        !           263: {
        !           264:        struct rfcomm_session *rs;
        !           265:        struct sockaddr_bt addr;
        !           266:
        !           267:        LIST_FOREACH(rs, &rfcomm_session_active, rs_next) {
        !           268:                if (rs->rs_state == RFCOMM_SESSION_CLOSED)
        !           269:                        continue;
        !           270:
        !           271:                l2cap_sockaddr(rs->rs_l2cap, &addr);
        !           272:
        !           273:                if (bdaddr_same(&src->bt_bdaddr, &addr.bt_bdaddr) == 0)
        !           274:                        if (bdaddr_any(&src->bt_bdaddr) == 0)
        !           275:                                continue;
        !           276:
        !           277:                l2cap_peeraddr(rs->rs_l2cap, &addr);
        !           278:
        !           279:                if (addr.bt_psm != dest->bt_psm)
        !           280:                        continue;
        !           281:
        !           282:                if (bdaddr_same(&dest->bt_bdaddr, &addr.bt_bdaddr))
        !           283:                        break;
        !           284:        }
        !           285:
        !           286:        return rs;
        !           287: }
        !           288:
        !           289: /*
        !           290:  * rfcomm_session_timeout(rfcomm_session)
        !           291:  *
        !           292:  * Session timeouts are scheduled when a session is left or
        !           293:  * created with no DLCs, and when SABM(0) or DISC(0) are
        !           294:  * sent.
        !           295:  *
        !           296:  * So, if it is in an open state with DLC's attached then
        !           297:  * we leave it alone, otherwise the session is lost.
        !           298:  */
        !           299: static void
        !           300: rfcomm_session_timeout(void *arg)
        !           301: {
        !           302:        struct rfcomm_session *rs = arg;
        !           303:        struct rfcomm_dlc *dlc;
        !           304:        int s;
        !           305:
        !           306:        KASSERT(rs != NULL);
        !           307:
        !           308:        s = splsoftnet();
        !           309:
        !           310:        if (rs->rs_state != RFCOMM_SESSION_OPEN) {
        !           311:                DPRINTF("timeout\n");
        !           312:                rs->rs_state = RFCOMM_SESSION_CLOSED;
        !           313:
        !           314:                while (!LIST_EMPTY(&rs->rs_dlcs)) {
        !           315:                        dlc = LIST_FIRST(&rs->rs_dlcs);
        !           316:
        !           317:                        rfcomm_dlc_close(dlc, ETIMEDOUT);
        !           318:                }
        !           319:        }
        !           320:
        !           321:        if (LIST_EMPTY(&rs->rs_dlcs)) {
        !           322:                DPRINTF("expiring\n");
        !           323:                rfcomm_session_free(rs);
        !           324:        }
        !           325:        splx(s);
        !           326: }
        !           327:
        !           328: /***********************************************************************
        !           329:  *
        !           330:  *     RFCOMM Session L2CAP protocol callbacks
        !           331:  *
        !           332:  */
        !           333:
        !           334: static void
        !           335: rfcomm_session_connecting(void *arg)
        !           336: {
        !           337:        /* struct rfcomm_session *rs = arg; */
        !           338:
        !           339:        DPRINTF("Connecting\n");
        !           340: }
        !           341:
        !           342: static void
        !           343: rfcomm_session_connected(void *arg)
        !           344: {
        !           345:        struct rfcomm_session *rs = arg;
        !           346:
        !           347:        DPRINTF("Connected\n");
        !           348:
        !           349:        /*
        !           350:         * L2CAP is open.
        !           351:         *
        !           352:         * If we are initiator, we can send our SABM(0)
        !           353:         * a timeout should be active?
        !           354:         *
        !           355:         * We must take note of the L2CAP MTU because currently
        !           356:         * the L2CAP implementation can only do Basic Mode.
        !           357:         */
        !           358:        l2cap_getopt(rs->rs_l2cap, SO_L2CAP_OMTU, &rs->rs_mtu);
        !           359:
        !           360:        rs->rs_mtu -= 6; /* (RFCOMM overhead could be this big) */
        !           361:        if (rs->rs_mtu < RFCOMM_MTU_MIN) {
        !           362:                rfcomm_session_disconnected(rs, EINVAL);
        !           363:                return;
        !           364:        }
        !           365:
        !           366:        if (IS_INITIATOR(rs)) {
        !           367:                int err;
        !           368:
        !           369:                err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_SABM, 0);
        !           370:                if (err)
        !           371:                        rfcomm_session_disconnected(rs, err);
        !           372:
        !           373:                timeout_add(&rs->rs_timeout, rfcomm_ack_timeout * hz);
        !           374:        }
        !           375: }
        !           376:
        !           377: static void
        !           378: rfcomm_session_disconnected(void *arg, int err)
        !           379: {
        !           380:        struct rfcomm_session *rs = arg;
        !           381:        struct rfcomm_dlc *dlc;
        !           382:
        !           383:        DPRINTF("Disconnected\n");
        !           384:
        !           385:        rs->rs_state = RFCOMM_SESSION_CLOSED;
        !           386:
        !           387:        while (!LIST_EMPTY(&rs->rs_dlcs)) {
        !           388:                dlc = LIST_FIRST(&rs->rs_dlcs);
        !           389:
        !           390:                rfcomm_dlc_close(dlc, err);
        !           391:        }
        !           392:
        !           393:        rfcomm_session_free(rs);
        !           394: }
        !           395:
        !           396: static void *
        !           397: rfcomm_session_newconn(void *arg, struct sockaddr_bt *laddr,
        !           398:                                struct sockaddr_bt *raddr)
        !           399: {
        !           400:        struct rfcomm_session *new, *rs = arg;
        !           401:
        !           402:        DPRINTF("New Connection\n");
        !           403:
        !           404:        /*
        !           405:         * Incoming session connect request. We should return a new
        !           406:         * session pointer if this is acceptable. The L2CAP layer
        !           407:         * passes local and remote addresses, which we must check as
        !           408:         * only one RFCOMM session is allowed between any two devices
        !           409:         */
        !           410:        new = rfcomm_session_lookup(laddr, raddr);
        !           411:        if (new != NULL)
        !           412:                return NULL;
        !           413:
        !           414:        new = rfcomm_session_alloc(&rfcomm_session_active, laddr);
        !           415:        if (new == NULL)
        !           416:                return NULL;
        !           417:
        !           418:        new->rs_mtu = rs->rs_mtu;
        !           419:        new->rs_state = RFCOMM_SESSION_WAIT_CONNECT;
        !           420:
        !           421:        /*
        !           422:         * schedule an expiry so that if nothing comes of it we
        !           423:         * can punt.
        !           424:         */
        !           425:        timeout_add(&new->rs_timeout, rfcomm_mcc_timeout * hz);
        !           426:
        !           427:        return new->rs_l2cap;
        !           428: }
        !           429:
        !           430: static void
        !           431: rfcomm_session_complete(void *arg, int count)
        !           432: {
        !           433:        struct rfcomm_session *rs = arg;
        !           434:        struct rfcomm_credit *credit;
        !           435:        struct rfcomm_dlc *dlc;
        !           436:
        !           437:        /*
        !           438:         * count L2CAP packets are 'complete', meaning that they are cleared
        !           439:         * our buffers (for best effort) or arrived safe (for guaranteed) so
        !           440:         * we can take it off our list and pass the message on, so that
        !           441:         * eventually the data can be removed from the sockbuf
        !           442:         */
        !           443:        while (count-- > 0) {
        !           444:                credit = SIMPLEQ_FIRST(&rs->rs_credits);
        !           445: #ifdef DIAGNOSTIC
        !           446:                if (credit == NULL) {
        !           447:                        printf("%s: too many packets completed!\n", __func__);
        !           448:                        break;
        !           449:                }
        !           450: #endif
        !           451:                dlc = credit->rc_dlc;
        !           452:                if (dlc != NULL) {
        !           453:                        dlc->rd_pending--;
        !           454:                        (*dlc->rd_proto->complete)
        !           455:                                        (dlc->rd_upper, credit->rc_len);
        !           456:
        !           457:                        /*
        !           458:                         * if not using credit flow control, we may push
        !           459:                         * more data now
        !           460:                         */
        !           461:                        if ((rs->rs_flags & RFCOMM_SESSION_CFC) == 0
        !           462:                            && dlc->rd_state == RFCOMM_DLC_OPEN) {
        !           463:                                rfcomm_dlc_start(dlc);
        !           464:                        }
        !           465:
        !           466:                        /*
        !           467:                         * When shutdown is indicated, we are just waiting to
        !           468:                         * clear outgoing data.
        !           469:                         */
        !           470:                        if ((dlc->rd_flags & RFCOMM_DLC_SHUTDOWN)
        !           471:                            && dlc->rd_txbuf == NULL && dlc->rd_pending == 0) {
        !           472:                                dlc->rd_state = RFCOMM_DLC_WAIT_DISCONNECT;
        !           473:                                rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC,
        !           474:                                                            dlc->rd_dlci);
        !           475:                                timeout_add(&dlc->rd_timeout,
        !           476:                                    rfcomm_ack_timeout * hz);
        !           477:                        }
        !           478:                }
        !           479:
        !           480:                SIMPLEQ_REMOVE_HEAD(&rs->rs_credits, rc_next);
        !           481:                pool_put(&rfcomm_credit_pool, credit);
        !           482:        }
        !           483:
        !           484:        /*
        !           485:         * If session is closed, we are just waiting to clear the queue
        !           486:         */
        !           487:        if (rs->rs_state == RFCOMM_SESSION_CLOSED) {
        !           488:                if (SIMPLEQ_EMPTY(&rs->rs_credits))
        !           489:                        l2cap_disconnect(rs->rs_l2cap, 0);
        !           490:        }
        !           491: }
        !           492:
        !           493: /*
        !           494:  * Link Mode changed
        !           495:  *
        !           496:  * This is called when a mode change is complete. Proceed with connections
        !           497:  * where appropriate, or pass the new mode to any active DLCs.
        !           498:  */
        !           499: static void
        !           500: rfcomm_session_linkmode(void *arg, int new)
        !           501: {
        !           502:        struct rfcomm_session *rs = arg;
        !           503:        struct rfcomm_dlc *dlc, *next;
        !           504:        int err, mode = 0;
        !           505:
        !           506:        DPRINTF("auth %s, encrypt %s, secure %s\n",
        !           507:                (new & L2CAP_LM_AUTH ? "on" : "off"),
        !           508:                (new & L2CAP_LM_ENCRYPT ? "on" : "off"),
        !           509:                (new & L2CAP_LM_SECURE ? "on" : "off"));
        !           510:
        !           511:        if (new & L2CAP_LM_AUTH)
        !           512:                mode |= RFCOMM_LM_AUTH;
        !           513:
        !           514:        if (new & L2CAP_LM_ENCRYPT)
        !           515:                mode |= RFCOMM_LM_ENCRYPT;
        !           516:
        !           517:        if (new & L2CAP_LM_SECURE)
        !           518:                mode |= RFCOMM_LM_SECURE;
        !           519:
        !           520:        next = LIST_FIRST(&rs->rs_dlcs);
        !           521:        while ((dlc = next) != NULL) {
        !           522:                next = LIST_NEXT(dlc, rd_next);
        !           523:
        !           524:                switch (dlc->rd_state) {
        !           525:                case RFCOMM_DLC_WAIT_SEND_SABM: /* we are connecting */
        !           526:                        if ((mode & dlc->rd_mode) != dlc->rd_mode) {
        !           527:                                rfcomm_dlc_close(dlc, ECONNABORTED);
        !           528:                        } else {
        !           529:                                err = rfcomm_session_send_frame(rs,
        !           530:                                            RFCOMM_FRAME_SABM, dlc->rd_dlci);
        !           531:                                if (err) {
        !           532:                                        rfcomm_dlc_close(dlc, err);
        !           533:                                } else {
        !           534:                                        dlc->rd_state = RFCOMM_DLC_WAIT_RECV_UA;
        !           535:                                        timeout_add(&dlc->rd_timeout,
        !           536:                                            rfcomm_ack_timeout * hz);
        !           537:                                        break;
        !           538:                                }
        !           539:                        }
        !           540:
        !           541:                        /*
        !           542:                         * If we aborted the connection and there are no more DLCs
        !           543:                         * on the session, it is our responsibility to disconnect.
        !           544:                         */
        !           545:                        if (!LIST_EMPTY(&rs->rs_dlcs))
        !           546:                                break;
        !           547:
        !           548:                        rs->rs_state = RFCOMM_SESSION_WAIT_DISCONNECT;
        !           549:                        rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC, 0);
        !           550:                        timeout_add(&rs->rs_timeout, rfcomm_ack_timeout * hz);
        !           551:                        break;
        !           552:
        !           553:                case RFCOMM_DLC_WAIT_SEND_UA: /* they are connecting */
        !           554:                        if ((mode & dlc->rd_mode) != dlc->rd_mode) {
        !           555:                                rfcomm_session_send_frame(rs,
        !           556:                                            RFCOMM_FRAME_DM, dlc->rd_dlci);
        !           557:                                rfcomm_dlc_close(dlc, ECONNABORTED);
        !           558:                                break;
        !           559:                        }
        !           560:
        !           561:                        err = rfcomm_session_send_frame(rs,
        !           562:                                            RFCOMM_FRAME_UA, dlc->rd_dlci);
        !           563:                        if (err) {
        !           564:                                rfcomm_session_send_frame(rs,
        !           565:                                                RFCOMM_FRAME_DM, dlc->rd_dlci);
        !           566:                                rfcomm_dlc_close(dlc, err);
        !           567:                                break;
        !           568:                        }
        !           569:
        !           570:                        err = rfcomm_dlc_open(dlc);
        !           571:                        if (err) {
        !           572:                                rfcomm_session_send_frame(rs,
        !           573:                                                RFCOMM_FRAME_DM, dlc->rd_dlci);
        !           574:                                rfcomm_dlc_close(dlc, err);
        !           575:                                break;
        !           576:                        }
        !           577:
        !           578:                        break;
        !           579:
        !           580:                case RFCOMM_DLC_WAIT_RECV_UA:
        !           581:                case RFCOMM_DLC_OPEN: /* already established */
        !           582:                        (*dlc->rd_proto->linkmode)(dlc->rd_upper, mode);
        !           583:                        break;
        !           584:
        !           585:                default:
        !           586:                        break;
        !           587:                }
        !           588:        }
        !           589: }
        !           590:
        !           591: /*
        !           592:  * Receive data from L2CAP layer for session. There is always exactly one
        !           593:  * RFCOMM frame contained in each L2CAP frame.
        !           594:  */
        !           595: static void
        !           596: rfcomm_session_input(void *arg, struct mbuf *m)
        !           597: {
        !           598:        struct rfcomm_session *rs = arg;
        !           599:        int dlci, len, type, pf;
        !           600:        uint8_t fcs, b;
        !           601:
        !           602:        KASSERT(m != NULL);
        !           603:        KASSERT(rs != NULL);
        !           604:
        !           605:        /*
        !           606:         * UIH frames: FCS is only calculated on address and control fields
        !           607:         * For other frames: FCS is calculated on address, control and length
        !           608:         * Length may extend to two octets
        !           609:         */
        !           610:        fcs = 0xff;
        !           611:
        !           612:        if (m->m_pkthdr.len < 4) {
        !           613:                DPRINTF("short frame (%d), discarded\n", m->m_pkthdr.len);
        !           614:                goto done;
        !           615:        }
        !           616:
        !           617:        /* address - one octet */
        !           618:        m_copydata(m, 0, 1, &b);
        !           619:        m_adj(m, 1);
        !           620:        fcs = FCS(fcs, b);
        !           621:        dlci = RFCOMM_DLCI(b);
        !           622:
        !           623:        /* control - one octet */
        !           624:        m_copydata(m, 0, 1, &b);
        !           625:        m_adj(m, 1);
        !           626:        fcs = FCS(fcs, b);
        !           627:        type = RFCOMM_TYPE(b);
        !           628:        pf = RFCOMM_PF(b);
        !           629:
        !           630:        /* length - may be two octets */
        !           631:        m_copydata(m, 0, 1, &b);
        !           632:        m_adj(m, 1);
        !           633:        if (type != RFCOMM_FRAME_UIH)
        !           634:                fcs = FCS(fcs, b);
        !           635:        len = (b >> 1) & 0x7f;
        !           636:
        !           637:        if (RFCOMM_EA(b) == 0) {
        !           638:                if (m->m_pkthdr.len < 2) {
        !           639:                        DPRINTF("short frame (%d, EA = 0), discarded\n",
        !           640:                                m->m_pkthdr.len);
        !           641:                        goto done;
        !           642:                }
        !           643:
        !           644:                m_copydata(m, 0, 1, &b);
        !           645:                m_adj(m, 1);
        !           646:                if (type != RFCOMM_FRAME_UIH)
        !           647:                        fcs = FCS(fcs, b);
        !           648:
        !           649:                len |= (b << 7);
        !           650:        }
        !           651:
        !           652:        /* FCS byte is last octet in frame */
        !           653:        m_copydata(m, m->m_pkthdr.len - 1, 1, &b);
        !           654:        m_adj(m, -1);
        !           655:        fcs = FCS(fcs, b);
        !           656:
        !           657:        if (fcs != 0xcf) {
        !           658:                DPRINTF("Bad FCS value (%#2.2x), frame discarded\n", fcs);
        !           659:                goto done;
        !           660:        }
        !           661:
        !           662:        DPRINTFN(10, "dlci %d, type %2.2x, len = %d\n", dlci, type, len);
        !           663:
        !           664:        switch (type) {
        !           665:        case RFCOMM_FRAME_SABM:
        !           666:                if (pf)
        !           667:                        rfcomm_session_recv_sabm(rs, dlci);
        !           668:                break;
        !           669:
        !           670:        case RFCOMM_FRAME_DISC:
        !           671:                if (pf)
        !           672:                        rfcomm_session_recv_disc(rs, dlci);
        !           673:                break;
        !           674:
        !           675:        case RFCOMM_FRAME_UA:
        !           676:                if (pf)
        !           677:                        rfcomm_session_recv_ua(rs, dlci);
        !           678:                break;
        !           679:
        !           680:        case RFCOMM_FRAME_DM:
        !           681:                rfcomm_session_recv_dm(rs, dlci);
        !           682:                break;
        !           683:
        !           684:        case RFCOMM_FRAME_UIH:
        !           685:                rfcomm_session_recv_uih(rs, dlci, pf, m, len);
        !           686:                return; /* (no release) */
        !           687:
        !           688:        default:
        !           689:                UNKNOWN(type);
        !           690:                break;
        !           691:        }
        !           692:
        !           693: done:
        !           694:        m_freem(m);
        !           695: }
        !           696:
        !           697: /***********************************************************************
        !           698:  *
        !           699:  *     RFCOMM Session receive processing
        !           700:  */
        !           701:
        !           702: /*
        !           703:  * rfcomm_session_recv_sabm(rfcomm_session, dlci)
        !           704:  *
        !           705:  * Set Asyncrhonous Balanced Mode - open the channel.
        !           706:  */
        !           707: static void
        !           708: rfcomm_session_recv_sabm(struct rfcomm_session *rs, int dlci)
        !           709: {
        !           710:        struct rfcomm_dlc *dlc;
        !           711:        int err;
        !           712:
        !           713:        DPRINTFN(5, "SABM(%d)\n", dlci);
        !           714:
        !           715:        if (dlci == 0) {        /* Open Session */
        !           716:                rs->rs_state = RFCOMM_SESSION_OPEN;
        !           717:                rfcomm_session_send_frame(rs, RFCOMM_FRAME_UA, 0);
        !           718:                LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next) {
        !           719:                        if (dlc->rd_state == RFCOMM_DLC_WAIT_SESSION)
        !           720:                                rfcomm_dlc_connect(dlc);
        !           721:                }
        !           722:                return;
        !           723:        }
        !           724:
        !           725:        if (rs->rs_state != RFCOMM_SESSION_OPEN) {
        !           726:                DPRINTF("session was not even open!\n");
        !           727:                return;
        !           728:        }
        !           729:
        !           730:        /* validate direction bit */
        !           731:        if ((IS_INITIATOR(rs) && !RFCOMM_DIRECTION(dlci))
        !           732:            || (!IS_INITIATOR(rs) && RFCOMM_DIRECTION(dlci))) {
        !           733:                DPRINTF("Invalid direction bit on DLCI\n");
        !           734:                return;
        !           735:        }
        !           736:
        !           737:        /*
        !           738:         * look for our DLC - this may exist if we received PN
        !           739:         * already, or we may have to fabricate a new one.
        !           740:         */
        !           741:        dlc = rfcomm_dlc_lookup(rs, dlci);
        !           742:        if (dlc == NULL) {
        !           743:                dlc = rfcomm_dlc_newconn(rs, dlci);
        !           744:                if (dlc == NULL)
        !           745:                        return; /* (DM is sent) */
        !           746:        }
        !           747:
        !           748:        /*
        !           749:         * ..but if this DLC is not waiting to connect, they did
        !           750:         * something wrong, ignore it.
        !           751:         */
        !           752:        if (dlc->rd_state != RFCOMM_DLC_WAIT_CONNECT)
        !           753:                return;
        !           754:
        !           755:        /* set link mode */
        !           756:        err = rfcomm_dlc_setmode(dlc);
        !           757:        if (err == EINPROGRESS) {
        !           758:                dlc->rd_state = RFCOMM_DLC_WAIT_SEND_UA;
        !           759:                (*dlc->rd_proto->connecting)(dlc->rd_upper);
        !           760:                return;
        !           761:        }
        !           762:        if (err)
        !           763:                goto close;
        !           764:
        !           765:        err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_UA, dlci);
        !           766:        if (err)
        !           767:                goto close;
        !           768:
        !           769:        /* and mark it open */
        !           770:        err = rfcomm_dlc_open(dlc);
        !           771:        if (err)
        !           772:                goto close;
        !           773:
        !           774:        return;
        !           775:
        !           776: close:
        !           777:        rfcomm_dlc_close(dlc, err);
        !           778: }
        !           779:
        !           780: /*
        !           781:  * Receive Disconnect Command
        !           782:  */
        !           783: static void
        !           784: rfcomm_session_recv_disc(struct rfcomm_session *rs, int dlci)
        !           785: {
        !           786:        struct rfcomm_dlc *dlc;
        !           787:
        !           788:        DPRINTFN(5, "DISC(%d)\n", dlci);
        !           789:
        !           790:        if (dlci == 0) {
        !           791:                /*
        !           792:                 * Disconnect Session
        !           793:                 *
        !           794:                 * We set the session state to CLOSED so that when
        !           795:                 * the UA frame is clear the session will be closed
        !           796:                 * automatically. We wont bother to close any DLC's
        !           797:                 * just yet as there should be none. In the unlikely
        !           798:                 * event that something is left, it will get flushed
        !           799:                 * out as the session goes down.
        !           800:                 */
        !           801:                rfcomm_session_send_frame(rs, RFCOMM_FRAME_UA, 0);
        !           802:                rs->rs_state = RFCOMM_SESSION_CLOSED;
        !           803:                return;
        !           804:        }
        !           805:
        !           806:        dlc = rfcomm_dlc_lookup(rs, dlci);
        !           807:        if (dlc == NULL) {
        !           808:                rfcomm_session_send_frame(rs, RFCOMM_FRAME_DM, dlci);
        !           809:                return;
        !           810:        }
        !           811:
        !           812:        rfcomm_dlc_close(dlc, ECONNRESET);
        !           813:        rfcomm_session_send_frame(rs, RFCOMM_FRAME_UA, dlci);
        !           814: }
        !           815:
        !           816: /*
        !           817:  * Receive Unnumbered Acknowledgement Response
        !           818:  *
        !           819:  * This should be a response to a DISC or SABM frame that we
        !           820:  * have previously sent. If unexpected, ignore it.
        !           821:  */
        !           822: static void
        !           823: rfcomm_session_recv_ua(struct rfcomm_session *rs, int dlci)
        !           824: {
        !           825:        struct rfcomm_dlc *dlc;
        !           826:
        !           827:        DPRINTFN(5, "UA(%d)\n", dlci);
        !           828:
        !           829:        if (dlci == 0) {
        !           830:                switch (rs->rs_state) {
        !           831:                case RFCOMM_SESSION_WAIT_CONNECT:       /* We sent SABM */
        !           832:                        timeout_del(&rs->rs_timeout);
        !           833:                        rs->rs_state = RFCOMM_SESSION_OPEN;
        !           834:                        LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next) {
        !           835:                                if (dlc->rd_state == RFCOMM_DLC_WAIT_SESSION)
        !           836:                                        rfcomm_dlc_connect(dlc);
        !           837:                        }
        !           838:                        break;
        !           839:
        !           840:                case RFCOMM_SESSION_WAIT_DISCONNECT:    /* We sent DISC */
        !           841:                        timeout_del(&rs->rs_timeout);
        !           842:                        rs->rs_state = RFCOMM_SESSION_CLOSED;
        !           843:                        l2cap_disconnect(rs->rs_l2cap, 0);
        !           844:                        break;
        !           845:
        !           846:                default:
        !           847:                        DPRINTF("Received spurious UA(0)!\n");
        !           848:                        break;
        !           849:                }
        !           850:
        !           851:                return;
        !           852:        }
        !           853:
        !           854:        /*
        !           855:         * If we have no DLC on this dlci, we may have aborted
        !           856:         * without shutting down properly, so check if the session
        !           857:         * needs disconnecting.
        !           858:         */
        !           859:        dlc = rfcomm_dlc_lookup(rs, dlci);
        !           860:        if (dlc == NULL)
        !           861:                goto check;
        !           862:
        !           863:        switch (dlc->rd_state) {
        !           864:        case RFCOMM_DLC_WAIT_RECV_UA:           /* We sent SABM */
        !           865:                rfcomm_dlc_open(dlc);
        !           866:                return;
        !           867:
        !           868:        case RFCOMM_DLC_WAIT_DISCONNECT:        /* We sent DISC */
        !           869:                rfcomm_dlc_close(dlc, 0);
        !           870:                break;
        !           871:
        !           872:        default:
        !           873:                DPRINTF("Received spurious UA(%d)!\n", dlci);
        !           874:                return;
        !           875:        }
        !           876:
        !           877: check: /* last one out turns out the light */
        !           878:        if (LIST_EMPTY(&rs->rs_dlcs)) {
        !           879:                rs->rs_state = RFCOMM_SESSION_WAIT_DISCONNECT;
        !           880:                rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC, 0);
        !           881:                timeout_add(&rs->rs_timeout, rfcomm_ack_timeout * hz);
        !           882:        }
        !           883: }
        !           884:
        !           885: /*
        !           886:  * Receive Disconnected Mode Response
        !           887:  *
        !           888:  * If this does not apply to a known DLC then we may ignore it.
        !           889:  */
        !           890: static void
        !           891: rfcomm_session_recv_dm(struct rfcomm_session *rs, int dlci)
        !           892: {
        !           893:        struct rfcomm_dlc *dlc;
        !           894:
        !           895:        DPRINTFN(5, "DM(%d)\n", dlci);
        !           896:
        !           897:        dlc = rfcomm_dlc_lookup(rs, dlci);
        !           898:        if (dlc == NULL)
        !           899:                return;
        !           900:
        !           901:        if (dlc->rd_state == RFCOMM_DLC_WAIT_CONNECT)
        !           902:                rfcomm_dlc_close(dlc, ECONNREFUSED);
        !           903:        else
        !           904:                rfcomm_dlc_close(dlc, ECONNRESET);
        !           905: }
        !           906:
        !           907: /*
        !           908:  * Receive Unnumbered Information with Header check (MCC or data packet)
        !           909:  */
        !           910: static void
        !           911: rfcomm_session_recv_uih(struct rfcomm_session *rs, int dlci,
        !           912:                        int pf, struct mbuf *m, int len)
        !           913: {
        !           914:        struct rfcomm_dlc *dlc;
        !           915:        uint8_t credits = 0;
        !           916:
        !           917:        DPRINTFN(10, "UIH(%d)\n", dlci);
        !           918:
        !           919:        if (dlci == 0) {
        !           920:                rfcomm_session_recv_mcc(rs, m);
        !           921:                return;
        !           922:        }
        !           923:
        !           924:        if (m->m_pkthdr.len != len + pf) {
        !           925:                DPRINTF("Bad Frame Length (%d), frame discarded\n",
        !           926:                            m->m_pkthdr.len);
        !           927:
        !           928:                goto discard;
        !           929:        }
        !           930:
        !           931:        dlc = rfcomm_dlc_lookup(rs, dlci);
        !           932:        if (dlc == NULL) {
        !           933:                DPRINTF("UIH received for non existent DLC, discarded\n");
        !           934:                rfcomm_session_send_frame(rs, RFCOMM_FRAME_DM, dlci);
        !           935:                goto discard;
        !           936:        }
        !           937:
        !           938:        if (dlc->rd_state != RFCOMM_DLC_OPEN) {
        !           939:                DPRINTF("non-open DLC (state = %d), discarded\n",
        !           940:                                dlc->rd_state);
        !           941:                goto discard;
        !           942:        }
        !           943:
        !           944:        /* if PF is set, credits were included */
        !           945:        if (rs->rs_flags & RFCOMM_SESSION_CFC) {
        !           946:                if (pf != 0) {
        !           947:                        if (m->m_pkthdr.len < sizeof(credits)) {
        !           948:                                DPRINTF("Bad PF value, UIH discarded\n");
        !           949:                                goto discard;
        !           950:                        }
        !           951:
        !           952:                        m_copydata(m, 0, sizeof(credits), &credits);
        !           953:                        m_adj(m, sizeof(credits));
        !           954:
        !           955:                        dlc->rd_txcred += credits;
        !           956:
        !           957:                        if (credits > 0 && dlc->rd_txbuf != NULL)
        !           958:                                rfcomm_dlc_start(dlc);
        !           959:                }
        !           960:
        !           961:                if (len == 0)
        !           962:                        goto discard;
        !           963:
        !           964:                if (dlc->rd_rxcred == 0) {
        !           965:                        DPRINTF("Credit limit reached, UIH discarded\n");
        !           966:                        goto discard;
        !           967:                }
        !           968:
        !           969:                if (len > dlc->rd_rxsize) {
        !           970:                        DPRINTF("UIH frame exceeds rxsize, discarded\n");
        !           971:                        goto discard;
        !           972:                }
        !           973:
        !           974:                dlc->rd_rxcred--;
        !           975:                dlc->rd_rxsize -= len;
        !           976:        }
        !           977:
        !           978:        (*dlc->rd_proto->input)(dlc->rd_upper, m);
        !           979:        return;
        !           980:
        !           981: discard:
        !           982:        m_freem(m);
        !           983: }
        !           984:
        !           985: /*
        !           986:  * Receive Multiplexer Control Command
        !           987:  */
        !           988: static void
        !           989: rfcomm_session_recv_mcc(struct rfcomm_session *rs, struct mbuf *m)
        !           990: {
        !           991:        int type, cr, len;
        !           992:        uint8_t b;
        !           993:
        !           994:        /*
        !           995:         * Extract MCC header.
        !           996:         *
        !           997:         * Fields are variable length using extension bit = 1 to signify the
        !           998:         * last octet in the sequence.
        !           999:         *
        !          1000:         * Only single octet types are defined in TS 07.10/RFCOMM spec
        !          1001:         *
        !          1002:         * Length can realistically only use 15 bits (max RFCOMM MTU)
        !          1003:         */
        !          1004:        if (m->m_pkthdr.len < sizeof(b)) {
        !          1005:                DPRINTF("Short MCC header, discarded\n");
        !          1006:                goto release;
        !          1007:        }
        !          1008:
        !          1009:        m_copydata(m, 0, sizeof(b), &b);
        !          1010:        m_adj(m, sizeof(b));
        !          1011:
        !          1012:        if (RFCOMM_EA(b) == 0) {        /* verify no extensions */
        !          1013:                DPRINTF("MCC type EA = 0, discarded\n");
        !          1014:                goto release;
        !          1015:        }
        !          1016:
        !          1017:        type = RFCOMM_MCC_TYPE(b);
        !          1018:        cr = RFCOMM_CR(b);
        !          1019:
        !          1020:        len = 0;
        !          1021:        do {
        !          1022:                if (m->m_pkthdr.len < sizeof(b)) {
        !          1023:                        DPRINTF("Short MCC header, discarded\n");
        !          1024:                        goto release;
        !          1025:                }
        !          1026:
        !          1027:                m_copydata(m, 0, sizeof(b), &b);
        !          1028:                m_adj(m, sizeof(b));
        !          1029:
        !          1030:                len = (len << 7) | (b >> 1);
        !          1031:                len = min(len, RFCOMM_MTU_MAX);
        !          1032:        } while (RFCOMM_EA(b) == 0);
        !          1033:
        !          1034:        if (len != m->m_pkthdr.len) {
        !          1035:                DPRINTF("Incorrect MCC length, discarded\n");
        !          1036:                goto release;
        !          1037:        }
        !          1038:
        !          1039:        DPRINTFN(2, "MCC %s type %2.2x (%d bytes)\n",
        !          1040:                (cr ? "command" : "response"), type, len);
        !          1041:
        !          1042:        /*
        !          1043:         * pass to command handler
        !          1044:         */
        !          1045:        switch(type) {
        !          1046:        case RFCOMM_MCC_TEST:   /* Test */
        !          1047:                rfcomm_session_recv_mcc_test(rs, cr, m);
        !          1048:                break;
        !          1049:
        !          1050:        case RFCOMM_MCC_FCON:   /* Flow Control On */
        !          1051:                rfcomm_session_recv_mcc_fcon(rs, cr);
        !          1052:                break;
        !          1053:
        !          1054:        case RFCOMM_MCC_FCOFF:  /* Flow Control Off */
        !          1055:                rfcomm_session_recv_mcc_fcoff(rs, cr);
        !          1056:                break;
        !          1057:
        !          1058:        case RFCOMM_MCC_MSC:    /* Modem Status Command */
        !          1059:                rfcomm_session_recv_mcc_msc(rs, cr, m);
        !          1060:                break;
        !          1061:
        !          1062:        case RFCOMM_MCC_RPN:    /* Remote Port Negotiation */
        !          1063:                rfcomm_session_recv_mcc_rpn(rs, cr, m);
        !          1064:                break;
        !          1065:
        !          1066:        case RFCOMM_MCC_RLS:    /* Remote Line Status */
        !          1067:                rfcomm_session_recv_mcc_rls(rs, cr, m);
        !          1068:                break;
        !          1069:
        !          1070:        case RFCOMM_MCC_PN:     /* Parameter Negotiation */
        !          1071:                rfcomm_session_recv_mcc_pn(rs, cr, m);
        !          1072:                break;
        !          1073:
        !          1074:        case RFCOMM_MCC_NSC:    /* Non Supported Command */
        !          1075:                rfcomm_session_recv_mcc_nsc(rs, cr, m);
        !          1076:                break;
        !          1077:
        !          1078:        default:
        !          1079:                b = RFCOMM_MKMCC_TYPE(cr, type);
        !          1080:                rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_NSC, &b, sizeof(b));
        !          1081:        }
        !          1082:
        !          1083: release:
        !          1084:        m_freem(m);
        !          1085: }
        !          1086:
        !          1087: /*
        !          1088:  * process TEST command/response
        !          1089:  */
        !          1090: static void
        !          1091: rfcomm_session_recv_mcc_test(struct rfcomm_session *rs, int cr, struct mbuf *m)
        !          1092: {
        !          1093:        void *data;
        !          1094:        int len;
        !          1095:
        !          1096:        if (cr == 0)    /* ignore ack */
        !          1097:                return;
        !          1098:
        !          1099:        /*
        !          1100:         * we must send all the data they included back as is
        !          1101:         */
        !          1102:
        !          1103:        len = m->m_pkthdr.len;
        !          1104:        if (len > RFCOMM_MTU_MAX)
        !          1105:                return;
        !          1106:
        !          1107:        data = malloc(len, M_BLUETOOTH, M_NOWAIT);
        !          1108:        if (data == NULL)
        !          1109:                return;
        !          1110:
        !          1111:        m_copydata(m, 0, len, data);
        !          1112:        rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_TEST, data, len);
        !          1113:        free(data, M_BLUETOOTH);
        !          1114: }
        !          1115:
        !          1116: /*
        !          1117:  * process Flow Control ON command/response
        !          1118:  */
        !          1119: static void
        !          1120: rfcomm_session_recv_mcc_fcon(struct rfcomm_session *rs, int cr)
        !          1121: {
        !          1122:
        !          1123:        if (cr == 0)    /* ignore ack */
        !          1124:                return;
        !          1125:
        !          1126:        rs->rs_flags |= RFCOMM_SESSION_RFC;
        !          1127:        rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_FCON, NULL, 0);
        !          1128: }
        !          1129:
        !          1130: /*
        !          1131:  * process Flow Control OFF command/response
        !          1132:  */
        !          1133: static void
        !          1134: rfcomm_session_recv_mcc_fcoff(struct rfcomm_session *rs, int cr)
        !          1135: {
        !          1136:
        !          1137:        if (cr == 0)    /* ignore ack */
        !          1138:                return;
        !          1139:
        !          1140:        rs->rs_flags &= ~RFCOMM_SESSION_RFC;
        !          1141:        rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_FCOFF, NULL, 0);
        !          1142: }
        !          1143:
        !          1144: /*
        !          1145:  * process Modem Status Command command/response
        !          1146:  */
        !          1147: static void
        !          1148: rfcomm_session_recv_mcc_msc(struct rfcomm_session *rs, int cr, struct mbuf *m)
        !          1149: {
        !          1150:        struct rfcomm_mcc_msc msc;      /* (3 octets) */
        !          1151:        struct rfcomm_dlc *dlc;
        !          1152:        int len = 0;
        !          1153:
        !          1154:        /* [ADDRESS] */
        !          1155:        if (m->m_pkthdr.len < sizeof(msc.address))
        !          1156:                return;
        !          1157:
        !          1158:        m_copydata(m, 0, sizeof(msc.address), &msc.address);
        !          1159:        m_adj(m, sizeof(msc.address));
        !          1160:        len += sizeof(msc.address);
        !          1161:
        !          1162:        dlc = rfcomm_dlc_lookup(rs, RFCOMM_DLCI(msc.address));
        !          1163:
        !          1164:        if (cr == 0) {  /* ignore acks */
        !          1165:                if (dlc != NULL)
        !          1166:                        timeout_del(&dlc->rd_timeout);
        !          1167:
        !          1168:                return;
        !          1169:        }
        !          1170:
        !          1171:        if (dlc == NULL) {
        !          1172:                rfcomm_session_send_frame(rs, RFCOMM_FRAME_DM,
        !          1173:                                                RFCOMM_DLCI(msc.address));
        !          1174:                return;
        !          1175:        }
        !          1176:
        !          1177:        /* [SIGNALS] */
        !          1178:        if (m->m_pkthdr.len < sizeof(msc.modem))
        !          1179:                return;
        !          1180:
        !          1181:        m_copydata(m, 0, sizeof(msc.modem), &msc.modem);
        !          1182:        m_adj(m, sizeof(msc.modem));
        !          1183:        len += sizeof(msc.modem);
        !          1184:
        !          1185:        dlc->rd_rmodem = msc.modem;
        !          1186:        /* XXX how do we signal this upstream? */
        !          1187:
        !          1188:        if (RFCOMM_EA(msc.modem) == 0) {
        !          1189:                if (m->m_pkthdr.len < sizeof(msc.brk))
        !          1190:                        return;
        !          1191:
        !          1192:                m_copydata(m, 0, sizeof(msc.brk), &msc.brk);
        !          1193:                m_adj(m, sizeof(msc.brk));
        !          1194:                len += sizeof(msc.brk);
        !          1195:
        !          1196:                /* XXX how do we signal this upstream? */
        !          1197:        }
        !          1198:
        !          1199:        rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_MSC, &msc, len);
        !          1200: }
        !          1201:
        !          1202: /*
        !          1203:  * process Remote Port Negotiation command/response
        !          1204:  */
        !          1205: static void
        !          1206: rfcomm_session_recv_mcc_rpn(struct rfcomm_session *rs, int cr, struct mbuf *m)
        !          1207: {
        !          1208:        struct rfcomm_mcc_rpn rpn;
        !          1209:        uint16_t mask;
        !          1210:
        !          1211:        if (cr == 0)    /* ignore ack */
        !          1212:                return;
        !          1213:
        !          1214:        /* default values */
        !          1215:        rpn.bit_rate = RFCOMM_RPN_BR_9600;
        !          1216:        rpn.line_settings = RFCOMM_RPN_8_N_1;
        !          1217:        rpn.flow_control = RFCOMM_RPN_FLOW_NONE;
        !          1218:        rpn.xon_char = RFCOMM_RPN_XON_CHAR;
        !          1219:        rpn.xoff_char = RFCOMM_RPN_XOFF_CHAR;
        !          1220:
        !          1221:        if (m->m_pkthdr.len == sizeof(rpn)) {
        !          1222:                m_copydata(m, 0, sizeof(rpn), (caddr_t)&rpn);
        !          1223:                rpn.param_mask = RFCOMM_RPN_PM_ALL;
        !          1224:        } else if (m->m_pkthdr.len == 1) {
        !          1225:                m_copydata(m, 0, 1, (caddr_t)&rpn);
        !          1226:                rpn.param_mask = letoh16(rpn.param_mask);
        !          1227:        } else {
        !          1228:                DPRINTF("Bad RPN length (%d)\n", m->m_pkthdr.len);
        !          1229:                return;
        !          1230:        }
        !          1231:
        !          1232:        mask = 0;
        !          1233:
        !          1234:        if (rpn.param_mask & RFCOMM_RPN_PM_RATE)
        !          1235:                mask |= RFCOMM_RPN_PM_RATE;
        !          1236:
        !          1237:        if (rpn.param_mask & RFCOMM_RPN_PM_DATA
        !          1238:            && RFCOMM_RPN_DATA_BITS(rpn.line_settings) == RFCOMM_RPN_DATA_8)
        !          1239:                mask |= RFCOMM_RPN_PM_DATA;
        !          1240:
        !          1241:        if (rpn.param_mask & RFCOMM_RPN_PM_STOP
        !          1242:            && RFCOMM_RPN_STOP_BITS(rpn.line_settings) == RFCOMM_RPN_STOP_1)
        !          1243:                mask |= RFCOMM_RPN_PM_STOP;
        !          1244:
        !          1245:        if (rpn.param_mask & RFCOMM_RPN_PM_PARITY
        !          1246:            && RFCOMM_RPN_PARITY(rpn.line_settings) == RFCOMM_RPN_PARITY_NONE)
        !          1247:                mask |= RFCOMM_RPN_PM_PARITY;
        !          1248:
        !          1249:        if (rpn.param_mask & RFCOMM_RPN_PM_XON
        !          1250:            && rpn.xon_char == RFCOMM_RPN_XON_CHAR)
        !          1251:                mask |= RFCOMM_RPN_PM_XON;
        !          1252:
        !          1253:        if (rpn.param_mask & RFCOMM_RPN_PM_XOFF
        !          1254:            && rpn.xoff_char == RFCOMM_RPN_XOFF_CHAR)
        !          1255:                mask |= RFCOMM_RPN_PM_XOFF;
        !          1256:
        !          1257:        if (rpn.param_mask & RFCOMM_RPN_PM_FLOW
        !          1258:            && rpn.flow_control == RFCOMM_RPN_FLOW_NONE)
        !          1259:                mask |= RFCOMM_RPN_PM_FLOW;
        !          1260:
        !          1261:        rpn.param_mask = htole16(mask);
        !          1262:
        !          1263:        rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_RPN, &rpn, sizeof(rpn));
        !          1264: }
        !          1265:
        !          1266: /*
        !          1267:  * process Remote Line Status command/response
        !          1268:  */
        !          1269: static void
        !          1270: rfcomm_session_recv_mcc_rls(struct rfcomm_session *rs, int cr, struct mbuf *m)
        !          1271: {
        !          1272:        struct rfcomm_mcc_rls rls;
        !          1273:
        !          1274:        if (cr == 0)    /* ignore ack */
        !          1275:                return;
        !          1276:
        !          1277:        if (m->m_pkthdr.len != sizeof(rls)) {
        !          1278:                DPRINTF("Bad RLS length %d\n", m->m_pkthdr.len);
        !          1279:                return;
        !          1280:        }
        !          1281:
        !          1282:        m_copydata(m, 0, sizeof(rls), (caddr_t)&rls);
        !          1283:
        !          1284:        /*
        !          1285:         * So far as I can tell, we just send back what
        !          1286:         * they sent us. This signifies errors that seem
        !          1287:         * irrelevent for RFCOMM over L2CAP.
        !          1288:         */
        !          1289:        rls.address |= 0x03;    /* EA = 1, CR = 1 */
        !          1290:        rls.status &= 0x0f;     /* only 4 bits valid */
        !          1291:
        !          1292:        rfcomm_session_send_mcc(rs, 0, RFCOMM_MCC_RLS, &rls, sizeof(rls));
        !          1293: }
        !          1294:
        !          1295: /*
        !          1296:  * process Parameter Negotiation command/response
        !          1297:  */
        !          1298: static void
        !          1299: rfcomm_session_recv_mcc_pn(struct rfcomm_session *rs, int cr, struct mbuf *m)
        !          1300: {
        !          1301:        struct rfcomm_dlc *dlc;
        !          1302:        struct rfcomm_mcc_pn pn;
        !          1303:        int err;
        !          1304:
        !          1305:        if (m->m_pkthdr.len != sizeof(pn)) {
        !          1306:                DPRINTF("Bad PN length %d\n", m->m_pkthdr.len);
        !          1307:                return;
        !          1308:        }
        !          1309:
        !          1310:        m_copydata(m, 0, sizeof(pn), (caddr_t)&pn);
        !          1311:
        !          1312:        pn.dlci &= 0x3f;
        !          1313:        pn.mtu = letoh16(pn.mtu);
        !          1314:
        !          1315:        dlc = rfcomm_dlc_lookup(rs, pn.dlci);
        !          1316:        if (cr) {       /* Command */
        !          1317:                /*
        !          1318:                 * If there is no DLC present, this is a new
        !          1319:                 * connection so attempt to make one
        !          1320:                 */
        !          1321:                if (dlc == NULL) {
        !          1322:                        dlc = rfcomm_dlc_newconn(rs, pn.dlci);
        !          1323:                        if (dlc == NULL)
        !          1324:                                return; /* (DM is sent) */
        !          1325:                }
        !          1326:
        !          1327:                /* accept any valid MTU, and offer it back */
        !          1328:                pn.mtu = min(pn.mtu, RFCOMM_MTU_MAX);
        !          1329:                pn.mtu = min(pn.mtu, rs->rs_mtu);
        !          1330:                pn.mtu = max(pn.mtu, RFCOMM_MTU_MIN);
        !          1331:                dlc->rd_mtu = pn.mtu;
        !          1332:                pn.mtu = htole16(pn.mtu);
        !          1333:
        !          1334:                /* credits are only set before DLC is open */
        !          1335:                if (dlc->rd_state == RFCOMM_DLC_WAIT_CONNECT
        !          1336:                    && (pn.flow_control & 0xf0) == 0xf0) {
        !          1337:                        rs->rs_flags |= RFCOMM_SESSION_CFC;
        !          1338:                        dlc->rd_txcred = pn.credits & 0x07;
        !          1339:
        !          1340:                        dlc->rd_rxcred = (dlc->rd_rxsize / dlc->rd_mtu);
        !          1341:                        dlc->rd_rxcred = min(dlc->rd_rxcred,
        !          1342:                                                RFCOMM_CREDITS_DEFAULT);
        !          1343:
        !          1344:                        pn.flow_control = 0xe0;
        !          1345:                        pn.credits = dlc->rd_rxcred;
        !          1346:                } else {
        !          1347:                        pn.flow_control = 0x00;
        !          1348:                        pn.credits = 0x00;
        !          1349:                }
        !          1350:
        !          1351:                /* unused fields must be ignored and set to zero */
        !          1352:                pn.ack_timer = 0;
        !          1353:                pn.max_retrans = 0;
        !          1354:
        !          1355:                /* send our response */
        !          1356:                err = rfcomm_session_send_mcc(rs, 0,
        !          1357:                                        RFCOMM_MCC_PN, &pn, sizeof(pn));
        !          1358:                if (err)
        !          1359:                        goto close;
        !          1360:
        !          1361:        } else {        /* Response */
        !          1362:                /* ignore responses with no matching DLC */
        !          1363:                if (dlc == NULL)
        !          1364:                        return;
        !          1365:
        !          1366:                timeout_del(&dlc->rd_timeout);
        !          1367:
        !          1368:                if (pn.mtu > RFCOMM_MTU_MAX || pn.mtu > dlc->rd_mtu) {
        !          1369:                        dlc->rd_state = RFCOMM_DLC_WAIT_DISCONNECT;
        !          1370:                        err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC,
        !          1371:                                                        pn.dlci);
        !          1372:                        if (err)
        !          1373:                                goto close;
        !          1374:
        !          1375:                        timeout_add(&dlc->rd_timeout,
        !          1376:                            rfcomm_ack_timeout * hz);
        !          1377:                        return;
        !          1378:                }
        !          1379:                dlc->rd_mtu = pn.mtu;
        !          1380:
        !          1381:                /* if DLC is not waiting to connect, we are done */
        !          1382:                if (dlc->rd_state != RFCOMM_DLC_WAIT_CONNECT)
        !          1383:                        return;
        !          1384:
        !          1385:                /* set initial credits according to RFCOMM spec */
        !          1386:                if ((pn.flow_control & 0xf0) == 0xe0) {
        !          1387:                        rs->rs_flags |= RFCOMM_SESSION_CFC;
        !          1388:                        dlc->rd_txcred = (pn.credits & 0x07);
        !          1389:                }
        !          1390:
        !          1391:                timeout_add(&dlc->rd_timeout, rfcomm_ack_timeout * hz);
        !          1392:
        !          1393:                /* set link mode */
        !          1394:                err = rfcomm_dlc_setmode(dlc);
        !          1395:                if (err == EINPROGRESS) {
        !          1396:                        dlc->rd_state = RFCOMM_DLC_WAIT_SEND_SABM;
        !          1397:                        (*dlc->rd_proto->connecting)(dlc->rd_upper);
        !          1398:                        return;
        !          1399:                }
        !          1400:                if (err)
        !          1401:                        goto close;
        !          1402:
        !          1403:                /* we can proceed now */
        !          1404:                err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_SABM, pn.dlci);
        !          1405:                if (err)
        !          1406:                        goto close;
        !          1407:
        !          1408:                dlc->rd_state = RFCOMM_DLC_WAIT_RECV_UA;
        !          1409:        }
        !          1410:        return;
        !          1411:
        !          1412: close:
        !          1413:        rfcomm_dlc_close(dlc, err);
        !          1414: }
        !          1415:
        !          1416: /*
        !          1417:  * process Non Supported Command command/response
        !          1418:  */
        !          1419: static void
        !          1420: rfcomm_session_recv_mcc_nsc(struct rfcomm_session *rs,
        !          1421:     int cr, struct mbuf *m)
        !          1422: {
        !          1423:        struct rfcomm_dlc *dlc, *next;
        !          1424:
        !          1425:        /*
        !          1426:         * Since we did nothing that is not mandatory,
        !          1427:         * we just abort the whole session..
        !          1428:         */
        !          1429:
        !          1430:        next = LIST_FIRST(&rs->rs_dlcs);
        !          1431:        while ((dlc = next) != NULL) {
        !          1432:                next = LIST_NEXT(dlc, rd_next);
        !          1433:                rfcomm_dlc_close(dlc, ECONNABORTED);
        !          1434:        }
        !          1435:
        !          1436:        rfcomm_session_free(rs);
        !          1437: }
        !          1438:
        !          1439: /***********************************************************************
        !          1440:  *
        !          1441:  *     RFCOMM Session outward frame/uih/mcc building
        !          1442:  */
        !          1443:
        !          1444: /*
        !          1445:  * SABM/DISC/DM/UA frames are all minimal and mostly identical.
        !          1446:  */
        !          1447: int
        !          1448: rfcomm_session_send_frame(struct rfcomm_session *rs, int type, int dlci)
        !          1449: {
        !          1450:        struct rfcomm_cmd_hdr *hdr;
        !          1451:        struct rfcomm_credit *credit;
        !          1452:        struct mbuf *m;
        !          1453:        uint8_t fcs, cr;
        !          1454:
        !          1455:        credit = pool_get(&rfcomm_credit_pool, PR_NOWAIT);
        !          1456:        if (credit == NULL)
        !          1457:                return ENOMEM;
        !          1458:
        !          1459:        m = m_gethdr(M_DONTWAIT, MT_DATA);
        !          1460:        if (m == NULL) {
        !          1461:                pool_put(&rfcomm_credit_pool, credit);
        !          1462:                return ENOMEM;
        !          1463:        }
        !          1464:
        !          1465:        /*
        !          1466:         * The CR (command/response) bit identifies the frame either as a
        !          1467:         * commmand or a response and is used along with the DLCI to form
        !          1468:         * the address. Commands contain the non-initiator address, whereas
        !          1469:         * responses contain the initiator address, so the CR value is
        !          1470:         * also dependent on the session direction.
        !          1471:         */
        !          1472:        if (type == RFCOMM_FRAME_UA || type == RFCOMM_FRAME_DM)
        !          1473:                cr = IS_INITIATOR(rs) ? 0 : 1;
        !          1474:        else
        !          1475:                cr = IS_INITIATOR(rs) ? 1 : 0;
        !          1476:
        !          1477:        hdr = mtod(m, struct rfcomm_cmd_hdr *);
        !          1478:        hdr->address = RFCOMM_MKADDRESS(cr, dlci);
        !          1479:        hdr->control = RFCOMM_MKCONTROL(type, 1);   /* PF = 1 */
        !          1480:        hdr->length = (0x00 << 1) | 0x01;           /* len = 0x00, EA = 1 */
        !          1481:
        !          1482:        fcs = 0xff;
        !          1483:        fcs = FCS(fcs, hdr->address);
        !          1484:        fcs = FCS(fcs, hdr->control);
        !          1485:        fcs = FCS(fcs, hdr->length);
        !          1486:        fcs = 0xff - fcs;       /* ones complement */
        !          1487:        hdr->fcs = fcs;
        !          1488:
        !          1489:        m->m_pkthdr.len = m->m_len = sizeof(struct rfcomm_cmd_hdr);
        !          1490:
        !          1491:        /* empty credit note */
        !          1492:        credit->rc_dlc = NULL;
        !          1493:        credit->rc_len = m->m_pkthdr.len;
        !          1494:        SIMPLEQ_INSERT_TAIL(&rs->rs_credits, credit, rc_next);
        !          1495:
        !          1496:        DPRINTFN(5, "dlci %d type %2.2x (%d bytes, fcs=%#2.2x)\n",
        !          1497:                dlci, type, m->m_pkthdr.len, fcs);
        !          1498:
        !          1499:        return l2cap_send(rs->rs_l2cap, m);
        !          1500: }
        !          1501:
        !          1502: /*
        !          1503:  * rfcomm_session_send_uih(rfcomm_session, rfcomm_dlc, credits, mbuf)
        !          1504:  *
        !          1505:  * UIH frame is per DLC data or Multiplexer Control Commands
        !          1506:  * when no DLC is given. Data mbuf is optional (just credits
        !          1507:  * will be sent in that case)
        !          1508:  */
        !          1509: int
        !          1510: rfcomm_session_send_uih(struct rfcomm_session *rs, struct rfcomm_dlc *dlc,
        !          1511:                        int credits, struct mbuf *m)
        !          1512: {
        !          1513:        struct rfcomm_credit *credit;
        !          1514:        struct mbuf *m0 = NULL;
        !          1515:        int err, len;
        !          1516:        uint8_t fcs, *hdr;
        !          1517:
        !          1518:        KASSERT(rs != NULL);
        !          1519:
        !          1520:        len = (m == NULL) ? 0 : m->m_pkthdr.len;
        !          1521:        KASSERT(!(credits == 0 && len == 0));
        !          1522:
        !          1523:        /*
        !          1524:         * Make a credit note for the completion notification
        !          1525:         */
        !          1526:        credit = pool_get(&rfcomm_credit_pool, PR_NOWAIT);
        !          1527:        if (credit == NULL)
        !          1528:                goto nomem;
        !          1529:
        !          1530:        credit->rc_len = len;
        !          1531:        credit->rc_dlc = dlc;
        !          1532:
        !          1533:        /*
        !          1534:         * Wrap UIH frame information around payload.
        !          1535:         *
        !          1536:         * [ADDRESS] [CONTROL] [LENGTH] [CREDITS] [...] [FCS]
        !          1537:         *
        !          1538:         * Address is one octet.
        !          1539:         * Control is one octet.
        !          1540:         * Length is one or two octets.
        !          1541:         * Credits may be one octet.
        !          1542:         *
        !          1543:         * FCS is one octet and calculated on address and
        !          1544:         *      control octets only.
        !          1545:         *
        !          1546:         * If there are credits to be sent, we will set the PF
        !          1547:         * flag and include them in the frame.
        !          1548:         */
        !          1549:        m0 = m_gethdr(M_DONTWAIT, MT_DATA);
        !          1550:        if (m0 == NULL)
        !          1551:                goto nomem;
        !          1552:
        !          1553:        MH_ALIGN(m0, 5);        /* (max 5 header octets) */
        !          1554:        hdr = mtod(m0, uint8_t *);
        !          1555:
        !          1556:        /* CR bit is set according to the initiator of the session */
        !          1557:        *hdr = RFCOMM_MKADDRESS((IS_INITIATOR(rs) ? 1 : 0),
        !          1558:                                (dlc ? dlc->rd_dlci : 0));
        !          1559:        fcs = FCS(0xff, *hdr);
        !          1560:        hdr++;
        !          1561:
        !          1562:        /* PF bit is set if credits are being sent */
        !          1563:        *hdr = RFCOMM_MKCONTROL(RFCOMM_FRAME_UIH, (credits > 0 ? 1 : 0));
        !          1564:        fcs = FCS(fcs, *hdr);
        !          1565:        hdr++;
        !          1566:
        !          1567:        if (len < (1 << 7)) {
        !          1568:                *hdr++ = ((len << 1) & 0xfe) | 0x01;    /* 7 bits, EA = 1 */
        !          1569:        } else {
        !          1570:                *hdr++ = ((len << 1) & 0xfe);           /* 7 bits, EA = 0 */
        !          1571:                *hdr++ = ((len >> 7) & 0xff);           /* 8 bits, no EA */
        !          1572:        }
        !          1573:
        !          1574:        if (credits > 0)
        !          1575:                *hdr++ = (uint8_t)credits;
        !          1576:
        !          1577:        m0->m_len = hdr - mtod(m0, uint8_t *);
        !          1578:
        !          1579:        /* Append payload */
        !          1580:        m0->m_next = m;
        !          1581:        m = NULL;
        !          1582:
        !          1583:        m0->m_pkthdr.len = m0->m_len + len;
        !          1584:
        !          1585:        /* Append FCS */
        !          1586:        fcs = 0xff - fcs;       /* ones complement */
        !          1587:        len = m0->m_pkthdr.len;
        !          1588:        m_copyback(m0, len, sizeof(fcs), &fcs);
        !          1589:        if (m0->m_pkthdr.len != len + sizeof(fcs))
        !          1590:                goto nomem;
        !          1591:
        !          1592:        DPRINTFN(10, "dlci %d, pktlen %d (%d data, %d credits), fcs=%#2.2x\n",
        !          1593:                dlc ? dlc->rd_dlci : 0, m0->m_pkthdr.len, credit->rc_len,
        !          1594:                credits, fcs);
        !          1595:
        !          1596:        /*
        !          1597:         * UIH frame ready to go..
        !          1598:         */
        !          1599:        err = l2cap_send(rs->rs_l2cap, m0);
        !          1600:        if (err)
        !          1601:                goto fail;
        !          1602:
        !          1603:        SIMPLEQ_INSERT_TAIL(&rs->rs_credits, credit, rc_next);
        !          1604:        return 0;
        !          1605:
        !          1606: nomem:
        !          1607:        err = ENOMEM;
        !          1608:
        !          1609:        if (m0 != NULL)
        !          1610:                m_freem(m0);
        !          1611:
        !          1612:        if (m != NULL)
        !          1613:                m_freem(m);
        !          1614:
        !          1615: fail:
        !          1616:        if (credit != NULL)
        !          1617:                pool_put(&rfcomm_credit_pool, credit);
        !          1618:
        !          1619:        return err;
        !          1620: }
        !          1621:
        !          1622: /*
        !          1623:  * send Multiplexer Control Command (or Response) on session
        !          1624:  */
        !          1625: int
        !          1626: rfcomm_session_send_mcc(struct rfcomm_session *rs, int cr,
        !          1627:                        uint8_t type, void *data, int len)
        !          1628: {
        !          1629:        struct mbuf *m;
        !          1630:        uint8_t *hdr;
        !          1631:        int hlen;
        !          1632:
        !          1633:        m = m_gethdr(M_DONTWAIT, MT_DATA);
        !          1634:        if (m == NULL)
        !          1635:                return ENOMEM;
        !          1636:
        !          1637:        hdr = mtod(m, uint8_t *);
        !          1638:
        !          1639:        /*
        !          1640:         * Technically the type field can extend past one octet, but none
        !          1641:         * currently defined will do that.
        !          1642:         */
        !          1643:        *hdr++ = RFCOMM_MKMCC_TYPE(cr, type);
        !          1644:
        !          1645:        /*
        !          1646:         * In the frame, the max length size is 2 octets (15 bits) whereas
        !          1647:         * no max length size is specified for MCC commands. We must allow
        !          1648:         * for 3 octets since for MCC frames we use 7 bits + EA in each.
        !          1649:         *
        !          1650:         * Only test data can possibly be that big.
        !          1651:         *
        !          1652:         * XXX Should we check this against the MTU?
        !          1653:         */
        !          1654:        if (len < (1 << 7)) {
        !          1655:                *hdr++ = ((len << 1) & 0xfe) | 0x01;    /* 7 bits, EA = 1 */
        !          1656:        } else if (len < (1 << 14)) {
        !          1657:                *hdr++ = ((len << 1) & 0xfe);           /* 7 bits, EA = 0 */
        !          1658:                *hdr++ = ((len >> 6) & 0xfe) | 0x01;    /* 7 bits, EA = 1 */
        !          1659:        } else if (len < (1 << 15)) {
        !          1660:                *hdr++ = ((len << 1) & 0xfe);           /* 7 bits, EA = 0 */
        !          1661:                *hdr++ = ((len >> 6) & 0xfe);           /* 7 bits, EA = 0 */
        !          1662:                *hdr++ = ((len >> 13) & 0x02) | 0x01;   /* 1 bit,  EA = 1 */
        !          1663:        } else {
        !          1664:                DPRINTF("incredible length! (%d)\n", len);
        !          1665:                m_freem(m);
        !          1666:                return EMSGSIZE;
        !          1667:        }
        !          1668:
        !          1669:        /*
        !          1670:         * add command data (to same mbuf if possible)
        !          1671:         */
        !          1672:        hlen = hdr - mtod(m, uint8_t *);
        !          1673:
        !          1674:        if (len > 0) {
        !          1675:                m->m_pkthdr.len = m->m_len = MHLEN;
        !          1676:                m_copyback(m, hlen, len, data);
        !          1677:                if (m->m_pkthdr.len != max(MHLEN, hlen + len)) {
        !          1678:                        m_freem(m);
        !          1679:                        return ENOMEM;
        !          1680:                }
        !          1681:        }
        !          1682:
        !          1683:        m->m_pkthdr.len = hlen + len;
        !          1684:        m->m_len = min(MHLEN, m->m_pkthdr.len);
        !          1685:
        !          1686:        DPRINTFN(5, "%s type %2.2x len %d\n",
        !          1687:                (cr ? "command" : "response"), type, m->m_pkthdr.len);
        !          1688:
        !          1689:        return rfcomm_session_send_uih(rs, NULL, 0, m);
        !          1690: }

CVSweb