Subject: IPv4 multicast set/getsockopt, specifying interface index
To: None <tech-net@netbsd.org>
From: None <itojun@iijlab.net>
List: tech-net
Date: 01/13/2001 12:53:17
IPv4 multicast set/getsockopt uses interface address to identify
the interface. this causes problem when you have the same IPv4
address on multiple interfaces (example: "unnumbered" p2p interface).
we need a way to specify interface by interface index instead.
also, if interface address changes after setsockopt(a, IP_MULTICAST_IF),
getsockopt(IP_MULTICAST_IF) will return the new address and it will
be harder for user program to guess which interface it is.
the following patch uses 0.0.0.0/8 as 24bit interface index value.
on getsockopt(IP_MULTICAST_IF) it will return the value the user has
set. does it look right, or messy?
(Dave Thaler suggested this based on RFC1724 section 3.3 - RIPv2
MIB, and he said there's other system doing/will be doing this)
itojun
Index: ip_output.c
===================================================================
RCS file: /cvsroot/kame/kame/netbsd/sys/netinet/ip_output.c,v
retrieving revision 1.17
diff -u -r1.17 ip_output.c
--- ip_output.c 2000/12/02 07:30:45 1.17
+++ ip_output.c 2001/01/13 03:19:12
@@ -145,6 +145,7 @@
#endif /*IPSEC*/
static struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *));
+static struct ifnet *ip_multicast_if __P((struct in_addr *));
static void ip_mloopback
__P((struct ifnet *, struct mbuf *, struct sockaddr_in *));
@@ -1194,6 +1195,26 @@
}
/*
+ * following RFC1724 section 3.3, 0.0.0.0/8 is interpreted as interface index.
+ */
+static struct ifnet *
+ip_multicast_if(a)
+ struct in_addr *a;
+{
+ int ifindex;
+ struct ifnet *ifp;
+
+ if (ntohl(a->s_addr) >> 24 == 0) {
+ ifindex = ntohl(a->s_addr) & 0xffffff;
+ if (ifindex < 0 || if_index < ifindex)
+ return NULL;
+ ifp = ifindex2ifnet[ifindex];
+ } else
+ INADDR_TO_IFP(*a, ifp);
+ return ifp;
+}
+
+/*
* Set the IP multicast options in response to user setsockopt().
*/
int
@@ -1224,6 +1245,7 @@
return (ENOBUFS);
*imop = imo;
imo->imo_multicast_ifp = NULL;
+ imo->imo_multicast_addr.s_addr = INADDR_ANY;
imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL;
imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP;
imo->imo_num_memberships = 0;
@@ -1254,12 +1276,13 @@
* IP address. Find the interface and confirm that
* it supports multicasting.
*/
- INADDR_TO_IFP(addr, ifp);
+ ifp = ip_multicast_if(&addr);
if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
error = EADDRNOTAVAIL;
break;
}
imo->imo_multicast_ifp = ifp;
+ imo->imo_multicast_addr = addr;
break;
case IP_MULTICAST_TTL:
@@ -1319,7 +1342,7 @@
ifp = ro.ro_rt->rt_ifp;
rtfree(ro.ro_rt);
} else {
- INADDR_TO_IFP(mreq->imr_interface, ifp);
+ ifp = ip_multicast_if(&mreq->imr_interface);
}
/*
* See if we found an interface, and confirm that it
@@ -1380,7 +1403,7 @@
if (in_nullhost(mreq->imr_interface))
ifp = NULL;
else {
- INADDR_TO_IFP(mreq->imr_interface, ifp);
+ ifp = ip_multicast_if(&mreq->imr_interface);
if (ifp == NULL) {
error = EADDRNOTAVAIL;
break;
@@ -1444,7 +1467,6 @@
u_char *ttl;
u_char *loop;
struct in_addr *addr;
- struct in_ifaddr *ia;
*mp = m_get(M_WAIT, MT_SOOPTS);
@@ -1456,8 +1478,8 @@
if (imo == NULL || imo->imo_multicast_ifp == NULL)
*addr = zeroin_addr;
else {
- IFP_TO_IA(imo->imo_multicast_ifp, ia);
- *addr = ia ? ia->ia_addr.sin_addr : zeroin_addr;
+ /* return the value user has set */
+ *addr = imo->imo_multicast_addr;
}
return (0);