[PATCH] add new macsec offload modes to abstract device-level details

Sabrina Dubroca sd at queasysnail.net
Tue Feb 6 06:15:03 PST 2024


Currently, users have to guess which offload mode their hardware
provides, as the kernel doesn't expose this information.

Add an "on" mode which requires offload (either to mac or phy) and a
"prefer" mode which allows fallback to SW when offload (either to mac
or phy) is unavailable.

Also rename the existing modes to string values to make the config
file a bit clearer.

Signed-off-by: Sabrina Dubroca <sd at queasysnail.net>
---
 hostapd/config_file.c              | 32 ++++++++++---
 hostapd/hostapd.conf               |  8 ++--
 src/ap/ap_config.h                 |  4 +-
 src/common/ieee802_1x_defs.h       | 10 ++++
 src/drivers/driver.h               |  4 +-
 src/drivers/driver_macsec_linux.c  | 73 +++++++++++++++++++++++++-----
 wpa_supplicant/config.c            | 36 ++++++++++++++-
 wpa_supplicant/config_file.c       |  8 +++-
 wpa_supplicant/config_ssid.h       |  4 +-
 wpa_supplicant/wpa_supplicant.conf | 10 ++--
 10 files changed, 152 insertions(+), 37 deletions(-)

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 1af083917052..7c00398dcc01 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2435,6 +2435,29 @@ static int get_u16(const char *pos, int line, u16 *ret_val)
 }
 #endif /* CONFIG_IEEE80211BE */
 
+#ifdef CONFIG_MACSEC
+const char *macsec_offload_strings[NUM_CONFIG_MACSEC_OFFLOAD_MODES] = {
+	"off",
+	"on",
+	"mac",
+	"phy",
+	"prefer",
+};
+static int parse_macsec_offload(struct hostapd_bss_config *bss, const char *val)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(macsec_offload_strings); i++) {
+		if (os_strcmp(macsec_offload_strings[i], val) == 0) {
+			bss->macsec_offload = i;
+			return 0;
+		}
+	}
+
+	return 1;
+}
+#endif /* CONFIG_MACSEC */
+
 
 static int hostapd_config_fill(struct hostapd_config *conf,
 			       struct hostapd_bss_config *bss,
@@ -4816,15 +4839,12 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 	} else if (os_strcmp(buf, "macsec_replay_window") == 0) {
 		bss->macsec_replay_window = atoi(pos);
 	} else if (os_strcmp(buf, "macsec_offload") == 0) {
-		int macsec_offload = atoi(pos);
-
-		if (macsec_offload < 0 || macsec_offload > 2) {
+		if (parse_macsec_offload(bss, pos)) {
 			wpa_printf(MSG_ERROR,
-				   "Line %d: invalid macsec_offload (%d): '%s'.",
-				   line, macsec_offload, pos);
+				   "Line %d: invalid macsec_offload: '%s'.",
+				   line, pos);
 			return 1;
 		}
-		bss->macsec_offload = macsec_offload;
 	} else if (os_strcmp(buf, "macsec_port") == 0) {
 		int macsec_port = atoi(pos);
 
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 13576499a358..368e0c3622ed 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -1174,9 +1174,11 @@ eapol_key_index_workaround=0
 # This setting applies only when MACsec is in use, i.e.,
 #  - macsec_policy is enabled
 #  - the key server has decided to enable MACsec
-# 0 = MACSEC_OFFLOAD_OFF (default)
-# 1 = MACSEC_OFFLOAD_PHY
-# 2 = MACSEC_OFFLOAD_MAC
+# off = don't offload (default)
+# mac = request offload to the MAC
+# phy = request offload to the PHY
+# on = request offload (to either MAC or PHY)
+# prefer = try to offload (to either MAC or PHY), fall back to software
 #
 # macsec_port: IEEE 802.1X/MACsec port
 # Port component of the SCI
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index de02ddafda77..5ce68b8d0b73 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -863,9 +863,7 @@ struct hostapd_bss_config {
 	 *  - macsec_policy is enabled
 	 *  - the key server has decided to enable MACsec
 	 *
-	 * 0 = MACSEC_OFFLOAD_OFF (default)
-	 * 1 = MACSEC_OFFLOAD_PHY
-	 * 2 = MACSEC_OFFLOAD_MAC
+	 * Values: enum macsec_offload_modes
 	 */
 	int macsec_offload;
 
diff --git a/src/common/ieee802_1x_defs.h b/src/common/ieee802_1x_defs.h
index e7acff108eb3..ea964e1dd338 100644
--- a/src/common/ieee802_1x_defs.h
+++ b/src/common/ieee802_1x_defs.h
@@ -83,4 +83,14 @@ enum confidentiality_offset {
 #define DEFAULT_PRIO_GROUP_CA_MEMBER   0x70
 #define DEFAULT_PRIO_NOT_KEY_SERVER    0xFF
 
+enum macsec_offload_modes {
+	CONFIG_MACSEC_OFFLOAD_OFF,
+	CONFIG_MACSEC_OFFLOAD_ON,
+	CONFIG_MACSEC_OFFLOAD_MAC,
+	CONFIG_MACSEC_OFFLOAD_PHY,
+	CONFIG_MACSEC_OFFLOAD_PREFER,
+	NUM_CONFIG_MACSEC_OFFLOAD_MODES,
+};
+extern const char *macsec_offload_strings[NUM_CONFIG_MACSEC_OFFLOAD_MODES];
+
 #endif /* IEEE802_1X_DEFS_H */
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 4974bbdc8711..e018aabcf8ed 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -4662,9 +4662,7 @@ struct wpa_driver_ops {
 	/**
 	 * set_offload - Set MACsec hardware offload
 	 * @priv: Private driver interface data
-	 * @offload: 0 = MACSEC_OFFLOAD_OFF
-	 *           1 = MACSEC_OFFLOAD_PHY
-	 *           2 = MACSEC_OFFLOAD_MAC
+	 * @offload: enum macsec_offload_modes
 	 * Returns: 0 on success, -1 on failure (or if not supported)
 	 */
 	int (*set_offload)(void *priv, u8 offload);
diff --git a/src/drivers/driver_macsec_linux.c b/src/drivers/driver_macsec_linux.c
index c867154981e9..3124104f4aad 100644
--- a/src/drivers/driver_macsec_linux.c
+++ b/src/drivers/driver_macsec_linux.c
@@ -78,7 +78,7 @@ struct macsec_drv_data {
 	bool replay_protect_set;
 
 #ifdef LIBNL_HAS_OFFLOAD
-	enum macsec_offload offload;
+	enum macsec_offload_modes offload;
 	bool offload_set;
 #endif /* LIBNL_HAS_OFFLOAD */
 
@@ -237,26 +237,77 @@ static int try_commit(struct macsec_drv_data *drv)
 						    drv->replay_window);
 	}
 
+	if (drv->encoding_sa_set) {
+		wpa_printf(MSG_DEBUG, DRV_PREFIX
+			   "%s: try_commit encoding_sa=%d",
+			   drv->ifname, drv->encoding_sa);
+		rtnl_link_macsec_set_encoding_sa(drv->link, drv->encoding_sa);
+	}
+
+	/* must be last */
 #ifdef LIBNL_HAS_OFFLOAD
 	if (drv->offload_set) {
+		int offload_value;
+
 		wpa_printf(MSG_DEBUG, DRV_PREFIX
 			   "%s: try_commit offload=%d",
 			   drv->ifname, drv->offload);
-		rtnl_link_macsec_set_offload(drv->link, drv->offload);
-	}
-#endif /* LIBNL_HAS_OFFLOAD */
+		if (drv->offload == CONFIG_MACSEC_OFFLOAD_PREFER ||
+		    drv->offload == CONFIG_MACSEC_OFFLOAD_ON) {
+			/* try MAC, then PHY, and also OFF (only for PREFER) */
+			wpa_printf(MSG_DEBUG, DRV_PREFIX
+				   "%s: attempting MACSEC_OFFLOAD_MAC",
+				   drv->ifname);
+			rtnl_link_macsec_set_offload(drv->link, MACSEC_OFFLOAD_MAC);
+			if (rtnl_link_add(drv->sk, drv->link, 0) >= 0)
+				goto end;
+
+			wpa_printf(MSG_DEBUG, DRV_PREFIX
+				   "%s: attempting MACSEC_OFFLOAD_PHY",
+				   drv->ifname);
+			rtnl_link_macsec_set_offload(drv->link, MACSEC_OFFLOAD_PHY);
+			if (rtnl_link_add(drv->sk, drv->link, 0) >= 0)
+				goto end;
+
+			if (drv->offload == CONFIG_MACSEC_OFFLOAD_ON) {
+				wpa_printf(MSG_DEBUG, DRV_PREFIX
+					   "%s: offload was requested but couldn't be set",
+					   drv->ifname);
+				return -1;
+			}
 
-	if (drv->encoding_sa_set) {
-		wpa_printf(MSG_DEBUG, DRV_PREFIX
-			   "%s: try_commit encoding_sa=%d",
-			   drv->ifname, drv->encoding_sa);
-		rtnl_link_macsec_set_encoding_sa(drv->link, drv->encoding_sa);
+			wpa_printf(MSG_DEBUG, DRV_PREFIX
+				   "%s: attempting MACSEC_OFFLOAD_OFF",
+				   drv->ifname);
+			rtnl_link_macsec_set_offload(drv->link, MACSEC_OFFLOAD_OFF);
+			if (rtnl_link_add(drv->sk, drv->link, 0) >= 0)
+				goto end;
+
+			return -1;
+		}
+
+		switch (drv->offload) {
+		case CONFIG_MACSEC_OFFLOAD_MAC:
+			offload_value = MACSEC_OFFLOAD_MAC;
+			break;
+		case CONFIG_MACSEC_OFFLOAD_PHY:
+			offload_value = MACSEC_OFFLOAD_PHY;
+			break;
+		default:
+			offload_value = MACSEC_OFFLOAD_OFF;
+			break;
+		}
+		rtnl_link_macsec_set_offload(drv->link, offload_value);
 	}
+#endif /* LIBNL_HAS_OFFLOAD */
 
 	err = rtnl_link_add(drv->sk, drv->link, 0);
 	if (err < 0)
 		return err;
 
+#ifdef LIBNL_HAS_OFFLOAD
+end:
+#endif /* LIBNL_HAS_OFFLOAD */
 	drv->protect_frames_set = false;
 	drv->encrypt_set = false;
 	drv->replay_protect_set = false;
@@ -476,9 +527,7 @@ static int macsec_drv_set_replay_protect(void *priv, bool enabled,
 /**
  * macsec_drv_set_offload - Set offload status
  * @priv: Private driver interface data
- * @offload: 0 = MACSEC_OFFLOAD_OFF
- *           1 = MACSEC_OFFLOAD_PHY
- *           2 = MACSEC_OFFLOAD_MAC
+ * @offload: see enum macsec_offload_modes
  * Returns: 0 on success, -1 on failure (or if not supported)
  */
 static int macsec_drv_set_offload(void *priv, u8 offload)
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index fca4320a19f2..e8dc14c4fa13 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -2280,6 +2280,30 @@ static int wpa_config_parse_mka_ckn(const struct parse_data *data,
 	return 0;
 }
 
+const char *macsec_offload_strings[NUM_CONFIG_MACSEC_OFFLOAD_MODES] = {
+	"off",
+	"on",
+	"mac",
+	"phy",
+	"prefer",
+};
+static int wpa_config_parse_macsec_offload(const struct parse_data *data,
+					   struct wpa_ssid *ssid, int line,
+					   const char *value)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(macsec_offload_strings); i++) {
+		if (os_strcmp(macsec_offload_strings[i], value) == 0) {
+			ssid->macsec_offload = i;
+			return 0;
+		}
+	}
+
+	wpa_printf(MSG_ERROR, "Line %d: Invalid macsec_offload: '%s'.",
+		  line, value);
+	return -1;
+}
 
 #ifndef NO_CONFIG_WRITE
 
@@ -2301,6 +2325,16 @@ static char * wpa_config_write_mka_ckn(const struct parse_data *data,
 	return wpa_config_write_string_hex(ssid->mka_ckn, ssid->mka_ckn_len);
 }
 
+static char * wpa_config_write_macsec_offload(const struct parse_data *data,
+					      struct wpa_ssid *ssid)
+{
+	const char *str = macsec_offload_strings[ssid->macsec_offload];
+
+	if (ssid->macsec_offload >= ARRAY_SIZE(macsec_offload_strings))
+		return NULL;
+	return wpa_config_write_string_ascii((const u8 *)str, strlen(str));
+}
+
 #endif /* NO_CONFIG_WRITE */
 
 #endif /* CONFIG_MACSEC */
@@ -2694,7 +2728,7 @@ static const struct parse_data ssid_fields[] = {
 	{ INT_RANGE(macsec_integ_only, 0, 1) },
 	{ INT_RANGE(macsec_replay_protect, 0, 1) },
 	{ INT(macsec_replay_window) },
-	{ INT_RANGE(macsec_offload, 0, 2) },
+	{ FUNC_KEY(macsec_offload) },
 	{ INT_RANGE(macsec_port, 1, 65534) },
 	{ INT_RANGE(mka_priority, 0, 255) },
 	{ INT_RANGE(macsec_csindex, 0, 1) },
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 4db85f9c07e1..80e40e47c97e 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -663,6 +663,12 @@ static void write_mka_ckn(FILE *f, struct wpa_ssid *ssid)
 	os_free(value);
 }
 
+static void write_macsec_offload(FILE *f, struct wpa_ssid *ssid)
+{
+	if (ssid->macsec_offload < ARRAY_SIZE(macsec_offload_strings))
+		fprintf(f, "\tmacsecoffload=%s\n", macsec_offload_strings[ssid->macsec_offload]);
+}
+
 #endif /* CONFIG_MACSEC */
 
 
@@ -814,7 +820,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
 	INT(macsec_integ_only);
 	INT(macsec_replay_protect);
 	INT(macsec_replay_window);
-	INT(macsec_offload);
+	write_macsec_offload(f, ssid);
 	INT(macsec_port);
 	INT_DEF(mka_priority, DEFAULT_PRIO_NOT_KEY_SERVER);
 	INT(macsec_csindex);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index ff045380ec96..c9d0ea195eed 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -934,9 +934,7 @@ struct wpa_ssid {
 	 * This setting applies only when MACsec is in use, i.e.,
 	 *  - the key server has decided to enable MACsec
 	 *
-	 * 0 = MACSEC_OFFLOAD_OFF (default)
-	 * 1 = MACSEC_OFFLOAD_PHY
-	 * 2 = MACSEC_OFFLOAD_MAC
+	 * Values: macsec_offload_modes
 	 */
 	int macsec_offload;
 
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 743f2a323e0e..74a6002cc01b 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -1150,13 +1150,13 @@ fast_reauth=1
 # 1..2^32-1: number of packets that could be misordered
 #
 # macsec_offload - Enable MACsec hardware offload
-#
 # This setting applies only when MACsec is in use, i.e.,
 #  - the key server has decided to enable MACsec
-#
-# 0 = MACSEC_OFFLOAD_OFF (default)
-# 1 = MACSEC_OFFLOAD_PHY
-# 2 = MACSEC_OFFLOAD_MAC
+# off = don't offload (default)
+# mac = request offload to the MAC
+# phy = request offload to the PHY
+# on = request offload (to either MAC or PHY)
+# prefer = try to offload (to either MAC or PHY), fall back to software
 #
 # macsec_port: IEEE 802.1X/MACsec port
 # Port component of the SCI
-- 
2.43.0




More information about the Hostap mailing list