[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

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