xref: /wlan-driver/qcacld-3.0/core/hdd/src/wlan_hdd_disa.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1 /*
2  * Copyright (c) 2016-2020 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: wlan_hdd_disa.c
22  *
23  * WLAN Host Device Driver file for DISA certification
24  *
25  */
26 
27 #include "wlan_hdd_disa.h"
28 #include "osif_sync.h"
29 #include "wlan_disa_ucfg_api.h"
30 #include "wlan_osif_request_manager.h"
31 #include "sme_api.h"
32 #include <qca_vendor.h>
33 
34 #define WLAN_WAIT_TIME_ENCRYPT_DECRYPT 1000
35 
36 
37 /**
38  * struct hdd_encrypt_decrypt_msg_context - hdd encrypt/decrypt message context
39  * @status: status of response. 0: no error, -ENOMEM: unable to allocate
40  *   memory for the response payload
41  * @request: encrypt/decrypt request
42  * @response: encrypt/decrypt response
43  */
44 struct hdd_encrypt_decrypt_msg_context {
45 	int status;
46 	struct disa_encrypt_decrypt_req_params request;
47 	struct disa_encrypt_decrypt_resp_params response;
48 };
49 
50 /**
51  * hdd_encrypt_decrypt_msg_cb () - encrypt/decrypt response message handler
52  * @cookie: hdd request cookie
53  * @resp: encrypt/decrypt response parameters
54  *
55  * Return: none
56  */
hdd_encrypt_decrypt_msg_cb(void * cookie,struct disa_encrypt_decrypt_resp_params * resp)57 static void hdd_encrypt_decrypt_msg_cb(void *cookie,
58 	struct disa_encrypt_decrypt_resp_params *resp)
59 {
60 	struct osif_request *request;
61 	struct hdd_encrypt_decrypt_msg_context *context;
62 
63 	hdd_enter();
64 
65 	if (!resp) {
66 		hdd_err("rsp params is NULL");
67 		return;
68 	}
69 
70 	request = osif_request_get(cookie);
71 	if (!request) {
72 		hdd_err("Obsolete request");
73 		return;
74 	}
75 
76 	print_hex_dump(KERN_INFO, "Data in hdd_encrypt_decrypt_msg_cb: ",
77 		DUMP_PREFIX_NONE, 16, 1,
78 		resp->data,
79 		resp->data_len, 0);
80 
81 	hdd_debug("vdev_id: %d status:%d data_length: %d",
82 		resp->vdev_id,
83 		resp->status,
84 		resp->data_len);
85 
86 	context = osif_request_priv(request);
87 	context->response = *resp;
88 	context->status = 0;
89 	if (resp->data_len) {
90 		context->response.data =
91 			qdf_mem_malloc(sizeof(uint8_t) *
92 				resp->data_len);
93 		if (!context->response.data) {
94 			context->status = -ENOMEM;
95 		} else {
96 			qdf_mem_copy(context->response.data,
97 				     resp->data,
98 				     resp->data_len);
99 		}
100 	} else {
101 		/* make sure we don't have a rogue pointer */
102 		context->response.data = NULL;
103 	}
104 
105 	osif_request_complete(request);
106 	osif_request_put(request);
107 	hdd_exit();
108 }
109 
110 /**
111  * hdd_post_encrypt_decrypt_msg_rsp () - send encrypt/decrypt data to user space
112  * @hdd_ctx: HDD context
113  * @resp: encrypt/decrypt response parameters
114  *
115  * Return: none
116  */
hdd_post_encrypt_decrypt_msg_rsp(struct hdd_context * hdd_ctx,struct disa_encrypt_decrypt_resp_params * resp)117 static int hdd_post_encrypt_decrypt_msg_rsp(struct hdd_context *hdd_ctx,
118 	struct disa_encrypt_decrypt_resp_params *resp)
119 {
120 	struct sk_buff *skb;
121 	uint32_t nl_buf_len;
122 
123 	hdd_enter();
124 
125 	nl_buf_len = resp->data_len + NLA_HDRLEN;
126 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
127 						       nl_buf_len);
128 	if (!skb) {
129 		hdd_err("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
130 		return -ENOMEM;
131 	}
132 
133 	if (resp->data_len) {
134 		if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA,
135 			    resp->data_len, resp->data)) {
136 			hdd_err("put fail");
137 			goto nla_put_failure;
138 		}
139 	}
140 
141 	wlan_cfg80211_vendor_cmd_reply(skb);
142 	hdd_exit();
143 	return 0;
144 
145 nla_put_failure:
146 	wlan_cfg80211_vendor_free_skb(skb);
147 	return -EINVAL;
148 }
149 
150 const struct nla_policy
151 encrypt_decrypt_policy[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX + 1] = {
152 	[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_NEEDS_DECRYPTION] = {
153 		.type = NLA_FLAG},
154 	[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER] = {
155 		.type = NLA_U32},
156 	[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID] = {
157 		.type = NLA_U8},
158 };
159 
160 /**
161  * hdd_fill_encrypt_decrypt_params () - parses data from user space
162  * and fills encrypt/decrypt parameters
163  * @encrypt_decrypt_params: encrypt/decrypt request parameters
164  * @adapter : adapter context
165  * @data: Pointer to data
166  * @data_len: Data length
167  *
168  * Return: 0 on success, negative errno on failure
169  */
170 static int
hdd_fill_encrypt_decrypt_params(struct disa_encrypt_decrypt_req_params * encrypt_decrypt_params,struct hdd_adapter * adapter,const void * data,int data_len)171 hdd_fill_encrypt_decrypt_params(struct disa_encrypt_decrypt_req_params
172 				*encrypt_decrypt_params,
173 				struct hdd_adapter *adapter,
174 				const void *data,
175 				int data_len)
176 {
177 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX + 1];
178 	uint8_t len, mac_hdr_len;
179 	uint8_t *tmp;
180 	uint8_t fc[2];
181 
182 	if (wlan_cfg80211_nla_parse(tb,
183 				    QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX,
184 				    data, data_len, encrypt_decrypt_policy)) {
185 		hdd_err("Invalid ATTR");
186 		return -EINVAL;
187 	}
188 
189 	encrypt_decrypt_params->vdev_id = adapter->deflink->vdev_id;
190 	hdd_debug("vdev_id: %d", encrypt_decrypt_params->vdev_id);
191 
192 	if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_NEEDS_DECRYPTION]) {
193 		hdd_err("attr flag NEEDS_DECRYPTION not present");
194 		encrypt_decrypt_params->key_flag = WMI_ENCRYPT;
195 	} else {
196 		hdd_err("attr flag NEEDS_DECRYPTION present");
197 		encrypt_decrypt_params->key_flag = WMI_DECRYPT;
198 	}
199 	hdd_debug("Key flag: %d", encrypt_decrypt_params->key_flag);
200 
201 	if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID]) {
202 		hdd_err("attr key id failed");
203 		return -EINVAL;
204 	}
205 	encrypt_decrypt_params->key_idx = nla_get_u8(tb
206 		    [QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_KEYID]);
207 	hdd_debug("Key Idx: %d", encrypt_decrypt_params->key_idx);
208 
209 	if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER]) {
210 		hdd_err("attr Cipher failed");
211 		return -EINVAL;
212 	}
213 	encrypt_decrypt_params->key_cipher = nla_get_u32(tb
214 		    [QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_CIPHER]);
215 	hdd_debug("key_cipher: %d", encrypt_decrypt_params->key_cipher);
216 
217 	if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK]) {
218 		hdd_err("attr TK failed");
219 		return -EINVAL;
220 	}
221 	encrypt_decrypt_params->key_len =
222 		nla_len(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK]);
223 	if (!encrypt_decrypt_params->key_len) {
224 		hdd_err("Invalid TK length");
225 		return -EINVAL;
226 	}
227 	hdd_debug("Key len: %d", encrypt_decrypt_params->key_len);
228 
229 	if (encrypt_decrypt_params->key_len > SIR_MAC_MAX_KEY_LENGTH)
230 		encrypt_decrypt_params->key_len = SIR_MAC_MAX_KEY_LENGTH;
231 
232 	tmp = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_TK]);
233 
234 	qdf_mem_copy(encrypt_decrypt_params->key_data, tmp,
235 			encrypt_decrypt_params->key_len);
236 
237 	print_hex_dump(KERN_INFO, "Key : ", DUMP_PREFIX_NONE, 16, 1,
238 			&encrypt_decrypt_params->key_data,
239 			encrypt_decrypt_params->key_len, 0);
240 
241 	if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN]) {
242 		hdd_err("attr PN failed");
243 		return -EINVAL;
244 	}
245 	len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN]);
246 	if (!len || len > sizeof(encrypt_decrypt_params->pn)) {
247 		hdd_err("Invalid PN length %u", len);
248 		return -EINVAL;
249 	}
250 
251 	tmp = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_PN]);
252 
253 	qdf_mem_copy(encrypt_decrypt_params->pn, tmp, len);
254 
255 	print_hex_dump(KERN_INFO, "PN received : ", DUMP_PREFIX_NONE, 16, 1,
256 			&encrypt_decrypt_params->pn, len, 0);
257 
258 	if (!tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA]) {
259 		hdd_err("attr header failed");
260 		return -EINVAL;
261 	}
262 	len = nla_len(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA]);
263 	if (len < MIN_MAC_HEADER_LEN) {
264 		hdd_err("Invalid header and payload length %u", len);
265 		return -EINVAL;
266 	}
267 
268 	hdd_debug("Header and Payload length: %d", len);
269 
270 	tmp = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA]);
271 
272 	print_hex_dump(KERN_INFO, "Header and Payload received: ",
273 			DUMP_PREFIX_NONE, 16, 1,
274 			tmp, len, 0);
275 
276 	mac_hdr_len = MIN_MAC_HEADER_LEN;
277 
278 	/*
279 	 * Check to find out address 4. Address 4 is present if ToDS and FromDS
280 	 * are 1 and data representation is little endian.
281 	 */
282 	fc[1] = *tmp;
283 	fc[0] = *(tmp + 1);
284 	if ((fc[0] & 0x03) == 0x03) {
285 		hdd_err("Address 4 is present");
286 		mac_hdr_len += QDF_MAC_ADDR_SIZE;
287 	}
288 
289 	/*
290 	 * Check to find out Qos control field. Qos control field is present
291 	 * if msb of subtype field is 1 and data representation is
292 	 * little endian.
293 	 */
294 	if (fc[1] & 0x80) {
295 		hdd_err("Qos control is present");
296 		mac_hdr_len += QOS_CONTROL_LEN;
297 	}
298 
299 	hdd_debug("mac_hdr_len: %d", mac_hdr_len);
300 
301 	if (len < mac_hdr_len) {
302 		hdd_err("Invalid header and payload length %u", len);
303 		return -EINVAL;
304 	}
305 	qdf_mem_copy(encrypt_decrypt_params->mac_header,
306 			tmp, mac_hdr_len);
307 
308 	print_hex_dump(KERN_INFO, "Header received in request: ",
309 			DUMP_PREFIX_NONE, 16, 1,
310 			encrypt_decrypt_params->mac_header,
311 			mac_hdr_len, 0);
312 
313 	encrypt_decrypt_params->data_len =
314 			len - mac_hdr_len;
315 
316 	hdd_debug("Payload length: %d", encrypt_decrypt_params->data_len);
317 
318 	if (encrypt_decrypt_params->data_len) {
319 		encrypt_decrypt_params->data =
320 			qdf_mem_malloc(sizeof(uint8_t) *
321 				encrypt_decrypt_params->data_len);
322 
323 		if (!encrypt_decrypt_params->data)
324 			return -ENOMEM;
325 
326 		qdf_mem_copy(encrypt_decrypt_params->data,
327 			tmp + mac_hdr_len,
328 			encrypt_decrypt_params->data_len);
329 
330 		print_hex_dump(KERN_INFO, "Data received in request: ",
331 			DUMP_PREFIX_NONE, 16, 1,
332 			encrypt_decrypt_params->data,
333 			encrypt_decrypt_params->data_len, 0);
334 	}
335 
336 	return 0;
337 }
338 
hdd_encrypt_decrypt_context_dealloc(void * priv)339 static void hdd_encrypt_decrypt_context_dealloc(void *priv)
340 {
341 	struct hdd_encrypt_decrypt_msg_context *context = priv;
342 
343 	qdf_mem_free(context->request.data);
344 	qdf_mem_free(context->response.data);
345 }
346 
347 /**
348  * hdd_encrypt_decrypt_msg () - process encrypt/decrypt message
349  * @adapter : adapter context
350  * @hdd_ctx: hdd context
351  * @data: Pointer to data
352  * @data_len: Data length
353  *
354  * Return: 0 on success, negative errno on failure
355  */
hdd_encrypt_decrypt_msg(struct hdd_adapter * adapter,struct hdd_context * hdd_ctx,const void * data,int data_len)356 static int hdd_encrypt_decrypt_msg(struct hdd_adapter *adapter,
357 				   struct hdd_context *hdd_ctx,
358 				   const void *data,
359 				   int data_len)
360 {
361 	QDF_STATUS qdf_status;
362 	int ret;
363 	void *cookie;
364 	struct osif_request *request;
365 	struct hdd_encrypt_decrypt_msg_context *context;
366 	static const struct osif_request_params params = {
367 		.priv_size = sizeof(*context),
368 		.timeout_ms = WLAN_WAIT_TIME_ENCRYPT_DECRYPT,
369 		.dealloc = hdd_encrypt_decrypt_context_dealloc,
370 	};
371 
372 	request = osif_request_alloc(&params);
373 	if (!request) {
374 		hdd_err("Request allocation failure");
375 		return -ENOMEM;
376 	}
377 	context = osif_request_priv(request);
378 
379 	ret = hdd_fill_encrypt_decrypt_params(&context->request, adapter,
380 					      data, data_len);
381 	if (ret)
382 		goto cleanup;
383 
384 	cookie = osif_request_cookie(request);
385 
386 	qdf_status = ucfg_disa_encrypt_decrypt_req(hdd_ctx->psoc,
387 				&context->request,
388 				hdd_encrypt_decrypt_msg_cb,
389 				cookie);
390 
391 	if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
392 		hdd_err("Unable to post encrypt/decrypt message");
393 		ret = -EINVAL;
394 		goto cleanup;
395 	}
396 
397 	ret = osif_request_wait_for_response(request);
398 	if (ret) {
399 		hdd_err("Target response timed out");
400 		goto cleanup;
401 	}
402 
403 	ret = context->status;
404 	if (ret) {
405 		hdd_err("Target response processing failed");
406 		goto cleanup;
407 	}
408 
409 	ret = hdd_post_encrypt_decrypt_msg_rsp(hdd_ctx, &context->response);
410 	if (ret)
411 		hdd_err("Failed to post encrypt/decrypt message response");
412 
413 cleanup:
414 	osif_request_put(request);
415 
416 	hdd_exit();
417 	return ret;
418 }
419 
420 /**
421  * __wlan_hdd_cfg80211_encrypt_decrypt_msg () - Encrypt/Decrypt msg
422  * @wiphy: Pointer to wireless phy
423  * @wdev: Pointer to wireless device
424  * @data: Pointer to data
425  * @data_len: Data length
426  *
427  * Return: 0 on success, negative errno on failure
428  */
__wlan_hdd_cfg80211_encrypt_decrypt_msg(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)429 static int __wlan_hdd_cfg80211_encrypt_decrypt_msg(struct wiphy *wiphy,
430 						struct wireless_dev *wdev,
431 						const void *data,
432 						int data_len)
433 {
434 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
435 	struct net_device *dev = wdev->netdev;
436 	struct hdd_adapter *adapter = NULL;
437 	int ret;
438 	bool is_bmps_enabled;
439 
440 	hdd_enter_dev(dev);
441 
442 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
443 		hdd_err("Command not allowed in FTM mode");
444 		return -EPERM;
445 	}
446 
447 	ret = wlan_hdd_validate_context(hdd_ctx);
448 	if (ret)
449 		return ret;
450 
451 	adapter = WLAN_HDD_GET_PRIV_PTR(dev);
452 
453 	ucfg_mlme_is_bmps_enabled(hdd_ctx->psoc, &is_bmps_enabled);
454 	if (is_bmps_enabled) {
455 		hdd_debug("DISA is not supported when PS is enabled");
456 		return -EINVAL;
457 	}
458 
459 	ret = hdd_encrypt_decrypt_msg(adapter, hdd_ctx, data, data_len);
460 
461 	return ret;
462 }
463 
464 /**
465  * wlan_hdd_cfg80211_encrypt_decrypt_msg () - Encrypt/Decrypt msg
466  * @wiphy: Pointer to wireless phy
467  * @wdev: Pointer to wireless device
468  * @data: Pointer to data
469  * @data_len: Data length
470  *
471  * Return: 0 on success, negative errno on failure
472  */
wlan_hdd_cfg80211_encrypt_decrypt_msg(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)473 int wlan_hdd_cfg80211_encrypt_decrypt_msg(struct wiphy *wiphy,
474 						struct wireless_dev *wdev,
475 						const void *data,
476 						int data_len)
477 {
478 	int errno;
479 	struct osif_vdev_sync *vdev_sync;
480 
481 	errno = osif_vdev_sync_op_start(wdev->netdev, &vdev_sync);
482 	if (errno)
483 		return errno;
484 
485 	errno = __wlan_hdd_cfg80211_encrypt_decrypt_msg(wiphy, wdev,
486 							data, data_len);
487 
488 	osif_vdev_sync_op_stop(vdev_sync);
489 
490 	return errno;
491 }
492