aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/tcp.c')
-rw-r--r--net/ipv4/tcp.c24
1 files changed, 16 insertions, 8 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index ce572f9dff02..0cd71b84e483 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -522,8 +522,12 @@ static int tcp_splice_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
522 unsigned int offset, size_t len) 522 unsigned int offset, size_t len)
523{ 523{
524 struct tcp_splice_state *tss = rd_desc->arg.data; 524 struct tcp_splice_state *tss = rd_desc->arg.data;
525 int ret;
525 526
526 return skb_splice_bits(skb, offset, tss->pipe, tss->len, tss->flags); 527 ret = skb_splice_bits(skb, offset, tss->pipe, rd_desc->count, tss->flags);
528 if (ret > 0)
529 rd_desc->count -= ret;
530 return ret;
527} 531}
528 532
529static int __tcp_splice_read(struct sock *sk, struct tcp_splice_state *tss) 533static int __tcp_splice_read(struct sock *sk, struct tcp_splice_state *tss)
@@ -531,6 +535,7 @@ static int __tcp_splice_read(struct sock *sk, struct tcp_splice_state *tss)
531 /* Store TCP splice context information in read_descriptor_t. */ 535 /* Store TCP splice context information in read_descriptor_t. */
532 read_descriptor_t rd_desc = { 536 read_descriptor_t rd_desc = {
533 .arg.data = tss, 537 .arg.data = tss,
538 .count = tss->len,
534 }; 539 };
535 540
536 return tcp_read_sock(sk, &rd_desc, tcp_splice_data_recv); 541 return tcp_read_sock(sk, &rd_desc, tcp_splice_data_recv);
@@ -611,11 +616,13 @@ ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos,
611 tss.len -= ret; 616 tss.len -= ret;
612 spliced += ret; 617 spliced += ret;
613 618
619 if (!timeo)
620 break;
614 release_sock(sk); 621 release_sock(sk);
615 lock_sock(sk); 622 lock_sock(sk);
616 623
617 if (sk->sk_err || sk->sk_state == TCP_CLOSE || 624 if (sk->sk_err || sk->sk_state == TCP_CLOSE ||
618 (sk->sk_shutdown & RCV_SHUTDOWN) || !timeo || 625 (sk->sk_shutdown & RCV_SHUTDOWN) ||
619 signal_pending(current)) 626 signal_pending(current))
620 break; 627 break;
621 } 628 }
@@ -2382,7 +2389,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features)
2382 unsigned int seq; 2389 unsigned int seq;
2383 __be32 delta; 2390 __be32 delta;
2384 unsigned int oldlen; 2391 unsigned int oldlen;
2385 unsigned int len; 2392 unsigned int mss;
2386 2393
2387 if (!pskb_may_pull(skb, sizeof(*th))) 2394 if (!pskb_may_pull(skb, sizeof(*th)))
2388 goto out; 2395 goto out;
@@ -2398,10 +2405,13 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features)
2398 oldlen = (u16)~skb->len; 2405 oldlen = (u16)~skb->len;
2399 __skb_pull(skb, thlen); 2406 __skb_pull(skb, thlen);
2400 2407
2408 mss = skb_shinfo(skb)->gso_size;
2409 if (unlikely(skb->len <= mss))
2410 goto out;
2411
2401 if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) { 2412 if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) {
2402 /* Packet is from an untrusted source, reset gso_segs. */ 2413 /* Packet is from an untrusted source, reset gso_segs. */
2403 int type = skb_shinfo(skb)->gso_type; 2414 int type = skb_shinfo(skb)->gso_type;
2404 int mss;
2405 2415
2406 if (unlikely(type & 2416 if (unlikely(type &
2407 ~(SKB_GSO_TCPV4 | 2417 ~(SKB_GSO_TCPV4 |
@@ -2412,7 +2422,6 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features)
2412 !(type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))) 2422 !(type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))))
2413 goto out; 2423 goto out;
2414 2424
2415 mss = skb_shinfo(skb)->gso_size;
2416 skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss); 2425 skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss);
2417 2426
2418 segs = NULL; 2427 segs = NULL;
@@ -2423,8 +2432,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features)
2423 if (IS_ERR(segs)) 2432 if (IS_ERR(segs))
2424 goto out; 2433 goto out;
2425 2434
2426 len = skb_shinfo(skb)->gso_size; 2435 delta = htonl(oldlen + (thlen + mss));
2427 delta = htonl(oldlen + (thlen + len));
2428 2436
2429 skb = segs; 2437 skb = segs;
2430 th = tcp_hdr(skb); 2438 th = tcp_hdr(skb);
@@ -2440,7 +2448,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features)
2440 csum_fold(csum_partial(skb_transport_header(skb), 2448 csum_fold(csum_partial(skb_transport_header(skb),
2441 thlen, skb->csum)); 2449 thlen, skb->csum));
2442 2450
2443 seq += len; 2451 seq += mss;
2444 skb = skb->next; 2452 skb = skb->next;
2445 th = tcp_hdr(skb); 2453 th = tcp_hdr(skb);
2446 2454