Skip to content

Commit

Permalink
Added throttling of number of simultaneous EAPOL authentications
Browse files Browse the repository at this point in the history
Authentication count is throttled based on border router TX queue and
memory.
  • Loading branch information
Mika Leppänen authored Feb 2, 2021
1 parent 0b84299 commit 3ad28c1
Show file tree
Hide file tree
Showing 13 changed files with 152 additions and 60 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*

### Changes
*
* Added throttling of number of simultaneous EAPOL authentications based on Border Router TX queue size

### Bugfix
*
Expand Down
67 changes: 66 additions & 1 deletion source/6LoWPAN/ws/ws_bootstrap.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ static void ws_bootstrap_nw_frame_counter_read(protocol_interface_info_entry_t *
static void ws_bootstrap_nw_info_updated(protocol_interface_info_entry_t *interface_ptr, uint16_t pan_id, uint16_t pan_version, char *network_name);
static void ws_bootstrap_authentication_completed(protocol_interface_info_entry_t *cur, auth_result_e result, uint8_t *target_eui_64);
static const uint8_t *ws_bootstrap_authentication_next_target(protocol_interface_info_entry_t *cur, const uint8_t *previous_eui_64, uint16_t *pan_id);
static bool ws_bootstrap_congestion_get(protocol_interface_info_entry_t *interface_ptr, uint16_t active_supp);
static void ws_bootstrap_pan_version_increment(protocol_interface_info_entry_t *cur);
static ws_nud_table_entry_t *ws_nud_entry_discover(protocol_interface_info_entry_t *cur, void *neighbor);
static void ws_nud_entry_remove(protocol_interface_info_entry_t *cur, mac_neighbor_table_entry_t *entry_ptr);
Expand Down Expand Up @@ -2316,7 +2317,7 @@ int ws_bootstrap_init(int8_t interface_id, net_6lowpan_mode_e bootstrap_mode)
ret_val = -4;
goto init_fail;
}
if (ws_pae_controller_cb_register(cur, &ws_bootstrap_authentication_completed, &ws_bootstrap_authentication_next_target, &ws_bootstrap_nw_key_set, &ws_bootstrap_nw_key_clear, &ws_bootstrap_nw_key_index_set, &ws_bootstrap_nw_frame_counter_set, &ws_bootstrap_nw_frame_counter_read, &ws_bootstrap_pan_version_increment, &ws_bootstrap_nw_info_updated) < 0) {
if (ws_pae_controller_cb_register(cur, &ws_bootstrap_authentication_completed, &ws_bootstrap_authentication_next_target, &ws_bootstrap_nw_key_set, &ws_bootstrap_nw_key_clear, &ws_bootstrap_nw_key_index_set, &ws_bootstrap_nw_frame_counter_set, &ws_bootstrap_nw_frame_counter_read, &ws_bootstrap_pan_version_increment, &ws_bootstrap_nw_info_updated, &ws_bootstrap_congestion_get) < 0) {
ret_val = -4;
goto init_fail;
}
Expand Down Expand Up @@ -3136,6 +3137,70 @@ static const uint8_t *ws_bootstrap_authentication_next_target(protocol_interface
return previous_eui_64;
}

static bool ws_bootstrap_congestion_get(protocol_interface_info_entry_t *interface_ptr, uint16_t active_supp)
{
if (interface_ptr == NULL || interface_ptr->random_early_detection == NULL) {
return false;
}

bool return_value = false;
static struct red_info_s *red_info = NULL;
uint16_t average = 0;
uint8_t active_max = 0;

//TODO implement API for HEAP info request
uint32_t heap_size;
const mem_stat_t *mem_stats = ns_dyn_mem_get_mem_stat();
if (mem_stats) {
heap_size = mem_stats->heap_sector_size;
} else {
heap_size = 0;
}

/*
* For different memory sizes the max simultaneous authentications will be
* 32k: (32k / 50k) * 2 + 1 = 1
* 65k: (65k / 50k) * 2 + 1 = 3
* 250k: (250k / 50k) * 2 + 1 = 11
* 1000k: (1000k / 50k) * 2 + 1 = 41
* 2000k: (2000k / 50k) * 2 + 1 = 50 (upper limit)
*/
active_max = (heap_size / 50000) * 2 + 1;
if (active_max > 50) {
active_max = 50;
}

// Maximum for active supplicants based on memory reached, fail
if (active_supp >= active_max) {
return_value = true;
goto congestion_get_end;
}

// Always allow at least five negotiations (if memory does not limit)
if (active_supp < 5) {
goto congestion_get_end;
}

if (red_info == NULL) {
red_info = random_early_detection_create(
interface_ptr->ws_info->cfg->sec_prot.max_simult_sec_neg_tx_queue_min,
interface_ptr->ws_info->cfg->sec_prot.max_simult_sec_neg_tx_queue_max,
100, RED_AVERAGE_WEIGHT_DISABLED);
}
if (red_info == NULL) {
goto congestion_get_end;
}

average = random_early_detetction_aq_read(interface_ptr->random_early_detection);
average = random_early_detetction_aq_calc(red_info, average);
return_value = random_early_detection_congestion_check(red_info);

congestion_get_end:
tr_info("Active supplicant limit, active: %i max: %i averageQ: %i drop: %s", active_supp, active_max, average, return_value ? "T" : "F");

return return_value;
}

// Start configuration learning
static void ws_bootstrap_start_configuration_learn(protocol_interface_info_entry_t *cur)
{
Expand Down
16 changes: 4 additions & 12 deletions source/6LoWPAN/ws/ws_cfg_settings.c
Original file line number Diff line number Diff line change
Expand Up @@ -457,8 +457,6 @@ static void ws_cfg_network_size_config_set_small(ws_cfg_nw_size_t *cfg)
cfg->sec_prot.sec_prot_trickle_timer_exp = SEC_PROT_TIMER_EXPIRATIONS;
cfg->sec_prot.sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_SMALL;

cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_SMALL;

cfg->sec_prot.initial_key_retry_delay = DEFAULT_INITIAL_KEY_RETRY_TIMER;
cfg->sec_prot.initial_key_imin = SMALL_NW_INITIAL_KEY_TRICKLE_IMIN_SECS;
cfg->sec_prot.initial_key_imax = SMALL_NW_INITIAL_KEY_TRICKLE_IMAX_SECS;
Expand Down Expand Up @@ -502,8 +500,6 @@ static void ws_cfg_network_size_config_set_medium(ws_cfg_nw_size_t *cfg)
cfg->sec_prot.sec_prot_trickle_timer_exp = SEC_PROT_TIMER_EXPIRATIONS;
cfg->sec_prot.sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_SMALL;

cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_MEDIUM;

cfg->sec_prot.initial_key_retry_delay = DEFAULT_INITIAL_KEY_RETRY_TIMER;
cfg->sec_prot.initial_key_imin = MEDIUM_NW_INITIAL_KEY_TRICKLE_IMIN_SECS;
cfg->sec_prot.initial_key_imax = MEDIUM_NW_INITIAL_KEY_TRICKLE_IMAX_SECS;
Expand Down Expand Up @@ -546,8 +542,6 @@ static void ws_cfg_network_size_config_set_large(ws_cfg_nw_size_t *cfg)
cfg->sec_prot.sec_prot_trickle_timer_exp = SEC_PROT_TIMER_EXPIRATIONS;
cfg->sec_prot.sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_LARGE;

cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_LARGE;

cfg->sec_prot.initial_key_retry_delay = NONE_INITIAL_KEY_RETRY_TIMER;
cfg->sec_prot.initial_key_imin = LARGE_NW_INITIAL_KEY_TRICKLE_IMIN_SECS;
cfg->sec_prot.initial_key_imax = LARGE_NW_INITIAL_KEY_TRICKLE_IMAX_SECS;
Expand Down Expand Up @@ -591,8 +585,6 @@ static void ws_cfg_network_size_config_set_xlarge(ws_cfg_nw_size_t *cfg)
cfg->sec_prot.sec_prot_trickle_timer_exp = SEC_PROT_TIMER_EXPIRATIONS;
cfg->sec_prot.sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_LARGE;

cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_LARGE;

cfg->sec_prot.initial_key_retry_delay = NONE_INITIAL_KEY_RETRY_TIMER;
cfg->sec_prot.initial_key_imin = EXTRA_LARGE_NW_INITIAL_KEY_TRICKLE_IMIN_SECS;
cfg->sec_prot.initial_key_imax = EXTRA_LARGE_NW_INITIAL_KEY_TRICKLE_IMAX_SECS;
Expand Down Expand Up @@ -635,8 +627,6 @@ static void ws_cfg_network_size_config_set_certificate(ws_cfg_nw_size_t *cfg)
cfg->sec_prot.sec_prot_trickle_timer_exp = SEC_PROT_TIMER_EXPIRATIONS;
cfg->sec_prot.sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_SMALL;

cfg->sec_prot.sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_SMALL;

cfg->sec_prot.initial_key_retry_delay = DEFAULT_INITIAL_KEY_RETRY_TIMER;
cfg->sec_prot.initial_key_imin = SMALL_NW_INITIAL_KEY_TRICKLE_IMIN_SECS;
cfg->sec_prot.initial_key_imax = SMALL_NW_INITIAL_KEY_TRICKLE_IMAX_SECS;
Expand Down Expand Up @@ -1237,7 +1227,8 @@ static int8_t ws_cfg_sec_prot_default_set(ws_sec_prot_cfg_t *cfg)
cfg->sec_prot_trickle_imax = SEC_PROT_SMALL_IMAX;
cfg->sec_prot_trickle_timer_exp = 2;
cfg->sec_prot_retry_timeout = SEC_PROT_RETRY_TIMEOUT_SMALL;
cfg->sec_max_ongoing_authentication = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_MEDIUM;
cfg->max_simult_sec_neg_tx_queue_min = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_TX_QUEUE_MIN;
cfg->max_simult_sec_neg_tx_queue_max = MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_TX_QUEUE_MAX;
cfg->initial_key_retry_delay = DEFAULT_INITIAL_KEY_RETRY_TIMER;
cfg->initial_key_imin = MEDIUM_NW_INITIAL_KEY_TRICKLE_IMIN_SECS;
cfg->initial_key_imax = MEDIUM_NW_INITIAL_KEY_TRICKLE_IMAX_SECS;
Expand All @@ -1263,7 +1254,8 @@ int8_t ws_cfg_sec_prot_validate(ws_sec_prot_cfg_t *cfg, ws_sec_prot_cfg_t *new_c
cfg->sec_prot_trickle_imax != new_cfg->sec_prot_trickle_imax ||
cfg->sec_prot_trickle_timer_exp != new_cfg->sec_prot_trickle_timer_exp ||
cfg->sec_prot_retry_timeout != new_cfg->sec_prot_retry_timeout ||
cfg->sec_max_ongoing_authentication != new_cfg->sec_max_ongoing_authentication ||
cfg->max_simult_sec_neg_tx_queue_min != new_cfg->max_simult_sec_neg_tx_queue_min ||
cfg->max_simult_sec_neg_tx_queue_max != new_cfg->max_simult_sec_neg_tx_queue_max ||
cfg->initial_key_retry_delay != new_cfg->initial_key_retry_delay ||
cfg->initial_key_imin != new_cfg->initial_key_retry_delay ||
cfg->initial_key_imax != new_cfg->initial_key_retry_delay ||
Expand Down
3 changes: 2 additions & 1 deletion source/6LoWPAN/ws/ws_cfg_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ typedef struct ws_sec_prot_cfg_s {
uint16_t sec_prot_trickle_imin; /**< Security protocol trickle parameters Imin; seconds; default 30 */
uint16_t sec_prot_trickle_imax; /**< Security protocol trickle parameters Imax; seconds; default 90 */
uint8_t sec_prot_trickle_timer_exp; /**< Security protocol trickle timer expirations; default 2 */
uint16_t sec_max_ongoing_authentication; /**< Pae authenticator max Accept ongoing authentication count */
uint16_t max_simult_sec_neg_tx_queue_min; /**< PAE authenticator max simultaneous security negotiations TX queue minimum */
uint16_t max_simult_sec_neg_tx_queue_max; /**< PAE authenticator max simultaneous security negotiations TX queue maximum */
uint16_t initial_key_retry_delay; /**< Delay before starting initial key trickle; seconds; default 120 */
uint16_t initial_key_imin; /**< Initial key trickle Imin; seconds; default 360 */
uint16_t initial_key_imax; /**< Initial key trickle Imax; seconds; default 720 */
Expand Down
5 changes: 2 additions & 3 deletions source/6LoWPAN/ws/ws_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -254,9 +254,8 @@ extern uint8_t DEVICE_MIN_SENS;
#define SEC_PROT_TIMER_EXPIRATIONS 2 // Number of retries

// Maximum number of simultaneous security negotiations
#define MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_SMALL 20
#define MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_MEDIUM 20
#define MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_LARGE 50
#define MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_TX_QUEUE_MIN 64
#define MAX_SIMULTANEOUS_SECURITY_NEGOTIATIONS_TX_QUEUE_MAX 192

/*
* Security protocol timer configuration parameters
Expand Down
22 changes: 17 additions & 5 deletions source/6LoWPAN/ws/ws_pae_auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ typedef struct {
ws_pae_auth_nw_key_index_set *nw_key_index_set; /**< Key index set callback */
ws_pae_auth_nw_info_updated *nw_info_updated; /**< Security keys network info updated callback */
ws_pae_auth_ip_addr_get *ip_addr_get; /**< IP address get callback */
ws_pae_auth_congestion_get *congestion_get; /**< Congestion get callback */
supp_list_t active_supp_list; /**< List of active supplicants */
shared_comp_list_t shared_comp_list; /**< Shared component list */
arm_event_storage_t *timer; /**< Timer */
Expand Down Expand Up @@ -128,6 +129,7 @@ static bool ws_pae_auth_timer_running(pae_auth_t *pae_auth);
static void ws_pae_auth_kmp_service_addr_get(kmp_service_t *service, kmp_api_t *kmp, kmp_addr_t *local_addr, kmp_addr_t *remote_addr);
static void ws_pae_auth_kmp_service_ip_addr_get(kmp_service_t *service, kmp_api_t *kmp, uint8_t *address);
static kmp_api_t *ws_pae_auth_kmp_service_api_get(kmp_service_t *service, kmp_api_t *kmp, kmp_type_e type);
static bool ws_pae_auth_active_limit_reached(uint16_t active_supp, pae_auth_t *pae_auth);
static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, uint8_t msg_if_instance_id, kmp_type_e type, const kmp_addr_t *addr, const void *pdu, uint16_t size);
static void ws_pae_auth_kmp_api_create_confirm(kmp_api_t *kmp, kmp_result_e result);
static void ws_pae_auth_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e type, kmp_addr_t *addr);
Expand Down Expand Up @@ -166,6 +168,9 @@ int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot
pae_auth->nw_key_insert = NULL;
pae_auth->nw_keys_remove = NULL;
pae_auth->nw_key_index_set = NULL;
pae_auth->nw_info_updated = NULL;
pae_auth->ip_addr_get = NULL;
pae_auth->congestion_get = NULL;

pae_auth->next_gtks = next_gtks;
pae_auth->certs = certs;
Expand Down Expand Up @@ -302,7 +307,7 @@ int8_t ws_pae_auth_delete(protocol_interface_info_entry_t *interface_ptr)
return 0;
}

void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated, ws_pae_auth_ip_addr_get *ip_addr_get)
void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated, ws_pae_auth_ip_addr_get *ip_addr_get, ws_pae_auth_congestion_get *congestion_get)
{
if (!interface_ptr) {
return;
Expand All @@ -318,6 +323,7 @@ void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_
pae_auth->nw_key_index_set = nw_key_index_set;
pae_auth->nw_info_updated = nw_info_updated;
pae_auth->ip_addr_get = ip_addr_get;
pae_auth->congestion_get = congestion_get;
}

void ws_pae_auth_start(protocol_interface_info_entry_t *interface_ptr)
Expand Down Expand Up @@ -936,6 +942,11 @@ static kmp_api_t *ws_pae_auth_kmp_service_api_get(kmp_service_t *service, kmp_ap
return ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, type);
}

static bool ws_pae_auth_active_limit_reached(uint16_t active_supp, pae_auth_t *pae_auth)
{
return pae_auth->congestion_get(pae_auth->interface_ptr, active_supp);
}

static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, uint8_t msg_if_instance_id, kmp_type_e type, const kmp_addr_t *addr, const void *pdu, uint16_t size)
{
pae_auth_t *pae_auth = ws_pae_auth_by_kmp_service_get(service);
Expand All @@ -954,8 +965,9 @@ static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, uint8_t m
supp_entry_t *supp_entry = ws_pae_lib_supp_list_entry_eui_64_get(&pae_auth->active_supp_list, kmp_address_eui_64_get(addr));

if (!supp_entry) {
uint16_t active_supp = ns_list_count(&pae_auth->active_supp_list);
// Checks if active supplicant list has space for new supplicants
if (ws_pae_lib_supp_list_active_limit_reached(&pae_auth->active_supp_list, pae_auth->sec_cfg->prot_cfg.sec_max_ongoing_authentication)) {
if (ws_pae_auth_active_limit_reached(active_supp, pae_auth)) {
tr_debug("PAE: active limit reached, eui-64: %s", trace_array(kmp_address_eui_64_get(addr), 8));
return NULL;
}
Expand Down Expand Up @@ -1103,10 +1115,10 @@ static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *sup
trigger timeout, authenticator initiates EAP-TLS towards
supplicant. Otherwise supplicant must re-send initial EAPOL-Key
to try again using its trickle schedule */
uint16_t ongoing_eap_tls_cnt = ws_pae_lib_supp_list_kmp_count(&pae_auth->active_supp_list, next_type);
if (ongoing_eap_tls_cnt >= pae_auth->sec_cfg->prot_cfg.sec_max_ongoing_authentication) {
uint16_t active_supp = ns_list_count(&pae_auth->active_supp_list);
if (ws_pae_auth_active_limit_reached(active_supp, pae_auth)) {
supp_entry->retry_ticks = EAP_TLS_NEGOTIATION_TRIGGER_TIMEOUT;
tr_info("EAP-TLS max ongoing reached, count %i, delayed: eui-64: %s", ongoing_eap_tls_cnt, trace_array(supp_entry->addr.eui_64, 8));
tr_info("EAP-TLS max ongoing reached, count %i, delayed: eui-64: %s", active_supp, trace_array(supp_entry->addr.eui_64, 8));
return;
}
}
Expand Down
16 changes: 14 additions & 2 deletions source/6LoWPAN/ws/ws_pae_auth.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,17 @@ typedef void ws_pae_auth_nw_info_updated(protocol_interface_info_entry_t *interf
*/
typedef void ws_pae_auth_ip_addr_get(protocol_interface_info_entry_t *interface_ptr, uint8_t *address);

/**
* ws_pae_auth_congestion_get get congestion information
*
* \param interface_ptr interface
* \param active_supp active supplicants
*
* \return TRUE reject, FALSE accept
*
*/
typedef bool ws_pae_auth_congestion_get(protocol_interface_info_entry_t *interface_ptr, uint16_t active_supp);

/**
* ws_pae_auth_cb_register register PAE authenticator callbacks
*
Expand All @@ -258,17 +269,18 @@ typedef void ws_pae_auth_ip_addr_get(protocol_interface_info_entry_t *interface_
* \param nw_key_index_set network send key index callback
* \param nw_info_updated network keys updated callback
* \param ip_addr_get IP addressing information callback
* \param congestion_get congestion get callback
*
*/
void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated, ws_pae_auth_ip_addr_get *ip_addr_get);
void ws_pae_auth_cb_register(protocol_interface_info_entry_t *interface_ptr, ws_pae_auth_gtk_hash_set *hash_set, ws_pae_auth_nw_key_insert *nw_key_insert, ws_pae_auth_nw_key_index_set *nw_key_index_set, ws_pae_auth_nw_info_updated *nw_info_updated, ws_pae_auth_ip_addr_get *ip_addr_get, ws_pae_auth_congestion_get *congestion_get);

#else

#define ws_pae_auth_init(interface_ptr, next_gtks, certs, sec_cfg, sec_keys_nw_info) 1
#define ws_pae_auth_timing_adjust(timing)
#define ws_pae_auth_addresses_set(interface_ptr, local_port, remote_addr, remote_port) 1
#define ws_pae_auth_delete NULL
#define ws_pae_auth_cb_register(interface_ptr, hash_set, nw_key_insert, nw_key_index_set, nw_info_updated, ip_addr_get) {(void) hash_set;}
#define ws_pae_auth_cb_register(interface_ptr, hash_set, nw_key_insert, nw_key_index_set, nw_info_updated, ip_addr_get, congestion_get) {(void) hash_set;}
#define ws_pae_auth_start(interface_ptr)
#define ws_pae_auth_gtks_updated NULL
#define ws_pae_auth_nw_key_index_update NULL
Expand Down
Loading

0 comments on commit 3ad28c1

Please sign in to comment.