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