aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2023-09-15 16:14:59 +0100
committerMichael Brown <mcb30@ipxe.org>2023-09-15 16:24:19 +0100
commit6447c7b92cfb582d8d8a1dad7e978a3319e71ab4 (patch)
tree1270b52e2b703cdfd4b68341ad092f3ed9e62785
parent83c96d217497fcef277682d7e1e6ac6ec9b919fa (diff)
downloadipxe-supplicant.zip
ipxe-supplicant.tar.gz
ipxe-supplicant.tar.bz2
[eapol] Send EAPoL-Start packets to trigger EAP authenticationsupplicant
We have no way to force a link-layer restart in iPXE, and therefore no way to explicitly trigger a restart of EAP authentication. If an iPXE script has performed some action that requires such a restart (e.g. registering a device such that the port VLAN assignment will be changed), then the only means currently available to effect the restart is to reboot the whole system. If iPXE is taking over a physical link already used by a preceding bootloader, then even a reboot may not work. In the EAP model, the supplicant is a pure responder and never initiates transmissions. EAPoL extends this to include an EAPoL-Start packet type that may be sent by the supplicant to (re)trigger EAP. Add support for sending EAPoL-Start packets at two-second intervals on links that are open and have reached physical link-up, but for which EAP has not yet completed. This allows "ifclose ; ifopen" to be used to restart the EAP process. Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r--src/include/ipxe/eapol.h8
-rw-r--r--src/net/eapol.c67
2 files changed, 75 insertions, 0 deletions
diff --git a/src/include/ipxe/eapol.h b/src/include/ipxe/eapol.h
index f6009a2..d4ea392 100644
--- a/src/include/ipxe/eapol.h
+++ b/src/include/ipxe/eapol.h
@@ -30,6 +30,9 @@ struct eapol_header {
/** EAPoL-encapsulated EAP packets */
#define EAPOL_TYPE_EAP 0
+/** EAPoL start */
+#define EAPOL_TYPE_START 1
+
/** EAPoL key */
#define EAPOL_TYPE_KEY 5
@@ -37,8 +40,13 @@ struct eapol_header {
struct eapol_supplicant {
/** EAP supplicant */
struct eap_supplicant eap;
+ /** EAPoL-Start retransmission timer */
+ struct retry_timer timer;
};
+/** Delay between EAPoL-Start packets */
+#define EAPOL_START_INTERVAL ( 2 * TICKS_PER_SEC )
+
/** An EAPoL handler */
struct eapol_handler {
/** Type */
diff --git a/src/net/eapol.c b/src/net/eapol.c
index bc629bc..9f432dd 100644
--- a/src/net/eapol.c
+++ b/src/net/eapol.c
@@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/iobuf.h>
#include <ipxe/if_ether.h>
#include <ipxe/netdevice.h>
+#include <ipxe/retry.h>
#include <ipxe/eap.h>
#include <ipxe/eapol.h>
@@ -46,6 +47,37 @@ static const uint8_t eapol_mac[ETH_ALEN] = {
};
/**
+ * Update EAPoL supplicant state
+ *
+ * @v supplicant EAPoL supplicant
+ * @v timeout Timer ticks until next EAPoL-Start (if applicable)
+ */
+static void eapol_update ( struct eapol_supplicant *supplicant,
+ unsigned long timeout ) {
+ struct net_device *netdev = supplicant->eap.netdev;
+
+ /* Check device and EAP state */
+ if ( netdev_is_open ( netdev ) && netdev_link_ok ( netdev ) ) {
+ if ( supplicant->eap.done ) {
+
+ /* EAP has completed: stop sending EAPoL-Start */
+ stop_timer ( &supplicant->timer );
+
+ } else if ( ! timer_running ( &supplicant->timer ) ) {
+
+ /* EAP has not yet begun: start sending EAPoL-Start */
+ start_timer_fixed ( &supplicant->timer, timeout );
+ }
+
+ } else {
+
+ /* Not ready: clear completion and stop sending EAPoL-Start */
+ supplicant->eap.done = 0;
+ stop_timer ( &supplicant->timer );
+ }
+}
+
+/**
* Process EAPoL packet
*
* @v iobuf I/O buffer
@@ -143,6 +175,9 @@ static int eapol_eap_rx ( struct eapol_supplicant *supplicant,
goto drop;
}
+ /* Update supplicant state */
+ eapol_update ( supplicant, EAPOL_START_INTERVAL );
+
drop:
free_iob ( iobuf );
return rc;
@@ -214,6 +249,23 @@ static int eapol_eap_tx ( struct eap_supplicant *eap, const void *data,
}
/**
+ * (Re)transmit EAPoL-Start packet
+ *
+ * @v timer EAPoL-Start timer
+ * @v expired Failure indicator
+ */
+static void eapol_expired ( struct retry_timer *timer, int fail __unused ) {
+ struct eapol_supplicant *supplicant =
+ container_of ( timer, struct eapol_supplicant, timer );
+
+ /* Schedule next transmission */
+ start_timer_fixed ( timer, EAPOL_START_INTERVAL );
+
+ /* Transmit EAPoL-Start, ignoring errors */
+ eapol_tx ( supplicant, EAPOL_TYPE_START, NULL, 0 );
+}
+
+/**
* Create EAPoL supplicant
*
* @v netdev Network device
@@ -226,13 +278,28 @@ static int eapol_probe ( struct net_device *netdev, void *priv ) {
/* Initialise structure */
supplicant->eap.netdev = netdev;
supplicant->eap.tx = eapol_eap_tx;
+ timer_init ( &supplicant->timer, eapol_expired, &netdev->refcnt );
return 0;
}
+/**
+ * Handle EAPoL supplicant state change
+ *
+ * @v netdev Network device
+ * @v priv Private data
+ */
+static void eapol_notify ( struct net_device *netdev __unused, void *priv ) {
+ struct eapol_supplicant *supplicant = priv;
+
+ /* Update supplicant state */
+ eapol_update ( supplicant, 0 );
+}
+
/** EAPoL driver */
struct net_driver eapol_driver __net_driver = {
.name = "EAPoL",
.priv_len = sizeof ( struct eapol_supplicant ),
.probe = eapol_probe,
+ .notify = eapol_notify,
};