Message ID | 20130702060405.GD9877@order.stressinduktion.org |
---|---|
State | Accepted, archived |
Delegated to: | David Miller |
Headers | show |
From: Hannes Frederic Sowa <hannes@stressinduktion.org> Date: Tue, 2 Jul 2013 08:04:05 +0200 > If the socket had an IPV6_MTU value set, ip6_append_data_mtu lost track > of this when appending the second frame on a corked socket. This results > in the following splat: ... > While there, also check if path mtu discovery is activated for this > socket. The logic was adapted from ip6_append_data when first writing > on the corked socket. > > This bug was introduced with commit > 0c1833797a5a6ec23ea9261d979aa18078720b74 ("ipv6: fix incorrect ipsec > fragment"). > > v2: > a) Replace IPV6_PMTU_DISC_DO with IPV6_PMTUDISC_PROBE. > b) Don't pass ipv6_pinfo to ip6_append_data_mtu (suggestion by Gao > feng, thanks!). > c) Change mtu to unsigned int, else we get a warning about > non-matching types because of the min()-macro type-check. > > Acked-by: Gao feng <gaofeng@cn.fujitsu.com> > Cc: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> > Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Applied and queued up for -stable. -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index dae1949..be7589e 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1093,11 +1093,12 @@ static inline struct ipv6_rt_hdr *ip6_rthdr_dup(struct ipv6_rt_hdr *src, return src ? kmemdup(src, (src->hdrlen + 1) * 8, gfp) : NULL; } -static void ip6_append_data_mtu(int *mtu, +static void ip6_append_data_mtu(unsigned int *mtu, int *maxfraglen, unsigned int fragheaderlen, struct sk_buff *skb, - struct rt6_info *rt) + struct rt6_info *rt, + bool pmtuprobe) { if (!(rt->dst.flags & DST_XFRM_TUNNEL)) { if (skb == NULL) { @@ -1109,7 +1110,9 @@ static void ip6_append_data_mtu(int *mtu, * this fragment is not first, the headers * space is regarded as data space. */ - *mtu = dst_mtu(rt->dst.path); + *mtu = min(*mtu, pmtuprobe ? + rt->dst.dev->mtu : + dst_mtu(rt->dst.path)); } *maxfraglen = ((*mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr); @@ -1126,11 +1129,10 @@ int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, struct ipv6_pinfo *np = inet6_sk(sk); struct inet_cork *cork; struct sk_buff *skb, *skb_prev = NULL; - unsigned int maxfraglen, fragheaderlen; + unsigned int maxfraglen, fragheaderlen, mtu; int exthdrlen; int dst_exthdrlen; int hh_len; - int mtu; int copy; int err; int offset = 0; @@ -1287,7 +1289,9 @@ alloc_new_skb: /* update mtu and maxfraglen if necessary */ if (skb == NULL || skb_prev == NULL) ip6_append_data_mtu(&mtu, &maxfraglen, - fragheaderlen, skb, rt); + fragheaderlen, skb, rt, + np->pmtudisc == + IPV6_PMTUDISC_PROBE); skb_prev = skb;