xref: /wlan-dirver/qca-wifi-host-cmn/os_if/linux/crypto/src/wlan_cfg80211_crypto.c (revision 2f4b444fb7e689b83a4ab0e7b3b38f0bf4def8e0)
1 /*
2  * Copyright (c) 2019-2021 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: defines crypto driver functions interfacing with linux kernel
21  */
22 #include <wlan_crypto_global_def.h>
23 #include <wlan_crypto_global_api.h>
24 #include <wlan_objmgr_vdev_obj.h>
25 #include <wlan_crypto_main_i.h>
26 #include <wlan_objmgr_pdev_obj.h>
27 #include <wlan_objmgr_peer_obj.h>
28 #include <wlan_crypto_def_i.h>
29 #include <wlan_crypto_obj_mgr_i.h>
30 #include <net/cfg80211.h>
31 #include <wlan_nl_to_crypto_params.h>
32 #include "wlan_cfg80211_crypto.h"
33 #include <wlan_cfg80211.h>
34 #include <wlan_osif_request_manager.h>
35 
36 static void wlan_cfg80211_translate_key(struct wlan_objmgr_vdev *vdev,
37 					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, opmode %d, key_len %d, seq_len %d",
47 		   key_type, vdev->vdev_mlme.vdev_opmode,
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->cipher_type = osif_nl_to_crypto_cipher_type(params->cipher);
53 	if (IS_WEP_CIPHER(crypto_key->cipher_type) && !mac_addr) {
54 		/*
55 		 * This is a valid scenario in case of WEP, where-in the
56 		 * keys are passed by the user space during the connect request
57 		 * but since we did not connect yet, so we do not know the peer
58 		 * address yet.
59 		 */
60 		osif_debug("No Mac Address to copy");
61 		return;
62 	}
63 	if (key_type == WLAN_CRYPTO_KEY_TYPE_UNICAST) {
64 		qdf_mem_copy(&crypto_key->macaddr, mac_addr, QDF_MAC_ADDR_SIZE);
65 	} else {
66 		if ((vdev->vdev_mlme.vdev_opmode == QDF_STA_MODE) ||
67 		    (vdev->vdev_mlme.vdev_opmode == QDF_P2P_CLIENT_MODE))
68 			qdf_mem_copy(&crypto_key->macaddr, mac_addr,
69 				     QDF_MAC_ADDR_SIZE);
70 		else
71 			qdf_mem_copy(&crypto_key->macaddr,
72 				     vdev->vdev_mlme.macaddr,
73 				     QDF_MAC_ADDR_SIZE);
74 	}
75 	osif_debug("mac "QDF_MAC_ADDR_FMT,
76 		   QDF_MAC_ADDR_REF(crypto_key->macaddr));
77 }
78 
79 int wlan_cfg80211_store_key(struct wlan_objmgr_vdev *vdev,
80 			    uint8_t key_index,
81 			    enum wlan_crypto_key_type key_type,
82 			    const u8 *mac_addr, struct key_params *params)
83 {
84 	struct wlan_crypto_key *crypto_key = NULL;
85 	enum wlan_crypto_cipher_type cipher;
86 	int cipher_len;
87 	QDF_STATUS status;
88 
89 	if (!vdev) {
90 		osif_err("vdev is NULL");
91 		return -EINVAL;
92 	}
93 	if (!params) {
94 		osif_err("Key params is NULL");
95 		return -EINVAL;
96 	}
97 	cipher_len = osif_nl_to_crypto_cipher_len(params->cipher);
98 	if (cipher_len < 0 || params->key_len < cipher_len) {
99 		osif_err("cipher length %d less than reqd len %d",
100 			 params->key_len, cipher_len);
101 		return -EINVAL;
102 	}
103 	cipher = osif_nl_to_crypto_cipher_type(params->cipher);
104 	if (!IS_WEP_CIPHER(cipher)) {
105 		if ((key_type == WLAN_CRYPTO_KEY_TYPE_UNICAST) &&
106 		    !mac_addr) {
107 			osif_err("mac_addr is NULL for pairwise Key");
108 			return -EINVAL;
109 		}
110 	}
111 	status = wlan_crypto_validate_key_params(cipher, key_index,
112 						 params->key_len,
113 						 params->seq_len);
114 	if (QDF_IS_STATUS_ERROR(status)) {
115 		osif_err("Invalid key params");
116 		return -EINVAL;
117 	}
118 
119 	/*
120 	 * key may already exist at times and may be retrieved only to
121 	 * update it.
122 	 */
123 	crypto_key = wlan_crypto_get_key(vdev, key_index);
124 	if (!crypto_key) {
125 		crypto_key = qdf_mem_malloc(sizeof(*crypto_key));
126 		if (!crypto_key)
127 			return -EINVAL;
128 	}
129 
130 	wlan_cfg80211_translate_key(vdev, key_index, key_type, mac_addr,
131 				    params, crypto_key);
132 
133 	status = wlan_crypto_save_key(vdev, key_index, crypto_key);
134 	if (QDF_IS_STATUS_ERROR(status)) {
135 		osif_err("Failed to save key");
136 		qdf_mem_free(crypto_key);
137 		return -EINVAL;
138 	}
139 	return 0;
140 }
141 
142 #define WLAN_WAIT_TIME_ADD_KEY 100
143 
144 static void
145 wlan_cfg80211_crypto_add_key_cb(void *context,
146 				struct crypto_add_key_result *result)
147 {
148 	struct osif_request *request;
149 	struct crypto_add_key_result *priv;
150 
151 	request = osif_request_get(context);
152 	if (!request) {
153 		osif_err("Obsolete request");
154 		return;
155 	}
156 
157 	priv = osif_request_priv(request);
158 	qdf_mem_copy(priv, result, sizeof(*priv));
159 	osif_request_complete(request);
160 	osif_request_put(request);
161 }
162 
163 int wlan_cfg80211_crypto_add_key(struct wlan_objmgr_vdev *vdev,
164 				 enum wlan_crypto_key_type key_type,
165 				 uint8_t key_index, bool sync)
166 {
167 	struct wlan_crypto_key *crypto_key;
168 	QDF_STATUS status;
169 	struct osif_request *request;
170 	struct crypto_add_key_result *result;
171 	struct wlan_crypto_comp_priv *priv;
172 	int ret;
173 	static const struct osif_request_params params = {
174 		.priv_size = sizeof(*result),
175 		.timeout_ms = WLAN_WAIT_TIME_ADD_KEY,
176 	};
177 
178 	crypto_key = wlan_crypto_get_key(vdev, key_index);
179 	if (!crypto_key) {
180 		osif_err("Crypto KEY is NULL");
181 		return -EINVAL;
182 	}
183 
184 	if (sync) {
185 		priv = wlan_get_vdev_crypto_obj(vdev);
186 		if (!priv) {
187 			osif_err("Invalid crypto_priv");
188 			return -EINVAL;
189 		}
190 
191 		request = osif_request_alloc(&params);
192 		if (!request) {
193 			osif_err("Request allocation failure");
194 			return -ENOMEM;
195 		}
196 
197 		priv->add_key_ctx = osif_request_cookie(request);;
198 		priv->add_key_cb = wlan_cfg80211_crypto_add_key_cb;
199 
200 		status  = ucfg_crypto_set_key_req(vdev, crypto_key, key_type);
201 		if (QDF_IS_STATUS_SUCCESS(status)) {
202 			ret = osif_request_wait_for_response(request);
203 			if (ret) {
204 				osif_err("Target response timed out");
205 			} else {
206 				result = osif_request_priv(request);
207 				osif_debug("complete, vdev_id %u, ix: %u, flags: %u, status: %u",
208 					   result->vdev_id, result->key_ix,
209 					   result->key_flags, result->status);
210 			}
211 		}
212 
213 		priv->add_key_ctx = NULL;
214 		priv->add_key_cb = NULL;
215 		osif_request_put(request);
216 	} else {
217 		status  = ucfg_crypto_set_key_req(vdev, crypto_key, key_type);
218 	}
219 
220 	return qdf_status_to_os_return(status);
221 }
222 
223 int wlan_cfg80211_set_default_key(struct wlan_objmgr_vdev *vdev,
224 				  uint8_t key_index, struct qdf_mac_addr *bssid)
225 {
226 	return wlan_crypto_default_key(vdev, (uint8_t *)bssid,
227 				       key_index, true);
228 }
229