• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2015, 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     int ret = 0;
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 < 0) {
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 < 0) {
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     if (wifiConfigCommand->put_u32(
87         QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_DYNAMIC_DTIM, extended_dtim)) {
88         ALOGE("wifi_extended_dtim_config_set(): failed to put vendor data. "
89             "Error:%d", ret);
90         goto cleanup;
91     }
92     wifiConfigCommand->attr_end(nlData);
93 
94     /* Send the NL msg. */
95     wifiConfigCommand->waitForRsp(false);
96     ret = wifiConfigCommand->requestEvent();
97     if (ret != 0) {
98         ALOGE("wifi_extended_dtim_config_set(): requestEvent Error:%d", ret);
99         goto cleanup;
100     }
101 
102 cleanup:
103     delete wifiConfigCommand;
104     return mapErrorKernelToWifiHAL(ret);
105 }
106 
107 /* Set the country code to driver. */
wifi_set_country_code(wifi_interface_handle iface,const char * country_code)108 wifi_error wifi_set_country_code(wifi_interface_handle iface,
109                                  const char* country_code)
110 {
111     int requestId, ret = 0;
112     WiFiConfigCommand *wifiConfigCommand;
113     wifi_handle wifiHandle = getWifiHandle(iface);
114 
115     ALOGV("%s: %s", __FUNCTION__, country_code);
116 
117     /* No request id from caller, so generate one and pass it on to the driver.
118      * Generate it randomly.
119      */
120     requestId = get_requestid();
121 
122     wifiConfigCommand = new WiFiConfigCommand(
123                             wifiHandle,
124                             requestId,
125                             OUI_QCA,
126                             QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
127     if (wifiConfigCommand == NULL) {
128         ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
129         return WIFI_ERROR_UNKNOWN;
130     }
131 
132     /* Create the NL message with NL80211_CMD_REQ_SET_REG NL cmd. */
133     ret = wifiConfigCommand->create_generic(NL80211_CMD_REQ_SET_REG);
134     if (ret < 0) {
135         ALOGE("wifi_set_country_code: failed to create NL msg. Error:%d", ret);
136         goto cleanup;
137     }
138 
139     if (wifiConfigCommand->put_string(NL80211_ATTR_REG_ALPHA2, country_code)) {
140         ALOGE("wifi_set_country_code: put country code failed. Error:%d", ret);
141         goto cleanup;
142     }
143 
144     /* Send the NL msg. */
145     wifiConfigCommand->waitForRsp(false);
146     ret = wifiConfigCommand->requestEvent();
147     if (ret != 0) {
148         ALOGE("wifi_set_country_code(): requestEvent Error:%d", ret);
149         goto cleanup;
150     }
151     usleep(WAIT_TIME_FOR_SET_REG_DOMAIN);
152 
153 cleanup:
154     delete wifiConfigCommand;
155     return mapErrorKernelToWifiHAL(ret);
156 }
157 
wifi_set_beacon_wifi_iface_stats_averaging_factor(wifi_request_id id,wifi_interface_handle iface,u16 factor)158 wifi_error wifi_set_beacon_wifi_iface_stats_averaging_factor(
159                                                 wifi_request_id id,
160                                                 wifi_interface_handle iface,
161                                                 u16 factor)
162 {
163     int ret = 0;
164     WiFiConfigCommand *wifiConfigCommand;
165     struct nlattr *nlData;
166     interface_info *ifaceInfo = getIfaceInfo(iface);
167     wifi_handle wifiHandle = getWifiHandle(iface);
168 
169     ALOGV("%s factor:%u", __FUNCTION__, factor);
170     wifiConfigCommand = new WiFiConfigCommand(
171                             wifiHandle,
172                             id,
173                             OUI_QCA,
174                             QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
175     if (wifiConfigCommand == NULL) {
176         ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
177         return WIFI_ERROR_UNKNOWN;
178     }
179 
180     /* Create the NL message. */
181     ret = wifiConfigCommand->create();
182     if (ret < 0) {
183         ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor: failed to "
184             "create NL msg. Error:%d", ret);
185         goto cleanup;
186     }
187 
188     /* Set the interface Id of the message. */
189     ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
190     if (ret < 0) {
191         ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor: failed to "
192             "set iface id. Error:%d", ret);
193         goto cleanup;
194     }
195 
196     /* Add the vendor specific attributes for the NL command. */
197     nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
198     if (!nlData) {
199         ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor: failed "
200             "attr_start for VENDOR_DATA. Error:%d", ret);
201         goto cleanup;
202     }
203 
204     if (wifiConfigCommand->put_u32(
205         QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_STATS_AVG_FACTOR, factor)) {
206         ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor(): failed to "
207             "put vendor data. Error:%d", ret);
208         goto cleanup;
209     }
210     wifiConfigCommand->attr_end(nlData);
211 
212     /* Send the NL msg. */
213     wifiConfigCommand->waitForRsp(false);
214     ret = wifiConfigCommand->requestEvent();
215     if (ret != 0) {
216         ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor(): "
217             "requestEvent Error:%d", ret);
218         goto cleanup;
219     }
220 
221 cleanup:
222     delete wifiConfigCommand;
223     return mapErrorKernelToWifiHAL(ret);
224 }
225 
wifi_set_guard_time(wifi_request_id id,wifi_interface_handle iface,u32 guard_time)226 wifi_error wifi_set_guard_time(wifi_request_id id,
227                                wifi_interface_handle iface,
228                                u32 guard_time)
229 {
230     int ret = 0;
231     WiFiConfigCommand *wifiConfigCommand;
232     struct nlattr *nlData;
233     interface_info *ifaceInfo = getIfaceInfo(iface);
234     wifi_handle wifiHandle = getWifiHandle(iface);
235 
236     ALOGV("%s : guard_time:%u", __FUNCTION__, guard_time);
237 
238     wifiConfigCommand = new WiFiConfigCommand(
239                             wifiHandle,
240                             id,
241                             OUI_QCA,
242                             QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
243     if (wifiConfigCommand == NULL) {
244         ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
245         return WIFI_ERROR_UNKNOWN;
246     }
247 
248     /* Create the NL message. */
249     ret = wifiConfigCommand->create();
250     if (ret < 0) {
251         ALOGE("wifi_set_guard_time: failed to create NL msg. Error:%d", ret);
252         goto cleanup;
253     }
254 
255     /* Set the interface Id of the message. */
256     ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
257     if (ret < 0) {
258         ALOGE("wifi_set_guard_time: failed to set iface id. Error:%d", ret);
259         goto cleanup;
260     }
261 
262     /* Add the vendor specific attributes for the NL command. */
263     nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
264     if (!nlData) {
265         ALOGE("wifi_set_guard_time: failed attr_start for VENDOR_DATA. "
266             "Error:%d", ret);
267         goto cleanup;
268     }
269 
270     if (wifiConfigCommand->put_u32(
271         QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_GUARD_TIME, guard_time)) {
272         ALOGE("wifi_set_guard_time: failed to add vendor data.");
273         goto cleanup;
274     }
275     wifiConfigCommand->attr_end(nlData);
276 
277     /* Send the NL msg. */
278     wifiConfigCommand->waitForRsp(false);
279     ret = wifiConfigCommand->requestEvent();
280     if (ret != 0) {
281         ALOGE("wifi_set_guard_time(): requestEvent Error:%d", ret);
282         goto cleanup;
283     }
284 
285 cleanup:
286     delete wifiConfigCommand;
287     return mapErrorKernelToWifiHAL(ret);
288 }
289 
wifi_select_tx_power_scenario(wifi_interface_handle handle,wifi_power_scenario scenario)290 wifi_error wifi_select_tx_power_scenario(wifi_interface_handle handle,
291                                          wifi_power_scenario scenario)
292 {
293     int ret = 0;
294     WiFiConfigCommand *wifiConfigCommand;
295     struct nlattr *nlData;
296     interface_info *ifaceInfo = getIfaceInfo(handle);
297     wifi_handle wifiHandle = getWifiHandle(handle);
298     u32 bdf_file = 0;
299 
300     ALOGV("%s : power scenario:%d", __FUNCTION__, scenario);
301 
302     wifiConfigCommand = new WiFiConfigCommand(
303                             wifiHandle,
304                             1,
305                             OUI_QCA,
306                             QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS);
307     if (wifiConfigCommand == NULL) {
308         ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
309         return WIFI_ERROR_UNKNOWN;
310     }
311 
312     /* Create the NL message. */
313     ret = wifiConfigCommand->create();
314     if (ret < 0) {
315         ALOGE("wifi_select_tx_power_scenario: failed to create NL msg. Error:%d", ret);
316         goto cleanup;
317     }
318 
319     /* Set the interface Id of the message. */
320     ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
321     if (ret < 0) {
322         ALOGE("wifi_select_tx_power_scenario: failed to set iface id. Error:%d", ret);
323         goto cleanup;
324     }
325 
326     /* Add the vendor specific attributes for the NL command. */
327     nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
328     if (!nlData) {
329         ALOGE("wifi_select_tx_power_scenario: failed attr_start for VENDOR_DATA. "
330             "Error:%d", ret);
331         goto cleanup;
332     }
333 
334     if (scenario == WIFI_POWER_SCENARIO_VOICE_CALL) {
335         bdf_file = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0;
336     } else {
337         ALOGE("wifi_select_tx_power_scenario: invalid scenario %d", scenario);
338         ret = WIFI_ERROR_INVALID_ARGS;
339         goto cleanup;
340     }
341     if (wifiConfigCommand->put_u32(
342                       QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE,
343                       bdf_file)) {
344         ALOGE("failed to put SAR_ENABLE");
345         goto cleanup;
346     }
347     wifiConfigCommand->attr_end(nlData);
348 
349     ret = wifiConfigCommand->requestEvent();
350     if (ret != 0) {
351         ALOGE("wifi_select_tx_power_scenario(): requestEvent Error:%d", ret);
352         goto cleanup;
353     }
354 
355 cleanup:
356     delete wifiConfigCommand;
357     return mapErrorKernelToWifiHAL(ret);
358 }
359 
wifi_reset_tx_power_scenario(wifi_interface_handle handle)360 wifi_error wifi_reset_tx_power_scenario(wifi_interface_handle handle)
361 {
362     int ret = 0;
363     WiFiConfigCommand *wifiConfigCommand;
364     struct nlattr *nlData;
365     interface_info *ifaceInfo = getIfaceInfo(handle);
366     wifi_handle wifiHandle = getWifiHandle(handle);
367 
368     wifiConfigCommand = new WiFiConfigCommand(
369                             wifiHandle,
370                             1,
371                             OUI_QCA,
372                             QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS);
373     if (wifiConfigCommand == NULL) {
374         ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
375         return WIFI_ERROR_UNKNOWN;
376     }
377 
378     /* Create the NL message. */
379     ret = wifiConfigCommand->create();
380     if (ret < 0) {
381         ALOGE("wifi_reset_tx_power_scenario: failed to create NL msg. Error:%d", ret);
382         goto cleanup;
383     }
384 
385     /* Set the interface Id of the message. */
386     ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
387     if (ret < 0) {
388         ALOGE("wifi_reset_tx_power_scenario: failed to set iface id. Error:%d", ret);
389         goto cleanup;
390     }
391 
392     /* Add the vendor specific attributes for the NL command. */
393     nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
394     if (!nlData) {
395         ALOGE("wifi_reset_tx_power_scenario: failed attr_start for VENDOR_DATA. "
396             "Error:%d", ret);
397         goto cleanup;
398     }
399 
400     if (wifiConfigCommand->put_u32(QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE,
401                                QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE)) {
402         ALOGE("failed to put SAR_ENABLE or NUM_SPECS");
403         goto cleanup;
404     }
405     wifiConfigCommand->attr_end(nlData);
406 
407     ret = wifiConfigCommand->requestEvent();
408     if (ret != 0) {
409         ALOGE("wifi_reset_tx_power_scenario(): requestEvent Error:%d", ret);
410         goto cleanup;
411     }
412 
413 cleanup:
414     delete wifiConfigCommand;
415     return mapErrorKernelToWifiHAL(ret);
416 }
417 
WiFiConfigCommand(wifi_handle handle,int id,u32 vendor_id,u32 subcmd)418 WiFiConfigCommand::WiFiConfigCommand(wifi_handle handle,
419                                      int id, u32 vendor_id,
420                                      u32 subcmd)
421         : WifiVendorCommand(handle, id, vendor_id, subcmd)
422 {
423     /* Initialize the member data variables here */
424     mWaitforRsp = false;
425     mRequestId = id;
426 }
427 
~WiFiConfigCommand()428 WiFiConfigCommand::~WiFiConfigCommand()
429 {
430     unregisterVendorHandler(mVendor_id, mSubcmd);
431 }
432 
433 /* This function implements creation of Vendor command */
create()434 int WiFiConfigCommand::create() {
435     int ret = mMsg.create(NL80211_CMD_VENDOR, 0, 0);
436     if (ret < 0) {
437         return ret;
438     }
439 
440     /* Insert the oui in the msg */
441     ret = mMsg.put_u32(NL80211_ATTR_VENDOR_ID, mVendor_id);
442     if (ret < 0)
443         goto out;
444     /* Insert the subcmd in the msg */
445     ret = mMsg.put_u32(NL80211_ATTR_VENDOR_SUBCMD, mSubcmd);
446     if (ret < 0)
447         goto out;
448 out:
449     return ret;
450 }
451 
452 /* This function implements creation of generic NL command */
create_generic(u8 cmdId)453 int WiFiConfigCommand::create_generic(u8 cmdId) {
454     int ret = mMsg.create(cmdId, 0, 0);
455     return ret;
456 }
457 
waitForRsp(bool wait)458 void WiFiConfigCommand::waitForRsp(bool wait)
459 {
460     mWaitforRsp = wait;
461 }
462 
463 /* Callback handlers registered for nl message send */
error_handler_wifi_config(struct sockaddr_nl * nla,struct nlmsgerr * err,void * arg)464 static int error_handler_wifi_config(struct sockaddr_nl *nla,
465                                      struct nlmsgerr *err,
466                                      void *arg)
467 {
468     struct sockaddr_nl *tmp;
469     int *ret = (int *)arg;
470     tmp = nla;
471     *ret = err->error;
472     ALOGE("%s: Error code:%d (%s)", __FUNCTION__, *ret, strerror(-(*ret)));
473     return NL_STOP;
474 }
475 
476 /* Callback handlers registered for nl message send */
ack_handler_wifi_config(struct nl_msg * msg,void * arg)477 static int ack_handler_wifi_config(struct nl_msg *msg, void *arg)
478 {
479     int *ret = (int *)arg;
480     struct nl_msg * a;
481 
482     a = msg;
483     *ret = 0;
484     return NL_STOP;
485 }
486 
487 /* Callback handlers registered for nl message send */
finish_handler_wifi_config(struct nl_msg * msg,void * arg)488 static int finish_handler_wifi_config(struct nl_msg *msg, void *arg)
489 {
490   int *ret = (int *)arg;
491   struct nl_msg * a;
492 
493   a = msg;
494   *ret = 0;
495   return NL_SKIP;
496 }
497 
498 /*
499  * Override base class requestEvent and implement little differently here.
500  * This will send the request message.
501  * We don't wait for any response back in case of wificonfig,
502  * thus no wait for condition.
503  */
requestEvent()504 int WiFiConfigCommand::requestEvent()
505 {
506     int res = -1;
507     struct nl_cb *cb;
508 
509     cb = nl_cb_alloc(NL_CB_DEFAULT);
510     if (!cb) {
511         ALOGE("%s: Callback allocation failed",__FUNCTION__);
512         res = -1;
513         goto out;
514     }
515 
516     res = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage());
517     if (res < 0)
518         goto out;
519     res = 1;
520 
521     nl_cb_err(cb, NL_CB_CUSTOM, error_handler_wifi_config, &res);
522     nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler_wifi_config,
523         &res);
524     nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler_wifi_config, &res);
525 
526     /* Err is populated as part of finish_handler. */
527     while (res > 0){
528          nl_recvmsgs(mInfo->cmd_sock, cb);
529     }
530 
531     /* Only wait for the asynchronous event if HDD returns success, res=0 */
532     if (!res && (mWaitforRsp == true)) {
533         struct timespec abstime;
534         abstime.tv_sec = 4;
535         abstime.tv_nsec = 0;
536         res = mCondition.wait(abstime);
537         if (res == ETIMEDOUT)
538         {
539             ALOGE("%s: Time out happened.", __FUNCTION__);
540         }
541         ALOGV("%s: Command invoked return value:%d, mWaitForRsp=%d",
542             __FUNCTION__, res, mWaitforRsp);
543     }
544 out:
545     /* Cleanup the mMsg */
546     mMsg.destroy();
547     return res;
548 }
549 
550