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