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_vlan.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 1998 Massachusetts Institute of Technology
    3  *
    4  * Permission to use, copy, modify, and distribute this software and
    5  * its documentation for any purpose and without fee is hereby
    6  * granted, provided that both the above copyright notice and this
    7  * permission notice appear in all copies, that both the above
    8  * copyright notice and this permission notice appear in all
    9  * supporting documentation, and that the name of M.I.T. not be used
   10  * in advertising or publicity pertaining to distribution of the
   11  * software without specific, written prior permission.  M.I.T. makes
   12  * no representations about the suitability of this software for any
   13  * purpose.  It is provided "as is" without express or implied
   14  * warranty.
   15  * 
   16  * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
   17  * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
   18  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
   20  * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   23  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   25  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   26  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  * $FreeBSD$
   30  */
   31 
   32 /*
   33  * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs.
   34  * Might be extended some day to also handle IEEE 802.1p priority
   35  * tagging.  This is sort of sneaky in the implementation, since
   36  * we need to pretend to be enough of an Ethernet implementation
   37  * to make arp work.  The way we do this is by telling everyone
   38  * that we are an Ethernet, and then catch the packets that
   39  * ether_output() left on our output queue when it calls
   40  * if_start(), rewrite them for use by the real outgoing interface,
   41  * and ask it to send them.
   42  */
   43 
   44 #include "opt_inet.h"
   45 
   46 #include <sys/param.h>
   47 #include <sys/kernel.h>
   48 #include <sys/malloc.h>
   49 #include <sys/mbuf.h>
   50 #include <sys/module.h>
   51 #include <sys/queue.h>
   52 #include <sys/socket.h>
   53 #include <sys/sockio.h>
   54 #include <sys/sysctl.h>
   55 #include <sys/systm.h>
   56 
   57 #include <net/bpf.h>
   58 #include <net/ethernet.h>
   59 #include <net/if.h>
   60 #include <net/if_clone.h>
   61 #include <net/if_arp.h>
   62 #include <net/if_dl.h>
   63 #include <net/if_types.h>
   64 #include <net/if_vlan_var.h>
   65 
   66 #ifdef INET
   67 #include <netinet/in.h>
   68 #include <netinet/if_ether.h>
   69 #endif
   70 
   71 #define VLANNAME        "vlan"
   72 #define VLAN_IFFLAGS    (IFF_BROADCAST | IFF_MULTICAST)
   73 
   74 struct vlan_mc_entry {
   75         struct ether_addr               mc_addr;
   76         SLIST_ENTRY(vlan_mc_entry)      mc_entries;
   77 };
   78 
   79 struct  ifvlan {
   80         struct  ifnet *ifv_ifp;
   81         struct  ifnet *ifv_p;   /* parent inteface of this vlan */
   82         int     ifv_pflags;     /* special flags we have set on parent */
   83         struct  ifv_linkmib {
   84                 int     ifvm_parent;
   85                 int     ifvm_encaplen;  /* encapsulation length */
   86                 int     ifvm_mtufudge;  /* MTU fudged by this much */
   87                 int     ifvm_mintu;     /* min transmission unit */
   88                 u_int16_t ifvm_proto; /* encapsulation ethertype */
   89                 u_int16_t ifvm_tag; /* tag to apply on packets leaving if */
   90         }       ifv_mib;
   91         SLIST_HEAD(__vlan_mchead, vlan_mc_entry)        vlan_mc_listhead;
   92         LIST_ENTRY(ifvlan) ifv_list;
   93 };
   94 #define ifv_tag ifv_mib.ifvm_tag
   95 #define ifv_encaplen    ifv_mib.ifvm_encaplen
   96 #define ifv_mtufudge    ifv_mib.ifvm_mtufudge
   97 #define ifv_mintu       ifv_mib.ifvm_mintu
   98 
   99 /* Special flags we should propagate to parent */
  100 static struct {
  101         int flag;
  102         int (*func)(struct ifnet *, int);
  103 } vlan_pflags[] = {
  104         {IFF_PROMISC, ifpromisc},
  105         {IFF_ALLMULTI, if_allmulti},
  106         {0, NULL}
  107 };
  108 
  109 SYSCTL_DECL(_net_link);
  110 SYSCTL_NODE(_net_link, IFT_L2VLAN, vlan, CTLFLAG_RW, 0, "IEEE 802.1Q VLAN");
  111 SYSCTL_NODE(_net_link_vlan, PF_LINK, link, CTLFLAG_RW, 0, "for consistency");
  112 
  113 static int soft_pad = 0;
  114 SYSCTL_INT(_net_link_vlan, OID_AUTO, soft_pad, CTLFLAG_RW, &soft_pad, 0,
  115            "pad short frames before tagging");
  116 
  117 static MALLOC_DEFINE(M_VLAN, VLANNAME, "802.1Q Virtual LAN Interface");
  118 static LIST_HEAD(, ifvlan) ifv_list;
  119 
  120 static eventhandler_tag ifdetach_tag;
  121 
  122 /*
  123  * Locking: one lock is used to guard both the ifv_list and modification
  124  * to vlan data structures.  We are rather conservative here; probably
  125  * more than necessary.
  126  */
  127 static struct mtx ifv_mtx;
  128 #define VLAN_LOCK_INIT()        mtx_init(&ifv_mtx, VLANNAME, NULL, MTX_DEF)
  129 #define VLAN_LOCK_DESTROY()     mtx_destroy(&ifv_mtx)
  130 #define VLAN_LOCK_ASSERT()      mtx_assert(&ifv_mtx, MA_OWNED)
  131 #define VLAN_LOCK()     mtx_lock(&ifv_mtx)
  132 #define VLAN_UNLOCK()   mtx_unlock(&ifv_mtx)
  133 
  134 static  void vlan_start(struct ifnet *ifp);
  135 static  void vlan_ifinit(void *foo);
  136 static  void vlan_input(struct ifnet *ifp, struct mbuf *m);
  137 static  int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr);
  138 static  int vlan_setflag(struct ifnet *ifp, int flag, int status,
  139     int (*func)(struct ifnet *, int));
  140 static  int vlan_setflags(struct ifnet *ifp, int status);
  141 static  int vlan_setmulti(struct ifnet *ifp);
  142 static  int vlan_unconfig(struct ifnet *ifp);
  143 static  int vlan_config(struct ifvlan *ifv, struct ifnet *p);
  144 static  void vlan_link_state(struct ifnet *ifp, int link);
  145 static  void vlan_ifdetach(void *arg, struct ifnet *ifp);
  146 
  147 static  struct ifnet *vlan_clone_match_ethertag(struct if_clone *,
  148     const char *, int *);
  149 static  int vlan_clone_match(struct if_clone *, const char *);
  150 static  int vlan_clone_create(struct if_clone *, char *, size_t);
  151 static  int vlan_clone_destroy(struct if_clone *, struct ifnet *);
  152 
  153 static  struct if_clone vlan_cloner = IFC_CLONE_INITIALIZER(VLANNAME, NULL,
  154     IF_MAXUNIT, NULL, vlan_clone_match, vlan_clone_create, vlan_clone_destroy);
  155 
  156 /*
  157  * Program our multicast filter. What we're actually doing is
  158  * programming the multicast filter of the parent. This has the
  159  * side effect of causing the parent interface to receive multicast
  160  * traffic that it doesn't really want, which ends up being discarded
  161  * later by the upper protocol layers. Unfortunately, there's no way
  162  * to avoid this: there really is only one physical interface.
  163  *
  164  * XXX: There is a possible race here if more than one thread is
  165  *      modifying the multicast state of the vlan interface at the same time.
  166  */
  167 static int
  168 vlan_setmulti(struct ifnet *ifp)
  169 {
  170         struct ifnet            *ifp_p;
  171         struct ifmultiaddr      *ifma, *rifma = NULL;
  172         struct ifvlan           *sc;
  173         struct vlan_mc_entry    *mc = NULL;
  174         struct sockaddr_dl      sdl;
  175         int                     error;
  176 
  177         /*VLAN_LOCK_ASSERT();*/
  178 
  179         /* Find the parent. */
  180         sc = ifp->if_softc;
  181         ifp_p = sc->ifv_p;
  182 
  183         /*
  184          * If we don't have a parent, just remember the membership for
  185          * when we do.
  186          */
  187         if (ifp_p == NULL)
  188                 return (0);
  189 
  190         bzero((char *)&sdl, sizeof(sdl));
  191         sdl.sdl_len = sizeof(sdl);
  192         sdl.sdl_family = AF_LINK;
  193         sdl.sdl_index = ifp_p->if_index;
  194         sdl.sdl_type = IFT_ETHER;
  195         sdl.sdl_alen = ETHER_ADDR_LEN;
  196 
  197         /* First, remove any existing filter entries. */
  198         while (SLIST_FIRST(&sc->vlan_mc_listhead) != NULL) {
  199                 mc = SLIST_FIRST(&sc->vlan_mc_listhead);
  200                 bcopy((char *)&mc->mc_addr, LLADDR(&sdl), ETHER_ADDR_LEN);
  201                 error = if_delmulti(ifp_p, (struct sockaddr *)&sdl);
  202                 if (error)
  203                         return (error);
  204                 SLIST_REMOVE_HEAD(&sc->vlan_mc_listhead, mc_entries);
  205                 free(mc, M_VLAN);
  206         }
  207 
  208         /* Now program new ones. */
  209         TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  210                 if (ifma->ifma_addr->sa_family != AF_LINK)
  211                         continue;
  212                 mc = malloc(sizeof(struct vlan_mc_entry), M_VLAN, M_NOWAIT);
  213                 if (mc == NULL)
  214                         return (ENOMEM);
  215                 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
  216                     (char *)&mc->mc_addr, ETHER_ADDR_LEN);
  217                 SLIST_INSERT_HEAD(&sc->vlan_mc_listhead, mc, mc_entries);
  218                 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
  219                     LLADDR(&sdl), ETHER_ADDR_LEN);
  220                 error = if_addmulti(ifp_p, (struct sockaddr *)&sdl, &rifma);
  221                 if (error)
  222                         return (error);
  223         }
  224 
  225         return (0);
  226 }
  227 
  228 /*
  229  * A handler for network interface departure events.
  230  * Track departure of trunks here so that we don't access invalid
  231  * pointers or whatever if a trunk is ripped from under us, e.g.,
  232  * by ejecting its hot-plug card.
  233  */
  234 static void
  235 vlan_ifdetach(void *arg __unused, struct ifnet *ifp)
  236 {
  237         struct ifvlan *ifv;
  238 
  239         /*
  240          * Check if it's a trunk interface first of all.
  241          */
  242         if (ifp->if_nvlans == 0)
  243                 return;
  244 
  245         /*
  246          * OK, it's a trunk.  Find all vlan's attached to it and detach them
  247          * from the parent interface.
  248          */
  249         VLAN_LOCK();
  250         LIST_FOREACH(ifv, &ifv_list, ifv_list)
  251                 if (ifv->ifv_p == ifp) {
  252                         vlan_unconfig(ifv->ifv_ifp);
  253                         ifv->ifv_ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
  254                 }
  255         VLAN_UNLOCK();
  256 
  257         if (ifp->if_nvlans)
  258                 if_printf(ifp, "%d vlans failed to detach\n", ifp->if_nvlans);
  259 }
  260 
  261 /*
  262  * VLAN support can be loaded as a module.  The only place in the
  263  * system that's intimately aware of this is ether_input.  We hook
  264  * into this code through vlan_input_p which is defined there and
  265  * set here.  Noone else in the system should be aware of this so
  266  * we use an explicit reference here.
  267  *
  268  * NB: Noone should ever need to check if vlan_input_p is null or
  269  *     not.  This is because interfaces have a count of the number
  270  *     of active vlans (if_nvlans) and this should never be bumped
  271  *     except by vlan_config--which is in this module so therefore
  272  *     the module must be loaded and vlan_input_p must be non-NULL.
  273  */
  274 extern  void (*vlan_input_p)(struct ifnet *, struct mbuf *);
  275 
  276 /* For if_link_state_change() eyes only... */
  277 extern  void (*vlan_link_state_p)(struct ifnet *, int);
  278 
  279 static int
  280 vlan_modevent(module_t mod, int type, void *data)
  281 {
  282 
  283         switch (type) {
  284         case MOD_LOAD:
  285                 ifdetach_tag = EVENTHANDLER_REGISTER(ifnet_departure_event,
  286                     vlan_ifdetach, NULL, EVENTHANDLER_PRI_ANY);
  287                 if (ifdetach_tag == NULL)
  288                         return (ENOMEM);
  289                 LIST_INIT(&ifv_list);
  290                 VLAN_LOCK_INIT();
  291                 vlan_input_p = vlan_input;
  292                 vlan_link_state_p = vlan_link_state;
  293                 if_clone_attach(&vlan_cloner);
  294                 break;
  295         case MOD_UNLOAD:
  296                 while (!LIST_EMPTY(&ifv_list))
  297                         vlan_clone_destroy(&vlan_cloner,
  298                             LIST_FIRST(&ifv_list)->ifv_ifp);
  299                 if_clone_detach(&vlan_cloner);
  300                 EVENTHANDLER_DEREGISTER(ifnet_departure_event, ifdetach_tag);
  301                 vlan_input_p = NULL;
  302                 vlan_link_state_p = NULL;
  303                 VLAN_LOCK_DESTROY();
  304                 break;
  305         default:
  306                 return (EOPNOTSUPP);
  307         }
  308         return (0);
  309 }
  310 
  311 static moduledata_t vlan_mod = {
  312         "if_vlan",
  313         vlan_modevent,
  314         0
  315 };
  316 
  317 DECLARE_MODULE(if_vlan, vlan_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
  318 
  319 static struct ifnet *
  320 vlan_clone_match_ethertag(struct if_clone *ifc, const char *name, int *tag)
  321 {
  322         const char *cp;
  323         struct ifnet *ifp;
  324         int t = 0;
  325 
  326         /* Check for <etherif>.<vlan> style interface names. */
  327         IFNET_RLOCK();
  328         TAILQ_FOREACH(ifp, &ifnet, if_link) {
  329                 if (ifp->if_type != IFT_ETHER)
  330                         continue;
  331                 if (strncmp(ifp->if_xname, name, strlen(ifp->if_xname)) != 0)
  332                         continue;
  333                 cp = name + strlen(ifp->if_xname);
  334                 if (*cp != '.')
  335                         continue;
  336                 for(; *cp != '\0'; cp++) {
  337                         if (*cp < '' || *cp > '9')
  338                                 continue;
  339                         t = (t * 10) + (*cp - '');
  340                 }
  341                 if (tag != NULL)
  342                         *tag = t;
  343                 break;
  344         }
  345         IFNET_RUNLOCK();
  346 
  347         return (ifp);
  348 }
  349 
  350 static int
  351 vlan_clone_match(struct if_clone *ifc, const char *name)
  352 {
  353         const char *cp;
  354 
  355         if (vlan_clone_match_ethertag(ifc, name, NULL) != NULL)
  356                 return (1);
  357 
  358         if (strncmp(VLANNAME, name, strlen(VLANNAME)) != 0)
  359                 return (0);
  360         for (cp = name + 4; *cp != '\0'; cp++) {
  361                 if (*cp < '' || *cp > '9')
  362                         return (0);
  363         }
  364 
  365         return (1);
  366 }
  367 
  368 static int
  369 vlan_clone_create(struct if_clone *ifc, char *name, size_t len)
  370 {
  371         char *dp;
  372         int wildcard;
  373         int unit;
  374         int error;
  375         int tag;
  376         int ethertag;
  377         struct ifvlan *ifv;
  378         struct ifnet *ifp;
  379         struct ifnet *p;
  380         u_char eaddr[6] = {0,0,0,0,0,0};
  381 
  382         if ((p = vlan_clone_match_ethertag(ifc, name, &tag)) != NULL) {
  383                 ethertag = 1;
  384                 unit = -1;
  385                 wildcard = 0;
  386 
  387                 /*
  388                  * Don't let the caller set up a VLAN tag with
  389                  * anything except VLID bits.
  390                  */
  391                 if (tag & ~EVL_VLID_MASK)
  392                         return (EINVAL);
  393         } else {
  394                 ethertag = 0;
  395 
  396                 error = ifc_name2unit(name, &unit);
  397                 if (error != 0)
  398                         return (error);
  399 
  400                 wildcard = (unit < 0);
  401         }
  402 
  403         error = ifc_alloc_unit(ifc, &unit);
  404         if (error != 0)
  405                 return (error);
  406 
  407         /* In the wildcard case, we need to update the name. */
  408         if (wildcard) {
  409                 for (dp = name; *dp != '\0'; dp++);
  410                 if (snprintf(dp, len - (dp-name), "%d", unit) >
  411                     len - (dp-name) - 1) {
  412                         panic("%s: interface name too long", __func__);
  413                 }
  414         }
  415 
  416         ifv = malloc(sizeof(struct ifvlan), M_VLAN, M_WAITOK | M_ZERO);
  417         ifp = ifv->ifv_ifp = if_alloc(IFT_ETHER);
  418         if (ifp == NULL) {
  419                 ifc_free_unit(ifc, unit);
  420                 free(ifv, M_VLAN);
  421                 return (ENOSPC);
  422         }
  423         SLIST_INIT(&ifv->vlan_mc_listhead);
  424 
  425         ifp->if_softc = ifv;
  426         /*
  427          * Set the name manually rather than using if_initname because
  428          * we don't conform to the default naming convention for interfaces.
  429          */
  430         strlcpy(ifp->if_xname, name, IFNAMSIZ);
  431         ifp->if_dname = ifc->ifc_name;
  432         ifp->if_dunit = unit;
  433         /* NB: flags are not set here */
  434         ifp->if_linkmib = &ifv->ifv_mib;
  435         ifp->if_linkmiblen = sizeof(ifv->ifv_mib);
  436         /* NB: mtu is not set here */
  437 
  438         ifp->if_init = vlan_ifinit;
  439         ifp->if_start = vlan_start;
  440         ifp->if_ioctl = vlan_ioctl;
  441         ifp->if_snd.ifq_maxlen = ifqmaxlen;
  442         ifp->if_flags = VLAN_IFFLAGS;
  443         ether_ifattach(ifp, eaddr);
  444         /* Now undo some of the damage... */
  445         ifp->if_baudrate = 0;
  446         ifp->if_type = IFT_L2VLAN;
  447         ifp->if_hdrlen = ETHER_VLAN_ENCAP_LEN;
  448 
  449         VLAN_LOCK();
  450         LIST_INSERT_HEAD(&ifv_list, ifv, ifv_list);
  451         VLAN_UNLOCK();
  452 
  453         if (ethertag) {
  454                 VLAN_LOCK();
  455                 error = vlan_config(ifv, p);
  456                 if (error != 0) {
  457                         /*
  458                          * Since we've partialy failed, we need to back
  459                          * out all the way, otherwise userland could get
  460                          * confused.  Thus, we destroy the interface.
  461                          */
  462                         LIST_REMOVE(ifv, ifv_list);
  463                         vlan_unconfig(ifp);
  464                         VLAN_UNLOCK();
  465                         ether_ifdetach(ifp);
  466                         if_free_type(ifp, IFT_ETHER);
  467                         free(ifv, M_VLAN);
  468 
  469                         return (error);
  470                 }
  471                 ifv->ifv_tag = tag;
  472                 ifp->if_drv_flags |= IFF_DRV_RUNNING;
  473                 VLAN_UNLOCK();
  474 
  475                 /* Update flags on the parent, if necessary. */
  476                 vlan_setflags(ifp, 1);
  477         }
  478 
  479         return (0);
  480 }
  481 
  482 static int
  483 vlan_clone_destroy(struct if_clone *ifc, struct ifnet *ifp)
  484 {
  485         int unit;
  486         struct ifvlan *ifv = ifp->if_softc;
  487 
  488         unit = ifp->if_dunit;
  489 
  490         VLAN_LOCK();
  491         LIST_REMOVE(ifv, ifv_list);
  492         vlan_unconfig(ifp);
  493         VLAN_UNLOCK();
  494 
  495         ether_ifdetach(ifp);
  496         if_free_type(ifp, IFT_ETHER);
  497 
  498         free(ifv, M_VLAN);
  499 
  500         ifc_free_unit(ifc, unit);
  501 
  502         return (0);
  503 }
  504 
  505 /*
  506  * The ifp->if_init entry point for vlan(4) is a no-op.
  507  */
  508 static void
  509 vlan_ifinit(void *foo)
  510 {
  511 
  512 }
  513 
  514 /*
  515  * The if_start method for vlan(4) interface. It doesn't
  516  * raises the IFF_DRV_OACTIVE flag, since it is called
  517  * only from IFQ_HANDOFF() macro in ether_output_frame().
  518  * If the interface queue is full, and vlan_start() is
  519  * not called, the queue would never get emptied and
  520  * interface would stall forever.
  521  */
  522 static void
  523 vlan_start(struct ifnet *ifp)
  524 {
  525         struct ifvlan *ifv;
  526         struct ifnet *p;
  527         struct ether_vlan_header *evl;
  528         struct mbuf *m;
  529         int error;
  530 
  531         ifv = ifp->if_softc;
  532         p = ifv->ifv_p;
  533 
  534         for (;;) {
  535                 IF_DEQUEUE(&ifp->if_snd, m);
  536                 if (m == 0)
  537                         break;
  538                 BPF_MTAP(ifp, m);
  539 
  540                 /*
  541                  * Do not run parent's if_start() if the parent is not up,
  542                  * or parent's driver will cause a system crash.
  543                  */
  544                 if (!((p->if_flags & IFF_UP) &&
  545                     (p->if_drv_flags & IFF_DRV_RUNNING))) {
  546                         m_freem(m);
  547                         ifp->if_collisions++;
  548                         continue;
  549                 }
  550 
  551                 /*
  552                  * Pad the frame to the minimum size allowed if told to.
  553                  * This option is in accord with IEEE Std 802.1Q, 2003 Ed.,
  554                  * paragraph C.4.4.3.b.  It can help to work around buggy
  555                  * bridges that violate paragraph C.4.4.3.a from the same
  556                  * document, i.e., fail to pad short frames after untagging.
  557                  * E.g., a tagged frame 66 bytes long (incl. FCS) is OK, but
  558                  * untagging it will produce a 62-byte frame, which is a runt
  559                  * and requires padding.  There are VLAN-enabled network
  560                  * devices that just discard such runts instead or mishandle
  561                  * them somehow.
  562                  */
  563                 if (soft_pad) {
  564                         static char pad[8];     /* just zeros */
  565                         int n;
  566 
  567                         for (n = ETHERMIN + ETHER_HDR_LEN - m->m_pkthdr.len;
  568                              n > 0; n -= sizeof(pad))
  569                                 if (!m_append(m, min(n, sizeof(pad)), pad))
  570                                         break;
  571 
  572                         if (n > 0) {
  573                                 if_printf(ifp, "cannot pad short frame\n");
  574                                 ifp->if_oerrors++;
  575                                 m_freem(m);
  576                                 continue;
  577                         }
  578                 }
  579 
  580                 /*
  581                  * If underlying interface can do VLAN tag insertion itself,
  582                  * just pass the packet along. However, we need some way to
  583                  * tell the interface where the packet came from so that it
  584                  * knows how to find the VLAN tag to use, so we attach a
  585                  * packet tag that holds it.
  586                  */
  587                 if (p->if_capenable & IFCAP_VLAN_HWTAGGING) {
  588                         struct m_tag *mtag = m_tag_alloc(MTAG_VLAN,
  589                                                          MTAG_VLAN_TAG,
  590                                                          sizeof(u_int),
  591                                                          M_NOWAIT);
  592                         if (mtag == NULL) {
  593                                 ifp->if_oerrors++;
  594                                 m_freem(m);
  595                                 continue;
  596                         }
  597                         VLAN_TAG_VALUE(mtag) = ifv->ifv_tag;
  598                         m_tag_prepend(m, mtag);
  599                         m->m_flags |= M_VLANTAG;
  600                 } else {
  601                         M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT);
  602                         if (m == NULL) {
  603                                 if_printf(ifp,
  604                                     "unable to prepend VLAN header\n");
  605                                 ifp->if_oerrors++;
  606                                 continue;
  607                         }
  608                         /* M_PREPEND takes care of m_len, m_pkthdr.len for us */
  609 
  610                         if (m->m_len < sizeof(*evl)) {
  611                                 m = m_pullup(m, sizeof(*evl));
  612                                 if (m == NULL) {
  613                                         if_printf(ifp,
  614                                             "cannot pullup VLAN header\n");
  615                                         ifp->if_oerrors++;
  616                                         continue;
  617                                 }
  618                         }
  619 
  620                         /*
  621                          * Transform the Ethernet header into an Ethernet header
  622                          * with 802.1Q encapsulation.
  623                          */
  624                         bcopy(mtod(m, char *) + ifv->ifv_encaplen,
  625                               mtod(m, char *), ETHER_HDR_LEN);
  626                         evl = mtod(m, struct ether_vlan_header *);
  627                         evl->evl_proto = evl->evl_encap_proto;
  628                         evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
  629                         evl->evl_tag = htons(ifv->ifv_tag);
  630 #ifdef DEBUG
  631                         printf("%s: %*D\n", __func__, (int)sizeof(*evl),
  632                             (unsigned char *)evl, ":");
  633 #endif
  634                 }
  635 
  636                 /*
  637                  * Send it, precisely as ether_output() would have.
  638                  * We are already running at splimp.
  639                  */
  640                 IFQ_HANDOFF(p, m, error);
  641                 if (!error)
  642                         ifp->if_opackets++;
  643                 else
  644                         ifp->if_oerrors++;
  645         }
  646 }
  647 
  648 static void
  649 vlan_input(struct ifnet *ifp, struct mbuf *m)
  650 {
  651         struct ether_vlan_header *evl;
  652         struct ifvlan *ifv;
  653         struct m_tag *mtag;
  654         u_int tag;
  655 
  656         if (m->m_flags & M_VLANTAG) {
  657                 /*
  658                  * Packet is tagged, but m contains a normal
  659                  * Ethernet frame; the tag is stored out-of-band.
  660                  */
  661                 mtag = m_tag_locate(m, MTAG_VLAN, MTAG_VLAN_TAG, NULL);
  662                 KASSERT(mtag != NULL,
  663                         ("%s: M_VLANTAG without m_tag", __func__));
  664                 tag = EVL_VLANOFTAG(VLAN_TAG_VALUE(mtag));
  665                 m_tag_delete(m, mtag);
  666                 m->m_flags &= ~M_VLANTAG;
  667         } else {
  668                 /*
  669                  * Packet is tagged in-band as specified by 802.1q.
  670                  */
  671                 mtag = NULL;
  672                 switch (ifp->if_type) {
  673                 case IFT_ETHER:
  674                         if (m->m_len < sizeof(*evl) &&
  675                             (m = m_pullup(m, sizeof(*evl))) == NULL) {
  676                                 if_printf(ifp, "cannot pullup VLAN header\n");
  677                                 return;
  678                         }
  679                         evl = mtod(m, struct ether_vlan_header *);
  680                         KASSERT(ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN,
  681                                 ("%s: bad encapsulation protocol (%u)",
  682                                  __func__, ntohs(evl->evl_encap_proto)));
  683 
  684                         tag = EVL_VLANOFTAG(ntohs(evl->evl_tag));
  685 
  686                         /*
  687                          * Restore the original ethertype.  We'll remove
  688                          * the encapsulation after we've found the vlan
  689                          * interface corresponding to the tag.
  690                          */
  691                         evl->evl_encap_proto = evl->evl_proto;
  692                         break;
  693                 default:
  694                         tag = (u_int) -1;
  695 #ifdef INVARIANTS
  696                         panic("%s: unsupported if_type (%u)",
  697                               __func__, ifp->if_type);
  698 #endif
  699                         break;
  700                 }
  701         }
  702 
  703         VLAN_LOCK();
  704         LIST_FOREACH(ifv, &ifv_list, ifv_list)
  705                 if (ifp == ifv->ifv_p && tag == ifv->ifv_tag)
  706                         break;
  707 
  708         if (ifv == NULL || (ifv->ifv_ifp->if_flags & IFF_UP) == 0) {
  709                 VLAN_UNLOCK();
  710                 m_freem(m);
  711                 ifp->if_noproto++;
  712 #ifdef DEBUG
  713                 printf("%s: tag %d, no interface\n", __func__, tag);
  714 #endif
  715                 return;
  716         }
  717         VLAN_UNLOCK();          /* XXX extend below? */
  718 #ifdef DEBUG
  719         printf("%s: tag %d, parent %s\n", __func__, tag, ifv->ifv_p->if_xname);
  720 #endif
  721 
  722         if (mtag == NULL) {
  723                 /*
  724                  * Packet had an in-line encapsulation header;
  725                  * remove it.  The original header has already
  726                  * been fixed up above.
  727                  */
  728                 bcopy(mtod(m, caddr_t),
  729                       mtod(m, caddr_t) + ETHER_VLAN_ENCAP_LEN,
  730                       ETHER_HDR_LEN);
  731                 m_adj(m, ETHER_VLAN_ENCAP_LEN);
  732         }
  733 
  734         m->m_pkthdr.rcvif = ifv->ifv_ifp;
  735         ifv->ifv_ifp->if_ipackets++;
  736 
  737         /* Pass it back through the parent's input routine. */
  738         (*ifp->if_input)(ifv->ifv_ifp, m);
  739 }
  740 
  741 static int
  742 vlan_config(struct ifvlan *ifv, struct ifnet *p)
  743 {
  744         struct ifaddr *ifa1, *ifa2;
  745         struct ifnet *ifp;
  746         struct sockaddr_dl *sdl1, *sdl2;
  747 
  748         VLAN_LOCK_ASSERT();
  749 
  750         if (p->if_type != IFT_ETHER)
  751                 return (EPROTONOSUPPORT);
  752         if ((p->if_flags & VLAN_IFFLAGS) != VLAN_IFFLAGS)
  753                 return (EPROTONOSUPPORT);
  754         if (ifv->ifv_p)
  755                 return (EBUSY);
  756 
  757         ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN;
  758         ifv->ifv_mintu = ETHERMIN;
  759         ifv->ifv_pflags = 0;
  760 
  761         /*
  762          * The active VLAN counter on the parent is used
  763          * at various places to see if there is a vlan(4)
  764          * attached to this physical interface.
  765          */
  766         p->if_nvlans++;
  767 
  768         /*
  769          * If the parent supports the VLAN_MTU capability,
  770          * i.e. can Tx/Rx larger than ETHER_MAX_LEN frames,
  771          * use it.
  772          */
  773         if (p->if_capenable & IFCAP_VLAN_MTU) {
  774                 /*
  775                  * No need to fudge the MTU since the parent can
  776                  * handle extended frames.
  777                  */
  778                 ifv->ifv_mtufudge = 0;
  779         } else {
  780                 /*
  781                  * Fudge the MTU by the encapsulation size.  This
  782                  * makes us incompatible with strictly compliant
  783                  * 802.1Q implementations, but allows us to use
  784                  * the feature with other NetBSD implementations,
  785                  * which might still be useful.
  786                  */
  787                 ifv->ifv_mtufudge = ifv->ifv_encaplen;
  788         }
  789 
  790         ifv->ifv_p = p;
  791         ifp = ifv->ifv_ifp;
  792         ifp->if_mtu = p->if_mtu - ifv->ifv_mtufudge;
  793         ifv->ifv_ifp->if_baudrate = p->if_baudrate;
  794         /*
  795          * Copy only a selected subset of flags from the parent.
  796          * Other flags are none of our business.
  797          */
  798 #define VLAN_COPY_FLAGS (IFF_SIMPLEX)
  799         ifp->if_flags &= ~VLAN_COPY_FLAGS;
  800         ifp->if_flags |= p->if_flags & VLAN_COPY_FLAGS;
  801 #undef VLAN_COPY_FLAGS
  802 
  803         ifp->if_link_state = p->if_link_state;
  804 
  805 #if 0
  806         /*
  807          * Not ready yet.  We need notification from the parent
  808          * when hw checksumming flags in its if_capenable change.
  809          * Flags set in if_capabilities only are useless.
  810          */
  811         /*
  812          * If the parent interface can do hardware-assisted
  813          * VLAN encapsulation, then propagate its hardware-
  814          * assisted checksumming flags.
  815          */
  816         if (p->if_capabilities & IFCAP_VLAN_HWTAGGING)
  817                 ifp->if_capabilities |= p->if_capabilities & IFCAP_HWCSUM;
  818 #endif
  819 
  820         /*
  821          * Set up our ``Ethernet address'' to reflect the underlying
  822          * physical interface's.
  823          */
  824         ifa1 = ifaddr_byindex(ifp->if_index);
  825         ifa2 = ifaddr_byindex(p->if_index);
  826         sdl1 = (struct sockaddr_dl *)ifa1->ifa_addr;
  827         sdl2 = (struct sockaddr_dl *)ifa2->ifa_addr;
  828         sdl1->sdl_type = IFT_ETHER;
  829         sdl1->sdl_alen = ETHER_ADDR_LEN;
  830         bcopy(LLADDR(sdl2), LLADDR(sdl1), ETHER_ADDR_LEN);
  831         bcopy(LLADDR(sdl2), IFP2ENADDR(ifp), ETHER_ADDR_LEN);
  832 
  833         /*
  834          * Configure multicast addresses that may already be
  835          * joined on the vlan device.
  836          */
  837         (void)vlan_setmulti(ifp); /* XXX: VLAN lock held */
  838 
  839         return (0);
  840 }
  841 
  842 static int
  843 vlan_unconfig(struct ifnet *ifp)
  844 {
  845         struct ifaddr *ifa;
  846         struct sockaddr_dl *sdl;
  847         struct vlan_mc_entry *mc;
  848         struct ifvlan *ifv;
  849         struct ifnet *p;
  850         int error;
  851 
  852         VLAN_LOCK_ASSERT();
  853 
  854         ifv = ifp->if_softc;
  855         p = ifv->ifv_p;
  856 
  857         if (p) {
  858                 struct sockaddr_dl sdl;
  859 
  860                 /*
  861                  * Since the interface is being unconfigured, we need to
  862                  * empty the list of multicast groups that we may have joined
  863                  * while we were alive from the parent's list.
  864                  */
  865                 bzero((char *)&sdl, sizeof(sdl));
  866                 sdl.sdl_len = sizeof(sdl);
  867                 sdl.sdl_family = AF_LINK;
  868                 sdl.sdl_index = p->if_index;
  869                 sdl.sdl_type = IFT_ETHER;
  870                 sdl.sdl_alen = ETHER_ADDR_LEN;
  871 
  872                 while(SLIST_FIRST(&ifv->vlan_mc_listhead) != NULL) {
  873                         mc = SLIST_FIRST(&ifv->vlan_mc_listhead);
  874                         bcopy((char *)&mc->mc_addr, LLADDR(&sdl),
  875                             ETHER_ADDR_LEN);
  876                         error = if_delmulti(p, (struct sockaddr *)&sdl);
  877                         if (error)
  878                                 return (error);
  879                         SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries);
  880                         free(mc, M_VLAN);
  881                 }
  882 
  883                 vlan_setflags(ifp, 0); /* clear special flags on parent */
  884                 p->if_nvlans--;
  885         }
  886 
  887         /* Disconnect from parent. */
  888         if (ifv->ifv_pflags)
  889                 if_printf(ifp, "%s: ifv_pflags unclean\n", __func__);
  890         ifv->ifv_p = NULL;
  891         ifv->ifv_ifp->if_mtu = ETHERMTU;                /* XXX why not 0? */
  892         ifv->ifv_ifp->if_link_state = LINK_STATE_UNKNOWN;
  893 
  894         /* Clear our MAC address. */
  895         ifa = ifaddr_byindex(ifv->ifv_ifp->if_index);
  896         sdl = (struct sockaddr_dl *)ifa->ifa_addr;
  897         sdl->sdl_type = IFT_ETHER;
  898         sdl->sdl_alen = ETHER_ADDR_LEN;
  899         bzero(LLADDR(sdl), ETHER_ADDR_LEN);
  900         bzero(IFP2ENADDR(ifv->ifv_ifp), ETHER_ADDR_LEN);
  901 
  902         return (0);
  903 }
  904 
  905 /* Handle a reference counted flag that should be set on the parent as well */
  906 static int
  907 vlan_setflag(struct ifnet *ifp, int flag, int status,
  908              int (*func)(struct ifnet *, int))
  909 {
  910         struct ifvlan *ifv;
  911         int error;
  912 
  913         /* XXX VLAN_LOCK_ASSERT(); */
  914 
  915         ifv = ifp->if_softc;
  916         status = status ? (ifp->if_flags & flag) : 0;
  917         /* Now "status" contains the flag value or 0 */
  918 
  919         /*
  920          * See if recorded parent's status is different from what
  921          * we want it to be.  If it is, flip it.  We record parent's
  922          * status in ifv_pflags so that we won't clear parent's flag
  923          * we haven't set.  In fact, we don't clear or set parent's
  924          * flags directly, but get or release references to them.
  925          * That's why we can be sure that recorded flags still are
  926          * in accord with actual parent's flags.
  927          */
  928         if (status != (ifv->ifv_pflags & flag)) {
  929                 error = (*func)(ifv->ifv_p, status);
  930                 if (error)
  931                         return (error);
  932                 ifv->ifv_pflags &= ~flag;
  933                 ifv->ifv_pflags |= status;
  934         }
  935         return (0);
  936 }
  937 
  938 /*
  939  * Handle IFF_* flags that require certain changes on the parent:
  940  * if "status" is true, update parent's flags respective to our if_flags;
  941  * if "status" is false, forcedly clear the flags set on parent.
  942  */
  943 static int
  944 vlan_setflags(struct ifnet *ifp, int status)
  945 {
  946         int error, i;
  947         
  948         for (i = 0; vlan_pflags[i].flag; i++) {
  949                 error = vlan_setflag(ifp, vlan_pflags[i].flag,
  950                                      status, vlan_pflags[i].func);
  951                 if (error)
  952                         return (error);
  953         }
  954         return (0);
  955 }
  956 
  957 /* Inform all vlans that their parent has changed link state */
  958 static void
  959 vlan_link_state(struct ifnet *ifp, int link)
  960 {
  961         struct ifvlan *ifv;
  962 
  963         VLAN_LOCK();
  964         LIST_FOREACH(ifv, &ifv_list, ifv_list) {
  965                 if (ifv->ifv_p == ifp) {
  966                         ifv->ifv_ifp->if_baudrate = ifp->if_baudrate;
  967                         if_link_state_change(ifv->ifv_ifp, ifp->if_link_state);
  968                 }
  969         }
  970         VLAN_UNLOCK();
  971 }
  972 
  973 static int
  974 vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  975 {
  976         struct ifaddr *ifa;
  977         struct ifnet *p;
  978         struct ifreq *ifr;
  979         struct ifvlan *ifv;
  980         struct vlanreq vlr;
  981         int error = 0;
  982 
  983         ifr = (struct ifreq *)data;
  984         ifa = (struct ifaddr *)data;
  985         ifv = ifp->if_softc;
  986 
  987         switch (cmd) {
  988         case SIOCSIFADDR:
  989                 ifp->if_flags |= IFF_UP;
  990 
  991                 switch (ifa->ifa_addr->sa_family) {
  992 #ifdef INET
  993                 case AF_INET:
  994                         arp_ifinit(ifv->ifv_ifp, ifa);
  995                         break;
  996 #endif
  997                 default:
  998                         break;
  999                 }
 1000                 break;
 1001 
 1002         case SIOCGIFADDR:
 1003                 {
 1004                         struct sockaddr *sa;
 1005 
 1006                         sa = (struct sockaddr *) &ifr->ifr_data;
 1007                         bcopy(IFP2ENADDR(ifp), (caddr_t)sa->sa_data,
 1008                             ETHER_ADDR_LEN);
 1009                 }
 1010                 break;
 1011 
 1012         case SIOCGIFMEDIA:
 1013                 VLAN_LOCK();
 1014                 if (ifv->ifv_p != NULL) {
 1015                         error = (*ifv->ifv_p->if_ioctl)(ifv->ifv_p,
 1016                                         SIOCGIFMEDIA, data);
 1017                         VLAN_UNLOCK();
 1018                         /* Limit the result to the parent's current config. */
 1019                         if (error == 0) {
 1020                                 struct ifmediareq *ifmr;
 1021 
 1022                                 ifmr = (struct ifmediareq *)data;
 1023                                 if (ifmr->ifm_count >= 1 && ifmr->ifm_ulist) {
 1024                                         ifmr->ifm_count = 1;
 1025                                         error = copyout(&ifmr->ifm_current,
 1026                                                 ifmr->ifm_ulist,
 1027                                                 sizeof(int));
 1028                                 }
 1029                         }
 1030                 } else {
 1031                         VLAN_UNLOCK();
 1032                         error = EINVAL;
 1033                 }
 1034                 break;
 1035 
 1036         case SIOCSIFMEDIA:
 1037                 error = EINVAL;
 1038                 break;
 1039 
 1040         case SIOCSIFMTU:
 1041                 /*
 1042                  * Set the interface MTU.
 1043                  */
 1044                 VLAN_LOCK();
 1045                 if (ifv->ifv_p != NULL) {
 1046                         if (ifr->ifr_mtu >
 1047                              (ifv->ifv_p->if_mtu - ifv->ifv_mtufudge) ||
 1048                             ifr->ifr_mtu <
 1049                              (ifv->ifv_mintu - ifv->ifv_mtufudge))
 1050                                 error = EINVAL;
 1051                         else
 1052                                 ifp->if_mtu = ifr->ifr_mtu;
 1053                 } else
 1054                         error = EINVAL;
 1055                 VLAN_UNLOCK();
 1056                 break;
 1057 
 1058         case SIOCSETVLAN:
 1059                 error = copyin(ifr->ifr_data, &vlr, sizeof(vlr));
 1060                 if (error)
 1061                         break;
 1062                 if (vlr.vlr_parent[0] == '\0') {
 1063                         VLAN_LOCK();
 1064                         vlan_unconfig(ifp);
 1065                         ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
 1066                         VLAN_UNLOCK();
 1067                         break;
 1068                 }
 1069                 p = ifunit(vlr.vlr_parent);
 1070                 if (p == 0) {
 1071                         error = ENOENT;
 1072                         break;
 1073                 }
 1074                 /*
 1075                  * Don't let the caller set up a VLAN tag with
 1076                  * anything except VLID bits.
 1077                  */
 1078                 if (vlr.vlr_tag & ~EVL_VLID_MASK) {
 1079                         error = EINVAL;
 1080                         break;
 1081                 }
 1082                 VLAN_LOCK();
 1083                 error = vlan_config(ifv, p);
 1084                 if (error) {
 1085                         VLAN_UNLOCK();
 1086                         break;
 1087                 }
 1088                 ifv->ifv_tag = vlr.vlr_tag;
 1089                 ifp->if_drv_flags |= IFF_DRV_RUNNING;
 1090                 VLAN_UNLOCK();
 1091 
 1092                 /* Update flags on the parent, if necessary. */
 1093                 vlan_setflags(ifp, 1);
 1094                 break;
 1095 
 1096         case SIOCGETVLAN:
 1097                 bzero(&vlr, sizeof(vlr));
 1098                 VLAN_LOCK();
 1099                 if (ifv->ifv_p) {
 1100                         strlcpy(vlr.vlr_parent, ifv->ifv_p->if_xname,
 1101                             sizeof(vlr.vlr_parent));
 1102                         vlr.vlr_tag = ifv->ifv_tag;
 1103                 }
 1104                 VLAN_UNLOCK();
 1105                 error = copyout(&vlr, ifr->ifr_data, sizeof(vlr));
 1106                 break;
 1107                 
 1108         case SIOCSIFFLAGS:
 1109                 /*
 1110                  * We should propagate selected flags to the parent,
 1111                  * e.g., promiscuous mode.
 1112                  */
 1113                 if (ifv->ifv_p != NULL)
 1114                         error = vlan_setflags(ifp, 1);
 1115                 break;
 1116 
 1117         case SIOCADDMULTI:
 1118         case SIOCDELMULTI:
 1119                 /*VLAN_LOCK();*/
 1120                 error = vlan_setmulti(ifp);
 1121                 /*VLAN_UNLOCK();*/
 1122                 break;
 1123         default:
 1124                 error = EINVAL;
 1125         }
 1126 
 1127         return (error);
 1128 }

Cache object: 9ab2ca01983cb51f8a9c08f476ba4c5c


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