mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	net/tcp: Wire TCP-AO to request sockets
Now when the new request socket is created from the listening socket, it's recorded what MKT was used by the peer. tcp_rsk_used_ao() is a new helper for checking if TCP-AO option was used to create the request socket. tcp_ao_copy_all_matching() will copy all keys that match the peer on the request socket, as well as preparing them for the usage (creating traffic keys). Co-developed-by: Francesco Ruggeri <fruggeri@arista.com> Signed-off-by: Francesco Ruggeri <fruggeri@arista.com> Co-developed-by: Salam Noureddine <noureddine@arista.com> Signed-off-by: Salam Noureddine <noureddine@arista.com> Signed-off-by: Dmitry Safonov <dima@arista.com> Acked-by: David Ahern <dsahern@kernel.org> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
							parent
							
								
									decde2586b
								
							
						
					
					
						commit
						06b22ef295
					
				
					 12 changed files with 505 additions and 50 deletions
				
			
		| 
						 | 
					@ -166,6 +166,11 @@ struct tcp_request_sock {
 | 
				
			||||||
						  * after data-in-SYN.
 | 
											  * after data-in-SYN.
 | 
				
			||||||
						  */
 | 
											  */
 | 
				
			||||||
	u8				syn_tos;
 | 
						u8				syn_tos;
 | 
				
			||||||
 | 
					#ifdef CONFIG_TCP_AO
 | 
				
			||||||
 | 
						u8				ao_keyid;
 | 
				
			||||||
 | 
						u8				ao_rcv_next;
 | 
				
			||||||
 | 
						u8				maclen;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req)
 | 
					static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req)
 | 
				
			||||||
| 
						 | 
					@ -173,6 +178,19 @@ static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req)
 | 
				
			||||||
	return (struct tcp_request_sock *)req;
 | 
						return (struct tcp_request_sock *)req;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline bool tcp_rsk_used_ao(const struct request_sock *req)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* The real length of MAC is saved in the request socket,
 | 
				
			||||||
 | 
						 * signing anything with zero-length makes no sense, so here is
 | 
				
			||||||
 | 
						 * a little hack..
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					#ifndef CONFIG_TCP_AO
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						return tcp_rsk(req)->maclen != 0;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define TCP_RMEM_TO_WIN_SCALE 8
 | 
					#define TCP_RMEM_TO_WIN_SCALE 8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct tcp_sock {
 | 
					struct tcp_sock {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2216,6 +2216,12 @@ struct tcp_request_sock_ops {
 | 
				
			||||||
					  const struct sock *sk,
 | 
										  const struct sock *sk,
 | 
				
			||||||
					  const struct sk_buff *skb);
 | 
										  const struct sk_buff *skb);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef CONFIG_TCP_AO
 | 
				
			||||||
 | 
						struct tcp_ao_key *(*ao_lookup)(const struct sock *sk,
 | 
				
			||||||
 | 
										struct request_sock *req,
 | 
				
			||||||
 | 
										int sndid, int rcvid);
 | 
				
			||||||
 | 
						int (*ao_calc_key)(struct tcp_ao_key *mkt, u8 *key, struct request_sock *sk);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
#ifdef CONFIG_SYN_COOKIES
 | 
					#ifdef CONFIG_SYN_COOKIES
 | 
				
			||||||
	__u32 (*cookie_init_seq)(const struct sk_buff *skb,
 | 
						__u32 (*cookie_init_seq)(const struct sk_buff *skb,
 | 
				
			||||||
				 __u16 *mss);
 | 
									 __u16 *mss);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -123,6 +123,9 @@ int tcp_parse_ao(struct sock *sk, int cmd, unsigned short int family,
 | 
				
			||||||
		 sockptr_t optval, int optlen);
 | 
							 sockptr_t optval, int optlen);
 | 
				
			||||||
struct tcp_ao_key *tcp_ao_established_key(struct tcp_ao_info *ao,
 | 
					struct tcp_ao_key *tcp_ao_established_key(struct tcp_ao_info *ao,
 | 
				
			||||||
					  int sndid, int rcvid);
 | 
										  int sndid, int rcvid);
 | 
				
			||||||
 | 
					int tcp_ao_copy_all_matching(const struct sock *sk, struct sock *newsk,
 | 
				
			||||||
 | 
								     struct request_sock *req, struct sk_buff *skb,
 | 
				
			||||||
 | 
								     int family);
 | 
				
			||||||
int tcp_ao_calc_traffic_key(struct tcp_ao_key *mkt, u8 *key, void *ctx,
 | 
					int tcp_ao_calc_traffic_key(struct tcp_ao_key *mkt, u8 *key, void *ctx,
 | 
				
			||||||
			    unsigned int len, struct tcp_sigpool *hp);
 | 
								    unsigned int len, struct tcp_sigpool *hp);
 | 
				
			||||||
void tcp_ao_destroy_sock(struct sock *sk, bool twsk);
 | 
					void tcp_ao_destroy_sock(struct sock *sk, bool twsk);
 | 
				
			||||||
| 
						 | 
					@ -147,6 +150,11 @@ struct tcp_ao_key *tcp_v4_ao_lookup(const struct sock *sk, struct sock *addr_sk,
 | 
				
			||||||
int tcp_v4_ao_calc_key_sk(struct tcp_ao_key *mkt, u8 *key,
 | 
					int tcp_v4_ao_calc_key_sk(struct tcp_ao_key *mkt, u8 *key,
 | 
				
			||||||
			  const struct sock *sk,
 | 
								  const struct sock *sk,
 | 
				
			||||||
			  __be32 sisn, __be32 disn, bool send);
 | 
								  __be32 sisn, __be32 disn, bool send);
 | 
				
			||||||
 | 
					int tcp_v4_ao_calc_key_rsk(struct tcp_ao_key *mkt, u8 *key,
 | 
				
			||||||
 | 
								   struct request_sock *req);
 | 
				
			||||||
 | 
					struct tcp_ao_key *tcp_v4_ao_lookup_rsk(const struct sock *sk,
 | 
				
			||||||
 | 
										struct request_sock *req,
 | 
				
			||||||
 | 
										int sndid, int rcvid);
 | 
				
			||||||
int tcp_v4_ao_hash_skb(char *ao_hash, struct tcp_ao_key *key,
 | 
					int tcp_v4_ao_hash_skb(char *ao_hash, struct tcp_ao_key *key,
 | 
				
			||||||
		       const struct sock *sk, const struct sk_buff *skb,
 | 
							       const struct sock *sk, const struct sk_buff *skb,
 | 
				
			||||||
		       const u8 *tkey, int hash_offset, u32 sne);
 | 
							       const u8 *tkey, int hash_offset, u32 sne);
 | 
				
			||||||
| 
						 | 
					@ -154,11 +162,21 @@ int tcp_v4_ao_hash_skb(char *ao_hash, struct tcp_ao_key *key,
 | 
				
			||||||
int tcp_v6_ao_hash_pseudoheader(struct tcp_sigpool *hp,
 | 
					int tcp_v6_ao_hash_pseudoheader(struct tcp_sigpool *hp,
 | 
				
			||||||
				const struct in6_addr *daddr,
 | 
									const struct in6_addr *daddr,
 | 
				
			||||||
				const struct in6_addr *saddr, int nbytes);
 | 
									const struct in6_addr *saddr, int nbytes);
 | 
				
			||||||
 | 
					int tcp_v6_ao_calc_key_skb(struct tcp_ao_key *mkt, u8 *key,
 | 
				
			||||||
 | 
								   const struct sk_buff *skb, __be32 sisn, __be32 disn);
 | 
				
			||||||
int tcp_v6_ao_calc_key_sk(struct tcp_ao_key *mkt, u8 *key,
 | 
					int tcp_v6_ao_calc_key_sk(struct tcp_ao_key *mkt, u8 *key,
 | 
				
			||||||
			  const struct sock *sk, __be32 sisn,
 | 
								  const struct sock *sk, __be32 sisn,
 | 
				
			||||||
			  __be32 disn, bool send);
 | 
								  __be32 disn, bool send);
 | 
				
			||||||
 | 
					int tcp_v6_ao_calc_key_rsk(struct tcp_ao_key *mkt, u8 *key,
 | 
				
			||||||
 | 
								   struct request_sock *req);
 | 
				
			||||||
 | 
					struct tcp_ao_key *tcp_v6_ao_do_lookup(const struct sock *sk,
 | 
				
			||||||
 | 
									       const struct in6_addr *addr,
 | 
				
			||||||
 | 
									       int sndid, int rcvid);
 | 
				
			||||||
struct tcp_ao_key *tcp_v6_ao_lookup(const struct sock *sk,
 | 
					struct tcp_ao_key *tcp_v6_ao_lookup(const struct sock *sk,
 | 
				
			||||||
				    struct sock *addr_sk, int sndid, int rcvid);
 | 
									    struct sock *addr_sk, int sndid, int rcvid);
 | 
				
			||||||
 | 
					struct tcp_ao_key *tcp_v6_ao_lookup_rsk(const struct sock *sk,
 | 
				
			||||||
 | 
										struct request_sock *req,
 | 
				
			||||||
 | 
										int sndid, int rcvid);
 | 
				
			||||||
int tcp_v6_ao_hash_skb(char *ao_hash, struct tcp_ao_key *key,
 | 
					int tcp_v6_ao_hash_skb(char *ao_hash, struct tcp_ao_key *key,
 | 
				
			||||||
		       const struct sock *sk, const struct sk_buff *skb,
 | 
							       const struct sock *sk, const struct sk_buff *skb,
 | 
				
			||||||
		       const u8 *tkey, int hash_offset, u32 sne);
 | 
							       const u8 *tkey, int hash_offset, u32 sne);
 | 
				
			||||||
| 
						 | 
					@ -178,6 +196,12 @@ static inline int tcp_ao_transmit_skb(struct sock *sk, struct sk_buff *skb,
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void tcp_ao_syncookie(struct sock *sk, const struct sk_buff *skb,
 | 
				
			||||||
 | 
									    struct tcp_request_sock *treq,
 | 
				
			||||||
 | 
									    unsigned short int family)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline struct tcp_ao_key *tcp_ao_do_lookup(const struct sock *sk,
 | 
					static inline struct tcp_ao_key *tcp_ao_do_lookup(const struct sock *sk,
 | 
				
			||||||
		const union tcp_ao_addr *addr, int family, int sndid, int rcvid)
 | 
							const union tcp_ao_addr *addr, int family, int sndid, int rcvid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -400,6 +400,8 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb)
 | 
				
			||||||
	treq->snt_synack	= 0;
 | 
						treq->snt_synack	= 0;
 | 
				
			||||||
	treq->tfo_listener	= false;
 | 
						treq->tfo_listener	= false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tcp_ao_syncookie(sk, skb, treq, AF_INET);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (IS_ENABLED(CONFIG_SMC))
 | 
						if (IS_ENABLED(CONFIG_SMC))
 | 
				
			||||||
		ireq->smc_ok = 0;
 | 
							ireq->smc_ok = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -169,6 +169,23 @@ static void tcp_ao_link_mkt(struct tcp_ao_info *ao, struct tcp_ao_key *mkt)
 | 
				
			||||||
	hlist_add_head_rcu(&mkt->node, &ao->head);
 | 
						hlist_add_head_rcu(&mkt->node, &ao->head);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct tcp_ao_key *tcp_ao_copy_key(struct sock *sk,
 | 
				
			||||||
 | 
										  struct tcp_ao_key *key)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct tcp_ao_key *new_key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						new_key = sock_kmalloc(sk, tcp_ao_sizeof_key(key),
 | 
				
			||||||
 | 
								       GFP_ATOMIC);
 | 
				
			||||||
 | 
						if (!new_key)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*new_key = *key;
 | 
				
			||||||
 | 
						INIT_HLIST_NODE(&new_key->node);
 | 
				
			||||||
 | 
						tcp_sigpool_get(new_key->tcp_sigpool_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return new_key;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void tcp_ao_key_free_rcu(struct rcu_head *head)
 | 
					static void tcp_ao_key_free_rcu(struct rcu_head *head)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct tcp_ao_key *key = container_of(head, struct tcp_ao_key, rcu);
 | 
						struct tcp_ao_key *key = container_of(head, struct tcp_ao_key, rcu);
 | 
				
			||||||
| 
						 | 
					@ -290,6 +307,42 @@ static int tcp_ao_calc_key_sk(struct tcp_ao_key *mkt, u8 *key,
 | 
				
			||||||
		return -EOPNOTSUPP;
 | 
							return -EOPNOTSUPP;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int tcp_v4_ao_calc_key_rsk(struct tcp_ao_key *mkt, u8 *key,
 | 
				
			||||||
 | 
								   struct request_sock *req)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct inet_request_sock *ireq = inet_rsk(req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return tcp_v4_ao_calc_key(mkt, key,
 | 
				
			||||||
 | 
									  ireq->ir_loc_addr, ireq->ir_rmt_addr,
 | 
				
			||||||
 | 
									  htons(ireq->ir_num), ireq->ir_rmt_port,
 | 
				
			||||||
 | 
									  htonl(tcp_rsk(req)->snt_isn),
 | 
				
			||||||
 | 
									  htonl(tcp_rsk(req)->rcv_isn));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int tcp_v4_ao_calc_key_skb(struct tcp_ao_key *mkt, u8 *key,
 | 
				
			||||||
 | 
									  const struct sk_buff *skb,
 | 
				
			||||||
 | 
									  __be32 sisn, __be32 disn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct iphdr *iph = ip_hdr(skb);
 | 
				
			||||||
 | 
						const struct tcphdr *th = tcp_hdr(skb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return tcp_v4_ao_calc_key(mkt, key, iph->saddr, iph->daddr,
 | 
				
			||||||
 | 
									  th->source, th->dest, sisn, disn);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int tcp_ao_calc_key_skb(struct tcp_ao_key *mkt, u8 *key,
 | 
				
			||||||
 | 
								       const struct sk_buff *skb,
 | 
				
			||||||
 | 
								       __be32 sisn, __be32 disn, int family)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (family == AF_INET)
 | 
				
			||||||
 | 
							return tcp_v4_ao_calc_key_skb(mkt, key, skb, sisn, disn);
 | 
				
			||||||
 | 
					#if IS_ENABLED(CONFIG_IPV6)
 | 
				
			||||||
 | 
						else if (family == AF_INET6)
 | 
				
			||||||
 | 
							return tcp_v6_ao_calc_key_skb(mkt, key, skb, sisn, disn);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						return -EAFNOSUPPORT;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int tcp_v4_ao_hash_pseudoheader(struct tcp_sigpool *hp,
 | 
					static int tcp_v4_ao_hash_pseudoheader(struct tcp_sigpool *hp,
 | 
				
			||||||
				       __be32 daddr, __be32 saddr,
 | 
									       __be32 daddr, __be32 saddr,
 | 
				
			||||||
				       int nbytes)
 | 
									       int nbytes)
 | 
				
			||||||
| 
						 | 
					@ -515,6 +568,16 @@ int tcp_v4_ao_hash_skb(char *ao_hash, struct tcp_ao_key *key,
 | 
				
			||||||
			       tkey, hash_offset, sne);
 | 
								       tkey, hash_offset, sne);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct tcp_ao_key *tcp_v4_ao_lookup_rsk(const struct sock *sk,
 | 
				
			||||||
 | 
										struct request_sock *req,
 | 
				
			||||||
 | 
										int sndid, int rcvid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						union tcp_ao_addr *addr =
 | 
				
			||||||
 | 
								(union tcp_ao_addr *)&inet_rsk(req)->ir_rmt_addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return tcp_ao_do_lookup(sk, addr, AF_INET, sndid, rcvid);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct tcp_ao_key *tcp_v4_ao_lookup(const struct sock *sk, struct sock *addr_sk,
 | 
					struct tcp_ao_key *tcp_v4_ao_lookup(const struct sock *sk, struct sock *addr_sk,
 | 
				
			||||||
				    int sndid, int rcvid)
 | 
									    int sndid, int rcvid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -528,7 +591,7 @@ int tcp_ao_prepare_reset(const struct sock *sk, struct sk_buff *skb,
 | 
				
			||||||
			 struct tcp_ao_key **key, char **traffic_key,
 | 
								 struct tcp_ao_key **key, char **traffic_key,
 | 
				
			||||||
			 bool *allocated_traffic_key, u8 *keyid, u32 *sne)
 | 
								 bool *allocated_traffic_key, u8 *keyid, u32 *sne)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct tcp_ao_key *rnext_key;
 | 
						const struct tcphdr *th = tcp_hdr(skb);
 | 
				
			||||||
	struct tcp_ao_info *ao_info;
 | 
						struct tcp_ao_info *ao_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*allocated_traffic_key = false;
 | 
						*allocated_traffic_key = false;
 | 
				
			||||||
| 
						 | 
					@ -543,23 +606,62 @@ int tcp_ao_prepare_reset(const struct sock *sk, struct sk_buff *skb,
 | 
				
			||||||
		return -ENOTCONN;
 | 
							return -ENOTCONN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_NEW_SYN_RECV)) {
 | 
						if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_NEW_SYN_RECV)) {
 | 
				
			||||||
		return -1;
 | 
							unsigned int family = READ_ONCE(sk->sk_family);
 | 
				
			||||||
 | 
							union tcp_ao_addr *addr;
 | 
				
			||||||
 | 
							__be32 disn, sisn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sk->sk_state == TCP_TIME_WAIT)
 | 
							if (sk->sk_state == TCP_NEW_SYN_RECV) {
 | 
				
			||||||
		ao_info = rcu_dereference(tcp_twsk(sk)->ao_info);
 | 
								struct request_sock *req = inet_reqsk(sk);
 | 
				
			||||||
	else
 | 
					
 | 
				
			||||||
 | 
								sisn = htonl(tcp_rsk(req)->rcv_isn);
 | 
				
			||||||
 | 
								disn = htonl(tcp_rsk(req)->snt_isn);
 | 
				
			||||||
 | 
								*sne = 0;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								sisn = th->seq;
 | 
				
			||||||
 | 
								disn = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (IS_ENABLED(CONFIG_IPV6) && family == AF_INET6)
 | 
				
			||||||
 | 
								addr = (union tcp_md5_addr *)&ipv6_hdr(skb)->saddr;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								addr = (union tcp_md5_addr *)&ip_hdr(skb)->saddr;
 | 
				
			||||||
 | 
					#if IS_ENABLED(CONFIG_IPV6)
 | 
				
			||||||
 | 
							if (family == AF_INET6 && ipv6_addr_v4mapped(&sk->sk_v6_daddr))
 | 
				
			||||||
 | 
								family = AF_INET;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							sk = sk_const_to_full_sk(sk);
 | 
				
			||||||
		ao_info = rcu_dereference(tcp_sk(sk)->ao_info);
 | 
							ao_info = rcu_dereference(tcp_sk(sk)->ao_info);
 | 
				
			||||||
	if (!ao_info)
 | 
							if (!ao_info)
 | 
				
			||||||
		return -ENOENT;
 | 
								return -ENOENT;
 | 
				
			||||||
 | 
							*key = tcp_ao_do_lookup(sk, addr, family, -1, aoh->rnext_keyid);
 | 
				
			||||||
 | 
							if (!*key)
 | 
				
			||||||
 | 
								return -ENOENT;
 | 
				
			||||||
 | 
							*traffic_key = kmalloc(tcp_ao_digest_size(*key), GFP_ATOMIC);
 | 
				
			||||||
 | 
							if (!*traffic_key)
 | 
				
			||||||
 | 
								return -ENOMEM;
 | 
				
			||||||
 | 
							*allocated_traffic_key = true;
 | 
				
			||||||
 | 
							if (tcp_ao_calc_key_skb(*key, *traffic_key, skb,
 | 
				
			||||||
 | 
										sisn, disn, family))
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							*keyid = (*key)->rcvid;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							struct tcp_ao_key *rnext_key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*key = tcp_ao_established_key(ao_info, aoh->rnext_keyid, -1);
 | 
							if (sk->sk_state == TCP_TIME_WAIT)
 | 
				
			||||||
	if (!*key)
 | 
								ao_info = rcu_dereference(tcp_twsk(sk)->ao_info);
 | 
				
			||||||
		return -ENOENT;
 | 
							else
 | 
				
			||||||
	*traffic_key = snd_other_key(*key);
 | 
								ao_info = rcu_dereference(tcp_sk(sk)->ao_info);
 | 
				
			||||||
	rnext_key = READ_ONCE(ao_info->rnext_key);
 | 
							if (!ao_info)
 | 
				
			||||||
	*keyid = rnext_key->rcvid;
 | 
								return -ENOENT;
 | 
				
			||||||
	*sne = 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							*key = tcp_ao_established_key(ao_info, aoh->rnext_keyid, -1);
 | 
				
			||||||
 | 
							if (!*key)
 | 
				
			||||||
 | 
								return -ENOENT;
 | 
				
			||||||
 | 
							*traffic_key = snd_other_key(*key);
 | 
				
			||||||
 | 
							rnext_key = READ_ONCE(ao_info->rnext_key);
 | 
				
			||||||
 | 
							*keyid = rnext_key->rcvid;
 | 
				
			||||||
 | 
							*sne = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -597,6 +699,46 @@ int tcp_ao_transmit_skb(struct sock *sk, struct sk_buff *skb,
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct tcp_ao_key *tcp_ao_inbound_lookup(unsigned short int family,
 | 
				
			||||||
 | 
							const struct sock *sk, const struct sk_buff *skb,
 | 
				
			||||||
 | 
							int sndid, int rcvid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (family == AF_INET) {
 | 
				
			||||||
 | 
							const struct iphdr *iph = ip_hdr(skb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return tcp_ao_do_lookup(sk, (union tcp_ao_addr *)&iph->saddr,
 | 
				
			||||||
 | 
									AF_INET, sndid, rcvid);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							const struct ipv6hdr *iph = ipv6_hdr(skb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return tcp_ao_do_lookup(sk, (union tcp_ao_addr *)&iph->saddr,
 | 
				
			||||||
 | 
									AF_INET6, sndid, rcvid);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void tcp_ao_syncookie(struct sock *sk, const struct sk_buff *skb,
 | 
				
			||||||
 | 
							      struct tcp_request_sock *treq,
 | 
				
			||||||
 | 
							      unsigned short int family)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct tcphdr *th = tcp_hdr(skb);
 | 
				
			||||||
 | 
						const struct tcp_ao_hdr *aoh;
 | 
				
			||||||
 | 
						struct tcp_ao_key *key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						treq->maclen = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (tcp_parse_auth_options(th, NULL, &aoh) || !aoh)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						key = tcp_ao_inbound_lookup(family, sk, skb, -1, aoh->keyid);
 | 
				
			||||||
 | 
						if (!key)
 | 
				
			||||||
 | 
							/* Key not found, continue without TCP-AO */
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						treq->ao_rcv_next = aoh->keyid;
 | 
				
			||||||
 | 
						treq->ao_keyid = aoh->rnext_keyid;
 | 
				
			||||||
 | 
						treq->maclen = tcp_ao_maclen(key);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int tcp_ao_cache_traffic_keys(const struct sock *sk,
 | 
					static int tcp_ao_cache_traffic_keys(const struct sock *sk,
 | 
				
			||||||
				     struct tcp_ao_info *ao,
 | 
									     struct tcp_ao_info *ao,
 | 
				
			||||||
				     struct tcp_ao_key *ao_key)
 | 
									     struct tcp_ao_key *ao_key)
 | 
				
			||||||
| 
						 | 
					@ -704,6 +846,100 @@ void tcp_ao_finish_connect(struct sock *sk, struct sk_buff *skb)
 | 
				
			||||||
		tcp_ao_cache_traffic_keys(sk, ao, key);
 | 
							tcp_ao_cache_traffic_keys(sk, ao, key);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int tcp_ao_copy_all_matching(const struct sock *sk, struct sock *newsk,
 | 
				
			||||||
 | 
								     struct request_sock *req, struct sk_buff *skb,
 | 
				
			||||||
 | 
								     int family)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct tcp_ao_key *key, *new_key, *first_key;
 | 
				
			||||||
 | 
						struct tcp_ao_info *new_ao, *ao;
 | 
				
			||||||
 | 
						struct hlist_node *key_head;
 | 
				
			||||||
 | 
						union tcp_ao_addr *addr;
 | 
				
			||||||
 | 
						bool match = false;
 | 
				
			||||||
 | 
						int ret = -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ao = rcu_dereference(tcp_sk(sk)->ao_info);
 | 
				
			||||||
 | 
						if (!ao)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* New socket without TCP-AO on it */
 | 
				
			||||||
 | 
						if (!tcp_rsk_used_ao(req))
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						new_ao = tcp_ao_alloc_info(GFP_ATOMIC);
 | 
				
			||||||
 | 
						if (!new_ao)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						new_ao->lisn = htonl(tcp_rsk(req)->snt_isn);
 | 
				
			||||||
 | 
						new_ao->risn = htonl(tcp_rsk(req)->rcv_isn);
 | 
				
			||||||
 | 
						new_ao->ao_required = ao->ao_required;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (family == AF_INET) {
 | 
				
			||||||
 | 
							addr = (union tcp_ao_addr *)&newsk->sk_daddr;
 | 
				
			||||||
 | 
					#if IS_ENABLED(CONFIG_IPV6)
 | 
				
			||||||
 | 
						} else if (family == AF_INET6) {
 | 
				
			||||||
 | 
							addr = (union tcp_ao_addr *)&newsk->sk_v6_daddr;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							ret = -EAFNOSUPPORT;
 | 
				
			||||||
 | 
							goto free_ao;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						hlist_for_each_entry_rcu(key, &ao->head, node) {
 | 
				
			||||||
 | 
							if (tcp_ao_key_cmp(key, addr, key->prefixlen, family, -1, -1))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							new_key = tcp_ao_copy_key(newsk, key);
 | 
				
			||||||
 | 
							if (!new_key)
 | 
				
			||||||
 | 
								goto free_and_exit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							tcp_ao_cache_traffic_keys(newsk, new_ao, new_key);
 | 
				
			||||||
 | 
							tcp_ao_link_mkt(new_ao, new_key);
 | 
				
			||||||
 | 
							match = true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!match) {
 | 
				
			||||||
 | 
							/* RFC5925 (7.4.1) specifies that the TCP-AO status
 | 
				
			||||||
 | 
							 * of a connection is determined on the initial SYN.
 | 
				
			||||||
 | 
							 * At this point the connection was TCP-AO enabled, so
 | 
				
			||||||
 | 
							 * it can't switch to being unsigned if peer's key
 | 
				
			||||||
 | 
							 * disappears on the listening socket.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							ret = -EKEYREJECTED;
 | 
				
			||||||
 | 
							goto free_and_exit;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						key_head = rcu_dereference(hlist_first_rcu(&new_ao->head));
 | 
				
			||||||
 | 
						first_key = hlist_entry_safe(key_head, struct tcp_ao_key, node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						key = tcp_ao_established_key(new_ao, tcp_rsk(req)->ao_keyid, -1);
 | 
				
			||||||
 | 
						if (key)
 | 
				
			||||||
 | 
							new_ao->current_key = key;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							new_ao->current_key = first_key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* set rnext_key */
 | 
				
			||||||
 | 
						key = tcp_ao_established_key(new_ao, -1, tcp_rsk(req)->ao_rcv_next);
 | 
				
			||||||
 | 
						if (key)
 | 
				
			||||||
 | 
							new_ao->rnext_key = key;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							new_ao->rnext_key = first_key;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sk_gso_disable(newsk);
 | 
				
			||||||
 | 
						rcu_assign_pointer(tcp_sk(newsk)->ao_info, new_ao);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					free_and_exit:
 | 
				
			||||||
 | 
						hlist_for_each_entry_safe(key, key_head, &new_ao->head, node) {
 | 
				
			||||||
 | 
							hlist_del(&key->node);
 | 
				
			||||||
 | 
							tcp_sigpool_release(key->tcp_sigpool_id);
 | 
				
			||||||
 | 
							atomic_sub(tcp_ao_sizeof_key(key), &newsk->sk_omem_alloc);
 | 
				
			||||||
 | 
							kfree_sensitive(key);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					free_ao:
 | 
				
			||||||
 | 
						kfree(new_ao);
 | 
				
			||||||
 | 
						return ret;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool tcp_ao_can_set_current_rnext(struct sock *sk)
 | 
					static bool tcp_ao_can_set_current_rnext(struct sock *sk)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* There aren't current/rnext keys on TCP_LISTEN sockets */
 | 
						/* There aren't current/rnext keys on TCP_LISTEN sockets */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7045,6 +7045,10 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
 | 
				
			||||||
	struct flowi fl;
 | 
						struct flowi fl;
 | 
				
			||||||
	u8 syncookies;
 | 
						u8 syncookies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_TCP_AO
 | 
				
			||||||
 | 
						const struct tcp_ao_hdr *aoh;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	syncookies = READ_ONCE(net->ipv4.sysctl_tcp_syncookies);
 | 
						syncookies = READ_ONCE(net->ipv4.sysctl_tcp_syncookies);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* TW buckets are converted to open requests without
 | 
						/* TW buckets are converted to open requests without
 | 
				
			||||||
| 
						 | 
					@ -7131,6 +7135,17 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
 | 
				
			||||||
			inet_rsk(req)->ecn_ok = 0;
 | 
								inet_rsk(req)->ecn_ok = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_TCP_AO
 | 
				
			||||||
 | 
						if (tcp_parse_auth_options(tcp_hdr(skb), NULL, &aoh))
 | 
				
			||||||
 | 
							goto drop_and_release; /* Invalid TCP options */
 | 
				
			||||||
 | 
						if (aoh) {
 | 
				
			||||||
 | 
							tcp_rsk(req)->maclen = aoh->length - sizeof(struct tcp_ao_hdr);
 | 
				
			||||||
 | 
							tcp_rsk(req)->ao_rcv_next = aoh->keyid;
 | 
				
			||||||
 | 
							tcp_rsk(req)->ao_keyid = aoh->rnext_keyid;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							tcp_rsk(req)->maclen = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
	tcp_rsk(req)->snt_isn = isn;
 | 
						tcp_rsk(req)->snt_isn = isn;
 | 
				
			||||||
	tcp_rsk(req)->txhash = net_tx_rndhash();
 | 
						tcp_rsk(req)->txhash = net_tx_rndhash();
 | 
				
			||||||
	tcp_rsk(req)->syn_tos = TCP_SKB_CB(skb)->ip_dsfield;
 | 
						tcp_rsk(req)->syn_tos = TCP_SKB_CB(skb)->ip_dsfield;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1072,13 +1072,47 @@ static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,
 | 
				
			||||||
	u32 seq = (sk->sk_state == TCP_LISTEN) ? tcp_rsk(req)->snt_isn + 1 :
 | 
						u32 seq = (sk->sk_state == TCP_LISTEN) ? tcp_rsk(req)->snt_isn + 1 :
 | 
				
			||||||
					     tcp_sk(sk)->snd_nxt;
 | 
										     tcp_sk(sk)->snd_nxt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* RFC 7323 2.3
 | 
					#ifdef CONFIG_TCP_AO
 | 
				
			||||||
	 * The window field (SEG.WND) of every outgoing segment, with the
 | 
						if (tcp_rsk_used_ao(req)) {
 | 
				
			||||||
	 * exception of <SYN> segments, MUST be right-shifted by
 | 
							const union tcp_md5_addr *addr;
 | 
				
			||||||
	 * Rcv.Wind.Shift bits:
 | 
							const struct tcp_ao_hdr *aoh;
 | 
				
			||||||
	 */
 | 
					
 | 
				
			||||||
 | 
							/* Invalid TCP option size or twice included auth */
 | 
				
			||||||
 | 
							if (tcp_parse_auth_options(tcp_hdr(skb), NULL, &aoh))
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							if (!aoh)
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							addr = (union tcp_md5_addr *)&ip_hdr(skb)->saddr;
 | 
				
			||||||
 | 
							key.ao_key = tcp_ao_do_lookup(sk, addr, AF_INET,
 | 
				
			||||||
 | 
										      aoh->rnext_keyid, -1);
 | 
				
			||||||
 | 
							if (unlikely(!key.ao_key)) {
 | 
				
			||||||
 | 
								/* Send ACK with any matching MKT for the peer */
 | 
				
			||||||
 | 
								key.ao_key = tcp_ao_do_lookup(sk, addr, AF_INET, -1, -1);
 | 
				
			||||||
 | 
								/* Matching key disappeared (user removed the key?)
 | 
				
			||||||
 | 
								 * let the handshake timeout.
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								if (!key.ao_key) {
 | 
				
			||||||
 | 
									net_info_ratelimited("TCP-AO key for (%pI4, %d)->(%pI4, %d) suddenly disappeared, won't ACK new connection\n",
 | 
				
			||||||
 | 
											     addr,
 | 
				
			||||||
 | 
											     ntohs(tcp_hdr(skb)->source),
 | 
				
			||||||
 | 
											     &ip_hdr(skb)->daddr,
 | 
				
			||||||
 | 
											     ntohs(tcp_hdr(skb)->dest));
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							key.traffic_key = kmalloc(tcp_ao_digest_size(key.ao_key), GFP_ATOMIC);
 | 
				
			||||||
 | 
							if (!key.traffic_key)
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							key.type = TCP_KEY_AO;
 | 
				
			||||||
 | 
							key.rcv_next = aoh->keyid;
 | 
				
			||||||
 | 
							tcp_v4_ao_calc_key_rsk(key.ao_key, key.traffic_key, req);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						if (0) {
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
#ifdef CONFIG_TCP_MD5SIG
 | 
					#ifdef CONFIG_TCP_MD5SIG
 | 
				
			||||||
	if (static_branch_unlikely(&tcp_md5_needed.key)) {
 | 
						} else if (static_branch_unlikely(&tcp_md5_needed.key)) {
 | 
				
			||||||
		const union tcp_md5_addr *addr;
 | 
							const union tcp_md5_addr *addr;
 | 
				
			||||||
		int l3index;
 | 
							int l3index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1087,8 +1121,14 @@ static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,
 | 
				
			||||||
		key.md5_key = tcp_md5_do_lookup(sk, l3index, addr, AF_INET);
 | 
							key.md5_key = tcp_md5_do_lookup(sk, l3index, addr, AF_INET);
 | 
				
			||||||
		if (key.md5_key)
 | 
							if (key.md5_key)
 | 
				
			||||||
			key.type = TCP_KEY_MD5;
 | 
								key.type = TCP_KEY_MD5;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* RFC 7323 2.3
 | 
				
			||||||
 | 
						 * The window field (SEG.WND) of every outgoing segment, with the
 | 
				
			||||||
 | 
						 * exception of <SYN> segments, MUST be right-shifted by
 | 
				
			||||||
 | 
						 * Rcv.Wind.Shift bits:
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
	tcp_v4_send_ack(sk, skb, seq,
 | 
						tcp_v4_send_ack(sk, skb, seq,
 | 
				
			||||||
			tcp_rsk(req)->rcv_nxt,
 | 
								tcp_rsk(req)->rcv_nxt,
 | 
				
			||||||
			req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale,
 | 
								req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale,
 | 
				
			||||||
| 
						 | 
					@ -1098,6 +1138,8 @@ static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,
 | 
				
			||||||
			inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0,
 | 
								inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0,
 | 
				
			||||||
			ip_hdr(skb)->tos,
 | 
								ip_hdr(skb)->tos,
 | 
				
			||||||
			READ_ONCE(tcp_rsk(req)->txhash));
 | 
								READ_ONCE(tcp_rsk(req)->txhash));
 | 
				
			||||||
 | 
						if (tcp_key_is_ao(&key))
 | 
				
			||||||
 | 
							kfree(key.traffic_key);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -1636,6 +1678,10 @@ const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = {
 | 
				
			||||||
	.req_md5_lookup	=	tcp_v4_md5_lookup,
 | 
						.req_md5_lookup	=	tcp_v4_md5_lookup,
 | 
				
			||||||
	.calc_md5_hash	=	tcp_v4_md5_hash_skb,
 | 
						.calc_md5_hash	=	tcp_v4_md5_hash_skb,
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef CONFIG_TCP_AO
 | 
				
			||||||
 | 
						.ao_lookup	=	tcp_v4_ao_lookup_rsk,
 | 
				
			||||||
 | 
						.ao_calc_key	=	tcp_v4_ao_calc_key_rsk,
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
#ifdef CONFIG_SYN_COOKIES
 | 
					#ifdef CONFIG_SYN_COOKIES
 | 
				
			||||||
	.cookie_init_seq =	cookie_v4_init_sequence,
 | 
						.cookie_init_seq =	cookie_v4_init_sequence,
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -1737,12 +1783,16 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,
 | 
				
			||||||
	/* Copy over the MD5 key from the original socket */
 | 
						/* Copy over the MD5 key from the original socket */
 | 
				
			||||||
	addr = (union tcp_md5_addr *)&newinet->inet_daddr;
 | 
						addr = (union tcp_md5_addr *)&newinet->inet_daddr;
 | 
				
			||||||
	key = tcp_md5_do_lookup(sk, l3index, addr, AF_INET);
 | 
						key = tcp_md5_do_lookup(sk, l3index, addr, AF_INET);
 | 
				
			||||||
	if (key) {
 | 
						if (key && !tcp_rsk_used_ao(req)) {
 | 
				
			||||||
		if (tcp_md5_key_copy(newsk, addr, AF_INET, 32, l3index, key))
 | 
							if (tcp_md5_key_copy(newsk, addr, AF_INET, 32, l3index, key))
 | 
				
			||||||
			goto put_and_exit;
 | 
								goto put_and_exit;
 | 
				
			||||||
		sk_gso_disable(newsk);
 | 
							sk_gso_disable(newsk);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef CONFIG_TCP_AO
 | 
				
			||||||
 | 
						if (tcp_ao_copy_all_matching(sk, newsk, req, skb, AF_INET))
 | 
				
			||||||
 | 
							goto put_and_exit; /* OOM, release back memory */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (__inet_inherit_port(sk, newsk) < 0)
 | 
						if (__inet_inherit_port(sk, newsk) < 0)
 | 
				
			||||||
		goto put_and_exit;
 | 
							goto put_and_exit;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -506,6 +506,9 @@ struct sock *tcp_create_openreq_child(const struct sock *sk,
 | 
				
			||||||
	const struct tcp_sock *oldtp;
 | 
						const struct tcp_sock *oldtp;
 | 
				
			||||||
	struct tcp_sock *newtp;
 | 
						struct tcp_sock *newtp;
 | 
				
			||||||
	u32 seq;
 | 
						u32 seq;
 | 
				
			||||||
 | 
					#ifdef CONFIG_TCP_AO
 | 
				
			||||||
 | 
						struct tcp_ao_key *ao_key;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!newsk)
 | 
						if (!newsk)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
| 
						 | 
					@ -594,6 +597,13 @@ struct sock *tcp_create_openreq_child(const struct sock *sk,
 | 
				
			||||||
#ifdef CONFIG_TCP_MD5SIG
 | 
					#ifdef CONFIG_TCP_MD5SIG
 | 
				
			||||||
	newtp->md5sig_info = NULL;	/*XXX*/
 | 
						newtp->md5sig_info = NULL;	/*XXX*/
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef CONFIG_TCP_AO
 | 
				
			||||||
 | 
						newtp->ao_info = NULL;
 | 
				
			||||||
 | 
						ao_key = treq->af_specific->ao_lookup(sk, req,
 | 
				
			||||||
 | 
									tcp_rsk(req)->ao_keyid, -1);
 | 
				
			||||||
 | 
						if (ao_key)
 | 
				
			||||||
 | 
							newtp->tcp_header_len += tcp_ao_len(ao_key);
 | 
				
			||||||
 | 
					 #endif
 | 
				
			||||||
	if (skb->len >= TCP_MSS_DEFAULT + newtp->tcp_header_len)
 | 
						if (skb->len >= TCP_MSS_DEFAULT + newtp->tcp_header_len)
 | 
				
			||||||
		newicsk->icsk_ack.last_seg_size = skb->len - newtp->tcp_header_len;
 | 
							newicsk->icsk_ack.last_seg_size = skb->len - newtp->tcp_header_len;
 | 
				
			||||||
	newtp->rx_opt.mss_clamp = req->mss;
 | 
						newtp->rx_opt.mss_clamp = req->mss;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -615,6 +615,7 @@ static void bpf_skops_write_hdr_opt(struct sock *sk, struct sk_buff *skb,
 | 
				
			||||||
 * (but it may well be that other scenarios fail similarly).
 | 
					 * (but it may well be that other scenarios fail similarly).
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void tcp_options_write(struct tcphdr *th, struct tcp_sock *tp,
 | 
					static void tcp_options_write(struct tcphdr *th, struct tcp_sock *tp,
 | 
				
			||||||
 | 
								      const struct tcp_request_sock *tcprsk,
 | 
				
			||||||
			      struct tcp_out_options *opts,
 | 
								      struct tcp_out_options *opts,
 | 
				
			||||||
			      struct tcp_key *key)
 | 
								      struct tcp_key *key)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -629,20 +630,28 @@ static void tcp_options_write(struct tcphdr *th, struct tcp_sock *tp,
 | 
				
			||||||
		ptr += 4;
 | 
							ptr += 4;
 | 
				
			||||||
	} else if (tcp_key_is_ao(key)) {
 | 
						} else if (tcp_key_is_ao(key)) {
 | 
				
			||||||
#ifdef CONFIG_TCP_AO
 | 
					#ifdef CONFIG_TCP_AO
 | 
				
			||||||
		struct tcp_ao_key *rnext_key;
 | 
							u8 maclen = tcp_ao_maclen(key->ao_key);
 | 
				
			||||||
		struct tcp_ao_info *ao_info;
 | 
					 | 
				
			||||||
		u8 maclen;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ao_info = rcu_dereference_check(tp->ao_info,
 | 
							if (tcprsk) {
 | 
				
			||||||
 | 
								u8 aolen = maclen + sizeof(struct tcp_ao_hdr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								*ptr++ = htonl((TCPOPT_AO << 24) | (aolen << 16) |
 | 
				
			||||||
 | 
									       (tcprsk->ao_keyid << 8) |
 | 
				
			||||||
 | 
									       (tcprsk->ao_rcv_next));
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								struct tcp_ao_key *rnext_key;
 | 
				
			||||||
 | 
								struct tcp_ao_info *ao_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								ao_info = rcu_dereference_check(tp->ao_info,
 | 
				
			||||||
				lockdep_sock_is_held(&tp->inet_conn.icsk_inet.sk));
 | 
									lockdep_sock_is_held(&tp->inet_conn.icsk_inet.sk));
 | 
				
			||||||
		rnext_key = READ_ONCE(ao_info->rnext_key);
 | 
								rnext_key = READ_ONCE(ao_info->rnext_key);
 | 
				
			||||||
		if (WARN_ON_ONCE(!rnext_key))
 | 
								if (WARN_ON_ONCE(!rnext_key))
 | 
				
			||||||
			goto out_ao;
 | 
									goto out_ao;
 | 
				
			||||||
		maclen = tcp_ao_maclen(key->ao_key);
 | 
								*ptr++ = htonl((TCPOPT_AO << 24) |
 | 
				
			||||||
		*ptr++ = htonl((TCPOPT_AO << 24) |
 | 
									       (tcp_ao_len(key->ao_key) << 16) |
 | 
				
			||||||
				(tcp_ao_len(key->ao_key) << 16) |
 | 
									       (key->ao_key->sndid << 8) |
 | 
				
			||||||
				(key->ao_key->sndid << 8) |
 | 
									       (rnext_key->rcvid));
 | 
				
			||||||
				(rnext_key->rcvid));
 | 
							}
 | 
				
			||||||
		opts->hash_location = (__u8 *)ptr;
 | 
							opts->hash_location = (__u8 *)ptr;
 | 
				
			||||||
		ptr += maclen / sizeof(*ptr);
 | 
							ptr += maclen / sizeof(*ptr);
 | 
				
			||||||
		if (unlikely(maclen % sizeof(*ptr))) {
 | 
							if (unlikely(maclen % sizeof(*ptr))) {
 | 
				
			||||||
| 
						 | 
					@ -1386,7 +1395,7 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb,
 | 
				
			||||||
		th->window	= htons(min(tp->rcv_wnd, 65535U));
 | 
							th->window	= htons(min(tp->rcv_wnd, 65535U));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tcp_options_write(th, tp, &opts, &key);
 | 
						tcp_options_write(th, tp, NULL, &opts, &key);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (tcp_key_is_md5(&key)) {
 | 
						if (tcp_key_is_md5(&key)) {
 | 
				
			||||||
#ifdef CONFIG_TCP_MD5SIG
 | 
					#ifdef CONFIG_TCP_MD5SIG
 | 
				
			||||||
| 
						 | 
					@ -3729,7 +3738,7 @@ struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */
 | 
						/* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */
 | 
				
			||||||
	th->window = htons(min(req->rsk_rcv_wnd, 65535U));
 | 
						th->window = htons(min(req->rsk_rcv_wnd, 65535U));
 | 
				
			||||||
	tcp_options_write(th, NULL, &opts, &key);
 | 
						tcp_options_write(th, NULL, NULL, &opts, &key);
 | 
				
			||||||
	th->doff = (tcp_header_size >> 2);
 | 
						th->doff = (tcp_header_size >> 2);
 | 
				
			||||||
	TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS);
 | 
						TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -214,6 +214,8 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
 | 
				
			||||||
	treq->snt_isn = cookie;
 | 
						treq->snt_isn = cookie;
 | 
				
			||||||
	treq->ts_off = 0;
 | 
						treq->ts_off = 0;
 | 
				
			||||||
	treq->txhash = net_tx_rndhash();
 | 
						treq->txhash = net_tx_rndhash();
 | 
				
			||||||
 | 
						tcp_ao_syncookie(sk, skb, treq, AF_INET6);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (IS_ENABLED(CONFIG_SMC))
 | 
						if (IS_ENABLED(CONFIG_SMC))
 | 
				
			||||||
		ireq->smc_ok = 0;
 | 
							ireq->smc_ok = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,6 +49,17 @@ static int tcp_v6_ao_calc_key(struct tcp_ao_key *mkt, u8 *key,
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int tcp_v6_ao_calc_key_skb(struct tcp_ao_key *mkt, u8 *key,
 | 
				
			||||||
 | 
								   const struct sk_buff *skb,
 | 
				
			||||||
 | 
								   __be32 sisn, __be32 disn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					       const struct ipv6hdr *iph = ipv6_hdr(skb);
 | 
				
			||||||
 | 
					       const struct tcphdr *th = tcp_hdr(skb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       return tcp_v6_ao_calc_key(mkt, key, &iph->saddr, &iph->daddr,
 | 
				
			||||||
 | 
									 th->source, th->dest, sisn, disn);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int tcp_v6_ao_calc_key_sk(struct tcp_ao_key *mkt, u8 *key,
 | 
					int tcp_v6_ao_calc_key_sk(struct tcp_ao_key *mkt, u8 *key,
 | 
				
			||||||
			  const struct sock *sk, __be32 sisn,
 | 
								  const struct sock *sk, __be32 sisn,
 | 
				
			||||||
			  __be32 disn, bool send)
 | 
								  __be32 disn, bool send)
 | 
				
			||||||
| 
						 | 
					@ -63,9 +74,21 @@ int tcp_v6_ao_calc_key_sk(struct tcp_ao_key *mkt, u8 *key,
 | 
				
			||||||
					  htons(sk->sk_num), disn, sisn);
 | 
										  htons(sk->sk_num), disn, sisn);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct tcp_ao_key *tcp_v6_ao_do_lookup(const struct sock *sk,
 | 
					int tcp_v6_ao_calc_key_rsk(struct tcp_ao_key *mkt, u8 *key,
 | 
				
			||||||
					      const struct in6_addr *addr,
 | 
								   struct request_sock *req)
 | 
				
			||||||
					      int sndid, int rcvid)
 | 
					{
 | 
				
			||||||
 | 
						struct inet_request_sock *ireq = inet_rsk(req);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return tcp_v6_ao_calc_key(mkt, key,
 | 
				
			||||||
 | 
								&ireq->ir_v6_loc_addr, &ireq->ir_v6_rmt_addr,
 | 
				
			||||||
 | 
								htons(ireq->ir_num), ireq->ir_rmt_port,
 | 
				
			||||||
 | 
								htonl(tcp_rsk(req)->snt_isn),
 | 
				
			||||||
 | 
								htonl(tcp_rsk(req)->rcv_isn));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct tcp_ao_key *tcp_v6_ao_do_lookup(const struct sock *sk,
 | 
				
			||||||
 | 
									       const struct in6_addr *addr,
 | 
				
			||||||
 | 
									       int sndid, int rcvid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return tcp_ao_do_lookup(sk, (union tcp_ao_addr *)addr, AF_INET6,
 | 
						return tcp_ao_do_lookup(sk, (union tcp_ao_addr *)addr, AF_INET6,
 | 
				
			||||||
				sndid, rcvid);
 | 
									sndid, rcvid);
 | 
				
			||||||
| 
						 | 
					@ -80,6 +103,15 @@ struct tcp_ao_key *tcp_v6_ao_lookup(const struct sock *sk,
 | 
				
			||||||
	return tcp_v6_ao_do_lookup(sk, addr, sndid, rcvid);
 | 
						return tcp_v6_ao_do_lookup(sk, addr, sndid, rcvid);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct tcp_ao_key *tcp_v6_ao_lookup_rsk(const struct sock *sk,
 | 
				
			||||||
 | 
										struct request_sock *req,
 | 
				
			||||||
 | 
										int sndid, int rcvid)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct in6_addr *addr = &inet_rsk(req)->ir_v6_rmt_addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return tcp_v6_ao_do_lookup(sk, addr, sndid, rcvid);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int tcp_v6_ao_hash_pseudoheader(struct tcp_sigpool *hp,
 | 
					int tcp_v6_ao_hash_pseudoheader(struct tcp_sigpool *hp,
 | 
				
			||||||
				const struct in6_addr *daddr,
 | 
									const struct in6_addr *daddr,
 | 
				
			||||||
				const struct in6_addr *saddr, int nbytes)
 | 
									const struct in6_addr *saddr, int nbytes)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -836,6 +836,10 @@ const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = {
 | 
				
			||||||
	.req_md5_lookup	=	tcp_v6_md5_lookup,
 | 
						.req_md5_lookup	=	tcp_v6_md5_lookup,
 | 
				
			||||||
	.calc_md5_hash	=	tcp_v6_md5_hash_skb,
 | 
						.calc_md5_hash	=	tcp_v6_md5_hash_skb,
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef CONFIG_TCP_AO
 | 
				
			||||||
 | 
						.ao_lookup	=	tcp_v6_ao_lookup_rsk,
 | 
				
			||||||
 | 
						.ao_calc_key	=	tcp_v6_ao_calc_key_rsk,
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
#ifdef CONFIG_SYN_COOKIES
 | 
					#ifdef CONFIG_SYN_COOKIES
 | 
				
			||||||
	.cookie_init_seq =	cookie_v6_init_sequence,
 | 
						.cookie_init_seq =	cookie_v6_init_sequence,
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -1192,16 +1196,54 @@ static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct tcp_key key = {};
 | 
						struct tcp_key key = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_TCP_AO
 | 
				
			||||||
 | 
						if (tcp_rsk_used_ao(req)) {
 | 
				
			||||||
 | 
							const struct in6_addr *addr = &ipv6_hdr(skb)->saddr;
 | 
				
			||||||
 | 
							const struct tcp_ao_hdr *aoh;
 | 
				
			||||||
 | 
							int l3index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							l3index = tcp_v6_sdif(skb) ? tcp_v6_iif_l3_slave(skb) : 0;
 | 
				
			||||||
 | 
							/* Invalid TCP option size or twice included auth */
 | 
				
			||||||
 | 
							if (tcp_parse_auth_options(tcp_hdr(skb), NULL, &aoh))
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							if (!aoh)
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							key.ao_key = tcp_v6_ao_do_lookup(sk, addr, aoh->rnext_keyid, -1);
 | 
				
			||||||
 | 
							if (unlikely(!key.ao_key)) {
 | 
				
			||||||
 | 
								/* Send ACK with any matching MKT for the peer */
 | 
				
			||||||
 | 
								key.ao_key = tcp_v6_ao_do_lookup(sk, addr, -1, -1);
 | 
				
			||||||
 | 
								/* Matching key disappeared (user removed the key?)
 | 
				
			||||||
 | 
								 * let the handshake timeout.
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								if (!key.ao_key) {
 | 
				
			||||||
 | 
									net_info_ratelimited("TCP-AO key for (%pI6, %d)->(%pI6, %d) suddenly disappeared, won't ACK new connection\n",
 | 
				
			||||||
 | 
											     addr,
 | 
				
			||||||
 | 
											     ntohs(tcp_hdr(skb)->source),
 | 
				
			||||||
 | 
											     &ipv6_hdr(skb)->daddr,
 | 
				
			||||||
 | 
											     ntohs(tcp_hdr(skb)->dest));
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							key.traffic_key = kmalloc(tcp_ao_digest_size(key.ao_key), GFP_ATOMIC);
 | 
				
			||||||
 | 
							if (!key.traffic_key)
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							key.type = TCP_KEY_AO;
 | 
				
			||||||
 | 
							key.rcv_next = aoh->keyid;
 | 
				
			||||||
 | 
							tcp_v6_ao_calc_key_rsk(key.ao_key, key.traffic_key, req);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						if (0) {
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
#ifdef CONFIG_TCP_MD5SIG
 | 
					#ifdef CONFIG_TCP_MD5SIG
 | 
				
			||||||
	if (static_branch_unlikely(&tcp_md5_needed.key)) {
 | 
						} else if (static_branch_unlikely(&tcp_md5_needed.key)) {
 | 
				
			||||||
		int l3index = tcp_v6_sdif(skb) ? tcp_v6_iif_l3_slave(skb) : 0;
 | 
							int l3index = tcp_v6_sdif(skb) ? tcp_v6_iif_l3_slave(skb) : 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		key.md5_key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr,
 | 
							key.md5_key = tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->saddr,
 | 
				
			||||||
						   l3index);
 | 
											   l3index);
 | 
				
			||||||
		if (key.md5_key)
 | 
							if (key.md5_key)
 | 
				
			||||||
			key.type = TCP_KEY_MD5;
 | 
								key.type = TCP_KEY_MD5;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV
 | 
						/* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV
 | 
				
			||||||
	 * sk->sk_state == TCP_SYN_RECV -> for Fast Open.
 | 
						 * sk->sk_state == TCP_SYN_RECV -> for Fast Open.
 | 
				
			||||||
| 
						 | 
					@ -1220,6 +1262,8 @@ static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb,
 | 
				
			||||||
			&key, ipv6_get_dsfield(ipv6_hdr(skb)), 0,
 | 
								&key, ipv6_get_dsfield(ipv6_hdr(skb)), 0,
 | 
				
			||||||
			READ_ONCE(sk->sk_priority),
 | 
								READ_ONCE(sk->sk_priority),
 | 
				
			||||||
			READ_ONCE(tcp_rsk(req)->txhash));
 | 
								READ_ONCE(tcp_rsk(req)->txhash));
 | 
				
			||||||
 | 
						if (tcp_key_is_ao(&key))
 | 
				
			||||||
 | 
							kfree(key.traffic_key);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1449,19 +1493,26 @@ static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *
 | 
				
			||||||
#ifdef CONFIG_TCP_MD5SIG
 | 
					#ifdef CONFIG_TCP_MD5SIG
 | 
				
			||||||
	l3index = l3mdev_master_ifindex_by_index(sock_net(sk), ireq->ir_iif);
 | 
						l3index = l3mdev_master_ifindex_by_index(sock_net(sk), ireq->ir_iif);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Copy over the MD5 key from the original socket */
 | 
						if (!tcp_rsk_used_ao(req)) {
 | 
				
			||||||
	key = tcp_v6_md5_do_lookup(sk, &newsk->sk_v6_daddr, l3index);
 | 
							/* Copy over the MD5 key from the original socket */
 | 
				
			||||||
	if (key) {
 | 
							key = tcp_v6_md5_do_lookup(sk, &newsk->sk_v6_daddr, l3index);
 | 
				
			||||||
		const union tcp_md5_addr *addr;
 | 
							if (key) {
 | 
				
			||||||
 | 
								const union tcp_md5_addr *addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		addr = (union tcp_md5_addr *)&newsk->sk_v6_daddr;
 | 
								addr = (union tcp_md5_addr *)&newsk->sk_v6_daddr;
 | 
				
			||||||
		if (tcp_md5_key_copy(newsk, addr, AF_INET6, 128, l3index, key)) {
 | 
								if (tcp_md5_key_copy(newsk, addr, AF_INET6, 128, l3index, key)) {
 | 
				
			||||||
			inet_csk_prepare_forced_close(newsk);
 | 
									inet_csk_prepare_forced_close(newsk);
 | 
				
			||||||
			tcp_done(newsk);
 | 
									tcp_done(newsk);
 | 
				
			||||||
			goto out;
 | 
									goto out;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef CONFIG_TCP_AO
 | 
				
			||||||
 | 
						/* Copy over tcp_ao_info if any */
 | 
				
			||||||
 | 
						if (tcp_ao_copy_all_matching(sk, newsk, req, skb, AF_INET6))
 | 
				
			||||||
 | 
							goto out; /* OOM */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (__inet_inherit_port(sk, newsk) < 0) {
 | 
						if (__inet_inherit_port(sk, newsk) < 0) {
 | 
				
			||||||
		inet_csk_prepare_forced_close(newsk);
 | 
							inet_csk_prepare_forced_close(newsk);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue