X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=NetworkPkg%2FUefiPxeBcDxe%2FPxeBcImpl.c;h=be3d248fa9f11e4dbb5570b96f584ec168084031;hb=6c8cfb0751bd64020495f065407cae0b7c3dd6ce;hp=7e5b4d63fdf47e461ed08b57cff7cc1a8430c372;hpb=a3bcde70e6dc69000f85cc5deee98101d2ae200a;p=mirror_edk2.git diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c b/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c index 7e5b4d63fd..be3d248fa9 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c @@ -1,7 +1,7 @@ /** @file This implementation of EFI_PXE_BASE_CODE_PROTOCOL and EFI_LOAD_FILE_PROTOCOL. - Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.
+ Copyright (c) 2007 - 2014, 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 @@ -81,6 +81,17 @@ EfiPxeBcStart ( if (Mode->UsingIpv6) { AsciiPrint ("\n>>Start PXE over IPv6"); + // + // Configure udp6 instance to receive data. + // + Status = Private->Udp6Read->Configure ( + Private->Udp6Read, + &Private->Udp6CfgData + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + // // Configure block size for TFTP as a default value to handle all link layers. // @@ -115,6 +126,17 @@ EfiPxeBcStart ( } } else { AsciiPrint ("\n>>Start PXE over IPv4"); + // + // Configure udp4 instance to receive data. + // + Status = Private->Udp4Read->Configure ( + Private->Udp4Read, + &Private->Udp4CfgData + ); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } + // // Configure block size for TFTP as a default value to handle all link layers. // @@ -321,6 +343,12 @@ EfiPxeBcStop ( gBS->CloseEvent (Private->UdpTimeOutEvent); Private->CurSrcPort = 0; Private->BootFileSize = 0; + Private->SolicitTimes = 0; + Private->ElapsedTime = 0; + ZeroMem (&Private->StationIp, sizeof (EFI_IP_ADDRESS)); + ZeroMem (&Private->SubnetMask, sizeof (EFI_IP_ADDRESS)); + ZeroMem (&Private->GatewayIp, sizeof (EFI_IP_ADDRESS)); + ZeroMem (&Private->ServerIp, sizeof (EFI_IP_ADDRESS)); // // Reset the mode data. @@ -386,6 +414,8 @@ EfiPxeBcDhcp ( Mode->IcmpErrorReceived = FALSE; Private->Function = EFI_PXE_BASE_CODE_FUNCTION_DHCP; Private->IsOfferSorted = SortOffers; + Private->SolicitTimes = 0; + Private->ElapsedTime = 0; if (!Mode->Started) { return EFI_NOT_STARTED; @@ -415,6 +445,14 @@ EfiPxeBcDhcp ( Status = PxeBcDhcp4Dora (Private, Private->Dhcp4); } + // + // Reconfigure the UDP instance with the default configuration. + // + if (Mode->UsingIpv6) { + Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData); + } else { + Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData); + } // // Dhcp(), Discover(), and Mtftp() set the IP filter, and return with the IP // receive filter list emptied and the filter set to EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP. @@ -489,6 +527,7 @@ EfiPxeBcDiscover ( UINT16 Index; EFI_STATUS Status; EFI_PXE_BASE_CODE_IP_FILTER IpFilter; + EFI_PXE_BASE_CODE_DISCOVER_INFO *NewCreatedInfo; if (This == NULL) { return EFI_INVALID_PARAMETER; @@ -501,6 +540,7 @@ EfiPxeBcDiscover ( SrvList = NULL; Status = EFI_DEVICE_ERROR; Private->Function = EFI_PXE_BASE_CODE_FUNCTION_DISCOVER; + NewCreatedInfo = NULL; if (!Mode->Started) { return EFI_NOT_STARTED; @@ -530,6 +570,7 @@ EfiPxeBcDiscover ( // // There are 3 methods to get the information for discover. // + ZeroMem (&DefaultInfo, sizeof (EFI_PXE_BASE_CODE_DISCOVER_INFO)); if (*Layer != EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL) { // // 1. Take the previous setting as the discover info. @@ -554,12 +595,13 @@ EfiPxeBcDiscover ( // // 2. Extract the discover information from the cached packets if unspecified. // - Info = &DefaultInfo; - Status = PxeBcExtractDiscoverInfo (Private, Type, Info, &BootSvrEntry, &SrvList); + NewCreatedInfo = &DefaultInfo; + Status = PxeBcExtractDiscoverInfo (Private, Type, &NewCreatedInfo, &BootSvrEntry, &SrvList); if (EFI_ERROR (Status)) { goto ON_EXIT; } - + ASSERT (NewCreatedInfo != NULL); + Info = NewCreatedInfo; } else { // // 3. Take the pass-in information as the discover info, and validate the server list. @@ -575,7 +617,7 @@ EfiPxeBcDiscover ( if (Index != Info->IpCnt) { // // It's invalid if the first server doesn't accecpt any response - // and meanwhile any of the rest servers accept any reponse. + // but any of the other servers does accept any response. // Status = EFI_INVALID_PARAMETER; goto ON_EXIT; @@ -594,30 +636,7 @@ EfiPxeBcDiscover ( Private->IsDoDiscover = TRUE; - if (Info->UseUCast) { - // - // Do discover by unicast. - // - for (Index = 0; Index < Info->IpCnt; Index++) { - if (BootSvrEntry == NULL) { - CopyMem (&Private->ServerIp, &SrvList[Index].IpAddr, sizeof (EFI_IP_ADDRESS)); - } else { - ASSERT (!Mode->UsingIpv6); - ZeroMem (&Private->ServerIp, sizeof (EFI_IP_ADDRESS)); - CopyMem (&Private->ServerIp, &BootSvrEntry->IpAddr[Index], sizeof (EFI_IPv4_ADDRESS)); - } - - Status = PxeBcDiscoverBootServer ( - Private, - Type, - Layer, - UseBis, - &SrvList[Index].IpAddr, - 0, - NULL - ); - } - } else if (Info->UseMCast) { + if (Info->UseMCast) { // // Do discover by multicast. // @@ -627,8 +646,8 @@ EfiPxeBcDiscover ( Layer, UseBis, &Info->ServerMCastIp, - 0, - NULL + Info->IpCnt, + SrvList ); } else if (Info->UseBCast) { @@ -645,6 +664,30 @@ EfiPxeBcDiscover ( Info->IpCnt, SrvList ); + + } else if (Info->UseUCast) { + // + // Do discover by unicast. + // + for (Index = 0; Index < Info->IpCnt; Index++) { + if (BootSvrEntry == NULL) { + CopyMem (&Private->ServerIp, &SrvList[Index].IpAddr, sizeof (EFI_IP_ADDRESS)); + } else { + ASSERT (!Mode->UsingIpv6); + ZeroMem (&Private->ServerIp, sizeof (EFI_IP_ADDRESS)); + CopyMem (&Private->ServerIp, &BootSvrEntry->IpAddr[Index], sizeof (EFI_IPv4_ADDRESS)); + } + + Status = PxeBcDiscoverBootServer ( + Private, + Type, + Layer, + UseBis, + &Private->ServerIp, + Info->IpCnt, + SrvList + ); + } } if (!EFI_ERROR (Status)) { @@ -656,8 +699,8 @@ EfiPxeBcDiscover ( if (!EFI_ERROR (Status)) { CopyMem ( &Mode->PxeReply.Dhcpv6, - &Private->PxeReply.Dhcp6.Packet.Offer, - Private->PxeReply.Dhcp6.Packet.Offer.Length + &Private->PxeReply.Dhcp6.Packet.Ack.Dhcp6, + Private->PxeReply.Dhcp6.Packet.Ack.Length ); Mode->PxeReplyReceived = TRUE; Mode->PxeDiscoverValid = TRUE; @@ -667,8 +710,8 @@ EfiPxeBcDiscover ( if (!EFI_ERROR (Status)) { CopyMem ( &Mode->PxeReply.Dhcpv4, - &Private->PxeReply.Dhcp4.Packet.Offer, - Private->PxeReply.Dhcp4.Packet.Offer.Length + &Private->PxeReply.Dhcp4.Packet.Ack.Dhcp4, + Private->PxeReply.Dhcp4.Packet.Ack.Length ); Mode->PxeReplyReceived = TRUE; Mode->PxeDiscoverValid = TRUE; @@ -678,6 +721,16 @@ EfiPxeBcDiscover ( ON_EXIT: + if (NewCreatedInfo != NULL && NewCreatedInfo != &DefaultInfo) { + FreePool (NewCreatedInfo); + } + + if (Mode->UsingIpv6) { + Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData); + } else { + Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData); + } + // // Dhcp(), Discover(), and Mtftp() set the IP filter, and return with the IP // receive filter list emptied and the filter set to EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP. @@ -909,6 +962,14 @@ EfiPxeBcMtftp ( Mode->IcmpErrorReceived = TRUE; } + // + // Reconfigure the UDP instance with the default configuration. + // + if (Mode->UsingIpv6) { + Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData); + } else { + Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData); + } // // Dhcp(), Discover(), and Mtftp() set the IP filter, and return with the IP // receive filter list emptied and the filter set to EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP. @@ -1188,6 +1249,12 @@ EfiPxeBcUdpRead ( BOOLEAN IsDone; BOOLEAN IsMatched; UINTN CopiedLen; + UINTN HeaderLen; + UINTN HeaderCopiedLen; + UINTN BufferCopiedLen; + UINT32 FragmentLength; + UINTN FragmentIndex; + UINT8 *FragmentBuffer; if (This == NULL || DestIp == NULL || DestPort == NULL) { return EFI_INVALID_PARAMETER; @@ -1302,26 +1369,55 @@ EfiPxeBcUdpRead ( // // Copy the rececived packet to user if matched by filter. // - CopiedLen = 0; if (Mode->UsingIpv6) { Udp6Rx = Udp6Token.Packet.RxData; ASSERT (Udp6Rx != NULL); - // - // Copy the header part of received data. - // + + HeaderLen = 0; if (HeaderSize != NULL) { - CopiedLen = MIN (*HeaderSize, Udp6Rx->DataLength); - *HeaderSize = CopiedLen; - CopyMem (HeaderPtr, Udp6Rx->FragmentTable[0].FragmentBuffer, *HeaderSize); + HeaderLen = MIN (*HeaderSize, Udp6Rx->DataLength); } - // - // Copy the other part of received data. - // - if (Udp6Rx->DataLength - CopiedLen > *BufferSize) { + + if (Udp6Rx->DataLength - HeaderLen > *BufferSize) { Status = EFI_BUFFER_TOO_SMALL; } else { - *BufferSize = Udp6Rx->DataLength - CopiedLen; - CopyMem (BufferPtr, (UINT8 *) Udp6Rx->FragmentTable[0].FragmentBuffer + CopiedLen, *BufferSize); + if (HeaderSize != NULL) { + *HeaderSize = HeaderLen; + } + *BufferSize = Udp6Rx->DataLength - HeaderLen; + + HeaderCopiedLen = 0; + BufferCopiedLen = 0; + for (FragmentIndex = 0; FragmentIndex < Udp6Rx->FragmentCount; FragmentIndex++) { + FragmentLength = Udp6Rx->FragmentTable[FragmentIndex].FragmentLength; + FragmentBuffer = Udp6Rx->FragmentTable[FragmentIndex].FragmentBuffer; + if (HeaderCopiedLen + FragmentLength < HeaderLen) { + // + // Copy the header part of received data. + // + CopyMem ((UINT8 *) HeaderPtr + HeaderCopiedLen, FragmentBuffer, FragmentLength); + HeaderCopiedLen += FragmentLength; + } else if (HeaderCopiedLen < HeaderLen) { + // + // Copy the header part of received data. + // + CopiedLen = HeaderLen - HeaderCopiedLen; + CopyMem ((UINT8 *) HeaderPtr + HeaderCopiedLen, FragmentBuffer, CopiedLen); + HeaderCopiedLen += CopiedLen; + + // + // Copy the other part of received data. + // + CopyMem ((UINT8 *) BufferPtr + BufferCopiedLen, FragmentBuffer + CopiedLen, FragmentLength - CopiedLen); + BufferCopiedLen += (FragmentLength - CopiedLen); + } else { + // + // Copy the other part of received data. + // + CopyMem ((UINT8 *) BufferPtr + BufferCopiedLen, FragmentBuffer, FragmentLength); + BufferCopiedLen += FragmentLength; + } + } } // // Recycle the receiving buffer after copy to user. @@ -1330,22 +1426,52 @@ EfiPxeBcUdpRead ( } else { Udp4Rx = Udp4Token.Packet.RxData; ASSERT (Udp4Rx != NULL); - // - // Copy the header part of received data. - // + + HeaderLen = 0; if (HeaderSize != NULL) { - CopiedLen = MIN (*HeaderSize, Udp4Rx->DataLength); - *HeaderSize = CopiedLen; - CopyMem (HeaderPtr, Udp4Rx->FragmentTable[0].FragmentBuffer, *HeaderSize); + HeaderLen = MIN (*HeaderSize, Udp4Rx->DataLength); } - // - // Copy the other part of received data. - // - if (Udp4Rx->DataLength - CopiedLen > *BufferSize) { + + if (Udp4Rx->DataLength - HeaderLen > *BufferSize) { Status = EFI_BUFFER_TOO_SMALL; } else { - *BufferSize = Udp4Rx->DataLength - CopiedLen; - CopyMem (BufferPtr, (UINT8 *) Udp4Rx->FragmentTable[0].FragmentBuffer + CopiedLen, *BufferSize); + if (HeaderSize != NULL) { + *HeaderSize = HeaderLen; + } + *BufferSize = Udp4Rx->DataLength - HeaderLen; + + HeaderCopiedLen = 0; + BufferCopiedLen = 0; + for (FragmentIndex = 0; FragmentIndex < Udp4Rx->FragmentCount; FragmentIndex++) { + FragmentLength = Udp4Rx->FragmentTable[FragmentIndex].FragmentLength; + FragmentBuffer = Udp4Rx->FragmentTable[FragmentIndex].FragmentBuffer; + if (HeaderCopiedLen + FragmentLength < HeaderLen) { + // + // Copy the header part of received data. + // + CopyMem ((UINT8 *) HeaderPtr + HeaderCopiedLen, FragmentBuffer, FragmentLength); + HeaderCopiedLen += FragmentLength; + } else if (HeaderCopiedLen < HeaderLen) { + // + // Copy the header part of received data. + // + CopiedLen = HeaderLen - HeaderCopiedLen; + CopyMem ((UINT8 *) HeaderPtr + HeaderCopiedLen, FragmentBuffer, CopiedLen); + HeaderCopiedLen += CopiedLen; + + // + // Copy the other part of received data. + // + CopyMem ((UINT8 *) BufferPtr + BufferCopiedLen, FragmentBuffer + CopiedLen, FragmentLength - CopiedLen); + BufferCopiedLen += (FragmentLength - CopiedLen); + } else { + // + // Copy the other part of received data. + // + CopyMem ((UINT8 *) BufferPtr + BufferCopiedLen, FragmentBuffer, FragmentLength); + BufferCopiedLen += FragmentLength; + } + } } // // Recycle the receiving buffer after copy to user. @@ -1408,10 +1534,13 @@ EfiPxeBcSetIpFilter ( EFI_STATUS Status; PXEBC_PRIVATE_DATA *Private; EFI_PXE_BASE_CODE_MODE *Mode; - EFI_UDP4_CONFIG_DATA Udp4Cfg; - EFI_UDP6_CONFIG_DATA Udp6Cfg; + EFI_UDP4_CONFIG_DATA *Udp4Cfg; + EFI_UDP6_CONFIG_DATA *Udp6Cfg; UINTN Index; BOOLEAN NeedPromiscuous; + BOOLEAN AcceptPromiscuous; + BOOLEAN AcceptBroadcast; + BOOLEAN MultiCastUpdate; if (This == NULL || NewFilter == NULL) { return EFI_INVALID_PARAMETER; @@ -1446,19 +1575,9 @@ EfiPxeBcSetIpFilter ( } } - // - // Clear configuration for UdpRead and leave the original group joined before. - // - if (Mode->UsingIpv6) { - CopyMem(&Udp6Cfg, &Private->Udp6CfgData, sizeof (EFI_UDP6_CONFIG_DATA)); - Private->Udp6Read->Configure (Private->Udp6Read, NULL); - Udp6Cfg.AcceptPromiscuous = FALSE; - } else { - CopyMem(&Udp4Cfg, &Private->Udp4CfgData, sizeof (EFI_UDP4_CONFIG_DATA)); - Private->Udp4Read->Configure (Private->Udp4Read, NULL); - Udp4Cfg.AcceptPromiscuous = FALSE; - Udp4Cfg.AcceptBroadcast = FALSE; - } + AcceptPromiscuous = FALSE; + AcceptBroadcast = FALSE; + MultiCastUpdate = FALSE; if (NeedPromiscuous || (NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) != 0 || @@ -1466,55 +1585,104 @@ EfiPxeBcSetIpFilter ( // // Configure UDPv4/UDPv6 as promiscuous mode to receive all packets. // - Udp4Cfg.AcceptPromiscuous = TRUE; - Udp6Cfg.AcceptPromiscuous = TRUE; - + AcceptPromiscuous = TRUE; } else if ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) != 0) { // // Configure UDPv4 to receive all broadcast packets. // - Udp4Cfg.AcceptBroadcast = TRUE; + AcceptBroadcast = TRUE; } // - // Configure UDPv4/UDPv6 instance with the new configuration. + // In multicast condition when Promiscuous FALSE and IpCnt no-zero. + // Here check if there is any update of the multicast ip address. If yes, + // we need leave the old multicast group (by Config UDP instance to NULL), + // and join the new multicast group. // - if (Mode->UsingIpv6) { - Status = Private->Udp6Read->Configure (Private->Udp6Read, &Udp6Cfg); - } else { - Status = Private->Udp4Read->Configure (Private->Udp4Read, &Udp4Cfg); - } - - if (EFI_ERROR (Status)) { - goto ON_EXIT; + if (!AcceptPromiscuous) { + if ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0) { + if (Mode->IpFilter.IpCnt != NewFilter->IpCnt) { + MultiCastUpdate = TRUE; + } else if (CompareMem (Mode->IpFilter.IpList, NewFilter->IpList, NewFilter->IpCnt * sizeof (EFI_IP_ADDRESS)) != 0 ) { + MultiCastUpdate = TRUE; + } + } } - if ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0) { - - for (Index = 0; Index < NewFilter->IpCnt; Index++) { + if (!Mode->UsingIpv6) { + // + // Check whether we need reconfigure the UDP4 instance. + // + Udp4Cfg = &Private->Udp4CfgData; + if ((AcceptPromiscuous != Udp4Cfg->AcceptPromiscuous) || + (AcceptBroadcast != Udp4Cfg->AcceptBroadcast) || MultiCastUpdate) { // - // Join the multicast group if needed. + // Clear the UDP4 instance configuration, all joined groups will be left + // during the operation. // - if (Mode->UsingIpv6) { - if (IP6_IS_MULTICAST (&NewFilter->IpList[Index].v6)) { - Status = Private->Udp6Read->Groups ( - Private->Udp6Read, - TRUE, - &NewFilter->IpList[Index].v6 - ); - if (EFI_ERROR (Status)) { - goto ON_EXIT; + Private->Udp4Read->Configure (Private->Udp4Read, NULL); + + // + // Configure the UDP instance with the new configuration. + // + Udp4Cfg->AcceptPromiscuous = AcceptPromiscuous; + Udp4Cfg->AcceptBroadcast = AcceptBroadcast; + Status = Private->Udp4Read->Configure (Private->Udp4Read, Udp4Cfg); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // In not Promiscuous mode, need to join the new multicast group. + // + if (!AcceptPromiscuous) { + for (Index = 0; Index < NewFilter->IpCnt; ++Index) { + if (IP4_IS_MULTICAST (EFI_NTOHL (NewFilter->IpList[Index].v4))) { + // + // Join the mutilcast group. + // + Status = Private->Udp4Read->Groups (Private->Udp4Read, TRUE, &NewFilter->IpList[Index].v4); + if (EFI_ERROR (Status)) { + return Status; + } } } - } else { - if (IP4_IS_MULTICAST (EFI_NTOHL (NewFilter->IpList[Index].v4))) { - Status = Private->Udp4Read->Groups ( - Private->Udp4Read, - TRUE, - &NewFilter->IpList[Index].v4 - ); - if (EFI_ERROR (Status)) { - goto ON_EXIT; + } + } + } else { + // + // Check whether we need reconfigure the UDP6 instance. + // + Udp6Cfg = &Private->Udp6CfgData; + if ((AcceptPromiscuous != Udp6Cfg->AcceptPromiscuous) || MultiCastUpdate) { + // + // Clear the UDP6 instance configuration, all joined groups will be left + // during the operation. + // + Private->Udp6Read->Configure (Private->Udp6Read, NULL); + + // + // Configure the UDP instance with the new configuration. + // + Udp6Cfg->AcceptPromiscuous = AcceptPromiscuous; + Status = Private->Udp6Read->Configure (Private->Udp6Read, Udp6Cfg); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // In not Promiscuous mode, need to join the new multicast group. + // + if (!AcceptPromiscuous) { + for (Index = 0; Index < NewFilter->IpCnt; ++Index) { + if (IP6_IS_MULTICAST (&NewFilter->IpList[Index].v6)) { + // + // Join the mutilcast group. + // + Status = Private->Udp6Read->Groups (Private->Udp6Read, TRUE, &NewFilter->IpList[Index].v6); + if (EFI_ERROR (Status)) { + return Status; + } } } } @@ -1526,7 +1694,6 @@ EfiPxeBcSetIpFilter ( // CopyMem (&Mode->IpFilter, NewFilter, sizeof (Mode->IpFilter)); -ON_EXIT: return Status; } @@ -1737,7 +1904,7 @@ EfiPxeBcSetParameters ( } if (NewSendGUID != NULL) { - if (*NewSendGUID && EFI_ERROR (PxeBcGetSystemGuid (&SystemGuid))) { + if (*NewSendGUID && EFI_ERROR (NetLibGetSystemGuid (&SystemGuid))) { return EFI_INVALID_PARAMETER; } Mode->SendGUID = *NewSendGUID; @@ -1858,7 +2025,7 @@ EfiPxeBcSetStationIP ( CopyMem (&Private->SubnetMask ,NewSubnetMask, sizeof (EFI_IP_ADDRESS)); } - Status = PxeBcFlushStaionIp (Private, NewStationIp, NewSubnetMask); + Status = PxeBcFlushStationIp (Private, NewStationIp, NewSubnetMask); ON_EXIT: return Status; } @@ -2177,6 +2344,15 @@ EfiPxeLoadFile ( // Start Pxe Base Code to initialize PXE boot. // Status = PxeBc->Start (PxeBc, UsingIpv6); + if (Status == EFI_ALREADY_STARTED && UsingIpv6 != PxeBc->Mode->UsingIpv6) { + // + // PxeBc protocol has already been started but not on the required IP version, restart it. + // + Status = PxeBc->Stop (PxeBc); + if (!EFI_ERROR (Status)) { + Status = PxeBc->Start (PxeBc, UsingIpv6); + } + } if (Status == EFI_SUCCESS || Status == EFI_ALREADY_STARTED) { Status = PxeBcLoadBootFile (Private, BufferSize, Buffer); }