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

Annotation of sys/netbt/rfcomm_dlc.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: rfcomm_dlc.c,v 1.1 2007/06/01 02:46:12 uwe Exp $      */
                      2: /*     $NetBSD: rfcomm_dlc.c,v 1.3 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:
                     43: #include <netbt/bluetooth.h>
                     44: #include <netbt/hci.h>
                     45: #include <netbt/l2cap.h>
                     46: #include <netbt/rfcomm.h>
                     47:
                     48: /*
                     49:  * rfcomm_dlc_lookup(rfcomm_session, dlci)
                     50:  *
                     51:  * Find DLC on session with matching dlci
                     52:  */
                     53: struct rfcomm_dlc *
                     54: rfcomm_dlc_lookup(struct rfcomm_session *rs, int dlci)
                     55: {
                     56:        struct rfcomm_dlc *dlc;
                     57:
                     58:        LIST_FOREACH(dlc, &rs->rs_dlcs, rd_next) {
                     59:                if (dlc->rd_dlci == dlci)
                     60:                        break;
                     61:        }
                     62:
                     63:        return dlc;
                     64: }
                     65:
                     66: /*
                     67:  * rfcomm_dlc_newconn(rfcomm_session, dlci)
                     68:  *
                     69:  * handle a new dlc request (since its called from a couple of places)
                     70:  */
                     71: struct rfcomm_dlc *
                     72: rfcomm_dlc_newconn(struct rfcomm_session *rs, int dlci)
                     73: {
                     74:        struct rfcomm_session *ls;
                     75:        struct rfcomm_dlc *new, *dlc, *any, *best;
                     76:        struct sockaddr_bt laddr, raddr, addr;
                     77:        int chan;
                     78:
                     79:        /*
                     80:         * Search amongst the listening DLC community for the best match for
                     81:         * address & channel. We keep listening DLC's hanging on listening
                     82:         * sessions in a last first order, so scan the entire bunch and keep
                     83:         * a note of the best address and BDADDR_ANY matches in order to find
                     84:         * the oldest and most specific match.
                     85:         */
                     86:        l2cap_sockaddr(rs->rs_l2cap, &laddr);
                     87:        l2cap_peeraddr(rs->rs_l2cap, &raddr);
                     88:        chan = RFCOMM_CHANNEL(dlci);
                     89:        new = NULL;
                     90:
                     91:        any = best = NULL;
                     92:        LIST_FOREACH(ls, &rfcomm_session_listen, rs_next) {
                     93:                l2cap_sockaddr(ls->rs_l2cap, &addr);
                     94:
                     95:                if (addr.bt_psm != laddr.bt_psm)
                     96:                        continue;
                     97:
                     98:                if (bdaddr_same(&laddr.bt_bdaddr, &addr.bt_bdaddr)) {
                     99:                        LIST_FOREACH(dlc, &ls->rs_dlcs, rd_next) {
                    100:                                if (dlc->rd_laddr.bt_channel == chan)
                    101:                                        best = dlc;
                    102:                        }
                    103:                }
                    104:
                    105:                if (bdaddr_any(&addr.bt_bdaddr)) {
                    106:                        LIST_FOREACH(dlc, &ls->rs_dlcs, rd_next) {
                    107:                                if (dlc->rd_laddr.bt_channel == chan)
                    108:                                        any = dlc;
                    109:                        }
                    110:                }
                    111:        }
                    112:
                    113:        dlc = best ? best : any;
                    114:
                    115:        /* XXX
                    116:         * Note that if this fails, we could have missed a chance to open
                    117:         * a connection - really need to rewrite the strategy for storing
                    118:         * listening DLC's so all can be checked in turn..
                    119:         */
                    120:        if (dlc != NULL)
                    121:                new = (*dlc->rd_proto->newconn)(dlc->rd_upper, &laddr, &raddr);
                    122:
                    123:        if (new == NULL) {
                    124:                rfcomm_session_send_frame(rs, RFCOMM_FRAME_DM, dlci);
                    125:                return NULL;
                    126:        }
                    127:
                    128:        new->rd_dlci = dlci;
                    129:        new->rd_mtu = rfcomm_mtu_default;
                    130:        new->rd_mode = dlc->rd_mode;
                    131:
                    132:        memcpy(&new->rd_laddr, &laddr, sizeof(struct sockaddr_bt));
                    133:        new->rd_laddr.bt_channel = chan;
                    134:
                    135:        memcpy(&new->rd_raddr, &raddr, sizeof(struct sockaddr_bt));
                    136:        new->rd_raddr.bt_channel = chan;
                    137:
                    138:        new->rd_session = rs;
                    139:        new->rd_state = RFCOMM_DLC_WAIT_CONNECT;
                    140:        LIST_INSERT_HEAD(&rs->rs_dlcs, new, rd_next);
                    141:
                    142:        return new;
                    143: }
                    144:
                    145: /*
                    146:  * rfcomm_dlc_close(dlc, error)
                    147:  *
                    148:  * detach DLC from session and clean up
                    149:  */
                    150: void
                    151: rfcomm_dlc_close(struct rfcomm_dlc *dlc, int err)
                    152: {
                    153:        struct rfcomm_session *rs;
                    154:        struct rfcomm_credit *credit;
                    155:
                    156:        KASSERT(dlc->rd_state != RFCOMM_DLC_CLOSED);
                    157:
                    158:        /* Clear credit history */
                    159:        rs = dlc->rd_session;
                    160:        SIMPLEQ_FOREACH(credit, &rs->rs_credits, rc_next)
                    161:                if (credit->rc_dlc == dlc)
                    162:                        credit->rc_dlc = NULL;
                    163:
                    164:        timeout_del(&dlc->rd_timeout);
                    165:
                    166:        LIST_REMOVE(dlc, rd_next);
                    167:        dlc->rd_session = NULL;
                    168:        dlc->rd_state = RFCOMM_DLC_CLOSED;
                    169:
                    170:        (*dlc->rd_proto->disconnected)(dlc->rd_upper, err);
                    171:
                    172:        /*
                    173:         * It is the responsibility of the party who sends the last
                    174:         * DISC(dlci) to disconnect the session, but we will schedule
                    175:         * an expiry just in case that doesnt happen..
                    176:         */
                    177:        if (LIST_EMPTY(&rs->rs_dlcs)) {
                    178:                if (rs->rs_state == RFCOMM_SESSION_LISTEN)
                    179:                        rfcomm_session_free(rs);
                    180:                else
                    181:                        timeout_add(&rs->rs_timeout,
                    182:                            rfcomm_ack_timeout * hz);
                    183:        }
                    184: }
                    185:
                    186: /*
                    187:  * rfcomm_dlc_timeout(dlc)
                    188:  *
                    189:  * DLC timeout function is schedUled when we sent any of SABM,
                    190:  * DISC, MCC_MSC, or MCC_PN and should be cancelled when we get
                    191:  * the relevant response. There is nothing to do but shut this
                    192:  * DLC down.
                    193:  */
                    194: void
                    195: rfcomm_dlc_timeout(void *arg)
                    196: {
                    197:        struct rfcomm_dlc *dlc = arg;
                    198:        int s;
                    199:
                    200:        s = splsoftnet();
                    201:
                    202:        if (dlc->rd_state != RFCOMM_DLC_CLOSED)
                    203:                rfcomm_dlc_close(dlc, ETIMEDOUT);
                    204:        else if (dlc->rd_flags & RFCOMM_DLC_DETACH)
                    205:                free(dlc, M_BLUETOOTH);
                    206:
                    207:        splx(s);
                    208: }
                    209:
                    210: /*
                    211:  * rfcomm_dlc_setmode(rfcomm_dlc)
                    212:  *
                    213:  * Set link mode for DLC.  This is only called when the session is
                    214:  * already open, so we don't need to worry about any previous mode
                    215:  * settings.
                    216:  */
                    217: int
                    218: rfcomm_dlc_setmode(struct rfcomm_dlc *dlc)
                    219: {
                    220:        int mode = 0;
                    221:
                    222:        KASSERT(dlc->rd_session != NULL);
                    223:        KASSERT(dlc->rd_session->rs_state == RFCOMM_SESSION_OPEN);
                    224:
                    225:        DPRINTF("dlci %d, auth %s, encrypt %s, secure %s\n", dlc->rd_dlci,
                    226:                (dlc->rd_mode & RFCOMM_LM_AUTH ? "yes" : "no"),
                    227:                (dlc->rd_mode & RFCOMM_LM_ENCRYPT ? "yes" : "no"),
                    228:                (dlc->rd_mode & RFCOMM_LM_SECURE ? "yes" : "no"));
                    229:
                    230:        if (dlc->rd_mode & RFCOMM_LM_AUTH)
                    231:                mode |= L2CAP_LM_AUTH;
                    232:
                    233:        if (dlc->rd_mode & RFCOMM_LM_ENCRYPT)
                    234:                mode |= L2CAP_LM_ENCRYPT;
                    235:
                    236:        if (dlc->rd_mode & RFCOMM_LM_SECURE)
                    237:                mode |= L2CAP_LM_SECURE;
                    238:
                    239:        return l2cap_setopt(dlc->rd_session->rs_l2cap, SO_L2CAP_LM, &mode);
                    240: }
                    241:
                    242: /*
                    243:  * rfcomm_dlc_connect(rfcomm_dlc)
                    244:  *
                    245:  * initiate DLC connection (session is already connected)
                    246:  */
                    247: int
                    248: rfcomm_dlc_connect(struct rfcomm_dlc *dlc)
                    249: {
                    250:        struct rfcomm_mcc_pn pn;
                    251:        int err = 0;
                    252:
                    253:        KASSERT(dlc->rd_session != NULL);
                    254:        KASSERT(dlc->rd_session->rs_state == RFCOMM_SESSION_OPEN);
                    255:        KASSERT(dlc->rd_state == RFCOMM_DLC_WAIT_SESSION);
                    256:
                    257:        /*
                    258:         * If we have not already sent a PN on the session, we must send
                    259:         * a PN to negotiate Credit Flow Control, and this setting will
                    260:         * apply to all future connections for this session. We ask for
                    261:         * this every time, in order to establish initial credits.
                    262:         */
                    263:        memset(&pn, 0, sizeof(pn));
                    264:        pn.dlci = dlc->rd_dlci;
                    265:        pn.priority = dlc->rd_dlci | 0x07;
                    266:        pn.mtu = htole16(dlc->rd_mtu);
                    267:
                    268:        pn.flow_control = 0xf0;
                    269:        dlc->rd_rxcred = (dlc->rd_rxsize / dlc->rd_mtu);
                    270:        dlc->rd_rxcred = min(dlc->rd_rxcred, RFCOMM_CREDITS_DEFAULT);
                    271:        pn.credits = dlc->rd_rxcred;
                    272:
                    273:        err = rfcomm_session_send_mcc(dlc->rd_session, 1,
                    274:                                        RFCOMM_MCC_PN, &pn, sizeof(pn));
                    275:        if (err)
                    276:                return err;
                    277:
                    278:        dlc->rd_state = RFCOMM_DLC_WAIT_CONNECT;
                    279:        timeout_add(&dlc->rd_timeout, rfcomm_mcc_timeout * hz);
                    280:
                    281:        return 0;
                    282: }
                    283:
                    284: /*
                    285:  * rfcomm_dlc_open(rfcomm_dlc)
                    286:  *
                    287:  * send "Modem Status Command" and mark DLC as open.
                    288:  */
                    289: int
                    290: rfcomm_dlc_open(struct rfcomm_dlc *dlc)
                    291: {
                    292:        struct rfcomm_mcc_msc msc;
                    293:        int err;
                    294:
                    295:        KASSERT(dlc->rd_session != NULL);
                    296:        KASSERT(dlc->rd_session->rs_state == RFCOMM_SESSION_OPEN);
                    297:
                    298:        memset(&msc, 0, sizeof(msc));
                    299:        msc.address = RFCOMM_MKADDRESS(1, dlc->rd_dlci);
                    300:        msc.modem = dlc->rd_lmodem & 0xfe;      /* EA = 0 */
                    301:        msc.brk =       0x00       | 0x01;      /* EA = 1 */
                    302:
                    303:        err = rfcomm_session_send_mcc(dlc->rd_session, 1,
                    304:                                RFCOMM_MCC_MSC, &msc, sizeof(msc));
                    305:        if (err)
                    306:                return err;
                    307:
                    308:        timeout_add(&dlc->rd_timeout, rfcomm_mcc_timeout * hz);
                    309:
                    310:        dlc->rd_state = RFCOMM_DLC_OPEN;
                    311:        (*dlc->rd_proto->connected)(dlc->rd_upper);
                    312:
                    313:        return 0;
                    314: }
                    315:
                    316: /*
                    317:  * rfcomm_dlc_start(rfcomm_dlc)
                    318:  *
                    319:  * Start sending data (and/or credits) for DLC. Our strategy is to
                    320:  * send anything we can down to the l2cap layer. When credits run
                    321:  * out, data will naturally bunch up. When not using credit flow
                    322:  * control, we limit the number of packets we have pending to reduce
                    323:  * flow control lag.
                    324:  * We should deal with channel priority somehow.
                    325:  */
                    326: void
                    327: rfcomm_dlc_start(struct rfcomm_dlc *dlc)
                    328: {
                    329:        struct rfcomm_session *rs = dlc->rd_session;
                    330:        struct mbuf *m;
                    331:        int len, credits;
                    332:
                    333:        KASSERT(rs != NULL);
                    334:        KASSERT(rs->rs_state == RFCOMM_SESSION_OPEN);
                    335:        KASSERT(dlc->rd_state == RFCOMM_DLC_OPEN);
                    336:
                    337:        for (;;) {
                    338:                credits = 0;
                    339:                len = dlc->rd_mtu;
                    340:                if (rs->rs_flags & RFCOMM_SESSION_CFC) {
                    341:                        credits = (dlc->rd_rxsize / dlc->rd_mtu);
                    342:                        credits -= dlc->rd_rxcred;
                    343:                        credits = min(credits, RFCOMM_CREDITS_MAX);
                    344:
                    345:                        if (credits > 0)
                    346:                                len--;
                    347:
                    348:                        if (dlc->rd_txcred == 0)
                    349:                                len = 0;
                    350:                } else {
                    351:                        if (rs->rs_flags & RFCOMM_SESSION_RFC)
                    352:                                break;
                    353:
                    354:                        if (dlc->rd_rmodem & RFCOMM_MSC_FC)
                    355:                                break;
                    356:
                    357:                        if (dlc->rd_pending > RFCOMM_CREDITS_DEFAULT)
                    358:                                break;
                    359:                }
                    360:
                    361:                if (dlc->rd_txbuf == NULL)
                    362:                        len = 0;
                    363:
                    364:                if (len == 0) {
                    365:                        if (credits == 0)
                    366:                                break;
                    367:
                    368:                        /*
                    369:                         * No need to send small numbers of credits on their
                    370:                         * own unless the other end hasn't many left.
                    371:                         */
                    372:                        if (credits < RFCOMM_CREDITS_DEFAULT
                    373:                            && dlc->rd_rxcred > RFCOMM_CREDITS_DEFAULT)
                    374:                                break;
                    375:
                    376:                        m = NULL;
                    377:                } else {
                    378:                        /*
                    379:                         * take what data we can from (front of) txbuf
                    380:                         */
                    381:                        m = dlc->rd_txbuf;
                    382:                        if (len < m->m_pkthdr.len) {
                    383:                                dlc->rd_txbuf = m_split(m, len, M_DONTWAIT);
                    384:                                if (dlc->rd_txbuf == NULL) {
                    385:                                        dlc->rd_txbuf = m;
                    386:                                        break;
                    387:                                }
                    388:                        } else {
                    389:                                dlc->rd_txbuf = NULL;
                    390:                                len = m->m_pkthdr.len;
                    391:                        }
                    392:                }
                    393:
                    394:                DPRINTFN(10, "dlci %d send %d bytes, %d credits, rxcred = %d\n",
                    395:                        dlc->rd_dlci, len, credits, dlc->rd_rxcred);
                    396:
                    397:                if (rfcomm_session_send_uih(rs, dlc, credits, m)) {
                    398:                        printf("%s: lost %d bytes on DLCI %d\n",
                    399:                                __func__, len, dlc->rd_dlci);
                    400:
                    401:                        break;
                    402:                }
                    403:
                    404:                dlc->rd_pending++;
                    405:
                    406:                if (rs->rs_flags & RFCOMM_SESSION_CFC) {
                    407:                        if (len > 0)
                    408:                                dlc->rd_txcred--;
                    409:
                    410:                        if (credits > 0)
                    411:                                dlc->rd_rxcred += credits;
                    412:                }
                    413:        }
                    414: }

CVSweb