blob: 916c15999e2e7108096a3fd94a28b30fc8d4de9c [file] [log] [blame]
Tom Rini70df9d62018-05-07 17:02:21 -04001// SPDX-License-Identifier: GPL-2.0+
Alexander Graf94c4b992016-05-06 21:01:01 +02002/*
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +02003 * Simple network protocol
4 * PXE base code protocol
Alexander Graf94c4b992016-05-06 21:01:01 +02005 *
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +02006 * Copyright (c) 2016 Alexander Graf
7 *
8 * The simple network protocol has the following statuses and services
9 * to move between them:
10 *
11 * Start(): EfiSimpleNetworkStopped -> EfiSimpleNetworkStarted
12 * Initialize(): EfiSimpleNetworkStarted -> EfiSimpleNetworkInitialized
13 * Shutdown(): EfiSimpleNetworkInitialized -> EfiSimpleNetworkStarted
14 * Stop(): EfiSimpleNetworkStarted -> EfiSimpleNetworkStopped
15 * Reset(): EfiSimpleNetworkInitialized -> EfiSimpleNetworkInitialized
Alexander Graf94c4b992016-05-06 21:01:01 +020016 */
17
Alexander Graf94c4b992016-05-06 21:01:01 +020018#include <efi_loader.h>
Adriano Cordova93cba0f2024-12-04 00:05:23 -030019#include <dm.h>
Adriano Cordova0d1f5092024-12-04 00:05:24 -030020#include <linux/sizes.h>
Alexander Graf94c4b992016-05-06 21:01:01 +020021#include <malloc.h>
Adriano Cordova3c951362024-12-04 00:05:21 -030022#include <vsprintf.h>
Simon Glass274e0b02020-05-10 11:39:56 -060023#include <net.h>
Alexander Graf94c4b992016-05-06 21:01:01 +020024
Heinrich Schuchardt788ad412019-04-20 07:39:11 +020025static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
Heinrich Schuchardt3127e7e2019-08-06 08:13:33 +020026static const efi_guid_t efi_pxe_base_code_protocol_guid =
27 EFI_PXE_BASE_CODE_PROTOCOL_GUID;
Alexander Graf94c4b992016-05-06 21:01:01 +020028static struct efi_pxe_packet *dhcp_ack;
Alexander Graf94c4b992016-05-06 21:01:01 +020029static void *new_tx_packet;
Heinrich Schuchardteb07c282018-12-01 00:16:32 +010030static void *transmit_buffer;
Patrick Wildtfab89102020-10-07 11:04:33 +020031static uchar **receive_buffer;
32static size_t *receive_lengths;
33static int rx_packet_idx;
34static int rx_packet_num;
Heinrich Schuchardt2f1a93f2022-11-26 16:44:38 +010035static struct efi_net_obj *netobj;
Heinrich Schuchardteb07c282018-12-01 00:16:32 +010036
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +020037/*
Adriano Cordova93cba0f2024-12-04 00:05:23 -030038 * The current network device path. This device path is updated when a new
39 * bootfile is downloaded from the network. If then the bootfile is loaded
40 * as an efi image, net_dp is passed as the device path of the loaded image.
41 */
42static struct efi_device_path *net_dp;
43
Adriano Cordova0d1f5092024-12-04 00:05:24 -030044static struct wget_http_info efi_wget_info = {
45 .set_bootdev = false,
46 .check_buffer_size = true,
47
48};
49
Adriano Cordova93cba0f2024-12-04 00:05:23 -030050/*
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +020051 * The notification function of this event is called in every timer cycle
52 * to check if a new network packet has been received.
53 */
54static struct efi_event *network_timer_event;
Heinrich Schuchardt0c153c22017-10-05 16:36:01 +020055/*
56 * This event is signaled when a packet has been received.
57 */
58static struct efi_event *wait_for_packet;
Alexander Graf94c4b992016-05-06 21:01:01 +020059
Heinrich Schuchardt72928722018-09-26 05:27:56 +020060/**
61 * struct efi_net_obj - EFI object representing a network interface
62 *
Adriano Cordova9debc902024-12-04 00:05:25 -030063 * @header: EFI object header
64 * @net: simple network protocol interface
65 * @net_mode: status of the network interface
66 * @pxe: PXE base code protocol interface
67 * @pxe_mode: status of the PXE base code protocol
68 * @ip4_config2: IP4 Config2 protocol interface
Heinrich Schuchardt72928722018-09-26 05:27:56 +020069 */
Alexander Graf94c4b992016-05-06 21:01:01 +020070struct efi_net_obj {
Heinrich Schuchardt72928722018-09-26 05:27:56 +020071 struct efi_object header;
Alexander Graf94c4b992016-05-06 21:01:01 +020072 struct efi_simple_network net;
73 struct efi_simple_network_mode net_mode;
Heinrich Schuchardt3127e7e2019-08-06 08:13:33 +020074 struct efi_pxe_base_code_protocol pxe;
Alexander Graf94c4b992016-05-06 21:01:01 +020075 struct efi_pxe_mode pxe_mode;
Adriano Cordova9debc902024-12-04 00:05:25 -030076#if IS_ENABLED(CONFIG_EFI_IP4_CONFIG2_PROTOCOL)
77 struct efi_ip4_config2_protocol ip4_config2;
78#endif
Alexander Graf94c4b992016-05-06 21:01:01 +020079};
80
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +010081/*
82 * efi_net_start() - start the network interface
83 *
84 * This function implements the Start service of the
85 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
86 * (UEFI) specification for details.
87 *
88 * @this: pointer to the protocol instance
89 * Return: status code
90 */
Alexander Graf94c4b992016-05-06 21:01:01 +020091static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this)
92{
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +010093 efi_status_t ret = EFI_SUCCESS;
94
Alexander Graf94c4b992016-05-06 21:01:01 +020095 EFI_ENTRY("%p", this);
96
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +010097 /* Check parameters */
98 if (!this) {
99 ret = EFI_INVALID_PARAMETER;
100 goto out;
101 }
102
Heinrich Schuchardtd3f1ff22019-08-31 09:56:30 +0200103 if (this->mode->state != EFI_NETWORK_STOPPED) {
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100104 ret = EFI_ALREADY_STARTED;
Heinrich Schuchardtd3f1ff22019-08-31 09:56:30 +0200105 } else {
106 this->int_status = 0;
107 wait_for_packet->is_signaled = false;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100108 this->mode->state = EFI_NETWORK_STARTED;
Heinrich Schuchardtd3f1ff22019-08-31 09:56:30 +0200109 }
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100110out:
111 return EFI_EXIT(ret);
Alexander Graf94c4b992016-05-06 21:01:01 +0200112}
113
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100114/*
115 * efi_net_stop() - stop the network interface
116 *
117 * This function implements the Stop service of the
118 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
119 * (UEFI) specification for details.
120 *
121 * @this: pointer to the protocol instance
122 * Return: status code
123 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200124static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this)
125{
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100126 efi_status_t ret = EFI_SUCCESS;
127
Alexander Graf94c4b992016-05-06 21:01:01 +0200128 EFI_ENTRY("%p", this);
129
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100130 /* Check parameters */
131 if (!this) {
132 ret = EFI_INVALID_PARAMETER;
133 goto out;
134 }
135
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200136 if (this->mode->state == EFI_NETWORK_STOPPED) {
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100137 ret = EFI_NOT_STARTED;
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200138 } else {
139 /* Disable hardware and put it into the reset state */
140 eth_halt();
Patrick Wildtfab89102020-10-07 11:04:33 +0200141 /* Clear cache of packets */
142 rx_packet_num = 0;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100143 this->mode->state = EFI_NETWORK_STOPPED;
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200144 }
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100145out:
146 return EFI_EXIT(ret);
Alexander Graf94c4b992016-05-06 21:01:01 +0200147}
148
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200149/*
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100150 * efi_net_initialize() - initialize the network interface
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200151 *
152 * This function implements the Initialize service of the
153 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
154 * (UEFI) specification for details.
155 *
156 * @this: pointer to the protocol instance
157 * @extra_rx: extra receive buffer to be allocated
158 * @extra_tx: extra transmit buffer to be allocated
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100159 * Return: status code
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200160 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200161static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
162 ulong extra_rx, ulong extra_tx)
163{
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200164 int ret;
165 efi_status_t r = EFI_SUCCESS;
166
Alexander Graf94c4b992016-05-06 21:01:01 +0200167 EFI_ENTRY("%p, %lx, %lx", this, extra_rx, extra_tx);
168
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100169 /* Check parameters */
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200170 if (!this) {
171 r = EFI_INVALID_PARAMETER;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100172 goto out;
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200173 }
174
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200175 switch (this->mode->state) {
176 case EFI_NETWORK_INITIALIZED:
177 case EFI_NETWORK_STARTED:
178 break;
179 default:
180 r = EFI_NOT_STARTED;
181 goto out;
182 }
183
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200184 /* Setup packet buffers */
185 net_init();
186 /* Disable hardware and put it into the reset state */
187 eth_halt();
Patrick Wildtfab89102020-10-07 11:04:33 +0200188 /* Clear cache of packets */
189 rx_packet_num = 0;
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200190 /* Set current device according to environment variables */
191 eth_set_current();
192 /* Get hardware ready for send and receive operations */
193 ret = eth_init();
194 if (ret < 0) {
195 eth_halt();
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100196 this->mode->state = EFI_NETWORK_STOPPED;
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200197 r = EFI_DEVICE_ERROR;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100198 goto out;
199 } else {
Heinrich Schuchardtd3f1ff22019-08-31 09:56:30 +0200200 this->int_status = 0;
201 wait_for_packet->is_signaled = false;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100202 this->mode->state = EFI_NETWORK_INITIALIZED;
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200203 }
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100204out:
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200205 return EFI_EXIT(r);
Alexander Graf94c4b992016-05-06 21:01:01 +0200206}
207
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100208/*
209 * efi_net_reset() - reinitialize the network interface
210 *
211 * This function implements the Reset service of the
212 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
213 * (UEFI) specification for details.
214 *
215 * @this: pointer to the protocol instance
216 * @extended_verification: execute exhaustive verification
217 * Return: status code
218 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200219static efi_status_t EFIAPI efi_net_reset(struct efi_simple_network *this,
220 int extended_verification)
221{
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200222 efi_status_t ret;
223
Alexander Graf94c4b992016-05-06 21:01:01 +0200224 EFI_ENTRY("%p, %x", this, extended_verification);
225
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200226 /* Check parameters */
227 if (!this) {
228 ret = EFI_INVALID_PARAMETER;
229 goto out;
230 }
231
232 switch (this->mode->state) {
233 case EFI_NETWORK_INITIALIZED:
234 break;
235 case EFI_NETWORK_STOPPED:
236 ret = EFI_NOT_STARTED;
237 goto out;
238 default:
239 ret = EFI_DEVICE_ERROR;
240 goto out;
241 }
242
243 this->mode->state = EFI_NETWORK_STARTED;
244 ret = EFI_CALL(efi_net_initialize(this, 0, 0));
245out:
246 return EFI_EXIT(ret);
Alexander Graf94c4b992016-05-06 21:01:01 +0200247}
248
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100249/*
250 * efi_net_shutdown() - shut down the network interface
251 *
252 * This function implements the Shutdown service of the
253 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
254 * (UEFI) specification for details.
255 *
256 * @this: pointer to the protocol instance
257 * Return: status code
258 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200259static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this)
260{
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100261 efi_status_t ret = EFI_SUCCESS;
262
Alexander Graf94c4b992016-05-06 21:01:01 +0200263 EFI_ENTRY("%p", this);
264
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100265 /* Check parameters */
266 if (!this) {
267 ret = EFI_INVALID_PARAMETER;
268 goto out;
269 }
270
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200271 switch (this->mode->state) {
272 case EFI_NETWORK_INITIALIZED:
273 break;
274 case EFI_NETWORK_STOPPED:
275 ret = EFI_NOT_STARTED;
276 goto out;
277 default:
278 ret = EFI_DEVICE_ERROR;
279 goto out;
280 }
281
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100282 eth_halt();
Heinrich Schuchardtd3f1ff22019-08-31 09:56:30 +0200283 this->int_status = 0;
284 wait_for_packet->is_signaled = false;
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200285 this->mode->state = EFI_NETWORK_STARTED;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100286
287out:
288 return EFI_EXIT(ret);
Alexander Graf94c4b992016-05-06 21:01:01 +0200289}
290
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100291/*
292 * efi_net_receive_filters() - mange multicast receive filters
293 *
294 * This function implements the ReceiveFilters service of the
295 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
296 * (UEFI) specification for details.
297 *
298 * @this: pointer to the protocol instance
299 * @enable: bit mask of receive filters to enable
300 * @disable: bit mask of receive filters to disable
301 * @reset_mcast_filter: true resets contents of the filters
302 * @mcast_filter_count: number of hardware MAC addresses in the new filters list
303 * @mcast_filter: list of new filters
304 * Return: status code
305 */
306static efi_status_t EFIAPI efi_net_receive_filters
307 (struct efi_simple_network *this, u32 enable, u32 disable,
308 int reset_mcast_filter, ulong mcast_filter_count,
309 struct efi_mac_address *mcast_filter)
Alexander Graf94c4b992016-05-06 21:01:01 +0200310{
311 EFI_ENTRY("%p, %x, %x, %x, %lx, %p", this, enable, disable,
312 reset_mcast_filter, mcast_filter_count, mcast_filter);
313
Heinrich Schuchardta50b5c62017-10-05 16:35:59 +0200314 return EFI_EXIT(EFI_UNSUPPORTED);
Alexander Graf94c4b992016-05-06 21:01:01 +0200315}
316
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100317/*
318 * efi_net_station_address() - set the hardware MAC address
319 *
320 * This function implements the StationAddress service of the
321 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
322 * (UEFI) specification for details.
323 *
324 * @this: pointer to the protocol instance
325 * @reset: if true reset the address to default
326 * @new_mac: new MAC address
327 * Return: status code
328 */
329static efi_status_t EFIAPI efi_net_station_address
330 (struct efi_simple_network *this, int reset,
331 struct efi_mac_address *new_mac)
Alexander Graf94c4b992016-05-06 21:01:01 +0200332{
333 EFI_ENTRY("%p, %x, %p", this, reset, new_mac);
334
Heinrich Schuchardta50b5c62017-10-05 16:35:59 +0200335 return EFI_EXIT(EFI_UNSUPPORTED);
Alexander Graf94c4b992016-05-06 21:01:01 +0200336}
337
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100338/*
339 * efi_net_statistics() - reset or collect statistics of the network interface
340 *
341 * This function implements the Statistics service of the
342 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
343 * (UEFI) specification for details.
344 *
345 * @this: pointer to the protocol instance
346 * @reset: if true, the statistics are reset
347 * @stat_size: size of the statistics table
348 * @stat_table: table to receive the statistics
349 * Return: status code
350 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200351static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this,
352 int reset, ulong *stat_size,
353 void *stat_table)
354{
355 EFI_ENTRY("%p, %x, %p, %p", this, reset, stat_size, stat_table);
356
Heinrich Schuchardta50b5c62017-10-05 16:35:59 +0200357 return EFI_EXIT(EFI_UNSUPPORTED);
Alexander Graf94c4b992016-05-06 21:01:01 +0200358}
359
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100360/*
361 * efi_net_mcastiptomac() - translate multicast IP address to MAC address
362 *
Heinrich Schuchardt33b318d2019-09-01 17:17:53 +0200363 * This function implements the MCastIPtoMAC service of the
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100364 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
365 * (UEFI) specification for details.
366 *
367 * @this: pointer to the protocol instance
368 * @ipv6: true if the IP address is an IPv6 address
369 * @ip: IP address
370 * @mac: MAC address
371 * Return: status code
372 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200373static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this,
374 int ipv6,
375 struct efi_ip_address *ip,
376 struct efi_mac_address *mac)
377{
Heinrich Schuchardt33b318d2019-09-01 17:17:53 +0200378 efi_status_t ret = EFI_SUCCESS;
379
Alexander Graf94c4b992016-05-06 21:01:01 +0200380 EFI_ENTRY("%p, %x, %p, %p", this, ipv6, ip, mac);
381
Heinrich Schuchardt33b318d2019-09-01 17:17:53 +0200382 if (!this || !ip || !mac) {
383 ret = EFI_INVALID_PARAMETER;
384 goto out;
385 }
386
387 if (ipv6) {
388 ret = EFI_UNSUPPORTED;
389 goto out;
390 }
391
392 /* Multi-cast addresses are in the range 224.0.0.0 - 239.255.255.255 */
393 if ((ip->ip_addr[0] & 0xf0) != 0xe0) {
394 ret = EFI_INVALID_PARAMETER;
395 goto out;
396 };
397
398 switch (this->mode->state) {
399 case EFI_NETWORK_INITIALIZED:
400 case EFI_NETWORK_STARTED:
401 break;
402 default:
403 ret = EFI_NOT_STARTED;
404 goto out;
405 }
406
407 memset(mac, 0, sizeof(struct efi_mac_address));
408
409 /*
410 * Copy lower 23 bits of IPv4 multi-cast address
411 * RFC 1112, RFC 7042 2.1.1.
412 */
413 mac->mac_addr[0] = 0x01;
414 mac->mac_addr[1] = 0x00;
415 mac->mac_addr[2] = 0x5E;
416 mac->mac_addr[3] = ip->ip_addr[1] & 0x7F;
417 mac->mac_addr[4] = ip->ip_addr[2];
418 mac->mac_addr[5] = ip->ip_addr[3];
419out:
420 return EFI_EXIT(ret);
Alexander Graf94c4b992016-05-06 21:01:01 +0200421}
422
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100423/**
424 * efi_net_nvdata() - read or write NVRAM
425 *
426 * This function implements the GetStatus service of the Simple Network
427 * Protocol. See the UEFI spec for details.
428 *
429 * @this: the instance of the Simple Network Protocol
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200430 * @read_write: true for read, false for write
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100431 * @offset: offset in NVRAM
432 * @buffer_size: size of buffer
433 * @buffer: buffer
434 * Return: status code
435 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200436static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this,
437 int read_write, ulong offset,
438 ulong buffer_size, char *buffer)
439{
440 EFI_ENTRY("%p, %x, %lx, %lx, %p", this, read_write, offset, buffer_size,
441 buffer);
442
Heinrich Schuchardta50b5c62017-10-05 16:35:59 +0200443 return EFI_EXIT(EFI_UNSUPPORTED);
Alexander Graf94c4b992016-05-06 21:01:01 +0200444}
445
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100446/**
447 * efi_net_get_status() - get interrupt status
448 *
449 * This function implements the GetStatus service of the Simple Network
450 * Protocol. See the UEFI spec for details.
451 *
452 * @this: the instance of the Simple Network Protocol
453 * @int_status: interface status
454 * @txbuf: transmission buffer
455 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200456static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this,
457 u32 *int_status, void **txbuf)
458{
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100459 efi_status_t ret = EFI_SUCCESS;
460
Alexander Graf94c4b992016-05-06 21:01:01 +0200461 EFI_ENTRY("%p, %p, %p", this, int_status, txbuf);
462
Heinrich Schuchardte371c5f2017-10-05 16:36:02 +0200463 efi_timer_check();
464
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100465 /* Check parameters */
466 if (!this) {
467 ret = EFI_INVALID_PARAMETER;
468 goto out;
469 }
470
471 switch (this->mode->state) {
472 case EFI_NETWORK_STOPPED:
473 ret = EFI_NOT_STARTED;
474 goto out;
475 case EFI_NETWORK_STARTED:
476 ret = EFI_DEVICE_ERROR;
477 goto out;
478 default:
479 break;
480 }
481
Heinrich Schuchardte371c5f2017-10-05 16:36:02 +0200482 if (int_status) {
Heinrich Schuchardtd3f1ff22019-08-31 09:56:30 +0200483 *int_status = this->int_status;
484 this->int_status = 0;
Heinrich Schuchardte371c5f2017-10-05 16:36:02 +0200485 }
Alexander Graf94c4b992016-05-06 21:01:01 +0200486 if (txbuf)
487 *txbuf = new_tx_packet;
488
489 new_tx_packet = NULL;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100490out:
491 return EFI_EXIT(ret);
Alexander Graf94c4b992016-05-06 21:01:01 +0200492}
493
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100494/**
495 * efi_net_transmit() - transmit a packet
496 *
497 * This function implements the Transmit service of the Simple Network Protocol.
498 * See the UEFI spec for details.
499 *
500 * @this: the instance of the Simple Network Protocol
501 * @header_size: size of the media header
502 * @buffer_size: size of the buffer to receive the packet
503 * @buffer: buffer to receive the packet
504 * @src_addr: source hardware MAC address
505 * @dest_addr: destination hardware MAC address
506 * @protocol: type of header to build
507 * Return: status code
508 */
509static efi_status_t EFIAPI efi_net_transmit
510 (struct efi_simple_network *this, size_t header_size,
511 size_t buffer_size, void *buffer,
512 struct efi_mac_address *src_addr,
513 struct efi_mac_address *dest_addr, u16 *protocol)
Alexander Graf94c4b992016-05-06 21:01:01 +0200514{
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100515 efi_status_t ret = EFI_SUCCESS;
516
Heinrich Schuchardtf66b2e32017-10-05 16:36:03 +0200517 EFI_ENTRY("%p, %lu, %lu, %p, %p, %p, %p", this,
518 (unsigned long)header_size, (unsigned long)buffer_size,
519 buffer, src_addr, dest_addr, protocol);
Alexander Graf94c4b992016-05-06 21:01:01 +0200520
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200521 efi_timer_check();
522
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100523 /* Check parameters */
Heinrich Schuchardtf286c2c2019-05-15 23:27:43 +0200524 if (!this || !buffer) {
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100525 ret = EFI_INVALID_PARAMETER;
526 goto out;
527 }
528
529 /* We do not support jumbo packets */
530 if (buffer_size > PKTSIZE_ALIGN) {
531 ret = EFI_INVALID_PARAMETER;
532 goto out;
533 }
534
Heinrich Schuchardt0218a8f2019-08-31 10:55:29 +0200535 /* At least the IP header has to fit into the buffer */
536 if (buffer_size < this->mode->media_header_size) {
537 ret = EFI_BUFFER_TOO_SMALL;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100538 goto out;
Alexander Graf94c4b992016-05-06 21:01:01 +0200539 }
540
Heinrich Schuchardt0218a8f2019-08-31 10:55:29 +0200541 /*
542 * TODO:
543 * Support VLANs. Use net_set_ether() for copying the header. Use a
544 * U_BOOT_ENV_CALLBACK to update the media header size.
545 */
546 if (header_size) {
547 struct ethernet_hdr *header = buffer;
548
549 if (!dest_addr || !protocol ||
550 header_size != this->mode->media_header_size) {
551 ret = EFI_INVALID_PARAMETER;
552 goto out;
553 }
554 if (!src_addr)
555 src_addr = &this->mode->current_address;
556
557 memcpy(header->et_dest, dest_addr, ARP_HLEN);
558 memcpy(header->et_src, src_addr, ARP_HLEN);
559 header->et_protlen = htons(*protocol);
560 }
561
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100562 switch (this->mode->state) {
563 case EFI_NETWORK_STOPPED:
564 ret = EFI_NOT_STARTED;
565 goto out;
566 case EFI_NETWORK_STARTED:
567 ret = EFI_DEVICE_ERROR;
568 goto out;
569 default:
570 break;
571 }
572
573 /* Ethernet packets always fit, just bounce */
Heinrich Schuchardteb07c282018-12-01 00:16:32 +0100574 memcpy(transmit_buffer, buffer, buffer_size);
575 net_send_packet(transmit_buffer, buffer_size);
Alexander Graf0b12b862016-09-06 14:26:27 +0200576
Alexander Graf94c4b992016-05-06 21:01:01 +0200577 new_tx_packet = buffer;
Heinrich Schuchardtd3f1ff22019-08-31 09:56:30 +0200578 this->int_status |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100579out:
580 return EFI_EXIT(ret);
Alexander Graf94c4b992016-05-06 21:01:01 +0200581}
582
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100583/**
584 * efi_net_receive() - receive a packet from a network interface
Heinrich Schuchardtf66b2e32017-10-05 16:36:03 +0200585 *
586 * This function implements the Receive service of the Simple Network Protocol.
587 * See the UEFI spec for details.
588 *
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100589 * @this: the instance of the Simple Network Protocol
590 * @header_size: size of the media header
591 * @buffer_size: size of the buffer to receive the packet
592 * @buffer: buffer to receive the packet
593 * @src_addr: source MAC address
594 * @dest_addr: destination MAC address
595 * @protocol: protocol
596 * Return: status code
Heinrich Schuchardtf66b2e32017-10-05 16:36:03 +0200597 */
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100598static efi_status_t EFIAPI efi_net_receive
599 (struct efi_simple_network *this, size_t *header_size,
600 size_t *buffer_size, void *buffer,
601 struct efi_mac_address *src_addr,
602 struct efi_mac_address *dest_addr, u16 *protocol)
Alexander Graf94c4b992016-05-06 21:01:01 +0200603{
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100604 efi_status_t ret = EFI_SUCCESS;
Heinrich Schuchardtaa0d1972017-10-05 16:36:04 +0200605 struct ethernet_hdr *eth_hdr;
606 size_t hdr_size = sizeof(struct ethernet_hdr);
607 u16 protlen;
608
Alexander Graf94c4b992016-05-06 21:01:01 +0200609 EFI_ENTRY("%p, %p, %p, %p, %p, %p, %p", this, header_size,
610 buffer_size, buffer, src_addr, dest_addr, protocol);
611
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100612 /* Execute events */
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200613 efi_timer_check();
Alexander Graf94c4b992016-05-06 21:01:01 +0200614
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100615 /* Check parameters */
Heinrich Schuchardtf286c2c2019-05-15 23:27:43 +0200616 if (!this || !buffer || !buffer_size) {
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100617 ret = EFI_INVALID_PARAMETER;
618 goto out;
619 }
620
621 switch (this->mode->state) {
622 case EFI_NETWORK_STOPPED:
623 ret = EFI_NOT_STARTED;
624 goto out;
625 case EFI_NETWORK_STARTED:
626 ret = EFI_DEVICE_ERROR;
627 goto out;
628 default:
629 break;
630 }
631
Patrick Wildtfab89102020-10-07 11:04:33 +0200632 if (!rx_packet_num) {
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100633 ret = EFI_NOT_READY;
634 goto out;
635 }
Heinrich Schuchardtaa0d1972017-10-05 16:36:04 +0200636 /* Fill export parameters */
Patrick Wildtfab89102020-10-07 11:04:33 +0200637 eth_hdr = (struct ethernet_hdr *)receive_buffer[rx_packet_idx];
Heinrich Schuchardtaa0d1972017-10-05 16:36:04 +0200638 protlen = ntohs(eth_hdr->et_protlen);
639 if (protlen == 0x8100) {
640 hdr_size += 4;
Patrick Wildtfab89102020-10-07 11:04:33 +0200641 protlen = ntohs(*(u16 *)&receive_buffer[rx_packet_idx][hdr_size - 2]);
Heinrich Schuchardtaa0d1972017-10-05 16:36:04 +0200642 }
643 if (header_size)
644 *header_size = hdr_size;
645 if (dest_addr)
646 memcpy(dest_addr, eth_hdr->et_dest, ARP_HLEN);
647 if (src_addr)
648 memcpy(src_addr, eth_hdr->et_src, ARP_HLEN);
649 if (protocol)
650 *protocol = protlen;
Patrick Wildtfab89102020-10-07 11:04:33 +0200651 if (*buffer_size < receive_lengths[rx_packet_idx]) {
Heinrich Schuchardt5e96f422018-10-18 21:51:38 +0200652 /* Packet doesn't fit, try again with bigger buffer */
Patrick Wildtfab89102020-10-07 11:04:33 +0200653 *buffer_size = receive_lengths[rx_packet_idx];
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100654 ret = EFI_BUFFER_TOO_SMALL;
655 goto out;
Alexander Graf94c4b992016-05-06 21:01:01 +0200656 }
Heinrich Schuchardtaa0d1972017-10-05 16:36:04 +0200657 /* Copy packet */
Patrick Wildtfab89102020-10-07 11:04:33 +0200658 memcpy(buffer, receive_buffer[rx_packet_idx],
659 receive_lengths[rx_packet_idx]);
660 *buffer_size = receive_lengths[rx_packet_idx];
661 rx_packet_idx = (rx_packet_idx + 1) % ETH_PACKETS_BATCH_RECV;
662 rx_packet_num--;
663 if (rx_packet_num)
664 wait_for_packet->is_signaled = true;
665 else
666 this->int_status &= ~EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100667out:
668 return EFI_EXIT(ret);
Alexander Graf94c4b992016-05-06 21:01:01 +0200669}
670
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100671/**
672 * efi_net_set_dhcp_ack() - take note of a selected DHCP IP address
673 *
674 * This function is called by dhcp_handler().
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200675 *
676 * @pkt: packet received by dhcp_handler()
677 * @len: length of the packet received
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100678 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200679void efi_net_set_dhcp_ack(void *pkt, int len)
680{
681 int maxsize = sizeof(*dhcp_ack);
682
Heinrich Schuchardt2f1a93f2022-11-26 16:44:38 +0100683 if (!dhcp_ack) {
Alexander Graf94c4b992016-05-06 21:01:01 +0200684 dhcp_ack = malloc(maxsize);
Heinrich Schuchardt2f1a93f2022-11-26 16:44:38 +0100685 if (!dhcp_ack)
686 return;
687 }
688 memset(dhcp_ack, 0, maxsize);
Alexander Graf94c4b992016-05-06 21:01:01 +0200689 memcpy(dhcp_ack, pkt, min(len, maxsize));
Heinrich Schuchardt2f1a93f2022-11-26 16:44:38 +0100690
691 if (netobj)
692 netobj->pxe_mode.dhcp_ack = *dhcp_ack;
Alexander Graf94c4b992016-05-06 21:01:01 +0200693}
694
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100695/**
696 * efi_net_push() - callback for received network packet
697 *
698 * This function is called when a network packet is received by eth_rx().
699 *
700 * @pkt: network packet
701 * @len: length
702 */
703static void efi_net_push(void *pkt, int len)
704{
Patrick Wildtfab89102020-10-07 11:04:33 +0200705 int rx_packet_next;
706
707 /* Check that we at least received an Ethernet header */
708 if (len < sizeof(struct ethernet_hdr))
709 return;
710
711 /* Check that the buffer won't overflow */
712 if (len > PKTSIZE_ALIGN)
713 return;
714
715 /* Can't store more than pre-alloced buffer */
716 if (rx_packet_num >= ETH_PACKETS_BATCH_RECV)
717 return;
718
719 rx_packet_next = (rx_packet_idx + rx_packet_num) %
720 ETH_PACKETS_BATCH_RECV;
721 memcpy(receive_buffer[rx_packet_next], pkt, len);
722 receive_lengths[rx_packet_next] = len;
723
724 rx_packet_num++;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100725}
726
727/**
728 * efi_network_timer_notify() - check if a new network packet has been received
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200729 *
730 * This notification function is called in every timer cycle.
731 *
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200732 * @event: the event for which this notification function is registered
733 * @context: event context - not used in this function
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200734 */
735static void EFIAPI efi_network_timer_notify(struct efi_event *event,
736 void *context)
737{
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100738 struct efi_simple_network *this = (struct efi_simple_network *)context;
739
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200740 EFI_ENTRY("%p, %p", event, context);
741
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100742 /*
743 * Some network drivers do not support calling eth_rx() before
744 * initialization.
745 */
746 if (!this || this->mode->state != EFI_NETWORK_INITIALIZED)
747 goto out;
748
Patrick Wildtfab89102020-10-07 11:04:33 +0200749 if (!rx_packet_num) {
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200750 push_packet = efi_net_push;
751 eth_rx();
752 push_packet = NULL;
Patrick Wildtfab89102020-10-07 11:04:33 +0200753 if (rx_packet_num) {
754 this->int_status |=
755 EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
756 wait_for_packet->is_signaled = true;
Heinrich Schuchardtd3f1ff22019-08-31 09:56:30 +0200757 }
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200758 }
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100759out:
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200760 EFI_EXIT(EFI_SUCCESS);
761}
762
Heinrich Schuchardt3127e7e2019-08-06 08:13:33 +0200763static efi_status_t EFIAPI efi_pxe_base_code_start(
764 struct efi_pxe_base_code_protocol *this,
765 u8 use_ipv6)
766{
767 return EFI_UNSUPPORTED;
768}
769
770static efi_status_t EFIAPI efi_pxe_base_code_stop(
771 struct efi_pxe_base_code_protocol *this)
772{
773 return EFI_UNSUPPORTED;
774}
775
776static efi_status_t EFIAPI efi_pxe_base_code_dhcp(
777 struct efi_pxe_base_code_protocol *this,
778 u8 sort_offers)
779{
780 return EFI_UNSUPPORTED;
781}
782
783static efi_status_t EFIAPI efi_pxe_base_code_discover(
784 struct efi_pxe_base_code_protocol *this,
785 u16 type, u16 *layer, u8 bis,
786 struct efi_pxe_base_code_discover_info *info)
787{
788 return EFI_UNSUPPORTED;
789}
790
791static efi_status_t EFIAPI efi_pxe_base_code_mtftp(
792 struct efi_pxe_base_code_protocol *this,
793 u32 operation, void *buffer_ptr,
794 u8 overwrite, efi_uintn_t *buffer_size,
795 struct efi_ip_address server_ip, char *filename,
796 struct efi_pxe_base_code_mtftp_info *info,
797 u8 dont_use_buffer)
798{
799 return EFI_UNSUPPORTED;
800}
801
802static efi_status_t EFIAPI efi_pxe_base_code_udp_write(
803 struct efi_pxe_base_code_protocol *this,
804 u16 op_flags, struct efi_ip_address *dest_ip,
805 u16 *dest_port,
806 struct efi_ip_address *gateway_ip,
807 struct efi_ip_address *src_ip, u16 *src_port,
808 efi_uintn_t *header_size, void *header_ptr,
809 efi_uintn_t *buffer_size, void *buffer_ptr)
810{
811 return EFI_UNSUPPORTED;
812}
813
814static efi_status_t EFIAPI efi_pxe_base_code_udp_read(
815 struct efi_pxe_base_code_protocol *this,
816 u16 op_flags, struct efi_ip_address *dest_ip,
817 u16 *dest_port, struct efi_ip_address *src_ip,
818 u16 *src_port, efi_uintn_t *header_size,
819 void *header_ptr, efi_uintn_t *buffer_size,
820 void *buffer_ptr)
821{
822 return EFI_UNSUPPORTED;
823}
824
825static efi_status_t EFIAPI efi_pxe_base_code_set_ip_filter(
826 struct efi_pxe_base_code_protocol *this,
827 struct efi_pxe_base_code_filter *new_filter)
828{
829 return EFI_UNSUPPORTED;
830}
831
832static efi_status_t EFIAPI efi_pxe_base_code_arp(
833 struct efi_pxe_base_code_protocol *this,
834 struct efi_ip_address *ip_addr,
835 struct efi_mac_address *mac_addr)
836{
837 return EFI_UNSUPPORTED;
838}
839
840static efi_status_t EFIAPI efi_pxe_base_code_set_parameters(
841 struct efi_pxe_base_code_protocol *this,
842 u8 *new_auto_arp, u8 *new_send_guid,
843 u8 *new_ttl, u8 *new_tos,
844 u8 *new_make_callback)
845{
846 return EFI_UNSUPPORTED;
847}
848
849static efi_status_t EFIAPI efi_pxe_base_code_set_station_ip(
850 struct efi_pxe_base_code_protocol *this,
851 struct efi_ip_address *new_station_ip,
852 struct efi_ip_address *new_subnet_mask)
853{
854 return EFI_UNSUPPORTED;
855}
856
857static efi_status_t EFIAPI efi_pxe_base_code_set_packets(
858 struct efi_pxe_base_code_protocol *this,
859 u8 *new_dhcp_discover_valid,
860 u8 *new_dhcp_ack_received,
861 u8 *new_proxy_offer_received,
862 u8 *new_pxe_discover_valid,
863 u8 *new_pxe_reply_received,
864 u8 *new_pxe_bis_reply_received,
865 EFI_PXE_BASE_CODE_PACKET *new_dchp_discover,
866 EFI_PXE_BASE_CODE_PACKET *new_dhcp_acc,
867 EFI_PXE_BASE_CODE_PACKET *new_proxy_offer,
868 EFI_PXE_BASE_CODE_PACKET *new_pxe_discover,
869 EFI_PXE_BASE_CODE_PACKET *new_pxe_reply,
870 EFI_PXE_BASE_CODE_PACKET *new_pxe_bis_reply)
871{
872 return EFI_UNSUPPORTED;
873}
874
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100875/**
876 * efi_net_register() - register the simple network protocol
877 *
878 * This gets called from do_bootefi_exec().
879 */
Heinrich Schuchardt6f5c73f2018-03-03 15:28:56 +0100880efi_status_t efi_net_register(void)
Alexander Graf94c4b992016-05-06 21:01:01 +0200881{
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200882 efi_status_t r;
Patrick Wildtfab89102020-10-07 11:04:33 +0200883 int i;
Alexander Graf94c4b992016-05-06 21:01:01 +0200884
885 if (!eth_get_dev()) {
Heinrich Schuchardt5e96f422018-10-18 21:51:38 +0200886 /* No network device active, don't expose any */
Heinrich Schuchardt6f5c73f2018-03-03 15:28:56 +0100887 return EFI_SUCCESS;
Alexander Graf94c4b992016-05-06 21:01:01 +0200888 }
889
Heinrich Schuchardt5e96f422018-10-18 21:51:38 +0200890 /* We only expose the "active" network device, so one is enough */
Alexander Graf94c4b992016-05-06 21:01:01 +0200891 netobj = calloc(1, sizeof(*netobj));
Heinrich Schuchardteb07c282018-12-01 00:16:32 +0100892 if (!netobj)
893 goto out_of_resources;
894
895 /* Allocate an aligned transmit buffer */
896 transmit_buffer = calloc(1, PKTSIZE_ALIGN + PKTALIGN);
897 if (!transmit_buffer)
898 goto out_of_resources;
899 transmit_buffer = (void *)ALIGN((uintptr_t)transmit_buffer, PKTALIGN);
Heinrich Schuchardt23b45b62017-11-26 14:05:13 +0100900
Patrick Wildtfab89102020-10-07 11:04:33 +0200901 /* Allocate a number of receive buffers */
902 receive_buffer = calloc(ETH_PACKETS_BATCH_RECV,
903 sizeof(*receive_buffer));
904 if (!receive_buffer)
905 goto out_of_resources;
906 for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++) {
907 receive_buffer[i] = malloc(PKTSIZE_ALIGN);
908 if (!receive_buffer[i])
909 goto out_of_resources;
910 }
911 receive_lengths = calloc(ETH_PACKETS_BATCH_RECV,
912 sizeof(*receive_lengths));
913 if (!receive_lengths)
914 goto out_of_resources;
915
Heinrich Schuchardt23b45b62017-11-26 14:05:13 +0100916 /* Hook net up to the device list */
Heinrich Schuchardt72928722018-09-26 05:27:56 +0200917 efi_add_handle(&netobj->header);
Alexander Graf94c4b992016-05-06 21:01:01 +0200918
919 /* Fill in object data */
Heinrich Schuchardt72928722018-09-26 05:27:56 +0200920 r = efi_add_protocol(&netobj->header, &efi_net_guid,
Heinrich Schuchardt23b45b62017-11-26 14:05:13 +0100921 &netobj->net);
922 if (r != EFI_SUCCESS)
Heinrich Schuchardt6f5c73f2018-03-03 15:28:56 +0100923 goto failure_to_add_protocol;
Adriano Cordova93cba0f2024-12-04 00:05:23 -0300924 if (!net_dp)
925 efi_net_set_dp("Net", NULL);
Heinrich Schuchardt72928722018-09-26 05:27:56 +0200926 r = efi_add_protocol(&netobj->header, &efi_guid_device_path,
Adriano Cordova93cba0f2024-12-04 00:05:23 -0300927 net_dp);
Heinrich Schuchardt23b45b62017-11-26 14:05:13 +0100928 if (r != EFI_SUCCESS)
Heinrich Schuchardt6f5c73f2018-03-03 15:28:56 +0100929 goto failure_to_add_protocol;
Heinrich Schuchardt3127e7e2019-08-06 08:13:33 +0200930 r = efi_add_protocol(&netobj->header, &efi_pxe_base_code_protocol_guid,
Heinrich Schuchardt23b45b62017-11-26 14:05:13 +0100931 &netobj->pxe);
932 if (r != EFI_SUCCESS)
Heinrich Schuchardt6f5c73f2018-03-03 15:28:56 +0100933 goto failure_to_add_protocol;
Heinrich Schuchardtd54396a2017-10-05 16:35:57 +0200934 netobj->net.revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
Alexander Graf94c4b992016-05-06 21:01:01 +0200935 netobj->net.start = efi_net_start;
936 netobj->net.stop = efi_net_stop;
937 netobj->net.initialize = efi_net_initialize;
938 netobj->net.reset = efi_net_reset;
939 netobj->net.shutdown = efi_net_shutdown;
940 netobj->net.receive_filters = efi_net_receive_filters;
941 netobj->net.station_address = efi_net_station_address;
942 netobj->net.statistics = efi_net_statistics;
943 netobj->net.mcastiptomac = efi_net_mcastiptomac;
944 netobj->net.nvdata = efi_net_nvdata;
945 netobj->net.get_status = efi_net_get_status;
946 netobj->net.transmit = efi_net_transmit;
947 netobj->net.receive = efi_net_receive;
948 netobj->net.mode = &netobj->net_mode;
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200949 netobj->net_mode.state = EFI_NETWORK_STOPPED;
Alexander Graf94c4b992016-05-06 21:01:01 +0200950 memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6);
Heinrich Schuchardtd1cc6cb2017-10-05 16:35:58 +0200951 netobj->net_mode.hwaddr_size = ARP_HLEN;
Heinrich Schuchardt0218a8f2019-08-31 10:55:29 +0200952 netobj->net_mode.media_header_size = ETHER_HDR_SIZE;
Alexander Graf94c4b992016-05-06 21:01:01 +0200953 netobj->net_mode.max_packet_size = PKTSIZE;
Andrew Thomas27df0a72018-06-21 16:21:01 -0700954 netobj->net_mode.if_type = ARP_ETHER;
Alexander Graf94c4b992016-05-06 21:01:01 +0200955
Heinrich Schuchardt3127e7e2019-08-06 08:13:33 +0200956 netobj->pxe.revision = EFI_PXE_BASE_CODE_PROTOCOL_REVISION;
957 netobj->pxe.start = efi_pxe_base_code_start;
958 netobj->pxe.stop = efi_pxe_base_code_stop;
959 netobj->pxe.dhcp = efi_pxe_base_code_dhcp;
960 netobj->pxe.discover = efi_pxe_base_code_discover;
961 netobj->pxe.mtftp = efi_pxe_base_code_mtftp;
962 netobj->pxe.udp_write = efi_pxe_base_code_udp_write;
963 netobj->pxe.udp_read = efi_pxe_base_code_udp_read;
964 netobj->pxe.set_ip_filter = efi_pxe_base_code_set_ip_filter;
965 netobj->pxe.arp = efi_pxe_base_code_arp;
966 netobj->pxe.set_parameters = efi_pxe_base_code_set_parameters;
967 netobj->pxe.set_station_ip = efi_pxe_base_code_set_station_ip;
968 netobj->pxe.set_packets = efi_pxe_base_code_set_packets;
Alexander Graf94c4b992016-05-06 21:01:01 +0200969 netobj->pxe.mode = &netobj->pxe_mode;
970 if (dhcp_ack)
971 netobj->pxe_mode.dhcp_ack = *dhcp_ack;
972
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200973 /*
Heinrich Schuchardt0c153c22017-10-05 16:36:01 +0200974 * Create WaitForPacket event.
975 */
976 r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK,
Heinrich Schuchardtbf7f1692018-02-18 15:17:52 +0100977 efi_network_timer_notify, NULL, NULL,
Heinrich Schuchardt0c153c22017-10-05 16:36:01 +0200978 &wait_for_packet);
979 if (r != EFI_SUCCESS) {
980 printf("ERROR: Failed to register network event\n");
981 return r;
982 }
983 netobj->net.wait_for_packet = wait_for_packet;
984 /*
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200985 * Create a timer event.
986 *
987 * The notification function is used to check if a new network packet
988 * has been received.
Heinrich Schuchardt86df48c2018-03-24 18:40:22 +0100989 *
990 * iPXE is running at TPL_CALLBACK most of the time. Use a higher TPL.
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200991 */
Heinrich Schuchardt86df48c2018-03-24 18:40:22 +0100992 r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_NOTIFY,
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100993 efi_network_timer_notify, &netobj->net, NULL,
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200994 &network_timer_event);
995 if (r != EFI_SUCCESS) {
996 printf("ERROR: Failed to register network event\n");
997 return r;
998 }
Heinrich Schuchardt5e96f422018-10-18 21:51:38 +0200999 /* Network is time critical, create event in every timer cycle */
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +02001000 r = efi_set_timer(network_timer_event, EFI_TIMER_PERIODIC, 0);
1001 if (r != EFI_SUCCESS) {
1002 printf("ERROR: Failed to set network timer\n");
1003 return r;
1004 }
1005
Adriano Cordova9debc902024-12-04 00:05:25 -03001006#if IS_ENABLED(CONFIG_EFI_IP4_CONFIG2_PROTOCOL)
1007 r = efi_ipconfig_register(&netobj->header, &netobj->ip4_config2);
1008 if (r != EFI_SUCCESS)
1009 goto failure_to_add_protocol;
1010#endif
1011
Heinrich Schuchardt6f5c73f2018-03-03 15:28:56 +01001012 return EFI_SUCCESS;
1013failure_to_add_protocol:
1014 printf("ERROR: Failure to add protocol\n");
1015 return r;
Heinrich Schuchardteb07c282018-12-01 00:16:32 +01001016out_of_resources:
1017 free(netobj);
Heinrich Schuchardt2f1a93f2022-11-26 16:44:38 +01001018 netobj = NULL;
Patrick Wildtfab89102020-10-07 11:04:33 +02001019 free(transmit_buffer);
1020 if (receive_buffer)
1021 for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++)
1022 free(receive_buffer[i]);
1023 free(receive_buffer);
1024 free(receive_lengths);
Heinrich Schuchardteb07c282018-12-01 00:16:32 +01001025 printf("ERROR: Out of memory\n");
1026 return EFI_OUT_OF_RESOURCES;
Alexander Graf94c4b992016-05-06 21:01:01 +02001027}
Adriano Cordova3c951362024-12-04 00:05:21 -03001028
1029/**
Adriano Cordova93cba0f2024-12-04 00:05:23 -03001030 * efi_net_set_dp() - set device path of efi net device
1031 *
1032 * This gets called to update the device path when a new boot
1033 * file is downloaded
1034 *
1035 * @dev: dev to set the device path from
1036 * @server: remote server address
1037 * Return: status code
1038 */
1039efi_status_t efi_net_set_dp(const char *dev, const char *server)
1040{
1041 efi_free_pool(net_dp);
1042
1043 net_dp = NULL;
1044 if (!strcmp(dev, "Net"))
1045 net_dp = efi_dp_from_eth();
1046 else if (!strcmp(dev, "Http"))
1047 net_dp = efi_dp_from_http(server);
1048
1049 if (!net_dp)
1050 return EFI_OUT_OF_RESOURCES;
1051
1052 return EFI_SUCCESS;
1053}
1054
1055/**
1056 * efi_net_get_dp() - get device path of efi net device
1057 *
1058 * Produce a copy of the current device path
1059 *
1060 * @dp: copy of the current device path, or NULL on error
1061 */
1062void efi_net_get_dp(struct efi_device_path **dp)
1063{
1064 if (!dp)
1065 return;
1066 if (!net_dp)
1067 efi_net_set_dp("Net", NULL);
1068 if (net_dp)
1069 *dp = efi_dp_dup(net_dp);
1070}
1071
1072/**
Adriano Cordova3c951362024-12-04 00:05:21 -03001073 * efi_net_get_addr() - get IP address information
1074 *
1075 * Copy the current IP address, mask, and gateway into the
1076 * efi_ipv4_address structs pointed to by ip, mask and gw,
1077 * respectively.
1078 *
1079 * @ip: pointer to an efi_ipv4_address struct to
1080 * be filled with the current IP address
1081 * @mask: pointer to an efi_ipv4_address struct to
1082 * be filled with the current network mask
1083 * @gw: pointer to an efi_ipv4_address struct to be
1084 * filled with the current network gateway
1085 */
1086void efi_net_get_addr(struct efi_ipv4_address *ip,
1087 struct efi_ipv4_address *mask,
1088 struct efi_ipv4_address *gw)
1089{
1090#ifdef CONFIG_NET_LWIP
1091 char ipstr[] = "ipaddr\0\0";
1092 char maskstr[] = "netmask\0\0";
1093 char gwstr[] = "gatewayip\0\0";
1094 int idx;
1095 struct in_addr tmp;
1096 char *env;
1097
1098 idx = dev_seq(eth_get_dev());
1099
1100 if (idx < 0 || idx > 99) {
1101 log_err("unexpected idx %d\n", idx);
1102 return;
1103 }
1104
1105 if (idx) {
1106 sprintf(ipstr, "ipaddr%d", idx);
1107 sprintf(maskstr, "netmask%d", idx);
1108 sprintf(gwstr, "gatewayip%d", idx);
1109 }
1110
1111 env = env_get(ipstr);
1112 if (env && ip) {
1113 tmp = string_to_ip(env);
1114 memcpy(ip, &tmp, sizeof(tmp));
1115 }
1116
1117 env = env_get(maskstr);
1118 if (env && mask) {
1119 tmp = string_to_ip(env);
1120 memcpy(mask, &tmp, sizeof(tmp));
1121 }
1122 env = env_get(gwstr);
1123 if (env && gw) {
1124 tmp = string_to_ip(env);
1125 memcpy(gw, &tmp, sizeof(tmp));
1126 }
1127#else
1128 if (ip)
1129 memcpy(ip, &net_ip, sizeof(net_ip));
1130 if (mask)
1131 memcpy(mask, &net_netmask, sizeof(net_netmask));
1132#endif
1133}
1134
1135/**
1136 * efi_net_set_addr() - set IP address information
1137 *
1138 * Set the current IP address, mask, and gateway to the
1139 * efi_ipv4_address structs pointed to by ip, mask and gw,
1140 * respectively.
1141 *
1142 * @ip: pointer to new IP address
1143 * @mask: pointer to new network mask to set
1144 * @gw: pointer to new network gateway
1145 */
1146void efi_net_set_addr(struct efi_ipv4_address *ip,
1147 struct efi_ipv4_address *mask,
1148 struct efi_ipv4_address *gw)
1149{
1150#ifdef CONFIG_NET_LWIP
1151 char ipstr[] = "ipaddr\0\0";
1152 char maskstr[] = "netmask\0\0";
1153 char gwstr[] = "gatewayip\0\0";
1154 int idx;
1155 struct in_addr *addr;
1156 char tmp[46];
1157
1158 idx = dev_seq(eth_get_dev());
1159
1160 if (idx < 0 || idx > 99) {
1161 log_err("unexpected idx %d\n", idx);
1162 return;
1163 }
1164
1165 if (idx) {
1166 sprintf(ipstr, "ipaddr%d", idx);
1167 sprintf(maskstr, "netmask%d", idx);
1168 sprintf(gwstr, "gatewayip%d", idx);
1169 }
1170
1171 if (ip) {
1172 addr = (struct in_addr *)ip;
1173 ip_to_string(*addr, tmp);
1174 env_set(ipstr, tmp);
1175 }
1176
1177 if (mask) {
1178 addr = (struct in_addr *)mask;
1179 ip_to_string(*addr, tmp);
1180 env_set(maskstr, tmp);
1181 }
1182
1183 if (gw) {
1184 addr = (struct in_addr *)gw;
1185 ip_to_string(*addr, tmp);
1186 env_set(gwstr, tmp);
1187 }
1188#else
1189 if (ip)
1190 memcpy(&net_ip, ip, sizeof(*ip));
1191 if (mask)
1192 memcpy(&net_netmask, mask, sizeof(*mask));
1193#endif
1194}
Adriano Cordova0d1f5092024-12-04 00:05:24 -03001195
1196/**
1197 * efi_net_set_buffer() - allocate a buffer of min 64K
1198 *
1199 * @buffer: allocated buffer
1200 * @size: desired buffer size
1201 * Return: status code
1202 */
1203static efi_status_t efi_net_set_buffer(void **buffer, size_t size)
1204{
1205 efi_status_t ret = EFI_SUCCESS;
1206
1207 if (size < SZ_64K)
1208 size = SZ_64K;
1209
1210 efi_free_pool(*buffer);
1211
1212 *buffer = efi_alloc(size);
1213 if (!*buffer)
1214 ret = EFI_OUT_OF_RESOURCES;
1215
1216 efi_wget_info.buffer_size = (ulong)size;
1217
1218 return ret;
1219}
1220
1221/**
1222 * efi_net_parse_headers() - parse HTTP headers
1223 *
1224 * Parses the raw buffer efi_wget_info.headers into an array headers
1225 * of efi structs http_headers. The array should be at least
1226 * MAX_HTTP_HEADERS long.
1227 *
1228 * @num_headers: number of headers
1229 * @headers: caller provided array of struct http_headers
1230 */
1231void efi_net_parse_headers(ulong *num_headers, struct http_header *headers)
1232{
1233 if (!num_headers || !headers)
1234 return;
1235
1236 // Populate info with http headers.
1237 *num_headers = 0;
1238 const uchar *line_start = efi_wget_info.headers;
1239 const uchar *line_end;
1240 ulong count;
1241 struct http_header *current_header;
1242 const uchar *separator;
1243 size_t name_length, value_length;
1244
1245 // Skip the first line (request or status line)
1246 line_end = strstr(line_start, "\r\n");
1247
1248 if (line_end)
1249 line_start = line_end + 2;
1250
1251 while ((line_end = strstr(line_start, "\r\n")) != NULL) {
1252 count = *num_headers;
1253 if (line_start == line_end || count >= MAX_HTTP_HEADERS)
1254 break;
1255 current_header = headers + count;
1256 separator = strchr(line_start, ':');
1257 if (separator) {
1258 name_length = separator - line_start;
1259 ++separator;
1260 while (*separator == ' ')
1261 ++separator;
1262 value_length = line_end - separator;
1263 if (name_length < MAX_HTTP_HEADER_NAME &&
1264 value_length < MAX_HTTP_HEADER_VALUE) {
1265 strncpy(current_header->name, line_start, name_length);
1266 current_header->name[name_length] = '\0';
1267 strncpy(current_header->value, separator, value_length);
1268 current_header->value[value_length] = '\0';
1269 (*num_headers)++;
1270 }
1271 }
1272 line_start = line_end + 2;
1273 }
1274}
1275
1276/**
1277 * efi_net_do_request() - issue an HTTP request using wget
1278 *
1279 * @url: url
1280 * @method: HTTP method
1281 * @buffer: data buffer
1282 * @status_code: HTTP status code
1283 * @file_size: file size in bytes
1284 * @headers_buffer: headers buffer
1285 * Return: status code
1286 */
1287efi_status_t efi_net_do_request(u8 *url, enum efi_http_method method, void **buffer,
1288 u32 *status_code, ulong *file_size, char *headers_buffer)
1289{
1290 efi_status_t ret = EFI_SUCCESS;
1291 int wget_ret;
1292 static bool last_head;
1293
1294 if (!buffer || !file_size)
1295 return EFI_ABORTED;
1296
1297 efi_wget_info.method = (enum wget_http_method)method;
1298 efi_wget_info.headers = headers_buffer;
1299
1300 switch (method) {
1301 case HTTP_METHOD_GET:
1302 ret = efi_net_set_buffer(buffer, last_head ? (size_t)efi_wget_info.hdr_cont_len : 0);
1303 if (ret != EFI_SUCCESS)
1304 goto out;
1305 wget_ret = wget_request((ulong)*buffer, url, &efi_wget_info);
1306 if ((ulong)efi_wget_info.hdr_cont_len > efi_wget_info.buffer_size) {
1307 // Try again with updated buffer size
1308 ret = efi_net_set_buffer(buffer, (size_t)efi_wget_info.hdr_cont_len);
1309 if (ret != EFI_SUCCESS)
1310 goto out;
1311 if (wget_request((ulong)*buffer, url, &efi_wget_info)) {
1312 efi_free_pool(*buffer);
1313 ret = EFI_DEVICE_ERROR;
1314 goto out;
1315 }
1316 } else if (wget_ret) {
1317 efi_free_pool(*buffer);
1318 ret = EFI_DEVICE_ERROR;
1319 goto out;
1320 }
1321 // Pass the actual number of received bytes to the application
1322 *file_size = efi_wget_info.file_size;
1323 *status_code = efi_wget_info.status_code;
1324 last_head = false;
1325 break;
1326 case HTTP_METHOD_HEAD:
1327 ret = efi_net_set_buffer(buffer, 0);
1328 if (ret != EFI_SUCCESS)
1329 goto out;
1330 wget_request((ulong)*buffer, url, &efi_wget_info);
1331 *file_size = 0;
1332 *status_code = efi_wget_info.status_code;
1333 last_head = true;
1334 break;
1335 default:
1336 ret = EFI_UNSUPPORTED;
1337 break;
1338 }
1339
1340out:
1341 return ret;
1342}