On Tue, Apr 19, 2016 at 11:56:45PM +1000, David Gwynne wrote:
| On Tue, Dec 22, 2015 at 10:11:23PM +0100, Paul de Weerd wrote:
| > Hi all,
| >
| > My ISP requires me to use different MAC addresses for internet and TV
| > access. These services arrive at the demarc as two different ethernet
| > VLANs, vlan4 (television) and vlan34 (internet), on one copper GE
| > port.
| >
| > I can get a lease on vlan34 just fine, and have internet access. Then
| > I change the MAC on my vlan4 interface:
| >
| > $ ifconfig vlan4 lladdr <some other MAC>
| >
| > However, dhclient doesn't give me a lease. To debug, I run tcpdump
| > and try again: lo, an offer arrives.
| >
| > Turns out, vlan4 only works when the parent interface (em2, in my
| > case) is in promiscuous mode. Seems to make sense from a naive
| > point of view: the interface filters traffic that's destined for it's
| > own MAC address, dropping traffic for other MACs. Is this a problem
| > with the em(4) driver, with vlan(4) or elsewhere?
|
| i think vlan.
Thanks David. I've applied your diff and built a fresh kernel with
it. Everything works fine now, without the bridge-hack.
Cheers!
Paul
| the diff below allows a vlan interface to be configured with a
| custom mac address. if that is done, itll mark itself as having a
| custom lladdr and will in turn enable promisc on the parent interface
| so those packets will actually end up coming into the kernel.
|
| it supports setting the mac address while the vlan interface is
| both up and down.
|
| if you set the mac address on the vlan interface to 00:00:00:00:00:00,
| itll treat that as removing the custom mac and will replace it with
| the parents mac address.
|
| lastly, this makes no effort to cope with the mac address of the
| parent interface being changed at runtime.
|
| Index: if_vlan_var.h
| ===================================================================
| RCS file: /cvs/src/sys/net/if_vlan_var.h,v
| retrieving revision 1.35
| diff -u -p -r1.35 if_vlan_var.h
| --- if_vlan_var.h 15 Apr 2016 04:34:10 -0000 1.35
| +++ if_vlan_var.h 19 Apr 2016 13:30:31 -0000
| @@ -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 */
| Index: if_vlan.c
| ===================================================================
| RCS file: /cvs/src/sys/net/if_vlan.c,v
| retrieving revision 1.162
| diff -u -p -r1.162 if_vlan.c
| --- if_vlan.c 15 Apr 2016 04:34:10 -0000 1.162
| +++ if_vlan.c 19 Apr 2016 13:30:31 -0000
| @@ -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 *, stru
| 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 *);
|
| @@ -432,6 +433,7 @@ vlan_parent_up(struct ifvlan *ifv, struc
| if_ih_insert(ifp0, vlan_input, NULL);
|
| return (0);
| +
| }
|
| int
| @@ -470,7 +472,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 +525,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 +568,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 +622,6 @@ vlan_link_state(struct ifvlan *ifv, u_ch
| }
|
| 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 +637,11 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd
| /* 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 +728,10 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd
| 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,7 +744,71 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd
| break;
| }
|
| + if (error == ENETRESET) {
| + if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
| + (IFF_UP | IFF_RUNNING))
| + 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
--
>++++++++[<++++++++++>-]<+++++++.>+++[<------>-]<.>+++[<+
+++++++++++>-]<.>++[<------------>-]<+.--------------.[-]
http://www.weirdnet.nl/