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/                 

Reply via email to