diff options
Diffstat (limited to 'net/ipv4/tcp_ipv4.c')
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 175 |
1 files changed, 123 insertions, 52 deletions
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index fe193e53af44..020766292bb0 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -84,6 +84,7 @@ | |||
84 | 84 | ||
85 | int sysctl_tcp_tw_reuse __read_mostly; | 85 | int sysctl_tcp_tw_reuse __read_mostly; |
86 | int sysctl_tcp_low_latency __read_mostly; | 86 | int sysctl_tcp_low_latency __read_mostly; |
87 | EXPORT_SYMBOL(sysctl_tcp_low_latency); | ||
87 | 88 | ||
88 | 89 | ||
89 | #ifdef CONFIG_TCP_MD5SIG | 90 | #ifdef CONFIG_TCP_MD5SIG |
@@ -100,6 +101,7 @@ struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr) | |||
100 | #endif | 101 | #endif |
101 | 102 | ||
102 | struct inet_hashinfo tcp_hashinfo; | 103 | struct inet_hashinfo tcp_hashinfo; |
104 | EXPORT_SYMBOL(tcp_hashinfo); | ||
103 | 105 | ||
104 | static inline __u32 tcp_v4_init_sequence(struct sk_buff *skb) | 106 | static inline __u32 tcp_v4_init_sequence(struct sk_buff *skb) |
105 | { | 107 | { |
@@ -139,7 +141,6 @@ int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp) | |||
139 | 141 | ||
140 | return 0; | 142 | return 0; |
141 | } | 143 | } |
142 | |||
143 | EXPORT_SYMBOL_GPL(tcp_twsk_unique); | 144 | EXPORT_SYMBOL_GPL(tcp_twsk_unique); |
144 | 145 | ||
145 | /* This will initiate an outgoing connection. */ | 146 | /* This will initiate an outgoing connection. */ |
@@ -204,10 +205,12 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
204 | * TIME-WAIT * and initialize rx_opt.ts_recent from it, | 205 | * TIME-WAIT * and initialize rx_opt.ts_recent from it, |
205 | * when trying new connection. | 206 | * when trying new connection. |
206 | */ | 207 | */ |
207 | if (peer != NULL && | 208 | if (peer) { |
208 | (u32)get_seconds() - peer->tcp_ts_stamp <= TCP_PAWS_MSL) { | 209 | inet_peer_refcheck(peer); |
209 | tp->rx_opt.ts_recent_stamp = peer->tcp_ts_stamp; | 210 | if ((u32)get_seconds() - peer->tcp_ts_stamp <= TCP_PAWS_MSL) { |
210 | tp->rx_opt.ts_recent = peer->tcp_ts; | 211 | tp->rx_opt.ts_recent_stamp = peer->tcp_ts_stamp; |
212 | tp->rx_opt.ts_recent = peer->tcp_ts; | ||
213 | } | ||
211 | } | 214 | } |
212 | } | 215 | } |
213 | 216 | ||
@@ -237,7 +240,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) | |||
237 | 240 | ||
238 | /* OK, now commit destination to socket. */ | 241 | /* OK, now commit destination to socket. */ |
239 | sk->sk_gso_type = SKB_GSO_TCPV4; | 242 | sk->sk_gso_type = SKB_GSO_TCPV4; |
240 | sk_setup_caps(sk, &rt->u.dst); | 243 | sk_setup_caps(sk, &rt->dst); |
241 | 244 | ||
242 | if (!tp->write_seq) | 245 | if (!tp->write_seq) |
243 | tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr, | 246 | tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr, |
@@ -265,6 +268,7 @@ failure: | |||
265 | inet->inet_dport = 0; | 268 | inet->inet_dport = 0; |
266 | return err; | 269 | return err; |
267 | } | 270 | } |
271 | EXPORT_SYMBOL(tcp_v4_connect); | ||
268 | 272 | ||
269 | /* | 273 | /* |
270 | * This routine does path mtu discovery as defined in RFC1191. | 274 | * This routine does path mtu discovery as defined in RFC1191. |
@@ -543,6 +547,7 @@ void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb) | |||
543 | 547 | ||
544 | __tcp_v4_send_check(skb, inet->inet_saddr, inet->inet_daddr); | 548 | __tcp_v4_send_check(skb, inet->inet_saddr, inet->inet_daddr); |
545 | } | 549 | } |
550 | EXPORT_SYMBOL(tcp_v4_send_check); | ||
546 | 551 | ||
547 | int tcp_v4_gso_send_check(struct sk_buff *skb) | 552 | int tcp_v4_gso_send_check(struct sk_buff *skb) |
548 | { | 553 | { |
@@ -793,19 +798,20 @@ static void tcp_v4_reqsk_destructor(struct request_sock *req) | |||
793 | kfree(inet_rsk(req)->opt); | 798 | kfree(inet_rsk(req)->opt); |
794 | } | 799 | } |
795 | 800 | ||
796 | #ifdef CONFIG_SYN_COOKIES | 801 | static void syn_flood_warning(const struct sk_buff *skb) |
797 | static void syn_flood_warning(struct sk_buff *skb) | ||
798 | { | 802 | { |
799 | static unsigned long warntime; | 803 | const char *msg; |
800 | 804 | ||
801 | if (time_after(jiffies, (warntime + HZ * 60))) { | 805 | #ifdef CONFIG_SYN_COOKIES |
802 | warntime = jiffies; | 806 | if (sysctl_tcp_syncookies) |
803 | printk(KERN_INFO | 807 | msg = "Sending cookies"; |
804 | "possible SYN flooding on port %d. Sending cookies.\n", | 808 | else |
805 | ntohs(tcp_hdr(skb)->dest)); | ||
806 | } | ||
807 | } | ||
808 | #endif | 809 | #endif |
810 | msg = "Dropping request"; | ||
811 | |||
812 | pr_info("TCP: Possible SYN flooding on port %d. %s.\n", | ||
813 | ntohs(tcp_hdr(skb)->dest), msg); | ||
814 | } | ||
809 | 815 | ||
810 | /* | 816 | /* |
811 | * Save and compile IPv4 options into the request_sock if needed. | 817 | * Save and compile IPv4 options into the request_sock if needed. |
@@ -857,7 +863,6 @@ struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk, | |||
857 | { | 863 | { |
858 | return tcp_v4_md5_do_lookup(sk, inet_sk(addr_sk)->inet_daddr); | 864 | return tcp_v4_md5_do_lookup(sk, inet_sk(addr_sk)->inet_daddr); |
859 | } | 865 | } |
860 | |||
861 | EXPORT_SYMBOL(tcp_v4_md5_lookup); | 866 | EXPORT_SYMBOL(tcp_v4_md5_lookup); |
862 | 867 | ||
863 | static struct tcp_md5sig_key *tcp_v4_reqsk_md5_lookup(struct sock *sk, | 868 | static struct tcp_md5sig_key *tcp_v4_reqsk_md5_lookup(struct sock *sk, |
@@ -924,7 +929,6 @@ int tcp_v4_md5_do_add(struct sock *sk, __be32 addr, | |||
924 | } | 929 | } |
925 | return 0; | 930 | return 0; |
926 | } | 931 | } |
927 | |||
928 | EXPORT_SYMBOL(tcp_v4_md5_do_add); | 932 | EXPORT_SYMBOL(tcp_v4_md5_do_add); |
929 | 933 | ||
930 | static int tcp_v4_md5_add_func(struct sock *sk, struct sock *addr_sk, | 934 | static int tcp_v4_md5_add_func(struct sock *sk, struct sock *addr_sk, |
@@ -962,7 +966,6 @@ int tcp_v4_md5_do_del(struct sock *sk, __be32 addr) | |||
962 | } | 966 | } |
963 | return -ENOENT; | 967 | return -ENOENT; |
964 | } | 968 | } |
965 | |||
966 | EXPORT_SYMBOL(tcp_v4_md5_do_del); | 969 | EXPORT_SYMBOL(tcp_v4_md5_do_del); |
967 | 970 | ||
968 | static void tcp_v4_clear_md5_list(struct sock *sk) | 971 | static void tcp_v4_clear_md5_list(struct sock *sk) |
@@ -1135,7 +1138,6 @@ clear_hash_noput: | |||
1135 | memset(md5_hash, 0, 16); | 1138 | memset(md5_hash, 0, 16); |
1136 | return 1; | 1139 | return 1; |
1137 | } | 1140 | } |
1138 | |||
1139 | EXPORT_SYMBOL(tcp_v4_md5_hash_skb); | 1141 | EXPORT_SYMBOL(tcp_v4_md5_hash_skb); |
1140 | 1142 | ||
1141 | static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb) | 1143 | static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb) |
@@ -1243,6 +1245,8 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1243 | * evidently real one. | 1245 | * evidently real one. |
1244 | */ | 1246 | */ |
1245 | if (inet_csk_reqsk_queue_is_full(sk) && !isn) { | 1247 | if (inet_csk_reqsk_queue_is_full(sk) && !isn) { |
1248 | if (net_ratelimit()) | ||
1249 | syn_flood_warning(skb); | ||
1246 | #ifdef CONFIG_SYN_COOKIES | 1250 | #ifdef CONFIG_SYN_COOKIES |
1247 | if (sysctl_tcp_syncookies) { | 1251 | if (sysctl_tcp_syncookies) { |
1248 | want_cookie = 1; | 1252 | want_cookie = 1; |
@@ -1323,15 +1327,12 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1323 | if (security_inet_conn_request(sk, skb, req)) | 1327 | if (security_inet_conn_request(sk, skb, req)) |
1324 | goto drop_and_free; | 1328 | goto drop_and_free; |
1325 | 1329 | ||
1326 | if (!want_cookie) | 1330 | if (!want_cookie || tmp_opt.tstamp_ok) |
1327 | TCP_ECN_create_request(req, tcp_hdr(skb)); | 1331 | TCP_ECN_create_request(req, tcp_hdr(skb)); |
1328 | 1332 | ||
1329 | if (want_cookie) { | 1333 | if (want_cookie) { |
1330 | #ifdef CONFIG_SYN_COOKIES | ||
1331 | syn_flood_warning(skb); | ||
1332 | req->cookie_ts = tmp_opt.tstamp_ok; | ||
1333 | #endif | ||
1334 | isn = cookie_v4_init_sequence(sk, skb, &req->mss); | 1334 | isn = cookie_v4_init_sequence(sk, skb, &req->mss); |
1335 | req->cookie_ts = tmp_opt.tstamp_ok; | ||
1335 | } else if (!isn) { | 1336 | } else if (!isn) { |
1336 | struct inet_peer *peer = NULL; | 1337 | struct inet_peer *peer = NULL; |
1337 | 1338 | ||
@@ -1349,6 +1350,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) | |||
1349 | (dst = inet_csk_route_req(sk, req)) != NULL && | 1350 | (dst = inet_csk_route_req(sk, req)) != NULL && |
1350 | (peer = rt_get_peer((struct rtable *)dst)) != NULL && | 1351 | (peer = rt_get_peer((struct rtable *)dst)) != NULL && |
1351 | peer->v4daddr == saddr) { | 1352 | peer->v4daddr == saddr) { |
1353 | inet_peer_refcheck(peer); | ||
1352 | if ((u32)get_seconds() - peer->tcp_ts_stamp < TCP_PAWS_MSL && | 1354 | if ((u32)get_seconds() - peer->tcp_ts_stamp < TCP_PAWS_MSL && |
1353 | (s32)(peer->tcp_ts - req->ts_recent) > | 1355 | (s32)(peer->tcp_ts - req->ts_recent) > |
1354 | TCP_PAWS_WINDOW) { | 1356 | TCP_PAWS_WINDOW) { |
@@ -1393,6 +1395,7 @@ drop_and_free: | |||
1393 | drop: | 1395 | drop: |
1394 | return 0; | 1396 | return 0; |
1395 | } | 1397 | } |
1398 | EXPORT_SYMBOL(tcp_v4_conn_request); | ||
1396 | 1399 | ||
1397 | 1400 | ||
1398 | /* | 1401 | /* |
@@ -1478,6 +1481,7 @@ exit: | |||
1478 | dst_release(dst); | 1481 | dst_release(dst); |
1479 | return NULL; | 1482 | return NULL; |
1480 | } | 1483 | } |
1484 | EXPORT_SYMBOL(tcp_v4_syn_recv_sock); | ||
1481 | 1485 | ||
1482 | static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) | 1486 | static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) |
1483 | { | 1487 | { |
@@ -1504,7 +1508,7 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb) | |||
1504 | } | 1508 | } |
1505 | 1509 | ||
1506 | #ifdef CONFIG_SYN_COOKIES | 1510 | #ifdef CONFIG_SYN_COOKIES |
1507 | if (!th->rst && !th->syn && th->ack) | 1511 | if (!th->syn) |
1508 | sk = cookie_v4_check(sk, skb, &(IPCB(skb)->opt)); | 1512 | sk = cookie_v4_check(sk, skb, &(IPCB(skb)->opt)); |
1509 | #endif | 1513 | #endif |
1510 | return sk; | 1514 | return sk; |
@@ -1607,6 +1611,7 @@ csum_err: | |||
1607 | TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS); | 1611 | TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS); |
1608 | goto discard; | 1612 | goto discard; |
1609 | } | 1613 | } |
1614 | EXPORT_SYMBOL(tcp_v4_do_rcv); | ||
1610 | 1615 | ||
1611 | /* | 1616 | /* |
1612 | * From tcp_input.c | 1617 | * From tcp_input.c |
@@ -1793,6 +1798,7 @@ int tcp_v4_remember_stamp(struct sock *sk) | |||
1793 | 1798 | ||
1794 | return 0; | 1799 | return 0; |
1795 | } | 1800 | } |
1801 | EXPORT_SYMBOL(tcp_v4_remember_stamp); | ||
1796 | 1802 | ||
1797 | int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw) | 1803 | int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw) |
1798 | { | 1804 | { |
@@ -1832,6 +1838,7 @@ const struct inet_connection_sock_af_ops ipv4_specific = { | |||
1832 | .compat_getsockopt = compat_ip_getsockopt, | 1838 | .compat_getsockopt = compat_ip_getsockopt, |
1833 | #endif | 1839 | #endif |
1834 | }; | 1840 | }; |
1841 | EXPORT_SYMBOL(ipv4_specific); | ||
1835 | 1842 | ||
1836 | #ifdef CONFIG_TCP_MD5SIG | 1843 | #ifdef CONFIG_TCP_MD5SIG |
1837 | static const struct tcp_sock_af_ops tcp_sock_ipv4_specific = { | 1844 | static const struct tcp_sock_af_ops tcp_sock_ipv4_specific = { |
@@ -1960,7 +1967,6 @@ void tcp_v4_destroy_sock(struct sock *sk) | |||
1960 | 1967 | ||
1961 | percpu_counter_dec(&tcp_sockets_allocated); | 1968 | percpu_counter_dec(&tcp_sockets_allocated); |
1962 | } | 1969 | } |
1963 | |||
1964 | EXPORT_SYMBOL(tcp_v4_destroy_sock); | 1970 | EXPORT_SYMBOL(tcp_v4_destroy_sock); |
1965 | 1971 | ||
1966 | #ifdef CONFIG_PROC_FS | 1972 | #ifdef CONFIG_PROC_FS |
@@ -1978,6 +1984,11 @@ static inline struct inet_timewait_sock *tw_next(struct inet_timewait_sock *tw) | |||
1978 | hlist_nulls_entry(tw->tw_node.next, typeof(*tw), tw_node) : NULL; | 1984 | hlist_nulls_entry(tw->tw_node.next, typeof(*tw), tw_node) : NULL; |
1979 | } | 1985 | } |
1980 | 1986 | ||
1987 | /* | ||
1988 | * Get next listener socket follow cur. If cur is NULL, get first socket | ||
1989 | * starting from bucket given in st->bucket; when st->bucket is zero the | ||
1990 | * very first socket in the hash table is returned. | ||
1991 | */ | ||
1981 | static void *listening_get_next(struct seq_file *seq, void *cur) | 1992 | static void *listening_get_next(struct seq_file *seq, void *cur) |
1982 | { | 1993 | { |
1983 | struct inet_connection_sock *icsk; | 1994 | struct inet_connection_sock *icsk; |
@@ -1988,14 +1999,15 @@ static void *listening_get_next(struct seq_file *seq, void *cur) | |||
1988 | struct net *net = seq_file_net(seq); | 1999 | struct net *net = seq_file_net(seq); |
1989 | 2000 | ||
1990 | if (!sk) { | 2001 | if (!sk) { |
1991 | st->bucket = 0; | 2002 | ilb = &tcp_hashinfo.listening_hash[st->bucket]; |
1992 | ilb = &tcp_hashinfo.listening_hash[0]; | ||
1993 | spin_lock_bh(&ilb->lock); | 2003 | spin_lock_bh(&ilb->lock); |
1994 | sk = sk_nulls_head(&ilb->head); | 2004 | sk = sk_nulls_head(&ilb->head); |
2005 | st->offset = 0; | ||
1995 | goto get_sk; | 2006 | goto get_sk; |
1996 | } | 2007 | } |
1997 | ilb = &tcp_hashinfo.listening_hash[st->bucket]; | 2008 | ilb = &tcp_hashinfo.listening_hash[st->bucket]; |
1998 | ++st->num; | 2009 | ++st->num; |
2010 | ++st->offset; | ||
1999 | 2011 | ||
2000 | if (st->state == TCP_SEQ_STATE_OPENREQ) { | 2012 | if (st->state == TCP_SEQ_STATE_OPENREQ) { |
2001 | struct request_sock *req = cur; | 2013 | struct request_sock *req = cur; |
@@ -2010,6 +2022,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur) | |||
2010 | } | 2022 | } |
2011 | req = req->dl_next; | 2023 | req = req->dl_next; |
2012 | } | 2024 | } |
2025 | st->offset = 0; | ||
2013 | if (++st->sbucket >= icsk->icsk_accept_queue.listen_opt->nr_table_entries) | 2026 | if (++st->sbucket >= icsk->icsk_accept_queue.listen_opt->nr_table_entries) |
2014 | break; | 2027 | break; |
2015 | get_req: | 2028 | get_req: |
@@ -2045,6 +2058,7 @@ start_req: | |||
2045 | read_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock); | 2058 | read_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock); |
2046 | } | 2059 | } |
2047 | spin_unlock_bh(&ilb->lock); | 2060 | spin_unlock_bh(&ilb->lock); |
2061 | st->offset = 0; | ||
2048 | if (++st->bucket < INET_LHTABLE_SIZE) { | 2062 | if (++st->bucket < INET_LHTABLE_SIZE) { |
2049 | ilb = &tcp_hashinfo.listening_hash[st->bucket]; | 2063 | ilb = &tcp_hashinfo.listening_hash[st->bucket]; |
2050 | spin_lock_bh(&ilb->lock); | 2064 | spin_lock_bh(&ilb->lock); |
@@ -2058,7 +2072,12 @@ out: | |||
2058 | 2072 | ||
2059 | static void *listening_get_idx(struct seq_file *seq, loff_t *pos) | 2073 | static void *listening_get_idx(struct seq_file *seq, loff_t *pos) |
2060 | { | 2074 | { |
2061 | void *rc = listening_get_next(seq, NULL); | 2075 | struct tcp_iter_state *st = seq->private; |
2076 | void *rc; | ||
2077 | |||
2078 | st->bucket = 0; | ||
2079 | st->offset = 0; | ||
2080 | rc = listening_get_next(seq, NULL); | ||
2062 | 2081 | ||
2063 | while (rc && *pos) { | 2082 | while (rc && *pos) { |
2064 | rc = listening_get_next(seq, rc); | 2083 | rc = listening_get_next(seq, rc); |
@@ -2073,13 +2092,18 @@ static inline int empty_bucket(struct tcp_iter_state *st) | |||
2073 | hlist_nulls_empty(&tcp_hashinfo.ehash[st->bucket].twchain); | 2092 | hlist_nulls_empty(&tcp_hashinfo.ehash[st->bucket].twchain); |
2074 | } | 2093 | } |
2075 | 2094 | ||
2095 | /* | ||
2096 | * Get first established socket starting from bucket given in st->bucket. | ||
2097 | * If st->bucket is zero, the very first socket in the hash is returned. | ||
2098 | */ | ||
2076 | static void *established_get_first(struct seq_file *seq) | 2099 | static void *established_get_first(struct seq_file *seq) |
2077 | { | 2100 | { |
2078 | struct tcp_iter_state *st = seq->private; | 2101 | struct tcp_iter_state *st = seq->private; |
2079 | struct net *net = seq_file_net(seq); | 2102 | struct net *net = seq_file_net(seq); |
2080 | void *rc = NULL; | 2103 | void *rc = NULL; |
2081 | 2104 | ||
2082 | for (st->bucket = 0; st->bucket <= tcp_hashinfo.ehash_mask; ++st->bucket) { | 2105 | st->offset = 0; |
2106 | for (; st->bucket <= tcp_hashinfo.ehash_mask; ++st->bucket) { | ||
2083 | struct sock *sk; | 2107 | struct sock *sk; |
2084 | struct hlist_nulls_node *node; | 2108 | struct hlist_nulls_node *node; |
2085 | struct inet_timewait_sock *tw; | 2109 | struct inet_timewait_sock *tw; |
@@ -2124,6 +2148,7 @@ static void *established_get_next(struct seq_file *seq, void *cur) | |||
2124 | struct net *net = seq_file_net(seq); | 2148 | struct net *net = seq_file_net(seq); |
2125 | 2149 | ||
2126 | ++st->num; | 2150 | ++st->num; |
2151 | ++st->offset; | ||
2127 | 2152 | ||
2128 | if (st->state == TCP_SEQ_STATE_TIME_WAIT) { | 2153 | if (st->state == TCP_SEQ_STATE_TIME_WAIT) { |
2129 | tw = cur; | 2154 | tw = cur; |
@@ -2140,6 +2165,7 @@ get_tw: | |||
2140 | st->state = TCP_SEQ_STATE_ESTABLISHED; | 2165 | st->state = TCP_SEQ_STATE_ESTABLISHED; |
2141 | 2166 | ||
2142 | /* Look for next non empty bucket */ | 2167 | /* Look for next non empty bucket */ |
2168 | st->offset = 0; | ||
2143 | while (++st->bucket <= tcp_hashinfo.ehash_mask && | 2169 | while (++st->bucket <= tcp_hashinfo.ehash_mask && |
2144 | empty_bucket(st)) | 2170 | empty_bucket(st)) |
2145 | ; | 2171 | ; |
@@ -2167,7 +2193,11 @@ out: | |||
2167 | 2193 | ||
2168 | static void *established_get_idx(struct seq_file *seq, loff_t pos) | 2194 | static void *established_get_idx(struct seq_file *seq, loff_t pos) |
2169 | { | 2195 | { |
2170 | void *rc = established_get_first(seq); | 2196 | struct tcp_iter_state *st = seq->private; |
2197 | void *rc; | ||
2198 | |||
2199 | st->bucket = 0; | ||
2200 | rc = established_get_first(seq); | ||
2171 | 2201 | ||
2172 | while (rc && pos) { | 2202 | while (rc && pos) { |
2173 | rc = established_get_next(seq, rc); | 2203 | rc = established_get_next(seq, rc); |
@@ -2192,24 +2222,72 @@ static void *tcp_get_idx(struct seq_file *seq, loff_t pos) | |||
2192 | return rc; | 2222 | return rc; |
2193 | } | 2223 | } |
2194 | 2224 | ||
2225 | static void *tcp_seek_last_pos(struct seq_file *seq) | ||
2226 | { | ||
2227 | struct tcp_iter_state *st = seq->private; | ||
2228 | int offset = st->offset; | ||
2229 | int orig_num = st->num; | ||
2230 | void *rc = NULL; | ||
2231 | |||
2232 | switch (st->state) { | ||
2233 | case TCP_SEQ_STATE_OPENREQ: | ||
2234 | case TCP_SEQ_STATE_LISTENING: | ||
2235 | if (st->bucket >= INET_LHTABLE_SIZE) | ||
2236 | break; | ||
2237 | st->state = TCP_SEQ_STATE_LISTENING; | ||
2238 | rc = listening_get_next(seq, NULL); | ||
2239 | while (offset-- && rc) | ||
2240 | rc = listening_get_next(seq, rc); | ||
2241 | if (rc) | ||
2242 | break; | ||
2243 | st->bucket = 0; | ||
2244 | /* Fallthrough */ | ||
2245 | case TCP_SEQ_STATE_ESTABLISHED: | ||
2246 | case TCP_SEQ_STATE_TIME_WAIT: | ||
2247 | st->state = TCP_SEQ_STATE_ESTABLISHED; | ||
2248 | if (st->bucket > tcp_hashinfo.ehash_mask) | ||
2249 | break; | ||
2250 | rc = established_get_first(seq); | ||
2251 | while (offset-- && rc) | ||
2252 | rc = established_get_next(seq, rc); | ||
2253 | } | ||
2254 | |||
2255 | st->num = orig_num; | ||
2256 | |||
2257 | return rc; | ||
2258 | } | ||
2259 | |||
2195 | static void *tcp_seq_start(struct seq_file *seq, loff_t *pos) | 2260 | static void *tcp_seq_start(struct seq_file *seq, loff_t *pos) |
2196 | { | 2261 | { |
2197 | struct tcp_iter_state *st = seq->private; | 2262 | struct tcp_iter_state *st = seq->private; |
2263 | void *rc; | ||
2264 | |||
2265 | if (*pos && *pos == st->last_pos) { | ||
2266 | rc = tcp_seek_last_pos(seq); | ||
2267 | if (rc) | ||
2268 | goto out; | ||
2269 | } | ||
2270 | |||
2198 | st->state = TCP_SEQ_STATE_LISTENING; | 2271 | st->state = TCP_SEQ_STATE_LISTENING; |
2199 | st->num = 0; | 2272 | st->num = 0; |
2200 | return *pos ? tcp_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; | 2273 | st->bucket = 0; |
2274 | st->offset = 0; | ||
2275 | rc = *pos ? tcp_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; | ||
2276 | |||
2277 | out: | ||
2278 | st->last_pos = *pos; | ||
2279 | return rc; | ||
2201 | } | 2280 | } |
2202 | 2281 | ||
2203 | static void *tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos) | 2282 | static void *tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos) |
2204 | { | 2283 | { |
2284 | struct tcp_iter_state *st = seq->private; | ||
2205 | void *rc = NULL; | 2285 | void *rc = NULL; |
2206 | struct tcp_iter_state *st; | ||
2207 | 2286 | ||
2208 | if (v == SEQ_START_TOKEN) { | 2287 | if (v == SEQ_START_TOKEN) { |
2209 | rc = tcp_get_idx(seq, 0); | 2288 | rc = tcp_get_idx(seq, 0); |
2210 | goto out; | 2289 | goto out; |
2211 | } | 2290 | } |
2212 | st = seq->private; | ||
2213 | 2291 | ||
2214 | switch (st->state) { | 2292 | switch (st->state) { |
2215 | case TCP_SEQ_STATE_OPENREQ: | 2293 | case TCP_SEQ_STATE_OPENREQ: |
@@ -2217,6 +2295,8 @@ static void *tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
2217 | rc = listening_get_next(seq, v); | 2295 | rc = listening_get_next(seq, v); |
2218 | if (!rc) { | 2296 | if (!rc) { |
2219 | st->state = TCP_SEQ_STATE_ESTABLISHED; | 2297 | st->state = TCP_SEQ_STATE_ESTABLISHED; |
2298 | st->bucket = 0; | ||
2299 | st->offset = 0; | ||
2220 | rc = established_get_first(seq); | 2300 | rc = established_get_first(seq); |
2221 | } | 2301 | } |
2222 | break; | 2302 | break; |
@@ -2227,6 +2307,7 @@ static void *tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos) | |||
2227 | } | 2307 | } |
2228 | out: | 2308 | out: |
2229 | ++*pos; | 2309 | ++*pos; |
2310 | st->last_pos = *pos; | ||
2230 | return rc; | 2311 | return rc; |
2231 | } | 2312 | } |
2232 | 2313 | ||
@@ -2265,6 +2346,7 @@ static int tcp_seq_open(struct inode *inode, struct file *file) | |||
2265 | 2346 | ||
2266 | s = ((struct seq_file *)file->private_data)->private; | 2347 | s = ((struct seq_file *)file->private_data)->private; |
2267 | s->family = afinfo->family; | 2348 | s->family = afinfo->family; |
2349 | s->last_pos = 0; | ||
2268 | return 0; | 2350 | return 0; |
2269 | } | 2351 | } |
2270 | 2352 | ||
@@ -2288,11 +2370,13 @@ int tcp_proc_register(struct net *net, struct tcp_seq_afinfo *afinfo) | |||
2288 | rc = -ENOMEM; | 2370 | rc = -ENOMEM; |
2289 | return rc; | 2371 | return rc; |
2290 | } | 2372 | } |
2373 | EXPORT_SYMBOL(tcp_proc_register); | ||
2291 | 2374 | ||
2292 | void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo) | 2375 | void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo) |
2293 | { | 2376 | { |
2294 | proc_net_remove(net, afinfo->name); | 2377 | proc_net_remove(net, afinfo->name); |
2295 | } | 2378 | } |
2379 | EXPORT_SYMBOL(tcp_proc_unregister); | ||
2296 | 2380 | ||
2297 | static void get_openreq4(struct sock *sk, struct request_sock *req, | 2381 | static void get_openreq4(struct sock *sk, struct request_sock *req, |
2298 | struct seq_file *f, int i, int uid, int *len) | 2382 | struct seq_file *f, int i, int uid, int *len) |
@@ -2516,6 +2600,8 @@ struct proto tcp_prot = { | |||
2516 | .setsockopt = tcp_setsockopt, | 2600 | .setsockopt = tcp_setsockopt, |
2517 | .getsockopt = tcp_getsockopt, | 2601 | .getsockopt = tcp_getsockopt, |
2518 | .recvmsg = tcp_recvmsg, | 2602 | .recvmsg = tcp_recvmsg, |
2603 | .sendmsg = tcp_sendmsg, | ||
2604 | .sendpage = tcp_sendpage, | ||
2519 | .backlog_rcv = tcp_v4_do_rcv, | 2605 | .backlog_rcv = tcp_v4_do_rcv, |
2520 | .hash = inet_hash, | 2606 | .hash = inet_hash, |
2521 | .unhash = inet_unhash, | 2607 | .unhash = inet_unhash, |
@@ -2534,11 +2620,13 @@ struct proto tcp_prot = { | |||
2534 | .twsk_prot = &tcp_timewait_sock_ops, | 2620 | .twsk_prot = &tcp_timewait_sock_ops, |
2535 | .rsk_prot = &tcp_request_sock_ops, | 2621 | .rsk_prot = &tcp_request_sock_ops, |
2536 | .h.hashinfo = &tcp_hashinfo, | 2622 | .h.hashinfo = &tcp_hashinfo, |
2623 | .no_autobind = true, | ||
2537 | #ifdef CONFIG_COMPAT | 2624 | #ifdef CONFIG_COMPAT |
2538 | .compat_setsockopt = compat_tcp_setsockopt, | 2625 | .compat_setsockopt = compat_tcp_setsockopt, |
2539 | .compat_getsockopt = compat_tcp_getsockopt, | 2626 | .compat_getsockopt = compat_tcp_getsockopt, |
2540 | #endif | 2627 | #endif |
2541 | }; | 2628 | }; |
2629 | EXPORT_SYMBOL(tcp_prot); | ||
2542 | 2630 | ||
2543 | 2631 | ||
2544 | static int __net_init tcp_sk_init(struct net *net) | 2632 | static int __net_init tcp_sk_init(struct net *net) |
@@ -2569,20 +2657,3 @@ void __init tcp_v4_init(void) | |||
2569 | if (register_pernet_subsys(&tcp_sk_ops)) | 2657 | if (register_pernet_subsys(&tcp_sk_ops)) |
2570 | panic("Failed to create the TCP control socket.\n"); | 2658 | panic("Failed to create the TCP control socket.\n"); |
2571 | } | 2659 | } |
2572 | |||
2573 | EXPORT_SYMBOL(ipv4_specific); | ||
2574 | EXPORT_SYMBOL(tcp_hashinfo); | ||
2575 | EXPORT_SYMBOL(tcp_prot); | ||
2576 | EXPORT_SYMBOL(tcp_v4_conn_request); | ||
2577 | EXPORT_SYMBOL(tcp_v4_connect); | ||
2578 | EXPORT_SYMBOL(tcp_v4_do_rcv); | ||
2579 | EXPORT_SYMBOL(tcp_v4_remember_stamp); | ||
2580 | EXPORT_SYMBOL(tcp_v4_send_check); | ||
2581 | EXPORT_SYMBOL(tcp_v4_syn_recv_sock); | ||
2582 | |||
2583 | #ifdef CONFIG_PROC_FS | ||
2584 | EXPORT_SYMBOL(tcp_proc_register); | ||
2585 | EXPORT_SYMBOL(tcp_proc_unregister); | ||
2586 | #endif | ||
2587 | EXPORT_SYMBOL(sysctl_tcp_low_latency); | ||
2588 | |||