diff options
-rw-r--r-- | NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c | 22 | ||||
-rw-r--r-- | NetworkPkg/UefiPxeBcDxe/PxeBcBoot.c | 8 | ||||
-rw-r--r-- | NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c | 2 | ||||
-rw-r--r-- | NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c | 280 | ||||
-rw-r--r-- | NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h | 30 | ||||
-rw-r--r-- | NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c | 8 | ||||
-rw-r--r-- | NetworkPkg/UefiPxeBcDxe/PxeBcImpl.h | 1 |
7 files changed, 311 insertions, 40 deletions
diff --git a/NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c b/NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c index ddb8dcd..9a1e3d0 100644 --- a/NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c +++ b/NetworkPkg/Ip6Dxe/Ip6ConfigImpl.c @@ -1,7 +1,7 @@ /** @file
The implementation of EFI IPv6 Configuration Protocol.
- Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
@@ -1013,6 +1013,14 @@ Ip6ConfigSetMaunualAddress ( );
//
+ // If the new address's prefix length is not specified, just use the previous configured
+ // prefix length for this address.
+ //
+ if (NewAddress->PrefixLength == 0) {
+ NewAddress->PrefixLength = CurrentAddrInfo->PrefixLength;
+ }
+
+ //
// This manual address is already in use, see whether prefix length is changed.
//
if (NewAddress->PrefixLength != CurrentAddrInfo->PrefixLength) {
@@ -1594,11 +1602,13 @@ Ip6ConfigSetStatefulAddrCallback ( //
// Decline those duplicates.
//
- Instance->Dhcp6->Decline (
- Instance->Dhcp6,
- Instance->DeclineAddressCount,
- Instance->DeclineAddress
- );
+ if (Instance->Dhcp6 != NULL) {
+ Instance->Dhcp6->Decline (
+ Instance->Dhcp6,
+ Instance->DeclineAddressCount,
+ Instance->DeclineAddress
+ );
+ }
}
if (Instance->DeclineAddress != NULL) {
diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcBoot.c b/NetworkPkg/UefiPxeBcDxe/PxeBcBoot.c index 84031e4..2531153 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcBoot.c +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcBoot.c @@ -633,6 +633,14 @@ PxeBcDhcp6BootInfo ( }
//
+ // Set the station address to IP layer.
+ //
+ Status = PxeBcSetIp6Address (Private);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
// Parse the value of boot file size.
//
if (Cache6->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_PARAM] != NULL) {
diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c index b113505..df17159 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp4.c @@ -512,7 +512,7 @@ PxeBcParseDhcp4Packet ( }
//
- // The offer with "yiaddr" is a proxy offer.
+ // The offer with zero "yiaddr" is a proxy offer.
//
if (Offer->Dhcp4.Header.YourAddr.Addr[0] == 0) {
IsProxyOffer = TRUE;
diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c index c93bad9..b71998b 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c @@ -488,7 +488,7 @@ PxeBcParseDhcp6Packet ( }
//
- // The offer with assigned client address is a proxy offer.
+ // The offer with assigned client address is NOT a proxy offer.
// An ia_na option, embeded with valid ia_addr option and a status_code of success.
//
Option = Options[PXEBC_DHCP6_IDX_IA_NA];
@@ -1235,9 +1235,128 @@ PxeBcUnregisterIp6Address ( }
}
+/**
+ Check whether IP driver could route the message which will be sent to ServerIp address.
+
+ This function will check the IP6 route table every 1 seconds until specified timeout is expired, if a valid
+ route is found in IP6 route table, the address will be filed in GatewayAddr and return.
+
+ @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
+ @param[in] TimeOutInSecond Timeout value in seconds.
+ @param[out] GatewayAddr Pointer to store the gateway IP address.
+
+ @retval EFI_SUCCESS Found a valid gateway address successfully.
+ @retval EFI_TIMEOUT The operation is time out.
+ @retval Other Unexpect error happened.
+
+**/
+EFI_STATUS
+PxeBcCheckRouteTable (
+ IN PXEBC_PRIVATE_DATA *Private,
+ IN UINTN TimeOutInSecond,
+ OUT EFI_IPv6_ADDRESS *GatewayAddr
+ )
+{
+ EFI_STATUS Status;
+ EFI_IP6_PROTOCOL *Ip6;
+ EFI_IP6_MODE_DATA Ip6ModeData;
+ UINTN Index;
+ EFI_EVENT TimeOutEvt;
+ UINTN RetryCount;
+ BOOLEAN GatewayIsFound;
+
+ ASSERT (GatewayAddr != NULL);
+ ASSERT (Private != NULL);
+
+ Ip6 = Private->Ip6;
+ GatewayIsFound = FALSE;
+ RetryCount = 0;
+ TimeOutEvt = NULL;
+ ZeroMem (GatewayAddr, sizeof (EFI_IPv6_ADDRESS));
+
+ while (TRUE) {
+ Status = Ip6->GetModeData (Ip6, &Ip6ModeData, NULL, NULL);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
+ //
+ // Find out the gateway address which can route the message whcih send to ServerIp.
+ //
+ for (Index = 0; Index < Ip6ModeData.RouteCount; Index++) {
+ if (NetIp6IsNetEqual (&Private->ServerIp.v6, &Ip6ModeData.RouteTable[Index].Destination, Ip6ModeData.RouteTable[Index].PrefixLength)) {
+ IP6_COPY_ADDRESS (GatewayAddr, &Ip6ModeData.RouteTable[Index].Gateway);
+ GatewayIsFound = TRUE;
+ break;
+ }
+ }
+
+ if (Ip6ModeData.AddressList != NULL) {
+ FreePool (Ip6ModeData.AddressList);
+ }
+ if (Ip6ModeData.GroupTable != NULL) {
+ FreePool (Ip6ModeData.GroupTable);
+ }
+ if (Ip6ModeData.RouteTable != NULL) {
+ FreePool (Ip6ModeData.RouteTable);
+ }
+ if (Ip6ModeData.NeighborCache != NULL) {
+ FreePool (Ip6ModeData.NeighborCache);
+ }
+ if (Ip6ModeData.PrefixTable != NULL) {
+ FreePool (Ip6ModeData.PrefixTable);
+ }
+ if (Ip6ModeData.IcmpTypeList != NULL) {
+ FreePool (Ip6ModeData.IcmpTypeList);
+ }
+
+ if (GatewayIsFound || RetryCount == TimeOutInSecond) {
+ break;
+ }
+
+ RetryCount++;
+
+ //
+ // Delay 1 second then recheck it again.
+ //
+ if (TimeOutEvt == NULL) {
+ Status = gBS->CreateEvent (
+ EVT_TIMER,
+ TPL_CALLBACK,
+ NULL,
+ NULL,
+ &TimeOutEvt
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ }
+
+ Status = gBS->SetTimer (TimeOutEvt, TimerRelative, TICKS_PER_SECOND);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) {
+ Ip6->Poll (Ip6);
+ }
+ }
+
+ON_EXIT:
+ if (TimeOutEvt != NULL) {
+ gBS->CloseEvent (TimeOutEvt);
+ }
+
+ if (GatewayIsFound) {
+ Status = EFI_SUCCESS;
+ } else if (RetryCount == TimeOutInSecond) {
+ Status = EFI_TIMEOUT;
+ }
+
+ return Status;
+}
/**
- Register the ready address by Ip6Config protocol.
+ Register the ready station address and gateway by Ip6Config protocol.
@param[in] Private The pointer to PXEBC_PRIVATE_DATA.
@param[in] Address The pointer to the ready address.
@@ -1256,6 +1375,7 @@ PxeBcRegisterIp6Address ( EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg;
EFI_IP6_CONFIG_POLICY Policy;
EFI_IP6_CONFIG_MANUAL_ADDRESS CfgAddr;
+ EFI_IPv6_ADDRESS GatewayAddr;
UINTN DataSize;
EFI_EVENT TimeOutEvt;
EFI_EVENT MappedEvt;
@@ -1273,19 +1393,19 @@ PxeBcRegisterIp6Address ( ZeroMem (&CfgAddr, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS));
CopyMem (&CfgAddr.Address, Address, sizeof (EFI_IPv6_ADDRESS));
+ Status = Ip6->Configure (Ip6, &Private->Ip6CfgData);
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+
//
- // Get and store the current policy of IP6 driver.
+ // Retrieve the gateway address from IP6 route table.
//
- Status = Ip6Cfg->GetData (
- Ip6Cfg,
- Ip6ConfigDataTypePolicy,
- &DataSize,
- &Private->Ip6Policy
- );
+ Status = PxeBcCheckRouteTable (Private, PXEBC_IP6_ROUTE_TABLE_TIMEOUT, &GatewayAddr);
if (EFI_ERROR (Status)) {
goto ON_EXIT;
}
-
+
//
// There is no channel between IP6 and PXE driver about address setting,
// so it has to set the new address by Ip6ConfigProtocol manually.
@@ -1381,6 +1501,21 @@ PxeBcRegisterIp6Address ( }
}
+ //
+ // Set the default gateway address back if needed.
+ //
+ if (!NetIp6IsUnspecifiedAddr (&GatewayAddr)) {
+ Status = Ip6Cfg->SetData (
+ Ip6Cfg,
+ Ip6ConfigDataTypeGateway,
+ sizeof (EFI_IPv6_ADDRESS),
+ &GatewayAddr
+ );
+ if (EFI_ERROR (Status)) {
+ goto ON_EXIT;
+ }
+ }
+
ON_EXIT:
if (MappedEvt != NULL) {
Ip6Cfg->UnregisterDataNotify (
@@ -1396,6 +1531,100 @@ ON_EXIT: return Status;
}
+/**
+ Set the IP6 policy to Automatic.
+
+ @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
+
+ @retval EFI_SUCCESS Switch the IP policy succesfully.
+ @retval Others Unexpect error happened.
+
+**/
+EFI_STATUS
+PxeBcSetIp6Policy (
+ IN PXEBC_PRIVATE_DATA *Private
+ )
+{
+ EFI_IP6_CONFIG_POLICY Policy;
+ EFI_STATUS Status;
+ EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg;
+ UINTN DataSize;
+
+ Ip6Cfg = Private->Ip6Cfg;
+ DataSize = sizeof (EFI_IP6_CONFIG_POLICY);
+
+ //
+ // Get and store the current policy of IP6 driver.
+ //
+ Status = Ip6Cfg->GetData (
+ Ip6Cfg,
+ Ip6ConfigDataTypePolicy,
+ &DataSize,
+ &Private->Ip6Policy
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Private->Ip6Policy == Ip6ConfigPolicyManual) {
+ Policy = Ip6ConfigPolicyAutomatic;
+ Status = Ip6Cfg->SetData (
+ Ip6Cfg,
+ Ip6ConfigDataTypePolicy,
+ sizeof(EFI_IP6_CONFIG_POLICY),
+ &Policy
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // There is no need to recover later.
+ //
+ Private->Ip6Policy = PXEBC_IP6_POLICY_MAX;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ This function will register the station IP address and flush IP instance to start using the new IP address.
+
+ @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
+
+ @retval EFI_SUCCESS The new IP address has been configured successfully.
+ @retval Others Failed to configure the address.
+
+**/
+EFI_STATUS
+PxeBcSetIp6Address (
+ IN PXEBC_PRIVATE_DATA *Private
+ )
+{
+ EFI_STATUS Status;
+ EFI_DHCP6_PROTOCOL *Dhcp6;
+
+ Dhcp6 = Private->Dhcp6;
+
+ CopyMem (&Private->StationIp.v6, &Private->TmpStationIp.v6, sizeof (EFI_IPv6_ADDRESS));
+ CopyMem (&Private->PxeBc.Mode->StationIp.v6, &Private->StationIp.v6, sizeof (EFI_IPv6_ADDRESS));
+
+ Status = PxeBcRegisterIp6Address (Private, &Private->StationIp.v6);
+ if (EFI_ERROR (Status)) {
+ Dhcp6->Stop (Dhcp6);
+ return Status;
+ }
+
+ Status = PxeBcFlushStationIp (Private, &Private->StationIp, NULL);
+ if (EFI_ERROR (Status)) {
+ PxeBcUnregisterIp6Address (Private);
+ Dhcp6->Stop (Dhcp6);
+ return Status;
+ }
+
+ AsciiPrint ("\n Station IP address is ");
+ PxeBcShowIp6Addr (&Private->StationIp.v6);
+
+ return EFI_SUCCESS;
+}
/**
EFI_DHCP6_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol driver
@@ -1843,36 +2072,23 @@ PxeBcDhcp6Sarr ( }
ASSERT (Mode.Ia->State == Dhcp6Bound);
- CopyMem (&Private->StationIp.v6, &Mode.Ia->IaAddress[0].IpAddress, sizeof (EFI_IPv6_ADDRESS));
- CopyMem (&PxeMode->StationIp.v6, &Private->StationIp.v6, sizeof (EFI_IPv6_ADDRESS));
-
- Status = PxeBcRegisterIp6Address (Private, &Private->StationIp.v6);
- if (EFI_ERROR (Status)) {
- Dhcp6->Stop (Dhcp6);
- return Status;
- }
-
- Status = PxeBcFlushStationIp (Private, &Private->StationIp, NULL);
- if (EFI_ERROR (Status)) {
- PxeBcUnregisterIp6Address (Private);
- Dhcp6->Stop (Dhcp6);
- return Status;
- }
+ //
+ // DHCP6 doesn't have an option to specify the router address on the subnet, the only way to get the
+ // router address in IP6 is the router discovery mechanism (the RS and RA, which only be handled when
+ // the IP policy is Automatic). So we just hold the station IP address here and leave the IP policy as
+ // Automatic, until we get the server IP address. This could let IP6 driver finish the router discovery
+ // to find a valid router address.
+ //
+ CopyMem (&Private->TmpStationIp.v6, &Mode.Ia->IaAddress[0].IpAddress, sizeof (EFI_IPv6_ADDRESS));
//
// Check the selected offer whether BINL retry is needed.
//
Status = PxeBcHandleDhcp6Offer (Private);
if (EFI_ERROR (Status)) {
- PxeBcUnregisterIp6Address (Private);
Dhcp6->Stop (Dhcp6);
return Status;
}
-
- AsciiPrint ("\n Station IP address is ");
-
- PxeBcShowIp6Addr (&Private->StationIp.v6);
-
+
return EFI_SUCCESS;
}
-
diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h index bb8ad65..38bf265 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.h @@ -1,7 +1,7 @@ /** @file
Functions declaration related with DHCPv6 for UefiPxeBc Driver.
- Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
@@ -20,6 +20,7 @@ #define PXEBC_DHCP6_OPTION_MAX_SIZE 312
#define PXEBC_DHCP6_PACKET_MAX_SIZE 1472
#define PXEBC_IP6_POLICY_MAX 0xff
+#define PXEBC_IP6_ROUTE_TABLE_TIMEOUT 10
#define PXEBC_DHCP6_S_PORT 547
#define PXEBC_DHCP6_C_PORT 546
@@ -254,6 +255,33 @@ PxeBcDhcp6Discover ( IN EFI_IP_ADDRESS *DestIp
);
+/**
+ Set the IP6 policy to Automatic.
+
+ @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
+
+ @retval EFI_SUCCESS Switch the IP policy succesfully.
+ @retval Others Unexpect error happened.
+
+**/
+EFI_STATUS
+PxeBcSetIp6Policy (
+ IN PXEBC_PRIVATE_DATA *Private
+ );
+
+/**
+ This function will register the station IP address and flush IP instance to start using the new IP address.
+
+ @param[in] Private The pointer to PXEBC_PRIVATE_DATA.
+
+ @retval EFI_SUCCESS The new IP address has been configured successfully.
+ @retval Others Failed to configure the address.
+
+**/
+EFI_STATUS
+PxeBcSetIp6Address (
+ IN PXEBC_PRIVATE_DATA *Private
+ );
/**
Start the DHCPv6 S.A.R.R. process to acquire the IPv6 address and other PXE boot information.
diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c b/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c index be3d248..89d43f8 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c @@ -124,6 +124,14 @@ EfiPxeBcStart ( if (EFI_ERROR (Status)) {
goto ON_ERROR;
}
+
+ //
+ // Set Ip6 policy to Automatic to start the IP6 router discovery.
+ //
+ Status = PxeBcSetIp6Policy (Private);
+ if (EFI_ERROR (Status)) {
+ goto ON_ERROR;
+ }
} else {
AsciiPrint ("\n>>Start PXE over IPv4");
//
diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.h b/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.h index 1d4381a..8f754e0 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.h +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.h @@ -160,6 +160,7 @@ struct _PXEBC_PRIVATE_DATA { BOOLEAN IsProxyRecved;
BOOLEAN IsDoDiscover;
+ EFI_IP_ADDRESS TmpStationIp;
EFI_IP_ADDRESS StationIp;
EFI_IP_ADDRESS SubnetMask;
EFI_IP_ADDRESS GatewayIp;
|