Commit 1a2c6181 authored by Christoph Paasch's avatar Christoph Paasch Committed by David S. Miller

tcp: Remove TCPCT

TCPCT uses option-number 253, reserved for experimental use and should
not be used in production environments.
Further, TCPCT does not fully implement RFC 6013.

As a nice side-effect, removing TCPCT increases TCP's performance for
very short flows:

Doing an apache-benchmark with -c 100 -n 100000, sending HTTP-requests
for files of 1KB size.

before this patch:
	average (among 7 runs) of 20845.5 Requests/Second
after:
	average (among 7 runs) of 21403.6 Requests/Second
Signed-off-by: default avatarChristoph Paasch <christoph.paasch@uclouvain.be>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 94d8f2b1
...@@ -175,14 +175,6 @@ tcp_congestion_control - STRING ...@@ -175,14 +175,6 @@ tcp_congestion_control - STRING
is inherited. is inherited.
[see setsockopt(listenfd, SOL_TCP, TCP_CONGESTION, "name" ...) ] [see setsockopt(listenfd, SOL_TCP, TCP_CONGESTION, "name" ...) ]
tcp_cookie_size - INTEGER
Default size of TCP Cookie Transactions (TCPCT) option, that may be
overridden on a per socket basis by the TCPCT socket option.
Values greater than the maximum (16) are interpreted as the maximum.
Values greater than zero and less than the minimum (8) are interpreted
as the minimum. Odd values are interpreted as the next even value.
Default: 0 (off).
tcp_dsack - BOOLEAN tcp_dsack - BOOLEAN
Allows TCP to send "duplicate" SACKs. Allows TCP to send "duplicate" SACKs.
......
...@@ -2915,7 +2915,7 @@ static void build_cpl_pass_accept_req(struct sk_buff *skb, int stid , u8 tos) ...@@ -2915,7 +2915,7 @@ static void build_cpl_pass_accept_req(struct sk_buff *skb, int stid , u8 tos)
*/ */
memset(&tmp_opt, 0, sizeof(tmp_opt)); memset(&tmp_opt, 0, sizeof(tmp_opt));
tcp_clear_options(&tmp_opt); tcp_clear_options(&tmp_opt);
tcp_parse_options(skb, &tmp_opt, NULL, 0, NULL); tcp_parse_options(skb, &tmp_opt, 0, NULL);
req = (struct cpl_pass_accept_req *)__skb_push(skb, sizeof(*req)); req = (struct cpl_pass_accept_req *)__skb_push(skb, sizeof(*req));
memset(req, 0, sizeof(*req)); memset(req, 0, sizeof(*req));
......
...@@ -90,9 +90,6 @@ struct tcp_options_received { ...@@ -90,9 +90,6 @@ struct tcp_options_received {
sack_ok : 4, /* SACK seen on SYN packet */ sack_ok : 4, /* SACK seen on SYN packet */
snd_wscale : 4, /* Window scaling received from sender */ snd_wscale : 4, /* Window scaling received from sender */
rcv_wscale : 4; /* Window scaling to send to receiver */ rcv_wscale : 4; /* Window scaling to send to receiver */
u8 cookie_plus:6, /* bytes in authenticator/cookie option */
cookie_out_never:1,
cookie_in_always:1;
u8 num_sacks; /* Number of SACK blocks */ u8 num_sacks; /* Number of SACK blocks */
u16 user_mss; /* mss requested by user in ioctl */ u16 user_mss; /* mss requested by user in ioctl */
u16 mss_clamp; /* Maximal mss, negotiated at connection setup */ u16 mss_clamp; /* Maximal mss, negotiated at connection setup */
...@@ -102,7 +99,6 @@ static inline void tcp_clear_options(struct tcp_options_received *rx_opt) ...@@ -102,7 +99,6 @@ static inline void tcp_clear_options(struct tcp_options_received *rx_opt)
{ {
rx_opt->tstamp_ok = rx_opt->sack_ok = 0; rx_opt->tstamp_ok = rx_opt->sack_ok = 0;
rx_opt->wscale_ok = rx_opt->snd_wscale = 0; rx_opt->wscale_ok = rx_opt->snd_wscale = 0;
rx_opt->cookie_plus = 0;
} }
/* This is the max number of SACKS that we'll generate and process. It's safe /* This is the max number of SACKS that we'll generate and process. It's safe
...@@ -320,12 +316,6 @@ struct tcp_sock { ...@@ -320,12 +316,6 @@ struct tcp_sock {
struct tcp_md5sig_info __rcu *md5sig_info; struct tcp_md5sig_info __rcu *md5sig_info;
#endif #endif
/* When the cookie options are generated and exchanged, then this
* object holds a reference to them (cookie_values->kref). Also
* contains related tcp_cookie_transactions fields.
*/
struct tcp_cookie_values *cookie_values;
/* TCP fastopen related information */ /* TCP fastopen related information */
struct tcp_fastopen_request *fastopen_req; struct tcp_fastopen_request *fastopen_req;
/* fastopen_rsk points to request_sock that resulted in this big /* fastopen_rsk points to request_sock that resulted in this big
......
...@@ -27,19 +27,13 @@ struct sk_buff; ...@@ -27,19 +27,13 @@ struct sk_buff;
struct dst_entry; struct dst_entry;
struct proto; struct proto;
/* empty to "strongly type" an otherwise void parameter.
*/
struct request_values {
};
struct request_sock_ops { struct request_sock_ops {
int family; int family;
int obj_size; int obj_size;
struct kmem_cache *slab; struct kmem_cache *slab;
char *slab_name; char *slab_name;
int (*rtx_syn_ack)(struct sock *sk, int (*rtx_syn_ack)(struct sock *sk,
struct request_sock *req, struct request_sock *req);
struct request_values *rvp);
void (*send_ack)(struct sock *sk, struct sk_buff *skb, void (*send_ack)(struct sock *sk, struct sk_buff *skb,
struct request_sock *req); struct request_sock *req);
void (*send_reset)(struct sock *sk, void (*send_reset)(struct sock *sk,
......
...@@ -179,7 +179,6 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo); ...@@ -179,7 +179,6 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);
#define TCPOPT_SACK 5 /* SACK Block */ #define TCPOPT_SACK 5 /* SACK Block */
#define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */ #define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */
#define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */ #define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */
#define TCPOPT_COOKIE 253 /* Cookie extension (experimental) */
#define TCPOPT_EXP 254 /* Experimental */ #define TCPOPT_EXP 254 /* Experimental */
/* Magic number to be after the option value for sharing TCP /* Magic number to be after the option value for sharing TCP
* experimental options. See draft-ietf-tcpm-experimental-options-00.txt * experimental options. See draft-ietf-tcpm-experimental-options-00.txt
...@@ -454,7 +453,7 @@ extern void tcp_syn_ack_timeout(struct sock *sk, struct request_sock *req); ...@@ -454,7 +453,7 @@ extern void tcp_syn_ack_timeout(struct sock *sk, struct request_sock *req);
extern int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, extern int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t len, int nonblock, int flags, int *addr_len); size_t len, int nonblock, int flags, int *addr_len);
extern void tcp_parse_options(const struct sk_buff *skb, extern void tcp_parse_options(const struct sk_buff *skb,
struct tcp_options_received *opt_rx, const u8 **hvpp, struct tcp_options_received *opt_rx,
int estab, struct tcp_fastopen_cookie *foc); int estab, struct tcp_fastopen_cookie *foc);
extern const u8 *tcp_parse_md5sig_option(const struct tcphdr *th); extern const u8 *tcp_parse_md5sig_option(const struct tcphdr *th);
...@@ -476,7 +475,6 @@ extern int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, ...@@ -476,7 +475,6 @@ extern int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr,
extern int tcp_connect(struct sock *sk); extern int tcp_connect(struct sock *sk);
extern struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, extern struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst,
struct request_sock *req, struct request_sock *req,
struct request_values *rvp,
struct tcp_fastopen_cookie *foc); struct tcp_fastopen_cookie *foc);
extern int tcp_disconnect(struct sock *sk, int flags); extern int tcp_disconnect(struct sock *sk, int flags);
...@@ -1589,91 +1587,6 @@ struct tcp_request_sock_ops { ...@@ -1589,91 +1587,6 @@ struct tcp_request_sock_ops {
#endif #endif
}; };
/* Using SHA1 for now, define some constants.
*/
#define COOKIE_DIGEST_WORDS (SHA_DIGEST_WORDS)
#define COOKIE_MESSAGE_WORDS (SHA_MESSAGE_BYTES / 4)
#define COOKIE_WORKSPACE_WORDS (COOKIE_DIGEST_WORDS + COOKIE_MESSAGE_WORDS)
extern int tcp_cookie_generator(u32 *bakery);
/**
* struct tcp_cookie_values - each socket needs extra space for the
* cookies, together with (optional) space for any SYN data.
*
* A tcp_sock contains a pointer to the current value, and this is
* cloned to the tcp_timewait_sock.
*
* @cookie_pair: variable data from the option exchange.
*
* @cookie_desired: user specified tcpct_cookie_desired. Zero
* indicates default (sysctl_tcp_cookie_size).
* After cookie sent, remembers size of cookie.
* Range 0, TCP_COOKIE_MIN to TCP_COOKIE_MAX.
*
* @s_data_desired: user specified tcpct_s_data_desired. When the
* constant payload is specified (@s_data_constant),
* holds its length instead.
* Range 0 to TCP_MSS_DESIRED.
*
* @s_data_payload: constant data that is to be included in the
* payload of SYN or SYNACK segments when the
* cookie option is present.
*/
struct tcp_cookie_values {
struct kref kref;
u8 cookie_pair[TCP_COOKIE_PAIR_SIZE];
u8 cookie_pair_size;
u8 cookie_desired;
u16 s_data_desired:11,
s_data_constant:1,
s_data_in:1,
s_data_out:1,
s_data_unused:2;
u8 s_data_payload[0];
};
static inline void tcp_cookie_values_release(struct kref *kref)
{
kfree(container_of(kref, struct tcp_cookie_values, kref));
}
/* The length of constant payload data. Note that s_data_desired is
* overloaded, depending on s_data_constant: either the length of constant
* data (returned here) or the limit on variable data.
*/
static inline int tcp_s_data_size(const struct tcp_sock *tp)
{
return (tp->cookie_values != NULL && tp->cookie_values->s_data_constant)
? tp->cookie_values->s_data_desired
: 0;
}
/**
* struct tcp_extend_values - tcp_ipv?.c to tcp_output.c workspace.
*
* As tcp_request_sock has already been extended in other places, the
* only remaining method is to pass stack values along as function
* parameters. These parameters are not needed after sending SYNACK.
*
* @cookie_bakery: cryptographic secret and message workspace.
*
* @cookie_plus: bytes in authenticator/cookie option, copied from
* struct tcp_options_received (above).
*/
struct tcp_extend_values {
struct request_values rv;
u32 cookie_bakery[COOKIE_WORKSPACE_WORDS];
u8 cookie_plus:6,
cookie_out_never:1,
cookie_in_always:1;
};
static inline struct tcp_extend_values *tcp_xv(struct request_values *rvp)
{
return (struct tcp_extend_values *)rvp;
}
extern void tcp_v4_init(void); extern void tcp_v4_init(void);
extern void tcp_init(void); extern void tcp_init(void);
......
...@@ -102,7 +102,6 @@ enum { ...@@ -102,7 +102,6 @@ enum {
#define TCP_QUICKACK 12 /* Block/reenable quick acks */ #define TCP_QUICKACK 12 /* Block/reenable quick acks */
#define TCP_CONGESTION 13 /* Congestion control algorithm */ #define TCP_CONGESTION 13 /* Congestion control algorithm */
#define TCP_MD5SIG 14 /* TCP MD5 Signature (RFC2385) */ #define TCP_MD5SIG 14 /* TCP MD5 Signature (RFC2385) */
#define TCP_COOKIE_TRANSACTIONS 15 /* TCP Cookie Transactions */
#define TCP_THIN_LINEAR_TIMEOUTS 16 /* Use linear timeouts for thin streams*/ #define TCP_THIN_LINEAR_TIMEOUTS 16 /* Use linear timeouts for thin streams*/
#define TCP_THIN_DUPACK 17 /* Fast retrans. after 1 dupack */ #define TCP_THIN_DUPACK 17 /* Fast retrans. after 1 dupack */
#define TCP_USER_TIMEOUT 18 /* How long for loss retry before timeout */ #define TCP_USER_TIMEOUT 18 /* How long for loss retry before timeout */
...@@ -199,29 +198,4 @@ struct tcp_md5sig { ...@@ -199,29 +198,4 @@ struct tcp_md5sig {
__u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* key (binary) */ __u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* key (binary) */
}; };
/* for TCP_COOKIE_TRANSACTIONS (TCPCT) socket option */
#define TCP_COOKIE_MIN 8 /* 64-bits */
#define TCP_COOKIE_MAX 16 /* 128-bits */
#define TCP_COOKIE_PAIR_SIZE (2*TCP_COOKIE_MAX)
/* Flags for both getsockopt and setsockopt */
#define TCP_COOKIE_IN_ALWAYS (1 << 0) /* Discard SYN without cookie */
#define TCP_COOKIE_OUT_NEVER (1 << 1) /* Prohibit outgoing cookies,
* supercedes everything. */
/* Flags for getsockopt */
#define TCP_S_DATA_IN (1 << 2) /* Was data received? */
#define TCP_S_DATA_OUT (1 << 3) /* Was data sent? */
/* TCP_COOKIE_TRANSACTIONS data */
struct tcp_cookie_transactions {
__u16 tcpct_flags; /* see above */
__u8 __tcpct_pad1; /* zero */
__u8 tcpct_cookie_desired; /* bytes */
__u16 tcpct_s_data_desired; /* bytes of variable data */
__u16 tcpct_used; /* bytes in value */
__u8 tcpct_value[TCP_MSS_DEFAULT];
};
#endif /* _UAPI_LINUX_TCP_H */ #endif /* _UAPI_LINUX_TCP_H */
...@@ -500,8 +500,7 @@ static struct dst_entry* dccp_v4_route_skb(struct net *net, struct sock *sk, ...@@ -500,8 +500,7 @@ static struct dst_entry* dccp_v4_route_skb(struct net *net, struct sock *sk,
return &rt->dst; return &rt->dst;
} }
static int dccp_v4_send_response(struct sock *sk, struct request_sock *req, static int dccp_v4_send_response(struct sock *sk, struct request_sock *req)
struct request_values *rv_unused)
{ {
int err = -1; int err = -1;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -658,7 +657,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) ...@@ -658,7 +657,7 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
dreq->dreq_gss = dreq->dreq_iss; dreq->dreq_gss = dreq->dreq_iss;
dreq->dreq_service = service; dreq->dreq_service = service;
if (dccp_v4_send_response(sk, req, NULL)) if (dccp_v4_send_response(sk, req))
goto drop_and_free; goto drop_and_free;
inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT); inet_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
......
...@@ -213,8 +213,7 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -213,8 +213,7 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
} }
static int dccp_v6_send_response(struct sock *sk, struct request_sock *req, static int dccp_v6_send_response(struct sock *sk, struct request_sock *req)
struct request_values *rv_unused)
{ {
struct inet6_request_sock *ireq6 = inet6_rsk(req); struct inet6_request_sock *ireq6 = inet6_rsk(req);
struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk);
...@@ -428,7 +427,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) ...@@ -428,7 +427,7 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
dreq->dreq_gss = dreq->dreq_iss; dreq->dreq_gss = dreq->dreq_iss;
dreq->dreq_service = service; dreq->dreq_service = service;
if (dccp_v6_send_response(sk, req, NULL)) if (dccp_v6_send_response(sk, req))
goto drop_and_free; goto drop_and_free;
inet6_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT); inet6_csk_reqsk_queue_hash_add(sk, req, DCCP_TIMEOUT_INIT);
......
...@@ -559,7 +559,7 @@ static inline void syn_ack_recalc(struct request_sock *req, const int thresh, ...@@ -559,7 +559,7 @@ static inline void syn_ack_recalc(struct request_sock *req, const int thresh,
int inet_rtx_syn_ack(struct sock *parent, struct request_sock *req) int inet_rtx_syn_ack(struct sock *parent, struct request_sock *req)
{ {
int err = req->rsk_ops->rtx_syn_ack(parent, req, NULL); int err = req->rsk_ops->rtx_syn_ack(parent, req);
if (!err) if (!err)
req->num_retrans++; req->num_retrans++;
......
...@@ -267,7 +267,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, ...@@ -267,7 +267,6 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
struct ip_options *opt) struct ip_options *opt)
{ {
struct tcp_options_received tcp_opt; struct tcp_options_received tcp_opt;
const u8 *hash_location;
struct inet_request_sock *ireq; struct inet_request_sock *ireq;
struct tcp_request_sock *treq; struct tcp_request_sock *treq;
struct tcp_sock *tp = tcp_sk(sk); struct tcp_sock *tp = tcp_sk(sk);
...@@ -294,7 +293,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb, ...@@ -294,7 +293,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
/* check for timestamp cookie support */ /* check for timestamp cookie support */
memset(&tcp_opt, 0, sizeof(tcp_opt)); memset(&tcp_opt, 0, sizeof(tcp_opt));
tcp_parse_options(skb, &tcp_opt, &hash_location, 0, NULL); tcp_parse_options(skb, &tcp_opt, 0, NULL);
if (!cookie_check_timestamp(&tcp_opt, sock_net(sk), &ecn_ok)) if (!cookie_check_timestamp(&tcp_opt, sock_net(sk), &ecn_ok))
goto out; goto out;
......
...@@ -732,13 +732,6 @@ static struct ctl_table ipv4_table[] = { ...@@ -732,13 +732,6 @@ static struct ctl_table ipv4_table[] = {
.mode = 0644, .mode = 0644,
.proc_handler = proc_dointvec, .proc_handler = proc_dointvec,
}, },
{
.procname = "tcp_cookie_size",
.data = &sysctl_tcp_cookie_size,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = proc_dointvec
},
{ {
.procname = "tcp_thin_linear_timeouts", .procname = "tcp_thin_linear_timeouts",
.data = &sysctl_tcp_thin_linear_timeouts, .data = &sysctl_tcp_thin_linear_timeouts,
......
...@@ -409,15 +409,6 @@ void tcp_init_sock(struct sock *sk) ...@@ -409,15 +409,6 @@ void tcp_init_sock(struct sock *sk)
icsk->icsk_sync_mss = tcp_sync_mss; icsk->icsk_sync_mss = tcp_sync_mss;
/* TCP Cookie Transactions */
if (sysctl_tcp_cookie_size > 0) {
/* Default, cookies without s_data_payload. */
tp->cookie_values =
kzalloc(sizeof(*tp->cookie_values),
sk->sk_allocation);
if (tp->cookie_values != NULL)
kref_init(&tp->cookie_values->kref);
}
/* Presumed zeroed, in order of appearance: /* Presumed zeroed, in order of appearance:
* cookie_in_always, cookie_out_never, * cookie_in_always, cookie_out_never,
* s_data_constant, s_data_in, s_data_out * s_data_constant, s_data_in, s_data_out
...@@ -2397,92 +2388,6 @@ static int do_tcp_setsockopt(struct sock *sk, int level, ...@@ -2397,92 +2388,6 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
release_sock(sk); release_sock(sk);
return err; return err;
} }
case TCP_COOKIE_TRANSACTIONS: {
struct tcp_cookie_transactions ctd;
struct tcp_cookie_values *cvp = NULL;
if (sizeof(ctd) > optlen)
return -EINVAL;
if (copy_from_user(&ctd, optval, sizeof(ctd)))
return -EFAULT;
if (ctd.tcpct_used > sizeof(ctd.tcpct_value) ||
ctd.tcpct_s_data_desired > TCP_MSS_DESIRED)
return -EINVAL;
if (ctd.tcpct_cookie_desired == 0) {
/* default to global value */
} else if ((0x1 & ctd.tcpct_cookie_desired) ||
ctd.tcpct_cookie_desired > TCP_COOKIE_MAX ||
ctd.tcpct_cookie_desired < TCP_COOKIE_MIN) {
return -EINVAL;
}
if (TCP_COOKIE_OUT_NEVER & ctd.tcpct_flags) {
/* Supercedes all other values */
lock_sock(sk);
if (tp->cookie_values != NULL) {
kref_put(&tp->cookie_values->kref,
tcp_cookie_values_release);
tp->cookie_values = NULL;
}
tp->rx_opt.cookie_in_always = 0; /* false */
tp->rx_opt.cookie_out_never = 1; /* true */
release_sock(sk);
return err;
}
/* Allocate ancillary memory before locking.
*/
if (ctd.tcpct_used > 0 ||
(tp->cookie_values == NULL &&
(sysctl_tcp_cookie_size > 0 ||
ctd.tcpct_cookie_desired > 0 ||
ctd.tcpct_s_data_desired > 0))) {
cvp = kzalloc(sizeof(*cvp) + ctd.tcpct_used,
GFP_KERNEL);
if (cvp == NULL)
return -ENOMEM;
kref_init(&cvp->kref);
}
lock_sock(sk);
tp->rx_opt.cookie_in_always =
(TCP_COOKIE_IN_ALWAYS & ctd.tcpct_flags);
tp->rx_opt.cookie_out_never = 0; /* false */
if (tp->cookie_values != NULL) {
if (cvp != NULL) {
/* Changed values are recorded by a changed
* pointer, ensuring the cookie will differ,
* without separately hashing each value later.
*/
kref_put(&tp->cookie_values->kref,
tcp_cookie_values_release);
} else {
cvp = tp->cookie_values;
}
}
if (cvp != NULL) {
cvp->cookie_desired = ctd.tcpct_cookie_desired;
if (ctd.tcpct_used > 0) {
memcpy(cvp->s_data_payload, ctd.tcpct_value,
ctd.tcpct_used);
cvp->s_data_desired = ctd.tcpct_used;
cvp->s_data_constant = 1; /* true */
} else {
/* No constant payload data. */
cvp->s_data_desired = ctd.tcpct_s_data_desired;
cvp->s_data_constant = 0; /* false */
}
tp->cookie_values = cvp;
}
release_sock(sk);
return err;
}
default: default:
/* fallthru */ /* fallthru */
break; break;
...@@ -2902,41 +2807,6 @@ static int do_tcp_getsockopt(struct sock *sk, int level, ...@@ -2902,41 +2807,6 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
return -EFAULT; return -EFAULT;
return 0; return 0;
case TCP_COOKIE_TRANSACTIONS: {
struct tcp_cookie_transactions ctd;
struct tcp_cookie_values *cvp = tp->cookie_values;
if (get_user(len, optlen))
return -EFAULT;
if (len < sizeof(ctd))
return -EINVAL;
memset(&ctd, 0, sizeof(ctd));
ctd.tcpct_flags = (tp->rx_opt.cookie_in_always ?
TCP_COOKIE_IN_ALWAYS : 0)
| (tp->rx_opt.cookie_out_never ?
TCP_COOKIE_OUT_NEVER : 0);
if (cvp != NULL) {
ctd.tcpct_flags |= (cvp->s_data_in ?
TCP_S_DATA_IN : 0)
| (cvp->s_data_out ?
TCP_S_DATA_OUT : 0);
ctd.tcpct_cookie_desired = cvp->cookie_desired;
ctd.tcpct_s_data_desired = cvp->s_data_desired;
memcpy(&ctd.tcpct_value[0], &cvp->cookie_pair[0],
cvp->cookie_pair_size);
ctd.tcpct_used = cvp->cookie_pair_size;
}
if (put_user(sizeof(ctd), optlen))
return -EFAULT;
if (copy_to_user(optval, &ctd, sizeof(ctd)))
return -EFAULT;
return 0;
}
case TCP_THIN_LINEAR_TIMEOUTS: case TCP_THIN_LINEAR_TIMEOUTS:
val = tp->thin_lto; val = tp->thin_lto;
break; break;
...@@ -3409,134 +3279,6 @@ EXPORT_SYMBOL(tcp_md5_hash_key); ...@@ -3409,134 +3279,6 @@ EXPORT_SYMBOL(tcp_md5_hash_key);
#endif #endif
/* Each Responder maintains up to two secret values concurrently for
* efficient secret rollover. Each secret value has 4 states:
*
* Generating. (tcp_secret_generating != tcp_secret_primary)
* Generates new Responder-Cookies, but not yet used for primary
* verification. This is a short-term state, typically lasting only
* one round trip time (RTT).
*
* Primary. (tcp_secret_generating == tcp_secret_primary)
* Used both for generation and primary verification.
*
* Retiring. (tcp_secret_retiring != tcp_secret_secondary)
* Used for verification, until the first failure that can be
* verified by the newer Generating secret. At that time, this
* cookie's state is changed to Secondary, and the Generating
* cookie's state is changed to Primary. This is a short-term state,
* typically lasting only one round trip time (RTT).
*
* Secondary. (tcp_secret_retiring == tcp_secret_secondary)
* Used for secondary verification, after primary verification
* failures. This state lasts no more than twice the Maximum Segment
* Lifetime (2MSL). Then, the secret is discarded.
*/
struct tcp_cookie_secret {
/* The secret is divided into two parts. The digest part is the
* equivalent of previously hashing a secret and saving the state,
* and serves as an initialization vector (IV). The message part
* serves as the trailing secret.
*/
u32 secrets[COOKIE_WORKSPACE_WORDS];
unsigned long expires;
};
#define TCP_SECRET_1MSL (HZ * TCP_PAWS_MSL)
#define TCP_SECRET_2MSL (HZ * TCP_PAWS_MSL * 2)
#define TCP_SECRET_LIFE (HZ * 600)
static struct tcp_cookie_secret tcp_secret_one;
static struct tcp_cookie_secret tcp_secret_two;
/* Essentially a circular list, without dynamic allocation. */
static struct tcp_cookie_secret *tcp_secret_generating;
static struct tcp_cookie_secret *tcp_secret_primary;
static struct tcp_cookie_secret *tcp_secret_retiring;
static struct tcp_cookie_secret *tcp_secret_secondary;
static DEFINE_SPINLOCK(tcp_secret_locker);
/* Select a pseudo-random word in the cookie workspace.
*/
static inline u32 tcp_cookie_work(const u32 *ws, const int n)
{
return ws[COOKIE_DIGEST_WORDS + ((COOKIE_MESSAGE_WORDS-1) & ws[n])];
}
/* Fill bakery[COOKIE_WORKSPACE_WORDS] with generator, updating as needed.
* Called in softirq context.
* Returns: 0 for success.
*/
int tcp_cookie_generator(u32 *bakery)
{
unsigned long jiffy = jiffies;
if (unlikely(time_after_eq(jiffy, tcp_secret_generating->expires))) {
spin_lock_bh(&tcp_secret_locker);
if (!time_after_eq(jiffy, tcp_secret_generating->expires)) {
/* refreshed by another */
memcpy(bakery,
&tcp_secret_generating->secrets[0],
COOKIE_WORKSPACE_WORDS);
} else {
/* still needs refreshing */
get_random_bytes(bakery, COOKIE_WORKSPACE_WORDS);
/* The first time, paranoia assumes that the
* randomization function isn't as strong. But,
* this secret initialization is delayed until
* the last possible moment (packet arrival).
* Although that time is observable, it is
* unpredictably variable. Mash in the most
* volatile clock bits available, and expire the
* secret extra quickly.
*/
if (unlikely(tcp_secret_primary->expires ==
tcp_secret_secondary->expires)) {
struct timespec tv;
getnstimeofday(&tv);
bakery[COOKIE_DIGEST_WORDS+0] ^=
(u32)tv.tv_nsec;
tcp_secret_secondary->expires = jiffy
+ TCP_SECRET_1MSL
+ (0x0f & tcp_cookie_work(bakery, 0));
} else {
tcp_secret_secondary->expires = jiffy
+ TCP_SECRET_LIFE
+ (0xff & tcp_cookie_work(bakery, 1));
tcp_secret_primary->expires = jiffy
+ TCP_SECRET_2MSL
+ (0x1f & tcp_cookie_work(bakery, 2));
}
memcpy(&tcp_secret_secondary->secrets[0],
bakery, COOKIE_WORKSPACE_WORDS);
rcu_assign_pointer(tcp_secret_generating,
tcp_secret_secondary);
rcu_assign_pointer(tcp_secret_retiring,
tcp_secret_primary);
/*
* Neither call_rcu() nor synchronize_rcu() needed.
* Retiring data is not freed. It is replaced after
* further (locked) pointer updates, and a quiet time
* (minimum 1MSL, maximum LIFE - 2MSL).
*/
}
spin_unlock_bh(&tcp_secret_locker);
} else {
rcu_read_lock_bh();
memcpy(bakery,
&rcu_dereference(tcp_secret_generating)->secrets[0],
COOKIE_WORKSPACE_WORDS);
rcu_read_unlock_bh();
}
return 0;
}
EXPORT_SYMBOL(tcp_cookie_generator);
void tcp_done(struct sock *sk) void tcp_done(struct sock *sk)
{ {
struct request_sock *req = tcp_sk(sk)->fastopen_rsk; struct request_sock *req = tcp_sk(sk)->fastopen_rsk;
...@@ -3591,7 +3333,6 @@ void __init tcp_init(void) ...@@ -3591,7 +3333,6 @@ void __init tcp_init(void)
unsigned long limit; unsigned long limit;
int max_rshare, max_wshare, cnt; int max_rshare, max_wshare, cnt;
unsigned int i; unsigned int i;
unsigned long jiffy = jiffies;
BUILD_BUG_ON(sizeof(struct tcp_skb_cb) > sizeof(skb->cb)); BUILD_BUG_ON(sizeof(struct tcp_skb_cb) > sizeof(skb->cb));
...@@ -3667,13 +3408,5 @@ void __init tcp_init(void) ...@@ -3667,13 +3408,5 @@ void __init tcp_init(void)
tcp_register_congestion_control(&tcp_reno); tcp_register_congestion_control(&tcp_reno);
memset(&tcp_secret_one.secrets[0], 0, sizeof(tcp_secret_one.secrets));
memset(&tcp_secret_two.secrets[0], 0, sizeof(tcp_secret_two.secrets));
tcp_secret_one.expires = jiffy; /* past due */
tcp_secret_two.expires = jiffy; /* past due */
tcp_secret_generating = &tcp_secret_one;
tcp_secret_primary = &tcp_secret_one;
tcp_secret_retiring = &tcp_secret_two;
tcp_secret_secondary = &tcp_secret_two;
tcp_tasklet_init(); tcp_tasklet_init();
} }
...@@ -3760,8 +3760,8 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) ...@@ -3760,8 +3760,8 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
* But, this can also be called on packets in the established flow when * But, this can also be called on packets in the established flow when
* the fast version below fails. * the fast version below fails.
*/ */
void tcp_parse_options(const struct sk_buff *skb, struct tcp_options_received *opt_rx, void tcp_parse_options(const struct sk_buff *skb,
const u8 **hvpp, int estab, struct tcp_options_received *opt_rx, int estab,
struct tcp_fastopen_cookie *foc) struct tcp_fastopen_cookie *foc)
{ {
const unsigned char *ptr; const unsigned char *ptr;
...@@ -3845,31 +3845,6 @@ void tcp_parse_options(const struct sk_buff *skb, struct tcp_options_received *o ...@@ -3845,31 +3845,6 @@ void tcp_parse_options(const struct sk_buff *skb, struct tcp_options_received *o
*/ */
break; break;
#endif #endif
case TCPOPT_COOKIE:
/* This option is variable length.
*/
switch (opsize) {
case TCPOLEN_COOKIE_BASE:
/* not yet implemented */
break;
case TCPOLEN_COOKIE_PAIR:
/* not yet implemented */
break;
case TCPOLEN_COOKIE_MIN+0:
case TCPOLEN_COOKIE_MIN+2:
case TCPOLEN_COOKIE_MIN+4:
case TCPOLEN_COOKIE_MIN+6:
case TCPOLEN_COOKIE_MAX:
/* 16-bit multiple */
opt_rx->cookie_plus = opsize;
*hvpp = ptr;
break;
default:
/* ignore option */
break;
}
break;
case TCPOPT_EXP: case TCPOPT_EXP:
/* Fast Open option shares code 254 using a /* Fast Open option shares code 254 using a
* 16 bits magic number. It's valid only in * 16 bits magic number. It's valid only in
...@@ -3915,8 +3890,7 @@ static bool tcp_parse_aligned_timestamp(struct tcp_sock *tp, const struct tcphdr ...@@ -3915,8 +3890,7 @@ static bool tcp_parse_aligned_timestamp(struct tcp_sock *tp, const struct tcphdr
* If it is wrong it falls back on tcp_parse_options(). * If it is wrong it falls back on tcp_parse_options().
*/ */
static bool tcp_fast_parse_options(const struct sk_buff *skb, static bool tcp_fast_parse_options(const struct sk_buff *skb,
const struct tcphdr *th, const struct tcphdr *th, struct tcp_sock *tp)
struct tcp_sock *tp, const u8 **hvpp)
{ {
/* In the spirit of fast parsing, compare doff directly to constant /* In the spirit of fast parsing, compare doff directly to constant
* values. Because equality is used, short doff can be ignored here. * values. Because equality is used, short doff can be ignored here.
...@@ -3930,7 +3904,7 @@ static bool tcp_fast_parse_options(const struct sk_buff *skb, ...@@ -3930,7 +3904,7 @@ static bool tcp_fast_parse_options(const struct sk_buff *skb,
return true; return true;
} }
tcp_parse_options(skb, &tp->rx_opt, hvpp, 1, NULL); tcp_parse_options(skb, &tp->rx_opt, 1, NULL);
if (tp->rx_opt.saw_tstamp) if (tp->rx_opt.saw_tstamp)
tp->rx_opt.rcv_tsecr -= tp->tsoffset; tp->rx_opt.rcv_tsecr -= tp->tsoffset;
...@@ -5311,12 +5285,10 @@ static bool tcp_dma_try_early_copy(struct sock *sk, struct sk_buff *skb, ...@@ -5311,12 +5285,10 @@ static bool tcp_dma_try_early_copy(struct sock *sk, struct sk_buff *skb,
static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,
const struct tcphdr *th, int syn_inerr) const struct tcphdr *th, int syn_inerr)
{ {
const u8 *hash_location;
struct tcp_sock *tp = tcp_sk(sk); struct tcp_sock *tp = tcp_sk(sk);
/* RFC1323: H1. Apply PAWS check first. */ /* RFC1323: H1. Apply PAWS check first. */
if (tcp_fast_parse_options(skb, th, tp, &hash_location) && if (tcp_fast_parse_options(skb, th, tp) && tp->rx_opt.saw_tstamp &&
tp->rx_opt.saw_tstamp &&
tcp_paws_discard(sk, skb)) { tcp_paws_discard(sk, skb)) {
if (!th->rst) { if (!th->rst) {
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED); NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED);
...@@ -5670,12 +5642,11 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack, ...@@ -5670,12 +5642,11 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack,
if (mss == tp->rx_opt.user_mss) { if (mss == tp->rx_opt.user_mss) {
struct tcp_options_received opt; struct tcp_options_received opt;
const u8 *hash_location;
/* Get original SYNACK MSS value if user MSS sets mss_clamp */ /* Get original SYNACK MSS value if user MSS sets mss_clamp */
tcp_clear_options(&opt); tcp_clear_options(&opt);
opt.user_mss = opt.mss_clamp = 0; opt.user_mss = opt.mss_clamp = 0;
tcp_parse_options(synack, &opt, &hash_location, 0, NULL); tcp_parse_options(synack, &opt, 0, NULL);
mss = opt.mss_clamp; mss = opt.mss_clamp;
} }
...@@ -5706,14 +5677,12 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack, ...@@ -5706,14 +5677,12 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack,
static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
const struct tcphdr *th, unsigned int len) const struct tcphdr *th, unsigned int len)
{ {
const u8 *hash_location;
struct inet_connection_sock *icsk = inet_csk(sk); struct inet_connection_sock *icsk = inet_csk(sk);
struct tcp_sock *tp = tcp_sk(sk); struct tcp_sock *tp = tcp_sk(sk);
struct tcp_cookie_values *cvp = tp->cookie_values;
struct tcp_fastopen_cookie foc = { .len = -1 }; struct tcp_fastopen_cookie foc = { .len = -1 };
int saved_clamp = tp->rx_opt.mss_clamp; int saved_clamp = tp->rx_opt.mss_clamp;
tcp_parse_options(skb, &tp->rx_opt, &hash_location, 0, &foc); tcp_parse_options(skb, &tp->rx_opt, 0, &foc);
if (tp->rx_opt.saw_tstamp) if (tp->rx_opt.saw_tstamp)
tp->rx_opt.rcv_tsecr -= tp->tsoffset; tp->rx_opt.rcv_tsecr -= tp->tsoffset;
...@@ -5810,30 +5779,6 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, ...@@ -5810,30 +5779,6 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
* is initialized. */ * is initialized. */
tp->copied_seq = tp->rcv_nxt; tp->copied_seq = tp->rcv_nxt;
if (cvp != NULL &&
cvp->cookie_pair_size > 0 &&
tp->rx_opt.cookie_plus > 0) {
int cookie_size = tp->rx_opt.cookie_plus
- TCPOLEN_COOKIE_BASE;
int cookie_pair_size = cookie_size
+ cvp->cookie_desired;
/* A cookie extension option was sent and returned.
* Note that each incoming SYNACK replaces the
* Responder cookie. The initial exchange is most
* fragile, as protection against spoofing relies
* entirely upon the sequence and timestamp (above).
* This replacement strategy allows the correct pair to
* pass through, while any others will be filtered via
* Responder verification later.
*/
if (sizeof(cvp->cookie_pair) >= cookie_pair_size) {
memcpy(&cvp->cookie_pair[cvp->cookie_desired],
hash_location, cookie_size);
cvp->cookie_pair_size = cookie_pair_size;
}
}
smp_mb(); smp_mb();
tcp_finish_connect(sk, skb); tcp_finish_connect(sk, skb);
......
...@@ -838,7 +838,6 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, ...@@ -838,7 +838,6 @@ static void tcp_v4_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
*/ */
static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst, static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
struct request_sock *req, struct request_sock *req,
struct request_values *rvp,
u16 queue_mapping, u16 queue_mapping,
bool nocache) bool nocache)
{ {
...@@ -851,7 +850,7 @@ static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst, ...@@ -851,7 +850,7 @@ static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
if (!dst && (dst = inet_csk_route_req(sk, &fl4, req)) == NULL) if (!dst && (dst = inet_csk_route_req(sk, &fl4, req)) == NULL)
return -1; return -1;
skb = tcp_make_synack(sk, dst, req, rvp, NULL); skb = tcp_make_synack(sk, dst, req, NULL);
if (skb) { if (skb) {
__tcp_v4_send_check(skb, ireq->loc_addr, ireq->rmt_addr); __tcp_v4_send_check(skb, ireq->loc_addr, ireq->rmt_addr);
...@@ -868,10 +867,9 @@ static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst, ...@@ -868,10 +867,9 @@ static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
return err; return err;
} }
static int tcp_v4_rtx_synack(struct sock *sk, struct request_sock *req, static int tcp_v4_rtx_synack(struct sock *sk, struct request_sock *req)
struct request_values *rvp)
{ {
int res = tcp_v4_send_synack(sk, NULL, req, rvp, 0, false); int res = tcp_v4_send_synack(sk, NULL, req, 0, false);
if (!res) if (!res)
TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);
...@@ -1371,8 +1369,7 @@ static bool tcp_fastopen_check(struct sock *sk, struct sk_buff *skb, ...@@ -1371,8 +1369,7 @@ static bool tcp_fastopen_check(struct sock *sk, struct sk_buff *skb,
static int tcp_v4_conn_req_fastopen(struct sock *sk, static int tcp_v4_conn_req_fastopen(struct sock *sk,
struct sk_buff *skb, struct sk_buff *skb,
struct sk_buff *skb_synack, struct sk_buff *skb_synack,
struct request_sock *req, struct request_sock *req)
struct request_values *rvp)
{ {
struct tcp_sock *tp = tcp_sk(sk); struct tcp_sock *tp = tcp_sk(sk);
struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue; struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue;
...@@ -1467,9 +1464,7 @@ static int tcp_v4_conn_req_fastopen(struct sock *sk, ...@@ -1467,9 +1464,7 @@ static int tcp_v4_conn_req_fastopen(struct sock *sk,
int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
{ {
struct tcp_extend_values tmp_ext;
struct tcp_options_received tmp_opt; struct tcp_options_received tmp_opt;
const u8 *hash_location;
struct request_sock *req; struct request_sock *req;
struct inet_request_sock *ireq; struct inet_request_sock *ireq;
struct tcp_sock *tp = tcp_sk(sk); struct tcp_sock *tp = tcp_sk(sk);
...@@ -1519,42 +1514,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) ...@@ -1519,42 +1514,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
tcp_clear_options(&tmp_opt); tcp_clear_options(&tmp_opt);
tmp_opt.mss_clamp = TCP_MSS_DEFAULT; tmp_opt.mss_clamp = TCP_MSS_DEFAULT;
tmp_opt.user_mss = tp->rx_opt.user_mss; tmp_opt.user_mss = tp->rx_opt.user_mss;
tcp_parse_options(skb, &tmp_opt, &hash_location, 0, tcp_parse_options(skb, &tmp_opt, 0, want_cookie ? NULL : &foc);
want_cookie ? NULL : &foc);
if (tmp_opt.cookie_plus > 0 &&
tmp_opt.saw_tstamp &&
!tp->rx_opt.cookie_out_never &&
(sysctl_tcp_cookie_size > 0 ||
(tp->cookie_values != NULL &&
tp->cookie_values->cookie_desired > 0))) {
u8 *c;
u32 *mess = &tmp_ext.cookie_bakery[COOKIE_DIGEST_WORDS];
int l = tmp_opt.cookie_plus - TCPOLEN_COOKIE_BASE;
if (tcp_cookie_generator(&tmp_ext.cookie_bakery[0]) != 0)
goto drop_and_release;
/* Secret recipe starts with IP addresses */
*mess++ ^= (__force u32)daddr;
*mess++ ^= (__force u32)saddr;
/* plus variable length Initiator Cookie */
c = (u8 *)mess;
while (l-- > 0)
*c++ ^= *hash_location++;
want_cookie = false; /* not our kind of cookie */
tmp_ext.cookie_out_never = 0; /* false */
tmp_ext.cookie_plus = tmp_opt.cookie_plus;
} else if (!tp->rx_opt.cookie_in_always) {
/* redundant indications, but ensure initialization. */
tmp_ext.cookie_out_never = 1; /* true */
tmp_ext.cookie_plus = 0;
} else {
goto drop_and_release;
}
tmp_ext.cookie_in_always = tp->rx_opt.cookie_in_always;
if (want_cookie && !tmp_opt.saw_tstamp) if (want_cookie && !tmp_opt.saw_tstamp)
tcp_clear_options(&tmp_opt); tcp_clear_options(&tmp_opt);
...@@ -1636,7 +1596,6 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) ...@@ -1636,7 +1596,6 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
* of tcp_v4_send_synack()->tcp_select_initial_window(). * of tcp_v4_send_synack()->tcp_select_initial_window().
*/ */
skb_synack = tcp_make_synack(sk, dst, req, skb_synack = tcp_make_synack(sk, dst, req,
(struct request_values *)&tmp_ext,
fastopen_cookie_present(&valid_foc) ? &valid_foc : NULL); fastopen_cookie_present(&valid_foc) ? &valid_foc : NULL);
if (skb_synack) { if (skb_synack) {
...@@ -1660,8 +1619,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) ...@@ -1660,8 +1619,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
if (fastopen_cookie_present(&foc) && foc.len != 0) if (fastopen_cookie_present(&foc) && foc.len != 0)
NET_INC_STATS_BH(sock_net(sk), NET_INC_STATS_BH(sock_net(sk),
LINUX_MIB_TCPFASTOPENPASSIVEFAIL); LINUX_MIB_TCPFASTOPENPASSIVEFAIL);
} else if (tcp_v4_conn_req_fastopen(sk, skb, skb_synack, req, } else if (tcp_v4_conn_req_fastopen(sk, skb, skb_synack, req))
(struct request_values *)&tmp_ext))
goto drop_and_free; goto drop_and_free;
return 0; return 0;
...@@ -2241,12 +2199,6 @@ void tcp_v4_destroy_sock(struct sock *sk) ...@@ -2241,12 +2199,6 @@ void tcp_v4_destroy_sock(struct sock *sk)
if (inet_csk(sk)->icsk_bind_hash) if (inet_csk(sk)->icsk_bind_hash)
inet_put_port(sk); inet_put_port(sk);
/* TCP Cookie Transactions */
if (tp->cookie_values != NULL) {
kref_put(&tp->cookie_values->kref,
tcp_cookie_values_release);
tp->cookie_values = NULL;
}
BUG_ON(tp->fastopen_rsk != NULL); BUG_ON(tp->fastopen_rsk != NULL);
/* If socket is aborted during connect operation */ /* If socket is aborted during connect operation */
......
...@@ -93,13 +93,12 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb, ...@@ -93,13 +93,12 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
const struct tcphdr *th) const struct tcphdr *th)
{ {
struct tcp_options_received tmp_opt; struct tcp_options_received tmp_opt;
const u8 *hash_location;
struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw); struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
bool paws_reject = false; bool paws_reject = false;
tmp_opt.saw_tstamp = 0; tmp_opt.saw_tstamp = 0;
if (th->doff > (sizeof(*th) >> 2) && tcptw->tw_ts_recent_stamp) { if (th->doff > (sizeof(*th) >> 2) && tcptw->tw_ts_recent_stamp) {
tcp_parse_options(skb, &tmp_opt, &hash_location, 0, NULL); tcp_parse_options(skb, &tmp_opt, 0, NULL);
if (tmp_opt.saw_tstamp) { if (tmp_opt.saw_tstamp) {
tmp_opt.rcv_tsecr -= tcptw->tw_ts_offset; tmp_opt.rcv_tsecr -= tcptw->tw_ts_offset;
...@@ -388,32 +387,6 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, ...@@ -388,32 +387,6 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
struct tcp_request_sock *treq = tcp_rsk(req); struct tcp_request_sock *treq = tcp_rsk(req);
struct inet_connection_sock *newicsk = inet_csk(newsk); struct inet_connection_sock *newicsk = inet_csk(newsk);
struct tcp_sock *newtp = tcp_sk(newsk); struct tcp_sock *newtp = tcp_sk(newsk);
struct tcp_sock *oldtp = tcp_sk(sk);
struct tcp_cookie_values *oldcvp = oldtp->cookie_values;
/* TCP Cookie Transactions require space for the cookie pair,
* as it differs for each connection. There is no need to
* copy any s_data_payload stored at the original socket.
* Failure will prevent resuming the connection.
*
* Presumed copied, in order of appearance:
* cookie_in_always, cookie_out_never
*/
if (oldcvp != NULL) {
struct tcp_cookie_values *newcvp =
kzalloc(sizeof(*newtp->cookie_values),
GFP_ATOMIC);
if (newcvp != NULL) {
kref_init(&newcvp->kref);
newcvp->cookie_desired =
oldcvp->cookie_desired;
newtp->cookie_values = newcvp;
} else {
/* Not Yet Implemented */
newtp->cookie_values = NULL;
}
}
/* Now setup tcp_sock */ /* Now setup tcp_sock */
newtp->pred_flags = 0; newtp->pred_flags = 0;
...@@ -422,8 +395,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, ...@@ -422,8 +395,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
newtp->rcv_nxt = treq->rcv_isn + 1; newtp->rcv_nxt = treq->rcv_isn + 1;
newtp->snd_sml = newtp->snd_una = newtp->snd_sml = newtp->snd_una =
newtp->snd_nxt = newtp->snd_up = newtp->snd_nxt = newtp->snd_up = treq->snt_isn + 1;
treq->snt_isn + 1 + tcp_s_data_size(oldtp);
tcp_prequeue_init(newtp); tcp_prequeue_init(newtp);
INIT_LIST_HEAD(&newtp->tsq_node); INIT_LIST_HEAD(&newtp->tsq_node);
...@@ -460,8 +432,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, ...@@ -460,8 +432,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
tcp_set_ca_state(newsk, TCP_CA_Open); tcp_set_ca_state(newsk, TCP_CA_Open);
tcp_init_xmit_timers(newsk); tcp_init_xmit_timers(newsk);
skb_queue_head_init(&newtp->out_of_order_queue); skb_queue_head_init(&newtp->out_of_order_queue);
newtp->write_seq = newtp->pushed_seq = newtp->write_seq = newtp->pushed_seq = treq->snt_isn + 1;
treq->snt_isn + 1 + tcp_s_data_size(oldtp);
newtp->rx_opt.saw_tstamp = 0; newtp->rx_opt.saw_tstamp = 0;
...@@ -538,7 +509,6 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, ...@@ -538,7 +509,6 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
bool fastopen) bool fastopen)
{ {
struct tcp_options_received tmp_opt; struct tcp_options_received tmp_opt;
const u8 *hash_location;
struct sock *child; struct sock *child;
const struct tcphdr *th = tcp_hdr(skb); const struct tcphdr *th = tcp_hdr(skb);
__be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK); __be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK);
...@@ -548,7 +518,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, ...@@ -548,7 +518,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
tmp_opt.saw_tstamp = 0; tmp_opt.saw_tstamp = 0;
if (th->doff > (sizeof(struct tcphdr)>>2)) { if (th->doff > (sizeof(struct tcphdr)>>2)) {
tcp_parse_options(skb, &tmp_opt, &hash_location, 0, NULL); tcp_parse_options(skb, &tmp_opt, 0, NULL);
if (tmp_opt.saw_tstamp) { if (tmp_opt.saw_tstamp) {
tmp_opt.ts_recent = req->ts_recent; tmp_opt.ts_recent = req->ts_recent;
...@@ -648,7 +618,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, ...@@ -648,7 +618,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
*/ */
if ((flg & TCP_FLAG_ACK) && !fastopen && if ((flg & TCP_FLAG_ACK) && !fastopen &&
(TCP_SKB_CB(skb)->ack_seq != (TCP_SKB_CB(skb)->ack_seq !=
tcp_rsk(req)->snt_isn + 1 + tcp_s_data_size(tcp_sk(sk)))) tcp_rsk(req)->snt_isn + 1))
return sk; return sk;
/* Also, it would be not so bad idea to check rcv_tsecr, which /* Also, it would be not so bad idea to check rcv_tsecr, which
......
This diff is collapsed.
...@@ -149,7 +149,6 @@ static inline int cookie_check(const struct sk_buff *skb, __u32 cookie) ...@@ -149,7 +149,6 @@ static inline int cookie_check(const struct sk_buff *skb, __u32 cookie)
struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
{ {
struct tcp_options_received tcp_opt; struct tcp_options_received tcp_opt;
const u8 *hash_location;
struct inet_request_sock *ireq; struct inet_request_sock *ireq;
struct inet6_request_sock *ireq6; struct inet6_request_sock *ireq6;
struct tcp_request_sock *treq; struct tcp_request_sock *treq;
...@@ -177,7 +176,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) ...@@ -177,7 +176,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
/* check for timestamp cookie support */ /* check for timestamp cookie support */
memset(&tcp_opt, 0, sizeof(tcp_opt)); memset(&tcp_opt, 0, sizeof(tcp_opt));
tcp_parse_options(skb, &tcp_opt, &hash_location, 0, NULL); tcp_parse_options(skb, &tcp_opt, 0, NULL);
if (!cookie_check_timestamp(&tcp_opt, sock_net(sk), &ecn_ok)) if (!cookie_check_timestamp(&tcp_opt, sock_net(sk), &ecn_ok))
goto out; goto out;
......
...@@ -454,7 +454,6 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -454,7 +454,6 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst, static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst,
struct flowi6 *fl6, struct flowi6 *fl6,
struct request_sock *req, struct request_sock *req,
struct request_values *rvp,
u16 queue_mapping) u16 queue_mapping)
{ {
struct inet6_request_sock *treq = inet6_rsk(req); struct inet6_request_sock *treq = inet6_rsk(req);
...@@ -466,7 +465,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst, ...@@ -466,7 +465,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst,
if (!dst && (dst = inet6_csk_route_req(sk, fl6, req)) == NULL) if (!dst && (dst = inet6_csk_route_req(sk, fl6, req)) == NULL)
goto done; goto done;
skb = tcp_make_synack(sk, dst, req, rvp, NULL); skb = tcp_make_synack(sk, dst, req, NULL);
if (skb) { if (skb) {
__tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr); __tcp_v6_send_check(skb, &treq->loc_addr, &treq->rmt_addr);
...@@ -481,13 +480,12 @@ static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst, ...@@ -481,13 +480,12 @@ static int tcp_v6_send_synack(struct sock *sk, struct dst_entry *dst,
return err; return err;
} }
static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req, static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req)
struct request_values *rvp)
{ {
struct flowi6 fl6; struct flowi6 fl6;
int res; int res;
res = tcp_v6_send_synack(sk, NULL, &fl6, req, rvp, 0); res = tcp_v6_send_synack(sk, NULL, &fl6, req, 0);
if (!res) if (!res)
TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS); TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_RETRANSSEGS);
return res; return res;
...@@ -940,9 +938,7 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb) ...@@ -940,9 +938,7 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
*/ */
static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
{ {
struct tcp_extend_values tmp_ext;
struct tcp_options_received tmp_opt; struct tcp_options_received tmp_opt;
const u8 *hash_location;
struct request_sock *req; struct request_sock *req;
struct inet6_request_sock *treq; struct inet6_request_sock *treq;
struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk);
...@@ -980,50 +976,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) ...@@ -980,50 +976,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
tcp_clear_options(&tmp_opt); tcp_clear_options(&tmp_opt);
tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); tmp_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr);
tmp_opt.user_mss = tp->rx_opt.user_mss; tmp_opt.user_mss = tp->rx_opt.user_mss;
tcp_parse_options(skb, &tmp_opt, &hash_location, 0, NULL); tcp_parse_options(skb, &tmp_opt, 0, NULL);
if (tmp_opt.cookie_plus > 0 &&
tmp_opt.saw_tstamp &&
!tp->rx_opt.cookie_out_never &&
(sysctl_tcp_cookie_size > 0 ||
(tp->cookie_values != NULL &&
tp->cookie_values->cookie_desired > 0))) {
u8 *c;
u32 *d;
u32 *mess = &tmp_ext.cookie_bakery[COOKIE_DIGEST_WORDS];
int l = tmp_opt.cookie_plus - TCPOLEN_COOKIE_BASE;
if (tcp_cookie_generator(&tmp_ext.cookie_bakery[0]) != 0)
goto drop_and_free;
/* Secret recipe starts with IP addresses */
d = (__force u32 *)&ipv6_hdr(skb)->daddr.s6_addr32[0];
*mess++ ^= *d++;
*mess++ ^= *d++;
*mess++ ^= *d++;
*mess++ ^= *d++;
d = (__force u32 *)&ipv6_hdr(skb)->saddr.s6_addr32[0];
*mess++ ^= *d++;
*mess++ ^= *d++;
*mess++ ^= *d++;
*mess++ ^= *d++;
/* plus variable length Initiator Cookie */
c = (u8 *)mess;
while (l-- > 0)
*c++ ^= *hash_location++;
want_cookie = false; /* not our kind of cookie */
tmp_ext.cookie_out_never = 0; /* false */
tmp_ext.cookie_plus = tmp_opt.cookie_plus;
} else if (!tp->rx_opt.cookie_in_always) {
/* redundant indications, but ensure initialization. */
tmp_ext.cookie_out_never = 1; /* true */
tmp_ext.cookie_plus = 0;
} else {
goto drop_and_free;
}
tmp_ext.cookie_in_always = tp->rx_opt.cookie_in_always;
if (want_cookie && !tmp_opt.saw_tstamp) if (want_cookie && !tmp_opt.saw_tstamp)
tcp_clear_options(&tmp_opt); tcp_clear_options(&tmp_opt);
...@@ -1101,7 +1054,6 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) ...@@ -1101,7 +1054,6 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
goto drop_and_release; goto drop_and_release;
if (tcp_v6_send_synack(sk, dst, &fl6, req, if (tcp_v6_send_synack(sk, dst, &fl6, req,
(struct request_values *)&tmp_ext,
skb_get_queue_mapping(skb)) || skb_get_queue_mapping(skb)) ||
want_cookie) want_cookie)
goto drop_and_free; goto drop_and_free;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment