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