|
|
@@ -1315,7 +1315,7 @@ static bool tcp_shifted_skb(struct sock *sk, struct sk_buff *prev,
|
|
|
TCP_SKB_CB(skb)->seq += shifted;
|
|
|
|
|
|
tcp_skb_pcount_add(prev, pcount);
|
|
|
- BUG_ON(tcp_skb_pcount(skb) < pcount);
|
|
|
+ WARN_ON_ONCE(tcp_skb_pcount(skb) < pcount);
|
|
|
tcp_skb_pcount_add(skb, -pcount);
|
|
|
|
|
|
/* When we're adding to gso_segs == 1, gso_size will be zero,
|
|
|
@@ -1381,6 +1381,21 @@ static int skb_can_shift(const struct sk_buff *skb)
|
|
|
return !skb_headlen(skb) && skb_is_nonlinear(skb);
|
|
|
}
|
|
|
|
|
|
+int tcp_skb_shift(struct sk_buff *to, struct sk_buff *from,
|
|
|
+ int pcount, int shiftlen)
|
|
|
+{
|
|
|
+ /* TCP min gso_size is 8 bytes (TCP_MIN_GSO_SIZE)
|
|
|
+ * Since TCP_SKB_CB(skb)->tcp_gso_segs is 16 bits, we need
|
|
|
+ * to make sure not storing more than 65535 * 8 bytes per skb,
|
|
|
+ * even if current MSS is bigger.
|
|
|
+ */
|
|
|
+ if (unlikely(to->len + shiftlen >= 65535 * TCP_MIN_GSO_SIZE))
|
|
|
+ return 0;
|
|
|
+ if (unlikely(tcp_skb_pcount(to) + pcount > 65535))
|
|
|
+ return 0;
|
|
|
+ return skb_shift(to, from, shiftlen);
|
|
|
+}
|
|
|
+
|
|
|
/* Try collapsing SACK blocks spanning across multiple skbs to a single
|
|
|
* skb.
|
|
|
*/
|
|
|
@@ -1486,7 +1501,7 @@ static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb,
|
|
|
if (!after(TCP_SKB_CB(skb)->seq + len, tp->snd_una))
|
|
|
goto fallback;
|
|
|
|
|
|
- if (!skb_shift(prev, skb, len))
|
|
|
+ if (!tcp_skb_shift(prev, skb, pcount, len))
|
|
|
goto fallback;
|
|
|
if (!tcp_shifted_skb(sk, prev, skb, state, pcount, len, mss, dup_sack))
|
|
|
goto out;
|
|
|
@@ -1504,11 +1519,10 @@ static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb,
|
|
|
goto out;
|
|
|
|
|
|
len = skb->len;
|
|
|
- if (skb_shift(prev, skb, len)) {
|
|
|
- pcount += tcp_skb_pcount(skb);
|
|
|
- tcp_shifted_skb(sk, prev, skb, state, tcp_skb_pcount(skb),
|
|
|
+ pcount = tcp_skb_pcount(skb);
|
|
|
+ if (tcp_skb_shift(prev, skb, pcount, len))
|
|
|
+ tcp_shifted_skb(sk, prev, skb, state, pcount,
|
|
|
len, mss, 0);
|
|
|
- }
|
|
|
|
|
|
out:
|
|
|
return prev;
|