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