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.170 2022/06/20 08:14:48 yamaguchi 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.170 2022/06/20 08:14:48 yamaguchi Exp $");
   82 
   83 #ifdef _KERNEL_OPT
   84 #include "opt_inet.h"
   85 #include "opt_net_mpsafe.h"
   86 #endif
   87 
   88 #include <sys/param.h>
   89 #include <sys/systm.h>
   90 #include <sys/kernel.h>
   91 #include <sys/mbuf.h>
   92 #include <sys/queue.h>
   93 #include <sys/socket.h>
   94 #include <sys/sockio.h>
   95 #include <sys/systm.h>
   96 #include <sys/proc.h>
   97 #include <sys/kauth.h>
   98 #include <sys/mutex.h>
   99 #include <sys/kmem.h>
  100 #include <sys/cpu.h>
  101 #include <sys/pserialize.h>
  102 #include <sys/psref.h>
  103 #include <sys/pslist.h>
  104 #include <sys/atomic.h>
  105 #include <sys/device.h>
  106 #include <sys/module.h>
  107 
  108 #include <net/bpf.h>
  109 #include <net/if.h>
  110 #include <net/if_dl.h>
  111 #include <net/if_types.h>
  112 #include <net/if_ether.h>
  113 #include <net/if_vlanvar.h>
  114 
  115 #ifdef INET
  116 #include <netinet/in.h>
  117 #include <netinet/if_inarp.h>
  118 #endif
  119 #ifdef INET6
  120 #include <netinet6/in6_ifattach.h>
  121 #include <netinet6/in6_var.h>
  122 #include <netinet6/nd6.h>
  123 #endif
  124 
  125 #include "ioconf.h"
  126 
  127 struct vlan_mc_entry {
  128         LIST_ENTRY(vlan_mc_entry)       mc_entries;
  129         /*
  130          * A key to identify this entry.  The mc_addr below can't be
  131          * used since multiple sockaddr may mapped into the same
  132          * ether_multi (e.g., AF_UNSPEC).
  133          */
  134         struct ether_multi      *mc_enm;
  135         struct sockaddr_storage         mc_addr;
  136 };
  137 
  138 struct ifvlan_linkmib {
  139         struct ifvlan *ifvm_ifvlan;
  140         const struct vlan_multisw *ifvm_msw;
  141         int     ifvm_mtufudge;  /* MTU fudged by this much */
  142         int     ifvm_mintu;     /* min transmission unit */
  143         uint16_t ifvm_proto;    /* encapsulation ethertype */
  144         uint16_t ifvm_tag;      /* tag to apply on packets */
  145         struct ifnet *ifvm_p;   /* parent interface of this vlan */
  146 
  147         struct psref_target ifvm_psref;
  148 };
  149 
  150 struct ifvlan {
  151         struct ethercom ifv_ec;
  152         struct ifvlan_linkmib *ifv_mib; /*
  153                                          * reader must use vlan_getref_linkmib()
  154                                          * instead of direct dereference
  155                                          */
  156         kmutex_t ifv_lock;              /* writer lock for ifv_mib */
  157         pserialize_t ifv_psz;
  158         void *ifv_linkstate_hook;
  159         void *ifv_ifdetach_hook;
  160 
  161         LIST_HEAD(__vlan_mchead, vlan_mc_entry) ifv_mc_listhead;
  162         struct pslist_entry ifv_hash;
  163         int ifv_flags;
  164         bool ifv_stopping;
  165 };
  166 
  167 #define IFVF_PROMISC    0x01            /* promiscuous mode enabled */
  168 
  169 #define ifv_if          ifv_ec.ec_if
  170 
  171 #define ifv_msw         ifv_mib.ifvm_msw
  172 #define ifv_mtufudge    ifv_mib.ifvm_mtufudge
  173 #define ifv_mintu       ifv_mib.ifvm_mintu
  174 #define ifv_tag         ifv_mib.ifvm_tag
  175 
  176 struct vlan_multisw {
  177         int     (*vmsw_addmulti)(struct ifvlan *, struct ifreq *);
  178         int     (*vmsw_delmulti)(struct ifvlan *, struct ifreq *);
  179         void    (*vmsw_purgemulti)(struct ifvlan *);
  180 };
  181 
  182 static int      vlan_ether_addmulti(struct ifvlan *, struct ifreq *);
  183 static int      vlan_ether_delmulti(struct ifvlan *, struct ifreq *);
  184 static void     vlan_ether_purgemulti(struct ifvlan *);
  185 
  186 const struct vlan_multisw vlan_ether_multisw = {
  187         .vmsw_addmulti = vlan_ether_addmulti,
  188         .vmsw_delmulti = vlan_ether_delmulti,
  189         .vmsw_purgemulti = vlan_ether_purgemulti,
  190 };
  191 
  192 static int      vlan_clone_create(struct if_clone *, int);
  193 static int      vlan_clone_destroy(struct ifnet *);
  194 static int      vlan_config(struct ifvlan *, struct ifnet *, uint16_t);
  195 static int      vlan_ioctl(struct ifnet *, u_long, void *);
  196 static void     vlan_start(struct ifnet *);
  197 static int      vlan_transmit(struct ifnet *, struct mbuf *);
  198 static void     vlan_link_state_changed(void *);
  199 static void     vlan_ifdetach(void *);
  200 static void     vlan_unconfig(struct ifnet *);
  201 static int      vlan_unconfig_locked(struct ifvlan *, struct ifvlan_linkmib *);
  202 static void     vlan_hash_init(void);
  203 static int      vlan_hash_fini(void);
  204 static int      vlan_tag_hash(uint16_t, u_long);
  205 static struct ifvlan_linkmib*
  206                 vlan_getref_linkmib(struct ifvlan *, struct psref *);
  207 static void     vlan_putref_linkmib(struct ifvlan_linkmib *, struct psref *);
  208 static void     vlan_linkmib_update(struct ifvlan *, struct ifvlan_linkmib *);
  209 static struct ifvlan_linkmib*
  210                 vlan_lookup_tag_psref(struct ifnet *, uint16_t,
  211                     struct psref *);
  212 
  213 #if !defined(VLAN_TAG_HASH_SIZE)
  214 #define VLAN_TAG_HASH_SIZE 32
  215 #endif
  216 static struct {
  217         kmutex_t lock;
  218         struct pslist_head *lists;
  219         u_long mask;
  220 } ifv_hash __cacheline_aligned = {
  221         .lists = NULL,
  222         .mask = 0,
  223 };
  224 
  225 pserialize_t vlan_psz __read_mostly;
  226 static struct psref_class *ifvm_psref_class __read_mostly;
  227 
  228 struct if_clone vlan_cloner =
  229     IF_CLONE_INITIALIZER("vlan", vlan_clone_create, vlan_clone_destroy);
  230 
  231 static uint32_t nvlanifs;
  232 
  233 static inline int
  234 vlan_safe_ifpromisc(struct ifnet *ifp, int pswitch)
  235 {
  236         int e;
  237 
  238         KERNEL_LOCK_UNLESS_NET_MPSAFE();
  239         e = ifpromisc(ifp, pswitch);
  240         KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
  241 
  242         return e;
  243 }
  244 
  245 __unused static inline int
  246 vlan_safe_ifpromisc_locked(struct ifnet *ifp, int pswitch)
  247 {
  248         int e;
  249 
  250         KERNEL_LOCK_UNLESS_NET_MPSAFE();
  251         e = ifpromisc_locked(ifp, pswitch);
  252         KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
  253 
  254         return e;
  255 }
  256 
  257 void
  258 vlanattach(int n)
  259 {
  260 
  261         /*
  262          * Nothing to do here, initialization is handled by the
  263          * module initialization code in vlaninit() below.
  264          */
  265 }
  266 
  267 static void
  268 vlaninit(void)
  269 {
  270         nvlanifs = 0;
  271 
  272         mutex_init(&ifv_hash.lock, MUTEX_DEFAULT, IPL_NONE);
  273         vlan_psz = pserialize_create();
  274         ifvm_psref_class = psref_class_create("vlanlinkmib", IPL_SOFTNET);
  275         if_clone_attach(&vlan_cloner);
  276 
  277         vlan_hash_init();
  278         MODULE_HOOK_SET(if_vlan_vlan_input_hook, vlan_input);
  279 }
  280 
  281 static int
  282 vlandetach(void)
  283 {
  284         int error;
  285 
  286         if (nvlanifs > 0)
  287                 return EBUSY;
  288 
  289         error = vlan_hash_fini();
  290         if (error != 0)
  291                 return error;
  292 
  293         if_clone_detach(&vlan_cloner);
  294         psref_class_destroy(ifvm_psref_class);
  295         pserialize_destroy(vlan_psz);
  296         mutex_destroy(&ifv_hash.lock);
  297 
  298         MODULE_HOOK_UNSET(if_vlan_vlan_input_hook);
  299         return 0;
  300 }
  301 
  302 static void
  303 vlan_reset_linkname(struct ifnet *ifp)
  304 {
  305 
  306         /*
  307          * We start out with a "802.1Q VLAN" type and zero-length
  308          * addresses.  When we attach to a parent interface, we
  309          * inherit its type, address length, address, and data link
  310          * type.
  311          */
  312 
  313         ifp->if_type = IFT_L2VLAN;
  314         ifp->if_addrlen = 0;
  315         ifp->if_dlt = DLT_NULL;
  316         if_alloc_sadl(ifp);
  317 }
  318 
  319 static int
  320 vlan_clone_create(struct if_clone *ifc, int unit)
  321 {
  322         struct ifvlan *ifv;
  323         struct ifnet *ifp;
  324         struct ifvlan_linkmib *mib;
  325 
  326         ifv = malloc(sizeof(struct ifvlan), M_DEVBUF, M_WAITOK | M_ZERO);
  327         mib = kmem_zalloc(sizeof(struct ifvlan_linkmib), KM_SLEEP);
  328         ifp = &ifv->ifv_if;
  329         LIST_INIT(&ifv->ifv_mc_listhead);
  330 
  331         mib->ifvm_ifvlan = ifv;
  332         mib->ifvm_p = NULL;
  333         psref_target_init(&mib->ifvm_psref, ifvm_psref_class);
  334 
  335         mutex_init(&ifv->ifv_lock, MUTEX_DEFAULT, IPL_NONE);
  336         ifv->ifv_psz = pserialize_create();
  337         ifv->ifv_mib = mib;
  338 
  339         atomic_inc_uint(&nvlanifs);
  340 
  341         if_initname(ifp, ifc->ifc_name, unit);
  342         ifp->if_softc = ifv;
  343         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
  344 #ifdef NET_MPSAFE
  345         ifp->if_extflags = IFEF_MPSAFE;
  346 #endif
  347         ifp->if_start = vlan_start;
  348         ifp->if_transmit = vlan_transmit;
  349         ifp->if_ioctl = vlan_ioctl;
  350         IFQ_SET_READY(&ifp->if_snd);
  351         if_initialize(ifp);
  352         /*
  353          * Set the link state to down.
  354          * When the parent interface attaches we will use that link state.
  355          * When the parent interface link state changes, so will ours.
  356          * When the parent interface detaches, set the link state to down.
  357          */
  358         ifp->if_link_state = LINK_STATE_DOWN;
  359 
  360         vlan_reset_linkname(ifp);
  361         if_register(ifp);
  362         return 0;
  363 }
  364 
  365 static int
  366 vlan_clone_destroy(struct ifnet *ifp)
  367 {
  368         struct ifvlan *ifv = ifp->if_softc;
  369 
  370         atomic_dec_uint(&nvlanifs);
  371 
  372         IFNET_LOCK(ifp);
  373         vlan_unconfig(ifp);
  374         IFNET_UNLOCK(ifp);
  375         if_detach(ifp);
  376 
  377         psref_target_destroy(&ifv->ifv_mib->ifvm_psref, ifvm_psref_class);
  378         kmem_free(ifv->ifv_mib, sizeof(struct ifvlan_linkmib));
  379         pserialize_destroy(ifv->ifv_psz);
  380         mutex_destroy(&ifv->ifv_lock);
  381         free(ifv, M_DEVBUF);
  382 
  383         return 0;
  384 }
  385 
  386 /*
  387  * Configure a VLAN interface.
  388  */
  389 static int
  390 vlan_config(struct ifvlan *ifv, struct ifnet *p, uint16_t tag)
  391 {
  392         struct ifnet *ifp = &ifv->ifv_if;
  393         struct ifvlan_linkmib *nmib = NULL;
  394         struct ifvlan_linkmib *omib = NULL;
  395         struct ifvlan_linkmib *checkmib;
  396         struct psref_target *nmib_psref = NULL;
  397         const uint16_t vid = EVL_VLANOFTAG(tag);
  398         int error = 0;
  399         int idx;
  400         bool omib_cleanup = false;
  401         struct psref psref;
  402 
  403         /* VLAN ID 0 and 4095 are reserved in the spec */
  404         if ((vid == 0) || (vid == 0xfff))
  405                 return EINVAL;
  406 
  407         nmib = kmem_alloc(sizeof(*nmib), KM_SLEEP);
  408         mutex_enter(&ifv->ifv_lock);
  409         omib = ifv->ifv_mib;
  410 
  411         if (omib->ifvm_p != NULL) {
  412                 error = EBUSY;
  413                 goto done;
  414         }
  415 
  416         /* Duplicate check */
  417         checkmib = vlan_lookup_tag_psref(p, vid, &psref);
  418         if (checkmib != NULL) {
  419                 vlan_putref_linkmib(checkmib, &psref);
  420                 error = EEXIST;
  421                 goto done;
  422         }
  423 
  424         *nmib = *omib;
  425         nmib_psref = &nmib->ifvm_psref;
  426 
  427         psref_target_init(nmib_psref, ifvm_psref_class);
  428 
  429         switch (p->if_type) {
  430         case IFT_ETHER:
  431             {
  432                 struct ethercom *ec = (void *)p;
  433 
  434                 nmib->ifvm_msw = &vlan_ether_multisw;
  435                 nmib->ifvm_mintu = ETHERMIN;
  436 
  437                 error = ether_add_vlantag(p, tag, NULL);
  438                 if (error != 0)
  439                         goto done;
  440 
  441                 if (ec->ec_capenable & ETHERCAP_VLAN_MTU) {
  442                         nmib->ifvm_mtufudge = 0;
  443                 } else {
  444                         /*
  445                          * Fudge the MTU by the encapsulation size. This
  446                          * makes us incompatible with strictly compliant
  447                          * 802.1Q implementations, but allows us to use
  448                          * the feature with other NetBSD
  449                          * implementations, which might still be useful.
  450                          */
  451                         nmib->ifvm_mtufudge = ETHER_VLAN_ENCAP_LEN;
  452                 }
  453 
  454                 /*
  455                  * If the parent interface can do hardware-assisted
  456                  * VLAN encapsulation, then propagate its hardware-
  457                  * assisted checksumming flags and tcp segmentation
  458                  * offload.
  459                  */
  460                 if (ec->ec_capabilities & ETHERCAP_VLAN_HWTAGGING) {
  461                         ifp->if_capabilities = p->if_capabilities &
  462                             (IFCAP_TSOv4 | IFCAP_TSOv6 |
  463                                 IFCAP_CSUM_IPv4_Tx  | IFCAP_CSUM_IPv4_Rx |
  464                                 IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx |
  465                                 IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx |
  466                                 IFCAP_CSUM_TCPv6_Tx | IFCAP_CSUM_TCPv6_Rx |
  467                                 IFCAP_CSUM_UDPv6_Tx | IFCAP_CSUM_UDPv6_Rx);
  468                 }
  469 
  470                 /*
  471                  * We inherit the parent's Ethernet address.
  472                  */
  473                 ether_ifattach(ifp, CLLADDR(p->if_sadl));
  474                 ifp->if_hdrlen = sizeof(struct ether_vlan_header); /* XXX? */
  475                 break;
  476             }
  477 
  478         default:
  479                 error = EPROTONOSUPPORT;
  480                 goto done;
  481         }
  482 
  483         nmib->ifvm_p = p;
  484         nmib->ifvm_tag = vid;
  485         ifv->ifv_if.if_mtu = p->if_mtu - nmib->ifvm_mtufudge;
  486         ifv->ifv_if.if_flags = p->if_flags &
  487             (IFF_UP | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
  488 
  489         /*
  490          * Inherit the if_type from the parent.  This allows us
  491          * to participate in bridges of that type.
  492          */
  493         ifv->ifv_if.if_type = p->if_type;
  494 
  495         PSLIST_ENTRY_INIT(ifv, ifv_hash);
  496         idx = vlan_tag_hash(vid, ifv_hash.mask);
  497 
  498         mutex_enter(&ifv_hash.lock);
  499         PSLIST_WRITER_INSERT_HEAD(&ifv_hash.lists[idx], ifv, ifv_hash);
  500         mutex_exit(&ifv_hash.lock);
  501 
  502         vlan_linkmib_update(ifv, nmib);
  503         nmib = NULL;
  504         nmib_psref = NULL;
  505         omib_cleanup = true;
  506 
  507         ifv->ifv_ifdetach_hook = ether_ifdetachhook_establish(p,
  508             vlan_ifdetach, ifp);
  509 
  510         /*
  511          * We inherit the parents link state.
  512          */
  513         ifv->ifv_linkstate_hook = if_linkstate_change_establish(p,
  514             vlan_link_state_changed, ifv);
  515         if_link_state_change(&ifv->ifv_if, p->if_link_state);
  516 
  517 done:
  518         mutex_exit(&ifv->ifv_lock);
  519 
  520         if (nmib_psref)
  521                 psref_target_destroy(nmib_psref, ifvm_psref_class);
  522         if (nmib)
  523                 kmem_free(nmib, sizeof(*nmib));
  524         if (omib_cleanup)
  525                 kmem_free(omib, sizeof(*omib));
  526 
  527         return error;
  528 }
  529 
  530 /*
  531  * Unconfigure a VLAN interface.
  532  */
  533 static void
  534 vlan_unconfig(struct ifnet *ifp)
  535 {
  536         struct ifvlan *ifv = ifp->if_softc;
  537         struct ifvlan_linkmib *nmib = NULL;
  538         int error;
  539 
  540         KASSERT(IFNET_LOCKED(ifp));
  541 
  542         nmib = kmem_alloc(sizeof(*nmib), KM_SLEEP);
  543 
  544         mutex_enter(&ifv->ifv_lock);
  545         error = vlan_unconfig_locked(ifv, nmib);
  546         mutex_exit(&ifv->ifv_lock);
  547 
  548         if (error)
  549                 kmem_free(nmib, sizeof(*nmib));
  550 }
  551 static int
  552 vlan_unconfig_locked(struct ifvlan *ifv, struct ifvlan_linkmib *nmib)
  553 {
  554         struct ifnet *p;
  555         struct ifnet *ifp = &ifv->ifv_if;
  556         struct psref_target *nmib_psref = NULL;
  557         struct ifvlan_linkmib *omib;
  558         int error = 0;
  559 
  560         KASSERT(IFNET_LOCKED(ifp));
  561         KASSERT(mutex_owned(&ifv->ifv_lock));
  562 
  563         if (ifv->ifv_stopping) {
  564                 error = -1;
  565                 goto done;
  566         }
  567 
  568         ifp->if_flags &= ~(IFF_UP | IFF_RUNNING);
  569 
  570         omib = ifv->ifv_mib;
  571         p = omib->ifvm_p;
  572 
  573         if (p == NULL) {
  574                 error = -1;
  575                 goto done;
  576         }
  577 
  578         *nmib = *omib;
  579         nmib_psref = &nmib->ifvm_psref;
  580         psref_target_init(nmib_psref, ifvm_psref_class);
  581 
  582         /*
  583          * Since the interface is being unconfigured, we need to empty the
  584          * list of multicast groups that we may have joined while we were
  585          * alive and remove them from the parent's list also.
  586          */
  587         (*nmib->ifvm_msw->vmsw_purgemulti)(ifv);
  588 
  589         /* Disconnect from parent. */
  590         switch (p->if_type) {
  591         case IFT_ETHER:
  592             {
  593                 (void)ether_del_vlantag(p, nmib->ifvm_tag);
  594 
  595                 /* XXX ether_ifdetach must not be called with IFNET_LOCK */
  596                 ifv->ifv_stopping = true;
  597                 mutex_exit(&ifv->ifv_lock);
  598                 IFNET_UNLOCK(ifp);
  599                 ether_ifdetach(ifp);
  600                 IFNET_LOCK(ifp);
  601                 mutex_enter(&ifv->ifv_lock);
  602                 ifv->ifv_stopping = false;
  603 
  604                 /* if_free_sadl must be called with IFNET_LOCK */
  605                 if_free_sadl(ifp, 1);
  606 
  607                 /* Restore vlan_ioctl overwritten by ether_ifdetach */
  608                 ifp->if_ioctl = vlan_ioctl;
  609                 vlan_reset_linkname(ifp);
  610                 break;
  611             }
  612 
  613         default:
  614                 panic("%s: impossible", __func__);
  615         }
  616 
  617         nmib->ifvm_p = NULL;
  618         ifv->ifv_if.if_mtu = 0;
  619         ifv->ifv_flags = 0;
  620 
  621         mutex_enter(&ifv_hash.lock);
  622         PSLIST_WRITER_REMOVE(ifv, ifv_hash);
  623         pserialize_perform(vlan_psz);
  624         mutex_exit(&ifv_hash.lock);
  625         PSLIST_ENTRY_DESTROY(ifv, ifv_hash);
  626         if_linkstate_change_disestablish(p,
  627             ifv->ifv_linkstate_hook, NULL);
  628 
  629         vlan_linkmib_update(ifv, nmib);
  630         if_link_state_change(ifp, LINK_STATE_DOWN);
  631 
  632         /*XXX ether_ifdetachhook_disestablish must not called with IFNET_LOCK */
  633         IFNET_UNLOCK(ifp);
  634         ether_ifdetachhook_disestablish(p, ifv->ifv_ifdetach_hook,
  635             &ifv->ifv_lock);
  636         mutex_exit(&ifv->ifv_lock);
  637         IFNET_LOCK(ifp);
  638 
  639         nmib_psref = NULL;
  640         kmem_free(omib, sizeof(*omib));
  641 
  642 #ifdef INET6
  643         KERNEL_LOCK_UNLESS_NET_MPSAFE();
  644         /* To delete v6 link local addresses */
  645         if (in6_present)
  646                 in6_ifdetach(ifp);
  647         KERNEL_UNLOCK_UNLESS_NET_MPSAFE();
  648 #endif
  649 
  650         if_down_locked(ifp);
  651         ifp->if_capabilities = 0;
  652         mutex_enter(&ifv->ifv_lock);
  653 done:
  654         if (nmib_psref)
  655                 psref_target_destroy(nmib_psref, ifvm_psref_class);
  656 
  657         return error;
  658 }
  659 
  660 static void
  661 vlan_hash_init(void)
  662 {
  663 
  664         ifv_hash.lists = hashinit(VLAN_TAG_HASH_SIZE, HASH_PSLIST, true,
  665             &ifv_hash.mask);
  666 }
  667 
  668 static int
  669 vlan_hash_fini(void)
  670 {
  671         int i;
  672 
  673         mutex_enter(&ifv_hash.lock);
  674 
  675         for (i = 0; i < ifv_hash.mask + 1; i++) {
  676                 if (PSLIST_WRITER_FIRST(&ifv_hash.lists[i], struct ifvlan,
  677                     ifv_hash) != NULL) {
  678                         mutex_exit(&ifv_hash.lock);
  679                         return EBUSY;
  680                 }
  681         }
  682 
  683         for (i = 0; i < ifv_hash.mask + 1; i++)
  684                 PSLIST_DESTROY(&ifv_hash.lists[i]);
  685 
  686         mutex_exit(&ifv_hash.lock);
  687 
  688         hashdone(ifv_hash.lists, HASH_PSLIST, ifv_hash.mask);
  689 
  690         ifv_hash.lists = NULL;
  691         ifv_hash.mask = 0;
  692 
  693         return 0;
  694 }
  695 
  696 static int
  697 vlan_tag_hash(uint16_t tag, u_long mask)
  698 {
  699         uint32_t hash;
  700 
  701         hash = (tag >> 8) ^ tag;
  702         hash = (hash >> 2) ^ hash;
  703 
  704         return hash & mask;
  705 }
  706 
  707 static struct ifvlan_linkmib *
  708 vlan_getref_linkmib(struct ifvlan *sc, struct psref *psref)
  709 {
  710         struct ifvlan_linkmib *mib;
  711         int s;
  712 
  713         s = pserialize_read_enter();
  714         mib = atomic_load_consume(&sc->ifv_mib);
  715         if (mib == NULL) {
  716                 pserialize_read_exit(s);
  717                 return NULL;
  718         }
  719         psref_acquire(psref, &mib->ifvm_psref, ifvm_psref_class);
  720         pserialize_read_exit(s);
  721 
  722         return mib;
  723 }
  724 
  725 static void
  726 vlan_putref_linkmib(struct ifvlan_linkmib *mib, struct psref *psref)
  727 {
  728         if (mib == NULL)
  729                 return;
  730         psref_release(psref, &mib->ifvm_psref, ifvm_psref_class);
  731 }
  732 
  733 static struct ifvlan_linkmib *
  734 vlan_lookup_tag_psref(struct ifnet *ifp, uint16_t tag, struct psref *psref)
  735 {
  736         int idx;
  737         int s;
  738         struct ifvlan *sc;
  739 
  740         idx = vlan_tag_hash(tag, ifv_hash.mask);
  741 
  742         s = pserialize_read_enter();
  743         PSLIST_READER_FOREACH(sc, &ifv_hash.lists[idx], struct ifvlan,
  744             ifv_hash) {
  745                 struct ifvlan_linkmib *mib = atomic_load_consume(&sc->ifv_mib);
  746                 if (mib == NULL)
  747                         continue;
  748                 if (mib->ifvm_tag != tag)
  749                         continue;
  750                 if (mib->ifvm_p != ifp)
  751                         continue;
  752 
  753                 psref_acquire(psref, &mib->ifvm_psref, ifvm_psref_class);
  754                 pserialize_read_exit(s);
  755                 return mib;
  756         }
  757         pserialize_read_exit(s);
  758         return NULL;
  759 }
  760 
  761 static void
  762 vlan_linkmib_update(struct ifvlan *ifv, struct ifvlan_linkmib *nmib)
  763 {
  764         struct ifvlan_linkmib *omib = ifv->ifv_mib;
  765 
  766         KASSERT(mutex_owned(&ifv->ifv_lock));
  767 
  768         atomic_store_release(&ifv->ifv_mib, nmib);
  769 
  770         pserialize_perform(ifv->ifv_psz);
  771         psref_target_destroy(&omib->ifvm_psref, ifvm_psref_class);
  772 }
  773 
  774 /*
  775  * Called when a parent interface is detaching; destroy any VLAN
  776  * configuration for the parent interface.
  777  */
  778 static void
  779 vlan_ifdetach(void *xifp)
  780 {
  781         struct ifnet *ifp;
  782 
  783         ifp = (struct ifnet *)xifp;
  784 
  785         /* IFNET_LOCK must be held before ifv_lock. */
  786         IFNET_LOCK(ifp);
  787         vlan_unconfig(ifp);
  788         IFNET_UNLOCK(ifp);
  789 }
  790 
  791 static int
  792 vlan_set_promisc(struct ifnet *ifp)
  793 {
  794         struct ifvlan *ifv = ifp->if_softc;
  795         struct ifvlan_linkmib *mib;
  796         struct psref psref;
  797         int error = 0;
  798         int bound;
  799 
  800         bound = curlwp_bind();
  801         mib = vlan_getref_linkmib(ifv, &psref);
  802         if (mib == NULL) {
  803                 curlwp_bindx(bound);
  804                 return EBUSY;
  805         }
  806 
  807         if ((ifp->if_flags & IFF_PROMISC) != 0) {
  808                 if ((ifv->ifv_flags & IFVF_PROMISC) == 0) {
  809                         error = vlan_safe_ifpromisc(mib->ifvm_p, 1);
  810                         if (error == 0)
  811                                 ifv->ifv_flags |= IFVF_PROMISC;
  812                 }
  813         } else {
  814                 if ((ifv->ifv_flags & IFVF_PROMISC) != 0) {
  815                         error = vlan_safe_ifpromisc(mib->ifvm_p, 0);
  816                         if (error == 0)
  817                                 ifv->ifv_flags &= ~IFVF_PROMISC;
  818                 }
  819         }
  820         vlan_putref_linkmib(mib, &psref);
  821         curlwp_bindx(bound);
  822 
  823         return error;
  824 }
  825 
  826 static int
  827 vlan_ioctl(struct ifnet *ifp, u_long cmd, void *data)
  828 {
  829         struct lwp *l = curlwp;
  830         struct ifvlan *ifv = ifp->if_softc;
  831         struct ifaddr *ifa = (struct ifaddr *) data;
  832         struct ifreq *ifr = (struct ifreq *) data;
  833         struct ifnet *pr;
  834         struct ifcapreq *ifcr;
  835         struct vlanreq vlr;
  836         struct ifvlan_linkmib *mib;
  837         struct psref psref;
  838         int error = 0;
  839         int bound;
  840 
  841         switch (cmd) {
  842         case SIOCSIFMTU:
  843                 bound = curlwp_bind();
  844                 mib = vlan_getref_linkmib(ifv, &psref);
  845                 if (mib == NULL) {
  846                         curlwp_bindx(bound);
  847                         error = EBUSY;
  848                         break;
  849                 }
  850 
  851                 if (mib->ifvm_p == NULL) {
  852                         vlan_putref_linkmib(mib, &psref);
  853                         curlwp_bindx(bound);
  854                         error = EINVAL;
  855                 } else if (
  856                     ifr->ifr_mtu > (mib->ifvm_p->if_mtu - mib->ifvm_mtufudge) ||
  857                     ifr->ifr_mtu < (mib->ifvm_mintu - mib->ifvm_mtufudge)) {
  858                         vlan_putref_linkmib(mib, &psref);
  859                         curlwp_bindx(bound);
  860                         error = EINVAL;
  861                 } else {
  862                         vlan_putref_linkmib(mib, &psref);
  863                         curlwp_bindx(bound);
  864 
  865                         error = ifioctl_common(ifp, cmd, data);
  866                         if (error == ENETRESET)
  867                                 error = 0;
  868                 }
  869 
  870                 break;
  871 
  872         case SIOCSETVLAN:
  873                 if ((error = kauth_authorize_network(l->l_cred,
  874                     KAUTH_NETWORK_INTERFACE,
  875                     KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
  876                     NULL)) != 0)
  877                         break;
  878                 if ((error = copyin(ifr->ifr_data, &vlr, sizeof(vlr))) != 0)
  879                         break;
  880 
  881                 if (vlr.vlr_parent[0] == '\0') {
  882                         bound = curlwp_bind();
  883                         mib = vlan_getref_linkmib(ifv, &psref);
  884                         if (mib == NULL) {
  885                                 curlwp_bindx(bound);
  886                                 error = EBUSY;
  887                                 break;
  888                         }
  889 
  890                         if (mib->ifvm_p != NULL &&
  891                             (ifp->if_flags & IFF_PROMISC) != 0)
  892                                 error = vlan_safe_ifpromisc(mib->ifvm_p, 0);
  893 
  894                         vlan_putref_linkmib(mib, &psref);
  895                         curlwp_bindx(bound);
  896 
  897                         vlan_unconfig(ifp);
  898                         break;
  899                 }
  900                 if (vlr.vlr_tag != EVL_VLANOFTAG(vlr.vlr_tag)) {
  901                         error = EINVAL;          /* check for valid tag */
  902                         break;
  903                 }
  904                 if ((pr = ifunit(vlr.vlr_parent)) == NULL) {
  905                         error = ENOENT;
  906                         break;
  907                 }
  908 
  909                 error = vlan_config(ifv, pr, vlr.vlr_tag);
  910                 if (error != 0)
  911                         break;
  912 
  913                 /* Update promiscuous mode, if necessary. */
  914                 vlan_set_promisc(ifp);
  915 
  916                 ifp->if_flags |= IFF_RUNNING;
  917                 break;
  918 
  919         case SIOCGETVLAN:
  920                 memset(&vlr, 0, sizeof(vlr));
  921                 bound = curlwp_bind();
  922                 mib = vlan_getref_linkmib(ifv, &psref);
  923                 if (mib == NULL) {
  924                         curlwp_bindx(bound);
  925                         error = EBUSY;
  926                         break;
  927                 }
  928                 if (mib->ifvm_p != NULL) {
  929                         snprintf(vlr.vlr_parent, sizeof(vlr.vlr_parent), "%s",
  930                             mib->ifvm_p->if_xname);
  931                         vlr.vlr_tag = mib->ifvm_tag;
  932                 }
  933                 vlan_putref_linkmib(mib, &psref);
  934                 curlwp_bindx(bound);
  935                 error = copyout(&vlr, ifr->ifr_data, sizeof(vlr));
  936                 break;
  937 
  938         case SIOCSIFFLAGS:
  939                 if ((error = ifioctl_common(ifp, cmd, data)) != 0)
  940                         break;
  941                 /*
  942                  * For promiscuous mode, we enable promiscuous mode on
  943                  * the parent if we need promiscuous on the VLAN interface.
  944                  */
  945                 bound = curlwp_bind();
  946                 mib = vlan_getref_linkmib(ifv, &psref);
  947                 if (mib == NULL) {
  948                         curlwp_bindx(bound);
  949                         error = EBUSY;
  950                         break;
  951                 }
  952 
  953                 if (mib->ifvm_p != NULL)
  954                         error = vlan_set_promisc(ifp);
  955                 vlan_putref_linkmib(mib, &psref);
  956                 curlwp_bindx(bound);
  957                 break;
  958 
  959         case SIOCADDMULTI:
  960                 mutex_enter(&ifv->ifv_lock);
  961                 mib = ifv->ifv_mib;
  962                 if (mib == NULL) {
  963                         error = EBUSY;
  964                         mutex_exit(&ifv->ifv_lock);
  965                         break;
  966                 }
  967 
  968                 error = (mib->ifvm_p != NULL) ?
  969                     (*mib->ifvm_msw->vmsw_addmulti)(ifv, ifr) : EINVAL;
  970                 mib = NULL;
  971                 mutex_exit(&ifv->ifv_lock);
  972                 break;
  973 
  974         case SIOCDELMULTI:
  975                 mutex_enter(&ifv->ifv_lock);
  976                 mib = ifv->ifv_mib;
  977                 if (mib == NULL) {
  978                         error = EBUSY;
  979                         mutex_exit(&ifv->ifv_lock);
  980                         break;
  981                 }
  982                 error = (mib->ifvm_p != NULL) ?
  983                     (*mib->ifvm_msw->vmsw_delmulti)(ifv, ifr) : EINVAL;
  984                 mib = NULL;
  985                 mutex_exit(&ifv->ifv_lock);
  986                 break;
  987 
  988         case SIOCSIFCAP:
  989                 ifcr = data;
  990                 /* make sure caps are enabled on parent */
  991                 bound = curlwp_bind();
  992                 mib = vlan_getref_linkmib(ifv, &psref);
  993                 if (mib == NULL) {
  994                         curlwp_bindx(bound);
  995                         error = EBUSY;
  996                         break;
  997                 }
  998 
  999                 if (mib->ifvm_p == NULL) {
 1000                         vlan_putref_linkmib(mib, &psref);
 1001                         curlwp_bindx(bound);
 1002                         error = EINVAL;
 1003                         break;
 1004                 }
 1005                 if ((mib->ifvm_p->if_capenable & ifcr->ifcr_capenable) !=
 1006                     ifcr->ifcr_capenable) {
 1007                         vlan_putref_linkmib(mib, &psref);
 1008                         curlwp_bindx(bound);
 1009                         error = EINVAL;
 1010                         break;
 1011                 }
 1012 
 1013                 vlan_putref_linkmib(mib, &psref);
 1014                 curlwp_bindx(bound);
 1015 
 1016                 if ((error = ifioctl_common(ifp, cmd, data)) == ENETRESET)
 1017                         error = 0;
 1018                 break;
 1019         case SIOCINITIFADDR:
 1020                 bound = curlwp_bind();
 1021                 mib = vlan_getref_linkmib(ifv, &psref);
 1022                 if (mib == NULL) {
 1023                         curlwp_bindx(bound);
 1024                         error = EBUSY;
 1025                         break;
 1026                 }
 1027 
 1028                 if (mib->ifvm_p == NULL) {
 1029                         error = EINVAL;
 1030                         vlan_putref_linkmib(mib, &psref);
 1031                         curlwp_bindx(bound);
 1032                         break;
 1033                 }
 1034                 vlan_putref_linkmib(mib, &psref);
 1035                 curlwp_bindx(bound);
 1036 
 1037                 ifp->if_flags |= IFF_UP;
 1038 #ifdef INET
 1039                 if (ifa->ifa_addr->sa_family == AF_INET)
 1040                         arp_ifinit(ifp, ifa);
 1041 #endif
 1042                 break;
 1043 
 1044         default:
 1045                 error = ether_ioctl(ifp, cmd, data);
 1046         }
 1047 
 1048         return error;
 1049 }
 1050 
 1051 static int
 1052 vlan_ether_addmulti(struct ifvlan *ifv, struct ifreq *ifr)
 1053 {
 1054         const struct sockaddr *sa = ifreq_getaddr(SIOCADDMULTI, ifr);
 1055         struct vlan_mc_entry *mc;
 1056         uint8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
 1057         struct ifvlan_linkmib *mib;
 1058         int error;
 1059 
 1060         KASSERT(mutex_owned(&ifv->ifv_lock));
 1061 
 1062         if (sa->sa_len > sizeof(struct sockaddr_storage))
 1063                 return EINVAL;
 1064 
 1065         error = ether_addmulti(sa, &ifv->ifv_ec);
 1066         if (error != ENETRESET)
 1067                 return error;
 1068 
 1069         /*
 1070          * This is a new multicast address.  We have to tell parent
 1071          * about it.  Also, remember this multicast address so that
 1072          * we can delete it on unconfigure.
 1073          */
 1074         mc = malloc(sizeof(struct vlan_mc_entry), M_DEVBUF, M_NOWAIT);
 1075         if (mc == NULL) {
 1076                 error = ENOMEM;
 1077                 goto alloc_failed;
 1078         }
 1079 
 1080         /*
 1081          * Since ether_addmulti() returned ENETRESET, the following two
 1082          * statements shouldn't fail. Here ifv_ec is implicitly protected
 1083          * by the ifv_lock lock.
 1084          */
 1085         error = ether_multiaddr(sa, addrlo, addrhi);
 1086         KASSERT(error == 0);
 1087 
 1088         ETHER_LOCK(&ifv->ifv_ec);
 1089         mc->mc_enm = ether_lookup_multi(addrlo, addrhi, &ifv->ifv_ec);
 1090         ETHER_UNLOCK(&ifv->ifv_ec);
 1091 
 1092         KASSERT(mc->mc_enm != NULL);
 1093 
 1094         memcpy(&mc->mc_addr, sa, sa->sa_len);
 1095         LIST_INSERT_HEAD(&ifv->ifv_mc_listhead, mc, mc_entries);
 1096 
 1097         mib = ifv->ifv_mib;
 1098 
 1099         KERNEL_LOCK_UNLESS_IFP_MPSAFE(mib->ifvm_p);
 1100         error = if_mcast_op(mib->ifvm_p, SIOCADDMULTI, sa);
 1101         KERNEL_UNLOCK_UNLESS_IFP_MPSAFE(mib->ifvm_p);
 1102 
 1103         if (error != 0)
 1104                 goto ioctl_failed;
 1105         return error;
 1106 
 1107 ioctl_failed:
 1108         LIST_REMOVE(mc, mc_entries);
 1109         free(mc, M_DEVBUF);
 1110 
 1111 alloc_failed:
 1112         (void)ether_delmulti(sa, &ifv->ifv_ec);
 1113         return error;
 1114 }
 1115 
 1116 static int
 1117 vlan_ether_delmulti(struct ifvlan *ifv, struct ifreq *ifr)
 1118 {
 1119         const struct sockaddr *sa = ifreq_getaddr(SIOCDELMULTI, ifr);
 1120         struct ether_multi *enm;
 1121         struct vlan_mc_entry *mc;
 1122         struct ifvlan_linkmib *mib;
 1123         uint8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
 1124         int error;
 1125 
 1126         KASSERT(mutex_owned(&ifv->ifv_lock));
 1127 
 1128         /*
 1129          * Find a key to lookup vlan_mc_entry.  We have to do this
 1130          * before calling ether_delmulti for obvious reasons.
 1131          */
 1132         if ((error = ether_multiaddr(sa, addrlo, addrhi)) != 0)
 1133                 return error;
 1134 
 1135         ETHER_LOCK(&ifv->ifv_ec);
 1136         enm = ether_lookup_multi(addrlo, addrhi, &ifv->ifv_ec);
 1137         ETHER_UNLOCK(&ifv->ifv_ec);
 1138         if (enm == NULL)
 1139                 return EINVAL;
 1140 
 1141         LIST_FOREACH(mc, &ifv->ifv_mc_listhead, mc_entries) {
 1142                 if (mc->mc_enm == enm)
 1143                         break;
 1144         }
 1145 
 1146         /* We woun't delete entries we didn't add */
 1147         if (mc == NULL)
 1148                 return EINVAL;
 1149 
 1150         error = ether_delmulti(sa, &ifv->ifv_ec);
 1151         if (error != ENETRESET)
 1152                 return error;
 1153 
 1154         /* We no longer use this multicast address.  Tell parent so. */
 1155         mib = ifv->ifv_mib;
 1156         error = if_mcast_op(mib->ifvm_p, SIOCDELMULTI, sa);
 1157 
 1158         if (error == 0) {
 1159                 /* And forget about this address. */
 1160                 LIST_REMOVE(mc, mc_entries);
 1161                 free(mc, M_DEVBUF);
 1162         } else {
 1163                 (void)ether_addmulti(sa, &ifv->ifv_ec);
 1164         }
 1165 
 1166         return error;
 1167 }
 1168 
 1169 /*
 1170  * Delete any multicast address we have asked to add from parent
 1171  * interface.  Called when the vlan is being unconfigured.
 1172  */
 1173 static void
 1174 vlan_ether_purgemulti(struct ifvlan *ifv)
 1175 {
 1176         struct vlan_mc_entry *mc;
 1177         struct ifvlan_linkmib *mib;
 1178 
 1179         KASSERT(mutex_owned(&ifv->ifv_lock));
 1180         mib = ifv->ifv_mib;
 1181         if (mib == NULL) {
 1182                 return;
 1183         }
 1184 
 1185         while ((mc = LIST_FIRST(&ifv->ifv_mc_listhead)) != NULL) {
 1186                 (void)if_mcast_op(mib->ifvm_p, SIOCDELMULTI,
 1187                     sstocsa(&mc->mc_addr));
 1188                 LIST_REMOVE(mc, mc_entries);
 1189                 free(mc, M_DEVBUF);
 1190         }
 1191 }
 1192 
 1193 static void
 1194 vlan_start(struct ifnet *ifp)
 1195 {
 1196         struct ifvlan *ifv = ifp->if_softc;
 1197         struct ifnet *p;
 1198         struct ethercom *ec;
 1199         struct mbuf *m;
 1200         struct ifvlan_linkmib *mib;
 1201         struct psref psref;
 1202         struct ether_header *eh;
 1203         int error, bound;
 1204 
 1205         bound = curlwp_bind();
 1206         mib = vlan_getref_linkmib(ifv, &psref);
 1207         if (mib == NULL) {
 1208                 curlwp_bindx(bound);
 1209                 return;
 1210         }
 1211 
 1212         if (__predict_false(mib->ifvm_p == NULL)) {
 1213                 vlan_putref_linkmib(mib, &psref);
 1214                 curlwp_bindx(bound);
 1215                 return;
 1216         }
 1217 
 1218         p = mib->ifvm_p;
 1219         ec = (void *)mib->ifvm_p;
 1220 
 1221         ifp->if_flags |= IFF_OACTIVE;
 1222 
 1223         for (;;) {
 1224                 IFQ_DEQUEUE(&ifp->if_snd, m);
 1225                 if (m == NULL)
 1226                         break;
 1227 
 1228                 if (m->m_len < sizeof(*eh)) {
 1229                         m = m_pullup(m, sizeof(*eh));
 1230                         if (m == NULL) {
 1231                                 if_statinc(ifp, if_oerrors);
 1232                                 continue;
 1233                         }
 1234                 }
 1235 
 1236                 eh = mtod(m, struct ether_header *);
 1237                 if (ntohs(eh->ether_type) == ETHERTYPE_VLAN) {
 1238                         m_freem(m);
 1239                         if_statinc(ifp, if_noproto);
 1240                         continue;
 1241                 }
 1242 
 1243 #ifdef ALTQ
 1244                 /*
 1245                  * KERNEL_LOCK is required for ALTQ even if NET_MPSAFE is
 1246                  * defined.
 1247                  */
 1248                 KERNEL_LOCK(1, NULL);
 1249                 /*
 1250                  * If ALTQ is enabled on the parent interface, do
 1251                  * classification; the queueing discipline might
 1252                  * not require classification, but might require
 1253                  * the address family/header pointer in the pktattr.
 1254                  */
 1255                 if (ALTQ_IS_ENABLED(&p->if_snd)) {
 1256                         switch (p->if_type) {
 1257                         case IFT_ETHER:
 1258                                 altq_etherclassify(&p->if_snd, m);
 1259                                 break;
 1260                         default:
 1261                                 panic("%s: impossible (altq)", __func__);
 1262                         }
 1263                 }
 1264                 KERNEL_UNLOCK_ONE(NULL);
 1265 #endif /* ALTQ */
 1266 
 1267                 bpf_mtap(ifp, m, BPF_D_OUT);
 1268                 /*
 1269                  * If the parent can insert the tag itself, just mark
 1270                  * the tag in the mbuf header.
 1271                  */
 1272                 if (ec->ec_capenable & ETHERCAP_VLAN_HWTAGGING) {
 1273                         vlan_set_tag(m, mib->ifvm_tag);
 1274                 } else {
 1275                         /*
 1276                          * insert the tag ourselves
 1277                          */
 1278 
 1279                         switch (p->if_type) {
 1280                         case IFT_ETHER:
 1281                                 (void)ether_inject_vlantag(&m,
 1282                                     ETHERTYPE_VLAN, mib->ifvm_tag);
 1283                                 if (m == NULL) {
 1284                                         printf("%s: unable to inject VLAN tag",
 1285                                             p->if_xname);
 1286                                         continue;
 1287                                 }
 1288                                 break;
 1289 
 1290                         default:
 1291                                 panic("%s: impossible", __func__);
 1292                         }
 1293                 }
 1294 
 1295                 if ((p->if_flags & IFF_RUNNING) == 0) {
 1296                         m_freem(m);
 1297                         continue;
 1298                 }
 1299 
 1300                 error = if_transmit_lock(p, m);
 1301                 if (error) {
 1302                         /* mbuf is already freed */
 1303                         if_statinc(ifp, if_oerrors);
 1304                         continue;
 1305                 }
 1306                 if_statinc(ifp, if_opackets);
 1307         }
 1308 
 1309         ifp->if_flags &= ~IFF_OACTIVE;
 1310 
 1311         /* Remove reference to mib before release */
 1312         vlan_putref_linkmib(mib, &psref);
 1313         curlwp_bindx(bound);
 1314 }
 1315 
 1316 static int
 1317 vlan_transmit(struct ifnet *ifp, struct mbuf *m)
 1318 {
 1319         struct ifvlan *ifv = ifp->if_softc;
 1320         struct ifnet *p;
 1321         struct ethercom *ec;
 1322         struct ifvlan_linkmib *mib;
 1323         struct psref psref;
 1324         struct ether_header *eh;
 1325         int error, bound;
 1326         size_t pktlen = m->m_pkthdr.len;
 1327         bool mcast = (m->m_flags & M_MCAST) != 0;
 1328 
 1329         if (m->m_len < sizeof(*eh)) {
 1330                 m = m_pullup(m, sizeof(*eh));
 1331                 if (m == NULL) {
 1332                         if_statinc(ifp, if_oerrors);
 1333                         return ENOBUFS;
 1334                 }
 1335         }
 1336 
 1337         eh = mtod(m, struct ether_header *);
 1338         if (ntohs(eh->ether_type) == ETHERTYPE_VLAN) {
 1339                 m_freem(m);
 1340                 if_statinc(ifp, if_noproto);
 1341                 return EPROTONOSUPPORT;
 1342         }
 1343 
 1344         bound = curlwp_bind();
 1345         mib = vlan_getref_linkmib(ifv, &psref);
 1346         if (mib == NULL) {
 1347                 curlwp_bindx(bound);
 1348                 m_freem(m);
 1349                 return ENETDOWN;
 1350         }
 1351 
 1352         if (__predict_false(mib->ifvm_p == NULL)) {
 1353                 vlan_putref_linkmib(mib, &psref);
 1354                 curlwp_bindx(bound);
 1355                 m_freem(m);
 1356                 return ENETDOWN;
 1357         }
 1358 
 1359         p = mib->ifvm_p;
 1360         ec = (void *)mib->ifvm_p;
 1361 
 1362         bpf_mtap(ifp, m, BPF_D_OUT);
 1363 
 1364         if ((error = pfil_run_hooks(ifp->if_pfil, &m, ifp, PFIL_OUT)) != 0)
 1365                 goto out;
 1366         if (m == NULL)
 1367                 goto out;
 1368 
 1369         /*
 1370          * If the parent can insert the tag itself, just mark
 1371          * the tag in the mbuf header.
 1372          */
 1373         if (ec->ec_capenable & ETHERCAP_VLAN_HWTAGGING) {
 1374                 vlan_set_tag(m, mib->ifvm_tag);
 1375         } else {
 1376                 /*
 1377                  * insert the tag ourselves
 1378                  */
 1379                 switch (p->if_type) {
 1380                 case IFT_ETHER:
 1381                         error = ether_inject_vlantag(&m,
 1382                             ETHERTYPE_VLAN, mib->ifvm_tag);
 1383                         if (error != 0) {
 1384                                 KASSERT(m == NULL);
 1385                                 printf("%s: unable to inject VLAN tag",
 1386                                     p->if_xname);
 1387                                 goto out;
 1388                         }
 1389                         break;
 1390 
 1391                 default:
 1392                         panic("%s: impossible", __func__);
 1393                 }
 1394         }
 1395 
 1396         if ((p->if_flags & IFF_RUNNING) == 0) {
 1397                 m_freem(m);
 1398                 error = ENETDOWN;
 1399                 goto out;
 1400         }
 1401 
 1402         error = if_transmit_lock(p, m);
 1403         net_stat_ref_t nsr = IF_STAT_GETREF(ifp);
 1404         if (error) {
 1405                 /* mbuf is already freed */
 1406                 if_statinc_ref(nsr, if_oerrors);
 1407         } else {
 1408                 if_statinc_ref(nsr, if_opackets);
 1409                 if_statadd_ref(nsr, if_obytes, pktlen);
 1410                 if (mcast)
 1411                         if_statinc_ref(nsr, if_omcasts);
 1412         }
 1413         IF_STAT_PUTREF(ifp);
 1414 
 1415 out:
 1416         /* Remove reference to mib before release */
 1417         vlan_putref_linkmib(mib, &psref);
 1418         curlwp_bindx(bound);
 1419 
 1420         return error;
 1421 }
 1422 
 1423 /*
 1424  * Given an Ethernet frame, find a valid vlan interface corresponding to the
 1425  * given source interface and tag, then run the real packet through the
 1426  * parent's input routine.
 1427  */
 1428 struct mbuf *
 1429 vlan_input(struct ifnet *ifp, struct mbuf *m)
 1430 {
 1431         struct ifvlan *ifv;
 1432         uint16_t vid;
 1433         struct ifvlan_linkmib *mib;
 1434         struct psref psref;
 1435 
 1436         KASSERT(vlan_has_tag(m));
 1437         vid = EVL_VLANOFTAG(vlan_get_tag(m));
 1438         KASSERT(vid != 0);
 1439 
 1440         mib = vlan_lookup_tag_psref(ifp, vid, &psref);
 1441         if (mib == NULL) {
 1442                 return m;
 1443         }
 1444 
 1445         ifv = mib->ifvm_ifvlan;
 1446         if ((ifv->ifv_if.if_flags & (IFF_UP | IFF_RUNNING)) !=
 1447             (IFF_UP | IFF_RUNNING)) {
 1448                 m_freem(m);
 1449                 if_statinc(ifp, if_noproto);
 1450                 goto out;
 1451         }
 1452 
 1453         /*
 1454          * Having found a valid vlan interface corresponding to
 1455          * the given source interface and vlan tag.
 1456          * remove the vlan tag.
 1457          */
 1458         m->m_flags &= ~M_VLANTAG;
 1459 
 1460         /*
 1461          * Drop promiscuously received packets if we are not in
 1462          * promiscuous mode
 1463          */
 1464         if ((m->m_flags & (M_BCAST | M_MCAST)) == 0 &&
 1465             (ifp->if_flags & IFF_PROMISC) &&
 1466             (ifv->ifv_if.if_flags & IFF_PROMISC) == 0) {
 1467                 struct ether_header *eh;
 1468 
 1469                 eh = mtod(m, struct ether_header *);
 1470                 if (memcmp(CLLADDR(ifv->ifv_if.if_sadl),
 1471                     eh->ether_dhost, ETHER_ADDR_LEN) != 0) {
 1472                         m_freem(m);
 1473                         if_statinc(&ifv->ifv_if, if_ierrors);
 1474                         goto out;
 1475                 }
 1476         }
 1477 
 1478         m_set_rcvif(m, &ifv->ifv_if);
 1479 
 1480         if (pfil_run_hooks(ifp->if_pfil, &m, ifp, PFIL_IN) != 0)
 1481                 goto out;
 1482         if (m == NULL)
 1483                 goto out;
 1484 
 1485         m->m_flags &= ~M_PROMISC;
 1486         if_input(&ifv->ifv_if, m);
 1487 out:
 1488         vlan_putref_linkmib(mib, &psref);
 1489         return NULL;
 1490 }
 1491 
 1492 /*
 1493  * If the parent link state changed, the vlan link state should change also.
 1494  */
 1495 static void
 1496 vlan_link_state_changed(void *xifv)
 1497 {
 1498         struct ifvlan *ifv = xifv;
 1499         struct ifnet *ifp, *p;
 1500         struct ifvlan_linkmib *mib;
 1501         struct psref psref;
 1502         int bound;
 1503 
 1504         bound = curlwp_bind();
 1505         mib = vlan_getref_linkmib(ifv, &psref);
 1506         if (mib == NULL) {
 1507                 curlwp_bindx(bound);
 1508                 return;
 1509         }
 1510 
 1511         if (mib->ifvm_p == NULL) {
 1512                 vlan_putref_linkmib(mib, &psref);
 1513                 curlwp_bindx(bound);
 1514                 return;
 1515         }
 1516 
 1517         ifp = &ifv->ifv_if;
 1518         p = mib->ifvm_p;
 1519         if_link_state_change(ifp, p->if_link_state);
 1520 
 1521         vlan_putref_linkmib(mib, &psref);
 1522         curlwp_bindx(bound);
 1523 }
 1524 
 1525 /*
 1526  * Module infrastructure
 1527  */
 1528 #include "if_module.h"
 1529 
 1530 IF_MODULE(MODULE_CLASS_DRIVER, vlan, NULL)

Cache object: 9d4565b6c8416178ed21de542b9643ad


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