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