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.1/sys/net/if_vlan.c 155822 2006-02-18 22:48:16Z yar $
   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 MALLOC_DEFINE(M_VLAN, VLANNAME, "802.1Q Virtual LAN Interface");
  114 static LIST_HEAD(, ifvlan) ifv_list;
  115 
  116 /*
  117  * Locking: one lock is used to guard both the ifv_list and modification
  118  * to vlan data structures.  We are rather conservative here; probably
  119  * more than necessary.
  120  */
  121 static struct mtx ifv_mtx;
  122 #define VLAN_LOCK_INIT()        mtx_init(&ifv_mtx, VLANNAME, NULL, MTX_DEF)
  123 #define VLAN_LOCK_DESTROY()     mtx_destroy(&ifv_mtx)
  124 #define VLAN_LOCK_ASSERT()      mtx_assert(&ifv_mtx, MA_OWNED)
  125 #define VLAN_LOCK()     mtx_lock(&ifv_mtx)
  126 #define VLAN_UNLOCK()   mtx_unlock(&ifv_mtx)
  127 
  128 static  void vlan_start(struct ifnet *ifp);
  129 static  void vlan_ifinit(void *foo);
  130 static  void vlan_input(struct ifnet *ifp, struct mbuf *m);
  131 static  int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr);
  132 static  int vlan_setflag(struct ifnet *ifp, int flag, int status,
  133     int (*func)(struct ifnet *, int));
  134 static  int vlan_setflags(struct ifnet *ifp, int status);
  135 static  int vlan_setmulti(struct ifnet *ifp);
  136 static  int vlan_unconfig(struct ifnet *ifp);
  137 static  int vlan_config(struct ifvlan *ifv, struct ifnet *p);
  138 static  void vlan_link_state(struct ifnet *ifp, int link);
  139 
  140 static  struct ifnet *vlan_clone_match_ethertag(struct if_clone *,
  141     const char *, int *);
  142 static  int vlan_clone_match(struct if_clone *, const char *);
  143 static  int vlan_clone_create(struct if_clone *, char *, size_t);
  144 static  int vlan_clone_destroy(struct if_clone *, struct ifnet *);
  145 
  146 static  struct if_clone vlan_cloner = IFC_CLONE_INITIALIZER(VLANNAME, NULL,
  147     IF_MAXUNIT, NULL, vlan_clone_match, vlan_clone_create, vlan_clone_destroy);
  148 
  149 /*
  150  * Program our multicast filter. What we're actually doing is
  151  * programming the multicast filter of the parent. This has the
  152  * side effect of causing the parent interface to receive multicast
  153  * traffic that it doesn't really want, which ends up being discarded
  154  * later by the upper protocol layers. Unfortunately, there's no way
  155  * to avoid this: there really is only one physical interface.
  156  *
  157  * XXX: There is a possible race here if more than one thread is
  158  *      modifying the multicast state of the vlan interface at the same time.
  159  */
  160 static int
  161 vlan_setmulti(struct ifnet *ifp)
  162 {
  163         struct ifnet            *ifp_p;
  164         struct ifmultiaddr      *ifma, *rifma = NULL;
  165         struct ifvlan           *sc;
  166         struct vlan_mc_entry    *mc = NULL;
  167         struct sockaddr_dl      sdl;
  168         int                     error;
  169 
  170         /*VLAN_LOCK_ASSERT();*/
  171 
  172         /* Find the parent. */
  173         sc = ifp->if_softc;
  174         ifp_p = sc->ifv_p;
  175 
  176         /*
  177          * If we don't have a parent, just remember the membership for
  178          * when we do.
  179          */
  180         if (ifp_p == NULL)
  181                 return (0);
  182 
  183         bzero((char *)&sdl, sizeof(sdl));
  184         sdl.sdl_len = sizeof(sdl);
  185         sdl.sdl_family = AF_LINK;
  186         sdl.sdl_index = ifp_p->if_index;
  187         sdl.sdl_type = IFT_ETHER;
  188         sdl.sdl_alen = ETHER_ADDR_LEN;
  189 
  190         /* First, remove any existing filter entries. */
  191         while (SLIST_FIRST(&sc->vlan_mc_listhead) != NULL) {
  192                 mc = SLIST_FIRST(&sc->vlan_mc_listhead);
  193                 bcopy((char *)&mc->mc_addr, LLADDR(&sdl), ETHER_ADDR_LEN);
  194                 error = if_delmulti(ifp_p, (struct sockaddr *)&sdl);
  195                 if (error)
  196                         return (error);
  197                 SLIST_REMOVE_HEAD(&sc->vlan_mc_listhead, mc_entries);
  198                 free(mc, M_VLAN);
  199         }
  200 
  201         /* Now program new ones. */
  202         TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  203                 if (ifma->ifma_addr->sa_family != AF_LINK)
  204                         continue;
  205                 mc = malloc(sizeof(struct vlan_mc_entry), M_VLAN, M_NOWAIT);
  206                 if (mc == NULL)
  207                         return (ENOMEM);
  208                 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
  209                     (char *)&mc->mc_addr, ETHER_ADDR_LEN);
  210                 SLIST_INSERT_HEAD(&sc->vlan_mc_listhead, mc, mc_entries);
  211                 bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
  212                     LLADDR(&sdl), ETHER_ADDR_LEN);
  213                 error = if_addmulti(ifp_p, (struct sockaddr *)&sdl, &rifma);
  214                 if (error)
  215                         return (error);
  216         }
  217 
  218         return (0);
  219 }
  220 
  221 /*
  222  * VLAN support can be loaded as a module.  The only place in the
  223  * system that's intimately aware of this is ether_input.  We hook
  224  * into this code through vlan_input_p which is defined there and
  225  * set here.  Noone else in the system should be aware of this so
  226  * we use an explicit reference here.
  227  *
  228  * NB: Noone should ever need to check if vlan_input_p is null or
  229  *     not.  This is because interfaces have a count of the number
  230  *     of active vlans (if_nvlans) and this should never be bumped
  231  *     except by vlan_config--which is in this module so therefore
  232  *     the module must be loaded and vlan_input_p must be non-NULL.
  233  */
  234 extern  void (*vlan_input_p)(struct ifnet *, struct mbuf *);
  235 
  236 /* For if_link_state_change() eyes only... */
  237 extern  void (*vlan_link_state_p)(struct ifnet *, int);
  238 
  239 static int
  240 vlan_modevent(module_t mod, int type, void *data)
  241 {
  242 
  243         switch (type) {
  244         case MOD_LOAD:
  245                 LIST_INIT(&ifv_list);
  246                 VLAN_LOCK_INIT();
  247                 vlan_input_p = vlan_input;
  248                 vlan_link_state_p = vlan_link_state;
  249                 if_clone_attach(&vlan_cloner);
  250                 break;
  251         case MOD_UNLOAD:
  252                 if_clone_detach(&vlan_cloner);
  253                 vlan_input_p = NULL;
  254                 vlan_link_state_p = NULL;
  255                 while (!LIST_EMPTY(&ifv_list))
  256                         vlan_clone_destroy(&vlan_cloner,
  257                             LIST_FIRST(&ifv_list)->ifv_ifp);
  258                 VLAN_LOCK_DESTROY();
  259                 break;
  260         default:
  261                 return (EOPNOTSUPP);
  262         }
  263         return (0);
  264 }
  265 
  266 static moduledata_t vlan_mod = {
  267         "if_vlan",
  268         vlan_modevent,
  269         0
  270 };
  271 
  272 DECLARE_MODULE(if_vlan, vlan_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
  273 MODULE_DEPEND(if_vlan, miibus, 1, 1, 1);
  274 
  275 static struct ifnet *
  276 vlan_clone_match_ethertag(struct if_clone *ifc, const char *name, int *tag)
  277 {
  278         const char *cp;
  279         struct ifnet *ifp;
  280         int t = 0;
  281 
  282         /* Check for <etherif>.<vlan> style interface names. */
  283         IFNET_RLOCK();
  284         TAILQ_FOREACH(ifp, &ifnet, if_link) {
  285                 if (ifp->if_type != IFT_ETHER)
  286                         continue;
  287                 if (strncmp(ifp->if_xname, name, strlen(ifp->if_xname)) != 0)
  288                         continue;
  289                 cp = name + strlen(ifp->if_xname);
  290                 if (*cp != '.')
  291                         continue;
  292                 for(; *cp != '\0'; cp++) {
  293                         if (*cp < '' || *cp > '9')
  294                                 continue;
  295                         t = (t * 10) + (*cp - '');
  296                 }
  297                 if (tag != NULL)
  298                         *tag = t;
  299                 break;
  300         }
  301         IFNET_RUNLOCK();
  302 
  303         return (ifp);
  304 }
  305 
  306 static int
  307 vlan_clone_match(struct if_clone *ifc, const char *name)
  308 {
  309         const char *cp;
  310 
  311         if (vlan_clone_match_ethertag(ifc, name, NULL) != NULL)
  312                 return (1);
  313 
  314         if (strncmp(VLANNAME, name, strlen(VLANNAME)) != 0)
  315                 return (0);
  316         for (cp = name + 4; *cp != '\0'; cp++) {
  317                 if (*cp < '' || *cp > '9')
  318                         return (0);
  319         }
  320 
  321         return (1);
  322 }
  323 
  324 static int
  325 vlan_clone_create(struct if_clone *ifc, char *name, size_t len)
  326 {
  327         char *dp;
  328         int wildcard;
  329         int unit;
  330         int error;
  331         int tag;
  332         int ethertag;
  333         struct ifvlan *ifv;
  334         struct ifnet *ifp;
  335         struct ifnet *p;
  336         u_char eaddr[6] = {0,0,0,0,0,0};
  337 
  338         if ((p = vlan_clone_match_ethertag(ifc, name, &tag)) != NULL) {
  339                 ethertag = 1;
  340                 unit = -1;
  341                 wildcard = 0;
  342 
  343                 /*
  344                  * Don't let the caller set up a VLAN tag with
  345                  * anything except VLID bits.
  346                  */
  347                 if (tag & ~EVL_VLID_MASK)
  348                         return (EINVAL);
  349         } else {
  350                 ethertag = 0;
  351 
  352                 error = ifc_name2unit(name, &unit);
  353                 if (error != 0)
  354                         return (error);
  355 
  356                 wildcard = (unit < 0);
  357         }
  358 
  359         error = ifc_alloc_unit(ifc, &unit);
  360         if (error != 0)
  361                 return (error);
  362 
  363         /* In the wildcard case, we need to update the name. */
  364         if (wildcard) {
  365                 for (dp = name; *dp != '\0'; dp++);
  366                 if (snprintf(dp, len - (dp-name), "%d", unit) >
  367                     len - (dp-name) - 1) {
  368                         panic("%s: interface name too long", __func__);
  369                 }
  370         }
  371 
  372         ifv = malloc(sizeof(struct ifvlan), M_VLAN, M_WAITOK | M_ZERO);
  373         ifp = ifv->ifv_ifp = if_alloc(IFT_ETHER);
  374         if (ifp == NULL) {
  375                 ifc_free_unit(ifc, unit);
  376                 free(ifv, M_VLAN);
  377                 return (ENOSPC);
  378         }
  379         SLIST_INIT(&ifv->vlan_mc_listhead);
  380 
  381         ifp->if_softc = ifv;
  382         /*
  383          * Set the name manually rather than using if_initname because
  384          * we don't conform to the default naming convention for interfaces.
  385          */
  386         strlcpy(ifp->if_xname, name, IFNAMSIZ);
  387         ifp->if_dname = ifc->ifc_name;
  388         ifp->if_dunit = unit;
  389         /* NB: flags are not set here */
  390         ifp->if_linkmib = &ifv->ifv_mib;
  391         ifp->if_linkmiblen = sizeof(ifv->ifv_mib);
  392         /* NB: mtu is not set here */
  393 
  394         ifp->if_init = vlan_ifinit;
  395         ifp->if_start = vlan_start;
  396         ifp->if_ioctl = vlan_ioctl;
  397         ifp->if_snd.ifq_maxlen = ifqmaxlen;
  398         ifp->if_flags = VLAN_IFFLAGS;
  399         ether_ifattach(ifp, eaddr);
  400         /* Now undo some of the damage... */
  401         ifp->if_baudrate = 0;
  402         ifp->if_type = IFT_L2VLAN;
  403         ifp->if_hdrlen = ETHER_VLAN_ENCAP_LEN;
  404 
  405         VLAN_LOCK();
  406         LIST_INSERT_HEAD(&ifv_list, ifv, ifv_list);
  407         VLAN_UNLOCK();
  408 
  409         if (ethertag) {
  410                 VLAN_LOCK();
  411                 error = vlan_config(ifv, p);
  412                 if (error != 0) {
  413                         /*
  414                          * Since we've partialy failed, we need to back
  415                          * out all the way, otherwise userland could get
  416                          * confused.  Thus, we destroy the interface.
  417                          */
  418                         LIST_REMOVE(ifv, ifv_list);
  419                         vlan_unconfig(ifp);
  420                         VLAN_UNLOCK();
  421                         ether_ifdetach(ifp);
  422                         if_free_type(ifp, IFT_ETHER);
  423                         free(ifv, M_VLAN);
  424 
  425                         return (error);
  426                 }
  427                 ifv->ifv_tag = tag;
  428                 ifp->if_drv_flags |= IFF_DRV_RUNNING;
  429                 VLAN_UNLOCK();
  430 
  431                 /* Update flags on the parent, if necessary. */
  432                 vlan_setflags(ifp, 1);
  433         }
  434 
  435         return (0);
  436 }
  437 
  438 static int
  439 vlan_clone_destroy(struct if_clone *ifc, struct ifnet *ifp)
  440 {
  441         int unit;
  442         struct ifvlan *ifv = ifp->if_softc;
  443 
  444         unit = ifp->if_dunit;
  445 
  446         VLAN_LOCK();
  447         LIST_REMOVE(ifv, ifv_list);
  448         vlan_unconfig(ifp);
  449         VLAN_UNLOCK();
  450 
  451         ether_ifdetach(ifp);
  452         if_free_type(ifp, IFT_ETHER);
  453 
  454         free(ifv, M_VLAN);
  455 
  456         ifc_free_unit(ifc, unit);
  457 
  458         return (0);
  459 }
  460 
  461 /*
  462  * The ifp->if_init entry point for vlan(4) is a no-op.
  463  */
  464 static void
  465 vlan_ifinit(void *foo)
  466 {
  467 
  468 }
  469 
  470 /*
  471  * The if_start method for vlan(4) interface. It doesn't
  472  * raises the IFF_DRV_OACTIVE flag, since it is called
  473  * only from IFQ_HANDOFF() macro in ether_output_frame().
  474  * If the interface queue is full, and vlan_start() is
  475  * not called, the queue would never get emptied and
  476  * interface would stall forever.
  477  */
  478 static void
  479 vlan_start(struct ifnet *ifp)
  480 {
  481         struct ifvlan *ifv;
  482         struct ifnet *p;
  483         struct ether_vlan_header *evl;
  484         struct mbuf *m;
  485         int error;
  486 
  487         ifv = ifp->if_softc;
  488         p = ifv->ifv_p;
  489 
  490         for (;;) {
  491                 IF_DEQUEUE(&ifp->if_snd, m);
  492                 if (m == 0)
  493                         break;
  494                 BPF_MTAP(ifp, m);
  495 
  496                 /*
  497                  * Do not run parent's if_start() if the parent is not up,
  498                  * or parent's driver will cause a system crash.
  499                  */
  500                 if (!((p->if_flags & IFF_UP) &&
  501                     (p->if_drv_flags & IFF_DRV_RUNNING))) {
  502                         m_freem(m);
  503                         ifp->if_collisions++;
  504                         continue;
  505                 }
  506 
  507                 /*
  508                  * If underlying interface can do VLAN tag insertion itself,
  509                  * just pass the packet along. However, we need some way to
  510                  * tell the interface where the packet came from so that it
  511                  * knows how to find the VLAN tag to use, so we attach a
  512                  * packet tag that holds it.
  513                  */
  514                 if (p->if_capenable & IFCAP_VLAN_HWTAGGING) {
  515                         struct m_tag *mtag = m_tag_alloc(MTAG_VLAN,
  516                                                          MTAG_VLAN_TAG,
  517                                                          sizeof(u_int),
  518                                                          M_NOWAIT);
  519                         if (mtag == NULL) {
  520                                 ifp->if_oerrors++;
  521                                 m_freem(m);
  522                                 continue;
  523                         }
  524                         VLAN_TAG_VALUE(mtag) = ifv->ifv_tag;
  525                         m_tag_prepend(m, mtag);
  526                         m->m_flags |= M_VLANTAG;
  527                 } else {
  528                         M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT);
  529                         if (m == NULL) {
  530                                 if_printf(ifp,
  531                                     "unable to prepend VLAN header\n");
  532                                 ifp->if_oerrors++;
  533                                 continue;
  534                         }
  535                         /* M_PREPEND takes care of m_len, m_pkthdr.len for us */
  536 
  537                         if (m->m_len < sizeof(*evl)) {
  538                                 m = m_pullup(m, sizeof(*evl));
  539                                 if (m == NULL) {
  540                                         if_printf(ifp,
  541                                             "cannot pullup VLAN header\n");
  542                                         ifp->if_oerrors++;
  543                                         continue;
  544                                 }
  545                         }
  546 
  547                         /*
  548                          * Transform the Ethernet header into an Ethernet header
  549                          * with 802.1Q encapsulation.
  550                          */
  551                         bcopy(mtod(m, char *) + ifv->ifv_encaplen,
  552                               mtod(m, char *), ETHER_HDR_LEN);
  553                         evl = mtod(m, struct ether_vlan_header *);
  554                         evl->evl_proto = evl->evl_encap_proto;
  555                         evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
  556                         evl->evl_tag = htons(ifv->ifv_tag);
  557 #ifdef DEBUG
  558                         printf("%s: %*D\n", __func__, (int)sizeof(*evl),
  559                             (unsigned char *)evl, ":");
  560 #endif
  561                 }
  562 
  563                 /*
  564                  * Send it, precisely as ether_output() would have.
  565                  * We are already running at splimp.
  566                  */
  567                 IFQ_HANDOFF(p, m, error);
  568                 if (!error)
  569                         ifp->if_opackets++;
  570                 else
  571                         ifp->if_oerrors++;
  572         }
  573 }
  574 
  575 static void
  576 vlan_input(struct ifnet *ifp, struct mbuf *m)
  577 {
  578         struct ether_vlan_header *evl;
  579         struct ifvlan *ifv;
  580         struct m_tag *mtag;
  581         u_int tag;
  582 
  583         if (m->m_flags & M_VLANTAG) {
  584                 /*
  585                  * Packet is tagged, but m contains a normal
  586                  * Ethernet frame; the tag is stored out-of-band.
  587                  */
  588                 mtag = m_tag_locate(m, MTAG_VLAN, MTAG_VLAN_TAG, NULL);
  589                 KASSERT(mtag != NULL,
  590                         ("%s: M_VLANTAG without m_tag", __func__));
  591                 tag = EVL_VLANOFTAG(VLAN_TAG_VALUE(mtag));
  592                 m_tag_delete(m, mtag);
  593                 m->m_flags &= ~M_VLANTAG;
  594         } else {
  595                 /*
  596                  * Packet is tagged in-band as specified by 802.1q.
  597                  */
  598                 mtag = NULL;
  599                 switch (ifp->if_type) {
  600                 case IFT_ETHER:
  601                         if (m->m_len < sizeof(*evl) &&
  602                             (m = m_pullup(m, sizeof(*evl))) == NULL) {
  603                                 if_printf(ifp, "cannot pullup VLAN header\n");
  604                                 return;
  605                         }
  606                         evl = mtod(m, struct ether_vlan_header *);
  607                         KASSERT(ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN,
  608                                 ("%s: bad encapsulation protocol (%u)",
  609                                  __func__, ntohs(evl->evl_encap_proto)));
  610 
  611                         tag = EVL_VLANOFTAG(ntohs(evl->evl_tag));
  612 
  613                         /*
  614                          * Restore the original ethertype.  We'll remove
  615                          * the encapsulation after we've found the vlan
  616                          * interface corresponding to the tag.
  617                          */
  618                         evl->evl_encap_proto = evl->evl_proto;
  619                         break;
  620                 default:
  621                         tag = (u_int) -1;
  622 #ifdef INVARIANTS
  623                         panic("%s: unsupported if_type (%u)",
  624                               __func__, ifp->if_type);
  625 #endif
  626                         break;
  627                 }
  628         }
  629 
  630         VLAN_LOCK();
  631         LIST_FOREACH(ifv, &ifv_list, ifv_list)
  632                 if (ifp == ifv->ifv_p && tag == ifv->ifv_tag)
  633                         break;
  634 
  635         if (ifv == NULL || (ifv->ifv_ifp->if_flags & IFF_UP) == 0) {
  636                 VLAN_UNLOCK();
  637                 m_freem(m);
  638                 ifp->if_noproto++;
  639 #ifdef DEBUG
  640                 printf("%s: tag %d, no interface\n", __func__, tag);
  641 #endif
  642                 return;
  643         }
  644         VLAN_UNLOCK();          /* XXX extend below? */
  645 #ifdef DEBUG
  646         printf("%s: tag %d, parent %s\n", __func__, tag, ifv->ifv_p->if_xname);
  647 #endif
  648 
  649         if (mtag == NULL) {
  650                 /*
  651                  * Packet had an in-line encapsulation header;
  652                  * remove it.  The original header has already
  653                  * been fixed up above.
  654                  */
  655                 bcopy(mtod(m, caddr_t),
  656                       mtod(m, caddr_t) + ETHER_VLAN_ENCAP_LEN,
  657                       ETHER_HDR_LEN);
  658                 m_adj(m, ETHER_VLAN_ENCAP_LEN);
  659         }
  660 
  661         m->m_pkthdr.rcvif = ifv->ifv_ifp;
  662         ifv->ifv_ifp->if_ipackets++;
  663 
  664         /* Pass it back through the parent's input routine. */
  665         (*ifp->if_input)(ifv->ifv_ifp, m);
  666 }
  667 
  668 static int
  669 vlan_config(struct ifvlan *ifv, struct ifnet *p)
  670 {
  671         struct ifaddr *ifa1, *ifa2;
  672         struct ifnet *ifp;
  673         struct sockaddr_dl *sdl1, *sdl2;
  674 
  675         VLAN_LOCK_ASSERT();
  676 
  677         if (p->if_type != IFT_ETHER)
  678                 return (EPROTONOSUPPORT);
  679         if ((p->if_flags & VLAN_IFFLAGS) != VLAN_IFFLAGS)
  680                 return (EPROTONOSUPPORT);
  681         if (ifv->ifv_p)
  682                 return (EBUSY);
  683 
  684         ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN;
  685         ifv->ifv_mintu = ETHERMIN;
  686         ifv->ifv_pflags = 0;
  687 
  688         /*
  689          * The active VLAN counter on the parent is used
  690          * at various places to see if there is a vlan(4)
  691          * attached to this physical interface.
  692          */
  693         p->if_nvlans++;
  694 
  695         /*
  696          * If the parent supports the VLAN_MTU capability,
  697          * i.e. can Tx/Rx larger than ETHER_MAX_LEN frames,
  698          * use it.
  699          */
  700         if (p->if_capenable & IFCAP_VLAN_MTU) {
  701                 /*
  702                  * No need to fudge the MTU since the parent can
  703                  * handle extended frames.
  704                  */
  705                 ifv->ifv_mtufudge = 0;
  706         } else {
  707                 /*
  708                  * Fudge the MTU by the encapsulation size.  This
  709                  * makes us incompatible with strictly compliant
  710                  * 802.1Q implementations, but allows us to use
  711                  * the feature with other NetBSD implementations,
  712                  * which might still be useful.
  713                  */
  714                 ifv->ifv_mtufudge = ifv->ifv_encaplen;
  715         }
  716 
  717         ifv->ifv_p = p;
  718         ifp = ifv->ifv_ifp;
  719         ifp->if_mtu = p->if_mtu - ifv->ifv_mtufudge;
  720         ifv->ifv_ifp->if_baudrate = p->if_baudrate;
  721         /*
  722          * Copy only a selected subset of flags from the parent.
  723          * Other flags are none of our business.
  724          */
  725 #define VLAN_COPY_FLAGS (IFF_SIMPLEX)
  726         ifp->if_flags &= ~VLAN_COPY_FLAGS;
  727         ifp->if_flags |= p->if_flags & VLAN_COPY_FLAGS;
  728 #undef VLAN_COPY_FLAGS
  729 
  730         ifp->if_link_state = p->if_link_state;
  731 
  732 #if 0
  733         /*
  734          * Not ready yet.  We need notification from the parent
  735          * when hw checksumming flags in its if_capenable change.
  736          * Flags set in if_capabilities only are useless.
  737          */
  738         /*
  739          * If the parent interface can do hardware-assisted
  740          * VLAN encapsulation, then propagate its hardware-
  741          * assisted checksumming flags.
  742          */
  743         if (p->if_capabilities & IFCAP_VLAN_HWTAGGING)
  744                 ifp->if_capabilities |= p->if_capabilities & IFCAP_HWCSUM;
  745 #endif
  746 
  747         /*
  748          * Set up our ``Ethernet address'' to reflect the underlying
  749          * physical interface's.
  750          */
  751         ifa1 = ifaddr_byindex(ifp->if_index);
  752         ifa2 = ifaddr_byindex(p->if_index);
  753         sdl1 = (struct sockaddr_dl *)ifa1->ifa_addr;
  754         sdl2 = (struct sockaddr_dl *)ifa2->ifa_addr;
  755         sdl1->sdl_type = IFT_ETHER;
  756         sdl1->sdl_alen = ETHER_ADDR_LEN;
  757         bcopy(LLADDR(sdl2), LLADDR(sdl1), ETHER_ADDR_LEN);
  758         bcopy(LLADDR(sdl2), IFP2ENADDR(ifp), ETHER_ADDR_LEN);
  759 
  760         /*
  761          * Configure multicast addresses that may already be
  762          * joined on the vlan device.
  763          */
  764         (void)vlan_setmulti(ifp); /* XXX: VLAN lock held */
  765 
  766         return (0);
  767 }
  768 
  769 static int
  770 vlan_unconfig(struct ifnet *ifp)
  771 {
  772         struct ifaddr *ifa;
  773         struct sockaddr_dl *sdl;
  774         struct vlan_mc_entry *mc;
  775         struct ifvlan *ifv;
  776         struct ifnet *p;
  777         int error;
  778 
  779         VLAN_LOCK_ASSERT();
  780 
  781         ifv = ifp->if_softc;
  782         p = ifv->ifv_p;
  783 
  784         if (p) {
  785                 struct sockaddr_dl sdl;
  786 
  787                 /*
  788                  * Since the interface is being unconfigured, we need to
  789                  * empty the list of multicast groups that we may have joined
  790                  * while we were alive from the parent's list.
  791                  */
  792                 bzero((char *)&sdl, sizeof(sdl));
  793                 sdl.sdl_len = sizeof(sdl);
  794                 sdl.sdl_family = AF_LINK;
  795                 sdl.sdl_index = p->if_index;
  796                 sdl.sdl_type = IFT_ETHER;
  797                 sdl.sdl_alen = ETHER_ADDR_LEN;
  798 
  799                 while(SLIST_FIRST(&ifv->vlan_mc_listhead) != NULL) {
  800                         mc = SLIST_FIRST(&ifv->vlan_mc_listhead);
  801                         bcopy((char *)&mc->mc_addr, LLADDR(&sdl),
  802                             ETHER_ADDR_LEN);
  803                         error = if_delmulti(p, (struct sockaddr *)&sdl);
  804                         if (error)
  805                                 return (error);
  806                         SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries);
  807                         free(mc, M_VLAN);
  808                 }
  809 
  810                 vlan_setflags(ifp, 0); /* clear special flags on parent */
  811                 p->if_nvlans--;
  812         }
  813 
  814         /* Disconnect from parent. */
  815         if (ifv->ifv_pflags)
  816                 if_printf(ifp, "%s: ifv_pflags unclean\n", __func__);
  817         ifv->ifv_p = NULL;
  818         ifv->ifv_ifp->if_mtu = ETHERMTU;                /* XXX why not 0? */
  819         ifv->ifv_ifp->if_link_state = LINK_STATE_UNKNOWN;
  820 
  821         /* Clear our MAC address. */
  822         ifa = ifaddr_byindex(ifv->ifv_ifp->if_index);
  823         sdl = (struct sockaddr_dl *)ifa->ifa_addr;
  824         sdl->sdl_type = IFT_ETHER;
  825         sdl->sdl_alen = ETHER_ADDR_LEN;
  826         bzero(LLADDR(sdl), ETHER_ADDR_LEN);
  827         bzero(IFP2ENADDR(ifv->ifv_ifp), ETHER_ADDR_LEN);
  828 
  829         return (0);
  830 }
  831 
  832 /* Handle a reference counted flag that should be set on the parent as well */
  833 static int
  834 vlan_setflag(struct ifnet *ifp, int flag, int status,
  835              int (*func)(struct ifnet *, int))
  836 {
  837         struct ifvlan *ifv;
  838         int error;
  839 
  840         /* XXX VLAN_LOCK_ASSERT(); */
  841 
  842         ifv = ifp->if_softc;
  843         status = status ? (ifp->if_flags & flag) : 0;
  844         /* Now "status" contains the flag value or 0 */
  845 
  846         /*
  847          * See if recorded parent's status is different from what
  848          * we want it to be.  If it is, flip it.  We record parent's
  849          * status in ifv_pflags so that we won't clear parent's flag
  850          * we haven't set.  In fact, we don't clear or set parent's
  851          * flags directly, but get or release references to them.
  852          * That's why we can be sure that recorded flags still are
  853          * in accord with actual parent's flags.
  854          */
  855         if (status != (ifv->ifv_pflags & flag)) {
  856                 error = (*func)(ifv->ifv_p, status);
  857                 if (error)
  858                         return (error);
  859                 ifv->ifv_pflags &= ~flag;
  860                 ifv->ifv_pflags |= status;
  861         }
  862         return (0);
  863 }
  864 
  865 /*
  866  * Handle IFF_* flags that require certain changes on the parent:
  867  * if "status" is true, update parent's flags respective to our if_flags;
  868  * if "status" is false, forcedly clear the flags set on parent.
  869  */
  870 static int
  871 vlan_setflags(struct ifnet *ifp, int status)
  872 {
  873         int error, i;
  874         
  875         for (i = 0; vlan_pflags[i].flag; i++) {
  876                 error = vlan_setflag(ifp, vlan_pflags[i].flag,
  877                                      status, vlan_pflags[i].func);
  878                 if (error)
  879                         return (error);
  880         }
  881         return (0);
  882 }
  883 
  884 /* Inform all vlans that their parent has changed link state */
  885 static void
  886 vlan_link_state(struct ifnet *ifp, int link)
  887 {
  888         struct ifvlan *ifv;
  889 
  890         VLAN_LOCK();
  891         LIST_FOREACH(ifv, &ifv_list, ifv_list) {
  892                 if (ifv->ifv_p == ifp)
  893                         if_link_state_change(ifv->ifv_ifp,
  894                             ifv->ifv_p->if_link_state);
  895         }
  896         VLAN_UNLOCK();
  897 }
  898 
  899 static int
  900 vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  901 {
  902         struct ifaddr *ifa;
  903         struct ifnet *p;
  904         struct ifreq *ifr;
  905         struct ifvlan *ifv;
  906         struct vlanreq vlr;
  907         int error = 0;
  908 
  909         ifr = (struct ifreq *)data;
  910         ifa = (struct ifaddr *)data;
  911         ifv = ifp->if_softc;
  912 
  913         switch (cmd) {
  914         case SIOCSIFADDR:
  915                 ifp->if_flags |= IFF_UP;
  916 
  917                 switch (ifa->ifa_addr->sa_family) {
  918 #ifdef INET
  919                 case AF_INET:
  920                         arp_ifinit(ifv->ifv_ifp, ifa);
  921                         break;
  922 #endif
  923                 default:
  924                         break;
  925                 }
  926                 break;
  927 
  928         case SIOCGIFADDR:
  929                 {
  930                         struct sockaddr *sa;
  931 
  932                         sa = (struct sockaddr *) &ifr->ifr_data;
  933                         bcopy(IFP2ENADDR(ifp), (caddr_t)sa->sa_data,
  934                             ETHER_ADDR_LEN);
  935                 }
  936                 break;
  937 
  938         case SIOCGIFMEDIA:
  939                 VLAN_LOCK();
  940                 if (ifv->ifv_p != NULL) {
  941                         error = (*ifv->ifv_p->if_ioctl)(ifv->ifv_p,
  942                                         SIOCGIFMEDIA, data);
  943                         VLAN_UNLOCK();
  944                         /* Limit the result to the parent's current config. */
  945                         if (error == 0) {
  946                                 struct ifmediareq *ifmr;
  947 
  948                                 ifmr = (struct ifmediareq *)data;
  949                                 if (ifmr->ifm_count >= 1 && ifmr->ifm_ulist) {
  950                                         ifmr->ifm_count = 1;
  951                                         error = copyout(&ifmr->ifm_current,
  952                                                 ifmr->ifm_ulist,
  953                                                 sizeof(int));
  954                                 }
  955                         }
  956                 } else {
  957                         VLAN_UNLOCK();
  958                         error = EINVAL;
  959                 }
  960                 break;
  961 
  962         case SIOCSIFMEDIA:
  963                 error = EINVAL;
  964                 break;
  965 
  966         case SIOCSIFMTU:
  967                 /*
  968                  * Set the interface MTU.
  969                  */
  970                 VLAN_LOCK();
  971                 if (ifv->ifv_p != NULL) {
  972                         if (ifr->ifr_mtu >
  973                              (ifv->ifv_p->if_mtu - ifv->ifv_mtufudge) ||
  974                             ifr->ifr_mtu <
  975                              (ifv->ifv_mintu - ifv->ifv_mtufudge))
  976                                 error = EINVAL;
  977                         else
  978                                 ifp->if_mtu = ifr->ifr_mtu;
  979                 } else
  980                         error = EINVAL;
  981                 VLAN_UNLOCK();
  982                 break;
  983 
  984         case SIOCSETVLAN:
  985                 error = copyin(ifr->ifr_data, &vlr, sizeof(vlr));
  986                 if (error)
  987                         break;
  988                 if (vlr.vlr_parent[0] == '\0') {
  989                         VLAN_LOCK();
  990                         vlan_unconfig(ifp);
  991                         ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
  992                         VLAN_UNLOCK();
  993                         break;
  994                 }
  995                 p = ifunit(vlr.vlr_parent);
  996                 if (p == 0) {
  997                         error = ENOENT;
  998                         break;
  999                 }
 1000                 /*
 1001                  * Don't let the caller set up a VLAN tag with
 1002                  * anything except VLID bits.
 1003                  */
 1004                 if (vlr.vlr_tag & ~EVL_VLID_MASK) {
 1005                         error = EINVAL;
 1006                         break;
 1007                 }
 1008                 VLAN_LOCK();
 1009                 error = vlan_config(ifv, p);
 1010                 if (error) {
 1011                         VLAN_UNLOCK();
 1012                         break;
 1013                 }
 1014                 ifv->ifv_tag = vlr.vlr_tag;
 1015                 ifp->if_drv_flags |= IFF_DRV_RUNNING;
 1016                 VLAN_UNLOCK();
 1017 
 1018                 /* Update flags on the parent, if necessary. */
 1019                 vlan_setflags(ifp, 1);
 1020                 break;
 1021 
 1022         case SIOCGETVLAN:
 1023                 bzero(&vlr, sizeof(vlr));
 1024                 VLAN_LOCK();
 1025                 if (ifv->ifv_p) {
 1026                         strlcpy(vlr.vlr_parent, ifv->ifv_p->if_xname,
 1027                             sizeof(vlr.vlr_parent));
 1028                         vlr.vlr_tag = ifv->ifv_tag;
 1029                 }
 1030                 VLAN_UNLOCK();
 1031                 error = copyout(&vlr, ifr->ifr_data, sizeof(vlr));
 1032                 break;
 1033                 
 1034         case SIOCSIFFLAGS:
 1035                 /*
 1036                  * We should propagate selected flags to the parent,
 1037                  * e.g., promiscuous mode.
 1038                  */
 1039                 if (ifv->ifv_p != NULL)
 1040                         error = vlan_setflags(ifp, 1);
 1041                 break;
 1042 
 1043         case SIOCADDMULTI:
 1044         case SIOCDELMULTI:
 1045                 /*VLAN_LOCK();*/
 1046                 error = vlan_setmulti(ifp);
 1047                 /*VLAN_UNLOCK();*/
 1048                 break;
 1049         default:
 1050                 error = EINVAL;
 1051         }
 1052 
 1053         return (error);
 1054 }

Cache object: 55033f6519e3f3f82043e48e9188fccd


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