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 <string>
37 #include <net/if.h>
38 #include <vector>
39 #include "wificonfigcommand.h"
40
41 /* 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)42 wifi_error wifi_extended_dtim_config_set(wifi_request_id id,
43 wifi_interface_handle iface,
44 int extended_dtim)
45 {
46 wifi_error ret;
47 WiFiConfigCommand *wifiConfigCommand;
48 struct nlattr *nlData;
49 interface_info *ifaceInfo = getIfaceInfo(iface);
50 wifi_handle wifiHandle = getWifiHandle(iface);
51
52 ALOGV("%s: extended_dtim:%d", __FUNCTION__, extended_dtim);
53
54 wifiConfigCommand = new WiFiConfigCommand(
55 wifiHandle,
56 id,
57 OUI_QCA,
58 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
59
60 if (wifiConfigCommand == NULL) {
61 ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
62 return WIFI_ERROR_UNKNOWN;
63 }
64
65 /* Create the NL message. */
66 ret = wifiConfigCommand->create();
67 if (ret != WIFI_SUCCESS) {
68 ALOGE("wifi_extended_dtim_config_set: failed to create NL msg. "
69 "Error:%d", ret);
70 goto cleanup;
71 }
72
73 /* Set the interface Id of the message. */
74 ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
75 if (ret != WIFI_SUCCESS) {
76 ALOGE("wifi_extended_dtim_config_set: failed to set iface id. "
77 "Error:%d", ret);
78 goto cleanup;
79 }
80
81 /* Add the vendor specific attributes for the NL command. */
82 nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
83 if (!nlData) {
84 ALOGE("wifi_extended_dtim_config_set: failed attr_start for "
85 "VENDOR_DATA. Error:%d", ret);
86 goto cleanup;
87 }
88
89 ret = wifiConfigCommand->put_u32(
90 QCA_WLAN_VENDOR_ATTR_CONFIG_DYNAMIC_DTIM, extended_dtim);
91 if (ret != WIFI_SUCCESS) {
92 ALOGE("wifi_extended_dtim_config_set(): failed to put vendor data. "
93 "Error:%d", ret);
94 goto cleanup;
95 }
96 wifiConfigCommand->attr_end(nlData);
97
98 /* Send the NL msg. */
99 wifiConfigCommand->waitForRsp(false);
100 ret = wifiConfigCommand->requestEvent();
101 if (ret != WIFI_SUCCESS) {
102 ALOGE("wifi_extended_dtim_config_set(): requestEvent Error:%d", ret);
103 goto cleanup;
104 }
105
106 cleanup:
107 delete wifiConfigCommand;
108 return ret;
109 }
110
check_feature(enum qca_wlan_vendor_features feature,features_info * info)111 int check_feature(enum qca_wlan_vendor_features feature, features_info *info)
112 {
113 size_t idx = feature / 8;
114
115 return (idx < info->flags_len) &&
116 (info->flags[idx] & BIT(feature % 8));
117 }
118
119 /* Set the country code to driver. */
wifi_set_country_code(wifi_interface_handle iface,const char * country_code)120 wifi_error wifi_set_country_code(wifi_interface_handle iface,
121 const char* country_code)
122 {
123 int requestId;
124 wifi_error ret;
125 WiFiConfigCommand *wifiConfigCommand;
126 wifi_handle wifiHandle = getWifiHandle(iface);
127 hal_info *info = getHalInfo(wifiHandle);
128
129 ALOGV("%s: %s", __FUNCTION__, country_code);
130
131 /* No request id from caller, so generate one and pass it on to the driver.
132 * Generate it randomly.
133 */
134 requestId = get_requestid();
135
136 wifiConfigCommand = new WiFiConfigCommand(
137 wifiHandle,
138 requestId,
139 OUI_QCA,
140 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
141 if (wifiConfigCommand == NULL) {
142 ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
143 return WIFI_ERROR_UNKNOWN;
144 }
145
146 /* Create the NL message with NL80211_CMD_REQ_SET_REG NL cmd. */
147 ret = wifiConfigCommand->create_generic(NL80211_CMD_REQ_SET_REG);
148 if (ret != WIFI_SUCCESS) {
149 ALOGE("wifi_set_country_code: failed to create NL msg. Error:%d", ret);
150 goto cleanup;
151 }
152
153 ret = wifiConfigCommand->put_string(NL80211_ATTR_REG_ALPHA2, country_code);
154 if (ret != WIFI_SUCCESS) {
155 ALOGE("wifi_set_country_code: put country code failed. Error:%d", ret);
156 goto cleanup;
157 }
158
159 if (check_feature(QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY,
160 &info->driver_supported_features)) {
161 ret = wifiConfigCommand->put_u32(NL80211_ATTR_USER_REG_HINT_TYPE,
162 NL80211_USER_REG_HINT_CELL_BASE);
163 if (ret != WIFI_SUCCESS) {
164 ALOGE("wifi_set_country_code: put reg hint type failed. Error:%d",
165 ret);
166 goto cleanup;
167 }
168 }
169
170
171 /* Send the NL msg. */
172 wifiConfigCommand->waitForRsp(false);
173 ret = wifiConfigCommand->requestEvent();
174 if (ret != WIFI_SUCCESS) {
175 ALOGE("wifi_set_country_code(): requestEvent Error:%d", ret);
176 goto cleanup;
177 }
178 usleep(WAIT_TIME_FOR_SET_REG_DOMAIN);
179
180 cleanup:
181 delete wifiConfigCommand;
182 return ret;
183 }
184
wifi_set_beacon_wifi_iface_stats_averaging_factor(wifi_request_id id,wifi_interface_handle iface,u16 factor)185 wifi_error wifi_set_beacon_wifi_iface_stats_averaging_factor(
186 wifi_request_id id,
187 wifi_interface_handle iface,
188 u16 factor)
189 {
190 wifi_error ret;
191 WiFiConfigCommand *wifiConfigCommand;
192 struct nlattr *nlData;
193 interface_info *ifaceInfo = getIfaceInfo(iface);
194 wifi_handle wifiHandle = getWifiHandle(iface);
195
196 ALOGV("%s factor:%u", __FUNCTION__, factor);
197 wifiConfigCommand = new WiFiConfigCommand(
198 wifiHandle,
199 id,
200 OUI_QCA,
201 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
202 if (wifiConfigCommand == NULL) {
203 ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
204 return WIFI_ERROR_UNKNOWN;
205 }
206
207 /* Create the NL message. */
208 ret = wifiConfigCommand->create();
209 if (ret != WIFI_SUCCESS) {
210 ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor: failed to "
211 "create NL msg. Error:%d", ret);
212 goto cleanup;
213 }
214
215 /* Set the interface Id of the message. */
216 ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
217 if (ret != WIFI_SUCCESS) {
218 ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor: failed to "
219 "set iface id. Error:%d", ret);
220 goto cleanup;
221 }
222
223 /* Add the vendor specific attributes for the NL command. */
224 nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
225 if (!nlData) {
226 ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor: failed "
227 "attr_start for VENDOR_DATA. Error:%d", ret);
228 goto cleanup;
229 }
230
231 if (wifiConfigCommand->put_u32(
232 QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR, factor)) {
233 ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor(): failed to "
234 "put vendor data. Error:%d", ret);
235 goto cleanup;
236 }
237 wifiConfigCommand->attr_end(nlData);
238
239 /* Send the NL msg. */
240 wifiConfigCommand->waitForRsp(false);
241 ret = wifiConfigCommand->requestEvent();
242 if (ret != WIFI_SUCCESS) {
243 ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor(): "
244 "requestEvent Error:%d", ret);
245 goto cleanup;
246 }
247
248 cleanup:
249 delete wifiConfigCommand;
250 return ret;
251 }
252
wifi_set_guard_time(wifi_request_id id,wifi_interface_handle iface,u32 guard_time)253 wifi_error wifi_set_guard_time(wifi_request_id id,
254 wifi_interface_handle iface,
255 u32 guard_time)
256 {
257 wifi_error ret;
258 WiFiConfigCommand *wifiConfigCommand;
259 struct nlattr *nlData;
260 interface_info *ifaceInfo = getIfaceInfo(iface);
261 wifi_handle wifiHandle = getWifiHandle(iface);
262
263 ALOGV("%s : guard_time:%u", __FUNCTION__, guard_time);
264
265 wifiConfigCommand = new WiFiConfigCommand(
266 wifiHandle,
267 id,
268 OUI_QCA,
269 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
270 if (wifiConfigCommand == NULL) {
271 ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
272 return WIFI_ERROR_UNKNOWN;
273 }
274
275 /* Create the NL message. */
276 ret = wifiConfigCommand->create();
277 if (ret != WIFI_SUCCESS) {
278 ALOGE("wifi_set_guard_time: failed to create NL msg. Error:%d", ret);
279 goto cleanup;
280 }
281
282 /* Set the interface Id of the message. */
283 ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
284 if (ret != WIFI_SUCCESS) {
285 ALOGE("wifi_set_guard_time: failed to set iface id. Error:%d", ret);
286 goto cleanup;
287 }
288
289 /* Add the vendor specific attributes for the NL command. */
290 nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
291 if (!nlData) {
292 ALOGE("wifi_set_guard_time: failed attr_start for VENDOR_DATA. "
293 "Error:%d", ret);
294 goto cleanup;
295 }
296
297 if (wifiConfigCommand->put_u32(
298 QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME, guard_time)) {
299 ALOGE("wifi_set_guard_time: failed to add vendor data.");
300 goto cleanup;
301 }
302 wifiConfigCommand->attr_end(nlData);
303
304 /* Send the NL msg. */
305 wifiConfigCommand->waitForRsp(false);
306 ret = wifiConfigCommand->requestEvent();
307 if (ret != WIFI_SUCCESS) {
308 ALOGE("wifi_set_guard_time(): requestEvent Error:%d", ret);
309 goto cleanup;
310 }
311
312 cleanup:
313 delete wifiConfigCommand;
314 return ret;
315 }
316
wifi_select_tx_power_scenario(wifi_interface_handle handle,wifi_power_scenario scenario)317 wifi_error wifi_select_tx_power_scenario(wifi_interface_handle handle,
318 wifi_power_scenario scenario)
319 {
320 wifi_error ret;
321 WiFiConfigCommand *wifiConfigCommand;
322 struct nlattr *nlData;
323 interface_info *ifaceInfo = getIfaceInfo(handle);
324 wifi_handle wifiHandle = getWifiHandle(handle);
325 u32 bdf_file = 0;
326
327 ALOGV("%s : power scenario:%d", __FUNCTION__, scenario);
328
329 wifiConfigCommand = new WiFiConfigCommand(
330 wifiHandle,
331 1,
332 OUI_QCA,
333 QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS);
334 if (wifiConfigCommand == NULL) {
335 ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
336 return WIFI_ERROR_UNKNOWN;
337 }
338
339 /* Create the NL message. */
340 ret = wifiConfigCommand->create();
341 if (ret != WIFI_SUCCESS) {
342 ALOGE("wifi_select_tx_power_scenario: failed to create NL msg. Error:%d", ret);
343 goto cleanup;
344 }
345
346 /* Set the interface Id of the message. */
347 ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
348 if (ret != WIFI_SUCCESS) {
349 ALOGE("wifi_select_tx_power_scenario: failed to set iface id. Error:%d", ret);
350 goto cleanup;
351 }
352
353 /* Add the vendor specific attributes for the NL command. */
354 nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
355 if (!nlData) {
356 ALOGE("wifi_select_tx_power_scenario: failed attr_start for VENDOR_DATA. "
357 "Error:%d", ret);
358 goto cleanup;
359 }
360
361 switch (scenario) {
362 case WIFI_POWER_SCENARIO_VOICE_CALL:
363 case WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF:
364 case WIFI_POWER_SCENARIO_ON_BODY_BT:
365 bdf_file = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0;
366 break;
367
368 case WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON:
369 bdf_file = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF1;
370 break;
371
372 case WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF:
373 bdf_file = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF2;
374 break;
375
376 case WIFI_POWER_SCENARIO_ON_BODY_CELL_ON:
377 bdf_file = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF3;
378 break;
379
380 default:
381 ALOGE("wifi_select_tx_power_scenario: invalid scenario %d", scenario);
382 ret = WIFI_ERROR_INVALID_ARGS;
383 goto cleanup;
384 }
385
386 if (wifiConfigCommand->put_u32(
387 QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE,
388 bdf_file)) {
389 ALOGE("failed to put SAR_ENABLE");
390 goto cleanup;
391 }
392 wifiConfigCommand->attr_end(nlData);
393
394 ret = wifiConfigCommand->requestEvent();
395 if (ret != WIFI_SUCCESS) {
396 ALOGE("wifi_select_tx_power_scenario(): requestEvent Error:%d", ret);
397 goto cleanup;
398 }
399
400 cleanup:
401 delete wifiConfigCommand;
402 return ret;
403 }
404
wifi_reset_tx_power_scenario(wifi_interface_handle handle)405 wifi_error wifi_reset_tx_power_scenario(wifi_interface_handle handle)
406 {
407 wifi_error ret;
408 WiFiConfigCommand *wifiConfigCommand;
409 struct nlattr *nlData;
410 interface_info *ifaceInfo = getIfaceInfo(handle);
411 wifi_handle wifiHandle = getWifiHandle(handle);
412
413 wifiConfigCommand = new WiFiConfigCommand(
414 wifiHandle,
415 1,
416 OUI_QCA,
417 QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS);
418 if (wifiConfigCommand == NULL) {
419 ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
420 return WIFI_ERROR_UNKNOWN;
421 }
422
423 /* Create the NL message. */
424 ret = wifiConfigCommand->create();
425 if (ret != WIFI_SUCCESS) {
426 ALOGE("wifi_reset_tx_power_scenario: failed to create NL msg. Error:%d", ret);
427 goto cleanup;
428 }
429
430 /* Set the interface Id of the message. */
431 ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
432 if (ret != WIFI_SUCCESS) {
433 ALOGE("wifi_reset_tx_power_scenario: failed to set iface id. Error:%d", ret);
434 goto cleanup;
435 }
436
437 /* Add the vendor specific attributes for the NL command. */
438 nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
439 if (!nlData) {
440 ALOGE("wifi_reset_tx_power_scenario: failed attr_start for VENDOR_DATA. "
441 "Error:%d", ret);
442 goto cleanup;
443 }
444
445 if (wifiConfigCommand->put_u32(QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE,
446 QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE)) {
447 ALOGE("failed to put SAR_ENABLE or NUM_SPECS");
448 goto cleanup;
449 }
450 wifiConfigCommand->attr_end(nlData);
451
452 ret = wifiConfigCommand->requestEvent();
453 if (ret != WIFI_SUCCESS) {
454 ALOGE("wifi_reset_tx_power_scenario(): requestEvent Error:%d", ret);
455 goto cleanup;
456 }
457
458 cleanup:
459 delete wifiConfigCommand;
460 return ret;
461 }
462
wifi_set_latency_mode(wifi_interface_handle handle,wifi_latency_mode mode)463 wifi_error wifi_set_latency_mode(wifi_interface_handle handle,
464 wifi_latency_mode mode) {
465 wifi_error ret;
466 WiFiConfigCommand *wifiConfigCommand;
467 struct nlattr *nlData;
468 u32 latency_mode;
469 interface_info *ifaceInfo = getIfaceInfo(handle);
470 wifi_handle wifiHandle = getWifiHandle(handle);
471 hal_info *info = getHalInfo(wifiHandle);
472
473 ALOGV("%s : latency mode:%d", __FUNCTION__, mode);
474
475 /* Check Supported low-latency capability */
476 if (!(info->supported_feature_set & WIFI_FEATURE_SET_LATENCY_MODE)) {
477 ALOGE("%s: Set latency mode feature not supported 0x%" PRIx64, __FUNCTION__,
478 info->supported_feature_set);
479 return WIFI_ERROR_NOT_SUPPORTED;
480 }
481
482 wifiConfigCommand = new WiFiConfigCommand(
483 wifiHandle,
484 1,
485 OUI_QCA,
486 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
487 if (wifiConfigCommand == NULL) {
488 ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
489 return WIFI_ERROR_UNKNOWN;
490 }
491
492 /* Create the NL message. */
493 ret = wifiConfigCommand->create();
494 if (ret != WIFI_SUCCESS) {
495 ALOGE("wifi_set_latency_mode: failed to create NL msg. Error:%d", ret);
496 goto cleanup;
497 }
498
499 /* Set the interface Id of the message. */
500 ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
501 if (ret != WIFI_SUCCESS) {
502 ALOGE("wifi_set_latency_mode: failed to set iface id. Error:%d", ret);
503 goto cleanup;
504 }
505
506 /* Add the vendor specific attributes for the NL command. */
507 nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
508 if (!nlData) {
509 ret = WIFI_ERROR_UNKNOWN;
510 ALOGE("wifi_set_latency_mode: failed attr_start for VENDOR_DATA. "
511 "Error:%d", ret);
512 goto cleanup;
513 }
514
515 switch(mode) {
516 case WIFI_LATENCY_MODE_NORMAL:
517 latency_mode = QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_NORMAL;
518 break;
519
520 case WIFI_LATENCY_MODE_LOW:
521 latency_mode = QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_LOW;
522 break;
523
524 default:
525 ALOGE("wifi_set_latency_mode: Invalid mode: %d", mode);
526 ret = WIFI_ERROR_UNKNOWN;
527 goto cleanup;
528 }
529
530 if (wifiConfigCommand->put_u32(
531 QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL,
532 latency_mode)) {
533 ALOGE("wifi_set_latency_mode: failed to put latency mode");
534 ret = WIFI_ERROR_UNKNOWN;
535 goto cleanup;
536 }
537 wifiConfigCommand->attr_end(nlData);
538
539 /* Send the NL msg. */
540 wifiConfigCommand->waitForRsp(false);
541 ret = wifiConfigCommand->requestEvent();
542 if (ret != WIFI_SUCCESS) {
543 ALOGE("wifi_set_latency_mode: requestEvent Error:%d", ret);
544 goto cleanup;
545 }
546
547 cleanup:
548 delete wifiConfigCommand;
549 return ret;
550 }
551
wifi_set_thermal_mitigation_mode(wifi_handle handle,wifi_thermal_mode mode,u32 completion_window)552 wifi_error wifi_set_thermal_mitigation_mode(wifi_handle handle,
553 wifi_thermal_mode mode,
554 u32 completion_window)
555 {
556 wifi_error ret;
557 WiFiConfigCommand *wifiConfigCommand;
558 struct nlattr *nlData;
559 u32 qca_vendor_thermal_level;
560 hal_info *info = getHalInfo(handle);
561
562 if (!info || info->num_interfaces < 1) {
563 ALOGE("%s: Error wifi_handle NULL or base wlan interface not present",
564 __FUNCTION__);
565 return WIFI_ERROR_UNKNOWN;
566 }
567
568 wifiConfigCommand = new WiFiConfigCommand(
569 handle,
570 1,
571 OUI_QCA,
572 QCA_NL80211_VENDOR_SUBCMD_THERMAL_CMD);
573 if (wifiConfigCommand == NULL) {
574 ALOGE("%s: Error, Failed to create wifiConfigCommand", __FUNCTION__);
575 return WIFI_ERROR_UNKNOWN;
576 }
577
578 /* Create the NL message. */
579 ret = wifiConfigCommand->create();
580 if (ret != WIFI_SUCCESS) {
581 ALOGE("Failed to create thermal vendor command, Error:%d", ret);
582 goto cleanup;
583 }
584
585 /* Set the interface Id of the message. */
586 if (wifiConfigCommand->put_u32(NL80211_ATTR_IFINDEX,
587 info->interfaces[0]->id)) {
588 ALOGE("%s: Failed to put iface id", __FUNCTION__);
589 goto cleanup;
590 }
591
592 nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
593 if (!nlData) {
594 ALOGE("%s: Failed in attr_start for VENDOR_DATA, Error:%d",
595 __FUNCTION__, ret);
596 goto cleanup;
597 }
598
599 if (wifiConfigCommand->put_u32(QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_VALUE,
600 QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL)) {
601 ALOGE("Failed to put THERMAL_LEVEL command type");
602 goto cleanup;
603 }
604
605 switch(mode) {
606 case WIFI_MITIGATION_NONE:
607 qca_vendor_thermal_level = QCA_WLAN_VENDOR_THERMAL_LEVEL_NONE;
608 break;
609 case WIFI_MITIGATION_LIGHT:
610 qca_vendor_thermal_level = QCA_WLAN_VENDOR_THERMAL_LEVEL_LIGHT;
611 break;
612 case WIFI_MITIGATION_MODERATE:
613 qca_vendor_thermal_level = QCA_WLAN_VENDOR_THERMAL_LEVEL_MODERATE;
614 break;
615 case WIFI_MITIGATION_SEVERE:
616 qca_vendor_thermal_level = QCA_WLAN_VENDOR_THERMAL_LEVEL_SEVERE;
617 break;
618 case WIFI_MITIGATION_CRITICAL:
619 qca_vendor_thermal_level = QCA_WLAN_VENDOR_THERMAL_LEVEL_CRITICAL;
620 break;
621 case WIFI_MITIGATION_EMERGENCY:
622 qca_vendor_thermal_level = QCA_WLAN_VENDOR_THERMAL_LEVEL_EMERGENCY;
623 break;
624 default:
625 ALOGE("Unknown thermal mitigation level %d", mode);
626 ret = WIFI_ERROR_UNKNOWN;
627 goto cleanup;
628 }
629
630 if (wifiConfigCommand->put_u32(
631 QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL,
632 qca_vendor_thermal_level)) {
633 ALOGE("Failed to put thermal level");
634 goto cleanup;
635 }
636
637 if (wifiConfigCommand->put_u32(
638 QCA_WLAN_VENDOR_ATTR_THERMAL_COMPLETION_WINDOW,
639 completion_window)) {
640 ALOGE("Failed to put thermal completion window");
641 goto cleanup;
642 }
643 wifiConfigCommand->attr_end(nlData);
644
645 wifiConfigCommand->waitForRsp(false);
646 ret = wifiConfigCommand->requestEvent();
647 if (ret != WIFI_SUCCESS) {
648 ALOGE("Failed to set thermal level with Error: %d", ret);
649 goto cleanup;
650 }
651
652 cleanup:
653 delete wifiConfigCommand;
654 return ret;
655 }
656
WiFiConfigCommand(wifi_handle handle,int id,u32 vendor_id,u32 subcmd)657 WiFiConfigCommand::WiFiConfigCommand(wifi_handle handle,
658 int id, u32 vendor_id,
659 u32 subcmd)
660 : WifiVendorCommand(handle, id, vendor_id, subcmd)
661 {
662 /* Initialize the member data variables here */
663 mWaitforRsp = false;
664 mRequestId = id;
665 }
666
~WiFiConfigCommand()667 WiFiConfigCommand::~WiFiConfigCommand()
668 {
669 unregisterVendorHandler(mVendor_id, mSubcmd);
670 }
671
672 /* This function implements creation of Vendor command */
create()673 wifi_error WiFiConfigCommand::create()
674 {
675 wifi_error ret = mMsg.create(NL80211_CMD_VENDOR, 0, 0);
676 if (ret != WIFI_SUCCESS)
677 return ret;
678
679 /* Insert the oui in the msg */
680 ret = mMsg.put_u32(NL80211_ATTR_VENDOR_ID, mVendor_id);
681 if (ret != WIFI_SUCCESS)
682 return ret;
683 /* Insert the subcmd in the msg */
684 ret = mMsg.put_u32(NL80211_ATTR_VENDOR_SUBCMD, mSubcmd);
685
686 return ret;
687 }
688
689 /* This function implements creation of generic NL command */
create_generic(u8 cmdId)690 wifi_error WiFiConfigCommand::create_generic(u8 cmdId)
691 {
692 wifi_error ret = mMsg.create(cmdId, 0, 0);
693 return ret;
694 }
695
waitForRsp(bool wait)696 void WiFiConfigCommand::waitForRsp(bool wait)
697 {
698 mWaitforRsp = wait;
699 }
700
701 /* Callback handlers registered for nl message send */
error_handler_wifi_config(struct sockaddr_nl * nla,struct nlmsgerr * err,void * arg)702 static int error_handler_wifi_config(struct sockaddr_nl *nla,
703 struct nlmsgerr *err,
704 void *arg)
705 {
706 struct sockaddr_nl *tmp;
707 int *ret = (int *)arg;
708 tmp = nla;
709 *ret = err->error;
710 ALOGE("%s: Error code:%d (%s)", __FUNCTION__, *ret, strerror(-(*ret)));
711 return NL_STOP;
712 }
713
714 /* Callback handlers registered for nl message send */
ack_handler_wifi_config(struct nl_msg * msg,void * arg)715 static int ack_handler_wifi_config(struct nl_msg *msg, void *arg)
716 {
717 int *ret = (int *)arg;
718 struct nl_msg * a;
719
720 a = msg;
721 *ret = 0;
722 return NL_STOP;
723 }
724
725 /* Callback handlers registered for nl message send */
finish_handler_wifi_config(struct nl_msg * msg,void * arg)726 static int finish_handler_wifi_config(struct nl_msg *msg, void *arg)
727 {
728 int *ret = (int *)arg;
729 struct nl_msg * a;
730
731 a = msg;
732 *ret = 0;
733 return NL_SKIP;
734 }
735
736 /*
737 * Override base class requestEvent and implement little differently here.
738 * This will send the request message.
739 * We don't wait for any response back in case of wificonfig,
740 * thus no wait for condition.
741 */
requestEvent()742 wifi_error WiFiConfigCommand::requestEvent()
743 {
744 int status;
745 wifi_error res = WIFI_SUCCESS;
746 struct nl_cb *cb;
747
748 cb = nl_cb_alloc(NL_CB_DEFAULT);
749 if (!cb) {
750 ALOGE("%s: Callback allocation failed",__FUNCTION__);
751 res = WIFI_ERROR_OUT_OF_MEMORY;
752 goto out;
753 }
754
755 status = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage());
756 if (status < 0) {
757 res = mapKernelErrortoWifiHalError(status);
758 goto out;
759 }
760 status = 1;
761
762 nl_cb_err(cb, NL_CB_CUSTOM, error_handler_wifi_config, &status);
763 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler_wifi_config,
764 &status);
765 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler_wifi_config, &status);
766
767 /* Err is populated as part of finish_handler. */
768 while (status > 0) {
769 nl_recvmsgs(mInfo->cmd_sock, cb);
770 }
771
772 if (status < 0) {
773 res = mapKernelErrortoWifiHalError(status);
774 goto out;
775 }
776
777 if (mWaitforRsp == true) {
778 struct timespec abstime;
779 abstime.tv_sec = 4;
780 abstime.tv_nsec = 0;
781 res = mCondition.wait(abstime);
782 if (res == WIFI_ERROR_TIMED_OUT)
783 ALOGE("%s: Time out happened.", __FUNCTION__);
784
785 ALOGV("%s: Command invoked return value:%d, mWaitForRsp=%d",
786 __FUNCTION__, res, mWaitforRsp);
787 }
788 out:
789 /* Cleanup the mMsg */
790 mMsg.destroy();
791 return res;
792 }
793
794 static std::vector<std::string> added_ifaces;
795
is_dynamic_interface(const char * ifname)796 static bool is_dynamic_interface(const char * ifname)
797 {
798 for (const auto& iface : added_ifaces) {
799 if (iface == std::string(ifname))
800 return true;
801 }
802 return false;
803 }
804
wifi_cleanup_dynamic_ifaces(wifi_handle handle)805 void wifi_cleanup_dynamic_ifaces(wifi_handle handle)
806 {
807 int len = added_ifaces.size();
808 while (len--) {
809 wifi_virtual_interface_delete(handle, added_ifaces.front().c_str());
810 }
811 added_ifaces.clear(); // could be redundent. But to be on safe side.
812 }
813
wifi_virtual_interface_create(wifi_handle handle,const char * ifname,wifi_interface_type iface_type)814 wifi_error wifi_virtual_interface_create(wifi_handle handle,
815 const char* ifname,
816 wifi_interface_type iface_type)
817 {
818 wifi_error ret;
819 WiFiConfigCommand *wifiConfigCommand;
820 u32 wlan0_id = if_nametoindex("wlan0");
821 if (!handle || !wlan0_id) {
822 ALOGE("%s: Error wifi_handle NULL or wlan0 not present", __FUNCTION__);
823 return WIFI_ERROR_UNKNOWN;
824 }
825
826 ALOGD("%s: ifname=%s create", __FUNCTION__, ifname);
827 // Do not create interface if already exist.
828 if (if_nametoindex(ifname))
829 return WIFI_SUCCESS;
830
831 wifiConfigCommand = new WiFiConfigCommand(handle, get_requestid(), 0, 0);
832 if (wifiConfigCommand == NULL) {
833 ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
834 return WIFI_ERROR_UNKNOWN;
835 }
836
837 nl80211_iftype type;
838 switch(iface_type) {
839 case WIFI_INTERFACE_TYPE_STA: /* IfaceType:STA */
840 type = NL80211_IFTYPE_STATION;
841 break;
842 case WIFI_INTERFACE_TYPE_AP: /* IfaceType:AP */
843 type = NL80211_IFTYPE_AP;
844 break;
845 case WIFI_INTERFACE_TYPE_P2P: /* IfaceType:P2P */
846 type = NL80211_IFTYPE_P2P_DEVICE;
847 break;
848 case WIFI_INTERFACE_TYPE_NAN: /* IfaceType:NAN */
849 type = NL80211_IFTYPE_NAN;
850 break;
851 default:
852 ALOGE("%s: Wrong interface type %u", __FUNCTION__, iface_type);
853 ret = WIFI_ERROR_UNKNOWN;
854 goto done;
855 break;
856 }
857 wifiConfigCommand->create_generic(NL80211_CMD_NEW_INTERFACE);
858 wifiConfigCommand->put_u32(NL80211_ATTR_IFINDEX, wlan0_id);
859 wifiConfigCommand->put_string(NL80211_ATTR_IFNAME, ifname);
860 wifiConfigCommand->put_u32(NL80211_ATTR_IFTYPE, type);
861 /* Send the NL msg. */
862 wifiConfigCommand->waitForRsp(false);
863 ret = wifiConfigCommand->requestEvent();
864 if (ret != WIFI_SUCCESS) {
865 ALOGE("%s: requestEvent Error:%d", __FUNCTION__,ret);
866 }
867 // Update dynamic interface list
868 added_ifaces.push_back(std::string(ifname));
869
870 done:
871 delete wifiConfigCommand;
872 return ret;
873 }
874
wifi_virtual_interface_delete(wifi_handle handle,const char * ifname)875 wifi_error wifi_virtual_interface_delete(wifi_handle handle,
876 const char* ifname)
877 {
878 wifi_error ret;
879 WiFiConfigCommand *wifiConfigCommand;
880 u32 wlan0_id = if_nametoindex("wlan0");
881
882 if (!handle || !wlan0_id) {
883 ALOGE("%s: Error wifi_handle NULL or wlan0 not present", __FUNCTION__);
884 return WIFI_ERROR_UNKNOWN;
885 }
886
887 ALOGD("%s: ifname=%s delete", __FUNCTION__, ifname);
888 if (if_nametoindex(ifname) && !is_dynamic_interface(ifname)) {
889 // Do not remove interface if it was not added dynamically.
890 return WIFI_SUCCESS;
891 }
892 wifiConfigCommand = new WiFiConfigCommand(handle, get_requestid(), 0, 0);
893 if (wifiConfigCommand == NULL) {
894 ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
895 return WIFI_ERROR_UNKNOWN;
896 }
897 wifiConfigCommand->create_generic(NL80211_CMD_DEL_INTERFACE);
898 wifiConfigCommand->put_u32(NL80211_ATTR_IFINDEX, if_nametoindex(ifname));
899 /* Send the NL msg. */
900 wifiConfigCommand->waitForRsp(false);
901 ret = wifiConfigCommand->requestEvent();
902 if (ret != WIFI_SUCCESS) {
903 ALOGE("%s: requestEvent Error:%d", __FUNCTION__,ret);
904 }
905 // Update dynamic interface list
906 added_ifaces.erase(std::remove(added_ifaces.begin(), added_ifaces.end(), std::string(ifname)),
907 added_ifaces.end());
908
909 delete wifiConfigCommand;
910 return ret;
911 }
912