Home | History | Annotate | Download | only in wifi_hal
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <errno.h>
     18 
     19 #include "common.h"
     20 #include "roamcommand.h"
     21 #include "vendor_definitions.h"
     22 
     23 RoamCommand::RoamCommand(wifi_handle handle, int id, u32 vendor_id, u32 subcmd)
     24         : WifiVendorCommand(handle, id, vendor_id, subcmd)
     25 {
     26 }
     27 
     28 RoamCommand::~RoamCommand()
     29 {
     30 }
     31 
     32 /* This function implements creation of Vendor command */
     33 int RoamCommand::create() {
     34     int ret = mMsg.create(NL80211_CMD_VENDOR, 0, 0);
     35     if (ret < 0) {
     36         return ret;
     37     }
     38 
     39     /* Insert the oui in the msg */
     40     ret = mMsg.put_u32(NL80211_ATTR_VENDOR_ID, mVendor_id);
     41     if (ret < 0)
     42         goto out;
     43     /* Insert the subcmd in the msg */
     44     ret = mMsg.put_u32(NL80211_ATTR_VENDOR_SUBCMD, mSubcmd);
     45     if (ret < 0)
     46         goto out;
     47 
     48      ALOGV("%s: mVendor_id = %d, Subcmd = %d.",
     49         __FUNCTION__, mVendor_id, mSubcmd);
     50 out:
     51     return ret;
     52 }
     53 
     54 int RoamCommand::requestResponse()
     55 {
     56     return WifiCommand::requestResponse(mMsg);
     57 }
     58 
     59 wifi_error wifi_set_bssid_blacklist(wifi_request_id id,
     60                                     wifi_interface_handle iface,
     61                                     wifi_bssid_params params)
     62 {
     63     int ret = 0, i;
     64     RoamCommand *roamCommand;
     65     struct nlattr *nlData, *nlBssids;
     66     interface_info *ifaceInfo = getIfaceInfo(iface);
     67     wifi_handle wifiHandle = getWifiHandle(iface);
     68     hal_info *info = getHalInfo(wifiHandle);
     69 
     70     if (!(info->supported_feature_set & WIFI_FEATURE_GSCAN)) {
     71         ALOGE("%s: GSCAN is not supported by driver",
     72             __FUNCTION__);
     73         return WIFI_ERROR_NOT_SUPPORTED;
     74     }
     75 
     76     for (i = 0; i < params.num_bssid; i++) {
     77         ALOGV("BSSID: %d : %02x:%02x:%02x:%02x:%02x:%02x", i,
     78                 params.bssids[i][0], params.bssids[i][1],
     79                 params.bssids[i][2], params.bssids[i][3],
     80                 params.bssids[i][4], params.bssids[i][5]);
     81     }
     82 
     83     roamCommand =
     84          new RoamCommand(wifiHandle,
     85                           id,
     86                           OUI_QCA,
     87                           QCA_NL80211_VENDOR_SUBCMD_ROAM);
     88     if (roamCommand == NULL) {
     89         ALOGE("%s: Error roamCommand NULL", __FUNCTION__);
     90         return WIFI_ERROR_UNKNOWN;
     91     }
     92 
     93     /* Create the NL message. */
     94     ret = roamCommand->create();
     95     if (ret < 0)
     96         goto cleanup;
     97 
     98     /* Set the interface Id of the message. */
     99     ret = roamCommand->set_iface_id(ifaceInfo->name);
    100     if (ret < 0)
    101         goto cleanup;
    102 
    103     /* Add the vendor specific attributes for the NL command. */
    104     nlData = roamCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
    105     if (!nlData)
    106         goto cleanup;
    107 
    108     if (roamCommand->put_u32(QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD,
    109             QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SET_BLACKLIST_BSSID) ||
    110         roamCommand->put_u32(
    111             QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID,
    112             id) ||
    113         roamCommand->put_u32(
    114             QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_NUM_BSSID,
    115             params.num_bssid)) {
    116         goto cleanup;
    117     }
    118 
    119     nlBssids = roamCommand->attr_start(
    120             QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS);
    121     for (i = 0; i < params.num_bssid; i++) {
    122         struct nlattr *nl_ssid = roamCommand->attr_start(i);
    123 
    124         if (roamCommand->put_addr(
    125                 QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_SET_BSSID_PARAMS_BSSID,
    126                 (u8 *)params.bssids[i])) {
    127             goto cleanup;
    128         }
    129 
    130         roamCommand->attr_end(nl_ssid);
    131     }
    132     roamCommand->attr_end(nlBssids);
    133 
    134     roamCommand->attr_end(nlData);
    135 
    136     ret = roamCommand->requestResponse();
    137     if (ret != 0) {
    138         ALOGE("wifi_set_bssid_blacklist(): requestResponse Error:%d", ret);
    139     }
    140 
    141 cleanup:
    142     delete roamCommand;
    143     return (wifi_error)ret;
    144 
    145 }
    146 
    147 wifi_error wifi_set_ssid_white_list(wifi_request_id id, wifi_interface_handle iface,
    148                                     int num_networks, ssid_t *ssid_list)
    149 {
    150     wifi_error result = WIFI_SUCCESS;
    151     int ret = 0, i;
    152     RoamCommand *roamCommand;
    153     struct nlattr *nlData, *nlSsids;
    154     interface_info *ifaceInfo = getIfaceInfo(iface);
    155     wifi_handle wifiHandle = getWifiHandle(iface);
    156     char ssid[MAX_SSID_LENGTH + 1];
    157 
    158     ALOGV("%s: Number of SSIDs : %d", __FUNCTION__, num_networks);
    159 
    160     roamCommand = new RoamCommand(
    161                                 wifiHandle,
    162                                 id,
    163                                 OUI_QCA,
    164                                 QCA_NL80211_VENDOR_SUBCMD_ROAM);
    165     if (roamCommand == NULL) {
    166         ALOGE("%s: Failed to create object of RoamCommand class", __FUNCTION__);
    167         return WIFI_ERROR_UNKNOWN;
    168     }
    169 
    170     /* Create the NL message. */
    171     ret = roamCommand->create();
    172     if (ret < 0) {
    173         ALOGE("%s: Failed to create NL message,  Error: %d", __FUNCTION__, ret);
    174         result = WIFI_ERROR_UNKNOWN;
    175         goto cleanup;
    176     }
    177 
    178     /* Set the interface Id of the message. */
    179     ret = roamCommand->set_iface_id(ifaceInfo->name);
    180     if (ret < 0) {
    181         ALOGE("%s: Failed to set interface Id of message, Error: %d", __FUNCTION__, ret);
    182         result = WIFI_ERROR_UNKNOWN;
    183         goto cleanup;
    184     }
    185 
    186     /* Add the vendor specific attributes for the NL command. */
    187     nlData = roamCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
    188     if (!nlData) {
    189         result = WIFI_ERROR_UNKNOWN;
    190         goto cleanup;
    191     }
    192 
    193     if (roamCommand->put_u32(QCA_WLAN_VENDOR_ATTR_ROAMING_SUBCMD,
    194                              QCA_WLAN_VENDOR_ATTR_ROAM_SUBCMD_SSID_WHITE_LIST) ||
    195         roamCommand->put_u32(QCA_WLAN_VENDOR_ATTR_ROAMING_REQ_ID, id) ||
    196         roamCommand->put_u32(QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_NUM_NETWORKS,
    197                              num_networks)) {
    198         ALOGE("%s: Failed to add vendor atributes, Error: %d", __FUNCTION__, ret);
    199         result = WIFI_ERROR_UNKNOWN;
    200         goto cleanup;
    201     }
    202 
    203     nlSsids = roamCommand->attr_start(QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID_LIST);
    204     for (i = 0; i < num_networks; i++) {
    205         struct nlattr *nl_ssid = roamCommand->attr_start(i);
    206 
    207         memcpy(ssid, ssid_list[i].ssid_str, ssid_list[i].length);
    208         ssid[ssid_list[i].length] = '\0';
    209         ALOGV("ssid[%d] : %s", i, ssid);
    210 
    211         if (roamCommand->put_bytes(QCA_WLAN_VENDOR_ATTR_ROAMING_PARAM_WHITE_LIST_SSID, ssid,
    212                                    (ssid_list[i].length + 1))) {
    213             ALOGE("%s: Failed to add ssid atribute, Error: %d", __FUNCTION__, ret);
    214             result = WIFI_ERROR_UNKNOWN;
    215             goto cleanup;
    216         }
    217 
    218         roamCommand->attr_end(nl_ssid);
    219     }
    220     roamCommand->attr_end(nlSsids);
    221 
    222     roamCommand->attr_end(nlData);
    223 
    224     ret = roamCommand->requestResponse();
    225     if (ret != 0) {
    226         ALOGE("%s: Failed to send request, Error:%d", __FUNCTION__, ret);
    227         result = WIFI_ERROR_UNKNOWN;
    228     }
    229 
    230 cleanup:
    231     delete roamCommand;
    232     return result;
    233 }
    234 
    235 wifi_error wifi_get_roaming_capabilities(wifi_interface_handle iface,
    236                                          wifi_roaming_capabilities *caps)
    237 {
    238     wifi_handle wifiHandle = getWifiHandle(iface);
    239     hal_info *info = getHalInfo(wifiHandle);
    240 
    241     if (!caps) {
    242         ALOGE("%s: Invalid Buffer provided. Exit", __FUNCTION__);
    243         return WIFI_ERROR_INVALID_ARGS;
    244     }
    245 
    246     if (!info) {
    247         ALOGE("%s: hal_info is NULL", __FUNCTION__);
    248         return WIFI_ERROR_INVALID_ARGS;
    249     }
    250 
    251     memcpy(caps, &info->capa.roaming_capa, sizeof(wifi_roaming_capabilities));
    252 
    253     return WIFI_SUCCESS;
    254 }
    255 
    256 wifi_error wifi_configure_roaming(wifi_interface_handle iface, wifi_roaming_config *roaming_config)
    257 {
    258     wifi_error ret;
    259     int requestId;
    260     wifi_bssid_params bssid_params;
    261     wifi_handle wifiHandle = getWifiHandle(iface);
    262     hal_info *info = getHalInfo(wifiHandle);
    263 
    264     if (!roaming_config) {
    265         ALOGE("%s: Invalid Buffer provided. Exit", __FUNCTION__);
    266         return WIFI_ERROR_INVALID_ARGS;
    267     }
    268 
    269     /* No request id from caller, so generate one and pass it on to the driver.
    270      * Generate it randomly.
    271      */
    272     requestId = get_requestid();
    273 
    274     /* Set bssid blacklist */
    275     if (roaming_config->num_blacklist_bssid > info->capa.roaming_capa.max_blacklist_size) {
    276         ALOGE("%s: Number of blacklist bssids(%d) provided is more than maximum blacklist bssids(%d)"
    277               " supported", __FUNCTION__, roaming_config->num_blacklist_bssid,
    278               info->capa.roaming_capa.max_blacklist_size);
    279         return WIFI_ERROR_NOT_SUPPORTED;
    280     }
    281     bssid_params.num_bssid = roaming_config->num_blacklist_bssid;
    282 
    283     memcpy(bssid_params.bssids, roaming_config->blacklist_bssid,
    284            (bssid_params.num_bssid * sizeof(mac_addr)));
    285 
    286     ret = wifi_set_bssid_blacklist(requestId, iface, bssid_params);
    287     if (ret != WIFI_SUCCESS) {
    288         ALOGE("%s: Failed to configure blacklist bssids", __FUNCTION__);
    289         return WIFI_ERROR_UNKNOWN;
    290     }
    291 
    292     /* Set ssid whitelist */
    293     if (roaming_config->num_whitelist_ssid > info->capa.roaming_capa.max_whitelist_size) {
    294         ALOGE("%s: Number of whitelist ssid(%d) provided is more than maximum whitelist ssids(%d) "
    295               "supported", __FUNCTION__, roaming_config->num_whitelist_ssid,
    296               info->capa.roaming_capa.max_whitelist_size);
    297         return WIFI_ERROR_NOT_SUPPORTED;
    298     }
    299     ret = wifi_set_ssid_white_list(requestId, iface, roaming_config->num_whitelist_ssid,
    300                                    roaming_config->whitelist_ssid);
    301     if (ret != WIFI_SUCCESS)
    302         ALOGE("%s: Failed to configure whitelist ssids", __FUNCTION__);
    303 
    304     return ret;
    305 }
    306 
    307 /* Enable/disable firmware roaming */
    308 wifi_error wifi_enable_firmware_roaming(wifi_interface_handle iface, fw_roaming_state_t state)
    309 {
    310     wifi_error result = WIFI_SUCCESS;
    311     int requestId, ret;
    312     RoamCommand *roamCommand;
    313     struct nlattr *nlData;
    314     interface_info *ifaceInfo = getIfaceInfo(iface);
    315     wifi_handle wifiHandle = getWifiHandle(iface);
    316     qca_roaming_policy policy;
    317 
    318     ALOGV("%s: set firmware roam state : %d", __FUNCTION__, state);
    319 
    320     if (state == ROAMING_ENABLE) {
    321         policy = QCA_ROAMING_ALLOWED_WITHIN_ESS;
    322     } else if(state == ROAMING_DISABLE) {
    323         policy = QCA_ROAMING_NOT_ALLOWED;
    324     } else {
    325         ALOGE("%s: Invalid state provided: %d. Exit \n", __FUNCTION__, state);
    326         return WIFI_ERROR_INVALID_ARGS;
    327     }
    328 
    329     /* No request id from caller, so generate one and pass it on to the driver.
    330      * Generate it randomly.
    331      */
    332     requestId = get_requestid();
    333 
    334     roamCommand =
    335          new RoamCommand(wifiHandle,
    336                           requestId,
    337                           OUI_QCA,
    338                           QCA_NL80211_VENDOR_SUBCMD_ROAMING);
    339     if (roamCommand == NULL) {
    340         ALOGE("%s: Failed to create object of RoamCommand class", __FUNCTION__);
    341         return WIFI_ERROR_UNKNOWN;
    342     }
    343 
    344     /* Create the NL message. */
    345     ret = roamCommand->create();
    346     if (ret < 0) {
    347         ALOGE("%s: Failed to create NL message,  Error: %d", __FUNCTION__, ret);
    348         result = WIFI_ERROR_UNKNOWN;
    349         goto cleanup;
    350     }
    351 
    352     /* Set the interface Id of the message. */
    353     ret = roamCommand->set_iface_id(ifaceInfo->name);
    354     if (ret < 0) {
    355         ALOGE("%s: Failed to set interface Id of message, Error: %d", __FUNCTION__, ret);
    356         result = WIFI_ERROR_UNKNOWN;
    357         goto cleanup;
    358     }
    359 
    360     /* Add the vendor specific attributes for the NL command. */
    361     nlData = roamCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
    362     if (!nlData) {
    363         result = WIFI_ERROR_UNKNOWN;
    364         goto cleanup;
    365     }
    366 
    367     if (roamCommand->put_u32(QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY, policy)) {
    368         ALOGE("%s: Failed to add roaming policy atribute, Error: %d", __FUNCTION__, ret);
    369         result = WIFI_ERROR_UNKNOWN;
    370         goto cleanup;
    371     }
    372 
    373     roamCommand->attr_end(nlData);
    374 
    375     ret = roamCommand->requestResponse();
    376     if (ret != 0) {
    377         ALOGE("%s: Failed to send request, Error:%d", __FUNCTION__, ret);
    378         if (ret == -EBUSY)
    379             result = WIFI_ERROR_BUSY;
    380         else
    381             result = WIFI_ERROR_UNKNOWN;
    382     }
    383 
    384 cleanup:
    385     delete roamCommand;
    386     return result;
    387 }
    388