REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the NetworkPkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Maciej Rabeda <maciej.rabeda@linux.intel.com>
		
			
				
	
	
		
			1540 lines
		
	
	
		
			44 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1540 lines
		
	
	
		
			44 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Support functions implementation for UefiPxeBc Driver.
 | |
| 
 | |
|   Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
 | |
| 
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "PxeBcImpl.h"
 | |
| 
 | |
| /**
 | |
|   Flush the previous configuration using the new station Ip address.
 | |
| 
 | |
|   @param[in]   Private        The pointer to the PxeBc private data.
 | |
|   @param[in]   StationIp      The pointer to the station Ip address.
 | |
|   @param[in]   SubnetMask     The pointer to the subnet mask address for v4.
 | |
| 
 | |
|   @retval EFI_SUCCESS         Successfully flushed the previous configuration.
 | |
|   @retval Others              Failed to flush using the new station Ip.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| PxeBcFlushStationIp (
 | |
|   PXEBC_PRIVATE_DATA  *Private,
 | |
|   EFI_IP_ADDRESS      *StationIp      OPTIONAL,
 | |
|   EFI_IP_ADDRESS      *SubnetMask     OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_PXE_BASE_CODE_MODE  *Mode;
 | |
|   EFI_STATUS              Status;
 | |
|   EFI_ARP_CONFIG_DATA     ArpConfigData;
 | |
| 
 | |
|   Mode   = Private->PxeBc.Mode;
 | |
|   Status = EFI_SUCCESS;
 | |
|   ZeroMem (&ArpConfigData, sizeof (EFI_ARP_CONFIG_DATA));
 | |
| 
 | |
|   if (Mode->UsingIpv6 && (StationIp != NULL)) {
 | |
|     //
 | |
|     // Overwrite Udp6CfgData/Ip6CfgData StationAddress.
 | |
|     //
 | |
|     CopyMem (&Private->Udp6CfgData.StationAddress, StationIp, sizeof (EFI_IPv6_ADDRESS));
 | |
|     CopyMem (&Private->Ip6CfgData.StationAddress, StationIp, sizeof (EFI_IPv6_ADDRESS));
 | |
| 
 | |
|     //
 | |
|     // Reconfigure the Ip6 instance to capture background ICMP6 packets with new station Ip address.
 | |
|     //
 | |
|     Private->Ip6->Cancel (Private->Ip6, &Private->Icmp6Token);
 | |
|     Private->Ip6->Configure (Private->Ip6, NULL);
 | |
| 
 | |
|     Status = Private->Ip6->Configure (Private->Ip6, &Private->Ip6CfgData);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
| 
 | |
|     Status = Private->Ip6->Receive (Private->Ip6, &Private->Icmp6Token);
 | |
|   } else {
 | |
|     if (StationIp != NULL) {
 | |
|       //
 | |
|       // Reconfigure the ARP instance with station Ip address.
 | |
|       //
 | |
|       ArpConfigData.SwAddressType   = 0x0800;
 | |
|       ArpConfigData.SwAddressLength = (UINT8)sizeof (EFI_IPv4_ADDRESS);
 | |
|       ArpConfigData.StationAddress  = StationIp;
 | |
| 
 | |
|       Private->Arp->Configure (Private->Arp, NULL);
 | |
|       Private->Arp->Configure (Private->Arp, &ArpConfigData);
 | |
| 
 | |
|       //
 | |
|       // Overwrite Udp4CfgData/Ip4CfgData StationAddress.
 | |
|       //
 | |
|       CopyMem (&Private->Udp4CfgData.StationAddress, StationIp, sizeof (EFI_IPv4_ADDRESS));
 | |
|       CopyMem (&Private->Ip4CfgData.StationAddress, StationIp, sizeof (EFI_IPv4_ADDRESS));
 | |
|     }
 | |
| 
 | |
|     if (SubnetMask != NULL) {
 | |
|       //
 | |
|       // Overwrite Udp4CfgData/Ip4CfgData SubnetMask.
 | |
|       //
 | |
|       CopyMem (&Private->Udp4CfgData.SubnetMask, SubnetMask, sizeof (EFI_IPv4_ADDRESS));
 | |
|       CopyMem (&Private->Ip4CfgData.SubnetMask, SubnetMask, sizeof (EFI_IPv4_ADDRESS));
 | |
|     }
 | |
| 
 | |
|     if ((StationIp != NULL) && (SubnetMask != NULL)) {
 | |
|       //
 | |
|       // Updated the route table.
 | |
|       //
 | |
|       Mode->RouteTableEntries                = 1;
 | |
|       Mode->RouteTable[0].IpAddr.Addr[0]     = StationIp->Addr[0] & SubnetMask->Addr[0];
 | |
|       Mode->RouteTable[0].SubnetMask.Addr[0] = SubnetMask->Addr[0];
 | |
|       Mode->RouteTable[0].GwAddr.Addr[0]     = 0;
 | |
|     }
 | |
| 
 | |
|     if ((StationIp != NULL) || (SubnetMask != NULL)) {
 | |
|       //
 | |
|       // Reconfigure the Ip4 instance to capture background ICMP packets with new station Ip address.
 | |
|       //
 | |
|       Private->Ip4->Cancel (Private->Ip4, &Private->IcmpToken);
 | |
|       Private->Ip4->Configure (Private->Ip4, NULL);
 | |
| 
 | |
|       Status = Private->Ip4->Configure (Private->Ip4, &Private->Ip4CfgData);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         goto ON_EXIT;
 | |
|       }
 | |
| 
 | |
|       Status = Private->Ip4->Receive (Private->Ip4, &Private->IcmpToken);
 | |
|     }
 | |
|   }
 | |
| 
 | |
| ON_EXIT:
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Notify the callback function when an event is triggered.
 | |
| 
 | |
|   @param[in]  Event           The triggered event.
 | |
|   @param[in]  Context         The opaque parameter to the function.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| PxeBcCommonNotify (
 | |
|   IN EFI_EVENT  Event,
 | |
|   IN VOID       *Context
 | |
|   )
 | |
| {
 | |
|   *((BOOLEAN *)Context) = TRUE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Do arp resolution from arp cache in PxeBcMode.
 | |
| 
 | |
|   @param  Mode           The pointer to EFI_PXE_BASE_CODE_MODE.
 | |
|   @param  Ip4Addr        The Ip4 address for resolution.
 | |
|   @param  MacAddress     The resolved MAC address if the resolution is successful.
 | |
|                          The value is undefined if the resolution fails.
 | |
| 
 | |
|   @retval TRUE           Found an matched entry.
 | |
|   @retval FALSE          Did not find a matched entry.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| PxeBcCheckArpCache (
 | |
|   IN  EFI_PXE_BASE_CODE_MODE  *Mode,
 | |
|   IN  EFI_IPv4_ADDRESS        *Ip4Addr,
 | |
|   OUT EFI_MAC_ADDRESS         *MacAddress
 | |
|   )
 | |
| {
 | |
|   UINT32  Index;
 | |
| 
 | |
|   ASSERT (!Mode->UsingIpv6);
 | |
| 
 | |
|   //
 | |
|   // Check whether the current Arp cache in mode data contains this information or not.
 | |
|   //
 | |
|   for (Index = 0; Index < Mode->ArpCacheEntries; Index++) {
 | |
|     if (EFI_IP4_EQUAL (&Mode->ArpCache[Index].IpAddr.v4, Ip4Addr)) {
 | |
|       CopyMem (
 | |
|         MacAddress,
 | |
|         &Mode->ArpCache[Index].MacAddr,
 | |
|         sizeof (EFI_MAC_ADDRESS)
 | |
|         );
 | |
|       return TRUE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Update the arp cache periodically.
 | |
| 
 | |
|   @param  Event              The pointer to EFI_PXE_BC_PROTOCOL.
 | |
|   @param  Context            Context of the timer event.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| PxeBcArpCacheUpdate (
 | |
|   IN EFI_EVENT  Event,
 | |
|   IN VOID       *Context
 | |
|   )
 | |
| {
 | |
|   PXEBC_PRIVATE_DATA      *Private;
 | |
|   EFI_PXE_BASE_CODE_MODE  *Mode;
 | |
|   EFI_ARP_FIND_DATA       *ArpEntry;
 | |
|   UINT32                  EntryLength;
 | |
|   UINT32                  EntryCount;
 | |
|   UINT32                  Index;
 | |
|   EFI_STATUS              Status;
 | |
| 
 | |
|   Private = (PXEBC_PRIVATE_DATA *)Context;
 | |
|   Mode    = Private->PxeBc.Mode;
 | |
| 
 | |
|   ASSERT (!Mode->UsingIpv6);
 | |
| 
 | |
|   //
 | |
|   // Get the current Arp cache from Arp driver.
 | |
|   //
 | |
|   Status = Private->Arp->Find (
 | |
|                            Private->Arp,
 | |
|                            TRUE,
 | |
|                            NULL,
 | |
|                            &EntryLength,
 | |
|                            &EntryCount,
 | |
|                            &ArpEntry,
 | |
|                            TRUE
 | |
|                            );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Update the Arp cache in mode data.
 | |
|   //
 | |
|   Mode->ArpCacheEntries = MIN (EntryCount, EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES);
 | |
| 
 | |
|   for (Index = 0; Index < Mode->ArpCacheEntries; Index++) {
 | |
|     CopyMem (
 | |
|       &Mode->ArpCache[Index].IpAddr,
 | |
|       ArpEntry + 1,
 | |
|       ArpEntry->SwAddressLength
 | |
|       );
 | |
|     CopyMem (
 | |
|       &Mode->ArpCache[Index].MacAddr,
 | |
|       (UINT8 *)(ArpEntry + 1) + ArpEntry->SwAddressLength,
 | |
|       ArpEntry->HwAddressLength
 | |
|       );
 | |
|     ArpEntry = (EFI_ARP_FIND_DATA *)((UINT8 *)ArpEntry + EntryLength);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Notify function to handle the received ICMP message in DPC.
 | |
| 
 | |
|   @param  Context               The PXEBC private data.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| PxeBcIcmpErrorDpcHandle (
 | |
|   IN VOID  *Context
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
|   EFI_IP4_RECEIVE_DATA    *RxData;
 | |
|   EFI_IP4_PROTOCOL        *Ip4;
 | |
|   PXEBC_PRIVATE_DATA      *Private;
 | |
|   EFI_PXE_BASE_CODE_MODE  *Mode;
 | |
|   UINT8                   Type;
 | |
|   UINTN                   Index;
 | |
|   UINT32                  CopiedLen;
 | |
|   UINT8                   *IcmpError;
 | |
| 
 | |
|   Private = (PXEBC_PRIVATE_DATA *)Context;
 | |
|   Mode    = &Private->Mode;
 | |
|   Status  = Private->IcmpToken.Status;
 | |
|   RxData  = Private->IcmpToken.Packet.RxData;
 | |
|   Ip4     = Private->Ip4;
 | |
| 
 | |
|   ASSERT (!Mode->UsingIpv6);
 | |
| 
 | |
|   if (Status == EFI_ABORTED) {
 | |
|     //
 | |
|     // It's triggered by user cancellation.
 | |
|     //
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (RxData == NULL) {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   if (Status != EFI_ICMP_ERROR) {
 | |
|     //
 | |
|     // The return status should be recognized as EFI_ICMP_ERROR.
 | |
|     //
 | |
|     goto ON_RECYCLE;
 | |
|   }
 | |
| 
 | |
|   if ((EFI_IP4 (RxData->Header->SourceAddress) != 0) &&
 | |
|       (NTOHL (Mode->SubnetMask.Addr[0]) != 0) &&
 | |
|       IP4_NET_EQUAL (NTOHL (Mode->StationIp.Addr[0]), EFI_NTOHL (RxData->Header->SourceAddress), NTOHL (Mode->SubnetMask.Addr[0])) &&
 | |
|       !NetIp4IsUnicast (EFI_NTOHL (RxData->Header->SourceAddress), NTOHL (Mode->SubnetMask.Addr[0])))
 | |
|   {
 | |
|     //
 | |
|     // The source address of the received packet should be a valid unicast address.
 | |
|     //
 | |
|     goto ON_RECYCLE;
 | |
|   }
 | |
| 
 | |
|   if (!EFI_IP4_EQUAL (&RxData->Header->DestinationAddress, &Mode->StationIp.v4)) {
 | |
|     //
 | |
|     // The destination address of the received packet should be equal to the host address.
 | |
|     //
 | |
|     goto ON_RECYCLE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // The protocol has been configured to only receive ICMP packet.
 | |
|   //
 | |
|   ASSERT (RxData->Header->Protocol == EFI_IP_PROTO_ICMP);
 | |
| 
 | |
|   Type = *((UINT8 *)RxData->FragmentTable[0].FragmentBuffer);
 | |
| 
 | |
|   if ((Type != ICMP_DEST_UNREACHABLE) &&
 | |
|       (Type != ICMP_SOURCE_QUENCH) &&
 | |
|       (Type != ICMP_REDIRECT) &&
 | |
|       (Type != ICMP_TIME_EXCEEDED) &&
 | |
|       (Type != ICMP_PARAMETER_PROBLEM))
 | |
|   {
 | |
|     //
 | |
|     // The type of the receveid ICMP message should be ICMP_ERROR_MESSAGE.
 | |
|     //
 | |
|     goto ON_RECYCLE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Copy the right ICMP error message into mode data.
 | |
|   //
 | |
|   CopiedLen = 0;
 | |
|   IcmpError = (UINT8 *)&Mode->IcmpError;
 | |
| 
 | |
|   for (Index = 0; Index < RxData->FragmentCount; Index++) {
 | |
|     CopiedLen += RxData->FragmentTable[Index].FragmentLength;
 | |
|     if (CopiedLen <= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)) {
 | |
|       CopyMem (
 | |
|         IcmpError,
 | |
|         RxData->FragmentTable[Index].FragmentBuffer,
 | |
|         RxData->FragmentTable[Index].FragmentLength
 | |
|         );
 | |
|     } else {
 | |
|       CopyMem (
 | |
|         IcmpError,
 | |
|         RxData->FragmentTable[Index].FragmentBuffer,
 | |
|         CopiedLen - sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     IcmpError += CopiedLen;
 | |
|   }
 | |
| 
 | |
| ON_RECYCLE:
 | |
|   gBS->SignalEvent (RxData->RecycleSignal);
 | |
| 
 | |
| ON_EXIT:
 | |
|   Private->IcmpToken.Status = EFI_NOT_READY;
 | |
|   Ip4->Receive (Ip4, &Private->IcmpToken);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Callback function to update the latest ICMP6 error message.
 | |
| 
 | |
|   @param  Event                 The event signalled.
 | |
|   @param  Context               The context passed in using the event notifier.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| PxeBcIcmpErrorUpdate (
 | |
|   IN EFI_EVENT  Event,
 | |
|   IN VOID       *Context
 | |
|   )
 | |
| {
 | |
|   QueueDpc (TPL_CALLBACK, PxeBcIcmpErrorDpcHandle, Context);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Notify function to handle the received ICMP6 message in DPC.
 | |
| 
 | |
|   @param  Context               The PXEBC private data.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| PxeBcIcmp6ErrorDpcHandle (
 | |
|   IN VOID  *Context
 | |
|   )
 | |
| {
 | |
|   PXEBC_PRIVATE_DATA      *Private;
 | |
|   EFI_IP6_RECEIVE_DATA    *RxData;
 | |
|   EFI_IP6_PROTOCOL        *Ip6;
 | |
|   EFI_PXE_BASE_CODE_MODE  *Mode;
 | |
|   EFI_STATUS              Status;
 | |
|   UINTN                   Index;
 | |
|   UINT8                   Type;
 | |
|   UINT32                  CopiedLen;
 | |
|   UINT8                   *Icmp6Error;
 | |
| 
 | |
|   Private = (PXEBC_PRIVATE_DATA *)Context;
 | |
|   Mode    = &Private->Mode;
 | |
|   Status  = Private->Icmp6Token.Status;
 | |
|   RxData  = Private->Icmp6Token.Packet.RxData;
 | |
|   Ip6     = Private->Ip6;
 | |
| 
 | |
|   ASSERT (Mode->UsingIpv6);
 | |
| 
 | |
|   if (Status == EFI_ABORTED) {
 | |
|     //
 | |
|     // It's triggered by user cancellation.
 | |
|     //
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (RxData == NULL) {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   if (Status != EFI_ICMP_ERROR) {
 | |
|     //
 | |
|     // The return status should be recognized as EFI_ICMP_ERROR.
 | |
|     //
 | |
|     goto ON_RECYCLE;
 | |
|   }
 | |
| 
 | |
|   if (!NetIp6IsValidUnicast (&RxData->Header->SourceAddress)) {
 | |
|     //
 | |
|     // The source address of the received packet should be a valid unicast address.
 | |
|     //
 | |
|     goto ON_RECYCLE;
 | |
|   }
 | |
| 
 | |
|   if (!NetIp6IsUnspecifiedAddr (&Mode->StationIp.v6) &&
 | |
|       !EFI_IP6_EQUAL (&RxData->Header->DestinationAddress, &Mode->StationIp.v6))
 | |
|   {
 | |
|     //
 | |
|     // The destination address of the received packet should be equal to the host address.
 | |
|     //
 | |
|     goto ON_RECYCLE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // The protocol has been configured to only receive ICMP packet.
 | |
|   //
 | |
|   ASSERT (RxData->Header->NextHeader == IP6_ICMP);
 | |
| 
 | |
|   Type = *((UINT8 *)RxData->FragmentTable[0].FragmentBuffer);
 | |
| 
 | |
|   if ((Type != ICMP_V6_DEST_UNREACHABLE) &&
 | |
|       (Type != ICMP_V6_PACKET_TOO_BIG) &&
 | |
|       (Type != ICMP_V6_TIME_EXCEEDED) &&
 | |
|       (Type != ICMP_V6_PARAMETER_PROBLEM))
 | |
|   {
 | |
|     //
 | |
|     // The type of the receveid packet should be an ICMP6 error message.
 | |
|     //
 | |
|     goto ON_RECYCLE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Copy the right ICMP6 error message into mode data.
 | |
|   //
 | |
|   CopiedLen  = 0;
 | |
|   Icmp6Error = (UINT8 *)&Mode->IcmpError;
 | |
| 
 | |
|   for (Index = 0; Index < RxData->FragmentCount; Index++) {
 | |
|     CopiedLen += RxData->FragmentTable[Index].FragmentLength;
 | |
|     if (CopiedLen <= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)) {
 | |
|       CopyMem (
 | |
|         Icmp6Error,
 | |
|         RxData->FragmentTable[Index].FragmentBuffer,
 | |
|         RxData->FragmentTable[Index].FragmentLength
 | |
|         );
 | |
|     } else {
 | |
|       CopyMem (
 | |
|         Icmp6Error,
 | |
|         RxData->FragmentTable[Index].FragmentBuffer,
 | |
|         CopiedLen - sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     Icmp6Error += CopiedLen;
 | |
|   }
 | |
| 
 | |
| ON_RECYCLE:
 | |
|   gBS->SignalEvent (RxData->RecycleSignal);
 | |
| 
 | |
| ON_EXIT:
 | |
|   Private->Icmp6Token.Status = EFI_NOT_READY;
 | |
|   Ip6->Receive (Ip6, &Private->Icmp6Token);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Callback function to update the latest ICMP6 error message.
 | |
| 
 | |
|   @param  Event                 The event signalled.
 | |
|   @param  Context               The context passed in using the event notifier.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| PxeBcIcmp6ErrorUpdate (
 | |
|   IN EFI_EVENT  Event,
 | |
|   IN VOID       *Context
 | |
|   )
 | |
| {
 | |
|   QueueDpc (TPL_CALLBACK, PxeBcIcmp6ErrorDpcHandle, Context);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function is to configure a UDPv4 instance for UdpWrite.
 | |
| 
 | |
|   @param[in]       Udp4                 The pointer to EFI_UDP4_PROTOCOL.
 | |
|   @param[in]       StationIp            The pointer to the station address.
 | |
|   @param[in]       SubnetMask           The pointer to the subnet mask.
 | |
|   @param[in]       Gateway              The pointer to the gateway address.
 | |
|   @param[in, out]  SrcPort              The pointer to the source port.
 | |
|   @param[in]       DoNotFragment        If TRUE, fragment is not enabled.
 | |
|                                         Otherwise, fragment is enabled.
 | |
|   @param[in]       Ttl                  The time to live field of the IP header.
 | |
|   @param[in]       ToS                  The type of service field of the IP header.
 | |
| 
 | |
|   @retval          EFI_SUCCESS          Successfully configured this instance.
 | |
|   @retval          Others               Failed to configure this instance.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| PxeBcConfigUdp4Write (
 | |
|   IN     EFI_UDP4_PROTOCOL  *Udp4,
 | |
|   IN     EFI_IPv4_ADDRESS   *StationIp,
 | |
|   IN     EFI_IPv4_ADDRESS   *SubnetMask,
 | |
|   IN     EFI_IPv4_ADDRESS   *Gateway,
 | |
|   IN OUT UINT16             *SrcPort,
 | |
|   IN     BOOLEAN            DoNotFragment,
 | |
|   IN     UINT8              Ttl,
 | |
|   IN     UINT8              ToS
 | |
|   )
 | |
| {
 | |
|   EFI_UDP4_CONFIG_DATA  Udp4CfgData;
 | |
|   EFI_STATUS            Status;
 | |
| 
 | |
|   ZeroMem (&Udp4CfgData, sizeof (Udp4CfgData));
 | |
| 
 | |
|   Udp4CfgData.TransmitTimeout    = PXEBC_DEFAULT_LIFETIME;
 | |
|   Udp4CfgData.ReceiveTimeout     = PXEBC_DEFAULT_LIFETIME;
 | |
|   Udp4CfgData.TypeOfService      = ToS;
 | |
|   Udp4CfgData.TimeToLive         = Ttl;
 | |
|   Udp4CfgData.AllowDuplicatePort = TRUE;
 | |
|   Udp4CfgData.DoNotFragment      = DoNotFragment;
 | |
| 
 | |
|   CopyMem (&Udp4CfgData.StationAddress, StationIp, sizeof (*StationIp));
 | |
|   CopyMem (&Udp4CfgData.SubnetMask, SubnetMask, sizeof (*SubnetMask));
 | |
| 
 | |
|   Udp4CfgData.StationPort = *SrcPort;
 | |
| 
 | |
|   //
 | |
|   // Reset the UDPv4 instance.
 | |
|   //
 | |
|   Udp4->Configure (Udp4, NULL);
 | |
| 
 | |
|   Status = Udp4->Configure (Udp4, &Udp4CfgData);
 | |
|   if (!EFI_ERROR (Status) && !EFI_IP4_EQUAL (Gateway, &mZeroIp4Addr)) {
 | |
|     //
 | |
|     // The basic configuration is OK, need to add the default route entry
 | |
|     //
 | |
|     Status = Udp4->Routes (Udp4, FALSE, &mZeroIp4Addr, &mZeroIp4Addr, Gateway);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       Udp4->Configure (Udp4, NULL);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!EFI_ERROR (Status) && (*SrcPort == 0)) {
 | |
|     Udp4->GetModeData (Udp4, &Udp4CfgData, NULL, NULL, NULL);
 | |
|     *SrcPort = Udp4CfgData.StationPort;
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function is to configure a UDPv6 instance for UdpWrite.
 | |
| 
 | |
|   @param[in]       Udp6                 The pointer to EFI_UDP6_PROTOCOL.
 | |
|   @param[in]       StationIp            The pointer to the station address.
 | |
|   @param[in, out]  SrcPort              The pointer to the source port.
 | |
| 
 | |
|   @retval          EFI_SUCCESS          Successfully configured this instance.
 | |
|   @retval          Others               Failed to configure this instance.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| PxeBcConfigUdp6Write (
 | |
|   IN     EFI_UDP6_PROTOCOL  *Udp6,
 | |
|   IN     EFI_IPv6_ADDRESS   *StationIp,
 | |
|   IN OUT UINT16             *SrcPort
 | |
|   )
 | |
| {
 | |
|   EFI_UDP6_CONFIG_DATA  CfgData;
 | |
|   EFI_STATUS            Status;
 | |
| 
 | |
|   ZeroMem (&CfgData, sizeof (EFI_UDP6_CONFIG_DATA));
 | |
| 
 | |
|   CfgData.ReceiveTimeout     = PXEBC_DEFAULT_LIFETIME;
 | |
|   CfgData.TransmitTimeout    = PXEBC_DEFAULT_LIFETIME;
 | |
|   CfgData.HopLimit           = PXEBC_DEFAULT_HOPLIMIT;
 | |
|   CfgData.AllowDuplicatePort = TRUE;
 | |
|   CfgData.StationPort        = *SrcPort;
 | |
| 
 | |
|   CopyMem (&CfgData.StationAddress, StationIp, sizeof (EFI_IPv6_ADDRESS));
 | |
| 
 | |
|   //
 | |
|   // Reset the UDPv6 instance.
 | |
|   //
 | |
|   Udp6->Configure (Udp6, NULL);
 | |
| 
 | |
|   Status = Udp6->Configure (Udp6, &CfgData);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   if (!EFI_ERROR (Status) && (*SrcPort == 0)) {
 | |
|     Udp6->GetModeData (Udp6, &CfgData, NULL, NULL, NULL);
 | |
|     *SrcPort = CfgData.StationPort;
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function is to configure a UDPv4 instance for UdpWrite.
 | |
| 
 | |
|   @param[in]       Udp4                 The pointer to EFI_UDP4_PROTOCOL.
 | |
|   @param[in]       Session              The pointer to the UDP4 session data.
 | |
|   @param[in]       TimeoutEvent         The event for timeout.
 | |
|   @param[in]       Gateway              The pointer to the gateway address.
 | |
|   @param[in]       HeaderSize           An optional field which may be set to the length of a header
 | |
|                                         at HeaderPtr to be prefixed to the data at BufferPtr.
 | |
|   @param[in]       HeaderPtr            If HeaderSize is not NULL, a pointer to a header to be
 | |
|                                         prefixed to the data at BufferPtr.
 | |
|   @param[in]       BufferSize           A pointer to the size of the data at BufferPtr.
 | |
|   @param[in]       BufferPtr            A pointer to the data to be written.
 | |
| 
 | |
|   @retval          EFI_SUCCESS          Successfully send out data using Udp4Write.
 | |
|   @retval          Others               Failed to send out data.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| PxeBcUdp4Write (
 | |
|   IN EFI_UDP4_PROTOCOL      *Udp4,
 | |
|   IN EFI_UDP4_SESSION_DATA  *Session,
 | |
|   IN EFI_EVENT              TimeoutEvent,
 | |
|   IN EFI_IPv4_ADDRESS       *Gateway      OPTIONAL,
 | |
|   IN UINTN                  *HeaderSize   OPTIONAL,
 | |
|   IN VOID                   *HeaderPtr    OPTIONAL,
 | |
|   IN UINTN                  *BufferSize,
 | |
|   IN VOID                   *BufferPtr
 | |
|   )
 | |
| {
 | |
|   EFI_UDP4_COMPLETION_TOKEN  Token;
 | |
|   EFI_UDP4_TRANSMIT_DATA     *TxData;
 | |
|   UINT32                     TxLength;
 | |
|   UINT32                     FragCount;
 | |
|   UINT32                     DataLength;
 | |
|   BOOLEAN                    IsDone;
 | |
|   EFI_STATUS                 Status;
 | |
| 
 | |
|   //
 | |
|   // Arrange one fragment buffer for data, and another fragment buffer for header if has.
 | |
|   //
 | |
|   FragCount = (HeaderSize != NULL) ? 2 : 1;
 | |
|   TxLength  = sizeof (EFI_UDP4_TRANSMIT_DATA) + (FragCount - 1) * sizeof (EFI_UDP4_FRAGMENT_DATA);
 | |
|   TxData    = (EFI_UDP4_TRANSMIT_DATA *)AllocateZeroPool (TxLength);
 | |
|   if (TxData == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   TxData->FragmentCount                               = FragCount;
 | |
|   TxData->FragmentTable[FragCount - 1].FragmentLength = (UINT32)*BufferSize;
 | |
|   TxData->FragmentTable[FragCount - 1].FragmentBuffer = BufferPtr;
 | |
|   DataLength                                          = (UINT32)*BufferSize;
 | |
| 
 | |
|   if (HeaderSize != NULL) {
 | |
|     TxData->FragmentTable[0].FragmentLength = (UINT32)*HeaderSize;
 | |
|     TxData->FragmentTable[0].FragmentBuffer = HeaderPtr;
 | |
|     DataLength                             += (UINT32)*HeaderSize;
 | |
|   }
 | |
| 
 | |
|   if (Gateway != NULL) {
 | |
|     TxData->GatewayAddress = Gateway;
 | |
|   }
 | |
| 
 | |
|   TxData->UdpSessionData = Session;
 | |
|   TxData->DataLength     = DataLength;
 | |
|   Token.Packet.TxData    = TxData;
 | |
|   Token.Status           = EFI_NOT_READY;
 | |
|   IsDone                 = FALSE;
 | |
| 
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_NOTIFY_SIGNAL,
 | |
|                   TPL_NOTIFY,
 | |
|                   PxeBcCommonNotify,
 | |
|                   &IsDone,
 | |
|                   &Token.Event
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   Status = Udp4->Transmit (Udp4, &Token);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Poll the UDPv6 read instance if no packet received and no timeout triggered.
 | |
|   //
 | |
|   while (!IsDone &&
 | |
|          Token.Status == EFI_NOT_READY &&
 | |
|          EFI_ERROR (gBS->CheckEvent (TimeoutEvent)))
 | |
|   {
 | |
|     Udp4->Poll (Udp4);
 | |
|   }
 | |
| 
 | |
|   Status = (Token.Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token.Status;
 | |
| 
 | |
| ON_EXIT:
 | |
|   if (Token.Event != NULL) {
 | |
|     gBS->CloseEvent (Token.Event);
 | |
|   }
 | |
| 
 | |
|   FreePool (TxData);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function is to configure a UDPv4 instance for UdpWrite.
 | |
| 
 | |
|   @param[in]       Udp6                 The pointer to EFI_UDP6_PROTOCOL.
 | |
|   @param[in]       Session              The pointer to the UDP6 session data.
 | |
|   @param[in]       TimeoutEvent         The event for timeout.
 | |
|   @param[in]       HeaderSize           An optional field which may be set to the length of a header
 | |
|                                         at HeaderPtr to be prefixed to the data at BufferPtr.
 | |
|   @param[in]       HeaderPtr            If HeaderSize is not NULL, a pointer to a header to be
 | |
|                                         prefixed to the data at BufferPtr.
 | |
|   @param[in]       BufferSize           A pointer to the size of the data at BufferPtr.
 | |
|   @param[in]       BufferPtr            A pointer to the data to be written.
 | |
| 
 | |
|   @retval          EFI_SUCCESS          Successfully sent out data using Udp6Write.
 | |
|   @retval          Others               Failed to send out data.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| PxeBcUdp6Write (
 | |
|   IN EFI_UDP6_PROTOCOL      *Udp6,
 | |
|   IN EFI_UDP6_SESSION_DATA  *Session,
 | |
|   IN EFI_EVENT              TimeoutEvent,
 | |
|   IN UINTN                  *HeaderSize   OPTIONAL,
 | |
|   IN VOID                   *HeaderPtr    OPTIONAL,
 | |
|   IN UINTN                  *BufferSize,
 | |
|   IN VOID                   *BufferPtr
 | |
|   )
 | |
| {
 | |
|   EFI_UDP6_COMPLETION_TOKEN  Token;
 | |
|   EFI_UDP6_TRANSMIT_DATA     *TxData;
 | |
|   UINT32                     TxLength;
 | |
|   UINT32                     FragCount;
 | |
|   UINT32                     DataLength;
 | |
|   BOOLEAN                    IsDone;
 | |
|   EFI_STATUS                 Status;
 | |
| 
 | |
|   //
 | |
|   // Arrange one fragment buffer for data, and another fragment buffer for header if has.
 | |
|   //
 | |
|   FragCount = (HeaderSize != NULL) ? 2 : 1;
 | |
|   TxLength  = sizeof (EFI_UDP6_TRANSMIT_DATA) + (FragCount - 1) * sizeof (EFI_UDP6_FRAGMENT_DATA);
 | |
|   TxData    = (EFI_UDP6_TRANSMIT_DATA *)AllocateZeroPool (TxLength);
 | |
|   if (TxData == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   TxData->FragmentCount                               = FragCount;
 | |
|   TxData->FragmentTable[FragCount - 1].FragmentLength = (UINT32)*BufferSize;
 | |
|   TxData->FragmentTable[FragCount - 1].FragmentBuffer = BufferPtr;
 | |
|   DataLength                                          = (UINT32)*BufferSize;
 | |
| 
 | |
|   if (HeaderSize != NULL) {
 | |
|     TxData->FragmentTable[0].FragmentLength = (UINT32)*HeaderSize;
 | |
|     TxData->FragmentTable[0].FragmentBuffer = HeaderPtr;
 | |
|     DataLength                             += (UINT32)*HeaderSize;
 | |
|   }
 | |
| 
 | |
|   TxData->UdpSessionData = Session;
 | |
|   TxData->DataLength     = DataLength;
 | |
|   Token.Packet.TxData    = TxData;
 | |
|   Token.Status           = EFI_NOT_READY;
 | |
|   IsDone                 = FALSE;
 | |
| 
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_NOTIFY_SIGNAL,
 | |
|                   TPL_NOTIFY,
 | |
|                   PxeBcCommonNotify,
 | |
|                   &IsDone,
 | |
|                   &Token.Event
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   Status = Udp6->Transmit (Udp6, &Token);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Poll the UDPv6 read instance if no packet received and no timeout triggered.
 | |
|   //
 | |
|   while (!IsDone &&
 | |
|          Token.Status == EFI_NOT_READY &&
 | |
|          EFI_ERROR (gBS->CheckEvent (TimeoutEvent)))
 | |
|   {
 | |
|     Udp6->Poll (Udp6);
 | |
|   }
 | |
| 
 | |
|   Status = (Token.Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token.Status;
 | |
| 
 | |
| ON_EXIT:
 | |
|   if (Token.Event != NULL) {
 | |
|     gBS->CloseEvent (Token.Event);
 | |
|   }
 | |
| 
 | |
|   FreePool (TxData);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Check the received packet using the Ip filter.
 | |
| 
 | |
|   @param[in]  Mode                The pointer to the mode data of PxeBc.
 | |
|   @param[in]  Session             The pointer to the current UDPv4 session.
 | |
|   @param[in]  OpFlags             Operation flag for UdpRead/UdpWrite.
 | |
| 
 | |
|   @retval     TRUE                Passed the Ip filter successfully.
 | |
|   @retval     FALSE               Failed to pass the Ip filter.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| PxeBcCheckByIpFilter (
 | |
|   IN EFI_PXE_BASE_CODE_MODE  *Mode,
 | |
|   IN VOID                    *Session,
 | |
|   IN UINT16                  OpFlags
 | |
|   )
 | |
| {
 | |
|   EFI_IP_ADDRESS  DestinationIp;
 | |
|   UINTN           Index;
 | |
| 
 | |
|   if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_USE_FILTER) == 0) {
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   if ((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS) != 0) {
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Convert the destination address in session data to host order.
 | |
|   //
 | |
|   if (Mode->UsingIpv6) {
 | |
|     CopyMem (
 | |
|       &DestinationIp,
 | |
|       &((EFI_UDP6_SESSION_DATA *)Session)->DestinationAddress,
 | |
|       sizeof (EFI_IPv6_ADDRESS)
 | |
|       );
 | |
|     NTOHLLL (&DestinationIp.v6);
 | |
|   } else {
 | |
|     ZeroMem (&DestinationIp, sizeof (EFI_IP_ADDRESS));
 | |
|     CopyMem (
 | |
|       &DestinationIp,
 | |
|       &((EFI_UDP4_SESSION_DATA *)Session)->DestinationAddress,
 | |
|       sizeof (EFI_IPv4_ADDRESS)
 | |
|       );
 | |
|     EFI_NTOHL (DestinationIp);
 | |
|   }
 | |
| 
 | |
|   if (((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) != 0) &&
 | |
|       (IP4_IS_MULTICAST (DestinationIp.Addr[0]) ||
 | |
|        IP6_IS_MULTICAST (&DestinationIp)))
 | |
|   {
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   if (((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_BROADCAST) != 0) &&
 | |
|       IP4_IS_LOCAL_BROADCAST (DestinationIp.Addr[0]))
 | |
|   {
 | |
|     ASSERT (!Mode->UsingIpv6);
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   if (((Mode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) != 0) &&
 | |
|       (EFI_IP4_EQUAL (&Mode->StationIp.v4, &DestinationIp) ||
 | |
|        EFI_IP6_EQUAL (&Mode->StationIp.v6, &DestinationIp)))
 | |
|   {
 | |
|     //
 | |
|     // Matched if the dest address is equal to the station address.
 | |
|     //
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   for (Index = 0; Index < Mode->IpFilter.IpCnt; Index++) {
 | |
|     ASSERT (Index < EFI_PXE_BASE_CODE_MAX_IPCNT);
 | |
|     if (EFI_IP4_EQUAL (&Mode->IpFilter.IpList[Index].v4, &DestinationIp) ||
 | |
|         EFI_IP6_EQUAL (&Mode->IpFilter.IpList[Index].v6, &DestinationIp))
 | |
|     {
 | |
|       //
 | |
|       // Matched if the dest address is equal to any of address in the filter list.
 | |
|       //
 | |
|       return TRUE;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Filter the received packet using the destination Ip.
 | |
| 
 | |
|   @param[in]       Mode           The pointer to the mode data of PxeBc.
 | |
|   @param[in]       Session        The pointer to the current UDPv4 session.
 | |
|   @param[in, out]  DestIp         The pointer to the destination Ip address.
 | |
|   @param[in]       OpFlags        Operation flag for UdpRead/UdpWrite.
 | |
| 
 | |
|   @retval     TRUE                Passed the IPv4 filter successfully.
 | |
|   @retval     FALSE               Failed to pass the IPv4 filter.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| PxeBcCheckByDestIp (
 | |
|   IN     EFI_PXE_BASE_CODE_MODE  *Mode,
 | |
|   IN     VOID                    *Session,
 | |
|   IN OUT EFI_IP_ADDRESS          *DestIp,
 | |
|   IN     UINT16                  OpFlags
 | |
|   )
 | |
| {
 | |
|   if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_IP) != 0) {
 | |
|     //
 | |
|     // Copy the destination address from the received packet if accept any.
 | |
|     //
 | |
|     if (DestIp != NULL) {
 | |
|       if (Mode->UsingIpv6) {
 | |
|         CopyMem (
 | |
|           DestIp,
 | |
|           &((EFI_UDP6_SESSION_DATA *)Session)->DestinationAddress,
 | |
|           sizeof (EFI_IPv6_ADDRESS)
 | |
|           );
 | |
|       } else {
 | |
|         ZeroMem (DestIp, sizeof (EFI_IP_ADDRESS));
 | |
|         CopyMem (
 | |
|           DestIp,
 | |
|           &((EFI_UDP4_SESSION_DATA *)Session)->DestinationAddress,
 | |
|           sizeof (EFI_IPv4_ADDRESS)
 | |
|           );
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     return TRUE;
 | |
|   } else if ((DestIp != NULL) &&
 | |
|              (EFI_IP4_EQUAL (DestIp, &((EFI_UDP4_SESSION_DATA *)Session)->DestinationAddress) ||
 | |
|               EFI_IP6_EQUAL (DestIp, &((EFI_UDP6_SESSION_DATA *)Session)->DestinationAddress)))
 | |
|   {
 | |
|     //
 | |
|     // The destination address in the received packet is matched if present.
 | |
|     //
 | |
|     return TRUE;
 | |
|   } else if (EFI_IP4_EQUAL (&Mode->StationIp, &((EFI_UDP4_SESSION_DATA *)Session)->DestinationAddress) ||
 | |
|              EFI_IP6_EQUAL (&Mode->StationIp, &((EFI_UDP6_SESSION_DATA *)Session)->DestinationAddress))
 | |
|   {
 | |
|     //
 | |
|     // The destination address in the received packet is equal to the host address.
 | |
|     //
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Check the received packet using the destination port.
 | |
| 
 | |
|   @param[in]       Mode           The pointer to the mode data of PxeBc.
 | |
|   @param[in]       Session        The pointer to the current UDPv4 session.
 | |
|   @param[in, out]  DestPort       The pointer to the destination port.
 | |
|   @param[in]       OpFlags        Operation flag for UdpRead/UdpWrite.
 | |
| 
 | |
|   @retval     TRUE                Passed the IPv4 filter successfully.
 | |
|   @retval     FALSE               Failed to pass the IPv4 filter.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| PxeBcCheckByDestPort (
 | |
|   IN     EFI_PXE_BASE_CODE_MODE  *Mode,
 | |
|   IN     VOID                    *Session,
 | |
|   IN OUT UINT16                  *DestPort,
 | |
|   IN     UINT16                  OpFlags
 | |
|   )
 | |
| {
 | |
|   UINT16  Port;
 | |
| 
 | |
|   if (Mode->UsingIpv6) {
 | |
|     Port = ((EFI_UDP6_SESSION_DATA *)Session)->DestinationPort;
 | |
|   } else {
 | |
|     Port = ((EFI_UDP4_SESSION_DATA *)Session)->DestinationPort;
 | |
|   }
 | |
| 
 | |
|   if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_DEST_PORT) != 0) {
 | |
|     //
 | |
|     // Return the destination port in the received packet if accept any.
 | |
|     //
 | |
|     if (DestPort != NULL) {
 | |
|       *DestPort = Port;
 | |
|     }
 | |
| 
 | |
|     return TRUE;
 | |
|   } else if ((DestPort != NULL) && (*DestPort == Port)) {
 | |
|     //
 | |
|     // The destination port in the received packet is matched if present.
 | |
|     //
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Filter the received packet using the source Ip.
 | |
| 
 | |
|   @param[in]       Mode           The pointer to the mode data of PxeBc.
 | |
|   @param[in]       Session        The pointer to the current UDPv4 session.
 | |
|   @param[in, out]  SrcIp          The pointer to the source Ip address.
 | |
|   @param[in]       OpFlags        Operation flag for UdpRead/UdpWrite.
 | |
| 
 | |
|   @retval     TRUE                Passed the IPv4 filter successfully.
 | |
|   @retval     FALSE               Failed to pass the IPv4 filter.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| PxeBcFilterBySrcIp (
 | |
|   IN     EFI_PXE_BASE_CODE_MODE  *Mode,
 | |
|   IN     VOID                    *Session,
 | |
|   IN OUT EFI_IP_ADDRESS          *SrcIp,
 | |
|   IN     UINT16                  OpFlags
 | |
|   )
 | |
| {
 | |
|   if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_IP) != 0) {
 | |
|     //
 | |
|     // Copy the source address from the received packet if accept any.
 | |
|     //
 | |
|     if (SrcIp != NULL) {
 | |
|       if (Mode->UsingIpv6) {
 | |
|         CopyMem (
 | |
|           SrcIp,
 | |
|           &((EFI_UDP6_SESSION_DATA *)Session)->SourceAddress,
 | |
|           sizeof (EFI_IPv6_ADDRESS)
 | |
|           );
 | |
|       } else {
 | |
|         ZeroMem (SrcIp, sizeof (EFI_IP_ADDRESS));
 | |
|         CopyMem (
 | |
|           SrcIp,
 | |
|           &((EFI_UDP4_SESSION_DATA *)Session)->SourceAddress,
 | |
|           sizeof (EFI_IPv4_ADDRESS)
 | |
|           );
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     return TRUE;
 | |
|   } else if ((SrcIp != NULL) &&
 | |
|              (EFI_IP4_EQUAL (SrcIp, &((EFI_UDP4_SESSION_DATA *)Session)->SourceAddress) ||
 | |
|               EFI_IP6_EQUAL (SrcIp, &((EFI_UDP6_SESSION_DATA *)Session)->SourceAddress)))
 | |
|   {
 | |
|     //
 | |
|     // The source address in the received packet is matched if present.
 | |
|     //
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Filter the received packet using the source port.
 | |
| 
 | |
|   @param[in]       Mode           The pointer to the mode data of PxeBc.
 | |
|   @param[in]       Session        The pointer to the current UDPv4 session.
 | |
|   @param[in, out]  SrcPort        The pointer to the source port.
 | |
|   @param[in]       OpFlags        Operation flag for UdpRead/UdpWrite.
 | |
| 
 | |
|   @retval     TRUE                Passed the IPv4 filter successfully.
 | |
|   @retval     FALSE               Failed to pass the IPv4 filter.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| PxeBcFilterBySrcPort (
 | |
|   IN     EFI_PXE_BASE_CODE_MODE  *Mode,
 | |
|   IN     VOID                    *Session,
 | |
|   IN OUT UINT16                  *SrcPort,
 | |
|   IN     UINT16                  OpFlags
 | |
|   )
 | |
| {
 | |
|   UINT16  Port;
 | |
| 
 | |
|   if (Mode->UsingIpv6) {
 | |
|     Port = ((EFI_UDP6_SESSION_DATA *)Session)->SourcePort;
 | |
|   } else {
 | |
|     Port = ((EFI_UDP4_SESSION_DATA *)Session)->SourcePort;
 | |
|   }
 | |
| 
 | |
|   if ((OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) != 0) {
 | |
|     //
 | |
|     // Return the source port in the received packet if accept any.
 | |
|     //
 | |
|     if (SrcPort != NULL) {
 | |
|       *SrcPort = Port;
 | |
|     }
 | |
| 
 | |
|     return TRUE;
 | |
|   } else if ((SrcPort != NULL) && (*SrcPort == Port)) {
 | |
|     //
 | |
|     // The source port in the received packet is matched if present.
 | |
|     //
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function is to receive packet using Udp4Read.
 | |
| 
 | |
|   @param[in]       Udp4                 The pointer to EFI_UDP4_PROTOCOL.
 | |
|   @param[in]       Token                The pointer to EFI_UDP4_COMPLETION_TOKEN.
 | |
|   @param[in]       Mode                 The pointer to EFI_PXE_BASE_CODE_MODE.
 | |
|   @param[in]       TimeoutEvent         The event for timeout.
 | |
|   @param[in]       OpFlags              The UDP operation flags.
 | |
|   @param[in]       IsDone               The pointer to the IsDone flag.
 | |
|   @param[out]      IsMatched            The pointer to the IsMatched flag.
 | |
|   @param[in, out]  DestIp               The pointer to the destination address.
 | |
|   @param[in, out]  DestPort             The pointer to the destination port.
 | |
|   @param[in, out]  SrcIp                The pointer to the source address.
 | |
|   @param[in, out]  SrcPort              The pointer to the source port.
 | |
| 
 | |
|   @retval          EFI_SUCCESS          Successfully read the data using Udp4.
 | |
|   @retval          Others               Failed to send out data.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| PxeBcUdp4Read (
 | |
|   IN     EFI_UDP4_PROTOCOL           *Udp4,
 | |
|   IN     EFI_UDP4_COMPLETION_TOKEN   *Token,
 | |
|   IN     EFI_PXE_BASE_CODE_MODE      *Mode,
 | |
|   IN     EFI_EVENT                   TimeoutEvent,
 | |
|   IN     UINT16                      OpFlags,
 | |
|   IN     BOOLEAN                     *IsDone,
 | |
|   OUT BOOLEAN                        *IsMatched,
 | |
|   IN OUT EFI_IP_ADDRESS              *DestIp      OPTIONAL,
 | |
|   IN OUT EFI_PXE_BASE_CODE_UDP_PORT  *DestPort    OPTIONAL,
 | |
|   IN OUT EFI_IP_ADDRESS              *SrcIp       OPTIONAL,
 | |
|   IN OUT EFI_PXE_BASE_CODE_UDP_PORT  *SrcPort     OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_UDP4_RECEIVE_DATA  *RxData;
 | |
|   EFI_UDP4_SESSION_DATA  *Session;
 | |
|   EFI_STATUS             Status;
 | |
| 
 | |
|   Token->Status = EFI_NOT_READY;
 | |
|   *IsDone       = FALSE;
 | |
| 
 | |
|   Status = Udp4->Receive (Udp4, Token);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Poll the UDPv6 read instance if no packet received and no timeout triggered.
 | |
|   //
 | |
|   while (!(*IsDone) &&
 | |
|          Token->Status == EFI_NOT_READY &&
 | |
|          EFI_ERROR (gBS->CheckEvent (TimeoutEvent)))
 | |
|   {
 | |
|     //
 | |
|     // Poll the token until reply/ICMPv6 error message received or timeout.
 | |
|     //
 | |
|     Udp4->Poll (Udp4);
 | |
|     if ((Token->Status == EFI_ICMP_ERROR) ||
 | |
|         (Token->Status == EFI_NETWORK_UNREACHABLE) ||
 | |
|         (Token->Status == EFI_HOST_UNREACHABLE) ||
 | |
|         (Token->Status == EFI_PROTOCOL_UNREACHABLE) ||
 | |
|         (Token->Status == EFI_PORT_UNREACHABLE))
 | |
|     {
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Status = (Token->Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token->Status;
 | |
| 
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // check whether this packet matches the filters
 | |
|     //
 | |
|     RxData  = Token->Packet.RxData;
 | |
|     Session = &RxData->UdpSession;
 | |
| 
 | |
|     *IsMatched = PxeBcCheckByIpFilter (Mode, Session, OpFlags);
 | |
| 
 | |
|     if (*IsMatched) {
 | |
|       *IsMatched = PxeBcCheckByDestIp (Mode, Session, DestIp, OpFlags);
 | |
|     }
 | |
| 
 | |
|     if (*IsMatched) {
 | |
|       *IsMatched = PxeBcCheckByDestPort (Mode, Session, DestPort, OpFlags);
 | |
|     }
 | |
| 
 | |
|     if (*IsMatched) {
 | |
|       *IsMatched = PxeBcFilterBySrcIp (Mode, Session, SrcIp, OpFlags);
 | |
|     }
 | |
| 
 | |
|     if (*IsMatched) {
 | |
|       *IsMatched = PxeBcFilterBySrcPort (Mode, Session, SrcPort, OpFlags);
 | |
|     }
 | |
| 
 | |
|     if (!(*IsMatched)) {
 | |
|       //
 | |
|       // Recycle the receiving buffer if not matched.
 | |
|       //
 | |
|       gBS->SignalEvent (RxData->RecycleSignal);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function is to receive packets using Udp6Read.
 | |
| 
 | |
|   @param[in]       Udp6                 The pointer to EFI_UDP6_PROTOCOL.
 | |
|   @param[in]       Token                The pointer to EFI_UDP6_COMPLETION_TOKEN.
 | |
|   @param[in]       Mode                 The pointer to EFI_PXE_BASE_CODE_MODE.
 | |
|   @param[in]       TimeoutEvent         The event for timeout.
 | |
|   @param[in]       OpFlags              The UDP operation flags.
 | |
|   @param[in]       IsDone               The pointer to the IsDone flag.
 | |
|   @param[out]      IsMatched            The pointer to the IsMatched flag.
 | |
|   @param[in, out]  DestIp               The pointer to the destination address.
 | |
|   @param[in, out]  DestPort             The pointer to the destination port.
 | |
|   @param[in, out]  SrcIp                The pointer to the source address.
 | |
|   @param[in, out]  SrcPort              The pointer to the source port.
 | |
| 
 | |
|   @retval          EFI_SUCCESS          Successfully read data using Udp6.
 | |
|   @retval          Others               Failed to send out data.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| PxeBcUdp6Read (
 | |
|   IN     EFI_UDP6_PROTOCOL           *Udp6,
 | |
|   IN     EFI_UDP6_COMPLETION_TOKEN   *Token,
 | |
|   IN     EFI_PXE_BASE_CODE_MODE      *Mode,
 | |
|   IN     EFI_EVENT                   TimeoutEvent,
 | |
|   IN     UINT16                      OpFlags,
 | |
|   IN     BOOLEAN                     *IsDone,
 | |
|   OUT BOOLEAN                        *IsMatched,
 | |
|   IN OUT EFI_IP_ADDRESS              *DestIp      OPTIONAL,
 | |
|   IN OUT EFI_PXE_BASE_CODE_UDP_PORT  *DestPort    OPTIONAL,
 | |
|   IN OUT EFI_IP_ADDRESS              *SrcIp       OPTIONAL,
 | |
|   IN OUT EFI_PXE_BASE_CODE_UDP_PORT  *SrcPort     OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_UDP6_RECEIVE_DATA  *RxData;
 | |
|   EFI_UDP6_SESSION_DATA  *Session;
 | |
|   EFI_STATUS             Status;
 | |
| 
 | |
|   Token->Status = EFI_NOT_READY;
 | |
|   *IsDone       = FALSE;
 | |
| 
 | |
|   Status = Udp6->Receive (Udp6, Token);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Poll the UDPv6 read instance if no packet received and no timeout triggered.
 | |
|   //
 | |
|   while (!(*IsDone) &&
 | |
|          Token->Status == EFI_NOT_READY &&
 | |
|          EFI_ERROR (gBS->CheckEvent (TimeoutEvent)))
 | |
|   {
 | |
|     //
 | |
|     // Poll the token until reply/ICMPv6 error message received or timeout.
 | |
|     //
 | |
|     Udp6->Poll (Udp6);
 | |
|     if ((Token->Status == EFI_ICMP_ERROR) ||
 | |
|         (Token->Status == EFI_NETWORK_UNREACHABLE) ||
 | |
|         (Token->Status == EFI_HOST_UNREACHABLE) ||
 | |
|         (Token->Status == EFI_PROTOCOL_UNREACHABLE) ||
 | |
|         (Token->Status == EFI_PORT_UNREACHABLE))
 | |
|     {
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Status = (Token->Status == EFI_NOT_READY) ? EFI_TIMEOUT : Token->Status;
 | |
| 
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // check whether this packet matches the filters
 | |
|     //
 | |
|     RxData  = Token->Packet.RxData;
 | |
|     Session = &RxData->UdpSession;
 | |
| 
 | |
|     *IsMatched = PxeBcCheckByIpFilter (Mode, Session, OpFlags);
 | |
| 
 | |
|     if (*IsMatched) {
 | |
|       *IsMatched = PxeBcCheckByDestIp (Mode, Session, DestIp, OpFlags);
 | |
|     }
 | |
| 
 | |
|     if (*IsMatched) {
 | |
|       *IsMatched = PxeBcCheckByDestPort (Mode, Session, DestPort, OpFlags);
 | |
|     }
 | |
| 
 | |
|     if (*IsMatched) {
 | |
|       *IsMatched = PxeBcFilterBySrcIp (Mode, Session, SrcIp, OpFlags);
 | |
|     }
 | |
| 
 | |
|     if (*IsMatched) {
 | |
|       *IsMatched = PxeBcFilterBySrcPort (Mode, Session, SrcPort, OpFlags);
 | |
|     }
 | |
| 
 | |
|     if (!(*IsMatched)) {
 | |
|       //
 | |
|       // Recycle the receiving buffer if not matched.
 | |
|       //
 | |
|       gBS->SignalEvent (RxData->RecycleSignal);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function is to display the IPv4 address.
 | |
| 
 | |
|   @param[in]  Ip        The pointer to the IPv4 address.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| PxeBcShowIp4Addr (
 | |
|   IN EFI_IPv4_ADDRESS  *Ip
 | |
|   )
 | |
| {
 | |
|   UINTN  Index;
 | |
| 
 | |
|   for (Index = 0; Index < 4; Index++) {
 | |
|     AsciiPrint ("%d", Ip->Addr[Index]);
 | |
|     if (Index < 3) {
 | |
|       AsciiPrint (".");
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function is to display the IPv6 address.
 | |
| 
 | |
|   @param[in]  Ip        The pointer to the IPv6 address.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| PxeBcShowIp6Addr (
 | |
|   IN EFI_IPv6_ADDRESS  *Ip
 | |
|   )
 | |
| {
 | |
|   UINTN  Index;
 | |
| 
 | |
|   for (Index = 0; Index < 16; Index++) {
 | |
|     if (Ip->Addr[Index] != 0) {
 | |
|       AsciiPrint ("%x", Ip->Addr[Index]);
 | |
|     }
 | |
| 
 | |
|     Index++;
 | |
|     if (Index > 15) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     if (((Ip->Addr[Index] & 0xf0) == 0) && (Ip->Addr[Index - 1] != 0)) {
 | |
|       AsciiPrint ("0");
 | |
|     }
 | |
| 
 | |
|     AsciiPrint ("%x", Ip->Addr[Index]);
 | |
|     if (Index < 15) {
 | |
|       AsciiPrint (":");
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function is to convert UINTN to ASCII string with the required formatting.
 | |
| 
 | |
|   @param[in]  Number         Numeric value to be converted.
 | |
|   @param[in]  Buffer         The pointer to the buffer for ASCII string.
 | |
|   @param[in]  Length         The length of the required format.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| PxeBcUintnToAscDecWithFormat (
 | |
|   IN UINTN  Number,
 | |
|   IN UINT8  *Buffer,
 | |
|   IN INTN   Length
 | |
|   )
 | |
| {
 | |
|   UINTN  Remainder;
 | |
| 
 | |
|   for ( ; Length > 0; Length--) {
 | |
|     Remainder          = Number % 10;
 | |
|     Number            /= 10;
 | |
|     Buffer[Length - 1] = (UINT8)('0' + Remainder);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function is to convert a UINTN to a ASCII string, and return the
 | |
|   actual length of the buffer.
 | |
| 
 | |
|   @param[in]  Number         Numeric value to be converted.
 | |
|   @param[in]  Buffer         The pointer to the buffer for ASCII string.
 | |
|   @param[in]  BufferSize     The maxsize of the buffer.
 | |
| 
 | |
|   @return     Length         The actual length of the ASCII string.
 | |
| 
 | |
| **/
 | |
| UINTN
 | |
| PxeBcUintnToAscDec (
 | |
|   IN UINTN  Number,
 | |
|   IN UINT8  *Buffer,
 | |
|   IN UINTN  BufferSize
 | |
|   )
 | |
| {
 | |
|   UINTN  Index;
 | |
|   UINTN  Length;
 | |
|   CHAR8  TempStr[64];
 | |
| 
 | |
|   Index          = 63;
 | |
|   TempStr[Index] = 0;
 | |
| 
 | |
|   do {
 | |
|     Index--;
 | |
|     TempStr[Index] = (CHAR8)('0' + (Number % 10));
 | |
|     Number         = (UINTN)(Number / 10);
 | |
|   } while (Number != 0);
 | |
| 
 | |
|   AsciiStrCpyS ((CHAR8 *)Buffer, BufferSize, &TempStr[Index]);
 | |
| 
 | |
|   Length = AsciiStrLen ((CHAR8 *)Buffer);
 | |
| 
 | |
|   return Length;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function is to convert unicode hex number to a UINT8.
 | |
| 
 | |
|   @param[out]  Digit                   The converted UINT8 for output.
 | |
|   @param[in]   Char                    The unicode hex number to be converted.
 | |
| 
 | |
|   @retval      EFI_SUCCESS             Successfully converted the unicode hex.
 | |
|   @retval      EFI_INVALID_PARAMETER   Failed to convert the unicode hex.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| PxeBcUniHexToUint8 (
 | |
|   OUT UINT8   *Digit,
 | |
|   IN  CHAR16  Char
 | |
|   )
 | |
| {
 | |
|   if ((Char >= L'0') && (Char <= L'9')) {
 | |
|     *Digit = (UINT8)(Char - L'0');
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   if ((Char >= L'A') && (Char <= L'F')) {
 | |
|     *Digit = (UINT8)(Char - L'A' + 0x0A);
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   if ((Char >= L'a') && (Char <= L'f')) {
 | |
|     *Digit = (UINT8)(Char - L'a' + 0x0A);
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   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 = MultU64x32 (
 | |
|                    ((((UINT32)(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;
 | |
|   }
 | |
| }
 |