144fd1c1fSVinay Kumar Yadav // SPDX-License-Identifier: GPL-2.0-only
244fd1c1fSVinay Kumar Yadav /*
344fd1c1fSVinay Kumar Yadav  * Copyright (c) 2018 Chelsio Communications, Inc.
444fd1c1fSVinay Kumar Yadav  *
544fd1c1fSVinay Kumar Yadav  * Written by: Atul Gupta (atul.gupta@chelsio.com)
644fd1c1fSVinay Kumar Yadav  */
744fd1c1fSVinay Kumar Yadav 
844fd1c1fSVinay Kumar Yadav #include <linux/module.h>
944fd1c1fSVinay Kumar Yadav #include <linux/list.h>
1044fd1c1fSVinay Kumar Yadav #include <linux/workqueue.h>
1144fd1c1fSVinay Kumar Yadav #include <linux/skbuff.h>
1244fd1c1fSVinay Kumar Yadav #include <linux/timer.h>
1344fd1c1fSVinay Kumar Yadav #include <linux/notifier.h>
1444fd1c1fSVinay Kumar Yadav #include <linux/inetdevice.h>
1544fd1c1fSVinay Kumar Yadav #include <linux/ip.h>
1644fd1c1fSVinay Kumar Yadav #include <linux/tcp.h>
1744fd1c1fSVinay Kumar Yadav #include <linux/tls.h>
1844fd1c1fSVinay Kumar Yadav #include <net/tls.h>
1944fd1c1fSVinay Kumar Yadav 
2044fd1c1fSVinay Kumar Yadav #include "chtls.h"
2144fd1c1fSVinay Kumar Yadav #include "chtls_cm.h"
2244fd1c1fSVinay Kumar Yadav 
__set_tcb_field_direct(struct chtls_sock * csk,struct cpl_set_tcb_field * req,u16 word,u64 mask,u64 val,u8 cookie,int no_reply)2344fd1c1fSVinay Kumar Yadav static void __set_tcb_field_direct(struct chtls_sock *csk,
2444fd1c1fSVinay Kumar Yadav 				   struct cpl_set_tcb_field *req, u16 word,
2544fd1c1fSVinay Kumar Yadav 				   u64 mask, u64 val, u8 cookie, int no_reply)
2644fd1c1fSVinay Kumar Yadav {
2744fd1c1fSVinay Kumar Yadav 	struct ulptx_idata *sc;
2844fd1c1fSVinay Kumar Yadav 
2944fd1c1fSVinay Kumar Yadav 	INIT_TP_WR_CPL(req, CPL_SET_TCB_FIELD, csk->tid);
3044fd1c1fSVinay Kumar Yadav 	req->wr.wr_mid |= htonl(FW_WR_FLOWID_V(csk->tid));
3144fd1c1fSVinay Kumar Yadav 	req->reply_ctrl = htons(NO_REPLY_V(no_reply) |
3244fd1c1fSVinay Kumar Yadav 				QUEUENO_V(csk->rss_qid));
3344fd1c1fSVinay Kumar Yadav 	req->word_cookie = htons(TCB_WORD_V(word) | TCB_COOKIE_V(cookie));
3444fd1c1fSVinay Kumar Yadav 	req->mask = cpu_to_be64(mask);
3544fd1c1fSVinay Kumar Yadav 	req->val = cpu_to_be64(val);
3644fd1c1fSVinay Kumar Yadav 	sc = (struct ulptx_idata *)(req + 1);
3744fd1c1fSVinay Kumar Yadav 	sc->cmd_more = htonl(ULPTX_CMD_V(ULP_TX_SC_NOOP));
3844fd1c1fSVinay Kumar Yadav 	sc->len = htonl(0);
3944fd1c1fSVinay Kumar Yadav }
4044fd1c1fSVinay Kumar Yadav 
__set_tcb_field(struct sock * sk,struct sk_buff * skb,u16 word,u64 mask,u64 val,u8 cookie,int no_reply)4144fd1c1fSVinay Kumar Yadav static void __set_tcb_field(struct sock *sk, struct sk_buff *skb, u16 word,
4244fd1c1fSVinay Kumar Yadav 			    u64 mask, u64 val, u8 cookie, int no_reply)
4344fd1c1fSVinay Kumar Yadav {
4444fd1c1fSVinay Kumar Yadav 	struct cpl_set_tcb_field *req;
4544fd1c1fSVinay Kumar Yadav 	struct chtls_sock *csk;
4644fd1c1fSVinay Kumar Yadav 	struct ulptx_idata *sc;
4744fd1c1fSVinay Kumar Yadav 	unsigned int wrlen;
4844fd1c1fSVinay Kumar Yadav 
4944fd1c1fSVinay Kumar Yadav 	wrlen = roundup(sizeof(*req) + sizeof(*sc), 16);
5044fd1c1fSVinay Kumar Yadav 	csk = rcu_dereference_sk_user_data(sk);
5144fd1c1fSVinay Kumar Yadav 
5244fd1c1fSVinay Kumar Yadav 	req = (struct cpl_set_tcb_field *)__skb_put(skb, wrlen);
5344fd1c1fSVinay Kumar Yadav 	__set_tcb_field_direct(csk, req, word, mask, val, cookie, no_reply);
5444fd1c1fSVinay Kumar Yadav 	set_wr_txq(skb, CPL_PRIORITY_CONTROL, csk->port_id);
5544fd1c1fSVinay Kumar Yadav }
5644fd1c1fSVinay Kumar Yadav 
5744fd1c1fSVinay Kumar Yadav /*
5844fd1c1fSVinay Kumar Yadav  * Send control message to HW, message go as immediate data and packet
5944fd1c1fSVinay Kumar Yadav  * is freed immediately.
6044fd1c1fSVinay Kumar Yadav  */
chtls_set_tcb_field(struct sock * sk,u16 word,u64 mask,u64 val)6144fd1c1fSVinay Kumar Yadav static int chtls_set_tcb_field(struct sock *sk, u16 word, u64 mask, u64 val)
6244fd1c1fSVinay Kumar Yadav {
6344fd1c1fSVinay Kumar Yadav 	struct cpl_set_tcb_field *req;
6444fd1c1fSVinay Kumar Yadav 	unsigned int credits_needed;
6544fd1c1fSVinay Kumar Yadav 	struct chtls_sock *csk;
6644fd1c1fSVinay Kumar Yadav 	struct ulptx_idata *sc;
6744fd1c1fSVinay Kumar Yadav 	struct sk_buff *skb;
6844fd1c1fSVinay Kumar Yadav 	unsigned int wrlen;
6944fd1c1fSVinay Kumar Yadav 	int ret;
7044fd1c1fSVinay Kumar Yadav 
7144fd1c1fSVinay Kumar Yadav 	wrlen = roundup(sizeof(*req) + sizeof(*sc), 16);
7244fd1c1fSVinay Kumar Yadav 
7344fd1c1fSVinay Kumar Yadav 	skb = alloc_skb(wrlen, GFP_ATOMIC);
7444fd1c1fSVinay Kumar Yadav 	if (!skb)
7544fd1c1fSVinay Kumar Yadav 		return -ENOMEM;
7644fd1c1fSVinay Kumar Yadav 
7744fd1c1fSVinay Kumar Yadav 	credits_needed = DIV_ROUND_UP(wrlen, 16);
7844fd1c1fSVinay Kumar Yadav 	csk = rcu_dereference_sk_user_data(sk);
7944fd1c1fSVinay Kumar Yadav 
8044fd1c1fSVinay Kumar Yadav 	__set_tcb_field(sk, skb, word, mask, val, 0, 1);
8144fd1c1fSVinay Kumar Yadav 	skb_set_queue_mapping(skb, (csk->txq_idx << 1) | CPL_PRIORITY_DATA);
8244fd1c1fSVinay Kumar Yadav 	csk->wr_credits -= credits_needed;
8344fd1c1fSVinay Kumar Yadav 	csk->wr_unacked += credits_needed;
8444fd1c1fSVinay Kumar Yadav 	enqueue_wr(csk, skb);
8544fd1c1fSVinay Kumar Yadav 	ret = cxgb4_ofld_send(csk->egress_dev, skb);
8644fd1c1fSVinay Kumar Yadav 	if (ret < 0)
8744fd1c1fSVinay Kumar Yadav 		kfree_skb(skb);
8844fd1c1fSVinay Kumar Yadav 	return ret < 0 ? ret : 0;
8944fd1c1fSVinay Kumar Yadav }
9044fd1c1fSVinay Kumar Yadav 
chtls_set_tcb_field_rpl_skb(struct sock * sk,u16 word,u64 mask,u64 val,u8 cookie,int through_l2t)91*8ad2a970SAyush Sawal void chtls_set_tcb_field_rpl_skb(struct sock *sk, u16 word,
92*8ad2a970SAyush Sawal 				 u64 mask, u64 val, u8 cookie,
93*8ad2a970SAyush Sawal 				 int through_l2t)
94*8ad2a970SAyush Sawal {
95*8ad2a970SAyush Sawal 	struct sk_buff *skb;
96*8ad2a970SAyush Sawal 	unsigned int wrlen;
97*8ad2a970SAyush Sawal 
98*8ad2a970SAyush Sawal 	wrlen = sizeof(struct cpl_set_tcb_field) + sizeof(struct ulptx_idata);
99*8ad2a970SAyush Sawal 	wrlen = roundup(wrlen, 16);
100*8ad2a970SAyush Sawal 
101*8ad2a970SAyush Sawal 	skb = alloc_skb(wrlen, GFP_KERNEL | __GFP_NOFAIL);
102*8ad2a970SAyush Sawal 	if (!skb)
103*8ad2a970SAyush Sawal 		return;
104*8ad2a970SAyush Sawal 
105*8ad2a970SAyush Sawal 	__set_tcb_field(sk, skb, word, mask, val, cookie, 0);
106*8ad2a970SAyush Sawal 	send_or_defer(sk, tcp_sk(sk), skb, through_l2t);
107*8ad2a970SAyush Sawal }
108*8ad2a970SAyush Sawal 
10944fd1c1fSVinay Kumar Yadav /*
11044fd1c1fSVinay Kumar Yadav  * Set one of the t_flags bits in the TCB.
11144fd1c1fSVinay Kumar Yadav  */
chtls_set_tcb_tflag(struct sock * sk,unsigned int bit_pos,int val)11244fd1c1fSVinay Kumar Yadav int chtls_set_tcb_tflag(struct sock *sk, unsigned int bit_pos, int val)
11344fd1c1fSVinay Kumar Yadav {
11444fd1c1fSVinay Kumar Yadav 	return chtls_set_tcb_field(sk, 1, 1ULL << bit_pos,
11544fd1c1fSVinay Kumar Yadav 				   (u64)val << bit_pos);
11644fd1c1fSVinay Kumar Yadav }
11744fd1c1fSVinay Kumar Yadav 
chtls_set_tcb_keyid(struct sock * sk,int keyid)11844fd1c1fSVinay Kumar Yadav static int chtls_set_tcb_keyid(struct sock *sk, int keyid)
11944fd1c1fSVinay Kumar Yadav {
12044fd1c1fSVinay Kumar Yadav 	return chtls_set_tcb_field(sk, 31, 0xFFFFFFFFULL, keyid);
12144fd1c1fSVinay Kumar Yadav }
12244fd1c1fSVinay Kumar Yadav 
chtls_set_tcb_seqno(struct sock * sk)12344fd1c1fSVinay Kumar Yadav static int chtls_set_tcb_seqno(struct sock *sk)
12444fd1c1fSVinay Kumar Yadav {
12544fd1c1fSVinay Kumar Yadav 	return chtls_set_tcb_field(sk, 28, ~0ULL, 0);
12644fd1c1fSVinay Kumar Yadav }
12744fd1c1fSVinay Kumar Yadav 
chtls_set_tcb_quiesce(struct sock * sk,int val)12844fd1c1fSVinay Kumar Yadav static int chtls_set_tcb_quiesce(struct sock *sk, int val)
12944fd1c1fSVinay Kumar Yadav {
13044fd1c1fSVinay Kumar Yadav 	return chtls_set_tcb_field(sk, 1, (1ULL << TF_RX_QUIESCE_S),
13144fd1c1fSVinay Kumar Yadav 				   TF_RX_QUIESCE_V(val));
13244fd1c1fSVinay Kumar Yadav }
13344fd1c1fSVinay Kumar Yadav 
chtls_set_quiesce_ctrl(struct sock * sk,int val)134*8ad2a970SAyush Sawal void chtls_set_quiesce_ctrl(struct sock *sk, int val)
135*8ad2a970SAyush Sawal {
136*8ad2a970SAyush Sawal 	struct chtls_sock *csk;
137*8ad2a970SAyush Sawal 	struct sk_buff *skb;
138*8ad2a970SAyush Sawal 	unsigned int wrlen;
139*8ad2a970SAyush Sawal 	int ret;
140*8ad2a970SAyush Sawal 
141*8ad2a970SAyush Sawal 	wrlen = sizeof(struct cpl_set_tcb_field) + sizeof(struct ulptx_idata);
142*8ad2a970SAyush Sawal 	wrlen = roundup(wrlen, 16);
143*8ad2a970SAyush Sawal 
144*8ad2a970SAyush Sawal 	skb = alloc_skb(wrlen, GFP_ATOMIC);
145*8ad2a970SAyush Sawal 	if (!skb)
146*8ad2a970SAyush Sawal 		return;
147*8ad2a970SAyush Sawal 
148*8ad2a970SAyush Sawal 	csk = rcu_dereference_sk_user_data(sk);
149*8ad2a970SAyush Sawal 
150*8ad2a970SAyush Sawal 	__set_tcb_field(sk, skb, 1, TF_RX_QUIESCE_V(1), 0, 0, 1);
151*8ad2a970SAyush Sawal 	set_wr_txq(skb, CPL_PRIORITY_CONTROL, csk->port_id);
152*8ad2a970SAyush Sawal 	ret = cxgb4_ofld_send(csk->egress_dev, skb);
153*8ad2a970SAyush Sawal 	if (ret < 0)
154*8ad2a970SAyush Sawal 		kfree_skb(skb);
155*8ad2a970SAyush Sawal }
156*8ad2a970SAyush Sawal 
15744fd1c1fSVinay Kumar Yadav /* TLS Key bitmap processing */
chtls_init_kmap(struct chtls_dev * cdev,struct cxgb4_lld_info * lldi)15844fd1c1fSVinay Kumar Yadav int chtls_init_kmap(struct chtls_dev *cdev, struct cxgb4_lld_info *lldi)
15944fd1c1fSVinay Kumar Yadav {
16044fd1c1fSVinay Kumar Yadav 	unsigned int num_key_ctx, bsize;
16144fd1c1fSVinay Kumar Yadav 	int ksize;
16244fd1c1fSVinay Kumar Yadav 
16344fd1c1fSVinay Kumar Yadav 	num_key_ctx = (lldi->vr->key.size / TLS_KEY_CONTEXT_SZ);
16444fd1c1fSVinay Kumar Yadav 	bsize = BITS_TO_LONGS(num_key_ctx);
16544fd1c1fSVinay Kumar Yadav 
16644fd1c1fSVinay Kumar Yadav 	cdev->kmap.size = num_key_ctx;
16744fd1c1fSVinay Kumar Yadav 	cdev->kmap.available = bsize;
16844fd1c1fSVinay Kumar Yadav 	ksize = sizeof(*cdev->kmap.addr) * bsize;
16944fd1c1fSVinay Kumar Yadav 	cdev->kmap.addr = kvzalloc(ksize, GFP_KERNEL);
17044fd1c1fSVinay Kumar Yadav 	if (!cdev->kmap.addr)
17144fd1c1fSVinay Kumar Yadav 		return -ENOMEM;
17244fd1c1fSVinay Kumar Yadav 
17344fd1c1fSVinay Kumar Yadav 	cdev->kmap.start = lldi->vr->key.start;
17444fd1c1fSVinay Kumar Yadav 	spin_lock_init(&cdev->kmap.lock);
17544fd1c1fSVinay Kumar Yadav 	return 0;
17644fd1c1fSVinay Kumar Yadav }
17744fd1c1fSVinay Kumar Yadav 
get_new_keyid(struct chtls_sock * csk,u32 optname)17844fd1c1fSVinay Kumar Yadav static int get_new_keyid(struct chtls_sock *csk, u32 optname)
17944fd1c1fSVinay Kumar Yadav {
18044fd1c1fSVinay Kumar Yadav 	struct net_device *dev = csk->egress_dev;
18144fd1c1fSVinay Kumar Yadav 	struct chtls_dev *cdev = csk->cdev;
18244fd1c1fSVinay Kumar Yadav 	struct chtls_hws *hws;
18344fd1c1fSVinay Kumar Yadav 	struct adapter *adap;
18444fd1c1fSVinay Kumar Yadav 	int keyid;
18544fd1c1fSVinay Kumar Yadav 
18644fd1c1fSVinay Kumar Yadav 	adap = netdev2adap(dev);
18744fd1c1fSVinay Kumar Yadav 	hws = &csk->tlshws;
18844fd1c1fSVinay Kumar Yadav 
18944fd1c1fSVinay Kumar Yadav 	spin_lock_bh(&cdev->kmap.lock);
19044fd1c1fSVinay Kumar Yadav 	keyid = find_first_zero_bit(cdev->kmap.addr, cdev->kmap.size);
19144fd1c1fSVinay Kumar Yadav 	if (keyid < cdev->kmap.size) {
19244fd1c1fSVinay Kumar Yadav 		__set_bit(keyid, cdev->kmap.addr);
19344fd1c1fSVinay Kumar Yadav 		if (optname == TLS_RX)
19444fd1c1fSVinay Kumar Yadav 			hws->rxkey = keyid;
19544fd1c1fSVinay Kumar Yadav 		else
19644fd1c1fSVinay Kumar Yadav 			hws->txkey = keyid;
19744fd1c1fSVinay Kumar Yadav 		atomic_inc(&adap->chcr_stats.tls_key);
19844fd1c1fSVinay Kumar Yadav 	} else {
19944fd1c1fSVinay Kumar Yadav 		keyid = -1;
20044fd1c1fSVinay Kumar Yadav 	}
20144fd1c1fSVinay Kumar Yadav 	spin_unlock_bh(&cdev->kmap.lock);
20244fd1c1fSVinay Kumar Yadav 	return keyid;
20344fd1c1fSVinay Kumar Yadav }
20444fd1c1fSVinay Kumar Yadav 
free_tls_keyid(struct sock * sk)20544fd1c1fSVinay Kumar Yadav void free_tls_keyid(struct sock *sk)
20644fd1c1fSVinay Kumar Yadav {
20744fd1c1fSVinay Kumar Yadav 	struct chtls_sock *csk = rcu_dereference_sk_user_data(sk);
20844fd1c1fSVinay Kumar Yadav 	struct net_device *dev = csk->egress_dev;
20944fd1c1fSVinay Kumar Yadav 	struct chtls_dev *cdev = csk->cdev;
21044fd1c1fSVinay Kumar Yadav 	struct chtls_hws *hws;
21144fd1c1fSVinay Kumar Yadav 	struct adapter *adap;
21244fd1c1fSVinay Kumar Yadav 
21344fd1c1fSVinay Kumar Yadav 	if (!cdev->kmap.addr)
21444fd1c1fSVinay Kumar Yadav 		return;
21544fd1c1fSVinay Kumar Yadav 
21644fd1c1fSVinay Kumar Yadav 	adap = netdev2adap(dev);
21744fd1c1fSVinay Kumar Yadav 	hws = &csk->tlshws;
21844fd1c1fSVinay Kumar Yadav 
21944fd1c1fSVinay Kumar Yadav 	spin_lock_bh(&cdev->kmap.lock);
22044fd1c1fSVinay Kumar Yadav 	if (hws->rxkey >= 0) {
22144fd1c1fSVinay Kumar Yadav 		__clear_bit(hws->rxkey, cdev->kmap.addr);
22244fd1c1fSVinay Kumar Yadav 		atomic_dec(&adap->chcr_stats.tls_key);
22344fd1c1fSVinay Kumar Yadav 		hws->rxkey = -1;
22444fd1c1fSVinay Kumar Yadav 	}
22544fd1c1fSVinay Kumar Yadav 	if (hws->txkey >= 0) {
22644fd1c1fSVinay Kumar Yadav 		__clear_bit(hws->txkey, cdev->kmap.addr);
22744fd1c1fSVinay Kumar Yadav 		atomic_dec(&adap->chcr_stats.tls_key);
22844fd1c1fSVinay Kumar Yadav 		hws->txkey = -1;
22944fd1c1fSVinay Kumar Yadav 	}
23044fd1c1fSVinay Kumar Yadav 	spin_unlock_bh(&cdev->kmap.lock);
23144fd1c1fSVinay Kumar Yadav }
23244fd1c1fSVinay Kumar Yadav 
keyid_to_addr(int start_addr,int keyid)23344fd1c1fSVinay Kumar Yadav unsigned int keyid_to_addr(int start_addr, int keyid)
23444fd1c1fSVinay Kumar Yadav {
23544fd1c1fSVinay Kumar Yadav 	return (start_addr + (keyid * TLS_KEY_CONTEXT_SZ)) >> 5;
23644fd1c1fSVinay Kumar Yadav }
23744fd1c1fSVinay Kumar Yadav 
chtls_rxkey_ivauth(struct _key_ctx * kctx)23844fd1c1fSVinay Kumar Yadav static void chtls_rxkey_ivauth(struct _key_ctx *kctx)
23944fd1c1fSVinay Kumar Yadav {
24044fd1c1fSVinay Kumar Yadav 	kctx->iv_to_auth = cpu_to_be64(KEYCTX_TX_WR_IV_V(6ULL) |
24144fd1c1fSVinay Kumar Yadav 				  KEYCTX_TX_WR_AAD_V(1ULL) |
24244fd1c1fSVinay Kumar Yadav 				  KEYCTX_TX_WR_AADST_V(5ULL) |
24344fd1c1fSVinay Kumar Yadav 				  KEYCTX_TX_WR_CIPHER_V(14ULL) |
24444fd1c1fSVinay Kumar Yadav 				  KEYCTX_TX_WR_CIPHERST_V(0ULL) |
24544fd1c1fSVinay Kumar Yadav 				  KEYCTX_TX_WR_AUTH_V(14ULL) |
24644fd1c1fSVinay Kumar Yadav 				  KEYCTX_TX_WR_AUTHST_V(16ULL) |
24744fd1c1fSVinay Kumar Yadav 				  KEYCTX_TX_WR_AUTHIN_V(16ULL));
24844fd1c1fSVinay Kumar Yadav }
24944fd1c1fSVinay Kumar Yadav 
chtls_key_info(struct chtls_sock * csk,struct _key_ctx * kctx,u32 keylen,u32 optname,int cipher_type)25044fd1c1fSVinay Kumar Yadav static int chtls_key_info(struct chtls_sock *csk,
25144fd1c1fSVinay Kumar Yadav 			  struct _key_ctx *kctx,
25244fd1c1fSVinay Kumar Yadav 			  u32 keylen, u32 optname,
25344fd1c1fSVinay Kumar Yadav 			  int cipher_type)
25444fd1c1fSVinay Kumar Yadav {
25544fd1c1fSVinay Kumar Yadav 	unsigned char key[AES_MAX_KEY_SIZE];
25644fd1c1fSVinay Kumar Yadav 	unsigned char *key_p, *salt;
25744fd1c1fSVinay Kumar Yadav 	unsigned char ghash_h[AEAD_H_SIZE];
25844fd1c1fSVinay Kumar Yadav 	int ck_size, key_ctx_size, kctx_mackey_size, salt_size;
25944fd1c1fSVinay Kumar Yadav 	struct crypto_aes_ctx aes;
26044fd1c1fSVinay Kumar Yadav 	int ret;
26144fd1c1fSVinay Kumar Yadav 
26244fd1c1fSVinay Kumar Yadav 	key_ctx_size = sizeof(struct _key_ctx) +
26344fd1c1fSVinay Kumar Yadav 		       roundup(keylen, 16) + AEAD_H_SIZE;
26444fd1c1fSVinay Kumar Yadav 
26544fd1c1fSVinay Kumar Yadav 	/* GCM mode of AES supports 128 and 256 bit encryption, so
26644fd1c1fSVinay Kumar Yadav 	 * prepare key context base on GCM cipher type
26744fd1c1fSVinay Kumar Yadav 	 */
26844fd1c1fSVinay Kumar Yadav 	switch (cipher_type) {
26944fd1c1fSVinay Kumar Yadav 	case TLS_CIPHER_AES_GCM_128: {
27044fd1c1fSVinay Kumar Yadav 		struct tls12_crypto_info_aes_gcm_128 *gcm_ctx_128 =
27144fd1c1fSVinay Kumar Yadav 			(struct tls12_crypto_info_aes_gcm_128 *)
27244fd1c1fSVinay Kumar Yadav 					&csk->tlshws.crypto_info;
27344fd1c1fSVinay Kumar Yadav 		memcpy(key, gcm_ctx_128->key, keylen);
27444fd1c1fSVinay Kumar Yadav 
27544fd1c1fSVinay Kumar Yadav 		key_p            = gcm_ctx_128->key;
27644fd1c1fSVinay Kumar Yadav 		salt             = gcm_ctx_128->salt;
27744fd1c1fSVinay Kumar Yadav 		ck_size          = CHCR_KEYCTX_CIPHER_KEY_SIZE_128;
27844fd1c1fSVinay Kumar Yadav 		salt_size        = TLS_CIPHER_AES_GCM_128_SALT_SIZE;
27944fd1c1fSVinay Kumar Yadav 		kctx_mackey_size = CHCR_KEYCTX_MAC_KEY_SIZE_128;
28044fd1c1fSVinay Kumar Yadav 		break;
28144fd1c1fSVinay Kumar Yadav 	}
28244fd1c1fSVinay Kumar Yadav 	case TLS_CIPHER_AES_GCM_256: {
28344fd1c1fSVinay Kumar Yadav 		struct tls12_crypto_info_aes_gcm_256 *gcm_ctx_256 =
28444fd1c1fSVinay Kumar Yadav 			(struct tls12_crypto_info_aes_gcm_256 *)
28544fd1c1fSVinay Kumar Yadav 					&csk->tlshws.crypto_info;
28644fd1c1fSVinay Kumar Yadav 		memcpy(key, gcm_ctx_256->key, keylen);
28744fd1c1fSVinay Kumar Yadav 
28844fd1c1fSVinay Kumar Yadav 		key_p            = gcm_ctx_256->key;
28944fd1c1fSVinay Kumar Yadav 		salt             = gcm_ctx_256->salt;
29044fd1c1fSVinay Kumar Yadav 		ck_size          = CHCR_KEYCTX_CIPHER_KEY_SIZE_256;
29144fd1c1fSVinay Kumar Yadav 		salt_size        = TLS_CIPHER_AES_GCM_256_SALT_SIZE;
29244fd1c1fSVinay Kumar Yadav 		kctx_mackey_size = CHCR_KEYCTX_MAC_KEY_SIZE_256;
29344fd1c1fSVinay Kumar Yadav 		break;
29444fd1c1fSVinay Kumar Yadav 	}
29544fd1c1fSVinay Kumar Yadav 	default:
29644fd1c1fSVinay Kumar Yadav 		pr_err("GCM: Invalid key length %d\n", keylen);
29744fd1c1fSVinay Kumar Yadav 		return -EINVAL;
29844fd1c1fSVinay Kumar Yadav 	}
29944fd1c1fSVinay Kumar Yadav 
30044fd1c1fSVinay Kumar Yadav 	/* Calculate the H = CIPH(K, 0 repeated 16 times).
30144fd1c1fSVinay Kumar Yadav 	 * It will go in key context
30244fd1c1fSVinay Kumar Yadav 	 */
30344fd1c1fSVinay Kumar Yadav 	ret = aes_expandkey(&aes, key, keylen);
30444fd1c1fSVinay Kumar Yadav 	if (ret)
30544fd1c1fSVinay Kumar Yadav 		return ret;
30644fd1c1fSVinay Kumar Yadav 
30744fd1c1fSVinay Kumar Yadav 	memset(ghash_h, 0, AEAD_H_SIZE);
30844fd1c1fSVinay Kumar Yadav 	aes_encrypt(&aes, ghash_h, ghash_h);
30944fd1c1fSVinay Kumar Yadav 	memzero_explicit(&aes, sizeof(aes));
31044fd1c1fSVinay Kumar Yadav 	csk->tlshws.keylen = key_ctx_size;
31144fd1c1fSVinay Kumar Yadav 
31244fd1c1fSVinay Kumar Yadav 	/* Copy the Key context */
31344fd1c1fSVinay Kumar Yadav 	if (optname == TLS_RX) {
31444fd1c1fSVinay Kumar Yadav 		int key_ctx;
31544fd1c1fSVinay Kumar Yadav 
31644fd1c1fSVinay Kumar Yadav 		key_ctx = ((key_ctx_size >> 4) << 3);
31744fd1c1fSVinay Kumar Yadav 		kctx->ctx_hdr = FILL_KEY_CRX_HDR(ck_size,
31844fd1c1fSVinay Kumar Yadav 						 kctx_mackey_size,
31944fd1c1fSVinay Kumar Yadav 						 0, 0, key_ctx);
32044fd1c1fSVinay Kumar Yadav 		chtls_rxkey_ivauth(kctx);
32144fd1c1fSVinay Kumar Yadav 	} else {
32244fd1c1fSVinay Kumar Yadav 		kctx->ctx_hdr = FILL_KEY_CTX_HDR(ck_size,
32344fd1c1fSVinay Kumar Yadav 						 kctx_mackey_size,
32444fd1c1fSVinay Kumar Yadav 						 0, 0, key_ctx_size >> 4);
32544fd1c1fSVinay Kumar Yadav 	}
32644fd1c1fSVinay Kumar Yadav 
32744fd1c1fSVinay Kumar Yadav 	memcpy(kctx->salt, salt, salt_size);
32844fd1c1fSVinay Kumar Yadav 	memcpy(kctx->key, key_p, keylen);
32944fd1c1fSVinay Kumar Yadav 	memcpy(kctx->key + keylen, ghash_h, AEAD_H_SIZE);
33044fd1c1fSVinay Kumar Yadav 	/* erase key info from driver */
33144fd1c1fSVinay Kumar Yadav 	memset(key_p, 0, keylen);
33244fd1c1fSVinay Kumar Yadav 
33344fd1c1fSVinay Kumar Yadav 	return 0;
33444fd1c1fSVinay Kumar Yadav }
33544fd1c1fSVinay Kumar Yadav 
chtls_set_scmd(struct chtls_sock * csk)33644fd1c1fSVinay Kumar Yadav static void chtls_set_scmd(struct chtls_sock *csk)
33744fd1c1fSVinay Kumar Yadav {
33844fd1c1fSVinay Kumar Yadav 	struct chtls_hws *hws = &csk->tlshws;
33944fd1c1fSVinay Kumar Yadav 
34044fd1c1fSVinay Kumar Yadav 	hws->scmd.seqno_numivs =
34144fd1c1fSVinay Kumar Yadav 		SCMD_SEQ_NO_CTRL_V(3) |
34244fd1c1fSVinay Kumar Yadav 		SCMD_PROTO_VERSION_V(0) |
34344fd1c1fSVinay Kumar Yadav 		SCMD_ENC_DEC_CTRL_V(0) |
34444fd1c1fSVinay Kumar Yadav 		SCMD_CIPH_AUTH_SEQ_CTRL_V(1) |
34544fd1c1fSVinay Kumar Yadav 		SCMD_CIPH_MODE_V(2) |
34644fd1c1fSVinay Kumar Yadav 		SCMD_AUTH_MODE_V(4) |
34744fd1c1fSVinay Kumar Yadav 		SCMD_HMAC_CTRL_V(0) |
34844fd1c1fSVinay Kumar Yadav 		SCMD_IV_SIZE_V(4) |
34944fd1c1fSVinay Kumar Yadav 		SCMD_NUM_IVS_V(1);
35044fd1c1fSVinay Kumar Yadav 
35144fd1c1fSVinay Kumar Yadav 	hws->scmd.ivgen_hdrlen =
35244fd1c1fSVinay Kumar Yadav 		SCMD_IV_GEN_CTRL_V(1) |
35344fd1c1fSVinay Kumar Yadav 		SCMD_KEY_CTX_INLINE_V(0) |
35444fd1c1fSVinay Kumar Yadav 		SCMD_TLS_FRAG_ENABLE_V(1);
35544fd1c1fSVinay Kumar Yadav }
35644fd1c1fSVinay Kumar Yadav 
chtls_setkey(struct chtls_sock * csk,u32 keylen,u32 optname,int cipher_type)35744fd1c1fSVinay Kumar Yadav int chtls_setkey(struct chtls_sock *csk, u32 keylen,
35844fd1c1fSVinay Kumar Yadav 		 u32 optname, int cipher_type)
35944fd1c1fSVinay Kumar Yadav {
36044fd1c1fSVinay Kumar Yadav 	struct tls_key_req *kwr;
36144fd1c1fSVinay Kumar Yadav 	struct chtls_dev *cdev;
36244fd1c1fSVinay Kumar Yadav 	struct _key_ctx *kctx;
36344fd1c1fSVinay Kumar Yadav 	int wrlen, klen, len;
36444fd1c1fSVinay Kumar Yadav 	struct sk_buff *skb;
36544fd1c1fSVinay Kumar Yadav 	struct sock *sk;
36644fd1c1fSVinay Kumar Yadav 	int keyid;
36744fd1c1fSVinay Kumar Yadav 	int kaddr;
36844fd1c1fSVinay Kumar Yadav 	int ret;
36944fd1c1fSVinay Kumar Yadav 
37044fd1c1fSVinay Kumar Yadav 	cdev = csk->cdev;
37144fd1c1fSVinay Kumar Yadav 	sk = csk->sk;
37244fd1c1fSVinay Kumar Yadav 
37344fd1c1fSVinay Kumar Yadav 	klen = roundup((keylen + AEAD_H_SIZE) + sizeof(*kctx), 32);
37444fd1c1fSVinay Kumar Yadav 	wrlen = roundup(sizeof(*kwr), 16);
37544fd1c1fSVinay Kumar Yadav 	len = klen + wrlen;
37644fd1c1fSVinay Kumar Yadav 
37744fd1c1fSVinay Kumar Yadav 	/* Flush out-standing data before new key takes effect */
37844fd1c1fSVinay Kumar Yadav 	if (optname == TLS_TX) {
37944fd1c1fSVinay Kumar Yadav 		lock_sock(sk);
38044fd1c1fSVinay Kumar Yadav 		if (skb_queue_len(&csk->txq))
38144fd1c1fSVinay Kumar Yadav 			chtls_push_frames(csk, 0);
38244fd1c1fSVinay Kumar Yadav 		release_sock(sk);
38344fd1c1fSVinay Kumar Yadav 	}
38444fd1c1fSVinay Kumar Yadav 
38544fd1c1fSVinay Kumar Yadav 	skb = alloc_skb(len, GFP_KERNEL);
38644fd1c1fSVinay Kumar Yadav 	if (!skb)
38744fd1c1fSVinay Kumar Yadav 		return -ENOMEM;
38844fd1c1fSVinay Kumar Yadav 
38944fd1c1fSVinay Kumar Yadav 	keyid = get_new_keyid(csk, optname);
39044fd1c1fSVinay Kumar Yadav 	if (keyid < 0) {
39144fd1c1fSVinay Kumar Yadav 		ret = -ENOSPC;
39244fd1c1fSVinay Kumar Yadav 		goto out_nokey;
39344fd1c1fSVinay Kumar Yadav 	}
39444fd1c1fSVinay Kumar Yadav 
39544fd1c1fSVinay Kumar Yadav 	kaddr = keyid_to_addr(cdev->kmap.start, keyid);
39644fd1c1fSVinay Kumar Yadav 	kwr = (struct tls_key_req *)__skb_put_zero(skb, len);
39744fd1c1fSVinay Kumar Yadav 	kwr->wr.op_to_compl =
39844fd1c1fSVinay Kumar Yadav 		cpu_to_be32(FW_WR_OP_V(FW_ULPTX_WR) | FW_WR_COMPL_F |
39944fd1c1fSVinay Kumar Yadav 		      FW_WR_ATOMIC_V(1U));
40044fd1c1fSVinay Kumar Yadav 	kwr->wr.flowid_len16 =
40144fd1c1fSVinay Kumar Yadav 		cpu_to_be32(FW_WR_LEN16_V(DIV_ROUND_UP(len, 16) |
40244fd1c1fSVinay Kumar Yadav 			    FW_WR_FLOWID_V(csk->tid)));
40344fd1c1fSVinay Kumar Yadav 	kwr->wr.protocol = 0;
40444fd1c1fSVinay Kumar Yadav 	kwr->wr.mfs = htons(TLS_MFS);
40544fd1c1fSVinay Kumar Yadav 	kwr->wr.reneg_to_write_rx = optname;
40644fd1c1fSVinay Kumar Yadav 
40744fd1c1fSVinay Kumar Yadav 	/* ulptx command */
40844fd1c1fSVinay Kumar Yadav 	kwr->req.cmd = cpu_to_be32(ULPTX_CMD_V(ULP_TX_MEM_WRITE) |
40944fd1c1fSVinay Kumar Yadav 			    T5_ULP_MEMIO_ORDER_V(1) |
41044fd1c1fSVinay Kumar Yadav 			    T5_ULP_MEMIO_IMM_V(1));
41144fd1c1fSVinay Kumar Yadav 	kwr->req.len16 = cpu_to_be32((csk->tid << 8) |
41244fd1c1fSVinay Kumar Yadav 			      DIV_ROUND_UP(len - sizeof(kwr->wr), 16));
41344fd1c1fSVinay Kumar Yadav 	kwr->req.dlen = cpu_to_be32(ULP_MEMIO_DATA_LEN_V(klen >> 5));
41444fd1c1fSVinay Kumar Yadav 	kwr->req.lock_addr = cpu_to_be32(ULP_MEMIO_ADDR_V(kaddr));
41544fd1c1fSVinay Kumar Yadav 
41644fd1c1fSVinay Kumar Yadav 	/* sub command */
41744fd1c1fSVinay Kumar Yadav 	kwr->sc_imm.cmd_more = cpu_to_be32(ULPTX_CMD_V(ULP_TX_SC_IMM));
41844fd1c1fSVinay Kumar Yadav 	kwr->sc_imm.len = cpu_to_be32(klen);
41944fd1c1fSVinay Kumar Yadav 
42044fd1c1fSVinay Kumar Yadav 	lock_sock(sk);
42144fd1c1fSVinay Kumar Yadav 	/* key info */
42244fd1c1fSVinay Kumar Yadav 	kctx = (struct _key_ctx *)(kwr + 1);
42344fd1c1fSVinay Kumar Yadav 	ret = chtls_key_info(csk, kctx, keylen, optname, cipher_type);
42444fd1c1fSVinay Kumar Yadav 	if (ret)
42544fd1c1fSVinay Kumar Yadav 		goto out_notcb;
42644fd1c1fSVinay Kumar Yadav 
4278080b462SVinay Kumar Yadav 	if (unlikely(csk_flag(sk, CSK_ABORT_SHUTDOWN)))
4288080b462SVinay Kumar Yadav 		goto out_notcb;
4298080b462SVinay Kumar Yadav 
43044fd1c1fSVinay Kumar Yadav 	set_wr_txq(skb, CPL_PRIORITY_DATA, csk->tlshws.txqid);
43144fd1c1fSVinay Kumar Yadav 	csk->wr_credits -= DIV_ROUND_UP(len, 16);
43244fd1c1fSVinay Kumar Yadav 	csk->wr_unacked += DIV_ROUND_UP(len, 16);
43344fd1c1fSVinay Kumar Yadav 	enqueue_wr(csk, skb);
43444fd1c1fSVinay Kumar Yadav 	cxgb4_ofld_send(csk->egress_dev, skb);
435391119fbSDan Carpenter 	skb = NULL;
43644fd1c1fSVinay Kumar Yadav 
43744fd1c1fSVinay Kumar Yadav 	chtls_set_scmd(csk);
43844fd1c1fSVinay Kumar Yadav 	/* Clear quiesce for Rx key */
43944fd1c1fSVinay Kumar Yadav 	if (optname == TLS_RX) {
44044fd1c1fSVinay Kumar Yadav 		ret = chtls_set_tcb_keyid(sk, keyid);
44144fd1c1fSVinay Kumar Yadav 		if (ret)
44244fd1c1fSVinay Kumar Yadav 			goto out_notcb;
44344fd1c1fSVinay Kumar Yadav 		ret = chtls_set_tcb_field(sk, 0,
44444fd1c1fSVinay Kumar Yadav 					  TCB_ULP_RAW_V(TCB_ULP_RAW_M),
44544fd1c1fSVinay Kumar Yadav 					  TCB_ULP_RAW_V((TF_TLS_KEY_SIZE_V(1) |
44644fd1c1fSVinay Kumar Yadav 					  TF_TLS_CONTROL_V(1) |
44744fd1c1fSVinay Kumar Yadav 					  TF_TLS_ACTIVE_V(1) |
44844fd1c1fSVinay Kumar Yadav 					  TF_TLS_ENABLE_V(1))));
44944fd1c1fSVinay Kumar Yadav 		if (ret)
45044fd1c1fSVinay Kumar Yadav 			goto out_notcb;
45144fd1c1fSVinay Kumar Yadav 		ret = chtls_set_tcb_seqno(sk);
45244fd1c1fSVinay Kumar Yadav 		if (ret)
45344fd1c1fSVinay Kumar Yadav 			goto out_notcb;
45444fd1c1fSVinay Kumar Yadav 		ret = chtls_set_tcb_quiesce(sk, 0);
45544fd1c1fSVinay Kumar Yadav 		if (ret)
45644fd1c1fSVinay Kumar Yadav 			goto out_notcb;
45744fd1c1fSVinay Kumar Yadav 		csk->tlshws.rxkey = keyid;
45844fd1c1fSVinay Kumar Yadav 	} else {
45944fd1c1fSVinay Kumar Yadav 		csk->tlshws.tx_seq_no = 0;
46044fd1c1fSVinay Kumar Yadav 		csk->tlshws.txkey = keyid;
46144fd1c1fSVinay Kumar Yadav 	}
46244fd1c1fSVinay Kumar Yadav 
46344fd1c1fSVinay Kumar Yadav 	release_sock(sk);
46444fd1c1fSVinay Kumar Yadav 	return ret;
46544fd1c1fSVinay Kumar Yadav out_notcb:
46644fd1c1fSVinay Kumar Yadav 	release_sock(sk);
46744fd1c1fSVinay Kumar Yadav 	free_tls_keyid(sk);
46844fd1c1fSVinay Kumar Yadav out_nokey:
46944fd1c1fSVinay Kumar Yadav 	kfree_skb(skb);
47044fd1c1fSVinay Kumar Yadav 	return ret;
47144fd1c1fSVinay Kumar Yadav }
472