| /* |
| * --------------------------------------------------------------------------- |
| * FILE: sme_mgt_blocking.c |
| * |
| * PURPOSE: |
| * This file contains the driver specific implementation of |
| * the WEXT <==> SME MGT interface for all SME builds that support WEXT. |
| * |
| * Copyright (C) 2009 by Cambridge Silicon Radio Ltd. |
| * |
| * Refer to LICENSE.txt included with this source code for details on |
| * the license terms. |
| * |
| * --------------------------------------------------------------------------- |
| */ |
| |
| #include "unifi_priv.h" |
| |
| |
| /* |
| * This file also contains the implementation of the asynchronous |
| * requests to the SME. |
| * |
| * Before calling an asynchronous SME function, we call sme_init_request() |
| * which gets hold of the SME semaphore and updates the request status. |
| * The semaphore makes sure that there is only one pending request to |
| * the SME at a time. |
| * |
| * Now we are ready to call the SME function, but only if |
| * sme_init_request() has returned 0. |
| * |
| * When the SME function returns, we need to wait |
| * for the reply. This is done in sme_wait_for_reply(). |
| * If the request times-out, the request status is set to SME_REQUEST_TIMEDOUT |
| * and the sme_wait_for_reply() returns. |
| * |
| * If the SME replies in time, we call sme_complete_request(). |
| * There we change the request status to SME_REQUEST_RECEIVED. This will |
| * wake up the process waiting on sme_wait_for_reply(). |
| * It is important that we copy the reply data in priv->sme_reply |
| * before calling sme_complete_request(). |
| * |
| * Handling the wext requests, we need to block |
| * until the SME sends the response to our request. |
| * We use the sme_init_request() and sme_wait_for_reply() |
| * to implement this behavior in the following functions: |
| * sme_mgt_wifi_on() |
| * sme_mgt_wifi_off() |
| * sme_mgt_scan_full() |
| * sme_mgt_scan_results_get_async() |
| * sme_mgt_connect() |
| * unifi_mgt_media_status_ind() |
| * sme_mgt_disconnect() |
| * sme_mgt_pmkid() |
| * sme_mgt_key() |
| * sme_mgt_mib_get() |
| * sme_mgt_mib_set() |
| * sme_mgt_versions_get() |
| * sme_mgt_set_value() |
| * sme_mgt_get_value() |
| * sme_mgt_set_value_async() |
| * sme_mgt_get_value_async() |
| * sme_mgt_packet_filter_set() |
| * sme_mgt_tspec() |
| */ |
| |
| |
| /* |
| * Handling the suspend and resume system events, we need to block |
| * until the SME sends the response to our indication. |
| * We use the sme_init_request() and sme_wait_for_reply() |
| * to implement this behavior in the following functions: |
| * sme_sys_suspend() |
| * sme_sys_resume() |
| */ |
| |
| #define UNIFI_SME_MGT_SHORT_TIMEOUT 10000 |
| #define UNIFI_SME_MGT_LONG_TIMEOUT 19000 |
| #define UNIFI_SME_SYS_LONG_TIMEOUT 10000 |
| |
| #ifdef UNIFI_DEBUG |
| # define sme_wait_for_reply(priv, t) _sme_wait_for_reply(priv, t, __func__) |
| #else |
| # define sme_wait_for_reply(priv, t) _sme_wait_for_reply(priv, t, NULL) |
| #endif |
| |
| static int |
| sme_init_request(unifi_priv_t *priv) |
| { |
| if (priv == NULL) { |
| unifi_error(priv, "sme_init_request: Invalid priv\n"); |
| return -EIO; |
| } |
| |
| unifi_trace(priv, UDBG5, "sme_init_request: wait sem\n"); |
| |
| /* Grab the SME semaphore until the reply comes, or timeout */ |
| if (down_interruptible(&priv->sme_sem)) { |
| unifi_error(priv, "sme_init_request: Failed to get SME semaphore\n"); |
| return -EIO; |
| } |
| unifi_trace(priv, UDBG5, "sme_init_request: got sem: pending\n"); |
| |
| priv->sme_reply.request_status = SME_REQUEST_PENDING; |
| |
| return 0; |
| |
| } /* sme_init_request() */ |
| |
| |
| void |
| uf_sme_complete_request(unifi_priv_t *priv, CsrResult reply_status, const char *func) |
| { |
| if (priv == NULL) { |
| unifi_error(priv, "sme_complete_request: Invalid priv\n"); |
| return; |
| } |
| |
| if (priv->sme_reply.request_status != SME_REQUEST_PENDING) { |
| unifi_notice(priv, |
| "sme_complete_request: request not pending %s (s:%d)\n", |
| (func ? func : ""), priv->sme_reply.request_status); |
| return; |
| } |
| unifi_trace(priv, UDBG5, |
| "sme_complete_request: completed %s (s:%d)\n", |
| (func ? func : ""), priv->sme_reply.request_status); |
| |
| priv->sme_reply.request_status = SME_REQUEST_RECEIVED; |
| priv->sme_reply.reply_status = reply_status; |
| |
| wake_up_interruptible(&priv->sme_request_wq); |
| |
| return; |
| } |
| |
| |
| void |
| uf_sme_cancel_request(unifi_priv_t *priv, CsrResult reply_status) |
| { |
| /* Check for a blocking SME request in progress, and cancel the wait. |
| * This should be used when the character device is closed. |
| */ |
| |
| if (priv == NULL) { |
| unifi_error(priv, "sme_cancel_request: Invalid priv\n"); |
| return; |
| } |
| |
| /* If no request is pending, nothing to wake up */ |
| if (priv->sme_reply.request_status != SME_REQUEST_PENDING) { |
| unifi_trace(priv, UDBG5, |
| "sme_cancel_request: no request was pending (s:%d)\n", |
| priv->sme_reply.request_status); |
| /* Nothing to do */ |
| return; |
| } |
| unifi_trace(priv, UDBG5, |
| "sme_cancel_request: request cancelled (s:%d)\n", |
| priv->sme_reply.request_status); |
| |
| /* Wake up the wait with an error status */ |
| priv->sme_reply.request_status = SME_REQUEST_CANCELLED; |
| priv->sme_reply.reply_status = reply_status; /* unimportant since the CANCELLED state will fail the ioctl */ |
| |
| wake_up_interruptible(&priv->sme_request_wq); |
| |
| return; |
| } |
| |
| |
| static int |
| _sme_wait_for_reply(unifi_priv_t *priv, |
| unsigned long timeout, const char *func) |
| { |
| long r; |
| |
| unifi_trace(priv, UDBG5, "sme_wait_for_reply: %s sleep\n", func ? func : ""); |
| r = wait_event_interruptible_timeout(priv->sme_request_wq, |
| (priv->sme_reply.request_status != SME_REQUEST_PENDING), |
| msecs_to_jiffies(timeout)); |
| unifi_trace(priv, UDBG5, "sme_wait_for_reply: %s awake (%d)\n", func ? func : "", r); |
| |
| if (r == -ERESTARTSYS) { |
| /* The thread was killed */ |
| unifi_info(priv, "ERESTARTSYS in _sme_wait_for_reply\n"); |
| up(&priv->sme_sem); |
| return r; |
| } |
| if (priv->sme_reply.request_status == SME_REQUEST_CANCELLED) { |
| unifi_trace(priv, UDBG5, "Cancelled waiting for SME to reply (%s s:%d, t:%d, r:%d)\n", |
| (func ? func : ""), priv->sme_reply.request_status, timeout, r); |
| |
| /* Release the SME semaphore that was downed in sme_init_request() */ |
| up(&priv->sme_sem); |
| return -EIO; /* fail the ioctl */ |
| } |
| if ((r == 0) && (priv->sme_reply.request_status != SME_REQUEST_RECEIVED)) { |
| unifi_notice(priv, "Timeout waiting for SME to reply (%s s:%d, t:%d)\n", |
| (func ? func : ""), priv->sme_reply.request_status, timeout); |
| |
| priv->sme_reply.request_status = SME_REQUEST_TIMEDOUT; |
| |
| /* Release the SME semaphore that was downed in sme_init_request() */ |
| up(&priv->sme_sem); |
| |
| return -ETIMEDOUT; |
| } |
| |
| unifi_trace(priv, UDBG5, "sme_wait_for_reply: %s received (%d)\n", |
| func ? func : "", r); |
| |
| /* Release the SME semaphore that was downed in sme_init_request() */ |
| up(&priv->sme_sem); |
| |
| return 0; |
| } /* sme_wait_for_reply() */ |
| |
| |
| |
| |
| #ifdef CSR_SUPPORT_WEXT |
| int sme_mgt_wifi_on(unifi_priv_t *priv) |
| { |
| u16 numElements; |
| CsrWifiSmeDataBlock* dataList; |
| #ifdef CSR_SUPPORT_WEXT_AP |
| int r; |
| #endif |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_wifi_on: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| if (priv->mib_data.length) { |
| numElements = 1; |
| dataList = &priv->mib_data; |
| } else { |
| numElements = 0; |
| dataList = NULL; |
| } |
| /* Start the SME */ |
| #ifdef CSR_SUPPORT_WEXT_AP |
| r = sme_init_request(priv); |
| if (r) { |
| return -EIO; |
| } |
| #endif |
| CsrWifiSmeWifiOnReqSend(0, priv->sta_mac_address, numElements, dataList); |
| #ifdef CSR_SUPPORT_WEXT_AP |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_LONG_TIMEOUT); |
| unifi_trace(priv, UDBG4, |
| "sme_mgt_wifi_on: unifi_mgt_wifi_oo_req <-- (r=%d, status=%d)\n", |
| r, priv->sme_reply.reply_status); |
| return convert_sme_error(priv->sme_reply.reply_status); |
| #else |
| return 0; |
| #endif |
| } /* sme_mgt_wifi_on() */ |
| |
| |
| int sme_mgt_wifi_off(unifi_priv_t *priv) |
| { |
| int r; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_wifi_off: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| /* Stop the SME */ |
| CsrWifiSmeWifiOffReqSend(0); |
| |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_LONG_TIMEOUT); |
| if (r) |
| return r; |
| |
| unifi_trace(priv, UDBG4, |
| "sme_mgt_wifi_off: unifi_mgt_wifi_off_req <-- (r=%d, status=%d)\n", |
| r, priv->sme_reply.reply_status); |
| return convert_sme_error(priv->sme_reply.reply_status); |
| |
| } /* sme_mgt_wifi_off */ |
| |
| int sme_mgt_key(unifi_priv_t *priv, CsrWifiSmeKey *sme_key, |
| CsrWifiSmeListAction action) |
| { |
| int r; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_key: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiSmeKeyReqSend(0, CSR_WIFI_INTERFACE_IN_USE, action, *sme_key); |
| |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| return convert_sme_error(priv->sme_reply.reply_status); |
| } |
| |
| |
| int sme_mgt_scan_full(unifi_priv_t *priv, |
| CsrWifiSsid *specific_ssid, |
| int num_channels, |
| unsigned char *channel_list) |
| { |
| CsrWifiMacAddress bcastAddress = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }}; |
| u8 is_active = (num_channels > 0) ? TRUE : FALSE; |
| int r; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_scan_full: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| unifi_trace(priv, UDBG4, "sme_mgt_scan_full: -->\n"); |
| |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| /* If a channel list is provided, do an active scan */ |
| if (is_active) { |
| unifi_trace(priv, UDBG1, |
| "channel list - num_channels: %d, active scan\n", |
| num_channels); |
| } |
| |
| CsrWifiSmeScanFullReqSend(0, |
| specific_ssid->length?1:0, /* 0 or 1 SSIDS */ |
| specific_ssid, |
| bcastAddress, |
| is_active, |
| CSR_WIFI_SME_BSS_TYPE_ANY_BSS, |
| CSR_WIFI_SME_SCAN_TYPE_ALL, |
| (u16)num_channels, channel_list, |
| 0, NULL); |
| |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_LONG_TIMEOUT); |
| if (r) |
| return r; |
| |
| unifi_trace(priv, UDBG4, "sme_mgt_scan_full: <-- (status=%d)\n", priv->sme_reply.reply_status); |
| if (priv->sme_reply.reply_status == CSR_WIFI_RESULT_UNAVAILABLE) |
| return 0; /* initial scan already underway */ |
| else |
| return convert_sme_error(priv->sme_reply.reply_status); |
| } |
| |
| |
| int sme_mgt_scan_results_get_async(unifi_priv_t *priv, |
| struct iw_request_info *info, |
| char *scan_results, |
| long scan_results_len) |
| { |
| u16 scan_result_list_count; |
| CsrWifiSmeScanResult *scan_result_list; |
| CsrWifiSmeScanResult *scan_result; |
| int r; |
| int i; |
| char *current_ev = scan_results; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_scan_results_get_async: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiSmeScanResultsGetReqSend(0); |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_LONG_TIMEOUT); |
| if (r) |
| return r; |
| |
| scan_result_list_count = priv->sme_reply.reply_scan_results_count; |
| scan_result_list = priv->sme_reply.reply_scan_results; |
| unifi_trace(priv, UDBG2, |
| "scan_results: Scan returned %d, numElements=%d\n", |
| r, scan_result_list_count); |
| |
| /* OK, now we have the scan results */ |
| for (i = 0; i < scan_result_list_count; ++i) { |
| scan_result = &scan_result_list[i]; |
| |
| unifi_trace(priv, UDBG2, "Scan Result: %.*s\n", |
| scan_result->ssid.length, |
| scan_result->ssid.ssid); |
| |
| r = unifi_translate_scan(priv->netdev[0], info, |
| current_ev, |
| scan_results + scan_results_len, |
| scan_result, i+1); |
| |
| if (r < 0) { |
| kfree(scan_result_list); |
| priv->sme_reply.reply_scan_results_count = 0; |
| priv->sme_reply.reply_scan_results = NULL; |
| return r; |
| } |
| |
| current_ev += r; |
| } |
| |
| /* |
| * Free the scan results allocated in unifi_mgt_scan_results_get_cfm() |
| * and invalidate the reply_scan_results to avoid re-using |
| * the freed pointers. |
| */ |
| kfree(scan_result_list); |
| priv->sme_reply.reply_scan_results_count = 0; |
| priv->sme_reply.reply_scan_results = NULL; |
| |
| unifi_trace(priv, UDBG2, |
| "scan_results: Scan translated to %d bytes\n", |
| current_ev - scan_results); |
| return (current_ev - scan_results); |
| } |
| |
| |
| int sme_mgt_connect(unifi_priv_t *priv) |
| { |
| int r; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_connect: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| unifi_trace(priv, UDBG2, "sme_mgt_connect: %.*s\n", |
| priv->connection_config.ssid.length, |
| priv->connection_config.ssid.ssid); |
| |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiSmeConnectReqSend(0, CSR_WIFI_INTERFACE_IN_USE, priv->connection_config); |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| if (priv->sme_reply.reply_status) |
| unifi_trace(priv, UDBG1, "sme_mgt_connect: failed with SME status %d\n", |
| priv->sme_reply.reply_status); |
| |
| return convert_sme_error(priv->sme_reply.reply_status); |
| } |
| |
| |
| int sme_mgt_disconnect(unifi_priv_t *priv) |
| { |
| int r; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_disconnect: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiSmeDisconnectReqSend(0, CSR_WIFI_INTERFACE_IN_USE); |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| unifi_trace(priv, UDBG4, "sme_mgt_disconnect: <-- (status=%d)\n", priv->sme_reply.reply_status); |
| return convert_sme_error(priv->sme_reply.reply_status); |
| } |
| |
| |
| int sme_mgt_pmkid(unifi_priv_t *priv, |
| CsrWifiSmeListAction action, |
| CsrWifiSmePmkidList *pmkid_list) |
| { |
| int r; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_pmkid: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiSmePmkidReqSend(0, CSR_WIFI_INTERFACE_IN_USE, action, |
| pmkid_list->pmkidsCount, pmkid_list->pmkids); |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| unifi_trace(priv, UDBG4, "sme_mgt_pmkid: <-- (status=%d)\n", priv->sme_reply.reply_status); |
| return convert_sme_error(priv->sme_reply.reply_status); |
| } |
| |
| |
| int sme_mgt_mib_get(unifi_priv_t *priv, |
| unsigned char *varbind, int *length) |
| { |
| int r; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_mib_get: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| priv->mib_cfm_buffer = varbind; |
| priv->mib_cfm_buffer_length = MAX_VARBIND_LENGTH; |
| |
| CsrWifiSmeMibGetReqSend(0, *length, varbind); |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) { |
| priv->mib_cfm_buffer_length = 0; |
| priv->mib_cfm_buffer = NULL; |
| return r; |
| } |
| |
| *length = priv->mib_cfm_buffer_length; |
| |
| priv->mib_cfm_buffer_length = 0; |
| priv->mib_cfm_buffer = NULL; |
| unifi_trace(priv, UDBG4, "sme_mgt_mib_get: <-- (status=%d)\n", priv->sme_reply.reply_status); |
| return convert_sme_error(priv->sme_reply.reply_status); |
| } |
| |
| int sme_mgt_mib_set(unifi_priv_t *priv, |
| unsigned char *varbind, int length) |
| { |
| int r; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_mib_get: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiSmeMibSetReqSend(0, length, varbind); |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| unifi_trace(priv, UDBG4, "sme_mgt_mib_set: <-- (status=%d)\n", priv->sme_reply.reply_status); |
| return convert_sme_error(priv->sme_reply.reply_status); |
| } |
| |
| #endif /* CSR_SUPPORT_WEXT */ |
| |
| int sme_mgt_power_config_set(unifi_priv_t *priv, CsrWifiSmePowerConfig *powerConfig) |
| { |
| #ifdef CSR_SME_USERSPACE |
| int r; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_set_value_async: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiSmePowerConfigSetReqSend(0, *powerConfig); |
| |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| unifi_trace(priv, UDBG4, |
| "sme_mgt_set_value_async: unifi_mgt_set_value_req <-- (r=%d status=%d)\n", |
| r, priv->sme_reply.reply_status); |
| return convert_sme_error(priv->sme_reply.reply_status); |
| #else |
| CsrResult status; |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_set_value: invalid smepriv\n"); |
| return -EIO; |
| } |
| CsrWifiSmeMgtClaimSyncAccess(priv->smepriv); |
| status = CsrWifiSmeMgtPowerConfigSetReq(priv->smepriv, *powerConfig); |
| CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv); |
| return convert_sme_error(status); |
| #endif |
| } |
| |
| int sme_mgt_sme_config_set(unifi_priv_t *priv, CsrWifiSmeStaConfig *staConfig, CsrWifiSmeDeviceConfig *deviceConfig) |
| { |
| #ifdef CSR_SME_USERSPACE |
| int r; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_sme_config_set: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiSmeSmeStaConfigSetReqSend(0, CSR_WIFI_INTERFACE_IN_USE, *staConfig); |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| unifi_trace(priv, UDBG4, |
| "sme_mgt_sme_config_set: CsrWifiSmeSmeStaConfigSetReq <-- (r=%d status=%d)\n", |
| r, priv->sme_reply.reply_status); |
| |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiSmeSmeCommonConfigSetReqSend(0, *deviceConfig); |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| unifi_trace(priv, UDBG4, |
| "sme_mgt_sme_config_set: CsrWifiSmeSmeCommonConfigSetReq <-- (r=%d status=%d)\n", |
| r, priv->sme_reply.reply_status); |
| |
| return convert_sme_error(priv->sme_reply.reply_status); |
| #else |
| CsrResult status; |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_sme_config_set: invalid smepriv\n"); |
| return -EIO; |
| } |
| CsrWifiSmeMgtClaimSyncAccess(priv->smepriv); |
| status = CsrWifiSmeMgtSmeConfigSetReq(priv->smepriv, *staConfig); |
| status = CsrWifiSmeMgtDeviceConfigSetReq(priv->smepriv, *deviceConfig); |
| CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv); |
| return convert_sme_error(status); |
| #endif |
| } |
| |
| #ifdef CSR_SUPPORT_WEXT |
| |
| int sme_mgt_mib_config_set(unifi_priv_t *priv, CsrWifiSmeMibConfig *mibConfig) |
| { |
| #ifdef CSR_SME_USERSPACE |
| int r; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_mib_config_set: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiSmeMibConfigSetReqSend(0, *mibConfig); |
| |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| unifi_trace(priv, UDBG4, |
| "sme_mgt_mib_config_set: unifi_mgt_set_mib_config_req <-- (r=%d status=%d)\n", |
| r, priv->sme_reply.reply_status); |
| return convert_sme_error(priv->sme_reply.reply_status); |
| #else |
| CsrResult status; |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_mib_config_set: invalid smepriv\n"); |
| return -EIO; |
| } |
| CsrWifiSmeMgtClaimSyncAccess(priv->smepriv); |
| status = CsrWifiSmeMgtMibConfigSetReq(priv->smepriv, *mibConfig); |
| CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv); |
| return convert_sme_error(status); |
| #endif |
| } |
| |
| int sme_mgt_coex_config_set(unifi_priv_t *priv, CsrWifiSmeCoexConfig *coexConfig) |
| { |
| #ifdef CSR_SME_USERSPACE |
| int r; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_coex_config_set: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiSmeCoexConfigSetReqSend(0, *coexConfig); |
| |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| unifi_trace(priv, UDBG4, |
| "sme_mgt_coex_config_set: unifi_mgt_set_mib_config_req <-- (r=%d status=%d)\n", |
| r, priv->sme_reply.reply_status); |
| return convert_sme_error(priv->sme_reply.reply_status); |
| #else |
| CsrResult status; |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_coex_config_set: invalid smepriv\n"); |
| return -EIO; |
| } |
| CsrWifiSmeMgtClaimSyncAccess(priv->smepriv); |
| status = CsrWifiSmeMgtCoexConfigSetReq(priv->smepriv, *coexConfig); |
| CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv); |
| return convert_sme_error(status); |
| #endif |
| } |
| |
| #endif /* CSR_SUPPORT_WEXT */ |
| |
| int sme_mgt_host_config_set(unifi_priv_t *priv, CsrWifiSmeHostConfig *hostConfig) |
| { |
| #ifdef CSR_SME_USERSPACE |
| int r; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_host_config_set: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiSmeHostConfigSetReqSend(0, CSR_WIFI_INTERFACE_IN_USE, *hostConfig); |
| |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| unifi_trace(priv, UDBG4, |
| "sme_mgt_host_config_set: unifi_mgt_set_host_config_req <-- (r=%d status=%d)\n", |
| r, priv->sme_reply.reply_status); |
| return convert_sme_error(priv->sme_reply.reply_status); |
| #else |
| CsrResult status; |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_host_config_set: invalid smepriv\n"); |
| return -EIO; |
| } |
| CsrWifiSmeMgtClaimSyncAccess(priv->smepriv); |
| status = CsrWifiSmeMgtHostConfigSetReq(priv->smepriv, *hostConfig); |
| CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv); |
| return convert_sme_error(status); |
| #endif |
| } |
| |
| #ifdef CSR_SUPPORT_WEXT |
| |
| int sme_mgt_versions_get(unifi_priv_t *priv, CsrWifiSmeVersions *versions) |
| { |
| #ifdef CSR_SME_USERSPACE |
| int r; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_versions_get: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| unifi_trace(priv, UDBG4, "sme_mgt_versions_get: unifi_mgt_versions_get_req -->\n"); |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiSmeVersionsGetReqSend(0); |
| |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| /* store the reply */ |
| if (versions != NULL) { |
| memcpy((unsigned char*)versions, |
| (unsigned char*)&priv->sme_reply.versions, |
| sizeof(CsrWifiSmeVersions)); |
| } |
| |
| unifi_trace(priv, UDBG4, |
| "sme_mgt_versions_get: unifi_mgt_versions_get_req <-- (r=%d status=%d)\n", |
| r, priv->sme_reply.reply_status); |
| |
| return convert_sme_error(priv->sme_reply.reply_status); |
| #else |
| CsrResult status; |
| CsrWifiSmeMgtClaimSyncAccess(priv->smepriv); |
| status = CsrWifiSmeMgtVersionsGetReq(priv->smepriv, versions); |
| CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv); |
| return convert_sme_error(status); |
| #endif |
| } |
| |
| #endif /* CSR_SUPPORT_WEXT */ |
| |
| int sme_mgt_power_config_get(unifi_priv_t *priv, CsrWifiSmePowerConfig *powerConfig) |
| { |
| #ifdef CSR_SME_USERSPACE |
| int r; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_power_config_get: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| unifi_trace(priv, UDBG4, "sme_mgt_power_config_get: unifi_mgt_power_config_req -->\n"); |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiSmePowerConfigGetReqSend(0); |
| |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| /* store the reply */ |
| if (powerConfig != NULL) { |
| memcpy((unsigned char*)powerConfig, |
| (unsigned char*)&priv->sme_reply.powerConfig, |
| sizeof(CsrWifiSmePowerConfig)); |
| } |
| |
| unifi_trace(priv, UDBG4, |
| "sme_mgt_get_versions: unifi_mgt_power_config_req <-- (r=%d status=%d)\n", |
| r, priv->sme_reply.reply_status); |
| |
| return convert_sme_error(priv->sme_reply.reply_status); |
| #else |
| CsrResult status; |
| CsrWifiSmeMgtClaimSyncAccess(priv->smepriv); |
| status = CsrWifiSmeMgtPowerConfigGetReq(priv->smepriv, powerConfig); |
| CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv); |
| return convert_sme_error(status); |
| #endif |
| } |
| |
| int sme_mgt_host_config_get(unifi_priv_t *priv, CsrWifiSmeHostConfig *hostConfig) |
| { |
| #ifdef CSR_SME_USERSPACE |
| int r; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_host_config_get: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| unifi_trace(priv, UDBG4, "sme_mgt_host_config_get: unifi_mgt_host_config_get_req -->\n"); |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiSmeHostConfigGetReqSend(0, CSR_WIFI_INTERFACE_IN_USE); |
| |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| /* store the reply */ |
| if (hostConfig != NULL) |
| memcpy((unsigned char*)hostConfig, |
| (unsigned char*)&priv->sme_reply.hostConfig, |
| sizeof(CsrWifiSmeHostConfig)); |
| |
| unifi_trace(priv, UDBG4, |
| "sme_mgt_host_config_get: unifi_mgt_host_config_get_req <-- (r=%d status=%d)\n", |
| r, priv->sme_reply.reply_status); |
| |
| return convert_sme_error(priv->sme_reply.reply_status); |
| #else |
| CsrResult status; |
| CsrWifiSmeMgtClaimSyncAccess(priv->smepriv); |
| status = CsrWifiSmeMgtHostConfigGetReq(priv->smepriv, hostConfig); |
| CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv); |
| return convert_sme_error(status); |
| #endif |
| } |
| |
| int sme_mgt_sme_config_get(unifi_priv_t *priv, CsrWifiSmeStaConfig *staConfig, CsrWifiSmeDeviceConfig *deviceConfig) |
| { |
| #ifdef CSR_SME_USERSPACE |
| int r; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_sme_config_get: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| unifi_trace(priv, UDBG4, "sme_mgt_sme_config_get: unifi_mgt_sme_config_get_req -->\n"); |
| |
| /* Common device config */ |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiSmeSmeCommonConfigGetReqSend(0); |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| /* store the reply */ |
| if (deviceConfig != NULL) |
| memcpy((unsigned char*)deviceConfig, |
| (unsigned char*)&priv->sme_reply.deviceConfig, |
| sizeof(CsrWifiSmeDeviceConfig)); |
| |
| /* STA config */ |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiSmeSmeStaConfigGetReqSend(0, CSR_WIFI_INTERFACE_IN_USE); |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| /* store the reply */ |
| if (staConfig != NULL) |
| memcpy((unsigned char*)staConfig, |
| (unsigned char*)&priv->sme_reply.staConfig, |
| sizeof(CsrWifiSmeStaConfig)); |
| |
| unifi_trace(priv, UDBG4, |
| "sme_mgt_sme_config_get: unifi_mgt_sme_config_get_req <-- (r=%d status=%d)\n", |
| r, priv->sme_reply.reply_status); |
| |
| return convert_sme_error(priv->sme_reply.reply_status); |
| #else |
| CsrResult status; |
| CsrWifiSmeMgtClaimSyncAccess(priv->smepriv); |
| status = CsrWifiSmeMgtSmeConfigGetReq(priv->smepriv, staConfig); |
| status = CsrWifiSmeMgtDeviceConfigGetReq(priv->smepriv, deviceConfig); |
| CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv); |
| return convert_sme_error(status); |
| #endif |
| } |
| |
| int sme_mgt_coex_info_get(unifi_priv_t *priv, CsrWifiSmeCoexInfo *coexInfo) |
| { |
| #ifdef CSR_SME_USERSPACE |
| int r; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_coex_info_get: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| unifi_trace(priv, UDBG4, "sme_mgt_coex_info_get: unifi_mgt_coex_info_get_req -->\n"); |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiSmeCoexInfoGetReqSend(0); |
| |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| /* store the reply */ |
| if (coexInfo != NULL) |
| memcpy((unsigned char*)coexInfo, |
| (unsigned char*)&priv->sme_reply.coexInfo, |
| sizeof(CsrWifiSmeCoexInfo)); |
| |
| unifi_trace(priv, UDBG4, |
| "sme_mgt_coex_info_get: unifi_mgt_coex_info_get_req <-- (r=%d status=%d)\n", |
| r, priv->sme_reply.reply_status); |
| |
| return convert_sme_error(priv->sme_reply.reply_status); |
| #else |
| CsrResult status; |
| CsrWifiSmeMgtClaimSyncAccess(priv->smepriv); |
| status = CsrWifiSmeMgtCoexInfoGetReq(priv->smepriv, coexInfo); |
| CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv); |
| return convert_sme_error(status); |
| #endif |
| } |
| |
| #ifdef CSR_SUPPORT_WEXT |
| |
| int sme_mgt_coex_config_get(unifi_priv_t *priv, CsrWifiSmeCoexConfig *coexConfig) |
| { |
| #ifdef CSR_SME_USERSPACE |
| int r; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_coex_config_get: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| unifi_trace(priv, UDBG4, "sme_mgt_coex_config_get: unifi_mgt_coex_config_get_req -->\n"); |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiSmeCoexConfigGetReqSend(0); |
| |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| /* store the reply */ |
| if (coexConfig != NULL) |
| memcpy((unsigned char*)coexConfig, |
| (unsigned char*)&priv->sme_reply.coexConfig, |
| sizeof(CsrWifiSmeCoexConfig)); |
| |
| unifi_trace(priv, UDBG4, |
| "sme_mgt_coex_config_get: unifi_mgt_coex_config_get_req <-- (r=%d status=%d)\n", |
| r, priv->sme_reply.reply_status); |
| |
| return convert_sme_error(priv->sme_reply.reply_status); |
| #else |
| CsrResult status; |
| CsrWifiSmeMgtClaimSyncAccess(priv->smepriv); |
| status = CsrWifiSmeMgtCoexConfigGetReq(priv->smepriv, coexConfig); |
| CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv); |
| return convert_sme_error(status); |
| #endif |
| } |
| |
| int sme_mgt_mib_config_get(unifi_priv_t *priv, CsrWifiSmeMibConfig *mibConfig) |
| { |
| #ifdef CSR_SME_USERSPACE |
| int r; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_mib_config_get: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| unifi_trace(priv, UDBG4, "sme_mgt_mib_config_get: unifi_mgt_mib_config_get_req -->\n"); |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiSmeMibConfigGetReqSend(0); |
| |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| /* store the reply */ |
| if (mibConfig != NULL) |
| memcpy((unsigned char*)mibConfig, |
| (unsigned char*)&priv->sme_reply.mibConfig, |
| sizeof(CsrWifiSmeMibConfig)); |
| |
| unifi_trace(priv, UDBG4, |
| "sme_mgt_mib_config_get: unifi_mgt_mib_config_get_req <-- (r=%d status=%d)\n", |
| r, priv->sme_reply.reply_status); |
| |
| return convert_sme_error(priv->sme_reply.reply_status); |
| #else |
| CsrResult status; |
| CsrWifiSmeMgtClaimSyncAccess(priv->smepriv); |
| status = CsrWifiSmeMgtMibConfigGetReq(priv->smepriv, mibConfig); |
| CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv); |
| return convert_sme_error(status); |
| #endif |
| } |
| |
| int sme_mgt_connection_info_get(unifi_priv_t *priv, CsrWifiSmeConnectionInfo *connectionInfo) |
| { |
| #ifdef CSR_SME_USERSPACE |
| int r; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_connection_info_get: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| unifi_trace(priv, UDBG4, "sme_mgt_connection_info_get: unifi_mgt_connection_info_get_req -->\n"); |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiSmeConnectionInfoGetReqSend(0, CSR_WIFI_INTERFACE_IN_USE); |
| |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| /* store the reply */ |
| if (connectionInfo != NULL) |
| memcpy((unsigned char*)connectionInfo, |
| (unsigned char*)&priv->sme_reply.connectionInfo, |
| sizeof(CsrWifiSmeConnectionInfo)); |
| |
| unifi_trace(priv, UDBG4, |
| "sme_mgt_connection_info_get: unifi_mgt_connection_info_get_req <-- (r=%d status=%d)\n", |
| r, priv->sme_reply.reply_status); |
| |
| return convert_sme_error(priv->sme_reply.reply_status); |
| #else |
| CsrResult status; |
| CsrWifiSmeMgtClaimSyncAccess(priv->smepriv); |
| status = CsrWifiSmeMgtConnectionInfoGetReq(priv->smepriv, connectionInfo); |
| CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv); |
| return convert_sme_error(status); |
| #endif |
| } |
| |
| int sme_mgt_connection_config_get(unifi_priv_t *priv, CsrWifiSmeConnectionConfig *connectionConfig) |
| { |
| #ifdef CSR_SME_USERSPACE |
| int r; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_connection_config_get: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| unifi_trace(priv, UDBG4, "sme_mgt_connection_config_get: unifi_mgt_connection_config_get_req -->\n"); |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiSmeConnectionConfigGetReqSend(0, CSR_WIFI_INTERFACE_IN_USE); |
| |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| /* store the reply */ |
| if (connectionConfig != NULL) |
| memcpy((unsigned char*)connectionConfig, |
| (unsigned char*)&priv->sme_reply.connectionConfig, |
| sizeof(CsrWifiSmeConnectionConfig)); |
| |
| unifi_trace(priv, UDBG4, |
| "sme_mgt_connection_config_get: unifi_mgt_connection_config_get_req <-- (r=%d status=%d)\n", |
| r, priv->sme_reply.reply_status); |
| |
| return convert_sme_error(priv->sme_reply.reply_status); |
| #else |
| CsrResult status; |
| CsrWifiSmeMgtClaimSyncAccess(priv->smepriv); |
| status = CsrWifiSmeMgtConnectionConfigGetReq(priv->smepriv, connectionConfig); |
| CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv); |
| return convert_sme_error(status); |
| #endif |
| } |
| |
| int sme_mgt_connection_stats_get(unifi_priv_t *priv, CsrWifiSmeConnectionStats *connectionStats) |
| { |
| #ifdef CSR_SME_USERSPACE |
| int r; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_connection_stats_get: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| unifi_trace(priv, UDBG4, "sme_mgt_connection_stats_get: unifi_mgt_connection_stats_get_req -->\n"); |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiSmeConnectionStatsGetReqSend(0, CSR_WIFI_INTERFACE_IN_USE); |
| |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| /* store the reply */ |
| if (connectionStats != NULL) |
| memcpy((unsigned char*)connectionStats, |
| (unsigned char*)&priv->sme_reply.connectionStats, |
| sizeof(CsrWifiSmeConnectionStats)); |
| |
| unifi_trace(priv, UDBG4, |
| "sme_mgt_connection_stats_get: unifi_mgt_connection_stats_get_req <-- (r=%d status=%d)\n", |
| r, priv->sme_reply.reply_status); |
| |
| return convert_sme_error(priv->sme_reply.reply_status); |
| #else |
| CsrResult status; |
| CsrWifiSmeMgtClaimSyncAccess(priv->smepriv); |
| status = CsrWifiSmeMgtConnectionStatsGetReq(priv->smepriv, connectionStats); |
| CsrWifiSmeMgtReleaseSyncAccess(priv->smepriv); |
| return convert_sme_error(status); |
| #endif |
| } |
| |
| #endif /* CSR_SUPPORT_WEXT */ |
| |
| int sme_mgt_packet_filter_set(unifi_priv_t *priv) |
| { |
| CsrWifiIp4Address ipAddress = {{0xFF, 0xFF, 0xFF, 0xFF }}; |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_packet_filter_set: invalid smepriv\n"); |
| return -EIO; |
| } |
| if (priv->packet_filters.arp_filter) { |
| ipAddress.a[0] = (priv->sta_ip_address ) & 0xFF; |
| ipAddress.a[1] = (priv->sta_ip_address >> 8) & 0xFF; |
| ipAddress.a[2] = (priv->sta_ip_address >> 16) & 0xFF; |
| ipAddress.a[3] = (priv->sta_ip_address >> 24) & 0xFF; |
| } |
| |
| unifi_trace(priv, UDBG5, |
| "sme_mgt_packet_filter_set: IP address %d.%d.%d.%d\n", |
| ipAddress.a[0], ipAddress.a[1], |
| ipAddress.a[2], ipAddress.a[3]); |
| |
| /* Doesn't block for a confirm */ |
| CsrWifiSmePacketFilterSetReqSend(0, CSR_WIFI_INTERFACE_IN_USE, |
| priv->packet_filters.tclas_ies_length, |
| priv->filter_tclas_ies, |
| priv->packet_filters.filter_mode, |
| ipAddress); |
| return 0; |
| } |
| |
| int sme_mgt_tspec(unifi_priv_t *priv, CsrWifiSmeListAction action, |
| u32 tid, CsrWifiSmeDataBlock *tspec, CsrWifiSmeDataBlock *tclas) |
| { |
| int r; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_mgt_tspec: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiSmeTspecReqSend(0, CSR_WIFI_INTERFACE_IN_USE, |
| action, tid, TRUE, 0, |
| tspec->length, tspec->data, |
| tclas->length, tclas->data); |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| unifi_trace(priv, UDBG4, "sme_mgt_tspec: <-- (status=%d)\n", priv->sme_reply.reply_status); |
| return convert_sme_error(priv->sme_reply.reply_status); |
| } |
| |
| |
| |
| int sme_sys_suspend(unifi_priv_t *priv) |
| { |
| int r; |
| CsrResult csrResult; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_sys_suspend: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| /* Suspend the SME, which MAY cause it to power down UniFi */ |
| CsrWifiRouterCtrlSuspendIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, 0, 0, priv->wol_suspend); |
| r = sme_wait_for_reply(priv, UNIFI_SME_SYS_LONG_TIMEOUT); |
| if (r) { |
| /* No reply - forcibly power down in case the request wasn't processed */ |
| unifi_notice(priv, |
| "suspend: SME did not reply %s, ", |
| (priv->ptest_mode | priv->wol_suspend) ? "leave powered" : "power off UniFi anyway\n"); |
| |
| /* Leave power on for production test, though */ |
| if (!priv->ptest_mode) { |
| /* Put UniFi to deep sleep, in case we can not power it off */ |
| CsrSdioClaim(priv->sdio); |
| unifi_trace(priv, UDBG1, "Force deep sleep"); |
| csrResult = unifi_force_low_power_mode(priv->card); |
| |
| /* For WOL, the UniFi must stay powered */ |
| if (!priv->wol_suspend) { |
| unifi_trace(priv, UDBG1, "Power off\n"); |
| CsrSdioPowerOff(priv->sdio); |
| } |
| CsrSdioRelease(priv->sdio); |
| } |
| } |
| |
| if (priv->wol_suspend) { |
| unifi_trace(priv, UDBG1, "UniFi left powered for WOL\n"); |
| |
| /* Remove the IRQ, which also disables the card SDIO interrupt. |
| * Disabling the card SDIO interrupt enables the PIO WOL source. |
| * Removal of the of the handler ensures that in both SDIO and PIO cases |
| * the card interrupt only wakes the host. The card will be polled |
| * after resume to handle any pending data. |
| */ |
| if (csr_sdio_linux_remove_irq(priv->sdio)) { |
| unifi_notice(priv, "WOL csr_sdio_linux_remove_irq failed\n"); |
| } |
| |
| if (enable_wol == UNIFI_WOL_SDIO) { |
| /* Because csr_sdio_linux_remove_irq() disabled the card SDIO interrupt, |
| * it must be left enabled to wake-on-SDIO. |
| */ |
| unifi_trace(priv, UDBG1, "Enable card SDIO interrupt for SDIO WOL\n"); |
| |
| CsrSdioClaim(priv->sdio); |
| csrResult = CsrSdioInterruptEnable(priv->sdio); |
| CsrSdioRelease(priv->sdio); |
| |
| if (csrResult != CSR_RESULT_SUCCESS) { |
| unifi_error(priv, "WOL CsrSdioInterruptEnable failed %d\n", csrResult); |
| } |
| } else { |
| unifi_trace(priv, UDBG1, "Disabled card SDIO interrupt for PIO WOL\n"); |
| } |
| |
| /* Prevent the BH thread from running during the suspend. |
| * Upon resume, sme_sys_resume() will trigger a wifi-on, this will cause |
| * the BH thread to be re-enabled and reinstall the ISR. |
| */ |
| priv->bh_thread.block_thread = 1; |
| |
| unifi_trace(priv, UDBG1, "unifi_suspend: suspended BH"); |
| } |
| |
| /* Consider UniFi to be uninitialised */ |
| priv->init_progress = UNIFI_INIT_NONE; |
| |
| unifi_trace(priv, UDBG1, "sme_sys_suspend: <-- (r=%d status=%d)\n", r, priv->sme_reply.reply_status); |
| return convert_sme_error(priv->sme_reply.reply_status); |
| } |
| |
| |
| int sme_sys_resume(unifi_priv_t *priv) |
| { |
| int r; |
| |
| unifi_trace(priv, UDBG1, "sme_sys_resume %s\n", priv->wol_suspend ? "warm" : ""); |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_sys_resume: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiRouterCtrlResumeIndSend(priv->CSR_WIFI_SME_IFACEQUEUE, 0, priv->wol_suspend); |
| |
| r = sme_wait_for_reply(priv, UNIFI_SME_SYS_LONG_TIMEOUT); |
| if (r) |
| unifi_notice(priv, |
| "resume: SME did not reply, return success anyway\n"); |
| |
| return 0; |
| } |
| |
| #ifdef CSR_SUPPORT_WEXT_AP |
| int sme_ap_stop(unifi_priv_t *priv, u16 interface_tag) |
| { |
| int r; |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_ap_stop: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiNmeApStopReqSend(0, interface_tag); |
| |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| unifi_trace(priv, UDBG4, |
| "sme_ap_stop <-- (r=%d status=%d)\n", |
| r, priv->sme_reply.reply_status); |
| return convert_sme_error(priv->sme_reply.reply_status); |
| |
| } |
| |
| int sme_ap_start(unifi_priv_t *priv, u16 interface_tag, |
| CsrWifiSmeApConfig_t * ap_config) |
| { |
| int r; |
| CsrWifiSmeApP2pGoConfig p2p_go_param; |
| memset(&p2p_go_param, 0, sizeof(CsrWifiSmeApP2pGoConfig)); |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_ap_start: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiNmeApStartReqSend(0, interface_tag, CSR_WIFI_AP_TYPE_LEGACY, FALSE, |
| ap_config->ssid, 1, ap_config->channel, |
| ap_config->credentials, ap_config->max_connections, |
| p2p_go_param, FALSE); |
| |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| unifi_trace(priv, UDBG4, |
| "sme_ap_start <-- (r=%d status=%d)\n", |
| r, priv->sme_reply.reply_status); |
| return convert_sme_error(priv->sme_reply.reply_status); |
| } |
| |
| int sme_ap_config(unifi_priv_t *priv, |
| CsrWifiSmeApMacConfig *ap_mac_config, |
| CsrWifiNmeApConfig *group_security_config) |
| { |
| int r; |
| CsrWifiSmeApP2pGoConfig p2p_go_param; |
| memset(&p2p_go_param, 0, sizeof(CsrWifiSmeApP2pGoConfig)); |
| |
| if (priv->smepriv == NULL) { |
| unifi_error(priv, "sme_ap_config: invalid smepriv\n"); |
| return -EIO; |
| } |
| |
| r = sme_init_request(priv); |
| if (r) |
| return -EIO; |
| |
| CsrWifiNmeApConfigSetReqSend(0, *group_security_config, |
| *ap_mac_config); |
| |
| r = sme_wait_for_reply(priv, UNIFI_SME_MGT_SHORT_TIMEOUT); |
| if (r) |
| return r; |
| |
| unifi_trace(priv, UDBG4, |
| "sme_ap_config <-- (r=%d status=%d)\n", |
| r, priv->sme_reply.reply_status); |
| return convert_sme_error(priv->sme_reply.reply_status); |
| } |
| #endif |