blob: e8af2e3d95e02af37215630fcd3277ef74dd82ef [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>
Alexander Graf94c4b992016-05-06 21:01:01 +020020#include <malloc.h>
Adriano Cordova3c951362024-12-04 00:05:21 -030021#include <vsprintf.h>
Simon Glass274e0b02020-05-10 11:39:56 -060022#include <net.h>
Alexander Graf94c4b992016-05-06 21:01:01 +020023
Heinrich Schuchardt788ad412019-04-20 07:39:11 +020024static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
Heinrich Schuchardt3127e7e2019-08-06 08:13:33 +020025static const efi_guid_t efi_pxe_base_code_protocol_guid =
26 EFI_PXE_BASE_CODE_PROTOCOL_GUID;
Alexander Graf94c4b992016-05-06 21:01:01 +020027static struct efi_pxe_packet *dhcp_ack;
Alexander Graf94c4b992016-05-06 21:01:01 +020028static void *new_tx_packet;
Heinrich Schuchardteb07c282018-12-01 00:16:32 +010029static void *transmit_buffer;
Patrick Wildtfab89102020-10-07 11:04:33 +020030static uchar **receive_buffer;
31static size_t *receive_lengths;
32static int rx_packet_idx;
33static int rx_packet_num;
Heinrich Schuchardt2f1a93f2022-11-26 16:44:38 +010034static struct efi_net_obj *netobj;
Heinrich Schuchardteb07c282018-12-01 00:16:32 +010035
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +020036/*
Adriano Cordova93cba0f2024-12-04 00:05:23 -030037 * The current network device path. This device path is updated when a new
38 * bootfile is downloaded from the network. If then the bootfile is loaded
39 * as an efi image, net_dp is passed as the device path of the loaded image.
40 */
41static struct efi_device_path *net_dp;
42
43/*
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +020044 * The notification function of this event is called in every timer cycle
45 * to check if a new network packet has been received.
46 */
47static struct efi_event *network_timer_event;
Heinrich Schuchardt0c153c22017-10-05 16:36:01 +020048/*
49 * This event is signaled when a packet has been received.
50 */
51static struct efi_event *wait_for_packet;
Alexander Graf94c4b992016-05-06 21:01:01 +020052
Heinrich Schuchardt72928722018-09-26 05:27:56 +020053/**
54 * struct efi_net_obj - EFI object representing a network interface
55 *
56 * @header: EFI object header
57 * @net: simple network protocol interface
58 * @net_mode: status of the network interface
59 * @pxe: PXE base code protocol interface
60 * @pxe_mode: status of the PXE base code protocol
61 */
Alexander Graf94c4b992016-05-06 21:01:01 +020062struct efi_net_obj {
Heinrich Schuchardt72928722018-09-26 05:27:56 +020063 struct efi_object header;
Alexander Graf94c4b992016-05-06 21:01:01 +020064 struct efi_simple_network net;
65 struct efi_simple_network_mode net_mode;
Heinrich Schuchardt3127e7e2019-08-06 08:13:33 +020066 struct efi_pxe_base_code_protocol pxe;
Alexander Graf94c4b992016-05-06 21:01:01 +020067 struct efi_pxe_mode pxe_mode;
68};
69
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +010070/*
71 * efi_net_start() - start the network interface
72 *
73 * This function implements the Start service of the
74 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
75 * (UEFI) specification for details.
76 *
77 * @this: pointer to the protocol instance
78 * Return: status code
79 */
Alexander Graf94c4b992016-05-06 21:01:01 +020080static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this)
81{
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +010082 efi_status_t ret = EFI_SUCCESS;
83
Alexander Graf94c4b992016-05-06 21:01:01 +020084 EFI_ENTRY("%p", this);
85
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +010086 /* Check parameters */
87 if (!this) {
88 ret = EFI_INVALID_PARAMETER;
89 goto out;
90 }
91
Heinrich Schuchardtd3f1ff22019-08-31 09:56:30 +020092 if (this->mode->state != EFI_NETWORK_STOPPED) {
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +010093 ret = EFI_ALREADY_STARTED;
Heinrich Schuchardtd3f1ff22019-08-31 09:56:30 +020094 } else {
95 this->int_status = 0;
96 wait_for_packet->is_signaled = false;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +010097 this->mode->state = EFI_NETWORK_STARTED;
Heinrich Schuchardtd3f1ff22019-08-31 09:56:30 +020098 }
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +010099out:
100 return EFI_EXIT(ret);
Alexander Graf94c4b992016-05-06 21:01:01 +0200101}
102
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100103/*
104 * efi_net_stop() - stop the network interface
105 *
106 * This function implements the Stop service of the
107 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
108 * (UEFI) specification for details.
109 *
110 * @this: pointer to the protocol instance
111 * Return: status code
112 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200113static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this)
114{
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100115 efi_status_t ret = EFI_SUCCESS;
116
Alexander Graf94c4b992016-05-06 21:01:01 +0200117 EFI_ENTRY("%p", this);
118
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100119 /* Check parameters */
120 if (!this) {
121 ret = EFI_INVALID_PARAMETER;
122 goto out;
123 }
124
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200125 if (this->mode->state == EFI_NETWORK_STOPPED) {
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100126 ret = EFI_NOT_STARTED;
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200127 } else {
128 /* Disable hardware and put it into the reset state */
129 eth_halt();
Patrick Wildtfab89102020-10-07 11:04:33 +0200130 /* Clear cache of packets */
131 rx_packet_num = 0;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100132 this->mode->state = EFI_NETWORK_STOPPED;
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200133 }
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100134out:
135 return EFI_EXIT(ret);
Alexander Graf94c4b992016-05-06 21:01:01 +0200136}
137
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200138/*
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100139 * efi_net_initialize() - initialize the network interface
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200140 *
141 * This function implements the Initialize service of the
142 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
143 * (UEFI) specification for details.
144 *
145 * @this: pointer to the protocol instance
146 * @extra_rx: extra receive buffer to be allocated
147 * @extra_tx: extra transmit buffer to be allocated
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100148 * Return: status code
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200149 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200150static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
151 ulong extra_rx, ulong extra_tx)
152{
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200153 int ret;
154 efi_status_t r = EFI_SUCCESS;
155
Alexander Graf94c4b992016-05-06 21:01:01 +0200156 EFI_ENTRY("%p, %lx, %lx", this, extra_rx, extra_tx);
157
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100158 /* Check parameters */
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200159 if (!this) {
160 r = EFI_INVALID_PARAMETER;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100161 goto out;
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200162 }
163
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200164 switch (this->mode->state) {
165 case EFI_NETWORK_INITIALIZED:
166 case EFI_NETWORK_STARTED:
167 break;
168 default:
169 r = EFI_NOT_STARTED;
170 goto out;
171 }
172
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200173 /* Setup packet buffers */
174 net_init();
175 /* Disable hardware and put it into the reset state */
176 eth_halt();
Patrick Wildtfab89102020-10-07 11:04:33 +0200177 /* Clear cache of packets */
178 rx_packet_num = 0;
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200179 /* Set current device according to environment variables */
180 eth_set_current();
181 /* Get hardware ready for send and receive operations */
182 ret = eth_init();
183 if (ret < 0) {
184 eth_halt();
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100185 this->mode->state = EFI_NETWORK_STOPPED;
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200186 r = EFI_DEVICE_ERROR;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100187 goto out;
188 } else {
Heinrich Schuchardtd3f1ff22019-08-31 09:56:30 +0200189 this->int_status = 0;
190 wait_for_packet->is_signaled = false;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100191 this->mode->state = EFI_NETWORK_INITIALIZED;
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200192 }
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100193out:
Heinrich Schuchardtad4d67c2018-04-03 22:06:52 +0200194 return EFI_EXIT(r);
Alexander Graf94c4b992016-05-06 21:01:01 +0200195}
196
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100197/*
198 * efi_net_reset() - reinitialize the network interface
199 *
200 * This function implements the Reset service of the
201 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
202 * (UEFI) specification for details.
203 *
204 * @this: pointer to the protocol instance
205 * @extended_verification: execute exhaustive verification
206 * Return: status code
207 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200208static efi_status_t EFIAPI efi_net_reset(struct efi_simple_network *this,
209 int extended_verification)
210{
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200211 efi_status_t ret;
212
Alexander Graf94c4b992016-05-06 21:01:01 +0200213 EFI_ENTRY("%p, %x", this, extended_verification);
214
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200215 /* Check parameters */
216 if (!this) {
217 ret = EFI_INVALID_PARAMETER;
218 goto out;
219 }
220
221 switch (this->mode->state) {
222 case EFI_NETWORK_INITIALIZED:
223 break;
224 case EFI_NETWORK_STOPPED:
225 ret = EFI_NOT_STARTED;
226 goto out;
227 default:
228 ret = EFI_DEVICE_ERROR;
229 goto out;
230 }
231
232 this->mode->state = EFI_NETWORK_STARTED;
233 ret = EFI_CALL(efi_net_initialize(this, 0, 0));
234out:
235 return EFI_EXIT(ret);
Alexander Graf94c4b992016-05-06 21:01:01 +0200236}
237
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100238/*
239 * efi_net_shutdown() - shut down the network interface
240 *
241 * This function implements the Shutdown service of the
242 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
243 * (UEFI) specification for details.
244 *
245 * @this: pointer to the protocol instance
246 * Return: status code
247 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200248static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this)
249{
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100250 efi_status_t ret = EFI_SUCCESS;
251
Alexander Graf94c4b992016-05-06 21:01:01 +0200252 EFI_ENTRY("%p", this);
253
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100254 /* Check parameters */
255 if (!this) {
256 ret = EFI_INVALID_PARAMETER;
257 goto out;
258 }
259
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200260 switch (this->mode->state) {
261 case EFI_NETWORK_INITIALIZED:
262 break;
263 case EFI_NETWORK_STOPPED:
264 ret = EFI_NOT_STARTED;
265 goto out;
266 default:
267 ret = EFI_DEVICE_ERROR;
268 goto out;
269 }
270
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100271 eth_halt();
Heinrich Schuchardtd3f1ff22019-08-31 09:56:30 +0200272 this->int_status = 0;
273 wait_for_packet->is_signaled = false;
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200274 this->mode->state = EFI_NETWORK_STARTED;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100275
276out:
277 return EFI_EXIT(ret);
Alexander Graf94c4b992016-05-06 21:01:01 +0200278}
279
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100280/*
281 * efi_net_receive_filters() - mange multicast receive filters
282 *
283 * This function implements the ReceiveFilters service of the
284 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
285 * (UEFI) specification for details.
286 *
287 * @this: pointer to the protocol instance
288 * @enable: bit mask of receive filters to enable
289 * @disable: bit mask of receive filters to disable
290 * @reset_mcast_filter: true resets contents of the filters
291 * @mcast_filter_count: number of hardware MAC addresses in the new filters list
292 * @mcast_filter: list of new filters
293 * Return: status code
294 */
295static efi_status_t EFIAPI efi_net_receive_filters
296 (struct efi_simple_network *this, u32 enable, u32 disable,
297 int reset_mcast_filter, ulong mcast_filter_count,
298 struct efi_mac_address *mcast_filter)
Alexander Graf94c4b992016-05-06 21:01:01 +0200299{
300 EFI_ENTRY("%p, %x, %x, %x, %lx, %p", this, enable, disable,
301 reset_mcast_filter, mcast_filter_count, mcast_filter);
302
Heinrich Schuchardta50b5c62017-10-05 16:35:59 +0200303 return EFI_EXIT(EFI_UNSUPPORTED);
Alexander Graf94c4b992016-05-06 21:01:01 +0200304}
305
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100306/*
307 * efi_net_station_address() - set the hardware MAC address
308 *
309 * This function implements the StationAddress service of the
310 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
311 * (UEFI) specification for details.
312 *
313 * @this: pointer to the protocol instance
314 * @reset: if true reset the address to default
315 * @new_mac: new MAC address
316 * Return: status code
317 */
318static efi_status_t EFIAPI efi_net_station_address
319 (struct efi_simple_network *this, int reset,
320 struct efi_mac_address *new_mac)
Alexander Graf94c4b992016-05-06 21:01:01 +0200321{
322 EFI_ENTRY("%p, %x, %p", this, reset, new_mac);
323
Heinrich Schuchardta50b5c62017-10-05 16:35:59 +0200324 return EFI_EXIT(EFI_UNSUPPORTED);
Alexander Graf94c4b992016-05-06 21:01:01 +0200325}
326
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100327/*
328 * efi_net_statistics() - reset or collect statistics of the network interface
329 *
330 * This function implements the Statistics service of the
331 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
332 * (UEFI) specification for details.
333 *
334 * @this: pointer to the protocol instance
335 * @reset: if true, the statistics are reset
336 * @stat_size: size of the statistics table
337 * @stat_table: table to receive the statistics
338 * Return: status code
339 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200340static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this,
341 int reset, ulong *stat_size,
342 void *stat_table)
343{
344 EFI_ENTRY("%p, %x, %p, %p", this, reset, stat_size, stat_table);
345
Heinrich Schuchardta50b5c62017-10-05 16:35:59 +0200346 return EFI_EXIT(EFI_UNSUPPORTED);
Alexander Graf94c4b992016-05-06 21:01:01 +0200347}
348
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100349/*
350 * efi_net_mcastiptomac() - translate multicast IP address to MAC address
351 *
Heinrich Schuchardt33b318d2019-09-01 17:17:53 +0200352 * This function implements the MCastIPtoMAC service of the
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100353 * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
354 * (UEFI) specification for details.
355 *
356 * @this: pointer to the protocol instance
357 * @ipv6: true if the IP address is an IPv6 address
358 * @ip: IP address
359 * @mac: MAC address
360 * Return: status code
361 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200362static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this,
363 int ipv6,
364 struct efi_ip_address *ip,
365 struct efi_mac_address *mac)
366{
Heinrich Schuchardt33b318d2019-09-01 17:17:53 +0200367 efi_status_t ret = EFI_SUCCESS;
368
Alexander Graf94c4b992016-05-06 21:01:01 +0200369 EFI_ENTRY("%p, %x, %p, %p", this, ipv6, ip, mac);
370
Heinrich Schuchardt33b318d2019-09-01 17:17:53 +0200371 if (!this || !ip || !mac) {
372 ret = EFI_INVALID_PARAMETER;
373 goto out;
374 }
375
376 if (ipv6) {
377 ret = EFI_UNSUPPORTED;
378 goto out;
379 }
380
381 /* Multi-cast addresses are in the range 224.0.0.0 - 239.255.255.255 */
382 if ((ip->ip_addr[0] & 0xf0) != 0xe0) {
383 ret = EFI_INVALID_PARAMETER;
384 goto out;
385 };
386
387 switch (this->mode->state) {
388 case EFI_NETWORK_INITIALIZED:
389 case EFI_NETWORK_STARTED:
390 break;
391 default:
392 ret = EFI_NOT_STARTED;
393 goto out;
394 }
395
396 memset(mac, 0, sizeof(struct efi_mac_address));
397
398 /*
399 * Copy lower 23 bits of IPv4 multi-cast address
400 * RFC 1112, RFC 7042 2.1.1.
401 */
402 mac->mac_addr[0] = 0x01;
403 mac->mac_addr[1] = 0x00;
404 mac->mac_addr[2] = 0x5E;
405 mac->mac_addr[3] = ip->ip_addr[1] & 0x7F;
406 mac->mac_addr[4] = ip->ip_addr[2];
407 mac->mac_addr[5] = ip->ip_addr[3];
408out:
409 return EFI_EXIT(ret);
Alexander Graf94c4b992016-05-06 21:01:01 +0200410}
411
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100412/**
413 * efi_net_nvdata() - read or write NVRAM
414 *
415 * This function implements the GetStatus service of the Simple Network
416 * Protocol. See the UEFI spec for details.
417 *
418 * @this: the instance of the Simple Network Protocol
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200419 * @read_write: true for read, false for write
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100420 * @offset: offset in NVRAM
421 * @buffer_size: size of buffer
422 * @buffer: buffer
423 * Return: status code
424 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200425static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this,
426 int read_write, ulong offset,
427 ulong buffer_size, char *buffer)
428{
429 EFI_ENTRY("%p, %x, %lx, %lx, %p", this, read_write, offset, buffer_size,
430 buffer);
431
Heinrich Schuchardta50b5c62017-10-05 16:35:59 +0200432 return EFI_EXIT(EFI_UNSUPPORTED);
Alexander Graf94c4b992016-05-06 21:01:01 +0200433}
434
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100435/**
436 * efi_net_get_status() - get interrupt status
437 *
438 * This function implements the GetStatus service of the Simple Network
439 * Protocol. See the UEFI spec for details.
440 *
441 * @this: the instance of the Simple Network Protocol
442 * @int_status: interface status
443 * @txbuf: transmission buffer
444 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200445static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this,
446 u32 *int_status, void **txbuf)
447{
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100448 efi_status_t ret = EFI_SUCCESS;
449
Alexander Graf94c4b992016-05-06 21:01:01 +0200450 EFI_ENTRY("%p, %p, %p", this, int_status, txbuf);
451
Heinrich Schuchardte371c5f2017-10-05 16:36:02 +0200452 efi_timer_check();
453
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100454 /* Check parameters */
455 if (!this) {
456 ret = EFI_INVALID_PARAMETER;
457 goto out;
458 }
459
460 switch (this->mode->state) {
461 case EFI_NETWORK_STOPPED:
462 ret = EFI_NOT_STARTED;
463 goto out;
464 case EFI_NETWORK_STARTED:
465 ret = EFI_DEVICE_ERROR;
466 goto out;
467 default:
468 break;
469 }
470
Heinrich Schuchardte371c5f2017-10-05 16:36:02 +0200471 if (int_status) {
Heinrich Schuchardtd3f1ff22019-08-31 09:56:30 +0200472 *int_status = this->int_status;
473 this->int_status = 0;
Heinrich Schuchardte371c5f2017-10-05 16:36:02 +0200474 }
Alexander Graf94c4b992016-05-06 21:01:01 +0200475 if (txbuf)
476 *txbuf = new_tx_packet;
477
478 new_tx_packet = NULL;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100479out:
480 return EFI_EXIT(ret);
Alexander Graf94c4b992016-05-06 21:01:01 +0200481}
482
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100483/**
484 * efi_net_transmit() - transmit a packet
485 *
486 * This function implements the Transmit service of the Simple Network Protocol.
487 * See the UEFI spec for details.
488 *
489 * @this: the instance of the Simple Network Protocol
490 * @header_size: size of the media header
491 * @buffer_size: size of the buffer to receive the packet
492 * @buffer: buffer to receive the packet
493 * @src_addr: source hardware MAC address
494 * @dest_addr: destination hardware MAC address
495 * @protocol: type of header to build
496 * Return: status code
497 */
498static efi_status_t EFIAPI efi_net_transmit
499 (struct efi_simple_network *this, size_t header_size,
500 size_t buffer_size, void *buffer,
501 struct efi_mac_address *src_addr,
502 struct efi_mac_address *dest_addr, u16 *protocol)
Alexander Graf94c4b992016-05-06 21:01:01 +0200503{
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100504 efi_status_t ret = EFI_SUCCESS;
505
Heinrich Schuchardtf66b2e32017-10-05 16:36:03 +0200506 EFI_ENTRY("%p, %lu, %lu, %p, %p, %p, %p", this,
507 (unsigned long)header_size, (unsigned long)buffer_size,
508 buffer, src_addr, dest_addr, protocol);
Alexander Graf94c4b992016-05-06 21:01:01 +0200509
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200510 efi_timer_check();
511
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100512 /* Check parameters */
Heinrich Schuchardtf286c2c2019-05-15 23:27:43 +0200513 if (!this || !buffer) {
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100514 ret = EFI_INVALID_PARAMETER;
515 goto out;
516 }
517
518 /* We do not support jumbo packets */
519 if (buffer_size > PKTSIZE_ALIGN) {
520 ret = EFI_INVALID_PARAMETER;
521 goto out;
522 }
523
Heinrich Schuchardt0218a8f2019-08-31 10:55:29 +0200524 /* At least the IP header has to fit into the buffer */
525 if (buffer_size < this->mode->media_header_size) {
526 ret = EFI_BUFFER_TOO_SMALL;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100527 goto out;
Alexander Graf94c4b992016-05-06 21:01:01 +0200528 }
529
Heinrich Schuchardt0218a8f2019-08-31 10:55:29 +0200530 /*
531 * TODO:
532 * Support VLANs. Use net_set_ether() for copying the header. Use a
533 * U_BOOT_ENV_CALLBACK to update the media header size.
534 */
535 if (header_size) {
536 struct ethernet_hdr *header = buffer;
537
538 if (!dest_addr || !protocol ||
539 header_size != this->mode->media_header_size) {
540 ret = EFI_INVALID_PARAMETER;
541 goto out;
542 }
543 if (!src_addr)
544 src_addr = &this->mode->current_address;
545
546 memcpy(header->et_dest, dest_addr, ARP_HLEN);
547 memcpy(header->et_src, src_addr, ARP_HLEN);
548 header->et_protlen = htons(*protocol);
549 }
550
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100551 switch (this->mode->state) {
552 case EFI_NETWORK_STOPPED:
553 ret = EFI_NOT_STARTED;
554 goto out;
555 case EFI_NETWORK_STARTED:
556 ret = EFI_DEVICE_ERROR;
557 goto out;
558 default:
559 break;
560 }
561
562 /* Ethernet packets always fit, just bounce */
Heinrich Schuchardteb07c282018-12-01 00:16:32 +0100563 memcpy(transmit_buffer, buffer, buffer_size);
564 net_send_packet(transmit_buffer, buffer_size);
Alexander Graf0b12b862016-09-06 14:26:27 +0200565
Alexander Graf94c4b992016-05-06 21:01:01 +0200566 new_tx_packet = buffer;
Heinrich Schuchardtd3f1ff22019-08-31 09:56:30 +0200567 this->int_status |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100568out:
569 return EFI_EXIT(ret);
Alexander Graf94c4b992016-05-06 21:01:01 +0200570}
571
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100572/**
573 * efi_net_receive() - receive a packet from a network interface
Heinrich Schuchardtf66b2e32017-10-05 16:36:03 +0200574 *
575 * This function implements the Receive service of the Simple Network Protocol.
576 * See the UEFI spec for details.
577 *
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100578 * @this: the instance of the Simple Network Protocol
579 * @header_size: size of the media header
580 * @buffer_size: size of the buffer to receive the packet
581 * @buffer: buffer to receive the packet
582 * @src_addr: source MAC address
583 * @dest_addr: destination MAC address
584 * @protocol: protocol
585 * Return: status code
Heinrich Schuchardtf66b2e32017-10-05 16:36:03 +0200586 */
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100587static efi_status_t EFIAPI efi_net_receive
588 (struct efi_simple_network *this, size_t *header_size,
589 size_t *buffer_size, void *buffer,
590 struct efi_mac_address *src_addr,
591 struct efi_mac_address *dest_addr, u16 *protocol)
Alexander Graf94c4b992016-05-06 21:01:01 +0200592{
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100593 efi_status_t ret = EFI_SUCCESS;
Heinrich Schuchardtaa0d1972017-10-05 16:36:04 +0200594 struct ethernet_hdr *eth_hdr;
595 size_t hdr_size = sizeof(struct ethernet_hdr);
596 u16 protlen;
597
Alexander Graf94c4b992016-05-06 21:01:01 +0200598 EFI_ENTRY("%p, %p, %p, %p, %p, %p, %p", this, header_size,
599 buffer_size, buffer, src_addr, dest_addr, protocol);
600
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100601 /* Execute events */
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200602 efi_timer_check();
Alexander Graf94c4b992016-05-06 21:01:01 +0200603
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100604 /* Check parameters */
Heinrich Schuchardtf286c2c2019-05-15 23:27:43 +0200605 if (!this || !buffer || !buffer_size) {
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100606 ret = EFI_INVALID_PARAMETER;
607 goto out;
608 }
609
610 switch (this->mode->state) {
611 case EFI_NETWORK_STOPPED:
612 ret = EFI_NOT_STARTED;
613 goto out;
614 case EFI_NETWORK_STARTED:
615 ret = EFI_DEVICE_ERROR;
616 goto out;
617 default:
618 break;
619 }
620
Patrick Wildtfab89102020-10-07 11:04:33 +0200621 if (!rx_packet_num) {
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100622 ret = EFI_NOT_READY;
623 goto out;
624 }
Heinrich Schuchardtaa0d1972017-10-05 16:36:04 +0200625 /* Fill export parameters */
Patrick Wildtfab89102020-10-07 11:04:33 +0200626 eth_hdr = (struct ethernet_hdr *)receive_buffer[rx_packet_idx];
Heinrich Schuchardtaa0d1972017-10-05 16:36:04 +0200627 protlen = ntohs(eth_hdr->et_protlen);
628 if (protlen == 0x8100) {
629 hdr_size += 4;
Patrick Wildtfab89102020-10-07 11:04:33 +0200630 protlen = ntohs(*(u16 *)&receive_buffer[rx_packet_idx][hdr_size - 2]);
Heinrich Schuchardtaa0d1972017-10-05 16:36:04 +0200631 }
632 if (header_size)
633 *header_size = hdr_size;
634 if (dest_addr)
635 memcpy(dest_addr, eth_hdr->et_dest, ARP_HLEN);
636 if (src_addr)
637 memcpy(src_addr, eth_hdr->et_src, ARP_HLEN);
638 if (protocol)
639 *protocol = protlen;
Patrick Wildtfab89102020-10-07 11:04:33 +0200640 if (*buffer_size < receive_lengths[rx_packet_idx]) {
Heinrich Schuchardt5e96f422018-10-18 21:51:38 +0200641 /* Packet doesn't fit, try again with bigger buffer */
Patrick Wildtfab89102020-10-07 11:04:33 +0200642 *buffer_size = receive_lengths[rx_packet_idx];
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100643 ret = EFI_BUFFER_TOO_SMALL;
644 goto out;
Alexander Graf94c4b992016-05-06 21:01:01 +0200645 }
Heinrich Schuchardtaa0d1972017-10-05 16:36:04 +0200646 /* Copy packet */
Patrick Wildtfab89102020-10-07 11:04:33 +0200647 memcpy(buffer, receive_buffer[rx_packet_idx],
648 receive_lengths[rx_packet_idx]);
649 *buffer_size = receive_lengths[rx_packet_idx];
650 rx_packet_idx = (rx_packet_idx + 1) % ETH_PACKETS_BATCH_RECV;
651 rx_packet_num--;
652 if (rx_packet_num)
653 wait_for_packet->is_signaled = true;
654 else
655 this->int_status &= ~EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100656out:
657 return EFI_EXIT(ret);
Alexander Graf94c4b992016-05-06 21:01:01 +0200658}
659
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100660/**
661 * efi_net_set_dhcp_ack() - take note of a selected DHCP IP address
662 *
663 * This function is called by dhcp_handler().
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200664 *
665 * @pkt: packet received by dhcp_handler()
666 * @len: length of the packet received
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100667 */
Alexander Graf94c4b992016-05-06 21:01:01 +0200668void efi_net_set_dhcp_ack(void *pkt, int len)
669{
670 int maxsize = sizeof(*dhcp_ack);
671
Heinrich Schuchardt2f1a93f2022-11-26 16:44:38 +0100672 if (!dhcp_ack) {
Alexander Graf94c4b992016-05-06 21:01:01 +0200673 dhcp_ack = malloc(maxsize);
Heinrich Schuchardt2f1a93f2022-11-26 16:44:38 +0100674 if (!dhcp_ack)
675 return;
676 }
677 memset(dhcp_ack, 0, maxsize);
Alexander Graf94c4b992016-05-06 21:01:01 +0200678 memcpy(dhcp_ack, pkt, min(len, maxsize));
Heinrich Schuchardt2f1a93f2022-11-26 16:44:38 +0100679
680 if (netobj)
681 netobj->pxe_mode.dhcp_ack = *dhcp_ack;
Alexander Graf94c4b992016-05-06 21:01:01 +0200682}
683
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100684/**
685 * efi_net_push() - callback for received network packet
686 *
687 * This function is called when a network packet is received by eth_rx().
688 *
689 * @pkt: network packet
690 * @len: length
691 */
692static void efi_net_push(void *pkt, int len)
693{
Patrick Wildtfab89102020-10-07 11:04:33 +0200694 int rx_packet_next;
695
696 /* Check that we at least received an Ethernet header */
697 if (len < sizeof(struct ethernet_hdr))
698 return;
699
700 /* Check that the buffer won't overflow */
701 if (len > PKTSIZE_ALIGN)
702 return;
703
704 /* Can't store more than pre-alloced buffer */
705 if (rx_packet_num >= ETH_PACKETS_BATCH_RECV)
706 return;
707
708 rx_packet_next = (rx_packet_idx + rx_packet_num) %
709 ETH_PACKETS_BATCH_RECV;
710 memcpy(receive_buffer[rx_packet_next], pkt, len);
711 receive_lengths[rx_packet_next] = len;
712
713 rx_packet_num++;
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100714}
715
716/**
717 * efi_network_timer_notify() - check if a new network packet has been received
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200718 *
719 * This notification function is called in every timer cycle.
720 *
Heinrich Schuchardtdc305ad2019-09-05 20:37:13 +0200721 * @event: the event for which this notification function is registered
722 * @context: event context - not used in this function
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200723 */
724static void EFIAPI efi_network_timer_notify(struct efi_event *event,
725 void *context)
726{
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100727 struct efi_simple_network *this = (struct efi_simple_network *)context;
728
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200729 EFI_ENTRY("%p, %p", event, context);
730
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100731 /*
732 * Some network drivers do not support calling eth_rx() before
733 * initialization.
734 */
735 if (!this || this->mode->state != EFI_NETWORK_INITIALIZED)
736 goto out;
737
Patrick Wildtfab89102020-10-07 11:04:33 +0200738 if (!rx_packet_num) {
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200739 push_packet = efi_net_push;
740 eth_rx();
741 push_packet = NULL;
Patrick Wildtfab89102020-10-07 11:04:33 +0200742 if (rx_packet_num) {
743 this->int_status |=
744 EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
745 wait_for_packet->is_signaled = true;
Heinrich Schuchardtd3f1ff22019-08-31 09:56:30 +0200746 }
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200747 }
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100748out:
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200749 EFI_EXIT(EFI_SUCCESS);
750}
751
Heinrich Schuchardt3127e7e2019-08-06 08:13:33 +0200752static efi_status_t EFIAPI efi_pxe_base_code_start(
753 struct efi_pxe_base_code_protocol *this,
754 u8 use_ipv6)
755{
756 return EFI_UNSUPPORTED;
757}
758
759static efi_status_t EFIAPI efi_pxe_base_code_stop(
760 struct efi_pxe_base_code_protocol *this)
761{
762 return EFI_UNSUPPORTED;
763}
764
765static efi_status_t EFIAPI efi_pxe_base_code_dhcp(
766 struct efi_pxe_base_code_protocol *this,
767 u8 sort_offers)
768{
769 return EFI_UNSUPPORTED;
770}
771
772static efi_status_t EFIAPI efi_pxe_base_code_discover(
773 struct efi_pxe_base_code_protocol *this,
774 u16 type, u16 *layer, u8 bis,
775 struct efi_pxe_base_code_discover_info *info)
776{
777 return EFI_UNSUPPORTED;
778}
779
780static efi_status_t EFIAPI efi_pxe_base_code_mtftp(
781 struct efi_pxe_base_code_protocol *this,
782 u32 operation, void *buffer_ptr,
783 u8 overwrite, efi_uintn_t *buffer_size,
784 struct efi_ip_address server_ip, char *filename,
785 struct efi_pxe_base_code_mtftp_info *info,
786 u8 dont_use_buffer)
787{
788 return EFI_UNSUPPORTED;
789}
790
791static efi_status_t EFIAPI efi_pxe_base_code_udp_write(
792 struct efi_pxe_base_code_protocol *this,
793 u16 op_flags, struct efi_ip_address *dest_ip,
794 u16 *dest_port,
795 struct efi_ip_address *gateway_ip,
796 struct efi_ip_address *src_ip, u16 *src_port,
797 efi_uintn_t *header_size, void *header_ptr,
798 efi_uintn_t *buffer_size, void *buffer_ptr)
799{
800 return EFI_UNSUPPORTED;
801}
802
803static efi_status_t EFIAPI efi_pxe_base_code_udp_read(
804 struct efi_pxe_base_code_protocol *this,
805 u16 op_flags, struct efi_ip_address *dest_ip,
806 u16 *dest_port, struct efi_ip_address *src_ip,
807 u16 *src_port, efi_uintn_t *header_size,
808 void *header_ptr, efi_uintn_t *buffer_size,
809 void *buffer_ptr)
810{
811 return EFI_UNSUPPORTED;
812}
813
814static efi_status_t EFIAPI efi_pxe_base_code_set_ip_filter(
815 struct efi_pxe_base_code_protocol *this,
816 struct efi_pxe_base_code_filter *new_filter)
817{
818 return EFI_UNSUPPORTED;
819}
820
821static efi_status_t EFIAPI efi_pxe_base_code_arp(
822 struct efi_pxe_base_code_protocol *this,
823 struct efi_ip_address *ip_addr,
824 struct efi_mac_address *mac_addr)
825{
826 return EFI_UNSUPPORTED;
827}
828
829static efi_status_t EFIAPI efi_pxe_base_code_set_parameters(
830 struct efi_pxe_base_code_protocol *this,
831 u8 *new_auto_arp, u8 *new_send_guid,
832 u8 *new_ttl, u8 *new_tos,
833 u8 *new_make_callback)
834{
835 return EFI_UNSUPPORTED;
836}
837
838static efi_status_t EFIAPI efi_pxe_base_code_set_station_ip(
839 struct efi_pxe_base_code_protocol *this,
840 struct efi_ip_address *new_station_ip,
841 struct efi_ip_address *new_subnet_mask)
842{
843 return EFI_UNSUPPORTED;
844}
845
846static efi_status_t EFIAPI efi_pxe_base_code_set_packets(
847 struct efi_pxe_base_code_protocol *this,
848 u8 *new_dhcp_discover_valid,
849 u8 *new_dhcp_ack_received,
850 u8 *new_proxy_offer_received,
851 u8 *new_pxe_discover_valid,
852 u8 *new_pxe_reply_received,
853 u8 *new_pxe_bis_reply_received,
854 EFI_PXE_BASE_CODE_PACKET *new_dchp_discover,
855 EFI_PXE_BASE_CODE_PACKET *new_dhcp_acc,
856 EFI_PXE_BASE_CODE_PACKET *new_proxy_offer,
857 EFI_PXE_BASE_CODE_PACKET *new_pxe_discover,
858 EFI_PXE_BASE_CODE_PACKET *new_pxe_reply,
859 EFI_PXE_BASE_CODE_PACKET *new_pxe_bis_reply)
860{
861 return EFI_UNSUPPORTED;
862}
863
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100864/**
865 * efi_net_register() - register the simple network protocol
866 *
867 * This gets called from do_bootefi_exec().
868 */
Heinrich Schuchardt6f5c73f2018-03-03 15:28:56 +0100869efi_status_t efi_net_register(void)
Alexander Graf94c4b992016-05-06 21:01:01 +0200870{
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200871 efi_status_t r;
Patrick Wildtfab89102020-10-07 11:04:33 +0200872 int i;
Alexander Graf94c4b992016-05-06 21:01:01 +0200873
874 if (!eth_get_dev()) {
Heinrich Schuchardt5e96f422018-10-18 21:51:38 +0200875 /* No network device active, don't expose any */
Heinrich Schuchardt6f5c73f2018-03-03 15:28:56 +0100876 return EFI_SUCCESS;
Alexander Graf94c4b992016-05-06 21:01:01 +0200877 }
878
Heinrich Schuchardt5e96f422018-10-18 21:51:38 +0200879 /* We only expose the "active" network device, so one is enough */
Alexander Graf94c4b992016-05-06 21:01:01 +0200880 netobj = calloc(1, sizeof(*netobj));
Heinrich Schuchardteb07c282018-12-01 00:16:32 +0100881 if (!netobj)
882 goto out_of_resources;
883
884 /* Allocate an aligned transmit buffer */
885 transmit_buffer = calloc(1, PKTSIZE_ALIGN + PKTALIGN);
886 if (!transmit_buffer)
887 goto out_of_resources;
888 transmit_buffer = (void *)ALIGN((uintptr_t)transmit_buffer, PKTALIGN);
Heinrich Schuchardt23b45b62017-11-26 14:05:13 +0100889
Patrick Wildtfab89102020-10-07 11:04:33 +0200890 /* Allocate a number of receive buffers */
891 receive_buffer = calloc(ETH_PACKETS_BATCH_RECV,
892 sizeof(*receive_buffer));
893 if (!receive_buffer)
894 goto out_of_resources;
895 for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++) {
896 receive_buffer[i] = malloc(PKTSIZE_ALIGN);
897 if (!receive_buffer[i])
898 goto out_of_resources;
899 }
900 receive_lengths = calloc(ETH_PACKETS_BATCH_RECV,
901 sizeof(*receive_lengths));
902 if (!receive_lengths)
903 goto out_of_resources;
904
Heinrich Schuchardt23b45b62017-11-26 14:05:13 +0100905 /* Hook net up to the device list */
Heinrich Schuchardt72928722018-09-26 05:27:56 +0200906 efi_add_handle(&netobj->header);
Alexander Graf94c4b992016-05-06 21:01:01 +0200907
908 /* Fill in object data */
Heinrich Schuchardt72928722018-09-26 05:27:56 +0200909 r = efi_add_protocol(&netobj->header, &efi_net_guid,
Heinrich Schuchardt23b45b62017-11-26 14:05:13 +0100910 &netobj->net);
911 if (r != EFI_SUCCESS)
Heinrich Schuchardt6f5c73f2018-03-03 15:28:56 +0100912 goto failure_to_add_protocol;
Adriano Cordova93cba0f2024-12-04 00:05:23 -0300913 if (!net_dp)
914 efi_net_set_dp("Net", NULL);
Heinrich Schuchardt72928722018-09-26 05:27:56 +0200915 r = efi_add_protocol(&netobj->header, &efi_guid_device_path,
Adriano Cordova93cba0f2024-12-04 00:05:23 -0300916 net_dp);
Heinrich Schuchardt23b45b62017-11-26 14:05:13 +0100917 if (r != EFI_SUCCESS)
Heinrich Schuchardt6f5c73f2018-03-03 15:28:56 +0100918 goto failure_to_add_protocol;
Heinrich Schuchardt3127e7e2019-08-06 08:13:33 +0200919 r = efi_add_protocol(&netobj->header, &efi_pxe_base_code_protocol_guid,
Heinrich Schuchardt23b45b62017-11-26 14:05:13 +0100920 &netobj->pxe);
921 if (r != EFI_SUCCESS)
Heinrich Schuchardt6f5c73f2018-03-03 15:28:56 +0100922 goto failure_to_add_protocol;
Heinrich Schuchardtd54396a2017-10-05 16:35:57 +0200923 netobj->net.revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
Alexander Graf94c4b992016-05-06 21:01:01 +0200924 netobj->net.start = efi_net_start;
925 netobj->net.stop = efi_net_stop;
926 netobj->net.initialize = efi_net_initialize;
927 netobj->net.reset = efi_net_reset;
928 netobj->net.shutdown = efi_net_shutdown;
929 netobj->net.receive_filters = efi_net_receive_filters;
930 netobj->net.station_address = efi_net_station_address;
931 netobj->net.statistics = efi_net_statistics;
932 netobj->net.mcastiptomac = efi_net_mcastiptomac;
933 netobj->net.nvdata = efi_net_nvdata;
934 netobj->net.get_status = efi_net_get_status;
935 netobj->net.transmit = efi_net_transmit;
936 netobj->net.receive = efi_net_receive;
937 netobj->net.mode = &netobj->net_mode;
Heinrich Schuchardt6a6e7d82019-09-01 15:24:47 +0200938 netobj->net_mode.state = EFI_NETWORK_STOPPED;
Alexander Graf94c4b992016-05-06 21:01:01 +0200939 memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6);
Heinrich Schuchardtd1cc6cb2017-10-05 16:35:58 +0200940 netobj->net_mode.hwaddr_size = ARP_HLEN;
Heinrich Schuchardt0218a8f2019-08-31 10:55:29 +0200941 netobj->net_mode.media_header_size = ETHER_HDR_SIZE;
Alexander Graf94c4b992016-05-06 21:01:01 +0200942 netobj->net_mode.max_packet_size = PKTSIZE;
Andrew Thomas27df0a72018-06-21 16:21:01 -0700943 netobj->net_mode.if_type = ARP_ETHER;
Alexander Graf94c4b992016-05-06 21:01:01 +0200944
Heinrich Schuchardt3127e7e2019-08-06 08:13:33 +0200945 netobj->pxe.revision = EFI_PXE_BASE_CODE_PROTOCOL_REVISION;
946 netobj->pxe.start = efi_pxe_base_code_start;
947 netobj->pxe.stop = efi_pxe_base_code_stop;
948 netobj->pxe.dhcp = efi_pxe_base_code_dhcp;
949 netobj->pxe.discover = efi_pxe_base_code_discover;
950 netobj->pxe.mtftp = efi_pxe_base_code_mtftp;
951 netobj->pxe.udp_write = efi_pxe_base_code_udp_write;
952 netobj->pxe.udp_read = efi_pxe_base_code_udp_read;
953 netobj->pxe.set_ip_filter = efi_pxe_base_code_set_ip_filter;
954 netobj->pxe.arp = efi_pxe_base_code_arp;
955 netobj->pxe.set_parameters = efi_pxe_base_code_set_parameters;
956 netobj->pxe.set_station_ip = efi_pxe_base_code_set_station_ip;
957 netobj->pxe.set_packets = efi_pxe_base_code_set_packets;
Alexander Graf94c4b992016-05-06 21:01:01 +0200958 netobj->pxe.mode = &netobj->pxe_mode;
959 if (dhcp_ack)
960 netobj->pxe_mode.dhcp_ack = *dhcp_ack;
961
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200962 /*
Heinrich Schuchardt0c153c22017-10-05 16:36:01 +0200963 * Create WaitForPacket event.
964 */
965 r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK,
Heinrich Schuchardtbf7f1692018-02-18 15:17:52 +0100966 efi_network_timer_notify, NULL, NULL,
Heinrich Schuchardt0c153c22017-10-05 16:36:01 +0200967 &wait_for_packet);
968 if (r != EFI_SUCCESS) {
969 printf("ERROR: Failed to register network event\n");
970 return r;
971 }
972 netobj->net.wait_for_packet = wait_for_packet;
973 /*
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200974 * Create a timer event.
975 *
976 * The notification function is used to check if a new network packet
977 * has been received.
Heinrich Schuchardt86df48c2018-03-24 18:40:22 +0100978 *
979 * iPXE is running at TPL_CALLBACK most of the time. Use a higher TPL.
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200980 */
Heinrich Schuchardt86df48c2018-03-24 18:40:22 +0100981 r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_NOTIFY,
Heinrich Schuchardtb6f20362018-12-01 00:16:33 +0100982 efi_network_timer_notify, &netobj->net, NULL,
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200983 &network_timer_event);
984 if (r != EFI_SUCCESS) {
985 printf("ERROR: Failed to register network event\n");
986 return r;
987 }
Heinrich Schuchardt5e96f422018-10-18 21:51:38 +0200988 /* Network is time critical, create event in every timer cycle */
Heinrich Schuchardt3d7fc692017-10-05 16:36:00 +0200989 r = efi_set_timer(network_timer_event, EFI_TIMER_PERIODIC, 0);
990 if (r != EFI_SUCCESS) {
991 printf("ERROR: Failed to set network timer\n");
992 return r;
993 }
994
Heinrich Schuchardt6f5c73f2018-03-03 15:28:56 +0100995 return EFI_SUCCESS;
996failure_to_add_protocol:
997 printf("ERROR: Failure to add protocol\n");
998 return r;
Heinrich Schuchardteb07c282018-12-01 00:16:32 +0100999out_of_resources:
1000 free(netobj);
Heinrich Schuchardt2f1a93f2022-11-26 16:44:38 +01001001 netobj = NULL;
Patrick Wildtfab89102020-10-07 11:04:33 +02001002 free(transmit_buffer);
1003 if (receive_buffer)
1004 for (i = 0; i < ETH_PACKETS_BATCH_RECV; i++)
1005 free(receive_buffer[i]);
1006 free(receive_buffer);
1007 free(receive_lengths);
Heinrich Schuchardteb07c282018-12-01 00:16:32 +01001008 printf("ERROR: Out of memory\n");
1009 return EFI_OUT_OF_RESOURCES;
Alexander Graf94c4b992016-05-06 21:01:01 +02001010}
Adriano Cordova3c951362024-12-04 00:05:21 -03001011
1012/**
Adriano Cordova93cba0f2024-12-04 00:05:23 -03001013 * efi_net_set_dp() - set device path of efi net device
1014 *
1015 * This gets called to update the device path when a new boot
1016 * file is downloaded
1017 *
1018 * @dev: dev to set the device path from
1019 * @server: remote server address
1020 * Return: status code
1021 */
1022efi_status_t efi_net_set_dp(const char *dev, const char *server)
1023{
1024 efi_free_pool(net_dp);
1025
1026 net_dp = NULL;
1027 if (!strcmp(dev, "Net"))
1028 net_dp = efi_dp_from_eth();
1029 else if (!strcmp(dev, "Http"))
1030 net_dp = efi_dp_from_http(server);
1031
1032 if (!net_dp)
1033 return EFI_OUT_OF_RESOURCES;
1034
1035 return EFI_SUCCESS;
1036}
1037
1038/**
1039 * efi_net_get_dp() - get device path of efi net device
1040 *
1041 * Produce a copy of the current device path
1042 *
1043 * @dp: copy of the current device path, or NULL on error
1044 */
1045void efi_net_get_dp(struct efi_device_path **dp)
1046{
1047 if (!dp)
1048 return;
1049 if (!net_dp)
1050 efi_net_set_dp("Net", NULL);
1051 if (net_dp)
1052 *dp = efi_dp_dup(net_dp);
1053}
1054
1055/**
Adriano Cordova3c951362024-12-04 00:05:21 -03001056 * efi_net_get_addr() - get IP address information
1057 *
1058 * Copy the current IP address, mask, and gateway into the
1059 * efi_ipv4_address structs pointed to by ip, mask and gw,
1060 * respectively.
1061 *
1062 * @ip: pointer to an efi_ipv4_address struct to
1063 * be filled with the current IP address
1064 * @mask: pointer to an efi_ipv4_address struct to
1065 * be filled with the current network mask
1066 * @gw: pointer to an efi_ipv4_address struct to be
1067 * filled with the current network gateway
1068 */
1069void efi_net_get_addr(struct efi_ipv4_address *ip,
1070 struct efi_ipv4_address *mask,
1071 struct efi_ipv4_address *gw)
1072{
1073#ifdef CONFIG_NET_LWIP
1074 char ipstr[] = "ipaddr\0\0";
1075 char maskstr[] = "netmask\0\0";
1076 char gwstr[] = "gatewayip\0\0";
1077 int idx;
1078 struct in_addr tmp;
1079 char *env;
1080
1081 idx = dev_seq(eth_get_dev());
1082
1083 if (idx < 0 || idx > 99) {
1084 log_err("unexpected idx %d\n", idx);
1085 return;
1086 }
1087
1088 if (idx) {
1089 sprintf(ipstr, "ipaddr%d", idx);
1090 sprintf(maskstr, "netmask%d", idx);
1091 sprintf(gwstr, "gatewayip%d", idx);
1092 }
1093
1094 env = env_get(ipstr);
1095 if (env && ip) {
1096 tmp = string_to_ip(env);
1097 memcpy(ip, &tmp, sizeof(tmp));
1098 }
1099
1100 env = env_get(maskstr);
1101 if (env && mask) {
1102 tmp = string_to_ip(env);
1103 memcpy(mask, &tmp, sizeof(tmp));
1104 }
1105 env = env_get(gwstr);
1106 if (env && gw) {
1107 tmp = string_to_ip(env);
1108 memcpy(gw, &tmp, sizeof(tmp));
1109 }
1110#else
1111 if (ip)
1112 memcpy(ip, &net_ip, sizeof(net_ip));
1113 if (mask)
1114 memcpy(mask, &net_netmask, sizeof(net_netmask));
1115#endif
1116}
1117
1118/**
1119 * efi_net_set_addr() - set IP address information
1120 *
1121 * Set the current IP address, mask, and gateway to the
1122 * efi_ipv4_address structs pointed to by ip, mask and gw,
1123 * respectively.
1124 *
1125 * @ip: pointer to new IP address
1126 * @mask: pointer to new network mask to set
1127 * @gw: pointer to new network gateway
1128 */
1129void efi_net_set_addr(struct efi_ipv4_address *ip,
1130 struct efi_ipv4_address *mask,
1131 struct efi_ipv4_address *gw)
1132{
1133#ifdef CONFIG_NET_LWIP
1134 char ipstr[] = "ipaddr\0\0";
1135 char maskstr[] = "netmask\0\0";
1136 char gwstr[] = "gatewayip\0\0";
1137 int idx;
1138 struct in_addr *addr;
1139 char tmp[46];
1140
1141 idx = dev_seq(eth_get_dev());
1142
1143 if (idx < 0 || idx > 99) {
1144 log_err("unexpected idx %d\n", idx);
1145 return;
1146 }
1147
1148 if (idx) {
1149 sprintf(ipstr, "ipaddr%d", idx);
1150 sprintf(maskstr, "netmask%d", idx);
1151 sprintf(gwstr, "gatewayip%d", idx);
1152 }
1153
1154 if (ip) {
1155 addr = (struct in_addr *)ip;
1156 ip_to_string(*addr, tmp);
1157 env_set(ipstr, tmp);
1158 }
1159
1160 if (mask) {
1161 addr = (struct in_addr *)mask;
1162 ip_to_string(*addr, tmp);
1163 env_set(maskstr, tmp);
1164 }
1165
1166 if (gw) {
1167 addr = (struct in_addr *)gw;
1168 ip_to_string(*addr, tmp);
1169 env_set(gwstr, tmp);
1170 }
1171#else
1172 if (ip)
1173 memcpy(&net_ip, ip, sizeof(*ip));
1174 if (mask)
1175 memcpy(&net_netmask, mask, sizeof(*mask));
1176#endif
1177}