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

Cache object: ec07c6db5983198fc08d1e344c2085a2


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