Home | History | Annotate | Download | only in DnsDxe
      1 /** @file
      2 DnsDxe support functions implementation.
      3 
      4 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "DnsImpl.h"
     16 
     17 /**
     18   Remove TokenEntry from TokenMap.
     19 
     20   @param[in] TokenMap          All DNSv4 Token entrys.
     21   @param[in] TokenEntry        TokenEntry need to be removed.
     22 
     23   @retval EFI_SUCCESS          Remove TokenEntry from TokenMap sucessfully.
     24   @retval EFI_NOT_FOUND        TokenEntry is not found in TokenMap.
     25 
     26 **/
     27 EFI_STATUS
     28 Dns4RemoveTokenEntry (
     29   IN NET_MAP                    *TokenMap,
     30   IN DNS4_TOKEN_ENTRY           *TokenEntry
     31   )
     32 {
     33   NET_MAP_ITEM  *Item;
     34 
     35   //
     36   // Find the TokenEntry first.
     37   //
     38   Item = NetMapFindKey (TokenMap, (VOID *) TokenEntry);
     39 
     40   if (Item != NULL) {
     41     //
     42     // Remove the TokenEntry if it's found in the map.
     43     //
     44     NetMapRemoveItem (TokenMap, Item, NULL);
     45 
     46     return EFI_SUCCESS;
     47   }
     48 
     49   return EFI_NOT_FOUND;
     50 }
     51 
     52 /**
     53   Remove TokenEntry from TokenMap.
     54 
     55   @param[in] TokenMap           All DNSv6 Token entrys.
     56   @param[in] TokenEntry         TokenEntry need to be removed.
     57 
     58   @retval EFI_SUCCESS           Remove TokenEntry from TokenMap sucessfully.
     59   @retval EFI_NOT_FOUND         TokenEntry is not found in TokenMap.
     60 
     61 **/
     62 EFI_STATUS
     63 Dns6RemoveTokenEntry (
     64   IN NET_MAP                    *TokenMap,
     65   IN DNS6_TOKEN_ENTRY           *TokenEntry
     66   )
     67 {
     68   NET_MAP_ITEM  *Item;
     69 
     70   //
     71   // Find the TokenEntry first.
     72   //
     73   Item = NetMapFindKey (TokenMap, (VOID *) TokenEntry);
     74 
     75   if (Item != NULL) {
     76     //
     77     // Remove the TokenEntry if it's found in the map.
     78     //
     79     NetMapRemoveItem (TokenMap, Item, NULL);
     80 
     81     return EFI_SUCCESS;
     82   }
     83 
     84   return EFI_NOT_FOUND;
     85 }
     86 
     87 /**
     88   This function cancle the token specified by Arg in the Map.
     89 
     90   @param[in]  Map             Pointer to the NET_MAP.
     91   @param[in]  Item            Pointer to the NET_MAP_ITEM.
     92   @param[in]  Arg             Pointer to the token to be cancelled. If NULL, all
     93                               the tokens in this Map will be cancelled.
     94                               This parameter is optional and may be NULL.
     95 
     96   @retval EFI_SUCCESS         The token is cancelled if Arg is NULL, or the token
     97                               is not the same as that in the Item, if Arg is not
     98                               NULL.
     99   @retval EFI_ABORTED         Arg is not NULL, and the token specified by Arg is
    100                               cancelled.
    101 
    102 **/
    103 EFI_STATUS
    104 EFIAPI
    105 Dns4CancelTokens (
    106   IN NET_MAP       *Map,
    107   IN NET_MAP_ITEM  *Item,
    108   IN VOID          *Arg OPTIONAL
    109   )
    110 {
    111   DNS4_TOKEN_ENTRY           *TokenEntry;
    112   NET_BUF                    *Packet;
    113   UDP_IO                     *UdpIo;
    114 
    115   if ((Arg != NULL) && (Item->Key != Arg)) {
    116     return EFI_SUCCESS;
    117   }
    118 
    119   if (Item->Value != NULL) {
    120     //
    121     // If the TokenEntry is a transmit TokenEntry, the corresponding Packet is recorded in
    122     // Item->Value.
    123     //
    124     Packet  = (NET_BUF *) (Item->Value);
    125     UdpIo = (UDP_IO *) (*((UINTN *) &Packet->ProtoData[0]));
    126 
    127     UdpIoCancelSentDatagram (UdpIo, Packet);
    128   }
    129 
    130   //
    131   // Remove TokenEntry from Dns4TxTokens.
    132   //
    133   TokenEntry = (DNS4_TOKEN_ENTRY *) Item->Key;
    134   if (Dns4RemoveTokenEntry (Map, TokenEntry) == EFI_SUCCESS) {
    135     TokenEntry->Token->Status = EFI_ABORTED;
    136     gBS->SignalEvent (TokenEntry->Token->Event);
    137     DispatchDpc ();
    138   }
    139 
    140   if (Arg != NULL) {
    141     return EFI_ABORTED;
    142   }
    143 
    144   return EFI_SUCCESS;
    145 }
    146 
    147 /**
    148   This function cancle the token specified by Arg in the Map.
    149 
    150   @param[in]  Map             Pointer to the NET_MAP.
    151   @param[in]  Item            Pointer to the NET_MAP_ITEM.
    152   @param[in]  Arg             Pointer to the token to be cancelled. If NULL, all
    153                               the tokens in this Map will be cancelled.
    154                               This parameter is optional and may be NULL.
    155 
    156   @retval EFI_SUCCESS         The token is cancelled if Arg is NULL, or the token
    157                               is not the same as that in the Item, if Arg is not
    158                               NULL.
    159   @retval EFI_ABORTED         Arg is not NULL, and the token specified by Arg is
    160                               cancelled.
    161 
    162 **/
    163 EFI_STATUS
    164 EFIAPI
    165 Dns6CancelTokens (
    166   IN NET_MAP       *Map,
    167   IN NET_MAP_ITEM  *Item,
    168   IN VOID          *Arg OPTIONAL
    169   )
    170 {
    171   DNS6_TOKEN_ENTRY           *TokenEntry;
    172   NET_BUF                    *Packet;
    173   UDP_IO                     *UdpIo;
    174 
    175   if ((Arg != NULL) && (Item->Key != Arg)) {
    176     return EFI_SUCCESS;
    177   }
    178 
    179   if (Item->Value != NULL) {
    180     //
    181     // If the TokenEntry is a transmit TokenEntry, the corresponding Packet is recorded in
    182     // Item->Value.
    183     //
    184     Packet  = (NET_BUF *) (Item->Value);
    185     UdpIo = (UDP_IO *) (*((UINTN *) &Packet->ProtoData[0]));
    186 
    187     UdpIoCancelSentDatagram (UdpIo, Packet);
    188   }
    189 
    190   //
    191   // Remove TokenEntry from Dns6TxTokens.
    192   //
    193   TokenEntry = (DNS6_TOKEN_ENTRY *) Item->Key;
    194   if (Dns6RemoveTokenEntry (Map, TokenEntry) == EFI_SUCCESS) {
    195     TokenEntry->Token->Status = EFI_ABORTED;
    196     gBS->SignalEvent (TokenEntry->Token->Event);
    197     DispatchDpc ();
    198   }
    199 
    200   if (Arg != NULL) {
    201     return EFI_ABORTED;
    202   }
    203 
    204   return EFI_SUCCESS;
    205 }
    206 
    207 /**
    208   Get the TokenEntry from the TokensMap.
    209 
    210   @param[in]  TokensMap           All DNSv4 Token entrys
    211   @param[in]  Token               Pointer to the token to be get.
    212   @param[out] TokenEntry          Pointer to TokenEntry corresponding Token.
    213 
    214   @retval EFI_SUCCESS             Get the TokenEntry from the TokensMap sucessfully.
    215   @retval EFI_NOT_FOUND           TokenEntry is not found in TokenMap.
    216 
    217 **/
    218 EFI_STATUS
    219 EFIAPI
    220 GetDns4TokenEntry (
    221   IN     NET_MAP                   *TokensMap,
    222   IN     EFI_DNS4_COMPLETION_TOKEN *Token,
    223      OUT DNS4_TOKEN_ENTRY          **TokenEntry
    224   )
    225 {
    226   LIST_ENTRY              *Entry;
    227 
    228   NET_MAP_ITEM            *Item;
    229 
    230   NET_LIST_FOR_EACH (Entry, &TokensMap->Used) {
    231     Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
    232     *TokenEntry = (DNS4_TOKEN_ENTRY *) (Item->Key);
    233     if ((*TokenEntry)->Token == Token) {
    234       return EFI_SUCCESS;
    235     }
    236   }
    237 
    238   *TokenEntry = NULL;
    239 
    240   return EFI_NOT_FOUND;
    241 }
    242 
    243 /**
    244   Get the TokenEntry from the TokensMap.
    245 
    246   @param[in]  TokensMap           All DNSv6 Token entrys
    247   @param[in]  Token               Pointer to the token to be get.
    248   @param[out] TokenEntry          Pointer to TokenEntry corresponding Token.
    249 
    250   @retval EFI_SUCCESS             Get the TokenEntry from the TokensMap sucessfully.
    251   @retval EFI_NOT_FOUND           TokenEntry is not found in TokenMap.
    252 
    253 **/
    254 EFI_STATUS
    255 EFIAPI
    256 GetDns6TokenEntry (
    257   IN     NET_MAP                   *TokensMap,
    258   IN     EFI_DNS6_COMPLETION_TOKEN *Token,
    259      OUT DNS6_TOKEN_ENTRY          **TokenEntry
    260   )
    261 {
    262   LIST_ENTRY              *Entry;
    263 
    264   NET_MAP_ITEM            *Item;
    265 
    266   NET_LIST_FOR_EACH (Entry, &TokensMap->Used) {
    267     Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
    268     *TokenEntry = (DNS6_TOKEN_ENTRY *) (Item->Key);
    269     if ((*TokenEntry)->Token == Token) {
    270       return EFI_SUCCESS;
    271     }
    272   }
    273 
    274   *TokenEntry =NULL;
    275 
    276   return EFI_NOT_FOUND;
    277 }
    278 
    279 /**
    280   Cancel DNS4 tokens from the DNS4 instance.
    281 
    282   @param[in]  Instance           Pointer to the DNS instance context data.
    283   @param[in]  Token              Pointer to the token to be canceled. If NULL, all
    284                                  tokens in this instance will be cancelled.
    285                                  This parameter is optional and may be NULL.
    286 
    287   @retval EFI_SUCCESS            The Token is cancelled.
    288   @retval EFI_NOT_FOUND          The Token is not found.
    289 
    290 **/
    291 EFI_STATUS
    292 Dns4InstanceCancelToken (
    293   IN DNS_INSTANCE               *Instance,
    294   IN EFI_DNS4_COMPLETION_TOKEN  *Token
    295   )
    296 {
    297   EFI_STATUS        Status;
    298   DNS4_TOKEN_ENTRY  *TokenEntry;
    299 
    300   TokenEntry = NULL;
    301 
    302   if(Token != NULL  ) {
    303     Status = GetDns4TokenEntry (&Instance->Dns4TxTokens, Token, &TokenEntry);
    304     if (EFI_ERROR (Status)) {
    305       return Status;
    306     }
    307   } else {
    308     TokenEntry = NULL;
    309   }
    310 
    311   //
    312   // Cancel this TokenEntry from the Dns4TxTokens map.
    313   //
    314   Status = NetMapIterate (&Instance->Dns4TxTokens, Dns4CancelTokens, TokenEntry);
    315 
    316   if ((TokenEntry != NULL) && (Status == EFI_ABORTED)) {
    317     //
    318     // If Token isn't NULL and Status is EFI_ABORTED, the token is cancelled from
    319     // the Dns4TxTokens and returns success.
    320     //
    321     if (NetMapIsEmpty (&Instance->Dns4TxTokens)) {
    322        Instance->UdpIo->Protocol.Udp4->Cancel (Instance->UdpIo->Protocol.Udp4, &Instance->UdpIo->RecvRequest->Token.Udp4);
    323     }
    324     return EFI_SUCCESS;
    325   }
    326 
    327   ASSERT ((TokenEntry != NULL) || (0 == NetMapGetCount (&Instance->Dns4TxTokens)));
    328 
    329   if (NetMapIsEmpty (&Instance->Dns4TxTokens)) {
    330     Instance->UdpIo->Protocol.Udp4->Cancel (Instance->UdpIo->Protocol.Udp4, &Instance->UdpIo->RecvRequest->Token.Udp4);
    331   }
    332 
    333   return EFI_SUCCESS;
    334 }
    335 
    336 /**
    337   Cancel DNS6 tokens from the DNS6 instance.
    338 
    339   @param[in]  Instance           Pointer to the DNS instance context data.
    340   @param[in]  Token              Pointer to the token to be canceled. If NULL, all
    341                                  tokens in this instance will be cancelled.
    342                                  This parameter is optional and may be NULL.
    343 
    344   @retval EFI_SUCCESS            The Token is cancelled.
    345   @retval EFI_NOT_FOUND          The Token is not found.
    346 
    347 **/
    348 EFI_STATUS
    349 Dns6InstanceCancelToken (
    350   IN DNS_INSTANCE               *Instance,
    351   IN EFI_DNS6_COMPLETION_TOKEN  *Token
    352   )
    353 {
    354   EFI_STATUS        Status;
    355   DNS6_TOKEN_ENTRY  *TokenEntry;
    356 
    357   TokenEntry = NULL;
    358 
    359   if(Token != NULL  ) {
    360     Status = GetDns6TokenEntry (&Instance->Dns6TxTokens, Token, &TokenEntry);
    361     if (EFI_ERROR (Status)) {
    362       return Status;
    363     }
    364   } else {
    365     TokenEntry = NULL;
    366   }
    367 
    368   //
    369   // Cancel this TokenEntry from the Dns6TxTokens map.
    370   //
    371   Status = NetMapIterate (&Instance->Dns6TxTokens, Dns6CancelTokens, TokenEntry);
    372 
    373   if ((TokenEntry != NULL) && (Status == EFI_ABORTED)) {
    374     //
    375     // If Token isn't NULL and Status is EFI_ABORTED, the token is cancelled from
    376     // the Dns6TxTokens and returns success.
    377     //
    378     if (NetMapIsEmpty (&Instance->Dns6TxTokens)) {
    379        Instance->UdpIo->Protocol.Udp6->Cancel (Instance->UdpIo->Protocol.Udp6, &Instance->UdpIo->RecvRequest->Token.Udp6);
    380     }
    381     return EFI_SUCCESS;
    382   }
    383 
    384   ASSERT ((TokenEntry != NULL) || (0 == NetMapGetCount (&Instance->Dns6TxTokens)));
    385 
    386   if (NetMapIsEmpty (&Instance->Dns6TxTokens)) {
    387     Instance->UdpIo->Protocol.Udp6->Cancel (Instance->UdpIo->Protocol.Udp6, &Instance->UdpIo->RecvRequest->Token.Udp6);
    388   }
    389 
    390   return EFI_SUCCESS;
    391 }
    392 
    393 /**
    394   Free the resource related to the configure parameters.
    395 
    396   @param  Config                 The DNS configure data
    397 
    398 **/
    399 VOID
    400 Dns4CleanConfigure (
    401   IN OUT EFI_DNS4_CONFIG_DATA  *Config
    402   )
    403 {
    404   if (Config->DnsServerList != NULL) {
    405     FreePool (Config->DnsServerList);
    406   }
    407 
    408   ZeroMem (Config, sizeof (EFI_DNS4_CONFIG_DATA));
    409 }
    410 
    411 /**
    412   Free the resource related to the configure parameters.
    413 
    414   @param  Config                 The DNS configure data
    415 
    416 **/
    417 VOID
    418 Dns6CleanConfigure (
    419   IN OUT EFI_DNS6_CONFIG_DATA  *Config
    420   )
    421 {
    422   if (Config->DnsServerList != NULL) {
    423     FreePool (Config->DnsServerList);
    424   }
    425 
    426   ZeroMem (Config, sizeof (EFI_DNS6_CONFIG_DATA));
    427 }
    428 
    429 /**
    430   Allocate memory for configure parameter such as timeout value for Dst,
    431   then copy the configure parameter from Src to Dst.
    432 
    433   @param[out]  Dst               The destination DHCP configure data.
    434   @param[in]   Src               The source DHCP configure data.
    435 
    436   @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory.
    437   @retval EFI_SUCCESS            The configure is copied.
    438 
    439 **/
    440 EFI_STATUS
    441 Dns4CopyConfigure (
    442   OUT EFI_DNS4_CONFIG_DATA  *Dst,
    443   IN  EFI_DNS4_CONFIG_DATA  *Src
    444   )
    445 {
    446   UINTN                     Len;
    447   UINT32                    Index;
    448 
    449   CopyMem (Dst, Src, sizeof (*Dst));
    450   Dst->DnsServerList = NULL;
    451 
    452   //
    453   // Allocate a memory then copy DnsServerList to it
    454   //
    455   if (Src->DnsServerList != NULL) {
    456     Len                = Src->DnsServerListCount * sizeof (EFI_IPv4_ADDRESS);
    457     Dst->DnsServerList = AllocatePool (Len);
    458     if (Dst->DnsServerList == NULL) {
    459       Dns4CleanConfigure (Dst);
    460       return EFI_OUT_OF_RESOURCES;
    461     }
    462 
    463     for (Index = 0; Index < Src->DnsServerListCount; Index++) {
    464       CopyMem (&Dst->DnsServerList[Index], &Src->DnsServerList[Index], sizeof (EFI_IPv4_ADDRESS));
    465     }
    466   }
    467 
    468   return EFI_SUCCESS;
    469 }
    470 
    471 /**
    472   Allocate memory for configure parameter such as timeout value for Dst,
    473   then copy the configure parameter from Src to Dst.
    474 
    475   @param[out]  Dst               The destination DHCP configure data.
    476   @param[in]   Src               The source DHCP configure data.
    477 
    478   @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory.
    479   @retval EFI_SUCCESS            The configure is copied.
    480 
    481 **/
    482 EFI_STATUS
    483 Dns6CopyConfigure (
    484   OUT EFI_DNS6_CONFIG_DATA  *Dst,
    485   IN  EFI_DNS6_CONFIG_DATA  *Src
    486   )
    487 {
    488   UINTN                     Len;
    489   UINT32                    Index;
    490 
    491   CopyMem (Dst, Src, sizeof (*Dst));
    492   Dst->DnsServerList = NULL;
    493 
    494   //
    495   // Allocate a memory then copy DnsServerList to it
    496   //
    497   if (Src->DnsServerList != NULL) {
    498     Len                = Src->DnsServerCount * sizeof (EFI_IPv6_ADDRESS);
    499     Dst->DnsServerList = AllocatePool (Len);
    500     if (Dst->DnsServerList == NULL) {
    501       Dns6CleanConfigure (Dst);
    502       return EFI_OUT_OF_RESOURCES;
    503     }
    504 
    505     for (Index = 0; Index < Src->DnsServerCount; Index++) {
    506       CopyMem (&Dst->DnsServerList[Index], &Src->DnsServerList[Index], sizeof (EFI_IPv6_ADDRESS));
    507     }
    508   }
    509 
    510   return EFI_SUCCESS;
    511 }
    512 
    513 /**
    514   Callback of Dns packet. Does nothing.
    515 
    516   @param Arg           The context.
    517 
    518 **/
    519 VOID
    520 EFIAPI
    521 DnsDummyExtFree (
    522   IN VOID                   *Arg
    523   )
    524 {
    525 }
    526 
    527 /**
    528   Poll the UDP to get the IP4 default address, which may be retrieved
    529   by DHCP.
    530 
    531   The default time out value is 5 seconds. If IP has retrieved the default address,
    532   the UDP is reconfigured.
    533 
    534   @param  Instance               The DNS instance
    535   @param  UdpIo                  The UDP_IO to poll
    536   @param  UdpCfgData             The UDP configure data to reconfigure the UDP_IO
    537 
    538   @retval TRUE                   The default address is retrieved and UDP is reconfigured.
    539   @retval FALSE                  Some error occured.
    540 
    541 **/
    542 BOOLEAN
    543 Dns4GetMapping (
    544   IN DNS_INSTANCE           *Instance,
    545   IN UDP_IO                 *UdpIo,
    546   IN EFI_UDP4_CONFIG_DATA   *UdpCfgData
    547   )
    548 {
    549   DNS_SERVICE               *Service;
    550   EFI_IP4_MODE_DATA         Ip4Mode;
    551   EFI_UDP4_PROTOCOL         *Udp;
    552   EFI_STATUS                Status;
    553 
    554   ASSERT (Instance->Dns4CfgData.UseDefaultSetting);
    555 
    556   Service = Instance->Service;
    557   Udp     = UdpIo->Protocol.Udp4;
    558 
    559   Status = gBS->SetTimer (
    560                   Service->TimerToGetMap,
    561                   TimerRelative,
    562                   DNS_TIME_TO_GETMAP * TICKS_PER_SECOND
    563                   );
    564   if (EFI_ERROR (Status)) {
    565     return FALSE;
    566   }
    567 
    568   while (EFI_ERROR (gBS->CheckEvent (Service->TimerToGetMap))) {
    569     Udp->Poll (Udp);
    570 
    571     if (!EFI_ERROR (Udp->GetModeData (Udp, NULL, &Ip4Mode, NULL, NULL)) &&
    572         Ip4Mode.IsConfigured) {
    573 
    574       Udp->Configure (Udp, NULL);
    575       return (BOOLEAN) (Udp->Configure (Udp, UdpCfgData) == EFI_SUCCESS);
    576     }
    577   }
    578 
    579   return FALSE;
    580 }
    581 
    582 /**
    583   Configure the opened Udp6 instance until the corresponding Ip6 instance
    584   has been configured.
    585 
    586   @param  Instance               The DNS instance
    587   @param  UdpIo                  The UDP_IO to poll
    588   @param  UdpCfgData             The UDP configure data to reconfigure the UDP_IO
    589 
    590   @retval TRUE                   Configure the Udp6 instance successfully.
    591   @retval FALSE                  Some error occured.
    592 
    593 **/
    594 BOOLEAN
    595 Dns6GetMapping (
    596   IN DNS_INSTANCE           *Instance,
    597   IN UDP_IO                 *UdpIo,
    598   IN EFI_UDP6_CONFIG_DATA   *UdpCfgData
    599   )
    600 {
    601   DNS_SERVICE               *Service;
    602   EFI_IP6_MODE_DATA         Ip6Mode;
    603   EFI_UDP6_PROTOCOL         *Udp;
    604   EFI_STATUS                Status;
    605 
    606   Service = Instance->Service;
    607   Udp     = UdpIo->Protocol.Udp6;
    608 
    609   Status = gBS->SetTimer (
    610                   Service->TimerToGetMap,
    611                   TimerRelative,
    612                   DNS_TIME_TO_GETMAP * TICKS_PER_SECOND
    613                   );
    614   if (EFI_ERROR (Status)) {
    615     return FALSE;
    616   }
    617 
    618   while (EFI_ERROR (gBS->CheckEvent (Service->TimerToGetMap))) {
    619     Udp->Poll (Udp);
    620 
    621     if (!EFI_ERROR (Udp->GetModeData (Udp, NULL, &Ip6Mode, NULL, NULL))) {
    622       if (Ip6Mode.AddressList != NULL) {
    623         FreePool (Ip6Mode.AddressList);
    624       }
    625 
    626       if (Ip6Mode.GroupTable != NULL) {
    627         FreePool (Ip6Mode.GroupTable);
    628       }
    629 
    630       if (Ip6Mode.RouteTable != NULL) {
    631         FreePool (Ip6Mode.RouteTable);
    632       }
    633 
    634       if (Ip6Mode.NeighborCache != NULL) {
    635         FreePool (Ip6Mode.NeighborCache);
    636       }
    637 
    638       if (Ip6Mode.PrefixTable != NULL) {
    639         FreePool (Ip6Mode.PrefixTable);
    640       }
    641 
    642       if (Ip6Mode.IcmpTypeList != NULL) {
    643         FreePool (Ip6Mode.IcmpTypeList);
    644       }
    645 
    646       if (Ip6Mode.IsConfigured) {
    647         Udp->Configure (Udp, NULL);
    648         return (BOOLEAN) (Udp->Configure (Udp, UdpCfgData) == EFI_SUCCESS);
    649       }
    650     }
    651   }
    652 
    653   return FALSE;
    654 }
    655 
    656 /**
    657   Configure the UDP.
    658 
    659   @param  Instance               The DNS session
    660   @param  UdpIo                  The UDP_IO instance
    661 
    662   @retval EFI_SUCCESS            The UDP is successfully configured for the
    663                                  session.
    664 
    665 **/
    666 EFI_STATUS
    667 Dns4ConfigUdp (
    668   IN DNS_INSTANCE           *Instance,
    669   IN UDP_IO                 *UdpIo
    670   )
    671 {
    672   EFI_DNS4_CONFIG_DATA      *Config;
    673   EFI_UDP4_CONFIG_DATA      UdpConfig;
    674   EFI_STATUS                Status;
    675 
    676   Config = &Instance->Dns4CfgData;
    677 
    678   UdpConfig.AcceptBroadcast    = FALSE;
    679   UdpConfig.AcceptPromiscuous  = FALSE;
    680   UdpConfig.AcceptAnyPort      = FALSE;
    681   UdpConfig.AllowDuplicatePort = FALSE;
    682   UdpConfig.TypeOfService      = 0;
    683   UdpConfig.TimeToLive         = 128;
    684   UdpConfig.DoNotFragment      = FALSE;
    685   UdpConfig.ReceiveTimeout     = 0;
    686   UdpConfig.TransmitTimeout    = 0;
    687   UdpConfig.UseDefaultAddress  = Config->UseDefaultSetting;
    688   UdpConfig.SubnetMask         = Config->SubnetMask;
    689   UdpConfig.StationPort        = Config->LocalPort;
    690   UdpConfig.RemotePort         = DNS_SERVER_PORT;
    691 
    692   CopyMem (&UdpConfig.StationAddress, &Config->StationIp, sizeof (EFI_IPv4_ADDRESS));
    693   CopyMem (&UdpConfig.RemoteAddress, &Instance->SessionDnsServer.v4, sizeof (EFI_IPv4_ADDRESS));
    694 
    695   Status = UdpIo->Protocol.Udp4->Configure (UdpIo->Protocol.Udp4, &UdpConfig);
    696 
    697   if ((Status == EFI_NO_MAPPING) && Dns4GetMapping (Instance, UdpIo, &UdpConfig)) {
    698     return EFI_SUCCESS;
    699   }
    700 
    701   return Status;
    702 }
    703 
    704 /**
    705   Configure the UDP.
    706 
    707   @param  Instance               The DNS session
    708   @param  UdpIo                  The UDP_IO instance
    709 
    710   @retval EFI_SUCCESS            The UDP is successfully configured for the
    711                                  session.
    712 
    713 **/
    714 EFI_STATUS
    715 Dns6ConfigUdp (
    716   IN DNS_INSTANCE           *Instance,
    717   IN UDP_IO                 *UdpIo
    718   )
    719 {
    720   EFI_DNS6_CONFIG_DATA      *Config;
    721   EFI_UDP6_CONFIG_DATA      UdpConfig;
    722   EFI_STATUS                Status;
    723 
    724   Config = &Instance->Dns6CfgData;
    725 
    726   UdpConfig.AcceptPromiscuous  = FALSE;
    727   UdpConfig.AcceptAnyPort      = FALSE;
    728   UdpConfig.AllowDuplicatePort = FALSE;
    729   UdpConfig.TrafficClass       = 0;
    730   UdpConfig.HopLimit           = 128;
    731   UdpConfig.ReceiveTimeout     = 0;
    732   UdpConfig.TransmitTimeout    = 0;
    733   UdpConfig.StationPort        = Config->LocalPort;
    734   UdpConfig.RemotePort         = DNS_SERVER_PORT;
    735   CopyMem (&UdpConfig.StationAddress, &Config->StationIp, sizeof (EFI_IPv6_ADDRESS));
    736   CopyMem (&UdpConfig.RemoteAddress, &Instance->SessionDnsServer.v6, sizeof (EFI_IPv6_ADDRESS));
    737 
    738   Status = UdpIo->Protocol.Udp6->Configure (UdpIo->Protocol.Udp6, &UdpConfig);
    739 
    740   if ((Status == EFI_NO_MAPPING) && Dns6GetMapping (Instance, UdpIo, &UdpConfig)) {
    741     return EFI_SUCCESS;
    742   }
    743 
    744   return Status;
    745 }
    746 
    747 /**
    748   Update Dns4 cache to shared list of caches of all DNSv4 instances.
    749 
    750   @param  Dns4CacheList      All Dns4 cache list.
    751   @param  DeleteFlag         If FALSE, this function is to add one entry to the DNS Cache.
    752                              If TRUE, this function will delete matching DNS Cache entry.
    753   @param  Override           If TRUE, the matching DNS cache entry will be overwritten with the supplied parameter.
    754                              If FALSE, EFI_ACCESS_DENIED will be returned if the entry to be added is already exists.
    755   @param  DnsCacheEntry      Entry Pointer to DNS Cache entry.
    756 
    757   @retval EFI_SUCCESS        Update Dns4 cache successfully.
    758   @retval Others             Failed to update Dns4 cache.
    759 
    760 **/
    761 EFI_STATUS
    762 EFIAPI
    763 UpdateDns4Cache (
    764   IN LIST_ENTRY             *Dns4CacheList,
    765   IN BOOLEAN                DeleteFlag,
    766   IN BOOLEAN                Override,
    767   IN EFI_DNS4_CACHE_ENTRY   DnsCacheEntry
    768   )
    769 {
    770   DNS4_CACHE    *NewDnsCache;
    771   DNS4_CACHE    *Item;
    772   LIST_ENTRY    *Entry;
    773   LIST_ENTRY    *Next;
    774 
    775   NewDnsCache = NULL;
    776   Item        = NULL;
    777 
    778   //
    779   // Search the database for the matching EFI_DNS_CACHE_ENTRY
    780   //
    781   NET_LIST_FOR_EACH_SAFE (Entry, Next, Dns4CacheList) {
    782     Item = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink);
    783     if (StrCmp (DnsCacheEntry.HostName, Item->DnsCache.HostName) == 0 && \
    784         CompareMem (DnsCacheEntry.IpAddress, Item->DnsCache.IpAddress, sizeof (EFI_IPv4_ADDRESS)) == 0) {
    785       //
    786       // This is the Dns cache entry
    787       //
    788       if (DeleteFlag) {
    789         //
    790         // Delete matching DNS Cache entry
    791         //
    792         RemoveEntryList (&Item->AllCacheLink);
    793 
    794         return EFI_SUCCESS;
    795       } else if (Override) {
    796         //
    797         // Update this one
    798         //
    799         Item->DnsCache.Timeout = DnsCacheEntry.Timeout;
    800 
    801         return EFI_SUCCESS;
    802       }else {
    803         return EFI_ACCESS_DENIED;
    804       }
    805     }
    806   }
    807 
    808   //
    809   // Add new one
    810   //
    811   NewDnsCache = AllocatePool (sizeof (DNS4_CACHE));
    812   if (NewDnsCache == NULL) {
    813     return EFI_OUT_OF_RESOURCES;
    814   }
    815 
    816   InitializeListHead (&NewDnsCache->AllCacheLink);
    817 
    818   NewDnsCache->DnsCache.HostName = AllocatePool (StrSize (DnsCacheEntry.HostName));
    819   if (NewDnsCache->DnsCache.HostName == NULL) {
    820     return EFI_OUT_OF_RESOURCES;
    821   }
    822 
    823   CopyMem (NewDnsCache->DnsCache.HostName, DnsCacheEntry.HostName, StrSize (DnsCacheEntry.HostName));
    824 
    825   NewDnsCache->DnsCache.IpAddress = AllocatePool (sizeof (EFI_IPv4_ADDRESS));
    826   if (NewDnsCache->DnsCache.IpAddress == NULL) {
    827     return EFI_OUT_OF_RESOURCES;
    828   }
    829 
    830   CopyMem (NewDnsCache->DnsCache.IpAddress, DnsCacheEntry.IpAddress, sizeof (EFI_IPv4_ADDRESS));
    831 
    832   NewDnsCache->DnsCache.Timeout = DnsCacheEntry.Timeout;
    833 
    834   InsertTailList (Dns4CacheList, &NewDnsCache->AllCacheLink);
    835 
    836   return EFI_SUCCESS;
    837 }
    838 
    839 /**
    840   Update Dns6 cache to shared list of caches of all DNSv6 instances.
    841 
    842   @param  Dns6CacheList      All Dns6 cache list.
    843   @param  DeleteFlag         If FALSE, this function is to add one entry to the DNS Cache.
    844                              If TRUE, this function will delete matching DNS Cache entry.
    845   @param  Override           If TRUE, the matching DNS cache entry will be overwritten with the supplied parameter.
    846                              If FALSE, EFI_ACCESS_DENIED will be returned if the entry to be added is already exists.
    847   @param  DnsCacheEntry      Entry Pointer to DNS Cache entry.
    848 
    849   @retval EFI_SUCCESS        Update Dns6 cache successfully.
    850   @retval Others             Failed to update Dns6 cache.
    851 **/
    852 EFI_STATUS
    853 EFIAPI
    854 UpdateDns6Cache (
    855   IN LIST_ENTRY             *Dns6CacheList,
    856   IN BOOLEAN                DeleteFlag,
    857   IN BOOLEAN                Override,
    858   IN EFI_DNS6_CACHE_ENTRY   DnsCacheEntry
    859   )
    860 {
    861   DNS6_CACHE    *NewDnsCache;
    862   DNS6_CACHE    *Item;
    863   LIST_ENTRY    *Entry;
    864   LIST_ENTRY    *Next;
    865 
    866   NewDnsCache = NULL;
    867   Item        = NULL;
    868 
    869   //
    870   // Search the database for the matching EFI_DNS_CACHE_ENTRY
    871   //
    872   NET_LIST_FOR_EACH_SAFE (Entry, Next, Dns6CacheList) {
    873     Item = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink);
    874     if (StrCmp (DnsCacheEntry.HostName, Item->DnsCache.HostName) == 0 && \
    875         CompareMem (DnsCacheEntry.IpAddress, Item->DnsCache.IpAddress, sizeof (EFI_IPv6_ADDRESS)) == 0) {
    876       //
    877       // This is the Dns cache entry
    878       //
    879       if (DeleteFlag) {
    880         //
    881         // Delete matching DNS Cache entry
    882         //
    883         RemoveEntryList (&Item->AllCacheLink);
    884 
    885         return EFI_SUCCESS;
    886       } else if (Override) {
    887         //
    888         // Update this one
    889         //
    890         Item->DnsCache.Timeout = DnsCacheEntry.Timeout;
    891 
    892         return EFI_SUCCESS;
    893       }else {
    894         return EFI_ACCESS_DENIED;
    895       }
    896     }
    897   }
    898 
    899   //
    900   // Add new one
    901   //
    902   NewDnsCache = AllocatePool (sizeof (DNS6_CACHE));
    903   if (NewDnsCache == NULL) {
    904     return EFI_OUT_OF_RESOURCES;
    905   }
    906 
    907   InitializeListHead (&NewDnsCache->AllCacheLink);
    908 
    909   NewDnsCache->DnsCache.HostName = AllocatePool (StrSize (DnsCacheEntry.HostName));
    910   if (NewDnsCache->DnsCache.HostName == NULL) {
    911     return EFI_OUT_OF_RESOURCES;
    912   }
    913 
    914   CopyMem (NewDnsCache->DnsCache.HostName, DnsCacheEntry.HostName, StrSize (DnsCacheEntry.HostName));
    915 
    916   NewDnsCache->DnsCache.IpAddress = AllocatePool (sizeof (EFI_IPv6_ADDRESS));
    917   if (NewDnsCache->DnsCache.IpAddress == NULL) {
    918     return EFI_OUT_OF_RESOURCES;
    919   }
    920 
    921   CopyMem (NewDnsCache->DnsCache.IpAddress, DnsCacheEntry.IpAddress, sizeof (EFI_IPv6_ADDRESS));
    922 
    923   NewDnsCache->DnsCache.Timeout = DnsCacheEntry.Timeout;
    924 
    925   InsertTailList (Dns6CacheList, &NewDnsCache->AllCacheLink);
    926 
    927   return EFI_SUCCESS;
    928 }
    929 
    930 /**
    931   Add Dns4 ServerIp to common list of addresses of all configured DNSv4 server.
    932 
    933   @param  Dns4ServerList    Common list of addresses of all configured DNSv4 server.
    934   @param  ServerIp          DNS server Ip.
    935 
    936   @retval EFI_SUCCESS       Add Dns4 ServerIp to common list successfully.
    937   @retval Others            Failed to add Dns4 ServerIp to common list.
    938 
    939 **/
    940 EFI_STATUS
    941 EFIAPI
    942 AddDns4ServerIp (
    943   IN LIST_ENTRY                *Dns4ServerList,
    944   IN EFI_IPv4_ADDRESS           ServerIp
    945   )
    946 {
    947   DNS4_SERVER_IP    *NewServerIp;
    948   DNS4_SERVER_IP    *Item;
    949   LIST_ENTRY        *Entry;
    950   LIST_ENTRY        *Next;
    951 
    952   NewServerIp = NULL;
    953   Item        = NULL;
    954 
    955   //
    956   // Search the database for the matching ServerIp
    957   //
    958   NET_LIST_FOR_EACH_SAFE (Entry, Next, Dns4ServerList) {
    959     Item = NET_LIST_USER_STRUCT (Entry, DNS4_SERVER_IP, AllServerLink);
    960     if (CompareMem (&Item->Dns4ServerIp, &ServerIp, sizeof (EFI_IPv4_ADDRESS)) == 0) {
    961       //
    962       // Already done.
    963       //
    964       return EFI_SUCCESS;
    965     }
    966   }
    967 
    968   //
    969   // Add new one
    970   //
    971   NewServerIp = AllocatePool (sizeof (DNS4_SERVER_IP));
    972   if (NewServerIp == NULL) {
    973     return EFI_OUT_OF_RESOURCES;
    974   }
    975 
    976   InitializeListHead (&NewServerIp->AllServerLink);
    977 
    978   CopyMem (&NewServerIp->Dns4ServerIp, &ServerIp, sizeof (EFI_IPv4_ADDRESS));
    979 
    980   InsertTailList (Dns4ServerList, &NewServerIp->AllServerLink);
    981 
    982   return EFI_SUCCESS;
    983 }
    984 
    985 /**
    986   Add Dns6 ServerIp to common list of addresses of all configured DNSv6 server.
    987 
    988   @param  Dns6ServerList    Common list of addresses of all configured DNSv6 server.
    989   @param  ServerIp          DNS server Ip.
    990 
    991   @retval EFI_SUCCESS       Add Dns6 ServerIp to common list successfully.
    992   @retval Others            Failed to add Dns6 ServerIp to common list.
    993 
    994 **/
    995 EFI_STATUS
    996 EFIAPI
    997 AddDns6ServerIp (
    998   IN LIST_ENTRY                *Dns6ServerList,
    999   IN EFI_IPv6_ADDRESS           ServerIp
   1000   )
   1001 {
   1002   DNS6_SERVER_IP    *NewServerIp;
   1003   DNS6_SERVER_IP    *Item;
   1004   LIST_ENTRY        *Entry;
   1005   LIST_ENTRY        *Next;
   1006 
   1007   NewServerIp = NULL;
   1008   Item        = NULL;
   1009 
   1010   //
   1011   // Search the database for the matching ServerIp
   1012   //
   1013   NET_LIST_FOR_EACH_SAFE (Entry, Next, Dns6ServerList) {
   1014     Item = NET_LIST_USER_STRUCT (Entry, DNS6_SERVER_IP, AllServerLink);
   1015     if (CompareMem (&Item->Dns6ServerIp, &ServerIp, sizeof (EFI_IPv6_ADDRESS)) == 0) {
   1016       //
   1017       // Already done.
   1018       //
   1019       return EFI_SUCCESS;
   1020     }
   1021   }
   1022 
   1023   //
   1024   // Add new one
   1025   //
   1026   NewServerIp = AllocatePool (sizeof (DNS6_SERVER_IP));
   1027   if (NewServerIp == NULL) {
   1028     return EFI_OUT_OF_RESOURCES;
   1029   }
   1030 
   1031   InitializeListHead (&NewServerIp->AllServerLink);
   1032 
   1033   CopyMem (&NewServerIp->Dns6ServerIp, &ServerIp, sizeof (EFI_IPv6_ADDRESS));
   1034 
   1035   InsertTailList (Dns6ServerList, &NewServerIp->AllServerLink);
   1036 
   1037   return EFI_SUCCESS;
   1038 }
   1039 
   1040 /**
   1041   Find out whether the response is valid or invalid.
   1042 
   1043   @param  TokensMap       All DNS transmittal Tokens entry.
   1044   @param  Identification  Identification for queried packet.
   1045   @param  Type            Type for queried packet.
   1046   @param  Class           Class for queried packet.
   1047   @param  Item            Return corresponding Token entry.
   1048 
   1049   @retval TRUE            The response is valid.
   1050   @retval FALSE           The response is invalid.
   1051 
   1052 **/
   1053 BOOLEAN
   1054 IsValidDnsResponse (
   1055   IN     NET_MAP      *TokensMap,
   1056   IN     UINT16       Identification,
   1057   IN     UINT16       Type,
   1058   IN     UINT16       Class,
   1059      OUT NET_MAP_ITEM **Item
   1060   )
   1061 {
   1062   LIST_ENTRY              *Entry;
   1063 
   1064   NET_BUF                 *Packet;
   1065   UINT8                   *TxString;
   1066   DNS_HEADER              *DnsHeader;
   1067   CHAR8                   *QueryName;
   1068   DNS_QUERY_SECTION       *QuerySection;
   1069 
   1070   NET_LIST_FOR_EACH (Entry, &TokensMap->Used) {
   1071     *Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
   1072     Packet = (NET_BUF *) ((*Item)->Value);
   1073     if (Packet == NULL){
   1074 
   1075       continue;
   1076     } else {
   1077       TxString = NetbufGetByte (Packet, 0, NULL);
   1078       ASSERT (TxString != NULL);
   1079       DnsHeader = (DNS_HEADER *) TxString;
   1080       QueryName = (CHAR8 *) (TxString + sizeof (*DnsHeader));
   1081       QuerySection = (DNS_QUERY_SECTION *) (QueryName + AsciiStrLen (QueryName) + 1);
   1082 
   1083       if (NTOHS (DnsHeader->Identification) == Identification &&
   1084           NTOHS (QuerySection->Type) == Type &&
   1085           NTOHS (QuerySection->Class) == Class) {
   1086         return TRUE;
   1087       }
   1088     }
   1089   }
   1090 
   1091   *Item = NULL;
   1092 
   1093   return FALSE;
   1094 }
   1095 
   1096 /**
   1097   Parse Dns Response.
   1098 
   1099   @param  Instance              The DNS instance
   1100   @param  RxString              Received buffer.
   1101   @param  Completed             Flag to indicate that Dns response is valid.
   1102 
   1103   @retval EFI_SUCCESS           Parse Dns Response successfully.
   1104   @retval Others                Failed to parse Dns Response.
   1105 
   1106 **/
   1107 EFI_STATUS
   1108 ParseDnsResponse (
   1109   IN OUT DNS_INSTANCE              *Instance,
   1110   IN     UINT8                     *RxString,
   1111      OUT BOOLEAN                   *Completed
   1112   )
   1113 {
   1114   DNS_HEADER            *DnsHeader;
   1115 
   1116   CHAR8                 *QueryName;
   1117   DNS_QUERY_SECTION     *QuerySection;
   1118 
   1119   CHAR8                 *AnswerName;
   1120   DNS_ANSWER_SECTION    *AnswerSection;
   1121   UINT8                 *AnswerData;
   1122 
   1123   NET_MAP_ITEM          *Item;
   1124   DNS4_TOKEN_ENTRY      *Dns4TokenEntry;
   1125   DNS6_TOKEN_ENTRY      *Dns6TokenEntry;
   1126 
   1127   UINT32                IpCount;
   1128   UINT32                RRCount;
   1129   UINT32                AnswerSectionNum;
   1130   UINT32                CNameTtl;
   1131 
   1132   EFI_IPv4_ADDRESS      *HostAddr4;
   1133   EFI_IPv6_ADDRESS      *HostAddr6;
   1134 
   1135   EFI_DNS4_CACHE_ENTRY  *Dns4CacheEntry;
   1136   EFI_DNS6_CACHE_ENTRY  *Dns6CacheEntry;
   1137 
   1138   DNS_RESOURCE_RECORD   *Dns4RR;
   1139   DNS6_RESOURCE_RECORD  *Dns6RR;
   1140 
   1141   EFI_STATUS            Status;
   1142 
   1143   EFI_TPL               OldTpl;
   1144 
   1145   Item             = NULL;
   1146   Dns4TokenEntry   = NULL;
   1147   Dns6TokenEntry   = NULL;
   1148 
   1149   IpCount          = 0;
   1150   RRCount          = 0;
   1151   AnswerSectionNum = 0;
   1152   CNameTtl         = 0;
   1153 
   1154   HostAddr4        = NULL;
   1155   HostAddr6        = NULL;
   1156 
   1157   Dns4CacheEntry   = NULL;
   1158   Dns6CacheEntry   = NULL;
   1159 
   1160   Dns4RR           = NULL;
   1161   Dns6RR           = NULL;
   1162 
   1163   *Completed       = TRUE;
   1164   Status           = EFI_SUCCESS;
   1165 
   1166   //
   1167   // Get header
   1168   //
   1169   DnsHeader = (DNS_HEADER *) RxString;
   1170 
   1171   DnsHeader->Identification = NTOHS (DnsHeader->Identification);
   1172   DnsHeader->Flags.Uint16 = NTOHS (DnsHeader->Flags.Uint16);
   1173   DnsHeader->QuestionsNum = NTOHS (DnsHeader->QuestionsNum);
   1174   DnsHeader->AnswersNum = NTOHS (DnsHeader->AnswersNum);
   1175   DnsHeader->AuthorityNum = NTOHS (DnsHeader->AuthorityNum);
   1176   DnsHeader->AditionalNum = NTOHS (DnsHeader->AditionalNum);
   1177 
   1178   //
   1179   // Get Query name
   1180   //
   1181   QueryName = (CHAR8 *) (RxString + sizeof (*DnsHeader));
   1182 
   1183   //
   1184   // Get query section
   1185   //
   1186   QuerySection = (DNS_QUERY_SECTION *) (QueryName + AsciiStrLen (QueryName) + 1);
   1187   QuerySection->Type = NTOHS (QuerySection->Type);
   1188   QuerySection->Class = NTOHS (QuerySection->Class);
   1189 
   1190   //
   1191   // Get Answer name
   1192   //
   1193   AnswerName = (CHAR8 *) QuerySection + sizeof (*QuerySection);
   1194 
   1195   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1196 
   1197   //
   1198   // Check DnsResponse Validity, if so, also get a valid NET_MAP_ITEM.
   1199   //
   1200   if (Instance->Service->IpVersion == IP_VERSION_4) {
   1201     if (!IsValidDnsResponse (
   1202            &Instance->Dns4TxTokens,
   1203            DnsHeader->Identification,
   1204            QuerySection->Type,
   1205            QuerySection->Class,
   1206            &Item
   1207            )) {
   1208       *Completed = FALSE;
   1209       Status = EFI_ABORTED;
   1210       goto ON_EXIT;
   1211     }
   1212     ASSERT (Item != NULL);
   1213     Dns4TokenEntry = (DNS4_TOKEN_ENTRY *) (Item->Key);
   1214   } else {
   1215     if (!IsValidDnsResponse (
   1216            &Instance->Dns6TxTokens,
   1217            DnsHeader->Identification,
   1218            QuerySection->Type,
   1219            QuerySection->Class,
   1220            &Item
   1221            )) {
   1222       *Completed = FALSE;
   1223       Status = EFI_ABORTED;
   1224       goto ON_EXIT;
   1225     }
   1226     ASSERT (Item != NULL);
   1227     Dns6TokenEntry = (DNS6_TOKEN_ENTRY *) (Item->Key);
   1228   }
   1229 
   1230   //
   1231   // Continue Check Some Errors.
   1232   //
   1233   if (DnsHeader->Flags.Bits.RCode != DNS_FLAGS_RCODE_NO_ERROR || DnsHeader->AnswersNum < 1 || \
   1234       DnsHeader->Flags.Bits.QR != DNS_FLAGS_QR_RESPONSE) {
   1235     //
   1236     // The domain name referenced in the query does not exist.
   1237     //
   1238     if (DnsHeader->Flags.Bits.RCode == DNS_FLAGS_RCODE_NAME_ERROR) {
   1239       Status = EFI_NOT_FOUND;
   1240     } else {
   1241       Status = EFI_DEVICE_ERROR;
   1242     }
   1243 
   1244     goto ON_COMPLETE;
   1245   }
   1246 
   1247   //
   1248   // Do some buffer allocations.
   1249   //
   1250   if (Instance->Service->IpVersion == IP_VERSION_4) {
   1251     ASSERT (Dns4TokenEntry != NULL);
   1252 
   1253     if (Dns4TokenEntry->GeneralLookUp) {
   1254       //
   1255       // It's the GeneralLookUp querying.
   1256       //
   1257       Dns4TokenEntry->Token->RspData.GLookupData = AllocatePool (sizeof (DNS_RESOURCE_RECORD));
   1258       if (Dns4TokenEntry->Token->RspData.GLookupData == NULL) {
   1259         Status = EFI_OUT_OF_RESOURCES;
   1260         goto ON_EXIT;
   1261       }
   1262       Dns4TokenEntry->Token->RspData.GLookupData->RRList = AllocatePool (DnsHeader->AnswersNum * sizeof (DNS_RESOURCE_RECORD));
   1263       if (Dns4TokenEntry->Token->RspData.GLookupData->RRList == NULL) {
   1264         Status = EFI_OUT_OF_RESOURCES;
   1265         goto ON_EXIT;
   1266       }
   1267     } else {
   1268       //
   1269       // It's not the GeneralLookUp querying. Check the Query type.
   1270       //
   1271       if (QuerySection->Type == DNS_TYPE_A) {
   1272         Dns4TokenEntry->Token->RspData.H2AData = AllocatePool (sizeof (DNS_HOST_TO_ADDR_DATA));
   1273         if (Dns4TokenEntry->Token->RspData.H2AData == NULL) {
   1274           Status = EFI_OUT_OF_RESOURCES;
   1275           goto ON_EXIT;
   1276         }
   1277         Dns4TokenEntry->Token->RspData.H2AData->IpList = AllocatePool (DnsHeader->AnswersNum * sizeof (EFI_IPv4_ADDRESS));
   1278         if (Dns4TokenEntry->Token->RspData.H2AData->IpList == NULL) {
   1279           Status = EFI_OUT_OF_RESOURCES;
   1280           goto ON_EXIT;
   1281         }
   1282       } else {
   1283         Status = EFI_UNSUPPORTED;
   1284         goto ON_EXIT;
   1285       }
   1286     }
   1287   } else {
   1288     ASSERT (Dns6TokenEntry != NULL);
   1289 
   1290     if (Dns6TokenEntry->GeneralLookUp) {
   1291       //
   1292       // It's the GeneralLookUp querying.
   1293       //
   1294       Dns6TokenEntry->Token->RspData.GLookupData = AllocatePool (sizeof (DNS_RESOURCE_RECORD));
   1295       if (Dns6TokenEntry->Token->RspData.GLookupData == NULL) {
   1296         Status = EFI_OUT_OF_RESOURCES;
   1297         goto ON_EXIT;
   1298       }
   1299       Dns6TokenEntry->Token->RspData.GLookupData->RRList = AllocatePool (DnsHeader->AnswersNum * sizeof (DNS_RESOURCE_RECORD));
   1300       if (Dns6TokenEntry->Token->RspData.GLookupData->RRList == NULL) {
   1301         Status = EFI_OUT_OF_RESOURCES;
   1302         goto ON_EXIT;
   1303       }
   1304     } else {
   1305       //
   1306       // It's not the GeneralLookUp querying. Check the Query type.
   1307       //
   1308       if (QuerySection->Type == DNS_TYPE_AAAA) {
   1309         Dns6TokenEntry->Token->RspData.H2AData = AllocatePool (sizeof (DNS6_HOST_TO_ADDR_DATA));
   1310         if (Dns6TokenEntry->Token->RspData.H2AData == NULL) {
   1311           Status = EFI_OUT_OF_RESOURCES;
   1312           goto ON_EXIT;
   1313         }
   1314         Dns6TokenEntry->Token->RspData.H2AData->IpList = AllocatePool (DnsHeader->AnswersNum * sizeof (EFI_IPv6_ADDRESS));
   1315         if (Dns6TokenEntry->Token->RspData.H2AData->IpList == NULL) {
   1316           Status = EFI_OUT_OF_RESOURCES;
   1317           goto ON_EXIT;
   1318         }
   1319       } else {
   1320         Status = EFI_UNSUPPORTED;
   1321         goto ON_EXIT;
   1322       }
   1323     }
   1324   }
   1325 
   1326   Status = EFI_NOT_FOUND;
   1327 
   1328   //
   1329   // Processing AnswerSection.
   1330   //
   1331   while (AnswerSectionNum < DnsHeader->AnswersNum) {
   1332     //
   1333     // Answer name should be PTR, else EFI_UNSUPPORTED returned.
   1334     //
   1335     if ((*(UINT8 *) AnswerName & 0xC0) != 0xC0) {
   1336       Status = EFI_UNSUPPORTED;
   1337       goto ON_EXIT;
   1338     }
   1339 
   1340     //
   1341     // Get Answer section.
   1342     //
   1343     AnswerSection = (DNS_ANSWER_SECTION *) (AnswerName + sizeof (UINT16));
   1344     AnswerSection->Type = NTOHS (AnswerSection->Type);
   1345     AnswerSection->Class = NTOHS (AnswerSection->Class);
   1346     AnswerSection->Ttl = NTOHL (AnswerSection->Ttl);
   1347     AnswerSection->DataLength = NTOHS (AnswerSection->DataLength);
   1348 
   1349     //
   1350     // Check whether it's the GeneralLookUp querying.
   1351     //
   1352     if (Instance->Service->IpVersion == IP_VERSION_4 && Dns4TokenEntry->GeneralLookUp) {
   1353       Dns4RR = Dns4TokenEntry->Token->RspData.GLookupData->RRList;
   1354       AnswerData = (UINT8 *) AnswerSection + sizeof (*AnswerSection);
   1355 
   1356       //
   1357       // Fill the ResourceRecord.
   1358       //
   1359       Dns4RR[RRCount].QName = AllocateZeroPool (AsciiStrLen (QueryName) + 1);
   1360       if (Dns4RR[RRCount].QName == NULL) {
   1361         Status = EFI_OUT_OF_RESOURCES;
   1362         goto ON_EXIT;
   1363       }
   1364       CopyMem (Dns4RR[RRCount].QName, QueryName, AsciiStrLen (QueryName));
   1365       Dns4RR[RRCount].QType = AnswerSection->Type;
   1366       Dns4RR[RRCount].QClass = AnswerSection->Class;
   1367       Dns4RR[RRCount].TTL = AnswerSection->Ttl;
   1368       Dns4RR[RRCount].DataLength = AnswerSection->DataLength;
   1369       Dns4RR[RRCount].RData = AllocateZeroPool (Dns4RR[RRCount].DataLength);
   1370       if (Dns4RR[RRCount].RData == NULL) {
   1371         Status = EFI_OUT_OF_RESOURCES;
   1372         goto ON_EXIT;
   1373       }
   1374       CopyMem (Dns4RR[RRCount].RData, AnswerData, Dns4RR[RRCount].DataLength);
   1375 
   1376       RRCount ++;
   1377       Status = EFI_SUCCESS;
   1378     } else if (Instance->Service->IpVersion == IP_VERSION_6 && Dns6TokenEntry->GeneralLookUp) {
   1379       Dns6RR = Dns6TokenEntry->Token->RspData.GLookupData->RRList;
   1380       AnswerData = (UINT8 *) AnswerSection + sizeof (*AnswerSection);
   1381 
   1382       //
   1383       // Fill the ResourceRecord.
   1384       //
   1385       Dns6RR[RRCount].QName = AllocateZeroPool (AsciiStrLen (QueryName) + 1);
   1386       if (Dns6RR[RRCount].QName == NULL) {
   1387         Status = EFI_OUT_OF_RESOURCES;
   1388         goto ON_EXIT;
   1389       }
   1390       CopyMem (Dns6RR[RRCount].QName, QueryName, AsciiStrLen (QueryName));
   1391       Dns6RR[RRCount].QType = AnswerSection->Type;
   1392       Dns6RR[RRCount].QClass = AnswerSection->Class;
   1393       Dns6RR[RRCount].TTL = AnswerSection->Ttl;
   1394       Dns6RR[RRCount].DataLength = AnswerSection->DataLength;
   1395       Dns6RR[RRCount].RData = AllocateZeroPool (Dns6RR[RRCount].DataLength);
   1396       if (Dns6RR[RRCount].RData == NULL) {
   1397         Status = EFI_OUT_OF_RESOURCES;
   1398         goto ON_EXIT;
   1399       }
   1400       CopyMem (Dns6RR[RRCount].RData, AnswerData, Dns6RR[RRCount].DataLength);
   1401 
   1402       RRCount ++;
   1403       Status = EFI_SUCCESS;
   1404     } else {
   1405       //
   1406       // It's not the GeneralLookUp querying.
   1407       // Check the Query type, parse the response packet.
   1408       //
   1409       switch (AnswerSection->Type) {
   1410       case DNS_TYPE_A:
   1411         //
   1412         // This is address entry, get Data.
   1413         //
   1414         ASSERT (Dns4TokenEntry != NULL);
   1415 
   1416         if (AnswerSection->DataLength != 4) {
   1417           Status = EFI_ABORTED;
   1418           goto ON_EXIT;
   1419         }
   1420 
   1421         HostAddr4 = Dns4TokenEntry->Token->RspData.H2AData->IpList;
   1422         AnswerData = (UINT8 *) AnswerSection + sizeof (*AnswerSection);
   1423         CopyMem (&HostAddr4[IpCount], AnswerData, sizeof (EFI_IPv4_ADDRESS));
   1424 
   1425         //
   1426         // Allocate new CacheEntry pool to update DNS cache dynamically.
   1427         //
   1428         Dns4CacheEntry = AllocateZeroPool (sizeof (EFI_DNS4_CACHE_ENTRY));
   1429         if (Dns4CacheEntry == NULL) {
   1430           Status = EFI_OUT_OF_RESOURCES;
   1431           goto ON_EXIT;
   1432         }
   1433         Dns4CacheEntry->HostName = AllocateZeroPool (2 * (StrLen(Dns4TokenEntry->QueryHostName) + 1));
   1434         if (Dns4CacheEntry->HostName == NULL) {
   1435           Status = EFI_OUT_OF_RESOURCES;
   1436           goto ON_EXIT;
   1437         }
   1438         CopyMem (Dns4CacheEntry->HostName, Dns4TokenEntry->QueryHostName, 2 * (StrLen(Dns4TokenEntry->QueryHostName) + 1));
   1439         Dns4CacheEntry->IpAddress = AllocateZeroPool (sizeof (EFI_IPv4_ADDRESS));
   1440         if (Dns4CacheEntry->IpAddress == NULL) {
   1441           Status = EFI_OUT_OF_RESOURCES;
   1442           goto ON_EXIT;
   1443         }
   1444         CopyMem (Dns4CacheEntry->IpAddress, AnswerData, sizeof (EFI_IPv4_ADDRESS));
   1445 
   1446         if (CNameTtl != 0 && AnswerSection->Ttl != 0) {
   1447           Dns4CacheEntry->Timeout = MIN (CNameTtl, AnswerSection->Ttl);
   1448         } else {
   1449           Dns4CacheEntry->Timeout = MAX (CNameTtl, AnswerSection->Ttl);
   1450         }
   1451 
   1452         UpdateDns4Cache (&mDriverData->Dns4CacheList, FALSE, TRUE, *Dns4CacheEntry);
   1453 
   1454         //
   1455         // Free allocated CacheEntry pool.
   1456         //
   1457         FreePool (Dns4CacheEntry->HostName);
   1458         Dns4CacheEntry->HostName = NULL;
   1459 
   1460         FreePool (Dns4CacheEntry->IpAddress);
   1461         Dns4CacheEntry->IpAddress = NULL;
   1462 
   1463         FreePool (Dns4CacheEntry);
   1464         Dns4CacheEntry = NULL;
   1465 
   1466         IpCount ++;
   1467         Status = EFI_SUCCESS;
   1468         break;
   1469       case DNS_TYPE_AAAA:
   1470         //
   1471         // This is address entry, get Data.
   1472         //
   1473         ASSERT (Dns6TokenEntry != NULL);
   1474 
   1475         if (AnswerSection->DataLength != 16) {
   1476           Status = EFI_ABORTED;
   1477           goto ON_EXIT;
   1478         }
   1479 
   1480         HostAddr6 = Dns6TokenEntry->Token->RspData.H2AData->IpList;
   1481         AnswerData = (UINT8 *) AnswerSection + sizeof (*AnswerSection);
   1482         CopyMem (&HostAddr6[IpCount], AnswerData, sizeof (EFI_IPv6_ADDRESS));
   1483 
   1484         //
   1485         // Allocate new CacheEntry pool to update DNS cache dynamically.
   1486         //
   1487         Dns6CacheEntry = AllocateZeroPool (sizeof (EFI_DNS6_CACHE_ENTRY));
   1488         if (Dns6CacheEntry == NULL) {
   1489           Status = EFI_OUT_OF_RESOURCES;
   1490           goto ON_EXIT;
   1491         }
   1492         Dns6CacheEntry->HostName = AllocateZeroPool (2 * (StrLen(Dns6TokenEntry->QueryHostName) + 1));
   1493         if (Dns6CacheEntry->HostName == NULL) {
   1494           Status = EFI_OUT_OF_RESOURCES;
   1495           goto ON_EXIT;
   1496         }
   1497         CopyMem (Dns6CacheEntry->HostName, Dns6TokenEntry->QueryHostName, 2 * (StrLen(Dns6TokenEntry->QueryHostName) + 1));
   1498         Dns6CacheEntry->IpAddress = AllocateZeroPool (sizeof (EFI_IPv6_ADDRESS));
   1499         if (Dns6CacheEntry->IpAddress == NULL) {
   1500           Status = EFI_OUT_OF_RESOURCES;
   1501           goto ON_EXIT;
   1502         }
   1503         CopyMem (Dns6CacheEntry->IpAddress, AnswerData, sizeof (EFI_IPv6_ADDRESS));
   1504 
   1505         if (CNameTtl != 0 && AnswerSection->Ttl != 0) {
   1506           Dns6CacheEntry->Timeout = MIN (CNameTtl, AnswerSection->Ttl);
   1507         } else {
   1508           Dns6CacheEntry->Timeout = MAX (CNameTtl, AnswerSection->Ttl);
   1509         }
   1510 
   1511         UpdateDns6Cache (&mDriverData->Dns6CacheList, FALSE, TRUE, *Dns6CacheEntry);
   1512 
   1513         //
   1514         // Free allocated CacheEntry pool.
   1515         //
   1516         FreePool (Dns6CacheEntry->HostName);
   1517         Dns6CacheEntry->HostName = NULL;
   1518 
   1519         FreePool (Dns6CacheEntry->IpAddress);
   1520         Dns6CacheEntry->IpAddress = NULL;
   1521 
   1522         FreePool (Dns6CacheEntry);
   1523         Dns6CacheEntry = NULL;
   1524 
   1525         IpCount ++;
   1526         Status = EFI_SUCCESS;
   1527         break;
   1528       case DNS_TYPE_CNAME:
   1529         //
   1530         // According RFC 1034 - 3.6.2, if the query name is an alias, the name server will include the CNAME
   1531         // record in the response and restart the query at the domain name specified in the data field of the
   1532         // CNAME record. So, just record the TTL value of the CNAME, then skip to parse the next record.
   1533         //
   1534         CNameTtl = AnswerSection->Ttl;
   1535         break;
   1536       default:
   1537         Status = EFI_UNSUPPORTED;
   1538         goto ON_EXIT;
   1539       }
   1540     }
   1541 
   1542     //
   1543     // Find next one
   1544     //
   1545     AnswerName = (CHAR8 *) AnswerSection + sizeof (*AnswerSection) + AnswerSection->DataLength;
   1546     AnswerSectionNum ++;
   1547   }
   1548 
   1549   if (Instance->Service->IpVersion == IP_VERSION_4) {
   1550     ASSERT (Dns4TokenEntry != NULL);
   1551 
   1552     if (Dns4TokenEntry->GeneralLookUp) {
   1553       Dns4TokenEntry->Token->RspData.GLookupData->RRCount = RRCount;
   1554     } else {
   1555       if (QuerySection->Type == DNS_TYPE_A) {
   1556         Dns4TokenEntry->Token->RspData.H2AData->IpCount = IpCount;
   1557       } else {
   1558         Status = EFI_UNSUPPORTED;
   1559         goto ON_EXIT;
   1560       }
   1561     }
   1562   } else {
   1563     ASSERT (Dns6TokenEntry != NULL);
   1564 
   1565     if (Dns6TokenEntry->GeneralLookUp) {
   1566       Dns6TokenEntry->Token->RspData.GLookupData->RRCount = RRCount;
   1567     } else {
   1568       if (QuerySection->Type == DNS_TYPE_AAAA) {
   1569         Dns6TokenEntry->Token->RspData.H2AData->IpCount = IpCount;
   1570       } else {
   1571         Status = EFI_UNSUPPORTED;
   1572         goto ON_EXIT;
   1573       }
   1574     }
   1575   }
   1576 
   1577 ON_COMPLETE:
   1578   //
   1579   // Parsing is complete, free the sending packet and signal Event here.
   1580   //
   1581   if (Item != NULL && Item->Value != NULL) {
   1582     NetbufFree ((NET_BUF *) (Item->Value));
   1583   }
   1584 
   1585   if (Instance->Service->IpVersion == IP_VERSION_4) {
   1586     ASSERT (Dns4TokenEntry != NULL);
   1587     Dns4RemoveTokenEntry (&Instance->Dns4TxTokens, Dns4TokenEntry);
   1588     Dns4TokenEntry->Token->Status = Status;
   1589     if (Dns4TokenEntry->Token->Event != NULL) {
   1590       gBS->SignalEvent (Dns4TokenEntry->Token->Event);
   1591       DispatchDpc ();
   1592     }
   1593   } else {
   1594     ASSERT (Dns6TokenEntry != NULL);
   1595     Dns6RemoveTokenEntry (&Instance->Dns6TxTokens, Dns6TokenEntry);
   1596     Dns6TokenEntry->Token->Status = Status;
   1597     if (Dns6TokenEntry->Token->Event != NULL) {
   1598       gBS->SignalEvent (Dns6TokenEntry->Token->Event);
   1599       DispatchDpc ();
   1600     }
   1601   }
   1602 
   1603 ON_EXIT:
   1604   gBS->RestoreTPL (OldTpl);
   1605   return Status;
   1606 }
   1607 
   1608 /**
   1609   Parse response packet.
   1610 
   1611   @param  Packet                The packets received.
   1612   @param  EndPoint              The local/remote UDP access point
   1613   @param  IoStatus              The status of the UDP receive
   1614   @param  Context               The opaque parameter to the function.
   1615 
   1616 **/
   1617 VOID
   1618 EFIAPI
   1619 DnsOnPacketReceived (
   1620   NET_BUF                   *Packet,
   1621   UDP_END_POINT             *EndPoint,
   1622   EFI_STATUS                IoStatus,
   1623   VOID                      *Context
   1624   )
   1625 {
   1626   DNS_INSTANCE              *Instance;
   1627 
   1628   UINT8                     *RcvString;
   1629 
   1630   BOOLEAN                   Completed;
   1631 
   1632   Instance  = (DNS_INSTANCE *) Context;
   1633   NET_CHECK_SIGNATURE (Instance, DNS_INSTANCE_SIGNATURE);
   1634 
   1635   RcvString = NULL;
   1636   Completed = FALSE;
   1637 
   1638   if (EFI_ERROR (IoStatus)) {
   1639     goto ON_EXIT;
   1640   }
   1641 
   1642   ASSERT (Packet != NULL);
   1643 
   1644   if (Packet->TotalSize <= sizeof (DNS_HEADER)) {
   1645     goto ON_EXIT;
   1646   }
   1647 
   1648   RcvString = NetbufGetByte (Packet, 0, NULL);
   1649   ASSERT (RcvString != NULL);
   1650 
   1651   //
   1652   // Parse Dns Response
   1653   //
   1654   ParseDnsResponse (Instance, RcvString, &Completed);
   1655 
   1656 ON_EXIT:
   1657 
   1658   if (Packet != NULL) {
   1659     NetbufFree (Packet);
   1660   }
   1661 
   1662   if (!Completed) {
   1663     UdpIoRecvDatagram (Instance->UdpIo, DnsOnPacketReceived, Instance, 0);
   1664   }
   1665 }
   1666 
   1667 /**
   1668   Release the net buffer when packet is sent.
   1669 
   1670   @param  Packet                The packets received.
   1671   @param  EndPoint              The local/remote UDP access point
   1672   @param  IoStatus              The status of the UDP receive
   1673   @param  Context               The opaque parameter to the function.
   1674 
   1675 **/
   1676 VOID
   1677 EFIAPI
   1678 DnsOnPacketSent (
   1679   NET_BUF                   *Packet,
   1680   UDP_END_POINT             *EndPoint,
   1681   EFI_STATUS                IoStatus,
   1682   VOID                      *Context
   1683   )
   1684 {
   1685   DNS_INSTANCE              *Instance;
   1686   LIST_ENTRY                *Entry;
   1687   NET_MAP_ITEM              *Item;
   1688   DNS4_TOKEN_ENTRY          *Dns4TokenEntry;
   1689   DNS6_TOKEN_ENTRY          *Dns6TokenEntry;
   1690 
   1691   Dns4TokenEntry = NULL;
   1692   Dns6TokenEntry = NULL;
   1693 
   1694   Instance  = (DNS_INSTANCE *) Context;
   1695   NET_CHECK_SIGNATURE (Instance, DNS_INSTANCE_SIGNATURE);
   1696 
   1697   if (Instance->Service->IpVersion == IP_VERSION_4) {
   1698     NET_LIST_FOR_EACH (Entry, &Instance->Dns4TxTokens.Used) {
   1699       Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
   1700       if (Packet == (NET_BUF *)(Item->Value)) {
   1701         Dns4TokenEntry = ((DNS4_TOKEN_ENTRY *)Item->Key);
   1702         Dns4TokenEntry->PacketToLive = Dns4TokenEntry->Token->RetryInterval;
   1703         break;
   1704       }
   1705     }
   1706   } else {
   1707     NET_LIST_FOR_EACH (Entry, &Instance->Dns6TxTokens.Used) {
   1708       Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
   1709       if (Packet == (NET_BUF *)(Item->Value)) {
   1710         Dns6TokenEntry = ((DNS6_TOKEN_ENTRY *)Item->Key);
   1711         Dns6TokenEntry->PacketToLive = Dns6TokenEntry->Token->RetryInterval;
   1712         break;
   1713       }
   1714     }
   1715   }
   1716 
   1717   NetbufFree (Packet);
   1718 }
   1719 
   1720 /**
   1721   Query request information.
   1722 
   1723   @param  Instance              The DNS instance
   1724   @param  Packet                The packet for querying request information.
   1725 
   1726   @retval EFI_SUCCESS           Query request information successfully.
   1727   @retval Others                Failed to query request information.
   1728 
   1729 **/
   1730 EFI_STATUS
   1731 DoDnsQuery (
   1732   IN  DNS_INSTANCE              *Instance,
   1733   IN  NET_BUF                   *Packet
   1734   )
   1735 {
   1736   EFI_STATUS      Status;
   1737 
   1738   //
   1739   // Ready to receive the DNS response.
   1740   //
   1741   if (Instance->UdpIo->RecvRequest == NULL) {
   1742     Status = UdpIoRecvDatagram (Instance->UdpIo, DnsOnPacketReceived, Instance, 0);
   1743     if (EFI_ERROR (Status)) {
   1744       return Status;
   1745     }
   1746   }
   1747 
   1748   //
   1749   // Transmit the DNS packet.
   1750   //
   1751   NET_GET_REF (Packet);
   1752 
   1753   Status = UdpIoSendDatagram (Instance->UdpIo, Packet, NULL, NULL, DnsOnPacketSent, Instance);
   1754 
   1755   return Status;
   1756 }
   1757 
   1758 /**
   1759   Construct the Packet according query section.
   1760 
   1761   @param  Instance              The DNS instance
   1762   @param  QueryName             Queried Name
   1763   @param  Type                  Queried Type
   1764   @param  Class                 Queried Class
   1765   @param  Packet                The packet for query
   1766 
   1767   @retval EFI_SUCCESS           The packet is constructed.
   1768   @retval Others                Failed to construct the Packet.
   1769 
   1770 **/
   1771 EFI_STATUS
   1772 ConstructDNSQuery (
   1773   IN  DNS_INSTANCE              *Instance,
   1774   IN  CHAR8                     *QueryName,
   1775   IN  UINT16                    Type,
   1776   IN  UINT16                    Class,
   1777   OUT NET_BUF                   **Packet
   1778   )
   1779 {
   1780   NET_FRAGMENT        Frag;
   1781   DNS_HEADER          *DnsHeader;
   1782   DNS_QUERY_SECTION   *DnsQuery;
   1783 
   1784   //
   1785   // Messages carried by UDP are restricted to 512 bytes (not counting the IP
   1786   // or UDP headers).
   1787   //
   1788   Frag.Bulk = AllocatePool (DNS_MAX_MESSAGE_SIZE * sizeof (UINT8));
   1789   if (Frag.Bulk == NULL) {
   1790     return EFI_OUT_OF_RESOURCES;
   1791   }
   1792 
   1793   //
   1794   // Fill header
   1795   //
   1796   DnsHeader = (DNS_HEADER *) Frag.Bulk;
   1797   DnsHeader->Identification = (UINT16)NET_RANDOM (NetRandomInitSeed());
   1798   DnsHeader->Flags.Uint16 = 0x0000;
   1799   DnsHeader->Flags.Bits.RD = 1;
   1800   DnsHeader->Flags.Bits.OpCode = DNS_FLAGS_OPCODE_STANDARD;
   1801   DnsHeader->Flags.Bits.QR = DNS_FLAGS_QR_QUERY;
   1802   DnsHeader->QuestionsNum = 1;
   1803   DnsHeader->AnswersNum = 0;
   1804   DnsHeader->AuthorityNum = 0;
   1805   DnsHeader->AditionalNum = 0;
   1806 
   1807   DnsHeader->Identification = HTONS (DnsHeader->Identification);
   1808   DnsHeader->Flags.Uint16 = HTONS (DnsHeader->Flags.Uint16);
   1809   DnsHeader->QuestionsNum = HTONS (DnsHeader->QuestionsNum);
   1810   DnsHeader->AnswersNum = HTONS (DnsHeader->AnswersNum);
   1811   DnsHeader->AuthorityNum = HTONS (DnsHeader->AuthorityNum);
   1812   DnsHeader->AditionalNum = HTONS (DnsHeader->AditionalNum);
   1813 
   1814   Frag.Len = sizeof (*DnsHeader);
   1815 
   1816   //
   1817   // Fill Query name
   1818   //
   1819   CopyMem (Frag.Bulk + Frag.Len, QueryName, AsciiStrLen (QueryName));
   1820   Frag.Len = (UINT32) (Frag.Len + AsciiStrLen (QueryName));
   1821   *(Frag.Bulk + Frag.Len) = 0;
   1822   Frag.Len ++;
   1823 
   1824   //
   1825   // Rest query section
   1826   //
   1827   DnsQuery = (DNS_QUERY_SECTION *) (Frag.Bulk + Frag.Len);
   1828 
   1829   DnsQuery->Type = HTONS (Type);
   1830   DnsQuery->Class = HTONS (Class);
   1831 
   1832   Frag.Len += sizeof (*DnsQuery);
   1833 
   1834   //
   1835   // Wrap the Frag in a net buffer.
   1836   //
   1837   *Packet = NetbufFromExt (&Frag, 1, 0, 0, DnsDummyExtFree, NULL);
   1838   if (*Packet == NULL) {
   1839     FreePool (Frag.Bulk);
   1840     return EFI_OUT_OF_RESOURCES;
   1841   }
   1842 
   1843   //
   1844   // Store the UdpIo in ProtoData.
   1845   //
   1846   *((UINTN *) &((*Packet)->ProtoData[0])) = (UINTN) (Instance->UdpIo);
   1847 
   1848   return EFI_SUCCESS;
   1849 }
   1850 
   1851 /**
   1852   Retransmit the packet.
   1853 
   1854   @param  Instance              The DNS instance
   1855   @param  Packet                Retransmit the packet
   1856 
   1857   @retval EFI_SUCCESS           The packet is retransmitted.
   1858   @retval Others                Failed to retransmit.
   1859 
   1860 **/
   1861 EFI_STATUS
   1862 DnsRetransmit (
   1863   IN DNS_INSTANCE        *Instance,
   1864   IN NET_BUF             *Packet
   1865   )
   1866 {
   1867   EFI_STATUS      Status;
   1868 
   1869   UINT8           *Buffer;
   1870 
   1871   ASSERT (Packet != NULL);
   1872 
   1873   //
   1874   // Set the requests to the listening port, other packets to the connected port
   1875   //
   1876   Buffer = NetbufGetByte (Packet, 0, NULL);
   1877   ASSERT (Buffer != NULL);
   1878 
   1879   NET_GET_REF (Packet);
   1880 
   1881   Status = UdpIoSendDatagram (
   1882              Instance->UdpIo,
   1883              Packet,
   1884              NULL,
   1885              NULL,
   1886              DnsOnPacketSent,
   1887              Instance
   1888              );
   1889 
   1890   if (EFI_ERROR (Status)) {
   1891     NET_PUT_REF (Packet);
   1892   }
   1893 
   1894   return Status;
   1895 }
   1896 
   1897 /**
   1898   The timer ticking function for the DNS services.
   1899 
   1900   @param  Event                 The ticking event
   1901   @param  Context               The DNS service instance
   1902 
   1903 **/
   1904 VOID
   1905 EFIAPI
   1906 DnsOnTimerRetransmit (
   1907   IN EFI_EVENT              Event,
   1908   IN VOID                   *Context
   1909   )
   1910 {
   1911   DNS_SERVICE                *Service;
   1912 
   1913   LIST_ENTRY                 *Entry;
   1914   LIST_ENTRY                 *Next;
   1915 
   1916   DNS_INSTANCE               *Instance;
   1917   LIST_ENTRY                 *EntryNetMap;
   1918   NET_MAP_ITEM               *ItemNetMap;
   1919   DNS4_TOKEN_ENTRY           *Dns4TokenEntry;
   1920   DNS6_TOKEN_ENTRY           *Dns6TokenEntry;
   1921 
   1922   Dns4TokenEntry = NULL;
   1923   Dns6TokenEntry = NULL;
   1924 
   1925   Service = (DNS_SERVICE *) Context;
   1926 
   1927 
   1928   if (Service->IpVersion == IP_VERSION_4) {
   1929     //
   1930     // Iterate through all the children of the DNS service instance. Time
   1931     // out the packet. If maximum retries reached, clean the Token up.
   1932     //
   1933     NET_LIST_FOR_EACH_SAFE (Entry, Next, &Service->Dns4ChildrenList) {
   1934       Instance = NET_LIST_USER_STRUCT (Entry, DNS_INSTANCE, Link);
   1935 
   1936       EntryNetMap = Instance->Dns4TxTokens.Used.ForwardLink;
   1937       while (EntryNetMap != &Instance->Dns4TxTokens.Used) {
   1938         ItemNetMap = NET_LIST_USER_STRUCT (EntryNetMap, NET_MAP_ITEM, Link);
   1939         Dns4TokenEntry = (DNS4_TOKEN_ENTRY *)(ItemNetMap->Key);
   1940         if (Dns4TokenEntry->PacketToLive == 0 || (--Dns4TokenEntry->PacketToLive > 0)) {
   1941           EntryNetMap = EntryNetMap->ForwardLink;
   1942           continue;
   1943         }
   1944 
   1945         //
   1946         // Retransmit the packet if haven't reach the maxmium retry count,
   1947         // otherwise exit the transfer.
   1948         //
   1949         if (++Dns4TokenEntry->Token->RetryCount < Instance->MaxRetry) {
   1950           DnsRetransmit (Instance, (NET_BUF *)ItemNetMap->Value);
   1951           EntryNetMap = EntryNetMap->ForwardLink;
   1952         } else {
   1953           //
   1954           // Maximum retries reached, clean the Token up.
   1955           //
   1956           Dns4RemoveTokenEntry (&Instance->Dns4TxTokens, Dns4TokenEntry);
   1957           Dns4TokenEntry->Token->Status = EFI_TIMEOUT;
   1958           gBS->SignalEvent (Dns4TokenEntry->Token->Event);
   1959           DispatchDpc ();
   1960 
   1961           //
   1962           // Free the sending packet.
   1963           //
   1964           if (ItemNetMap->Value != NULL) {
   1965             NetbufFree ((NET_BUF *)(ItemNetMap->Value));
   1966           }
   1967 
   1968           EntryNetMap = Instance->Dns4TxTokens.Used.ForwardLink;
   1969         }
   1970       }
   1971     }
   1972   }else {
   1973     //
   1974     // Iterate through all the children of the DNS service instance. Time
   1975     // out the packet. If maximum retries reached, clean the Token up.
   1976     //
   1977     NET_LIST_FOR_EACH_SAFE (Entry, Next, &Service->Dns6ChildrenList) {
   1978       Instance = NET_LIST_USER_STRUCT (Entry, DNS_INSTANCE, Link);
   1979 
   1980       EntryNetMap = Instance->Dns6TxTokens.Used.ForwardLink;
   1981       while (EntryNetMap != &Instance->Dns6TxTokens.Used) {
   1982         ItemNetMap = NET_LIST_USER_STRUCT (EntryNetMap, NET_MAP_ITEM, Link);
   1983         Dns6TokenEntry = (DNS6_TOKEN_ENTRY *) (ItemNetMap->Key);
   1984         if (Dns6TokenEntry->PacketToLive == 0 || (--Dns6TokenEntry->PacketToLive > 0)) {
   1985           EntryNetMap = EntryNetMap->ForwardLink;
   1986           continue;
   1987         }
   1988 
   1989         //
   1990         // Retransmit the packet if haven't reach the maxmium retry count,
   1991         // otherwise exit the transfer.
   1992         //
   1993         if (++Dns6TokenEntry->Token->RetryCount < Instance->MaxRetry) {
   1994           DnsRetransmit (Instance, (NET_BUF *) ItemNetMap->Value);
   1995           EntryNetMap = EntryNetMap->ForwardLink;
   1996         } else {
   1997           //
   1998           // Maximum retries reached, clean the Token up.
   1999           //
   2000           Dns6RemoveTokenEntry (&Instance->Dns6TxTokens, Dns6TokenEntry);
   2001           Dns6TokenEntry->Token->Status = EFI_TIMEOUT;
   2002           gBS->SignalEvent (Dns6TokenEntry->Token->Event);
   2003           DispatchDpc ();
   2004 
   2005           //
   2006           // Free the sending packet.
   2007           //
   2008           if (ItemNetMap->Value != NULL) {
   2009             NetbufFree ((NET_BUF *) (ItemNetMap->Value));
   2010           }
   2011 
   2012           EntryNetMap = Instance->Dns6TxTokens.Used.ForwardLink;
   2013         }
   2014       }
   2015     }
   2016   }
   2017 }
   2018 
   2019 /**
   2020   The timer ticking function for the DNS driver.
   2021 
   2022   @param  Event                 The ticking event
   2023   @param  Context               NULL
   2024 
   2025 **/
   2026 VOID
   2027 EFIAPI
   2028 DnsOnTimerUpdate (
   2029   IN EFI_EVENT              Event,
   2030   IN VOID                   *Context
   2031   )
   2032 {
   2033   LIST_ENTRY                 *Entry;
   2034   LIST_ENTRY                 *Next;
   2035   DNS4_CACHE                 *Item4;
   2036   DNS6_CACHE                 *Item6;
   2037 
   2038   Item4 = NULL;
   2039   Item6 = NULL;
   2040 
   2041   //
   2042   // Iterate through all the DNS4 cache list.
   2043   //
   2044   NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns4CacheList) {
   2045     Item4 = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink);
   2046     Item4->DnsCache.Timeout--;
   2047   }
   2048 
   2049   Entry = mDriverData->Dns4CacheList.ForwardLink;
   2050   while (Entry != &mDriverData->Dns4CacheList) {
   2051     Item4 = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink);
   2052     if (Item4->DnsCache.Timeout == 0) {
   2053       RemoveEntryList (&Item4->AllCacheLink);
   2054       Entry = mDriverData->Dns4CacheList.ForwardLink;
   2055     } else {
   2056       Entry = Entry->ForwardLink;
   2057     }
   2058   }
   2059 
   2060   //
   2061   // Iterate through all the DNS6 cache list.
   2062   //
   2063   NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns6CacheList) {
   2064     Item6 = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink);
   2065     Item6->DnsCache.Timeout--;
   2066   }
   2067 
   2068   Entry = mDriverData->Dns6CacheList.ForwardLink;
   2069   while (Entry != &mDriverData->Dns6CacheList) {
   2070     Item6 = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink);
   2071     if (Item6->DnsCache.Timeout == 0) {
   2072       RemoveEntryList (&Item6->AllCacheLink);
   2073       Entry = mDriverData->Dns6CacheList.ForwardLink;
   2074     } else {
   2075       Entry = Entry->ForwardLink;
   2076     }
   2077   }
   2078 }
   2079 
   2080