[BACK]Return to if_tun.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / net

Annotation of src/sys/net/if_tun.c, Revision 1.100

1.100   ! pooka       1: /*     $NetBSD: if_tun.c,v 1.99 2007/10/19 12:16:45 ad Exp $   */
1.14      cgd         2:
1.1       cgd         3: /*
1.8       deraadt     4:  * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk>
                      5:  * Nottingham University 1987.
1.1       cgd         6:  *
                      7:  * This source may be freely distributed, however I would be interested
                      8:  * in any changes that are made.
1.6       deraadt     9:  *
1.1       cgd        10:  * This driver takes packets off the IP i/f and hands them up to a
1.21      scottr     11:  * user process to have its wicked way with. This driver has its
1.1       cgd        12:  * roots in a similar driver written by Phil Cockcroft (formerly) at
1.27      mycroft    13:  * UCL. This driver is based much more on read/write/poll mode of
1.1       cgd        14:  * operation though.
                     15:  */
1.48      lukem      16:
                     17: #include <sys/cdefs.h>
1.100   ! pooka      18: __KERNEL_RCSID(0, "$NetBSD: if_tun.c,v 1.99 2007/10/19 12:16:45 ad Exp $");
1.33      jonathan   19:
                     20: #include "opt_inet.h"
1.8       deraadt    21:
1.6       deraadt    22: #include <sys/param.h>
1.8       deraadt    23: #include <sys/proc.h>
1.6       deraadt    24: #include <sys/systm.h>
                     25: #include <sys/mbuf.h>
                     26: #include <sys/buf.h>
                     27: #include <sys/protosw.h>
                     28: #include <sys/socket.h>
                     29: #include <sys/ioctl.h>
                     30: #include <sys/errno.h>
                     31: #include <sys/syslog.h>
                     32: #include <sys/select.h>
1.27      mycroft    33: #include <sys/poll.h>
1.8       deraadt    34: #include <sys/file.h>
1.22      christos   35: #include <sys/signalvar.h>
1.23      christos   36: #include <sys/conf.h>
1.89      elad       37: #include <sys/kauth.h>
1.9       deraadt    38:
1.99      ad         39: #include <sys/cpu.h>
1.6       deraadt    40:
                     41: #include <net/if.h>
1.69      tron       42: #include <net/if_types.h>
1.6       deraadt    43: #include <net/netisr.h>
                     44: #include <net/route.h>
1.1       cgd        45:
1.30      is         46:
1.1       cgd        47: #ifdef INET
1.6       deraadt    48: #include <netinet/in.h>
                     49: #include <netinet/in_systm.h>
                     50: #include <netinet/in_var.h>
                     51: #include <netinet/ip.h>
1.30      is         52: #include <netinet/if_inarp.h>
1.1       cgd        53: #endif
                     54:
                     55:
1.8       deraadt    56: #include "bpfilter.h"
                     57: #if NBPFILTER > 0
                     58: #include <sys/time.h>
                     59: #include <net/bpf.h>
                     60: #endif
                     61:
                     62: #include <net/if_tun.h>
                     63:
1.29      christos   64: #define TUNDEBUG       if (tundebug) printf
1.6       deraadt    65: int    tundebug = 0;
1.1       cgd        66:
1.6       deraadt    67: extern int ifqmaxlen;
1.78      thorpej    68: void   tunattach(int);
                     69:
                     70: static LIST_HEAD(, tun_softc) tun_softc_list;
                     71: static LIST_HEAD(, tun_softc) tunz_softc_list;
1.46      atatat     72: static struct simplelock tun_softc_lock;
1.6       deraadt    73:
1.97      christos   74: static int     tun_ioctl(struct ifnet *, u_long, void *);
1.96      dyoung     75: static int     tun_output(struct ifnet *, struct mbuf *,
                     76:                        const struct sockaddr *, struct rtentry *rt);
1.78      thorpej    77: static int     tun_clone_create(struct if_clone *, int);
                     78: static int     tun_clone_destroy(struct ifnet *);
1.6       deraadt    79:
1.78      thorpej    80: static struct if_clone tun_cloner =
1.46      atatat     81:     IF_CLONE_INITIALIZER("tun", tun_clone_create, tun_clone_destroy);
                     82:
1.78      thorpej    83: static void tunattach0(struct tun_softc *);
                     84: static void tuninit(struct tun_softc *);
1.50      itojun     85: #ifdef ALTQ
1.78      thorpej    86: static void tunstart(struct ifnet *);
1.50      itojun     87: #endif
1.78      thorpej    88: static struct tun_softc *tun_find_unit(dev_t);
                     89: static struct tun_softc *tun_find_zunit(int);
1.53      gehenna    90:
1.78      thorpej    91: static dev_type_open(tunopen);
                     92: static dev_type_close(tunclose);
                     93: static dev_type_read(tunread);
                     94: static dev_type_write(tunwrite);
                     95: static dev_type_ioctl(tunioctl);
                     96: static dev_type_poll(tunpoll);
                     97: static dev_type_kqfilter(tunkqfilter);
1.53      gehenna    98:
                     99: const struct cdevsw tun_cdevsw = {
                    100:        tunopen, tunclose, tunread, tunwrite, tunioctl,
1.91      christos  101:        nostop, notty, tunpoll, nommap, tunkqfilter, D_OTHER,
1.53      gehenna   102: };
1.6       deraadt   103:
1.8       deraadt   104: void
1.94      christos  105: tunattach(int unused)
1.8       deraadt   106: {
1.46      atatat    107:
                    108:        simple_lock_init(&tun_softc_lock);
                    109:        LIST_INIT(&tun_softc_list);
1.70      pk        110:        LIST_INIT(&tunz_softc_list);
1.46      atatat    111:        if_clone_attach(&tun_cloner);
                    112: }
                    113:
1.70      pk        114: /*
                    115:  * Find driver instance from dev_t.
                    116:  * Call at splnet().
                    117:  * Returns with tp locked (if found).
                    118:  */
                    119: static struct tun_softc *
1.78      thorpej   120: tun_find_unit(dev_t dev)
1.70      pk        121: {
                    122:        struct tun_softc *tp;
                    123:        int unit = minor(dev);
                    124:
                    125:        simple_lock(&tun_softc_lock);
                    126:        LIST_FOREACH(tp, &tun_softc_list, tun_list)
                    127:                if (unit == tp->tun_unit)
                    128:                        break;
                    129:        if (tp)
                    130:                simple_lock(&tp->tun_lock);
                    131:        simple_unlock(&tun_softc_lock);
                    132:
                    133:        return (tp);
                    134: }
                    135:
                    136: /*
                    137:  * Find zombie driver instance by unit number.
                    138:  * Call at splnet().
                    139:  * Remove tp from list and return it unlocked (if found).
                    140:  */
                    141: static struct tun_softc *
1.78      thorpej   142: tun_find_zunit(int unit)
1.70      pk        143: {
                    144:        struct tun_softc *tp;
                    145:
                    146:        simple_lock(&tun_softc_lock);
                    147:        LIST_FOREACH(tp, &tunz_softc_list, tun_list)
                    148:                if (unit == tp->tun_unit)
                    149:                        break;
                    150:        if (tp)
                    151:                LIST_REMOVE(tp, tun_list);
                    152:        simple_unlock(&tun_softc_lock);
                    153: #ifdef DIAGNOSTIC
                    154:        if (tp != NULL && (tp->tun_flags & (TUN_INITED|TUN_OPEN)) != TUN_OPEN)
                    155:                printf("tun%d: inconsistent flags: %x\n", unit, tp->tun_flags);
                    156: #endif
                    157:
                    158:        return (tp);
                    159: }
                    160:
1.78      thorpej   161: static int
                    162: tun_clone_create(struct if_clone *ifc, int unit)
1.46      atatat    163: {
1.70      pk        164:        struct tun_softc *tp;
1.46      atatat    165:
1.70      pk        166:        if ((tp = tun_find_zunit(unit)) == NULL) {
                    167:                /* Allocate a new instance */
                    168:                tp = malloc(sizeof(struct tun_softc), M_DEVBUF, M_WAITOK);
                    169:                (void)memset(tp, 0, sizeof(struct tun_softc));
1.46      atatat    170:
1.70      pk        171:                tp->tun_unit = unit;
                    172:                simple_lock_init(&tp->tun_lock);
                    173:        } else {
                    174:                /* Revive tunnel instance; clear ifp part */
                    175:                (void)memset(&tp->tun_if, 0, sizeof(struct ifnet));
                    176:        }
1.46      atatat    177:
1.70      pk        178:        (void)snprintf(tp->tun_if.if_xname, sizeof(tp->tun_if.if_xname),
                    179:                        "%s%d", ifc->ifc_name, unit);
                    180:        tunattach0(tp);
                    181:        tp->tun_flags |= TUN_INITED;
1.46      atatat    182:
                    183:        simple_lock(&tun_softc_lock);
1.70      pk        184:        LIST_INSERT_HEAD(&tun_softc_list, tp, tun_list);
1.46      atatat    185:        simple_unlock(&tun_softc_lock);
                    186:
                    187:        return (0);
                    188: }
                    189:
1.78      thorpej   190: static void
                    191: tunattach0(struct tun_softc *tp)
1.46      atatat    192: {
1.70      pk        193:        struct ifnet *ifp;
1.46      atatat    194:
1.70      pk        195:        ifp = &tp->tun_if;
                    196:        ifp->if_softc = tp;
1.46      atatat    197:        ifp->if_mtu = TUNMTU;
                    198:        ifp->if_ioctl = tun_ioctl;
                    199:        ifp->if_output = tun_output;
1.50      itojun    200: #ifdef ALTQ
                    201:        ifp->if_start = tunstart;
                    202: #endif
1.46      atatat    203:        ifp->if_flags = IFF_POINTOPOINT;
1.69      tron      204:        ifp->if_type = IFT_TUNNEL;
1.46      atatat    205:        ifp->if_snd.ifq_maxlen = ifqmaxlen;
                    206:        ifp->if_collisions = 0;
                    207:        ifp->if_ierrors = 0;
                    208:        ifp->if_oerrors = 0;
                    209:        ifp->if_ipackets = 0;
                    210:        ifp->if_opackets = 0;
1.58      jdolecek  211:        ifp->if_ibytes   = 0;
                    212:        ifp->if_obytes   = 0;
1.46      atatat    213:        ifp->if_dlt = DLT_NULL;
1.50      itojun    214:        IFQ_SET_READY(&ifp->if_snd);
1.46      atatat    215:        if_attach(ifp);
                    216:        if_alloc_sadl(ifp);
                    217: #if NBPFILTER > 0
                    218:        bpfattach(ifp, DLT_NULL, sizeof(u_int32_t));
                    219: #endif
                    220: }
                    221:
1.78      thorpej   222: static int
                    223: tun_clone_destroy(struct ifnet *ifp)
1.46      atatat    224: {
                    225:        struct tun_softc *tp = (void *)ifp;
1.70      pk        226:        int s, zombie = 0;
1.8       deraadt   227:
1.70      pk        228:        s = splnet();
1.46      atatat    229:        simple_lock(&tun_softc_lock);
                    230:        simple_lock(&tp->tun_lock);
                    231:        LIST_REMOVE(tp, tun_list);
1.70      pk        232:        if (tp->tun_flags & TUN_OPEN) {
                    233:                /* Hang on to storage until last close */
                    234:                zombie = 1;
                    235:                tp->tun_flags &= ~TUN_INITED;
                    236:                LIST_INSERT_HEAD(&tunz_softc_list, tp, tun_list);
                    237:        }
1.46      atatat    238:        simple_unlock(&tun_softc_lock);
                    239:
1.70      pk        240:        IF_PURGE(&ifp->if_snd);
                    241:        ifp->if_flags &= ~IFF_RUNNING;
                    242:
1.46      atatat    243:        if (tp->tun_flags & TUN_RWAIT) {
                    244:                tp->tun_flags &= ~TUN_RWAIT;
1.97      christos  245:                wakeup((void *)tp);
1.46      atatat    246:        }
1.64      jdolecek  247:        if (tp->tun_flags & TUN_ASYNC && tp->tun_pgid)
1.66      christos  248:                fownsignal(tp->tun_pgid, SIGIO, POLL_HUP, 0, NULL);
1.64      jdolecek  249:
1.46      atatat    250:        selwakeup(&tp->tun_rsel);
1.8       deraadt   251:
1.70      pk        252:        simple_unlock(&tp->tun_lock);
                    253:        splx(s);
                    254:
1.8       deraadt   255: #if NBPFILTER > 0
1.46      atatat    256:        bpfdetach(ifp);
1.8       deraadt   257: #endif
1.46      atatat    258:        if_detach(ifp);
                    259:
1.70      pk        260:        if (!zombie)
                    261:                free(tp, M_DEVBUF);
1.73      peter     262:
                    263:        return (0);
1.8       deraadt   264: }
                    265:
1.6       deraadt   266: /*
                    267:  * tunnel open - must be superuser & the device must be
                    268:  * configured in
                    269:  */
1.78      thorpej   270: static int
1.94      christos  271: tunopen(dev_t dev, int flag, int mode, struct lwp *l)
1.6       deraadt   272: {
                    273:        struct ifnet    *ifp;
1.8       deraadt   274:        struct tun_softc *tp;
1.70      pk        275:        int     s, error;
1.1       cgd       276:
1.90      ad        277:        if ((error = kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
1.95      elad      278:            NULL)) != 0)
1.5       deraadt   279:                return (error);
                    280:
1.70      pk        281:        s = splnet();
1.46      atatat    282:        tp = tun_find_unit(dev);
1.52      atatat    283:
1.70      pk        284:        if (tp == NULL) {
1.52      atatat    285:                (void)tun_clone_create(&tun_cloner, minor(dev));
                    286:                tp = tun_find_unit(dev);
1.70      pk        287:                if (tp == NULL) {
                    288:                        error = ENXIO;
                    289:                        goto out_nolock;
                    290:                }
1.52      atatat    291:        }
1.46      atatat    292:
                    293:        if (tp->tun_flags & TUN_OPEN) {
1.70      pk        294:                error = EBUSY;
                    295:                goto out;
1.46      atatat    296:        }
                    297:
1.6       deraadt   298:        ifp = &tp->tun_if;
                    299:        tp->tun_flags |= TUN_OPEN;
1.24      thorpej   300:        TUNDEBUG("%s: open\n", ifp->if_xname);
1.70      pk        301: out:
1.46      atatat    302:        simple_unlock(&tp->tun_lock);
1.70      pk        303: out_nolock:
                    304:        splx(s);
                    305:        return (error);
1.1       cgd       306: }
                    307:
1.6       deraadt   308: /*
                    309:  * tunclose - close the device - mark i/f down & delete
                    310:  * routing info
                    311:  */
                    312: int
1.94      christos  313: tunclose(dev_t dev, int flag, int mode,
                    314:     struct lwp *l)
1.6       deraadt   315: {
1.46      atatat    316:        int     s;
                    317:        struct tun_softc *tp;
                    318:        struct ifnet    *ifp;
1.6       deraadt   319:
1.70      pk        320:        s = splnet();
                    321:        if ((tp = tun_find_zunit(minor(dev))) != NULL) {
                    322:                /* interface was "destroyed" before the close */
                    323:                free(tp, M_DEVBUF);
                    324:                goto out_nolock;
                    325:        }
1.46      atatat    326:
1.70      pk        327:        if ((tp = tun_find_unit(dev)) == NULL)
                    328:                goto out_nolock;
1.46      atatat    329:
                    330:        ifp = &tp->tun_if;
                    331:
1.10      andrew    332:        tp->tun_flags &= ~TUN_OPEN;
1.6       deraadt   333:
                    334:        /*
                    335:         * junk all pending output
                    336:         */
1.50      itojun    337:        IFQ_PURGE(&ifp->if_snd);
1.6       deraadt   338:
                    339:        if (ifp->if_flags & IFF_UP) {
                    340:                if_down(ifp);
1.8       deraadt   341:                if (ifp->if_flags & IFF_RUNNING) {
1.17      mycroft   342:                        /* find internet addresses and delete routes */
1.39      augustss  343:                        struct ifaddr *ifa;
1.76      matt      344:                        IFADDR_FOREACH(ifa, ifp) {
1.80      rpaulo    345: #if defined(INET) || defined(INET6)
                    346:                                if (ifa->ifa_addr->sa_family == AF_INET ||
                    347:                                    ifa->ifa_addr->sa_family == AF_INET6) {
1.18      mycroft   348:                                        rtinit(ifa, (int)RTM_DELETE,
1.26      pk        349:                                               tp->tun_flags & TUN_DSTADDR
                    350:                                                        ? RTF_HOST
                    351:                                                        : 0);
1.18      mycroft   352:                                }
1.38      itojun    353: #endif
1.11      deraadt   354:                        }
1.8       deraadt   355:                }
1.6       deraadt   356:        }
1.64      jdolecek  357:        tp->tun_pgid = 0;
1.56      jdolecek  358:        selnotify(&tp->tun_rsel, 0);
1.70      pk        359:
1.24      thorpej   360:        TUNDEBUG ("%s: closed\n", ifp->if_xname);
1.46      atatat    361:        simple_unlock(&tp->tun_lock);
1.70      pk        362: out_nolock:
                    363:        splx(s);
1.6       deraadt   364:        return (0);
1.1       cgd       365: }
                    366:
1.70      pk        367: /*
                    368:  * Call at splnet() with tp locked.
                    369:  */
1.26      pk        370: static void
1.78      thorpej   371: tuninit(struct tun_softc *tp)
1.6       deraadt   372: {
                    373:        struct ifnet    *ifp = &tp->tun_if;
1.46      atatat    374:        struct ifaddr   *ifa;
1.8       deraadt   375:
1.24      thorpej   376:        TUNDEBUG("%s: tuninit\n", ifp->if_xname);
1.6       deraadt   377:
                    378:        ifp->if_flags |= IFF_UP | IFF_RUNNING;
1.8       deraadt   379:
1.26      pk        380:        tp->tun_flags &= ~(TUN_IASET|TUN_DSTADDR);
1.76      matt      381:        IFADDR_FOREACH(ifa, ifp) {
1.38      itojun    382: #ifdef INET
1.11      deraadt   383:                if (ifa->ifa_addr->sa_family == AF_INET) {
1.17      mycroft   384:                        struct sockaddr_in *sin;
1.11      deraadt   385:
1.17      mycroft   386:                        sin = satosin(ifa->ifa_addr);
                    387:                        if (sin && sin->sin_addr.s_addr)
                    388:                                tp->tun_flags |= TUN_IASET;
                    389:
1.26      pk        390:                        if (ifp->if_flags & IFF_POINTOPOINT) {
                    391:                                sin = satosin(ifa->ifa_dstaddr);
                    392:                                if (sin && sin->sin_addr.s_addr)
                    393:                                        tp->tun_flags |= TUN_DSTADDR;
                    394:                        }
1.11      deraadt   395:                }
1.38      itojun    396: #endif
1.80      rpaulo    397: #ifdef INET6
                    398:                if (ifa->ifa_addr->sa_family == AF_INET6) {
                    399:                        struct sockaddr_in6 *sin;
                    400:
                    401:                        sin = (struct sockaddr_in6 *)ifa->ifa_addr;
                    402:                        if (!IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr))
                    403:                                tp->tun_flags |= TUN_IASET;
                    404:
                    405:                        if (ifp->if_flags & IFF_POINTOPOINT) {
                    406:                                sin = (struct sockaddr_in6 *)ifa->ifa_dstaddr;
                    407:                                if (sin &&
                    408:                                    !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr))
                    409:                                        tp->tun_flags |= TUN_DSTADDR;
                    410:                        } else
                    411:                                tp->tun_flags &= ~TUN_DSTADDR;
                    412:                }
                    413: #endif /* INET6 */
1.18      mycroft   414:        }
1.8       deraadt   415:
1.26      pk        416:        return;
1.1       cgd       417: }
                    418:
                    419: /*
                    420:  * Process an ioctl request.
                    421:  */
1.78      thorpej   422: static int
1.97      christos  423: tun_ioctl(struct ifnet *ifp, u_long cmd, void *data)
1.6       deraadt   424: {
                    425:        int             error = 0, s;
1.46      atatat    426:        struct tun_softc *tp = (struct tun_softc *)(ifp->if_softc);
                    427:
1.70      pk        428:        s = splnet();
1.46      atatat    429:        simple_lock(&tp->tun_lock);
1.6       deraadt   430:
1.61      itojun    431:        switch (cmd) {
1.6       deraadt   432:        case SIOCSIFADDR:
1.70      pk        433:                tuninit(tp);
1.24      thorpej   434:                TUNDEBUG("%s: address set\n", ifp->if_xname);
1.6       deraadt   435:                break;
                    436:        case SIOCSIFDSTADDR:
1.70      pk        437:                tuninit(tp);
1.24      thorpej   438:                TUNDEBUG("%s: destination address set\n", ifp->if_xname);
1.6       deraadt   439:                break;
1.26      pk        440:        case SIOCSIFBRDADDR:
                    441:                TUNDEBUG("%s: broadcast address set\n", ifp->if_xname);
                    442:                break;
1.31      matt      443:        case SIOCSIFMTU: {
                    444:                struct ifreq *ifr = (struct ifreq *) data;
                    445:                if (ifr->ifr_mtu > TUNMTU || ifr->ifr_mtu < 576) {
                    446:                    error = EINVAL;
                    447:                    break;
                    448:                }
                    449:                TUNDEBUG("%s: interface mtu set\n", ifp->if_xname);
                    450:                ifp->if_mtu = ifr->ifr_mtu;
1.32      matt      451:                break;
                    452:        }
                    453:        case SIOCADDMULTI:
                    454:        case SIOCDELMULTI: {
                    455:                struct ifreq *ifr = (struct ifreq *) data;
                    456:                if (ifr == 0) {
                    457:                        error = EAFNOSUPPORT;           /* XXX */
                    458:                        break;
                    459:                }
1.98      dyoung    460:                switch (ifreq_getaddr(cmd, ifr)->sa_family) {
1.32      matt      461: #ifdef INET
                    462:                case AF_INET:
                    463:                        break;
                    464: #endif
1.80      rpaulo    465: #ifdef INET6
                    466:                case AF_INET6:
                    467:                        break;
                    468: #endif
1.32      matt      469:                default:
                    470:                        error = EAFNOSUPPORT;
                    471:                        break;
                    472:                }
1.31      matt      473:                break;
                    474:        }
1.38      itojun    475:        case SIOCSIFFLAGS:
                    476:                break;
1.6       deraadt   477:        default:
                    478:                error = EINVAL;
                    479:        }
1.70      pk        480:
                    481:        simple_unlock(&tp->tun_lock);
1.6       deraadt   482:        splx(s);
                    483:        return (error);
1.1       cgd       484: }
                    485:
                    486: /*
1.22      christos  487:  * tun_output - queue packets from higher level ready to put out.
1.1       cgd       488:  */
1.78      thorpej   489: static int
1.96      dyoung    490: tun_output(struct ifnet *ifp, struct mbuf *m0, const struct sockaddr *dst,
1.94      christos  491:     struct rtentry *rt)
1.6       deraadt   492: {
1.24      thorpej   493:        struct tun_softc *tp = ifp->if_softc;
1.6       deraadt   494:        int             s;
1.51      itojun    495:        int             error;
1.80      rpaulo    496: #if defined(INET) || defined(INET6)
1.75      christos  497:        int             mlen;
1.80      rpaulo    498:        uint32_t        *af;
1.38      itojun    499: #endif
1.50      itojun    500:        ALTQ_DECL(struct altq_pktattr pktattr;)
1.6       deraadt   501:
1.70      pk        502:        s = splnet();
1.46      atatat    503:        simple_lock(&tp->tun_lock);
1.24      thorpej   504:        TUNDEBUG ("%s: tun_output\n", ifp->if_xname);
1.1       cgd       505:
1.8       deraadt   506:        if ((tp->tun_flags & TUN_READY) != TUN_READY) {
1.24      thorpej   507:                TUNDEBUG ("%s: not ready 0%o\n", ifp->if_xname,
                    508:                          tp->tun_flags);
1.8       deraadt   509:                m_freem (m0);
1.70      pk        510:                error = EHOSTDOWN;
                    511:                goto out;
1.8       deraadt   512:        }
                    513:
1.50      itojun    514:        /*
                    515:         * if the queueing discipline needs packet classification,
                    516:         * do it before prepending link headers.
                    517:         */
                    518:        IFQ_CLASSIFY(&ifp->if_snd, m0, dst->sa_family, &pktattr);
1.70      pk        519:
1.8       deraadt   520: #if NBPFILTER > 0
1.72      christos  521:        if (ifp->if_bpf)
                    522:                bpf_mtap_af(ifp->if_bpf, dst->sa_family, m0);
1.8       deraadt   523: #endif
                    524:
1.6       deraadt   525:        switch(dst->sa_family) {
1.79      rpaulo    526: #ifdef INET6
                    527:        case AF_INET6:
                    528: #endif
1.1       cgd       529: #ifdef INET
1.6       deraadt   530:        case AF_INET:
1.79      rpaulo    531: #endif
                    532: #if defined(INET) || defined(INET6)
1.26      pk        533:                if (tp->tun_flags & TUN_PREPADDR) {
                    534:                        /* Simple link-layer header */
                    535:                        M_PREPEND(m0, dst->sa_len, M_DONTWAIT);
                    536:                        if (m0 == NULL) {
                    537:                                IF_DROP(&ifp->if_snd);
1.70      pk        538:                                error = ENOBUFS;
                    539:                                goto out;
1.26      pk        540:                        }
                    541:                        bcopy(dst, mtod(m0, char *), dst->sa_len);
1.85      rpaulo    542:                }
                    543:
                    544:                if (tp->tun_flags & TUN_IFHEAD) {
1.81      rpaulo    545:                        /* Prepend the address family */
1.82      rpaulo    546:                        M_PREPEND(m0, sizeof(*af), M_DONTWAIT);
1.80      rpaulo    547:                        if (m0 == NULL) {
                    548:                                IF_DROP(&ifp->if_snd);
                    549:                                error = ENOBUFS;
                    550:                                goto out;
                    551:                        }
                    552:                        af = mtod(m0,uint32_t *);
                    553:                        *af = htonl(dst->sa_family);
1.86      rpaulo    554:                } else {
                    555: #ifdef INET
                    556:                        if (dst->sa_family != AF_INET)
                    557: #endif
                    558:                        {
                    559:                                m_freem(m0);
                    560:                                error = EAFNOSUPPORT;
                    561:                                goto out;
                    562:                        }
1.26      pk        563:                }
1.36      sommerfe  564:                /* FALLTHROUGH */
                    565:        case AF_UNSPEC:
1.50      itojun    566:                IFQ_ENQUEUE(&ifp->if_snd, m0, &pktattr, error);
                    567:                if (error) {
1.6       deraadt   568:                        ifp->if_collisions++;
1.70      pk        569:                        error = EAFNOSUPPORT;
                    570:                        goto out;
1.6       deraadt   571:                }
1.58      jdolecek  572:                mlen = m0->m_pkthdr.len;
1.6       deraadt   573:                ifp->if_opackets++;
1.58      jdolecek  574:                ifp->if_obytes += mlen;
1.6       deraadt   575:                break;
1.1       cgd       576: #endif
1.6       deraadt   577:        default:
                    578:                m_freem(m0);
1.70      pk        579:                error = EAFNOSUPPORT;
                    580:                goto out;
1.6       deraadt   581:        }
                    582:
                    583:        if (tp->tun_flags & TUN_RWAIT) {
                    584:                tp->tun_flags &= ~TUN_RWAIT;
1.97      christos  585:                wakeup((void *)tp);
1.6       deraadt   586:        }
1.64      jdolecek  587:        if (tp->tun_flags & TUN_ASYNC && tp->tun_pgid)
1.66      christos  588:                fownsignal(tp->tun_pgid, SIGIO, POLL_IN, POLLIN|POLLRDNORM,
                    589:                    NULL);
1.64      jdolecek  590:
1.56      jdolecek  591:        selnotify(&tp->tun_rsel, 0);
1.70      pk        592: out:
1.46      atatat    593:        simple_unlock(&tp->tun_lock);
1.70      pk        594:        splx(s);
1.26      pk        595:        return (0);
1.1       cgd       596: }
                    597:
                    598: /*
                    599:  * the cdevsw interface is now pretty minimal.
                    600:  */
1.6       deraadt   601: int
1.97      christos  602: tunioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
1.6       deraadt   603: {
1.46      atatat    604:        struct tun_softc *tp;
1.70      pk        605:        int s, error = 0;
1.46      atatat    606:
1.70      pk        607:        s = splnet();
1.46      atatat    608:        tp = tun_find_unit(dev);
                    609:
                    610:        /* interface was "destroyed" already */
1.70      pk        611:        if (tp == NULL) {
                    612:                error = ENXIO;
                    613:                goto out_nolock;
                    614:        }
1.6       deraadt   615:
                    616:        switch (cmd) {
                    617:        case TUNSDEBUG:
                    618:                tundebug = *(int *)data;
                    619:                break;
1.26      pk        620:
1.6       deraadt   621:        case TUNGDEBUG:
                    622:                *(int *)data = tundebug;
                    623:                break;
1.26      pk        624:
                    625:        case TUNSIFMODE:
1.31      matt      626:                switch (*(int *)data & (IFF_POINTOPOINT|IFF_BROADCAST)) {
1.26      pk        627:                case IFF_POINTOPOINT:
                    628:                case IFF_BROADCAST:
                    629:                        if (tp->tun_if.if_flags & IFF_UP) {
1.70      pk        630:                                error = EBUSY;
                    631:                                goto out;
1.26      pk        632:                        }
                    633:                        tp->tun_if.if_flags &=
1.31      matt      634:                                ~(IFF_BROADCAST|IFF_POINTOPOINT|IFF_MULTICAST);
1.26      pk        635:                        tp->tun_if.if_flags |= *(int *)data;
                    636:                        break;
                    637:                default:
1.70      pk        638:                        error = EINVAL;
                    639:                        goto out;
1.26      pk        640:                }
                    641:                break;
                    642:
                    643:        case TUNSLMODE:
1.87      rpaulo    644:                if (*(int *)data) {
1.26      pk        645:                        tp->tun_flags |= TUN_PREPADDR;
1.87      rpaulo    646:                        tp->tun_flags &= ~TUN_IFHEAD;
                    647:                } else
1.26      pk        648:                        tp->tun_flags &= ~TUN_PREPADDR;
                    649:                break;
                    650:
1.84      rpaulo    651:        case TUNSIFHEAD:
1.87      rpaulo    652:                if (*(int *)data) {
1.84      rpaulo    653:                        tp->tun_flags |= TUN_IFHEAD;
1.88      rpaulo    654:                        tp->tun_flags &= ~TUN_PREPADDR;
1.87      rpaulo    655:                } else
1.84      rpaulo    656:                        tp->tun_flags &= ~TUN_IFHEAD;
                    657:                break;
                    658:
                    659:        case TUNGIFHEAD:
                    660:                *(int *)data = (tp->tun_flags & TUN_IFHEAD);
                    661:                break;
                    662:
1.6       deraadt   663:        case FIONBIO:
                    664:                if (*(int *)data)
                    665:                        tp->tun_flags |= TUN_NBIO;
                    666:                else
                    667:                        tp->tun_flags &= ~TUN_NBIO;
                    668:                break;
1.26      pk        669:
1.6       deraadt   670:        case FIOASYNC:
                    671:                if (*(int *)data)
                    672:                        tp->tun_flags |= TUN_ASYNC;
                    673:                else
                    674:                        tp->tun_flags &= ~TUN_ASYNC;
                    675:                break;
1.26      pk        676:
1.6       deraadt   677:        case FIONREAD:
                    678:                if (tp->tun_if.if_snd.ifq_head)
1.19      pk        679:                        *(int *)data = tp->tun_if.if_snd.ifq_head->m_pkthdr.len;
1.70      pk        680:                else
1.6       deraadt   681:                        *(int *)data = 0;
                    682:                break;
1.26      pk        683:
1.6       deraadt   684:        case TIOCSPGRP:
1.64      jdolecek  685:        case FIOSETOWN:
1.77      christos  686:                error = fsetown(l->l_proc, &tp->tun_pgid, cmd, data);
1.6       deraadt   687:                break;
1.26      pk        688:
1.6       deraadt   689:        case TIOCGPGRP:
1.64      jdolecek  690:        case FIOGETOWN:
1.77      christos  691:                error = fgetown(l->l_proc, tp->tun_pgid, cmd, data);
1.6       deraadt   692:                break;
1.26      pk        693:
1.6       deraadt   694:        default:
1.70      pk        695:                error = ENOTTY;
1.6       deraadt   696:        }
1.70      pk        697:
                    698: out:
1.46      atatat    699:        simple_unlock(&tp->tun_lock);
1.70      pk        700: out_nolock:
                    701:        splx(s);
1.64      jdolecek  702:        return (error);
1.1       cgd       703: }
                    704:
                    705: /*
1.6       deraadt   706:  * The cdevsw read interface - reads a packet at a time, or at
                    707:  * least as much of a packet as can be read.
1.1       cgd       708:  */
1.6       deraadt   709: int
1.94      christos  710: tunread(dev_t dev, struct uio *uio, int ioflag)
1.6       deraadt   711: {
1.46      atatat    712:        struct tun_softc *tp;
                    713:        struct ifnet    *ifp;
1.6       deraadt   714:        struct mbuf     *m, *m0;
1.70      pk        715:        int             error = 0, len, s, index;
1.46      atatat    716:
1.70      pk        717:        s = splnet();
1.46      atatat    718:        tp = tun_find_unit(dev);
                    719:
                    720:        /* interface was "destroyed" already */
1.70      pk        721:        if (tp == NULL) {
                    722:                error = ENXIO;
                    723:                goto out_nolock;
                    724:        }
1.46      atatat    725:
                    726:        index = tp->tun_if.if_index;
                    727:        ifp = &tp->tun_if;
1.6       deraadt   728:
1.24      thorpej   729:        TUNDEBUG ("%s: read\n", ifp->if_xname);
1.8       deraadt   730:        if ((tp->tun_flags & TUN_READY) != TUN_READY) {
1.26      pk        731:                TUNDEBUG ("%s: not ready 0%o\n", ifp->if_xname, tp->tun_flags);
1.70      pk        732:                error = EHOSTDOWN;
                    733:                goto out;
1.8       deraadt   734:        }
                    735:
1.6       deraadt   736:        tp->tun_flags &= ~TUN_RWAIT;
                    737:
                    738:        do {
1.50      itojun    739:                IFQ_DEQUEUE(&ifp->if_snd, m0);
1.6       deraadt   740:                if (m0 == 0) {
                    741:                        if (tp->tun_flags & TUN_NBIO) {
1.70      pk        742:                                error = EWOULDBLOCK;
                    743:                                goto out;
1.6       deraadt   744:                        }
                    745:                        tp->tun_flags |= TUN_RWAIT;
1.97      christos  746:                        if (ltsleep((void *)tp, PZERO|PCATCH|PNORELOCK,
1.70      pk        747:                                        "tunread", 0, &tp->tun_lock) != 0) {
                    748:                                error = EINTR;
                    749:                                goto out_nolock;
1.46      atatat    750:                        } else {
                    751:                                /*
                    752:                                 * Maybe the interface was destroyed while
                    753:                                 * we were sleeping, so let's ensure that
                    754:                                 * we're looking at the same (valid) tun
                    755:                                 * interface before looping.
                    756:                                 */
                    757:                                tp = tun_find_unit(dev);
1.70      pk        758:                                if (tp == NULL) {
                    759:                                        error = ENXIO;
                    760:                                        goto out_nolock;
                    761:                                }
                    762:                                if (tp->tun_if.if_index != index) {
                    763:                                        error = ENXIO;
                    764:                                        goto out;
1.46      atatat    765:                                }
1.26      pk        766:                        }
1.6       deraadt   767:                }
                    768:        } while (m0 == 0);
1.70      pk        769:
                    770:        simple_unlock(&tp->tun_lock);
1.6       deraadt   771:        splx(s);
                    772:
1.70      pk        773:        /* Copy the mbuf chain */
1.6       deraadt   774:        while (m0 && uio->uio_resid > 0 && error == 0) {
1.13      deraadt   775:                len = min(uio->uio_resid, m0->m_len);
1.45      itojun    776:                if (len != 0)
1.97      christos  777:                        error = uiomove(mtod(m0, void *), len, uio);
1.6       deraadt   778:                MFREE(m0, m);
                    779:                m0 = m;
                    780:        }
                    781:
                    782:        if (m0) {
                    783:                TUNDEBUG("Dropping mbuf\n");
                    784:                m_freem(m0);
                    785:        }
1.19      pk        786:        if (error)
                    787:                ifp->if_ierrors++;
1.70      pk        788:
                    789:        return (error);
                    790:
                    791: out:
1.46      atatat    792:        simple_unlock(&tp->tun_lock);
1.70      pk        793: out_nolock:
                    794:        splx(s);
1.26      pk        795:        return (error);
1.1       cgd       796: }
                    797:
                    798: /*
                    799:  * the cdevsw write interface - an atomic write is a packet - or else!
                    800:  */
1.6       deraadt   801: int
1.94      christos  802: tunwrite(dev_t dev, struct uio *uio, int ioflag)
1.6       deraadt   803: {
1.46      atatat    804:        struct tun_softc *tp;
                    805:        struct ifnet    *ifp;
1.6       deraadt   806:        struct mbuf     *top, **mp, *m;
1.26      pk        807:        struct ifqueue  *ifq;
                    808:        struct sockaddr dst;
1.70      pk        809:        int             isr, error = 0, s, tlen, mlen;
1.80      rpaulo    810:        uint32_t        family;
1.6       deraadt   811:
1.70      pk        812:        s = splnet();
1.46      atatat    813:        tp = tun_find_unit(dev);
                    814:
                    815:        /* interface was "destroyed" already */
1.70      pk        816:        if (tp == NULL) {
                    817:                error = ENXIO;
                    818:                goto out_nolock;
                    819:        }
                    820:
                    821:        /* Unlock until we've got the data */
                    822:        simple_unlock(&tp->tun_lock);
                    823:        splx(s);
1.46      atatat    824:
                    825:        ifp = &tp->tun_if;
                    826:
1.24      thorpej   827:        TUNDEBUG("%s: tunwrite\n", ifp->if_xname);
1.6       deraadt   828:
1.26      pk        829:        if (tp->tun_flags & TUN_PREPADDR) {
1.46      atatat    830:                if (uio->uio_resid < sizeof(dst)) {
1.70      pk        831:                        error = EIO;
                    832:                        goto out0;
1.46      atatat    833:                }
1.97      christos  834:                error = uiomove((void *)&dst, sizeof(dst), uio);
1.26      pk        835:                if (dst.sa_len > sizeof(dst)) {
                    836:                        /* Duh.. */
                    837:                        char discard;
                    838:                        int n = dst.sa_len - sizeof(dst);
                    839:                        while (n--)
1.46      atatat    840:                                if ((error = uiomove(&discard, 1, uio)) != 0) {
1.70      pk        841:                                        goto out0;
1.46      atatat    842:                                }
1.26      pk        843:                }
1.85      rpaulo    844:        } else if (tp->tun_flags & TUN_IFHEAD) {
1.80      rpaulo    845:                if (uio->uio_resid < sizeof(family)){
                    846:                        error = EIO;
                    847:                        goto out0;
                    848:                }
1.97      christos  849:                error = uiomove((void *)&family, sizeof(family), uio);
1.80      rpaulo    850:                dst.sa_family = ntohl(family);
1.85      rpaulo    851:        } else {
                    852: #ifdef INET
                    853:                dst.sa_family = AF_INET;
                    854: #endif
1.26      pk        855:        }
                    856:
1.54      simonb    857:        if (uio->uio_resid > TUNMTU) {
1.37      mjacob    858:                TUNDEBUG("%s: len=%lu!\n", ifp->if_xname,
                    859:                    (unsigned long)uio->uio_resid);
1.70      pk        860:                error = EIO;
                    861:                goto out0;
1.6       deraadt   862:        }
1.26      pk        863:
                    864:        switch (dst.sa_family) {
                    865: #ifdef INET
                    866:        case AF_INET:
                    867:                ifq = &ipintrq;
                    868:                isr = NETISR_IP;
                    869:                break;
                    870: #endif
1.79      rpaulo    871: #ifdef INET6
                    872:        case AF_INET6:
                    873:                ifq = &ip6intrq;
                    874:                isr = NETISR_IPV6;
1.83      rpaulo    875:                break;
1.79      rpaulo    876: #endif
1.26      pk        877:        default:
1.70      pk        878:                error = EAFNOSUPPORT;
                    879:                goto out0;
1.26      pk        880:        }
                    881:
1.8       deraadt   882:        tlen = uio->uio_resid;
                    883:
                    884:        /* get a header mbuf */
                    885:        MGETHDR(m, M_DONTWAIT, MT_DATA);
1.46      atatat    886:        if (m == NULL) {
1.70      pk        887:                error = ENOBUFS;
                    888:                goto out0;
1.46      atatat    889:        }
1.8       deraadt   890:        mlen = MHLEN;
                    891:
1.68      tron      892:        top = NULL;
1.6       deraadt   893:        mp = &top;
                    894:        while (error == 0 && uio->uio_resid > 0) {
1.13      deraadt   895:                m->m_len = min(mlen, uio->uio_resid);
1.97      christos  896:                error = uiomove(mtod(m, void *), m->m_len, uio);
1.6       deraadt   897:                *mp = m;
                    898:                mp = &m->m_next;
1.68      tron      899:                if (error == 0 && uio->uio_resid > 0) {
                    900:                        MGET(m, M_DONTWAIT, MT_DATA);
                    901:                        if (m == NULL) {
1.8       deraadt   902:                                error = ENOBUFS;
                    903:                                break;
                    904:                        }
                    905:                        mlen = MLEN;
                    906:                }
1.6       deraadt   907:        }
                    908:        if (error) {
1.68      tron      909:                if (top != NULL)
1.8       deraadt   910:                        m_freem (top);
1.19      pk        911:                ifp->if_ierrors++;
1.70      pk        912:                goto out0;
1.6       deraadt   913:        }
                    914:
1.8       deraadt   915:        top->m_pkthdr.len = tlen;
                    916:        top->m_pkthdr.rcvif = ifp;
                    917:
                    918: #if NBPFILTER > 0
1.72      christos  919:        if (ifp->if_bpf)
1.80      rpaulo    920:                bpf_mtap_af(ifp->if_bpf, dst.sa_family, top);
1.8       deraadt   921: #endif
1.6       deraadt   922:
1.43      thorpej   923:        s = splnet();
1.70      pk        924:        simple_lock(&tp->tun_lock);
                    925:        if ((tp->tun_flags & TUN_INITED) == 0) {
                    926:                /* Interface was destroyed */
                    927:                error = ENXIO;
                    928:                goto out;
                    929:        }
1.26      pk        930:        if (IF_QFULL(ifq)) {
                    931:                IF_DROP(ifq);
1.6       deraadt   932:                ifp->if_collisions++;
                    933:                m_freem(top);
1.70      pk        934:                error = ENOBUFS;
                    935:                goto out;
1.6       deraadt   936:        }
1.70      pk        937:
1.26      pk        938:        IF_ENQUEUE(ifq, top);
1.6       deraadt   939:        ifp->if_ipackets++;
1.58      jdolecek  940:        ifp->if_ibytes += tlen;
1.26      pk        941:        schednetisr(isr);
1.70      pk        942: out:
1.46      atatat    943:        simple_unlock(&tp->tun_lock);
1.70      pk        944: out_nolock:
                    945:        splx(s);
                    946: out0:
1.26      pk        947:        return (error);
1.1       cgd       948: }
                    949:
1.50      itojun    950: #ifdef ALTQ
                    951: /*
                    952:  * Start packet transmission on the interface.
                    953:  * when the interface queue is rate-limited by ALTQ or TBR,
                    954:  * if_start is needed to drain packets from the queue in order
                    955:  * to notify readers when outgoing packets become ready.
1.70      pk        956:  *
                    957:  * Should be called at splnet.
1.50      itojun    958:  */
                    959: static void
1.78      thorpej   960: tunstart(struct ifnet *ifp)
1.50      itojun    961: {
                    962:        struct tun_softc *tp = ifp->if_softc;
                    963:
                    964:        if (!ALTQ_IS_ENABLED(&ifp->if_snd) && !TBR_IS_ENABLED(&ifp->if_snd))
                    965:                return;
                    966:
1.70      pk        967:        simple_lock(&tp->tun_lock);
                    968:        if (!IF_IS_EMPTY(&ifp->if_snd)) {
1.50      itojun    969:                if (tp->tun_flags & TUN_RWAIT) {
                    970:                        tp->tun_flags &= ~TUN_RWAIT;
1.97      christos  971:                        wakeup((void *)tp);
1.50      itojun    972:                }
1.64      jdolecek  973:                if (tp->tun_flags & TUN_ASYNC && tp->tun_pgid)
1.67      cl        974:                        fownsignal(tp->tun_pgid, SIGIO, POLL_OUT,
                    975:                                POLLOUT|POLLWRNORM, NULL);
1.70      pk        976:
1.50      itojun    977:                selwakeup(&tp->tun_rsel);
                    978:        }
1.70      pk        979:        simple_unlock(&tp->tun_lock);
1.50      itojun    980: }
                    981: #endif /* ALTQ */
1.1       cgd       982: /*
1.27      mycroft   983:  * tunpoll - the poll interface, this is only useful on reads
1.6       deraadt   984:  * really. The write detect always returns true, write never blocks
                    985:  * anyway, it either accepts the packet or drops it.
                    986:  */
                    987: int
1.78      thorpej   988: tunpoll(dev_t dev, int events, struct lwp *l)
1.6       deraadt   989: {
1.46      atatat    990:        struct tun_softc *tp;
                    991:        struct ifnet    *ifp;
                    992:        int             s, revents = 0;
                    993:
1.70      pk        994:        s = splnet();
1.46      atatat    995:        tp = tun_find_unit(dev);
                    996:
                    997:        /* interface was "destroyed" already */
                    998:        if (tp == NULL)
1.70      pk        999:                goto out_nolock;
1.46      atatat   1000:
                   1001:        ifp = &tp->tun_if;
1.6       deraadt  1002:
1.27      mycroft  1003:        TUNDEBUG("%s: tunpoll\n", ifp->if_xname);
1.6       deraadt  1004:
1.35      veego    1005:        if (events & (POLLIN | POLLRDNORM)) {
1.70      pk       1006:                if (!IFQ_IS_EMPTY(&ifp->if_snd)) {
1.27      mycroft  1007:                        TUNDEBUG("%s: tunpoll q=%d\n", ifp->if_xname,
1.24      thorpej  1008:                            ifp->if_snd.ifq_len);
1.27      mycroft  1009:                        revents |= events & (POLLIN | POLLRDNORM);
                   1010:                } else {
                   1011:                        TUNDEBUG("%s: tunpoll waiting\n", ifp->if_xname);
1.77      christos 1012:                        selrecord(l, &tp->tun_rsel);
1.6       deraadt  1013:                }
1.35      veego    1014:        }
1.27      mycroft  1015:
                   1016:        if (events & (POLLOUT | POLLWRNORM))
                   1017:                revents |= events & (POLLOUT | POLLWRNORM);
                   1018:
1.70      pk       1019:        simple_unlock(&tp->tun_lock);
                   1020: out_nolock:
1.6       deraadt  1021:        splx(s);
1.27      mycroft  1022:        return (revents);
1.56      jdolecek 1023: }
                   1024:
                   1025: static void
                   1026: filt_tunrdetach(struct knote *kn)
                   1027: {
                   1028:        struct tun_softc *tp = kn->kn_hook;
                   1029:        int s;
                   1030:
                   1031:        s = splnet();
1.57      christos 1032:        SLIST_REMOVE(&tp->tun_rsel.sel_klist, kn, knote, kn_selnext);
1.56      jdolecek 1033:        splx(s);
                   1034: }
                   1035:
                   1036: static int
1.94      christos 1037: filt_tunread(struct knote *kn, long hint)
1.56      jdolecek 1038: {
                   1039:        struct tun_softc *tp = kn->kn_hook;
                   1040:        struct ifnet *ifp = &tp->tun_if;
                   1041:        struct mbuf *m;
                   1042:        int s;
                   1043:
                   1044:        s = splnet();
                   1045:        IF_POLL(&ifp->if_snd, m);
                   1046:        if (m == NULL) {
                   1047:                splx(s);
                   1048:                return (0);
                   1049:        }
                   1050:
                   1051:        for (kn->kn_data = 0; m != NULL; m = m->m_next)
                   1052:                kn->kn_data += m->m_len;
                   1053:
                   1054:        splx(s);
                   1055:        return (1);
                   1056: }
                   1057:
                   1058: static const struct filterops tunread_filtops =
                   1059:        { 1, NULL, filt_tunrdetach, filt_tunread };
                   1060:
                   1061: static const struct filterops tun_seltrue_filtops =
                   1062:        { 1, NULL, filt_tunrdetach, filt_seltrue };
                   1063:
                   1064: int
                   1065: tunkqfilter(dev_t dev, struct knote *kn)
                   1066: {
1.70      pk       1067:        struct tun_softc *tp;
1.56      jdolecek 1068:        struct klist *klist;
1.70      pk       1069:        int rv = 0, s;
                   1070:
                   1071:        s = splnet();
                   1072:        tp = tun_find_unit(dev);
                   1073:        if (tp == NULL)
                   1074:                goto out_nolock;
1.56      jdolecek 1075:
                   1076:        switch (kn->kn_filter) {
                   1077:        case EVFILT_READ:
1.57      christos 1078:                klist = &tp->tun_rsel.sel_klist;
1.56      jdolecek 1079:                kn->kn_fop = &tunread_filtops;
                   1080:                break;
                   1081:
                   1082:        case EVFILT_WRITE:
1.57      christos 1083:                klist = &tp->tun_rsel.sel_klist;
1.56      jdolecek 1084:                kn->kn_fop = &tun_seltrue_filtops;
                   1085:                break;
                   1086:
                   1087:        default:
1.100   ! pooka    1088:                rv = EINVAL;
1.70      pk       1089:                goto out;
1.56      jdolecek 1090:        }
                   1091:
                   1092:        kn->kn_hook = tp;
                   1093:
                   1094:        SLIST_INSERT_HEAD(klist, kn, kn_selnext);
1.70      pk       1095:
                   1096: out:
                   1097:        simple_unlock(&tp->tun_lock);
                   1098: out_nolock:
1.56      jdolecek 1099:        splx(s);
1.70      pk       1100:        return (rv);
1.1       cgd      1101: }

CVSweb <webmaster@jp.NetBSD.org>