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 */
/* 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;
}
/* 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
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);
}
}
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);
}
}
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) {
#include "net.h"
#include "script.h"
-static struct rt *routes;
+static struct rt_head *routes;
int
inet_ntocidr(struct in_addr address)
}
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 ||
(!srt || srt != rt) &&
rt->net.s_addr == r->net.s_addr)
return rt;
- if (lrt)
- *lrt = rt;
}
return NULL;
}
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;
}
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));
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;
}
/* 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;
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;
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;
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;
}
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)
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 ||
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;
}
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);
}