Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ws_pae_auth.c Source File

ws_pae_auth.c

00001 /*
00002  * Copyright (c) 2018-2019, Arm Limited and affiliates.
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 #include "nsconfig.h"
00019 #include <string.h>
00020 #include <randLIB.h>
00021 #include "ns_types.h"
00022 #include "ns_list.h"
00023 #include "ns_trace.h"
00024 #include "nsdynmemLIB.h"
00025 #include "fhss_config.h "
00026 #include "eventOS_event.h"
00027 #include "eventOS_scheduler.h"
00028 #include "eventOS_event_timer.h"
00029 #include "ns_address.h"
00030 #include "NWK_INTERFACE/Include/protocol.h"
00031 #include "6LoWPAN/ws/ws_config.h"
00032 #include "Security/kmp/kmp_addr.h"
00033 #include "Security/kmp/kmp_api.h"
00034 #include "Security/kmp/kmp_socket_if.h"
00035 #include "Security/protocols/sec_prot_certs.h"
00036 #include "Security/protocols/sec_prot_keys.h"
00037 #include "Security/protocols/key_sec_prot/key_sec_prot.h"
00038 #include "Security/protocols/eap_tls_sec_prot/auth_eap_tls_sec_prot.h"
00039 #include "Security/protocols/tls_sec_prot/tls_sec_prot.h"
00040 #include "Security/protocols/fwh_sec_prot/auth_fwh_sec_prot.h"
00041 #include "Security/protocols/gkh_sec_prot/auth_gkh_sec_prot.h"
00042 #include "6LoWPAN/ws/ws_pae_controller.h"
00043 #include "6LoWPAN/ws/ws_pae_timers.h"
00044 #include "6LoWPAN/ws/ws_pae_auth.h"
00045 #include "6LoWPAN/ws/ws_pae_lib.h"
00046 
00047 #ifdef HAVE_WS
00048 #ifdef HAVE_PAE_AUTH
00049 
00050 #define TRACE_GROUP "wspa"
00051 
00052 #define PAE_TASKLET_INIT                       1
00053 #define PAE_TASKLET_EVENT                      2
00054 #define PAE_TASKLET_TIMER                      3
00055 
00056 // Wait for for supplicant to indicate activity (e.g. to send a message)
00057 #define WAIT_FOR_AUTHENTICATION_TICKS          5 * 60 * 10  // 5 minutes
00058 
00059 // Maximum number of simultaneous EAP-TLS negotiations
00060 #define MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS  3
00061 
00062 /* If EAP-TLS is delayed due to simultaneous negotiations limit, defines how
00063    long to wait for previous negotiation to complete */
00064 #define EAP_TLS_NEGOTIATION_TRIGGER_TIMEOUT    60 * 10 // 60 seconds
00065 
00066 // Default for maximum number of supplicants
00067 #define SUPPLICANT_MAX_NUMBER                  1000
00068 
00069 /* Default for number of supplicants to purge per garbage collect call from
00070    nanostack monitor */
00071 #define SUPPLICANT_NUMBER_TO_PURGE             5
00072 
00073 typedef struct {
00074     ns_list_link_t link;                                     /**< Link */
00075     kmp_service_t *kmp_service;                              /**< KMP service */
00076     protocol_interface_info_entry_t *interface_ptr;          /**< Interface pointer */
00077     ws_pae_auth_gtk_hash_set *hash_set;                      /**< GTK hash set callback */
00078     ws_pae_auth_nw_key_insert *nw_key_insert;                /**< Key insert callback */
00079     ws_pae_auth_nw_key_index_set *nw_key_index_set;          /**< Key index set callback */
00080     supp_list_t active_supp_list;                            /**< List of active supplicants */
00081     supp_list_t inactive_supp_list;                          /**< List of inactive supplicants */
00082     arm_event_storage_t *timer;                              /**< Timer */
00083     sec_prot_gtk_keys_t *gtks;                               /**< GTKs */
00084     sec_prot_gtk_keys_t *next_gtks;                          /**< Next GTKs */
00085     const sec_prot_certs_t *certs;                           /**< Certificates */
00086     timer_settings_t *timer_settings;                        /**< Timer settings */
00087     uint16_t supp_max_number;                                /**< Max number of stored supplicants */
00088     uint16_t slow_timer_seconds;                             /**< Slow timer seconds */
00089     bool timer_running : 1;                                  /**< Timer is running */
00090     bool gtk_new_inst_req_exp : 1;                           /**< GTK new install required timer expired */
00091     bool gtk_new_act_time_exp: 1;                            /**< GTK new activation time expired */
00092 } pae_auth_t;
00093 
00094 static int8_t ws_pae_auth_network_keys_from_gtks_set(pae_auth_t *pae_auth);
00095 static int8_t ws_pae_auth_active_gtk_set(pae_auth_t *pae_auth, uint8_t index);
00096 static int8_t ws_pae_auth_network_key_index_set(pae_auth_t *pae_auth, uint8_t index);
00097 static void ws_pae_auth_free(pae_auth_t *pae_auth);
00098 static pae_auth_t *ws_pae_auth_get(protocol_interface_info_entry_t *interface_ptr);
00099 static pae_auth_t *ws_pae_auth_by_kmp_service_get(kmp_service_t *service);
00100 static int8_t ws_pae_auth_event_send(kmp_service_t *service, void *data);
00101 static void ws_pae_auth_tasklet_handler(arm_event_s *event);
00102 static void ws_pae_auth_gtk_key_insert(pae_auth_t *pae_auth);
00103 static int8_t ws_pae_auth_new_gtk_activate(pae_auth_t *pae_auth);
00104 static int8_t ws_pae_auth_timer_if_start(kmp_service_t *service, kmp_api_t *kmp);
00105 static int8_t ws_pae_auth_timer_if_stop(kmp_service_t *service, kmp_api_t *kmp);
00106 static int8_t ws_pae_auth_timer_start(pae_auth_t *pae_auth);
00107 static int8_t ws_pae_auth_timer_stop(pae_auth_t *pae_auth);
00108 static bool ws_pae_auth_timer_running(pae_auth_t *pae_auth);
00109 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);
00110 static kmp_api_t *ws_pae_auth_kmp_service_api_get(kmp_service_t *service, kmp_api_t *kmp, kmp_type_e type);
00111 static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, kmp_type_e type, const kmp_addr_t *addr);
00112 static void ws_pae_auth_kmp_api_create_confirm(kmp_api_t *kmp, kmp_result_e result);
00113 static void ws_pae_auth_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e type, kmp_addr_t *addr);
00114 static void ws_pae_auth_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys);
00115 static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *supp_entry);
00116 static kmp_type_e ws_pae_auth_next_protocol_get(supp_entry_t *supp_entry);
00117 static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, supp_entry_t *supp_entry);
00118 static void ws_pae_auth_kmp_api_finished(kmp_api_t *kmp);
00119 
00120 static int8_t tasklet_id = -1;
00121 static NS_LIST_DEFINE(pae_auth_list, pae_auth_t, link);
00122 
00123 int8_t ws_pae_auth_init(protocol_interface_info_entry_t *interface_ptr, sec_prot_gtk_keys_t *gtks, sec_prot_gtk_keys_t *next_gtks, const sec_prot_certs_t *certs, timer_settings_t *timer_settings)
00124 {
00125     if (!interface_ptr || !gtks || !certs) {
00126         return -1;
00127     }
00128 
00129     if (ws_pae_auth_get(interface_ptr) != NULL) {
00130         return 0;
00131     }
00132 
00133     pae_auth_t *pae_auth = ns_dyn_mem_alloc(sizeof(pae_auth_t));
00134     if (!pae_auth) {
00135         return -1;
00136     }
00137 
00138     pae_auth->interface_ptr = interface_ptr;
00139     ws_pae_lib_supp_list_init(&pae_auth->active_supp_list);
00140     ws_pae_lib_supp_list_init(&pae_auth->inactive_supp_list);
00141     pae_auth->timer = NULL;
00142 
00143     pae_auth->hash_set = NULL;
00144     pae_auth->nw_key_insert = NULL;
00145     pae_auth->nw_key_index_set = NULL;
00146 
00147     pae_auth->gtks = gtks;
00148     pae_auth->next_gtks = next_gtks;
00149     pae_auth->certs = certs;
00150     pae_auth->timer_settings = timer_settings;
00151     pae_auth->supp_max_number = SUPPLICANT_MAX_NUMBER;
00152 
00153     pae_auth->slow_timer_seconds = 0;
00154     pae_auth->gtk_new_inst_req_exp = false;
00155     pae_auth->gtk_new_act_time_exp = false;
00156 
00157     pae_auth->kmp_service = kmp_service_create();
00158     if (!pae_auth->kmp_service) {
00159         goto error;
00160     }
00161 
00162     if (kmp_service_cb_register(pae_auth->kmp_service, ws_pae_auth_kmp_incoming_ind, NULL, ws_pae_auth_kmp_service_addr_get, ws_pae_auth_kmp_service_api_get)) {
00163         goto error;
00164     }
00165 
00166     if (kmp_service_event_if_register(pae_auth->kmp_service, ws_pae_auth_event_send)) {
00167         goto error;
00168     }
00169 
00170     if (kmp_service_timer_if_register(pae_auth->kmp_service, ws_pae_auth_timer_if_start, ws_pae_auth_timer_if_stop)) {
00171         goto error;
00172     }
00173 
00174     if (auth_key_sec_prot_register(pae_auth->kmp_service) < 0) {
00175         goto error;
00176     }
00177 
00178     if (auth_eap_tls_sec_prot_register(pae_auth->kmp_service) < 0) {
00179         goto error;
00180     }
00181 
00182     if (server_tls_sec_prot_register(pae_auth->kmp_service) < 0) {
00183         goto error;
00184     }
00185 
00186     if (auth_fwh_sec_prot_register(pae_auth->kmp_service) < 0) {
00187         goto error;
00188     }
00189 
00190     if (auth_gkh_sec_prot_register(pae_auth->kmp_service) < 0) {
00191         goto error;
00192     }
00193 
00194     if (tasklet_id < 0) {
00195         tasklet_id = eventOS_event_handler_create(ws_pae_auth_tasklet_handler, PAE_TASKLET_INIT);
00196         if (tasklet_id < 0) {
00197             goto error;
00198         }
00199     }
00200 
00201     if (ws_pae_auth_timer_stop(pae_auth) < 0) {
00202         goto error;
00203     }
00204 
00205     ns_list_add_to_end(&pae_auth_list, pae_auth);
00206 
00207     return 0;
00208 
00209 error:
00210     ws_pae_auth_free(pae_auth);
00211 
00212     return -1;
00213 }
00214 
00215 int8_t ws_pae_auth_timing_adjust(uint8_t timing)
00216 {
00217     auth_gkh_sec_prot_timing_adjust(timing);
00218     auth_fwh_sec_prot_timing_adjust(timing);
00219     auth_eap_tls_sec_prot_timing_adjust(timing);
00220     return 0;
00221 }
00222 
00223 int8_t ws_pae_auth_addresses_set(protocol_interface_info_entry_t *interface_ptr, uint16_t local_port, const uint8_t *remote_addr, uint16_t remote_port)
00224 {
00225     if (!interface_ptr || !remote_addr) {
00226         return -1;
00227     }
00228 
00229     pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr);
00230     if (!pae_auth) {
00231         return -1;
00232     }
00233     if (!pae_auth->kmp_service) {
00234         return -1;
00235     }
00236 
00237     if (kmp_socket_if_register(pae_auth->kmp_service, local_port, remote_addr, remote_port) < 0) {
00238         return -1;
00239     }
00240 
00241     return 0;
00242 }
00243 
00244 int8_t ws_pae_auth_delete(protocol_interface_info_entry_t *interface_ptr)
00245 {
00246     if (!interface_ptr) {
00247         return -1;
00248     }
00249 
00250     pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr);
00251     if (!pae_auth) {
00252         return -1;
00253     }
00254 
00255     ws_pae_auth_free(pae_auth);
00256     return 0;
00257 }
00258 
00259 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)
00260 {
00261     if (!interface_ptr) {
00262         return;
00263     }
00264 
00265     pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr);
00266     if (!pae_auth) {
00267         return;
00268     }
00269 
00270     pae_auth->hash_set = hash_set;
00271     pae_auth->nw_key_insert = nw_key_insert;
00272     pae_auth->nw_key_index_set = nw_key_index_set;
00273 }
00274 
00275 void ws_pae_auth_start(protocol_interface_info_entry_t *interface_ptr)
00276 {
00277     if (!interface_ptr) {
00278         return;
00279     }
00280 
00281     pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr);
00282     if (!pae_auth) {
00283         return;
00284     }
00285 
00286     // Checks if there is predefined active key
00287     int8_t index = sec_prot_keys_gtk_status_active_get(pae_auth->gtks);
00288     if (index < 0) {
00289         // If there is no key, inserts a new one
00290         ws_pae_auth_gtk_key_insert(pae_auth);
00291         index = sec_prot_keys_gtk_install_order_first_index_get(pae_auth->gtks);
00292         ws_pae_auth_active_gtk_set(pae_auth, index);
00293     } else {
00294         ws_pae_auth_active_gtk_set(pae_auth, index);
00295     }
00296 
00297     // Inserts keys and updates GTK hash on stack
00298     ws_pae_auth_network_keys_from_gtks_set(pae_auth);
00299 
00300     // Sets active key index
00301     ws_pae_auth_network_key_index_set(pae_auth, index);
00302 }
00303 
00304 void ws_pae_auth_gtks_updated(protocol_interface_info_entry_t *interface_ptr)
00305 {
00306     if (!interface_ptr) {
00307         return;
00308     }
00309 
00310     pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr);
00311     if (!pae_auth) {
00312         return;
00313     }
00314 
00315     ws_pae_auth_network_keys_from_gtks_set(pae_auth);
00316 }
00317 
00318 int8_t ws_pae_auth_nw_key_index_update(protocol_interface_info_entry_t *interface_ptr, uint8_t index)
00319 {
00320     if (!interface_ptr) {
00321         return -1;
00322     }
00323 
00324     pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr);
00325     if (!pae_auth) {
00326         return -1;
00327     }
00328 
00329     ws_pae_auth_active_gtk_set(pae_auth, index);
00330     ws_pae_auth_network_key_index_set(pae_auth, index);
00331     return 0;
00332 }
00333 
00334 int8_t ws_pae_auth_node_keys_remove(protocol_interface_info_entry_t *interface_ptr, uint8_t *eui_64)
00335 {
00336     if (!interface_ptr) {
00337         return -1;
00338     }
00339 
00340     pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr);
00341     if (!pae_auth) {
00342         return -1;
00343     }
00344 
00345     // Checks if supplicant is active
00346     supp_entry_t *supp = ws_pae_lib_supp_list_entry_eui_64_get(&pae_auth->active_supp_list, eui_64);
00347 
00348     if (supp) {
00349         // Deletes keys and marks as revoked
00350         sec_prot_keys_pmk_delete(&supp->sec_keys);
00351         sec_prot_keys_ptk_delete(&supp->sec_keys);
00352         supp->access_revoked = true;
00353         tr_info("Access revoked; keys removed, eui-64: %s", trace_array(supp->addr.eui_64, 8));
00354         return 0;
00355     }
00356 
00357     // Checks if supplicant is inactive
00358     supp = ws_pae_lib_supp_list_entry_eui_64_get(&pae_auth->inactive_supp_list, eui_64);
00359     if (supp) {
00360         // Deletes supplicant
00361         tr_info("Access revoked; deleted, eui-64: %s", trace_array(supp->addr.eui_64, 8));
00362         ws_pae_lib_supp_list_remove(&pae_auth->inactive_supp_list, supp);
00363         return 0;
00364     }
00365 
00366     return -1;
00367 }
00368 
00369 int8_t ws_pae_auth_node_access_revoke_start(protocol_interface_info_entry_t *interface_ptr)
00370 {
00371     if (!interface_ptr) {
00372         return -1;
00373     }
00374 
00375     pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr);
00376     if (!pae_auth) {
00377         return -1;
00378     }
00379 
00380     // Gets active GTK
00381     int8_t active_index = sec_prot_keys_gtk_status_active_get(pae_auth->gtks);
00382 
00383     if (active_index >= 0) {
00384         // As default removes other keys than active
00385         int8_t not_removed_index = active_index;
00386 
00387         uint32_t revocation_lifetime = ws_pae_timers_gtk_revocation_lifetime_get(pae_auth->timer_settings);
00388 
00389         uint32_t active_lifetime = sec_prot_keys_gtk_lifetime_get(pae_auth->gtks, active_index);
00390 
00391         // If active GTK lifetime is larger than revocation lifetime decrements active GTK lifetime
00392         if (active_lifetime > revocation_lifetime) {
00393             sec_prot_keys_gtk_lifetime_decrement(pae_auth->gtks, active_index, active_lifetime - revocation_lifetime);
00394             tr_info("Access revocation start, GTK active index: %i, revoked lifetime: %"PRIu32"", active_index, revocation_lifetime);
00395         } else {
00396             // Otherwise decrements lifetime of the GTK to be installed after the active one
00397             int8_t second_index = sec_prot_keys_gtk_install_order_second_index_get(pae_auth->gtks);
00398             if (second_index >= 0) {
00399                 // Second GTK revocation lifetime is the active GTK lifetime added with revocation time
00400                 uint32_t second_revocation_lifetime = active_lifetime + revocation_lifetime;
00401 
00402                 uint32_t second_lifetime = sec_prot_keys_gtk_lifetime_get(pae_auth->gtks, second_index);
00403                 if (second_lifetime > second_revocation_lifetime) {
00404                     sec_prot_keys_gtk_lifetime_decrement(pae_auth->gtks, second_index, second_lifetime - second_revocation_lifetime);
00405                     tr_info("Access revocation start, GTK second active index: %i, revoked lifetime: %"PRIu32"", second_index, second_revocation_lifetime);
00406                 }
00407                 // Removes other keys than active and GTK to be installed next
00408                 not_removed_index = second_index;
00409             }
00410         }
00411 
00412         // Deletes other GTKs
00413         int8_t last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->gtks);
00414         while (last_index >= 0 && last_index != not_removed_index) {
00415             tr_info("Access revocation GTK clear index: %i", last_index);
00416             sec_prot_keys_gtk_clear(pae_auth->gtks, last_index);
00417             last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->gtks);
00418         }
00419     }
00420 
00421     // Adds new GTK
00422     ws_pae_auth_gtk_key_insert(pae_auth);
00423     ws_pae_auth_network_keys_from_gtks_set(pae_auth);
00424 
00425     return 0;
00426 }
00427 
00428 int8_t ws_pae_auth_node_limit_set(protocol_interface_info_entry_t *interface_ptr, uint16_t limit)
00429 {
00430     if (!interface_ptr) {
00431         return -1;
00432     }
00433 
00434     pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr);
00435     if (!pae_auth) {
00436         return -1;
00437     }
00438 
00439     pae_auth->supp_max_number = limit;
00440 
00441     return 0;
00442 }
00443 
00444 void ws_pae_auth_forced_gc(protocol_interface_info_entry_t *interface_ptr)
00445 {
00446     if (!interface_ptr) {
00447         return;
00448     }
00449 
00450     pae_auth_t *pae_auth = ws_pae_auth_get(interface_ptr);
00451     if (!pae_auth) {
00452         return;
00453     }
00454 
00455     /* Purge in maximum five entries from supplicant list (starting from oldest one)
00456        per call to the function (called by nanostack monitor) */
00457     ws_pae_lib_supp_list_purge(&pae_auth->active_supp_list, &pae_auth->inactive_supp_list, 0, SUPPLICANT_NUMBER_TO_PURGE);
00458 }
00459 
00460 static int8_t ws_pae_auth_network_keys_from_gtks_set(pae_auth_t *pae_auth)
00461 {
00462     // Authenticator keys are always fresh
00463     sec_prot_keys_gtk_status_all_fresh_set(pae_auth->gtks);
00464 
00465     if (pae_auth->hash_set) {
00466         uint8_t gtk_hash[32];
00467         sec_prot_keys_gtks_hash_generate(pae_auth->gtks, gtk_hash);
00468         pae_auth->hash_set(pae_auth->interface_ptr, gtk_hash);
00469     }
00470 
00471     if (pae_auth->nw_key_insert) {
00472         pae_auth->nw_key_insert(pae_auth->interface_ptr, pae_auth->gtks);
00473     }
00474 
00475     return 0;
00476 }
00477 
00478 static int8_t ws_pae_auth_active_gtk_set(pae_auth_t *pae_auth, uint8_t index)
00479 {
00480     return sec_prot_keys_gtk_status_active_set(pae_auth->gtks, index);
00481 }
00482 
00483 static int8_t ws_pae_auth_gtk_clear(pae_auth_t *pae_auth, uint8_t index)
00484 {
00485     return sec_prot_keys_gtk_clear(pae_auth->gtks, index);
00486 }
00487 
00488 static int8_t ws_pae_auth_network_key_index_set(pae_auth_t *pae_auth, uint8_t index)
00489 {
00490     if (pae_auth->nw_key_index_set) {
00491         pae_auth->nw_key_index_set(pae_auth->interface_ptr, index);
00492     }
00493 
00494     return 0;
00495 }
00496 
00497 static void ws_pae_auth_free(pae_auth_t *pae_auth)
00498 {
00499     if (!pae_auth) {
00500         return;
00501     }
00502 
00503     ws_pae_lib_supp_list_delete(&pae_auth->active_supp_list);
00504     ws_pae_lib_supp_list_delete(&pae_auth->inactive_supp_list);
00505 
00506     kmp_socket_if_unregister(pae_auth->kmp_service);
00507 
00508     kmp_service_delete(pae_auth->kmp_service);
00509 
00510     ns_list_remove(&pae_auth_list, pae_auth);
00511     ns_dyn_mem_free(pae_auth);
00512 }
00513 
00514 static pae_auth_t *ws_pae_auth_get(protocol_interface_info_entry_t *interface_ptr)
00515 {
00516     ns_list_foreach(pae_auth_t, entry, &pae_auth_list) {
00517         if (entry->interface_ptr == interface_ptr) {
00518             return entry;
00519         }
00520     }
00521 
00522     return NULL;
00523 }
00524 
00525 static pae_auth_t *ws_pae_auth_by_kmp_service_get(kmp_service_t *service)
00526 {
00527     ns_list_foreach(pae_auth_t, entry, &pae_auth_list) {
00528         if (entry->kmp_service == service) {
00529             return entry;
00530         }
00531     }
00532 
00533     return NULL;
00534 }
00535 
00536 static int8_t ws_pae_auth_event_send(kmp_service_t *service, void *data)
00537 {
00538     pae_auth_t *pae_auth = ws_pae_auth_by_kmp_service_get(service);
00539     if (!pae_auth) {
00540         return -1;
00541     }
00542 
00543     arm_event_s event = {
00544         .receiver = tasklet_id,
00545         .sender = 0,
00546         .event_id = pae_auth->interface_ptr->id,
00547         .data_ptr = data,
00548         .event_type = PAE_TASKLET_EVENT,
00549         .priority = ARM_LIB_LOW_PRIORITY_EVENT,
00550     };
00551 
00552     if (eventOS_event_send(&event) != 0) {
00553         return -1;
00554     }
00555 
00556     return 0;
00557 }
00558 
00559 static void ws_pae_auth_tasklet_handler(arm_event_s *event)
00560 {
00561     if (event->event_type == PAE_TASKLET_INIT) {
00562 
00563     } else if (event->event_type == PAE_TASKLET_EVENT) {
00564         pae_auth_t *pae_auth = NULL;
00565 
00566         ns_list_foreach(pae_auth_t, entry, &pae_auth_list) {
00567             if (entry->interface_ptr->id == event->event_id) {
00568                 pae_auth = entry;
00569                 break;
00570             }
00571         }
00572 
00573         if (pae_auth) {
00574             kmp_service_event_if_event(pae_auth->kmp_service, event->data_ptr);
00575         }
00576     }
00577 }
00578 
00579 void ws_pae_auth_fast_timer(uint16_t ticks)
00580 {
00581     ns_list_foreach(pae_auth_t, pae_auth, &pae_auth_list) {
00582         if (!ws_pae_auth_timer_running(pae_auth)) {
00583             continue;
00584         }
00585 
00586         // Updates KMP timers
00587         bool running = ws_pae_lib_supp_list_timer_update(&pae_auth->active_supp_list, &pae_auth->inactive_supp_list, ticks, kmp_service_timer_if_timeout);
00588         if (!running) {
00589             ws_pae_auth_timer_stop(pae_auth);
00590         }
00591     }
00592 }
00593 
00594 void ws_pae_auth_slow_timer(uint16_t seconds)
00595 {
00596     ns_list_foreach(pae_auth_t, pae_auth, &pae_auth_list) {
00597 
00598         // Gets index of currently active GTK
00599         int8_t active_index = sec_prot_keys_gtk_status_active_get(pae_auth->gtks);
00600 
00601         for (uint8_t i = 0; i < GTK_NUM; i++) {
00602             if (!sec_prot_keys_gtk_is_set(pae_auth->gtks, i)) {
00603                 continue;
00604             }
00605             uint32_t timer_seconds = sec_prot_keys_gtk_lifetime_decrement(pae_auth->gtks, i, seconds);
00606             if (active_index == i) {
00607                 if (!pae_auth->gtk_new_inst_req_exp) {
00608                     pae_auth->gtk_new_inst_req_exp = ws_pae_timers_gtk_new_install_required(pae_auth->timer_settings, timer_seconds);
00609                     if (pae_auth->gtk_new_inst_req_exp) {
00610                         int8_t second_index = sec_prot_keys_gtk_install_order_second_index_get(pae_auth->gtks);
00611                         if (second_index < 0) {
00612                             tr_info("GTK new install required active index: %i, time: %"PRIu32", system time: %"PRIu32"", active_index, timer_seconds, protocol_core_monotonic_time / 10);
00613                             ws_pae_auth_gtk_key_insert(pae_auth);
00614                             ws_pae_auth_network_keys_from_gtks_set(pae_auth);
00615                         } else {
00616                             tr_info("GTK new install already done; second index: %i, time: %"PRIu32", system time: %"PRIu32"", second_index, timer_seconds, protocol_core_monotonic_time / 10);
00617                         }
00618                     }
00619                 }
00620 
00621                 if (!pae_auth->gtk_new_act_time_exp) {
00622                     pae_auth->gtk_new_act_time_exp =  ws_pae_timers_gtk_new_activation_time(pae_auth->timer_settings, timer_seconds);
00623                     if (pae_auth->gtk_new_act_time_exp) {
00624                         int8_t new_active_index = ws_pae_auth_new_gtk_activate(pae_auth);
00625                         tr_info("GTK new activation time active index: %i, time: %"PRIu32", new index: %i, system time: %"PRIu32"", active_index, timer_seconds, new_active_index, protocol_core_monotonic_time / 10);
00626                         if (new_active_index >= 0) {
00627                             ws_pae_auth_network_key_index_set(pae_auth, new_active_index);
00628                         }
00629                         pae_auth->gtk_new_inst_req_exp = false;
00630                         pae_auth->gtk_new_act_time_exp = false;
00631                     }
00632                 }
00633             }
00634 
00635             if (timer_seconds == 0) {
00636                 tr_info("GTK expired index: %i, system time: %"PRIu32"", i, protocol_core_monotonic_time / 10);
00637                 ws_pae_auth_gtk_clear(pae_auth, i);
00638                 ws_pae_auth_network_keys_from_gtks_set(pae_auth);
00639             }
00640         }
00641 
00642         pae_auth->slow_timer_seconds += seconds;
00643         if (pae_auth->slow_timer_seconds > 60) {
00644             ws_pae_lib_supp_list_slow_timer_update(&pae_auth->active_supp_list, pae_auth->timer_settings, pae_auth->slow_timer_seconds);
00645             ws_pae_lib_supp_list_slow_timer_update(&pae_auth->inactive_supp_list, pae_auth->timer_settings, pae_auth->slow_timer_seconds);
00646             pae_auth->slow_timer_seconds = 0;
00647         }
00648     }
00649 }
00650 
00651 static void ws_pae_auth_gtk_key_insert(pae_auth_t *pae_auth)
00652 {
00653     // Gets index to install the key
00654     uint8_t install_index = sec_prot_keys_gtk_install_index_get(pae_auth->gtks);
00655 
00656     // Key to install
00657     uint8_t gtk_value[GTK_LEN];
00658 
00659     // Checks if next GTK values are set and gets first GTK to install
00660     int8_t next_gtk_index = sec_prot_keys_gtk_install_order_first_index_get(pae_auth->next_gtks);
00661     if (next_gtk_index >= 0) {
00662         // Gets GTK value
00663         uint8_t *gtk = sec_prot_keys_gtk_get(pae_auth->next_gtks, next_gtk_index);
00664         memcpy(gtk_value, gtk, GTK_LEN);
00665         // Sets same key back to next GTKs but as the last key to be installed
00666         sec_prot_keys_gtk_clear(pae_auth->next_gtks, next_gtk_index);
00667         sec_prot_keys_gtk_set(pae_auth->next_gtks, next_gtk_index, gtk_value, 0);
00668     } else {
00669         randLIB_get_n_bytes_random(gtk_value, GTK_LEN);
00670     }
00671 
00672     // Gets latest installed key lifetime and adds GTK expire offset to it
00673     uint32_t lifetime = pae_auth->timer_settings->gtk_expire_offset;
00674     int8_t last_index = sec_prot_keys_gtk_install_order_last_index_get(pae_auth->gtks);
00675     if (last_index >= 0) {
00676         lifetime += sec_prot_keys_gtk_lifetime_get(pae_auth->gtks, last_index);
00677     }
00678 
00679     // Installs the new key
00680     sec_prot_keys_gtk_clear(pae_auth->gtks, install_index);
00681     sec_prot_keys_gtk_set(pae_auth->gtks, install_index, gtk_value, lifetime);
00682 
00683     // Authenticator keys are always fresh
00684     sec_prot_keys_gtk_status_all_fresh_set(pae_auth->gtks);
00685 
00686     tr_info("GTK install new index: %i, lifetime: %"PRIu32" system time: %"PRIu32"", install_index, lifetime, protocol_core_monotonic_time / 10);
00687 }
00688 
00689 static int8_t ws_pae_auth_new_gtk_activate(pae_auth_t *pae_auth)
00690 {
00691     int8_t new_active_index = sec_prot_keys_gtk_install_order_second_index_get(pae_auth->gtks);
00692     if (new_active_index >= 0) {
00693         ws_pae_auth_active_gtk_set(pae_auth, new_active_index);
00694     }
00695 
00696     return new_active_index;
00697 }
00698 
00699 static int8_t ws_pae_auth_timer_if_start(kmp_service_t *service, kmp_api_t *kmp)
00700 {
00701     pae_auth_t *pae_auth = ws_pae_auth_by_kmp_service_get(service);
00702     if (!pae_auth) {
00703         return -1;
00704     }
00705 
00706     if (ws_pae_auth_timer_start(pae_auth) < 0) {
00707         return -1;
00708     }
00709 
00710     supp_entry_t *supp_entry = kmp_api_data_get(kmp);
00711     if (!supp_entry) {
00712         return -1;
00713     }
00714 
00715     kmp_entry_t *entry = ws_pae_lib_kmp_list_entry_get(&supp_entry->kmp_list, kmp);
00716     if (!entry) {
00717         return -1;
00718     }
00719 
00720     ws_pae_lib_supp_list_to_active(&pae_auth->active_supp_list, &pae_auth->inactive_supp_list, supp_entry);
00721 
00722     ws_pae_lib_kmp_timer_start(&supp_entry->kmp_list, entry);
00723     return 0;
00724 }
00725 
00726 static int8_t ws_pae_auth_timer_if_stop(kmp_service_t *service, kmp_api_t *kmp)
00727 {
00728     (void) service;
00729 
00730     supp_entry_t *supp_entry = kmp_api_data_get(kmp);
00731 
00732     kmp_entry_t *entry = ws_pae_lib_kmp_list_entry_get(&supp_entry->kmp_list, kmp);
00733     if (!entry) {
00734         return -1;
00735     }
00736 
00737     ws_pae_lib_kmp_timer_stop(&supp_entry->kmp_list, entry);
00738     return 0;
00739 }
00740 
00741 static int8_t ws_pae_auth_timer_start(pae_auth_t *pae_auth)
00742 {
00743     pae_auth->timer_running = true;
00744     return 0;
00745 }
00746 
00747 static int8_t ws_pae_auth_timer_stop(pae_auth_t *pae_auth)
00748 {
00749     pae_auth->timer_running = false;
00750     return 0;
00751 }
00752 
00753 static bool ws_pae_auth_timer_running(pae_auth_t *pae_auth)
00754 {
00755     return pae_auth->timer_running;
00756 }
00757 
00758 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)
00759 {
00760     pae_auth_t *pae_auth = ws_pae_auth_by_kmp_service_get(service);
00761     if (!pae_auth) {
00762         return;
00763     }
00764 
00765     // Get own EUI-64
00766     link_layer_address_s mac_params;
00767     if (arm_nwk_mac_address_read(pae_auth->interface_ptr->id, &mac_params) >= 0) {
00768         kmp_address_eui_64_set(local_addr, mac_params.mac_long);
00769     }
00770 
00771     // Get supplicant address
00772     supp_entry_t *entry = kmp_api_data_get(kmp);
00773     if (entry) {
00774         kmp_address_copy(remote_addr, &entry->addr);
00775     }
00776 }
00777 
00778 static kmp_api_t *ws_pae_auth_kmp_service_api_get(kmp_service_t *service, kmp_api_t *kmp, kmp_type_e type)
00779 {
00780     (void) service;
00781 
00782     supp_entry_t *supp_entry = kmp_api_data_get(kmp);
00783     if (!supp_entry) {
00784         return NULL;
00785     }
00786 
00787     return ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, type);
00788 }
00789 
00790 static kmp_api_t *ws_pae_auth_kmp_incoming_ind(kmp_service_t *service, kmp_type_e type, const kmp_addr_t *addr)
00791 {
00792     pae_auth_t *pae_auth = ws_pae_auth_by_kmp_service_get(service);
00793     if (!pae_auth) {
00794         return NULL;
00795     }
00796 
00797     // Find supplicant from list of active supplicants
00798     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));
00799 
00800     if (!supp_entry) {
00801         // Find supplicant from list of inactive supplicants
00802         supp_entry = ws_pae_lib_supp_list_entry_eui_64_get(&pae_auth->inactive_supp_list, kmp_address_eui_64_get(addr));
00803         if (supp_entry) {
00804             // Move supplicant to active list
00805             ws_pae_lib_supp_list_to_active(&pae_auth->active_supp_list, &pae_auth->inactive_supp_list, supp_entry);
00806         }
00807     }
00808 
00809     // If does not exists add it to list
00810     if (!supp_entry) {
00811         // Checks if maximum number of supplicants is reached and purge supplicant list (starting from oldest one)
00812         ws_pae_lib_supp_list_purge(&pae_auth->active_supp_list, &pae_auth->inactive_supp_list, pae_auth->supp_max_number, 0);
00813 
00814         supp_entry = ws_pae_lib_supp_list_add(&pae_auth->active_supp_list, addr);
00815         if (!supp_entry) {
00816             return 0;
00817         }
00818         sec_prot_keys_init(&supp_entry->sec_keys, pae_auth->gtks, pae_auth->certs);
00819         // Fixes the address of the supplicant to keys
00820         sec_prot_keys_ptk_eui_64_write(&supp_entry->sec_keys, kmp_address_eui_64_get(addr));
00821     } else {
00822         // Updates relay address
00823         kmp_address_copy(&supp_entry->addr, addr);
00824     }
00825 
00826     // Increases waiting time for supplicant authentication
00827     ws_pae_lib_supp_timer_ticks_set(supp_entry, WAIT_FOR_AUTHENTICATION_TICKS);
00828 
00829     // Get KMP for supplicant
00830     kmp_api_t *kmp = ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, type);
00831     if (kmp) {
00832         return kmp;
00833     }
00834 
00835     // Create a new KMP for initial eapol-key
00836     kmp = kmp_api_create(service, type + IEEE_802_1X_INITIAL_KEY);
00837 
00838     if (!kmp) {
00839         return 0;
00840     }
00841 
00842     kmp_api_data_set(kmp, supp_entry);
00843     // Sets address to KMP
00844     kmp_api_addr_set(kmp, &supp_entry->addr);
00845 
00846     // Sets security keys to KMP
00847     kmp_api_sec_keys_set(kmp, &supp_entry->sec_keys);
00848 
00849     if (ws_pae_lib_kmp_list_add(&supp_entry->kmp_list, kmp) == NULL) {
00850         kmp_api_delete(kmp);
00851         return 0;
00852     }
00853 
00854     kmp_api_cb_register(kmp,
00855                         ws_pae_auth_kmp_api_create_confirm,
00856                         ws_pae_auth_kmp_api_create_indication,
00857                         ws_pae_auth_kmp_api_finished_indication,
00858                         ws_pae_auth_kmp_api_finished);
00859 
00860     if (kmp_api_start(kmp) < 0) {
00861         ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, kmp);
00862         return 0;
00863     }
00864 
00865     return kmp;
00866 }
00867 
00868 static void ws_pae_auth_kmp_api_create_confirm(kmp_api_t *kmp, kmp_result_e result)
00869 {
00870     (void) kmp;
00871     (void) result;
00872     // If KMP-CREATE.request has failed, authentication error, just stop for now
00873 }
00874 
00875 static void ws_pae_auth_kmp_api_create_indication(kmp_api_t *kmp, kmp_type_e type, kmp_addr_t *addr)
00876 {
00877     (void) type;
00878     (void) addr;
00879     // For now, accept every KMP-CREATE.indication
00880     kmp_api_create_response(kmp, KMP_RESULT_OK);
00881 }
00882 
00883 static void ws_pae_auth_kmp_api_finished_indication(kmp_api_t *kmp, kmp_result_e result, kmp_sec_keys_t *sec_keys)
00884 {
00885     (void) sec_keys;
00886 
00887     // For now, just ignore if not ok
00888     if (result != KMP_RESULT_OK) {
00889         return;
00890     }
00891 
00892     supp_entry_t *supp_entry = kmp_api_data_get(kmp);
00893     if (!supp_entry) {
00894         // Should not be possible
00895         return;
00896     }
00897     kmp_service_t *service = kmp_api_service_get(kmp);
00898     pae_auth_t *pae_auth = ws_pae_auth_by_kmp_service_get(service);
00899     if (!pae_auth) {
00900         // Should not be possible
00901         return;
00902     }
00903 
00904     ws_pae_auth_next_kmp_trigger(pae_auth, supp_entry);
00905 }
00906 
00907 static void ws_pae_auth_next_kmp_trigger(pae_auth_t *pae_auth, supp_entry_t *supp_entry)
00908 {
00909     // Disables KMP retry timer
00910     supp_entry->retry_ticks = 0;
00911 
00912     // Get next protocol based on what keys supplicant has
00913     kmp_type_e next_type = ws_pae_auth_next_protocol_get(supp_entry);
00914 
00915     if (next_type == KMP_TYPE_NONE) {
00916         // All done
00917         return;
00918     } else {
00919 
00920         kmp_api_t *api = ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, next_type);
00921         if (api != NULL) {
00922             /* For other types than GTK, only one ongoing negotiation at the same time,
00923                for GTK there can be previous terminating and the new one for next key index */
00924             if (next_type != IEEE_802_11_GKH) {
00925                 tr_info("KMP already ongoing; ignored, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8));
00926                 return;
00927             }
00928         }
00929     }
00930 
00931     // Increases waiting time for supplicant authentication
00932     ws_pae_lib_supp_timer_ticks_set(supp_entry, WAIT_FOR_AUTHENTICATION_TICKS);
00933 
00934     if (next_type == IEEE_802_1X_MKA) {
00935         /* For EAP-TLS, limits the number of ongoing negotiations. If limit
00936            is reached, authenticator does not initiate EAP-TLS right away.
00937            If previous EAP-TLS negotiation completes before negotiation
00938            trigger timeout, authenticator initiates EAP-TLS towards
00939            supplicant. Otherwise supplicant must re-send initial EAPOL-Key
00940            to try again using its trickle schedule */
00941         uint16_t ongoing_eap_tls_cnt = ws_pae_lib_supp_list_kmp_count(&pae_auth->active_supp_list, IEEE_802_1X_MKA);
00942         if (ongoing_eap_tls_cnt >= MAX_SIMULTANEOUS_EAP_TLS_NEGOTIATIONS) {
00943             supp_entry->retry_ticks = EAP_TLS_NEGOTIATION_TRIGGER_TIMEOUT;
00944             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));
00945             return;
00946         }
00947     }
00948 
00949     // Create new instance
00950     kmp_api_t *new_kmp = ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, next_type, supp_entry);
00951     if (!new_kmp) {
00952         return;
00953     }
00954 
00955     // For EAP-TLS create also TLS in addition to EAP-TLS
00956     if (next_type == IEEE_802_1X_MKA) {
00957         if (ws_pae_lib_kmp_list_type_get(&supp_entry->kmp_list, TLS_PROT) != NULL) {
00958             // TLS already exists, wait for it to be deleted
00959             ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, new_kmp);
00960             return;
00961         }
00962         // Create TLS instance */
00963         if (ws_pae_auth_kmp_create_and_start(pae_auth->kmp_service, TLS_PROT, supp_entry) == NULL) {
00964             ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, new_kmp);
00965             return;
00966         }
00967     }
00968 
00969     kmp_api_create_request(new_kmp, next_type, &supp_entry->addr, &supp_entry->sec_keys);
00970 }
00971 
00972 static kmp_type_e ws_pae_auth_next_protocol_get(supp_entry_t *supp_entry)
00973 {
00974     kmp_type_e next_type = KMP_TYPE_NONE;
00975     sec_prot_keys_t *sec_keys = &supp_entry->sec_keys;
00976 
00977     // Supplicant has indicated that PMK is not valid
00978     if (sec_keys->pmk_mismatch) {
00979         sec_keys->ptk_mismatch = true;
00980         // start EAP-TLS towards supplicant
00981         next_type = IEEE_802_1X_MKA;
00982         tr_info("PAE start EAP-TLS, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8));
00983     } else if (sec_keys->ptk_mismatch) {
00984         // start 4WH towards supplicant
00985         next_type = IEEE_802_11_4WH;
00986         tr_info("PAE start 4WH, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8));
00987     }
00988 
00989     int8_t gtk_index = -1;
00990     if (next_type != IEEE_802_1X_MKA) {
00991         // Checks if GTK needs to be inserted
00992         gtk_index = sec_prot_keys_gtk_insert_index_from_gtkl_get(sec_keys);
00993 
00994         // For 4WH insert always a key, in case no other then active
00995         if (next_type == IEEE_802_11_4WH && gtk_index < 0) {
00996             gtk_index = sec_prot_keys_gtk_status_active_get(sec_keys->gtks);
00997         }
00998     }
00999 
01000     if (gtk_index >= 0) {
01001         if (next_type == KMP_TYPE_NONE && gtk_index >= 0) {
01002             // Update just GTK
01003             next_type = IEEE_802_11_GKH;
01004             tr_info("PAE start GKH, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8));
01005         }
01006 
01007         tr_info("PAE update GTK index: %i, eui-64: %s", gtk_index, trace_array(supp_entry->addr.eui_64, 8));
01008     }
01009 
01010     if (next_type == KMP_TYPE_NONE) {
01011         tr_info("PAE authenticated, eui-64: %s", trace_array(supp_entry->addr.eui_64, 8));
01012     }
01013 
01014     return next_type;
01015 }
01016 
01017 
01018 static kmp_api_t *ws_pae_auth_kmp_create_and_start(kmp_service_t *service, kmp_type_e type, supp_entry_t *supp_entry)
01019 {
01020     // Create KMP instance for new authentication
01021     kmp_api_t *kmp = kmp_api_create(service, type);
01022 
01023     if (!kmp) {
01024         return NULL;
01025     }
01026 
01027     if (ws_pae_lib_kmp_list_add(&supp_entry->kmp_list, kmp) == NULL) {
01028         kmp_api_delete(kmp);
01029         return NULL;
01030     }
01031 
01032     kmp_api_cb_register(kmp,
01033                         ws_pae_auth_kmp_api_create_confirm,
01034                         ws_pae_auth_kmp_api_create_indication,
01035                         ws_pae_auth_kmp_api_finished_indication,
01036                         ws_pae_auth_kmp_api_finished);
01037 
01038     kmp_api_data_set(kmp, supp_entry);
01039 
01040     if (kmp_api_start(kmp) < 0) {
01041         ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, kmp);
01042         return NULL;
01043     }
01044 
01045     return kmp;
01046 }
01047 
01048 static void ws_pae_auth_kmp_api_finished(kmp_api_t *kmp)
01049 {
01050     supp_entry_t *supp_entry = kmp_api_data_get(kmp);
01051     if (!supp_entry) {
01052         // Should not be possible
01053         return;
01054     }
01055 
01056     pae_auth_t *pae_auth = NULL;
01057     supp_entry_t *retry_supp = NULL;
01058     // When EAP-TLS completes check if there are other supplicants that have requested it lately
01059     if (kmp_api_type_get(kmp) == IEEE_802_1X_MKA) {
01060         kmp_service_t *service = kmp_api_service_get(kmp);
01061         pae_auth = ws_pae_auth_by_kmp_service_get(service);
01062         if (pae_auth) {
01063             retry_supp = ws_pae_lib_supp_list_entry_retry_timer_get(&pae_auth->active_supp_list);
01064         }
01065     }
01066 
01067     // Delete KMP
01068     ws_pae_lib_kmp_list_delete(&supp_entry->kmp_list, kmp);
01069 
01070     if (retry_supp) {
01071         tr_info("PAE next KMP trigger, eui-64: %s", trace_array(retry_supp->addr.eui_64, 8));
01072         ws_pae_auth_next_kmp_trigger(pae_auth, retry_supp);
01073     }
01074 
01075 }
01076 
01077 #endif /* HAVE_PAE_AUTH */
01078 #endif /* HAVE_WS */
01079