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_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 
check_feature(enum qca_wlan_vendor_features feature,features_info * info)108 int check_feature(enum qca_wlan_vendor_features feature, features_info *info)
109 {
110     size_t idx = feature / 8;
111 
112     return (idx < info->flags_len) &&
113             (info->flags[idx] & BIT(feature % 8));
114 }
115 
116 /* Set the country code to driver. */
wifi_set_country_code(wifi_interface_handle iface,const char * country_code)117 wifi_error wifi_set_country_code(wifi_interface_handle iface,
118                                  const char* country_code)
119 {
120     int requestId;
121     wifi_error ret;
122     WiFiConfigCommand *wifiConfigCommand;
123     wifi_handle wifiHandle = getWifiHandle(iface);
124     hal_info *info = getHalInfo(wifiHandle);
125 
126     ALOGV("%s: %s", __FUNCTION__, country_code);
127 
128     /* No request id from caller, so generate one and pass it on to the driver.
129      * Generate it randomly.
130      */
131     requestId = get_requestid();
132 
133     wifiConfigCommand = new WiFiConfigCommand(
134                             wifiHandle,
135                             requestId,
136                             OUI_QCA,
137                             QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
138     if (wifiConfigCommand == NULL) {
139         ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
140         return WIFI_ERROR_UNKNOWN;
141     }
142 
143     /* Create the NL message with NL80211_CMD_REQ_SET_REG NL cmd. */
144     ret = wifiConfigCommand->create_generic(NL80211_CMD_REQ_SET_REG);
145     if (ret != WIFI_SUCCESS) {
146         ALOGE("wifi_set_country_code: failed to create NL msg. Error:%d", ret);
147         goto cleanup;
148     }
149 
150     ret = wifiConfigCommand->put_string(NL80211_ATTR_REG_ALPHA2, country_code);
151     if (ret != WIFI_SUCCESS) {
152         ALOGE("wifi_set_country_code: put country code failed. Error:%d", ret);
153         goto cleanup;
154     }
155 
156     if (check_feature(QCA_WLAN_VENDOR_FEATURE_SELF_MANAGED_REGULATORY,
157                       &info->driver_supported_features)) {
158         ret = wifiConfigCommand->put_u32(NL80211_ATTR_USER_REG_HINT_TYPE,
159                                          NL80211_USER_REG_HINT_CELL_BASE);
160         if (ret != WIFI_SUCCESS) {
161             ALOGE("wifi_set_country_code: put reg hint type failed. Error:%d",
162                   ret);
163             goto cleanup;
164         }
165     }
166 
167 
168     /* Send the NL msg. */
169     wifiConfigCommand->waitForRsp(false);
170     ret = wifiConfigCommand->requestEvent();
171     if (ret != WIFI_SUCCESS) {
172         ALOGE("wifi_set_country_code(): requestEvent Error:%d", ret);
173         goto cleanup;
174     }
175     usleep(WAIT_TIME_FOR_SET_REG_DOMAIN);
176 
177 cleanup:
178     delete wifiConfigCommand;
179     return ret;
180 }
181 
wifi_set_beacon_wifi_iface_stats_averaging_factor(wifi_request_id id,wifi_interface_handle iface,u16 factor)182 wifi_error wifi_set_beacon_wifi_iface_stats_averaging_factor(
183                                                 wifi_request_id id,
184                                                 wifi_interface_handle iface,
185                                                 u16 factor)
186 {
187     wifi_error ret;
188     WiFiConfigCommand *wifiConfigCommand;
189     struct nlattr *nlData;
190     interface_info *ifaceInfo = getIfaceInfo(iface);
191     wifi_handle wifiHandle = getWifiHandle(iface);
192 
193     ALOGV("%s factor:%u", __FUNCTION__, factor);
194     wifiConfigCommand = new WiFiConfigCommand(
195                             wifiHandle,
196                             id,
197                             OUI_QCA,
198                             QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
199     if (wifiConfigCommand == NULL) {
200         ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
201         return WIFI_ERROR_UNKNOWN;
202     }
203 
204     /* Create the NL message. */
205     ret = wifiConfigCommand->create();
206     if (ret != WIFI_SUCCESS) {
207         ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor: failed to "
208             "create NL msg. Error:%d", ret);
209         goto cleanup;
210     }
211 
212     /* Set the interface Id of the message. */
213     ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
214     if (ret != WIFI_SUCCESS) {
215         ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor: failed to "
216             "set iface id. Error:%d", ret);
217         goto cleanup;
218     }
219 
220     /* Add the vendor specific attributes for the NL command. */
221     nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
222     if (!nlData) {
223         ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor: failed "
224             "attr_start for VENDOR_DATA. Error:%d", ret);
225         goto cleanup;
226     }
227 
228     if (wifiConfigCommand->put_u32(
229         QCA_WLAN_VENDOR_ATTR_CONFIG_STATS_AVG_FACTOR, factor)) {
230         ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor(): failed to "
231             "put vendor data. Error:%d", ret);
232         goto cleanup;
233     }
234     wifiConfigCommand->attr_end(nlData);
235 
236     /* Send the NL msg. */
237     wifiConfigCommand->waitForRsp(false);
238     ret = wifiConfigCommand->requestEvent();
239     if (ret != WIFI_SUCCESS) {
240         ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor(): "
241             "requestEvent Error:%d", ret);
242         goto cleanup;
243     }
244 
245 cleanup:
246     delete wifiConfigCommand;
247     return ret;
248 }
249 
wifi_set_guard_time(wifi_request_id id,wifi_interface_handle iface,u32 guard_time)250 wifi_error wifi_set_guard_time(wifi_request_id id,
251                                wifi_interface_handle iface,
252                                u32 guard_time)
253 {
254     wifi_error ret;
255     WiFiConfigCommand *wifiConfigCommand;
256     struct nlattr *nlData;
257     interface_info *ifaceInfo = getIfaceInfo(iface);
258     wifi_handle wifiHandle = getWifiHandle(iface);
259 
260     ALOGV("%s : guard_time:%u", __FUNCTION__, guard_time);
261 
262     wifiConfigCommand = new WiFiConfigCommand(
263                             wifiHandle,
264                             id,
265                             OUI_QCA,
266                             QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
267     if (wifiConfigCommand == NULL) {
268         ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
269         return WIFI_ERROR_UNKNOWN;
270     }
271 
272     /* Create the NL message. */
273     ret = wifiConfigCommand->create();
274     if (ret != WIFI_SUCCESS) {
275         ALOGE("wifi_set_guard_time: failed to create NL msg. Error:%d", ret);
276         goto cleanup;
277     }
278 
279     /* Set the interface Id of the message. */
280     ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
281     if (ret != WIFI_SUCCESS) {
282         ALOGE("wifi_set_guard_time: failed to set iface id. Error:%d", ret);
283         goto cleanup;
284     }
285 
286     /* Add the vendor specific attributes for the NL command. */
287     nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
288     if (!nlData) {
289         ALOGE("wifi_set_guard_time: failed attr_start for VENDOR_DATA. "
290             "Error:%d", ret);
291         goto cleanup;
292     }
293 
294     if (wifiConfigCommand->put_u32(
295         QCA_WLAN_VENDOR_ATTR_CONFIG_GUARD_TIME, guard_time)) {
296         ALOGE("wifi_set_guard_time: failed to add vendor data.");
297         goto cleanup;
298     }
299     wifiConfigCommand->attr_end(nlData);
300 
301     /* Send the NL msg. */
302     wifiConfigCommand->waitForRsp(false);
303     ret = wifiConfigCommand->requestEvent();
304     if (ret != WIFI_SUCCESS) {
305         ALOGE("wifi_set_guard_time(): requestEvent Error:%d", ret);
306         goto cleanup;
307     }
308 
309 cleanup:
310     delete wifiConfigCommand;
311     return ret;
312 }
313 
wifi_select_tx_power_scenario(wifi_interface_handle handle,wifi_power_scenario scenario)314 wifi_error wifi_select_tx_power_scenario(wifi_interface_handle handle,
315                                          wifi_power_scenario scenario)
316 {
317     wifi_error ret;
318     WiFiConfigCommand *wifiConfigCommand;
319     struct nlattr *nlData;
320     interface_info *ifaceInfo = getIfaceInfo(handle);
321     wifi_handle wifiHandle = getWifiHandle(handle);
322     u32 bdf_file = 0;
323 
324     ALOGV("%s : power scenario:%d", __FUNCTION__, scenario);
325 
326     wifiConfigCommand = new WiFiConfigCommand(
327                             wifiHandle,
328                             1,
329                             OUI_QCA,
330                             QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS);
331     if (wifiConfigCommand == NULL) {
332         ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
333         return WIFI_ERROR_UNKNOWN;
334     }
335 
336     /* Create the NL message. */
337     ret = wifiConfigCommand->create();
338     if (ret != WIFI_SUCCESS) {
339         ALOGE("wifi_select_tx_power_scenario: failed to create NL msg. Error:%d", ret);
340         goto cleanup;
341     }
342 
343     /* Set the interface Id of the message. */
344     ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
345     if (ret != WIFI_SUCCESS) {
346         ALOGE("wifi_select_tx_power_scenario: failed to set iface id. Error:%d", ret);
347         goto cleanup;
348     }
349 
350     /* Add the vendor specific attributes for the NL command. */
351     nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
352     if (!nlData) {
353         ALOGE("wifi_select_tx_power_scenario: failed attr_start for VENDOR_DATA. "
354             "Error:%d", ret);
355         goto cleanup;
356     }
357 
358     switch (scenario) {
359         case WIFI_POWER_SCENARIO_VOICE_CALL:
360         case WIFI_POWER_SCENARIO_ON_HEAD_CELL_OFF:
361         case WIFI_POWER_SCENARIO_ON_BODY_BT:
362             bdf_file = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF0;
363             break;
364 
365         case WIFI_POWER_SCENARIO_ON_HEAD_CELL_ON:
366             bdf_file = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF1;
367             break;
368 
369         case WIFI_POWER_SCENARIO_ON_BODY_CELL_OFF:
370             bdf_file = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF2;
371             break;
372 
373         case WIFI_POWER_SCENARIO_ON_BODY_CELL_ON:
374             bdf_file = QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_BDF3;
375             break;
376 
377         default:
378             ALOGE("wifi_select_tx_power_scenario: invalid scenario %d", scenario);
379             ret = WIFI_ERROR_INVALID_ARGS;
380             goto cleanup;
381     }
382 
383     if (wifiConfigCommand->put_u32(
384                       QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE,
385                       bdf_file)) {
386         ALOGE("failed to put SAR_ENABLE");
387         goto cleanup;
388     }
389     wifiConfigCommand->attr_end(nlData);
390 
391     ret = wifiConfigCommand->requestEvent();
392     if (ret != WIFI_SUCCESS) {
393         ALOGE("wifi_select_tx_power_scenario(): requestEvent Error:%d", ret);
394         goto cleanup;
395     }
396 
397 cleanup:
398     delete wifiConfigCommand;
399     return ret;
400 }
401 
wifi_reset_tx_power_scenario(wifi_interface_handle handle)402 wifi_error wifi_reset_tx_power_scenario(wifi_interface_handle handle)
403 {
404     wifi_error ret;
405     WiFiConfigCommand *wifiConfigCommand;
406     struct nlattr *nlData;
407     interface_info *ifaceInfo = getIfaceInfo(handle);
408     wifi_handle wifiHandle = getWifiHandle(handle);
409 
410     wifiConfigCommand = new WiFiConfigCommand(
411                             wifiHandle,
412                             1,
413                             OUI_QCA,
414                             QCA_NL80211_VENDOR_SUBCMD_SET_SAR_LIMITS);
415     if (wifiConfigCommand == NULL) {
416         ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
417         return WIFI_ERROR_UNKNOWN;
418     }
419 
420     /* Create the NL message. */
421     ret = wifiConfigCommand->create();
422     if (ret != WIFI_SUCCESS) {
423         ALOGE("wifi_reset_tx_power_scenario: failed to create NL msg. Error:%d", ret);
424         goto cleanup;
425     }
426 
427     /* Set the interface Id of the message. */
428     ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
429     if (ret != WIFI_SUCCESS) {
430         ALOGE("wifi_reset_tx_power_scenario: failed to set iface id. Error:%d", ret);
431         goto cleanup;
432     }
433 
434     /* Add the vendor specific attributes for the NL command. */
435     nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
436     if (!nlData) {
437         ALOGE("wifi_reset_tx_power_scenario: failed attr_start for VENDOR_DATA. "
438             "Error:%d", ret);
439         goto cleanup;
440     }
441 
442     if (wifiConfigCommand->put_u32(QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SAR_ENABLE,
443                                QCA_WLAN_VENDOR_ATTR_SAR_LIMITS_SELECT_NONE)) {
444         ALOGE("failed to put SAR_ENABLE or NUM_SPECS");
445         goto cleanup;
446     }
447     wifiConfigCommand->attr_end(nlData);
448 
449     ret = wifiConfigCommand->requestEvent();
450     if (ret != WIFI_SUCCESS) {
451         ALOGE("wifi_reset_tx_power_scenario(): requestEvent Error:%d", ret);
452         goto cleanup;
453     }
454 
455 cleanup:
456     delete wifiConfigCommand;
457     return ret;
458 }
459 
wifi_set_latency_mode(wifi_interface_handle handle,wifi_latency_mode mode)460 wifi_error wifi_set_latency_mode(wifi_interface_handle handle,
461                                  wifi_latency_mode mode) {
462     wifi_error ret;
463     WiFiConfigCommand *wifiConfigCommand;
464     struct nlattr *nlData;
465     u32 latency_mode;
466     interface_info *ifaceInfo = getIfaceInfo(handle);
467     wifi_handle wifiHandle = getWifiHandle(handle);
468     hal_info *info = getHalInfo(wifiHandle);
469 
470     ALOGV("%s : latency mode:%d", __FUNCTION__, mode);
471 
472     /* Check Supported low-latency capability */
473     if (!(info->supported_feature_set & WIFI_FEATURE_SET_LATENCY_MODE)) {
474         ALOGE("%s: Set latency mode feature not supported %x", __FUNCTION__,
475               info->supported_feature_set);
476         return WIFI_ERROR_NOT_SUPPORTED;
477     }
478 
479     wifiConfigCommand = new WiFiConfigCommand(
480                             wifiHandle,
481                             1,
482                             OUI_QCA,
483                             QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
484     if (wifiConfigCommand == NULL) {
485         ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
486         return WIFI_ERROR_UNKNOWN;
487     }
488 
489     /* Create the NL message. */
490     ret = wifiConfigCommand->create();
491     if (ret != WIFI_SUCCESS) {
492         ALOGE("wifi_set_latency_mode: failed to create NL msg. Error:%d", ret);
493         goto cleanup;
494     }
495 
496     /* Set the interface Id of the message. */
497     ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
498     if (ret != WIFI_SUCCESS) {
499         ALOGE("wifi_set_latency_mode: failed to set iface id. Error:%d", ret);
500         goto cleanup;
501     }
502 
503     /* Add the vendor specific attributes for the NL command. */
504     nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
505     if (!nlData) {
506         ret = WIFI_ERROR_UNKNOWN;
507         ALOGE("wifi_set_latency_mode: failed attr_start for VENDOR_DATA. "
508             "Error:%d", ret);
509         goto cleanup;
510     }
511 
512     switch(mode) {
513         case WIFI_LATENCY_MODE_NORMAL:
514             latency_mode = QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_NORMAL;
515         break;
516 
517         case WIFI_LATENCY_MODE_LOW:
518             latency_mode = QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL_LOW;
519         break;
520 
521         default:
522             ALOGE("wifi_set_latency_mode: Invalid mode: %d", mode);
523             ret = WIFI_ERROR_UNKNOWN;
524             goto cleanup;
525     }
526 
527     if (wifiConfigCommand->put_u32(
528                       QCA_WLAN_VENDOR_ATTR_CONFIG_LATENCY_LEVEL,
529                       latency_mode)) {
530         ALOGE("wifi_set_latency_mode: failed to put latency mode");
531         ret = WIFI_ERROR_UNKNOWN;
532         goto cleanup;
533     }
534     wifiConfigCommand->attr_end(nlData);
535 
536     /* Send the NL msg. */
537     wifiConfigCommand->waitForRsp(false);
538     ret = wifiConfigCommand->requestEvent();
539     if (ret != WIFI_SUCCESS) {
540         ALOGE("wifi_set_latency_mode: requestEvent Error:%d", ret);
541         goto cleanup;
542     }
543 
544 cleanup:
545     delete wifiConfigCommand;
546     return ret;
547 }
548 
WiFiConfigCommand(wifi_handle handle,int id,u32 vendor_id,u32 subcmd)549 WiFiConfigCommand::WiFiConfigCommand(wifi_handle handle,
550                                      int id, u32 vendor_id,
551                                      u32 subcmd)
552         : WifiVendorCommand(handle, id, vendor_id, subcmd)
553 {
554     /* Initialize the member data variables here */
555     mWaitforRsp = false;
556     mRequestId = id;
557 }
558 
~WiFiConfigCommand()559 WiFiConfigCommand::~WiFiConfigCommand()
560 {
561     unregisterVendorHandler(mVendor_id, mSubcmd);
562 }
563 
564 /* This function implements creation of Vendor command */
create()565 wifi_error WiFiConfigCommand::create()
566 {
567     wifi_error ret = mMsg.create(NL80211_CMD_VENDOR, 0, 0);
568     if (ret != WIFI_SUCCESS)
569         return ret;
570 
571     /* Insert the oui in the msg */
572     ret = mMsg.put_u32(NL80211_ATTR_VENDOR_ID, mVendor_id);
573     if (ret != WIFI_SUCCESS)
574         return ret;
575     /* Insert the subcmd in the msg */
576     ret = mMsg.put_u32(NL80211_ATTR_VENDOR_SUBCMD, mSubcmd);
577 
578     return ret;
579 }
580 
581 /* This function implements creation of generic NL command */
create_generic(u8 cmdId)582 wifi_error WiFiConfigCommand::create_generic(u8 cmdId)
583 {
584     wifi_error ret = mMsg.create(cmdId, 0, 0);
585     return ret;
586 }
587 
waitForRsp(bool wait)588 void WiFiConfigCommand::waitForRsp(bool wait)
589 {
590     mWaitforRsp = wait;
591 }
592 
593 /* Callback handlers registered for nl message send */
error_handler_wifi_config(struct sockaddr_nl * nla,struct nlmsgerr * err,void * arg)594 static int error_handler_wifi_config(struct sockaddr_nl *nla,
595                                      struct nlmsgerr *err,
596                                      void *arg)
597 {
598     struct sockaddr_nl *tmp;
599     int *ret = (int *)arg;
600     tmp = nla;
601     *ret = err->error;
602     ALOGE("%s: Error code:%d (%s)", __FUNCTION__, *ret, strerror(-(*ret)));
603     return NL_STOP;
604 }
605 
606 /* Callback handlers registered for nl message send */
ack_handler_wifi_config(struct nl_msg * msg,void * arg)607 static int ack_handler_wifi_config(struct nl_msg *msg, void *arg)
608 {
609     int *ret = (int *)arg;
610     struct nl_msg * a;
611 
612     a = msg;
613     *ret = 0;
614     return NL_STOP;
615 }
616 
617 /* Callback handlers registered for nl message send */
finish_handler_wifi_config(struct nl_msg * msg,void * arg)618 static int finish_handler_wifi_config(struct nl_msg *msg, void *arg)
619 {
620   int *ret = (int *)arg;
621   struct nl_msg * a;
622 
623   a = msg;
624   *ret = 0;
625   return NL_SKIP;
626 }
627 
628 /*
629  * Override base class requestEvent and implement little differently here.
630  * This will send the request message.
631  * We don't wait for any response back in case of wificonfig,
632  * thus no wait for condition.
633  */
requestEvent()634 wifi_error WiFiConfigCommand::requestEvent()
635 {
636     int status;
637     wifi_error res = WIFI_SUCCESS;
638     struct nl_cb *cb;
639 
640     cb = nl_cb_alloc(NL_CB_DEFAULT);
641     if (!cb) {
642         ALOGE("%s: Callback allocation failed",__FUNCTION__);
643         res = WIFI_ERROR_OUT_OF_MEMORY;
644         goto out;
645     }
646 
647     status = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage());
648     if (status < 0) {
649         res = mapKernelErrortoWifiHalError(status);
650         goto out;
651     }
652     status = 1;
653 
654     nl_cb_err(cb, NL_CB_CUSTOM, error_handler_wifi_config, &status);
655     nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler_wifi_config,
656         &status);
657     nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler_wifi_config, &status);
658 
659     /* Err is populated as part of finish_handler. */
660     while (status > 0) {
661          nl_recvmsgs(mInfo->cmd_sock, cb);
662     }
663 
664     if (status < 0) {
665         res = mapKernelErrortoWifiHalError(status);
666         goto out;
667     }
668 
669     if (mWaitforRsp == true) {
670         struct timespec abstime;
671         abstime.tv_sec = 4;
672         abstime.tv_nsec = 0;
673         res = mCondition.wait(abstime);
674         if (res == WIFI_ERROR_TIMED_OUT)
675             ALOGE("%s: Time out happened.", __FUNCTION__);
676 
677         ALOGV("%s: Command invoked return value:%d, mWaitForRsp=%d",
678             __FUNCTION__, res, mWaitforRsp);
679     }
680 out:
681     /* Cleanup the mMsg */
682     mMsg.destroy();
683     return res;
684 }
685 
686