1 /** @file
2 DnsDxe support functions implementation.
3 
4 Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "DnsImpl.h"
10 
11 /**
12   Remove TokenEntry from TokenMap.
13 
14   @param[in] TokenMap          All DNSv4 Token entrys.
15   @param[in] TokenEntry        TokenEntry need to be removed.
16 
17   @retval EFI_SUCCESS          Remove TokenEntry from TokenMap sucessfully.
18   @retval EFI_NOT_FOUND        TokenEntry is not found in TokenMap.
19 
20 **/
21 EFI_STATUS
Dns4RemoveTokenEntry(IN NET_MAP * TokenMap,IN DNS4_TOKEN_ENTRY * TokenEntry)22 Dns4RemoveTokenEntry (
23   IN NET_MAP                    *TokenMap,
24   IN DNS4_TOKEN_ENTRY           *TokenEntry
25   )
26 {
27   NET_MAP_ITEM  *Item;
28 
29   //
30   // Find the TokenEntry first.
31   //
32   Item = NetMapFindKey (TokenMap, (VOID *) TokenEntry);
33 
34   if (Item != NULL) {
35     //
36     // Remove the TokenEntry if it's found in the map.
37     //
38     NetMapRemoveItem (TokenMap, Item, NULL);
39 
40     return EFI_SUCCESS;
41   }
42 
43   return EFI_NOT_FOUND;
44 }
45 
46 /**
47   Remove TokenEntry from TokenMap.
48 
49   @param[in] TokenMap           All DNSv6 Token entrys.
50   @param[in] TokenEntry         TokenEntry need to be removed.
51 
52   @retval EFI_SUCCESS           Remove TokenEntry from TokenMap sucessfully.
53   @retval EFI_NOT_FOUND         TokenEntry is not found in TokenMap.
54 
55 **/
56 EFI_STATUS
Dns6RemoveTokenEntry(IN NET_MAP * TokenMap,IN DNS6_TOKEN_ENTRY * TokenEntry)57 Dns6RemoveTokenEntry (
58   IN NET_MAP                    *TokenMap,
59   IN DNS6_TOKEN_ENTRY           *TokenEntry
60   )
61 {
62   NET_MAP_ITEM  *Item;
63 
64   //
65   // Find the TokenEntry first.
66   //
67   Item = NetMapFindKey (TokenMap, (VOID *) TokenEntry);
68 
69   if (Item != NULL) {
70     //
71     // Remove the TokenEntry if it's found in the map.
72     //
73     NetMapRemoveItem (TokenMap, Item, NULL);
74 
75     return EFI_SUCCESS;
76   }
77 
78   return EFI_NOT_FOUND;
79 }
80 
81 /**
82   This function cancle the token specified by Arg in the Map.
83 
84   @param[in]  Map             Pointer to the NET_MAP.
85   @param[in]  Item            Pointer to the NET_MAP_ITEM.
86   @param[in]  Arg             Pointer to the token to be cancelled. If NULL, all
87                               the tokens in this Map will be cancelled.
88                               This parameter is optional and may be NULL.
89 
90   @retval EFI_SUCCESS         The token is cancelled if Arg is NULL, or the token
91                               is not the same as that in the Item, if Arg is not
92                               NULL.
93   @retval EFI_ABORTED         Arg is not NULL, and the token specified by Arg is
94                               cancelled.
95 
96 **/
97 EFI_STATUS
98 EFIAPI
Dns4CancelTokens(IN NET_MAP * Map,IN NET_MAP_ITEM * Item,IN VOID * Arg OPTIONAL)99 Dns4CancelTokens (
100   IN NET_MAP       *Map,
101   IN NET_MAP_ITEM  *Item,
102   IN VOID          *Arg OPTIONAL
103   )
104 {
105   DNS4_TOKEN_ENTRY           *TokenEntry;
106   NET_BUF                    *Packet;
107   UDP_IO                     *UdpIo;
108 
109   if ((Arg != NULL) && (Item->Key != Arg)) {
110     return EFI_SUCCESS;
111   }
112 
113   if (Item->Value != NULL) {
114     //
115     // If the TokenEntry is a transmit TokenEntry, the corresponding Packet is recorded in
116     // Item->Value.
117     //
118     Packet  = (NET_BUF *) (Item->Value);
119     UdpIo = (UDP_IO *) (*((UINTN *) &Packet->ProtoData[0]));
120 
121     UdpIoCancelSentDatagram (UdpIo, Packet);
122   }
123 
124   //
125   // Remove TokenEntry from Dns4TxTokens.
126   //
127   TokenEntry = (DNS4_TOKEN_ENTRY *) Item->Key;
128   if (Dns4RemoveTokenEntry (Map, TokenEntry) == EFI_SUCCESS) {
129     TokenEntry->Token->Status = EFI_ABORTED;
130     gBS->SignalEvent (TokenEntry->Token->Event);
131     DispatchDpc ();
132   }
133 
134   if (Arg != NULL) {
135     return EFI_ABORTED;
136   }
137 
138   return EFI_SUCCESS;
139 }
140 
141 /**
142   This function cancle the token specified by Arg in the Map.
143 
144   @param[in]  Map             Pointer to the NET_MAP.
145   @param[in]  Item            Pointer to the NET_MAP_ITEM.
146   @param[in]  Arg             Pointer to the token to be cancelled. If NULL, all
147                               the tokens in this Map will be cancelled.
148                               This parameter is optional and may be NULL.
149 
150   @retval EFI_SUCCESS         The token is cancelled if Arg is NULL, or the token
151                               is not the same as that in the Item, if Arg is not
152                               NULL.
153   @retval EFI_ABORTED         Arg is not NULL, and the token specified by Arg is
154                               cancelled.
155 
156 **/
157 EFI_STATUS
158 EFIAPI
Dns6CancelTokens(IN NET_MAP * Map,IN NET_MAP_ITEM * Item,IN VOID * Arg OPTIONAL)159 Dns6CancelTokens (
160   IN NET_MAP       *Map,
161   IN NET_MAP_ITEM  *Item,
162   IN VOID          *Arg OPTIONAL
163   )
164 {
165   DNS6_TOKEN_ENTRY           *TokenEntry;
166   NET_BUF                    *Packet;
167   UDP_IO                     *UdpIo;
168 
169   if ((Arg != NULL) && (Item->Key != Arg)) {
170     return EFI_SUCCESS;
171   }
172 
173   if (Item->Value != NULL) {
174     //
175     // If the TokenEntry is a transmit TokenEntry, the corresponding Packet is recorded in
176     // Item->Value.
177     //
178     Packet  = (NET_BUF *) (Item->Value);
179     UdpIo = (UDP_IO *) (*((UINTN *) &Packet->ProtoData[0]));
180 
181     UdpIoCancelSentDatagram (UdpIo, Packet);
182   }
183 
184   //
185   // Remove TokenEntry from Dns6TxTokens.
186   //
187   TokenEntry = (DNS6_TOKEN_ENTRY *) Item->Key;
188   if (Dns6RemoveTokenEntry (Map, TokenEntry) == EFI_SUCCESS) {
189     TokenEntry->Token->Status = EFI_ABORTED;
190     gBS->SignalEvent (TokenEntry->Token->Event);
191     DispatchDpc ();
192   }
193 
194   if (Arg != NULL) {
195     return EFI_ABORTED;
196   }
197 
198   return EFI_SUCCESS;
199 }
200 
201 /**
202   Get the TokenEntry from the TokensMap.
203 
204   @param[in]  TokensMap           All DNSv4 Token entrys
205   @param[in]  Token               Pointer to the token to be get.
206   @param[out] TokenEntry          Pointer to TokenEntry corresponding Token.
207 
208   @retval EFI_SUCCESS             Get the TokenEntry from the TokensMap sucessfully.
209   @retval EFI_NOT_FOUND           TokenEntry is not found in TokenMap.
210 
211 **/
212 EFI_STATUS
213 EFIAPI
GetDns4TokenEntry(IN NET_MAP * TokensMap,IN EFI_DNS4_COMPLETION_TOKEN * Token,OUT DNS4_TOKEN_ENTRY ** TokenEntry)214 GetDns4TokenEntry (
215   IN     NET_MAP                   *TokensMap,
216   IN     EFI_DNS4_COMPLETION_TOKEN *Token,
217      OUT DNS4_TOKEN_ENTRY          **TokenEntry
218   )
219 {
220   LIST_ENTRY              *Entry;
221 
222   NET_MAP_ITEM            *Item;
223 
224   NET_LIST_FOR_EACH (Entry, &TokensMap->Used) {
225     Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
226     *TokenEntry = (DNS4_TOKEN_ENTRY *) (Item->Key);
227     if ((*TokenEntry)->Token == Token) {
228       return EFI_SUCCESS;
229     }
230   }
231 
232   *TokenEntry = NULL;
233 
234   return EFI_NOT_FOUND;
235 }
236 
237 /**
238   Get the TokenEntry from the TokensMap.
239 
240   @param[in]  TokensMap           All DNSv6 Token entrys
241   @param[in]  Token               Pointer to the token to be get.
242   @param[out] TokenEntry          Pointer to TokenEntry corresponding Token.
243 
244   @retval EFI_SUCCESS             Get the TokenEntry from the TokensMap sucessfully.
245   @retval EFI_NOT_FOUND           TokenEntry is not found in TokenMap.
246 
247 **/
248 EFI_STATUS
249 EFIAPI
GetDns6TokenEntry(IN NET_MAP * TokensMap,IN EFI_DNS6_COMPLETION_TOKEN * Token,OUT DNS6_TOKEN_ENTRY ** TokenEntry)250 GetDns6TokenEntry (
251   IN     NET_MAP                   *TokensMap,
252   IN     EFI_DNS6_COMPLETION_TOKEN *Token,
253      OUT DNS6_TOKEN_ENTRY          **TokenEntry
254   )
255 {
256   LIST_ENTRY              *Entry;
257 
258   NET_MAP_ITEM            *Item;
259 
260   NET_LIST_FOR_EACH (Entry, &TokensMap->Used) {
261     Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
262     *TokenEntry = (DNS6_TOKEN_ENTRY *) (Item->Key);
263     if ((*TokenEntry)->Token == Token) {
264       return EFI_SUCCESS;
265     }
266   }
267 
268   *TokenEntry =NULL;
269 
270   return EFI_NOT_FOUND;
271 }
272 
273 /**
274   Cancel DNS4 tokens from the DNS4 instance.
275 
276   @param[in]  Instance           Pointer to the DNS instance context data.
277   @param[in]  Token              Pointer to the token to be canceled. If NULL, all
278                                  tokens in this instance will be cancelled.
279                                  This parameter is optional and may be NULL.
280 
281   @retval EFI_SUCCESS            The Token is cancelled.
282   @retval EFI_NOT_FOUND          The Token is not found.
283 
284 **/
285 EFI_STATUS
Dns4InstanceCancelToken(IN DNS_INSTANCE * Instance,IN EFI_DNS4_COMPLETION_TOKEN * Token)286 Dns4InstanceCancelToken (
287   IN DNS_INSTANCE               *Instance,
288   IN EFI_DNS4_COMPLETION_TOKEN  *Token
289   )
290 {
291   EFI_STATUS        Status;
292   DNS4_TOKEN_ENTRY  *TokenEntry;
293 
294   TokenEntry = NULL;
295 
296   if(Token != NULL  ) {
297     Status = GetDns4TokenEntry (&Instance->Dns4TxTokens, Token, &TokenEntry);
298     if (EFI_ERROR (Status)) {
299       return Status;
300     }
301   } else {
302     TokenEntry = NULL;
303   }
304 
305   //
306   // Cancel this TokenEntry from the Dns4TxTokens map.
307   //
308   Status = NetMapIterate (&Instance->Dns4TxTokens, Dns4CancelTokens, TokenEntry);
309 
310   if ((TokenEntry != NULL) && (Status == EFI_ABORTED)) {
311     //
312     // If Token isn't NULL and Status is EFI_ABORTED, the token is cancelled from
313     // the Dns4TxTokens and returns success.
314     //
315     if (NetMapIsEmpty (&Instance->Dns4TxTokens)) {
316        Instance->UdpIo->Protocol.Udp4->Cancel (Instance->UdpIo->Protocol.Udp4, &Instance->UdpIo->RecvRequest->Token.Udp4);
317     }
318     return EFI_SUCCESS;
319   }
320 
321   ASSERT ((TokenEntry != NULL) || (0 == NetMapGetCount (&Instance->Dns4TxTokens)));
322 
323   if (NetMapIsEmpty (&Instance->Dns4TxTokens)) {
324     Instance->UdpIo->Protocol.Udp4->Cancel (Instance->UdpIo->Protocol.Udp4, &Instance->UdpIo->RecvRequest->Token.Udp4);
325   }
326 
327   return EFI_SUCCESS;
328 }
329 
330 /**
331   Cancel DNS6 tokens from the DNS6 instance.
332 
333   @param[in]  Instance           Pointer to the DNS instance context data.
334   @param[in]  Token              Pointer to the token to be canceled. If NULL, all
335                                  tokens in this instance will be cancelled.
336                                  This parameter is optional and may be NULL.
337 
338   @retval EFI_SUCCESS            The Token is cancelled.
339   @retval EFI_NOT_FOUND          The Token is not found.
340 
341 **/
342 EFI_STATUS
Dns6InstanceCancelToken(IN DNS_INSTANCE * Instance,IN EFI_DNS6_COMPLETION_TOKEN * Token)343 Dns6InstanceCancelToken (
344   IN DNS_INSTANCE               *Instance,
345   IN EFI_DNS6_COMPLETION_TOKEN  *Token
346   )
347 {
348   EFI_STATUS        Status;
349   DNS6_TOKEN_ENTRY  *TokenEntry;
350 
351   TokenEntry = NULL;
352 
353   if(Token != NULL  ) {
354     Status = GetDns6TokenEntry (&Instance->Dns6TxTokens, Token, &TokenEntry);
355     if (EFI_ERROR (Status)) {
356       return Status;
357     }
358   } else {
359     TokenEntry = NULL;
360   }
361 
362   //
363   // Cancel this TokenEntry from the Dns6TxTokens map.
364   //
365   Status = NetMapIterate (&Instance->Dns6TxTokens, Dns6CancelTokens, TokenEntry);
366 
367   if ((TokenEntry != NULL) && (Status == EFI_ABORTED)) {
368     //
369     // If Token isn't NULL and Status is EFI_ABORTED, the token is cancelled from
370     // the Dns6TxTokens and returns success.
371     //
372     if (NetMapIsEmpty (&Instance->Dns6TxTokens)) {
373        Instance->UdpIo->Protocol.Udp6->Cancel (Instance->UdpIo->Protocol.Udp6, &Instance->UdpIo->RecvRequest->Token.Udp6);
374     }
375     return EFI_SUCCESS;
376   }
377 
378   ASSERT ((TokenEntry != NULL) || (0 == NetMapGetCount (&Instance->Dns6TxTokens)));
379 
380   if (NetMapIsEmpty (&Instance->Dns6TxTokens)) {
381     Instance->UdpIo->Protocol.Udp6->Cancel (Instance->UdpIo->Protocol.Udp6, &Instance->UdpIo->RecvRequest->Token.Udp6);
382   }
383 
384   return EFI_SUCCESS;
385 }
386 
387 /**
388   Free the resource related to the configure parameters.
389 
390   @param  Config                 The DNS configure data
391 
392 **/
393 VOID
Dns4CleanConfigure(IN OUT EFI_DNS4_CONFIG_DATA * Config)394 Dns4CleanConfigure (
395   IN OUT EFI_DNS4_CONFIG_DATA  *Config
396   )
397 {
398   if (Config->DnsServerList != NULL) {
399     FreePool (Config->DnsServerList);
400   }
401 
402   ZeroMem (Config, sizeof (EFI_DNS4_CONFIG_DATA));
403 }
404 
405 /**
406   Free the resource related to the configure parameters.
407 
408   @param  Config                 The DNS configure data
409 
410 **/
411 VOID
Dns6CleanConfigure(IN OUT EFI_DNS6_CONFIG_DATA * Config)412 Dns6CleanConfigure (
413   IN OUT EFI_DNS6_CONFIG_DATA  *Config
414   )
415 {
416   if (Config->DnsServerList != NULL) {
417     FreePool (Config->DnsServerList);
418   }
419 
420   ZeroMem (Config, sizeof (EFI_DNS6_CONFIG_DATA));
421 }
422 
423 /**
424   Allocate memory for configure parameter such as timeout value for Dst,
425   then copy the configure parameter from Src to Dst.
426 
427   @param[out]  Dst               The destination DHCP configure data.
428   @param[in]   Src               The source DHCP configure data.
429 
430   @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory.
431   @retval EFI_SUCCESS            The configure is copied.
432 
433 **/
434 EFI_STATUS
Dns4CopyConfigure(OUT EFI_DNS4_CONFIG_DATA * Dst,IN EFI_DNS4_CONFIG_DATA * Src)435 Dns4CopyConfigure (
436   OUT EFI_DNS4_CONFIG_DATA  *Dst,
437   IN  EFI_DNS4_CONFIG_DATA  *Src
438   )
439 {
440   UINTN                     Len;
441   UINT32                    Index;
442 
443   CopyMem (Dst, Src, sizeof (*Dst));
444   Dst->DnsServerList = NULL;
445 
446   //
447   // Allocate a memory then copy DnsServerList to it
448   //
449   if (Src->DnsServerList != NULL) {
450     Len                = Src->DnsServerListCount * sizeof (EFI_IPv4_ADDRESS);
451     Dst->DnsServerList = AllocatePool (Len);
452     if (Dst->DnsServerList == NULL) {
453       Dns4CleanConfigure (Dst);
454       return EFI_OUT_OF_RESOURCES;
455     }
456 
457     for (Index = 0; Index < Src->DnsServerListCount; Index++) {
458       CopyMem (&Dst->DnsServerList[Index], &Src->DnsServerList[Index], sizeof (EFI_IPv4_ADDRESS));
459     }
460   }
461 
462   return EFI_SUCCESS;
463 }
464 
465 /**
466   Allocate memory for configure parameter such as timeout value for Dst,
467   then copy the configure parameter from Src to Dst.
468 
469   @param[out]  Dst               The destination DHCP configure data.
470   @param[in]   Src               The source DHCP configure data.
471 
472   @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory.
473   @retval EFI_SUCCESS            The configure is copied.
474 
475 **/
476 EFI_STATUS
Dns6CopyConfigure(OUT EFI_DNS6_CONFIG_DATA * Dst,IN EFI_DNS6_CONFIG_DATA * Src)477 Dns6CopyConfigure (
478   OUT EFI_DNS6_CONFIG_DATA  *Dst,
479   IN  EFI_DNS6_CONFIG_DATA  *Src
480   )
481 {
482   UINTN                     Len;
483   UINT32                    Index;
484 
485   CopyMem (Dst, Src, sizeof (*Dst));
486   Dst->DnsServerList = NULL;
487 
488   //
489   // Allocate a memory then copy DnsServerList to it
490   //
491   if (Src->DnsServerList != NULL) {
492     Len                = Src->DnsServerCount * sizeof (EFI_IPv6_ADDRESS);
493     Dst->DnsServerList = AllocatePool (Len);
494     if (Dst->DnsServerList == NULL) {
495       Dns6CleanConfigure (Dst);
496       return EFI_OUT_OF_RESOURCES;
497     }
498 
499     for (Index = 0; Index < Src->DnsServerCount; Index++) {
500       CopyMem (&Dst->DnsServerList[Index], &Src->DnsServerList[Index], sizeof (EFI_IPv6_ADDRESS));
501     }
502   }
503 
504   return EFI_SUCCESS;
505 }
506 
507 /**
508   Callback of Dns packet. Does nothing.
509 
510   @param Arg           The context.
511 
512 **/
513 VOID
514 EFIAPI
DnsDummyExtFree(IN VOID * Arg)515 DnsDummyExtFree (
516   IN VOID                   *Arg
517   )
518 {
519 }
520 
521 /**
522   Poll the UDP to get the IP4 default address, which may be retrieved
523   by DHCP.
524 
525   The default time out value is 5 seconds. If IP has retrieved the default address,
526   the UDP is reconfigured.
527 
528   @param  Instance               The DNS instance
529   @param  UdpIo                  The UDP_IO to poll
530   @param  UdpCfgData             The UDP configure data to reconfigure the UDP_IO
531 
532   @retval TRUE                   The default address is retrieved and UDP is reconfigured.
533   @retval FALSE                  Some error occured.
534 
535 **/
536 BOOLEAN
Dns4GetMapping(IN DNS_INSTANCE * Instance,IN UDP_IO * UdpIo,IN EFI_UDP4_CONFIG_DATA * UdpCfgData)537 Dns4GetMapping (
538   IN DNS_INSTANCE           *Instance,
539   IN UDP_IO                 *UdpIo,
540   IN EFI_UDP4_CONFIG_DATA   *UdpCfgData
541   )
542 {
543   DNS_SERVICE               *Service;
544   EFI_IP4_MODE_DATA         Ip4Mode;
545   EFI_UDP4_PROTOCOL         *Udp;
546   EFI_STATUS                Status;
547 
548   ASSERT (Instance->Dns4CfgData.UseDefaultSetting);
549 
550   Service = Instance->Service;
551   Udp     = UdpIo->Protocol.Udp4;
552 
553   Status = gBS->SetTimer (
554                   Service->TimerToGetMap,
555                   TimerRelative,
556                   DNS_TIME_TO_GETMAP * TICKS_PER_SECOND
557                   );
558   if (EFI_ERROR (Status)) {
559     return FALSE;
560   }
561 
562   while (EFI_ERROR (gBS->CheckEvent (Service->TimerToGetMap))) {
563     Udp->Poll (Udp);
564 
565     if (!EFI_ERROR (Udp->GetModeData (Udp, NULL, &Ip4Mode, NULL, NULL)) &&
566         Ip4Mode.IsConfigured) {
567 
568       Udp->Configure (Udp, NULL);
569       return (BOOLEAN) (Udp->Configure (Udp, UdpCfgData) == EFI_SUCCESS);
570     }
571   }
572 
573   return FALSE;
574 }
575 
576 /**
577   Configure the opened Udp6 instance until the corresponding Ip6 instance
578   has been configured.
579 
580   @param  Instance               The DNS instance
581   @param  UdpIo                  The UDP_IO to poll
582   @param  UdpCfgData             The UDP configure data to reconfigure the UDP_IO
583 
584   @retval TRUE                   Configure the Udp6 instance successfully.
585   @retval FALSE                  Some error occured.
586 
587 **/
588 BOOLEAN
Dns6GetMapping(IN DNS_INSTANCE * Instance,IN UDP_IO * UdpIo,IN EFI_UDP6_CONFIG_DATA * UdpCfgData)589 Dns6GetMapping (
590   IN DNS_INSTANCE           *Instance,
591   IN UDP_IO                 *UdpIo,
592   IN EFI_UDP6_CONFIG_DATA   *UdpCfgData
593   )
594 {
595   DNS_SERVICE               *Service;
596   EFI_IP6_MODE_DATA         Ip6Mode;
597   EFI_UDP6_PROTOCOL         *Udp;
598   EFI_STATUS                Status;
599 
600   Service = Instance->Service;
601   Udp     = UdpIo->Protocol.Udp6;
602 
603   Status = gBS->SetTimer (
604                   Service->TimerToGetMap,
605                   TimerRelative,
606                   DNS_TIME_TO_GETMAP * TICKS_PER_SECOND
607                   );
608   if (EFI_ERROR (Status)) {
609     return FALSE;
610   }
611 
612   while (EFI_ERROR (gBS->CheckEvent (Service->TimerToGetMap))) {
613     Udp->Poll (Udp);
614 
615     if (!EFI_ERROR (Udp->GetModeData (Udp, NULL, &Ip6Mode, NULL, NULL))) {
616       if (Ip6Mode.AddressList != NULL) {
617         FreePool (Ip6Mode.AddressList);
618       }
619 
620       if (Ip6Mode.GroupTable != NULL) {
621         FreePool (Ip6Mode.GroupTable);
622       }
623 
624       if (Ip6Mode.RouteTable != NULL) {
625         FreePool (Ip6Mode.RouteTable);
626       }
627 
628       if (Ip6Mode.NeighborCache != NULL) {
629         FreePool (Ip6Mode.NeighborCache);
630       }
631 
632       if (Ip6Mode.PrefixTable != NULL) {
633         FreePool (Ip6Mode.PrefixTable);
634       }
635 
636       if (Ip6Mode.IcmpTypeList != NULL) {
637         FreePool (Ip6Mode.IcmpTypeList);
638       }
639 
640       if (!Ip6Mode.IsStarted || Ip6Mode.IsConfigured) {
641         Udp->Configure (Udp, NULL);
642         if (Udp->Configure (Udp, UdpCfgData) == EFI_SUCCESS) {
643           return TRUE;
644         }
645       }
646     }
647   }
648 
649   return FALSE;
650 }
651 
652 /**
653   Configure the UDP.
654 
655   @param  Instance               The DNS session
656   @param  UdpIo                  The UDP_IO instance
657 
658   @retval EFI_SUCCESS            The UDP is successfully configured for the
659                                  session.
660 
661 **/
662 EFI_STATUS
Dns4ConfigUdp(IN DNS_INSTANCE * Instance,IN UDP_IO * UdpIo)663 Dns4ConfigUdp (
664   IN DNS_INSTANCE           *Instance,
665   IN UDP_IO                 *UdpIo
666   )
667 {
668   EFI_DNS4_CONFIG_DATA      *Config;
669   EFI_UDP4_CONFIG_DATA      UdpConfig;
670   EFI_STATUS                Status;
671 
672   Config = &Instance->Dns4CfgData;
673 
674   UdpConfig.AcceptBroadcast    = FALSE;
675   UdpConfig.AcceptPromiscuous  = FALSE;
676   UdpConfig.AcceptAnyPort      = FALSE;
677   UdpConfig.AllowDuplicatePort = FALSE;
678   UdpConfig.TypeOfService      = 0;
679   UdpConfig.TimeToLive         = 128;
680   UdpConfig.DoNotFragment      = FALSE;
681   UdpConfig.ReceiveTimeout     = 0;
682   UdpConfig.TransmitTimeout    = 0;
683   UdpConfig.UseDefaultAddress  = Config->UseDefaultSetting;
684   UdpConfig.SubnetMask         = Config->SubnetMask;
685   UdpConfig.StationPort        = Config->LocalPort;
686   UdpConfig.RemotePort         = DNS_SERVER_PORT;
687 
688   CopyMem (&UdpConfig.StationAddress, &Config->StationIp, sizeof (EFI_IPv4_ADDRESS));
689   CopyMem (&UdpConfig.RemoteAddress, &Instance->SessionDnsServer.v4, sizeof (EFI_IPv4_ADDRESS));
690 
691   Status = UdpIo->Protocol.Udp4->Configure (UdpIo->Protocol.Udp4, &UdpConfig);
692 
693   if ((Status == EFI_NO_MAPPING) && Dns4GetMapping (Instance, UdpIo, &UdpConfig)) {
694     return EFI_SUCCESS;
695   }
696 
697   return Status;
698 }
699 
700 /**
701   Configure the UDP.
702 
703   @param  Instance               The DNS session
704   @param  UdpIo                  The UDP_IO instance
705 
706   @retval EFI_SUCCESS            The UDP is successfully configured for the
707                                  session.
708 
709 **/
710 EFI_STATUS
Dns6ConfigUdp(IN DNS_INSTANCE * Instance,IN UDP_IO * UdpIo)711 Dns6ConfigUdp (
712   IN DNS_INSTANCE           *Instance,
713   IN UDP_IO                 *UdpIo
714   )
715 {
716   EFI_DNS6_CONFIG_DATA      *Config;
717   EFI_UDP6_CONFIG_DATA      UdpConfig;
718   EFI_STATUS                Status;
719 
720   Config = &Instance->Dns6CfgData;
721 
722   UdpConfig.AcceptPromiscuous  = FALSE;
723   UdpConfig.AcceptAnyPort      = FALSE;
724   UdpConfig.AllowDuplicatePort = FALSE;
725   UdpConfig.TrafficClass       = 0;
726   UdpConfig.HopLimit           = 128;
727   UdpConfig.ReceiveTimeout     = 0;
728   UdpConfig.TransmitTimeout    = 0;
729   UdpConfig.StationPort        = Config->LocalPort;
730   UdpConfig.RemotePort         = DNS_SERVER_PORT;
731   CopyMem (&UdpConfig.StationAddress, &Config->StationIp, sizeof (EFI_IPv6_ADDRESS));
732   CopyMem (&UdpConfig.RemoteAddress, &Instance->SessionDnsServer.v6, sizeof (EFI_IPv6_ADDRESS));
733 
734   Status = UdpIo->Protocol.Udp6->Configure (UdpIo->Protocol.Udp6, &UdpConfig);
735 
736   if ((Status == EFI_NO_MAPPING) && Dns6GetMapping (Instance, UdpIo, &UdpConfig)) {
737     return EFI_SUCCESS;
738   }
739 
740   return Status;
741 }
742 
743 /**
744   Update Dns4 cache to shared list of caches of all DNSv4 instances.
745 
746   @param  Dns4CacheList      All Dns4 cache list.
747   @param  DeleteFlag         If FALSE, this function is to add one entry to the DNS Cache.
748                              If TRUE, this function will delete matching DNS Cache entry.
749   @param  Override           If TRUE, the matching DNS cache entry will be overwritten with the supplied parameter.
750                              If FALSE, EFI_ACCESS_DENIED will be returned if the entry to be added is already exists.
751   @param  DnsCacheEntry      Entry Pointer to DNS Cache entry.
752 
753   @retval EFI_SUCCESS        Update Dns4 cache successfully.
754   @retval Others             Failed to update Dns4 cache.
755 
756 **/
757 EFI_STATUS
758 EFIAPI
UpdateDns4Cache(IN LIST_ENTRY * Dns4CacheList,IN BOOLEAN DeleteFlag,IN BOOLEAN Override,IN EFI_DNS4_CACHE_ENTRY DnsCacheEntry)759 UpdateDns4Cache (
760   IN LIST_ENTRY             *Dns4CacheList,
761   IN BOOLEAN                DeleteFlag,
762   IN BOOLEAN                Override,
763   IN EFI_DNS4_CACHE_ENTRY   DnsCacheEntry
764   )
765 {
766   DNS4_CACHE    *NewDnsCache;
767   DNS4_CACHE    *Item;
768   LIST_ENTRY    *Entry;
769   LIST_ENTRY    *Next;
770 
771   NewDnsCache = NULL;
772   Item        = NULL;
773 
774   //
775   // Search the database for the matching EFI_DNS_CACHE_ENTRY
776   //
777   NET_LIST_FOR_EACH_SAFE (Entry, Next, Dns4CacheList) {
778     Item = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink);
779     if (StrCmp (DnsCacheEntry.HostName, Item->DnsCache.HostName) == 0 && \
780         CompareMem (DnsCacheEntry.IpAddress, Item->DnsCache.IpAddress, sizeof (EFI_IPv4_ADDRESS)) == 0) {
781       //
782       // This is the Dns cache entry
783       //
784       if (DeleteFlag) {
785         //
786         // Delete matching DNS Cache entry
787         //
788         RemoveEntryList (&Item->AllCacheLink);
789 
790         FreePool (Item->DnsCache.HostName);
791         FreePool (Item->DnsCache.IpAddress);
792         FreePool (Item);
793 
794         return EFI_SUCCESS;
795       } else if (Override) {
796         //
797         // Update this one
798         //
799         Item->DnsCache.Timeout = DnsCacheEntry.Timeout;
800 
801         return EFI_SUCCESS;
802       }else {
803         return EFI_ACCESS_DENIED;
804       }
805     }
806   }
807 
808   //
809   // Add new one
810   //
811   NewDnsCache = AllocatePool (sizeof (DNS4_CACHE));
812   if (NewDnsCache == NULL) {
813     return EFI_OUT_OF_RESOURCES;
814   }
815 
816   InitializeListHead (&NewDnsCache->AllCacheLink);
817 
818   NewDnsCache->DnsCache.HostName = AllocatePool (StrSize (DnsCacheEntry.HostName));
819   if (NewDnsCache->DnsCache.HostName == NULL) {
820     FreePool (NewDnsCache);
821     return EFI_OUT_OF_RESOURCES;
822   }
823 
824   CopyMem (NewDnsCache->DnsCache.HostName, DnsCacheEntry.HostName, StrSize (DnsCacheEntry.HostName));
825 
826   NewDnsCache->DnsCache.IpAddress = AllocatePool (sizeof (EFI_IPv4_ADDRESS));
827   if (NewDnsCache->DnsCache.IpAddress == NULL) {
828     FreePool (NewDnsCache->DnsCache.HostName);
829     FreePool (NewDnsCache);
830     return EFI_OUT_OF_RESOURCES;
831   }
832 
833   CopyMem (NewDnsCache->DnsCache.IpAddress, DnsCacheEntry.IpAddress, sizeof (EFI_IPv4_ADDRESS));
834 
835   NewDnsCache->DnsCache.Timeout = DnsCacheEntry.Timeout;
836 
837   InsertTailList (Dns4CacheList, &NewDnsCache->AllCacheLink);
838 
839   return EFI_SUCCESS;
840 }
841 
842 /**
843   Update Dns6 cache to shared list of caches of all DNSv6 instances.
844 
845   @param  Dns6CacheList      All Dns6 cache list.
846   @param  DeleteFlag         If FALSE, this function is to add one entry to the DNS Cache.
847                              If TRUE, this function will delete matching DNS Cache entry.
848   @param  Override           If TRUE, the matching DNS cache entry will be overwritten with the supplied parameter.
849                              If FALSE, EFI_ACCESS_DENIED will be returned if the entry to be added is already exists.
850   @param  DnsCacheEntry      Entry Pointer to DNS Cache entry.
851 
852   @retval EFI_SUCCESS        Update Dns6 cache successfully.
853   @retval Others             Failed to update Dns6 cache.
854 **/
855 EFI_STATUS
856 EFIAPI
UpdateDns6Cache(IN LIST_ENTRY * Dns6CacheList,IN BOOLEAN DeleteFlag,IN BOOLEAN Override,IN EFI_DNS6_CACHE_ENTRY DnsCacheEntry)857 UpdateDns6Cache (
858   IN LIST_ENTRY             *Dns6CacheList,
859   IN BOOLEAN                DeleteFlag,
860   IN BOOLEAN                Override,
861   IN EFI_DNS6_CACHE_ENTRY   DnsCacheEntry
862   )
863 {
864   DNS6_CACHE    *NewDnsCache;
865   DNS6_CACHE    *Item;
866   LIST_ENTRY    *Entry;
867   LIST_ENTRY    *Next;
868 
869   NewDnsCache = NULL;
870   Item        = NULL;
871 
872   //
873   // Search the database for the matching EFI_DNS_CACHE_ENTRY
874   //
875   NET_LIST_FOR_EACH_SAFE (Entry, Next, Dns6CacheList) {
876     Item = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink);
877     if (StrCmp (DnsCacheEntry.HostName, Item->DnsCache.HostName) == 0 && \
878         CompareMem (DnsCacheEntry.IpAddress, Item->DnsCache.IpAddress, sizeof (EFI_IPv6_ADDRESS)) == 0) {
879       //
880       // This is the Dns cache entry
881       //
882       if (DeleteFlag) {
883         //
884         // Delete matching DNS Cache entry
885         //
886         RemoveEntryList (&Item->AllCacheLink);
887 
888         FreePool (Item->DnsCache.HostName);
889         FreePool (Item->DnsCache.IpAddress);
890         FreePool (Item);
891 
892         return EFI_SUCCESS;
893       } else if (Override) {
894         //
895         // Update this one
896         //
897         Item->DnsCache.Timeout = DnsCacheEntry.Timeout;
898 
899         return EFI_SUCCESS;
900       }else {
901         return EFI_ACCESS_DENIED;
902       }
903     }
904   }
905 
906   //
907   // Add new one
908   //
909   NewDnsCache = AllocatePool (sizeof (DNS6_CACHE));
910   if (NewDnsCache == NULL) {
911     return EFI_OUT_OF_RESOURCES;
912   }
913 
914   InitializeListHead (&NewDnsCache->AllCacheLink);
915 
916   NewDnsCache->DnsCache.HostName = AllocatePool (StrSize (DnsCacheEntry.HostName));
917   if (NewDnsCache->DnsCache.HostName == NULL) {
918     FreePool (NewDnsCache);
919     return EFI_OUT_OF_RESOURCES;
920   }
921 
922   CopyMem (NewDnsCache->DnsCache.HostName, DnsCacheEntry.HostName, StrSize (DnsCacheEntry.HostName));
923 
924   NewDnsCache->DnsCache.IpAddress = AllocatePool (sizeof (EFI_IPv6_ADDRESS));
925   if (NewDnsCache->DnsCache.IpAddress == NULL) {
926     FreePool (NewDnsCache->DnsCache.HostName);
927     FreePool (NewDnsCache);
928     return EFI_OUT_OF_RESOURCES;
929   }
930 
931   CopyMem (NewDnsCache->DnsCache.IpAddress, DnsCacheEntry.IpAddress, sizeof (EFI_IPv6_ADDRESS));
932 
933   NewDnsCache->DnsCache.Timeout = DnsCacheEntry.Timeout;
934 
935   InsertTailList (Dns6CacheList, &NewDnsCache->AllCacheLink);
936 
937   return EFI_SUCCESS;
938 }
939 
940 /**
941   Add Dns4 ServerIp to common list of addresses of all configured DNSv4 server.
942 
943   @param  Dns4ServerList    Common list of addresses of all configured DNSv4 server.
944   @param  ServerIp          DNS server Ip.
945 
946   @retval EFI_SUCCESS       Add Dns4 ServerIp to common list successfully.
947   @retval Others            Failed to add Dns4 ServerIp to common list.
948 
949 **/
950 EFI_STATUS
951 EFIAPI
AddDns4ServerIp(IN LIST_ENTRY * Dns4ServerList,IN EFI_IPv4_ADDRESS ServerIp)952 AddDns4ServerIp (
953   IN LIST_ENTRY                *Dns4ServerList,
954   IN EFI_IPv4_ADDRESS           ServerIp
955   )
956 {
957   DNS4_SERVER_IP    *NewServerIp;
958   DNS4_SERVER_IP    *Item;
959   LIST_ENTRY        *Entry;
960   LIST_ENTRY        *Next;
961 
962   NewServerIp = NULL;
963   Item        = NULL;
964 
965   //
966   // Search the database for the matching ServerIp
967   //
968   NET_LIST_FOR_EACH_SAFE (Entry, Next, Dns4ServerList) {
969     Item = NET_LIST_USER_STRUCT (Entry, DNS4_SERVER_IP, AllServerLink);
970     if (CompareMem (&Item->Dns4ServerIp, &ServerIp, sizeof (EFI_IPv4_ADDRESS)) == 0) {
971       //
972       // Already done.
973       //
974       return EFI_SUCCESS;
975     }
976   }
977 
978   //
979   // Add new one
980   //
981   NewServerIp = AllocatePool (sizeof (DNS4_SERVER_IP));
982   if (NewServerIp == NULL) {
983     return EFI_OUT_OF_RESOURCES;
984   }
985 
986   InitializeListHead (&NewServerIp->AllServerLink);
987 
988   CopyMem (&NewServerIp->Dns4ServerIp, &ServerIp, sizeof (EFI_IPv4_ADDRESS));
989 
990   InsertTailList (Dns4ServerList, &NewServerIp->AllServerLink);
991 
992   return EFI_SUCCESS;
993 }
994 
995 /**
996   Add Dns6 ServerIp to common list of addresses of all configured DNSv6 server.
997 
998   @param  Dns6ServerList    Common list of addresses of all configured DNSv6 server.
999   @param  ServerIp          DNS server Ip.
1000 
1001   @retval EFI_SUCCESS       Add Dns6 ServerIp to common list successfully.
1002   @retval Others            Failed to add Dns6 ServerIp to common list.
1003 
1004 **/
1005 EFI_STATUS
1006 EFIAPI
AddDns6ServerIp(IN LIST_ENTRY * Dns6ServerList,IN EFI_IPv6_ADDRESS ServerIp)1007 AddDns6ServerIp (
1008   IN LIST_ENTRY                *Dns6ServerList,
1009   IN EFI_IPv6_ADDRESS           ServerIp
1010   )
1011 {
1012   DNS6_SERVER_IP    *NewServerIp;
1013   DNS6_SERVER_IP    *Item;
1014   LIST_ENTRY        *Entry;
1015   LIST_ENTRY        *Next;
1016 
1017   NewServerIp = NULL;
1018   Item        = NULL;
1019 
1020   //
1021   // Search the database for the matching ServerIp
1022   //
1023   NET_LIST_FOR_EACH_SAFE (Entry, Next, Dns6ServerList) {
1024     Item = NET_LIST_USER_STRUCT (Entry, DNS6_SERVER_IP, AllServerLink);
1025     if (CompareMem (&Item->Dns6ServerIp, &ServerIp, sizeof (EFI_IPv6_ADDRESS)) == 0) {
1026       //
1027       // Already done.
1028       //
1029       return EFI_SUCCESS;
1030     }
1031   }
1032 
1033   //
1034   // Add new one
1035   //
1036   NewServerIp = AllocatePool (sizeof (DNS6_SERVER_IP));
1037   if (NewServerIp == NULL) {
1038     return EFI_OUT_OF_RESOURCES;
1039   }
1040 
1041   InitializeListHead (&NewServerIp->AllServerLink);
1042 
1043   CopyMem (&NewServerIp->Dns6ServerIp, &ServerIp, sizeof (EFI_IPv6_ADDRESS));
1044 
1045   InsertTailList (Dns6ServerList, &NewServerIp->AllServerLink);
1046 
1047   return EFI_SUCCESS;
1048 }
1049 
1050 /**
1051   Find out whether the response is valid or invalid.
1052 
1053   @param  TokensMap       All DNS transmittal Tokens entry.
1054   @param  Identification  Identification for queried packet.
1055   @param  Type            Type for queried packet.
1056   @param  Class           Class for queried packet.
1057   @param  Item            Return corresponding Token entry.
1058 
1059   @retval TRUE            The response is valid.
1060   @retval FALSE           The response is invalid.
1061 
1062 **/
1063 BOOLEAN
IsValidDnsResponse(IN NET_MAP * TokensMap,IN UINT16 Identification,IN UINT16 Type,IN UINT16 Class,OUT NET_MAP_ITEM ** Item)1064 IsValidDnsResponse (
1065   IN     NET_MAP      *TokensMap,
1066   IN     UINT16       Identification,
1067   IN     UINT16       Type,
1068   IN     UINT16       Class,
1069      OUT NET_MAP_ITEM **Item
1070   )
1071 {
1072   LIST_ENTRY              *Entry;
1073 
1074   NET_BUF                 *Packet;
1075   UINT8                   *TxString;
1076   DNS_HEADER              *DnsHeader;
1077   CHAR8                   *QueryName;
1078   DNS_QUERY_SECTION       *QuerySection;
1079 
1080   NET_LIST_FOR_EACH (Entry, &TokensMap->Used) {
1081     *Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
1082     Packet = (NET_BUF *) ((*Item)->Value);
1083     if (Packet == NULL){
1084 
1085       continue;
1086     } else {
1087       TxString = NetbufGetByte (Packet, 0, NULL);
1088       ASSERT (TxString != NULL);
1089       DnsHeader = (DNS_HEADER *) TxString;
1090       QueryName = (CHAR8 *) (TxString + sizeof (*DnsHeader));
1091       QuerySection = (DNS_QUERY_SECTION *) (QueryName + AsciiStrLen (QueryName) + 1);
1092 
1093       if (NTOHS (DnsHeader->Identification) == Identification &&
1094           NTOHS (QuerySection->Type) == Type &&
1095           NTOHS (QuerySection->Class) == Class) {
1096         return TRUE;
1097       }
1098     }
1099   }
1100 
1101   *Item = NULL;
1102 
1103   return FALSE;
1104 }
1105 
1106 /**
1107   Parse Dns Response.
1108 
1109   @param  Instance              The DNS instance
1110   @param  RxString              Received buffer.
1111   @param  Length                Received buffer length.
1112   @param  Completed             Flag to indicate that Dns response is valid.
1113 
1114   @retval EFI_SUCCESS           Parse Dns Response successfully.
1115   @retval Others                Failed to parse Dns Response.
1116 
1117 **/
1118 EFI_STATUS
ParseDnsResponse(IN OUT DNS_INSTANCE * Instance,IN UINT8 * RxString,IN UINT32 Length,OUT BOOLEAN * Completed)1119 ParseDnsResponse (
1120   IN OUT DNS_INSTANCE              *Instance,
1121   IN     UINT8                     *RxString,
1122   IN     UINT32                    Length,
1123      OUT BOOLEAN                   *Completed
1124   )
1125 {
1126   DNS_HEADER            *DnsHeader;
1127 
1128   CHAR8                 *QueryName;
1129   UINT32                QueryNameLen;
1130   DNS_QUERY_SECTION     *QuerySection;
1131 
1132   CHAR8                 *AnswerName;
1133   DNS_ANSWER_SECTION    *AnswerSection;
1134   UINT8                 *AnswerData;
1135 
1136   NET_MAP_ITEM          *Item;
1137   DNS4_TOKEN_ENTRY      *Dns4TokenEntry;
1138   DNS6_TOKEN_ENTRY      *Dns6TokenEntry;
1139 
1140   UINT32                IpCount;
1141   UINT32                RRCount;
1142   UINT32                AnswerSectionNum;
1143   UINT32                CNameTtl;
1144 
1145   EFI_IPv4_ADDRESS      *HostAddr4;
1146   EFI_IPv6_ADDRESS      *HostAddr6;
1147 
1148   EFI_DNS4_CACHE_ENTRY  *Dns4CacheEntry;
1149   EFI_DNS6_CACHE_ENTRY  *Dns6CacheEntry;
1150 
1151   DNS_RESOURCE_RECORD   *Dns4RR;
1152   DNS6_RESOURCE_RECORD  *Dns6RR;
1153 
1154   EFI_STATUS            Status;
1155   UINT32                RemainingLength;
1156 
1157   EFI_TPL               OldTpl;
1158 
1159   Item             = NULL;
1160   Dns4TokenEntry   = NULL;
1161   Dns6TokenEntry   = NULL;
1162 
1163   IpCount          = 0;
1164   RRCount          = 0;
1165   AnswerSectionNum = 0;
1166   CNameTtl         = 0;
1167 
1168   HostAddr4        = NULL;
1169   HostAddr6        = NULL;
1170 
1171   Dns4CacheEntry   = NULL;
1172   Dns6CacheEntry   = NULL;
1173 
1174   Dns4RR           = NULL;
1175   Dns6RR           = NULL;
1176 
1177   *Completed       = TRUE;
1178   Status           = EFI_SUCCESS;
1179   RemainingLength  = Length;
1180 
1181   //
1182   // Check whether the remaining packet length is avaiable or not.
1183   //
1184   if (RemainingLength <= sizeof (DNS_HEADER)) {
1185     *Completed = FALSE;
1186     return EFI_ABORTED;
1187   } else {
1188     RemainingLength -= sizeof (DNS_HEADER);
1189   }
1190 
1191   //
1192   // Get header
1193   //
1194   DnsHeader = (DNS_HEADER *) RxString;
1195 
1196   DnsHeader->Identification = NTOHS (DnsHeader->Identification);
1197   DnsHeader->Flags.Uint16 = NTOHS (DnsHeader->Flags.Uint16);
1198   DnsHeader->QuestionsNum = NTOHS (DnsHeader->QuestionsNum);
1199   DnsHeader->AnswersNum = NTOHS (DnsHeader->AnswersNum);
1200   DnsHeader->AuthorityNum = NTOHS (DnsHeader->AuthorityNum);
1201   DnsHeader->AditionalNum = NTOHS (DnsHeader->AditionalNum);
1202 
1203   //
1204   // There is always one QuestionsNum in DNS message. The capability to handle more
1205   // than one requires to redesign the message format. Currently, it's not supported.
1206   //
1207   if (DnsHeader->QuestionsNum > 1) {
1208     *Completed = FALSE;
1209     return EFI_UNSUPPORTED;
1210   }
1211 
1212   //
1213   // Get Query name
1214   //
1215   QueryName = (CHAR8 *) (RxString + sizeof (*DnsHeader));
1216 
1217   QueryNameLen = (UINT32) AsciiStrLen (QueryName) + 1;
1218 
1219   //
1220   // Check whether the remaining packet length is avaiable or not.
1221   //
1222   if (RemainingLength <= QueryNameLen + sizeof (DNS_QUERY_SECTION)) {
1223     *Completed = FALSE;
1224     return EFI_ABORTED;
1225   } else {
1226     RemainingLength -= (QueryNameLen + sizeof (DNS_QUERY_SECTION));
1227   }
1228 
1229   //
1230   // Get query section
1231   //
1232   QuerySection = (DNS_QUERY_SECTION *) (QueryName + QueryNameLen);
1233   QuerySection->Type = NTOHS (QuerySection->Type);
1234   QuerySection->Class = NTOHS (QuerySection->Class);
1235 
1236   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1237 
1238   //
1239   // Check DnsResponse Validity, if so, also get a valid NET_MAP_ITEM.
1240   //
1241   if (Instance->Service->IpVersion == IP_VERSION_4) {
1242     if (!IsValidDnsResponse (
1243            &Instance->Dns4TxTokens,
1244            DnsHeader->Identification,
1245            QuerySection->Type,
1246            QuerySection->Class,
1247            &Item
1248            )) {
1249       *Completed = FALSE;
1250       Status = EFI_ABORTED;
1251       goto ON_EXIT;
1252     }
1253     ASSERT (Item != NULL);
1254     Dns4TokenEntry = (DNS4_TOKEN_ENTRY *) (Item->Key);
1255   } else {
1256     if (!IsValidDnsResponse (
1257            &Instance->Dns6TxTokens,
1258            DnsHeader->Identification,
1259            QuerySection->Type,
1260            QuerySection->Class,
1261            &Item
1262            )) {
1263       *Completed = FALSE;
1264       Status = EFI_ABORTED;
1265       goto ON_EXIT;
1266     }
1267     ASSERT (Item != NULL);
1268     Dns6TokenEntry = (DNS6_TOKEN_ENTRY *) (Item->Key);
1269   }
1270 
1271   //
1272   // Continue Check Some Errors.
1273   //
1274   if (DnsHeader->Flags.Bits.RCode != DNS_FLAGS_RCODE_NO_ERROR || DnsHeader->AnswersNum < 1 || \
1275       DnsHeader->Flags.Bits.QR != DNS_FLAGS_QR_RESPONSE) {
1276     //
1277     // The domain name referenced in the query does not exist.
1278     //
1279     if (DnsHeader->Flags.Bits.RCode == DNS_FLAGS_RCODE_NAME_ERROR) {
1280       Status = EFI_NOT_FOUND;
1281     } else {
1282       Status = EFI_DEVICE_ERROR;
1283     }
1284 
1285     goto ON_COMPLETE;
1286   }
1287 
1288   //
1289   // Do some buffer allocations.
1290   //
1291   if (Instance->Service->IpVersion == IP_VERSION_4) {
1292     ASSERT (Dns4TokenEntry != NULL);
1293 
1294     if (Dns4TokenEntry->GeneralLookUp) {
1295       //
1296       // It's the GeneralLookUp querying.
1297       //
1298       Dns4TokenEntry->Token->RspData.GLookupData = AllocateZeroPool (sizeof (DNS_RESOURCE_RECORD));
1299       if (Dns4TokenEntry->Token->RspData.GLookupData == NULL) {
1300         Status = EFI_OUT_OF_RESOURCES;
1301         goto ON_EXIT;
1302       }
1303       Dns4TokenEntry->Token->RspData.GLookupData->RRList = AllocateZeroPool (DnsHeader->AnswersNum * sizeof (DNS_RESOURCE_RECORD));
1304       if (Dns4TokenEntry->Token->RspData.GLookupData->RRList == NULL) {
1305         Status = EFI_OUT_OF_RESOURCES;
1306         goto ON_EXIT;
1307       }
1308     } else {
1309       //
1310       // It's not the GeneralLookUp querying. Check the Query type.
1311       //
1312       if (QuerySection->Type == DNS_TYPE_A) {
1313         Dns4TokenEntry->Token->RspData.H2AData = AllocateZeroPool (sizeof (DNS_HOST_TO_ADDR_DATA));
1314         if (Dns4TokenEntry->Token->RspData.H2AData == NULL) {
1315           Status = EFI_OUT_OF_RESOURCES;
1316           goto ON_EXIT;
1317         }
1318         Dns4TokenEntry->Token->RspData.H2AData->IpList = AllocateZeroPool (DnsHeader->AnswersNum * sizeof (EFI_IPv4_ADDRESS));
1319         if (Dns4TokenEntry->Token->RspData.H2AData->IpList == NULL) {
1320           Status = EFI_OUT_OF_RESOURCES;
1321           goto ON_EXIT;
1322         }
1323       } else {
1324         Status = EFI_UNSUPPORTED;
1325         goto ON_EXIT;
1326       }
1327     }
1328   } else {
1329     ASSERT (Dns6TokenEntry != NULL);
1330 
1331     if (Dns6TokenEntry->GeneralLookUp) {
1332       //
1333       // It's the GeneralLookUp querying.
1334       //
1335       Dns6TokenEntry->Token->RspData.GLookupData = AllocateZeroPool (sizeof (DNS_RESOURCE_RECORD));
1336       if (Dns6TokenEntry->Token->RspData.GLookupData == NULL) {
1337         Status = EFI_OUT_OF_RESOURCES;
1338         goto ON_EXIT;
1339       }
1340       Dns6TokenEntry->Token->RspData.GLookupData->RRList = AllocateZeroPool (DnsHeader->AnswersNum * sizeof (DNS_RESOURCE_RECORD));
1341       if (Dns6TokenEntry->Token->RspData.GLookupData->RRList == NULL) {
1342         Status = EFI_OUT_OF_RESOURCES;
1343         goto ON_EXIT;
1344       }
1345     } else {
1346       //
1347       // It's not the GeneralLookUp querying. Check the Query type.
1348       //
1349       if (QuerySection->Type == DNS_TYPE_AAAA) {
1350         Dns6TokenEntry->Token->RspData.H2AData = AllocateZeroPool (sizeof (DNS6_HOST_TO_ADDR_DATA));
1351         if (Dns6TokenEntry->Token->RspData.H2AData == NULL) {
1352           Status = EFI_OUT_OF_RESOURCES;
1353           goto ON_EXIT;
1354         }
1355         Dns6TokenEntry->Token->RspData.H2AData->IpList = AllocateZeroPool (DnsHeader->AnswersNum * sizeof (EFI_IPv6_ADDRESS));
1356         if (Dns6TokenEntry->Token->RspData.H2AData->IpList == NULL) {
1357           Status = EFI_OUT_OF_RESOURCES;
1358           goto ON_EXIT;
1359         }
1360       } else {
1361         Status = EFI_UNSUPPORTED;
1362         goto ON_EXIT;
1363       }
1364     }
1365   }
1366 
1367   Status = EFI_NOT_FOUND;
1368 
1369   //
1370   // Get Answer name
1371   //
1372   AnswerName = (CHAR8 *) QuerySection + sizeof (*QuerySection);
1373 
1374   //
1375   // Processing AnswerSection.
1376   //
1377   while (AnswerSectionNum < DnsHeader->AnswersNum) {
1378     //
1379     // Check whether the remaining packet length is avaiable or not.
1380     //
1381     if (RemainingLength <= sizeof (UINT16) + sizeof (DNS_ANSWER_SECTION)) {
1382       *Completed = FALSE;
1383       Status = EFI_ABORTED;
1384       goto ON_EXIT;
1385     } else {
1386       RemainingLength -= (sizeof (UINT16) + sizeof (DNS_ANSWER_SECTION));
1387     }
1388 
1389     //
1390     // Answer name should be PTR, else EFI_UNSUPPORTED returned.
1391     //
1392     if ((*(UINT8 *) AnswerName & 0xC0) != 0xC0) {
1393       Status = EFI_UNSUPPORTED;
1394       goto ON_EXIT;
1395     }
1396 
1397     //
1398     // Get Answer section.
1399     //
1400     AnswerSection = (DNS_ANSWER_SECTION *) (AnswerName + sizeof (UINT16));
1401     AnswerSection->Type = NTOHS (AnswerSection->Type);
1402     AnswerSection->Class = NTOHS (AnswerSection->Class);
1403     AnswerSection->Ttl = NTOHL (AnswerSection->Ttl);
1404     AnswerSection->DataLength = NTOHS (AnswerSection->DataLength);
1405 
1406     //
1407     // Check whether the remaining packet length is avaiable or not.
1408     //
1409     if (RemainingLength < AnswerSection->DataLength) {
1410       *Completed = FALSE;
1411       Status = EFI_ABORTED;
1412       goto ON_EXIT;
1413     } else {
1414       RemainingLength -= AnswerSection->DataLength;
1415     }
1416 
1417     //
1418     // Check whether it's the GeneralLookUp querying.
1419     //
1420     if (Instance->Service->IpVersion == IP_VERSION_4 && Dns4TokenEntry->GeneralLookUp) {
1421       Dns4RR = Dns4TokenEntry->Token->RspData.GLookupData->RRList;
1422       AnswerData = (UINT8 *) AnswerSection + sizeof (*AnswerSection);
1423 
1424       //
1425       // Fill the ResourceRecord.
1426       //
1427       Dns4RR[RRCount].QName = AllocateZeroPool (AsciiStrLen (QueryName) + 1);
1428       if (Dns4RR[RRCount].QName == NULL) {
1429         Status = EFI_OUT_OF_RESOURCES;
1430         goto ON_EXIT;
1431       }
1432       CopyMem (Dns4RR[RRCount].QName, QueryName, AsciiStrLen (QueryName));
1433       Dns4RR[RRCount].QType = AnswerSection->Type;
1434       Dns4RR[RRCount].QClass = AnswerSection->Class;
1435       Dns4RR[RRCount].TTL = AnswerSection->Ttl;
1436       Dns4RR[RRCount].DataLength = AnswerSection->DataLength;
1437       Dns4RR[RRCount].RData = AllocateZeroPool (Dns4RR[RRCount].DataLength);
1438       if (Dns4RR[RRCount].RData == NULL) {
1439         Status = EFI_OUT_OF_RESOURCES;
1440         goto ON_EXIT;
1441       }
1442       CopyMem (Dns4RR[RRCount].RData, AnswerData, Dns4RR[RRCount].DataLength);
1443 
1444       RRCount ++;
1445       Status = EFI_SUCCESS;
1446     } else if (Instance->Service->IpVersion == IP_VERSION_6 && Dns6TokenEntry->GeneralLookUp) {
1447       Dns6RR = Dns6TokenEntry->Token->RspData.GLookupData->RRList;
1448       AnswerData = (UINT8 *) AnswerSection + sizeof (*AnswerSection);
1449 
1450       //
1451       // Fill the ResourceRecord.
1452       //
1453       Dns6RR[RRCount].QName = AllocateZeroPool (AsciiStrLen (QueryName) + 1);
1454       if (Dns6RR[RRCount].QName == NULL) {
1455         Status = EFI_OUT_OF_RESOURCES;
1456         goto ON_EXIT;
1457       }
1458       CopyMem (Dns6RR[RRCount].QName, QueryName, AsciiStrLen (QueryName));
1459       Dns6RR[RRCount].QType = AnswerSection->Type;
1460       Dns6RR[RRCount].QClass = AnswerSection->Class;
1461       Dns6RR[RRCount].TTL = AnswerSection->Ttl;
1462       Dns6RR[RRCount].DataLength = AnswerSection->DataLength;
1463       Dns6RR[RRCount].RData = AllocateZeroPool (Dns6RR[RRCount].DataLength);
1464       if (Dns6RR[RRCount].RData == NULL) {
1465         Status = EFI_OUT_OF_RESOURCES;
1466         goto ON_EXIT;
1467       }
1468       CopyMem (Dns6RR[RRCount].RData, AnswerData, Dns6RR[RRCount].DataLength);
1469 
1470       RRCount ++;
1471       Status = EFI_SUCCESS;
1472     } else {
1473       //
1474       // It's not the GeneralLookUp querying.
1475       // Check the Query type, parse the response packet.
1476       //
1477       switch (AnswerSection->Type) {
1478       case DNS_TYPE_A:
1479         //
1480         // This is address entry, get Data.
1481         //
1482         ASSERT (Dns4TokenEntry != NULL);
1483 
1484         if (AnswerSection->DataLength != 4) {
1485           Status = EFI_ABORTED;
1486           goto ON_EXIT;
1487         }
1488 
1489         HostAddr4 = Dns4TokenEntry->Token->RspData.H2AData->IpList;
1490         AnswerData = (UINT8 *) AnswerSection + sizeof (*AnswerSection);
1491         CopyMem (&HostAddr4[IpCount], AnswerData, sizeof (EFI_IPv4_ADDRESS));
1492 
1493         //
1494         // Allocate new CacheEntry pool to update DNS cache dynamically.
1495         //
1496         Dns4CacheEntry = AllocateZeroPool (sizeof (EFI_DNS4_CACHE_ENTRY));
1497         if (Dns4CacheEntry == NULL) {
1498           Status = EFI_OUT_OF_RESOURCES;
1499           goto ON_EXIT;
1500         }
1501         Dns4CacheEntry->HostName = AllocateZeroPool (2 * (StrLen(Dns4TokenEntry->QueryHostName) + 1));
1502         if (Dns4CacheEntry->HostName == NULL) {
1503           Status = EFI_OUT_OF_RESOURCES;
1504           goto ON_EXIT;
1505         }
1506         CopyMem (Dns4CacheEntry->HostName, Dns4TokenEntry->QueryHostName, 2 * (StrLen(Dns4TokenEntry->QueryHostName) + 1));
1507         Dns4CacheEntry->IpAddress = AllocateZeroPool (sizeof (EFI_IPv4_ADDRESS));
1508         if (Dns4CacheEntry->IpAddress == NULL) {
1509           Status = EFI_OUT_OF_RESOURCES;
1510           goto ON_EXIT;
1511         }
1512         CopyMem (Dns4CacheEntry->IpAddress, AnswerData, sizeof (EFI_IPv4_ADDRESS));
1513 
1514         if (CNameTtl != 0 && AnswerSection->Ttl != 0) {
1515           Dns4CacheEntry->Timeout = MIN (CNameTtl, AnswerSection->Ttl);
1516         } else {
1517           Dns4CacheEntry->Timeout = MAX (CNameTtl, AnswerSection->Ttl);
1518         }
1519 
1520         UpdateDns4Cache (&mDriverData->Dns4CacheList, FALSE, TRUE, *Dns4CacheEntry);
1521 
1522         //
1523         // Free allocated CacheEntry pool.
1524         //
1525         FreePool (Dns4CacheEntry->HostName);
1526         Dns4CacheEntry->HostName = NULL;
1527 
1528         FreePool (Dns4CacheEntry->IpAddress);
1529         Dns4CacheEntry->IpAddress = NULL;
1530 
1531         FreePool (Dns4CacheEntry);
1532         Dns4CacheEntry = NULL;
1533 
1534         IpCount ++;
1535         Status = EFI_SUCCESS;
1536         break;
1537       case DNS_TYPE_AAAA:
1538         //
1539         // This is address entry, get Data.
1540         //
1541         ASSERT (Dns6TokenEntry != NULL);
1542 
1543         if (AnswerSection->DataLength != 16) {
1544           Status = EFI_ABORTED;
1545           goto ON_EXIT;
1546         }
1547 
1548         HostAddr6 = Dns6TokenEntry->Token->RspData.H2AData->IpList;
1549         AnswerData = (UINT8 *) AnswerSection + sizeof (*AnswerSection);
1550         CopyMem (&HostAddr6[IpCount], AnswerData, sizeof (EFI_IPv6_ADDRESS));
1551 
1552         //
1553         // Allocate new CacheEntry pool to update DNS cache dynamically.
1554         //
1555         Dns6CacheEntry = AllocateZeroPool (sizeof (EFI_DNS6_CACHE_ENTRY));
1556         if (Dns6CacheEntry == NULL) {
1557           Status = EFI_OUT_OF_RESOURCES;
1558           goto ON_EXIT;
1559         }
1560         Dns6CacheEntry->HostName = AllocateZeroPool (2 * (StrLen(Dns6TokenEntry->QueryHostName) + 1));
1561         if (Dns6CacheEntry->HostName == NULL) {
1562           Status = EFI_OUT_OF_RESOURCES;
1563           goto ON_EXIT;
1564         }
1565         CopyMem (Dns6CacheEntry->HostName, Dns6TokenEntry->QueryHostName, 2 * (StrLen(Dns6TokenEntry->QueryHostName) + 1));
1566         Dns6CacheEntry->IpAddress = AllocateZeroPool (sizeof (EFI_IPv6_ADDRESS));
1567         if (Dns6CacheEntry->IpAddress == NULL) {
1568           Status = EFI_OUT_OF_RESOURCES;
1569           goto ON_EXIT;
1570         }
1571         CopyMem (Dns6CacheEntry->IpAddress, AnswerData, sizeof (EFI_IPv6_ADDRESS));
1572 
1573         if (CNameTtl != 0 && AnswerSection->Ttl != 0) {
1574           Dns6CacheEntry->Timeout = MIN (CNameTtl, AnswerSection->Ttl);
1575         } else {
1576           Dns6CacheEntry->Timeout = MAX (CNameTtl, AnswerSection->Ttl);
1577         }
1578 
1579         UpdateDns6Cache (&mDriverData->Dns6CacheList, FALSE, TRUE, *Dns6CacheEntry);
1580 
1581         //
1582         // Free allocated CacheEntry pool.
1583         //
1584         FreePool (Dns6CacheEntry->HostName);
1585         Dns6CacheEntry->HostName = NULL;
1586 
1587         FreePool (Dns6CacheEntry->IpAddress);
1588         Dns6CacheEntry->IpAddress = NULL;
1589 
1590         FreePool (Dns6CacheEntry);
1591         Dns6CacheEntry = NULL;
1592 
1593         IpCount ++;
1594         Status = EFI_SUCCESS;
1595         break;
1596       case DNS_TYPE_CNAME:
1597         //
1598         // According RFC 1034 - 3.6.2, if the query name is an alias, the name server will include the CNAME
1599         // record in the response and restart the query at the domain name specified in the data field of the
1600         // CNAME record. So, just record the TTL value of the CNAME, then skip to parse the next record.
1601         //
1602         CNameTtl = AnswerSection->Ttl;
1603         break;
1604       default:
1605         Status = EFI_UNSUPPORTED;
1606         goto ON_EXIT;
1607       }
1608     }
1609 
1610     //
1611     // Find next one
1612     //
1613     AnswerName = (CHAR8 *) AnswerSection + sizeof (*AnswerSection) + AnswerSection->DataLength;
1614     AnswerSectionNum ++;
1615   }
1616 
1617   if (Instance->Service->IpVersion == IP_VERSION_4) {
1618     ASSERT (Dns4TokenEntry != NULL);
1619 
1620     if (Dns4TokenEntry->GeneralLookUp) {
1621       Dns4TokenEntry->Token->RspData.GLookupData->RRCount = RRCount;
1622     } else {
1623       if (QuerySection->Type == DNS_TYPE_A) {
1624         Dns4TokenEntry->Token->RspData.H2AData->IpCount = IpCount;
1625       } else {
1626         Status = EFI_UNSUPPORTED;
1627         goto ON_EXIT;
1628       }
1629     }
1630   } else {
1631     ASSERT (Dns6TokenEntry != NULL);
1632 
1633     if (Dns6TokenEntry->GeneralLookUp) {
1634       Dns6TokenEntry->Token->RspData.GLookupData->RRCount = RRCount;
1635     } else {
1636       if (QuerySection->Type == DNS_TYPE_AAAA) {
1637         Dns6TokenEntry->Token->RspData.H2AData->IpCount = IpCount;
1638       } else {
1639         Status = EFI_UNSUPPORTED;
1640         goto ON_EXIT;
1641       }
1642     }
1643   }
1644 
1645 ON_COMPLETE:
1646   //
1647   // Parsing is complete, free the sending packet and signal Event here.
1648   //
1649   if (Item != NULL && Item->Value != NULL) {
1650     NetbufFree ((NET_BUF *) (Item->Value));
1651   }
1652 
1653   if (Instance->Service->IpVersion == IP_VERSION_4) {
1654     ASSERT (Dns4TokenEntry != NULL);
1655     Dns4RemoveTokenEntry (&Instance->Dns4TxTokens, Dns4TokenEntry);
1656     Dns4TokenEntry->Token->Status = Status;
1657     if (Dns4TokenEntry->Token->Event != NULL) {
1658       gBS->SignalEvent (Dns4TokenEntry->Token->Event);
1659       DispatchDpc ();
1660     }
1661   } else {
1662     ASSERT (Dns6TokenEntry != NULL);
1663     Dns6RemoveTokenEntry (&Instance->Dns6TxTokens, Dns6TokenEntry);
1664     Dns6TokenEntry->Token->Status = Status;
1665     if (Dns6TokenEntry->Token->Event != NULL) {
1666       gBS->SignalEvent (Dns6TokenEntry->Token->Event);
1667       DispatchDpc ();
1668     }
1669   }
1670 
1671 ON_EXIT:
1672   //
1673   // Free the allocated buffer if error happen.
1674   //
1675   if (EFI_ERROR (Status)) {
1676     if (Dns4TokenEntry != NULL) {
1677       if (Dns4TokenEntry->GeneralLookUp) {
1678         if (Dns4TokenEntry->Token->RspData.GLookupData != NULL) {
1679           if (Dns4TokenEntry->Token->RspData.GLookupData->RRList != NULL) {
1680             while (RRCount != 0) {
1681               RRCount --;
1682               if (Dns4TokenEntry->Token->RspData.GLookupData->RRList[RRCount].QName != NULL) {
1683                 FreePool (Dns4TokenEntry->Token->RspData.GLookupData->RRList[RRCount].QName);
1684               }
1685 
1686               if (Dns4TokenEntry->Token->RspData.GLookupData->RRList[RRCount].RData != NULL) {
1687                 FreePool (Dns4TokenEntry->Token->RspData.GLookupData->RRList[RRCount].RData);
1688               }
1689             }
1690 
1691             FreePool (Dns4TokenEntry->Token->RspData.GLookupData->RRList);
1692           }
1693 
1694           FreePool (Dns4TokenEntry->Token->RspData.GLookupData);
1695         }
1696       } else {
1697         if (QuerySection->Type == DNS_TYPE_A && Dns4TokenEntry->Token->RspData.H2AData != NULL) {
1698           if (Dns4TokenEntry->Token->RspData.H2AData->IpList != NULL) {
1699             FreePool (Dns4TokenEntry->Token->RspData.H2AData->IpList);
1700           }
1701 
1702           FreePool (Dns4TokenEntry->Token->RspData.H2AData);
1703         }
1704       }
1705     }
1706 
1707     if (Dns6TokenEntry != NULL) {
1708       if (Dns6TokenEntry->GeneralLookUp) {
1709         if (Dns6TokenEntry->Token->RspData.GLookupData != NULL) {
1710           if (Dns6TokenEntry->Token->RspData.GLookupData->RRList != NULL) {
1711             while (RRCount != 0) {
1712               RRCount --;
1713               if (Dns6TokenEntry->Token->RspData.GLookupData->RRList[RRCount].QName != NULL) {
1714                 FreePool (Dns6TokenEntry->Token->RspData.GLookupData->RRList[RRCount].QName);
1715               }
1716 
1717               if (Dns6TokenEntry->Token->RspData.GLookupData->RRList[RRCount].RData != NULL) {
1718                 FreePool (Dns6TokenEntry->Token->RspData.GLookupData->RRList[RRCount].RData);
1719               }
1720             }
1721 
1722             FreePool (Dns6TokenEntry->Token->RspData.GLookupData->RRList);
1723           }
1724 
1725           FreePool (Dns6TokenEntry->Token->RspData.GLookupData);
1726         }
1727       } else {
1728         if (QuerySection->Type == DNS_TYPE_AAAA && Dns6TokenEntry->Token->RspData.H2AData != NULL) {
1729           if (Dns6TokenEntry->Token->RspData.H2AData->IpList != NULL) {
1730             FreePool (Dns6TokenEntry->Token->RspData.H2AData->IpList);
1731           }
1732 
1733           FreePool (Dns6TokenEntry->Token->RspData.H2AData);
1734         }
1735       }
1736     }
1737 
1738     if (Dns4CacheEntry != NULL) {
1739       if (Dns4CacheEntry->HostName != NULL) {
1740         FreePool (Dns4CacheEntry->HostName);
1741       }
1742 
1743       if (Dns4CacheEntry->IpAddress != NULL) {
1744         FreePool (Dns4CacheEntry->IpAddress);
1745       }
1746 
1747       FreePool (Dns4CacheEntry);
1748     }
1749 
1750     if (Dns6CacheEntry != NULL) {
1751       if (Dns6CacheEntry->HostName != NULL) {
1752         FreePool (Dns6CacheEntry->HostName);
1753       }
1754 
1755       if (Dns6CacheEntry->IpAddress != NULL) {
1756         FreePool (Dns6CacheEntry->IpAddress);
1757       }
1758 
1759       FreePool (Dns6CacheEntry);
1760     }
1761   }
1762 
1763   gBS->RestoreTPL (OldTpl);
1764   return Status;
1765 }
1766 
1767 /**
1768   Parse response packet.
1769 
1770   @param  Packet                The packets received.
1771   @param  EndPoint              The local/remote UDP access point
1772   @param  IoStatus              The status of the UDP receive
1773   @param  Context               The opaque parameter to the function.
1774 
1775 **/
1776 VOID
1777 EFIAPI
DnsOnPacketReceived(NET_BUF * Packet,UDP_END_POINT * EndPoint,EFI_STATUS IoStatus,VOID * Context)1778 DnsOnPacketReceived (
1779   NET_BUF                   *Packet,
1780   UDP_END_POINT             *EndPoint,
1781   EFI_STATUS                IoStatus,
1782   VOID                      *Context
1783   )
1784 {
1785   DNS_INSTANCE              *Instance;
1786 
1787   UINT8                     *RcvString;
1788   UINT32                    Len;
1789 
1790   BOOLEAN                   Completed;
1791 
1792   Instance  = (DNS_INSTANCE *) Context;
1793   NET_CHECK_SIGNATURE (Instance, DNS_INSTANCE_SIGNATURE);
1794 
1795   RcvString = NULL;
1796   Completed = FALSE;
1797 
1798   if (EFI_ERROR (IoStatus)) {
1799     goto ON_EXIT;
1800   }
1801 
1802   ASSERT (Packet != NULL);
1803 
1804   Len = Packet->TotalSize;
1805 
1806   RcvString = NetbufGetByte (Packet, 0, NULL);
1807   ASSERT (RcvString != NULL);
1808 
1809   //
1810   // Parse Dns Response
1811   //
1812   ParseDnsResponse (Instance, RcvString, Len, &Completed);
1813 
1814 ON_EXIT:
1815 
1816   if (Packet != NULL) {
1817     NetbufFree (Packet);
1818   }
1819 
1820   if (!Completed) {
1821     UdpIoRecvDatagram (Instance->UdpIo, DnsOnPacketReceived, Instance, 0);
1822   }
1823 }
1824 
1825 /**
1826   Release the net buffer when packet is sent.
1827 
1828   @param  Packet                The packets received.
1829   @param  EndPoint              The local/remote UDP access point
1830   @param  IoStatus              The status of the UDP receive
1831   @param  Context               The opaque parameter to the function.
1832 
1833 **/
1834 VOID
1835 EFIAPI
DnsOnPacketSent(NET_BUF * Packet,UDP_END_POINT * EndPoint,EFI_STATUS IoStatus,VOID * Context)1836 DnsOnPacketSent (
1837   NET_BUF                   *Packet,
1838   UDP_END_POINT             *EndPoint,
1839   EFI_STATUS                IoStatus,
1840   VOID                      *Context
1841   )
1842 {
1843   DNS_INSTANCE              *Instance;
1844   LIST_ENTRY                *Entry;
1845   NET_MAP_ITEM              *Item;
1846   DNS4_TOKEN_ENTRY          *Dns4TokenEntry;
1847   DNS6_TOKEN_ENTRY          *Dns6TokenEntry;
1848 
1849   Dns4TokenEntry = NULL;
1850   Dns6TokenEntry = NULL;
1851 
1852   Instance  = (DNS_INSTANCE *) Context;
1853   NET_CHECK_SIGNATURE (Instance, DNS_INSTANCE_SIGNATURE);
1854 
1855   if (Instance->Service->IpVersion == IP_VERSION_4) {
1856     NET_LIST_FOR_EACH (Entry, &Instance->Dns4TxTokens.Used) {
1857       Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
1858       if (Packet == (NET_BUF *)(Item->Value)) {
1859         Dns4TokenEntry = ((DNS4_TOKEN_ENTRY *)Item->Key);
1860         Dns4TokenEntry->PacketToLive = Dns4TokenEntry->Token->RetryInterval;
1861         break;
1862       }
1863     }
1864   } else {
1865     NET_LIST_FOR_EACH (Entry, &Instance->Dns6TxTokens.Used) {
1866       Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
1867       if (Packet == (NET_BUF *)(Item->Value)) {
1868         Dns6TokenEntry = ((DNS6_TOKEN_ENTRY *)Item->Key);
1869         Dns6TokenEntry->PacketToLive = Dns6TokenEntry->Token->RetryInterval;
1870         break;
1871       }
1872     }
1873   }
1874 
1875   NetbufFree (Packet);
1876 }
1877 
1878 /**
1879   Query request information.
1880 
1881   @param  Instance              The DNS instance
1882   @param  Packet                The packet for querying request information.
1883 
1884   @retval EFI_SUCCESS           Query request information successfully.
1885   @retval Others                Failed to query request information.
1886 
1887 **/
1888 EFI_STATUS
DoDnsQuery(IN DNS_INSTANCE * Instance,IN NET_BUF * Packet)1889 DoDnsQuery (
1890   IN  DNS_INSTANCE              *Instance,
1891   IN  NET_BUF                   *Packet
1892   )
1893 {
1894   EFI_STATUS      Status;
1895 
1896   //
1897   // Ready to receive the DNS response.
1898   //
1899   if (Instance->UdpIo->RecvRequest == NULL) {
1900     Status = UdpIoRecvDatagram (Instance->UdpIo, DnsOnPacketReceived, Instance, 0);
1901     if (EFI_ERROR (Status)) {
1902       return Status;
1903     }
1904   }
1905 
1906   //
1907   // Transmit the DNS packet.
1908   //
1909   NET_GET_REF (Packet);
1910 
1911   Status = UdpIoSendDatagram (Instance->UdpIo, Packet, NULL, NULL, DnsOnPacketSent, Instance);
1912 
1913   return Status;
1914 }
1915 
1916 /**
1917   Construct the Packet according query section.
1918 
1919   @param  Instance              The DNS instance
1920   @param  QueryName             Queried Name
1921   @param  Type                  Queried Type
1922   @param  Class                 Queried Class
1923   @param  Packet                The packet for query
1924 
1925   @retval EFI_SUCCESS           The packet is constructed.
1926   @retval Others                Failed to construct the Packet.
1927 
1928 **/
1929 EFI_STATUS
ConstructDNSQuery(IN DNS_INSTANCE * Instance,IN CHAR8 * QueryName,IN UINT16 Type,IN UINT16 Class,OUT NET_BUF ** Packet)1930 ConstructDNSQuery (
1931   IN  DNS_INSTANCE              *Instance,
1932   IN  CHAR8                     *QueryName,
1933   IN  UINT16                    Type,
1934   IN  UINT16                    Class,
1935   OUT NET_BUF                   **Packet
1936   )
1937 {
1938   NET_FRAGMENT        Frag;
1939   DNS_HEADER          *DnsHeader;
1940   DNS_QUERY_SECTION   *DnsQuery;
1941 
1942   //
1943   // Messages carried by UDP are restricted to 512 bytes (not counting the IP
1944   // or UDP headers).
1945   //
1946   Frag.Bulk = AllocatePool (DNS_MAX_MESSAGE_SIZE * sizeof (UINT8));
1947   if (Frag.Bulk == NULL) {
1948     return EFI_OUT_OF_RESOURCES;
1949   }
1950 
1951   //
1952   // Fill header
1953   //
1954   DnsHeader = (DNS_HEADER *) Frag.Bulk;
1955   DnsHeader->Identification = (UINT16)NET_RANDOM (NetRandomInitSeed());
1956   DnsHeader->Flags.Uint16 = 0x0000;
1957   DnsHeader->Flags.Bits.RD = 1;
1958   DnsHeader->Flags.Bits.OpCode = DNS_FLAGS_OPCODE_STANDARD;
1959   DnsHeader->Flags.Bits.QR = DNS_FLAGS_QR_QUERY;
1960   DnsHeader->QuestionsNum = 1;
1961   DnsHeader->AnswersNum = 0;
1962   DnsHeader->AuthorityNum = 0;
1963   DnsHeader->AditionalNum = 0;
1964 
1965   DnsHeader->Identification = HTONS (DnsHeader->Identification);
1966   DnsHeader->Flags.Uint16 = HTONS (DnsHeader->Flags.Uint16);
1967   DnsHeader->QuestionsNum = HTONS (DnsHeader->QuestionsNum);
1968   DnsHeader->AnswersNum = HTONS (DnsHeader->AnswersNum);
1969   DnsHeader->AuthorityNum = HTONS (DnsHeader->AuthorityNum);
1970   DnsHeader->AditionalNum = HTONS (DnsHeader->AditionalNum);
1971 
1972   Frag.Len = sizeof (*DnsHeader);
1973 
1974   //
1975   // Fill Query name
1976   //
1977   CopyMem (Frag.Bulk + Frag.Len, QueryName, AsciiStrLen (QueryName));
1978   Frag.Len = (UINT32) (Frag.Len + AsciiStrLen (QueryName));
1979   *(Frag.Bulk + Frag.Len) = 0;
1980   Frag.Len ++;
1981 
1982   //
1983   // Rest query section
1984   //
1985   DnsQuery = (DNS_QUERY_SECTION *) (Frag.Bulk + Frag.Len);
1986 
1987   DnsQuery->Type = HTONS (Type);
1988   DnsQuery->Class = HTONS (Class);
1989 
1990   Frag.Len += sizeof (*DnsQuery);
1991 
1992   //
1993   // Wrap the Frag in a net buffer.
1994   //
1995   *Packet = NetbufFromExt (&Frag, 1, 0, 0, DnsDummyExtFree, NULL);
1996   if (*Packet == NULL) {
1997     FreePool (Frag.Bulk);
1998     return EFI_OUT_OF_RESOURCES;
1999   }
2000 
2001   //
2002   // Store the UdpIo in ProtoData.
2003   //
2004   *((UINTN *) &((*Packet)->ProtoData[0])) = (UINTN) (Instance->UdpIo);
2005 
2006   return EFI_SUCCESS;
2007 }
2008 
2009 /**
2010   Retransmit the packet.
2011 
2012   @param  Instance              The DNS instance
2013   @param  Packet                Retransmit the packet
2014 
2015   @retval EFI_SUCCESS           The packet is retransmitted.
2016   @retval Others                Failed to retransmit.
2017 
2018 **/
2019 EFI_STATUS
DnsRetransmit(IN DNS_INSTANCE * Instance,IN NET_BUF * Packet)2020 DnsRetransmit (
2021   IN DNS_INSTANCE        *Instance,
2022   IN NET_BUF             *Packet
2023   )
2024 {
2025   EFI_STATUS      Status;
2026 
2027   UINT8           *Buffer;
2028 
2029   ASSERT (Packet != NULL);
2030 
2031   //
2032   // Set the requests to the listening port, other packets to the connected port
2033   //
2034   Buffer = NetbufGetByte (Packet, 0, NULL);
2035   ASSERT (Buffer != NULL);
2036 
2037   NET_GET_REF (Packet);
2038 
2039   Status = UdpIoSendDatagram (
2040              Instance->UdpIo,
2041              Packet,
2042              NULL,
2043              NULL,
2044              DnsOnPacketSent,
2045              Instance
2046              );
2047 
2048   if (EFI_ERROR (Status)) {
2049     NET_PUT_REF (Packet);
2050   }
2051 
2052   return Status;
2053 }
2054 
2055 /**
2056   The timer ticking function for the DNS services.
2057 
2058   @param  Event                 The ticking event
2059   @param  Context               The DNS service instance
2060 
2061 **/
2062 VOID
2063 EFIAPI
DnsOnTimerRetransmit(IN EFI_EVENT Event,IN VOID * Context)2064 DnsOnTimerRetransmit (
2065   IN EFI_EVENT              Event,
2066   IN VOID                   *Context
2067   )
2068 {
2069   DNS_SERVICE                *Service;
2070 
2071   LIST_ENTRY                 *Entry;
2072   LIST_ENTRY                 *Next;
2073 
2074   DNS_INSTANCE               *Instance;
2075   LIST_ENTRY                 *EntryNetMap;
2076   NET_MAP_ITEM               *ItemNetMap;
2077   DNS4_TOKEN_ENTRY           *Dns4TokenEntry;
2078   DNS6_TOKEN_ENTRY           *Dns6TokenEntry;
2079 
2080   Dns4TokenEntry = NULL;
2081   Dns6TokenEntry = NULL;
2082 
2083   Service = (DNS_SERVICE *) Context;
2084 
2085 
2086   if (Service->IpVersion == IP_VERSION_4) {
2087     //
2088     // Iterate through all the children of the DNS service instance. Time
2089     // out the packet. If maximum retries reached, clean the Token up.
2090     //
2091     NET_LIST_FOR_EACH_SAFE (Entry, Next, &Service->Dns4ChildrenList) {
2092       Instance = NET_LIST_USER_STRUCT (Entry, DNS_INSTANCE, Link);
2093 
2094       EntryNetMap = Instance->Dns4TxTokens.Used.ForwardLink;
2095       while (EntryNetMap != &Instance->Dns4TxTokens.Used) {
2096         ItemNetMap = NET_LIST_USER_STRUCT (EntryNetMap, NET_MAP_ITEM, Link);
2097         Dns4TokenEntry = (DNS4_TOKEN_ENTRY *)(ItemNetMap->Key);
2098         if (Dns4TokenEntry->PacketToLive == 0 || (--Dns4TokenEntry->PacketToLive > 0)) {
2099           EntryNetMap = EntryNetMap->ForwardLink;
2100           continue;
2101         }
2102 
2103         //
2104         // Retransmit the packet if haven't reach the maxmium retry count,
2105         // otherwise exit the transfer.
2106         //
2107         if (++Dns4TokenEntry->RetryCounting <= Dns4TokenEntry->Token->RetryCount) {
2108           DnsRetransmit (Instance, (NET_BUF *)ItemNetMap->Value);
2109           EntryNetMap = EntryNetMap->ForwardLink;
2110         } else {
2111           //
2112           // Maximum retries reached, clean the Token up.
2113           //
2114           Dns4RemoveTokenEntry (&Instance->Dns4TxTokens, Dns4TokenEntry);
2115           Dns4TokenEntry->Token->Status = EFI_TIMEOUT;
2116           gBS->SignalEvent (Dns4TokenEntry->Token->Event);
2117           DispatchDpc ();
2118 
2119           //
2120           // Free the sending packet.
2121           //
2122           if (ItemNetMap->Value != NULL) {
2123             NetbufFree ((NET_BUF *)(ItemNetMap->Value));
2124           }
2125 
2126           EntryNetMap = Instance->Dns4TxTokens.Used.ForwardLink;
2127         }
2128       }
2129     }
2130   }else {
2131     //
2132     // Iterate through all the children of the DNS service instance. Time
2133     // out the packet. If maximum retries reached, clean the Token up.
2134     //
2135     NET_LIST_FOR_EACH_SAFE (Entry, Next, &Service->Dns6ChildrenList) {
2136       Instance = NET_LIST_USER_STRUCT (Entry, DNS_INSTANCE, Link);
2137 
2138       EntryNetMap = Instance->Dns6TxTokens.Used.ForwardLink;
2139       while (EntryNetMap != &Instance->Dns6TxTokens.Used) {
2140         ItemNetMap = NET_LIST_USER_STRUCT (EntryNetMap, NET_MAP_ITEM, Link);
2141         Dns6TokenEntry = (DNS6_TOKEN_ENTRY *) (ItemNetMap->Key);
2142         if (Dns6TokenEntry->PacketToLive == 0 || (--Dns6TokenEntry->PacketToLive > 0)) {
2143           EntryNetMap = EntryNetMap->ForwardLink;
2144           continue;
2145         }
2146 
2147         //
2148         // Retransmit the packet if haven't reach the maxmium retry count,
2149         // otherwise exit the transfer.
2150         //
2151         if (++Dns6TokenEntry->RetryCounting <= Dns6TokenEntry->Token->RetryCount) {
2152           DnsRetransmit (Instance, (NET_BUF *) ItemNetMap->Value);
2153           EntryNetMap = EntryNetMap->ForwardLink;
2154         } else {
2155           //
2156           // Maximum retries reached, clean the Token up.
2157           //
2158           Dns6RemoveTokenEntry (&Instance->Dns6TxTokens, Dns6TokenEntry);
2159           Dns6TokenEntry->Token->Status = EFI_TIMEOUT;
2160           gBS->SignalEvent (Dns6TokenEntry->Token->Event);
2161           DispatchDpc ();
2162 
2163           //
2164           // Free the sending packet.
2165           //
2166           if (ItemNetMap->Value != NULL) {
2167             NetbufFree ((NET_BUF *) (ItemNetMap->Value));
2168           }
2169 
2170           EntryNetMap = Instance->Dns6TxTokens.Used.ForwardLink;
2171         }
2172       }
2173     }
2174   }
2175 }
2176 
2177 /**
2178   The timer ticking function for the DNS driver.
2179 
2180   @param  Event                 The ticking event
2181   @param  Context               NULL
2182 
2183 **/
2184 VOID
2185 EFIAPI
DnsOnTimerUpdate(IN EFI_EVENT Event,IN VOID * Context)2186 DnsOnTimerUpdate (
2187   IN EFI_EVENT              Event,
2188   IN VOID                   *Context
2189   )
2190 {
2191   LIST_ENTRY                 *Entry;
2192   LIST_ENTRY                 *Next;
2193   DNS4_CACHE                 *Item4;
2194   DNS6_CACHE                 *Item6;
2195 
2196   Item4 = NULL;
2197   Item6 = NULL;
2198 
2199   //
2200   // Iterate through all the DNS4 cache list.
2201   //
2202   NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns4CacheList) {
2203     Item4 = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink);
2204     Item4->DnsCache.Timeout--;
2205   }
2206 
2207   Entry = mDriverData->Dns4CacheList.ForwardLink;
2208   while (Entry != &mDriverData->Dns4CacheList) {
2209     Item4 = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink);
2210     if (Item4->DnsCache.Timeout == 0) {
2211       RemoveEntryList (&Item4->AllCacheLink);
2212       FreePool (Item4->DnsCache.HostName);
2213       FreePool (Item4->DnsCache.IpAddress);
2214       FreePool (Item4);
2215       Entry = mDriverData->Dns4CacheList.ForwardLink;
2216     } else {
2217       Entry = Entry->ForwardLink;
2218     }
2219   }
2220 
2221   //
2222   // Iterate through all the DNS6 cache list.
2223   //
2224   NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns6CacheList) {
2225     Item6 = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink);
2226     Item6->DnsCache.Timeout--;
2227   }
2228 
2229   Entry = mDriverData->Dns6CacheList.ForwardLink;
2230   while (Entry != &mDriverData->Dns6CacheList) {
2231     Item6 = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink);
2232     if (Item6->DnsCache.Timeout == 0) {
2233       RemoveEntryList (&Item6->AllCacheLink);
2234       FreePool (Item6->DnsCache.HostName);
2235       FreePool (Item6->DnsCache.IpAddress);
2236       FreePool (Item6);
2237       Entry = mDriverData->Dns6CacheList.ForwardLink;
2238     } else {
2239       Entry = Entry->ForwardLink;
2240     }
2241   }
2242 }
2243 
2244