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 "wificonfigcommand.h"
36 
37 /* 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)38 wifi_error wifi_extended_dtim_config_set(wifi_request_id id,
39                                          wifi_interface_handle iface,
40                                          int extended_dtim)
41 {
42     int ret = 0;
43     WiFiConfigCommand *wifiConfigCommand;
44     struct nlattr *nlData;
45     interface_info *ifaceInfo = getIfaceInfo(iface);
46     wifi_handle wifiHandle = getWifiHandle(iface);
47 
48     ALOGV("%s: extended_dtim:%d", __FUNCTION__, extended_dtim);
49 
50     wifiConfigCommand = new WiFiConfigCommand(
51                             wifiHandle,
52                             id,
53                             OUI_QCA,
54                             QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
55 
56     if (wifiConfigCommand == NULL) {
57         ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
58         return WIFI_ERROR_UNKNOWN;
59     }
60 
61     /* Create the NL message. */
62     ret = wifiConfigCommand->create();
63     if (ret < 0) {
64         ALOGE("wifi_extended_dtim_config_set: failed to create NL msg. "
65             "Error:%d", ret);
66         goto cleanup;
67     }
68 
69     /* Set the interface Id of the message. */
70     ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
71     if (ret < 0) {
72         ALOGE("wifi_extended_dtim_config_set: failed to set iface id. "
73             "Error:%d", ret);
74         goto cleanup;
75     }
76 
77     /* Add the vendor specific attributes for the NL command. */
78     nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
79     if (!nlData) {
80         ALOGE("wifi_extended_dtim_config_set: failed attr_start for "
81             "VENDOR_DATA. Error:%d", ret);
82         goto cleanup;
83     }
84 
85     if (wifiConfigCommand->put_u32(
86         QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_DYNAMIC_DTIM, extended_dtim)) {
87         ALOGE("wifi_extended_dtim_config_set(): failed to put vendor data. "
88             "Error:%d", ret);
89         goto cleanup;
90     }
91     wifiConfigCommand->attr_end(nlData);
92 
93     /* Send the NL msg. */
94     wifiConfigCommand->waitForRsp(false);
95     ret = wifiConfigCommand->requestEvent();
96     if (ret != 0) {
97         ALOGE("wifi_extended_dtim_config_set(): requestEvent Error:%d", ret);
98         goto cleanup;
99     }
100 
101 cleanup:
102     delete wifiConfigCommand;
103     return (wifi_error)ret;
104 }
105 
106 /* Set the country code to driver. */
wifi_set_country_code(wifi_interface_handle iface,const char * country_code)107 wifi_error wifi_set_country_code(wifi_interface_handle iface,
108                                  const char* country_code)
109 {
110     int requestId, ret = 0;
111     WiFiConfigCommand *wifiConfigCommand;
112     wifi_handle wifiHandle = getWifiHandle(iface);
113 
114     ALOGV("%s: %s", __FUNCTION__, country_code);
115 
116     /* No request id from caller, so generate one and pass it on to the driver.
117      * Generate it randomly.
118      */
119     requestId = get_requestid();
120 
121     wifiConfigCommand = new WiFiConfigCommand(
122                             wifiHandle,
123                             requestId,
124                             OUI_QCA,
125                             QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
126     if (wifiConfigCommand == NULL) {
127         ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
128         return WIFI_ERROR_UNKNOWN;
129     }
130 
131     /* Create the NL message with NL80211_CMD_REQ_SET_REG NL cmd. */
132     ret = wifiConfigCommand->create_generic(NL80211_CMD_REQ_SET_REG);
133     if (ret < 0) {
134         ALOGE("wifi_set_country_code: failed to create NL msg. Error:%d", ret);
135         goto cleanup;
136     }
137 
138     if (wifiConfigCommand->put_string(NL80211_ATTR_REG_ALPHA2, country_code)) {
139         ALOGE("wifi_set_country_code: put country code failed. Error:%d", ret);
140         goto cleanup;
141     }
142 
143     /* Send the NL msg. */
144     wifiConfigCommand->waitForRsp(false);
145     ret = wifiConfigCommand->requestEvent();
146     if (ret != 0) {
147         ALOGE("wifi_set_country_code(): requestEvent Error:%d", ret);
148         goto cleanup;
149     }
150     usleep(WAIT_TIME_FOR_SET_REG_DOMAIN);
151 
152 cleanup:
153     delete wifiConfigCommand;
154     return (wifi_error)ret;
155 }
156 
wifi_set_beacon_wifi_iface_stats_averaging_factor(wifi_request_id id,wifi_interface_handle iface,u16 factor)157 wifi_error wifi_set_beacon_wifi_iface_stats_averaging_factor(
158                                                 wifi_request_id id,
159                                                 wifi_interface_handle iface,
160                                                 u16 factor)
161 {
162     int ret = 0;
163     WiFiConfigCommand *wifiConfigCommand;
164     struct nlattr *nlData;
165     interface_info *ifaceInfo = getIfaceInfo(iface);
166     wifi_handle wifiHandle = getWifiHandle(iface);
167 
168     ALOGV("%s factor:%u", __FUNCTION__, factor);
169     wifiConfigCommand = new WiFiConfigCommand(
170                             wifiHandle,
171                             id,
172                             OUI_QCA,
173                             QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
174     if (wifiConfigCommand == NULL) {
175         ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
176         return WIFI_ERROR_UNKNOWN;
177     }
178 
179     /* Create the NL message. */
180     ret = wifiConfigCommand->create();
181     if (ret < 0) {
182         ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor: failed to "
183             "create NL msg. Error:%d", ret);
184         goto cleanup;
185     }
186 
187     /* Set the interface Id of the message. */
188     ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
189     if (ret < 0) {
190         ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor: failed to "
191             "set iface id. Error:%d", ret);
192         goto cleanup;
193     }
194 
195     /* Add the vendor specific attributes for the NL command. */
196     nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
197     if (!nlData) {
198         ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor: failed "
199             "attr_start for VENDOR_DATA. Error:%d", ret);
200         goto cleanup;
201     }
202 
203     if (wifiConfigCommand->put_u32(
204         QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_STATS_AVG_FACTOR, factor)) {
205         ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor(): failed to "
206             "put vendor data. Error:%d", ret);
207         goto cleanup;
208     }
209     wifiConfigCommand->attr_end(nlData);
210 
211     /* Send the NL msg. */
212     wifiConfigCommand->waitForRsp(false);
213     ret = wifiConfigCommand->requestEvent();
214     if (ret != 0) {
215         ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor(): "
216             "requestEvent Error:%d", ret);
217         goto cleanup;
218     }
219 
220 cleanup:
221     delete wifiConfigCommand;
222     return (wifi_error)ret;
223 }
224 
wifi_set_guard_time(wifi_request_id id,wifi_interface_handle iface,u32 guard_time)225 wifi_error wifi_set_guard_time(wifi_request_id id,
226                                wifi_interface_handle iface,
227                                u32 guard_time)
228 {
229     int ret = 0;
230     WiFiConfigCommand *wifiConfigCommand;
231     struct nlattr *nlData;
232     interface_info *ifaceInfo = getIfaceInfo(iface);
233     wifi_handle wifiHandle = getWifiHandle(iface);
234 
235     ALOGV("%s : guard_time:%u", __FUNCTION__, guard_time);
236 
237     wifiConfigCommand = new WiFiConfigCommand(
238                             wifiHandle,
239                             id,
240                             OUI_QCA,
241                             QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
242     if (wifiConfigCommand == NULL) {
243         ALOGE("%s: Error wifiConfigCommand NULL", __FUNCTION__);
244         return WIFI_ERROR_UNKNOWN;
245     }
246 
247     /* Create the NL message. */
248     ret = wifiConfigCommand->create();
249     if (ret < 0) {
250         ALOGE("wifi_set_guard_time: failed to create NL msg. Error:%d", ret);
251         goto cleanup;
252     }
253 
254     /* Set the interface Id of the message. */
255     ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
256     if (ret < 0) {
257         ALOGE("wifi_set_guard_time: failed to set iface id. Error:%d", ret);
258         goto cleanup;
259     }
260 
261     /* Add the vendor specific attributes for the NL command. */
262     nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
263     if (!nlData) {
264         ALOGE("wifi_set_guard_time: failed attr_start for VENDOR_DATA. "
265             "Error:%d", ret);
266         goto cleanup;
267     }
268 
269     if (wifiConfigCommand->put_u32(
270         QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_GUARD_TIME, guard_time)) {
271         ALOGE("wifi_set_guard_time: failed to add vendor data.");
272         goto cleanup;
273     }
274     wifiConfigCommand->attr_end(nlData);
275 
276     /* Send the NL msg. */
277     wifiConfigCommand->waitForRsp(false);
278     ret = wifiConfigCommand->requestEvent();
279     if (ret != 0) {
280         ALOGE("wifi_set_guard_time(): requestEvent Error:%d", ret);
281         goto cleanup;
282     }
283 
284 cleanup:
285     delete wifiConfigCommand;
286     return (wifi_error)ret;
287 }
288 
WiFiConfigCommand(wifi_handle handle,int id,u32 vendor_id,u32 subcmd)289 WiFiConfigCommand::WiFiConfigCommand(wifi_handle handle,
290                                      int id, u32 vendor_id,
291                                      u32 subcmd)
292         : WifiVendorCommand(handle, id, vendor_id, subcmd)
293 {
294     /* Initialize the member data variables here */
295     mWaitforRsp = false;
296     mRequestId = id;
297 }
298 
~WiFiConfigCommand()299 WiFiConfigCommand::~WiFiConfigCommand()
300 {
301     unregisterVendorHandler(mVendor_id, mSubcmd);
302 }
303 
304 /* This function implements creation of Vendor command */
create()305 int WiFiConfigCommand::create() {
306     int ret = mMsg.create(NL80211_CMD_VENDOR, 0, 0);
307     if (ret < 0) {
308         return ret;
309     }
310 
311     /* Insert the oui in the msg */
312     ret = mMsg.put_u32(NL80211_ATTR_VENDOR_ID, mVendor_id);
313     if (ret < 0)
314         goto out;
315     /* Insert the subcmd in the msg */
316     ret = mMsg.put_u32(NL80211_ATTR_VENDOR_SUBCMD, mSubcmd);
317     if (ret < 0)
318         goto out;
319 out:
320     return ret;
321 }
322 
323 /* This function implements creation of generic NL command */
create_generic(u8 cmdId)324 int WiFiConfigCommand::create_generic(u8 cmdId) {
325     int ret = mMsg.create(cmdId, 0, 0);
326     return ret;
327 }
328 
waitForRsp(bool wait)329 void WiFiConfigCommand::waitForRsp(bool wait)
330 {
331     mWaitforRsp = wait;
332 }
333 
334 /* Callback handlers registered for nl message send */
error_handler_wifi_config(struct sockaddr_nl * nla,struct nlmsgerr * err,void * arg)335 static int error_handler_wifi_config(struct sockaddr_nl *nla,
336                                      struct nlmsgerr *err,
337                                      void *arg)
338 {
339     struct sockaddr_nl *tmp;
340     int *ret = (int *)arg;
341     tmp = nla;
342     *ret = err->error;
343     ALOGE("%s: Error code:%d (%s)", __FUNCTION__, *ret, strerror(-(*ret)));
344     return NL_STOP;
345 }
346 
347 /* Callback handlers registered for nl message send */
ack_handler_wifi_config(struct nl_msg * msg,void * arg)348 static int ack_handler_wifi_config(struct nl_msg *msg, void *arg)
349 {
350     int *ret = (int *)arg;
351     struct nl_msg * a;
352 
353     a = msg;
354     *ret = 0;
355     return NL_STOP;
356 }
357 
358 /* Callback handlers registered for nl message send */
finish_handler_wifi_config(struct nl_msg * msg,void * arg)359 static int finish_handler_wifi_config(struct nl_msg *msg, void *arg)
360 {
361   int *ret = (int *)arg;
362   struct nl_msg * a;
363 
364   a = msg;
365   *ret = 0;
366   return NL_SKIP;
367 }
368 
369 /*
370  * Override base class requestEvent and implement little differently here.
371  * This will send the request message.
372  * We don't wait for any response back in case of wificonfig,
373  * thus no wait for condition.
374  */
requestEvent()375 int WiFiConfigCommand::requestEvent()
376 {
377     int res = -1;
378     struct nl_cb *cb;
379 
380     cb = nl_cb_alloc(NL_CB_DEFAULT);
381     if (!cb) {
382         ALOGE("%s: Callback allocation failed",__FUNCTION__);
383         res = -1;
384         goto out;
385     }
386 
387     res = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage());
388     if (res < 0)
389         goto out;
390     res = 1;
391 
392     nl_cb_err(cb, NL_CB_CUSTOM, error_handler_wifi_config, &res);
393     nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler_wifi_config,
394         &res);
395     nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler_wifi_config, &res);
396 
397     /* Err is populated as part of finish_handler. */
398     while (res > 0){
399          nl_recvmsgs(mInfo->cmd_sock, cb);
400     }
401 
402     /* Only wait for the asynchronous event if HDD returns success, res=0 */
403     if (!res && (mWaitforRsp == true)) {
404         struct timespec abstime;
405         abstime.tv_sec = 4;
406         abstime.tv_nsec = 0;
407         res = mCondition.wait(abstime);
408         if (res == ETIMEDOUT)
409         {
410             ALOGE("%s: Time out happened.", __FUNCTION__);
411         }
412         ALOGV("%s: Command invoked return value:%d, mWaitForRsp=%d",
413             __FUNCTION__, res, mWaitforRsp);
414     }
415 out:
416     /* Cleanup the mMsg */
417     mMsg.destroy();
418     return res;
419 }
420 
421