xref: /openbmc/u-boot/lib/efi_loader/efi_net.c (revision 9450ab2b)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  *  EFI application network access support
4  *
5  *  Copyright (c) 2016 Alexander Graf
6  */
7 
8 #include <common.h>
9 #include <efi_loader.h>
10 #include <malloc.h>
11 
12 static const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_GUID;
13 static const efi_guid_t efi_pxe_guid = EFI_PXE_GUID;
14 static struct efi_pxe_packet *dhcp_ack;
15 static bool new_rx_packet;
16 static void *new_tx_packet;
17 static void *transmit_buffer;
18 
19 /*
20  * The notification function of this event is called in every timer cycle
21  * to check if a new network packet has been received.
22  */
23 static struct efi_event *network_timer_event;
24 /*
25  * This event is signaled when a packet has been received.
26  */
27 static struct efi_event *wait_for_packet;
28 
29 /**
30  * struct efi_net_obj - EFI object representing a network interface
31  *
32  * @header:	EFI object header
33  * @net:	simple network protocol interface
34  * @net_mode:	status of the network interface
35  * @pxe:	PXE base code protocol interface
36  * @pxe_mode:	status of the PXE base code protocol
37  */
38 struct efi_net_obj {
39 	struct efi_object header;
40 	struct efi_simple_network net;
41 	struct efi_simple_network_mode net_mode;
42 	struct efi_pxe pxe;
43 	struct efi_pxe_mode pxe_mode;
44 };
45 
46 /*
47  * efi_net_start() - start the network interface
48  *
49  * This function implements the Start service of the
50  * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
51  * (UEFI) specification for details.
52  *
53  * @this:	pointer to the protocol instance
54  * Return:	status code
55  */
efi_net_start(struct efi_simple_network * this)56 static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this)
57 {
58 	efi_status_t ret = EFI_SUCCESS;
59 
60 	EFI_ENTRY("%p", this);
61 
62 	/* Check parameters */
63 	if (!this) {
64 		ret = EFI_INVALID_PARAMETER;
65 		goto out;
66 	}
67 
68 	if (this->mode->state != EFI_NETWORK_STOPPED)
69 		ret = EFI_ALREADY_STARTED;
70 	else
71 		this->mode->state = EFI_NETWORK_STARTED;
72 out:
73 	return EFI_EXIT(ret);
74 }
75 
76 /*
77  * efi_net_stop() - stop the network interface
78  *
79  * This function implements the Stop service of the
80  * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
81  * (UEFI) specification for details.
82  *
83  * @this:	pointer to the protocol instance
84  * Return:	status code
85  */
efi_net_stop(struct efi_simple_network * this)86 static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this)
87 {
88 	efi_status_t ret = EFI_SUCCESS;
89 
90 	EFI_ENTRY("%p", this);
91 
92 	/* Check parameters */
93 	if (!this) {
94 		ret = EFI_INVALID_PARAMETER;
95 		goto out;
96 	}
97 
98 	if (this->mode->state == EFI_NETWORK_STOPPED)
99 		ret = EFI_NOT_STARTED;
100 	else
101 		this->mode->state = EFI_NETWORK_STOPPED;
102 out:
103 	return EFI_EXIT(ret);
104 }
105 
106 /*
107  * efi_net_initialize() - initialize the network interface
108  *
109  * This function implements the Initialize service of the
110  * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
111  * (UEFI) specification for details.
112  *
113  * @this:	pointer to the protocol instance
114  * @extra_rx:	extra receive buffer to be allocated
115  * @extra_tx:	extra transmit buffer to be allocated
116  * Return:	status code
117  */
efi_net_initialize(struct efi_simple_network * this,ulong extra_rx,ulong extra_tx)118 static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
119 					      ulong extra_rx, ulong extra_tx)
120 {
121 	int ret;
122 	efi_status_t r = EFI_SUCCESS;
123 
124 	EFI_ENTRY("%p, %lx, %lx", this, extra_rx, extra_tx);
125 
126 	/* Check parameters */
127 	if (!this) {
128 		r = EFI_INVALID_PARAMETER;
129 		goto out;
130 	}
131 
132 	/* Setup packet buffers */
133 	net_init();
134 	/* Disable hardware and put it into the reset state */
135 	eth_halt();
136 	/* Set current device according to environment variables */
137 	eth_set_current();
138 	/* Get hardware ready for send and receive operations */
139 	ret = eth_init();
140 	if (ret < 0) {
141 		eth_halt();
142 		this->mode->state = EFI_NETWORK_STOPPED;
143 		r = EFI_DEVICE_ERROR;
144 		goto out;
145 	} else {
146 		this->mode->state = EFI_NETWORK_INITIALIZED;
147 	}
148 out:
149 	return EFI_EXIT(r);
150 }
151 
152 /*
153  * efi_net_reset() - reinitialize the network interface
154  *
155  * This function implements the Reset service of the
156  * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
157  * (UEFI) specification for details.
158  *
159  * @this:			pointer to the protocol instance
160  * @extended_verification:	execute exhaustive verification
161  * Return:			status code
162  */
efi_net_reset(struct efi_simple_network * this,int extended_verification)163 static efi_status_t EFIAPI efi_net_reset(struct efi_simple_network *this,
164 					 int extended_verification)
165 {
166 	EFI_ENTRY("%p, %x", this, extended_verification);
167 
168 	return EFI_EXIT(EFI_CALL(efi_net_initialize(this, 0, 0)));
169 }
170 
171 /*
172  * efi_net_shutdown() - shut down the network interface
173  *
174  * This function implements the Shutdown service of the
175  * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
176  * (UEFI) specification for details.
177  *
178  * @this:	pointer to the protocol instance
179  * Return:	status code
180  */
efi_net_shutdown(struct efi_simple_network * this)181 static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this)
182 {
183 	efi_status_t ret = EFI_SUCCESS;
184 
185 	EFI_ENTRY("%p", this);
186 
187 	/* Check parameters */
188 	if (!this) {
189 		ret = EFI_INVALID_PARAMETER;
190 		goto out;
191 	}
192 
193 	eth_halt();
194 	this->mode->state = EFI_NETWORK_STOPPED;
195 
196 out:
197 	return EFI_EXIT(ret);
198 }
199 
200 /*
201  * efi_net_receive_filters() - mange multicast receive filters
202  *
203  * This function implements the ReceiveFilters service of the
204  * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
205  * (UEFI) specification for details.
206  *
207  * @this:		pointer to the protocol instance
208  * @enable:		bit mask of receive filters to enable
209  * @disable:		bit mask of receive filters to disable
210  * @reset_mcast_filter:	true resets contents of the filters
211  * @mcast_filter_count:	number of hardware MAC addresses in the new filters list
212  * @mcast_filter:	list of new filters
213  * Return:		status code
214  */
efi_net_receive_filters(struct efi_simple_network * this,u32 enable,u32 disable,int reset_mcast_filter,ulong mcast_filter_count,struct efi_mac_address * mcast_filter)215 static efi_status_t EFIAPI efi_net_receive_filters
216 		(struct efi_simple_network *this, u32 enable, u32 disable,
217 		 int reset_mcast_filter, ulong mcast_filter_count,
218 		 struct efi_mac_address *mcast_filter)
219 {
220 	EFI_ENTRY("%p, %x, %x, %x, %lx, %p", this, enable, disable,
221 		  reset_mcast_filter, mcast_filter_count, mcast_filter);
222 
223 	return EFI_EXIT(EFI_UNSUPPORTED);
224 }
225 
226 /*
227  * efi_net_station_address() - set the hardware MAC address
228  *
229  * This function implements the StationAddress service of the
230  * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
231  * (UEFI) specification for details.
232  *
233  * @this:	pointer to the protocol instance
234  * @reset:	if true reset the address to default
235  * @new_mac:	new MAC address
236  * Return:	status code
237  */
efi_net_station_address(struct efi_simple_network * this,int reset,struct efi_mac_address * new_mac)238 static efi_status_t EFIAPI efi_net_station_address
239 		(struct efi_simple_network *this, int reset,
240 		 struct efi_mac_address *new_mac)
241 {
242 	EFI_ENTRY("%p, %x, %p", this, reset, new_mac);
243 
244 	return EFI_EXIT(EFI_UNSUPPORTED);
245 }
246 
247 /*
248  * efi_net_statistics() - reset or collect statistics of the network interface
249  *
250  * This function implements the Statistics service of the
251  * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
252  * (UEFI) specification for details.
253  *
254  * @this:	pointer to the protocol instance
255  * @reset:	if true, the statistics are reset
256  * @stat_size:	size of the statistics table
257  * @stat_table:	table to receive the statistics
258  * Return:	status code
259  */
efi_net_statistics(struct efi_simple_network * this,int reset,ulong * stat_size,void * stat_table)260 static efi_status_t EFIAPI efi_net_statistics(struct efi_simple_network *this,
261 					      int reset, ulong *stat_size,
262 					      void *stat_table)
263 {
264 	EFI_ENTRY("%p, %x, %p, %p", this, reset, stat_size, stat_table);
265 
266 	return EFI_EXIT(EFI_UNSUPPORTED);
267 }
268 
269 /*
270  * efi_net_mcastiptomac() - translate multicast IP address to MAC address
271  *
272  * This function implements the Statistics service of the
273  * EFI_SIMPLE_NETWORK_PROTOCOL. See the Unified Extensible Firmware Interface
274  * (UEFI) specification for details.
275  *
276  * @this:	pointer to the protocol instance
277  * @ipv6:	true if the IP address is an IPv6 address
278  * @ip:		IP address
279  * @mac:	MAC address
280  * Return:	status code
281  */
efi_net_mcastiptomac(struct efi_simple_network * this,int ipv6,struct efi_ip_address * ip,struct efi_mac_address * mac)282 static efi_status_t EFIAPI efi_net_mcastiptomac(struct efi_simple_network *this,
283 						int ipv6,
284 						struct efi_ip_address *ip,
285 						struct efi_mac_address *mac)
286 {
287 	EFI_ENTRY("%p, %x, %p, %p", this, ipv6, ip, mac);
288 
289 	return EFI_EXIT(EFI_INVALID_PARAMETER);
290 }
291 
292 /**
293  * efi_net_nvdata() - read or write NVRAM
294  *
295  * This function implements the GetStatus service of the Simple Network
296  * Protocol. See the UEFI spec for details.
297  *
298  * @this:		the instance of the Simple Network Protocol
299  * @readwrite:		true for read, false for write
300  * @offset:		offset in NVRAM
301  * @buffer_size:	size of buffer
302  * @buffer:		buffer
303  * Return:		status code
304  */
efi_net_nvdata(struct efi_simple_network * this,int read_write,ulong offset,ulong buffer_size,char * buffer)305 static efi_status_t EFIAPI efi_net_nvdata(struct efi_simple_network *this,
306 					  int read_write, ulong offset,
307 					  ulong buffer_size, char *buffer)
308 {
309 	EFI_ENTRY("%p, %x, %lx, %lx, %p", this, read_write, offset, buffer_size,
310 		  buffer);
311 
312 	return EFI_EXIT(EFI_UNSUPPORTED);
313 }
314 
315 /**
316  * efi_net_get_status() - get interrupt status
317  *
318  * This function implements the GetStatus service of the Simple Network
319  * Protocol. See the UEFI spec for details.
320  *
321  * @this:		the instance of the Simple Network Protocol
322  * @int_status:		interface status
323  * @txbuf:		transmission buffer
324  */
efi_net_get_status(struct efi_simple_network * this,u32 * int_status,void ** txbuf)325 static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this,
326 					      u32 *int_status, void **txbuf)
327 {
328 	efi_status_t ret = EFI_SUCCESS;
329 
330 	EFI_ENTRY("%p, %p, %p", this, int_status, txbuf);
331 
332 	efi_timer_check();
333 
334 	/* Check parameters */
335 	if (!this) {
336 		ret = EFI_INVALID_PARAMETER;
337 		goto out;
338 	}
339 
340 	switch (this->mode->state) {
341 	case EFI_NETWORK_STOPPED:
342 		ret = EFI_NOT_STARTED;
343 		goto out;
344 	case EFI_NETWORK_STARTED:
345 		ret = EFI_DEVICE_ERROR;
346 		goto out;
347 	default:
348 		break;
349 	}
350 
351 	if (int_status) {
352 		/* We send packets synchronously, so nothing is outstanding */
353 		*int_status = EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
354 		if (new_rx_packet)
355 			*int_status |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
356 	}
357 	if (txbuf)
358 		*txbuf = new_tx_packet;
359 
360 	new_tx_packet = NULL;
361 out:
362 	return EFI_EXIT(ret);
363 }
364 
365 /**
366  * efi_net_transmit() - transmit a packet
367  *
368  * This function implements the Transmit service of the Simple Network Protocol.
369  * See the UEFI spec for details.
370  *
371  * @this:		the instance of the Simple Network Protocol
372  * @header_size:	size of the media header
373  * @buffer_size:	size of the buffer to receive the packet
374  * @buffer:		buffer to receive the packet
375  * @src_addr:		source hardware MAC address
376  * @dest_addr:		destination hardware MAC address
377  * @protocol:		type of header to build
378  * Return:		status code
379  */
efi_net_transmit(struct efi_simple_network * this,size_t header_size,size_t buffer_size,void * buffer,struct efi_mac_address * src_addr,struct efi_mac_address * dest_addr,u16 * protocol)380 static efi_status_t EFIAPI efi_net_transmit
381 		(struct efi_simple_network *this, size_t header_size,
382 		 size_t buffer_size, void *buffer,
383 		 struct efi_mac_address *src_addr,
384 		 struct efi_mac_address *dest_addr, u16 *protocol)
385 {
386 	efi_status_t ret = EFI_SUCCESS;
387 
388 	EFI_ENTRY("%p, %lu, %lu, %p, %p, %p, %p", this,
389 		  (unsigned long)header_size, (unsigned long)buffer_size,
390 		  buffer, src_addr, dest_addr, protocol);
391 
392 	efi_timer_check();
393 
394 	/* Check parameters */
395 	if (!this) {
396 		ret = EFI_INVALID_PARAMETER;
397 		goto out;
398 	}
399 
400 	/* We do not support jumbo packets */
401 	if (buffer_size > PKTSIZE_ALIGN) {
402 		ret = EFI_INVALID_PARAMETER;
403 		goto out;
404 	}
405 
406 	if (header_size) {
407 		/*
408 		 * TODO: We would need to create the header
409 		 * if header_size != 0
410 		 */
411 		ret = EFI_INVALID_PARAMETER;
412 		goto out;
413 	}
414 
415 	switch (this->mode->state) {
416 	case EFI_NETWORK_STOPPED:
417 		ret = EFI_NOT_STARTED;
418 		goto out;
419 	case EFI_NETWORK_STARTED:
420 		ret = EFI_DEVICE_ERROR;
421 		goto out;
422 	default:
423 		break;
424 	}
425 
426 	/* Ethernet packets always fit, just bounce */
427 	memcpy(transmit_buffer, buffer, buffer_size);
428 	net_send_packet(transmit_buffer, buffer_size);
429 
430 	new_tx_packet = buffer;
431 
432 out:
433 	return EFI_EXIT(ret);
434 }
435 
436 /**
437  * efi_net_receive() - receive a packet from a network interface
438  *
439  * This function implements the Receive service of the Simple Network Protocol.
440  * See the UEFI spec for details.
441  *
442  * @this:		the instance of the Simple Network Protocol
443  * @header_size:	size of the media header
444  * @buffer_size:	size of the buffer to receive the packet
445  * @buffer:		buffer to receive the packet
446  * @src_addr:		source MAC address
447  * @dest_addr:		destination MAC address
448  * @protocol:		protocol
449  * Return:		status code
450  */
efi_net_receive(struct efi_simple_network * this,size_t * header_size,size_t * buffer_size,void * buffer,struct efi_mac_address * src_addr,struct efi_mac_address * dest_addr,u16 * protocol)451 static efi_status_t EFIAPI efi_net_receive
452 		(struct efi_simple_network *this, size_t *header_size,
453 		 size_t *buffer_size, void *buffer,
454 		 struct efi_mac_address *src_addr,
455 		 struct efi_mac_address *dest_addr, u16 *protocol)
456 {
457 	efi_status_t ret = EFI_SUCCESS;
458 	struct ethernet_hdr *eth_hdr;
459 	size_t hdr_size = sizeof(struct ethernet_hdr);
460 	u16 protlen;
461 
462 	EFI_ENTRY("%p, %p, %p, %p, %p, %p, %p", this, header_size,
463 		  buffer_size, buffer, src_addr, dest_addr, protocol);
464 
465 	/* Execute events */
466 	efi_timer_check();
467 
468 	/* Check parameters */
469 	if (!this) {
470 		ret = EFI_INVALID_PARAMETER;
471 		goto out;
472 	}
473 
474 	switch (this->mode->state) {
475 	case EFI_NETWORK_STOPPED:
476 		ret = EFI_NOT_STARTED;
477 		goto out;
478 	case EFI_NETWORK_STARTED:
479 		ret = EFI_DEVICE_ERROR;
480 		goto out;
481 	default:
482 		break;
483 	}
484 
485 	if (!new_rx_packet) {
486 		ret = EFI_NOT_READY;
487 		goto out;
488 	}
489 	/* Check that we at least received an Ethernet header */
490 	if (net_rx_packet_len < sizeof(struct ethernet_hdr)) {
491 		new_rx_packet = false;
492 		ret = EFI_NOT_READY;
493 		goto out;
494 	}
495 	/* Fill export parameters */
496 	eth_hdr = (struct ethernet_hdr *)net_rx_packet;
497 	protlen = ntohs(eth_hdr->et_protlen);
498 	if (protlen == 0x8100) {
499 		hdr_size += 4;
500 		protlen = ntohs(*(u16 *)&net_rx_packet[hdr_size - 2]);
501 	}
502 	if (header_size)
503 		*header_size = hdr_size;
504 	if (dest_addr)
505 		memcpy(dest_addr, eth_hdr->et_dest, ARP_HLEN);
506 	if (src_addr)
507 		memcpy(src_addr, eth_hdr->et_src, ARP_HLEN);
508 	if (protocol)
509 		*protocol = protlen;
510 	if (*buffer_size < net_rx_packet_len) {
511 		/* Packet doesn't fit, try again with bigger buffer */
512 		*buffer_size = net_rx_packet_len;
513 		ret = EFI_BUFFER_TOO_SMALL;
514 		goto out;
515 	}
516 	/* Copy packet */
517 	memcpy(buffer, net_rx_packet, net_rx_packet_len);
518 	*buffer_size = net_rx_packet_len;
519 	new_rx_packet = false;
520 out:
521 	return EFI_EXIT(ret);
522 }
523 
524 /**
525  * efi_net_set_dhcp_ack() - take note of a selected DHCP IP address
526  *
527  * This function is called by dhcp_handler().
528  */
efi_net_set_dhcp_ack(void * pkt,int len)529 void efi_net_set_dhcp_ack(void *pkt, int len)
530 {
531 	int maxsize = sizeof(*dhcp_ack);
532 
533 	if (!dhcp_ack)
534 		dhcp_ack = malloc(maxsize);
535 
536 	memcpy(dhcp_ack, pkt, min(len, maxsize));
537 }
538 
539 /**
540  * efi_net_push() - callback for received network packet
541  *
542  * This function is called when a network packet is received by eth_rx().
543  *
544  * @pkt:	network packet
545  * @len:	length
546  */
efi_net_push(void * pkt,int len)547 static void efi_net_push(void *pkt, int len)
548 {
549 	new_rx_packet = true;
550 	wait_for_packet->is_signaled = true;
551 }
552 
553 /**
554  * efi_network_timer_notify() - check if a new network packet has been received
555  *
556  * This notification function is called in every timer cycle.
557  *
558  * @event	the event for which this notification function is registered
559  * @context	event context - not used in this function
560  */
efi_network_timer_notify(struct efi_event * event,void * context)561 static void EFIAPI efi_network_timer_notify(struct efi_event *event,
562 					    void *context)
563 {
564 	struct efi_simple_network *this = (struct efi_simple_network *)context;
565 
566 	EFI_ENTRY("%p, %p", event, context);
567 
568 	/*
569 	 * Some network drivers do not support calling eth_rx() before
570 	 * initialization.
571 	 */
572 	if (!this || this->mode->state != EFI_NETWORK_INITIALIZED)
573 		goto out;
574 
575 	if (!new_rx_packet) {
576 		push_packet = efi_net_push;
577 		eth_rx();
578 		push_packet = NULL;
579 	}
580 out:
581 	EFI_EXIT(EFI_SUCCESS);
582 }
583 
584 /**
585  * efi_net_register() - register the simple network protocol
586  *
587  * This gets called from do_bootefi_exec().
588  */
efi_net_register(void)589 efi_status_t efi_net_register(void)
590 {
591 	struct efi_net_obj *netobj = NULL;
592 	efi_status_t r;
593 
594 	if (!eth_get_dev()) {
595 		/* No network device active, don't expose any */
596 		return EFI_SUCCESS;
597 	}
598 
599 	/* We only expose the "active" network device, so one is enough */
600 	netobj = calloc(1, sizeof(*netobj));
601 	if (!netobj)
602 		goto out_of_resources;
603 
604 	/* Allocate an aligned transmit buffer */
605 	transmit_buffer = calloc(1, PKTSIZE_ALIGN + PKTALIGN);
606 	if (!transmit_buffer)
607 		goto out_of_resources;
608 	transmit_buffer = (void *)ALIGN((uintptr_t)transmit_buffer, PKTALIGN);
609 
610 	/* Hook net up to the device list */
611 	efi_add_handle(&netobj->header);
612 
613 	/* Fill in object data */
614 	r = efi_add_protocol(&netobj->header, &efi_net_guid,
615 			     &netobj->net);
616 	if (r != EFI_SUCCESS)
617 		goto failure_to_add_protocol;
618 	r = efi_add_protocol(&netobj->header, &efi_guid_device_path,
619 			     efi_dp_from_eth());
620 	if (r != EFI_SUCCESS)
621 		goto failure_to_add_protocol;
622 	r = efi_add_protocol(&netobj->header, &efi_pxe_guid,
623 			     &netobj->pxe);
624 	if (r != EFI_SUCCESS)
625 		goto failure_to_add_protocol;
626 	netobj->net.revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
627 	netobj->net.start = efi_net_start;
628 	netobj->net.stop = efi_net_stop;
629 	netobj->net.initialize = efi_net_initialize;
630 	netobj->net.reset = efi_net_reset;
631 	netobj->net.shutdown = efi_net_shutdown;
632 	netobj->net.receive_filters = efi_net_receive_filters;
633 	netobj->net.station_address = efi_net_station_address;
634 	netobj->net.statistics = efi_net_statistics;
635 	netobj->net.mcastiptomac = efi_net_mcastiptomac;
636 	netobj->net.nvdata = efi_net_nvdata;
637 	netobj->net.get_status = efi_net_get_status;
638 	netobj->net.transmit = efi_net_transmit;
639 	netobj->net.receive = efi_net_receive;
640 	netobj->net.mode = &netobj->net_mode;
641 	netobj->net_mode.state = EFI_NETWORK_STARTED;
642 	memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6);
643 	netobj->net_mode.hwaddr_size = ARP_HLEN;
644 	netobj->net_mode.max_packet_size = PKTSIZE;
645 	netobj->net_mode.if_type = ARP_ETHER;
646 
647 	netobj->pxe.mode = &netobj->pxe_mode;
648 	if (dhcp_ack)
649 		netobj->pxe_mode.dhcp_ack = *dhcp_ack;
650 
651 	/*
652 	 * Create WaitForPacket event.
653 	 */
654 	r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK,
655 			     efi_network_timer_notify, NULL, NULL,
656 			     &wait_for_packet);
657 	if (r != EFI_SUCCESS) {
658 		printf("ERROR: Failed to register network event\n");
659 		return r;
660 	}
661 	netobj->net.wait_for_packet = wait_for_packet;
662 	/*
663 	 * Create a timer event.
664 	 *
665 	 * The notification function is used to check if a new network packet
666 	 * has been received.
667 	 *
668 	 * iPXE is running at TPL_CALLBACK most of the time. Use a higher TPL.
669 	 */
670 	r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_NOTIFY,
671 			     efi_network_timer_notify, &netobj->net, NULL,
672 			     &network_timer_event);
673 	if (r != EFI_SUCCESS) {
674 		printf("ERROR: Failed to register network event\n");
675 		return r;
676 	}
677 	/* Network is time critical, create event in every timer cycle */
678 	r = efi_set_timer(network_timer_event, EFI_TIMER_PERIODIC, 0);
679 	if (r != EFI_SUCCESS) {
680 		printf("ERROR: Failed to set network timer\n");
681 		return r;
682 	}
683 
684 	return EFI_SUCCESS;
685 failure_to_add_protocol:
686 	printf("ERROR: Failure to add protocol\n");
687 	return r;
688 out_of_resources:
689 	free(netobj);
690 	/* free(transmit_buffer) not needed yet */
691 	printf("ERROR: Out of memory\n");
692 	return EFI_OUT_OF_RESOURCES;
693 }
694