diff options
Diffstat (limited to 'net/ipv4/tcp_ipv4.c')
| -rw-r--r-- | net/ipv4/tcp_ipv4.c | 64 |
1 files changed, 42 insertions, 22 deletions
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 25ecc6e2478b..c83938b8fcb1 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
| @@ -52,7 +52,6 @@ | |||
| 52 | * a single port at the same time. | 52 | * a single port at the same time. |
| 53 | */ | 53 | */ |
| 54 | 54 | ||
| 55 | #include <linux/config.h> | ||
| 56 | 55 | ||
| 57 | #include <linux/types.h> | 56 | #include <linux/types.h> |
| 58 | #include <linux/fcntl.h> | 57 | #include <linux/fcntl.h> |
| @@ -79,8 +78,8 @@ | |||
| 79 | #include <linux/proc_fs.h> | 78 | #include <linux/proc_fs.h> |
| 80 | #include <linux/seq_file.h> | 79 | #include <linux/seq_file.h> |
| 81 | 80 | ||
| 82 | int sysctl_tcp_tw_reuse; | 81 | int sysctl_tcp_tw_reuse __read_mostly; |
| 83 | int sysctl_tcp_low_latency; | 82 | int sysctl_tcp_low_latency __read_mostly; |
| 84 | 83 | ||
| 85 | /* Check TCP sequence numbers in ICMP packets. */ | 84 | /* Check TCP sequence numbers in ICMP packets. */ |
| 86 | #define ICMP_MIN_LENGTH 8 | 85 | #define ICMP_MIN_LENGTH 8 |
| @@ -91,7 +90,7 @@ static struct socket *tcp_socket; | |||
| 91 | void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb); | 90 | void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb); |
| 92 | 91 | ||
| 93 | struct inet_hashinfo __cacheline_aligned tcp_hashinfo = { | 92 | struct inet_hashinfo __cacheline_aligned tcp_hashinfo = { |
| 94 | .lhash_lock = RW_LOCK_UNLOCKED, | 93 | .lhash_lock = __RW_LOCK_UNLOCKED(tcp_hashinfo.lhash_lock), |
| 95 | .lhash_users = ATOMIC_INIT(0), | 94 | .lhash_users = ATOMIC_INIT(0), |
| 96 | .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(tcp_hashinfo.lhash_wait), | 95 | .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(tcp_hashinfo.lhash_wait), |
| 97 | }; | 96 | }; |
| @@ -160,7 +159,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
| 160 | struct tcp_sock *tp = tcp_sk(sk); | 159 | struct tcp_sock *tp = tcp_sk(sk); |
| 161 | struct sockaddr_in *usin = (struct sockaddr_in *)uaddr; | 160 | struct sockaddr_in *usin = (struct sockaddr_in *)uaddr; |
| 162 | struct rtable *rt; | 161 | struct rtable *rt; |
| 163 | u32 daddr, nexthop; | 162 | __be32 daddr, nexthop; |
| 164 | int tmp; | 163 | int tmp; |
| 165 | int err; | 164 | int err; |
| 166 | 165 | ||
| @@ -242,6 +241,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
| 242 | goto failure; | 241 | goto failure; |
| 243 | 242 | ||
| 244 | /* OK, now commit destination to socket. */ | 243 | /* OK, now commit destination to socket. */ |
| 244 | sk->sk_gso_type = SKB_GSO_TCPV4; | ||
| 245 | sk_setup_caps(sk, &rt->u.dst); | 245 | sk_setup_caps(sk, &rt->u.dst); |
| 246 | 246 | ||
| 247 | if (!tp->write_seq) | 247 | if (!tp->write_seq) |
| @@ -438,7 +438,6 @@ void tcp_v4_err(struct sk_buff *skb, u32 info) | |||
| 438 | It can f.e. if SYNs crossed. | 438 | It can f.e. if SYNs crossed. |
| 439 | */ | 439 | */ |
| 440 | if (!sock_owned_by_user(sk)) { | 440 | if (!sock_owned_by_user(sk)) { |
| 441 | TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS); | ||
| 442 | sk->sk_err = err; | 441 | sk->sk_err = err; |
| 443 | 442 | ||
| 444 | sk->sk_error_report(sk); | 443 | sk->sk_error_report(sk); |
| @@ -485,7 +484,7 @@ void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb) | |||
| 485 | struct inet_sock *inet = inet_sk(sk); | 484 | struct inet_sock *inet = inet_sk(sk); |
| 486 | struct tcphdr *th = skb->h.th; | 485 | struct tcphdr *th = skb->h.th; |
| 487 | 486 | ||
| 488 | if (skb->ip_summed == CHECKSUM_HW) { | 487 | if (skb->ip_summed == CHECKSUM_PARTIAL) { |
| 489 | th->check = ~tcp_v4_check(th, len, inet->saddr, inet->daddr, 0); | 488 | th->check = ~tcp_v4_check(th, len, inet->saddr, inet->daddr, 0); |
| 490 | skb->csum = offsetof(struct tcphdr, check); | 489 | skb->csum = offsetof(struct tcphdr, check); |
| 491 | } else { | 490 | } else { |
| @@ -496,6 +495,24 @@ void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb) | |||
| 496 | } | 495 | } |
| 497 | } | 496 | } |
| 498 | 497 | ||
| 498 | int tcp_v4_gso_send_check(struct sk_buff *skb) | ||
| 499 | { | ||
| 500 | struct iphdr *iph; | ||
| 501 | struct tcphdr *th; | ||
| 502 | |||
| 503 | if (!pskb_may_pull(skb, sizeof(*th))) | ||
| 504 | return -EINVAL; | ||
| 505 | |||
| 506 | iph = skb->nh.iph; | ||
| 507 | th = skb->h.th; | ||
| 508 | |||
| 509 | th->check = 0; | ||
| 510 | th->check = ~tcp_v4_check(th, skb->len, iph->saddr, iph->daddr, 0); | ||
| 511 | skb->csum = offsetof(struct tcphdr, check); | ||
| 512 | skb->ip_summed = CHECKSUM_PARTIAL; | ||
| 513 | return 0; | ||
| 514 | } | ||
| 515 | |||
| 499 | /* | 516 | /* |
| 500 | * This routine will send an RST to the other tcp. | 517 | * This routine will send an RST to the other tcp. |
| 501 | * | 518 | * |
| @@ -717,8 +734,8 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
| 717 | struct inet_request_sock *ireq; | 734 | struct inet_request_sock *ireq; |
| 718 | struct tcp_options_received tmp_opt; | 735 | struct tcp_options_received tmp_opt; |
| 719 | struct request_sock *req; | 736 | struct request_sock *req; |
| 720 | __u32 saddr = skb->nh.iph->saddr; | 737 | __be32 saddr = skb->nh.iph->saddr; |
| 721 | __u32 daddr = skb->nh.iph->daddr; | 738 | __be32 daddr = skb->nh.iph->daddr; |
| 722 | __u32 isn = TCP_SKB_CB(skb)->when; | 739 | __u32 isn = TCP_SKB_CB(skb)->when; |
| 723 | struct dst_entry *dst = NULL; | 740 | struct dst_entry *dst = NULL; |
| 724 | #ifdef CONFIG_SYN_COOKIES | 741 | #ifdef CONFIG_SYN_COOKIES |
| @@ -781,6 +798,9 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
| 781 | 798 | ||
| 782 | tcp_openreq_init(req, &tmp_opt, skb); | 799 | tcp_openreq_init(req, &tmp_opt, skb); |
| 783 | 800 | ||
| 801 | if (security_inet_conn_request(sk, skb, req)) | ||
| 802 | goto drop_and_free; | ||
| 803 | |||
| 784 | ireq = inet_rsk(req); | 804 | ireq = inet_rsk(req); |
| 785 | ireq->loc_addr = daddr; | 805 | ireq->loc_addr = daddr; |
| 786 | ireq->rmt_addr = saddr; | 806 | ireq->rmt_addr = saddr; |
| @@ -856,7 +876,6 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
| 856 | drop_and_free: | 876 | drop_and_free: |
| 857 | reqsk_free(req); | 877 | reqsk_free(req); |
| 858 | drop: | 878 | drop: |
| 859 | TCP_INC_STATS_BH(TCP_MIB_ATTEMPTFAILS); | ||
| 860 | return 0; | 879 | return 0; |
| 861 | } | 880 | } |
| 862 | 881 | ||
| @@ -884,6 +903,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb, | |||
| 884 | if (!newsk) | 903 | if (!newsk) |
| 885 | goto exit; | 904 | goto exit; |
| 886 | 905 | ||
| 906 | newsk->sk_gso_type = SKB_GSO_TCPV4; | ||
| 887 | sk_setup_caps(newsk, dst); | 907 | sk_setup_caps(newsk, dst); |
| 888 | 908 | ||
| 889 | newtp = tcp_sk(newsk); | 909 | newtp = tcp_sk(newsk); |
| @@ -931,9 +951,9 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) | |||
| 931 | if (req) | 951 | if (req) |
| 932 | return tcp_check_req(sk, skb, req, prev); | 952 | return tcp_check_req(sk, skb, req, prev); |
| 933 | 953 | ||
| 934 | nsk = __inet_lookup_established(&tcp_hashinfo, skb->nh.iph->saddr, | 954 | nsk = inet_lookup_established(&tcp_hashinfo, skb->nh.iph->saddr, |
| 935 | th->source, skb->nh.iph->daddr, | 955 | th->source, skb->nh.iph->daddr, |
| 936 | ntohs(th->dest), inet_iif(skb)); | 956 | th->dest, inet_iif(skb)); |
| 937 | 957 | ||
| 938 | if (nsk) { | 958 | if (nsk) { |
| 939 | if (nsk->sk_state != TCP_TIME_WAIT) { | 959 | if (nsk->sk_state != TCP_TIME_WAIT) { |
| @@ -953,7 +973,7 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) | |||
| 953 | 973 | ||
| 954 | static int tcp_v4_checksum_init(struct sk_buff *skb) | 974 | static int tcp_v4_checksum_init(struct sk_buff *skb) |
| 955 | { | 975 | { |
| 956 | if (skb->ip_summed == CHECKSUM_HW) { | 976 | if (skb->ip_summed == CHECKSUM_COMPLETE) { |
| 957 | if (!tcp_v4_check(skb->h.th, skb->len, skb->nh.iph->saddr, | 977 | if (!tcp_v4_check(skb->h.th, skb->len, skb->nh.iph->saddr, |
| 958 | skb->nh.iph->daddr, skb->csum)) { | 978 | skb->nh.iph->daddr, skb->csum)) { |
| 959 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 979 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
| @@ -1070,7 +1090,7 @@ int tcp_v4_rcv(struct sk_buff *skb) | |||
| 1070 | TCP_SKB_CB(skb)->sacked = 0; | 1090 | TCP_SKB_CB(skb)->sacked = 0; |
| 1071 | 1091 | ||
| 1072 | sk = __inet_lookup(&tcp_hashinfo, skb->nh.iph->saddr, th->source, | 1092 | sk = __inet_lookup(&tcp_hashinfo, skb->nh.iph->saddr, th->source, |
| 1073 | skb->nh.iph->daddr, ntohs(th->dest), | 1093 | skb->nh.iph->daddr, th->dest, |
| 1074 | inet_iif(skb)); | 1094 | inet_iif(skb)); |
| 1075 | 1095 | ||
| 1076 | if (!sk) | 1096 | if (!sk) |
| @@ -1084,12 +1104,12 @@ process: | |||
| 1084 | goto discard_and_relse; | 1104 | goto discard_and_relse; |
| 1085 | nf_reset(skb); | 1105 | nf_reset(skb); |
| 1086 | 1106 | ||
| 1087 | if (sk_filter(sk, skb, 0)) | 1107 | if (sk_filter(sk, skb)) |
| 1088 | goto discard_and_relse; | 1108 | goto discard_and_relse; |
| 1089 | 1109 | ||
| 1090 | skb->dev = NULL; | 1110 | skb->dev = NULL; |
| 1091 | 1111 | ||
| 1092 | bh_lock_sock(sk); | 1112 | bh_lock_sock_nested(sk); |
| 1093 | ret = 0; | 1113 | ret = 0; |
| 1094 | if (!sock_owned_by_user(sk)) { | 1114 | if (!sock_owned_by_user(sk)) { |
| 1095 | #ifdef CONFIG_NET_DMA | 1115 | #ifdef CONFIG_NET_DMA |
| @@ -1148,7 +1168,7 @@ do_time_wait: | |||
| 1148 | case TCP_TW_SYN: { | 1168 | case TCP_TW_SYN: { |
| 1149 | struct sock *sk2 = inet_lookup_listener(&tcp_hashinfo, | 1169 | struct sock *sk2 = inet_lookup_listener(&tcp_hashinfo, |
| 1150 | skb->nh.iph->daddr, | 1170 | skb->nh.iph->daddr, |
| 1151 | ntohs(th->dest), | 1171 | th->dest, |
| 1152 | inet_iif(skb)); | 1172 | inet_iif(skb)); |
| 1153 | if (sk2) { | 1173 | if (sk2) { |
| 1154 | inet_twsk_deschedule((struct inet_timewait_sock *)sk, | 1174 | inet_twsk_deschedule((struct inet_timewait_sock *)sk, |
| @@ -1621,10 +1641,9 @@ static int tcp_seq_open(struct inode *inode, struct file *file) | |||
| 1621 | if (unlikely(afinfo == NULL)) | 1641 | if (unlikely(afinfo == NULL)) |
| 1622 | return -EINVAL; | 1642 | return -EINVAL; |
| 1623 | 1643 | ||
| 1624 | s = kmalloc(sizeof(*s), GFP_KERNEL); | 1644 | s = kzalloc(sizeof(*s), GFP_KERNEL); |
| 1625 | if (!s) | 1645 | if (!s) |
| 1626 | return -ENOMEM; | 1646 | return -ENOMEM; |
| 1627 | memset(s, 0, sizeof(*s)); | ||
| 1628 | s->family = afinfo->family; | 1647 | s->family = afinfo->family; |
| 1629 | s->seq_ops.start = tcp_seq_start; | 1648 | s->seq_ops.start = tcp_seq_start; |
| 1630 | s->seq_ops.next = tcp_seq_next; | 1649 | s->seq_ops.next = tcp_seq_next; |
| @@ -1726,7 +1745,8 @@ static void get_tcp4_sock(struct sock *sp, char *tmpbuf, int i) | |||
| 1726 | sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX " | 1745 | sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX " |
| 1727 | "%08X %5d %8d %lu %d %p %u %u %u %u %d", | 1746 | "%08X %5d %8d %lu %d %p %u %u %u %u %d", |
| 1728 | i, src, srcp, dest, destp, sp->sk_state, | 1747 | i, src, srcp, dest, destp, sp->sk_state, |
| 1729 | tp->write_seq - tp->snd_una, tp->rcv_nxt - tp->copied_seq, | 1748 | tp->write_seq - tp->snd_una, |
| 1749 | (sp->sk_state == TCP_LISTEN) ? sp->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq), | ||
| 1730 | timer_active, | 1750 | timer_active, |
| 1731 | jiffies_to_clock_t(timer_expires - jiffies), | 1751 | jiffies_to_clock_t(timer_expires - jiffies), |
| 1732 | icsk->icsk_retransmits, | 1752 | icsk->icsk_retransmits, |
| @@ -1743,7 +1763,7 @@ static void get_tcp4_sock(struct sock *sp, char *tmpbuf, int i) | |||
| 1743 | 1763 | ||
| 1744 | static void get_timewait4_sock(struct inet_timewait_sock *tw, char *tmpbuf, int i) | 1764 | static void get_timewait4_sock(struct inet_timewait_sock *tw, char *tmpbuf, int i) |
| 1745 | { | 1765 | { |
| 1746 | unsigned int dest, src; | 1766 | __be32 dest, src; |
| 1747 | __u16 destp, srcp; | 1767 | __u16 destp, srcp; |
| 1748 | int ttd = tw->tw_ttd - jiffies; | 1768 | int ttd = tw->tw_ttd - jiffies; |
| 1749 | 1769 | ||
