diff options
-rw-r--r-- | sys/netinet6/in6_prefix.c | 47 |
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; } |