diff --git a/sys/net/if.c b/sys/net/if.c --- a/sys/net/if.c +++ b/sys/net/if.c @@ -1077,7 +1077,7 @@ #endif /* INET */ #ifdef INET6 if (ifa->ifa_addr->sa_family == AF_INET6) { - in6_purgeaddr(ifa); + in6_purgeifaddr((struct in6_ifaddr *)ifa); /* ifp_addrhead is already updated */ continue; } diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -696,31 +696,10 @@ } case SIOCDIFADDR_IN6: - { - struct nd_prefix *pr; - - /* - * If the address being deleted is the only one that owns - * the corresponding prefix, expire the prefix as well. - * XXX: theoretically, we don't have to worry about such - * relationship, since we separate the address management - * and the prefix management. We do this, however, to provide - * as much backward compatibility as possible in terms of - * the ioctl operation. - * Note that in6_purgeaddr() will decrement ndpr_addrcnt. - */ - pr = ia->ia6_ndpr; - in6_purgeaddr(&ia->ia_ifa); - if (pr != NULL && pr->ndpr_addrcnt == 0) { - ND6_WLOCK(); - nd6_prefix_unlink(pr, NULL); - ND6_WUNLOCK(); - nd6_prefix_del(pr); - } + in6_purgeifaddr(ia); EVENTHANDLER_INVOKE(ifaddr_event_ext, ifp, &ia->ia_ifa, IFADDR_EVENT_DEL); break; - } default: if (ifp->if_ioctl == NULL) { @@ -1364,6 +1343,36 @@ in6_unlink_ifa(ia, ifp); } +/* + * Removes @ia from the corresponding interfaces and unlinks corresponding + * prefix if no addresses are using it anymore. + */ +void +in6_purgeifaddr(struct in6_ifaddr *ia) +{ + struct nd_prefix *pr; + + /* + * If the address being deleted is the only one that owns + * the corresponding prefix, expire the prefix as well. + * XXX: theoretically, we don't have to worry about such + * relationship, since we separate the address management + * and the prefix management. We do this, however, to provide + * as much backward compatibility as possible in terms of + * the ioctl operation. + * Note that in6_purgeaddr() will decrement ndpr_addrcnt. + */ + pr = ia->ia6_ndpr; + in6_purgeaddr(&ia->ia_ifa); + if (pr != NULL && pr->ndpr_addrcnt == 0) { + ND6_WLOCK(); + nd6_prefix_unlink(pr, NULL); + ND6_WUNLOCK(); + nd6_prefix_del(pr); + } +} + + static void in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp) { diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h --- a/sys/netinet6/in6_var.h +++ b/sys/netinet6/in6_var.h @@ -887,6 +887,7 @@ void in6_prepare_ifra(struct in6_aliasreq *, const struct in6_addr *, const struct in6_addr *); void in6_purgeaddr(struct ifaddr *); +void in6_purgeifaddr(struct in6_ifaddr *); int in6if_do_dad(struct ifnet *); void in6_savemkludge(struct in6_ifaddr *); void *in6_domifattach(struct ifnet *);