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 /*      $NetBSD: if_vlan.c,v 1.60.4.1 2009/05/03 18:01:01 snj Exp $     */
    2 
    3 /*-
    4  * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Andrew Doran, and by Jason R. Thorpe of Zembu Labs, Inc.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 /*
   33  * Copyright 1998 Massachusetts Institute of Technology
   34  *
   35  * Permission to use, copy, modify, and distribute this software and
   36  * its documentation for any purpose and without fee is hereby
   37  * granted, provided that both the above copyright notice and this
   38  * permission notice appear in all copies, that both the above
   39  * copyright notice and this permission notice appear in all
   40  * supporting documentation, and that the name of M.I.T. not be used
   41  * in advertising or publicity pertaining to distribution of the
   42  * software without specific, written prior permission.  M.I.T. makes
   43  * no representations about the suitability of this software for any
   44  * purpose.  It is provided "as is" without express or implied
   45  * warranty.
   46  *
   47  * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
   48  * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
   49  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   50  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
   51  * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   52  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   53  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   54  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   55  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   56  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   57  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   58  * SUCH DAMAGE.
   59  *
   60  * from FreeBSD: if_vlan.c,v 1.16 2000/03/26 15:21:40 charnier Exp
   61  * via OpenBSD: if_vlan.c,v 1.4 2000/05/15 19:15:00 chris Exp
   62  */
   63 
   64 /*
   65  * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs.  Might be
   66  * extended some day to also handle IEEE 802.1P priority tagging.  This is
   67  * sort of sneaky in the implementation, since we need to pretend to be
   68  * enough of an Ethernet implementation to make ARP work.  The way we do
   69  * this is by telling everyone that we are an Ethernet interface, and then
   70  * catch the packets that ether_output() left on our output queue when it
   71  * calls if_start(), rewrite them for use by the real outgoing interface,
   72  * and ask it to send them.
   73  *
   74  * TODO:
   75  *
   76  *      - Need some way to notify vlan interfaces when the parent
   77  *        interface changes MTU.
   78  */
   79 
   80 #include <sys/cdefs.h>
   81 __KERNEL_RCSID(0, "$NetBSD: if_vlan.c,v 1.60.4.1 2009/05/03 18:01:01 snj Exp $");
   82 
   83 #include "opt_inet.h"
   84 #include "bpfilter.h"
   85 
   86 #include <sys/param.h>
   87 #include <sys/kernel.h>
   88 #include <sys/mbuf.h>
   89 #include <sys/queue.h>
   90 #include <sys/socket.h>
   91 #include <sys/sockio.h>
   92 #include <sys/systm.h>
   93 #include <sys/proc.h>
   94 #include <sys/kauth.h>
   95 
   96 #if NBPFILTER > 0
   97 #include <net/bpf.h>
   98 #endif
   99 #include <net/if.h>
  100 #include <net/if_dl.h>
  101 #include <net/if_types.h>
  102 #include <net/if_ether.h>
  103 #include <net/if_vlanvar.h>
  104 
  105 #ifdef INET
  106 #include <netinet/in.h>
  107 #include <netinet/if_inarp.h>
  108 #endif
  109 
  110 struct vlan_mc_entry {
  111         LIST_ENTRY(vlan_mc_entry)       mc_entries;
  112         /*
  113          * A key to identify this entry.  The mc_addr below can't be
  114          * used since multiple sockaddr may mapped into the same
  115          * ether_multi (e.g., AF_UNSPEC).
  116          */
  117         union {
  118                 struct ether_multi      *mcu_enm;
  119         } mc_u;
  120         struct sockaddr_storage         mc_addr;
  121 };
  122 
  123 #define mc_enm          mc_u.mcu_enm
  124 
  125 struct ifvlan {
  126         union {
  127                 struct ethercom ifvu_ec;
  128         } ifv_u;
  129         struct ifnet *ifv_p;    /* parent interface of this vlan */
  130         struct ifv_linkmib {
  131                 const struct vlan_multisw *ifvm_msw;
  132                 int     ifvm_encaplen;  /* encapsulation length */
  133                 int     ifvm_mtufudge;  /* MTU fudged by this much */
  134                 int     ifvm_mintu;     /* min transmission unit */
  135                 uint16_t ifvm_proto;    /* encapsulation ethertype */
  136                 uint16_t ifvm_tag;      /* tag to apply on packets */
  137         } ifv_mib;
  138         LIST_HEAD(__vlan_mchead, vlan_mc_entry) ifv_mc_listhead;
  139         LIST_ENTRY(ifvlan) ifv_list;
  140         int ifv_flags;
  141 };
  142 
  143 #define IFVF_PROMISC    0x01            /* promiscuous mode enabled */
  144 
  145 #define ifv_ec          ifv_u.ifvu_ec
  146 
  147 #define ifv_if          ifv_ec.ec_if
  148 
  149 #define ifv_msw         ifv_mib.ifvm_msw
  150 #define ifv_encaplen    ifv_mib.ifvm_encaplen
  151 #define ifv_mtufudge    ifv_mib.ifvm_mtufudge
  152 #define ifv_mintu       ifv_mib.ifvm_mintu
  153 #define ifv_tag         ifv_mib.ifvm_tag
  154 
  155 struct vlan_multisw {
  156         int     (*vmsw_addmulti)(struct ifvlan *, struct ifreq *);
  157         int     (*vmsw_delmulti)(struct ifvlan *, struct ifreq *);
  158         void    (*vmsw_purgemulti)(struct ifvlan *);
  159 };
  160 
  161 static int      vlan_ether_addmulti(struct ifvlan *, struct ifreq *);
  162 static int      vlan_ether_delmulti(struct ifvlan *, struct ifreq *);
  163 static void     vlan_ether_purgemulti(struct ifvlan *);
  164 
  165 const struct vlan_multisw vlan_ether_multisw = {
  166         vlan_ether_addmulti,
  167         vlan_ether_delmulti,
  168         vlan_ether_purgemulti,
  169 };
  170 
  171 static int      vlan_clone_create(struct if_clone *, int);
  172 static int      vlan_clone_destroy(struct ifnet *);
  173 static int      vlan_config(struct ifvlan *, struct ifnet *);
  174 static int      vlan_ioctl(struct ifnet *, u_long, void *);
  175 static void     vlan_start(struct ifnet *);
  176 static void     vlan_unconfig(struct ifnet *);
  177 
  178 void            vlanattach(int);
  179 
  180 /* XXX This should be a hash table with the tag as the basis of the key. */
  181 static LIST_HEAD(, ifvlan) ifv_list;
  182 
  183 struct if_clone vlan_cloner =
  184     IF_CLONE_INITIALIZER("vlan", vlan_clone_create, vlan_clone_destroy);
  185 
  186 /* Used to pad ethernet frames with < ETHER_MIN_LEN bytes */
  187 static char vlan_zero_pad_buff[ETHER_MIN_LEN];
  188 
  189 void
  190 vlanattach(int n)
  191 {
  192 
  193         LIST_INIT(&ifv_list);
  194         if_clone_attach(&vlan_cloner);
  195 }
  196 
  197 static void
  198 vlan_reset_linkname(struct ifnet *ifp)
  199 {
  200 
  201         /*
  202          * We start out with a "802.1Q VLAN" type and zero-length
  203          * addresses.  When we attach to a parent interface, we
  204          * inherit its type, address length, address, and data link
  205          * type.
  206          */
  207 
  208         ifp->if_type = IFT_L2VLAN;
  209         ifp->if_addrlen = 0;
  210         ifp->if_dlt = DLT_NULL;
  211         if_alloc_sadl(ifp);
  212 }
  213 
  214 static int
  215 vlan_clone_create(struct if_clone *ifc, int unit)
  216 {
  217         struct ifvlan *ifv;
  218         struct ifnet *ifp;
  219         int s;
  220 
  221         ifv = malloc(sizeof(struct ifvlan), M_DEVBUF, M_WAITOK|M_ZERO);
  222         ifp = &ifv->ifv_if;
  223         LIST_INIT(&ifv->ifv_mc_listhead);
  224 
  225         s = splnet();
  226         LIST_INSERT_HEAD(&ifv_list, ifv, ifv_list);
  227         splx(s);
  228 
  229         if_initname(ifp, ifc->ifc_name, unit);
  230         ifp->if_softc = ifv;
  231         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
  232         ifp->if_start = vlan_start;
  233         ifp->if_ioctl = vlan_ioctl;
  234         IFQ_SET_READY(&ifp->if_snd);
  235 
  236         if_attach(ifp);
  237         vlan_reset_linkname(ifp);
  238 
  239         return (0);
  240 }
  241 
  242 static int
  243 vlan_clone_destroy(struct ifnet *ifp)
  244 {
  245         struct ifvlan *ifv = ifp->if_softc;
  246         int s;
  247 
  248         s = splnet();
  249         LIST_REMOVE(ifv, ifv_list);
  250         vlan_unconfig(ifp);
  251         splx(s);
  252 
  253         if_detach(ifp);
  254         free(ifv, M_DEVBUF);
  255 
  256         return (0);
  257 }
  258 
  259 /*
  260  * Configure a VLAN interface.  Must be called at splnet().
  261  */
  262 static int
  263 vlan_config(struct ifvlan *ifv, struct ifnet *p)
  264 {
  265         struct ifnet *ifp = &ifv->ifv_if;
  266         int error;
  267 
  268         if (ifv->ifv_p != NULL)
  269                 return (EBUSY);
  270 
  271         switch (p->if_type) {
  272         case IFT_ETHER:
  273             {
  274                 struct ethercom *ec = (void *) p;
  275 
  276                 ifv->ifv_msw = &vlan_ether_multisw;
  277                 ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN;
  278                 ifv->ifv_mintu = ETHERMIN;
  279 
  280                 /*
  281                  * If the parent supports the VLAN_MTU capability,
  282                  * i.e. can Tx/Rx larger than ETHER_MAX_LEN frames,
  283                  * enable it.
  284                  */
  285                 if (ec->ec_nvlans++ == 0 &&
  286                     (ec->ec_capabilities & ETHERCAP_VLAN_MTU) != 0) {
  287                         /*
  288                          * Enable Tx/Rx of VLAN-sized frames.
  289                          */
  290                         ec->ec_capenable |= ETHERCAP_VLAN_MTU;
  291                         if (p->if_flags & IFF_UP) {
  292                                 struct ifreq ifr;
  293 
  294                                 ifr.ifr_flags = p->if_flags;
  295                                 error = (*p->if_ioctl)(p, SIOCSIFFLAGS,
  296                                     (void *) &ifr);
  297                                 if (error) {
  298                                         if (ec->ec_nvlans-- == 1)
  299                                                 ec->ec_capenable &=
  300                                                     ~ETHERCAP_VLAN_MTU;
  301                                         return (error);
  302                                 }
  303                         }
  304                         ifv->ifv_mtufudge = 0;
  305                 } else if ((ec->ec_capabilities & ETHERCAP_VLAN_MTU) == 0) {
  306                         /*
  307                          * Fudge the MTU by the encapsulation size.  This
  308                          * makes us incompatible with strictly compliant
  309                          * 802.1Q implementations, but allows us to use
  310                          * the feature with other NetBSD implementations,
  311                          * which might still be useful.
  312                          */
  313                         ifv->ifv_mtufudge = ifv->ifv_encaplen;
  314                 }
  315 
  316                 /*
  317                  * If the parent interface can do hardware-assisted
  318                  * VLAN encapsulation, then propagate its hardware-
  319                  * assisted checksumming flags and tcp segmentation
  320                  * offload.
  321                  */
  322                 if (ec->ec_capabilities & ETHERCAP_VLAN_HWTAGGING)
  323                         ifp->if_capabilities = p->if_capabilities &
  324                             (IFCAP_TSOv4 |
  325                              IFCAP_CSUM_IPv4_Tx|IFCAP_CSUM_IPv4_Rx|
  326                              IFCAP_CSUM_TCPv4_Tx|IFCAP_CSUM_TCPv4_Rx|
  327                              IFCAP_CSUM_UDPv4_Tx|IFCAP_CSUM_UDPv4_Rx|
  328                              IFCAP_CSUM_TCPv6_Tx|IFCAP_CSUM_TCPv6_Rx|
  329                              IFCAP_CSUM_UDPv6_Tx|IFCAP_CSUM_UDPv6_Rx);
  330 
  331                 /*
  332                  * We inherit the parent's Ethernet address.
  333                  */
  334                 ether_ifattach(ifp, CLLADDR(p->if_sadl));
  335                 ifp->if_hdrlen = sizeof(struct ether_vlan_header); /* XXX? */
  336                 break;
  337             }
  338 
  339         default:
  340                 return (EPROTONOSUPPORT);
  341         }
  342 
  343         ifv->ifv_p = p;
  344         ifv->ifv_if.if_mtu = p->if_mtu - ifv->ifv_mtufudge;
  345         ifv->ifv_if.if_flags = p->if_flags &
  346             (IFF_UP | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
  347 
  348         /*
  349          * Inherit the if_type from the parent.  This allows us
  350          * to participate in bridges of that type.
  351          */
  352         ifv->ifv_if.if_type = p->if_type;
  353 
  354         return (0);
  355 }
  356 
  357 /*
  358  * Unconfigure a VLAN interface.  Must be called at splnet().
  359  */
  360 static void
  361 vlan_unconfig(struct ifnet *ifp)
  362 {
  363         struct ifvlan *ifv = ifp->if_softc;
  364 
  365         if (ifv->ifv_p == NULL)
  366                 return;
  367 
  368         /*
  369          * Since the interface is being unconfigured, we need to empty the
  370          * list of multicast groups that we may have joined while we were
  371          * alive and remove them from the parent's list also.
  372          */
  373         (*ifv->ifv_msw->vmsw_purgemulti)(ifv);
  374 
  375         /* Disconnect from parent. */
  376         switch (ifv->ifv_p->if_type) {
  377         case IFT_ETHER:
  378             {
  379                 struct ethercom *ec = (void *) ifv->ifv_p;
  380 
  381                 if (ec->ec_nvlans-- == 1) {
  382                         /*
  383                          * Disable Tx/Rx of VLAN-sized frames.
  384                          */
  385                         ec->ec_capenable &= ~ETHERCAP_VLAN_MTU;
  386                         if (ifv->ifv_p->if_flags & IFF_UP) {
  387                                 struct ifreq ifr;
  388 
  389                                 ifr.ifr_flags = ifv->ifv_p->if_flags;
  390                                 (void) (*ifv->ifv_p->if_ioctl)(ifv->ifv_p,
  391                                     SIOCSIFFLAGS, (void *) &ifr);
  392                         }
  393                 }
  394 
  395                 ether_ifdetach(ifp);
  396                 vlan_reset_linkname(ifp);
  397                 break;
  398             }
  399 
  400 #ifdef DIAGNOSTIC
  401         default:
  402                 panic("vlan_unconfig: impossible");
  403 #endif
  404         }
  405 
  406         ifv->ifv_p = NULL;
  407         ifv->ifv_if.if_mtu = 0;
  408         ifv->ifv_flags = 0;
  409 
  410         if_down(ifp);
  411         ifp->if_flags &= ~(IFF_UP|IFF_RUNNING);
  412         ifp->if_capabilities = 0;
  413 }
  414 
  415 /*
  416  * Called when a parent interface is detaching; destroy any VLAN
  417  * configuration for the parent interface.
  418  */
  419 void
  420 vlan_ifdetach(struct ifnet *p)
  421 {
  422         struct ifvlan *ifv;
  423         int s;
  424 
  425         s = splnet();
  426 
  427         for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
  428              ifv = LIST_NEXT(ifv, ifv_list)) {
  429                 if (ifv->ifv_p == p)
  430                         vlan_unconfig(&ifv->ifv_if);
  431         }
  432 
  433         splx(s);
  434 }
  435 
  436 static int
  437 vlan_set_promisc(struct ifnet *ifp)
  438 {
  439         struct ifvlan *ifv = ifp->if_softc;
  440         int error = 0;
  441 
  442         if ((ifp->if_flags & IFF_PROMISC) != 0) {
  443                 if ((ifv->ifv_flags & IFVF_PROMISC) == 0) {
  444                         error = ifpromisc(ifv->ifv_p, 1);
  445                         if (error == 0)
  446                                 ifv->ifv_flags |= IFVF_PROMISC;
  447                 }
  448         } else {
  449                 if ((ifv->ifv_flags & IFVF_PROMISC) != 0) {
  450                         error = ifpromisc(ifv->ifv_p, 0);
  451                         if (error == 0)
  452                                 ifv->ifv_flags &= ~IFVF_PROMISC;
  453                 }
  454         }
  455 
  456         return (error);
  457 }
  458 
  459 static int
  460 vlan_ioctl(struct ifnet *ifp, u_long cmd, void *data)
  461 {
  462         struct lwp *l = curlwp; /* XXX */
  463         struct ifvlan *ifv = ifp->if_softc;
  464         struct ifaddr *ifa = (struct ifaddr *) data;
  465         struct ifreq *ifr = (struct ifreq *) data;
  466         struct ifnet *pr;
  467         struct ifcapreq *ifcr;
  468         struct vlanreq vlr;
  469         struct sockaddr *sa;
  470         int s, error = 0;
  471 
  472         s = splnet();
  473 
  474         switch (cmd) {
  475         case SIOCSIFADDR:
  476                 if (ifv->ifv_p != NULL) {
  477                         ifp->if_flags |= IFF_UP;
  478 
  479                         switch (ifa->ifa_addr->sa_family) {
  480 #ifdef INET
  481                         case AF_INET:
  482                                 arp_ifinit(ifp, ifa);
  483                                 break;
  484 #endif
  485                         default:
  486                                 break;
  487                         }
  488                 } else {
  489                         error = EINVAL;
  490                 }
  491                 break;
  492 
  493         case SIOCGIFADDR:
  494                 sa = (struct sockaddr *)&ifr->ifr_data;
  495                 memcpy(sa->sa_data, CLLADDR(ifp->if_sadl), ifp->if_addrlen);
  496                 break;
  497 
  498         case SIOCSIFMTU:
  499                 if (ifv->ifv_p == NULL)
  500                         error = EINVAL;
  501                 else if (
  502                     ifr->ifr_mtu > (ifv->ifv_p->if_mtu - ifv->ifv_mtufudge) ||
  503                     ifr->ifr_mtu < (ifv->ifv_mintu - ifv->ifv_mtufudge))
  504                         error = EINVAL;
  505                 else if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET)
  506                         error = 0;
  507                 break;
  508 
  509         case SIOCSETVLAN:
  510                 if ((error = kauth_authorize_network(l->l_cred,
  511                     KAUTH_NETWORK_INTERFACE,
  512                     KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
  513                     NULL)) != 0)
  514                         break;
  515                 if ((error = copyin(ifr->ifr_data, &vlr, sizeof(vlr))) != 0)
  516                         break;
  517                 if (vlr.vlr_parent[0] == '\0') {
  518                         vlan_unconfig(ifp);
  519                         break;
  520                 }
  521                 if (vlr.vlr_tag != EVL_VLANOFTAG(vlr.vlr_tag)) {
  522                         error = EINVAL;          /* check for valid tag */
  523                         break;
  524                 }
  525                 if ((pr = ifunit(vlr.vlr_parent)) == 0) {
  526                         error = ENOENT;
  527                         break;
  528                 }
  529                 if ((error = vlan_config(ifv, pr)) != 0)
  530                         break;
  531                 ifv->ifv_tag = vlr.vlr_tag;
  532                 ifp->if_flags |= IFF_RUNNING;
  533 
  534                 /* Update promiscuous mode, if necessary. */
  535                 vlan_set_promisc(ifp);
  536                 break;
  537 
  538         case SIOCGETVLAN:
  539                 memset(&vlr, 0, sizeof(vlr));
  540                 if (ifv->ifv_p != NULL) {
  541                         snprintf(vlr.vlr_parent, sizeof(vlr.vlr_parent), "%s",
  542                             ifv->ifv_p->if_xname);
  543                         vlr.vlr_tag = ifv->ifv_tag;
  544                 }
  545                 error = copyout(&vlr, ifr->ifr_data, sizeof(vlr));
  546                 break;
  547 
  548         case SIOCSIFFLAGS:
  549                 /*
  550                  * For promiscuous mode, we enable promiscuous mode on
  551                  * the parent if we need promiscuous on the VLAN interface.
  552                  */
  553                 if (ifv->ifv_p != NULL)
  554                         error = vlan_set_promisc(ifp);
  555                 break;
  556 
  557         case SIOCADDMULTI:
  558                 error = (ifv->ifv_p != NULL) ?
  559                     (*ifv->ifv_msw->vmsw_addmulti)(ifv, ifr) : EINVAL;
  560                 break;
  561 
  562         case SIOCDELMULTI:
  563                 error = (ifv->ifv_p != NULL) ?
  564                     (*ifv->ifv_msw->vmsw_delmulti)(ifv, ifr) : EINVAL;
  565                 break;
  566 
  567         case SIOCSIFCAP:
  568                 ifcr = data;
  569                 /* make sure caps are enabled on parent */
  570                 if ((ifv->ifv_p->if_capenable & ifcr->ifcr_capenable) !=
  571                     ifcr->ifcr_capenable) {
  572                         error = EINVAL;
  573                         break;
  574                 }
  575                 if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET)
  576                         error = 0;
  577                 break;
  578         default:
  579                 error = EINVAL;
  580         }
  581 
  582         splx(s);
  583 
  584         return (error);
  585 }
  586 
  587 static int
  588 vlan_ether_addmulti(struct ifvlan *ifv, struct ifreq *ifr)
  589 {
  590         const struct sockaddr *sa = ifreq_getaddr(SIOCADDMULTI, ifr);
  591         struct vlan_mc_entry *mc;
  592         uint8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
  593         int error;
  594 
  595         if (sa->sa_len > sizeof(struct sockaddr_storage))
  596                 return (EINVAL);
  597 
  598         error = ether_addmulti(sa, &ifv->ifv_ec);
  599         if (error != ENETRESET)
  600                 return (error);
  601 
  602         /*
  603          * This is new multicast address.  We have to tell parent
  604          * about it.  Also, remember this multicast address so that
  605          * we can delete them on unconfigure.
  606          */
  607         MALLOC(mc, struct vlan_mc_entry *, sizeof(struct vlan_mc_entry),
  608             M_DEVBUF, M_NOWAIT);
  609         if (mc == NULL) {
  610                 error = ENOMEM;
  611                 goto alloc_failed;
  612         }
  613 
  614         /*
  615          * As ether_addmulti() returns ENETRESET, following two
  616          * statement shouldn't fail.
  617          */
  618         (void)ether_multiaddr(sa, addrlo, addrhi);
  619         ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ec, mc->mc_enm);
  620         memcpy(&mc->mc_addr, sa, sa->sa_len);
  621         LIST_INSERT_HEAD(&ifv->ifv_mc_listhead, mc, mc_entries);
  622 
  623         error = (*ifv->ifv_p->if_ioctl)(ifv->ifv_p, SIOCADDMULTI,
  624             (void *)ifr);
  625         if (error != 0)
  626                 goto ioctl_failed;
  627         return (error);
  628 
  629  ioctl_failed:
  630         LIST_REMOVE(mc, mc_entries);
  631         FREE(mc, M_DEVBUF);
  632  alloc_failed:
  633         (void)ether_delmulti(sa, &ifv->ifv_ec);
  634         return (error);
  635 }
  636 
  637 static int
  638 vlan_ether_delmulti(struct ifvlan *ifv, struct ifreq *ifr)
  639 {
  640         const struct sockaddr *sa = ifreq_getaddr(SIOCDELMULTI, ifr);
  641         struct ether_multi *enm;
  642         struct vlan_mc_entry *mc;
  643         uint8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
  644         int error;
  645 
  646         /*
  647          * Find a key to lookup vlan_mc_entry.  We have to do this
  648          * before calling ether_delmulti for obvious reason.
  649          */
  650         if ((error = ether_multiaddr(sa, addrlo, addrhi)) != 0)
  651                 return (error);
  652         ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ec, enm);
  653 
  654         error = ether_delmulti(sa, &ifv->ifv_ec);
  655         if (error != ENETRESET)
  656                 return (error);
  657 
  658         /* We no longer use this multicast address.  Tell parent so. */
  659         error = (*ifv->ifv_p->if_ioctl)(ifv->ifv_p, SIOCDELMULTI,
  660             (void *)ifr);
  661         if (error == 0) {
  662                 /* And forget about this address. */
  663                 for (mc = LIST_FIRST(&ifv->ifv_mc_listhead); mc != NULL;
  664                     mc = LIST_NEXT(mc, mc_entries)) {
  665                         if (mc->mc_enm == enm) {
  666                                 LIST_REMOVE(mc, mc_entries);
  667                                 FREE(mc, M_DEVBUF);
  668                                 break;
  669                         }
  670                 }
  671                 KASSERT(mc != NULL);
  672         } else
  673                 (void)ether_addmulti(sa, &ifv->ifv_ec);
  674         return (error);
  675 }
  676 
  677 /*
  678  * Delete any multicast address we have asked to add from parent
  679  * interface.  Called when the vlan is being unconfigured.
  680  */
  681 static void
  682 vlan_ether_purgemulti(struct ifvlan *ifv)
  683 {
  684         struct ifnet *ifp = ifv->ifv_p;         /* Parent. */
  685         struct vlan_mc_entry *mc;
  686         union {
  687                 struct ifreq ifreq;
  688                 struct {
  689                         char ifr_name[IFNAMSIZ];
  690                         struct sockaddr_storage ifr_ss;
  691                 } ifreq_storage;
  692         } ifreq;
  693         struct ifreq *ifr = &ifreq.ifreq;
  694 
  695         memcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ);
  696         while ((mc = LIST_FIRST(&ifv->ifv_mc_listhead)) != NULL) {
  697                 ifreq_setaddr(SIOCDELMULTI, ifr,
  698                     (const struct sockaddr *)&mc->mc_addr);
  699                 (void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (void *)ifr);
  700                 LIST_REMOVE(mc, mc_entries);
  701                 FREE(mc, M_DEVBUF);
  702         }
  703 }
  704 
  705 static void
  706 vlan_start(struct ifnet *ifp)
  707 {
  708         struct ifvlan *ifv = ifp->if_softc;
  709         struct ifnet *p = ifv->ifv_p;
  710         struct ethercom *ec = (void *) ifv->ifv_p;
  711         struct mbuf *m;
  712         int error;
  713         ALTQ_DECL(struct altq_pktattr pktattr;)
  714 
  715         ifp->if_flags |= IFF_OACTIVE;
  716 
  717         for (;;) {
  718                 IFQ_DEQUEUE(&ifp->if_snd, m);
  719                 if (m == NULL)
  720                         break;
  721 
  722 #ifdef ALTQ
  723                 /*
  724                  * If ALTQ is enabled on the parent interface, do
  725                  * classification; the queueing discipline might
  726                  * not require classification, but might require
  727                  * the address family/header pointer in the pktattr.
  728                  */
  729                 if (ALTQ_IS_ENABLED(&p->if_snd)) {
  730                         switch (p->if_type) {
  731                         case IFT_ETHER:
  732                                 altq_etherclassify(&p->if_snd, m, &pktattr);
  733                                 break;
  734 #ifdef DIAGNOSTIC
  735                         default:
  736                                 panic("vlan_start: impossible (altq)");
  737 #endif
  738                         }
  739                 }
  740 #endif /* ALTQ */
  741 
  742 #if NBPFILTER > 0
  743                 if (ifp->if_bpf)
  744                         bpf_mtap(ifp->if_bpf, m);
  745 #endif
  746                 /*
  747                  * If the parent can insert the tag itself, just mark
  748                  * the tag in the mbuf header.
  749                  */
  750                 if (ec->ec_capabilities & ETHERCAP_VLAN_HWTAGGING) {
  751                         struct m_tag *mtag;
  752 
  753                         mtag = m_tag_get(PACKET_TAG_VLAN, sizeof(u_int),
  754                             M_NOWAIT);
  755                         if (mtag == NULL) {
  756                                 ifp->if_oerrors++;
  757                                 m_freem(m);
  758                                 continue;
  759                         }
  760                         *(u_int *)(mtag + 1) = ifv->ifv_tag;
  761                         m_tag_prepend(m, mtag);
  762                 } else {
  763                         /*
  764                          * insert the tag ourselves
  765                          */
  766                         M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT);
  767                         if (m == NULL) {
  768                                 printf("%s: unable to prepend encap header",
  769                                     ifv->ifv_p->if_xname);
  770                                 ifp->if_oerrors++;
  771                                 continue;
  772                         }
  773 
  774                         switch (p->if_type) {
  775                         case IFT_ETHER:
  776                             {
  777                                 struct ether_vlan_header *evl;
  778 
  779                                 if (m->m_len < sizeof(struct ether_vlan_header))
  780                                         m = m_pullup(m,
  781                                             sizeof(struct ether_vlan_header));
  782                                 if (m == NULL) {
  783                                         printf("%s: unable to pullup encap "
  784                                             "header", ifv->ifv_p->if_xname);
  785                                         ifp->if_oerrors++;
  786                                         continue;
  787                                 }
  788 
  789                                 /*
  790                                  * Transform the Ethernet header into an
  791                                  * Ethernet header with 802.1Q encapsulation.
  792                                  */
  793                                 memmove(mtod(m, void *),
  794                                     mtod(m, char *) + ifv->ifv_encaplen,
  795                                     sizeof(struct ether_header));
  796                                 evl = mtod(m, struct ether_vlan_header *);
  797                                 evl->evl_proto = evl->evl_encap_proto;
  798                                 evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
  799                                 evl->evl_tag = htons(ifv->ifv_tag);
  800 
  801                                 /*
  802                                  * To cater for VLAN-aware layer 2 ethernet
  803                                  * switches which may need to strip the tag
  804                                  * before forwarding the packet, make sure
  805                                  * the packet+tag is at least 68 bytes long.
  806                                  * This is necessary because our parent will
  807                                  * only pad to 64 bytes (ETHER_MIN_LEN) and
  808                                  * some switches will not pad by themselves
  809                                  * after deleting a tag.
  810                                  */
  811                                 if (m->m_pkthdr.len <
  812                                     (ETHER_MIN_LEN + ETHER_VLAN_ENCAP_LEN)) {
  813                                         m_copyback(m, m->m_pkthdr.len,
  814                                             (ETHER_MIN_LEN +
  815                                              ETHER_VLAN_ENCAP_LEN) -
  816                                              m->m_pkthdr.len,
  817                                             vlan_zero_pad_buff);
  818                                 }
  819                                 break;
  820                             }
  821 
  822 #ifdef DIAGNOSTIC
  823                         default:
  824                                 panic("vlan_start: impossible");
  825 #endif
  826                         }
  827                 }
  828 
  829                 /*
  830                  * Send it, precisely as the parent's output routine
  831                  * would have.  We are already running at splnet.
  832                  */
  833                 IFQ_ENQUEUE(&p->if_snd, m, &pktattr, error);
  834                 if (error) {
  835                         /* mbuf is already freed */
  836                         ifp->if_oerrors++;
  837                         continue;
  838                 }
  839 
  840                 ifp->if_opackets++;
  841                 if ((p->if_flags & (IFF_RUNNING|IFF_OACTIVE)) == IFF_RUNNING)
  842                         (*p->if_start)(p);
  843         }
  844 
  845         ifp->if_flags &= ~IFF_OACTIVE;
  846 }
  847 
  848 /*
  849  * Given an Ethernet frame, find a valid vlan interface corresponding to the
  850  * given source interface and tag, then run the real packet through the
  851  * parent's input routine.
  852  */
  853 void
  854 vlan_input(struct ifnet *ifp, struct mbuf *m)
  855 {
  856         struct ifvlan *ifv;
  857         u_int tag;
  858         struct m_tag *mtag;
  859 
  860         mtag = m_tag_find(m, PACKET_TAG_VLAN, NULL);
  861         if (mtag != NULL) {
  862                 /* m contains a normal ethernet frame, the tag is in mtag */
  863                 tag = EVL_VLANOFTAG(*(u_int *)(mtag + 1));
  864                 m_tag_delete(m, mtag);
  865         } else {
  866                 switch (ifp->if_type) {
  867                 case IFT_ETHER:
  868                     {
  869                         struct ether_vlan_header *evl;
  870 
  871                         if (m->m_len < sizeof(struct ether_vlan_header) &&
  872                             (m = m_pullup(m,
  873                              sizeof(struct ether_vlan_header))) == NULL) {
  874                                 printf("%s: no memory for VLAN header, "
  875                                     "dropping packet.\n", ifp->if_xname);
  876                                 return;
  877                         }
  878                         evl = mtod(m, struct ether_vlan_header *);
  879                         KASSERT(ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN);
  880 
  881                         tag = EVL_VLANOFTAG(ntohs(evl->evl_tag));
  882 
  883                         /*
  884                          * Restore the original ethertype.  We'll remove
  885                          * the encapsulation after we've found the vlan
  886                          * interface corresponding to the tag.
  887                          */
  888                         evl->evl_encap_proto = evl->evl_proto;
  889                         break;
  890                     }
  891 
  892                 default:
  893                         tag = (u_int) -1;       /* XXX GCC */
  894 #ifdef DIAGNOSTIC
  895                         panic("vlan_input: impossible");
  896 #endif
  897                 }
  898         }
  899 
  900         for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
  901             ifv = LIST_NEXT(ifv, ifv_list))
  902                 if (ifp == ifv->ifv_p && tag == ifv->ifv_tag)
  903                         break;
  904 
  905         if (ifv == NULL ||
  906             (ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
  907              (IFF_UP|IFF_RUNNING)) {
  908                 m_freem(m);
  909                 ifp->if_noproto++;
  910                 return;
  911         }
  912 
  913         /*
  914          * Now, remove the encapsulation header.  The original
  915          * header has already been fixed up above.
  916          */
  917         if (mtag == NULL) {
  918                 memmove(mtod(m, char *) + ifv->ifv_encaplen,
  919                     mtod(m, void *), sizeof(struct ether_header));
  920                 m_adj(m, ifv->ifv_encaplen);
  921         }
  922 
  923         m->m_pkthdr.rcvif = &ifv->ifv_if;
  924         ifv->ifv_if.if_ipackets++;
  925 
  926 #if NBPFILTER > 0
  927         if (ifv->ifv_if.if_bpf)
  928                 bpf_mtap(ifv->ifv_if.if_bpf, m);
  929 #endif
  930 
  931         /* Pass it back through the parent's input routine. */
  932         (*ifp->if_input)(&ifv->ifv_if, m);
  933 }

Cache object: eb997621ca9687ed207ec53acc552f33


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