Home | History | Annotate | Download | only in wifi_hal
      1 /* Copyright (c) 2014, 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 #define LOG_TAG  "WifiHAL"
     31 #include <utils/Log.h>
     32 #include <time.h>
     33 
     34 #include "ifaceeventhandler.h"
     35 
     36 /* Used to handle NL command events from driver/firmware. */
     37 IfaceEventHandlerCommand *mwifiEventHandler = NULL;
     38 
     39 /* Set the interface event monitor handler*/
     40 wifi_error wifi_set_iface_event_handler(wifi_request_id id,
     41                                         wifi_interface_handle iface,
     42                                         wifi_event_handler eh)
     43 {
     44     int ret = 0;
     45     wifi_handle wifiHandle = getWifiHandle(iface);
     46 
     47     /* Check if a similar request to set iface event handler was made earlier.
     48      * Right now we don't differentiate between the case where (i) the new
     49      * Request Id is different from the current one vs (ii) both new and
     50      * Request Ids are the same.
     51      */
     52     if (mwifiEventHandler)
     53     {
     54         if (id == mwifiEventHandler->get_request_id()) {
     55             ALOGE("%s: Iface Event Handler Set for request Id %d is still"
     56                 "running. Exit", __func__, id);
     57             return WIFI_ERROR_TOO_MANY_REQUESTS;
     58         } else {
     59             ALOGE("%s: Iface Event Handler Set for a different Request "
     60                 "Id:%d is requested. Not supported. Exit", __func__, id);
     61             return WIFI_ERROR_NOT_SUPPORTED;
     62         }
     63     }
     64 
     65     mwifiEventHandler = new IfaceEventHandlerCommand(
     66                     wifiHandle,
     67                     id,
     68                     NL80211_CMD_REG_CHANGE);
     69     if (mwifiEventHandler == NULL) {
     70         ALOGE("%s: Error mwifiEventHandler NULL", __func__);
     71         return WIFI_ERROR_UNKNOWN;
     72     }
     73     mwifiEventHandler->setCallbackHandler(eh);
     74 
     75     return (wifi_error)ret;
     76 }
     77 
     78 /* Reset monitoring for the NL event*/
     79 wifi_error wifi_reset_iface_event_handler(wifi_request_id id,
     80                                           wifi_interface_handle iface)
     81 {
     82     int ret = 0;
     83 
     84     if (mwifiEventHandler)
     85     {
     86         if (id == mwifiEventHandler->get_request_id()) {
     87             ALOGV("Delete Object mwifiEventHandler for id = %d", id);
     88             delete mwifiEventHandler;
     89             mwifiEventHandler = NULL;
     90         } else {
     91             ALOGE("%s: Iface Event Handler Set for a different Request "
     92                 "Id:%d is requested. Not supported. Exit", __func__, id);
     93             return WIFI_ERROR_NOT_SUPPORTED;
     94         }
     95     } else {
     96         ALOGV("Object mwifiEventHandler for id = %d already Deleted", id);
     97     }
     98 
     99     return (wifi_error)ret;
    100 }
    101 
    102 /* This function will be the main handler for the registered incoming
    103  * (from driver) Commads. Calls the appropriate callback handler after
    104  * parsing the vendor data.
    105  */
    106 int IfaceEventHandlerCommand::handleEvent(WifiEvent &event)
    107 {
    108     wifiEventHandler::handleEvent(event);
    109 
    110     switch(mSubcmd)
    111     {
    112         case NL80211_CMD_REG_CHANGE:
    113         {
    114             char code[2];
    115             memset(&code[0], 0, 2);
    116             if(tb[NL80211_ATTR_REG_ALPHA2])
    117             {
    118                 memcpy(&code[0], (char *) nla_data(tb[NL80211_ATTR_REG_ALPHA2]), 2);
    119             } else {
    120                 ALOGE("%s: NL80211_ATTR_REG_ALPHA2 not found", __func__);
    121             }
    122             ALOGV("Country : %c%c", code[0], code[1]);
    123             if(mHandler.on_country_code_changed)
    124             {
    125                 mHandler.on_country_code_changed(code);
    126             }
    127         }
    128         break;
    129         default:
    130             ALOGV("NL Event : %d Not supported", mSubcmd);
    131     }
    132 
    133     return NL_SKIP;
    134 }
    135 
    136 IfaceEventHandlerCommand::IfaceEventHandlerCommand(wifi_handle handle, int id, u32 subcmd)
    137         : wifiEventHandler(handle, id, subcmd)
    138 {
    139     ALOGV("wifiEventHandler %p constructed", this);
    140     registerHandler(mSubcmd);
    141     memset(&mHandler, 0, sizeof(wifi_event_handler));
    142     mEventData = NULL;
    143     mDataLen = 0;
    144 }
    145 
    146 IfaceEventHandlerCommand::~IfaceEventHandlerCommand()
    147 {
    148     ALOGV("IfaceEventHandlerCommand %p destructor", this);
    149     unregisterHandler(mSubcmd);
    150 }
    151 
    152 void IfaceEventHandlerCommand::setCallbackHandler(wifi_event_handler nHandler)
    153 {
    154     mHandler = nHandler;
    155 }
    156 
    157 int wifiEventHandler::get_request_id()
    158 {
    159     return mRequestId;
    160 }
    161 
    162 int IfaceEventHandlerCommand::get_request_id()
    163 {
    164     return wifiEventHandler::get_request_id();
    165 }
    166 
    167 wifiEventHandler::wifiEventHandler(wifi_handle handle, int id, u32 subcmd)
    168         : WifiCommand(handle, id)
    169 {
    170     mRequestId = id;
    171     mSubcmd = subcmd;
    172     registerHandler(mSubcmd);
    173     ALOGV("wifiEventHandler %p constructed", this);
    174 }
    175 
    176 wifiEventHandler::~wifiEventHandler()
    177 {
    178     ALOGV("wifiEventHandler %p destructor", this);
    179     unregisterHandler(mSubcmd);
    180 }
    181 
    182 int wifiEventHandler::handleEvent(WifiEvent &event)
    183 {
    184     struct genlmsghdr *gnlh = event.header();
    185     mSubcmd = gnlh->cmd;
    186     nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
    187             genlmsg_attrlen(gnlh, 0), NULL);
    188     ALOGV("Got NL Event : %d from the Driver.", gnlh->cmd);
    189 
    190     return NL_SKIP;
    191 }
    192 
    193 WifihalGeneric::WifihalGeneric(wifi_handle handle, int id, u32 vendor_id,
    194                                   u32 subcmd)
    195         : WifiVendorCommand(handle, id, vendor_id, subcmd)
    196 {
    197     hal_info *info = getHalInfo(handle);
    198 
    199     /* Initialize the member data variables here */
    200     mSet = 0;
    201     mSetSizeMax = 0;
    202     mSetSizePtr = NULL;
    203     mConcurrencySet = 0;
    204     filterVersion = 0;
    205     filterLength = 0;
    206     firmware_bus_max_size = 0;
    207     mCapa = &(info->capa);
    208 }
    209 
    210 WifihalGeneric::~WifihalGeneric()
    211 {
    212     mCapa = NULL;
    213 }
    214 
    215 int WifihalGeneric::requestResponse()
    216 {
    217     return WifiCommand::requestResponse(mMsg);
    218 }
    219 
    220 int WifihalGeneric::handleResponse(WifiEvent &reply)
    221 {
    222     ALOGV("Got a Wi-Fi HAL module message from Driver");
    223     int i = 0;
    224     WifiVendorCommand::handleResponse(reply);
    225 
    226     // Parse the vendordata and get the attribute
    227     switch(mSubcmd)
    228     {
    229         case QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_FEATURES:
    230             {
    231                 struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_FEATURE_SET_MAX + 1];
    232                 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_FEATURE_SET_MAX,
    233                         (struct nlattr *)mVendorData,
    234                         mDataLen, NULL);
    235 
    236                 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_FEATURE_SET])
    237                 {
    238                     ALOGE("%s: QCA_WLAN_VENDOR_ATTR_FEATURE_SET not found", __func__);
    239                     return WIFI_ERROR_INVALID_ARGS;
    240                 }
    241                 mSet = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_FEATURE_SET]);
    242                 ALOGV("Supported feature set : %x", mSet);
    243 
    244                 break;
    245             }
    246         case QCA_NL80211_VENDOR_SUBCMD_GET_CONCURRENCY_MATRIX:
    247             {
    248                 struct nlattr *tb_vendor[
    249                     QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_MAX + 1];
    250                 nla_parse(tb_vendor,
    251                     QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_MAX,
    252                     (struct nlattr *)mVendorData,mDataLen, NULL);
    253 
    254                 if (tb_vendor[
    255                     QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_RESULTS_SET_SIZE]) {
    256                     u32 val;
    257                     val = nla_get_u32(
    258                         tb_vendor[
    259                     QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_RESULTS_SET_SIZE]);
    260 
    261                     ALOGV("%s: Num of concurrency combinations: %d",
    262                         __func__, val);
    263                     val = val > (unsigned int)mSetSizeMax ?
    264                           (unsigned int)mSetSizeMax : val;
    265                     *mSetSizePtr = val;
    266 
    267                     /* Extract the list of channels. */
    268                     if (*mSetSizePtr > 0 &&
    269                         tb_vendor[
    270                         QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_RESULTS_SET]) {
    271                         nla_memcpy(mConcurrencySet,
    272                             tb_vendor[
    273                         QCA_WLAN_VENDOR_ATTR_GET_CONCURRENCY_MATRIX_RESULTS_SET],
    274                             sizeof(feature_set) * (*mSetSizePtr));
    275                     }
    276 
    277                     ALOGV("%s: Get concurrency matrix response received.",
    278                         __func__);
    279                     ALOGV("%s: Num of concurrency combinations : %d",
    280                         __func__, *mSetSizePtr);
    281                     ALOGV("%s: List of valid concurrency combinations is: ",
    282                         __func__);
    283                     for(i = 0; i < *mSetSizePtr; i++)
    284                     {
    285                         ALOGV("%x", *(mConcurrencySet + i));
    286                     }
    287                 }
    288             }
    289             break;
    290         case QCA_NL80211_VENDOR_SUBCMD_PACKET_FILTER:
    291             {
    292                 struct nlattr *tb_vendor[
    293                         QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_MAX + 1];
    294                 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_MAX,
    295                         (struct nlattr *)mVendorData,
    296                         mDataLen, NULL);
    297 
    298                 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_VERSION])
    299                 {
    300                     ALOGE("%s: QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_VERSION"
    301                           " not found", __FUNCTION__);
    302                     return WIFI_ERROR_INVALID_ARGS;
    303                 }
    304                 filterVersion = nla_get_u32(
    305                        tb_vendor[QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_VERSION]);
    306                 ALOGV("Current version : %u", filterVersion);
    307 
    308                 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_TOTAL_LENGTH])
    309                 {
    310                     ALOGE("%s: QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_TOTAL_LENGTH"
    311                           " not found", __FUNCTION__);
    312                     return WIFI_ERROR_INVALID_ARGS;
    313                 }
    314                 filterLength = nla_get_u32(
    315                     tb_vendor[QCA_WLAN_VENDOR_ATTR_PACKET_FILTER_TOTAL_LENGTH]);
    316                 ALOGV("Max filter length Supported : %u", filterLength);
    317 
    318             }
    319             break;
    320         case QCA_NL80211_VENDOR_SUBCMD_GET_BUS_SIZE:
    321             {
    322                 struct nlattr *tb_vendor[
    323                         QCA_WLAN_VENDOR_ATTR_DRV_INFO_MAX + 1];
    324                 nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_DRV_INFO_MAX,
    325                           (struct nlattr *)mVendorData, mDataLen, NULL);
    326 
    327                 if (!tb_vendor[QCA_WLAN_VENDOR_ATTR_DRV_INFO_BUS_SIZE])
    328                 {
    329                     ALOGE("%s: QCA_WLAN_VENDOR_ATTR_DRV_INFO_BUS_SIZE"
    330                           " not found", __FUNCTION__);
    331                     return WIFI_ERROR_INVALID_ARGS;
    332                 }
    333                 firmware_bus_max_size = nla_get_u32(
    334                        tb_vendor[QCA_WLAN_VENDOR_ATTR_DRV_INFO_BUS_SIZE]);
    335                 ALOGV("Max BUS size Supported: %d", firmware_bus_max_size);
    336             }
    337             break;
    338         case QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_CAPABILITIES:
    339             {
    340                 struct nlattr *tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX + 1];
    341                 nla_parse(tbVendor, QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_MAX,
    342                           (struct nlattr *)mVendorData,mDataLen, NULL);
    343 
    344                 if (wifiParseCapabilities(tbVendor) == WIFI_SUCCESS) {
    345                     ALOGV("%s: GSCAN Capabilities:\n"
    346                           "     max_ap_cache_per_scan:%d\n"
    347                           "     max_bssid_history_entries:%d\n"
    348                           "     max_hotlist_bssids:%d\n"
    349                           "     max_hotlist_ssids:%d\n"
    350                           "     max_rssi_sample_size:%d\n"
    351                           "     max_scan_buckets:%d\n"
    352                           "     max_scan_cache_size:%d\n"
    353                           "     max_scan_reporting_threshold:%d\n"
    354                           "     max_significant_wifi_change_aps:%d\n"
    355                           "     max_number_epno_networks:%d\n"
    356                           "     max_number_epno_networks_by_ssid:%d\n"
    357                           "     max_number_of_white_listed_ssid:%d.",
    358                           __FUNCTION__, mCapa->gscan_capa.max_ap_cache_per_scan,
    359                           mCapa->gscan_capa.max_bssid_history_entries,
    360                           mCapa->gscan_capa.max_hotlist_bssids,
    361                           mCapa->gscan_capa.max_hotlist_ssids,
    362                           mCapa->gscan_capa.max_rssi_sample_size,
    363                           mCapa->gscan_capa.max_scan_buckets,
    364                           mCapa->gscan_capa.max_scan_cache_size,
    365                           mCapa->gscan_capa.max_scan_reporting_threshold,
    366                           mCapa->gscan_capa.max_significant_wifi_change_aps,
    367                           mCapa->gscan_capa.max_number_epno_networks,
    368                           mCapa->gscan_capa.max_number_epno_networks_by_ssid,
    369                           mCapa->gscan_capa.max_number_of_white_listed_ssid);
    370 
    371                     ALOGV("%s: Roaming Capabilities:\n"
    372                           "    max_blacklist_size: %d\n"
    373                           "    max_whitelist_size: %d\n",
    374                           __FUNCTION__, mCapa->roaming_capa.max_blacklist_size,
    375                           mCapa->roaming_capa.max_whitelist_size);
    376                 }
    377             }
    378             break;
    379         default :
    380             ALOGE("%s: Wrong Wi-Fi HAL event received %d", __func__, mSubcmd);
    381     }
    382     return NL_SKIP;
    383 }
    384 
    385 /* Parses and extract capabilities results. */
    386 wifi_error WifihalGeneric::wifiParseCapabilities(struct nlattr **tbVendor)
    387 {
    388     if (!tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SCAN_CACHE_SIZE]) {
    389         ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SCAN_CACHE_SIZE not found",
    390               __FUNCTION__);
    391         return WIFI_ERROR_INVALID_ARGS;
    392     }
    393     mCapa->gscan_capa.max_scan_cache_size = nla_get_u32(tbVendor[
    394                               QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SCAN_CACHE_SIZE]);
    395 
    396     if (!tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SCAN_BUCKETS]) {
    397         ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SCAN_BUCKETS not found",
    398               __FUNCTION__);
    399         return WIFI_ERROR_INVALID_ARGS;
    400     }
    401     mCapa->gscan_capa.max_scan_buckets = nla_get_u32(tbVendor[
    402                                  QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SCAN_BUCKETS]);
    403 
    404     if (!tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_AP_CACHE_PER_SCAN]) {
    405         ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_AP_CACHE_PER_SCAN not found",
    406               __FUNCTION__);
    407         return WIFI_ERROR_INVALID_ARGS;
    408     }
    409     mCapa->gscan_capa.max_ap_cache_per_scan = nla_get_u32(tbVendor[
    410                             QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_AP_CACHE_PER_SCAN]);
    411 
    412     if (!tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_RSSI_SAMPLE_SIZE]) {
    413         ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_RSSI_SAMPLE_SIZE not found",
    414               __FUNCTION__);
    415         return WIFI_ERROR_INVALID_ARGS;
    416     }
    417     mCapa->gscan_capa.max_rssi_sample_size = nla_get_u32(tbVendor[
    418                              QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_RSSI_SAMPLE_SIZE]);
    419 
    420     if (!tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SCAN_REPORTING_THRESHOLD]) {
    421         ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SCAN_REPORTING_THRESHOLD not"
    422               " found", __FUNCTION__);
    423         return WIFI_ERROR_INVALID_ARGS;
    424     }
    425     mCapa->gscan_capa.max_scan_reporting_threshold = nla_get_u32(tbVendor[
    426                      QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SCAN_REPORTING_THRESHOLD]);
    427 
    428     if (!tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_BSSIDS]) {
    429         ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_BSSIDS not found",
    430               __FUNCTION__);
    431         return WIFI_ERROR_INVALID_ARGS;
    432     }
    433     mCapa->gscan_capa.max_hotlist_bssids = nla_get_u32(tbVendor[
    434                                QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_BSSIDS]);
    435 
    436     if (!tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SIGNIFICANT_WIFI_CHANGE_APS]
    437        ) {
    438         ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SIGNIFICANT_WIFI_CHANGE_APS "
    439               "not found", __FUNCTION__);
    440         return WIFI_ERROR_INVALID_ARGS;
    441     }
    442     mCapa->gscan_capa.max_significant_wifi_change_aps = nla_get_u32(tbVendor[
    443                   QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_SIGNIFICANT_WIFI_CHANGE_APS]);
    444 
    445     if (!tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_BSSID_HISTORY_ENTRIES]) {
    446         ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_BSSID_HISTORY_ENTRIES not "
    447               "found", __FUNCTION__);
    448         return WIFI_ERROR_INVALID_ARGS;
    449     }
    450     mCapa->gscan_capa.max_bssid_history_entries = nla_get_u32(tbVendor[
    451                         QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_BSSID_HISTORY_ENTRIES]);
    452 
    453     if (!tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_SSIDS]) {
    454         ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_SSIDS not found. Set"
    455               " to 0.", __FUNCTION__);
    456         mCapa->gscan_capa.max_hotlist_ssids = 0;
    457     } else {
    458         mCapa->gscan_capa.max_hotlist_ssids = nla_get_u32(tbVendor[
    459                                 QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_HOTLIST_SSIDS]);
    460     }
    461 
    462     if (!tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS]) {
    463         ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS not found. Set"
    464               " to 0.", __FUNCTION__);
    465         mCapa->gscan_capa.max_number_epno_networks = 0;
    466     } else {
    467         mCapa->gscan_capa.max_number_epno_networks
    468             = nla_get_u32(tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS
    469                                   ]);
    470     }
    471 
    472     if (!tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS_BY_SSID]) {
    473         ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS_BY_SSID not "
    474               "found. Set to 0.", __FUNCTION__);
    475         mCapa->gscan_capa.max_number_epno_networks_by_ssid = 0;
    476     } else {
    477         mCapa->gscan_capa.max_number_epno_networks_by_ssid = nla_get_u32(tbVendor[
    478                         QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_NUM_EPNO_NETS_BY_SSID]);
    479     }
    480 
    481     if (!tbVendor[QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_NUM_WHITELISTED_SSID]) {
    482         ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_NUM_WHITELISTED_SSID not "
    483               "found. Set to 0.", __FUNCTION__);
    484         mCapa->gscan_capa.max_number_of_white_listed_ssid = 0;
    485         mCapa->roaming_capa.max_whitelist_size = 0;
    486     } else {
    487         mCapa->gscan_capa.max_number_of_white_listed_ssid = nla_get_u32(tbVendor[
    488                          QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX_NUM_WHITELISTED_SSID]);
    489         mCapa->roaming_capa.max_whitelist_size = mCapa->gscan_capa.max_number_of_white_listed_ssid;
    490     }
    491 
    492     if (!tbVendor[QCA_WLAN_VENDOR_ATTR_CAPABILITIES_MAX_NUM_BLACKLISTED_BSSID]) {
    493         ALOGE("%s: QCA_WLAN_VENDOR_ATTR_GSCAN_RESULTS_CAPABILITIES_MAX"
    494             "_NUM_BLACKLIST_BSSID not found. Set to 0.", __FUNCTION__);
    495         mCapa->roaming_capa.max_blacklist_size = 0;
    496     } else {
    497         mCapa->roaming_capa.max_blacklist_size = nla_get_u32(tbVendor[
    498                                       QCA_WLAN_VENDOR_ATTR_CAPABILITIES_MAX_NUM_BLACKLISTED_BSSID]);
    499     }
    500     return WIFI_SUCCESS;
    501 }
    502 
    503 void WifihalGeneric::getResponseparams(feature_set *pset)
    504 {
    505     *pset = mSet;
    506 }
    507 
    508 void WifihalGeneric::setMaxSetSize(int set_size_max) {
    509     mSetSizeMax = set_size_max;
    510 }
    511 
    512 void WifihalGeneric::setConcurrencySet(feature_set set[]) {
    513     mConcurrencySet = set;
    514 }
    515 
    516 void WifihalGeneric::setSizePtr(int *set_size) {
    517     mSetSizePtr = set_size;
    518 }
    519 
    520 int WifihalGeneric::getFilterVersion() {
    521     return filterVersion;
    522 }
    523 
    524 int WifihalGeneric::getFilterLength() {
    525     return filterLength;
    526 }
    527 
    528 int WifihalGeneric::getBusSize() {
    529     return firmware_bus_max_size;
    530 }
    531 
    532 wifi_error WifihalGeneric::wifiGetCapabilities(wifi_interface_handle handle)
    533 {
    534     int ret;
    535     struct nlattr *nlData;
    536     interface_info *ifaceInfo = getIfaceInfo(handle);
    537 
    538     /* Create the NL message. */
    539     ret = create();
    540     if (ret < 0) {
    541         ALOGE("%s: Failed to create NL message,  Error:%d", __FUNCTION__, ret);
    542         return WIFI_ERROR_UNKNOWN;
    543     }
    544 
    545     /* Set the interface Id of the message. */
    546     ret = set_iface_id(ifaceInfo->name);
    547     if (ret < 0) {
    548         ALOGE("%s: Failed to set interface Id of message, Error:%d", __FUNCTION__, ret);
    549         return WIFI_ERROR_UNKNOWN;
    550     }
    551 
    552     /* Add the vendor specific attributes for the NL command. */
    553     nlData = attr_start(NL80211_ATTR_VENDOR_DATA);
    554     if (!nlData)
    555         return WIFI_ERROR_UNKNOWN;
    556 
    557     ret = put_u32(QCA_WLAN_VENDOR_ATTR_GSCAN_SUBCMD_CONFIG_PARAM_REQUEST_ID, mId);
    558     if (ret < 0) {
    559         ALOGE("%s: Failed to add request_ID to NL command, Error:%d", __FUNCTION__, ret);
    560         return WIFI_ERROR_UNKNOWN;
    561     }
    562 
    563     attr_end(nlData);
    564 
    565     ret = requestResponse();
    566     if (ret != 0) {
    567         ALOGE("%s: Failed to send request, Error:%d", __FUNCTION__, ret);
    568         return WIFI_ERROR_UNKNOWN;
    569     }
    570 
    571     return WIFI_SUCCESS;
    572 }
    573