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