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