xref: /wlan-dirver/qca-wifi-host-cmn/target_if/crypto/src/target_if_crypto.c (revision 45a38684b07295822dc8eba39e293408f203eec8)
1 /*
2  * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
3  *
4  * Permission to use, copy, modify, and/or distribute this software for
5  * any purpose with or without fee is hereby granted, provided that the
6  * above copyright notice and this permission notice appear in all
7  * copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /**
20  * DOC: offload lmac interface APIs definitions for crypto
21  */
22 
23 #include <qdf_mem.h>
24 #include <qdf_status.h>
25 #include <target_if_crypto.h>
26 #include <wmi_unified_priv.h>
27 #include <wmi_unified_param.h>
28 #include <wlan_objmgr_psoc_obj.h>
29 #include <target_if.h>
30 #include <wlan_crypto_global_def.h>
31 #include <wlan_crypto_global_api.h>
32 #include <wlan_objmgr_vdev_obj.h>
33 #include <cdp_txrx_cmn_struct.h>
34 #include <cds_api.h>
35 #include <cdp_txrx_cmn.h>
36 #include <wmi_unified_api.h>
37 #include <wmi_unified_crypto_api.h>
38 #include <cdp_txrx_peer_ops.h>
39 
40 #ifdef FEATURE_WLAN_WAPI
41 #ifdef FEATURE_WAPI_BIG_ENDIAN
42 /*
43  * All lithium firmware expects WAPI in big endian
44  * format , whereas helium firmware's expect otherwise
45  */
46 
47 static void wlan_crypto_set_wapi_key(struct wlan_objmgr_vdev *vdev,
48 				     bool pairwise,
49 				     enum wlan_crypto_cipher_type cipher_type,
50 				     struct set_key_params *params)
51 {
52 	static const unsigned char tx_iv[16] = {0x5c, 0x36, 0x5c, 0x36, 0x5c,
53 						0x36, 0x5c, 0x36, 0x5c, 0x36,
54 						0x5c, 0x36, 0x5c, 0x36, 0x5c,
55 						0x36};
56 
57 	static const unsigned char rx_iv[16] = {0x5c, 0x36, 0x5c, 0x36, 0x5c,
58 						0x36, 0x5c, 0x36, 0x5c, 0x36,
59 						0x5c, 0x36, 0x5c, 0x36, 0x5c,
60 						0x37};
61 
62 	if (cipher_type != WLAN_CRYPTO_CIPHER_WAPI_SMS4 &&
63 	    cipher_type != WLAN_CRYPTO_CIPHER_WAPI_GCM4)
64 		return;
65 
66 	if (vdev->vdev_mlme.vdev_opmode == QDF_SAP_MODE ||
67 	    vdev->vdev_mlme.vdev_opmode == QDF_P2P_GO_MODE) {
68 			qdf_mem_copy(&params->rx_iv, &tx_iv,
69 					 WLAN_CRYPTO_WAPI_IV_SIZE);
70 			qdf_mem_copy(params->tx_iv, &rx_iv,
71 					 WLAN_CRYPTO_WAPI_IV_SIZE);
72 	} else {
73 			qdf_mem_copy(params->rx_iv, &rx_iv,
74 					 WLAN_CRYPTO_WAPI_IV_SIZE);
75 			qdf_mem_copy(params->tx_iv, &tx_iv,
76 					 WLAN_CRYPTO_WAPI_IV_SIZE);
77 		}
78 
79 	params->key_txmic_len = WLAN_CRYPTO_MIC_LEN;
80 	params->key_rxmic_len = WLAN_CRYPTO_MIC_LEN;
81 }
82 #else
83 static void wlan_crypto_set_wapi_key(struct wlan_objmgr_vdev *vdev,
84 				     bool pairwise,
85 				     enum wlan_crypto_cipher_type cipher_type,
86 				     struct set_key_params *params)
87 {
88 	static const unsigned char tx_iv[16] = {0x36, 0x5c, 0x36, 0x5c, 0x36,
89 						0x5c, 0x36, 0x5c, 0x36, 0x5c,
90 						0x36, 0x5c, 0x36, 0x5c, 0x36,
91 						0x5c};
92 
93 	static const unsigned char rx_iv[16] = {0x5c, 0x36, 0x5c, 0x36, 0x5c,
94 						0x36, 0x5c, 0x36, 0x5c, 0x36,
95 						0x5c, 0x36, 0x5c, 0x36, 0x5c,
96 						0x37};
97 
98 	if (cipher_type != WLAN_CRYPTO_CIPHER_WAPI_SMS4 &&
99 	    cipher_type != WLAN_CRYPTO_CIPHER_WAPI_GCM4)
100 		return;
101 
102 	qdf_mem_copy(&params->rx_iv, &rx_iv,
103 		     WLAN_CRYPTO_WAPI_IV_SIZE);
104 	qdf_mem_copy(&params->tx_iv, &tx_iv,
105 		     WLAN_CRYPTO_WAPI_IV_SIZE);
106 
107 	if (vdev->vdev_mlme.vdev_opmode == QDF_SAP_MODE) {
108 		if (pairwise)
109 			params->tx_iv[0] = 0x37;
110 
111 		params->rx_iv[WLAN_CRYPTO_WAPI_IV_SIZE - 1] = 0x36;
112 	} else {
113 		if (!pairwise)
114 			params->rx_iv[WLAN_CRYPTO_WAPI_IV_SIZE - 1] = 0x36;
115 	}
116 
117 	params->key_txmic_len = WLAN_CRYPTO_MIC_LEN;
118 	params->key_rxmic_len = WLAN_CRYPTO_MIC_LEN;
119 }
120 #endif /* FEATURE_WAPI_BIG_ENDIAN */
121 #else
122 static inline void wlan_crypto_set_wapi_key(struct wlan_objmgr_vdev *vdev,
123 					    bool pairwise,
124 					    enum wlan_crypto_cipher_type cipher,
125 					    struct set_key_params *params)
126 {
127 }
128 #endif /* FEATURE_WLAN_WAPI */
129 
130 #ifdef BIG_ENDIAN_HOST
131 static void wlan_crypto_endianness_conversion(uint8_t *dest, uint8_t *src,
132 					      uint32_t keylen)
133 {
134 	int8_t i;
135 
136 	for (i = 0; i < roundup(keylen, sizeof(uint32_t)) / 4; i++) {
137 		*dest = le32_to_cpu(*src);
138 		dest++;
139 		src++;
140 	}
141 }
142 #else
143 static void wlan_crypto_endianness_conversion(uint8_t *dest, uint8_t *src,
144 					      uint32_t keylen)
145 {
146 	qdf_mem_copy(dest, src, keylen);
147 }
148 #endif
149 
150 QDF_STATUS target_if_crypto_set_key(struct wlan_objmgr_vdev *vdev,
151 				    struct wlan_crypto_key *req,
152 				    enum wlan_crypto_key_type key_type)
153 {
154 	struct set_key_params params = {0};
155 	struct wlan_objmgr_psoc *psoc;
156 	struct wlan_objmgr_pdev *pdev;
157 	enum cdp_sec_type sec_type = cdp_sec_type_none;
158 	void *soc = cds_get_context(QDF_MODULE_ID_SOC);
159 	uint32_t pn[4] = {0, 0, 0, 0};
160 	bool peer_exist = false;
161 	uint8_t def_tx_idx;
162 	wmi_unified_t pdev_wmi_handle;
163 	bool pairwise;
164 	QDF_STATUS status;
165 
166 	pdev = wlan_vdev_get_pdev(vdev);
167 	if (!pdev) {
168 		target_if_err("Invalid PDEV");
169 		return QDF_STATUS_E_FAILURE;
170 	}
171 	psoc = wlan_vdev_get_psoc(vdev);
172 	if (!psoc) {
173 		target_if_err("Invalid PSOC");
174 		return QDF_STATUS_E_FAILURE;
175 	}
176 	soc = wlan_psoc_get_dp_handle(psoc);
177 	if (!soc) {
178 		target_if_err("Invalid DP Handle");
179 		return QDF_STATUS_E_FAILURE;
180 	}
181 	params.vdev_id = wlan_vdev_get_id(vdev);
182 	params.key_idx = req->keyix;
183 	qdf_mem_copy(params.peer_mac, req->macaddr, QDF_MAC_ADDR_SIZE);
184 	pdev_wmi_handle = GET_WMI_HDL_FROM_PDEV(pdev);
185 	if (!pdev_wmi_handle) {
186 		target_if_err("Invalid PDEV WMI handle");
187 		return QDF_STATUS_E_FAILURE;
188 	}
189 
190 	params.key_flags = req->flags;
191 	if (key_type != WLAN_CRYPTO_KEY_TYPE_UNICAST) {
192 		pairwise = false;
193 		params.key_flags |= GROUP_USAGE;
194 
195 	} else {
196 		pairwise = true;
197 		params.key_flags |= PAIRWISE_USAGE;
198 	}
199 	qdf_mem_copy(&params.key_rsc_ctr,
200 		     &req->keyrsc[0], sizeof(uint64_t));
201 
202 	peer_exist = cdp_find_peer_exist(soc, pdev->pdev_objmgr.wlan_pdev_id,
203 					 req->macaddr);
204 	target_if_debug("key_type %d, mac: %02x:%02x:%02x:%02x:%02x:%02x",
205 			key_type, req->macaddr[0], req->macaddr[1],
206 			req->macaddr[2], req->macaddr[3], req->macaddr[4],
207 			req->macaddr[5]);
208 
209 	if ((key_type == WLAN_CRYPTO_KEY_TYPE_UNICAST) && !peer_exist) {
210 		target_if_err("Invalid peer");
211 		return QDF_STATUS_E_FAILURE;
212 	}
213 
214 	params.key_cipher = wlan_crypto_cipher_to_wmi_cipher(req->cipher_type);
215 	sec_type = wlan_crypto_cipher_to_cdp_sec_type(req->cipher_type);
216 	wlan_crypto_set_wapi_key(vdev, pairwise, req->cipher_type, &params);
217 
218 	switch (req->cipher_type) {
219 	case WLAN_CRYPTO_CIPHER_WEP:
220 	case WLAN_CRYPTO_CIPHER_WEP_40:
221 	case WLAN_CRYPTO_CIPHER_WEP_104:
222 		def_tx_idx = wlan_crypto_get_default_key_idx(vdev, false);
223 		if (pairwise && params.key_idx == def_tx_idx)
224 			params.key_flags |= TX_USAGE;
225 		else if ((vdev->vdev_mlme.vdev_opmode == QDF_SAP_MODE) &&
226 			 (params.key_idx == def_tx_idx))
227 			params.key_flags |= TX_USAGE;
228 		break;
229 	case WLAN_CRYPTO_CIPHER_TKIP:
230 		params.key_txmic_len = WLAN_CRYPTO_MIC_LEN;
231 		params.key_rxmic_len = WLAN_CRYPTO_MIC_LEN;
232 		break;
233 	default:
234 		break;
235 	}
236 
237 	wlan_crypto_endianness_conversion(&params.key_data[0],
238 					  &req->keyval[0],
239 					  req->keylen);
240 	params.key_len = req->keylen;
241 
242 	/* Set PN check & security type in data path */
243 	qdf_mem_copy(&pn[0], &params.key_rsc_ctr, sizeof(pn));
244 	cdp_set_pn_check(soc, vdev->vdev_objmgr.vdev_id, req->macaddr,
245 			 sec_type, pn);
246 
247 	cdp_set_key_sec_type(soc, vdev->vdev_objmgr.vdev_id, req->macaddr,
248 			     sec_type, pairwise);
249 
250 	cdp_set_key(soc, vdev->vdev_objmgr.vdev_id, req->macaddr, pairwise,
251 		    (uint32_t *)(req->keyval + WLAN_CRYPTO_IV_SIZE +
252 		     WLAN_CRYPTO_MIC_LEN));
253 
254 	target_if_debug("vdev_id:%d, key: idx:%d,len:%d", params.vdev_id,
255 			params.key_idx, params.key_len);
256 	target_if_debug("peer mac %pM", params.peer_mac);
257 	QDF_TRACE_HEX_DUMP(QDF_MODULE_ID_CRYPTO, QDF_TRACE_LEVEL_DEBUG,
258 			   &params.key_rsc_ctr, sizeof(uint64_t));
259 	status = wmi_unified_setup_install_key_cmd(pdev_wmi_handle, &params);
260 
261 	/* Zero-out local key variables */
262 	qdf_mem_zero(&params, sizeof(struct set_key_params));
263 	return status;
264 }
265 
266 QDF_STATUS target_if_crypto_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
267 {
268 	struct wlan_lmac_if_crypto_tx_ops *crypto;
269 
270 	if (!tx_ops) {
271 		target_if_err("txops NULL");
272 		return QDF_STATUS_E_FAILURE;
273 	}
274 	crypto = &tx_ops->crypto_tx_ops;
275 
276 	crypto->set_key = target_if_crypto_set_key;
277 
278 	return QDF_STATUS_SUCCESS;
279 }
280 
281