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  * Copyright 2012 ADARA Networks, Inc.
    4  *
    5  * Portions of this software were developed by Robert N. M. Watson under
    6  * contract to ADARA Networks, Inc.
    7  *
    8  * Permission to use, copy, modify, and distribute this software and
    9  * its documentation for any purpose and without fee is hereby
   10  * granted, provided that both the above copyright notice and this
   11  * permission notice appear in all copies, that both the above
   12  * copyright notice and this permission notice appear in all
   13  * supporting documentation, and that the name of M.I.T. not be used
   14  * in advertising or publicity pertaining to distribution of the
   15  * software without specific, written prior permission.  M.I.T. makes
   16  * no representations about the suitability of this software for any
   17  * purpose.  It is provided "as is" without express or implied
   18  * warranty.
   19  * 
   20  * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
   21  * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
   22  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   23  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
   24  * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   27  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   28  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   30  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31  * SUCH DAMAGE.
   32  */
   33 
   34 /*
   35  * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs.
   36  * This is sort of sneaky in the implementation, since
   37  * we need to pretend to be enough of an Ethernet implementation
   38  * to make arp work.  The way we do this is by telling everyone
   39  * that we are an Ethernet, and then catch the packets that
   40  * ether_output() sends to us via if_transmit(), rewrite them for
   41  * use by the real outgoing interface, and ask it to send them.
   42  */
   43 
   44 #include <sys/cdefs.h>
   45 __FBSDID("$FreeBSD: releng/11.1/sys/net/if_vlan.c 319224 2017-05-30 16:34:18Z mav $");
   46 
   47 #include "opt_inet.h"
   48 #include "opt_vlan.h"
   49 
   50 #include <sys/param.h>
   51 #include <sys/eventhandler.h>
   52 #include <sys/kernel.h>
   53 #include <sys/lock.h>
   54 #include <sys/malloc.h>
   55 #include <sys/mbuf.h>
   56 #include <sys/module.h>
   57 #include <sys/rmlock.h>
   58 #include <sys/priv.h>
   59 #include <sys/queue.h>
   60 #include <sys/socket.h>
   61 #include <sys/sockio.h>
   62 #include <sys/sysctl.h>
   63 #include <sys/systm.h>
   64 #include <sys/sx.h>
   65 
   66 #include <net/bpf.h>
   67 #include <net/ethernet.h>
   68 #include <net/if.h>
   69 #include <net/if_var.h>
   70 #include <net/if_clone.h>
   71 #include <net/if_dl.h>
   72 #include <net/if_types.h>
   73 #include <net/if_vlan_var.h>
   74 #include <net/vnet.h>
   75 
   76 #ifdef INET
   77 #include <netinet/in.h>
   78 #include <netinet/if_ether.h>
   79 #endif
   80 
   81 #define VLAN_DEF_HWIDTH 4
   82 #define VLAN_IFFLAGS    (IFF_BROADCAST | IFF_MULTICAST)
   83 
   84 #define UP_AND_RUNNING(ifp) \
   85     ((ifp)->if_flags & IFF_UP && (ifp)->if_drv_flags & IFF_DRV_RUNNING)
   86 
   87 LIST_HEAD(ifvlanhead, ifvlan);
   88 
   89 struct ifvlantrunk {
   90         struct  ifnet   *parent;        /* parent interface of this trunk */
   91         struct  rmlock  lock;
   92 #ifdef VLAN_ARRAY
   93 #define VLAN_ARRAY_SIZE (EVL_VLID_MASK + 1)
   94         struct  ifvlan  *vlans[VLAN_ARRAY_SIZE]; /* static table */
   95 #else
   96         struct  ifvlanhead *hash;       /* dynamic hash-list table */
   97         uint16_t        hmask;
   98         uint16_t        hwidth;
   99 #endif
  100         int             refcnt;
  101 };
  102 
  103 struct vlan_mc_entry {
  104         struct sockaddr_dl              mc_addr;
  105         SLIST_ENTRY(vlan_mc_entry)      mc_entries;
  106 };
  107 
  108 struct  ifvlan {
  109         struct  ifvlantrunk *ifv_trunk;
  110         struct  ifnet *ifv_ifp;
  111 #define TRUNK(ifv)      ((ifv)->ifv_trunk)
  112 #define PARENT(ifv)     ((ifv)->ifv_trunk->parent)
  113         void    *ifv_cookie;
  114         int     ifv_pflags;     /* special flags we have set on parent */
  115         int     ifv_capenable;
  116         struct  ifv_linkmib {
  117                 int     ifvm_encaplen;  /* encapsulation length */
  118                 int     ifvm_mtufudge;  /* MTU fudged by this much */
  119                 int     ifvm_mintu;     /* min transmission unit */
  120                 uint16_t ifvm_proto;    /* encapsulation ethertype */
  121                 uint16_t ifvm_tag;      /* tag to apply on packets leaving if */
  122                 uint16_t ifvm_vid;      /* VLAN ID */
  123                 uint8_t ifvm_pcp;       /* Priority Code Point (PCP). */
  124         }       ifv_mib;
  125         SLIST_HEAD(, vlan_mc_entry) vlan_mc_listhead;
  126 #ifndef VLAN_ARRAY
  127         LIST_ENTRY(ifvlan) ifv_list;
  128 #endif
  129 };
  130 #define ifv_proto       ifv_mib.ifvm_proto
  131 #define ifv_tag         ifv_mib.ifvm_tag
  132 #define ifv_vid         ifv_mib.ifvm_vid
  133 #define ifv_pcp         ifv_mib.ifvm_pcp
  134 #define ifv_encaplen    ifv_mib.ifvm_encaplen
  135 #define ifv_mtufudge    ifv_mib.ifvm_mtufudge
  136 #define ifv_mintu       ifv_mib.ifvm_mintu
  137 
  138 /* Special flags we should propagate to parent. */
  139 static struct {
  140         int flag;
  141         int (*func)(struct ifnet *, int);
  142 } vlan_pflags[] = {
  143         {IFF_PROMISC, ifpromisc},
  144         {IFF_ALLMULTI, if_allmulti},
  145         {0, NULL}
  146 };
  147 
  148 SYSCTL_DECL(_net_link);
  149 static SYSCTL_NODE(_net_link, IFT_L2VLAN, vlan, CTLFLAG_RW, 0,
  150     "IEEE 802.1Q VLAN");
  151 static SYSCTL_NODE(_net_link_vlan, PF_LINK, link, CTLFLAG_RW, 0,
  152     "for consistency");
  153 
  154 static VNET_DEFINE(int, soft_pad);
  155 #define V_soft_pad      VNET(soft_pad)
  156 SYSCTL_INT(_net_link_vlan, OID_AUTO, soft_pad, CTLFLAG_RW | CTLFLAG_VNET,
  157     &VNET_NAME(soft_pad), 0, "pad short frames before tagging");
  158 
  159 /*
  160  * For now, make preserving PCP via an mbuf tag optional, as it increases
  161  * per-packet memory allocations and frees.  In the future, it would be
  162  * preferable to reuse ether_vtag for this, or similar.
  163  */
  164 static int vlan_mtag_pcp = 0;
  165 SYSCTL_INT(_net_link_vlan, OID_AUTO, mtag_pcp, CTLFLAG_RW, &vlan_mtag_pcp, 0,
  166         "Retain VLAN PCP information as packets are passed up the stack");
  167 
  168 static const char vlanname[] = "vlan";
  169 static MALLOC_DEFINE(M_VLAN, vlanname, "802.1Q Virtual LAN Interface");
  170 
  171 static eventhandler_tag ifdetach_tag;
  172 static eventhandler_tag iflladdr_tag;
  173 
  174 /*
  175  * We have a global mutex, that is used to serialize configuration
  176  * changes and isn't used in normal packet delivery.
  177  *
  178  * We also have a per-trunk rmlock(9), that is locked shared on packet
  179  * processing and exclusive when configuration is changed.
  180  *
  181  * The VLAN_ARRAY substitutes the dynamic hash with a static array
  182  * with 4096 entries. In theory this can give a boost in processing,
  183  * however on practice it does not. Probably this is because array
  184  * is too big to fit into CPU cache.
  185  */
  186 static struct sx ifv_lock;
  187 #define VLAN_LOCK_INIT()        sx_init(&ifv_lock, "vlan_global")
  188 #define VLAN_LOCK_DESTROY()     sx_destroy(&ifv_lock)
  189 #define VLAN_LOCK_ASSERT()      sx_assert(&ifv_lock, SA_LOCKED)
  190 #define VLAN_LOCK()             sx_xlock(&ifv_lock)
  191 #define VLAN_UNLOCK()           sx_xunlock(&ifv_lock)
  192 #define TRUNK_LOCK_INIT(trunk)  rm_init(&(trunk)->lock, vlanname)
  193 #define TRUNK_LOCK_DESTROY(trunk) rm_destroy(&(trunk)->lock)
  194 #define TRUNK_LOCK(trunk)       rm_wlock(&(trunk)->lock)
  195 #define TRUNK_UNLOCK(trunk)     rm_wunlock(&(trunk)->lock)
  196 #define TRUNK_LOCK_ASSERT(trunk) rm_assert(&(trunk)->lock, RA_WLOCKED)
  197 #define TRUNK_RLOCK(trunk)      rm_rlock(&(trunk)->lock, &tracker)
  198 #define TRUNK_RUNLOCK(trunk)    rm_runlock(&(trunk)->lock, &tracker)
  199 #define TRUNK_LOCK_RASSERT(trunk) rm_assert(&(trunk)->lock, RA_RLOCKED)
  200 #define TRUNK_LOCK_READER       struct rm_priotracker tracker
  201 
  202 #ifndef VLAN_ARRAY
  203 static  void vlan_inithash(struct ifvlantrunk *trunk);
  204 static  void vlan_freehash(struct ifvlantrunk *trunk);
  205 static  int vlan_inshash(struct ifvlantrunk *trunk, struct ifvlan *ifv);
  206 static  int vlan_remhash(struct ifvlantrunk *trunk, struct ifvlan *ifv);
  207 static  void vlan_growhash(struct ifvlantrunk *trunk, int howmuch);
  208 static __inline struct ifvlan * vlan_gethash(struct ifvlantrunk *trunk,
  209         uint16_t vid);
  210 #endif
  211 static  void trunk_destroy(struct ifvlantrunk *trunk);
  212 
  213 static  void vlan_init(void *foo);
  214 static  void vlan_input(struct ifnet *ifp, struct mbuf *m);
  215 static  int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr);
  216 static  void vlan_qflush(struct ifnet *ifp);
  217 static  int vlan_setflag(struct ifnet *ifp, int flag, int status,
  218     int (*func)(struct ifnet *, int));
  219 static  int vlan_setflags(struct ifnet *ifp, int status);
  220 static  int vlan_setmulti(struct ifnet *ifp);
  221 static  int vlan_transmit(struct ifnet *ifp, struct mbuf *m);
  222 static  void vlan_unconfig(struct ifnet *ifp);
  223 static  void vlan_unconfig_locked(struct ifnet *ifp, int departing);
  224 static  int vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t tag);
  225 static  void vlan_link_state(struct ifnet *ifp);
  226 static  void vlan_capabilities(struct ifvlan *ifv);
  227 static  void vlan_trunk_capabilities(struct ifnet *ifp);
  228 
  229 static  struct ifnet *vlan_clone_match_ethervid(const char *, int *);
  230 static  int vlan_clone_match(struct if_clone *, const char *);
  231 static  int vlan_clone_create(struct if_clone *, char *, size_t, caddr_t);
  232 static  int vlan_clone_destroy(struct if_clone *, struct ifnet *);
  233 
  234 static  void vlan_ifdetach(void *arg, struct ifnet *ifp);
  235 static  void vlan_iflladdr(void *arg, struct ifnet *ifp);
  236 
  237 static struct if_clone *vlan_cloner;
  238 
  239 #ifdef VIMAGE
  240 static VNET_DEFINE(struct if_clone *, vlan_cloner);
  241 #define V_vlan_cloner   VNET(vlan_cloner)
  242 #endif
  243 
  244 #ifndef VLAN_ARRAY
  245 #define HASH(n, m)      ((((n) >> 8) ^ ((n) >> 4) ^ (n)) & (m))
  246 
  247 static void
  248 vlan_inithash(struct ifvlantrunk *trunk)
  249 {
  250         int i, n;
  251         
  252         /*
  253          * The trunk must not be locked here since we call malloc(M_WAITOK).
  254          * It is OK in case this function is called before the trunk struct
  255          * gets hooked up and becomes visible from other threads.
  256          */
  257 
  258         KASSERT(trunk->hwidth == 0 && trunk->hash == NULL,
  259             ("%s: hash already initialized", __func__));
  260 
  261         trunk->hwidth = VLAN_DEF_HWIDTH;
  262         n = 1 << trunk->hwidth;
  263         trunk->hmask = n - 1;
  264         trunk->hash = malloc(sizeof(struct ifvlanhead) * n, M_VLAN, M_WAITOK);
  265         for (i = 0; i < n; i++)
  266                 LIST_INIT(&trunk->hash[i]);
  267 }
  268 
  269 static void
  270 vlan_freehash(struct ifvlantrunk *trunk)
  271 {
  272 #ifdef INVARIANTS
  273         int i;
  274 
  275         KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__));
  276         for (i = 0; i < (1 << trunk->hwidth); i++)
  277                 KASSERT(LIST_EMPTY(&trunk->hash[i]),
  278                     ("%s: hash table not empty", __func__));
  279 #endif
  280         free(trunk->hash, M_VLAN);
  281         trunk->hash = NULL;
  282         trunk->hwidth = trunk->hmask = 0;
  283 }
  284 
  285 static int
  286 vlan_inshash(struct ifvlantrunk *trunk, struct ifvlan *ifv)
  287 {
  288         int i, b;
  289         struct ifvlan *ifv2;
  290 
  291         TRUNK_LOCK_ASSERT(trunk);
  292         KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__));
  293 
  294         b = 1 << trunk->hwidth;
  295         i = HASH(ifv->ifv_vid, trunk->hmask);
  296         LIST_FOREACH(ifv2, &trunk->hash[i], ifv_list)
  297                 if (ifv->ifv_vid == ifv2->ifv_vid)
  298                         return (EEXIST);
  299 
  300         /*
  301          * Grow the hash when the number of vlans exceeds half of the number of
  302          * hash buckets squared. This will make the average linked-list length
  303          * buckets/2.
  304          */
  305         if (trunk->refcnt > (b * b) / 2) {
  306                 vlan_growhash(trunk, 1);
  307                 i = HASH(ifv->ifv_vid, trunk->hmask);
  308         }
  309         LIST_INSERT_HEAD(&trunk->hash[i], ifv, ifv_list);
  310         trunk->refcnt++;
  311 
  312         return (0);
  313 }
  314 
  315 static int
  316 vlan_remhash(struct ifvlantrunk *trunk, struct ifvlan *ifv)
  317 {
  318         int i, b;
  319         struct ifvlan *ifv2;
  320 
  321         TRUNK_LOCK_ASSERT(trunk);
  322         KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__));
  323         
  324         b = 1 << trunk->hwidth;
  325         i = HASH(ifv->ifv_vid, trunk->hmask);
  326         LIST_FOREACH(ifv2, &trunk->hash[i], ifv_list)
  327                 if (ifv2 == ifv) {
  328                         trunk->refcnt--;
  329                         LIST_REMOVE(ifv2, ifv_list);
  330                         if (trunk->refcnt < (b * b) / 2)
  331                                 vlan_growhash(trunk, -1);
  332                         return (0);
  333                 }
  334 
  335         panic("%s: vlan not found\n", __func__);
  336         return (ENOENT); /*NOTREACHED*/
  337 }
  338 
  339 /*
  340  * Grow the hash larger or smaller if memory permits.
  341  */
  342 static void
  343 vlan_growhash(struct ifvlantrunk *trunk, int howmuch)
  344 {
  345         struct ifvlan *ifv;
  346         struct ifvlanhead *hash2;
  347         int hwidth2, i, j, n, n2;
  348 
  349         TRUNK_LOCK_ASSERT(trunk);
  350         KASSERT(trunk->hwidth > 0, ("%s: hwidth not positive", __func__));
  351 
  352         if (howmuch == 0) {
  353                 /* Harmless yet obvious coding error */
  354                 printf("%s: howmuch is 0\n", __func__);
  355                 return;
  356         }
  357 
  358         hwidth2 = trunk->hwidth + howmuch;
  359         n = 1 << trunk->hwidth;
  360         n2 = 1 << hwidth2;
  361         /* Do not shrink the table below the default */
  362         if (hwidth2 < VLAN_DEF_HWIDTH)
  363                 return;
  364 
  365         /* M_NOWAIT because we're called with trunk mutex held */
  366         hash2 = malloc(sizeof(struct ifvlanhead) * n2, M_VLAN, M_NOWAIT);
  367         if (hash2 == NULL) {
  368                 printf("%s: out of memory -- hash size not changed\n",
  369                     __func__);
  370                 return;         /* We can live with the old hash table */
  371         }
  372         for (j = 0; j < n2; j++)
  373                 LIST_INIT(&hash2[j]);
  374         for (i = 0; i < n; i++)
  375                 while ((ifv = LIST_FIRST(&trunk->hash[i])) != NULL) {
  376                         LIST_REMOVE(ifv, ifv_list);
  377                         j = HASH(ifv->ifv_vid, n2 - 1);
  378                         LIST_INSERT_HEAD(&hash2[j], ifv, ifv_list);
  379                 }
  380         free(trunk->hash, M_VLAN);
  381         trunk->hash = hash2;
  382         trunk->hwidth = hwidth2;
  383         trunk->hmask = n2 - 1;
  384 
  385         if (bootverbose)
  386                 if_printf(trunk->parent,
  387                     "VLAN hash table resized from %d to %d buckets\n", n, n2);
  388 }
  389 
  390 static __inline struct ifvlan *
  391 vlan_gethash(struct ifvlantrunk *trunk, uint16_t vid)
  392 {
  393         struct ifvlan *ifv;
  394 
  395         TRUNK_LOCK_RASSERT(trunk);
  396 
  397         LIST_FOREACH(ifv, &trunk->hash[HASH(vid, trunk->hmask)], ifv_list)
  398                 if (ifv->ifv_vid == vid)
  399                         return (ifv);
  400         return (NULL);
  401 }
  402 
  403 #if 0
  404 /* Debugging code to view the hashtables. */
  405 static void
  406 vlan_dumphash(struct ifvlantrunk *trunk)
  407 {
  408         int i;
  409         struct ifvlan *ifv;
  410 
  411         for (i = 0; i < (1 << trunk->hwidth); i++) {
  412                 printf("%d: ", i);
  413                 LIST_FOREACH(ifv, &trunk->hash[i], ifv_list)
  414                         printf("%s ", ifv->ifv_ifp->if_xname);
  415                 printf("\n");
  416         }
  417 }
  418 #endif /* 0 */
  419 #else
  420 
  421 static __inline struct ifvlan *
  422 vlan_gethash(struct ifvlantrunk *trunk, uint16_t vid)
  423 {
  424 
  425         return trunk->vlans[vid];
  426 }
  427 
  428 static __inline int
  429 vlan_inshash(struct ifvlantrunk *trunk, struct ifvlan *ifv)
  430 {
  431 
  432         if (trunk->vlans[ifv->ifv_vid] != NULL)
  433                 return EEXIST;
  434         trunk->vlans[ifv->ifv_vid] = ifv;
  435         trunk->refcnt++;
  436 
  437         return (0);
  438 }
  439 
  440 static __inline int
  441 vlan_remhash(struct ifvlantrunk *trunk, struct ifvlan *ifv)
  442 {
  443 
  444         trunk->vlans[ifv->ifv_vid] = NULL;
  445         trunk->refcnt--;
  446 
  447         return (0);
  448 }
  449 
  450 static __inline void
  451 vlan_freehash(struct ifvlantrunk *trunk)
  452 {
  453 }
  454 
  455 static __inline void
  456 vlan_inithash(struct ifvlantrunk *trunk)
  457 {
  458 }
  459 
  460 #endif /* !VLAN_ARRAY */
  461 
  462 static void
  463 trunk_destroy(struct ifvlantrunk *trunk)
  464 {
  465         VLAN_LOCK_ASSERT();
  466 
  467         TRUNK_LOCK(trunk);
  468         vlan_freehash(trunk);
  469         trunk->parent->if_vlantrunk = NULL;
  470         TRUNK_UNLOCK(trunk);
  471         TRUNK_LOCK_DESTROY(trunk);
  472         if_rele(trunk->parent);
  473         free(trunk, M_VLAN);
  474 }
  475 
  476 /*
  477  * Program our multicast filter. What we're actually doing is
  478  * programming the multicast filter of the parent. This has the
  479  * side effect of causing the parent interface to receive multicast
  480  * traffic that it doesn't really want, which ends up being discarded
  481  * later by the upper protocol layers. Unfortunately, there's no way
  482  * to avoid this: there really is only one physical interface.
  483  */
  484 static int
  485 vlan_setmulti(struct ifnet *ifp)
  486 {
  487         struct ifnet            *ifp_p;
  488         struct ifmultiaddr      *ifma;
  489         struct ifvlan           *sc;
  490         struct vlan_mc_entry    *mc;
  491         int                     error;
  492 
  493         /* Find the parent. */
  494         sc = ifp->if_softc;
  495         TRUNK_LOCK_ASSERT(TRUNK(sc));
  496         ifp_p = PARENT(sc);
  497 
  498         CURVNET_SET_QUIET(ifp_p->if_vnet);
  499 
  500         /* First, remove any existing filter entries. */
  501         while ((mc = SLIST_FIRST(&sc->vlan_mc_listhead)) != NULL) {
  502                 SLIST_REMOVE_HEAD(&sc->vlan_mc_listhead, mc_entries);
  503                 (void)if_delmulti(ifp_p, (struct sockaddr *)&mc->mc_addr);
  504                 free(mc, M_VLAN);
  505         }
  506 
  507         /* Now program new ones. */
  508         IF_ADDR_WLOCK(ifp);
  509         TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  510                 if (ifma->ifma_addr->sa_family != AF_LINK)
  511                         continue;
  512                 mc = malloc(sizeof(struct vlan_mc_entry), M_VLAN, M_NOWAIT);
  513                 if (mc == NULL) {
  514                         IF_ADDR_WUNLOCK(ifp);
  515                         return (ENOMEM);
  516                 }
  517                 bcopy(ifma->ifma_addr, &mc->mc_addr, ifma->ifma_addr->sa_len);
  518                 mc->mc_addr.sdl_index = ifp_p->if_index;
  519                 SLIST_INSERT_HEAD(&sc->vlan_mc_listhead, mc, mc_entries);
  520         }
  521         IF_ADDR_WUNLOCK(ifp);
  522         SLIST_FOREACH (mc, &sc->vlan_mc_listhead, mc_entries) {
  523                 error = if_addmulti(ifp_p, (struct sockaddr *)&mc->mc_addr,
  524                     NULL);
  525                 if (error)
  526                         return (error);
  527         }
  528 
  529         CURVNET_RESTORE();
  530         return (0);
  531 }
  532 
  533 /*
  534  * A handler for parent interface link layer address changes.
  535  * If the parent interface link layer address is changed we
  536  * should also change it on all children vlans.
  537  */
  538 static void
  539 vlan_iflladdr(void *arg __unused, struct ifnet *ifp)
  540 {
  541         struct ifvlan *ifv;
  542 #ifndef VLAN_ARRAY
  543         struct ifvlan *next;
  544 #endif
  545         int i;
  546 
  547         /*
  548          * Check if it's a trunk interface first of all
  549          * to avoid needless locking.
  550          */
  551         if (ifp->if_vlantrunk == NULL)
  552                 return;
  553 
  554         VLAN_LOCK();
  555         /*
  556          * OK, it's a trunk.  Loop over and change all vlan's lladdrs on it.
  557          */
  558 #ifdef VLAN_ARRAY
  559         for (i = 0; i < VLAN_ARRAY_SIZE; i++)
  560                 if ((ifv = ifp->if_vlantrunk->vlans[i])) {
  561 #else /* VLAN_ARRAY */
  562         for (i = 0; i < (1 << ifp->if_vlantrunk->hwidth); i++)
  563                 LIST_FOREACH_SAFE(ifv, &ifp->if_vlantrunk->hash[i], ifv_list, next) {
  564 #endif /* VLAN_ARRAY */
  565                         VLAN_UNLOCK();
  566                         if_setlladdr(ifv->ifv_ifp, IF_LLADDR(ifp),
  567                             ifp->if_addrlen);
  568                         VLAN_LOCK();
  569                 }
  570         VLAN_UNLOCK();
  571 
  572 }
  573 
  574 /*
  575  * A handler for network interface departure events.
  576  * Track departure of trunks here so that we don't access invalid
  577  * pointers or whatever if a trunk is ripped from under us, e.g.,
  578  * by ejecting its hot-plug card.  However, if an ifnet is simply
  579  * being renamed, then there's no need to tear down the state.
  580  */
  581 static void
  582 vlan_ifdetach(void *arg __unused, struct ifnet *ifp)
  583 {
  584         struct ifvlan *ifv;
  585         int i;
  586 
  587         /*
  588          * Check if it's a trunk interface first of all
  589          * to avoid needless locking.
  590          */
  591         if (ifp->if_vlantrunk == NULL)
  592                 return;
  593 
  594         /* If the ifnet is just being renamed, don't do anything. */
  595         if (ifp->if_flags & IFF_RENAMING)
  596                 return;
  597 
  598         VLAN_LOCK();
  599         /*
  600          * OK, it's a trunk.  Loop over and detach all vlan's on it.
  601          * Check trunk pointer after each vlan_unconfig() as it will
  602          * free it and set to NULL after the last vlan was detached.
  603          */
  604 #ifdef VLAN_ARRAY
  605         for (i = 0; i < VLAN_ARRAY_SIZE; i++)
  606                 if ((ifv = ifp->if_vlantrunk->vlans[i])) {
  607                         vlan_unconfig_locked(ifv->ifv_ifp, 1);
  608                         if (ifp->if_vlantrunk == NULL)
  609                                 break;
  610                 }
  611 #else /* VLAN_ARRAY */
  612 restart:
  613         for (i = 0; i < (1 << ifp->if_vlantrunk->hwidth); i++)
  614                 if ((ifv = LIST_FIRST(&ifp->if_vlantrunk->hash[i]))) {
  615                         vlan_unconfig_locked(ifv->ifv_ifp, 1);
  616                         if (ifp->if_vlantrunk)
  617                                 goto restart;   /* trunk->hwidth can change */
  618                         else
  619                                 break;
  620                 }
  621 #endif /* VLAN_ARRAY */
  622         /* Trunk should have been destroyed in vlan_unconfig(). */
  623         KASSERT(ifp->if_vlantrunk == NULL, ("%s: purge failed", __func__));
  624         VLAN_UNLOCK();
  625 }
  626 
  627 /*
  628  * Return the trunk device for a virtual interface.
  629  */
  630 static struct ifnet  *
  631 vlan_trunkdev(struct ifnet *ifp)
  632 {
  633         struct ifvlan *ifv;
  634 
  635         if (ifp->if_type != IFT_L2VLAN)
  636                 return (NULL);
  637         ifv = ifp->if_softc;
  638         ifp = NULL;
  639         VLAN_LOCK();
  640         if (ifv->ifv_trunk)
  641                 ifp = PARENT(ifv);
  642         VLAN_UNLOCK();
  643         return (ifp);
  644 }
  645 
  646 /*
  647  * Return the 12-bit VLAN VID for this interface, for use by external
  648  * components such as Infiniband.
  649  *
  650  * XXXRW: Note that the function name here is historical; it should be named
  651  * vlan_vid().
  652  */
  653 static int
  654 vlan_tag(struct ifnet *ifp, uint16_t *vidp)
  655 {
  656         struct ifvlan *ifv;
  657 
  658         if (ifp->if_type != IFT_L2VLAN)
  659                 return (EINVAL);
  660         ifv = ifp->if_softc;
  661         *vidp = ifv->ifv_vid;
  662         return (0);
  663 }
  664 
  665 /*
  666  * Return a driver specific cookie for this interface.  Synchronization
  667  * with setcookie must be provided by the driver. 
  668  */
  669 static void *
  670 vlan_cookie(struct ifnet *ifp)
  671 {
  672         struct ifvlan *ifv;
  673 
  674         if (ifp->if_type != IFT_L2VLAN)
  675                 return (NULL);
  676         ifv = ifp->if_softc;
  677         return (ifv->ifv_cookie);
  678 }
  679 
  680 /*
  681  * Store a cookie in our softc that drivers can use to store driver
  682  * private per-instance data in.
  683  */
  684 static int
  685 vlan_setcookie(struct ifnet *ifp, void *cookie)
  686 {
  687         struct ifvlan *ifv;
  688 
  689         if (ifp->if_type != IFT_L2VLAN)
  690                 return (EINVAL);
  691         ifv = ifp->if_softc;
  692         ifv->ifv_cookie = cookie;
  693         return (0);
  694 }
  695 
  696 /*
  697  * Return the vlan device present at the specific VID.
  698  */
  699 static struct ifnet *
  700 vlan_devat(struct ifnet *ifp, uint16_t vid)
  701 {
  702         struct ifvlantrunk *trunk;
  703         struct ifvlan *ifv;
  704         TRUNK_LOCK_READER;
  705 
  706         trunk = ifp->if_vlantrunk;
  707         if (trunk == NULL)
  708                 return (NULL);
  709         ifp = NULL;
  710         TRUNK_RLOCK(trunk);
  711         ifv = vlan_gethash(trunk, vid);
  712         if (ifv)
  713                 ifp = ifv->ifv_ifp;
  714         TRUNK_RUNLOCK(trunk);
  715         return (ifp);
  716 }
  717 
  718 /*
  719  * Recalculate the cached VLAN tag exposed via the MIB.
  720  */
  721 static void
  722 vlan_tag_recalculate(struct ifvlan *ifv)
  723 {
  724 
  725        ifv->ifv_tag = EVL_MAKETAG(ifv->ifv_vid, ifv->ifv_pcp, 0);
  726 }
  727 
  728 /*
  729  * VLAN support can be loaded as a module.  The only place in the
  730  * system that's intimately aware of this is ether_input.  We hook
  731  * into this code through vlan_input_p which is defined there and
  732  * set here.  No one else in the system should be aware of this so
  733  * we use an explicit reference here.
  734  */
  735 extern  void (*vlan_input_p)(struct ifnet *, struct mbuf *);
  736 
  737 /* For if_link_state_change() eyes only... */
  738 extern  void (*vlan_link_state_p)(struct ifnet *);
  739 
  740 static int
  741 vlan_modevent(module_t mod, int type, void *data)
  742 {
  743 
  744         switch (type) {
  745         case MOD_LOAD:
  746                 ifdetach_tag = EVENTHANDLER_REGISTER(ifnet_departure_event,
  747                     vlan_ifdetach, NULL, EVENTHANDLER_PRI_ANY);
  748                 if (ifdetach_tag == NULL)
  749                         return (ENOMEM);
  750                 iflladdr_tag = EVENTHANDLER_REGISTER(iflladdr_event,
  751                     vlan_iflladdr, NULL, EVENTHANDLER_PRI_ANY);
  752                 if (iflladdr_tag == NULL)
  753                         return (ENOMEM);
  754                 VLAN_LOCK_INIT();
  755                 vlan_input_p = vlan_input;
  756                 vlan_link_state_p = vlan_link_state;
  757                 vlan_trunk_cap_p = vlan_trunk_capabilities;
  758                 vlan_trunkdev_p = vlan_trunkdev;
  759                 vlan_cookie_p = vlan_cookie;
  760                 vlan_setcookie_p = vlan_setcookie;
  761                 vlan_tag_p = vlan_tag;
  762                 vlan_devat_p = vlan_devat;
  763 #ifndef VIMAGE
  764                 vlan_cloner = if_clone_advanced(vlanname, 0, vlan_clone_match,
  765                     vlan_clone_create, vlan_clone_destroy);
  766 #endif
  767                 if (bootverbose)
  768                         printf("vlan: initialized, using "
  769 #ifdef VLAN_ARRAY
  770                                "full-size arrays"
  771 #else
  772                                "hash tables with chaining"
  773 #endif
  774                         
  775                                "\n");
  776                 break;
  777         case MOD_UNLOAD:
  778 #ifndef VIMAGE
  779                 if_clone_detach(vlan_cloner);
  780 #endif
  781                 EVENTHANDLER_DEREGISTER(ifnet_departure_event, ifdetach_tag);
  782                 EVENTHANDLER_DEREGISTER(iflladdr_event, iflladdr_tag);
  783                 vlan_input_p = NULL;
  784                 vlan_link_state_p = NULL;
  785                 vlan_trunk_cap_p = NULL;
  786                 vlan_trunkdev_p = NULL;
  787                 vlan_tag_p = NULL;
  788                 vlan_cookie_p = NULL;
  789                 vlan_setcookie_p = NULL;
  790                 vlan_devat_p = NULL;
  791                 VLAN_LOCK_DESTROY();
  792                 if (bootverbose)
  793                         printf("vlan: unloaded\n");
  794                 break;
  795         default:
  796                 return (EOPNOTSUPP);
  797         }
  798         return (0);
  799 }
  800 
  801 static moduledata_t vlan_mod = {
  802         "if_vlan",
  803         vlan_modevent,
  804         0
  805 };
  806 
  807 DECLARE_MODULE(if_vlan, vlan_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
  808 MODULE_VERSION(if_vlan, 3);
  809 
  810 #ifdef VIMAGE
  811 static void
  812 vnet_vlan_init(const void *unused __unused)
  813 {
  814 
  815         vlan_cloner = if_clone_advanced(vlanname, 0, vlan_clone_match,
  816                     vlan_clone_create, vlan_clone_destroy);
  817         V_vlan_cloner = vlan_cloner;
  818 }
  819 VNET_SYSINIT(vnet_vlan_init, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY,
  820     vnet_vlan_init, NULL);
  821 
  822 static void
  823 vnet_vlan_uninit(const void *unused __unused)
  824 {
  825 
  826         if_clone_detach(V_vlan_cloner);
  827 }
  828 VNET_SYSUNINIT(vnet_vlan_uninit, SI_SUB_INIT_IF, SI_ORDER_FIRST,
  829     vnet_vlan_uninit, NULL);
  830 #endif
  831 
  832 /*
  833  * Check for <etherif>.<vlan> style interface names.
  834  */
  835 static struct ifnet *
  836 vlan_clone_match_ethervid(const char *name, int *vidp)
  837 {
  838         char ifname[IFNAMSIZ];
  839         char *cp;
  840         struct ifnet *ifp;
  841         int vid;
  842 
  843         strlcpy(ifname, name, IFNAMSIZ);
  844         if ((cp = strchr(ifname, '.')) == NULL)
  845                 return (NULL);
  846         *cp = '\0';
  847         if ((ifp = ifunit_ref(ifname)) == NULL)
  848                 return (NULL);
  849         /* Parse VID. */
  850         if (*++cp == '\0') {
  851                 if_rele(ifp);
  852                 return (NULL);
  853         }
  854         vid = 0;
  855         for(; *cp >= '' && *cp <= '9'; cp++)
  856                 vid = (vid * 10) + (*cp - '');
  857         if (*cp != '\0') {
  858                 if_rele(ifp);
  859                 return (NULL);
  860         }
  861         if (vidp != NULL)
  862                 *vidp = vid;
  863 
  864         return (ifp);
  865 }
  866 
  867 static int
  868 vlan_clone_match(struct if_clone *ifc, const char *name)
  869 {
  870         const char *cp;
  871 
  872         if (vlan_clone_match_ethervid(name, NULL) != NULL)
  873                 return (1);
  874 
  875         if (strncmp(vlanname, name, strlen(vlanname)) != 0)
  876                 return (0);
  877         for (cp = name + 4; *cp != '\0'; cp++) {
  878                 if (*cp < '' || *cp > '9')
  879                         return (0);
  880         }
  881 
  882         return (1);
  883 }
  884 
  885 static int
  886 vlan_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
  887 {
  888         char *dp;
  889         int wildcard;
  890         int unit;
  891         int error;
  892         int vid;
  893         struct ifvlan *ifv;
  894         struct ifnet *ifp;
  895         struct ifnet *p;
  896         struct ifaddr *ifa;
  897         struct sockaddr_dl *sdl;
  898         struct vlanreq vlr;
  899         static const u_char eaddr[ETHER_ADDR_LEN];      /* 00:00:00:00:00:00 */
  900 
  901         /*
  902          * There are 3 (ugh) ways to specify the cloned device:
  903          * o pass a parameter block with the clone request.
  904          * o specify parameters in the text of the clone device name
  905          * o specify no parameters and get an unattached device that
  906          *   must be configured separately.
  907          * The first technique is preferred; the latter two are
  908          * supported for backwards compatibility.
  909          *
  910          * XXXRW: Note historic use of the word "tag" here.  New ioctls may be
  911          * called for.
  912          */
  913         if (params) {
  914                 error = copyin(params, &vlr, sizeof(vlr));
  915                 if (error)
  916                         return error;
  917                 p = ifunit_ref(vlr.vlr_parent);
  918                 if (p == NULL)
  919                         return (ENXIO);
  920                 error = ifc_name2unit(name, &unit);
  921                 if (error != 0) {
  922                         if_rele(p);
  923                         return (error);
  924                 }
  925                 vid = vlr.vlr_tag;
  926                 wildcard = (unit < 0);
  927         } else if ((p = vlan_clone_match_ethervid(name, &vid)) != NULL) {
  928                 unit = -1;
  929                 wildcard = 0;
  930         } else {
  931                 p = NULL;
  932                 error = ifc_name2unit(name, &unit);
  933                 if (error != 0)
  934                         return (error);
  935 
  936                 wildcard = (unit < 0);
  937         }
  938 
  939         error = ifc_alloc_unit(ifc, &unit);
  940         if (error != 0) {
  941                 if (p != NULL)
  942                         if_rele(p);
  943                 return (error);
  944         }
  945 
  946         /* In the wildcard case, we need to update the name. */
  947         if (wildcard) {
  948                 for (dp = name; *dp != '\0'; dp++);
  949                 if (snprintf(dp, len - (dp-name), "%d", unit) >
  950                     len - (dp-name) - 1) {
  951                         panic("%s: interface name too long", __func__);
  952                 }
  953         }
  954 
  955         ifv = malloc(sizeof(struct ifvlan), M_VLAN, M_WAITOK | M_ZERO);
  956         ifp = ifv->ifv_ifp = if_alloc(IFT_ETHER);
  957         if (ifp == NULL) {
  958                 ifc_free_unit(ifc, unit);
  959                 free(ifv, M_VLAN);
  960                 if (p != NULL)
  961                         if_rele(p);
  962                 return (ENOSPC);
  963         }
  964         SLIST_INIT(&ifv->vlan_mc_listhead);
  965         ifp->if_softc = ifv;
  966         /*
  967          * Set the name manually rather than using if_initname because
  968          * we don't conform to the default naming convention for interfaces.
  969          */
  970         strlcpy(ifp->if_xname, name, IFNAMSIZ);
  971         ifp->if_dname = vlanname;
  972         ifp->if_dunit = unit;
  973         /* NB: flags are not set here */
  974         ifp->if_linkmib = &ifv->ifv_mib;
  975         ifp->if_linkmiblen = sizeof(ifv->ifv_mib);
  976         /* NB: mtu is not set here */
  977 
  978         ifp->if_init = vlan_init;
  979         ifp->if_transmit = vlan_transmit;
  980         ifp->if_qflush = vlan_qflush;
  981         ifp->if_ioctl = vlan_ioctl;
  982         ifp->if_flags = VLAN_IFFLAGS;
  983         ether_ifattach(ifp, eaddr);
  984         /* Now undo some of the damage... */
  985         ifp->if_baudrate = 0;
  986         ifp->if_type = IFT_L2VLAN;
  987         ifp->if_hdrlen = ETHER_VLAN_ENCAP_LEN;
  988         ifa = ifp->if_addr;
  989         sdl = (struct sockaddr_dl *)ifa->ifa_addr;
  990         sdl->sdl_type = IFT_L2VLAN;
  991 
  992         if (p != NULL) {
  993                 error = vlan_config(ifv, p, vid);
  994                 if_rele(p);
  995                 if (error != 0) {
  996                         /*
  997                          * Since we've partially failed, we need to back
  998                          * out all the way, otherwise userland could get
  999                          * confused.  Thus, we destroy the interface.
 1000                          */
 1001                         ether_ifdetach(ifp);
 1002                         vlan_unconfig(ifp);
 1003                         if_free(ifp);
 1004                         ifc_free_unit(ifc, unit);
 1005                         free(ifv, M_VLAN);
 1006 
 1007                         return (error);
 1008                 }
 1009 
 1010                 /* Update flags on the parent, if necessary. */
 1011                 vlan_setflags(ifp, 1);
 1012         }
 1013 
 1014         return (0);
 1015 }
 1016 
 1017 static int
 1018 vlan_clone_destroy(struct if_clone *ifc, struct ifnet *ifp)
 1019 {
 1020         struct ifvlan *ifv = ifp->if_softc;
 1021         int unit = ifp->if_dunit;
 1022 
 1023         ether_ifdetach(ifp);    /* first, remove it from system-wide lists */
 1024         vlan_unconfig(ifp);     /* now it can be unconfigured and freed */
 1025         if_free(ifp);
 1026         free(ifv, M_VLAN);
 1027         ifc_free_unit(ifc, unit);
 1028 
 1029         return (0);
 1030 }
 1031 
 1032 /*
 1033  * The ifp->if_init entry point for vlan(4) is a no-op.
 1034  */
 1035 static void
 1036 vlan_init(void *foo __unused)
 1037 {
 1038 }
 1039 
 1040 /*
 1041  * The if_transmit method for vlan(4) interface.
 1042  */
 1043 static int
 1044 vlan_transmit(struct ifnet *ifp, struct mbuf *m)
 1045 {
 1046         struct ifvlan *ifv;
 1047         struct ifnet *p;
 1048         struct m_tag *mtag;
 1049         uint16_t tag;
 1050         int error, len, mcast;
 1051 
 1052         ifv = ifp->if_softc;
 1053         p = PARENT(ifv);
 1054         len = m->m_pkthdr.len;
 1055         mcast = (m->m_flags & (M_MCAST | M_BCAST)) ? 1 : 0;
 1056 
 1057         BPF_MTAP(ifp, m);
 1058 
 1059         /*
 1060          * Do not run parent's if_transmit() if the parent is not up,
 1061          * or parent's driver will cause a system crash.
 1062          */
 1063         if (!UP_AND_RUNNING(p)) {
 1064                 m_freem(m);
 1065                 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
 1066                 return (ENETDOWN);
 1067         }
 1068 
 1069         /*
 1070          * Pad the frame to the minimum size allowed if told to.
 1071          * This option is in accord with IEEE Std 802.1Q, 2003 Ed.,
 1072          * paragraph C.4.4.3.b.  It can help to work around buggy
 1073          * bridges that violate paragraph C.4.4.3.a from the same
 1074          * document, i.e., fail to pad short frames after untagging.
 1075          * E.g., a tagged frame 66 bytes long (incl. FCS) is OK, but
 1076          * untagging it will produce a 62-byte frame, which is a runt
 1077          * and requires padding.  There are VLAN-enabled network
 1078          * devices that just discard such runts instead or mishandle
 1079          * them somehow.
 1080          */
 1081         if (V_soft_pad && p->if_type == IFT_ETHER) {
 1082                 static char pad[8];     /* just zeros */
 1083                 int n;
 1084 
 1085                 for (n = ETHERMIN + ETHER_HDR_LEN - m->m_pkthdr.len;
 1086                      n > 0; n -= sizeof(pad))
 1087                         if (!m_append(m, min(n, sizeof(pad)), pad))
 1088                                 break;
 1089 
 1090                 if (n > 0) {
 1091                         if_printf(ifp, "cannot pad short frame\n");
 1092                         if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
 1093                         m_freem(m);
 1094                         return (0);
 1095                 }
 1096         }
 1097 
 1098         /*
 1099          * If underlying interface can do VLAN tag insertion itself,
 1100          * just pass the packet along. However, we need some way to
 1101          * tell the interface where the packet came from so that it
 1102          * knows how to find the VLAN tag to use, so we attach a
 1103          * packet tag that holds it.
 1104          */
 1105         if (vlan_mtag_pcp && (mtag = m_tag_locate(m, MTAG_8021Q,
 1106             MTAG_8021Q_PCP_OUT, NULL)) != NULL)
 1107                 tag = EVL_MAKETAG(ifv->ifv_vid, *(uint8_t *)(mtag + 1), 0);
 1108         else
 1109               tag = ifv->ifv_tag;
 1110         if (p->if_capenable & IFCAP_VLAN_HWTAGGING) {
 1111                 m->m_pkthdr.ether_vtag = tag;
 1112                 m->m_flags |= M_VLANTAG;
 1113         } else {
 1114                 m = ether_vlanencap(m, tag);
 1115                 if (m == NULL) {
 1116                         if_printf(ifp, "unable to prepend VLAN header\n");
 1117                         if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
 1118                         return (0);
 1119                 }
 1120         }
 1121 
 1122         /*
 1123          * Send it, precisely as ether_output() would have.
 1124          */
 1125         error = (p->if_transmit)(p, m);
 1126         if (error == 0) {
 1127                 if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
 1128                 if_inc_counter(ifp, IFCOUNTER_OBYTES, len);
 1129                 if_inc_counter(ifp, IFCOUNTER_OMCASTS, mcast);
 1130         } else
 1131                 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
 1132         return (error);
 1133 }
 1134 
 1135 /*
 1136  * The ifp->if_qflush entry point for vlan(4) is a no-op.
 1137  */
 1138 static void
 1139 vlan_qflush(struct ifnet *ifp __unused)
 1140 {
 1141 }
 1142 
 1143 static void
 1144 vlan_input(struct ifnet *ifp, struct mbuf *m)
 1145 {
 1146         struct ifvlantrunk *trunk = ifp->if_vlantrunk;
 1147         struct ifvlan *ifv;
 1148         TRUNK_LOCK_READER;
 1149         struct m_tag *mtag;
 1150         uint16_t vid, tag;
 1151 
 1152         KASSERT(trunk != NULL, ("%s: no trunk", __func__));
 1153 
 1154         if (m->m_flags & M_VLANTAG) {
 1155                 /*
 1156                  * Packet is tagged, but m contains a normal
 1157                  * Ethernet frame; the tag is stored out-of-band.
 1158                  */
 1159                 tag = m->m_pkthdr.ether_vtag;
 1160                 m->m_flags &= ~M_VLANTAG;
 1161         } else {
 1162                 struct ether_vlan_header *evl;
 1163 
 1164                 /*
 1165                  * Packet is tagged in-band as specified by 802.1q.
 1166                  */
 1167                 switch (ifp->if_type) {
 1168                 case IFT_ETHER:
 1169                         if (m->m_len < sizeof(*evl) &&
 1170                             (m = m_pullup(m, sizeof(*evl))) == NULL) {
 1171                                 if_printf(ifp, "cannot pullup VLAN header\n");
 1172                                 return;
 1173                         }
 1174                         evl = mtod(m, struct ether_vlan_header *);
 1175                         tag = ntohs(evl->evl_tag);
 1176 
 1177                         /*
 1178                          * Remove the 802.1q header by copying the Ethernet
 1179                          * addresses over it and adjusting the beginning of
 1180                          * the data in the mbuf.  The encapsulated Ethernet
 1181                          * type field is already in place.
 1182                          */
 1183                         bcopy((char *)evl, (char *)evl + ETHER_VLAN_ENCAP_LEN,
 1184                               ETHER_HDR_LEN - ETHER_TYPE_LEN);
 1185                         m_adj(m, ETHER_VLAN_ENCAP_LEN);
 1186                         break;
 1187 
 1188                 default:
 1189 #ifdef INVARIANTS
 1190                         panic("%s: %s has unsupported if_type %u",
 1191                               __func__, ifp->if_xname, ifp->if_type);
 1192 #endif
 1193                         m_freem(m);
 1194                         if_inc_counter(ifp, IFCOUNTER_NOPROTO, 1);
 1195                         return;
 1196                 }
 1197         }
 1198 
 1199         vid = EVL_VLANOFTAG(tag);
 1200 
 1201         TRUNK_RLOCK(trunk);
 1202         ifv = vlan_gethash(trunk, vid);
 1203         if (ifv == NULL || !UP_AND_RUNNING(ifv->ifv_ifp)) {
 1204                 TRUNK_RUNLOCK(trunk);
 1205                 m_freem(m);
 1206                 if_inc_counter(ifp, IFCOUNTER_NOPROTO, 1);
 1207                 return;
 1208         }
 1209         TRUNK_RUNLOCK(trunk);
 1210 
 1211         if (vlan_mtag_pcp) {
 1212                 /*
 1213                  * While uncommon, it is possible that we will find a 802.1q
 1214                  * packet encapsulated inside another packet that also had an
 1215                  * 802.1q header.  For example, ethernet tunneled over IPSEC
 1216                  * arriving over ethernet.  In that case, we replace the
 1217                  * existing 802.1q PCP m_tag value.
 1218                  */
 1219                 mtag = m_tag_locate(m, MTAG_8021Q, MTAG_8021Q_PCP_IN, NULL);
 1220                 if (mtag == NULL) {
 1221                         mtag = m_tag_alloc(MTAG_8021Q, MTAG_8021Q_PCP_IN,
 1222                             sizeof(uint8_t), M_NOWAIT);
 1223                         if (mtag == NULL) {
 1224                                 m_freem(m);
 1225                                 if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
 1226                                 return;
 1227                         }
 1228                         m_tag_prepend(m, mtag);
 1229                 }
 1230                 *(uint8_t *)(mtag + 1) = EVL_PRIOFTAG(tag);
 1231         }
 1232 
 1233         m->m_pkthdr.rcvif = ifv->ifv_ifp;
 1234         if_inc_counter(ifv->ifv_ifp, IFCOUNTER_IPACKETS, 1);
 1235 
 1236         /* Pass it back through the parent's input routine. */
 1237         (*ifp->if_input)(ifv->ifv_ifp, m);
 1238 }
 1239 
 1240 static int
 1241 vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t vid)
 1242 {
 1243         struct ifvlantrunk *trunk;
 1244         struct ifnet *ifp;
 1245         int error = 0;
 1246 
 1247         /*
 1248          * We can handle non-ethernet hardware types as long as
 1249          * they handle the tagging and headers themselves.
 1250          */
 1251         if (p->if_type != IFT_ETHER &&
 1252             (p->if_capenable & IFCAP_VLAN_HWTAGGING) == 0)
 1253                 return (EPROTONOSUPPORT);
 1254         if ((p->if_flags & VLAN_IFFLAGS) != VLAN_IFFLAGS)
 1255                 return (EPROTONOSUPPORT);
 1256         /*
 1257          * Don't let the caller set up a VLAN VID with
 1258          * anything except VLID bits.
 1259          * VID numbers 0x0 and 0xFFF are reserved.
 1260          */
 1261         if (vid == 0 || vid == 0xFFF || (vid & ~EVL_VLID_MASK))
 1262                 return (EINVAL);
 1263         if (ifv->ifv_trunk)
 1264                 return (EBUSY);
 1265 
 1266         if (p->if_vlantrunk == NULL) {
 1267                 trunk = malloc(sizeof(struct ifvlantrunk),
 1268                     M_VLAN, M_WAITOK | M_ZERO);
 1269                 vlan_inithash(trunk);
 1270                 VLAN_LOCK();
 1271                 if (p->if_vlantrunk != NULL) {
 1272                         /* A race that is very unlikely to be hit. */
 1273                         vlan_freehash(trunk);
 1274                         free(trunk, M_VLAN);
 1275                         goto exists;
 1276                 }
 1277                 TRUNK_LOCK_INIT(trunk);
 1278                 TRUNK_LOCK(trunk);
 1279                 p->if_vlantrunk = trunk;
 1280                 trunk->parent = p;
 1281                 if_ref(trunk->parent);
 1282         } else {
 1283                 VLAN_LOCK();
 1284 exists:
 1285                 trunk = p->if_vlantrunk;
 1286                 TRUNK_LOCK(trunk);
 1287         }
 1288 
 1289         ifv->ifv_vid = vid;     /* must set this before vlan_inshash() */
 1290         ifv->ifv_pcp = 0;       /* Default: best effort delivery. */
 1291         vlan_tag_recalculate(ifv);
 1292         error = vlan_inshash(trunk, ifv);
 1293         if (error)
 1294                 goto done;
 1295         ifv->ifv_proto = ETHERTYPE_VLAN;
 1296         ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN;
 1297         ifv->ifv_mintu = ETHERMIN;
 1298         ifv->ifv_pflags = 0;
 1299         ifv->ifv_capenable = -1;
 1300 
 1301         /*
 1302          * If the parent supports the VLAN_MTU capability,
 1303          * i.e. can Tx/Rx larger than ETHER_MAX_LEN frames,
 1304          * use it.
 1305          */
 1306         if (p->if_capenable & IFCAP_VLAN_MTU) {
 1307                 /*
 1308                  * No need to fudge the MTU since the parent can
 1309                  * handle extended frames.
 1310                  */
 1311                 ifv->ifv_mtufudge = 0;
 1312         } else {
 1313                 /*
 1314                  * Fudge the MTU by the encapsulation size.  This
 1315                  * makes us incompatible with strictly compliant
 1316                  * 802.1Q implementations, but allows us to use
 1317                  * the feature with other NetBSD implementations,
 1318                  * which might still be useful.
 1319                  */
 1320                 ifv->ifv_mtufudge = ifv->ifv_encaplen;
 1321         }
 1322 
 1323         ifv->ifv_trunk = trunk;
 1324         ifp = ifv->ifv_ifp;
 1325         /*
 1326          * Initialize fields from our parent.  This duplicates some
 1327          * work with ether_ifattach() but allows for non-ethernet
 1328          * interfaces to also work.
 1329          */
 1330         ifp->if_mtu = p->if_mtu - ifv->ifv_mtufudge;
 1331         ifp->if_baudrate = p->if_baudrate;
 1332         ifp->if_output = p->if_output;
 1333         ifp->if_input = p->if_input;
 1334         ifp->if_resolvemulti = p->if_resolvemulti;
 1335         ifp->if_addrlen = p->if_addrlen;
 1336         ifp->if_broadcastaddr = p->if_broadcastaddr;
 1337 
 1338         /*
 1339          * Copy only a selected subset of flags from the parent.
 1340          * Other flags are none of our business.
 1341          */
 1342 #define VLAN_COPY_FLAGS (IFF_SIMPLEX)
 1343         ifp->if_flags &= ~VLAN_COPY_FLAGS;
 1344         ifp->if_flags |= p->if_flags & VLAN_COPY_FLAGS;
 1345 #undef VLAN_COPY_FLAGS
 1346 
 1347         ifp->if_link_state = p->if_link_state;
 1348 
 1349         vlan_capabilities(ifv);
 1350 
 1351         /*
 1352          * Set up our interface address to reflect the underlying
 1353          * physical interface's.
 1354          */
 1355         bcopy(IF_LLADDR(p), IF_LLADDR(ifp), p->if_addrlen);
 1356         ((struct sockaddr_dl *)ifp->if_addr->ifa_addr)->sdl_alen =
 1357             p->if_addrlen;
 1358 
 1359         /*
 1360          * Configure multicast addresses that may already be
 1361          * joined on the vlan device.
 1362          */
 1363         (void)vlan_setmulti(ifp); /* XXX: VLAN lock held */
 1364 
 1365         /* We are ready for operation now. */
 1366         ifp->if_drv_flags |= IFF_DRV_RUNNING;
 1367 done:
 1368         TRUNK_UNLOCK(trunk);
 1369         if (error == 0)
 1370                 EVENTHANDLER_INVOKE(vlan_config, p, ifv->ifv_vid);
 1371         VLAN_UNLOCK();
 1372 
 1373         return (error);
 1374 }
 1375 
 1376 static void
 1377 vlan_unconfig(struct ifnet *ifp)
 1378 {
 1379 
 1380         VLAN_LOCK();
 1381         vlan_unconfig_locked(ifp, 0);
 1382         VLAN_UNLOCK();
 1383 }
 1384 
 1385 static void
 1386 vlan_unconfig_locked(struct ifnet *ifp, int departing)
 1387 {
 1388         struct ifvlantrunk *trunk;
 1389         struct vlan_mc_entry *mc;
 1390         struct ifvlan *ifv;
 1391         struct ifnet  *parent;
 1392         int error;
 1393 
 1394         VLAN_LOCK_ASSERT();
 1395 
 1396         ifv = ifp->if_softc;
 1397         trunk = ifv->ifv_trunk;
 1398         parent = NULL;
 1399 
 1400         if (trunk != NULL) {
 1401 
 1402                 TRUNK_LOCK(trunk);
 1403                 parent = trunk->parent;
 1404 
 1405                 /*
 1406                  * Since the interface is being unconfigured, we need to
 1407                  * empty the list of multicast groups that we may have joined
 1408                  * while we were alive from the parent's list.
 1409                  */
 1410                 while ((mc = SLIST_FIRST(&ifv->vlan_mc_listhead)) != NULL) {
 1411                         /*
 1412                          * If the parent interface is being detached,
 1413                          * all its multicast addresses have already
 1414                          * been removed.  Warn about errors if
 1415                          * if_delmulti() does fail, but don't abort as
 1416                          * all callers expect vlan destruction to
 1417                          * succeed.
 1418                          */
 1419                         if (!departing) {
 1420                                 error = if_delmulti(parent,
 1421                                     (struct sockaddr *)&mc->mc_addr);
 1422                                 if (error)
 1423                                         if_printf(ifp,
 1424                     "Failed to delete multicast address from parent: %d\n",
 1425                                             error);
 1426                         }
 1427                         SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries);
 1428                         free(mc, M_VLAN);
 1429                 }
 1430 
 1431                 vlan_setflags(ifp, 0); /* clear special flags on parent */
 1432                 vlan_remhash(trunk, ifv);
 1433                 ifv->ifv_trunk = NULL;
 1434 
 1435                 /*
 1436                  * Check if we were the last.
 1437                  */
 1438                 if (trunk->refcnt == 0) {
 1439                         parent->if_vlantrunk = NULL;
 1440                         /*
 1441                          * XXXGL: If some ithread has already entered
 1442                          * vlan_input() and is now blocked on the trunk
 1443                          * lock, then it should preempt us right after
 1444                          * unlock and finish its work. Then we will acquire
 1445                          * lock again in trunk_destroy().
 1446                          */
 1447                         TRUNK_UNLOCK(trunk);
 1448                         trunk_destroy(trunk);
 1449                 } else
 1450                         TRUNK_UNLOCK(trunk);
 1451         }
 1452 
 1453         /* Disconnect from parent. */
 1454         if (ifv->ifv_pflags)
 1455                 if_printf(ifp, "%s: ifv_pflags unclean\n", __func__);
 1456         ifp->if_mtu = ETHERMTU;
 1457         ifp->if_link_state = LINK_STATE_UNKNOWN;
 1458         ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
 1459 
 1460         /*
 1461          * Only dispatch an event if vlan was
 1462          * attached, otherwise there is nothing
 1463          * to cleanup anyway.
 1464          */
 1465         if (parent != NULL)
 1466                 EVENTHANDLER_INVOKE(vlan_unconfig, parent, ifv->ifv_vid);
 1467 }
 1468 
 1469 /* Handle a reference counted flag that should be set on the parent as well */
 1470 static int
 1471 vlan_setflag(struct ifnet *ifp, int flag, int status,
 1472              int (*func)(struct ifnet *, int))
 1473 {
 1474         struct ifvlan *ifv;
 1475         int error;
 1476 
 1477         /* XXX VLAN_LOCK_ASSERT(); */
 1478 
 1479         ifv = ifp->if_softc;
 1480         status = status ? (ifp->if_flags & flag) : 0;
 1481         /* Now "status" contains the flag value or 0 */
 1482 
 1483         /*
 1484          * See if recorded parent's status is different from what
 1485          * we want it to be.  If it is, flip it.  We record parent's
 1486          * status in ifv_pflags so that we won't clear parent's flag
 1487          * we haven't set.  In fact, we don't clear or set parent's
 1488          * flags directly, but get or release references to them.
 1489          * That's why we can be sure that recorded flags still are
 1490          * in accord with actual parent's flags.
 1491          */
 1492         if (status != (ifv->ifv_pflags & flag)) {
 1493                 error = (*func)(PARENT(ifv), status);
 1494                 if (error)
 1495                         return (error);
 1496                 ifv->ifv_pflags &= ~flag;
 1497                 ifv->ifv_pflags |= status;
 1498         }
 1499         return (0);
 1500 }
 1501 
 1502 /*
 1503  * Handle IFF_* flags that require certain changes on the parent:
 1504  * if "status" is true, update parent's flags respective to our if_flags;
 1505  * if "status" is false, forcedly clear the flags set on parent.
 1506  */
 1507 static int
 1508 vlan_setflags(struct ifnet *ifp, int status)
 1509 {
 1510         int error, i;
 1511         
 1512         for (i = 0; vlan_pflags[i].flag; i++) {
 1513                 error = vlan_setflag(ifp, vlan_pflags[i].flag,
 1514                                      status, vlan_pflags[i].func);
 1515                 if (error)
 1516                         return (error);
 1517         }
 1518         return (0);
 1519 }
 1520 
 1521 /* Inform all vlans that their parent has changed link state */
 1522 static void
 1523 vlan_link_state(struct ifnet *ifp)
 1524 {
 1525         struct ifvlantrunk *trunk = ifp->if_vlantrunk;
 1526         struct ifvlan *ifv;
 1527         int i;
 1528 
 1529         TRUNK_LOCK(trunk);
 1530 #ifdef VLAN_ARRAY
 1531         for (i = 0; i < VLAN_ARRAY_SIZE; i++)
 1532                 if (trunk->vlans[i] != NULL) {
 1533                         ifv = trunk->vlans[i];
 1534 #else
 1535         for (i = 0; i < (1 << trunk->hwidth); i++)
 1536                 LIST_FOREACH(ifv, &trunk->hash[i], ifv_list) {
 1537 #endif
 1538                         ifv->ifv_ifp->if_baudrate = trunk->parent->if_baudrate;
 1539                         if_link_state_change(ifv->ifv_ifp,
 1540                             trunk->parent->if_link_state);
 1541                 }
 1542         TRUNK_UNLOCK(trunk);
 1543 }
 1544 
 1545 static void
 1546 vlan_capabilities(struct ifvlan *ifv)
 1547 {
 1548         struct ifnet *p = PARENT(ifv);
 1549         struct ifnet *ifp = ifv->ifv_ifp;
 1550         struct ifnet_hw_tsomax hw_tsomax;
 1551         int cap = 0, ena = 0, mena;
 1552         u_long hwa = 0;
 1553 
 1554         TRUNK_LOCK_ASSERT(TRUNK(ifv));
 1555 
 1556         /* Mask parent interface enabled capabilities disabled by user. */
 1557         mena = p->if_capenable & ifv->ifv_capenable;
 1558 
 1559         /*
 1560          * If the parent interface can do checksum offloading
 1561          * on VLANs, then propagate its hardware-assisted
 1562          * checksumming flags. Also assert that checksum
 1563          * offloading requires hardware VLAN tagging.
 1564          */
 1565         if (p->if_capabilities & IFCAP_VLAN_HWCSUM)
 1566                 cap |= p->if_capabilities & (IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6);
 1567         if (p->if_capenable & IFCAP_VLAN_HWCSUM &&
 1568             p->if_capenable & IFCAP_VLAN_HWTAGGING) {
 1569                 ena |= mena & (IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6);
 1570                 if (ena & IFCAP_TXCSUM)
 1571                         hwa |= p->if_hwassist & (CSUM_IP | CSUM_TCP |
 1572                             CSUM_UDP | CSUM_SCTP);
 1573                 if (ena & IFCAP_TXCSUM_IPV6)
 1574                         hwa |= p->if_hwassist & (CSUM_TCP_IPV6 |
 1575                             CSUM_UDP_IPV6 | CSUM_SCTP_IPV6);
 1576         }
 1577 
 1578         /*
 1579          * If the parent interface can do TSO on VLANs then
 1580          * propagate the hardware-assisted flag. TSO on VLANs
 1581          * does not necessarily require hardware VLAN tagging.
 1582          */
 1583         memset(&hw_tsomax, 0, sizeof(hw_tsomax));
 1584         if_hw_tsomax_common(p, &hw_tsomax);
 1585         if_hw_tsomax_update(ifp, &hw_tsomax);
 1586         if (p->if_capabilities & IFCAP_VLAN_HWTSO)
 1587                 cap |= p->if_capabilities & IFCAP_TSO;
 1588         if (p->if_capenable & IFCAP_VLAN_HWTSO) {
 1589                 ena |= mena & IFCAP_TSO;
 1590                 if (ena & IFCAP_TSO)
 1591                         hwa |= p->if_hwassist & CSUM_TSO;
 1592         }
 1593 
 1594         /*
 1595          * If the parent interface can do LRO and checksum offloading on
 1596          * VLANs, then guess it may do LRO on VLANs.  False positive here
 1597          * cost nothing, while false negative may lead to some confusions.
 1598          */
 1599         if (p->if_capabilities & IFCAP_VLAN_HWCSUM)
 1600                 cap |= p->if_capabilities & IFCAP_LRO;
 1601         if (p->if_capenable & IFCAP_VLAN_HWCSUM)
 1602                 ena |= p->if_capenable & IFCAP_LRO;
 1603 
 1604         /*
 1605          * If the parent interface can offload TCP connections over VLANs then
 1606          * propagate its TOE capability to the VLAN interface.
 1607          *
 1608          * All TOE drivers in the tree today can deal with VLANs.  If this
 1609          * changes then IFCAP_VLAN_TOE should be promoted to a full capability
 1610          * with its own bit.
 1611          */
 1612 #define IFCAP_VLAN_TOE IFCAP_TOE
 1613         if (p->if_capabilities & IFCAP_VLAN_TOE)
 1614                 cap |= p->if_capabilities & IFCAP_TOE;
 1615         if (p->if_capenable & IFCAP_VLAN_TOE) {
 1616                 TOEDEV(ifp) = TOEDEV(p);
 1617                 ena |= mena & IFCAP_TOE;
 1618         }
 1619 
 1620         /*
 1621          * If the parent interface supports dynamic link state, so does the
 1622          * VLAN interface.
 1623          */
 1624         cap |= (p->if_capabilities & IFCAP_LINKSTATE);
 1625         ena |= (mena & IFCAP_LINKSTATE);
 1626 
 1627         ifp->if_capabilities = cap;
 1628         ifp->if_capenable = ena;
 1629         ifp->if_hwassist = hwa;
 1630 }
 1631 
 1632 static void
 1633 vlan_trunk_capabilities(struct ifnet *ifp)
 1634 {
 1635         struct ifvlantrunk *trunk = ifp->if_vlantrunk;
 1636         struct ifvlan *ifv;
 1637         int i;
 1638 
 1639         TRUNK_LOCK(trunk);
 1640 #ifdef VLAN_ARRAY
 1641         for (i = 0; i < VLAN_ARRAY_SIZE; i++)
 1642                 if (trunk->vlans[i] != NULL) {
 1643                         ifv = trunk->vlans[i];
 1644 #else
 1645         for (i = 0; i < (1 << trunk->hwidth); i++) {
 1646                 LIST_FOREACH(ifv, &trunk->hash[i], ifv_list)
 1647 #endif
 1648                         vlan_capabilities(ifv);
 1649         }
 1650         TRUNK_UNLOCK(trunk);
 1651 }
 1652 
 1653 static int
 1654 vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 1655 {
 1656         struct ifnet *p;
 1657         struct ifreq *ifr;
 1658         struct ifaddr *ifa;
 1659         struct ifvlan *ifv;
 1660         struct ifvlantrunk *trunk;
 1661         struct vlanreq vlr;
 1662         int error = 0;
 1663 
 1664         ifr = (struct ifreq *)data;
 1665         ifa = (struct ifaddr *) data;
 1666         ifv = ifp->if_softc;
 1667 
 1668         switch (cmd) {
 1669         case SIOCSIFADDR:
 1670                 ifp->if_flags |= IFF_UP;
 1671 #ifdef INET
 1672                 if (ifa->ifa_addr->sa_family == AF_INET)
 1673                         arp_ifinit(ifp, ifa);
 1674 #endif
 1675                 break;
 1676         case SIOCGIFADDR:
 1677                 {
 1678                         struct sockaddr *sa;
 1679 
 1680                         sa = (struct sockaddr *)&ifr->ifr_data;
 1681                         bcopy(IF_LLADDR(ifp), sa->sa_data, ifp->if_addrlen);
 1682                 }
 1683                 break;
 1684         case SIOCGIFMEDIA:
 1685                 VLAN_LOCK();
 1686                 if (TRUNK(ifv) != NULL) {
 1687                         p = PARENT(ifv);
 1688                         if_ref(p);
 1689                         VLAN_UNLOCK();
 1690                         error = (*p->if_ioctl)(p, SIOCGIFMEDIA, data);
 1691                         if_rele(p);
 1692                         /* Limit the result to the parent's current config. */
 1693                         if (error == 0) {
 1694                                 struct ifmediareq *ifmr;
 1695 
 1696                                 ifmr = (struct ifmediareq *)data;
 1697                                 if (ifmr->ifm_count >= 1 && ifmr->ifm_ulist) {
 1698                                         ifmr->ifm_count = 1;
 1699                                         error = copyout(&ifmr->ifm_current,
 1700                                                 ifmr->ifm_ulist,
 1701                                                 sizeof(int));
 1702                                 }
 1703                         }
 1704                 } else {
 1705                         VLAN_UNLOCK();
 1706                         error = EINVAL;
 1707                 }
 1708                 break;
 1709 
 1710         case SIOCSIFMEDIA:
 1711                 error = EINVAL;
 1712                 break;
 1713 
 1714         case SIOCSIFMTU:
 1715                 /*
 1716                  * Set the interface MTU.
 1717                  */
 1718                 VLAN_LOCK();
 1719                 if (TRUNK(ifv) != NULL) {
 1720                         if (ifr->ifr_mtu >
 1721                              (PARENT(ifv)->if_mtu - ifv->ifv_mtufudge) ||
 1722                             ifr->ifr_mtu <
 1723                              (ifv->ifv_mintu - ifv->ifv_mtufudge))
 1724                                 error = EINVAL;
 1725                         else
 1726                                 ifp->if_mtu = ifr->ifr_mtu;
 1727                 } else
 1728                         error = EINVAL;
 1729                 VLAN_UNLOCK();
 1730                 break;
 1731 
 1732         case SIOCSETVLAN:
 1733 #ifdef VIMAGE
 1734                 /*
 1735                  * XXXRW/XXXBZ: The goal in these checks is to allow a VLAN
 1736                  * interface to be delegated to a jail without allowing the
 1737                  * jail to change what underlying interface/VID it is
 1738                  * associated with.  We are not entirely convinced that this
 1739                  * is the right way to accomplish that policy goal.
 1740                  */
 1741                 if (ifp->if_vnet != ifp->if_home_vnet) {
 1742                         error = EPERM;
 1743                         break;
 1744                 }
 1745 #endif
 1746                 error = copyin(ifr->ifr_data, &vlr, sizeof(vlr));
 1747                 if (error)
 1748                         break;
 1749                 if (vlr.vlr_parent[0] == '\0') {
 1750                         vlan_unconfig(ifp);
 1751                         break;
 1752                 }
 1753                 p = ifunit_ref(vlr.vlr_parent);
 1754                 if (p == NULL) {
 1755                         error = ENOENT;
 1756                         break;
 1757                 }
 1758                 error = vlan_config(ifv, p, vlr.vlr_tag);
 1759                 if_rele(p);
 1760                 if (error)
 1761                         break;
 1762 
 1763                 /* Update flags on the parent, if necessary. */
 1764                 vlan_setflags(ifp, 1);
 1765                 break;
 1766 
 1767         case SIOCGETVLAN:
 1768 #ifdef VIMAGE
 1769                 if (ifp->if_vnet != ifp->if_home_vnet) {
 1770                         error = EPERM;
 1771                         break;
 1772                 }
 1773 #endif
 1774                 bzero(&vlr, sizeof(vlr));
 1775                 VLAN_LOCK();
 1776                 if (TRUNK(ifv) != NULL) {
 1777                         strlcpy(vlr.vlr_parent, PARENT(ifv)->if_xname,
 1778                             sizeof(vlr.vlr_parent));
 1779                         vlr.vlr_tag = ifv->ifv_vid;
 1780                 }
 1781                 VLAN_UNLOCK();
 1782                 error = copyout(&vlr, ifr->ifr_data, sizeof(vlr));
 1783                 break;
 1784                 
 1785         case SIOCSIFFLAGS:
 1786                 /*
 1787                  * We should propagate selected flags to the parent,
 1788                  * e.g., promiscuous mode.
 1789                  */
 1790                 if (TRUNK(ifv) != NULL)
 1791                         error = vlan_setflags(ifp, 1);
 1792                 break;
 1793 
 1794         case SIOCADDMULTI:
 1795         case SIOCDELMULTI:
 1796                 /*
 1797                  * If we don't have a parent, just remember the membership for
 1798                  * when we do.
 1799                  */
 1800                 trunk = TRUNK(ifv);
 1801                 if (trunk != NULL) {
 1802                         TRUNK_LOCK(trunk);
 1803                         error = vlan_setmulti(ifp);
 1804                         TRUNK_UNLOCK(trunk);
 1805                 }
 1806                 break;
 1807 
 1808         case SIOCGVLANPCP:
 1809 #ifdef VIMAGE
 1810                 if (ifp->if_vnet != ifp->if_home_vnet) {
 1811                         error = EPERM;
 1812                         break;
 1813                 }
 1814 #endif
 1815                 ifr->ifr_vlan_pcp = ifv->ifv_pcp;
 1816                 break;
 1817 
 1818         case SIOCSVLANPCP:
 1819 #ifdef VIMAGE
 1820                 if (ifp->if_vnet != ifp->if_home_vnet) {
 1821                         error = EPERM;
 1822                         break;
 1823                 }
 1824 #endif
 1825                 error = priv_check(curthread, PRIV_NET_SETVLANPCP);
 1826                 if (error)
 1827                         break;
 1828                 if (ifr->ifr_vlan_pcp > 7) {
 1829                         error = EINVAL;
 1830                         break;
 1831                 }
 1832                 ifv->ifv_pcp = ifr->ifr_vlan_pcp;
 1833                 vlan_tag_recalculate(ifv);
 1834                 break;
 1835 
 1836         case SIOCSIFCAP:
 1837                 VLAN_LOCK();
 1838                 ifv->ifv_capenable = ifr->ifr_reqcap;
 1839                 trunk = TRUNK(ifv);
 1840                 if (trunk != NULL) {
 1841                         TRUNK_LOCK(trunk);
 1842                         vlan_capabilities(ifv);
 1843                         TRUNK_UNLOCK(trunk);
 1844                 }
 1845                 VLAN_UNLOCK();
 1846                 break;
 1847 
 1848         default:
 1849                 error = EINVAL;
 1850                 break;
 1851         }
 1852 
 1853         return (error);
 1854 }

Cache object: 7429dde31137396669b870821c07c8d8


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