X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=NetworkPkg%2FUefiPxeBcDxe%2FPxeBcImpl.c;h=5d18207b6ce8bdec04dfac94d8d4612a707d7ae9;hp=67abd48f4cc2aef9c532ad007bfaa3e066ac84c3;hb=5add2c557773a1e07245926e4768c5d69f666213;hpb=357af28525c3a5be6ca0a201f2533dc0a372dbfb diff --git a/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c b/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c index 67abd48f4c..5d18207b6c 100644 --- a/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c +++ b/NetworkPkg/UefiPxeBcDxe/PxeBcImpl.c @@ -1,15 +1,9 @@ /** @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 - 2018, 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 - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php. - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + SPDX-License-Identifier: BSD-2-Clause-Patent **/ @@ -91,23 +85,23 @@ EfiPxeBcStart ( 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; } // @@ -124,6 +118,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"); // @@ -136,22 +138,22 @@ EfiPxeBcStart ( 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); @@ -196,6 +198,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 its policy to static. + // + Status = PxeBcSetIp4Policy (Private); + if (EFI_ERROR (Status)) { + goto ON_ERROR; + } } // @@ -338,6 +352,7 @@ EfiPxeBcStop ( gBS->CloseEvent (Private->IcmpToken.Event); Private->IcmpToken.Event = NULL; } + Private->BootFileName = NULL; } gBS->CloseEvent (Private->UdpTimeOutEvent); @@ -345,6 +360,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. @@ -428,10 +447,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)) { - goto ON_EXIT; - } } else { // @@ -443,13 +458,11 @@ 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)) { - goto ON_EXIT; - } } - -ON_EXIT: + + // + // Reconfigure the UDP instance with the default configuration. + // if (Mode->UsingIpv6) { Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData); } else { @@ -529,6 +542,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; @@ -541,6 +555,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; @@ -570,6 +585,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. @@ -594,12 +610,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. @@ -614,8 +631,8 @@ 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. + // It's invalid if the first server doesn't accept any response + // but any of the other servers does accept any response. // Status = EFI_INVALID_PARAMETER; goto ON_EXIT; @@ -634,30 +651,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. // @@ -667,8 +661,8 @@ EfiPxeBcDiscover ( Layer, UseBis, &Info->ServerMCastIp, - 0, - NULL + Info->IpCnt, + SrvList ); } else if (Info->UseBCast) { @@ -685,11 +679,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)) { - goto ON_EXIT; - } else { + if (!EFI_ERROR (Status)) { // // Parse the cached PXE reply packet, and store it into mode data if valid. // @@ -698,8 +714,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; @@ -709,8 +725,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; @@ -720,12 +736,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. @@ -823,23 +843,45 @@ EfiPxeBcMtftp ( VOID *Config; EFI_STATUS Status; EFI_PXE_BASE_CODE_IP_FILTER IpFilter; - + UINTN WindowSize; if ((This == NULL) || (Filename == NULL) || (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; } + if (Operation == EFI_PXE_BASE_CODE_TFTP_READ_FILE || + Operation == EFI_PXE_BASE_CODE_TFTP_READ_DIRECTORY || + Operation == EFI_PXE_BASE_CODE_MTFTP_READ_FILE || + Operation == EFI_PXE_BASE_CODE_MTFTP_READ_DIRECTORY) { + if (BufferPtr == NULL && !DontUseBuffer) { + return EFI_INVALID_PARAMETER; + } + } + Config = NULL; Status = EFI_DEVICE_ERROR; Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This); Mode = Private->PxeBc.Mode; + // + // Get PcdPxeTftpWindowSize. + // + WindowSize = (UINTN) PcdGet64 (PcdPxeTftpWindowSize); + + 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. @@ -887,6 +929,7 @@ EfiPxeBcMtftp ( Config, Filename, BlockSize, + (WindowSize > 1) ? &WindowSize : NULL, BufferSize ); @@ -901,6 +944,7 @@ EfiPxeBcMtftp ( Config, Filename, BlockSize, + (WindowSize > 1) ? &WindowSize : NULL, BufferPtr, BufferSize, DontUseBuffer @@ -933,6 +977,7 @@ EfiPxeBcMtftp ( Config, Filename, BlockSize, + (WindowSize > 1) ? &WindowSize : NULL, BufferPtr, BufferSize, DontUseBuffer @@ -957,11 +1002,9 @@ EfiPxeBcMtftp ( Mode->IcmpErrorReceived = TRUE; } - if (EFI_ERROR (Status)) { - goto ON_EXIT; - } - -ON_EXIT: + // + // Reconfigure the UDP instance with the default configuration. + // if (Mode->UsingIpv6) { Private->Udp6Read->Configure (Private->Udp6Read, &Private->Udp6CfgData); } else { @@ -1052,7 +1095,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. // @@ -1101,7 +1145,9 @@ EfiPxeBcUdpWrite ( &Private->SubnetMask.v4, &Private->GatewayIp.v4, &Private->CurSrcPort, - DoNotFragment + DoNotFragment, + Private->Mode.TTL, + Private->Mode.ToS ); } @@ -1253,7 +1299,7 @@ EfiPxeBcUdpRead ( UINTN FragmentIndex; UINT8 *FragmentBuffer; - if (This == NULL || DestIp == NULL || DestPort == NULL) { + if (This == NULL) { return EFI_INVALID_PARAMETER; } @@ -1264,9 +1310,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; } @@ -1364,7 +1410,7 @@ EfiPxeBcUdpRead ( if (IsMatched) { // - // Copy the rececived packet to user if matched by filter. + // Copy the received packet to user if matched by filter. // if (Mode->UsingIpv6) { Udp6Rx = Udp6Token.Packet.RxData; @@ -1378,7 +1424,9 @@ EfiPxeBcUdpRead ( if (Udp6Rx->DataLength - HeaderLen > *BufferSize) { Status = EFI_BUFFER_TOO_SMALL; } else { - *HeaderSize = HeaderLen; + if (HeaderSize != NULL) { + *HeaderSize = HeaderLen; + } *BufferSize = Udp6Rx->DataLength - HeaderLen; HeaderCopiedLen = 0; @@ -1430,7 +1478,9 @@ EfiPxeBcUdpRead ( if (Udp4Rx->DataLength - HeaderLen > *BufferSize) { Status = EFI_BUFFER_TOO_SMALL; } else { - *HeaderSize = HeaderLen; + if (HeaderSize != NULL) { + *HeaderSize = HeaderLen; + } *BufferSize = Udp4Rx->DataLength - HeaderLen; HeaderCopiedLen = 0; @@ -1557,13 +1607,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; } } @@ -1608,13 +1661,13 @@ EfiPxeBcSetIpFilter ( // Udp4Cfg = &Private->Udp4CfgData; if ((AcceptPromiscuous != Udp4Cfg->AcceptPromiscuous) || - (AcceptBroadcast != Udp4Cfg->AcceptBroadcast) || MultiCastUpdate) { + (AcceptBroadcast != Udp4Cfg->AcceptBroadcast) || MultiCastUpdate) { // // Clear the UDP4 instance configuration, all joined groups will be left // during the operation. // Private->Udp4Read->Configure (Private->Udp4Read, NULL); - + // // Configure the UDP instance with the new configuration. // @@ -1624,7 +1677,7 @@ EfiPxeBcSetIpFilter ( if (EFI_ERROR (Status)) { return Status; } - + // // In not Promiscuous mode, need to join the new multicast group. // @@ -1632,7 +1685,7 @@ EfiPxeBcSetIpFilter ( for (Index = 0; Index < NewFilter->IpCnt; ++Index) { if (IP4_IS_MULTICAST (EFI_NTOHL (NewFilter->IpList[Index].v4))) { // - // Join the mutilcast group. + // Join the multicast group. // Status = Private->Udp4Read->Groups (Private->Udp4Read, TRUE, &NewFilter->IpList[Index].v4); if (EFI_ERROR (Status)) { @@ -1653,7 +1706,7 @@ EfiPxeBcSetIpFilter ( // during the operation. // Private->Udp6Read->Configure (Private->Udp6Read, NULL); - + // // Configure the UDP instance with the new configuration. // @@ -1662,7 +1715,7 @@ EfiPxeBcSetIpFilter ( if (EFI_ERROR (Status)) { return Status; } - + // // In not Promiscuous mode, need to join the new multicast group. // @@ -1670,7 +1723,7 @@ EfiPxeBcSetIpFilter ( for (Index = 0; Index < NewFilter->IpCnt; ++Index) { if (IP6_IS_MULTICAST (&NewFilter->IpList[Index].v6)) { // - // Join the mutilcast group. + // Join the multicast group. // Status = Private->Udp6Read->Groups (Private->Udp6Read, TRUE, &NewFilter->IpList[Index].v6); if (EFI_ERROR (Status)) { @@ -1882,7 +1935,7 @@ EfiPxeBcSetParameters ( // Update the previous PxeBcCallback protocol. // Status = gBS->HandleProtocol ( - Private->Controller, + Mode->UsingIpv6 ? Private->Ip6Nic->Controller : Private->Ip4Nic->Controller, &gEfiPxeBaseCodeCallbackProtocolGuid, (VOID **) &Private->PxeBcCallback ); @@ -1898,6 +1951,7 @@ EfiPxeBcSetParameters ( if (NewSendGUID != NULL) { if (*NewSendGUID && EFI_ERROR (NetLibGetSystemGuid (&SystemGuid))) { + DEBUG ((EFI_D_WARN, "PXE: Failed to read system GUID from the smbios table!\n")); return EFI_INVALID_PARAMETER; } Mode->SendGUID = *NewSendGUID; @@ -1951,15 +2005,12 @@ EfiPxeBcSetStationIP ( EFI_STATUS Status; PXEBC_PRIVATE_DATA *Private; EFI_PXE_BASE_CODE_MODE *Mode; - EFI_ARP_CONFIG_DATA ArpConfigData; if (This == NULL) { 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; } @@ -1973,6 +2024,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; } @@ -1985,27 +2044,6 @@ EfiPxeBcSetStationIP ( if (EFI_ERROR (Status)) { goto ON_EXIT; } - } else if (!Mode->UsingIpv6 && NewStationIp != NULL) { - // - // Configure the corresponding ARP with the IPv4 address. - // - ZeroMem (&ArpConfigData, sizeof (EFI_ARP_CONFIG_DATA)); - - ArpConfigData.SwAddressType = 0x0800; - ArpConfigData.SwAddressLength = (UINT8) sizeof (EFI_IPv4_ADDRESS); - ArpConfigData.StationAddress = &NewStationIp->v4; - - Private->Arp->Configure (Private->Arp, NULL); - Private->Arp->Configure (Private->Arp, &ArpConfigData); - - if (NewSubnetMask != NULL) { - Mode->RouteTableEntries = 1; - Mode->RouteTable[0].IpAddr.Addr[0] = NewStationIp->Addr[0] & NewSubnetMask->Addr[0]; - Mode->RouteTable[0].SubnetMask.Addr[0] = NewSubnetMask->Addr[0]; - Mode->RouteTable[0].GwAddr.Addr[0] = 0; - } - - Private->IsAddressOk = TRUE; } if (NewStationIp != NULL) { @@ -2018,7 +2056,11 @@ EfiPxeBcSetStationIP ( CopyMem (&Private->SubnetMask ,NewSubnetMask, sizeof (EFI_IP_ADDRESS)); } - Status = PxeBcFlushStaionIp (Private, NewStationIp, NewSubnetMask); + Status = PxeBcFlushStationIp (Private, NewStationIp, NewSubnetMask); + if (!EFI_ERROR (Status)) { + Private->IsAddressOk = TRUE; + } + ON_EXIT: return Status; } @@ -2298,15 +2340,9 @@ EfiPxeLoadFile ( EFI_PXE_BASE_CODE_PROTOCOL *PxeBc; BOOLEAN UsingIpv6; EFI_STATUS Status; - BOOLEAN MediaPresent; - - VirtualNic = PXEBC_VIRTUAL_NIC_FROM_LOADFILE (This); - Private = VirtualNic->Private; - PxeBc = &Private->PxeBc; - UsingIpv6 = FALSE; - Status = EFI_DEVICE_ERROR; + EFI_STATUS MediaStatus; - if (This == NULL || BufferSize == NULL) { + if (This == NULL || BufferSize == NULL || FilePath == NULL || !IsDevicePathEnd (FilePath)) { return EFI_INVALID_PARAMETER; } @@ -2317,12 +2353,18 @@ EfiPxeLoadFile ( return EFI_UNSUPPORTED; } + VirtualNic = PXEBC_VIRTUAL_NIC_FROM_LOADFILE (This); + Private = VirtualNic->Private; + PxeBc = &Private->PxeBc; + UsingIpv6 = FALSE; + Status = EFI_DEVICE_ERROR; + // // Check media status before PXE start // - MediaPresent = TRUE; - NetLibDetectMedia (Private->Controller, &MediaPresent); - if (!MediaPresent) { + MediaStatus = EFI_SUCCESS; + NetLibDetectMediaWaitTimeout (Private->Controller, PXEBC_CHECK_MEDIA_WAITING_TIME, &MediaStatus); + if (MediaStatus != EFI_SUCCESS) { return EFI_NO_MEDIA; } @@ -2337,6 +2379,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); } @@ -2351,6 +2402,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;