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
      9  *    copyright notice, this list of conditions and the following
     10  *    disclaimer in the documentation and/or other materials provided
     11  *    with the 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 #include <errno.h>
     34 #include <stdlib.h>
     35 #include "wificonfigcommand.h"
     36 
     37 /* Implementation of the API functions exposed in wifi_config.h */
     38 wifi_error wifi_extended_dtim_config_set(wifi_request_id id,
     39                                          wifi_interface_handle iface,
     40                                          int extended_dtim)
     41 {
     42     int ret = 0;
     43     WiFiConfigCommand *wifiConfigCommand;
     44     struct nlattr *nlData;
     45     interface_info *ifaceInfo = getIfaceInfo(iface);
     46     wifi_handle wifiHandle = getWifiHandle(iface);
     47 
     48     ALOGV("%s: extended_dtim:%d", __FUNCTION__, extended_dtim);
     49 
     50     wifiConfigCommand = new WiFiConfigCommand(
     51                             wifiHandle,
     52                             id,
     53                             OUI_QCA,
     54                             QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
     55 
     56     if (wifiConfigCommand == NULL) {
     57         ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
     58         return WIFI_ERROR_UNKNOWN;
     59     }
     60 
     61     /* Create the NL message. */
     62     ret = wifiConfigCommand->create();
     63     if (ret < 0) {
     64         ALOGE("wifi_extended_dtim_config_set: failed to create NL msg. "
     65             "Error:%d", ret);
     66         goto cleanup;
     67     }
     68 
     69     /* Set the interface Id of the message. */
     70     ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
     71     if (ret < 0) {
     72         ALOGE("wifi_extended_dtim_config_set: failed to set iface id. "
     73             "Error:%d", ret);
     74         goto cleanup;
     75     }
     76 
     77     /* Add the vendor specific attributes for the NL command. */
     78     nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
     79     if (!nlData) {
     80         ALOGE("wifi_extended_dtim_config_set: failed attr_start for "
     81             "VENDOR_DATA. Error:%d", ret);
     82         goto cleanup;
     83     }
     84 
     85     if (wifiConfigCommand->put_u32(
     86         QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_DYNAMIC_DTIM, extended_dtim)) {
     87         ALOGE("wifi_extended_dtim_config_set(): failed to put vendor data. "
     88             "Error:%d", ret);
     89         goto cleanup;
     90     }
     91     wifiConfigCommand->attr_end(nlData);
     92 
     93     /* Send the NL msg. */
     94     wifiConfigCommand->waitForRsp(false);
     95     ret = wifiConfigCommand->requestEvent();
     96     if (ret != 0) {
     97         ALOGE("wifi_extended_dtim_config_set(): requestEvent Error:%d", ret);
     98         goto cleanup;
     99     }
    100 
    101 cleanup:
    102     delete wifiConfigCommand;
    103     return (wifi_error)ret;
    104 }
    105 
    106 /* Set the country code to driver. */
    107 wifi_error wifi_set_country_code(wifi_interface_handle iface,
    108                                  const char* country_code)
    109 {
    110     int requestId, ret = 0;
    111     WiFiConfigCommand *wifiConfigCommand;
    112     wifi_handle wifiHandle = getWifiHandle(iface);
    113 
    114     ALOGV("%s: %s", __FUNCTION__, country_code);
    115 
    116     /* No request id from caller, so generate one and pass it on to the driver.
    117      * Generate it randomly.
    118      */
    119     requestId = get_requestid();
    120 
    121     wifiConfigCommand = new WiFiConfigCommand(
    122                             wifiHandle,
    123                             requestId,
    124                             OUI_QCA,
    125                             QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
    126     if (wifiConfigCommand == NULL) {
    127         ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
    128         return WIFI_ERROR_UNKNOWN;
    129     }
    130 
    131     /* Create the NL message with NL80211_CMD_REQ_SET_REG NL cmd. */
    132     ret = wifiConfigCommand->create_generic(NL80211_CMD_REQ_SET_REG);
    133     if (ret < 0) {
    134         ALOGE("wifi_set_country_code: failed to create NL msg. Error:%d", ret);
    135         goto cleanup;
    136     }
    137 
    138     if (wifiConfigCommand->put_string(NL80211_ATTR_REG_ALPHA2, country_code)) {
    139         ALOGE("wifi_set_country_code: put country code failed. Error:%d", ret);
    140         goto cleanup;
    141     }
    142 
    143     /* Send the NL msg. */
    144     wifiConfigCommand->waitForRsp(false);
    145     ret = wifiConfigCommand->requestEvent();
    146     if (ret != 0) {
    147         ALOGE("wifi_set_country_code(): requestEvent Error:%d", ret);
    148         goto cleanup;
    149     }
    150     usleep(WAIT_TIME_FOR_SET_REG_DOMAIN);
    151 
    152 cleanup:
    153     delete wifiConfigCommand;
    154     return (wifi_error)ret;
    155 }
    156 
    157 wifi_error wifi_set_beacon_wifi_iface_stats_averaging_factor(
    158                                                 wifi_request_id id,
    159                                                 wifi_interface_handle iface,
    160                                                 u16 factor)
    161 {
    162     int ret = 0;
    163     WiFiConfigCommand *wifiConfigCommand;
    164     struct nlattr *nlData;
    165     interface_info *ifaceInfo = getIfaceInfo(iface);
    166     wifi_handle wifiHandle = getWifiHandle(iface);
    167 
    168     ALOGV("%s factor:%u", __FUNCTION__, factor);
    169     wifiConfigCommand = new WiFiConfigCommand(
    170                             wifiHandle,
    171                             id,
    172                             OUI_QCA,
    173                             QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
    174     if (wifiConfigCommand == NULL) {
    175         ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
    176         return WIFI_ERROR_UNKNOWN;
    177     }
    178 
    179     /* Create the NL message. */
    180     ret = wifiConfigCommand->create();
    181     if (ret < 0) {
    182         ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor: failed to "
    183             "create NL msg. Error:%d", ret);
    184         goto cleanup;
    185     }
    186 
    187     /* Set the interface Id of the message. */
    188     ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
    189     if (ret < 0) {
    190         ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor: failed to "
    191             "set iface id. Error:%d", ret);
    192         goto cleanup;
    193     }
    194 
    195     /* Add the vendor specific attributes for the NL command. */
    196     nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
    197     if (!nlData) {
    198         ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor: failed "
    199             "attr_start for VENDOR_DATA. Error:%d", ret);
    200         goto cleanup;
    201     }
    202 
    203     if (wifiConfigCommand->put_u32(
    204         QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_STATS_AVG_FACTOR, factor)) {
    205         ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor(): failed to "
    206             "put vendor data. Error:%d", ret);
    207         goto cleanup;
    208     }
    209     wifiConfigCommand->attr_end(nlData);
    210 
    211     /* Send the NL msg. */
    212     wifiConfigCommand->waitForRsp(false);
    213     ret = wifiConfigCommand->requestEvent();
    214     if (ret != 0) {
    215         ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor(): "
    216             "requestEvent Error:%d", ret);
    217         goto cleanup;
    218     }
    219 
    220 cleanup:
    221     delete wifiConfigCommand;
    222     return (wifi_error)ret;
    223 }
    224 
    225 wifi_error wifi_set_guard_time(wifi_request_id id,
    226                                wifi_interface_handle iface,
    227                                u32 guard_time)
    228 {
    229     int ret = 0;
    230     WiFiConfigCommand *wifiConfigCommand;
    231     struct nlattr *nlData;
    232     interface_info *ifaceInfo = getIfaceInfo(iface);
    233     wifi_handle wifiHandle = getWifiHandle(iface);
    234 
    235     ALOGV("%s : guard_time:%u", __FUNCTION__, guard_time);
    236 
    237     wifiConfigCommand = new WiFiConfigCommand(
    238                             wifiHandle,
    239                             id,
    240                             OUI_QCA,
    241                             QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
    242     if (wifiConfigCommand == NULL) {
    243         ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
    244         return WIFI_ERROR_UNKNOWN;
    245     }
    246 
    247     /* Create the NL message. */
    248     ret = wifiConfigCommand->create();
    249     if (ret < 0) {
    250         ALOGE("wifi_set_guard_time: failed to create NL msg. Error:%d", ret);
    251         goto cleanup;
    252     }
    253 
    254     /* Set the interface Id of the message. */
    255     ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
    256     if (ret < 0) {
    257         ALOGE("wifi_set_guard_time: failed to set iface id. Error:%d", ret);
    258         goto cleanup;
    259     }
    260 
    261     /* Add the vendor specific attributes for the NL command. */
    262     nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
    263     if (!nlData) {
    264         ALOGE("wifi_set_guard_time: failed attr_start for VENDOR_DATA. "
    265             "Error:%d", ret);
    266         goto cleanup;
    267     }
    268 
    269     if (wifiConfigCommand->put_u32(
    270         QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_GUARD_TIME, guard_time)) {
    271         ALOGE("wifi_set_guard_time: failed to add vendor data.");
    272         goto cleanup;
    273     }
    274     wifiConfigCommand->attr_end(nlData);
    275 
    276     /* Send the NL msg. */
    277     wifiConfigCommand->waitForRsp(false);
    278     ret = wifiConfigCommand->requestEvent();
    279     if (ret != 0) {
    280         ALOGE("wifi_set_guard_time(): requestEvent Error:%d", ret);
    281         goto cleanup;
    282     }
    283 
    284 cleanup:
    285     delete wifiConfigCommand;
    286     return (wifi_error)ret;
    287 }
    288 
    289 WiFiConfigCommand::WiFiConfigCommand(wifi_handle handle,
    290                                      int id, u32 vendor_id,
    291                                      u32 subcmd)
    292         : WifiVendorCommand(handle, id, vendor_id, subcmd)
    293 {
    294     /* Initialize the member data variables here */
    295     mWaitforRsp = false;
    296     mRequestId = id;
    297 }
    298 
    299 WiFiConfigCommand::~WiFiConfigCommand()
    300 {
    301     unregisterVendorHandler(mVendor_id, mSubcmd);
    302 }
    303 
    304 /* This function implements creation of Vendor command */
    305 int WiFiConfigCommand::create() {
    306     int ret = mMsg.create(NL80211_CMD_VENDOR, 0, 0);
    307     if (ret < 0) {
    308         return ret;
    309     }
    310 
    311     /* Insert the oui in the msg */
    312     ret = mMsg.put_u32(NL80211_ATTR_VENDOR_ID, mVendor_id);
    313     if (ret < 0)
    314         goto out;
    315     /* Insert the subcmd in the msg */
    316     ret = mMsg.put_u32(NL80211_ATTR_VENDOR_SUBCMD, mSubcmd);
    317     if (ret < 0)
    318         goto out;
    319 out:
    320     return ret;
    321 }
    322 
    323 /* This function implements creation of generic NL command */
    324 int WiFiConfigCommand::create_generic(u8 cmdId) {
    325     int ret = mMsg.create(cmdId, 0, 0);
    326     return ret;
    327 }
    328 
    329 void WiFiConfigCommand::waitForRsp(bool wait)
    330 {
    331     mWaitforRsp = wait;
    332 }
    333 
    334 /* Callback handlers registered for nl message send */
    335 static int error_handler_wifi_config(struct sockaddr_nl *nla,
    336                                      struct nlmsgerr *err,
    337                                      void *arg)
    338 {
    339     struct sockaddr_nl *tmp;
    340     int *ret = (int *)arg;
    341     tmp = nla;
    342     *ret = err->error;
    343     ALOGE("%s: Error code:%d (%s)", __FUNCTION__, *ret, strerror(-(*ret)));
    344     return NL_STOP;
    345 }
    346 
    347 /* Callback handlers registered for nl message send */
    348 static int ack_handler_wifi_config(struct nl_msg *msg, void *arg)
    349 {
    350     int *ret = (int *)arg;
    351     struct nl_msg * a;
    352 
    353     a = msg;
    354     *ret = 0;
    355     return NL_STOP;
    356 }
    357 
    358 /* Callback handlers registered for nl message send */
    359 static int finish_handler_wifi_config(struct nl_msg *msg, void *arg)
    360 {
    361   int *ret = (int *)arg;
    362   struct nl_msg * a;
    363 
    364   a = msg;
    365   *ret = 0;
    366   return NL_SKIP;
    367 }
    368 
    369 /*
    370  * Override base class requestEvent and implement little differently here.
    371  * This will send the request message.
    372  * We don't wait for any response back in case of wificonfig,
    373  * thus no wait for condition.
    374  */
    375 int WiFiConfigCommand::requestEvent()
    376 {
    377     int res = -1;
    378     struct nl_cb *cb;
    379 
    380     cb = nl_cb_alloc(NL_CB_DEFAULT);
    381     if (!cb) {
    382         ALOGE("%s: Callback allocation failed",__FUNCTION__);
    383         res = -1;
    384         goto out;
    385     }
    386 
    387     res = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage());
    388     if (res < 0)
    389         goto out;
    390     res = 1;
    391 
    392     nl_cb_err(cb, NL_CB_CUSTOM, error_handler_wifi_config, &res);
    393     nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler_wifi_config,
    394         &res);
    395     nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler_wifi_config, &res);
    396 
    397     /* Err is populated as part of finish_handler. */
    398     while (res > 0){
    399          nl_recvmsgs(mInfo->cmd_sock, cb);
    400     }
    401 
    402     /* Only wait for the asynchronous event if HDD returns success, res=0 */
    403     if (!res && (mWaitforRsp == true)) {
    404         struct timespec abstime;
    405         abstime.tv_sec = 4;
    406         abstime.tv_nsec = 0;
    407         res = mCondition.wait(abstime);
    408         if (res == ETIMEDOUT)
    409         {
    410             ALOGE("%s: Time out happened.", __FUNCTION__);
    411         }
    412         ALOGV("%s: Command invoked return value:%d, mWaitForRsp=%d",
    413             __FUNCTION__, res, mWaitforRsp);
    414     }
    415 out:
    416     /* Cleanup the mMsg */
    417     mMsg.destroy();
    418     return res;
    419 }
    420 
    421