Merge tag 'signed-efi-2019.01' of git://github.com/agraf/u-boot
[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_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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 }