C++程序  |  371行  |  12.06 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 "vendor_definitions.h"

/* Used to handle rssi command events from driver/firmware.*/
typedef struct rssi_monitor_event_handler_s {
    RSSIMonitorCommand* mRSSIMonitorCommandInstance;
} rssi_monitor_event_handlers;

wifi_error initializeRSSIMonitorHandler(hal_info *info)
{
    info->rssi_handlers = (rssi_monitor_event_handlers *)malloc(sizeof(
                              rssi_monitor_event_handlers));
    if (info->rssi_handlers) {
        memset(info->rssi_handlers, 0, sizeof(rssi_monitor_event_handlers));
    }
    else {
        ALOGE("%s: Allocation of RSSI event handlers failed",
              __FUNCTION__);
        return WIFI_ERROR_OUT_OF_MEMORY;
    }
    return WIFI_SUCCESS;
}

wifi_error cleanupRSSIMonitorHandler(hal_info *info)
{
    rssi_monitor_event_handlers* event_handlers;
    if (info && info->rssi_handlers) {
        event_handlers = (rssi_monitor_event_handlers*) info->rssi_handlers;
        if (event_handlers->mRSSIMonitorCommandInstance) {
            delete event_handlers->mRSSIMonitorCommandInstance;
        }
        memset(event_handlers, 0, sizeof(rssi_monitor_event_handlers));
        return WIFI_SUCCESS;
    }
    ALOGE ("%s: info or info->rssi_handlers NULL", __FUNCTION__);
    return WIFI_ERROR_UNKNOWN;
}

void RSSIMonitorCommand::enableEventHandling()
{
    pthread_mutex_lock(&rm_lock);
    mEventHandlingEnabled = true;
    pthread_mutex_unlock(&rm_lock);
}

void RSSIMonitorCommand::disableEventHandling()
{
    pthread_mutex_lock(&rm_lock);
    mEventHandlingEnabled = false;
    pthread_mutex_unlock(&rm_lock);
}

bool RSSIMonitorCommand::isEventHandlingEnabled()
{
    bool eventHandlingEnabled;
    pthread_mutex_lock(&rm_lock);
    eventHandlingEnabled = mEventHandlingEnabled;
    pthread_mutex_unlock(&rm_lock);

    return eventHandlingEnabled;
}

void RSSIMonitorCommand::setCallbackHandler(wifi_rssi_event_handler handler)
{
    mHandler = handler;
}

RSSIMonitorCommand::RSSIMonitorCommand(wifi_handle handle, int id,
                                       u32 vendor_id, u32 subcmd)
        : WifiVendorCommand(handle, id, vendor_id, subcmd)
{
    memset(&mHandler, 0, sizeof(mHandler));
    if (registerVendorHandler(vendor_id, subcmd)) {
        /* Error case should not happen print log */
        ALOGE("%s: Unable to register Vendor Handler Vendor Id=0x%x subcmd=%u",
              __FUNCTION__, vendor_id, subcmd);
    }
    pthread_mutex_init(&rm_lock, NULL);
    disableEventHandling();
}

RSSIMonitorCommand::~RSSIMonitorCommand()
{
    unregisterVendorHandler(mVendor_id, mSubcmd);
    pthread_mutex_destroy(&rm_lock);
}

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;
    }
    hal_info *info = getHalInfo(handle);
    if (!info || !info->rssi_handlers) {
        ALOGE("rssi_handlers is invalid");
        return NULL;
    }

    RSSIMonitorCommand* mRSSIMonitorCommandInstance =
        info->rssi_handlers->mRSSIMonitorCommandInstance;

    if (mRSSIMonitorCommandInstance == NULL) {
        mRSSIMonitorCommandInstance = new RSSIMonitorCommand(handle, id,
                OUI_QCA,
                QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI);
        info->rssi_handlers->mRSSIMonitorCommandInstance = mRSSIMonitorCommandInstance;
        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 */
            ALOGV("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;

    if (isEventHandlingEnabled() == false) {
        ALOGE("%s: RSSI monitor isn't running or already stopped. "
              "Nothing to do. Exit", __FUNCTION__);
        return ret;
    }

    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));

            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()) {
                ALOGV("%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;
            }
            ALOGV(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]);
            ALOGV("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 ret;
}

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;
    }

    ALOGV("%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;
    }

    rssiCommand->setCallbackHandler(eh);

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

    rssiCommand->enableEventHandling();

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;
    rssi_monitor_event_handlers* event_handlers;
    hal_info *info = getHalInfo(wifiHandle);

    event_handlers = (rssi_monitor_event_handlers*)info->rssi_handlers;
    rssiCommand = event_handlers->mRSSIMonitorCommandInstance;

    if (rssiCommand == NULL ||
        rssiCommand->isEventHandlingEnabled() == false) {
        ALOGE("%s: RSSI monitor isn't running or already stopped. "
            "Nothing to do. Exit", __FUNCTION__);
        return WIFI_ERROR_NOT_AVAILABLE;
    }

    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->disableEventHandling();


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