Skip to content

Commit 8b14652

Browse files
committedSep 19, 2023
[eapol] Send EAPoL-Start packets to trigger EAP authentication
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>
1 parent 56cc61a commit 8b14652

File tree

2 files changed

+81
-0
lines changed

2 files changed

+81
-0
lines changed
 

‎src/include/ipxe/eapol.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,23 @@ struct eapol_header {
3030
/** EAPoL-encapsulated EAP packets */
3131
#define EAPOL_TYPE_EAP 0
3232

33+
/** EAPoL start */
34+
#define EAPOL_TYPE_START 1
35+
3336
/** EAPoL key */
3437
#define EAPOL_TYPE_KEY 5
3538

3639
/** An EAPoL supplicant */
3740
struct eapol_supplicant {
3841
/** EAP supplicant */
3942
struct eap_supplicant eap;
43+
/** EAPoL-Start retransmission timer */
44+
struct retry_timer timer;
4045
};
4146

47+
/** Delay between EAPoL-Start packets */
48+
#define EAPOL_START_INTERVAL ( 2 * TICKS_PER_SEC )
49+
4250
/** An EAPoL handler */
4351
struct eapol_handler {
4452
/** Type */

‎src/net/eapol.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
3131
#include <ipxe/if_arp.h>
3232
#include <ipxe/netdevice.h>
3333
#include <ipxe/vlan.h>
34+
#include <ipxe/retry.h>
3435
#include <ipxe/eap.h>
3536
#include <ipxe/eapol.h>
3637

@@ -47,6 +48,37 @@ static const uint8_t eapol_mac[ETH_ALEN] = {
4748
0x01, 0x80, 0xc2, 0x00, 0x00, 0x03
4849
};
4950

51+
/**
52+
* Update EAPoL supplicant state
53+
*
54+
* @v supplicant EAPoL supplicant
55+
* @v timeout Timer ticks until next EAPoL-Start (if applicable)
56+
*/
57+
static void eapol_update ( struct eapol_supplicant *supplicant,
58+
unsigned long timeout ) {
59+
struct net_device *netdev = supplicant->eap.netdev;
60+
61+
/* Check device and EAP state */
62+
if ( netdev_is_open ( netdev ) && netdev_link_ok ( netdev ) ) {
63+
if ( supplicant->eap.done ) {
64+
65+
/* EAP has completed: stop sending EAPoL-Start */
66+
stop_timer ( &supplicant->timer );
67+
68+
} else if ( ! timer_running ( &supplicant->timer ) ) {
69+
70+
/* EAP has not yet begun: start sending EAPoL-Start */
71+
start_timer_fixed ( &supplicant->timer, timeout );
72+
}
73+
74+
} else {
75+
76+
/* Not ready: clear completion and stop sending EAPoL-Start */
77+
supplicant->eap.done = 0;
78+
stop_timer ( &supplicant->timer );
79+
}
80+
}
81+
5082
/**
5183
* Process EAPoL packet
5284
*
@@ -154,6 +186,9 @@ static int eapol_eap_rx ( struct eapol_supplicant *supplicant,
154186
goto drop;
155187
}
156188

189+
/* Update supplicant state */
190+
eapol_update ( supplicant, EAPOL_START_INTERVAL );
191+
157192
drop:
158193
free_iob ( iobuf );
159194
return rc;
@@ -224,6 +259,25 @@ static int eapol_eap_tx ( struct eap_supplicant *eap, const void *data,
224259
return eapol_tx ( supplicant, EAPOL_TYPE_EAP, data, len );
225260
}
226261

262+
/**
263+
* (Re)transmit EAPoL-Start packet
264+
*
265+
* @v timer EAPoL-Start timer
266+
* @v expired Failure indicator
267+
*/
268+
static void eapol_expired ( struct retry_timer *timer, int fail __unused ) {
269+
struct eapol_supplicant *supplicant =
270+
container_of ( timer, struct eapol_supplicant, timer );
271+
struct net_device *netdev = supplicant->eap.netdev;
272+
273+
/* Schedule next transmission */
274+
start_timer_fixed ( timer, EAPOL_START_INTERVAL );
275+
276+
/* Transmit EAPoL-Start, ignoring errors */
277+
DBGC2 ( netdev, "EAPOL %s transmitting Start\n", netdev->name );
278+
eapol_tx ( supplicant, EAPOL_TYPE_START, NULL, 0 );
279+
}
280+
227281
/**
228282
* Create EAPoL supplicant
229283
*
@@ -244,13 +298,32 @@ static int eapol_probe ( struct net_device *netdev, void *priv ) {
244298
/* Initialise structure */
245299
supplicant->eap.netdev = netdev;
246300
supplicant->eap.tx = eapol_eap_tx;
301+
timer_init ( &supplicant->timer, eapol_expired, &netdev->refcnt );
247302

248303
return 0;
249304
}
250305

306+
/**
307+
* Handle EAPoL supplicant state change
308+
*
309+
* @v netdev Network device
310+
* @v priv Private data
311+
*/
312+
static void eapol_notify ( struct net_device *netdev __unused, void *priv ) {
313+
struct eapol_supplicant *supplicant = priv;
314+
315+
/* Ignore non-EAPoL devices */
316+
if ( ! supplicant->eap.netdev )
317+
return;
318+
319+
/* Update supplicant state */
320+
eapol_update ( supplicant, 0 );
321+
}
322+
251323
/** EAPoL driver */
252324
struct net_driver eapol_driver __net_driver = {
253325
.name = "EAPoL",
254326
.priv_len = sizeof ( struct eapol_supplicant ),
255327
.probe = eapol_probe,
328+
.notify = eapol_notify,
256329
};

0 commit comments

Comments
 (0)