Implementing IP_SENDIF (like SO_BINDTODEVICE)

Bruce M Simpson bms at spc.org
Wed Oct 27 00:39:11 PDT 2004


It annoys me that we have to resort to BPF to send IP datagrams on
unnumbered interfaces. Here is a half baked idea. Please look and
tell me what you think.
-------------- next part --------------
Adding IP_SENDIF (like Linux's SO_BINDTODEVICE) support to FreeBSD.
Clean up the RFC 1724 hack in ip_output.c

TODO:

Add IP_SENDIF processing to ip_ctloutput.
Move inp_depend6.inp6_ifindex into general inpcb structure.
Update #define.
Pass IP_ROUTETOIF flag to ip_output() from udp and rawip.
Pass inp_ifindex to ip_output() as destination from udp and rawip.

Index: src/sys/netinet/ip_output.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_output.c,v
retrieving revision 1.225.2.4
diff -u -p -r1.225.2.4 ip_output.c
--- src/sys/netinet/ip_output.c	22 Sep 2004 19:23:38 -0000	1.225.2.4
+++ src/sys/netinet/ip_output.c	27 Oct 2004 07:27:24 -0000
@@ -93,7 +93,7 @@ SYSCTL_INT(_net_inet_ip, OID_AUTO, mbuf_
 #endif
 
 static struct mbuf *ip_insertoptions(struct mbuf *, struct mbuf *, int *);
-static struct ifnet *ip_multicast_if(struct in_addr *, int *);
+static struct ifnet *ina_to_rfc1724_if(struct in_addr *, int *);
 static void	ip_mloopback
 	(struct ifnet *, struct mbuf *, struct sockaddr_in *, int);
 static int	ip_getmoptions
@@ -206,19 +206,30 @@ again:
 		dst->sin_addr = ip->ip_dst;
 	}
 	/*
-	 * If routing to interface only,
-	 * short circuit routing lookup.
+	 * If routing to interface only, short circuit routing lookup.
+	 *
+	 * Assume the destination is either the destination end of a
+	 * point-to-point interface, the network address of an interface,
+	 * or the address of an interface itself. In the last case, an
+	 * interface may be specified by index as per RFC 1724.
+	 * 
 	 */
 	if (flags & IP_ROUTETOIF) {
-		if ((ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)))) == NULL &&
-		    (ia = ifatoia(ifa_ifwithnet(sintosa(dst)))) == NULL) {
+		ia = ifatoia(ifa_ifwithdstaddr(sintosa(dst)));
+		if (ia == NULL)
+			ia = ifatoia(ifa_ifwithnet(sintosa(dst)));
+		if (ia != NULL)
+			ifp = ia->ia_ifp;
+		else
+			ifp = ina_to_rfc1724_if(&dst->sin_addr, NULL);
+		if (ifp == NULL) {
 			ipstat.ips_noroute++;
 			error = ENETUNREACH;
 			goto bad;
 		}
-		ifp = ia->ia_ifp;
 		ip->ip_ttl = 1;
-		isbroadcast = in_broadcast(dst->sin_addr, ifp);
+		isbroadcast = (flags & IP_SENDONES) |
+			      in_broadcast(dst->sin_addr, ifp);
 	} else if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) &&
 	    imo != NULL && imo->imo_multicast_ifp != NULL) {
 		/*
@@ -1531,11 +1542,15 @@ bad:
  * standard option (IP_TTL).
  */
 
+#define	INADDR_IFINDEX_MASK	0x00FFFFFF		/* 0.0.0.0/8 */
+
 /*
- * following RFC1724 section 3.3, 0.0.0.0/8 is interpreted as interface index.
+ * Look up the ifnet corresponding to a given IPv4 host address, taking the
+ * RFC1724 hack into account. If the address given has the network prefix
+ * 0.0.0.0/8, interpret the host portion as an interface index.
  */
 static struct ifnet *
-ip_multicast_if(a, ifindexp)
+ina_to_rfc1724_if(a, ifindexp)
 	struct in_addr *a;
 	int *ifindexp;
 {
@@ -1544,8 +1559,8 @@ ip_multicast_if(a, ifindexp)
 
 	if (ifindexp)
 		*ifindexp = 0;
-	if (ntohl(a->s_addr) >> 24 == 0) {
-		ifindex = ntohl(a->s_addr) & 0xffffff;
+	if ((ntohl(a->s_addr) & ~INADDR_IFINDEX_MASK) == 0) {
+		ifindex = ntohl(a->s_addr) & 0x00FFFFFF;
 		if (ifindex < 0 || if_index < ifindex)
 			return NULL;
 		ifp = ifnet_byindex(ifindex);
@@ -1554,7 +1569,7 @@ ip_multicast_if(a, ifindexp)
 	} else {
 		INADDR_TO_IFP(*a, ifp);
 	}
-	return ifp;
+	return (ifp);
 }
 
 /*
@@ -1634,7 +1649,7 @@ ip_setmoptions(sopt, imop)
 		 * it supports multicasting.
 		 */
 		s = splimp();
-		ifp = ip_multicast_if(&addr, &ifindex);
+		ifp = ina_to_rfc1724_if(&addr, &ifindex);
 		if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) {
 			splx(s);
 			error = EADDRNOTAVAIL;
@@ -1731,7 +1746,7 @@ ip_setmoptions(sopt, imop)
 			RTFREE(ro.ro_rt);
 		}
 		else {
-			ifp = ip_multicast_if(&mreq.imr_interface, NULL);
+			ifp = ina_to_rfc1724_if(&mreq.imr_interface, NULL);
 		}
 
 		/*
@@ -1799,7 +1814,7 @@ ip_setmoptions(sopt, imop)
 		if (mreq.imr_interface.s_addr == INADDR_ANY)
 			ifp = NULL;
 		else {
-			ifp = ip_multicast_if(&mreq.imr_interface, NULL);
+			ifp = ina_to_rfc1724_if(&mreq.imr_interface, NULL);
 			if (ifp == NULL) {
 				error = EADDRNOTAVAIL;
 				splx(s);
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 167 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-net/attachments/20041027/77fd0480/attachment.bin


More information about the freebsd-net mailing list