iPXE
eapol.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2021 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_SECBOOT ( PERMITTED );
26
27#include <string.h>
28#include <assert.h>
29#include <errno.h>
30#include <byteswap.h>
31#include <ipxe/iobuf.h>
32#include <ipxe/if_ether.h>
33#include <ipxe/if_arp.h>
34#include <ipxe/netdevice.h>
35#include <ipxe/vlan.h>
36#include <ipxe/retry.h>
37#include <ipxe/eap.h>
38#include <ipxe/eapol.h>
39
40/** @file
41 *
42 * Extensible Authentication Protocol over LAN (EAPoL)
43 *
44 */
45
46struct net_driver eapol_driver __net_driver;
47
48/** EAPoL destination MAC address */
49static const uint8_t eapol_mac[ETH_ALEN] = {
50 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03
51};
52
53/**
54 * Process EAPoL packet
55 *
56 * @v iobuf I/O buffer
57 * @v netdev Network device
58 * @v ll_dest Link-layer destination address
59 * @v ll_source Link-layer source address
60 * @v flags Packet flags
61 * @ret rc Return status code
62 */
63static int eapol_rx ( struct io_buffer *iobuf, struct net_device *netdev,
64 const void *ll_dest __unused, const void *ll_source,
65 unsigned int flags __unused ) {
66 struct eapol_supplicant *supplicant;
67 struct eapol_header *eapol;
68 struct eapol_handler *handler;
69 size_t remaining;
70 size_t len;
71 int rc;
72
73 /* Find matching supplicant */
74 supplicant = netdev_priv ( netdev, &eapol_driver );
75
76 /* Ignore non-EAPoL devices */
77 if ( ! supplicant->eap.netdev ) {
78 DBGC ( netdev, "EAPOL %s is not an EAPoL device\n",
79 netdev->name );
80 DBGC_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) );
81 rc = -ENOTTY;
82 goto drop;
83 }
84
85 /* Sanity checks */
86 if ( iob_len ( iobuf ) < sizeof ( *eapol ) ) {
87 DBGC ( netdev, "EAPOL %s underlength header:\n",
88 netdev->name );
89 DBGC_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) );
90 rc = -EINVAL;
91 goto drop;
92 }
93 eapol = iobuf->data;
94 remaining = ( iob_len ( iobuf ) - sizeof ( *eapol ) );
95 len = ntohs ( eapol->len );
96 if ( len > remaining ) {
97 DBGC ( netdev, "EAPOL %s v%d type %d len %zd underlength "
98 "payload:\n", netdev->name, eapol->version,
99 eapol->type, len );
100 DBGC_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) );
101 rc = -EINVAL;
102 goto drop;
103 }
104
105 /* Strip any trailing padding */
106 iob_unput ( iobuf, ( len - remaining ) );
107
108 /* Handle according to type */
110 if ( handler->type == eapol->type ) {
111 return handler->rx ( supplicant, iob_disown ( iobuf ),
112 ll_source );
113 }
114 }
115 rc = -ENOTSUP;
116 DBGC ( netdev, "EAPOL %s v%d type %d unsupported\n",
117 netdev->name, eapol->version, eapol->type );
118 DBGC_HDA ( netdev, 0, iobuf->data, iob_len ( iobuf ) );
119
120 drop:
121 free_iob ( iobuf );
122 return rc;
123}
124
125/** EAPoL protocol */
126struct net_protocol eapol_protocol __net_protocol = {
127 .name = "EAPOL",
128 .net_proto = htons ( ETH_P_EAPOL ),
129 .rx = eapol_rx,
130};
131
132/**
133 * Process EAPoL-encapsulated EAP packet
134 *
135 * @v supplicant EAPoL supplicant
136 * @v ll_source Link-layer source address
137 * @ret rc Return status code
138 */
139static int eapol_eap_rx ( struct eapol_supplicant *supplicant,
140 struct io_buffer *iobuf,
141 const void *ll_source __unused ) {
142 struct net_device *netdev = supplicant->eap.netdev;
143 struct eapol_header *eapol;
144 int rc;
145
146 /* Sanity check */
147 assert ( iob_len ( iobuf ) >= sizeof ( *eapol ) );
148
149 /* Strip EAPoL header */
150 eapol = iob_pull ( iobuf, sizeof ( *eapol ) );
151
152 /* Process EAP packet */
153 if ( ( rc = eap_rx ( &supplicant->eap, iobuf->data,
154 iob_len ( iobuf ) ) ) != 0 ) {
155 DBGC ( netdev, "EAPOL %s v%d EAP failed: %s\n",
156 netdev->name, eapol->version, strerror ( rc ) );
157 goto drop;
158 }
159
160 /* Update EAPoL-Start transmission timer */
161 if ( supplicant->eap.flags & EAP_FL_PASSIVE ) {
162 /* Stop sending EAPoL-Start */
163 if ( timer_running ( &supplicant->timer ) ) {
164 DBGC ( netdev, "EAPOL %s becoming passive\n",
165 netdev->name );
166 }
167 stop_timer ( &supplicant->timer );
168 } else if ( supplicant->eap.flags & EAP_FL_ONGOING ) {
169 /* Delay EAPoL-Start until after next expected packet */
170 DBGC ( netdev, "EAPOL %s deferring Start\n", netdev->name );
171 start_timer_fixed ( &supplicant->timer, EAP_WAIT_TIMEOUT );
172 supplicant->count = 0;
173 }
174
175 drop:
176 free_iob ( iobuf );
177 return rc;
178}
179
180/** EAPoL handler for EAP packets */
181struct eapol_handler eapol_eap __eapol_handler = {
182 .type = EAPOL_TYPE_EAP,
183 .rx = eapol_eap_rx,
184};
185
186/**
187 * Transmit EAPoL packet
188 *
189 * @v supplicant EAPoL supplicant
190 * @v type Packet type
191 * @v data Packet body
192 * @v len Length of packet body
193 * @ret rc Return status code
194 */
195static int eapol_tx ( struct eapol_supplicant *supplicant, unsigned int type,
196 const void *data, size_t len ) {
197 struct net_device *netdev = supplicant->eap.netdev;
198 struct io_buffer *iobuf;
199 struct eapol_header *eapol;
200 int rc;
201
202 /* Allocate I/O buffer */
203 iobuf = alloc_iob ( MAX_LL_HEADER_LEN + sizeof ( *eapol ) + len );
204 if ( ! iobuf )
205 return -ENOMEM;
207
208 /* Construct EAPoL header */
209 eapol = iob_put ( iobuf, sizeof ( *eapol ) );
211 eapol->type = type;
212 eapol->len = htons ( len );
213
214 /* Append packet body */
215 memcpy ( iob_put ( iobuf, len ), data, len );
216
217 /* Transmit packet */
218 if ( ( rc = net_tx ( iob_disown ( iobuf ), netdev, &eapol_protocol,
219 &eapol_mac, netdev->ll_addr ) ) != 0 ) {
220 DBGC ( netdev, "EAPOL %s could not transmit type %d: %s\n",
221 netdev->name, type, strerror ( rc ) );
222 DBGC_HDA ( netdev, 0, data, len );
223 return rc;
224 }
225
226 return 0;
227}
228
229/**
230 * Transmit EAPoL-encapsulated EAP packet
231 *
232 * @v supplicant EAPoL supplicant
233 * @v ll_source Link-layer source address
234 * @ret rc Return status code
235 */
236static int eapol_eap_tx ( struct eap_supplicant *eap, const void *data,
237 size_t len ) {
238 struct eapol_supplicant *supplicant =
240
241 /* Transmit encapsulated packet */
242 return eapol_tx ( supplicant, EAPOL_TYPE_EAP, data, len );
243}
244
245/**
246 * (Re)transmit EAPoL-Start packet
247 *
248 * @v timer EAPoL-Start timer
249 * @v expired Failure indicator
250 */
251static void eapol_expired ( struct retry_timer *timer, int fail __unused ) {
252 struct eapol_supplicant *supplicant =
254 struct net_device *netdev = supplicant->eap.netdev;
255
256 /* Stop transmitting after maximum number of attempts */
257 if ( supplicant->count++ >= EAPOL_START_COUNT ) {
258 DBGC ( netdev, "EAPOL %s giving up\n", netdev->name );
259 return;
260 }
261
262 /* Schedule next transmission */
264
265 /* Transmit EAPoL-Start, ignoring errors */
266 DBGC2 ( netdev, "EAPOL %s transmitting Start\n", netdev->name );
267 eapol_tx ( supplicant, EAPOL_TYPE_START, NULL, 0 );
268}
269
270/**
271 * Create EAPoL supplicant
272 *
273 * @v netdev Network device
274 * @v priv Private data
275 * @ret rc Return status code
276 */
277static int eapol_probe ( struct net_device *netdev, void *priv ) {
278 struct eapol_supplicant *supplicant = priv;
279 struct ll_protocol *ll_protocol = netdev->ll_protocol;
280
281 /* Ignore non-EAPoL devices */
283 return 0;
284 if ( vlan_tag ( netdev ) )
285 return 0;
286
287 /* Initialise structure */
288 supplicant->eap.netdev = netdev;
289 supplicant->eap.tx = eapol_eap_tx;
290 timer_init ( &supplicant->timer, eapol_expired, &netdev->refcnt );
291
292 return 0;
293}
294
295/**
296 * Handle EAPoL supplicant state change
297 *
298 * @v netdev Network device
299 * @v priv Private data
300 */
301static void eapol_notify ( struct net_device *netdev, void *priv ) {
302 struct eapol_supplicant *supplicant = priv;
303
304 /* Ignore non-EAPoL devices */
305 if ( ! supplicant->eap.netdev )
306 return;
307
308 /* Terminate and reset EAP when link goes down */
309 if ( ! ( netdev_is_open ( netdev ) && netdev_link_ok ( netdev ) ) ) {
310 if ( timer_running ( &supplicant->timer ) ) {
311 DBGC ( netdev, "EAPOL %s shutting down\n",
312 netdev->name );
313 }
314 supplicant->eap.flags = 0;
315 stop_timer ( &supplicant->timer );
316 return;
317 }
318
319 /* Do nothing if EAP is already in progress */
320 if ( timer_running ( &supplicant->timer ) )
321 return;
322
323 /* Do nothing if EAP has already finished transmitting */
324 if ( supplicant->eap.flags & EAP_FL_PASSIVE )
325 return;
326
327 /* Otherwise, start sending EAPoL-Start */
328 start_timer_nodelay ( &supplicant->timer );
329 supplicant->count = 0;
330 DBGC ( netdev, "EAPOL %s starting up\n", netdev->name );
331}
332
333/** EAPoL driver */
334struct net_driver eapol_driver __net_driver = {
335 .name = "EAPoL",
336 .priv_len = sizeof ( struct eapol_supplicant ),
337 .probe = eapol_probe,
338 .notify = eapol_notify,
339};
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned char uint8_t
Definition stdint.h:10
Assertions.
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
ring len
Length.
Definition dwmac.h:226
int eap_rx(struct eap_supplicant *supplicant, const void *data, size_t len)
Handle EAP packet.
Definition eap.c:264
Extensible Authentication Protocol.
#define EAP_WAIT_TIMEOUT
EAP protocol wait timeout.
Definition eap.h:136
#define EAP_FL_ONGOING
EAP authentication is in progress.
Definition eap.h:165
#define EAP_FL_PASSIVE
EAP supplicant is passive.
Definition eap.h:175
static int eapol_probe(struct net_device *netdev, void *priv)
Create EAPoL supplicant.
Definition eapol.c:277
static const uint8_t eapol_mac[ETH_ALEN]
EAPoL destination MAC address.
Definition eapol.c:49
static int eapol_rx(struct io_buffer *iobuf, struct net_device *netdev, const void *ll_dest __unused, const void *ll_source, unsigned int flags __unused)
Process EAPoL packet.
Definition eapol.c:63
static void eapol_expired(struct retry_timer *timer, int fail __unused)
(Re)transmit EAPoL-Start packet
Definition eapol.c:251
static int eapol_eap_tx(struct eap_supplicant *eap, const void *data, size_t len)
Transmit EAPoL-encapsulated EAP packet.
Definition eapol.c:236
static int eapol_eap_rx(struct eapol_supplicant *supplicant, struct io_buffer *iobuf, const void *ll_source __unused)
Process EAPoL-encapsulated EAP packet.
Definition eapol.c:139
static int eapol_tx(struct eapol_supplicant *supplicant, unsigned int type, const void *data, size_t len)
Transmit EAPoL packet.
Definition eapol.c:195
static void eapol_notify(struct net_device *netdev, void *priv)
Handle EAPoL supplicant state change.
Definition eapol.c:301
Extensible Authentication Protocol over LAN (EAPoL)
#define EAPOL_START_INTERVAL
Delay between EAPoL-Start packets.
Definition eapol.h:51
#define EAPOL_TYPE_START
EAPoL start.
Definition eapol.h:35
#define __eapol_handler
Declare an EAPoL handler.
Definition eapol.h:78
#define EAPOL_VERSION_2001
802.1X-2001
Definition eapol.h:29
#define EAPOL_TYPE_EAP
EAPoL-encapsulated EAP packets.
Definition eapol.h:32
#define EAPOL_HANDLERS
EAPoL handler table.
Definition eapol.h:75
#define EAPOL_START_COUNT
Maximum number of EAPoL-Start packets to transmit.
Definition eapol.h:54
uint32_t type
Operating system type.
Definition ena.h:1
uint8_t data[48]
Additional event data.
Definition ena.h:11
uint8_t flags
Flags.
Definition ena.h:7
Error codes.
static struct net_device * netdev
Definition gdbudp.c:53
#define __unused
Declare a variable or data structure as unused.
Definition compiler.h:573
#define DBGC2(...)
Definition compiler.h:522
#define DBGC(...)
Definition compiler.h:505
#define DBGC_HDA(...)
Definition compiler.h:506
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define EINVAL
Invalid argument.
Definition errno.h:429
#define ENOMEM
Not enough space.
Definition errno.h:535
#define ENOTSUP
Operation not supported.
Definition errno.h:590
#define ENOTTY
Inappropriate I/O control operation.
Definition errno.h:595
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
Address Resolution Protocol constants and types.
#define ARPHRD_ETHER
Ethernet 10Mbps.
Definition if_arp.h:17
#define ETH_ALEN
Definition if_ether.h:9
#define ETH_P_EAPOL
Definition if_ether.h:25
#define htons(value)
Definition byteswap.h:136
#define ntohs(value)
Definition byteswap.h:137
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition iobuf.c:153
struct io_buffer * alloc_iob(size_t len)
Allocate I/O buffer.
Definition iobuf.c:131
I/O buffers.
#define iob_put(iobuf, len)
Definition iobuf.h:125
#define iob_disown(iobuf)
Disown an I/O buffer.
Definition iobuf.h:217
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition iobuf.h:160
#define iob_reserve(iobuf, len)
Definition iobuf.h:72
#define iob_pull(iobuf, len)
Definition iobuf.h:107
#define iob_unput(iobuf, len)
Definition iobuf.h:140
int net_tx(struct io_buffer *iobuf, struct net_device *netdev, struct net_protocol *net_protocol, const void *ll_dest, const void *ll_source)
Transmit network-layer packet.
Definition netdevice.c:1074
void * netdev_priv(struct net_device *netdev, struct net_driver *driver)
Get network device driver private data.
Definition netdevice.c:153
Network device management.
static int netdev_is_open(struct net_device *netdev)
Check whether or not network device is open.
Definition netdevice.h:662
static int netdev_link_ok(struct net_device *netdev)
Check link state of network device.
Definition netdevice.h:640
#define __net_driver
Declare a network driver.
Definition netdevice.h:507
#define MAX_LL_HEADER_LEN
Maximum length of a link-layer header.
Definition netdevice.h:46
#define __net_protocol
Declare a network-layer protocol.
Definition netdevice.h:474
void start_timer_fixed(struct retry_timer *timer, unsigned long timeout)
Start timer with a specified timeout.
Definition retry.c:65
void stop_timer(struct retry_timer *timer)
Stop timer.
Definition retry.c:118
Retry timers.
static void start_timer_nodelay(struct retry_timer *timer)
Start timer with no delay.
Definition retry.h:100
#define container_of(ptr, type, field)
Get containing structure.
Definition stddef.h:36
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
An EAP supplicant.
Definition eap.h:139
uint16_t flags
Flags.
Definition eap.h:143
struct net_device * netdev
Network device.
Definition eap.h:141
int(* tx)(struct eap_supplicant *supplicant, const void *data, size_t len)
Transmit EAP response.
Definition eap.h:156
An EAPoL handler.
Definition eapol.h:57
int(* rx)(struct eapol_supplicant *supplicant, struct io_buffer *iobuf, const void *ll_source)
Process received packet.
Definition eapol.h:70
uint8_t type
Type.
Definition eapol.h:59
EAPoL header.
Definition eapol.h:19
uint8_t version
Version.
Definition eapol.h:21
uint8_t type
Type.
Definition eapol.h:23
uint16_t len
Payload length.
Definition eapol.h:25
An EAPoL supplicant.
Definition eapol.h:41
unsigned int count
EAPoL-Start transmission count.
Definition eapol.h:47
struct eap_supplicant eap
EAP supplicant.
Definition eapol.h:43
struct retry_timer timer
EAPoL-Start retransmission timer.
Definition eapol.h:45
A persistent I/O buffer.
Definition iobuf.h:38
void * data
Start of data.
Definition iobuf.h:53
A link-layer protocol.
Definition netdevice.h:115
uint16_t ll_proto
Link-layer protocol.
Definition netdevice.h:195
A network device.
Definition netdevice.h:353
A network upper-layer driver.
Definition netdevice.h:477
A network-layer protocol.
Definition netdevice.h:65
A retry timer.
Definition retry.h:22
A timer.
Definition timer.h:29
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition tables.h:386
static struct tlan_private * priv
Definition tlan.c:225
Virtual LANs.
static unsigned int vlan_tag(struct net_device *netdev)
Get the VLAN tag.
Definition vlan.h:74