[APR-2053]wlbt: NAN R2 integration fxes
[GitHub/MotorolaMobilityLLC/hardware-samsung_slsi-scsc_wifibt-wifi_hal.git] / gscan.cpp
CommitLineData
7753f181 1#include <stdint.h>
6ff2d683 2#include <stddef.h>
7753f181
DD
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
7753f181
DD
21#include <utils/Log.h>
22
23#include "wifi_hal.h"
24#include "common.h"
25#include "cpp_bindings.h"
26
6ff2d683 27typedef enum {
1fc70afb
MG
28 EPNO_ATTRIBUTE_MINIMUM_5G_RSSI,
29 EPNO_ATTRIBUTE_MINIMUM_2G_RSSI,
30 EPNO_ATTRIBUTE_INITIAL_SCORE_MAX,
31 EPNO_ATTRIBUTE_CUR_CONN_BONUS,
32 EPNO_ATTRIBUTE_SAME_NETWORK_BONUS,
33 EPNO_ATTRIBUTE_SECURE_BONUS,
34 EPNO_ATTRIBUTE_5G_BONUS,
6ff2d683 35 EPNO_ATTRIBUTE_SSID_NUM,
1fc70afb 36 EPNO_ATTRIBUTE_SSID_LIST,
6ff2d683
JPS
37 EPNO_ATTRIBUTE_SSID,
38 EPNO_ATTRIBUTE_SSID_LEN,
6ff2d683
JPS
39 EPNO_ATTRIBUTE_FLAGS,
40 EPNO_ATTRIBUTE_AUTH,
41 EPNO_ATTRIBUTE_MAX
42} EPNO_ATTRIBUTE;
43
44typedef enum {
45 EPNO_ATTRIBUTE_HS_PARAM_LIST,
46 EPNO_ATTRIBUTE_HS_NUM,
47 EPNO_ATTRIBUTE_HS_ID,
48 EPNO_ATTRIBUTE_HS_REALM,
49 EPNO_ATTRIBUTE_HS_CONSORTIUM_IDS,
50 EPNO_ATTRIBUTE_HS_PLMN,
51 EPNO_ATTRIBUTE_HS_MAX
52} EPNO_HS_ATTRIBUTE;
53
7753f181
DD
54
55class GetCapabilitiesCommand : public WifiCommand
56{
57 wifi_gscan_capabilities *mCapabilities;
58public:
59 GetCapabilitiesCommand(wifi_interface_handle iface, wifi_gscan_capabilities *capabitlites)
60 : WifiCommand(iface, 0), mCapabilities(capabitlites)
61 {
62 memset(mCapabilities, 0, sizeof(*mCapabilities));
63 }
64
65 virtual int create() {
7753f181
DD
66 int ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_GET_CAPABILITIES);
67 if (ret < 0) {
9a2ccc1c 68 ALOGE("NL message creation failed");
7753f181
DD
69 return ret;
70 }
71
72 return ret;
73 }
74
75protected:
76 virtual int handleResponse(WifiEvent& reply) {
77
7753f181 78 if (reply.get_cmd() != NL80211_CMD_VENDOR) {
d20effd2 79 ALOGE("Ignoring reply with cmd = %d", reply.get_cmd());
7753f181
DD
80 return NL_SKIP;
81 }
82
7753f181
DD
83 void *data = reply.get_vendor_data();
84 int len = reply.get_vendor_data_len();
85
7753f181
DD
86 memcpy(mCapabilities, data, min(len, (int) sizeof(*mCapabilities)));
87
88 return NL_OK;
89 }
90};
91
92
93wifi_error wifi_get_gscan_capabilities(wifi_interface_handle handle,
94 wifi_gscan_capabilities *capabilities)
95{
96 GetCapabilitiesCommand command(handle, capabilities);
97 return (wifi_error) command.requestResponse();
98}
99
100class GetChannelListCommand : public WifiCommand
101{
102 wifi_channel *channels;
103 int max_channels;
104 int *num_channels;
105 int band;
106public:
107 GetChannelListCommand(wifi_interface_handle iface, wifi_channel *channel_buf, int *ch_num,
108 int num_max_ch, int band)
109 : WifiCommand(iface, 0), channels(channel_buf), max_channels(num_max_ch), num_channels(ch_num),
110 band(band)
111 {
112 memset(channels, 0, sizeof(wifi_channel) * max_channels);
113 }
114 virtual int create() {
7753f181
DD
115 int ret = mMsg.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_GET_VALID_CHANNELS);
116 if (ret < 0) {
117 return ret;
118 }
119
120 nlattr *data = mMsg.attr_start(NL80211_ATTR_VENDOR_DATA);
121 ret = mMsg.put_u32(GSCAN_ATTRIBUTE_BAND, band);
122 if (ret < 0) {
123 return ret;
124 }
125
126 mMsg.attr_end(data);
127
128 return ret;
129 }
130
131protected:
132 virtual int handleResponse(WifiEvent& reply) {
133
7753f181 134 if (reply.get_cmd() != NL80211_CMD_VENDOR) {
d20effd2 135 ALOGE("Ignoring reply with cmd = %d", reply.get_cmd());
7753f181
DD
136 return NL_SKIP;
137 }
138
7753f181
DD
139 int num_channels_to_copy = 0;
140
141 nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
142 int len = reply.get_vendor_data_len();
143
7753f181
DD
144 if (vendor_data == NULL || len == 0) {
145 ALOGE("no vendor data in GetChannelList response; ignoring it");
146 return NL_SKIP;
147 }
148
149 for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
150 if (it.get_type() == GSCAN_ATTRIBUTE_NUM_CHANNELS) {
151 num_channels_to_copy = it.get_u32();
c0b490a2 152 /*ALOGD("Got channel list with %d channels", num_channels_to_copy);*/
7753f181
DD
153 if(num_channels_to_copy > max_channels)
154 num_channels_to_copy = max_channels;
155 *num_channels = num_channels_to_copy;
156 } else if (it.get_type() == GSCAN_ATTRIBUTE_CHANNEL_LIST && num_channels_to_copy) {
157 memcpy(channels, it.get_data(), sizeof(int) * num_channels_to_copy);
158 } else {
159 ALOGW("Ignoring invalid attribute type = %d, size = %d",
160 it.get_type(), it.get_len());
161 }
162 }
163
164 return NL_OK;
165 }
166};
167
168wifi_error wifi_get_valid_channels(wifi_interface_handle handle,
169 int band, int max_channels, wifi_channel *channels, int *num_channels)
170{
171 GetChannelListCommand command(handle, channels, num_channels,
172 max_channels, band);
173 return (wifi_error) command.requestResponse();
174}
175/////////////////////////////////////////////////////////////////////////////
176
177/* helper functions */
178
8094868d 179/*
7753f181
DD
180static int parseScanResults(wifi_scan_result *results, int num, nlattr *attr)
181{
182 memset(results, 0, sizeof(wifi_scan_result) * num);
183
184 int i = 0;
185 for (nl_iterator it(attr); it.has_next() && i < num; it.next(), i++) {
186
7753f181
DD
187 nlattr *sc_data = (nlattr *) it.get_data();
188 wifi_scan_result *result = results + i;
189
190 for (nl_iterator it2(sc_data); it2.has_next(); it2.next()) {
191 int type = it2.get_type();
192 if (type == GSCAN_ATTRIBUTE_SSID) {
193 strncpy(result->ssid, (char *) it2.get_data(), it2.get_len());
194 result->ssid[it2.get_len()] = 0;
195 } else if (type == GSCAN_ATTRIBUTE_BSSID) {
196 memcpy(result->bssid, (byte *) it2.get_data(), sizeof(mac_addr));
197 } else if (type == GSCAN_ATTRIBUTE_TIMESTAMP) {
198 result->ts = it2.get_u64();
199 } else if (type == GSCAN_ATTRIBUTE_CHANNEL) {
200 result->ts = it2.get_u16();
201 } else if (type == GSCAN_ATTRIBUTE_RSSI) {
202 result->rssi = it2.get_u8();
203 } else if (type == GSCAN_ATTRIBUTE_RTT) {
204 result->rtt = it2.get_u64();
205 } else if (type == GSCAN_ATTRIBUTE_RTTSD) {
206 result->rtt_sd = it2.get_u64();
207 }
208 }
209
210 }
211
212 if (i >= num) {
213 ALOGE("Got too many results; skipping some");
214 }
215
216 return i;
217}
8094868d 218*/
7753f181
DD
219
220int createFeatureRequest(WifiRequest& request, int subcmd) {
221
222 int result = request.create(GOOGLE_OUI, subcmd);
223 if (result < 0) {
224 return result;
225 }
226
227 return WIFI_SUCCESS;
228}
229
230class ScanCommand : public WifiCommand
231{
232 wifi_scan_cmd_params *mParams;
233 wifi_scan_result_handler mHandler;
234 static unsigned mGlobalFullScanBuckets;
7753f181
DD
235public:
236 ScanCommand(wifi_interface_handle iface, int id, wifi_scan_cmd_params *params,
237 wifi_scan_result_handler handler)
8094868d 238 : WifiCommand(iface, id), mParams(params), mHandler(handler)
7753f181
DD
239 { }
240
241 int createSetupRequest(WifiRequest& request) {
242 int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_ADD_GSCAN);
243 if (result < 0) {
244 return result;
245 }
246
247 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
248 result = request.put_u32(GSCAN_ATTRIBUTE_BASE_PERIOD, mParams->base_period);
249 if (result < 0) {
250 return result;
251 }
252
acc9b163 253 result = request.put_u32(GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN, mParams->max_ap_per_scan);
7753f181
DD
254 if (result < 0) {
255 return result;
256 }
257
258 result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_THRESHOLD, mParams->report_threshold_percent);
259 if (result < 0) {
260 return result;
261 }
262
263 result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_THRESHOLD_NUM_SCANS, mParams->report_threshold_num_scans);
264 if (result < 0) {
265 return result;
266 }
267
268 result = request.put_u32(GSCAN_ATTRIBUTE_NUM_BUCKETS, mParams->num_buckets);
269 if (result < 0) {
270 return result;
271 }
272
273 for (int i = 0; i < mParams->num_buckets; i++) {
274 nlattr * bucket = request.attr_start(i); // next bucket
275 result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_ID, mParams->buckets[i].bucket);
276 if (result < 0) {
277 return result;
278 }
279 result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_PERIOD, mParams->buckets[i].period);
280 if (result < 0) {
281 return result;
282 }
283 result = request.put_u32(GSCAN_ATTRIBUTE_BUCKETS_BAND,
284 mParams->buckets[i].band);
285 if (result < 0) {
286 return result;
287 }
288
f3a9f24c
MG
289 if (mParams->buckets[i].report_events == 0) {
290 mParams->buckets[i].report_events = REPORT_EVENTS_EACH_SCAN;
291 }
7753f181
DD
292 result = request.put_u32(GSCAN_ATTRIBUTE_REPORT_EVENTS,
293 mParams->buckets[i].report_events);
294 if (result < 0) {
295 return result;
296 }
297
298 result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS,
299 mParams->buckets[i].num_channels);
300 if (result < 0) {
301 return result;
302 }
303
0e19df50 304 result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_EXPONENT,
acc9b163 305 mParams->buckets[i].base);
0e19df50
JPS
306 if (result < 0) {
307 return result;
308 }
309
310 result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_MAX_PERIOD,
311 mParams->buckets[i].max_period);
312 if (result < 0) {
313 return result;
314 }
315
316 result = request.put_u32(GSCAN_ATTRIBUTE_BUCKET_STEP_COUNT,
317 mParams->buckets[i].step_count);
318 if (result < 0) {
319 return result;
320 }
321
7753f181
DD
322 if (mParams->buckets[i].num_channels) {
323 nlattr *channels = request.attr_start(GSCAN_ATTRIBUTE_BUCKET_CHANNELS);
324 for (int j = 0; j < mParams->buckets[i].num_channels; j++) {
325 result = request.put_u32(j, mParams->buckets[i].channels[j].channel);
326 if (result < 0) {
327 return result;
328 }
329 }
330 request.attr_end(channels);
331 }
332
333 request.attr_end(bucket);
334 }
335
336 request.attr_end(data);
337 return WIFI_SUCCESS;
338 }
339
340 int createStartRequest(WifiRequest& request) {
341 return createFeatureRequest(request, SLSI_NL80211_VENDOR_SUBCMD_ADD_GSCAN);
342 }
343
344 int createStopRequest(WifiRequest& request) {
345 return createFeatureRequest(request, SLSI_NL80211_VENDOR_SUBCMD_DEL_GSCAN);
346 }
347
348 int start() {
c0b490a2 349 ALOGD("starting Gscan");
7753f181
DD
350 WifiRequest request(familyId(), ifaceId());
351 int result = createSetupRequest(request);
352 if (result != WIFI_SUCCESS) {
353 ALOGE("failed to create setup request; result = %d", result);
354 return result;
355 }
7753f181
DD
356
357 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
358 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN);
359
360 int nBuckets = 0;
361 for (int i = 0; i < mParams->num_buckets; i++) {
3ba88d77 362 if (mParams->buckets[i].report_events & REPORT_EVENTS_FULL_RESULTS) {
7753f181
DD
363 nBuckets++;
364 }
365 }
366
367 if (nBuckets != 0) {
368 ALOGI("Full scan requested with nBuckets = %d", nBuckets);
369 registerVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
370 }
371 result = requestResponse(request);
372 if (result != WIFI_SUCCESS) {
373 ALOGE("failed to start scan; result = %d", result);
374 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN);
375 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
376 return result;
377 }
378
0fe9bfaf 379
7753f181
DD
380 return result;
381 }
382
383 virtual int cancel() {
c0b490a2 384 ALOGD("Stopping Gscan");
7753f181
DD
385
386 WifiRequest request(familyId(), ifaceId());
387 int result = createStopRequest(request);
388 if (result != WIFI_SUCCESS) {
389 ALOGE("failed to create stop request; result = %d", result);
390 } else {
391 result = requestResponse(request);
392 if (result != WIFI_SUCCESS) {
393 ALOGE("failed to stop scan; result = %d", result);
394 }
395 }
396
397 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_COMPLETE_SCAN);
398 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE);
399 unregisterVendorHandler(GOOGLE_OUI, GSCAN_EVENT_FULL_SCAN_RESULTS);
400
401 return WIFI_SUCCESS;
402 }
403
404 virtual int handleResponse(WifiEvent& reply) {
405 /* Nothing to do on response! */
406 return NL_SKIP;
407 }
408
409 virtual int handleEvent(WifiEvent& event) {
d20effd2 410 //event.log();
7753f181
DD
411
412 nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
413 unsigned int len = event.get_vendor_data_len();
414 int event_id = event.get_vendor_subcmd();
7753f181
DD
415
416 if(event_id == GSCAN_EVENT_COMPLETE_SCAN) {
417 if (vendor_data == NULL || len != 4) {
9a2ccc1c 418 ALOGE("Scan complete type not mentioned!");
7753f181
DD
419 return NL_SKIP;
420 }
421 wifi_scan_event evt_type;
422
423 evt_type = (wifi_scan_event) event.get_u32(NL80211_ATTR_VENDOR_DATA);
7753f181 424 if(*mHandler.on_scan_event)
f3a9f24c 425 (*mHandler.on_scan_event)(id(), evt_type);
7753f181 426 } else if(event_id == GSCAN_EVENT_FULL_SCAN_RESULTS) {
0fe9bfaf 427 uint32_t bucket_scanned = 0;
acc9b163
JPS
428 wifi_scan_result *scan_result = NULL;
429 for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
430 if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_BUCKET_BIT) {
431 bucket_scanned = it.get_u32();
432 } else if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS) {
433 if (it.get_len() >= (int)sizeof(*scan_result))
434 scan_result = (wifi_scan_result *)it.get_data();
435 }
436 }
437 if (scan_result) {
438 if(*mHandler.on_full_scan_result)
439 (*mHandler.on_full_scan_result)(id(), scan_result, bucket_scanned);
d20effd2 440/*
acc9b163
JPS
441 ALOGD("%-32s\t", scan_result->ssid);
442 ALOGD("%02x:%02x:%02x:%02x:%02x:%02x ", scan_result->bssid[0], scan_result->bssid[1],
443 scan_result->bssid[2], scan_result->bssid[3], scan_result->bssid[4], scan_result->bssid[5]);
444 ALOGD("%d\t", scan_result->rssi);
445 ALOGD("%d\t", scan_result->channel);
446 ALOGD("%lld\t", scan_result->ts);
447 ALOGD("%lld\t", scan_result->rtt);
448 ALOGD("%lld\n", scan_result->rtt_sd);
d20effd2 449*/
7753f181 450 }
7753f181
DD
451 }
452 return NL_SKIP;
453 }
454};
455
456unsigned ScanCommand::mGlobalFullScanBuckets = 0;
457
458wifi_error wifi_start_gscan(
459 wifi_request_id id,
460 wifi_interface_handle iface,
461 wifi_scan_cmd_params params,
462 wifi_scan_result_handler handler)
463{
464 wifi_handle handle = getWifiHandle(iface);
465
7753f181
DD
466 ScanCommand *cmd = new ScanCommand(iface, id, &params, handler);
467 wifi_register_cmd(handle, id, cmd);
468 return (wifi_error)cmd->start();
469}
470
471wifi_error wifi_stop_gscan(wifi_request_id id, wifi_interface_handle iface)
472{
7753f181
DD
473 wifi_handle handle = getWifiHandle(iface);
474
475 if(id == -1) {
476 wifi_scan_result_handler handler;
477 wifi_scan_cmd_params dummy_params;
7753f181
DD
478 memset(&handler, 0, sizeof(handler));
479
480 ScanCommand *cmd = new ScanCommand(iface, id, &dummy_params, handler);
481 cmd->cancel();
482 cmd->releaseRef();
483 return WIFI_SUCCESS;
484 }
485
486
487 WifiCommand *cmd = wifi_unregister_cmd(handle, id);
488 if (cmd) {
489 cmd->cancel();
490 cmd->releaseRef();
491 return WIFI_SUCCESS;
492 }
493
494 return WIFI_ERROR_INVALID_ARGS;
495}
496
497class GetScanResultsCommand : public WifiCommand {
498 wifi_cached_scan_results *mScans;
499 int mMax;
500 int *mNum;
501 int mRetrieved;
502 byte mFlush;
503 int mCompleted;
504 static const int MAX_RESULTS = 320;
505 wifi_scan_result mScanResults[MAX_RESULTS];
506 int mNextScanResult;
507public:
508 GetScanResultsCommand(wifi_interface_handle iface, byte flush,
509 wifi_cached_scan_results *results, int max, int *num)
510 : WifiCommand(iface, -1), mScans(results), mMax(max), mNum(num),
511 mRetrieved(0), mFlush(flush), mCompleted(0)
0fe9bfaf
PG
512 {
513 memset(mScanResults,0,sizeof(mScanResults));
514 mNextScanResult = 0;
515 }
7753f181
DD
516
517 int createRequest(WifiRequest& request, int num, byte flush) {
518 int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_GET_SCAN_RESULTS);
519 if (result < 0) {
520 return result;
521 }
522
523 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
524 result = request.put_u32(GSCAN_ATTRIBUTE_NUM_OF_RESULTS, num);
525 if (result < 0) {
526 return result;
527 }
528
529 request.attr_end(data);
530 return WIFI_SUCCESS;
531 }
532
533 int execute() {
534 WifiRequest request(familyId(), ifaceId());
7753f181
DD
535
536 for (int i = 0; i < 10 && mRetrieved < mMax; i++) {
537 int result = createRequest(request, (mMax - mRetrieved), mFlush);
538 if (result < 0) {
539 ALOGE("failed to create request");
540 return result;
541 }
542
543 int prev_retrieved = mRetrieved;
544
545 result = requestResponse(request);
546
547 if (result != WIFI_SUCCESS) {
548 ALOGE("failed to retrieve scan results; result = %d", result);
549 return result;
550 }
551
552 if (mRetrieved == prev_retrieved || mCompleted) {
553 /* no more items left to retrieve */
554 break;
555 }
556
557 request.destroy();
558 }
559
560 ALOGE("GetScanResults read %d results", mRetrieved);
561 *mNum = mRetrieved;
562 return WIFI_SUCCESS;
563 }
564
565 virtual int handleResponse(WifiEvent& reply) {
7753f181
DD
566
567 if (reply.get_cmd() != NL80211_CMD_VENDOR) {
d20effd2 568 ALOGE("Ignoring reply with cmd = %d", reply.get_cmd());
7753f181
DD
569 return NL_SKIP;
570 }
571
7753f181
DD
572 nlattr *vendor_data = reply.get_attribute(NL80211_ATTR_VENDOR_DATA);
573 int len = reply.get_vendor_data_len();
574
575 if (vendor_data == NULL || len == 0) {
576 ALOGE("no vendor data in GetScanResults response; ignoring it");
577 return NL_SKIP;
578 }
579
580 for (nl_iterator it(vendor_data); it.has_next(); it.next()) {
581 if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE) {
582 mCompleted = it.get_u8();
d20effd2 583 //ALOGD("retrieved mCompleted flag : %d", mCompleted);
7753f181
DD
584 } else if (it.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS || it.get_type() == 0) {
585 int scan_id = 0, flags = 0, num = 0;
586 for (nl_iterator it2(it.get()); it2.has_next(); it2.next()) {
587 if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_ID) {
588 scan_id = it2.get_u32();
d20effd2 589 //ALOGD("retrieved scan_id : 0x%0x", scan_id);
7753f181
DD
590 } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_FLAGS) {
591 flags = it2.get_u8();
d20effd2 592 //ALOGD("retrieved scan_flags : 0x%0x", flags);
7753f181
DD
593 } else if (it2.get_type() == GSCAN_ATTRIBUTE_NUM_OF_RESULTS) {
594 num = it2.get_u32();
d20effd2 595 //ALOGD("retrieved num_results: %d", num);
7753f181
DD
596 } else if (it2.get_type() == GSCAN_ATTRIBUTE_SCAN_RESULTS) {
597 if (mRetrieved >= mMax) {
598 ALOGW("Stored %d scans, ignoring excess results", mRetrieved);
599 break;
600 }
601 num = it2.get_len() / sizeof(wifi_scan_result);
602 num = min(MAX_RESULTS - mNextScanResult, num);
603 num = min((int)MAX_AP_CACHE_PER_SCAN, num);
604 memcpy(mScanResults + mNextScanResult, it2.get_data(),
605 sizeof(wifi_scan_result) * num);
d20effd2 606 /*
8094868d 607 wifi_scan_result *results = (wifi_scan_result *)it2.get_data();
7753f181
DD
608 for (int i = 0; i < num; i++) {
609 wifi_scan_result *result = results + i;
610 ALOGD("%02d %-32s %02x:%02x:%02x:%02x:%02x:%02x %04d", i,
611 result->ssid, result->bssid[0], result->bssid[1], result->bssid[2],
612 result->bssid[3], result->bssid[4], result->bssid[5],
613 result->rssi);
d20effd2 614 }*/
7753f181
DD
615 mScans[mRetrieved].scan_id = scan_id;
616 mScans[mRetrieved].flags = flags;
617 mScans[mRetrieved].num_results = num;
d20effd2 618 //ALOGD("Setting result of scan_id : 0x%0x", mScans[mRetrieved].scan_id);
7753f181
DD
619 memcpy(mScans[mRetrieved].results,
620 &(mScanResults[mNextScanResult]), num * sizeof(wifi_scan_result));
621 mNextScanResult += num;
622 mRetrieved++;
623 } else {
624 ALOGW("Ignoring invalid attribute type = %d, size = %d",
625 it.get_type(), it.get_len());
626 }
627 }
628 } else {
629 ALOGW("Ignoring invalid attribute type = %d, size = %d",
630 it.get_type(), it.get_len());
631 }
632 }
633
634 return NL_OK;
635 }
636};
637
638wifi_error wifi_get_cached_gscan_results(wifi_interface_handle iface, byte flush,
639 int max, wifi_cached_scan_results *results, int *num) {
7753f181
DD
640 GetScanResultsCommand *cmd = new GetScanResultsCommand(iface, flush, results, max, num);
641 return (wifi_error)cmd->execute();
642}
643
644/////////////////////////////////////////////////////////////////////////////
6ff2d683
JPS
645class ePNOCommand : public WifiCommand
646{
647private:
c15187c1 648 wifi_epno_params *epno_params;
6ff2d683
JPS
649 wifi_epno_handler mHandler;
650 wifi_scan_result mResults;
651public:
652 ePNOCommand(wifi_interface_handle handle, int id,
c15187c1 653 wifi_epno_params *params, wifi_epno_handler handler)
6ff2d683
JPS
654 : WifiCommand(handle, id), mHandler(handler)
655 {
c15187c1 656 epno_params = params;
0fe9bfaf 657 memset(&mResults,0,sizeof(wifi_scan_result));
6ff2d683
JPS
658 }
659
660 int createSetupRequest(WifiRequest& request) {
661 int result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_EPNO_LIST);
662 if (result < 0) {
663 return result;
664 }
665
666 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
c15187c1
JPS
667 if (epno_params == NULL) {
668 result = request.put_u8(EPNO_ATTRIBUTE_SSID_NUM, 0);
669 if (result < 0) {
670 return result;
671 }
672 request.attr_end(data);
673 return result;
674 }
1fc70afb
MG
675 result = request.put_u16(EPNO_ATTRIBUTE_MINIMUM_5G_RSSI, epno_params->min5GHz_rssi);
676 if (result < 0) {
677 return result;
678 }
679 result = request.put_u16(EPNO_ATTRIBUTE_MINIMUM_2G_RSSI, epno_params->min24GHz_rssi);
680 if (result < 0) {
681 return result;
682 }
683 result = request.put_u16(EPNO_ATTRIBUTE_INITIAL_SCORE_MAX, epno_params->initial_score_max);
684 if (result < 0) {
685 return result;
686 }
687 result = request.put_u8(EPNO_ATTRIBUTE_CUR_CONN_BONUS, epno_params->current_connection_bonus);
688 if (result < 0) {
689 return result;
690 }
691 result = request.put_u8(EPNO_ATTRIBUTE_SAME_NETWORK_BONUS, epno_params->same_network_bonus);
692 if (result < 0) {
693 return result;
694 }
695 result = request.put_u8(EPNO_ATTRIBUTE_SECURE_BONUS, epno_params->secure_bonus);
696 if (result < 0) {
697 return result;
698 }
699 result = request.put_u8(EPNO_ATTRIBUTE_5G_BONUS, epno_params->band5GHz_bonus);
700 if (result < 0) {
701 return result;
702 }
c15187c1 703 result = request.put_u8(EPNO_ATTRIBUTE_SSID_NUM, epno_params->num_networks);
6ff2d683
JPS
704 if (result < 0) {
705 return result;
706 }
707
1fc70afb 708 ALOGI("ePNO [min5GHz_rssi:%d min24GHz_rssi:%d initial_score_max:%d current_connection_bonus:%d same_network_bonus:%d secure_bonus:%d band5GHz_bonus:%d num_networks:%d]",
c0b490a2
JPS
709 epno_params->min5GHz_rssi,
710 epno_params->min24GHz_rssi,
711 epno_params->initial_score_max,
712 epno_params->current_connection_bonus,
713 epno_params->same_network_bonus,
714 epno_params->secure_bonus,
715 epno_params->band5GHz_bonus,
716 epno_params->num_networks);
1fc70afb 717
6ff2d683 718 struct nlattr * attr = request.attr_start(EPNO_ATTRIBUTE_SSID_LIST);
c15187c1 719 for (int i = 0; i < epno_params->num_networks; i++) {
6ff2d683
JPS
720 nlattr *attr2 = request.attr_start(i);
721 if (attr2 == NULL) {
722 return WIFI_ERROR_OUT_OF_MEMORY;
723 }
1fc70afb 724 result = request.put_u16(EPNO_ATTRIBUTE_FLAGS, epno_params->networks[i].flags);
6ff2d683
JPS
725 if (result < 0) {
726 return result;
727 }
1fc70afb 728 result = request.put_u8(EPNO_ATTRIBUTE_AUTH, epno_params->networks[i].auth_bit_field);
6ff2d683
JPS
729 if (result < 0) {
730 return result;
731 }
1fc70afb 732 result = request.put_u8(EPNO_ATTRIBUTE_SSID_LEN, strlen(epno_params->networks[i].ssid));
6ff2d683
JPS
733 if (result < 0) {
734 return result;
735 }
1fc70afb 736 result = request.put(EPNO_ATTRIBUTE_SSID, epno_params->networks[i].ssid, strlen(epno_params->networks[i].ssid));
6ff2d683
JPS
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 start() {
c15187c1 749 ALOGI("ePNO num_network=%d", epno_params ? epno_params->num_networks : 0);
6ff2d683
JPS
750 WifiRequest request(familyId(), ifaceId());
751 int result = createSetupRequest(request);
752 if (result < 0) {
753 return result;
754 }
755
756 result = requestResponse(request);
757 if (result < 0) {
758 ALOGI("Failed: ePNO setup request, result = %d", result);
759 unregisterVendorHandler(GOOGLE_OUI, WIFI_EPNO_EVENT);
760 return result;
761 }
762
c15187c1 763 if (epno_params) {
c15187c1 764 registerVendorHandler(GOOGLE_OUI, WIFI_EPNO_EVENT);
c15187c1 765 }
6ff2d683
JPS
766 return result;
767 }
768
769 virtual int cancel() {
770 /* unregister event handler */
771 unregisterVendorHandler(GOOGLE_OUI, WIFI_EPNO_EVENT);
772 return 0;
773 }
774
775 virtual int handleResponse(WifiEvent& reply) {
776 /* Nothing to do on response! */
777 return NL_SKIP;
778 }
779
780 virtual int handleEvent(WifiEvent& event) {
6ff2d683
JPS
781 // event.log();
782
783 nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
784 int len = event.get_vendor_data_len();
785
786 if (vendor_data == NULL || len == 0) {
787 ALOGI("No scan results found");
788 return NL_SKIP;
789 }
790
0fe9bfaf 791
6ff2d683
JPS
792 mResults = *(wifi_scan_result *) event.get_vendor_data();
793 if (*mHandler.on_network_found)
794 (*mHandler.on_network_found)(id(), 1, &mResults);
795 return NL_SKIP;
796 }
797};
798
799wifi_error wifi_set_epno_list(wifi_request_id id,
800 wifi_interface_handle iface,
c15187c1 801 const wifi_epno_params *epno_params,
6ff2d683
JPS
802 wifi_epno_handler handler)
803{
c15187c1 804 wifi_handle handle = getWifiHandle(iface);
c15187c1
JPS
805 ePNOCommand *cmd = new ePNOCommand(iface, id, (wifi_epno_params *)epno_params, handler);
806 wifi_register_cmd(handle, id, cmd);
807 wifi_error result = (wifi_error)cmd->start();
808 if (result != WIFI_SUCCESS) {
809 wifi_unregister_cmd(handle, id);
810 }
811 return result;
812}
813
814wifi_error wifi_reset_epno_list(wifi_request_id id, wifi_interface_handle iface)
815{
816 wifi_handle handle = getWifiHandle(iface);
817 wifi_epno_handler handler;
818
819 handler.on_network_found = NULL;
820 ePNOCommand *cmd = new ePNOCommand(iface, id, NULL, handler);
821 wifi_register_cmd(handle, id, cmd);
822 wifi_error result = (wifi_error)cmd->start();
823 if (result != WIFI_SUCCESS) {
824 wifi_unregister_cmd(handle, id);
825 }
826 return result;
6ff2d683
JPS
827}
828
829class HsListCommand : public WifiCommand
830{
831 int num_hs;
832 wifi_passpoint_network *mNetworks;
833 wifi_passpoint_event_handler mHandler;
834public:
835 HsListCommand(wifi_request_id id, wifi_interface_handle iface,
836 int num, wifi_passpoint_network *hs_list, wifi_passpoint_event_handler handler)
837 : WifiCommand(iface, id), num_hs(num), mNetworks(hs_list),
838 mHandler(handler)
839 {
840 }
841
842 HsListCommand(wifi_request_id id, wifi_interface_handle iface,
843 int num)
844 : WifiCommand(iface, id), num_hs(num), mNetworks(NULL)
845 {
0fe9bfaf 846 mHandler.on_passpoint_network_found = NULL;
6ff2d683
JPS
847 }
848
849 int createRequest(WifiRequest& request, int val) {
850 int result;
851
852 if (val) {
853 result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_SET_HS_LIST);
854 result = request.put_u32(EPNO_ATTRIBUTE_HS_NUM, num_hs);
855 if (result < 0) {
856 return result;
857 }
858 nlattr *data = request.attr_start(NL80211_ATTR_VENDOR_DATA);
859
860 struct nlattr * attr = request.attr_start(EPNO_ATTRIBUTE_HS_PARAM_LIST);
861 for (int i = 0; i < num_hs; i++) {
862 nlattr *attr2 = request.attr_start(i);
863 if (attr2 == NULL) {
864 return WIFI_ERROR_OUT_OF_MEMORY;
865 }
866 result = request.put_u32(EPNO_ATTRIBUTE_HS_ID, mNetworks[i].id);
867 if (result < 0) {
868 return result;
869 }
870 result = request.put(EPNO_ATTRIBUTE_HS_REALM, mNetworks[i].realm, 256);
871 if (result < 0) {
872 return result;
873 }
874 result = request.put(EPNO_ATTRIBUTE_HS_CONSORTIUM_IDS, mNetworks[i].roamingConsortiumIds, 128);
875 if (result < 0) {
876 return result;
877 }
878 result = request.put(EPNO_ATTRIBUTE_HS_PLMN, mNetworks[i].plmn, 3);
879 if (result < 0) {
880 return result;
881 }
882 request.attr_end(attr2);
883 }
884 request.attr_end(attr);
885 request.attr_end(data);
886 }else {
887 result = request.create(GOOGLE_OUI, SLSI_NL80211_VENDOR_SUBCMD_RESET_HS_LIST);
888 if (result < 0) {
889 return result;
890 }
891 }
892
893 return WIFI_SUCCESS;
894 }
895
896 int start() {
897
898 WifiRequest request(familyId(), ifaceId());
899 int result = createRequest(request, num_hs);
900 if (result != WIFI_SUCCESS) {
901 ALOGE("failed to create request; result = %d", result);
902 return result;
903 }
904
905 registerVendorHandler(GOOGLE_OUI, WIFI_HOTSPOT_MATCH);
906
907 result = requestResponse(request);
908 if (result != WIFI_SUCCESS) {
909 ALOGE("failed to set ANQPO networks; result = %d", result);
910 unregisterVendorHandler(GOOGLE_OUI, WIFI_HOTSPOT_MATCH);
911 return result;
912 }
913
914 return result;
915 }
916
917 virtual int cancel() {
918
919 WifiRequest request(familyId(), ifaceId());
920 int result = createRequest(request, 0);
921 if (result != WIFI_SUCCESS) {
922 ALOGE("failed to create request; result = %d", result);
923 } else {
924 result = requestResponse(request);
925 if (result != WIFI_SUCCESS) {
926 ALOGE("failed to reset ANQPO networks;result = %d", result);
927 }
928 }
929
930 unregisterVendorHandler(GOOGLE_OUI, WIFI_HOTSPOT_MATCH);
931 return WIFI_SUCCESS;
932 }
933
934 virtual int handleResponse(WifiEvent& reply) {
6ff2d683
JPS
935 /* Nothing to do on response! */
936 return NL_SKIP;
937 }
938
939 virtual int handleEvent(WifiEvent& event) {
6ff2d683
JPS
940 nlattr *vendor_data = event.get_attribute(NL80211_ATTR_VENDOR_DATA);
941 unsigned int len = event.get_vendor_data_len();
942 if (vendor_data == NULL || len < sizeof(wifi_scan_result)) {
943 ALOGE("ERROR: No scan results found");
944 return NL_SKIP;
945 }
946
947 wifi_scan_result *result = (wifi_scan_result *)event.get_vendor_data();
948 byte *anqp = (byte *)result + offsetof(wifi_scan_result, ie_data) + result->ie_length;
949 int networkId = *(int *)anqp;
950 anqp += sizeof(int);
951 int anqp_len = *(u16 *)anqp;
952 anqp += sizeof(u16);
953
6ff2d683
JPS
954 if(*mHandler.on_passpoint_network_found)
955 (*mHandler.on_passpoint_network_found)(id(), networkId, result, anqp_len, anqp);
956
957 return NL_SKIP;
958 }
959};
960
961wifi_error wifi_set_passpoint_list(wifi_request_id id, wifi_interface_handle iface, int num,
962 wifi_passpoint_network *networks, wifi_passpoint_event_handler handler)
963{
964 wifi_handle handle = getWifiHandle(iface);
965 HsListCommand *cmd = new HsListCommand(id, iface, num, networks, handler);
966
967 wifi_register_cmd(handle, id, cmd);
968 wifi_error result = (wifi_error)cmd->start();
969 if (result != WIFI_SUCCESS) {
970 wifi_unregister_cmd(handle, id);
971 }
972 return result;
973}
974
975wifi_error wifi_reset_passpoint_list(wifi_request_id id, wifi_interface_handle iface)
976{
977 wifi_handle handle = getWifiHandle(iface);
978 wifi_error result;
979 HsListCommand *cmd = (HsListCommand *)(wifi_get_cmd(handle, id));
980
981 if (cmd == NULL) {
982 cmd = new HsListCommand(id, iface, 0);
983 wifi_register_cmd(handle, id, cmd);
984 }
985 result = (wifi_error)cmd->cancel();
986 wifi_unregister_cmd(handle, id);
987 return result;
988}