ipv6_newaddr(struct interface *ifp, const struct in6_addr *addr,
uint8_t prefix_len, unsigned int flags)
{
- struct ipv6_addr *ia;
+ struct ipv6_addr *ia, *iaf;
char buf[INET6_ADDRSTRLEN];
const char *cbp;
bool tempaddr;
int addr_flags;
+#ifdef IPV6_AF_TEMPORARY
+ tempaddr = flags & IPV6_AF_TEMPORARY;
+#else
+ tempaddr = false;
+#endif
+
/* If adding a new DHCP / RA derived address, check current flags
* from an existing address. */
- ia = ipv6_iffindaddr(ifp, addr, 0);
- if (ia != NULL) {
- addr_flags = ia->addr_flags;
+ if (flags & IPV6_AF_AUTOCONF)
+ iaf = ipv6nd_iffindprefix(ifp, addr, prefix_len);
+ else
+ iaf = ipv6_iffindaddr(ifp, addr, 0);
+ if (iaf != NULL) {
+ addr_flags = iaf->addr_flags;
flags |= IPV6_AF_ADDED;
} else
addr_flags = IN6_IFF_TENTATIVE;
TAILQ_INIT(&ia->pd_pfxs);
#endif
-#ifdef IPV6_AF_TEMPORARY
- tempaddr = ia->flags & IPV6_AF_TEMPORARY;
-#else
- tempaddr = false;
-#endif
-
if (prefix_len == 128)
goto makepfx;
else if (ia->flags & IPV6_AF_AUTOCONF && !tempaddr) {
ia->prefix = *addr;
- ia->dadcounter = ipv6_makeaddr(&ia->addr, ifp,
- &ia->prefix,
- ia->prefix_len);
- if (ia->dadcounter == -1)
- goto err;
+ if (iaf != NULL)
+ memcpy(&ia->addr, &iaf->addr, sizeof(ia->addr));
+ else {
+ ia->dadcounter = ipv6_makeaddr(&ia->addr, ifp,
+ &ia->prefix,
+ ia->prefix_len);
+ if (ia->dadcounter == -1)
+ goto err;
+ }
} else if (ia->flags & IPV6_AF_RAPFX) {
ia->prefix = *addr;
#ifdef __sun
return NULL;
}
+static struct ipv6_addr *
+ipv6nd_rapfindprefix(struct ra *rap,
+ const struct in6_addr *pfx, uint8_t pfxlen)
+{
+ struct ipv6_addr *ia;
+
+ TAILQ_FOREACH(ia, &rap->addrs, next) {
+ if (ia->prefix_vltime == 0)
+ continue;
+ if (ia->prefix_len == pfxlen &&
+ IN6_ARE_ADDR_EQUAL(&ia->prefix, pfx))
+ break;
+ }
+ return ia;
+}
+
+struct ipv6_addr *
+ipv6nd_iffindprefix(struct interface *ifp,
+ const struct in6_addr *pfx, uint8_t pfxlen)
+{
+ struct ra *rap;
+ struct ipv6_addr *ia;
+
+ ia = NULL;
+ TAILQ_FOREACH(rap, ifp->ctx->ra_routers, next) {
+ if (rap->iface != ifp)
+ continue;
+ ia = ipv6nd_rapfindprefix(rap, pfx, pfxlen);
+ if (ia != NULL)
+ break;
+ }
+ return ia;
+}
+
static void
ipv6nd_removefreedrop_ra(struct ra *rap, int remove_ra, int drop_ra)
{
logmessage(loglevel, "%s: pltime > vltime", ifp->name);
continue;
}
- TAILQ_FOREACH(ia, &rap->addrs, next)
- if (ia->prefix_len == pi.nd_opt_pi_prefix_len &&
- IN6_ARE_ADDR_EQUAL(&ia->prefix, &pi_prefix))
- break;
+ ia = ipv6nd_rapfindprefix(rap,
+ &pi_prefix, pi.nd_opt_pi_prefix_len);
if (ia == NULL) {
unsigned int flags;
const struct in6_addr *addr, unsigned int flags);
struct ipv6_addr *ipv6nd_findaddr(struct dhcpcd_ctx *,
const struct in6_addr *, unsigned int);
+struct ipv6_addr *ipv6nd_iffindprefix(struct interface *,
+ const struct in6_addr *, uint8_t);
ssize_t ipv6nd_free(struct interface *);
void ipv6nd_expirera(void *arg);
bool ipv6nd_hasralifetime(const struct interface *, bool);