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: releng/6.3/sys/net/if_vlan.c 173886 2007-11-24 19:45:58Z cvs2svn $
   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 MODULE_DEPEND(if_vlan, miibus, 1, 1, 1);
  319 
  320 static struct ifnet *
  321 vlan_clone_match_ethertag(struct if_clone *ifc, const char *name, int *tag)
  322 {
  323         const char *cp;
  324         struct ifnet *ifp;
  325         int t = 0;
  326 
  327         /* Check for <etherif>.<vlan> style interface names. */
  328         IFNET_RLOCK();
  329         TAILQ_FOREACH(ifp, &ifnet, if_link) {
  330                 if (ifp->if_type != IFT_ETHER)
  331                         continue;
  332                 if (strncmp(ifp->if_xname, name, strlen(ifp->if_xname)) != 0)
  333                         continue;
  334                 cp = name + strlen(ifp->if_xname);
  335                 if (*cp != '.')
  336                         continue;
  337                 for(; *cp != '\0'; cp++) {
  338                         if (*cp < '' || *cp > '9')
  339                                 continue;
  340                         t = (t * 10) + (*cp - '');
  341                 }
  342                 if (tag != NULL)
  343                         *tag = t;
  344                 break;
  345         }
  346         IFNET_RUNLOCK();
  347 
  348         return (ifp);
  349 }
  350 
  351 static int
  352 vlan_clone_match(struct if_clone *ifc, const char *name)
  353 {
  354         const char *cp;
  355 
  356         if (vlan_clone_match_ethertag(ifc, name, NULL) != NULL)
  357                 return (1);
  358 
  359         if (strncmp(VLANNAME, name, strlen(VLANNAME)) != 0)
  360                 return (0);
  361         for (cp = name + 4; *cp != '\0'; cp++) {
  362                 if (*cp < '' || *cp > '9')
  363                         return (0);
  364         }
  365 
  366         return (1);
  367 }
  368 
  369 static int
  370 vlan_clone_create(struct if_clone *ifc, char *name, size_t len)
  371 {
  372         char *dp;
  373         int wildcard;
  374         int unit;
  375         int error;
  376         int tag;
  377         int ethertag;
  378         struct ifvlan *ifv;
  379         struct ifnet *ifp;
  380         struct ifnet *p;
  381         u_char eaddr[6] = {0,0,0,0,0,0};
  382 
  383         if ((p = vlan_clone_match_ethertag(ifc, name, &tag)) != NULL) {
  384                 ethertag = 1;
  385                 unit = -1;
  386                 wildcard = 0;
  387 
  388                 /*
  389                  * Don't let the caller set up a VLAN tag with
  390                  * anything except VLID bits.
  391                  */
  392                 if (tag & ~EVL_VLID_MASK)
  393                         return (EINVAL);
  394         } else {
  395                 ethertag = 0;
  396 
  397                 error = ifc_name2unit(name, &unit);
  398                 if (error != 0)
  399                         return (error);
  400 
  401                 wildcard = (unit < 0);
  402         }
  403 
  404         error = ifc_alloc_unit(ifc, &unit);
  405         if (error != 0)
  406                 return (error);
  407 
  408         /* In the wildcard case, we need to update the name. */
  409         if (wildcard) {
  410                 for (dp = name; *dp != '\0'; dp++);
  411                 if (snprintf(dp, len - (dp-name), "%d", unit) >
  412                     len - (dp-name) - 1) {
  413                         panic("%s: interface name too long", __func__);
  414                 }
  415         }
  416 
  417         ifv = malloc(sizeof(struct ifvlan), M_VLAN, M_WAITOK | M_ZERO);
  418         ifp = ifv->ifv_ifp = if_alloc(IFT_ETHER);
  419         if (ifp == NULL) {
  420                 ifc_free_unit(ifc, unit);
  421                 free(ifv, M_VLAN);
  422                 return (ENOSPC);
  423         }
  424         SLIST_INIT(&ifv->vlan_mc_listhead);
  425 
  426         ifp->if_softc = ifv;
  427         /*
  428          * Set the name manually rather than using if_initname because
  429          * we don't conform to the default naming convention for interfaces.
  430          */
  431         strlcpy(ifp->if_xname, name, IFNAMSIZ);
  432         ifp->if_dname = ifc->ifc_name;
  433         ifp->if_dunit = unit;
  434         /* NB: flags are not set here */
  435         ifp->if_linkmib = &ifv->ifv_mib;
  436         ifp->if_linkmiblen = sizeof(ifv->ifv_mib);
  437         /* NB: mtu is not set here */
  438 
  439         ifp->if_init = vlan_ifinit;
  440         ifp->if_start = vlan_start;
  441         ifp->if_ioctl = vlan_ioctl;
  442         ifp->if_snd.ifq_maxlen = ifqmaxlen;
  443         ifp->if_flags = VLAN_IFFLAGS;
  444         ether_ifattach(ifp, eaddr);
  445         /* Now undo some of the damage... */
  446         ifp->if_baudrate = 0;
  447         ifp->if_type = IFT_L2VLAN;
  448         ifp->if_hdrlen = ETHER_VLAN_ENCAP_LEN;
  449 
  450         VLAN_LOCK();
  451         LIST_INSERT_HEAD(&ifv_list, ifv, ifv_list);
  452         VLAN_UNLOCK();
  453 
  454         if (ethertag) {
  455                 VLAN_LOCK();
  456                 error = vlan_config(ifv, p);
  457                 if (error != 0) {
  458                         /*
  459                          * Since we've partialy failed, we need to back
  460                          * out all the way, otherwise userland could get
  461                          * confused.  Thus, we destroy the interface.
  462                          */
  463                         LIST_REMOVE(ifv, ifv_list);
  464                         vlan_unconfig(ifp);
  465                         VLAN_UNLOCK();
  466                         ether_ifdetach(ifp);
  467                         if_free_type(ifp, IFT_ETHER);
  468                         free(ifv, M_VLAN);
  469 
  470                         return (error);
  471                 }
  472                 ifv->ifv_tag = tag;
  473                 ifp->if_drv_flags |= IFF_DRV_RUNNING;
  474                 VLAN_UNLOCK();
  475 
  476                 /* Update flags on the parent, if necessary. */
  477                 vlan_setflags(ifp, 1);
  478         }
  479 
  480         return (0);
  481 }
  482 
  483 static int
  484 vlan_clone_destroy(struct if_clone *ifc, struct ifnet *ifp)
  485 {
  486         int unit;
  487         struct ifvlan *ifv = ifp->if_softc;
  488 
  489         unit = ifp->if_dunit;
  490 
  491         VLAN_LOCK();
  492         LIST_REMOVE(ifv, ifv_list);
  493         vlan_unconfig(ifp);
  494         VLAN_UNLOCK();
  495 
  496         ether_ifdetach(ifp);
  497         if_free_type(ifp, IFT_ETHER);
  498 
  499         free(ifv, M_VLAN);
  500 
  501         ifc_free_unit(ifc, unit);
  502 
  503         return (0);
  504 }
  505 
  506 /*
  507  * The ifp->if_init entry point for vlan(4) is a no-op.
  508  */
  509 static void
  510 vlan_ifinit(void *foo)
  511 {
  512 
  513 }
  514 
  515 /*
  516  * The if_start method for vlan(4) interface. It doesn't
  517  * raises the IFF_DRV_OACTIVE flag, since it is called
  518  * only from IFQ_HANDOFF() macro in ether_output_frame().
  519  * If the interface queue is full, and vlan_start() is
  520  * not called, the queue would never get emptied and
  521  * interface would stall forever.
  522  */
  523 static void
  524 vlan_start(struct ifnet *ifp)
  525 {
  526         struct ifvlan *ifv;
  527         struct ifnet *p;
  528         struct ether_vlan_header *evl;
  529         struct mbuf *m;
  530         int error;
  531 
  532         ifv = ifp->if_softc;
  533         p = ifv->ifv_p;
  534 
  535         for (;;) {
  536                 IF_DEQUEUE(&ifp->if_snd, m);
  537                 if (m == 0)
  538                         break;
  539                 BPF_MTAP(ifp, m);
  540 
  541                 /*
  542                  * Do not run parent's if_start() if the parent is not up,
  543                  * or parent's driver will cause a system crash.
  544                  */
  545                 if (!((p->if_flags & IFF_UP) &&
  546                     (p->if_drv_flags & IFF_DRV_RUNNING))) {
  547                         m_freem(m);
  548                         ifp->if_collisions++;
  549                         continue;
  550                 }
  551 
  552                 /*
  553                  * Pad the frame to the minimum size allowed if told to.
  554                  * This option is in accord with IEEE Std 802.1Q, 2003 Ed.,
  555                  * paragraph C.4.4.3.b.  It can help to work around buggy
  556                  * bridges that violate paragraph C.4.4.3.a from the same
  557                  * document, i.e., fail to pad short frames after untagging.
  558                  * E.g., a tagged frame 66 bytes long (incl. FCS) is OK, but
  559                  * untagging it will produce a 62-byte frame, which is a runt
  560                  * and requires padding.  There are VLAN-enabled network
  561                  * devices that just discard such runts instead or mishandle
  562                  * them somehow.
  563                  */
  564                 if (soft_pad) {
  565                         static char pad[8];     /* just zeros */
  566                         int n;
  567 
  568                         for (n = ETHERMIN + ETHER_HDR_LEN - m->m_pkthdr.len;
  569                              n > 0; n -= sizeof(pad))
  570                                 if (!m_append(m, min(n, sizeof(pad)), pad))
  571                                         break;
  572 
  573                         if (n > 0) {
  574                                 if_printf(ifp, "cannot pad short frame\n");
  575                                 ifp->if_oerrors++;
  576                                 m_freem(m);
  577                                 continue;
  578                         }
  579                 }
  580 
  581                 /*
  582                  * If underlying interface can do VLAN tag insertion itself,
  583                  * just pass the packet along. However, we need some way to
  584                  * tell the interface where the packet came from so that it
  585                  * knows how to find the VLAN tag to use, so we attach a
  586                  * packet tag that holds it.
  587                  */
  588                 if (p->if_capenable & IFCAP_VLAN_HWTAGGING) {
  589                         struct m_tag *mtag = m_tag_alloc(MTAG_VLAN,
  590                                                          MTAG_VLAN_TAG,
  591                                                          sizeof(u_int),
  592                                                          M_NOWAIT);
  593                         if (mtag == NULL) {
  594                                 ifp->if_oerrors++;
  595                                 m_freem(m);
  596                                 continue;
  597                         }
  598                         VLAN_TAG_VALUE(mtag) = ifv->ifv_tag;
  599                         m_tag_prepend(m, mtag);
  600                         m->m_flags |= M_VLANTAG;
  601                 } else {
  602                         M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT);
  603                         if (m == NULL) {
  604                                 if_printf(ifp,
  605                                     "unable to prepend VLAN header\n");
  606                                 ifp->if_oerrors++;
  607                                 continue;
  608                         }
  609                         /* M_PREPEND takes care of m_len, m_pkthdr.len for us */
  610 
  611                         if (m->m_len < sizeof(*evl)) {
  612                                 m = m_pullup(m, sizeof(*evl));
  613                                 if (m == NULL) {
  614                                         if_printf(ifp,
  615                                             "cannot pullup VLAN header\n");
  616                                         ifp->if_oerrors++;
  617                                         continue;
  618                                 }
  619                         }
  620 
  621                         /*
  622                          * Transform the Ethernet header into an Ethernet header
  623                          * with 802.1Q encapsulation.
  624                          */
  625                         bcopy(mtod(m, char *) + ifv->ifv_encaplen,
  626                               mtod(m, char *), ETHER_HDR_LEN);
  627                         evl = mtod(m, struct ether_vlan_header *);
  628                         evl->evl_proto = evl->evl_encap_proto;
  629                         evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
  630                         evl->evl_tag = htons(ifv->ifv_tag);
  631 #ifdef DEBUG
  632                         printf("%s: %*D\n", __func__, (int)sizeof(*evl),
  633                             (unsigned char *)evl, ":");
  634 #endif
  635                 }
  636 
  637                 /*
  638                  * Send it, precisely as ether_output() would have.
  639                  * We are already running at splimp.
  640                  */
  641                 IFQ_HANDOFF(p, m, error);
  642                 if (!error)
  643                         ifp->if_opackets++;
  644                 else
  645                         ifp->if_oerrors++;
  646         }
  647 }
  648 
  649 static void
  650 vlan_input(struct ifnet *ifp, struct mbuf *m)
  651 {
  652         struct ether_vlan_header *evl;
  653         struct ifvlan *ifv;
  654         struct m_tag *mtag;
  655         u_int tag;
  656 
  657         if (m->m_flags & M_VLANTAG) {
  658                 /*
  659                  * Packet is tagged, but m contains a normal
  660                  * Ethernet frame; the tag is stored out-of-band.
  661                  */
  662                 mtag = m_tag_locate(m, MTAG_VLAN, MTAG_VLAN_TAG, NULL);
  663                 KASSERT(mtag != NULL,
  664                         ("%s: M_VLANTAG without m_tag", __func__));
  665                 tag = EVL_VLANOFTAG(VLAN_TAG_VALUE(mtag));
  666                 m_tag_delete(m, mtag);
  667                 m->m_flags &= ~M_VLANTAG;
  668         } else {
  669                 /*
  670                  * Packet is tagged in-band as specified by 802.1q.
  671                  */
  672                 mtag = NULL;
  673                 switch (ifp->if_type) {
  674                 case IFT_ETHER:
  675                         if (m->m_len < sizeof(*evl) &&
  676                             (m = m_pullup(m, sizeof(*evl))) == NULL) {
  677                                 if_printf(ifp, "cannot pullup VLAN header\n");
  678                                 return;
  679                         }
  680                         evl = mtod(m, struct ether_vlan_header *);
  681                         KASSERT(ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN,
  682                                 ("%s: bad encapsulation protocol (%u)",
  683                                  __func__, ntohs(evl->evl_encap_proto)));
  684 
  685                         tag = EVL_VLANOFTAG(ntohs(evl->evl_tag));
  686 
  687                         /*
  688                          * Restore the original ethertype.  We'll remove
  689                          * the encapsulation after we've found the vlan
  690                          * interface corresponding to the tag.
  691                          */
  692                         evl->evl_encap_proto = evl->evl_proto;
  693                         break;
  694                 default:
  695                         tag = (u_int) -1;
  696 #ifdef INVARIANTS
  697                         panic("%s: unsupported if_type (%u)",
  698                               __func__, ifp->if_type);
  699 #endif
  700                         break;
  701                 }
  702         }
  703 
  704         VLAN_LOCK();
  705         LIST_FOREACH(ifv, &ifv_list, ifv_list)
  706                 if (ifp == ifv->ifv_p && tag == ifv->ifv_tag)
  707                         break;
  708 
  709         if (ifv == NULL || (ifv->ifv_ifp->if_flags & IFF_UP) == 0) {
  710                 VLAN_UNLOCK();
  711                 m_freem(m);
  712                 ifp->if_noproto++;
  713 #ifdef DEBUG
  714                 printf("%s: tag %d, no interface\n", __func__, tag);
  715 #endif
  716                 return;
  717         }
  718         VLAN_UNLOCK();          /* XXX extend below? */
  719 #ifdef DEBUG
  720         printf("%s: tag %d, parent %s\n", __func__, tag, ifv->ifv_p->if_xname);
  721 #endif
  722 
  723         if (mtag == NULL) {
  724                 /*
  725                  * Packet had an in-line encapsulation header;
  726                  * remove it.  The original header has already
  727                  * been fixed up above.
  728                  */
  729                 bcopy(mtod(m, caddr_t),
  730                       mtod(m, caddr_t) + ETHER_VLAN_ENCAP_LEN,
  731                       ETHER_HDR_LEN);
  732                 m_adj(m, ETHER_VLAN_ENCAP_LEN);
  733         }
  734 
  735         m->m_pkthdr.rcvif = ifv->ifv_ifp;
  736         ifv->ifv_ifp->if_ipackets++;
  737 
  738         /* Pass it back through the parent's input routine. */
  739         (*ifp->if_input)(ifv->ifv_ifp, m);
  740 }
  741 
  742 static int
  743 vlan_config(struct ifvlan *ifv, struct ifnet *p)
  744 {
  745         struct ifaddr *ifa1, *ifa2;
  746         struct ifnet *ifp;
  747         struct sockaddr_dl *sdl1, *sdl2;
  748 
  749         VLAN_LOCK_ASSERT();
  750 
  751         if (p->if_type != IFT_ETHER)
  752                 return (EPROTONOSUPPORT);
  753         if ((p->if_flags & VLAN_IFFLAGS) != VLAN_IFFLAGS)
  754                 return (EPROTONOSUPPORT);
  755         if (ifv->ifv_p)
  756                 return (EBUSY);
  757 
  758         ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN;
  759         ifv->ifv_mintu = ETHERMIN;
  760         ifv->ifv_pflags = 0;
  761 
  762         /*
  763          * The active VLAN counter on the parent is used
  764          * at various places to see if there is a vlan(4)
  765          * attached to this physical interface.
  766          */
  767         p->if_nvlans++;
  768 
  769         /*
  770          * If the parent supports the VLAN_MTU capability,
  771          * i.e. can Tx/Rx larger than ETHER_MAX_LEN frames,
  772          * use it.
  773          */
  774         if (p->if_capenable & IFCAP_VLAN_MTU) {
  775                 /*
  776                  * No need to fudge the MTU since the parent can
  777                  * handle extended frames.
  778                  */
  779                 ifv->ifv_mtufudge = 0;
  780         } else {
  781                 /*
  782                  * Fudge the MTU by the encapsulation size.  This
  783                  * makes us incompatible with strictly compliant
  784                  * 802.1Q implementations, but allows us to use
  785                  * the feature with other NetBSD implementations,
  786                  * which might still be useful.
  787                  */
  788                 ifv->ifv_mtufudge = ifv->ifv_encaplen;
  789         }
  790 
  791         ifv->ifv_p = p;
  792         ifp = ifv->ifv_ifp;
  793         ifp->if_mtu = p->if_mtu - ifv->ifv_mtufudge;
  794         ifv->ifv_ifp->if_baudrate = p->if_baudrate;
  795         /*
  796          * Copy only a selected subset of flags from the parent.
  797          * Other flags are none of our business.
  798          */
  799 #define VLAN_COPY_FLAGS (IFF_SIMPLEX)
  800         ifp->if_flags &= ~VLAN_COPY_FLAGS;
  801         ifp->if_flags |= p->if_flags & VLAN_COPY_FLAGS;
  802 #undef VLAN_COPY_FLAGS
  803 
  804         ifp->if_link_state = p->if_link_state;
  805 
  806 #if 0
  807         /*
  808          * Not ready yet.  We need notification from the parent
  809          * when hw checksumming flags in its if_capenable change.
  810          * Flags set in if_capabilities only are useless.
  811          */
  812         /*
  813          * If the parent interface can do hardware-assisted
  814          * VLAN encapsulation, then propagate its hardware-
  815          * assisted checksumming flags.
  816          */
  817         if (p->if_capabilities & IFCAP_VLAN_HWTAGGING)
  818                 ifp->if_capabilities |= p->if_capabilities & IFCAP_HWCSUM;
  819 #endif
  820 
  821         /*
  822          * Set up our ``Ethernet address'' to reflect the underlying
  823          * physical interface's.
  824          */
  825         ifa1 = ifaddr_byindex(ifp->if_index);
  826         ifa2 = ifaddr_byindex(p->if_index);
  827         sdl1 = (struct sockaddr_dl *)ifa1->ifa_addr;
  828         sdl2 = (struct sockaddr_dl *)ifa2->ifa_addr;
  829         sdl1->sdl_type = IFT_ETHER;
  830         sdl1->sdl_alen = ETHER_ADDR_LEN;
  831         bcopy(LLADDR(sdl2), LLADDR(sdl1), ETHER_ADDR_LEN);
  832         bcopy(LLADDR(sdl2), IFP2ENADDR(ifp), ETHER_ADDR_LEN);
  833 
  834         /*
  835          * Configure multicast addresses that may already be
  836          * joined on the vlan device.
  837          */
  838         (void)vlan_setmulti(ifp); /* XXX: VLAN lock held */
  839 
  840         return (0);
  841 }
  842 
  843 static int
  844 vlan_unconfig(struct ifnet *ifp)
  845 {
  846         struct ifaddr *ifa;
  847         struct sockaddr_dl *sdl;
  848         struct vlan_mc_entry *mc;
  849         struct ifvlan *ifv;
  850         struct ifnet *p;
  851         int error;
  852 
  853         VLAN_LOCK_ASSERT();
  854 
  855         ifv = ifp->if_softc;
  856         p = ifv->ifv_p;
  857 
  858         if (p) {
  859                 struct sockaddr_dl sdl;
  860 
  861                 /*
  862                  * Since the interface is being unconfigured, we need to
  863                  * empty the list of multicast groups that we may have joined
  864                  * while we were alive from the parent's list.
  865                  */
  866                 bzero((char *)&sdl, sizeof(sdl));
  867                 sdl.sdl_len = sizeof(sdl);
  868                 sdl.sdl_family = AF_LINK;
  869                 sdl.sdl_index = p->if_index;
  870                 sdl.sdl_type = IFT_ETHER;
  871                 sdl.sdl_alen = ETHER_ADDR_LEN;
  872 
  873                 while(SLIST_FIRST(&ifv->vlan_mc_listhead) != NULL) {
  874                         mc = SLIST_FIRST(&ifv->vlan_mc_listhead);
  875                         bcopy((char *)&mc->mc_addr, LLADDR(&sdl),
  876                             ETHER_ADDR_LEN);
  877                         error = if_delmulti(p, (struct sockaddr *)&sdl);
  878                         if (error)
  879                                 return (error);
  880                         SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries);
  881                         free(mc, M_VLAN);
  882                 }
  883 
  884                 vlan_setflags(ifp, 0); /* clear special flags on parent */
  885                 p->if_nvlans--;
  886         }
  887 
  888         /* Disconnect from parent. */
  889         if (ifv->ifv_pflags)
  890                 if_printf(ifp, "%s: ifv_pflags unclean\n", __func__);
  891         ifv->ifv_p = NULL;
  892         ifv->ifv_ifp->if_mtu = ETHERMTU;                /* XXX why not 0? */
  893         ifv->ifv_ifp->if_link_state = LINK_STATE_UNKNOWN;
  894 
  895         /* Clear our MAC address. */
  896         ifa = ifaddr_byindex(ifv->ifv_ifp->if_index);
  897         sdl = (struct sockaddr_dl *)ifa->ifa_addr;
  898         sdl->sdl_type = IFT_ETHER;
  899         sdl->sdl_alen = ETHER_ADDR_LEN;
  900         bzero(LLADDR(sdl), ETHER_ADDR_LEN);
  901         bzero(IFP2ENADDR(ifv->ifv_ifp), ETHER_ADDR_LEN);
  902 
  903         return (0);
  904 }
  905 
  906 /* Handle a reference counted flag that should be set on the parent as well */
  907 static int
  908 vlan_setflag(struct ifnet *ifp, int flag, int status,
  909              int (*func)(struct ifnet *, int))
  910 {
  911         struct ifvlan *ifv;
  912         int error;
  913 
  914         /* XXX VLAN_LOCK_ASSERT(); */
  915 
  916         ifv = ifp->if_softc;
  917         status = status ? (ifp->if_flags & flag) : 0;
  918         /* Now "status" contains the flag value or 0 */
  919 
  920         /*
  921          * See if recorded parent's status is different from what
  922          * we want it to be.  If it is, flip it.  We record parent's
  923          * status in ifv_pflags so that we won't clear parent's flag
  924          * we haven't set.  In fact, we don't clear or set parent's
  925          * flags directly, but get or release references to them.
  926          * That's why we can be sure that recorded flags still are
  927          * in accord with actual parent's flags.
  928          */
  929         if (status != (ifv->ifv_pflags & flag)) {
  930                 error = (*func)(ifv->ifv_p, status);
  931                 if (error)
  932                         return (error);
  933                 ifv->ifv_pflags &= ~flag;
  934                 ifv->ifv_pflags |= status;
  935         }
  936         return (0);
  937 }
  938 
  939 /*
  940  * Handle IFF_* flags that require certain changes on the parent:
  941  * if "status" is true, update parent's flags respective to our if_flags;
  942  * if "status" is false, forcedly clear the flags set on parent.
  943  */
  944 static int
  945 vlan_setflags(struct ifnet *ifp, int status)
  946 {
  947         int error, i;
  948         
  949         for (i = 0; vlan_pflags[i].flag; i++) {
  950                 error = vlan_setflag(ifp, vlan_pflags[i].flag,
  951                                      status, vlan_pflags[i].func);
  952                 if (error)
  953                         return (error);
  954         }
  955         return (0);
  956 }
  957 
  958 /* Inform all vlans that their parent has changed link state */
  959 static void
  960 vlan_link_state(struct ifnet *ifp, int link)
  961 {
  962         struct ifvlan *ifv;
  963 
  964         VLAN_LOCK();
  965         LIST_FOREACH(ifv, &ifv_list, ifv_list) {
  966                 if (ifv->ifv_p == ifp) {
  967                         ifv->ifv_ifp->if_baudrate = ifp->if_baudrate;
  968                         if_link_state_change(ifv->ifv_ifp, ifp->if_link_state);
  969                 }
  970         }
  971         VLAN_UNLOCK();
  972 }
  973 
  974 static int
  975 vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  976 {
  977         struct ifaddr *ifa;
  978         struct ifnet *p;
  979         struct ifreq *ifr;
  980         struct ifvlan *ifv;
  981         struct vlanreq vlr;
  982         int error = 0;
  983 
  984         ifr = (struct ifreq *)data;
  985         ifa = (struct ifaddr *)data;
  986         ifv = ifp->if_softc;
  987 
  988         switch (cmd) {
  989         case SIOCSIFADDR:
  990                 ifp->if_flags |= IFF_UP;
  991 
  992                 switch (ifa->ifa_addr->sa_family) {
  993 #ifdef INET
  994                 case AF_INET:
  995                         arp_ifinit(ifv->ifv_ifp, ifa);
  996                         break;
  997 #endif
  998                 default:
  999                         break;
 1000                 }
 1001                 break;
 1002 
 1003         case SIOCGIFADDR:
 1004                 {
 1005                         struct sockaddr *sa;
 1006 
 1007                         sa = (struct sockaddr *) &ifr->ifr_data;
 1008                         bcopy(IFP2ENADDR(ifp), (caddr_t)sa->sa_data,
 1009                             ETHER_ADDR_LEN);
 1010                 }
 1011                 break;
 1012 
 1013         case SIOCGIFMEDIA:
 1014                 VLAN_LOCK();
 1015                 if (ifv->ifv_p != NULL) {
 1016                         error = (*ifv->ifv_p->if_ioctl)(ifv->ifv_p,
 1017                                         SIOCGIFMEDIA, data);
 1018                         VLAN_UNLOCK();
 1019                         /* Limit the result to the parent's current config. */
 1020                         if (error == 0) {
 1021                                 struct ifmediareq *ifmr;
 1022 
 1023                                 ifmr = (struct ifmediareq *)data;
 1024                                 if (ifmr->ifm_count >= 1 && ifmr->ifm_ulist) {
 1025                                         ifmr->ifm_count = 1;
 1026                                         error = copyout(&ifmr->ifm_current,
 1027                                                 ifmr->ifm_ulist,
 1028                                                 sizeof(int));
 1029                                 }
 1030                         }
 1031                 } else {
 1032                         VLAN_UNLOCK();
 1033                         error = EINVAL;
 1034                 }
 1035                 break;
 1036 
 1037         case SIOCSIFMEDIA:
 1038                 error = EINVAL;
 1039                 break;
 1040 
 1041         case SIOCSIFMTU:
 1042                 /*
 1043                  * Set the interface MTU.
 1044                  */
 1045                 VLAN_LOCK();
 1046                 if (ifv->ifv_p != NULL) {
 1047                         if (ifr->ifr_mtu >
 1048                              (ifv->ifv_p->if_mtu - ifv->ifv_mtufudge) ||
 1049                             ifr->ifr_mtu <
 1050                              (ifv->ifv_mintu - ifv->ifv_mtufudge))
 1051                                 error = EINVAL;
 1052                         else
 1053                                 ifp->if_mtu = ifr->ifr_mtu;
 1054                 } else
 1055                         error = EINVAL;
 1056                 VLAN_UNLOCK();
 1057                 break;
 1058 
 1059         case SIOCSETVLAN:
 1060                 error = copyin(ifr->ifr_data, &vlr, sizeof(vlr));
 1061                 if (error)
 1062                         break;
 1063                 if (vlr.vlr_parent[0] == '\0') {
 1064                         VLAN_LOCK();
 1065                         vlan_unconfig(ifp);
 1066                         ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
 1067                         VLAN_UNLOCK();
 1068                         break;
 1069                 }
 1070                 p = ifunit(vlr.vlr_parent);
 1071                 if (p == 0) {
 1072                         error = ENOENT;
 1073                         break;
 1074                 }
 1075                 /*
 1076                  * Don't let the caller set up a VLAN tag with
 1077                  * anything except VLID bits.
 1078                  */
 1079                 if (vlr.vlr_tag & ~EVL_VLID_MASK) {
 1080                         error = EINVAL;
 1081                         break;
 1082                 }
 1083                 VLAN_LOCK();
 1084                 error = vlan_config(ifv, p);
 1085                 if (error) {
 1086                         VLAN_UNLOCK();
 1087                         break;
 1088                 }
 1089                 ifv->ifv_tag = vlr.vlr_tag;
 1090                 ifp->if_drv_flags |= IFF_DRV_RUNNING;
 1091                 VLAN_UNLOCK();
 1092 
 1093                 /* Update flags on the parent, if necessary. */
 1094                 vlan_setflags(ifp, 1);
 1095                 break;
 1096 
 1097         case SIOCGETVLAN:
 1098                 bzero(&vlr, sizeof(vlr));
 1099                 VLAN_LOCK();
 1100                 if (ifv->ifv_p) {
 1101                         strlcpy(vlr.vlr_parent, ifv->ifv_p->if_xname,
 1102                             sizeof(vlr.vlr_parent));
 1103                         vlr.vlr_tag = ifv->ifv_tag;
 1104                 }
 1105                 VLAN_UNLOCK();
 1106                 error = copyout(&vlr, ifr->ifr_data, sizeof(vlr));
 1107                 break;
 1108                 
 1109         case SIOCSIFFLAGS:
 1110                 /*
 1111                  * We should propagate selected flags to the parent,
 1112                  * e.g., promiscuous mode.
 1113                  */
 1114                 if (ifv->ifv_p != NULL)
 1115                         error = vlan_setflags(ifp, 1);
 1116                 break;
 1117 
 1118         case SIOCADDMULTI:
 1119         case SIOCDELMULTI:
 1120                 /*VLAN_LOCK();*/
 1121                 error = vlan_setmulti(ifp);
 1122                 /*VLAN_UNLOCK();*/
 1123                 break;
 1124         default:
 1125                 error = EINVAL;
 1126         }
 1127 
 1128         return (error);
 1129 }

Cache object: 1f0d2ed13eb648c050c8232808f18b36


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