On 09/03/16(Wed) 16:26, David Gwynne wrote:
> this is an unfortunately large reworking of vlan(4) to make tx mpsafe
This is great but unfortunately hard to review.
> it also includes the following:
>
> - moving away from the vlan specific SIOC[SG]ETVLAN ioctls to the
> SIOC[SGD]{VNETID,IFPARENT} ioctls
> [...]
> - added compat for the legacy ioctls built out of the new ioctls
> [...]
> - added compat for the old ifconfig options.
> [...]
> - made the implicit IFF_UP handling like other drivers
>
> other drivers do IFF_UP when you configure an address on the
> interface. vlan(4) did it when you configured a vlan/vlandev, but
> not when you configured an interface.
>
> - serialise changes affecting the vlan tag hashes used on input.
I don't like the way it is done. If you insist for putting a rwlock
then I'd rather see it in the common ioctl path in net/if.c. This
way you don't need to back your locking for every driver.
I bet that we're going to change our mind about how we're serializing
ioctl(2) code execution in some months? years?. So I'd rather keep
the code easy to grok and modify.
> - restrict config changes while IFF_UP
Makes sense.
> - rework multicast group membership handling
This should be kept in sync with the other pseudo-drivers.
> - make transmit mpsafe
>
> this relied on a lot of fixes on the config side to be safe, but
> the changes to vlan_start are hilariously small compared to the
> config changes.
>
>
> it is big, but pulling it apart would be error prone and a long
> process to get us to the same place this diff is already at.
If the goal you want to reach is to commit a mpsafe vlan(4) I agree.
But if what you want is peer review, which implies teaching others
about your changes, then I disagree. Splitting your diff is like
doing the effort yourself to make it easier for others to understand.
Asking for ok on a big diff is like asking me (because nobody else
will look at that) to wrap my head around your 1,3K lines diff. Would
you do that if I was asking you? Maybe. I won't.
> i would welcome tests and eyes.
As I already said you insisted for the parent interface to be name
"ifp0" coherently in carp(4) I think you should do the same here.
> Index: sbin/ifconfig/ifconfig.c
> ===================================================================
> RCS file: /cvs/src/sbin/ifconfig/ifconfig.c,v
> retrieving revision 1.316
> diff -u -p -r1.316 ifconfig.c
> --- sbin/ifconfig/ifconfig.c 2 Mar 2016 00:00:16 -0000 1.316
> +++ sbin/ifconfig/ifconfig.c 9 Mar 2016 05:47:13 -0000
> @@ -181,6 +181,7 @@ void settunnelinst(const char *, int);
> void settunnelttl(const char *, int);
> void setvnetid(const char *, int);
> void delvnetid(const char *, int);
> +void getvnetid(void);
> void setifparent(const char *, int);
> void delifparent(const char *, int);
> void getifparent(void);
> @@ -209,12 +210,8 @@ void setmpwencap(const char *, int);
> void setmpwlabel(const char *, const char *);
> void setmpwneighbor(const char *, int);
> void setmpwcontrolword(const char *, int);
> -void setvlantag(const char *, int);
> -void setvlandev(const char *, int);
> -void unsetvlandev(const char *, int);
> void mpe_status(void);
> void mpw_status(void);
> -void vlan_status(void);
> void setinstance(const char *, int);
> int main(int, char *[]);
> int prefix(void *val, int);
> @@ -350,9 +347,9 @@ const struct cmd {
> { "scan", NEXTARG0, 0, setifscan },
> { "broadcast", NEXTARG, 0, setifbroadaddr },
> { "prefixlen", NEXTARG, 0, setifprefixlen},
> - { "vlan", NEXTARG, 0, setvlantag },
> - { "vlandev", NEXTARG, 0, setvlandev },
> - { "-vlandev", 1, 0, unsetvlandev },
> + { "vlan", NEXTARG, 0, setvnetid },
> + { "vlandev", NEXTARG, 0, setifparent },
> + { "-vlandev", 1, 0, delifparent },
> { "group", NEXTARG, 0, setifgroup },
> { "-group", NEXTARG, 0, unsetifgroup },
> { "autoconf", 1, 0, setautoconf },
> @@ -2850,8 +2847,6 @@ phys_status(int force)
>
> if (dstport)
> printf(":%u", ntohs(dstport));
> - if (ioctl(s, SIOCGVNETID, (caddr_t)&ifr) == 0)
> - printf(" vnetid %d", ifr.ifr_vnetid);
> if (ioctl(s, SIOCGLIFPHYTTL, (caddr_t)&ifr) == 0 && ifr.ifr_ttl > 0)
> printf(" ttl %d", ifr.ifr_ttl);
> #ifndef SMALL
> @@ -2942,7 +2937,7 @@ status(int link, struct sockaddr_dl *sdl
> if_indextoname(ifrdesc.ifr_index, ifname) != NULL)
> printf("\tpatch: %s\n", ifname);
> #endif
> - vlan_status();
> + getvnetid();
> getifparent();
> #ifndef SMALL
> carp_status();
> @@ -3399,6 +3394,24 @@ delvnetid(const char *ignored, int alsoi
> }
>
> void
> +getvnetid(void)
> +{
> + if (strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)) >=
> + sizeof(ifr.ifr_name))
> + errx(1, "vnetid: name is too long");
> +
> + if (ioctl(s, SIOCGVNETID, &ifr) == -1) {
> + if (errno != EADDRNOTAVAIL)
> + return;
> +
> + printf("\tvnetid: none\n");
> + return;
> + }
> +
> + printf("\tvnetid: %u\n", ifr.ifr_vnetid);
> +}
> +
> +void
> setifparent(const char *id, int param)
> {
> struct if_parent ifp;
> @@ -3628,100 +3641,6 @@ setmpwcontrolword(const char *value, int
> imrsave.imr_flags &= ~IMR_FLAG_CONTROLWORD;
> }
> #endif /* SMALL */
> -
> -static int __tag = 0;
> -static int __have_tag = 0;
> -
> -void
> -vlan_status(void)
> -{
> - struct vlanreq vreq;
> -
> - bzero((char *)&vreq, sizeof(struct vlanreq));
> - ifr.ifr_data = (caddr_t)&vreq;
> -
> - if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
> - return;
> -
> - if (vreq.vlr_tag || (vreq.vlr_parent[0] != '\0'))
> - printf("\tvlan: %d parent interface: %s\n",
> - vreq.vlr_tag, vreq.vlr_parent[0] == '\0' ?
> - "<none>" : vreq.vlr_parent);
> -}
> -
> -/* ARGSUSED */
> -void
> -setvlantag(const char *val, int d)
> -{
> - u_int16_t tag;
> - struct vlanreq vreq;
> - const char *errmsg = NULL;
> -
> - __tag = tag = strtonum(val, 0, 4095, &errmsg);
> - if (errmsg)
> - errx(1, "vlan tag %s: %s", val, errmsg);
> - __have_tag = 1;
> -
> - bzero((char *)&vreq, sizeof(struct vlanreq));
> - ifr.ifr_data = (caddr_t)&vreq;
> -
> - if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
> - err(1, "SIOCGETVLAN");
> -
> - vreq.vlr_tag = tag;
> -
> - if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
> - err(1, "SIOCSETVLAN");
> -}
> -
> -/* ARGSUSED */
> -void
> -setvlandev(const char *val, int d)
> -{
> - struct vlanreq vreq;
> - int tag;
> - size_t skip;
> - const char *estr;
> -
> - bzero((char *)&vreq, sizeof(struct vlanreq));
> - ifr.ifr_data = (caddr_t)&vreq;
> -
> - if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
> - err(1, "SIOCGETVLAN");
> -
> - (void) strlcpy(vreq.vlr_parent, val, sizeof(vreq.vlr_parent));
> -
> - if (!__have_tag && vreq.vlr_tag == 0) {
> - skip = strcspn(ifr.ifr_name, "0123456789");
> - tag = strtonum(ifr.ifr_name + skip, 0, 4095, &estr);
> - if (estr != NULL)
> - errx(1, "invalid vlan tag and device specification");
> - vreq.vlr_tag = tag;
> - } else if (__have_tag)
> - vreq.vlr_tag = __tag;
> -
> - if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
> - err(1, "SIOCSETVLAN");
> -}
> -
> -/* ARGSUSED */
> -void
> -unsetvlandev(const char *val, int d)
> -{
> - struct vlanreq vreq;
> -
> - bzero((char *)&vreq, sizeof(struct vlanreq));
> - ifr.ifr_data = (caddr_t)&vreq;
> -
> - if (ioctl(s, SIOCGETVLAN, (caddr_t)&ifr) == -1)
> - err(1, "SIOCGETVLAN");
> -
> - bzero((char *)&vreq.vlr_parent, sizeof(vreq.vlr_parent));
> - vreq.vlr_tag = 0;
> -
> - if (ioctl(s, SIOCSETVLAN, (caddr_t)&ifr) == -1)
> - err(1, "SIOCSETVLAN");
> -}
>
> void
> settrunkport(const char *val, int d)
> Index: sys/net/if_vlan.c
> ===================================================================
> RCS file: /cvs/src/sys/net/if_vlan.c,v
> retrieving revision 1.152
> diff -u -p -r1.152 if_vlan.c
> --- sys/net/if_vlan.c 3 Mar 2016 02:53:28 -0000 1.152
> +++ sys/net/if_vlan.c 9 Mar 2016 05:47:17 -0000
> @@ -78,23 +78,34 @@
> #define TAG_HASH_MASK (TAG_HASH_SIZE - 1)
> #define TAG_HASH(tag) (tag & TAG_HASH_MASK)
> SRPL_HEAD(, ifvlan) *vlan_tagh, *svlan_tagh;
> -struct rwlock vlan_tagh_lk = RWLOCK_INITIALIZER("vlantag");
> +struct rwlock vlan_cfg_lk = RWLOCK_INITIALIZER("vlantag");
>
> int vlan_input(struct ifnet *, struct mbuf *, void *);
> void vlan_start(struct ifnet *ifp);
> int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr);
> -int vlan_unconfig(struct ifnet *ifp, struct ifnet *newp);
> -int vlan_config(struct ifvlan *, struct ifnet *, u_int16_t);
> -void vlan_vlandev_state(void *);
> +int vlan_up(struct ifvlan *);
> +int vlan_down(struct ifvlan *);
> +int vlan_p_unconfig(struct ifnet *, struct ifnet *);
> +int vlan_p_config(struct ifvlan *, struct ifnet *);
> +void vlan_link_hook(void *);
> +void vlan_link_state(struct ifvlan *, u_char, uint64_t);
> void vlanattach(int count);
> int vlan_set_promisc(struct ifnet *ifp);
> -int vlan_ether_addmulti(struct ifvlan *, struct ifreq *);
> -int vlan_ether_delmulti(struct ifvlan *, struct ifreq *);
> -void vlan_ether_purgemulti(struct ifvlan *);
> -void vlan_ether_resetmulti(struct ifvlan *, struct ifnet *);
> +int vlan_set_vnetid(struct ifvlan *, uint16_t);
> +
> +int vlan_set_compat(struct ifnet *, struct ifreq *);
> +int vlan_get_compat(struct ifnet *, struct ifreq *);
> +
> +int vlan_multi_add(struct ifvlan *, struct ifreq *);
> +int vlan_multi_del(struct ifvlan *, struct ifreq *);
> +void vlan_multi_apply(struct ifvlan *, struct ifnet *, u_long);
> +void vlan_multi_free(struct ifvlan *);
> +
> +int vlan_inuse(uint16_t, unsigned int, uint16_t);
> +int vlan_inuse_locked(uint16_t, unsigned int, uint16_t);
> +
> int vlan_clone_create(struct if_clone *, int);
> int vlan_clone_destroy(struct ifnet *);
> -void vlan_ifdetach(void *);
>
> struct if_clone vlan_cloner =
> IF_CLONE_INITIALIZER("vlan", vlan_clone_create, vlan_clone_destroy);
> @@ -145,10 +156,9 @@ vlan_clone_create(struct if_clone *ifc,
> LIST_INIT(&ifv->vlan_mc_listhead);
> ifp = &ifv->ifv_if;
> ifp->if_softc = ifv;
> - snprintf(ifp->if_xname, sizeof ifp->if_xname, "%s%d", ifc->ifc_name,
> - unit);
> + snprintf(ifp->if_xname, sizeof(ifp->if_xname), "%s%d",
> + ifc->ifc_name, unit);
> /* NB: flags are not set here */
> - /* NB: mtu is not set here */
>
> /* Special handling for the IEEE 802.1ad QinQ variant */
> if (strcmp("svlan", ifc->ifc_name) == 0)
> @@ -157,10 +167,12 @@ vlan_clone_create(struct if_clone *ifc,
> ifv->ifv_type = ETHERTYPE_VLAN;
>
> refcnt_init(&ifv->ifv_refcnt);
> -
> + ifp->if_flags = IFF_BROADCAST | IFF_MULTICAST;
> + ifp->if_xflags = IFXF_MPSAFE;
> ifp->if_start = vlan_start;
> ifp->if_ioctl = vlan_ioctl;
> - IFQ_SET_MAXLEN(&ifp->if_snd, 1);
> + ifp->if_hardmtu = 0xffff;
> + ifp->if_link_state = LINK_STATE_DOWN;
> IFQ_SET_READY(&ifp->if_snd);
> if_attach(ifp);
> ether_ifattach(ifp);
> @@ -190,22 +202,18 @@ vlan_clone_destroy(struct ifnet *ifp)
> {
> struct ifvlan *ifv = ifp->if_softc;
>
> - vlan_unconfig(ifp, NULL);
> + if (ISSET(ifp->if_flags, IFF_RUNNING))
> + vlan_down(ifv);
> +
> ether_ifdetach(ifp);
> if_detach(ifp);
> refcnt_finalize(&ifv->ifv_refcnt, "vlanrefs");
> + vlan_multi_free(ifv);
> free(ifv, M_DEVBUF, sizeof(*ifv));
>
> return (0);
> }
>
> -void
> -vlan_ifdetach(void *ptr)
> -{
> - struct ifvlan *ifv = ptr;
> - vlan_clone_destroy(&ifv->ifv_if);
> -}
> -
> static inline int
> vlan_mplstunnel(int ifidx)
> {
> @@ -227,31 +235,23 @@ vlan_mplstunnel(int ifidx)
> void
> vlan_start(struct ifnet *ifp)
> {
> - struct ifvlan *ifv;
> + struct ifvlan *ifv = ifp->if_softc;
> struct ifnet *p;
> struct mbuf *m;
> uint8_t prio;
>
> - ifv = ifp->if_softc;
> - p = ifv->ifv_p;
> -
> - for (;;) {
> - IFQ_DEQUEUE(&ifp->if_snd, m);
> - if (m == NULL)
> - break;
> + p = if_get(ifv->ifv_p);
> + if (p == NULL) {
> + IFQ_PURGE(&ifp->if_snd);
> + return;
> + }
>
> + while ((m = ifq_dequeue(&ifp->if_snd)) != NULL) {
> #if NBPFILTER > 0
> if (ifp->if_bpf)
> bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT);
> #endif /* NBPFILTER > 0 */
>
> - if ((p->if_flags & (IFF_UP|IFF_RUNNING)) !=
> - (IFF_UP|IFF_RUNNING)) {
> - ifp->if_oerrors++;
> - m_freem(m);
> - continue;
> - }
> -
> /* IEEE 802.1p has prio 0 and 1 swapped */
> prio = m->m_pkthdr.pf.prio;
> if (prio <= 1)
> @@ -314,7 +314,7 @@ vlan_inject(struct mbuf *m, uint16_t typ
> * vlan_input() returns 1 if it has consumed the packet, 0 otherwise.
> */
> int
> -vlan_input(struct ifnet *ifp, struct mbuf *m, void *cookie)
> +vlan_input(struct ifnet *p, struct mbuf *m, void *cookie)
> {
> struct ifvlan *ifv;
> struct ether_vlan_header *evl;
> @@ -332,9 +332,9 @@ vlan_input(struct ifnet *ifp, struct mbu
> etype = ETHERTYPE_VLAN;
> tagh = vlan_tagh;
> } else if ((etype == ETHERTYPE_VLAN) || (etype == ETHERTYPE_QINQ)) {
> - if (m->m_len < EVL_ENCAPLEN &&
> - (m = m_pullup(m, EVL_ENCAPLEN)) == NULL) {
> - ifp->if_ierrors++;
> + if (m->m_len < sizeof(*evl) &&
> + (m = m_pullup(m, sizeof(*evl))) == NULL) {
> + p->if_ierrors++;
> return (1);
> }
>
> @@ -356,13 +356,14 @@ vlan_input(struct ifnet *ifp, struct mbu
>
> list = &tagh[TAG_HASH(tag)];
> SRPL_FOREACH(ifv, list, &i, ifv_list) {
> - if (ifp == ifv->ifv_p && tag == ifv->ifv_tag &&
> + if (p->if_index == ifv->ifv_p &&
> + tag == ifv->ifv_tag &&
> etype == ifv->ifv_type)
> break;
> }
>
> if (ifv == NULL) {
> - ifp->if_noproto++;
> + p->if_noproto++;
> goto drop;
> }
>
> @@ -371,18 +372,6 @@ vlan_input(struct ifnet *ifp, struct mbu
> goto drop;
>
> /*
> - * Drop promiscuously received packets if we are not in
> - * promiscuous mode.
> - */
> - if (!ETHER_IS_MULTICAST(eh->ether_dhost) &&
> - (ifp->if_flags & IFF_PROMISC) &&
> - (ifv->ifv_if.if_flags & IFF_PROMISC) == 0) {
> - if (bcmp(&ifv->ifv_ac.ac_enaddr, eh->ether_dhost,
> - ETHER_ADDR_LEN))
> - goto drop;
> - }
> -
> - /*
> * Having found a valid vlan interface corresponding to
> * the given source interface and vlan tag, remove the
> * encapsulation.
> @@ -406,47 +395,150 @@ drop:
> return (1);
> }
>
> +void
> +vlan_p_detach(void *v)
> +{
> + struct ifvlan *ifv = v;
> + struct ifnet *ifp = &ifv->ifv_if;
> +
> + if (ISSET(ifp->if_flags, IFF_RUNNING)) {
> + (void)vlan_down(ifv);
> + CLR(ifp->if_flags, IFF_UP);
> + }
> +
> + ifv->ifv_p = 0;
> +}
> +
> +void
> +vlan_link_hook(void *v)
> +{
> + struct ifvlan *ifv = v;
> + struct ifnet *p;
> +
> + u_char link = LINK_STATE_DOWN;
> + uint64_t baud = 0;
> +
> + p = if_get(ifv->ifv_p);
> + if (p != NULL) {
> + link = p->if_link_state;
> + baud = p->if_baudrate;
> + }
> + if_put(p);
> +
> + vlan_link_state(ifv, link, baud);
> +}
> +
> +void
> +vlan_link_state(struct ifvlan *ifv, u_char link, uint64_t baud)
> +{
> + if (ifv->ifv_if.if_link_state == link)
> + return;
> +
> + ifv->ifv_if.if_link_state = link;
> + ifv->ifv_if.if_baudrate = baud;
> +
> + if_link_state_change(&ifv->ifv_if);
> +}
> +
> int
> -vlan_config(struct ifvlan *ifv, struct ifnet *p, u_int16_t tag)
> +vlan_promisc(struct ifvlan *ifv, int promisc)
> {
> - struct sockaddr_dl *sdl1, *sdl2;
> - SRPL_HEAD(, ifvlan) *tagh, *list;
> - u_int flags;
> -
> - if (p->if_type != IFT_ETHER)
> - return EPROTONOSUPPORT;
> - if (ifv->ifv_p == p && ifv->ifv_tag == tag) /* noop */
> + struct ifnet *p;
> + int error = 0;
> +
> + if (ifv->ifv_promisc == promisc)
> return (0);
>
> - /* Remember existing interface flags and reset the interface */
> - flags = ifv->ifv_flags;
> - vlan_unconfig(&ifv->ifv_if, p);
> - ifv->ifv_p = p;
> - ifv->ifv_if.if_baudrate = p->if_baudrate;
> -
> - if (p->if_capabilities & IFCAP_VLAN_MTU) {
> - ifv->ifv_if.if_mtu = p->if_mtu;
> - ifv->ifv_if.if_hardmtu = p->if_hardmtu;
> - } else {
> - ifv->ifv_if.if_mtu = p->if_mtu - EVL_ENCAPLEN;
> - ifv->ifv_if.if_hardmtu = p->if_hardmtu - EVL_ENCAPLEN;
> + p = if_get(ifv->ifv_p);
> + if (p != NULL) {
> + error = ifpromisc(p, promisc);
> + }
> + if_put(p);
> +
> + if (error == 0)
> + ifv->ifv_promisc = promisc;
> +
> + return (error);
> +}
> +
> +int
> +vlan_parent_config(struct ifvlan *ifv, struct ifnet *p)
> +{
> + int error;
> +
> + vlan_multi_apply(ifv, p, SIOCADDMULTI);
> +
> + if (ifv->ifv_promisc) {
> + error = ifpromisc(p, 1);
> + if (error != 0)
> + goto delmulti;
> + }
> +
> + return (0);
> +
> +delmulti:
> + vlan_multi_apply(ifv, p, SIOCDELMULTI);
> + return (error);
> +}
> +
> +int
> +vlan_up(struct ifvlan *ifv)
> +{
> + struct ifnet *ifp = &ifv->ifv_if;
> + struct ifnet *p;
> + SRPL_HEAD(, ifvlan) *tagh, *list;
> + int error = 0;
> + u_int hardmtu;
> +
> + KASSERT(!ISSET(ifp->if_flags, IFF_RUNNING));
> +
> + tagh = ifv->ifv_type == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh;
> + list = &tagh[TAG_HASH(ifv->ifv_tag)];
> +
> + if (ifv->ifv_tag == EVL_VLID_NONE)
> + return (EADDRNOTAVAIL);
> +
> + p = if_get(ifv->ifv_p);
> + if (p == NULL)
> + return (ENXIO);
> +
> + if (p->if_type != IFT_ETHER) {
> + error = EPROTONOSUPPORT;
> + goto put;
> }
>
> - ifv->ifv_if.if_flags = p->if_flags &
> - (IFF_UP | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
> + hardmtu = p->if_hardmtu;
> + if (!ISSET(p->if_capabilities, IFCAP_VLAN_MTU))
> + hardmtu -= EVL_ENCAPLEN;
>
> - /* Reset promisc mode on the interface and its parent */
> - if (flags & IFVF_PROMISC) {
> - ifv->ifv_if.if_flags |= IFF_PROMISC;
> - vlan_set_promisc(&ifv->ifv_if);
> + if (ifp->if_mtu > hardmtu) {
> + error = ENOBUFS;
> + goto put;
> }
>
> + error = rw_enter(&vlan_cfg_lk, RW_WRITE | RW_INTR);
> + if (error != 0)
> + goto put;
> +
> + error = vlan_inuse_locked(ifv->ifv_type, ifv->ifv_p, ifv->ifv_tag);
> + if (error != 0)
> + goto leave;
> +
> + error = vlan_parent_config(ifv, p);
> + if (error != 0)
> + goto leave;
> +
> + /* commit */
> + ifp->if_hardmtu = hardmtu;
> + ifp->if_flags |= p->if_flags & IFF_SIMPLEX;
> +
> + if_setlladdr(ifp, LLADDR(p->if_sadl));
> if (ifv->ifv_type != ETHERTYPE_VLAN) {
> /*
> - * Hardware offload only works with the default VLAN
> + * Hardware offloads only works with the default VLAN
> * ethernet type (0x8100).
> */
> - ifv->ifv_if.if_capabilities = 0;
> + ifp->if_capabilities = 0;
> } else if (p->if_capabilities & IFCAP_VLAN_HWTAGGING) {
> /*
> * If the parent interface can do hardware-assisted
> @@ -456,251 +548,359 @@ vlan_config(struct ifvlan *ifv, struct i
> * If the card cannot handle hardware tagging, it cannot
> * possibly compute the correct checksums for tagged packets.
> */
> - ifv->ifv_if.if_capabilities = p->if_capabilities &
> - IFCAP_CSUM_MASK;
> + ifp->if_capabilities = p->if_capabilities & IFCAP_CSUM_MASK;
> }
>
> - /*
> - * Set up our ``Ethernet address'' to reflect the underlying
> - * physical interface's.
> - */
> - sdl1 = ifv->ifv_if.if_sadl;
> - sdl2 = p->if_sadl;
> - sdl1->sdl_type = IFT_ETHER;
> - sdl1->sdl_alen = ETHER_ADDR_LEN;
> - bcopy(LLADDR(sdl2), LLADDR(sdl1), ETHER_ADDR_LEN);
> - bcopy(LLADDR(sdl2), ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN);
> -
> - ifv->ifv_tag = tag;
> -
> /* Register callback for physical link state changes */
> ifv->lh_cookie = hook_establish(p->if_linkstatehooks, 1,
> - vlan_vlandev_state, ifv);
> + vlan_link_hook, ifv);
>
> /* Register callback if parent wants to unregister */
> ifv->dh_cookie = hook_establish(p->if_detachhooks, 0,
> - vlan_ifdetach, ifv);
> + vlan_p_detach, ifv);
>
> - vlan_vlandev_state(ifv);
> -
> - /* Change input handler of the physical interface. */
> + SRPL_INSERT_HEAD_LOCKED(&vlan_tagh_rc, list, ifv, ifv_list);
> if_ih_insert(p, vlan_input, NULL);
>
> - tagh = ifv->ifv_type == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh;
> - list = &tagh[TAG_HASH(tag)];
> + vlan_link_state(ifv, p->if_link_state, p->if_baudrate);
>
> - rw_enter_write(&vlan_tagh_lk);
> - SRPL_INSERT_HEAD_LOCKED(&vlan_tagh_rc, list, ifv, ifv_list);
> - rw_exit_write(&vlan_tagh_lk);
> + SET(ifp->if_flags, IFF_RUNNING);
>
> - return (0);
> +leave:
> + rw_exit(&vlan_cfg_lk);
> +
> +put:
> + if_put(p);
> + return (error);
> }
>
> int
> -vlan_unconfig(struct ifnet *ifp, struct ifnet *newp)
> +vlan_down(struct ifvlan *ifv)
> {
> - struct sockaddr_dl *sdl;
> - struct ifvlan *ifv;
> - SRPL_HEAD(, ifvlan) *tagh, *list;
> - struct ifnet *p;
> + SRPL_HEAD(, ifvlan) *tagh, *list;
> + struct ifnet *ifp = &ifv->ifv_if;
> + struct ifnet *p;
> + int error;
>
> - ifv = ifp->if_softc;
> - if ((p = ifv->ifv_p) == NULL)
> - return 0;
> -
> - /* Unset promisc mode on the interface and its parent */
> - if (ifv->ifv_flags & IFVF_PROMISC) {
> - ifp->if_flags &= ~IFF_PROMISC;
> - vlan_set_promisc(ifp);
> - }
> + KASSERT(ISSET(ifp->if_flags, IFF_RUNNING));
>
> tagh = ifv->ifv_type == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh;
> list = &tagh[TAG_HASH(ifv->ifv_tag)];
>
> - rw_enter_write(&vlan_tagh_lk);
> - SRPL_REMOVE_LOCKED(&vlan_tagh_rc, list, ifv, ifvlan, ifv_list);
> - rw_exit_write(&vlan_tagh_lk);
> + error = rw_enter(&vlan_cfg_lk, RW_WRITE | RW_INTR);
> + if (error != 0)
> + return (error);
>
> - /* Restore previous input handler. */
> - if_ih_remove(p, vlan_input, NULL);
> + CLR(ifp->if_flags, IFF_RUNNING);
>
> - hook_disestablish(p->if_linkstatehooks, ifv->lh_cookie);
> - hook_disestablish(p->if_detachhooks, ifv->dh_cookie);
> - /* Reset link state */
> - if (newp != NULL) {
> - ifp->if_link_state = LINK_STATE_INVALID;
> - if_link_state_change(ifp);
> - }
> + ifq_barrier(&ifp->if_snd);
>
> - /*
> - * Since the interface is being unconfigured, we need to
> - * empty the list of multicast groups that we may have joined
> - * while we were alive and remove them from the parent's list
> - * as well.
> - */
> - vlan_ether_resetmulti(ifv, newp);
> + vlan_link_state(ifv, LINK_STATE_DOWN, 0);
>
> - /* Disconnect from parent. */
> - ifv->ifv_p = NULL;
> - ifv->ifv_if.if_mtu = ETHERMTU;
> - ifv->ifv_if.if_hardmtu = ETHERMTU;
> - ifv->ifv_flags = 0;
> -
> - /* Clear our MAC address. */
> - sdl = ifv->ifv_if.if_sadl;
> - sdl->sdl_type = IFT_ETHER;
> - sdl->sdl_alen = ETHER_ADDR_LEN;
> - bzero(LLADDR(sdl), ETHER_ADDR_LEN);
> - bzero(ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN);
> + p = if_get(ifv->ifv_p);
> + if (p != NULL)
> + if_ih_remove(p, vlan_input, NULL);
> + if_put(p);
>
> - return (0);
> -}
> + SRPL_REMOVE_LOCKED(&vlan_tagh_rc, list, ifv, ifvlan, ifv_list);
>
> -void
> -vlan_vlandev_state(void *v)
> -{
> - struct ifvlan *ifv = v;
> + hook_disestablish(p->if_detachhooks, ifv->dh_cookie);
> + hook_disestablish(p->if_linkstatehooks, ifv->lh_cookie);
>
> - if (ifv->ifv_if.if_link_state == ifv->ifv_p->if_link_state)
> - return;
> + ifp->if_capabilities = 0;
>
> - ifv->ifv_if.if_link_state = ifv->ifv_p->if_link_state;
> - ifv->ifv_if.if_baudrate = ifv->ifv_p->if_baudrate;
> - if_link_state_change(&ifv->ifv_if);
> -}
> + if_setlladdr(ifp, etheranyaddr);
>
> -int
> -vlan_set_promisc(struct ifnet *ifp)
> -{
> - struct ifvlan *ifv = ifp->if_softc;
> - int error = 0;
> + CLR(ifp->if_flags, IFF_SIMPLEX);
> +
> + ifp->if_hardmtu = 0xffff;
> +
> + rw_exit(&vlan_cfg_lk);
>
> - if ((ifp->if_flags & IFF_PROMISC) != 0) {
> - if ((ifv->ifv_flags & IFVF_PROMISC) == 0)
> - if ((error = ifpromisc(ifv->ifv_p, 1)) == 0)
> - ifv->ifv_flags |= IFVF_PROMISC;
> - } else {
> - if ((ifv->ifv_flags & IFVF_PROMISC) != 0)
> - if ((error = ifpromisc(ifv->ifv_p, 0)) == 0)
> - ifv->ifv_flags &= ~IFVF_PROMISC;
> - }
> return (0);
> }
>
> int
> vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
> {
> - struct proc *p = curproc; /* XXX */
> - struct ifaddr *ifa;
> - struct ifnet *pr;
> - struct ifreq *ifr;
> - struct ifvlan *ifv;
> - struct vlanreq vlr;
> - int error = 0, s;
> -
> - ifr = (struct ifreq *)data;
> - ifa = (struct ifaddr *)data;
> - ifv = ifp->if_softc;
> + struct ifvlan *ifv = ifp->if_softc;
> + struct ifreq *ifr = (struct ifreq *)data;
> + struct if_parent *parent = (struct if_parent *)data;
> + struct ifnet *p;
> + uint16_t tag;
> + int error = 0;
>
> switch (cmd) {
> case SIOCSIFADDR:
> - if (ifv->ifv_p != NULL)
> - ifp->if_flags |= IFF_UP;
> - else
> - error = EINVAL;
> + ifp->if_flags |= IFF_UP;
> + /* FALLTHROUGH */
> +
> + case SIOCSIFFLAGS:
> + error = vlan_promisc(ifv,
> + ISSET(ifp->if_flags, IFF_PROMISC) ? 1 : 0);
> + if (error != 0)
> + break;
> +
> + if (ISSET(ifp->if_flags, IFF_UP)) {
> + if (!ISSET(ifp->if_flags, IFF_RUNNING))
> + error = vlan_up(ifv);
> + } else {
> + if (ISSET(ifp->if_flags, IFF_RUNNING))
> + error = vlan_down(ifv);
> + }
> break;
>
> - case SIOCSIFMTU:
> - if (ifv->ifv_p != NULL) {
> - if (ifr->ifr_mtu < ETHERMIN ||
> - ifr->ifr_mtu > ifv->ifv_if.if_hardmtu)
> - error = EINVAL;
> - else
> - ifp->if_mtu = ifr->ifr_mtu;
> - } else
> + case SIOCSVNETID:
> + tag = ifr->ifr_vnetid;
> + if (tag == ifv->ifv_tag)
> + break;
> +
> + if (tag < EVL_VLID_MIN || tag > EVL_VLID_MAX) {
> error = EINVAL;
> + break;
> + }
>
> + error = vlan_set_vnetid(ifv, tag);
> break;
>
> - case SIOCSETVLAN:
> - if ((error = suser(p, 0)) != 0)
> - break;
> - if ((error = copyin(ifr->ifr_data, &vlr, sizeof vlr)))
> + case SIOCGVNETID:
> + if (ifv->ifv_tag == EVL_VLID_NONE)
> + error = EADDRNOTAVAIL;
> + else
> + ifr->ifr_vnetid = (uint32_t)ifv->ifv_tag;
> + break;
> +
> + case SIOCDVNETID:
> + if (ISSET(ifp->if_flags, IFF_RUNNING)) {
> + error = EBUSY;
> break;
> - if (vlr.vlr_parent[0] == '\0') {
> - s = splnet();
> - vlan_unconfig(ifp, NULL);
> - if (ifp->if_flags & IFF_UP)
> - if_down(ifp);
> - ifp->if_flags &= ~IFF_RUNNING;
> - splx(s);
> - break;
> - }
> - pr = ifunit(vlr.vlr_parent);
> - if (pr == NULL) {
> - error = ENOENT;
> + }
> +
> + ifv->ifv_tag = 0;
> + break;
> +
> + case SIOCSIFPARENT:
> + if (ISSET(ifp->if_flags, IFF_RUNNING)) {
> + error = EBUSY;
> break;
> }
> - /*
> - * Don't let the caller set up a VLAN tag with
> - * anything except VLID bits.
> - */
> - if (vlr.vlr_tag & ~EVL_VLID_MASK) {
> +
> + p = ifunit(parent->ifp_parent);
> + if (p == NULL) {
> error = EINVAL;
> break;
> }
> - error = vlan_config(ifv, pr, vlr.vlr_tag);
> - if (error)
> +
> + if (ifv->ifv_p == p->if_index) {
> + /* nop */
> break;
> - ifp->if_flags |= IFF_RUNNING;
> + }
>
> - /* Update promiscuous mode, if necessary. */
> - vlan_set_promisc(ifp);
> - break;
> -
> - case SIOCGETVLAN:
> - bzero(&vlr, sizeof vlr);
> - if (ifv->ifv_p) {
> - snprintf(vlr.vlr_parent, sizeof(vlr.vlr_parent),
> - "%s", ifv->ifv_p->if_xname);
> - vlr.vlr_tag = ifv->ifv_tag;
> + if (p->if_type != IFT_ETHER) {
> + error = EPROTONOSUPPORT;
> + break;
> }
> - error = copyout(&vlr, ifr->ifr_data, sizeof vlr);
> +
> + error = vlan_inuse(ifv->ifv_type, p->if_index, ifv->ifv_tag);
> + if (error != 0)
> + break;
> +
> + ifv->ifv_p = p->if_index;
> break;
> - case SIOCSIFFLAGS:
> - /*
> - * For promiscuous mode, we enable promiscuous mode on
> - * the parent if we need promiscuous on the VLAN interface.
> - */
> - if (ifv->ifv_p != NULL)
> - error = vlan_set_promisc(ifp);
> +
> + case SIOCGIFPARENT:
> + p = if_get(ifv->ifv_p);
> + if (p == NULL)
> + error = EADDRNOTAVAIL;
> + else {
> + memcpy(parent->ifp_parent, p->if_xname,
> + sizeof(parent->ifp_parent));
> + }
> + if_put(p);
> break;
>
> + case SIOCDIFPARENT:
> + if (ISSET(ifp->if_flags, IFF_RUNNING)) {
> + error = EBUSY;
> + break;
> + }
> +
> + ifv->ifv_p = 0;
> + break;
> +
> case SIOCADDMULTI:
> - error = (ifv->ifv_p != NULL) ?
> - vlan_ether_addmulti(ifv, ifr) : EINVAL;
> + error = vlan_multi_add(ifv, ifr);
> break;
> -
> case SIOCDELMULTI:
> - error = (ifv->ifv_p != NULL) ?
> - vlan_ether_delmulti(ifv, ifr) : EINVAL;
> + error = vlan_multi_del(ifv, ifr);
> + break;
> +
> + case SIOCSETVLAN:
> + error = vlan_set_compat(ifp, ifr);
> + break;
> + case SIOCGETVLAN:
> + error = vlan_get_compat(ifp, ifr);
> break;
> +
> default:
> - error = ENOTTY;
> + error = ether_ioctl(ifp, &ifv->ifv_ac, cmd, data);
> + break;
> }
> - return error;
> +
> + return (error);
> }
>
> +int
> +vlan_set_vnetid(struct ifvlan *ifv, uint16_t tag)
> +{
> + struct ifnet *ifp = &ifv->ifv_if;
> + SRPL_HEAD(, ifvlan) *tagh, *list;
> + int error;
> +
> + tagh = ifv->ifv_type == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh;
> +
> + error = rw_enter(&vlan_cfg_lk, RW_WRITE | RW_INTR);
> + if (error != 0)
> + return (error);
> +
> + error = vlan_inuse_locked(ifv->ifv_type, ifv->ifv_p, tag);
> + if (error != 0)
> + goto unlock;
> +
> + if (ISSET(ifp->if_flags, IFF_RUNNING)) {
> + u_char link = ifp->if_link_state;
> + uint64_t baud = ifp->if_baudrate;
> +
> + if (LINK_STATE_IS_UP(link))
> + vlan_link_state(ifv, LINK_STATE_DOWN, 0);
> +
> + list = &tagh[TAG_HASH(ifv->ifv_tag)];
> + SRPL_REMOVE_LOCKED(&vlan_tagh_rc, list, ifv, ifvlan, ifv_list);
> +
> + ifv->ifv_tag = tag;
> + list = &tagh[TAG_HASH(ifv->ifv_tag)];
> + SRPL_INSERT_HEAD_LOCKED(&vlan_tagh_rc, list, ifv, ifv_list);
> +
> + if (LINK_STATE_IS_UP(link))
> + vlan_link_state(ifv, link, baud);
> + } else
> + ifv->ifv_tag = tag;
> +
> +unlock:
> + rw_exit(&vlan_cfg_lk);
> +
> + return (error);
> +}
>
> int
> -vlan_ether_addmulti(struct ifvlan *ifv, struct ifreq *ifr)
> +vlan_set_compat(struct ifnet *ifp, struct ifreq *ifr)
> {
> - struct ifnet *ifp = ifv->ifv_p;
> + struct vlanreq vlr;
> + struct ifreq req;
> + struct if_parent parent;
> +
> + int error;
> +
> + error = suser(curproc, 0);
> + if (error != 0)
> + return (error);
> +
> + error = copyin(ifr->ifr_data, &vlr, sizeof(vlr));
> + if (error != 0)
> + return (error);
> +
> + if (vlr.vlr_parent[0] == '\0')
> + return (vlan_ioctl(ifp, SIOCDIFPARENT, (caddr_t)ifr));
> +
> + memset(&req, 0, sizeof(req));
> + memcpy(req.ifr_name, ifp->if_xname, sizeof(req.ifr_name));
> + req.ifr_vnetid = vlr.vlr_tag;
> +
> + error = vlan_ioctl(ifp, SIOCSVNETID, (caddr_t)&req);
> + if (error != 0)
> + return (error);
> +
> + memset(&parent, 0, sizeof(parent));
> + memcpy(parent.ifp_name, ifp->if_xname, sizeof(parent.ifp_name));
> + memcpy(parent.ifp_parent, vlr.vlr_parent, sizeof(parent.ifp_parent));
> + error = vlan_ioctl(ifp, SIOCSIFPARENT, (caddr_t)&parent);
> + if (error != 0)
> + return (error);
> +
> + memset(&req, 0, sizeof(req));
> + memcpy(req.ifr_name, ifp->if_xname, sizeof(req.ifr_name));
> + SET(ifp->if_flags, IFF_UP);
> + return (vlan_ioctl(ifp, SIOCSIFFLAGS, (caddr_t)&req));
> +}
> +
> +int
> +vlan_get_compat(struct ifnet *ifp, struct ifreq *ifr)
> +{
> + struct ifvlan *ifv = ifp->if_softc;
> + struct vlanreq vlr;
> + struct ifnet *p;
> +
> + memset(&vlr, 0, sizeof(vlr));
> + p = if_get(ifv->ifv_p);
> + if (p != NULL)
> + memcpy(vlr.vlr_parent, p->if_xname, sizeof(vlr.vlr_parent));
> + if_put(p);
> +
> + vlr.vlr_tag = ifv->ifv_tag;
> +
> + return (copyout(&vlr, ifr->ifr_data, sizeof(vlr)));
> +}
> +
> +/*
> + * do a quick check of up and running vlans for existing configurations.
> + *
> + * NOTE: this does allow the same config on down vlans, but vlan_up()
> + * will catch them.
> + */
> +int
> +vlan_inuse(uint16_t type, unsigned int ifidx, uint16_t tag)
> +{
> + int error = 0;
> +
> + error = rw_enter(&vlan_cfg_lk, RW_READ | RW_INTR);
> + if (error != 0)
> + return (error);
> +
> + error = vlan_inuse_locked(type, ifidx, tag);
> +
> + rw_exit(&vlan_cfg_lk);
> +
> + return (error);
> +}
> +
> +int
> +vlan_inuse_locked(uint16_t type, unsigned int ifidx, uint16_t tag)
> +{
> + SRPL_HEAD(, ifvlan) *tagh, *list;
> + struct ifvlan *ifv;
> +
> + tagh = type == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh;
> + list = &tagh[TAG_HASH(tag)];
> +
> + SRPL_FOREACH_LOCKED(ifv, list, ifv_list) {
> + if (ifv->ifv_tag == tag &&
> + ifv->ifv_type == type && /* wat */
> + ifv->ifv_p == ifidx)
> + return (EADDRINUSE);
> + }
> +
> + return (0);
> +}
> +
> +int
> +vlan_multi_add(struct ifvlan *ifv, struct ifreq *ifr)
> +{
> + struct ifnet *p;
> struct vlan_mc_entry *mc;
> u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
> int error;
>
> - error = ether_addmulti(ifr, (struct arpcom *)&ifv->ifv_ac);
> + error = ether_addmulti(ifr, &ifv->ifv_ac);
> if (error != ENETRESET)
> return (error);
>
> @@ -723,24 +923,28 @@ vlan_ether_addmulti(struct ifvlan *ifv,
> memcpy(&mc->mc_addr, &ifr->ifr_addr, ifr->ifr_addr.sa_len);
> LIST_INSERT_HEAD(&ifv->vlan_mc_listhead, mc, mc_entries);
>
> - if ((error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)ifr)) != 0)
> + p = if_get(ifv->ifv_p);
> + error = p == NULL ? 0 : (*p->if_ioctl)(p, SIOCADDMULTI, (caddr_t)ifr);
> + if_put(p);
> +
> + if (error != 0)
> goto ioctl_failed;
>
> return (error);
>
> ioctl_failed:
> LIST_REMOVE(mc, mc_entries);
> - free(mc, M_DEVBUF, sizeof *mc);
> + free(mc, M_DEVBUF, sizeof(*mc));
> alloc_failed:
> - (void)ether_delmulti(ifr, (struct arpcom *)&ifv->ifv_ac);
> + (void)ether_delmulti(ifr, &ifv->ifv_ac);
>
> return (error);
> }
>
> int
> -vlan_ether_delmulti(struct ifvlan *ifv, struct ifreq *ifr)
> +vlan_multi_del(struct ifvlan *ifv, struct ifreq *ifr)
> {
> - struct ifnet *ifp = ifv->ifv_p;
> + struct ifnet *p;
> struct ether_multi *enm;
> struct vlan_mc_entry *mc;
> u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
> @@ -756,35 +960,42 @@ vlan_ether_delmulti(struct ifvlan *ifv,
> if (enm == NULL)
> return (EINVAL);
>
> - LIST_FOREACH(mc, &ifv->vlan_mc_listhead, mc_entries)
> + LIST_FOREACH(mc, &ifv->vlan_mc_listhead, mc_entries) {
> if (mc->mc_enm == enm)
> break;
> + }
>
> /* We won't delete entries we didn't add */
> if (mc == NULL)
> return (EINVAL);
>
> - if ((error = ether_delmulti(ifr, (struct arpcom *)&ifv->ifv_ac)) != 0)
> + error = ether_delmulti(ifr, &ifv->ifv_ac);
> + if (error != ENETRESET)
> + return (error);
> +
> + if (!ISSET(ifv->ifv_if.if_flags, IFF_RUNNING))
> + goto forget;
> +
> + p = if_get(ifv->ifv_p);
> + error = p == NULL ? 0 : (*p->if_ioctl)(p, SIOCDELMULTI, (caddr_t)ifr);
> + if_put(p);
> +
> + if (error != 0) {
> + (void)ether_addmulti(ifr, &ifv->ifv_ac);
> return (error);
> + }
>
> - /* We no longer use this multicast address. Tell parent so. */
> - if ((error = (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr)) != 0) {
> - /* And forget about this address. */
> - LIST_REMOVE(mc, mc_entries);
> - free(mc, M_DEVBUF, sizeof *mc);
> - } else
> - (void)ether_addmulti(ifr, (struct arpcom *)&ifv->ifv_ac);
> - return (error);
> +forget:
> + /* forget about this address */
> + LIST_REMOVE(mc, mc_entries);
> + free(mc, M_DEVBUF, sizeof(*mc));
> +
> + return (0);
> }
>
> -/*
> - * Delete any multicast address we have asked to add from parent
> - * interface. Called when the vlan is being unconfigured.
> - */
> void
> -vlan_ether_purgemulti(struct ifvlan *ifv)
> +vlan_multi_apply(struct ifvlan *ifv, struct ifnet *p, u_long cmd)
> {
> - struct ifnet *ifp = ifv->ifv_p;
> struct vlan_mc_entry *mc;
> union {
> struct ifreq ifreq;
> @@ -795,44 +1006,21 @@ vlan_ether_purgemulti(struct ifvlan *ifv
> } ifreq;
> struct ifreq *ifr = &ifreq.ifreq;
>
> - memcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ);
> - while ((mc = LIST_FIRST(&ifv->vlan_mc_listhead)) != NULL) {
> + memcpy(ifr->ifr_name, p->if_xname, IFNAMSIZ);
> + LIST_FOREACH(mc, &ifv->vlan_mc_listhead, mc_entries) {
> memcpy(&ifr->ifr_addr, &mc->mc_addr, mc->mc_addr.ss_len);
> - (void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr);
> - LIST_REMOVE(mc, mc_entries);
> - free(mc, M_DEVBUF, sizeof *mc);
> +
> + (void)(*p->if_ioctl)(p, cmd, (caddr_t)ifr);
> }
> }
>
> void
> -vlan_ether_resetmulti(struct ifvlan *ifv, struct ifnet *p)
> +vlan_multi_free(struct ifvlan *ifv)
> {
> - struct ifnet *ifp = ifv->ifv_p;
> struct vlan_mc_entry *mc;
> - union {
> - struct ifreq ifreq;
> - struct {
> - char ifr_name[IFNAMSIZ];
> - struct sockaddr_storage ifr_ss;
> - } ifreq_storage;
> - } ifreq;
> - struct ifreq *ifr = &ifreq.ifreq;
>
> - if (p == NULL) {
> - vlan_ether_purgemulti(ifv);
> - return;
> - } else if (ifp == p)
> - return;
> -
> - LIST_FOREACH(mc, &ifv->vlan_mc_listhead, mc_entries) {
> - memcpy(&ifr->ifr_addr, &mc->mc_addr, mc->mc_addr.ss_len);
> -
> - /* Remove from the old parent */
> - memcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ);
> - (void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr);
> -
> - /* Try to add to the new parent */
> - memcpy(ifr->ifr_name, p->if_xname, IFNAMSIZ);
> - (void)(*p->if_ioctl)(p, SIOCADDMULTI, (caddr_t)ifr);
> + while ((mc = LIST_FIRST(&ifv->vlan_mc_listhead)) != NULL) {
> + LIST_REMOVE(mc, mc_entries);
> + free(mc, M_DEVBUF, sizeof(*mc));
> }
> }
> Index: sys/net/if_vlan_var.h
> ===================================================================
> RCS file: /cvs/src/sys/net/if_vlan_var.h,v
> retrieving revision 1.32
> diff -u -p -r1.32 if_vlan_var.h
> --- sys/net/if_vlan_var.h 3 Mar 2016 09:27:51 -0000 1.32
> +++ sys/net/if_vlan_var.h 9 Mar 2016 05:47:17 -0000
> @@ -42,7 +42,11 @@ struct ether_vlan_header {
> u_int16_t evl_proto;
> };
>
> -#define EVL_VLID_MASK 0x0FFF
> +#define EVL_VLID_MASK 0xFFF
> +#define EVL_VLID_NONE 0x000
> +/* 0x000 and 0xFFF are reserved */
> +#define EVL_VLID_MIN 0x001
> +#define EVL_VLID_MAX 0xFFE
> #define EVL_VLANOFTAG(tag) ((tag) & EVL_VLID_MASK)
> #define EVL_PRIOFTAG(tag) (((tag) >> EVL_PRIO_BITS) & 7)
> #define EVL_ENCAPLEN 4 /* length in octets of encapsulation */
> @@ -76,28 +80,24 @@ struct vlan_mc_entry {
>
> struct ifvlan {
> struct arpcom ifv_ac; /* make this an interface */
> - struct ifnet *ifv_p; /* parent interface of this vlan */
> + unsigned int ifv_p; /* parent interface of this vlan */
> struct ifv_linkmib {
> - int ifvm_parent;
> - u_int16_t ifvm_proto; /* encapsulation ethertype */
> u_int16_t ifvm_tag; /* tag to apply on packets leaving if */
> u_int16_t ifvm_prio; /* prio to apply on packet leaving if */
> u_int16_t ifvm_type; /* non-standard ethertype or 0x8100 */
> } ifv_mib;
> LIST_HEAD(__vlan_mchead, vlan_mc_entry) vlan_mc_listhead;
> SRPL_ENTRY(ifvlan) ifv_list;
> - int ifv_flags;
> + int ifv_promisc;
> struct refcnt ifv_refcnt;
> void *lh_cookie;
> void *dh_cookie;
> - struct ifih *ifv_ifih;
> };
>
> #define ifv_if ifv_ac.ac_if
> #define ifv_tag ifv_mib.ifvm_tag
> #define ifv_prio ifv_mib.ifvm_prio
> #define ifv_type ifv_mib.ifvm_type
> -#define IFVF_PROMISC 0x01
>
> struct mbuf *vlan_inject(struct mbuf *, uint16_t, uint16_t);
> #endif /* _KERNEL */
>
>