@@ -301,6 +301,7 @@ struct hostapd_bss_config {
int eapol_version;
int eap_server; /* Use internal EAP server instead of external
* RADIUS server */
+ u8 eapol_dest_addr[ETH_ALEN];
struct hostapd_eap_user *eap_user;
char *eap_user_sqlite;
char *eap_sim_db;
@@ -331,6 +331,7 @@ int ieee802_1x_alloc_kay_sm_hapd(struct hostapd_data *hapd,
hapd->conf->macsec_port,
hapd->conf->mka_priority,
hapd->conf->macsec_csindex,
+ hapd->conf->eapol_dest_addr,
hapd->conf->iface,
hapd->own_addr);
/* ieee802_1x_kay_init() frees kay_ctx on failure */
@@ -83,4 +83,12 @@ enum confidentiality_offset {
#define DEFAULT_PRIO_GROUP_CA_MEMBER 0x70
#define DEFAULT_PRIO_NOT_KEY_SERVER 0xFF
+/*
+ * Nearest non-TPMR (non Two Port MAC Relay) Bridge group address,
+ * also referred to as IEEE Std 802.1X PAE address
+ * IEEE Std 802.1X-2020 - Table 11-1
+ */
+
+#define PAE_GROUP_ADDRESS { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 }
+
#endif /* IEEE802_1X_DEFS_H */
@@ -2451,10 +2451,6 @@ ieee802_1x_kay_decide_macsec_use(
return 0;
}
-static const u8 pae_group_addr[ETH_ALEN] = {
- 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03
-};
-
/**
* ieee802_1x_kay_encode_mkpdu -
@@ -2468,7 +2464,8 @@ ieee802_1x_kay_encode_mkpdu(struct ieee802_1x_mka_participant *participant,
struct ieee802_1x_hdr *eapol_hdr;
ether_hdr = wpabuf_put(pbuf, sizeof(*ether_hdr));
- os_memcpy(ether_hdr->dest, pae_group_addr, sizeof(ether_hdr->dest));
+ os_memcpy(ether_hdr->dest, participant->kay->eapol_dest_addr,
+ sizeof(ether_hdr->dest));
os_memcpy(ether_hdr->src, participant->kay->actor_sci.addr,
sizeof(ether_hdr->dest));
ether_hdr->ethertype = host_to_be16(ETH_P_EAPOL);
@@ -3495,7 +3492,8 @@ struct ieee802_1x_kay *
ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
bool macsec_replay_protect, u32 macsec_replay_window,
u8 macsec_offload, u16 port, u8 priority,
- u32 macsec_csindex, const char *ifname, const u8 *addr)
+ u32 macsec_csindex,
+ const u8 *eapol_dest_addr, const char *ifname, const u8 *addr)
{
struct ieee802_1x_kay *kay;
@@ -3536,6 +3534,8 @@ ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
kay->mka_algindex = DEFAULT_MKA_ALG_INDEX;
kay->mka_version = MKA_VERSION_ID;
+ os_memcpy(kay->eapol_dest_addr, eapol_dest_addr, ETH_ALEN);
+
os_memcpy(kay->algo_agility, mka_algo_agility,
sizeof(kay->algo_agility));
@@ -234,6 +234,8 @@ struct ieee802_1x_kay {
enum validate_frames vf;
enum confidentiality_offset co;
+
+ u8 eapol_dest_addr[ETH_ALEN];
};
@@ -243,7 +245,8 @@ struct ieee802_1x_kay *
ieee802_1x_kay_init(struct ieee802_1x_kay_ctx *ctx, enum macsec_policy policy,
bool macsec_replay_protect, u32 macsec_replay_window,
u8 macsec_offload, u16 port, u8 priority,
- u32 macsec_csindex, const char *ifname, const u8 *addr);
+ u32 macsec_csindex,
+ const u8 *eapol_dest_addr, const char *ifname, const u8 *addr);
void ieee802_1x_kay_deinit(struct ieee802_1x_kay *kay);
struct ieee802_1x_mka_participant *
@@ -21,6 +21,9 @@
#include "config.h"
+static const u8 pae_group_addr[ETH_ALEN] = PAE_GROUP_ADDRESS;
+
+
#if !defined(CONFIG_CTRL_IFACE) && defined(CONFIG_NO_CONFIG_WRITE)
#define NO_CONFIG_WRITE
#endif
@@ -1663,6 +1666,30 @@ static int wpa_config_parse_eap(const struct parse_data *data,
}
+static int wpa_config_parse_eapol_dest_addr(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
+ const char *value)
+{
+ wpa_printf(MSG_DEBUG, "value: '%s'", value);
+
+ if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 ||
+ os_strcmp(value, "default") == 0) {
+ os_memcpy(ssid->eapol_dest_addr, pae_group_addr, ETH_ALEN);
+ wpa_printf(MSG_DEBUG, "EAPOL using PAE (default) destination MAC address" MACSTR,
+ MAC2STR(ssid->eapol_dest_addr));
+ return 0;
+ }
+ if (hwaddr_aton2(value, ssid->eapol_dest_addr) == -1) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid EAPOL destination MAC address '%s'.",
+ line, value);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "EAPOL destination MAC address " MACSTR,
+ MAC2STR(ssid->eapol_dest_addr));
+ return 0;
+}
+
+
#ifndef NO_CONFIG_WRITE
static char * wpa_config_write_eap(const struct parse_data *data,
struct wpa_ssid *ssid)
@@ -1697,6 +1724,28 @@ static char * wpa_config_write_eap(const struct parse_data *data,
return buf;
}
+
+
+static char * wpa_config_write_eapol_dest_addr(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ char *value;
+ int res;
+
+ if (is_zero_ether_addr(ssid->eapol_dest_addr))
+ return NULL;
+
+ value = os_malloc(20);
+ if (value == NULL)
+ return NULL;
+ res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->eapol_dest_addr));
+ if (os_snprintf_error(20, res)) {
+ os_free(value);
+ return NULL;
+ }
+ value[20 - 1] = '\0';
+ return value;
+}
#endif /* NO_CONFIG_WRITE */
@@ -2549,6 +2598,7 @@ static const struct parse_data ssid_fields[] = {
{ INT(vht_center_freq2) },
#ifdef IEEE8021X_EAPOL
{ FUNC(eap) },
+ { FUNC(eapol_dest_addr) },
{ STR_LENe(identity, identity) },
{ STR_LENe(anonymous_identity, anonymous_identity) },
{ STR_LENe(imsi_identity, imsi_identity) },
@@ -3236,6 +3286,7 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
ssid->eap_workaround = DEFAULT_EAP_WORKAROUND;
ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE;
ssid->eap.sim_num = DEFAULT_USER_SELECTED_SIM;
+ os_memcpy(ssid->eapol_dest_addr, pae_group_addr, ETH_ALEN);
#endif /* IEEE8021X_EAPOL */
#ifdef CONFIG_MESH
ssid->dot11MeshMaxRetries = DEFAULT_MESH_MAX_RETRIES;
@@ -418,6 +418,17 @@ struct wpa_ssid {
*/
unsigned int eap_workaround;
+ /**
+ * eapol_dest_addr - mac addr for EAPOL packets (802.11AE-2018+ etc.)
+ * EAPOL packets may have their destination MAC address set to any
+ * non-individual (i.g. multi-cast) address, including the ethernet
+ * broadcast address (ff:ff:ff:ff:ff:ff). Choice of destination
+ * address is dictated by which types of entity (should) filter them
+ * out vs. act on their contents vs. relay them.
+ * See 802.11X-2020 Table 11-1
+ */
+ u8 eapol_dest_addr[ETH_ALEN];
+
#endif /* IEEE8021X_EAPOL */
/**
@@ -249,6 +249,7 @@ int ieee802_1x_alloc_kay_sm(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
ssid->macsec_replay_window,
ssid->macsec_offload, ssid->macsec_port,
ssid->mka_priority, ssid->macsec_csindex,
+ ssid->eapol_dest_addr,
wpa_s->ifname, wpa_s->own_addr);
/* ieee802_1x_kay_init() frees kay_ctx on failure */
if (res == NULL)