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