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

Cache object: d2d0bfe801130c007a60388efe7509a3


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