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