aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorDaniel Lee <Longinus00@gmail.com>2015-04-06 17:37:26 -0400
committerDavid S. Miller <davem@davemloft.net>2015-04-07 18:36:39 -0400
commit7f9b838b71eb78a27de27a12ca5de8542fac3115 (patch)
tree05567522b8a365930815675c5961c608f9157940 /net/ipv4
parent812034f11628aaaab0e2d7af1d3bc50a49eb396b (diff)
tcp: RFC7413 option support for Fast Open server
Fast Open has been using the experimental option with a magic number (RFC6994) to request and grant Fast Open cookies. This patch enables the server to support the official IANA option 34 in RFC7413 in addition. The change has passed all existing Fast Open tests with both old and new options at Google. Signed-off-by: Daniel Lee <Longinus00@gmail.com> Signed-off-by: Yuchung Cheng <ycheng@google.com> Signed-off-by: Neal Cardwell <ncardwell@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/tcp_fastopen.c1
-rw-r--r--net/ipv4/tcp_input.c42
-rw-r--r--net/ipv4/tcp_output.c34
3 files changed, 54 insertions, 23 deletions
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;