IPv6 prefix assignment bug fixes.

(1)When all related IPv6 addresses are removed,
       then remove the associated IPv6 prefix.
    (2)When multiple IPv6 link local addrs exist for a same
       interface , then let its IPv6 prefix have multiple
       interface id, and create multiple IPv6 global addrs with same
       interface id.
    (3)When a new IPv6 link local addr is assigned for an
       interface, then let its IPv6 prefix also have the
       interface id of the new IPv6 link local addr, and
       create new IPv6 global addrs with same interface id.

Approved by: jkh
This commit is contained in:
shin 2000-02-07 01:45:30 +00:00
parent f70608d097
commit eb70be25c7

View File

@ -89,11 +89,14 @@ struct rr_prhead rr_prefix;
#include <net/net_osdep.h>
static void add_each_addr __P((struct socket *so, struct rr_prefix *rpp,
struct rp_addr *rap));
static int create_ra_entry __P((struct rp_addr **rapp));
static int add_each_prefix __P((struct socket *so,
struct rr_prefix *rpp));
static void free_rp_entries __P((struct rr_prefix *rpp));
static int link_stray_ia6s __P((struct rr_prefix *rpp));
static void rp_remove __P((struct rr_prefix *rpp));
/*
* Copy bits from src to tgt, from off bit for len bits.
@ -399,6 +402,33 @@ assigne_ra_entry(struct rr_prefix *rpp, int iilen, struct in6_ifaddr *ia)
return 0;
}
static int
in6_prefix_add_llifid(int iilen, struct in6_ifaddr *ia)
{
struct rr_prefix *rpp;
struct rp_addr *rap;
struct socket so;
int error, s;
if ((error = create_ra_entry(&rap)) != 0)
return(error);
/* copy interface id part */
bit_copy((caddr_t)&rap->ra_ifid, sizeof(rap->ra_ifid) << 3,
(caddr_t)IA6_IN6(ia), sizeof(*IA6_IN6(ia)) << 3,
64, (sizeof(rap->ra_ifid) << 3) - 64);
/* XXX: init dummy so */
bzero(&so, sizeof(so));
/* insert into list */
LIST_FOREACH(rpp, &rr_prefix, rp_entry) {
s = splnet();
LIST_INSERT_HEAD(&rpp->rp_addrhead, rap, ra_entry);
splx(s);
add_each_addr(&so, rpp, rap);
}
return 0;
}
int
in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia)
{
@ -407,6 +437,8 @@ in6_prefix_add_ifid(int iilen, struct in6_ifaddr *ia)
struct rp_addr *rap;
int error = 0;
if (IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia)))
return(in6_prefix_add_llifid(iilen, ia));
ifpr = in6_prefixwithifp(ia->ia_ifp, plen, IA6_IN6(ia));
if (ifpr == NULL) {
struct rr_prefix rp;
@ -492,6 +524,8 @@ in6_prefix_remove_ifid(int iilen, struct in6_ifaddr *ia)
splx(s);
free(rap, M_RR_ADDR);
}
if (LIST_EMPTY(&ifpr2rp(ia->ia6_ifpr)->rp_addrhead))
rp_remove(ifpr2rp(ia->ia6_ifpr));
}
static void
@ -1035,11 +1069,17 @@ in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data,
free_rp_entries(&rp_tmp);
break;
}
ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp);
if (ifa != NULL) {
TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
if (ifa->ifa_addr == NULL)
continue; /* just for safety */
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa)) == 0)
continue;
if ((error = create_ra_entry(&rap)) != 0) {
free_rp_entries(&rp_tmp);
break;
goto bad;
}
/* copy interface id part */
bit_copy((caddr_t)&rap->ra_ifid,
@ -1066,6 +1106,7 @@ in6_prefix_ioctl(struct socket *so, u_long cmd, caddr_t data,
error = delete_each_prefix(so, rpp, ipr->ipr_origin);
break;
}
bad:
return error;
}