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