2 * ---------------------------------------------------------------------------
3 * FILE: sme_mgt_blocking.c
6 * This file contains the driver specific implementation of
7 * the WEXT <==> SME MGT interface for all SME builds that support WEXT.
9 * Copyright (C) 2009 by Cambridge Silicon Radio Ltd.
11 * Refer to LICENSE.txt included with this source code for details on
14 * ---------------------------------------------------------------------------
17 #include "unifi_priv.h"
21 * This file also contains the implementation of the asynchronous
22 * requests to the SME.
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
29 * Now we are ready to call the SME function, but only if
30 * sme_init_request() has returned 0.
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.
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().
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:
50 * sme_mgt_scan_results_get_async()
52 * unifi_mgt_media_status_ind()
53 * sme_mgt_disconnect()
58 * sme_mgt_versions_get()
61 * sme_mgt_set_value_async()
62 * sme_mgt_get_value_async()
63 * sme_mgt_packet_filter_set()
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:
77 #define UNIFI_SME_MGT_SHORT_TIMEOUT 10000
78 #define UNIFI_SME_MGT_LONG_TIMEOUT 19000
79 #define UNIFI_SME_SYS_LONG_TIMEOUT 10000
82 # define sme_wait_for_reply(priv, t) _sme_wait_for_reply(priv, t, __func__)
84 # define sme_wait_for_reply(priv, t) _sme_wait_for_reply(priv, t, NULL)
88 sme_init_request(unifi_priv_t *priv)
91 unifi_error(priv, "sme_init_request: Invalid priv\n");
95 unifi_trace(priv, UDBG5, "sme_init_request: wait sem\n");
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");
102 unifi_trace(priv, UDBG5, "sme_init_request: got sem: pending\n");
104 priv->sme_reply.request_status = SME_REQUEST_PENDING;
108 } /* sme_init_request() */
112 uf_sme_complete_request(unifi_priv_t *priv, CsrResult reply_status, const char *func)
115 unifi_error(priv, "sme_complete_request: Invalid priv\n");
119 if (priv->sme_reply.request_status != SME_REQUEST_PENDING) {
121 "sme_complete_request: request not pending %s (s:%d)\n",
122 (func ? func : ""), priv->sme_reply.request_status);
125 unifi_trace(priv, UDBG5,
126 "sme_complete_request: completed %s (s:%d)\n",
127 (func ? func : ""), priv->sme_reply.request_status);
129 priv->sme_reply.request_status = SME_REQUEST_RECEIVED;
130 priv->sme_reply.reply_status = reply_status;
132 wake_up_interruptible(&priv->sme_request_wq);
139 uf_sme_cancel_request(unifi_priv_t *priv, CsrResult reply_status)
141 /* Check for a blocking SME request in progress, and cancel the wait.
142 * This should be used when the character device is closed.
146 unifi_error(priv, "sme_cancel_request: Invalid priv\n");
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);
158 unifi_trace(priv, UDBG5,
159 "sme_cancel_request: request cancelled (s:%d)\n",
160 priv->sme_reply.request_status);
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 */
166 wake_up_interruptible(&priv->sme_request_wq);
173 _sme_wait_for_reply(unifi_priv_t *priv,
174 unsigned long timeout, const char *func)
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);
184 if (r == -ERESTARTSYS) {
185 /* The thread was killed */
186 unifi_info(priv, "ERESTARTSYS in _sme_wait_for_reply\n");
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);
194 /* Release the SME semaphore that was downed in sme_init_request() */
196 return -EIO; /* fail the ioctl */
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);
202 priv->sme_reply.request_status = SME_REQUEST_TIMEDOUT;
204 /* Release the SME semaphore that was downed in sme_init_request() */
210 unifi_trace(priv, UDBG5, "sme_wait_for_reply: %s received (%d)\n",
211 func ? func : "", r);
213 /* Release the SME semaphore that was downed in sme_init_request() */
217 } /* sme_wait_for_reply() */
222 #ifdef CSR_SUPPORT_WEXT
223 int sme_mgt_wifi_on(unifi_priv_t *priv)
226 CsrWifiSmeDataBlock* dataList;
227 #ifdef CSR_SUPPORT_WEXT_AP
231 if (priv->smepriv == NULL) {
232 unifi_error(priv, "sme_mgt_wifi_on: invalid smepriv\n");
236 if (priv->mib_data.length) {
238 dataList = &priv->mib_data;
244 #ifdef CSR_SUPPORT_WEXT_AP
245 r = sme_init_request(priv);
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);
260 } /* sme_mgt_wifi_on() */
263 int sme_mgt_wifi_off(unifi_priv_t *priv)
267 if (priv->smepriv == NULL) {
268 unifi_error(priv, "sme_mgt_wifi_off: invalid smepriv\n");
272 r = sme_init_request(priv);
278 CsrWifiSmeWifiOffReqSend(0);
280 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_LONG_TIMEOUT);
285 unifi_trace(priv, UDBG4,
286 "sme_mgt_wifi_off: unifi_mgt_wifi_off_req <-- (r=%d, status=%d)\n",
287 r, priv->sme_reply.reply_status);
288 return convert_sme_error(priv->sme_reply.reply_status);
290 } /* sme_mgt_wifi_off */
292 int sme_mgt_key(unifi_priv_t *priv, CsrWifiSmeKey *sme_key,
293 CsrWifiSmeListAction action)
297 if (priv->smepriv == NULL) {
298 unifi_error(priv, "sme_mgt_key: invalid smepriv\n");
302 r = sme_init_request(priv);
307 CsrWifiSmeKeyReqSend(0, CSR_WIFI_INTERFACE_IN_USE, action, *sme_key);
309 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
314 return convert_sme_error(priv->sme_reply.reply_status);
318 int sme_mgt_scan_full(unifi_priv_t *priv,
319 CsrWifiSsid *specific_ssid,
321 unsigned char *channel_list)
323 CsrWifiMacAddress bcastAddress = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }};
324 u8 is_active = (num_channels > 0) ? TRUE : FALSE;
327 if (priv->smepriv == NULL) {
328 unifi_error(priv, "sme_mgt_scan_full: invalid smepriv\n");
332 unifi_trace(priv, UDBG4, "sme_mgt_scan_full: -->\n");
334 r = sme_init_request(priv);
339 /* If a channel list is provided, do an active scan */
341 unifi_trace(priv, UDBG1,
342 "channel list - num_channels: %d, active scan\n",
346 CsrWifiSmeScanFullReqSend(0,
347 specific_ssid->length?1:0, /* 0 or 1 SSIDS */
351 CSR_WIFI_SME_BSS_TYPE_ANY_BSS,
352 CSR_WIFI_SME_SCAN_TYPE_ALL,
353 (u16)num_channels, channel_list,
356 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_LONG_TIMEOUT);
361 unifi_trace(priv, UDBG4, "sme_mgt_scan_full: <-- (status=%d)\n", priv->sme_reply.reply_status);
362 if (priv->sme_reply.reply_status == CSR_WIFI_RESULT_UNAVAILABLE) {
363 return 0; /* initial scan already underway */
365 return convert_sme_error(priv->sme_reply.reply_status);
370 int sme_mgt_scan_results_get_async(unifi_priv_t *priv,
371 struct iw_request_info *info,
373 long scan_results_len)
375 u16 scan_result_list_count;
376 CsrWifiSmeScanResult *scan_result_list;
377 CsrWifiSmeScanResult *scan_result;
380 char *current_ev = scan_results;
382 if (priv->smepriv == NULL) {
383 unifi_error(priv, "sme_mgt_scan_results_get_async: invalid smepriv\n");
387 r = sme_init_request(priv);
392 CsrWifiSmeScanResultsGetReqSend(0);
393 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_LONG_TIMEOUT);
398 scan_result_list_count = priv->sme_reply.reply_scan_results_count;
399 scan_result_list = priv->sme_reply.reply_scan_results;
400 unifi_trace(priv, UDBG2,
401 "scan_results: Scan returned %d, numElements=%d\n",
402 r, scan_result_list_count);
404 /* OK, now we have the scan results */
405 for (i = 0; i < scan_result_list_count; ++i) {
406 scan_result = &scan_result_list[i];
408 unifi_trace(priv, UDBG2, "Scan Result: %.*s\n",
409 scan_result->ssid.length,
410 scan_result->ssid.ssid);
412 r = unifi_translate_scan(priv->netdev[0], info,
414 scan_results + scan_results_len,
418 kfree(scan_result_list);
419 priv->sme_reply.reply_scan_results_count = 0;
420 priv->sme_reply.reply_scan_results = NULL;
428 * Free the scan results allocated in unifi_mgt_scan_results_get_cfm()
429 * and invalidate the reply_scan_results to avoid re-using
430 * the freed pointers.
432 kfree(scan_result_list);
433 priv->sme_reply.reply_scan_results_count = 0;
434 priv->sme_reply.reply_scan_results = NULL;
436 unifi_trace(priv, UDBG2,
437 "scan_results: Scan translated to %d bytes\n",
438 current_ev - scan_results);
439 return (current_ev - scan_results);
443 int sme_mgt_connect(unifi_priv_t *priv)
447 if (priv->smepriv == NULL) {
448 unifi_error(priv, "sme_mgt_connect: invalid smepriv\n");
452 unifi_trace(priv, UDBG2, "sme_mgt_connect: %.*s\n",
453 priv->connection_config.ssid.length,
454 priv->connection_config.ssid.ssid);
456 r = sme_init_request(priv);
461 CsrWifiSmeConnectReqSend(0, CSR_WIFI_INTERFACE_IN_USE, priv->connection_config);
462 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
467 if (priv->sme_reply.reply_status) {
468 unifi_trace(priv, UDBG1, "sme_mgt_connect: failed with SME status %d\n",
469 priv->sme_reply.reply_status);
472 return convert_sme_error(priv->sme_reply.reply_status);
476 int sme_mgt_disconnect(unifi_priv_t *priv)
480 if (priv->smepriv == NULL) {
481 unifi_error(priv, "sme_mgt_disconnect: invalid smepriv\n");
485 r = sme_init_request(priv);
490 CsrWifiSmeDisconnectReqSend(0, CSR_WIFI_INTERFACE_IN_USE);
491 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
496 unifi_trace(priv, UDBG4, "sme_mgt_disconnect: <-- (status=%d)\n", priv->sme_reply.reply_status);
497 return convert_sme_error(priv->sme_reply.reply_status);
501 int sme_mgt_pmkid(unifi_priv_t *priv,
502 CsrWifiSmeListAction action,
503 CsrWifiSmePmkidList *pmkid_list)
507 if (priv->smepriv == NULL) {
508 unifi_error(priv, "sme_mgt_pmkid: invalid smepriv\n");
512 r = sme_init_request(priv);
517 CsrWifiSmePmkidReqSend(0, CSR_WIFI_INTERFACE_IN_USE, action,
518 pmkid_list->pmkidsCount, pmkid_list->pmkids);
519 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
524 unifi_trace(priv, UDBG4, "sme_mgt_pmkid: <-- (status=%d)\n", priv->sme_reply.reply_status);
525 return convert_sme_error(priv->sme_reply.reply_status);
529 int sme_mgt_mib_get(unifi_priv_t *priv,
530 unsigned char *varbind, int *length)
534 if (priv->smepriv == NULL) {
535 unifi_error(priv, "sme_mgt_mib_get: invalid smepriv\n");
539 r = sme_init_request(priv);
544 priv->mib_cfm_buffer = varbind;
545 priv->mib_cfm_buffer_length = MAX_VARBIND_LENGTH;
547 CsrWifiSmeMibGetReqSend(0, *length, varbind);
548 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
550 priv->mib_cfm_buffer_length = 0;
551 priv->mib_cfm_buffer = NULL;
555 *length = priv->mib_cfm_buffer_length;
557 priv->mib_cfm_buffer_length = 0;
558 priv->mib_cfm_buffer = NULL;
559 unifi_trace(priv, UDBG4, "sme_mgt_mib_get: <-- (status=%d)\n", priv->sme_reply.reply_status);
560 return convert_sme_error(priv->sme_reply.reply_status);
563 int sme_mgt_mib_set(unifi_priv_t *priv,
564 unsigned char *varbind, int length)
568 if (priv->smepriv == NULL) {
569 unifi_error(priv, "sme_mgt_mib_get: invalid smepriv\n");
573 r = sme_init_request(priv);
578 CsrWifiSmeMibSetReqSend(0, length, varbind);
579 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
584 unifi_trace(priv, UDBG4, "sme_mgt_mib_set: <-- (status=%d)\n", priv->sme_reply.reply_status);
585 return convert_sme_error(priv->sme_reply.reply_status);
588 #endif /* CSR_SUPPORT_WEXT */
590 int sme_mgt_power_config_set(unifi_priv_t *priv, CsrWifiSmePowerConfig *powerConfig)
592 #ifdef CSR_SME_USERSPACE
595 if (priv->smepriv == NULL) {
596 unifi_error(priv, "sme_mgt_set_value_async: invalid smepriv\n");
600 r = sme_init_request(priv);
605 CsrWifiSmePowerConfigSetReqSend(0, *powerConfig);
607 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
612 unifi_trace(priv, UDBG4,
613 "sme_mgt_set_value_async: unifi_mgt_set_value_req <-- (r=%d status=%d)\n",
614 r, priv->sme_reply.reply_status);
615 return convert_sme_error(priv->sme_reply.reply_status);
618 if (priv->smepriv == NULL) {
619 unifi_error(priv, "sme_mgt_set_value: invalid smepriv\n");
622 CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
623 status = CsrWifiSmeMgtPowerConfigSetReq(priv->smepriv, *powerConfig);
624 CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
625 return convert_sme_error(status);
629 int sme_mgt_sme_config_set(unifi_priv_t *priv, CsrWifiSmeStaConfig *staConfig, CsrWifiSmeDeviceConfig *deviceConfig)
631 #ifdef CSR_SME_USERSPACE
634 if (priv->smepriv == NULL) {
635 unifi_error(priv, "sme_mgt_sme_config_set: invalid smepriv\n");
639 r = sme_init_request(priv);
644 CsrWifiSmeSmeStaConfigSetReqSend(0, CSR_WIFI_INTERFACE_IN_USE, *staConfig);
645 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
649 unifi_trace(priv, UDBG4,
650 "sme_mgt_sme_config_set: CsrWifiSmeSmeStaConfigSetReq <-- (r=%d status=%d)\n",
651 r, priv->sme_reply.reply_status);
653 r = sme_init_request(priv);
658 CsrWifiSmeSmeCommonConfigSetReqSend(0, *deviceConfig);
659 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
664 unifi_trace(priv, UDBG4,
665 "sme_mgt_sme_config_set: CsrWifiSmeSmeCommonConfigSetReq <-- (r=%d status=%d)\n",
666 r, priv->sme_reply.reply_status);
668 return convert_sme_error(priv->sme_reply.reply_status);
671 if (priv->smepriv == NULL) {
672 unifi_error(priv, "sme_mgt_sme_config_set: invalid smepriv\n");
675 CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
676 status = CsrWifiSmeMgtSmeConfigSetReq(priv->smepriv, *staConfig);
677 status = CsrWifiSmeMgtDeviceConfigSetReq(priv->smepriv, *deviceConfig);
678 CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
679 return convert_sme_error(status);
683 #ifdef CSR_SUPPORT_WEXT
685 int sme_mgt_mib_config_set(unifi_priv_t *priv, CsrWifiSmeMibConfig *mibConfig)
687 #ifdef CSR_SME_USERSPACE
690 if (priv->smepriv == NULL) {
691 unifi_error(priv, "sme_mgt_mib_config_set: invalid smepriv\n");
695 r = sme_init_request(priv);
700 CsrWifiSmeMibConfigSetReqSend(0, *mibConfig);
702 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
707 unifi_trace(priv, UDBG4,
708 "sme_mgt_mib_config_set: unifi_mgt_set_mib_config_req <-- (r=%d status=%d)\n",
709 r, priv->sme_reply.reply_status);
710 return convert_sme_error(priv->sme_reply.reply_status);
713 if (priv->smepriv == NULL) {
714 unifi_error(priv, "sme_mgt_mib_config_set: invalid smepriv\n");
717 CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
718 status = CsrWifiSmeMgtMibConfigSetReq(priv->smepriv, *mibConfig);
719 CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
720 return convert_sme_error(status);
724 int sme_mgt_coex_config_set(unifi_priv_t *priv, CsrWifiSmeCoexConfig *coexConfig)
726 #ifdef CSR_SME_USERSPACE
729 if (priv->smepriv == NULL) {
730 unifi_error(priv, "sme_mgt_coex_config_set: invalid smepriv\n");
734 r = sme_init_request(priv);
739 CsrWifiSmeCoexConfigSetReqSend(0, *coexConfig);
741 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
746 unifi_trace(priv, UDBG4,
747 "sme_mgt_coex_config_set: unifi_mgt_set_mib_config_req <-- (r=%d status=%d)\n",
748 r, priv->sme_reply.reply_status);
749 return convert_sme_error(priv->sme_reply.reply_status);
752 if (priv->smepriv == NULL) {
753 unifi_error(priv, "sme_mgt_coex_config_set: invalid smepriv\n");
756 CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
757 status = CsrWifiSmeMgtCoexConfigSetReq(priv->smepriv, *coexConfig);
758 CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
759 return convert_sme_error(status);
763 #endif /* CSR_SUPPORT_WEXT */
765 int sme_mgt_host_config_set(unifi_priv_t *priv, CsrWifiSmeHostConfig *hostConfig)
767 #ifdef CSR_SME_USERSPACE
770 if (priv->smepriv == NULL) {
771 unifi_error(priv, "sme_mgt_host_config_set: invalid smepriv\n");
775 r = sme_init_request(priv);
780 CsrWifiSmeHostConfigSetReqSend(0, CSR_WIFI_INTERFACE_IN_USE, *hostConfig);
782 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
787 unifi_trace(priv, UDBG4,
788 "sme_mgt_host_config_set: unifi_mgt_set_host_config_req <-- (r=%d status=%d)\n",
789 r, priv->sme_reply.reply_status);
790 return convert_sme_error(priv->sme_reply.reply_status);
793 if (priv->smepriv == NULL) {
794 unifi_error(priv, "sme_mgt_host_config_set: invalid smepriv\n");
797 CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
798 status = CsrWifiSmeMgtHostConfigSetReq(priv->smepriv, *hostConfig);
799 CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
800 return convert_sme_error(status);
804 #ifdef CSR_SUPPORT_WEXT
806 int sme_mgt_versions_get(unifi_priv_t *priv, CsrWifiSmeVersions *versions)
808 #ifdef CSR_SME_USERSPACE
811 if (priv->smepriv == NULL) {
812 unifi_error(priv, "sme_mgt_versions_get: invalid smepriv\n");
816 unifi_trace(priv, UDBG4, "sme_mgt_versions_get: unifi_mgt_versions_get_req -->\n");
817 r = sme_init_request(priv);
822 CsrWifiSmeVersionsGetReqSend(0);
824 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
829 /* store the reply */
830 if (versions != NULL) {
831 memcpy((unsigned char*)versions,
832 (unsigned char*)&priv->sme_reply.versions,
833 sizeof(CsrWifiSmeVersions));
836 unifi_trace(priv, UDBG4,
837 "sme_mgt_versions_get: unifi_mgt_versions_get_req <-- (r=%d status=%d)\n",
838 r, priv->sme_reply.reply_status);
840 return convert_sme_error(priv->sme_reply.reply_status);
843 CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
844 status = CsrWifiSmeMgtVersionsGetReq(priv->smepriv, versions);
845 CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
846 return convert_sme_error(status);
850 #endif /* CSR_SUPPORT_WEXT */
852 int sme_mgt_power_config_get(unifi_priv_t *priv, CsrWifiSmePowerConfig *powerConfig)
854 #ifdef CSR_SME_USERSPACE
857 if (priv->smepriv == NULL) {
858 unifi_error(priv, "sme_mgt_power_config_get: invalid smepriv\n");
862 unifi_trace(priv, UDBG4, "sme_mgt_power_config_get: unifi_mgt_power_config_req -->\n");
863 r = sme_init_request(priv);
868 CsrWifiSmePowerConfigGetReqSend(0);
870 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
875 /* store the reply */
876 if (powerConfig != NULL) {
877 memcpy((unsigned char*)powerConfig,
878 (unsigned char*)&priv->sme_reply.powerConfig,
879 sizeof(CsrWifiSmePowerConfig));
882 unifi_trace(priv, UDBG4,
883 "sme_mgt_get_versions: unifi_mgt_power_config_req <-- (r=%d status=%d)\n",
884 r, priv->sme_reply.reply_status);
886 return convert_sme_error(priv->sme_reply.reply_status);
889 CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
890 status = CsrWifiSmeMgtPowerConfigGetReq(priv->smepriv, powerConfig);
891 CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
892 return convert_sme_error(status);
896 int sme_mgt_host_config_get(unifi_priv_t *priv, CsrWifiSmeHostConfig *hostConfig)
898 #ifdef CSR_SME_USERSPACE
901 if (priv->smepriv == NULL) {
902 unifi_error(priv, "sme_mgt_host_config_get: invalid smepriv\n");
906 unifi_trace(priv, UDBG4, "sme_mgt_host_config_get: unifi_mgt_host_config_get_req -->\n");
907 r = sme_init_request(priv);
912 CsrWifiSmeHostConfigGetReqSend(0, CSR_WIFI_INTERFACE_IN_USE);
914 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
919 /* store the reply */
920 if (hostConfig != NULL) {
921 memcpy((unsigned char*)hostConfig,
922 (unsigned char*)&priv->sme_reply.hostConfig,
923 sizeof(CsrWifiSmeHostConfig));
926 unifi_trace(priv, UDBG4,
927 "sme_mgt_host_config_get: unifi_mgt_host_config_get_req <-- (r=%d status=%d)\n",
928 r, priv->sme_reply.reply_status);
930 return convert_sme_error(priv->sme_reply.reply_status);
933 CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
934 status = CsrWifiSmeMgtHostConfigGetReq(priv->smepriv, hostConfig);
935 CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
936 return convert_sme_error(status);
940 int sme_mgt_sme_config_get(unifi_priv_t *priv, CsrWifiSmeStaConfig *staConfig, CsrWifiSmeDeviceConfig *deviceConfig)
942 #ifdef CSR_SME_USERSPACE
945 if (priv->smepriv == NULL) {
946 unifi_error(priv, "sme_mgt_sme_config_get: invalid smepriv\n");
950 unifi_trace(priv, UDBG4, "sme_mgt_sme_config_get: unifi_mgt_sme_config_get_req -->\n");
952 /* Common device config */
953 r = sme_init_request(priv);
958 CsrWifiSmeSmeCommonConfigGetReqSend(0);
959 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
964 /* store the reply */
965 if (deviceConfig != NULL) {
966 memcpy((unsigned char*)deviceConfig,
967 (unsigned char*)&priv->sme_reply.deviceConfig,
968 sizeof(CsrWifiSmeDeviceConfig));
972 r = sme_init_request(priv);
977 CsrWifiSmeSmeStaConfigGetReqSend(0, CSR_WIFI_INTERFACE_IN_USE);
978 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
983 /* store the reply */
984 if (staConfig != NULL) {
985 memcpy((unsigned char*)staConfig,
986 (unsigned char*)&priv->sme_reply.staConfig,
987 sizeof(CsrWifiSmeStaConfig));
990 unifi_trace(priv, UDBG4,
991 "sme_mgt_sme_config_get: unifi_mgt_sme_config_get_req <-- (r=%d status=%d)\n",
992 r, priv->sme_reply.reply_status);
994 return convert_sme_error(priv->sme_reply.reply_status);
997 CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
998 status = CsrWifiSmeMgtSmeConfigGetReq(priv->smepriv, staConfig);
999 status = CsrWifiSmeMgtDeviceConfigGetReq(priv->smepriv, deviceConfig);
1000 CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
1001 return convert_sme_error(status);
1005 int sme_mgt_coex_info_get(unifi_priv_t *priv, CsrWifiSmeCoexInfo *coexInfo)
1007 #ifdef CSR_SME_USERSPACE
1010 if (priv->smepriv == NULL) {
1011 unifi_error(priv, "sme_mgt_coex_info_get: invalid smepriv\n");
1015 unifi_trace(priv, UDBG4, "sme_mgt_coex_info_get: unifi_mgt_coex_info_get_req -->\n");
1016 r = sme_init_request(priv);
1021 CsrWifiSmeCoexInfoGetReqSend(0);
1023 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
1028 /* store the reply */
1029 if (coexInfo != NULL) {
1030 memcpy((unsigned char*)coexInfo,
1031 (unsigned char*)&priv->sme_reply.coexInfo,
1032 sizeof(CsrWifiSmeCoexInfo));
1035 unifi_trace(priv, UDBG4,
1036 "sme_mgt_coex_info_get: unifi_mgt_coex_info_get_req <-- (r=%d status=%d)\n",
1037 r, priv->sme_reply.reply_status);
1039 return convert_sme_error(priv->sme_reply.reply_status);
1042 CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
1043 status = CsrWifiSmeMgtCoexInfoGetReq(priv->smepriv, coexInfo);
1044 CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
1045 return convert_sme_error(status);
1049 #ifdef CSR_SUPPORT_WEXT
1051 int sme_mgt_coex_config_get(unifi_priv_t *priv, CsrWifiSmeCoexConfig *coexConfig)
1053 #ifdef CSR_SME_USERSPACE
1056 if (priv->smepriv == NULL) {
1057 unifi_error(priv, "sme_mgt_coex_config_get: invalid smepriv\n");
1061 unifi_trace(priv, UDBG4, "sme_mgt_coex_config_get: unifi_mgt_coex_config_get_req -->\n");
1062 r = sme_init_request(priv);
1067 CsrWifiSmeCoexConfigGetReqSend(0);
1069 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
1074 /* store the reply */
1075 if (coexConfig != NULL) {
1076 memcpy((unsigned char*)coexConfig,
1077 (unsigned char*)&priv->sme_reply.coexConfig,
1078 sizeof(CsrWifiSmeCoexConfig));
1081 unifi_trace(priv, UDBG4,
1082 "sme_mgt_coex_config_get: unifi_mgt_coex_config_get_req <-- (r=%d status=%d)\n",
1083 r, priv->sme_reply.reply_status);
1085 return convert_sme_error(priv->sme_reply.reply_status);
1088 CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
1089 status = CsrWifiSmeMgtCoexConfigGetReq(priv->smepriv, coexConfig);
1090 CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
1091 return convert_sme_error(status);
1095 int sme_mgt_mib_config_get(unifi_priv_t *priv, CsrWifiSmeMibConfig *mibConfig)
1097 #ifdef CSR_SME_USERSPACE
1100 if (priv->smepriv == NULL) {
1101 unifi_error(priv, "sme_mgt_mib_config_get: invalid smepriv\n");
1105 unifi_trace(priv, UDBG4, "sme_mgt_mib_config_get: unifi_mgt_mib_config_get_req -->\n");
1106 r = sme_init_request(priv);
1111 CsrWifiSmeMibConfigGetReqSend(0);
1113 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
1118 /* store the reply */
1119 if (mibConfig != NULL) {
1120 memcpy((unsigned char*)mibConfig,
1121 (unsigned char*)&priv->sme_reply.mibConfig,
1122 sizeof(CsrWifiSmeMibConfig));
1125 unifi_trace(priv, UDBG4,
1126 "sme_mgt_mib_config_get: unifi_mgt_mib_config_get_req <-- (r=%d status=%d)\n",
1127 r, priv->sme_reply.reply_status);
1129 return convert_sme_error(priv->sme_reply.reply_status);
1132 CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
1133 status = CsrWifiSmeMgtMibConfigGetReq(priv->smepriv, mibConfig);
1134 CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
1135 return convert_sme_error(status);
1139 int sme_mgt_connection_info_get(unifi_priv_t *priv, CsrWifiSmeConnectionInfo *connectionInfo)
1141 #ifdef CSR_SME_USERSPACE
1144 if (priv->smepriv == NULL) {
1145 unifi_error(priv, "sme_mgt_connection_info_get: invalid smepriv\n");
1149 unifi_trace(priv, UDBG4, "sme_mgt_connection_info_get: unifi_mgt_connection_info_get_req -->\n");
1150 r = sme_init_request(priv);
1155 CsrWifiSmeConnectionInfoGetReqSend(0, CSR_WIFI_INTERFACE_IN_USE);
1157 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
1162 /* store the reply */
1163 if (connectionInfo != NULL) {
1164 memcpy((unsigned char*)connectionInfo,
1165 (unsigned char*)&priv->sme_reply.connectionInfo,
1166 sizeof(CsrWifiSmeConnectionInfo));
1169 unifi_trace(priv, UDBG4,
1170 "sme_mgt_connection_info_get: unifi_mgt_connection_info_get_req <-- (r=%d status=%d)\n",
1171 r, priv->sme_reply.reply_status);
1173 return convert_sme_error(priv->sme_reply.reply_status);
1176 CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
1177 status = CsrWifiSmeMgtConnectionInfoGetReq(priv->smepriv, connectionInfo);
1178 CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
1179 return convert_sme_error(status);
1183 int sme_mgt_connection_config_get(unifi_priv_t *priv, CsrWifiSmeConnectionConfig *connectionConfig)
1185 #ifdef CSR_SME_USERSPACE
1188 if (priv->smepriv == NULL) {
1189 unifi_error(priv, "sme_mgt_connection_config_get: invalid smepriv\n");
1193 unifi_trace(priv, UDBG4, "sme_mgt_connection_config_get: unifi_mgt_connection_config_get_req -->\n");
1194 r = sme_init_request(priv);
1199 CsrWifiSmeConnectionConfigGetReqSend(0, CSR_WIFI_INTERFACE_IN_USE);
1201 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
1206 /* store the reply */
1207 if (connectionConfig != NULL) {
1208 memcpy((unsigned char*)connectionConfig,
1209 (unsigned char*)&priv->sme_reply.connectionConfig,
1210 sizeof(CsrWifiSmeConnectionConfig));
1213 unifi_trace(priv, UDBG4,
1214 "sme_mgt_connection_config_get: unifi_mgt_connection_config_get_req <-- (r=%d status=%d)\n",
1215 r, priv->sme_reply.reply_status);
1217 return convert_sme_error(priv->sme_reply.reply_status);
1220 CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
1221 status = CsrWifiSmeMgtConnectionConfigGetReq(priv->smepriv, connectionConfig);
1222 CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
1223 return convert_sme_error(status);
1227 int sme_mgt_connection_stats_get(unifi_priv_t *priv, CsrWifiSmeConnectionStats *connectionStats)
1229 #ifdef CSR_SME_USERSPACE
1232 if (priv->smepriv == NULL) {
1233 unifi_error(priv, "sme_mgt_connection_stats_get: invalid smepriv\n");
1237 unifi_trace(priv, UDBG4, "sme_mgt_connection_stats_get: unifi_mgt_connection_stats_get_req -->\n");
1238 r = sme_init_request(priv);
1243 CsrWifiSmeConnectionStatsGetReqSend(0, CSR_WIFI_INTERFACE_IN_USE);
1245 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
1250 /* store the reply */
1251 if (connectionStats != NULL) {
1252 memcpy((unsigned char*)connectionStats,
1253 (unsigned char*)&priv->sme_reply.connectionStats,
1254 sizeof(CsrWifiSmeConnectionStats));
1257 unifi_trace(priv, UDBG4,
1258 "sme_mgt_connection_stats_get: unifi_mgt_connection_stats_get_req <-- (r=%d status=%d)\n",
1259 r, priv->sme_reply.reply_status);
1261 return convert_sme_error(priv->sme_reply.reply_status);
1264 CsrWifiSmeMgtClaimSyncAccess(priv->smepriv);
1265 status = CsrWifiSmeMgtConnectionStatsGetReq(priv->smepriv, connectionStats);
1266 CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv);
1267 return convert_sme_error(status);
1271 #endif /* CSR_SUPPORT_WEXT */
1273 int sme_mgt_packet_filter_set(unifi_priv_t *priv)
1275 CsrWifiIp4Address ipAddress = {{0xFF, 0xFF, 0xFF, 0xFF }};
1276 if (priv->smepriv == NULL) {
1277 unifi_error(priv, "sme_mgt_packet_filter_set: invalid smepriv\n");
1280 if (priv->packet_filters.arp_filter) {
1281 ipAddress.a[0] = (priv->sta_ip_address ) & 0xFF;
1282 ipAddress.a[1] = (priv->sta_ip_address >> 8) & 0xFF;
1283 ipAddress.a[2] = (priv->sta_ip_address >> 16) & 0xFF;
1284 ipAddress.a[3] = (priv->sta_ip_address >> 24) & 0xFF;
1287 unifi_trace(priv, UDBG5,
1288 "sme_mgt_packet_filter_set: IP address %d.%d.%d.%d\n",
1289 ipAddress.a[0], ipAddress.a[1],
1290 ipAddress.a[2], ipAddress.a[3]);
1292 /* Doesn't block for a confirm */
1293 CsrWifiSmePacketFilterSetReqSend(0, CSR_WIFI_INTERFACE_IN_USE,
1294 priv->packet_filters.tclas_ies_length,
1295 priv->filter_tclas_ies,
1296 priv->packet_filters.filter_mode,
1301 int sme_mgt_tspec(unifi_priv_t *priv, CsrWifiSmeListAction action,
1302 u32 tid, CsrWifiSmeDataBlock *tspec, CsrWifiSmeDataBlock *tclas)
1306 if (priv->smepriv == NULL) {
1307 unifi_error(priv, "sme_mgt_tspec: invalid smepriv\n");
1311 r = sme_init_request(priv);
1316 CsrWifiSmeTspecReqSend(0, CSR_WIFI_INTERFACE_IN_USE,
1317 action, tid, TRUE, 0,
1318 tspec->length, tspec->data,
1319 tclas->length, tclas->data);
1320 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
1325 unifi_trace(priv, UDBG4, "sme_mgt_tspec: <-- (status=%d)\n", priv->sme_reply.reply_status);
1326 return convert_sme_error(priv->sme_reply.reply_status);
1331 int sme_sys_suspend(unifi_priv_t *priv)
1334 CsrResult csrResult;
1336 if (priv->smepriv == NULL) {
1337 unifi_error(priv, "sme_sys_suspend: invalid smepriv\n");
1341 r = sme_init_request(priv);
1346 /* Suspend the SME, which MAY cause it to power down UniFi */
1347 CsrWifiRouterCtrlSuspendIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0, 0, priv->wol_suspend);
1348 r = sme_wait_for_reply(priv, UNIFI_SME_SYS_LONG_TIMEOUT);
1350 /* No reply - forcibly power down in case the request wasn't processed */
1352 "suspend: SME did not reply %s, ",
1353 (priv->ptest_mode | priv->wol_suspend) ? "leave powered" : "power off UniFi anyway\n");
1355 /* Leave power on for production test, though */
1356 if (!priv->ptest_mode) {
1357 /* Put UniFi to deep sleep, in case we can not power it off */
1358 CsrSdioClaim(priv->sdio);
1359 unifi_trace(priv, UDBG1, "Force deep sleep");
1360 csrResult = unifi_force_low_power_mode(priv->card);
1362 /* For WOL, the UniFi must stay powered */
1363 if (!priv->wol_suspend) {
1364 unifi_trace(priv, UDBG1, "Power off\n");
1365 CsrSdioPowerOff(priv->sdio);
1367 CsrSdioRelease(priv->sdio);
1371 if (priv->wol_suspend) {
1372 unifi_trace(priv, UDBG1, "UniFi left powered for WOL\n");
1374 /* Remove the IRQ, which also disables the card SDIO interrupt.
1375 * Disabling the card SDIO interrupt enables the PIO WOL source.
1376 * Removal of the of the handler ensures that in both SDIO and PIO cases
1377 * the card interrupt only wakes the host. The card will be polled
1378 * after resume to handle any pending data.
1380 if (csr_sdio_linux_remove_irq(priv->sdio)) {
1381 unifi_notice(priv, "WOL csr_sdio_linux_remove_irq failed\n");
1384 if (enable_wol == UNIFI_WOL_SDIO) {
1385 /* Because csr_sdio_linux_remove_irq() disabled the card SDIO interrupt,
1386 * it must be left enabled to wake-on-SDIO.
1388 unifi_trace(priv, UDBG1, "Enable card SDIO interrupt for SDIO WOL\n");
1390 CsrSdioClaim(priv->sdio);
1391 csrResult = CsrSdioInterruptEnable(priv->sdio);
1392 CsrSdioRelease(priv->sdio);
1394 if (csrResult != CSR_RESULT_SUCCESS) {
1395 unifi_error(priv, "WOL CsrSdioInterruptEnable failed %d\n", csrResult);
1398 unifi_trace(priv, UDBG1, "Disabled card SDIO interrupt for PIO WOL\n");
1401 /* Prevent the BH thread from running during the suspend.
1402 * Upon resume, sme_sys_resume() will trigger a wifi-on, this will cause
1403 * the BH thread to be re-enabled and reinstall the ISR.
1405 priv->bh_thread.block_thread = 1;
1407 unifi_trace(priv, UDBG1, "unifi_suspend: suspended BH");
1410 /* Consider UniFi to be uninitialised */
1411 priv->init_progress = UNIFI_INIT_NONE;
1413 unifi_trace(priv, UDBG1, "sme_sys_suspend: <-- (r=%d status=%d)\n", r, priv->sme_reply.reply_status);
1414 return convert_sme_error(priv->sme_reply.reply_status);
1418 int sme_sys_resume(unifi_priv_t *priv)
1422 unifi_trace(priv, UDBG1, "sme_sys_resume %s\n", priv->wol_suspend ? "warm" : "");
1424 if (priv->smepriv == NULL) {
1425 unifi_error(priv, "sme_sys_resume: invalid smepriv\n");
1429 r = sme_init_request(priv);
1434 CsrWifiRouterCtrlResumeIndSend(priv->CSR_WIFI_SME_IFACEQUEUE,0, priv->wol_suspend);
1436 r = sme_wait_for_reply(priv, UNIFI_SME_SYS_LONG_TIMEOUT);
1439 "resume: SME did not reply, return success anyway\n");
1445 #ifdef CSR_SUPPORT_WEXT_AP
1446 int sme_ap_stop(unifi_priv_t *priv,u16 interface_tag)
1450 if (priv->smepriv == NULL) {
1451 unifi_error(priv, "sme_ap_stop: invalid smepriv\n");
1455 r = sme_init_request(priv);
1460 CsrWifiNmeApStopReqSend(0,interface_tag);
1462 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
1467 unifi_trace(priv, UDBG4,
1468 "sme_ap_stop <-- (r=%d status=%d)\n",
1469 r, priv->sme_reply.reply_status);
1470 return convert_sme_error(priv->sme_reply.reply_status);
1474 int sme_ap_start(unifi_priv_t *priv,u16 interface_tag,
1475 CsrWifiSmeApConfig_t * ap_config)
1478 CsrWifiSmeApP2pGoConfig p2p_go_param;
1479 memset(&p2p_go_param,0,sizeof(CsrWifiSmeApP2pGoConfig));
1481 if (priv->smepriv == NULL) {
1482 unifi_error(priv, "sme_ap_start: invalid smepriv\n");
1486 r = sme_init_request(priv);
1491 CsrWifiNmeApStartReqSend(0,interface_tag,CSR_WIFI_AP_TYPE_LEGACY,FALSE,
1492 ap_config->ssid,1,ap_config->channel,
1493 ap_config->credentials,ap_config->max_connections,
1494 p2p_go_param,FALSE);
1496 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
1501 unifi_trace(priv, UDBG4,
1502 "sme_ap_start <-- (r=%d status=%d)\n",
1503 r, priv->sme_reply.reply_status);
1504 return convert_sme_error(priv->sme_reply.reply_status);
1507 int sme_ap_config(unifi_priv_t *priv,
1508 CsrWifiSmeApMacConfig *ap_mac_config,
1509 CsrWifiNmeApConfig *group_security_config)
1512 CsrWifiSmeApP2pGoConfig p2p_go_param;
1513 memset(&p2p_go_param,0,sizeof(CsrWifiSmeApP2pGoConfig));
1515 if (priv->smepriv == NULL) {
1516 unifi_error(priv, "sme_ap_config: invalid smepriv\n");
1520 r = sme_init_request(priv);
1525 CsrWifiNmeApConfigSetReqSend(0,*group_security_config,
1528 r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT);
1530 unifi_trace(priv, UDBG4,
1531 "sme_ap_config <-- (r=%d status=%d)\n",
1532 r, priv->sme_reply.reply_status);
1533 return convert_sme_error(priv->sme_reply.reply_status);