wlan_bearer/wlanengine/wlan_common/wlanengine_common_3.1/src/core_operation_protected_setup.cpp
changeset 0 c40eb8fe8501
equal deleted inserted replaced
-1:000000000000 0:c40eb8fe8501
       
     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     }