xref: /wlan-dirver/qca-wifi-host-cmn/os_if/linux/crypto/src/wlan_cfg80211_crypto.c (revision 901120c066e139c7f8a2c8e4820561fdd83c67ef)
1 /*
2  * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for
6  * any purpose with or without fee is hereby granted, provided that the
7  * above copyright notice and this permission notice appear in all
8  * copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /**
21  * DOC: defines crypto driver functions interfacing with linux kernel
22  */
23 #include <wlan_crypto_global_def.h>
24 #include <wlan_crypto_global_api.h>
25 #include <wlan_objmgr_vdev_obj.h>
26 #include <wlan_crypto_main_i.h>
27 #include <wlan_objmgr_pdev_obj.h>
28 #include <wlan_objmgr_peer_obj.h>
29 #include <wlan_crypto_def_i.h>
30 #include <wlan_crypto_obj_mgr_i.h>
31 #include <net/cfg80211.h>
32 #include <wlan_nl_to_crypto_params.h>
33 #include "wlan_cfg80211_crypto.h"
34 #include <wlan_cfg80211.h>
35 #include <wlan_osif_request_manager.h>
36 
37 void wlan_cfg80211_translate_key(struct wlan_objmgr_vdev *vdev,
38 				 uint8_t key_index,
39 				 enum wlan_crypto_key_type key_type,
40 				 const u8 *mac_addr,
41 				 struct key_params *params,
42 				 struct wlan_crypto_key *crypto_key)
43 {
44 	qdf_mem_zero(crypto_key, sizeof(*crypto_key));
45 	crypto_key->keylen = params->key_len;
46 	crypto_key->keyix = key_index;
47 	osif_debug("key_type %d, opmode %d, key_len %d, seq_len %d",
48 		   key_type, vdev->vdev_mlme.vdev_opmode,
49 		   params->key_len, params->seq_len);
50 	qdf_mem_copy(&crypto_key->keyval[0], params->key, params->key_len);
51 	qdf_mem_copy(&crypto_key->keyrsc[0], params->seq, params->seq_len);
52 
53 	crypto_key->key_type = key_type;
54 	crypto_key->cipher_type = osif_nl_to_crypto_cipher_type(params->cipher);
55 	if (IS_WEP_CIPHER(crypto_key->cipher_type) && !mac_addr) {
56 		/*
57 		 * This is a valid scenario in case of WEP, where-in the
58 		 * keys are passed by the user space during the connect request
59 		 * but since we did not connect yet, so we do not know the peer
60 		 * address yet.
61 		 */
62 		osif_debug("No Mac Address to copy");
63 		return;
64 	}
65 	if (key_type == WLAN_CRYPTO_KEY_TYPE_UNICAST) {
66 		qdf_mem_copy(&crypto_key->macaddr, mac_addr, QDF_MAC_ADDR_SIZE);
67 	} else {
68 		if ((vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE) ||
69 		    (vdev->vdev_mlme.vdev_opmode == QDF_P2P_CLIENT_MODE))
70 			qdf_mem_copy(&crypto_key->macaddr, mac_addr,
71 				     QDF_MAC_ADDR_SIZE);
72 		else
73 			qdf_mem_copy(&crypto_key->macaddr,
74 				     vdev->vdev_mlme.macaddr,
75 				     QDF_MAC_ADDR_SIZE);
76 	}
77 	osif_debug("mac "QDF_MAC_ADDR_FMT,
78 		   QDF_MAC_ADDR_REF(crypto_key->macaddr));
79 }
80 
81 int wlan_cfg80211_store_key(struct wlan_objmgr_vdev *vdev,
82 			    uint8_t key_index,
83 			    enum wlan_crypto_key_type key_type,
84 			    const u8 *mac_addr, struct key_params *params)
85 {
86 	struct wlan_crypto_key *crypto_key = NULL;
87 	enum wlan_crypto_cipher_type cipher;
88 	int cipher_len;
89 	QDF_STATUS status;
90 
91 	if (!vdev) {
92 		osif_err("vdev is NULL");
93 		return -EINVAL;
94 	}
95 	if (!params) {
96 		osif_err("Key params is NULL");
97 		return -EINVAL;
98 	}
99 	cipher_len = osif_nl_to_crypto_cipher_len(params->cipher);
100 	if (cipher_len < 0 || params->key_len < cipher_len) {
101 		osif_err("cipher length %d less than reqd len %d",
102 			 params->key_len, cipher_len);
103 		return -EINVAL;
104 	}
105 	cipher = osif_nl_to_crypto_cipher_type(params->cipher);
106 	if (!IS_WEP_CIPHER(cipher)) {
107 		if ((key_type == WLAN_CRYPTO_KEY_TYPE_UNICAST) &&
108 		    !mac_addr) {
109 			osif_err("mac_addr is NULL for pairwise Key");
110 			return -EINVAL;
111 		}
112 	}
113 	status = wlan_crypto_validate_key_params(cipher, key_index,
114 						 params->key_len,
115 						 params->seq_len);
116 	if (QDF_IS_STATUS_ERROR(status)) {
117 		osif_err("Invalid key params");
118 		return -EINVAL;
119 	}
120 
121 	/*
122 	 * key may already exist at times and may be retrieved only to
123 	 * update it.
124 	 */
125 	crypto_key = wlan_crypto_get_key(vdev, key_index);
126 	if (!crypto_key) {
127 		crypto_key = qdf_mem_malloc(sizeof(*crypto_key));
128 		if (!crypto_key)
129 			return -EINVAL;
130 	}
131 
132 	wlan_cfg80211_translate_key(vdev, key_index, key_type, mac_addr,
133 				    params, crypto_key);
134 
135 	status = wlan_crypto_save_key(vdev, key_index, crypto_key);
136 	if (QDF_IS_STATUS_ERROR(status)) {
137 		osif_err("Failed to save key");
138 		qdf_mem_free(crypto_key);
139 		return -EINVAL;
140 	}
141 	return 0;
142 }
143 
144 #define WLAN_WAIT_TIME_ADD_KEY 100
145 
146 static void
147 wlan_cfg80211_crypto_add_key_cb(void *context,
148 				struct crypto_add_key_result *result)
149 {
150 	struct osif_request *request;
151 	struct crypto_add_key_result *priv;
152 
153 	request = osif_request_get(context);
154 	if (!request) {
155 		osif_err("Obsolete request");
156 		return;
157 	}
158 
159 	priv = osif_request_priv(request);
160 	qdf_mem_copy(priv, result, sizeof(*priv));
161 	osif_request_complete(request);
162 	osif_request_put(request);
163 }
164 
165 int wlan_cfg80211_crypto_add_key(struct wlan_objmgr_vdev *vdev,
166 				 enum wlan_crypto_key_type key_type,
167 				 uint8_t key_index, bool sync)
168 {
169 	struct wlan_crypto_key *crypto_key;
170 	QDF_STATUS status;
171 	struct osif_request *request;
172 	struct crypto_add_key_result *result;
173 	struct wlan_crypto_comp_priv *priv;
174 	int ret;
175 	static const struct osif_request_params params = {
176 		.priv_size = sizeof(*result),
177 		.timeout_ms = WLAN_WAIT_TIME_ADD_KEY,
178 	};
179 
180 	crypto_key = wlan_crypto_get_key(vdev, key_index);
181 	if (!crypto_key) {
182 		osif_err("Crypto KEY is NULL");
183 		return -EINVAL;
184 	}
185 
186 	if (sync) {
187 		priv = wlan_get_vdev_crypto_obj(vdev);
188 		if (!priv) {
189 			osif_err("Invalid crypto_priv");
190 			return -EINVAL;
191 		}
192 
193 		request = osif_request_alloc(&params);
194 		if (!request) {
195 			osif_err("Request allocation failure");
196 			return -ENOMEM;
197 		}
198 
199 		priv->add_key_ctx = osif_request_cookie(request);;
200 		priv->add_key_cb = wlan_cfg80211_crypto_add_key_cb;
201 
202 		status  = ucfg_crypto_set_key_req(vdev, crypto_key, key_type);
203 		if (QDF_IS_STATUS_SUCCESS(status)) {
204 			ret = osif_request_wait_for_response(request);
205 			if (ret) {
206 				osif_err("Target response timed out");
207 			} else {
208 				result = osif_request_priv(request);
209 				osif_debug("complete, vdev_id %u, ix: %u, flags: %u, status: %u",
210 					   result->vdev_id, result->key_ix,
211 					   result->key_flags, result->status);
212 			}
213 		}
214 
215 		priv->add_key_ctx = NULL;
216 		priv->add_key_cb = NULL;
217 		osif_request_put(request);
218 	} else {
219 		status  = ucfg_crypto_set_key_req(vdev, crypto_key, key_type);
220 	}
221 
222 	return qdf_status_to_os_return(status);
223 }
224 
225 int wlan_cfg80211_set_default_key(struct wlan_objmgr_vdev *vdev,
226 				  uint8_t key_index, struct qdf_mac_addr *bssid)
227 {
228 	return wlan_crypto_default_key(vdev, (uint8_t *)bssid,
229 				       key_index, true);
230 }
231