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_BODY_BT:
364 bdf_file = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0;
365 break;
366
367 case WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF:
368 case WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON:
369 case WIFI_POWER_SCENARIO_ON_HEAD_HOTSPOT:
370 case WIFI_POWER_SCENARIO_ON_HEAD_HOTSPOT_MMW:
371 bdf_file = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF1;
372 break;
373
374 case WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF:
375 bdf_file = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF2;
376 break;
377
378 case WIFI_POWER_SCENARIO_ON_BODY_CELL_ON:
379 case WIFI_POWER_SCENARIO_ON_BODY_CELL_ON_BT:
380 case WIFI_POWER_SCENARIO_ON_BODY_HOTSPOT:
381 case WIFI_POWER_SCENARIO_ON_BODY_HOTSPOT_BT:
382 case WIFI_POWER_SCENARIO_ON_BODY_HOTSPOT_MMW:
383 case WIFI_POWER_SCENARIO_ON_BODY_HOTSPOT_BT_MMW:
384 bdf_file = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF3;
385 break;
386
387 default:
388 ALOGE("wifi_select_tx_power_scenario: invalid scenario %d", scenario);
389 ret = WIFI_ERROR_INVALID_ARGS;
390 goto cleanup;
391 }
392
393 if (wifiConfigCommand->put_u32(
394 QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE,
395 bdf_file)) {
396 ALOGE("failed to put SAR_ENABLE");
397 goto cleanup;
398 }
399 wifiConfigCommand->attr_end(nlData);
400
401 ret = wifiConfigCommand->requestEvent();
402 if (ret != WIFI_SUCCESS) {
403 ALOGE("wifi_select_tx_power_scenario(): requestEvent Error:%d", ret);
404 goto cleanup;
405 }
406
407 cleanup:
408 delete wifiConfigCommand;
409 return ret;
410 }
411
wifi_reset_tx_power_scenario(wifi_interface_handle handle)412 wifi_error wifi_reset_tx_power_scenario(wifi_interface_handle handle)
413 {
414 wifi_error ret;
415 WiFiConfigCommand *wifiConfigCommand;
416 struct nlattr *nlData;
417 interface_info *ifaceInfo = getIfaceInfo(handle);
418 wifi_handle wifiHandle = getWifiHandle(handle);
419
420 wifiConfigCommand = new WiFiConfigCommand(
421 wifiHandle,
422 1,
423 OUI_QCA,
424 QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS);
425 if (wifiConfigCommand == NULL) {
426 ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
427 return WIFI_ERROR_UNKNOWN;
428 }
429
430 /* Create the NL message. */
431 ret = wifiConfigCommand->create();
432 if (ret != WIFI_SUCCESS) {
433 ALOGE("wifi_reset_tx_power_scenario: failed to create NL msg. Error:%d", ret);
434 goto cleanup;
435 }
436
437 /* Set the interface Id of the message. */
438 ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
439 if (ret != WIFI_SUCCESS) {
440 ALOGE("wifi_reset_tx_power_scenario: failed to set iface id. Error:%d", ret);
441 goto cleanup;
442 }
443
444 /* Add the vendor specific attributes for the NL command. */
445 nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
446 if (!nlData) {
447 ALOGE("wifi_reset_tx_power_scenario: failed attr_start for VENDOR_DATA. "
448 "Error:%d", ret);
449 goto cleanup;
450 }
451
452 if (wifiConfigCommand->put_u32(QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE,
453 QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE)) {
454 ALOGE("failed to put SAR_ENABLE or NUM_SPECS");
455 goto cleanup;
456 }
457 wifiConfigCommand->attr_end(nlData);
458
459 ret = wifiConfigCommand->requestEvent();
460 if (ret != WIFI_SUCCESS) {
461 ALOGE("wifi_reset_tx_power_scenario(): requestEvent Error:%d", ret);
462 goto cleanup;
463 }
464
465 cleanup:
466 delete wifiConfigCommand;
467 return ret;
468 }
469
wifi_set_latency_mode(wifi_interface_handle handle,wifi_latency_mode mode)470 wifi_error wifi_set_latency_mode(wifi_interface_handle handle,
471 wifi_latency_mode mode) {
472 wifi_error ret;
473 WiFiConfigCommand *wifiConfigCommand;
474 struct nlattr *nlData;
475 u32 latency_mode;
476 interface_info *ifaceInfo = getIfaceInfo(handle);
477 wifi_handle wifiHandle = getWifiHandle(handle);
478 hal_info *info = getHalInfo(wifiHandle);
479
480 ALOGV("%s : latency mode:%d", __FUNCTION__, mode);
481
482 /* Check Supported low-latency capability */
483 if (!(info->supported_feature_set & WIFI_FEATURE_SET_LATENCY_MODE)) {
484 ALOGE("%s: Set latency mode feature not supported 0x%" PRIx64, __FUNCTION__,
485 info->supported_feature_set);
486 return WIFI_ERROR_NOT_SUPPORTED;
487 }
488
489 wifiConfigCommand = new WiFiConfigCommand(
490 wifiHandle,
491 1,
492 OUI_QCA,
493 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
494 if (wifiConfigCommand == NULL) {
495 ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
496 return WIFI_ERROR_UNKNOWN;
497 }
498
499 /* Create the NL message. */
500 ret = wifiConfigCommand->create();
501 if (ret != WIFI_SUCCESS) {
502 ALOGE("wifi_set_latency_mode: failed to create NL msg. Error:%d", ret);
503 goto cleanup;
504 }
505
506 /* Set the interface Id of the message. */
507 ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
508 if (ret != WIFI_SUCCESS) {
509 ALOGE("wifi_set_latency_mode: failed to set iface id. Error:%d", ret);
510 goto cleanup;
511 }
512
513 /* Add the vendor specific attributes for the NL command. */
514 nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
515 if (!nlData) {
516 ret = WIFI_ERROR_UNKNOWN;
517 ALOGE("wifi_set_latency_mode: failed attr_start for VENDOR_DATA. "
518 "Error:%d", ret);
519 goto cleanup;
520 }
521
522 switch(mode) {
523 case WIFI_LATENCY_MODE_NORMAL:
524 latency_mode = QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_NORMAL;
525 break;
526
527 case WIFI_LATENCY_MODE_LOW:
528 latency_mode = QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_LOW;
529 break;
530
531 default:
532 ALOGE("wifi_set_latency_mode: Invalid mode: %d", mode);
533 ret = WIFI_ERROR_UNKNOWN;
534 goto cleanup;
535 }
536
537 if (wifiConfigCommand->put_u32(
538 QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL,
539 latency_mode)) {
540 ALOGE("wifi_set_latency_mode: failed to put latency mode");
541 ret = WIFI_ERROR_UNKNOWN;
542 goto cleanup;
543 }
544 wifiConfigCommand->attr_end(nlData);
545
546 /* Send the NL msg. */
547 wifiConfigCommand->waitForRsp(false);
548 ret = wifiConfigCommand->requestEvent();
549 if (ret != WIFI_SUCCESS) {
550 ALOGE("wifi_set_latency_mode: requestEvent Error:%d", ret);
551 goto cleanup;
552 }
553
554 cleanup:
555 delete wifiConfigCommand;
556 return ret;
557 }
558
wifi_set_thermal_mitigation_mode(wifi_handle handle,wifi_thermal_mode mode,u32 completion_window)559 wifi_error wifi_set_thermal_mitigation_mode(wifi_handle handle,
560 wifi_thermal_mode mode,
561 u32 completion_window)
562 {
563 wifi_error ret;
564 WiFiConfigCommand *wifiConfigCommand;
565 struct nlattr *nlData;
566 u32 qca_vendor_thermal_level;
567 hal_info *info = getHalInfo(handle);
568
569 if (!info || info->num_interfaces < 1) {
570 ALOGE("%s: Error wifi_handle NULL or base wlan interface not present",
571 __FUNCTION__);
572 return WIFI_ERROR_UNKNOWN;
573 }
574
575 wifiConfigCommand = new WiFiConfigCommand(
576 handle,
577 1,
578 OUI_QCA,
579 QCA_NL80211_VENDOR_SUBCMD_THERMAL_CMD);
580 if (wifiConfigCommand == NULL) {
581 ALOGE("%s: Error, Failed to create wifiConfigCommand", __FUNCTION__);
582 return WIFI_ERROR_UNKNOWN;
583 }
584
585 /* Create the NL message. */
586 ret = wifiConfigCommand->create();
587 if (ret != WIFI_SUCCESS) {
588 ALOGE("Failed to create thermal vendor command, Error:%d", ret);
589 goto cleanup;
590 }
591
592 /* Set the interface Id of the message. */
593 if (wifiConfigCommand->put_u32(NL80211_ATTR_IFINDEX,
594 info->interfaces[0]->id)) {
595 ALOGE("%s: Failed to put iface id", __FUNCTION__);
596 goto cleanup;
597 }
598
599 nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
600 if (!nlData) {
601 ALOGE("%s: Failed in attr_start for VENDOR_DATA, Error:%d",
602 __FUNCTION__, ret);
603 goto cleanup;
604 }
605
606 if (wifiConfigCommand->put_u32(QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_VALUE,
607 QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL)) {
608 ALOGE("Failed to put THERMAL_LEVEL command type");
609 goto cleanup;
610 }
611
612 switch(mode) {
613 case WIFI_MITIGATION_NONE:
614 qca_vendor_thermal_level = QCA_WLAN_VENDOR_THERMAL_LEVEL_NONE;
615 break;
616 case WIFI_MITIGATION_LIGHT:
617 qca_vendor_thermal_level = QCA_WLAN_VENDOR_THERMAL_LEVEL_LIGHT;
618 break;
619 case WIFI_MITIGATION_MODERATE:
620 qca_vendor_thermal_level = QCA_WLAN_VENDOR_THERMAL_LEVEL_MODERATE;
621 break;
622 case WIFI_MITIGATION_SEVERE:
623 qca_vendor_thermal_level = QCA_WLAN_VENDOR_THERMAL_LEVEL_SEVERE;
624 break;
625 case WIFI_MITIGATION_CRITICAL:
626 qca_vendor_thermal_level = QCA_WLAN_VENDOR_THERMAL_LEVEL_CRITICAL;
627 break;
628 case WIFI_MITIGATION_EMERGENCY:
629 qca_vendor_thermal_level = QCA_WLAN_VENDOR_THERMAL_LEVEL_EMERGENCY;
630 break;
631 default:
632 ALOGE("Unknown thermal mitigation level %d", mode);
633 ret = WIFI_ERROR_UNKNOWN;
634 goto cleanup;
635 }
636
637 if (wifiConfigCommand->put_u32(
638 QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL,
639 qca_vendor_thermal_level)) {
640 ALOGE("Failed to put thermal level");
641 goto cleanup;
642 }
643
644 if (wifiConfigCommand->put_u32(
645 QCA_WLAN_VENDOR_ATTR_THERMAL_COMPLETION_WINDOW,
646 completion_window)) {
647 ALOGE("Failed to put thermal completion window");
648 goto cleanup;
649 }
650 wifiConfigCommand->attr_end(nlData);
651
652 wifiConfigCommand->waitForRsp(false);
653 ret = wifiConfigCommand->requestEvent();
654 if (ret != WIFI_SUCCESS) {
655 ALOGE("Failed to set thermal level with Error: %d", ret);
656 goto cleanup;
657 }
658
659 cleanup:
660 delete wifiConfigCommand;
661 return ret;
662 }
663
WiFiConfigCommand(wifi_handle handle,int id,u32 vendor_id,u32 subcmd)664 WiFiConfigCommand::WiFiConfigCommand(wifi_handle handle,
665 int id, u32 vendor_id,
666 u32 subcmd)
667 : WifiVendorCommand(handle, id, vendor_id, subcmd)
668 {
669 /* Initialize the member data variables here */
670 mWaitforRsp = false;
671 mRequestId = id;
672 }
673
~WiFiConfigCommand()674 WiFiConfigCommand::~WiFiConfigCommand()
675 {
676 unregisterVendorHandler(mVendor_id, mSubcmd);
677 }
678
679 /* This function implements creation of Vendor command */
create()680 wifi_error WiFiConfigCommand::create()
681 {
682 wifi_error ret = mMsg.create(NL80211_CMD_VENDOR, 0, 0);
683 if (ret != WIFI_SUCCESS)
684 return ret;
685
686 /* Insert the oui in the msg */
687 ret = mMsg.put_u32(NL80211_ATTR_VENDOR_ID, mVendor_id);
688 if (ret != WIFI_SUCCESS)
689 return ret;
690 /* Insert the subcmd in the msg */
691 ret = mMsg.put_u32(NL80211_ATTR_VENDOR_SUBCMD, mSubcmd);
692
693 return ret;
694 }
695
696 /* This function implements creation of generic NL command */
create_generic(u8 cmdId)697 wifi_error WiFiConfigCommand::create_generic(u8 cmdId)
698 {
699 wifi_error ret = mMsg.create(cmdId, 0, 0);
700 return ret;
701 }
702
waitForRsp(bool wait)703 void WiFiConfigCommand::waitForRsp(bool wait)
704 {
705 mWaitforRsp = wait;
706 }
707
708 /* Callback handlers registered for nl message send */
error_handler_wifi_config(struct sockaddr_nl * nla,struct nlmsgerr * err,void * arg)709 static int error_handler_wifi_config(struct sockaddr_nl *nla,
710 struct nlmsgerr *err,
711 void *arg)
712 {
713 struct sockaddr_nl *tmp;
714 int *ret = (int *)arg;
715 tmp = nla;
716 *ret = err->error;
717 ALOGE("%s: Error code:%d (%s)", __FUNCTION__, *ret, strerror(-(*ret)));
718 return NL_STOP;
719 }
720
721 /* Callback handlers registered for nl message send */
ack_handler_wifi_config(struct nl_msg * msg,void * arg)722 static int ack_handler_wifi_config(struct nl_msg *msg, void *arg)
723 {
724 int *ret = (int *)arg;
725 struct nl_msg * a;
726
727 a = msg;
728 *ret = 0;
729 return NL_STOP;
730 }
731
732 /* Callback handlers registered for nl message send */
finish_handler_wifi_config(struct nl_msg * msg,void * arg)733 static int finish_handler_wifi_config(struct nl_msg *msg, void *arg)
734 {
735 int *ret = (int *)arg;
736 struct nl_msg * a;
737
738 a = msg;
739 *ret = 0;
740 return NL_SKIP;
741 }
742
743 /*
744 * Override base class requestEvent and implement little differently here.
745 * This will send the request message.
746 * We don't wait for any response back in case of wificonfig,
747 * thus no wait for condition.
748 */
requestEvent()749 wifi_error WiFiConfigCommand::requestEvent()
750 {
751 int status;
752 wifi_error res = WIFI_SUCCESS;
753 struct nl_cb *cb;
754
755 cb = nl_cb_alloc(NL_CB_DEFAULT);
756 if (!cb) {
757 ALOGE("%s: Callback allocation failed",__FUNCTION__);
758 res = WIFI_ERROR_OUT_OF_MEMORY;
759 goto out;
760 }
761
762 status = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage());
763 if (status < 0) {
764 res = mapKernelErrortoWifiHalError(status);
765 goto out;
766 }
767 status = 1;
768
769 nl_cb_err(cb, NL_CB_CUSTOM, error_handler_wifi_config, &status);
770 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler_wifi_config,
771 &status);
772 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler_wifi_config, &status);
773
774 /* Err is populated as part of finish_handler. */
775 while (status > 0) {
776 nl_recvmsgs(mInfo->cmd_sock, cb);
777 }
778
779 if (status < 0) {
780 res = mapKernelErrortoWifiHalError(status);
781 goto out;
782 }
783
784 if (mWaitforRsp == true) {
785 struct timespec abstime;
786 abstime.tv_sec = 4;
787 abstime.tv_nsec = 0;
788 res = mCondition.wait(abstime);
789 if (res == WIFI_ERROR_TIMED_OUT)
790 ALOGE("%s: Time out happened.", __FUNCTION__);
791
792 ALOGV("%s: Command invoked return value:%d, mWaitForRsp=%d",
793 __FUNCTION__, res, mWaitforRsp);
794 }
795 out:
796 /* Cleanup the mMsg */
797 mMsg.destroy();
798 return res;
799 }
800
801 static std::vector<std::string> added_ifaces;
802
is_dynamic_interface(const char * ifname)803 static bool is_dynamic_interface(const char * ifname)
804 {
805 for (const auto& iface : added_ifaces) {
806 if (iface == std::string(ifname))
807 return true;
808 }
809 return false;
810 }
811
wifi_cleanup_dynamic_ifaces(wifi_handle handle)812 void wifi_cleanup_dynamic_ifaces(wifi_handle handle)
813 {
814 int len = added_ifaces.size();
815 while (len--) {
816 wifi_virtual_interface_delete(handle, added_ifaces.front().c_str());
817 }
818 added_ifaces.clear(); // could be redundent. But to be on safe side.
819 }
820
wifi_virtual_interface_create(wifi_handle handle,const char * ifname,wifi_interface_type iface_type)821 wifi_error wifi_virtual_interface_create(wifi_handle handle,
822 const char* ifname,
823 wifi_interface_type iface_type)
824 {
825 wifi_error ret;
826 WiFiConfigCommand *wifiConfigCommand;
827 u32 wlan0_id = if_nametoindex("wlan0");
828 if (!handle || !wlan0_id) {
829 ALOGE("%s: Error wifi_handle NULL or wlan0 not present", __FUNCTION__);
830 return WIFI_ERROR_UNKNOWN;
831 }
832
833 ALOGD("%s: ifname=%s create", __FUNCTION__, ifname);
834 // Do not create interface if already exist.
835 if (if_nametoindex(ifname))
836 return WIFI_SUCCESS;
837
838 wifiConfigCommand = new WiFiConfigCommand(handle, get_requestid(), 0, 0);
839 if (wifiConfigCommand == NULL) {
840 ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
841 return WIFI_ERROR_UNKNOWN;
842 }
843
844 nl80211_iftype type;
845 switch(iface_type) {
846 case WIFI_INTERFACE_TYPE_STA: /* IfaceType:STA */
847 type = NL80211_IFTYPE_STATION;
848 break;
849 case WIFI_INTERFACE_TYPE_AP: /* IfaceType:AP */
850 type = NL80211_IFTYPE_AP;
851 break;
852 case WIFI_INTERFACE_TYPE_P2P: /* IfaceType:P2P */
853 type = NL80211_IFTYPE_P2P_DEVICE;
854 break;
855 case WIFI_INTERFACE_TYPE_NAN: /* IfaceType:NAN */
856 type = NL80211_IFTYPE_NAN;
857 break;
858 default:
859 ALOGE("%s: Wrong interface type %u", __FUNCTION__, iface_type);
860 ret = WIFI_ERROR_UNKNOWN;
861 goto done;
862 break;
863 }
864 wifiConfigCommand->create_generic(NL80211_CMD_NEW_INTERFACE);
865 wifiConfigCommand->put_u32(NL80211_ATTR_IFINDEX, wlan0_id);
866 wifiConfigCommand->put_string(NL80211_ATTR_IFNAME, ifname);
867 wifiConfigCommand->put_u32(NL80211_ATTR_IFTYPE, type);
868 /* Send the NL msg. */
869 wifiConfigCommand->waitForRsp(false);
870 ret = wifiConfigCommand->requestEvent();
871 if (ret != WIFI_SUCCESS) {
872 ALOGE("%s: requestEvent Error:%d", __FUNCTION__,ret);
873 }
874 // Update dynamic interface list
875 added_ifaces.push_back(std::string(ifname));
876
877 done:
878 delete wifiConfigCommand;
879 return ret;
880 }
881
wifi_virtual_interface_delete(wifi_handle handle,const char * ifname)882 wifi_error wifi_virtual_interface_delete(wifi_handle handle,
883 const char* ifname)
884 {
885 wifi_error ret;
886 WiFiConfigCommand *wifiConfigCommand;
887 u32 wlan0_id = if_nametoindex("wlan0");
888
889 if (!handle || !wlan0_id) {
890 ALOGE("%s: Error wifi_handle NULL or wlan0 not present", __FUNCTION__);
891 return WIFI_ERROR_UNKNOWN;
892 }
893
894 ALOGD("%s: ifname=%s delete", __FUNCTION__, ifname);
895 if (if_nametoindex(ifname) && !is_dynamic_interface(ifname)) {
896 // Do not remove interface if it was not added dynamically.
897 return WIFI_SUCCESS;
898 }
899 wifiConfigCommand = new WiFiConfigCommand(handle, get_requestid(), 0, 0);
900 if (wifiConfigCommand == NULL) {
901 ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
902 return WIFI_ERROR_UNKNOWN;
903 }
904 wifiConfigCommand->create_generic(NL80211_CMD_DEL_INTERFACE);
905 wifiConfigCommand->put_u32(NL80211_ATTR_IFINDEX, if_nametoindex(ifname));
906 /* Send the NL msg. */
907 wifiConfigCommand->waitForRsp(false);
908 ret = wifiConfigCommand->requestEvent();
909 if (ret != WIFI_SUCCESS) {
910 ALOGE("%s: requestEvent Error:%d", __FUNCTION__,ret);
911 }
912 // Update dynamic interface list
913 added_ifaces.erase(std::remove(added_ifaces.begin(), added_ifaces.end(), std::string(ifname)),
914 added_ifaces.end());
915
916 delete wifiConfigCommand;
917 return ret;
918 }
919