[APR-1563] wlbt: HAL changes for wifi low latency mode
[GitHub/MotorolaMobilityLLC/hardware-samsung_slsi-scsc_wifibt-wifi_hal.git] / wifi_hal.cpp
CommitLineData
7753f181
DD
1#include <errno.h>
2#include <stdint.h>
c0b490a2 3#include <string.h>
7753f181
DD
4#include <fcntl.h>
5#include <sys/socket.h>
6#include <netlink/genl/genl.h>
7#include <netlink/genl/family.h>
8#include <netlink/genl/ctrl.h>
9#include <linux/rtnetlink.h>
10#include <netpacket/packet.h>
11#include <linux/filter.h>
12#include <linux/errqueue.h>
13
14#include <linux/pkt_sched.h>
15#include <netlink/object-api.h>
16#include <netlink/netlink.h>
17#include <netlink/socket.h>
18#include <netlink/attr.h>
19#include <netlink/handlers.h>
20#include <netlink/msg.h>
21
22#include <dirent.h>
23#include <net/if.h>
24
25#include "sync.h"
26
27#define LOG_TAG "WifiHAL"
28
29#include <utils/Log.h>
7753f181
DD
30#include "wifi_hal.h"
31#include "common.h"
32#include "cpp_bindings.h"
02b2b8ab 33#include "roam.h"
7753f181
DD
34
35
36#define WIFI_HAL_CMD_SOCK_PORT 644
37#define WIFI_HAL_EVENT_SOCK_PORT 645
38
39#define FEATURE_SET 0
40#define FEATURE_SET_MATRIX 1
41#define ATTR_NODFS_VALUE 3
1fdbd4c1 42#define ATTR_COUNTRY_CODE 4
f8204f99 43#define ATTR_LOW_LATENCY_MODE 5
7753f181 44
7753f181
DD
45static int internal_no_seq_check(nl_msg *msg, void *arg);
46static int internal_valid_message_handler(nl_msg *msg, void *arg);
47static int wifi_get_multicast_id(wifi_handle handle, const char *name, const char *group);
48static int wifi_add_membership(wifi_handle handle, const char *group);
49static wifi_error wifi_init_interfaces(wifi_handle handle);
50
51typedef enum wifi_attr {
de14a5c9 52 ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_CONFIG,
7753f181
DD
53 ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI
54} wifi_attr_t;
55
f425b4a8
PG
56enum wifi_rssi_monitor_attr {
57 RSSI_MONITOR_ATTRIBUTE_MAX_RSSI,
58 RSSI_MONITOR_ATTRIBUTE_MIN_RSSI,
59 RSSI_MONITOR_ATTRIBUTE_START,
60};
61
5822f843
SP
62enum wifi_apf_attr {
63 APF_ATTRIBUTE_VERSION,
64 APF_ATTRIBUTE_MAX_LEN,
65 APF_ATTRIBUTE_PROGRAM,
66 APF_ATTRIBUTE_PROGRAM_LEN
67};
68
69enum apf_request_type {
70 GET_APF_CAPABILITIES,
71 SET_APF_PROGRAM,
72 READ_APF_PROGRAM
73};
74
f425b4a8
PG
75static wifi_error wifi_start_rssi_monitoring(wifi_request_id id, wifi_interface_handle
76 iface, s8 max_rssi, s8 min_rssi, wifi_rssi_event_handler eh);
77static wifi_error wifi_stop_rssi_monitoring(wifi_request_id id, wifi_interface_handle iface);
b562d5aa 78wifi_error wifi_get_wake_reason_stats(wifi_interface_handle iface, WLAN_DRIVER_WAKE_REASON_CNT *wifi_wake_reason_cnt);
f425b4a8 79
7753f181
DD
80/* Initialize/Cleanup */
81
82void wifi_socket_set_local_port(struct nl_sock *sock, uint32_t port)
83{
84 uint32_t pid = getpid() & 0x3FFFFF;
85 nl_socket_set_local_port(sock, pid + (port << 22));
86}
87
5822f843
SP
88class AndroidPktFilterCommand : public WifiCommand {
89 private:
90 const u8* mProgram;
91 u32 mProgramLen;
92 u32* mVersion;
93 u32* mMaxLen;
94 u32 mSourceOffset;
95 u8 *mHostDestination;
96 u32 mLength;
97 int mReqType;
98 public:
99 AndroidPktFilterCommand(wifi_interface_handle handle,
100 u32* version, u32* max_len)
101 : WifiCommand(handle, 0),
102 mVersion(version), mMaxLen(max_len),
103 mReqType(GET_APF_CAPABILITIES)
104 {
105 }
106
107 AndroidPktFilterCommand(wifi_interface_handle handle,
108 const u8* program, u32 len)
109 : WifiCommand(handle, 0),
110 mProgram(program), mProgramLen(len),
111 mReqType(SET_APF_PROGRAM)
112 {
113 }
114
115 AndroidPktFilterCommand(wifi_interface_handle handle,
116 u32 src_offset, u8 *host_dst, u32 length)
117 : WifiCommand(handle, 0),
118 mSourceOffset(src_offset), mHostDestination(host_dst), mLength(length),
119 mReqType(READ_APF_PROGRAM)
120 {
121 }
122
123 int createRequest(WifiRequest& request) {
124 if (mReqType == SET_APF_PROGRAM) {
125 ALOGI("\n%s: APF set program request\n", __FUNCTION__);
126 return createSetPktFilterRequest(request);
127 } else if (mReqType == GET_APF_CAPABILITIES) {
128 ALOGI("\n%s: APF get capabilities request\n", __FUNCTION__);
129 return createGetPktFilterCapabilitesRequest(request);
130 } else if (mReqType == READ_APF_PROGRAM) {
131 ALOGI("\n%s: APF read program request\n", __FUNCTION__);
132 return createReadPktFilterRequest(request);
133 } else {
134 ALOGE("\n%s Unknown APF request\n", __FUNCTION__);
135 return WIFI_ERROR_NOT_SUPPORTED;
136 }
137 return WIFI_SUCCESS;
138 }
139
140 int createSetPktFilterRequest(WifiRequest& request) {
141 u8 *program = new u8[mProgramLen];
142 NULL_CHECK_RETURN(program, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
143 int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_APF_SET_FILTER);
144 if (result < 0) {
145 return result;
146 }
147
148 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
149 result = request.put_u32(APF_ATTRIBUTE_PROGRAM_LEN, mProgramLen);
150 if (result < 0) {
151 return result;
152 }
153 memcpy(program, mProgram, mProgramLen);
154 result = request.put(APF_ATTRIBUTE_PROGRAM, program, mProgramLen);
155 if (result < 0) {
156 return result;
157 }
158 request.attr_end(data);
159 delete[] program;
160 return result;
161 }
162
163 int createGetPktFilterCapabilitesRequest(WifiRequest& request) {
164 return request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_APF_GET_CAPABILITIES);
165 }
166
167 int createReadPktFilterRequest(WifiRequest& request) {
168 return request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_APF_READ_FILTER);
169 }
170
171 int start() {
172 WifiRequest request(familyId(), ifaceId());
173 int result = createRequest(request);
174 if (result < 0) {
175 return result;
176 }
177 result = requestResponse(request);
178 if (result < 0) {
179 ALOGI("Request Response failed for APF, result = %d", result);
180 return result;
181 }
182 ALOGI("Done!");
183 return result;
184 }
185
186 int cancel() {
187 return WIFI_SUCCESS;
188 }
189
190 int handleResponse(WifiEvent& reply) {
191 ALOGD("In SetAPFCommand::handleResponse");
192
193 if (reply.get_cmd() != NL80211_CMD_VENDOR) {
194 ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
195 return NL_SKIP;
196 }
197
198 int id = reply.get_vendor_id();
199 int subcmd = reply.get_vendor_subcmd();
200
201 nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
202 int len = reply.get_vendor_data_len();
203
204 ALOGD("Id = %0x, subcmd = %d, len = %d", id, subcmd, len);
205 if (vendor_data == NULL || len == 0) {
206 ALOGE("no vendor data in SetAPFCommand response; ignoring it");
207 return NL_SKIP;
208 }
209 if (mReqType == GET_APF_CAPABILITIES) {
210 *mVersion = 0;
211 *mMaxLen = 0;
212 ALOGD("Response recieved for get packet filter capabilities command\n");
213 for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
214 if (it.get_type() == APF_ATTRIBUTE_VERSION) {
215 *mVersion = it.get_u32();
216 ALOGI("APF version is %d\n", *mVersion);
217 } else if (it.get_type() == APF_ATTRIBUTE_MAX_LEN) {
218 *mMaxLen = it.get_u32();
219 ALOGI("APF max len is %d\n", *mMaxLen);
220 } else {
221 ALOGE("Ignoring invalid attribute type = %d, size = %d",
222 it.get_type(), it.get_len());
223 }
224 }
225 } else if (mReqType == READ_APF_PROGRAM) {
226 ALOGD("Response recieved for read apf packet filter command\n");
227 u32 len = reply.get_vendor_data_len();
228 void *data = reply.get_vendor_data();
229
230 memcpy(mHostDestination, (u8 *)data + mSourceOffset, min(len, mLength));
231 }
232 return NL_OK;
233 }
234
235 int handleEvent(WifiEvent& event) {
236 /* No Event to recieve for APF commands */
237 return NL_SKIP;
238 }
239};
240
d76317a7
TK
241class SetNdoffloadCommand : public WifiCommand {
242
243private:
244 u8 mEnable;
245public:
246 SetNdoffloadCommand(wifi_interface_handle handle, u8 enable)
247 : WifiCommand(handle, 0) {
248 mEnable = enable;
249 }
250 virtual int create() {
251 int ret;
252
253 ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_CONFIGURE_ND_OFFLOAD);
254 if (ret < 0) {
255 ALOGE("Can't create message to send to driver - %d", ret);
256 return WIFI_ERROR_NOT_AVAILABLE;
257 }
258
259 nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
260 ret = mMsg.put_u8(ANDR_WIFI_ATTRIBUTE_ND_OFFLOAD_CONFIG, mEnable);
261 if (ret < 0) {
262 return ret;
263 }
264 ALOGD("Driver message has been created successfully--> %d", mEnable);
265 mMsg.attr_end(data);
266 return WIFI_SUCCESS;
267 }
268};
269
7753f181
DD
270static nl_sock * wifi_create_nl_socket(int port)
271{
7753f181
DD
272 struct nl_sock *sock = nl_socket_alloc();
273 if (sock == NULL) {
274 ALOGE("Could not create handle");
275 return NULL;
276 }
277
278 wifi_socket_set_local_port(sock, port);
279
7753f181
DD
280 if (nl_connect(sock, NETLINK_GENERIC)) {
281 ALOGE("Could not connect handle");
282 nl_socket_free(sock);
283 return NULL;
284 }
285
7753f181
DD
286 return sock;
287}
288
d76317a7
TK
289
290wifi_error wifi_configure_nd_offload(wifi_interface_handle handle, u8 enable)
291{
292 SetNdoffloadCommand command(handle, enable);
293 int ret = command.requestResponse();
294 if (ret != WIFI_SUCCESS) {
295 if (ret == -EPERM) { /*This is just to pass VTS test */
296 ALOGD("return value from driver--> %d",ret);
297 return WIFI_SUCCESS;
298 }
299 }
300 return (wifi_error)ret;
301}
302
303wifi_error wifi_get_packet_filter_capabilities(wifi_interface_handle handle,
5822f843 304 u32 *version, u32 *max_len)
d76317a7 305{
5822f843
SP
306 ALOGD("Getting APF capabilities, halHandle = %p\n", handle);
307 AndroidPktFilterCommand *cmd = new AndroidPktFilterCommand(handle, version, max_len);
308 NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
309 wifi_error result = (wifi_error)cmd->start();
310 if (result == WIFI_SUCCESS) {
311 ALOGD("Getting APF capability, version = %d, max_len = %d\n", *version, *max_len);
312 } else {
313 /* Return success to pass VTS test */
314 *version = 0;
315 *max_len = 0;
316 ALOGD("Packet Filter not supported");
317 result = WIFI_SUCCESS;
318 }
319 cmd->releaseRef();
320 return result;
321}
d76317a7 322
5822f843
SP
323wifi_error wifi_set_packet_filter(wifi_interface_handle handle,
324 const u8 *program, u32 len)
325{
326 ALOGD("Setting APF program, halHandle = %p\n", handle);
327 AndroidPktFilterCommand *cmd = new AndroidPktFilterCommand(handle, program, len);
328 NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
329 wifi_error result = (wifi_error)cmd->start();
330 cmd->releaseRef();
331 return result;
332}
d76317a7 333
5822f843
SP
334wifi_error wifi_read_packet_filter(wifi_interface_handle handle,
335 u32 src_offset, u8 *host_dst, u32 length)
336{
337 ALOGD("Reading APF filter, halHandle = %p\n", handle);
338 AndroidPktFilterCommand *cmd = new AndroidPktFilterCommand(handle, src_offset, host_dst, length);
339 NULL_CHECK_RETURN(cmd, "memory allocation failure", WIFI_ERROR_OUT_OF_MEMORY);
340 wifi_error result = (wifi_error)cmd->start();
341 cmd->releaseRef();
342 return result;
d76317a7
TK
343}
344
d59e4b54 345/* Initialize HAL function pointer table */
7753f181
DD
346wifi_error init_wifi_vendor_hal_func_table(wifi_hal_fn *fn)
347{
348 if (fn == NULL) {
349 return WIFI_ERROR_UNKNOWN;
350 }
351 fn->wifi_initialize = wifi_initialize;
352 fn->wifi_cleanup = wifi_cleanup;
353 fn->wifi_event_loop = wifi_event_loop;
354 fn->wifi_get_supported_feature_set = wifi_get_supported_feature_set;
355 fn->wifi_get_concurrency_matrix = wifi_get_concurrency_matrix;
356 fn->wifi_set_scanning_mac_oui = wifi_set_scanning_mac_oui;
357 fn->wifi_get_ifaces = wifi_get_ifaces;
358 fn->wifi_get_iface_name = wifi_get_iface_name;
359 fn->wifi_start_gscan = wifi_start_gscan;
360 fn->wifi_stop_gscan = wifi_stop_gscan;
361 fn->wifi_get_cached_gscan_results = wifi_get_cached_gscan_results;
7753f181 362 fn->wifi_get_gscan_capabilities = wifi_get_gscan_capabilities;
7753f181
DD
363 fn->wifi_get_valid_channels = wifi_get_valid_channels;
364 fn->wifi_rtt_range_request = wifi_rtt_range_request;
365 fn->wifi_rtt_range_cancel = wifi_rtt_range_cancel;
366 fn->wifi_get_rtt_capabilities = wifi_get_rtt_capabilities;
367 fn->wifi_set_nodfs_flag = wifi_set_nodfs_flag;
f0567d5c 368 fn->wifi_start_sending_offloaded_packet = wifi_start_sending_offloaded_packet;
3c0c6ab1 369 fn->wifi_stop_sending_offloaded_packet = wifi_stop_sending_offloaded_packet;
6ff2d683 370 fn->wifi_set_epno_list = wifi_set_epno_list;
c15187c1 371 fn->wifi_reset_epno_list = wifi_reset_epno_list;
6ff2d683
JPS
372 fn->wifi_set_passpoint_list = wifi_set_passpoint_list;
373 fn->wifi_reset_passpoint_list = wifi_reset_passpoint_list;
f425b4a8
PG
374 fn->wifi_start_rssi_monitoring = wifi_start_rssi_monitoring;
375 fn->wifi_stop_rssi_monitoring = wifi_stop_rssi_monitoring;
d583845d 376 fn->wifi_set_link_stats = wifi_set_link_stats;
058cae5f 377 fn->wifi_get_link_stats = wifi_get_link_stats;
d583845d 378 fn->wifi_clear_link_stats = wifi_clear_link_stats;
1fdbd4c1 379 fn->wifi_set_country_code = wifi_set_country_code;
02b2b8ab 380 fn->wifi_configure_roaming = wifi_configure_roaming;
de14a5c9 381 fn->wifi_configure_nd_offload = wifi_configure_nd_offload;
cdc775c7
HG
382 fn->wifi_start_pkt_fate_monitoring = wifi_start_pkt_fate_monitoring;
383 fn->wifi_get_tx_pkt_fates = wifi_get_tx_pkt_fates;
384 fn->wifi_get_rx_pkt_fates = wifi_get_rx_pkt_fates;
385 fn->wifi_start_logging = wifi_start_logging;
386 fn->wifi_set_log_handler = wifi_set_log_handler;
387 fn->wifi_set_alert_handler= wifi_set_alert_handler;
388 fn->wifi_get_ring_buffers_status = wifi_get_ring_buffers_status;
389 fn->wifi_get_logger_supported_feature_set = wifi_get_logger_supported_feature_set;
390 fn->wifi_get_ring_data = wifi_get_ring_data;
391 fn->wifi_get_driver_version = wifi_get_driver_version;
392 fn->wifi_get_firmware_version = wifi_get_firmware_version;
393 fn->wifi_get_firmware_memory_dump = wifi_get_firmware_memory_dump;
394 fn->wifi_get_driver_memory_dump = wifi_get_driver_memory_dump;
395 fn->wifi_get_wake_reason_stats = wifi_get_wake_reason_stats;
d3a587e8
JPS
396 fn->wifi_nan_enable_request = nan_enable_request;
397 fn->wifi_nan_disable_request = nan_disable_request;
398 fn->wifi_nan_publish_request = nan_publish_request;
399 fn->wifi_nan_publish_cancel_request = nan_publish_cancel_request;
400 fn->wifi_nan_subscribe_request = nan_subscribe_request;
401 fn->wifi_nan_subscribe_cancel_request = nan_subscribe_cancel_request;
402 fn->wifi_nan_transmit_followup_request = nan_transmit_followup_request;
403 fn->wifi_nan_config_request = nan_config_request;
404 fn->wifi_nan_register_handler = nan_register_handler;
405 fn->wifi_nan_get_version = nan_get_version;
406 fn->wifi_nan_get_capabilities = nan_get_capabilities;
47e18f37
JPS
407 fn->wifi_get_roaming_capabilities = wifi_get_roaming_capabilities;
408 fn->wifi_enable_firmware_roaming = wifi_enable_firmware_roaming;
5822f843
SP
409 fn->wifi_get_packet_filter_capabilities = wifi_get_packet_filter_capabilities;
410 fn->wifi_set_packet_filter = wifi_set_packet_filter;
411 fn->wifi_read_packet_filter = wifi_read_packet_filter;
f8204f99 412 fn->wifi_set_latency_mode = wifi_set_latency_mode;
d1c19a13 413
7753f181
DD
414 return WIFI_SUCCESS;
415}
416
417wifi_error wifi_initialize(wifi_handle *handle)
418{
419 srand(getpid());
420
421 ALOGI("Initializing wifi");
422 hal_info *info = (hal_info *)malloc(sizeof(hal_info));
423 if (info == NULL) {
424 ALOGE("Could not allocate hal_info");
425 return WIFI_ERROR_UNKNOWN;
426 }
427
428 memset(info, 0, sizeof(*info));
429
7753f181
DD
430 if (socketpair(AF_UNIX, SOCK_STREAM, 0, info->cleanup_socks) == -1) {
431 ALOGE("Could not create cleanup sockets");
432 free(info);
433 return WIFI_ERROR_UNKNOWN;
434 }
435
436 struct nl_sock *cmd_sock = wifi_create_nl_socket(WIFI_HAL_CMD_SOCK_PORT);
437 if (cmd_sock == NULL) {
438 ALOGE("Could not create handle");
439 free(info);
440 return WIFI_ERROR_UNKNOWN;
441 }
442
443 struct nl_sock *event_sock = wifi_create_nl_socket(WIFI_HAL_EVENT_SOCK_PORT);
444 if (event_sock == NULL) {
445 ALOGE("Could not create handle");
446 nl_socket_free(cmd_sock);
447 free(info);
448 return WIFI_ERROR_UNKNOWN;
449 }
450
451 struct nl_cb *cb = nl_socket_get_cb(event_sock);
452 if (cb == NULL) {
453 ALOGE("Could not create handle");
454 nl_socket_free(cmd_sock);
455 nl_socket_free(event_sock);
456 free(info);
457 return WIFI_ERROR_UNKNOWN;
458 }
459
460// ALOGI("cb->refcnt = %d", cb->cb_refcnt);
461 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, internal_no_seq_check, info);
462 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, internal_valid_message_handler, info);
463 nl_cb_put(cb);
464
465 info->cmd_sock = cmd_sock;
466 info->event_sock = event_sock;
467 info->clean_up = false;
468 info->in_event_loop = false;
469
470 info->event_cb = (cb_info *)malloc(sizeof(cb_info) * DEFAULT_EVENT_CB_SIZE);
471 info->alloc_event_cb = DEFAULT_EVENT_CB_SIZE;
472 info->num_event_cb = 0;
473
474 info->cmd = (cmd_info *)malloc(sizeof(cmd_info) * DEFAULT_CMD_SIZE);
475 info->alloc_cmd = DEFAULT_CMD_SIZE;
476 info->num_cmd = 0;
477
478 info->nl80211_family_id = genl_ctrl_resolve(cmd_sock, "nl80211");
479 if (info->nl80211_family_id < 0) {
480 ALOGE("Could not resolve nl80211 familty id");
481 nl_socket_free(cmd_sock);
482 nl_socket_free(event_sock);
483 free(info);
484 return WIFI_ERROR_UNKNOWN;
485 }
486
487 pthread_mutex_init(&info->cb_lock, NULL);
488
489 *handle = (wifi_handle) info;
7753f181
DD
490 wifi_add_membership(*handle, "scan");
491 wifi_add_membership(*handle, "mlme");
492 wifi_add_membership(*handle, "regulatory");
493 wifi_add_membership(*handle, "vendor");
494
495 wifi_init_interfaces(*handle);
c0b490a2
JPS
496 char intf_name_buff[10 * 10 + 4]; /* Randomly choosen max interface 10. each interface name max 9 + 1(for space) */
497 char *pos = intf_name_buff;
498 for (int i = 0; i < (info->num_interfaces < 10 ? info->num_interfaces : 10); i++) {
499 strncpy(pos, info->interfaces[i]->name, sizeof(intf_name_buff) - (pos - intf_name_buff));
500 pos += strlen(pos);
501 }
502 if (info->num_interfaces > 10) {
503 strncpy(pos, "...", 3);
504 }
7753f181 505
c0b490a2 506 ALOGD("Found %d interfaces[%s]. Initialized Wifi HAL Successfully", info->num_interfaces, intf_name_buff);
7753f181 507
7753f181
DD
508 return WIFI_SUCCESS;
509}
510
511static int wifi_add_membership(wifi_handle handle, const char *group)
512{
513 hal_info *info = getHalInfo(handle);
514
515 int id = wifi_get_multicast_id(handle, "nl80211", group);
516 if (id < 0) {
517 ALOGE("Could not find group %s", group);
518 return id;
519 }
520
521 int ret = nl_socket_add_membership(info->event_sock, id);
522 if (ret < 0) {
523 ALOGE("Could not add membership to group %s", group);
524 }
7753f181
DD
525 return ret;
526}
527
528static void internal_cleaned_up_handler(wifi_handle handle)
529{
530 hal_info *info = getHalInfo(handle);
531 wifi_cleaned_up_handler cleaned_up_handler = info->cleaned_up_handler;
532
533 if (info->cmd_sock != 0) {
534 close(info->cleanup_socks[0]);
535 close(info->cleanup_socks[1]);
536 nl_socket_free(info->cmd_sock);
537 nl_socket_free(info->event_sock);
538 info->cmd_sock = NULL;
539 info->event_sock = NULL;
540 }
541
542 (*cleaned_up_handler)(handle);
543 pthread_mutex_destroy(&info->cb_lock);
544 free(info);
7753f181
DD
545}
546
547void wifi_cleanup(wifi_handle handle, wifi_cleaned_up_handler handler)
548{
549 hal_info *info = getHalInfo(handle);
550 char buf[64];
551
552 info->cleaned_up_handler = handler;
553 if (write(info->cleanup_socks[0], "Exit", 4) < 1) {
554 ALOGE("could not write to the cleanup socket");
555 } else {
556 // Listen to the response
557 // Hopefully we dont get errors or get hung up
558 // Not much can be done in that case, but assume that
559 // it has rx'ed the Exit message to exit the thread.
560 // As a fallback set the cleanup flag to TRUE
561 memset(buf, 0, sizeof(buf));
562 int result = read(info->cleanup_socks[0], buf, sizeof(buf));
563 ALOGE("%s: Read after POLL returned %d, error no = %d", __FUNCTION__, result, errno);
c0b490a2 564 if (strncmp(buf, "Done", 4) != 0) {
7753f181
DD
565 ALOGD("Rx'ed %s", buf);
566 }
567 }
568 info->clean_up = true;
569 pthread_mutex_lock(&info->cb_lock);
570
571 int bad_commands = 0;
572
7753f181
DD
573 while (info->num_cmd > bad_commands) {
574 int num_cmd = info->num_cmd;
575 cmd_info *cmdi = &(info->cmd[bad_commands]);
576 WifiCommand *cmd = cmdi->cmd;
577 if (cmd != NULL) {
578 pthread_mutex_unlock(&info->cb_lock);
579 cmd->cancel();
580 pthread_mutex_lock(&info->cb_lock);
581 /* release reference added when command is saved */
582 cmd->releaseRef();
583 if (num_cmd == info->num_cmd) {
584 bad_commands++;
585 }
586 }
587 }
588
589 for (int i = 0; i < info->num_event_cb; i++) {
590 cb_info *cbi = &(info->event_cb[i]);
591 WifiCommand *cmd = (WifiCommand *)cbi->cb_arg;
592 ALOGE("Leaked command %p", cmd);
593 }
594 pthread_mutex_unlock(&info->cb_lock);
595 internal_cleaned_up_handler(handle);
596}
597
598static int internal_pollin_handler(wifi_handle handle)
599{
600 hal_info *info = getHalInfo(handle);
7753f181
DD
601 struct nl_cb *cb = nl_socket_get_cb(info->event_sock);
602 int res = nl_recvmsgs(info->event_sock, cb);
7753f181
DD
603 nl_cb_put(cb);
604 return res;
605}
606
607/* Run event handler */
608void wifi_event_loop(wifi_handle handle)
609{
610 hal_info *info = getHalInfo(handle);
7753f181
DD
611 if (info->in_event_loop) {
612 return;
613 } else {
614 info->in_event_loop = true;
615 }
616
617 pollfd pfd[2];
618 memset(&pfd[0], 0, sizeof(pollfd) * 2);
619
620 pfd[0].fd = nl_socket_get_fd(info->event_sock);
621 pfd[0].events = POLLIN;
622 pfd[1].fd = info->cleanup_socks[1];
623 pfd[1].events = POLLIN;
624
625 char buf[2048];
626
627 do {
628 int timeout = -1; /* Infinite timeout */
629 pfd[0].revents = 0;
630 pfd[1].revents = 0;
631 int result = poll(pfd, 2, timeout);
632 if (result < 0) {
633 } else if (pfd[0].revents & POLLERR) {
c0b490a2 634 int prev_err = (int)errno;
7753f181 635 int result2 = read(pfd[0].fd, buf, sizeof(buf));
c0b490a2 636 ALOGE("Poll err:%d | Read after POLL returned %d, error no = %d", prev_err, result2, errno);
7753f181
DD
637 } else if (pfd[0].revents & POLLHUP) {
638 ALOGE("Remote side hung up");
639 break;
640 } else if (pfd[0].revents & POLLIN) {
641 internal_pollin_handler(handle);
642 } else if (pfd[1].revents & POLLIN) {
643 memset(buf, 0, sizeof(buf));
644 int result2 = read(pfd[1].fd, buf, sizeof(buf));
645 ALOGE("%s: Read after POLL returned %d, error no = %d", __FUNCTION__, result2, errno);
646 if (strncmp(buf, "Exit", 4) == 0) {
647 ALOGD("Got a signal to exit!!!");
648 if (write(pfd[1].fd, "Done", 4) < 1) {
649 ALOGE("could not write to the cleanup socket");
650 }
651 break;
652 } else {
653 ALOGD("Rx'ed %s on the cleanup socket\n", buf);
654 }
655 } else {
656 ALOGE("Unknown event - %0x, %0x", pfd[0].revents, pfd[1].revents);
657 }
658 } while (!info->clean_up);
7753f181
DD
659}
660
661///////////////////////////////////////////////////////////////////////////////////////
662
663static int internal_no_seq_check(struct nl_msg *msg, void *arg)
664{
665 return NL_OK;
666}
667
668static int internal_valid_message_handler(nl_msg *msg, void *arg)
669{
670 wifi_handle handle = (wifi_handle)arg;
671 hal_info *info = getHalInfo(handle);
7753f181
DD
672
673 WifiEvent event(msg);
674 int res = event.parse();
675 if (res < 0) {
676 ALOGE("Failed to parse event: %d", res);
677 return NL_SKIP;
678 }
679
680 int cmd = event.get_cmd();
681 uint32_t vendor_id = 0;
682 int subcmd = 0;
683
684 if (cmd == NL80211_CMD_VENDOR) {
685 vendor_id = event.get_u32(NL80211_ATTR_VENDOR_ID);
686 subcmd = event.get_u32(NL80211_ATTR_VENDOR_SUBCMD);
d20effd2 687 /*
7753f181 688 ALOGI("event received %s, vendor_id = 0x%0x, subcmd = 0x%0x",
d20effd2 689 event.get_cmdString(), vendor_id, subcmd);*/
7753f181
DD
690 }
691
692 //ALOGI("event received %s, vendor_id = 0x%0x", event.get_cmdString(), vendor_id);
693 //event.log();
694
7753f181 695 pthread_mutex_lock(&info->cb_lock);
3c0c6ab1 696
7753f181
DD
697 for (int i = 0; i < info->num_event_cb; i++) {
698 if (cmd == info->event_cb[i].nl_cmd) {
699 if (cmd == NL80211_CMD_VENDOR
700 && ((vendor_id != info->event_cb[i].vendor_id)
701 || (subcmd != info->event_cb[i].vendor_subcmd)))
702 {
703 /* event for a different vendor, ignore it */
704 continue;
705 }
706
707 cb_info *cbi = &(info->event_cb[i]);
708 nl_recvmsg_msg_cb_t cb_func = cbi->cb_func;
709 void *cb_arg = cbi->cb_arg;
710 WifiCommand *cmd = (WifiCommand *)cbi->cb_arg;
711 if (cmd != NULL) {
712 cmd->addRef();
713 }
714
715 pthread_mutex_unlock(&info->cb_lock);
716 if (cb_func)
717 (*cb_func)(msg, cb_arg);
718 if (cmd != NULL) {
719 cmd->releaseRef();
720 }
721
722 return NL_OK;
723 }
724 }
725
726 pthread_mutex_unlock(&info->cb_lock);
727 return NL_OK;
728}
729
730///////////////////////////////////////////////////////////////////////////////////////
731
732class GetMulticastIdCommand : public WifiCommand
733{
734private:
735 const char *mName;
736 const char *mGroup;
737 int mId;
738public:
739 GetMulticastIdCommand(wifi_handle handle, const char *name, const char *group)
740 : WifiCommand(handle, 0)
741 {
742 mName = name;
743 mGroup = group;
744 mId = -1;
745 }
746
747 int getId() {
748 return mId;
749 }
750
751 virtual int create() {
752 int nlctrlFamily = genl_ctrl_resolve(mInfo->cmd_sock, "nlctrl");
7753f181
DD
753 int ret = mMsg.create(nlctrlFamily, CTRL_CMD_GETFAMILY, 0, 0);
754 if (ret < 0) {
755 return ret;
756 }
757 ret = mMsg.put_string(CTRL_ATTR_FAMILY_NAME, mName);
758 return ret;
759 }
760
761 virtual int handleResponse(WifiEvent& reply) {
7753f181 762 struct nlattr **tb = reply.attributes();
7753f181
DD
763 struct nlattr *mcgrp = NULL;
764 int i;
765
766 if (!tb[CTRL_ATTR_MCAST_GROUPS]) {
767 ALOGE("No multicast groups found");
768 return NL_SKIP;
7753f181
DD
769 }
770
771 for_each_attr(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
772
7753f181
DD
773 struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
774 nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, (nlattr *)nla_data(mcgrp),
775 nla_len(mcgrp), NULL);
776 if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] || !tb2[CTRL_ATTR_MCAST_GRP_ID]) {
777 continue;
778 }
779
780 char *grpName = (char *)nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]);
781 int grpNameLen = nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME]);
782
7753f181
DD
783 if (strncmp(grpName, mGroup, grpNameLen) != 0)
784 continue;
785
786 mId = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
787 break;
788 }
789
790 return NL_SKIP;
791 }
792
793};
794
795class SetPnoMacAddrOuiCommand : public WifiCommand {
796
797private:
798 byte *mOui;
799 feature_set *fset;
800 feature_set *feature_matrix;
801 int *fm_size;
802 int set_size_max;
803public:
804 SetPnoMacAddrOuiCommand(wifi_interface_handle handle, oui scan_oui)
805 : WifiCommand(handle, 0)
806 {
807 mOui = scan_oui;
ec386ae4
HG
808 fset = NULL;
809 feature_matrix = NULL;
810 fm_size = NULL;
811 set_size_max = 0;
7753f181
DD
812 }
813
814 int createRequest(WifiRequest& request, int subcmd, byte *scan_oui) {
815 int result = request.create(GOOGLE_OUI, subcmd);
816 if (result < 0) {
817 return result;
818 }
819
820 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
821 result = request.put(ANDR_WIFI_ATTRIBUTE_PNO_RANDOM_MAC_OUI, scan_oui, DOT11_OUI_LEN);
822 if (result < 0) {
823 return result;
824 }
825
826 request.attr_end(data);
827 return WIFI_SUCCESS;
828
829 }
830
831 int start() {
7753f181
DD
832 WifiRequest request(familyId(), ifaceId());
833 int result = createRequest(request, SLSI_NL80211_VENDOR_SUBCMD_SET_GSCAN_OUI, mOui);
834 if (result != WIFI_SUCCESS) {
835 ALOGE("failed to create request; result = %d", result);
836 return result;
837 }
838
839 result = requestResponse(request);
840 if (result != WIFI_SUCCESS) {
841 ALOGE("failed to set scanning mac OUI; result = %d", result);
842 }
843
844 return result;
845 }
846protected:
847 virtual int handleResponse(WifiEvent& reply) {
7753f181
DD
848 /* Nothing to do on response! */
849 return NL_SKIP;
850 }
851};
852
853class SetNodfsCommand : public WifiCommand {
854
855private:
856 u32 mNoDfs;
857public:
858 SetNodfsCommand(wifi_interface_handle handle, u32 nodfs)
859 : WifiCommand(handle, 0) {
860 mNoDfs = nodfs;
861 }
862 virtual int create() {
863 int ret;
864
865 ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_NODFS);
866 if (ret < 0) {
867 ALOGE("Can't create message to send to driver - %d", ret);
868 return ret;
869 }
870
871 nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
872 ret = mMsg.put_u32(ATTR_NODFS_VALUE, mNoDfs);
873 if (ret < 0) {
874 return ret;
875 }
876
877 mMsg.attr_end(data);
878 return WIFI_SUCCESS;
879 }
880};
881
f425b4a8
PG
882class SetRSSIMonitorCommand : public WifiCommand {
883private:
884 s8 mMax_rssi;
885 s8 mMin_rssi;
886 wifi_rssi_event_handler mHandler;
887public:
888 SetRSSIMonitorCommand(wifi_request_id id, wifi_interface_handle handle,
889 s8 max_rssi, s8 min_rssi, wifi_rssi_event_handler eh)
890 : WifiCommand(handle, id), mMax_rssi(max_rssi), mMin_rssi
891 (min_rssi), mHandler(eh)
892 {
893 }
894 int createRequest(WifiRequest& request, int enable) {
895 int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_RSSI_MONITOR);
896 if (result < 0) {
897 return result;
898 }
899
900 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
901 result = request.put_u8(RSSI_MONITOR_ATTRIBUTE_MAX_RSSI, (enable ? mMax_rssi: 0));
902 if (result < 0) {
903 return result;
904 }
c0b490a2 905
f425b4a8
PG
906 result = request.put_u8(RSSI_MONITOR_ATTRIBUTE_MIN_RSSI, (enable? mMin_rssi: 0));
907 if (result < 0) {
908 return result;
909 }
910 result = request.put_u8(RSSI_MONITOR_ATTRIBUTE_START, enable);
911 if (result < 0) {
912 return result;
913 }
914 request.attr_end(data);
915 return result;
916 }
917
918 int start() {
919 WifiRequest request(familyId(), ifaceId());
920 int result = createRequest(request, 1);
921 if (result < 0) {
922 return result;
923 }
924 result = requestResponse(request);
925 if (result < 0) {
926 ALOGI("Failed to set RSSI Monitor, result = %d", result);
927 return result;
928 }
929 ALOGI("Successfully set RSSI monitoring");
930 registerVendorHandler(GOOGLE_OUI, WIFI_RSSI_REPORT_EVENT);
931
f425b4a8
PG
932 return result;
933 }
934
935 virtual int cancel() {
936
937 WifiRequest request(familyId(), ifaceId());
938 int result = createRequest(request, 0);
939 if (result != WIFI_SUCCESS) {
940 ALOGE("failed to create request; result = %d", result);
941 } else {
942 result = requestResponse(request);
943 if (result != WIFI_SUCCESS) {
944 ALOGE("failed to stop RSSI monitoring = %d", result);
945 }
946 }
947 unregisterVendorHandler(GOOGLE_OUI, WIFI_RSSI_REPORT_EVENT);
948 return WIFI_SUCCESS;
949 }
950
951 virtual int handleResponse(WifiEvent& reply) {
952 /* Nothing to do on response! */
953 return NL_SKIP;
954 }
955
956 virtual int handleEvent(WifiEvent& event) {
f425b4a8
PG
957
958 nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
959 int len = event.get_vendor_data_len();
960
961 if (vendor_data == NULL || len == 0) {
962 ALOGI("RSSI monitor: No data");
963 return NL_SKIP;
964 }
965
966 typedef struct {
967 s8 cur_rssi;
968 mac_addr BSSID;
969 } rssi_monitor_evt;
970
971 rssi_monitor_evt *data = (rssi_monitor_evt *)event.get_vendor_data();
972
973 if (*mHandler.on_rssi_threshold_breached) {
974 (*mHandler.on_rssi_threshold_breached)(id(), data->BSSID, data->cur_rssi);
975 } else {
976 ALOGW("No RSSI monitor handler registered");
977 }
978
979 return NL_SKIP;
980 }
981
982};
983
1fdbd4c1
MG
984class SetCountryCodeCommand : public WifiCommand {
985private:
986 const char *mCountryCode;
987public:
988 SetCountryCodeCommand(wifi_interface_handle handle, const char *country_code)
989 : WifiCommand(handle, 0) {
990 mCountryCode = country_code;
991 }
992 virtual int create() {
993 int ret;
994
995 ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_COUNTRY_CODE);
996 if (ret < 0) {
997 ALOGE("Can't create message to send to driver - %d", ret);
998 return ret;
999 }
1000
1001 nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
1002 ret = mMsg.put_string(ATTR_COUNTRY_CODE, mCountryCode);
1003 if (ret < 0) {
1004 return ret;
1005 }
1006
1007 mMsg.attr_end(data);
1008 return WIFI_SUCCESS;
1009
1010 }
1011};
1012
0318783f 1013class GetFeatureSetCommand : public WifiCommand {
f425b4a8 1014
0318783f 1015private:
0fe9bfaf 1016
0318783f 1017 feature_set *fset;
0fe9bfaf 1018
0318783f
JPS
1019public:
1020 GetFeatureSetCommand(wifi_interface_handle handle, feature_set *set)
1021 : WifiCommand(handle, 0)
1022 {
1023 fset = set;
1024 }
1025
1026 virtual int create() {
1027 int ret;
1028
1029 ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_GET_FEATURE_SET);
1030 if (ret < 0) {
1031 ALOGE("create failed - %d", ret);
1032 }
1033
1034 return ret;
1035 }
1036
1037protected:
1038 virtual int handleResponse(WifiEvent& reply) {
1039
0318783f
JPS
1040 if (reply.get_cmd() != NL80211_CMD_VENDOR) {
1041 ALOGD("Ignore reply; cmd = %d", reply.get_cmd());
1042 return NL_SKIP;
1043 }
1044
1045 nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
1046 int len = reply.get_vendor_data_len();
1047
1048 if (vendor_data == NULL || len == 0) {
1049 ALOGE("vendor data in GetFeatureSetCommand missing!!");
1050 return NL_SKIP;
1051 }
1052
1053 void *data = reply.get_vendor_data();
1054 if(!fset) {
1055 ALOGE("feature_set Pointer not set");
1056 return NL_SKIP;
1057 }
1058 memcpy(fset, data, min(len, (int) sizeof(*fset)));
1059 return NL_OK;
1060 }
1061
1062};
f425b4a8 1063
f8204f99
AC
1064class SetLatencyLockCommand : public WifiCommand {
1065private:
1066 wifi_latency_mode mMode;
1067public:
1068 SetLatencyLockCommand(wifi_interface_handle handle, wifi_latency_mode mode)
1069 : WifiCommand(handle, 0) {
1070 mMode = mode;
1071 }
1072 virtual int create() {
1073 int ret;
1074
1075 ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_LATENCY_MODE);
1076 if (ret < 0) {
1077 ALOGE("Can't create message to send to driver - %d", ret);
1078 return ret;
1079 }
de14a5c9 1080
f8204f99
AC
1081 nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
1082 ret = mMsg.put_u8(ATTR_LOW_LATENCY_MODE, mMode);
1083 if (ret < 0) {
1084 return ret;
1085 }
1086
1087 mMsg.attr_end(data);
1088 return WIFI_SUCCESS;
1089 }
1090};
de14a5c9 1091
7753f181
DD
1092static int wifi_get_multicast_id(wifi_handle handle, const char *name, const char *group)
1093{
1094 GetMulticastIdCommand cmd(handle, name, group);
1095 int res = cmd.requestResponse();
1096 if (res < 0)
1097 return res;
1098 else
1099 return cmd.getId();
1100}
1101
1102/////////////////////////////////////////////////////////////////////////
1103
1104static bool is_wifi_interface(const char *name)
1105{
1106 if (strncmp(name, "wlan", 4) != 0 && strncmp(name, "p2p", 3) != 0) {
1107 /* not a wifi interface; ignore it */
1108 return false;
1109 } else {
1110 return true;
1111 }
1112}
1113
1114static int get_interface(const char *name, interface_info *info)
1115{
1116 strcpy(info->name, name);
1117 info->id = if_nametoindex(name);
7753f181
DD
1118 return WIFI_SUCCESS;
1119}
1120
1121wifi_error wifi_init_interfaces(wifi_handle handle)
1122{
1123 hal_info *info = (hal_info *)handle;
7753f181
DD
1124 struct dirent *de;
1125
1126 DIR *d = opendir("/sys/class/net");
1127 if (d == 0)
1128 return WIFI_ERROR_UNKNOWN;
1129
1130 int n = 0;
1131 while ((de = readdir(d))) {
1132 if (de->d_name[0] == '.')
1133 continue;
1134 if (is_wifi_interface(de->d_name) ) {
1135 n++;
1136 }
1137 }
1138
1139 closedir(d);
1140
1141 d = opendir("/sys/class/net");
1142 if (d == 0)
1143 return WIFI_ERROR_UNKNOWN;
1144
1145 info->interfaces = (interface_info **)malloc(sizeof(interface_info *) * n);
1146
1147 int i = 0;
1148 while ((de = readdir(d))) {
1149 if (de->d_name[0] == '.')
1150 continue;
1151 if (is_wifi_interface(de->d_name)) {
1152 interface_info *ifinfo = (interface_info *)malloc(sizeof(interface_info));
1153 if (get_interface(de->d_name, ifinfo) != WIFI_SUCCESS) {
1154 free(ifinfo);
1155 continue;
1156 }
1157 ifinfo->handle = handle;
1158 info->interfaces[i] = ifinfo;
1159 i++;
1160 }
1161 }
1162
1163 closedir(d);
1164
1165 info->num_interfaces = n;
1166 return WIFI_SUCCESS;
1167}
1168
1169wifi_error wifi_get_ifaces(wifi_handle handle, int *num, wifi_interface_handle **interfaces)
1170{
1171 hal_info *info = (hal_info *)handle;
1172
1173 *interfaces = (wifi_interface_handle *)info->interfaces;
1174 *num = info->num_interfaces;
1175
1176 return WIFI_SUCCESS;
1177}
1178
1179wifi_error wifi_get_iface_name(wifi_interface_handle handle, char *name, size_t size)
1180{
1181 interface_info *info = (interface_info *)handle;
1182 strcpy(name, info->name);
1183 return WIFI_SUCCESS;
1184}
1185
7753f181
DD
1186wifi_error wifi_get_concurrency_matrix(wifi_interface_handle handle, int set_size_max,
1187 feature_set set[], int *set_size)
1188{
1189 return WIFI_ERROR_NOT_SUPPORTED;
1190}
1191
1192wifi_error wifi_set_scanning_mac_oui(wifi_interface_handle handle, oui scan_oui)
1193{
046aeb41
HG
1194 SetPnoMacAddrOuiCommand command(handle, scan_oui);
1195 return (wifi_error)command.start();
1196
7753f181
DD
1197}
1198
1199wifi_error wifi_set_nodfs_flag(wifi_interface_handle handle, u32 nodfs)
1200{
1201 SetNodfsCommand command(handle, nodfs);
1202 return (wifi_error) command.requestResponse();
1203}
1204
f425b4a8
PG
1205static wifi_error wifi_start_rssi_monitoring(wifi_request_id id, wifi_interface_handle
1206 iface, s8 max_rssi, s8 min_rssi, wifi_rssi_event_handler eh)
1207{
1208 ALOGD("Start RSSI monitor %d", id);
1209 wifi_handle handle = getWifiHandle(iface);
1210 SetRSSIMonitorCommand *cmd = new SetRSSIMonitorCommand(id, iface, max_rssi, min_rssi, eh);
1211 wifi_register_cmd(handle, id, cmd);
1212
1213 wifi_error result = (wifi_error)cmd->start();
1214 if (result != WIFI_SUCCESS) {
1215 wifi_unregister_cmd(handle, id);
1216 }
1217 return result;
1218}
1219
1220
1221static wifi_error wifi_stop_rssi_monitoring(wifi_request_id id, wifi_interface_handle iface)
1222{
1223 ALOGD("Stopping RSSI monitor");
1224
1225 if(id == -1) {
1226 wifi_rssi_event_handler handler;
f425b4a8
PG
1227 memset(&handler, 0, sizeof(handler));
1228 SetRSSIMonitorCommand *cmd = new SetRSSIMonitorCommand(id, iface,
1229 0, 0, handler);
1230 cmd->cancel();
1231 cmd->releaseRef();
1232 return WIFI_SUCCESS;
1233 }
1234 return wifi_cancel_cmd(id, iface);
1235}
1236
0318783f
JPS
1237wifi_error wifi_get_supported_feature_set(wifi_interface_handle handle, feature_set *set)
1238{
1239 GetFeatureSetCommand command(handle, set);
1240 return (wifi_error) command.requestResponse();
1241}
1242
1fdbd4c1
MG
1243wifi_error wifi_set_country_code(wifi_interface_handle handle, const char *country_code)
1244{
1245 SetCountryCodeCommand command(handle, country_code);
1246 return (wifi_error) command.requestResponse();
1247}
1248
f8204f99
AC
1249wifi_error wifi_set_latency_mode(wifi_interface_handle handle, wifi_latency_mode mode) {
1250 SetLatencyLockCommand cmd(handle, mode);
1251 return (wifi_error) cmd.requestResponse();
1252}
114ef2d7
HG
1253/////////////////////////////////////////////////////////////////////////////
1254