Home | History | Annotate | Download | only in DnsDxe
      1 /** @file
      2 Implementation of EFI_DNS4_PROTOCOL and EFI_DNS6_PROTOCOL interfaces.
      3 
      4 Copyright (c) 2015 - 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 EFI_DNS4_PROTOCOL  mDns4Protocol = {
     18   Dns4GetModeData,
     19   Dns4Configure,
     20   Dns4HostNameToIp,
     21   Dns4IpToHostName,
     22   Dns4GeneralLookUp,
     23   Dns4UpdateDnsCache,
     24   Dns4Poll,
     25   Dns4Cancel
     26 };
     27 
     28 EFI_DNS6_PROTOCOL  mDns6Protocol = {
     29   Dns6GetModeData,
     30   Dns6Configure,
     31   Dns6HostNameToIp,
     32   Dns6IpToHostName,
     33   Dns6GeneralLookUp,
     34   Dns6UpdateDnsCache,
     35   Dns6Poll,
     36   Dns6Cancel
     37 };
     38 
     39 /**
     40   Retrieve mode data of this DNS instance.
     41 
     42   This function is used to retrieve DNS mode data for this DNS instance.
     43 
     44   @param[in]   This               Pointer to EFI_DNS4_PROTOCOL instance.
     45   @param[out]  DnsModeData        Point to the mode data.
     46 
     47   @retval EFI_SUCCESS             The operation completed successfully.
     48   @retval EFI_NOT_STARTED         When DnsConfigData is queried, no configuration data
     49                                   is available because this instance has not been
     50                                   configured.
     51   @retval EFI_INVALID_PARAMETER   This is NULL or DnsModeData is NULL.
     52   @retval EFI_OUT_OF_RESOURCES    Failed to allocate needed resources.
     53 **/
     54 EFI_STATUS
     55 EFIAPI
     56 Dns4GetModeData (
     57   IN  EFI_DNS4_PROTOCOL          *This,
     58   OUT EFI_DNS4_MODE_DATA         *DnsModeData
     59   )
     60 {
     61   DNS_INSTANCE         *Instance;
     62 
     63   EFI_TPL              OldTpl;
     64 
     65   UINTN                Index;
     66 
     67   LIST_ENTRY           *Entry;
     68   LIST_ENTRY           *Next;
     69 
     70   DNS4_SERVER_IP       *ServerItem;
     71   EFI_IPv4_ADDRESS     *ServerList;
     72   DNS4_CACHE           *CacheItem;
     73   EFI_DNS4_CACHE_ENTRY *CacheList;
     74   EFI_STATUS           Status;
     75 
     76   ServerItem = NULL;
     77   ServerList = NULL;
     78   CacheItem  = NULL;
     79   CacheList  = NULL;
     80   Status     = EFI_SUCCESS;
     81 
     82 
     83   if ((This == NULL) || (DnsModeData == NULL)) {
     84     return EFI_INVALID_PARAMETER;
     85   }
     86 
     87   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
     88 
     89   Instance = DNS_INSTANCE_FROM_THIS_PROTOCOL4 (This);
     90   if (Instance->State == DNS_STATE_UNCONFIGED) {
     91     Status = EFI_NOT_STARTED;
     92     goto ON_EXIT;
     93   }
     94 
     95   ZeroMem (DnsModeData, sizeof (EFI_DNS4_MODE_DATA));
     96 
     97   //
     98   // Get the current configuration data of this instance.
     99   //
    100   Status = Dns4CopyConfigure (&DnsModeData->DnsConfigData, &Instance->Dns4CfgData);
    101   if (EFI_ERROR (Status)) {
    102     goto ON_EXIT;
    103   }
    104 
    105   //
    106   // Get the DnsServerCount and DnsServerList
    107   //
    108   Index = 0;
    109   NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns4ServerList) {
    110     Index++;
    111   }
    112   DnsModeData->DnsServerCount = (UINT32) Index;
    113   ServerList = AllocatePool (sizeof (EFI_IPv4_ADDRESS) * DnsModeData->DnsServerCount);
    114   if (ServerList == NULL) {
    115     Status = EFI_OUT_OF_RESOURCES;
    116     Dns4CleanConfigure (&DnsModeData->DnsConfigData);
    117     goto ON_EXIT;
    118   }
    119 
    120   Index = 0;
    121   NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns4ServerList) {
    122     ServerItem = NET_LIST_USER_STRUCT (Entry, DNS4_SERVER_IP, AllServerLink);
    123     CopyMem (ServerList + Index, &ServerItem->Dns4ServerIp, sizeof (EFI_IPv4_ADDRESS));
    124     Index++;
    125   }
    126   DnsModeData->DnsServerList = ServerList;
    127 
    128   //
    129   // Get the DnsCacheCount and DnsCacheList
    130   //
    131   Index =0;
    132   NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns4CacheList) {
    133     Index++;
    134   }
    135   DnsModeData->DnsCacheCount = (UINT32) Index;
    136   CacheList = AllocatePool (sizeof (EFI_DNS4_CACHE_ENTRY) * DnsModeData->DnsCacheCount);
    137   if (CacheList == NULL) {
    138     Status = EFI_OUT_OF_RESOURCES;
    139     Dns4CleanConfigure (&DnsModeData->DnsConfigData);
    140     FreePool (ServerList);
    141     goto ON_EXIT;
    142   }
    143 
    144   Index =0;
    145   NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns4CacheList) {
    146     CacheItem = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink);
    147     CopyMem (CacheList + Index, &CacheItem->DnsCache, sizeof (EFI_DNS4_CACHE_ENTRY));
    148     Index++;
    149   }
    150   DnsModeData->DnsCacheList = CacheList;
    151 
    152 ON_EXIT:
    153   gBS->RestoreTPL (OldTpl);
    154   return Status;
    155 }
    156 
    157 /**
    158   Configure this DNS instance.
    159 
    160   This function is used to configure DNS mode data for this DNS instance.
    161 
    162   @param[in]  This                Pointer to EFI_DNS4_PROTOCOL instance.
    163   @param[in]  DnsConfigData       Point to the Configuration data.
    164 
    165   @retval EFI_SUCCESS             The operation completed successfully.
    166   @retval EFI_UNSUPPORTED         The designated protocol is not supported.
    167   @retval EFI_INVALID_PARAMTER    Thisis NULL.
    168                                   The StationIp address provided in DnsConfigData is not a
    169                                   valid unicast.
    170                                   DnsServerList is NULL while DnsServerListCount
    171                                   is not ZERO.
    172                                   DnsServerListCount is ZERO while DnsServerList
    173                                   is not NULL
    174   @retval EFI_OUT_OF_RESOURCES    The DNS instance data or required space could not be
    175                                   allocated.
    176   @retval EFI_DEVICE_ERROR        An unexpected system or network error occurred. The
    177                                   EFI DNSv4 Protocol instance is not configured.
    178   @retval EFI_ALREADY_STARTED     Second call to Configure() with DnsConfigData. To
    179                                   reconfigure the instance the caller must call Configure()
    180                                   with NULL first to return driver to unconfigured state.
    181 **/
    182 EFI_STATUS
    183 EFIAPI
    184 Dns4Configure (
    185   IN EFI_DNS4_PROTOCOL           *This,
    186   IN EFI_DNS4_CONFIG_DATA        *DnsConfigData
    187   )
    188 {
    189   EFI_STATUS                Status;
    190   DNS_INSTANCE              *Instance;
    191 
    192   EFI_TPL                   OldTpl;
    193   IP4_ADDR                  Ip;
    194   IP4_ADDR                  Netmask;
    195 
    196   UINT32                    ServerListCount;
    197   EFI_IPv4_ADDRESS          *ServerList;
    198 
    199   Status     = EFI_SUCCESS;
    200   ServerList = NULL;
    201 
    202   if (This == NULL ||
    203      (DnsConfigData != NULL && ((DnsConfigData->DnsServerListCount != 0 && DnsConfigData->DnsServerList == NULL) ||
    204                                 (DnsConfigData->DnsServerListCount == 0 && DnsConfigData->DnsServerList != NULL)))) {
    205     return EFI_INVALID_PARAMETER;
    206   }
    207 
    208   if (DnsConfigData != NULL && DnsConfigData->Protocol != DNS_PROTOCOL_UDP) {
    209     return EFI_UNSUPPORTED;
    210   }
    211 
    212   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    213 
    214   Instance = DNS_INSTANCE_FROM_THIS_PROTOCOL4 (This);
    215 
    216   if (DnsConfigData == NULL) {
    217     ZeroMem (&Instance->SessionDnsServer, sizeof (EFI_IP_ADDRESS));
    218 
    219     //
    220     // Reset the Instance if ConfigData is NULL
    221     //
    222     if (!NetMapIsEmpty(&Instance->Dns4TxTokens)) {
    223       Dns4InstanceCancelToken(Instance, NULL);
    224     }
    225 
    226     Instance->MaxRetry = 0;
    227 
    228     if (Instance->UdpIo != NULL){
    229       UdpIoCleanIo (Instance->UdpIo);
    230     }
    231 
    232     if (Instance->Dns4CfgData.DnsServerList != NULL) {
    233       FreePool (Instance->Dns4CfgData.DnsServerList);
    234     }
    235     ZeroMem (&Instance->Dns4CfgData, sizeof (EFI_DNS4_CONFIG_DATA));
    236 
    237     Instance->State = DNS_STATE_UNCONFIGED;
    238   } else {
    239     //
    240     // Configure the parameters for new operation.
    241     //
    242     CopyMem (&Ip, &DnsConfigData->StationIp, sizeof (IP4_ADDR));
    243     CopyMem (&Netmask, &DnsConfigData->SubnetMask, sizeof (IP4_ADDR));
    244 
    245     Ip       = NTOHL (Ip);
    246     Netmask  = NTOHL (Netmask);
    247 
    248     if (!DnsConfigData->UseDefaultSetting &&
    249        ((!IP4_IS_VALID_NETMASK (Netmask) || !NetIp4IsUnicast (Ip, Netmask)))) {
    250       Status = EFI_INVALID_PARAMETER;
    251       goto ON_EXIT;
    252     }
    253 
    254     Status = Dns4CopyConfigure (&Instance->Dns4CfgData, DnsConfigData);
    255     if (EFI_ERROR (Status)) {
    256       goto ON_EXIT;
    257     }
    258 
    259     if (DnsConfigData->DnsServerListCount == 0 || DnsConfigData->DnsServerList == NULL) {
    260       gBS->RestoreTPL (OldTpl);
    261 
    262       //
    263       // The DNS instance will retrieve DNS server from DHCP Server
    264       //
    265       Status = GetDns4ServerFromDhcp4 (
    266                  Instance,
    267                  &ServerListCount,
    268                  &ServerList
    269                  );
    270       if (EFI_ERROR (Status)) {
    271         return Status;
    272       }
    273 
    274       ASSERT(ServerList != NULL);
    275 
    276       OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    277 
    278       CopyMem (&Instance->SessionDnsServer.v4, &ServerList[0], sizeof (EFI_IPv4_ADDRESS));
    279     } else {
    280       CopyMem (&Instance->SessionDnsServer.v4, &DnsConfigData->DnsServerList[0], sizeof (EFI_IPv4_ADDRESS));
    281     }
    282 
    283     //
    284     // Config UDP
    285     //
    286     Status = Dns4ConfigUdp (Instance, Instance->UdpIo);
    287     if (EFI_ERROR (Status)) {
    288       if (Instance->Dns4CfgData.DnsServerList != NULL) {
    289         FreePool (Instance->Dns4CfgData.DnsServerList);
    290         Instance->Dns4CfgData.DnsServerList = NULL;
    291       }
    292       goto ON_EXIT;
    293     }
    294 
    295     //
    296     // Add configured DNS server used by this instance to ServerList.
    297     //
    298     Status = AddDns4ServerIp (&mDriverData->Dns4ServerList, Instance->SessionDnsServer.v4);
    299     if (EFI_ERROR (Status)) {
    300       if (Instance->Dns4CfgData.DnsServerList != NULL) {
    301         FreePool (Instance->Dns4CfgData.DnsServerList);
    302         Instance->Dns4CfgData.DnsServerList = NULL;
    303       }
    304       goto ON_EXIT;
    305     }
    306 
    307     Instance->State = DNS_STATE_CONFIGED;
    308   }
    309 
    310 ON_EXIT:
    311   gBS->RestoreTPL (OldTpl);
    312   return Status;
    313 }
    314 
    315 /**
    316   Host name to host address translation.
    317 
    318   The HostNameToIp () function is used to translate the host name to host IP address. A
    319   type A query is used to get the one or more IP addresses for this host.
    320 
    321   @param[in]  This                Pointer to EFI_DNS4_PROTOCOL instance.
    322   @param[in]  HostName            Host name.
    323   @param[in]  Token               Point to the completion token to translate host name
    324                                   to host address.
    325 
    326   @retval EFI_SUCCESS             The operation completed successfully.
    327   @retval EFI_INVALID_PARAMETER   One or more of the following conditions is TRUE:
    328                                   This is NULL.
    329                                   Token is NULL.
    330                                   Token.Event is NULL.
    331                                   HostName is NULL. HostName string is unsupported format.
    332   @retval EFI_NO_MAPPING          There's no source address is available for use.
    333   @retval EFI_NOT_STARTED         This instance has not been started.
    334 **/
    335 EFI_STATUS
    336 EFIAPI
    337 Dns4HostNameToIp (
    338   IN  EFI_DNS4_PROTOCOL          *This,
    339   IN  CHAR16                     *HostName,
    340   IN  EFI_DNS4_COMPLETION_TOKEN  *Token
    341   )
    342 {
    343   EFI_STATUS            Status;
    344 
    345   DNS_INSTANCE          *Instance;
    346 
    347   EFI_DNS4_CONFIG_DATA  *ConfigData;
    348 
    349   UINTN                 Index;
    350   DNS4_CACHE            *Item;
    351   LIST_ENTRY            *Entry;
    352   LIST_ENTRY            *Next;
    353 
    354   CHAR8                 *QueryName;
    355 
    356   DNS4_TOKEN_ENTRY      *TokenEntry;
    357   NET_BUF               *Packet;
    358 
    359   EFI_TPL               OldTpl;
    360 
    361   Status     = EFI_SUCCESS;
    362   Item       = NULL;
    363   QueryName  = NULL;
    364   TokenEntry = NULL;
    365   Packet     = NULL;
    366 
    367   //
    368   // Validate the parameters
    369   //
    370   if ((This == NULL) || (HostName == NULL) || Token == NULL) {
    371     return EFI_INVALID_PARAMETER;
    372   }
    373 
    374   OldTpl   = gBS->RaiseTPL (TPL_CALLBACK);
    375 
    376   Instance = DNS_INSTANCE_FROM_THIS_PROTOCOL4 (This);
    377 
    378   ConfigData = &(Instance->Dns4CfgData);
    379 
    380   Instance->MaxRetry = ConfigData->RetryCount;
    381 
    382   Token->Status = EFI_NOT_READY;
    383   Token->RetryCount = 0;
    384   Token->RetryInterval = ConfigData->RetryInterval;
    385 
    386   if (Instance->State != DNS_STATE_CONFIGED) {
    387     Status = EFI_NOT_STARTED;
    388     goto ON_EXIT;
    389   }
    390 
    391   //
    392   // Check the MaxRetry and RetryInterval values.
    393   //
    394   if (Instance->MaxRetry == 0) {
    395     Instance->MaxRetry = DNS_DEFAULT_RETRY;
    396   }
    397 
    398   if (Token->RetryInterval < DNS_DEFAULT_TIMEOUT) {
    399     Token->RetryInterval = DNS_DEFAULT_TIMEOUT;
    400   }
    401 
    402   //
    403   // Check cache
    404   //
    405   if (ConfigData->EnableDnsCache) {
    406     Index = 0;
    407     NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns4CacheList) {
    408       Item = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink);
    409       if (StrCmp (HostName, Item->DnsCache.HostName) == 0) {
    410         Index++;
    411       }
    412     }
    413 
    414     if (Index != 0) {
    415       Token->RspData.H2AData = AllocatePool (sizeof (DNS_HOST_TO_ADDR_DATA));
    416       if (Token->RspData.H2AData == NULL) {
    417         Status = EFI_OUT_OF_RESOURCES;
    418         goto ON_EXIT;
    419       }
    420 
    421       Token->RspData.H2AData->IpCount = (UINT32)Index;
    422       Token->RspData.H2AData->IpList = AllocatePool (sizeof (EFI_IPv4_ADDRESS) * Index);
    423       if (Token->RspData.H2AData->IpList == NULL) {
    424         if (Token->RspData.H2AData != NULL) {
    425           FreePool (Token->RspData.H2AData);
    426         }
    427 
    428         Status = EFI_OUT_OF_RESOURCES;
    429         goto ON_EXIT;
    430       }
    431 
    432       Index = 0;
    433       NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns4CacheList) {
    434         Item = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink);
    435         if ((UINT32)Index < Token->RspData.H2AData->IpCount && StrCmp (HostName, Item->DnsCache.HostName) == 0) {
    436           CopyMem ((Token->RspData.H2AData->IpList) + Index, Item->DnsCache.IpAddress, sizeof (EFI_IPv4_ADDRESS));
    437           Index++;
    438         }
    439       }
    440 
    441       Token->Status = EFI_SUCCESS;
    442 
    443       if (Token->Event != NULL) {
    444         gBS->SignalEvent (Token->Event);
    445         DispatchDpc ();
    446       }
    447 
    448       Status = Token->Status;
    449       goto ON_EXIT;
    450     }
    451   }
    452 
    453   //
    454   // Construct DNS TokenEntry.
    455   //
    456   TokenEntry = AllocateZeroPool (sizeof(DNS4_TOKEN_ENTRY));
    457   if (TokenEntry == NULL) {
    458     Status = EFI_OUT_OF_RESOURCES;
    459     goto ON_EXIT;
    460   }
    461 
    462   TokenEntry->PacketToLive = Token->RetryInterval;
    463   TokenEntry->QueryHostName = HostName;
    464   TokenEntry->Token = Token;
    465 
    466   //
    467   // Construct QName.
    468   //
    469   QueryName = NetLibCreateDnsQName (TokenEntry->QueryHostName);
    470   if (QueryName == NULL) {
    471     Status = EFI_OUT_OF_RESOURCES;
    472     goto ON_EXIT;
    473   }
    474 
    475   //
    476   // Construct DNS Query Packet.
    477   //
    478   Status = ConstructDNSQuery (Instance, QueryName, DNS_TYPE_A, DNS_CLASS_INET, &Packet);
    479   if (EFI_ERROR (Status)) {
    480     if (TokenEntry != NULL) {
    481       FreePool (TokenEntry);
    482     }
    483 
    484     goto ON_EXIT;
    485   }
    486 
    487   ASSERT (Packet != NULL);
    488 
    489   //
    490   // Save the token into the Dns4TxTokens map.
    491   //
    492   Status = NetMapInsertTail (&Instance->Dns4TxTokens, TokenEntry, Packet);
    493   if (EFI_ERROR (Status)) {
    494     if (TokenEntry != NULL) {
    495       FreePool (TokenEntry);
    496     }
    497 
    498     NetbufFree (Packet);
    499 
    500     goto ON_EXIT;
    501   }
    502 
    503   //
    504   // Dns Query Ip
    505   //
    506   Status = DoDnsQuery (Instance, Packet);
    507   if (EFI_ERROR (Status)) {
    508     Dns4RemoveTokenEntry (&Instance->Dns4TxTokens, TokenEntry);
    509 
    510     if (TokenEntry != NULL) {
    511       FreePool (TokenEntry);
    512     }
    513 
    514     NetbufFree (Packet);
    515   }
    516 
    517 ON_EXIT:
    518   if (QueryName != NULL) {
    519     FreePool (QueryName);
    520   }
    521 
    522   gBS->RestoreTPL (OldTpl);
    523   return Status;
    524 }
    525 
    526 /**
    527   IPv4 address to host name translation also known as Reverse DNS lookup.
    528 
    529   The IpToHostName() function is used to translate the host address to host name. A type PTR
    530   query is used to get the primary name of the host. Support of this function is optional.
    531 
    532   @param[in]  This                Pointer to EFI_DNS4_PROTOCOL instance.
    533   @param[in]  IpAddress           Ip Address.
    534   @param[in]  Token               Point to the completion token to translate host
    535                                   address to host name.
    536 
    537   @retval EFI_SUCCESS             The operation completed successfully.
    538   @retval EFI_UNSUPPORTED         This function is not supported.
    539   @retval EFI_INVALID_PARAMETER   One or more of the following conditions is TRUE:
    540                                   This is NULL.
    541                                   Token is NULL.
    542                                   Token.Event is NULL.
    543                                   IpAddress is not valid IP address .
    544   @retval EFI_NO_MAPPING          There's no source address is available for use.
    545   @retval EFI_ALREADY_STARTED     This Token is being used in another DNS session.
    546   @retval EFI_OUT_OF_RESOURCES    Failed to allocate needed resources.
    547 **/
    548 EFI_STATUS
    549 EFIAPI
    550 Dns4IpToHostName (
    551   IN  EFI_DNS4_PROTOCOL              *This,
    552   IN  EFI_IPv4_ADDRESS               IpAddress,
    553   IN  EFI_DNS4_COMPLETION_TOKEN      *Token
    554   )
    555 {
    556   return EFI_UNSUPPORTED;
    557 }
    558 
    559 /**
    560   Retrieve arbitrary information from the DNS server.
    561 
    562   This GeneralLookup() function retrieves arbitrary information from the DNS. The caller
    563   supplies a QNAME, QTYPE, and QCLASS, and all of the matching RRs are returned. All
    564   RR content (e.g., TTL) was returned. The caller need parse the returned RR to get
    565   required information. The function is optional.
    566 
    567   @param[in]  This                Pointer to EFI_DNS4_PROTOCOL instance.
    568   @param[in]  QName               Pointer to Query Name.
    569   @param[in]  QType               Query Type.
    570   @param[in]  QClass              Query Name.
    571   @param[in]  Token               Point to the completion token to retrieve arbitrary
    572                                   information.
    573 
    574   @retval EFI_SUCCESS             The operation completed successfully.
    575   @retval EFI_UNSUPPORTED         This function is not supported. Or the requested
    576                                   QType is not supported
    577   @retval EFI_INVALID_PARAMETER   One or more of the following conditions is TRUE:
    578                                   This is NULL.
    579                                   Token is NULL.
    580                                   Token.Event is NULL.
    581                                   QName is NULL.
    582   @retval EFI_NO_MAPPING          There's no source address is available for use.
    583   @retval EFI_ALREADY_STARTED     This Token is being used in another DNS session.
    584   @retval EFI_OUT_OF_RESOURCES    Failed to allocate needed resources.
    585 **/
    586 EFI_STATUS
    587 EFIAPI
    588 Dns4GeneralLookUp (
    589   IN  EFI_DNS4_PROTOCOL                *This,
    590   IN  CHAR8                            *QName,
    591   IN  UINT16                           QType,
    592   IN  UINT16                           QClass,
    593   IN  EFI_DNS4_COMPLETION_TOKEN        *Token
    594   )
    595 {
    596   EFI_STATUS            Status;
    597 
    598   DNS_INSTANCE          *Instance;
    599 
    600   EFI_DNS4_CONFIG_DATA  *ConfigData;
    601 
    602   DNS4_TOKEN_ENTRY      *TokenEntry;
    603   NET_BUF               *Packet;
    604 
    605   EFI_TPL               OldTpl;
    606 
    607   Status     = EFI_SUCCESS;
    608   TokenEntry = NULL;
    609   Packet     = NULL;
    610 
    611   //
    612   // Validate the parameters
    613   //
    614   if ((This == NULL) || (QName == NULL) || Token == NULL) {
    615     return EFI_INVALID_PARAMETER;
    616   }
    617 
    618   OldTpl   = gBS->RaiseTPL (TPL_CALLBACK);
    619 
    620   Instance = DNS_INSTANCE_FROM_THIS_PROTOCOL4 (This);
    621 
    622   ConfigData = &(Instance->Dns4CfgData);
    623 
    624   Instance->MaxRetry = ConfigData->RetryCount;
    625 
    626   Token->Status = EFI_NOT_READY;
    627   Token->RetryCount = 0;
    628   Token->RetryInterval = ConfigData->RetryInterval;
    629 
    630   if (Instance->State != DNS_STATE_CONFIGED) {
    631     Status = EFI_NOT_STARTED;
    632     goto ON_EXIT;
    633   }
    634 
    635   //
    636   // Check the MaxRetry and RetryInterval values.
    637   //
    638   if (Instance->MaxRetry == 0) {
    639     Instance->MaxRetry = DNS_DEFAULT_RETRY;
    640   }
    641 
    642   if (Token->RetryInterval < DNS_DEFAULT_TIMEOUT) {
    643     Token->RetryInterval = DNS_DEFAULT_TIMEOUT;
    644   }
    645 
    646   //
    647   // Construct DNS TokenEntry.
    648   //
    649   TokenEntry = AllocateZeroPool (sizeof(DNS4_TOKEN_ENTRY));
    650   if (TokenEntry == NULL) {
    651     Status = EFI_OUT_OF_RESOURCES;
    652     goto ON_EXIT;
    653   }
    654 
    655   TokenEntry->PacketToLive = Token->RetryInterval;
    656   TokenEntry->GeneralLookUp = TRUE;
    657   TokenEntry->Token = Token;
    658 
    659   //
    660   // Construct DNS Query Packet.
    661   //
    662   Status = ConstructDNSQuery (Instance, QName, QType, QClass, &Packet);
    663   if (EFI_ERROR (Status)) {
    664     if (TokenEntry != NULL) {
    665       FreePool (TokenEntry);
    666     }
    667 
    668     goto ON_EXIT;
    669   }
    670 
    671   ASSERT (Packet != NULL);
    672 
    673   //
    674   // Save the token into the Dns4TxTokens map.
    675   //
    676   Status = NetMapInsertTail (&Instance->Dns4TxTokens, TokenEntry, Packet);
    677   if (EFI_ERROR (Status)) {
    678     if (TokenEntry != NULL) {
    679       FreePool (TokenEntry);
    680     }
    681 
    682     NetbufFree (Packet);
    683 
    684     goto ON_EXIT;
    685   }
    686 
    687   //
    688   // Dns Query Ip
    689   //
    690   Status = DoDnsQuery (Instance, Packet);
    691   if (EFI_ERROR (Status)) {
    692     Dns4RemoveTokenEntry (&Instance->Dns4TxTokens, TokenEntry);
    693 
    694     if (TokenEntry != NULL) {
    695       FreePool (TokenEntry);
    696     }
    697 
    698     NetbufFree (Packet);
    699   }
    700 
    701 ON_EXIT:
    702   gBS->RestoreTPL (OldTpl);
    703   return Status;
    704 }
    705 
    706 /**
    707   This function is to update the DNS Cache.
    708 
    709   The UpdateDnsCache() function is used to add/delete/modify DNS cache entry. DNS cache
    710   can be normally dynamically updated after the DNS resolve succeeds. This function
    711   provided capability to manually add/delete/modify the DNS cache.
    712 
    713   @param[in]  This                Pointer to EFI_DNS4_PROTOCOL instance.
    714   @param[in]  DeleteFlag          If FALSE, this function is to add one entry to the
    715                                   DNS Cahce. If TRUE, this function will delete
    716                                   matching DNS Cache entry.
    717   @param[in]  Override            If TRUE, the maching DNS cache entry will be
    718                                   overwritten with the supplied parameter. If FALSE,
    719                                   EFI_ACCESS_DENIED will be returned if the entry to
    720                                   be added is already existed.
    721   @param[in]  DnsCacheEntry       Pointer to DNS Cache entry.
    722 
    723   @retval EFI_SUCCESS             The operation completed successfully.
    724   @retval EFI_INVALID_PARAMETER   One or more of the following conditions is TRUE:
    725                                   This is NULL.
    726                                   DnsCacheEntry.HostName is NULL.
    727                                   DnsCacheEntry.IpAddress is NULL.
    728                                   DnsCacheEntry.Timeout is zero.
    729   @retval EFI_ACCESS_DENIED       The DNS cache entry already exists and Override is
    730                                   not TRUE.
    731 **/
    732 EFI_STATUS
    733 EFIAPI
    734 Dns4UpdateDnsCache (
    735   IN EFI_DNS4_PROTOCOL      *This,
    736   IN BOOLEAN                DeleteFlag,
    737   IN BOOLEAN                Override,
    738   IN EFI_DNS4_CACHE_ENTRY   DnsCacheEntry
    739   )
    740 {
    741   EFI_STATUS    Status;
    742   EFI_TPL       OldTpl;
    743 
    744   Status = EFI_SUCCESS;
    745 
    746   if (DnsCacheEntry.HostName == NULL || DnsCacheEntry.IpAddress == NULL || DnsCacheEntry.Timeout == 0) {
    747     return EFI_INVALID_PARAMETER;
    748   }
    749 
    750   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    751 
    752   //
    753   // Update Dns4Cache here.
    754   //
    755   Status = UpdateDns4Cache (&mDriverData->Dns4CacheList, DeleteFlag, Override, DnsCacheEntry);
    756 
    757   gBS->RestoreTPL (OldTpl);
    758 
    759   return Status;
    760 }
    761 
    762 /**
    763   Polls for incoming data packets and processes outgoing data packets.
    764 
    765   The Poll() function can be used by network drivers and applications to increase the
    766   rate that data packets are moved between the communications device and the transmit
    767   and receive queues.
    768   In some systems, the periodic timer event in the managed network driver may not poll
    769   the underlying communications device fast enough to transmit and/or receive all data
    770   packets without missing incoming packets or dropping outgoing packets. Drivers and
    771   applications that are experiencing packet loss should try calling the Poll()
    772   function more often.
    773 
    774   @param[in]  This                Pointer to EFI_DNS4_PROTOCOL instance.
    775 
    776   @retval EFI_SUCCESS             Incoming or outgoing data was processed.
    777   @retval EFI_NOT_STARTED         This EFI DNS Protocol instance has not been started.
    778   @retval EFI_INVALID_PARAMETER   This is NULL.
    779   @retval EFI_DEVICE_ERROR        An unexpected system or network error occurred.
    780   @retval EFI_TIMEOUT             Data was dropped out of the transmit and/or receive
    781                                   queue. Consider increasing the polling rate.
    782 **/
    783 EFI_STATUS
    784 EFIAPI
    785 Dns4Poll (
    786   IN EFI_DNS4_PROTOCOL    *This
    787   )
    788 {
    789   DNS_INSTANCE           *Instance;
    790   EFI_UDP4_PROTOCOL      *Udp;
    791 
    792   if (This == NULL) {
    793     return EFI_INVALID_PARAMETER;
    794   }
    795 
    796   Instance = DNS_INSTANCE_FROM_THIS_PROTOCOL4 (This);
    797 
    798   if (Instance->State == DNS_STATE_UNCONFIGED) {
    799     return EFI_NOT_STARTED;
    800   } else if (Instance->State == DNS_STATE_DESTROY) {
    801     return EFI_DEVICE_ERROR;
    802   }
    803 
    804   Udp = Instance->UdpIo->Protocol.Udp4;
    805 
    806   return Udp->Poll (Udp);
    807 }
    808 
    809 /**
    810   Abort an asynchronous DNS operation, including translation between IP and Host, and
    811   general look up behavior.
    812 
    813   The Cancel() function is used to abort a pending resolution request. After calling
    814   this function, Token.Status will be set to EFI_ABORTED and then Token.Event will be
    815   signaled. If the token is not in one of the queues, which usually means that the
    816   asynchronous operation has completed, this function will not signal the token and
    817   EFI_NOT_FOUND is returned.
    818 
    819   @param[in]  This                Pointer to EFI_DNS4_PROTOCOL instance.
    820   @param[in]  Token               Pointer to a token that has been issued by
    821                                   EFI_DNS4_PROTOCOL.HostNameToIp (),
    822                                   EFI_DNS4_PROTOCOL.IpToHostName() or
    823                                   EFI_DNS4_PROTOCOL.GeneralLookup().
    824                                   If NULL, all pending tokens are aborted.
    825 
    826   @retval EFI_SUCCESS             Incoming or outgoing data was processed.
    827   @retval EFI_NOT_STARTED         This EFI DNS4 Protocol instance has not been started.
    828   @retval EFI_INVALID_PARAMETER   This is NULL.
    829   @retval EFI_NOT_FOUND           When Token is not NULL, and the asynchronous DNS
    830                                   operation was not found in the transmit queue. It
    831                                   was either completed or was not issued by
    832                                   HostNameToIp(), IpToHostName() or GeneralLookup().
    833 **/
    834 EFI_STATUS
    835 EFIAPI
    836 Dns4Cancel (
    837   IN  EFI_DNS4_PROTOCOL          *This,
    838   IN  EFI_DNS4_COMPLETION_TOKEN  *Token
    839   )
    840 {
    841   EFI_STATUS          Status;
    842   DNS_INSTANCE        *Instance;
    843   EFI_TPL             OldTpl;
    844 
    845   if (This == NULL) {
    846     return EFI_INVALID_PARAMETER;
    847   }
    848 
    849   Instance = DNS_INSTANCE_FROM_THIS_PROTOCOL4 (This);
    850 
    851   if (Instance->State == DNS_STATE_UNCONFIGED) {
    852     return EFI_NOT_STARTED;
    853   }
    854 
    855   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    856 
    857   //
    858   // Cancle the tokens specified by Token for this instance.
    859   //
    860   Status = Dns4InstanceCancelToken (Instance, Token);
    861 
    862   //
    863   // Dispatch the DPC queued by the NotifyFunction of the canceled token's events.
    864   //
    865   DispatchDpc ();
    866 
    867   gBS->RestoreTPL (OldTpl);
    868 
    869   return Status;
    870 }
    871 
    872 /**
    873   Retrieve mode data of this DNS instance.
    874 
    875   This function is used to retrieve DNS mode data for this DNS instance.
    876 
    877   @param[in]   This                Pointer to EFI_DNS6_PROTOCOL instance.
    878   @param[out]  DnsModeData         Pointer to the caller-allocated storage for the
    879                                    EFI_DNS6_MODE_DATA data.
    880 
    881   @retval EFI_SUCCESS             The operation completed successfully.
    882   @retval EFI_NOT_STARTED         When DnsConfigData is queried, no configuration data
    883                                   is available because this instance has not been
    884                                   configured.
    885   @retval EFI_INVALID_PARAMETER   This is NULL or DnsModeData is NULL.
    886   @retval EFI_OUT_OF_RESOURCE     Failed to allocate needed resources.
    887 **/
    888 EFI_STATUS
    889 EFIAPI
    890 Dns6GetModeData (
    891   IN  EFI_DNS6_PROTOCOL          *This,
    892   OUT EFI_DNS6_MODE_DATA         *DnsModeData
    893   )
    894 {
    895   DNS_INSTANCE         *Instance;
    896 
    897   EFI_TPL              OldTpl;
    898 
    899   UINTN                Index;
    900 
    901   LIST_ENTRY           *Entry;
    902   LIST_ENTRY           *Next;
    903 
    904   DNS6_SERVER_IP       *ServerItem;
    905   EFI_IPv6_ADDRESS     *ServerList;
    906   DNS6_CACHE           *CacheItem;
    907   EFI_DNS6_CACHE_ENTRY *CacheList;
    908   EFI_STATUS           Status;
    909 
    910   ServerItem = NULL;
    911   ServerList = NULL;
    912   CacheItem  = NULL;
    913   CacheList  = NULL;
    914   Status     = EFI_SUCCESS;
    915 
    916   if ((This == NULL) || (DnsModeData == NULL)) {
    917     return EFI_INVALID_PARAMETER;
    918   }
    919 
    920   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
    921 
    922   Instance  = DNS_INSTANCE_FROM_THIS_PROTOCOL6 (This);
    923   if (Instance->State == DNS_STATE_UNCONFIGED) {
    924     Status =  EFI_NOT_STARTED;
    925     goto ON_EXIT;
    926   }
    927 
    928   ZeroMem (DnsModeData, sizeof (EFI_DNS6_MODE_DATA));
    929 
    930   //
    931   // Get the current configuration data of this instance.
    932   //
    933   Status = Dns6CopyConfigure (&DnsModeData->DnsConfigData, &Instance->Dns6CfgData);
    934   if (EFI_ERROR (Status)) {
    935     goto ON_EXIT;
    936   }
    937 
    938   //
    939   // Get the DnsServerCount and DnsServerList
    940   //
    941   Index = 0;
    942   NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns6ServerList) {
    943     Index++;
    944   }
    945   DnsModeData->DnsServerCount = (UINT32) Index;
    946   ServerList = AllocatePool (sizeof(EFI_IPv6_ADDRESS) * DnsModeData->DnsServerCount);
    947   if (ServerList == NULL) {
    948     Status = EFI_OUT_OF_RESOURCES;
    949     Dns6CleanConfigure (&DnsModeData->DnsConfigData);
    950     goto ON_EXIT;
    951   }
    952 
    953   Index = 0;
    954   NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns6ServerList) {
    955     ServerItem = NET_LIST_USER_STRUCT (Entry, DNS6_SERVER_IP, AllServerLink);
    956     CopyMem (ServerList + Index, &ServerItem->Dns6ServerIp, sizeof (EFI_IPv6_ADDRESS));
    957     Index++;
    958   }
    959   DnsModeData->DnsServerList = ServerList;
    960 
    961   //
    962   // Get the DnsCacheCount and DnsCacheList
    963   //
    964   Index =0;
    965   NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns6CacheList) {
    966     Index++;
    967   }
    968   DnsModeData->DnsCacheCount = (UINT32) Index;
    969   CacheList = AllocatePool (sizeof(EFI_DNS6_CACHE_ENTRY) * DnsModeData->DnsCacheCount);
    970   if (CacheList == NULL) {
    971     Status = EFI_OUT_OF_RESOURCES;
    972     Dns6CleanConfigure (&DnsModeData->DnsConfigData);
    973     FreePool (ServerList);
    974     goto ON_EXIT;
    975   }
    976 
    977   Index =0;
    978   NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns6CacheList) {
    979     CacheItem = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink);
    980     CopyMem (CacheList + Index, &CacheItem->DnsCache, sizeof (EFI_DNS6_CACHE_ENTRY));
    981     Index++;
    982   }
    983   DnsModeData->DnsCacheList = CacheList;
    984 
    985 ON_EXIT:
    986   gBS->RestoreTPL (OldTpl);
    987   return Status;
    988 }
    989 
    990 /**
    991   Configure this DNS instance.
    992 
    993   The Configure() function is used to set and change the configuration data for this
    994   EFI DNSv6 Protocol driver instance. Reset the DNS instance if DnsConfigData is NULL.
    995 
    996   @param[in]  This                Pointer to EFI_DNS6_PROTOCOL instance.
    997   @param[in]  DnsConfigData       Pointer to the configuration data structure. All associated
    998                                   storage to be allocated and released by caller.
    999 
   1000   @retval EFI_SUCCESS             The operation completed successfully.
   1001   @retval EFI_INVALID_PARAMTER    This is NULL.
   1002                                   The StationIp address provided in DnsConfigData is not zero and not a valid unicast.
   1003                                   DnsServerList is NULL while DnsServerList Count is not ZERO.
   1004                                   DnsServerList Count is ZERO while DnsServerList is not NULL.
   1005   @retval EFI_OUT_OF_RESOURCES    The DNS instance data or required space could not be allocated.
   1006   @retval EFI_DEVICE_ERROR        An unexpected system or network error occurred. The
   1007                                   EFI DNSv6 Protocol instance is not configured.
   1008   @retval EFI_UNSUPPORTED         The designated protocol is not supported.
   1009   @retval EFI_ALREADY_STARTED     Second call to Configure() with DnsConfigData. To
   1010                                   reconfigure the instance the caller must call Configure() with
   1011                                   NULL first to return driver to unconfigured state.
   1012 **/
   1013 EFI_STATUS
   1014 EFIAPI
   1015 Dns6Configure (
   1016   IN EFI_DNS6_PROTOCOL           *This,
   1017   IN EFI_DNS6_CONFIG_DATA        *DnsConfigData
   1018   )
   1019 {
   1020   EFI_STATUS                Status;
   1021   DNS_INSTANCE              *Instance;
   1022 
   1023   EFI_TPL                   OldTpl;
   1024 
   1025   UINT32                    ServerListCount;
   1026   EFI_IPv6_ADDRESS          *ServerList;
   1027 
   1028   Status     = EFI_SUCCESS;
   1029   ServerList = NULL;
   1030 
   1031   if (This == NULL ||
   1032      (DnsConfigData != NULL && ((DnsConfigData->DnsServerCount != 0 && DnsConfigData->DnsServerList == NULL) ||
   1033                                 (DnsConfigData->DnsServerCount == 0 && DnsConfigData->DnsServerList != NULL)))) {
   1034     return EFI_INVALID_PARAMETER;
   1035   }
   1036 
   1037   if (DnsConfigData != NULL && DnsConfigData->Protocol != DNS_PROTOCOL_UDP) {
   1038     return EFI_UNSUPPORTED;
   1039   }
   1040 
   1041   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1042 
   1043   Instance = DNS_INSTANCE_FROM_THIS_PROTOCOL6 (This);
   1044 
   1045   if (DnsConfigData == NULL) {
   1046     ZeroMem (&Instance->SessionDnsServer, sizeof (EFI_IP_ADDRESS));
   1047 
   1048     //
   1049     // Reset the Instance if ConfigData is NULL
   1050     //
   1051     if (!NetMapIsEmpty(&Instance->Dns6TxTokens)) {
   1052       Dns6InstanceCancelToken(Instance, NULL);
   1053     }
   1054 
   1055     Instance->MaxRetry = 0;
   1056 
   1057     if (Instance->UdpIo != NULL){
   1058       UdpIoCleanIo (Instance->UdpIo);
   1059     }
   1060 
   1061     if (Instance->Dns6CfgData.DnsServerList != NULL) {
   1062       FreePool (Instance->Dns6CfgData.DnsServerList);
   1063     }
   1064     ZeroMem (&Instance->Dns6CfgData, sizeof (EFI_DNS6_CONFIG_DATA));
   1065 
   1066     Instance->State = DNS_STATE_UNCONFIGED;
   1067   } else {
   1068     //
   1069     // Configure the parameters for new operation.
   1070     //
   1071     if (!NetIp6IsUnspecifiedAddr (&DnsConfigData->StationIp) && !NetIp6IsValidUnicast (&DnsConfigData->StationIp)) {
   1072       Status = EFI_INVALID_PARAMETER;
   1073       goto ON_EXIT;
   1074     }
   1075 
   1076     Status = Dns6CopyConfigure (&Instance->Dns6CfgData, DnsConfigData);
   1077     if (EFI_ERROR (Status)) {
   1078       goto ON_EXIT;
   1079     }
   1080 
   1081     if (DnsConfigData->DnsServerCount == 0 || DnsConfigData->DnsServerList == NULL) {
   1082       gBS->RestoreTPL (OldTpl);
   1083 
   1084       //
   1085       //The DNS instance will retrieve DNS server from DHCP Server.
   1086       //
   1087       Status = GetDns6ServerFromDhcp6 (
   1088                  Instance->Service->ImageHandle,
   1089                  Instance->Service->ControllerHandle,
   1090                  &ServerListCount,
   1091                  &ServerList
   1092                  );
   1093       if (EFI_ERROR (Status)) {
   1094         goto ON_EXIT;
   1095       }
   1096 
   1097       ASSERT(ServerList != NULL);
   1098 
   1099       OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1100 
   1101       CopyMem (&Instance->SessionDnsServer.v6, &ServerList[0], sizeof (EFI_IPv6_ADDRESS));
   1102     } else {
   1103       CopyMem (&Instance->SessionDnsServer.v6, &DnsConfigData->DnsServerList[0], sizeof (EFI_IPv6_ADDRESS));
   1104     }
   1105 
   1106     //
   1107     // Config UDP
   1108     //
   1109     Status = Dns6ConfigUdp (Instance, Instance->UdpIo);
   1110     if (EFI_ERROR (Status)) {
   1111       if (Instance->Dns6CfgData.DnsServerList != NULL) {
   1112         FreePool (Instance->Dns6CfgData.DnsServerList);
   1113         Instance->Dns6CfgData.DnsServerList = NULL;
   1114       }
   1115       goto ON_EXIT;
   1116     }
   1117 
   1118     //
   1119     // Add configured DNS server used by this instance to ServerList.
   1120     //
   1121     Status = AddDns6ServerIp (&mDriverData->Dns6ServerList, Instance->SessionDnsServer.v6);
   1122     if (EFI_ERROR (Status)) {
   1123       if (Instance->Dns6CfgData.DnsServerList != NULL) {
   1124         FreePool (Instance->Dns6CfgData.DnsServerList);
   1125         Instance->Dns6CfgData.DnsServerList = NULL;
   1126       }
   1127       goto ON_EXIT;
   1128     }
   1129 
   1130     Instance->State = DNS_STATE_CONFIGED;
   1131   }
   1132 
   1133 ON_EXIT:
   1134   gBS->RestoreTPL (OldTpl);
   1135   return Status;
   1136 }
   1137 
   1138 /**
   1139   Host name to host address translation.
   1140 
   1141   The HostNameToIp () function is used to translate the host name to host IP address. A
   1142   type AAAA query is used to get the one or more IPv6 addresses for this host.
   1143 
   1144   @param[in]  This                Pointer to EFI_DNS6_PROTOCOL instance.
   1145   @param[in]  HostName            Host name.
   1146   @param[in]  Token               Point to the completion token to translate host name
   1147                                   to host address.
   1148 
   1149   @retval EFI_SUCCESS             The operation completed successfully.
   1150   @retval EFI_INVALID_PARAMETER   One or more of the following conditions is TRUE:
   1151                                   This is NULL.
   1152                                   Token is NULL.
   1153                                   Token.Event is NULL.
   1154                                   HostName is NULL or buffer contained unsupported characters.
   1155   @retval EFI_NO_MAPPING          There's no source address is available for use.
   1156   @retval EFI_ALREADY_STARTED     This Token is being used in another DNS session.
   1157   @retval EFI_NOT_STARTED         This instance has not been started.
   1158   @retval EFI_OUT_OF_RESOURCES    Failed to allocate needed resources.
   1159 **/
   1160 EFI_STATUS
   1161 EFIAPI
   1162 Dns6HostNameToIp (
   1163   IN  EFI_DNS6_PROTOCOL          *This,
   1164   IN  CHAR16                     *HostName,
   1165   IN  EFI_DNS6_COMPLETION_TOKEN  *Token
   1166   )
   1167 {
   1168   EFI_STATUS            Status;
   1169 
   1170   DNS_INSTANCE          *Instance;
   1171 
   1172   EFI_DNS6_CONFIG_DATA  *ConfigData;
   1173 
   1174   UINTN                 Index;
   1175   DNS6_CACHE            *Item;
   1176   LIST_ENTRY            *Entry;
   1177   LIST_ENTRY            *Next;
   1178 
   1179   CHAR8                 *QueryName;
   1180 
   1181   DNS6_TOKEN_ENTRY      *TokenEntry;
   1182   NET_BUF               *Packet;
   1183 
   1184   EFI_TPL               OldTpl;
   1185 
   1186   Status     = EFI_SUCCESS;
   1187   Item       = NULL;
   1188   QueryName  = NULL;
   1189   TokenEntry = NULL;
   1190   Packet     = NULL;
   1191 
   1192   //
   1193   // Validate the parameters
   1194   //
   1195   if ((This == NULL) || (HostName == NULL) || Token == NULL) {
   1196     return EFI_INVALID_PARAMETER;
   1197   }
   1198 
   1199   OldTpl   = gBS->RaiseTPL (TPL_CALLBACK);
   1200 
   1201   Instance = DNS_INSTANCE_FROM_THIS_PROTOCOL6 (This);
   1202 
   1203   ConfigData = &(Instance->Dns6CfgData);
   1204 
   1205   Instance->MaxRetry = ConfigData->RetryCount;
   1206 
   1207   Token->Status = EFI_NOT_READY;
   1208   Token->RetryCount = 0;
   1209   Token->RetryInterval = ConfigData->RetryInterval;
   1210 
   1211   if (Instance->State != DNS_STATE_CONFIGED) {
   1212     Status = EFI_NOT_STARTED;
   1213     goto ON_EXIT;
   1214   }
   1215 
   1216   //
   1217   // Check the MaxRetry and RetryInterval values.
   1218   //
   1219   if (Instance->MaxRetry == 0) {
   1220     Instance->MaxRetry = DNS_DEFAULT_RETRY;
   1221   }
   1222 
   1223   if (Token->RetryInterval < DNS_DEFAULT_TIMEOUT) {
   1224     Token->RetryInterval = DNS_DEFAULT_TIMEOUT;
   1225   }
   1226 
   1227   //
   1228   // Check cache
   1229   //
   1230   if (ConfigData->EnableDnsCache) {
   1231     Index = 0;
   1232     NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns6CacheList) {
   1233       Item = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink);
   1234       if (StrCmp (HostName, Item->DnsCache.HostName) == 0) {
   1235         Index++;
   1236       }
   1237     }
   1238 
   1239     if (Index != 0) {
   1240       Token->RspData.H2AData = AllocatePool (sizeof (DNS6_HOST_TO_ADDR_DATA));
   1241       if (Token->RspData.H2AData == NULL) {
   1242         Status = EFI_OUT_OF_RESOURCES;
   1243         goto ON_EXIT;
   1244       }
   1245 
   1246       Token->RspData.H2AData->IpCount = (UINT32)Index;
   1247       Token->RspData.H2AData->IpList = AllocatePool (sizeof (EFI_IPv6_ADDRESS) * Index);
   1248       if (Token->RspData.H2AData->IpList == NULL) {
   1249         if (Token->RspData.H2AData != NULL) {
   1250           FreePool (Token->RspData.H2AData);
   1251         }
   1252 
   1253         Status = EFI_OUT_OF_RESOURCES;
   1254         goto ON_EXIT;
   1255       }
   1256 
   1257       Index = 0;
   1258       NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns6CacheList) {
   1259         Item = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink);
   1260         if ((UINT32)Index < Token->RspData.H2AData->IpCount && StrCmp (HostName, Item->DnsCache.HostName) == 0) {
   1261           CopyMem ((Token->RspData.H2AData->IpList) + Index, Item->DnsCache.IpAddress, sizeof (EFI_IPv6_ADDRESS));
   1262           Index++;
   1263         }
   1264       }
   1265 
   1266       Token->Status = EFI_SUCCESS;
   1267 
   1268       if (Token->Event != NULL) {
   1269         gBS->SignalEvent (Token->Event);
   1270         DispatchDpc ();
   1271       }
   1272 
   1273       Status = Token->Status;
   1274       goto ON_EXIT;
   1275     }
   1276   }
   1277 
   1278   //
   1279   // Construct DNS TokenEntry.
   1280   //
   1281   TokenEntry = AllocateZeroPool (sizeof (DNS6_TOKEN_ENTRY));
   1282   if (TokenEntry == NULL) {
   1283     Status = EFI_OUT_OF_RESOURCES;
   1284     goto ON_EXIT;
   1285   }
   1286 
   1287   TokenEntry->PacketToLive = Token->RetryInterval;
   1288   TokenEntry->QueryHostName = HostName;
   1289   TokenEntry->Token = Token;
   1290 
   1291 
   1292   //
   1293   // Construct QName.
   1294   //
   1295   QueryName = NetLibCreateDnsQName (TokenEntry->QueryHostName);
   1296   if (QueryName == NULL) {
   1297     Status = EFI_OUT_OF_RESOURCES;
   1298     goto ON_EXIT;
   1299   }
   1300 
   1301   //
   1302   // Construct DNS Query Packet.
   1303   //
   1304   Status = ConstructDNSQuery (Instance, QueryName, DNS_TYPE_AAAA, DNS_CLASS_INET, &Packet);
   1305   if (EFI_ERROR (Status)) {
   1306     if (TokenEntry != NULL) {
   1307       FreePool (TokenEntry);
   1308     }
   1309 
   1310     goto ON_EXIT;
   1311   }
   1312 
   1313   ASSERT (Packet != NULL);
   1314 
   1315   //
   1316   // Save the token into the Dns6TxTokens map.
   1317   //
   1318   Status = NetMapInsertTail (&Instance->Dns6TxTokens, TokenEntry, Packet);
   1319   if (EFI_ERROR (Status)) {
   1320     if (TokenEntry != NULL) {
   1321       FreePool (TokenEntry);
   1322     }
   1323 
   1324     NetbufFree (Packet);
   1325 
   1326     goto ON_EXIT;
   1327   }
   1328 
   1329   //
   1330   // Dns Query Ip
   1331   //
   1332   Status = DoDnsQuery (Instance, Packet);
   1333   if (EFI_ERROR (Status)) {
   1334     Dns6RemoveTokenEntry (&Instance->Dns6TxTokens, TokenEntry);
   1335 
   1336     if (TokenEntry != NULL) {
   1337       FreePool (TokenEntry);
   1338     }
   1339 
   1340     NetbufFree (Packet);
   1341   }
   1342 
   1343 ON_EXIT:
   1344   if (QueryName != NULL) {
   1345     FreePool (QueryName);
   1346   }
   1347 
   1348   gBS->RestoreTPL (OldTpl);
   1349   return Status;
   1350 }
   1351 
   1352 /**
   1353   Host address to host name translation.
   1354 
   1355   The IpToHostName () function is used to translate the host address to host name. A
   1356   type PTR query is used to get the primary name of the host. Implementation can choose
   1357   to support this function or not.
   1358 
   1359   @param[in]  This                Pointer to EFI_DNS6_PROTOCOL instance.
   1360   @param[in]  IpAddress           Ip Address.
   1361   @param[in]  Token               Point to the completion token to translate host
   1362                                   address to host name.
   1363 
   1364   @retval EFI_SUCCESS             The operation completed successfully.
   1365   @retval EFI_UNSUPPORTED         This function is not supported.
   1366   @retval EFI_INVALID_PARAMETER   One or more of the following conditions is TRUE:
   1367                                   This is NULL.
   1368                                   Token is NULL.
   1369                                   Token.Event is NULL.
   1370                                   IpAddress is not valid IP address.
   1371   @retval EFI_NO_MAPPING          There's no source address is available for use.
   1372   @retval EFI_NOT_STARTED         This instance has not been started.
   1373   @retval EFI_OUT_OF_RESOURCES    Failed to allocate needed resources.
   1374 **/
   1375 EFI_STATUS
   1376 EFIAPI
   1377 Dns6IpToHostName (
   1378   IN  EFI_DNS6_PROTOCOL              *This,
   1379   IN  EFI_IPv6_ADDRESS               IpAddress,
   1380   IN  EFI_DNS6_COMPLETION_TOKEN      *Token
   1381   )
   1382 {
   1383   return EFI_UNSUPPORTED;
   1384 }
   1385 
   1386 /**
   1387   This function provides capability to retrieve arbitrary information from the DNS
   1388   server.
   1389 
   1390   This GeneralLookup() function retrieves arbitrary information from the DNS. The caller
   1391   supplies a QNAME, QTYPE, and QCLASS, and all of the matching RRs are returned. All
   1392   RR content (e.g., TTL) was returned. The caller need parse the returned RR to get
   1393   required information. The function is optional. Implementation can choose to support
   1394   it or not.
   1395 
   1396   @param[in]  This                Pointer to EFI_DNS6_PROTOCOL instance.
   1397   @param[in]  QName               Pointer to Query Name.
   1398   @param[in]  QType               Query Type.
   1399   @param[in]  QClass              Query Name.
   1400   @param[in]  Token               Point to the completion token to retrieve arbitrary
   1401                                   information.
   1402 
   1403   @retval EFI_SUCCESS             The operation completed successfully.
   1404   @retval EFI_UNSUPPORTED         This function is not supported. Or the requested
   1405                                   QType is not supported
   1406   @retval EFI_INVALID_PARAMETER   One or more of the following conditions is TRUE:
   1407                                   This is NULL.
   1408                                   Token is NULL.
   1409                                   Token.Event is NULL.
   1410                                   QName is NULL.
   1411   @retval EFI_NO_MAPPING          There's no source address is available for use.
   1412   @retval EFI_NOT_STARTED         This instance has not been started.
   1413   @retval EFI_OUT_OF_RESOURCES    Failed to allocate needed resources.
   1414 **/
   1415 EFI_STATUS
   1416 EFIAPI
   1417 Dns6GeneralLookUp (
   1418   IN  EFI_DNS6_PROTOCOL                 *This,
   1419   IN  CHAR8                             *QName,
   1420   IN  UINT16                            QType,
   1421   IN  UINT16                            QClass,
   1422   IN  EFI_DNS6_COMPLETION_TOKEN         *Token
   1423   )
   1424 {
   1425   EFI_STATUS            Status;
   1426 
   1427   DNS_INSTANCE          *Instance;
   1428 
   1429   EFI_DNS6_CONFIG_DATA  *ConfigData;
   1430 
   1431   DNS6_TOKEN_ENTRY      *TokenEntry;
   1432   NET_BUF               *Packet;
   1433 
   1434   EFI_TPL               OldTpl;
   1435 
   1436   Status     = EFI_SUCCESS;
   1437   TokenEntry = NULL;
   1438   Packet     = NULL;
   1439 
   1440   //
   1441   // Validate the parameters
   1442   //
   1443   if ((This == NULL) || (QName == NULL) || Token == NULL) {
   1444     return EFI_INVALID_PARAMETER;
   1445   }
   1446 
   1447   OldTpl   = gBS->RaiseTPL (TPL_CALLBACK);
   1448 
   1449   Instance = DNS_INSTANCE_FROM_THIS_PROTOCOL6 (This);
   1450 
   1451   ConfigData = &(Instance->Dns6CfgData);
   1452 
   1453   Instance->MaxRetry = ConfigData->RetryCount;
   1454 
   1455   Token->Status = EFI_NOT_READY;
   1456   Token->RetryCount = 0;
   1457   Token->RetryInterval = ConfigData->RetryInterval;
   1458 
   1459   if (Instance->State != DNS_STATE_CONFIGED) {
   1460     Status = EFI_NOT_STARTED;
   1461     goto ON_EXIT;
   1462   }
   1463 
   1464   //
   1465   // Check the MaxRetry and RetryInterval values.
   1466   //
   1467   if (Instance->MaxRetry == 0) {
   1468     Instance->MaxRetry = DNS_DEFAULT_RETRY;
   1469   }
   1470 
   1471   if (Token->RetryInterval < DNS_DEFAULT_TIMEOUT) {
   1472     Token->RetryInterval = DNS_DEFAULT_TIMEOUT;
   1473   }
   1474 
   1475   //
   1476   // Construct DNS TokenEntry.
   1477   //
   1478   TokenEntry = AllocateZeroPool (sizeof(DNS6_TOKEN_ENTRY));
   1479   if (TokenEntry == NULL) {
   1480     Status = EFI_OUT_OF_RESOURCES;
   1481     goto ON_EXIT;
   1482   }
   1483 
   1484   TokenEntry->PacketToLive = Token->RetryInterval;
   1485   TokenEntry->GeneralLookUp = TRUE;
   1486   TokenEntry->Token = Token;
   1487 
   1488   //
   1489   // Construct DNS Query Packet.
   1490   //
   1491   Status = ConstructDNSQuery (Instance, QName, QType, QClass, &Packet);
   1492   if (EFI_ERROR (Status)) {
   1493     if (TokenEntry != NULL) {
   1494       FreePool (TokenEntry);
   1495     }
   1496 
   1497     goto ON_EXIT;
   1498   }
   1499 
   1500   ASSERT (Packet != NULL);
   1501 
   1502   //
   1503   // Save the token into the Dns6TxTokens map.
   1504   //
   1505   Status = NetMapInsertTail (&Instance->Dns6TxTokens, TokenEntry, Packet);
   1506   if (EFI_ERROR (Status)) {
   1507     if (TokenEntry != NULL) {
   1508       FreePool (TokenEntry);
   1509     }
   1510 
   1511     NetbufFree (Packet);
   1512 
   1513     goto ON_EXIT;
   1514   }
   1515 
   1516   //
   1517   // Dns Query Ip
   1518   //
   1519   Status = DoDnsQuery (Instance, Packet);
   1520   if (EFI_ERROR (Status)) {
   1521     Dns6RemoveTokenEntry (&Instance->Dns6TxTokens, TokenEntry);
   1522 
   1523     if (TokenEntry != NULL) {
   1524       FreePool (TokenEntry);
   1525     }
   1526 
   1527     NetbufFree (Packet);
   1528   }
   1529 
   1530 ON_EXIT:
   1531   gBS->RestoreTPL (OldTpl);
   1532   return Status;
   1533 }
   1534 
   1535 /**
   1536   This function is to update the DNS Cache.
   1537 
   1538   The UpdateDnsCache() function is used to add/delete/modify DNS cache entry. DNS cache
   1539   can be normally dynamically updated after the DNS resolve succeeds. This function
   1540   provided capability to manually add/delete/modify the DNS cache.
   1541 
   1542   @param[in]  This                Pointer to EFI_DNS6_PROTOCOL instance.
   1543   @param[in]  DeleteFlag          If FALSE, this function is to add one entry to the
   1544                                   DNS Cahce. If TRUE, this function will delete
   1545                                   matching DNS Cache entry.
   1546   @param[in]  Override            If TRUE, the maching DNS cache entry will be
   1547                                   overwritten with the supplied parameter. If FALSE,
   1548                                   EFI_ACCESS_DENIED will be returned if the entry to
   1549                                   be added is already existed.
   1550   @param[in]  DnsCacheEntry       Pointer to DNS Cache entry.
   1551 
   1552   @retval EFI_SUCCESS             The operation completed successfully.
   1553   @retval EFI_INVALID_PARAMETER   One or more of the following conditions is TRUE:
   1554                                   This is NULL.
   1555                                   DnsCacheEntry.HostName is NULL.
   1556                                   DnsCacheEntry.IpAddress is NULL.
   1557                                   DnsCacheEntry.Timeout is zero.
   1558   @retval EFI_ACCESS_DENIED       The DNS cache entry already exists and Override is
   1559                                   not TRUE.
   1560   @retval EFI_OUT_OF_RESOURCE     Failed to allocate needed resources.
   1561 **/
   1562 EFI_STATUS
   1563 EFIAPI
   1564 Dns6UpdateDnsCache (
   1565   IN EFI_DNS6_PROTOCOL      *This,
   1566   IN BOOLEAN                DeleteFlag,
   1567   IN BOOLEAN                Override,
   1568   IN EFI_DNS6_CACHE_ENTRY   DnsCacheEntry
   1569   )
   1570 {
   1571   EFI_STATUS    Status;
   1572   EFI_TPL       OldTpl;
   1573 
   1574   Status = EFI_SUCCESS;
   1575 
   1576   if (DnsCacheEntry.HostName == NULL || DnsCacheEntry.IpAddress == NULL || DnsCacheEntry.Timeout == 0) {
   1577     return EFI_INVALID_PARAMETER;
   1578   }
   1579 
   1580   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1581 
   1582   //
   1583   // Update Dns6Cache here.
   1584   //
   1585   Status = UpdateDns6Cache (&mDriverData->Dns6CacheList, DeleteFlag, Override, DnsCacheEntry);
   1586 
   1587   gBS->RestoreTPL (OldTpl);
   1588 
   1589   return Status;
   1590 }
   1591 
   1592 /**
   1593   Polls for incoming data packets and processes outgoing data packets.
   1594 
   1595   The Poll() function can be used by network drivers and applications to increase the
   1596   rate that data packets are moved between the communications device and the transmit
   1597   and receive queues.
   1598 
   1599   In some systems, the periodic timer event in the managed network driver may not poll
   1600   the underlying communications device fast enough to transmit and/or receive all data
   1601   packets without missing incoming packets or dropping outgoing packets. Drivers and
   1602   applications that are experiencing packet loss should try calling the Poll()
   1603   function more often.
   1604 
   1605   @param[in]  This                Pointer to EFI_DNS6_PROTOCOL instance.
   1606 
   1607   @retval EFI_SUCCESS             Incoming or outgoing data was processed.
   1608   @retval EFI_NOT_STARTED         This EFI DNS Protocol instance has not been started.
   1609   @retval EFI_INVALID_PARAMETER   This is NULL.
   1610   @retval EFI_NO_MAPPING          There is no source address is available for use.
   1611   @retval EFI_DEVICE_ERROR        An unexpected system or network error occurred.
   1612   @retval EFI_TIMEOUT             Data was dropped out of the transmit and/or receive
   1613                                   queue. Consider increasing the polling rate.
   1614 **/
   1615 EFI_STATUS
   1616 EFIAPI
   1617 Dns6Poll (
   1618   IN EFI_DNS6_PROTOCOL    *This
   1619   )
   1620 {
   1621   DNS_INSTANCE           *Instance;
   1622   EFI_UDP6_PROTOCOL      *Udp;
   1623 
   1624   if (This == NULL) {
   1625     return EFI_INVALID_PARAMETER;
   1626   }
   1627 
   1628   Instance = DNS_INSTANCE_FROM_THIS_PROTOCOL6 (This);
   1629 
   1630   if (Instance->State == DNS_STATE_UNCONFIGED) {
   1631     return EFI_NOT_STARTED;
   1632   } else if (Instance->State == DNS_STATE_DESTROY) {
   1633     return EFI_DEVICE_ERROR;
   1634   }
   1635 
   1636   Udp = Instance->UdpIo->Protocol.Udp6;
   1637 
   1638   return Udp->Poll (Udp);
   1639 }
   1640 
   1641 /**
   1642   Abort an asynchronous DNS operation, including translation between IP and Host, and
   1643   general look up behavior.
   1644 
   1645   The Cancel() function is used to abort a pending resolution request. After calling
   1646   this function, Token.Status will be set to EFI_ABORTED and then Token.Event will be
   1647   signaled. If the token is not in one of the queues, which usually means that the
   1648   asynchronous operation has completed, this function will not signal the token and
   1649   EFI_NOT_FOUND is returned.
   1650 
   1651   @param[in]  This                Pointer to EFI_DNS6_PROTOCOL instance.
   1652   @param[in]  Token               Pointer to a token that has been issued by
   1653                                   EFI_DNS6_PROTOCOL.HostNameToIp (),
   1654                                   EFI_DNS6_PROTOCOL.IpToHostName() or
   1655                                   EFI_DNS6_PROTOCOL.GeneralLookup().
   1656                                   If NULL, all pending tokens are aborted.
   1657 
   1658   @retval EFI_SUCCESS             Incoming or outgoing data was processed.
   1659   @retval EFI_NOT_STARTED         This EFI DNS6 Protocol instance has not been started.
   1660   @retval EFI_INVALID_PARAMETER   This is NULL.
   1661   @retval EFI_NO_MAPPING          There's no source address is available for use.
   1662   @retval EFI_NOT_FOUND           When Token is not NULL, and the asynchronous DNS
   1663                                   operation was not found in the transmit queue. It
   1664                                   was either completed or was not issued by
   1665                                   HostNameToIp(), IpToHostName() or GeneralLookup().
   1666 **/
   1667 EFI_STATUS
   1668 EFIAPI
   1669 Dns6Cancel (
   1670   IN  EFI_DNS6_PROTOCOL          *This,
   1671   IN  EFI_DNS6_COMPLETION_TOKEN  *Token
   1672   )
   1673 {
   1674   EFI_STATUS          Status;
   1675   DNS_INSTANCE        *Instance;
   1676   EFI_TPL             OldTpl;
   1677 
   1678   if (This == NULL) {
   1679     return EFI_INVALID_PARAMETER;
   1680   }
   1681 
   1682   Instance = DNS_INSTANCE_FROM_THIS_PROTOCOL6 (This);
   1683 
   1684   if (Instance->State == DNS_STATE_UNCONFIGED) {
   1685     return EFI_NOT_STARTED;
   1686   }
   1687 
   1688   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1689 
   1690   //
   1691   // Cancle the tokens specified by Token for this instance.
   1692   //
   1693   Status = Dns6InstanceCancelToken (Instance, Token);
   1694 
   1695   //
   1696   // Dispatch the DPC queued by the NotifyFunction of the canceled token's events.
   1697   //
   1698   DispatchDpc ();
   1699 
   1700   gBS->RestoreTPL (OldTpl);
   1701 
   1702   return Status;
   1703 }
   1704 
   1705