aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp_input.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/tcp_input.c')
-rw-r--r--net/ipv4/tcp_input.c28
1 files changed, 24 insertions, 4 deletions
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index fdd88c3803a6..0003d409fec5 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -2478,6 +2478,9 @@ static void tcp_cwnd_reduction(struct sock *sk, const int prior_unsacked,
2478 int newly_acked_sacked = prior_unsacked - 2478 int newly_acked_sacked = prior_unsacked -
2479 (tp->packets_out - tp->sacked_out); 2479 (tp->packets_out - tp->sacked_out);
2480 2480
2481 if (newly_acked_sacked <= 0 || WARN_ON_ONCE(!tp->prior_cwnd))
2482 return;
2483
2481 tp->prr_delivered += newly_acked_sacked; 2484 tp->prr_delivered += newly_acked_sacked;
2482 if (delta < 0) { 2485 if (delta < 0) {
2483 u64 dividend = (u64)tp->snd_ssthresh * tp->prr_delivered + 2486 u64 dividend = (u64)tp->snd_ssthresh * tp->prr_delivered +
@@ -4481,19 +4484,34 @@ static int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int
4481int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size) 4484int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size)
4482{ 4485{
4483 struct sk_buff *skb; 4486 struct sk_buff *skb;
4487 int err = -ENOMEM;
4488 int data_len = 0;
4484 bool fragstolen; 4489 bool fragstolen;
4485 4490
4486 if (size == 0) 4491 if (size == 0)
4487 return 0; 4492 return 0;
4488 4493
4489 skb = alloc_skb(size, sk->sk_allocation); 4494 if (size > PAGE_SIZE) {
4495 int npages = min_t(size_t, size >> PAGE_SHIFT, MAX_SKB_FRAGS);
4496
4497 data_len = npages << PAGE_SHIFT;
4498 size = data_len + (size & ~PAGE_MASK);
4499 }
4500 skb = alloc_skb_with_frags(size - data_len, data_len,
4501 PAGE_ALLOC_COSTLY_ORDER,
4502 &err, sk->sk_allocation);
4490 if (!skb) 4503 if (!skb)
4491 goto err; 4504 goto err;
4492 4505
4506 skb_put(skb, size - data_len);
4507 skb->data_len = data_len;
4508 skb->len = size;
4509
4493 if (tcp_try_rmem_schedule(sk, skb, skb->truesize)) 4510 if (tcp_try_rmem_schedule(sk, skb, skb->truesize))
4494 goto err_free; 4511 goto err_free;
4495 4512
4496 if (memcpy_from_msg(skb_put(skb, size), msg, size)) 4513 err = skb_copy_datagram_from_iter(skb, 0, &msg->msg_iter, size);
4514 if (err)
4497 goto err_free; 4515 goto err_free;
4498 4516
4499 TCP_SKB_CB(skb)->seq = tcp_sk(sk)->rcv_nxt; 4517 TCP_SKB_CB(skb)->seq = tcp_sk(sk)->rcv_nxt;
@@ -4509,7 +4527,8 @@ int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size)
4509err_free: 4527err_free:
4510 kfree_skb(skb); 4528 kfree_skb(skb);
4511err: 4529err:
4512 return -ENOMEM; 4530 return err;
4531
4513} 4532}
4514 4533
4515static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) 4534static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
@@ -5667,6 +5686,7 @@ discard:
5667 } 5686 }
5668 5687
5669 tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1; 5688 tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;
5689 tp->copied_seq = tp->rcv_nxt;
5670 tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1; 5690 tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1;
5671 5691
5672 /* RFC1323: The window in SYN & SYN/ACK segments is 5692 /* RFC1323: The window in SYN & SYN/ACK segments is
@@ -6187,7 +6207,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
6187 tcp_openreq_init(req, &tmp_opt, skb, sk); 6207 tcp_openreq_init(req, &tmp_opt, skb, sk);
6188 6208
6189 /* Note: tcp_v6_init_req() might override ir_iif for link locals */ 6209 /* Note: tcp_v6_init_req() might override ir_iif for link locals */
6190 inet_rsk(req)->ir_iif = sk->sk_bound_dev_if; 6210 inet_rsk(req)->ir_iif = inet_request_bound_dev_if(sk, skb);
6191 6211
6192 af_ops->init_req(req, sk, skb); 6212 af_ops->init_req(req, sk, skb);
6193 6213