Linux-libre 3.10.54-gnu
[librecmc/linux-libre.git] / drivers / staging / csr / sme_blocking.c
1 /*
2  * ---------------------------------------------------------------------------
3  * FILE:     sme_mgt_blocking.c
4  *
5  * PURPOSE:
6  *      This file contains the driver specific implementation of
7  *      the WEXT <==> SME MGT interface for all SME builds that support WEXT.
8  *
9  * Copyright (C) 2009 by Cambridge Silicon Radio Ltd.
10  *
11  * Refer to LICENSE.txt included with this source code for details on
12  * the license terms.
13  *
14  * ---------------------------------------------------------------------------
15  */
16
17 #include "unifi_priv.h"
18
19
20 /*
21  * This file also contains the implementation of the asynchronous
22  * requests to the SME.
23  *
24  * Before calling an asynchronous SME function, we call sme_init_request()
25  * which gets hold of the SME semaphore and updates the request status.
26  * The semaphore makes sure that there is only one pending request to
27  * the SME at a time.
28  *
29  * Now we are ready to call the SME function, but only if
30  * sme_init_request() has returned 0.
31  *
32  * When the SME function returns, we need to wait
33  * for the reply. This is done in sme_wait_for_reply().
34  * If the request times-out, the request status is set to SME_REQUEST_TIMEDOUT
35  * and the sme_wait_for_reply() returns.
36  *
37  * If the SME replies in time, we call sme_complete_request().
38  * There we change the request status to SME_REQUEST_RECEIVED. This will
39  * wake up the process waiting on sme_wait_for_reply().
40  * It is important that we copy the reply data in priv->sme_reply
41  * before calling sme_complete_request().
42  *
43  * Handling the wext requests, we need to block
44  * until the SME sends the response to our request.
45  * We use the sme_init_request() and sme_wait_for_reply()
46  * to implement this behavior in the following functions:
47  * sme_mgt_wifi_on()
48  * sme_mgt_wifi_off()
49  * sme_mgt_scan_full()
50  * sme_mgt_scan_results_get_async()
51  * sme_mgt_connect()
52  * unifi_mgt_media_status_ind()
53  * sme_mgt_disconnect()
54  * sme_mgt_pmkid()
55  * sme_mgt_key()
56  * sme_mgt_mib_get()
57  * sme_mgt_mib_set()
58  * sme_mgt_versions_get()
59  * sme_mgt_set_value()
60  * sme_mgt_get_value()
61  * sme_mgt_set_value_async()
62  * sme_mgt_get_value_async()
63  * sme_mgt_packet_filter_set()
64  * sme_mgt_tspec()
65  */
66
67
68 /*
69  * Handling the suspend and resume system events, we need to block
70  * until the SME sends the response to our indication.
71  * We use the sme_init_request() and sme_wait_for_reply()
72  * to implement this behavior in the following functions:
73  * sme_sys_suspend()
74  * sme_sys_resume()
75  */
76
77 #define UNIFI_SME_MGT_SHORT_TIMEOUT    10000
78 #define UNIFI_SME_MGT_LONG_TIMEOUT     19000
79 #define UNIFI_SME_SYS_LONG_TIMEOUT     10000
80
81 #ifdef UNIFI_DEBUG
82 # define sme_wait_for_reply(priv, t) _sme_wait_for_reply(priv, t, __func__)
83 #else
84 # define sme_wait_for_reply(priv, t) _sme_wait_for_reply(priv, t, NULL)
85 #endif
86
87 static int
88 sme_init_request(unifi_priv_t *priv)
89 {
90     if (priv == NULL) {
91         unifi_error(priv, "sme_init_request: Invalid priv\n");
92         return -EIO;
93     }
94
95     unifi_trace(priv, UDBG5, "sme_init_request: wait sem\n");
96
97     /* Grab the SME semaphore until the reply comes, or timeout */
98     if (down_interruptible(&priv->sme_sem)) {
99         unifi_error(priv, "sme_init_request: Failed to get SME semaphore\n");
100         return -EIO;
101     }
102     unifi_trace(priv, UDBG5, "sme_init_request: got sem: pending\n");
103
104     priv->sme_reply.request_status = SME_REQUEST_PENDING;
105
106     return 0;
107
108 } /* sme_init_request() */
109
110
111 void
112 uf_sme_complete_request(unifi_priv_t *priv, CsrResult reply_status, const char *func)
113 {
114     if (priv == NULL) {
115         unifi_error(priv, "sme_complete_request: Invalid priv\n");
116         return;
117     }
118
119     if (priv->sme_reply.request_status != SME_REQUEST_PENDING) {
120         unifi_notice(priv,
121                     "sme_complete_request: request not pending %s (s:%d)\n",
122                     (func ? func : ""), priv->sme_reply.request_status);
123         return;
124     }
125     unifi_trace(priv, UDBG5,
126                 "sme_complete_request: completed %s (s:%d)\n",
127                 (func ? func : ""), priv->sme_reply.request_status);
128
129     priv->sme_reply.request_status = SME_REQUEST_RECEIVED;
130     priv->sme_reply.reply_status = reply_status;
131
132     wake_up_interruptible(&priv->sme_request_wq);
133
134     return;
135 }
136
137
138 void
139 uf_sme_cancel_request(unifi_priv_t *priv, CsrResult reply_status)
140 {
141     /* Check for a blocking SME request in progress, and cancel the wait.
142      * This should be used when the character device is closed.
143      */
144
145     if (priv == NULL) {
146         unifi_error(priv, "sme_cancel_request: Invalid priv\n");
147         return;
148     }
149
150     /* If no request is pending, nothing to wake up */
151     if (priv->sme_reply.request_status != SME_REQUEST_PENDING) {
152         unifi_trace(priv, UDBG5,
153                     "sme_cancel_request: no request was pending (s:%d)\n",
154                     priv->sme_reply.request_status);
155         /* Nothing to do */
156         return;
157     }
158     unifi_trace(priv, UDBG5,
159                 "sme_cancel_request: request cancelled (s:%d)\n",
160                 priv->sme_reply.request_status);
161
162     /* Wake up the wait with an error status */
163     priv->sme_reply.request_status = SME_REQUEST_CANCELLED;
164     priv->sme_reply.reply_status = reply_status; /* unimportant since the CANCELLED state will fail the ioctl */
165
166     wake_up_interruptible(&priv->sme_request_wq);
167
168     return;
169 }
170
171
172 static int
173 _sme_wait_for_reply(unifi_priv_t *priv,
174         unsigned long timeout, const char *func)
175 {
176     long r;
177
178     unifi_trace(priv, UDBG5, "sme_wait_for_reply: %s sleep\n", func ? func : "");
179     r = wait_event_interruptible_timeout(priv->sme_request_wq,
180                                          (priv->sme_reply.request_status != SME_REQUEST_PENDING),
181                                          msecs_to_jiffies(timeout));
182     unifi_trace(priv, UDBG5, "sme_wait_for_reply: %s awake (%d)\n", func ? func : "", r);
183
184     if (r == -ERESTARTSYS) {
185         /* The thread was killed */
186         unifi_info(priv, "ERESTARTSYS in _sme_wait_for_reply\n");
187         up(&priv->sme_sem);
188         return r;
189     }
190     if (priv->sme_reply.request_status == SME_REQUEST_CANCELLED) {
191         unifi_trace(priv, UDBG5, "Cancelled waiting for SME to reply (%s s:%d, t:%d, r:%d)\n",
192                     (func ? func : ""), priv->sme_reply.request_status, timeout, r);
193
194         /* Release the SME semaphore that was downed in sme_init_request() */
195         up(&priv->sme_sem);
196         return -EIO; /* fail the ioctl */
197     }
198     if ((r == 0) && (priv->sme_reply.request_status != SME_REQUEST_RECEIVED)) {
199         unifi_notice(priv, "Timeout waiting for SME to reply (%s s:%d, t:%d)\n",
200                      (func ? func : ""), priv->sme_reply.request_status, timeout);
201
202         priv->sme_reply.request_status = SME_REQUEST_TIMEDOUT;
203
204         /* Release the SME semaphore that was downed in sme_init_request() */
205         up(&priv->sme_sem);
206
207         return -ETIMEDOUT;
208     }
209
210     unifi_trace(priv, UDBG5, "sme_wait_for_reply: %s received (%d)\n",
211                 func ? func : "", r);
212
213     /* Release the SME semaphore that was downed in sme_init_request() */
214     up(&priv->sme_sem);
215
216     return 0;
217 } /* sme_wait_for_reply() */
218
219
220
221
222 #ifdef CSR_SUPPORT_WEXT
223 int sme_mgt_wifi_on(unifi_priv_t *priv)
224 {
225     u16 numElements;
226     CsrWifiSmeDataBlock* dataList;
227 #ifdef CSR_SUPPORT_WEXT_AP
228     int r;
229 #endif
230
231     if (priv->smepriv == NULL) {
232         unifi_error(priv, "sme_mgt_wifi_on: invalid smepriv\n");
233         return -EIO;
234     }
235
236     if (priv->mib_data.length) {
237         numElements = 1;
238         dataList = &priv->mib_data;
239     } else {
240         numElements = 0;
241         dataList = NULL;
242     }
243     /* Start the SME */
244 #ifdef CSR_SUPPORT_WEXT_AP
245     r = sme_init_request(priv);
246     if (r) {
247         return -EIO;
248     }
249 #endif
250     CsrWifiSmeWifiOnReqSend(0, priv->sta_mac_address, numElements, dataList);
251 #ifdef CSR_SUPPORT_WEXT_AP
252     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_LONG_TIMEOUT);
253     unifi_trace(priv, UDBG4,
254                 "sme_mgt_wifi_on: unifi_mgt_wifi_oo_req <-- (r=%d, status=%d)\n",
255                 r, priv->sme_reply.reply_status);
256     return convert_sme_error(priv->sme_reply.reply_status);
257 #else
258     return 0;
259 #endif
260 } /* sme_mgt_wifi_on() */
261
262
263 int sme_mgt_wifi_off(unifi_priv_t *priv)
264 {
265     int r;
266
267     if (priv->smepriv == NULL) {
268         unifi_error(priv, "sme_mgt_wifi_off: invalid smepriv\n");
269         return -EIO;
270     }
271
272     r = sme_init_request(priv);
273     if (r)
274         return -EIO;
275
276     /* Stop the SME */
277     CsrWifiSmeWifiOffReqSend(0);
278
279     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_LONG_TIMEOUT);
280     if (r)
281         return r;
282
283     unifi_trace(priv, UDBG4,
284                 "sme_mgt_wifi_off: unifi_mgt_wifi_off_req <-- (r=%d, status=%d)\n",
285                 r, priv->sme_reply.reply_status);
286     return convert_sme_error(priv->sme_reply.reply_status);
287
288 } /* sme_mgt_wifi_off */
289
290 int sme_mgt_key(unifi_priv_t *priv, CsrWifiSmeKey *sme_key,
291         CsrWifiSmeListAction action)
292 {
293     int r;
294
295     if (priv->smepriv == NULL) {
296         unifi_error(priv, "sme_mgt_key: invalid smepriv\n");
297         return -EIO;
298     }
299
300     r = sme_init_request(priv);
301     if (r)
302         return -EIO;
303
304     CsrWifiSmeKeyReqSend(0, CSR_WIFI_INTERFACE_IN_USE, action, *sme_key);
305
306     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
307     if (r)
308         return r;
309
310     return convert_sme_error(priv->sme_reply.reply_status);
311 }
312
313
314 int sme_mgt_scan_full(unifi_priv_t *priv,
315         CsrWifiSsid *specific_ssid,
316         int num_channels,
317         unsigned char *channel_list)
318 {
319     CsrWifiMacAddress bcastAddress = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }};
320     u8 is_active = (num_channels > 0) ? TRUE : FALSE;
321     int r;
322
323     if (priv->smepriv == NULL) {
324         unifi_error(priv, "sme_mgt_scan_full: invalid smepriv\n");
325         return -EIO;
326     }
327
328     unifi_trace(priv, UDBG4, "sme_mgt_scan_full: -->\n");
329
330     r = sme_init_request(priv);
331     if (r)
332         return -EIO;
333
334     /* If a channel list is provided, do an active scan */
335     if (is_active) {
336         unifi_trace(priv, UDBG1,
337                     "channel list - num_channels: %d, active scan\n",
338                     num_channels);
339     }
340
341     CsrWifiSmeScanFullReqSend(0,
342                               specific_ssid->length?1:0, /* 0 or 1 SSIDS */
343                               specific_ssid,
344                               bcastAddress,
345                               is_active,
346                               CSR_WIFI_SME_BSS_TYPE_ANY_BSS,
347                               CSR_WIFI_SME_SCAN_TYPE_ALL,
348                               (u16)num_channels, channel_list,
349                               0, NULL);
350
351     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_LONG_TIMEOUT);
352     if (r)
353         return r;
354
355     unifi_trace(priv, UDBG4, "sme_mgt_scan_full: <-- (status=%d)\n", priv->sme_reply.reply_status);
356     if (priv->sme_reply.reply_status == CSR_WIFI_RESULT_UNAVAILABLE)
357         return 0; /* initial scan already underway */
358     else
359         return convert_sme_error(priv->sme_reply.reply_status);
360 }
361
362
363 int sme_mgt_scan_results_get_async(unifi_priv_t *priv,
364         struct iw_request_info *info,
365         char *scan_results,
366         long scan_results_len)
367 {
368     u16 scan_result_list_count;
369     CsrWifiSmeScanResult *scan_result_list;
370     CsrWifiSmeScanResult *scan_result;
371     int r;
372     int i;
373     char *current_ev = scan_results;
374
375     if (priv->smepriv == NULL) {
376         unifi_error(priv, "sme_mgt_scan_results_get_async: invalid smepriv\n");
377         return -EIO;
378     }
379
380     r = sme_init_request(priv);
381     if (r)
382         return -EIO;
383
384     CsrWifiSmeScanResultsGetReqSend(0);
385     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_LONG_TIMEOUT);
386     if (r)
387         return r;
388
389     scan_result_list_count = priv->sme_reply.reply_scan_results_count;
390     scan_result_list = priv->sme_reply.reply_scan_results;
391     unifi_trace(priv, UDBG2,
392                 "scan_results: Scan returned %d, numElements=%d\n",
393                 r, scan_result_list_count);
394
395     /* OK, now we have the scan results */
396     for (i = 0; i < scan_result_list_count; ++i) {
397         scan_result = &scan_result_list[i];
398
399         unifi_trace(priv, UDBG2, "Scan Result: %.*s\n",
400                     scan_result->ssid.length,
401                     scan_result->ssid.ssid);
402
403         r = unifi_translate_scan(priv->netdev[0], info,
404                                  current_ev,
405                                  scan_results + scan_results_len,
406                                  scan_result, i+1);
407
408         if (r < 0) {
409             kfree(scan_result_list);
410             priv->sme_reply.reply_scan_results_count = 0;
411             priv->sme_reply.reply_scan_results = NULL;
412             return r;
413         }
414
415         current_ev += r;
416     }
417
418     /*
419      * Free the scan results allocated in unifi_mgt_scan_results_get_cfm()
420      * and invalidate the reply_scan_results to avoid re-using
421      * the freed pointers.
422      */
423     kfree(scan_result_list);
424     priv->sme_reply.reply_scan_results_count = 0;
425     priv->sme_reply.reply_scan_results = NULL;
426
427     unifi_trace(priv, UDBG2,
428                 "scan_results: Scan translated to %d bytes\n",
429                 current_ev - scan_results);
430     return (current_ev - scan_results);
431 }
432
433
434 int sme_mgt_connect(unifi_priv_t *priv)
435 {
436     int r;
437
438     if (priv->smepriv == NULL) {
439         unifi_error(priv, "sme_mgt_connect: invalid smepriv\n");
440         return -EIO;
441     }
442
443     unifi_trace(priv, UDBG2, "sme_mgt_connect: %.*s\n",
444                 priv->connection_config.ssid.length,
445                 priv->connection_config.ssid.ssid);
446
447     r = sme_init_request(priv);
448     if (r)
449         return -EIO;
450
451     CsrWifiSmeConnectReqSend(0, CSR_WIFI_INTERFACE_IN_USE, priv->connection_config);
452     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
453     if (r)
454         return r;
455
456     if (priv->sme_reply.reply_status)
457         unifi_trace(priv, UDBG1, "sme_mgt_connect: failed with SME status %d\n",
458                     priv->sme_reply.reply_status);
459
460     return convert_sme_error(priv->sme_reply.reply_status);
461 }
462
463
464 int sme_mgt_disconnect(unifi_priv_t *priv)
465 {
466     int r;
467
468     if (priv->smepriv == NULL) {
469         unifi_error(priv, "sme_mgt_disconnect: invalid smepriv\n");
470         return -EIO;
471     }
472
473     r = sme_init_request(priv);
474     if (r)
475         return -EIO;
476
477     CsrWifiSmeDisconnectReqSend(0, CSR_WIFI_INTERFACE_IN_USE);
478     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
479     if (r)
480         return r;
481
482     unifi_trace(priv, UDBG4, "sme_mgt_disconnect: <-- (status=%d)\n", priv->sme_reply.reply_status);
483     return convert_sme_error(priv->sme_reply.reply_status);
484 }
485
486
487 int sme_mgt_pmkid(unifi_priv_t *priv,
488         CsrWifiSmeListAction action,
489         CsrWifiSmePmkidList *pmkid_list)
490 {
491     int r;
492
493     if (priv->smepriv == NULL) {
494         unifi_error(priv, "sme_mgt_pmkid: invalid smepriv\n");
495         return -EIO;
496     }
497
498     r = sme_init_request(priv);
499     if (r)
500         return -EIO;
501
502     CsrWifiSmePmkidReqSend(0, CSR_WIFI_INTERFACE_IN_USE, action,
503                         pmkid_list->pmkidsCount, pmkid_list->pmkids);
504     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
505     if (r)
506         return r;
507
508     unifi_trace(priv, UDBG4, "sme_mgt_pmkid: <-- (status=%d)\n", priv->sme_reply.reply_status);
509     return convert_sme_error(priv->sme_reply.reply_status);
510 }
511
512
513 int sme_mgt_mib_get(unifi_priv_t *priv,
514         unsigned char *varbind, int *length)
515 {
516     int r;
517
518     if (priv->smepriv == NULL) {
519         unifi_error(priv, "sme_mgt_mib_get: invalid smepriv\n");
520         return -EIO;
521     }
522
523     r = sme_init_request(priv);
524     if (r)
525         return -EIO;
526
527     priv->mib_cfm_buffer = varbind;
528     priv->mib_cfm_buffer_length = MAX_VARBIND_LENGTH;
529
530     CsrWifiSmeMibGetReqSend(0, *length, varbind);
531     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
532     if (r) {
533         priv->mib_cfm_buffer_length = 0;
534         priv->mib_cfm_buffer = NULL;
535         return r;
536     }
537
538     *length = priv->mib_cfm_buffer_length;
539
540     priv->mib_cfm_buffer_length = 0;
541     priv->mib_cfm_buffer = NULL;
542     unifi_trace(priv, UDBG4, "sme_mgt_mib_get: <-- (status=%d)\n", priv->sme_reply.reply_status);
543     return convert_sme_error(priv->sme_reply.reply_status);
544 }
545
546 int sme_mgt_mib_set(unifi_priv_t *priv,
547         unsigned char *varbind, int length)
548 {
549     int r;
550
551     if (priv->smepriv == NULL) {
552         unifi_error(priv, "sme_mgt_mib_get: invalid smepriv\n");
553         return -EIO;
554     }
555
556     r = sme_init_request(priv);
557     if (r)
558         return -EIO;
559
560     CsrWifiSmeMibSetReqSend(0, length, varbind);
561     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
562     if (r)
563         return r;
564
565     unifi_trace(priv, UDBG4, "sme_mgt_mib_set: <-- (status=%d)\n", priv->sme_reply.reply_status);
566     return convert_sme_error(priv->sme_reply.reply_status);
567 }
568
569 #endif /* CSR_SUPPORT_WEXT */
570
571 int sme_mgt_power_config_set(unifi_priv_t *priv, CsrWifiSmePowerConfig *powerConfig)
572 {
573 #ifdef CSR_SME_USERSPACE
574     int r;
575
576     if (priv->smepriv == NULL) {
577         unifi_error(priv, "sme_mgt_set_value_async: invalid smepriv\n");
578         return -EIO;
579     }
580
581     r = sme_init_request(priv);
582     if (r)
583         return -EIO;
584
585     CsrWifiSmePowerConfigSetReqSend(0, *powerConfig);
586
587     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
588     if (r)
589         return r;
590
591     unifi_trace(priv, UDBG4,
592                 "sme_mgt_set_value_async: unifi_mgt_set_value_req <-- (r=%d status=%d)\n",
593                 r, priv->sme_reply.reply_status);
594     return convert_sme_error(priv->sme_reply.reply_status);
595 #else
596     CsrResult status;
597     if (priv->smepriv == NULL) {
598         unifi_error(priv, "sme_mgt_set_value: invalid smepriv\n");
599         return -EIO;
600     }
601     CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
602     status = CsrWifiSmeMgtPowerConfigSetReq(priv->smepriv, *powerConfig);
603     CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
604     return convert_sme_error(status);
605 #endif
606 }
607
608 int sme_mgt_sme_config_set(unifi_priv_t *priv, CsrWifiSmeStaConfig *staConfig, CsrWifiSmeDeviceConfig *deviceConfig)
609 {
610 #ifdef CSR_SME_USERSPACE
611     int r;
612
613     if (priv->smepriv == NULL) {
614         unifi_error(priv, "sme_mgt_sme_config_set: invalid smepriv\n");
615         return -EIO;
616     }
617
618     r = sme_init_request(priv);
619     if (r)
620         return -EIO;
621
622     CsrWifiSmeSmeStaConfigSetReqSend(0, CSR_WIFI_INTERFACE_IN_USE, *staConfig);
623     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
624     if (r)
625         return r;
626
627     unifi_trace(priv, UDBG4,
628                 "sme_mgt_sme_config_set: CsrWifiSmeSmeStaConfigSetReq <-- (r=%d status=%d)\n",
629                 r, priv->sme_reply.reply_status);
630
631     r = sme_init_request(priv);
632     if (r)
633         return -EIO;
634
635     CsrWifiSmeSmeCommonConfigSetReqSend(0, *deviceConfig);
636     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
637     if (r)
638         return r;
639
640     unifi_trace(priv, UDBG4,
641                 "sme_mgt_sme_config_set: CsrWifiSmeSmeCommonConfigSetReq <-- (r=%d status=%d)\n",
642                 r, priv->sme_reply.reply_status);
643
644     return convert_sme_error(priv->sme_reply.reply_status);
645 #else
646     CsrResult status;
647     if (priv->smepriv == NULL) {
648         unifi_error(priv, "sme_mgt_sme_config_set: invalid smepriv\n");
649         return -EIO;
650     }
651     CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
652     status = CsrWifiSmeMgtSmeConfigSetReq(priv->smepriv, *staConfig);
653     status = CsrWifiSmeMgtDeviceConfigSetReq(priv->smepriv, *deviceConfig);
654     CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
655     return convert_sme_error(status);
656 #endif
657 }
658
659 #ifdef CSR_SUPPORT_WEXT
660
661 int sme_mgt_mib_config_set(unifi_priv_t *priv, CsrWifiSmeMibConfig *mibConfig)
662 {
663 #ifdef CSR_SME_USERSPACE
664     int r;
665
666     if (priv->smepriv == NULL) {
667         unifi_error(priv, "sme_mgt_mib_config_set: invalid smepriv\n");
668         return -EIO;
669     }
670
671     r = sme_init_request(priv);
672     if (r)
673         return -EIO;
674
675     CsrWifiSmeMibConfigSetReqSend(0, *mibConfig);
676
677     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
678     if (r)
679         return r;
680
681     unifi_trace(priv, UDBG4,
682                 "sme_mgt_mib_config_set: unifi_mgt_set_mib_config_req <-- (r=%d status=%d)\n",
683                 r, priv->sme_reply.reply_status);
684     return convert_sme_error(priv->sme_reply.reply_status);
685 #else
686     CsrResult status;
687     if (priv->smepriv == NULL) {
688         unifi_error(priv, "sme_mgt_mib_config_set: invalid smepriv\n");
689         return -EIO;
690     }
691     CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
692     status = CsrWifiSmeMgtMibConfigSetReq(priv->smepriv, *mibConfig);
693     CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
694     return convert_sme_error(status);
695 #endif
696 }
697
698 int sme_mgt_coex_config_set(unifi_priv_t *priv, CsrWifiSmeCoexConfig *coexConfig)
699 {
700 #ifdef CSR_SME_USERSPACE
701     int r;
702
703     if (priv->smepriv == NULL) {
704         unifi_error(priv, "sme_mgt_coex_config_set: invalid smepriv\n");
705         return -EIO;
706     }
707
708     r = sme_init_request(priv);
709     if (r)
710         return -EIO;
711
712     CsrWifiSmeCoexConfigSetReqSend(0, *coexConfig);
713
714     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
715     if (r)
716         return r;
717
718     unifi_trace(priv, UDBG4,
719                 "sme_mgt_coex_config_set: unifi_mgt_set_mib_config_req <-- (r=%d status=%d)\n",
720                 r, priv->sme_reply.reply_status);
721     return convert_sme_error(priv->sme_reply.reply_status);
722 #else
723     CsrResult status;
724     if (priv->smepriv == NULL) {
725         unifi_error(priv, "sme_mgt_coex_config_set: invalid smepriv\n");
726         return -EIO;
727     }
728     CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
729     status = CsrWifiSmeMgtCoexConfigSetReq(priv->smepriv, *coexConfig);
730     CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
731     return convert_sme_error(status);
732 #endif
733 }
734
735 #endif /* CSR_SUPPORT_WEXT */
736
737 int sme_mgt_host_config_set(unifi_priv_t *priv, CsrWifiSmeHostConfig *hostConfig)
738 {
739 #ifdef CSR_SME_USERSPACE
740     int r;
741
742     if (priv->smepriv == NULL) {
743         unifi_error(priv, "sme_mgt_host_config_set: invalid smepriv\n");
744         return -EIO;
745     }
746
747     r = sme_init_request(priv);
748     if (r)
749         return -EIO;
750
751     CsrWifiSmeHostConfigSetReqSend(0, CSR_WIFI_INTERFACE_IN_USE, *hostConfig);
752
753     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
754     if (r)
755         return r;
756
757     unifi_trace(priv, UDBG4,
758                 "sme_mgt_host_config_set: unifi_mgt_set_host_config_req <-- (r=%d status=%d)\n",
759                 r, priv->sme_reply.reply_status);
760     return convert_sme_error(priv->sme_reply.reply_status);
761 #else
762     CsrResult status;
763     if (priv->smepriv == NULL) {
764         unifi_error(priv, "sme_mgt_host_config_set: invalid smepriv\n");
765         return -EIO;
766     }
767     CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
768     status = CsrWifiSmeMgtHostConfigSetReq(priv->smepriv, *hostConfig);
769     CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
770     return convert_sme_error(status);
771 #endif
772 }
773
774 #ifdef CSR_SUPPORT_WEXT
775
776 int sme_mgt_versions_get(unifi_priv_t *priv, CsrWifiSmeVersions *versions)
777 {
778 #ifdef CSR_SME_USERSPACE
779     int r;
780
781     if (priv->smepriv == NULL) {
782         unifi_error(priv, "sme_mgt_versions_get: invalid smepriv\n");
783         return -EIO;
784     }
785
786     unifi_trace(priv, UDBG4, "sme_mgt_versions_get: unifi_mgt_versions_get_req -->\n");
787     r = sme_init_request(priv);
788     if (r)
789         return -EIO;
790
791     CsrWifiSmeVersionsGetReqSend(0);
792
793     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
794     if (r)
795         return r;
796
797     /* store the reply */
798     if (versions != NULL) {
799         memcpy((unsigned char*)versions,
800                (unsigned char*)&priv->sme_reply.versions,
801                sizeof(CsrWifiSmeVersions));
802     }
803
804     unifi_trace(priv, UDBG4,
805                 "sme_mgt_versions_get: unifi_mgt_versions_get_req <-- (r=%d status=%d)\n",
806                 r, priv->sme_reply.reply_status);
807
808     return convert_sme_error(priv->sme_reply.reply_status);
809 #else
810     CsrResult status;
811     CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
812     status = CsrWifiSmeMgtVersionsGetReq(priv->smepriv, versions);
813     CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
814     return convert_sme_error(status);
815 #endif
816 }
817
818 #endif /* CSR_SUPPORT_WEXT */
819
820 int sme_mgt_power_config_get(unifi_priv_t *priv, CsrWifiSmePowerConfig *powerConfig)
821 {
822 #ifdef CSR_SME_USERSPACE
823     int r;
824
825     if (priv->smepriv == NULL) {
826         unifi_error(priv, "sme_mgt_power_config_get: invalid smepriv\n");
827         return -EIO;
828     }
829
830     unifi_trace(priv, UDBG4, "sme_mgt_power_config_get: unifi_mgt_power_config_req -->\n");
831     r = sme_init_request(priv);
832     if (r)
833         return -EIO;
834
835     CsrWifiSmePowerConfigGetReqSend(0);
836
837     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
838     if (r)
839         return r;
840
841     /* store the reply */
842     if (powerConfig != NULL) {
843         memcpy((unsigned char*)powerConfig,
844                (unsigned char*)&priv->sme_reply.powerConfig,
845                sizeof(CsrWifiSmePowerConfig));
846     }
847
848     unifi_trace(priv, UDBG4,
849                 "sme_mgt_get_versions: unifi_mgt_power_config_req <-- (r=%d status=%d)\n",
850                 r, priv->sme_reply.reply_status);
851
852     return convert_sme_error(priv->sme_reply.reply_status);
853 #else
854     CsrResult status;
855     CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
856     status = CsrWifiSmeMgtPowerConfigGetReq(priv->smepriv, powerConfig);
857     CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
858     return convert_sme_error(status);
859 #endif
860 }
861
862 int sme_mgt_host_config_get(unifi_priv_t *priv, CsrWifiSmeHostConfig *hostConfig)
863 {
864 #ifdef CSR_SME_USERSPACE
865     int r;
866
867     if (priv->smepriv == NULL) {
868         unifi_error(priv, "sme_mgt_host_config_get: invalid smepriv\n");
869         return -EIO;
870     }
871
872     unifi_trace(priv, UDBG4, "sme_mgt_host_config_get: unifi_mgt_host_config_get_req -->\n");
873     r = sme_init_request(priv);
874     if (r)
875         return -EIO;
876
877     CsrWifiSmeHostConfigGetReqSend(0, CSR_WIFI_INTERFACE_IN_USE);
878
879     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
880     if (r)
881         return r;
882
883     /* store the reply */
884     if (hostConfig != NULL)
885         memcpy((unsigned char*)hostConfig,
886                (unsigned char*)&priv->sme_reply.hostConfig,
887                sizeof(CsrWifiSmeHostConfig));
888
889     unifi_trace(priv, UDBG4,
890                 "sme_mgt_host_config_get: unifi_mgt_host_config_get_req <-- (r=%d status=%d)\n",
891                 r, priv->sme_reply.reply_status);
892
893     return convert_sme_error(priv->sme_reply.reply_status);
894 #else
895     CsrResult status;
896     CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
897     status = CsrWifiSmeMgtHostConfigGetReq(priv->smepriv, hostConfig);
898     CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
899     return convert_sme_error(status);
900 #endif
901 }
902
903 int sme_mgt_sme_config_get(unifi_priv_t *priv, CsrWifiSmeStaConfig *staConfig, CsrWifiSmeDeviceConfig *deviceConfig)
904 {
905 #ifdef CSR_SME_USERSPACE
906     int r;
907
908     if (priv->smepriv == NULL) {
909         unifi_error(priv, "sme_mgt_sme_config_get: invalid smepriv\n");
910         return -EIO;
911     }
912
913     unifi_trace(priv, UDBG4, "sme_mgt_sme_config_get: unifi_mgt_sme_config_get_req -->\n");
914
915     /* Common device config */
916     r = sme_init_request(priv);
917     if (r)
918         return -EIO;
919
920     CsrWifiSmeSmeCommonConfigGetReqSend(0);
921     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
922     if (r)
923         return r;
924
925     /* store the reply */
926     if (deviceConfig != NULL)
927         memcpy((unsigned char*)deviceConfig,
928                (unsigned char*)&priv->sme_reply.deviceConfig,
929                sizeof(CsrWifiSmeDeviceConfig));
930
931     /* STA config */
932     r = sme_init_request(priv);
933     if (r)
934         return -EIO;
935
936     CsrWifiSmeSmeStaConfigGetReqSend(0, CSR_WIFI_INTERFACE_IN_USE);
937     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
938     if (r)
939         return r;
940
941     /* store the reply */
942     if (staConfig != NULL)
943         memcpy((unsigned char*)staConfig,
944                (unsigned char*)&priv->sme_reply.staConfig,
945                sizeof(CsrWifiSmeStaConfig));
946
947     unifi_trace(priv, UDBG4,
948                 "sme_mgt_sme_config_get: unifi_mgt_sme_config_get_req <-- (r=%d status=%d)\n",
949                 r, priv->sme_reply.reply_status);
950
951     return convert_sme_error(priv->sme_reply.reply_status);
952 #else
953     CsrResult status;
954     CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
955     status = CsrWifiSmeMgtSmeConfigGetReq(priv->smepriv, staConfig);
956     status = CsrWifiSmeMgtDeviceConfigGetReq(priv->smepriv, deviceConfig);
957     CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
958     return convert_sme_error(status);
959 #endif
960 }
961
962 int sme_mgt_coex_info_get(unifi_priv_t *priv, CsrWifiSmeCoexInfo *coexInfo)
963 {
964 #ifdef CSR_SME_USERSPACE
965     int r;
966
967     if (priv->smepriv == NULL) {
968         unifi_error(priv, "sme_mgt_coex_info_get: invalid smepriv\n");
969         return -EIO;
970     }
971
972     unifi_trace(priv, UDBG4, "sme_mgt_coex_info_get: unifi_mgt_coex_info_get_req -->\n");
973     r = sme_init_request(priv);
974     if (r)
975         return -EIO;
976
977     CsrWifiSmeCoexInfoGetReqSend(0);
978
979     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
980     if (r)
981         return r;
982
983     /* store the reply */
984     if (coexInfo != NULL)
985         memcpy((unsigned char*)coexInfo,
986                (unsigned char*)&priv->sme_reply.coexInfo,
987                sizeof(CsrWifiSmeCoexInfo));
988
989     unifi_trace(priv, UDBG4,
990                 "sme_mgt_coex_info_get: unifi_mgt_coex_info_get_req <-- (r=%d status=%d)\n",
991                 r, priv->sme_reply.reply_status);
992
993     return convert_sme_error(priv->sme_reply.reply_status);
994 #else
995     CsrResult status;
996     CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
997     status = CsrWifiSmeMgtCoexInfoGetReq(priv->smepriv, coexInfo);
998     CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
999     return convert_sme_error(status);
1000 #endif
1001 }
1002
1003 #ifdef CSR_SUPPORT_WEXT
1004
1005 int sme_mgt_coex_config_get(unifi_priv_t *priv, CsrWifiSmeCoexConfig *coexConfig)
1006 {
1007 #ifdef CSR_SME_USERSPACE
1008     int r;
1009
1010     if (priv->smepriv == NULL) {
1011         unifi_error(priv, "sme_mgt_coex_config_get: invalid smepriv\n");
1012         return -EIO;
1013     }
1014
1015     unifi_trace(priv, UDBG4, "sme_mgt_coex_config_get: unifi_mgt_coex_config_get_req -->\n");
1016     r = sme_init_request(priv);
1017     if (r)
1018         return -EIO;
1019
1020     CsrWifiSmeCoexConfigGetReqSend(0);
1021
1022     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
1023     if (r)
1024         return r;
1025
1026     /* store the reply */
1027     if (coexConfig != NULL)
1028         memcpy((unsigned char*)coexConfig,
1029                (unsigned char*)&priv->sme_reply.coexConfig,
1030                sizeof(CsrWifiSmeCoexConfig));
1031
1032     unifi_trace(priv, UDBG4,
1033                 "sme_mgt_coex_config_get: unifi_mgt_coex_config_get_req <-- (r=%d status=%d)\n",
1034                 r, priv->sme_reply.reply_status);
1035
1036     return convert_sme_error(priv->sme_reply.reply_status);
1037 #else
1038     CsrResult status;
1039     CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
1040     status = CsrWifiSmeMgtCoexConfigGetReq(priv->smepriv, coexConfig);
1041     CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
1042     return convert_sme_error(status);
1043 #endif
1044 }
1045
1046 int sme_mgt_mib_config_get(unifi_priv_t *priv, CsrWifiSmeMibConfig *mibConfig)
1047 {
1048 #ifdef CSR_SME_USERSPACE
1049     int r;
1050
1051     if (priv->smepriv == NULL) {
1052         unifi_error(priv, "sme_mgt_mib_config_get: invalid smepriv\n");
1053         return -EIO;
1054     }
1055
1056     unifi_trace(priv, UDBG4, "sme_mgt_mib_config_get: unifi_mgt_mib_config_get_req -->\n");
1057     r = sme_init_request(priv);
1058     if (r)
1059         return -EIO;
1060
1061     CsrWifiSmeMibConfigGetReqSend(0);
1062
1063     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
1064     if (r)
1065         return r;
1066
1067     /* store the reply */
1068     if (mibConfig != NULL)
1069         memcpy((unsigned char*)mibConfig,
1070                (unsigned char*)&priv->sme_reply.mibConfig,
1071                sizeof(CsrWifiSmeMibConfig));
1072
1073     unifi_trace(priv, UDBG4,
1074                 "sme_mgt_mib_config_get: unifi_mgt_mib_config_get_req <-- (r=%d status=%d)\n",
1075                 r, priv->sme_reply.reply_status);
1076
1077     return convert_sme_error(priv->sme_reply.reply_status);
1078 #else
1079     CsrResult status;
1080     CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
1081     status = CsrWifiSmeMgtMibConfigGetReq(priv->smepriv, mibConfig);
1082     CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
1083     return convert_sme_error(status);
1084 #endif
1085 }
1086
1087 int sme_mgt_connection_info_get(unifi_priv_t *priv, CsrWifiSmeConnectionInfo *connectionInfo)
1088 {
1089 #ifdef CSR_SME_USERSPACE
1090     int r;
1091
1092     if (priv->smepriv == NULL) {
1093         unifi_error(priv, "sme_mgt_connection_info_get: invalid smepriv\n");
1094         return -EIO;
1095     }
1096
1097     unifi_trace(priv, UDBG4, "sme_mgt_connection_info_get: unifi_mgt_connection_info_get_req -->\n");
1098     r = sme_init_request(priv);
1099     if (r)
1100         return -EIO;
1101
1102     CsrWifiSmeConnectionInfoGetReqSend(0, CSR_WIFI_INTERFACE_IN_USE);
1103
1104     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
1105     if (r)
1106         return r;
1107
1108     /* store the reply */
1109     if (connectionInfo != NULL)
1110         memcpy((unsigned char*)connectionInfo,
1111                (unsigned char*)&priv->sme_reply.connectionInfo,
1112                sizeof(CsrWifiSmeConnectionInfo));
1113
1114     unifi_trace(priv, UDBG4,
1115                 "sme_mgt_connection_info_get: unifi_mgt_connection_info_get_req <-- (r=%d status=%d)\n",
1116                 r, priv->sme_reply.reply_status);
1117
1118     return convert_sme_error(priv->sme_reply.reply_status);
1119 #else
1120     CsrResult status;
1121     CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
1122     status = CsrWifiSmeMgtConnectionInfoGetReq(priv->smepriv, connectionInfo);
1123     CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
1124     return convert_sme_error(status);
1125 #endif
1126 }
1127
1128 int sme_mgt_connection_config_get(unifi_priv_t *priv, CsrWifiSmeConnectionConfig *connectionConfig)
1129 {
1130 #ifdef CSR_SME_USERSPACE
1131     int r;
1132
1133     if (priv->smepriv == NULL) {
1134         unifi_error(priv, "sme_mgt_connection_config_get: invalid smepriv\n");
1135         return -EIO;
1136     }
1137
1138     unifi_trace(priv, UDBG4, "sme_mgt_connection_config_get: unifi_mgt_connection_config_get_req -->\n");
1139     r = sme_init_request(priv);
1140     if (r)
1141         return -EIO;
1142
1143     CsrWifiSmeConnectionConfigGetReqSend(0, CSR_WIFI_INTERFACE_IN_USE);
1144
1145     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
1146     if (r)
1147         return r;
1148
1149     /* store the reply */
1150     if (connectionConfig != NULL)
1151         memcpy((unsigned char*)connectionConfig,
1152                (unsigned char*)&priv->sme_reply.connectionConfig,
1153                sizeof(CsrWifiSmeConnectionConfig));
1154
1155     unifi_trace(priv, UDBG4,
1156                 "sme_mgt_connection_config_get: unifi_mgt_connection_config_get_req <-- (r=%d status=%d)\n",
1157                 r, priv->sme_reply.reply_status);
1158
1159     return convert_sme_error(priv->sme_reply.reply_status);
1160 #else
1161     CsrResult status;
1162     CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
1163     status = CsrWifiSmeMgtConnectionConfigGetReq(priv->smepriv, connectionConfig);
1164     CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
1165     return convert_sme_error(status);
1166 #endif
1167 }
1168
1169 int sme_mgt_connection_stats_get(unifi_priv_t *priv, CsrWifiSmeConnectionStats *connectionStats)
1170 {
1171 #ifdef CSR_SME_USERSPACE
1172     int r;
1173
1174     if (priv->smepriv == NULL) {
1175         unifi_error(priv, "sme_mgt_connection_stats_get: invalid smepriv\n");
1176         return -EIO;
1177     }
1178
1179     unifi_trace(priv, UDBG4, "sme_mgt_connection_stats_get: unifi_mgt_connection_stats_get_req -->\n");
1180     r = sme_init_request(priv);
1181     if (r)
1182         return -EIO;
1183
1184     CsrWifiSmeConnectionStatsGetReqSend(0, CSR_WIFI_INTERFACE_IN_USE);
1185
1186     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
1187     if (r)
1188         return r;
1189
1190     /* store the reply */
1191     if (connectionStats != NULL)
1192         memcpy((unsigned char*)connectionStats,
1193                (unsigned char*)&priv->sme_reply.connectionStats,
1194                sizeof(CsrWifiSmeConnectionStats));
1195
1196     unifi_trace(priv, UDBG4,
1197                 "sme_mgt_connection_stats_get: unifi_mgt_connection_stats_get_req <-- (r=%d status=%d)\n",
1198                 r, priv->sme_reply.reply_status);
1199
1200     return convert_sme_error(priv->sme_reply.reply_status);
1201 #else
1202     CsrResult status;
1203     CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
1204     status = CsrWifiSmeMgtConnectionStatsGetReq(priv->smepriv, connectionStats);
1205     CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
1206     return convert_sme_error(status);
1207 #endif
1208 }
1209
1210 #endif /* CSR_SUPPORT_WEXT */
1211
1212 int sme_mgt_packet_filter_set(unifi_priv_t *priv)
1213 {
1214         CsrWifiIp4Address ipAddress = {{0xFF, 0xFF, 0xFF, 0xFF }};
1215         if (priv->smepriv == NULL) {
1216                 unifi_error(priv, "sme_mgt_packet_filter_set: invalid smepriv\n");
1217                 return -EIO;
1218         }
1219         if (priv->packet_filters.arp_filter) {
1220                 ipAddress.a[0] = (priv->sta_ip_address      ) & 0xFF;
1221                 ipAddress.a[1] = (priv->sta_ip_address >>  8) & 0xFF;
1222                 ipAddress.a[2] = (priv->sta_ip_address >> 16) & 0xFF;
1223                 ipAddress.a[3] = (priv->sta_ip_address >> 24) & 0xFF;
1224         }
1225
1226         unifi_trace(priv, UDBG5,
1227                 "sme_mgt_packet_filter_set: IP address %d.%d.%d.%d\n",
1228                 ipAddress.a[0], ipAddress.a[1],
1229                 ipAddress.a[2], ipAddress.a[3]);
1230
1231         /* Doesn't block for a confirm */
1232         CsrWifiSmePacketFilterSetReqSend(0, CSR_WIFI_INTERFACE_IN_USE,
1233                                      priv->packet_filters.tclas_ies_length,
1234                                      priv->filter_tclas_ies,
1235                                      priv->packet_filters.filter_mode,
1236                                      ipAddress);
1237         return 0;
1238 }
1239
1240 int sme_mgt_tspec(unifi_priv_t *priv, CsrWifiSmeListAction action,
1241         u32 tid, CsrWifiSmeDataBlock *tspec, CsrWifiSmeDataBlock *tclas)
1242 {
1243         int r;
1244
1245         if (priv->smepriv == NULL) {
1246                 unifi_error(priv, "sme_mgt_tspec: invalid smepriv\n");
1247                 return -EIO;
1248         }
1249
1250         r = sme_init_request(priv);
1251         if (r)
1252                 return -EIO;
1253
1254         CsrWifiSmeTspecReqSend(0, CSR_WIFI_INTERFACE_IN_USE,
1255                               action, tid, TRUE, 0,
1256                               tspec->length, tspec->data,
1257                               tclas->length, tclas->data);
1258         r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
1259         if (r)
1260                 return r;
1261
1262         unifi_trace(priv, UDBG4, "sme_mgt_tspec: <-- (status=%d)\n", priv->sme_reply.reply_status);
1263         return convert_sme_error(priv->sme_reply.reply_status);
1264 }
1265
1266
1267
1268 int sme_sys_suspend(unifi_priv_t *priv)
1269 {
1270     int r;
1271     CsrResult csrResult;
1272
1273     if (priv->smepriv == NULL) {
1274         unifi_error(priv, "sme_sys_suspend: invalid smepriv\n");
1275         return -EIO;
1276     }
1277
1278     r = sme_init_request(priv);
1279     if (r)
1280         return -EIO;
1281
1282     /* Suspend the SME, which MAY cause it to power down UniFi */
1283     CsrWifiRouterCtrlSuspendIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0, 0, priv->wol_suspend);
1284     r = sme_wait_for_reply(priv, UNIFI_SME_SYS_LONG_TIMEOUT);
1285     if (r) {
1286         /* No reply - forcibly power down in case the request wasn't processed */
1287         unifi_notice(priv,
1288                      "suspend: SME did not reply %s, ",
1289                      (priv->ptest_mode | priv->wol_suspend) ? "leave powered" : "power off UniFi anyway\n");
1290
1291         /* Leave power on for production test, though */
1292         if (!priv->ptest_mode) {
1293             /* Put UniFi to deep sleep, in case we can not power it off */
1294             CsrSdioClaim(priv->sdio);
1295             unifi_trace(priv, UDBG1, "Force deep sleep");
1296             csrResult = unifi_force_low_power_mode(priv->card);
1297
1298             /* For WOL, the UniFi must stay powered */
1299             if (!priv->wol_suspend) {
1300                 unifi_trace(priv, UDBG1, "Power off\n");
1301                 CsrSdioPowerOff(priv->sdio);
1302             }
1303             CsrSdioRelease(priv->sdio);
1304         }
1305     }
1306
1307     if (priv->wol_suspend) {
1308         unifi_trace(priv, UDBG1, "UniFi left powered for WOL\n");
1309
1310         /* Remove the IRQ, which also disables the card SDIO interrupt.
1311          * Disabling the card SDIO interrupt enables the PIO WOL source.
1312          * Removal of the of the handler ensures that in both SDIO and PIO cases
1313          * the card interrupt only wakes the host. The card will be polled
1314          * after resume to handle any pending data.
1315          */
1316         if (csr_sdio_linux_remove_irq(priv->sdio)) {
1317             unifi_notice(priv, "WOL csr_sdio_linux_remove_irq failed\n");
1318         }
1319
1320         if (enable_wol == UNIFI_WOL_SDIO) {
1321             /* Because csr_sdio_linux_remove_irq() disabled the card SDIO interrupt,
1322              * it must be left enabled to wake-on-SDIO.
1323              */
1324             unifi_trace(priv, UDBG1, "Enable card SDIO interrupt for SDIO WOL\n");
1325
1326             CsrSdioClaim(priv->sdio);
1327             csrResult = CsrSdioInterruptEnable(priv->sdio);
1328             CsrSdioRelease(priv->sdio);
1329
1330             if (csrResult != CSR_RESULT_SUCCESS) {
1331                 unifi_error(priv, "WOL CsrSdioInterruptEnable failed %d\n", csrResult);
1332             }
1333         } else {
1334             unifi_trace(priv, UDBG1, "Disabled card SDIO interrupt for PIO WOL\n");
1335         }
1336
1337         /* Prevent the BH thread from running during the suspend.
1338          * Upon resume, sme_sys_resume() will trigger a wifi-on, this will cause
1339          * the BH thread to be re-enabled and reinstall the ISR.
1340          */
1341         priv->bh_thread.block_thread = 1;
1342
1343         unifi_trace(priv, UDBG1, "unifi_suspend: suspended BH");
1344     }
1345
1346     /* Consider UniFi to be uninitialised */
1347     priv->init_progress = UNIFI_INIT_NONE;
1348
1349     unifi_trace(priv, UDBG1, "sme_sys_suspend: <-- (r=%d status=%d)\n", r, priv->sme_reply.reply_status);
1350     return convert_sme_error(priv->sme_reply.reply_status);
1351 }
1352
1353
1354 int sme_sys_resume(unifi_priv_t *priv)
1355 {
1356     int r;
1357
1358     unifi_trace(priv, UDBG1, "sme_sys_resume %s\n", priv->wol_suspend ? "warm" : "");
1359
1360     if (priv->smepriv == NULL) {
1361         unifi_error(priv, "sme_sys_resume: invalid smepriv\n");
1362         return -EIO;
1363     }
1364
1365     r = sme_init_request(priv);
1366     if (r)
1367         return -EIO;
1368
1369     CsrWifiRouterCtrlResumeIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0, priv->wol_suspend);
1370
1371     r = sme_wait_for_reply(priv, UNIFI_SME_SYS_LONG_TIMEOUT);
1372     if (r)
1373         unifi_notice(priv,
1374                 "resume: SME did not reply, return success anyway\n");
1375
1376     return 0;
1377 }
1378
1379 #ifdef CSR_SUPPORT_WEXT_AP
1380 int sme_ap_stop(unifi_priv_t *priv,u16 interface_tag)
1381 {
1382     int r;
1383
1384     if (priv->smepriv == NULL) {
1385         unifi_error(priv, "sme_ap_stop: invalid smepriv\n");
1386         return -EIO;
1387     }
1388
1389     r = sme_init_request(priv);
1390     if (r)
1391         return -EIO;
1392
1393     CsrWifiNmeApStopReqSend(0,interface_tag);
1394
1395     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
1396     if (r)
1397         return r;
1398
1399     unifi_trace(priv, UDBG4,
1400                 "sme_ap_stop <-- (r=%d status=%d)\n",
1401                 r, priv->sme_reply.reply_status);
1402     return convert_sme_error(priv->sme_reply.reply_status);
1403
1404 }
1405
1406 int sme_ap_start(unifi_priv_t *priv,u16 interface_tag,
1407                  CsrWifiSmeApConfig_t * ap_config)
1408 {
1409     int r;
1410     CsrWifiSmeApP2pGoConfig p2p_go_param;
1411     memset(&p2p_go_param,0,sizeof(CsrWifiSmeApP2pGoConfig));
1412
1413     if (priv->smepriv == NULL) {
1414         unifi_error(priv, "sme_ap_start: invalid smepriv\n");
1415         return -EIO;
1416     }
1417
1418     r = sme_init_request(priv);
1419     if (r)
1420         return -EIO;
1421
1422     CsrWifiNmeApStartReqSend(0,interface_tag,CSR_WIFI_AP_TYPE_LEGACY,FALSE,
1423                              ap_config->ssid,1,ap_config->channel,
1424                              ap_config->credentials,ap_config->max_connections,
1425                              p2p_go_param,FALSE);
1426
1427     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
1428     if (r)
1429         return r;
1430
1431     unifi_trace(priv, UDBG4,
1432                 "sme_ap_start <-- (r=%d status=%d)\n",
1433                 r, priv->sme_reply.reply_status);
1434     return convert_sme_error(priv->sme_reply.reply_status);
1435 }
1436
1437 int sme_ap_config(unifi_priv_t *priv,
1438                   CsrWifiSmeApMacConfig *ap_mac_config,
1439                   CsrWifiNmeApConfig *group_security_config)
1440 {
1441     int r;
1442     CsrWifiSmeApP2pGoConfig p2p_go_param;
1443     memset(&p2p_go_param,0,sizeof(CsrWifiSmeApP2pGoConfig));
1444
1445     if (priv->smepriv == NULL) {
1446         unifi_error(priv, "sme_ap_config: invalid smepriv\n");
1447         return -EIO;
1448     }
1449
1450     r = sme_init_request(priv);
1451     if (r)
1452         return -EIO;
1453
1454     CsrWifiNmeApConfigSetReqSend(0,*group_security_config,
1455                                  *ap_mac_config);
1456
1457     r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
1458         if (r)
1459                 return r;
1460
1461     unifi_trace(priv, UDBG4,
1462                 "sme_ap_config <-- (r=%d status=%d)\n",
1463                 r, priv->sme_reply.reply_status);
1464     return convert_sme_error(priv->sme_reply.reply_status);
1465 }
1466 #endif