15b9c547cSRui Paulo /* 25b9c547cSRui Paulo * IEEE 802.1X-2010 Controlled Port of PAE state machine - CP state machine 35b9c547cSRui Paulo * Copyright (c) 2013-2014, Qualcomm Atheros, Inc. 45b9c547cSRui Paulo * 55b9c547cSRui Paulo * This software may be distributed under the terms of the BSD license. 65b9c547cSRui Paulo * See README for more details. 75b9c547cSRui Paulo */ 85b9c547cSRui Paulo 95b9c547cSRui Paulo #include "utils/includes.h" 105b9c547cSRui Paulo 115b9c547cSRui Paulo #include "utils/common.h" 125b9c547cSRui Paulo #include "utils/eloop.h" 135b9c547cSRui Paulo #include "common/defs.h" 145b9c547cSRui Paulo #include "common/ieee802_1x_defs.h" 155b9c547cSRui Paulo #include "utils/state_machine.h" 165b9c547cSRui Paulo #include "ieee802_1x_kay.h" 175b9c547cSRui Paulo #include "ieee802_1x_secy_ops.h" 185b9c547cSRui Paulo #include "pae/ieee802_1x_cp.h" 195b9c547cSRui Paulo 205b9c547cSRui Paulo #define STATE_MACHINE_DATA struct ieee802_1x_cp_sm 215b9c547cSRui Paulo #define STATE_MACHINE_DEBUG_PREFIX "CP" 225b9c547cSRui Paulo 23780fb4a2SCy Schubert static u64 default_cs_id = CS_ID_GCM_AES_128; 245b9c547cSRui Paulo 255b9c547cSRui Paulo /* The variable defined in clause 12 in IEEE Std 802.1X-2010 */ 265b9c547cSRui Paulo enum connect_type { PENDING, UNAUTHENTICATED, AUTHENTICATED, SECURE }; 275b9c547cSRui Paulo 285b9c547cSRui Paulo struct ieee802_1x_cp_sm { 295b9c547cSRui Paulo enum cp_states { 305b9c547cSRui Paulo CP_BEGIN, CP_INIT, CP_CHANGE, CP_ALLOWED, CP_AUTHENTICATED, 315b9c547cSRui Paulo CP_SECURED, CP_RECEIVE, CP_RECEIVING, CP_READY, CP_TRANSMIT, 325b9c547cSRui Paulo CP_TRANSMITTING, CP_ABANDON, CP_RETIRE 335b9c547cSRui Paulo } CP_state; 345b9c547cSRui Paulo Boolean changed; 355b9c547cSRui Paulo 365b9c547cSRui Paulo /* CP -> Client */ 375b9c547cSRui Paulo Boolean port_valid; 385b9c547cSRui Paulo 395b9c547cSRui Paulo /* Logon -> CP */ 405b9c547cSRui Paulo enum connect_type connect; 415b9c547cSRui Paulo u8 *authorization_data; 425b9c547cSRui Paulo 435b9c547cSRui Paulo /* KaY -> CP */ 445b9c547cSRui Paulo Boolean chgd_server; /* clear by CP */ 455b9c547cSRui Paulo Boolean elected_self; 465b9c547cSRui Paulo u8 *authorization_data1; 475b9c547cSRui Paulo enum confidentiality_offset cipher_offset; 48780fb4a2SCy Schubert u64 cipher_suite; 495b9c547cSRui Paulo Boolean new_sak; /* clear by CP */ 505b9c547cSRui Paulo struct ieee802_1x_mka_ki distributed_ki; 515b9c547cSRui Paulo u8 distributed_an; 525b9c547cSRui Paulo Boolean using_receive_sas; 535b9c547cSRui Paulo Boolean all_receiving; 545b9c547cSRui Paulo Boolean server_transmitting; 555b9c547cSRui Paulo Boolean using_transmit_sa; 565b9c547cSRui Paulo 575b9c547cSRui Paulo /* CP -> KaY */ 585b9c547cSRui Paulo struct ieee802_1x_mka_ki *lki; 595b9c547cSRui Paulo u8 lan; 605b9c547cSRui Paulo Boolean ltx; 615b9c547cSRui Paulo Boolean lrx; 625b9c547cSRui Paulo struct ieee802_1x_mka_ki *oki; 635b9c547cSRui Paulo u8 oan; 645b9c547cSRui Paulo Boolean otx; 655b9c547cSRui Paulo Boolean orx; 665b9c547cSRui Paulo 675b9c547cSRui Paulo /* CP -> SecY */ 685b9c547cSRui Paulo Boolean protect_frames; 695b9c547cSRui Paulo enum validate_frames validate_frames; 705b9c547cSRui Paulo 715b9c547cSRui Paulo Boolean replay_protect; 725b9c547cSRui Paulo u32 replay_window; 735b9c547cSRui Paulo 74780fb4a2SCy Schubert u64 current_cipher_suite; 755b9c547cSRui Paulo enum confidentiality_offset confidentiality_offset; 765b9c547cSRui Paulo Boolean controlled_port_enabled; 775b9c547cSRui Paulo 785b9c547cSRui Paulo /* SecY -> CP */ 795b9c547cSRui Paulo Boolean port_enabled; /* SecY->CP */ 805b9c547cSRui Paulo 815b9c547cSRui Paulo /* private */ 825b9c547cSRui Paulo u32 transmit_when; 835b9c547cSRui Paulo u32 transmit_delay; 845b9c547cSRui Paulo u32 retire_when; 855b9c547cSRui Paulo u32 retire_delay; 865b9c547cSRui Paulo 875b9c547cSRui Paulo /* not defined IEEE Std 802.1X-2010 */ 885b9c547cSRui Paulo struct ieee802_1x_kay *kay; 895b9c547cSRui Paulo }; 905b9c547cSRui Paulo 915b9c547cSRui Paulo static void ieee802_1x_cp_retire_when_timeout(void *eloop_ctx, 925b9c547cSRui Paulo void *timeout_ctx); 935b9c547cSRui Paulo static void ieee802_1x_cp_transmit_when_timeout(void *eloop_ctx, 945b9c547cSRui Paulo void *timeout_ctx); 955b9c547cSRui Paulo 965b9c547cSRui Paulo 975b9c547cSRui Paulo static int changed_cipher(struct ieee802_1x_cp_sm *sm) 985b9c547cSRui Paulo { 995b9c547cSRui Paulo return sm->confidentiality_offset != sm->cipher_offset || 100780fb4a2SCy Schubert sm->current_cipher_suite != sm->cipher_suite; 1015b9c547cSRui Paulo } 1025b9c547cSRui Paulo 1035b9c547cSRui Paulo 1045b9c547cSRui Paulo static int changed_connect(struct ieee802_1x_cp_sm *sm) 1055b9c547cSRui Paulo { 1065b9c547cSRui Paulo return sm->connect != SECURE || sm->chgd_server || changed_cipher(sm); 1075b9c547cSRui Paulo } 1085b9c547cSRui Paulo 1095b9c547cSRui Paulo 1105b9c547cSRui Paulo SM_STATE(CP, INIT) 1115b9c547cSRui Paulo { 1125b9c547cSRui Paulo SM_ENTRY(CP, INIT); 1135b9c547cSRui Paulo 1145b9c547cSRui Paulo sm->controlled_port_enabled = FALSE; 1155b9c547cSRui Paulo secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled); 1165b9c547cSRui Paulo 1175b9c547cSRui Paulo sm->port_valid = FALSE; 1185b9c547cSRui Paulo 1195b9c547cSRui Paulo os_free(sm->lki); 1205b9c547cSRui Paulo sm->lki = NULL; 1215b9c547cSRui Paulo sm->ltx = FALSE; 1225b9c547cSRui Paulo sm->lrx = FALSE; 1235b9c547cSRui Paulo 1245b9c547cSRui Paulo os_free(sm->oki); 1255b9c547cSRui Paulo sm->oki = NULL; 1265b9c547cSRui Paulo sm->otx = FALSE; 1275b9c547cSRui Paulo sm->orx = FALSE; 1285b9c547cSRui Paulo 1295b9c547cSRui Paulo sm->port_enabled = TRUE; 1305b9c547cSRui Paulo sm->chgd_server = FALSE; 1315b9c547cSRui Paulo } 1325b9c547cSRui Paulo 1335b9c547cSRui Paulo 1345b9c547cSRui Paulo SM_STATE(CP, CHANGE) 1355b9c547cSRui Paulo { 1365b9c547cSRui Paulo SM_ENTRY(CP, CHANGE); 1375b9c547cSRui Paulo 1385b9c547cSRui Paulo sm->port_valid = FALSE; 1395b9c547cSRui Paulo sm->controlled_port_enabled = FALSE; 1405b9c547cSRui Paulo secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled); 1415b9c547cSRui Paulo 1425b9c547cSRui Paulo if (sm->lki) 1435b9c547cSRui Paulo ieee802_1x_kay_delete_sas(sm->kay, sm->lki); 1445b9c547cSRui Paulo if (sm->oki) 1455b9c547cSRui Paulo ieee802_1x_kay_delete_sas(sm->kay, sm->oki); 1465b9c547cSRui Paulo } 1475b9c547cSRui Paulo 1485b9c547cSRui Paulo 1495b9c547cSRui Paulo SM_STATE(CP, ALLOWED) 1505b9c547cSRui Paulo { 1515b9c547cSRui Paulo SM_ENTRY(CP, ALLOWED); 1525b9c547cSRui Paulo 1535b9c547cSRui Paulo sm->protect_frames = FALSE; 1545b9c547cSRui Paulo sm->replay_protect = FALSE; 1555b9c547cSRui Paulo sm->validate_frames = Checked; 1565b9c547cSRui Paulo 1575b9c547cSRui Paulo sm->port_valid = FALSE; 1585b9c547cSRui Paulo sm->controlled_port_enabled = TRUE; 1595b9c547cSRui Paulo 1605b9c547cSRui Paulo secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled); 1615b9c547cSRui Paulo secy_cp_control_protect_frames(sm->kay, sm->protect_frames); 162*85732ac8SCy Schubert secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt); 1635b9c547cSRui Paulo secy_cp_control_validate_frames(sm->kay, sm->validate_frames); 1645b9c547cSRui Paulo secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window); 1655b9c547cSRui Paulo } 1665b9c547cSRui Paulo 1675b9c547cSRui Paulo 1685b9c547cSRui Paulo SM_STATE(CP, AUTHENTICATED) 1695b9c547cSRui Paulo { 1705b9c547cSRui Paulo SM_ENTRY(CP, AUTHENTICATED); 1715b9c547cSRui Paulo 1725b9c547cSRui Paulo sm->protect_frames = FALSE; 1735b9c547cSRui Paulo sm->replay_protect = FALSE; 1745b9c547cSRui Paulo sm->validate_frames = Checked; 1755b9c547cSRui Paulo 1765b9c547cSRui Paulo sm->port_valid = FALSE; 1775b9c547cSRui Paulo sm->controlled_port_enabled = TRUE; 1785b9c547cSRui Paulo 1795b9c547cSRui Paulo secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled); 1805b9c547cSRui Paulo secy_cp_control_protect_frames(sm->kay, sm->protect_frames); 181*85732ac8SCy Schubert secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt); 1825b9c547cSRui Paulo secy_cp_control_validate_frames(sm->kay, sm->validate_frames); 1835b9c547cSRui Paulo secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window); 1845b9c547cSRui Paulo } 1855b9c547cSRui Paulo 1865b9c547cSRui Paulo 1875b9c547cSRui Paulo SM_STATE(CP, SECURED) 1885b9c547cSRui Paulo { 1895b9c547cSRui Paulo SM_ENTRY(CP, SECURED); 1905b9c547cSRui Paulo 1915b9c547cSRui Paulo sm->chgd_server = FALSE; 1925b9c547cSRui Paulo 193780fb4a2SCy Schubert sm->protect_frames = sm->kay->macsec_protect; 194780fb4a2SCy Schubert sm->replay_protect = sm->kay->macsec_replay_protect; 195780fb4a2SCy Schubert sm->validate_frames = sm->kay->macsec_validate; 1965b9c547cSRui Paulo 197780fb4a2SCy Schubert /* NOTE: now no other than default cipher suite (AES-GCM-128) */ 198780fb4a2SCy Schubert sm->current_cipher_suite = sm->cipher_suite; 199780fb4a2SCy Schubert secy_cp_control_current_cipher_suite(sm->kay, sm->current_cipher_suite); 2005b9c547cSRui Paulo 2015b9c547cSRui Paulo sm->confidentiality_offset = sm->cipher_offset; 2025b9c547cSRui Paulo 2035b9c547cSRui Paulo sm->port_valid = TRUE; 2045b9c547cSRui Paulo 2055b9c547cSRui Paulo secy_cp_control_confidentiality_offset(sm->kay, 2065b9c547cSRui Paulo sm->confidentiality_offset); 2075b9c547cSRui Paulo secy_cp_control_protect_frames(sm->kay, sm->protect_frames); 208*85732ac8SCy Schubert secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt); 2095b9c547cSRui Paulo secy_cp_control_validate_frames(sm->kay, sm->validate_frames); 2105b9c547cSRui Paulo secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window); 2115b9c547cSRui Paulo } 2125b9c547cSRui Paulo 2135b9c547cSRui Paulo 2145b9c547cSRui Paulo SM_STATE(CP, RECEIVE) 2155b9c547cSRui Paulo { 2165b9c547cSRui Paulo SM_ENTRY(CP, RECEIVE); 2175b9c547cSRui Paulo /* RECEIVE state machine not keep with Figure 12-2 in 2185b9c547cSRui Paulo * IEEE Std 802.1X-2010 */ 2195b9c547cSRui Paulo sm->oki = sm->lki; 2205b9c547cSRui Paulo sm->oan = sm->lan; 2215b9c547cSRui Paulo sm->otx = sm->ltx; 2225b9c547cSRui Paulo sm->orx = sm->lrx; 2235b9c547cSRui Paulo ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan, 2245b9c547cSRui Paulo sm->otx, sm->orx); 2255b9c547cSRui Paulo 2265b9c547cSRui Paulo sm->lki = os_malloc(sizeof(*sm->lki)); 2275b9c547cSRui Paulo if (!sm->lki) { 2285b9c547cSRui Paulo wpa_printf(MSG_ERROR, "CP-%s: Out of memory", __func__); 2295b9c547cSRui Paulo return; 2305b9c547cSRui Paulo } 2315b9c547cSRui Paulo os_memcpy(sm->lki, &sm->distributed_ki, sizeof(*sm->lki)); 2325b9c547cSRui Paulo sm->lan = sm->distributed_an; 2335b9c547cSRui Paulo sm->ltx = FALSE; 2345b9c547cSRui Paulo sm->lrx = FALSE; 2355b9c547cSRui Paulo ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan, 2365b9c547cSRui Paulo sm->ltx, sm->lrx); 2375b9c547cSRui Paulo ieee802_1x_kay_create_sas(sm->kay, sm->lki); 2385b9c547cSRui Paulo ieee802_1x_kay_enable_rx_sas(sm->kay, sm->lki); 2395b9c547cSRui Paulo sm->new_sak = FALSE; 2405b9c547cSRui Paulo sm->all_receiving = FALSE; 2415b9c547cSRui Paulo } 2425b9c547cSRui Paulo 2435b9c547cSRui Paulo 2445b9c547cSRui Paulo SM_STATE(CP, RECEIVING) 2455b9c547cSRui Paulo { 2465b9c547cSRui Paulo SM_ENTRY(CP, RECEIVING); 2475b9c547cSRui Paulo 2485b9c547cSRui Paulo sm->lrx = TRUE; 2495b9c547cSRui Paulo ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan, 2505b9c547cSRui Paulo sm->ltx, sm->lrx); 2515b9c547cSRui Paulo sm->transmit_when = sm->transmit_delay; 2525b9c547cSRui Paulo eloop_cancel_timeout(ieee802_1x_cp_transmit_when_timeout, sm, NULL); 2535b9c547cSRui Paulo eloop_register_timeout(sm->transmit_when / 1000, 0, 2545b9c547cSRui Paulo ieee802_1x_cp_transmit_when_timeout, sm, NULL); 2555b9c547cSRui Paulo /* the electedSelf have been set before CP entering to RECEIVING 2565b9c547cSRui Paulo * but the CP will transmit from RECEIVING to READY under 2575b9c547cSRui Paulo * the !electedSelf when KaY is not key server */ 2585b9c547cSRui Paulo ieee802_1x_cp_sm_step(sm); 2595b9c547cSRui Paulo sm->using_receive_sas = FALSE; 2605b9c547cSRui Paulo sm->server_transmitting = FALSE; 2615b9c547cSRui Paulo } 2625b9c547cSRui Paulo 2635b9c547cSRui Paulo 2645b9c547cSRui Paulo SM_STATE(CP, READY) 2655b9c547cSRui Paulo { 2665b9c547cSRui Paulo SM_ENTRY(CP, READY); 2675b9c547cSRui Paulo 2685b9c547cSRui Paulo ieee802_1x_kay_enable_new_info(sm->kay); 2695b9c547cSRui Paulo } 2705b9c547cSRui Paulo 2715b9c547cSRui Paulo 2725b9c547cSRui Paulo SM_STATE(CP, TRANSMIT) 2735b9c547cSRui Paulo { 2745b9c547cSRui Paulo SM_ENTRY(CP, TRANSMIT); 2755b9c547cSRui Paulo 2765b9c547cSRui Paulo sm->controlled_port_enabled = TRUE; 2775b9c547cSRui Paulo secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled); 2785b9c547cSRui Paulo sm->ltx = TRUE; 2795b9c547cSRui Paulo ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan, 2805b9c547cSRui Paulo sm->ltx, sm->lrx); 2815b9c547cSRui Paulo ieee802_1x_kay_enable_tx_sas(sm->kay, sm->lki); 2825b9c547cSRui Paulo sm->all_receiving = FALSE; 2835b9c547cSRui Paulo sm->server_transmitting = FALSE; 2845b9c547cSRui Paulo } 2855b9c547cSRui Paulo 2865b9c547cSRui Paulo 2875b9c547cSRui Paulo SM_STATE(CP, TRANSMITTING) 2885b9c547cSRui Paulo { 2895b9c547cSRui Paulo SM_ENTRY(CP, TRANSMITTING); 2905b9c547cSRui Paulo sm->retire_when = sm->orx ? sm->retire_delay : 0; 2915b9c547cSRui Paulo sm->otx = FALSE; 2925b9c547cSRui Paulo ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan, 2935b9c547cSRui Paulo sm->otx, sm->orx); 2945b9c547cSRui Paulo ieee802_1x_kay_enable_new_info(sm->kay); 2955b9c547cSRui Paulo eloop_cancel_timeout(ieee802_1x_cp_retire_when_timeout, sm, NULL); 2965b9c547cSRui Paulo eloop_register_timeout(sm->retire_when / 1000, 0, 2975b9c547cSRui Paulo ieee802_1x_cp_retire_when_timeout, sm, NULL); 2985b9c547cSRui Paulo sm->using_transmit_sa = FALSE; 2995b9c547cSRui Paulo } 3005b9c547cSRui Paulo 3015b9c547cSRui Paulo 3025b9c547cSRui Paulo SM_STATE(CP, ABANDON) 3035b9c547cSRui Paulo { 3045b9c547cSRui Paulo SM_ENTRY(CP, ABANDON); 3055b9c547cSRui Paulo sm->lrx = FALSE; 3065b9c547cSRui Paulo ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan, 3075b9c547cSRui Paulo sm->ltx, sm->lrx); 3085b9c547cSRui Paulo ieee802_1x_kay_delete_sas(sm->kay, sm->lki); 3095b9c547cSRui Paulo 3105b9c547cSRui Paulo os_free(sm->lki); 3115b9c547cSRui Paulo sm->lki = NULL; 3125b9c547cSRui Paulo ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan, 3135b9c547cSRui Paulo sm->ltx, sm->lrx); 3145b9c547cSRui Paulo sm->new_sak = FALSE; 3155b9c547cSRui Paulo } 3165b9c547cSRui Paulo 3175b9c547cSRui Paulo 3185b9c547cSRui Paulo SM_STATE(CP, RETIRE) 3195b9c547cSRui Paulo { 3205b9c547cSRui Paulo SM_ENTRY(CP, RETIRE); 3215b9c547cSRui Paulo /* RETIRE state machine not keep with Figure 12-2 in 3225b9c547cSRui Paulo * IEEE Std 802.1X-2010 */ 3235b9c547cSRui Paulo os_free(sm->oki); 3245b9c547cSRui Paulo sm->oki = NULL; 3255b9c547cSRui Paulo sm->orx = FALSE; 3265b9c547cSRui Paulo sm->otx = FALSE; 3275b9c547cSRui Paulo ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan, 3285b9c547cSRui Paulo sm->otx, sm->orx); 3295b9c547cSRui Paulo } 3305b9c547cSRui Paulo 3315b9c547cSRui Paulo 3325b9c547cSRui Paulo /** 3335b9c547cSRui Paulo * CP state machine handler entry 3345b9c547cSRui Paulo */ 3355b9c547cSRui Paulo SM_STEP(CP) 3365b9c547cSRui Paulo { 3375b9c547cSRui Paulo if (!sm->port_enabled) 3385b9c547cSRui Paulo SM_ENTER(CP, INIT); 3395b9c547cSRui Paulo 3405b9c547cSRui Paulo switch (sm->CP_state) { 3415b9c547cSRui Paulo case CP_BEGIN: 3425b9c547cSRui Paulo SM_ENTER(CP, INIT); 3435b9c547cSRui Paulo break; 3445b9c547cSRui Paulo 3455b9c547cSRui Paulo case CP_INIT: 3465b9c547cSRui Paulo SM_ENTER(CP, CHANGE); 3475b9c547cSRui Paulo break; 3485b9c547cSRui Paulo 3495b9c547cSRui Paulo case CP_CHANGE: 3505b9c547cSRui Paulo if (sm->connect == UNAUTHENTICATED) 3515b9c547cSRui Paulo SM_ENTER(CP, ALLOWED); 3525b9c547cSRui Paulo else if (sm->connect == AUTHENTICATED) 3535b9c547cSRui Paulo SM_ENTER(CP, AUTHENTICATED); 3545b9c547cSRui Paulo else if (sm->connect == SECURE) 3555b9c547cSRui Paulo SM_ENTER(CP, SECURED); 3565b9c547cSRui Paulo break; 3575b9c547cSRui Paulo 3585b9c547cSRui Paulo case CP_ALLOWED: 3595b9c547cSRui Paulo if (sm->connect != UNAUTHENTICATED) 3605b9c547cSRui Paulo SM_ENTER(CP, CHANGE); 3615b9c547cSRui Paulo break; 3625b9c547cSRui Paulo 3635b9c547cSRui Paulo case CP_AUTHENTICATED: 3645b9c547cSRui Paulo if (sm->connect != AUTHENTICATED) 3655b9c547cSRui Paulo SM_ENTER(CP, CHANGE); 3665b9c547cSRui Paulo break; 3675b9c547cSRui Paulo 3685b9c547cSRui Paulo case CP_SECURED: 3695b9c547cSRui Paulo if (changed_connect(sm)) 3705b9c547cSRui Paulo SM_ENTER(CP, CHANGE); 3715b9c547cSRui Paulo else if (sm->new_sak) 3725b9c547cSRui Paulo SM_ENTER(CP, RECEIVE); 3735b9c547cSRui Paulo break; 3745b9c547cSRui Paulo 3755b9c547cSRui Paulo case CP_RECEIVE: 3765b9c547cSRui Paulo if (sm->using_receive_sas) 3775b9c547cSRui Paulo SM_ENTER(CP, RECEIVING); 3785b9c547cSRui Paulo break; 3795b9c547cSRui Paulo 3805b9c547cSRui Paulo case CP_RECEIVING: 3815b9c547cSRui Paulo if (sm->new_sak || changed_connect(sm)) 3825b9c547cSRui Paulo SM_ENTER(CP, ABANDON); 3835b9c547cSRui Paulo if (!sm->elected_self) 3845b9c547cSRui Paulo SM_ENTER(CP, READY); 3855b9c547cSRui Paulo if (sm->elected_self && 3865b9c547cSRui Paulo (sm->all_receiving || !sm->transmit_when)) 3875b9c547cSRui Paulo SM_ENTER(CP, TRANSMIT); 3885b9c547cSRui Paulo break; 3895b9c547cSRui Paulo 3905b9c547cSRui Paulo case CP_TRANSMIT: 3915b9c547cSRui Paulo if (sm->using_transmit_sa) 3925b9c547cSRui Paulo SM_ENTER(CP, TRANSMITTING); 3935b9c547cSRui Paulo break; 3945b9c547cSRui Paulo 3955b9c547cSRui Paulo case CP_TRANSMITTING: 3965b9c547cSRui Paulo if (!sm->retire_when || changed_connect(sm)) 3975b9c547cSRui Paulo SM_ENTER(CP, RETIRE); 3985b9c547cSRui Paulo break; 3995b9c547cSRui Paulo 4005b9c547cSRui Paulo case CP_RETIRE: 4015b9c547cSRui Paulo if (changed_connect(sm)) 4025b9c547cSRui Paulo SM_ENTER(CP, CHANGE); 4035b9c547cSRui Paulo else if (sm->new_sak) 4045b9c547cSRui Paulo SM_ENTER(CP, RECEIVE); 4055b9c547cSRui Paulo break; 4065b9c547cSRui Paulo 4075b9c547cSRui Paulo case CP_READY: 4085b9c547cSRui Paulo if (sm->new_sak || changed_connect(sm)) 4095b9c547cSRui Paulo SM_ENTER(CP, RECEIVE); 4105b9c547cSRui Paulo if (sm->server_transmitting) 4115b9c547cSRui Paulo SM_ENTER(CP, TRANSMIT); 4125b9c547cSRui Paulo break; 4135b9c547cSRui Paulo case CP_ABANDON: 4145b9c547cSRui Paulo if (changed_connect(sm)) 4155b9c547cSRui Paulo SM_ENTER(CP, RETIRE); 4165b9c547cSRui Paulo else if (sm->new_sak) 4175b9c547cSRui Paulo SM_ENTER(CP, RECEIVE); 4185b9c547cSRui Paulo break; 4195b9c547cSRui Paulo default: 4205b9c547cSRui Paulo wpa_printf(MSG_ERROR, "CP: the state machine is not defined"); 4215b9c547cSRui Paulo break; 4225b9c547cSRui Paulo } 4235b9c547cSRui Paulo } 4245b9c547cSRui Paulo 4255b9c547cSRui Paulo 4265b9c547cSRui Paulo /** 4275b9c547cSRui Paulo * ieee802_1x_cp_sm_init - 4285b9c547cSRui Paulo */ 429780fb4a2SCy Schubert struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(struct ieee802_1x_kay *kay) 4305b9c547cSRui Paulo { 4315b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm; 4325b9c547cSRui Paulo 4335b9c547cSRui Paulo sm = os_zalloc(sizeof(*sm)); 4345b9c547cSRui Paulo if (sm == NULL) { 4355b9c547cSRui Paulo wpa_printf(MSG_ERROR, "CP-%s: out of memory", __func__); 4365b9c547cSRui Paulo return NULL; 4375b9c547cSRui Paulo } 4385b9c547cSRui Paulo 4395b9c547cSRui Paulo sm->kay = kay; 4405b9c547cSRui Paulo 4415b9c547cSRui Paulo sm->port_valid = FALSE; 4425b9c547cSRui Paulo 4435b9c547cSRui Paulo sm->chgd_server = FALSE; 4445b9c547cSRui Paulo 445780fb4a2SCy Schubert sm->protect_frames = kay->macsec_protect; 446780fb4a2SCy Schubert sm->validate_frames = kay->macsec_validate; 447780fb4a2SCy Schubert sm->replay_protect = kay->macsec_replay_protect; 448780fb4a2SCy Schubert sm->replay_window = kay->macsec_replay_window; 4495b9c547cSRui Paulo 4505b9c547cSRui Paulo sm->controlled_port_enabled = FALSE; 4515b9c547cSRui Paulo 4525b9c547cSRui Paulo sm->lki = NULL; 4535b9c547cSRui Paulo sm->lrx = FALSE; 4545b9c547cSRui Paulo sm->ltx = FALSE; 4555b9c547cSRui Paulo sm->oki = NULL; 4565b9c547cSRui Paulo sm->orx = FALSE; 4575b9c547cSRui Paulo sm->otx = FALSE; 4585b9c547cSRui Paulo 459780fb4a2SCy Schubert sm->current_cipher_suite = default_cs_id; 460780fb4a2SCy Schubert sm->cipher_suite = default_cs_id; 4615b9c547cSRui Paulo sm->cipher_offset = CONFIDENTIALITY_OFFSET_0; 4625b9c547cSRui Paulo sm->confidentiality_offset = sm->cipher_offset; 4635b9c547cSRui Paulo sm->transmit_delay = MKA_LIFE_TIME; 4645b9c547cSRui Paulo sm->retire_delay = MKA_SAK_RETIRE_TIME; 4655b9c547cSRui Paulo sm->CP_state = CP_BEGIN; 4665b9c547cSRui Paulo sm->changed = FALSE; 4675b9c547cSRui Paulo sm->authorization_data = NULL; 4685b9c547cSRui Paulo 4695b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "CP: state machine created"); 4705b9c547cSRui Paulo 4715b9c547cSRui Paulo secy_cp_control_protect_frames(sm->kay, sm->protect_frames); 472*85732ac8SCy Schubert secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt); 4735b9c547cSRui Paulo secy_cp_control_validate_frames(sm->kay, sm->validate_frames); 4745b9c547cSRui Paulo secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window); 4755b9c547cSRui Paulo secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled); 4765b9c547cSRui Paulo secy_cp_control_confidentiality_offset(sm->kay, 4775b9c547cSRui Paulo sm->confidentiality_offset); 4785b9c547cSRui Paulo 4795b9c547cSRui Paulo SM_ENTER(CP, INIT); 4805b9c547cSRui Paulo SM_STEP_RUN(CP); 4815b9c547cSRui Paulo 4825b9c547cSRui Paulo return sm; 4835b9c547cSRui Paulo } 4845b9c547cSRui Paulo 4855b9c547cSRui Paulo 4865b9c547cSRui Paulo static void ieee802_1x_cp_step_run(struct ieee802_1x_cp_sm *sm) 4875b9c547cSRui Paulo { 4885b9c547cSRui Paulo enum cp_states prev_state; 4895b9c547cSRui Paulo int i; 4905b9c547cSRui Paulo 4915b9c547cSRui Paulo for (i = 0; i < 100; i++) { 4925b9c547cSRui Paulo prev_state = sm->CP_state; 4935b9c547cSRui Paulo SM_STEP_RUN(CP); 4945b9c547cSRui Paulo if (prev_state == sm->CP_state) 4955b9c547cSRui Paulo break; 4965b9c547cSRui Paulo } 4975b9c547cSRui Paulo } 4985b9c547cSRui Paulo 4995b9c547cSRui Paulo 5005b9c547cSRui Paulo static void ieee802_1x_cp_step_cb(void *eloop_ctx, void *timeout_ctx) 5015b9c547cSRui Paulo { 5025b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = eloop_ctx; 5035b9c547cSRui Paulo ieee802_1x_cp_step_run(sm); 5045b9c547cSRui Paulo } 5055b9c547cSRui Paulo 5065b9c547cSRui Paulo 5075b9c547cSRui Paulo /** 5085b9c547cSRui Paulo * ieee802_1x_cp_sm_deinit - 5095b9c547cSRui Paulo */ 5105b9c547cSRui Paulo void ieee802_1x_cp_sm_deinit(struct ieee802_1x_cp_sm *sm) 5115b9c547cSRui Paulo { 5125b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "CP: state machine removed"); 5135b9c547cSRui Paulo if (!sm) 5145b9c547cSRui Paulo return; 5155b9c547cSRui Paulo 5165b9c547cSRui Paulo eloop_cancel_timeout(ieee802_1x_cp_retire_when_timeout, sm, NULL); 5175b9c547cSRui Paulo eloop_cancel_timeout(ieee802_1x_cp_transmit_when_timeout, sm, NULL); 5185b9c547cSRui Paulo eloop_cancel_timeout(ieee802_1x_cp_step_cb, sm, NULL); 5195b9c547cSRui Paulo os_free(sm->lki); 5205b9c547cSRui Paulo os_free(sm->oki); 5215b9c547cSRui Paulo os_free(sm->authorization_data); 5225b9c547cSRui Paulo os_free(sm); 5235b9c547cSRui Paulo } 5245b9c547cSRui Paulo 5255b9c547cSRui Paulo 5265b9c547cSRui Paulo /** 5275b9c547cSRui Paulo * ieee802_1x_cp_connect_pending 5285b9c547cSRui Paulo */ 5295b9c547cSRui Paulo void ieee802_1x_cp_connect_pending(void *cp_ctx) 5305b9c547cSRui Paulo { 5315b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx; 5325b9c547cSRui Paulo 5335b9c547cSRui Paulo sm->connect = PENDING; 5345b9c547cSRui Paulo } 5355b9c547cSRui Paulo 5365b9c547cSRui Paulo 5375b9c547cSRui Paulo /** 5385b9c547cSRui Paulo * ieee802_1x_cp_connect_unauthenticated 5395b9c547cSRui Paulo */ 5405b9c547cSRui Paulo void ieee802_1x_cp_connect_unauthenticated(void *cp_ctx) 5415b9c547cSRui Paulo { 5425b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = (struct ieee802_1x_cp_sm *)cp_ctx; 5435b9c547cSRui Paulo 5445b9c547cSRui Paulo sm->connect = UNAUTHENTICATED; 5455b9c547cSRui Paulo } 5465b9c547cSRui Paulo 5475b9c547cSRui Paulo 5485b9c547cSRui Paulo /** 5495b9c547cSRui Paulo * ieee802_1x_cp_connect_authenticated 5505b9c547cSRui Paulo */ 5515b9c547cSRui Paulo void ieee802_1x_cp_connect_authenticated(void *cp_ctx) 5525b9c547cSRui Paulo { 5535b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx; 5545b9c547cSRui Paulo 5555b9c547cSRui Paulo sm->connect = AUTHENTICATED; 5565b9c547cSRui Paulo } 5575b9c547cSRui Paulo 5585b9c547cSRui Paulo 5595b9c547cSRui Paulo /** 5605b9c547cSRui Paulo * ieee802_1x_cp_connect_secure 5615b9c547cSRui Paulo */ 5625b9c547cSRui Paulo void ieee802_1x_cp_connect_secure(void *cp_ctx) 5635b9c547cSRui Paulo { 5645b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx; 5655b9c547cSRui Paulo 5665b9c547cSRui Paulo sm->connect = SECURE; 5675b9c547cSRui Paulo } 5685b9c547cSRui Paulo 5695b9c547cSRui Paulo 5705b9c547cSRui Paulo /** 5715b9c547cSRui Paulo * ieee802_1x_cp_set_chgdserver - 5725b9c547cSRui Paulo */ 5735b9c547cSRui Paulo void ieee802_1x_cp_signal_chgdserver(void *cp_ctx) 5745b9c547cSRui Paulo { 5755b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx; 5765b9c547cSRui Paulo 5775b9c547cSRui Paulo sm->chgd_server = TRUE; 5785b9c547cSRui Paulo } 5795b9c547cSRui Paulo 5805b9c547cSRui Paulo 5815b9c547cSRui Paulo /** 5825b9c547cSRui Paulo * ieee802_1x_cp_set_electedself - 5835b9c547cSRui Paulo */ 5845b9c547cSRui Paulo void ieee802_1x_cp_set_electedself(void *cp_ctx, Boolean status) 5855b9c547cSRui Paulo { 5865b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx; 5875b9c547cSRui Paulo sm->elected_self = status; 5885b9c547cSRui Paulo } 5895b9c547cSRui Paulo 5905b9c547cSRui Paulo 5915b9c547cSRui Paulo /** 5925b9c547cSRui Paulo * ieee802_1x_cp_set_authorizationdata - 5935b9c547cSRui Paulo */ 5945b9c547cSRui Paulo void ieee802_1x_cp_set_authorizationdata(void *cp_ctx, u8 *pdata, int len) 5955b9c547cSRui Paulo { 5965b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx; 5975b9c547cSRui Paulo os_free(sm->authorization_data); 5985b9c547cSRui Paulo sm->authorization_data = os_zalloc(len); 5995b9c547cSRui Paulo if (sm->authorization_data) 6005b9c547cSRui Paulo os_memcpy(sm->authorization_data, pdata, len); 6015b9c547cSRui Paulo } 6025b9c547cSRui Paulo 6035b9c547cSRui Paulo 6045b9c547cSRui Paulo /** 6055b9c547cSRui Paulo * ieee802_1x_cp_set_ciphersuite - 6065b9c547cSRui Paulo */ 607780fb4a2SCy Schubert void ieee802_1x_cp_set_ciphersuite(void *cp_ctx, u64 cs) 6085b9c547cSRui Paulo { 6095b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx; 610780fb4a2SCy Schubert sm->cipher_suite = cs; 6115b9c547cSRui Paulo } 6125b9c547cSRui Paulo 6135b9c547cSRui Paulo 6145b9c547cSRui Paulo /** 6155b9c547cSRui Paulo * ieee802_1x_cp_set_offset - 6165b9c547cSRui Paulo */ 6175b9c547cSRui Paulo void ieee802_1x_cp_set_offset(void *cp_ctx, enum confidentiality_offset offset) 6185b9c547cSRui Paulo { 6195b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx; 6205b9c547cSRui Paulo sm->cipher_offset = offset; 6215b9c547cSRui Paulo } 6225b9c547cSRui Paulo 6235b9c547cSRui Paulo 6245b9c547cSRui Paulo /** 6255b9c547cSRui Paulo * ieee802_1x_cp_signal_newsak - 6265b9c547cSRui Paulo */ 6275b9c547cSRui Paulo void ieee802_1x_cp_signal_newsak(void *cp_ctx) 6285b9c547cSRui Paulo { 6295b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx; 6305b9c547cSRui Paulo sm->new_sak = TRUE; 6315b9c547cSRui Paulo } 6325b9c547cSRui Paulo 6335b9c547cSRui Paulo 6345b9c547cSRui Paulo /** 6355b9c547cSRui Paulo * ieee802_1x_cp_set_distributedki - 6365b9c547cSRui Paulo */ 6375b9c547cSRui Paulo void ieee802_1x_cp_set_distributedki(void *cp_ctx, 6385b9c547cSRui Paulo const struct ieee802_1x_mka_ki *dki) 6395b9c547cSRui Paulo { 6405b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx; 6415b9c547cSRui Paulo os_memcpy(&sm->distributed_ki, dki, sizeof(struct ieee802_1x_mka_ki)); 6425b9c547cSRui Paulo } 6435b9c547cSRui Paulo 6445b9c547cSRui Paulo 6455b9c547cSRui Paulo /** 6465b9c547cSRui Paulo * ieee802_1x_cp_set_distributedan - 6475b9c547cSRui Paulo */ 6485b9c547cSRui Paulo void ieee802_1x_cp_set_distributedan(void *cp_ctx, u8 an) 6495b9c547cSRui Paulo { 6505b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx; 6515b9c547cSRui Paulo sm->distributed_an = an; 6525b9c547cSRui Paulo } 6535b9c547cSRui Paulo 6545b9c547cSRui Paulo 6555b9c547cSRui Paulo /** 6565b9c547cSRui Paulo * ieee802_1x_cp_set_usingreceivesas - 6575b9c547cSRui Paulo */ 6585b9c547cSRui Paulo void ieee802_1x_cp_set_usingreceivesas(void *cp_ctx, Boolean status) 6595b9c547cSRui Paulo { 6605b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx; 6615b9c547cSRui Paulo sm->using_receive_sas = status; 6625b9c547cSRui Paulo } 6635b9c547cSRui Paulo 6645b9c547cSRui Paulo 6655b9c547cSRui Paulo /** 6665b9c547cSRui Paulo * ieee802_1x_cp_set_allreceiving - 6675b9c547cSRui Paulo */ 6685b9c547cSRui Paulo void ieee802_1x_cp_set_allreceiving(void *cp_ctx, Boolean status) 6695b9c547cSRui Paulo { 6705b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx; 6715b9c547cSRui Paulo sm->all_receiving = status; 6725b9c547cSRui Paulo } 6735b9c547cSRui Paulo 6745b9c547cSRui Paulo 6755b9c547cSRui Paulo /** 6765b9c547cSRui Paulo * ieee802_1x_cp_set_servertransmitting - 6775b9c547cSRui Paulo */ 6785b9c547cSRui Paulo void ieee802_1x_cp_set_servertransmitting(void *cp_ctx, Boolean status) 6795b9c547cSRui Paulo { 6805b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx; 6815b9c547cSRui Paulo sm->server_transmitting = status; 6825b9c547cSRui Paulo } 6835b9c547cSRui Paulo 6845b9c547cSRui Paulo 6855b9c547cSRui Paulo /** 6865b9c547cSRui Paulo * ieee802_1x_cp_set_usingtransmitsas - 6875b9c547cSRui Paulo */ 6885b9c547cSRui Paulo void ieee802_1x_cp_set_usingtransmitas(void *cp_ctx, Boolean status) 6895b9c547cSRui Paulo { 6905b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx; 6915b9c547cSRui Paulo sm->using_transmit_sa = status; 6925b9c547cSRui Paulo } 6935b9c547cSRui Paulo 6945b9c547cSRui Paulo 6955b9c547cSRui Paulo /** 6965b9c547cSRui Paulo * ieee802_1x_cp_sm_step - Advance EAPOL state machines 6975b9c547cSRui Paulo * @sm: EAPOL state machine 6985b9c547cSRui Paulo * 6995b9c547cSRui Paulo * This function is called to advance CP state machines after any change 7005b9c547cSRui Paulo * that could affect their state. 7015b9c547cSRui Paulo */ 7025b9c547cSRui Paulo void ieee802_1x_cp_sm_step(void *cp_ctx) 7035b9c547cSRui Paulo { 7045b9c547cSRui Paulo /* 7055b9c547cSRui Paulo * Run ieee802_1x_cp_step_run from a registered timeout 7065b9c547cSRui Paulo * to make sure that other possible timeouts/events are processed 7075b9c547cSRui Paulo * and to avoid long function call chains. 7085b9c547cSRui Paulo */ 7095b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx; 7105b9c547cSRui Paulo eloop_cancel_timeout(ieee802_1x_cp_step_cb, sm, NULL); 7115b9c547cSRui Paulo eloop_register_timeout(0, 0, ieee802_1x_cp_step_cb, sm, NULL); 7125b9c547cSRui Paulo } 7135b9c547cSRui Paulo 7145b9c547cSRui Paulo 7155b9c547cSRui Paulo static void ieee802_1x_cp_retire_when_timeout(void *eloop_ctx, 7165b9c547cSRui Paulo void *timeout_ctx) 7175b9c547cSRui Paulo { 7185b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = eloop_ctx; 7195b9c547cSRui Paulo sm->retire_when = 0; 7205b9c547cSRui Paulo ieee802_1x_cp_step_run(sm); 7215b9c547cSRui Paulo } 7225b9c547cSRui Paulo 7235b9c547cSRui Paulo 7245b9c547cSRui Paulo static void 7255b9c547cSRui Paulo ieee802_1x_cp_transmit_when_timeout(void *eloop_ctx, void *timeout_ctx) 7265b9c547cSRui Paulo { 7275b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = eloop_ctx; 7285b9c547cSRui Paulo sm->transmit_when = 0; 7295b9c547cSRui Paulo ieee802_1x_cp_step_run(sm); 7305b9c547cSRui Paulo } 731