1/** @file
2Implementation of EFI_DNS4_PROTOCOL and EFI_DNS6_PROTOCOL interfaces.
3
4Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution.  The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15#include "DnsImpl.h"
16
17EFI_DNS4_PROTOCOL  mDns4Protocol = {
18  Dns4GetModeData,
19  Dns4Configure,
20  Dns4HostNameToIp,
21  Dns4IpToHostName,
22  Dns4GeneralLookUp,
23  Dns4UpdateDnsCache,
24  Dns4Poll,
25  Dns4Cancel
26};
27
28EFI_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**/
54EFI_STATUS
55EFIAPI
56Dns4GetModeData (
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
152ON_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**/
182EFI_STATUS
183EFIAPI
184Dns4Configure (
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
310ON_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**/
335EFI_STATUS
336EFIAPI
337Dns4HostNameToIp (
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
517ON_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**/
548EFI_STATUS
549EFIAPI
550Dns4IpToHostName (
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**/
586EFI_STATUS
587EFIAPI
588Dns4GeneralLookUp (
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
701ON_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**/
732EFI_STATUS
733EFIAPI
734Dns4UpdateDnsCache (
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**/
783EFI_STATUS
784EFIAPI
785Dns4Poll (
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**/
834EFI_STATUS
835EFIAPI
836Dns4Cancel (
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**/
888EFI_STATUS
889EFIAPI
890Dns6GetModeData (
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
985ON_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**/
1013EFI_STATUS
1014EFIAPI
1015Dns6Configure (
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
1133ON_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**/
1160EFI_STATUS
1161EFIAPI
1162Dns6HostNameToIp (
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
1343ON_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**/
1375EFI_STATUS
1376EFIAPI
1377Dns6IpToHostName (
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**/
1415EFI_STATUS
1416EFIAPI
1417Dns6GeneralLookUp (
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
1530ON_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**/
1562EFI_STATUS
1563EFIAPI
1564Dns6UpdateDnsCache (
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**/
1615EFI_STATUS
1616EFIAPI
1617Dns6Poll (
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**/
1667EFI_STATUS
1668EFIAPI
1669Dns6Cancel (
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