aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/tcp.h1
-rw-r--r--include/net/tcp.h2
-rw-r--r--net/ipv4/tcp_fastopen.c1
-rw-r--r--net/ipv4/tcp_input.c42
-rw-r--r--net/ipv4/tcp_output.c34
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)
58struct tcp_fastopen_cookie { 58struct 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
3606static 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;