diff options
-rw-r--r-- | include/linux/tcp.h | 10 | ||||
-rw-r--r-- | include/net/tcp.h | 9 | ||||
-rw-r--r-- | net/ipv4/Makefile | 2 | ||||
-rw-r--r-- | net/ipv4/syncookies.c | 2 | ||||
-rw-r--r-- | net/ipv4/sysctl_net_ipv4.c | 7 | ||||
-rw-r--r-- | net/ipv4/tcp_fastopen.c | 11 | ||||
-rw-r--r-- | net/ipv4/tcp_input.c | 26 | ||||
-rw-r--r-- | net/ipv4/tcp_ipv4.c | 2 | ||||
-rw-r--r-- | net/ipv4/tcp_minisocks.c | 4 | ||||
-rw-r--r-- | net/ipv4/tcp_output.c | 25 | ||||
-rw-r--r-- | net/ipv6/syncookies.c | 2 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 2 |
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 */ | ||
251 | struct 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. */ |
247 | struct tcp_sack_block_wire { | 257 | struct 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; | |||
222 | extern int sysctl_tcp_retries2; | 228 | extern int sysctl_tcp_retries2; |
223 | extern int sysctl_tcp_orphan_retries; | 229 | extern int sysctl_tcp_orphan_retries; |
224 | extern int sysctl_tcp_syncookies; | 230 | extern int sysctl_tcp_syncookies; |
231 | extern int sysctl_tcp_fastopen; | ||
225 | extern int sysctl_tcp_retrans_collapse; | 232 | extern int sysctl_tcp_retrans_collapse; |
226 | extern int sysctl_tcp_stdurg; | 233 | extern int sysctl_tcp_stdurg; |
227 | extern int sysctl_tcp_rfc1337; | 234 | extern 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); |
419 | extern void tcp_parse_options(const struct sk_buff *skb, | 426 | extern 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); |
422 | extern const u8 *tcp_parse_md5sig_option(const struct tcphdr *th); | 429 | extern 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 | |||
4 | int sysctl_tcp_fastopen; | ||
5 | |||
6 | static int __init tcp_fastopen_init(void) | ||
7 | { | ||
8 | return 0; | ||
9 | } | ||
10 | |||
11 | late_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 | */ |
3734 | void tcp_parse_options(const struct sk_buff *skb, struct tcp_options_received *opt_rx, | 3734 | void 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 | ||
389 | struct tcp_out_options { | 390 | struct 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) | |||
442 | static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, | 444 | static 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 && |