Let a simple network protocol interface be shared by more than one efi
net device, but with only one owner. The owner should be the efi net device
whose underlying udevice does not use the snp protocol for its ethernet ops.
See efi_selftest_net_driver for an use.

Signed-off-by: Adriano Cordova <[email protected]>
---
 lib/efi_loader/efi_net.c | 50 +++++++++++++++++++++++++---------------
 1 file changed, 32 insertions(+), 18 deletions(-)

diff --git a/lib/efi_loader/efi_net.c b/lib/efi_loader/efi_net.c
index c172da4e66..2f981b043a 100644
--- a/lib/efi_loader/efi_net.c
+++ b/lib/efi_loader/efi_net.c
@@ -104,6 +104,7 @@ struct efi_net_obj {
         */
        struct efi_event *network_timer_event;
        int efi_seq_num;
+       bool snp_owner;
 };
 
 static int curr_efi_net_obj;
@@ -128,14 +129,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) {
+               if (net_objs[i] && net_objs[i]->net == snp &&
+                   (!snp_owner || net_objs[i]->snp_owner)) {
                        // Do not register duplicate devices
                        return net_objs[i];
                }
@@ -165,7 +169,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;
@@ -201,7 +205,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;
@@ -244,7 +248,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:
@@ -341,7 +345,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:
@@ -547,7 +551,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:
@@ -608,7 +612,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) {
@@ -706,7 +710,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:
@@ -864,7 +868,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
@@ -1194,7 +1198,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)
@@ -1408,6 +1412,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;
@@ -1419,6 +1424,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;
@@ -1546,14 +1553,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;
 
@@ -1569,6 +1571,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);
@@ -1591,8 +1602,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.43.0

Reply via email to