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