aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/tcp.h10
-rw-r--r--include/net/tcp.h9
-rw-r--r--net/ipv4/Makefile2
-rw-r--r--net/ipv4/syncookies.c2
-rw-r--r--net/ipv4/sysctl_net_ipv4.c7
-rw-r--r--net/ipv4/tcp_fastopen.c11
-rw-r--r--net/ipv4/tcp_input.c26
-rw-r--r--net/ipv4/tcp_ipv4.c2
-rw-r--r--net/ipv4/tcp_minisocks.c4
-rw-r--r--net/ipv4/tcp_output.c25
-rw-r--r--net/ipv6/syncookies.c2
-rw-r--r--net/ipv6/tcp_ipv6.c2
12 files changed, 86 insertions, 16 deletions
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 1888169e07c7..12948f543839 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -243,6 +243,16 @@ static inline unsigned int tcp_optlen(const struct sk_buff *skb)
243 return (tcp_hdr(skb)->doff - 5) * 4; 243 return (tcp_hdr(skb)->doff - 5) * 4;
244} 244}
245 245
246/* TCP Fast Open */
247#define TCP_FASTOPEN_COOKIE_MIN 4 /* Min Fast Open Cookie size in bytes */
248#define TCP_FASTOPEN_COOKIE_MAX 16 /* Max Fast Open Cookie size in bytes */
249
250/* TCP Fast Open Cookie as stored in memory */
251struct tcp_fastopen_cookie {
252 s8 len;
253 u8 val[TCP_FASTOPEN_COOKIE_MAX];
254};
255
246/* This defines a selective acknowledgement block. */ 256/* This defines a selective acknowledgement block. */
247struct tcp_sack_block_wire { 257struct tcp_sack_block_wire {
248 __be32 start_seq; 258 __be32 start_seq;
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 85c5090bfe25..5aed3718fde8 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -170,6 +170,11 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);
170#define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */ 170#define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */
171#define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */ 171#define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */
172#define TCPOPT_COOKIE 253 /* Cookie extension (experimental) */ 172#define TCPOPT_COOKIE 253 /* Cookie extension (experimental) */
173#define TCPOPT_EXP 254 /* Experimental */
174/* Magic number to be after the option value for sharing TCP
175 * experimental options. See draft-ietf-tcpm-experimental-options-00.txt
176 */
177#define TCPOPT_FASTOPEN_MAGIC 0xF989
173 178
174/* 179/*
175 * TCP option lengths 180 * TCP option lengths
@@ -180,6 +185,7 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);
180#define TCPOLEN_SACK_PERM 2 185#define TCPOLEN_SACK_PERM 2
181#define TCPOLEN_TIMESTAMP 10 186#define TCPOLEN_TIMESTAMP 10
182#define TCPOLEN_MD5SIG 18 187#define TCPOLEN_MD5SIG 18
188#define TCPOLEN_EXP_FASTOPEN_BASE 4
183#define TCPOLEN_COOKIE_BASE 2 /* Cookie-less header extension */ 189#define TCPOLEN_COOKIE_BASE 2 /* Cookie-less header extension */
184#define TCPOLEN_COOKIE_PAIR 3 /* Cookie pair header extension */ 190#define TCPOLEN_COOKIE_PAIR 3 /* Cookie pair header extension */
185#define TCPOLEN_COOKIE_MIN (TCPOLEN_COOKIE_BASE+TCP_COOKIE_MIN) 191#define TCPOLEN_COOKIE_MIN (TCPOLEN_COOKIE_BASE+TCP_COOKIE_MIN)
@@ -222,6 +228,7 @@ extern int sysctl_tcp_retries1;
222extern int sysctl_tcp_retries2; 228extern int sysctl_tcp_retries2;
223extern int sysctl_tcp_orphan_retries; 229extern int sysctl_tcp_orphan_retries;
224extern int sysctl_tcp_syncookies; 230extern int sysctl_tcp_syncookies;
231extern int sysctl_tcp_fastopen;
225extern int sysctl_tcp_retrans_collapse; 232extern int sysctl_tcp_retrans_collapse;
226extern int sysctl_tcp_stdurg; 233extern int sysctl_tcp_stdurg;
227extern int sysctl_tcp_rfc1337; 234extern int sysctl_tcp_rfc1337;
@@ -418,7 +425,7 @@ extern int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
418 size_t len, int nonblock, int flags, int *addr_len); 425 size_t len, int nonblock, int flags, int *addr_len);
419extern void tcp_parse_options(const struct sk_buff *skb, 426extern void tcp_parse_options(const struct sk_buff *skb,
420 struct tcp_options_received *opt_rx, const u8 **hvpp, 427 struct tcp_options_received *opt_rx, const u8 **hvpp,
421 int estab); 428 int estab, struct tcp_fastopen_cookie *foc);
422extern const u8 *tcp_parse_md5sig_option(const struct tcphdr *th); 429extern const u8 *tcp_parse_md5sig_option(const struct tcphdr *th);
423 430
424/* 431/*
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index a677d804e53e..ae2ccf2890e4 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -7,7 +7,7 @@ obj-y := route.o inetpeer.o protocol.o \
7 ip_output.o ip_sockglue.o inet_hashtables.o \ 7 ip_output.o ip_sockglue.o inet_hashtables.o \
8 inet_timewait_sock.o inet_connection_sock.o \ 8 inet_timewait_sock.o inet_connection_sock.o \
9 tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \ 9 tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \
10 tcp_minisocks.o tcp_cong.o tcp_metrics.o \ 10 tcp_minisocks.o tcp_cong.o tcp_metrics.o tcp_fastopen.o \
11 datagram.o raw.o udp.o udplite.o \ 11 datagram.o raw.o udp.o udplite.o \
12 arp.o icmp.o devinet.o af_inet.o igmp.o \ 12 arp.o icmp.o devinet.o af_inet.o igmp.o \
13 fib_frontend.o fib_semantics.o fib_trie.o \ 13 fib_frontend.o fib_semantics.o fib_trie.o \
diff --git a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
index eab2a7fb15d1..650e1528e1e6 100644
--- a/net/ipv4/syncookies.c
+++ b/net/ipv4/syncookies.c
@@ -293,7 +293,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
293 293
294 /* check for timestamp cookie support */ 294 /* check for timestamp cookie support */
295 memset(&tcp_opt, 0, sizeof(tcp_opt)); 295 memset(&tcp_opt, 0, sizeof(tcp_opt));
296 tcp_parse_options(skb, &tcp_opt, &hash_location, 0); 296 tcp_parse_options(skb, &tcp_opt, &hash_location, 0, NULL);
297 297
298 if (!cookie_check_timestamp(&tcp_opt, &ecn_ok)) 298 if (!cookie_check_timestamp(&tcp_opt, &ecn_ok))
299 goto out; 299 goto out;
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 3f6a1e762e9c..5840c3255721 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -367,6 +367,13 @@ static struct ctl_table ipv4_table[] = {
367 }, 367 },
368#endif 368#endif
369 { 369 {
370 .procname = "tcp_fastopen",
371 .data = &sysctl_tcp_fastopen,
372 .maxlen = sizeof(int),
373 .mode = 0644,
374 .proc_handler = proc_dointvec,
375 },
376 {
370 .procname = "tcp_tw_recycle", 377 .procname = "tcp_tw_recycle",
371 .data = &tcp_death_row.sysctl_tw_recycle, 378 .data = &tcp_death_row.sysctl_tw_recycle,
372 .maxlen = sizeof(int), 379 .maxlen = sizeof(int),
diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c
new file mode 100644
index 000000000000..a7f729c409d7
--- /dev/null
+++ b/net/ipv4/tcp_fastopen.c
@@ -0,0 +1,11 @@
1#include <linux/init.h>
2#include <linux/kernel.h>
3
4int sysctl_tcp_fastopen;
5
6static int __init tcp_fastopen_init(void)
7{
8 return 0;
9}
10
11late_initcall(tcp_fastopen_init);
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index fdd49f1b7a52..a06bb8959e7e 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -3732,7 +3732,8 @@ old_ack:
3732 * the fast version below fails. 3732 * the fast version below fails.
3733 */ 3733 */
3734void tcp_parse_options(const struct sk_buff *skb, struct tcp_options_received *opt_rx, 3734void tcp_parse_options(const struct sk_buff *skb, struct tcp_options_received *opt_rx,
3735 const u8 **hvpp, int estab) 3735 const u8 **hvpp, int estab,
3736 struct tcp_fastopen_cookie *foc)
3736{ 3737{
3737 const unsigned char *ptr; 3738 const unsigned char *ptr;
3738 const struct tcphdr *th = tcp_hdr(skb); 3739 const struct tcphdr *th = tcp_hdr(skb);
@@ -3839,8 +3840,25 @@ void tcp_parse_options(const struct sk_buff *skb, struct tcp_options_received *o
3839 break; 3840 break;
3840 } 3841 }
3841 break; 3842 break;
3842 }
3843 3843
3844 case TCPOPT_EXP:
3845 /* Fast Open option shares code 254 using a
3846 * 16 bits magic number. It's valid only in
3847 * SYN or SYN-ACK with an even size.
3848 */
3849 if (opsize < TCPOLEN_EXP_FASTOPEN_BASE ||
3850 get_unaligned_be16(ptr) != TCPOPT_FASTOPEN_MAGIC ||
3851 foc == NULL || !th->syn || (opsize & 1))
3852 break;
3853 foc->len = opsize - TCPOLEN_EXP_FASTOPEN_BASE;
3854 if (foc->len >= TCP_FASTOPEN_COOKIE_MIN &&
3855 foc->len <= TCP_FASTOPEN_COOKIE_MAX)
3856 memcpy(foc->val, ptr + 2, foc->len);
3857 else if (foc->len != 0)
3858 foc->len = -1;
3859 break;
3860
3861 }
3844 ptr += opsize-2; 3862 ptr += opsize-2;
3845 length -= opsize; 3863 length -= opsize;
3846 } 3864 }
@@ -3882,7 +3900,7 @@ static bool tcp_fast_parse_options(const struct sk_buff *skb,
3882 if (tcp_parse_aligned_timestamp(tp, th)) 3900 if (tcp_parse_aligned_timestamp(tp, th))
3883 return true; 3901 return true;
3884 } 3902 }
3885 tcp_parse_options(skb, &tp->rx_opt, hvpp, 1); 3903 tcp_parse_options(skb, &tp->rx_opt, hvpp, 1, NULL);
3886 return true; 3904 return true;
3887} 3905}
3888 3906
@@ -5637,7 +5655,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
5637 struct tcp_cookie_values *cvp = tp->cookie_values; 5655 struct tcp_cookie_values *cvp = tp->cookie_values;
5638 int saved_clamp = tp->rx_opt.mss_clamp; 5656 int saved_clamp = tp->rx_opt.mss_clamp;
5639 5657
5640 tcp_parse_options(skb, &tp->rx_opt, &hash_location, 0); 5658 tcp_parse_options(skb, &tp->rx_opt, &hash_location, 0, NULL);
5641 5659
5642 if (th->ack) { 5660 if (th->ack) {
5643 /* rfc793: 5661 /* rfc793:
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index d7d2fa50f07f..01aa77a97020 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1307,7 +1307,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
1307 tcp_clear_options(&tmp_opt); 1307 tcp_clear_options(&tmp_opt);
1308 tmp_opt.mss_clamp = TCP_MSS_DEFAULT; 1308 tmp_opt.mss_clamp = TCP_MSS_DEFAULT;
1309 tmp_opt.user_mss = tp->rx_opt.user_mss; 1309 tmp_opt.user_mss = tp->rx_opt.user_mss;
1310 tcp_parse_options(skb, &tmp_opt, &hash_location, 0); 1310 tcp_parse_options(skb, &tmp_opt, &hash_location, 0, NULL);
1311 1311
1312 if (tmp_opt.cookie_plus > 0 && 1312 if (tmp_opt.cookie_plus > 0 &&
1313 tmp_opt.saw_tstamp && 1313 tmp_opt.saw_tstamp &&
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index c66f2ede160e..5912ac3fd240 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -97,7 +97,7 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
97 97
98 tmp_opt.saw_tstamp = 0; 98 tmp_opt.saw_tstamp = 0;
99 if (th->doff > (sizeof(*th) >> 2) && tcptw->tw_ts_recent_stamp) { 99 if (th->doff > (sizeof(*th) >> 2) && tcptw->tw_ts_recent_stamp) {
100 tcp_parse_options(skb, &tmp_opt, &hash_location, 0); 100 tcp_parse_options(skb, &tmp_opt, &hash_location, 0, NULL);
101 101
102 if (tmp_opt.saw_tstamp) { 102 if (tmp_opt.saw_tstamp) {
103 tmp_opt.ts_recent = tcptw->tw_ts_recent; 103 tmp_opt.ts_recent = tcptw->tw_ts_recent;
@@ -534,7 +534,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
534 534
535 tmp_opt.saw_tstamp = 0; 535 tmp_opt.saw_tstamp = 0;
536 if (th->doff > (sizeof(struct tcphdr)>>2)) { 536 if (th->doff > (sizeof(struct tcphdr)>>2)) {
537 tcp_parse_options(skb, &tmp_opt, &hash_location, 0); 537 tcp_parse_options(skb, &tmp_opt, &hash_location, 0, NULL);
538 538
539 if (tmp_opt.saw_tstamp) { 539 if (tmp_opt.saw_tstamp) {
540 tmp_opt.ts_recent = req->ts_recent; 540 tmp_opt.ts_recent = req->ts_recent;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 15a7c7bc3e58..4849be76ccd6 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -385,15 +385,17 @@ static inline bool tcp_urg_mode(const struct tcp_sock *tp)
385#define OPTION_MD5 (1 << 2) 385#define OPTION_MD5 (1 << 2)
386#define OPTION_WSCALE (1 << 3) 386#define OPTION_WSCALE (1 << 3)
387#define OPTION_COOKIE_EXTENSION (1 << 4) 387#define OPTION_COOKIE_EXTENSION (1 << 4)
388#define OPTION_FAST_OPEN_COOKIE (1 << 8)
388 389
389struct tcp_out_options { 390struct tcp_out_options {
390 u8 options; /* bit field of OPTION_* */ 391 u16 options; /* bit field of OPTION_* */
392 u16 mss; /* 0 to disable */
391 u8 ws; /* window scale, 0 to disable */ 393 u8 ws; /* window scale, 0 to disable */
392 u8 num_sack_blocks; /* number of SACK blocks to include */ 394 u8 num_sack_blocks; /* number of SACK blocks to include */
393 u8 hash_size; /* bytes in hash_location */ 395 u8 hash_size; /* bytes in hash_location */
394 u16 mss; /* 0 to disable */
395 __u32 tsval, tsecr; /* need to include OPTION_TS */
396 __u8 *hash_location; /* temporary pointer, overloaded */ 396 __u8 *hash_location; /* temporary pointer, overloaded */
397 __u32 tsval, tsecr; /* need to include OPTION_TS */
398 struct tcp_fastopen_cookie *fastopen_cookie; /* Fast open cookie */
397}; 399};
398 400
399/* The sysctl int routines are generic, so check consistency here. 401/* The sysctl int routines are generic, so check consistency here.
@@ -442,7 +444,7 @@ static u8 tcp_cookie_size_check(u8 desired)
442static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, 444static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
443 struct tcp_out_options *opts) 445 struct tcp_out_options *opts)
444{ 446{
445 u8 options = opts->options; /* mungable copy */ 447 u16 options = opts->options; /* mungable copy */
446 448
447 /* Having both authentication and cookies for security is redundant, 449 /* Having both authentication and cookies for security is redundant,
448 * and there's certainly not enough room. Instead, the cookie-less 450 * and there's certainly not enough room. Instead, the cookie-less
@@ -564,6 +566,21 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
564 566
565 tp->rx_opt.dsack = 0; 567 tp->rx_opt.dsack = 0;
566 } 568 }
569
570 if (unlikely(OPTION_FAST_OPEN_COOKIE & options)) {
571 struct tcp_fastopen_cookie *foc = opts->fastopen_cookie;
572
573 *ptr++ = htonl((TCPOPT_EXP << 24) |
574 ((TCPOLEN_EXP_FASTOPEN_BASE + foc->len) << 16) |
575 TCPOPT_FASTOPEN_MAGIC);
576
577 memcpy(ptr, foc->val, foc->len);
578 if ((foc->len & 3) == 2) {
579 u8 *align = ((u8 *)ptr) + foc->len;
580 align[0] = align[1] = TCPOPT_NOP;
581 }
582 ptr += (foc->len + 3) >> 2;
583 }
567} 584}
568 585
569/* Compute TCP options for SYN packets. This is not the final 586/* Compute TCP options for SYN packets. This is not the final
diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c
index 7bf3cc427c28..bb46061c813a 100644
--- a/net/ipv6/syncookies.c
+++ b/net/ipv6/syncookies.c
@@ -177,7 +177,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
177 177
178 /* check for timestamp cookie support */ 178 /* check for timestamp cookie support */
179 memset(&tcp_opt, 0, sizeof(tcp_opt)); 179 memset(&tcp_opt, 0, sizeof(tcp_opt));
180 tcp_parse_options(skb, &tcp_opt, &hash_location, 0); 180 tcp_parse_options(skb, &tcp_opt, &hash_location, 0, NULL);
181 181
182 if (!cookie_check_timestamp(&tcp_opt, &ecn_ok)) 182 if (!cookie_check_timestamp(&tcp_opt, &ecn_ok))
183 goto out; 183 goto out;
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index c9dabdd832d7..0302ec3fecfc 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1033,7 +1033,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
1033 tcp_clear_options(&tmp_opt); 1033 tcp_clear_options(&tmp_opt);
1034 tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); 1034 tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
1035 tmp_opt.user_mss = tp->rx_opt.user_mss; 1035 tmp_opt.user_mss = tp->rx_opt.user_mss;
1036 tcp_parse_options(skb, &tmp_opt, &hash_location, 0); 1036 tcp_parse_options(skb, &tmp_opt, &hash_location, 0, NULL);
1037 1037
1038 if (tmp_opt.cookie_plus > 0 && 1038 if (tmp_opt.cookie_plus > 0 &&
1039 tmp_opt.saw_tstamp && 1039 tmp_opt.saw_tstamp &&