[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