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: Christoph Paasch <christoph.paasch@uclouvain.be> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
94d8f2b133
commit
1a2c6181c4
18 changed files with 37 additions and 840 deletions
|
@ -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)
|
||||||
*/
|
*/
|
||||||
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 {
|
||||||
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)
|
||||||
{
|
{
|
||||||
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 {
|
||||||
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;
|
||||||
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);
|
||||||
#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);
|
||||||
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,
|
||||||
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 {
|
||||||
#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 {
|
||||||
#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 {
|
||||||
__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,
|
||||||
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)
|
||||||
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 @@ out:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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)
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
/* 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[] = {
|
||||||
.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,
|
||||||
|
|
267
net/ipv4/tcp.c
267
net/ipv4/tcp.c
|
@ -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,
|
||||||
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,
|
||||||
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);
|
||||||
|
|
||||||
#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)
|
||||||
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)
|
||||||
|
|
||||||
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 @@ old_ack:
|
||||||
* 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
|
||||||
*/
|
*/
|
||||||
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
|
||||||
* 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,
|
||||||
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 @@ out:
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
* 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,
|
||||||
*/
|
*/
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
* 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)
|
||||||
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)
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
*/
|
*/
|
||||||
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
|
||||||
|
|
|
@ -65,9 +65,6 @@ int sysctl_tcp_base_mss __read_mostly = TCP_BASE_MSS;
|
||||||
/* By default, RFC2861 behavior. */
|
/* By default, RFC2861 behavior. */
|
||||||
int sysctl_tcp_slow_start_after_idle __read_mostly = 1;
|
int sysctl_tcp_slow_start_after_idle __read_mostly = 1;
|
||||||
|
|
||||||
int sysctl_tcp_cookie_size __read_mostly = 0; /* TCP_COOKIE_MAX */
|
|
||||||
EXPORT_SYMBOL_GPL(sysctl_tcp_cookie_size);
|
|
||||||
|
|
||||||
static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
|
static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle,
|
||||||
int push_one, gfp_t gfp);
|
int push_one, gfp_t gfp);
|
||||||
|
|
||||||
|
@ -386,7 +383,6 @@ static inline bool tcp_urg_mode(const struct tcp_sock *tp)
|
||||||
#define OPTION_TS (1 << 1)
|
#define OPTION_TS (1 << 1)
|
||||||
#define OPTION_MD5 (1 << 2)
|
#define OPTION_MD5 (1 << 2)
|
||||||
#define OPTION_WSCALE (1 << 3)
|
#define OPTION_WSCALE (1 << 3)
|
||||||
#define OPTION_COOKIE_EXTENSION (1 << 4)
|
|
||||||
#define OPTION_FAST_OPEN_COOKIE (1 << 8)
|
#define OPTION_FAST_OPEN_COOKIE (1 << 8)
|
||||||
|
|
||||||
struct tcp_out_options {
|
struct tcp_out_options {
|
||||||
|
@ -400,36 +396,6 @@ struct tcp_out_options {
|
||||||
struct tcp_fastopen_cookie *fastopen_cookie; /* Fast open cookie */
|
struct tcp_fastopen_cookie *fastopen_cookie; /* Fast open cookie */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The sysctl int routines are generic, so check consistency here.
|
|
||||||
*/
|
|
||||||
static u8 tcp_cookie_size_check(u8 desired)
|
|
||||||
{
|
|
||||||
int cookie_size;
|
|
||||||
|
|
||||||
if (desired > 0)
|
|
||||||
/* previously specified */
|
|
||||||
return desired;
|
|
||||||
|
|
||||||
cookie_size = ACCESS_ONCE(sysctl_tcp_cookie_size);
|
|
||||||
if (cookie_size <= 0)
|
|
||||||
/* no default specified */
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (cookie_size <= TCP_COOKIE_MIN)
|
|
||||||
/* value too small, specify minimum */
|
|
||||||
return TCP_COOKIE_MIN;
|
|
||||||
|
|
||||||
if (cookie_size >= TCP_COOKIE_MAX)
|
|
||||||
/* value too large, specify maximum */
|
|
||||||
return TCP_COOKIE_MAX;
|
|
||||||
|
|
||||||
if (cookie_size & 1)
|
|
||||||
/* 8-bit multiple, illegal, fix it */
|
|
||||||
cookie_size++;
|
|
||||||
|
|
||||||
return (u8)cookie_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write previously computed TCP options to the packet.
|
/* Write previously computed TCP options to the packet.
|
||||||
*
|
*
|
||||||
* Beware: Something in the Internet is very sensitive to the ordering of
|
* Beware: Something in the Internet is very sensitive to the ordering of
|
||||||
|
@ -448,27 +414,9 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
|
||||||
{
|
{
|
||||||
u16 options = opts->options; /* mungable copy */
|
u16 options = opts->options; /* mungable copy */
|
||||||
|
|
||||||
/* Having both authentication and cookies for security is redundant,
|
|
||||||
* and there's certainly not enough room. Instead, the cookie-less
|
|
||||||
* extension variant is proposed.
|
|
||||||
*
|
|
||||||
* Consider the pessimal case with authentication. The options
|
|
||||||
* could look like:
|
|
||||||
* COOKIE|MD5(20) + MSS(4) + SACK|TS(12) + WSCALE(4) == 40
|
|
||||||
*/
|
|
||||||
if (unlikely(OPTION_MD5 & options)) {
|
if (unlikely(OPTION_MD5 & options)) {
|
||||||
if (unlikely(OPTION_COOKIE_EXTENSION & options)) {
|
*ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
|
||||||
*ptr++ = htonl((TCPOPT_COOKIE << 24) |
|
(TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG);
|
||||||
(TCPOLEN_COOKIE_BASE << 16) |
|
|
||||||
(TCPOPT_MD5SIG << 8) |
|
|
||||||
TCPOLEN_MD5SIG);
|
|
||||||
} else {
|
|
||||||
*ptr++ = htonl((TCPOPT_NOP << 24) |
|
|
||||||
(TCPOPT_NOP << 16) |
|
|
||||||
(TCPOPT_MD5SIG << 8) |
|
|
||||||
TCPOLEN_MD5SIG);
|
|
||||||
}
|
|
||||||
options &= ~OPTION_COOKIE_EXTENSION;
|
|
||||||
/* overload cookie hash location */
|
/* overload cookie hash location */
|
||||||
opts->hash_location = (__u8 *)ptr;
|
opts->hash_location = (__u8 *)ptr;
|
||||||
ptr += 4;
|
ptr += 4;
|
||||||
|
@ -497,44 +445,6 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
|
||||||
*ptr++ = htonl(opts->tsecr);
|
*ptr++ = htonl(opts->tsecr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Specification requires after timestamp, so do it now.
|
|
||||||
*
|
|
||||||
* Consider the pessimal case without authentication. The options
|
|
||||||
* could look like:
|
|
||||||
* MSS(4) + SACK|TS(12) + COOKIE(20) + WSCALE(4) == 40
|
|
||||||
*/
|
|
||||||
if (unlikely(OPTION_COOKIE_EXTENSION & options)) {
|
|
||||||
__u8 *cookie_copy = opts->hash_location;
|
|
||||||
u8 cookie_size = opts->hash_size;
|
|
||||||
|
|
||||||
/* 8-bit multiple handled in tcp_cookie_size_check() above,
|
|
||||||
* and elsewhere.
|
|
||||||
*/
|
|
||||||
if (0x2 & cookie_size) {
|
|
||||||
__u8 *p = (__u8 *)ptr;
|
|
||||||
|
|
||||||
/* 16-bit multiple */
|
|
||||||
*p++ = TCPOPT_COOKIE;
|
|
||||||
*p++ = TCPOLEN_COOKIE_BASE + cookie_size;
|
|
||||||
*p++ = *cookie_copy++;
|
|
||||||
*p++ = *cookie_copy++;
|
|
||||||
ptr++;
|
|
||||||
cookie_size -= 2;
|
|
||||||
} else {
|
|
||||||
/* 32-bit multiple */
|
|
||||||
*ptr++ = htonl(((TCPOPT_NOP << 24) |
|
|
||||||
(TCPOPT_NOP << 16) |
|
|
||||||
(TCPOPT_COOKIE << 8) |
|
|
||||||
TCPOLEN_COOKIE_BASE) +
|
|
||||||
cookie_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cookie_size > 0) {
|
|
||||||
memcpy(ptr, cookie_copy, cookie_size);
|
|
||||||
ptr += (cookie_size / 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (unlikely(OPTION_SACK_ADVERTISE & options)) {
|
if (unlikely(OPTION_SACK_ADVERTISE & options)) {
|
||||||
*ptr++ = htonl((TCPOPT_NOP << 24) |
|
*ptr++ = htonl((TCPOPT_NOP << 24) |
|
||||||
(TCPOPT_NOP << 16) |
|
(TCPOPT_NOP << 16) |
|
||||||
|
@ -593,11 +503,7 @@ static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb,
|
||||||
struct tcp_md5sig_key **md5)
|
struct tcp_md5sig_key **md5)
|
||||||
{
|
{
|
||||||
struct tcp_sock *tp = tcp_sk(sk);
|
struct tcp_sock *tp = tcp_sk(sk);
|
||||||
struct tcp_cookie_values *cvp = tp->cookie_values;
|
|
||||||
unsigned int remaining = MAX_TCP_OPTION_SPACE;
|
unsigned int remaining = MAX_TCP_OPTION_SPACE;
|
||||||
u8 cookie_size = (!tp->rx_opt.cookie_out_never && cvp != NULL) ?
|
|
||||||
tcp_cookie_size_check(cvp->cookie_desired) :
|
|
||||||
0;
|
|
||||||
struct tcp_fastopen_request *fastopen = tp->fastopen_req;
|
struct tcp_fastopen_request *fastopen = tp->fastopen_req;
|
||||||
|
|
||||||
#ifdef CONFIG_TCP_MD5SIG
|
#ifdef CONFIG_TCP_MD5SIG
|
||||||
|
@ -649,52 +555,7 @@ static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb,
|
||||||
tp->syn_fastopen = 1;
|
tp->syn_fastopen = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Note that timestamps are required by the specification.
|
|
||||||
*
|
|
||||||
* Odd numbers of bytes are prohibited by the specification, ensuring
|
|
||||||
* that the cookie is 16-bit aligned, and the resulting cookie pair is
|
|
||||||
* 32-bit aligned.
|
|
||||||
*/
|
|
||||||
if (*md5 == NULL &&
|
|
||||||
(OPTION_TS & opts->options) &&
|
|
||||||
cookie_size > 0) {
|
|
||||||
int need = TCPOLEN_COOKIE_BASE + cookie_size;
|
|
||||||
|
|
||||||
if (0x2 & need) {
|
|
||||||
/* 32-bit multiple */
|
|
||||||
need += 2; /* NOPs */
|
|
||||||
|
|
||||||
if (need > remaining) {
|
|
||||||
/* try shrinking cookie to fit */
|
|
||||||
cookie_size -= 2;
|
|
||||||
need -= 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (need > remaining && TCP_COOKIE_MIN <= cookie_size) {
|
|
||||||
cookie_size -= 4;
|
|
||||||
need -= 4;
|
|
||||||
}
|
|
||||||
if (TCP_COOKIE_MIN <= cookie_size) {
|
|
||||||
opts->options |= OPTION_COOKIE_EXTENSION;
|
|
||||||
opts->hash_location = (__u8 *)&cvp->cookie_pair[0];
|
|
||||||
opts->hash_size = cookie_size;
|
|
||||||
|
|
||||||
/* Remember for future incarnations. */
|
|
||||||
cvp->cookie_desired = cookie_size;
|
|
||||||
|
|
||||||
if (cvp->cookie_desired != cvp->cookie_pair_size) {
|
|
||||||
/* Currently use random bytes as a nonce,
|
|
||||||
* assuming these are completely unpredictable
|
|
||||||
* by hostile users of the same system.
|
|
||||||
*/
|
|
||||||
get_random_bytes(&cvp->cookie_pair[0],
|
|
||||||
cookie_size);
|
|
||||||
cvp->cookie_pair_size = cookie_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
remaining -= need;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return MAX_TCP_OPTION_SPACE - remaining;
|
return MAX_TCP_OPTION_SPACE - remaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -704,14 +565,10 @@ static unsigned int tcp_synack_options(struct sock *sk,
|
||||||
unsigned int mss, struct sk_buff *skb,
|
unsigned int mss, struct sk_buff *skb,
|
||||||
struct tcp_out_options *opts,
|
struct tcp_out_options *opts,
|
||||||
struct tcp_md5sig_key **md5,
|
struct tcp_md5sig_key **md5,
|
||||||
struct tcp_extend_values *xvp,
|
|
||||||
struct tcp_fastopen_cookie *foc)
|
struct tcp_fastopen_cookie *foc)
|
||||||
{
|
{
|
||||||
struct inet_request_sock *ireq = inet_rsk(req);
|
struct inet_request_sock *ireq = inet_rsk(req);
|
||||||
unsigned int remaining = MAX_TCP_OPTION_SPACE;
|
unsigned int remaining = MAX_TCP_OPTION_SPACE;
|
||||||
u8 cookie_plus = (xvp != NULL && !xvp->cookie_out_never) ?
|
|
||||||
xvp->cookie_plus :
|
|
||||||
0;
|
|
||||||
|
|
||||||
#ifdef CONFIG_TCP_MD5SIG
|
#ifdef CONFIG_TCP_MD5SIG
|
||||||
*md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req);
|
*md5 = tcp_rsk(req)->af_specific->md5_lookup(sk, req);
|
||||||
|
@ -759,28 +616,7 @@ static unsigned int tcp_synack_options(struct sock *sk,
|
||||||
remaining -= need;
|
remaining -= need;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Similar rationale to tcp_syn_options() applies here, too.
|
|
||||||
* If the <SYN> options fit, the same options should fit now!
|
|
||||||
*/
|
|
||||||
if (*md5 == NULL &&
|
|
||||||
ireq->tstamp_ok &&
|
|
||||||
cookie_plus > TCPOLEN_COOKIE_BASE) {
|
|
||||||
int need = cookie_plus; /* has TCPOLEN_COOKIE_BASE */
|
|
||||||
|
|
||||||
if (0x2 & need) {
|
|
||||||
/* 32-bit multiple */
|
|
||||||
need += 2; /* NOPs */
|
|
||||||
}
|
|
||||||
if (need <= remaining) {
|
|
||||||
opts->options |= OPTION_COOKIE_EXTENSION;
|
|
||||||
opts->hash_size = cookie_plus - TCPOLEN_COOKIE_BASE;
|
|
||||||
remaining -= need;
|
|
||||||
} else {
|
|
||||||
/* There's no error return, so flag it. */
|
|
||||||
xvp->cookie_out_never = 1; /* true */
|
|
||||||
opts->hash_size = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return MAX_TCP_OPTION_SPACE - remaining;
|
return MAX_TCP_OPTION_SPACE - remaining;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2802,32 +2638,24 @@ int tcp_send_synack(struct sock *sk)
|
||||||
* sk: listener socket
|
* sk: listener socket
|
||||||
* dst: dst entry attached to the SYNACK
|
* dst: dst entry attached to the SYNACK
|
||||||
* req: request_sock pointer
|
* req: request_sock pointer
|
||||||
* rvp: request_values pointer
|
|
||||||
*
|
*
|
||||||
* Allocate one skb and build a SYNACK packet.
|
* Allocate one skb and build a SYNACK packet.
|
||||||
* @dst is consumed : Caller should not use it again.
|
* @dst is consumed : Caller should not use it again.
|
||||||
*/
|
*/
|
||||||
struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
|
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)
|
||||||
{
|
{
|
||||||
struct tcp_out_options opts;
|
struct tcp_out_options opts;
|
||||||
struct tcp_extend_values *xvp = tcp_xv(rvp);
|
|
||||||
struct inet_request_sock *ireq = inet_rsk(req);
|
struct inet_request_sock *ireq = inet_rsk(req);
|
||||||
struct tcp_sock *tp = tcp_sk(sk);
|
struct tcp_sock *tp = tcp_sk(sk);
|
||||||
const struct tcp_cookie_values *cvp = tp->cookie_values;
|
|
||||||
struct tcphdr *th;
|
struct tcphdr *th;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
struct tcp_md5sig_key *md5;
|
struct tcp_md5sig_key *md5;
|
||||||
int tcp_header_size;
|
int tcp_header_size;
|
||||||
int mss;
|
int mss;
|
||||||
int s_data_desired = 0;
|
|
||||||
|
|
||||||
if (cvp != NULL && cvp->s_data_constant && cvp->s_data_desired)
|
skb = alloc_skb(MAX_TCP_HEADER + 15, sk_gfp_atomic(sk, GFP_ATOMIC));
|
||||||
s_data_desired = cvp->s_data_desired;
|
|
||||||
skb = alloc_skb(MAX_TCP_HEADER + 15 + s_data_desired,
|
|
||||||
sk_gfp_atomic(sk, GFP_ATOMIC));
|
|
||||||
if (unlikely(!skb)) {
|
if (unlikely(!skb)) {
|
||||||
dst_release(dst);
|
dst_release(dst);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -2869,9 +2697,8 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
TCP_SKB_CB(skb)->when = tcp_time_stamp;
|
TCP_SKB_CB(skb)->when = tcp_time_stamp;
|
||||||
tcp_header_size = tcp_synack_options(sk, req, mss,
|
tcp_header_size = tcp_synack_options(sk, req, mss, skb, &opts, &md5,
|
||||||
skb, &opts, &md5, xvp, foc)
|
foc) + sizeof(*th);
|
||||||
+ sizeof(*th);
|
|
||||||
|
|
||||||
skb_push(skb, tcp_header_size);
|
skb_push(skb, tcp_header_size);
|
||||||
skb_reset_transport_header(skb);
|
skb_reset_transport_header(skb);
|
||||||
|
@ -2889,40 +2716,6 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
|
||||||
tcp_init_nondata_skb(skb, tcp_rsk(req)->snt_isn,
|
tcp_init_nondata_skb(skb, tcp_rsk(req)->snt_isn,
|
||||||
TCPHDR_SYN | TCPHDR_ACK);
|
TCPHDR_SYN | TCPHDR_ACK);
|
||||||
|
|
||||||
if (OPTION_COOKIE_EXTENSION & opts.options) {
|
|
||||||
if (s_data_desired) {
|
|
||||||
u8 *buf = skb_put(skb, s_data_desired);
|
|
||||||
|
|
||||||
/* copy data directly from the listening socket. */
|
|
||||||
memcpy(buf, cvp->s_data_payload, s_data_desired);
|
|
||||||
TCP_SKB_CB(skb)->end_seq += s_data_desired;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (opts.hash_size > 0) {
|
|
||||||
__u32 workspace[SHA_WORKSPACE_WORDS];
|
|
||||||
u32 *mess = &xvp->cookie_bakery[COOKIE_DIGEST_WORDS];
|
|
||||||
u32 *tail = &mess[COOKIE_MESSAGE_WORDS-1];
|
|
||||||
|
|
||||||
/* Secret recipe depends on the Timestamp, (future)
|
|
||||||
* Sequence and Acknowledgment Numbers, Initiator
|
|
||||||
* Cookie, and others handled by IP variant caller.
|
|
||||||
*/
|
|
||||||
*tail-- ^= opts.tsval;
|
|
||||||
*tail-- ^= tcp_rsk(req)->rcv_isn + 1;
|
|
||||||
*tail-- ^= TCP_SKB_CB(skb)->seq + 1;
|
|
||||||
|
|
||||||
/* recommended */
|
|
||||||
*tail-- ^= (((__force u32)th->dest << 16) | (__force u32)th->source);
|
|
||||||
*tail-- ^= (u32)(unsigned long)cvp; /* per sockopt */
|
|
||||||
|
|
||||||
sha_transform((__u32 *)&xvp->cookie_bakery[0],
|
|
||||||
(char *)mess,
|
|
||||||
&workspace[0]);
|
|
||||||
opts.hash_location =
|
|
||||||
(__u8 *)&xvp->cookie_bakery[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
th->seq = htonl(TCP_SKB_CB(skb)->seq);
|
th->seq = htonl(TCP_SKB_CB(skb)->seq);
|
||||||
/* XXX data is queued and acked as is. No buffer/window check */
|
/* XXX data is queued and acked as is. No buffer/window check */
|
||||||
th->ack_seq = htonl(tcp_rsk(req)->rcv_nxt);
|
th->ack_seq = htonl(tcp_rsk(req)->rcv_nxt);
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
/* 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 @@ out:
|
||||||
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,
|
||||||
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 @@ done:
|
||||||
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)
|
||||||
*/
|
*/
|
||||||
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)
|
||||||
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 @@ have_isn:
|
||||||
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;
|
||||||
|
|
Loading…
Add table
Reference in a new issue