X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=NetworkPkg%2FUefiPxeBcDxe%2FPxeBcImpl.c;h=ab9e494b56800a449c348978507b19514fb0b973;hb=37a00f1a9dea715d8b2b4f1c760040ab4b305985;hp=ae81693bfb5879d55130a956b29e6d70bc2e68c1;hpb=ef2455b1755237cb0ffc6c13642fde216fbdc640;p=mirror_edk2.git diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c b/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c index ae81693bfb..ab9e494b56 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 - 2011, Intel Corporation. All rights reserved.
+ Copyright (c) 2007 - 2017, 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,22 +81,33 @@ 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. // - Private->BlockSize = (UINTN) (Private->Ip6MaxPacketSize - - PXEBC_DEFAULT_UDP_OVERHEAD_SIZE - PXEBC_DEFAULT_TFTP_OVERHEAD_SIZE); + Private->BlockSize = Private->Ip6MaxPacketSize - + PXEBC_DEFAULT_UDP_OVERHEAD_SIZE - PXEBC_DEFAULT_TFTP_OVERHEAD_SIZE; // // PXE over IPv6 starts here, initialize the fields and list header. // Private->Ip6Policy = PXEBC_IP6_POLICY_MAX; - Private->ProxyOffer.Dhcp6.Packet.Offer.Size = PXEBC_DHCP6_PACKET_MAX_SIZE; - Private->DhcpAck.Dhcp6.Packet.Ack.Size = PXEBC_DHCP6_PACKET_MAX_SIZE; - Private->PxeReply.Dhcp6.Packet.Ack.Size = PXEBC_DHCP6_PACKET_MAX_SIZE; + Private->ProxyOffer.Dhcp6.Packet.Offer.Size = PXEBC_CACHED_DHCP6_PACKET_MAX_SIZE; + Private->DhcpAck.Dhcp6.Packet.Ack.Size = PXEBC_CACHED_DHCP6_PACKET_MAX_SIZE; + Private->PxeReply.Dhcp6.Packet.Ack.Size = PXEBC_CACHED_DHCP6_PACKET_MAX_SIZE; for (Index = 0; Index < PXEBC_OFFER_MAX_NUM; Index++) { - Private->OfferBuffer[Index].Dhcp6.Packet.Offer.Size = PXEBC_DHCP6_PACKET_MAX_SIZE; + Private->OfferBuffer[Index].Dhcp6.Packet.Offer.Size = PXEBC_CACHED_DHCP6_PACKET_MAX_SIZE; } // @@ -113,23 +124,42 @@ 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"); + // + // 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. // - Private->BlockSize = (UINTN) (Private->Ip4MaxPacketSize - - PXEBC_DEFAULT_UDP_OVERHEAD_SIZE - PXEBC_DEFAULT_TFTP_OVERHEAD_SIZE); + Private->BlockSize = Private->Ip4MaxPacketSize - + PXEBC_DEFAULT_UDP_OVERHEAD_SIZE - PXEBC_DEFAULT_TFTP_OVERHEAD_SIZE; // // PXE over IPv4 starts here, initialize the fields. // - Private->ProxyOffer.Dhcp4.Packet.Offer.Size = PXEBC_DHCP4_PACKET_MAX_SIZE; - Private->DhcpAck.Dhcp4.Packet.Ack.Size = PXEBC_DHCP4_PACKET_MAX_SIZE; - Private->PxeReply.Dhcp4.Packet.Ack.Size = PXEBC_DHCP4_PACKET_MAX_SIZE; + Private->ProxyOffer.Dhcp4.Packet.Offer.Size = PXEBC_CACHED_DHCP4_PACKET_MAX_SIZE; + Private->DhcpAck.Dhcp4.Packet.Ack.Size = PXEBC_CACHED_DHCP4_PACKET_MAX_SIZE; + Private->PxeReply.Dhcp4.Packet.Ack.Size = PXEBC_CACHED_DHCP4_PACKET_MAX_SIZE; for (Index = 0; Index < PXEBC_OFFER_MAX_NUM; Index++) { - Private->OfferBuffer[Index].Dhcp4.Packet.Offer.Size = PXEBC_DHCP4_PACKET_MAX_SIZE; + Private->OfferBuffer[Index].Dhcp4.Packet.Offer.Size = PXEBC_CACHED_DHCP4_PACKET_MAX_SIZE; } PxeBcSeedDhcp4Packet (&Private->SeedPacket, Private->Udp4Read); @@ -174,6 +204,18 @@ EfiPxeBcStart ( if (EFI_ERROR (Status)) { goto ON_ERROR; } + + // + //DHCP4 service allows only one of its children to be configured in + //the active state, If the DHCP4 D.O.R.A started by IP4 auto + //configuration and has not been completed, the Dhcp4 state machine + //will not be in the right state for the PXE to start a new round D.O.R.A. + //so we need to switch it's policy to static. + // + Status = PxeBcSetIp4Policy (Private); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } } // @@ -316,6 +358,7 @@ EfiPxeBcStop ( gBS->CloseEvent (Private->IcmpToken.Event); Private->IcmpToken.Event = NULL; } + Private->BootFileName = NULL; } gBS->CloseEvent (Private->UdpTimeOutEvent); @@ -323,6 +366,10 @@ EfiPxeBcStop ( 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. @@ -406,15 +453,6 @@ EfiPxeBcDhcp ( // Start S.A.R.R. process to get a IPv6 address and other boot information. // Status = PxeBcDhcp6Sarr (Private, Private->Dhcp6); - - if (EFI_ERROR (Status)) { - return Status; - } - - // - // Configure Udp6Read instance - // - Status = Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData); } else { // @@ -426,17 +464,16 @@ EfiPxeBcDhcp ( // Start D.O.R.A. process to get a IPv4 address and other boot information. // Status = PxeBcDhcp4Dora (Private, Private->Dhcp4); - - if (EFI_ERROR (Status)) { - return Status; - } - - // - // Configure Udp4Read instance - // - Status = Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData); } + // + // 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. @@ -511,6 +548,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; @@ -523,6 +561,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; @@ -552,6 +591,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. @@ -576,12 +616,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. @@ -597,7 +638,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; @@ -616,30 +657,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. // @@ -649,8 +667,8 @@ EfiPxeBcDiscover ( Layer, UseBis, &Info->ServerMCastIp, - 0, - NULL + Info->IpCnt, + SrvList ); } else if (Info->UseBCast) { @@ -667,11 +685,33 @@ 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)) { - return Status; - } else { + if (!EFI_ERROR (Status)) { // // Parse the cached PXE reply packet, and store it into mode data if valid. // @@ -680,8 +720,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; @@ -691,8 +731,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; @@ -702,10 +742,14 @@ EfiPxeBcDiscover ( ON_EXIT: + if (NewCreatedInfo != NULL && NewCreatedInfo != &DefaultInfo) { + FreePool (NewCreatedInfo); + } + if (Mode->UsingIpv6) { - Status = Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData); + Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData); } else { - Status = Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData); + Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData); } // @@ -812,8 +856,7 @@ EfiPxeBcMtftp ( (BufferSize == NULL) || (ServerIp == NULL) || ((BufferPtr == NULL) && DontUseBuffer) || - ((BlockSize != NULL) && (*BlockSize < PXE_MTFTP_DEFAULT_BLOCK_SIZE)) || - (!NetIp4IsUnicast (NTOHL (ServerIp->Addr[0]), 0) && !NetIp6IsValidUnicast (&ServerIp->v6))) { + ((BlockSize != NULL) && (*BlockSize < PXE_MTFTP_DEFAULT_BLOCK_SIZE))) { return EFI_INVALID_PARAMETER; } @@ -822,6 +865,16 @@ EfiPxeBcMtftp ( Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This); Mode = Private->PxeBc.Mode; + if (Mode->UsingIpv6) { + if (!NetIp6IsValidUnicast (&ServerIp->v6)) { + return EFI_INVALID_PARAMETER; + } + } else { + if (IP4_IS_UNSPECIFIED (NTOHL (ServerIp->Addr[0])) || IP4_IS_LOCAL_BROADCAST (NTOHL (ServerIp->Addr[0]))) { + return EFI_INVALID_PARAMETER; + } + } + if (Mode->UsingIpv6) { // // Set configuration data for Mtftp6 instance. @@ -939,16 +992,14 @@ EfiPxeBcMtftp ( Mode->IcmpErrorReceived = TRUE; } - if (EFI_ERROR (Status)) { - return Status; - } - + // + // Reconfigure the UDP instance with the default configuration. + // if (Mode->UsingIpv6) { - Status = Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData); + Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData); } else { - Status = Private->Udp4Read->Configure (Private->Udp4Read, &Private->Udp4CfgData); + 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. @@ -1034,7 +1085,8 @@ EfiPxeBcUdpWrite ( DoNotFragment = TRUE; } - if (!Mode->UsingIpv6 && GatewayIp != NULL && !NetIp4IsUnicast (NTOHL (GatewayIp->Addr[0]), 0)) { + if (!Mode->UsingIpv6 && GatewayIp != NULL && Mode->SubnetMask.Addr[0] != 0 && + !NetIp4IsUnicast (NTOHL (GatewayIp->Addr[0]), EFI_NTOHL(Mode->SubnetMask))) { // // Gateway is provided but it's not a unicast IPv4 address, while it will be ignored for IPv6. // @@ -1083,7 +1135,9 @@ EfiPxeBcUdpWrite ( &Private->SubnetMask.v4, &Private->GatewayIp.v4, &Private->CurSrcPort, - DoNotFragment + DoNotFragment, + Private->Mode.TTL, + Private->Mode.ToS ); } @@ -1228,8 +1282,14 @@ 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) { + if (This == NULL) { return EFI_INVALID_PARAMETER; } @@ -1240,9 +1300,9 @@ EfiPxeBcUdpRead ( Udp4Rx = NULL; Udp6Rx = NULL; - if (((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) != 0 && DestPort == NULL) || - ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) != 0 && SrcIp == NULL) || - ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) != 0 && SrcPort == NULL)) { + if (((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) == 0 && DestPort == NULL) || + ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) == 0 && SrcIp == NULL) || + ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) == 0 && SrcPort == NULL)) { return EFI_INVALID_PARAMETER; } @@ -1342,26 +1402,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. @@ -1370,22 +1459,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. @@ -1478,13 +1597,16 @@ EfiPxeBcSetIpFilter ( // return EFI_INVALID_PARAMETER; } - if ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0 && - (NetIp4IsUnicast (EFI_IP4 (NewFilter->IpList[Index].v4), 0) || - NetIp6IsValidUnicast (&NewFilter->IpList[Index].v6))) { - // - // If EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP is set and IPv4/IPv6 address - // is in IpList, promiscuous mode is needed. - // + if (Mode->UsingIpv6) { + if ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0 && + NetIp6IsValidUnicast (&NewFilter->IpList[Index].v6)) { + NeedPromiscuous = TRUE; + } + } else if ((EFI_NTOHL(Mode->StationIp) != 0) && + (EFI_NTOHL(Mode->SubnetMask) != 0) && + IP4_NET_EQUAL(EFI_NTOHL(Mode->StationIp), EFI_NTOHL(NewFilter->IpList[Index].v4), EFI_NTOHL(Mode->SubnetMask.v4)) && + NetIp4IsUnicast (EFI_IP4 (NewFilter->IpList[Index].v4), EFI_NTOHL(Mode->SubnetMask)) && + ((NewFilter->Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0)) { NeedPromiscuous = TRUE; } } @@ -1878,9 +2000,7 @@ EfiPxeBcSetStationIP ( return EFI_INVALID_PARAMETER; } - if (NewStationIp != NULL && - (!NetIp4IsUnicast (NTOHL (NewStationIp->Addr[0]), 0) && - !NetIp6IsValidUnicast (&NewStationIp->v6))) { + if (NewStationIp != NULL && !NetIp6IsValidUnicast (&NewStationIp->v6)) { return EFI_INVALID_PARAMETER; } @@ -1894,6 +2014,14 @@ EfiPxeBcSetStationIP ( return EFI_INVALID_PARAMETER; } + if (!Mode->UsingIpv6 && NewStationIp != NULL) { + if (IP4_IS_UNSPECIFIED(NTOHL (NewStationIp->Addr[0])) || + IP4_IS_LOCAL_BROADCAST(NTOHL (NewStationIp->Addr[0])) || + (NewSubnetMask != NULL && NewSubnetMask->Addr[0] != 0 && !NetIp4IsUnicast (NTOHL (NewStationIp->Addr[0]), NTOHL (NewSubnetMask->Addr[0])))) { + return EFI_INVALID_PARAMETER; + } + } + if (!Mode->Started) { return EFI_NOT_STARTED; } @@ -1939,7 +2067,7 @@ EfiPxeBcSetStationIP ( CopyMem (&Private->SubnetMask ,NewSubnetMask, sizeof (EFI_IP_ADDRESS)); } - Status = PxeBcFlushStaionIp (Private, NewStationIp, NewSubnetMask); + Status = PxeBcFlushStationIp (Private, NewStationIp, NewSubnetMask); ON_EXIT: return Status; } @@ -2221,6 +2349,10 @@ EfiPxeLoadFile ( EFI_STATUS Status; BOOLEAN MediaPresent; + if (FilePath == NULL || !IsDevicePathEnd (FilePath)) { + return EFI_INVALID_PARAMETER; + } + VirtualNic = PXEBC_VIRTUAL_NIC_FROM_LOADFILE (This); Private = VirtualNic->Private; PxeBc = &Private->PxeBc; @@ -2258,6 +2390,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); } @@ -2272,6 +2413,16 @@ EfiPxeLoadFile ( // 3. unsupported. // PxeBc->Stop (PxeBc); + } else { + // + // The DHCP4 can have only one configured child instance so we need to stop + // reset the DHCP4 child before we return. Otherwise these programs which + // also need to use DHCP4 will be impacted. + // + if (!PxeBc->Mode->UsingIpv6) { + Private->Dhcp4->Stop (Private->Dhcp4); + Private->Dhcp4->Configure (Private->Dhcp4, NULL); + } } return Status;