blob: a4153fc5f1db38d2ffa036f1797778ecd6e01a48 [file] [log] [blame]
Padma, Santhosh Kumard7cc0792016-06-28 18:54:12 +05301/*
2 * Copyright (c) 2016 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 : wlan_hdd_disa.c
21 *
22 * WLAN Host Device Driver file for DISA certification
23 *
24 */
25
26#include "wlan_hdd_disa.h"
27#include "sme_api.h"
28
29#define ENCRYPT_DECRYPT_CONTEXT_MAGIC 0x4475354
30#define WLAN_WAIT_TIME_ENCRYPT_DECRYPT 1000
31
32
33/**
34 * hdd_encrypt_decrypt_msg_context - hdd encrypt/decrypt message context
35 *
36 * @magic: magic number
37 * @completion: Completion variable for encrypt/decrypt message
38 * @response_event: encrypt/decrypt message request wait event
39 */
40struct hdd_encrypt_decrypt_msg_context {
41 unsigned int magic;
42 struct completion completion;
43 struct sir_encrypt_decrypt_rsp_params response;
44};
45static struct hdd_encrypt_decrypt_msg_context encrypt_decrypt_msg_context;
46
47/**
48 * hdd_encrypt_decrypt_msg_cb () - sends encrypt/decrypt data to user space
49 * @encrypt_decrypt_rsp_params: encrypt/decrypt response parameters
50 *
51 * Return: none
52 */
53static void hdd_encrypt_decrypt_msg_cb(void *hdd_context,
54 struct sir_encrypt_decrypt_rsp_params *encrypt_decrypt_rsp_params)
55{
56 hdd_context_t *hdd_ctx = hdd_context;
57 int ret;
58 struct hdd_encrypt_decrypt_msg_context *context;
59
60 ENTER();
61
62 ret = wlan_hdd_validate_context(hdd_ctx);
63 if (ret)
64 return;
65
66 if (!encrypt_decrypt_rsp_params) {
67 hdd_err("rsp params is NULL");
68 return;
69 }
70
71 print_hex_dump(KERN_INFO, "Data in hdd_encrypt_decrypt_msg_cb: ",
72 DUMP_PREFIX_NONE, 16, 1,
73 encrypt_decrypt_rsp_params->data,
74 encrypt_decrypt_rsp_params->data_length, 0);
75
76 hdd_err("vdev_id %d,status %d data_length %d",
77 encrypt_decrypt_rsp_params->vdev_id,
78 encrypt_decrypt_rsp_params->status,
79 encrypt_decrypt_rsp_params->data_length);
80
81 spin_lock(&hdd_context_lock);
82
83 context = &encrypt_decrypt_msg_context;
84 /* The caller presumably timed out so there is nothing we can do */
85 if (context->magic != ENCRYPT_DECRYPT_CONTEXT_MAGIC) {
86 spin_unlock(&hdd_context_lock);
87 return;
88 }
89
90 /* context is valid so caller is still waiting */
91 context->response = *encrypt_decrypt_rsp_params;
92
93 if (encrypt_decrypt_rsp_params->data_length) {
94 context->response.data =
95 qdf_mem_malloc(sizeof(uint8_t) *
96 encrypt_decrypt_rsp_params->data_length);
97 if (context->response.data == NULL) {
98 hdd_err("cdf_mem_alloc failed for data");
99 spin_unlock(&hdd_context_lock);
100 return;
101 }
102 qdf_mem_copy(context->response.data,
103 encrypt_decrypt_rsp_params->data,
104 encrypt_decrypt_rsp_params->data_length);
105 }
106
107 /*
108 * Indicate to calling thread that
109 * response data is available
110 */
111 context->magic = 0;
112
113 complete(&context->completion);
114
115 spin_unlock(&hdd_context_lock);
116
117
118 EXIT();
119}
120
121
122/**
123 * hdd_encrypt_decrypt_msg_cb () - sends encrypt/decrypt data to user space
124 * @encrypt_decrypt_rsp_params: encrypt/decrypt response parameters
125 *
126 * Return: none
127 */
128static int hdd_post_encrypt_decrypt_msg_rsp(hdd_context_t *hdd_ctx,
129 struct sir_encrypt_decrypt_rsp_params *encrypt_decrypt_rsp_params)
130{
131 struct sk_buff *skb;
132 uint32_t nl_buf_len;
133
134 ENTER();
135
136 nl_buf_len = encrypt_decrypt_rsp_params->data_length + NLA_HDRLEN;
137
138 skb = cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy, nl_buf_len);
139 if (!skb) {
140 hdd_err(FL("cfg80211_vendor_cmd_alloc_reply_skb failed"));
141 return -ENOMEM;
142 }
143
144 if (encrypt_decrypt_rsp_params->data_length) {
145 if (nla_put(skb, QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_DATA,
146 encrypt_decrypt_rsp_params->data_length,
147 encrypt_decrypt_rsp_params->data)) {
148 hdd_err(FL("put fail"));
149 goto nla_put_failure;
150 }
151 }
152
153 cfg80211_vendor_cmd_reply(skb);
154 EXIT();
155 return 0;
156
157nla_put_failure:
158 kfree_skb(skb);
159 return -EINVAL;
160}
161
162/**
163 * hdd_fill_encrypt_decrypt_params () - parses data from user space
164 * and fills encrypt/decrypt parameters
165 * @encrypt_decrypt_params: encrypt/decrypt request parameters
166 * @adapter : adapter context
167 * @data: Pointer to data
168 * @data_len: Data length
169 *
170 Return: 0 on success, negative errno on failure
171 */
172static int hdd_fill_encrypt_decrypt_params(struct encrypt_decrypt_req_params
173 *encrypt_decrypt_params,
174 hdd_adapter_t *adapter,
175 const void *data,
176 int data_len)
177{
178 struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX + 1];
179 uint8_t len, mac_hdr_len;
180 uint8_t *tmp;
181 uint8_t fc[2];
182
183 if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ENCRYPTION_TEST_MAX,
184 data, data_len, NULL)) {
185 hdd_err("Invalid ATTR");
186 return -EINVAL;
187 }
188
189 encrypt_decrypt_params->vdev_id = adapter->sessionId;
190 hdd_err("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_err("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_err("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_err("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_err("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) {
247 hdd_err("Invalid PN length");
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) {
264 hdd_err("Invalid header and payload length");
265 return -EINVAL;
266 }
267
268 hdd_err("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 += IEEE80211_ADDR_LEN;
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_err("mac_hdr_len %d", mac_hdr_len);
300
301 qdf_mem_copy(encrypt_decrypt_params->mac_header,
302 tmp, mac_hdr_len);
303
304 print_hex_dump(KERN_INFO, "Header received in request: ",
305 DUMP_PREFIX_NONE, 16, 1,
306 encrypt_decrypt_params->mac_header,
307 mac_hdr_len, 0);
308
309 encrypt_decrypt_params->data_len =
310 len - mac_hdr_len;
311
312 hdd_err("Payload length : %d", encrypt_decrypt_params->data_len);
313
314 if (encrypt_decrypt_params->data_len) {
315 encrypt_decrypt_params->data =
316 qdf_mem_malloc(sizeof(uint8_t) *
317 encrypt_decrypt_params->data_len);
318
319 if (encrypt_decrypt_params->data == NULL) {
320 hdd_err("cdf_mem_alloc failed for data");
321 return -ENOMEM;
322 }
323
324 qdf_mem_copy(encrypt_decrypt_params->data,
325 tmp + mac_hdr_len,
326 encrypt_decrypt_params->data_len);
327
328 print_hex_dump(KERN_INFO, "Data received in request: ",
329 DUMP_PREFIX_NONE, 16, 1,
330 encrypt_decrypt_params->data,
331 encrypt_decrypt_params->data_len, 0);
332 }
333
334 return 0;
335}
336
337/**
338 * hdd_encrypt_decrypt_msg () - process encrypt/decrypt message
339 * @adapter : adapter context
340 * @hdd_ctx: hdd context
341 * @data: Pointer to data
342 * @data_len: Data length
343 *
344 Return: 0 on success, negative errno on failure
345 */
346static int hdd_encrypt_decrypt_msg(hdd_adapter_t *adapter,
347 hdd_context_t *hdd_ctx,
348 const void *data,
349 int data_len)
350{
351 struct encrypt_decrypt_req_params encrypt_decrypt_params = {0};
352 QDF_STATUS qdf_status;
353 int ret;
354 struct hdd_encrypt_decrypt_msg_context *context;
355 unsigned long rc;
356
357 ret = hdd_fill_encrypt_decrypt_params(&encrypt_decrypt_params,
358 adapter, data, data_len);
359 if (ret)
360 return ret;
361
362 spin_lock(&hdd_context_lock);
363 context = &encrypt_decrypt_msg_context;
364 context->magic = ENCRYPT_DECRYPT_CONTEXT_MAGIC;
365 INIT_COMPLETION(context->completion);
366 spin_unlock(&hdd_context_lock);
367
368 qdf_status = sme_encrypt_decrypt_msg(hdd_ctx->hHal,
369 &encrypt_decrypt_params);
370
371 qdf_mem_free(encrypt_decrypt_params.data);
372
373 if (!QDF_IS_STATUS_SUCCESS(qdf_status)) {
374 hdd_err("Unable to post encrypt/decrypt message");
375 return -EINVAL;
376 }
377
378 rc = wait_for_completion_timeout(&context->completion,
379 msecs_to_jiffies(WLAN_WAIT_TIME_ENCRYPT_DECRYPT));
380
381 spin_lock(&hdd_context_lock);
382 if (!rc && (context->magic ==
383 ENCRYPT_DECRYPT_CONTEXT_MAGIC)) {
384 hdd_err("Target response timed out");
385 context->magic = 0;
386 spin_unlock(&hdd_context_lock);
387 return -ETIMEDOUT;
388 }
389
390 spin_unlock(&hdd_context_lock);
391 ret = hdd_post_encrypt_decrypt_msg_rsp(hdd_ctx,
392 &encrypt_decrypt_msg_context.response);
393 if (ret)
394 hdd_err("Failed to post encrypt/decrypt message response");
395
396 qdf_mem_free(encrypt_decrypt_msg_context.response.data);
397
398 EXIT();
399 return ret;
400}
401
402/**
403 * hdd_encrypt_decrypt_init () - exposes encrypt/decrypt initialization
404 * functionality
405 * @hdd_ctx: hdd context
406 *
407 Return: 0 on success, negative errno on failure
408 */
409int hdd_encrypt_decrypt_init(hdd_context_t *hdd_ctx)
410{
411 QDF_STATUS status;
412
413 init_completion(&encrypt_decrypt_msg_context.completion);
414
415 status = sme_encrypt_decrypt_msg_register_callback(hdd_ctx->hHal,
416 hdd_encrypt_decrypt_msg_cb);
417 if (!QDF_IS_STATUS_SUCCESS(status)) {
418 hdd_err("encrypt/decrypt callback failed %d", status);
419 return -EINVAL;
420 }
421 return 0;
422}
423
424/**
425 * hdd_encrypt_decrypt_deinit () - exposes encrypt/decrypt deinitialization
426 * functionality
427 * @hdd_ctx: hdd context
428 *
429 Return: 0 on success, negative errno on failure
430 */
431int hdd_encrypt_decrypt_deinit(hdd_context_t *hdd_ctx)
432{
433 QDF_STATUS status;
434
435 status = sme_encrypt_decrypt_msg_deregister_callback(hdd_ctx->hHal);
436 if (!QDF_IS_STATUS_SUCCESS(status))
437 hdd_err("De-register encrypt/decrypt callback failed: %d",
438 status);
439 return 0;
440}
441
442/**
443 * __wlan_hdd_cfg80211_encrypt_decrypt_msg () - Encrypt/Decrypt msg
444 * @wiphy: Pointer to wireless phy
445 * @wdev: Pointer to wireless device
446 * @data: Pointer to data
447 * @data_len: Data length
448 *
449 * Return: 0 on success, negative errno on failure
450 */
451static int __wlan_hdd_cfg80211_encrypt_decrypt_msg(struct wiphy *wiphy,
452 struct wireless_dev *wdev,
453 const void *data,
454 int data_len)
455{
456 hdd_context_t *hdd_ctx = wiphy_priv(wiphy);
457 struct net_device *dev = wdev->netdev;
458 hdd_adapter_t *adapter = NULL;
459 int ret;
460
461 ENTER_DEV(dev);
462
463 ret = wlan_hdd_validate_context(hdd_ctx);
464 if (ret)
465 return ret;
466
467 adapter = WLAN_HDD_GET_PRIV_PTR(dev);
468
469 ret = hdd_encrypt_decrypt_msg(adapter, hdd_ctx, data, data_len);
470
471 return ret;
472}
473
474/**
475 * wlan_hdd_cfg80211_encrypt_decrypt_msg () - Encrypt/Decrypt msg
476 * @wiphy: Pointer to wireless phy
477 * @wdev: Pointer to wireless device
478 * @data: Pointer to data
479 * @data_len: Data length
480 *
481 * Return: 0 on success, negative errno on failure
482 */
483int wlan_hdd_cfg80211_encrypt_decrypt_msg(struct wiphy *wiphy,
484 struct wireless_dev *wdev,
485 const void *data,
486 int data_len)
487{
488 int ret;
489
490 cds_ssr_protect(__func__);
491 ret = __wlan_hdd_cfg80211_encrypt_decrypt_msg(wiphy, wdev,
492 data, data_len);
493 cds_ssr_unprotect(__func__);
494
495 return ret;
496}