• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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