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

Cache object: 76d091d956394e24ec4d12a871b8163d


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