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(¶ms);
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