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.94 2006/11/16 01:33:40 christos 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 its
   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 
   17 #include <sys/cdefs.h>
   18 __KERNEL_RCSID(0, "$NetBSD: if_tun.c,v 1.94 2006/11/16 01:33:40 christos Exp $");
   19 
   20 #include "opt_inet.h"
   21 
   22 #include <sys/param.h>
   23 #include <sys/proc.h>
   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>
   33 #include <sys/poll.h>
   34 #include <sys/file.h>
   35 #include <sys/signalvar.h>
   36 #include <sys/conf.h>
   37 #include <sys/kauth.h>
   38 
   39 #include <machine/cpu.h>
   40 
   41 #include <net/if.h>
   42 #include <net/if_types.h>
   43 #include <net/netisr.h>
   44 #include <net/route.h>
   45 
   46 
   47 #ifdef INET
   48 #include <netinet/in.h>
   49 #include <netinet/in_systm.h>
   50 #include <netinet/in_var.h>
   51 #include <netinet/ip.h>
   52 #include <netinet/if_inarp.h>
   53 #endif
   54 
   55 
   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 
   64 #define TUNDEBUG        if (tundebug) printf
   65 int     tundebug = 0;
   66 
   67 extern int ifqmaxlen;
   68 void    tunattach(int);
   69 
   70 static LIST_HEAD(, tun_softc) tun_softc_list;
   71 static LIST_HEAD(, tun_softc) tunz_softc_list;
   72 static struct simplelock tun_softc_lock;
   73 
   74 static int      tun_ioctl(struct ifnet *, u_long, caddr_t);
   75 static int      tun_output(struct ifnet *, struct mbuf *, struct sockaddr *,
   76                        struct rtentry *rt);
   77 static int      tun_clone_create(struct if_clone *, int);
   78 static int      tun_clone_destroy(struct ifnet *);
   79 
   80 static struct if_clone tun_cloner =
   81     IF_CLONE_INITIALIZER("tun", tun_clone_create, tun_clone_destroy);
   82 
   83 static void tunattach0(struct tun_softc *);
   84 static void tuninit(struct tun_softc *);
   85 #ifdef ALTQ
   86 static void tunstart(struct ifnet *);
   87 #endif
   88 static struct tun_softc *tun_find_unit(dev_t);
   89 static struct tun_softc *tun_find_zunit(int);
   90 
   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);
   98 
   99 const struct cdevsw tun_cdevsw = {
  100         tunopen, tunclose, tunread, tunwrite, tunioctl,
  101         nostop, notty, tunpoll, nommap, tunkqfilter, D_OTHER,
  102 };
  103 
  104 void
  105 tunattach(int unused)
  106 {
  107 
  108         simple_lock_init(&tun_softc_lock);
  109         LIST_INIT(&tun_softc_list);
  110         LIST_INIT(&tunz_softc_list);
  111         if_clone_attach(&tun_cloner);
  112 }
  113 
  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 *
  120 tun_find_unit(dev_t dev)
  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 *
  142 tun_find_zunit(int unit)
  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 
  161 static int
  162 tun_clone_create(struct if_clone *ifc, int unit)
  163 {
  164         struct tun_softc *tp;
  165 
  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));
  170 
  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         }
  177 
  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;
  182 
  183         simple_lock(&tun_softc_lock);
  184         LIST_INSERT_HEAD(&tun_softc_list, tp, tun_list);
  185         simple_unlock(&tun_softc_lock);
  186 
  187         return (0);
  188 }
  189 
  190 static void
  191 tunattach0(struct tun_softc *tp)
  192 {
  193         struct ifnet *ifp;
  194 
  195         ifp = &tp->tun_if;
  196         ifp->if_softc = tp;
  197         ifp->if_mtu = TUNMTU;
  198         ifp->if_ioctl = tun_ioctl;
  199         ifp->if_output = tun_output;
  200 #ifdef ALTQ
  201         ifp->if_start = tunstart;
  202 #endif
  203         ifp->if_flags = IFF_POINTOPOINT;
  204         ifp->if_type = IFT_TUNNEL;
  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;
  211         ifp->if_ibytes   = 0;
  212         ifp->if_obytes   = 0;
  213         ifp->if_dlt = DLT_NULL;
  214         IFQ_SET_READY(&ifp->if_snd);
  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 
  222 static int
  223 tun_clone_destroy(struct ifnet *ifp)
  224 {
  225         struct tun_softc *tp = (void *)ifp;
  226         int s, zombie = 0;
  227 
  228         s = splnet();
  229         simple_lock(&tun_softc_lock);
  230         simple_lock(&tp->tun_lock);
  231         LIST_REMOVE(tp, tun_list);
  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         }
  238         simple_unlock(&tun_softc_lock);
  239 
  240         IF_PURGE(&ifp->if_snd);
  241         ifp->if_flags &= ~IFF_RUNNING;
  242 
  243         if (tp->tun_flags & TUN_RWAIT) {
  244                 tp->tun_flags &= ~TUN_RWAIT;
  245                 wakeup((caddr_t)tp);
  246         }
  247         if (tp->tun_flags & TUN_ASYNC && tp->tun_pgid)
  248                 fownsignal(tp->tun_pgid, SIGIO, POLL_HUP, 0, NULL);
  249 
  250         selwakeup(&tp->tun_rsel);
  251 
  252         simple_unlock(&tp->tun_lock);
  253         splx(s);
  254 
  255 #if NBPFILTER > 0
  256         bpfdetach(ifp);
  257 #endif
  258         if_detach(ifp);
  259 
  260         if (!zombie)
  261                 free(tp, M_DEVBUF);
  262 
  263         return (0);
  264 }
  265 
  266 /*
  267  * tunnel open - must be superuser & the device must be
  268  * configured in
  269  */
  270 static int
  271 tunopen(dev_t dev, int flag, int mode, struct lwp *l)
  272 {
  273         struct ifnet    *ifp;
  274         struct tun_softc *tp;
  275         int     s, error;
  276 
  277         if ((error = kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
  278             &l->l_acflag)) != 0)
  279                 return (error);
  280 
  281         s = splnet();
  282         tp = tun_find_unit(dev);
  283 
  284         if (tp == NULL) {
  285                 (void)tun_clone_create(&tun_cloner, minor(dev));
  286                 tp = tun_find_unit(dev);
  287                 if (tp == NULL) {
  288                         error = ENXIO;
  289                         goto out_nolock;
  290                 }
  291         }
  292 
  293         if (tp->tun_flags & TUN_OPEN) {
  294                 error = EBUSY;
  295                 goto out;
  296         }
  297 
  298         ifp = &tp->tun_if;
  299         tp->tun_flags |= TUN_OPEN;
  300         TUNDEBUG("%s: open\n", ifp->if_xname);
  301 out:
  302         simple_unlock(&tp->tun_lock);
  303 out_nolock:
  304         splx(s);
  305         return (error);
  306 }
  307 
  308 /*
  309  * tunclose - close the device - mark i/f down & delete
  310  * routing info
  311  */
  312 int
  313 tunclose(dev_t dev, int flag, int mode,
  314     struct lwp *l)
  315 {
  316         int     s;
  317         struct tun_softc *tp;
  318         struct ifnet    *ifp;
  319 
  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         }
  326 
  327         if ((tp = tun_find_unit(dev)) == NULL)
  328                 goto out_nolock;
  329 
  330         ifp = &tp->tun_if;
  331 
  332         tp->tun_flags &= ~TUN_OPEN;
  333 
  334         /*
  335          * junk all pending output
  336          */
  337         IFQ_PURGE(&ifp->if_snd);
  338 
  339         if (ifp->if_flags & IFF_UP) {
  340                 if_down(ifp);
  341                 if (ifp->if_flags & IFF_RUNNING) {
  342                         /* find internet addresses and delete routes */
  343                         struct ifaddr *ifa;
  344                         IFADDR_FOREACH(ifa, ifp) {
  345 #if defined(INET) || defined(INET6)
  346                                 if (ifa->ifa_addr->sa_family == AF_INET ||
  347                                     ifa->ifa_addr->sa_family == AF_INET6) {
  348                                         rtinit(ifa, (int)RTM_DELETE,
  349                                                tp->tun_flags & TUN_DSTADDR
  350                                                         ? RTF_HOST
  351                                                         : 0);
  352                                 }
  353 #endif
  354                         }
  355                 }
  356         }
  357         tp->tun_pgid = 0;
  358         selnotify(&tp->tun_rsel, 0);
  359 
  360         TUNDEBUG ("%s: closed\n", ifp->if_xname);
  361         simple_unlock(&tp->tun_lock);
  362 out_nolock:
  363         splx(s);
  364         return (0);
  365 }
  366 
  367 /*
  368  * Call at splnet() with tp locked.
  369  */
  370 static void
  371 tuninit(struct tun_softc *tp)
  372 {
  373         struct ifnet    *ifp = &tp->tun_if;
  374         struct ifaddr   *ifa;
  375 
  376         TUNDEBUG("%s: tuninit\n", ifp->if_xname);
  377 
  378         ifp->if_flags |= IFF_UP | IFF_RUNNING;
  379 
  380         tp->tun_flags &= ~(TUN_IASET|TUN_DSTADDR);
  381         IFADDR_FOREACH(ifa, ifp) {
  382 #ifdef INET
  383                 if (ifa->ifa_addr->sa_family == AF_INET) {
  384                         struct sockaddr_in *sin;
  385 
  386                         sin = satosin(ifa->ifa_addr);
  387                         if (sin && sin->sin_addr.s_addr)
  388                                 tp->tun_flags |= TUN_IASET;
  389 
  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                         }
  395                 }
  396 #endif
  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 */
  414         }
  415 
  416         return;
  417 }
  418 
  419 /*
  420  * Process an ioctl request.
  421  */
  422 static int
  423 tun_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  424 {
  425         int             error = 0, s;
  426         struct tun_softc *tp = (struct tun_softc *)(ifp->if_softc);
  427 
  428         s = splnet();
  429         simple_lock(&tp->tun_lock);
  430 
  431         switch (cmd) {
  432         case SIOCSIFADDR:
  433                 tuninit(tp);
  434                 TUNDEBUG("%s: address set\n", ifp->if_xname);
  435                 break;
  436         case SIOCSIFDSTADDR:
  437                 tuninit(tp);
  438                 TUNDEBUG("%s: destination address set\n", ifp->if_xname);
  439                 break;
  440         case SIOCSIFBRDADDR:
  441                 TUNDEBUG("%s: broadcast address set\n", ifp->if_xname);
  442                 break;
  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;
  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                 }
  460                 switch (ifr->ifr_addr.sa_family) {
  461 #ifdef INET
  462                 case AF_INET:
  463                         break;
  464 #endif
  465 #ifdef INET6
  466                 case AF_INET6:
  467                         break;
  468 #endif
  469                 default:
  470                         error = EAFNOSUPPORT;
  471                         break;
  472                 }
  473                 break;
  474         }
  475         case SIOCSIFFLAGS:
  476                 break;
  477         default:
  478                 error = EINVAL;
  479         }
  480 
  481         simple_unlock(&tp->tun_lock);
  482         splx(s);
  483         return (error);
  484 }
  485 
  486 /*
  487  * tun_output - queue packets from higher level ready to put out.
  488  */
  489 static int
  490 tun_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst,
  491     struct rtentry *rt)
  492 {
  493         struct tun_softc *tp = ifp->if_softc;
  494         int             s;
  495         int             error;
  496 #if defined(INET) || defined(INET6)
  497         int             mlen;
  498         uint32_t        *af;
  499 #endif
  500         ALTQ_DECL(struct altq_pktattr pktattr;)
  501 
  502         s = splnet();
  503         simple_lock(&tp->tun_lock);
  504         TUNDEBUG ("%s: tun_output\n", ifp->if_xname);
  505 
  506         if ((tp->tun_flags & TUN_READY) != TUN_READY) {
  507                 TUNDEBUG ("%s: not ready 0%o\n", ifp->if_xname,
  508                           tp->tun_flags);
  509                 m_freem (m0);
  510                 error = EHOSTDOWN;
  511                 goto out;
  512         }
  513 
  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);
  519 
  520 #if NBPFILTER > 0
  521         if (ifp->if_bpf)
  522                 bpf_mtap_af(ifp->if_bpf, dst->sa_family, m0);
  523 #endif
  524 
  525         switch(dst->sa_family) {
  526 #ifdef INET6
  527         case AF_INET6:
  528 #endif
  529 #ifdef INET
  530         case AF_INET:
  531 #endif
  532 #if defined(INET) || defined(INET6)
  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);
  538                                 error = ENOBUFS;
  539                                 goto out;
  540                         }
  541                         bcopy(dst, mtod(m0, char *), dst->sa_len);
  542                 }
  543 
  544                 if (tp->tun_flags & TUN_IFHEAD) {
  545                         /* Prepend the address family */
  546                         M_PREPEND(m0, sizeof(*af), M_DONTWAIT);
  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);
  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                         }
  563                 }
  564                 /* FALLTHROUGH */
  565         case AF_UNSPEC:
  566                 IFQ_ENQUEUE(&ifp->if_snd, m0, &pktattr, error);
  567                 if (error) {
  568                         ifp->if_collisions++;
  569                         error = EAFNOSUPPORT;
  570                         goto out;
  571                 }
  572                 mlen = m0->m_pkthdr.len;
  573                 ifp->if_opackets++;
  574                 ifp->if_obytes += mlen;
  575                 break;
  576 #endif
  577         default:
  578                 m_freem(m0);
  579                 error = EAFNOSUPPORT;
  580                 goto out;
  581         }
  582 
  583         if (tp->tun_flags & TUN_RWAIT) {
  584                 tp->tun_flags &= ~TUN_RWAIT;
  585                 wakeup((caddr_t)tp);
  586         }
  587         if (tp->tun_flags & TUN_ASYNC && tp->tun_pgid)
  588                 fownsignal(tp->tun_pgid, SIGIO, POLL_IN, POLLIN|POLLRDNORM,
  589                     NULL);
  590 
  591         selnotify(&tp->tun_rsel, 0);
  592 out:
  593         simple_unlock(&tp->tun_lock);
  594         splx(s);
  595         return (0);
  596 }
  597 
  598 /*
  599  * the cdevsw interface is now pretty minimal.
  600  */
  601 int
  602 tunioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct lwp *l)
  603 {
  604         struct tun_softc *tp;
  605         int s, error = 0;
  606 
  607         s = splnet();
  608         tp = tun_find_unit(dev);
  609 
  610         /* interface was "destroyed" already */
  611         if (tp == NULL) {
  612                 error = ENXIO;
  613                 goto out_nolock;
  614         }
  615 
  616         switch (cmd) {
  617         case TUNSDEBUG:
  618                 tundebug = *(int *)data;
  619                 break;
  620 
  621         case TUNGDEBUG:
  622                 *(int *)data = tundebug;
  623                 break;
  624 
  625         case TUNSIFMODE:
  626                 switch (*(int *)data & (IFF_POINTOPOINT|IFF_BROADCAST)) {
  627                 case IFF_POINTOPOINT:
  628                 case IFF_BROADCAST:
  629                         if (tp->tun_if.if_flags & IFF_UP) {
  630                                 error = EBUSY;
  631                                 goto out;
  632                         }
  633                         tp->tun_if.if_flags &=
  634                                 ~(IFF_BROADCAST|IFF_POINTOPOINT|IFF_MULTICAST);
  635                         tp->tun_if.if_flags |= *(int *)data;
  636                         break;
  637                 default:
  638                         error = EINVAL;
  639                         goto out;
  640                 }
  641                 break;
  642 
  643         case TUNSLMODE:
  644                 if (*(int *)data) {
  645                         tp->tun_flags |= TUN_PREPADDR;
  646                         tp->tun_flags &= ~TUN_IFHEAD;
  647                 } else
  648                         tp->tun_flags &= ~TUN_PREPADDR;
  649                 break;
  650 
  651         case TUNSIFHEAD:
  652                 if (*(int *)data) {
  653                         tp->tun_flags |= TUN_IFHEAD;
  654                         tp->tun_flags &= ~TUN_PREPADDR;
  655                 } else
  656                         tp->tun_flags &= ~TUN_IFHEAD;
  657                 break;
  658 
  659         case TUNGIFHEAD:
  660                 *(int *)data = (tp->tun_flags & TUN_IFHEAD);
  661                 break;
  662 
  663         case FIONBIO:
  664                 if (*(int *)data)
  665                         tp->tun_flags |= TUN_NBIO;
  666                 else
  667                         tp->tun_flags &= ~TUN_NBIO;
  668                 break;
  669 
  670         case FIOASYNC:
  671                 if (*(int *)data)
  672                         tp->tun_flags |= TUN_ASYNC;
  673                 else
  674                         tp->tun_flags &= ~TUN_ASYNC;
  675                 break;
  676 
  677         case FIONREAD:
  678                 if (tp->tun_if.if_snd.ifq_head)
  679                         *(int *)data = tp->tun_if.if_snd.ifq_head->m_pkthdr.len;
  680                 else
  681                         *(int *)data = 0;
  682                 break;
  683 
  684         case TIOCSPGRP:
  685         case FIOSETOWN:
  686                 error = fsetown(l->l_proc, &tp->tun_pgid, cmd, data);
  687                 break;
  688 
  689         case TIOCGPGRP:
  690         case FIOGETOWN:
  691                 error = fgetown(l->l_proc, tp->tun_pgid, cmd, data);
  692                 break;
  693 
  694         default:
  695                 error = ENOTTY;
  696         }
  697 
  698 out:
  699         simple_unlock(&tp->tun_lock);
  700 out_nolock:
  701         splx(s);
  702         return (error);
  703 }
  704 
  705 /*
  706  * The cdevsw read interface - reads a packet at a time, or at
  707  * least as much of a packet as can be read.
  708  */
  709 int
  710 tunread(dev_t dev, struct uio *uio, int ioflag)
  711 {
  712         struct tun_softc *tp;
  713         struct ifnet    *ifp;
  714         struct mbuf     *m, *m0;
  715         int             error = 0, len, s, index;
  716 
  717         s = splnet();
  718         tp = tun_find_unit(dev);
  719 
  720         /* interface was "destroyed" already */
  721         if (tp == NULL) {
  722                 error = ENXIO;
  723                 goto out_nolock;
  724         }
  725 
  726         index = tp->tun_if.if_index;
  727         ifp = &tp->tun_if;
  728 
  729         TUNDEBUG ("%s: read\n", ifp->if_xname);
  730         if ((tp->tun_flags & TUN_READY) != TUN_READY) {
  731                 TUNDEBUG ("%s: not ready 0%o\n", ifp->if_xname, tp->tun_flags);
  732                 error = EHOSTDOWN;
  733                 goto out;
  734         }
  735 
  736         tp->tun_flags &= ~TUN_RWAIT;
  737 
  738         do {
  739                 IFQ_DEQUEUE(&ifp->if_snd, m0);
  740                 if (m0 == 0) {
  741                         if (tp->tun_flags & TUN_NBIO) {
  742                                 error = EWOULDBLOCK;
  743                                 goto out;
  744                         }
  745                         tp->tun_flags |= TUN_RWAIT;
  746                         if (ltsleep((caddr_t)tp, PZERO|PCATCH|PNORELOCK,
  747                                         "tunread", 0, &tp->tun_lock) != 0) {
  748                                 error = EINTR;
  749                                 goto out_nolock;
  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);
  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;
  765                                 }
  766                         }
  767                 }
  768         } while (m0 == 0);
  769 
  770         simple_unlock(&tp->tun_lock);
  771         splx(s);
  772 
  773         /* Copy the mbuf chain */
  774         while (m0 && uio->uio_resid > 0 && error == 0) {
  775                 len = min(uio->uio_resid, m0->m_len);
  776                 if (len != 0)
  777                         error = uiomove(mtod(m0, caddr_t), len, uio);
  778                 MFREE(m0, m);
  779                 m0 = m;
  780         }
  781 
  782         if (m0) {
  783                 TUNDEBUG("Dropping mbuf\n");
  784                 m_freem(m0);
  785         }
  786         if (error)
  787                 ifp->if_ierrors++;
  788 
  789         return (error);
  790 
  791 out:
  792         simple_unlock(&tp->tun_lock);
  793 out_nolock:
  794         splx(s);
  795         return (error);
  796 }
  797 
  798 /*
  799  * the cdevsw write interface - an atomic write is a packet - or else!
  800  */
  801 int
  802 tunwrite(dev_t dev, struct uio *uio, int ioflag)
  803 {
  804         struct tun_softc *tp;
  805         struct ifnet    *ifp;
  806         struct mbuf     *top, **mp, *m;
  807         struct ifqueue  *ifq;
  808         struct sockaddr dst;
  809         int             isr, error = 0, s, tlen, mlen;
  810         uint32_t        family;
  811 
  812         s = splnet();
  813         tp = tun_find_unit(dev);
  814 
  815         /* interface was "destroyed" already */
  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);
  824 
  825         ifp = &tp->tun_if;
  826 
  827         TUNDEBUG("%s: tunwrite\n", ifp->if_xname);
  828 
  829         if (tp->tun_flags & TUN_PREPADDR) {
  830                 if (uio->uio_resid < sizeof(dst)) {
  831                         error = EIO;
  832                         goto out0;
  833                 }
  834                 error = uiomove((caddr_t)&dst, sizeof(dst), uio);
  835                 if (dst.sa_len > sizeof(dst)) {
  836                         /* Duh.. */
  837                         char discard;
  838                         int n = dst.sa_len - sizeof(dst);
  839                         while (n--)
  840                                 if ((error = uiomove(&discard, 1, uio)) != 0) {
  841                                         goto out0;
  842                                 }
  843                 }
  844         } else if (tp->tun_flags & TUN_IFHEAD) {
  845                 if (uio->uio_resid < sizeof(family)){
  846                         error = EIO;
  847                         goto out0;
  848                 }
  849                 error = uiomove((caddr_t)&family, sizeof(family), uio);
  850                 dst.sa_family = ntohl(family);
  851         } else {
  852 #ifdef INET
  853                 dst.sa_family = AF_INET;
  854 #endif
  855         }
  856 
  857         if (uio->uio_resid > TUNMTU) {
  858                 TUNDEBUG("%s: len=%lu!\n", ifp->if_xname,
  859                     (unsigned long)uio->uio_resid);
  860                 error = EIO;
  861                 goto out0;
  862         }
  863 
  864         switch (dst.sa_family) {
  865 #ifdef INET
  866         case AF_INET:
  867                 ifq = &ipintrq;
  868                 isr = NETISR_IP;
  869                 break;
  870 #endif
  871 #ifdef INET6
  872         case AF_INET6:
  873                 ifq = &ip6intrq;
  874                 isr = NETISR_IPV6;
  875                 break;
  876 #endif
  877         default:
  878                 error = EAFNOSUPPORT;
  879                 goto out0;
  880         }
  881 
  882         tlen = uio->uio_resid;
  883 
  884         /* get a header mbuf */
  885         MGETHDR(m, M_DONTWAIT, MT_DATA);
  886         if (m == NULL) {
  887                 error = ENOBUFS;
  888                 goto out0;
  889         }
  890         mlen = MHLEN;
  891 
  892         top = NULL;
  893         mp = &top;
  894         while (error == 0 && uio->uio_resid > 0) {
  895                 m->m_len = min(mlen, uio->uio_resid);
  896                 error = uiomove(mtod(m, caddr_t), m->m_len, uio);
  897                 *mp = m;
  898                 mp = &m->m_next;
  899                 if (error == 0 && uio->uio_resid > 0) {
  900                         MGET(m, M_DONTWAIT, MT_DATA);
  901                         if (m == NULL) {
  902                                 error = ENOBUFS;
  903                                 break;
  904                         }
  905                         mlen = MLEN;
  906                 }
  907         }
  908         if (error) {
  909                 if (top != NULL)
  910                         m_freem (top);
  911                 ifp->if_ierrors++;
  912                 goto out0;
  913         }
  914 
  915         top->m_pkthdr.len = tlen;
  916         top->m_pkthdr.rcvif = ifp;
  917 
  918 #if NBPFILTER > 0
  919         if (ifp->if_bpf)
  920                 bpf_mtap_af(ifp->if_bpf, dst.sa_family, top);
  921 #endif
  922 
  923         s = splnet();
  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         }
  930         if (IF_QFULL(ifq)) {
  931                 IF_DROP(ifq);
  932                 ifp->if_collisions++;
  933                 m_freem(top);
  934                 error = ENOBUFS;
  935                 goto out;
  936         }
  937 
  938         IF_ENQUEUE(ifq, top);
  939         ifp->if_ipackets++;
  940         ifp->if_ibytes += tlen;
  941         schednetisr(isr);
  942 out:
  943         simple_unlock(&tp->tun_lock);
  944 out_nolock:
  945         splx(s);
  946 out0:
  947         return (error);
  948 }
  949 
  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.
  956  *
  957  * Should be called at splnet.
  958  */
  959 static void
  960 tunstart(struct ifnet *ifp)
  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 
  967         simple_lock(&tp->tun_lock);
  968         if (!IF_IS_EMPTY(&ifp->if_snd)) {
  969                 if (tp->tun_flags & TUN_RWAIT) {
  970                         tp->tun_flags &= ~TUN_RWAIT;
  971                         wakeup((caddr_t)tp);
  972                 }
  973                 if (tp->tun_flags & TUN_ASYNC && tp->tun_pgid)
  974                         fownsignal(tp->tun_pgid, SIGIO, POLL_OUT,
  975                                 POLLOUT|POLLWRNORM, NULL);
  976 
  977                 selwakeup(&tp->tun_rsel);
  978         }
  979         simple_unlock(&tp->tun_lock);
  980 }
  981 #endif /* ALTQ */
  982 /*
  983  * tunpoll - the poll interface, this is only useful on reads
  984  * really. The write detect always returns true, write never blocks
  985  * anyway, it either accepts the packet or drops it.
  986  */
  987 int
  988 tunpoll(dev_t dev, int events, struct lwp *l)
  989 {
  990         struct tun_softc *tp;
  991         struct ifnet    *ifp;
  992         int             s, revents = 0;
  993 
  994         s = splnet();
  995         tp = tun_find_unit(dev);
  996 
  997         /* interface was "destroyed" already */
  998         if (tp == NULL)
  999                 goto out_nolock;
 1000 
 1001         ifp = &tp->tun_if;
 1002 
 1003         TUNDEBUG("%s: tunpoll\n", ifp->if_xname);
 1004 
 1005         if (events & (POLLIN | POLLRDNORM)) {
 1006                 if (!IFQ_IS_EMPTY(&ifp->if_snd)) {
 1007                         TUNDEBUG("%s: tunpoll q=%d\n", ifp->if_xname,
 1008                             ifp->if_snd.ifq_len);
 1009                         revents |= events & (POLLIN | POLLRDNORM);
 1010                 } else {
 1011                         TUNDEBUG("%s: tunpoll waiting\n", ifp->if_xname);
 1012                         selrecord(l, &tp->tun_rsel);
 1013                 }
 1014         }
 1015 
 1016         if (events & (POLLOUT | POLLWRNORM))
 1017                 revents |= events & (POLLOUT | POLLWRNORM);
 1018 
 1019         simple_unlock(&tp->tun_lock);
 1020 out_nolock:
 1021         splx(s);
 1022         return (revents);
 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();
 1032         SLIST_REMOVE(&tp->tun_rsel.sel_klist, kn, knote, kn_selnext);
 1033         splx(s);
 1034 }
 1035 
 1036 static int
 1037 filt_tunread(struct knote *kn, long hint)
 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 {
 1067         struct tun_softc *tp;
 1068         struct klist *klist;
 1069         int rv = 0, s;
 1070 
 1071         s = splnet();
 1072         tp = tun_find_unit(dev);
 1073         if (tp == NULL)
 1074                 goto out_nolock;
 1075 
 1076         switch (kn->kn_filter) {
 1077         case EVFILT_READ:
 1078                 klist = &tp->tun_rsel.sel_klist;
 1079                 kn->kn_fop = &tunread_filtops;
 1080                 break;
 1081 
 1082         case EVFILT_WRITE:
 1083                 klist = &tp->tun_rsel.sel_klist;
 1084                 kn->kn_fop = &tun_seltrue_filtops;
 1085                 break;
 1086 
 1087         default:
 1088                 rv = 1;
 1089                 goto out;
 1090         }
 1091 
 1092         kn->kn_hook = tp;
 1093 
 1094         SLIST_INSERT_HEAD(klist, kn, kn_selnext);
 1095 
 1096 out:
 1097         simple_unlock(&tp->tun_lock);
 1098 out_nolock:
 1099         splx(s);
 1100         return (rv);
 1101 }

Cache object: 85c4c0d6cabd1e3a8370305673d25bf7


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