|
1 /* |
|
2 * Copyright (c) 2005-2007 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 * |
|
14 * Description: Statemachine for Wi-Fi Protected setup |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include "core_operation_protected_setup.h" |
|
20 #include "core_operation_scan.h" |
|
21 #include "core_sub_operation_wpa_connect.h" |
|
22 #include "core_operation_release.h" |
|
23 #include "core_server.h" |
|
24 #include "core_timer_factory.h" |
|
25 #include "core_callback.h" |
|
26 #include "core_frame_wsc_ie.h" |
|
27 #include "core_ap_data.h" |
|
28 #include "core_tools.h" |
|
29 #include "core_tools_parser.h" |
|
30 |
|
31 #include "am_debug.h" |
|
32 |
|
33 // This is for cheat to enable testing even when there are no selected registrars. |
|
34 //#define CHEAT_FOR_TESTING |
|
35 #define SCANLIST_PARSING_AND_PRINTING |
|
36 |
|
37 /** |
|
38 * Delay between scans when looking for a selected registrar (in microseconds). |
|
39 * The default is two seconds. |
|
40 */ |
|
41 const u32_t CORE_OPERATION_PROTECTED_SETUP_DELAY_FOR_NEXT_SCAN = 2 * SECONDS_FROM_MICROSECONDS; |
|
42 |
|
43 /** |
|
44 * Timeout for finding a selected registrar (in microseconds). The default value is 120 seconds. |
|
45 */ |
|
46 const u32_t CORE_OPERATION_PROTECTED_SETUP_WALKTIME = 120 * SECONDS_FROM_MICROSECONDS; |
|
47 |
|
48 /** |
|
49 * Defines how often Protected Setup is attempted against an AP even if the selected |
|
50 * registrar bit is not set. The default is every third scan. |
|
51 */ |
|
52 const u32_t CORE_OPERATION_PROTECTED_SETUP_ROUNDTRIP_INTERVAL = 3; |
|
53 |
|
54 /** |
|
55 * Defines how many scans are required before CORE_OPERATION_PROTECTED_SETUP_ROUNDTRIP_INTERVAL |
|
56 * is taken into use. |
|
57 */ |
|
58 const u32_t CORE_OPERATION_PROTECTED_SETUP_ROUNDTRIP_START = 13; |
|
59 |
|
60 /** |
|
61 * Delay before Protected Setup is attempted against an AP (in microseconds). Some APs are not |
|
62 * ready immediately even if the selected registrat bit is set. The default delay is 5 seconds. |
|
63 */ |
|
64 const u32_t CORE_OPERATION_PROTECTED_SETUP_START_DELAY = 5 * SECONDS_FROM_MICROSECONDS; |
|
65 |
|
66 // ======== MEMBER FUNCTIONS ======== |
|
67 |
|
68 // --------------------------------------------------------------------------- |
|
69 // --------------------------------------------------------------------------- |
|
70 // |
|
71 core_operation_protected_setup_c::core_operation_protected_setup_c( |
|
72 u32_t request_id, |
|
73 core_server_c* server, |
|
74 abs_core_driverif_c* drivers, |
|
75 abs_core_server_callback_c* adaptation, |
|
76 const core_iap_data_s& iap_data, |
|
77 core_type_list_c<core_iap_data_s>& iap_data_list, |
|
78 core_protected_setup_status_e& protected_setup_status ) : |
|
79 core_operation_base_c( core_operation_protected_setup, request_id, server, drivers, adaptation, |
|
80 core_base_flag_drivers_needed ), |
|
81 core_iap_data_m( iap_data ), |
|
82 iap_data_list_m( iap_data_list ), |
|
83 protected_setup_status_m( protected_setup_status ), |
|
84 scan_data_m( NULL ), |
|
85 walktime_timer_m( NULL ), |
|
86 selected_ap_data_m( NULL ), |
|
87 tag_m( core_scan_list_tag_scan ), |
|
88 all_valid_scan_channels_m( ), |
|
89 assoc_ie_list_m( false_t ), |
|
90 is_reassociation_m( false_t ), |
|
91 management_status_m( core_management_status_success ), |
|
92 is_connected_m( false_t ), |
|
93 wps_scan_count_m( 0 ), |
|
94 is_selected_registrar_found_m( false_t ), |
|
95 is_pushbutton_method_used_m( false_t ) |
|
96 { |
|
97 DEBUG( "core_operation_protected_setup_c::core_operation_protected_setup_c()" ); |
|
98 |
|
99 all_valid_scan_channels_m = server_m->get_core_settings().all_valid_scan_channels(); |
|
100 } |
|
101 |
|
102 // --------------------------------------------------------------------------- |
|
103 // --------------------------------------------------------------------------- |
|
104 // |
|
105 core_operation_protected_setup_c::~core_operation_protected_setup_c() |
|
106 { |
|
107 DEBUG( "core_operation_protected_setup_c::~core_operation_protected_setup_c()" ); |
|
108 delete scan_data_m; |
|
109 scan_data_m = NULL; |
|
110 |
|
111 assoc_ie_list_m.clear(); |
|
112 |
|
113 if ( walktime_timer_m ) |
|
114 { |
|
115 walktime_timer_m->stop(); |
|
116 core_timer_factory_c::destroy_timer( walktime_timer_m ); |
|
117 walktime_timer_m = NULL; |
|
118 } |
|
119 selected_ap_data_m = NULL; |
|
120 |
|
121 if ( operation_state_m > core_state_init |
|
122 && server_m->get_core_settings().connection_state() != core_connection_state_notconnected ) |
|
123 { |
|
124 DEBUG( "core_operation_protected_setup_c::~core_operation_protected_setup_c() - Error: Connection is not released!" ); |
|
125 ASSERT( false_t ); |
|
126 } |
|
127 server_m->set_protected_setup_handler( NULL ); |
|
128 } |
|
129 |
|
130 // --------------------------------------------------------------------------- |
|
131 // --------------------------------------------------------------------------- |
|
132 // |
|
133 core_error_e core_operation_protected_setup_c::next_state() |
|
134 { |
|
135 DEBUG( "core_operation_protected_setup_c::next_state()" ); |
|
136 switch( operation_state_m ) |
|
137 { |
|
138 case core_state_init: |
|
139 { |
|
140 // This state is for initial actions. |
|
141 DEBUG( "- core_state_init" ); |
|
142 DEBUG1S("User selected SSID: ", core_iap_data_m.ssid.length, core_iap_data_m.ssid.ssid); |
|
143 |
|
144 if ( core_iap_data_m.wpa_preshared_key.key_length == 0 ) |
|
145 { |
|
146 DEBUG( "Using Pushbutton method" ); |
|
147 is_pushbutton_method_used_m = true_t; |
|
148 } |
|
149 else |
|
150 { |
|
151 DEBUG( "Using Pincode method" ); |
|
152 is_pushbutton_method_used_m = false_t; |
|
153 } |
|
154 |
|
155 scan_data_m = new ScanList; |
|
156 if( !scan_data_m ) |
|
157 { |
|
158 DEBUG( "core_operation_protected_setup_c::next_state() - unable to create ScanList" ); |
|
159 return core_error_no_memory; |
|
160 } |
|
161 |
|
162 core_callback_c* timer_callback = |
|
163 new core_callback_c( &(core_operation_protected_setup_c::timer_expired), this ); |
|
164 if( !timer_callback ) |
|
165 { |
|
166 DEBUG( "core_operation_protected_setup_c::next_state() - unable to create callbacks" ); |
|
167 return core_error_no_memory; |
|
168 } |
|
169 |
|
170 walktime_timer_m = core_timer_factory_c::create_timer( timer_callback ); |
|
171 if( !walktime_timer_m ) |
|
172 { |
|
173 DEBUG( "core_operation_protected_setup_c::next_state() - unable to create timer" ); |
|
174 delete timer_callback; |
|
175 return core_error_no_memory; |
|
176 } |
|
177 |
|
178 |
|
179 if ( server_m->get_core_settings().is_connected() ) |
|
180 { |
|
181 DEBUG( "core_operation_protected_setup_c::next_state() - already connected, completing request" ); |
|
182 |
|
183 return core_error_connection_already_active; |
|
184 } |
|
185 |
|
186 // Override the security mode just in case. |
|
187 core_iap_data_m.security_mode = core_security_mode_protected_setup; |
|
188 |
|
189 if ( !server_m->create_eapol_instance( core_eapol_operating_mode_wfa ) ) |
|
190 { |
|
191 DEBUG( "core_operation_protected_setup_c::next_state() - unable to instantiate EAPOL" ); |
|
192 return core_error_no_memory; |
|
193 } |
|
194 |
|
195 walktime_timer_m->start( CORE_OPERATION_PROTECTED_SETUP_WALKTIME ); |
|
196 |
|
197 return goto_state( core_state_prepare_scanning ); |
|
198 } |
|
199 // This state is for actions what should be done at start or after core_operation_release_c. |
|
200 case core_state_prepare_scanning: |
|
201 { |
|
202 DEBUG( "- core_state_prepare_scanning" ); |
|
203 core_error_e ret = server_m->init_connection_data( |
|
204 core_iap_data_m, |
|
205 server_m->get_device_settings() ); |
|
206 if ( ret != core_error_ok ) |
|
207 { |
|
208 DEBUG1( "core_operation_protected_setup_c::next_state() - unable to initialize connection data (%d)", ret ); |
|
209 return ret; |
|
210 } |
|
211 |
|
212 if ( !server_m->get_connection_data()->iap_data().is_eap_used() ) |
|
213 { |
|
214 DEBUG( "core_operation_protected_setup_c::next_state() - is_eap_used() == false, it should be true." ); |
|
215 return core_error_illegal_argument; |
|
216 } |
|
217 |
|
218 server_m->get_core_settings().set_connection_state( core_connection_state_searching ); |
|
219 |
|
220 return goto_state( core_state_start_scanning ); |
|
221 } |
|
222 |
|
223 case core_state_start_scanning: |
|
224 { |
|
225 DEBUG( "- core_state_start_scanning" ); |
|
226 operation_state_m = core_state_scan; |
|
227 |
|
228 // Clear scanlist |
|
229 ASSERT( scan_data_m ); |
|
230 scan_data_m->ClearAll(); |
|
231 |
|
232 // add tag to help scanlist iteration |
|
233 server_m->get_scan_list().set_tag( tag_m ); |
|
234 selected_ap_data_m = NULL; |
|
235 |
|
236 // Broadcast scan is used to detect session overlap. |
|
237 // Otherwise this could be direct scan. |
|
238 core_operation_base_c* operation = new core_operation_scan_c( |
|
239 request_id_m, |
|
240 server_m, |
|
241 drivers_m, |
|
242 adaptation_m, |
|
243 core_scan_mode_active, |
|
244 BROADCAST_SSID, |
|
245 all_valid_scan_channels_m, |
|
246 0, |
|
247 *scan_data_m, |
|
248 false_t, |
|
249 false_t ); |
|
250 |
|
251 return run_sub_operation( operation ); |
|
252 } |
|
253 |
|
254 case core_state_scan: |
|
255 { |
|
256 DEBUG( "- core_state_scan" ); |
|
257 operation_state_m = core_state_MAX; // This is just to spot leak in following switch. |
|
258 ++wps_scan_count_m; |
|
259 |
|
260 #ifdef SCANLIST_PARSING_AND_PRINTING |
|
261 |
|
262 core_scan_list_iterator_by_tag_c parsing_iter( |
|
263 server_m->get_scan_list(), |
|
264 tag_m); |
|
265 for ( core_ap_data_c* ap_data = parsing_iter.first(); ap_data; ap_data = parsing_iter.next() ) |
|
266 { |
|
267 u8_t buffer[70]; |
|
268 core_tools_c::fillz(buffer, sizeof(buffer) ); |
|
269 |
|
270 for (u32_t i=0; i<ap_data->ssid().length; ++i) |
|
271 { |
|
272 buffer[2*i] = ap_data->ssid().ssid[i]; |
|
273 buffer[2*i+1] = 0; |
|
274 } |
|
275 |
|
276 DEBUG8("RADAR: SSID:%s BSSID:%02x.%02x.%02x.%02x.%02x.%02x RCPI:%u", |
|
277 buffer, |
|
278 //ap_data->ssid().ssid, |
|
279 ap_data->bssid().addr[0], |
|
280 ap_data->bssid().addr[1], |
|
281 ap_data->bssid().addr[2], |
|
282 ap_data->bssid().addr[3], |
|
283 ap_data->bssid().addr[4], |
|
284 ap_data->bssid().addr[5], |
|
285 ap_data->rcpi() |
|
286 ); |
|
287 } |
|
288 |
|
289 #endif // SCANLIST_PARSING_AND_PRINTING |
|
290 |
|
291 // Decide whether ap_data should be copied even when selected_registrar is not set. |
|
292 bool_t copy_ap_data( false_t ); |
|
293 if( wps_scan_count_m == 1 || |
|
294 ( wps_scan_count_m >= CORE_OPERATION_PROTECTED_SETUP_ROUNDTRIP_START && |
|
295 ( wps_scan_count_m % CORE_OPERATION_PROTECTED_SETUP_ROUNDTRIP_INTERVAL == 1 ) ) ) |
|
296 { |
|
297 copy_ap_data = true_t; |
|
298 } |
|
299 DEBUG2( "core_operation_protected_setup_c::next_state() - wps_scan_count_m=%d, copy_ap_data=%d", wps_scan_count_m, copy_ap_data ); |
|
300 |
|
301 abs_core_scan_list_iterator_c * iter; |
|
302 |
|
303 if ( is_pushbutton_method_used_m ) |
|
304 { |
|
305 // Pushbutton: Check all APs from scanlist. |
|
306 iter = new core_scan_list_iterator_by_tag_c( |
|
307 server_m->get_scan_list(), |
|
308 tag_m); |
|
309 } |
|
310 else |
|
311 { |
|
312 // Pincode: Check only APs with given SSID from scanlist. |
|
313 iter = new core_scan_list_iterator_by_tag_and_ssid_c( |
|
314 server_m->get_scan_list(), |
|
315 tag_m, |
|
316 core_iap_data_m.ssid); |
|
317 } |
|
318 |
|
319 u32_t selected_registrar_count( check_selected_registrars( iter, copy_ap_data ) ); |
|
320 delete iter; |
|
321 iter = NULL; |
|
322 switch ( selected_registrar_count ) |
|
323 { |
|
324 case 0: // No selected registrars yet. We should wait until some registrar appears |
|
325 { |
|
326 // Second round-trip should not start before selected_registrar is found. |
|
327 if ( !selected_ap_data_m ) |
|
328 { |
|
329 // Wait some time before new scan |
|
330 return asynch_goto( core_state_start_scanning, CORE_OPERATION_PROTECTED_SETUP_DELAY_FOR_NEXT_SCAN ); |
|
331 } |
|
332 } |
|
333 /* |
|
334 * This will fall through in first round-trip if selected AP was found. |
|
335 * It means that selected_registrar flag is not required until second round-trip. |
|
336 */ |
|
337 //lint -fallthrough |
|
338 case 1: // Successfull case: one and only one selected registrar |
|
339 { |
|
340 // AP not found. It is coding error. |
|
341 ASSERT( selected_ap_data_m ); |
|
342 |
|
343 // Check that selected registrar is in SSID where it should be... |
|
344 if ( core_iap_data_m.ssid != selected_ap_data_m->ssid() ) |
|
345 { |
|
346 // If it is not, then wait some time before new scan |
|
347 DEBUG( "core_operation_protected_setup_c::next_state() - selected registrar is not in wanted AP, ignoring" ); |
|
348 return asynch_goto( core_state_start_scanning, CORE_OPERATION_PROTECTED_SETUP_DELAY_FOR_NEXT_SCAN ); |
|
349 } |
|
350 if ( selected_registrar_count > 0 ) |
|
351 { |
|
352 // selected_registrar == true was found in correct AP. |
|
353 is_selected_registrar_found_m = true_t; |
|
354 } |
|
355 |
|
356 return asynch_goto( core_state_connect_and_setup, CORE_OPERATION_PROTECTED_SETUP_START_DELAY ); |
|
357 } |
|
358 default: // More than one selected registrar: It means "multiple PBC sessions detected" |
|
359 { |
|
360 // But if we are using pincode method, then we just try connection with first AP. |
|
361 // No need to check SSID, because it is already filtered. |
|
362 if ( !is_pushbutton_method_used_m ) |
|
363 { |
|
364 DEBUG1( "core_operation_protected_setup_c::next_state() - %i selected registrars found for the same SSID, trying pincode for first AP.", selected_registrar_count ); |
|
365 is_selected_registrar_found_m = true_t; |
|
366 return asynch_goto( core_state_connect_and_setup, CORE_OPERATION_PROTECTED_SETUP_START_DELAY ); |
|
367 } |
|
368 |
|
369 protected_setup_status_m = core_protected_setup_status_multiple_PBC_sessions_detected; |
|
370 walktime_timer_m->stop(); |
|
371 |
|
372 server_m->get_core_settings().set_connection_state( core_connection_state_notconnected ); |
|
373 |
|
374 return core_error_ok; |
|
375 } |
|
376 } |
|
377 } |
|
378 |
|
379 case core_state_connect_and_setup: |
|
380 { |
|
381 DEBUG( "- core_state_connect_and_setup" ); |
|
382 |
|
383 if ( is_selected_registrar_found_m ) |
|
384 { |
|
385 /** |
|
386 * Walk time timer can be stopped because user has pressed |
|
387 * Push-button or PIN-code from both phone and registrar. |
|
388 * Do not stop timer, if selected registrar is not found. |
|
389 */ |
|
390 ASSERT( walktime_timer_m ); |
|
391 walktime_timer_m->stop(); |
|
392 } |
|
393 |
|
394 core_iap_data_c core_iap_data( core_iap_data_m ); |
|
395 |
|
396 operation_state_m = core_state_setup_completed; |
|
397 |
|
398 // Add WSC IE to association request |
|
399 core_frame_wsc_ie_c* wsc_ie = core_frame_wsc_ie_c::instance( |
|
400 CORE_FRAME_WSC_IE_USED_VERSION, |
|
401 CORE_FRAME_WSC_IE_REQUEST_TYPE_ENROLLEE ); |
|
402 |
|
403 if ( wsc_ie == NULL ) |
|
404 { |
|
405 server_m->get_core_settings().set_connection_state( core_connection_state_notconnected ); |
|
406 return core_error_no_memory; |
|
407 } |
|
408 assoc_ie_list_m.append( |
|
409 wsc_ie, |
|
410 wsc_ie->element_id() ); |
|
411 |
|
412 ASSERT( selected_ap_data_m != NULL ); |
|
413 |
|
414 server_m->set_protected_setup_handler( this ); |
|
415 |
|
416 server_m->get_core_settings().set_connection_state( core_connection_state_secureinfra ); |
|
417 |
|
418 // WPA connect initiates connection and start authentication (in this case starts protected setup) |
|
419 core_operation_base_c* operation = new core_sub_operation_wpa_connect_c( |
|
420 request_id_m, |
|
421 server_m, |
|
422 drivers_m, |
|
423 adaptation_m, |
|
424 is_connected_m, |
|
425 management_status_m, |
|
426 core_iap_data_m.ssid, |
|
427 *selected_ap_data_m, |
|
428 is_reassociation_m, |
|
429 assoc_ie_list_m, |
|
430 NULL ); |
|
431 |
|
432 return run_sub_operation( operation ); |
|
433 } |
|
434 |
|
435 case core_state_setup_completed: |
|
436 { |
|
437 DEBUG( "- core_state_setup_completed" ); |
|
438 |
|
439 protected_setup_status_m = core_protected_setup_status_ok; |
|
440 ASSERT( walktime_timer_m ); |
|
441 walktime_timer_m->stop(); |
|
442 |
|
443 DEBUG( "Wi-Fi Protected Setup done, starting disconnect." ); |
|
444 |
|
445 operation_state_m = core_state_disconnect; |
|
446 |
|
447 core_operation_base_c* operation = new core_operation_release_c( |
|
448 request_id_m, |
|
449 server_m, |
|
450 drivers_m, |
|
451 adaptation_m, |
|
452 core_release_reason_other ); |
|
453 |
|
454 return run_sub_operation( operation ); |
|
455 } |
|
456 |
|
457 case core_state_disconnect: |
|
458 { |
|
459 DEBUG( "- core_state_disconnect" ); |
|
460 server_m->get_core_settings().set_connection_state( core_connection_state_notconnected ); |
|
461 return core_error_ok; |
|
462 } |
|
463 |
|
464 case core_state_user_cancel: |
|
465 { |
|
466 DEBUG( "- core_state_user_cancel" ); |
|
467 |
|
468 operation_state_m = core_state_disconnect_on_cancel; |
|
469 |
|
470 // |
|
471 ASSERT( walktime_timer_m ); |
|
472 walktime_timer_m->stop(); |
|
473 |
|
474 // We should cancel this timer, because asynch_goto could be ongoing. |
|
475 server_m->cancel_operation_timer(); |
|
476 |
|
477 // This is not necessary? operation release will check this also... |
|
478 if( server_m->get_core_settings().connection_state() |
|
479 == core_connection_state_secureinfra ) |
|
480 { |
|
481 core_operation_base_c* operation = new core_operation_release_c( |
|
482 request_id_m, |
|
483 server_m, |
|
484 drivers_m, |
|
485 adaptation_m, |
|
486 core_release_reason_external_request ); |
|
487 |
|
488 return run_sub_operation( operation ); |
|
489 } |
|
490 return next_state( ); |
|
491 } |
|
492 |
|
493 case core_state_disconnect_on_cancel: |
|
494 { |
|
495 DEBUG( "- core_state_disconnect_on_cancel" ); |
|
496 |
|
497 server_m->get_core_settings().set_connection_state( core_connection_state_notconnected ); |
|
498 |
|
499 return core_error_cancel; |
|
500 } |
|
501 |
|
502 case core_state_setup_failed: |
|
503 { |
|
504 DEBUG( "- core_state_setup_failed" ); |
|
505 |
|
506 operation_state_m = core_state_disconnect_on_error; |
|
507 ASSERT( walktime_timer_m ); |
|
508 walktime_timer_m->stop(); |
|
509 |
|
510 // Get EAPOL errorcode before releasing connection. |
|
511 wlan_eapol_if_eap_status_e eapol_status = static_cast<wlan_eapol_if_eap_status_e>( server_m->get_connection_data()->last_eap_error() ); |
|
512 protected_setup_status_m = core_tools_c::convert_eapol_error_to_protected_setup_status( eapol_status ); |
|
513 |
|
514 DEBUG2( "Protected Setup has failed, starting disconnect. (EAPOL status %i, protected setup status %i)", |
|
515 eapol_status, |
|
516 protected_setup_status_m ); |
|
517 server_m->get_core_settings().set_connection_state( core_connection_state_secureinfra ); |
|
518 |
|
519 core_operation_base_c* operation = new core_operation_release_c( |
|
520 request_id_m, |
|
521 server_m, |
|
522 drivers_m, |
|
523 adaptation_m, |
|
524 core_release_reason_other ); |
|
525 |
|
526 return run_sub_operation( operation ); |
|
527 } |
|
528 |
|
529 case core_state_disconnect_on_error: |
|
530 { |
|
531 DEBUG( "- core_state_disconnect_on_error" ); |
|
532 |
|
533 server_m->get_core_settings().set_connection_state( core_connection_state_notconnected ); |
|
534 |
|
535 DEBUG1( "core_operation_protected_setup_c::next_state() - failure_reason_m is %u", |
|
536 failure_reason_m ); |
|
537 DEBUG1( "core_operation_protected_setup_c::next_state() - management_status_m is %u", |
|
538 management_status_m ); |
|
539 |
|
540 core_error_e ret = protected_setup_status( |
|
541 failure_reason_m, |
|
542 management_status_m, |
|
543 protected_setup_status_m ); |
|
544 DEBUG1( "core_operation_protected_setup_c::next_state() - returned error code is %u", |
|
545 ret ); |
|
546 DEBUG1( "core_operation_protected_setup_c::next_state() - returned status is %u", |
|
547 protected_setup_status_m ); |
|
548 |
|
549 return ret; |
|
550 } |
|
551 |
|
552 case core_state_disconnect_before_second_round_trip: |
|
553 { |
|
554 DEBUG( "- core_state_disconnect_before_second_round_trip" ); |
|
555 |
|
556 operation_state_m = core_state_prepare_scanning; |
|
557 |
|
558 // Get EAPOL errorcode before releasing connection. |
|
559 wlan_eapol_if_eap_status_e eapol_status = static_cast<wlan_eapol_if_eap_status_e>( server_m->get_connection_data()->last_eap_error() ); |
|
560 protected_setup_status_m = core_tools_c::convert_eapol_error_to_protected_setup_status( eapol_status ); |
|
561 |
|
562 DEBUG2( "Protected Setup has failed (first round-trip), starting disconnect. (EAPOL status %i, protected setup status %i)", |
|
563 eapol_status, |
|
564 protected_setup_status_m ); |
|
565 server_m->get_core_settings().set_connection_state( core_connection_state_secureinfra ); |
|
566 |
|
567 core_operation_base_c* operation = new core_operation_release_c( |
|
568 request_id_m, |
|
569 server_m, |
|
570 drivers_m, |
|
571 adaptation_m, |
|
572 core_release_reason_other ); |
|
573 |
|
574 return run_sub_operation( operation ); |
|
575 } |
|
576 |
|
577 case core_state_walktime_expiration: |
|
578 { |
|
579 DEBUG( "- core_state_walktime_expiration" ); |
|
580 |
|
581 server_m->get_core_settings().set_connection_state( core_connection_state_notconnected ); |
|
582 |
|
583 // indicate unsuccessfully completed protected setup |
|
584 protected_setup_status_m = core_protected_setup_status_walktime_expired; |
|
585 |
|
586 return core_error_ok; |
|
587 } |
|
588 |
|
589 default: |
|
590 { |
|
591 ASSERT( false_t ); |
|
592 } |
|
593 } |
|
594 return core_error_request_pending; |
|
595 } |
|
596 |
|
597 // --------------------------------------------------------------------------- |
|
598 // --------------------------------------------------------------------------- |
|
599 // |
|
600 core_error_e core_operation_protected_setup_c::cancel() |
|
601 { |
|
602 DEBUG( "core_operation_protected_setup_c::cancel()" ); |
|
603 |
|
604 if ( operation_state_m == core_state_setup_completed ) |
|
605 { |
|
606 DEBUG( "core_operation_protected_setup_c::cancel() - Protected Setup has failed " ); |
|
607 if ( !is_selected_registrar_found_m ) |
|
608 { |
|
609 DEBUG( "core_operation_protected_setup_c::cancel() - Goto core_state_disconnect_before_second_round_trip"); |
|
610 return asynch_goto( core_state_disconnect_before_second_round_trip, CORE_TIMER_IMMEDIATELY ); |
|
611 } |
|
612 return goto_state( core_state_setup_failed ); |
|
613 } |
|
614 |
|
615 server_m->get_core_settings().set_connection_state( core_connection_state_notconnected ); |
|
616 |
|
617 return failure_reason_m; |
|
618 } |
|
619 |
|
620 // --------------------------------------------------------------------------- |
|
621 // --------------------------------------------------------------------------- |
|
622 // Handle cancel from user. |
|
623 // |
|
624 void core_operation_protected_setup_c::user_cancel( |
|
625 bool_t /* do_graceful_cancel */ ) |
|
626 { |
|
627 DEBUG( "core_operation_protected_setup_c::user_cancel()" ); |
|
628 |
|
629 // This will move execution to user cancel state, when we get execution time next time. |
|
630 operation_state_m = core_state_user_cancel; |
|
631 |
|
632 return; |
|
633 } |
|
634 |
|
635 // --------------------------------------------------------------------------- |
|
636 // --------------------------------------------------------------------------- |
|
637 // |
|
638 u32_t core_operation_protected_setup_c::check_selected_registrars( |
|
639 abs_core_scan_list_iterator_c * iter, |
|
640 bool_t copy_ap_data_always ) |
|
641 { |
|
642 DEBUG( "core_operation_protected_setup_c::check_selected_registrars()" ); |
|
643 u32_t registrar_count = 0; |
|
644 |
|
645 // Search through scan_list to count all selected registrars |
|
646 for ( core_ap_data_c* ap_data = iter->first(); ap_data; ap_data = iter->next() ) |
|
647 { |
|
648 const core_frame_wsc_ie_c* wsc_ie = ap_data->wsc_ie(); |
|
649 if ( wsc_ie != NULL ) |
|
650 { |
|
651 // Do we need to check something else? AP setup locked? |
|
652 if (wsc_ie->selected_registrar() == true_t) |
|
653 { |
|
654 ++registrar_count; |
|
655 selected_ap_data_m = ap_data; |
|
656 DEBUG1S( "core_operation_protected_setup_c::check_selected_registrars() - selected_registrar=true, SSID: ", |
|
657 ap_data->ssid().length, |
|
658 ap_data->ssid().ssid ); |
|
659 } |
|
660 else |
|
661 { |
|
662 DEBUG( "core_operation_protected_setup_c::check_selected_registrars() - selected_registrar=false" ); |
|
663 |
|
664 // Copy ap_data in first round-trip. Do not overwrite if selected_registrar is already found. |
|
665 if ( copy_ap_data_always && |
|
666 registrar_count == 0 && |
|
667 core_iap_data_m.ssid == ap_data->ssid() ) |
|
668 { |
|
669 DEBUG( "core_operation_protected_setup_c::check_selected_registrars() - SSID found. Copying ap_data."); |
|
670 selected_ap_data_m = ap_data; |
|
671 } |
|
672 } |
|
673 |
|
674 delete wsc_ie; |
|
675 wsc_ie = NULL; |
|
676 } |
|
677 |
|
678 #ifdef CHEAT_FOR_TESTING |
|
679 if ( core_tools_c::compare( |
|
680 core_iap_data_m.ssid.ssid, |
|
681 core_iap_data_m.ssid.length, |
|
682 ap_data->ssid().ssid, |
|
683 ap_data->ssid().length ) == 0) |
|
684 { |
|
685 DEBUG( "copy ap_data for testing..."); |
|
686 selected_ap_data_m = ap_data; |
|
687 } |
|
688 #endif // CHEAT_FOR_TESTING |
|
689 } |
|
690 DEBUG1( "core_operation_protected_setup_c::check_selected_registrars() - registrar_count %i", registrar_count); |
|
691 return registrar_count; |
|
692 } |
|
693 |
|
694 // --------------------------------------------------------------------------- |
|
695 // --------------------------------------------------------------------------- |
|
696 // |
|
697 void core_operation_protected_setup_c::timer_expired( void* this_ptr ) |
|
698 { |
|
699 DEBUG( "core_operation_protected_setup_c::timer_expired()" ); |
|
700 |
|
701 core_operation_protected_setup_c* self = |
|
702 static_cast<core_operation_protected_setup_c*>( this_ptr ); |
|
703 |
|
704 ASSERT( self ); |
|
705 |
|
706 // If scan is ongoing, do not use operation_timer. |
|
707 if ( self->operation_state_m == core_state_scan ) |
|
708 { |
|
709 DEBUG( "core_operation_protected_setup_c::timer_expired() - goto core_state_walktime_expiration after scan_complete" ); |
|
710 self->operation_state_m = core_state_walktime_expiration; |
|
711 } |
|
712 else if ( self->operation_state_m == core_state_setup_completed ) |
|
713 { |
|
714 DEBUG( "core_operation_protected_setup_c::timer_expired() - Ignoring walktime timer. Let EAPOL continue." ); |
|
715 /* |
|
716 * This will prevent newer ending round-trips, if walktime timer expires |
|
717 * while EAPOL is running protected setup and if it fails. |
|
718 */ |
|
719 self->is_selected_registrar_found_m = true_t; |
|
720 } |
|
721 else |
|
722 { |
|
723 DEBUG( "core_operation_protected_setup_c::timer_expired() - goto core_state_walktime_expiration immediately" ); |
|
724 |
|
725 // Must stop operation timer before asynch_goto. |
|
726 self->server_m->cancel_operation_timer(); |
|
727 self->asynch_goto( core_state_walktime_expiration, CORE_TIMER_IMMEDIATELY ); |
|
728 } |
|
729 } |
|
730 |
|
731 // --------------------------------------------------------------------------- |
|
732 // --------------------------------------------------------------------------- |
|
733 // |
|
734 void core_operation_protected_setup_c::handle_protected_setup_network( |
|
735 const core_iap_data_s& iap_data ) |
|
736 { |
|
737 DEBUG( "core_operation_protected_setup_c::handle_protected_setup_network()" ); |
|
738 |
|
739 core_iap_data_s* instance = new core_iap_data_s( |
|
740 iap_data ); |
|
741 if ( instance ) |
|
742 { |
|
743 iap_data_list_m.append( instance ); |
|
744 } |
|
745 } |
|
746 |
|
747 // --------------------------------------------------------------------------- |
|
748 // --------------------------------------------------------------------------- |
|
749 // |
|
750 core_error_e core_operation_protected_setup_c::protected_setup_status( |
|
751 core_error_e request_status, |
|
752 core_management_status_e management_status, |
|
753 core_protected_setup_status_e& protected_setup_status ) const |
|
754 { |
|
755 |
|
756 /** |
|
757 * If management status is defined, the AP has refused our authentication |
|
758 * or association. |
|
759 */ |
|
760 if ( management_status != core_management_status_success ) |
|
761 { |
|
762 switch ( management_status ) |
|
763 { |
|
764 case core_management_status_auth_algo_not_supported: |
|
765 /** Falls through on purpose. */ |
|
766 case core_management_status_auth_frame_out_of_sequence: |
|
767 /** Falls through on purpose. */ |
|
768 case core_management_status_auth_challenge_failure: |
|
769 /** Falls through on purpose. */ |
|
770 case core_management_status_auth_timeout: |
|
771 { |
|
772 protected_setup_status = core_protected_setup_status_network_auth_failure; |
|
773 break; |
|
774 } |
|
775 default: |
|
776 { |
|
777 protected_setup_status = core_protected_setup_status_network_assoc_failure; |
|
778 break; |
|
779 } |
|
780 } |
|
781 |
|
782 return core_error_ok; |
|
783 } |
|
784 |
|
785 /** |
|
786 * If EAPOL has indicated an error, determine the error code from |
|
787 * the saved notifications. |
|
788 */ |
|
789 if ( request_status == core_error_eapol_total_failure || |
|
790 request_status == core_error_eapol_failure ) |
|
791 { |
|
792 // In this case, protected_setup_status is already set from EAPOL errorcode (no need to set it here). |
|
793 return core_error_ok; |
|
794 } |
|
795 else if ( request_status == core_error_timeout ) |
|
796 { |
|
797 protected_setup_status = core_protected_setup_status_network_assoc_failure; |
|
798 return core_error_ok; |
|
799 } |
|
800 else if ( request_status != core_error_ok ) |
|
801 { |
|
802 protected_setup_status = core_protected_setup_status_network_auth_failure; |
|
803 return core_error_ok; |
|
804 } |
|
805 |
|
806 /** |
|
807 * An error occured somewhere else, has nothing to do with Protected Setup. |
|
808 */ |
|
809 protected_setup_status = core_protected_setup_status_undefined; |
|
810 |
|
811 return request_status; |
|
812 } |