aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>2006-03-20 17:05:13 -0800
committerDavid S. Miller <davem@davemloft.net>2006-03-20 17:05:13 -0800
commit270972554c91acd29412d8b6a10e606041012106 (patch)
tree1d8f563c5c79ccd805d3ab8c5acfe1ceb73b08db
parentebacaaa0fdf4402cdf4c8e569f54af36b6f0aa2d (diff)
downloadlinux-270972554c91acd29412d8b6a10e606041012106.tar.gz
[IPV6]: ROUTE: Add Router Reachability Probing (RFC4191).
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv6/route.c39
1 files changed, 39 insertions, 0 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index a7030fed1a18bd..8ba8900c0a5fde 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -218,6 +218,42 @@ static __inline__ struct rt6_info *rt6_device_match(struct rt6_info *rt,
return rt;
}
+#ifdef CONFIG_IPV6_ROUTER_PREF
+static void rt6_probe(struct rt6_info *rt)
+{
+ struct neighbour *neigh = rt ? rt->rt6i_nexthop : NULL;
+ /*
+ * Okay, this does not seem to be appropriate
+ * for now, however, we need to check if it
+ * is really so; aka Router Reachability Probing.
+ *
+ * Router Reachability Probe MUST be rate-limited
+ * to no more than one per minute.
+ */
+ if (!neigh || (neigh->nud_state & NUD_VALID))
+ return;
+ read_lock_bh(&neigh->lock);
+ if (!(neigh->nud_state & NUD_VALID) &&
+ time_after(jiffies, neigh->updated + 60 * HZ)) {
+ struct in6_addr mcaddr;
+ struct in6_addr *target;
+
+ neigh->updated = jiffies;
+ read_unlock_bh(&neigh->lock);
+
+ target = (struct in6_addr *)&neigh->primary_key;
+ addrconf_addr_solict_mult(target, &mcaddr);
+ ndisc_send_ns(rt->rt6i_dev, NULL, target, &mcaddr, NULL);
+ } else
+ read_unlock_bh(&neigh->lock);
+}
+#else
+static inline void rt6_probe(struct rt6_info *rt)
+{
+ return;
+}
+#endif
+
/*
* Default Router Selection (RFC 2461 6.3.6)
*/
@@ -287,8 +323,11 @@ static struct rt6_info *rt6_select(struct rt6_info **head, int oif,
continue;
if (m > mpri) {
+ rt6_probe(match);
match = rt;
mpri = m;
+ } else {
+ rt6_probe(rt);
}
}