|
@@ -223,6 +223,21 @@ static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst,
|
|
|
return neigh_create(&nd_tbl, daddr, dst->dev);
|
|
|
}
|
|
|
|
|
|
+static void ip6_confirm_neigh(const struct dst_entry *dst, const void *daddr)
|
|
|
+{
|
|
|
+ struct net_device *dev = dst->dev;
|
|
|
+ struct rt6_info *rt = (struct rt6_info *)dst;
|
|
|
+
|
|
|
+ daddr = choose_neigh_daddr(rt, NULL, daddr);
|
|
|
+ if (!daddr)
|
|
|
+ return;
|
|
|
+ if (dev->flags & (IFF_NOARP | IFF_LOOPBACK))
|
|
|
+ return;
|
|
|
+ if (ipv6_addr_is_multicast((const struct in6_addr *)daddr))
|
|
|
+ return;
|
|
|
+ __ipv6_confirm_neigh(dev, daddr);
|
|
|
+}
|
|
|
+
|
|
|
static struct dst_ops ip6_dst_ops_template = {
|
|
|
.family = AF_INET6,
|
|
|
.gc = ip6_dst_gc,
|
|
@@ -239,6 +254,7 @@ static struct dst_ops ip6_dst_ops_template = {
|
|
|
.redirect = rt6_do_redirect,
|
|
|
.local_out = __ip6_local_out,
|
|
|
.neigh_lookup = ip6_neigh_lookup,
|
|
|
+ .confirm_neigh = ip6_confirm_neigh,
|
|
|
};
|
|
|
|
|
|
static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst)
|
|
@@ -1365,6 +1381,7 @@ static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt)
|
|
|
static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
|
|
|
const struct ipv6hdr *iph, u32 mtu)
|
|
|
{
|
|
|
+ const struct in6_addr *daddr, *saddr;
|
|
|
struct rt6_info *rt6 = (struct rt6_info *)dst;
|
|
|
|
|
|
if (rt6->rt6i_flags & RTF_LOCAL)
|
|
@@ -1373,26 +1390,26 @@ static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk,
|
|
|
if (dst_metric_locked(dst, RTAX_MTU))
|
|
|
return;
|
|
|
|
|
|
- dst_confirm(dst);
|
|
|
+ if (iph) {
|
|
|
+ daddr = &iph->daddr;
|
|
|
+ saddr = &iph->saddr;
|
|
|
+ } else if (sk) {
|
|
|
+ daddr = &sk->sk_v6_daddr;
|
|
|
+ saddr = &inet6_sk(sk)->saddr;
|
|
|
+ } else {
|
|
|
+ daddr = NULL;
|
|
|
+ saddr = NULL;
|
|
|
+ }
|
|
|
+ dst_confirm_neigh(dst, daddr);
|
|
|
mtu = max_t(u32, mtu, IPV6_MIN_MTU);
|
|
|
if (mtu >= dst_mtu(dst))
|
|
|
return;
|
|
|
|
|
|
if (!rt6_cache_allowed_for_pmtu(rt6)) {
|
|
|
rt6_do_update_pmtu(rt6, mtu);
|
|
|
- } else {
|
|
|
- const struct in6_addr *daddr, *saddr;
|
|
|
+ } else if (daddr) {
|
|
|
struct rt6_info *nrt6;
|
|
|
|
|
|
- if (iph) {
|
|
|
- daddr = &iph->daddr;
|
|
|
- saddr = &iph->saddr;
|
|
|
- } else if (sk) {
|
|
|
- daddr = &sk->sk_v6_daddr;
|
|
|
- saddr = &inet6_sk(sk)->saddr;
|
|
|
- } else {
|
|
|
- return;
|
|
|
- }
|
|
|
nrt6 = ip6_rt_cache_alloc(rt6, daddr, saddr);
|
|
|
if (nrt6) {
|
|
|
rt6_do_update_pmtu(nrt6, mtu);
|
|
@@ -2316,7 +2333,7 @@ static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_bu
|
|
|
* Look, redirects are sent only in response to data packets,
|
|
|
* so that this nexthop apparently is reachable. --ANK
|
|
|
*/
|
|
|
- dst_confirm(&rt->dst);
|
|
|
+ dst_confirm_neigh(&rt->dst, &ipv6_hdr(skb)->saddr);
|
|
|
|
|
|
neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1);
|
|
|
if (!neigh)
|