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$
   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 
   58 #include <net/bpf.h>
   59 #include <net/ethernet.h>
   60 #include <net/if.h>
   61 #include <net/if_arp.h>
   62 #include <net/route.h>
   63 
   64 #include <netinet/in.h>
   65 
   66 #include <net/if_tapvar.h>
   67 #include <net/if_tap.h>
   68 
   69 
   70 #define CDEV_NAME       "tap"
   71 #define CDEV_MAJOR      149
   72 #define TAPDEBUG        if (tapdebug) printf
   73 
   74 #define TAP             "tap"
   75 #define VMNET           "vmnet"
   76 #define VMNET_DEV_MASK  0x00010000
   77 
   78 /* module */
   79 static int              tapmodevent     __P((module_t, int, void *));
   80 
   81 /* device */
   82 static void             tapcreate       __P((dev_t));
   83 
   84 /* network interface */
   85 static void             tapifstart      __P((struct ifnet *));
   86 static int              tapifioctl      __P((struct ifnet *, u_long, caddr_t));
   87 static void             tapifinit       __P((void *));
   88 
   89 /* character device */
   90 static d_open_t         tapopen;
   91 static d_close_t        tapclose;
   92 static d_read_t         tapread;
   93 static d_write_t        tapwrite;
   94 static d_ioctl_t        tapioctl;
   95 static d_poll_t         tappoll;
   96 
   97 static struct cdevsw    tap_cdevsw = {
   98         /* open */      tapopen,
   99         /* close */     tapclose,
  100         /* read */      tapread,
  101         /* write */     tapwrite,
  102         /* ioctl */     tapioctl,
  103         /* poll */      tappoll,
  104         /* mmap */      nommap,
  105         /* startegy */  nostrategy,
  106         /* dev name */  CDEV_NAME,
  107         /* dev major */ CDEV_MAJOR,
  108         /* dump */      nodump,
  109         /* psize */     nopsize,
  110         /* flags */     0,
  111         /* bmaj */      -1
  112 };
  113 
  114 static int              taprefcnt = 0;          /* module ref. counter   */
  115 static int              taplastunit = -1;       /* max. open unit number */
  116 static int              tapdebug = 0;           /* debug flag            */
  117 
  118 MALLOC_DECLARE(M_TAP);
  119 MALLOC_DEFINE(M_TAP, CDEV_NAME, "Ethernet tunnel interface");
  120 SYSCTL_INT(_debug, OID_AUTO, if_tap_debug, CTLFLAG_RW, &tapdebug, 0, "");
  121 DEV_MODULE(if_tap, tapmodevent, NULL);
  122 
  123 /*
  124  * tapmodevent
  125  *
  126  * module event handler
  127  */
  128 static int
  129 tapmodevent(mod, type, data)
  130         module_t         mod;
  131         int              type;
  132         void            *data;
  133 {
  134         static int               attached = 0;
  135         struct ifnet            *ifp = NULL;
  136         int                      unit, s;
  137 
  138         switch (type) {
  139         case MOD_LOAD:
  140                 if (attached)
  141                         return (EEXIST);
  142 
  143                 cdevsw_add(&tap_cdevsw);
  144                 attached = 1;
  145         break;
  146 
  147         case MOD_UNLOAD:
  148                 if (taprefcnt > 0)
  149                         return (EBUSY);
  150 
  151                 cdevsw_remove(&tap_cdevsw);
  152 
  153                 unit = 0;
  154                 while (unit <= taplastunit) {
  155                         s = splimp();
  156                         TAILQ_FOREACH(ifp, &ifnet, if_link)
  157                                 if ((strcmp(ifp->if_name, TAP) == 0) ||
  158                                     (strcmp(ifp->if_name, VMNET) == 0))
  159                                         if (ifp->if_unit == unit)
  160                                                 break;
  161                         splx(s);
  162 
  163                         if (ifp != NULL) {
  164                                 struct tap_softc        *tp = ifp->if_softc;
  165 
  166                                 TAPDEBUG("detaching %s%d. minor = %#x, " \
  167                                         "taplastunit = %d\n",
  168                                         ifp->if_name, unit, minor(tp->tap_dev),
  169                                         taplastunit);
  170 
  171                                 s = splimp();
  172                                 ether_ifdetach(ifp, 1);
  173                                 splx(s);
  174                                 destroy_dev(tp->tap_dev);
  175                                 free(tp, M_TAP);
  176                         }
  177                         else
  178                                 unit ++;
  179                 }
  180 
  181                 attached = 0;
  182         break;
  183 
  184         default:
  185                 return (EOPNOTSUPP);
  186         }
  187 
  188         return (0);
  189 } /* tapmodevent */
  190 
  191 
  192 /*
  193  * tapcreate
  194  *
  195  * to create interface
  196  */
  197 static void
  198 tapcreate(dev)
  199         dev_t   dev;
  200 {
  201         struct ifnet            *ifp = NULL;
  202         struct tap_softc        *tp = NULL;
  203         unsigned short           macaddr_hi;
  204         int                      unit, s;
  205         char                    *name = NULL;
  206 
  207         /* allocate driver storage and create device */
  208         MALLOC(tp, struct tap_softc *, sizeof(*tp), M_TAP, M_WAITOK);
  209         bzero(tp, sizeof(*tp));
  210 
  211         /* select device: tap or vmnet */
  212         if (minor(dev) & VMNET_DEV_MASK) {
  213                 name = VMNET;
  214                 unit = lminor(dev) & 0xff;
  215                 tp->tap_flags |= TAP_VMNET;
  216         }
  217         else {
  218                 name = TAP;
  219                 unit = lminor(dev);
  220         }
  221 
  222         tp->tap_dev = make_dev(&tap_cdevsw, minor(dev), UID_ROOT, GID_WHEEL, 
  223                                                 0600, "%s%d", name, unit);
  224         tp->tap_dev->si_drv1 = dev->si_drv1 = tp;
  225 
  226         /* generate fake MAC address: 00 bd xx xx xx unit_no */
  227         macaddr_hi = htons(0x00bd);
  228         bcopy(&macaddr_hi, &tp->arpcom.ac_enaddr[0], sizeof(short));
  229         bcopy(&ticks, &tp->arpcom.ac_enaddr[2], sizeof(long));
  230         tp->arpcom.ac_enaddr[5] = (u_char)unit;
  231 
  232         /* fill the rest and attach interface */        
  233         ifp = &tp->tap_if;
  234         ifp->if_softc = tp;
  235 
  236         ifp->if_unit = unit;
  237         if (unit > taplastunit)
  238                 taplastunit = unit;
  239 
  240         ifp->if_name = name;
  241         ifp->if_init = tapifinit;
  242         ifp->if_output = ether_output;
  243         ifp->if_start = tapifstart;
  244         ifp->if_ioctl = tapifioctl;
  245         ifp->if_mtu = ETHERMTU;
  246         ifp->if_flags = (IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST);
  247         ifp->if_snd.ifq_maxlen = ifqmaxlen;
  248 
  249         s = splimp();
  250         ether_ifattach(ifp, 1);
  251         splx(s);
  252 
  253         tp->tap_flags |= TAP_INITED;
  254 
  255         TAPDEBUG("interface %s%d created. minor = %#x\n",
  256                         ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
  257 } /* tapcreate */
  258 
  259 
  260 /*
  261  * tapopen 
  262  *
  263  * to open tunnel. must be superuser
  264  */
  265 static int
  266 tapopen(dev, flag, mode, p)
  267         dev_t            dev;
  268         int              flag;
  269         int              mode;
  270         struct proc     *p;
  271 {
  272         struct tap_softc        *tp = NULL;
  273         int                      error;
  274 
  275         if ((error = suser(p)) != 0)
  276                 return (error);
  277 
  278         tp = dev->si_drv1;
  279         if (tp == NULL) {
  280                 tapcreate(dev);
  281                 tp = dev->si_drv1;
  282         }
  283 
  284         if (tp->tap_flags & TAP_OPEN)
  285                 return (EBUSY);
  286 
  287         bcopy(tp->arpcom.ac_enaddr, tp->ether_addr, sizeof(tp->ether_addr));
  288 
  289         tp->tap_pid = p->p_pid;
  290         tp->tap_flags |= TAP_OPEN;
  291         taprefcnt ++;
  292 
  293         TAPDEBUG("%s%d is open. minor = %#x, refcnt = %d, taplastunit = %d\n",
  294                 tp->tap_if.if_name, tp->tap_if.if_unit,
  295                 minor(tp->tap_dev), taprefcnt, taplastunit);
  296 
  297         return (0);
  298 } /* tapopen */
  299 
  300 
  301 /*
  302  * tapclose
  303  *
  304  * close the device - mark i/f down & delete routing info
  305  */
  306 static int
  307 tapclose(dev, foo, bar, p)
  308         dev_t            dev;
  309         int              foo;
  310         int              bar;
  311         struct proc     *p;
  312 {
  313         int                      s;
  314         struct tap_softc        *tp = dev->si_drv1;
  315         struct ifnet            *ifp = &tp->tap_if;
  316         struct mbuf             *m = NULL;
  317 
  318         /* junk all pending output */
  319 
  320         s = splimp();
  321         do {
  322                 IF_DEQUEUE(&ifp->if_snd, m);
  323                 if (m != NULL)
  324                         m_freem(m);
  325         } while (m != NULL);
  326         splx(s);
  327 
  328         /*
  329          * do not bring the interface down, and do not anything with
  330          * interface, if we are in VMnet mode. just close the device.
  331          */
  332 
  333         if (((tp->tap_flags & TAP_VMNET) == 0) && (ifp->if_flags & IFF_UP)) {
  334                 s = splimp();
  335                 if_down(ifp);
  336                 if (ifp->if_flags & IFF_RUNNING) {
  337                         /* find internet addresses and delete routes */
  338                         struct ifaddr   *ifa = NULL;
  339 
  340                         TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
  341                                 if (ifa->ifa_addr->sa_family == AF_INET) {
  342                                         rtinit(ifa, (int)RTM_DELETE, 0);
  343 
  344                                         /* remove address from interface */
  345                                         bzero(ifa->ifa_addr, 
  346                                                    sizeof(*(ifa->ifa_addr)));
  347                                         bzero(ifa->ifa_dstaddr, 
  348                                                    sizeof(*(ifa->ifa_dstaddr)));
  349                                         bzero(ifa->ifa_netmask, 
  350                                                    sizeof(*(ifa->ifa_netmask)));
  351                                 }
  352                         }
  353 
  354                         ifp->if_flags &= ~IFF_RUNNING;
  355                 }
  356                 splx(s);
  357         }
  358 
  359         funsetown(tp->tap_sigio);
  360         selwakeup(&tp->tap_rsel);
  361 
  362         tp->tap_flags &= ~TAP_OPEN;
  363         tp->tap_pid = 0;
  364 
  365         taprefcnt --;
  366         if (taprefcnt < 0) {
  367                 taprefcnt = 0;
  368                 printf("%s%d minor = %#x, refcnt = %d is out of sync. " \
  369                         "set refcnt to 0\n", ifp->if_name, ifp->if_unit, 
  370                         minor(tp->tap_dev), taprefcnt);
  371         }
  372 
  373         TAPDEBUG("%s%d is closed. minor = %#x, refcnt = %d, taplastunit = %d\n",
  374                         ifp->if_name, ifp->if_unit, minor(tp->tap_dev),
  375                         taprefcnt, taplastunit);
  376 
  377         return (0);
  378 } /* tapclose */
  379 
  380 
  381 /*
  382  * tapifinit
  383  *
  384  * network interface initialization function
  385  */
  386 static void
  387 tapifinit(xtp)
  388         void    *xtp;
  389 {
  390         struct tap_softc        *tp = (struct tap_softc *)xtp;
  391         struct ifnet            *ifp = &tp->tap_if;
  392 
  393         TAPDEBUG("initializing %s%d, minor = %#x\n",
  394                         ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
  395 
  396         ifp->if_flags |= IFF_RUNNING;
  397         ifp->if_flags &= ~IFF_OACTIVE;
  398 
  399         /* attempt to start output */
  400         tapifstart(ifp);
  401 } /* tapifinit */
  402 
  403 
  404 /*
  405  * tapifioctl
  406  *
  407  * Process an ioctl request on network interface
  408  */
  409 int
  410 tapifioctl(ifp, cmd, data)
  411         struct ifnet    *ifp;
  412         u_long           cmd;
  413         caddr_t          data;
  414 {
  415         struct tap_softc        *tp = (struct tap_softc *)(ifp->if_softc);
  416         struct ifstat           *ifs = NULL;
  417         int                      s, dummy;
  418 
  419         switch (cmd) {
  420                 case SIOCSIFADDR:
  421                 case SIOCGIFADDR:
  422                 case SIOCSIFMTU:
  423                         s = splimp();
  424                         dummy = ether_ioctl(ifp, cmd, data);
  425                         splx(s);
  426                         return (dummy);
  427 
  428                 case SIOCSIFFLAGS: /* XXX -- just like vmnet does */
  429                 case SIOCADDMULTI:
  430                 case SIOCDELMULTI:
  431                 break;
  432 
  433                 case SIOCGIFSTATUS:
  434                         s = splimp();
  435                         ifs = (struct ifstat *)data;
  436                         dummy = strlen(ifs->ascii);
  437                         if (tp->tap_pid != 0 && dummy < sizeof(ifs->ascii))
  438                                 snprintf(ifs->ascii + dummy,
  439                                         sizeof(ifs->ascii) - dummy,
  440                                         "\tOpened by PID %d\n", tp->tap_pid);
  441                         splx(s);
  442                 break;
  443 
  444                 default:
  445                         return (EINVAL);
  446         }
  447 
  448         return (0);
  449 } /* tapifioctl */
  450 
  451 
  452 /*
  453  * tapifstart 
  454  * 
  455  * queue packets from higher level ready to put out
  456  */
  457 static void
  458 tapifstart(ifp)
  459         struct ifnet    *ifp;
  460 {
  461         struct tap_softc        *tp = ifp->if_softc;
  462         int                      s;
  463 
  464         TAPDEBUG("%s%d starting, minor = %#x\n", 
  465                         ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
  466 
  467         /*
  468          * do not junk pending output if we are in VMnet mode.
  469          * XXX: can this do any harm because of queue overflow?
  470          */
  471 
  472         if (((tp->tap_flags & TAP_VMNET) == 0) && 
  473             ((tp->tap_flags & TAP_READY) != TAP_READY)) {
  474                 struct mbuf     *m = NULL;
  475 
  476                 TAPDEBUG("%s%d not ready. minor = %#x, tap_flags = 0x%x\n",
  477                         ifp->if_name, ifp->if_unit,
  478                         minor(tp->tap_dev), tp->tap_flags);
  479 
  480                 s = splimp();
  481                 do {
  482                         IF_DEQUEUE(&ifp->if_snd, m);
  483                         if (m != NULL)
  484                                 m_freem(m);
  485                         ifp->if_oerrors ++;
  486                 } while (m != NULL);
  487                 splx(s);
  488 
  489                 return;
  490         }
  491 
  492         s = splimp();
  493         ifp->if_flags |= IFF_OACTIVE;
  494 
  495         if (ifp->if_snd.ifq_len != 0) {
  496                 if (tp->tap_flags & TAP_RWAIT) {
  497                         tp->tap_flags &= ~TAP_RWAIT;
  498                         wakeup((caddr_t)tp);
  499                 }
  500 
  501                 if ((tp->tap_flags & TAP_ASYNC) && (tp->tap_sigio != NULL))
  502                         pgsigio(tp->tap_sigio, SIGIO, 0);
  503 
  504                 selwakeup(&tp->tap_rsel);
  505                 ifp->if_opackets ++; /* obytes are counted in ether_output */
  506         }
  507 
  508         ifp->if_flags &= ~IFF_OACTIVE;
  509         splx(s);
  510 } /* tapifstart */
  511 
  512 
  513 /*
  514  * tapioctl
  515  *
  516  * the cdevsw interface is now pretty minimal
  517  */
  518 static int
  519 tapioctl(dev, cmd, data, flag, p)
  520         dev_t            dev;
  521         u_long           cmd;
  522         caddr_t          data;
  523         int              flag;
  524         struct proc     *p;
  525 {
  526         struct tap_softc        *tp = dev->si_drv1;
  527         struct ifnet            *ifp = &tp->tap_if;
  528         struct tapinfo          *tapp = NULL;
  529         int                      s;
  530 
  531         switch (cmd) {
  532                 case TAPSIFINFO:
  533                         s = splimp();
  534                         tapp = (struct tapinfo *)data;
  535                         ifp->if_mtu = tapp->mtu;
  536                         ifp->if_type = tapp->type;
  537                         ifp->if_baudrate = tapp->baudrate;
  538                         splx(s);
  539                 break;
  540 
  541                 case TAPGIFINFO:
  542                         tapp = (struct tapinfo *)data;
  543                         tapp->mtu = ifp->if_mtu;
  544                         tapp->type = ifp->if_type;
  545                         tapp->baudrate = ifp->if_baudrate;
  546                 break;
  547 
  548                 case TAPSDEBUG:
  549                         tapdebug = *(int *)data;
  550                 break;
  551 
  552                 case TAPGDEBUG:
  553                         *(int *)data = tapdebug;
  554                 break;
  555 
  556                 case FIONBIO:
  557                 break;
  558 
  559                 case FIOASYNC:
  560                         s = splimp();
  561                         if (*(int *)data)
  562                                 tp->tap_flags |= TAP_ASYNC;
  563                         else
  564                                 tp->tap_flags &= ~TAP_ASYNC;
  565                         splx(s);
  566                 break;
  567 
  568                 case FIONREAD:
  569                         s = splimp();
  570                         if (ifp->if_snd.ifq_head) {
  571                                 struct mbuf     *mb = ifp->if_snd.ifq_head;
  572 
  573                                 for(*(int *)data = 0;mb != NULL;mb = mb->m_next)
  574                                         *(int *)data += mb->m_len;
  575                         } 
  576                         else
  577                                 *(int *)data = 0;
  578                         splx(s);
  579                 break;
  580 
  581                 case FIOSETOWN:
  582                         return (fsetown(*(int *)data, &tp->tap_sigio));
  583 
  584                 case FIOGETOWN:
  585                         *(int *)data = fgetown(tp->tap_sigio);
  586                         return (0);
  587 
  588                 /* this is deprecated, FIOSETOWN should be used instead */
  589                 case TIOCSPGRP:
  590                         return (fsetown(-(*(int *)data), &tp->tap_sigio));
  591 
  592                 /* this is deprecated, FIOGETOWN should be used instead */
  593                 case TIOCGPGRP:
  594                         *(int *)data = -fgetown(tp->tap_sigio);
  595                         return (0);
  596 
  597                 /* VMware/VMnet port ioctl's */
  598 
  599                 case SIOCGIFFLAGS:      /* get ifnet flags */
  600                         bcopy(&ifp->if_flags, data, sizeof(ifp->if_flags));
  601                 break;
  602 
  603                 case VMIO_SIOCSIFFLAGS: { /* VMware/VMnet SIOCSIFFLAGS */
  604                         short   f = *(short *)data;
  605 
  606                         f &= 0x0fff;
  607                         f &= ~IFF_CANTCHANGE;
  608                         f |= IFF_UP;
  609 
  610                         s = splimp();
  611                         ifp->if_flags = f | (ifp->if_flags & IFF_CANTCHANGE);
  612                         splx(s);
  613                 } break;
  614 
  615                 case OSIOCGIFADDR:      /* get MAC address of the remote side */
  616                 case SIOCGIFADDR:
  617                         bcopy(tp->ether_addr, data, sizeof(tp->ether_addr));
  618                 break;
  619 
  620                 case SIOCSIFADDR:       /* set MAC address of the remote side */
  621                         bcopy(data, tp->ether_addr, sizeof(tp->ether_addr));
  622                 break;
  623 
  624                 default:
  625                         return (ENOTTY);
  626         }
  627         return (0);
  628 } /* tapioctl */
  629 
  630 
  631 /*
  632  * tapread
  633  *
  634  * the cdevsw read interface - reads a packet at a time, or at
  635  * least as much of a packet as can be read
  636  */
  637 static int
  638 tapread(dev, uio, flag)
  639         dev_t            dev;
  640         struct uio      *uio;
  641         int              flag;
  642 {
  643         struct tap_softc        *tp = dev->si_drv1;
  644         struct ifnet            *ifp = &tp->tap_if;
  645         struct mbuf             *m0 = NULL;
  646         int                      error = 0, len, s;
  647 
  648         TAPDEBUG("%s%d reading, minor = %#x\n",
  649                         ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
  650 
  651         if ((tp->tap_flags & TAP_READY) != TAP_READY) {
  652                 TAPDEBUG("%s%d not ready. minor = %#x, tap_flags = 0x%x\n",
  653                                 ifp->if_name, ifp->if_unit, 
  654                                 minor(tp->tap_dev), tp->tap_flags);
  655 
  656                 return (EHOSTDOWN);
  657         }
  658 
  659         tp->tap_flags &= ~TAP_RWAIT;
  660 
  661         /* sleep until we get a packet */
  662         do {
  663                 s = splimp();
  664                 IF_DEQUEUE(&ifp->if_snd, m0);
  665                 splx(s);
  666 
  667                 if (m0 == NULL) {
  668                         if (flag & IO_NDELAY)
  669                                 return (EWOULDBLOCK);
  670                         
  671                         tp->tap_flags |= TAP_RWAIT;
  672                         error = tsleep((caddr_t)tp,PCATCH|(PZERO+1),"taprd",0);
  673                         if (error)
  674                                 return (error);
  675                 }
  676         } while (m0 == NULL);
  677 
  678         /* feed packet to bpf */
  679         if (ifp->if_bpf != NULL)
  680                 bpf_mtap(ifp, m0);
  681 
  682         /* xfer packet to user space */
  683         while ((m0 != NULL) && (uio->uio_resid > 0) && (error == 0)) {
  684                 len = min(uio->uio_resid, m0->m_len);
  685                 if (len == 0)
  686                         break;
  687 
  688                 error = uiomove(mtod(m0, caddr_t), len, uio);
  689                 m0 = m_free(m0);
  690         }
  691 
  692         if (m0 != NULL) {
  693                 TAPDEBUG("%s%d dropping mbuf, minor = %#x\n",
  694                                 ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
  695                 m_freem(m0);
  696         }
  697 
  698         return (error);
  699 } /* tapread */
  700 
  701 
  702 /*
  703  * tapwrite
  704  *
  705  * the cdevsw write interface - an atomic write is a packet - or else!
  706  */
  707 static int
  708 tapwrite(dev, uio, flag)
  709         dev_t            dev;
  710         struct uio      *uio;
  711         int              flag;
  712 {
  713         struct tap_softc        *tp = dev->si_drv1;
  714         struct ifnet            *ifp = &tp->tap_if;
  715         struct mbuf             *top = NULL, **mp = NULL, *m = NULL;
  716         struct ether_header     *eh = NULL;
  717         int                      error = 0, tlen, mlen;
  718 
  719         TAPDEBUG("%s%d writting, minor = %#x\n",
  720                                 ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
  721 
  722         if (uio->uio_resid == 0)
  723                 return (0);
  724 
  725         if ((uio->uio_resid < 0) || (uio->uio_resid > TAPMRU)) {
  726                 TAPDEBUG("%s%d invalid packet len = %d, minor = %#x\n",
  727                                 ifp->if_name, ifp->if_unit, 
  728                                 uio->uio_resid, minor(tp->tap_dev));
  729 
  730                 return (EIO);
  731         }
  732         tlen = uio->uio_resid;
  733 
  734         /* get a header mbuf */
  735         MGETHDR(m, M_DONTWAIT, MT_DATA);
  736         if (m == NULL)
  737                 return (ENOBUFS);
  738         mlen = MHLEN;
  739 
  740         top = 0;
  741         mp = &top;
  742         while ((error == 0) && (uio->uio_resid > 0)) {
  743                 m->m_len = min(mlen, uio->uio_resid);
  744                 error = uiomove(mtod(m, caddr_t), m->m_len, uio);
  745                 *mp = m;
  746                 mp = &m->m_next;
  747                 if (uio->uio_resid > 0) {
  748                         MGET(m, M_DONTWAIT, MT_DATA);
  749                         if (m == NULL) {
  750                                 error = ENOBUFS;
  751                                 break;
  752                         }
  753                         mlen = MLEN;
  754                 }
  755         }
  756         if (error) {
  757                 ifp->if_ierrors ++;
  758                 if (top)
  759                         m_freem(top);
  760                 return (error);
  761         }
  762 
  763         top->m_pkthdr.len = tlen;
  764         top->m_pkthdr.rcvif = ifp;
  765         
  766         /*
  767          * Ethernet bridge and bpf are handled in ether_input
  768          *
  769          * adjust mbuf and give packet to the ether_input
  770          */
  771 
  772         eh = mtod(top, struct ether_header *);
  773         m_adj(top, sizeof(struct ether_header));
  774         ether_input(ifp, eh, top);
  775         ifp->if_ipackets ++; /* ibytes are counted in ether_input */
  776 
  777         return (0);
  778 } /* tapwrite */
  779 
  780 
  781 /*
  782  * tappoll
  783  *
  784  * the poll interface, this is only useful on reads
  785  * really. the write detect always returns true, write never blocks
  786  * anyway, it either accepts the packet or drops it
  787  */
  788 static int
  789 tappoll(dev, events, p)
  790         dev_t            dev;
  791         int              events;
  792         struct proc     *p;
  793 {
  794         struct tap_softc        *tp = dev->si_drv1;
  795         struct ifnet            *ifp = &tp->tap_if;
  796         int                      s, revents = 0;
  797 
  798         TAPDEBUG("%s%d polling, minor = %#x\n",
  799                                 ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
  800 
  801         s = splimp();
  802         if (events & (POLLIN | POLLRDNORM)) {
  803                 if (ifp->if_snd.ifq_len > 0) {
  804                         TAPDEBUG("%s%d have data in queue. len = %d, " \
  805                                 "minor = %#x\n", ifp->if_name, ifp->if_unit,
  806                                 ifp->if_snd.ifq_len, minor(tp->tap_dev));
  807 
  808                         revents |= (events & (POLLIN | POLLRDNORM));
  809                 } 
  810                 else {
  811                         TAPDEBUG("%s%d waiting for data, minor = %#x\n",
  812                                 ifp->if_name, ifp->if_unit, minor(tp->tap_dev));
  813 
  814                         selrecord(p, &tp->tap_rsel);
  815                 }
  816         }
  817 
  818         if (events & (POLLOUT | POLLWRNORM))
  819                 revents |= (events & (POLLOUT | POLLWRNORM));
  820 
  821         splx(s);
  822         return (revents);
  823 } /* tappoll */

Cache object: d121dbc1a8e4a739f788396b9527ca6a


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