Commit 637575a1 authored by Shirley Ma's avatar Shirley Ma Committed by David S. Miller

[IPV6]: Initialize pmtu/advmss in ndisc dst entries.

When creating dst entry from ndisc, the dst entry of pmtu is not set, and the 
outout for this kind of dst entry is set to ip_output2 instead of ip_output. 
This could lead to send bigger packets through these des entries without 
fragmentation, and uninitialized pmtu could lead the network unreachable. 

These problems are easy reproduced when configuring IPSEC for ipv6. IPSEC 
could pick up dst entry created by ndisc as child des entry if ndisc dst 
entry generated earlier. If sending bigger packets through IPSEC, the ip 
output2 will send bigger packets out, the driver will drop these packets on 
receiver side. Also the dst_entry pmtu will be 0, the network is unreachable.

The patch has been tested against 2.6.6. I am not sure why ndisc genereats dst 
entry with output equal to ip6_output2 not ip6_output. If ndisc sends bigger 
packets, it will break also.
Signed-off-by: default avatarShirley Ma <mashirle@us.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@redhat.com>
parent be59ef03
...@@ -356,7 +356,6 @@ extern int ip6_dst_lookup(struct sock *sk, ...@@ -356,7 +356,6 @@ extern int ip6_dst_lookup(struct sock *sk,
*/ */
extern int ip6_output(struct sk_buff **pskb); extern int ip6_output(struct sk_buff **pskb);
extern int ip6_output2(struct sk_buff **pskb);
extern int ip6_forward(struct sk_buff *skb); extern int ip6_forward(struct sk_buff *skb);
extern int ip6_input(struct sk_buff *skb); extern int ip6_input(struct sk_buff *skb);
extern int ip6_mc_input(struct sk_buff *skb); extern int ip6_mc_input(struct sk_buff *skb);
......
...@@ -107,7 +107,7 @@ static int ip6_dev_loopback_xmit(struct sk_buff *newskb) ...@@ -107,7 +107,7 @@ static int ip6_dev_loopback_xmit(struct sk_buff *newskb)
} }
int ip6_output2(struct sk_buff **pskb) static int ip6_output2(struct sk_buff **pskb)
{ {
struct sk_buff *skb = *pskb; struct sk_buff *skb = *pskb;
struct dst_entry *dst = skb->dst; struct dst_entry *dst = skb->dst;
......
...@@ -395,7 +395,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, ...@@ -395,7 +395,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
ndisc_flow_init(&fl, NDISC_NEIGHBOUR_ADVERTISEMENT, src_addr, daddr); ndisc_flow_init(&fl, NDISC_NEIGHBOUR_ADVERTISEMENT, src_addr, daddr);
dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output2); dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output);
if (!dst) if (!dst)
return; return;
...@@ -486,7 +486,7 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, ...@@ -486,7 +486,7 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
ndisc_flow_init(&fl, NDISC_NEIGHBOUR_SOLICITATION, saddr, daddr); ndisc_flow_init(&fl, NDISC_NEIGHBOUR_SOLICITATION, saddr, daddr);
dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output2); dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output);
if (!dst) if (!dst)
return; return;
...@@ -562,7 +562,7 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, ...@@ -562,7 +562,7 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr,
ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr); ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr);
dst = ndisc_dst_alloc(dev, NULL, daddr, ip6_output2); dst = ndisc_dst_alloc(dev, NULL, daddr, ip6_output);
if (!dst) if (!dst)
return; return;
......
...@@ -573,6 +573,8 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu) ...@@ -573,6 +573,8 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
/* Protected by rt6_lock. */ /* Protected by rt6_lock. */
static struct dst_entry *ndisc_dst_gc_list; static struct dst_entry *ndisc_dst_gc_list;
static int ipv6_get_mtu(struct net_device *dev);
static inline unsigned int ipv6_advmss(unsigned int mtu);
struct dst_entry *ndisc_dst_alloc(struct net_device *dev, struct dst_entry *ndisc_dst_alloc(struct net_device *dev,
struct neighbour *neigh, struct neighbour *neigh,
...@@ -598,6 +600,8 @@ struct dst_entry *ndisc_dst_alloc(struct net_device *dev, ...@@ -598,6 +600,8 @@ struct dst_entry *ndisc_dst_alloc(struct net_device *dev,
rt->rt6i_metric = 0; rt->rt6i_metric = 0;
atomic_set(&rt->u.dst.__refcnt, 1); atomic_set(&rt->u.dst.__refcnt, 1);
rt->u.dst.metrics[RTAX_HOPLIMIT-1] = 255; rt->u.dst.metrics[RTAX_HOPLIMIT-1] = 255;
rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev);
rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_pmtu(&rt->u.dst));
rt->u.dst.output = output; rt->u.dst.output = output;
write_lock_bh(&rt6_lock); write_lock_bh(&rt6_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment