blob: 368f62c5b2d235c759e443e687371a7e1bec7e54 [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 *
63 * @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 */
Alexander Graf94c4b992016-05-06 21:01:01 +020069struct efi_net_obj {
Heinrich Schuchardt72928722018-09-26 05:27:56 +020070 struct efi_object header;
Alexander Graf94c4b992016-05-06 21:01:01 +020071 struct efi_simple_network net;
72 struct efi_simple_network_mode net_mode;
Heinrich Schuchardt3127e7e2019-08-06 08:13:33 +020073 struct efi_pxe_base_code_protocol pxe;
Alexander Graf94c4b992016-05-06 21:01:01 +020074 struct efi_pxe_mode pxe_mode;
75};
76
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +010077/*
78 * efi_net_start() - start the network interface
79 *
80 * This function implements the Start service of the
81 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
82 * (UEFI) specification for details.
83 *
84 * @this: pointer to the protocol instance
85 * Return: status code
86 */
Alexander Graf94c4b992016-05-06 21:01:01 +020087static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this)
88{
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +010089 efi_status_t ret = EFI_SUCCESS;
90
Alexander Graf94c4b992016-05-06 21:01:01 +020091 EFI_ENTRY("%p", this);
92
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +010093 /* Check parameters */
94 if (!this) {
95 ret = EFI_INVALID_PARAMETER;
96 goto out;
97 }
98
Heinrich Schuchardtd3f1ff22019-08-31 09:56:30 +020099 if (this->mode->state != EFI_NETWORK_STOPPED) {
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100100 ret = EFI_ALREADY_STARTED;
Heinrich Schuchardtd3f1ff22019-08-31 09:56:30 +0200101 } else {
102 this->int_status = 0;
103 wait_for_packet->is_signaled = false;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100104 this->mode->state = EFI_NETWORK_STARTED;
Heinrich Schuchardtd3f1ff22019-08-31 09:56:30 +0200105 }
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100106out:
107 return EFI_EXIT(ret);
Alexander Graf94c4b992016-05-06 21:01:01 +0200108}
109
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100110/*
111 * efi_net_stop() - stop the network interface
112 *
113 * This function implements the Stop service of the
114 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
115 * (UEFI) specification for details.
116 *
117 * @this: pointer to the protocol instance
118 * Return: status code
119 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200120static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this)
121{
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100122 efi_status_t ret = EFI_SUCCESS;
123
Alexander Graf94c4b992016-05-06 21:01:01 +0200124 EFI_ENTRY("%p", this);
125
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100126 /* Check parameters */
127 if (!this) {
128 ret = EFI_INVALID_PARAMETER;
129 goto out;
130 }
131
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200132 if (this->mode->state == EFI_NETWORK_STOPPED) {
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100133 ret = EFI_NOT_STARTED;
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200134 } else {
135 /* Disable hardware and put it into the reset state */
136 eth_halt();
Patrick Wildtfab89102020-10-07 11:04:33 +0200137 /* Clear cache of packets */
138 rx_packet_num = 0;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100139 this->mode->state = EFI_NETWORK_STOPPED;
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200140 }
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100141out:
142 return EFI_EXIT(ret);
Alexander Graf94c4b992016-05-06 21:01:01 +0200143}
144
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200145/*
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100146 * efi_net_initialize() - initialize the network interface
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200147 *
148 * This function implements the Initialize service of the
149 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
150 * (UEFI) specification for details.
151 *
152 * @this: pointer to the protocol instance
153 * @extra_rx: extra receive buffer to be allocated
154 * @extra_tx: extra transmit buffer to be allocated
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100155 * Return: status code
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200156 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200157static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
158 ulong extra_rx, ulong extra_tx)
159{
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200160 int ret;
161 efi_status_t r = EFI_SUCCESS;
162
Alexander Graf94c4b992016-05-06 21:01:01 +0200163 EFI_ENTRY("%p, %lx, %lx", this, extra_rx, extra_tx);
164
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100165 /* Check parameters */
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200166 if (!this) {
167 r = EFI_INVALID_PARAMETER;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100168 goto out;
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200169 }
170
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200171 switch (this->mode->state) {
172 case EFI_NETWORK_INITIALIZED:
173 case EFI_NETWORK_STARTED:
174 break;
175 default:
176 r = EFI_NOT_STARTED;
177 goto out;
178 }
179
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200180 /* Setup packet buffers */
181 net_init();
182 /* Disable hardware and put it into the reset state */
183 eth_halt();
Patrick Wildtfab89102020-10-07 11:04:33 +0200184 /* Clear cache of packets */
185 rx_packet_num = 0;
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200186 /* Set current device according to environment variables */
187 eth_set_current();
188 /* Get hardware ready for send and receive operations */
189 ret = eth_init();
190 if (ret < 0) {
191 eth_halt();
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100192 this->mode->state = EFI_NETWORK_STOPPED;
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200193 r = EFI_DEVICE_ERROR;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100194 goto out;
195 } else {
Heinrich Schuchardtd3f1ff22019-08-31 09:56:30 +0200196 this->int_status = 0;
197 wait_for_packet->is_signaled = false;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100198 this->mode->state = EFI_NETWORK_INITIALIZED;
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200199 }
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100200out:
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200201 return EFI_EXIT(r);
Alexander Graf94c4b992016-05-06 21:01:01 +0200202}
203
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100204/*
205 * efi_net_reset() - reinitialize the network interface
206 *
207 * This function implements the Reset service of the
208 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
209 * (UEFI) specification for details.
210 *
211 * @this: pointer to the protocol instance
212 * @extended_verification: execute exhaustive verification
213 * Return: status code
214 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200215static efi_status_t EFIAPI efi_net_reset(struct efi_simple_network *this,
216 int extended_verification)
217{
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200218 efi_status_t ret;
219
Alexander Graf94c4b992016-05-06 21:01:01 +0200220 EFI_ENTRY("%p, %x", this, extended_verification);
221
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200222 /* Check parameters */
223 if (!this) {
224 ret = EFI_INVALID_PARAMETER;
225 goto out;
226 }
227
228 switch (this->mode->state) {
229 case EFI_NETWORK_INITIALIZED:
230 break;
231 case EFI_NETWORK_STOPPED:
232 ret = EFI_NOT_STARTED;
233 goto out;
234 default:
235 ret = EFI_DEVICE_ERROR;
236 goto out;
237 }
238
239 this->mode->state = EFI_NETWORK_STARTED;
240 ret = EFI_CALL(efi_net_initialize(this, 0, 0));
241out:
242 return EFI_EXIT(ret);
Alexander Graf94c4b992016-05-06 21:01:01 +0200243}
244
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100245/*
246 * efi_net_shutdown() - shut down the network interface
247 *
248 * This function implements the Shutdown service of the
249 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
250 * (UEFI) specification for details.
251 *
252 * @this: pointer to the protocol instance
253 * Return: status code
254 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200255static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this)
256{
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100257 efi_status_t ret = EFI_SUCCESS;
258
Alexander Graf94c4b992016-05-06 21:01:01 +0200259 EFI_ENTRY("%p", this);
260
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100261 /* Check parameters */
262 if (!this) {
263 ret = EFI_INVALID_PARAMETER;
264 goto out;
265 }
266
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200267 switch (this->mode->state) {
268 case EFI_NETWORK_INITIALIZED:
269 break;
270 case EFI_NETWORK_STOPPED:
271 ret = EFI_NOT_STARTED;
272 goto out;
273 default:
274 ret = EFI_DEVICE_ERROR;
275 goto out;
276 }
277
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100278 eth_halt();
Heinrich Schuchardtd3f1ff22019-08-31 09:56:30 +0200279 this->int_status = 0;
280 wait_for_packet->is_signaled = false;
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200281 this->mode->state = EFI_NETWORK_STARTED;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100282
283out:
284 return EFI_EXIT(ret);
Alexander Graf94c4b992016-05-06 21:01:01 +0200285}
286
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100287/*
288 * efi_net_receive_filters() - mange multicast receive filters
289 *
290 * This function implements the ReceiveFilters service of the
291 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
292 * (UEFI) specification for details.
293 *
294 * @this: pointer to the protocol instance
295 * @enable: bit mask of receive filters to enable
296 * @disable: bit mask of receive filters to disable
297 * @reset_mcast_filter: true resets contents of the filters
298 * @mcast_filter_count: number of hardware MAC addresses in the new filters list
299 * @mcast_filter: list of new filters
300 * Return: status code
301 */
302static efi_status_t EFIAPI efi_net_receive_filters
303 (struct efi_simple_network *this, u32 enable, u32 disable,
304 int reset_mcast_filter, ulong mcast_filter_count,
305 struct efi_mac_address *mcast_filter)
Alexander Graf94c4b992016-05-06 21:01:01 +0200306{
307 EFI_ENTRY("%p, %x, %x, %x, %lx, %p", this, enable, disable,
308 reset_mcast_filter, mcast_filter_count, mcast_filter);
309
Heinrich Schuchardta50b5c62017-10-05 16:35:59 +0200310 return EFI_EXIT(EFI_UNSUPPORTED);
Alexander Graf94c4b992016-05-06 21:01:01 +0200311}
312
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100313/*
314 * efi_net_station_address() - set the hardware MAC address
315 *
316 * This function implements the StationAddress service of the
317 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
318 * (UEFI) specification for details.
319 *
320 * @this: pointer to the protocol instance
321 * @reset: if true reset the address to default
322 * @new_mac: new MAC address
323 * Return: status code
324 */
325static efi_status_t EFIAPI efi_net_station_address
326 (struct efi_simple_network *this, int reset,
327 struct efi_mac_address *new_mac)
Alexander Graf94c4b992016-05-06 21:01:01 +0200328{
329 EFI_ENTRY("%p, %x, %p", this, reset, new_mac);
330
Heinrich Schuchardta50b5c62017-10-05 16:35:59 +0200331 return EFI_EXIT(EFI_UNSUPPORTED);
Alexander Graf94c4b992016-05-06 21:01:01 +0200332}
333
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100334/*
335 * efi_net_statistics() - reset or collect statistics of the network interface
336 *
337 * This function implements the Statistics service of the
338 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
339 * (UEFI) specification for details.
340 *
341 * @this: pointer to the protocol instance
342 * @reset: if true, the statistics are reset
343 * @stat_size: size of the statistics table
344 * @stat_table: table to receive the statistics
345 * Return: status code
346 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200347static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this,
348 int reset, ulong *stat_size,
349 void *stat_table)
350{
351 EFI_ENTRY("%p, %x, %p, %p", this, reset, stat_size, stat_table);
352
Heinrich Schuchardta50b5c62017-10-05 16:35:59 +0200353 return EFI_EXIT(EFI_UNSUPPORTED);
Alexander Graf94c4b992016-05-06 21:01:01 +0200354}
355
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100356/*
357 * efi_net_mcastiptomac() - translate multicast IP address to MAC address
358 *
Heinrich Schuchardt33b318d2019-09-01 17:17:53 +0200359 * This function implements the MCastIPtoMAC service of the
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100360 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
361 * (UEFI) specification for details.
362 *
363 * @this: pointer to the protocol instance
364 * @ipv6: true if the IP address is an IPv6 address
365 * @ip: IP address
366 * @mac: MAC address
367 * Return: status code
368 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200369static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this,
370 int ipv6,
371 struct efi_ip_address *ip,
372 struct efi_mac_address *mac)
373{
Heinrich Schuchardt33b318d2019-09-01 17:17:53 +0200374 efi_status_t ret = EFI_SUCCESS;
375
Alexander Graf94c4b992016-05-06 21:01:01 +0200376 EFI_ENTRY("%p, %x, %p, %p", this, ipv6, ip, mac);
377
Heinrich Schuchardt33b318d2019-09-01 17:17:53 +0200378 if (!this || !ip || !mac) {
379 ret = EFI_INVALID_PARAMETER;
380 goto out;
381 }
382
383 if (ipv6) {
384 ret = EFI_UNSUPPORTED;
385 goto out;
386 }
387
388 /* Multi-cast addresses are in the range 224.0.0.0 - 239.255.255.255 */
389 if ((ip->ip_addr[0] & 0xf0) != 0xe0) {
390 ret = EFI_INVALID_PARAMETER;
391 goto out;
392 };
393
394 switch (this->mode->state) {
395 case EFI_NETWORK_INITIALIZED:
396 case EFI_NETWORK_STARTED:
397 break;
398 default:
399 ret = EFI_NOT_STARTED;
400 goto out;
401 }
402
403 memset(mac, 0, sizeof(struct efi_mac_address));
404
405 /*
406 * Copy lower 23 bits of IPv4 multi-cast address
407 * RFC 1112, RFC 7042 2.1.1.
408 */
409 mac->mac_addr[0] = 0x01;
410 mac->mac_addr[1] = 0x00;
411 mac->mac_addr[2] = 0x5E;
412 mac->mac_addr[3] = ip->ip_addr[1] & 0x7F;
413 mac->mac_addr[4] = ip->ip_addr[2];
414 mac->mac_addr[5] = ip->ip_addr[3];
415out:
416 return EFI_EXIT(ret);
Alexander Graf94c4b992016-05-06 21:01:01 +0200417}
418
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100419/**
420 * efi_net_nvdata() - read or write NVRAM
421 *
422 * This function implements the GetStatus service of the Simple Network
423 * Protocol. See the UEFI spec for details.
424 *
425 * @this: the instance of the Simple Network Protocol
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200426 * @read_write: true for read, false for write
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100427 * @offset: offset in NVRAM
428 * @buffer_size: size of buffer
429 * @buffer: buffer
430 * Return: status code
431 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200432static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this,
433 int read_write, ulong offset,
434 ulong buffer_size, char *buffer)
435{
436 EFI_ENTRY("%p, %x, %lx, %lx, %p", this, read_write, offset, buffer_size,
437 buffer);
438
Heinrich Schuchardta50b5c62017-10-05 16:35:59 +0200439 return EFI_EXIT(EFI_UNSUPPORTED);
Alexander Graf94c4b992016-05-06 21:01:01 +0200440}
441
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100442/**
443 * efi_net_get_status() - get interrupt status
444 *
445 * This function implements the GetStatus service of the Simple Network
446 * Protocol. See the UEFI spec for details.
447 *
448 * @this: the instance of the Simple Network Protocol
449 * @int_status: interface status
450 * @txbuf: transmission buffer
451 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200452static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this,
453 u32 *int_status, void **txbuf)
454{
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100455 efi_status_t ret = EFI_SUCCESS;
456
Alexander Graf94c4b992016-05-06 21:01:01 +0200457 EFI_ENTRY("%p, %p, %p", this, int_status, txbuf);
458
Heinrich Schuchardte371c5f2017-10-05 16:36:02 +0200459 efi_timer_check();
460
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100461 /* Check parameters */
462 if (!this) {
463 ret = EFI_INVALID_PARAMETER;
464 goto out;
465 }
466
467 switch (this->mode->state) {
468 case EFI_NETWORK_STOPPED:
469 ret = EFI_NOT_STARTED;
470 goto out;
471 case EFI_NETWORK_STARTED:
472 ret = EFI_DEVICE_ERROR;
473 goto out;
474 default:
475 break;
476 }
477
Heinrich Schuchardte371c5f2017-10-05 16:36:02 +0200478 if (int_status) {
Heinrich Schuchardtd3f1ff22019-08-31 09:56:30 +0200479 *int_status = this->int_status;
480 this->int_status = 0;
Heinrich Schuchardte371c5f2017-10-05 16:36:02 +0200481 }
Alexander Graf94c4b992016-05-06 21:01:01 +0200482 if (txbuf)
483 *txbuf = new_tx_packet;
484
485 new_tx_packet = NULL;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100486out:
487 return EFI_EXIT(ret);
Alexander Graf94c4b992016-05-06 21:01:01 +0200488}
489
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100490/**
491 * efi_net_transmit() - transmit a packet
492 *
493 * This function implements the Transmit service of the Simple Network Protocol.
494 * See the UEFI spec for details.
495 *
496 * @this: the instance of the Simple Network Protocol
497 * @header_size: size of the media header
498 * @buffer_size: size of the buffer to receive the packet
499 * @buffer: buffer to receive the packet
500 * @src_addr: source hardware MAC address
501 * @dest_addr: destination hardware MAC address
502 * @protocol: type of header to build
503 * Return: status code
504 */
505static efi_status_t EFIAPI efi_net_transmit
506 (struct efi_simple_network *this, size_t header_size,
507 size_t buffer_size, void *buffer,
508 struct efi_mac_address *src_addr,
509 struct efi_mac_address *dest_addr, u16 *protocol)
Alexander Graf94c4b992016-05-06 21:01:01 +0200510{
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100511 efi_status_t ret = EFI_SUCCESS;
512
Heinrich Schuchardtf66b2e32017-10-05 16:36:03 +0200513 EFI_ENTRY("%p, %lu, %lu, %p, %p, %p, %p", this,
514 (unsigned long)header_size, (unsigned long)buffer_size,
515 buffer, src_addr, dest_addr, protocol);
Alexander Graf94c4b992016-05-06 21:01:01 +0200516
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200517 efi_timer_check();
518
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100519 /* Check parameters */
Heinrich Schuchardtf286c2c2019-05-15 23:27:43 +0200520 if (!this || !buffer) {
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100521 ret = EFI_INVALID_PARAMETER;
522 goto out;
523 }
524
525 /* We do not support jumbo packets */
526 if (buffer_size > PKTSIZE_ALIGN) {
527 ret = EFI_INVALID_PARAMETER;
528 goto out;
529 }
530
Heinrich Schuchardt0218a8f2019-08-31 10:55:29 +0200531 /* At least the IP header has to fit into the buffer */
532 if (buffer_size < this->mode->media_header_size) {
533 ret = EFI_BUFFER_TOO_SMALL;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100534 goto out;
Alexander Graf94c4b992016-05-06 21:01:01 +0200535 }
536
Heinrich Schuchardt0218a8f2019-08-31 10:55:29 +0200537 /*
538 * TODO:
539 * Support VLANs. Use net_set_ether() for copying the header. Use a
540 * U_BOOT_ENV_CALLBACK to update the media header size.
541 */
542 if (header_size) {
543 struct ethernet_hdr *header = buffer;
544
545 if (!dest_addr || !protocol ||
546 header_size != this->mode->media_header_size) {
547 ret = EFI_INVALID_PARAMETER;
548 goto out;
549 }
550 if (!src_addr)
551 src_addr = &this->mode->current_address;
552
553 memcpy(header->et_dest, dest_addr, ARP_HLEN);
554 memcpy(header->et_src, src_addr, ARP_HLEN);
555 header->et_protlen = htons(*protocol);
556 }
557
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100558 switch (this->mode->state) {
559 case EFI_NETWORK_STOPPED:
560 ret = EFI_NOT_STARTED;
561 goto out;
562 case EFI_NETWORK_STARTED:
563 ret = EFI_DEVICE_ERROR;
564 goto out;
565 default:
566 break;
567 }
568
569 /* Ethernet packets always fit, just bounce */
Heinrich Schuchardteb07c282018-12-01 00:16:32 +0100570 memcpy(transmit_buffer, buffer, buffer_size);
571 net_send_packet(transmit_buffer, buffer_size);
Alexander Graf0b12b862016-09-06 14:26:27 +0200572
Alexander Graf94c4b992016-05-06 21:01:01 +0200573 new_tx_packet = buffer;
Heinrich Schuchardtd3f1ff22019-08-31 09:56:30 +0200574 this->int_status |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100575out:
576 return EFI_EXIT(ret);
Alexander Graf94c4b992016-05-06 21:01:01 +0200577}
578
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100579/**
580 * efi_net_receive() - receive a packet from a network interface
Heinrich Schuchardtf66b2e32017-10-05 16:36:03 +0200581 *
582 * This function implements the Receive service of the Simple Network Protocol.
583 * See the UEFI spec for details.
584 *
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100585 * @this: the instance of the Simple Network Protocol
586 * @header_size: size of the media header
587 * @buffer_size: size of the buffer to receive the packet
588 * @buffer: buffer to receive the packet
589 * @src_addr: source MAC address
590 * @dest_addr: destination MAC address
591 * @protocol: protocol
592 * Return: status code
Heinrich Schuchardtf66b2e32017-10-05 16:36:03 +0200593 */
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100594static efi_status_t EFIAPI efi_net_receive
595 (struct efi_simple_network *this, size_t *header_size,
596 size_t *buffer_size, void *buffer,
597 struct efi_mac_address *src_addr,
598 struct efi_mac_address *dest_addr, u16 *protocol)
Alexander Graf94c4b992016-05-06 21:01:01 +0200599{
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100600 efi_status_t ret = EFI_SUCCESS;
Heinrich Schuchardtaa0d1972017-10-05 16:36:04 +0200601 struct ethernet_hdr *eth_hdr;
602 size_t hdr_size = sizeof(struct ethernet_hdr);
603 u16 protlen;
604
Alexander Graf94c4b992016-05-06 21:01:01 +0200605 EFI_ENTRY("%p, %p, %p, %p, %p, %p, %p", this, header_size,
606 buffer_size, buffer, src_addr, dest_addr, protocol);
607
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100608 /* Execute events */
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200609 efi_timer_check();
Alexander Graf94c4b992016-05-06 21:01:01 +0200610
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100611 /* Check parameters */
Heinrich Schuchardtf286c2c2019-05-15 23:27:43 +0200612 if (!this || !buffer || !buffer_size) {
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100613 ret = EFI_INVALID_PARAMETER;
614 goto out;
615 }
616
617 switch (this->mode->state) {
618 case EFI_NETWORK_STOPPED:
619 ret = EFI_NOT_STARTED;
620 goto out;
621 case EFI_NETWORK_STARTED:
622 ret = EFI_DEVICE_ERROR;
623 goto out;
624 default:
625 break;
626 }
627
Patrick Wildtfab89102020-10-07 11:04:33 +0200628 if (!rx_packet_num) {
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100629 ret = EFI_NOT_READY;
630 goto out;
631 }
Heinrich Schuchardtaa0d1972017-10-05 16:36:04 +0200632 /* Fill export parameters */
Patrick Wildtfab89102020-10-07 11:04:33 +0200633 eth_hdr = (struct ethernet_hdr *)receive_buffer[rx_packet_idx];
Heinrich Schuchardtaa0d1972017-10-05 16:36:04 +0200634 protlen = ntohs(eth_hdr->et_protlen);
635 if (protlen == 0x8100) {
636 hdr_size += 4;
Patrick Wildtfab89102020-10-07 11:04:33 +0200637 protlen = ntohs(*(u16 *)&receive_buffer[rx_packet_idx][hdr_size - 2]);
Heinrich Schuchardtaa0d1972017-10-05 16:36:04 +0200638 }
639 if (header_size)
640 *header_size = hdr_size;
641 if (dest_addr)
642 memcpy(dest_addr, eth_hdr->et_dest, ARP_HLEN);
643 if (src_addr)
644 memcpy(src_addr, eth_hdr->et_src, ARP_HLEN);
645 if (protocol)
646 *protocol = protlen;
Patrick Wildtfab89102020-10-07 11:04:33 +0200647 if (*buffer_size < receive_lengths[rx_packet_idx]) {
Heinrich Schuchardt5e96f422018-10-18 21:51:38 +0200648 /* Packet doesn't fit, try again with bigger buffer */
Patrick Wildtfab89102020-10-07 11:04:33 +0200649 *buffer_size = receive_lengths[rx_packet_idx];
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100650 ret = EFI_BUFFER_TOO_SMALL;
651 goto out;
Alexander Graf94c4b992016-05-06 21:01:01 +0200652 }
Heinrich Schuchardtaa0d1972017-10-05 16:36:04 +0200653 /* Copy packet */
Patrick Wildtfab89102020-10-07 11:04:33 +0200654 memcpy(buffer, receive_buffer[rx_packet_idx],
655 receive_lengths[rx_packet_idx]);
656 *buffer_size = receive_lengths[rx_packet_idx];
657 rx_packet_idx = (rx_packet_idx + 1) % ETH_PACKETS_BATCH_RECV;
658 rx_packet_num--;
659 if (rx_packet_num)
660 wait_for_packet->is_signaled = true;
661 else
662 this->int_status &= ~EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100663out:
664 return EFI_EXIT(ret);
Alexander Graf94c4b992016-05-06 21:01:01 +0200665}
666
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100667/**
668 * efi_net_set_dhcp_ack() - take note of a selected DHCP IP address
669 *
670 * This function is called by dhcp_handler().
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200671 *
672 * @pkt: packet received by dhcp_handler()
673 * @len: length of the packet received
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100674 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200675void efi_net_set_dhcp_ack(void *pkt, int len)
676{
677 int maxsize = sizeof(*dhcp_ack);
678
Heinrich Schuchardt2f1a93f2022-11-26 16:44:38 +0100679 if (!dhcp_ack) {
Alexander Graf94c4b992016-05-06 21:01:01 +0200680 dhcp_ack = malloc(maxsize);
Heinrich Schuchardt2f1a93f2022-11-26 16:44:38 +0100681 if (!dhcp_ack)
682 return;
683 }
684 memset(dhcp_ack, 0, maxsize);
Alexander Graf94c4b992016-05-06 21:01:01 +0200685 memcpy(dhcp_ack, pkt, min(len, maxsize));
Heinrich Schuchardt2f1a93f2022-11-26 16:44:38 +0100686
687 if (netobj)
688 netobj->pxe_mode.dhcp_ack = *dhcp_ack;
Alexander Graf94c4b992016-05-06 21:01:01 +0200689}
690
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100691/**
692 * efi_net_push() - callback for received network packet
693 *
694 * This function is called when a network packet is received by eth_rx().
695 *
696 * @pkt: network packet
697 * @len: length
698 */
699static void efi_net_push(void *pkt, int len)
700{
Patrick Wildtfab89102020-10-07 11:04:33 +0200701 int rx_packet_next;
702
703 /* Check that we at least received an Ethernet header */
704 if (len < sizeof(struct ethernet_hdr))
705 return;
706
707 /* Check that the buffer won't overflow */
708 if (len > PKTSIZE_ALIGN)
709 return;
710
711 /* Can't store more than pre-alloced buffer */
712 if (rx_packet_num >= ETH_PACKETS_BATCH_RECV)
713 return;
714
715 rx_packet_next = (rx_packet_idx + rx_packet_num) %
716 ETH_PACKETS_BATCH_RECV;
717 memcpy(receive_buffer[rx_packet_next], pkt, len);
718 receive_lengths[rx_packet_next] = len;
719
720 rx_packet_num++;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100721}
722
723/**
724 * efi_network_timer_notify() - check if a new network packet has been received
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200725 *
726 * This notification function is called in every timer cycle.
727 *
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200728 * @event: the event for which this notification function is registered
729 * @context: event context - not used in this function
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200730 */
731static void EFIAPI efi_network_timer_notify(struct efi_event *event,
732 void *context)
733{
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100734 struct efi_simple_network *this = (struct efi_simple_network *)context;
735
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200736 EFI_ENTRY("%p, %p", event, context);
737
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100738 /*
739 * Some network drivers do not support calling eth_rx() before
740 * initialization.
741 */
742 if (!this || this->mode->state != EFI_NETWORK_INITIALIZED)
743 goto out;
744
Patrick Wildtfab89102020-10-07 11:04:33 +0200745 if (!rx_packet_num) {
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200746 push_packet = efi_net_push;
747 eth_rx();
748 push_packet = NULL;
Patrick Wildtfab89102020-10-07 11:04:33 +0200749 if (rx_packet_num) {
750 this->int_status |=
751 EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
752 wait_for_packet->is_signaled = true;
Heinrich Schuchardtd3f1ff22019-08-31 09:56:30 +0200753 }
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200754 }
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100755out:
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200756 EFI_EXIT(EFI_SUCCESS);
757}
758
Heinrich Schuchardt3127e7e2019-08-06 08:13:33 +0200759static efi_status_t EFIAPI efi_pxe_base_code_start(
760 struct efi_pxe_base_code_protocol *this,
761 u8 use_ipv6)
762{
763 return EFI_UNSUPPORTED;
764}
765
766static efi_status_t EFIAPI efi_pxe_base_code_stop(
767 struct efi_pxe_base_code_protocol *this)
768{
769 return EFI_UNSUPPORTED;
770}
771
772static efi_status_t EFIAPI efi_pxe_base_code_dhcp(
773 struct efi_pxe_base_code_protocol *this,
774 u8 sort_offers)
775{
776 return EFI_UNSUPPORTED;
777}
778
779static efi_status_t EFIAPI efi_pxe_base_code_discover(
780 struct efi_pxe_base_code_protocol *this,
781 u16 type, u16 *layer, u8 bis,
782 struct efi_pxe_base_code_discover_info *info)
783{
784 return EFI_UNSUPPORTED;
785}
786
787static efi_status_t EFIAPI efi_pxe_base_code_mtftp(
788 struct efi_pxe_base_code_protocol *this,
789 u32 operation, void *buffer_ptr,
790 u8 overwrite, efi_uintn_t *buffer_size,
791 struct efi_ip_address server_ip, char *filename,
792 struct efi_pxe_base_code_mtftp_info *info,
793 u8 dont_use_buffer)
794{
795 return EFI_UNSUPPORTED;
796}
797
798static efi_status_t EFIAPI efi_pxe_base_code_udp_write(
799 struct efi_pxe_base_code_protocol *this,
800 u16 op_flags, struct efi_ip_address *dest_ip,
801 u16 *dest_port,
802 struct efi_ip_address *gateway_ip,
803 struct efi_ip_address *src_ip, u16 *src_port,
804 efi_uintn_t *header_size, void *header_ptr,
805 efi_uintn_t *buffer_size, void *buffer_ptr)
806{
807 return EFI_UNSUPPORTED;
808}
809
810static efi_status_t EFIAPI efi_pxe_base_code_udp_read(
811 struct efi_pxe_base_code_protocol *this,
812 u16 op_flags, struct efi_ip_address *dest_ip,
813 u16 *dest_port, struct efi_ip_address *src_ip,
814 u16 *src_port, efi_uintn_t *header_size,
815 void *header_ptr, efi_uintn_t *buffer_size,
816 void *buffer_ptr)
817{
818 return EFI_UNSUPPORTED;
819}
820
821static efi_status_t EFIAPI efi_pxe_base_code_set_ip_filter(
822 struct efi_pxe_base_code_protocol *this,
823 struct efi_pxe_base_code_filter *new_filter)
824{
825 return EFI_UNSUPPORTED;
826}
827
828static efi_status_t EFIAPI efi_pxe_base_code_arp(
829 struct efi_pxe_base_code_protocol *this,
830 struct efi_ip_address *ip_addr,
831 struct efi_mac_address *mac_addr)
832{
833 return EFI_UNSUPPORTED;
834}
835
836static efi_status_t EFIAPI efi_pxe_base_code_set_parameters(
837 struct efi_pxe_base_code_protocol *this,
838 u8 *new_auto_arp, u8 *new_send_guid,
839 u8 *new_ttl, u8 *new_tos,
840 u8 *new_make_callback)
841{
842 return EFI_UNSUPPORTED;
843}
844
845static efi_status_t EFIAPI efi_pxe_base_code_set_station_ip(
846 struct efi_pxe_base_code_protocol *this,
847 struct efi_ip_address *new_station_ip,
848 struct efi_ip_address *new_subnet_mask)
849{
850 return EFI_UNSUPPORTED;
851}
852
853static efi_status_t EFIAPI efi_pxe_base_code_set_packets(
854 struct efi_pxe_base_code_protocol *this,
855 u8 *new_dhcp_discover_valid,
856 u8 *new_dhcp_ack_received,
857 u8 *new_proxy_offer_received,
858 u8 *new_pxe_discover_valid,
859 u8 *new_pxe_reply_received,
860 u8 *new_pxe_bis_reply_received,
861 EFI_PXE_BASE_CODE_PACKET *new_dchp_discover,
862 EFI_PXE_BASE_CODE_PACKET *new_dhcp_acc,
863 EFI_PXE_BASE_CODE_PACKET *new_proxy_offer,
864 EFI_PXE_BASE_CODE_PACKET *new_pxe_discover,
865 EFI_PXE_BASE_CODE_PACKET *new_pxe_reply,
866 EFI_PXE_BASE_CODE_PACKET *new_pxe_bis_reply)
867{
868 return EFI_UNSUPPORTED;
869}
870
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100871/**
872 * efi_net_register() - register the simple network protocol
873 *
874 * This gets called from do_bootefi_exec().
875 */
Heinrich Schuchardt6f5c73f2018-03-03 15:28:56 +0100876efi_status_t efi_net_register(void)
Alexander Graf94c4b992016-05-06 21:01:01 +0200877{
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200878 efi_status_t r;
Patrick Wildtfab89102020-10-07 11:04:33 +0200879 int i;
Alexander Graf94c4b992016-05-06 21:01:01 +0200880
881 if (!eth_get_dev()) {
Heinrich Schuchardt5e96f422018-10-18 21:51:38 +0200882 /* No network device active, don't expose any */
Heinrich Schuchardt6f5c73f2018-03-03 15:28:56 +0100883 return EFI_SUCCESS;
Alexander Graf94c4b992016-05-06 21:01:01 +0200884 }
885
Heinrich Schuchardt5e96f422018-10-18 21:51:38 +0200886 /* We only expose the "active" network device, so one is enough */
Alexander Graf94c4b992016-05-06 21:01:01 +0200887 netobj = calloc(1, sizeof(*netobj));
Heinrich Schuchardteb07c282018-12-01 00:16:32 +0100888 if (!netobj)
889 goto out_of_resources;
890
891 /* Allocate an aligned transmit buffer */
892 transmit_buffer = calloc(1, PKTSIZE_ALIGN + PKTALIGN);
893 if (!transmit_buffer)
894 goto out_of_resources;
895 transmit_buffer = (void *)ALIGN((uintptr_t)transmit_buffer, PKTALIGN);
Heinrich Schuchardt23b45b62017-11-26 14:05:13 +0100896
Patrick Wildtfab89102020-10-07 11:04:33 +0200897 /* Allocate a number of receive buffers */
898 receive_buffer = calloc(ETH_PACKETS_BATCH_RECV,
899 sizeof(*receive_buffer));
900 if (!receive_buffer)
901 goto out_of_resources;
902 for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++) {
903 receive_buffer[i] = malloc(PKTSIZE_ALIGN);
904 if (!receive_buffer[i])
905 goto out_of_resources;
906 }
907 receive_lengths = calloc(ETH_PACKETS_BATCH_RECV,
908 sizeof(*receive_lengths));
909 if (!receive_lengths)
910 goto out_of_resources;
911
Heinrich Schuchardt23b45b62017-11-26 14:05:13 +0100912 /* Hook net up to the device list */
Heinrich Schuchardt72928722018-09-26 05:27:56 +0200913 efi_add_handle(&netobj->header);
Alexander Graf94c4b992016-05-06 21:01:01 +0200914
915 /* Fill in object data */
Heinrich Schuchardt72928722018-09-26 05:27:56 +0200916 r = efi_add_protocol(&netobj->header, &efi_net_guid,
Heinrich Schuchardt23b45b62017-11-26 14:05:13 +0100917 &netobj->net);
918 if (r != EFI_SUCCESS)
Heinrich Schuchardt6f5c73f2018-03-03 15:28:56 +0100919 goto failure_to_add_protocol;
Adriano Cordova93cba0f2024-12-04 00:05:23 -0300920 if (!net_dp)
921 efi_net_set_dp("Net", NULL);
Heinrich Schuchardt72928722018-09-26 05:27:56 +0200922 r = efi_add_protocol(&netobj->header, &efi_guid_device_path,
Adriano Cordova93cba0f2024-12-04 00:05:23 -0300923 net_dp);
Heinrich Schuchardt23b45b62017-11-26 14:05:13 +0100924 if (r != EFI_SUCCESS)
Heinrich Schuchardt6f5c73f2018-03-03 15:28:56 +0100925 goto failure_to_add_protocol;
Heinrich Schuchardt3127e7e2019-08-06 08:13:33 +0200926 r = efi_add_protocol(&netobj->header, &efi_pxe_base_code_protocol_guid,
Heinrich Schuchardt23b45b62017-11-26 14:05:13 +0100927 &netobj->pxe);
928 if (r != EFI_SUCCESS)
Heinrich Schuchardt6f5c73f2018-03-03 15:28:56 +0100929 goto failure_to_add_protocol;
Heinrich Schuchardtd54396a2017-10-05 16:35:57 +0200930 netobj->net.revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
Alexander Graf94c4b992016-05-06 21:01:01 +0200931 netobj->net.start = efi_net_start;
932 netobj->net.stop = efi_net_stop;
933 netobj->net.initialize = efi_net_initialize;
934 netobj->net.reset = efi_net_reset;
935 netobj->net.shutdown = efi_net_shutdown;
936 netobj->net.receive_filters = efi_net_receive_filters;
937 netobj->net.station_address = efi_net_station_address;
938 netobj->net.statistics = efi_net_statistics;
939 netobj->net.mcastiptomac = efi_net_mcastiptomac;
940 netobj->net.nvdata = efi_net_nvdata;
941 netobj->net.get_status = efi_net_get_status;
942 netobj->net.transmit = efi_net_transmit;
943 netobj->net.receive = efi_net_receive;
944 netobj->net.mode = &netobj->net_mode;
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200945 netobj->net_mode.state = EFI_NETWORK_STOPPED;
Alexander Graf94c4b992016-05-06 21:01:01 +0200946 memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6);
Heinrich Schuchardtd1cc6cb2017-10-05 16:35:58 +0200947 netobj->net_mode.hwaddr_size = ARP_HLEN;
Heinrich Schuchardt0218a8f2019-08-31 10:55:29 +0200948 netobj->net_mode.media_header_size = ETHER_HDR_SIZE;
Alexander Graf94c4b992016-05-06 21:01:01 +0200949 netobj->net_mode.max_packet_size = PKTSIZE;
Andrew Thomas27df0a72018-06-21 16:21:01 -0700950 netobj->net_mode.if_type = ARP_ETHER;
Alexander Graf94c4b992016-05-06 21:01:01 +0200951
Heinrich Schuchardt3127e7e2019-08-06 08:13:33 +0200952 netobj->pxe.revision = EFI_PXE_BASE_CODE_PROTOCOL_REVISION;
953 netobj->pxe.start = efi_pxe_base_code_start;
954 netobj->pxe.stop = efi_pxe_base_code_stop;
955 netobj->pxe.dhcp = efi_pxe_base_code_dhcp;
956 netobj->pxe.discover = efi_pxe_base_code_discover;
957 netobj->pxe.mtftp = efi_pxe_base_code_mtftp;
958 netobj->pxe.udp_write = efi_pxe_base_code_udp_write;
959 netobj->pxe.udp_read = efi_pxe_base_code_udp_read;
960 netobj->pxe.set_ip_filter = efi_pxe_base_code_set_ip_filter;
961 netobj->pxe.arp = efi_pxe_base_code_arp;
962 netobj->pxe.set_parameters = efi_pxe_base_code_set_parameters;
963 netobj->pxe.set_station_ip = efi_pxe_base_code_set_station_ip;
964 netobj->pxe.set_packets = efi_pxe_base_code_set_packets;
Alexander Graf94c4b992016-05-06 21:01:01 +0200965 netobj->pxe.mode = &netobj->pxe_mode;
966 if (dhcp_ack)
967 netobj->pxe_mode.dhcp_ack = *dhcp_ack;
968
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200969 /*
Heinrich Schuchardt0c153c22017-10-05 16:36:01 +0200970 * Create WaitForPacket event.
971 */
972 r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK,
Heinrich Schuchardtbf7f1692018-02-18 15:17:52 +0100973 efi_network_timer_notify, NULL, NULL,
Heinrich Schuchardt0c153c22017-10-05 16:36:01 +0200974 &wait_for_packet);
975 if (r != EFI_SUCCESS) {
976 printf("ERROR: Failed to register network event\n");
977 return r;
978 }
979 netobj->net.wait_for_packet = wait_for_packet;
980 /*
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200981 * Create a timer event.
982 *
983 * The notification function is used to check if a new network packet
984 * has been received.
Heinrich Schuchardt86df48c2018-03-24 18:40:22 +0100985 *
986 * iPXE is running at TPL_CALLBACK most of the time. Use a higher TPL.
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200987 */
Heinrich Schuchardt86df48c2018-03-24 18:40:22 +0100988 r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_NOTIFY,
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100989 efi_network_timer_notify, &netobj->net, NULL,
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200990 &network_timer_event);
991 if (r != EFI_SUCCESS) {
992 printf("ERROR: Failed to register network event\n");
993 return r;
994 }
Heinrich Schuchardt5e96f422018-10-18 21:51:38 +0200995 /* Network is time critical, create event in every timer cycle */
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200996 r = efi_set_timer(network_timer_event, EFI_TIMER_PERIODIC, 0);
997 if (r != EFI_SUCCESS) {
998 printf("ERROR: Failed to set network timer\n");
999 return r;
1000 }
1001
Heinrich Schuchardt6f5c73f2018-03-03 15:28:56 +01001002 return EFI_SUCCESS;
1003failure_to_add_protocol:
1004 printf("ERROR: Failure to add protocol\n");
1005 return r;
Heinrich Schuchardteb07c282018-12-01 00:16:32 +01001006out_of_resources:
1007 free(netobj);
Heinrich Schuchardt2f1a93f2022-11-26 16:44:38 +01001008 netobj = NULL;
Patrick Wildtfab89102020-10-07 11:04:33 +02001009 free(transmit_buffer);
1010 if (receive_buffer)
1011 for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++)
1012 free(receive_buffer[i]);
1013 free(receive_buffer);
1014 free(receive_lengths);
Heinrich Schuchardteb07c282018-12-01 00:16:32 +01001015 printf("ERROR: Out of memory\n");
1016 return EFI_OUT_OF_RESOURCES;
Alexander Graf94c4b992016-05-06 21:01:01 +02001017}
Adriano Cordova3c951362024-12-04 00:05:21 -03001018
1019/**
Adriano Cordova93cba0f2024-12-04 00:05:23 -03001020 * efi_net_set_dp() - set device path of efi net device
1021 *
1022 * This gets called to update the device path when a new boot
1023 * file is downloaded
1024 *
1025 * @dev: dev to set the device path from
1026 * @server: remote server address
1027 * Return: status code
1028 */
1029efi_status_t efi_net_set_dp(const char *dev, const char *server)
1030{
1031 efi_free_pool(net_dp);
1032
1033 net_dp = NULL;
1034 if (!strcmp(dev, "Net"))
1035 net_dp = efi_dp_from_eth();
1036 else if (!strcmp(dev, "Http"))
1037 net_dp = efi_dp_from_http(server);
1038
1039 if (!net_dp)
1040 return EFI_OUT_OF_RESOURCES;
1041
1042 return EFI_SUCCESS;
1043}
1044
1045/**
1046 * efi_net_get_dp() - get device path of efi net device
1047 *
1048 * Produce a copy of the current device path
1049 *
1050 * @dp: copy of the current device path, or NULL on error
1051 */
1052void efi_net_get_dp(struct efi_device_path **dp)
1053{
1054 if (!dp)
1055 return;
1056 if (!net_dp)
1057 efi_net_set_dp("Net", NULL);
1058 if (net_dp)
1059 *dp = efi_dp_dup(net_dp);
1060}
1061
1062/**
Adriano Cordova3c951362024-12-04 00:05:21 -03001063 * efi_net_get_addr() - get IP address information
1064 *
1065 * Copy the current IP address, mask, and gateway into the
1066 * efi_ipv4_address structs pointed to by ip, mask and gw,
1067 * respectively.
1068 *
1069 * @ip: pointer to an efi_ipv4_address struct to
1070 * be filled with the current IP address
1071 * @mask: pointer to an efi_ipv4_address struct to
1072 * be filled with the current network mask
1073 * @gw: pointer to an efi_ipv4_address struct to be
1074 * filled with the current network gateway
1075 */
1076void efi_net_get_addr(struct efi_ipv4_address *ip,
1077 struct efi_ipv4_address *mask,
1078 struct efi_ipv4_address *gw)
1079{
1080#ifdef CONFIG_NET_LWIP
1081 char ipstr[] = "ipaddr\0\0";
1082 char maskstr[] = "netmask\0\0";
1083 char gwstr[] = "gatewayip\0\0";
1084 int idx;
1085 struct in_addr tmp;
1086 char *env;
1087
1088 idx = dev_seq(eth_get_dev());
1089
1090 if (idx < 0 || idx > 99) {
1091 log_err("unexpected idx %d\n", idx);
1092 return;
1093 }
1094
1095 if (idx) {
1096 sprintf(ipstr, "ipaddr%d", idx);
1097 sprintf(maskstr, "netmask%d", idx);
1098 sprintf(gwstr, "gatewayip%d", idx);
1099 }
1100
1101 env = env_get(ipstr);
1102 if (env && ip) {
1103 tmp = string_to_ip(env);
1104 memcpy(ip, &tmp, sizeof(tmp));
1105 }
1106
1107 env = env_get(maskstr);
1108 if (env && mask) {
1109 tmp = string_to_ip(env);
1110 memcpy(mask, &tmp, sizeof(tmp));
1111 }
1112 env = env_get(gwstr);
1113 if (env && gw) {
1114 tmp = string_to_ip(env);
1115 memcpy(gw, &tmp, sizeof(tmp));
1116 }
1117#else
1118 if (ip)
1119 memcpy(ip, &net_ip, sizeof(net_ip));
1120 if (mask)
1121 memcpy(mask, &net_netmask, sizeof(net_netmask));
1122#endif
1123}
1124
1125/**
1126 * efi_net_set_addr() - set IP address information
1127 *
1128 * Set the current IP address, mask, and gateway to the
1129 * efi_ipv4_address structs pointed to by ip, mask and gw,
1130 * respectively.
1131 *
1132 * @ip: pointer to new IP address
1133 * @mask: pointer to new network mask to set
1134 * @gw: pointer to new network gateway
1135 */
1136void efi_net_set_addr(struct efi_ipv4_address *ip,
1137 struct efi_ipv4_address *mask,
1138 struct efi_ipv4_address *gw)
1139{
1140#ifdef CONFIG_NET_LWIP
1141 char ipstr[] = "ipaddr\0\0";
1142 char maskstr[] = "netmask\0\0";
1143 char gwstr[] = "gatewayip\0\0";
1144 int idx;
1145 struct in_addr *addr;
1146 char tmp[46];
1147
1148 idx = dev_seq(eth_get_dev());
1149
1150 if (idx < 0 || idx > 99) {
1151 log_err("unexpected idx %d\n", idx);
1152 return;
1153 }
1154
1155 if (idx) {
1156 sprintf(ipstr, "ipaddr%d", idx);
1157 sprintf(maskstr, "netmask%d", idx);
1158 sprintf(gwstr, "gatewayip%d", idx);
1159 }
1160
1161 if (ip) {
1162 addr = (struct in_addr *)ip;
1163 ip_to_string(*addr, tmp);
1164 env_set(ipstr, tmp);
1165 }
1166
1167 if (mask) {
1168 addr = (struct in_addr *)mask;
1169 ip_to_string(*addr, tmp);
1170 env_set(maskstr, tmp);
1171 }
1172
1173 if (gw) {
1174 addr = (struct in_addr *)gw;
1175 ip_to_string(*addr, tmp);
1176 env_set(gwstr, tmp);
1177 }
1178#else
1179 if (ip)
1180 memcpy(&net_ip, ip, sizeof(*ip));
1181 if (mask)
1182 memcpy(&net_netmask, mask, sizeof(*mask));
1183#endif
1184}
Adriano Cordova0d1f5092024-12-04 00:05:24 -03001185
1186/**
1187 * efi_net_set_buffer() - allocate a buffer of min 64K
1188 *
1189 * @buffer: allocated buffer
1190 * @size: desired buffer size
1191 * Return: status code
1192 */
1193static efi_status_t efi_net_set_buffer(void **buffer, size_t size)
1194{
1195 efi_status_t ret = EFI_SUCCESS;
1196
1197 if (size < SZ_64K)
1198 size = SZ_64K;
1199
1200 efi_free_pool(*buffer);
1201
1202 *buffer = efi_alloc(size);
1203 if (!*buffer)
1204 ret = EFI_OUT_OF_RESOURCES;
1205
1206 efi_wget_info.buffer_size = (ulong)size;
1207
1208 return ret;
1209}
1210
1211/**
1212 * efi_net_parse_headers() - parse HTTP headers
1213 *
1214 * Parses the raw buffer efi_wget_info.headers into an array headers
1215 * of efi structs http_headers. The array should be at least
1216 * MAX_HTTP_HEADERS long.
1217 *
1218 * @num_headers: number of headers
1219 * @headers: caller provided array of struct http_headers
1220 */
1221void efi_net_parse_headers(ulong *num_headers, struct http_header *headers)
1222{
1223 if (!num_headers || !headers)
1224 return;
1225
1226 // Populate info with http headers.
1227 *num_headers = 0;
1228 const uchar *line_start = efi_wget_info.headers;
1229 const uchar *line_end;
1230 ulong count;
1231 struct http_header *current_header;
1232 const uchar *separator;
1233 size_t name_length, value_length;
1234
1235 // Skip the first line (request or status line)
1236 line_end = strstr(line_start, "\r\n");
1237
1238 if (line_end)
1239 line_start = line_end + 2;
1240
1241 while ((line_end = strstr(line_start, "\r\n")) != NULL) {
1242 count = *num_headers;
1243 if (line_start == line_end || count >= MAX_HTTP_HEADERS)
1244 break;
1245 current_header = headers + count;
1246 separator = strchr(line_start, ':');
1247 if (separator) {
1248 name_length = separator - line_start;
1249 ++separator;
1250 while (*separator == ' ')
1251 ++separator;
1252 value_length = line_end - separator;
1253 if (name_length < MAX_HTTP_HEADER_NAME &&
1254 value_length < MAX_HTTP_HEADER_VALUE) {
1255 strncpy(current_header->name, line_start, name_length);
1256 current_header->name[name_length] = '\0';
1257 strncpy(current_header->value, separator, value_length);
1258 current_header->value[value_length] = '\0';
1259 (*num_headers)++;
1260 }
1261 }
1262 line_start = line_end + 2;
1263 }
1264}
1265
1266/**
1267 * efi_net_do_request() - issue an HTTP request using wget
1268 *
1269 * @url: url
1270 * @method: HTTP method
1271 * @buffer: data buffer
1272 * @status_code: HTTP status code
1273 * @file_size: file size in bytes
1274 * @headers_buffer: headers buffer
1275 * Return: status code
1276 */
1277efi_status_t efi_net_do_request(u8 *url, enum efi_http_method method, void **buffer,
1278 u32 *status_code, ulong *file_size, char *headers_buffer)
1279{
1280 efi_status_t ret = EFI_SUCCESS;
1281 int wget_ret;
1282 static bool last_head;
1283
1284 if (!buffer || !file_size)
1285 return EFI_ABORTED;
1286
1287 efi_wget_info.method = (enum wget_http_method)method;
1288 efi_wget_info.headers = headers_buffer;
1289
1290 switch (method) {
1291 case HTTP_METHOD_GET:
1292 ret = efi_net_set_buffer(buffer, last_head ? (size_t)efi_wget_info.hdr_cont_len : 0);
1293 if (ret != EFI_SUCCESS)
1294 goto out;
1295 wget_ret = wget_request((ulong)*buffer, url, &efi_wget_info);
1296 if ((ulong)efi_wget_info.hdr_cont_len > efi_wget_info.buffer_size) {
1297 // Try again with updated buffer size
1298 ret = efi_net_set_buffer(buffer, (size_t)efi_wget_info.hdr_cont_len);
1299 if (ret != EFI_SUCCESS)
1300 goto out;
1301 if (wget_request((ulong)*buffer, url, &efi_wget_info)) {
1302 efi_free_pool(*buffer);
1303 ret = EFI_DEVICE_ERROR;
1304 goto out;
1305 }
1306 } else if (wget_ret) {
1307 efi_free_pool(*buffer);
1308 ret = EFI_DEVICE_ERROR;
1309 goto out;
1310 }
1311 // Pass the actual number of received bytes to the application
1312 *file_size = efi_wget_info.file_size;
1313 *status_code = efi_wget_info.status_code;
1314 last_head = false;
1315 break;
1316 case HTTP_METHOD_HEAD:
1317 ret = efi_net_set_buffer(buffer, 0);
1318 if (ret != EFI_SUCCESS)
1319 goto out;
1320 wget_request((ulong)*buffer, url, &efi_wget_info);
1321 *file_size = 0;
1322 *status_code = efi_wget_info.status_code;
1323 last_head = true;
1324 break;
1325 default:
1326 ret = EFI_UNSUPPORTED;
1327 break;
1328 }
1329
1330out:
1331 return ret;
1332}