diff --git a/src/common/ieee802_1x_defs.h b/src/common/ieee802_1x_defs.h index 918082469..b5c4525be 100644 --- a/src/common/ieee802_1x_defs.h +++ b/src/common/ieee802_1x_defs.h @@ -72,6 +72,20 @@ enum validate_frames { Strict, }; +/* + * IEEE Association Number (which identifies the SA within an SC + * in a Macsec frame) is 2b wide. Hence we can have up to 4 + * SAs active at any given time per SC. This setting + * allows an implementation to specify a lower value + */ +enum max_sa_per_sc { + MAX_SA_PER_SC_1 = 1, + MAX_SA_PER_SC_2 = 2, + MAX_SA_PER_SC_3 = 3, + MAX_SA_PER_SC_4 = 4, + MAX_SA_PER_SC_DEFAULT = MAX_SA_PER_SC_4, +}; + /* IEEE Std 802.1X-2010 - Table 11-6 - Confidentiality Offset */ enum confidentiality_offset { CONFIDENTIALITY_NONE = 0, @@ -81,6 +95,8 @@ enum confidentiality_offset { }; /* IEEE Std 802.1X-2010 - Table 9-2 */ + +#define DEFAULT_PRIO_HIGHEST 0x0 #define DEFAULT_PRIO_INFRA_PORT 0x10 #define DEFAULT_PRIO_PRIMRAY_AP 0x30 #define DEFAULT_PRIO_SECONDARY_AP 0x50 diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 9b8a585bd..bb890994a 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -4021,6 +4021,14 @@ struct wpa_driver_ops { */ int (*macsec_get_capability)(void *priv, enum macsec_cap *cap); + /** + * macsec_get_max_sa_per_sc - Inform MKA of max number of SAs per SC + * @priv: Private driver interface data + * @max: Max number of SAs per SC + * Returns: 0 on success, -1 on failure + */ + int (*macsec_get_max_sa_per_sc)(void *priv, enum max_sa_per_sc *max); + /** * enable_protect_frames - Set protect frames status * @priv: Private driver interface data diff --git a/src/drivers/driver_macsec_sonic.c b/src/drivers/driver_macsec_sonic.c index 144a7ad71..ea656011e 100644 --- a/src/drivers/driver_macsec_sonic.c +++ b/src/drivers/driver_macsec_sonic.c @@ -204,6 +204,53 @@ static int macsec_sonic_macsec_deinit(void *priv) return ret; } +static int macsec_sonic_macsec_get_max_sa_per_sc(void *priv, + enum max_sa_per_sc *max) +{ + struct macsec_sonic_data *drv = priv; + ENTER_LOG; + + const struct sonic_db_name_value_pair pairs[] = + { + {"state", "ok"}, + }; + + int ret = sonic_db_wait( + drv->sonic_manager, + STATE_DB, + STATE_MACSEC_PORT_TABLE_NAME, + SET_COMMAND, + drv->ifname, + PAIR_ARRAY(pairs)); + if (ret == SONIC_DB_SUCCESS) + { + struct sonic_db_name_value_pairs * get_pairs = sonic_db_malloc_name_value_pairs(); + ret = sonic_db_get( + drv->sonic_manager, + STATE_DB, + STATE_MACSEC_PORT_TABLE_NAME, + drv->ifname, + get_pairs); + if (ret == SONIC_DB_SUCCESS) { + int max_val = -1; + for ( unsigned int i = 0; i < get_pairs->pair_count; ++i ) { + if ( strcmp( get_pairs->pairs[i].name, "max_sa_per_sc" ) == 0 ) { + PRINT_LOG( "max_sa_per_sc found: %s", get_pairs->pairs[i].value ); + sscanf( get_pairs->pairs[i].value, "%4d", &max_val ); + break; + } + } + if ( max_val == -1 ) { + // If we don't find a max_sa_per_sc attribute use default value + max_val = MAX_SA_PER_SC_DEFAULT; + } + *max = max_val; + } + sonic_db_free_name_value_pairs( get_pairs ); + } + return ret; +} + static int macsec_sonic_get_capability(void *priv, enum macsec_cap *cap) { struct macsec_sonic_data *drv = priv; @@ -982,6 +1029,7 @@ const struct wpa_driver_ops wpa_driver_macsec_sonic_ops = { .macsec_init = macsec_sonic_macsec_init, .macsec_deinit = macsec_sonic_macsec_deinit, + .macsec_get_max_sa_per_sc = macsec_sonic_macsec_get_max_sa_per_sc, .macsec_get_capability = macsec_sonic_get_capability, .enable_protect_frames = macsec_sonic_enable_protect_frames, .enable_encrypt = macsec_sonic_enable_encrypt, diff --git a/src/drivers/sonic_operators.cpp b/src/drivers/sonic_operators.cpp index fa998fe60..153b95bea 100644 --- a/src/drivers/sonic_operators.cpp +++ b/src/drivers/sonic_operators.cpp @@ -250,8 +250,9 @@ class sonic_db_manager{ memcpy(name, result[i].first.data(), result[i].first.length() + 1); pairs->pairs[pairs->pair_count].name = name; char * value = reinterpret_cast(malloc(result[i].second.length() + 1)); - memcpy(value, result[i].first.data(), result[i].second.length() + 1); + memcpy(value, result[i].second.data(), result[i].second.length() + 1); pairs->pairs[pairs->pair_count].value = value; + pairs->pair_count++; } return SONIC_DB_SUCCESS; } diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c index 23dfc48e0..e68343e29 100644 --- a/src/pae/ieee802_1x_kay.c +++ b/src/pae/ieee802_1x_kay.c @@ -2323,7 +2323,7 @@ ieee802_1x_kay_generate_new_sak(struct ieee802_1x_mka_participant *participant) kay->dist_kn++; kay->dist_an++; - if (kay->dist_an > 3) + if (kay->dist_an > kay->max_sa_per_sc - 1) kay->dist_an = 0; kay->dist_time = time(NULL); @@ -3595,7 +3595,6 @@ ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy, kay->actor_sci.port = host_to_be16(port ? port : 0x0001); wpa_printf(MSG_DEBUG, "KaY: Generated SCI: %s", sci_txt(&kay->actor_sci)); - kay->actor_priority = priority; /* While actor acts as a key server, shall distribute sakey */ kay->dist_kn = 1; @@ -3659,6 +3658,22 @@ ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy, wpa_printf(MSG_DEBUG, "KaY: secy init macsec done"); + enum max_sa_per_sc max; + if (secy_get_max_sa_per_sc( kay, &max ) < 0){ + wpa_printf(MSG_ERROR, "KaY: Could not determine max SAs per SC"); + goto error; + } + kay->max_sa_per_sc = max; + + /* + * If the maximum SAs per SC is not the default, the actor_priority + * is forced to the highest value of 0 so it can be elected as key + * server and control the AN assignments to within the supported limit + */ + if (max != MAX_SA_PER_SC_4) + priority = DEFAULT_PRIO_HIGHEST; + kay->actor_priority = priority; + /* init CP */ kay->cp = ieee802_1x_cp_sm_init(kay); if (kay->cp == NULL) diff --git a/src/pae/ieee802_1x_kay.h b/src/pae/ieee802_1x_kay.h index f7aa7f45b..abf29bc9c 100644 --- a/src/pae/ieee802_1x_kay.h +++ b/src/pae/ieee802_1x_kay.h @@ -146,6 +146,7 @@ struct ieee802_1x_kay_ctx { /* abstract wpa driver interface */ int (*macsec_init)(void *ctx, struct macsec_init_params *params); int (*macsec_deinit)(void *ctx); + int (*macsec_get_max_sa_per_sc)(void *priv, enum max_sa_per_sc *max); int (*macsec_get_capability)(void *priv, enum macsec_cap *cap); int (*enable_protect_frames)(void *ctx, bool enabled); int (*enable_encrypt)(void *ctx, bool enabled); @@ -193,6 +194,7 @@ struct ieee802_1x_kay { bool macsec_include_sci; bool macsec_replay_protect; u32 macsec_replay_window; + u8 max_sa_per_sc; enum validate_frames macsec_validate; enum confidentiality_offset macsec_confidentiality; u32 mka_hello_time; diff --git a/src/pae/ieee802_1x_secy_ops.c b/src/pae/ieee802_1x_secy_ops.c index ca0c393b9..c1575eda6 100644 --- a/src/pae/ieee802_1x_secy_ops.c +++ b/src/pae/ieee802_1x_secy_ops.c @@ -537,3 +537,32 @@ int secy_deinit_macsec(struct ieee802_1x_kay *kay) return ops->macsec_deinit(ops->ctx); } + +int secy_get_max_sa_per_sc(struct ieee802_1x_kay *kay, enum max_sa_per_sc *max) +{ + struct ieee802_1x_kay_ctx *ops; + + if (!kay) { + wpa_printf(MSG_ERROR, "KaY: %s params invalid", __func__); + return -1; + } + + ops = kay->ctx; + if (!ops) { + wpa_printf(MSG_ERROR, + "KaY: secy get_max_sas_per_sc operation not supported"); + return -1; + } + + /* + * If the max SAs per SC setting control is not implemented by + * the driver, then return the default + */ + if( !ops->macsec_get_max_sa_per_sc) { + *max = MAX_SA_PER_SC_DEFAULT; + return 0; + } + + return ops->macsec_get_max_sa_per_sc(ops->ctx, max); +} + diff --git a/src/pae/ieee802_1x_secy_ops.h b/src/pae/ieee802_1x_secy_ops.h index 18c06f665..0a3beee3c 100644 --- a/src/pae/ieee802_1x_secy_ops.h +++ b/src/pae/ieee802_1x_secy_ops.h @@ -16,6 +16,7 @@ struct ieee802_1x_kay_conf; int secy_init_macsec(struct ieee802_1x_kay *kay); int secy_deinit_macsec(struct ieee802_1x_kay *kay); +int secy_get_max_sa_per_sc(struct ieee802_1x_kay *kay, enum max_sa_per_sc *max); /****** CP -> SecY ******/ int secy_cp_control_validate_frames(struct ieee802_1x_kay *kay, diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index ba8cc552b..ab2fe42d1 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -769,6 +769,14 @@ static inline int wpa_drv_macsec_deinit(struct wpa_supplicant *wpa_s) return wpa_s->driver->macsec_deinit(wpa_s->drv_priv); } +static inline int wpa_drv_macsec_get_max_sa_per_sc(struct wpa_supplicant *wpa_s, + enum max_sa_per_sc *max) +{ + if (!wpa_s->driver->macsec_get_max_sa_per_sc) + return -1; + return wpa_s->driver->macsec_get_max_sa_per_sc(wpa_s->drv_priv, max); +} + static inline int wpa_drv_macsec_get_capability(struct wpa_supplicant *wpa_s, enum macsec_cap *cap) { diff --git a/wpa_supplicant/wpas_kay.c b/wpa_supplicant/wpas_kay.c index 001c9547d..082dad935 100644 --- a/wpa_supplicant/wpas_kay.c +++ b/wpa_supplicant/wpas_kay.c @@ -37,6 +37,10 @@ static int wpas_macsec_deinit(void *priv) return wpa_drv_macsec_deinit(priv); } +static int wpas_macsec_get_max_sa_per_sc(void *priv, enum max_sa_per_sc *max) +{ + return wpa_drv_macsec_get_max_sa_per_sc(priv, max); +} static int wpas_macsec_get_capability(void *priv, enum macsec_cap *cap) { @@ -216,6 +220,7 @@ int ieee802_1x_alloc_kay_sm(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) kay_ctx->macsec_init = wpas_macsec_init; kay_ctx->macsec_deinit = wpas_macsec_deinit; + kay_ctx->macsec_get_max_sa_per_sc = wpas_macsec_get_max_sa_per_sc; kay_ctx->macsec_get_capability = wpas_macsec_get_capability; kay_ctx->enable_protect_frames = wpas_enable_protect_frames; kay_ctx->enable_encrypt = wpas_enable_encrypt;