changeset 1110:1b6ef729f41e draft dhcpcd-4.0.7

Ensure host routes and subnet routes are added correctly.
author Roy Marples <roy@marples.name>
date Mon, 01 Dec 2008 16:58:17 +0000
parents 6c45bd0426e1
children 358ff18175bc
files if-bsd.c
diffstat 1 files changed, 52 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/if-bsd.c	Mon Dec 01 16:56:01 2008 +0000
+++ b/if-bsd.c	Mon Dec 01 16:58:17 2008 +0000
@@ -98,12 +98,11 @@
 }
 
 int
-if_route(const struct interface *iface, const struct in_addr *destination,
-	 const struct in_addr *netmask, const struct in_addr *gateway,
+if_route(const struct interface *iface, const struct in_addr *dest,
+	 const struct in_addr *net, const struct in_addr *gate,
 	 _unused int metric, int action)
 {
 	int s;
-	static int seq;
 	union sockunion {
 		struct sockaddr sa;
 		struct sockaddr_in sin;
@@ -122,58 +121,77 @@
 	size_t l;
 	int retval = 0;
 
-#define ADDSU(_su) \
+#define ADDSU(_su) { \
 	l = SA_SIZE(&(_su.sa)); \
 	memcpy(bp, &(_su), l); \
-	bp += l;
-#define ADDADDR(_addr) \
+	bp += l; \
+}
+#define ADDADDR(_addr) { \
 	memset (&su, 0, sizeof(su)); \
 	su.sin.sin_family = AF_INET; \
 	su.sin.sin_len = sizeof(su.sin); \
 	memcpy (&su.sin.sin_addr, _addr, sizeof(su.sin.sin_addr)); \
-	ADDSU(su);
+	ADDSU(su); \
+}
 
 	if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
 		return -1;
 
 	memset(&rtm, 0, sizeof(rtm));
 	rtm.hdr.rtm_version = RTM_VERSION;
-	rtm.hdr.rtm_seq = ++seq;
+	rtm.hdr.rtm_seq = 1;
 	if (action == 0)
 		rtm.hdr.rtm_type = RTM_CHANGE;
 	else if (action > 0)
 		rtm.hdr.rtm_type = RTM_ADD;
 	else
 		rtm.hdr.rtm_type = RTM_DELETE;
-	rtm.hdr.rtm_flags = RTF_UP | RTF_STATIC;
-	if (netmask->s_addr == INADDR_BROADCAST)
+	rtm.hdr.rtm_flags = RTF_UP;
+	/* None interface subnet routes are static. */
+	if (gate->s_addr != INADDR_ANY ||
+	    net->s_addr != iface->net.s_addr ||
+	    dest->s_addr != (iface->addr.s_addr & iface->net.s_addr))
+		rtm.hdr.rtm_flags |= RTF_STATIC;
+	rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY;
+	if (dest->s_addr == gate->s_addr && net->s_addr == INADDR_BROADCAST)
 		rtm.hdr.rtm_flags |= RTF_HOST;
-	if (gateway->s_addr != INADDR_ANY)	
-		rtm.hdr.rtm_flags |= RTF_GATEWAY;
-	rtm.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_IFP;
-
-	ADDADDR(destination);
-	ADDADDR(gateway);
+	else {
+		rtm.hdr.rtm_addrs |= RTA_NETMASK;
+		if (rtm.hdr.rtm_flags & RTF_STATIC)
+			rtm.hdr.rtm_flags |= RTF_GATEWAY;
+		if (action >= 0)
+			rtm.hdr.rtm_addrs |= RTA_IFA;
+	}
 
-	/* Ensure that netmask is set correctly */
-	memset(&su, 0, sizeof(su));
-	su.sin.sin_family = AF_INET;
-	su.sin.sin_len = sizeof(su.sin);
-	memcpy(&su.sin.sin_addr, &netmask->s_addr, sizeof(su.sin.sin_addr));
-	p = su.sa.sa_len + (char *)&su;
-	for (su.sa.sa_len = 0; p > (char *)&su; )
-		if (*--p != 0) {
-			su.sa.sa_len = 1 + p - (char *)&su;
-			break;
-		}
-	ADDSU(su);
+	ADDADDR(dest);
+	if (rtm.hdr.rtm_flags & RTF_HOST ||
+	    !(rtm.hdr.rtm_flags & RTF_STATIC))
+	{
+		/* Make us a link layer socket for the host gateway */
+		memset(&su, 0, sizeof(su));
+		su.sdl.sdl_len = sizeof(struct sockaddr_dl);
+		link_addr(iface->name, &su.sdl);
+		ADDSU(su);
+	} else
+		ADDADDR(gate);
 
-	/* Make us a link layer socket for IFP */
-	memset(&su, 0, sizeof(su));
-	su.sdl.sdl_family = AF_LINK;
-	su.sdl.sdl_len = sizeof(su.sdl);
-	link_addr(iface->name, &su.sdl);
-	ADDSU(su);
+	if (rtm.hdr.rtm_addrs & RTA_NETMASK) {
+		/* Ensure that netmask is set correctly */
+		memset(&su, 0, sizeof(su));
+		su.sin.sin_family = AF_INET;
+		su.sin.sin_len = sizeof(su.sin);
+		memcpy(&su.sin.sin_addr, &net->s_addr, sizeof(su.sin.sin_addr));
+		p = su.sa.sa_len + (char *)&su;
+		for (su.sa.sa_len = 0; p > (char *)&su;)
+			if (*--p != 0) {
+				su.sa.sa_len = 1 + p - (char *)&su;
+				break;
+			}
+		ADDSU(su);
+	}
+
+	if (rtm.hdr.rtm_addrs & RTA_IFA)
+		ADDADDR(&iface->addr);
 
 	rtm.hdr.rtm_msglen = l = bp - (char *)&rtm;
 	if (write(s, &rtm, l) == -1)