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

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

1.1     ! nbrk        1: /*     $OpenBSD: l2cap_socket.c,v 1.1 2007/06/01 02:46:11 uwe Exp $    */
        !             2: /*     $NetBSD: l2cap_socket.c,v 1.7 2007/04/21 06:15:23 plunky Exp $  */
        !             3:
        !             4: /*-
        !             5:  * Copyright (c) 2005 Iain Hibbert.
        !             6:  * Copyright (c) 2006 Itronix Inc.
        !             7:  * All rights reserved.
        !             8:  *
        !             9:  * Redistribution and use in source and binary forms, with or without
        !            10:  * modification, are permitted provided that the following conditions
        !            11:  * are met:
        !            12:  * 1. Redistributions of source code must retain the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer.
        !            14:  * 2. Redistributions in binary form must reproduce the above copyright
        !            15:  *    notice, this list of conditions and the following disclaimer in the
        !            16:  *    documentation and/or other materials provided with the distribution.
        !            17:  * 3. The name of Itronix Inc. may not be used to endorse
        !            18:  *    or promote products derived from this software without specific
        !            19:  *    prior written permission.
        !            20:  *
        !            21:  * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
        !            22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
        !            23:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
        !            24:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
        !            25:  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
        !            26:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
        !            27:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
        !            28:  * ON ANY THEORY OF LIABILITY, WHETHER IN
        !            29:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
        !            30:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
        !            31:  * POSSIBILITY OF SUCH DAMAGE.
        !            32:  */
        !            33:
        !            34: #include <sys/cdefs.h>
        !            35:
        !            36: /* load symbolic names */
        !            37: #ifdef BLUETOOTH_DEBUG
        !            38: #define PRUREQUESTS
        !            39: #define PRCOREQUESTS
        !            40: #endif
        !            41:
        !            42: #include <sys/param.h>
        !            43: #include <sys/domain.h>
        !            44: #include <sys/kernel.h>
        !            45: #include <sys/mbuf.h>
        !            46: #include <sys/proc.h>
        !            47: #include <sys/protosw.h>
        !            48: #include <sys/socket.h>
        !            49: #include <sys/socketvar.h>
        !            50: #include <sys/systm.h>
        !            51:
        !            52: #include <netbt/bluetooth.h>
        !            53: #include <netbt/hci.h>         /* XXX for EPASSTHROUGH */
        !            54: #include <netbt/l2cap.h>
        !            55:
        !            56: /*
        !            57:  * L2CAP Sockets
        !            58:  *
        !            59:  *     SOCK_SEQPACKET - normal L2CAP connection
        !            60:  *
        !            61:  *     SOCK_DGRAM - connectionless L2CAP - XXX not yet
        !            62:  */
        !            63:
        !            64: static void l2cap_connecting(void *);
        !            65: static void l2cap_connected(void *);
        !            66: static void l2cap_disconnected(void *, int);
        !            67: static void *l2cap_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
        !            68: static void l2cap_complete(void *, int);
        !            69: static void l2cap_linkmode(void *, int);
        !            70: static void l2cap_input(void *, struct mbuf *);
        !            71:
        !            72: static const struct btproto l2cap_proto = {
        !            73:        l2cap_connecting,
        !            74:        l2cap_connected,
        !            75:        l2cap_disconnected,
        !            76:        l2cap_newconn,
        !            77:        l2cap_complete,
        !            78:        l2cap_linkmode,
        !            79:        l2cap_input,
        !            80: };
        !            81:
        !            82: /* sysctl variables */
        !            83: int l2cap_sendspace = 4096;
        !            84: int l2cap_recvspace = 4096;
        !            85:
        !            86: /*
        !            87:  * User Request.
        !            88:  * up is socket
        !            89:  * m is either
        !            90:  *     optional mbuf chain containing message
        !            91:  *     ioctl command (PRU_CONTROL)
        !            92:  * nam is either
        !            93:  *     optional mbuf chain containing an address
        !            94:  *     ioctl data (PRU_CONTROL)
        !            95:  *     optionally protocol number (PRU_ATTACH)
        !            96:  *     message flags (PRU_RCVD)
        !            97:  * ctl is either
        !            98:  *     optional mbuf chain containing socket options
        !            99:  *     optional interface pointer (PRU_CONTROL, PRU_PURGEIF)
        !           100:  * l is pointer to process requesting action (if any)
        !           101:  *
        !           102:  * we are responsible for disposing of m and ctl if
        !           103:  * they are mbuf chains
        !           104:  */
        !           105: int
        !           106: l2cap_usrreq(struct socket *up, int req, struct mbuf *m,
        !           107:     struct mbuf *nam, struct mbuf *ctl)
        !           108: {
        !           109:        struct l2cap_channel *pcb = up->so_pcb;
        !           110:        struct sockaddr_bt *sa;
        !           111:        struct mbuf *m0;
        !           112:        int err = 0;
        !           113:
        !           114: #ifdef notyet                  /* XXX */
        !           115:        DPRINTFN(2, "%s\n", prurequests[req]);
        !           116: #endif
        !           117:
        !           118:        switch (req) {
        !           119:        case PRU_CONTROL:
        !           120:                return EPASSTHROUGH;
        !           121:
        !           122: #ifdef notyet                  /* XXX */
        !           123:        case PRU_PURGEIF:
        !           124:                return EOPNOTSUPP;
        !           125: #endif
        !           126:
        !           127:        case PRU_ATTACH:
        !           128:                if (pcb != NULL)
        !           129:                        return EINVAL;
        !           130:
        !           131:                /*
        !           132:                 * For L2CAP socket PCB we just use an l2cap_channel structure
        !           133:                 * since we have nothing to add..
        !           134:                 */
        !           135:                err = soreserve(up, l2cap_sendspace, l2cap_recvspace);
        !           136:                if (err)
        !           137:                        return err;
        !           138:
        !           139:                return l2cap_attach((struct l2cap_channel **)&up->so_pcb,
        !           140:                                        &l2cap_proto, up);
        !           141:        }
        !           142:
        !           143:        if (pcb == NULL) {
        !           144:                err = EINVAL;
        !           145:                goto release;
        !           146:        }
        !           147:
        !           148:        switch(req) {
        !           149:        case PRU_DISCONNECT:
        !           150:                soisdisconnecting(up);
        !           151:                return l2cap_disconnect(pcb, up->so_linger);
        !           152:
        !           153:        case PRU_ABORT:
        !           154:                l2cap_disconnect(pcb, 0);
        !           155:                soisdisconnected(up);
        !           156:                /* fall through to */
        !           157:        case PRU_DETACH:
        !           158:                return l2cap_detach((struct l2cap_channel **)&up->so_pcb);
        !           159:
        !           160:        case PRU_BIND:
        !           161:                KASSERT(nam != NULL);
        !           162:                sa = mtod(nam, struct sockaddr_bt *);
        !           163:
        !           164:                if (sa->bt_len != sizeof(struct sockaddr_bt))
        !           165:                        return EINVAL;
        !           166:
        !           167:                if (sa->bt_family != AF_BLUETOOTH)
        !           168:                        return EAFNOSUPPORT;
        !           169:
        !           170:                return l2cap_bind(pcb, sa);
        !           171:
        !           172:        case PRU_CONNECT:
        !           173:                KASSERT(nam != NULL);
        !           174:                sa = mtod(nam, struct sockaddr_bt *);
        !           175:
        !           176:                if (sa->bt_len != sizeof(struct sockaddr_bt))
        !           177:                        return EINVAL;
        !           178:
        !           179:                if (sa->bt_family != AF_BLUETOOTH)
        !           180:                        return EAFNOSUPPORT;
        !           181:
        !           182:                soisconnecting(up);
        !           183:                return l2cap_connect(pcb, sa);
        !           184:
        !           185:        case PRU_PEERADDR:
        !           186:                KASSERT(nam != NULL);
        !           187:                sa = mtod(nam, struct sockaddr_bt *);
        !           188:                nam->m_len = sizeof(struct sockaddr_bt);
        !           189:                return l2cap_peeraddr(pcb, sa);
        !           190:
        !           191:        case PRU_SOCKADDR:
        !           192:                KASSERT(nam != NULL);
        !           193:                sa = mtod(nam, struct sockaddr_bt *);
        !           194:                nam->m_len = sizeof(struct sockaddr_bt);
        !           195:                return l2cap_sockaddr(pcb, sa);
        !           196:
        !           197:        case PRU_SHUTDOWN:
        !           198:                socantsendmore(up);
        !           199:                break;
        !           200:
        !           201:        case PRU_SEND:
        !           202:                KASSERT(m != NULL);
        !           203:                if (m->m_pkthdr.len == 0)
        !           204:                        break;
        !           205:
        !           206:                if (m->m_pkthdr.len > pcb->lc_omtu) {
        !           207:                        err = EMSGSIZE;
        !           208:                        break;
        !           209:                }
        !           210:
        !           211:                m0 = m_copym(m, 0, M_COPYALL, M_DONTWAIT);
        !           212:                if (m0 == NULL) {
        !           213:                        err = ENOMEM;
        !           214:                        break;
        !           215:                }
        !           216:
        !           217:                if (ctl)        /* no use for that */
        !           218:                        m_freem(ctl);
        !           219:
        !           220:                sbappendrecord(&up->so_snd, m);
        !           221:                return l2cap_send(pcb, m0);
        !           222:
        !           223:        case PRU_SENSE:
        !           224:                return 0;               /* (no release) */
        !           225:
        !           226:        case PRU_RCVD:
        !           227:        case PRU_RCVOOB:
        !           228:                return EOPNOTSUPP;      /* (no release) */
        !           229:
        !           230:        case PRU_LISTEN:
        !           231:                return l2cap_listen(pcb);
        !           232:
        !           233:        case PRU_ACCEPT:
        !           234:                KASSERT(nam != NULL);
        !           235:                sa = mtod(nam, struct sockaddr_bt *);
        !           236:                nam->m_len = sizeof(struct sockaddr_bt);
        !           237:                return l2cap_peeraddr(pcb, sa);
        !           238:
        !           239:        case PRU_CONNECT2:
        !           240:        case PRU_SENDOOB:
        !           241:        case PRU_FASTTIMO:
        !           242:        case PRU_SLOWTIMO:
        !           243:        case PRU_PROTORCV:
        !           244:        case PRU_PROTOSEND:
        !           245:                err = EOPNOTSUPP;
        !           246:                break;
        !           247:
        !           248:        default:
        !           249:                UNKNOWN(req);
        !           250:                err = EOPNOTSUPP;
        !           251:                break;
        !           252:        }
        !           253:
        !           254: release:
        !           255:        if (m) m_freem(m);
        !           256:        if (ctl) m_freem(ctl);
        !           257:        return err;
        !           258: }
        !           259:
        !           260: /*
        !           261:  * l2cap_ctloutput(request, socket, level, optname, opt)
        !           262:  *
        !           263:  *     Apply configuration commands to channel. This corresponds to
        !           264:  *     "Reconfigure Channel Request" in the L2CAP specification.
        !           265:  */
        !           266: int
        !           267: l2cap_ctloutput(int req, struct socket *so, int level,
        !           268:                int optname, struct mbuf **opt)
        !           269: {
        !           270:        struct l2cap_channel *pcb = so->so_pcb;
        !           271:        struct mbuf *m;
        !           272:        int err = 0;
        !           273:
        !           274: #ifdef notyet                  /* XXX */
        !           275:        DPRINTFN(2, "%s\n", prcorequests[req]);
        !           276: #endif
        !           277:
        !           278:        if (pcb == NULL)
        !           279:                return EINVAL;
        !           280:
        !           281:        if (level != BTPROTO_L2CAP)
        !           282:                return ENOPROTOOPT;
        !           283:
        !           284:        switch(req) {
        !           285:        case PRCO_GETOPT:
        !           286:                m = m_get(M_WAIT, MT_SOOPTS);
        !           287:                m->m_len = l2cap_getopt(pcb, optname, mtod(m, void *));
        !           288:                if (m->m_len == 0) {
        !           289:                        m_freem(m);
        !           290:                        m = NULL;
        !           291:                        err = ENOPROTOOPT;
        !           292:                }
        !           293:                *opt = m;
        !           294:                break;
        !           295:
        !           296:        case PRCO_SETOPT:
        !           297:                m = *opt;
        !           298:                KASSERT(m != NULL);
        !           299:                err = l2cap_setopt(pcb, optname, mtod(m, void *));
        !           300:                m_freem(m);
        !           301:                break;
        !           302:
        !           303:        default:
        !           304:                err = ENOPROTOOPT;
        !           305:                break;
        !           306:        }
        !           307:
        !           308:        return err;
        !           309: }
        !           310:
        !           311: /**********************************************************************
        !           312:  *
        !           313:  *     L2CAP Protocol socket callbacks
        !           314:  *
        !           315:  */
        !           316:
        !           317: static void
        !           318: l2cap_connecting(void *arg)
        !           319: {
        !           320:        struct socket *so = arg;
        !           321:
        !           322:        DPRINTF("Connecting\n");
        !           323:        soisconnecting(so);
        !           324: }
        !           325:
        !           326: static void
        !           327: l2cap_connected(void *arg)
        !           328: {
        !           329:        struct socket *so = arg;
        !           330:
        !           331:        DPRINTF("Connected\n");
        !           332:        soisconnected(so);
        !           333: }
        !           334:
        !           335: static void
        !           336: l2cap_disconnected(void *arg, int err)
        !           337: {
        !           338:        struct socket *so = arg;
        !           339:
        !           340:        DPRINTF("Disconnected (%d)\n", err);
        !           341:
        !           342:        so->so_error = err;
        !           343:        soisdisconnected(so);
        !           344: }
        !           345:
        !           346: static void *
        !           347: l2cap_newconn(void *arg, struct sockaddr_bt *laddr,
        !           348:     struct sockaddr_bt *raddr)
        !           349: {
        !           350:        struct socket *so = arg;
        !           351:
        !           352:        DPRINTF("New Connection\n");
        !           353:        so = sonewconn(so, 0);
        !           354:        if (so == NULL)
        !           355:                return NULL;
        !           356:
        !           357:        soisconnecting(so);
        !           358:
        !           359:        return so->so_pcb;
        !           360: }
        !           361:
        !           362: static void
        !           363: l2cap_complete(void *arg, int count)
        !           364: {
        !           365:        struct socket *so = arg;
        !           366:
        !           367:        while (count-- > 0)
        !           368:                sbdroprecord(&so->so_snd);
        !           369:
        !           370:        sowwakeup(so);
        !           371: }
        !           372:
        !           373: static void
        !           374: l2cap_linkmode(void *arg, int new)
        !           375: {
        !           376:        struct socket *so = arg;
        !           377:        int mode;
        !           378:
        !           379:        DPRINTF("auth %s, encrypt %s, secure %s\n",
        !           380:                (new & L2CAP_LM_AUTH ? "on" : "off"),
        !           381:                (new & L2CAP_LM_ENCRYPT ? "on" : "off"),
        !           382:                (new & L2CAP_LM_SECURE ? "on" : "off"));
        !           383:
        !           384:        (void)l2cap_getopt(so->so_pcb, SO_L2CAP_LM, &mode);
        !           385:        if (((mode & L2CAP_LM_AUTH) && !(new & L2CAP_LM_AUTH))
        !           386:            || ((mode & L2CAP_LM_ENCRYPT) && !(new & L2CAP_LM_ENCRYPT))
        !           387:            || ((mode & L2CAP_LM_SECURE) && !(new & L2CAP_LM_SECURE)))
        !           388:                l2cap_disconnect(so->so_pcb, 0);
        !           389: }
        !           390:
        !           391: static void
        !           392: l2cap_input(void *arg, struct mbuf *m)
        !           393: {
        !           394:        struct socket *so = arg;
        !           395:
        !           396:        if (m->m_pkthdr.len > sbspace(&so->so_rcv)) {
        !           397:                printf("%s: packet (%d bytes) dropped (socket buffer full)\n",
        !           398:                        __func__, m->m_pkthdr.len);
        !           399:                m_freem(m);
        !           400:                return;
        !           401:        }
        !           402:
        !           403:        DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
        !           404:
        !           405:        sbappendrecord(&so->so_rcv, m);
        !           406:        sorwakeup(so);
        !           407: }

CVSweb