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