summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2016-04-19 23:31:33 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2016-04-19 23:31:33 +0000
commit6d2f1ab40f2fa8813b579aeea7a0d7dd97e47a12 (patch)
treea638069aaa6df457777af54cd5a1364704af3e4c
parent94f05de63943d09787168fee12c4337b5b688329 (diff)
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
-rw-r--r--sys/net/if_vlan.c112
-rw-r--r--sys/net/if_vlan_var.h5
2 files changed, 81 insertions, 36 deletions
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;
@@ -617,29 +621,6 @@ vlan_link_state(struct ifvlan *ifv, u_char link, uint64_t baud)
}
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)
{
struct ifvlan *ifv = ifp->if_softc;
@@ -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,10 +743,72 @@ 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)
{
struct ifnet *ifp = &ifv->ifv_if;
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 */