|
1 /* |
|
2 * Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * ST-Ericsson |
|
14 * |
|
15 * Description: Statemachine for scanning |
|
16 * |
|
17 */ |
|
18 |
|
19 |
|
20 #include "core_operation_scan.h" |
|
21 #include "core_server.h" |
|
22 #include "core_tools.h" |
|
23 #include "core_frame_beacon.h" |
|
24 #include "core_scan_list.h" |
|
25 #include "am_debug.h" |
|
26 |
|
27 // ======== MEMBER FUNCTIONS ======== |
|
28 |
|
29 // --------------------------------------------------------------------------- |
|
30 // --------------------------------------------------------------------------- |
|
31 // |
|
32 core_operation_scan_c::core_operation_scan_c( |
|
33 u32_t request_id, |
|
34 core_server_c* server, |
|
35 abs_core_driverif_c* drivers, |
|
36 abs_core_server_callback_c* adaptation, |
|
37 core_scan_mode_e scan_mode, |
|
38 const core_ssid_s& scan_ssid, |
|
39 const core_scan_channels_s& scan_channels, |
|
40 u8_t scan_max_age, |
|
41 ScanList& scan_data, |
|
42 bool_t passive_scan_all_channels, |
|
43 bool_t is_current_ap_added ) : |
|
44 core_operation_base_c( core_operation_scan, request_id, server, drivers, adaptation, |
|
45 core_base_flag_drivers_needed ), |
|
46 scan_mode_m( scan_mode ), |
|
47 scan_ssid_m( scan_ssid ), |
|
48 scan_channels_m( scan_channels ), |
|
49 scan_max_age_m( scan_max_age ), |
|
50 scan_data_m( scan_data ), |
|
51 passive_scan_all_channels_m( passive_scan_all_channels ), |
|
52 region_from_ap_m( core_wlan_region_fcc ), |
|
53 is_current_ap_added_m( is_current_ap_added ), |
|
54 current_rcpi_m( 0 ) |
|
55 { |
|
56 DEBUG( "core_operation_scan_c::core_operation_scan_c()" ); |
|
57 } |
|
58 |
|
59 // --------------------------------------------------------------------------- |
|
60 // --------------------------------------------------------------------------- |
|
61 // |
|
62 core_operation_scan_c::~core_operation_scan_c() |
|
63 { |
|
64 DEBUG( "core_operation_scan_c::~core_operation_scan_c()" ); |
|
65 |
|
66 server_m->unregister_event_handler( this ); |
|
67 server_m->unregister_frame_handler( this ); |
|
68 } |
|
69 |
|
70 // --------------------------------------------------------------------------- |
|
71 // --------------------------------------------------------------------------- |
|
72 // |
|
73 core_error_e core_operation_scan_c::next_state() |
|
74 { |
|
75 DEBUG( "core_operation_scan_c::next_state()" ); |
|
76 |
|
77 switch ( operation_state_m ) |
|
78 { |
|
79 case core_state_init: |
|
80 { |
|
81 operation_state_m = core_state_scan_start; |
|
82 |
|
83 u32_t min_ch_time( server_m->get_device_settings().active_scan_min_ch_time ); |
|
84 u32_t max_ch_time( server_m->get_device_settings().active_scan_max_ch_time ); |
|
85 if ( scan_mode_m == core_scan_mode_passive ) |
|
86 { |
|
87 min_ch_time = server_m->get_device_settings().passive_scan_min_ch_time; |
|
88 max_ch_time = server_m->get_device_settings().passive_scan_max_ch_time; |
|
89 } |
|
90 |
|
91 if ( scan_ssid_m.length ) |
|
92 { |
|
93 DEBUG1S( "core_operation_scan_c::next_state() - requesting a direct scan with SSID ", |
|
94 scan_ssid_m.length, &scan_ssid_m.ssid[0] ); |
|
95 } |
|
96 else |
|
97 { |
|
98 DEBUG( "core_operation_scan_c::next_state() - requesting a broadcast scan" ); |
|
99 } |
|
100 |
|
101 bool_t is_split_scan( false_t ); |
|
102 if ( server_m->get_core_settings().is_connected() ) |
|
103 { |
|
104 is_split_scan = true_t; |
|
105 DEBUG( "core_operation_scan_c::next_state() - requesting a split-scan" ); |
|
106 } |
|
107 else |
|
108 { |
|
109 DEBUG( "core_operation_scan_c::next_state() - requesting a regular scan" ); |
|
110 } |
|
111 |
|
112 server_m->get_scan_list().remove_entries_by_age( |
|
113 server_m->get_device_settings().scan_list_expiration_time ); |
|
114 |
|
115 server_m->get_scan_list().set_tag( |
|
116 core_scan_list_tag_scan ); |
|
117 |
|
118 server_m->register_event_handler( this ); |
|
119 server_m->register_frame_handler( this ); |
|
120 |
|
121 drivers_m->scan( |
|
122 request_id_m, |
|
123 scan_mode_m, |
|
124 scan_ssid_m, |
|
125 server_m->get_device_settings().scan_rate, |
|
126 server_m->get_core_settings().valid_scan_channels( scan_channels_m ), |
|
127 min_ch_time, |
|
128 max_ch_time, |
|
129 is_split_scan ); |
|
130 |
|
131 break; |
|
132 } |
|
133 case core_state_scan_start: |
|
134 { |
|
135 DEBUG( "core_operation_scan_c::next_state() - scan request completed, waiting for scan completion" ); |
|
136 |
|
137 break; |
|
138 } |
|
139 case core_state_scan_complete: |
|
140 { |
|
141 /* If country information is not known then channels 12 and 13 can be scanned in passive mode */ |
|
142 if ( server_m->get_core_settings().mcc_known() || scan_ssid_m.length || !passive_scan_all_channels_m ) |
|
143 { |
|
144 /* All possible scans are done. |
|
145 * When MCC information is known, the allowed scan channels are known and handled already. |
|
146 * If SSID is given then direct scan would be required so no need to do passive broadcast scan. |
|
147 * If operation does not require passive scanning on channels 12 and 13, this is not done. |
|
148 */ |
|
149 return goto_state( core_state_scan_complete_handle_result ); |
|
150 } |
|
151 |
|
152 operation_state_m = core_state_scan_start_unknown_region; |
|
153 |
|
154 u32_t min_ch_time( server_m->get_device_settings().passive_scan_min_ch_time ); |
|
155 u32_t max_ch_time( server_m->get_device_settings().passive_scan_max_ch_time ); |
|
156 |
|
157 bool_t is_split_scan( false_t ); |
|
158 if ( server_m->get_core_settings().is_connected() ) |
|
159 { |
|
160 is_split_scan = true_t; |
|
161 DEBUG( "core_operation_scan_c::next_state() - requesting a split-scan for channels 12 and 13" ); |
|
162 } |
|
163 else |
|
164 { |
|
165 DEBUG( "core_operation_scan_c::next_state() - requesting a regular scan for channels 12 and 13" ); |
|
166 } |
|
167 |
|
168 server_m->register_event_handler( this ); |
|
169 server_m->register_frame_handler( this ); |
|
170 |
|
171 drivers_m->scan( |
|
172 request_id_m, |
|
173 core_scan_mode_passive, |
|
174 scan_ssid_m, |
|
175 server_m->get_device_settings().scan_rate, |
|
176 server_m->get_core_settings().invalid_scan_channels( scan_channels_m ), |
|
177 min_ch_time, |
|
178 max_ch_time, |
|
179 is_split_scan ); |
|
180 |
|
181 break; |
|
182 } |
|
183 case core_state_scan_start_unknown_region: |
|
184 { |
|
185 DEBUG( "core_operation_scan_c::next_state() - scan request for channels 12 and 13 completed, waiting for scan completion" ); |
|
186 |
|
187 break; |
|
188 } |
|
189 case core_state_scan_complete_unknown_region: |
|
190 { |
|
191 server_m->unregister_frame_handler( this ); |
|
192 server_m->get_scan_list().print_contents(); // Additional print |
|
193 |
|
194 operation_state_m = core_state_scan_complete_store_country_info; |
|
195 |
|
196 /* If WLAN region was not known before the scan, then check if country information is present |
|
197 * in the scan results. APs on channels 12 and 13 must be ignored if country information indicates this. |
|
198 */ |
|
199 core_scan_list_iterator_by_tag_c iter_country_beacon( |
|
200 server_m->get_scan_list(), |
|
201 core_scan_list_tag_scan ); |
|
202 |
|
203 core_wlan_region_e found_region = core_wlan_region_undefined; |
|
204 bool_t inconsistent_info( false_t ); |
|
205 for ( core_ap_data_c* ap_data = iter_country_beacon.first(); ap_data; ap_data = iter_country_beacon.next() ) |
|
206 { |
|
207 core_country_string_s country_info = ap_data->country_info(); |
|
208 core_wlan_region_e ap_region = core_wlan_region_undefined; |
|
209 if ( country_info.country[0] != 0 ) |
|
210 { |
|
211 ap_region = core_tools_c::convert_country_to_region( country_info ); |
|
212 if ( found_region != core_wlan_region_undefined ) |
|
213 { |
|
214 if ( ap_region != found_region ) |
|
215 { |
|
216 inconsistent_info = true_t; |
|
217 } |
|
218 } |
|
219 else |
|
220 { |
|
221 found_region = ap_region; |
|
222 } |
|
223 } |
|
224 } |
|
225 if ( found_region != core_wlan_region_undefined ) |
|
226 { |
|
227 if ( !inconsistent_info ) |
|
228 { |
|
229 region_from_ap_m = found_region; |
|
230 } |
|
231 else |
|
232 { |
|
233 region_from_ap_m = core_wlan_region_etsi; |
|
234 } |
|
235 adaptation_m->store_ap_country_info( request_id_m, region_from_ap_m, inconsistent_info ); |
|
236 } |
|
237 else |
|
238 { |
|
239 DEBUG( "core_operation_scan_c::next_state() - country info not found, continue with handling scan results" ); |
|
240 return goto_state( core_state_scan_complete_handle_result ); |
|
241 } |
|
242 break; |
|
243 } |
|
244 |
|
245 case core_state_scan_complete_store_country_info: |
|
246 { |
|
247 operation_state_m = core_state_scan_complete_handle_result; |
|
248 |
|
249 /* Set the new region information also to core settings */ |
|
250 DEBUG1( "core_operation_scan_c::next_state() - current region %u", |
|
251 region_from_ap_m ); |
|
252 server_m->get_core_settings().set_regional_domain( |
|
253 region_from_ap_m ); |
|
254 server_m->get_core_settings().set_mcc_known( true_t ); |
|
255 |
|
256 return goto_state( core_state_scan_complete_handle_result ); |
|
257 } |
|
258 |
|
259 case core_state_scan_complete_handle_result: |
|
260 { |
|
261 /* If region is FCC, then ignore and remove the APs from channels 12 and 13 */ |
|
262 if ( server_m->get_core_settings().regional_domain() == core_wlan_region_fcc ) |
|
263 { |
|
264 DEBUG( "core_operation_scan_c::next_state() - remove APs that were found on channels 12 and 13" ); |
|
265 remove_disallowed_aps(); |
|
266 } |
|
267 |
|
268 DEBUG( "core_operation_scan_c::next_state() - final scan list" ); |
|
269 server_m->get_scan_list().print_contents(); // Additional print |
|
270 |
|
271 /** |
|
272 * If we have an ongoing connection, we'll have to see whether |
|
273 * the current AP was found in the scan. |
|
274 */ |
|
275 core_ssid_s current_ssid( BROADCAST_SSID ); |
|
276 core_mac_address_s current_bssid( ZERO_MAC_ADDR ); |
|
277 bool_t is_current_ap_in_list( true_t ); |
|
278 if ( is_current_ap_added_m && |
|
279 server_m->get_connection_data() && |
|
280 server_m->get_connection_data()->current_ap_data() ) |
|
281 { |
|
282 current_ssid = |
|
283 server_m->get_connection_data()->ssid(); |
|
284 current_bssid = |
|
285 server_m->get_connection_data()->current_ap_data()->bssid(); |
|
286 |
|
287 /** |
|
288 * Current AP only needs to be added in a broadcast scan or a direct |
|
289 * scan done with the same SSID. |
|
290 */ |
|
291 if ( !scan_ssid_m.length || |
|
292 scan_ssid_m == current_ssid ) |
|
293 { |
|
294 is_current_ap_in_list = false_t; |
|
295 } |
|
296 } |
|
297 |
|
298 if ( scan_ssid_m.length ) |
|
299 { |
|
300 core_scan_list_iterator_by_tag_and_ssid_c iter( |
|
301 server_m->get_scan_list(), |
|
302 core_scan_list_tag_scan, |
|
303 scan_ssid_m ); |
|
304 for ( core_ap_data_c* ap_data = iter.first(); ap_data; ap_data = iter.next() ) |
|
305 { |
|
306 const core_mac_address_s bssid = ap_data->bssid(); |
|
307 |
|
308 if ( !server_m->get_core_settings().is_mac_in_permanent_blacklist( bssid ) ) |
|
309 { |
|
310 if ( !is_current_ap_in_list && |
|
311 current_bssid == bssid && |
|
312 current_ssid == ap_data->ssid() ) |
|
313 { |
|
314 is_current_ap_in_list = true_t; |
|
315 } |
|
316 |
|
317 core_tools_c::add_beacon_to_scan_list( |
|
318 scan_data_m, |
|
319 *ap_data, |
|
320 ap_data->rcpi() ); |
|
321 } |
|
322 } |
|
323 } |
|
324 else if ( !scan_max_age_m ) |
|
325 { |
|
326 core_scan_list_iterator_by_tag_c iter( |
|
327 server_m->get_scan_list(), |
|
328 core_scan_list_tag_scan ); |
|
329 for ( core_ap_data_c* ap_data = iter.first(); ap_data; ap_data = iter.next() ) |
|
330 { |
|
331 const core_mac_address_s bssid = ap_data->bssid(); |
|
332 |
|
333 if ( !server_m->get_core_settings().is_mac_in_permanent_blacklist( bssid ) ) |
|
334 { |
|
335 if ( !is_current_ap_in_list && |
|
336 current_bssid == bssid && |
|
337 current_ssid == ap_data->ssid() ) |
|
338 { |
|
339 is_current_ap_in_list = true_t; |
|
340 } |
|
341 |
|
342 core_tools_c::add_beacon_to_scan_list( |
|
343 scan_data_m, |
|
344 *ap_data, |
|
345 ap_data->rcpi() ); |
|
346 } |
|
347 } |
|
348 } |
|
349 else |
|
350 { |
|
351 core_scan_list_iterator_by_age_c iter( |
|
352 server_m->get_scan_list(), |
|
353 scan_max_age_m ); |
|
354 for ( core_ap_data_c* ap_data = iter.first(); ap_data; ap_data = iter.next() ) |
|
355 { |
|
356 const core_mac_address_s bssid = ap_data->bssid(); |
|
357 |
|
358 if ( !server_m->get_core_settings().is_mac_in_permanent_blacklist( bssid ) ) |
|
359 { |
|
360 if ( !is_current_ap_in_list && |
|
361 current_bssid == bssid && |
|
362 current_ssid == ap_data->ssid() ) |
|
363 { |
|
364 is_current_ap_in_list = true_t; |
|
365 } |
|
366 |
|
367 core_tools_c::add_beacon_to_scan_list( |
|
368 scan_data_m, |
|
369 *ap_data, |
|
370 ap_data->rcpi() ); |
|
371 } |
|
372 } |
|
373 } |
|
374 |
|
375 if ( is_current_ap_in_list ) |
|
376 { |
|
377 return goto_state( core_state_scanning_done ); |
|
378 } |
|
379 |
|
380 operation_state_m = core_state_rcpi_received; |
|
381 |
|
382 DEBUG( "core_operation_scan_c::next_state() - current AP was not found in scan" ); |
|
383 DEBUG( "core_operation_scan_c::next_state() - requesting RCPI" ); |
|
384 |
|
385 drivers_m->get_current_rcpi( |
|
386 request_id_m, |
|
387 current_rcpi_m ); |
|
388 |
|
389 break; |
|
390 } |
|
391 case core_state_rcpi_received: |
|
392 { |
|
393 DEBUG1( "core_operation_scan_c::next_state() - current RCPI is %u", |
|
394 current_rcpi_m ); |
|
395 DEBUG( "core_operation_scan_c::next_state() - appending current AP to the scan list" ); |
|
396 |
|
397 core_tools_c::add_beacon_to_scan_list( |
|
398 scan_data_m, |
|
399 *server_m->get_connection_data()->current_ap_data(), |
|
400 current_rcpi_m ); |
|
401 |
|
402 return goto_state( core_state_scanning_done ); |
|
403 } |
|
404 case core_state_scanning_done: |
|
405 { |
|
406 DEBUG( "core_operation_scan_c::next_state() - scan complete" ); |
|
407 DEBUG1( "core_operation_scan_c::next_state() - scan list contains %u AP(s)", |
|
408 scan_data_m.Count() ); |
|
409 DEBUG1( "core_operation_scan_c::next_state() - scan list size is %u bytes", |
|
410 scan_data_m.Size() ); |
|
411 |
|
412 return core_error_ok; |
|
413 } |
|
414 default: |
|
415 { |
|
416 ASSERT( false_t ); |
|
417 } |
|
418 } |
|
419 |
|
420 return core_error_request_pending; |
|
421 } |
|
422 |
|
423 // --------------------------------------------------------------------------- |
|
424 // --------------------------------------------------------------------------- |
|
425 // |
|
426 void core_operation_scan_c::user_cancel( |
|
427 bool_t do_graceful_cancel ) |
|
428 { |
|
429 DEBUG1( "core_operation_scan_c::user_cancel(do_graceful_cancel=%d)", do_graceful_cancel ); |
|
430 |
|
431 /** |
|
432 * If region is FCC and region information is not known, then ignore |
|
433 * and remove the APs from channels 12 and 13 |
|
434 */ |
|
435 if ( !server_m->get_core_settings().mcc_known() && |
|
436 server_m->get_core_settings().regional_domain() == core_wlan_region_fcc ) |
|
437 { |
|
438 DEBUG( "core_operation_scan_c::next_state() - remove APs that were found on channels 12 and 13" ); |
|
439 remove_disallowed_aps(); |
|
440 } |
|
441 |
|
442 if ( !do_graceful_cancel ) |
|
443 { |
|
444 /** |
|
445 * If we are in a middle of a scan, we have to schedule our own |
|
446 * event. |
|
447 */ |
|
448 if ( ( operation_state_m == core_state_scan_start || |
|
449 operation_state_m == core_state_scan_start_unknown_region ) && |
|
450 server_m->event_handler() == this && |
|
451 server_m->frame_handler() == this ) |
|
452 { |
|
453 asynch_default_user_cancel(); |
|
454 |
|
455 return; |
|
456 } |
|
457 |
|
458 /** |
|
459 * Everything else is handled by the default implementation. |
|
460 */ |
|
461 core_operation_base_c::user_cancel( do_graceful_cancel ); |
|
462 } |
|
463 } |
|
464 |
|
465 // --------------------------------------------------------------------------- |
|
466 // --------------------------------------------------------------------------- |
|
467 // |
|
468 bool_t core_operation_scan_c::receive_frame( |
|
469 const core_frame_dot11_c* frame, |
|
470 u8_t rcpi ) |
|
471 { |
|
472 DEBUG( "core_operation_scan_c::receive_frame()" ); |
|
473 |
|
474 if ( frame->type() != core_frame_dot11_c::core_dot11_type_beacon && |
|
475 frame->type() != core_frame_dot11_c::core_dot11_type_probe_resp ) |
|
476 { |
|
477 DEBUG( "core_operation_scan_c::receive_frame() - not a beacon or a probe" ); |
|
478 return false_t; |
|
479 } |
|
480 |
|
481 core_ap_data_c* ap_data = core_ap_data_c::instance( |
|
482 server_m->get_wpx_adaptation_instance(), |
|
483 frame, |
|
484 rcpi, |
|
485 false_t ); |
|
486 if ( ap_data ) |
|
487 { |
|
488 const core_ssid_s ssid = ap_data->ssid(); |
|
489 DEBUG1S( "core_operation_scan_c::receive_frame() - SSID: ", |
|
490 ssid.length, &ssid.ssid[0] ); |
|
491 |
|
492 core_mac_address_s bssid( |
|
493 ap_data->bssid() ); |
|
494 DEBUG6( "core_operation_scan_c::receive_frame() - BSSID: %02X:%02X:%02X:%02X:%02X:%02X", |
|
495 bssid.addr[0], bssid.addr[1], bssid.addr[2], |
|
496 bssid.addr[3], bssid.addr[4], bssid.addr[5] ); |
|
497 |
|
498 server_m->get_scan_list().update_entry( *ap_data ); |
|
499 |
|
500 delete ap_data; |
|
501 ap_data = NULL; |
|
502 } |
|
503 |
|
504 return true_t; |
|
505 } |
|
506 |
|
507 // --------------------------------------------------------------------------- |
|
508 // --------------------------------------------------------------------------- |
|
509 // |
|
510 bool_t core_operation_scan_c::notify( |
|
511 core_am_indication_e indication ) |
|
512 { |
|
513 if ( operation_state_m == core_state_scan_start && |
|
514 indication == core_am_indication_wlan_scan_complete ) |
|
515 { |
|
516 server_m->unregister_event_handler( this ); |
|
517 |
|
518 DEBUG( "core_operation_scan_c::notify() - scan complete" ); |
|
519 |
|
520 asynch_goto( core_state_scan_complete, CORE_TIMER_IMMEDIATELY ); |
|
521 |
|
522 return true_t; |
|
523 } |
|
524 else if ( operation_state_m == core_state_scan_start_unknown_region && |
|
525 indication == core_am_indication_wlan_scan_complete ) |
|
526 { |
|
527 server_m->unregister_event_handler( this ); |
|
528 |
|
529 DEBUG( "core_operation_scan_c::notify() - scan complete for channels 12 and 13" ); |
|
530 |
|
531 asynch_goto( core_state_scan_complete_unknown_region, CORE_TIMER_IMMEDIATELY ); |
|
532 |
|
533 return true_t; |
|
534 } |
|
535 |
|
536 return false_t; |
|
537 } |
|
538 |
|
539 // --------------------------------------------------------------------------- |
|
540 // --------------------------------------------------------------------------- |
|
541 // |
|
542 void core_operation_scan_c::remove_disallowed_aps() |
|
543 { |
|
544 core_type_list_c<core_mac_address_s> remove_ap_list; |
|
545 |
|
546 core_scan_list_iterator_by_tag_c iter_removed_aps( |
|
547 server_m->get_scan_list(), |
|
548 core_scan_list_tag_scan ); |
|
549 |
|
550 core_ap_data_c* ap_data = iter_removed_aps.first(); |
|
551 while (ap_data) |
|
552 { |
|
553 if ( !server_m->get_core_settings().is_valid_channel( |
|
554 SCAN_BAND_2DOT4GHZ, |
|
555 ap_data->channel() ) ) |
|
556 { |
|
557 core_mac_address_s* ignored_ap = new core_mac_address_s; |
|
558 if ( ignored_ap ) |
|
559 { |
|
560 *ignored_ap = ap_data->bssid(); |
|
561 remove_ap_list.append( ignored_ap ); |
|
562 } |
|
563 } |
|
564 ap_data = iter_removed_aps.next(); |
|
565 } |
|
566 |
|
567 core_mac_address_s* ignored_bssid = remove_ap_list.first(); |
|
568 while (ignored_bssid ) |
|
569 { |
|
570 server_m->get_scan_list().remove_entries_by_bssid( *ignored_bssid ); |
|
571 ignored_bssid = remove_ap_list.next(); |
|
572 } |
|
573 remove_ap_list.clear(); |
|
574 |
|
575 } |