This is a special code path for acks and resets outside of normal connection establishment and closing.
Signed-off-by: Leonard Crestez cdleonard@gmail.com --- net/ipv4/tcp_authopt.c | 2 ++ net/ipv6/tcp_ipv6.c | 57 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+)
diff --git a/net/ipv4/tcp_authopt.c b/net/ipv4/tcp_authopt.c index 05234923cb9f..f1213c7db63b 100644 --- a/net/ipv4/tcp_authopt.c +++ b/net/ipv4/tcp_authopt.c @@ -320,10 +320,11 @@ struct tcp_authopt_key_info *__tcp_authopt_select_key(const struct sock *sk, const struct sock *addr_sk, u8 *rnextkeyid) { return tcp_authopt_lookup_send(info, addr_sk, -1); } +EXPORT_SYMBOL(__tcp_authopt_select_key);
static struct tcp_authopt_info *__tcp_authopt_info_get_or_create(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); struct tcp_authopt_info *info; @@ -1195,10 +1196,11 @@ int tcp_authopt_hash(char *hash_location, * try to make it obvious inside the packet. */ memset(hash_location, 0, TCP_AUTHOPT_MACLEN); return err; } +EXPORT_SYMBOL(tcp_authopt_hash);
static struct tcp_authopt_key_info *tcp_authopt_lookup_recv(struct sock *sk, struct sk_buff *skb, struct tcp_authopt_info *info, int recv_id, diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 3105a367d6b5..cd8544d08a36 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -886,10 +886,48 @@ const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { .init_seq = tcp_v6_init_seq, .init_ts_off = tcp_v6_init_ts_off, .send_synack = tcp_v6_send_synack, };
+#ifdef CONFIG_TCP_AUTHOPT +static int tcp_v6_send_response_init_authopt(const struct sock *sk, + struct tcp_authopt_info **info, + struct tcp_authopt_key_info **key, + u8 *rnextkeyid) +{ + /* Key lookup before SKB allocation */ + if (!(tcp_authopt_needed && sk)) + return 0; + if (sk->sk_state == TCP_TIME_WAIT) + *info = tcp_twsk(sk)->tw_authopt_info; + else + *info = rcu_dereference(tcp_sk(sk)->authopt_info); + if (!*info) + return 0; + *key = __tcp_authopt_select_key(sk, *info, sk, rnextkeyid); + if (*key) + return TCPOLEN_AUTHOPT_OUTPUT; + return 0; +} + +static void tcp_v6_send_response_sign_authopt(const struct sock *sk, + struct tcp_authopt_info *info, + struct tcp_authopt_key_info *key, + struct sk_buff *skb, + struct tcphdr_authopt *ptr, + u8 rnextkeyid) +{ + if (!(tcp_authopt_needed && key)) + return; + ptr->num = TCPOPT_AUTHOPT; + ptr->len = TCPOLEN_AUTHOPT_OUTPUT; + ptr->keyid = key->send_id; + ptr->rnextkeyid = rnextkeyid; + tcp_authopt_hash(ptr->mac, key, info, (struct sock *)sk, skb); +} +#endif + static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 tsval, u32 tsecr, int oif, struct tcp_md5sig_key *key, int rst, u8 tclass, __be32 label, u32 priority) { @@ -901,13 +939,28 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 struct sock *ctl_sk = net->ipv6.tcp_sk; unsigned int tot_len = sizeof(struct tcphdr); __be32 mrst = 0, *topt; struct dst_entry *dst; __u32 mark = 0; +#ifdef CONFIG_TCP_AUTHOPT + struct tcp_authopt_info *aoinfo; + struct tcp_authopt_key_info *aokey; + u8 aornextkeyid; + int aolen; +#endif
if (tsecr) tot_len += TCPOLEN_TSTAMP_ALIGNED; +#ifdef CONFIG_TCP_AUTHOPT + /* Key lookup before SKB allocation */ + aolen = tcp_v6_send_response_init_authopt(sk, &aoinfo, &aokey, &aornextkeyid); + if (aolen) { + tot_len += aolen; + /* Don't use MD5 */ + key = NULL; + } +#endif #ifdef CONFIG_TCP_MD5SIG if (key) tot_len += TCPOLEN_MD5SIG_ALIGNED; #endif
@@ -960,10 +1013,14 @@ static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 tcp_v6_md5_hash_hdr((__u8 *)topt, key, &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, t1); } #endif +#ifdef CONFIG_TCP_AUTHOPT + tcp_v6_send_response_sign_authopt(sk, aoinfo, aokey, buff, + (struct tcphdr_authopt *)topt, aornextkeyid); +#endif
memset(&fl6, 0, sizeof(fl6)); fl6.daddr = ipv6_hdr(skb)->saddr; fl6.saddr = ipv6_hdr(skb)->daddr; fl6.flowlabel = label;