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