mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-31 18:54:02 +00:00 
			
		
		
		
	 43d7e60734
			
		
	
	
		43d7e60734
		
	
	
	
	
		
			
			Cc: Ye Ting <ting.ye@intel.com> Cc: Fu Siyuan <siyuan.fu@intel.com> Cc: Wang Fan <fan.wang@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Wu Jiaxin <jiaxin.wu@intel.com> Reviewed-by: Fu Siyuan <siyuan.fu@intel.com>
		
			
				
	
	
		
			2193 lines
		
	
	
		
			64 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2193 lines
		
	
	
		
			64 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
| DnsDxe support functions implementation.
 | |
|   
 | |
| Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>
 | |
| 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.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "DnsImpl.h"
 | |
| 
 | |
| /**
 | |
|   Remove TokenEntry from TokenMap.
 | |
| 
 | |
|   @param[in] TokenMap          All DNSv4 Token entrys.
 | |
|   @param[in] TokenEntry        TokenEntry need to be removed.
 | |
| 
 | |
|   @retval EFI_SUCCESS          Remove TokenEntry from TokenMap sucessfully.
 | |
|   @retval EFI_NOT_FOUND        TokenEntry is not found in TokenMap.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| Dns4RemoveTokenEntry (
 | |
|   IN NET_MAP                    *TokenMap,
 | |
|   IN DNS4_TOKEN_ENTRY           *TokenEntry
 | |
|   )
 | |
| {
 | |
|   NET_MAP_ITEM  *Item;
 | |
| 
 | |
|   //
 | |
|   // Find the TokenEntry first.
 | |
|   //
 | |
|   Item = NetMapFindKey (TokenMap, (VOID *) TokenEntry);
 | |
| 
 | |
|   if (Item != NULL) {
 | |
|     //
 | |
|     // Remove the TokenEntry if it's found in the map.
 | |
|     //
 | |
|     NetMapRemoveItem (TokenMap, Item, NULL);
 | |
| 
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
|   
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Remove TokenEntry from TokenMap.
 | |
| 
 | |
|   @param[in] TokenMap           All DNSv6 Token entrys.
 | |
|   @param[in] TokenEntry         TokenEntry need to be removed.
 | |
| 
 | |
|   @retval EFI_SUCCESS           Remove TokenEntry from TokenMap sucessfully.
 | |
|   @retval EFI_NOT_FOUND         TokenEntry is not found in TokenMap.
 | |
|   
 | |
| **/
 | |
| EFI_STATUS
 | |
| Dns6RemoveTokenEntry (
 | |
|   IN NET_MAP                    *TokenMap,
 | |
|   IN DNS6_TOKEN_ENTRY           *TokenEntry
 | |
|   )
 | |
| {
 | |
|   NET_MAP_ITEM  *Item;
 | |
| 
 | |
|   //
 | |
|   // Find the TokenEntry first.
 | |
|   //
 | |
|   Item = NetMapFindKey (TokenMap, (VOID *) TokenEntry);
 | |
| 
 | |
|   if (Item != NULL) {
 | |
|     //
 | |
|     // Remove the TokenEntry if it's found in the map.
 | |
|     //
 | |
|     NetMapRemoveItem (TokenMap, Item, NULL);
 | |
| 
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
|   
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function cancle the token specified by Arg in the Map.
 | |
| 
 | |
|   @param[in]  Map             Pointer to the NET_MAP.
 | |
|   @param[in]  Item            Pointer to the NET_MAP_ITEM.
 | |
|   @param[in]  Arg             Pointer to the token to be cancelled. If NULL, all
 | |
|                               the tokens in this Map will be cancelled.
 | |
|                               This parameter is optional and may be NULL.
 | |
| 
 | |
|   @retval EFI_SUCCESS         The token is cancelled if Arg is NULL, or the token
 | |
|                               is not the same as that in the Item, if Arg is not
 | |
|                               NULL.
 | |
|   @retval EFI_ABORTED         Arg is not NULL, and the token specified by Arg is
 | |
|                               cancelled.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| Dns4CancelTokens (
 | |
|   IN NET_MAP       *Map,
 | |
|   IN NET_MAP_ITEM  *Item,
 | |
|   IN VOID          *Arg OPTIONAL
 | |
|   )
 | |
| {
 | |
|   DNS4_TOKEN_ENTRY           *TokenEntry;
 | |
|   NET_BUF                    *Packet;
 | |
|   UDP_IO                     *UdpIo;
 | |
| 
 | |
|   if ((Arg != NULL) && (Item->Key != Arg)) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   if (Item->Value != NULL) {
 | |
|     //
 | |
|     // If the TokenEntry is a transmit TokenEntry, the corresponding Packet is recorded in
 | |
|     // Item->Value.
 | |
|     //
 | |
|     Packet  = (NET_BUF *) (Item->Value);
 | |
|     UdpIo = (UDP_IO *) (*((UINTN *) &Packet->ProtoData[0]));
 | |
| 
 | |
|     UdpIoCancelSentDatagram (UdpIo, Packet);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Remove TokenEntry from Dns4TxTokens.
 | |
|   //
 | |
|   TokenEntry = (DNS4_TOKEN_ENTRY *) Item->Key;
 | |
|   if (Dns4RemoveTokenEntry (Map, TokenEntry) == EFI_SUCCESS) {
 | |
|     TokenEntry->Token->Status = EFI_ABORTED;
 | |
|     gBS->SignalEvent (TokenEntry->Token->Event);
 | |
|     DispatchDpc ();
 | |
|   }
 | |
| 
 | |
|   if (Arg != NULL) {
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function cancle the token specified by Arg in the Map.
 | |
| 
 | |
|   @param[in]  Map             Pointer to the NET_MAP.
 | |
|   @param[in]  Item            Pointer to the NET_MAP_ITEM.
 | |
|   @param[in]  Arg             Pointer to the token to be cancelled. If NULL, all
 | |
|                               the tokens in this Map will be cancelled.
 | |
|                               This parameter is optional and may be NULL.
 | |
| 
 | |
|   @retval EFI_SUCCESS         The token is cancelled if Arg is NULL, or the token
 | |
|                               is not the same as that in the Item, if Arg is not
 | |
|                               NULL.
 | |
|   @retval EFI_ABORTED         Arg is not NULL, and the token specified by Arg is
 | |
|                               cancelled.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| Dns6CancelTokens (
 | |
|   IN NET_MAP       *Map,
 | |
|   IN NET_MAP_ITEM  *Item,
 | |
|   IN VOID          *Arg OPTIONAL
 | |
|   )
 | |
| {
 | |
|   DNS6_TOKEN_ENTRY           *TokenEntry;
 | |
|   NET_BUF                    *Packet;
 | |
|   UDP_IO                     *UdpIo;
 | |
| 
 | |
|   if ((Arg != NULL) && (Item->Key != Arg)) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   if (Item->Value != NULL) {
 | |
|     //
 | |
|     // If the TokenEntry is a transmit TokenEntry, the corresponding Packet is recorded in
 | |
|     // Item->Value.
 | |
|     //
 | |
|     Packet  = (NET_BUF *) (Item->Value);
 | |
|     UdpIo = (UDP_IO *) (*((UINTN *) &Packet->ProtoData[0]));
 | |
| 
 | |
|     UdpIoCancelSentDatagram (UdpIo, Packet);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Remove TokenEntry from Dns6TxTokens.
 | |
|   //
 | |
|   TokenEntry = (DNS6_TOKEN_ENTRY *) Item->Key;
 | |
|   if (Dns6RemoveTokenEntry (Map, TokenEntry) == EFI_SUCCESS) {
 | |
|     TokenEntry->Token->Status = EFI_ABORTED;
 | |
|     gBS->SignalEvent (TokenEntry->Token->Event);
 | |
|     DispatchDpc ();
 | |
|   }
 | |
| 
 | |
|   if (Arg != NULL) {
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get the TokenEntry from the TokensMap.
 | |
| 
 | |
|   @param[in]  TokensMap           All DNSv4 Token entrys
 | |
|   @param[in]  Token               Pointer to the token to be get.
 | |
|   @param[out] TokenEntry          Pointer to TokenEntry corresponding Token.
 | |
| 
 | |
|   @retval EFI_SUCCESS             Get the TokenEntry from the TokensMap sucessfully.
 | |
|   @retval EFI_NOT_FOUND           TokenEntry is not found in TokenMap.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| GetDns4TokenEntry (
 | |
|   IN     NET_MAP                   *TokensMap,
 | |
|   IN     EFI_DNS4_COMPLETION_TOKEN *Token, 
 | |
|      OUT DNS4_TOKEN_ENTRY          **TokenEntry
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY              *Entry;
 | |
|   
 | |
|   NET_MAP_ITEM            *Item;
 | |
|   
 | |
|   NET_LIST_FOR_EACH (Entry, &TokensMap->Used) {
 | |
|     Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
 | |
|     *TokenEntry = (DNS4_TOKEN_ENTRY *) (Item->Key);  
 | |
|     if ((*TokenEntry)->Token == Token) {
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
|   
 | |
|   *TokenEntry = NULL;
 | |
|   
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get the TokenEntry from the TokensMap.
 | |
| 
 | |
|   @param[in]  TokensMap           All DNSv6 Token entrys
 | |
|   @param[in]  Token               Pointer to the token to be get.
 | |
|   @param[out] TokenEntry          Pointer to TokenEntry corresponding Token.
 | |
| 
 | |
|   @retval EFI_SUCCESS             Get the TokenEntry from the TokensMap sucessfully.
 | |
|   @retval EFI_NOT_FOUND           TokenEntry is not found in TokenMap.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| GetDns6TokenEntry (
 | |
|   IN     NET_MAP                   *TokensMap,
 | |
|   IN     EFI_DNS6_COMPLETION_TOKEN *Token, 
 | |
|      OUT DNS6_TOKEN_ENTRY          **TokenEntry
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY              *Entry;
 | |
|   
 | |
|   NET_MAP_ITEM            *Item;
 | |
|   
 | |
|   NET_LIST_FOR_EACH (Entry, &TokensMap->Used) {
 | |
|     Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
 | |
|     *TokenEntry = (DNS6_TOKEN_ENTRY *) (Item->Key);  
 | |
|     if ((*TokenEntry)->Token == Token) {
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
|   
 | |
|   *TokenEntry =NULL;
 | |
|   
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Cancel DNS4 tokens from the DNS4 instance.
 | |
| 
 | |
|   @param[in]  Instance           Pointer to the DNS instance context data.
 | |
|   @param[in]  Token              Pointer to the token to be canceled. If NULL, all
 | |
|                                  tokens in this instance will be cancelled.
 | |
|                                  This parameter is optional and may be NULL.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The Token is cancelled.
 | |
|   @retval EFI_NOT_FOUND          The Token is not found.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| Dns4InstanceCancelToken (
 | |
|   IN DNS_INSTANCE               *Instance,
 | |
|   IN EFI_DNS4_COMPLETION_TOKEN  *Token
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS        Status;
 | |
|   DNS4_TOKEN_ENTRY  *TokenEntry;
 | |
| 
 | |
|   TokenEntry = NULL;
 | |
| 
 | |
|   if(Token != NULL  ) {
 | |
|     Status = GetDns4TokenEntry (&Instance->Dns4TxTokens, Token, &TokenEntry);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|   } else {
 | |
|     TokenEntry = NULL;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Cancel this TokenEntry from the Dns4TxTokens map.
 | |
|   //
 | |
|   Status = NetMapIterate (&Instance->Dns4TxTokens, Dns4CancelTokens, TokenEntry);
 | |
| 
 | |
|   if ((TokenEntry != NULL) && (Status == EFI_ABORTED)) {
 | |
|     //
 | |
|     // If Token isn't NULL and Status is EFI_ABORTED, the token is cancelled from
 | |
|     // the Dns4TxTokens and returns success.
 | |
|     //
 | |
|     if (NetMapIsEmpty (&Instance->Dns4TxTokens)) {
 | |
|        Instance->UdpIo->Protocol.Udp4->Cancel (Instance->UdpIo->Protocol.Udp4, &Instance->UdpIo->RecvRequest->Token.Udp4);
 | |
|     }
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   ASSERT ((TokenEntry != NULL) || (0 == NetMapGetCount (&Instance->Dns4TxTokens)));
 | |
|   
 | |
|   if (NetMapIsEmpty (&Instance->Dns4TxTokens)) {
 | |
|     Instance->UdpIo->Protocol.Udp4->Cancel (Instance->UdpIo->Protocol.Udp4, &Instance->UdpIo->RecvRequest->Token.Udp4);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Cancel DNS6 tokens from the DNS6 instance.
 | |
| 
 | |
|   @param[in]  Instance           Pointer to the DNS instance context data.
 | |
|   @param[in]  Token              Pointer to the token to be canceled. If NULL, all
 | |
|                                  tokens in this instance will be cancelled.
 | |
|                                  This parameter is optional and may be NULL.
 | |
| 
 | |
|   @retval EFI_SUCCESS            The Token is cancelled.
 | |
|   @retval EFI_NOT_FOUND          The Token is not found.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| Dns6InstanceCancelToken (
 | |
|   IN DNS_INSTANCE               *Instance,
 | |
|   IN EFI_DNS6_COMPLETION_TOKEN  *Token
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS        Status;
 | |
|   DNS6_TOKEN_ENTRY  *TokenEntry;
 | |
| 
 | |
|   TokenEntry = NULL;
 | |
| 
 | |
|   if(Token != NULL  ) {
 | |
|     Status = GetDns6TokenEntry (&Instance->Dns6TxTokens, Token, &TokenEntry);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|   } else {
 | |
|     TokenEntry = NULL;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Cancel this TokenEntry from the Dns6TxTokens map.
 | |
|   //
 | |
|   Status = NetMapIterate (&Instance->Dns6TxTokens, Dns6CancelTokens, TokenEntry);
 | |
| 
 | |
|   if ((TokenEntry != NULL) && (Status == EFI_ABORTED)) {
 | |
|     //
 | |
|     // If Token isn't NULL and Status is EFI_ABORTED, the token is cancelled from
 | |
|     // the Dns6TxTokens and returns success.
 | |
|     //
 | |
|     if (NetMapIsEmpty (&Instance->Dns6TxTokens)) {
 | |
|        Instance->UdpIo->Protocol.Udp6->Cancel (Instance->UdpIo->Protocol.Udp6, &Instance->UdpIo->RecvRequest->Token.Udp6);
 | |
|     }
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   ASSERT ((TokenEntry != NULL) || (0 == NetMapGetCount (&Instance->Dns6TxTokens)));
 | |
|   
 | |
|   if (NetMapIsEmpty (&Instance->Dns6TxTokens)) {
 | |
|     Instance->UdpIo->Protocol.Udp6->Cancel (Instance->UdpIo->Protocol.Udp6, &Instance->UdpIo->RecvRequest->Token.Udp6);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Free the resource related to the configure parameters.
 | |
| 
 | |
|   @param  Config                 The DNS configure data
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| Dns4CleanConfigure (
 | |
|   IN OUT EFI_DNS4_CONFIG_DATA  *Config
 | |
|   )
 | |
| {
 | |
|   if (Config->DnsServerList != NULL) {
 | |
|     FreePool (Config->DnsServerList);
 | |
|   }
 | |
| 
 | |
|   ZeroMem (Config, sizeof (EFI_DNS4_CONFIG_DATA));
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Free the resource related to the configure parameters.
 | |
| 
 | |
|   @param  Config                 The DNS configure data
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| Dns6CleanConfigure (
 | |
|   IN OUT EFI_DNS6_CONFIG_DATA  *Config
 | |
|   )
 | |
| {
 | |
|   if (Config->DnsServerList != NULL) {
 | |
|     FreePool (Config->DnsServerList);
 | |
|   }
 | |
| 
 | |
|   ZeroMem (Config, sizeof (EFI_DNS6_CONFIG_DATA));
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Allocate memory for configure parameter such as timeout value for Dst,
 | |
|   then copy the configure parameter from Src to Dst.
 | |
| 
 | |
|   @param[out]  Dst               The destination DHCP configure data.
 | |
|   @param[in]   Src               The source DHCP configure data.
 | |
| 
 | |
|   @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory.
 | |
|   @retval EFI_SUCCESS            The configure is copied.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| Dns4CopyConfigure (
 | |
|   OUT EFI_DNS4_CONFIG_DATA  *Dst,
 | |
|   IN  EFI_DNS4_CONFIG_DATA  *Src
 | |
|   )
 | |
| {
 | |
|   UINTN                     Len;
 | |
|   UINT32                    Index;
 | |
| 
 | |
|   CopyMem (Dst, Src, sizeof (*Dst));
 | |
|   Dst->DnsServerList = NULL;
 | |
| 
 | |
|   //
 | |
|   // Allocate a memory then copy DnsServerList to it
 | |
|   //
 | |
|   if (Src->DnsServerList != NULL) {
 | |
|     Len                = Src->DnsServerListCount * sizeof (EFI_IPv4_ADDRESS);
 | |
|     Dst->DnsServerList = AllocatePool (Len);
 | |
|     if (Dst->DnsServerList == NULL) {
 | |
|       Dns4CleanConfigure (Dst);
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
| 
 | |
|     for (Index = 0; Index < Src->DnsServerListCount; Index++) {
 | |
|       CopyMem (&Dst->DnsServerList[Index], &Src->DnsServerList[Index], sizeof (EFI_IPv4_ADDRESS));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Allocate memory for configure parameter such as timeout value for Dst,
 | |
|   then copy the configure parameter from Src to Dst.
 | |
| 
 | |
|   @param[out]  Dst               The destination DHCP configure data.
 | |
|   @param[in]   Src               The source DHCP configure data.
 | |
| 
 | |
|   @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory.
 | |
|   @retval EFI_SUCCESS            The configure is copied.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| Dns6CopyConfigure (
 | |
|   OUT EFI_DNS6_CONFIG_DATA  *Dst,
 | |
|   IN  EFI_DNS6_CONFIG_DATA  *Src
 | |
|   )
 | |
| {
 | |
|   UINTN                     Len;
 | |
|   UINT32                    Index;
 | |
| 
 | |
|   CopyMem (Dst, Src, sizeof (*Dst));
 | |
|   Dst->DnsServerList = NULL;
 | |
| 
 | |
|   //
 | |
|   // Allocate a memory then copy DnsServerList to it
 | |
|   //
 | |
|   if (Src->DnsServerList != NULL) {
 | |
|     Len                = Src->DnsServerCount * sizeof (EFI_IPv6_ADDRESS);
 | |
|     Dst->DnsServerList = AllocatePool (Len);
 | |
|     if (Dst->DnsServerList == NULL) {
 | |
|       Dns6CleanConfigure (Dst);
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
| 
 | |
|     for (Index = 0; Index < Src->DnsServerCount; Index++) {
 | |
|       CopyMem (&Dst->DnsServerList[Index], &Src->DnsServerList[Index], sizeof (EFI_IPv6_ADDRESS));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Callback of Dns packet. Does nothing.
 | |
| 
 | |
|   @param Arg           The context.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| DnsDummyExtFree (
 | |
|   IN VOID                   *Arg
 | |
|   )
 | |
| {
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Poll the UDP to get the IP4 default address, which may be retrieved
 | |
|   by DHCP. 
 | |
|   
 | |
|   The default time out value is 5 seconds. If IP has retrieved the default address, 
 | |
|   the UDP is reconfigured.
 | |
| 
 | |
|   @param  Instance               The DNS instance
 | |
|   @param  UdpIo                  The UDP_IO to poll
 | |
|   @param  UdpCfgData             The UDP configure data to reconfigure the UDP_IO
 | |
| 
 | |
|   @retval TRUE                   The default address is retrieved and UDP is reconfigured.
 | |
|   @retval FALSE                  Some error occured.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| Dns4GetMapping (
 | |
|   IN DNS_INSTANCE           *Instance,
 | |
|   IN UDP_IO                 *UdpIo,
 | |
|   IN EFI_UDP4_CONFIG_DATA   *UdpCfgData
 | |
|   )
 | |
| {
 | |
|   DNS_SERVICE               *Service;
 | |
|   EFI_IP4_MODE_DATA         Ip4Mode;
 | |
|   EFI_UDP4_PROTOCOL         *Udp;
 | |
|   EFI_STATUS                Status;
 | |
| 
 | |
|   ASSERT (Instance->Dns4CfgData.UseDefaultSetting);
 | |
| 
 | |
|   Service = Instance->Service;
 | |
|   Udp     = UdpIo->Protocol.Udp4;
 | |
| 
 | |
|   Status = gBS->SetTimer (
 | |
|                   Service->TimerToGetMap,
 | |
|                   TimerRelative,
 | |
|                   DNS_TIME_TO_GETMAP * TICKS_PER_SECOND
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   while (EFI_ERROR (gBS->CheckEvent (Service->TimerToGetMap))) {
 | |
|     Udp->Poll (Udp);
 | |
| 
 | |
|     if (!EFI_ERROR (Udp->GetModeData (Udp, NULL, &Ip4Mode, NULL, NULL)) &&
 | |
|         Ip4Mode.IsConfigured) {
 | |
| 
 | |
|       Udp->Configure (Udp, NULL);
 | |
|       return (BOOLEAN) (Udp->Configure (Udp, UdpCfgData) == EFI_SUCCESS);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Configure the opened Udp6 instance until the corresponding Ip6 instance
 | |
|   has been configured.
 | |
| 
 | |
|   @param  Instance               The DNS instance
 | |
|   @param  UdpIo                  The UDP_IO to poll
 | |
|   @param  UdpCfgData             The UDP configure data to reconfigure the UDP_IO
 | |
| 
 | |
|   @retval TRUE                   Configure the Udp6 instance successfully.
 | |
|   @retval FALSE                  Some error occured.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| Dns6GetMapping (
 | |
|   IN DNS_INSTANCE           *Instance,
 | |
|   IN UDP_IO                 *UdpIo,
 | |
|   IN EFI_UDP6_CONFIG_DATA   *UdpCfgData
 | |
|   )
 | |
| {
 | |
|   DNS_SERVICE               *Service;
 | |
|   EFI_IP6_MODE_DATA         Ip6Mode;
 | |
|   EFI_UDP6_PROTOCOL         *Udp;
 | |
|   EFI_STATUS                Status;
 | |
| 
 | |
|   Service = Instance->Service;
 | |
|   Udp     = UdpIo->Protocol.Udp6;
 | |
| 
 | |
|   Status = gBS->SetTimer (
 | |
|                   Service->TimerToGetMap,
 | |
|                   TimerRelative,
 | |
|                   DNS_TIME_TO_GETMAP * TICKS_PER_SECOND
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return FALSE;
 | |
|   }
 | |
| 
 | |
|   while (EFI_ERROR (gBS->CheckEvent (Service->TimerToGetMap))) {
 | |
|     Udp->Poll (Udp);
 | |
| 
 | |
|     if (!EFI_ERROR (Udp->GetModeData (Udp, NULL, &Ip6Mode, NULL, NULL))) {
 | |
|       if (Ip6Mode.AddressList != NULL) {
 | |
|         FreePool (Ip6Mode.AddressList);
 | |
|       }
 | |
| 
 | |
|       if (Ip6Mode.GroupTable != NULL) {
 | |
|         FreePool (Ip6Mode.GroupTable);
 | |
|       }
 | |
| 
 | |
|       if (Ip6Mode.RouteTable != NULL) {
 | |
|         FreePool (Ip6Mode.RouteTable);
 | |
|       }
 | |
| 
 | |
|       if (Ip6Mode.NeighborCache != NULL) {
 | |
|         FreePool (Ip6Mode.NeighborCache);
 | |
|       }
 | |
| 
 | |
|       if (Ip6Mode.PrefixTable != NULL) {
 | |
|         FreePool (Ip6Mode.PrefixTable);
 | |
|       }
 | |
| 
 | |
|       if (Ip6Mode.IcmpTypeList != NULL) {
 | |
|         FreePool (Ip6Mode.IcmpTypeList);
 | |
|       }
 | |
| 
 | |
|       if (!Ip6Mode.IsStarted || Ip6Mode.IsConfigured) {
 | |
|         Udp->Configure (Udp, NULL);
 | |
|         if (Udp->Configure (Udp, UdpCfgData) == EFI_SUCCESS) {
 | |
|           return TRUE;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Configure the UDP.
 | |
|   
 | |
|   @param  Instance               The DNS session
 | |
|   @param  UdpIo                  The UDP_IO instance
 | |
|   
 | |
|   @retval EFI_SUCCESS            The UDP is successfully configured for the
 | |
|                                  session.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| Dns4ConfigUdp (
 | |
|   IN DNS_INSTANCE           *Instance,
 | |
|   IN UDP_IO                 *UdpIo
 | |
|   )
 | |
| {
 | |
|   EFI_DNS4_CONFIG_DATA      *Config;
 | |
|   EFI_UDP4_CONFIG_DATA      UdpConfig;
 | |
|   EFI_STATUS                Status;
 | |
| 
 | |
|   Config = &Instance->Dns4CfgData;
 | |
| 
 | |
|   UdpConfig.AcceptBroadcast    = FALSE;
 | |
|   UdpConfig.AcceptPromiscuous  = FALSE;
 | |
|   UdpConfig.AcceptAnyPort      = FALSE;
 | |
|   UdpConfig.AllowDuplicatePort = FALSE;
 | |
|   UdpConfig.TypeOfService      = 0;
 | |
|   UdpConfig.TimeToLive         = 128;
 | |
|   UdpConfig.DoNotFragment      = FALSE;
 | |
|   UdpConfig.ReceiveTimeout     = 0;
 | |
|   UdpConfig.TransmitTimeout    = 0;
 | |
|   UdpConfig.UseDefaultAddress  = Config->UseDefaultSetting;
 | |
|   UdpConfig.SubnetMask         = Config->SubnetMask;
 | |
|   UdpConfig.StationPort        = Config->LocalPort;
 | |
|   UdpConfig.RemotePort         = DNS_SERVER_PORT;
 | |
| 
 | |
|   CopyMem (&UdpConfig.StationAddress, &Config->StationIp, sizeof (EFI_IPv4_ADDRESS));
 | |
|   CopyMem (&UdpConfig.RemoteAddress, &Instance->SessionDnsServer.v4, sizeof (EFI_IPv4_ADDRESS));
 | |
| 
 | |
|   Status = UdpIo->Protocol.Udp4->Configure (UdpIo->Protocol.Udp4, &UdpConfig);
 | |
| 
 | |
|   if ((Status == EFI_NO_MAPPING) && Dns4GetMapping (Instance, UdpIo, &UdpConfig)) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
|   
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Configure the UDP.
 | |
|   
 | |
|   @param  Instance               The DNS session
 | |
|   @param  UdpIo                  The UDP_IO instance
 | |
| 
 | |
|   @retval EFI_SUCCESS            The UDP is successfully configured for the
 | |
|                                  session.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| Dns6ConfigUdp (
 | |
|   IN DNS_INSTANCE           *Instance,
 | |
|   IN UDP_IO                 *UdpIo
 | |
|   )
 | |
| {
 | |
|   EFI_DNS6_CONFIG_DATA      *Config;
 | |
|   EFI_UDP6_CONFIG_DATA      UdpConfig;
 | |
|   EFI_STATUS                Status;
 | |
| 
 | |
|   Config = &Instance->Dns6CfgData;
 | |
| 
 | |
|   UdpConfig.AcceptPromiscuous  = FALSE;
 | |
|   UdpConfig.AcceptAnyPort      = FALSE;
 | |
|   UdpConfig.AllowDuplicatePort = FALSE;
 | |
|   UdpConfig.TrafficClass       = 0;
 | |
|   UdpConfig.HopLimit           = 128;
 | |
|   UdpConfig.ReceiveTimeout     = 0;
 | |
|   UdpConfig.TransmitTimeout    = 0;
 | |
|   UdpConfig.StationPort        = Config->LocalPort;
 | |
|   UdpConfig.RemotePort         = DNS_SERVER_PORT;
 | |
|   CopyMem (&UdpConfig.StationAddress, &Config->StationIp, sizeof (EFI_IPv6_ADDRESS));
 | |
|   CopyMem (&UdpConfig.RemoteAddress, &Instance->SessionDnsServer.v6, sizeof (EFI_IPv6_ADDRESS));
 | |
| 
 | |
|   Status = UdpIo->Protocol.Udp6->Configure (UdpIo->Protocol.Udp6, &UdpConfig);
 | |
| 
 | |
|   if ((Status == EFI_NO_MAPPING) && Dns6GetMapping (Instance, UdpIo, &UdpConfig)) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
|   
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Update Dns4 cache to shared list of caches of all DNSv4 instances.
 | |
|   
 | |
|   @param  Dns4CacheList      All Dns4 cache list.
 | |
|   @param  DeleteFlag         If FALSE, this function is to add one entry to the DNS Cache. 
 | |
|                              If TRUE, this function will delete matching DNS Cache entry. 
 | |
|   @param  Override           If TRUE, the matching DNS cache entry will be overwritten with the supplied parameter. 
 | |
|                              If FALSE, EFI_ACCESS_DENIED will be returned if the entry to be added is already exists.
 | |
|   @param  DnsCacheEntry      Entry Pointer to DNS Cache entry.
 | |
| 
 | |
|   @retval EFI_SUCCESS        Update Dns4 cache successfully.
 | |
|   @retval Others             Failed to update Dns4 cache.   
 | |
|   
 | |
| **/ 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| UpdateDns4Cache (
 | |
|   IN LIST_ENTRY             *Dns4CacheList,
 | |
|   IN BOOLEAN                DeleteFlag,
 | |
|   IN BOOLEAN                Override,
 | |
|   IN EFI_DNS4_CACHE_ENTRY   DnsCacheEntry
 | |
|   )
 | |
| {
 | |
|   DNS4_CACHE    *NewDnsCache;  
 | |
|   DNS4_CACHE    *Item;
 | |
|   LIST_ENTRY    *Entry;
 | |
|   LIST_ENTRY    *Next;
 | |
| 
 | |
|   NewDnsCache = NULL;
 | |
|   Item        = NULL;
 | |
|   
 | |
|   //
 | |
|   // Search the database for the matching EFI_DNS_CACHE_ENTRY
 | |
|   //
 | |
|   NET_LIST_FOR_EACH_SAFE (Entry, Next, Dns4CacheList) {
 | |
|     Item = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink);
 | |
|     if (StrCmp (DnsCacheEntry.HostName, Item->DnsCache.HostName) == 0 && \
 | |
|         CompareMem (DnsCacheEntry.IpAddress, Item->DnsCache.IpAddress, sizeof (EFI_IPv4_ADDRESS)) == 0) {
 | |
|       //
 | |
|       // This is the Dns cache entry
 | |
|       //
 | |
|       if (DeleteFlag) {
 | |
|         //
 | |
|         // Delete matching DNS Cache entry
 | |
|         //
 | |
|         RemoveEntryList (&Item->AllCacheLink);
 | |
| 
 | |
|         FreePool (Item->DnsCache.HostName);
 | |
|         FreePool (Item->DnsCache.IpAddress);
 | |
|         FreePool (Item);
 | |
|         
 | |
|         return EFI_SUCCESS;
 | |
|       } else if (Override) {
 | |
|         //
 | |
|         // Update this one
 | |
|         //
 | |
|         Item->DnsCache.Timeout = DnsCacheEntry.Timeout;
 | |
|         
 | |
|         return EFI_SUCCESS;
 | |
|       }else {
 | |
|         return EFI_ACCESS_DENIED;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Add new one
 | |
|   //
 | |
|   NewDnsCache = AllocatePool (sizeof (DNS4_CACHE));
 | |
|   if (NewDnsCache == NULL) { 
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   
 | |
|   InitializeListHead (&NewDnsCache->AllCacheLink);
 | |
|    
 | |
|   NewDnsCache->DnsCache.HostName = AllocatePool (StrSize (DnsCacheEntry.HostName));
 | |
|   if (NewDnsCache->DnsCache.HostName == NULL) { 
 | |
|     FreePool (NewDnsCache);
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   
 | |
|   CopyMem (NewDnsCache->DnsCache.HostName, DnsCacheEntry.HostName, StrSize (DnsCacheEntry.HostName));
 | |
| 
 | |
|   NewDnsCache->DnsCache.IpAddress = AllocatePool (sizeof (EFI_IPv4_ADDRESS));
 | |
|   if (NewDnsCache->DnsCache.IpAddress == NULL) {
 | |
|     FreePool (NewDnsCache->DnsCache.HostName);
 | |
|     FreePool (NewDnsCache);
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   CopyMem (NewDnsCache->DnsCache.IpAddress, DnsCacheEntry.IpAddress, sizeof (EFI_IPv4_ADDRESS));
 | |
| 
 | |
|   NewDnsCache->DnsCache.Timeout = DnsCacheEntry.Timeout;
 | |
|   
 | |
|   InsertTailList (Dns4CacheList, &NewDnsCache->AllCacheLink);
 | |
|   
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Update Dns6 cache to shared list of caches of all DNSv6 instances. 
 | |
| 
 | |
|   @param  Dns6CacheList      All Dns6 cache list.
 | |
|   @param  DeleteFlag         If FALSE, this function is to add one entry to the DNS Cache. 
 | |
|                              If TRUE, this function will delete matching DNS Cache entry. 
 | |
|   @param  Override           If TRUE, the matching DNS cache entry will be overwritten with the supplied parameter. 
 | |
|                              If FALSE, EFI_ACCESS_DENIED will be returned if the entry to be added is already exists.
 | |
|   @param  DnsCacheEntry      Entry Pointer to DNS Cache entry.
 | |
|   
 | |
|   @retval EFI_SUCCESS        Update Dns6 cache successfully.
 | |
|   @retval Others             Failed to update Dns6 cache.
 | |
| **/ 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| UpdateDns6Cache (
 | |
|   IN LIST_ENTRY             *Dns6CacheList,
 | |
|   IN BOOLEAN                DeleteFlag,
 | |
|   IN BOOLEAN                Override,
 | |
|   IN EFI_DNS6_CACHE_ENTRY   DnsCacheEntry
 | |
|   )
 | |
| {
 | |
|   DNS6_CACHE    *NewDnsCache;  
 | |
|   DNS6_CACHE    *Item;
 | |
|   LIST_ENTRY    *Entry;
 | |
|   LIST_ENTRY    *Next;
 | |
| 
 | |
|   NewDnsCache = NULL;
 | |
|   Item        = NULL;
 | |
|   
 | |
|   //
 | |
|   // Search the database for the matching EFI_DNS_CACHE_ENTRY
 | |
|   //
 | |
|   NET_LIST_FOR_EACH_SAFE (Entry, Next, Dns6CacheList) {
 | |
|     Item = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink);
 | |
|     if (StrCmp (DnsCacheEntry.HostName, Item->DnsCache.HostName) == 0 && \
 | |
|         CompareMem (DnsCacheEntry.IpAddress, Item->DnsCache.IpAddress, sizeof (EFI_IPv6_ADDRESS)) == 0) {
 | |
|       //
 | |
|       // This is the Dns cache entry
 | |
|       //
 | |
|       if (DeleteFlag) {
 | |
|         //
 | |
|         // Delete matching DNS Cache entry
 | |
|         //
 | |
|         RemoveEntryList (&Item->AllCacheLink);
 | |
|         
 | |
|         FreePool (Item->DnsCache.HostName);
 | |
|         FreePool (Item->DnsCache.IpAddress);
 | |
|         FreePool (Item);
 | |
|         
 | |
|         return EFI_SUCCESS;
 | |
|       } else if (Override) {
 | |
|         //
 | |
|         // Update this one
 | |
|         //
 | |
|         Item->DnsCache.Timeout = DnsCacheEntry.Timeout;
 | |
|         
 | |
|         return EFI_SUCCESS;
 | |
|       }else {
 | |
|         return EFI_ACCESS_DENIED;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Add new one
 | |
|   //
 | |
|   NewDnsCache = AllocatePool (sizeof (DNS6_CACHE));
 | |
|   if (NewDnsCache == NULL) { 
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   
 | |
|   InitializeListHead (&NewDnsCache->AllCacheLink);
 | |
|    
 | |
|   NewDnsCache->DnsCache.HostName = AllocatePool (StrSize (DnsCacheEntry.HostName));
 | |
|   if (NewDnsCache->DnsCache.HostName == NULL) { 
 | |
|     FreePool (NewDnsCache);
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   
 | |
|   CopyMem (NewDnsCache->DnsCache.HostName, DnsCacheEntry.HostName, StrSize (DnsCacheEntry.HostName));
 | |
| 
 | |
|   NewDnsCache->DnsCache.IpAddress = AllocatePool (sizeof (EFI_IPv6_ADDRESS));
 | |
|   if (NewDnsCache->DnsCache.IpAddress == NULL) {
 | |
|     FreePool (NewDnsCache->DnsCache.HostName);
 | |
|     FreePool (NewDnsCache);
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   
 | |
|   CopyMem (NewDnsCache->DnsCache.IpAddress, DnsCacheEntry.IpAddress, sizeof (EFI_IPv6_ADDRESS));
 | |
| 
 | |
|   NewDnsCache->DnsCache.Timeout = DnsCacheEntry.Timeout;
 | |
|   
 | |
|   InsertTailList (Dns6CacheList, &NewDnsCache->AllCacheLink);
 | |
|   
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Add Dns4 ServerIp to common list of addresses of all configured DNSv4 server. 
 | |
| 
 | |
|   @param  Dns4ServerList    Common list of addresses of all configured DNSv4 server.  
 | |
|   @param  ServerIp          DNS server Ip.  
 | |
| 
 | |
|   @retval EFI_SUCCESS       Add Dns4 ServerIp to common list successfully.
 | |
|   @retval Others            Failed to add Dns4 ServerIp to common list.
 | |
|   
 | |
| **/ 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AddDns4ServerIp (
 | |
|   IN LIST_ENTRY                *Dns4ServerList,
 | |
|   IN EFI_IPv4_ADDRESS           ServerIp
 | |
|   )
 | |
| {
 | |
|   DNS4_SERVER_IP    *NewServerIp;  
 | |
|   DNS4_SERVER_IP    *Item;
 | |
|   LIST_ENTRY        *Entry;
 | |
|   LIST_ENTRY        *Next;
 | |
| 
 | |
|   NewServerIp = NULL;
 | |
|   Item        = NULL;
 | |
|   
 | |
|   //
 | |
|   // Search the database for the matching ServerIp
 | |
|   //
 | |
|   NET_LIST_FOR_EACH_SAFE (Entry, Next, Dns4ServerList) {
 | |
|     Item = NET_LIST_USER_STRUCT (Entry, DNS4_SERVER_IP, AllServerLink);
 | |
|     if (CompareMem (&Item->Dns4ServerIp, &ServerIp, sizeof (EFI_IPv4_ADDRESS)) == 0) {
 | |
|       //
 | |
|       // Already done.
 | |
|       // 
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Add new one
 | |
|   //
 | |
|   NewServerIp = AllocatePool (sizeof (DNS4_SERVER_IP));
 | |
|   if (NewServerIp == NULL) { 
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   
 | |
|   InitializeListHead (&NewServerIp->AllServerLink);
 | |
|    
 | |
|   CopyMem (&NewServerIp->Dns4ServerIp, &ServerIp, sizeof (EFI_IPv4_ADDRESS));
 | |
|   
 | |
|   InsertTailList (Dns4ServerList, &NewServerIp->AllServerLink);
 | |
|   
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Add Dns6 ServerIp to common list of addresses of all configured DNSv6 server. 
 | |
| 
 | |
|   @param  Dns6ServerList    Common list of addresses of all configured DNSv6 server.  
 | |
|   @param  ServerIp          DNS server Ip.  
 | |
| 
 | |
|   @retval EFI_SUCCESS       Add Dns6 ServerIp to common list successfully.
 | |
|   @retval Others            Failed to add Dns6 ServerIp to common list.
 | |
|   
 | |
| **/ 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| AddDns6ServerIp (
 | |
|   IN LIST_ENTRY                *Dns6ServerList,
 | |
|   IN EFI_IPv6_ADDRESS           ServerIp
 | |
|   )
 | |
| {
 | |
|   DNS6_SERVER_IP    *NewServerIp;  
 | |
|   DNS6_SERVER_IP    *Item;
 | |
|   LIST_ENTRY        *Entry;
 | |
|   LIST_ENTRY        *Next;
 | |
| 
 | |
|   NewServerIp = NULL;
 | |
|   Item        = NULL;
 | |
|   
 | |
|   //
 | |
|   // Search the database for the matching ServerIp
 | |
|   //
 | |
|   NET_LIST_FOR_EACH_SAFE (Entry, Next, Dns6ServerList) {
 | |
|     Item = NET_LIST_USER_STRUCT (Entry, DNS6_SERVER_IP, AllServerLink);
 | |
|     if (CompareMem (&Item->Dns6ServerIp, &ServerIp, sizeof (EFI_IPv6_ADDRESS)) == 0) {
 | |
|       //
 | |
|       // Already done.
 | |
|       // 
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Add new one
 | |
|   //
 | |
|   NewServerIp = AllocatePool (sizeof (DNS6_SERVER_IP));
 | |
|   if (NewServerIp == NULL) { 
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   
 | |
|   InitializeListHead (&NewServerIp->AllServerLink);
 | |
|    
 | |
|   CopyMem (&NewServerIp->Dns6ServerIp, &ServerIp, sizeof (EFI_IPv6_ADDRESS));
 | |
|   
 | |
|   InsertTailList (Dns6ServerList, &NewServerIp->AllServerLink);
 | |
|   
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Find out whether the response is valid or invalid.
 | |
| 
 | |
|   @param  TokensMap       All DNS transmittal Tokens entry.  
 | |
|   @param  Identification  Identification for queried packet.  
 | |
|   @param  Type            Type for queried packet.
 | |
|   @param  Class           Class for queried packet.
 | |
|   @param  Item            Return corresponding Token entry.
 | |
| 
 | |
|   @retval TRUE            The response is valid.
 | |
|   @retval FALSE           The response is invalid.
 | |
|   
 | |
| **/ 
 | |
| BOOLEAN
 | |
| IsValidDnsResponse (
 | |
|   IN     NET_MAP      *TokensMap,
 | |
|   IN     UINT16       Identification,
 | |
|   IN     UINT16       Type,
 | |
|   IN     UINT16       Class,
 | |
|      OUT NET_MAP_ITEM **Item
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY              *Entry;
 | |
| 
 | |
|   NET_BUF                 *Packet;
 | |
|   UINT8                   *TxString;
 | |
|   DNS_HEADER              *DnsHeader;
 | |
|   CHAR8                   *QueryName;
 | |
|   DNS_QUERY_SECTION       *QuerySection;
 | |
| 
 | |
|   NET_LIST_FOR_EACH (Entry, &TokensMap->Used) {
 | |
|     *Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
 | |
|     Packet = (NET_BUF *) ((*Item)->Value);
 | |
|     if (Packet == NULL){
 | |
|       
 | |
|       continue;
 | |
|     } else {
 | |
|       TxString = NetbufGetByte (Packet, 0, NULL);
 | |
|       ASSERT (TxString != NULL);
 | |
|       DnsHeader = (DNS_HEADER *) TxString;
 | |
|       QueryName = (CHAR8 *) (TxString + sizeof (*DnsHeader));
 | |
|       QuerySection = (DNS_QUERY_SECTION *) (QueryName + AsciiStrLen (QueryName) + 1);
 | |
|         
 | |
|       if (NTOHS (DnsHeader->Identification) == Identification &&
 | |
|           NTOHS (QuerySection->Type) == Type && 
 | |
|           NTOHS (QuerySection->Class) == Class) {
 | |
|         return TRUE;
 | |
|       }
 | |
|     } 
 | |
|   }
 | |
|   
 | |
|   *Item = NULL;
 | |
|   
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Parse Dns Response.
 | |
| 
 | |
|   @param  Instance              The DNS instance
 | |
|   @param  RxString              Received buffer.
 | |
|   @param  Completed             Flag to indicate that Dns response is valid. 
 | |
|   
 | |
|   @retval EFI_SUCCESS           Parse Dns Response successfully.
 | |
|   @retval Others                Failed to parse Dns Response.
 | |
|   
 | |
| **/ 
 | |
| EFI_STATUS
 | |
| ParseDnsResponse (
 | |
|   IN OUT DNS_INSTANCE              *Instance,
 | |
|   IN     UINT8                     *RxString,
 | |
|      OUT BOOLEAN                   *Completed
 | |
|   )
 | |
| {
 | |
|   DNS_HEADER            *DnsHeader;
 | |
|   
 | |
|   CHAR8                 *QueryName;
 | |
|   DNS_QUERY_SECTION     *QuerySection;
 | |
|   
 | |
|   CHAR8                 *AnswerName;
 | |
|   DNS_ANSWER_SECTION    *AnswerSection;
 | |
|   UINT8                 *AnswerData;
 | |
| 
 | |
|   NET_MAP_ITEM          *Item;
 | |
|   DNS4_TOKEN_ENTRY      *Dns4TokenEntry;
 | |
|   DNS6_TOKEN_ENTRY      *Dns6TokenEntry;
 | |
|   
 | |
|   UINT32                IpCount;
 | |
|   UINT32                RRCount;
 | |
|   UINT32                AnswerSectionNum;
 | |
|   UINT32                CNameTtl;
 | |
|   
 | |
|   EFI_IPv4_ADDRESS      *HostAddr4;
 | |
|   EFI_IPv6_ADDRESS      *HostAddr6;
 | |
| 
 | |
|   EFI_DNS4_CACHE_ENTRY  *Dns4CacheEntry;
 | |
|   EFI_DNS6_CACHE_ENTRY  *Dns6CacheEntry;
 | |
| 
 | |
|   DNS_RESOURCE_RECORD   *Dns4RR;
 | |
|   DNS6_RESOURCE_RECORD  *Dns6RR;
 | |
| 
 | |
|   EFI_STATUS            Status;
 | |
| 
 | |
|   EFI_TPL               OldTpl;
 | |
|   
 | |
|   Item             = NULL;
 | |
|   Dns4TokenEntry   = NULL;
 | |
|   Dns6TokenEntry   = NULL;
 | |
|   
 | |
|   IpCount          = 0;
 | |
|   RRCount          = 0;
 | |
|   AnswerSectionNum = 0;
 | |
|   CNameTtl         = 0;
 | |
|   
 | |
|   HostAddr4        = NULL;
 | |
|   HostAddr6        = NULL;
 | |
|   
 | |
|   Dns4CacheEntry   = NULL;
 | |
|   Dns6CacheEntry   = NULL;
 | |
|   
 | |
|   Dns4RR           = NULL;
 | |
|   Dns6RR           = NULL;
 | |
| 
 | |
|   *Completed       = TRUE;
 | |
|   Status           = EFI_SUCCESS;
 | |
|   
 | |
|   //
 | |
|   // Get header
 | |
|   //
 | |
|   DnsHeader = (DNS_HEADER *) RxString;
 | |
|   
 | |
|   DnsHeader->Identification = NTOHS (DnsHeader->Identification);
 | |
|   DnsHeader->Flags.Uint16 = NTOHS (DnsHeader->Flags.Uint16);
 | |
|   DnsHeader->QuestionsNum = NTOHS (DnsHeader->QuestionsNum);
 | |
|   DnsHeader->AnswersNum = NTOHS (DnsHeader->AnswersNum);
 | |
|   DnsHeader->AuthorityNum = NTOHS (DnsHeader->AuthorityNum);
 | |
|   DnsHeader->AditionalNum = NTOHS (DnsHeader->AditionalNum);
 | |
| 
 | |
|   //
 | |
|   // Get Query name
 | |
|   //
 | |
|   QueryName = (CHAR8 *) (RxString + sizeof (*DnsHeader));
 | |
| 
 | |
|   //
 | |
|   // Get query section
 | |
|   //
 | |
|   QuerySection = (DNS_QUERY_SECTION *) (QueryName + AsciiStrLen (QueryName) + 1);
 | |
|   QuerySection->Type = NTOHS (QuerySection->Type);
 | |
|   QuerySection->Class = NTOHS (QuerySection->Class);
 | |
| 
 | |
|   //
 | |
|   // Get Answer name
 | |
|   //
 | |
|   AnswerName = (CHAR8 *) QuerySection + sizeof (*QuerySection);
 | |
| 
 | |
|   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
 | |
| 
 | |
|   //
 | |
|   // Check DnsResponse Validity, if so, also get a valid NET_MAP_ITEM.
 | |
|   //
 | |
|   if (Instance->Service->IpVersion == IP_VERSION_4) {
 | |
|     if (!IsValidDnsResponse (
 | |
|            &Instance->Dns4TxTokens, 
 | |
|            DnsHeader->Identification, 
 | |
|            QuerySection->Type,
 | |
|            QuerySection->Class,
 | |
|            &Item
 | |
|            )) {
 | |
|       *Completed = FALSE;
 | |
|       Status = EFI_ABORTED;
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
|     ASSERT (Item != NULL);
 | |
|     Dns4TokenEntry = (DNS4_TOKEN_ENTRY *) (Item->Key);
 | |
|   } else {
 | |
|     if (!IsValidDnsResponse (
 | |
|            &Instance->Dns6TxTokens, 
 | |
|            DnsHeader->Identification, 
 | |
|            QuerySection->Type,
 | |
|            QuerySection->Class,
 | |
|            &Item
 | |
|            )) {
 | |
|       *Completed = FALSE;
 | |
|       Status = EFI_ABORTED;
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
|     ASSERT (Item != NULL);
 | |
|     Dns6TokenEntry = (DNS6_TOKEN_ENTRY *) (Item->Key);
 | |
|   }
 | |
|    
 | |
|   //
 | |
|   // Continue Check Some Errors.
 | |
|   //
 | |
|   if (DnsHeader->Flags.Bits.RCode != DNS_FLAGS_RCODE_NO_ERROR || DnsHeader->AnswersNum < 1 || \
 | |
|       DnsHeader->Flags.Bits.QR != DNS_FLAGS_QR_RESPONSE) {
 | |
|     //
 | |
|     // The domain name referenced in the query does not exist.
 | |
|     //
 | |
|     if (DnsHeader->Flags.Bits.RCode == DNS_FLAGS_RCODE_NAME_ERROR) {
 | |
|       Status = EFI_NOT_FOUND; 
 | |
|     } else {
 | |
|       Status = EFI_DEVICE_ERROR;
 | |
|     }
 | |
|     
 | |
|     goto ON_COMPLETE;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Do some buffer allocations.
 | |
|   //
 | |
|   if (Instance->Service->IpVersion == IP_VERSION_4) {
 | |
|     ASSERT (Dns4TokenEntry != NULL);
 | |
| 
 | |
|     if (Dns4TokenEntry->GeneralLookUp) {
 | |
|       //
 | |
|       // It's the GeneralLookUp querying.
 | |
|       //
 | |
|       Dns4TokenEntry->Token->RspData.GLookupData = AllocateZeroPool (sizeof (DNS_RESOURCE_RECORD));
 | |
|       if (Dns4TokenEntry->Token->RspData.GLookupData == NULL) {
 | |
|         Status = EFI_OUT_OF_RESOURCES;
 | |
|         goto ON_EXIT;
 | |
|       }
 | |
|       Dns4TokenEntry->Token->RspData.GLookupData->RRList = AllocateZeroPool (DnsHeader->AnswersNum * sizeof (DNS_RESOURCE_RECORD));
 | |
|       if (Dns4TokenEntry->Token->RspData.GLookupData->RRList == NULL) {
 | |
|         Status = EFI_OUT_OF_RESOURCES;
 | |
|         goto ON_EXIT;
 | |
|       }
 | |
|     } else {
 | |
|       //
 | |
|       // It's not the GeneralLookUp querying. Check the Query type.
 | |
|       //
 | |
|       if (QuerySection->Type == DNS_TYPE_A) {
 | |
|         Dns4TokenEntry->Token->RspData.H2AData = AllocateZeroPool (sizeof (DNS_HOST_TO_ADDR_DATA));
 | |
|         if (Dns4TokenEntry->Token->RspData.H2AData == NULL) {
 | |
|           Status = EFI_OUT_OF_RESOURCES;
 | |
|           goto ON_EXIT;
 | |
|         }
 | |
|         Dns4TokenEntry->Token->RspData.H2AData->IpList = AllocateZeroPool (DnsHeader->AnswersNum * sizeof (EFI_IPv4_ADDRESS));
 | |
|         if (Dns4TokenEntry->Token->RspData.H2AData->IpList == NULL) {
 | |
|           Status = EFI_OUT_OF_RESOURCES;
 | |
|           goto ON_EXIT;
 | |
|         }
 | |
|       } else {
 | |
|         Status = EFI_UNSUPPORTED;
 | |
|         goto ON_EXIT;
 | |
|       }
 | |
|     }
 | |
|   } else {
 | |
|     ASSERT (Dns6TokenEntry != NULL);
 | |
| 
 | |
|     if (Dns6TokenEntry->GeneralLookUp) {
 | |
|       //
 | |
|       // It's the GeneralLookUp querying.
 | |
|       //
 | |
|       Dns6TokenEntry->Token->RspData.GLookupData = AllocateZeroPool (sizeof (DNS_RESOURCE_RECORD));
 | |
|       if (Dns6TokenEntry->Token->RspData.GLookupData == NULL) {
 | |
|         Status = EFI_OUT_OF_RESOURCES;
 | |
|         goto ON_EXIT;
 | |
|       }
 | |
|       Dns6TokenEntry->Token->RspData.GLookupData->RRList = AllocateZeroPool (DnsHeader->AnswersNum * sizeof (DNS_RESOURCE_RECORD));
 | |
|       if (Dns6TokenEntry->Token->RspData.GLookupData->RRList == NULL) {
 | |
|         Status = EFI_OUT_OF_RESOURCES;
 | |
|         goto ON_EXIT;
 | |
|       }
 | |
|     } else {
 | |
|       //
 | |
|       // It's not the GeneralLookUp querying. Check the Query type.
 | |
|       //
 | |
|       if (QuerySection->Type == DNS_TYPE_AAAA) {
 | |
|         Dns6TokenEntry->Token->RspData.H2AData = AllocateZeroPool (sizeof (DNS6_HOST_TO_ADDR_DATA));
 | |
|         if (Dns6TokenEntry->Token->RspData.H2AData == NULL) {
 | |
|           Status = EFI_OUT_OF_RESOURCES;
 | |
|           goto ON_EXIT;
 | |
|         }
 | |
|         Dns6TokenEntry->Token->RspData.H2AData->IpList = AllocateZeroPool (DnsHeader->AnswersNum * sizeof (EFI_IPv6_ADDRESS));
 | |
|         if (Dns6TokenEntry->Token->RspData.H2AData->IpList == NULL) {
 | |
|           Status = EFI_OUT_OF_RESOURCES;
 | |
|           goto ON_EXIT;
 | |
|         }
 | |
|       } else {
 | |
|         Status = EFI_UNSUPPORTED;
 | |
|         goto ON_EXIT;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Status = EFI_NOT_FOUND;
 | |
| 
 | |
|   //
 | |
|   // Processing AnswerSection.
 | |
|   //
 | |
|   while (AnswerSectionNum < DnsHeader->AnswersNum) {
 | |
|     //
 | |
|     // Answer name should be PTR, else EFI_UNSUPPORTED returned.
 | |
|     //
 | |
|     if ((*(UINT8 *) AnswerName & 0xC0) != 0xC0) {
 | |
|       Status = EFI_UNSUPPORTED;
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
|     
 | |
|     //
 | |
|     // Get Answer section.
 | |
|     //
 | |
|     AnswerSection = (DNS_ANSWER_SECTION *) (AnswerName + sizeof (UINT16));
 | |
|     AnswerSection->Type = NTOHS (AnswerSection->Type);
 | |
|     AnswerSection->Class = NTOHS (AnswerSection->Class);
 | |
|     AnswerSection->Ttl = NTOHL (AnswerSection->Ttl);
 | |
|     AnswerSection->DataLength = NTOHS (AnswerSection->DataLength);
 | |
| 
 | |
|     //
 | |
|     // Check whether it's the GeneralLookUp querying.
 | |
|     //
 | |
|     if (Instance->Service->IpVersion == IP_VERSION_4 && Dns4TokenEntry->GeneralLookUp) {
 | |
|       Dns4RR = Dns4TokenEntry->Token->RspData.GLookupData->RRList;
 | |
|       AnswerData = (UINT8 *) AnswerSection + sizeof (*AnswerSection);
 | |
| 
 | |
|       //
 | |
|       // Fill the ResourceRecord.
 | |
|       //
 | |
|       Dns4RR[RRCount].QName = AllocateZeroPool (AsciiStrLen (QueryName) + 1);
 | |
|       if (Dns4RR[RRCount].QName == NULL) {
 | |
|         Status = EFI_OUT_OF_RESOURCES;
 | |
|         goto ON_EXIT;
 | |
|       }
 | |
|       CopyMem (Dns4RR[RRCount].QName, QueryName, AsciiStrLen (QueryName));
 | |
|       Dns4RR[RRCount].QType = AnswerSection->Type;
 | |
|       Dns4RR[RRCount].QClass = AnswerSection->Class;
 | |
|       Dns4RR[RRCount].TTL = AnswerSection->Ttl;
 | |
|       Dns4RR[RRCount].DataLength = AnswerSection->DataLength;
 | |
|       Dns4RR[RRCount].RData = AllocateZeroPool (Dns4RR[RRCount].DataLength);
 | |
|       if (Dns4RR[RRCount].RData == NULL) {
 | |
|         Status = EFI_OUT_OF_RESOURCES;
 | |
|         goto ON_EXIT;
 | |
|       }
 | |
|       CopyMem (Dns4RR[RRCount].RData, AnswerData, Dns4RR[RRCount].DataLength);
 | |
|       
 | |
|       RRCount ++;
 | |
|       Status = EFI_SUCCESS;
 | |
|     } else if (Instance->Service->IpVersion == IP_VERSION_6 && Dns6TokenEntry->GeneralLookUp) {
 | |
|       Dns6RR = Dns6TokenEntry->Token->RspData.GLookupData->RRList;
 | |
|       AnswerData = (UINT8 *) AnswerSection + sizeof (*AnswerSection);
 | |
| 
 | |
|       //
 | |
|       // Fill the ResourceRecord.
 | |
|       //
 | |
|       Dns6RR[RRCount].QName = AllocateZeroPool (AsciiStrLen (QueryName) + 1);
 | |
|       if (Dns6RR[RRCount].QName == NULL) {
 | |
|         Status = EFI_OUT_OF_RESOURCES;
 | |
|         goto ON_EXIT;
 | |
|       }
 | |
|       CopyMem (Dns6RR[RRCount].QName, QueryName, AsciiStrLen (QueryName));
 | |
|       Dns6RR[RRCount].QType = AnswerSection->Type;
 | |
|       Dns6RR[RRCount].QClass = AnswerSection->Class;
 | |
|       Dns6RR[RRCount].TTL = AnswerSection->Ttl;
 | |
|       Dns6RR[RRCount].DataLength = AnswerSection->DataLength;
 | |
|       Dns6RR[RRCount].RData = AllocateZeroPool (Dns6RR[RRCount].DataLength);
 | |
|       if (Dns6RR[RRCount].RData == NULL) {
 | |
|         Status = EFI_OUT_OF_RESOURCES;
 | |
|         goto ON_EXIT;
 | |
|       }
 | |
|       CopyMem (Dns6RR[RRCount].RData, AnswerData, Dns6RR[RRCount].DataLength);
 | |
|       
 | |
|       RRCount ++;
 | |
|       Status = EFI_SUCCESS;
 | |
|     } else {
 | |
|       //
 | |
|       // It's not the GeneralLookUp querying. 
 | |
|       // Check the Query type, parse the response packet.
 | |
|       //
 | |
|       switch (AnswerSection->Type) {
 | |
|       case DNS_TYPE_A:
 | |
|         //
 | |
|         // This is address entry, get Data.
 | |
|         //
 | |
|         ASSERT (Dns4TokenEntry != NULL);
 | |
| 
 | |
|         if (AnswerSection->DataLength != 4) {
 | |
|           Status = EFI_ABORTED;
 | |
|           goto ON_EXIT;
 | |
|         }
 | |
|         
 | |
|         HostAddr4 = Dns4TokenEntry->Token->RspData.H2AData->IpList;
 | |
|         AnswerData = (UINT8 *) AnswerSection + sizeof (*AnswerSection);
 | |
|         CopyMem (&HostAddr4[IpCount], AnswerData, sizeof (EFI_IPv4_ADDRESS));
 | |
| 
 | |
|         // 
 | |
|         // Allocate new CacheEntry pool to update DNS cache dynamically.
 | |
|         //
 | |
|         Dns4CacheEntry = AllocateZeroPool (sizeof (EFI_DNS4_CACHE_ENTRY));
 | |
|         if (Dns4CacheEntry == NULL) {
 | |
|           Status = EFI_OUT_OF_RESOURCES;
 | |
|           goto ON_EXIT;
 | |
|         }
 | |
|         Dns4CacheEntry->HostName = AllocateZeroPool (2 * (StrLen(Dns4TokenEntry->QueryHostName) + 1));
 | |
|         if (Dns4CacheEntry->HostName == NULL) {
 | |
|           Status = EFI_OUT_OF_RESOURCES;
 | |
|           goto ON_EXIT;
 | |
|         }
 | |
|         CopyMem (Dns4CacheEntry->HostName, Dns4TokenEntry->QueryHostName, 2 * (StrLen(Dns4TokenEntry->QueryHostName) + 1));
 | |
|         Dns4CacheEntry->IpAddress = AllocateZeroPool (sizeof (EFI_IPv4_ADDRESS));
 | |
|         if (Dns4CacheEntry->IpAddress == NULL) {
 | |
|           Status = EFI_OUT_OF_RESOURCES;
 | |
|           goto ON_EXIT;
 | |
|         }
 | |
|         CopyMem (Dns4CacheEntry->IpAddress, AnswerData, sizeof (EFI_IPv4_ADDRESS));
 | |
| 
 | |
|         if (CNameTtl != 0 && AnswerSection->Ttl != 0) {
 | |
|           Dns4CacheEntry->Timeout = MIN (CNameTtl, AnswerSection->Ttl);
 | |
|         } else {
 | |
|           Dns4CacheEntry->Timeout = MAX (CNameTtl, AnswerSection->Ttl);
 | |
|         }
 | |
|         
 | |
|         UpdateDns4Cache (&mDriverData->Dns4CacheList, FALSE, TRUE, *Dns4CacheEntry);
 | |
| 
 | |
|         // 
 | |
|         // Free allocated CacheEntry pool.
 | |
|         //
 | |
|         FreePool (Dns4CacheEntry->HostName);
 | |
|         Dns4CacheEntry->HostName = NULL;
 | |
|         
 | |
|         FreePool (Dns4CacheEntry->IpAddress);
 | |
|         Dns4CacheEntry->IpAddress = NULL;
 | |
| 
 | |
|         FreePool (Dns4CacheEntry);
 | |
|         Dns4CacheEntry = NULL;
 | |
| 
 | |
|         IpCount ++;
 | |
|         Status = EFI_SUCCESS;
 | |
|         break;
 | |
|       case DNS_TYPE_AAAA:
 | |
|         //
 | |
|         // This is address entry, get Data.
 | |
|         //
 | |
|         ASSERT (Dns6TokenEntry != NULL);
 | |
| 
 | |
|         if (AnswerSection->DataLength != 16) {
 | |
|           Status = EFI_ABORTED;
 | |
|           goto ON_EXIT;
 | |
|         }
 | |
|         
 | |
|         HostAddr6 = Dns6TokenEntry->Token->RspData.H2AData->IpList;
 | |
|         AnswerData = (UINT8 *) AnswerSection + sizeof (*AnswerSection);
 | |
|         CopyMem (&HostAddr6[IpCount], AnswerData, sizeof (EFI_IPv6_ADDRESS));
 | |
| 
 | |
|         // 
 | |
|         // Allocate new CacheEntry pool to update DNS cache dynamically.
 | |
|         //
 | |
|         Dns6CacheEntry = AllocateZeroPool (sizeof (EFI_DNS6_CACHE_ENTRY));
 | |
|         if (Dns6CacheEntry == NULL) {
 | |
|           Status = EFI_OUT_OF_RESOURCES;
 | |
|           goto ON_EXIT;
 | |
|         }
 | |
|         Dns6CacheEntry->HostName = AllocateZeroPool (2 * (StrLen(Dns6TokenEntry->QueryHostName) + 1));
 | |
|         if (Dns6CacheEntry->HostName == NULL) {
 | |
|           Status = EFI_OUT_OF_RESOURCES;
 | |
|           goto ON_EXIT;
 | |
|         }
 | |
|         CopyMem (Dns6CacheEntry->HostName, Dns6TokenEntry->QueryHostName, 2 * (StrLen(Dns6TokenEntry->QueryHostName) + 1));
 | |
|         Dns6CacheEntry->IpAddress = AllocateZeroPool (sizeof (EFI_IPv6_ADDRESS));
 | |
|         if (Dns6CacheEntry->IpAddress == NULL) {
 | |
|           Status = EFI_OUT_OF_RESOURCES;
 | |
|           goto ON_EXIT;
 | |
|         }
 | |
|         CopyMem (Dns6CacheEntry->IpAddress, AnswerData, sizeof (EFI_IPv6_ADDRESS));
 | |
| 
 | |
|         if (CNameTtl != 0 && AnswerSection->Ttl != 0) {
 | |
|           Dns6CacheEntry->Timeout = MIN (CNameTtl, AnswerSection->Ttl);
 | |
|         } else {
 | |
|           Dns6CacheEntry->Timeout = MAX (CNameTtl, AnswerSection->Ttl);
 | |
|         }
 | |
|         
 | |
|         UpdateDns6Cache (&mDriverData->Dns6CacheList, FALSE, TRUE, *Dns6CacheEntry);
 | |
| 
 | |
|         // 
 | |
|         // Free allocated CacheEntry pool.
 | |
|         //
 | |
|         FreePool (Dns6CacheEntry->HostName);
 | |
|         Dns6CacheEntry->HostName = NULL;
 | |
|         
 | |
|         FreePool (Dns6CacheEntry->IpAddress);
 | |
|         Dns6CacheEntry->IpAddress = NULL;
 | |
| 
 | |
|         FreePool (Dns6CacheEntry);
 | |
|         Dns6CacheEntry = NULL;
 | |
|         
 | |
|         IpCount ++;
 | |
|         Status = EFI_SUCCESS;
 | |
|         break;
 | |
|       case DNS_TYPE_CNAME:
 | |
|         //
 | |
|         // According RFC 1034 - 3.6.2, if the query name is an alias, the name server will include the CNAME 
 | |
|         // record in the response and restart the query at the domain name specified in the data field of the 
 | |
|         // CNAME record. So, just record the TTL value of the CNAME, then skip to parse the next record.
 | |
|         //
 | |
|         CNameTtl = AnswerSection->Ttl;
 | |
|         break;
 | |
|       default:
 | |
|         Status = EFI_UNSUPPORTED;
 | |
|         goto ON_EXIT;
 | |
|       }
 | |
|     }
 | |
|     
 | |
|     //
 | |
|     // Find next one
 | |
|     //
 | |
|     AnswerName = (CHAR8 *) AnswerSection + sizeof (*AnswerSection) + AnswerSection->DataLength;
 | |
|     AnswerSectionNum ++;
 | |
|   }
 | |
| 
 | |
|   if (Instance->Service->IpVersion == IP_VERSION_4) {
 | |
|     ASSERT (Dns4TokenEntry != NULL);
 | |
|     
 | |
|     if (Dns4TokenEntry->GeneralLookUp) {
 | |
|       Dns4TokenEntry->Token->RspData.GLookupData->RRCount = RRCount;
 | |
|     } else {
 | |
|       if (QuerySection->Type == DNS_TYPE_A) {
 | |
|         Dns4TokenEntry->Token->RspData.H2AData->IpCount = IpCount;
 | |
|       } else {
 | |
|         Status = EFI_UNSUPPORTED;
 | |
|         goto ON_EXIT;
 | |
|       }
 | |
|     }
 | |
|   } else {
 | |
|     ASSERT (Dns6TokenEntry != NULL);
 | |
| 
 | |
|     if (Dns6TokenEntry->GeneralLookUp) {
 | |
|       Dns6TokenEntry->Token->RspData.GLookupData->RRCount = RRCount;
 | |
|     } else {
 | |
|       if (QuerySection->Type == DNS_TYPE_AAAA) {
 | |
|         Dns6TokenEntry->Token->RspData.H2AData->IpCount = IpCount;
 | |
|       } else {
 | |
|         Status = EFI_UNSUPPORTED;
 | |
|         goto ON_EXIT;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   
 | |
| ON_COMPLETE:
 | |
|   //
 | |
|   // Parsing is complete, free the sending packet and signal Event here.
 | |
|   //
 | |
|   if (Item != NULL && Item->Value != NULL) {
 | |
|     NetbufFree ((NET_BUF *) (Item->Value));
 | |
|   }
 | |
|   
 | |
|   if (Instance->Service->IpVersion == IP_VERSION_4) {
 | |
|     ASSERT (Dns4TokenEntry != NULL);
 | |
|     Dns4RemoveTokenEntry (&Instance->Dns4TxTokens, Dns4TokenEntry);
 | |
|     Dns4TokenEntry->Token->Status = Status;
 | |
|     if (Dns4TokenEntry->Token->Event != NULL) {
 | |
|       gBS->SignalEvent (Dns4TokenEntry->Token->Event);
 | |
|       DispatchDpc ();
 | |
|     }
 | |
|   } else {
 | |
|     ASSERT (Dns6TokenEntry != NULL);
 | |
|     Dns6RemoveTokenEntry (&Instance->Dns6TxTokens, Dns6TokenEntry);
 | |
|     Dns6TokenEntry->Token->Status = Status;
 | |
|     if (Dns6TokenEntry->Token->Event != NULL) {
 | |
|       gBS->SignalEvent (Dns6TokenEntry->Token->Event);
 | |
|       DispatchDpc ();
 | |
|     }
 | |
|   }
 | |
| 
 | |
| ON_EXIT:
 | |
|   //
 | |
|   // Free the allocated buffer if error happen.
 | |
|   //
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     if (Dns4TokenEntry != NULL) {
 | |
|       if (Dns4TokenEntry->GeneralLookUp) {
 | |
|         if (Dns4TokenEntry->Token->RspData.GLookupData != NULL) {
 | |
|           if (Dns4TokenEntry->Token->RspData.GLookupData->RRList != NULL) {
 | |
|             while (RRCount != 0) {
 | |
|               RRCount --;
 | |
|               if (Dns4TokenEntry->Token->RspData.GLookupData->RRList[RRCount].QName != NULL) {
 | |
|                 FreePool (Dns4TokenEntry->Token->RspData.GLookupData->RRList[RRCount].QName);
 | |
|               }
 | |
| 
 | |
|               if (Dns4TokenEntry->Token->RspData.GLookupData->RRList[RRCount].RData != NULL) {
 | |
|                 FreePool (Dns4TokenEntry->Token->RspData.GLookupData->RRList[RRCount].RData);
 | |
|               }
 | |
|             }
 | |
|             
 | |
|             FreePool (Dns4TokenEntry->Token->RspData.GLookupData->RRList);
 | |
|           }
 | |
|           
 | |
|           FreePool (Dns4TokenEntry->Token->RspData.GLookupData);
 | |
|         }
 | |
|       } else {
 | |
|         if (QuerySection->Type == DNS_TYPE_A && Dns4TokenEntry->Token->RspData.H2AData != NULL) {
 | |
|           if (Dns4TokenEntry->Token->RspData.H2AData->IpList != NULL) {
 | |
|             FreePool (Dns4TokenEntry->Token->RspData.H2AData->IpList);
 | |
|           }
 | |
|           
 | |
|           FreePool (Dns4TokenEntry->Token->RspData.H2AData);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (Dns6TokenEntry != NULL) {
 | |
|       if (Dns6TokenEntry->GeneralLookUp) {
 | |
|         if (Dns6TokenEntry->Token->RspData.GLookupData != NULL) {
 | |
|           if (Dns6TokenEntry->Token->RspData.GLookupData->RRList != NULL) {
 | |
|             while (RRCount != 0) {
 | |
|               RRCount --;
 | |
|               if (Dns6TokenEntry->Token->RspData.GLookupData->RRList[RRCount].QName != NULL) {
 | |
|                 FreePool (Dns6TokenEntry->Token->RspData.GLookupData->RRList[RRCount].QName);
 | |
|               }
 | |
| 
 | |
|               if (Dns6TokenEntry->Token->RspData.GLookupData->RRList[RRCount].RData != NULL) {
 | |
|                 FreePool (Dns6TokenEntry->Token->RspData.GLookupData->RRList[RRCount].RData);
 | |
|               }
 | |
|             }
 | |
|             
 | |
|             FreePool (Dns6TokenEntry->Token->RspData.GLookupData->RRList);
 | |
|           }
 | |
|           
 | |
|           FreePool (Dns6TokenEntry->Token->RspData.GLookupData);
 | |
|         }
 | |
|       } else {
 | |
|         if (QuerySection->Type == DNS_TYPE_AAAA && Dns6TokenEntry->Token->RspData.H2AData != NULL) {
 | |
|           if (Dns6TokenEntry->Token->RspData.H2AData->IpList != NULL) {
 | |
|             FreePool (Dns6TokenEntry->Token->RspData.H2AData->IpList);
 | |
|           }
 | |
|           
 | |
|           FreePool (Dns6TokenEntry->Token->RspData.H2AData);
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (Dns4CacheEntry != NULL) {
 | |
|       if (Dns4CacheEntry->HostName != NULL) {
 | |
|         FreePool (Dns4CacheEntry->HostName);
 | |
|       }
 | |
| 
 | |
|       if (Dns4CacheEntry->IpAddress != NULL) {
 | |
|         FreePool (Dns4CacheEntry->IpAddress);
 | |
|       }
 | |
| 
 | |
|       FreePool (Dns4CacheEntry);
 | |
|     }
 | |
| 
 | |
|     if (Dns6CacheEntry != NULL) {
 | |
|       if (Dns6CacheEntry->HostName != NULL) {
 | |
|         FreePool (Dns6CacheEntry->HostName);
 | |
|       }
 | |
| 
 | |
|       if (Dns6CacheEntry->IpAddress != NULL) {
 | |
|         FreePool (Dns6CacheEntry->IpAddress);
 | |
|       }
 | |
| 
 | |
|       FreePool (Dns6CacheEntry);
 | |
|     }    
 | |
|   }
 | |
|   
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Parse response packet.
 | |
| 
 | |
|   @param  Packet                The packets received.
 | |
|   @param  EndPoint              The local/remote UDP access point
 | |
|   @param  IoStatus              The status of the UDP receive
 | |
|   @param  Context               The opaque parameter to the function.
 | |
| 
 | |
| **/  
 | |
| VOID
 | |
| EFIAPI
 | |
| DnsOnPacketReceived (
 | |
|   NET_BUF                   *Packet,
 | |
|   UDP_END_POINT             *EndPoint,
 | |
|   EFI_STATUS                IoStatus,
 | |
|   VOID                      *Context
 | |
|   )
 | |
| {
 | |
|   DNS_INSTANCE              *Instance;
 | |
| 
 | |
|   UINT8                     *RcvString;
 | |
| 
 | |
|   BOOLEAN                   Completed;
 | |
|   
 | |
|   Instance  = (DNS_INSTANCE *) Context;
 | |
|   NET_CHECK_SIGNATURE (Instance, DNS_INSTANCE_SIGNATURE);
 | |
| 
 | |
|   RcvString = NULL;
 | |
|   Completed = FALSE;
 | |
| 
 | |
|   if (EFI_ERROR (IoStatus)) {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   ASSERT (Packet != NULL);
 | |
| 
 | |
|   if (Packet->TotalSize <= sizeof (DNS_HEADER)) {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
|   
 | |
|   RcvString = NetbufGetByte (Packet, 0, NULL);
 | |
|   ASSERT (RcvString != NULL);
 | |
|   
 | |
|   //
 | |
|   // Parse Dns Response
 | |
|   //
 | |
|   ParseDnsResponse (Instance, RcvString, &Completed);
 | |
| 
 | |
| ON_EXIT:
 | |
| 
 | |
|   if (Packet != NULL) {
 | |
|     NetbufFree (Packet);
 | |
|   }
 | |
| 
 | |
|   if (!Completed) {
 | |
|     UdpIoRecvDatagram (Instance->UdpIo, DnsOnPacketReceived, Instance, 0);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Release the net buffer when packet is sent.
 | |
| 
 | |
|   @param  Packet                The packets received.
 | |
|   @param  EndPoint              The local/remote UDP access point
 | |
|   @param  IoStatus              The status of the UDP receive
 | |
|   @param  Context               The opaque parameter to the function.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| DnsOnPacketSent (
 | |
|   NET_BUF                   *Packet,
 | |
|   UDP_END_POINT             *EndPoint,
 | |
|   EFI_STATUS                IoStatus,
 | |
|   VOID                      *Context
 | |
|   )
 | |
| {
 | |
|   DNS_INSTANCE              *Instance;
 | |
|   LIST_ENTRY                *Entry;
 | |
|   NET_MAP_ITEM              *Item;
 | |
|   DNS4_TOKEN_ENTRY          *Dns4TokenEntry;
 | |
|   DNS6_TOKEN_ENTRY          *Dns6TokenEntry;
 | |
| 
 | |
|   Dns4TokenEntry = NULL;
 | |
|   Dns6TokenEntry = NULL;
 | |
| 
 | |
|   Instance  = (DNS_INSTANCE *) Context;
 | |
|   NET_CHECK_SIGNATURE (Instance, DNS_INSTANCE_SIGNATURE);
 | |
| 
 | |
|   if (Instance->Service->IpVersion == IP_VERSION_4) {
 | |
|     NET_LIST_FOR_EACH (Entry, &Instance->Dns4TxTokens.Used) {
 | |
|       Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
 | |
|       if (Packet == (NET_BUF *)(Item->Value)) {
 | |
|         Dns4TokenEntry = ((DNS4_TOKEN_ENTRY *)Item->Key);
 | |
|         Dns4TokenEntry->PacketToLive = Dns4TokenEntry->Token->RetryInterval;
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|   } else {
 | |
|     NET_LIST_FOR_EACH (Entry, &Instance->Dns6TxTokens.Used) {
 | |
|       Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
 | |
|       if (Packet == (NET_BUF *)(Item->Value)) {
 | |
|         Dns6TokenEntry = ((DNS6_TOKEN_ENTRY *)Item->Key);
 | |
|         Dns6TokenEntry->PacketToLive = Dns6TokenEntry->Token->RetryInterval;
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   
 | |
|   NetbufFree (Packet);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Query request information.
 | |
| 
 | |
|   @param  Instance              The DNS instance
 | |
|   @param  Packet                The packet for querying request information.
 | |
| 
 | |
|   @retval EFI_SUCCESS           Query request information successfully.
 | |
|   @retval Others                Failed to query request information.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| DoDnsQuery (
 | |
|   IN  DNS_INSTANCE              *Instance,
 | |
|   IN  NET_BUF                   *Packet
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS      Status;
 | |
| 
 | |
|   //
 | |
|   // Ready to receive the DNS response.
 | |
|   //
 | |
|   if (Instance->UdpIo->RecvRequest == NULL) {
 | |
|     Status = UdpIoRecvDatagram (Instance->UdpIo, DnsOnPacketReceived, Instance, 0);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Transmit the DNS packet.
 | |
|   //
 | |
|   NET_GET_REF (Packet);
 | |
| 
 | |
|   Status = UdpIoSendDatagram (Instance->UdpIo, Packet, NULL, NULL, DnsOnPacketSent, Instance);
 | |
|   
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Construct the Packet according query section.
 | |
| 
 | |
|   @param  Instance              The DNS instance
 | |
|   @param  QueryName             Queried Name  
 | |
|   @param  Type                  Queried Type 
 | |
|   @param  Class                 Queried Class 
 | |
|   @param  Packet                The packet for query
 | |
| 
 | |
|   @retval EFI_SUCCESS           The packet is constructed.
 | |
|   @retval Others                Failed to construct the Packet.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| ConstructDNSQuery (
 | |
|   IN  DNS_INSTANCE              *Instance,
 | |
|   IN  CHAR8                     *QueryName,
 | |
|   IN  UINT16                    Type,
 | |
|   IN  UINT16                    Class,
 | |
|   OUT NET_BUF                   **Packet
 | |
|   )
 | |
| {
 | |
|   NET_FRAGMENT        Frag;
 | |
|   DNS_HEADER          *DnsHeader;
 | |
|   DNS_QUERY_SECTION   *DnsQuery;
 | |
| 
 | |
|   //
 | |
|   // Messages carried by UDP are restricted to 512 bytes (not counting the IP
 | |
|   // or UDP headers).
 | |
|   //
 | |
|   Frag.Bulk = AllocatePool (DNS_MAX_MESSAGE_SIZE * sizeof (UINT8));
 | |
|   if (Frag.Bulk == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Fill header
 | |
|   //
 | |
|   DnsHeader = (DNS_HEADER *) Frag.Bulk; 
 | |
|   DnsHeader->Identification = (UINT16)NET_RANDOM (NetRandomInitSeed());
 | |
|   DnsHeader->Flags.Uint16 = 0x0000;
 | |
|   DnsHeader->Flags.Bits.RD = 1;
 | |
|   DnsHeader->Flags.Bits.OpCode = DNS_FLAGS_OPCODE_STANDARD;
 | |
|   DnsHeader->Flags.Bits.QR = DNS_FLAGS_QR_QUERY;
 | |
|   DnsHeader->QuestionsNum = 1;
 | |
|   DnsHeader->AnswersNum = 0;
 | |
|   DnsHeader->AuthorityNum = 0;
 | |
|   DnsHeader->AditionalNum = 0;
 | |
| 
 | |
|   DnsHeader->Identification = HTONS (DnsHeader->Identification);
 | |
|   DnsHeader->Flags.Uint16 = HTONS (DnsHeader->Flags.Uint16);
 | |
|   DnsHeader->QuestionsNum = HTONS (DnsHeader->QuestionsNum);
 | |
|   DnsHeader->AnswersNum = HTONS (DnsHeader->AnswersNum);
 | |
|   DnsHeader->AuthorityNum = HTONS (DnsHeader->AuthorityNum);
 | |
|   DnsHeader->AditionalNum = HTONS (DnsHeader->AditionalNum);
 | |
| 
 | |
|   Frag.Len = sizeof (*DnsHeader);
 | |
| 
 | |
|   //
 | |
|   // Fill Query name
 | |
|   //
 | |
|   CopyMem (Frag.Bulk + Frag.Len, QueryName, AsciiStrLen (QueryName));
 | |
|   Frag.Len = (UINT32) (Frag.Len + AsciiStrLen (QueryName));
 | |
|   *(Frag.Bulk + Frag.Len) = 0;
 | |
|   Frag.Len ++;
 | |
|   
 | |
|   //
 | |
|   // Rest query section
 | |
|   //
 | |
|   DnsQuery = (DNS_QUERY_SECTION *) (Frag.Bulk + Frag.Len);
 | |
| 
 | |
|   DnsQuery->Type = HTONS (Type);
 | |
|   DnsQuery->Class = HTONS (Class);
 | |
| 
 | |
|   Frag.Len += sizeof (*DnsQuery);
 | |
| 
 | |
|   //
 | |
|   // Wrap the Frag in a net buffer.
 | |
|   //
 | |
|   *Packet = NetbufFromExt (&Frag, 1, 0, 0, DnsDummyExtFree, NULL);
 | |
|   if (*Packet == NULL) {
 | |
|     FreePool (Frag.Bulk);
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Store the UdpIo in ProtoData.
 | |
|   //
 | |
|   *((UINTN *) &((*Packet)->ProtoData[0])) = (UINTN) (Instance->UdpIo);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Retransmit the packet.
 | |
| 
 | |
|   @param  Instance              The DNS instance
 | |
|   @param  Packet                Retransmit the packet 
 | |
| 
 | |
|   @retval EFI_SUCCESS           The packet is retransmitted.
 | |
|   @retval Others                Failed to retransmit.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| DnsRetransmit (
 | |
|   IN DNS_INSTANCE        *Instance,
 | |
|   IN NET_BUF             *Packet
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS      Status;
 | |
|   
 | |
|   UINT8           *Buffer;
 | |
| 
 | |
|   ASSERT (Packet != NULL);
 | |
| 
 | |
|   //
 | |
|   // Set the requests to the listening port, other packets to the connected port
 | |
|   //
 | |
|   Buffer = NetbufGetByte (Packet, 0, NULL);
 | |
|   ASSERT (Buffer != NULL);
 | |
| 
 | |
|   NET_GET_REF (Packet);
 | |
| 
 | |
|   Status = UdpIoSendDatagram (
 | |
|              Instance->UdpIo,
 | |
|              Packet,
 | |
|              NULL,
 | |
|              NULL,
 | |
|              DnsOnPacketSent,
 | |
|              Instance
 | |
|              );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     NET_PUT_REF (Packet);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   The timer ticking function for the DNS services.
 | |
| 
 | |
|   @param  Event                 The ticking event
 | |
|   @param  Context               The DNS service instance
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| DnsOnTimerRetransmit (
 | |
|   IN EFI_EVENT              Event,
 | |
|   IN VOID                   *Context
 | |
|   )
 | |
| {
 | |
|   DNS_SERVICE                *Service;
 | |
| 
 | |
|   LIST_ENTRY                 *Entry;
 | |
|   LIST_ENTRY                 *Next;
 | |
| 
 | |
|   DNS_INSTANCE               *Instance;
 | |
|   LIST_ENTRY                 *EntryNetMap;
 | |
|   NET_MAP_ITEM               *ItemNetMap;
 | |
|   DNS4_TOKEN_ENTRY           *Dns4TokenEntry;
 | |
|   DNS6_TOKEN_ENTRY           *Dns6TokenEntry;
 | |
| 
 | |
|   Dns4TokenEntry = NULL;
 | |
|   Dns6TokenEntry = NULL;
 | |
| 
 | |
|   Service = (DNS_SERVICE *) Context;
 | |
| 
 | |
| 
 | |
|   if (Service->IpVersion == IP_VERSION_4) {
 | |
|     //
 | |
|     // Iterate through all the children of the DNS service instance. Time
 | |
|     // out the packet. If maximum retries reached, clean the Token up.
 | |
|     //
 | |
|     NET_LIST_FOR_EACH_SAFE (Entry, Next, &Service->Dns4ChildrenList) {
 | |
|       Instance = NET_LIST_USER_STRUCT (Entry, DNS_INSTANCE, Link);
 | |
| 
 | |
|       EntryNetMap = Instance->Dns4TxTokens.Used.ForwardLink;
 | |
|       while (EntryNetMap != &Instance->Dns4TxTokens.Used) {
 | |
|         ItemNetMap = NET_LIST_USER_STRUCT (EntryNetMap, NET_MAP_ITEM, Link);
 | |
|         Dns4TokenEntry = (DNS4_TOKEN_ENTRY *)(ItemNetMap->Key);
 | |
|         if (Dns4TokenEntry->PacketToLive == 0 || (--Dns4TokenEntry->PacketToLive > 0)) {
 | |
|           EntryNetMap = EntryNetMap->ForwardLink;
 | |
|           continue;
 | |
|         }
 | |
| 
 | |
|         //
 | |
|         // Retransmit the packet if haven't reach the maxmium retry count,
 | |
|         // otherwise exit the transfer.
 | |
|         //
 | |
|         if (++Dns4TokenEntry->RetryCounting <= Dns4TokenEntry->Token->RetryCount) {
 | |
|           DnsRetransmit (Instance, (NET_BUF *)ItemNetMap->Value);
 | |
|           EntryNetMap = EntryNetMap->ForwardLink;
 | |
|         } else {
 | |
|           //
 | |
|           // Maximum retries reached, clean the Token up.
 | |
|           //
 | |
|           Dns4RemoveTokenEntry (&Instance->Dns4TxTokens, Dns4TokenEntry);
 | |
|           Dns4TokenEntry->Token->Status = EFI_TIMEOUT;
 | |
|           gBS->SignalEvent (Dns4TokenEntry->Token->Event);
 | |
|           DispatchDpc ();
 | |
|           
 | |
|           //
 | |
|           // Free the sending packet.
 | |
|           //
 | |
|           if (ItemNetMap->Value != NULL) {
 | |
|             NetbufFree ((NET_BUF *)(ItemNetMap->Value));
 | |
|           }
 | |
| 
 | |
|           EntryNetMap = Instance->Dns4TxTokens.Used.ForwardLink;
 | |
|         }
 | |
|       }
 | |
|     } 
 | |
|   }else {
 | |
|     //
 | |
|     // Iterate through all the children of the DNS service instance. Time
 | |
|     // out the packet. If maximum retries reached, clean the Token up.
 | |
|     //
 | |
|     NET_LIST_FOR_EACH_SAFE (Entry, Next, &Service->Dns6ChildrenList) {
 | |
|       Instance = NET_LIST_USER_STRUCT (Entry, DNS_INSTANCE, Link);
 | |
|       
 | |
|       EntryNetMap = Instance->Dns6TxTokens.Used.ForwardLink;
 | |
|       while (EntryNetMap != &Instance->Dns6TxTokens.Used) {
 | |
|         ItemNetMap = NET_LIST_USER_STRUCT (EntryNetMap, NET_MAP_ITEM, Link);
 | |
|         Dns6TokenEntry = (DNS6_TOKEN_ENTRY *) (ItemNetMap->Key);
 | |
|         if (Dns6TokenEntry->PacketToLive == 0 || (--Dns6TokenEntry->PacketToLive > 0)) {
 | |
|           EntryNetMap = EntryNetMap->ForwardLink;
 | |
|           continue;
 | |
|         }
 | |
| 
 | |
|         //
 | |
|         // Retransmit the packet if haven't reach the maxmium retry count,
 | |
|         // otherwise exit the transfer.
 | |
|         //
 | |
|         if (++Dns6TokenEntry->RetryCounting <= Dns6TokenEntry->Token->RetryCount) {
 | |
|           DnsRetransmit (Instance, (NET_BUF *) ItemNetMap->Value);
 | |
|           EntryNetMap = EntryNetMap->ForwardLink;
 | |
|         } else {
 | |
|           //
 | |
|           // Maximum retries reached, clean the Token up.
 | |
|           //
 | |
|           Dns6RemoveTokenEntry (&Instance->Dns6TxTokens, Dns6TokenEntry);
 | |
|           Dns6TokenEntry->Token->Status = EFI_TIMEOUT;
 | |
|           gBS->SignalEvent (Dns6TokenEntry->Token->Event);
 | |
|           DispatchDpc ();
 | |
|           
 | |
|           //
 | |
|           // Free the sending packet.
 | |
|           //
 | |
|           if (ItemNetMap->Value != NULL) {
 | |
|             NetbufFree ((NET_BUF *) (ItemNetMap->Value));
 | |
|           }
 | |
| 
 | |
|           EntryNetMap = Instance->Dns6TxTokens.Used.ForwardLink;
 | |
|         } 
 | |
|       }
 | |
|     }
 | |
|   } 
 | |
| }
 | |
| 
 | |
| /**
 | |
|   The timer ticking function for the DNS driver.
 | |
| 
 | |
|   @param  Event                 The ticking event
 | |
|   @param  Context               NULL
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| DnsOnTimerUpdate (
 | |
|   IN EFI_EVENT              Event,
 | |
|   IN VOID                   *Context
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY                 *Entry;
 | |
|   LIST_ENTRY                 *Next;
 | |
|   DNS4_CACHE                 *Item4;
 | |
|   DNS6_CACHE                 *Item6;
 | |
| 
 | |
|   Item4 = NULL;
 | |
|   Item6 = NULL;
 | |
| 
 | |
|   //
 | |
|   // Iterate through all the DNS4 cache list.
 | |
|   //
 | |
|   NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns4CacheList) {
 | |
|     Item4 = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink);
 | |
|     Item4->DnsCache.Timeout--;
 | |
|   }
 | |
|   
 | |
|   Entry = mDriverData->Dns4CacheList.ForwardLink;
 | |
|   while (Entry != &mDriverData->Dns4CacheList) {
 | |
|     Item4 = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink);
 | |
|     if (Item4->DnsCache.Timeout == 0) {
 | |
|       RemoveEntryList (&Item4->AllCacheLink);
 | |
|       FreePool (Item4->DnsCache.HostName);
 | |
|       FreePool (Item4->DnsCache.IpAddress);
 | |
|       FreePool (Item4);
 | |
|       Entry = mDriverData->Dns4CacheList.ForwardLink;
 | |
|     } else {
 | |
|       Entry = Entry->ForwardLink;
 | |
|     }
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Iterate through all the DNS6 cache list.
 | |
|   //
 | |
|   NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns6CacheList) {
 | |
|     Item6 = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink);
 | |
|     Item6->DnsCache.Timeout--;
 | |
|   }
 | |
|   
 | |
|   Entry = mDriverData->Dns6CacheList.ForwardLink;
 | |
|   while (Entry != &mDriverData->Dns6CacheList) {
 | |
|     Item6 = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink);
 | |
|     if (Item6->DnsCache.Timeout == 0) {
 | |
|       RemoveEntryList (&Item6->AllCacheLink);
 | |
|       FreePool (Item6->DnsCache.HostName);
 | |
|       FreePool (Item6->DnsCache.IpAddress);
 | |
|       FreePool (Item6);
 | |
|       Entry = mDriverData->Dns6CacheList.ForwardLink;
 | |
|     } else {
 | |
|       Entry = Entry->ForwardLink;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 |