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

Cache object: df189824886e058705a4312df1457c6d


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