diff options
-rw-r--r-- | include/linux/tcp.h | 1 | ||||
-rw-r--r-- | include/net/tcp.h | 2 | ||||
-rw-r--r-- | net/ipv4/tcp_fastopen.c | 1 | ||||
-rw-r--r-- | net/ipv4/tcp_input.c | 42 | ||||
-rw-r--r-- | net/ipv4/tcp_output.c | 34 |
5 files changed, 57 insertions, 23 deletions
diff --git a/include/linux/tcp.h b/include/linux/tcp.h index f869ae8afbaf..a48d00318683 100644 --- a/include/linux/tcp.h +++ b/include/linux/tcp.h | |||
@@ -58,6 +58,7 @@ static inline unsigned int tcp_optlen(const struct sk_buff *skb) | |||
58 | struct tcp_fastopen_cookie { | 58 | struct tcp_fastopen_cookie { |
59 | s8 len; | 59 | s8 len; |
60 | u8 val[TCP_FASTOPEN_COOKIE_MAX]; | 60 | u8 val[TCP_FASTOPEN_COOKIE_MAX]; |
61 | bool exp; /* In RFC6994 experimental option format */ | ||
61 | }; | 62 | }; |
62 | 63 | ||
63 | /* This defines a selective acknowledgement block. */ | 64 | /* This defines a selective acknowledgement block. */ |
diff --git a/include/net/tcp.h b/include/net/tcp.h index 963303fb96ae..7292c3c575bc 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h | |||
@@ -179,6 +179,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo); | |||
179 | #define TCPOPT_SACK 5 /* SACK Block */ | 179 | #define TCPOPT_SACK 5 /* SACK Block */ |
180 | #define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */ | 180 | #define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */ |
181 | #define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */ | 181 | #define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */ |
182 | #define TCPOPT_FASTOPEN 34 /* Fast open (RFC7413) */ | ||
182 | #define TCPOPT_EXP 254 /* Experimental */ | 183 | #define TCPOPT_EXP 254 /* Experimental */ |
183 | /* Magic number to be after the option value for sharing TCP | 184 | /* Magic number to be after the option value for sharing TCP |
184 | * experimental options. See draft-ietf-tcpm-experimental-options-00.txt | 185 | * experimental options. See draft-ietf-tcpm-experimental-options-00.txt |
@@ -194,6 +195,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo); | |||
194 | #define TCPOLEN_SACK_PERM 2 | 195 | #define TCPOLEN_SACK_PERM 2 |
195 | #define TCPOLEN_TIMESTAMP 10 | 196 | #define TCPOLEN_TIMESTAMP 10 |
196 | #define TCPOLEN_MD5SIG 18 | 197 | #define TCPOLEN_MD5SIG 18 |
198 | #define TCPOLEN_FASTOPEN_BASE 2 | ||
197 | #define TCPOLEN_EXP_FASTOPEN_BASE 4 | 199 | #define TCPOLEN_EXP_FASTOPEN_BASE 4 |
198 | 200 | ||
199 | /* But this is what stacks really send out. */ | 201 | /* But this is what stacks really send out. */ |
diff --git a/net/ipv4/tcp_fastopen.c b/net/ipv4/tcp_fastopen.c index 5da55e2b5cd2..e3d87aca6be8 100644 --- a/net/ipv4/tcp_fastopen.c +++ b/net/ipv4/tcp_fastopen.c | |||
@@ -303,6 +303,7 @@ fastopen: | |||
303 | } else if (foc->len > 0) /* Client presents an invalid cookie */ | 303 | } else if (foc->len > 0) /* Client presents an invalid cookie */ |
304 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPFASTOPENPASSIVEFAIL); | 304 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPFASTOPENPASSIVEFAIL); |
305 | 305 | ||
306 | valid_foc.exp = foc->exp; | ||
306 | *foc = valid_foc; | 307 | *foc = valid_foc; |
307 | return false; | 308 | return false; |
308 | } | 309 | } |
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index c1ce304ba8d2..24f1630b2afb 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -3603,6 +3603,23 @@ old_ack: | |||
3603 | return 0; | 3603 | return 0; |
3604 | } | 3604 | } |
3605 | 3605 | ||
3606 | static void tcp_parse_fastopen_option(int len, const unsigned char *cookie, | ||
3607 | bool syn, struct tcp_fastopen_cookie *foc, | ||
3608 | bool exp_opt) | ||
3609 | { | ||
3610 | /* Valid only in SYN or SYN-ACK with an even length. */ | ||
3611 | if (!foc || !syn || len < 0 || (len & 1)) | ||
3612 | return; | ||
3613 | |||
3614 | if (len >= TCP_FASTOPEN_COOKIE_MIN && | ||
3615 | len <= TCP_FASTOPEN_COOKIE_MAX) | ||
3616 | memcpy(foc->val, cookie, len); | ||
3617 | else if (len != 0) | ||
3618 | len = -1; | ||
3619 | foc->len = len; | ||
3620 | foc->exp = exp_opt; | ||
3621 | } | ||
3622 | |||
3606 | /* Look for tcp options. Normally only called on SYN and SYNACK packets. | 3623 | /* Look for tcp options. Normally only called on SYN and SYNACK packets. |
3607 | * But, this can also be called on packets in the established flow when | 3624 | * But, this can also be called on packets in the established flow when |
3608 | * the fast version below fails. | 3625 | * the fast version below fails. |
@@ -3692,21 +3709,22 @@ void tcp_parse_options(const struct sk_buff *skb, | |||
3692 | */ | 3709 | */ |
3693 | break; | 3710 | break; |
3694 | #endif | 3711 | #endif |
3712 | case TCPOPT_FASTOPEN: | ||
3713 | tcp_parse_fastopen_option( | ||
3714 | opsize - TCPOLEN_FASTOPEN_BASE, | ||
3715 | ptr, th->syn, foc, false); | ||
3716 | break; | ||
3717 | |||
3695 | case TCPOPT_EXP: | 3718 | case TCPOPT_EXP: |
3696 | /* Fast Open option shares code 254 using a | 3719 | /* Fast Open option shares code 254 using a |
3697 | * 16 bits magic number. It's valid only in | 3720 | * 16 bits magic number. |
3698 | * SYN or SYN-ACK with an even size. | ||
3699 | */ | 3721 | */ |
3700 | if (opsize < TCPOLEN_EXP_FASTOPEN_BASE || | 3722 | if (opsize >= TCPOLEN_EXP_FASTOPEN_BASE && |
3701 | get_unaligned_be16(ptr) != TCPOPT_FASTOPEN_MAGIC || | 3723 | get_unaligned_be16(ptr) == |
3702 | !foc || !th->syn || (opsize & 1)) | 3724 | TCPOPT_FASTOPEN_MAGIC) |
3703 | break; | 3725 | tcp_parse_fastopen_option(opsize - |
3704 | foc->len = opsize - TCPOLEN_EXP_FASTOPEN_BASE; | 3726 | TCPOLEN_EXP_FASTOPEN_BASE, |
3705 | if (foc->len >= TCP_FASTOPEN_COOKIE_MIN && | 3727 | ptr + 2, th->syn, foc, true); |
3706 | foc->len <= TCP_FASTOPEN_COOKIE_MAX) | ||
3707 | memcpy(foc->val, ptr + 2, foc->len); | ||
3708 | else if (foc->len != 0) | ||
3709 | foc->len = -1; | ||
3710 | break; | 3728 | break; |
3711 | 3729 | ||
3712 | } | 3730 | } |
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 7404e5238e00..464bd8c5de69 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c | |||
@@ -518,17 +518,26 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, | |||
518 | 518 | ||
519 | if (unlikely(OPTION_FAST_OPEN_COOKIE & options)) { | 519 | if (unlikely(OPTION_FAST_OPEN_COOKIE & options)) { |
520 | struct tcp_fastopen_cookie *foc = opts->fastopen_cookie; | 520 | struct tcp_fastopen_cookie *foc = opts->fastopen_cookie; |
521 | u8 *p = (u8 *)ptr; | ||
522 | u32 len; /* Fast Open option length */ | ||
523 | |||
524 | if (foc->exp) { | ||
525 | len = TCPOLEN_EXP_FASTOPEN_BASE + foc->len; | ||
526 | *ptr = htonl((TCPOPT_EXP << 24) | (len << 16) | | ||
527 | TCPOPT_FASTOPEN_MAGIC); | ||
528 | p += TCPOLEN_EXP_FASTOPEN_BASE; | ||
529 | } else { | ||
530 | len = TCPOLEN_FASTOPEN_BASE + foc->len; | ||
531 | *p++ = TCPOPT_FASTOPEN; | ||
532 | *p++ = len; | ||
533 | } | ||
521 | 534 | ||
522 | *ptr++ = htonl((TCPOPT_EXP << 24) | | 535 | memcpy(p, foc->val, foc->len); |
523 | ((TCPOLEN_EXP_FASTOPEN_BASE + foc->len) << 16) | | 536 | if ((len & 3) == 2) { |
524 | TCPOPT_FASTOPEN_MAGIC); | 537 | p[foc->len] = TCPOPT_NOP; |
525 | 538 | p[foc->len + 1] = TCPOPT_NOP; | |
526 | memcpy(ptr, foc->val, foc->len); | ||
527 | if ((foc->len & 3) == 2) { | ||
528 | u8 *align = ((u8 *)ptr) + foc->len; | ||
529 | align[0] = align[1] = TCPOPT_NOP; | ||
530 | } | 539 | } |
531 | ptr += (foc->len + 3) >> 2; | 540 | ptr += (len + 3) >> 2; |
532 | } | 541 | } |
533 | } | 542 | } |
534 | 543 | ||
@@ -641,8 +650,11 @@ static unsigned int tcp_synack_options(struct sock *sk, | |||
641 | if (unlikely(!ireq->tstamp_ok)) | 650 | if (unlikely(!ireq->tstamp_ok)) |
642 | remaining -= TCPOLEN_SACKPERM_ALIGNED; | 651 | remaining -= TCPOLEN_SACKPERM_ALIGNED; |
643 | } | 652 | } |
644 | if (foc && foc->len >= 0) { | 653 | if (foc != NULL && foc->len >= 0) { |
645 | u32 need = TCPOLEN_EXP_FASTOPEN_BASE + foc->len; | 654 | u32 need = foc->len; |
655 | |||
656 | need += foc->exp ? TCPOLEN_EXP_FASTOPEN_BASE : | ||
657 | TCPOLEN_FASTOPEN_BASE; | ||
646 | need = (need + 3) & ~3U; /* Align to 32 bits */ | 658 | need = (need + 3) & ~3U; /* Align to 32 bits */ |
647 | if (remaining >= need) { | 659 | if (remaining >= need) { |
648 | opts->options |= OPTION_FAST_OPEN_COOKIE; | 660 | opts->options |= OPTION_FAST_OPEN_COOKIE; |