SSB-8693 slsi hal library code for GSCAN
[GitHub/MotorolaMobilityLLC/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_DWELL_TIME,
42 GSCAN_ATTRIBUTE_SCAN_TYPE,
43 GSCAN_ATTRIBUTE_BAND = GSCAN_ATTRIBUTE_BUCKETS_BAND,
44
45 GSCAN_ATTRIBUTE_ENABLE_FEATURE = 20,
46 GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE, /* indicates no more results */
47 GSCAN_ENABLE_FULL_SCAN_RESULTS,
48 GSCAN_ATTRIBUTE_REPORT_EVENTS,
49
50 /* remaining reserved for additional attributes */
51 GSCAN_ATTRIBUTE_NUM_OF_RESULTS = 30,
52 GSCAN_ATTRIBUTE_SCAN_RESULTS, /* flat array of wifi_scan_result */
53 GSCAN_ATTRIBUTE_NUM_CHANNELS,
54 GSCAN_ATTRIBUTE_CHANNEL_LIST,
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);
309 if (result < 0) {
310 return result;
311 }
312
313 result = request.put_u32(GSCAN_ATTRIBUTE_NUM_BUCKETS, mParams->num_buckets);
314 if (result < 0) {
315 return result;
316 }
317
318 for (int i = 0; i < mParams->num_buckets; i++) {
319 nlattr * bucket = request.attr_start(i); // next bucket
320 result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_ID, mParams->buckets[i].bucket);
321 if (result < 0) {
322 return result;
323 }
324 result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_PERIOD, mParams->buckets[i].period);
325 if (result < 0) {
326 return result;
327 }
328 result = request.put_u32(GSCAN_ATTRIBUTE_BUCKETS_BAND,
329 mParams->buckets[i].band);
330 if (result < 0) {
331 return result;
332 }
333
334 result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_EVENTS,
335 mParams->buckets[i].report_events);
336 if (result < 0) {
337 return result;
338 }
339
340 result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS,
341 mParams->buckets[i].num_channels);
342 if (result < 0) {
343 return result;
344 }
345
346 if (mParams->buckets[i].num_channels) {
347 nlattr *channels = request.attr_start(GSCAN_ATTRIBUTE_BUCKET_CHANNELS);
348 for (int j = 0; j < mParams->buckets[i].num_channels; j++) {
349 result = request.put_u32(j, mParams->buckets[i].channels[j].channel);
350 if (result < 0) {
351 return result;
352 }
353 }
354 request.attr_end(channels);
355 }
356
357 request.attr_end(bucket);
358 }
359
360 request.attr_end(data);
361 return WIFI_SUCCESS;
362 }
363
364 int createStartRequest(WifiRequest& request) {
365 return createFeatureRequest(request, SLSI_NL80211_VENDOR_SUBCMD_ADD_GSCAN);
366 }
367
368 int createStopRequest(WifiRequest& request) {
369 return createFeatureRequest(request, SLSI_NL80211_VENDOR_SUBCMD_DEL_GSCAN);
370 }
371
372 int enableFullScanResultsIfRequired() {
373 /* temporary workaround till we have full support for per bucket scans */
374
375 ALOGI("enabling full scan results if needed");
376 int nBuckets = 0;
377 for (int i = 0; i < mParams->num_buckets; i++) {
378 if (mParams->buckets[i].report_events == 2) {
379 nBuckets++;
380 }
381 }
382
383 if (mGlobalFullScanBuckets == 0 && nBuckets != 0) {
384
385 ALOGI("full scan results were requested ");
386 ALOGI("mGlobalFullScanBuckets = %d, nBuckets = %d", mGlobalFullScanBuckets, nBuckets);
387 mLocalFullScanBuckets = nBuckets;
388 mGlobalFullScanBuckets += nBuckets;
389 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
390
391 } else {
392 ALOGI("mGlobalFullScanBuckets = %d, nBuckets = %d", mGlobalFullScanBuckets, nBuckets);
393
394 }
395
396 return WIFI_SUCCESS;
397 }
398 int disableFullScanResultsIfRequired() {
399 /* temporary workaround till we have full support for per bucket scans */
400
401 if (mLocalFullScanBuckets == 0) {
402 return WIFI_SUCCESS;
403 }
404
405 mGlobalFullScanBuckets -= mLocalFullScanBuckets;
406 if (mGlobalFullScanBuckets == 0) {
407
408 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
409 }
410
411 return WIFI_SUCCESS;
412 }
413 int start() {
414 ALOGD(" sending scan req to driver");
415 WifiRequest request(familyId(), ifaceId());
416 int result = createSetupRequest(request);
417 if (result != WIFI_SUCCESS) {
418 ALOGE("failed to create setup request; result = %d", result);
419 return result;
420 }
421 ALOGD("Starting scan");
422
423 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
424 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN);
425 result = enableFullScanResultsIfRequired();
426 if ( result == WIFI_SUCCESS)
427 {
428
429 }
430
431 result = requestResponse(request);
432 if (result != WIFI_SUCCESS) {
433 ALOGE("failed to start scan; result = %d", result);
434 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN);
435 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
436 return result;
437 }
438
439
440 return result;
441 }
442
443 virtual int cancel() {
444 ALOGD("Stopping scan");
445
446 WifiRequest request(familyId(), ifaceId());
447 int result = createStopRequest(request);
448 if (result != WIFI_SUCCESS) {
449 ALOGE("failed to create stop request; result = %d", result);
450 } else {
451 result = requestResponse(request);
452 if (result != WIFI_SUCCESS) {
453 ALOGE("failed to stop scan; result = %d", result);
454 }
455 }
456
457 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN);
458 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
459 disableFullScanResultsIfRequired();
460
461 return WIFI_SUCCESS;
462 }
463
464 virtual int handleResponse(WifiEvent& reply) {
465 /* Nothing to do on response! */
466 return NL_SKIP;
467 }
468
469 virtual int handleEvent(WifiEvent& event) {
470 ALOGD("Got a scan results event");
471
472 event.log();
473
474 nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
475 int len = event.get_vendor_data_len();
476 int event_id = event.get_vendor_subcmd();
477
478 if(event_id == GSCAN_EVENT_COMPLETE_SCAN) {
479 if (vendor_data == NULL || len != 4) {
480 ALOGD("Scan complete type not mentioned!");
481 return NL_SKIP;
482 }
483 wifi_scan_event evt_type;
484
485 evt_type = (wifi_scan_event) event.get_u32(NL80211_ATTR_VENDOR_DATA);
486 ALOGD("Scan complete: Received event type %d", evt_type);
487 if(*mHandler.on_scan_event)
488 (*mHandler.on_scan_event)(evt_type, evt_type);
489 } else if(event_id == GSCAN_EVENT_FULL_SCAN_RESULTS) {
490 if (vendor_data == NULL || len < sizeof(wifi_scan_result)) {
491 ALOGD("No scan results found");
492 return NL_SKIP;
493 }
494 wifi_scan_result *result = (wifi_scan_result *)event.get_vendor_data();
495
496 if(*mHandler.on_full_scan_result)
497 (*mHandler.on_full_scan_result)(id(), result);
498
499 ALOGD("%-32s\t", result->ssid);
500
501 ALOGD("%02x:%02x:%02x:%02x:%02x:%02x ", result->bssid[0], result->bssid[1],
502 result->bssid[2], result->bssid[3], result->bssid[4], result->bssid[5]);
503
504 ALOGD("%d\t", result->rssi);
505 ALOGD("%d\t", result->channel);
506 ALOGD("%lld\t", result->ts);
507 ALOGD("%lld\t", result->rtt);
508 ALOGD("%lld\n", result->rtt_sd);
509 } else {
510
511 if (vendor_data == NULL || len != 4) {
512 ALOGD("No scan results found");
513 return NL_SKIP;
514 }
515
516 int num = event.get_u32(NL80211_ATTR_VENDOR_DATA);
517 ALOGD("Found %d scan results", num);
518 if(*mHandler.on_scan_results_available)
519 (*mHandler.on_scan_results_available)(id(), num);
520 }
521 return NL_SKIP;
522 }
523 };
524
525 unsigned ScanCommand::mGlobalFullScanBuckets = 0;
526
527 wifi_error wifi_start_gscan(
528 wifi_request_id id,
529 wifi_interface_handle iface,
530 wifi_scan_cmd_params params,
531 wifi_scan_result_handler handler)
532 {
533 wifi_handle handle = getWifiHandle(iface);
534
535 ALOGD("Starting GScan, halHandle = %p", handle);
536
537 ScanCommand *cmd = new ScanCommand(iface, id, &params, handler);
538 wifi_register_cmd(handle, id, cmd);
539 return (wifi_error)cmd->start();
540 }
541
542 wifi_error wifi_stop_gscan(wifi_request_id id, wifi_interface_handle iface)
543 {
544 ALOGD("Stopping GScan");
545 wifi_handle handle = getWifiHandle(iface);
546
547 if(id == -1) {
548 wifi_scan_result_handler handler;
549 wifi_scan_cmd_params dummy_params;
550 wifi_handle handle = getWifiHandle(iface);
551 memset(&handler, 0, sizeof(handler));
552
553 ScanCommand *cmd = new ScanCommand(iface, id, &dummy_params, handler);
554 cmd->cancel();
555 cmd->releaseRef();
556 return WIFI_SUCCESS;
557 }
558
559
560 WifiCommand *cmd = wifi_unregister_cmd(handle, id);
561 if (cmd) {
562 cmd->cancel();
563 cmd->releaseRef();
564 return WIFI_SUCCESS;
565 }
566
567 return WIFI_ERROR_INVALID_ARGS;
568 }
569
570 class GetScanResultsCommand : public WifiCommand {
571 wifi_scan_result *mResults;
572 int mMax;
573 int *mNum;
574 int mRetrieved;
575 byte mFlush;
576 int mCompleted;
577 public:
578 GetScanResultsCommand(wifi_interface_handle iface, byte flush,
579 wifi_scan_result *results, int max, int *num)
580 : WifiCommand(iface, -1), mResults(results), mMax(max), mNum(num),
581 mRetrieved(0), mFlush(flush), mCompleted(0)
582 { }
583
584 int createRequest(WifiRequest& request, int num, byte flush) {
585 int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_GET_SCAN_RESULTS);
586 if (result < 0) {
587 return result;
588 }
589
590 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
591 result = request.put_u32(GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num);
592 if (result < 0) {
593 return result;
594 }
595
596 request.attr_end(data);
597 return WIFI_SUCCESS;
598 }
599
600 int execute() {
601 WifiRequest request(familyId(), ifaceId());
602 ALOGD("retrieving %d scan results", mMax);
603
604 for (int i = 0; i < 10 && mRetrieved < mMax; i++) {
605 int result = createRequest(request, (mMax - mRetrieved), mFlush);
606 if (result < 0) {
607 ALOGE("failed to create request");
608 return result;
609 }
610
611 int prev_retrieved = mRetrieved;
612
613 result = requestResponse(request);
614
615 if (result != WIFI_SUCCESS) {
616 ALOGE("failed to retrieve scan results; result = %d", result);
617 return result;
618 }
619
620 if (mRetrieved == prev_retrieved || mCompleted) {
621 /* no more items left to retrieve */
622 break;
623 }
624
625 request.destroy();
626 }
627
628 ALOGE("GetScanResults read %d results", mRetrieved);
629 *mNum = mRetrieved;
630 return WIFI_SUCCESS;
631 }
632
633 virtual int handleResponse(WifiEvent& reply) {
634 ALOGD("In GetScanResultsCommand::handleResponse");
635
636 if (reply.get_cmd() != NL80211_CMD_VENDOR) {
637 ALOGD("Ignoring reply with cmd = %d", reply.get_cmd());
638 return NL_SKIP;
639 }
640
641 int id = reply.get_vendor_id();
642 int subcmd = reply.get_vendor_subcmd();
643
644 ALOGD("Id = %0x, subcmd = %d", id, subcmd);
645
646 /*
647 if (subcmd != GSCAN_SUBCMD_SCAN_RESULTS) {
648 ALOGE("Invalid response to GetScanResultsCommand; ignoring it");
649 return NL_SKIP;
650 }
651 */
652
653 nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
654 int len = reply.get_vendor_data_len();
655
656 if (vendor_data == NULL || len == 0) {
657 ALOGE("no vendor data in GetScanResults response; ignoring it");
658 return NL_SKIP;
659 }
660
661 for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
662 if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE) {
663 mCompleted = it.get_u8();
664 ALOGD("retrieved mCompleted flag : %d", mCompleted);
665 } else if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS || it.get_type() == 0) {
666 for (nl_iterator it2(it.get()); it2.has_next(); it2.next()) {
667 int num = 0;
668 if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS) {
669 num = it2.get_len() / sizeof(wifi_scan_result);
670 num = min(*mNum - mRetrieved, num);
671 memcpy(mResults + mRetrieved, it2.get_data(),
672 sizeof(wifi_scan_result) * num);
673 ALOGD("Retrieved %d scan results", num);
674 wifi_scan_result *results = (wifi_scan_result *)it2.get_data();
675 for (int i = 0; i < num; i++) {
676 wifi_scan_result *result = results + i;
677 ALOGD("%02d %-32s %02x:%02x:%02x:%02x:%02x:%02x %04d", i,
678 result->ssid, result->bssid[0], result->bssid[1], result->bssid[2],
679 result->bssid[3], result->bssid[4], result->bssid[5],
680 result->rssi);
681 }
682 mRetrieved += num;
683 } else {
684 ALOGW("Ignoring invalid attribute type = %d, size = %d",
685 it.get_type(), it.get_len());
686 }
687 }
688 } else {
689 ALOGW("Ignoring invalid attribute type = %d, size = %d",
690 it.get_type(), it.get_len());
691 }
692 }
693
694 return NL_OK;
695 }
696 };
697
698 wifi_error wifi_get_cached_gscan_results(wifi_interface_handle iface, byte flush,
699 int max, wifi_scan_result *results, int *num) {
700
701 ALOGD("Getting cached scan results, iface handle = %p, num = %d", iface, *num);
702
703 GetScanResultsCommand *cmd = new GetScanResultsCommand(iface, flush, results, max, num);
704 return (wifi_error)cmd->execute();
705 }
706
707 /////////////////////////////////////////////////////////////////////////////
708
709 class BssidHotlistCommand : public WifiCommand
710 {
711 private:
712 wifi_bssid_hotlist_params mParams;
713 wifi_hotlist_ap_found_handler mHandler;
714 static const int MAX_RESULTS = 64;
715 wifi_scan_result mResults[MAX_RESULTS];
716 public:
717 BssidHotlistCommand(wifi_interface_handle handle, int id,
718 wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler)
719 : WifiCommand(handle, id), mParams(params), mHandler(handler)
720 { }
721
722 int createSetupRequest(WifiRequest& request) {
723 int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_BSSID_HOTLIST);
724 if (result < 0) {
725 return result;
726 }
727
728 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
729
730 result = request.put_u32(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, mParams.lost_ap_sample_size);
731 if (result < 0) {
732 return result;
733 }
734
735 struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_BSSIDS);
736 for (int i = 0; i < mParams.num_ap; i++) {
737 nlattr *attr2 = request.attr_start(GSCAN_ATTRIBUTE_HOTLIST_ELEM);
738 if (attr2 == NULL) {
739 return WIFI_ERROR_OUT_OF_MEMORY;
740 }
741 result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid);
742 if (result < 0) {
743 return result;
744 }
745 result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high);
746 if (result < 0) {
747 return result;
748 }
749 result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low);
750 if (result < 0) {
751 return result;
752 }
753 result = request.put_u8(GSCAN_ATTRIBUTE_CHANNEL_NUMBER, mParams.ap[i].channel);
754 if (result < 0) {
755 return result;
756 }
757 request.attr_end(attr2);
758 }
759
760 request.attr_end(attr);
761 request.attr_end(data);
762 return result;
763 }
764
765 int createTeardownRequest(WifiRequest& request) {
766 int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_RESET_BSSID_HOTLIST);
767 if (result < 0) {
768 return result;
769 }
770
771 return result;
772 }
773
774 int start() {
775 ALOGD("Executing hotlist setup request, num = %d", mParams.num_ap);
776 WifiRequest request(familyId(), ifaceId());
777 int result = createSetupRequest(request);
778 if (result < 0) {
779 return result;
780 }
781
782 result = requestResponse(request);
783 if (result < 0) {
784 ALOGD("Failed to execute hotlist setup request, result = %d", result);
785 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND);
786 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST);
787 return result;
788 }
789
790 ALOGD("Successfully set %d APs in the hotlist", mParams.num_ap);
791 result = createFeatureRequest(request, SLSI_NL80211_VENDOR_SUBCMD_ADD_GSCAN);
792 if (result < 0) {
793 return result;
794 }
795
796 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND);
797 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST);
798
799 result = requestResponse(request);
800 if (result < 0) {
801 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND);
802 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST);
803 return result;
804 }
805
806 ALOGD("successfully restarted the scan");
807 return result;
808 }
809
810 virtual int cancel() {
811 /* unregister event handler */
812 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_FOUND);
813 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_HOTLIST_RESULTS_LOST);
814 /* create set hotlist message with empty hotlist */
815 WifiRequest request(familyId(), ifaceId());
816 int result = createTeardownRequest(request);
817 if (result < 0) {
818 return result;
819 }
820
821 result = requestResponse(request);
822 if (result < 0) {
823 return result;
824 }
825
826 ALOGD("Successfully reset APs in current hotlist");
827 return result;
828 }
829
830 virtual int handleResponse(WifiEvent& reply) {
831 /* Nothing to do on response! */
832 return NL_SKIP;
833 }
834
835 virtual int handleEvent(WifiEvent& event) {
836 ALOGD("Hotlist AP event");
837 int event_id = event.get_vendor_subcmd();
838 event.log();
839
840 nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
841 int len = event.get_vendor_data_len();
842
843 if (vendor_data == NULL || len == 0) {
844 ALOGD("No scan results found");
845 return NL_SKIP;
846 }
847
848 memset(mResults, 0, sizeof(wifi_scan_result) * MAX_RESULTS);
849
850 int num = len / sizeof(wifi_scan_result);
851 num = min(MAX_RESULTS, num);
852 memcpy(mResults, event.get_vendor_data(), num * sizeof(wifi_scan_result));
853
854 if (event_id == GSCAN_EVENT_HOTLIST_RESULTS_FOUND) {
855 ALOGD("FOUND %d hotlist APs", num);
856 if (*mHandler.on_hotlist_ap_found)
857 (*mHandler.on_hotlist_ap_found)(id(), num, mResults);
858 } else if (event_id == GSCAN_EVENT_HOTLIST_RESULTS_LOST) {
859 ALOGD("LOST %d hotlist APs", num);
860 if (*mHandler.on_hotlist_ap_lost)
861 (*mHandler.on_hotlist_ap_lost)(id(), num, mResults);
862 }
863 return NL_SKIP;
864 }
865 };
866
867 wifi_error wifi_set_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface,
868 wifi_bssid_hotlist_params params, wifi_hotlist_ap_found_handler handler)
869 {
870 wifi_handle handle = getWifiHandle(iface);
871
872 BssidHotlistCommand *cmd = new BssidHotlistCommand(iface, id, params, handler);
873 wifi_register_cmd(handle, id, cmd);
874 return (wifi_error)cmd->start();
875 }
876
877 wifi_error wifi_reset_bssid_hotlist(wifi_request_id id, wifi_interface_handle iface)
878 {
879 wifi_handle handle = getWifiHandle(iface);
880
881 WifiCommand *cmd = wifi_unregister_cmd(handle, id);
882 if (cmd) {
883 cmd->cancel();
884 cmd->releaseRef();
885 return WIFI_SUCCESS;
886 }
887
888 return WIFI_ERROR_INVALID_ARGS;
889 }
890
891
892 /////////////////////////////////////////////////////////////////////////////
893
894 class SignificantWifiChangeCommand : public WifiCommand
895 {
896 typedef struct {
897 mac_addr bssid; // BSSID
898 wifi_channel channel; // channel frequency in MHz
899 int num_rssi; // number of rssi samples
900 wifi_rssi rssi[8]; // RSSI history in db
901 } wifi_significant_change_result_internal;
902
903 private:
904 wifi_significant_change_params mParams;
905 wifi_significant_change_handler mHandler;
906 static const int MAX_RESULTS = 64;
907 wifi_significant_change_result_internal mResultsBuffer[MAX_RESULTS];
908 wifi_significant_change_result *mResults[MAX_RESULTS];
909 public:
910 SignificantWifiChangeCommand(wifi_interface_handle handle, int id,
911 wifi_significant_change_params params, wifi_significant_change_handler handler)
912 : WifiCommand(handle, id), mParams(params), mHandler(handler)
913 { }
914
915 int createSetupRequest(WifiRequest& request) {
916 int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_SIGNIFICANT_CHANGE);
917 if (result < 0) {
918 return result;
919 }
920
921 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
922
923 result = request.put_u16(GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE, mParams.rssi_sample_size);
924 if (result < 0) {
925 return result;
926 }
927 result = request.put_u16(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE, mParams.lost_ap_sample_size);
928 if (result < 0) {
929 return result;
930 }
931 result = request.put_u16(GSCAN_ATTRIBUTE_MIN_BREACHING, mParams.min_breaching);
932 if (result < 0) {
933 return result;
934 }
935
936 struct nlattr * attr = request.attr_start(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS);
937
938 for (int i = 0; i < mParams.num_ap; i++) {
939
940 nlattr *attr2 = request.attr_start(i);
941 if (attr2 == NULL) {
942 return WIFI_ERROR_OUT_OF_MEMORY;
943 }
944 result = request.put_addr(GSCAN_ATTRIBUTE_BSSID, mParams.ap[i].bssid);
945 if (result < 0) {
946 return result;
947 }
948 result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH, mParams.ap[i].high);
949 if (result < 0) {
950 return result;
951 }
952 result = request.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW, mParams.ap[i].low);
953 if (result < 0) {
954 return result;
955 }
956 request.attr_end(attr2);
957 }
958
959 request.attr_end(attr);
960 request.attr_end(data);
961
962 return result;
963 }
964
965 int createTeardownRequest(WifiRequest& request) {
966 int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_RESET_SIGNIFICANT_CHANGE);
967 if (result < 0) {
968 return result;
969 }
970
971 return result;
972 }
973
974 int start() {
975 ALOGD("Set significant wifi change");
976 WifiRequest request(familyId(), ifaceId());
977
978 int result = createSetupRequest(request);
979 if (result < 0) {
980 return result;
981 }
982
983 result = requestResponse(request);
984 if (result < 0) {
985 ALOGD("failed to set significant wifi change %d", result);
986 return result;
987 }
988
989 result = createFeatureRequest(request, SLSI_NL80211_VENDOR_SUBCMD_ADD_GSCAN);
990 if (result < 0) {
991 return result;
992 }
993
994 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
995
996 result = requestResponse(request);
997 if (result < 0) {
998 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
999 return result;
1000 }
1001
1002 ALOGD("successfully restarted the scan");
1003 return result;
1004 }
1005
1006 virtual int cancel() {
1007 /* unregister event handler */
1008 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS);
1009
1010 /* create set significant change monitor message with empty hotlist */
1011 WifiRequest request(familyId(), ifaceId());
1012
1013 int result = createTeardownRequest(request);
1014 if (result < 0) {
1015 return result;
1016 }
1017
1018 result = requestResponse(request);
1019 if (result < 0) {
1020 return result;
1021 }
1022
1023 ALOGD("successfully reset significant wifi change");
1024 return result;
1025 }
1026
1027 virtual int handleResponse(WifiEvent& reply) {
1028 /* Nothing to do on response! */
1029 return NL_SKIP;
1030 }
1031
1032 virtual int handleEvent(WifiEvent& event) {
1033 ALOGD("Got a significant wifi change event");
1034
1035 nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
1036 int len = event.get_vendor_data_len();
1037
1038 if (vendor_data == NULL || len == 0) {
1039 ALOGD("No scan results found");
1040 return NL_SKIP;
1041 }
1042
1043 typedef struct {
1044 uint16_t channel;
1045 mac_addr bssid;
1046 s16 rssi_history[8];
1047 } ChangeInfo;
1048
1049 int num = min(len / sizeof(ChangeInfo), MAX_RESULTS);
1050 ChangeInfo *ci = (ChangeInfo *)event.get_vendor_data();
1051
1052 for (int i = 0; i < num; i++) {
1053 memcpy(mResultsBuffer[i].bssid, ci[i].bssid, sizeof(mac_addr));
1054 mResultsBuffer[i].channel = ci[i].channel;
1055 mResultsBuffer[i].num_rssi = 8;
1056 for (int j = 0; j < mResultsBuffer[i].num_rssi; j++)
1057 mResultsBuffer[i].rssi[j] = (int) ci[i].rssi_history[j];
1058 mResults[i] = reinterpret_cast<wifi_significant_change_result *>(&(mResultsBuffer[i]));
1059 }
1060
1061 ALOGD("Retrieved %d scan results", num);
1062
1063 if (num != 0) {
1064 (*mHandler.on_significant_change)(id(), num, mResults);
1065 } else {
1066 ALOGW("No significant change reported");
1067 }
1068
1069 return NL_SKIP;
1070 }
1071 };
1072
1073 wifi_error wifi_set_significant_change_handler(wifi_request_id id, wifi_interface_handle iface,
1074 wifi_significant_change_params params, wifi_significant_change_handler handler)
1075 {
1076 wifi_handle handle = getWifiHandle(iface);
1077
1078 SignificantWifiChangeCommand *cmd = new SignificantWifiChangeCommand(
1079 iface, id, params, handler);
1080 wifi_register_cmd(handle, id, cmd);
1081 return (wifi_error)cmd->start();
1082 }
1083
1084 wifi_error wifi_reset_significant_change_handler(wifi_request_id id, wifi_interface_handle iface)
1085 {
1086 wifi_handle handle = getWifiHandle(iface);
1087
1088 WifiCommand *cmd = wifi_unregister_cmd(handle, id);
1089 if (cmd) {
1090 cmd->cancel();
1091 cmd->releaseRef();
1092 return WIFI_SUCCESS;
1093 }
1094
1095 return WIFI_ERROR_INVALID_ARGS;
1096 }