@@ -126,7 +126,6 @@ SM_STATE(CP, INIT)
sm->otx = FALSE;
sm->orx = FALSE;
- sm->port_enabled = TRUE;
sm->chgd_server = FALSE;
}
@@ -448,6 +447,7 @@ struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(struct ieee802_1x_kay *kay)
sm->replay_window = kay->macsec_replay_window;
sm->controlled_port_enabled = FALSE;
+ sm->port_enabled = TRUE;
sm->lki = NULL;
sm->lrx = FALSE;
@@ -693,6 +693,17 @@ void ieee802_1x_cp_set_usingtransmitas(void *cp_ctx, Boolean status)
/**
+ * ieee802_1x_cp_set_portenabled -
+ * @status: indicates MAC_Operational status of the common port
+ */
+void ieee802_1x_cp_set_portenabled(void *cp_ctx, Boolean status)
+{
+ struct ieee802_1x_cp_sm *sm = cp_ctx;
+ sm->port_enabled = status;
+}
+
+
+/**
* ieee802_1x_cp_sm_step - Advance EAPOL state machines
* @sm: EAPOL state machine
*
@@ -36,5 +36,6 @@ void ieee802_1x_cp_set_usingreceivesas(void *cp_ctx, Boolean status);
void ieee802_1x_cp_set_allreceiving(void *cp_ctx, Boolean status);
void ieee802_1x_cp_set_servertransmitting(void *cp_ctx, Boolean status);
void ieee802_1x_cp_set_usingtransmitas(void *cp_ctx, Boolean status);
+void ieee802_1x_cp_set_portenabled(void *cp_ctx, Boolean status);
#endif /* IEEE802_1X_CP_H */
@@ -772,6 +772,11 @@ ieee802_1x_mka_decode_basic_body(struct ieee802_1x_kay *kay, const u8 *mka_msg,
return NULL;
}
+ if (!participant->participant) {
+ wpa_printf(MSG_MSGDUMP, "KaY: MKA participation disabled");
+ return NULL;
+ }
+
/* If the peer's MI is my MI, I will choose new MI */
if (os_memcmp(body->actor_mi, participant->mi, MI_LEN) == 0) {
if (!reset_participant_mi(participant))
@@ -1240,7 +1245,6 @@ ieee802_1x_mka_encode_sak_use_body(
/* set CP's variable */
if (body->ltx) {
kay->tx_enable = TRUE;
- kay->port_enable = TRUE;
}
if (body->lrx)
kay->rx_enable = TRUE;
@@ -2329,6 +2333,28 @@ static void ieee802_1x_delete_transmit_sa(struct ieee802_1x_kay *kay,
/**
+ * ieee802_1x_kay_recalc_mka_active -
+ */
+static void
+ieee802_1x_kay_recalc_mka_active(struct ieee802_1x_kay *kay)
+{
+ struct ieee802_1x_mka_participant *participant;
+ Boolean active = FALSE;
+
+ /* Recalculate KaY active (ieee8021XKayMkaActive) */
+ dl_list_for_each(participant, &kay->participant_list,
+ struct ieee802_1x_mka_participant, list) {
+ if (participant->active) {
+ active = TRUE;
+ break;
+ }
+ }
+
+ kay->active = active;
+}
+
+
+/**
* ieee802_1x_participant_timer -
*/
static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx)
@@ -2338,6 +2364,7 @@ static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx)
struct ieee802_1x_kay_peer *peer, *pre_peer;
time_t now = time(NULL);
Boolean lp_changed;
+ Boolean participate;
struct receive_sc *rxsc, *pre_rxsc;
struct transmit_sa *txsa, *pre_txsa;
@@ -2348,6 +2375,10 @@ static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx)
goto delete_mka;
}
+ /* only participate in MKA (i.e., transmit MKPDUs) if port
+ * is enabled and participant has not been disabled */
+ participate = kay->port_enable && participant->participant;
+
/* should delete MKA instance if there are not live peers
* when the MKA life elapsed since its creating */
if (participant->mka_life) {
@@ -2362,7 +2393,7 @@ static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx)
lp_changed = FALSE;
dl_list_for_each_safe(peer, pre_peer, &participant->live_peers,
struct ieee802_1x_kay_peer, list) {
- if (now > peer->expire) {
+ if (!participate || (now > peer->expire)) {
wpa_printf(MSG_DEBUG, "KaY: Live peer removed");
wpa_hexdump(MSG_DEBUG, "\tMI: ", peer->mi,
sizeof(peer->mi));
@@ -2420,7 +2451,7 @@ static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx)
dl_list_for_each_safe(peer, pre_peer, &participant->potential_peers,
struct ieee802_1x_kay_peer, list) {
- if (now > peer->expire) {
+ if (!participate || (now > peer->expire)) {
wpa_printf(MSG_DEBUG, "KaY: Potential peer removed");
wpa_hexdump(MSG_DEBUG, "\tMI: ", peer->mi,
sizeof(peer->mi));
@@ -2430,6 +2461,12 @@ static void ieee802_1x_participant_timer(void *eloop_ctx, void *timeout_ctx)
}
}
+ if (!participate) {
+ participant->active = FALSE;
+ ieee802_1x_kay_recalc_mka_active(kay);
+ return;
+ }
+
if (participant->new_sak) {
if (!ieee802_1x_kay_generate_new_sak(participant))
participant->to_dist_sak = TRUE;
@@ -2836,7 +2873,7 @@ int ieee802_1x_kay_enable_new_info(struct ieee802_1x_kay *kay)
struct ieee802_1x_mka_participant *principal;
principal = ieee802_1x_kay_get_principal_participant(kay);
- if (!principal)
+ if (!principal || !principal->participant)
return -1;
if (principal->retry_count < MAX_RETRY_CNT || principal->mode == PSK) {
@@ -3321,7 +3358,7 @@ ieee802_1x_kay_create_mka(struct ieee802_1x_kay *kay, struct mka_key_name *ckn,
participant->cached = FALSE;
participant->active = FALSE;
- participant->participant = FALSE;
+ participant->participant = TRUE;
participant->retain = FALSE;
participant->activate = DEFAULT;
@@ -3465,6 +3502,8 @@ ieee802_1x_kay_delete_mka(struct ieee802_1x_kay *kay, struct mka_key_name *ckn)
os_memset(&participant->kek, 0, sizeof(participant->kek));
os_memset(&participant->ick, 0, sizeof(participant->ick));
os_free(participant);
+
+ ieee802_1x_kay_recalc_mka_active(kay);
}
@@ -3484,7 +3523,57 @@ void ieee802_1x_kay_mka_participate(struct ieee802_1x_kay *kay,
if (!participant)
return;
- participant->active = status;
+ if (participant->participant == status)
+ return;
+
+ participant->participant = status;
+
+ if (status) {
+ /* Restart timer immediately if both port and participant are enabled */
+ if (kay->port_enable) {
+ eloop_register_timeout(0, 0, ieee802_1x_participant_timer,
+ participant, NULL);
+ }
+ } else {
+ participant->active = FALSE;
+ ieee802_1x_kay_recalc_mka_active(kay);
+ }
+}
+
+
+/**
+ * ieee802_1x_kay_notify_port_enabled -
+ */
+void ieee802_1x_kay_notify_port_enabled(struct ieee802_1x_kay *kay,
+ Boolean enabled)
+{
+ struct ieee802_1x_mka_participant *participant;
+ unsigned int usecs;
+
+ if (kay->port_enable == enabled)
+ return;
+
+ wpa_printf(MSG_DEBUG, "KaY: External notification - "
+ "portEnabled=%d", enabled);
+
+ kay->port_enable = enabled;
+
+ ieee802_1x_cp_set_portenabled(kay->cp, enabled);
+
+ if (!enabled) {
+ /* Existing participants will be cleaned up next time their timers expire */
+ kay->active = FALSE;
+ } else {
+ /* Staggered restart of participant timers */
+ dl_list_for_each(participant, &kay->participant_list,
+ struct ieee802_1x_mka_participant, list) {
+ if (participant->participant) {
+ usecs = os_random() % (MKA_HELLO_TIME * 1000);
+ eloop_register_timeout(0, usecs, ieee802_1x_participant_timer,
+ participant, NULL);
+ }
+ }
+ }
}
@@ -3575,6 +3664,7 @@ int ieee802_1x_kay_get_status(struct ieee802_1x_kay *kay, char *buf,
return 0;
len = os_snprintf(buf, buflen,
+ "Port status=%s\n"
"PAE KaY status=%s\n"
"Authenticated=%s\n"
"Secured=%s\n"
@@ -3584,6 +3674,7 @@ int ieee802_1x_kay_get_status(struct ieee802_1x_kay *kay, char *buf,
"Is Key Server=%s\n"
"Number of Keys Distributed=%u\n"
"Number of Keys Received=%u\n",
+ kay->port_enable ? "Enabled" : "Disabled",
kay->active ? "Active" : "Not-Active",
kay->authenticated ? "Yes" : "No",
kay->secured ? "Yes" : "No",
@@ -249,6 +249,8 @@ void ieee802_1x_kay_delete_mka(struct ieee802_1x_kay *kay,
void ieee802_1x_kay_mka_participate(struct ieee802_1x_kay *kay,
struct mka_key_name *ckn,
Boolean status);
+void ieee802_1x_kay_notify_port_enabled(struct ieee802_1x_kay *kay,
+ Boolean enabled);
int ieee802_1x_kay_new_sak(struct ieee802_1x_kay *kay);
int ieee802_1x_kay_change_cipher_suite(struct ieee802_1x_kay *kay,
unsigned int cs_index);
@@ -90,8 +90,8 @@ struct ieee802_1x_mka_participant {
Boolean cached;
/* used by management to monitor and control activation */
- Boolean active;
- Boolean participant;
+ Boolean active; /* used to calculate ieee8021XKayMkaActive (IEEE8021X-PAE-MIB) */
+ Boolean participant; /* MKA.participate, from IEEE802.1X-2010, Clause 12.2 */
Boolean retain;
enum mka_created_mode mode;