Update routed to use the RFC 3678 protocol-independent multicast API. Use IP_MULTICAST_IF with struct ip_mreqn (obtained from Linux) to tell the stack which interface index to use for sending IPv4 datagrams. diff -uNr routed.orig/defs.h routed/defs.h --- routed.orig/defs.h Thu Nov 11 17:34:53 2004 +++ routed/defs.h Sun Apr 8 02:43:06 2007 @@ -123,21 +123,6 @@ #define _HAVE_SIN_LEN #endif -/* Turn on if IP_{ADD,DROP}_MEMBERSHIP and IP_MULTICAST_IF considers address - * within 0.0.0.0/8 as interface index. - */ -#ifdef __NetBSD__ -#define MCAST_IFINDEX -#endif - -/* Turn on if IP_DROP_MEMBERSHIP and IP_ADD_MEMBERSHIP do not look at - * the dstaddr of point-to-point interfaces. - * #define MCAST_PPP_BUG - */ -#ifdef MCAST_IFINDEX -#undef MCAST_PPP_BUG -#endif - #define DAY (24*60*60) #define NEVER DAY /* a long time */ #define EPOCH NEVER /* bias time by this to avoid <0 */ diff -uNr routed.orig/if.c routed/if.c --- routed.orig/if.c Thu Nov 11 17:34:22 2004 +++ routed/if.c Sun Apr 8 02:51:35 2007 @@ -454,7 +454,6 @@ static void ifdel(struct interface *ifp) { - struct ip_mreq m; struct interface *ifp1; @@ -493,25 +492,23 @@ ifdel(ifp1); } - if ((ifp->int_if_flags & IFF_MULTICAST) -#ifdef MCAST_PPP_BUG - && !(ifp->int_if_flags & IFF_POINTOPOINT) + if ((ifp->int_if_flags & IFF_MULTICAST) && rip_sock >= 0) { + struct group_req gr; + struct sockaddr_in *sin; + + memset(&gr, 0, sizeof(gr)); + gr.gr_interface = ifp->int_index; + sin = (struct sockaddr_in *)&gr.gr_group; + sin->sin_family = AF_INET; +#ifdef _HAVE_SIN_LEN + sin->sin_len = sizeof(struct sockaddr_in); #endif - && rip_sock >= 0) { - m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP); -#ifdef MCAST_IFINDEX - m.imr_interface.s_addr = htonl(ifp->int_index); -#else - m.imr_interface.s_addr = ((ifp->int_if_flags - & IFF_POINTOPOINT) - ? ifp->int_dstaddr - : ifp->int_addr); -#endif - if (setsockopt(rip_sock,IPPROTO_IP,IP_DROP_MEMBERSHIP, - &m, sizeof(m)) < 0 + sin->sin_addr.s_addr = htonl(INADDR_RIP_GROUP); + if (setsockopt(rip_sock, IPPROTO_IP, MCAST_LEAVE_GROUP, + &gr, sizeof(gr)) < 0 && errno != EADDRNOTAVAIL && !TRACEACTIONS) - LOGERR("setsockopt(IP_DROP_MEMBERSHIP RIP)"); + LOGERR("setsockopt(MCAST_LEAVE_GROUP RIP)"); if (rip_sock_mcast == ifp) rip_sock_mcast = 0; } diff -uNr routed.orig/main.c routed/main.c --- routed.orig/main.c Thu Nov 11 17:34:22 2004 +++ routed/main.c Sun Apr 8 02:51:49 2007 @@ -717,25 +717,23 @@ static void rip_mcast_on(struct interface *ifp) { - struct ip_mreq m; + struct group_req gr; + struct sockaddr_in *sin; if (!IS_RIP_IN_OFF(ifp->int_state) && (ifp->int_if_flags & IFF_MULTICAST) -#ifdef MCAST_PPP_BUG - && !(ifp->int_if_flags & IFF_POINTOPOINT) -#endif && !(ifp->int_state & IS_ALIAS)) { - m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP); -#ifdef MCAST_IFINDEX - m.imr_interface.s_addr = htonl(ifp->int_index); -#else - m.imr_interface.s_addr = ((ifp->int_if_flags & IFF_POINTOPOINT) - ? ifp->int_dstaddr - : ifp->int_addr); + memset(&gr, 0, sizeof(gr)); + gr.gr_interface = ifp->int_index; + sin = (struct sockaddr_in *)&gr.gr_group; + sin->sin_family = AF_INET; +#ifdef _HAVE_SIN_LEN + sin->sin_len = sizeof(struct sockaddr_in); #endif - if (setsockopt(rip_sock,IPPROTO_IP, IP_ADD_MEMBERSHIP, - &m, sizeof(m)) < 0) - LOGERR("setsockopt(IP_ADD_MEMBERSHIP RIP)"); + sin->sin_addr.s_addr = htonl(INADDR_RIP_GROUP); + if (setsockopt(rip_sock, IPPROTO_IP, MCAST_JOIN_GROUP, + &gr, sizeof(gr)) < 0) + LOGERR("setsockopt(MCAST_JOIN_GROUP RIP)"); } } diff -uNr routed.orig/output.c routed/output.c --- routed.orig/output.c Thu Nov 11 17:34:52 2004 +++ routed/output.c Mon Apr 9 05:09:24 2007 @@ -106,7 +106,6 @@ int flags; const char *msg; int res; - naddr tgt_mcast; int soc; int serrno; @@ -152,31 +151,17 @@ } else { msg = "Send mcast"; if (rip_sock_mcast != ifp) { -#ifdef MCAST_IFINDEX - /* specify ifindex */ - tgt_mcast = htonl(ifp->int_index); -#else -#ifdef MCAST_PPP_BUG - /* Do not specify the primary interface - * explicitly if we have the multicast - * point-to-point kernel bug, since the - * kernel will do the wrong thing if the - * local address of a point-to-point link - * is the same as the address of an ordinary - * interface. - */ - if (ifp->int_addr == myaddr) { - tgt_mcast = 0; - } else -#endif - tgt_mcast = ifp->int_addr; -#endif + struct ip_mreqn mreqn; + + memset(&mreqn, 0, sizeof(struct ip_mreqn)); + mreqn.imr_ifindex = ifp->int_index; if (0 > setsockopt(rip_sock, - IPPROTO_IP, IP_MULTICAST_IF, - &tgt_mcast, - sizeof(tgt_mcast))) { + IPPROTO_IP, + IP_MULTICAST_IF, + &mreqn, + sizeof(mreqn))) { serrno = errno; - LOGERR("setsockopt(rip_sock," + LOGERR("setsockopt(rip_sock, " "IP_MULTICAST_IF)"); errno = serrno; ifp = 0; diff -uNr routed.orig/rdisc.c routed/rdisc.c --- routed.orig/rdisc.c Sat Mar 27 14:52:01 2004 +++ routed/rdisc.c Mon Apr 9 05:09:32 2007 @@ -171,7 +171,8 @@ set_rdisc_mg(struct interface *ifp, int on) /* 0=turn it off */ { - struct ip_mreq m; + struct group_req gr; + struct sockaddr_in *sin; if (rdisc_sock < 0) { /* Create the raw socket so that we can hear at least @@ -188,39 +189,35 @@ return; } -#ifdef MCAST_PPP_BUG - if (ifp->int_if_flags & IFF_POINTOPOINT) - return; -#endif - memset(&m, 0, sizeof(m)); -#ifdef MCAST_IFINDEX - m.imr_interface.s_addr = htonl(ifp->int_index); -#else - m.imr_interface.s_addr = ((ifp->int_if_flags & IFF_POINTOPOINT) - ? ifp->int_dstaddr - : ifp->int_addr); + memset(&gr, 0, sizeof(gr)); + gr.gr_interface = ifp->int_index; + sin = (struct sockaddr_in *)&gr.gr_group; + sin->sin_family = AF_INET; +#ifdef _HAVE_SIN_LEN + sin->sin_len = sizeof(struct sockaddr_in); #endif + if (supplier || (ifp->int_state & IS_NO_ADV_IN) || !on) { /* stop listening to advertisements */ if (ifp->int_state & IS_ALL_HOSTS) { - m.imr_multiaddr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); + sin->sin_addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); if (setsockopt(rdisc_sock, IPPROTO_IP, - IP_DROP_MEMBERSHIP, - &m, sizeof(m)) < 0) - LOGERR("IP_DROP_MEMBERSHIP ALLHOSTS"); + MCAST_LEAVE_GROUP, + &gr, sizeof(gr)) < 0) + LOGERR("MCAST_LEAVE_GROUP ALLHOSTS"); ifp->int_state &= ~IS_ALL_HOSTS; } } else if (!(ifp->int_state & IS_ALL_HOSTS)) { /* start listening to advertisements */ - m.imr_multiaddr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); - if (setsockopt(rdisc_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, - &m, sizeof(m)) < 0) { - LOGERR("IP_ADD_MEMBERSHIP ALLHOSTS"); + sin->sin_addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); + if (setsockopt(rdisc_sock, IPPROTO_IP, MCAST_JOIN_GROUP, + &gr, sizeof(gr)) < 0) { + LOGERR("MCAST_JOIN_GROUP ALLHOSTS"); } else { ifp->int_state |= IS_ALL_HOSTS; } @@ -232,21 +229,21 @@ /* stop listening to solicitations */ if (ifp->int_state & IS_ALL_ROUTERS) { - m.imr_multiaddr.s_addr=htonl(INADDR_ALLROUTERS_GROUP); + sin->sin_addr.s_addr = htonl(INADDR_ALLROUTERS_GROUP); if (setsockopt(rdisc_sock, IPPROTO_IP, - IP_DROP_MEMBERSHIP, - &m, sizeof(m)) < 0) - LOGERR("IP_DROP_MEMBERSHIP ALLROUTERS"); + MCAST_LEAVE_GROUP, + &gr, sizeof(gr)) < 0) + LOGERR("MCAST_LEAVE_GROUP ALLROUTERS"); ifp->int_state &= ~IS_ALL_ROUTERS; } } else if (!(ifp->int_state & IS_ALL_ROUTERS)) { /* start hearing solicitations */ - m.imr_multiaddr.s_addr=htonl(INADDR_ALLROUTERS_GROUP); - if (setsockopt(rdisc_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, - &m, sizeof(m)) < 0) { - LOGERR("IP_ADD_MEMBERSHIP ALLROUTERS"); + sin->sin_addr.s_addr = htonl(INADDR_ALLROUTERS_GROUP); + if (setsockopt(rdisc_sock, IPPROTO_IP, MCAST_JOIN_GROUP, + &gr, sizeof(gr)) < 0) { + LOGERR("MCAST_JOIN_GROUP ALLROUTERS"); } else { ifp->int_state |= IS_ALL_ROUTERS; } @@ -702,7 +699,6 @@ struct sockaddr_in rsin; int flags; const char *msg; - naddr tgt_mcast; memset(&rsin, 0, sizeof(rsin)); @@ -739,27 +735,14 @@ } if (rdisc_sock_mcast != ifp) { /* select the right interface. */ -#ifdef MCAST_IFINDEX - /* specify ifindex */ - tgt_mcast = htonl(ifp->int_index); -#else -#ifdef MCAST_PPP_BUG - /* Do not specify the primary interface explicitly - * if we have the multicast point-to-point kernel - * bug, since the kernel will do the wrong thing - * if the local address of a point-to-point link - * is the same as the address of an ordinary - * interface. - */ - if (ifp->int_addr == myaddr) { - tgt_mcast = 0; - } else -#endif - tgt_mcast = ifp->int_addr; -#endif + struct ip_mreqn mreqn; + + memset(&mreqn, 0, sizeof(struct ip_mreqn)); + mreqn.imr_ifindex = ifp->int_index; if (0 > setsockopt(rdisc_sock, IPPROTO_IP, IP_MULTICAST_IF, - &tgt_mcast, sizeof(tgt_mcast))) { + &mreqn, + sizeof(mreqn))) { LOGERR("setsockopt(rdisc_sock," "IP_MULTICAST_IF)"); rdisc_sock_mcast = 0;