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>
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>
21 #define LOG_TAG "WifiHAL"
23 #include <utils/Log.h>
27 #include "cpp_bindings.h"
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
,
43 GSCAN_ATTRIBUTE_ENABLE_FEATURE
= 20,
44 GSCAN_ATTRIBUTE_SCAN_RESULTS_COMPLETE
, /* indicates no more results */
45 GSCAN_ATTRIBUTE_REPORT_EVENTS
,
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
,
53 /* remaining reserved for additional attributes */
55 GSCAN_ATTRIBUTE_SSID
= 40,
56 GSCAN_ATTRIBUTE_BSSID
,
57 GSCAN_ATTRIBUTE_CHANNEL
,
59 GSCAN_ATTRIBUTE_TIMESTAMP
,
61 GSCAN_ATTRIBUTE_RTTSD
,
63 /* remaining reserved for additional attributes */
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
,
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
,
83 class GetCapabilitiesCommand
: public WifiCommand
85 wifi_gscan_capabilities
*mCapabilities
;
87 GetCapabilitiesCommand(wifi_interface_handle iface
, wifi_gscan_capabilities
*capabitlites
)
88 : WifiCommand(iface
, 0), mCapabilities(capabitlites
)
90 memset(mCapabilities
, 0, sizeof(*mCapabilities
));
93 virtual int create() {
94 ALOGD("Creating message to get scan capablities; iface = %d", mIfaceInfo
->id
);
96 int ret
= mMsg
.create(GOOGLE_OUI
, SLSI_NL80211_VENDOR_SUBCMD_GET_CAPABILITIES
);
98 ALOGD("NL message creation failed");
106 virtual int handleResponse(WifiEvent
& reply
) {
108 ALOGD("In GetCapabilities::handleResponse");
110 if (reply
.get_cmd() != NL80211_CMD_VENDOR
) {
111 ALOGD("Ignoring reply with cmd = %d", reply
.get_cmd());
115 int id
= reply
.get_vendor_id();
116 int subcmd
= reply
.get_vendor_subcmd();
118 void *data
= reply
.get_vendor_data();
119 int len
= reply
.get_vendor_data_len();
121 ALOGD("Id = %0x, subcmd = %d, len = %d, expected len = %d", id
, subcmd
, len
,
122 sizeof(*mCapabilities
));
124 memcpy(mCapabilities
, data
, min(len
, (int) sizeof(*mCapabilities
)));
131 wifi_error
wifi_get_gscan_capabilities(wifi_interface_handle handle
,
132 wifi_gscan_capabilities
*capabilities
)
134 GetCapabilitiesCommand
command(handle
, capabilities
);
135 return (wifi_error
) command
.requestResponse();
138 class GetChannelListCommand
: public WifiCommand
140 wifi_channel
*channels
;
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
),
150 memset(channels
, 0, sizeof(wifi_channel
) * max_channels
);
152 virtual int create() {
153 ALOGD("Creating message to get channel list; iface = %d", mIfaceInfo
->id
);
155 int ret
= mMsg
.create(GOOGLE_OUI
, SLSI_NL80211_VENDOR_SUBCMD_GET_VALID_CHANNELS
);
160 nlattr
*data
= mMsg
.attr_start(NL80211_ATTR_VENDOR_DATA
);
161 ret
= mMsg
.put_u32(GSCAN_ATTRIBUTE_BAND
, band
);
172 virtual int handleResponse(WifiEvent
& reply
) {
174 ALOGD("In GetChannelList::handleResponse");
176 if (reply
.get_cmd() != NL80211_CMD_VENDOR
) {
177 ALOGD("Ignoring reply with cmd = %d", reply
.get_cmd());
181 int id
= reply
.get_vendor_id();
182 int subcmd
= reply
.get_vendor_subcmd();
183 int num_channels_to_copy
= 0;
185 nlattr
*vendor_data
= reply
.get_attribute(NL80211_ATTR_VENDOR_DATA
);
186 int len
= reply
.get_vendor_data_len();
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");
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
);
204 ALOGW("Ignoring invalid attribute type = %d, size = %d",
205 it
.get_type(), it
.get_len());
213 wifi_error
wifi_get_valid_channels(wifi_interface_handle handle
,
214 int band
, int max_channels
, wifi_channel
*channels
, int *num_channels
)
216 GetChannelListCommand
command(handle
, channels
, num_channels
,
218 return (wifi_error
) command
.requestResponse();
220 /////////////////////////////////////////////////////////////////////////////
222 /* helper functions */
224 static int parseScanResults(wifi_scan_result
*results
, int num
, nlattr
*attr
)
226 memset(results
, 0, sizeof(wifi_scan_result
) * num
);
229 for (nl_iterator
it(attr
); it
.has_next() && i
< num
; it
.next(), i
++) {
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
;
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();
259 ALOGE("Got too many results; skipping some");
265 int createFeatureRequest(WifiRequest
& request
, int subcmd
) {
267 int result
= request
.create(GOOGLE_OUI
, subcmd
);
275 class ScanCommand
: public WifiCommand
277 wifi_scan_cmd_params
*mParams
;
278 wifi_scan_result_handler mHandler
;
279 static unsigned mGlobalFullScanBuckets
;
280 bool mLocalFullScanBuckets
;
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)
288 int createSetupRequest(WifiRequest
& request
) {
289 int result
= request
.create(GOOGLE_OUI
, SLSI_NL80211_VENDOR_SUBCMD_ADD_GSCAN
);
294 nlattr
*data
= request
.attr_start(NL80211_ATTR_VENDOR_DATA
);
295 result
= request
.put_u32(GSCAN_ATTRIBUTE_BASE_PERIOD
, mParams
->base_period
);
300 result
= request
.put_u32(GSCAN_ATTRIBUTE_NUM_AP_PER_SCAN
, mParams
->max_ap_per_scan
);
305 result
= request
.put_u32(GSCAN_ATTRIBUTE_REPORT_THRESHOLD
, mParams
->report_threshold_percent
);
310 result
= request
.put_u32(GSCAN_ATTRIBUTE_NUM_BUCKETS
, mParams
->num_buckets
);
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
);
321 result
= request
.put_u32(GSCAN_ATTRIBUTE_BUCKET_PERIOD
, mParams
->buckets
[i
].period
);
325 result
= request
.put_u32(GSCAN_ATTRIBUTE_BUCKETS_BAND
,
326 mParams
->buckets
[i
].band
);
331 result
= request
.put_u32(GSCAN_ATTRIBUTE_REPORT_EVENTS
,
332 mParams
->buckets
[i
].report_events
);
337 result
= request
.put_u32(GSCAN_ATTRIBUTE_BUCKET_NUM_CHANNELS
,
338 mParams
->buckets
[i
].num_channels
);
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
);
351 request
.attr_end(channels
);
354 request
.attr_end(bucket
);
357 request
.attr_end(data
);
361 int createStartRequest(WifiRequest
& request
) {
362 return createFeatureRequest(request
, SLSI_NL80211_VENDOR_SUBCMD_ADD_GSCAN
);
365 int createStopRequest(WifiRequest
& request
) {
366 return createFeatureRequest(request
, SLSI_NL80211_VENDOR_SUBCMD_DEL_GSCAN
);
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
);
377 ALOGD("Starting scan");
379 registerVendorHandler(GOOGLE_OUI
, GSCAN_EVENT_SCAN_RESULTS_AVAILABLE
);
380 registerVendorHandler(GOOGLE_OUI
, GSCAN_EVENT_COMPLETE_SCAN
);
383 for (int i
= 0; i
< mParams
->num_buckets
; i
++) {
384 if (mParams
->buckets
[i
].report_events
== 2) {
390 ALOGI("Full scan requested with nBuckets = %d", nBuckets
);
391 registerVendorHandler(GOOGLE_OUI
, GSCAN_EVENT_FULL_SCAN_RESULTS
);
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
);
405 virtual int cancel() {
406 ALOGD("Stopping scan");
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
);
413 result
= requestResponse(request
);
414 if (result
!= WIFI_SUCCESS
) {
415 ALOGE("failed to stop scan; result = %d", result
);
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
);
426 virtual int handleResponse(WifiEvent
& reply
) {
427 /* Nothing to do on response! */
431 virtual int handleEvent(WifiEvent
& event
) {
432 ALOGD("Got a scan results event");
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
);
441 if(event_id
== GSCAN_EVENT_COMPLETE_SCAN
) {
442 if (vendor_data
== NULL
|| len
!= 4) {
443 ALOGD("Scan complete type not mentioned!");
446 wifi_scan_event evt_type
;
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");
457 wifi_scan_result
*result
= (wifi_scan_result
*)event
.get_vendor_data();
459 if(*mHandler
.on_full_scan_result
)
460 (*mHandler
.on_full_scan_result
)(id(), result
);
462 ALOGD("%-32s\t", result
->ssid
);
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]);
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
);
474 if (vendor_data
== NULL
|| len
!= 4) {
475 ALOGD("No scan results found");
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
);
488 unsigned ScanCommand::mGlobalFullScanBuckets
= 0;
490 wifi_error
wifi_start_gscan(
492 wifi_interface_handle iface
,
493 wifi_scan_cmd_params params
,
494 wifi_scan_result_handler handler
)
496 wifi_handle handle
= getWifiHandle(iface
);
498 ALOGD("Starting GScan, halHandle = %p", handle
);
500 ScanCommand
*cmd
= new ScanCommand(iface
, id
, ¶ms
, handler
);
501 wifi_register_cmd(handle
, id
, cmd
);
502 return (wifi_error
)cmd
->start();
505 wifi_error
wifi_stop_gscan(wifi_request_id id
, wifi_interface_handle iface
)
507 ALOGD("Stopping GScan");
508 wifi_handle handle
= getWifiHandle(iface
);
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
));
516 ScanCommand
*cmd
= new ScanCommand(iface
, id
, &dummy_params
, handler
);
523 WifiCommand
*cmd
= wifi_unregister_cmd(handle
, id
);
530 return WIFI_ERROR_INVALID_ARGS
;
533 class GetScanResultsCommand
: public WifiCommand
{
534 wifi_cached_scan_results
*mResults
;
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)
547 int createRequest(WifiRequest
& request
, int num
, byte flush
) {
548 int result
= request
.create(GOOGLE_OUI
, SLSI_NL80211_VENDOR_SUBCMD_GET_SCAN_RESULTS
);
553 nlattr
*data
= request
.attr_start(NL80211_ATTR_VENDOR_DATA
);
554 result
= request
.put_u32(GSCAN_ATTRIBUTE_NUM_OF_RESULTS
, num
);
559 request
.attr_end(data
);
564 WifiRequest
request(familyId(), ifaceId());
565 ALOGD("retrieving %d scan results", mMax
);
567 for (int i
= 0; i
< 10 && mRetrieved
< mMax
; i
++) {
568 int result
= createRequest(request
, (mMax
- mRetrieved
), mFlush
);
570 ALOGE("failed to create request");
574 int prev_retrieved
= mRetrieved
;
576 result
= requestResponse(request
);
578 if (result
!= WIFI_SUCCESS
) {
579 ALOGE("failed to retrieve scan results; result = %d", result
);
583 if (mRetrieved
== prev_retrieved
|| mCompleted
) {
584 /* no more items left to retrieve */
591 ALOGE("GetScanResults read %d results", mRetrieved
);
596 virtual int handleResponse(WifiEvent
& reply
) {
597 ALOGD("In GetScanResultsCommand::handleResponse");
599 if (reply
.get_cmd() != NL80211_CMD_VENDOR
) {
600 ALOGD("Ignoring reply with cmd = %d", reply
.get_cmd());
604 int id
= reply
.get_vendor_id();
605 int subcmd
= reply
.get_vendor_subcmd();
607 ALOGD("Id = %0x, subcmd = %d", id
, subcmd
);
609 nlattr
*vendor_data
= reply
.get_attribute(NL80211_ATTR_VENDOR_DATA
);
610 int len
= reply
.get_vendor_data_len();
612 if (vendor_data
== NULL
|| len
== 0) {
613 ALOGE("no vendor data in GetScanResults response; ignoring it");
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()) {
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],
640 ALOGW("Ignoring invalid attribute type = %d, size = %d",
641 it
.get_type(), it
.get_len());
645 ALOGW("Ignoring invalid attribute type = %d, size = %d",
646 it
.get_type(), it
.get_len());
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
);
658 GetScanResultsCommand
*cmd
= new GetScanResultsCommand(iface
, flush
, results
, max
, num
);
659 return (wifi_error
)cmd
->execute();
662 /////////////////////////////////////////////////////////////////////////////
664 class BssidHotlistCommand
: public WifiCommand
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
];
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
)
677 int createSetupRequest(WifiRequest
& request
) {
678 int result
= request
.create(GOOGLE_OUI
, SLSI_NL80211_VENDOR_SUBCMD_SET_BSSID_HOTLIST
);
683 nlattr
*data
= request
.attr_start(NL80211_ATTR_VENDOR_DATA
);
685 result
= request
.put_u32(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE
, mParams
.lost_ap_sample_size
);
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
);
694 return WIFI_ERROR_OUT_OF_MEMORY
;
696 result
= request
.put_addr(GSCAN_ATTRIBUTE_BSSID
, mParams
.ap
[i
].bssid
);
700 result
= request
.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH
, mParams
.ap
[i
].high
);
704 result
= request
.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW
, mParams
.ap
[i
].low
);
708 request
.attr_end(attr2
);
711 request
.attr_end(attr
);
712 request
.attr_end(data
);
716 int createTeardownRequest(WifiRequest
& request
) {
717 int result
= request
.create(GOOGLE_OUI
, SLSI_NL80211_VENDOR_SUBCMD_RESET_BSSID_HOTLIST
);
726 ALOGD("Executing hotlist setup request, num = %d", mParams
.num_bssid
);
727 WifiRequest
request(familyId(), ifaceId());
728 int result
= createSetupRequest(request
);
733 result
= requestResponse(request
);
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
);
741 ALOGD("Successfully set %d APs in the hotlist", mParams
.num_bssid
);
743 registerVendorHandler(GOOGLE_OUI
, GSCAN_EVENT_HOTLIST_RESULTS_FOUND
);
744 registerVendorHandler(GOOGLE_OUI
, GSCAN_EVENT_HOTLIST_RESULTS_LOST
);
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
);
760 result
= requestResponse(request
);
765 ALOGD("Successfully reset APs in current hotlist");
769 virtual int handleResponse(WifiEvent
& reply
) {
770 /* Nothing to do on response! */
774 virtual int handleEvent(WifiEvent
& event
) {
775 ALOGD("Hotlist AP event");
776 int event_id
= event
.get_vendor_subcmd();
779 nlattr
*vendor_data
= event
.get_attribute(NL80211_ATTR_VENDOR_DATA
);
780 int len
= event
.get_vendor_data_len();
782 if (vendor_data
== NULL
|| len
== 0) {
783 ALOGD("No scan results found");
787 memset(mResults
, 0, sizeof(wifi_scan_result
) * MAX_RESULTS
);
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
));
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
);
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
)
809 wifi_handle handle
= getWifiHandle(iface
);
811 BssidHotlistCommand
*cmd
= new BssidHotlistCommand(iface
, id
, params
, handler
);
812 wifi_register_cmd(handle
, id
, cmd
);
813 return (wifi_error
)cmd
->start();
816 wifi_error
wifi_reset_bssid_hotlist(wifi_request_id id
, wifi_interface_handle iface
)
818 wifi_handle handle
= getWifiHandle(iface
);
820 WifiCommand
*cmd
= wifi_unregister_cmd(handle
, id
);
827 return WIFI_ERROR_INVALID_ARGS
;
831 /////////////////////////////////////////////////////////////////////////////
833 class SignificantWifiChangeCommand
: public WifiCommand
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
;
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
];
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
)
854 int createSetupRequest(WifiRequest
& request
) {
855 int result
= request
.create(GOOGLE_OUI
, SLSI_NL80211_VENDOR_SUBCMD_SET_SIGNIFICANT_CHANGE
);
860 nlattr
*data
= request
.attr_start(NL80211_ATTR_VENDOR_DATA
);
862 result
= request
.put_u16(GSCAN_ATTRIBUTE_RSSI_SAMPLE_SIZE
, mParams
.rssi_sample_size
);
866 result
= request
.put_u16(GSCAN_ATTRIBUTE_LOST_AP_SAMPLE_SIZE
, mParams
.lost_ap_sample_size
);
870 result
= request
.put_u16(GSCAN_ATTRIBUTE_MIN_BREACHING
, mParams
.min_breaching
);
875 struct nlattr
* attr
= request
.attr_start(GSCAN_ATTRIBUTE_SIGNIFICANT_CHANGE_BSSIDS
);
877 for (int i
= 0; i
< mParams
.num_bssid
; i
++) {
879 nlattr
*attr2
= request
.attr_start(i
);
881 return WIFI_ERROR_OUT_OF_MEMORY
;
883 result
= request
.put_addr(GSCAN_ATTRIBUTE_BSSID
, mParams
.ap
[i
].bssid
);
887 result
= request
.put_u8(GSCAN_ATTRIBUTE_RSSI_HIGH
, mParams
.ap
[i
].high
);
891 result
= request
.put_u8(GSCAN_ATTRIBUTE_RSSI_LOW
, mParams
.ap
[i
].low
);
895 request
.attr_end(attr2
);
898 request
.attr_end(attr
);
899 request
.attr_end(data
);
904 int createTeardownRequest(WifiRequest
& request
) {
905 int result
= request
.create(GOOGLE_OUI
, SLSI_NL80211_VENDOR_SUBCMD_RESET_SIGNIFICANT_CHANGE
);
914 ALOGD("Set significant wifi change");
915 WifiRequest
request(familyId(), ifaceId());
917 int result
= createSetupRequest(request
);
922 result
= requestResponse(request
);
924 ALOGD("failed to set significant wifi change %d", result
);
927 registerVendorHandler(GOOGLE_OUI
, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS
);
932 virtual int cancel() {
933 /* unregister event handler */
934 unregisterVendorHandler(GOOGLE_OUI
, GSCAN_EVENT_SIGNIFICANT_CHANGE_RESULTS
);
936 /* create set significant change monitor message with empty hotlist */
937 WifiRequest
request(familyId(), ifaceId());
939 int result
= createTeardownRequest(request
);
944 result
= requestResponse(request
);
949 ALOGD("successfully reset significant wifi change");
953 virtual int handleResponse(WifiEvent
& reply
) {
954 /* Nothing to do on response! */
958 virtual int handleEvent(WifiEvent
& event
) {
959 ALOGD("Got a significant wifi change event");
961 nlattr
*vendor_data
= event
.get_attribute(NL80211_ATTR_VENDOR_DATA
);
962 int len
= event
.get_vendor_data_len();
964 if (vendor_data
== NULL
|| len
== 0) {
965 ALOGD("No scan results found");
972 int16_t rssi_history
[8];
975 int num
= min(len
/ sizeof(ChangeInfo
), MAX_RESULTS
);
976 ChangeInfo
*ci
= (ChangeInfo
*)event
.get_vendor_data();
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. */
984 for (int j
= 0; j
< 8; j
++) {
985 if (ci
[i
].rssi_history
[j
] == 0x7FFF) {
989 mResultsBuffer
[i
].rssi
[j
] = (int) ci
[i
].rssi_history
[j
];
991 mResultsBuffer
[i
].num_rssi
= num_rssi
;
992 mResults
[i
] = reinterpret_cast<wifi_significant_change_result
*>(&(mResultsBuffer
[i
]));
995 ALOGD("Retrieved %d scan results", num
);
998 (*mHandler
.on_significant_change
)(id(), num
, mResults
);
1000 ALOGW("No significant change reported");
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
)
1010 wifi_handle handle
= getWifiHandle(iface
);
1012 SignificantWifiChangeCommand
*cmd
= new SignificantWifiChangeCommand(
1013 iface
, id
, params
, handler
);
1014 wifi_register_cmd(handle
, id
, cmd
);
1015 return (wifi_error
)cmd
->start();
1018 wifi_error
wifi_reset_significant_change_handler(wifi_request_id id
, wifi_interface_handle iface
)
1020 wifi_handle handle
= getWifiHandle(iface
);
1022 WifiCommand
*cmd
= wifi_unregister_cmd(handle
, id
);
1026 return WIFI_SUCCESS
;
1029 return WIFI_ERROR_INVALID_ARGS
;