/*
 * ---------------------------------------------------------------------------
 * 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