C++程序  |  309行  |  10.1 KB

/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of The Linux Foundation nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "sync.h"

#define LOG_TAG  "WifiHAL"

#include <utils/Log.h>

#include "wifi_hal.h"
#include "common.h"
#include "cpp_bindings.h"
#include "rssi_monitor.h"
#include "qca-vendor.h"
#include "vendor_definitions.h"

//Singleton Static Instance
RSSIMonitorCommand* RSSIMonitorCommand::mRSSIMonitorCommandInstance = NULL;

RSSIMonitorCommand::RSSIMonitorCommand(wifi_handle handle, int id,
                                       u32 vendor_id, u32 subcmd)
        : WifiVendorCommand(handle, id, vendor_id, subcmd)
{
    mRSSIMonitorCommandInstance = NULL;
    memset(&mHandler, 0, sizeof(mHandler));
}

RSSIMonitorCommand::~RSSIMonitorCommand()
{
    mRSSIMonitorCommandInstance = NULL;
}

void RSSIMonitorCommand::setReqId(wifi_request_id reqid)
{
    mId = reqid;
}

RSSIMonitorCommand* RSSIMonitorCommand::instance(wifi_handle handle,
                                                 wifi_request_id id)
{
    if (handle == NULL) {
        ALOGE("Interface Handle is invalid");
        return NULL;
    }
    if (mRSSIMonitorCommandInstance == NULL) {
        mRSSIMonitorCommandInstance = new RSSIMonitorCommand(handle, id,
                OUI_QCA,
                QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI);
        return mRSSIMonitorCommandInstance;
    }
    else
    {
        if (handle != getWifiHandle(mRSSIMonitorCommandInstance->mInfo))
        {
            /* upper layer must have cleaned up the handle and reinitialized,
               so we need to update the same */
            ALOGI("Handle different, update the handle");
            mRSSIMonitorCommandInstance->mInfo = (hal_info *)handle;
        }
        mRSSIMonitorCommandInstance->setReqId(id);
    }
    return mRSSIMonitorCommandInstance;
}

/* This function will be the main handler for incoming event.
 * Call the appropriate callback handler after parsing the vendor data.
 */
int RSSIMonitorCommand::handleEvent(WifiEvent &event)
{
    int ret = WIFI_SUCCESS;
    WifiVendorCommand::handleEvent(event);

    /* Parse the vendordata and get the attribute */
    switch(mSubcmd)
    {
        case QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI:
        {
            mac_addr addr;
            s8 rssi;
            wifi_request_id reqId;
            struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX
                                     + 1];
            nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX,
                    (struct nlattr *)mVendorData,
                    mDataLen, NULL);

            memset(addr, 0, sizeof(mac_addr));

            ALOGI("QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI Received");

            if (!tb_vendor[
                QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID])
            {
                ALOGE("%s: ATTR_RSSI_MONITORING_REQUEST_ID not found. Exit.",
                    __FUNCTION__);
                ret = WIFI_ERROR_INVALID_ARGS;
                break;
            }
            reqId = nla_get_u32(
                    tb_vendor[QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID]
                    );
            /* If event has a different request_id, ignore that and use the
             *  request_id value which we're maintaining.
             */
            if (reqId != id()) {
                ALOGD("%s: Event has Req. ID:%d <> Ours:%d, continue...",
                    __FUNCTION__, reqId, id());
                reqId = id();
            }
            ret = get_mac_addr(tb_vendor,
                    QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_BSSID,
                    addr);
            if (ret != WIFI_SUCCESS) {
                return ret;
            }
            ALOGI(MAC_ADDR_STR, MAC_ADDR_ARRAY(addr));

            if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI])
            {
                ALOGE("%s: QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI"
                      " not found", __FUNCTION__);
                return WIFI_ERROR_INVALID_ARGS;
            }
            rssi = get_s8(tb_vendor[
                        QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI]);
            ALOGI("Current RSSI : %d ", rssi);

            if (mHandler.on_rssi_threshold_breached)
                (*mHandler.on_rssi_threshold_breached)(reqId, addr, rssi);
            else
                ALOGE("RSSI Monitoring: No Callback registered: ");
        }
        break;

        default:
            /* Error case should not happen print log */
            ALOGE("%s: Wrong subcmd received %d", __FUNCTION__, mSubcmd);
    }

    return NL_SKIP;
}

int RSSIMonitorCommand::setCallbackHandler(wifi_rssi_event_handler nHandler,
                                           u32 event)
{
    int ret;
    mHandler = nHandler;
    ret = registerVendorHandler(mVendor_id, event);
    if (ret != 0) {
        /* Error case should not happen print log */
        ALOGE("%s: Unable to register Vendor Handler Vendor Id=0x%x subcmd=%u",
              __FUNCTION__, mVendor_id, mSubcmd);
    }
    return ret;
}

wifi_error RSSIMonitorCommand::unregisterHandler(u32 subCmd)
{
    unregisterVendorHandler(mVendor_id, subCmd);
    return WIFI_SUCCESS;
}

wifi_error wifi_start_rssi_monitoring(wifi_request_id id,
                                      wifi_interface_handle iface,
                                      s8 max_rssi,
                                      s8 min_rssi,
                                      wifi_rssi_event_handler eh)
{
    int ret = WIFI_SUCCESS;
    struct nlattr *nlData;
    WifiVendorCommand *vCommand = NULL;
    wifi_handle wifiHandle = getWifiHandle(iface);
    RSSIMonitorCommand *rssiCommand;

    ret = initialize_vendor_cmd(iface, id,
                                QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI,
                                &vCommand);
    if (ret != WIFI_SUCCESS) {
        ALOGE("%s: Initialization failed", __FUNCTION__);
        return (wifi_error)ret;
    }

    ALOGI("%s: Max RSSI:%d Min RSSI:%d", __FUNCTION__,
          max_rssi, min_rssi);
    /* Add the vendor specific attributes for the NL command. */
    nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
    if (!nlData)
        goto cleanup;

    if (vCommand->put_u32(
            QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL,
            QCA_WLAN_RSSI_MONITORING_START) ||
        vCommand->put_u32(
            QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID,
            id) ||
        vCommand->put_s8(
            QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX_RSSI,
            max_rssi) ||
        vCommand->put_s8(
            QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MIN_RSSI,
            min_rssi))
    {
        goto cleanup;
    }

    vCommand->attr_end(nlData);

    rssiCommand = RSSIMonitorCommand::instance(wifiHandle, id);
    if (rssiCommand == NULL) {
        ALOGE("%s: Error rssiCommand NULL", __FUNCTION__);
        return WIFI_ERROR_OUT_OF_MEMORY;
    }

    ret = rssiCommand->setCallbackHandler(eh,
            QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI);
    if (ret < 0)
        goto cleanup;

    ret = vCommand->requestResponse();
    if (ret < 0)
        goto cleanup;

cleanup:
    delete vCommand;
    return (wifi_error)ret;
}

wifi_error wifi_stop_rssi_monitoring(wifi_request_id id,
                                     wifi_interface_handle iface)
{
    int ret = WIFI_SUCCESS;
    struct nlattr *nlData;
    WifiVendorCommand *vCommand = NULL;
    wifi_handle wifiHandle = getWifiHandle(iface);
    RSSIMonitorCommand *rssiCommand;

    ret = initialize_vendor_cmd(iface, id,
                                QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI,
                                &vCommand);
    if (ret != WIFI_SUCCESS) {
        ALOGE("%s: Initialization failed", __FUNCTION__);
        return (wifi_error)ret;
    }

    /* Add the vendor specific attributes for the NL command. */
    nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
    if (!nlData)
        goto cleanup;

    if (vCommand->put_u32(
            QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL,
            QCA_WLAN_RSSI_MONITORING_STOP) ||
        vCommand->put_u32(
            QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID,
            id))
    {
        goto cleanup;
    }

    vCommand->attr_end(nlData);

    ret = vCommand->requestResponse();
    if (ret < 0)
        goto cleanup;

    rssiCommand = RSSIMonitorCommand::instance(wifiHandle, id);
    if (rssiCommand == NULL) {
        ALOGE("%s: Error rssiCommand NULL", __FUNCTION__);
        ret = WIFI_ERROR_OUT_OF_MEMORY;
        goto cleanup;
    }

    ret = rssiCommand->unregisterHandler(
                                        QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI);
    if (ret != WIFI_SUCCESS)
        goto cleanup;

    delete rssiCommand;

cleanup:
    delete vCommand;
    return (wifi_error)ret;
}