The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net/if_tun.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: if_tun.c,v 1.14 1994/06/29 06:36:25 cgd Exp $  */
    2 
    3 /*
    4  * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk>
    5  * Nottingham University 1987.
    6  *
    7  * This source may be freely distributed, however I would be interested
    8  * in any changes that are made.
    9  *
   10  * This driver takes packets off the IP i/f and hands them up to a
   11  * user process to have its wicked way with. This driver has it's
   12  * roots in a similar driver written by Phil Cockcroft (formerly) at
   13  * UCL. This driver is based much more on read/write/poll mode of
   14  * operation though.
   15  *
   16  * $FreeBSD: releng/5.0/sys/net/if_tun.c 106939 2002-11-15 00:00:15Z sam $
   17  */
   18 
   19 #include "opt_inet.h"
   20 #include "opt_mac.h"
   21 
   22 #include <sys/param.h>
   23 #include <sys/proc.h>
   24 #include <sys/systm.h>
   25 #include <sys/mac.h>
   26 #include <sys/mbuf.h>
   27 #include <sys/module.h>
   28 #include <sys/socket.h>
   29 #include <sys/filio.h>
   30 #include <sys/sockio.h>
   31 #include <sys/ttycom.h>
   32 #include <sys/poll.h>
   33 #include <sys/signalvar.h>
   34 #include <sys/filedesc.h>
   35 #include <sys/kernel.h>
   36 #include <sys/sysctl.h>
   37 #include <sys/conf.h>
   38 #include <sys/uio.h>
   39 #include <sys/vnode.h>
   40 #include <sys/malloc.h>
   41 #include <machine/bus.h>        /* XXX Shouldn't really be required ! */
   42 #include <sys/rman.h>
   43 
   44 #include <net/if.h>
   45 #include <net/if_types.h>
   46 #include <net/route.h>
   47 #include <net/intrq.h>
   48 #ifdef INET
   49 #include <netinet/in.h>
   50 #endif
   51 #include <net/bpf.h>
   52 #include <net/if_tunvar.h>
   53 #include <net/if_tun.h>
   54 
   55 #define TUNDEBUG        if (tundebug) printf
   56 #define TUNNAME         "tun"
   57 #define TUN_MAXUNIT     0x7fff  /* ifp->if_unit is only 15 bits */
   58 
   59 static MALLOC_DEFINE(M_TUN, TUNNAME, "Tunnel Interface");
   60 static int tundebug = 0;
   61 static struct tun_softc *tunhead = NULL;
   62 static struct rman tununits;
   63 static udev_t tunbasedev = NOUDEV;
   64 SYSCTL_INT(_debug, OID_AUTO, if_tun_debug, CTLFLAG_RW, &tundebug, 0, "");
   65 
   66 static void     tunclone(void *arg, char *name, int namelen, dev_t *dev);
   67 static void     tuncreate(dev_t dev);
   68 static int      tunifioctl(struct ifnet *, u_long, caddr_t);
   69 static int      tuninit(struct ifnet *);
   70 static int      tunmodevent(module_t, int, void *);
   71 static int      tunoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
   72                     struct rtentry *rt);
   73 static void     tunstart(struct ifnet *);
   74 
   75 static d_open_t         tunopen;
   76 static d_close_t        tunclose;
   77 static d_read_t         tunread;
   78 static d_write_t        tunwrite;
   79 static d_ioctl_t        tunioctl;
   80 static d_poll_t         tunpoll;
   81 
   82 #define CDEV_MAJOR 52
   83 static struct cdevsw tun_cdevsw = {
   84         /* open */      tunopen,
   85         /* close */     tunclose,
   86         /* read */      tunread,
   87         /* write */     tunwrite,
   88         /* ioctl */     tunioctl,
   89         /* poll */      tunpoll,
   90         /* mmap */      nommap,
   91         /* strategy */  nostrategy,
   92         /* name */      TUNNAME,
   93         /* maj */       CDEV_MAJOR,
   94         /* dump */      nodump,
   95         /* psize */     nopsize,
   96         /* flags */     0,
   97 };
   98 
   99 static void
  100 tunclone(void *arg, char *name, int namelen, dev_t *dev)
  101 {
  102         struct resource *r;
  103         int err;
  104         int u;
  105 
  106         if (*dev != NODEV)
  107                 return;
  108 
  109         if (strcmp(name, TUNNAME) == 0) {
  110                 r = rman_reserve_resource(&tununits, 0, TUN_MAXUNIT, 1,
  111                     RF_ALLOCATED | RF_ACTIVE, NULL);
  112                 u = rman_get_start(r);
  113                 err = rman_release_resource(r);
  114                 KASSERT(err == 0, ("Unexpected failure releasing resource"));
  115                 *dev = makedev(CDEV_MAJOR, unit2minor(u));
  116                 if ((*dev)->si_flags & SI_NAMED)
  117                         return; /* Already make_dev()d */
  118         } else if (dev_stdclone(name, NULL, TUNNAME, &u) != 1)
  119                 return; /* Don't recognise the name */
  120 
  121         *dev = make_dev(&tun_cdevsw, unit2minor(u),
  122             UID_ROOT, GID_WHEEL, 0600, "tun%d", u);
  123 
  124         /*
  125          * All devices depend on tunbasedev so that we can simply
  126          * destroy_dev() this device at module unload time to get
  127          * rid of all our make_dev()d resources.
  128          */
  129         if (tunbasedev == NOUDEV)
  130                 tunbasedev = (*dev)->si_udev;
  131         else {
  132                 (*dev)->si_flags |= SI_CHEAPCLONE;
  133                 dev_depends(udev2dev(tunbasedev, 0), *dev);
  134         }
  135 }
  136 
  137 static int
  138 tunmodevent(module_t mod, int type, void *data) 
  139 {
  140         static eventhandler_tag tag;
  141         struct tun_softc *tp;
  142         dev_t dev;
  143         int err;
  144 
  145         switch (type) { 
  146         case MOD_LOAD: 
  147                 tag = EVENTHANDLER_REGISTER(dev_clone, tunclone, 0, 1000);
  148                 if (tag == NULL)
  149                         return (ENOMEM);
  150                 if (!devfs_present) {
  151                         err = cdevsw_add(&tun_cdevsw);
  152                         if (err != 0) {
  153                                 EVENTHANDLER_DEREGISTER(dev_clone, tag);
  154                                 return (err);
  155                         }
  156                 }
  157                 tununits.rm_type = RMAN_ARRAY;
  158                 tununits.rm_descr = "open if_tun units";
  159                 err = rman_init(&tununits);
  160                 if (err != 0) {
  161                         cdevsw_remove(&tun_cdevsw);
  162                         EVENTHANDLER_DEREGISTER(dev_clone, tag);
  163                         return (err);
  164                 }
  165                 err = rman_manage_region(&tununits, 0, TUN_MAXUNIT);
  166                 if (err != 0) {
  167                         printf("%s: tununits: rman_manage_region: Failed %d\n",
  168                             TUNNAME, err);
  169                         rman_fini(&tununits);
  170                         cdevsw_remove(&tun_cdevsw);
  171                         EVENTHANDLER_DEREGISTER(dev_clone, tag);
  172                         return (err);
  173                 }
  174                 break; 
  175         case MOD_UNLOAD: 
  176                 err = rman_fini(&tununits);
  177                 if (err != 0)
  178                         return (err);
  179                 EVENTHANDLER_DEREGISTER(dev_clone, tag);
  180 
  181                 while (tunhead != NULL) {
  182                         KASSERT((tunhead->tun_flags & TUN_OPEN) == 0,
  183                             ("tununits is out of sync - unit %d",
  184                             tunhead->tun_if.if_unit));
  185                         tp = tunhead;
  186                         dev = makedev(tun_cdevsw.d_maj,
  187                             unit2minor(tp->tun_if.if_unit));
  188                         KASSERT(dev->si_drv1 == tp, ("Bad makedev result"));
  189                         tunhead = tp->next;
  190                         bpfdetach(&tp->tun_if);
  191                         if_detach(&tp->tun_if);
  192                         KASSERT(dev->si_flags & SI_NAMED, ("Missing make_dev"));
  193                         free(tp, M_TUN);
  194                 }
  195 
  196                 /*
  197                  * Destroying tunbasedev results in all of our make_dev()s
  198                  * conveniently going away.
  199                  */
  200                 if (tunbasedev != NOUDEV)
  201                         destroy_dev(udev2dev(tunbasedev, 0));
  202 
  203                 if (!devfs_present)
  204                         cdevsw_remove(&tun_cdevsw);
  205                 break;
  206         } 
  207         return 0; 
  208 } 
  209 
  210 static moduledata_t tun_mod = { 
  211         "if_tun", 
  212         tunmodevent, 
  213         0
  214 }; 
  215 
  216 DECLARE_MODULE(if_tun, tun_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
  217 
  218 static void
  219 tunstart(struct ifnet *ifp)
  220 {
  221         struct tun_softc *tp = ifp->if_softc;
  222 
  223         if (tp->tun_flags & TUN_RWAIT) {
  224                 tp->tun_flags &= ~TUN_RWAIT;
  225                 wakeup((caddr_t)tp);
  226         }
  227         if (tp->tun_flags & TUN_ASYNC && tp->tun_sigio)
  228                 pgsigio(&tp->tun_sigio, SIGIO, 0);
  229         selwakeup(&tp->tun_rsel);
  230 }
  231 
  232 static void
  233 tuncreate(dev_t dev)
  234 {
  235         struct tun_softc *sc;
  236         struct ifnet *ifp;
  237 
  238         if (!(dev->si_flags & SI_NAMED))
  239                 dev = make_dev(&tun_cdevsw, minor(dev),
  240                     UID_UUCP, GID_DIALER, 0600, "tun%d", dev2unit(dev));
  241 
  242         MALLOC(sc, struct tun_softc *, sizeof(*sc), M_TUN, M_WAITOK | M_ZERO);
  243         sc->tun_flags = TUN_INITED;
  244         sc->next = tunhead;
  245         tunhead = sc;
  246 
  247         ifp = &sc->tun_if;
  248         ifp->if_unit = dev2unit(dev);
  249         ifp->if_name = TUNNAME;
  250         ifp->if_mtu = TUNMTU;
  251         ifp->if_ioctl = tunifioctl;
  252         ifp->if_output = tunoutput;
  253         ifp->if_start = tunstart;
  254         ifp->if_flags = IFF_POINTOPOINT | IFF_MULTICAST;
  255         ifp->if_type = IFT_PPP;
  256         ifp->if_snd.ifq_maxlen = ifqmaxlen;
  257         ifp->if_softc = sc;
  258         if_attach(ifp);
  259         bpfattach(ifp, DLT_NULL, sizeof(u_int));
  260         dev->si_drv1 = sc;
  261 }
  262 
  263 static int
  264 tunopen(dev_t dev, int flag, int mode, struct thread *td)
  265 {
  266         struct resource *r;
  267         struct ifnet    *ifp;
  268         struct tun_softc *tp;
  269         int unit;
  270 
  271         unit = dev2unit(dev);
  272         if (unit > TUN_MAXUNIT)
  273                 return (ENXIO);
  274 
  275         r = rman_reserve_resource(&tununits, unit, unit, 1,
  276             RF_ALLOCATED | RF_ACTIVE, NULL);
  277         if (r == NULL)
  278                 return (EBUSY);
  279 
  280         dev->si_flags &= ~SI_CHEAPCLONE;
  281 
  282         tp = dev->si_drv1;
  283         if (!tp) {
  284                 tuncreate(dev);
  285                 tp = dev->si_drv1;
  286         }
  287         KASSERT(!(tp->tun_flags & TUN_OPEN), ("Resource & flags out-of-sync"));
  288         tp->r_unit = r;
  289         tp->tun_pid = td->td_proc->p_pid;
  290         ifp = &tp->tun_if;
  291         tp->tun_flags |= TUN_OPEN;
  292         TUNDEBUG("%s%d: open\n", ifp->if_name, ifp->if_unit);
  293 
  294         return (0);
  295 }
  296 
  297 /*
  298  * tunclose - close the device - mark i/f down & delete
  299  * routing info
  300  */
  301 static  int
  302 tunclose(dev_t dev, int foo, int bar, struct thread *td)
  303 {
  304         struct tun_softc *tp;
  305         struct ifnet *ifp;
  306         int s;
  307         int err;
  308 
  309         tp = dev->si_drv1;
  310         ifp = &tp->tun_if;
  311 
  312         KASSERT(tp->r_unit, ("Unit %d not marked open", ifp->if_unit));
  313         tp->tun_flags &= ~TUN_OPEN;
  314         tp->tun_pid = 0;
  315 
  316         /*
  317          * junk all pending output
  318          */
  319         IF_DRAIN(&ifp->if_snd);
  320 
  321         if (ifp->if_flags & IFF_UP) {
  322                 s = splimp();
  323                 if_down(ifp);
  324                 splx(s);
  325         }
  326 
  327         if (ifp->if_flags & IFF_RUNNING) {
  328                 register struct ifaddr *ifa;
  329 
  330                 s = splimp();
  331                 /* find internet addresses and delete routes */
  332                 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
  333                         if (ifa->ifa_addr->sa_family == AF_INET)
  334                                 rtinit(ifa, (int)RTM_DELETE,
  335                                     tp->tun_flags & TUN_DSTADDR ? RTF_HOST : 0);
  336                 ifp->if_flags &= ~IFF_RUNNING;
  337                 splx(s);
  338         }
  339 
  340         funsetown(&tp->tun_sigio);
  341         selwakeup(&tp->tun_rsel);
  342 
  343         TUNDEBUG ("%s%d: closed\n", ifp->if_name, ifp->if_unit);
  344         err = rman_release_resource(tp->r_unit);
  345         KASSERT(err == 0, ("Unit %d failed to release", ifp->if_unit));
  346 
  347         return (0);
  348 }
  349 
  350 static int
  351 tuninit(struct ifnet *ifp)
  352 {
  353         struct tun_softc *tp = ifp->if_softc;
  354         register struct ifaddr *ifa;
  355         int error = 0;
  356 
  357         TUNDEBUG("%s%d: tuninit\n", ifp->if_name, ifp->if_unit);
  358 
  359         ifp->if_flags |= IFF_UP | IFF_RUNNING;
  360         getmicrotime(&ifp->if_lastchange);
  361 
  362         for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa; 
  363              ifa = TAILQ_NEXT(ifa, ifa_link)) {
  364                 if (ifa->ifa_addr == NULL)
  365                         error = EFAULT;
  366                         /* XXX: Should maybe return straight off? */
  367                 else {
  368 #ifdef INET
  369                         if (ifa->ifa_addr->sa_family == AF_INET) {
  370                             struct sockaddr_in *si;
  371 
  372                             si = (struct sockaddr_in *)ifa->ifa_addr;
  373                             if (si->sin_addr.s_addr)
  374                                     tp->tun_flags |= TUN_IASET;
  375 
  376                             si = (struct sockaddr_in *)ifa->ifa_dstaddr;
  377                             if (si && si->sin_addr.s_addr)
  378                                     tp->tun_flags |= TUN_DSTADDR;
  379                         }
  380 #endif
  381                 }
  382         }
  383         return (error);
  384 }
  385 
  386 /*
  387  * Process an ioctl request.
  388  */
  389 static int
  390 tunifioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  391 {
  392         struct ifreq *ifr = (struct ifreq *)data;
  393         struct tun_softc *tp = ifp->if_softc;
  394         struct ifstat *ifs;
  395         int             error = 0, s;
  396 
  397         s = splimp();
  398         switch(cmd) {
  399         case SIOCGIFSTATUS:
  400                 ifs = (struct ifstat *)data;
  401                 if (tp->tun_pid)
  402                         sprintf(ifs->ascii + strlen(ifs->ascii),
  403                             "\tOpened by PID %d\n", tp->tun_pid);
  404                 break;
  405         case SIOCSIFADDR:
  406                 error = tuninit(ifp);
  407                 TUNDEBUG("%s%d: address set, error=%d\n",
  408                          ifp->if_name, ifp->if_unit, error);
  409                 break;
  410         case SIOCSIFDSTADDR:
  411                 error = tuninit(ifp);
  412                 TUNDEBUG("%s%d: destination address set, error=%d\n",
  413                          ifp->if_name, ifp->if_unit, error);
  414                 break;
  415         case SIOCSIFMTU:
  416                 ifp->if_mtu = ifr->ifr_mtu;
  417                 TUNDEBUG("%s%d: mtu set\n", ifp->if_name, ifp->if_unit);
  418                 break;
  419         case SIOCSIFFLAGS:
  420         case SIOCADDMULTI:
  421         case SIOCDELMULTI:
  422                 break;
  423         default:
  424                 error = EINVAL;
  425         }
  426         splx(s);
  427         return (error);
  428 }
  429 
  430 /*
  431  * tunoutput - queue packets from higher level ready to put out.
  432  */
  433 static int
  434 tunoutput(
  435         struct ifnet *ifp,
  436         struct mbuf *m0,
  437         struct sockaddr *dst,
  438         struct rtentry *rt)
  439 {
  440         struct tun_softc *tp = ifp->if_softc;
  441 #ifdef MAC
  442         int error;
  443 #endif
  444 
  445         TUNDEBUG ("%s%d: tunoutput\n", ifp->if_name, ifp->if_unit);
  446 
  447 #ifdef MAC
  448         error = mac_check_ifnet_transmit(ifp, m0);
  449         if (error) {
  450                 m_freem(m0);
  451                 return (error);
  452         }
  453 #endif
  454 
  455         if ((tp->tun_flags & TUN_READY) != TUN_READY) {
  456                 TUNDEBUG ("%s%d: not ready 0%o\n", ifp->if_name,
  457                           ifp->if_unit, tp->tun_flags);
  458                 m_freem (m0);
  459                 return (EHOSTDOWN);
  460         }
  461 
  462         if ((ifp->if_flags & IFF_UP) != IFF_UP) {
  463                 m_freem (m0);
  464                 return (EHOSTDOWN);
  465         }
  466 
  467         /* BPF write needs to be handled specially */
  468         if (dst->sa_family == AF_UNSPEC) {
  469                 dst->sa_family = *(mtod(m0, int *));
  470                 m0->m_len -= sizeof(int);
  471                 m0->m_pkthdr.len -= sizeof(int);
  472                 m0->m_data += sizeof(int);
  473         }
  474 
  475         if (ifp->if_bpf) {
  476                 /*
  477                  * We need to prepend the address family as
  478                  * a four byte field.  Cons up a dummy header
  479                  * to pacify bpf.  This is safe because bpf
  480                  * will only read from the mbuf (i.e., it won't
  481                  * try to free it or keep a pointer to it).
  482                  */
  483                 struct mbuf m;
  484                 uint32_t af = dst->sa_family;
  485 
  486                 m.m_next = m0;
  487                 m.m_len = 4;
  488                 m.m_data = (char *)&af;
  489 
  490                 BPF_MTAP(ifp, &m);
  491         }
  492 
  493         /* prepend sockaddr? this may abort if the mbuf allocation fails */
  494         if (tp->tun_flags & TUN_LMODE) {
  495                 /* allocate space for sockaddr */
  496                 M_PREPEND(m0, dst->sa_len, M_DONTWAIT);
  497 
  498                 /* if allocation failed drop packet */
  499                 if (m0 == NULL) {
  500                         ifp->if_iqdrops++;
  501                         ifp->if_oerrors++;
  502                         return (ENOBUFS);
  503                 } else {
  504                         bcopy(dst, m0->m_data, dst->sa_len);
  505                 }
  506         }
  507 
  508         if (tp->tun_flags & TUN_IFHEAD) {
  509                 /* Prepend the address family */
  510                 M_PREPEND(m0, 4, M_DONTWAIT);
  511 
  512                 /* if allocation failed drop packet */
  513                 if (m0 == NULL) {
  514                         ifp->if_iqdrops++;
  515                         ifp->if_oerrors++;
  516                         return (ENOBUFS);
  517                 } else
  518                         *(u_int32_t *)m0->m_data = htonl(dst->sa_family);
  519         } else {
  520 #ifdef INET
  521                 if (dst->sa_family != AF_INET)
  522 #endif
  523                 {
  524                         m_freem(m0);
  525                         return (EAFNOSUPPORT);
  526                 }
  527         }
  528 
  529         if (! IF_HANDOFF(&ifp->if_snd, m0, ifp)) {
  530                 ifp->if_collisions++;
  531                 return (ENOBUFS);
  532         }
  533         ifp->if_opackets++;
  534         return (0);
  535 }
  536 
  537 /*
  538  * the cdevsw interface is now pretty minimal.
  539  */
  540 static  int
  541 tunioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct thread *td)
  542 {
  543         int             s;
  544         int             error;
  545         struct tun_softc *tp = dev->si_drv1;
  546         struct tuninfo *tunp;
  547 
  548         switch (cmd) {
  549         case TUNSIFINFO:
  550                 tunp = (struct tuninfo *)data;
  551                 if (tunp->mtu < IF_MINMTU)
  552                         return (EINVAL);
  553                 if (tp->tun_if.if_mtu != tunp->mtu
  554                 && (error = suser(td)) != 0)
  555                         return (error);
  556                 tp->tun_if.if_mtu = tunp->mtu;
  557                 tp->tun_if.if_type = tunp->type;
  558                 tp->tun_if.if_baudrate = tunp->baudrate;
  559                 break;
  560         case TUNGIFINFO:
  561                 tunp = (struct tuninfo *)data;
  562                 tunp->mtu = tp->tun_if.if_mtu;
  563                 tunp->type = tp->tun_if.if_type;
  564                 tunp->baudrate = tp->tun_if.if_baudrate;
  565                 break;
  566         case TUNSDEBUG:
  567                 tundebug = *(int *)data;
  568                 break;
  569         case TUNGDEBUG:
  570                 *(int *)data = tundebug;
  571                 break;
  572         case TUNSLMODE:
  573                 if (*(int *)data) {
  574                         tp->tun_flags |= TUN_LMODE;
  575                         tp->tun_flags &= ~TUN_IFHEAD;
  576                 } else
  577                         tp->tun_flags &= ~TUN_LMODE;
  578                 break;
  579         case TUNSIFHEAD:
  580                 if (*(int *)data) {
  581                         tp->tun_flags |= TUN_IFHEAD;
  582                         tp->tun_flags &= ~TUN_LMODE;
  583                 } else 
  584                         tp->tun_flags &= ~TUN_IFHEAD;
  585                 break;
  586         case TUNGIFHEAD:
  587                 *(int *)data = (tp->tun_flags & TUN_IFHEAD) ? 1 : 0;
  588                 break;
  589         case TUNSIFMODE:
  590                 /* deny this if UP */
  591                 if (tp->tun_if.if_flags & IFF_UP)
  592                         return(EBUSY);
  593 
  594                 switch (*(int *)data & ~IFF_MULTICAST) {
  595                 case IFF_POINTOPOINT:
  596                 case IFF_BROADCAST:
  597                         tp->tun_if.if_flags &=
  598                             ~(IFF_BROADCAST|IFF_POINTOPOINT|IFF_MULTICAST);
  599                         tp->tun_if.if_flags |= *(int *)data;
  600                         break;
  601                 default:
  602                         return(EINVAL);
  603                 }
  604                 break;
  605         case TUNSIFPID:
  606                 tp->tun_pid = curthread->td_proc->p_pid;
  607                 break;
  608         case FIONBIO:
  609                 break;
  610         case FIOASYNC:
  611                 if (*(int *)data)
  612                         tp->tun_flags |= TUN_ASYNC;
  613                 else
  614                         tp->tun_flags &= ~TUN_ASYNC;
  615                 break;
  616         case FIONREAD:
  617                 s = splimp();
  618                 if (tp->tun_if.if_snd.ifq_head) {
  619                         struct mbuf *mb = tp->tun_if.if_snd.ifq_head;
  620                         for( *(int *)data = 0; mb != 0; mb = mb->m_next) 
  621                                 *(int *)data += mb->m_len;
  622                 } else
  623                         *(int *)data = 0;
  624                 splx(s);
  625                 break;
  626         case FIOSETOWN:
  627                 return (fsetown(*(int *)data, &tp->tun_sigio));
  628 
  629         case FIOGETOWN:
  630                 *(int *)data = fgetown(&tp->tun_sigio);
  631                 return (0);
  632 
  633         /* This is deprecated, FIOSETOWN should be used instead. */
  634         case TIOCSPGRP:
  635                 return (fsetown(-(*(int *)data), &tp->tun_sigio));
  636 
  637         /* This is deprecated, FIOGETOWN should be used instead. */
  638         case TIOCGPGRP:
  639                 *(int *)data = -fgetown(&tp->tun_sigio);
  640                 return (0);
  641 
  642         default:
  643                 return (ENOTTY);
  644         }
  645         return (0);
  646 }
  647 
  648 /*
  649  * The cdevsw read interface - reads a packet at a time, or at
  650  * least as much of a packet as can be read.
  651  */
  652 static  int
  653 tunread(dev_t dev, struct uio *uio, int flag)
  654 {
  655         struct tun_softc *tp = dev->si_drv1;
  656         struct ifnet    *ifp = &tp->tun_if;
  657         struct mbuf     *m;
  658         int             error=0, len, s;
  659 
  660         TUNDEBUG ("%s%d: read\n", ifp->if_name, ifp->if_unit);
  661         if ((tp->tun_flags & TUN_READY) != TUN_READY) {
  662                 TUNDEBUG ("%s%d: not ready 0%o\n", ifp->if_name,
  663                           ifp->if_unit, tp->tun_flags);
  664                 return (EHOSTDOWN);
  665         }
  666 
  667         tp->tun_flags &= ~TUN_RWAIT;
  668 
  669         s = splimp();
  670         do {
  671                 IF_DEQUEUE(&ifp->if_snd, m);
  672                 if (m == NULL) {
  673                         if (flag & IO_NDELAY) {
  674                                 splx(s);
  675                                 return (EWOULDBLOCK);
  676                         }
  677                         tp->tun_flags |= TUN_RWAIT;
  678                         if((error = tsleep((caddr_t)tp, PCATCH | (PZERO + 1),
  679                                         "tunread", 0)) != 0) {
  680                                 splx(s);
  681                                 return (error);
  682                         }
  683                 }
  684         } while (m == NULL);
  685         splx(s);
  686 
  687         while (m && uio->uio_resid > 0 && error == 0) {
  688                 len = min(uio->uio_resid, m->m_len);
  689                 if (len != 0)
  690                         error = uiomove(mtod(m, caddr_t), len, uio);
  691                 m = m_free(m);
  692         }
  693 
  694         if (m) {
  695                 TUNDEBUG("%s%d: Dropping mbuf\n", ifp->if_name, ifp->if_unit);
  696                 m_freem(m);
  697         }
  698         return (error);
  699 }
  700 
  701 /*
  702  * the cdevsw write interface - an atomic write is a packet - or else!
  703  */
  704 static  int
  705 tunwrite(dev_t dev, struct uio *uio, int flag)
  706 {
  707         struct tun_softc *tp = dev->si_drv1;
  708         struct ifnet    *ifp = &tp->tun_if;
  709         struct mbuf     *top, **mp, *m;
  710         int             error=0, tlen, mlen;
  711         uint32_t        family;
  712 
  713         TUNDEBUG("%s%d: tunwrite\n", ifp->if_name, ifp->if_unit);
  714 
  715         if ((ifp->if_flags & IFF_UP) != IFF_UP)
  716                 /* ignore silently */
  717                 return (0);
  718 
  719         if (uio->uio_resid == 0)
  720                 return (0);
  721 
  722         if (uio->uio_resid < 0 || uio->uio_resid > TUNMRU) {
  723                 TUNDEBUG("%s%d: len=%d!\n", ifp->if_name, ifp->if_unit,
  724                     uio->uio_resid);
  725                 return (EIO);
  726         }
  727         tlen = uio->uio_resid;
  728 
  729         /* get a header mbuf */
  730         MGETHDR(m, M_DONTWAIT, MT_DATA);
  731         if (m == NULL)
  732                 return (ENOBUFS);
  733         mlen = MHLEN;
  734 
  735         top = 0;
  736         mp = &top;
  737         while (error == 0 && uio->uio_resid > 0) {
  738                 m->m_len = min(mlen, uio->uio_resid);
  739                 error = uiomove(mtod (m, caddr_t), m->m_len, uio);
  740                 *mp = m;
  741                 mp = &m->m_next;
  742                 if (uio->uio_resid > 0) {
  743                         MGET (m, M_DONTWAIT, MT_DATA);
  744                         if (m == 0) {
  745                                 error = ENOBUFS;
  746                                 break;
  747                         }
  748                         mlen = MLEN;
  749                 }
  750         }
  751         if (error) {
  752                 if (top)
  753                         m_freem (top);
  754                 ifp->if_ierrors++;
  755                 return (error);
  756         }
  757 
  758         top->m_pkthdr.len = tlen;
  759         top->m_pkthdr.rcvif = ifp;
  760 #ifdef MAC
  761         mac_create_mbuf_from_ifnet(ifp, top);
  762 #endif
  763 
  764         if (ifp->if_bpf) {
  765                 if (tp->tun_flags & TUN_IFHEAD) {
  766                         /*
  767                          * Conveniently, we already have a 4-byte address
  768                          * family prepended to our packet !
  769                          * Inconveniently, it's in the wrong byte order !
  770                          */
  771                         if ((top = m_pullup(top, sizeof(family))) == NULL)
  772                                 return (ENOBUFS);
  773                         *mtod(top, u_int32_t *) =
  774                             ntohl(*mtod(top, u_int32_t *));
  775                         BPF_MTAP(ifp, top);
  776                         *mtod(top, u_int32_t *) =
  777                             htonl(*mtod(top, u_int32_t *));
  778                 } else {
  779                         /*
  780                          * We need to prepend the address family as
  781                          * a four byte field.  Cons up a dummy header
  782                          * to pacify bpf.  This is safe because bpf
  783                          * will only read from the mbuf (i.e., it won't
  784                          * try to free it or keep a pointer to it).
  785                          */
  786                         struct mbuf m;
  787                         uint32_t af = AF_INET;
  788 
  789                         m.m_next = top;
  790                         m.m_len = 4;
  791                         m.m_data = (char *)&af;
  792 
  793                         BPF_MTAP(ifp, &m);
  794                 }
  795         }
  796 
  797         if (tp->tun_flags & TUN_IFHEAD) {
  798                 if (top->m_len < sizeof(family) &&
  799                     (top = m_pullup(top, sizeof(family))) == NULL)
  800                         return (ENOBUFS);
  801                 family = ntohl(*mtod(top, u_int32_t *));
  802                 m_adj(top, sizeof(family));
  803         } else
  804                 family = AF_INET;
  805 
  806         ifp->if_ibytes += top->m_pkthdr.len;
  807         ifp->if_ipackets++;
  808 
  809         return (family_enqueue(family, top));
  810 }
  811 
  812 /*
  813  * tunpoll - the poll interface, this is only useful on reads
  814  * really. The write detect always returns true, write never blocks
  815  * anyway, it either accepts the packet or drops it.
  816  */
  817 static  int
  818 tunpoll(dev_t dev, int events, struct thread *td)
  819 {
  820         int             s;
  821         struct tun_softc *tp = dev->si_drv1;
  822         struct ifnet    *ifp = &tp->tun_if;
  823         int             revents = 0;
  824 
  825         s = splimp();
  826         TUNDEBUG("%s%d: tunpoll\n", ifp->if_name, ifp->if_unit);
  827 
  828         if (events & (POLLIN | POLLRDNORM)) {
  829                 if (ifp->if_snd.ifq_len > 0) {
  830                         TUNDEBUG("%s%d: tunpoll q=%d\n", ifp->if_name,
  831                             ifp->if_unit, ifp->if_snd.ifq_len);
  832                         revents |= events & (POLLIN | POLLRDNORM);
  833                 } else {
  834                         TUNDEBUG("%s%d: tunpoll waiting\n", ifp->if_name,
  835                             ifp->if_unit);
  836                         selrecord(td, &tp->tun_rsel);
  837                 }
  838         }
  839         if (events & (POLLOUT | POLLWRNORM))
  840                 revents |= events & (POLLOUT | POLLWRNORM);
  841 
  842         splx(s);
  843         return (revents);
  844 }

Cache object: 46f7d0bcf1f6ee04e9ead2224c57abe7


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.