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_tap.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 /*-
    2  * Copyright (C) 1999-2000 by Maksim Yevmenkin <m_evmenkin@yahoo.com>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  * BASED ON:
   27  * -------------------------------------------------------------------------
   28  *
   29  * Copyright (c) 1988, Julian Onions <jpo@cs.nott.ac.uk>
   30  * Nottingham University 1987.
   31  */
   32 
   33 /*
   34  * $FreeBSD: releng/11.0/sys/net/if_tap.c 289718 2015-10-21 19:56:16Z emaste $
   35  * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $
   36  */
   37 
   38 #include "opt_compat.h"
   39 #include "opt_inet.h"
   40 
   41 #include <sys/param.h>
   42 #include <sys/conf.h>
   43 #include <sys/fcntl.h>
   44 #include <sys/filio.h>
   45 #include <sys/jail.h>
   46 #include <sys/kernel.h>
   47 #include <sys/malloc.h>
   48 #include <sys/mbuf.h>
   49 #include <sys/module.h>
   50 #include <sys/poll.h>
   51 #include <sys/priv.h>
   52 #include <sys/proc.h>
   53 #include <sys/selinfo.h>
   54 #include <sys/signalvar.h>
   55 #include <sys/socket.h>
   56 #include <sys/sockio.h>
   57 #include <sys/sysctl.h>
   58 #include <sys/systm.h>
   59 #include <sys/ttycom.h>
   60 #include <sys/uio.h>
   61 #include <sys/queue.h>
   62 
   63 #include <net/bpf.h>
   64 #include <net/ethernet.h>
   65 #include <net/if.h>
   66 #include <net/if_var.h>
   67 #include <net/if_clone.h>
   68 #include <net/if_dl.h>
   69 #include <net/if_media.h>
   70 #include <net/if_types.h>
   71 #include <net/route.h>
   72 #include <net/vnet.h>
   73 
   74 #include <netinet/in.h>
   75 
   76 #include <net/if_tapvar.h>
   77 #include <net/if_tap.h>
   78 
   79 
   80 #define CDEV_NAME       "tap"
   81 #define TAPDEBUG        if (tapdebug) printf
   82 
   83 static const char tapname[] = "tap";
   84 static const char vmnetname[] = "vmnet";
   85 #define TAPMAXUNIT      0x7fff
   86 #define VMNET_DEV_MASK  CLONE_FLAG0
   87 
   88 /* module */
   89 static int              tapmodevent(module_t, int, void *);
   90 
   91 /* device */
   92 static void             tapclone(void *, struct ucred *, char *, int,
   93                             struct cdev **);
   94 static void             tapcreate(struct cdev *);
   95 
   96 /* network interface */
   97 static void             tapifstart(struct ifnet *);
   98 static int              tapifioctl(struct ifnet *, u_long, caddr_t);
   99 static void             tapifinit(void *);
  100 
  101 static int              tap_clone_create(struct if_clone *, int, caddr_t);
  102 static void             tap_clone_destroy(struct ifnet *);
  103 static struct if_clone *tap_cloner;
  104 static int              vmnet_clone_create(struct if_clone *, int, caddr_t);
  105 static void             vmnet_clone_destroy(struct ifnet *);
  106 static struct if_clone *vmnet_cloner;
  107 
  108 /* character device */
  109 static d_open_t         tapopen;
  110 static d_close_t        tapclose;
  111 static d_read_t         tapread;
  112 static d_write_t        tapwrite;
  113 static d_ioctl_t        tapioctl;
  114 static d_poll_t         tappoll;
  115 static d_kqfilter_t     tapkqfilter;
  116 
  117 /* kqueue(2) */
  118 static int              tapkqread(struct knote *, long);
  119 static int              tapkqwrite(struct knote *, long);
  120 static void             tapkqdetach(struct knote *);
  121 
  122 static struct filterops tap_read_filterops = {
  123         .f_isfd =       1,
  124         .f_attach =     NULL,
  125         .f_detach =     tapkqdetach,
  126         .f_event =      tapkqread,
  127 };
  128 
  129 static struct filterops tap_write_filterops = {
  130         .f_isfd =       1,
  131         .f_attach =     NULL,
  132         .f_detach =     tapkqdetach,
  133         .f_event =      tapkqwrite,
  134 };
  135 
  136 static struct cdevsw    tap_cdevsw = {
  137         .d_version =    D_VERSION,
  138         .d_flags =      D_NEEDMINOR,
  139         .d_open =       tapopen,
  140         .d_close =      tapclose,
  141         .d_read =       tapread,
  142         .d_write =      tapwrite,
  143         .d_ioctl =      tapioctl,
  144         .d_poll =       tappoll,
  145         .d_name =       CDEV_NAME,
  146         .d_kqfilter =   tapkqfilter,
  147 };
  148 
  149 /*
  150  * All global variables in if_tap.c are locked with tapmtx, with the
  151  * exception of tapdebug, which is accessed unlocked; tapclones is
  152  * static at runtime.
  153  */
  154 static struct mtx               tapmtx;
  155 static int                      tapdebug = 0;        /* debug flag   */
  156 static int                      tapuopen = 0;        /* allow user open() */
  157 static int                      tapuponopen = 0;    /* IFF_UP on open() */
  158 static int                      tapdclone = 1;  /* enable devfs cloning */
  159 static SLIST_HEAD(, tap_softc)  taphead;             /* first device */
  160 static struct clonedevs         *tapclones;
  161 
  162 MALLOC_DECLARE(M_TAP);
  163 MALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
  164 SYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
  165 
  166 SYSCTL_DECL(_net_link);
  167 static SYSCTL_NODE(_net_link, OID_AUTO, tap, CTLFLAG_RW, 0,
  168     "Ethernet tunnel software network interface");
  169 SYSCTL_INT(_net_link_tap, OID_AUTO, user_open, CTLFLAG_RW, &tapuopen, 0,
  170         "Allow user to open /dev/tap (based on node permissions)");
  171 SYSCTL_INT(_net_link_tap, OID_AUTO, up_on_open, CTLFLAG_RW, &tapuponopen, 0,
  172         "Bring interface up when /dev/tap is opened");
  173 SYSCTL_INT(_net_link_tap, OID_AUTO, devfs_cloning, CTLFLAG_RWTUN, &tapdclone, 0,
  174         "Enable legacy devfs interface creation");
  175 SYSCTL_INT(_net_link_tap, OID_AUTO, debug, CTLFLAG_RW, &tapdebug, 0, "");
  176 
  177 DEV_MODULE(if_tap, tapmodevent, NULL);
  178 
  179 static int
  180 tap_clone_create(struct if_clone *ifc, int unit, caddr_t params)
  181 {
  182         struct cdev *dev;
  183         int i;
  184 
  185         /* Find any existing device, or allocate new unit number. */
  186         i = clone_create(&tapclones, &tap_cdevsw, &unit, &dev, 0);
  187         if (i) {
  188                 dev = make_dev(&tap_cdevsw, unit, UID_ROOT, GID_WHEEL, 0600,
  189                     "%s%d", tapname, unit);
  190         }
  191 
  192         tapcreate(dev);
  193         return (0);
  194 }
  195 
  196 /* vmnet devices are tap devices in disguise */
  197 static int
  198 vmnet_clone_create(struct if_clone *ifc, int unit, caddr_t params)
  199 {
  200         struct cdev *dev;
  201         int i;
  202 
  203         /* Find any existing device, or allocate new unit number. */
  204         i = clone_create(&tapclones, &tap_cdevsw, &unit, &dev, VMNET_DEV_MASK);
  205         if (i) {
  206                 dev = make_dev(&tap_cdevsw, unit | VMNET_DEV_MASK, UID_ROOT,
  207                     GID_WHEEL, 0600, "%s%d", vmnetname, unit);
  208         }
  209 
  210         tapcreate(dev);
  211         return (0);
  212 }
  213 
  214 static void
  215 tap_destroy(struct tap_softc *tp)
  216 {
  217         struct ifnet *ifp = tp->tap_ifp;
  218 
  219         CURVNET_SET(ifp->if_vnet);
  220         destroy_dev(tp->tap_dev);
  221         seldrain(&tp->tap_rsel);
  222         knlist_clear(&tp->tap_rsel.si_note, 0);
  223         knlist_destroy(&tp->tap_rsel.si_note);
  224         ether_ifdetach(ifp);
  225         if_free(ifp);
  226 
  227         mtx_destroy(&tp->tap_mtx);
  228         free(tp, M_TAP);
  229         CURVNET_RESTORE();
  230 }
  231 
  232 static void
  233 tap_clone_destroy(struct ifnet *ifp)
  234 {
  235         struct tap_softc *tp = ifp->if_softc;
  236 
  237         mtx_lock(&tapmtx);
  238         SLIST_REMOVE(&taphead, tp, tap_softc, tap_next);
  239         mtx_unlock(&tapmtx);
  240         tap_destroy(tp);
  241 }
  242 
  243 /* vmnet devices are tap devices in disguise */
  244 static void
  245 vmnet_clone_destroy(struct ifnet *ifp)
  246 {
  247         tap_clone_destroy(ifp);
  248 }
  249 
  250 /*
  251  * tapmodevent
  252  *
  253  * module event handler
  254  */
  255 static int
  256 tapmodevent(module_t mod, int type, void *data)
  257 {
  258         static eventhandler_tag  eh_tag = NULL;
  259         struct tap_softc        *tp = NULL;
  260         struct ifnet            *ifp = NULL;
  261 
  262         switch (type) {
  263         case MOD_LOAD:
  264 
  265                 /* intitialize device */
  266 
  267                 mtx_init(&tapmtx, "tapmtx", NULL, MTX_DEF);
  268                 SLIST_INIT(&taphead);
  269 
  270                 clone_setup(&tapclones);
  271                 eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000);
  272                 if (eh_tag == NULL) {
  273                         clone_cleanup(&tapclones);
  274                         mtx_destroy(&tapmtx);
  275                         return (ENOMEM);
  276                 }
  277                 tap_cloner = if_clone_simple(tapname, tap_clone_create,
  278                     tap_clone_destroy, 0);
  279                 vmnet_cloner = if_clone_simple(vmnetname, vmnet_clone_create,
  280                     vmnet_clone_destroy, 0);
  281                 return (0);
  282 
  283         case MOD_UNLOAD:
  284                 /*
  285                  * The EBUSY algorithm here can't quite atomically
  286                  * guarantee that this is race-free since we have to
  287                  * release the tap mtx to deregister the clone handler.
  288                  */
  289                 mtx_lock(&tapmtx);
  290                 SLIST_FOREACH(tp, &taphead, tap_next) {
  291                         mtx_lock(&tp->tap_mtx);
  292                         if (tp->tap_flags & TAP_OPEN) {
  293                                 mtx_unlock(&tp->tap_mtx);
  294                                 mtx_unlock(&tapmtx);
  295                                 return (EBUSY);
  296                         }
  297                         mtx_unlock(&tp->tap_mtx);
  298                 }
  299                 mtx_unlock(&tapmtx);
  300 
  301                 EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
  302                 if_clone_detach(tap_cloner);
  303                 if_clone_detach(vmnet_cloner);
  304                 drain_dev_clone_events();
  305 
  306                 mtx_lock(&tapmtx);
  307                 while ((tp = SLIST_FIRST(&taphead)) != NULL) {
  308                         SLIST_REMOVE_HEAD(&taphead, tap_next);
  309                         mtx_unlock(&tapmtx);
  310 
  311                         ifp = tp->tap_ifp;
  312 
  313                         TAPDEBUG("detaching %s\n", ifp->if_xname);
  314 
  315                         tap_destroy(tp);
  316                         mtx_lock(&tapmtx);
  317                 }
  318                 mtx_unlock(&tapmtx);
  319                 clone_cleanup(&tapclones);
  320 
  321                 mtx_destroy(&tapmtx);
  322 
  323                 break;
  324 
  325         default:
  326                 return (EOPNOTSUPP);
  327         }
  328 
  329         return (0);
  330 } /* tapmodevent */
  331 
  332 
  333 /*
  334  * DEVFS handler
  335  *
  336  * We need to support two kind of devices - tap and vmnet
  337  */
  338 static void
  339 tapclone(void *arg, struct ucred *cred, char *name, int namelen, struct cdev **dev)
  340 {
  341         char            devname[SPECNAMELEN + 1];
  342         int             i, unit, append_unit;
  343         int             extra;
  344 
  345         if (*dev != NULL)
  346                 return;
  347 
  348         if (!tapdclone ||
  349             (!tapuopen && priv_check_cred(cred, PRIV_NET_IFCREATE, 0) != 0))
  350                 return;
  351 
  352         unit = 0;
  353         append_unit = 0;
  354         extra = 0;
  355 
  356         /* We're interested in only tap/vmnet devices. */
  357         if (strcmp(name, tapname) == 0) {
  358                 unit = -1;
  359         } else if (strcmp(name, vmnetname) == 0) {
  360                 unit = -1;
  361                 extra = VMNET_DEV_MASK;
  362         } else if (dev_stdclone(name, NULL, tapname, &unit) != 1) {
  363                 if (dev_stdclone(name, NULL, vmnetname, &unit) != 1) {
  364                         return;
  365                 } else {
  366                         extra = VMNET_DEV_MASK;
  367                 }
  368         }
  369 
  370         if (unit == -1)
  371                 append_unit = 1;
  372 
  373         CURVNET_SET(CRED_TO_VNET(cred));
  374         /* find any existing device, or allocate new unit number */
  375         i = clone_create(&tapclones, &tap_cdevsw, &unit, dev, extra);
  376         if (i) {
  377                 if (append_unit) {
  378                         /*
  379                          * We were passed 'tun' or 'tap', with no unit specified
  380                          * so we'll need to append it now.
  381                          */
  382                         namelen = snprintf(devname, sizeof(devname), "%s%d", name,
  383                             unit);
  384                         name = devname;
  385                 }
  386 
  387                 *dev = make_dev_credf(MAKEDEV_REF, &tap_cdevsw, unit | extra,
  388                      cred, UID_ROOT, GID_WHEEL, 0600, "%s", name);
  389         }
  390 
  391         if_clone_create(name, namelen, NULL);
  392         CURVNET_RESTORE();
  393 } /* tapclone */
  394 
  395 
  396 /*
  397  * tapcreate
  398  *
  399  * to create interface
  400  */
  401 static void
  402 tapcreate(struct cdev *dev)
  403 {
  404         struct ifnet            *ifp = NULL;
  405         struct tap_softc        *tp = NULL;
  406         unsigned short           macaddr_hi;
  407         uint32_t                 macaddr_mid;
  408         int                      unit;
  409         const char              *name = NULL;
  410         u_char                  eaddr[6];
  411 
  412         /* allocate driver storage and create device */
  413         tp = malloc(sizeof(*tp), M_TAP, M_WAITOK | M_ZERO);
  414         mtx_init(&tp->tap_mtx, "tap_mtx", NULL, MTX_DEF);
  415         mtx_lock(&tapmtx);
  416         SLIST_INSERT_HEAD(&taphead, tp, tap_next);
  417         mtx_unlock(&tapmtx);
  418 
  419         unit = dev2unit(dev);
  420 
  421         /* select device: tap or vmnet */
  422         if (unit & VMNET_DEV_MASK) {
  423                 name = vmnetname;
  424                 tp->tap_flags |= TAP_VMNET;
  425         } else
  426                 name = tapname;
  427 
  428         unit &= TAPMAXUNIT;
  429 
  430         TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, dev2unit(dev));
  431 
  432         /* generate fake MAC address: 00 bd xx xx xx unit_no */
  433         macaddr_hi = htons(0x00bd);
  434         macaddr_mid = (uint32_t) ticks;
  435         bcopy(&macaddr_hi, eaddr, sizeof(short));
  436         bcopy(&macaddr_mid, &eaddr[2], sizeof(uint32_t));
  437         eaddr[5] = (u_char)unit;
  438 
  439         /* fill the rest and attach interface */
  440         ifp = tp->tap_ifp = if_alloc(IFT_ETHER);
  441         if (ifp == NULL)
  442                 panic("%s%d: can not if_alloc()", name, unit);
  443         ifp->if_softc = tp;
  444         if_initname(ifp, name, unit);
  445         ifp->if_init = tapifinit;
  446         ifp->if_start = tapifstart;
  447         ifp->if_ioctl = tapifioctl;
  448         ifp->if_mtu = ETHERMTU;
  449         ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
  450         IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
  451         ifp->if_capabilities |= IFCAP_LINKSTATE;
  452         ifp->if_capenable |= IFCAP_LINKSTATE;
  453 
  454         dev->si_drv1 = tp;
  455         tp->tap_dev = dev;
  456 
  457         ether_ifattach(ifp, eaddr);
  458 
  459         mtx_lock(&tp->tap_mtx);
  460         tp->tap_flags |= TAP_INITED;
  461         mtx_unlock(&tp->tap_mtx);
  462 
  463         knlist_init_mtx(&tp->tap_rsel.si_note, &tp->tap_mtx);
  464 
  465         TAPDEBUG("interface %s is created. minor = %#x\n", 
  466                 ifp->if_xname, dev2unit(dev));
  467 } /* tapcreate */
  468 
  469 
  470 /*
  471  * tapopen
  472  *
  473  * to open tunnel. must be superuser
  474  */
  475 static int
  476 tapopen(struct cdev *dev, int flag, int mode, struct thread *td)
  477 {
  478         struct tap_softc        *tp = NULL;
  479         struct ifnet            *ifp = NULL;
  480         int                      error;
  481 
  482         if (tapuopen == 0) {
  483                 error = priv_check(td, PRIV_NET_TAP);
  484                 if (error)
  485                         return (error);
  486         }
  487 
  488         if ((dev2unit(dev) & CLONE_UNITMASK) > TAPMAXUNIT)
  489                 return (ENXIO);
  490 
  491         tp = dev->si_drv1;
  492 
  493         mtx_lock(&tp->tap_mtx);
  494         if (tp->tap_flags & TAP_OPEN) {
  495                 mtx_unlock(&tp->tap_mtx);
  496                 return (EBUSY);
  497         }
  498 
  499         bcopy(IF_LLADDR(tp->tap_ifp), tp->ether_addr, sizeof(tp->ether_addr));
  500         tp->tap_pid = td->td_proc->p_pid;
  501         tp->tap_flags |= TAP_OPEN;
  502         ifp = tp->tap_ifp;
  503 
  504         ifp->if_drv_flags |= IFF_DRV_RUNNING;
  505         ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
  506         if (tapuponopen)
  507                 ifp->if_flags |= IFF_UP;
  508         if_link_state_change(ifp, LINK_STATE_UP);
  509         mtx_unlock(&tp->tap_mtx);
  510 
  511         TAPDEBUG("%s is open. minor = %#x\n", ifp->if_xname, dev2unit(dev));
  512 
  513         return (0);
  514 } /* tapopen */
  515 
  516 
  517 /*
  518  * tapclose
  519  *
  520  * close the device - mark i/f down & delete routing info
  521  */
  522 static int
  523 tapclose(struct cdev *dev, int foo, int bar, struct thread *td)
  524 {
  525         struct ifaddr           *ifa;
  526         struct tap_softc        *tp = dev->si_drv1;
  527         struct ifnet            *ifp = tp->tap_ifp;
  528 
  529         /* junk all pending output */
  530         mtx_lock(&tp->tap_mtx);
  531         CURVNET_SET(ifp->if_vnet);
  532         IF_DRAIN(&ifp->if_snd);
  533 
  534         /*
  535          * Do not bring the interface down, and do not anything with
  536          * interface, if we are in VMnet mode. Just close the device.
  537          */
  538         if (((tp->tap_flags & TAP_VMNET) == 0) &&
  539             (ifp->if_flags & (IFF_UP | IFF_LINK0)) == IFF_UP) {
  540                 mtx_unlock(&tp->tap_mtx);
  541                 if_down(ifp);
  542                 mtx_lock(&tp->tap_mtx);
  543                 if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
  544                         ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
  545                         mtx_unlock(&tp->tap_mtx);
  546                         TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
  547                                 rtinit(ifa, (int)RTM_DELETE, 0);
  548                         }
  549                         if_purgeaddrs(ifp);
  550                         mtx_lock(&tp->tap_mtx);
  551                 }
  552         }
  553 
  554         if_link_state_change(ifp, LINK_STATE_DOWN);
  555         CURVNET_RESTORE();
  556 
  557         funsetown(&tp->tap_sigio);
  558         selwakeuppri(&tp->tap_rsel, PZERO+1);
  559         KNOTE_LOCKED(&tp->tap_rsel.si_note, 0);
  560 
  561         tp->tap_flags &= ~TAP_OPEN;
  562         tp->tap_pid = 0;
  563         mtx_unlock(&tp->tap_mtx);
  564 
  565         TAPDEBUG("%s is closed. minor = %#x\n", 
  566                 ifp->if_xname, dev2unit(dev));
  567 
  568         return (0);
  569 } /* tapclose */
  570 
  571 
  572 /*
  573  * tapifinit
  574  *
  575  * network interface initialization function
  576  */
  577 static void
  578 tapifinit(void *xtp)
  579 {
  580         struct tap_softc        *tp = (struct tap_softc *)xtp;
  581         struct ifnet            *ifp = tp->tap_ifp;
  582 
  583         TAPDEBUG("initializing %s\n", ifp->if_xname);
  584 
  585         mtx_lock(&tp->tap_mtx);
  586         ifp->if_drv_flags |= IFF_DRV_RUNNING;
  587         ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
  588         mtx_unlock(&tp->tap_mtx);
  589 
  590         /* attempt to start output */
  591         tapifstart(ifp);
  592 } /* tapifinit */
  593 
  594 
  595 /*
  596  * tapifioctl
  597  *
  598  * Process an ioctl request on network interface
  599  */
  600 static int
  601 tapifioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  602 {
  603         struct tap_softc        *tp = ifp->if_softc;
  604         struct ifreq            *ifr = (struct ifreq *)data;
  605         struct ifstat           *ifs = NULL;
  606         struct ifmediareq       *ifmr = NULL;
  607         int                      dummy, error = 0;
  608 
  609         switch (cmd) {
  610                 case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
  611                 case SIOCADDMULTI:
  612                 case SIOCDELMULTI:
  613                         break;
  614 
  615                 case SIOCGIFMEDIA:
  616                         ifmr = (struct ifmediareq *)data;
  617                         dummy = ifmr->ifm_count;
  618                         ifmr->ifm_count = 1;
  619                         ifmr->ifm_status = IFM_AVALID;
  620                         ifmr->ifm_active = IFM_ETHER;
  621                         if (tp->tap_flags & TAP_OPEN)
  622                                 ifmr->ifm_status |= IFM_ACTIVE;
  623                         ifmr->ifm_current = ifmr->ifm_active;
  624                         if (dummy >= 1) {
  625                                 int media = IFM_ETHER;
  626                                 error = copyout(&media, ifmr->ifm_ulist,
  627                                     sizeof(int));
  628                         }
  629                         break;
  630 
  631                 case SIOCSIFMTU:
  632                         ifp->if_mtu = ifr->ifr_mtu;
  633                         break;
  634 
  635                 case SIOCGIFSTATUS:
  636                         ifs = (struct ifstat *)data;
  637                         mtx_lock(&tp->tap_mtx);
  638                         if (tp->tap_pid != 0)
  639                                 snprintf(ifs->ascii, sizeof(ifs->ascii),
  640                                         "\tOpened by PID %d\n", tp->tap_pid);
  641                         else
  642                                 ifs->ascii[0] = '\0';
  643                         mtx_unlock(&tp->tap_mtx);
  644                         break;
  645 
  646                 default:
  647                         error = ether_ioctl(ifp, cmd, data);
  648                         break;
  649         }
  650 
  651         return (error);
  652 } /* tapifioctl */
  653 
  654 
  655 /*
  656  * tapifstart
  657  *
  658  * queue packets from higher level ready to put out
  659  */
  660 static void
  661 tapifstart(struct ifnet *ifp)
  662 {
  663         struct tap_softc        *tp = ifp->if_softc;
  664 
  665         TAPDEBUG("%s starting\n", ifp->if_xname);
  666 
  667         /*
  668          * do not junk pending output if we are in VMnet mode.
  669          * XXX: can this do any harm because of queue overflow?
  670          */
  671 
  672         mtx_lock(&tp->tap_mtx);
  673         if (((tp->tap_flags & TAP_VMNET) == 0) &&
  674             ((tp->tap_flags & TAP_READY) != TAP_READY)) {
  675                 struct mbuf *m;
  676 
  677                 /* Unlocked read. */
  678                 TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname, 
  679                     tp->tap_flags);
  680 
  681                 for (;;) {
  682                         IF_DEQUEUE(&ifp->if_snd, m);
  683                         if (m != NULL) {
  684                                 m_freem(m);
  685                                 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
  686                         } else
  687                                 break;
  688                 }
  689                 mtx_unlock(&tp->tap_mtx);
  690 
  691                 return;
  692         }
  693 
  694         ifp->if_drv_flags |= IFF_DRV_OACTIVE;
  695 
  696         if (!IFQ_IS_EMPTY(&ifp->if_snd)) {
  697                 if (tp->tap_flags & TAP_RWAIT) {
  698                         tp->tap_flags &= ~TAP_RWAIT;
  699                         wakeup(tp);
  700                 }
  701 
  702                 if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL)) {
  703                         mtx_unlock(&tp->tap_mtx);
  704                         pgsigio(&tp->tap_sigio, SIGIO, 0);
  705                         mtx_lock(&tp->tap_mtx);
  706                 }
  707 
  708                 selwakeuppri(&tp->tap_rsel, PZERO+1);
  709                 KNOTE_LOCKED(&tp->tap_rsel.si_note, 0);
  710                 if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); /* obytes are counted in ether_output */
  711         }
  712 
  713         ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
  714         mtx_unlock(&tp->tap_mtx);
  715 } /* tapifstart */
  716 
  717 
  718 /*
  719  * tapioctl
  720  *
  721  * the cdevsw interface is now pretty minimal
  722  */
  723 static int
  724 tapioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
  725 {
  726         struct tap_softc        *tp = dev->si_drv1;
  727         struct ifnet            *ifp = tp->tap_ifp;
  728         struct tapinfo          *tapp = NULL;
  729         int                      f;
  730 #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
  731     defined(COMPAT_FREEBSD4)
  732         int                      ival;
  733 #endif
  734 
  735         switch (cmd) {
  736                 case TAPSIFINFO:
  737                         tapp = (struct tapinfo *)data;
  738                         mtx_lock(&tp->tap_mtx);
  739                         ifp->if_mtu = tapp->mtu;
  740                         ifp->if_type = tapp->type;
  741                         ifp->if_baudrate = tapp->baudrate;
  742                         mtx_unlock(&tp->tap_mtx);
  743                         break;
  744 
  745                 case TAPGIFINFO:
  746                         tapp = (struct tapinfo *)data;
  747                         mtx_lock(&tp->tap_mtx);
  748                         tapp->mtu = ifp->if_mtu;
  749                         tapp->type = ifp->if_type;
  750                         tapp->baudrate = ifp->if_baudrate;
  751                         mtx_unlock(&tp->tap_mtx);
  752                         break;
  753 
  754                 case TAPSDEBUG:
  755                         tapdebug = *(int *)data;
  756                         break;
  757 
  758                 case TAPGDEBUG:
  759                         *(int *)data = tapdebug;
  760                         break;
  761 
  762                 case TAPGIFNAME: {
  763                         struct ifreq    *ifr = (struct ifreq *) data;
  764 
  765                         strlcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ);
  766                         } break;
  767 
  768                 case FIONBIO:
  769                         break;
  770 
  771                 case FIOASYNC:
  772                         mtx_lock(&tp->tap_mtx);
  773                         if (*(int *)data)
  774                                 tp->tap_flags |= TAP_ASYNC;
  775                         else
  776                                 tp->tap_flags &= ~TAP_ASYNC;
  777                         mtx_unlock(&tp->tap_mtx);
  778                         break;
  779 
  780                 case FIONREAD:
  781                         if (!IFQ_IS_EMPTY(&ifp->if_snd)) {
  782                                 struct mbuf *mb;
  783 
  784                                 IFQ_LOCK(&ifp->if_snd);
  785                                 IFQ_POLL_NOLOCK(&ifp->if_snd, mb);
  786                                 for (*(int *)data = 0; mb != NULL;
  787                                      mb = mb->m_next)
  788                                         *(int *)data += mb->m_len;
  789                                 IFQ_UNLOCK(&ifp->if_snd);
  790                         } else
  791                                 *(int *)data = 0;
  792                         break;
  793 
  794                 case FIOSETOWN:
  795                         return (fsetown(*(int *)data, &tp->tap_sigio));
  796 
  797                 case FIOGETOWN:
  798                         *(int *)data = fgetown(&tp->tap_sigio);
  799                         return (0);
  800 
  801                 /* this is deprecated, FIOSETOWN should be used instead */
  802                 case TIOCSPGRP:
  803                         return (fsetown(-(*(int *)data), &tp->tap_sigio));
  804 
  805                 /* this is deprecated, FIOGETOWN should be used instead */
  806                 case TIOCGPGRP:
  807                         *(int *)data = -fgetown(&tp->tap_sigio);
  808                         return (0);
  809 
  810                 /* VMware/VMnet port ioctl's */
  811 
  812 #if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \
  813     defined(COMPAT_FREEBSD4)
  814                 case _IO('V', 0):
  815                         ival = IOCPARM_IVAL(data);
  816                         data = (caddr_t)&ival;
  817                         /* FALLTHROUGH */
  818 #endif
  819                 case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */
  820                         f = *(int *)data;
  821                         f &= 0x0fff;
  822                         f &= ~IFF_CANTCHANGE;
  823                         f |= IFF_UP;
  824 
  825                         mtx_lock(&tp->tap_mtx);
  826                         ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE);
  827                         mtx_unlock(&tp->tap_mtx);
  828                         break;
  829 
  830                 case SIOCGIFADDR:       /* get MAC address of the remote side */
  831                         mtx_lock(&tp->tap_mtx);
  832                         bcopy(tp->ether_addr, data, sizeof(tp->ether_addr));
  833                         mtx_unlock(&tp->tap_mtx);
  834                         break;
  835 
  836                 case SIOCSIFADDR:       /* set MAC address of the remote side */
  837                         mtx_lock(&tp->tap_mtx);
  838                         bcopy(data, tp->ether_addr, sizeof(tp->ether_addr));
  839                         mtx_unlock(&tp->tap_mtx);
  840                         break;
  841 
  842                 default:
  843                         return (ENOTTY);
  844         }
  845         return (0);
  846 } /* tapioctl */
  847 
  848 
  849 /*
  850  * tapread
  851  *
  852  * the cdevsw read interface - reads a packet at a time, or at
  853  * least as much of a packet as can be read
  854  */
  855 static int
  856 tapread(struct cdev *dev, struct uio *uio, int flag)
  857 {
  858         struct tap_softc        *tp = dev->si_drv1;
  859         struct ifnet            *ifp = tp->tap_ifp;
  860         struct mbuf             *m = NULL;
  861         int                      error = 0, len;
  862 
  863         TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, dev2unit(dev));
  864 
  865         mtx_lock(&tp->tap_mtx);
  866         if ((tp->tap_flags & TAP_READY) != TAP_READY) {
  867                 mtx_unlock(&tp->tap_mtx);
  868 
  869                 /* Unlocked read. */
  870                 TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n",
  871                         ifp->if_xname, dev2unit(dev), tp->tap_flags);
  872 
  873                 return (EHOSTDOWN);
  874         }
  875 
  876         tp->tap_flags &= ~TAP_RWAIT;
  877 
  878         /* sleep until we get a packet */
  879         do {
  880                 IF_DEQUEUE(&ifp->if_snd, m);
  881 
  882                 if (m == NULL) {
  883                         if (flag & O_NONBLOCK) {
  884                                 mtx_unlock(&tp->tap_mtx);
  885                                 return (EWOULDBLOCK);
  886                         }
  887 
  888                         tp->tap_flags |= TAP_RWAIT;
  889                         error = mtx_sleep(tp, &tp->tap_mtx, PCATCH | (PZERO + 1),
  890                             "taprd", 0);
  891                         if (error) {
  892                                 mtx_unlock(&tp->tap_mtx);
  893                                 return (error);
  894                         }
  895                 }
  896         } while (m == NULL);
  897         mtx_unlock(&tp->tap_mtx);
  898 
  899         /* feed packet to bpf */
  900         BPF_MTAP(ifp, m);
  901 
  902         /* xfer packet to user space */
  903         while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) {
  904                 len = min(uio->uio_resid, m->m_len);
  905                 if (len == 0)
  906                         break;
  907 
  908                 error = uiomove(mtod(m, void *), len, uio);
  909                 m = m_free(m);
  910         }
  911 
  912         if (m != NULL) {
  913                 TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname, 
  914                         dev2unit(dev));
  915                 m_freem(m);
  916         }
  917 
  918         return (error);
  919 } /* tapread */
  920 
  921 
  922 /*
  923  * tapwrite
  924  *
  925  * the cdevsw write interface - an atomic write is a packet - or else!
  926  */
  927 static int
  928 tapwrite(struct cdev *dev, struct uio *uio, int flag)
  929 {
  930         struct ether_header     *eh;
  931         struct tap_softc        *tp = dev->si_drv1;
  932         struct ifnet            *ifp = tp->tap_ifp;
  933         struct mbuf             *m;
  934 
  935         TAPDEBUG("%s writing, minor = %#x\n", 
  936                 ifp->if_xname, dev2unit(dev));
  937 
  938         if (uio->uio_resid == 0)
  939                 return (0);
  940 
  941         if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) {
  942                 TAPDEBUG("%s invalid packet len = %zd, minor = %#x\n",
  943                         ifp->if_xname, uio->uio_resid, dev2unit(dev));
  944 
  945                 return (EIO);
  946         }
  947 
  948         if ((m = m_uiotombuf(uio, M_NOWAIT, 0, ETHER_ALIGN,
  949             M_PKTHDR)) == NULL) {
  950                 if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
  951                 return (ENOBUFS);
  952         }
  953 
  954         m->m_pkthdr.rcvif = ifp;
  955 
  956         /*
  957          * Only pass a unicast frame to ether_input(), if it would actually
  958          * have been received by non-virtual hardware.
  959          */
  960         if (m->m_len < sizeof(struct ether_header)) {
  961                 m_freem(m);
  962                 return (0);
  963         }
  964         eh = mtod(m, struct ether_header *);
  965 
  966         if (eh && (ifp->if_flags & IFF_PROMISC) == 0 &&
  967             !ETHER_IS_MULTICAST(eh->ether_dhost) &&
  968             bcmp(eh->ether_dhost, IF_LLADDR(ifp), ETHER_ADDR_LEN) != 0) {
  969                 m_freem(m);
  970                 return (0);
  971         }
  972 
  973         /* Pass packet up to parent. */
  974         CURVNET_SET(ifp->if_vnet);
  975         (*ifp->if_input)(ifp, m);
  976         CURVNET_RESTORE();
  977         if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1); /* ibytes are counted in parent */
  978 
  979         return (0);
  980 } /* tapwrite */
  981 
  982 
  983 /*
  984  * tappoll
  985  *
  986  * the poll interface, this is only useful on reads
  987  * really. the write detect always returns true, write never blocks
  988  * anyway, it either accepts the packet or drops it
  989  */
  990 static int
  991 tappoll(struct cdev *dev, int events, struct thread *td)
  992 {
  993         struct tap_softc        *tp = dev->si_drv1;
  994         struct ifnet            *ifp = tp->tap_ifp;
  995         int                      revents = 0;
  996 
  997         TAPDEBUG("%s polling, minor = %#x\n", 
  998                 ifp->if_xname, dev2unit(dev));
  999 
 1000         if (events & (POLLIN | POLLRDNORM)) {
 1001                 IFQ_LOCK(&ifp->if_snd);
 1002                 if (!IFQ_IS_EMPTY(&ifp->if_snd)) {
 1003                         TAPDEBUG("%s have data in queue. len = %d, " \
 1004                                 "minor = %#x\n", ifp->if_xname,
 1005                                 ifp->if_snd.ifq_len, dev2unit(dev));
 1006 
 1007                         revents |= (events & (POLLIN | POLLRDNORM));
 1008                 } else {
 1009                         TAPDEBUG("%s waiting for data, minor = %#x\n",
 1010                                 ifp->if_xname, dev2unit(dev));
 1011 
 1012                         selrecord(td, &tp->tap_rsel);
 1013                 }
 1014                 IFQ_UNLOCK(&ifp->if_snd);
 1015         }
 1016 
 1017         if (events & (POLLOUT | POLLWRNORM))
 1018                 revents |= (events & (POLLOUT | POLLWRNORM));
 1019 
 1020         return (revents);
 1021 } /* tappoll */
 1022 
 1023 
 1024 /*
 1025  * tap_kqfilter
 1026  *
 1027  * support for kevent() system call
 1028  */
 1029 static int
 1030 tapkqfilter(struct cdev *dev, struct knote *kn)
 1031 {
 1032         struct tap_softc        *tp = dev->si_drv1;
 1033         struct ifnet            *ifp = tp->tap_ifp;
 1034 
 1035         switch (kn->kn_filter) {
 1036         case EVFILT_READ:
 1037                 TAPDEBUG("%s kqfilter: EVFILT_READ, minor = %#x\n",
 1038                         ifp->if_xname, dev2unit(dev));
 1039                 kn->kn_fop = &tap_read_filterops;
 1040                 break;
 1041 
 1042         case EVFILT_WRITE:
 1043                 TAPDEBUG("%s kqfilter: EVFILT_WRITE, minor = %#x\n",
 1044                         ifp->if_xname, dev2unit(dev));
 1045                 kn->kn_fop = &tap_write_filterops;
 1046                 break;
 1047 
 1048         default:
 1049                 TAPDEBUG("%s kqfilter: invalid filter, minor = %#x\n",
 1050                         ifp->if_xname, dev2unit(dev));
 1051                 return (EINVAL);
 1052                 /* NOT REACHED */
 1053         }
 1054 
 1055         kn->kn_hook = tp;
 1056         knlist_add(&tp->tap_rsel.si_note, kn, 0);
 1057 
 1058         return (0);
 1059 } /* tapkqfilter */
 1060 
 1061 
 1062 /*
 1063  * tap_kqread
 1064  * 
 1065  * Return true if there is data in the interface queue
 1066  */
 1067 static int
 1068 tapkqread(struct knote *kn, long hint)
 1069 {
 1070         int                      ret;
 1071         struct tap_softc        *tp = kn->kn_hook;
 1072         struct cdev             *dev = tp->tap_dev;
 1073         struct ifnet            *ifp = tp->tap_ifp;
 1074 
 1075         if ((kn->kn_data = ifp->if_snd.ifq_len) > 0) {
 1076                 TAPDEBUG("%s have data in queue. len = %d, minor = %#x\n",
 1077                         ifp->if_xname, ifp->if_snd.ifq_len, dev2unit(dev));
 1078                 ret = 1;
 1079         } else {
 1080                 TAPDEBUG("%s waiting for data, minor = %#x\n",
 1081                         ifp->if_xname, dev2unit(dev));
 1082                 ret = 0;
 1083         }
 1084 
 1085         return (ret);
 1086 } /* tapkqread */
 1087 
 1088 
 1089 /*
 1090  * tap_kqwrite
 1091  *
 1092  * Always can write. Return the MTU in kn->data
 1093  */
 1094 static int
 1095 tapkqwrite(struct knote *kn, long hint)
 1096 {
 1097         struct tap_softc        *tp = kn->kn_hook;
 1098         struct ifnet            *ifp = tp->tap_ifp;
 1099 
 1100         kn->kn_data = ifp->if_mtu;
 1101 
 1102         return (1);
 1103 } /* tapkqwrite */
 1104 
 1105 
 1106 static void
 1107 tapkqdetach(struct knote *kn)
 1108 {
 1109         struct tap_softc        *tp = kn->kn_hook;
 1110 
 1111         knlist_remove(&tp->tap_rsel.si_note, kn, 0);
 1112 } /* tapkqdetach */
 1113 

Cache object: f7cd17d3ff9b46e32a4c66e04037d287


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