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