--- /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<u8_t>('0' + octet);
+ }
+ else if (10 <= octet && octet <= 16)
+ {
+ return static_cast<u8_t>('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<u8_t>(character - '0');
+ }
+ else if ('a' <= character && character <= 'f')
+ {
+ return static_cast<u8_t>((character - 'a') + 10u);
+ }
+ else if ('A' <= character && character <= 'F')
+ {
+ return static_cast<u8_t>((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<const u8_t *>(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<u32_t>(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<u32_t>(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<u32_t>(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<u32_t>(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<u32_t>(real_sleep_time),
+ static_cast<u32_t>(delay_time)));
+
+ next_sleep_time = pulse_timer(static_cast<u32_t>(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<u32_t>(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<u32_t>(real_sleep_time),
+ static_cast<u32_t>(virtual_time),
+ static_cast<u32_t>(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<const u8_t *>(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<u8_t>(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<const u8_t *>(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<u8_t>((source_byte) + 'A');
+ }
+ else if (26u <= source_byte && source_byte < 52u)
+ {
+ // 'a' ... 'z'
+ return static_cast<u8_t>((source_byte - 26u) + 'a');
+ }
+ else if (52u <= source_byte && source_byte < 62u)
+ {
+ // '0' ... '9'
+ return static_cast<u8_t>(source_byte - 52u + '0');
+ }
+ else if (source_byte == 62u)
+ {
+ return static_cast<u8_t>('+');
+ }
+ else if (source_byte == 63u)
+ {
+ return static_cast<u8_t>('/');
+ }
+ 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<u8_t>((source_byte) - 'A');
+ }
+ else if ('a' <= source_byte && source_byte <= 'z')
+ {
+ // 'a' ... 'z'
+ return static_cast<u8_t>((source_byte + 26u) - 'a');
+ }
+ else if ('0' <= source_byte && source_byte <= '9')
+ {
+ // '0' ... '9'
+ return static_cast<u8_t>((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<u8_t>(source_byte >> 2u));
+ *saved_bits = static_cast<u8_t>(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<u8_t>(((*saved_bits) << 4u) | ((source_byte & 0xf0) >> 4u));
+ value = octet_to_ascii_armor(src);
+ *saved_bits = static_cast<u8_t>(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<u8_t>(((*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<u8_t>(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<u8_t>((*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<u8_t>(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<u8_t>((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<u8_t>((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<const u8_t *>(
+ 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<u32_t>(at_character))
+ - reinterpret_cast<u32_t>(nai->get_data(
+ nai->get_data_length()))))
+ {
+ u32_t realm_length = nai->get_data_length()
+ - ((1UL + reinterpret_cast<u32_t>(at_character))
+ - reinterpret_cast<u32_t>(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<u8_t *>(&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<u8_t *>(&error_type),
+ sizeof(error_type));
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(this, status);
+ }
+
+ error_type = static_cast<eap_random_error_type>(
+ static_cast<u32_t>(error_type)
+ % static_cast<u32_t>(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<u8_t *>(&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<u8_t *>(&delta_length),
+ sizeof(delta_length));
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(this, status);
+ }
+
+ new_length = static_cast<i32_t>(sent_packet->get_data_length()) + static_cast<i32_t>(delta_length);
+ }
+ while (new_length < static_cast<i32_t>(minimum_packet_length) /*eapol_ethernet_header_wr_c::get_header_length()*/
+ || new_length > static_cast<i32_t>(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<u8_t *>(&delta_length),
+ sizeof(delta_length));
+ if (status != eap_status_ok)
+ {
+ return EAP_STATUS_RETURN(this, status);
+ }
+
+ delta_length %= (static_cast<i32_t>(sent_packet->get_data_length())
+ - static_cast<i32_t>(minimum_packet_length) /*eapol_ethernet_header_wr_c::get_header_length()*/ );
+
+ if (delta_length == 0)
+ {
+ continue;
+ }
+
+ new_length = static_cast<i32_t>(sent_packet->get_data_length()) - static_cast<i32_t>(delta_length);
+ }
+ while (new_length < static_cast<i32_t>(minimum_packet_length) /*eapol_ethernet_header_wr_c::get_header_length()*/
+ || new_length > static_cast<i32_t>(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<i32_t>(number_string[ind]));
+
+ u32_t addition = static_cast<u32_t>(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.