diff -r 000000000000 -r c8830336c852 eapol/eapol_framework/eapol_common/am/common/eap_am_tools.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/eapol/eapol_framework/eapol_common/am/common/eap_am_tools.cpp Thu Dec 17 08:47:43 2009 +0200 @@ -0,0 +1,2462 @@ +/* +* 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 13 + #undef EAP_FILE_NUMBER_DATE + #define EAP_FILE_NUMBER_DATE 1127594498 +#endif //#if defined(USE_EAP_MINIMUM_RELEASE_TRACES) + + + +#include "eap_am_memory.h" +#include "eap_am_tools.h" +#include "abs_eap_am_mutex.h" +#include "eap_crypto_api.h" +#include "eap_buffer.h" +#include "eap_configuration_field.h" + +//#if !defined(NO_EAP_AM_MEMORY_STORE) + #include "eap_am_memory_store.h" +//#endif //#if !defined(NO_EAP_AM_MEMORY_STORE) + +/** + * This is the at character used in NAI. + */ +const u8_t EAP_AT_CHARACTER = '@'; + +/** + * This is the length of UUIDs. + */ +static const u32_t EAP_UUID_LENGTH = 16; + +/** + * This is the name space UUID for MAC addresses. + */ +static const u8_t EAP_MAC_ADDRESS_NAMESPACE_UUID_V5[] = + { 0x35, 0x0b, 0x16, 0xfd, + 0x5c, 0xd8, 0x45, 0x50, + 0x9b, 0xb8, 0x49, 0x8f, + 0x95, 0x8a, 0xc9, 0x66 }; + + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_am_tools_c::~eap_am_tools_c() +{ + EAP_ASSERT_ALWAYS_NO_TRACE(m_shutdown_was_called == true); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_am_tools_c::eap_am_tools_c() +: +#if !defined(NO_EAP_AM_MEMORY_STORE) + m_memory_store(0) +, +#endif //#if !defined(NO_EAP_AM_MEMORY_STORE) + m_trace_mask(eap_am_tools_c::eap_trace_mask_none) +#if defined(USE_EAP_ERROR_TESTS) +, m_packet_index(0u) +#endif //#if defined(USE_EAP_ERROR_TESTS) +, m_use_seconds_timestamp_in_traces(true) +, m_thread_stopped(false) +, m_use_timer_queue(false) +, m_shutdown_was_called(false) +, m_activate_trace_on_error(false) +{ + abs_eap_am_tools_c *m_am_tools = this; + u32_t bytes_8 = 8u; + u32_t bytes_4 = 4u; + u32_t bytes_2 = 2u; + u32_t bytes_1 = 1u; + + EAP_UNREFERENCED_PARAMETER(m_am_tools); + EAP_UNREFERENCED_PARAMETER(bytes_8); + EAP_UNREFERENCED_PARAMETER(bytes_4); + EAP_UNREFERENCED_PARAMETER(bytes_2); + EAP_UNREFERENCED_PARAMETER(bytes_1); + + EAP_ASSERT_ALWAYS(sizeof(u64_t) == bytes_8); + EAP_ASSERT_ALWAYS(sizeof(u32_t) == bytes_4); + EAP_ASSERT_ALWAYS(sizeof(u16_t) == bytes_2); + EAP_ASSERT_ALWAYS(sizeof(u8_t) == bytes_1); + + EAP_ASSERT_ALWAYS(sizeof(i64_t) == bytes_8); + EAP_ASSERT_ALWAYS(sizeof(i32_t) == bytes_4); + EAP_ASSERT_ALWAYS(sizeof(i16_t) == bytes_2); + EAP_ASSERT_ALWAYS(sizeof(i8_t) == bytes_1); + + m_tmp_buffer[0] = 0; + m_tmp_ascii_buffer[0] = 0; + +#if !defined(NO_EAP_AM_MEMORY_STORE) + m_memory_store = new eap_am_memory_store_c(m_am_tools); +#endif //#if !defined(NO_EAP_AM_MEMORY_STORE) +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT bool eap_am_tools_c::get_use_seconds_timestamp_in_traces() +{ + return m_use_seconds_timestamp_in_traces; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT bool eap_am_tools_c::get_thread_stopped() +{ + return m_thread_stopped; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT void eap_am_tools_c::set_use_timer_queue() +{ + m_use_timer_queue = true; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT bool eap_am_tools_c::get_use_timer_queue() +{ + return m_use_timer_queue; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT u32_t eap_am_tools_c::get_trace_mask() const +{ + return m_trace_mask; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT void eap_am_tools_c::set_trace_mask(const u32_t mask) +{ + m_trace_mask = mask; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT void eap_am_tools_c::set_activate_trace_on_error() +{ + m_activate_trace_on_error = true; + + // NOTE the always active traces are only left active. + set_trace_mask(eap_trace_mask_always); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT void eap_am_tools_c::check_activate_trace_on_error() +{ + if (m_activate_trace_on_error == true) + { + set_trace_mask( + eap_trace_mask_debug + | eap_trace_mask_always + | eap_trace_mask_error + | eap_am_tools_c::eap_trace_mask_message_data); + } +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT u8_t eap_am_tools_c::octet_to_ascii(i32_t octet) +{ + if (0 <= octet && octet <= 9) + { + return static_cast('0' + octet); + } + else if (10 <= octet && octet <= 16) + { + return static_cast('a' + (octet-10u)); + } + else + { + return 0; + } +} + + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT u8_t eap_am_tools_c::ascii_to_octet(i32_t character) +{ + if ('0' <= character && character <= '9') + { + return static_cast(character - '0'); + } + else if ('a' <= character && character <= 'f') + { + return static_cast((character - 'a') + 10u); + } + else if ('A' <= character && character <= 'F') + { + return static_cast((character - 'A') + 10u); + } + else + { + return 0; + } +} + + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT void eap_am_tools_c::trace_data( + eap_const_string prefix, + const void * const p_data, + const u32_t data_length) +{ + u8_t *cursor = m_tmp_buffer; + u8_t *cursor_ascii = m_tmp_ascii_buffer; + const u8_t *data = reinterpret_cast(p_data); + u32_t ind; + bool must_print = false; + u32_t data_start = 0u; + + const u32_t EAP_DATA_TRACE_BYTE_GROUP_SIZE = 1; + u32_t byte_group_size = EAP_DATA_TRACE_BYTE_GROUP_SIZE; + +#if !defined(USE_EAP_DEBUG_TRACE) + // This does not trace the pointer of the data. + formatted_print( + EAPL("%s: data begins: %d (0x%x) bytes\n"), + prefix, + data_length, + data_length); +#else + formatted_print( + EAPL("%s: data begins 0x%08x: %d (0x%x) bytes\n"), + prefix, + p_data, + data_length, + data_length); +#endif + + if (p_data != 0) + { + for (ind = 0u; ind < data_length; ind++) + { + if ((cursor-m_tmp_buffer)+5u >= sizeof(m_tmp_buffer)) + { + must_print = true; + formatted_print( + EAPL("ERROR: eap_am_tools_c::trace_data local buffer (%d bytes) too small.\n"), + sizeof(m_tmp_buffer)); + break; + } + + if (ind > 0u + && (ind % 16) == 0) + { + *cursor++ = 0; + *cursor_ascii++ = 0; + + formatted_print( + EAPL("%s: 0x%04x: %-48s |%-16s|\n"), + prefix, + data_start, + m_tmp_buffer, + m_tmp_ascii_buffer); + + cursor = m_tmp_buffer; + cursor_ascii = m_tmp_ascii_buffer; + must_print = false; + data_start = ind; + } + + *cursor_ascii++ = (*data >= 0x20 && *data < 0x7f) ? *data : '.'; + + *cursor++ = octet_to_ascii(((*data) & 0xf0) >> 4); + *cursor++ = octet_to_ascii(((*data) & 0x0f)); + data++; + + if (ind > 0u + && ((ind+1) % byte_group_size) == 0 + || byte_group_size == 1ul) + { + *cursor++ = ' '; + } + + must_print = true; + } + + if (must_print == true) + { + *cursor++ = 0; + *cursor_ascii = 0; + formatted_print( + EAPL("%s: 0x%04x: %-48s |%-16s|\n"), + prefix, + data_start, + m_tmp_buffer, + m_tmp_ascii_buffer); + } + } + +#if !defined(USE_EAP_DEBUG_TRACE) + // This does not trace the pointer of the data. + formatted_print( + EAPL("%s: data ends: %d (0x%x) bytes\n"), + prefix, + data_length, + data_length); +#else + formatted_print( + EAPL("%s: data ends 0x%08x: %d (0x%x) bytes\n"), + prefix, + p_data, + data_length, + data_length); +#endif + +} + +//-------------------------------------------------- + +#if defined(__SYMBIAN32__) && defined(USE_MULTITHREADING)// Symbian does not have 64 bit divide operator :-(. + +#include "eap_am_tools_symbian.h" +EAP_FUNC_EXPORT eap_status_e eap_am_tools_c::timer_thread_function() +{ + EAP_TRACE_DEBUG(this, TRACE_FLAGS_DEFAULT, (EAPL("TIMER: Timer thread starts.\n"))); + + u64_t start_time = get_clock_ticks(); + u64_t current_time = start_time; + u64_t real_time = 0u; + u64_t virtual_time = 0u; + u64_t begin_time = 0u; + u64_t end_time = 0u; +#if defined(_DEBUG) + TInt64 *_begin_time = (TInt64 *)&begin_time; + TInt64 *_real_time = (TInt64 *)&real_time; + TInt64 *_end_time = (TInt64 *)&end_time; +#endif + u64_t hw_ticks_of_millisecond = get_clock_ticks_of_second(); + TInt64 *hw_ticks_of_millisecond_tmp = (TInt64 *)&hw_ticks_of_millisecond; + TReal _hw_ticks_of_millisecond = hw_ticks_of_millisecond_tmp->GetTReal(); + _hw_ticks_of_millisecond /= 1000.0; + + // Note 64-bit casted to 32-bit. + EAP_TRACE_DEBUG(this, TRACE_FLAGS_DEFAULT, (EAPL("TIMER: get_clock_ticks_of_second() = %lu\n"), + static_cast(get_clock_ticks_of_second())); + + + u32_t sleep_time = get_timer_resolution_ms(); + // The mutex handle must be dublicated in Symbian operating system for each thread. + abs_eap_am_mutex_c *mutex = get_global_mutex()->dublicate_mutex(); + + if (mutex == 0 + || mutex->get_is_valid() == false) + { + EAP_TRACE_ERROR(this, TRACE_FLAGS_DEFAULT, (EAPL("ERROR: Mutex dublication failed.\n"))); + m_thread_stopped =true; + return EAP_STATUS_RETURN(this, eap_status_allocation_error); + } + + u32_t next_sleep_time = sleep_time; + + mutex->mutex_enter(); + while(get_is_timer_thread_active()) + { + mutex->mutex_leave(this); + + virtual_time += sleep_time; + + // Symbian sleep is more like random generator. + // It never sleep right time. + begin_time = get_clock_ticks(); + timer_sleep(sleep_time); + end_time = get_clock_ticks(); + + current_time = get_clock_ticks(); + real_time = current_time - start_time; + + EAP_TRACE_DEBUG( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("TIMER: Timer thread pulse_timer, sleep time = %d ms, ") + EAPL("actually %.3f ms, virtual_time %d ms, real_time %.3f ms.\n"), + sleep_time, + ((_end_time->GetTReal() - _begin_time->GetTReal()))/_hw_ticks_of_millisecond, + (static_cast(virtual_time), + (_real_time->GetTReal())/_hw_ticks_of_millisecond)); + + mutex->mutex_enter(); + if (get_is_timer_thread_active()) + { + next_sleep_time = pulse_timer(next_sleep_time); + } + } + + mutex->mutex_leave(this); + + delete mutex; + EAP_TRACE_DEBUG(this, TRACE_FLAGS_DEFAULT, (EAPL("TIMER: Timer thread stops.\n"))); + + m_thread_stopped =true; + + return eap_status_ok; +} + +#elif !defined(__SYMBIAN32__) + +#if defined(USE_EAP_TIMER_QUEUE_TRACE) + #define EAP_TRACE_TIMER EAP_TRACE_DEBUG +#else + #define EAP_TRACE_TIMER(object, flags, parameters) +#endif //#if defined(USE_EAP_TIMER_QUEUE_TRACE) + +EAP_FUNC_EXPORT eap_status_e eap_am_tools_c::timer_thread_function() +{ + EAP_TRACE_TIMER(this, TRACE_FLAGS_DEFAULT, (EAPL("TIMER: Timer thread starts.\n"))); + + u32_t static_sleep_time = get_timer_resolution_ms(); + u64_t start_time = get_clock_ticks(); + u64_t current_time = start_time; + u64_t virtual_time = 0u; + u64_t real_sleep_time = 0ul; + u32_t current_sleep_time = 0u; + u64_t real_time = 0u; + u64_t hw_ticks_of_millisecond = 0u; + + u64_t begin_time = 0u; + u64_t end_time = 0u; + + // Note 64-bit casted to 32-bit. + EAP_TRACE_TIMER( + this, + TRACE_FLAGS_DEFAULT, (EAPL("TIMER: get_clock_ticks_of_second() = %lu\n"), + static_cast(get_clock_ticks_of_second()))); + + hw_ticks_of_millisecond = get_clock_ticks_of_second(); + hw_ticks_of_millisecond /= 1000u; + + // The mutex handle must be dublicated in Symbian operating system for each thread. + abs_eap_am_mutex_c *mutex = get_global_mutex()->dublicate_mutex(); + + if (mutex == 0 + || mutex->get_is_valid() == false) + { + EAP_TRACE_ERROR( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: Mutex dublication failed.\n"))); + m_thread_stopped =true; + return EAP_STATUS_RETURN(this, eap_status_allocation_error); + } + + u32_t next_sleep_time = static_sleep_time; + u64_t delay_time = 0ul; + + + EAP_TRACE_TIMER( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("MUTEX: eap_am_tools_c::timer_thread_function(): mutex_enter(): begin\n"))); + + mutex->mutex_enter(); + + EAP_TRACE_TIMER( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("MUTEX: eap_am_tools_c::timer_thread_function(): mutex_enter(): end\n"))); + + while(get_is_timer_thread_active()) + { + bool timer_queue_is_empty = get_timer_queue_is_empty(); + + current_sleep_time = next_sleep_time; + + EAP_TRACE_TIMER( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("TIMER: timer_sleep(): current_sleep_time=%d\n"), + static_cast(current_sleep_time))); + + // - - - - - - - - - - - - - - - - - - - - - - - - + begin_time = get_clock_ticks(); + + EAP_TRACE_TIMER( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("MUTEX: eap_am_tools_c::timer_thread_function(): mutex_leave(): begin\n"))); + + mutex->mutex_leave(this); + + EAP_TRACE_TIMER( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("MUTEX: eap_am_tools_c::timer_thread_function(): mutex_leave(): end\n"))); + + // Sleep happens outside of the mutex. + timer_sleep(current_sleep_time); + + EAP_TRACE_TIMER( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("MUTEX: eap_am_tools_c::timer_thread_function(): mutex_enter(): begin\n"))); + + mutex->mutex_enter(); + + EAP_TRACE_TIMER( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("MUTEX: eap_am_tools_c::timer_thread_function(): mutex_enter(): end\n"))); + + end_time = get_clock_ticks(); + // - - - - - - - - - - - - - - - - - - - - - - - - + + if (timer_queue_is_empty == true) + { + real_sleep_time = 0ul; + delay_time = 0ul; + EAP_TRACE_TIMER( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("TIMER: empty timer queue\n"))); + } + else + { + if (end_time < begin_time) + { + end_time = begin_time; + } + real_sleep_time = (end_time - begin_time)/hw_ticks_of_millisecond; + } + + // - - - - - - - - - - - - - - - - - - - - - - - - + begin_time = get_clock_ticks(); + if (get_is_timer_thread_active() == true + && get_use_eap_milli_second_timer() == true) + { + EAP_TRACE_TIMER( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("TIMER: real_sleep_time=%d, delay_time=%d\n"), + static_cast(real_sleep_time), + static_cast(delay_time))); + + next_sleep_time = pulse_timer(static_cast(real_sleep_time+delay_time)); + } + else + { + (void) pulse_timer(static_sleep_time); + next_sleep_time = static_sleep_time; + } + end_time = get_clock_ticks(); + // - - - - - - - - - - - - - - - - - - - - - - - - + + + if (end_time < begin_time) + { + end_time = begin_time; + } + + delay_time = (end_time - begin_time)/hw_ticks_of_millisecond; + if (delay_time < next_sleep_time) + { + next_sleep_time -= static_cast(delay_time); + } + else + { + next_sleep_time = 0ul; + } + + current_time = get_clock_ticks(); + real_time = current_time - start_time; + real_time /= hw_ticks_of_millisecond; + + real_sleep_time += delay_time; + virtual_time += real_sleep_time; + + + EAP_TRACE_TIMER( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("TIMER: Timer thread pulse_timer, sleep time = %4d ms, real_sleep_time %4d ms, ") + EAPL("virtual_time %6d, real_time %6d, next_sleep_time %4d, delay_time %4d.\n"), + current_sleep_time, + static_cast(real_sleep_time), + static_cast(virtual_time), + static_cast(real_time), + next_sleep_time, + delay_time)); + + } // while() + + EAP_TRACE_TIMER( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("MUTEX: eap_am_tools_c::timer_thread_function(): mutex_leave(): begin\n"))); + + mutex->mutex_leave(this); + + EAP_TRACE_TIMER( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("MUTEX: eap_am_tools_c::timer_thread_function(): mutex_leave(): end\n"))); + + delete mutex; + + EAP_TRACE_TIMER(this, TRACE_FLAGS_DEFAULT, (EAPL("TIMER: Timer thread stops.\n"))); + + m_thread_stopped =true; + + return eap_status_ok; +} + +#else + +EAP_FUNC_EXPORT eap_status_e eap_am_tools_c::timer_thread_function() +{ + return EAP_STATUS_RETURN(this, eap_status_not_supported); +} + +#endif + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_am_tools_c::convert_ascii_to_uppercase( + u8_t * const source_bytes, + const u32_t source_bytes_length) +{ + u32_t ind; + for (ind = 0u; ind < source_bytes_length; ind++) + { + if (source_bytes[ind] >= 'a' && source_bytes[ind] <= 'z') + { + source_bytes[ind] -= 32; + } + } + + return eap_status_ok; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_am_tools_c::convert_bytes_to_hex_ascii( + const u8_t * const source_bytes, + const u32_t source_bytes_length, + u8_t * const target, + u32_t *target_length) +{ + u32_t ind; + u32_t length = (source_bytes_length*2u < (*target_length)) ? source_bytes_length : (*target_length)/2u; + for (ind = 0u; ind < length; ind++) + { + target[ind*2u] = octet_to_ascii((source_bytes[ind] >> 4) & 0x0f); + target[(ind*2u)+1] = octet_to_ascii(source_bytes[ind] & 0x0f); + } + *target_length = (ind*2u); + + return eap_status_ok; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_am_tools_c::convert_bytes_to_hex_ascii( + const void * const source_bytes, + const u32_t source_bytes_length, + eap_variable_data_c * const target) +{ + if (target == 0 + || target->get_is_valid() == false) + { + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, eap_status_illegal_parameter); + } + + eap_status_e status = target->set_buffer_length(source_bytes_length/2ul); + if (status != eap_status_ok) + { + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, status); + } + + status = target->set_data_length(target->get_buffer_length()); + if (status != eap_status_ok) + { + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, status); + } + + u32_t byte_length(target->get_data_length()); + + status = convert_bytes_to_hex_ascii( + reinterpret_cast(source_bytes), + source_bytes_length, + target->get_data(), + &byte_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, status); + } + else if (byte_length != target->get_data_length()) + { + target->reset(); + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, eap_status_illegal_data_payload); + } + + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_am_tools_c::convert_hex_ascii_to_bytes( + const u8_t * const source_bytes, + const u32_t source_bytes_length, + u8_t * const target, + u32_t *target_length) +{ + if ((source_bytes_length % 2u) != 0) + { + return EAP_STATUS_RETURN(this, eap_status_data_length_not_aligned_to_block_size); + } + + u32_t ind; + u32_t length = (source_bytes_length/2u < (*target_length)) ? source_bytes_length/2u : (*target_length); + for (ind = 0u; ind < length; ind++) + { + target[ind] = static_cast(ascii_to_octet(source_bytes[ind*2u]) << 4u | ascii_to_octet(source_bytes[ind*2u+1u])); + } + *target_length = (ind); + + return eap_status_ok; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_am_tools_c::convert_hex_ascii_to_bytes( + const void * const source_bytes, + const u32_t source_bytes_length, + eap_variable_data_c * const target) +{ + if (target == 0 + || target->get_is_valid() == false) + { + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, eap_status_illegal_parameter); + } + + eap_status_e status = target->set_buffer_length(source_bytes_length/2ul); + if (status != eap_status_ok) + { + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, status); + } + + status = target->set_data_length(source_bytes_length/2ul); + if (status != eap_status_ok) + { + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, status); + } + + u32_t byte_length(target->get_data_length()); + + status = convert_hex_ascii_to_bytes( + reinterpret_cast(source_bytes), + source_bytes_length, + target->get_data(), + &byte_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, status); + } + else if (byte_length != target->get_data_length()) + { + target->reset(); + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, eap_status_illegal_data_payload); + } + + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, status); +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT u8_t eap_am_tools_c::octet_to_ascii_armor( + const u8_t source_byte) +{ + if (source_byte < 26u) + { + // 'A' ... 'Z' + return static_cast((source_byte) + 'A'); + } + else if (26u <= source_byte && source_byte < 52u) + { + // 'a' ... 'z' + return static_cast((source_byte - 26u) + 'a'); + } + else if (52u <= source_byte && source_byte < 62u) + { + // '0' ... '9' + return static_cast(source_byte - 52u + '0'); + } + else if (source_byte == 62u) + { + return static_cast('+'); + } + else if (source_byte == 63u) + { + return static_cast('/'); + } + else + { + return 0u; + } +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT u8_t eap_am_tools_c::octet_from_ascii_armor( + const u8_t source_byte) +{ + if ('A' <= source_byte && source_byte <= 'Z') + { + // 'A' ... 'Z' + return static_cast((source_byte) - 'A'); + } + else if ('a' <= source_byte && source_byte <= 'z') + { + // 'a' ... 'z' + return static_cast((source_byte + 26u) - 'a'); + } + else if ('0' <= source_byte && source_byte <= '9') + { + // '0' ... '9' + return static_cast((source_byte + 52) - '0'); + } + else if (source_byte == '+') + { + return 62; + } + else if (source_byte == '/') + { + return 63; + } + else + { + return 0u; + } +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT void eap_am_tools_c::convert_selected_bytes_to_ascii_armor( + const u8_t source_byte, + u32_t * const saved_bit_count, + u8_t * const saved_bits, + u8_t * const target, + u32_t * const output_ind, + const bool last_input_byte) +{ + u8_t value; + + if (*saved_bit_count == 0u) + { + /* |0 1 2 3 4 5 6 7| + // +-+-+-+-+-+-+-+-+ + // | : : : : : : : | + // +-+-+-+-+-+-+-+-+ + // |0 1 2 3 4 5|0 1 + // | + + // | \ + // | \ + // | + + // | | + // |0 1 2 3 4 5 6 7| + // +-+-+-+-+-+-+-+-+ + // | : : : : : : : | + // +-+-+-+-+-+-+-+-+ + */ + value = octet_to_ascii_armor(static_cast(source_byte >> 2u)); + *saved_bits = static_cast(source_byte & 0x03); + *saved_bit_count = 2u; + target[*output_ind] = value; + ++(*output_ind); + } + else if (*saved_bit_count == 2u) + { + /* 6 7|0 1 2 3 4 5 6 7| + // +-+-+-+-+-+-+-+-+-+-+ + // : : | : : : : : : : | + // +-+-+-+-+-+-+-+-+-+-+ + // |0 1 2 3 4 5|0 1 2 3 + // | + + // | \ + // + \ + // \ \ + // \ \ + // + + + // | | + // 6 7|0 1 2 3 4 5 6 7| + // +-+-+-+-+-+-+-+-+-+-+ + // : : | : : : : : : : | + // +-+-+-+-+-+-+-+-+-+-+ + */ + const u8_t src = static_cast(((*saved_bits) << 4u) | ((source_byte & 0xf0) >> 4u)); + value = octet_to_ascii_armor(src); + *saved_bits = static_cast(source_byte & 0x0f); + *saved_bit_count = 4u; + target[*output_ind] = value; + ++(*output_ind); + } + else if (*saved_bit_count == 4u) + { + /* 4 5 6 7|0 1 2 3 4 5 6 7| + // +-+-+-+-+-+-+-+-+-+-+-+-+ + // : : : : | : : : : : : : | + // +-+-+-+-+-+-+-+-+-+-+-+-+ + // |0 1 2 3 4 5|0 1 2 3 4 5| + // | | + + // | | \ + // | + \ + // | \ \ + // + \ \ + // \ \ \ + // \ \ \ + // \ \ \ + // \ \ \ + // + + + + // | | | + // 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7| + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // : : : : | : : : : : : : | : : : : : : : | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + const u8_t src = static_cast(((*saved_bits) << 2u) | ((source_byte & 0xc0) >> 6u)); + value = octet_to_ascii_armor(src); + target[*output_ind] = value; + ++(*output_ind); + value = octet_to_ascii_armor(static_cast(source_byte & 0x3f)); + target[*output_ind] = value; + ++(*output_ind); + *saved_bits = 0u; + *saved_bit_count = 0u; + } + else + { + eap_am_tools_c *m_am_tools = this; + EAP_UNREFERENCED_PARAMETER(m_am_tools); + EAP_ASSERT(*saved_bit_count == 0u || *saved_bit_count == 2u || *saved_bit_count == 4u); + } + + if (last_input_byte == true + && *saved_bit_count > 0u) + { + value = octet_to_ascii_armor(static_cast((*saved_bits) << (6u - *saved_bit_count))); + target[*output_ind] = value; + ++(*output_ind); + *saved_bits = 0u; + *saved_bit_count = 0u; + } + +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT void eap_am_tools_c::restore_selected_bytes_from_ascii_armor( + const u8_t source_byte, + u32_t * const missing_bit_count, + u8_t * const target, + u32_t * const output_ind, + const bool last_input_byte) +{ + u8_t value; + + EAP_UNREFERENCED_PARAMETER(last_input_byte); + + if (source_byte == '=') + { + return; + } + + if (*missing_bit_count == 0u) + { + /* |0 1 2 3 4 5 6 7| + // +-+-+-+-+-+-+-+-+ + // | : : : : : : : | + // +-+-+-+-+-+-+-+-+ + // |0 1 2 3 4 5|0 1 + // | + + // | \ + // | \ + // | + + // | | + // |0 1 2 3 4 5 6 7| + // +-+-+-+-+-+-+-+-+ + // | : : : : : : : | + // +-+-+-+-+-+-+-+-+ + */ + value = static_cast(octet_from_ascii_armor(source_byte) << 2u); + target[*output_ind] = value; + *missing_bit_count = 2u; + } + else if (*missing_bit_count == 2u) + { + /* 6 7|0 1 2 3 4 5 6 7| + // +-+-+-+-+-+-+-+-+-+-+ + // : : | : : : : : : : | + // +-+-+-+-+-+-+-+-+-+-+ + // |0 1 2 3 4 5|0 1 2 3 + // | + + // | \ + // + \ + // \ \ + // \ \ + // + + + // | | + // 6 7|0 1 2 3 4 5 6 7| + // +-+-+-+-+-+-+-+-+-+-+ + // : : | : : : : : : : | + // +-+-+-+-+-+-+-+-+-+-+ + */ + value = octet_from_ascii_armor(source_byte); + target[*output_ind] |= (value & 0x30) >> 4u; + ++(*output_ind); + if (last_input_byte == false) + { + target[*output_ind] = static_cast((value & 0x0f) << 4u); + *missing_bit_count = 4u; + } + else + { + *missing_bit_count = 0u; + } + } + else if (*missing_bit_count == 4u) + { + /* 4 5 6 7|0 1 + // +-+-+-+-+-+-+ + // : : : : | : : + // +-+-+-+-+-+-+ + // |0 1 2 3 4 5| + // | + + // | \ + // + \ + // \ \ + // \ \ + // \ \ + // \ \ + // + + + // | | + // 4 5 6 7|0 1 2 3 4 5 6 7| + // +-+-+-+-+-+-+-+-+-+-+-+-+ + // : : : : | : : : : : : : | + // +-+-+-+-+-+-+-+-+-+-+-+-+ + */ + value = octet_from_ascii_armor(source_byte); + target[*output_ind] |= (value >> 2u) & 0x0f; + ++(*output_ind); + if (last_input_byte == false) + { + target[*output_ind] = static_cast((value & 0x03) << 6u); + *missing_bit_count = 6u; + } + else + { + *missing_bit_count = 0u; + } + } + else if (*missing_bit_count == 6u) + { + /* 2 3 4 5 6 7| + // +-+-+-+-+-+-+ + // : : : : : : | + // +-+-+-+-+-+-+ + // |0 1 2 3 4 5| + // | + + // | \ + // + \ + // \ \ + // \ \ + // \ \ + // \ \ + // \ \ + // \ \ + // + + + // | | + // 2 3 4 5 6 7|0 1 2 3 4 5 6 7| + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // : : : : : : | : : : : : : : | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + value = octet_from_ascii_armor(source_byte); + target[*output_ind] |= value; + ++(*output_ind); + *missing_bit_count = 0u; + } + else + { + eap_am_tools_c *m_am_tools = this; + EAP_UNREFERENCED_PARAMETER(m_am_tools); + EAP_ASSERT(*missing_bit_count == 0u || *missing_bit_count == 2u || *missing_bit_count == 4u || *missing_bit_count == 6u); + } + +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_am_tools_c::convert_bytes_to_ascii_armor( + const u8_t * const source_bytes, + const u32_t source_bytes_length, + u8_t * const target, + u32_t *target_length) +{ + if (source_bytes == 0) + { + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, eap_status_illegal_parameter); + } + + if (target == 0) + { + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, eap_status_illegal_parameter); + } + + if (target_length == 0) + { + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, eap_status_illegal_parameter); + } + + /* 8-bit ascii values are converted to binary 6-bit blocks. Ascii values can easily represent 2^6=64 values. + // If length of source array is not module 3, missing bits are padded with zero bits. + + // |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7| + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | : : : : : : : | : : : : : : : | : : : : : : : | : : : : : : : |0:0:0:0| + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // |0 1 2 3 4 5|0 1 2 3 4 5|0 1 2 3 4 5|0 1 2 3 4 5|0 1 2 3 4 5|0 1 2 3 4 5| + // | | | | | | + + // | | | | | | \ + // | | | | | + \ + // | | | | | \ \ + // | | | | + \ \ + // | | | | \ \ \ + // | | | + \ \ \ + // | | | \ \ \ \ + // | | + \ \ \ \ + // | | \ \ \ \ \ + // | + \ \ \ \ \ + // | \ \ \ \ \ \ + // | \ \ \ \ \ \ + // | + + + + + + + // | | | | | | | + // |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7| + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | : : : : : : : | : : : : : : : | : : : : : : : | : : : : : : : | : : : : : : : | : : : : : : : | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + u32_t output_ind = 0u; + u32_t input_ind = 0u; + u32_t input_count = (source_bytes_length*4u < (*target_length)*3u) ? source_bytes_length : (*target_length)*3u/4u; + u8_t saved_bits = 0u; + u32_t saved_bit_count = 0ul; + + for (input_ind = 0u; input_ind < input_count; input_ind++) + { + convert_selected_bytes_to_ascii_armor(source_bytes[input_ind], &saved_bit_count, &saved_bits, target, &output_ind, (input_ind+1 == input_count)); + } // for() + + u32_t remainder = output_ind % 4ul; + if (remainder != 0ul) + { + u32_t padding_count(4ul - remainder); + + if (padding_count == 2ul) + { + // Add padding '='-characters. + target[output_ind++] = '='; + --padding_count; + } + if (padding_count == 1ul) + { + // Add padding '='-characters. + target[output_ind++] = '='; + } + } + + *target_length = output_ind; + + return eap_status_ok; +} + +//-------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_am_tools_c::restore_bytes_from_ascii_armor( + const u8_t * const source_bytes, + const u32_t source_bytes_length, + u8_t * const target, + u32_t *target_length) +{ + if (source_bytes == 0) + { + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, eap_status_illegal_parameter); + } + + if (target == 0) + { + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, eap_status_illegal_parameter); + } + + if (target_length == 0) + { + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, eap_status_illegal_parameter); + } + + /* Binary 6-bit blocks are converted to 8-bit ascii values. Ascii values can easily represent 2^6=64 values. + // If length of target array is not module 3, padding zero bits are ignored. + + // |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7| + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | : : : : : : : | : : : : : : : | : : : : : : : | : : : : : : : | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // |0 1 2 3 4 5|0 1 2 3 4 5|0 1 2 3 4 5|0 1 2 3 4 5|0 1 2 3 4 5|0 1 2 3 4 5| + // | | | | | | + + // | | | | | | \ + // | | | | | + \ + // | | | | | \ \ + // | | | | + \ \ + // | | | | \ \ \ + // | | | + \ \ \ + // | | | \ \ \ \ + // | | + \ \ \ \ + // | | \ \ \ \ \ + // | + \ \ \ \ \ + // | \ \ \ \ \ \ + // | \ \ \ \ \ \ + // | + + + + + + + // | | | | | | | + // |0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7|0 1 2 3 4 5 6 7| + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | : : : : : : : | : : : : : : : | : : : : : : : | : : : : : : : | : : : : : : : | : : : : : : : | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + u32_t output_ind = 0u; + u32_t input_ind = 0u; + u32_t input_count = source_bytes_length; + u32_t missing_bit_count = 0ul; + + for (input_ind = 0u; input_ind < input_count; input_ind++) + { + restore_selected_bytes_from_ascii_armor(source_bytes[input_ind], &missing_bit_count, target, &output_ind, (input_ind+1 == input_count)); + } // for() + + *target_length = output_ind; + + return eap_status_ok; +} + +//----------------------------------------------------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e eap_am_tools_c::eap_status_return( + const bool print_error_when_true, + const eap_status_e status, + const eap_char * const file_name, + const i32_t line_number) +{ + if (status == eap_status_not_supported) + { + eap_status_string_c status_string; + + EAP_UNREFERENCED_PARAMETER(file_name); + EAP_UNREFERENCED_PARAMETER(line_number); + + EAP_TRACE_DEBUG( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("TODO: %s=%d returned from %s:%d\n"), + status_string.get_status_string(status), + status, + file_name, + line_number)); + } + else if (status == eap_status_success) + { + eap_status_string_c status_string; + + EAP_TRACE_DEBUG( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("SUCCESS: %s=%d returned from %s:%d\n"), + status_string.get_status_string(status), + status, + file_name, + line_number)); + } + else if (status == eap_status_not_found + || status == eap_status_illegal_configure_field + || status == eap_status_illegal_configure_type + || status == eap_status_syncronization_failure) + { + eap_status_string_c status_string; + + EAP_TRACE_DEBUG( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("WARNING: %s=%d returned from %s:%d\n"), + status_string.get_status_string(status), + status, + file_name, + line_number)); + } + else if (status == eap_status_pending_request + || status == eap_status_completed_request + || status == eap_status_drop_packet_quietly + || status == eap_status_end_of_file + || status == eap_status_section_ends + || status == eap_status_end_recursion) + { + eap_status_string_c status_string; + + EAP_TRACE_DEBUG( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("INFO: %s=%d returned from %s:%d\n"), + status_string.get_status_string(status), + status, + file_name, + line_number)); + } +#if defined(_DEBUG) + else if ((get_trace_mask() & TRACE_FLAGS_OK_RETURNS) + && (status == eap_status_ok + || status == eap_status_success + || status == eap_status_not_supported + || status == eap_status_pending_request + || status == eap_status_completed_request + || status == eap_status_drop_packet_quietly) + ) + { + eap_status_string_c status_string; + + EAP_TRACE_DEBUG( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("EXTRA: %s=%d returned from %s:%d\n"), + status_string.get_status_string(status), + status, + file_name, + line_number)); + } +#endif + else if (status != eap_status_ok + && status != eap_status_success + && status != eap_status_not_supported + && status != eap_status_pending_request + && status != eap_status_completed_request + && status != eap_status_drop_packet_quietly + ) + { + check_activate_trace_on_error(); + + eap_status_string_c status_string; + + if (print_error_when_true == true) + { + EAP_TRACE_ALWAYS( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: %s=%d returned from %s:%d\n"), + status_string.get_status_string(status), + status, + file_name, + line_number)); + } + else + { + EAP_TRACE_ALWAYS( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("WARNING: %s=%d returned from %s:%d\n"), + status_string.get_status_string(status), + status, + file_name, + line_number)); + } + } + + return status; +} + +//----------------------------------------------------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e eap_am_tools_c::eap_status_return_file_number( + const bool print_error_when_true, + const eap_status_e status, + const u32_t file_date, + const u32_t file_number, + const i32_t line_number) +{ + if (status == eap_status_not_supported) + { + eap_status_string_c status_string; + + EAP_UNREFERENCED_PARAMETER(file_date); + EAP_UNREFERENCED_PARAMETER(file_number); + EAP_UNREFERENCED_PARAMETER(line_number); + + EAP_TRACE_DEBUG( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("TODO: %d:%d:%d:%d\n"), + status, + file_date, + file_number, + line_number)); + } + else if (status == eap_status_success) + { + EAP_TRACE_DEBUG( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("SUCCESS: %d:%d:%d:%d\n"), + status, + file_date, + file_number, + line_number)); + } + else if (status == eap_status_not_found + || status == eap_status_illegal_configure_field + || status == eap_status_illegal_configure_type + || status == eap_status_syncronization_failure) + { + EAP_TRACE_DEBUG( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("WARNING: %d:%d:%d:%d\n"), + status, + file_date, + file_number, + line_number)); + } + else if (status == eap_status_pending_request + || status == eap_status_completed_request + || status == eap_status_drop_packet_quietly + || status == eap_status_end_of_file + || status == eap_status_section_ends) + { + EAP_TRACE_DEBUG( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("INFO: %d:%d:%d:%d\n"), + status, + file_date, + file_number, + line_number)); + } + else if (status != eap_status_ok + && status != eap_status_success + && status != eap_status_not_supported + && status != eap_status_pending_request + && status != eap_status_completed_request + && status != eap_status_drop_packet_quietly + + ) + { + check_activate_trace_on_error(); + + if (print_error_when_true == true) + { + EAP_TRACE_ALWAYS( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("ERROR: %d:%d:%d:%d\n"), + status, + file_date, + file_number, + line_number)); + } + else + { + EAP_TRACE_ALWAYS( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("WARNING: %d:%d:%d:%d\n"), + status, + file_date, + file_number, + line_number)); + } + } + + return status; +} + +//----------------------------------------------------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e eap_am_tools_c::memory_store_add_data( + const eap_variable_data_c * const key, + eap_tlv_message_data_c * const data, + const u32_t timeout) +{ + EAP_TRACE_BEGIN(this, TRACE_FLAGS_DEFAULT); + +#if !defined(NO_EAP_AM_MEMORY_STORE) + + if (m_memory_store == 0 + || m_memory_store->get_is_valid() == false) + { + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, eap_status_allocation_error); + } + + eap_status_e status = m_memory_store->add_data( + key, + data, + timeout); + + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, status); + +#else + + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, eap_status_not_supported); + +#endif //#if !defined(NO_EAP_AM_MEMORY_STORE) +} + +//----------------------------------------------------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e eap_am_tools_c::memory_store_get_data( + const eap_variable_data_c * const key, + eap_tlv_message_data_c * const data) +{ + EAP_TRACE_BEGIN(this, TRACE_FLAGS_DEFAULT); + +#if !defined(NO_EAP_AM_MEMORY_STORE) + + if (m_memory_store == 0 + || m_memory_store->get_is_valid() == false) + { + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, eap_status_allocation_error); + } + + eap_status_e status = eap_status_process_general_error; + + status = m_memory_store->get_data( + key, + data); + + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, status); + +#else + + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, eap_status_not_found); + +#endif //#if !defined(NO_EAP_AM_MEMORY_STORE) + +} + +//----------------------------------------------------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e eap_am_tools_c::memory_store_remove_data( + const eap_variable_data_c * const key) +{ + EAP_TRACE_BEGIN(this, TRACE_FLAGS_DEFAULT); + +#if !defined(NO_EAP_AM_MEMORY_STORE) + + if (m_memory_store == 0 + || m_memory_store->get_is_valid() == false) + { + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, eap_status_allocation_error); + } + + eap_status_e status = m_memory_store->remove_data( + key); + + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, status); + +#else + + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, eap_status_not_found); + +#endif //#if !defined(NO_EAP_AM_MEMORY_STORE) +} + +//-------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e eap_am_tools_c::shutdown_am_tools() +{ + eap_status_e status = eap_status_ok; + + EAP_TRACE_DEBUG( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_am_tools_c::shutdown_am_tools(); this = 0x%08x\n"), + this)); + + if (m_shutdown_was_called == false) + { + m_shutdown_was_called = true; + + #if !defined(NO_EAP_AM_MEMORY_STORE) + if (m_memory_store != 0) + { + status = m_memory_store->shutdown(); + } + delete m_memory_store; + m_memory_store = 0; + #endif //#if !defined(NO_EAP_AM_MEMORY_STORE) + } + + return EAP_STATUS_RETURN(this, status); +} + +//-------------------------------------------------- + +/// Coverts unicode string to UTF8 string. +EAP_FUNC_EXPORT eap_status_e eap_am_tools_c::generic_convert_unicode_to_utf8( + eap_variable_data_c & dest, + const eap_variable_data_c & src) +{ + if (src.get_is_valid_data() == true) + { + u32_t len = src.get_data_length(); + u8_t * ascii = new u8_t[len / 2]; + if (!ascii) + { + return EAP_STATUS_RETURN(this, eap_status_allocation_error); + } + u8_t * src_ptr = src.get_data(len); + u32_t dest_len = len / 2; + u32_t i; + for (i = 0; i < dest_len; i++) + { + ascii[i] = src_ptr[i * 2]; + } + + return EAP_STATUS_RETURN(this, dest.set_buffer(ascii, dest_len, true, true)); + } + + return EAP_STATUS_RETURN(this, eap_status_process_general_error); +} + +//-------------------------------------------------- + +/// Coverts UTF8 string to unicode string. Not yet implemented. +EAP_FUNC_EXPORT eap_status_e eap_am_tools_c::generic_convert_utf8_to_unicode( + eap_variable_data_c & dest, + const eap_variable_data_c & src) +{ + if (src.get_is_valid_data() == true) + { + u32_t len = src.get_data_length(); + u8_t * src_ptr = src.get_data(len); + + eap_status_e status = dest.set_buffer_length(2ul*len); + if (status != eap_status_ok) + { + return EAP_STATUS_RETURN(this, status); + } + + u8_t null_byte(0x00); + u32_t i; + for (i = 0; i < len; i++) + { + status = dest.add_data(&(src_ptr[i]), sizeof(u8_t)); + if (status != eap_status_ok) + { + return EAP_STATUS_RETURN(this, status); + } + + status = dest.add_data(&null_byte, sizeof(u8_t)); + if (status != eap_status_ok) + { + return EAP_STATUS_RETURN(this, status); + } + } + + return EAP_STATUS_RETURN(this, eap_status_ok); + } + + return EAP_STATUS_RETURN(this, eap_status_process_general_error); +} + +//----------------------------------------------------------------------------------------------- + +// +EAP_FUNC_EXPORT eap_status_e eap_am_tools_c::parse_nai( + const eap_variable_data_c * const nai, + eap_variable_data_c * const username, + eap_variable_data_c * const realm) +{ + if (nai == 0 + || username == 0 + || realm == 0) + { + return EAP_STATUS_RETURN(this, eap_status_illegal_parameter); + } + + username->reset(); + realm->reset(); + + if (nai->get_is_valid() == false) + { + return EAP_STATUS_RETURN(this, eap_status_illegal_parameter); + } + + EAP_TRACE_DATA_DEBUG( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_am_tools_c::parse_nai(): NAI"), + nai->get_data(), + nai->get_data_length())); + + + eap_status_e status(eap_status_ok); + u32_t username_length = nai->get_data_length(); + + // We read the realm from NAI. + const u8_t *at_character = reinterpret_cast( + memchr( + nai->get_data(nai->get_data_length()), + EAP_AT_CHARACTER, + nai->get_data_length())); + if (at_character != 0 + && nai->get_data_length() + > ((1UL + reinterpret_cast(at_character)) + - reinterpret_cast(nai->get_data( + nai->get_data_length())))) + { + u32_t realm_length = nai->get_data_length() + - ((1UL + reinterpret_cast(at_character)) + - reinterpret_cast(nai->get_data( + nai->get_data_length()))); + + if (realm_length > 0UL) + { + status = realm->set_copy_of_buffer( + at_character+1, + realm_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, status); + } + + username_length -= (realm_length + 1ul); + } + } + else + { + // No realm. + } + + // The begin of the NAI to '@' or the end is username. + status = username->set_copy_of_buffer( + nai->get_data(username_length), + username_length); + if (status != eap_status_ok) + { + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, status); + } + + EAP_TRACE_DATA_DEBUG( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_am_tools_c::parse_nai(): username"), + username->get_data(), + username->get_data_length())); + + EAP_TRACE_DATA_DEBUG( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("eap_am_tools_c::parse_nai(): realm"), + realm->get_data(), + realm->get_data_length())); + + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, status); +} + +//----------------------------------------------------------------------------------------------- + +#if defined(USE_EAP_ERROR_TESTS) + +// +EAP_FUNC_EXPORT eap_status_e eap_am_tools_c::generate_random_error( + eap_buf_chain_wr_c * const sent_packet, + const bool forse_error, + const u32_t packet_index, + const u32_t minimum_index, + const u32_t error_probability, + const u32_t minimum_packet_length) +{ + eap_status_e status(eap_status_ok); + EAP_UNREFERENCED_PARAMETER(packet_index); + + u8_t *data = sent_packet->get_data(sent_packet->get_data_length()); + if (data == 0) + { + return EAP_STATUS_RETURN(this, eap_status_allocation_error); + } + + crypto_random_c rand(this); + u32_t random_guard = 0; + bool error_generated = false; + + for (u32_t ind = minimum_index; ind < sent_packet->get_data_length(); ind++) + { + status = rand.get_rand_bytes( + reinterpret_cast(&random_guard), + sizeof(random_guard)); + if (status != eap_status_ok) + { + return EAP_STATUS_RETURN(this, status); + } + + // This is simple limiter to the probability of an error. + // probability = m_error_probability / (2^32) + if (random_guard < error_probability) + { + u8_t rnd; + u8_t previous_data; + // Create an error. + status = rand.get_rand_bytes( + &rnd, + sizeof(rnd)); + if (status != eap_status_ok) + { + return EAP_STATUS_RETURN(this, status); + } + + previous_data = data[ind]; + data[ind] ^= rnd; + + if (previous_data != data[ind]) + { + error_generated = true; + sent_packet->set_random_error_type(eap_random_error_type_manipulate_byte); + + EAP_TRACE_DEBUG( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("TEST: random_error(): error: manipulate, packet_index 0x%08x:%lu, data[0x%04x] ") + EAPL("changed from 0x%02x to 0x%02x.\n"), + this, packet_index, ind, previous_data, data[ind])); + } + } + } // for() + + + if (error_generated == false + && forse_error == true + && sent_packet->get_data_length() > 0ul) + { + // Generate one error. + + // Random error type. + eap_random_error_type error_type = eap_random_error_type_none_keep_this_last_case; + status = rand.get_rand_bytes( + reinterpret_cast(&error_type), + sizeof(error_type)); + if (status != eap_status_ok) + { + return EAP_STATUS_RETURN(this, status); + } + + error_type = static_cast( + static_cast(error_type) + % static_cast(eap_random_error_type_none_keep_this_last_case)); + + sent_packet->set_random_error_type(error_type); + + switch(error_type) + { + case eap_random_error_type_manipulate_byte: + { + u32_t rnd_index; + u8_t previous_data; + u32_t index; + + do + { + do + { + // Create an error index. + status = rand.get_rand_bytes( + reinterpret_cast(&rnd_index), + sizeof(rnd_index)); + if (status != eap_status_ok) + { + return EAP_STATUS_RETURN(this, status); + } + + index = (rnd_index % (sent_packet->get_data_length() - minimum_index)) + + minimum_index; + } + while(index < minimum_index + || index > sent_packet->get_buffer_length()); + + u8_t rnd; + // Create an error. + status = rand.get_rand_bytes( + &rnd, + sizeof(rnd)); + if (status != eap_status_ok) + { + return EAP_STATUS_RETURN(this, status); + } + + previous_data = data[index]; + data[index] ^= rnd; + } + while(previous_data == data[index]); + + EAP_TRACE_DEBUG( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("TEST: random_error(): error: manipulate, packet_index 0x%08x:%lu, ") + EAPL("data[0x%04x] changed from 0x%02x to 0x%02x.\n"), + this, packet_index, index, previous_data, data[index])); + + error_generated = true; + } + break; + case eap_random_error_type_change_packet_length_longer: + { + u8_t delta_length = 0; + i32_t new_length = 0; + + do + { + status = rand.get_rand_bytes( + reinterpret_cast(&delta_length), + sizeof(delta_length)); + if (status != eap_status_ok) + { + return EAP_STATUS_RETURN(this, status); + } + + new_length = static_cast(sent_packet->get_data_length()) + static_cast(delta_length); + } + while (new_length < static_cast(minimum_packet_length) /*eapol_ethernet_header_wr_c::get_header_length()*/ + || new_length > static_cast(sent_packet->get_buffer_length())); + + EAP_TRACE_DEBUG( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("TEST: random_error(): error: manipulate, packet_index 0x%08x:%lu, ") + EAPL("packet length changed from %lu to %lu.\n"), + this, + packet_index, + sent_packet->get_data_length(), + new_length)); + + sent_packet->set_data_length(new_length); + + error_generated = true; + } + break; + case eap_random_error_type_change_packet_length_shorter: + { + u8_t delta_length = 0; + i32_t new_length = 0; + + do + { + status = rand.get_rand_bytes( + reinterpret_cast(&delta_length), + sizeof(delta_length)); + if (status != eap_status_ok) + { + return EAP_STATUS_RETURN(this, status); + } + + delta_length %= (static_cast(sent_packet->get_data_length()) + - static_cast(minimum_packet_length) /*eapol_ethernet_header_wr_c::get_header_length()*/ ); + + if (delta_length == 0) + { + continue; + } + + new_length = static_cast(sent_packet->get_data_length()) - static_cast(delta_length); + } + while (new_length < static_cast(minimum_packet_length) /*eapol_ethernet_header_wr_c::get_header_length()*/ + || new_length > static_cast(sent_packet->get_buffer_length())); + + EAP_TRACE_DEBUG( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("TEST: random_error(): error: manipulate, packet_index 0x%08x:%lu, ") + EAPL("packet length changed from %lu to %lu.\n"), + this, + packet_index, + sent_packet->get_data_length(), + new_length)); + + sent_packet->set_data_length(new_length); + + error_generated = true; + } + break; + default: + EAP_ASSERT_ANYWAY_TOOLS(this); + break; + } + } // if () + + + if (error_generated == true) + { + sent_packet->set_is_manipulated(); + } + + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, status); +} + +#endif //#if defined(USE_EAP_ERROR_TESTS) + +//----------------------------------------------------------------------------------------------- + +#if defined(USE_EAP_ERROR_TESTS) + +EAP_FUNC_EXPORT u32_t eap_am_tools_c::get_packet_index() +{ + return m_packet_index; +} + +#endif //#if defined(USE_EAP_ERROR_TESTS) + +//----------------------------------------------------------------------------------------------- + +#if defined(USE_EAP_ERROR_TESTS) + +EAP_FUNC_EXPORT void eap_am_tools_c::increase_packet_index() +{ + ++m_packet_index; +} + +#endif //#if defined(USE_EAP_ERROR_TESTS) + +//----------------------------------------------------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e eap_am_tools_c::number_string_to_u32( + const u8_t * const number_string, + const u32_t number_string_length, + u32_t * const integer) +{ + EAP_TRACE_BEGIN(this, TRACE_FLAGS_DEFAULT); + + if (number_string == 0 + || number_string_length == 0UL + || integer == 0) + { + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, eap_status_illegal_parameter); + } + + *integer = 0UL; + + u32_t multiplier = 1UL; + + for (i32_t ind = number_string_length-1; ind >= 0; ind--) + { + u8_t character = number_string[ind]; + if (character < '0' || '9' < character) + { + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, eap_status_illegal_data_payload); + } + + u8_t digit = ascii_to_octet(static_cast(number_string[ind])); + + u32_t addition = static_cast(digit) * multiplier; + if (((~0UL) - *integer) < addition) + { + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, eap_status_illegal_data_payload); + } + + *integer += addition; + + multiplier *= 10UL; + } + + EAP_TRACE_END(this, TRACE_FLAGS_DEFAULT); + return EAP_STATUS_RETURN(this, eap_status_ok); +} + +//----------------------------------------------------------------------------------------------- + +EAP_FUNC_EXPORT void eap_am_tools_c::trace_configuration( + const eap_status_e configuration_read_status, + const eap_configuration_field_c * const field, + const eap_variable_data_c * const data) +{ + EAP_UNREFERENCED_PARAMETER(data); + + if (configuration_read_status != eap_status_ok) + { + EAP_TRACE_DATA_DEBUG( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("WARNING: unknown configuration parameter"), + field->get_field(), + field->get_field_length())); + } + else + { + EAP_TRACE_DATA_ALWAYS( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("configuration parameter"), + field->get_field(), + field->get_field_length())); + + if (field->get_is_secret() == true) + { + EAP_TRACE_DEBUG( + this, + TRACE_FLAGS_DEFAULT, + (EAPL("This is secret data. Not shown here.\n"))); + } + else + { + EAP_TRACE_DATA_ALWAYS( + this, + TRACE_FLAGS_DEFAULT, + (EAPL(" configuration value"), + data->get_data(data->get_data_length()), + data->get_data_length())); + } + } +} + +//----------------------------------------------------------------------------------------------- + +EAP_FUNC_EXPORT u64_t eap_am_tools_c::xor_u64( + const u64_t p_a, + const u64_t p_b) +{ + +#if defined(USE_EAP_64_BIT_XOR) + + u64_t ret = p_a ^ p_b; + +#else + + u64_struct a = u64_t_to_u64_struct(p_a); + u64_struct b = u64_t_to_u64_struct(p_b); + + + // Result + u64_struct result; + result.high = a.high ^ b.high; + result.low = a.low ^ b.low; + + u64_t ret = u64_struct_to_u64_t(result); + +#endif //#if defined(USE_EAP_64_BIT_XOR) + + return ret; +} + +//----------------------------------------------------------------------------------------------- + +EAP_FUNC_EXPORT u64_t eap_am_tools_c::multiply_u64( + const u64_t p_a, + const u64_t p_b) +{ + +#if defined(USE_EAP_64_BIT_MULTIPLICATION) + + return p_a * p_b; + +#else + + u32_t a_tmp[4]; + u32_t b_tmp[4]; + u32_t wide_tmp[8]; + u32_t tmp; + u64_struct a = u64_t_to_u64_struct(p_a); + u64_struct b = u64_t_to_u64_struct(p_b); + + // <--- 32 bits ---> <--- 32 bits ---> <--- 32 bits ---> <--- 32 bits ---> + // +--------+--------+--------+--------+--------+--------+--------+--------+ + // | overf. | 0-15 | overf. | 16-31 | overf. | 32-47 | overf. | 48-63 | + // +--------+--------+--------+--------+--------+--------+--------+--------+ + a_tmp[0] = a.low & 0xffff; + a_tmp[1] = (a.low >> 16) & 0xffff; + a_tmp[2] = a.high & 0xffff; + a_tmp[3] = (a.high >> 16) & 0xffff; + + b_tmp[0] = b.low & 0xffff; + b_tmp[1] = (b.low >> 16) & 0xffff; + b_tmp[2] = b.high & 0xffff; + b_tmp[3] = (b.high >> 16) & 0xffff; + + u32_t j_ind; + + for(j_ind = 0ul; j_ind < 4ul; j_ind++) + { + wide_tmp[j_ind]= 0ul; + } + + for(j_ind = 0ul; j_ind < 4ul; j_ind++) + { + if(b_tmp[j_ind] == 0ul) + { + wide_tmp[j_ind+4ul] = 0ul; + } + else + { + u32_t l_ind; + u32_t overflow = 0ul; + + for(l_ind = 0ul; l_ind < 4ul; l_ind++) + { + tmp = a_tmp[l_ind] * b_tmp[j_ind] + wide_tmp[l_ind+j_ind] + overflow; + wide_tmp[l_ind+j_ind] = tmp & 0xffff; + overflow = (tmp >> 16) & 0xffff; + } + + wide_tmp[j_ind+4] = overflow; + } + } + + // Overflow + u64_struct overflow; + overflow.high = ((wide_tmp[7] << 16) & 0xffff0000) + wide_tmp[6]; + overflow.low = ((wide_tmp[5] << 16) & 0xffff0000) + wide_tmp[4]; + EAP_UNREFERENCED_PARAMETER(overflow); + + + // Result + u64_struct result; + result.high = ((wide_tmp[3] << 16) & 0xffff0000) + wide_tmp[2]; + result.low = ((wide_tmp[1] << 16) & 0xffff0000) + wide_tmp[0]; + + u64_t ret = u64_struct_to_u64_t(result); + + return ret; + +#endif //#if defined(USE_EAP_64_BIT_MULTIPLICATION) + +} + +//----------------------------------------------------------------------------------------------- + +EAP_FUNC_EXPORT i32_t eap_am_tools_c::compare_u64(const u64_t p_a, const u64_t p_b) +{ + u64_struct a = u64_t_to_u64_struct(p_a); + u64_struct b = u64_t_to_u64_struct(p_b); + + if (a.high > b.high) + { + return +1; + } + else if (a.high < b.high) + { + return -1; + } + else // if (a.high == b.high) + { + if (a.low > b.low) + { + return +1; + } + else if (a.low < b.low) + { + return -1; + } + else + { + return 0; + } + } +} + +//----------------------------------------------------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e eap_am_tools_c::create_uuid_v5( + const void* const ns_uuid, + const u32_t ns_uuid_length, + const void* const name, + const u32_t name_length, + eap_variable_data_c* const uuid ) +{ + // check input + if( ns_uuid == 0 || + ns_uuid_length != EAP_UUID_LENGTH || + name == 0 || name_length <= 0 || + uuid == 0 || uuid->get_is_valid() == false ) + { + return EAP_STATUS_RETURN(this, eap_status_illegal_parameter); + } + + // make sure that uuid is empty + uuid->reset(); + + crypto_sha1_c sha( this ); + if( sha.get_is_valid() == false ) + { + return EAP_STATUS_RETURN(this, eap_status_allocation_error); + } + + u32_t hash_len = sha.get_digest_length(); + // hash length must be at least the UUID length + if( hash_len < EAP_UUID_LENGTH ) + { + return EAP_STATUS_RETURN(this, eap_status_illegal_encryption_parameter_size); + } + + eap_status_e status = sha.hash_init(); + if( status != eap_status_ok ) + { + return EAP_STATUS_RETURN(this, status); + } + + status = sha.hash_update( ns_uuid, ns_uuid_length ); + if( status != eap_status_ok ) + { + return EAP_STATUS_RETURN(this, status); + } + + status = sha.hash_update( name, name_length ); + if( status != eap_status_ok ) + { + return EAP_STATUS_RETURN(this, status); + } + + u8_t* hash = new u8_t[hash_len]; + if( hash == 0 ) + { + return EAP_STATUS_RETURN(this, eap_status_allocation_error); + } + + status = sha.hash_final( hash, 0 ); // 0 - we have space for full digest in hash + if( status != eap_status_ok ) + { + delete[] hash; + hash = 0; + return EAP_STATUS_RETURN(this, status); + } + + // save only the needed bytes + status = uuid->set_copy_of_buffer(hash, EAP_UUID_LENGTH ); + delete[] hash; + if( status != eap_status_ok ) + { + return EAP_STATUS_RETURN(this, status); + } + + // use hash as a temporary pointer + hash = uuid->get_data(); + + // Format according to UUID version 5 (RFC 4122). + // MSByte LSByte + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | time_low | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | time_mid | time_hi_and_version | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // |clk_seq_hi_res | clk_seq_low | node (0-1) | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | node (2-5) | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + // set the four most significant bits (bits 12 through 15) of the + // time_hi_and_version field to the appropriate 4-bit version number + hash[6] &= 0x0F; + hash[6] |= 0x50; + + // set the two most significant bits (bits 6 and 7) of the + // clock_seq_hi_and_reserved to zero and one, respectively + hash[8] &= 0x3F; + hash[8] |= 0x80; + + return EAP_STATUS_RETURN(this, eap_status_ok); +} + +//----------------------------------------------------------------------------------------------- + +EAP_FUNC_EXPORT eap_status_e eap_am_tools_c::create_uuid_v5_from_mac_address( + const u8_t* const mac_address, + const u32_t mac_address_length, + eap_variable_data_c* const uuid ) +{ + + eap_status_e status = create_uuid_v5( + EAP_MAC_ADDRESS_NAMESPACE_UUID_V5, + sizeof(EAP_MAC_ADDRESS_NAMESPACE_UUID_V5), + mac_address, + mac_address_length, + uuid); + + return EAP_STATUS_RETURN(this, status); +} + +//----------------------------------------------------------------------------------------------- + +// End.