diff options
Diffstat (limited to 'src/net')
-rw-r--r-- | src/net/eapol.c | 67 |
1 files changed, 67 insertions, 0 deletions
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, }; |