summaryrefslogtreecommitdiffstats
path: root/ipv6.c
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2014-02-12 00:39:46 +0000
committerRoy Marples <roy@marples.name>2014-02-12 00:39:46 +0000
commit4eb7b4896f7b4a74da17b1a0acc9119072866c3e (patch)
tree1b756fb2ec7afb302fdf7edeaa946dabd13fd929 /ipv6.c
parent06e4195f573dd03e9791ffecff64d54641f59c01 (diff)
downloaddhcpcd-4eb7b4896f7b4a74da17b1a0acc9119072866c3e.tar.xz
Move all global variables into contexts, with a small exception for
signal handling. This allows dhcpcd to work better in a threaded environment such as rtems.
Diffstat (limited to 'ipv6.c')
-rw-r--r--ipv6.c130
1 files changed, 85 insertions, 45 deletions
diff --git a/ipv6.c b/ipv6.c
index d5473f17..8cab5934 100644
--- a/ipv6.c
+++ b/ipv6.c
@@ -72,19 +72,53 @@
while (/*CONSTCOND*/ 0)
#define EUI64_GROUP(in6) ((in6)->s6_addr[8] & EUI64_GBIT)
-static struct rt6head *routes;
-int
-ipv6_init(void)
+struct ipv6_ctx *
+ipv6_init(struct dhcpcd_ctx *dhcpcd_ctx)
{
+ struct ipv6_ctx *ctx;
- if (routes == NULL) {
- routes = malloc(sizeof(*routes));
- if (routes == NULL)
- return -1;
- TAILQ_INIT(routes);
+ if (dhcpcd_ctx->ipv6)
+ return dhcpcd_ctx->ipv6;
+
+ ctx = calloc(1, sizeof(*ctx));
+ if (ctx == NULL)
+ return NULL;
+
+ ctx->routes = malloc(sizeof(*ctx->routes));
+ if (ctx->routes == NULL) {
+ free(ctx);
+ return NULL;
}
- return 0;
+ TAILQ_INIT(ctx->routes);
+
+ ctx->ra_routers = malloc(sizeof(*ctx->ra_routers));
+ if (ctx->ra_routers == NULL) {
+ free(ctx->routes);
+ free(ctx);
+ return NULL;
+ }
+ TAILQ_INIT(ctx->ra_routers);
+
+ ctx->sndhdr.msg_namelen = sizeof(struct sockaddr_in6);
+ ctx->sndhdr.msg_iov = ctx->sndiov;
+ ctx->sndhdr.msg_iovlen = 1;
+ ctx->sndhdr.msg_control = ctx->sndbuf;
+ ctx->sndhdr.msg_controllen = sizeof(ctx->sndbuf);
+ ctx->rcvhdr.msg_name = &ctx->from;
+ ctx->rcvhdr.msg_namelen = sizeof(ctx->from);
+ ctx->rcvhdr.msg_iov = ctx->rcviov;
+ ctx->rcvhdr.msg_iovlen = 1;
+ ctx->rcvhdr.msg_control = ctx->rcvbuf;
+ ctx->rcvhdr.msg_controllen = sizeof(ctx->rcvbuf);
+ ctx->rcviov[0].iov_base = ctx->ansbuf;
+ ctx->rcviov[0].iov_len = sizeof(ctx->ansbuf);
+
+ ctx->nd_fd = -1;
+ ctx->dhcp_fd = -1;
+
+ dhcpcd_ctx->ipv6 = ctx;
+ return ctx;
}
ssize_t
@@ -435,12 +469,14 @@ ipv6_freedrop_addrs(struct ipv6_addrhead *addrs, int drop,
continue;
TAILQ_REMOVE(addrs, ap, next);
if (ap->dadcallback)
- eloop_q_timeout_delete(0, NULL, ap->dadcallback);
+ eloop_q_timeout_delete(ap->iface->ctx->eloop,
+ 0, NULL, ap->dadcallback);
/* Only drop the address if no other RAs have assigned it.
* This is safe because the RA is removed from the list
* before we are called. */
if (drop && ap->flags & IPV6_AF_ADDED &&
- !ipv6nd_addrexists(ap) && !dhcp6_addrexists(ap) &&
+ !ipv6nd_addrexists(ap->iface->ctx, ap) &&
+ !dhcp6_addrexists(ap->iface->ctx, ap) &&
(ap->iface->options->options &
(DHCPCD_EXITING | DHCPCD_PERSISTENT)) !=
(DHCPCD_EXITING | DHCPCD_PERSISTENT))
@@ -475,7 +511,8 @@ ipv6_getstate(struct interface *ifp)
}
void
-ipv6_handleifa(int cmd, struct if_head *ifs, const char *ifname,
+ipv6_handleifa(struct dhcpcd_ctx *ctx,
+ int cmd, struct if_head *ifs, const char *ifname,
const struct in6_addr *addr, int flags)
{
struct interface *ifp;
@@ -502,7 +539,7 @@ ipv6_handleifa(int cmd, struct if_head *ifs, const char *ifname,
}
if (ifs == NULL)
- ifs = ifaces;
+ ifs = ctx->ifaces;
if (ifs == NULL) {
errno = ESRCH;
return;
@@ -521,8 +558,8 @@ ipv6_handleifa(int cmd, struct if_head *ifs, const char *ifname,
return;
if (!IN6_IS_ADDR_LINKLOCAL(addr)) {
- ipv6nd_handleifa(cmd, ifname, addr, flags);
- dhcp6_handleifa(cmd, ifname, addr, flags);
+ ipv6nd_handleifa(ctx, cmd, ifname, addr, flags);
+ dhcp6_handleifa(ctx, cmd, ifname, addr, flags);
}
/* We don't care about duplicated addresses, so remove them */
@@ -642,7 +679,6 @@ ipv6_free(struct interface *ifp)
{
struct ipv6_state *state;
struct ipv6_addr_l *ap;
- struct rt6 *rt;
if (ifp) {
ipv6_free_ll_callbacks(ifp);
@@ -655,18 +691,21 @@ ipv6_free(struct interface *ifp)
free(state);
ifp->if_data[IF_DATA_IPV6] = NULL;
}
- } else {
- if (routes) {
- while ((rt = TAILQ_FIRST(routes))) {
- TAILQ_REMOVE(routes, rt, next);
- free(rt);
- }
- free(routes);
- routes = NULL;
- }
}
}
+void
+ipv6_ctxfree(struct dhcpcd_ctx *ctx)
+{
+
+ if (ctx->ipv6 == NULL)
+ return;
+
+ free(ctx->ipv6->routes);
+ free(ctx->ipv6->ra_routers);
+ free(ctx->ipv6);
+}
+
int
ipv6_handleifa_addrs(int cmd,
struct ipv6_addrhead *addrs, const struct in6_addr *addr, int flags)
@@ -713,7 +752,7 @@ ipv6_handleifa_addrs(int cmd,
}
static struct rt6 *
-find_route6(struct rt6head *rts, const struct rt6 *r)
+find_route6(struct rt6_head *rts, const struct rt6 *r)
{
struct rt6 *rt;
@@ -844,7 +883,7 @@ make_router(const struct ra *rap)
}
int
-ipv6_removesubnet(const struct interface *ifp, struct ipv6_addr *addr)
+ipv6_removesubnet(struct interface *ifp, struct ipv6_addr *addr)
{
struct rt6 *rt;
#if HAVE_ROUTE_METRIC
@@ -867,10 +906,10 @@ ipv6_removesubnet(const struct interface *ifp, struct ipv6_addr *addr)
/* For some reason, Linux likes to re-add the subnet
route under the original metric.
I would love to find a way of stopping this! */
- if ((ort = find_route6(routes, rt)) == NULL ||
+ if ((ort = find_route6(ifp->ctx->ipv6->routes, rt)) == NULL ||
ort->metric != rt->metric)
#else
- if (!find_route6(routes, rt))
+ if (!find_route6(ifp->ctx->ipv6->routes, rt))
#endif
{
r = del_route6(rt);
@@ -887,13 +926,13 @@ ipv6_removesubnet(const struct interface *ifp, struct ipv6_addr *addr)
IN6_ARE_ADDR_EQUAL(&((rtp)->net), &in6addr_any))
static void
-ipv6_build_ra_routes(struct rt6head *dnr, int expired)
+ipv6_build_ra_routes(struct ipv6_ctx *ctx, struct rt6_head *dnr, int expired)
{
struct rt6 *rt;
const struct ra *rap;
const struct ipv6_addr *addr;
- TAILQ_FOREACH(rap, &ipv6_routers, next) {
+ TAILQ_FOREACH(rap, ctx->ra_routers, next) {
if (rap->expired != expired)
continue;
if (rap->iface->options->options & DHCPCD_IPV6RA_OWN) {
@@ -916,14 +955,15 @@ ipv6_build_ra_routes(struct rt6head *dnr, int expired)
}
static void
-ipv6_build_dhcp_routes(struct rt6head *dnr, enum DH6S dstate)
+ipv6_build_dhcp_routes(struct dhcpcd_ctx *ctx,
+ struct rt6_head *dnr, enum DH6S dstate)
{
const struct interface *ifp;
const struct dhcp6_state *d6_state;
const struct ipv6_addr *addr;
struct rt6 *rt;
- TAILQ_FOREACH(ifp, ifaces, next) {
+ TAILQ_FOREACH(ifp, ctx->ifaces, next) {
if (!(ifp->options->options & DHCPCD_IPV6RA_OWN))
continue;
d6_state = D6_CSTATE(ifp);
@@ -941,9 +981,9 @@ ipv6_build_dhcp_routes(struct rt6head *dnr, enum DH6S dstate)
}
void
-ipv6_buildroutes(void)
+ipv6_buildroutes(struct dhcpcd_ctx *ctx)
{
- struct rt6head dnr, *nrs;
+ struct rt6_head dnr, *nrs;
struct rt6 *rt, *rtn, *or;
uint8_t have_default;
unsigned long long o;
@@ -951,7 +991,7 @@ ipv6_buildroutes(void)
TAILQ_INIT(&dnr);
/* First add reachable routers and their prefixes */
- ipv6_build_ra_routes(&dnr, 0);
+ ipv6_build_ra_routes(ctx->ipv6, &dnr, 0);
#if HAVE_ROUTE_METRIC
have_default = (TAILQ_FIRST(&dnr) != NULL);
#endif
@@ -959,8 +999,8 @@ ipv6_buildroutes(void)
/* We have no way of knowing if prefixes added by DHCP are reachable
* or not, so we have to assume they are.
* Add bound before delegated so we can prefer interfaces better */
- ipv6_build_dhcp_routes(&dnr, DH6S_BOUND);
- ipv6_build_dhcp_routes(&dnr, DH6S_DELEGATED);
+ ipv6_build_dhcp_routes(ctx, &dnr, DH6S_BOUND);
+ ipv6_build_dhcp_routes(ctx, &dnr, DH6S_DELEGATED);
#if HAVE_ROUTE_METRIC
/* If we have an unreachable router, we really do need to remove the
@@ -972,7 +1012,7 @@ ipv6_buildroutes(void)
/* Add our non-reachable routers and prefixes
* Unsure if this is needed, but it's a close match to kernel
* behaviour */
- ipv6_build_ra_routes(&dnr, 1);
+ ipv6_build_ra_routes(ctx->ipv6, &dnr, 1);
nrs = malloc(sizeof(*nrs));
if (nrs == NULL) {
@@ -987,7 +1027,7 @@ ipv6_buildroutes(void)
continue;
//rt->src.s_addr = ifp->addr.s_addr;
/* Do we already manage it? */
- if ((or = find_route6(routes, rt))) {
+ if ((or = find_route6(ctx->ipv6->routes, rt))) {
if (or->iface != rt->iface ||
// or->src.s_addr != ifp->addr.s_addr ||
!IN6_ARE_ADDR_EQUAL(&rt->gate, &or->gate) ||
@@ -996,7 +1036,7 @@ ipv6_buildroutes(void)
if (c_route(or, rt) != 0)
continue;
}
- TAILQ_REMOVE(routes, or, next);
+ TAILQ_REMOVE(ctx->ipv6->routes, or, next);
free(or);
} else {
if (n_route(rt) != 0)
@@ -1017,8 +1057,8 @@ ipv6_buildroutes(void)
/* Remove old routes we used to manage
* If we own the default route, but not RA management itself
* then we need to preserve the last best default route we had */
- while ((rt = TAILQ_LAST(routes, rt6head))) {
- TAILQ_REMOVE(routes, rt, next);
+ while ((rt = TAILQ_LAST(ctx->ipv6->routes, rt6_head))) {
+ TAILQ_REMOVE(ctx->ipv6->routes, rt, next);
if (find_route6(nrs, rt) == NULL) {
o = rt->iface->options->options;
if (!have_default &&
@@ -1037,6 +1077,6 @@ ipv6_buildroutes(void)
free(rt);
}
- free(routes);
- routes = nrs;
+ free(ctx->ipv6->routes);
+ ctx->ipv6->routes = nrs;
}