X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=NetworkPkg%2FUefiPxeBcDxe%2FPxeBcDhcp6.c;h=8003f314910ef015dfa032dbe61a94ffadbcbdf8;hp=c3ae23ec82f52d9059704456e62402c62b719b5d;hb=fa848a4048943251fc057fe8d6c5a82e01d2ffb6;hpb=eb2710af5bee8637741d92ed8d32df562941e6d9 diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c index c3ae23ec82..8003f31491 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c @@ -1,7 +1,8 @@ /** @file Functions implementation related with DHCPv6 for UefiPxeBc Driver. - Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.
+ (C) Copyright 2014 Hewlett-Packard Development Company, L.P.
+ Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -15,6 +16,12 @@ #include "PxeBcImpl.h" +// +// Well-known multi-cast address defined in section-24.1 of rfc-3315 +// +// ALL_DHCP_Relay_Agents_and_Servers address: FF02::1:2 +// +EFI_IPv6_ADDRESS mAllDhcpRelayAndServersAddress = {{0xFF, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2}}; /** Parse out a DHCPv6 option by OptTag, and find the position in buffer. @@ -232,8 +239,8 @@ PxeBcExtractBootFileUrl ( ) { UINT16 PrefixLen; - UINT8 *BootFileNamePtr; - UINT8 *BootFileName; + CHAR8 *BootFileNamePtr; + CHAR8 *BootFileName; UINT16 BootFileNameLen; CHAR8 *TmpStr; CHAR8 TmpChar; @@ -314,7 +321,7 @@ PxeBcExtractBootFileUrl ( // // Get the part of BOOTFILE_NAME string. // - BootFileNamePtr = (UINT8*)((UINTN)ServerAddress + 1); + BootFileNamePtr = (CHAR8*)((UINTN)ServerAddress + 1); if (*BootFileNamePtr != PXEBC_TFTP_URL_SEPARATOR) { FreePool (TmpStr); return EFI_INVALID_PARAMETER; @@ -337,12 +344,12 @@ PxeBcExtractBootFileUrl ( // // Extract boot file name from URL. // - BootFileName = (UINT8 *) AllocateZeroPool (BootFileNameLen); + BootFileName = (CHAR8 *) AllocateZeroPool (BootFileNameLen); if (BootFileName == NULL) { FreePool (TmpStr); return EFI_OUT_OF_RESOURCES; } - *FileName = BootFileName; + *FileName = (UINT8*) BootFileName; // // Decode percent-encoding in boot file name. @@ -482,7 +489,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]; @@ -658,7 +665,6 @@ PxeBcRequestBootService ( { EFI_PXE_BASE_CODE_UDP_PORT SrcPort; EFI_PXE_BASE_CODE_UDP_PORT DestPort; - EFI_PXE_BASE_CODE_MODE *Mode; EFI_PXE_BASE_CODE_PROTOCOL *PxeBc; EFI_PXE_BASE_CODE_DHCPV6_PACKET *Discover; UINTN DiscoverLen; @@ -676,7 +682,6 @@ PxeBcRequestBootService ( UINT8 *Option; PxeBc = &Private->PxeBc; - Mode = PxeBc->Mode; Request = Private->Dhcp6Request; ProxyOffer = &Private->OfferBuffer[Index].Dhcp6.Packet.Offer; SrcPort = PXEBC_BS_DISCOVER_PORT; @@ -788,8 +793,8 @@ PxeBcRequestBootService ( Status = PxeBc->UdpRead ( PxeBc, - OpFlags, - &Private->StationIp, + EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP, + NULL, &SrcPort, &Private->ServerIp, &DestPort, @@ -844,19 +849,29 @@ PxeBcRetryDhcp6Binl ( Mode = Private->PxeBc.Mode; Private->IsDoDiscover = FALSE; Offer = &Private->OfferBuffer[Index].Dhcp6; - - ASSERT (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL); - // - // Parse out the next server address from the last offer, and store it - // - Status = PxeBcExtractBootFileUrl ( - &Private->BootFileName, - &Private->ServerIp.v6, - (CHAR8 *) (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data), - NTOHS (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->OpLen) - ); - if (EFI_ERROR (Status)) { - return Status; + if (Offer->OfferType == PxeOfferTypeDhcpBinl) { + // + // There is no BootFileUrl option in dhcp6 offer, so use servers multi-cast address instead. + // + CopyMem ( + &Private->ServerIp.v6, + &mAllDhcpRelayAndServersAddress, + sizeof (EFI_IPv6_ADDRESS) + ); + } else { + ASSERT (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL] != NULL); + // + // Parse out the next server address from the last offer, and store it + // + Status = PxeBcExtractBootFileUrl ( + &Private->BootFileName, + &Private->ServerIp.v6, + (CHAR8 *) (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->Data), + NTOHS (Offer->OptList[PXEBC_DHCP6_IDX_BOOT_FILE_URL]->OpLen) + ); + if (EFI_ERROR (Status)) { + return Status; + } } // @@ -1219,9 +1234,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 which 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. @@ -1240,34 +1374,38 @@ 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; EFI_STATUS Status; + BOOLEAN NoGateway; + EFI_IPv6_ADDRESS *Ip6Addr; + UINTN Index; Status = EFI_SUCCESS; - TimeOutEvt = NULL; MappedEvt = NULL; + Ip6Addr = NULL; DataSize = sizeof (EFI_IP6_CONFIG_POLICY); Ip6Cfg = Private->Ip6Cfg; Ip6 = Private->Ip6; + NoGateway = FALSE; ZeroMem (&CfgAddr, sizeof (EFI_IP6_CONFIG_MANUAL_ADDRESS)); CopyMem (&CfgAddr.Address, Address, sizeof (EFI_IPv6_ADDRESS)); - // - // Get and store the current policy of IP6 driver. - // - Status = Ip6Cfg->GetData ( - Ip6Cfg, - Ip6ConfigDataTypePolicy, - &DataSize, - &Private->Ip6Policy - ); + Status = Ip6->Configure (Ip6, &Private->Ip6CfgData); if (EFI_ERROR (Status)) { goto ON_EXIT; } + // + // Retrieve the gateway address from IP6 route table. + // + Status = PxeBcCheckRouteTable (Private, PXEBC_IP6_ROUTE_TABLE_TIMEOUT, &GatewayAddr); + if (EFI_ERROR (Status)) { + NoGateway = TRUE; + } + // // There is no channel between IP6 and PXE driver about address setting, // so it has to set the new address by Ip6ConfigProtocol manually. @@ -1287,20 +1425,6 @@ PxeBcRegisterIp6Address ( goto ON_EXIT; } - // - // Create a timer as setting address timeout event since DAD in IP6 driver. - // - Status = gBS->CreateEvent ( - EVT_TIMER, - TPL_CALLBACK, - NULL, - NULL, - &TimeOutEvt - ); - if (EFI_ERROR (Status)) { - goto ON_EXIT; - } - // // Create a notify event to set address flag when DAD if IP6 driver succeeded. // @@ -1315,6 +1439,7 @@ PxeBcRegisterIp6Address ( goto ON_EXIT; } + Private->IsAddressOk = FALSE; Status = Ip6Cfg->RegisterDataNotify ( Ip6Cfg, Ip6ConfigDataTypeManualAddress, @@ -1332,19 +1457,66 @@ PxeBcRegisterIp6Address ( ); if (EFI_ERROR(Status) && Status != EFI_NOT_READY) { goto ON_EXIT; - } + } else if (Status == EFI_NOT_READY) { + // + // Poll the network until the asynchronous process is finished. + // + while (!Private->IsAddressOk) { + Ip6->Poll (Ip6); + } + // + // Check whether the IP6 address setting is successed. + // + DataSize = 0; + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeManualAddress, + &DataSize, + NULL + ); + if (Status != EFI_BUFFER_TOO_SMALL || DataSize == 0) { + Status = EFI_DEVICE_ERROR; + goto ON_EXIT; + } - // - // Start the 5 secondes timer to wait for setting address. - // - Status = EFI_NO_MAPPING; - gBS->SetTimer (TimeOutEvt, TimerRelative, PXEBC_DHCP6_MAPPING_TIMEOUT); + Ip6Addr = AllocatePool (DataSize); + if (Ip6Addr == NULL) { + return EFI_OUT_OF_RESOURCES; + } + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeManualAddress, + &DataSize, + (VOID*) Ip6Addr + ); + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + goto ON_EXIT; + } - while (EFI_ERROR (gBS->CheckEvent (TimeOutEvt))) { - Ip6->Poll (Ip6); - if (Private->IsAddressOk) { - Status = EFI_SUCCESS; - break; + for (Index = 0; Index < DataSize / sizeof (EFI_IPv6_ADDRESS); Index++) { + if (CompareMem (Ip6Addr + Index, Address, sizeof (EFI_IPv6_ADDRESS)) == 0) { + break; + } + } + if (Index == DataSize / sizeof (EFI_IPv6_ADDRESS)) { + Status = EFI_ABORTED; + goto ON_EXIT; + } + } + + // + // Set the default gateway address back if needed. + // + if (!NoGateway && !NetIp6IsUnspecifiedAddr (&GatewayAddr)) { + Status = Ip6Cfg->SetData ( + Ip6Cfg, + Ip6ConfigDataTypeGateway, + sizeof (EFI_IPv6_ADDRESS), + &GatewayAddr + ); + if (EFI_ERROR (Status)) { + goto ON_EXIT; } } @@ -1357,12 +1529,106 @@ ON_EXIT: ); gBS->CloseEvent (MappedEvt); } - if (TimeOutEvt != NULL) { - gBS->CloseEvent (TimeOutEvt); + if (Ip6Addr != NULL) { + FreePool (Ip6Addr); + } + 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 @@ -1544,7 +1810,6 @@ PxeBcDhcp6Discover ( UINT8 *RequestOpt; UINT8 *DiscoverOpt; UINTN ReadSize; - UINT16 OpFlags; UINT16 OpCode; UINT16 OpLen; UINT32 Xid; @@ -1555,7 +1820,6 @@ PxeBcDhcp6Discover ( Request = Private->Dhcp6Request; SrcPort = PXEBC_BS_DISCOVER_PORT; DestPort = PXEBC_BS_DISCOVER_PORT; - OpFlags = 0; if (!UseBis && Layer != NULL) { *Layer &= EFI_PXE_BASE_CODE_BOOT_LAYER_MASK; @@ -1599,7 +1863,7 @@ PxeBcDhcp6Discover ( Status = PxeBc->UdpWrite ( PxeBc, - OpFlags, + 0, &Private->ServerIp, &DestPort, NULL, @@ -1626,10 +1890,18 @@ PxeBcDhcp6Discover ( } ReadSize = (UINTN) Reply->Size; + // + // Start Udp6Read instance + // + Status = Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData); + if (EFI_ERROR (Status)) { + return Status; + } + Status = PxeBc->UdpRead ( PxeBc, - OpFlags, - &Private->StationIp, + EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP, + NULL, &SrcPort, &Private->ServerIp, &DestPort, @@ -1638,6 +1910,10 @@ PxeBcDhcp6Discover ( &ReadSize, (VOID *) &Reply->Dhcp6 ); + // + // Stop Udp6Read instance + // + Private->Udp6Read->Configure (Private->Udp6Read, NULL); if (EFI_ERROR (Status)) { return Status; } @@ -1670,9 +1946,17 @@ PxeBcDhcp6Sarr ( UINT8 Buffer[PXEBC_DHCP6_OPTION_MAX_SIZE]; UINT32 OptCount; EFI_STATUS Status; + EFI_IP6_CONFIG_PROTOCOL *Ip6Cfg; + EFI_STATUS TimerStatus; + EFI_EVENT Timer; + UINT64 GetMappingTimeOut; + UINTN DataSize; + EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS DadXmits; Status = EFI_SUCCESS; PxeMode = Private->PxeBc.Mode; + Ip6Cfg = Private->Ip6Cfg; + Timer = NULL; // // Build option list for the request packet. @@ -1695,7 +1979,7 @@ PxeBcDhcp6Sarr ( Config.IaInfoEvent = NULL; Config.RapidCommit = FALSE; Config.ReconfigureAccept = FALSE; - Config.IaDescriptor.IaId = 1; + Config.IaDescriptor.IaId = Private->IaId; Config.IaDescriptor.Type = EFI_DHCP6_IA_TYPE_NA; Config.SolicitRetransmission = Retransmit; Retransmit->Irt = 4; @@ -1707,8 +1991,8 @@ PxeBcDhcp6Sarr ( // Configure the DHCPv6 instance for PXE boot. // Status = Dhcp6->Configure (Dhcp6, &Config); + FreePool (Retransmit); if (EFI_ERROR (Status)) { - FreePool (Retransmit); return Status; } @@ -1726,6 +2010,52 @@ PxeBcDhcp6Sarr ( // Start DHCPv6 S.A.R.R. process to acquire IPv6 address. // Status = Dhcp6->Start (Dhcp6); + if (Status == EFI_NO_MAPPING) { + // + // IP6 Linklocal address is not available for use, so stop current Dhcp process + // and wait for duplicate address detection to finish. + // + Dhcp6->Stop (Dhcp6); + + // + // Get Duplicate Address Detection Transmits count. + // + DataSize = sizeof (EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS); + Status = Ip6Cfg->GetData ( + Ip6Cfg, + Ip6ConfigDataTypeDupAddrDetectTransmits, + &DataSize, + &DadXmits + ); + if (EFI_ERROR (Status)) { + Dhcp6->Configure (Dhcp6, NULL); + return Status; + } + + Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer); + if (EFI_ERROR (Status)) { + Dhcp6->Configure (Dhcp6, NULL); + return Status; + } + + GetMappingTimeOut = TICKS_PER_SECOND * DadXmits.DupAddrDetectTransmits + PXEBC_DAD_ADDITIONAL_DELAY; + Status = gBS->SetTimer (Timer, TimerRelative, GetMappingTimeOut); + if (EFI_ERROR (Status)) { + gBS->CloseEvent (Timer); + Dhcp6->Configure (Dhcp6, NULL); + return Status; + } + + do { + + TimerStatus = gBS->CheckEvent (Timer); + if (!EFI_ERROR (TimerStatus)) { + Status = Dhcp6->Start (Dhcp6); + } + } while (TimerStatus == EFI_NOT_READY); + + gBS->CloseEvent (Timer); + } if (EFI_ERROR (Status)) { if (Status == EFI_ICMP_ERROR) { PxeMode->IcmpErrorReceived = TRUE; @@ -1743,37 +2073,29 @@ PxeBcDhcp6Sarr ( return Status; } - 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; + ASSERT ((Mode.Ia != NULL) && (Mode.Ia->State == Dhcp6Bound)); + // + // 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)); + if (Mode.ClientId != NULL) { + FreePool (Mode.ClientId); } - - Status = PxeBcFlushStaionIp (Private, &Private->StationIp, NULL); - if (EFI_ERROR (Status)) { - PxeBcUnregisterIp6Address (Private); - Dhcp6->Stop (Dhcp6); - return Status; + if (Mode.Ia != NULL) { + FreePool (Mode.Ia); } - // // 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; } -