efi_loader: fix status management in network stack

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>
This commit is contained in:
Heinrich Schuchardt 2019-09-01 15:24:47 +02:00
parent 5947b49b09
commit 72a8f1685a
2 changed files with 105 additions and 14 deletions

View file

@ -1,8 +1,18 @@
// SPDX-License-Identifier: GPL-2.0+ // 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> #include <common.h>
@ -99,10 +109,13 @@ static efi_status_t EFIAPI efi_net_stop(struct efi_simple_network *this)
goto out; goto out;
} }
if (this->mode->state == EFI_NETWORK_STOPPED) if (this->mode->state == EFI_NETWORK_STOPPED) {
ret = EFI_NOT_STARTED; ret = EFI_NOT_STARTED;
else } else {
/* Disable hardware and put it into the reset state */
eth_halt();
this->mode->state = EFI_NETWORK_STOPPED; this->mode->state = EFI_NETWORK_STOPPED;
}
out: out:
return EFI_EXIT(ret); return EFI_EXIT(ret);
} }
@ -133,6 +146,15 @@ static efi_status_t EFIAPI efi_net_initialize(struct efi_simple_network *this,
goto out; 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 */ /* Setup packet buffers */
net_init(); net_init();
/* Disable hardware and put it into the reset state */ /* 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, static efi_status_t EFIAPI efi_net_reset(struct efi_simple_network *this,
int extended_verification) int extended_verification)
{ {
efi_status_t ret;
EFI_ENTRY("%p, %x", this, extended_verification); 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; 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(); eth_halt();
this->int_status = 0; this->int_status = 0;
wait_for_packet->is_signaled = false; wait_for_packet->is_signaled = false;
this->mode->state = EFI_NETWORK_STOPPED; this->mode->state = EFI_NETWORK_STARTED;
out: out:
return EFI_EXIT(ret); return EFI_EXIT(ret);
@ -779,7 +834,7 @@ efi_status_t efi_net_register(void)
netobj->net.transmit = efi_net_transmit; netobj->net.transmit = efi_net_transmit;
netobj->net.receive = efi_net_receive; netobj->net.receive = efi_net_receive;
netobj->net.mode = &netobj->net_mode; 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); memcpy(netobj->net_mode.current_address.mac_addr, eth_get_ethaddr(), 6);
netobj->net_mode.hwaddr_size = ARP_HLEN; netobj->net_mode.hwaddr_size = ARP_HLEN;
netobj->net_mode.media_header_size = ETHER_HDR_SIZE; netobj->net_mode.media_header_size = ETHER_HDR_SIZE;

View file

@ -228,6 +228,26 @@ static int setup(const efi_handle_t handle,
efi_st_error("WaitForPacket event missing\n"); efi_st_error("WaitForPacket event missing\n");
return EFI_ST_FAILURE; 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. * Start network adapter.
*/ */
@ -236,6 +256,10 @@ static int setup(const efi_handle_t handle,
efi_st_error("Failed to start network adapter\n"); efi_st_error("Failed to start network adapter\n");
return EFI_ST_FAILURE; 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. * Initialize network adapter.
*/ */
@ -244,6 +268,10 @@ static int setup(const efi_handle_t handle,
efi_st_error("Failed to initialize network adapter\n"); efi_st_error("Failed to initialize network adapter\n");
return EFI_ST_FAILURE; 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; return EFI_ST_SUCCESS;
} }
@ -411,6 +439,18 @@ static int teardown(void)
} }
} }
if (net) { if (net) {
/*
* Shut down network adapter.
*/
ret = net->shutdown(net);
if (ret != EFI_SUCCESS) {
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;
}
/* /*
* Stop network adapter. * Stop network adapter.
*/ */
@ -419,13 +459,9 @@ static int teardown(void)
efi_st_error("Failed to stop network adapter\n"); efi_st_error("Failed to stop network adapter\n");
exit_status = EFI_ST_FAILURE; exit_status = EFI_ST_FAILURE;
} }
/* if (net->mode->state != EFI_NETWORK_STOPPED) {
* Shut down network adapter. efi_st_error("Failed to stop network adapter\n");
*/ return EFI_ST_FAILURE;
ret = net->shutdown(net);
if (ret != EFI_SUCCESS) {
efi_st_error("Failed to shut down network adapter\n");
exit_status = EFI_ST_FAILURE;
} }
} }