diff options
Diffstat (limited to 'net/ipv4/tcp.c')
-rw-r--r-- | net/ipv4/tcp.c | 47 |
1 files changed, 27 insertions, 20 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 7a0f0b27bf1f..17b89c523f9d 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -439,12 +439,14 @@ int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg) | |||
439 | !tp->urg_data || | 439 | !tp->urg_data || |
440 | before(tp->urg_seq, tp->copied_seq) || | 440 | before(tp->urg_seq, tp->copied_seq) || |
441 | !before(tp->urg_seq, tp->rcv_nxt)) { | 441 | !before(tp->urg_seq, tp->rcv_nxt)) { |
442 | struct sk_buff *skb; | ||
443 | |||
442 | answ = tp->rcv_nxt - tp->copied_seq; | 444 | answ = tp->rcv_nxt - tp->copied_seq; |
443 | 445 | ||
444 | /* Subtract 1, if FIN is in queue. */ | 446 | /* Subtract 1, if FIN is in queue. */ |
445 | if (answ && !skb_queue_empty(&sk->sk_receive_queue)) | 447 | skb = skb_peek_tail(&sk->sk_receive_queue); |
446 | answ -= | 448 | if (answ && skb) |
447 | tcp_hdr((struct sk_buff *)sk->sk_receive_queue.prev)->fin; | 449 | answ -= tcp_hdr(skb)->fin; |
448 | } else | 450 | } else |
449 | answ = tp->urg_seq - tp->copied_seq; | 451 | answ = tp->urg_seq - tp->copied_seq; |
450 | release_sock(sk); | 452 | release_sock(sk); |
@@ -1382,11 +1384,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
1382 | 1384 | ||
1383 | /* Next get a buffer. */ | 1385 | /* Next get a buffer. */ |
1384 | 1386 | ||
1385 | skb = skb_peek(&sk->sk_receive_queue); | 1387 | skb_queue_walk(&sk->sk_receive_queue, skb) { |
1386 | do { | ||
1387 | if (!skb) | ||
1388 | break; | ||
1389 | |||
1390 | /* Now that we have two receive queues this | 1388 | /* Now that we have two receive queues this |
1391 | * shouldn't happen. | 1389 | * shouldn't happen. |
1392 | */ | 1390 | */ |
@@ -1403,8 +1401,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
1403 | if (tcp_hdr(skb)->fin) | 1401 | if (tcp_hdr(skb)->fin) |
1404 | goto found_fin_ok; | 1402 | goto found_fin_ok; |
1405 | WARN_ON(!(flags & MSG_PEEK)); | 1403 | WARN_ON(!(flags & MSG_PEEK)); |
1406 | skb = skb->next; | 1404 | } |
1407 | } while (skb != (struct sk_buff *)&sk->sk_receive_queue); | ||
1408 | 1405 | ||
1409 | /* Well, if we have backlog, try to process it now yet. */ | 1406 | /* Well, if we have backlog, try to process it now yet. */ |
1410 | 1407 | ||
@@ -2518,20 +2515,30 @@ struct sk_buff **tcp_gro_receive(struct sk_buff **head, struct sk_buff *skb) | |||
2518 | unsigned int thlen; | 2515 | unsigned int thlen; |
2519 | unsigned int flags; | 2516 | unsigned int flags; |
2520 | unsigned int mss = 1; | 2517 | unsigned int mss = 1; |
2518 | unsigned int hlen; | ||
2519 | unsigned int off; | ||
2521 | int flush = 1; | 2520 | int flush = 1; |
2522 | int i; | 2521 | int i; |
2523 | 2522 | ||
2524 | th = skb_gro_header(skb, sizeof(*th)); | 2523 | off = skb_gro_offset(skb); |
2525 | if (unlikely(!th)) | 2524 | hlen = off + sizeof(*th); |
2526 | goto out; | 2525 | th = skb_gro_header_fast(skb, off); |
2526 | if (skb_gro_header_hard(skb, hlen)) { | ||
2527 | th = skb_gro_header_slow(skb, hlen, off); | ||
2528 | if (unlikely(!th)) | ||
2529 | goto out; | ||
2530 | } | ||
2527 | 2531 | ||
2528 | thlen = th->doff * 4; | 2532 | thlen = th->doff * 4; |
2529 | if (thlen < sizeof(*th)) | 2533 | if (thlen < sizeof(*th)) |
2530 | goto out; | 2534 | goto out; |
2531 | 2535 | ||
2532 | th = skb_gro_header(skb, thlen); | 2536 | hlen = off + thlen; |
2533 | if (unlikely(!th)) | 2537 | if (skb_gro_header_hard(skb, hlen)) { |
2534 | goto out; | 2538 | th = skb_gro_header_slow(skb, hlen, off); |
2539 | if (unlikely(!th)) | ||
2540 | goto out; | ||
2541 | } | ||
2535 | 2542 | ||
2536 | skb_gro_pull(skb, thlen); | 2543 | skb_gro_pull(skb, thlen); |
2537 | 2544 | ||
@@ -2544,7 +2551,7 @@ struct sk_buff **tcp_gro_receive(struct sk_buff **head, struct sk_buff *skb) | |||
2544 | 2551 | ||
2545 | th2 = tcp_hdr(p); | 2552 | th2 = tcp_hdr(p); |
2546 | 2553 | ||
2547 | if ((th->source ^ th2->source) | (th->dest ^ th2->dest)) { | 2554 | if (*(u32 *)&th->source ^ *(u32 *)&th2->source) { |
2548 | NAPI_GRO_CB(p)->same_flow = 0; | 2555 | NAPI_GRO_CB(p)->same_flow = 0; |
2549 | continue; | 2556 | continue; |
2550 | } | 2557 | } |
@@ -2559,14 +2566,14 @@ found: | |||
2559 | flush |= flags & TCP_FLAG_CWR; | 2566 | flush |= flags & TCP_FLAG_CWR; |
2560 | flush |= (flags ^ tcp_flag_word(th2)) & | 2567 | flush |= (flags ^ tcp_flag_word(th2)) & |
2561 | ~(TCP_FLAG_CWR | TCP_FLAG_FIN | TCP_FLAG_PSH); | 2568 | ~(TCP_FLAG_CWR | TCP_FLAG_FIN | TCP_FLAG_PSH); |
2562 | flush |= (th->ack_seq ^ th2->ack_seq) | (th->window ^ th2->window); | 2569 | flush |= th->ack_seq ^ th2->ack_seq; |
2563 | for (i = sizeof(*th); !flush && i < thlen; i += 4) | 2570 | for (i = sizeof(*th); i < thlen; i += 4) |
2564 | flush |= *(u32 *)((u8 *)th + i) ^ | 2571 | flush |= *(u32 *)((u8 *)th + i) ^ |
2565 | *(u32 *)((u8 *)th2 + i); | 2572 | *(u32 *)((u8 *)th2 + i); |
2566 | 2573 | ||
2567 | mss = skb_shinfo(p)->gso_size; | 2574 | mss = skb_shinfo(p)->gso_size; |
2568 | 2575 | ||
2569 | flush |= (len > mss) | !len; | 2576 | flush |= (len - 1) >= mss; |
2570 | flush |= (ntohl(th2->seq) + skb_gro_len(p)) ^ ntohl(th->seq); | 2577 | flush |= (ntohl(th2->seq) + skb_gro_len(p)) ^ ntohl(th->seq); |
2571 | 2578 | ||
2572 | if (flush || skb_gro_receive(head, skb)) { | 2579 | if (flush || skb_gro_receive(head, skb)) { |