#endif
#ifdef INET6
+static void
+ifa_scope(struct sockaddr_in6 *sin, unsigned int index)
+{
+
+#ifdef __KAME__
+ /* KAME based systems want to store the scope inside the sin6_addr
+ * for link local addreses */
+ if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
+ uint16_t scope = htons(index);
+ memcpy(&sin->sin6_addr.s6_addr[2], &scope,
+ sizeof(scope));
+ }
+ sin->sin6_scope_id = 0;
+#else
+ if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr))
+ sin->sin6_scope_id = index;
+ else
+ sin->sin6_scope_id = 0;
+#endif
+}
+
int
if_address6(const struct ipv6_addr *a, int action)
{
}
ADDADDR(&ifa.ifra_addr, &a->addr);
+ ifa_scope(&ifa.ifra_addr, a->iface->index);
ipv6_mask(&mask, a->prefix_len);
ADDADDR(&ifa.ifra_prefixmask, &mask);
ifa.ifra_lifetime.ia6t_vltime = a->prefix_vltime;
if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
return -1;
-/* KAME based systems want to store the scope inside the sin6_addr
- * for link local addreses */
-#ifdef __KAME__
-#define SCOPE { \
- if (IN6_IS_ADDR_LINKLOCAL(&su.sin.sin6_addr)) { \
- uint16_t scope = htons(su.sin.sin6_scope_id); \
- memcpy(&su.sin.sin6_addr.s6_addr[2], &scope, \
- sizeof(scope)); \
- su.sin.sin6_scope_id = 0; \
- } \
- }
-#else
-#define SCOPE
-#endif
-
#define ADDSU { \
l = RT_ROUNDUP(su.sa.sa_len); \
memcpy(bp, &su, l); \
su.sin.sin6_family = AF_INET6; \
su.sin.sin6_len = sizeof(su.sin); \
(&su.sin)->sin6_addr = *addr; \
- su.sin.sin6_scope_id = scope; \
- SCOPE; \
+ if (scope) \
+ ifa_scope(&su.sin, scope); \
ADDSU; \
}
#define ADDADDR(addr) ADDADDRS(addr, 0)
return -1;
ADDADDRS(&lla->addr, rt->iface->index);
} else {
- ADDADDRS(&rt->gate,
- IN6_ARE_ADDR_EQUAL(&rt->gate, &in6addr_loopback)
- ? 0 : rt->iface->index);
+ ADDADDR(&rt->gate);
}
}
#undef ADDADDR
#undef ADDSU
-#undef SCOPE
if (action >= 0 && rt->mtu) {
rtm.hdr.rtm_inits |= RTV_MTU;
#ifdef INET6
int
-if_addrflags6(const char *ifname, const struct in6_addr *addr)
+if_addrflags6(const struct in6_addr *addr, const struct interface *ifp)
{
int s, flags;
struct in6_ifreq ifr6;
flags = -1;
if (s != -1) {
memset(&ifr6, 0, sizeof(ifr6));
- strncpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
+ strncpy(ifr6.ifr_name, ifp->name, sizeof(ifr6.ifr_name));
ifr6.ifr_addr.sin6_family = AF_INET6;
ifr6.ifr_addr.sin6_addr = *addr;
+ ifa_scope(&ifr6.ifr_addr, ifp->index);
if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) != -1)
flags = ifr6.ifr_ifru.ifru_flags6;
close(s);
ia6.s6_addr[2] = ia6.s6_addr[3] = '\0';
#endif
if (rtm->rtm_type == RTM_NEWADDR) {
- ifa_flags = if_addrflags6(ifp->name,
- &ia6);
+ ifa_flags = if_addrflags6(&ia6, ifp);
if (ifa_flags == -1)
break;
} else
const struct sockaddr_in *dst;
#endif
#ifdef INET6
- const struct sockaddr_in6 *sin6;
+ struct sockaddr_in6 *sin6;
int ifa_flags;
#endif
#ifdef AF_LINK
#endif
#ifdef INET6
case AF_INET6:
- sin6 = (const struct sockaddr_in6 *)
- (void *)ifa->ifa_addr;
- ifa_flags = if_addrflags6(ifa->ifa_name,
- &sin6->sin6_addr);
+ TAILQ_FOREACH(ifp, ifs, next) {
+ if (strcmp(ifp->name, ifa->ifa_name) == 0)
+ break;
+ }
+ if (ifp == NULL)
+ break; /* Should be impossible */
+ sin6 = (struct sockaddr_in6 *)(void *)ifa->ifa_addr;
+#ifdef __KAME__
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
+ /* Remove the scope from the address */
+ sin6->sin6_addr.s6_addr[2] =
+ sin6->sin6_addr.s6_addr[3] = '\0';
+#endif
+ ifa_flags = if_addrflags6(&sin6->sin6_addr, ifp);
if (ifa_flags != -1)
ipv6_handleifa(ctx, RTM_NEWADDR, ifs,
ifa->ifa_name,