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

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

1.1       nbrk        1: /*     $OpenBSD: sco_upper.c,v 1.1 2007/06/01 02:46:12 uwe Exp $       */
                      2: /*     $NetBSD: sco_upper.c,v 1.6 2007/03/30 20:47:03 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/sco.h>
                     46:
                     47: /****************************************************************************
                     48:  *
                     49:  *     SCO - Upper Protocol API
                     50:  */
                     51:
                     52: struct sco_pcb_list sco_pcb = LIST_HEAD_INITIALIZER(sco_pcb);
                     53:
                     54: /*
                     55:  * sco_attach(handle, proto, upper)
                     56:  *
                     57:  *     Attach a new instance of SCO pcb to handle
                     58:  */
                     59: int
                     60: sco_attach(struct sco_pcb **handle,
                     61:                const struct btproto *proto, void *upper)
                     62: {
                     63:        struct sco_pcb *pcb;
                     64:
                     65:        KASSERT(handle != NULL);
                     66:        KASSERT(proto != NULL);
                     67:        KASSERT(upper != NULL);
                     68:
                     69:        pcb = malloc(sizeof(struct sco_pcb), M_BLUETOOTH, M_NOWAIT);
                     70:        if (pcb == NULL)
                     71:                return ENOMEM;
                     72:        bzero(pcb, sizeof *pcb);
                     73:
                     74:        pcb->sp_proto = proto;
                     75:        pcb->sp_upper = upper;
                     76:
                     77:        LIST_INSERT_HEAD(&sco_pcb, pcb, sp_next);
                     78:
                     79:        *handle = pcb;
                     80:        return 0;
                     81: }
                     82:
                     83: /*
                     84:  * sco_bind(pcb, sockaddr)
                     85:  *
                     86:  *     Bind SCO pcb to local address
                     87:  */
                     88: int
                     89: sco_bind(struct sco_pcb *pcb, struct sockaddr_bt *addr)
                     90: {
                     91:
                     92:        bdaddr_copy(&pcb->sp_laddr, &addr->bt_bdaddr);
                     93:        return 0;
                     94: }
                     95:
                     96: /*
                     97:  * sco_sockaddr(pcb, sockaddr)
                     98:  *
                     99:  *     Copy local address of PCB to sockaddr
                    100:  */
                    101: int
                    102: sco_sockaddr(struct sco_pcb *pcb, struct sockaddr_bt *addr)
                    103: {
                    104:
                    105:        memset(addr, 0, sizeof(struct sockaddr_bt));
                    106:        addr->bt_len = sizeof(struct sockaddr_bt);
                    107:        addr->bt_family = AF_BLUETOOTH;
                    108:        bdaddr_copy(&addr->bt_bdaddr, &pcb->sp_laddr);
                    109:        return 0;
                    110: }
                    111:
                    112: /*
                    113:  * sco_connect(pcb, sockaddr)
                    114:  *
                    115:  *     Initiate a SCO connection to the destination address.
                    116:  */
                    117: int
                    118: sco_connect(struct sco_pcb *pcb, struct sockaddr_bt *dest)
                    119: {
                    120:        hci_add_sco_con_cp cp;
                    121:        struct hci_unit *unit;
                    122:        struct hci_link *acl, *sco;
                    123:        int err;
                    124:
                    125:        if (pcb->sp_flags & SP_LISTENING)
                    126:                return EINVAL;
                    127:
                    128:        bdaddr_copy(&pcb->sp_raddr, &dest->bt_bdaddr);
                    129:
                    130:        if (bdaddr_any(&pcb->sp_raddr))
                    131:                return EDESTADDRREQ;
                    132:
                    133:        if (bdaddr_any(&pcb->sp_laddr)) {
                    134:                err = hci_route_lookup(&pcb->sp_laddr, &pcb->sp_raddr);
                    135:                if (err)
                    136:                        return err;
                    137:        }
                    138:
                    139:        unit = hci_unit_lookup(&pcb->sp_laddr);
                    140:        if (unit == NULL)
                    141:                return ENETDOWN;
                    142:
                    143:        /*
                    144:         * We must have an already open ACL connection before we open the SCO
                    145:         * connection, and since SCO connections dont happen on their own we
                    146:         * will not open one, the application wanting this should have opened
                    147:         * it previously.
                    148:         */
                    149:        acl = hci_link_lookup_bdaddr(unit, &pcb->sp_raddr, HCI_LINK_ACL);
                    150:        if (acl == NULL || acl->hl_state != HCI_LINK_OPEN)
                    151:                return EHOSTUNREACH;
                    152:
                    153:        sco = hci_link_alloc(unit);
                    154:        if (sco == NULL)
                    155:                return ENOMEM;
                    156:
                    157:        sco->hl_type = HCI_LINK_SCO;
                    158:        bdaddr_copy(&sco->hl_bdaddr, &pcb->sp_raddr);
                    159:
                    160:        sco->hl_link = hci_acl_open(unit, &pcb->sp_raddr);
                    161:        KASSERT(sco->hl_link == acl);
                    162:
                    163:        cp.con_handle = htole16(acl->hl_handle);
                    164:        cp.pkt_type = htole16(0x00e0);          /* HV1, HV2, HV3 */
                    165:        err = hci_send_cmd(unit, HCI_CMD_ADD_SCO_CON, &cp, sizeof(cp));
                    166:        if (err) {
                    167:                hci_link_free(sco, err);
                    168:                return err;
                    169:        }
                    170:
                    171:        sco->hl_sco = pcb;
                    172:        pcb->sp_link = sco;
                    173:
                    174:        pcb->sp_mtu = unit->hci_max_sco_size;
                    175:        return 0;
                    176: }
                    177:
                    178: /*
                    179:  * sco_peeraddr(pcb, sockaddr)
                    180:  *
                    181:  *     Copy remote address of SCO pcb to sockaddr
                    182:  */
                    183: int
                    184: sco_peeraddr(struct sco_pcb *pcb, struct sockaddr_bt *addr)
                    185: {
                    186:
                    187:        memset(addr, 0, sizeof(struct sockaddr_bt));
                    188:        addr->bt_len = sizeof(struct sockaddr_bt);
                    189:        addr->bt_family = AF_BLUETOOTH;
                    190:        bdaddr_copy(&addr->bt_bdaddr, &pcb->sp_raddr);
                    191:        return 0;
                    192: }
                    193:
                    194: /*
                    195:  * sco_disconnect(pcb, linger)
                    196:  *
                    197:  *     Initiate disconnection of connected SCO pcb
                    198:  */
                    199: int
                    200: sco_disconnect(struct sco_pcb *pcb, int linger)
                    201: {
                    202:        hci_discon_cp cp;
                    203:        struct hci_link *sco;
                    204:        int err;
                    205:
                    206:        sco = pcb->sp_link;
                    207:        if (sco == NULL)
                    208:                return EINVAL;
                    209:
                    210:        cp.con_handle = htole16(sco->hl_handle);
                    211:        cp.reason = 0x13;       /* "Remote User Terminated Connection" */
                    212:
                    213:        err = hci_send_cmd(sco->hl_unit, HCI_CMD_DISCONNECT, &cp, sizeof(cp));
                    214:        if (err || linger == 0) {
                    215:                sco->hl_sco = NULL;
                    216:                pcb->sp_link = NULL;
                    217:                hci_link_free(sco, err);
                    218:        }
                    219:
                    220:        return err;
                    221: }
                    222:
                    223: /*
                    224:  * sco_detach(handle)
                    225:  *
                    226:  *     Detach SCO pcb from handle and clear up
                    227:  */
                    228: int
                    229: sco_detach(struct sco_pcb **handle)
                    230: {
                    231:        struct sco_pcb *pcb;
                    232:
                    233:        KASSERT(handle != NULL);
                    234:        pcb = *handle;
                    235:        *handle = NULL;
                    236:
                    237:        if (pcb == NULL)
                    238:                return EINVAL;
                    239:
                    240:        if (pcb->sp_link != NULL) {
                    241:                sco_disconnect(pcb, 0);
                    242:                pcb->sp_link = NULL;
                    243:        }
                    244:
                    245:        LIST_REMOVE(pcb, sp_next);
                    246:        free(pcb, M_BLUETOOTH);
                    247:        return 0;
                    248: }
                    249:
                    250: /*
                    251:  * sco_listen(pcb)
                    252:  *
                    253:  *     Mark pcb as a listener.
                    254:  */
                    255: int
                    256: sco_listen(struct sco_pcb *pcb)
                    257: {
                    258:
                    259:        if (pcb->sp_link != NULL)
                    260:                return EINVAL;
                    261:
                    262:        pcb->sp_flags |= SP_LISTENING;
                    263:        return 0;
                    264: }
                    265:
                    266: /*
                    267:  * sco_send(pcb, mbuf)
                    268:  *
                    269:  *     Send data on SCO pcb.
                    270:  *
                    271:  * Gross hackage, we just output the packet directly onto the unit queue.
                    272:  * This will work fine for one channel per unit, but for more channels it
                    273:  * really needs fixing. We set the context so that when the packet is sent,
                    274:  * we can drop a record from the socket buffer.
                    275:  */
                    276: int
                    277: sco_send(struct sco_pcb *pcb, struct mbuf *m)
                    278: {
                    279:        hci_scodata_hdr_t *hdr;
                    280:        int plen;
                    281:
                    282:        if (pcb->sp_link == NULL) {
                    283:                m_freem(m);
                    284:                return EINVAL;
                    285:        }
                    286:
                    287:        plen = m->m_pkthdr.len;
                    288:        DPRINTFN(10, "%d bytes\n", plen);
                    289:
                    290:        /*
                    291:         * This is a temporary limitation, as USB devices cannot
                    292:         * handle SCO packet sizes that are not an integer number
                    293:         * of Isochronous frames. See ubt(4)
                    294:         */
                    295:        if (plen != pcb->sp_mtu) {
                    296:                m_freem(m);
                    297:                return EMSGSIZE;
                    298:        }
                    299:
                    300:        M_PREPEND(m, sizeof(hci_scodata_hdr_t), M_DONTWAIT);
                    301:        if (m == NULL)
                    302:                return ENOMEM;
                    303:
                    304:        hdr = mtod(m, hci_scodata_hdr_t *);
                    305:        hdr->type = HCI_SCO_DATA_PKT;
                    306:        hdr->con_handle = htole16(pcb->sp_link->hl_handle);
                    307:        hdr->length = plen;
                    308:
                    309:        pcb->sp_pending++;
                    310:        M_SETCTX(m, pcb->sp_link);
                    311:        hci_output_sco(pcb->sp_link->hl_unit, m);
                    312:
                    313:        return 0;
                    314: }
                    315:
                    316: /*
                    317:  * sco_setopt(pcb, option, addr)
                    318:  *
                    319:  *     Set SCO pcb options
                    320:  */
                    321: int
                    322: sco_setopt(struct sco_pcb *pcb, int opt, void *addr)
                    323: {
                    324:        int err = 0;
                    325:
                    326:        switch (opt) {
                    327:        default:
                    328:                err = ENOPROTOOPT;
                    329:                break;
                    330:        }
                    331:
                    332:        return err;
                    333: }
                    334:
                    335: /*
                    336:  * sco_getopt(pcb, option, addr)
                    337:  *
                    338:  *     Get SCO pcb options
                    339:  */
                    340: int
                    341: sco_getopt(struct sco_pcb *pcb, int opt, void *addr)
                    342: {
                    343:
                    344:        switch (opt) {
                    345:        case SO_SCO_MTU:
                    346:                *(uint16_t *)addr = pcb->sp_mtu;
                    347:                return sizeof(uint16_t);
                    348:
                    349:        case SO_SCO_HANDLE:
                    350:                if (pcb->sp_link) {
                    351:                        *(uint16_t *)addr = pcb->sp_link->hl_handle;
                    352:                        return sizeof(uint16_t);
                    353:                }
                    354:                break;
                    355:
                    356:        default:
                    357:                break;
                    358:        }
                    359:        return 0;
                    360: }

CVSweb