Two efi_net_obj's could share the same efi_simple_network_protocol interface. For example, say a working U-Boot net device is registered in the EFI subsystem, this will create an instance of an efi simple network protocol. Then another handle, say handle A, could be created using this same efi simple network protocol interface, and connect controller could be called. A U-Boot udevice would be created for handle A and it would be registered in the EFI subsystem as an efi_net_obj with the same simple network protocol interface as the efi_net_obj we started with.
Signed-off-by: Adriano Cordova <adriano.cord...@canonical.com> --- lib/efi_loader/efi_net.c | 51 +++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c index 5a00e7a570c..3ad51d343da 100644 --- a/lib/efi_loader/efi_net.c +++ b/lib/efi_loader/efi_net.c @@ -110,6 +110,7 @@ struct efi_net_obj { struct efi_event *wait_for_packet; struct efi_event *network_timer_event; int efi_seq_num; + bool snp_owner; }; static int curr_efi_net_obj; @@ -134,15 +135,17 @@ static bool efi_netobj_is_active(struct efi_net_obj *netobj) * * * @snp: pointer to the simple network protocol + * @bool: snp owner * Return: pointer to efi_net_obj, NULL on error */ -static struct efi_net_obj *efi_netobj_from_snp(struct efi_simple_network *snp) +static struct efi_net_obj *efi_netobj_from_snp(struct efi_simple_network *snp, + bool snp_owner) { int i; for (i = 0; i < MAX_EFI_NET_OBJS; i++) { - if (net_objs[i] && net_objs[i]->net == snp) { - // Do not register duplicate devices + if (net_objs[i] && net_objs[i]->net == snp && + (!snp_owner || net_objs[i]->snp_owner)) { return net_objs[i]; } } @@ -171,7 +174,7 @@ static efi_status_t EFIAPI efi_net_start(struct efi_simple_network *this) goto out; } - nt = efi_netobj_from_snp(this); + nt = efi_netobj_from_snp(this, true); if (this->mode->state != EFI_NETWORK_STOPPED) { ret = EFI_ALREADY_STARTED; @@ -207,7 +210,7 @@ static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this) goto out; } - nt = efi_netobj_from_snp(this); + nt = efi_netobj_from_snp(this, true); if (this->mode->state == EFI_NETWORK_STOPPED) { ret = EFI_NOT_STARTED; @@ -250,7 +253,7 @@ static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this, r = EFI_INVALID_PARAMETER; goto out; } - nt = efi_netobj_from_snp(this); + nt = efi_netobj_from_snp(this, true); switch (this->mode->state) { case EFI_NETWORK_INITIALIZED: @@ -347,7 +350,7 @@ static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this) ret = EFI_INVALID_PARAMETER; goto out; } - nt = efi_netobj_from_snp(this); + nt = efi_netobj_from_snp(this, true); switch (this->mode->state) { case EFI_NETWORK_INITIALIZED: @@ -553,7 +556,7 @@ static efi_status_t EFIAPI efi_net_get_status(struct efi_simple_network *this, goto out; } - nt = efi_netobj_from_snp(this); + nt = efi_netobj_from_snp(this, true); switch (this->mode->state) { case EFI_NETWORK_STOPPED: @@ -614,7 +617,7 @@ static efi_status_t EFIAPI efi_net_transmit goto out; } - nt = efi_netobj_from_snp(this); + nt = efi_netobj_from_snp(this, true); /* We do not support jumbo packets */ if (buffer_size > PKTSIZE_ALIGN) { @@ -712,7 +715,7 @@ static efi_status_t EFIAPI efi_net_receive goto out; } - nt = efi_netobj_from_snp(this); + nt = efi_netobj_from_snp(this, true); switch (this->mode->state) { case EFI_NETWORK_STOPPED: @@ -870,7 +873,7 @@ static void EFIAPI efi_network_timer_notify(struct efi_event *event, if (!this || this->mode->state != EFI_NETWORK_INITIALIZED) goto out; - nt = efi_netobj_from_snp(this); + nt = efi_netobj_from_snp(this, true); curr_efi_net_obj = nt->efi_seq_num; // The following only happens if the net obj was removed but the event @@ -1205,7 +1208,7 @@ static int efi_netobj_init(struct efi_net_obj *netobj) dev = netobj->dev; - if (efi_netobj_is_active(netobj)) + if (efi_netobj_is_active(netobj) || !netobj->snp_owner) goto set_timers; if (!netobj->net_mode) @@ -1417,6 +1420,7 @@ struct efi_net_obj *efi_netobj_alloc(efi_handle_t handle, free(netobj->net->mode); free(netobj->net); } + netobj->net = NULL; if (handle) { netobj->handle = handle; @@ -1429,6 +1433,8 @@ struct efi_net_obj *efi_netobj_alloc(efi_handle_t handle, } } + netobj->snp_owner = efi_netobj_from_snp(net, true) ? false : true; + if (net) { netobj->net = net; netobj->net_mode = net->mode; @@ -1556,14 +1562,9 @@ int efi_net_unregister(void *ctx, struct event *event) return -1; } + interface = NULL; 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; @@ -1581,6 +1582,15 @@ int efi_net_unregister(void *ctx, struct event *event) } } + if (netobj->snp_owner) { + 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; + } + #if IS_ENABLED(CONFIG_EFI_IP4_CONFIG2_PROTOCOL) if (netobj->ip4_config2) { r = efi_ipconfig_unregister(netobj->handle, netobj->ip4_config2); @@ -1603,8 +1613,11 @@ int efi_net_unregister(void *ctx, struct event *event) ret = efi_delete_handle(netobj->handle); if (ret != EFI_SUCCESS) return -1; + } + + efi_free_pool(interface); - efi_free_pool(interface); + if (netobj->snp_owner) { if (netobj->net) free(netobj->net); if (netobj->net_mode) -- 2.48.1