1 /*
2 * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
3 * Copyright (c) 2022-2023 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
wlan_cfg80211_translate_ml_sta_key(uint8_t key_index,enum wlan_crypto_key_type key_type,const u8 * mac_addr,struct key_params * params,struct wlan_crypto_key * crypto_key)37 void wlan_cfg80211_translate_ml_sta_key(uint8_t key_index,
38 enum wlan_crypto_key_type key_type,
39 const u8 *mac_addr,
40 struct key_params *params,
41 struct wlan_crypto_key *crypto_key)
42 {
43 qdf_mem_zero(crypto_key, sizeof(*crypto_key));
44 crypto_key->keylen = params->key_len;
45 crypto_key->keyix = key_index;
46 osif_debug("key_type %d, key_len %d, seq_len %d",
47 key_type,
48 params->key_len, params->seq_len);
49 qdf_mem_copy(&crypto_key->keyval[0], params->key, params->key_len);
50 qdf_mem_copy(&crypto_key->keyrsc[0], params->seq, params->seq_len);
51
52 crypto_key->key_type = key_type;
53 crypto_key->cipher_type = osif_nl_to_crypto_cipher_type(params->cipher);
54
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 qdf_mem_copy(&crypto_key->macaddr, mac_addr,
66 QDF_MAC_ADDR_SIZE);
67 osif_debug("crypto key mac " QDF_MAC_ADDR_FMT,
68 QDF_MAC_ADDR_REF(crypto_key->macaddr));
69 }
70
wlan_cfg80211_translate_key(struct wlan_objmgr_vdev * vdev,uint8_t key_index,enum wlan_crypto_key_type key_type,const u8 * mac_addr,struct key_params * params,struct wlan_crypto_key * crypto_key)71 void wlan_cfg80211_translate_key(struct wlan_objmgr_vdev *vdev,
72 uint8_t key_index,
73 enum wlan_crypto_key_type key_type,
74 const u8 *mac_addr,
75 struct key_params *params,
76 struct wlan_crypto_key *crypto_key)
77 {
78 qdf_mem_zero(crypto_key, sizeof(*crypto_key));
79 crypto_key->keylen = params->key_len;
80 crypto_key->keyix = key_index;
81 osif_debug("key_type %d, opmode %d, key_len %d, seq_len %d",
82 key_type, vdev->vdev_mlme.vdev_opmode,
83 params->key_len, params->seq_len);
84 qdf_mem_copy(&crypto_key->keyval[0], params->key, params->key_len);
85 qdf_mem_copy(&crypto_key->keyrsc[0], params->seq, params->seq_len);
86
87 crypto_key->key_type = key_type;
88 crypto_key->cipher_type = osif_nl_to_crypto_cipher_type(params->cipher);
89 if (IS_WEP_CIPHER(crypto_key->cipher_type) && !mac_addr) {
90 /*
91 * This is a valid scenario in case of WEP, where-in the
92 * keys are passed by the user space during the connect request
93 * but since we did not connect yet, so we do not know the peer
94 * address yet.
95 */
96 osif_debug("No Mac Address to copy");
97 return;
98 }
99 if (key_type == WLAN_CRYPTO_KEY_TYPE_UNICAST) {
100 qdf_mem_copy(&crypto_key->macaddr, mac_addr, QDF_MAC_ADDR_SIZE);
101 } else {
102 if ((vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE) ||
103 (vdev->vdev_mlme.vdev_opmode == QDF_P2P_CLIENT_MODE))
104 qdf_mem_copy(&crypto_key->macaddr, mac_addr,
105 QDF_MAC_ADDR_SIZE);
106 else
107 qdf_mem_copy(&crypto_key->macaddr,
108 vdev->vdev_mlme.macaddr,
109 QDF_MAC_ADDR_SIZE);
110 }
111 osif_debug("mac "QDF_MAC_ADDR_FMT,
112 QDF_MAC_ADDR_REF(crypto_key->macaddr));
113 }
114
wlan_cfg80211_store_link_key(struct wlan_objmgr_psoc * psoc,uint8_t key_index,enum wlan_crypto_key_type key_type,const u8 * mac_addr,struct key_params * params,struct qdf_mac_addr * link_addr,uint8_t link_id)115 int wlan_cfg80211_store_link_key(struct wlan_objmgr_psoc *psoc,
116 uint8_t key_index,
117 enum wlan_crypto_key_type key_type,
118 const u8 *mac_addr, struct key_params *params,
119 struct qdf_mac_addr *link_addr,
120 uint8_t link_id)
121 {
122 struct wlan_crypto_key *crypto_key = NULL;
123 enum wlan_crypto_cipher_type cipher;
124 int cipher_len;
125 QDF_STATUS status;
126
127 if (!psoc) {
128 osif_err("psoc is NULL");
129 return -EINVAL;
130 }
131 if (!params) {
132 osif_err("Key params is NULL");
133 return -EINVAL;
134 }
135 cipher_len = osif_nl_to_crypto_cipher_len(params->cipher);
136 if (cipher_len < 0 || params->key_len < cipher_len) {
137 osif_err("cipher length %d less than reqd len %d",
138 params->key_len, cipher_len);
139 return -EINVAL;
140 }
141 cipher = osif_nl_to_crypto_cipher_type(params->cipher);
142 if (!IS_WEP_CIPHER(cipher)) {
143 if ((key_type == WLAN_CRYPTO_KEY_TYPE_UNICAST) &&
144 !mac_addr) {
145 osif_err("mac_addr is NULL for pairwise Key");
146 return -EINVAL;
147 }
148 }
149 status = wlan_crypto_validate_key_params(cipher, key_index,
150 params->key_len,
151 params->seq_len);
152 if (QDF_IS_STATUS_ERROR(status)) {
153 osif_err("Invalid key params");
154 return -EINVAL;
155 }
156
157 /*
158 * key may already exist at times and may be retrieved only to
159 * update it.
160 */
161 wlan_crypto_aquire_lock();
162 crypto_key = wlan_crypto_get_ml_sta_link_key(psoc, key_index,
163 link_addr, link_id);
164 if (!crypto_key) {
165 wlan_crypto_release_lock();
166 crypto_key = qdf_mem_malloc(sizeof(*crypto_key));
167 if (!crypto_key)
168 return -EINVAL;
169 wlan_crypto_aquire_lock();
170 }
171
172 wlan_cfg80211_translate_ml_sta_key(key_index, key_type, mac_addr,
173 params, crypto_key);
174
175 status = wlan_crypto_save_ml_sta_key(psoc, key_index, crypto_key,
176 link_addr, link_id);
177 if (QDF_IS_STATUS_ERROR(status)) {
178 wlan_crypto_release_lock();
179 osif_err("Failed to save key");
180 qdf_mem_free(crypto_key);
181 return -EINVAL;
182 }
183 wlan_crypto_release_lock();
184 return 0;
185 }
186
wlan_cfg80211_store_key(struct wlan_objmgr_vdev * vdev,uint8_t key_index,enum wlan_crypto_key_type key_type,const u8 * mac_addr,struct key_params * params)187 int wlan_cfg80211_store_key(struct wlan_objmgr_vdev *vdev,
188 uint8_t key_index,
189 enum wlan_crypto_key_type key_type,
190 const u8 *mac_addr, struct key_params *params)
191 {
192 struct wlan_crypto_key *crypto_key = NULL;
193 enum wlan_crypto_cipher_type cipher;
194 int cipher_len;
195 QDF_STATUS status;
196
197 if (!vdev) {
198 osif_err("vdev is NULL");
199 return -EINVAL;
200 }
201 if (!params) {
202 osif_err("Key params is NULL");
203 return -EINVAL;
204 }
205 cipher_len = osif_nl_to_crypto_cipher_len(params->cipher);
206 if (cipher_len < 0 || params->key_len < cipher_len) {
207 osif_err("cipher length %d less than reqd len %d",
208 params->key_len, cipher_len);
209 return -EINVAL;
210 }
211 cipher = osif_nl_to_crypto_cipher_type(params->cipher);
212 if (!IS_WEP_CIPHER(cipher)) {
213 if ((key_type == WLAN_CRYPTO_KEY_TYPE_UNICAST) &&
214 !mac_addr) {
215 osif_err("mac_addr is NULL for pairwise Key");
216 return -EINVAL;
217 }
218 }
219 status = wlan_crypto_validate_key_params(cipher, key_index,
220 params->key_len,
221 params->seq_len);
222 if (QDF_IS_STATUS_ERROR(status)) {
223 osif_err("Invalid key params");
224 return -EINVAL;
225 }
226
227 /*
228 * key may already exist at times and may be retrieved only to
229 * update it.
230 */
231 wlan_crypto_aquire_lock();
232 crypto_key = wlan_crypto_get_key(vdev, key_index);
233 if (!crypto_key) {
234 wlan_crypto_release_lock();
235 crypto_key = qdf_mem_malloc(sizeof(*crypto_key));
236 if (!crypto_key)
237 return -EINVAL;
238 wlan_crypto_aquire_lock();
239 }
240
241 wlan_cfg80211_translate_key(vdev, key_index, key_type, mac_addr,
242 params, crypto_key);
243
244 status = wlan_crypto_save_key(vdev, key_index, crypto_key);
245 if (QDF_IS_STATUS_ERROR(status)) {
246 wlan_crypto_release_lock();
247 osif_err("Failed to save key");
248 qdf_mem_free(crypto_key);
249 return -EINVAL;
250 }
251 wlan_crypto_release_lock();
252 return 0;
253 }
254
255 #define WLAN_WAIT_TIME_ADD_KEY 100
256
257 static void
wlan_cfg80211_crypto_add_key_cb(void * context,struct crypto_add_key_result * result)258 wlan_cfg80211_crypto_add_key_cb(void *context,
259 struct crypto_add_key_result *result)
260 {
261 struct osif_request *request;
262 struct crypto_add_key_result *priv;
263
264 request = osif_request_get(context);
265 if (!request) {
266 osif_err("Obsolete request");
267 return;
268 }
269
270 priv = osif_request_priv(request);
271 qdf_mem_copy(priv, result, sizeof(*priv));
272 osif_request_complete(request);
273 osif_request_put(request);
274 }
275
wlan_cfg80211_crypto_add_key(struct wlan_objmgr_vdev * vdev,enum wlan_crypto_key_type key_type,uint8_t key_index,bool sync)276 int wlan_cfg80211_crypto_add_key(struct wlan_objmgr_vdev *vdev,
277 enum wlan_crypto_key_type key_type,
278 uint8_t key_index, bool sync)
279 {
280 struct wlan_crypto_key *crypto_key;
281 QDF_STATUS status;
282 struct osif_request *request;
283 struct crypto_add_key_result *result;
284 struct wlan_crypto_comp_priv *priv;
285 int ret;
286 static const struct osif_request_params params = {
287 .priv_size = sizeof(*result),
288 .timeout_ms = WLAN_WAIT_TIME_ADD_KEY,
289 };
290
291 wlan_crypto_aquire_lock();
292 crypto_key = wlan_crypto_get_key(vdev, key_index);
293 if (!crypto_key) {
294 wlan_crypto_release_lock();
295 osif_err("Crypto KEY is NULL");
296 return -EINVAL;
297 }
298 wlan_crypto_release_lock();
299
300 if (sync) {
301 priv = wlan_get_vdev_crypto_obj(vdev);
302 if (!priv) {
303 osif_err("Invalid crypto_priv");
304 return -EINVAL;
305 }
306
307 request = osif_request_alloc(¶ms);
308 if (!request) {
309 osif_err("Request allocation failure");
310 return -ENOMEM;
311 }
312
313 priv->add_key_ctx = osif_request_cookie(request);;
314 priv->add_key_cb = wlan_cfg80211_crypto_add_key_cb;
315
316 status = ucfg_crypto_set_key_req(vdev, crypto_key, key_type);
317 if (QDF_IS_STATUS_SUCCESS(status)) {
318 ret = osif_request_wait_for_response(request);
319 if (ret) {
320 osif_err("Target response timed out");
321 } else {
322 result = osif_request_priv(request);
323 osif_debug("complete, vdev_id %u, ix: %u, flags: %u, status: %u",
324 result->vdev_id, result->key_ix,
325 result->key_flags, result->status);
326 }
327 }
328
329 priv->add_key_ctx = NULL;
330 priv->add_key_cb = NULL;
331 osif_request_put(request);
332 } else {
333 status = ucfg_crypto_set_key_req(vdev, crypto_key, key_type);
334 }
335 return qdf_status_to_os_return(status);
336 }
337
wlan_cfg80211_set_default_key(struct wlan_objmgr_vdev * vdev,uint8_t key_index,struct qdf_mac_addr * bssid)338 int wlan_cfg80211_set_default_key(struct wlan_objmgr_vdev *vdev,
339 uint8_t key_index, struct qdf_mac_addr *bssid)
340 {
341 return wlan_crypto_default_key(vdev, (uint8_t *)bssid,
342 key_index, true);
343 }
344