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

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

1.1     ! nbrk        1: /*     $OpenBSD: rfcomm_upper.c,v 1.2 2007/06/26 10:30:05 tom Exp $    */
        !             2: /*     $NetBSD: rfcomm_upper.c,v 1.6 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:  *
        !            50:  *     RFCOMM DLC - Upper Protocol API
        !            51:  *
        !            52:  * Currently the only 'Port Emulation Entity' is the RFCOMM socket code
        !            53:  * but it is should be possible to provide a pseudo-device for a direct
        !            54:  * tty interface.
        !            55:  */
        !            56:
        !            57: /*
        !            58:  * rfcomm_attach(handle, proto, upper)
        !            59:  *
        !            60:  * attach a new RFCOMM DLC to handle, populate with reasonable defaults
        !            61:  */
        !            62: int
        !            63: rfcomm_attach(struct rfcomm_dlc **handle,
        !            64:                const struct btproto *proto, void *upper)
        !            65: {
        !            66:        struct rfcomm_dlc *dlc;
        !            67:
        !            68:        KASSERT(handle != NULL);
        !            69:        KASSERT(proto != NULL);
        !            70:        KASSERT(upper != NULL);
        !            71:
        !            72:        dlc = malloc(sizeof(struct rfcomm_dlc), M_BLUETOOTH, M_NOWAIT);
        !            73:        if (dlc == NULL)
        !            74:                return ENOMEM;
        !            75:        bzero(dlc, sizeof *dlc);
        !            76:
        !            77:        dlc->rd_state = RFCOMM_DLC_CLOSED;
        !            78:        dlc->rd_mtu = rfcomm_mtu_default;
        !            79:
        !            80:        dlc->rd_proto = proto;
        !            81:        dlc->rd_upper = upper;
        !            82:
        !            83:        dlc->rd_laddr.bt_len = sizeof(struct sockaddr_bt);
        !            84:        dlc->rd_laddr.bt_family = AF_BLUETOOTH;
        !            85:        dlc->rd_laddr.bt_psm = L2CAP_PSM_RFCOMM;
        !            86:
        !            87:        dlc->rd_raddr.bt_len = sizeof(struct sockaddr_bt);
        !            88:        dlc->rd_raddr.bt_family = AF_BLUETOOTH;
        !            89:        dlc->rd_raddr.bt_psm = L2CAP_PSM_RFCOMM;
        !            90:
        !            91:        dlc->rd_lmodem = RFCOMM_MSC_RTC | RFCOMM_MSC_RTR | RFCOMM_MSC_DV;
        !            92:
        !            93:        timeout_set(&dlc->rd_timeout, rfcomm_dlc_timeout, dlc);
        !            94:
        !            95:        *handle = dlc;
        !            96:        return 0;
        !            97: }
        !            98:
        !            99: /*
        !           100:  * rfcomm_bind(dlc, sockaddr)
        !           101:  *
        !           102:  * bind DLC to local address
        !           103:  */
        !           104: int
        !           105: rfcomm_bind(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
        !           106: {
        !           107:
        !           108:        memcpy(&dlc->rd_laddr, addr, sizeof(struct sockaddr_bt));
        !           109:        return 0;
        !           110: }
        !           111:
        !           112: /*
        !           113:  * rfcomm_sockaddr(dlc, sockaddr)
        !           114:  *
        !           115:  * return local address
        !           116:  */
        !           117: int
        !           118: rfcomm_sockaddr(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
        !           119: {
        !           120:
        !           121:        memcpy(addr, &dlc->rd_laddr, sizeof(struct sockaddr_bt));
        !           122:        return 0;
        !           123: }
        !           124:
        !           125: /*
        !           126:  * rfcomm_connect(dlc, sockaddr)
        !           127:  *
        !           128:  * Initiate connection of RFCOMM DLC to remote address.
        !           129:  */
        !           130: int
        !           131: rfcomm_connect(struct rfcomm_dlc *dlc, struct sockaddr_bt *dest)
        !           132: {
        !           133:        struct rfcomm_session *rs;
        !           134:        int err = 0;
        !           135:
        !           136:        if (dlc->rd_state != RFCOMM_DLC_CLOSED)
        !           137:                return EISCONN;
        !           138:
        !           139:        memcpy(&dlc->rd_raddr, dest, sizeof(struct sockaddr_bt));
        !           140:
        !           141:        if (dlc->rd_raddr.bt_channel < RFCOMM_CHANNEL_MIN
        !           142:            || dlc->rd_raddr.bt_channel > RFCOMM_CHANNEL_MAX
        !           143:            || bdaddr_any(&dlc->rd_raddr.bt_bdaddr))
        !           144:                return EDESTADDRREQ;
        !           145:
        !           146:        if (dlc->rd_raddr.bt_psm == L2CAP_PSM_ANY)
        !           147:                dlc->rd_raddr.bt_psm = L2CAP_PSM_RFCOMM;
        !           148:        else if (dlc->rd_raddr.bt_psm != L2CAP_PSM_RFCOMM
        !           149:            && (dlc->rd_raddr.bt_psm < 0x1001
        !           150:            || L2CAP_PSM_INVALID(dlc->rd_raddr.bt_psm)))
        !           151:                return EINVAL;
        !           152:
        !           153:        /*
        !           154:         * We are allowed only one RFCOMM session between any 2 Bluetooth
        !           155:         * devices, so see if there is a session already otherwise create
        !           156:         * one and set it connecting.
        !           157:         */
        !           158:        rs = rfcomm_session_lookup(&dlc->rd_laddr, &dlc->rd_raddr);
        !           159:        if (rs == NULL) {
        !           160:                rs = rfcomm_session_alloc(&rfcomm_session_active,
        !           161:                                                &dlc->rd_laddr);
        !           162:                if (rs == NULL)
        !           163:                        return ENOMEM;
        !           164:
        !           165:                rs->rs_flags |= RFCOMM_SESSION_INITIATOR;
        !           166:                rs->rs_state = RFCOMM_SESSION_WAIT_CONNECT;
        !           167:
        !           168:                err = l2cap_connect(rs->rs_l2cap, &dlc->rd_raddr);
        !           169:                if (err) {
        !           170:                        rfcomm_session_free(rs);
        !           171:                        return err;
        !           172:                }
        !           173:
        !           174:                /*
        !           175:                 * This session will start up automatically when its
        !           176:                 * L2CAP channel is connected.
        !           177:                 */
        !           178:        }
        !           179:
        !           180:        /* construct DLC */
        !           181:        dlc->rd_dlci = RFCOMM_MKDLCI(IS_INITIATOR(rs) ? 0:1, dest->bt_channel);
        !           182:        if (rfcomm_dlc_lookup(rs, dlc->rd_dlci))
        !           183:                return EBUSY;
        !           184:
        !           185:        l2cap_sockaddr(rs->rs_l2cap, &dlc->rd_laddr);
        !           186:
        !           187:        /*
        !           188:         * attach the DLC to the session and start it off
        !           189:         */
        !           190:        dlc->rd_session = rs;
        !           191:        dlc->rd_state = RFCOMM_DLC_WAIT_SESSION;
        !           192:        LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next);
        !           193:
        !           194:        if (rs->rs_state == RFCOMM_SESSION_OPEN)
        !           195:                err = rfcomm_dlc_connect(dlc);
        !           196:
        !           197:        return err;
        !           198: }
        !           199:
        !           200: /*
        !           201:  * rfcomm_peeraddr(dlc, sockaddr)
        !           202:  *
        !           203:  * return remote address
        !           204:  */
        !           205: int
        !           206: rfcomm_peeraddr(struct rfcomm_dlc *dlc, struct sockaddr_bt *addr)
        !           207: {
        !           208:
        !           209:        memcpy(addr, &dlc->rd_raddr, sizeof(struct sockaddr_bt));
        !           210:        return 0;
        !           211: }
        !           212:
        !           213: /*
        !           214:  * rfcomm_disconnect(dlc, linger)
        !           215:  *
        !           216:  * disconnect RFCOMM DLC
        !           217:  */
        !           218: int
        !           219: rfcomm_disconnect(struct rfcomm_dlc *dlc, int linger)
        !           220: {
        !           221:        struct rfcomm_session *rs = dlc->rd_session;
        !           222:        int err = 0;
        !           223:
        !           224:        KASSERT(dlc != NULL);
        !           225:
        !           226:        switch (dlc->rd_state) {
        !           227:        case RFCOMM_DLC_CLOSED:
        !           228:        case RFCOMM_DLC_LISTEN:
        !           229:                return EINVAL;
        !           230:
        !           231:        case RFCOMM_DLC_WAIT_SEND_UA:
        !           232:                err = rfcomm_session_send_frame(rs,
        !           233:                                RFCOMM_FRAME_DM, dlc->rd_dlci);
        !           234:
        !           235:                /* fall through */
        !           236:        case RFCOMM_DLC_WAIT_SESSION:
        !           237:        case RFCOMM_DLC_WAIT_CONNECT:
        !           238:        case RFCOMM_DLC_WAIT_SEND_SABM:
        !           239:                rfcomm_dlc_close(dlc, 0);
        !           240:                break;
        !           241:
        !           242:        case RFCOMM_DLC_OPEN:
        !           243:                if (dlc->rd_txbuf != NULL && linger != 0) {
        !           244:                        dlc->rd_flags |= RFCOMM_DLC_SHUTDOWN;
        !           245:                        break;
        !           246:                }
        !           247:
        !           248:                /* else fall through */
        !           249:        case RFCOMM_DLC_WAIT_RECV_UA:
        !           250:                dlc->rd_state = RFCOMM_DLC_WAIT_DISCONNECT;
        !           251:                err = rfcomm_session_send_frame(rs, RFCOMM_FRAME_DISC,
        !           252:                                                        dlc->rd_dlci);
        !           253:                timeout_add(&dlc->rd_timeout, rfcomm_ack_timeout * hz);
        !           254:                break;
        !           255:
        !           256:        case RFCOMM_DLC_WAIT_DISCONNECT:
        !           257:                err = EALREADY;
        !           258:                break;
        !           259:
        !           260:        default:
        !           261:                UNKNOWN(dlc->rd_state);
        !           262:                break;
        !           263:        }
        !           264:
        !           265:        return err;
        !           266: }
        !           267:
        !           268: /*
        !           269:  * rfcomm_detach(handle)
        !           270:  *
        !           271:  * detach RFCOMM DLC from handle
        !           272:  */
        !           273: int
        !           274: rfcomm_detach(struct rfcomm_dlc **handle)
        !           275: {
        !           276:        struct rfcomm_dlc *dlc = *handle;
        !           277:
        !           278:        if (dlc->rd_state != RFCOMM_DLC_CLOSED)
        !           279:                rfcomm_dlc_close(dlc, 0);
        !           280:
        !           281:        if (dlc->rd_txbuf != NULL) {
        !           282:                m_freem(dlc->rd_txbuf);
        !           283:                dlc->rd_txbuf = NULL;
        !           284:        }
        !           285:
        !           286:        dlc->rd_upper = NULL;
        !           287:        *handle = NULL;
        !           288:
        !           289:        /*
        !           290:         * If callout is invoking we can't free the DLC so
        !           291:         * mark it and let the callout release it.
        !           292:         */
        !           293:        if (timeout_triggered(&dlc->rd_timeout))
        !           294:                dlc->rd_flags |= RFCOMM_DLC_DETACH;
        !           295:        else
        !           296:                free(dlc, M_BLUETOOTH);
        !           297:
        !           298:        return 0;
        !           299: }
        !           300:
        !           301: /*
        !           302:  * rfcomm_listen(dlc)
        !           303:  *
        !           304:  * This DLC is a listener. We look for an existing listening session
        !           305:  * with a matching address to attach to or else create a new one on
        !           306:  * the listeners list.
        !           307:  */
        !           308: int
        !           309: rfcomm_listen(struct rfcomm_dlc *dlc)
        !           310: {
        !           311:        struct rfcomm_session *rs, *any, *best;
        !           312:        struct sockaddr_bt addr;
        !           313:        int err;
        !           314:
        !           315:        if (dlc->rd_state != RFCOMM_DLC_CLOSED)
        !           316:                return EISCONN;
        !           317:
        !           318:        if (dlc->rd_laddr.bt_channel < RFCOMM_CHANNEL_MIN
        !           319:            || dlc->rd_laddr.bt_channel > RFCOMM_CHANNEL_MAX)
        !           320:                return EADDRNOTAVAIL;
        !           321:
        !           322:        if (dlc->rd_laddr.bt_psm == L2CAP_PSM_ANY)
        !           323:                dlc->rd_laddr.bt_psm = L2CAP_PSM_RFCOMM;
        !           324:        else if (dlc->rd_laddr.bt_psm != L2CAP_PSM_RFCOMM
        !           325:            && (dlc->rd_laddr.bt_psm < 0x1001
        !           326:            || L2CAP_PSM_INVALID(dlc->rd_laddr.bt_psm)))
        !           327:                return EADDRNOTAVAIL;
        !           328:
        !           329:        any = best = NULL;
        !           330:        LIST_FOREACH(rs, &rfcomm_session_listen, rs_next) {
        !           331:                l2cap_sockaddr(rs->rs_l2cap, &addr);
        !           332:
        !           333:                if (addr.bt_psm != dlc->rd_laddr.bt_psm)
        !           334:                        continue;
        !           335:
        !           336:                if (bdaddr_same(&dlc->rd_laddr.bt_bdaddr, &addr.bt_bdaddr))
        !           337:                        best = rs;
        !           338:
        !           339:                if (bdaddr_any(&addr.bt_bdaddr))
        !           340:                        any = rs;
        !           341:        }
        !           342:
        !           343:        rs = best ? best : any;
        !           344:        if (rs == NULL) {
        !           345:                rs = rfcomm_session_alloc(&rfcomm_session_listen,
        !           346:                                                &dlc->rd_laddr);
        !           347:                if (rs == NULL)
        !           348:                        return ENOMEM;
        !           349:
        !           350:                rs->rs_state = RFCOMM_SESSION_LISTEN;
        !           351:
        !           352:                err = l2cap_listen(rs->rs_l2cap);
        !           353:                if (err) {
        !           354:                        rfcomm_session_free(rs);
        !           355:                        return err;
        !           356:                }
        !           357:        }
        !           358:
        !           359:        dlc->rd_session = rs;
        !           360:        dlc->rd_state = RFCOMM_DLC_LISTEN;
        !           361:        LIST_INSERT_HEAD(&rs->rs_dlcs, dlc, rd_next);
        !           362:
        !           363:        return 0;
        !           364: }
        !           365:
        !           366: /*
        !           367:  * rfcomm_send(dlc, mbuf)
        !           368:  *
        !           369:  * Output data on DLC. This is streamed data, so we add it
        !           370:  * to our buffer and start the DLC, which will assemble
        !           371:  * packets and send them if it can.
        !           372:  */
        !           373: int
        !           374: rfcomm_send(struct rfcomm_dlc *dlc, struct mbuf *m)
        !           375: {
        !           376:
        !           377:        if (dlc->rd_txbuf != NULL) {
        !           378:                dlc->rd_txbuf->m_pkthdr.len += m->m_pkthdr.len;
        !           379:                m_cat(dlc->rd_txbuf, m);
        !           380:        } else {
        !           381:                dlc->rd_txbuf = m;
        !           382:        }
        !           383:
        !           384:        if (dlc->rd_state == RFCOMM_DLC_OPEN)
        !           385:                rfcomm_dlc_start(dlc);
        !           386:
        !           387:        return 0;
        !           388: }
        !           389:
        !           390: /*
        !           391:  * rfcomm_rcvd(dlc, space)
        !           392:  *
        !           393:  * Indicate space now available in receive buffer
        !           394:  *
        !           395:  * This should be used to give an initial value of the receive buffer
        !           396:  * size when the DLC is attached and anytime data is cleared from the
        !           397:  * buffer after that.
        !           398:  */
        !           399: int
        !           400: rfcomm_rcvd(struct rfcomm_dlc *dlc, size_t space)
        !           401: {
        !           402:
        !           403:        KASSERT(dlc != NULL);
        !           404:
        !           405:        dlc->rd_rxsize = space;
        !           406:
        !           407:        /*
        !           408:         * if we are using credit based flow control, we may
        !           409:         * want to send some credits..
        !           410:         */
        !           411:        if (dlc->rd_state == RFCOMM_DLC_OPEN
        !           412:            && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
        !           413:                rfcomm_dlc_start(dlc);
        !           414:
        !           415:        return 0;
        !           416: }
        !           417:
        !           418: /*
        !           419:  * rfcomm_setopt(dlc, option, addr)
        !           420:  *
        !           421:  * set DLC options
        !           422:  */
        !           423: int
        !           424: rfcomm_setopt(struct rfcomm_dlc *dlc, int opt, void *addr)
        !           425: {
        !           426:        int mode, err = 0;
        !           427:        uint16_t mtu;
        !           428:
        !           429:        switch (opt) {
        !           430:        case SO_RFCOMM_MTU:
        !           431:                mtu = *(uint16_t *)addr;
        !           432:                if (mtu < RFCOMM_MTU_MIN || mtu > RFCOMM_MTU_MAX)
        !           433:                        err = EINVAL;
        !           434:                else if (dlc->rd_state == RFCOMM_DLC_CLOSED)
        !           435:                        dlc->rd_mtu = mtu;
        !           436:                else
        !           437:                        err = EBUSY;
        !           438:
        !           439:                break;
        !           440:
        !           441:        case SO_RFCOMM_LM:
        !           442:                mode = *(int *)addr;
        !           443:                mode &= (RFCOMM_LM_SECURE | RFCOMM_LM_ENCRYPT | RFCOMM_LM_AUTH);
        !           444:
        !           445:                if (mode & RFCOMM_LM_SECURE)
        !           446:                        mode |= RFCOMM_LM_ENCRYPT;
        !           447:
        !           448:                if (mode & RFCOMM_LM_ENCRYPT)
        !           449:                        mode |= RFCOMM_LM_AUTH;
        !           450:
        !           451:                dlc->rd_mode = mode;
        !           452:
        !           453:                if (dlc->rd_state == RFCOMM_DLC_OPEN)
        !           454:                        err = rfcomm_dlc_setmode(dlc);
        !           455:
        !           456:                break;
        !           457:
        !           458:        default:
        !           459:                err = ENOPROTOOPT;
        !           460:                break;
        !           461:        }
        !           462:        return err;
        !           463: }
        !           464:
        !           465: /*
        !           466:  * rfcomm_getopt(dlc, option, addr)
        !           467:  *
        !           468:  * get DLC options
        !           469:  */
        !           470: int
        !           471: rfcomm_getopt(struct rfcomm_dlc *dlc, int opt, void *addr)
        !           472: {
        !           473:        struct rfcomm_fc_info *fc;
        !           474:
        !           475:        switch (opt) {
        !           476:        case SO_RFCOMM_MTU:
        !           477:                *(uint16_t *)addr = dlc->rd_mtu;
        !           478:                return sizeof(uint16_t);
        !           479:
        !           480:        case SO_RFCOMM_FC_INFO:
        !           481:                fc = addr;
        !           482:                memset(fc, 0, sizeof(*fc));
        !           483:                fc->lmodem = dlc->rd_lmodem;
        !           484:                fc->rmodem = dlc->rd_rmodem;
        !           485:                fc->tx_cred = max(dlc->rd_txcred, 0xff);
        !           486:                fc->rx_cred = max(dlc->rd_rxcred, 0xff);
        !           487:                if (dlc->rd_session
        !           488:                    && (dlc->rd_session->rs_flags & RFCOMM_SESSION_CFC))
        !           489:                        fc->cfc = 1;
        !           490:
        !           491:                return sizeof(*fc);
        !           492:
        !           493:        case SO_RFCOMM_LM:
        !           494:                *(int *)addr = dlc->rd_mode;
        !           495:                return sizeof(int);
        !           496:
        !           497:        default:
        !           498:                break;
        !           499:        }
        !           500:
        !           501:        return 0;
        !           502: }

CVSweb