changeset 1862:53174e89d78a draft

Use TAILQ macros for IPv4 routes.
author Roy Marples <roy@marples.name>
date Tue, 19 Feb 2013 15:23:53 +0000
parents b580e72f6408
children 0acca144defd
files dhcp.c dhcp.h dhcpcd.c if-linux.c if-options.c if-options.h ipv4.c ipv4.h ipv6.c platform-linux.c
diffstat 10 files changed, 150 insertions(+), 133 deletions(-) [+]
line wrap: on
line diff
--- a/dhcp.c	Tue Feb 19 13:37:42 2013 +0000
+++ b/dhcp.c	Tue Feb 19 15:23:53 2013 +0000
@@ -476,41 +476,40 @@
 	return bytes;
 }
 
-static struct rt *
+static struct rt_head *
 decode_rfc3442_rt(int dl, const uint8_t *data)
 {
 	const uint8_t *p = data;
 	const uint8_t *e;
 	uint8_t cidr;
 	size_t ocets;
-	struct rt *routes = NULL;
+	struct rt_head *routes;
 	struct rt *rt = NULL;
 
 	/* Minimum is 5 -first is CIDR and a router length of 4 */
 	if (dl < 5)
 		return NULL;
 
+	routes = malloc(sizeof(*routes));
+	TAILQ_INIT(routes);
 	e = p + dl;
 	while (p < e) {
 		cidr = *p++;
 		if (cidr > 32) {
 			ipv4_freeroutes(routes);
+			free(routes);
 			errno = EINVAL;
 			return NULL;
 		}
 
-		if (rt) {
-			rt->next = calloc(1, sizeof(*rt));
-			rt = rt->next;
-		} else {
-			routes = rt = calloc(1, sizeof(*routes));
-		}
+		rt = calloc(1, sizeof(*rt));
 		if (rt == NULL) {
 			syslog(LOG_ERR, "%s: %m", __func__);
 			ipv4_freeroutes(routes);
+			free(routes);
 			return NULL;
 		}
-		rt->next = NULL;
+		TAILQ_INSERT_TAIL(routes, rt, next);
 
 		ocets = (cidr + 7) / 8;
 		/* If we have ocets then we have a destination and netmask */
@@ -713,13 +712,13 @@
 /* We need to obey routing options.
  * If we have a CSR then we only use that.
  * Otherwise we add static routes and then routers. */
-struct rt *
+struct rt_head *
 get_option_routes(struct interface *ifp, const struct dhcp_message *dhcp)
 {
 	struct if_options *ifo = ifp->options;
 	const uint8_t *p;
 	const uint8_t *e;
-	struct rt *routes = NULL;
+	struct rt_head *routes = NULL;
 	struct rt *route = NULL;
 	int len;
 
@@ -745,6 +744,11 @@
 	}
 
 	/* OK, get our static routes first. */
+	routes = malloc(sizeof(*routes));
+	if (routes == NULL) {
+		syslog(LOG_ERR, "%s: %m", __func__);
+		return NULL;
+	}
 	if (!has_option_mask(ifo->nomask, DHO_STATICROUTE))
 		p = get_option(dhcp, DHO_STATICROUTE, &len, NULL);
 	else
@@ -752,21 +756,17 @@
 	if (p) {
 		e = p + len;
 		while (p < e) {
-			if (route) {
-				route->next = calloc(1, sizeof(*route));
-				route = route->next;
-			} else
-				routes = route = calloc(1, sizeof(*routes));
+			route = calloc(1, sizeof(*route));
 			if (route == NULL) {
 				syslog(LOG_ERR, "%s: %m", __func__);
 				break;
 			}
-			route->next = NULL;
 			memcpy(&route->dest.s_addr, p, 4);
 			p += 4;
 			memcpy(&route->gate.s_addr, p, 4);
 			p += 4;
 			route->net.s_addr = route_netmask(route->dest.s_addr);
+			TAILQ_INSERT_TAIL(routes, route, next);
 		}
 	}
 
@@ -778,17 +778,14 @@
 	if (p) {
 		e = p + len;
 		while (p < e) {
-			if (route) {
-				route->next = calloc(1, sizeof(*route));
-				route = route->next;
-			} else
-				routes = route = calloc(1, sizeof(*route));
+			route = calloc(1, sizeof(*route));
 			if (route == NULL) {
 				syslog(LOG_ERR, "%s: %m", __func__);
 				break;
 			}
 			memcpy(&route->gate.s_addr, p, 4);
 			p += 4;
+			TAILQ_INSERT_TAIL(routes, route, next);
 		}
 	}
 
--- a/dhcp.h	Tue Feb 19 13:37:42 2013 +0000
+++ b/dhcp.h	Tue Feb 19 15:23:53 2013 +0000
@@ -241,7 +241,8 @@
 #define is_bootp(m) (m &&						\
 	    !IN_LINKLOCAL(htonl((m)->yiaddr)) &&			\
 	    get_option_uint8(NULL, m, DHO_MESSAGETYPE) == -1)
-struct rt *get_option_routes(struct interface *, const struct dhcp_message *);
+struct rt_head *get_option_routes(struct interface *,
+    const struct dhcp_message *);
 ssize_t dhcp_env(char **, const char *, const struct dhcp_message *,
     const struct interface *);
 
--- a/dhcpcd.c	Tue Feb 19 13:37:42 2013 +0000
+++ b/dhcpcd.c	Tue Feb 19 15:23:53 2013 +0000
@@ -469,11 +469,16 @@
 			eloop_event_add(linkfd, handle_link, NULL);
 	}
 
+	if (ifo->options & DHCPCD_IPV4 && ipv4_init() == -1) {
+		syslog(LOG_ERR, "ipv4_init: %m");
+		ifo->options &= ~DHCPCD_IPV4;
+	}
+
 	if (ifo->options & DHCPCD_IPV6RS && !check_ipv6(NULL))
 		ifo->options &= ~DHCPCD_IPV6RS;
 	if (ifo->options & DHCPCD_IPV6RS && ipv6_init() == -1) {
+		syslog(LOG_ERR, "ipv6_init: %m");
 		ifo->options &= ~DHCPCD_IPV6RS;
-		syslog(LOG_ERR, "ipv6_init: %m");
 	}
 
 	if (!(options & DHCPCD_TEST))
--- a/if-linux.c	Tue Feb 19 13:37:42 2013 +0000
+++ b/if-linux.c	Tue Feb 19 15:23:53 2013 +0000
@@ -264,11 +264,10 @@
 		return 1;
 	rta = (struct rtattr *)(void *)((char *)rtm +NLMSG_ALIGN(sizeof(*rtm)));
 	len = NLMSG_PAYLOAD(nlm, sizeof(*rtm));
-	rt.iface = NULL;
+	memset(&rt, 0, sizeof(rt));
 	rt.dest.s_addr = INADDR_ANY;
 	rt.net.s_addr = INADDR_ANY;
 	rt.gate.s_addr = INADDR_ANY;
-	rt.next = NULL;
 	metric = 0;
 	while (RTA_OK(rta, len)) {
 		switch (rta->rta_type) {
--- a/if-options.c	Tue Feb 19 13:37:42 2013 +0000
+++ b/if-options.c	Tue Feb 19 15:23:53 2013 +0000
@@ -749,54 +749,49 @@
 			while (*np == ' ')
 				np++;
 			if (ifo->routes == NULL) {
-				rt = ifo->routes = calloc(1, sizeof(*rt));
-				if (rt == NULL) {
-					syslog(LOG_ERR, "%s: %m", __func__);
-					*fp = ' ';
-					return -1;
-				}
-			} else {
-				rt = ifo->routes;
-				while (rt->next)
-					rt = rt->next;
-				rt->next = malloc(sizeof(*rt));
-				if (rt->next == NULL) {
+				ifo->routes = malloc(sizeof(*ifo->routes));
+				if (ifo->routes == NULL) {
 					syslog(LOG_ERR, "%s: %m", __func__);
 					return -1;
 				}
-				rt = rt->next;
+ 				TAILQ_INIT(ifo->routes);
 			}
-			rt->next = NULL;
+			rt = malloc(sizeof(*rt));
+			if (rt == NULL) {
+				syslog(LOG_ERR, "%s: %m", __func__);
+				*fp = ' ';
+				return -1;
+			}
 			if (parse_addr(&rt->dest, &rt->net, p) == -1 ||
 			    parse_addr(&rt->gate, NULL, np) == -1)
 			{
+				free(rt);
 				*fp = ' ';
 				return -1;
 			}
+			TAILQ_INSERT_TAIL(ifo->routes, rt, next);
 			*fp = ' ';
 		} else if (strncmp(arg, "routers=", strlen("routers=")) == 0) {
 			if (ifo->routes == NULL) {
-				rt = ifo->routes = calloc(1, sizeof(*rt));
-				if (rt == NULL) {
+				ifo->routes = malloc(sizeof(*ifo->routes));
+				if (ifo->routes == NULL) {
 					syslog(LOG_ERR, "%s: %m", __func__);
 					return -1;
 				}
-			} else {
-				rt = ifo->routes;
-				while (rt->next)
-					rt = rt->next;
-				rt->next = malloc(sizeof(*rt));
-				if (rt->next == NULL) {
-					syslog(LOG_ERR, "%s: %m", __func__);
-					return -1;
-				}
-				rt = rt->next;
+ 				TAILQ_INIT(ifo->routes);
+			}
+			rt = malloc(sizeof(*rt));
+			if (rt == NULL) {
+				syslog(LOG_ERR, "%s: %m", __func__);
+				return -1;
 			}
 			rt->dest.s_addr = INADDR_ANY;
 			rt->net.s_addr = INADDR_ANY;
-			rt->next = NULL;
-			if (parse_addr(&rt->gate, NULL, p) == -1)
+			if (parse_addr(&rt->gate, NULL, p) == -1) {
+				free(rt);
 				return -1;
+			}
+			TAILQ_INSERT_TAIL(ifo->routes, rt, next);
 		} else {
 			s = 0;
 			if (ifo->config != NULL) {
--- a/if-options.h	Tue Feb 19 13:37:42 2013 +0000
+++ b/if-options.h	Tue Feb 19 15:23:53 2013 +0000
@@ -36,6 +36,8 @@
 #include <limits.h>
 #include <stdint.h>
 
+#include "ipv4.h"
+
 /* Don't set any optional arguments here so we retain POSIX
  * compatibility with getopt */
 #define IF_OPTS "46bc:de:f:gh:i:kl:m:no:pqr:s:t:u:v:wxy:z:ABC:DEF:GHI:JKLO:Q:S:TUVW:X:Z:"
@@ -105,7 +107,7 @@
 
 	struct in_addr req_addr;
 	struct in_addr req_mask;
-	struct rt *routes;
+	struct rt_head *routes;
 	char **config;
 
 	char **environ;
--- a/ipv4.c	Tue Feb 19 13:37:42 2013 +0000
+++ b/ipv4.c	Tue Feb 19 15:23:53 2013 +0000
@@ -54,7 +54,7 @@
 #include "net.h"
 #include "script.h"
 
-static struct rt *routes;
+static struct rt_head *routes;
 
 int
 inet_ntocidr(struct in_addr address)
@@ -157,26 +157,52 @@
 }
 
 void
-ipv4_freeroutes(struct rt *rts)
+ipv4_freeroutes(struct rt_head *rts)
 {
 	struct rt *r;
 
-	while (rts) {
-		r = rts->next;
+	if (rts) {
+		while ((r = TAILQ_FIRST(rts))) {
+			TAILQ_REMOVE(rts, r, next);
+			free(r);
+		}
 		free(rts);
-		rts = r;
 	}
 }
 
+#ifdef DEBUG_MEMORY
+static void
+ipv4_cleanup()
+{
+
+	ipv4_freeroutes(routes);
+}
+#endif
+
+int
+ipv4_init(void)
+{
+
+	if (routes == NULL) {
+		routes = malloc(sizeof(*routes));
+		if (routes == NULL) 
+			return -1;
+		TAILQ_INIT(routes);
+#ifdef DEBUG_MEMORY
+		atexit(ipv4_cleanup);
+#endif
+	}
+	return 0;
+}
+
 static struct rt *
-find_route(struct rt *rts, const struct rt *r, struct rt **lrt,
-    const struct rt *srt)
+find_route(struct rt_head *rts, const struct rt *r, const struct rt *srt)
 {
 	struct rt *rt;
 
-	if (lrt)
-		*lrt = NULL;
-	for (rt = rts; rt; rt = rt->next) {
+	if (rts == NULL)
+		return NULL;
+	TAILQ_FOREACH(rt, rts, next) {
 		if (rt->dest.s_addr == r->dest.s_addr &&
 #if HAVE_ROUTE_METRIC
 		    (srt || (!rt->iface ||
@@ -185,8 +211,6 @@
                     (!srt || srt != rt) &&
 		    rt->net.s_addr == r->net.s_addr)
 			return rt;
-		if (lrt)
-			*lrt = rt;
 	}
 	return NULL;
 }
@@ -218,16 +242,13 @@
 int
 ipv4_routedeleted(const struct rt *rt)
 {
-	struct rt *f, *l;
+	struct rt *f;
 
-	f = find_route(routes, rt, &l, NULL);
+	f = find_route(routes, rt, NULL);
 	if (f == NULL)
 		return 0;
 	desc_route("removing", f);
-	if (l)
-		l->next = f->next;
-	else
-		routes = f->next;
+	TAILQ_REMOVE(routes, f, next);
 	free(f);
 	return 1;
 }
@@ -314,18 +335,18 @@
 	return rt;
 }
 
-static struct rt *
-add_subnet_route(struct rt *rt, const struct interface *iface)
+static struct rt_head *
+add_subnet_route(struct rt_head *rt, const struct interface *ifp)
 {
 	struct rt *r;
 	const struct dhcp_state *s;
 
-	s = D_CSTATE(iface);
+	s = D_CSTATE(ifp);
 	if (s->net.s_addr == INADDR_BROADCAST ||
 	    s->net.s_addr == INADDR_ANY ||
-	    (iface->options->options &
+	    (ifp->options->options &
 	     (DHCPCD_INFORM | DHCPCD_STATIC) &&
-	     iface->options->req_addr.s_addr == INADDR_ANY))
+	     ifp->options->req_addr.s_addr == INADDR_ANY))
 		return rt;
 
 	r = malloc(sizeof(*r));
@@ -334,35 +355,30 @@
 	r->dest.s_addr = s->addr.s_addr & s->net.s_addr;
 	r->net.s_addr = s->net.s_addr;
 	r->gate.s_addr = 0;
-	r->next = rt;
-	return r;
+	TAILQ_INSERT_HEAD(rt, r, next);
+	return rt;
 }
 
-static struct rt *
+static struct rt_head *
 get_routes(struct interface *ifp)
 {
-	struct rt *rt, *nrt = NULL, *r = NULL;
+	struct rt_head *nrt;
+	struct rt *rt, *r = NULL;
 
-	if (ifp->options->routes != NULL) {
-		for (rt = ifp->options->routes;
-		     rt != NULL;
-		     rt = rt->next)
-		{
+	if (ifp->options->routes && TAILQ_FIRST(ifp->options->routes)) {
+		nrt = malloc(sizeof(*nrt));
+		TAILQ_INIT(nrt);
+		TAILQ_FOREACH(rt, ifp->options->routes, next) {
 			if (rt->gate.s_addr == 0)
 				break;
-			if (r == NULL)
-				r = nrt = malloc(sizeof(*r));
-			else {
-				r->next = malloc(sizeof(*r));
-				r = r->next;
-			}
+			r = malloc(sizeof(*r));
 			if (r == NULL) {
 				syslog(LOG_ERR, "%s: %m", __func__);
 				ipv4_freeroutes(nrt);
 				return NULL;
 			}
 			memcpy(r, rt, sizeof(*r));
-			r->next = NULL;
+			TAILQ_INSERT_TAIL(nrt, rt, next);
 		}
 		return nrt;
 	}
@@ -373,12 +389,12 @@
 /* Some DHCP servers add set host routes by setting the gateway
  * to the assinged IP address. This differs from our notion of a host route
  * where the gateway is the destination address, so we fix it. */
-static struct rt *
-massage_host_routes(struct rt *rt, const struct interface *ifp)
+static struct rt_head *
+massage_host_routes(struct rt_head *rt, const struct interface *ifp)
 {
 	struct rt *r;
 
-	for (r = rt; r; r = r->next) {
+	TAILQ_FOREACH(r, rt, next) {
 		if (r->gate.s_addr == D_CSTATE(ifp)->addr.s_addr &&
 		    r->net.s_addr == INADDR_BROADCAST)
 			r->gate.s_addr = r->dest.s_addr;
@@ -386,8 +402,8 @@
 	return rt;
 }
 
-static struct rt *
-add_destination_route(struct rt *rt, const struct interface *iface)
+static struct rt_head *
+add_destination_route(struct rt_head *rt, const struct interface *iface)
 {
 	struct rt *r;
 
@@ -402,23 +418,25 @@
 	r->dest.s_addr = INADDR_ANY;
 	r->net.s_addr = INADDR_ANY;
 	r->gate.s_addr = D_CSTATE(iface)->dst.s_addr;
-	r->next = rt;
-	return r;
+	TAILQ_INSERT_HEAD(rt, r, next);
+	return rt;
 }
 
 /* We should check to ensure the routers are on the same subnet
  * OR supply a host route. If not, warn and add a host route. */
-static struct rt *
-add_router_host_route(struct rt *rt, const struct interface *ifp)
+static struct rt_head *
+add_router_host_route(struct rt_head *rt, const struct interface *ifp)
 {
-	struct rt *rtp, *rtl, *rtn;
+	struct rt *rtp, *rtn;
 	const char *cp, *cp2, *cp3, *cplim;
 
-	for (rtp = rt, rtl = NULL; rtp; rtl = rtp, rtp = rtp->next) {
+	TAILQ_FOREACH(rtp, rt, next) {
 		if (rtp->dest.s_addr != INADDR_ANY)
 			continue;
 		/* Scan for a route to match */
-		for (rtn = rt; rtn != rtp; rtn = rtn->next) {
+		TAILQ_FOREACH(rtn, rt, next) {
+			if (rtn == rtp)
+				break;
 			/* match host */
 			if (rtn->dest.s_addr == rtp->gate.s_addr)
 				break;
@@ -453,11 +471,7 @@
 		rtn->dest.s_addr = rtp->gate.s_addr;
 		rtn->net.s_addr = INADDR_BROADCAST;
 		rtn->gate.s_addr = rtp->gate.s_addr;
-		rtn->next = rtp;
-		if (rtl == NULL)
-			rt = rtn;
-		else
-			rtl->next = rtn;
+		TAILQ_INSERT_BEFORE(rtp, rtn, next);
 	}
 	return rt;
 }
@@ -465,10 +479,17 @@
 void
 ipv4_buildroutes(void)
 {
-	struct rt *nrs = NULL, *dnr, *or, *rt, *rtn, *rtl, *lrt = NULL;
+	struct rt_head *nrs, *dnr;
+	struct rt *or, *rt, *rtn;
 	struct interface *ifp;
 	const struct dhcp_state *state;
 
+	nrs = malloc(sizeof(*nrs));
+	if (nrs == NULL) {
+		syslog(LOG_ERR, "%s: %m", __func__);
+		return;
+	}
+	TAILQ_INIT(nrs);
 	TAILQ_FOREACH(ifp, ifaces, next) {
 		state = D_CSTATE(ifp);
 		if (state == NULL || state->new == NULL)
@@ -480,15 +501,15 @@
 			dnr = add_router_host_route(dnr, ifp);
 			dnr = add_destination_route(dnr, ifp);
 		}
-		for (rt = dnr; rt && (rtn = rt->next, 1); lrt = rt, rt = rtn) {
+		TAILQ_FOREACH_SAFE(rt, dnr, next, rtn) {
 			rt->iface = ifp;
 			rt->metric = ifp->metric;
 			/* Is this route already in our table? */
-			if ((find_route(nrs, rt, NULL, NULL)) != NULL)
+			if ((find_route(nrs, rt, NULL)) != NULL)
 				continue;
 			rt->src.s_addr = state->addr.s_addr;
 			/* Do we already manage it? */
-			if ((or = find_route(routes, rt, &rtl, NULL))) {
+			if ((or = find_route(routes, rt, NULL))) {
 				if (or->iface != ifp ||
 				    or->src.s_addr != state->addr.s_addr ||
 				    rt->gate.s_addr != or->gate.s_addr ||
@@ -497,33 +518,25 @@
 					if (c_route(or, rt) != 0)
 						continue;
 				}
-				if (rtl != NULL)
-					rtl->next = or->next;
-				else
-					routes = or->next;
+				TAILQ_REMOVE(routes, or, next);
 				free(or);
 			} else {
 				if (n_route(rt) != 0)
 					continue;
 			}
-			if (dnr == rt)
-				dnr = rtn;
-			else if (lrt)
-				lrt->next = rtn;
-			rt->next = nrs;
-			nrs = rt;
-			rt = lrt; /* When we loop this makes lrt correct */
+			TAILQ_REMOVE(dnr, rt, next);
+			TAILQ_INSERT_TAIL(nrs, rt, next);
 		}
 		ipv4_freeroutes(dnr);
 	}
 
 	/* Remove old routes we used to manage */
-	for (rt = routes; rt; rt = rt->next) {
-		if (find_route(nrs, rt, NULL, NULL) == NULL)
+	TAILQ_FOREACH(rt, routes, next) {
+		if (find_route(nrs, rt, NULL) == NULL)
 			d_route(rt);
 	}
+	ipv4_freeroutes(routes);
 
-	ipv4_freeroutes(routes);
 	routes = nrs;
 }
 
@@ -608,7 +621,7 @@
 	if (rt != NULL) {
 		rt->iface = ifp;
 		rt->metric = 0;
-		if (!find_route(routes, rt, NULL, NULL))
+		if (!find_route(routes, rt, NULL))
 			ipv4_deleteroute(rt);
 		free(rt);
 	}
--- a/ipv4.h	Tue Feb 19 13:37:42 2013 +0000
+++ b/ipv4.h	Tue Feb 19 15:23:53 2013 +0000
@@ -31,16 +31,18 @@
 #include "dhcpcd.h"
 
 struct rt {
+	TAILQ_ENTRY(rt) next;
 	struct in_addr dest;
 	struct in_addr net;
 	struct in_addr gate;
 	const struct interface *iface;
 	int metric;
 	struct in_addr src;
-	struct rt *next;
 };
+TAILQ_HEAD(rt_head, rt);
 
 #ifdef INET
+int ipv4_init(void);
 int inet_ntocidr(struct in_addr);
 int inet_cidrtoaddr(int, struct in_addr *);
 uint32_t ipv4_getnetmask(uint32_t);
@@ -71,13 +73,14 @@
 #define ipv4_changeroute(rt) if_route(rt, 0)
 #define ipv4_deleteroute(rt) if_route(rt, -1)
 #define del_src_route(rt) i_route(rt, -2);
-void ipv4_freeroutes(struct rt *);
+void ipv4_freeroutes(struct rt_head *);
 
 int ipv4_opensocket(struct interface *, int);
 ssize_t ipv4_sendrawpacket(const struct interface *,
     int, const void *, ssize_t);
 ssize_t ipv4_getrawpacket(struct interface *, int, void *, ssize_t, int *);
 #else
+#define ipv4_init() -1
 #define ipv4_applyaddr(a) {}
 #define ipv4_freeroutes(a) {}
 #endif
--- a/ipv6.c	Tue Feb 19 13:37:42 2013 +0000
+++ b/ipv6.c	Tue Feb 19 15:23:53 2013 +0000
@@ -64,7 +64,8 @@
 }
 #endif
 
-int ipv6_init(void)
+int
+ipv6_init(void)
 {
 
 	if (routes == NULL) {
--- a/platform-linux.c	Tue Feb 19 13:37:42 2013 +0000
+++ b/platform-linux.c	Tue Feb 19 15:23:53 2013 +0000
@@ -32,6 +32,7 @@
 #include <syslog.h>
 
 #include "common.h"
+#include "dhcpcd.h"
 #include "if-options.h"
 #include "platform.h"