[7570] wlbt: implement exponential G-scan
[GitHub/LineageOS/android_hardware_samsung_slsi_scsc_wifibt_wifi_hal.git] / gscan.cpp
CommitLineData
7753f181
DD
1
2#include <stdint.h>
3#include <fcntl.h>
4#include <sys/socket.h>
5#include <netlink/genl/genl.h>
6#include <netlink/genl/family.h>
7#include <netlink/genl/ctrl.h>
8#include <linux/rtnetlink.h>
9#include <netpacket/packet.h>
10#include <linux/filter.h>
11#include <linux/errqueue.h>
12
13#include <linux/pkt_sched.h>
14#include <netlink/object-api.h>
15#include <netlink/netlink.h>
16#include <netlink/socket.h>
17#include <netlink/handlers.h>
18
19#include "sync.h"
20
21#define LOG_TAG "WifiHAL"
22
23#include <utils/Log.h>
24
25#include "wifi_hal.h"
26#include "common.h"
27#include "cpp_bindings.h"
28
29typedef enum {
30
31 GSCAN_ATTRIBUTE_NUM_BUCKETS = 10,
32 GSCAN_ATTRIBUTE_BASE_PERIOD,
33 GSCAN_ATTRIBUTE_BUCKETS_BAND,
34 GSCAN_ATTRIBUTE_BUCKET_ID,
35 GSCAN_ATTRIBUTE_BUCKET_PERIOD,
36 GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS,
37 GSCAN_ATTRIBUTE_BUCKET_CHANNELS,
38 GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN,
39 GSCAN_ATTRIBUTE_REPORT_THRESHOLD,
40 GSCAN_ATTRIBUTE_NUM_SCANS_TO_CACHE,
41 GSCAN_ATTRIBUTE_REPORT_THRESHOLD_NUM_SCANS,
42 GSCAN_ATTRIBUTE_BAND = GSCAN_ATTRIBUTE_BUCKETS_BAND,
43
44 GSCAN_ATTRIBUTE_ENABLE_FEATURE = 20,
45 GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, /* indicates no more results */
46 GSCAN_ATTRIBUTE_REPORT_EVENTS,
47
48 /* remaining reserved for additional attributes */
49 GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30,
50 GSCAN_ATTRIBUTE_SCAN_RESULTS, /* flat array of wifi_scan_result */
51 GSCAN_ATTRIBUTE_NUM_CHANNELS,
52 GSCAN_ATTRIBUTE_CHANNEL_LIST,
53 GSCAN_ATTRIBUTE_SCAN_ID,
54 GSCAN_ATTRIBUTE_SCAN_FLAGS,
55
56 /* remaining reserved for additional attributes */
57
58 GSCAN_ATTRIBUTE_SSID = 40,
59 GSCAN_ATTRIBUTE_BSSID,
60 GSCAN_ATTRIBUTE_CHANNEL,
61 GSCAN_ATTRIBUTE_RSSI,
62 GSCAN_ATTRIBUTE_TIMESTAMP,
63 GSCAN_ATTRIBUTE_RTT,
64 GSCAN_ATTRIBUTE_RTTSD,
65
66 /* remaining reserved for additional attributes */
67
68 GSCAN_ATTRIBUTE_HOTLIST_BSSIDS = 50,
69 GSCAN_ATTRIBUTE_RSSI_LOW,
70 GSCAN_ATTRIBUTE_RSSI_HIGH,
71 GSCAN_ATTRIBUTE_HOTLIST_ELEM,
72 GSCAN_ATTRIBUTE_HOTLIST_FLUSH,
73 GSCAN_ATTRIBUTE_CHANNEL_NUMBER,
74
75 /* remaining reserved for additional attributes */
76 GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE = 60,
77 GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE,
78 GSCAN_ATTRIBUTE_MIN_BREACHING,
79 GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS,
80
0e19df50
JPS
81 GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT = 70,
82 GSCAN_ATTRIBUTE_BUCKET_EXPONENT,
83 GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD,
84
7753f181
DD
85 GSCAN_ATTRIBUTE_MAX
86
87} GSCAN_ATTRIBUTE;
88
89
90class GetCapabilitiesCommand : public WifiCommand
91{
92 wifi_gscan_capabilities *mCapabilities;
93public:
94 GetCapabilitiesCommand(wifi_interface_handle iface, wifi_gscan_capabilities *capabitlites)
95 : WifiCommand(iface, 0), mCapabilities(capabitlites)
96 {
97 memset(mCapabilities, 0, sizeof(*mCapabilities));
98 }
99
100 virtual int create() {
101 ALOGD("Creating message to get scan capablities; iface = %d", mIfaceInfo->id);
102
103 int ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_GET_CAPABILITIES);
104 if (ret < 0) {
105 ALOGD("NL message creation failed");
106 return ret;
107 }
108
109 return ret;
110 }
111
112protected:
113 virtual int handleResponse(WifiEvent& reply) {
114
115 ALOGD("In GetCapabilities::handleResponse");
116
117 if (reply.get_cmd() != NL80211_CMD_VENDOR) {
118 ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
119 return NL_SKIP;
120 }
121
122 int id = reply.get_vendor_id();
123 int subcmd = reply.get_vendor_subcmd();
124
125 void *data = reply.get_vendor_data();
126 int len = reply.get_vendor_data_len();
127
128 ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id, subcmd, len,
129 sizeof(*mCapabilities));
130
131 memcpy(mCapabilities, data, min(len, (int) sizeof(*mCapabilities)));
132
133 return NL_OK;
134 }
135};
136
137
138wifi_error wifi_get_gscan_capabilities(wifi_interface_handle handle,
139 wifi_gscan_capabilities *capabilities)
140{
141 GetCapabilitiesCommand command(handle, capabilities);
142 return (wifi_error) command.requestResponse();
143}
144
145class GetChannelListCommand : public WifiCommand
146{
147 wifi_channel *channels;
148 int max_channels;
149 int *num_channels;
150 int band;
151public:
152 GetChannelListCommand(wifi_interface_handle iface, wifi_channel *channel_buf, int *ch_num,
153 int num_max_ch, int band)
154 : WifiCommand(iface, 0), channels(channel_buf), max_channels(num_max_ch), num_channels(ch_num),
155 band(band)
156 {
157 memset(channels, 0, sizeof(wifi_channel) * max_channels);
158 }
159 virtual int create() {
160 ALOGD("Creating message to get channel list; iface = %d", mIfaceInfo->id);
161
162 int ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_GET_VALID_CHANNELS);
163 if (ret < 0) {
164 return ret;
165 }
166
167 nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
168 ret = mMsg.put_u32(GSCAN_ATTRIBUTE_BAND, band);
169 if (ret < 0) {
170 return ret;
171 }
172
173 mMsg.attr_end(data);
174
175 return ret;
176 }
177
178protected:
179 virtual int handleResponse(WifiEvent& reply) {
180
181 ALOGD("In GetChannelList::handleResponse");
182
183 if (reply.get_cmd() != NL80211_CMD_VENDOR) {
184 ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
185 return NL_SKIP;
186 }
187
188 int id = reply.get_vendor_id();
189 int subcmd = reply.get_vendor_subcmd();
190 int num_channels_to_copy = 0;
191
192 nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
193 int len = reply.get_vendor_data_len();
194
195 ALOGD("Id = %0x, subcmd = %d, len = %d", id, subcmd, len);
196 if (vendor_data == NULL || len == 0) {
197 ALOGE("no vendor data in GetChannelList response; ignoring it");
198 return NL_SKIP;
199 }
200
201 for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
202 if (it.get_type() == GSCAN_ATTRIBUTE_NUM_CHANNELS) {
203 num_channels_to_copy = it.get_u32();
204 ALOGD("Got channel list with %d channels", num_channels_to_copy);
205 if(num_channels_to_copy > max_channels)
206 num_channels_to_copy = max_channels;
207 *num_channels = num_channels_to_copy;
208 } else if (it.get_type() == GSCAN_ATTRIBUTE_CHANNEL_LIST && num_channels_to_copy) {
209 memcpy(channels, it.get_data(), sizeof(int) * num_channels_to_copy);
210 } else {
211 ALOGW("Ignoring invalid attribute type = %d, size = %d",
212 it.get_type(), it.get_len());
213 }
214 }
215
216 return NL_OK;
217 }
218};
219
220wifi_error wifi_get_valid_channels(wifi_interface_handle handle,
221 int band, int max_channels, wifi_channel *channels, int *num_channels)
222{
223 GetChannelListCommand command(handle, channels, num_channels,
224 max_channels, band);
225 return (wifi_error) command.requestResponse();
226}
227/////////////////////////////////////////////////////////////////////////////
228
229/* helper functions */
230
231static int parseScanResults(wifi_scan_result *results, int num, nlattr *attr)
232{
233 memset(results, 0, sizeof(wifi_scan_result) * num);
234
235 int i = 0;
236 for (nl_iterator it(attr); it.has_next() && i < num; it.next(), i++) {
237
238 int index = it.get_type();
239 ALOGD("retrieved scan result %d", index);
240 nlattr *sc_data = (nlattr *) it.get_data();
241 wifi_scan_result *result = results + i;
242
243 for (nl_iterator it2(sc_data); it2.has_next(); it2.next()) {
244 int type = it2.get_type();
245 if (type == GSCAN_ATTRIBUTE_SSID) {
246 strncpy(result->ssid, (char *) it2.get_data(), it2.get_len());
247 result->ssid[it2.get_len()] = 0;
248 } else if (type == GSCAN_ATTRIBUTE_BSSID) {
249 memcpy(result->bssid, (byte *) it2.get_data(), sizeof(mac_addr));
250 } else if (type == GSCAN_ATTRIBUTE_TIMESTAMP) {
251 result->ts = it2.get_u64();
252 } else if (type == GSCAN_ATTRIBUTE_CHANNEL) {
253 result->ts = it2.get_u16();
254 } else if (type == GSCAN_ATTRIBUTE_RSSI) {
255 result->rssi = it2.get_u8();
256 } else if (type == GSCAN_ATTRIBUTE_RTT) {
257 result->rtt = it2.get_u64();
258 } else if (type == GSCAN_ATTRIBUTE_RTTSD) {
259 result->rtt_sd = it2.get_u64();
260 }
261 }
262
263 }
264
265 if (i >= num) {
266 ALOGE("Got too many results; skipping some");
267 }
268
269 return i;
270}
271
272int createFeatureRequest(WifiRequest& request, int subcmd) {
273
274 int result = request.create(GOOGLE_OUI, subcmd);
275 if (result < 0) {
276 return result;
277 }
278
279 return WIFI_SUCCESS;
280}
281
282class ScanCommand : public WifiCommand
283{
284 wifi_scan_cmd_params *mParams;
285 wifi_scan_result_handler mHandler;
286 static unsigned mGlobalFullScanBuckets;
287 bool mLocalFullScanBuckets;
288public:
289 ScanCommand(wifi_interface_handle iface, int id, wifi_scan_cmd_params *params,
290 wifi_scan_result_handler handler)
291 : WifiCommand(iface, id), mParams(params), mHandler(handler),
292 mLocalFullScanBuckets(0)
293 { }
294
295 int createSetupRequest(WifiRequest& request) {
296 int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_ADD_GSCAN);
297 if (result < 0) {
298 return result;
299 }
300
301 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
302 result = request.put_u32(GSCAN_ATTRIBUTE_BASE_PERIOD, mParams->base_period);
303 if (result < 0) {
304 return result;
305 }
306
307 result = request.put_u32(GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN, mParams->max_ap_per_scan);
308 if (result < 0) {
309 return result;
310 }
311
312 result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_THRESHOLD, mParams->report_threshold_percent);
313 if (result < 0) {
314 return result;
315 }
316
317 result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_THRESHOLD_NUM_SCANS, mParams->report_threshold_num_scans);
318 if (result < 0) {
319 return result;
320 }
321
322 result = request.put_u32(GSCAN_ATTRIBUTE_NUM_BUCKETS, mParams->num_buckets);
323 if (result < 0) {
324 return result;
325 }
326
327 for (int i = 0; i < mParams->num_buckets; i++) {
328 nlattr * bucket = request.attr_start(i); // next bucket
329 result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_ID, mParams->buckets[i].bucket);
330 if (result < 0) {
331 return result;
332 }
333 result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_PERIOD, mParams->buckets[i].period);
334 if (result < 0) {
335 return result;
336 }
337 result = request.put_u32(GSCAN_ATTRIBUTE_BUCKETS_BAND,
338 mParams->buckets[i].band);
339 if (result < 0) {
340 return result;
341 }
342
343 result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_EVENTS,
344 mParams->buckets[i].report_events);
345 if (result < 0) {
346 return result;
347 }
348
349 result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS,
350 mParams->buckets[i].num_channels);
351 if (result < 0) {
352 return result;
353 }
354
0e19df50
JPS
355 result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_EXPONENT,
356 mParams->buckets[i].exponent);
357 if (result < 0) {
358 return result;
359 }
360
361 result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD,
362 mParams->buckets[i].max_period);
363 if (result < 0) {
364 return result;
365 }
366
367 result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT,
368 mParams->buckets[i].step_count);
369 if (result < 0) {
370 return result;
371 }
372
7753f181
DD
373 if (mParams->buckets[i].num_channels) {
374 nlattr *channels = request.attr_start(GSCAN_ATTRIBUTE_BUCKET_CHANNELS);
375 for (int j = 0; j < mParams->buckets[i].num_channels; j++) {
376 result = request.put_u32(j, mParams->buckets[i].channels[j].channel);
377 if (result < 0) {
378 return result;
379 }
380 }
381 request.attr_end(channels);
382 }
383
384 request.attr_end(bucket);
385 }
386
387 request.attr_end(data);
388 return WIFI_SUCCESS;
389 }
390
391 int createStartRequest(WifiRequest& request) {
392 return createFeatureRequest(request, SLSI_NL80211_VENDOR_SUBCMD_ADD_GSCAN);
393 }
394
395 int createStopRequest(WifiRequest& request) {
396 return createFeatureRequest(request, SLSI_NL80211_VENDOR_SUBCMD_DEL_GSCAN);
397 }
398
399 int start() {
400 ALOGD(" sending scan req to driver");
401 WifiRequest request(familyId(), ifaceId());
402 int result = createSetupRequest(request);
403 if (result != WIFI_SUCCESS) {
404 ALOGE("failed to create setup request; result = %d", result);
405 return result;
406 }
407 ALOGD("Starting scan");
408
409 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
410 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN);
411
412 int nBuckets = 0;
413 for (int i = 0; i < mParams->num_buckets; i++) {
414 if (mParams->buckets[i].report_events == 2) {
415 nBuckets++;
416 }
417 }
418
419 if (nBuckets != 0) {
420 ALOGI("Full scan requested with nBuckets = %d", nBuckets);
421 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
422 }
423 result = requestResponse(request);
424 if (result != WIFI_SUCCESS) {
425 ALOGE("failed to start scan; result = %d", result);
426 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN);
427 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
428 return result;
429 }
430
431
432 return result;
433 }
434
435 virtual int cancel() {
436 ALOGD("Stopping scan");
437
438 WifiRequest request(familyId(), ifaceId());
439 int result = createStopRequest(request);
440 if (result != WIFI_SUCCESS) {
441 ALOGE("failed to create stop request; result = %d", result);
442 } else {
443 result = requestResponse(request);
444 if (result != WIFI_SUCCESS) {
445 ALOGE("failed to stop scan; result = %d", result);
446 }
447 }
448
449 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN);
450 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
451 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
452
453 return WIFI_SUCCESS;
454 }
455
456 virtual int handleResponse(WifiEvent& reply) {
457 /* Nothing to do on response! */
458 return NL_SKIP;
459 }
460
461 virtual int handleEvent(WifiEvent& event) {
462 ALOGD("Got a scan results event");
463
464 event.log();
465
466 nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
467 unsigned int len = event.get_vendor_data_len();
468 int event_id = event.get_vendor_subcmd();
469 ALOGD("handleEvent, event_id = %d", event_id);
470
471 if(event_id == GSCAN_EVENT_COMPLETE_SCAN) {
472 if (vendor_data == NULL || len != 4) {
473 ALOGD("Scan complete type not mentioned!");
474 return NL_SKIP;
475 }
476 wifi_scan_event evt_type;
477
478 evt_type = (wifi_scan_event) event.get_u32(NL80211_ATTR_VENDOR_DATA);
479 ALOGD("Scan complete: Received event type %d", evt_type);
480 if(*mHandler.on_scan_event)
481 (*mHandler.on_scan_event)(evt_type, evt_type);
482 } else if(event_id == GSCAN_EVENT_FULL_SCAN_RESULTS) {
483 if (vendor_data == NULL || len < sizeof(wifi_scan_result)) {
484 ALOGD("No scan results found");
485 return NL_SKIP;
486 }
487 wifi_scan_result *result = (wifi_scan_result *)event.get_vendor_data();
488
489 if(*mHandler.on_full_scan_result)
490 (*mHandler.on_full_scan_result)(id(), result);
491
492 ALOGD("%-32s\t", result->ssid);
493
494 ALOGD("%02x:%02x:%02x:%02x:%02x:%02x ", result->bssid[0], result->bssid[1],
495 result->bssid[2], result->bssid[3], result->bssid[4], result->bssid[5]);
496
497 ALOGD("%d\t", result->rssi);
498 ALOGD("%d\t", result->channel);
499 ALOGD("%lld\t", result->ts);
500 ALOGD("%lld\t", result->rtt);
501 ALOGD("%lld\n", result->rtt_sd);
502 } else {
503
504 if (vendor_data == NULL || len != 4) {
505 ALOGD("No scan results found");
506 return NL_SKIP;
507 }
508
509 int num = event.get_u32(NL80211_ATTR_VENDOR_DATA);
510 ALOGD("Found %d scan results", num);
511 if(*mHandler.on_scan_results_available)
512 (*mHandler.on_scan_results_available)(id(), num);
513 }
514 return NL_SKIP;
515 }
516};
517
518unsigned ScanCommand::mGlobalFullScanBuckets = 0;
519
520wifi_error wifi_start_gscan(
521 wifi_request_id id,
522 wifi_interface_handle iface,
523 wifi_scan_cmd_params params,
524 wifi_scan_result_handler handler)
525{
526 wifi_handle handle = getWifiHandle(iface);
527
528 ALOGD("Starting GScan, halHandle = %p", handle);
529
530 ScanCommand *cmd = new ScanCommand(iface, id, &params, handler);
531 wifi_register_cmd(handle, id, cmd);
532 return (wifi_error)cmd->start();
533}
534
535wifi_error wifi_stop_gscan(wifi_request_id id, wifi_interface_handle iface)
536{
537 ALOGD("Stopping GScan");
538 wifi_handle handle = getWifiHandle(iface);
539
540 if(id == -1) {
541 wifi_scan_result_handler handler;
542 wifi_scan_cmd_params dummy_params;
543 wifi_handle handle = getWifiHandle(iface);
544 memset(&handler, 0, sizeof(handler));
545
546 ScanCommand *cmd = new ScanCommand(iface, id, &dummy_params, handler);
547 cmd->cancel();
548 cmd->releaseRef();
549 return WIFI_SUCCESS;
550 }
551
552
553 WifiCommand *cmd = wifi_unregister_cmd(handle, id);
554 if (cmd) {
555 cmd->cancel();
556 cmd->releaseRef();
557 return WIFI_SUCCESS;
558 }
559
560 return WIFI_ERROR_INVALID_ARGS;
561}
562
563class GetScanResultsCommand : public WifiCommand {
564 wifi_cached_scan_results *mScans;
565 int mMax;
566 int *mNum;
567 int mRetrieved;
568 byte mFlush;
569 int mCompleted;
570 static const int MAX_RESULTS = 320;
571 wifi_scan_result mScanResults[MAX_RESULTS];
572 int mNextScanResult;
573public:
574 GetScanResultsCommand(wifi_interface_handle iface, byte flush,
575 wifi_cached_scan_results *results, int max, int *num)
576 : WifiCommand(iface, -1), mScans(results), mMax(max), mNum(num),
577 mRetrieved(0), mFlush(flush), mCompleted(0)
578 { }
579
580 int createRequest(WifiRequest& request, int num, byte flush) {
581 int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_GET_SCAN_RESULTS);
582 if (result < 0) {
583 return result;
584 }
585
586 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
587 result = request.put_u32(GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num);
588 if (result < 0) {
589 return result;
590 }
591
592 request.attr_end(data);
593 return WIFI_SUCCESS;
594 }
595
596 int execute() {
597 WifiRequest request(familyId(), ifaceId());
598 ALOGD("retrieving %d scan results", mMax);
599
600 for (int i = 0; i < 10 && mRetrieved < mMax; i++) {
601 int result = createRequest(request, (mMax - mRetrieved), mFlush);
602 if (result < 0) {
603 ALOGE("failed to create request");
604 return result;
605 }
606
607 int prev_retrieved = mRetrieved;
608
609 result = requestResponse(request);
610
611 if (result != WIFI_SUCCESS) {
612 ALOGE("failed to retrieve scan results; result = %d", result);
613 return result;
614 }
615
616 if (mRetrieved == prev_retrieved || mCompleted) {
617 /* no more items left to retrieve */
618 break;
619 }
620
621 request.destroy();
622 }
623
624 ALOGE("GetScanResults read %d results", mRetrieved);
625 *mNum = mRetrieved;
626 return WIFI_SUCCESS;
627 }
628
629 virtual int handleResponse(WifiEvent& reply) {
630 ALOGD("In GetScanResultsCommand::handleResponse");
631
632 if (reply.get_cmd() != NL80211_CMD_VENDOR) {
633 ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
634 return NL_SKIP;
635 }
636
637 int id = reply.get_vendor_id();
638 int subcmd = reply.get_vendor_subcmd();
639
640 ALOGD("Id = %0x, subcmd = %d", id, subcmd);
641
642 nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
643 int len = reply.get_vendor_data_len();
644
645 if (vendor_data == NULL || len == 0) {
646 ALOGE("no vendor data in GetScanResults response; ignoring it");
647 return NL_SKIP;
648 }
649
650 for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
651 if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE) {
652 mCompleted = it.get_u8();
653 ALOGD("retrieved mCompleted flag : %d", mCompleted);
654 } else if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS || it.get_type() == 0) {
655 int scan_id = 0, flags = 0, num = 0;
656 for (nl_iterator it2(it.get()); it2.has_next(); it2.next()) {
657 if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_ID) {
658 scan_id = it2.get_u32();
659 ALOGD("retrieved scan_id : 0x%0x", scan_id);
660 } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_FLAGS) {
661 flags = it2.get_u8();
662 ALOGD("retrieved scan_flags : 0x%0x", flags);
663 } else if (it2.get_type() == GSCAN_ATTRIBUTE_NUM_OF_RESULTS) {
664 num = it2.get_u32();
665 ALOGD("retrieved num_results: %d", num);
666 } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS) {
667 if (mRetrieved >= mMax) {
668 ALOGW("Stored %d scans, ignoring excess results", mRetrieved);
669 break;
670 }
671 num = it2.get_len() / sizeof(wifi_scan_result);
672 num = min(MAX_RESULTS - mNextScanResult, num);
673 num = min((int)MAX_AP_CACHE_PER_SCAN, num);
674 memcpy(mScanResults + mNextScanResult, it2.get_data(),
675 sizeof(wifi_scan_result) * num);
676 ALOGD("Retrieved %d scan results", num);
677 wifi_scan_result *results = (wifi_scan_result *)it2.get_data();
678 for (int i = 0; i < num; i++) {
679 wifi_scan_result *result = results + i;
680 ALOGD("%02d %-32s %02x:%02x:%02x:%02x:%02x:%02x %04d", i,
681 result->ssid, result->bssid[0], result->bssid[1], result->bssid[2],
682 result->bssid[3], result->bssid[4], result->bssid[5],
683 result->rssi);
684 }
685 mScans[mRetrieved].scan_id = scan_id;
686 mScans[mRetrieved].flags = flags;
687 mScans[mRetrieved].num_results = num;
688 ALOGD("Setting result of scan_id : 0x%0x", mScans[mRetrieved].scan_id);
689 memcpy(mScans[mRetrieved].results,
690 &(mScanResults[mNextScanResult]), num * sizeof(wifi_scan_result));
691 mNextScanResult += num;
692 mRetrieved++;
693 } else {
694 ALOGW("Ignoring invalid attribute type = %d, size = %d",
695 it.get_type(), it.get_len());
696 }
697 }
698 } else {
699 ALOGW("Ignoring invalid attribute type = %d, size = %d",
700 it.get_type(), it.get_len());
701 }
702 }
703
704 return NL_OK;
705 }
706};
707
708wifi_error wifi_get_cached_gscan_results(wifi_interface_handle iface, byte flush,
709 int max, wifi_cached_scan_results *results, int *num) {
710 ALOGD("Getting cached scan results, iface handle = %p, num = %d", iface, *num);
711
712 GetScanResultsCommand *cmd = new GetScanResultsCommand(iface, flush, results, max, num);
713 return (wifi_error)cmd->execute();
714}
715
716/////////////////////////////////////////////////////////////////////////////
717
718class BssidHotlistCommand : public WifiCommand
719{
720private:
721 wifi_bssid_hotlist_params mParams;
722 wifi_hotlist_ap_found_handler mHandler;
723 static const int MAX_RESULTS = 64;
724 wifi_scan_result mResults[MAX_RESULTS];
725public:
726 BssidHotlistCommand(wifi_interface_handle handle, int id,
727 wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler)
728 : WifiCommand(handle, id), mParams(params), mHandler(handler)
729 { }
730
731 int createSetupRequest(WifiRequest& request) {
732 int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_BSSID_HOTLIST);
733 if (result < 0) {
734 return result;
735 }
736
737 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
738
739 result = request.put_u32(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, mParams.lost_ap_sample_size);
740 if (result < 0) {
741 return result;
742 }
743
744 struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS);
745 for (int i = 0; i < mParams.num_bssid; i++) {
746 nlattr *attr2 = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_ELEM);
747 if (attr2 == NULL) {
748 return WIFI_ERROR_OUT_OF_MEMORY;
749 }
750 result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid);
751 if (result < 0) {
752 return result;
753 }
754 result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high);
755 if (result < 0) {
756 return result;
757 }
758 result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low);
759 if (result < 0) {
760 return result;
761 }
762 request.attr_end(attr2);
763 }
764
765 request.attr_end(attr);
766 request.attr_end(data);
767 return result;
768 }
769
770 int createTeardownRequest(WifiRequest& request) {
771 int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_RESET_BSSID_HOTLIST);
772 if (result < 0) {
773 return result;
774 }
775
776 return result;
777 }
778
779 int start() {
780 ALOGD("Executing hotlist setup request, num = %d", mParams.num_bssid);
781 WifiRequest request(familyId(), ifaceId());
782 int result = createSetupRequest(request);
783 if (result < 0) {
784 return result;
785 }
786
787 result = requestResponse(request);
788 if (result < 0) {
789 ALOGD("Failed to execute hotlist setup request, result = %d", result);
790 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND);
791 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST);
792 return result;
793 }
794
795 ALOGD("Successfully set %d APs in the hotlist", mParams.num_bssid);
796
797 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND);
798 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST);
799
800 return result;
801 }
802
803 virtual int cancel() {
804 /* unregister event handler */
805 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND);
806 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST);
807 /* create set hotlist message with empty hotlist */
808 WifiRequest request(familyId(), ifaceId());
809 int result = createTeardownRequest(request);
810 if (result < 0) {
811 return result;
812 }
813
814 result = requestResponse(request);
815 if (result < 0) {
816 return result;
817 }
818
819 ALOGD("Successfully reset APs in current hotlist");
820 return result;
821 }
822
823 virtual int handleResponse(WifiEvent& reply) {
824 /* Nothing to do on response! */
825 return NL_SKIP;
826 }
827
828 virtual int handleEvent(WifiEvent& event) {
829 ALOGD("Hotlist AP event");
830 int event_id = event.get_vendor_subcmd();
831 event.log();
832
833 nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
834 int len = event.get_vendor_data_len();
835
836 if (vendor_data == NULL || len == 0) {
837 ALOGD("No scan results found");
838 return NL_SKIP;
839 }
840
841 memset(mResults, 0, sizeof(wifi_scan_result) * MAX_RESULTS);
842
843 int num = len / sizeof(wifi_scan_result);
844 num = min(MAX_RESULTS, num);
845 memcpy(mResults, event.get_vendor_data(), num * sizeof(wifi_scan_result));
846
847 if (event_id == GSCAN_EVENT_HOTLIST_RESULTS_FOUND) {
848 ALOGD("FOUND %d hotlist APs", num);
849 if (*mHandler.on_hotlist_ap_found)
850 (*mHandler.on_hotlist_ap_found)(id(), num, mResults);
851 } else if (event_id == GSCAN_EVENT_HOTLIST_RESULTS_LOST) {
852 ALOGD("LOST %d hotlist APs", num);
853 if (*mHandler.on_hotlist_ap_lost)
854 (*mHandler.on_hotlist_ap_lost)(id(), num, mResults);
855 }
856 return NL_SKIP;
857 }
858};
859
860wifi_error wifi_set_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface,
861 wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler)
862{
863 wifi_handle handle = getWifiHandle(iface);
864
865 BssidHotlistCommand *cmd = new BssidHotlistCommand(iface, id, params, handler);
866 wifi_register_cmd(handle, id, cmd);
867 return (wifi_error)cmd->start();
868}
869
870wifi_error wifi_reset_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface)
871{
872 wifi_handle handle = getWifiHandle(iface);
873
874 WifiCommand *cmd = wifi_unregister_cmd(handle, id);
875 if (cmd) {
876 cmd->cancel();
877 cmd->releaseRef();
878 return WIFI_SUCCESS;
879 }
880
881 return WIFI_ERROR_INVALID_ARGS;
882}
883
884
885/////////////////////////////////////////////////////////////////////////////
886
887class SignificantWifiChangeCommand : public WifiCommand
888{
889 typedef struct {
890 mac_addr bssid; // BSSID
891 wifi_channel channel; // channel frequency in MHz
892 int num_rssi; // number of rssi samples
893 wifi_rssi rssi[8]; // RSSI history in db
894 } wifi_significant_change_result_internal;
895
896private:
897 wifi_significant_change_params mParams;
898 wifi_significant_change_handler mHandler;
899 static const int MAX_RESULTS = 64;
900 wifi_significant_change_result_internal mResultsBuffer[MAX_RESULTS];
901 wifi_significant_change_result *mResults[MAX_RESULTS];
902public:
903 SignificantWifiChangeCommand(wifi_interface_handle handle, int id,
904 wifi_significant_change_params params, wifi_significant_change_handler handler)
905 : WifiCommand(handle, id), mParams(params), mHandler(handler)
906 { }
907
908 int createSetupRequest(WifiRequest& request) {
909 int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_SIGNIFICANT_CHANGE);
910 if (result < 0) {
911 return result;
912 }
913
914 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
915
916 result = request.put_u16(GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE, mParams.rssi_sample_size);
917 if (result < 0) {
918 return result;
919 }
920 result = request.put_u16(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, mParams.lost_ap_sample_size);
921 if (result < 0) {
922 return result;
923 }
924 result = request.put_u16(GSCAN_ATTRIBUTE_MIN_BREACHING, mParams.min_breaching);
925 if (result < 0) {
926 return result;
927 }
928
929 struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS);
930
931 for (int i = 0; i < mParams.num_bssid; i++) {
932
933 nlattr *attr2 = request.attr_start(i);
934 if (attr2 == NULL) {
935 return WIFI_ERROR_OUT_OF_MEMORY;
936 }
937 result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid);
938 if (result < 0) {
939 return result;
940 }
941 result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high);
942 if (result < 0) {
943 return result;
944 }
945 result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low);
946 if (result < 0) {
947 return result;
948 }
949 request.attr_end(attr2);
950 }
951
952 request.attr_end(attr);
953 request.attr_end(data);
954
955 return result;
956 }
957
958 int createTeardownRequest(WifiRequest& request) {
959 int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_RESET_SIGNIFICANT_CHANGE);
960 if (result < 0) {
961 return result;
962 }
963
964 return result;
965 }
966
967 int start() {
968 ALOGD("Set significant wifi change");
969 WifiRequest request(familyId(), ifaceId());
970
971 int result = createSetupRequest(request);
972 if (result < 0) {
973 return result;
974 }
975
976 result = requestResponse(request);
977 if (result < 0) {
978 ALOGD("failed to set significant wifi change %d", result);
979 return result;
980 }
981 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
982
983 return result;
984 }
985
986 virtual int cancel() {
987 /* unregister event handler */
988 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
989
990 /* create set significant change monitor message with empty hotlist */
991 WifiRequest request(familyId(), ifaceId());
992
993 int result = createTeardownRequest(request);
994 if (result < 0) {
995 return result;
996 }
997
998 result = requestResponse(request);
999 if (result < 0) {
1000 return result;
1001 }
1002
1003 ALOGD("successfully reset significant wifi change");
1004 return result;
1005 }
1006
1007 virtual int handleResponse(WifiEvent& reply) {
1008 /* Nothing to do on response! */
1009 return NL_SKIP;
1010 }
1011
1012 virtual int handleEvent(WifiEvent& event) {
1013 ALOGD("Got a significant wifi change event");
1014
1015 nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
1016 int len = event.get_vendor_data_len();
1017
1018 if (vendor_data == NULL || len == 0) {
1019 ALOGD("No scan results found");
1020 return NL_SKIP;
1021 }
1022
1023 typedef struct {
1024 uint16_t channel;
1025 mac_addr bssid;
1026 int16_t rssi_history[8];
1027 } ChangeInfo;
1028
1029 int num = min(len / sizeof(ChangeInfo), MAX_RESULTS);
1030 ChangeInfo *ci = (ChangeInfo *)event.get_vendor_data();
1031
1032 for (int i = 0; i < num; i++) {
1033 memcpy(mResultsBuffer[i].bssid, ci[i].bssid, sizeof(mac_addr));
1034 mResultsBuffer[i].channel = ci[i].channel;
1035 /* Driver sends N samples and the rest 8-N are filled 0x7FFF
1036 * N = no of rssi samples to average sent in significant change request. */
1037 int num_rssi = 0;
1038 for (int j = 0; j < 8; j++) {
1039 if (ci[i].rssi_history[j] == 0x7FFF) {
1040 num_rssi = j;
1041 break;
1042 }
1043 mResultsBuffer[i].rssi[j] = (int) ci[i].rssi_history[j];
1044 }
1045 mResultsBuffer[i].num_rssi = num_rssi;
1046 mResults[i] = reinterpret_cast<wifi_significant_change_result *>(&(mResultsBuffer[i]));
1047 }
1048
1049 ALOGD("Retrieved %d scan results", num);
1050
1051 if (num != 0) {
1052 (*mHandler.on_significant_change)(id(), num, mResults);
1053 } else {
1054 ALOGW("No significant change reported");
1055 }
1056
1057 return NL_SKIP;
1058 }
1059};
1060
1061wifi_error wifi_set_significant_change_handler(wifi_request_id id, wifi_interface_handle iface,
1062 wifi_significant_change_params params, wifi_significant_change_handler handler)
1063{
1064 wifi_handle handle = getWifiHandle(iface);
1065
1066 SignificantWifiChangeCommand *cmd = new SignificantWifiChangeCommand(
1067 iface, id, params, handler);
1068 wifi_register_cmd(handle, id, cmd);
1069 return (wifi_error)cmd->start();
1070}
1071
1072wifi_error wifi_reset_significant_change_handler(wifi_request_id id, wifi_interface_handle iface)
1073{
1074 wifi_handle handle = getWifiHandle(iface);
1075
1076 WifiCommand *cmd = wifi_unregister_cmd(handle, id);
1077 if (cmd) {
1078 cmd->cancel();
1079 cmd->releaseRef();
1080 return WIFI_SUCCESS;
1081 }
1082
1083 return WIFI_ERROR_INVALID_ARGS;
1084}