From: Roy Marples Date: Tue, 19 Feb 2013 15:23:53 +0000 (+0000) Subject: Use TAILQ macros for IPv4 routes. X-Git-Tag: v5.99.6~52 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4c9c4b3ea08e7d010b27c251fae57da11be8d1fd;p=thirdparty%2Fdhcpcd.git Use TAILQ macros for IPv4 routes. --- diff --git a/dhcp.c b/dhcp.c index a7042e7e..1b1fcd91 100644 --- a/dhcp.c +++ b/dhcp.c @@ -476,41 +476,40 @@ decode_rfc3442(char *out, ssize_t len, int pl, const uint8_t *p) 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 @@ route_netmask(uint32_t ip_in) /* 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 @@ get_option_routes(struct interface *ifp, const struct dhcp_message *dhcp) } /* 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 @@ get_option_routes(struct interface *ifp, const struct dhcp_message *dhcp) 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 @@ get_option_routes(struct interface *ifp, const struct dhcp_message *dhcp) 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); } } diff --git a/dhcp.h b/dhcp.h index 68cfa811..8b59b852 100644 --- a/dhcp.h +++ b/dhcp.h @@ -241,7 +241,8 @@ int get_option_uint8(uint8_t *, const struct dhcp_message *, uint8_t); #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 *); diff --git a/dhcpcd.c b/dhcpcd.c index 440f4e4a..e06d5138 100644 --- a/dhcpcd.c +++ b/dhcpcd.c @@ -469,11 +469,16 @@ init_state(struct interface *ifp, int argc, char **argv) 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) { - ifo->options &= ~DHCPCD_IPV6RS; syslog(LOG_ERR, "ipv6_init: %m"); + ifo->options &= ~DHCPCD_IPV6RS; } if (!(options & DHCPCD_TEST)) diff --git a/if-linux.c b/if-linux.c index 3240e388..ba317a38 100644 --- a/if-linux.c +++ b/if-linux.c @@ -264,11 +264,10 @@ link_route(struct nlmsghdr *nlm) 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) { diff --git a/if-options.c b/if-options.c index 0d20d4d5..a75027e3 100644 --- a/if-options.c +++ b/if-options.c @@ -749,54 +749,49 @@ parse_option(struct if_options *ifo, int opt, const char *arg) while (*np == ' ') np++; 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__); - *fp = ' '; 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__); + *fp = ' '; + return -1; } - rt->next = NULL; 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) { diff --git a/if-options.h b/if-options.h index ffec6fca..c6032b7c 100644 --- a/if-options.h +++ b/if-options.h @@ -36,6 +36,8 @@ #include #include +#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 if_options { struct in_addr req_addr; struct in_addr req_mask; - struct rt *routes; + struct rt_head *routes; char **config; char **environ; diff --git a/ipv4.c b/ipv4.c index ed4b11af..a7f0f913 100644 --- a/ipv4.c +++ b/ipv4.c @@ -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 @@ ipv4_doaddress(const char *ifname, } 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 @@ find_route(struct rt *rts, const struct rt *r, struct rt **lrt, (!srt || srt != rt) && rt->net.s_addr == r->net.s_addr) return rt; - if (lrt) - *lrt = rt; } return NULL; } @@ -218,16 +242,13 @@ desc_route(const char *cmd, const struct rt *rt) 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 @@ get_subnet_route(struct dhcp_message *dhcp) 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 @@ add_subnet_route(struct rt *rt, const struct interface *iface) 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 @@ get_routes(struct interface *ifp) /* 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 @@ massage_host_routes(struct rt *rt, const struct interface *ifp) 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 @@ add_destination_route(struct rt *rt, const struct interface *iface) 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 @@ add_router_host_route(struct rt *rt, const struct interface *ifp) 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 @@ add_router_host_route(struct rt *rt, const struct interface *ifp) 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 @@ ipv4_buildroutes(void) 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 @@ ipv4_buildroutes(void) 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); + routes = nrs; } @@ -608,7 +621,7 @@ ipv4_applyaddr(void *arg) 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); } diff --git a/ipv4.h b/ipv4.h index ff0fbe86..712b5339 100644 --- a/ipv4.h +++ b/ipv4.h @@ -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 @@ int if_route(const struct rt *rt, int); #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 diff --git a/ipv6.c b/ipv6.c index 4d5505f3..f7209f6c 100644 --- a/ipv6.c +++ b/ipv6.c @@ -64,7 +64,8 @@ ipv6_cleanup() } #endif -int ipv6_init(void) +int +ipv6_init(void) { if (routes == NULL) { diff --git a/platform-linux.c b/platform-linux.c index e5d401bd..ece22c4f 100644 --- a/platform-linux.c +++ b/platform-linux.c @@ -32,6 +32,7 @@ #include #include "common.h" +#include "dhcpcd.h" #include "if-options.h" #include "platform.h"