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