efi_loader: fix status management in network stack
authorHeinrich Schuchardt <xypron.glpk@gmx.de>
Sun, 1 Sep 2019 13:24:47 +0000 (15:24 +0200)
committerHeinrich Schuchardt <xypron.glpk@gmx.de>
Thu, 5 Sep 2019 21:18:51 +0000 (23:18 +0200)
The network should start in status EfiSimpleNetworkStopped.

Add and correct status checks in the simple network protocol.

Correct the unit test:
* Shutdown() and Stop() during setup if needed
* invoke Shutdown() before Stop() when tearing down

Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
lib/efi_loader/efi_net.c
lib/efi_selftest/efi_selftest_snp.c

index 950b6ed4b2bbd2fbf520e28787a33cf3f38d88ba..66c1898940fce92e881a15ce026e820cd834b373 100644 (file)
@@ -1,8 +1,18 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
- *  EFI application network access support
+ * Simple network protocol
+ * PXE base code protocol
  *
- *  Copyright (c) 2016 Alexander Graf
+ * Copyright (c) 2016 Alexander Graf
+ *
+ * The simple network protocol has the following statuses and services
+ * to move between them:
+ *
+ * Start():     EfiSimpleNetworkStopped     -> EfiSimpleNetworkStarted
+ * Initialize(): EfiSimpleNetworkStarted     -> EfiSimpleNetworkInitialized
+ * Shutdown():  EfiSimpleNetworkInitialized -> EfiSimpleNetworkStarted
+ * Stop():      EfiSimpleNetworkStarted     -> EfiSimpleNetworkStopped
+ * Reset():     EfiSimpleNetworkInitialized -> EfiSimpleNetworkInitialized
  */
 
 #include <common.h>
@@ -99,10 +109,13 @@ static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this)
                goto out;
        }
 
-       if (this->mode->state == EFI_NETWORK_STOPPED)
+       if (this->mode->state == EFI_NETWORK_STOPPED) {
                ret = EFI_NOT_STARTED;
-       else
+       } else {
+               /* Disable hardware and put it into the reset state */
+               eth_halt();
                this->mode->state = EFI_NETWORK_STOPPED;
+       }
 out:
        return EFI_EXIT(ret);
 }
@@ -133,6 +146,15 @@ static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
                goto out;
        }
 
+       switch (this->mode->state) {
+       case EFI_NETWORK_INITIALIZED:
+       case EFI_NETWORK_STARTED:
+               break;
+       default:
+               r = EFI_NOT_STARTED;
+               goto out;
+       }
+
        /* Setup packet buffers */
        net_init();
        /* Disable hardware and put it into the reset state */
@@ -169,9 +191,31 @@ out:
 static efi_status_t EFIAPI efi_net_reset(struct efi_simple_network *this,
                                         int extended_verification)
 {
+       efi_status_t ret;
+
        EFI_ENTRY("%p, %x", this, extended_verification);
 
-       return EFI_EXIT(EFI_CALL(efi_net_initialize(this, 0, 0)));
+       /* Check parameters */
+       if (!this) {
+               ret = EFI_INVALID_PARAMETER;
+               goto out;
+       }
+
+       switch (this->mode->state) {
+       case EFI_NETWORK_INITIALIZED:
+               break;
+       case EFI_NETWORK_STOPPED:
+               ret = EFI_NOT_STARTED;
+               goto out;
+       default:
+               ret = EFI_DEVICE_ERROR;
+               goto out;
+       }
+
+       this->mode->state = EFI_NETWORK_STARTED;
+       ret = EFI_CALL(efi_net_initialize(this, 0, 0));
+out:
+       return EFI_EXIT(ret);
 }
 
 /*
@@ -196,10 +240,21 @@ static efi_status_t EFIAPI efi_net_shutdown(struct efi_simple_network *this)
                goto out;
        }
 
+       switch (this->mode->state) {
+       case EFI_NETWORK_INITIALIZED:
+               break;
+       case EFI_NETWORK_STOPPED:
+               ret = EFI_NOT_STARTED;
+               goto out;
+       default:
+               ret = EFI_DEVICE_ERROR;
+               goto out;
+       }
+
        eth_halt();
        this->int_status = 0;
        wait_for_packet->is_signaled = false;
-       this->mode->state = EFI_NETWORK_STOPPED;
+       this->mode->state = EFI_NETWORK_STARTED;
 
 out:
        return EFI_EXIT(ret);
@@ -779,7 +834,7 @@ efi_status_t efi_net_register(void)
        netobj->net.transmit = efi_net_transmit;
        netobj->net.receive = efi_net_receive;
        netobj->net.mode = &netobj->net_mode;
-       netobj->net_mode.state = EFI_NETWORK_STARTED;
+       netobj->net_mode.state = EFI_NETWORK_STOPPED;
        memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6);
        netobj->net_mode.hwaddr_size = ARP_HLEN;
        netobj->net_mode.media_header_size = ETHER_HDR_SIZE;
index 807b8657b9e6d970a402c3005f4dbcd41de0ff1f..9797ecaf42ee053c0f872e18369acf2bb86cf513 100644 (file)
@@ -228,6 +228,26 @@ static int setup(const efi_handle_t handle,
                efi_st_error("WaitForPacket event missing\n");
                return EFI_ST_FAILURE;
        }
+       if (net->mode->state == EFI_NETWORK_INITIALIZED) {
+               /*
+                * Shut down network adapter.
+                */
+               ret = net->shutdown(net);
+               if (ret != EFI_SUCCESS) {
+                       efi_st_error("Failed to shut down network adapter\n");
+                       return EFI_ST_FAILURE;
+               }
+       }
+       if (net->mode->state == EFI_NETWORK_STARTED) {
+               /*
+                * Stop network adapter.
+                */
+               ret = net->stop(net);
+               if (ret != EFI_SUCCESS) {
+                       efi_st_error("Failed to stop network adapter\n");
+                       return EFI_ST_FAILURE;
+               }
+       }
        /*
         * Start network adapter.
         */
@@ -236,6 +256,10 @@ static int setup(const efi_handle_t handle,
                efi_st_error("Failed to start network adapter\n");
                return EFI_ST_FAILURE;
        }
+       if (net->mode->state != EFI_NETWORK_STARTED) {
+               efi_st_error("Failed to start network adapter\n");
+               return EFI_ST_FAILURE;
+       }
        /*
         * Initialize network adapter.
         */
@@ -244,6 +268,10 @@ static int setup(const efi_handle_t handle,
                efi_st_error("Failed to initialize network adapter\n");
                return EFI_ST_FAILURE;
        }
+       if (net->mode->state != EFI_NETWORK_INITIALIZED) {
+               efi_st_error("Failed to initialize network adapter\n");
+               return EFI_ST_FAILURE;
+       }
        return EFI_ST_SUCCESS;
 }
 
@@ -412,21 +440,29 @@ static int teardown(void)
        }
        if (net) {
                /*
-                * Stop network adapter.
+                * Shut down network adapter.
                 */
-               ret = net->stop(net);
+               ret = net->shutdown(net);
                if (ret != EFI_SUCCESS) {
-                       efi_st_error("Failed to stop network adapter\n");
+                       efi_st_error("Failed to shut down network adapter\n");
                        exit_status = EFI_ST_FAILURE;
                }
+               if (net->mode->state != EFI_NETWORK_STARTED) {
+                       efi_st_error("Failed to shutdown network adapter\n");
+                       return EFI_ST_FAILURE;
+               }
                /*
-                * Shut down network adapter.
+                * Stop network adapter.
                 */
-               ret = net->shutdown(net);
+               ret = net->stop(net);
                if (ret != EFI_SUCCESS) {
-                       efi_st_error("Failed to shut down network adapter\n");
+                       efi_st_error("Failed to stop network adapter\n");
                        exit_status = EFI_ST_FAILURE;
                }
+               if (net->mode->state != EFI_NETWORK_STOPPED) {
+                       efi_st_error("Failed to stop network adapter\n");
+                       return EFI_ST_FAILURE;
+               }
        }
 
        return exit_status;