After experimenting some more, I've come to the conclusion that trying to
manually add a non-IP ethernet multicast address doesn't work properly.
The ether_resolvemulti() assumes that addresses will be specified as
either AF_LINK or AF_INET; if the family is AF_LINK, it assumes that
a struct sockaddr_dl will be used. However, the user is supposed to
pass the address using a struct ifreq, and struct ifreq uses struct
sockaddr, not struct sockaddr_dl.

The original code in 2.2.x expected a struct sockaddr with a family
of AF_UNSPEC. This no longer works in 3.0, which breaks compatibility.
Among other things, the Columbia Appletalk port doesn't work because
of this.

As an aside, the equal() macro in /sys/net/if.c does a bcmp() using
sa_len as the length of the data to check, but doesn't account for
the possibility of sa_len being 0 (this makes it always return true,
which can yield false positives).

The patches included with this post change /sys/net/if.c and
/sys/net/if_ethersubr.c so that adding a mutlicast address with 
SIOCADDMULTI using a struct sockaddr and AF_UNSPEC works again. I would 
like Those Who Know More Than I (tm) to review these changes and offer 
criticisms and comments.

These patches are against 3.0-RELEASE but should apply to -current
and -stable as well.

-Bill

-- 
=============================================================================
-Bill Paul            (212) 854-6020 | System Manager, Master of Unix-Fu
Work:         wp...@ctr.columbia.edu | Center for Telecommunications Research
Home:  wp...@skynet.ctr.columbia.edu | Columbia University, New York City
=============================================================================
 "It is not I who am crazy; it is I who am mad!" - Ren Hoek, "Space Madness"
=============================================================================

*** if.c.orig   Sun Jan 31 17:13:01 1999
--- if.c        Sun Jan 31 17:10:36 1999
***************
*** 186,192 ****
        register struct ifaddr *ifa;
  
  #define       equal(a1, a2) \
!   (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
        for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next)
            for (ifa = ifp->if_addrhead.tqh_first; ifa; 
                 ifa = ifa->ifa_link.tqe_next) {
--- 186,193 ----
        register struct ifaddr *ifa;
  
  #define       equal(a1, a2) \
!   (((struct sockaddr *)(a1))->sa_len && \
!    bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0)
        for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next)
            for (ifa = ifp->if_addrhead.tqh_first; ifa; 
                 ifa = ifa->ifa_link.tqe_next) {
***************
*** 636,642 ****
                        return EOPNOTSUPP;
  
                /* Don't let users screw up protocols' entries. */
!               if (ifr->ifr_addr.sa_family != AF_LINK)
                        return EINVAL;
  
                if (cmd == SIOCADDMULTI) {
--- 637,644 ----
                        return EOPNOTSUPP;
  
                /* Don't let users screw up protocols' entries. */
!               if (ifr->ifr_addr.sa_family != AF_LINK &&
!                       ifr->ifr_addr.sa_family != AF_UNSPEC)
                        return EINVAL;
  
                if (cmd == SIOCADDMULTI) {
*** if_ethersubr.c.orig Sun Jan 31 17:13:07 1999
--- if_ethersubr.c      Sun Jan 31 17:00:54 1999
***************
*** 778,783 ****
--- 778,800 ----
        u_char *e_addr;
  
        switch(sa->sa_family) {
+       case AF_UNSPEC:
+               e_addr = (u_char *)&sa->sa_data;
+               if ((e_addr[0] & 1) != 1)
+                       return EADDRNOTAVAIL;
+               MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
+                      M_WAITOK);
+               sdl->sdl_len = sizeof *sdl;
+               sdl->sdl_family = AF_LINK;
+               sdl->sdl_index = ifp->if_index;
+               sdl->sdl_type = IFT_ETHER;
+               sdl->sdl_nlen = 0;
+               sdl->sdl_alen = ETHER_ADDR_LEN;
+               sdl->sdl_slen = 0;
+               e_addr = LLADDR(sdl);
+               bcopy((char *)&sa->sa_data, (char *)e_addr, ETHER_ADDR_LEN);
+               *llsa = (struct sockaddr *)sdl;
+               return 0;
        case AF_LINK:
                /* 
                 * No mapping needed. Just check that it's a valid MC address.

To Unsubscribe: send mail to majord...@freebsd.org
with "unsubscribe freebsd-current" in the body of the message

Reply via email to