Home | History | Annotate | Download | only in wifi_hal
      1 /* Copyright (c) 2015, The Linux Foundation. All rights reserved.
      2  *
      3  * Redistribution and use in source and binary forms, with or without
      4  * modification, are permitted provided that the following conditions
      5  * are met:
      6  *  * Redistributions of source code must retain the above copyright
      7  *    notice, this list of conditions and the following disclaimer.
      8  *  * Redistributions in binary form must reproduce the above copyright
      9  *    notice, this list of conditions and the following disclaimer in
     10  *    the documentation and/or other materials provided with the
     11  *    distribution.
     12  *  * Neither the name of The Linux Foundation nor the names of its
     13  *    contributors may be used to endorse or promote products derived
     14  *    from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
     19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     23  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     25  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     26  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include "sync.h"
     30 
     31 #define LOG_TAG  "WifiHAL"
     32 
     33 #include <utils/Log.h>
     34 
     35 #include "wifi_hal.h"
     36 #include "common.h"
     37 #include "cpp_bindings.h"
     38 #include "rssi_monitor.h"
     39 #include "vendor_definitions.h"
     40 
     41 /* Used to handle rssi command events from driver/firmware.*/
     42 typedef struct rssi_monitor_event_handler_s {
     43     RSSIMonitorCommand* mRSSIMonitorCommandInstance;
     44 } rssi_monitor_event_handlers;
     45 
     46 wifi_error initializeRSSIMonitorHandler(hal_info *info)
     47 {
     48     info->rssi_handlers = (rssi_monitor_event_handlers *)malloc(sizeof(
     49                               rssi_monitor_event_handlers));
     50     if (info->rssi_handlers) {
     51         memset(info->rssi_handlers, 0, sizeof(rssi_monitor_event_handlers));
     52     }
     53     else {
     54         ALOGE("%s: Allocation of RSSI event handlers failed",
     55               __FUNCTION__);
     56         return WIFI_ERROR_OUT_OF_MEMORY;
     57     }
     58     return WIFI_SUCCESS;
     59 }
     60 
     61 wifi_error cleanupRSSIMonitorHandler(hal_info *info)
     62 {
     63     rssi_monitor_event_handlers* event_handlers;
     64     if (info && info->rssi_handlers) {
     65         event_handlers = (rssi_monitor_event_handlers*) info->rssi_handlers;
     66         if (event_handlers->mRSSIMonitorCommandInstance) {
     67             delete event_handlers->mRSSIMonitorCommandInstance;
     68         }
     69         memset(event_handlers, 0, sizeof(rssi_monitor_event_handlers));
     70         return WIFI_SUCCESS;
     71     }
     72     ALOGE ("%s: info or info->rssi_handlers NULL", __FUNCTION__);
     73     return WIFI_ERROR_UNKNOWN;
     74 }
     75 
     76 void RSSIMonitorCommand::enableEventHandling()
     77 {
     78     pthread_mutex_lock(&rm_lock);
     79     mEventHandlingEnabled = true;
     80     pthread_mutex_unlock(&rm_lock);
     81 }
     82 
     83 void RSSIMonitorCommand::disableEventHandling()
     84 {
     85     pthread_mutex_lock(&rm_lock);
     86     mEventHandlingEnabled = false;
     87     pthread_mutex_unlock(&rm_lock);
     88 }
     89 
     90 bool RSSIMonitorCommand::isEventHandlingEnabled()
     91 {
     92     bool eventHandlingEnabled;
     93     pthread_mutex_lock(&rm_lock);
     94     eventHandlingEnabled = mEventHandlingEnabled;
     95     pthread_mutex_unlock(&rm_lock);
     96 
     97     return eventHandlingEnabled;
     98 }
     99 
    100 void RSSIMonitorCommand::setCallbackHandler(wifi_rssi_event_handler handler)
    101 {
    102     mHandler = handler;
    103 }
    104 
    105 RSSIMonitorCommand::RSSIMonitorCommand(wifi_handle handle, int id,
    106                                        u32 vendor_id, u32 subcmd)
    107         : WifiVendorCommand(handle, id, vendor_id, subcmd)
    108 {
    109     memset(&mHandler, 0, sizeof(mHandler));
    110     if (registerVendorHandler(vendor_id, subcmd)) {
    111         /* Error case should not happen print log */
    112         ALOGE("%s: Unable to register Vendor Handler Vendor Id=0x%x subcmd=%u",
    113               __FUNCTION__, vendor_id, subcmd);
    114     }
    115     pthread_mutex_init(&rm_lock, NULL);
    116     disableEventHandling();
    117 }
    118 
    119 RSSIMonitorCommand::~RSSIMonitorCommand()
    120 {
    121     unregisterVendorHandler(mVendor_id, mSubcmd);
    122     pthread_mutex_destroy(&rm_lock);
    123 }
    124 
    125 void RSSIMonitorCommand::setReqId(wifi_request_id reqid)
    126 {
    127     mId = reqid;
    128 }
    129 
    130 RSSIMonitorCommand* RSSIMonitorCommand::instance(wifi_handle handle,
    131                                                  wifi_request_id id)
    132 {
    133     if (handle == NULL) {
    134         ALOGE("Interface Handle is invalid");
    135         return NULL;
    136     }
    137     hal_info *info = getHalInfo(handle);
    138     if (!info || !info->rssi_handlers) {
    139         ALOGE("rssi_handlers is invalid");
    140         return NULL;
    141     }
    142 
    143     RSSIMonitorCommand* mRSSIMonitorCommandInstance =
    144         info->rssi_handlers->mRSSIMonitorCommandInstance;
    145 
    146     if (mRSSIMonitorCommandInstance == NULL) {
    147         mRSSIMonitorCommandInstance = new RSSIMonitorCommand(handle, id,
    148                 OUI_QCA,
    149                 QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI);
    150         info->rssi_handlers->mRSSIMonitorCommandInstance = mRSSIMonitorCommandInstance;
    151         return mRSSIMonitorCommandInstance;
    152     }
    153     else
    154     {
    155         if (handle != getWifiHandle(mRSSIMonitorCommandInstance->mInfo))
    156         {
    157             /* upper layer must have cleaned up the handle and reinitialized,
    158                so we need to update the same */
    159             ALOGV("Handle different, update the handle");
    160             mRSSIMonitorCommandInstance->mInfo = (hal_info *)handle;
    161         }
    162         mRSSIMonitorCommandInstance->setReqId(id);
    163     }
    164     return mRSSIMonitorCommandInstance;
    165 }
    166 
    167 /* This function will be the main handler for incoming event.
    168  * Call the appropriate callback handler after parsing the vendor data.
    169  */
    170 int RSSIMonitorCommand::handleEvent(WifiEvent &event)
    171 {
    172     int ret = WIFI_SUCCESS;
    173 
    174     if (isEventHandlingEnabled() == false) {
    175         ALOGE("%s: RSSI monitor isn't running or already stopped. "
    176               "Nothing to do. Exit", __FUNCTION__);
    177         return ret;
    178     }
    179 
    180     WifiVendorCommand::handleEvent(event);
    181 
    182     /* Parse the vendordata and get the attribute */
    183     switch(mSubcmd)
    184     {
    185         case QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI:
    186         {
    187             mac_addr addr;
    188             s8 rssi;
    189             wifi_request_id reqId;
    190             struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX
    191                                      + 1];
    192             nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX,
    193                     (struct nlattr *)mVendorData,
    194                     mDataLen, NULL);
    195 
    196             memset(addr, 0, sizeof(mac_addr));
    197 
    198             if (!tb_vendor[
    199                 QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID])
    200             {
    201                 ALOGE("%s: ATTR_RSSI_MONITORING_REQUEST_ID not found. Exit.",
    202                     __FUNCTION__);
    203                 ret = WIFI_ERROR_INVALID_ARGS;
    204                 break;
    205             }
    206             reqId = nla_get_u32(
    207                     tb_vendor[QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID]
    208                     );
    209             /* If event has a different request_id, ignore that and use the
    210              *  request_id value which we're maintaining.
    211              */
    212             if (reqId != id()) {
    213                 ALOGV("%s: Event has Req. ID:%d <> Ours:%d, continue...",
    214                     __FUNCTION__, reqId, id());
    215                 reqId = id();
    216             }
    217             ret = get_mac_addr(tb_vendor,
    218                     QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_BSSID,
    219                     addr);
    220             if (ret != WIFI_SUCCESS) {
    221                 return ret;
    222             }
    223             ALOGV(MAC_ADDR_STR, MAC_ADDR_ARRAY(addr));
    224 
    225             if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI])
    226             {
    227                 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI"
    228                       " not found", __FUNCTION__);
    229                 return WIFI_ERROR_INVALID_ARGS;
    230             }
    231             rssi = get_s8(tb_vendor[
    232                         QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI]);
    233             ALOGV("Current RSSI : %d ", rssi);
    234 
    235             if (mHandler.on_rssi_threshold_breached)
    236                 (*mHandler.on_rssi_threshold_breached)(reqId, addr, rssi);
    237             else
    238                 ALOGE("RSSI Monitoring: No Callback registered: ");
    239         }
    240         break;
    241 
    242         default:
    243             /* Error case should not happen print log */
    244             ALOGE("%s: Wrong subcmd received %d", __FUNCTION__, mSubcmd);
    245     }
    246 
    247     return ret;
    248 }
    249 
    250 wifi_error wifi_start_rssi_monitoring(wifi_request_id id,
    251                                       wifi_interface_handle iface,
    252                                       s8 max_rssi,
    253                                       s8 min_rssi,
    254                                       wifi_rssi_event_handler eh)
    255 {
    256     int ret = WIFI_SUCCESS;
    257     struct nlattr *nlData;
    258     WifiVendorCommand *vCommand = NULL;
    259     wifi_handle wifiHandle = getWifiHandle(iface);
    260     RSSIMonitorCommand *rssiCommand;
    261 
    262     ret = initialize_vendor_cmd(iface, id,
    263                                 QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI,
    264                                 &vCommand);
    265     if (ret != WIFI_SUCCESS) {
    266         ALOGE("%s: Initialization failed", __FUNCTION__);
    267         return (wifi_error)ret;
    268     }
    269 
    270     ALOGV("%s: Max RSSI:%d Min RSSI:%d", __FUNCTION__,
    271           max_rssi, min_rssi);
    272     /* Add the vendor specific attributes for the NL command. */
    273     nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
    274     if (!nlData)
    275         goto cleanup;
    276 
    277     if (vCommand->put_u32(
    278             QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL,
    279             QCA_WLAN_RSSI_MONITORING_START) ||
    280         vCommand->put_u32(
    281             QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID,
    282             id) ||
    283         vCommand->put_s8(
    284             QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX_RSSI,
    285             max_rssi) ||
    286         vCommand->put_s8(
    287             QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MIN_RSSI,
    288             min_rssi))
    289     {
    290         goto cleanup;
    291     }
    292 
    293     vCommand->attr_end(nlData);
    294 
    295     rssiCommand = RSSIMonitorCommand::instance(wifiHandle, id);
    296     if (rssiCommand == NULL) {
    297         ALOGE("%s: Error rssiCommand NULL", __FUNCTION__);
    298         return WIFI_ERROR_OUT_OF_MEMORY;
    299     }
    300 
    301     rssiCommand->setCallbackHandler(eh);
    302 
    303     ret = vCommand->requestResponse();
    304     if (ret < 0)
    305         goto cleanup;
    306 
    307     rssiCommand->enableEventHandling();
    308 
    309 cleanup:
    310     delete vCommand;
    311     return (wifi_error)ret;
    312 }
    313 
    314 wifi_error wifi_stop_rssi_monitoring(wifi_request_id id,
    315                                      wifi_interface_handle iface)
    316 {
    317     int ret = WIFI_SUCCESS;
    318     struct nlattr *nlData;
    319     WifiVendorCommand *vCommand = NULL;
    320     wifi_handle wifiHandle = getWifiHandle(iface);
    321     RSSIMonitorCommand *rssiCommand;
    322     rssi_monitor_event_handlers* event_handlers;
    323     hal_info *info = getHalInfo(wifiHandle);
    324 
    325     event_handlers = (rssi_monitor_event_handlers*)info->rssi_handlers;
    326     rssiCommand = event_handlers->mRSSIMonitorCommandInstance;
    327 
    328     if (rssiCommand == NULL ||
    329         rssiCommand->isEventHandlingEnabled() == false) {
    330         ALOGE("%s: RSSI monitor isn't running or already stopped. "
    331             "Nothing to do. Exit", __FUNCTION__);
    332         return WIFI_ERROR_NOT_AVAILABLE;
    333     }
    334 
    335     ret = initialize_vendor_cmd(iface, id,
    336                                 QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI,
    337                                 &vCommand);
    338     if (ret != WIFI_SUCCESS) {
    339         ALOGE("%s: Initialization failed", __FUNCTION__);
    340         return (wifi_error)ret;
    341     }
    342 
    343     /* Add the vendor specific attributes for the NL command. */
    344     nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
    345     if (!nlData)
    346         goto cleanup;
    347 
    348     if (vCommand->put_u32(
    349             QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL,
    350             QCA_WLAN_RSSI_MONITORING_STOP) ||
    351         vCommand->put_u32(
    352             QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID,
    353             id))
    354     {
    355         goto cleanup;
    356     }
    357 
    358     vCommand->attr_end(nlData);
    359 
    360     ret = vCommand->requestResponse();
    361     if (ret < 0)
    362         goto cleanup;
    363 
    364     rssiCommand->disableEventHandling();
    365 
    366 
    367 cleanup:
    368     delete vCommand;
    369     return (wifi_error)ret;
    370 }
    371