diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h b/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h index 84d50ad244..dda0cf37d5 100644 --- a/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h +++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Impl.h @@ -212,6 +212,7 @@ struct _DHCP6_TX_CB { UINT32 RetryLos; UINT32 TickTime; UINT16 *Elapsed; + BOOLEAN SolicitRetry; }; // diff --git a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c index cca1468683..7320642edd 100644 --- a/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c +++ b/NetworkPkg/Dhcp6Dxe/Dhcp6Io.c @@ -2817,7 +2817,7 @@ Dhcp6OnTimerTick ( // // Handle the first rt in the transmission of solicit specially. // - if (TxCb->RetryCnt == 0 && TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgSolicit) { + if ((TxCb->RetryCnt == 0 || TxCb->SolicitRetry) && TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgSolicit) { if (Instance->AdSelect == NULL) { // // Set adpref as 0xff here to indicate select any advertisement @@ -2893,6 +2893,10 @@ Dhcp6OnTimerTick ( // Retransmit the last sent packet again. // Dhcp6TransmitPacket (Instance, TxCb->TxPacket, TxCb->Elapsed); + TxCb->SolicitRetry = FALSE; + if (TxCb->TxPacket->Dhcp6.Header.MessageType == Dhcp6MsgSolicit) { + TxCb->SolicitRetry = TRUE; + } } } diff --git a/NetworkPkg/Ip6Dxe/Ip6Output.c b/NetworkPkg/Ip6Dxe/Ip6Output.c index ecbaf2d94c..0e18c10c83 100644 --- a/NetworkPkg/Ip6Dxe/Ip6Output.c +++ b/NetworkPkg/Ip6Dxe/Ip6Output.c @@ -1,7 +1,7 @@ /** @file The internal functions and routines to transmit the IP6 packet. - Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 2011, 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 @@ -689,13 +689,25 @@ Ip6Output ( // For unicast packets, use a combination of the Destination Cache, the Prefix List // and the Default Router List to determine the IP address of the appropriate next hop. // - RouteCache = Ip6Route (IpSb, &Head->DestinationAddress, &Head->SourceAddress); - if (RouteCache == NULL) { - return EFI_NOT_FOUND; - } - IP6_COPY_ADDRESS (&NextHop, &RouteCache->NextHop); - Ip6FreeRouteCacheEntry (RouteCache); + NeighborCache = Ip6FindNeighborEntry (IpSb, &Head->DestinationAddress); + if (NeighborCache != NULL) { + // + // Hit Neighbor Cache. + // + IP6_COPY_ADDRESS (&NextHop, &Head->DestinationAddress); + } else { + // + // Not in Neighbor Cache, check Router cache + // + RouteCache = Ip6Route (IpSb, &Head->DestinationAddress, &Head->SourceAddress); + if (RouteCache == NULL) { + return EFI_NOT_FOUND; + } + + IP6_COPY_ADDRESS (&NextHop, &RouteCache->NextHop); + Ip6FreeRouteCacheEntry (RouteCache); + } } // diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c index 64e15030c5..23ec9e7fc9 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcDhcp6.c @@ -1,7 +1,7 @@ /** @file Functions implementation related with DHCPv6 for UefiPxeBc Driver. - Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.
+ Copyright (c) 2009 - 2011, 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 @@ -236,6 +236,7 @@ PxeBcExtractBootFileUrl ( UINT8 *BootFileName; UINT16 BootFileNameLen; CHAR8 *TmpStr; + CHAR8 TmpChar; CHAR8 *ServerAddressOption; CHAR8 *ServerAddress; EFI_STATUS Status; @@ -321,17 +322,35 @@ PxeBcExtractBootFileUrl ( ++BootFileNamePtr; BootFileNameLen = (UINT16)(Length - (UINT16) ((UINTN)BootFileNamePtr - (UINTN)TmpStr) + 1); if (BootFileNameLen != 0 || FileName != NULL) { + // + // Extract boot file name from URL. + // BootFileName = (UINT8 *) AllocateZeroPool (BootFileNameLen); if (BootFileName == NULL) { FreePool (TmpStr); return EFI_OUT_OF_RESOURCES; } - - CopyMem (BootFileName, BootFileNamePtr, BootFileNameLen); - BootFileName[BootFileNameLen - 1] = '\0'; *FileName = BootFileName; - } + // + // Decode percent-encoding in boot file name. + // + while (*BootFileNamePtr != '\0') { + if (*BootFileNamePtr == '%') { + TmpChar = *(BootFileNamePtr+ 3); + *(BootFileNamePtr+ 3) = '\0'; + *BootFileName = (UINT8) AsciiStrHexToUintn (BootFileNamePtr + 1); + BootFileName++; + *(BootFileNamePtr+ 3) = TmpChar; + BootFileNamePtr += 3; + } else { + *BootFileName = *BootFileNamePtr; + BootFileName++; + BootFileNamePtr++; + } + } + *BootFileName = '\0'; + } FreePool (TmpStr); @@ -455,13 +474,13 @@ PxeBcParseDhcp6Packet ( // An ia_na option, embeded with valid ia_addr option and a status_code of success. // Option = Options[PXEBC_DHCP6_IDX_IA_NA]; - if (Option != NULL && NTOHS(Option->OpLen) >= 12) { + if (Option != NULL) { Option = PxeBcParseDhcp6Options ( Option->Data + 12, NTOHS (Option->OpLen), PXEBC_DHCP6_OPT_STATUS_CODE ); - if (Option != NULL && Option->Data[0] == 0) { + if ((Option != NULL && Option->Data[0] == 0) || (Option == NULL)) { IsProxyOffer = FALSE; } } @@ -470,11 +489,12 @@ PxeBcParseDhcp6Packet ( // The offer with "PXEClient" is a pxe offer. // Option = Options[PXEBC_DHCP6_IDX_VENDOR_CLASS]; - EnterpriseNum = PXEBC_DHCP6_ENTERPRISE_NUM; + EnterpriseNum = HTONL(PXEBC_DHCP6_ENTERPRISE_NUM); + if (Option != NULL && NTOHS(Option->OpLen) >= 13 && CompareMem (Option->Data, &EnterpriseNum, sizeof (UINT32)) == 0 && - CompareMem (&Option->Data[4], DEFAULT_CLASS_ID_DATA, 9) == 0) { + CompareMem (&Option->Data[6], DEFAULT_CLASS_ID_DATA, 9) == 0) { IsPxeOffer = TRUE; } @@ -566,6 +586,223 @@ PxeBcCopyDhcp6Proxy ( Mode->ProxyOfferReceived = TRUE; } +/** + Seek the address of the first byte of the option header. + + @param[in] Buf The pointer to the buffer. + @param[in] SeekLen The length to seek. + @param[in] OptType The option type. + + @retval NULL If it failed to seek the option. + @retval others The position to the option. + +**/ +UINT8 * +PxeBcDhcp6SeekOption ( + IN UINT8 *Buf, + IN UINT32 SeekLen, + IN UINT16 OptType + ) +{ + UINT8 *Cursor; + UINT8 *Option; + UINT16 DataLen; + UINT16 OpCode; + + Option = NULL; + Cursor = Buf; + + while (Cursor < Buf + SeekLen) { + OpCode = ReadUnaligned16 ((UINT16 *) Cursor); + if (OpCode == HTONS (OptType)) { + Option = Cursor; + break; + } + DataLen = NTOHS (ReadUnaligned16 ((UINT16 *) (Cursor + 2))); + Cursor += (DataLen + 4); + } + + return Option; +} + + +/** + Build and send out the request packet for the bootfile, and parse the reply. + + @param[in] Private The pointer to PxeBc private data. + @param[in] Index PxeBc option boot item type. + + @retval EFI_SUCCESS Successfully discovered the boot file. + @retval EFI_OUT_OF_RESOURCES Failed to allocate resources. + @retval EFI_NOT_FOUND Can't get the PXE reply packet. + @retval Others Failed to discover the boot file. + +**/ +EFI_STATUS +PxeBcRequestBootService ( + IN PXEBC_PRIVATE_DATA *Private, + IN UINT32 Index + ) +{ + 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; + EFI_DHCP6_PACKET *Request; + UINTN RequestLen; + EFI_DHCP6_PACKET *Reply; + UINT8 *RequestOpt; + UINT8 *DiscoverOpt; + UINTN ReadSize; + UINT16 OpFlags; + UINT16 OpCode; + UINT16 OpLen; + EFI_STATUS Status; + EFI_DHCP6_PACKET *ProxyOffer; + UINT8 *Option; + + PxeBc = &Private->PxeBc; + Mode = PxeBc->Mode; + Request = Private->Dhcp6Request; + ProxyOffer = &Private->OfferBuffer[Index].Dhcp6.Packet.Offer; + SrcPort = PXEBC_BS_DISCOVER_PORT; + DestPort = PXEBC_BS_DISCOVER_PORT; + OpFlags = 0; + + if (Request == NULL) { + return EFI_DEVICE_ERROR; + } + + Discover = AllocateZeroPool (sizeof (EFI_PXE_BASE_CODE_DHCPV6_PACKET)); + if (Discover == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Build the request packet by the cached request packet before. + // + Discover->TransactionId = ProxyOffer->Dhcp6.Header.TransactionId; + Discover->MessageType = Request->Dhcp6.Header.MessageType; + RequestOpt = Request->Dhcp6.Option; + DiscoverOpt = Discover->DhcpOptions; + DiscoverLen = sizeof (EFI_DHCP6_HEADER); + RequestLen = DiscoverLen; + + // + // Find Server ID Option from ProxyOffer. + // + Option = PxeBcDhcp6SeekOption ( + ProxyOffer->Dhcp6.Option, + ProxyOffer->Length - 4, + PXEBC_DHCP6_OPT_SERVER_ID + ); + if (Option == NULL) { + return EFI_NOT_FOUND; + } + + // + // Add Server ID Option. + // + OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *) Option)->OpLen); + CopyMem (DiscoverOpt, Option, OpLen + 4); + DiscoverOpt += (OpLen + 4); + DiscoverLen += (OpLen + 4); + + while (RequestLen < Request->Length) { + OpCode = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpCode); + OpLen = NTOHS (((EFI_DHCP6_PACKET_OPTION *) RequestOpt)->OpLen); + if (OpCode != EFI_DHCP6_IA_TYPE_NA && + OpCode != EFI_DHCP6_IA_TYPE_TA && + OpCode != PXEBC_DHCP6_OPT_SERVER_ID + ) { + // + // Copy all the options except IA option and Server ID + // + CopyMem (DiscoverOpt, RequestOpt, OpLen + 4); + DiscoverOpt += (OpLen + 4); + DiscoverLen += (OpLen + 4); + } + RequestOpt += (OpLen + 4); + RequestLen += (OpLen + 4); + } + + // + // Update Elapsed option in the package + // + Option = PxeBcDhcp6SeekOption ( + Discover->DhcpOptions, + (UINT32)(RequestLen - 4), + PXEBC_DHCP6_OPT_ELAPSED_TIME + ); + if (Option != NULL) { + CalcElapsedTime (Private); + WriteUnaligned16 ((UINT16*)(Option + 4), HTONS((UINT16) Private->ElapsedTime)); + } + + Status = PxeBc->UdpWrite ( + PxeBc, + OpFlags, + &Private->ServerIp, + &DestPort, + NULL, + &Private->StationIp, + &SrcPort, + NULL, + NULL, + &DiscoverLen, + (VOID *) Discover + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Cache the right PXE reply packet here, set valid flag later. + // Especially for PXE discover packet, store it into mode data here. + // + Reply = &Private->ProxyOffer.Dhcp6.Packet.Offer; + 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, + &SrcPort, + &Private->ServerIp, + &DestPort, + NULL, + NULL, + &ReadSize, + (VOID *) &Reply->Dhcp6 + ); + // + // Stop Udp6Read instance + // + Private->Udp6Read->Configure (Private->Udp6Read, NULL); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Update length + // + Reply->Length = (UINT32) ReadSize; + + return EFI_SUCCESS; +} + /** Retry to request bootfile name by the BINL offer. @@ -586,7 +823,6 @@ PxeBcRetryDhcp6Binl ( EFI_PXE_BASE_CODE_MODE *Mode; PXEBC_DHCP6_PACKET_CACHE *Offer; PXEBC_DHCP6_PACKET_CACHE *Cache6; - EFI_IP_ADDRESS ServerIp; EFI_STATUS Status; ASSERT (Index < PXEBC_OFFER_MAX_NUM); @@ -602,8 +838,8 @@ PxeBcRetryDhcp6Binl ( // Parse out the next server address from the last offer, and store it // Status = PxeBcExtractBootFileUrl ( - NULL, - &ServerIp.v6, + &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) ); @@ -614,13 +850,8 @@ PxeBcRetryDhcp6Binl ( // // Retry Dhcp6Binl again for the bootfile, and the reply cached into Private->ProxyOffer. // - Status = PxeBcDhcp6Discover ( - Private, - 0, - NULL, - FALSE, - &ServerIp - ); + Status = PxeBcRequestBootService (Private, Index); + if (EFI_ERROR (Status)) { return Status; } @@ -1193,6 +1424,13 @@ PxeBcDhcp6CallBack ( switch (Dhcp6Event) { case Dhcp6SendSolicit: + // + // Record the first Solicate msg time + // + if (Private->SolicitTimes == 0) { + CalcElapsedTime (Private); + Private->SolicitTimes++; + } // // Cache the dhcp discover packet to mode data directly. // diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c b/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c index cd8eab3df9..f582590838 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c @@ -321,6 +321,8 @@ EfiPxeBcStop ( gBS->CloseEvent (Private->UdpTimeOutEvent); Private->CurSrcPort = 0; Private->BootFileSize = 0; + Private->SolicitTimes = 0; + Private->ElapsedTime = 0; // // Reset the mode data. diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.h b/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.h index c4a0add1c9..04e0617c6e 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.h +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.h @@ -2,7 +2,7 @@ This EFI_PXE_BASE_CODE_PROTOCOL and EFI_LOAD_FILE_PROTOCOL. interfaces declaration. - Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.
+ Copyright (c) 2007 - 2011, 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 @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -146,6 +147,8 @@ struct _PXEBC_PRIVATE_DATA { EFI_PXE_BASE_CODE_MODE Mode; EFI_PXE_BASE_CODE_FUNCTION Function; UINT32 Ip6Policy; + UINT32 SolicitTimes; + UINT64 ElapsedTime; EFI_UDP4_CONFIG_DATA Udp4CfgData; EFI_UDP6_CONFIG_DATA Udp6CfgData; diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcSupport.c b/NetworkPkg/UefiPxeBcDxe/PxeBcSupport.c index 30418c3b6a..6ddcac718e 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcSupport.c +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcSupport.c @@ -1464,3 +1464,56 @@ PxeBcUniHexToUint8 ( return EFI_INVALID_PARAMETER; } + +/** + Calculate the elapsed time + + @param[in] Private The pointer to PXE private data + +**/ +VOID +CalcElapsedTime ( + IN PXEBC_PRIVATE_DATA *Private + ) +{ + EFI_TIME Time; + UINT64 CurrentStamp; + UINT64 ElapsedTimeValue; + + // + // Generate a time stamp of the centiseconds from 1900/1/1, assume 30day/month. + // + ZeroMem (&Time, sizeof (EFI_TIME)); + gRT->GetTime (&Time, NULL); + CurrentStamp = (UINT64) + ( + ((((((Time.Year - 1900) * 360 + + (Time.Month - 1)) * 30 + + (Time.Day - 1)) * 24 + Time.Hour) * 60 + + Time.Minute) * 60 + Time.Second) * 100 + + DivU64x32(Time.Nanosecond, 10000000) + ); + + // + // Sentinel value of 0 means that this is the first DHCP packet that we are + // sending and that we need to initialize the value. First DHCP Solicit + // gets 0 elapsed-time. Otherwise, calculate based on StartTime. + // + if (Private->ElapsedTime == 0) { + Private->ElapsedTime = CurrentStamp; + } else { + ElapsedTimeValue = CurrentStamp - Private->ElapsedTime; + + // + // If elapsed time cannot fit in two bytes, set it to 0xffff. + // + if (ElapsedTimeValue > 0xffff) { + ElapsedTimeValue = 0xffff; + } + // + // Save the elapsed time + // + Private->ElapsedTime = ElapsedTimeValue; + } +} + diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcSupport.h b/NetworkPkg/UefiPxeBcDxe/PxeBcSupport.h index a4f5d3131a..797f607642 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcSupport.h +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcSupport.h @@ -474,4 +474,15 @@ PxeBcUniHexToUint8 ( IN CHAR16 Char ); +/** + Calculate the elapsed time + + @param[in] Private The pointer to PXE private data + +**/ +VOID +CalcElapsedTime ( + IN PXEBC_PRIVATE_DATA *Private + ); + #endif