diff options
-rw-r--r-- | src/include/ipxe/eapol.h | 8 | ||||
-rw-r--r-- | src/net/eapol.c | 73 |
2 files changed, 81 insertions, 0 deletions
diff --git a/src/include/ipxe/eapol.h b/src/include/ipxe/eapol.h index f6009a2ff..d4ea39208 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 172037ce1..1b843e896 100644 --- a/src/net/eapol.c +++ b/src/net/eapol.c @@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/if_arp.h> #include <ipxe/netdevice.h> #include <ipxe/vlan.h> +#include <ipxe/retry.h> #include <ipxe/eap.h> #include <ipxe/eapol.h> @@ -48,6 +49,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 @@ -154,6 +186,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; @@ -225,6 +260,25 @@ 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 ); + struct net_device *netdev = supplicant->eap.netdev; + + /* Schedule next transmission */ + start_timer_fixed ( timer, EAPOL_START_INTERVAL ); + + /* Transmit EAPoL-Start, ignoring errors */ + DBGC2 ( netdev, "EAPOL %s transmitting Start\n", netdev->name ); + eapol_tx ( supplicant, EAPOL_TYPE_START, NULL, 0 ); +} + +/** * Create EAPoL supplicant * * @v netdev Network device @@ -244,13 +298,32 @@ 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; + + /* Ignore non-EAPoL devices */ + if ( ! supplicant->eap.netdev ) + return; + + /* 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, }; |