summaryrefslogtreecommitdiffstats
path: root/ipv6.c
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2016-07-22 20:59:04 +0000
committerRoy Marples <roy@marples.name>2016-07-22 20:59:04 +0000
commit5012262fd6a3d7a59c9014a58a094b6cc01850fd (patch)
tree71f66cbeffb835c16c67b060c77afb66c2b9d729 /ipv6.c
parent66ca918ff743157e3704f4bbc41a41b1ae520bec (diff)
downloaddhcpcd-5012262fd6a3d7a59c9014a58a094b6cc01850fd.tar.xz
Add initial support for aliased addresses on Solaris.
Diffstat (limited to 'ipv6.c')
-rw-r--r--ipv6.c75
1 files changed, 73 insertions, 2 deletions
diff --git a/ipv6.c b/ipv6.c
index 41c2eec3..27434b67 100644
--- a/ipv6.c
+++ b/ipv6.c
@@ -616,8 +616,8 @@ ipv6_deleteaddr(struct ipv6_addr *ia)
}
}
-int
-ipv6_addaddr(struct ipv6_addr *ap, const struct timespec *now)
+static int
+ipv6_addaddr1(struct ipv6_addr *ap, const struct timespec *now)
{
struct interface *ifp;
struct ipv6_state *state;
@@ -751,6 +751,74 @@ ipv6_addaddr(struct ipv6_addr *ap, const struct timespec *now)
return 0;
}
+#ifdef ALIAS_ADDR
+/* Find the next logical aliase address we can use. */
+static int
+ipv6_aliasaddr(struct ipv6_addr *ia, struct ipv6_addr **repl)
+{
+ struct ipv6_state *state;
+ struct ipv6_addr *iap;
+ unsigned int unit;
+ char alias[IF_NAMESIZE];
+
+ unit = 0;
+ state = IPV6_STATE(ia->iface);
+find_unit:
+ if (unit == 0)
+ strlcpy(alias, ia->iface->name, sizeof(alias));
+ else
+ snprintf(alias, sizeof(alias), "%s:%u", ia->iface->name, unit);
+ TAILQ_FOREACH(iap, &state->addrs, next) {
+ if (iap->iface != ia->iface)
+ continue;
+ if (IN6_IS_ADDR_UNSPECIFIED(&iap->addr)) {
+ /* No address assigned? Lets use it. */
+ strlcpy(ia->alias, iap->alias, sizeof(ia->alias));
+ if (repl)
+ *repl = iap;
+ return 1;
+ }
+ if (strcmp(iap->alias, alias) == 0)
+ break;
+ }
+ if (iap != NULL) {
+ if (unit == UINT_MAX) {
+ errno = ERANGE;
+ return -1;
+ }
+ unit++;
+ goto find_unit;
+ }
+ strlcpy(ia->alias, alias, sizeof(ia->alias));
+ return 0;
+}
+#endif
+
+int
+ipv6_addaddr(struct ipv6_addr *ia, const struct timespec *now)
+{
+ int r;
+#ifdef ALIAS_ADDR
+ int replaced;
+ struct ipv6_addr *replaced_ia;
+
+ if ((replaced = ipv6_aliasaddr(ia, &replaced_ia)) == -1)
+ return -1;
+#endif
+
+ if ((r = ipv6_addaddr1(ia, now)) == 0) {
+#ifdef ALIAS_ADDR
+ if (replaced) {
+ struct ipv6_state *state;
+
+ state = IPV6_STATE(ia->iface);
+ TAILQ_REMOVE(&state->addrs, replaced_ia, next);
+ ipv6_freeaddr(replaced_ia);
+ }
+#endif
+ }
+ return r;
+}
int
ipv6_findaddrmatch(const struct ipv6_addr *addr, const struct in6_addr *match,
@@ -1000,6 +1068,9 @@ ipv6_handleifa(struct dhcpcd_ctx *ctx,
"%s: calloc: %m", __func__);
break;
}
+#ifdef ALIAS_ADDR
+ strlcpy(ap->alias, ifname, sizeof(ap->alias));
+#endif
ap->iface = ifp;
ap->addr = *addr;
ap->prefix_len = prefix_len;