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