[PATCH 16/21] efi_loader: efi_net: Add functions to [un]register http and ip4_config2 protocols, and add pxe protocol on demand

Adriano Cordova adrianox at gmail.com
Wed Jan 22 18:08:53 CET 2025


Add efi_ipconfig_[un]register and efi_http_[un]register to [un]register
the ip4_config2 and the http_service_binding protocol. And add the pxe
protocol only if a dhcp_ack was received. The latter makes sense as pxe
is otherwise not currently implemented.

Signed-off-by: Adriano Cordova <adriano.cordova at 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      | 212 ++++++++++++++++++++++------------
 4 files changed, 201 insertions(+), 85 deletions(-)

diff --git a/include/efi_loader.h b/include/efi_loader.h
index 3bb95cfeb9..063c0a05fd 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -655,10 +655,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);
diff --git a/lib/efi_loader/efi_http.c b/lib/efi_loader/efi_http.c
index 20450604ec..8831ad922c 100644
--- a/lib/efi_loader/efi_http.c
+++ b/lib/efi_loader/efi_http.c
@@ -484,23 +484,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_CALL(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 10035e8a7b..ead2e147bd 100644
--- a/lib/efi_loader/efi_ipconfig.c
+++ b/lib/efi_loader/efi_ipconfig.c
@@ -193,12 +193,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;
@@ -206,10 +212,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_CALL(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 b5284ffe34..c172da4e66 100644
--- a/lib/efi_loader/efi_net.c
+++ b/lib/efi_loader/efi_net.c
@@ -17,6 +17,7 @@
 
 #include <efi_loader.h>
 #include <dm.h>
+#include <dm/lists.h>
 #include <linux/sizes.h>
 #include <malloc.h>
 #include <vsprintf.h>
@@ -29,6 +30,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;
 
 static struct wget_http_info efi_wget_info = {
 	.set_bootdev = false,
@@ -80,10 +83,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;
@@ -755,6 +758,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
  *
@@ -789,9 +794,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;
+			}
 		}
 	}
 }
@@ -1058,6 +1066,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 r;
+}
+
 /**
  * efi_netobj_start() - start an efi net device
  *
@@ -1069,7 +1123,7 @@ efi_status_t efi_netobj_start(struct efi_net_obj *netobj)
 {
 	efi_status_t r = EFI_SUCCESS;
 	struct efi_device_path *net_dp;
-	int i;
+
 
 	if (!efi_netobj_is_active(netobj))
 		return r;
@@ -1091,16 +1145,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
+			 (struct efi_ipv4_address *)&netobj->pxe_mode.subnet_mask, NULL, netobj->dev);
 
 	return 0;
 }
@@ -1137,16 +1183,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;
 	uchar **receive_buffer;
 	size_t *receive_lengths;
-	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)
@@ -1193,11 +1243,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;
@@ -1223,38 +1268,13 @@ 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;
-
-	ret = EFI_CALL(efi_connect_controller(net_objs[i]->handle, NULL, NULL, 0));
-	if (ret != EFI_SUCCESS)
-		return -1;
+	efi_net_add_pxe(netobj);
 
-	/*
-	 * 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;
-		}
-	}
+	r = EFI_CALL(efi_connect_controller(netobj->handle, NULL, NULL, 0));
+	if (r != EFI_SUCCESS)
+		return -1;
 
+set_timers:
 	/*
 	 * Create WaitForPacket event.
 	 */
@@ -1289,16 +1309,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:
 #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:
 	return 0;
 failure_to_add_protocol:
 	printf("ERROR: Failure to add protocol\n");
@@ -1316,7 +1346,6 @@ out_of_resources:
 efi_status_t efi_net_init(void)
 {
 	int i, r;
-	efi_status_t ret;
 
 	for (i = 0; i < MAX_EFI_NET_OBJS; i++) {
 		if (net_objs[i]) {
@@ -1422,9 +1451,12 @@ 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;
-	efi_status_t ret;
 	int i, r;
 
 	dev = event->data.dm.dev;
@@ -1444,17 +1476,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;
@@ -1471,7 +1510,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;
@@ -1496,18 +1537,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;
@@ -1517,22 +1562,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;
-- 
2.43.0



More information about the U-Boot mailing list