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/5.2/sys/net/if_tap.c 122352 2003-11-09 09:17:26Z tanimura $
   35  * $Id: if_tap.c,v 0.21 2000/07/23 21:46:02 max Exp $
   36  */
   37 
   38 #include "opt_inet.h"
   39 
   40 #include <sys/param.h>
   41 #include <sys/conf.h>
   42 #include <sys/filedesc.h>
   43 #include <sys/filio.h>
   44 #include <sys/kernel.h>
   45 #include <sys/malloc.h>
   46 #include <sys/mbuf.h>
   47 #include <sys/poll.h>
   48 #include <sys/proc.h>
   49 #include <sys/signalvar.h>
   50 #include <sys/socket.h>
   51 #include <sys/sockio.h>
   52 #include <sys/sysctl.h>
   53 #include <sys/systm.h>
   54 #include <sys/ttycom.h>
   55 #include <sys/uio.h>
   56 #include <sys/vnode.h>
   57 #include <machine/bus.h>        /* XXX: Shouldn't really be required! */
   58 #include <sys/rman.h>
   59 #include <sys/queue.h>
   60 
   61 #include <net/bpf.h>
   62 #include <net/ethernet.h>
   63 #include <net/if.h>
   64 #include <net/if_arp.h>
   65 #include <net/route.h>
   66 
   67 #include <netinet/in.h>
   68 
   69 #include <net/if_tapvar.h>
   70 #include <net/if_tap.h>
   71 
   72 
   73 #define CDEV_NAME       "tap"
   74 #define CDEV_MAJOR      149
   75 #define TAPDEBUG        if (tapdebug) printf
   76 
   77 #define TAP             "tap"
   78 #define VMNET           "vmnet"
   79 #define TAPMAXUNIT      0x7fff
   80 #define VMNET_DEV_MASK  0x00800000
   81                 /*      0x007f00ff      */
   82 
   83 /* module */
   84 static int              tapmodevent(module_t, int, void *);
   85 
   86 /* device */
   87 static void             tapclone(void *, char *, int, dev_t *);
   88 static void             tapcreate(dev_t);
   89 
   90 /* network interface */
   91 static void             tapifstart(struct ifnet *);
   92 static int              tapifioctl(struct ifnet *, u_long, caddr_t);
   93 static void             tapifinit(void *);
   94 
   95 /* character device */
   96 static d_open_t         tapopen;
   97 static d_close_t        tapclose;
   98 static d_read_t         tapread;
   99 static d_write_t        tapwrite;
  100 static d_ioctl_t        tapioctl;
  101 static d_poll_t         tappoll;
  102 
  103 static struct cdevsw    tap_cdevsw = {
  104         .d_open =       tapopen,
  105         .d_close =      tapclose,
  106         .d_read =       tapread,
  107         .d_write =      tapwrite,
  108         .d_ioctl =      tapioctl,
  109         .d_poll =       tappoll,
  110         .d_name =       CDEV_NAME,
  111         .d_maj =        CDEV_MAJOR,
  112 };
  113 
  114 static int                      tapdebug = 0;        /* debug flag   */
  115 static SLIST_HEAD(, tap_softc)  taphead;             /* first device */
  116 static udev_t                   tapbasedev = NOUDEV; /* base device  */
  117 static struct rman              tapdevunits[2];      /* device units */
  118 #define         tapunits        tapdevunits
  119 #define         vmnetunits      (tapdevunits + 1)
  120 
  121 MALLOC_DECLARE(M_TAP);
  122 MALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
  123 SYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
  124 DEV_MODULE(if_tap, tapmodevent, NULL);
  125 
  126 /*
  127  * tapmodevent
  128  *
  129  * module event handler
  130  */
  131 static int
  132 tapmodevent(mod, type, data)
  133         module_t         mod;
  134         int              type;
  135         void            *data;
  136 {
  137         static eventhandler_tag  eh_tag = NULL;
  138         struct tap_softc        *tp = NULL;
  139         struct ifnet            *ifp = NULL;
  140         int                      error, s;
  141 
  142         switch (type) {
  143         case MOD_LOAD:
  144                 /* initialize resources */
  145                 tapunits->rm_type = RMAN_ARRAY;
  146                 tapunits->rm_descr = "open tap units";
  147                 vmnetunits->rm_type = RMAN_ARRAY;
  148                 vmnetunits->rm_descr = "open vmnet units";
  149 
  150                 error = rman_init(tapunits);
  151                 if (error != 0)
  152                         goto bail;
  153 
  154                 error = rman_init(vmnetunits);
  155                 if (error != 0)
  156                         goto bail1;
  157 
  158                 error = rman_manage_region(tapunits, 0, TAPMAXUNIT);
  159                 if (error != 0)
  160                         goto bail2;
  161 
  162                 error = rman_manage_region(vmnetunits, 0, TAPMAXUNIT);
  163                 if (error != 0)
  164                         goto bail2;
  165 
  166                 /* intitialize device */
  167 
  168                 SLIST_INIT(&taphead);
  169 
  170                 eh_tag = EVENTHANDLER_REGISTER(dev_clone, tapclone, 0, 1000);
  171                 if (eh_tag == NULL) {
  172                         error = ENOMEM;
  173                         goto bail2;
  174                 }
  175 
  176 
  177                 return (0);
  178 bail2:
  179                 rman_fini(vmnetunits);
  180 bail1:
  181                 rman_fini(tapunits);
  182 bail:
  183                 return (error);
  184 
  185         case MOD_UNLOAD:
  186                 SLIST_FOREACH(tp, &taphead, tap_next)
  187                         if (tp->tap_unit != NULL)
  188                                 return (EBUSY);
  189 
  190                 EVENTHANDLER_DEREGISTER(dev_clone, eh_tag);
  191 
  192                 error = rman_fini(tapunits);
  193                 KASSERT((error == 0), ("Could not fini tap units"));
  194                 error = rman_fini(vmnetunits);
  195                 KASSERT((error == 0), ("Could not fini vmnet units"));
  196 
  197                 while ((tp = SLIST_FIRST(&taphead)) != NULL) {
  198                         SLIST_REMOVE_HEAD(&taphead, tap_next);
  199 
  200                         ifp = &tp->tap_if;
  201 
  202                         TAPDEBUG("detaching %s\n", ifp->if_xname);
  203 
  204                         KASSERT(!(tp->tap_flags & TAP_OPEN), 
  205                                 ("%s flags is out of sync", ifp->if_xname));
  206 
  207                         /* XXX makedev check? nah.. not right now :) */
  208 
  209                         s = splimp();
  210                         ether_ifdetach(ifp);
  211                         splx(s);
  212 
  213                         free(tp, M_TAP);
  214                 }
  215 
  216                 if (tapbasedev != NOUDEV)
  217                         destroy_dev(udev2dev(tapbasedev, 0));
  218 
  219 
  220                 break;
  221 
  222         default:
  223                 return (EOPNOTSUPP);
  224         }
  225 
  226         return (0);
  227 } /* tapmodevent */
  228 
  229 
  230 /*
  231  * DEVFS handler
  232  *
  233  * We need to support two kind of devices - tap and vmnet
  234  */
  235 static void
  236 tapclone(arg, name, namelen, dev)
  237         void    *arg;
  238         char    *name;
  239         int      namelen;
  240         dev_t   *dev;
  241 {
  242         int              unit, minor = 0 /* XXX avoid warning */ , error;
  243         char            *device_name = name;
  244         struct resource *r = NULL;
  245 
  246         if (*dev != NODEV)
  247                 return;
  248 
  249         if (strcmp(device_name, TAP) == 0) {
  250                 /* get first free tap unit */
  251                 r = rman_reserve_resource(tapunits, 0, TAPMAXUNIT, 1,
  252                         RF_ALLOCATED | RF_ACTIVE, NULL);
  253                 unit = rman_get_start(r);
  254                 minor = unit2minor(unit);
  255         }
  256         else if (strcmp(device_name, VMNET) == 0) {
  257                 /* get first free vmnet unit */
  258                 r = rman_reserve_resource(vmnetunits, 0, TAPMAXUNIT, 1,
  259                         RF_ALLOCATED | RF_ACTIVE, NULL);
  260                 unit = rman_get_start(r);
  261                 minor = unit2minor(unit) | VMNET_DEV_MASK;
  262         }
  263 
  264         if (r != NULL) { /* need cloning */
  265                 TAPDEBUG("%s%d is available. minor = %#x\n",
  266                         device_name, unit, minor);
  267 
  268                 error = rman_release_resource(r);
  269                 KASSERT((error == 0), ("Could not release tap/vmnet unit"));
  270 
  271                 /* check if device for the unit has been created */
  272                 *dev = makedev(CDEV_MAJOR, minor);
  273                 if ((*dev)->si_flags & SI_NAMED) {
  274                         TAPDEBUG("%s%d device exists. minor = %#x\n",
  275                                 device_name, unit, minor);
  276                         return; /* device has been created */
  277                 }
  278         } else { /* try to match name/unit, first try tap then vmnet */
  279                 device_name = TAP;
  280                 if (dev_stdclone(name, NULL, device_name, &unit) != 1) {
  281                         device_name = VMNET;
  282 
  283                         if (dev_stdclone(name, NULL, device_name, &unit) != 1)
  284                                 return;
  285 
  286                         minor = unit2minor(unit) | VMNET_DEV_MASK;
  287                 } else
  288                         minor = unit2minor(unit);
  289         }
  290 
  291         TAPDEBUG("make_dev(%s%d). minor = %#x\n", device_name, unit, minor);
  292 
  293         *dev = make_dev(&tap_cdevsw, minor, UID_ROOT, GID_WHEEL, 0600, "%s%d",
  294                         device_name, unit);
  295 
  296         if (tapbasedev == NOUDEV)
  297                 tapbasedev = (*dev)->si_udev;
  298         else {
  299                 (*dev)->si_flags |= SI_CHEAPCLONE;
  300                 dev_depends(udev2dev(tapbasedev, 0), *dev);
  301         }
  302 } /* tapclone */
  303 
  304 
  305 /*
  306  * tapcreate
  307  *
  308  * to create interface
  309  */
  310 static void
  311 tapcreate(dev)
  312         dev_t   dev;
  313 {
  314         struct ifnet            *ifp = NULL;
  315         struct tap_softc        *tp = NULL;
  316         unsigned short           macaddr_hi;
  317         int                      unit, s;
  318         char                    *name = NULL;
  319 
  320         /* allocate driver storage and create device */
  321         MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK | M_ZERO);
  322         SLIST_INSERT_HEAD(&taphead, tp, tap_next);
  323 
  324         unit = dev2unit(dev) & TAPMAXUNIT;
  325 
  326         /* select device: tap or vmnet */
  327         if (minor(dev) & VMNET_DEV_MASK) {
  328                 name = VMNET;
  329                 tp->tap_flags |= TAP_VMNET;
  330         } else
  331                 name = TAP;
  332 
  333         TAPDEBUG("tapcreate(%s%d). minor = %#x\n", name, unit, minor(dev));
  334 
  335         if (!(dev->si_flags & SI_NAMED))
  336                 dev = make_dev(&tap_cdevsw, minor(dev), UID_ROOT, GID_WHEEL,
  337                                                 0600, "%s%d", name, unit);
  338 
  339         /* generate fake MAC address: 00 bd xx xx xx unit_no */
  340         macaddr_hi = htons(0x00bd);
  341         bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short));
  342         bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long));
  343         tp->arpcom.ac_enaddr[5] = (u_char)unit;
  344 
  345         /* fill the rest and attach interface */
  346         ifp = &tp->tap_if;
  347         ifp->if_softc = tp;
  348         if_initname(ifp, name, unit);
  349         ifp->if_init = tapifinit;
  350         ifp->if_start = tapifstart;
  351         ifp->if_ioctl = tapifioctl;
  352         ifp->if_mtu = ETHERMTU;
  353         ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
  354         ifp->if_snd.ifq_maxlen = ifqmaxlen;
  355 
  356         dev->si_drv1 = tp;
  357 
  358         s = splimp();
  359         ether_ifattach(ifp, tp->arpcom.ac_enaddr);
  360         splx(s);
  361 
  362         tp->tap_flags |= TAP_INITED;
  363 
  364         TAPDEBUG("interface %s is created. minor = %#x\n", 
  365                 ifp->if_xname, minor(dev));
  366 } /* tapcreate */
  367 
  368 
  369 /*
  370  * tapopen
  371  *
  372  * to open tunnel. must be superuser
  373  */
  374 static int
  375 tapopen(dev, flag, mode, td)
  376         dev_t            dev;
  377         int              flag;
  378         int              mode;
  379         struct thread   *td;
  380 {
  381         struct tap_softc        *tp = NULL;
  382         int                      unit, error;
  383         struct resource         *r = NULL;
  384 
  385         if ((error = suser(td)) != 0)
  386                 return (error);
  387 
  388         unit = dev2unit(dev) & TAPMAXUNIT;
  389 
  390         if (minor(dev) & VMNET_DEV_MASK)
  391                 r = rman_reserve_resource(vmnetunits, unit, unit, 1,
  392                         RF_ALLOCATED | RF_ACTIVE, NULL);
  393         else
  394                 r = rman_reserve_resource(tapunits, unit, unit, 1,
  395                         RF_ALLOCATED | RF_ACTIVE, NULL);
  396 
  397         if (r == NULL)
  398                 return (EBUSY);
  399 
  400         dev->si_flags &= ~SI_CHEAPCLONE;
  401 
  402         tp = dev->si_drv1;
  403         if (tp == NULL) {
  404                 tapcreate(dev);
  405                 tp = dev->si_drv1;
  406         }
  407 
  408         KASSERT(!(tp->tap_flags & TAP_OPEN), 
  409                 ("%s flags is out of sync", tp->tap_if.if_xname));
  410 
  411         bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr));
  412 
  413         tp->tap_unit = r;
  414         tp->tap_pid = td->td_proc->p_pid;
  415         tp->tap_flags |= TAP_OPEN;
  416 
  417         TAPDEBUG("%s is open. minor = %#x\n", 
  418                 tp->tap_if.if_xname, minor(dev));
  419 
  420         return (0);
  421 } /* tapopen */
  422 
  423 
  424 /*
  425  * tapclose
  426  *
  427  * close the device - mark i/f down & delete routing info
  428  */
  429 static int
  430 tapclose(dev, foo, bar, td)
  431         dev_t            dev;
  432         int              foo;
  433         int              bar;
  434         struct thread   *td;
  435 {
  436         int                      s, error;
  437         struct tap_softc        *tp = dev->si_drv1;
  438         struct ifnet            *ifp = &tp->tap_if;
  439 
  440         KASSERT((tp->tap_unit != NULL),
  441                 ("%s is not open", ifp->if_xname));
  442 
  443         /* junk all pending output */
  444         IF_DRAIN(&ifp->if_snd);
  445 
  446         /*
  447          * do not bring the interface down, and do not anything with
  448          * interface, if we are in VMnet mode. just close the device.
  449          */
  450 
  451         if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) {
  452                 s = splimp();
  453                 if_down(ifp);
  454                 if (ifp->if_flags & IFF_RUNNING) {
  455                         /* find internet addresses and delete routes */
  456                         struct ifaddr   *ifa = NULL;
  457 
  458                         TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
  459                                 if (ifa->ifa_addr->sa_family == AF_INET) {
  460                                         rtinit(ifa, (int)RTM_DELETE, 0);
  461 
  462                                         /* remove address from interface */
  463                                         bzero(ifa->ifa_addr,
  464                                                    sizeof(*(ifa->ifa_addr)));
  465                                         bzero(ifa->ifa_dstaddr,
  466                                                    sizeof(*(ifa->ifa_dstaddr)));
  467                                         bzero(ifa->ifa_netmask,
  468                                                    sizeof(*(ifa->ifa_netmask)));
  469                                 }
  470                         }
  471 
  472                         ifp->if_flags &= ~IFF_RUNNING;
  473                 }
  474                 splx(s);
  475         }
  476 
  477         funsetown(&tp->tap_sigio);
  478         selwakeuppri(&tp->tap_rsel, PZERO+1);
  479 
  480         tp->tap_flags &= ~TAP_OPEN;
  481         tp->tap_pid = 0;
  482         error = rman_release_resource(tp->tap_unit);
  483         KASSERT((error == 0), 
  484                 ("%s could not release unit", ifp->if_xname)); 
  485         tp->tap_unit = NULL;
  486 
  487         TAPDEBUG("%s is closed. minor = %#x\n", 
  488                 ifp->if_xname, minor(dev));
  489 
  490         return (0);
  491 } /* tapclose */
  492 
  493 
  494 /*
  495  * tapifinit
  496  *
  497  * network interface initialization function
  498  */
  499 static void
  500 tapifinit(xtp)
  501         void    *xtp;
  502 {
  503         struct tap_softc        *tp = (struct tap_softc *)xtp;
  504         struct ifnet            *ifp = &tp->tap_if;
  505 
  506         TAPDEBUG("initializing %s\n", ifp->if_xname);
  507 
  508         ifp->if_flags |= IFF_RUNNING;
  509         ifp->if_flags &= ~IFF_OACTIVE;
  510 
  511         /* attempt to start output */
  512         tapifstart(ifp);
  513 } /* tapifinit */
  514 
  515 
  516 /*
  517  * tapifioctl
  518  *
  519  * Process an ioctl request on network interface
  520  */
  521 static int
  522 tapifioctl(ifp, cmd, data)
  523         struct ifnet    *ifp;
  524         u_long           cmd;
  525         caddr_t          data;
  526 {
  527         struct tap_softc        *tp = (struct tap_softc *)(ifp->if_softc);
  528         struct ifstat           *ifs = NULL;
  529         int                      s, dummy;
  530 
  531         switch (cmd) {
  532                 case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
  533                 case SIOCADDMULTI:
  534                 case SIOCDELMULTI:
  535                         break;
  536 
  537                 case SIOCGIFSTATUS:
  538                         s = splimp();
  539                         ifs = (struct ifstat *)data;
  540                         dummy = strlen(ifs->ascii);
  541                         if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii))
  542                                 snprintf(ifs->ascii + dummy,
  543                                         sizeof(ifs->ascii) - dummy,
  544                                         "\tOpened by PID %d\n", tp->tap_pid);
  545                         splx(s);
  546                         break;
  547 
  548                 default:
  549                         s = splimp();
  550                         dummy = ether_ioctl(ifp, cmd, data);
  551                         splx(s);
  552                         return (dummy);
  553         }
  554 
  555         return (0);
  556 } /* tapifioctl */
  557 
  558 
  559 /*
  560  * tapifstart
  561  *
  562  * queue packets from higher level ready to put out
  563  */
  564 static void
  565 tapifstart(ifp)
  566         struct ifnet    *ifp;
  567 {
  568         struct tap_softc        *tp = ifp->if_softc;
  569         int                      s;
  570 
  571         TAPDEBUG("%s starting\n", ifp->if_xname);
  572 
  573         /*
  574          * do not junk pending output if we are in VMnet mode.
  575          * XXX: can this do any harm because of queue overflow?
  576          */
  577 
  578         if (((tp->tap_flags & TAP_VMNET) == 0) &&
  579             ((tp->tap_flags & TAP_READY) != TAP_READY)) {
  580                 struct mbuf     *m = NULL;
  581 
  582                 TAPDEBUG("%s not ready, tap_flags = 0x%x\n", ifp->if_xname, 
  583                     tp->tap_flags);
  584 
  585                 s = splimp();
  586                 do {
  587                         IF_DEQUEUE(&ifp->if_snd, m);
  588                         if (m != NULL)
  589                                 m_freem(m);
  590                         ifp->if_oerrors ++;
  591                 } while (m != NULL);
  592                 splx(s);
  593 
  594                 return;
  595         }
  596 
  597         s = splimp();
  598         ifp->if_flags |= IFF_OACTIVE;
  599 
  600         if (ifp->if_snd.ifq_len != 0) {
  601                 if (tp->tap_flags & TAP_RWAIT) {
  602                         tp->tap_flags &= ~TAP_RWAIT;
  603                         wakeup(tp);
  604                 }
  605 
  606                 if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL))
  607                         pgsigio(&tp->tap_sigio, SIGIO, 0);
  608 
  609                 selwakeuppri(&tp->tap_rsel, PZERO+1);
  610                 ifp->if_opackets ++; /* obytes are counted in ether_output */
  611         }
  612 
  613         ifp->if_flags &= ~IFF_OACTIVE;
  614         splx(s);
  615 } /* tapifstart */
  616 
  617 
  618 /*
  619  * tapioctl
  620  *
  621  * the cdevsw interface is now pretty minimal
  622  */
  623 static int
  624 tapioctl(dev, cmd, data, flag, td)
  625         dev_t            dev;
  626         u_long           cmd;
  627         caddr_t          data;
  628         int              flag;
  629         struct thread   *td;
  630 {
  631         struct tap_softc        *tp = dev->si_drv1;
  632         struct ifnet            *ifp = &tp->tap_if;
  633         struct tapinfo          *tapp = NULL;
  634         int                      s;
  635         int                      f;
  636 
  637         switch (cmd) {
  638                 case TAPSIFINFO:
  639                         s = splimp();
  640                         tapp = (struct tapinfo *)data;
  641                         ifp->if_mtu = tapp->mtu;
  642                         ifp->if_type = tapp->type;
  643                         ifp->if_baudrate = tapp->baudrate;
  644                         splx(s);
  645                         break;
  646 
  647                 case TAPGIFINFO:
  648                         tapp = (struct tapinfo *)data;
  649                         tapp->mtu = ifp->if_mtu;
  650                         tapp->type = ifp->if_type;
  651                         tapp->baudrate = ifp->if_baudrate;
  652                         break;
  653 
  654                 case TAPSDEBUG:
  655                         tapdebug = *(int *)data;
  656                         break;
  657 
  658                 case TAPGDEBUG:
  659                         *(int *)data = tapdebug;
  660                         break;
  661 
  662                 case FIONBIO:
  663                         break;
  664 
  665                 case FIOASYNC:
  666                         s = splimp();
  667                         if (*(int *)data)
  668                                 tp->tap_flags |= TAP_ASYNC;
  669                         else
  670                                 tp->tap_flags &= ~TAP_ASYNC;
  671                         splx(s);
  672                         break;
  673 
  674                 case FIONREAD:
  675                         s = splimp();
  676                         if (ifp->if_snd.ifq_head) {
  677                                 struct mbuf     *mb = ifp->if_snd.ifq_head;
  678 
  679                                 for(*(int *)data = 0;mb != NULL;mb = mb->m_next)
  680                                         *(int *)data += mb->m_len;
  681                         } else
  682                                 *(int *)data = 0;
  683                         splx(s);
  684                         break;
  685 
  686                 case FIOSETOWN:
  687                         return (fsetown(*(int *)data, &tp->tap_sigio));
  688 
  689                 case FIOGETOWN:
  690                         *(int *)data = fgetown(&tp->tap_sigio);
  691                         return (0);
  692 
  693                 /* this is deprecated, FIOSETOWN should be used instead */
  694                 case TIOCSPGRP:
  695                         return (fsetown(-(*(int *)data), &tp->tap_sigio));
  696 
  697                 /* this is deprecated, FIOGETOWN should be used instead */
  698                 case TIOCGPGRP:
  699                         *(int *)data = -fgetown(&tp->tap_sigio);
  700                         return (0);
  701 
  702                 /* VMware/VMnet port ioctl's */
  703 
  704                 case SIOCGIFFLAGS:      /* get ifnet flags */
  705                         bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags));
  706                         break;
  707 
  708                 case VMIO_SIOCSIFFLAGS: /* VMware/VMnet SIOCSIFFLAGS */
  709                         f = *(int *)data;
  710                         f &= 0x0fff;
  711                         f &= ~IFF_CANTCHANGE;
  712                         f |= IFF_UP;
  713 
  714                         s = splimp();
  715                         ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE);
  716                         splx(s);
  717                         break;
  718 
  719                 case OSIOCGIFADDR:      /* get MAC address of the remote side */
  720                 case SIOCGIFADDR:
  721                         bcopy(tp->ether_addr, data, sizeof(tp->ether_addr));
  722                         break;
  723 
  724                 case SIOCSIFADDR:       /* set MAC address of the remote side */
  725                         bcopy(data, tp->ether_addr, sizeof(tp->ether_addr));
  726                         break;
  727 
  728                 default:
  729                         return (ENOTTY);
  730         }
  731         return (0);
  732 } /* tapioctl */
  733 
  734 
  735 /*
  736  * tapread
  737  *
  738  * the cdevsw read interface - reads a packet at a time, or at
  739  * least as much of a packet as can be read
  740  */
  741 static int
  742 tapread(dev, uio, flag)
  743         dev_t            dev;
  744         struct uio      *uio;
  745         int              flag;
  746 {
  747         struct tap_softc        *tp = dev->si_drv1;
  748         struct ifnet            *ifp = &tp->tap_if;
  749         struct mbuf             *m = NULL;
  750         int                      error = 0, len, s;
  751 
  752         TAPDEBUG("%s reading, minor = %#x\n", ifp->if_xname, minor(dev));
  753 
  754         if ((tp->tap_flags & TAP_READY) != TAP_READY) {
  755                 TAPDEBUG("%s not ready. minor = %#x, tap_flags = 0x%x\n",
  756                         ifp->if_xname, minor(dev), tp->tap_flags);
  757 
  758                 return (EHOSTDOWN);
  759         }
  760 
  761         tp->tap_flags &= ~TAP_RWAIT;
  762 
  763         /* sleep until we get a packet */
  764         do {
  765                 s = splimp();
  766                 IF_DEQUEUE(&ifp->if_snd, m);
  767                 splx(s);
  768 
  769                 if (m == NULL) {
  770                         if (flag & IO_NDELAY)
  771                                 return (EWOULDBLOCK);
  772 
  773                         tp->tap_flags |= TAP_RWAIT;
  774                         error = tsleep(tp,PCATCH|(PZERO+1),"taprd",0);
  775                         if (error)
  776                                 return (error);
  777                 }
  778         } while (m == NULL);
  779 
  780         /* feed packet to bpf */
  781         BPF_MTAP(ifp, m);
  782 
  783         /* xfer packet to user space */
  784         while ((m != NULL) && (uio->uio_resid > 0) && (error == 0)) {
  785                 len = min(uio->uio_resid, m->m_len);
  786                 if (len == 0)
  787                         break;
  788 
  789                 error = uiomove(mtod(m, void *), len, uio);
  790                 m = m_free(m);
  791         }
  792 
  793         if (m != NULL) {
  794                 TAPDEBUG("%s dropping mbuf, minor = %#x\n", ifp->if_xname, 
  795                         minor(dev));
  796                 m_freem(m);
  797         }
  798 
  799         return (error);
  800 } /* tapread */
  801 
  802 
  803 /*
  804  * tapwrite
  805  *
  806  * the cdevsw write interface - an atomic write is a packet - or else!
  807  */
  808 static int
  809 tapwrite(dev, uio, flag)
  810         dev_t            dev;
  811         struct uio      *uio;
  812         int              flag;
  813 {
  814         struct tap_softc        *tp = dev->si_drv1;
  815         struct ifnet            *ifp = &tp->tap_if;
  816         struct mbuf             *top = NULL, **mp = NULL, *m = NULL;
  817         int                      error = 0, tlen, mlen;
  818 
  819         TAPDEBUG("%s writting, minor = %#x\n", 
  820                 ifp->if_xname, minor(dev));
  821 
  822         if (uio->uio_resid == 0)
  823                 return (0);
  824 
  825         if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) {
  826                 TAPDEBUG("%s invalid packet len = %d, minor = %#x\n",
  827                         ifp->if_xname, uio->uio_resid, minor(dev));
  828 
  829                 return (EIO);
  830         }
  831         tlen = uio->uio_resid;
  832 
  833         /* get a header mbuf */
  834         MGETHDR(m, M_DONTWAIT, MT_DATA);
  835         if (m == NULL)
  836                 return (ENOBUFS);
  837         mlen = MHLEN;
  838 
  839         top = 0;
  840         mp = &top;
  841         while ((error == 0) && (uio->uio_resid > 0)) {
  842                 m->m_len = min(mlen, uio->uio_resid);
  843                 error = uiomove(mtod(m, void *), m->m_len, uio);
  844                 *mp = m;
  845                 mp = &m->m_next;
  846                 if (uio->uio_resid > 0) {
  847                         MGET(m, M_DONTWAIT, MT_DATA);
  848                         if (m == NULL) {
  849                                 error = ENOBUFS;
  850                                 break;
  851                         }
  852                         mlen = MLEN;
  853                 }
  854         }
  855         if (error) {
  856                 ifp->if_ierrors ++;
  857                 if (top)
  858                         m_freem(top);
  859                 return (error);
  860         }
  861 
  862         top->m_pkthdr.len = tlen;
  863         top->m_pkthdr.rcvif = ifp;
  864 
  865         /* Pass packet up to parent. */
  866         (*ifp->if_input)(ifp, top);
  867         ifp->if_ipackets ++; /* ibytes are counted in parent */
  868 
  869         return (0);
  870 } /* tapwrite */
  871 
  872 
  873 /*
  874  * tappoll
  875  *
  876  * the poll interface, this is only useful on reads
  877  * really. the write detect always returns true, write never blocks
  878  * anyway, it either accepts the packet or drops it
  879  */
  880 static int
  881 tappoll(dev, events, td)
  882         dev_t            dev;
  883         int              events;
  884         struct thread   *td;
  885 {
  886         struct tap_softc        *tp = dev->si_drv1;
  887         struct ifnet            *ifp = &tp->tap_if;
  888         int                      s, revents = 0;
  889 
  890         TAPDEBUG("%s polling, minor = %#x\n", 
  891                 ifp->if_xname, minor(dev));
  892 
  893         s = splimp();
  894         if (events & (POLLIN | POLLRDNORM)) {
  895                 if (ifp->if_snd.ifq_len > 0) {
  896                         TAPDEBUG("%s have data in queue. len = %d, " \
  897                                 "minor = %#x\n", ifp->if_xname,
  898                                 ifp->if_snd.ifq_len, minor(dev));
  899 
  900                         revents |= (events & (POLLIN | POLLRDNORM));
  901                 } else {
  902                         TAPDEBUG("%s waiting for data, minor = %#x\n",
  903                                 ifp->if_xname, minor(dev));
  904 
  905                         selrecord(td, &tp->tap_rsel);
  906                 }
  907         }
  908 
  909         if (events & (POLLOUT | POLLWRNORM))
  910                 revents |= (events & (POLLOUT | POLLWRNORM));
  911 
  912         splx(s);
  913         return (revents);
  914 } /* tappoll */

Cache object: 4800cc90ce2ce1f9dca24369749bc7a4


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