|
@@ -564,18 +564,17 @@ int ip6_fragment(struct sock *sk, struct sk_buff *skb,
|
|
/* We must not fragment if the socket is set to force MTU discovery
|
|
/* We must not fragment if the socket is set to force MTU discovery
|
|
* or if the skb it not generated by a local socket.
|
|
* or if the skb it not generated by a local socket.
|
|
*/
|
|
*/
|
|
- if (unlikely(!skb->ignore_df && skb->len > mtu) ||
|
|
|
|
- (IP6CB(skb)->frag_max_size &&
|
|
|
|
- IP6CB(skb)->frag_max_size > mtu)) {
|
|
|
|
- if (skb->sk && dst_allfrag(skb_dst(skb)))
|
|
|
|
- sk_nocaps_add(skb->sk, NETIF_F_GSO_MASK);
|
|
|
|
|
|
+ if (unlikely(!skb->ignore_df && skb->len > mtu))
|
|
|
|
+ goto fail_toobig;
|
|
|
|
|
|
- skb->dev = skb_dst(skb)->dev;
|
|
|
|
- icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
|
|
|
|
- IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
|
|
|
|
- IPSTATS_MIB_FRAGFAILS);
|
|
|
|
- kfree_skb(skb);
|
|
|
|
- return -EMSGSIZE;
|
|
|
|
|
|
+ if (IP6CB(skb)->frag_max_size) {
|
|
|
|
+ if (IP6CB(skb)->frag_max_size > mtu)
|
|
|
|
+ goto fail_toobig;
|
|
|
|
+
|
|
|
|
+ /* don't send fragments larger than what we received */
|
|
|
|
+ mtu = IP6CB(skb)->frag_max_size;
|
|
|
|
+ if (mtu < IPV6_MIN_MTU)
|
|
|
|
+ mtu = IPV6_MIN_MTU;
|
|
}
|
|
}
|
|
|
|
|
|
if (np && np->frag_size < mtu) {
|
|
if (np && np->frag_size < mtu) {
|
|
@@ -813,6 +812,14 @@ slow_path:
|
|
consume_skb(skb);
|
|
consume_skb(skb);
|
|
return err;
|
|
return err;
|
|
|
|
|
|
|
|
+fail_toobig:
|
|
|
|
+ if (skb->sk && dst_allfrag(skb_dst(skb)))
|
|
|
|
+ sk_nocaps_add(skb->sk, NETIF_F_GSO_MASK);
|
|
|
|
+
|
|
|
|
+ skb->dev = skb_dst(skb)->dev;
|
|
|
|
+ icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
|
|
|
|
+ err = -EMSGSIZE;
|
|
|
|
+
|
|
fail:
|
|
fail:
|
|
IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
|
|
IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)),
|
|
IPSTATS_MIB_FRAGFAILS);
|
|
IPSTATS_MIB_FRAGFAILS);
|