1 /* Copyright (c) 2015, 2018 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 <unistd.h>
36 #include "wificonfigcommand.h"
37
38 /* Implementation of the API functions exposed in wifi_config.h */
wifi_extended_dtim_config_set(wifi_request_id id,wifi_interface_handle iface,int extended_dtim)39 wifi_error wifi_extended_dtim_config_set(wifi_request_id id,
40 wifi_interface_handle iface,
41 int extended_dtim)
42 {
43 wifi_error ret;
44 WiFiConfigCommand *wifiConfigCommand;
45 struct nlattr *nlData;
46 interface_info *ifaceInfo = getIfaceInfo(iface);
47 wifi_handle wifiHandle = getWifiHandle(iface);
48
49 ALOGV("%s: extended_dtim:%d", __FUNCTION__, extended_dtim);
50
51 wifiConfigCommand = new WiFiConfigCommand(
52 wifiHandle,
53 id,
54 OUI_QCA,
55 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
56
57 if (wifiConfigCommand == NULL) {
58 ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
59 return WIFI_ERROR_UNKNOWN;
60 }
61
62 /* Create the NL message. */
63 ret = wifiConfigCommand->create();
64 if (ret != WIFI_SUCCESS) {
65 ALOGE("wifi_extended_dtim_config_set: failed to create NL msg. "
66 "Error:%d", ret);
67 goto cleanup;
68 }
69
70 /* Set the interface Id of the message. */
71 ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
72 if (ret != WIFI_SUCCESS) {
73 ALOGE("wifi_extended_dtim_config_set: failed to set iface id. "
74 "Error:%d", ret);
75 goto cleanup;
76 }
77
78 /* Add the vendor specific attributes for the NL command. */
79 nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
80 if (!nlData) {
81 ALOGE("wifi_extended_dtim_config_set: failed attr_start for "
82 "VENDOR_DATA. Error:%d", ret);
83 goto cleanup;
84 }
85
86 ret = wifiConfigCommand->put_u32(
87 QCA_WLAN_VENDOR_ATTR_CONFIG_DYNAMIC_DTIM, extended_dtim);
88 if (ret != WIFI_SUCCESS) {
89 ALOGE("wifi_extended_dtim_config_set(): failed to put vendor data. "
90 "Error:%d", ret);
91 goto cleanup;
92 }
93 wifiConfigCommand->attr_end(nlData);
94
95 /* Send the NL msg. */
96 wifiConfigCommand->waitForRsp(false);
97 ret = wifiConfigCommand->requestEvent();
98 if (ret != WIFI_SUCCESS) {
99 ALOGE("wifi_extended_dtim_config_set(): requestEvent Error:%d", ret);
100 goto cleanup;
101 }
102
103 cleanup:
104 delete wifiConfigCommand;
105 return ret;
106 }
107
check_feature(enum qca_wlan_vendor_features feature,features_info * info)108 int check_feature(enum qca_wlan_vendor_features feature, features_info *info)
109 {
110 size_t idx = feature / 8;
111
112 return (idx < info->flags_len) &&
113 (info->flags[idx] & BIT(feature % 8));
114 }
115
116 /* Set the country code to driver. */
wifi_set_country_code(wifi_interface_handle iface,const char * country_code)117 wifi_error wifi_set_country_code(wifi_interface_handle iface,
118 const char* country_code)
119 {
120 int requestId;
121 wifi_error ret;
122 WiFiConfigCommand *wifiConfigCommand;
123 wifi_handle wifiHandle = getWifiHandle(iface);
124 hal_info *info = getHalInfo(wifiHandle);
125
126 ALOGV("%s: %s", __FUNCTION__, country_code);
127
128 /* No request id from caller, so generate one and pass it on to the driver.
129 * Generate it randomly.
130 */
131 requestId = get_requestid();
132
133 wifiConfigCommand = new WiFiConfigCommand(
134 wifiHandle,
135 requestId,
136 OUI_QCA,
137 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
138 if (wifiConfigCommand == NULL) {
139 ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
140 return WIFI_ERROR_UNKNOWN;
141 }
142
143 /* Create the NL message with NL80211_CMD_REQ_SET_REG NL cmd. */
144 ret = wifiConfigCommand->create_generic(NL80211_CMD_REQ_SET_REG);
145 if (ret != WIFI_SUCCESS) {
146 ALOGE("wifi_set_country_code: failed to create NL msg. Error:%d", ret);
147 goto cleanup;
148 }
149
150 ret = wifiConfigCommand->put_string(NL80211_ATTR_REG_ALPHA2, country_code);
151 if (ret != WIFI_SUCCESS) {
152 ALOGE("wifi_set_country_code: put country code failed. Error:%d", ret);
153 goto cleanup;
154 }
155
156 if (check_feature(QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY,
157 &info->driver_supported_features)) {
158 ret = wifiConfigCommand->put_u32(NL80211_ATTR_USER_REG_HINT_TYPE,
159 NL80211_USER_REG_HINT_CELL_BASE);
160 if (ret != WIFI_SUCCESS) {
161 ALOGE("wifi_set_country_code: put reg hint type failed. Error:%d",
162 ret);
163 goto cleanup;
164 }
165 }
166
167
168 /* Send the NL msg. */
169 wifiConfigCommand->waitForRsp(false);
170 ret = wifiConfigCommand->requestEvent();
171 if (ret != WIFI_SUCCESS) {
172 ALOGE("wifi_set_country_code(): requestEvent Error:%d", ret);
173 goto cleanup;
174 }
175 usleep(WAIT_TIME_FOR_SET_REG_DOMAIN);
176
177 cleanup:
178 delete wifiConfigCommand;
179 return ret;
180 }
181
wifi_set_beacon_wifi_iface_stats_averaging_factor(wifi_request_id id,wifi_interface_handle iface,u16 factor)182 wifi_error wifi_set_beacon_wifi_iface_stats_averaging_factor(
183 wifi_request_id id,
184 wifi_interface_handle iface,
185 u16 factor)
186 {
187 wifi_error ret;
188 WiFiConfigCommand *wifiConfigCommand;
189 struct nlattr *nlData;
190 interface_info *ifaceInfo = getIfaceInfo(iface);
191 wifi_handle wifiHandle = getWifiHandle(iface);
192
193 ALOGV("%s factor:%u", __FUNCTION__, factor);
194 wifiConfigCommand = new WiFiConfigCommand(
195 wifiHandle,
196 id,
197 OUI_QCA,
198 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
199 if (wifiConfigCommand == NULL) {
200 ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
201 return WIFI_ERROR_UNKNOWN;
202 }
203
204 /* Create the NL message. */
205 ret = wifiConfigCommand->create();
206 if (ret != WIFI_SUCCESS) {
207 ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor: failed to "
208 "create NL msg. Error:%d", ret);
209 goto cleanup;
210 }
211
212 /* Set the interface Id of the message. */
213 ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
214 if (ret != WIFI_SUCCESS) {
215 ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor: failed to "
216 "set iface id. Error:%d", ret);
217 goto cleanup;
218 }
219
220 /* Add the vendor specific attributes for the NL command. */
221 nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
222 if (!nlData) {
223 ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor: failed "
224 "attr_start for VENDOR_DATA. Error:%d", ret);
225 goto cleanup;
226 }
227
228 if (wifiConfigCommand->put_u32(
229 QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR, factor)) {
230 ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor(): failed to "
231 "put vendor data. Error:%d", ret);
232 goto cleanup;
233 }
234 wifiConfigCommand->attr_end(nlData);
235
236 /* Send the NL msg. */
237 wifiConfigCommand->waitForRsp(false);
238 ret = wifiConfigCommand->requestEvent();
239 if (ret != WIFI_SUCCESS) {
240 ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor(): "
241 "requestEvent Error:%d", ret);
242 goto cleanup;
243 }
244
245 cleanup:
246 delete wifiConfigCommand;
247 return ret;
248 }
249
wifi_set_guard_time(wifi_request_id id,wifi_interface_handle iface,u32 guard_time)250 wifi_error wifi_set_guard_time(wifi_request_id id,
251 wifi_interface_handle iface,
252 u32 guard_time)
253 {
254 wifi_error ret;
255 WiFiConfigCommand *wifiConfigCommand;
256 struct nlattr *nlData;
257 interface_info *ifaceInfo = getIfaceInfo(iface);
258 wifi_handle wifiHandle = getWifiHandle(iface);
259
260 ALOGV("%s : guard_time:%u", __FUNCTION__, guard_time);
261
262 wifiConfigCommand = new WiFiConfigCommand(
263 wifiHandle,
264 id,
265 OUI_QCA,
266 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
267 if (wifiConfigCommand == NULL) {
268 ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
269 return WIFI_ERROR_UNKNOWN;
270 }
271
272 /* Create the NL message. */
273 ret = wifiConfigCommand->create();
274 if (ret != WIFI_SUCCESS) {
275 ALOGE("wifi_set_guard_time: failed to create NL msg. Error:%d", ret);
276 goto cleanup;
277 }
278
279 /* Set the interface Id of the message. */
280 ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
281 if (ret != WIFI_SUCCESS) {
282 ALOGE("wifi_set_guard_time: failed to set iface id. Error:%d", ret);
283 goto cleanup;
284 }
285
286 /* Add the vendor specific attributes for the NL command. */
287 nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
288 if (!nlData) {
289 ALOGE("wifi_set_guard_time: failed attr_start for VENDOR_DATA. "
290 "Error:%d", ret);
291 goto cleanup;
292 }
293
294 if (wifiConfigCommand->put_u32(
295 QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME, guard_time)) {
296 ALOGE("wifi_set_guard_time: failed to add vendor data.");
297 goto cleanup;
298 }
299 wifiConfigCommand->attr_end(nlData);
300
301 /* Send the NL msg. */
302 wifiConfigCommand->waitForRsp(false);
303 ret = wifiConfigCommand->requestEvent();
304 if (ret != WIFI_SUCCESS) {
305 ALOGE("wifi_set_guard_time(): requestEvent Error:%d", ret);
306 goto cleanup;
307 }
308
309 cleanup:
310 delete wifiConfigCommand;
311 return ret;
312 }
313
wifi_select_tx_power_scenario(wifi_interface_handle handle,wifi_power_scenario scenario)314 wifi_error wifi_select_tx_power_scenario(wifi_interface_handle handle,
315 wifi_power_scenario scenario)
316 {
317 wifi_error ret;
318 WiFiConfigCommand *wifiConfigCommand;
319 struct nlattr *nlData;
320 interface_info *ifaceInfo = getIfaceInfo(handle);
321 wifi_handle wifiHandle = getWifiHandle(handle);
322 u32 bdf_file = 0;
323
324 ALOGV("%s : power scenario:%d", __FUNCTION__, scenario);
325
326 wifiConfigCommand = new WiFiConfigCommand(
327 wifiHandle,
328 1,
329 OUI_QCA,
330 QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS);
331 if (wifiConfigCommand == NULL) {
332 ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
333 return WIFI_ERROR_UNKNOWN;
334 }
335
336 /* Create the NL message. */
337 ret = wifiConfigCommand->create();
338 if (ret != WIFI_SUCCESS) {
339 ALOGE("wifi_select_tx_power_scenario: failed to create NL msg. Error:%d", ret);
340 goto cleanup;
341 }
342
343 /* Set the interface Id of the message. */
344 ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
345 if (ret != WIFI_SUCCESS) {
346 ALOGE("wifi_select_tx_power_scenario: failed to set iface id. Error:%d", ret);
347 goto cleanup;
348 }
349
350 /* Add the vendor specific attributes for the NL command. */
351 nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
352 if (!nlData) {
353 ALOGE("wifi_select_tx_power_scenario: failed attr_start for VENDOR_DATA. "
354 "Error:%d", ret);
355 goto cleanup;
356 }
357
358 switch (scenario) {
359 case WIFI_POWER_SCENARIO_VOICE_CALL:
360 case WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF:
361 case WIFI_POWER_SCENARIO_ON_BODY_BT:
362 bdf_file = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0;
363 break;
364
365 case WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON:
366 bdf_file = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF1;
367 break;
368
369 case WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF:
370 bdf_file = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF2;
371 break;
372
373 case WIFI_POWER_SCENARIO_ON_BODY_CELL_ON:
374 bdf_file = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF3;
375 break;
376
377 default:
378 ALOGE("wifi_select_tx_power_scenario: invalid scenario %d", scenario);
379 ret = WIFI_ERROR_INVALID_ARGS;
380 goto cleanup;
381 }
382
383 if (wifiConfigCommand->put_u32(
384 QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE,
385 bdf_file)) {
386 ALOGE("failed to put SAR_ENABLE");
387 goto cleanup;
388 }
389 wifiConfigCommand->attr_end(nlData);
390
391 ret = wifiConfigCommand->requestEvent();
392 if (ret != WIFI_SUCCESS) {
393 ALOGE("wifi_select_tx_power_scenario(): requestEvent Error:%d", ret);
394 goto cleanup;
395 }
396
397 cleanup:
398 delete wifiConfigCommand;
399 return ret;
400 }
401
wifi_reset_tx_power_scenario(wifi_interface_handle handle)402 wifi_error wifi_reset_tx_power_scenario(wifi_interface_handle handle)
403 {
404 wifi_error ret;
405 WiFiConfigCommand *wifiConfigCommand;
406 struct nlattr *nlData;
407 interface_info *ifaceInfo = getIfaceInfo(handle);
408 wifi_handle wifiHandle = getWifiHandle(handle);
409
410 wifiConfigCommand = new WiFiConfigCommand(
411 wifiHandle,
412 1,
413 OUI_QCA,
414 QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS);
415 if (wifiConfigCommand == NULL) {
416 ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
417 return WIFI_ERROR_UNKNOWN;
418 }
419
420 /* Create the NL message. */
421 ret = wifiConfigCommand->create();
422 if (ret != WIFI_SUCCESS) {
423 ALOGE("wifi_reset_tx_power_scenario: failed to create NL msg. Error:%d", ret);
424 goto cleanup;
425 }
426
427 /* Set the interface Id of the message. */
428 ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
429 if (ret != WIFI_SUCCESS) {
430 ALOGE("wifi_reset_tx_power_scenario: failed to set iface id. Error:%d", ret);
431 goto cleanup;
432 }
433
434 /* Add the vendor specific attributes for the NL command. */
435 nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
436 if (!nlData) {
437 ALOGE("wifi_reset_tx_power_scenario: failed attr_start for VENDOR_DATA. "
438 "Error:%d", ret);
439 goto cleanup;
440 }
441
442 if (wifiConfigCommand->put_u32(QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE,
443 QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE)) {
444 ALOGE("failed to put SAR_ENABLE or NUM_SPECS");
445 goto cleanup;
446 }
447 wifiConfigCommand->attr_end(nlData);
448
449 ret = wifiConfigCommand->requestEvent();
450 if (ret != WIFI_SUCCESS) {
451 ALOGE("wifi_reset_tx_power_scenario(): requestEvent Error:%d", ret);
452 goto cleanup;
453 }
454
455 cleanup:
456 delete wifiConfigCommand;
457 return ret;
458 }
459
wifi_set_latency_mode(wifi_interface_handle handle,wifi_latency_mode mode)460 wifi_error wifi_set_latency_mode(wifi_interface_handle handle,
461 wifi_latency_mode mode) {
462 wifi_error ret;
463 WiFiConfigCommand *wifiConfigCommand;
464 struct nlattr *nlData;
465 u32 latency_mode;
466 interface_info *ifaceInfo = getIfaceInfo(handle);
467 wifi_handle wifiHandle = getWifiHandle(handle);
468 hal_info *info = getHalInfo(wifiHandle);
469
470 ALOGV("%s : latency mode:%d", __FUNCTION__, mode);
471
472 /* Check Supported low-latency capability */
473 if (!(info->supported_feature_set & WIFI_FEATURE_SET_LATENCY_MODE)) {
474 ALOGE("%s: Set latency mode feature not supported %x", __FUNCTION__,
475 info->supported_feature_set);
476 return WIFI_ERROR_NOT_SUPPORTED;
477 }
478
479 wifiConfigCommand = new WiFiConfigCommand(
480 wifiHandle,
481 1,
482 OUI_QCA,
483 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
484 if (wifiConfigCommand == NULL) {
485 ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
486 return WIFI_ERROR_UNKNOWN;
487 }
488
489 /* Create the NL message. */
490 ret = wifiConfigCommand->create();
491 if (ret != WIFI_SUCCESS) {
492 ALOGE("wifi_set_latency_mode: failed to create NL msg. Error:%d", ret);
493 goto cleanup;
494 }
495
496 /* Set the interface Id of the message. */
497 ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
498 if (ret != WIFI_SUCCESS) {
499 ALOGE("wifi_set_latency_mode: failed to set iface id. Error:%d", ret);
500 goto cleanup;
501 }
502
503 /* Add the vendor specific attributes for the NL command. */
504 nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
505 if (!nlData) {
506 ret = WIFI_ERROR_UNKNOWN;
507 ALOGE("wifi_set_latency_mode: failed attr_start for VENDOR_DATA. "
508 "Error:%d", ret);
509 goto cleanup;
510 }
511
512 switch(mode) {
513 case WIFI_LATENCY_MODE_NORMAL:
514 latency_mode = QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_NORMAL;
515 break;
516
517 case WIFI_LATENCY_MODE_LOW:
518 latency_mode = QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_LOW;
519 break;
520
521 default:
522 ALOGE("wifi_set_latency_mode: Invalid mode: %d", mode);
523 ret = WIFI_ERROR_UNKNOWN;
524 goto cleanup;
525 }
526
527 if (wifiConfigCommand->put_u32(
528 QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL,
529 latency_mode)) {
530 ALOGE("wifi_set_latency_mode: failed to put latency mode");
531 ret = WIFI_ERROR_UNKNOWN;
532 goto cleanup;
533 }
534 wifiConfigCommand->attr_end(nlData);
535
536 /* Send the NL msg. */
537 wifiConfigCommand->waitForRsp(false);
538 ret = wifiConfigCommand->requestEvent();
539 if (ret != WIFI_SUCCESS) {
540 ALOGE("wifi_set_latency_mode: requestEvent Error:%d", ret);
541 goto cleanup;
542 }
543
544 cleanup:
545 delete wifiConfigCommand;
546 return ret;
547 }
548
WiFiConfigCommand(wifi_handle handle,int id,u32 vendor_id,u32 subcmd)549 WiFiConfigCommand::WiFiConfigCommand(wifi_handle handle,
550 int id, u32 vendor_id,
551 u32 subcmd)
552 : WifiVendorCommand(handle, id, vendor_id, subcmd)
553 {
554 /* Initialize the member data variables here */
555 mWaitforRsp = false;
556 mRequestId = id;
557 }
558
~WiFiConfigCommand()559 WiFiConfigCommand::~WiFiConfigCommand()
560 {
561 unregisterVendorHandler(mVendor_id, mSubcmd);
562 }
563
564 /* This function implements creation of Vendor command */
create()565 wifi_error WiFiConfigCommand::create()
566 {
567 wifi_error ret = mMsg.create(NL80211_CMD_VENDOR, 0, 0);
568 if (ret != WIFI_SUCCESS)
569 return ret;
570
571 /* Insert the oui in the msg */
572 ret = mMsg.put_u32(NL80211_ATTR_VENDOR_ID, mVendor_id);
573 if (ret != WIFI_SUCCESS)
574 return ret;
575 /* Insert the subcmd in the msg */
576 ret = mMsg.put_u32(NL80211_ATTR_VENDOR_SUBCMD, mSubcmd);
577
578 return ret;
579 }
580
581 /* This function implements creation of generic NL command */
create_generic(u8 cmdId)582 wifi_error WiFiConfigCommand::create_generic(u8 cmdId)
583 {
584 wifi_error ret = mMsg.create(cmdId, 0, 0);
585 return ret;
586 }
587
waitForRsp(bool wait)588 void WiFiConfigCommand::waitForRsp(bool wait)
589 {
590 mWaitforRsp = wait;
591 }
592
593 /* Callback handlers registered for nl message send */
error_handler_wifi_config(struct sockaddr_nl * nla,struct nlmsgerr * err,void * arg)594 static int error_handler_wifi_config(struct sockaddr_nl *nla,
595 struct nlmsgerr *err,
596 void *arg)
597 {
598 struct sockaddr_nl *tmp;
599 int *ret = (int *)arg;
600 tmp = nla;
601 *ret = err->error;
602 ALOGE("%s: Error code:%d (%s)", __FUNCTION__, *ret, strerror(-(*ret)));
603 return NL_STOP;
604 }
605
606 /* Callback handlers registered for nl message send */
ack_handler_wifi_config(struct nl_msg * msg,void * arg)607 static int ack_handler_wifi_config(struct nl_msg *msg, void *arg)
608 {
609 int *ret = (int *)arg;
610 struct nl_msg * a;
611
612 a = msg;
613 *ret = 0;
614 return NL_STOP;
615 }
616
617 /* Callback handlers registered for nl message send */
finish_handler_wifi_config(struct nl_msg * msg,void * arg)618 static int finish_handler_wifi_config(struct nl_msg *msg, void *arg)
619 {
620 int *ret = (int *)arg;
621 struct nl_msg * a;
622
623 a = msg;
624 *ret = 0;
625 return NL_SKIP;
626 }
627
628 /*
629 * Override base class requestEvent and implement little differently here.
630 * This will send the request message.
631 * We don't wait for any response back in case of wificonfig,
632 * thus no wait for condition.
633 */
requestEvent()634 wifi_error WiFiConfigCommand::requestEvent()
635 {
636 int status;
637 wifi_error res = WIFI_SUCCESS;
638 struct nl_cb *cb;
639
640 cb = nl_cb_alloc(NL_CB_DEFAULT);
641 if (!cb) {
642 ALOGE("%s: Callback allocation failed",__FUNCTION__);
643 res = WIFI_ERROR_OUT_OF_MEMORY;
644 goto out;
645 }
646
647 status = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage());
648 if (status < 0) {
649 res = mapKernelErrortoWifiHalError(status);
650 goto out;
651 }
652 status = 1;
653
654 nl_cb_err(cb, NL_CB_CUSTOM, error_handler_wifi_config, &status);
655 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler_wifi_config,
656 &status);
657 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler_wifi_config, &status);
658
659 /* Err is populated as part of finish_handler. */
660 while (status > 0) {
661 nl_recvmsgs(mInfo->cmd_sock, cb);
662 }
663
664 if (status < 0) {
665 res = mapKernelErrortoWifiHalError(status);
666 goto out;
667 }
668
669 if (mWaitforRsp == true) {
670 struct timespec abstime;
671 abstime.tv_sec = 4;
672 abstime.tv_nsec = 0;
673 res = mCondition.wait(abstime);
674 if (res == WIFI_ERROR_TIMED_OUT)
675 ALOGE("%s: Time out happened.", __FUNCTION__);
676
677 ALOGV("%s: Command invoked return value:%d, mWaitForRsp=%d",
678 __FUNCTION__, res, mWaitforRsp);
679 }
680 out:
681 /* Cleanup the mMsg */
682 mMsg.destroy();
683 return res;
684 }
685
686