summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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