diff -r 000000000000 -r c8830336c852 eapol/eapol_framework/eapol_common/type/simple_config/eap/src/eap_type_simple_config.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eapol/eapol_framework/eapol_common/type/simple_config/eap/src/eap_type_simple_config.cpp Thu Dec 17 08:47:43 2009 +0200 @@ -0,0 +1,3782 @@ +/* +* Copyright (c) 2001-2006 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: EAP and WLAN authentication protocols. +* +*/ + + +// This is enumeration of EAPOL source code. +#if defined(USE_EAP_MINIMUM_RELEASE_TRACES) + #undef EAP_FILE_NUMBER_ENUM + #define EAP_FILE_NUMBER_ENUM 590 + #undef EAP_FILE_NUMBER_DATE + #define EAP_FILE_NUMBER_DATE 1127594498 +#endif //#if defined(USE_EAP_MINIMUM_RELEASE_TRACES) + + +#if defined(USE_EAP_SIMPLE_CONFIG) + +#include "eap_am_memory.h" +#include "eap_type_simple_config_types.h" +#include "eap_type_simple_config.h" +#include "eap_type_simple_config_header.h" +#include "eap_type_simple_config_state_notification.h" +#include "eap_am_type_simple_config.h" +#include "eap_state_notification.h" +#include "simple_config_tlv_header.h" +#include "simple_config_base_record.h" +#include "eap_config.h" +#include "eap_header_string.h" + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_type_simple_config_c::~eap_type_simple_config_c() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("%s: function: eap_type_simple_config_c::~eap_type_simple_config_c(): this = 0x%08x => 0x%08x,") + EAPL(" m_am_type_simple_config = 0x%08x (validity %d).\n"), + (m_is_client == true ? "client": "server"), + this, + dynamic_cast(this), + m_am_type_simple_config, + m_am_type_simple_config->get_is_valid())); + + EAP_ASSERT(m_shutdown_was_called == true); + + if (m_free_simple_config_record == true) + { + delete m_simple_config_record; + m_simple_config_record = 0; + } + + if (m_free_am_type_simple_config == true) + { + delete m_am_type_simple_config; + m_am_type_simple_config = 0; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_type_simple_config_c::eap_type_simple_config_c( + abs_eap_am_tools_c * const tools, ///< This is pointer to the tools AM of current platform. + abs_eap_base_type_c * const partner, ///< This is back pointer to object which created this object. + eap_am_type_simple_config_c * const am_type_simple_config, ///< This is pointer to adaptation module of EAP-SIMPLE_CONFIG type. + const bool free_am_type_simple_config, + simple_config_base_record_c * const simple_config_record, /// This is pointer to SIMPLE_CONFIG implementation. + const bool free_simple_config_record, + const bool is_client_when_true, ///< Indicates whether this is client (true) or server (false). + const eap_type_value_e current_eap_type, ///< This the current EAP-type (SIMPLE_CONFIG or PEAP). + const eap_am_network_id_c * const receive_network_id) + : eap_base_type_c(tools, partner) + , m_am_tools(tools) + , m_am_type_simple_config(am_type_simple_config) + , m_simple_config_record(simple_config_record) + , m_nai_realm(tools) + , m_NAI(tools) + , m_send_network_id(tools) + , m_simple_config_header_offset(0u) + , m_MTU(0u) + , m_trailer_length(0u) + , m_state(eap_type_simple_config_state_waiting_for_identity_request) + , m_saved_previous_state(eap_type_simple_config_state_waiting_for_identity_request) + , m_reassembly_state(eap_type_simple_config_reassembly_state_wait_first_message) + , m_saved_previous_reassembly_state(eap_type_simple_config_reassembly_state_wait_first_message) + , m_simple_config_message_send_offset(0ul) + , m_simple_config_message_buffer(tools) + , m_first_fragment_eap_identifier(0ul) + , m_free_am_type_simple_config(free_am_type_simple_config) + , m_free_simple_config_record(free_simple_config_record) + , m_is_valid(false) + , m_is_client(is_client_when_true) + , m_check_identifier_of_eap_identity_response(false) + , m_simple_config_test_version(false) + , m_check_nai_realm(false) + , m_failure_message_received(false) + , m_authentication_finished_successfully(false) + , m_last_eap_identifier(0ul) + , m_shutdown_was_called(false) + , m_simple_config_message_type(simple_config_Message_Type_None) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("%s: function: eap_type_simple_config_c::eap_type_simple_config_c(): ") + EAPL("this = 0x%08x => 0x%08x, compiled %s %s\n"), + (m_is_client == true ? "client": "server"), + this, + dynamic_cast(this), + __DATE__, + __TIME__)); + + if (receive_network_id == 0 + || receive_network_id->get_is_valid_data() == false) + { + // No need to delete anything here because it is done in destructor. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return; + } + + if (simple_config_record == 0) + { + // No need to delete anything here because it is done in destructor. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return; + } + m_simple_config_record->set_type_partner(this); + + if (m_am_type_simple_config == 0) + { + // Something wrong with AM. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return; + } + m_am_type_simple_config->set_am_partner(this); + + + // Here we swap the addresses. + eap_am_network_id_c send_network_id( + m_am_tools, + receive_network_id->get_destination_id(), + receive_network_id->get_source_id(), + receive_network_id->get_type()); + + eap_status_e status = get_send_network_id()->set_copy_of_network_id( + &send_network_id); + if (status != eap_status_ok) + { + EAP_UNREFERENCED_PARAMETER(current_eap_type); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return; + } + + if (m_is_client == false) + { + // Server waits EAP-Response/Identity. + m_state = eap_type_simple_config_state_waiting_for_identity_response; + m_saved_previous_state + = eap_type_simple_config_state_waiting_for_identity_response; + } + + set_is_valid(); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT void eap_type_simple_config_c::save_current_state() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + m_saved_previous_state = m_state; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT void eap_type_simple_config_c::restore_saved_previous_state() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + set_state(m_saved_previous_state); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT void eap_type_simple_config_c::set_state( + const eap_type_simple_config_state_variable_e state) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_type_simple_config_state_variable_e previous_state = m_state; + EAP_UNREFERENCED_PARAMETER(previous_state); // This is used only for debugging. + + if (m_state != eap_type_simple_config_state_failure) + { + m_state = state; + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_simple_config_c::set_state(): ") + EAPL("%s: Previous state %d=%s, new state %d=%s.\n"), + (m_is_client == true ? "client": "server"), + previous_state, + get_state_string(previous_state), + m_state, + get_state_string(m_state))); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_type_simple_config_reassembly_state_e eap_type_simple_config_c::get_reassembly_state() const +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return m_reassembly_state; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT void eap_type_simple_config_c::set_reassembly_state( + const eap_type_simple_config_reassembly_state_e state) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + m_reassembly_state = state; + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT void eap_type_simple_config_c::save_current_reassembly_state() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + m_saved_previous_reassembly_state = m_reassembly_state; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT void eap_type_simple_config_c::restore_saved_reassembly_state() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + m_reassembly_state = m_saved_previous_reassembly_state; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_am_network_id_c * eap_type_simple_config_c::get_send_network_id() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return &m_send_network_id; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT void eap_type_simple_config_c::set_last_eap_identifier(const u8_t last_eap_identifier) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + m_last_eap_identifier = last_eap_identifier; + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_simple_config_c::set_last_eap_identifier():") + EAPL("%s, saved EAP-identifier %d, state %s\n"), + (m_is_client == true ? "client": "server"), + m_last_eap_identifier, + get_state_string())); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT u8_t eap_type_simple_config_c::get_last_eap_identifier() const +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_simple_config_c::get_last_eap_identifier():") + EAPL("%s, saved EAP-identifier %d, state %s\n"), + (m_is_client == true ? "client": "server"), + m_last_eap_identifier, + get_state_string())); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return m_last_eap_identifier; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_const_string eap_type_simple_config_c::get_state_string( + eap_type_simple_config_state_variable_e state) +{ + +#if defined(USE_EAP_TRACE_STRINGS) + EAP_IF_RETURN_STRING(state, eap_type_simple_config_state_waiting_for_identity_request) + else EAP_IF_RETURN_STRING(state, eap_type_simple_config_state_pending_identity_query) + else EAP_IF_RETURN_STRING(state, eap_type_simple_config_state_waiting_for_simple_config_start) + else EAP_IF_RETURN_STRING(state, eap_type_simple_config_state_process_simple_config_start) + else EAP_IF_RETURN_STRING(state, eap_type_simple_config_state_waiting_for_request) + else EAP_IF_RETURN_STRING(state, eap_type_simple_config_state_waiting_for_identity_response) + else EAP_IF_RETURN_STRING(state, eap_type_simple_config_state_waiting_for_response) + else EAP_IF_RETURN_STRING(state, eap_type_simple_config_state_process_simple_config_message) + else EAP_IF_RETURN_STRING(state, eap_type_simple_config_state_success) + else EAP_IF_RETURN_STRING(state, eap_type_simple_config_state_failure) + else +#else + EAP_UNREFERENCED_PARAMETER(state); +#endif // #if defined(USE_EAP_TRACE_STRINGS) + { + return EAPL("Unknown EAP-SIMPLE_CONFIG state"); + } +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_const_string eap_type_simple_config_c::get_reassembly_state_string( + eap_type_simple_config_reassembly_state_e state) +{ + +#if defined(USE_EAP_TRACE_STRINGS) + EAP_IF_RETURN_STRING(state, eap_type_simple_config_reassembly_state_none) + else EAP_IF_RETURN_STRING(state, eap_type_simple_config_reassembly_state_wait_first_message) + else EAP_IF_RETURN_STRING(state, eap_type_simple_config_reassembly_state_wait_last_fragment) + else EAP_IF_RETURN_STRING(state, eap_type_simple_config_reassembly_state_message_reassembled) + else +#else + EAP_UNREFERENCED_PARAMETER(state); +#endif // #if defined(USE_EAP_TRACE_STRINGS) + { + return EAPL("Unknown SIMPLE_CONFIG reassembly state"); + } +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_const_string eap_type_simple_config_c::get_state_string() const +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return get_state_string(m_state); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_const_string eap_type_simple_config_c::get_reassembly_state_string() const +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return get_reassembly_state_string(m_reassembly_state); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_const_string eap_type_simple_config_c::get_saved_previous_state_string() const +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return get_state_string(m_saved_previous_state); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT void eap_type_simple_config_c::set_failure_message_received() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + m_failure_message_received = true; +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT void eap_type_simple_config_c::unset_failure_message_received() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + m_failure_message_received = false; +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT bool eap_type_simple_config_c::get_failure_message_received() const +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return m_failure_message_received; +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_type_simple_config_state_variable_e eap_type_simple_config_c::get_state() const +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return m_state; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_variable_data_c * eap_type_simple_config_c::get_nai_realm() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return &m_nai_realm; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_variable_data_c * eap_type_simple_config_c::get_NAI() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return &m_NAI; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT void eap_type_simple_config_c::update_buffer_indexes( + const u32_t maximum_buffer_size, + const u32_t payload_size, + u32_t * const buffer_offset, + u32_t * const buffer_free) +{ + EAP_UNREFERENCED_PARAMETER(maximum_buffer_size); + + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_ASSERT_ALWAYS(*buffer_offset + *buffer_free <= maximum_buffer_size-m_trailer_length); + EAP_ASSERT_ALWAYS(*buffer_free >= payload_size); + EAP_ASSERT_ALWAYS(m_simple_config_header_offset+m_MTU == *buffer_offset + *buffer_free); + + *buffer_free -= payload_size; + *buffer_offset += payload_size; + + EAP_ASSERT_ALWAYS(*buffer_offset + *buffer_free <= maximum_buffer_size-m_trailer_length); + EAP_ASSERT_ALWAYS(*buffer_offset <= m_simple_config_header_offset+m_MTU); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT void eap_type_simple_config_c::update_payload_indexes( + const u32_t /*maximum_buffer_size*/, + const u32_t /*eap_header_size*/, + const u32_t /*payload_size*/, + u32_t * const /*data_offset*/, + u32_t * const /*data_free*/, + u32_t * const /*buffer_offset*/, + u32_t * const /*buffer_free*/) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::parse_identity( + const u8_t * const identity, ///< This is pointer to received EAP-Identity buffer. + const u32_t identity_length ///< This is length of received EAP-Identity buffer. + ) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (identity_length < 1u) + { + // Anonymous identity. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); + } + + const u8_t *at_character = reinterpret_cast( + m_am_tools->memchr( + identity, + EAP_SIMPLE_CONFIG_AT_CHARACTER, + identity_length)); + if (at_character == 0) + { + // No realm. + // This is allowed. + } + + eap_status_e status = check_NAI(identity, identity_length, at_character); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = eap_status_process_general_error; + + status = get_NAI()->set_copy_of_buffer(identity, identity_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("SIMPLE_CONFIG received EAP-identity NAI"), + get_NAI()->get_data(get_NAI()->get_data_length()), + get_NAI()->get_data_length())); + + if (get_NAI()->get_data_length() != EAP_SIMPLE_CONFIG_ENROLLEE_IDENTITY_LENGTH + || m_am_tools->memcmp( + get_NAI()->get_data(), + EAP_SIMPLE_CONFIG_ENROLLEE_IDENTITY, + EAP_SIMPLE_CONFIG_ENROLLEE_IDENTITY_LENGTH) != 0) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::simple_config_packet_send( + eap_buf_chain_wr_c * const sent_packet, + const simple_config_Message_Type_e message_type + ) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_SIMPLE_CONFIG: %s: function: simple_config_packet_send()\n"), + (m_is_client == true ? "client": "server"))); + + eap_status_e status = eap_status_not_supported; + + if ((m_is_client == true + && get_state() == eap_type_simple_config_state_process_simple_config_start) + || get_state() == eap_type_simple_config_state_process_simple_config_message + || get_state() == eap_type_simple_config_state_waiting_for_request // This state is needed to send messages from asyncronous completions. + || get_state() == eap_type_simple_config_state_waiting_for_response // This state is needed to send messages from asyncronous completions. + || get_state() == eap_type_simple_config_state_success // This state is needed to send the WCS_Done message. + || get_state() == eap_type_simple_config_state_failure // This state is needed to send failure messages. + || (m_is_client == false + && get_state() == eap_type_simple_config_state_success) + ) + { + status = m_simple_config_message_buffer.set_copy_of_buffer( + sent_packet->get_data(sent_packet->get_data_length()), + sent_packet->get_data_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // This will start the packet send from begin of the message. + m_simple_config_message_send_offset = 0ul; + + // Save the type of the message for fragmentation + m_simple_config_message_type = message_type; + + status = eap_simple_config_fragment_send(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_SIMPLE_CONFIG_ERROR, + (EAPL("ERROR: eap_type_simple_config_c::simple_config_packet_send(): ") + EAPL("Cannot send EAP-SIMPLE_CONFIG message in ") + EAPL("eap_type_simple_config_state_variable_e %d=%s.\n"), + get_state(), + get_state_string())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_wrong_eap_type_state); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::packet_send( + const eap_am_network_id_c * const network_id, + eap_buf_chain_wr_c * const sent_packet, + const u32_t header_offset, + const u32_t data_length, + const u32_t buffer_length) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_SIMPLE_CONFIG: %s: function: packet_send()\n"), + (m_is_client == true ? "client": "server"))); + + eap_header_wr_c eap( + m_am_tools, + sent_packet->get_data_offset( + header_offset, data_length), + data_length); + if (eap.get_is_valid() == false) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("packet_send: packet buffer corrupted.\n"))); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error); + } + + packet_trace( + EAPL("<-"), + network_id, + &eap, + data_length); + + eap_status_e status = get_type_partner()->packet_send( + network_id, + sent_packet, + header_offset, + data_length, + buffer_length + ); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::check_NAI( + const u8_t * const identity, + const u32_t identity_length, + const u8_t * const at_character) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + bool includes_at = false; + bool includes_dot = false; + u32_t username_length = 0u; + u32_t realm_length = 0u; + + for (u32_t ind = 0; ind < identity_length; ind++) + { + const u8_t character = identity[ind]; + + if (includes_at == false) + { + if (character != EAP_SIMPLE_CONFIG_AT_CHARACTER) + { + ++username_length; + } + } + else + { + ++realm_length; + } + + + if ('0' <= character && character <= '9') + { + // OK. + } + else if ('a' <= character && character <= 'z') + { + // OK. + } + else if ('A' <= character && character <= 'Z') + { + // OK. + } + else if (character == EAP_SIMPLE_CONFIG_AT_CHARACTER) + { + if (includes_at == false) + { + includes_at = true; + } + else + { + // Second at ('@'). + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: Illegal NAI, includes second at \'@\' character."), + identity, + identity_length)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_nai); + } + } + else if (character == '.') + { + if (includes_at == true) + { + // OK. + includes_dot = true; + } + else + { + // dot ('.') within username + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: Illegal NAI, dot \'.\' within username."), + identity, + identity_length)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_nai); + } + } + else if (character == '<' + || character == '>' + || character == '(' + || character == ')' + || character == '[' + || character == ']' + || character == '\\' + || character == '.' + || character == ',' + || character == ';' + || character == ':' + || character == EAP_SIMPLE_CONFIG_AT_CHARACTER + || character == ' ' // space + || character <= 0x1f // Ctrl + || character >= 0x7f) // extented characters + { + // Illegal character. + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_SIMPLE_CONFIG_ERROR, + (EAPL("ERROR: Illegal NAI, includes illegal character 0x%02x=%c.\n"), + character, + character)); + EAP_TRACE_DATA_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: Illegal NAI, includes illegal character."), + identity, + identity_length)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_nai); + } + else + { + // All other ascii values are OK. + } + } + + // Note the username could be zero length. + if ((realm_length == 1u && includes_at == true) // one at ('@') is illegal. + || (realm_length == 2u && includes_at == true && includes_dot == true)) // one at ('@') and one dot is illegal. + { + EAP_TRACE_DATA_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("ERROR: Illegal NAI."), + identity, + identity_length)); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_nai); + } + + if (m_check_nai_realm == true) + { + if (at_character == 0 + && realm_length == 0 + && get_nai_realm()->get_data_length() == 0) + { + // OK, no realm. + } + else if (at_character == 0 + || realm_length != get_nai_realm()->get_data_length() + || m_am_tools->memcmp( + at_character+1u, + get_nai_realm()->get_data(get_nai_realm()->get_data_length()), + get_nai_realm()->get_data_length()) != 0) + { + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("Illegal NAI, realm unknown."), + identity, + identity_length)); + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("NAI should be"), + get_nai_realm()->get_data(get_nai_realm()->get_data_length()), + get_nai_realm()->get_data_length())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_nai); + } + } + + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT void eap_type_simple_config_c::packet_trace( + eap_const_string prefix, + const eap_am_network_id_c * const /*receive_network_id*/, + eap_header_wr_c * const eap_packet, + const u32_t eap_packet_length) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_UNREFERENCED_PARAMETER(prefix); // in release + + if (eap_packet_length > eap_header_base_c::get_header_length() + && eap_packet->get_type() == eap_expanded_type_simple_config.get_type()) + { + eap_simple_config_header_c * const received_simple_config + = reinterpret_cast(eap_packet); + + const u8_t * const p_simple_config_flags = received_simple_config->get_simple_config_flags(); + u8_t simple_config_flags = 0u; + EAP_UNREFERENCED_PARAMETER(simple_config_flags); // in release + if (p_simple_config_flags != 0) + { + simple_config_flags = *p_simple_config_flags; + } + + u32_t simple_config_message_length = 0ul; + if (received_simple_config->get_simple_config_message_length(&simple_config_message_length) != eap_status_ok) + { + simple_config_message_length = 0ul; + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("%s EAP-SIMPLE_CONFIG header %s: code=0x%02x=%s, identifier=0x%02x=%d, ") + EAPL("length=0x%04x=%d, ") + EAPL("type=0x%08x=%s, OP-Code=0x%02x=%s, SIMPLE_CONFIG-flags=0x%02x %s%s, SIMPLE_CONFIG-length=0x%08x=%d.\n"), + prefix, + (m_is_client == true) ? "client": "server", + received_simple_config->get_code(), + received_simple_config->get_code_string(), + received_simple_config->get_identifier(), + received_simple_config->get_identifier(), + received_simple_config->get_length(), + received_simple_config->get_length(), + convert_eap_type_to_u32_t(received_simple_config->get_type()), + received_simple_config->get_eap_type_string(), + received_simple_config->get_sc_op_code(), + received_simple_config->get_sc_op_code_string(), + simple_config_flags, + (simple_config_flags & eap_simple_config_header_c::m_flag_mask_simple_config_length_included) ? "L": " ", + (simple_config_flags & eap_simple_config_header_c::m_flag_mask_more_fragments) ? "M": " ", + simple_config_message_length, + simple_config_message_length)); + } + else + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL("%s EAP header %s: code=0x%02x=%s, identifier=0x%02x, length=0x%04x=%d, ") + EAPL("type=0x%08x=%s\n"), + prefix, + (m_is_client == true) ? "client": "server", + eap_packet->get_code(), + eap_packet->get_code_string(), + eap_packet->get_identifier(), + eap_packet->get_length(), + eap_packet->get_length(), + convert_eap_type_to_u32_t(eap_packet->get_type()), + eap_packet->get_type_string())); + + EAP_TRACE_DEBUG( + m_am_tools, + eap_am_tools_c::eap_trace_mask_eap_messages, + (EAPL("\n\t%s\n\tcode = 0x%02x = %s\n\tidentifier = 0x%02x\n\t") + EAPL("length = 0x%04x = %lu\n\ttype = 0x%08x = %s\n"), + (m_is_client == true) ? "client": "server", + eap_packet->get_code(), + eap_packet->get_code_string(), + eap_packet->get_identifier(), + eap_packet->get_length(), + eap_packet->get_length(), + convert_eap_type_to_u32_t(eap_packet->get_type()), + eap_packet->get_type_string())); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::finish_successful_authentication() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_SIMPLE_CONFIG: %s: function: finish_successful_authentication()\n"), + (m_is_client == true ? "client": "server"))); + + eap_simple_config_trace_string_c simple_config_trace; + EAP_TRACE_ALWAYS( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL("EAP_type_SIMPLE_CONFIG: %s, EAP-type %s EAP-SUCCESS\n"), + ((m_is_client == true) ? "client": "server"), + eap_header_string_c::get_eap_type_string(eap_expanded_type_simple_config.get_type()))); + + set_state(eap_type_simple_config_state_success); + + // Note, authentication is always terminated unsuccessfully. + // Server will send EAP-Failure always. + // Client should accept EAP-Failure quietly. + { + eap_state_notification_c notification( + m_am_tools, + get_send_network_id(), + m_is_client, + eap_state_notification_eap, + eap_protocol_layer_eap, + eap_expanded_type_simple_config.get_type(), + eap_state_none, + eap_state_use_eap_failure_in_termination, + get_last_eap_identifier(), // Note the EAP-Failure uses the same EAP-Identifier as the last EAP-Request. + false); + get_type_partner()->state_notification(¬ification); + } + + eap_state_notification_c notification( + m_am_tools, + get_send_network_id(), + m_is_client, + eap_state_notification_eap, + eap_protocol_layer_eap, + eap_expanded_type_simple_config.get_type(), + eap_state_none, + eap_state_authentication_finished_successfully, + get_last_eap_identifier(), // Note the EAP-Success uses the same EAP-Identifier as the last EAP-Request. + false); + get_type_partner()->state_notification(¬ification); + + // Indicate EAP-SIMPLE_CONFIG AM authentication finished successfully. + m_am_type_simple_config->authentication_finished(true, false); + + m_authentication_finished_successfully = true; + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_success); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::send_final_notification() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_SIMPLE_CONFIG: %s: function: send_final_notification()\n"), + (m_is_client == true ? "client": "server"))); + + if (m_is_valid == true + && m_authentication_finished_successfully == false) + { + eap_simple_config_trace_string_c simple_config_trace; + EAP_TRACE_ALWAYS( + m_am_tools, + TRACE_FLAGS_DEFAULT|TRACE_TEST_VECTORS, + (EAPL("EAP_type_SIMPLE_CONFIG: %s, EAP-type %s FAILED\n"), + ((m_is_client == true) ? "client": "server"), + eap_header_string_c::get_eap_type_string(eap_expanded_type_simple_config.get_type()))); + + set_state(eap_type_simple_config_state_failure); + + // Notifies the lower level of unsuccessfull authentication. + eap_state_notification_c notification( + m_am_tools, + get_send_network_id(), + m_is_client, + eap_state_notification_eap, + eap_protocol_layer_eap, + eap_expanded_type_simple_config.get_type(), + eap_state_none, + eap_state_authentication_terminated_unsuccessfully, + get_last_eap_identifier(), + false); + + notification.set_authentication_error(eap_status_authentication_failure); + + get_type_partner()->state_notification(¬ification); + + // Indicate EAP-SIMPLE_CONFIG AM authentication terminated unsuccessfully. + m_am_type_simple_config->authentication_finished(false, false); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT bool eap_type_simple_config_c::get_is_client() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return m_is_client; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::handle_eap_identity_query( + const eap_am_network_id_c * const receive_network_id, + const u8_t eap_identifier, + const bool use_manual_username, + const eap_variable_data_c * const manual_username, + const bool use_manual_realm, + const eap_variable_data_c * const manual_realm + ) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = eap_status_process_general_error; + eap_variable_data_c local_identity(m_am_tools); + + // Here we swap the addresses. + eap_am_network_id_c send_network_id( + m_am_tools, + receive_network_id->get_destination_id(), + receive_network_id->get_source_id(), + receive_network_id->get_type()); + + if (use_manual_username == true + && manual_username != 0 + && manual_username->get_is_valid() == true + && use_manual_realm == true + && manual_realm != 0 + && manual_realm->get_is_valid() == true) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_SIMPLE_CONFIG: %s: eap_type_simple_config_c::handle_eap_identity_query(): manual username and manual realm.\n"), + (m_is_client == true ? "client": "server"))); + + // Here manual username could be zero or more bytes in length. + status = local_identity.set_copy_of_buffer(manual_username); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + if (manual_realm->get_data_length() > 0ul) + { + // When manual realm is one or more bytes in length + // we add @ and manual realm to the identity. + u8_t at_char = EAP_SIMPLE_CONFIG_AT_CHARACTER; + status = local_identity.add_data(&at_char, sizeof(at_char)); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = local_identity.add_data(manual_realm); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + } + else if (use_manual_username == true + && manual_username != 0 + && manual_username->get_is_valid() == true + && use_manual_realm == false) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_SIMPLE_CONFIG: %s: eap_type_simple_config_c::handle_eap_identity_query(): manual username.\n"), + (m_is_client == true ? "client": "server"))); + + status = local_identity.set_copy_of_buffer(manual_username); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_SIMPLE_CONFIG: %s: eap_type_simple_config_c::handle_eap_identity_query(): no identity.\n"), + (m_is_client == true ? "client": "server"))); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_eap_identity); + } + + status = get_NAI()->set_copy_of_buffer(&local_identity); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_simple_config_c::handle_eap_identity_query(): identity"), + local_identity.get_data(), + local_identity.get_data_length())); + + + status = get_type_partner()->complete_eap_identity_query( + &send_network_id, + &local_identity, + eap_identifier); + if (status == eap_status_ok) + { + set_state(eap_type_simple_config_state_waiting_for_simple_config_start); + } + else + { + get_NAI()->reset(); + restore_saved_previous_state(); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::complete_eap_identity_query( + const eap_am_network_id_c * const receive_network_id, + const u8_t eap_identifier, + const eap_status_e completion_status, + const bool use_manual_username, + const eap_variable_data_c * const manual_username, + const bool use_manual_realm, + const eap_variable_data_c * const manual_realm + ) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (m_state == eap_type_simple_config_state_pending_identity_query) + { + if (completion_status != eap_status_ok) + { + set_state(eap_type_simple_config_state_failure); + + // The completion_status error value is more important + // than return value of set_session_timeout(). + get_type_partner()->set_session_timeout(0ul); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, completion_status); + } + + eap_status_e status = handle_eap_identity_query( + receive_network_id, + eap_identifier, + use_manual_username, + manual_username, + use_manual_realm, + manual_realm); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_SIMPLE_CONFIG_ERROR, + (EAPL("ERROR: eap_type_simple_config_c::complete_eap_identity_query(): ") + EAPL("Illegal EAP-Identity query completion in ") + EAPL("eap_type_simple_config_state_variable_e %d=%s.\n"), + get_state(), + get_state_string())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_wrong_eap_type_state); + } +} + +//-------------------------------------------------- + +// +eap_status_e eap_type_simple_config_c::check_received_eap_identifier( + const eap_header_wr_c * const eap_header) +{ + if (m_is_client == false + && eap_header->get_type() == eap_type_identity + && eap_header->get_code() == eap_code_response + && m_check_identifier_of_eap_identity_response == true + && eap_header->get_identifier() != get_last_eap_identifier()) + { + eap_status_e status(eap_status_unexpected_message); + + eap_status_string_c status_string; + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_SIMPLE_CONFIG_ERROR, + (EAPL("ERROR: eap_type_simple_config_c::packet_process() failed,") + EAPL("status %d=%s, received EAP-type 0x%08x, received EAP-code %d, ") + EAPL("received EAP-identifier %d, current EAP-identifier %d, state %s\n"), + status, + status_string.get_status_string(status), + convert_eap_type_to_u32_t(eap_header->get_type()), + eap_header->get_code(), + eap_header->get_identifier(), + get_last_eap_identifier(), + get_state_string())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (m_is_client == false + && eap_header->get_type() == eap_expanded_type_simple_config.get_type() + && eap_header->get_identifier() != get_last_eap_identifier()) + { + eap_status_e status(eap_status_unexpected_message); + + eap_status_string_c status_string; + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_SIMPLE_CONFIG_ERROR, + (EAPL("ERROR: eap_type_simple_config_c::packet_process() failed,") + EAPL("status %d=%s, received EAP-identifier %d, ") + EAPL("current EAP-identifier %d, state %s\n"), + status, + status_string.get_status_string(status), + eap_header->get_identifier(), + get_last_eap_identifier(), + get_state_string())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (m_is_client == true + && eap_header->get_identifier() == get_last_eap_identifier()) + { + // Client have received this packet already. + eap_status_e status(eap_status_drop_packet_quietly); + + eap_status_string_c status_string; + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("WARNING: eap_type_simple_config_c::packet_process() failed,") + EAPL("status %d=%s, drops already received EAP-identifier %d, ") + EAPL("current EAP-identifier %d, state %s\n"), + status, + status_string.get_status_string(status), + eap_header->get_identifier(), + get_last_eap_identifier(), + get_state_string())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::packet_process( + const eap_am_network_id_c * const receive_network_id, ///< This is the network identity of the received EAP packet. + eap_header_wr_c * const eap_header, ///< This is pointer to EAP header and data. + const u32_t eap_packet_length ///< This is length of received EAP packet. + ) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_SIMPLE_CONFIG: %s: function: packet_process()\n"), + (m_is_client == true ? "client": "server"))); + + packet_trace( + EAPL("->"), + receive_network_id, + eap_header, + eap_packet_length); + + if (eap_packet_length < eap_header->get_length()) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_packet_length=0x%04x < eap_header->get_length()=0x%04x.\n"), + eap_packet_length, eap_header->get_length())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_illegal_packet_error); + } + + if (eap_header->get_length() < eap_header_base_c::get_header_length()) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_SIMPLE_CONFIG_ERROR, + (EAPL("ERROR: eap_type_simple_config_c::packet_process(): ") + EAPL("eap_header->get_length() < eap_header_base_c::get_header_length().\n"))); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_illegal_packet_error); + } + + + // NOTE: by disabling these calls throughput increases about 18%. + // Disabling also decreases random seeds. + m_am_tools->get_crypto()->add_rand_seed( + eap_header->get_header_buffer(eap_packet_length), + eap_packet_length); + m_am_tools->get_crypto()->add_rand_seed_hw_ticks(); + + eap_status_e status = eap_status_process_general_error; + + if ((m_is_client == true + && eap_header->get_code() == eap_code_request) + || (m_is_client == false + && eap_header->get_code() == eap_code_response)) + { + if (eap_header->get_type() == eap_type_identity + || eap_header->get_type() == eap_expanded_type_simple_config.get_type()) + { + eap_simple_config_header_c simple_config_header( + m_am_tools, + eap_header->get_header_buffer(eap_packet_length), + eap_packet_length); + + if (eap_header->get_type() == eap_type_identity + && eap_header->get_code() == eap_code_request) + { + // EAP-Request/Identity is handled in eap_core_c. + status = eap_status_unexpected_message; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (eap_header->get_type() == eap_type_identity + && eap_header->get_code() == eap_code_response + && eap_header->get_length() <= eap_header_base_c::get_header_length()) + { + status = eap_status_header_corrupted; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (eap_header->get_type() == eap_expanded_type_simple_config.get_type() + && eap_header->get_length() < simple_config_header.get_simple_config_min_header_length()) + { + status = eap_status_header_corrupted; + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (check_received_eap_identifier(eap_header) != eap_status_ok) + { + status = eap_status_unexpected_message; + eap_status_string_c status_string; + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_SIMPLE_CONFIG_ERROR, + (EAPL("ERROR: eap_type_simple_config_c::packet_process() failed,") + EAPL("status %d=%s, received EAP-type 0x%08x, received EAP-code %d, ") + EAPL("received EAP-identifier %d, current EAP-identifier %d, state %s\n"), + status, + status_string.get_status_string(status), + convert_eap_type_to_u32_t(eap_header->get_type()), + eap_header->get_code(), + eap_header->get_identifier(), + get_last_eap_identifier(), + get_state_string())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else + { + if (m_is_client == true) + { + // Client saves the received EAP-Identifier. + set_last_eap_identifier(eap_header->get_identifier()); + } + + if (eap_header->get_type() == eap_type_identity) + { + status = eap_identity_response_packet_process( + receive_network_id, + eap_header, + eap_packet_length); + + if (status != eap_status_ok + && status != eap_status_success + && status != eap_status_drop_packet_quietly) + { + eap_status_string_c status_string; + + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_SIMPLE_CONFIG_ERROR, + (EAPL("ERROR: eap_type_simple_config_c::") + EAPL("eap_identity_response_packet_process() failed, status %d=%s\n"), + status, status_string.get_status_string(status))); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + if (status == eap_status_ok) + { + EAP_GENERAL_HEADER_SET_ERROR_DETECTED(eap_header, false); + + eap_state_notification_c notification( + m_am_tools, + get_send_network_id(), + m_is_client, + eap_state_notification_eap, + eap_protocol_layer_eap, + eap_expanded_type_simple_config.get_type(), + eap_state_none, + eap_state_identity_response_received, + get_last_eap_identifier(), + false); + get_type_partner()->state_notification(¬ification); + } + } + else + { + status = simple_config_packet_process( + receive_network_id, + &simple_config_header, + eap_packet_length); + + if (status == eap_status_ok) + { + EAP_GENERAL_HEADER_SET_ERROR_DETECTED(eap_header, false); + } + + if (status != eap_status_ok + && status != eap_status_success + && status != eap_status_pending_request + && status != eap_status_drop_packet_quietly) + { + eap_status_string_c status_string; + + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_SIMPLE_CONFIG_ERROR, + (EAPL("ERROR: eap_type_simple_config_c::simple_config_packet_process() ") + EAPL("failed, status %d=%s\n"), + status, status_string.get_status_string(status))); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (eap_header->get_type() == eap_type_notification) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("dropped EAP type notification: code=0x%02x, identifier=0x%02x, ") + EAPL("length=0x%04x, type=0x%08x\n"), + eap_header->get_code(), + eap_header->get_identifier(), + eap_header->get_length(), + convert_eap_type_to_u32_t(eap_header->get_type()))); + + status = eap_status_illegal_eap_type; + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("dropped EAP type unknown: code=0x%02x, identifier=0x%02x, ") + EAPL("length=0x%04x, type=0x%08x\n"), + eap_header->get_code(), + eap_header->get_identifier(), + eap_header->get_length(), + convert_eap_type_to_u32_t(eap_header->get_type()))); + + status = eap_status_illegal_eap_type; + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else if (eap_header->get_code() == eap_code_success + || eap_header->get_code() == eap_code_failure) + { + // Here we swap the addresses. + eap_am_network_id_c send_network_id(m_am_tools, + receive_network_id->get_destination_id(), + receive_network_id->get_source_id(), + receive_network_id->get_type()); + + if (eap_header->get_code() == eap_code_success) + { + if (get_state() == eap_type_simple_config_state_success) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("quietly dropped EAP-Success: code=0x%02x, identifier=0x%02x, ") + EAPL("length=0x%04x, state %d=%s, is client %d\n"), + eap_header->get_code(), + eap_header->get_identifier(), + eap_header->get_length(), + get_state(), + get_state_string(), + (m_is_client == true))); + status = eap_status_drop_packet_quietly; + } + else + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("dropped EAP-Success: code=0x%02x, identifier=0x%02x, ") + EAPL("length=0x%04x, state %d=%s, is client %d\n"), + eap_header->get_code(), + eap_header->get_identifier(), + eap_header->get_length(), + get_state(), + get_state_string(), + (m_is_client == true))); + status = eap_status_illegal_eap_code; + } + } + else if (eap_header->get_code() == eap_code_failure) + { + // EAP is quite sloppy protocol. + // Somebody just send a EAP-failure message and authentication is terminated. + + // Save received failure. We do not change our state yet. + // The real correct EAP message could be received later if this failure was + // send by nasty attacker. + set_failure_message_received(); + // We handle the EAP-Request/Failure message after a timeout. + + status = eap_status_ok; + } + else + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("dropped EAP code unknown: code=0x%02x, identifier=0x%02x, ") + EAPL("length=0x%04x, is client %d\n"), + eap_header->get_code(), + eap_header->get_identifier(), + eap_header->get_length(), + (m_is_client == true))); + status = eap_status_illegal_eap_code; + } + } + else + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("dropped EAP code unknown: code=0x%02x, identifier=0x%02x, ") + EAPL("length=0x%04x, is client %d\n"), + eap_header->get_code(), + eap_header->get_identifier(), + eap_header->get_length(), + (m_is_client == true))); + status = eap_status_illegal_eap_code; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::send_sc_frag_ack() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_buf_chain_wr_c eap_fragment_acknowledge_packet( + eap_write_buffer, + m_am_tools, + SIMPLE_CONFIG_LOCAL_PACKET_BUFFER_LENGTH); + + if (eap_fragment_acknowledge_packet.get_is_valid() == false) + { + EAP_TRACE_ERROR(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("packet buffer corrupted.\n"))); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + EAP_ASSERT_ALWAYS(SIMPLE_CONFIG_LOCAL_PACKET_BUFFER_LENGTH + >= (m_simple_config_header_offset+m_trailer_length)); + u32_t packet_buffer_free = SIMPLE_CONFIG_LOCAL_PACKET_BUFFER_LENGTH-m_trailer_length; + u32_t packet_buffer_offset = 0u; + + if (m_simple_config_header_offset+m_MTU < packet_buffer_free) + { + packet_buffer_free = m_simple_config_header_offset+m_MTU; + } + + eap_simple_config_header_c fragment_acknowledge( + m_am_tools, + eap_fragment_acknowledge_packet.get_data_offset( + m_simple_config_header_offset, + (packet_buffer_free-m_simple_config_header_offset)), + (packet_buffer_free-m_simple_config_header_offset)); + + if (fragment_acknowledge.get_is_valid() == false) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("packet_send: packet buffer corrupted.\n"))); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error); + } + + fragment_acknowledge.reset_header( + m_am_tools, + static_cast(packet_buffer_free-m_simple_config_header_offset), + true); + + fragment_acknowledge.set_eap_length( + static_cast(packet_buffer_free-m_simple_config_header_offset), + true); + + if (m_is_client == true) + { + fragment_acknowledge.set_eap_code(eap_code_response); + fragment_acknowledge.set_eap_identifier(static_cast(get_last_eap_identifier())); + } + else // if (m_is_client == false) + { + fragment_acknowledge.set_eap_code(eap_code_request); + fragment_acknowledge.set_eap_identifier(static_cast(get_last_eap_identifier()+1u)); + } + + fragment_acknowledge.set_eap_type( + eap_expanded_type_simple_config.get_type(), + true); + + fragment_acknowledge.set_sc_op_code(eap_simple_config_header_c::op_code_FRAG_ACK); + + u32_t simple_config_data_offset = 0u; + + update_buffer_indexes( + SIMPLE_CONFIG_LOCAL_PACKET_BUFFER_LENGTH, + m_simple_config_header_offset+fragment_acknowledge.get_header_length(), + &packet_buffer_offset, + &packet_buffer_free); + + // - - - - - - - - - - - - - - - - - - - - - - - - + + // No payloads. + + fragment_acknowledge.set_data_length( + simple_config_data_offset, + true); + eap_fragment_acknowledge_packet.set_data_length(packet_buffer_offset); + + EAP_ASSERT_ALWAYS( + m_simple_config_header_offset + +fragment_acknowledge.get_header_length() + +fragment_acknowledge.get_data_length() + == packet_buffer_offset); + + eap_status_e status = eap_status_process_general_error; + + // - - - - - - - - - - - - - - - - - - - - - - - - + + if (m_is_client == true) + { + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL(" send: EAP-Response/SIMPLE_CONFIG/Acknowledge packet"), + fragment_acknowledge.get_header_buffer(fragment_acknowledge.get_eap_length()), + fragment_acknowledge.get_eap_length())); + } + else // if (m_is_client == false) + { + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL(" send: EAP-Request/SIMPLE_CONFIG/Acknowledge packet"), + fragment_acknowledge.get_header_buffer(fragment_acknowledge.get_eap_length()), + fragment_acknowledge.get_eap_length())); + } + + status = packet_send( + get_send_network_id(), + &eap_fragment_acknowledge_packet, + m_simple_config_header_offset, + fragment_acknowledge.get_eap_length(), + SIMPLE_CONFIG_LOCAL_PACKET_BUFFER_LENGTH + ); + + if (status == eap_status_ok) + { + if (m_is_client == false) + { + // Server saves the sent EAP-Identifier. + set_last_eap_identifier(static_cast(get_last_eap_identifier()+1ul)); + } + } + + // - - - - - - - - - - - - - - - - - - - - - - - - + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::send_simple_config_start_message( + const u8_t next_eap_identifier ///< This is EAP-Identifier of next EAP packet. + ) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_buf_chain_wr_c eap_simple_config_start_packet( + eap_write_buffer, + m_am_tools, + SIMPLE_CONFIG_LOCAL_PACKET_BUFFER_LENGTH); + + if (eap_simple_config_start_packet.get_is_valid() == false) + { + EAP_TRACE_ERROR(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("packet buffer corrupted.\n"))); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + EAP_ASSERT_ALWAYS(SIMPLE_CONFIG_LOCAL_PACKET_BUFFER_LENGTH + >= (m_simple_config_header_offset+m_trailer_length)); + u32_t packet_buffer_free = SIMPLE_CONFIG_LOCAL_PACKET_BUFFER_LENGTH-m_trailer_length; + u32_t packet_buffer_offset = 0u; + + if (m_simple_config_header_offset+m_MTU < packet_buffer_free) + { + packet_buffer_free = m_simple_config_header_offset+m_MTU; + } + + eap_simple_config_header_c simple_config_start_packet( + m_am_tools, + eap_simple_config_start_packet.get_data_offset( + m_simple_config_header_offset, + (packet_buffer_free-m_simple_config_header_offset)), + (packet_buffer_free-m_simple_config_header_offset)); + + if (simple_config_start_packet.get_is_valid() == false) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("packet_send: packet buffer corrupted.\n"))); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error); + } + + simple_config_start_packet.reset_header( + m_am_tools, + static_cast(packet_buffer_free-m_simple_config_header_offset), + true); + + simple_config_start_packet.set_flag_simple_config_length_included(false); + + simple_config_start_packet.set_eap_length( + static_cast( + packet_buffer_free-m_simple_config_header_offset), + true); + + simple_config_start_packet.set_eap_code(eap_code_request); + simple_config_start_packet.set_eap_identifier(next_eap_identifier); + simple_config_start_packet.set_eap_type( + eap_expanded_type_simple_config.get_type(), + true); + simple_config_start_packet.set_sc_op_code(eap_simple_config_header_c::op_code_WSC_Start); + + update_buffer_indexes( + SIMPLE_CONFIG_LOCAL_PACKET_BUFFER_LENGTH, + m_simple_config_header_offset+simple_config_start_packet.get_header_length(), + &packet_buffer_offset, + &packet_buffer_free); + + // - - - - - - - - - - - - - - - - - - - - - - - - + + simple_config_start_packet.set_data_length( + 0ul, + true); + eap_simple_config_start_packet.set_data_length(packet_buffer_offset); + + EAP_ASSERT_ALWAYS( + m_simple_config_header_offset+simple_config_start_packet.get_header_length() + +simple_config_start_packet.get_data_length() + == packet_buffer_offset); + + eap_status_e status = eap_status_process_general_error; + + // - - - - - - - - - - - - - - - - - - - - - - - - + + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL(" send: EAP-Request/SIMPLE_CONFIG/Start packet"), + simple_config_start_packet.get_header_buffer(simple_config_start_packet.get_eap_length()), + simple_config_start_packet.get_eap_length())); + + status = packet_send( + get_send_network_id(), + &eap_simple_config_start_packet, + m_simple_config_header_offset, + simple_config_start_packet.get_eap_length(), + SIMPLE_CONFIG_LOCAL_PACKET_BUFFER_LENGTH + ); + + if (status == eap_status_ok) + { + if (m_is_client == false) + { + // Server saves the sent EAP-Identifier. + set_last_eap_identifier(next_eap_identifier); + + set_state(eap_type_simple_config_state_waiting_for_response); + } + } + + // - - - - - - - - - - - - - - - - - - - - - - - - + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::start_simple_config_authentication( + const eap_am_network_id_c * const /*receive_network_id*/, ///< This is the network identity of the received EAP packet. + const eap_variable_data_c * const NAI ///< This is the full NAI of the client. + ) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = m_simple_config_record->start_simple_config_authentication(NAI); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::eap_simple_config_fragment_send() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = eap_status_not_supported; + + if (m_simple_config_message_send_offset == 0ul + && m_simple_config_message_buffer.get_data_length() + < simple_config_tlv_header_c::get_header_length()) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_simple_config_fragment_send(): ") + EAPL("packet buffer too short, %d bytes.\n"), + m_simple_config_message_buffer.get_data_length())); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + else if (m_simple_config_message_buffer.get_data_length() + < m_simple_config_message_send_offset) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_simple_config_fragment_send(): ") + EAPL("packet buffer %d shorter than ") + EAPL("m_simple_config_message_send_offset %d.\n"), + m_simple_config_message_buffer.get_data_length(), + m_simple_config_message_send_offset)); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + + eap_buf_chain_wr_c eap_simple_config_fragment( + eap_write_buffer, + m_am_tools, + EAP_MAX_LOCAL_PACKET_BUFFER_LENGTH); + + if (eap_simple_config_fragment.get_is_valid() == false) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("packet buffer corrupted.\n"))); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_allocation_error); + } + + EAP_ASSERT_ALWAYS(EAP_MAX_LOCAL_PACKET_BUFFER_LENGTH + >= (m_simple_config_header_offset+m_trailer_length)); + u32_t packet_buffer_free + = EAP_MAX_LOCAL_PACKET_BUFFER_LENGTH-m_trailer_length; + u32_t packet_buffer_offset = 0u; + + if (m_simple_config_header_offset+m_MTU < packet_buffer_free) + { + packet_buffer_free = m_simple_config_header_offset+m_MTU; + } + + u32_t packet_eap_data_free + = packet_buffer_free + - m_simple_config_header_offset + - eap_simple_config_header_c::get_simple_config_max_header_length(); + + eap_simple_config_header_c eap_simple_config_packet( + m_am_tools, + eap_simple_config_fragment.get_data_offset( + m_simple_config_header_offset, + packet_eap_data_free), + packet_eap_data_free); + + if (eap_simple_config_packet.get_is_valid() == false) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("packet_send: packet buffer corrupted.\n"))); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error); + } + + eap_simple_config_packet.reset_header( + m_am_tools, + static_cast(packet_eap_data_free), + true); + if (m_simple_config_message_send_offset == 0) + { + // This is the first fragment. + eap_simple_config_packet.set_flag_simple_config_length_included(true); + eap_simple_config_packet.set_simple_config_message_length( + m_simple_config_message_buffer.get_data_length()); + } + + eap_simple_config_packet.set_eap_length( + static_cast(packet_eap_data_free), + true); + + if (m_is_client == true) + { + eap_simple_config_packet.set_eap_code(eap_code_response); + eap_simple_config_packet.set_eap_identifier(get_last_eap_identifier()); + } + else + { + eap_simple_config_packet.set_eap_code(eap_code_request); + eap_simple_config_packet.set_eap_identifier( + static_cast(get_last_eap_identifier()+1ul)); + } + + // -------------------------------------------------------------------- + + eap_simple_config_trace_string_c message_string; + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_simple_config_fragment_send: %s: message type: %s\n"), + (m_is_client == true ? "client": "server"), + message_string.get_message_type_string(m_simple_config_message_type))); + + EAP_UNREFERENCED_PARAMETER(message_string); // for release + + // Set Op-Code based on the message type + if( m_simple_config_message_type == simple_config_Message_Type_None + || m_simple_config_message_type == simple_config_Message_Type_Beacon + || m_simple_config_message_type == simple_config_Message_Type_Probe_Request + || m_simple_config_message_type == simple_config_Message_Type_Probe_Response + || m_simple_config_message_type > simple_config_Message_keep_this_last ) + { + // Something is wrong + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_simple_config_fragment_send: invalid message type, cannot set Op-Code correctly.\n"))); + return EAP_STATUS_RETURN(m_am_tools, eap_status_process_general_error); + } + else if( m_simple_config_message_type == simple_config_Message_Type_WSC_ACK ) + { + eap_simple_config_packet.set_sc_op_code(eap_simple_config_header_c::op_code_WSC_ACK); + } + else if( m_simple_config_message_type == simple_config_Message_Type_WSC_NACK ) + { + eap_simple_config_packet.set_sc_op_code(eap_simple_config_header_c::op_code_WSC_NACK); + } + else if( m_simple_config_message_type == simple_config_Message_Type_WSC_DONE ) + { + eap_simple_config_packet.set_sc_op_code(eap_simple_config_header_c::op_code_WSC_Done); + } + else + { + // In other cases this is a WSC message + eap_simple_config_packet.set_sc_op_code(eap_simple_config_header_c::op_code_WSC_MSG); + } + + // -------------------------------------------------------------------- + + eap_simple_config_packet.set_eap_type( + eap_expanded_type_simple_config.get_type(), + true); + + + u32_t fragment_length + = m_MTU + - eap_simple_config_header_c::get_simple_config_max_header_length(); + u32_t pending_message_length + = m_simple_config_message_buffer.get_data_length() + - m_simple_config_message_send_offset; + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP-SIMPLE_CONFIG fragment: packet_eap_data_free %d, ") + EAPL("fragment_length %d, pending_message_length %d, ") + EAPL("EAP-header length %d, buffer length %d\n"), + packet_eap_data_free, + fragment_length, + pending_message_length, + eap_simple_config_packet.get_header_length(), + eap_simple_config_fragment.get_buffer_length())); + + if (packet_eap_data_free >= pending_message_length) + { + // Message data is less than the buffer length, + // so the fragment is only length of the message data. + fragment_length = pending_message_length; + + // SIMPLE_CONFIG-message length is not included, + // because no fragmentation is used. + eap_simple_config_packet.set_flag_simple_config_length_included(false); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP-SIMPLE_CONFIG fragment: packet_eap_data_free %d, ") + EAPL("fragment_length %d, pending_message_length %d, ") + EAPL("EAP-header length %d\n"), + packet_eap_data_free, + fragment_length, + pending_message_length, + eap_simple_config_packet.get_header_length())); + } + + if (fragment_length < pending_message_length) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP-SIMPLE_CONFIG fragment: more fragments follow. ") + EAPL("fragment_length %d, pending_message_length %d, ") + EAPL("EAP-header length %d\n"), + fragment_length, + pending_message_length, + eap_simple_config_packet.get_header_length())); + + if (m_simple_config_message_send_offset == 0) + { + // SIMPLE_CONFIG-message length is included, + eap_simple_config_packet.set_flag_simple_config_length_included(true); + } + + eap_simple_config_packet.set_flag_more_fragments(true); + } + + + update_buffer_indexes( + SIMPLE_CONFIG_LOCAL_PACKET_BUFFER_LENGTH, + m_simple_config_header_offset+eap_simple_config_packet.get_header_length(), + &packet_buffer_offset, + &packet_buffer_free); + + status = eap_simple_config_fragment.set_data_length(packet_buffer_offset); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // - - - - - - - - - - - - - - - - - - - - - - - - + // Payload is SIMPLE_CONFIG-message fragment. + + status = eap_simple_config_fragment.add_data_to_offset( + packet_buffer_offset, + m_simple_config_message_buffer.get_data_offset( + m_simple_config_message_send_offset, fragment_length), + fragment_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + update_buffer_indexes( + SIMPLE_CONFIG_LOCAL_PACKET_BUFFER_LENGTH, + fragment_length, + &packet_buffer_offset, + &packet_buffer_free); + + // - - - - - - - - - - - - - - - - - - - - - - - - + + eap_simple_config_packet.set_data_length( + fragment_length, + true); + + status = eap_simple_config_fragment.set_data_length(packet_buffer_offset); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_simple_config_fragment_send(): m_simple_config_header_offset %d ") + EAPL("+ eap_simple_config_packet.get_header_length()") + EAPL("%d + eap_simple_config_packet.get_data_length() ") + EAPL("%d = %d == packet_buffer_offset %d.\n"), + m_simple_config_header_offset, + eap_simple_config_packet.get_header_length(), + eap_simple_config_packet.get_data_length(), + (m_simple_config_header_offset + + eap_simple_config_packet.get_header_length() + + eap_simple_config_packet.get_data_length()), + packet_buffer_offset)); + + EAP_ASSERT_ALWAYS( + m_simple_config_header_offset + +eap_simple_config_packet.get_header_length() + +eap_simple_config_packet.get_data_length() + == packet_buffer_offset); + + status = eap_status_process_general_error; + + // - - - - - - - - - - - - - - - - - - - - - - - - + + status = packet_send( + get_send_network_id(), + &eap_simple_config_fragment, + m_simple_config_header_offset, + eap_simple_config_packet.get_eap_length(), + SIMPLE_CONFIG_LOCAL_PACKET_BUFFER_LENGTH + ); + + if (status == eap_status_ok) + { + m_simple_config_message_send_offset += fragment_length; + + if (m_is_client == false) + { + // Server saves the sent EAP-Identifier. + set_last_eap_identifier( + static_cast(get_last_eap_identifier()+1ul)); + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::simple_config_message_process( + const eap_am_network_id_c * const /*receive_network_id*/, ///< This is the network identity of the received EAP packet. + eap_simple_config_header_c * const received_simple_config, ///< This is pointer to EAP header including EAP-SIMPLE_CONFIG fields. + const u32_t /*simple_config_packet_length*/ ///< This is length of received EAP-SIMPLE_CONFIG packet. + ) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (m_simple_config_message_buffer.get_is_valid_data() == false) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("simple_config_message_process: packet buffer invalid.\n"))); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + if (m_simple_config_message_buffer.get_data_length() + < simple_config_tlv_header_c::get_header_length()) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("simple_config_message_process: packet buffer too short, %d bytes.\n"), + m_simple_config_message_buffer.get_data_length())); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + save_current_state(); + set_state(eap_type_simple_config_state_process_simple_config_message); + + eap_status_e status = m_simple_config_record->packet_process( + &m_simple_config_message_buffer, + received_simple_config->get_eap_identifier()); + + if (status == eap_status_ok) + { + // Do nothing. + } + else if (status == eap_status_pending_request) + { + // Asyncronous operation is pending. + // Do nothing. + } + else if (status == eap_status_success) + { + // Authentication OK. + // Do nothing. + } + else if (status == eap_status_drop_packet_quietly) + { + // Dropped packet. + // Do nothing. + } + else + { + // All other return values are ERROR. Authentication is failed. + + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("%s: simple_config_message_process: Authentication failed.\n"), + (m_is_client == true) ? "client": "server")); + + restore_saved_previous_state(); + set_state(eap_type_simple_config_state_failure); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::eap_identity_response_packet_process( + const eap_am_network_id_c * const /*receive_network_id*/, ///< This is the network identity of the received EAP packet. + eap_header_wr_c * const eap_header, ///< This is pointer to EAP header and data. + const u32_t eap_packet_length ///< This is length of received EAP packet. + ) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_SIMPLE_CONFIG: %s: function: eap_identity_response_packet_process()\n"), + (m_is_client == true ? "client": "server"))); + + if (eap_header->check_header() != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + else if (eap_header->get_length() > eap_packet_length) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + + if (m_check_identifier_of_eap_identity_response == true) + { + if (m_state == eap_type_simple_config_state_waiting_for_identity_response + && eap_header->get_identifier() != get_last_eap_identifier()) + { + // Wrong EAP-Identifier in this state. + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_SIMPLE_CONFIG_ERROR, + (EAPL("ERROR: eap_type_simple_config_c::handle_identity_response_message(): ") + EAPL("EAP-Identifier 0x%02x is wrong (0x%02x is correct) in ") + EAPL("eap_type_simple_config_state_variable_e %d=%s.\n"), + eap_header->get_identifier(), + get_last_eap_identifier(), + get_state(), + get_state_string())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_eap_identity); + } + else if (m_simple_config_test_version == true + && m_state == eap_type_simple_config_state_success) // This one is for testing purposes. + { + // NOTE here we can not check the EAP-identifier. + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("WARNING: eap_type_simple_config_c::handle_identity_response_message(): ") + EAPL("EAP-Identifier 0x%02x is not checked in ") + EAPL("eap_type_simple_config_state_variable_e %d=%s.\n"), + eap_header->get_identifier(), + get_state(), + get_state_string())); + } + } + + + if (m_state == eap_type_simple_config_state_waiting_for_identity_response + || (m_simple_config_test_version == true + // In test version new authentication could start from this state. + && m_state == eap_type_simple_config_state_success)) + { + // EAP-Response/Identity is accepted only as a very first message. + + eap_status_e status = eap_status_process_general_error; + + save_current_state(); + + // In test version new authentication could start from this state. + if (m_simple_config_test_version == true + && m_state == eap_type_simple_config_state_success) // This one is for testing purposes. + { + // NOTE here we can not check the EAP-identifier. + set_state(eap_type_simple_config_state_waiting_for_identity_response); + } + + u8_t next_eap_identifier = static_cast(eap_header->get_identifier()+1u); + + status = parse_identity( + eap_header->get_type_data( + eap_header->get_type_data_length()), + eap_header->get_type_data_length()); + if (status != eap_status_ok) + { + restore_saved_previous_state(); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = send_simple_config_start_message(next_eap_identifier); + if (status != eap_status_ok) + { + restore_saved_previous_state(); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + set_last_eap_identifier(next_eap_identifier); + set_state(eap_type_simple_config_state_waiting_for_response); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: eap_type_simple_config_c::handle_identity_response_message(): ") + EAPL("EAP-Identifier 0x%02x in eap_type_simple_config_state_variable_e %d=%s. ") + EAPL("EAP-Response/Identity is accepted only in ") + EAPL("eap_type_simple_config_state_waiting_for_identity_response.\n"), + eap_header->get_identifier(), + get_state(), + get_state_string())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_wrong_eap_type_state); + } +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::simple_config_packet_process( + const eap_am_network_id_c * const receive_network_id, ///< This is the network identity of the received EAP packet. + eap_simple_config_header_c * const received_simple_config, ///< This is pointer to EAP header including EAP-SIMPLE_CONFIG fields. + const u32_t simple_config_packet_length ///< This is length of received EAP-SIMPLE_CONFIG packet. + ) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG(m_am_tools, TRACE_FLAGS_DEFAULT, (EAPL("\n"))); + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("EAP_type_SIMPLE_CONFIG: %s: function: simple_config_packet_process()\n"), + (m_is_client == true ? "client": "server"))); + + if (m_simple_config_test_version == true + && get_state() == eap_type_simple_config_state_failure) + { + // This is for testing. + if (m_is_client == false + && received_simple_config->get_eap_code() == eap_code_response + && received_simple_config->get_eap_type() == eap_type_identity) + { + set_state(eap_type_simple_config_state_waiting_for_identity_response); + } + else if (m_is_client == true + && received_simple_config->get_sc_op_code() == eap_simple_config_header_c::op_code_WSC_Start) + { + set_state(eap_type_simple_config_state_waiting_for_simple_config_start); + } + } + + if (received_simple_config->check_header( + m_am_tools, + m_is_client) != eap_status_ok) + { + // ERROR: EAP-SIMPLE_CONFIG header is corrupted. + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_SIMPLE_CONFIG_ERROR, + (EAPL("ERROR: eap_type_simple_config_c::simple_config_packet_process(): ") + EAPL("EAP-SIMPLE_CONFIG header is corrupted in ") + EAPL("eap_type_simple_config_state_variable_e %d=%s.\n"), + get_state(), + get_state_string())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + else if (received_simple_config->get_eap_length() > simple_config_packet_length) + { + // ERROR: EAP-Lenght field value is larger than actual received packet. + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_SIMPLE_CONFIG_ERROR, + (EAPL("ERROR: eap_type_simple_config_c::simple_config_packet_process(): ") + EAPL("EAP-Lenght field %d value is larger than actual received ") + EAPL("packet %d in eap_type_simple_config_state_variable_e %d=%s.\n"), + received_simple_config->get_eap_length(), + simple_config_packet_length, + get_state(), + get_state_string())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + else if (m_is_client == false + && received_simple_config->get_sc_op_code() == eap_simple_config_header_c::op_code_WSC_Start) + { + // ERROR: Server cannot receive EAP-SIMPLE_CONFIG Start message. + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_SIMPLE_CONFIG_ERROR, + (EAPL("ERROR: eap_type_simple_config_c::simple_config_packet_process(): ") + EAPL("Server cannot receive EAP-SIMPLE_CONFIG Start message. ") + EAPL("eap_type_simple_config_state_variable_e %d=%s.\n"), + get_state(), + get_state_string())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_unexpected_message); + } + else if (m_is_client == true + && (get_state() != eap_type_simple_config_state_waiting_for_request + && get_state() != eap_type_simple_config_state_waiting_for_identity_request + // EAP-SIMPLE_CONFIG could start without EAP-Request/Identity message. + && get_state() != eap_type_simple_config_state_waiting_for_simple_config_start + )) + { + // ERROR: Client cannot receive EAP-SIMPLE_CONFIG message in other states. + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("WARNING: eap_type_simple_config_c::simple_config_packet_process(): ") + EAPL("Client cannot receive EAP-SIMPLE_CONFIG message in ") + EAPL("eap_type_simple_config_state_variable_e %d=%s.\n"), + get_state(), + get_state_string())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + else if (m_is_client == false + && get_state() != eap_type_simple_config_state_waiting_for_response + ) + { + // WARNING: Server cannot receive EAP-SIMPLE_CONFIG message in other states. + // This packet is dropped quietly. + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("WARNING: eap_type_simple_config_c::simple_config_packet_process(): ") + EAPL("Server cannot receive EAP-SIMPLE_CONFIG message in ") + EAPL("eap_type_simple_config_state_variable_e %d=%s.\n"), + get_state(), + get_state_string())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_drop_packet_quietly); + } + else if (received_simple_config->get_sc_op_code() == eap_simple_config_header_c::op_code_WSC_Start + && get_state() != eap_type_simple_config_state_waiting_for_simple_config_start + && get_state() != eap_type_simple_config_state_waiting_for_identity_request) + // EAP-SIMPLE_CONFIG could start without EAP-Request/Identity message. + { + // ERROR: EAP-SIMPLE_CONFIG Start message is accepted only in + // eap_type_simple_config_state_waiting_for_simple_config_start. + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_SIMPLE_CONFIG_ERROR, + (EAPL("ERROR: eap_type_simple_config_c::simple_config_packet_process(): ") + EAPL("EAP-SIMPLE_CONFIG Start message is NOT accepted in ") + EAPL("eap_type_simple_config_state_variable_e %d=%s.\n"), + get_state(), + get_state_string())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_unexpected_message); + } + + // EAP-SIMPLE_CONFIG and PEAP fragmentation support: + // + // Flags include the Length included (L), More fragments (M), and EAP-SIMPLE_CONFIG Start (S) bits. + // + // The L flag is set to indicate the presence of the four octet SIMPLE_CONFIG Message + // Length field, and MUST be set for the first fragment of a fragmented + // SIMPLE_CONFIG message or set of messages. + // + // The M flag is set on all but the last fragment. + // + // The S flag is set only within the EAP-SIMPLE_CONFIG start message + // sent from the EAP server to the peer. This differentiates + // the EAP-SIMPLE_CONFIG Start message from a fragment acknowledgement. + // + // The SIMPLE_CONFIG Message Length field is four octets, and provides + // the total length of the SIMPLE_CONFIG message or set of messages + // that is being fragmented. This simplifies buffer allocation. + + eap_status_e status = eap_status_process_general_error; + + save_current_reassembly_state(); + + if (get_reassembly_state() == eap_type_simple_config_reassembly_state_wait_first_message) + { + if (received_simple_config->get_flag_more_fragments() == true + && received_simple_config->get_flag_simple_config_length_included() == false) + { + // The first fragmented message must include SIMPLE_CONFIG-length field. + restore_saved_reassembly_state(); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + + + bool first_fragment = false; + u32_t simple_config_message_length = 0ul; + + if (received_simple_config->get_flag_simple_config_length_included() == true) + { + // This is the first fragment and SIMPLE_CONFIG message length is included. + // We must allocate buffer for the fragments. + + status = received_simple_config->get_simple_config_message_length(&simple_config_message_length); + if (status != eap_status_ok) + { + restore_saved_reassembly_state(); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + first_fragment = true; + } + else if (received_simple_config->get_flag_more_fragments() == false + && received_simple_config->get_sc_op_code() != eap_simple_config_header_c::op_code_WSC_Start + && received_simple_config->get_data_length() > 0ul) + { + // This is the individual message and SIMPLE_CONFIG message length is not included. + // We must allocate buffer for the message. + + simple_config_message_length = received_simple_config->get_data_length(); + + first_fragment = true; + } + + + if (first_fragment == true) + { + m_simple_config_message_buffer.reset(); + + if (simple_config_message_length > 0ul) + { + if (simple_config_message_length > EAP_SIMPLE_CONFIG_MAX_MESSAGE_LENGTH) + { + restore_saved_reassembly_state(); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_too_long_message); + } + + // Next allocate buffer for reassembled SIMPLE_CONFIG-message. + status = m_simple_config_message_buffer.set_buffer_length(simple_config_message_length); + if (status != eap_status_ok) + { + restore_saved_reassembly_state(); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // Copy first fragment to the reassembly buffer. + status = m_simple_config_message_buffer.add_data( + received_simple_config->get_data(m_am_tools, received_simple_config->get_data_length()), + received_simple_config->get_data_length()); + if (status != eap_status_ok) + { + restore_saved_reassembly_state(); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + m_first_fragment_eap_identifier = received_simple_config->get_eap_identifier(); + } + } + + + if (received_simple_config->get_flag_more_fragments() == true) + { + // This is NOT the last fragment. + + // Send fragment acknowledge message. + status = send_sc_frag_ack(); + if (status != eap_status_ok) + { + restore_saved_reassembly_state(); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // Change reassembly state. + set_reassembly_state(eap_type_simple_config_reassembly_state_wait_last_fragment); + } + else + { + // This is the last fragment or non fragmented message. + // Change reassembly state. + set_reassembly_state(eap_type_simple_config_reassembly_state_message_reassembled); + + if (received_simple_config->get_sc_op_code() == eap_simple_config_header_c::op_code_FRAG_ACK) + { + // This is EAP-SIMPLE_CONFIG fragment acknowledge. + if (m_simple_config_message_buffer.get_is_valid_data() == true + && m_simple_config_message_send_offset < m_simple_config_message_buffer.get_data_length()) + { + // We can send next fragment. + + save_current_state(); + set_state(eap_type_simple_config_state_process_simple_config_message); + + status = eap_simple_config_fragment_send(); + if (status != eap_status_ok) + { + restore_saved_previous_state(); + restore_saved_reassembly_state(); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + if (m_is_client == true) + { + set_state(eap_type_simple_config_state_waiting_for_request); + } + else + { + set_state(eap_type_simple_config_state_waiting_for_response); + } + } + else + { + // No fragment available. Drop this packet. + restore_saved_reassembly_state(); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + } + else if (received_simple_config->get_sc_op_code() == eap_simple_config_header_c::op_code_WSC_Start) + { + if (get_state() == eap_type_simple_config_state_waiting_for_simple_config_start) + { + // This is EAP-SIMPLE_CONFIG Start message. + save_current_state(); + set_state(eap_type_simple_config_state_process_simple_config_start); + + if (get_NAI()->get_is_valid_data() == false) + { + status = get_type_partner()->get_saved_eap_identity(get_NAI()); + if (status != eap_status_ok) + { + restore_saved_previous_state(); + restore_saved_reassembly_state(); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + status = start_simple_config_authentication(receive_network_id, get_NAI()); + if (status == eap_status_pending_request) + { + // Do nothing. + } + else if (status != eap_status_ok) + { + restore_saved_previous_state(); + restore_saved_reassembly_state(); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else + { + // OK. + set_reassembly_state(eap_type_simple_config_reassembly_state_wait_first_message); + } + } + else + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_SIMPLE_CONFIG_ERROR, + (EAPL("ERROR: eap_type_simple_config_c::simple_config_packet_process(): ") + EAPL("Cannot receive EAP-SIMPLE_CONFIG message in ") + EAPL("eap_type_simple_config_state_variable_e %d=%s, ") + EAPL("eap_type_simple_config_reassembly_state_e %d=%s.\n"), + get_state(), + get_state_string(), + get_reassembly_state(), + get_reassembly_state_string())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_wrong_eap_type_state); + } + } + else + { + status = received_simple_config->check_header( + m_am_tools, + m_is_client); + if (status != eap_status_ok) + { + restore_saved_reassembly_state(); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + // Process the reassembled SIMPLE_CONFIG message. + status = simple_config_message_process( + receive_network_id, + received_simple_config, + simple_config_packet_length); + + if (status != eap_status_ok + && status != eap_status_pending_request + && status != eap_status_success) + { + restore_saved_reassembly_state(); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + set_reassembly_state(eap_type_simple_config_reassembly_state_wait_first_message); + } + } + else if (get_reassembly_state() == eap_type_simple_config_reassembly_state_wait_last_fragment) + { + // SIMPLE_CONFIG message length field may or may not be included. + + EAP_ASSERT_ALWAYS(received_simple_config->get_sc_op_code() != eap_simple_config_header_c::op_code_WSC_Start); + + // Concatenate fragment to the reassembly buffer. + status = m_simple_config_message_buffer.add_data( + received_simple_config->get_data(m_am_tools, received_simple_config->get_data_length()), + received_simple_config->get_data_length()); + if (status != eap_status_ok) + { + restore_saved_reassembly_state(); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + if (received_simple_config->get_flag_more_fragments() == true) + { + // This is NOT the last fragment. + + // Send fragment acknowledge message. + status = send_sc_frag_ack(); + if (status != eap_status_ok) + { + restore_saved_reassembly_state(); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + else + { + // This is the last fragment. + // Change reassembly state. + set_reassembly_state(eap_type_simple_config_reassembly_state_message_reassembled); + + // Process the reassembled SIMPLE_CONFIG message. + status = simple_config_message_process( + receive_network_id, + received_simple_config, + simple_config_packet_length); + + if (status != eap_status_ok + && status != eap_status_pending_request + && status != eap_status_success) + { + restore_saved_reassembly_state(); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + set_reassembly_state(eap_type_simple_config_reassembly_state_wait_first_message); + } + } + else if (get_reassembly_state() == eap_type_simple_config_reassembly_state_message_reassembled) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_SIMPLE_CONFIG_ERROR, + (EAPL("ERROR: eap_type_simple_config_c::simple_config_packet_process(): ") + EAPL("Cannot receive EAP-SIMPLE_CONFIG message in ") + EAPL("eap_type_simple_config_state_variable_e %d=%s, ") + EAPL("eap_type_simple_config_reassembly_state_e %d=%s.\n"), + get_state(), + get_state_string(), + get_reassembly_state(), + get_reassembly_state_string())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_wrong_eap_type_state); + } + else + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_SIMPLE_CONFIG_ERROR, + (EAPL("ERROR: eap_type_simple_config_c::simple_config_packet_process(): ") + EAPL("Cannot receive EAP-SIMPLE_CONFIG message in ") + EAPL("eap_type_simple_config_state_variable_e %d=%s, ") + EAPL("eap_type_simple_config_reassembly_state_e %d=%s.\n"), + get_state(), + get_state_string(), + get_reassembly_state(), + get_reassembly_state_string())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_wrong_eap_type_state); + } + + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT u32_t eap_type_simple_config_c::get_header_offset( + u32_t * const MTU, + u32_t * const trailer_length + ) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + // Note, EAP-SIMPLE_CONFIG and PEAP supports fragmentation. + // Here we could tell the MTU is big enough, the maximum memory buffer size is perfect. + + if (MTU != 0) + { + *MTU = EAP_SIMPLE_CONFIG_MAX_MESSAGE_LENGTH; + } + + if (trailer_length != 0) + { + *trailer_length = 0ul; + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return 0ul; // This is the header offset of the SIMPLE_CONFIG-record header. +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::timer_expired( + const u32_t /*id*/, void * /*data*/ + ) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::timer_delete_data( + const u32_t /*id*/, void * /*data*/ + ) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT void eap_type_simple_config_c::set_is_valid() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + m_is_valid = true; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT bool eap_type_simple_config_c::get_is_valid() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return m_is_valid; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::configure() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = eap_status_process_general_error; + + status = m_am_type_simple_config->configure(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + status = m_simple_config_record->configure(); + if (status != eap_status_ok) + { + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + + //---------------------------------------------------------- + + { + eap_variable_data_c check_identifier_of_eap_identity_response(m_am_tools); + + status = read_configure( + cf_str_EAP_SIMPLE_CONFIG_check_identifier_of_eap_identity_response.get_field(), + &check_identifier_of_eap_identity_response); + + if (status == eap_status_ok + && check_identifier_of_eap_identity_response.get_is_valid_data() == true) + { + u32_t *flag = reinterpret_cast( + check_identifier_of_eap_identity_response.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag == 0) + { + m_check_identifier_of_eap_identity_response = false; + } + else + { + m_check_identifier_of_eap_identity_response = true; + } + } + else + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_SIMPLE_CONFIG_ERROR, + (EAPL("ERROR: illegal configuration value %s\n"), + cf_str_EAP_SIMPLE_CONFIG_check_identifier_of_eap_identity_response + .get_field()->get_field())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_illegal_configure_field); + } + } + } + + //---------------------------------------------------------- + + { + eap_variable_data_c EAP_SIMPLE_CONFIG_check_nai_realm(m_am_tools); + + status = read_configure( + cf_str_EAP_SIMPLE_CONFIG_check_nai_realm.get_field(), + &EAP_SIMPLE_CONFIG_check_nai_realm); + if (status == eap_status_ok + && EAP_SIMPLE_CONFIG_check_nai_realm.get_is_valid_data() == true) + { + u32_t *check_nai_realm = reinterpret_cast( + EAP_SIMPLE_CONFIG_check_nai_realm.get_data(sizeof(u32_t))); + if (check_nai_realm != 0 + && *check_nai_realm != 0) + { + m_check_nai_realm = true; + } + } + } + + //---------------------------------------------------------- + + { + eap_variable_data_c test_version(m_am_tools); + + status = read_configure( + cf_str_EAP_SIMPLE_CONFIG_test_version.get_field(), + &test_version); + if (status == eap_status_ok + && test_version.get_is_valid_data() == true + && test_version.get_data_length() == sizeof(u32_t) + && test_version.get_data(sizeof(u32_t)) != 0) + { + // This is optional value. + u32_t *flag = reinterpret_cast(test_version.get_data(sizeof(u32_t))); + if (flag != 0) + { + if (*flag == 0) + { + m_simple_config_test_version = false; + } + else + { + m_simple_config_test_version = true; + } + } + } + } + + //---------------------------------------------------------- + + m_simple_config_header_offset = get_type_partner()->get_header_offset( + &m_MTU, &m_trailer_length); + + if (m_simple_config_header_offset+m_MTU+m_trailer_length > SIMPLE_CONFIG_LOCAL_PACKET_BUFFER_LENGTH) + { + EAP_ASSERT_ALWAYS(SIMPLE_CONFIG_LOCAL_PACKET_BUFFER_LENGTH + >= (m_simple_config_header_offset+m_trailer_length)); + + m_MTU = SIMPLE_CONFIG_LOCAL_PACKET_BUFFER_LENGTH + - (m_simple_config_header_offset+m_trailer_length); + } + + //---------------------------------------------------------- + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::shutdown() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("%s: function: eap_type_simple_config_c::shutdown(): this = 0x%08x => 0x%08x\n"), + (m_is_client == true ? "client": "server"), + this, + dynamic_cast(this))); + + if (m_shutdown_was_called == true) + { + // Shutdown was already called (this prevents looping forever) + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); + } + + m_shutdown_was_called = true; + + send_final_notification(); + + // Here we ignore return value. Both shutdown() calls must be done. + eap_status_e status = m_simple_config_record->shutdown(); + + status = m_am_type_simple_config->shutdown(); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::read_configure( + const eap_configuration_field_c * const field, + eap_variable_data_c * const data + ) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + // NOTE this will be read from AM of EAP-SIMPLE_CONFIG type. + eap_status_e status = m_am_type_simple_config->type_configure_read(field, data); + if (status != eap_status_ok) + { + // EAP-SIMPLE_CONFIG AM did not have configuration parameter. + // Let's try the global configuration. + status = get_type_partner()->read_configure(field, data); + if (status != eap_status_ok) + { + EAP_TRACE_DATA_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("WARNING: eap_type_simple_config_c::read_configure(): ") + EAPL("unknown configuration parameter"), + field->get_field(), + field->get_field_length())); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::write_configure( + const eap_configuration_field_c * const field, + eap_variable_data_c * const data + ) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + // NOTE this will be read from AM of EAP-SIMPLE_CONFIG type. + const eap_status_e status = m_am_type_simple_config->type_configure_write(field, data); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT void eap_type_simple_config_c::state_notification( + const abs_eap_state_notification_c * const state + ) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + if (state->get_protocol_layer() == eap_protocol_layer_general) + { + // Just forward these notifications to lower layers. + + if (state->get_eap_type() == eap_type_none) + { + // NOTE, here we set the EAP-type. + eap_state_notification_c notification( + m_am_tools, + state->get_send_network_id(), + state->get_is_client(), + eap_state_notification_eap, + state->get_protocol_layer(), + eap_expanded_type_simple_config.get_type(), + state->get_previous_state(), + state->get_current_state(), + state->get_eap_identifier(), + false); + + notification.set_authentication_error(state->get_authentication_error()); + + get_type_partner()->state_notification(¬ification); + } + else + { + get_type_partner()->state_notification(state); + } + + return; + } + + + if (state->get_protocol_layer() == eap_protocol_layer_eap) + { + if (state->get_current_state() == eap_state_authentication_terminated_unsuccessfully) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: %s: eap_type_simple_config_c::state_notification(): ") + EAPL("authentication failed: EAP-type 0x%08x\n"), + (m_is_client == true ? "client": "server"), + convert_eap_type_to_u32_t(eap_expanded_type_simple_config.get_type()))); + + // Here we must change the EAP-type of the notification. + { + eap_state_notification_c notification( + m_am_tools, + state->get_send_network_id(), + state->get_is_client(), + eap_state_notification_eap, + state->get_protocol_layer(), + eap_expanded_type_simple_config.get_type(), + state->get_previous_state(), + eap_state_authentication_terminated_unsuccessfully, + state->get_eap_identifier(), + false); + + notification.set_authentication_error(eap_status_authentication_failure); + + get_type_partner()->state_notification(¬ification); + } + } + else if (state->get_current_state() == eap_state_authentication_finished_successfully) + { + EAP_TRACE_ALWAYS( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("%s: eap_type_simple_config_c::state_notification(): ") + EAPL("authentication EAP-SUCCESS: EAP-type 0x%08x\n"), + (m_is_client == true ? "client": "server"), + convert_eap_type_to_u32_t(eap_expanded_type_simple_config.get_type()))); + + (void) finish_successful_authentication(); + } + } + else if (state->get_protocol_layer() == eap_protocol_layer_internal_type) + { + eap_simple_config_trace_string_c simple_config_trace; + + if (state->get_current_state() == simple_config_state_failure) + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("%s: eap_type_simple_config_c::state_notification(): SIMPLE_CONFIG tunneled ") + EAPL("authentication failed: EAP-type 0x%08x\n"), + (m_is_client == true ? "client": "server"), + convert_eap_type_to_u32_t(eap_expanded_type_simple_config.get_type()))); + + set_state(eap_type_simple_config_state_failure); + } + else if (state->get_current_state() == simple_config_state_simple_config_success) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("%s: eap_type_simple_config_c::state_notification(): ") + EAPL("SIMPLE_CONFIG authentication ") + EAPL("EAP-SUCCESS: EAP-type 0x%08x\n"), + (m_is_client == true ? "client": "server"), + convert_eap_type_to_u32_t(eap_expanded_type_simple_config.get_type()))); + } + else if (state->get_current_state() == simple_config_state_pending_simple_config_messages_processed) + { + if (get_state() == eap_type_simple_config_state_process_simple_config_message + || get_state() == eap_type_simple_config_state_process_simple_config_start) + { + if (m_is_client == true) + { + set_state(eap_type_simple_config_state_waiting_for_request); + } + else + { + set_state(eap_type_simple_config_state_waiting_for_response); + } + } + } + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::query_eap_identity( + const bool /* must_be_synchronous */, + eap_variable_data_c * const identity, + const eap_am_network_id_c * const receive_network_id, + const u8_t eap_identifier) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_simple_config_c::query_eap_identity() ") + EAPL("in eap_type_simple_config_state_variable_e %d=%s.\n"), + get_state(), + get_state_string())); + + if (m_simple_config_test_version == true + && get_state() == eap_type_simple_config_state_failure) + { + // This is for testing. + if (m_is_client == false) + { + set_state(eap_type_simple_config_state_waiting_for_identity_response); + } + else if (m_is_client == true) + { + set_state(eap_type_simple_config_state_waiting_for_simple_config_start); + } + } + + + bool use_manual_username(false); + eap_variable_data_c manual_username(m_am_tools); + bool use_manual_realm(false); + eap_variable_data_c manual_realm(m_am_tools); + + + if (m_state == eap_type_simple_config_state_waiting_for_identity_request + || (m_simple_config_test_version == true // This one is for testing purposes. + && m_state == eap_type_simple_config_state_success)) + { + save_current_state(); + set_state(eap_type_simple_config_state_pending_identity_query); + + eap_status_e status = eap_status_process_general_error; + + status = m_am_type_simple_config->query_eap_identity( + receive_network_id, + eap_identifier, + &use_manual_username, + &manual_username, + &use_manual_realm, + &manual_realm); + + if (status == eap_status_pending_request) + { + // This is pending query, that will be completed by complete_eap_identity_query() call. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (status == eap_status_completed_request) + { + // This is already completed by complete_eap_identity_query() call. + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (status != eap_status_ok + && status != eap_status_success) + { + // This is an error case. + restore_saved_previous_state(); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else + { + status = handle_eap_identity_query( + receive_network_id, + eap_identifier, + use_manual_username, + &manual_username, + use_manual_realm, + &manual_realm); + } + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else if (m_state == eap_type_simple_config_state_waiting_for_simple_config_start) + { + // This is re-transmission request. We do not change our state. + // Just send EAP-Identity again. + if (get_NAI()->get_is_valid_data() == true) + { + eap_status_e status = identity->set_copy_of_buffer(get_NAI()); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_simple_config_c::query_eap_identity() ") + EAPL("returns already obtained NAI in ") + EAPL("eap_type_simple_config_state_variable_e %d=%s.\n"), + get_state(), + get_state_string())); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); + } + else + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_SIMPLE_CONFIG_ERROR, + (EAPL("ERROR: eap_type_simple_config_c::query_eap_identity(): ") + EAPL("EAP-Request/Identity cannot be completed, identity (NAI) ") + EAPL("is missing. in eap_type_simple_config_state_variable_e %d=%s.\n"), + get_state(), + get_state_string())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_header_corrupted); + } + } + else if (m_state == eap_type_simple_config_state_pending_identity_query) + { + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_type_simple_config_c::query_eap_identity(): ") + EAPL("Already pending EAP-Identity query in ") + EAPL("eap_type_simple_config_state_variable_e %d=%s.\n"), + get_state(), + get_state_string())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_pending_request); + } + else + { + EAP_TRACE_ERROR( + m_am_tools, + TRACE_FLAGS_SIMPLE_CONFIG_ERROR, + (EAPL("ERROR: eap_type_simple_config_c::query_eap_identity(): ") + EAPL("Illegal EAP-Identity query in eap_type_simple_config_state_variable_e %d=%s.\n"), + get_state(), + get_state_string())); + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_wrong_eap_type_state); + } +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::set_initial_eap_identifier( + const eap_am_network_id_c * const /*receive_network_id*/, + const u8_t /*initial_identifier*/) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::eap_acknowledge( + const eap_am_network_id_c * const /* receive_network_id */) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_not_supported); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::reset() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + EAP_TRACE_DEBUG( + m_am_tools, + TRACE_FLAGS_DEFAULT, + (EAPL("%s: eap_type_simple_config_c::reset(): this = 0x%08x: %d=%s.\n"), + (m_is_client == true) ? "client": "server", + this, + get_state(), + get_state_string())); + + get_NAI()->reset(); + + if (m_is_client == true) + { + // Client waits EAP-Request/Identity. + m_state = eap_type_simple_config_state_waiting_for_identity_request; + m_saved_previous_state = eap_type_simple_config_state_waiting_for_identity_request; + } + else if (m_is_client == false) + { + // Server waits EAP-Response/Identity. + m_state = eap_type_simple_config_state_waiting_for_identity_response; + m_saved_previous_state = eap_type_simple_config_state_waiting_for_identity_response; + } + + m_reassembly_state = eap_type_simple_config_reassembly_state_wait_first_message; + + m_saved_previous_reassembly_state = eap_type_simple_config_reassembly_state_wait_first_message; + + m_simple_config_message_send_offset = 0ul; + + m_simple_config_message_buffer.reset(); + + eap_status_e status = m_simple_config_record->reset(); + + m_failure_message_received = false; + m_authentication_finished_successfully = false; + m_last_eap_identifier = 0ul; + + m_first_fragment_eap_identifier = 0ul; + + m_am_type_simple_config->reset(); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::set_timer( + abs_eap_base_timer_c * const p_initializer, + const u32_t p_id, + void * const p_data, + const u32_t p_time_ms) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = get_type_partner()->set_timer( + p_initializer, + p_id, + p_data, + p_time_ms); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::cancel_timer( + abs_eap_base_timer_c * const p_initializer, + const u32_t p_id) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = get_type_partner()->cancel_timer( + p_initializer, + p_id); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::cancel_all_timers() +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + eap_status_e status = get_type_partner()->cancel_all_timers(); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// This is commented in abs_simple_config_base_application_c. +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::load_module( + const eap_type_value_e type, + const eap_type_value_e tunneling_type, + abs_eap_base_type_c * const partner, + eap_base_type_c ** const eap_type, + const bool is_client_when_true, + const eap_am_network_id_c * const receive_network_id) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + // This call is forwarded to EAPOL AM module because it handles all the + // tunneled EAP type handlings for PEAP. + const eap_status_e status = get_type_partner()->load_module( + type, + tunneling_type, + partner, + eap_type, + is_client_when_true, + receive_network_id); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// This is commented in abs_simple_config_base_application_c. +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::unload_module(const eap_type_value_e type) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + // This call is forwarded to EAPOL AM module because it handles all the + // tunneled EAP type handlings for PEAP. + const eap_status_e status = get_type_partner()->unload_module(type); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// This is commented in abs_simple_config_base_application_c. +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::restart_authentication( + const eap_am_network_id_c * const receive_network_id, + const bool is_client_when_true, + const bool /*force_clean_restart*/, + const bool /*from_timer*/) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + // Here we swap the addresses. + eap_am_network_id_c send_network_id(m_am_tools, + receive_network_id->get_destination_id(), + receive_network_id->get_source_id(), + receive_network_id->get_type()); + + const eap_status_e status = get_type_partner()->restart_authentication( + &send_network_id, + is_client_when_true); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// This is commented in abs_simple_config_base_application_c. +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::packet_data_crypto_keys( + const eap_am_network_id_c * const /*send_network_id*/, + const eap_master_session_key_c * const /*master_session_key*/) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + // NOTE we do NOT forward keys to lower layer. + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, eap_status_ok); +} + +//-------------------------------------------------- + +// This is commented in abs_simple_config_base_application_c. +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::check_is_valid_eap_type( + const eap_type_value_e eap_type) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + // This call is forwarded to SIMPLE_CONFIG AM module because it handles all the + // tunneled EAP type handlings for PEAP. + const eap_status_e status = m_am_type_simple_config->check_is_valid_eap_type(eap_type); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// This is commented in abs_simple_config_base_application_c. +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::get_eap_type_list( + eap_array_c * const eap_type_list) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + const eap_status_e status = m_am_type_simple_config->get_eap_type_list(eap_type_list); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::set_session_timeout( + const u32_t session_timeout_ms) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + const eap_status_e status = get_type_partner()->set_session_timeout(session_timeout_ms); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e eap_type_simple_config_c::add_rogue_ap( + eap_array_c & rogue_ap_list) +{ + EAP_TRACE_BEGIN(m_am_tools, TRACE_FLAGS_DEFAULT); + + const eap_status_e status = get_type_partner()->add_rogue_ap(rogue_ap_list); + + EAP_TRACE_END(m_am_tools, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(m_am_tools, status); +} + +//-------------------------------------------------- + + +#endif //#if defined(USE_EAP_SIMPLE_CONFIG) + +// End.