On 11.03.25 17:47, Adriano Cordova wrote:
Add http and ip4_config2 only if they are not already provided
in the handle. The current use of pxe is only to store an ip
address if a dhcp ack is received, this address is used by grub.
Add pxe only if a dhcp ack is actually received.

Signed-off-by: Adriano Cordova <adriano.cord...@canonical.com>
---
  include/efi_loader.h          |   8 +-
  lib/efi_loader/efi_http.c     |  30 ++++-
  lib/efi_loader/efi_ipconfig.c |  36 +++++-
  lib/efi_loader/efi_net.c      | 203 +++++++++++++++++++++++-----------
  4 files changed, 199 insertions(+), 78 deletions(-)

diff --git a/include/efi_loader.h b/include/efi_loader.h
index 35f500fd97d..ad234dbe6b3 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -677,10 +677,14 @@ efi_status_t efi_net_init(void);
  efi_status_t efi_net_do_start(void);
  /* Called by efi_net_register to make the ip4 config2 protocol available */
  efi_status_t efi_ipconfig_register(const efi_handle_t handle,
-                                  struct efi_ip4_config2_protocol *ip4config);
+                                  struct efi_ip4_config2_protocol **ip4config);
+efi_status_t efi_ipconfig_unregister(const efi_handle_t handle,
+                                    struct efi_ip4_config2_protocol 
*ip4config);
  /* Called by efi_net_register to make the http protocol available */
  efi_status_t efi_http_register(const efi_handle_t handle,
-                              struct efi_service_binding_protocol 
*http_service_binding);
+                              struct efi_service_binding_protocol 
**http_service_binding);
+efi_status_t efi_http_unregister(const efi_handle_t handle,
+                                struct efi_service_binding_protocol 
*http_service_binding);
  /* Called by bootefi to make the watchdog available */
  efi_status_t efi_watchdog_register(void);
  efi_status_t efi_initrd_register(void);
diff --git a/lib/efi_loader/efi_http.c b/lib/efi_loader/efi_http.c
index 189317fe2d2..dcef875f5b5 100644
--- a/lib/efi_loader/efi_http.c
+++ b/lib/efi_loader/efi_http.c
@@ -486,23 +486,45 @@ static efi_status_t EFIAPI 
efi_http_service_binding_destroy_child(
   *
   */
  efi_status_t efi_http_register(const efi_handle_t handle,
-                              struct efi_service_binding_protocol 
*http_service_binding)
+                              struct efi_service_binding_protocol 
**http_service_binding)
  {
        efi_status_t r = EFI_SUCCESS;

+       r = efi_allocate_pool(EFI_LOADER_DATA, sizeof(**http_service_binding),
+                             (void **)http_service_binding);
+       if (r != EFI_SUCCESS)
+               return r;
        r = efi_add_protocol(handle, &efi_http_service_binding_guid,
-                            http_service_binding);
+                            *http_service_binding);
        if (r != EFI_SUCCESS)
                goto failure_to_add_protocol;

-       http_service_binding->create_child = 
efi_http_service_binding_create_child;
-       http_service_binding->destroy_child = 
efi_http_service_binding_destroy_child;
+       (*http_service_binding)->create_child = 
efi_http_service_binding_create_child;
+       (*http_service_binding)->destroy_child = 
efi_http_service_binding_destroy_child;

        return EFI_SUCCESS;
  failure_to_add_protocol:
        return r;
  }

+/**
+ * efi_http_unregister() - unregister the http protocol
+ *
+ */
+efi_status_t efi_http_unregister(const efi_handle_t handle,
+                                struct efi_service_binding_protocol 
*http_service_binding)
+{
+       efi_status_t r = EFI_SUCCESS;
+
+       r = efi_uninstall_protocol(handle, &efi_http_service_binding_guid,
+                                  http_service_binding, true);
+       if (r != EFI_SUCCESS)
+               return r;
+       efi_free_pool(http_service_binding);
+
+       return EFI_SUCCESS;
+}
+
  enum efi_http_status_code efi_u32_to_httpstatus(u32 status)
  {
        switch (status) {
diff --git a/lib/efi_loader/efi_ipconfig.c b/lib/efi_loader/efi_ipconfig.c
index 9f51f77fa9a..18f659f4ed1 100644
--- a/lib/efi_loader/efi_ipconfig.c
+++ b/lib/efi_loader/efi_ipconfig.c
@@ -194,12 +194,18 @@ static efi_status_t EFIAPI 
efi_ip4_config2_unregister_notify(struct efi_ip4_conf
   *
   */
  efi_status_t efi_ipconfig_register(const efi_handle_t handle,
-                                  struct efi_ip4_config2_protocol *ip4config)
+                                  struct efi_ip4_config2_protocol **ip4config)
  {
        efi_status_t r = EFI_SUCCESS;

+       if (!ip4config)
+               return EFI_INVALID_PARAMETER;
+
+       r = efi_allocate_pool(EFI_LOADER_DATA, sizeof(**ip4config), (void 
**)ip4config);
+       if (r != EFI_SUCCESS)
+               return r;
        r = efi_add_protocol(handle, &efi_ip4_config2_guid,
-                            ip4config);
+                            *ip4config);
        if (r != EFI_SUCCESS) {
                log_err("ERROR: Failure to add protocol\n");
                return r;
@@ -207,10 +213,28 @@ efi_status_t efi_ipconfig_register(const efi_handle_t 
handle,

        memcpy(current_mac_addr, eth_get_ethaddr(), 6);

-       ip4config->set_data = efi_ip4_config2_set_data;
-       ip4config->get_data = efi_ip4_config2_get_data;
-       ip4config->register_data_notify = efi_ip4_config2_register_notify;
-       ip4config->unregister_data_notify = efi_ip4_config2_unregister_notify;
+       (*ip4config)->set_data = efi_ip4_config2_set_data;
+       (*ip4config)->get_data = efi_ip4_config2_get_data;
+       (*ip4config)->register_data_notify = efi_ip4_config2_register_notify;
+       (*ip4config)->unregister_data_notify = 
efi_ip4_config2_unregister_notify;
+
+       return EFI_SUCCESS;
+}
+
+/**
+ * efi_ipconfig_unregister() - unregister the ip4_config2 protocol
+ *
+ */
+efi_status_t efi_ipconfig_unregister(const efi_handle_t handle,
+                                    struct efi_ip4_config2_protocol *ip4config)
+{
+       efi_status_t r = EFI_SUCCESS;
+
+       r = efi_uninstall_protocol(handle, &efi_ip4_config2_guid,
+                                  ip4config, true);
+       if (r != EFI_SUCCESS)
+               return r;
+       efi_free_pool(ip4config);

        return EFI_SUCCESS;
  }
diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
index fd43eec4c03..5a00e7a570c 100644
--- a/lib/efi_loader/efi_net.c
+++ b/lib/efi_loader/efi_net.c
@@ -19,6 +19,7 @@

  #include <efi_loader.h>
  #include <dm.h>
+#include <dm/lists.h>
  #include <linux/sizes.h>
  #include <malloc.h>
  #include <vsprintf.h>
@@ -31,6 +32,8 @@
  const efi_guid_t efi_net_guid = EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
  static const efi_guid_t efi_pxe_base_code_protocol_guid =
                                        EFI_PXE_BASE_CODE_PROTOCOL_GUID;
+static const efi_guid_t efi_ip4_config2_guid = EFI_IP4_CONFIG2_PROTOCOL_GUID;
+static const efi_guid_t efi_http_service_binding_guid = 
EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID;

  struct dp_entry {
        struct efi_device_path *net_dp;
@@ -93,10 +96,10 @@ struct efi_net_obj {
        struct efi_pxe_base_code_protocol pxe;
        struct efi_pxe_mode pxe_mode;
  #if IS_ENABLED(CONFIG_EFI_IP4_CONFIG2_PROTOCOL)
-       struct efi_ip4_config2_protocol ip4_config2;
+       struct efi_ip4_config2_protocol *ip4_config2;
  #endif
  #if IS_ENABLED(CONFIG_EFI_HTTP_PROTOCOL)
-       struct efi_service_binding_protocol http_service_binding;
+       struct efi_service_binding_protocol *http_service_binding;
  #endif
        void *new_tx_packet;
        void *transmit_buffer;
@@ -761,6 +764,8 @@ out:
        return EFI_EXIT(ret);
  }

+efi_status_t efi_net_add_pxe(struct efi_net_obj *netobj);
+
  /**
   * efi_net_set_dhcp_ack() - take note of a selected DHCP IP address
   *
@@ -795,9 +800,12 @@ void efi_net_set_dhcp_ack(void *pkt, int len)
        next_dhcp_entry++;
        next_dhcp_entry %= MAX_NUM_DHCP_ENTRIES;

-       for (i = 0; i < MAX_EFI_NET_OBJS; i++) {
-               if (net_objs[i] && net_objs[i]->dev == dev) {
-                       net_objs[i]->pxe_mode.dhcp_ack = **dhcp_ack;
+       if (efi_obj_list_initialized == EFI_SUCCESS) {
+               for (i = 0; i < MAX_EFI_NET_OBJS; i++) {
+                       if (net_objs[i] && net_objs[i]->dev == dev) {
+                               efi_net_add_pxe(net_objs[i]);
+                               break;
+                       }
                }
        }
  }
@@ -1069,6 +1077,52 @@ static struct efi_device_path *efi_netobj_get_dp(struct 
efi_net_obj *netobj)
        return NULL;
  }

+/**
+ * efi_net_add_pxe() - install the pxe protocol to a netobj
+ *
+ * @netobj:    pointer to efi_net_obj
+ * Return:     status code
+ */
+efi_status_t efi_net_add_pxe(struct efi_net_obj *netobj)
+{
+       efi_status_t r = EFI_SUCCESS;
+       struct efi_handler *phandler;
+       int i, j;
+
+       r = efi_search_protocol(netobj->handle, &efi_pxe_base_code_protocol_guid, 
&phandler);
+       if (r == EFI_SUCCESS)
+               return r;
+
+       i = (next_dhcp_entry + MAX_NUM_DHCP_ENTRIES - 1) % MAX_NUM_DHCP_ENTRIES;
+       for (j = 0; netobj->dev && dhcp_cache[i].is_valid && j < 
MAX_NUM_DHCP_ENTRIES;
+            i = (i + MAX_NUM_DHCP_ENTRIES - 1) % MAX_NUM_DHCP_ENTRIES, j++) {
+               if (netobj->dev == dhcp_cache[i].dev) {
+                       netobj->pxe_mode.dhcp_ack = *dhcp_cache[i].dhcp_ack;
+                       r = efi_add_protocol(netobj->handle, 
&efi_pxe_base_code_protocol_guid,
+                                            &netobj->pxe);
+                       if (r != EFI_SUCCESS)
+                               return r;
+                       netobj->pxe.revision = 
EFI_PXE_BASE_CODE_PROTOCOL_REVISION;
+                       netobj->pxe.start = efi_pxe_base_code_start;
+                       netobj->pxe.stop = efi_pxe_base_code_stop;
+                       netobj->pxe.dhcp = efi_pxe_base_code_dhcp;
+                       netobj->pxe.discover = efi_pxe_base_code_discover;
+                       netobj->pxe.mtftp = efi_pxe_base_code_mtftp;
+                       netobj->pxe.udp_write = efi_pxe_base_code_udp_write;
+                       netobj->pxe.udp_read = efi_pxe_base_code_udp_read;
+                       netobj->pxe.set_ip_filter = 
efi_pxe_base_code_set_ip_filter;
+                       netobj->pxe.arp = efi_pxe_base_code_arp;
+                       netobj->pxe.set_parameters = 
efi_pxe_base_code_set_parameters;
+                       netobj->pxe.set_station_ip = 
efi_pxe_base_code_set_station_ip;
+                       netobj->pxe.set_packets = efi_pxe_base_code_set_packets;
+                       netobj->pxe.mode = &netobj->pxe_mode;
+                       break;
+               }
+       }
+
+       return EFI_SUCCESS;
+}
+
  /**
   * efi_netobj_start() - start an efi net device
   *
@@ -1102,15 +1156,8 @@ efi_status_t efi_netobj_start(struct efi_net_obj *netobj)
        if (r != EFI_SUCCESS)
                return r;
  set_addr:
-#ifdef CONFIG_EFI_HTTP_PROTOCOL
-       /*
-        * No harm on doing the following. If the PXE handle is present, the 
client could
-        * find it and try to get its IP address from it. In here the PXE 
handle is present
-        * but the PXE protocol is not yet implmenented, so we add this in the 
meantime.
-        */
        efi_net_get_addr((struct efi_ipv4_address 
*)&netobj->pxe_mode.station_ip,
                         (struct efi_ipv4_address *)&netobj->pxe_mode.subnet_mask, 
NULL, netobj->dev);
-#endif

        return 0;
  }
@@ -1147,16 +1194,20 @@ static int efi_netobj_init(struct efi_net_obj *netobj)
  {
        efi_status_t r;
        struct udevice *dev;
+       struct efi_handler *phandler;
        void *transmit_buffer = NULL;
        uchar **receive_buffer = NULL;
        size_t *receive_lengths = NULL;
-       int i, j;
+       int i;

-       if (!netobj || !netobj->net || efi_netobj_is_active(netobj))
+       if (!netobj || !netobj->net)
                return 0;

        dev = netobj->dev;

+       if (efi_netobj_is_active(netobj))
+               goto set_timers;
+
        if (!netobj->net_mode)
                netobj->net_mode = calloc(1, sizeof(*netobj->net_mode));
        if (!netobj->net_mode)
@@ -1203,11 +1254,6 @@ static int efi_netobj_init(struct efi_net_obj *netobj)
                        netobj->net);
        if (r != EFI_SUCCESS)
                goto failure_to_add_protocol;
-
-       r = efi_add_protocol(netobj->handle, &efi_pxe_base_code_protocol_guid,
-                            &netobj->pxe);
-       if (r != EFI_SUCCESS)
-               goto failure_to_add_protocol;
        netobj->net->revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
        netobj->net->start = efi_net_start;
        netobj->net->stop = efi_net_stop;
@@ -1233,38 +1279,15 @@ static int efi_netobj_init(struct efi_net_obj *netobj)
        netobj->net_mode->max_packet_size = PKTSIZE;
        netobj->net_mode->if_type = ARP_ETHER;

-       netobj->pxe.revision = EFI_PXE_BASE_CODE_PROTOCOL_REVISION;
-       netobj->pxe.start = efi_pxe_base_code_start;
-       netobj->pxe.stop = efi_pxe_base_code_stop;
-       netobj->pxe.dhcp = efi_pxe_base_code_dhcp;
-       netobj->pxe.discover = efi_pxe_base_code_discover;
-       netobj->pxe.mtftp = efi_pxe_base_code_mtftp;
-       netobj->pxe.udp_write = efi_pxe_base_code_udp_write;
-       netobj->pxe.udp_read = efi_pxe_base_code_udp_read;
-       netobj->pxe.set_ip_filter = efi_pxe_base_code_set_ip_filter;
-       netobj->pxe.arp = efi_pxe_base_code_arp;
-       netobj->pxe.set_parameters = efi_pxe_base_code_set_parameters;
-       netobj->pxe.set_station_ip = efi_pxe_base_code_set_station_ip;
-       netobj->pxe.set_packets = efi_pxe_base_code_set_packets;
-       netobj->pxe.mode = &netobj->pxe_mode;
+       r = efi_net_add_pxe(netobj);
+       if (r != EFI_SUCCESS)
+               return -1;

        r = EFI_CALL(efi_connect_controller(netobj->handle, NULL, NULL, 0));
        if (r != EFI_SUCCESS)
                return -1;

-       /*
-        * Scan dhcp entries for one corresponding
-        * to this udevice, from newest to oldest
-        */
-       i = (next_dhcp_entry + MAX_NUM_DHCP_ENTRIES - 1) % MAX_NUM_DHCP_ENTRIES;
-       for (j = 0; dev && dhcp_cache[i].is_valid && j < MAX_NUM_DHCP_ENTRIES;
-            i = (i + MAX_NUM_DHCP_ENTRIES - 1) % MAX_NUM_DHCP_ENTRIES, j++) {
-               if (dev == dhcp_cache[i].dev) {
-                       netobj->pxe_mode.dhcp_ack = *dhcp_cache[i].dhcp_ack;
-                       break;
-               }
-       }
-
+set_timers:
        /*
         * Create WaitForPacket event.
         */
@@ -1299,16 +1322,26 @@ static int efi_netobj_init(struct efi_net_obj *netobj)
        }

  #if IS_ENABLED(CONFIG_EFI_IP4_CONFIG2_PROTOCOL)
+       netobj->ip4_config2 = NULL;
+       r = efi_search_protocol(netobj->handle, &efi_ip4_config2_guid, 
&phandler);
+       if (r == EFI_SUCCESS)
+               goto http;
        r = efi_ipconfig_register(netobj->handle, &netobj->ip4_config2);
        if (r != EFI_SUCCESS)
                goto failure_to_add_protocol;
  #endif

+http:

This does not build if CONFIG_EFI_IP4_CONFIG2_PROTOCOL=n:

+lib/efi_loader/efi_net.c:1337:1: error: label 'http' defined but not
used [-Werror=unused-label]
+ 1337 | http:
+      | ^~~~

See https://source.denx.de/u-boot/custodians/u-boot-efi/-/jobs/1101680

  #ifdef CONFIG_EFI_HTTP_PROTOCOL
+       netobj->http_service_binding = NULL;
+       r = efi_search_protocol(netobj->handle, &efi_http_service_binding_guid, 
&phandler);
+       if (r == EFI_SUCCESS)
+               goto out;
        r = efi_http_register(netobj->handle, &netobj->http_service_binding);
        if (r != EFI_SUCCESS)
                goto failure_to_add_protocol;
  #endif
+out:

This does not build if CONFIG_EFI_HTTP_PROTOCOL=n

+lib/efi_loader/efi_net.c: In function 'efi_netobj_init':
+lib/efi_loader/efi_net.c:1347:1: error: label 'out' defined but not
used [-Werror=unused-label]
+ 1347 | out:

Best regards

Heinrich

        return 0;
  failure_to_add_protocol:
        printf("ERROR: Failure to add protocol\n");
@@ -1428,6 +1461,10 @@ struct efi_net_obj *efi_netobj_alloc(efi_handle_t handle,
  int efi_net_register(void *ctx, struct event *event)
  {
        struct udevice *dev;
+       struct driver *drv;
+       struct efi_netdev_plat *plat;
+       efi_handle_t handle;
+       struct efi_simple_network *net;
        enum uclass_id id;
        struct efi_net_obj *netobj;
        int i, r;
@@ -1449,17 +1486,24 @@ int efi_net_register(void *ctx, struct event *event)
                }
        }

-       netobj = efi_netobj_alloc(NULL, NULL, dev);
+       handle = NULL;
+       net = NULL;
+       drv = lists_driver_lookup_name("efi_netdev");
+       if (drv && dev->driver == drv) {
+               plat = dev_get_plat(dev);
+               handle = plat->handle;
+               net = plat->snp;
+       }
+
+       netobj = efi_netobj_alloc(handle, net, dev);

        if (!netobj)
                return -1;

        if (efi_obj_list_initialized == EFI_SUCCESS) {
-               if (!efi_netobj_is_active(netobj)) {
-                       r = efi_netobj_init(netobj);
-                       if (r)
-                               return -1;
-               }
+               r = efi_netobj_init(netobj);
+               if (r)
+                       return -1;
        }

        return 0;
@@ -1476,7 +1520,9 @@ int efi_net_register(void *ctx, struct event *event)
  int efi_net_unregister(void *ctx, struct event *event)
  {
        efi_status_t ret = EFI_SUCCESS;
+       int r;
        struct udevice *dev;
+       struct driver *drv;
        enum uclass_id id;
        struct efi_net_obj *netobj;
        struct efi_handler *phandler;
@@ -1501,18 +1547,22 @@ int efi_net_unregister(void *ctx, struct event *event)
                }
        }

-       if (!netobj)
+       if (!netobj || !efi_netobj_is_active(netobj))
                return 0;

-       if (efi_netobj_is_active(netobj)) {
+       drv = lists_driver_lookup_name("efi_netdev");
+       if (!drv) {
+               log_err("Cannot find driver 'efi_netdev'\n");
+               return -1;
+       }
+
+       if (drv != dev->driver) {
                ret = EFI_CALL(efi_disconnect_controller(netobj->handle, NULL, 
NULL));
                if (ret != EFI_SUCCESS)
                        return -1;
-
                ret = EFI_CALL(efi_close_event(netobj->wait_for_packet));
                if (ret != EFI_SUCCESS)
                        return -1;
-
                ret = EFI_CALL(efi_close_event(netobj->network_timer_event));
                if (ret != EFI_SUCCESS)
                        return -1;
@@ -1524,22 +1574,43 @@ int efi_net_unregister(void *ctx, struct event *event)
                if (phandler && phandler->protocol_interface)
                        interface = phandler->protocol_interface;

+               if (netobj->handle->dev) {
+                       r = efi_unlink_dev(netobj->handle);
+                       if (r)
+                               return -1;
+               }
+       }
+
+#if IS_ENABLED(CONFIG_EFI_IP4_CONFIG2_PROTOCOL)
+       if (netobj->ip4_config2) {
+               r = efi_ipconfig_unregister(netobj->handle, 
netobj->ip4_config2);
+               if (r != EFI_SUCCESS)
+                       return -1;
+               netobj->ip4_config2 = NULL;
+       }
+#endif
+
+#ifdef CONFIG_EFI_HTTP_PROTOCOL
+       if (netobj->http_service_binding) {
+               r = efi_http_unregister(netobj->handle, 
netobj->http_service_binding);
+               if (r != EFI_SUCCESS)
+                       return -1;
+               netobj->http_service_binding = NULL;
+       }
+#endif
+
+       if (drv != dev->driver) {
                ret = efi_delete_handle(netobj->handle);
                if (ret != EFI_SUCCESS)
                        return -1;

                efi_free_pool(interface);
+               if (netobj->net)
+                       free(netobj->net);
+               if (netobj->net_mode)
+                       free(netobj->net_mode);
        }

-       if (netobj->net) {
-               if (netobj->net->mode)
-                       free(netobj->net->mode);
-               free(netobj->net);
-       }
-
-       if (netobj->net_mode)
-               free(netobj->net_mode);
-
        // Mark as free in the list
        netobj->handle = NULL;
        netobj->dev = NULL;
@@ -1891,7 +1962,7 @@ efi_status_t efi_net_do_request(u8 *url, enum 
efi_http_method method, void **buf
        // Set corresponding udevice
        dev = NULL;
        for (i = 0; i < MAX_EFI_NET_OBJS; i++) {
-               if (net_objs[i] && &net_objs[i]->http_service_binding == parent)
+               if (net_objs[i] && net_objs[i]->http_service_binding == parent)
                        dev = net_objs[i]->dev;
        }
        if (!dev)

Reply via email to