diff options
author | Michael Brown <mcb30@ipxe.org> | 2023-11-07 11:08:33 +0000 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2023-11-07 13:31:20 +0000 |
commit | 1bd01b761f1f33723f0b07d277863b3284dfe232 (patch) | |
tree | 65e1a4a066e38d039a39a3853b5597a2b3e91949 /src/net | |
parent | 5524bb98328dd1b16037916498b0f91e0200a87c (diff) | |
download | ipxe-1bd01b761f1f33723f0b07d277863b3284dfe232.zip ipxe-1bd01b761f1f33723f0b07d277863b3284dfe232.tar.gz ipxe-1bd01b761f1f33723f0b07d277863b3284dfe232.tar.bz2 |
[eapol] Delay EAPoL-Start while waiting for EAP to complete
EAP exchanges may take a long time to reach a final status, especially
when relying upon MAC Authentication Bypass (MAB). Our current
behaviour of sending EAPoL-Start every few seconds until a final
status is obtained can prevent these exchanges from ever completing.
Fix by redefining the EAP supplicant state to allow EAPoL-Start to be
suppressed: either temporarily (while waiting for a full EAP exchange
to complete, in which case we need to eventually resend EAPoL-Start if
the final Success or Failure packet is lost), or permanently (while
waiting for the potentially very long MAC Authentication Bypass
timeout period).
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/net')
-rw-r--r-- | src/net/eap.c | 15 | ||||
-rw-r--r-- | src/net/eapol.c | 72 |
2 files changed, 46 insertions, 41 deletions
diff --git a/src/net/eap.c b/src/net/eap.c index beaeb61..2c68b75 100644 --- a/src/net/eap.c +++ b/src/net/eap.c @@ -47,6 +47,14 @@ static int eap_rx_request_identity ( struct eap_supplicant *supplicant ) { netdev->name ); netdev_link_block ( netdev, EAP_BLOCK_TIMEOUT ); + /* Mark EAP as in progress */ + supplicant->flags |= EAP_FL_ONGOING; + + /* We have no identity to offer, so wait until the switch + * times out and switches to MAC Authentication Bypass (MAB). + */ + supplicant->flags |= EAP_FL_PASSIVE; + return 0; } @@ -69,9 +77,6 @@ static int eap_rx_request ( struct eap_supplicant *supplicant, return -EINVAL; } - /* Mark authentication as incomplete */ - supplicant->done = 0; - /* Handle according to type */ switch ( req->type ) { case EAP_TYPE_IDENTITY: @@ -94,7 +99,7 @@ static int eap_rx_success ( struct eap_supplicant *supplicant ) { struct net_device *netdev = supplicant->netdev; /* Mark authentication as complete */ - supplicant->done = 1; + supplicant->flags = EAP_FL_PASSIVE; /* Mark link as unblocked */ DBGC ( netdev, "EAP %s Success\n", netdev->name ); @@ -113,7 +118,7 @@ static int eap_rx_failure ( struct eap_supplicant *supplicant ) { struct net_device *netdev = supplicant->netdev; /* Mark authentication as complete */ - supplicant->done = 1; + supplicant->flags = EAP_FL_PASSIVE; /* Record error */ DBGC ( netdev, "EAP %s Failure\n", netdev->name ); diff --git a/src/net/eapol.c b/src/net/eapol.c index 1b843e8..ce7be55 100644 --- a/src/net/eapol.c +++ b/src/net/eapol.c @@ -49,37 +49,6 @@ 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 @@ -186,8 +155,19 @@ static int eapol_eap_rx ( struct eapol_supplicant *supplicant, goto drop; } - /* Update supplicant state */ - eapol_update ( supplicant, EAPOL_START_INTERVAL ); + /* Update EAPoL-Start transmission timer */ + if ( supplicant->eap.flags & EAP_FL_PASSIVE ) { + /* Stop sending EAPoL-Start */ + if ( timer_running ( &supplicant->timer ) ) { + DBGC ( netdev, "EAPOL %s becoming passive\n", + netdev->name ); + } + stop_timer ( &supplicant->timer ); + } else if ( supplicant->eap.flags & EAP_FL_ONGOING ) { + /* Delay EAPoL-Start until after next expected packet */ + DBGC ( netdev, "EAPOL %s deferring Start\n", netdev->name ); + start_timer_fixed ( &supplicant->timer, EAP_WAIT_TIMEOUT ); + } drop: free_iob ( iobuf ); @@ -309,15 +289,35 @@ static int eapol_probe ( struct net_device *netdev, void *priv ) { * @v netdev Network device * @v priv Private data */ -static void eapol_notify ( struct net_device *netdev __unused, void *priv ) { +static void eapol_notify ( struct net_device *netdev, void *priv ) { struct eapol_supplicant *supplicant = priv; /* Ignore non-EAPoL devices */ if ( ! supplicant->eap.netdev ) return; - /* Update supplicant state */ - eapol_update ( supplicant, 0 ); + /* Terminate and reset EAP when link goes down */ + if ( ! ( netdev_is_open ( netdev ) && netdev_link_ok ( netdev ) ) ) { + if ( timer_running ( &supplicant->timer ) ) { + DBGC ( netdev, "EAPOL %s shutting down\n", + netdev->name ); + } + supplicant->eap.flags = 0; + stop_timer ( &supplicant->timer ); + return; + } + + /* Do nothing if EAP is already in progress */ + if ( timer_running ( &supplicant->timer ) ) + return; + + /* Do nothing if EAP has already finished transmitting */ + if ( supplicant->eap.flags & EAP_FL_PASSIVE ) + return; + + /* Otherwise, start sending EAPoL-Start */ + start_timer_nodelay ( &supplicant->timer ); + DBGC ( netdev, "EAPOL %s starting up\n", netdev->name ); } /** EAPoL driver */ |