blob: 5c41369dad87c40b9cd68464de9b87a3c225dfe2 [file] [log] [blame]
Ahmad Kholaif159de4f2015-03-23 16:02:05 -07001/* 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>
Ajay Dudani65b8c552015-04-11 22:52:06 -070033#include <errno.h>
Amarnath Hullur Subramanyamb131c772015-08-06 14:22:50 -070034#include <stdlib.h>
Ahmad Kholaif159de4f2015-03-23 16:02:05 -070035#include "wificonfigcommand.h"
36
37/* Implementation of the API functions exposed in wifi_config.h */
38wifi_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 ALOGD("wifi_extended_dtim_config_set(): Enter");
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", __func__);
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
102cleanup:
103 ALOGI("%s: Delete object.", __func__);
104 delete wifiConfigCommand;
105 return (wifi_error)ret;
106}
107
108/* Set the country code to driver. */
109wifi_error wifi_set_country_code(wifi_interface_handle iface,
110 const char* country_code)
111{
112 int requestId, ret = 0;
113 WiFiConfigCommand *wifiConfigCommand;
114 struct nlattr *nlData;
115 interface_info *ifaceInfo = getIfaceInfo(iface);
116 wifi_handle wifiHandle = getWifiHandle(iface);
117 hal_info *info = getHalInfo(wifiHandle);
118
Srinivas Dasari02d14ee2015-08-19 16:52:08 +0530119 ALOGD("wifi_set_country_code(): %s", country_code);
Ahmad Kholaif159de4f2015-03-23 16:02:05 -0700120
121 /* No request id from caller, so generate one and pass it on to the driver.
122 * Generate it randomly.
123 */
Amarnath Hullur Subramanyamb131c772015-08-06 14:22:50 -0700124 requestId = get_requestid();
Ahmad Kholaif159de4f2015-03-23 16:02:05 -0700125
126 wifiConfigCommand = new WiFiConfigCommand(
127 wifiHandle,
128 requestId,
129 OUI_QCA,
130 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
131 if (wifiConfigCommand == NULL) {
132 ALOGE("%s: Error wifiConfigCommand NULL", __func__);
133 return WIFI_ERROR_UNKNOWN;
134 }
135
136 /* Create the NL message with NL80211_CMD_REQ_SET_REG NL cmd. */
137 ret = wifiConfigCommand->create_generic(NL80211_CMD_REQ_SET_REG);
138 if (ret < 0) {
139 ALOGE("wifi_set_country_code: failed to create NL msg. Error:%d", ret);
140 goto cleanup;
141 }
142
143 if (wifiConfigCommand->put_string(NL80211_ATTR_REG_ALPHA2, country_code)) {
144 ALOGE("wifi_set_country_code: put country code failed. Error:%d", ret);
145 goto cleanup;
146 }
147
148 /* Send the NL msg. */
149 wifiConfigCommand->waitForRsp(false);
150 ret = wifiConfigCommand->requestEvent();
151 if (ret != 0) {
152 ALOGE("wifi_set_country_code(): requestEvent Error:%d", ret);
153 goto cleanup;
154 }
Srinivas Dasari02d14ee2015-08-19 16:52:08 +0530155 usleep(WAIT_TIME_FOR_SET_REG_DOMAIN);
Ahmad Kholaif159de4f2015-03-23 16:02:05 -0700156
157cleanup:
Srinivas Dasari02d14ee2015-08-19 16:52:08 +0530158 ALOGV("%s: Delete object.", __func__);
Ahmad Kholaif159de4f2015-03-23 16:02:05 -0700159 delete wifiConfigCommand;
160 return (wifi_error)ret;
161}
162
163wifi_error wifi_set_beacon_wifi_iface_stats_averaging_factor(
164 wifi_request_id id,
165 wifi_interface_handle iface,
166 u16 factor)
167{
168 int ret = 0;
169 WiFiConfigCommand *wifiConfigCommand;
170 struct nlattr *nlData;
171 interface_info *ifaceInfo = getIfaceInfo(iface);
172 wifi_handle wifiHandle = getWifiHandle(iface);
173 hal_info *info = getHalInfo(wifiHandle);
174
175 ALOGD("wifi_set_beacon_wifi_iface_stats_averaging_factor(): Enter");
176 wifiConfigCommand = new WiFiConfigCommand(
177 wifiHandle,
178 id,
179 OUI_QCA,
180 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
181 if (wifiConfigCommand == NULL) {
182 ALOGE("%s: Error wifiConfigCommand NULL", __func__);
183 return WIFI_ERROR_UNKNOWN;
184 }
185
186 /* Create the NL message. */
187 ret = wifiConfigCommand->create();
188 if (ret < 0) {
189 ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor: failed to "
190 "create NL msg. Error:%d", ret);
191 goto cleanup;
192 }
193
194 /* Set the interface Id of the message. */
195 ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
196 if (ret < 0) {
197 ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor: failed to "
198 "set iface id. Error:%d", ret);
199 goto cleanup;
200 }
201
202 /* Add the vendor specific attributes for the NL command. */
203 nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
204 if (!nlData) {
205 ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor: failed "
206 "attr_start for VENDOR_DATA. Error:%d", ret);
207 goto cleanup;
208 }
209
210 if (wifiConfigCommand->put_u32(
211 QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_STATS_AVG_FACTOR, factor)) {
212 ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor(): failed to "
213 "put vendor data. Error:%d", ret);
214 goto cleanup;
215 }
216 wifiConfigCommand->attr_end(nlData);
217
218 /* Send the NL msg. */
219 wifiConfigCommand->waitForRsp(false);
220 ret = wifiConfigCommand->requestEvent();
221 if (ret != 0) {
222 ALOGE("wifi_set_beacon_wifi_iface_stats_averaging_factor(): "
223 "requestEvent Error:%d", ret);
224 goto cleanup;
225 }
226
227cleanup:
228 ALOGI("%s: Delete object.", __func__);
229 delete wifiConfigCommand;
230 return (wifi_error)ret;
231}
232
233wifi_error wifi_set_guard_time(wifi_request_id id,
234 wifi_interface_handle iface,
235 u32 guard_time)
236{
237 int ret = 0;
238 WiFiConfigCommand *wifiConfigCommand;
239 struct nlattr *nlData;
240 interface_info *ifaceInfo = getIfaceInfo(iface);
241 wifi_handle wifiHandle = getWifiHandle(iface);
242 hal_info *info = getHalInfo(wifiHandle);
243
244 ALOGD("wifi_set_guard_time(): Enter");
245
246 wifiConfigCommand = new WiFiConfigCommand(
247 wifiHandle,
248 id,
249 OUI_QCA,
250 QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION);
251 if (wifiConfigCommand == NULL) {
252 ALOGE("%s: Error wifiConfigCommand NULL", __func__);
253 return WIFI_ERROR_UNKNOWN;
254 }
255
256 /* Create the NL message. */
257 ret = wifiConfigCommand->create();
258 if (ret < 0) {
259 ALOGE("wifi_set_guard_time: failed to create NL msg. Error:%d", ret);
260 goto cleanup;
261 }
262
263 /* Set the interface Id of the message. */
264 ret = wifiConfigCommand->set_iface_id(ifaceInfo->name);
265 if (ret < 0) {
266 ALOGE("wifi_set_guard_time: failed to set iface id. Error:%d", ret);
267 goto cleanup;
268 }
269
270 /* Add the vendor specific attributes for the NL command. */
271 nlData = wifiConfigCommand->attr_start(NL80211_ATTR_VENDOR_DATA);
272 if (!nlData) {
273 ALOGE("wifi_set_guard_time: failed attr_start for VENDOR_DATA. "
274 "Error:%d", ret);
275 goto cleanup;
276 }
277
278 if (wifiConfigCommand->put_u32(
279 QCA_WLAN_VENDOR_ATTR_WIFI_CONFIG_GUARD_TIME, guard_time)) {
280 ALOGE("wifi_set_guard_time: failed to add vendor data.");
281 goto cleanup;
282 }
283 wifiConfigCommand->attr_end(nlData);
284
285 /* Send the NL msg. */
286 wifiConfigCommand->waitForRsp(false);
287 ret = wifiConfigCommand->requestEvent();
288 if (ret != 0) {
289 ALOGE("wifi_set_guard_time(): requestEvent Error:%d", ret);
290 goto cleanup;
291 }
292
293cleanup:
294 ALOGI("%s: Delete object.", __func__);
295 delete wifiConfigCommand;
296 return (wifi_error)ret;
297}
298
299WiFiConfigCommand::WiFiConfigCommand(wifi_handle handle,
300 int id, u32 vendor_id,
301 u32 subcmd)
302 : WifiVendorCommand(handle, id, vendor_id, subcmd)
303{
Ahmad Kholaif159de4f2015-03-23 16:02:05 -0700304 /* Initialize the member data variables here */
305 mWaitforRsp = false;
306 mRequestId = id;
307}
308
309WiFiConfigCommand::~WiFiConfigCommand()
310{
Ahmad Kholaif159de4f2015-03-23 16:02:05 -0700311 unregisterVendorHandler(mVendor_id, mSubcmd);
312}
313
314/* This function implements creation of Vendor command */
315int WiFiConfigCommand::create() {
316 int ret = mMsg.create(NL80211_CMD_VENDOR, 0, 0);
317 if (ret < 0) {
318 return ret;
319 }
320
321 /* Insert the oui in the msg */
322 ret = mMsg.put_u32(NL80211_ATTR_VENDOR_ID, mVendor_id);
323 if (ret < 0)
324 goto out;
325 /* Insert the subcmd in the msg */
326 ret = mMsg.put_u32(NL80211_ATTR_VENDOR_SUBCMD, mSubcmd);
327 if (ret < 0)
328 goto out;
329
330 ALOGI("%s: mVendor_id = %d, Subcmd = %d.",
331 __func__, mVendor_id, mSubcmd);
332out:
333 return ret;
334}
335
336/* This function implements creation of generic NL command */
337int WiFiConfigCommand::create_generic(u8 cmdId) {
338 ALOGI("%s: cmdId = %d", __func__, cmdId);
339 int ret = mMsg.create(cmdId, 0, 0);
340 return ret;
341}
342
343void WiFiConfigCommand::waitForRsp(bool wait)
344{
345 mWaitforRsp = wait;
346}
347
348/* Callback handlers registered for nl message send */
349static int error_handler_wifi_config(struct sockaddr_nl *nla,
350 struct nlmsgerr *err,
351 void *arg)
352{
353 struct sockaddr_nl *tmp;
354 int *ret = (int *)arg;
355 tmp = nla;
356 *ret = err->error;
357 ALOGE("%s: Error code:%d (%s)", __func__, *ret, strerror(-(*ret)));
358 return NL_STOP;
359}
360
361/* Callback handlers registered for nl message send */
362static int ack_handler_wifi_config(struct nl_msg *msg, void *arg)
363{
364 int *ret = (int *)arg;
365 struct nl_msg * a;
366
Ahmad Kholaif159de4f2015-03-23 16:02:05 -0700367 a = msg;
368 *ret = 0;
369 return NL_STOP;
370}
371
372/* Callback handlers registered for nl message send */
373static int finish_handler_wifi_config(struct nl_msg *msg, void *arg)
374{
375 int *ret = (int *)arg;
376 struct nl_msg * a;
377
Ahmad Kholaif159de4f2015-03-23 16:02:05 -0700378 a = msg;
379 *ret = 0;
380 return NL_SKIP;
381}
382
383/*
384 * Override base class requestEvent and implement little differently here.
385 * This will send the request message.
386 * We don't wait for any response back in case of wificonfig,
387 * thus no wait for condition.
388 */
389int WiFiConfigCommand::requestEvent()
390{
391 int res = -1;
392 struct nl_cb *cb;
393
Ahmad Kholaif159de4f2015-03-23 16:02:05 -0700394 cb = nl_cb_alloc(NL_CB_DEFAULT);
395 if (!cb) {
396 ALOGE("%s: Callback allocation failed",__func__);
397 res = -1;
398 goto out;
399 }
400
Ahmad Kholaif159de4f2015-03-23 16:02:05 -0700401 res = nl_send_auto_complete(mInfo->cmd_sock, mMsg.getMessage());
402 if (res < 0)
403 goto out;
404 res = 1;
405
406 nl_cb_err(cb, NL_CB_CUSTOM, error_handler_wifi_config, &res);
407 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler_wifi_config,
408 &res);
409 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler_wifi_config, &res);
410
411 /* Err is populated as part of finish_handler. */
412 while (res > 0){
413 nl_recvmsgs(mInfo->cmd_sock, cb);
414 }
415
Ahmad Kholaif159de4f2015-03-23 16:02:05 -0700416 /* Only wait for the asynchronous event if HDD returns success, res=0 */
417 if (!res && (mWaitforRsp == true)) {
418 struct timespec abstime;
419 abstime.tv_sec = 4;
420 abstime.tv_nsec = 0;
421 res = mCondition.wait(abstime);
422 if (res == ETIMEDOUT)
423 {
424 ALOGE("%s: Time out happened.", __func__);
425 }
426 ALOGD("%s: Command invoked return value:%d, mWaitForRsp=%d",
427 __func__, res, mWaitforRsp);
428 }
429out:
430 /* Cleanup the mMsg */
431 mMsg.destroy();
432 return res;
433}
434