From 6d2f1ab40f2fa8813b579aeea7a0d7dd97e47a12 Mon Sep 17 00:00:00 2001 From: David Gwynne Date: Tue, 19 Apr 2016 23:31:33 +0000 Subject: make setting a vlan interfaces lladdr more likely to work the recent vlan code sets the vlan interfaces mac address to the parent interfaces mac address when it is brought up, and resets it when the vlan interface is brought down. now, if you set a mac address manually (eg, ifconfig vlanX lladdr f0:0b:a7:ba:2b:00), vlan(4) ignores the parents mac address and never resets its own. to make this work, setting a custom lladdr on a vlan interface makes the parent interface promisc so the packets wont be filtered by the hardware interface. setting the mac address to 00:00:00:00:00:00 resets this behavior and makes the interface inherit the parents mac again. issue reported by and fix tested by paul de weerd --- sys/net/if_vlan.c | 112 +++++++++++++++++++++++++++++++++++--------------- sys/net/if_vlan_var.h | 5 ++- 2 files changed, 81 insertions(+), 36 deletions(-) (limited to 'sys/net') diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c index 2e7ea5f1a9c..d9eaf106399 100644 --- a/sys/net/if_vlan.c +++ b/sys/net/if_vlan.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_vlan.c,v 1.162 2016/04/15 04:34:10 dlg Exp $ */ +/* $OpenBSD: if_vlan.c,v 1.163 2016/04/19 23:31:32 dlg Exp $ */ /* * Copyright 1998 Massachusetts Institute of Technology @@ -92,8 +92,6 @@ int vlan_up(struct ifvlan *); int vlan_parent_up(struct ifvlan *, struct ifnet *); int vlan_down(struct ifvlan *); -int vlan_promisc(struct ifvlan *, int); - void vlan_ifdetach(void *); void vlan_link_hook(void *); void vlan_link_state(struct ifvlan *, u_char, u_int64_t); @@ -107,6 +105,9 @@ 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_iff(struct ifvlan *); +int vlan_setlladdr(struct ifvlan *, struct ifreq *); + int vlan_set_compat(struct ifnet *, struct ifreq *); int vlan_get_compat(struct ifnet *, struct ifreq *); @@ -470,7 +471,8 @@ vlan_up(struct ifvlan *ifv) /* parent is fine, let's prepare the ifv to handle packets */ ifp->if_hardmtu = hardmtu; SET(ifp->if_flags, ifp0->if_flags & IFF_SIMPLEX); - if_setlladdr(ifp, LLADDR(ifp0->if_sadl)); + if (!ISSET(ifv->ifv_flags, IFVF_LLADDR)) + if_setlladdr(ifp, LLADDR(ifp0->if_sadl)); if (ifv->ifv_type != ETHERTYPE_VLAN) { /* @@ -522,7 +524,8 @@ leave: rw_exit(&vlan_tagh_lk); scrub: ifp->if_capabilities = 0; - if_setlladdr(ifp, etheranyaddr); + if (!ISSET(ifv->ifv_flags, IFVF_LLADDR)) + if_setlladdr(ifp, etheranyaddr); CLR(ifp->if_flags, IFF_SIMPLEX); ifp->if_hardmtu = 0xffff; put: @@ -564,7 +567,8 @@ vlan_down(struct ifvlan *ifv) rw_exit_write(&vlan_tagh_lk); ifp->if_capabilities = 0; - if_setlladdr(ifp, etheranyaddr); + if (!ISSET(ifv->ifv_flags, IFVF_LLADDR)) + if_setlladdr(ifp, etheranyaddr); CLR(ifp->if_flags, IFF_SIMPLEX); ifp->if_hardmtu = 0xffff; @@ -616,29 +620,6 @@ vlan_link_state(struct ifvlan *ifv, u_char link, uint64_t baud) if_link_state_change(&ifv->ifv_if); } -int -vlan_promisc(struct ifvlan *ifv, int promisc) -{ - struct ifnet *ifp0; - int error = 0; - - if ((ISSET(ifv->ifv_flags, IFVF_PROMISC) ? 1 : 0) == promisc) - return (0); - - ifp0 = if_get(ifv->ifv_ifp0); - if (ifp0 != NULL) { - error = ifpromisc(ifp0, promisc); - } - if_put(ifp0); - - if (error == 0) { - CLR(ifv->ifv_flags, IFVF_PROMISC); - SET(ifv->ifv_flags, promisc ? IFVF_PROMISC : 0); - } - - return (error); -} - int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) { @@ -655,14 +636,11 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) /* 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 + error = ENETRESET; } else { if (ISSET(ifp->if_flags, IFF_RUNNING)) error = vlan_down(ifv); @@ -749,6 +727,10 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) error = vlan_multi_del(ifv, ifr); break; + case SIOCSIFLLADDR: + error = vlan_setlladdr(ifv, ifr); + break; + case SIOCSETVLAN: error = vlan_set_compat(ifp, ifr); break; @@ -761,9 +743,71 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) break; } + if (error == ENETRESET) { + vlan_iff(ifv); + error = 0; + } + return error; } +int +vlan_iff(struct ifvlan *ifv) +{ + struct ifnet *ifp0; + int promisc = 0; + int error = 0; + + if (ISSET(ifv->ifv_if.if_flags, IFF_PROMISC) || + ISSET(ifv->ifv_flags, IFVF_LLADDR)) + promisc = IFVF_PROMISC; + + if (ISSET(ifv->ifv_flags, IFVF_PROMISC) == promisc) + return (0); + + if (ISSET(ifv->ifv_if.if_flags, IFF_RUNNING)) { + ifp0 = if_get(ifv->ifv_ifp0); + if (ifp0 != NULL) + error = ifpromisc(ifp0, promisc); + if_put(ifp0); + } + + if (error == 0) { + CLR(ifv->ifv_flags, IFVF_PROMISC); + SET(ifv->ifv_flags, promisc); + } + + return (error); +} + +int +vlan_setlladdr(struct ifvlan *ifv, struct ifreq *ifr) +{ + struct ifnet *ifp = &ifv->ifv_if;; + struct ifnet *ifp0; + int flag = IFVF_LLADDR; + + /* setting the mac addr to 00:00:00:00:00:00 means reset lladdr */ + if (memcmp(ifr->ifr_addr.sa_data, etheranyaddr, ETHER_ADDR_LEN) == 0) + flag = 0; + + if (ISSET(ifv->ifv_flags, IFVF_LLADDR) == flag) + return (0); + + /* if we're up and the mac is reset, inherit the parents mac */ + if (ISSET(ifp->if_flags, IFF_RUNNING) && flag == 0) { + ifp0 = if_get(ifv->ifv_ifp0); + if (ifp0 != NULL) + if_setlladdr(ifp, LLADDR(ifp0->if_sadl)); + if_put(ifp0); + } + + CLR(ifv->ifv_flags, IFVF_LLADDR); + SET(ifv->ifv_flags, flag); + + return (ENETRESET); +} + int vlan_set_vnetid(struct ifvlan *ifv, uint16_t tag) { diff --git a/sys/net/if_vlan_var.h b/sys/net/if_vlan_var.h index ea479f57bcf..9361a9f33bd 100644 --- a/sys/net/if_vlan_var.h +++ b/sys/net/if_vlan_var.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_vlan_var.h,v 1.35 2016/04/15 04:34:10 dlg Exp $ */ +/* $OpenBSD: if_vlan_var.h,v 1.36 2016/04/19 23:31:32 dlg Exp $ */ /* * Copyright 1998 Massachusetts Institute of Technology @@ -81,7 +81,8 @@ struct ifvlan { #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 +#define IFVF_PROMISC 0x01 /* the parent should be made promisc */ +#define IFVF_LLADDR 0x02 /* don't inherit the parents mac */ struct mbuf *vlan_inject(struct mbuf *, uint16_t, uint16_t); #endif /* _KERNEL */ -- cgit v1.2.3