LCOV - code coverage report
Current view: top level - net - if_vlan.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 518 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 30 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: if_vlan.c,v 1.178 2018/07/11 14:20:18 sf Exp $        */
       2             : 
       3             : /*
       4             :  * Copyright 1998 Massachusetts Institute of Technology
       5             :  *
       6             :  * Permission to use, copy, modify, and distribute this software and
       7             :  * its documentation for any purpose and without fee is hereby
       8             :  * granted, provided that both the above copyright notice and this
       9             :  * permission notice appear in all copies, that both the above
      10             :  * copyright notice and this permission notice appear in all
      11             :  * supporting documentation, and that the name of M.I.T. not be used
      12             :  * in advertising or publicity pertaining to distribution of the
      13             :  * software without specific, written prior permission.  M.I.T. makes
      14             :  * no representations about the suitability of this software for any
      15             :  * purpose.  It is provided "as is" without express or implied
      16             :  * warranty.
      17             :  *
      18             :  * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
      19             :  * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
      20             :  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
      21             :  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
      22             :  * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      23             :  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
      24             :  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
      25             :  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
      26             :  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
      27             :  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
      28             :  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      29             :  * SUCH DAMAGE.
      30             :  *
      31             :  * $FreeBSD: src/sys/net/if_vlan.c,v 1.16 2000/03/26 15:21:40 charnier Exp $
      32             :  */
      33             : 
      34             : /*
      35             :  * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs.
      36             :  * This is sort of sneaky in the implementation, since
      37             :  * we need to pretend to be enough of an Ethernet implementation
      38             :  * to make arp work.  The way we do this is by telling everyone
      39             :  * that we are an Ethernet, and then catch the packets that
      40             :  * ether_output() left on our output queue when it calls
      41             :  * if_start(), rewrite them for use by the real outgoing interface,
      42             :  * and ask it to send them.
      43             :  *
      44             :  * Some devices support 802.1Q tag insertion in firmware.  The
      45             :  * vlan interface behavior changes when the IFCAP_VLAN_HWTAGGING
      46             :  * capability is set on the parent.  In this case, vlan_start()
      47             :  * will not modify the ethernet header.
      48             :  */
      49             : 
      50             : #include "mpw.h"
      51             : 
      52             : #include <sys/param.h>
      53             : #include <sys/kernel.h>
      54             : #include <sys/malloc.h>
      55             : #include <sys/mbuf.h>
      56             : #include <sys/queue.h>
      57             : #include <sys/socket.h>
      58             : #include <sys/sockio.h>
      59             : #include <sys/systm.h>
      60             : #include <sys/rwlock.h>
      61             : 
      62             : #include <net/if.h>
      63             : #include <net/if_dl.h>
      64             : #include <net/if_types.h>
      65             : 
      66             : #include <netinet/in.h>
      67             : #include <netinet/if_ether.h>
      68             : 
      69             : #include <net/if_vlan_var.h>
      70             : 
      71             : #include "bpfilter.h"
      72             : #if NBPFILTER > 0
      73             : #include <net/bpf.h>
      74             : #endif
      75             : 
      76             : #define TAG_HASH_BITS           5
      77             : #define TAG_HASH_SIZE           (1 << TAG_HASH_BITS)
      78             : #define TAG_HASH_MASK           (TAG_HASH_SIZE - 1)
      79             : #define TAG_HASH(tag)           (tag & TAG_HASH_MASK)
      80             : SRPL_HEAD(, ifvlan) *vlan_tagh, *svlan_tagh;
      81             : struct rwlock vlan_tagh_lk = RWLOCK_INITIALIZER("vlantag");
      82             : 
      83             : void    vlanattach(int count);
      84             : int     vlan_clone_create(struct if_clone *, int);
      85             : int     vlan_clone_destroy(struct ifnet *);
      86             : 
      87             : int     vlan_input(struct ifnet *, struct mbuf *, void *);
      88             : void    vlan_start(struct ifqueue *ifq);
      89             : int     vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr);
      90             : 
      91             : int     vlan_up(struct ifvlan *);
      92             : int     vlan_parent_up(struct ifvlan *, struct ifnet *);
      93             : int     vlan_down(struct ifvlan *);
      94             : 
      95             : void    vlan_ifdetach(void *);
      96             : void    vlan_link_hook(void *);
      97             : void    vlan_link_state(struct ifvlan *, u_char, u_int64_t);
      98             : 
      99             : int     vlan_set_vnetid(struct ifvlan *, uint16_t);
     100             : int     vlan_set_parent(struct ifvlan *, const char *);
     101             : int     vlan_del_parent(struct ifvlan *);
     102             : int     vlan_inuse(uint16_t, unsigned int, uint16_t);
     103             : int     vlan_inuse_locked(uint16_t, unsigned int, uint16_t);
     104             : 
     105             : int     vlan_multi_add(struct ifvlan *, struct ifreq *);
     106             : int     vlan_multi_del(struct ifvlan *, struct ifreq *);
     107             : void    vlan_multi_apply(struct ifvlan *, struct ifnet *, u_long);
     108             : void    vlan_multi_free(struct ifvlan *);
     109             : 
     110             : int     vlan_media_get(struct ifvlan *, struct ifreq *);
     111             : 
     112             : int     vlan_iff(struct ifvlan *);
     113             : int     vlan_setlladdr(struct ifvlan *, struct ifreq *);
     114             : 
     115             : int     vlan_set_compat(struct ifnet *, struct ifreq *);
     116             : int     vlan_get_compat(struct ifnet *, struct ifreq *);
     117             : 
     118             : struct if_clone vlan_cloner =
     119             :     IF_CLONE_INITIALIZER("vlan", vlan_clone_create, vlan_clone_destroy);
     120             : struct if_clone svlan_cloner =
     121             :     IF_CLONE_INITIALIZER("svlan", vlan_clone_create, vlan_clone_destroy);
     122             : 
     123             : void vlan_ref(void *, void *);
     124             : void vlan_unref(void *, void *);
     125             : 
     126             : struct srpl_rc vlan_tagh_rc = SRPL_RC_INITIALIZER(vlan_ref, vlan_unref, NULL);
     127             : 
     128             : void
     129           0 : vlanattach(int count)
     130             : {
     131             :         u_int i;
     132             : 
     133             :         /* Normal VLAN */
     134           0 :         vlan_tagh = mallocarray(TAG_HASH_SIZE, sizeof(*vlan_tagh),
     135             :             M_DEVBUF, M_NOWAIT);
     136           0 :         if (vlan_tagh == NULL)
     137           0 :                 panic("vlanattach: hashinit");
     138             : 
     139             :         /* Service-VLAN for QinQ/802.1ad provider bridges */
     140           0 :         svlan_tagh = mallocarray(TAG_HASH_SIZE, sizeof(*svlan_tagh),
     141             :             M_DEVBUF, M_NOWAIT);
     142           0 :         if (svlan_tagh == NULL)
     143           0 :                 panic("vlanattach: hashinit");
     144             : 
     145           0 :         for (i = 0; i < TAG_HASH_SIZE; i++) {
     146           0 :                 SRPL_INIT(&vlan_tagh[i]);
     147           0 :                 SRPL_INIT(&svlan_tagh[i]);
     148             :         }
     149             : 
     150           0 :         if_clone_attach(&vlan_cloner);
     151           0 :         if_clone_attach(&svlan_cloner);
     152           0 : }
     153             : 
     154             : int
     155           0 : vlan_clone_create(struct if_clone *ifc, int unit)
     156             : {
     157             :         struct ifvlan   *ifv;
     158             :         struct ifnet    *ifp;
     159             : 
     160           0 :         ifv = malloc(sizeof(*ifv), M_DEVBUF, M_WAITOK|M_ZERO);
     161           0 :         LIST_INIT(&ifv->vlan_mc_listhead);
     162           0 :         ifp = &ifv->ifv_if;
     163           0 :         ifp->if_softc = ifv;
     164           0 :         snprintf(ifp->if_xname, sizeof ifp->if_xname, "%s%d", ifc->ifc_name,
     165             :             unit);
     166             :         /* NB: flags are not set here */
     167             :         /* NB: mtu is not set here */
     168             : 
     169             :         /* Special handling for the IEEE 802.1ad QinQ variant */
     170           0 :         if (strcmp("svlan", ifc->ifc_name) == 0)
     171           0 :                 ifv->ifv_type = ETHERTYPE_QINQ;
     172             :         else
     173           0 :                 ifv->ifv_type = ETHERTYPE_VLAN;
     174             : 
     175           0 :         refcnt_init(&ifv->ifv_refcnt);
     176             : 
     177           0 :         ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST;
     178           0 :         ifp->if_xflags = IFXF_CLONED|IFXF_MPSAFE;
     179           0 :         ifp->if_qstart = vlan_start;
     180           0 :         ifp->if_ioctl = vlan_ioctl;
     181           0 :         ifp->if_hardmtu = 0xffff;
     182           0 :         ifp->if_link_state = LINK_STATE_DOWN;
     183           0 :         if_attach(ifp);
     184           0 :         ether_ifattach(ifp);
     185           0 :         ifp->if_hdrlen = EVL_ENCAPLEN;
     186             : 
     187           0 :         return (0);
     188             : }
     189             : 
     190             : void
     191           0 : vlan_ref(void *null, void *v)
     192             : {
     193           0 :         struct ifvlan *ifv = v;
     194             : 
     195           0 :         refcnt_take(&ifv->ifv_refcnt);
     196           0 : }
     197             : 
     198             : void
     199           0 : vlan_unref(void *null, void *v)
     200             : {
     201           0 :         struct ifvlan *ifv = v;
     202             : 
     203           0 :         refcnt_rele_wake(&ifv->ifv_refcnt);
     204           0 : }
     205             : 
     206             : int
     207           0 : vlan_clone_destroy(struct ifnet *ifp)
     208             : {
     209           0 :         struct ifvlan   *ifv = ifp->if_softc;
     210             : 
     211           0 :         if (ISSET(ifp->if_flags, IFF_RUNNING))
     212           0 :                 vlan_down(ifv);
     213             : 
     214           0 :         ether_ifdetach(ifp);
     215           0 :         if_detach(ifp);
     216           0 :         refcnt_finalize(&ifv->ifv_refcnt, "vlanrefs");
     217           0 :         vlan_multi_free(ifv);
     218           0 :         free(ifv, M_DEVBUF, sizeof(*ifv));
     219             : 
     220           0 :         return (0);
     221             : }
     222             : 
     223             : static inline int
     224           0 : vlan_mplstunnel(int ifidx)
     225             : {
     226             : #if NMPW > 0
     227             :         struct ifnet *ifp;
     228             :         int rv = 0;
     229             : 
     230           0 :         ifp = if_get(ifidx);
     231           0 :         if (ifp != NULL) {
     232           0 :                 rv = ifp->if_type == IFT_MPLSTUNNEL;
     233           0 :                 if_put(ifp);
     234           0 :         }
     235           0 :         return (rv);
     236             : #else
     237             :         return (0);
     238             : #endif
     239             : }
     240             : 
     241             : void
     242           0 : vlan_start(struct ifqueue *ifq)
     243             : {
     244           0 :         struct ifnet    *ifp = ifq->ifq_if;
     245             :         struct ifvlan   *ifv;
     246             :         struct ifnet    *ifp0;
     247             :         struct mbuf     *m;
     248             :         uint8_t          prio;
     249             : 
     250           0 :         ifv = ifp->if_softc;
     251           0 :         ifp0 = if_get(ifv->ifv_ifp0);
     252           0 :         if (ifp0 == NULL || (ifp0->if_flags & (IFF_UP|IFF_RUNNING)) !=
     253             :             (IFF_UP|IFF_RUNNING)) {
     254           0 :                 ifq_purge(ifq);
     255           0 :                 goto leave;
     256             :         }
     257             : 
     258           0 :         while ((m = ifq_dequeue(ifq)) != NULL) {
     259             : #if NBPFILTER > 0
     260           0 :                 if (ifp->if_bpf)
     261           0 :                         bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT);
     262             : #endif /* NBPFILTER > 0 */
     263             : 
     264           0 :                 prio = ISSET(ifp->if_flags, IFF_LINK0) ?
     265           0 :                     ifp->if_llprio : m->m_pkthdr.pf.prio;
     266             : 
     267             :                 /* IEEE 802.1p has prio 0 and 1 swapped */
     268           0 :                 if (prio <= 1)
     269           0 :                         prio = !prio;
     270             : 
     271             :                 /*
     272             :                  * If this packet came from a pseudowire it means it already
     273             :                  * has all tags it needs, so just output it.
     274             :                  */
     275           0 :                 if (vlan_mplstunnel(m->m_pkthdr.ph_ifidx)) {
     276             :                         /* NOTHING */
     277             : 
     278             :                 /*
     279             :                  * If the underlying interface cannot do VLAN tag insertion
     280             :                  * itself, create an encapsulation header.
     281             :                  */
     282           0 :                 } else if ((ifp0->if_capabilities & IFCAP_VLAN_HWTAGGING) &&
     283           0 :                     (ifv->ifv_type == ETHERTYPE_VLAN)) {
     284           0 :                         m->m_pkthdr.ether_vtag = ifv->ifv_tag +
     285           0 :                             (prio << EVL_PRIO_BITS);
     286           0 :                         m->m_flags |= M_VLANTAG;
     287           0 :                 } else {
     288           0 :                         m = vlan_inject(m, ifv->ifv_type, ifv->ifv_tag |
     289           0 :                             (prio << EVL_PRIO_BITS));
     290           0 :                         if (m == NULL) {
     291           0 :                                 ifp->if_oerrors++;
     292           0 :                                 continue;
     293             :                         }
     294             :                 }
     295             : 
     296           0 :                 if (if_enqueue(ifp0, m)) {
     297           0 :                         ifp->if_oerrors++;
     298           0 :                         ifq->ifq_errors++;
     299           0 :                         continue;
     300             :                 }
     301             :         }
     302             : 
     303             : leave:
     304           0 :         if_put(ifp0);
     305           0 : }
     306             : 
     307             : struct mbuf *
     308           0 : vlan_inject(struct mbuf *m, uint16_t type, uint16_t tag)
     309             : {
     310           0 :         struct ether_vlan_header evh;
     311             : 
     312           0 :         m_copydata(m, 0, ETHER_HDR_LEN, (caddr_t)&evh);
     313           0 :         evh.evl_proto = evh.evl_encap_proto;
     314           0 :         evh.evl_encap_proto = htons(type);
     315           0 :         evh.evl_tag = htons(tag);
     316           0 :         m_adj(m, ETHER_HDR_LEN);
     317           0 :         M_PREPEND(m, sizeof(evh) + ETHER_ALIGN, M_DONTWAIT);
     318           0 :         if (m == NULL)
     319           0 :                 return (NULL);
     320             : 
     321           0 :         m_adj(m, ETHER_ALIGN);
     322             : 
     323           0 :         m_copyback(m, 0, sizeof(evh), &evh, M_NOWAIT);
     324           0 :         CLR(m->m_flags, M_VLANTAG);
     325             : 
     326           0 :         return (m);
     327           0 :  }
     328             : 
     329             : /*
     330             :  * vlan_input() returns 1 if it has consumed the packet, 0 otherwise.
     331             :  */
     332             : int
     333           0 : vlan_input(struct ifnet *ifp0, struct mbuf *m, void *cookie)
     334             : {
     335             :         struct ifvlan                   *ifv;
     336             :         struct ether_vlan_header        *evl;
     337             :         struct ether_header             *eh;
     338             :         SRPL_HEAD(, ifvlan)             *tagh, *list;
     339           0 :         struct srp_ref                   sr;
     340             :         u_int                            tag;
     341           0 :         struct mbuf_list                 ml = MBUF_LIST_INITIALIZER();
     342             :         u_int16_t                        etype;
     343             : 
     344           0 :         eh = mtod(m, struct ether_header *);
     345           0 :         etype = ntohs(eh->ether_type);
     346             : 
     347           0 :         if (m->m_flags & M_VLANTAG) {
     348             :                 etype = ETHERTYPE_VLAN;
     349           0 :                 tagh = vlan_tagh;
     350           0 :         } else if ((etype == ETHERTYPE_VLAN) || (etype == ETHERTYPE_QINQ)) {
     351           0 :                 if (m->m_len < sizeof(*evl) &&
     352           0 :                     (m = m_pullup(m, sizeof(*evl))) == NULL) {
     353           0 :                         ifp0->if_ierrors++;
     354           0 :                         return (1);
     355             :                 }
     356             : 
     357           0 :                 evl = mtod(m, struct ether_vlan_header *);
     358           0 :                 m->m_pkthdr.ether_vtag = ntohs(evl->evl_tag);
     359           0 :                 tagh = etype == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh;
     360             :         } else {
     361             :                 /* Skip non-VLAN packets. */
     362           0 :                 return (0);
     363             :         }
     364             : 
     365             :         /* From now on ether_vtag is fine */
     366           0 :         tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag);
     367           0 :         m->m_pkthdr.pf.prio = EVL_PRIOFTAG(m->m_pkthdr.ether_vtag);
     368             : 
     369             :         /* IEEE 802.1p has prio 0 and 1 swapped */
     370           0 :         if (m->m_pkthdr.pf.prio <= 1)
     371           0 :                 m->m_pkthdr.pf.prio = !m->m_pkthdr.pf.prio;
     372             : 
     373           0 :         list = &tagh[TAG_HASH(tag)];
     374           0 :         SRPL_FOREACH(ifv, &sr, list, ifv_list) {
     375           0 :                 if (ifp0->if_index == ifv->ifv_ifp0 && tag == ifv->ifv_tag &&
     376           0 :                     etype == ifv->ifv_type)
     377             :                         break;
     378             :         }
     379             : 
     380           0 :         if (ifv == NULL) {
     381           0 :                 ifp0->if_noproto++;
     382           0 :                 goto drop;
     383             :         }
     384             : 
     385           0 :         if ((ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
     386             :             (IFF_UP|IFF_RUNNING))
     387             :                 goto drop;
     388             : 
     389             :         /*
     390             :          * Having found a valid vlan interface corresponding to
     391             :          * the given source interface and vlan tag, remove the
     392             :          * encapsulation.
     393             :          */
     394           0 :         if (m->m_flags & M_VLANTAG) {
     395           0 :                 m->m_flags &= ~M_VLANTAG;
     396           0 :         } else {
     397           0 :                 eh->ether_type = evl->evl_proto;
     398           0 :                 memmove((char *)eh + EVL_ENCAPLEN, eh, sizeof(*eh));
     399           0 :                 m_adj(m, EVL_ENCAPLEN);
     400             :         }
     401             : 
     402           0 :         ml_enqueue(&ml, m);
     403           0 :         if_input(&ifv->ifv_if, &ml);
     404           0 :         SRPL_LEAVE(&sr);
     405           0 :         return (1);
     406             : 
     407             : drop:
     408           0 :         SRPL_LEAVE(&sr);
     409           0 :         m_freem(m);
     410           0 :         return (1);
     411           0 : }
     412             : 
     413             : int
     414           0 : vlan_parent_up(struct ifvlan *ifv, struct ifnet *ifp0)
     415             : {
     416             :         int error;
     417             : 
     418           0 :         if (ISSET(ifv->ifv_flags, IFVF_PROMISC)) {
     419           0 :                 error = ifpromisc(ifp0, 1);
     420           0 :                 if (error != 0)
     421           0 :                         return (error);
     422             :         }
     423             : 
     424             :         /* Register callback for physical link state changes */
     425           0 :         ifv->lh_cookie = hook_establish(ifp0->if_linkstatehooks, 1,
     426           0 :             vlan_link_hook, ifv);
     427             : 
     428             :         /* Register callback if parent wants to unregister */
     429           0 :         ifv->dh_cookie = hook_establish(ifp0->if_detachhooks, 0,
     430             :             vlan_ifdetach, ifv);
     431             : 
     432           0 :         vlan_multi_apply(ifv, ifp0, SIOCADDMULTI);
     433             : 
     434           0 :         if_ih_insert(ifp0, vlan_input, NULL);
     435             : 
     436           0 :         return (0);
     437           0 : }
     438             : 
     439             : int
     440           0 : vlan_up(struct ifvlan *ifv)
     441             : {
     442             :         SRPL_HEAD(, ifvlan) *tagh, *list;
     443           0 :         struct ifnet *ifp = &ifv->ifv_if;
     444             :         struct ifnet *ifp0;
     445             :         int error = 0;
     446             :         u_int hardmtu;
     447             : 
     448           0 :         KASSERT(!ISSET(ifp->if_flags, IFF_RUNNING));
     449             : 
     450           0 :         tagh = ifv->ifv_type == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh;
     451           0 :         list = &tagh[TAG_HASH(ifv->ifv_tag)];
     452             : 
     453           0 :         ifp0 = if_get(ifv->ifv_ifp0);
     454           0 :         if (ifp0 == NULL)
     455           0 :                 return (ENXIO);
     456             : 
     457             :         /* check vlan will work on top of the parent */
     458           0 :         if (ifp0->if_type != IFT_ETHER) {
     459             :                 error = EPROTONOSUPPORT;
     460           0 :                 goto put;
     461             :         }
     462             : 
     463           0 :         hardmtu = ifp0->if_hardmtu;
     464           0 :         if (!ISSET(ifp0->if_capabilities, IFCAP_VLAN_MTU))
     465           0 :                 hardmtu -= EVL_ENCAPLEN;
     466             : 
     467           0 :         if (ifp->if_mtu > hardmtu) {
     468             :                 error = ENOBUFS;
     469           0 :                 goto put;
     470             :         }
     471             : 
     472             :         /* parent is fine, let's prepare the ifv to handle packets */
     473           0 :         ifp->if_hardmtu = hardmtu;
     474           0 :         SET(ifp->if_flags, ifp0->if_flags & IFF_SIMPLEX);
     475             : 
     476             :         /*
     477             :          * Note: In cases like vio(4) and em(4) where the offsets of the
     478             :          * csum can be freely defined, we could actually do csum offload
     479             :          * for VLAN and QINQ packets.
     480             :          */
     481           0 :         if (ifv->ifv_type != ETHERTYPE_VLAN) {
     482             :                 /*
     483             :                  * Hardware offload only works with the default VLAN
     484             :                  * ethernet type (0x8100).
     485             :                  */
     486           0 :                 ifp->if_capabilities = 0;
     487           0 :         } else if (ISSET(ifp0->if_capabilities, IFCAP_VLAN_HWTAGGING)) {
     488             :                 /*
     489             :                  * Chips that can do hardware-assisted VLAN encapsulation, can
     490             :                  * calculate the correct checksum for VLAN tagged packets.
     491             :                  */
     492           0 :                 ifp->if_capabilities = ifp0->if_capabilities & IFCAP_CSUM_MASK;
     493           0 :         }
     494             : 
     495             :         /* commit the ifv */
     496           0 :         error = rw_enter(&vlan_tagh_lk, RW_WRITE | RW_INTR);
     497           0 :         if (error != 0)
     498             :                 goto scrub;
     499             : 
     500           0 :         error = vlan_inuse_locked(ifv->ifv_type, ifv->ifv_ifp0, ifv->ifv_tag);
     501           0 :         if (error != 0)
     502             :                 goto leave;
     503             : 
     504           0 :         SRPL_INSERT_HEAD_LOCKED(&vlan_tagh_rc, list, ifv, ifv_list);
     505           0 :         rw_exit(&vlan_tagh_lk);
     506             : 
     507             :         /* configure the parent to handle packets for this vlan */
     508           0 :         error = vlan_parent_up(ifv, ifp0);
     509           0 :         if (error != 0)
     510             :                 goto remove;
     511             : 
     512             :         /* we're running now */
     513           0 :         SET(ifp->if_flags, IFF_RUNNING);
     514           0 :         vlan_link_state(ifv, ifp0->if_link_state, ifp0->if_baudrate);
     515             : 
     516           0 :         if_put(ifp0);
     517             : 
     518           0 :         return (0);
     519             : 
     520             : remove:
     521           0 :         rw_enter(&vlan_tagh_lk, RW_WRITE);
     522           0 :         SRPL_REMOVE_LOCKED(&vlan_tagh_rc, list, ifv, ifvlan, ifv_list);
     523             : leave:
     524           0 :         rw_exit(&vlan_tagh_lk);
     525             : scrub:
     526           0 :         ifp->if_capabilities = 0;
     527           0 :         CLR(ifp->if_flags, IFF_SIMPLEX);
     528           0 :         ifp->if_hardmtu = 0xffff;
     529             : put:
     530           0 :         if_put(ifp0);
     531             : 
     532           0 :         return (error);
     533           0 : }
     534             : 
     535             : int
     536           0 : vlan_down(struct ifvlan *ifv)
     537             : {
     538             :         SRPL_HEAD(, ifvlan) *tagh, *list;
     539           0 :         struct ifnet *ifp = &ifv->ifv_if;
     540             :         struct ifnet *ifp0;
     541             : 
     542           0 :         tagh = ifv->ifv_type == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh;
     543           0 :         list = &tagh[TAG_HASH(ifv->ifv_tag)];
     544             : 
     545           0 :         KASSERT(ISSET(ifp->if_flags, IFF_RUNNING));
     546             : 
     547           0 :         vlan_link_state(ifv, LINK_STATE_DOWN, 0);
     548           0 :         CLR(ifp->if_flags, IFF_RUNNING);
     549             : 
     550           0 :         ifq_barrier(&ifp->if_snd);
     551             : 
     552           0 :         ifp0 = if_get(ifv->ifv_ifp0);
     553           0 :         if (ifp0 != NULL) {
     554           0 :                 if_ih_remove(ifp0, vlan_input, NULL);
     555           0 :                 if (ISSET(ifv->ifv_flags, IFVF_PROMISC))
     556           0 :                         ifpromisc(ifp0, 0);
     557           0 :                 vlan_multi_apply(ifv, ifp0, SIOCDELMULTI);
     558           0 :                 hook_disestablish(ifp0->if_detachhooks, ifv->dh_cookie);
     559           0 :                 hook_disestablish(ifp0->if_linkstatehooks, ifv->lh_cookie);
     560           0 :         }
     561           0 :         if_put(ifp0);
     562             : 
     563           0 :         rw_enter_write(&vlan_tagh_lk);
     564           0 :         SRPL_REMOVE_LOCKED(&vlan_tagh_rc, list, ifv, ifvlan, ifv_list);
     565           0 :         rw_exit_write(&vlan_tagh_lk);
     566             : 
     567           0 :         ifp->if_capabilities = 0;
     568           0 :         CLR(ifp->if_flags, IFF_SIMPLEX);
     569           0 :         ifp->if_hardmtu = 0xffff;
     570             : 
     571           0 :         return (0);
     572             : }
     573             : 
     574             : void
     575           0 : vlan_ifdetach(void *v)
     576             : {
     577           0 :         struct ifvlan *ifv = v;
     578           0 :         struct ifnet *ifp = &ifv->ifv_if;
     579             : 
     580           0 :         if (ISSET(ifp->if_flags, IFF_RUNNING)) {
     581           0 :                 vlan_down(ifv);
     582           0 :                 CLR(ifp->if_flags, IFF_UP);
     583           0 :         }
     584             : 
     585           0 :         ifv->ifv_ifp0 = 0;
     586           0 : }
     587             : 
     588             : void
     589           0 : vlan_link_hook(void *v)
     590             : {
     591           0 :         struct ifvlan *ifv = v;
     592             :         struct ifnet *ifp0;
     593             : 
     594             :         u_char link = LINK_STATE_DOWN;
     595             :         uint64_t baud = 0;
     596             : 
     597           0 :         ifp0 = if_get(ifv->ifv_ifp0);
     598           0 :         if (ifp0 != NULL) {
     599           0 :                 link = ifp0->if_link_state;
     600           0 :                 baud = ifp0->if_baudrate;
     601           0 :         }
     602           0 :         if_put(ifp0);
     603             : 
     604           0 :         vlan_link_state(ifv, link, baud);
     605           0 : }
     606             : 
     607             : void
     608           0 : vlan_link_state(struct ifvlan *ifv, u_char link, uint64_t baud)
     609             : {
     610           0 :         if (ifv->ifv_if.if_link_state == link)
     611             :                 return;
     612             : 
     613           0 :         ifv->ifv_if.if_link_state = link;
     614           0 :         ifv->ifv_if.if_baudrate = baud;
     615             : 
     616           0 :         if_link_state_change(&ifv->ifv_if);
     617           0 : }
     618             : 
     619             : int
     620           0 : vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
     621             : {
     622           0 :         struct ifvlan *ifv = ifp->if_softc;
     623           0 :         struct ifreq *ifr = (struct ifreq *)data;
     624           0 :         struct if_parent *parent = (struct if_parent *)data;
     625             :         struct ifnet *ifp0;
     626             :         uint16_t tag;
     627             :         int error = 0;
     628             : 
     629           0 :         switch (cmd) {
     630             :         case SIOCSIFADDR:
     631           0 :                 ifp->if_flags |= IFF_UP;
     632             :                 /* FALLTHROUGH */
     633             : 
     634             :         case SIOCSIFFLAGS:
     635           0 :                 if (ISSET(ifp->if_flags, IFF_UP)) {
     636           0 :                         if (!ISSET(ifp->if_flags, IFF_RUNNING))
     637           0 :                                 error = vlan_up(ifv);
     638             :                         else
     639             :                                 error = ENETRESET;
     640             :                 } else {
     641           0 :                         if (ISSET(ifp->if_flags, IFF_RUNNING))
     642           0 :                                 error = vlan_down(ifv);
     643             :                 }
     644             :                 break;
     645             : 
     646             :         case SIOCSVNETID:
     647           0 :                 if (ifr->ifr_vnetid < EVL_VLID_MIN ||
     648           0 :                     ifr->ifr_vnetid > EVL_VLID_MAX) {
     649             :                         error = EINVAL;
     650           0 :                         break;
     651             :                 }
     652             : 
     653           0 :                 tag = ifr->ifr_vnetid;
     654           0 :                 if (tag == ifv->ifv_tag)
     655             :                         break;
     656             : 
     657           0 :                 error = vlan_set_vnetid(ifv, tag);
     658           0 :                 break;
     659             : 
     660             :         case SIOCGVNETID:
     661           0 :                 if (ifv->ifv_tag == EVL_VLID_NULL)
     662           0 :                         error = EADDRNOTAVAIL;
     663             :                 else
     664           0 :                         ifr->ifr_vnetid = (int64_t)ifv->ifv_tag;
     665             :                 break;
     666             : 
     667             :         case SIOCDVNETID:
     668           0 :                 error = vlan_set_vnetid(ifv, 0);
     669           0 :                 break;
     670             : 
     671             :         case SIOCSIFPARENT:
     672           0 :                 error = vlan_set_parent(ifv, parent->ifp_parent);
     673           0 :                 break;
     674             : 
     675             :         case SIOCGIFPARENT:
     676           0 :                 ifp0 = if_get(ifv->ifv_ifp0);
     677           0 :                 if (ifp0 == NULL)
     678           0 :                         error = EADDRNOTAVAIL;
     679             :                 else {
     680           0 :                         memcpy(parent->ifp_parent, ifp0->if_xname,
     681             :                             sizeof(parent->ifp_parent));
     682             :                 }
     683           0 :                 if_put(ifp0);
     684           0 :                 break;
     685             : 
     686             :         case SIOCDIFPARENT:
     687           0 :                 error = vlan_del_parent(ifv);
     688           0 :                 break;
     689             : 
     690             :         case SIOCADDMULTI:
     691           0 :                 error = vlan_multi_add(ifv, ifr);
     692           0 :                 break;
     693             : 
     694             :         case SIOCDELMULTI:
     695           0 :                 error = vlan_multi_del(ifv, ifr);
     696           0 :                 break;
     697             : 
     698             :         case SIOCGIFMEDIA:
     699           0 :                 error = vlan_media_get(ifv, ifr);
     700           0 :                 break;
     701             : 
     702             :         case SIOCSIFMEDIA:
     703             :                 error = ENOTTY;
     704           0 :                 break;
     705             : 
     706             :         case SIOCSIFLLADDR:
     707           0 :                 error = vlan_setlladdr(ifv, ifr);
     708           0 :                 break;
     709             : 
     710             :         case SIOCSETVLAN:
     711           0 :                 error = vlan_set_compat(ifp, ifr);
     712           0 :                 break;
     713             :         case SIOCGETVLAN:
     714           0 :                 error = vlan_get_compat(ifp, ifr);
     715           0 :                 break;
     716             : 
     717             :         default:
     718           0 :                 error = ether_ioctl(ifp, &ifv->ifv_ac, cmd, data);
     719           0 :                 break;
     720             :         }
     721             : 
     722           0 :         if (error == ENETRESET) {
     723           0 :                 vlan_iff(ifv);
     724             :                 error = 0;
     725           0 :         }
     726             : 
     727           0 :         return error;
     728             : }
     729             : 
     730             : int
     731           0 : vlan_iff(struct ifvlan *ifv)
     732             : {
     733             :         struct ifnet *ifp0;
     734             :         int promisc = 0;
     735             :         int error = 0;
     736             : 
     737           0 :         if (ISSET(ifv->ifv_if.if_flags, IFF_PROMISC) ||
     738           0 :             ISSET(ifv->ifv_flags, IFVF_LLADDR))
     739           0 :                 promisc = IFVF_PROMISC;
     740             : 
     741           0 :         if (ISSET(ifv->ifv_flags, IFVF_PROMISC) == promisc)
     742           0 :                 return (0);
     743             : 
     744           0 :         if (ISSET(ifv->ifv_if.if_flags, IFF_RUNNING)) {
     745           0 :                 ifp0 = if_get(ifv->ifv_ifp0);
     746           0 :                 if (ifp0 != NULL)
     747           0 :                         error = ifpromisc(ifp0, promisc);
     748           0 :                 if_put(ifp0);
     749           0 :         }
     750             : 
     751           0 :         if (error == 0) {
     752           0 :                 CLR(ifv->ifv_flags, IFVF_PROMISC);
     753           0 :                 SET(ifv->ifv_flags, promisc);
     754           0 :         }
     755             : 
     756           0 :         return (error);
     757           0 : }
     758             : 
     759             : int
     760           0 : vlan_setlladdr(struct ifvlan *ifv, struct ifreq *ifr)
     761             : {
     762           0 :         struct ifnet *ifp = &ifv->ifv_if;
     763             :         struct ifnet *ifp0;
     764           0 :         uint8_t lladdr[ETHER_ADDR_LEN];
     765             :         int flag;
     766             : 
     767           0 :         memcpy(lladdr, ifr->ifr_addr.sa_data, sizeof(lladdr));
     768             : 
     769             :         /* setting the mac addr to 00:00:00:00:00:00 means reset lladdr */
     770           0 :         if (memcmp(lladdr, etheranyaddr, sizeof(lladdr)) == 0) {
     771           0 :                 ifp0 = if_get(ifv->ifv_ifp0);
     772           0 :                 if (ifp0 != NULL)
     773           0 :                         memcpy(lladdr, LLADDR(ifp0->if_sadl), sizeof(lladdr));
     774           0 :                 if_put(ifp0);
     775             : 
     776             :                 flag = 0;
     777           0 :         } else
     778             :                 flag = IFVF_LLADDR;
     779             : 
     780           0 :         if (memcmp(lladdr, LLADDR(ifp->if_sadl), sizeof(lladdr)) == 0 &&
     781           0 :             ISSET(ifv->ifv_flags, IFVF_LLADDR) == flag) {
     782             :                 /* nop */
     783           0 :                 return (0);
     784             :         }
     785             : 
     786             :         /* commit */
     787           0 :         if_setlladdr(ifp, lladdr);
     788           0 :         CLR(ifv->ifv_flags, IFVF_LLADDR);
     789           0 :         SET(ifv->ifv_flags, flag);
     790             : 
     791           0 :         return (ENETRESET);
     792           0 : }
     793             : 
     794             : int
     795           0 : vlan_set_vnetid(struct ifvlan *ifv, uint16_t tag)
     796             : {
     797           0 :         struct ifnet *ifp = &ifv->ifv_if;
     798             :         SRPL_HEAD(, ifvlan) *tagh, *list;
     799           0 :         u_char link = ifp->if_link_state;
     800           0 :         uint64_t baud = ifp->if_baudrate;
     801             :         int error;
     802             : 
     803           0 :         tagh = ifv->ifv_type == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh;
     804             : 
     805           0 :         if (ISSET(ifp->if_flags, IFF_RUNNING) && LINK_STATE_IS_UP(link))
     806           0 :                 vlan_link_state(ifv, LINK_STATE_DOWN, 0);
     807             : 
     808           0 :         error = rw_enter(&vlan_tagh_lk, RW_WRITE);
     809           0 :         if (error != 0)
     810           0 :                 return (error);
     811             : 
     812           0 :         error = vlan_inuse_locked(ifv->ifv_type, ifv->ifv_ifp0, tag);
     813           0 :         if (error != 0)
     814             :                 goto unlock;
     815             : 
     816           0 :         if (ISSET(ifp->if_flags, IFF_RUNNING)) {
     817           0 :                 list = &tagh[TAG_HASH(ifv->ifv_tag)];
     818           0 :                 SRPL_REMOVE_LOCKED(&vlan_tagh_rc, list, ifv, ifvlan, ifv_list);
     819             : 
     820           0 :                 ifv->ifv_tag = tag;
     821             : 
     822           0 :                 list = &tagh[TAG_HASH(ifv->ifv_tag)];
     823           0 :                 SRPL_INSERT_HEAD_LOCKED(&vlan_tagh_rc, list, ifv, ifv_list);
     824           0 :         } else
     825           0 :                 ifv->ifv_tag = tag;
     826             : 
     827             : unlock:
     828           0 :         rw_exit(&vlan_tagh_lk);
     829             : 
     830           0 :         if (ISSET(ifp->if_flags, IFF_RUNNING) && LINK_STATE_IS_UP(link))
     831           0 :                 vlan_link_state(ifv, link, baud);
     832             : 
     833           0 :         return (error);
     834           0 : }
     835             : 
     836             : int
     837           0 : vlan_set_parent(struct ifvlan *ifv, const char *parent)
     838             : {
     839           0 :         struct ifnet *ifp = &ifv->ifv_if;
     840             :         struct ifnet *ifp0;
     841             :         int error = 0;
     842             : 
     843           0 :         ifp0 = ifunit(parent); /* doesn't need an if_put */
     844           0 :         if (ifp0 == NULL)
     845           0 :                 return (EINVAL);
     846             : 
     847           0 :         if (ifp0->if_type != IFT_ETHER)
     848           0 :                 return (EPROTONOSUPPORT);
     849             : 
     850           0 :         if (ifv->ifv_ifp0 == ifp0->if_index) {
     851             :                 /* nop */
     852           0 :                 return (0);
     853             :         }
     854             : 
     855           0 :         if (ISSET(ifp->if_flags, IFF_RUNNING))
     856           0 :                 return (EBUSY);
     857             : 
     858           0 :         error = vlan_inuse(ifv->ifv_type, ifp0->if_index, ifv->ifv_tag);
     859           0 :         if (error != 0)
     860           0 :                 return (error);
     861             : 
     862             :         /* commit */
     863           0 :         ifv->ifv_ifp0 = ifp0->if_index;
     864           0 :         if (!ISSET(ifv->ifv_flags, IFVF_LLADDR))
     865           0 :                 if_setlladdr(ifp, LLADDR(ifp0->if_sadl));
     866             : 
     867           0 :         return (0);
     868           0 : }
     869             : 
     870             : int
     871           0 : vlan_del_parent(struct ifvlan *ifv)
     872             : {
     873           0 :         struct ifnet *ifp = &ifv->ifv_if;
     874             : 
     875           0 :         if (ISSET(ifp->if_flags, IFF_RUNNING))
     876           0 :                 return (EBUSY);
     877             : 
     878             :         /* commit */
     879           0 :         ifv->ifv_ifp0 = 0;
     880           0 :         if (!ISSET(ifv->ifv_flags, IFVF_LLADDR))
     881           0 :                 if_setlladdr(ifp, etheranyaddr);
     882             : 
     883           0 :         return (0);
     884           0 : }
     885             : 
     886             : int
     887           0 : vlan_set_compat(struct ifnet *ifp, struct ifreq *ifr)
     888             : {
     889           0 :         struct vlanreq vlr;
     890           0 :         struct ifreq req;
     891           0 :         struct if_parent parent;
     892             : 
     893             :         int error;
     894             : 
     895           0 :         error = suser(curproc);
     896           0 :         if (error != 0)
     897           0 :                 return (error);
     898             : 
     899           0 :         error = copyin(ifr->ifr_data, &vlr, sizeof(vlr));
     900           0 :         if (error != 0)
     901           0 :                 return (error);
     902             : 
     903           0 :         if (vlr.vlr_parent[0] == '\0')
     904           0 :                 return (vlan_ioctl(ifp, SIOCDIFPARENT, (caddr_t)ifr));
     905             : 
     906           0 :         memset(&req, 0, sizeof(req));
     907           0 :         memcpy(req.ifr_name, ifp->if_xname, sizeof(req.ifr_name));
     908           0 :         req.ifr_vnetid = vlr.vlr_tag;
     909             : 
     910           0 :         error = vlan_ioctl(ifp, SIOCSVNETID, (caddr_t)&req);
     911           0 :         if (error != 0)
     912           0 :                 return (error);
     913             : 
     914           0 :         memset(&parent, 0, sizeof(parent));
     915           0 :         memcpy(parent.ifp_name, ifp->if_xname, sizeof(parent.ifp_name));
     916           0 :         memcpy(parent.ifp_parent, vlr.vlr_parent, sizeof(parent.ifp_parent));
     917           0 :         error = vlan_ioctl(ifp, SIOCSIFPARENT, (caddr_t)&parent);
     918           0 :         if (error != 0)
     919           0 :                 return (error);
     920             : 
     921           0 :         memset(&req, 0, sizeof(req));
     922           0 :         memcpy(req.ifr_name, ifp->if_xname, sizeof(req.ifr_name));
     923           0 :         SET(ifp->if_flags, IFF_UP);
     924           0 :         return (vlan_ioctl(ifp, SIOCSIFFLAGS, (caddr_t)&req));
     925           0 : }
     926             : 
     927             : int
     928           0 : vlan_get_compat(struct ifnet *ifp, struct ifreq *ifr)
     929             : {
     930           0 :         struct ifvlan *ifv = ifp->if_softc;
     931           0 :         struct vlanreq vlr;
     932             :         struct ifnet *p;
     933             : 
     934           0 :         memset(&vlr, 0, sizeof(vlr));
     935           0 :         p = if_get(ifv->ifv_ifp0);
     936           0 :         if (p != NULL)
     937           0 :                 memcpy(vlr.vlr_parent, p->if_xname, sizeof(vlr.vlr_parent));
     938           0 :         if_put(p);
     939             : 
     940           0 :         vlr.vlr_tag = ifv->ifv_tag;
     941             : 
     942           0 :         return (copyout(&vlr, ifr->ifr_data, sizeof(vlr)));
     943           0 : }
     944             : 
     945             : /*
     946             :  * do a quick check of up and running vlans for existing configurations.
     947             :  *
     948             :  * NOTE: this does allow the same config on down vlans, but vlan_up()
     949             :  * will catch them.
     950             :  */
     951             : int
     952           0 : vlan_inuse(uint16_t type, unsigned int ifidx, uint16_t tag)
     953             : {
     954             :         int error = 0;
     955             : 
     956           0 :         error = rw_enter(&vlan_tagh_lk, RW_READ | RW_INTR);
     957           0 :         if (error != 0)
     958           0 :                 return (error);
     959             : 
     960           0 :         error = vlan_inuse_locked(type, ifidx, tag);
     961             : 
     962           0 :         rw_exit(&vlan_tagh_lk);
     963             : 
     964           0 :         return (error);
     965           0 : }
     966             : 
     967             : int
     968           0 : vlan_inuse_locked(uint16_t type, unsigned int ifidx, uint16_t tag)
     969             : {
     970             :         SRPL_HEAD(, ifvlan) *tagh, *list;
     971             :         struct ifvlan *ifv;
     972             : 
     973           0 :         tagh = type == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh;
     974           0 :         list = &tagh[TAG_HASH(tag)];
     975             : 
     976           0 :         SRPL_FOREACH_LOCKED(ifv, list, ifv_list) {
     977           0 :                 if (ifv->ifv_tag == tag &&
     978           0 :                     ifv->ifv_type == type && /* wat */
     979           0 :                     ifv->ifv_ifp0 == ifidx)
     980           0 :                         return (EADDRINUSE);
     981             :         }
     982             : 
     983           0 :         return (0);
     984           0 : }
     985             : 
     986             : int
     987           0 : vlan_multi_add(struct ifvlan *ifv, struct ifreq *ifr)
     988             : {
     989             :         struct ifnet            *ifp0;
     990             :         struct vlan_mc_entry    *mc;
     991           0 :         u_int8_t                 addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
     992             :         int                      error;
     993             : 
     994           0 :         error = ether_addmulti(ifr, &ifv->ifv_ac);
     995           0 :         if (error != ENETRESET)
     996           0 :                 return (error);
     997             : 
     998             :         /*
     999             :          * This is new multicast address.  We have to tell parent
    1000             :          * about it.  Also, remember this multicast address so that
    1001             :          * we can delete them on unconfigure.
    1002             :          */
    1003           0 :         if ((mc = malloc(sizeof(*mc), M_DEVBUF, M_NOWAIT)) == NULL) {
    1004             :                 error = ENOMEM;
    1005           0 :                 goto alloc_failed;
    1006             :         }
    1007             : 
    1008             :         /*
    1009             :          * As ether_addmulti() returns ENETRESET, following two
    1010             :          * statement shouldn't fail.
    1011             :          */
    1012           0 :         (void)ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi);
    1013           0 :         ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ac, mc->mc_enm);
    1014           0 :         memcpy(&mc->mc_addr, &ifr->ifr_addr, ifr->ifr_addr.sa_len);
    1015           0 :         LIST_INSERT_HEAD(&ifv->vlan_mc_listhead, mc, mc_entries);
    1016             : 
    1017           0 :         ifp0 = if_get(ifv->ifv_ifp0);
    1018           0 :         error = (ifp0 == NULL) ? 0 :
    1019           0 :             (*ifp0->if_ioctl)(ifp0, SIOCADDMULTI, (caddr_t)ifr);
    1020           0 :         if_put(ifp0);
    1021             : 
    1022           0 :         if (error != 0)
    1023             :                 goto ioctl_failed;
    1024             : 
    1025           0 :         return (error);
    1026             : 
    1027             :  ioctl_failed:
    1028           0 :         LIST_REMOVE(mc, mc_entries);
    1029           0 :         free(mc, M_DEVBUF, sizeof(*mc));
    1030             :  alloc_failed:
    1031           0 :         (void)ether_delmulti(ifr, &ifv->ifv_ac);
    1032             : 
    1033           0 :         return (error);
    1034           0 : }
    1035             : 
    1036             : int
    1037           0 : vlan_multi_del(struct ifvlan *ifv, struct ifreq *ifr)
    1038             : {
    1039             :         struct ifnet            *ifp0;
    1040             :         struct ether_multi      *enm;
    1041             :         struct vlan_mc_entry    *mc;
    1042           0 :         u_int8_t                 addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
    1043             :         int                      error;
    1044             : 
    1045             :         /*
    1046             :          * Find a key to lookup vlan_mc_entry.  We have to do this
    1047             :          * before calling ether_delmulti for obvious reason.
    1048             :          */
    1049           0 :         if ((error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi)) != 0)
    1050           0 :                 return (error);
    1051           0 :         ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ac, enm);
    1052           0 :         if (enm == NULL)
    1053           0 :                 return (EINVAL);
    1054             : 
    1055           0 :         LIST_FOREACH(mc, &ifv->vlan_mc_listhead, mc_entries) {
    1056           0 :                 if (mc->mc_enm == enm)
    1057             :                         break;
    1058             :         }
    1059             : 
    1060             :         /* We won't delete entries we didn't add */
    1061           0 :         if (mc == NULL)
    1062           0 :                 return (EINVAL);
    1063             : 
    1064           0 :         error = ether_delmulti(ifr, &ifv->ifv_ac);
    1065           0 :         if (error != ENETRESET)
    1066           0 :                 return (error);
    1067             : 
    1068           0 :         if (!ISSET(ifv->ifv_if.if_flags, IFF_RUNNING))
    1069             :                 goto forget;
    1070             : 
    1071           0 :         ifp0 = if_get(ifv->ifv_ifp0);
    1072           0 :         error = (ifp0 == NULL) ? 0 :
    1073           0 :             (*ifp0->if_ioctl)(ifp0, SIOCDELMULTI, (caddr_t)ifr);
    1074           0 :         if_put(ifp0);
    1075             : 
    1076           0 :         if (error != 0) {
    1077           0 :                 (void)ether_addmulti(ifr, &ifv->ifv_ac);
    1078           0 :                 return (error);
    1079             :         }
    1080             : 
    1081             : forget:
    1082             :         /* forget about this address */
    1083           0 :         LIST_REMOVE(mc, mc_entries);
    1084           0 :         free(mc, M_DEVBUF, sizeof(*mc));
    1085             : 
    1086           0 :         return (0);
    1087           0 : }
    1088             : 
    1089             : int
    1090           0 : vlan_media_get(struct ifvlan *ifv, struct ifreq *ifr)
    1091             : {
    1092             :         struct ifnet            *ifp0;
    1093             :         int                      error;
    1094             : 
    1095           0 :         ifp0 = if_get(ifv->ifv_ifp0);
    1096           0 :         error = (ifp0 == NULL) ? ENOTTY :
    1097           0 :             (*ifp0->if_ioctl)(ifp0, SIOCGIFMEDIA, (caddr_t)ifr);
    1098           0 :         if_put(ifp0);
    1099             : 
    1100           0 :         return (error);
    1101             : }
    1102             : 
    1103             : void
    1104           0 : vlan_multi_apply(struct ifvlan *ifv, struct ifnet *ifp0, u_long cmd)
    1105             : {
    1106             :         struct vlan_mc_entry    *mc;
    1107           0 :         union {
    1108             :                 struct ifreq ifreq;
    1109             :                 struct {
    1110             :                         char                    ifr_name[IFNAMSIZ];
    1111             :                         struct sockaddr_storage ifr_ss;
    1112             :                 } ifreq_storage;
    1113             :         } ifreq;
    1114           0 :         struct ifreq    *ifr = &ifreq.ifreq;
    1115             : 
    1116           0 :         memcpy(ifr->ifr_name, ifp0->if_xname, IFNAMSIZ);
    1117           0 :         LIST_FOREACH(mc, &ifv->vlan_mc_listhead, mc_entries) {
    1118           0 :                 memcpy(&ifr->ifr_addr, &mc->mc_addr, mc->mc_addr.ss_len);
    1119             : 
    1120           0 :                 (void)(*ifp0->if_ioctl)(ifp0, cmd, (caddr_t)ifr);
    1121             :         }
    1122           0 : }
    1123             : 
    1124             : void
    1125           0 : vlan_multi_free(struct ifvlan *ifv)
    1126             : {
    1127             :         struct vlan_mc_entry    *mc;
    1128             : 
    1129           0 :         while ((mc = LIST_FIRST(&ifv->vlan_mc_listhead)) != NULL) {
    1130           0 :                 LIST_REMOVE(mc, mc_entries);
    1131           0 :                 free(mc, M_DEVBUF, sizeof(*mc));
    1132             :         }
    1133           0 : }

Generated by: LCOV version 1.13