Home | History | Annotate | Download | only in wifi_hal
      1 /* Copyright (c) 2015, 2018 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         free(info->rssi_handlers);
     71         info->rssi_handlers = NULL;
     72         return WIFI_SUCCESS;
     73     }
     74     ALOGE ("%s: info or info->rssi_handlers NULL", __FUNCTION__);
     75     return WIFI_ERROR_UNKNOWN;
     76 }
     77 
     78 void RSSIMonitorCommand::enableEventHandling()
     79 {
     80     pthread_mutex_lock(&rm_lock);
     81     mEventHandlingEnabled = true;
     82     pthread_mutex_unlock(&rm_lock);
     83 }
     84 
     85 void RSSIMonitorCommand::disableEventHandling()
     86 {
     87     pthread_mutex_lock(&rm_lock);
     88     mEventHandlingEnabled = false;
     89     pthread_mutex_unlock(&rm_lock);
     90 }
     91 
     92 bool RSSIMonitorCommand::isEventHandlingEnabled()
     93 {
     94     bool eventHandlingEnabled;
     95     pthread_mutex_lock(&rm_lock);
     96     eventHandlingEnabled = mEventHandlingEnabled;
     97     pthread_mutex_unlock(&rm_lock);
     98 
     99     return eventHandlingEnabled;
    100 }
    101 
    102 void RSSIMonitorCommand::setCallbackHandler(wifi_rssi_event_handler handler)
    103 {
    104     mHandler = handler;
    105 }
    106 
    107 RSSIMonitorCommand::RSSIMonitorCommand(wifi_handle handle, int id,
    108                                        u32 vendor_id, u32 subcmd)
    109         : WifiVendorCommand(handle, id, vendor_id, subcmd)
    110 {
    111     memset(&mHandler, 0, sizeof(mHandler));
    112     if (registerVendorHandler(vendor_id, subcmd)) {
    113         /* Error case should not happen print log */
    114         ALOGE("%s: Unable to register Vendor Handler Vendor Id=0x%x subcmd=%u",
    115               __FUNCTION__, vendor_id, subcmd);
    116     }
    117     pthread_mutex_init(&rm_lock, NULL);
    118     disableEventHandling();
    119 }
    120 
    121 RSSIMonitorCommand::~RSSIMonitorCommand()
    122 {
    123     unregisterVendorHandler(mVendor_id, mSubcmd);
    124     pthread_mutex_destroy(&rm_lock);
    125 }
    126 
    127 void RSSIMonitorCommand::setReqId(wifi_request_id reqid)
    128 {
    129     mId = reqid;
    130 }
    131 
    132 RSSIMonitorCommand* RSSIMonitorCommand::instance(wifi_handle handle,
    133                                                  wifi_request_id id)
    134 {
    135     if (handle == NULL) {
    136         ALOGE("Interface Handle is invalid");
    137         return NULL;
    138     }
    139     hal_info *info = getHalInfo(handle);
    140     if (!info || !info->rssi_handlers) {
    141         ALOGE("rssi_handlers is invalid");
    142         return NULL;
    143     }
    144 
    145     RSSIMonitorCommand* mRSSIMonitorCommandInstance =
    146         info->rssi_handlers->mRSSIMonitorCommandInstance;
    147 
    148     if (mRSSIMonitorCommandInstance == NULL) {
    149         mRSSIMonitorCommandInstance = new RSSIMonitorCommand(handle, id,
    150                 OUI_QCA,
    151                 QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI);
    152         info->rssi_handlers->mRSSIMonitorCommandInstance = mRSSIMonitorCommandInstance;
    153         return mRSSIMonitorCommandInstance;
    154     }
    155     else
    156     {
    157         if (handle != getWifiHandle(mRSSIMonitorCommandInstance->mInfo))
    158         {
    159             /* upper layer must have cleaned up the handle and reinitialized,
    160                so we need to update the same */
    161             ALOGV("Handle different, update the handle");
    162             mRSSIMonitorCommandInstance->mInfo = (hal_info *)handle;
    163         }
    164         mRSSIMonitorCommandInstance->setReqId(id);
    165     }
    166     return mRSSIMonitorCommandInstance;
    167 }
    168 
    169 /* This function will be the main handler for incoming event.
    170  * Call the appropriate callback handler after parsing the vendor data.
    171  */
    172 int RSSIMonitorCommand::handleEvent(WifiEvent &event)
    173 {
    174     int ret = WIFI_SUCCESS;
    175 
    176     if (isEventHandlingEnabled() == false) {
    177         ALOGE("%s: RSSI monitor isn't running or already stopped. "
    178               "Nothing to do. Exit", __FUNCTION__);
    179         return ret;
    180     }
    181 
    182     WifiVendorCommand::handleEvent(event);
    183 
    184     /* Parse the vendordata and get the attribute */
    185     switch(mSubcmd)
    186     {
    187         case QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI:
    188         {
    189             mac_addr addr;
    190             s8 rssi;
    191             wifi_request_id reqId;
    192             struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX
    193                                      + 1];
    194             nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX,
    195                     (struct nlattr *)mVendorData,
    196                     mDataLen, NULL);
    197 
    198             memset(addr, 0, sizeof(mac_addr));
    199 
    200             if (!tb_vendor[
    201                 QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID])
    202             {
    203                 ALOGE("%s: ATTR_RSSI_MONITORING_REQUEST_ID not found. Exit.",
    204                     __FUNCTION__);
    205                 ret = WIFI_ERROR_INVALID_ARGS;
    206                 break;
    207             }
    208             reqId = nla_get_u32(
    209                     tb_vendor[QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID]
    210                     );
    211             /* If event has a different request_id, ignore that and use the
    212              *  request_id value which we're maintaining.
    213              */
    214             if (reqId != id()) {
    215                 ALOGV("%s: Event has Req. ID:%d <> Ours:%d, continue...",
    216                     __FUNCTION__, reqId, id());
    217                 reqId = id();
    218             }
    219             ret = get_mac_addr(tb_vendor,
    220                     QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_BSSID,
    221                     addr);
    222             if (ret != WIFI_SUCCESS) {
    223                 return ret;
    224             }
    225             ALOGV(MAC_ADDR_STR, MAC_ADDR_ARRAY(addr));
    226 
    227             if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI])
    228             {
    229                 ALOGE("%s: QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI"
    230                       " not found", __FUNCTION__);
    231                 return WIFI_ERROR_INVALID_ARGS;
    232             }
    233             rssi = get_s8(tb_vendor[
    234                         QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CUR_RSSI]);
    235             ALOGV("Current RSSI : %d ", rssi);
    236 
    237             if (mHandler.on_rssi_threshold_breached)
    238                 (*mHandler.on_rssi_threshold_breached)(reqId, addr, rssi);
    239             else
    240                 ALOGE("RSSI Monitoring: No Callback registered: ");
    241         }
    242         break;
    243 
    244         default:
    245             /* Error case should not happen print log */
    246             ALOGE("%s: Wrong subcmd received %d", __FUNCTION__, mSubcmd);
    247     }
    248 
    249     return ret;
    250 }
    251 
    252 wifi_error wifi_start_rssi_monitoring(wifi_request_id id,
    253                                       wifi_interface_handle iface,
    254                                       s8 max_rssi,
    255                                       s8 min_rssi,
    256                                       wifi_rssi_event_handler eh)
    257 {
    258     wifi_error ret;
    259     struct nlattr *nlData;
    260     WifiVendorCommand *vCommand = NULL;
    261     wifi_handle wifiHandle = getWifiHandle(iface);
    262     RSSIMonitorCommand *rssiCommand;
    263 
    264     ret = initialize_vendor_cmd(iface, id,
    265                                 QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI,
    266                                 &vCommand);
    267     if (ret != WIFI_SUCCESS) {
    268         ALOGE("%s: Initialization failed", __FUNCTION__);
    269         return ret;
    270     }
    271 
    272     ALOGV("%s: Max RSSI:%d Min RSSI:%d", __FUNCTION__,
    273           max_rssi, min_rssi);
    274     /* Add the vendor specific attributes for the NL command. */
    275     nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
    276     if (!nlData)
    277         goto cleanup;
    278 
    279     ret = vCommand->put_u32(QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL,
    280                              QCA_WLAN_RSSI_MONITORING_START);
    281     if (ret != WIFI_SUCCESS)
    282         goto cleanup;
    283     ret = vCommand->put_u32(QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID,
    284                             id);
    285     if (ret != WIFI_SUCCESS)
    286         goto cleanup;
    287     ret = vCommand->put_s8(QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MAX_RSSI,
    288                            max_rssi);
    289     if (ret != WIFI_SUCCESS)
    290         goto cleanup;
    291     ret = vCommand->put_s8(QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_MIN_RSSI,
    292                            min_rssi);
    293     if (ret != WIFI_SUCCESS)
    294         goto cleanup;
    295 
    296     vCommand->attr_end(nlData);
    297 
    298     rssiCommand = RSSIMonitorCommand::instance(wifiHandle, id);
    299     if (rssiCommand == NULL) {
    300         ALOGE("%s: Error rssiCommand NULL", __FUNCTION__);
    301         ret = WIFI_ERROR_OUT_OF_MEMORY;
    302         goto cleanup;
    303     }
    304 
    305     rssiCommand->setCallbackHandler(eh);
    306 
    307     ret = vCommand->requestResponse();
    308     if (ret != WIFI_SUCCESS)
    309         goto cleanup;
    310 
    311     rssiCommand->enableEventHandling();
    312 
    313 cleanup:
    314     delete vCommand;
    315     return ret;
    316 }
    317 
    318 wifi_error wifi_stop_rssi_monitoring(wifi_request_id id,
    319                                      wifi_interface_handle iface)
    320 {
    321     wifi_error ret;
    322     struct nlattr *nlData;
    323     WifiVendorCommand *vCommand = NULL;
    324     wifi_handle wifiHandle = getWifiHandle(iface);
    325     RSSIMonitorCommand *rssiCommand;
    326     rssi_monitor_event_handlers* event_handlers;
    327     hal_info *info = getHalInfo(wifiHandle);
    328 
    329     event_handlers = info->rssi_handlers;
    330     rssiCommand = event_handlers->mRSSIMonitorCommandInstance;
    331 
    332     if (rssiCommand == NULL ||
    333         rssiCommand->isEventHandlingEnabled() == false) {
    334         ALOGE("%s: RSSI monitor isn't running or already stopped. "
    335             "Nothing to do. Exit", __FUNCTION__);
    336         return WIFI_ERROR_NOT_AVAILABLE;
    337     }
    338 
    339     ret = initialize_vendor_cmd(iface, id,
    340                                 QCA_NL80211_VENDOR_SUBCMD_MONITOR_RSSI,
    341                                 &vCommand);
    342     if (ret != WIFI_SUCCESS) {
    343         ALOGE("%s: Initialization failed", __FUNCTION__);
    344         return ret;
    345     }
    346 
    347     /* Add the vendor specific attributes for the NL command. */
    348     nlData = vCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
    349     if (!nlData)
    350         goto cleanup;
    351 
    352     ret = vCommand->put_u32(QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_CONTROL,
    353                             QCA_WLAN_RSSI_MONITORING_STOP);
    354     if (ret != WIFI_SUCCESS)
    355         goto cleanup;
    356     ret = vCommand->put_u32(QCA_WLAN_VENDOR_ATTR_RSSI_MONITORING_REQUEST_ID,
    357                             id);
    358     if (ret != WIFI_SUCCESS)
    359         goto cleanup;
    360 
    361     vCommand->attr_end(nlData);
    362 
    363     ret = vCommand->requestResponse();
    364     if (ret != WIFI_SUCCESS)
    365         goto cleanup;
    366 
    367     rssiCommand->disableEventHandling();
    368 
    369 cleanup:
    370     delete vCommand;
    371     return ret;
    372 }
    373