1 /* Copyright (c) 2015, 2018 The Linux Foundation. All rights reserved.
2  *
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions
5  * are met:
6  *  * Redistributions of source code must retain the above copyright
7  *    notice, this list of conditions and the following disclaimer.
8  *  * Redistributions in binary form must reproduce the above
9  *    copyright notice, this list of conditions and the following
10  *    disclaimer in the documentation and/or other materials provided
11  *    with the distribution.
12  *  * Neither the name of The Linux Foundation nor the names of its
13  *    contributors may be used to endorse or promote products derived
14  *    from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "sync.h"
30 #define LOG_TAG  "WifiHAL"
31 #include <utils/Log.h>
32 #include <time.h>
33 #include <errno.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include "wificonfigcommand.h"
37 
38 /* Implementation of the API functions exposed in wifi_config.h */
wifi_extended_dtim_config_set(wifi_request_id id,wifi_interface_handle iface,int extended_dtim)39 wifi_error wifi_extended_dtim_config_set(wifi_request_id id,
40                                          wifi_interface_handle iface,
41                                          int extended_dtim)
42 {
43     wifi_error ret;
44     WiFiConfigCommand *wifiConfigCommand;
45     struct nlattr *nlData;
46     interface_info *ifaceInfo = getIfaceInfo(iface);
47     wifi_handle wifiHandle = getWifiHandle(iface);
48 
49     ALOGV("%s: extended_dtim:%d", __FUNCTION__, extended_dtim);
50 
51     wifiConfigCommand = new WiFiConfigCommand(
52                             wifiHandle,
53                             id,
54                             OUI_QCA,
55                             QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
56 
57     if (wifiConfigCommand == NULL) {
58         ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
59         return WIFI_ERROR_UNKNOWN;
60     }
61 
62     /* Create the NL message. */
63     ret = wifiConfigCommand->create();
64     if (ret != WIFI_SUCCESS) {
65         ALOGE("wifi_extended_dtim_config_set: failed to create NL msg. "
66             "Error:%d", ret);
67         goto cleanup;
68     }
69 
70     /* Set the interface Id of the message. */
71     ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
72     if (ret != WIFI_SUCCESS) {
73         ALOGE("wifi_extended_dtim_config_set: failed to set iface id. "
74             "Error:%d", ret);
75         goto cleanup;
76     }
77 
78     /* Add the vendor specific attributes for the NL command. */
79     nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
80     if (!nlData) {
81         ALOGE("wifi_extended_dtim_config_set: failed attr_start for "
82             "VENDOR_DATA. Error:%d", ret);
83         goto cleanup;
84     }
85 
86     ret = wifiConfigCommand->put_u32(
87                   QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_DYNAMIC_DTIM, extended_dtim);
88     if (ret != WIFI_SUCCESS) {
89         ALOGE("wifi_extended_dtim_config_set(): failed to put vendor data. "
90             "Error:%d", ret);
91         goto cleanup;
92     }
93     wifiConfigCommand->attr_end(nlData);
94 
95     /* Send the NL msg. */
96     wifiConfigCommand->waitForRsp(false);
97     ret = wifiConfigCommand->requestEvent();
98     if (ret != WIFI_SUCCESS) {
99         ALOGE("wifi_extended_dtim_config_set(): requestEvent Error:%d", ret);
100         goto cleanup;
101     }
102 
103 cleanup:
104     delete wifiConfigCommand;
105     return ret;
106 }
107 
108 /* Set the country code to driver. */
wifi_set_country_code(wifi_interface_handle iface,const char * country_code)109 wifi_error wifi_set_country_code(wifi_interface_handle iface,
110                                  const char* country_code)
111 {
112     int requestId;
113     wifi_error ret;
114     WiFiConfigCommand *wifiConfigCommand;
115     wifi_handle wifiHandle = getWifiHandle(iface);
116 
117     ALOGV("%s: %s", __FUNCTION__, country_code);
118 
119     /* No request id from caller, so generate one and pass it on to the driver.
120      * Generate it randomly.
121      */
122     requestId = get_requestid();
123 
124     wifiConfigCommand = new WiFiConfigCommand(
125                             wifiHandle,
126                             requestId,
127                             OUI_QCA,
128                             QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
129     if (wifiConfigCommand == NULL) {
130         ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
131         return WIFI_ERROR_UNKNOWN;
132     }
133 
134     /* Create the NL message with NL80211_CMD_REQ_SET_REG NL cmd. */
135     ret = wifiConfigCommand->create_generic(NL80211_CMD_REQ_SET_REG);
136     if (ret != WIFI_SUCCESS) {
137         ALOGE("wifi_set_country_code: failed to create NL msg. Error:%d", ret);
138         goto cleanup;
139     }
140 
141     ret = wifiConfigCommand->put_string(NL80211_ATTR_REG_ALPHA2, country_code);
142     if (ret != WIFI_SUCCESS) {
143         ALOGE("wifi_set_country_code: put country code failed. Error:%d", ret);
144         goto cleanup;
145     }
146 
147     /* Send the NL msg. */
148     wifiConfigCommand->waitForRsp(false);
149     ret = wifiConfigCommand->requestEvent();
150     if (ret != WIFI_SUCCESS) {
151         ALOGE("wifi_set_country_code(): requestEvent Error:%d", ret);
152         goto cleanup;
153     }
154     usleep(WAIT_TIME_FOR_SET_REG_DOMAIN);
155 
156 cleanup:
157     delete wifiConfigCommand;
158     return ret;
159 }
160 
wifi_set_beacon_wifi_iface_stats_averaging_factor(wifi_request_id id,wifi_interface_handle iface,u16 factor)161 wifi_error wifi_set_beacon_wifi_iface_stats_averaging_factor(
162                                                 wifi_request_id id,
163                                                 wifi_interface_handle iface,
164                                                 u16 factor)
165 {
166     wifi_error ret;
167     WiFiConfigCommand *wifiConfigCommand;
168     struct nlattr *nlData;
169     interface_info *ifaceInfo = getIfaceInfo(iface);
170     wifi_handle wifiHandle = getWifiHandle(iface);
171 
172     ALOGV("%s factor:%u", __FUNCTION__, factor);
173     wifiConfigCommand = new WiFiConfigCommand(
174                             wifiHandle,
175                             id,
176                             OUI_QCA,
177                             QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
178     if (wifiConfigCommand == NULL) {
179         ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
180         return WIFI_ERROR_UNKNOWN;
181     }
182 
183     /* Create the NL message. */
184     ret = wifiConfigCommand->create();
185     if (ret != WIFI_SUCCESS) {
186         ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor: failed to "
187             "create NL msg. Error:%d", ret);
188         goto cleanup;
189     }
190 
191     /* Set the interface Id of the message. */
192     ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
193     if (ret != WIFI_SUCCESS) {
194         ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor: failed to "
195             "set iface id. Error:%d", ret);
196         goto cleanup;
197     }
198 
199     /* Add the vendor specific attributes for the NL command. */
200     nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
201     if (!nlData) {
202         ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor: failed "
203             "attr_start for VENDOR_DATA. Error:%d", ret);
204         goto cleanup;
205     }
206 
207     if (wifiConfigCommand->put_u32(
208         QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_STATS_AVG_FACTOR, factor)) {
209         ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor(): failed to "
210             "put vendor data. Error:%d", ret);
211         goto cleanup;
212     }
213     wifiConfigCommand->attr_end(nlData);
214 
215     /* Send the NL msg. */
216     wifiConfigCommand->waitForRsp(false);
217     ret = wifiConfigCommand->requestEvent();
218     if (ret != WIFI_SUCCESS) {
219         ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor(): "
220             "requestEvent Error:%d", ret);
221         goto cleanup;
222     }
223 
224 cleanup:
225     delete wifiConfigCommand;
226     return ret;
227 }
228 
wifi_set_guard_time(wifi_request_id id,wifi_interface_handle iface,u32 guard_time)229 wifi_error wifi_set_guard_time(wifi_request_id id,
230                                wifi_interface_handle iface,
231                                u32 guard_time)
232 {
233     wifi_error ret;
234     WiFiConfigCommand *wifiConfigCommand;
235     struct nlattr *nlData;
236     interface_info *ifaceInfo = getIfaceInfo(iface);
237     wifi_handle wifiHandle = getWifiHandle(iface);
238 
239     ALOGV("%s : guard_time:%u", __FUNCTION__, guard_time);
240 
241     wifiConfigCommand = new WiFiConfigCommand(
242                             wifiHandle,
243                             id,
244                             OUI_QCA,
245                             QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
246     if (wifiConfigCommand == NULL) {
247         ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
248         return WIFI_ERROR_UNKNOWN;
249     }
250 
251     /* Create the NL message. */
252     ret = wifiConfigCommand->create();
253     if (ret != WIFI_SUCCESS) {
254         ALOGE("wifi_set_guard_time: failed to create NL msg. Error:%d", ret);
255         goto cleanup;
256     }
257 
258     /* Set the interface Id of the message. */
259     ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
260     if (ret != WIFI_SUCCESS) {
261         ALOGE("wifi_set_guard_time: failed to set iface id. Error:%d", ret);
262         goto cleanup;
263     }
264 
265     /* Add the vendor specific attributes for the NL command. */
266     nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
267     if (!nlData) {
268         ALOGE("wifi_set_guard_time: failed attr_start for VENDOR_DATA. "
269             "Error:%d", ret);
270         goto cleanup;
271     }
272 
273     if (wifiConfigCommand->put_u32(
274         QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_GUARD_TIME, guard_time)) {
275         ALOGE("wifi_set_guard_time: failed to add vendor data.");
276         goto cleanup;
277     }
278     wifiConfigCommand->attr_end(nlData);
279 
280     /* Send the NL msg. */
281     wifiConfigCommand->waitForRsp(false);
282     ret = wifiConfigCommand->requestEvent();
283     if (ret != WIFI_SUCCESS) {
284         ALOGE("wifi_set_guard_time(): requestEvent Error:%d", ret);
285         goto cleanup;
286     }
287 
288 cleanup:
289     delete wifiConfigCommand;
290     return ret;
291 }
292 
wifi_select_tx_power_scenario(wifi_interface_handle handle,wifi_power_scenario scenario)293 wifi_error wifi_select_tx_power_scenario(wifi_interface_handle handle,
294                                          wifi_power_scenario scenario)
295 {
296     wifi_error ret;
297     WiFiConfigCommand *wifiConfigCommand;
298     struct nlattr *nlData;
299     interface_info *ifaceInfo = getIfaceInfo(handle);
300     wifi_handle wifiHandle = getWifiHandle(handle);
301     u32 bdf_file = 0;
302 
303     ALOGV("%s : power scenario:%d", __FUNCTION__, scenario);
304 
305     wifiConfigCommand = new WiFiConfigCommand(
306                             wifiHandle,
307                             1,
308                             OUI_QCA,
309                             QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS);
310     if (wifiConfigCommand == NULL) {
311         ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
312         return WIFI_ERROR_UNKNOWN;
313     }
314 
315     /* Create the NL message. */
316     ret = wifiConfigCommand->create();
317     if (ret != WIFI_SUCCESS) {
318         ALOGE("wifi_select_tx_power_scenario: failed to create NL msg. Error:%d", ret);
319         goto cleanup;
320     }
321 
322     /* Set the interface Id of the message. */
323     ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
324     if (ret != WIFI_SUCCESS) {
325         ALOGE("wifi_select_tx_power_scenario: failed to set iface id. Error:%d", ret);
326         goto cleanup;
327     }
328 
329     /* Add the vendor specific attributes for the NL command. */
330     nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
331     if (!nlData) {
332         ALOGE("wifi_select_tx_power_scenario: failed attr_start for VENDOR_DATA. "
333             "Error:%d", ret);
334         goto cleanup;
335     }
336 
337     switch (scenario) {
338         case WIFI_POWER_SCENARIO_VOICE_CALL:
339         case WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF:
340             bdf_file = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0;
341             break;
342 
343         case WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON:
344             bdf_file = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF1;
345             break;
346 
347         case WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF:
348             bdf_file = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF2;
349             break;
350 
351         case WIFI_POWER_SCENARIO_ON_BODY_CELL_ON:
352             bdf_file = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF3;
353             break;
354 
355         default:
356             ALOGE("wifi_select_tx_power_scenario: invalid scenario %d", scenario);
357             ret = WIFI_ERROR_INVALID_ARGS;
358             goto cleanup;
359     }
360 
361     if (wifiConfigCommand->put_u32(
362                       QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE,
363                       bdf_file)) {
364         ALOGE("failed to put SAR_ENABLE");
365         goto cleanup;
366     }
367     wifiConfigCommand->attr_end(nlData);
368 
369     ret = wifiConfigCommand->requestEvent();
370     if (ret != WIFI_SUCCESS) {
371         ALOGE("wifi_select_tx_power_scenario(): requestEvent Error:%d", ret);
372         goto cleanup;
373     }
374 
375 cleanup:
376     delete wifiConfigCommand;
377     return ret;
378 }
379 
wifi_reset_tx_power_scenario(wifi_interface_handle handle)380 wifi_error wifi_reset_tx_power_scenario(wifi_interface_handle handle)
381 {
382     wifi_error ret;
383     WiFiConfigCommand *wifiConfigCommand;
384     struct nlattr *nlData;
385     interface_info *ifaceInfo = getIfaceInfo(handle);
386     wifi_handle wifiHandle = getWifiHandle(handle);
387 
388     wifiConfigCommand = new WiFiConfigCommand(
389                             wifiHandle,
390                             1,
391                             OUI_QCA,
392                             QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS);
393     if (wifiConfigCommand == NULL) {
394         ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
395         return WIFI_ERROR_UNKNOWN;
396     }
397 
398     /* Create the NL message. */
399     ret = wifiConfigCommand->create();
400     if (ret != WIFI_SUCCESS) {
401         ALOGE("wifi_reset_tx_power_scenario: failed to create NL msg. Error:%d", ret);
402         goto cleanup;
403     }
404 
405     /* Set the interface Id of the message. */
406     ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
407     if (ret != WIFI_SUCCESS) {
408         ALOGE("wifi_reset_tx_power_scenario: failed to set iface id. Error:%d", ret);
409         goto cleanup;
410     }
411 
412     /* Add the vendor specific attributes for the NL command. */
413     nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
414     if (!nlData) {
415         ALOGE("wifi_reset_tx_power_scenario: failed attr_start for VENDOR_DATA. "
416             "Error:%d", ret);
417         goto cleanup;
418     }
419 
420     if (wifiConfigCommand->put_u32(QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE,
421                                QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE)) {
422         ALOGE("failed to put SAR_ENABLE or NUM_SPECS");
423         goto cleanup;
424     }
425     wifiConfigCommand->attr_end(nlData);
426 
427     ret = wifiConfigCommand->requestEvent();
428     if (ret != WIFI_SUCCESS) {
429         ALOGE("wifi_reset_tx_power_scenario(): requestEvent Error:%d", ret);
430         goto cleanup;
431     }
432 
433 cleanup:
434     delete wifiConfigCommand;
435     return ret;
436 }
437 
WiFiConfigCommand(wifi_handle handle,int id,u32 vendor_id,u32 subcmd)438 WiFiConfigCommand::WiFiConfigCommand(wifi_handle handle,
439                                      int id, u32 vendor_id,
440                                      u32 subcmd)
441         : WifiVendorCommand(handle, id, vendor_id, subcmd)
442 {
443     /* Initialize the member data variables here */
444     mWaitforRsp = false;
445     mRequestId = id;
446 }
447 
~WiFiConfigCommand()448 WiFiConfigCommand::~WiFiConfigCommand()
449 {
450     unregisterVendorHandler(mVendor_id, mSubcmd);
451 }
452 
453 /* This function implements creation of Vendor command */
create()454 wifi_error WiFiConfigCommand::create()
455 {
456     wifi_error ret = mMsg.create(NL80211_CMD_VENDOR, 0, 0);
457     if (ret != WIFI_SUCCESS)
458         return ret;
459 
460     /* Insert the oui in the msg */
461     ret = mMsg.put_u32(NL80211_ATTR_VENDOR_ID, mVendor_id);
462     if (ret != WIFI_SUCCESS)
463         return ret;
464     /* Insert the subcmd in the msg */
465     ret = mMsg.put_u32(NL80211_ATTR_VENDOR_SUBCMD, mSubcmd);
466 
467     return ret;
468 }
469 
470 /* This function implements creation of generic NL command */
create_generic(u8 cmdId)471 wifi_error WiFiConfigCommand::create_generic(u8 cmdId)
472 {
473     wifi_error ret = mMsg.create(cmdId, 0, 0);
474     return ret;
475 }
476 
waitForRsp(bool wait)477 void WiFiConfigCommand::waitForRsp(bool wait)
478 {
479     mWaitforRsp = wait;
480 }
481 
482 /* Callback handlers registered for nl message send */
error_handler_wifi_config(struct sockaddr_nl * nla,struct nlmsgerr * err,void * arg)483 static int error_handler_wifi_config(struct sockaddr_nl *nla,
484                                      struct nlmsgerr *err,
485                                      void *arg)
486 {
487     struct sockaddr_nl *tmp;
488     int *ret = (int *)arg;
489     tmp = nla;
490     *ret = err->error;
491     ALOGE("%s: Error code:%d (%s)", __FUNCTION__, *ret, strerror(-(*ret)));
492     return NL_STOP;
493 }
494 
495 /* Callback handlers registered for nl message send */
ack_handler_wifi_config(struct nl_msg * msg,void * arg)496 static int ack_handler_wifi_config(struct nl_msg *msg, void *arg)
497 {
498     int *ret = (int *)arg;
499     struct nl_msg * a;
500 
501     a = msg;
502     *ret = 0;
503     return NL_STOP;
504 }
505 
506 /* Callback handlers registered for nl message send */
finish_handler_wifi_config(struct nl_msg * msg,void * arg)507 static int finish_handler_wifi_config(struct nl_msg *msg, void *arg)
508 {
509   int *ret = (int *)arg;
510   struct nl_msg * a;
511 
512   a = msg;
513   *ret = 0;
514   return NL_SKIP;
515 }
516 
517 /*
518  * Override base class requestEvent and implement little differently here.
519  * This will send the request message.
520  * We don't wait for any response back in case of wificonfig,
521  * thus no wait for condition.
522  */
requestEvent()523 wifi_error WiFiConfigCommand::requestEvent()
524 {
525     int status;
526     wifi_error res = WIFI_SUCCESS;
527     struct nl_cb *cb;
528 
529     cb = nl_cb_alloc(NL_CB_DEFAULT);
530     if (!cb) {
531         ALOGE("%s: Callback allocation failed",__FUNCTION__);
532         res = WIFI_ERROR_OUT_OF_MEMORY;
533         goto out;
534     }
535 
536     status = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage());
537     if (status < 0) {
538         res = mapKernelErrortoWifiHalError(status);
539         goto out;
540     }
541     status = 1;
542 
543     nl_cb_err(cb, NL_CB_CUSTOM, error_handler_wifi_config, &status);
544     nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler_wifi_config,
545         &status);
546     nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler_wifi_config, &status);
547 
548     /* Err is populated as part of finish_handler. */
549     while (status > 0) {
550          nl_recvmsgs(mInfo->cmd_sock, cb);
551     }
552 
553     if (status < 0) {
554         res = mapKernelErrortoWifiHalError(status);
555         goto out;
556     }
557 
558     if (mWaitforRsp == true) {
559         struct timespec abstime;
560         abstime.tv_sec = 4;
561         abstime.tv_nsec = 0;
562         res = mCondition.wait(abstime);
563         if (res == WIFI_ERROR_TIMED_OUT)
564             ALOGE("%s: Time out happened.", __FUNCTION__);
565 
566         ALOGV("%s: Command invoked return value:%d, mWaitForRsp=%d",
567             __FUNCTION__, res, mWaitforRsp);
568     }
569 out:
570     /* Cleanup the mMsg */
571     mMsg.destroy();
572     return res;
573 }
574 
575