[CUWiN-Dev] in_getifa-patch on NetBSD-current

David Young dyoung at pobox.com
Fri Jun 17 22:54:58 CDT 2005


On Fri, Jun 17, 2005 at 03:05:06PM -0500, Bill Comisky wrote:
> Dave,
> 
> I'm getting the same problem with NetBSD-current where 169.254/16 
> addressed packets are going out to our local LAN through the gateway 
> instead of 10/8 addressed packets.  So I applied the in_getifa-patch.  I 
> had to merge one hunk in sys/netinet/in.c manually because the __P() stuff 
> has been removed since your patch was generated.  However, after patching, 
> the build dies compiling in.c.  See the tail of the output at the bottom 
> of this message; there didn't seem to be an instructive error message.

NetBSD is using new compiler flags that keep it from building if a
type-cast discards the "const-ness" of an expression.  I've updated the
patch to suit the new flags.  See attachment.

Dave

-- 
David Young             OJC Technologies
dyoung at ojctech.com      Urbana, IL * (217) 278-3933
-------------- next part --------------
Index: sys/net/if.h
===================================================================
RCS file: /cvsroot/src/sys/net/if.h,v
retrieving revision 1.108
diff -u -r1.108 if.h
--- sys/net/if.h	2 May 2005 15:34:32 -0000	1.108
+++ sys/net/if.h	18 Jun 2005 03:44:34 -0000
@@ -130,6 +130,7 @@
 struct rtentry;
 struct socket;
 struct ether_header;
+struct ifaddr;
 struct ifnet;
 struct rt_addrinfo;
 
@@ -457,6 +458,8 @@
 	u_int	ifa_flags;		/* mostly rt_flags for cloning */
 	int	ifa_refcnt;		/* count of references */
 	int	ifa_metric;		/* cost of going out this interface */
+	struct ifaddr	*(*ifa_getifa)(struct ifaddr *,
+			               const struct sockaddr *);
 };
 #define	IFA_ROUTE	RTF_UP /* 0x01 *//* route installed */
 
Index: sys/net/route.c
===================================================================
RCS file: /cvsroot/src/sys/net/route.c,v
retrieving revision 1.66
diff -u -r1.66 route.c
--- sys/net/route.c	29 May 2005 21:22:53 -0000	1.66
+++ sys/net/route.c	18 Jun 2005 03:44:34 -0000
@@ -509,7 +509,6 @@
 rt_getifa(struct rt_addrinfo *info)
 {
 	struct ifaddr *ifa;
-	int error = 0;
 
 	/*
 	 * ifp may be specified by sockaddr_dl when protocol address
@@ -533,12 +532,13 @@
 		else if (sa != NULL)
 			info->rti_ifa = ifa_ifwithroute(flags, sa, sa);
 	}
-	if ((ifa = info->rti_ifa) != NULL) {
-		if (info->rti_ifp == NULL)
-			info->rti_ifp = ifa->ifa_ifp;
-	} else
-		error = ENETUNREACH;
-	return (error);
+	if ((ifa = info->rti_ifa) == NULL)
+		return ENETUNREACH;
+	if (ifa->ifa_getifa != NULL)
+		info->rti_ifa = ifa = (*ifa->ifa_getifa)(ifa, dst);
+	if (info->rti_ifp == NULL)
+		info->rti_ifp = ifa->ifa_ifp;
+	return 0;
 }
 
 int
Index: sys/netinet/in.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/in.c,v
retrieving revision 1.104
diff -u -r1.104 in.c
--- sys/netinet/in.c	26 Feb 2005 22:45:12 -0000	1.104
+++ sys/netinet/in.c	18 Jun 2005 03:44:35 -0000
@@ -139,7 +139,7 @@
 static void in_len2mask(struct in_addr *, u_int);
 static int in_lifaddr_ioctl(struct socket *, u_long, caddr_t,
 	struct ifnet *, struct proc *);
-
+static struct ifaddr *in_getifa(struct ifaddr *, const struct sockaddr *);
 static int in_addprefix(struct in_ifaddr *, int);
 static int in_scrubprefix(struct in_ifaddr *);
 
@@ -391,6 +391,7 @@
 			ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
 			ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
 			ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
+			ia->ia_ifa.ifa_getifa = in_getifa;
 			ia->ia_sockmask.sin_len = 8;
 			if (ifp->if_flags & IFF_BROADCAST) {
 				ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
@@ -1126,4 +1129,125 @@
 	}
 	splx(s);
 }
+
+#define	IN_CATEGORY_LINKLOCAL	0
+#define	IN_CATEGORY_PRIVATE	1
+#define	IN_CATEGORY_OTHER	2
+
+#define	LOGIC_EQ(__a, __b)	(!(__a) == !(__b))
+#define	SIN_ANY_LOCAL(__sin)	IN_ANY_LOCAL((__sin)->sin_addr.s_addr)
+#define	SIN_PRIVATE(__sin)	IN_PRIVATE((__sin)->sin_addr.s_addr)
+
+#ifdef GETIFA_DEBUG
+#define	GETIFA_PRINTF(__x)	printf __x
+#else
+#define	GETIFA_PRINTF(__x)
+#endif
+
+/*
+ * Length of longest common prefix of src and dst.
+ *
+ * (Derived from in6_matchlen.)
+ */
+static int
+in_matchlen(const struct in_addr *src, const struct in_addr *dst)
+{
+	int match = 0;
+	const uint8_t *s = (const uint8_t *)src, *d = (const uint8_t *)dst;
+	const uint8_t *lim = s + 4;
+	uint_fast8_t r = 0;
+
+	while (s < lim && (r = (*d++ ^ *s++)) == 0)
+		match += 8;
+
+	if (s == lim)
+		return match;
+
+	while ((r & 0x80) == 0) {
+		match++;
+		r <<= 1;
+	}
+	return match;
+}
+
+static int
+in_categorize(const struct sockaddr_in *sin)
+{
+	if (SIN_ANY_LOCAL(sin))
+		return IN_CATEGORY_LINKLOCAL;
+	else if (SIN_PRIVATE(sin))
+		return IN_CATEGORY_PRIVATE;
+	else
+		return IN_CATEGORY_OTHER;
+}
+
+static struct ifaddr *
+in_getifa(struct ifaddr *ifa, const struct sockaddr *dst0)
+{
+	int best_score, score;
+	int category = IN_CATEGORY_OTHER;
+	const struct sockaddr_in *dst, *src;
+	struct ifaddr *alt_ifa, *best_ifa;
+
+	if (dst0 == NULL) {				/* XXX impossible? */
+		printf("%s: dst0 == NULL\n", __func__);
+		return ifa;
+	}
+	if (ifa->ifa_addr->sa_family != AF_INET) {	/* XXX impossible? */
+		printf("%s: ifa->ifa_addr->sa_family != AF_INET\n", __func__);
+		return ifa;
+	}
+	if (dst0->sa_family != AF_INET)			/* does occur */
+		return ifa;
+
+	dst = (const struct sockaddr_in *)dst0;
+
+	category = in_categorize(dst);
+
+	best_ifa = ifa;
+
+	best_score = in_matchlen(&dst->sin_addr,
+				 &satosin(best_ifa->ifa_addr)->sin_addr);
+	if (category == in_categorize(satosin(best_ifa->ifa_addr)))
+		best_score += 64;
+
+	GETIFA_PRINTF(("%s: enter dst %#" PRIx32 " src %#" PRIx32
+	    " best_score %d\n", __func__, ntohl(dst->sin_addr.s_addr),
+	    ntohl(satosin(best_ifa->ifa_addr)->sin_addr.s_addr), best_score));
+
+	TAILQ_FOREACH(alt_ifa, &ifa->ifa_ifp->if_addrlist, ifa_list) {
+		src = IA_SIN(alt_ifa);
+
+		if (alt_ifa == ifa || src->sin_family != AF_INET)
+			continue;
+
+		if (category == in_categorize(src)) {
+			score = 64 + in_matchlen(&dst->sin_addr,
+			                         &src->sin_addr);
+		} else if (best_score >= 64) {
+			GETIFA_PRINTF(("%s: skip src %#" PRIx32 "\n", __func__,
+			    ntohl(src->sin_addr.s_addr)));
+			continue;
+		} else
+			score = in_matchlen(&dst->sin_addr, &src->sin_addr);
+
+		GETIFA_PRINTF(("%s: src %#" PRIx32 " score %d\n", __func__,
+		    ntohl(src->sin_addr.s_addr), score));
+
+		if (score > best_score) {
+			best_score = score;
+			best_ifa = alt_ifa;
+		}
+	}
+	GETIFA_PRINTF(("%s: choose src %#" PRIx32 " score %d\n", __func__,
+	    ntohl(IA_SIN(best_ifa)->sin_addr.s_addr), best_score));
+
+	return best_ifa;
+}
+#undef	IN_CATEGORY_LINKLOCAL
+#undef	IN_CATEGORY_OTHER
+#undef	IN_CATEGORY_PRIVATE
+#undef	LOGIC_EQ
+#undef	SIN_ANY_LOCAL
+#undef	SIN_PRIVATE
 #endif
Index: sys/netinet/in.h
===================================================================
RCS file: /cvsroot/src/sys/netinet/in.h,v
retrieving revision 1.70
diff -u -r1.70 in.h
--- sys/netinet/in.h	31 Jan 2005 23:49:36 -0000	1.70
+++ sys/netinet/in.h	18 Jun 2005 03:44:35 -0000
@@ -202,9 +202,21 @@
 #define	IN_BADCLASS(i)		(((uint32_t)(i) & __IPADDR(0xf0000000)) == \
 				 __IPADDR(0xf0000000))
 
+#define IN_LINKLOCAL(i)	(((uint32_t)(i) & __IPADDR(0xffff0000)) == \
+			 __IPADDR(0xa9fe0000))
+
+#define	IN_PRIVATE(i)	((((uint32_t)(i) & __IPADDR(0xff000000)) ==	\
+			  __IPADDR(0x0a000000))	||			\
+			 (((uint32_t)(i) & __IPADDR(0xfff00000)) ==	\
+			  __IPADDR(0xac100000))	||			\
+			 (((uint32_t)(i) & __IPADDR(0xffff0000)) ==	\
+			  __IPADDR(0xc0a80000)))
+
 #define	IN_LOCAL_GROUP(i)	(((uint32_t)(i) & __IPADDR(0xffffff00)) == \
 				 __IPADDR(0xe0000000))
 
+#define	IN_ANY_LOCAL(i)		(IN_LINKLOCAL(i) || IN_LOCAL_GROUP(i))
+
 #define	INADDR_ANY		__IPADDR(0x00000000)
 #define	INADDR_LOOPBACK		__IPADDR(0x7f000001)
 #define	INADDR_BROADCAST	__IPADDR(0xffffffff)	/* must be masked */
Index: sys/netinet/in_pcb.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/in_pcb.c,v
retrieving revision 1.100
diff -u -r1.100 in_pcb.c
--- sys/netinet/in_pcb.c	29 May 2005 21:41:23 -0000	1.100
+++ sys/netinet/in_pcb.c	18 Jun 2005 03:44:35 -0000
@@ -972,5 +972,9 @@
 			}
 		}
 	}
+	if (ia->ia_ifa.ifa_getifa != NULL) {
+		ia = ifatoia((*ia->ia_ifa.ifa_getifa)(&ia->ia_ifa,
+		                                      sintosa(sin)));
+	}
 	return satosin(&ia->ia_addr);
 }


More information about the CU-Wireless-Dev mailing list