Home | History | Annotate | Download | only in DnsDxe
      1 /** @file
      2 DnsDxe support functions implementation.
      3 
      4 Copyright (c) 2015, 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         Ip6Mode.IsConfigured) {
    623 
    624       Udp->Configure (Udp, NULL);
    625       return (BOOLEAN) (Udp->Configure (Udp, UdpCfgData) == EFI_SUCCESS);
    626     }
    627   }
    628 
    629   return FALSE;
    630 }
    631 
    632 /**
    633   Configure the UDP.
    634 
    635   @param  Instance               The DNS session
    636   @param  UdpIo                  The UDP_IO instance
    637 
    638   @retval EFI_SUCCESS            The UDP is successfully configured for the
    639                                  session.
    640 
    641 **/
    642 EFI_STATUS
    643 Dns4ConfigUdp (
    644   IN DNS_INSTANCE           *Instance,
    645   IN UDP_IO                 *UdpIo
    646   )
    647 {
    648   EFI_DNS4_CONFIG_DATA      *Config;
    649   EFI_UDP4_CONFIG_DATA      UdpConfig;
    650   EFI_STATUS                Status;
    651 
    652   Config = &Instance->Dns4CfgData;
    653 
    654   UdpConfig.AcceptBroadcast    = FALSE;
    655   UdpConfig.AcceptPromiscuous  = FALSE;
    656   UdpConfig.AcceptAnyPort      = FALSE;
    657   UdpConfig.AllowDuplicatePort = FALSE;
    658   UdpConfig.TypeOfService      = 0;
    659   UdpConfig.TimeToLive         = 128;
    660   UdpConfig.DoNotFragment      = FALSE;
    661   UdpConfig.ReceiveTimeout     = 0;
    662   UdpConfig.TransmitTimeout    = 0;
    663   UdpConfig.UseDefaultAddress  = Config->UseDefaultSetting;
    664   UdpConfig.SubnetMask         = Config->SubnetMask;
    665   UdpConfig.StationPort        = Config->LocalPort;
    666   UdpConfig.RemotePort         = DNS_SERVER_PORT;
    667 
    668   CopyMem (&UdpConfig.StationAddress, &Config->StationIp, sizeof (EFI_IPv4_ADDRESS));
    669   CopyMem (&UdpConfig.RemoteAddress, &Instance->SessionDnsServer.v4, sizeof (EFI_IPv4_ADDRESS));
    670 
    671   Status = UdpIo->Protocol.Udp4->Configure (UdpIo->Protocol.Udp4, &UdpConfig);
    672 
    673   if ((Status == EFI_NO_MAPPING) && Dns4GetMapping (Instance, UdpIo, &UdpConfig)) {
    674     return EFI_SUCCESS;
    675   }
    676 
    677   return Status;
    678 }
    679 
    680 /**
    681   Configure the UDP.
    682 
    683   @param  Instance               The DNS session
    684   @param  UdpIo                  The UDP_IO instance
    685 
    686   @retval EFI_SUCCESS            The UDP is successfully configured for the
    687                                  session.
    688 
    689 **/
    690 EFI_STATUS
    691 Dns6ConfigUdp (
    692   IN DNS_INSTANCE           *Instance,
    693   IN UDP_IO                 *UdpIo
    694   )
    695 {
    696   EFI_DNS6_CONFIG_DATA      *Config;
    697   EFI_UDP6_CONFIG_DATA      UdpConfig;
    698   EFI_STATUS                Status;
    699 
    700   Config = &Instance->Dns6CfgData;
    701 
    702   UdpConfig.AcceptPromiscuous  = FALSE;
    703   UdpConfig.AcceptAnyPort      = FALSE;
    704   UdpConfig.AllowDuplicatePort = FALSE;
    705   UdpConfig.TrafficClass       = 0;
    706   UdpConfig.HopLimit           = 128;
    707   UdpConfig.ReceiveTimeout     = 0;
    708   UdpConfig.TransmitTimeout    = 0;
    709   UdpConfig.StationPort        = Config->LocalPort;
    710   UdpConfig.RemotePort         = DNS_SERVER_PORT;
    711   CopyMem (&UdpConfig.StationAddress, &Config->StationIp, sizeof (EFI_IPv6_ADDRESS));
    712   CopyMem (&UdpConfig.RemoteAddress, &Instance->SessionDnsServer.v6, sizeof (EFI_IPv6_ADDRESS));
    713 
    714   Status = UdpIo->Protocol.Udp6->Configure (UdpIo->Protocol.Udp6, &UdpConfig);
    715 
    716   if ((Status == EFI_NO_MAPPING) && Dns6GetMapping (Instance, UdpIo, &UdpConfig)) {
    717     return EFI_SUCCESS;
    718   }
    719 
    720   return Status;
    721 }
    722 
    723 /**
    724   Update Dns4 cache to shared list of caches of all DNSv4 instances.
    725 
    726   @param  Dns4CacheList      All Dns4 cache list.
    727   @param  DeleteFlag         If FALSE, this function is to add one entry to the DNS Cache.
    728                              If TRUE, this function will delete matching DNS Cache entry.
    729   @param  Override           If TRUE, the matching DNS cache entry will be overwritten with the supplied parameter.
    730                              If FALSE, EFI_ACCESS_DENIED will be returned if the entry to be added is already exists.
    731   @param  DnsCacheEntry      Entry Pointer to DNS Cache entry.
    732 
    733   @retval EFI_SUCCESS        Update Dns4 cache successfully.
    734   @retval Others             Failed to update Dns4 cache.
    735 
    736 **/
    737 EFI_STATUS
    738 EFIAPI
    739 UpdateDns4Cache (
    740   IN LIST_ENTRY             *Dns4CacheList,
    741   IN BOOLEAN                DeleteFlag,
    742   IN BOOLEAN                Override,
    743   IN EFI_DNS4_CACHE_ENTRY   DnsCacheEntry
    744   )
    745 {
    746   DNS4_CACHE    *NewDnsCache;
    747   DNS4_CACHE    *Item;
    748   LIST_ENTRY    *Entry;
    749   LIST_ENTRY    *Next;
    750 
    751   NewDnsCache = NULL;
    752   Item        = NULL;
    753 
    754   //
    755   // Search the database for the matching EFI_DNS_CACHE_ENTRY
    756   //
    757   NET_LIST_FOR_EACH_SAFE (Entry, Next, Dns4CacheList) {
    758     Item = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink);
    759     if (StrCmp (DnsCacheEntry.HostName, Item->DnsCache.HostName) == 0 && \
    760         CompareMem (DnsCacheEntry.IpAddress, Item->DnsCache.IpAddress, sizeof (EFI_IPv4_ADDRESS)) == 0) {
    761       //
    762       // This is the Dns cache entry
    763       //
    764       if (DeleteFlag) {
    765         //
    766         // Delete matching DNS Cache entry
    767         //
    768         RemoveEntryList (&Item->AllCacheLink);
    769 
    770         return EFI_SUCCESS;
    771       } else if (Override) {
    772         //
    773         // Update this one
    774         //
    775         Item->DnsCache.Timeout = DnsCacheEntry.Timeout;
    776 
    777         return EFI_SUCCESS;
    778       }else {
    779         return EFI_ACCESS_DENIED;
    780       }
    781     }
    782   }
    783 
    784   //
    785   // Add new one
    786   //
    787   NewDnsCache = AllocatePool (sizeof (DNS4_CACHE));
    788   if (NewDnsCache == NULL) {
    789     return EFI_OUT_OF_RESOURCES;
    790   }
    791 
    792   InitializeListHead (&NewDnsCache->AllCacheLink);
    793 
    794   NewDnsCache->DnsCache.HostName = AllocatePool (StrSize (DnsCacheEntry.HostName));
    795   if (NewDnsCache->DnsCache.HostName == NULL) {
    796     return EFI_OUT_OF_RESOURCES;
    797   }
    798 
    799   CopyMem (NewDnsCache->DnsCache.HostName, DnsCacheEntry.HostName, StrSize (DnsCacheEntry.HostName));
    800 
    801   NewDnsCache->DnsCache.IpAddress = AllocatePool (sizeof (EFI_IPv4_ADDRESS));
    802   if (NewDnsCache->DnsCache.IpAddress == NULL) {
    803     return EFI_OUT_OF_RESOURCES;
    804   }
    805 
    806   CopyMem (NewDnsCache->DnsCache.IpAddress, DnsCacheEntry.IpAddress, sizeof (EFI_IPv4_ADDRESS));
    807 
    808   NewDnsCache->DnsCache.Timeout = DnsCacheEntry.Timeout;
    809 
    810   InsertTailList (Dns4CacheList, &NewDnsCache->AllCacheLink);
    811 
    812   return EFI_SUCCESS;
    813 }
    814 
    815 /**
    816   Update Dns6 cache to shared list of caches of all DNSv6 instances.
    817 
    818   @param  Dns6CacheList      All Dns6 cache list.
    819   @param  DeleteFlag         If FALSE, this function is to add one entry to the DNS Cache.
    820                              If TRUE, this function will delete matching DNS Cache entry.
    821   @param  Override           If TRUE, the matching DNS cache entry will be overwritten with the supplied parameter.
    822                              If FALSE, EFI_ACCESS_DENIED will be returned if the entry to be added is already exists.
    823   @param  DnsCacheEntry      Entry Pointer to DNS Cache entry.
    824 
    825   @retval EFI_SUCCESS        Update Dns6 cache successfully.
    826   @retval Others             Failed to update Dns6 cache.
    827 **/
    828 EFI_STATUS
    829 EFIAPI
    830 UpdateDns6Cache (
    831   IN LIST_ENTRY             *Dns6CacheList,
    832   IN BOOLEAN                DeleteFlag,
    833   IN BOOLEAN                Override,
    834   IN EFI_DNS6_CACHE_ENTRY   DnsCacheEntry
    835   )
    836 {
    837   DNS6_CACHE    *NewDnsCache;
    838   DNS6_CACHE    *Item;
    839   LIST_ENTRY    *Entry;
    840   LIST_ENTRY    *Next;
    841 
    842   NewDnsCache = NULL;
    843   Item        = NULL;
    844 
    845   //
    846   // Search the database for the matching EFI_DNS_CACHE_ENTRY
    847   //
    848   NET_LIST_FOR_EACH_SAFE (Entry, Next, Dns6CacheList) {
    849     Item = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink);
    850     if (StrCmp (DnsCacheEntry.HostName, Item->DnsCache.HostName) == 0 && \
    851         CompareMem (DnsCacheEntry.IpAddress, Item->DnsCache.IpAddress, sizeof (EFI_IPv6_ADDRESS)) == 0) {
    852       //
    853       // This is the Dns cache entry
    854       //
    855       if (DeleteFlag) {
    856         //
    857         // Delete matching DNS Cache entry
    858         //
    859         RemoveEntryList (&Item->AllCacheLink);
    860 
    861         return EFI_SUCCESS;
    862       } else if (Override) {
    863         //
    864         // Update this one
    865         //
    866         Item->DnsCache.Timeout = DnsCacheEntry.Timeout;
    867 
    868         return EFI_SUCCESS;
    869       }else {
    870         return EFI_ACCESS_DENIED;
    871       }
    872     }
    873   }
    874 
    875   //
    876   // Add new one
    877   //
    878   NewDnsCache = AllocatePool (sizeof (DNS6_CACHE));
    879   if (NewDnsCache == NULL) {
    880     return EFI_OUT_OF_RESOURCES;
    881   }
    882 
    883   InitializeListHead (&NewDnsCache->AllCacheLink);
    884 
    885   NewDnsCache->DnsCache.HostName = AllocatePool (StrSize (DnsCacheEntry.HostName));
    886   if (NewDnsCache->DnsCache.HostName == NULL) {
    887     return EFI_OUT_OF_RESOURCES;
    888   }
    889 
    890   CopyMem (NewDnsCache->DnsCache.HostName, DnsCacheEntry.HostName, StrSize (DnsCacheEntry.HostName));
    891 
    892   NewDnsCache->DnsCache.IpAddress = AllocatePool (sizeof (EFI_IPv6_ADDRESS));
    893   if (NewDnsCache->DnsCache.IpAddress == NULL) {
    894     return EFI_OUT_OF_RESOURCES;
    895   }
    896 
    897   CopyMem (NewDnsCache->DnsCache.IpAddress, DnsCacheEntry.IpAddress, sizeof (EFI_IPv6_ADDRESS));
    898 
    899   NewDnsCache->DnsCache.Timeout = DnsCacheEntry.Timeout;
    900 
    901   InsertTailList (Dns6CacheList, &NewDnsCache->AllCacheLink);
    902 
    903   return EFI_SUCCESS;
    904 }
    905 
    906 /**
    907   Add Dns4 ServerIp to common list of addresses of all configured DNSv4 server.
    908 
    909   @param  Dns4ServerList    Common list of addresses of all configured DNSv4 server.
    910   @param  ServerIp          DNS server Ip.
    911 
    912   @retval EFI_SUCCESS       Add Dns4 ServerIp to common list successfully.
    913   @retval Others            Failed to add Dns4 ServerIp to common list.
    914 
    915 **/
    916 EFI_STATUS
    917 EFIAPI
    918 AddDns4ServerIp (
    919   IN LIST_ENTRY                *Dns4ServerList,
    920   IN EFI_IPv4_ADDRESS           ServerIp
    921   )
    922 {
    923   DNS4_SERVER_IP    *NewServerIp;
    924   DNS4_SERVER_IP    *Item;
    925   LIST_ENTRY        *Entry;
    926   LIST_ENTRY        *Next;
    927 
    928   NewServerIp = NULL;
    929   Item        = NULL;
    930 
    931   //
    932   // Search the database for the matching ServerIp
    933   //
    934   NET_LIST_FOR_EACH_SAFE (Entry, Next, Dns4ServerList) {
    935     Item = NET_LIST_USER_STRUCT (Entry, DNS4_SERVER_IP, AllServerLink);
    936     if (CompareMem (&Item->Dns4ServerIp, &ServerIp, sizeof (EFI_IPv4_ADDRESS)) == 0) {
    937       //
    938       // Already done.
    939       //
    940       return EFI_SUCCESS;
    941     }
    942   }
    943 
    944   //
    945   // Add new one
    946   //
    947   NewServerIp = AllocatePool (sizeof (DNS4_SERVER_IP));
    948   if (NewServerIp == NULL) {
    949     return EFI_OUT_OF_RESOURCES;
    950   }
    951 
    952   InitializeListHead (&NewServerIp->AllServerLink);
    953 
    954   CopyMem (&NewServerIp->Dns4ServerIp, &ServerIp, sizeof (EFI_IPv4_ADDRESS));
    955 
    956   InsertTailList (Dns4ServerList, &NewServerIp->AllServerLink);
    957 
    958   return EFI_SUCCESS;
    959 }
    960 
    961 /**
    962   Add Dns6 ServerIp to common list of addresses of all configured DNSv6 server.
    963 
    964   @param  Dns6ServerList    Common list of addresses of all configured DNSv6 server.
    965   @param  ServerIp          DNS server Ip.
    966 
    967   @retval EFI_SUCCESS       Add Dns6 ServerIp to common list successfully.
    968   @retval Others            Failed to add Dns6 ServerIp to common list.
    969 
    970 **/
    971 EFI_STATUS
    972 EFIAPI
    973 AddDns6ServerIp (
    974   IN LIST_ENTRY                *Dns6ServerList,
    975   IN EFI_IPv6_ADDRESS           ServerIp
    976   )
    977 {
    978   DNS6_SERVER_IP    *NewServerIp;
    979   DNS6_SERVER_IP    *Item;
    980   LIST_ENTRY        *Entry;
    981   LIST_ENTRY        *Next;
    982 
    983   NewServerIp = NULL;
    984   Item        = NULL;
    985 
    986   //
    987   // Search the database for the matching ServerIp
    988   //
    989   NET_LIST_FOR_EACH_SAFE (Entry, Next, Dns6ServerList) {
    990     Item = NET_LIST_USER_STRUCT (Entry, DNS6_SERVER_IP, AllServerLink);
    991     if (CompareMem (&Item->Dns6ServerIp, &ServerIp, sizeof (EFI_IPv6_ADDRESS)) == 0) {
    992       //
    993       // Already done.
    994       //
    995       return EFI_SUCCESS;
    996     }
    997   }
    998 
    999   //
   1000   // Add new one
   1001   //
   1002   NewServerIp = AllocatePool (sizeof (DNS6_SERVER_IP));
   1003   if (NewServerIp == NULL) {
   1004     return EFI_OUT_OF_RESOURCES;
   1005   }
   1006 
   1007   InitializeListHead (&NewServerIp->AllServerLink);
   1008 
   1009   CopyMem (&NewServerIp->Dns6ServerIp, &ServerIp, sizeof (EFI_IPv6_ADDRESS));
   1010 
   1011   InsertTailList (Dns6ServerList, &NewServerIp->AllServerLink);
   1012 
   1013   return EFI_SUCCESS;
   1014 }
   1015 
   1016 /**
   1017   Fill QName for IP querying. QName is a domain name represented as
   1018   a sequence of labels, where each label consists of a length octet
   1019   followed by that number of octets. The domain name terminates with
   1020   the zero length octet for the null label of the root. Caller should
   1021   take responsibility to the buffer in QName.
   1022 
   1023   @param  HostName          Queried HostName
   1024 
   1025   @retval NULL      Failed to fill QName.
   1026   @return           QName filled successfully.
   1027 
   1028 **/
   1029 CHAR8 *
   1030 EFIAPI
   1031 DnsFillinQNameForQueryIp (
   1032   IN  CHAR16              *HostName
   1033   )
   1034 {
   1035   CHAR8                 *QueryName;
   1036   CHAR8                 *Header;
   1037   CHAR8                 *Tail;
   1038   UINTN                 Len;
   1039   UINTN                 Index;
   1040 
   1041   QueryName  = NULL;
   1042   Header     = NULL;
   1043   Tail       = NULL;
   1044 
   1045   QueryName = AllocateZeroPool (DNS_DEFAULT_BLKSIZE);
   1046   if (QueryName == NULL) {
   1047     return NULL;
   1048   }
   1049 
   1050   Header = QueryName;
   1051   Tail = Header + 1;
   1052   Len = 0;
   1053   for (Index = 0; HostName[Index] != 0; Index++) {
   1054     *Tail = (CHAR8) HostName[Index];
   1055     if (*Tail == '.') {
   1056       *Header = (CHAR8) Len;
   1057       Header = Tail;
   1058       Tail ++;
   1059       Len = 0;
   1060     } else {
   1061       Tail++;
   1062       Len++;
   1063     }
   1064   }
   1065   *Header = (CHAR8) Len;
   1066   *Tail = 0;
   1067 
   1068   return QueryName;
   1069 }
   1070 
   1071 /**
   1072   Find out whether the response is valid or invalid.
   1073 
   1074   @param  TokensMap       All DNS transmittal Tokens entry.
   1075   @param  Identification  Identification for queried packet.
   1076   @param  Type            Type for queried packet.
   1077   @param  Item            Return corresponding Token entry.
   1078 
   1079   @retval TRUE            The response is valid.
   1080   @retval FALSE           The response is invalid.
   1081 
   1082 **/
   1083 BOOLEAN
   1084 IsValidDnsResponse (
   1085   IN     NET_MAP      *TokensMap,
   1086   IN     UINT16       Identification,
   1087   IN     UINT16       Type,
   1088      OUT NET_MAP_ITEM **Item
   1089   )
   1090 {
   1091   LIST_ENTRY              *Entry;
   1092 
   1093   NET_BUF                 *Packet;
   1094   UINT8                   *TxString;
   1095   DNS_HEADER              *DnsHeader;
   1096   CHAR8                   *QueryName;
   1097   DNS_QUERY_SECTION       *QuerySection;
   1098 
   1099   NET_LIST_FOR_EACH (Entry, &TokensMap->Used) {
   1100     *Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
   1101     Packet = (NET_BUF *) ((*Item)->Value);
   1102     if (Packet == NULL){
   1103 
   1104       continue;
   1105     } else {
   1106       TxString = NetbufGetByte (Packet, 0, NULL);
   1107       ASSERT (TxString != NULL);
   1108       DnsHeader = (DNS_HEADER *) TxString;
   1109       QueryName = (CHAR8 *) (TxString + sizeof (*DnsHeader));
   1110       QuerySection = (DNS_QUERY_SECTION *) (QueryName + AsciiStrLen (QueryName) + 1);
   1111 
   1112       DnsHeader->Identification = NTOHS (DnsHeader->Identification);
   1113       QuerySection->Type = NTOHS (QuerySection->Type);
   1114 
   1115       if (DnsHeader->Identification == Identification && QuerySection->Type == Type) {
   1116         return TRUE;
   1117       }
   1118     }
   1119   }
   1120 
   1121   *Item =NULL;
   1122 
   1123   return FALSE;
   1124 }
   1125 
   1126 /**
   1127   Parse Dns Response.
   1128 
   1129   @param  Instance              The DNS instance
   1130   @param  RxString              Received buffer.
   1131   @param  Completed             Flag to indicate that Dns response is valid.
   1132 
   1133   @retval EFI_SUCCESS           Parse Dns Response successfully.
   1134   @retval Others                Failed to parse Dns Response.
   1135 
   1136 **/
   1137 EFI_STATUS
   1138 ParseDnsResponse (
   1139   IN OUT DNS_INSTANCE              *Instance,
   1140   IN     UINT8                     *RxString,
   1141      OUT BOOLEAN                   *Completed
   1142   )
   1143 {
   1144   DNS_HEADER            *DnsHeader;
   1145 
   1146   CHAR8                 *QueryName;
   1147   DNS_QUERY_SECTION     *QuerySection;
   1148 
   1149   CHAR8                 *AnswerName;
   1150   DNS_ANSWER_SECTION    *AnswerSection;
   1151   UINT8                 *AnswerData;
   1152 
   1153   NET_MAP_ITEM          *Item;
   1154   DNS4_TOKEN_ENTRY      *Dns4TokenEntry;
   1155   DNS6_TOKEN_ENTRY      *Dns6TokenEntry;
   1156 
   1157   UINT32                IpCount;
   1158   UINT32                RRCount;
   1159   UINT32                AnswerSectionNum;
   1160 
   1161   EFI_IPv4_ADDRESS      *HostAddr4;
   1162   EFI_IPv6_ADDRESS      *HostAddr6;
   1163 
   1164   EFI_DNS4_CACHE_ENTRY  *Dns4CacheEntry;
   1165   EFI_DNS6_CACHE_ENTRY  *Dns6CacheEntry;
   1166 
   1167   DNS_RESOURCE_RECORD   *Dns4RR;
   1168   DNS6_RESOURCE_RECORD  *Dns6RR;
   1169 
   1170   EFI_STATUS            Status;
   1171 
   1172   EFI_TPL               OldTpl;
   1173 
   1174   Item             = NULL;
   1175   Dns4TokenEntry   = NULL;
   1176   Dns6TokenEntry   = NULL;
   1177 
   1178   IpCount          = 0;
   1179   RRCount          = 0;
   1180   AnswerSectionNum = 0;
   1181 
   1182   HostAddr4        = NULL;
   1183   HostAddr6        = NULL;
   1184 
   1185   Dns4CacheEntry   = NULL;
   1186   Dns6CacheEntry   = NULL;
   1187 
   1188   Dns4RR           = NULL;
   1189   Dns6RR           = NULL;
   1190 
   1191   *Completed       = TRUE;
   1192   Status           = EFI_SUCCESS;
   1193 
   1194   //
   1195   // Get header
   1196   //
   1197   DnsHeader = (DNS_HEADER *) RxString;
   1198 
   1199   DnsHeader->Identification = NTOHS (DnsHeader->Identification);
   1200   DnsHeader->Flags.Uint16 = NTOHS (DnsHeader->Flags.Uint16);
   1201   DnsHeader->QuestionsNum = NTOHS (DnsHeader->QuestionsNum);
   1202   DnsHeader->AnswersNum = NTOHS (DnsHeader->AnswersNum);
   1203   DnsHeader->AuthorityNum = NTOHS (DnsHeader->AuthorityNum);
   1204   DnsHeader->AditionalNum = NTOHS (DnsHeader->AditionalNum);
   1205 
   1206   //
   1207   // Get Query name
   1208   //
   1209   QueryName = (CHAR8 *) (RxString + sizeof (*DnsHeader));
   1210 
   1211   //
   1212   // Get query section
   1213   //
   1214   QuerySection = (DNS_QUERY_SECTION *) (QueryName + AsciiStrLen (QueryName) + 1);
   1215   QuerySection->Type = NTOHS (QuerySection->Type);
   1216   QuerySection->Class = NTOHS (QuerySection->Class);
   1217 
   1218   //
   1219   // Get Answer name
   1220   //
   1221   AnswerName = (CHAR8 *) QuerySection + sizeof (*QuerySection);
   1222 
   1223   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1224 
   1225   //
   1226   // Check DnsResponse Validity, if so, also get a valid NET_MAP_ITEM.
   1227   //
   1228   if (Instance->Service->IpVersion == IP_VERSION_4) {
   1229     if (!IsValidDnsResponse (&Instance->Dns4TxTokens, DnsHeader->Identification, QuerySection->Type, &Item)) {
   1230       *Completed = FALSE;
   1231       Status = EFI_ABORTED;
   1232       goto ON_EXIT;
   1233     }
   1234     ASSERT (Item != NULL);
   1235     Dns4TokenEntry = (DNS4_TOKEN_ENTRY *) (Item->Key);
   1236   } else {
   1237     if (!IsValidDnsResponse (&Instance->Dns6TxTokens, DnsHeader->Identification, QuerySection->Type, &Item)) {
   1238       *Completed = FALSE;
   1239       Status = EFI_ABORTED;
   1240       goto ON_EXIT;
   1241     }
   1242     ASSERT (Item != NULL);
   1243     Dns6TokenEntry = (DNS6_TOKEN_ENTRY *) (Item->Key);
   1244   }
   1245 
   1246   //
   1247   // Continue Check Some Errors.
   1248   //
   1249   if (DnsHeader->Flags.Bits.RCode != DNS_FLAGS_RCODE_NO_ERROR || DnsHeader->AnswersNum < 1 || \
   1250       DnsHeader->Flags.Bits.QR != DNS_FLAGS_QR_RESPONSE || QuerySection->Class != DNS_CLASS_INET) {
   1251       Status = EFI_ABORTED;
   1252       goto ON_EXIT;
   1253   }
   1254 
   1255   //
   1256   // Free the sending packet.
   1257   //
   1258   if (Item->Value != NULL) {
   1259     NetbufFree ((NET_BUF *) (Item->Value));
   1260   }
   1261 
   1262   //
   1263   // Do some buffer allocations.
   1264   //
   1265   if (Instance->Service->IpVersion == IP_VERSION_4) {
   1266     ASSERT (Dns4TokenEntry != NULL);
   1267 
   1268     if (Dns4TokenEntry->GeneralLookUp) {
   1269       //
   1270       // It's the GeneralLookUp querying.
   1271       //
   1272       Dns4TokenEntry->Token->RspData.GLookupData = AllocatePool (sizeof (DNS_RESOURCE_RECORD));
   1273       if (Dns4TokenEntry->Token->RspData.GLookupData == NULL) {
   1274         Status = EFI_OUT_OF_RESOURCES;
   1275         goto ON_EXIT;
   1276       }
   1277       Dns4TokenEntry->Token->RspData.GLookupData->RRList = AllocatePool (DnsHeader->AnswersNum * sizeof (DNS_RESOURCE_RECORD));
   1278       if (Dns4TokenEntry->Token->RspData.GLookupData->RRList == NULL) {
   1279         Status = EFI_OUT_OF_RESOURCES;
   1280         goto ON_EXIT;
   1281       }
   1282     } else {
   1283       //
   1284       // It's not the GeneralLookUp querying. Check the Query type.
   1285       //
   1286       if (QuerySection->Type == DNS_TYPE_A) {
   1287         Dns4TokenEntry->Token->RspData.H2AData = AllocatePool (sizeof (DNS_HOST_TO_ADDR_DATA));
   1288         if (Dns4TokenEntry->Token->RspData.H2AData == NULL) {
   1289           Status = EFI_OUT_OF_RESOURCES;
   1290           goto ON_EXIT;
   1291         }
   1292         Dns4TokenEntry->Token->RspData.H2AData->IpList = AllocatePool (DnsHeader->AnswersNum * sizeof (EFI_IPv4_ADDRESS));
   1293         if (Dns4TokenEntry->Token->RspData.H2AData->IpList == NULL) {
   1294           Status = EFI_OUT_OF_RESOURCES;
   1295           goto ON_EXIT;
   1296         }
   1297       } else {
   1298         Status = EFI_UNSUPPORTED;
   1299         goto ON_EXIT;
   1300       }
   1301     }
   1302   } else {
   1303     ASSERT (Dns6TokenEntry != NULL);
   1304 
   1305     if (Dns6TokenEntry->GeneralLookUp) {
   1306       //
   1307       // It's the GeneralLookUp querying.
   1308       //
   1309       Dns6TokenEntry->Token->RspData.GLookupData = AllocatePool (sizeof (DNS_RESOURCE_RECORD));
   1310       if (Dns6TokenEntry->Token->RspData.GLookupData == NULL) {
   1311         Status = EFI_UNSUPPORTED;
   1312         goto ON_EXIT;
   1313       }
   1314       Dns6TokenEntry->Token->RspData.GLookupData->RRList = AllocatePool (DnsHeader->AnswersNum * sizeof (DNS_RESOURCE_RECORD));
   1315       if (Dns6TokenEntry->Token->RspData.GLookupData->RRList == NULL) {
   1316         Status = EFI_UNSUPPORTED;
   1317         goto ON_EXIT;
   1318       }
   1319     } else {
   1320       //
   1321       // It's not the GeneralLookUp querying. Check the Query type.
   1322       //
   1323       if (QuerySection->Type == DNS_TYPE_AAAA) {
   1324         Dns6TokenEntry->Token->RspData.H2AData = AllocatePool (sizeof (DNS6_HOST_TO_ADDR_DATA));
   1325         if (Dns6TokenEntry->Token->RspData.H2AData == NULL) {
   1326           Status = EFI_UNSUPPORTED;
   1327           goto ON_EXIT;
   1328         }
   1329         Dns6TokenEntry->Token->RspData.H2AData->IpList = AllocatePool (DnsHeader->AnswersNum * sizeof (EFI_IPv6_ADDRESS));
   1330         if (Dns6TokenEntry->Token->RspData.H2AData->IpList == NULL) {
   1331           Status = EFI_UNSUPPORTED;
   1332           goto ON_EXIT;
   1333         }
   1334       } else {
   1335         Status = EFI_UNSUPPORTED;
   1336         goto ON_EXIT;
   1337       }
   1338     }
   1339   }
   1340 
   1341   //
   1342   // Processing AnswerSection.
   1343   //
   1344   while (AnswerSectionNum < DnsHeader->AnswersNum) {
   1345     //
   1346     // Answer name should be PTR.
   1347     //
   1348     ASSERT ((*(UINT8 *) AnswerName & 0xC0) == 0xC0);
   1349 
   1350     //
   1351     // Get Answer section.
   1352     //
   1353     AnswerSection = (DNS_ANSWER_SECTION *) (AnswerName + sizeof (UINT16));
   1354     AnswerSection->Type = NTOHS (AnswerSection->Type);
   1355     AnswerSection->Class = NTOHS (AnswerSection->Class);
   1356     AnswerSection->Ttl = NTOHL (AnswerSection->Ttl);
   1357     AnswerSection->DataLength = NTOHS (AnswerSection->DataLength);
   1358 
   1359     //
   1360     // Check whether it's the GeneralLookUp querying.
   1361     //
   1362     if (Instance->Service->IpVersion == IP_VERSION_4 && Dns4TokenEntry->GeneralLookUp) {
   1363       Dns4RR = Dns4TokenEntry->Token->RspData.GLookupData->RRList;
   1364       AnswerData = (UINT8 *) AnswerSection + sizeof (*AnswerSection);
   1365 
   1366       //
   1367       // Fill the ResourceRecord.
   1368       //
   1369       Dns4RR[RRCount].QName = AllocateZeroPool (AsciiStrLen (QueryName) + 1);
   1370       if (Dns4RR[RRCount].QName == NULL) {
   1371         Status = EFI_UNSUPPORTED;
   1372         goto ON_EXIT;
   1373       }
   1374       CopyMem (Dns4RR[RRCount].QName, QueryName, AsciiStrLen (QueryName));
   1375       Dns4RR[RRCount].QType = AnswerSection->Type;
   1376       Dns4RR[RRCount].QClass = AnswerSection->Class;
   1377       Dns4RR[RRCount].TTL = AnswerSection->Ttl;
   1378       Dns4RR[RRCount].DataLength = AnswerSection->DataLength;
   1379       Dns4RR[RRCount].RData = AllocateZeroPool (Dns4RR[RRCount].DataLength);
   1380       if (Dns4RR[RRCount].RData == NULL) {
   1381         Status = EFI_UNSUPPORTED;
   1382         goto ON_EXIT;
   1383       }
   1384       CopyMem (Dns4RR[RRCount].RData, AnswerData, Dns4RR[RRCount].DataLength);
   1385 
   1386       RRCount ++;
   1387     } else if (Instance->Service->IpVersion == IP_VERSION_6 && Dns6TokenEntry->GeneralLookUp) {
   1388       Dns6RR = Dns6TokenEntry->Token->RspData.GLookupData->RRList;
   1389       AnswerData = (UINT8 *) AnswerSection + sizeof (*AnswerSection);
   1390 
   1391       //
   1392       // Fill the ResourceRecord.
   1393       //
   1394       Dns6RR[RRCount].QName = AllocateZeroPool (AsciiStrLen (QueryName) + 1);
   1395       if (Dns6RR[RRCount].QName == NULL) {
   1396         Status = EFI_UNSUPPORTED;
   1397         goto ON_EXIT;
   1398       }
   1399       CopyMem (Dns6RR[RRCount].QName, QueryName, AsciiStrLen (QueryName));
   1400       Dns6RR[RRCount].QType = AnswerSection->Type;
   1401       Dns6RR[RRCount].QClass = AnswerSection->Class;
   1402       Dns6RR[RRCount].TTL = AnswerSection->Ttl;
   1403       Dns6RR[RRCount].DataLength = AnswerSection->DataLength;
   1404       Dns6RR[RRCount].RData = AllocateZeroPool (Dns6RR[RRCount].DataLength);
   1405       if (Dns6RR[RRCount].RData == NULL) {
   1406         Status = EFI_UNSUPPORTED;
   1407         goto ON_EXIT;
   1408       }
   1409       CopyMem (Dns6RR[RRCount].RData, AnswerData, Dns6RR[RRCount].DataLength);
   1410 
   1411       RRCount ++;
   1412     } else {
   1413       //
   1414       // It's not the GeneralLookUp querying.
   1415       // Check the Query type, parse the response packet.
   1416       //
   1417       switch (AnswerSection->Type) {
   1418       case DNS_TYPE_A:
   1419         //
   1420         // This is address entry, get Data.
   1421         //
   1422         ASSERT (Dns4TokenEntry != NULL && AnswerSection->DataLength == 4);
   1423 
   1424         HostAddr4 = Dns4TokenEntry->Token->RspData.H2AData->IpList;
   1425         AnswerData = (UINT8 *) AnswerSection + sizeof (*AnswerSection);
   1426         CopyMem (&HostAddr4[IpCount], AnswerData, sizeof (EFI_IPv4_ADDRESS));
   1427 
   1428         //
   1429         // Update DNS cache dynamically.
   1430         //
   1431         if (Dns4CacheEntry != NULL) {
   1432           if (Dns4CacheEntry->HostName != NULL) {
   1433             FreePool (Dns4CacheEntry->HostName);
   1434           }
   1435 
   1436           if (Dns4CacheEntry->IpAddress != NULL) {
   1437             FreePool (Dns4CacheEntry->IpAddress);
   1438           }
   1439 
   1440           FreePool (Dns4CacheEntry);
   1441         }
   1442 
   1443         //
   1444         // Allocate new CacheEntry pool.
   1445         //
   1446         Dns4CacheEntry = AllocateZeroPool (sizeof (EFI_DNS4_CACHE_ENTRY));
   1447         if (Dns4CacheEntry == NULL) {
   1448           Status = EFI_UNSUPPORTED;
   1449           goto ON_EXIT;
   1450         }
   1451         Dns4CacheEntry->HostName = AllocateZeroPool (2 * (StrLen(Dns4TokenEntry->QueryHostName) + 1));
   1452         if (Dns4CacheEntry->HostName == NULL) {
   1453           Status = EFI_UNSUPPORTED;
   1454           goto ON_EXIT;
   1455         }
   1456         CopyMem (Dns4CacheEntry->HostName, Dns4TokenEntry->QueryHostName, 2 * (StrLen(Dns4TokenEntry->QueryHostName) + 1));
   1457         Dns4CacheEntry->IpAddress = AllocateZeroPool (sizeof (EFI_IPv4_ADDRESS));
   1458         if (Dns4CacheEntry->IpAddress == NULL) {
   1459           Status = EFI_UNSUPPORTED;
   1460           goto ON_EXIT;
   1461         }
   1462         CopyMem (Dns4CacheEntry->IpAddress, AnswerData, sizeof (EFI_IPv4_ADDRESS));
   1463         Dns4CacheEntry->Timeout = AnswerSection->Ttl;
   1464 
   1465         UpdateDns4Cache (&mDriverData->Dns4CacheList, FALSE, TRUE, *Dns4CacheEntry);
   1466 
   1467         IpCount ++;
   1468         break;
   1469       case DNS_TYPE_AAAA:
   1470         //
   1471         // This is address entry, get Data.
   1472         //
   1473         ASSERT (Dns6TokenEntry != NULL && AnswerSection->DataLength == 16);
   1474 
   1475         HostAddr6 = Dns6TokenEntry->Token->RspData.H2AData->IpList;
   1476         AnswerData = (UINT8 *) AnswerSection + sizeof (*AnswerSection);
   1477         CopyMem (&HostAddr6[IpCount], AnswerData, sizeof (EFI_IPv6_ADDRESS));
   1478 
   1479         //
   1480         // Update DNS cache dynamically.
   1481         //
   1482         if (Dns6CacheEntry != NULL) {
   1483           if (Dns6CacheEntry->HostName != NULL) {
   1484             FreePool (Dns6CacheEntry->HostName);
   1485           }
   1486 
   1487           if (Dns6CacheEntry->IpAddress != NULL) {
   1488             FreePool (Dns6CacheEntry->IpAddress);
   1489           }
   1490 
   1491           FreePool (Dns6CacheEntry);
   1492         }
   1493 
   1494         //
   1495         // Allocate new CacheEntry pool.
   1496         //
   1497         Dns6CacheEntry = AllocateZeroPool (sizeof (EFI_DNS6_CACHE_ENTRY));
   1498         if (Dns6CacheEntry == NULL) {
   1499           Status = EFI_UNSUPPORTED;
   1500           goto ON_EXIT;
   1501         }
   1502         Dns6CacheEntry->HostName = AllocateZeroPool (2 * (StrLen(Dns6TokenEntry->QueryHostName) + 1));
   1503         if (Dns6CacheEntry->HostName == NULL) {
   1504           Status = EFI_UNSUPPORTED;
   1505           goto ON_EXIT;
   1506         }
   1507         CopyMem (Dns6CacheEntry->HostName, Dns6TokenEntry->QueryHostName, 2 * (StrLen(Dns6TokenEntry->QueryHostName) + 1));
   1508         Dns6CacheEntry->IpAddress = AllocateZeroPool (sizeof (EFI_IPv6_ADDRESS));
   1509         if (Dns6CacheEntry->IpAddress == NULL) {
   1510           Status = EFI_UNSUPPORTED;
   1511           goto ON_EXIT;
   1512         }
   1513         CopyMem (Dns6CacheEntry->IpAddress, AnswerData, sizeof (EFI_IPv6_ADDRESS));
   1514         Dns6CacheEntry->Timeout = AnswerSection->Ttl;
   1515 
   1516         UpdateDns6Cache (&mDriverData->Dns6CacheList, FALSE, TRUE, *Dns6CacheEntry);
   1517 
   1518         IpCount ++;
   1519         break;
   1520       default:
   1521         Status = EFI_UNSUPPORTED;
   1522         goto ON_EXIT;
   1523       }
   1524     }
   1525 
   1526     //
   1527     // Find next one
   1528     //
   1529     AnswerName = (CHAR8 *) AnswerSection + sizeof (*AnswerSection) + AnswerSection->DataLength;
   1530     AnswerSectionNum ++;
   1531   }
   1532 
   1533   if (Instance->Service->IpVersion == IP_VERSION_4) {
   1534     ASSERT (Dns4TokenEntry != NULL);
   1535 
   1536     if (Dns4TokenEntry->GeneralLookUp) {
   1537       Dns4TokenEntry->Token->RspData.GLookupData->RRCount = RRCount;
   1538     } else {
   1539       if (QuerySection->Type == DNS_TYPE_A) {
   1540         Dns4TokenEntry->Token->RspData.H2AData->IpCount = IpCount;
   1541       } else {
   1542         Status = EFI_UNSUPPORTED;
   1543         goto ON_EXIT;
   1544       }
   1545     }
   1546   } else {
   1547     ASSERT (Dns6TokenEntry != NULL);
   1548 
   1549     if (Dns6TokenEntry->GeneralLookUp) {
   1550       Dns6TokenEntry->Token->RspData.GLookupData->RRCount = RRCount;
   1551     } else {
   1552       if (QuerySection->Type == DNS_TYPE_AAAA) {
   1553         Dns6TokenEntry->Token->RspData.H2AData->IpCount = IpCount;
   1554       } else {
   1555         Status = EFI_UNSUPPORTED;
   1556         goto ON_EXIT;
   1557       }
   1558     }
   1559   }
   1560 
   1561   //
   1562   // Parsing is complete, SignalEvent here.
   1563   //
   1564   if (Instance->Service->IpVersion == IP_VERSION_4) {
   1565     ASSERT (Dns4TokenEntry != NULL);
   1566     Dns4RemoveTokenEntry (&Instance->Dns4TxTokens, Dns4TokenEntry);
   1567     Dns4TokenEntry->Token->Status = EFI_SUCCESS;
   1568     if (Dns4TokenEntry->Token->Event != NULL) {
   1569       gBS->SignalEvent (Dns4TokenEntry->Token->Event);
   1570       DispatchDpc ();
   1571     }
   1572   } else {
   1573     ASSERT (Dns6TokenEntry != NULL);
   1574     Dns6RemoveTokenEntry (&Instance->Dns6TxTokens, Dns6TokenEntry);
   1575     Dns6TokenEntry->Token->Status = EFI_SUCCESS;
   1576     if (Dns6TokenEntry->Token->Event != NULL) {
   1577       gBS->SignalEvent (Dns6TokenEntry->Token->Event);
   1578       DispatchDpc ();
   1579     }
   1580   }
   1581 
   1582   //
   1583   // Free allocated CacheEntry pool.
   1584   //
   1585   if (Dns4CacheEntry != NULL) {
   1586     if (Dns4CacheEntry->HostName != NULL) {
   1587       FreePool (Dns4CacheEntry->HostName);
   1588     }
   1589 
   1590     if (Dns4CacheEntry->IpAddress != NULL) {
   1591       FreePool (Dns4CacheEntry->IpAddress);
   1592     }
   1593 
   1594     FreePool (Dns4CacheEntry);
   1595   }
   1596 
   1597   if (Dns6CacheEntry != NULL) {
   1598     if (Dns6CacheEntry->HostName != NULL) {
   1599       FreePool (Dns6CacheEntry->HostName);
   1600     }
   1601 
   1602     if (Dns6CacheEntry->IpAddress != NULL) {
   1603       FreePool (Dns6CacheEntry->IpAddress);
   1604     }
   1605 
   1606     FreePool (Dns6CacheEntry);
   1607   }
   1608 
   1609 ON_EXIT:
   1610   gBS->RestoreTPL (OldTpl);
   1611   return Status;
   1612 }
   1613 
   1614 /**
   1615   Parse response packet.
   1616 
   1617   @param  Packet                The packets received.
   1618   @param  EndPoint              The local/remote UDP access point
   1619   @param  IoStatus              The status of the UDP receive
   1620   @param  Context               The opaque parameter to the function.
   1621 
   1622 **/
   1623 VOID
   1624 EFIAPI
   1625 DnsOnPacketReceived (
   1626   NET_BUF                   *Packet,
   1627   UDP_END_POINT             *EndPoint,
   1628   EFI_STATUS                IoStatus,
   1629   VOID                      *Context
   1630   )
   1631 {
   1632   DNS_INSTANCE              *Instance;
   1633 
   1634   UINT8                     *RcvString;
   1635 
   1636   BOOLEAN                   Completed;
   1637 
   1638   Instance  = (DNS_INSTANCE *) Context;
   1639   NET_CHECK_SIGNATURE (Instance, DNS_INSTANCE_SIGNATURE);
   1640 
   1641   RcvString = NULL;
   1642   Completed = FALSE;
   1643 
   1644   if (EFI_ERROR (IoStatus)) {
   1645     goto ON_EXIT;
   1646   }
   1647 
   1648   ASSERT (Packet != NULL);
   1649 
   1650   RcvString = NetbufGetByte (Packet, 0, NULL);
   1651   ASSERT (RcvString != NULL);
   1652 
   1653   //
   1654   // Parse Dns Response
   1655   //
   1656   ParseDnsResponse (Instance, RcvString, &Completed);
   1657 
   1658   ON_EXIT:
   1659 
   1660     if (Packet != NULL) {
   1661       NetbufFree (Packet);
   1662     }
   1663 
   1664     if (!Completed) {
   1665       UdpIoRecvDatagram (Instance->UdpIo, DnsOnPacketReceived, Instance, 0);
   1666     }
   1667 }
   1668 
   1669 /**
   1670   Release the net buffer when packet is sent.
   1671 
   1672   @param  Packet                The packets received.
   1673   @param  EndPoint              The local/remote UDP access point
   1674   @param  IoStatus              The status of the UDP receive
   1675   @param  Context               The opaque parameter to the function.
   1676 
   1677 **/
   1678 VOID
   1679 EFIAPI
   1680 DnsOnPacketSent (
   1681   NET_BUF                   *Packet,
   1682   UDP_END_POINT             *EndPoint,
   1683   EFI_STATUS                IoStatus,
   1684   VOID                      *Context
   1685   )
   1686 {
   1687   DNS_INSTANCE              *Instance;
   1688   LIST_ENTRY                *Entry;
   1689   NET_MAP_ITEM              *Item;
   1690   DNS4_TOKEN_ENTRY          *Dns4TokenEntry;
   1691   DNS6_TOKEN_ENTRY          *Dns6TokenEntry;
   1692 
   1693   Dns4TokenEntry = NULL;
   1694   Dns6TokenEntry = NULL;
   1695 
   1696   Instance  = (DNS_INSTANCE *) Context;
   1697   NET_CHECK_SIGNATURE (Instance, DNS_INSTANCE_SIGNATURE);
   1698 
   1699   if (Instance->Service->IpVersion == IP_VERSION_4) {
   1700     NET_LIST_FOR_EACH (Entry, &Instance->Dns4TxTokens.Used) {
   1701       Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
   1702       if (Packet == (NET_BUF *)(Item->Value)) {
   1703         Dns4TokenEntry = ((DNS4_TOKEN_ENTRY *)Item->Key);
   1704         Dns4TokenEntry->PacketToLive = Dns4TokenEntry->Token->RetryInterval;
   1705         break;
   1706       }
   1707     }
   1708   } else {
   1709     NET_LIST_FOR_EACH (Entry, &Instance->Dns6TxTokens.Used) {
   1710       Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
   1711       if (Packet == (NET_BUF *)(Item->Value)) {
   1712         Dns6TokenEntry = ((DNS6_TOKEN_ENTRY *)Item->Key);
   1713         Dns6TokenEntry->PacketToLive = Dns6TokenEntry->Token->RetryInterval;
   1714         break;
   1715       }
   1716     }
   1717   }
   1718 
   1719   NetbufFree (Packet);
   1720 }
   1721 
   1722 /**
   1723   Query request information.
   1724 
   1725   @param  Instance              The DNS instance
   1726   @param  Packet                The packet for querying request information.
   1727 
   1728   @retval EFI_SUCCESS           Query request information successfully.
   1729   @retval Others                Failed to query request information.
   1730 
   1731 **/
   1732 EFI_STATUS
   1733 DoDnsQuery (
   1734   IN  DNS_INSTANCE              *Instance,
   1735   IN  NET_BUF                   *Packet
   1736   )
   1737 {
   1738   EFI_STATUS      Status;
   1739 
   1740   //
   1741   // Ready to receive the DNS response.
   1742   //
   1743   if (Instance->UdpIo->RecvRequest == NULL) {
   1744     Status = UdpIoRecvDatagram (Instance->UdpIo, DnsOnPacketReceived, Instance, 0);
   1745     if (EFI_ERROR (Status)) {
   1746       return Status;
   1747     }
   1748   }
   1749 
   1750   //
   1751   // Transmit the DNS packet.
   1752   //
   1753   NET_GET_REF (Packet);
   1754 
   1755   Status = UdpIoSendDatagram (Instance->UdpIo, Packet, NULL, NULL, DnsOnPacketSent, Instance);
   1756 
   1757   return Status;
   1758 }
   1759 
   1760 /**
   1761   Construct the Packet according query section.
   1762 
   1763   @param  Instance              The DNS instance
   1764   @param  QueryName             Queried Name
   1765   @param  Type                  Queried Type
   1766   @param  Class                 Queried Class
   1767   @param  Packet                The packet for query
   1768 
   1769   @retval EFI_SUCCESS           The packet is constructed.
   1770   @retval Others                Failed to construct the Packet.
   1771 
   1772 **/
   1773 EFI_STATUS
   1774 ConstructDNSQuery (
   1775   IN  DNS_INSTANCE              *Instance,
   1776   IN  CHAR8                     *QueryName,
   1777   IN  UINT16                    Type,
   1778   IN  UINT16                    Class,
   1779   OUT NET_BUF                   **Packet
   1780   )
   1781 {
   1782   NET_FRAGMENT        Frag;
   1783   DNS_HEADER          *DnsHeader;
   1784   DNS_QUERY_SECTION   *DnsQuery;
   1785 
   1786   Frag.Bulk = AllocatePool (DNS_DEFAULT_BLKSIZE * sizeof (UINT8));
   1787   if (Frag.Bulk == NULL) {
   1788     return EFI_OUT_OF_RESOURCES;
   1789   }
   1790 
   1791   //
   1792   // Fill header
   1793   //
   1794   DnsHeader = (DNS_HEADER *) Frag.Bulk;
   1795   DnsHeader->Identification = (UINT16)NET_RANDOM (NetRandomInitSeed());
   1796   DnsHeader->Flags.Uint16 = 0x0000;
   1797   DnsHeader->Flags.Bits.RD = 1;
   1798   DnsHeader->Flags.Bits.OpCode = DNS_FLAGS_OPCODE_STANDARD;
   1799   DnsHeader->Flags.Bits.QR = DNS_FLAGS_QR_QUERY;
   1800   DnsHeader->QuestionsNum = 1;
   1801   DnsHeader->AnswersNum = 0;
   1802   DnsHeader->AuthorityNum = 0;
   1803   DnsHeader->AditionalNum = 0;
   1804 
   1805   DnsHeader->Identification = HTONS (DnsHeader->Identification);
   1806   DnsHeader->Flags.Uint16 = HTONS (DnsHeader->Flags.Uint16);
   1807   DnsHeader->QuestionsNum = HTONS (DnsHeader->QuestionsNum);
   1808   DnsHeader->AnswersNum = HTONS (DnsHeader->AnswersNum);
   1809   DnsHeader->AuthorityNum = HTONS (DnsHeader->AuthorityNum);
   1810   DnsHeader->AditionalNum = HTONS (DnsHeader->AditionalNum);
   1811 
   1812   Frag.Len = sizeof (*DnsHeader);
   1813 
   1814   //
   1815   // Fill Query name
   1816   //
   1817   CopyMem (Frag.Bulk + Frag.Len, QueryName, AsciiStrLen (QueryName));
   1818   Frag.Len = (UINT32) (Frag.Len + AsciiStrLen (QueryName));
   1819   *(Frag.Bulk + Frag.Len) = 0;
   1820   Frag.Len ++;
   1821 
   1822   //
   1823   // Rest query section
   1824   //
   1825   DnsQuery = (DNS_QUERY_SECTION *) (Frag.Bulk + Frag.Len);
   1826 
   1827   DnsQuery->Type = HTONS (Type);
   1828   DnsQuery->Class = HTONS (Class);
   1829 
   1830   Frag.Len += sizeof (*DnsQuery);
   1831 
   1832   //
   1833   // Wrap the Frag in a net buffer.
   1834   //
   1835   *Packet = NetbufFromExt (&Frag, 1, 0, 0, DnsDummyExtFree, NULL);
   1836   if (*Packet == NULL) {
   1837     FreePool (Frag.Bulk);
   1838     return EFI_OUT_OF_RESOURCES;
   1839   }
   1840 
   1841   //
   1842   // Store the UdpIo in ProtoData.
   1843   //
   1844   *((UINTN *) &((*Packet)->ProtoData[0])) = (UINTN) (Instance->UdpIo);
   1845 
   1846   return EFI_SUCCESS;
   1847 }
   1848 
   1849 /**
   1850   Retransmit the packet.
   1851 
   1852   @param  Instance              The DNS instance
   1853   @param  Packet                Retransmit the packet
   1854 
   1855   @retval EFI_SUCCESS           The packet is retransmitted.
   1856   @retval Others                Failed to retransmit.
   1857 
   1858 **/
   1859 EFI_STATUS
   1860 DnsRetransmit (
   1861   IN DNS_INSTANCE        *Instance,
   1862   IN NET_BUF             *Packet
   1863   )
   1864 {
   1865   EFI_STATUS      Status;
   1866 
   1867   UINT8           *Buffer;
   1868 
   1869   ASSERT (Packet != NULL);
   1870 
   1871   //
   1872   // Set the requests to the listening port, other packets to the connected port
   1873   //
   1874   Buffer = NetbufGetByte (Packet, 0, NULL);
   1875   ASSERT (Buffer != NULL);
   1876 
   1877   NET_GET_REF (Packet);
   1878 
   1879   Status = UdpIoSendDatagram (
   1880              Instance->UdpIo,
   1881              Packet,
   1882              NULL,
   1883              NULL,
   1884              DnsOnPacketSent,
   1885              Instance
   1886              );
   1887 
   1888   if (EFI_ERROR (Status)) {
   1889     NET_PUT_REF (Packet);
   1890   }
   1891 
   1892   return Status;
   1893 }
   1894 
   1895 /**
   1896   The timer ticking function for the DNS services.
   1897 
   1898   @param  Event                 The ticking event
   1899   @param  Context               The DNS service instance
   1900 
   1901 **/
   1902 VOID
   1903 EFIAPI
   1904 DnsOnTimerRetransmit (
   1905   IN EFI_EVENT              Event,
   1906   IN VOID                   *Context
   1907   )
   1908 {
   1909   DNS_SERVICE                *Service;
   1910 
   1911   LIST_ENTRY                 *Entry;
   1912   LIST_ENTRY                 *Next;
   1913 
   1914   DNS_INSTANCE               *Instance;
   1915   LIST_ENTRY                 *EntryNetMap;
   1916   NET_MAP_ITEM               *ItemNetMap;
   1917   DNS4_TOKEN_ENTRY           *Dns4TokenEntry;
   1918   DNS6_TOKEN_ENTRY           *Dns6TokenEntry;
   1919 
   1920   Dns4TokenEntry = NULL;
   1921   Dns6TokenEntry = NULL;
   1922 
   1923   Service = (DNS_SERVICE *) Context;
   1924 
   1925 
   1926   if (Service->IpVersion == IP_VERSION_4) {
   1927     //
   1928     // Iterate through all the children of the DNS service instance. Time
   1929     // out the packet. If maximum retries reached, clean the Token up.
   1930     //
   1931     NET_LIST_FOR_EACH_SAFE (Entry, Next, &Service->Dns4ChildrenList) {
   1932       Instance = NET_LIST_USER_STRUCT (Entry, DNS_INSTANCE, Link);
   1933 
   1934       EntryNetMap = Instance->Dns4TxTokens.Used.ForwardLink;
   1935       while (EntryNetMap != &Instance->Dns4TxTokens.Used) {
   1936         ItemNetMap = NET_LIST_USER_STRUCT (EntryNetMap, NET_MAP_ITEM, Link);
   1937         Dns4TokenEntry = (DNS4_TOKEN_ENTRY *)(ItemNetMap->Key);
   1938         if (Dns4TokenEntry->PacketToLive == 0 || (--Dns4TokenEntry->PacketToLive > 0)) {
   1939           EntryNetMap = EntryNetMap->ForwardLink;
   1940           continue;
   1941         }
   1942 
   1943         //
   1944         // Retransmit the packet if haven't reach the maxmium retry count,
   1945         // otherwise exit the transfer.
   1946         //
   1947         if (++Dns4TokenEntry->Token->RetryCount < Instance->MaxRetry) {
   1948           DnsRetransmit (Instance, (NET_BUF *)ItemNetMap->Value);
   1949           EntryNetMap = EntryNetMap->ForwardLink;
   1950         } else {
   1951           //
   1952           // Maximum retries reached, clean the Token up.
   1953           //
   1954           Dns4RemoveTokenEntry (&Instance->Dns4TxTokens, Dns4TokenEntry);
   1955           Dns4TokenEntry->Token->Status = EFI_TIMEOUT;
   1956           gBS->SignalEvent (Dns4TokenEntry->Token->Event);
   1957           DispatchDpc ();
   1958 
   1959           //
   1960           // Free the sending packet.
   1961           //
   1962           if (ItemNetMap->Value != NULL) {
   1963             NetbufFree ((NET_BUF *)(ItemNetMap->Value));
   1964           }
   1965 
   1966           EntryNetMap = Instance->Dns4TxTokens.Used.ForwardLink;
   1967         }
   1968       }
   1969     }
   1970   }else {
   1971     //
   1972     // Iterate through all the children of the DNS service instance. Time
   1973     // out the packet. If maximum retries reached, clean the Token up.
   1974     //
   1975     NET_LIST_FOR_EACH_SAFE (Entry, Next, &Service->Dns6ChildrenList) {
   1976       Instance = NET_LIST_USER_STRUCT (Entry, DNS_INSTANCE, Link);
   1977 
   1978       EntryNetMap = Instance->Dns6TxTokens.Used.ForwardLink;
   1979       while (EntryNetMap != &Instance->Dns6TxTokens.Used) {
   1980         ItemNetMap = NET_LIST_USER_STRUCT (EntryNetMap, NET_MAP_ITEM, Link);
   1981         Dns6TokenEntry = (DNS6_TOKEN_ENTRY *) (ItemNetMap->Key);
   1982         if (Dns6TokenEntry->PacketToLive == 0 || (--Dns6TokenEntry->PacketToLive > 0)) {
   1983           EntryNetMap = EntryNetMap->ForwardLink;
   1984           continue;
   1985         }
   1986 
   1987         //
   1988         // Retransmit the packet if haven't reach the maxmium retry count,
   1989         // otherwise exit the transfer.
   1990         //
   1991         if (++Dns6TokenEntry->Token->RetryCount < Instance->MaxRetry) {
   1992           DnsRetransmit (Instance, (NET_BUF *) ItemNetMap->Value);
   1993           EntryNetMap = EntryNetMap->ForwardLink;
   1994         } else {
   1995           //
   1996           // Maximum retries reached, clean the Token up.
   1997           //
   1998           Dns6RemoveTokenEntry (&Instance->Dns6TxTokens, Dns6TokenEntry);
   1999           Dns6TokenEntry->Token->Status = EFI_TIMEOUT;
   2000           gBS->SignalEvent (Dns6TokenEntry->Token->Event);
   2001           DispatchDpc ();
   2002 
   2003           //
   2004           // Free the sending packet.
   2005           //
   2006           if (ItemNetMap->Value != NULL) {
   2007             NetbufFree ((NET_BUF *) (ItemNetMap->Value));
   2008           }
   2009 
   2010           EntryNetMap = Instance->Dns6TxTokens.Used.ForwardLink;
   2011         }
   2012       }
   2013     }
   2014   }
   2015 }
   2016 
   2017 /**
   2018   The timer ticking function for the DNS driver.
   2019 
   2020   @param  Event                 The ticking event
   2021   @param  Context               NULL
   2022 
   2023 **/
   2024 VOID
   2025 EFIAPI
   2026 DnsOnTimerUpdate (
   2027   IN EFI_EVENT              Event,
   2028   IN VOID                   *Context
   2029   )
   2030 {
   2031   LIST_ENTRY                 *Entry;
   2032   LIST_ENTRY                 *Next;
   2033   DNS4_CACHE                 *Item4;
   2034   DNS6_CACHE                 *Item6;
   2035 
   2036   Item4 = NULL;
   2037   Item6 = NULL;
   2038 
   2039   //
   2040   // Iterate through all the DNS4 cache list.
   2041   //
   2042   NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns4CacheList) {
   2043     Item4 = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink);
   2044     Item4->DnsCache.Timeout--;
   2045   }
   2046 
   2047   Entry = mDriverData->Dns4CacheList.ForwardLink;
   2048   while (Entry != &mDriverData->Dns4CacheList) {
   2049     Item4 = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink);
   2050     if (Item4->DnsCache.Timeout<=0) {
   2051       RemoveEntryList (&Item4->AllCacheLink);
   2052       Entry = mDriverData->Dns4CacheList.ForwardLink;
   2053     } else {
   2054       Entry = Entry->ForwardLink;
   2055     }
   2056   }
   2057 
   2058   //
   2059   // Iterate through all the DNS6 cache list.
   2060   //
   2061   NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns6CacheList) {
   2062     Item6 = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink);
   2063     Item6->DnsCache.Timeout--;
   2064   }
   2065 
   2066   Entry = mDriverData->Dns6CacheList.ForwardLink;
   2067   while (Entry != &mDriverData->Dns6CacheList) {
   2068     Item6 = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink);
   2069     if (Item6->DnsCache.Timeout<=0) {
   2070       RemoveEntryList (&Item6->AllCacheLink);
   2071       Entry = mDriverData->Dns6CacheList.ForwardLink;
   2072     } else {
   2073       Entry = Entry->ForwardLink;
   2074     }
   2075   }
   2076 }
   2077 
   2078