[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.82.2.5

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

CVSweb <webmaster@jp.NetBSD.org>