summaryrefslogtreecommitdiffstats
path: root/sys/netinet6/in6_prefix.c
diff options
context:
space:
mode:
authorshin <shin@FreeBSD.org>2000-02-07 01:45:30 +0000
committershin <shin@FreeBSD.org>2000-02-07 01:45:30 +0000
commiteb70be25c7a84f53a22e684eb6455de670fcc769 (patch)
treec357b57387c014d2ac5f5550a5d3ebe6feb8ef0e /sys/netinet6/in6_prefix.c
parentf70608d097453462b734b50effa7e049dd9c2bae (diff)
downloadFreeBSD-src-eb70be25c7a84f53a22e684eb6455de670fcc769.zip
FreeBSD-src-eb70be25c7a84f53a22e684eb6455de670fcc769.tar.gz
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
Diffstat (limited to 'sys/netinet6/in6_prefix.c')
-rw-r--r--sys/netinet6/in6_prefix.c47
1 files changed, 44 insertions, 3 deletions
diff --git a/sys/netinet6/in6_prefix.c b/sys/netinet6/in6_prefix.c
index f55e30d..a323991 100644
--- a/sys/netinet6/in6_prefix.c
+++ b/sys/netinet6/in6_prefix.c
@@ -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;
}
OpenPOWER on IntegriCloud