summaryrefslogtreecommitdiffstats
path: root/sys/netinet6/nd6.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet6/nd6.c')
-rw-r--r--sys/netinet6/nd6.c48
1 files changed, 40 insertions, 8 deletions
diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c
index f1e48ea..2b51e43 100644
--- a/sys/netinet6/nd6.c
+++ b/sys/netinet6/nd6.c
@@ -193,6 +193,8 @@ nd6_ifattach(struct ifnet *ifp)
/* A loopback interface does not need to accept RTADV. */
if (V_ip6_accept_rtadv && !(ifp->if_flags & IFF_LOOPBACK))
nd->flags |= ND6_IFF_ACCEPT_RTADV;
+ if (V_ip6_no_radr && !(ifp->if_flags & IFF_LOOPBACK))
+ nd->flags |= ND6_IFF_NO_RADR;
/* XXX: we cannot call nd6_setmtu since ifp is not fully initialized */
nd6_setmtu0(ifp, nd);
@@ -825,7 +827,7 @@ nd6_purge(struct ifnet *ifp)
if (V_nd6_defifindex == ifp->if_index)
nd6_setdefaultiface(0);
- if (!V_ip6_forwarding && ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV) {
+ if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV) {
/* Refresh default router list. */
defrouter_select();
}
@@ -958,10 +960,9 @@ nd6_is_new_addr_neighbor(struct sockaddr_in6 *addr, struct ifnet *ifp)
/*
* If the default router list is empty, all addresses are regarded
* as on-link, and thus, as a neighbor.
- * XXX: we restrict the condition to hosts, because routers usually do
- * not have the "default router list".
*/
- if (!V_ip6_forwarding && TAILQ_FIRST(&V_nd_defrouter) == NULL &&
+ if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV &&
+ TAILQ_FIRST(&V_nd_defrouter) == NULL &&
V_nd6_defifindex == ifp->if_index) {
return (1);
}
@@ -1022,8 +1023,7 @@ nd6_free(struct llentry *ln, int gc)
ifp = ln->lle_tbl->llt_ifp;
- if (!V_ip6_forwarding) {
-
+ if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV) {
dr = defrouter_lookup(&L3_ADDR_SIN6(ln)->sin6_addr, ifp);
if (dr != NULL && dr->expire &&
@@ -1322,6 +1322,16 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
struct ifaddr *ifa;
struct in6_ifaddr *ia;
+ /*
+ * Try to clear ifdisabled flag when enabling
+ * accept_rtadv or auto_linklocal.
+ */
+ if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
+ !(ND.flags & ND6_IFF_IFDISABLED) &&
+ (ND.flags & (ND6_IFF_ACCEPT_RTADV |
+ ND6_IFF_AUTO_LINKLOCAL)))
+ ND.flags &= ~ND6_IFF_IFDISABLED;
+
if ((ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) &&
!(ND.flags & ND6_IFF_IFDISABLED)) {
/* ifdisabled 1->0 transision */
@@ -1340,7 +1350,7 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
continue;
ia = (struct in6_ifaddr *)ifa;
if ((ia->ia6_flags & IN6_IFF_DUPLICATED) &&
- IN6_IS_ADDR_LINKLOCAL(&ia->ia_addr.sin6_addr)) {
+ IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))) {
duplicated_linklocal = 1;
break;
}
@@ -1379,6 +1389,28 @@ nd6_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp)
/* If no link-local address on ifp, configure */
ND_IFINFO(ifp)->flags |= ND6_IFF_AUTO_LINKLOCAL;
in6_ifattach(ifp, NULL);
+ } else if ((ND_IFINFO(ifp)->flags & ND6_IFF_AUTO_LINKLOCAL) &&
+ !(ND.flags & ND6_IFF_IFDISABLED)) {
+ /*
+ * When the IF already has
+ * ND6_IFF_AUTO_LINKLOCAL and no link-local
+ * address is assigned, try to assign one.
+ */
+ int haslinklocal = 0;
+
+ IF_ADDR_LOCK(ifp);
+ TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ if (ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+ ia = (struct in6_ifaddr *)ifa;
+ if (IN6_IS_ADDR_LINKLOCAL(IA6_IN6(ia))) {
+ haslinklocal = 1;
+ break;
+ }
+ }
+ IF_ADDR_UNLOCK(ifp);
+ if (!haslinklocal)
+ in6_ifattach(ifp, NULL);
}
}
ND_IFINFO(ifp)->flags = ND.flags;
@@ -1718,7 +1750,7 @@ nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr,
* for those are not autoconfigured hosts, we explicitly avoid such
* cases for safety.
*/
- if (do_update && router && !V_ip6_forwarding &&
+ if (do_update && router &&
ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV) {
/*
* guaranteed recursion
OpenPOWER on IntegriCloud