1 /** @file
2 DnsDxe support functions implementation.
3 
4 Copyright (c) 2015, 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         Ip6Mode.IsConfigured) {
623 
624       Udp->Configure (Udp, NULL);
625       return (BOOLEAN) (Udp->Configure (Udp, UdpCfgData) == EFI_SUCCESS);
626     }
627   }
628 
629   return FALSE;
630 }
631 
632 /**
633   Configure the UDP.
634 
635   @param  Instance               The DNS session
636   @param  UdpIo                  The UDP_IO instance
637 
638   @retval EFI_SUCCESS            The UDP is successfully configured for the
639                                  session.
640 
641 **/
642 EFI_STATUS
Dns4ConfigUdp(IN DNS_INSTANCE * Instance,IN UDP_IO * UdpIo)643 Dns4ConfigUdp (
644   IN DNS_INSTANCE           *Instance,
645   IN UDP_IO                 *UdpIo
646   )
647 {
648   EFI_DNS4_CONFIG_DATA      *Config;
649   EFI_UDP4_CONFIG_DATA      UdpConfig;
650   EFI_STATUS                Status;
651 
652   Config = &Instance->Dns4CfgData;
653 
654   UdpConfig.AcceptBroadcast    = FALSE;
655   UdpConfig.AcceptPromiscuous  = FALSE;
656   UdpConfig.AcceptAnyPort      = FALSE;
657   UdpConfig.AllowDuplicatePort = FALSE;
658   UdpConfig.TypeOfService      = 0;
659   UdpConfig.TimeToLive         = 128;
660   UdpConfig.DoNotFragment      = FALSE;
661   UdpConfig.ReceiveTimeout     = 0;
662   UdpConfig.TransmitTimeout    = 0;
663   UdpConfig.UseDefaultAddress  = Config->UseDefaultSetting;
664   UdpConfig.SubnetMask         = Config->SubnetMask;
665   UdpConfig.StationPort        = Config->LocalPort;
666   UdpConfig.RemotePort         = DNS_SERVER_PORT;
667 
668   CopyMem (&UdpConfig.StationAddress, &Config->StationIp, sizeof (EFI_IPv4_ADDRESS));
669   CopyMem (&UdpConfig.RemoteAddress, &Instance->SessionDnsServer.v4, sizeof (EFI_IPv4_ADDRESS));
670 
671   Status = UdpIo->Protocol.Udp4->Configure (UdpIo->Protocol.Udp4, &UdpConfig);
672 
673   if ((Status == EFI_NO_MAPPING) && Dns4GetMapping (Instance, UdpIo, &UdpConfig)) {
674     return EFI_SUCCESS;
675   }
676 
677   return Status;
678 }
679 
680 /**
681   Configure the UDP.
682 
683   @param  Instance               The DNS session
684   @param  UdpIo                  The UDP_IO instance
685 
686   @retval EFI_SUCCESS            The UDP is successfully configured for the
687                                  session.
688 
689 **/
690 EFI_STATUS
Dns6ConfigUdp(IN DNS_INSTANCE * Instance,IN UDP_IO * UdpIo)691 Dns6ConfigUdp (
692   IN DNS_INSTANCE           *Instance,
693   IN UDP_IO                 *UdpIo
694   )
695 {
696   EFI_DNS6_CONFIG_DATA      *Config;
697   EFI_UDP6_CONFIG_DATA      UdpConfig;
698   EFI_STATUS                Status;
699 
700   Config = &Instance->Dns6CfgData;
701 
702   UdpConfig.AcceptPromiscuous  = FALSE;
703   UdpConfig.AcceptAnyPort      = FALSE;
704   UdpConfig.AllowDuplicatePort = FALSE;
705   UdpConfig.TrafficClass       = 0;
706   UdpConfig.HopLimit           = 128;
707   UdpConfig.ReceiveTimeout     = 0;
708   UdpConfig.TransmitTimeout    = 0;
709   UdpConfig.StationPort        = Config->LocalPort;
710   UdpConfig.RemotePort         = DNS_SERVER_PORT;
711   CopyMem (&UdpConfig.StationAddress, &Config->StationIp, sizeof (EFI_IPv6_ADDRESS));
712   CopyMem (&UdpConfig.RemoteAddress, &Instance->SessionDnsServer.v6, sizeof (EFI_IPv6_ADDRESS));
713 
714   Status = UdpIo->Protocol.Udp6->Configure (UdpIo->Protocol.Udp6, &UdpConfig);
715 
716   if ((Status == EFI_NO_MAPPING) && Dns6GetMapping (Instance, UdpIo, &UdpConfig)) {
717     return EFI_SUCCESS;
718   }
719 
720   return Status;
721 }
722 
723 /**
724   Update Dns4 cache to shared list of caches of all DNSv4 instances.
725 
726   @param  Dns4CacheList      All Dns4 cache list.
727   @param  DeleteFlag         If FALSE, this function is to add one entry to the DNS Cache.
728                              If TRUE, this function will delete matching DNS Cache entry.
729   @param  Override           If TRUE, the matching DNS cache entry will be overwritten with the supplied parameter.
730                              If FALSE, EFI_ACCESS_DENIED will be returned if the entry to be added is already exists.
731   @param  DnsCacheEntry      Entry Pointer to DNS Cache entry.
732 
733   @retval EFI_SUCCESS        Update Dns4 cache successfully.
734   @retval Others             Failed to update Dns4 cache.
735 
736 **/
737 EFI_STATUS
738 EFIAPI
UpdateDns4Cache(IN LIST_ENTRY * Dns4CacheList,IN BOOLEAN DeleteFlag,IN BOOLEAN Override,IN EFI_DNS4_CACHE_ENTRY DnsCacheEntry)739 UpdateDns4Cache (
740   IN LIST_ENTRY             *Dns4CacheList,
741   IN BOOLEAN                DeleteFlag,
742   IN BOOLEAN                Override,
743   IN EFI_DNS4_CACHE_ENTRY   DnsCacheEntry
744   )
745 {
746   DNS4_CACHE    *NewDnsCache;
747   DNS4_CACHE    *Item;
748   LIST_ENTRY    *Entry;
749   LIST_ENTRY    *Next;
750 
751   NewDnsCache = NULL;
752   Item        = NULL;
753 
754   //
755   // Search the database for the matching EFI_DNS_CACHE_ENTRY
756   //
757   NET_LIST_FOR_EACH_SAFE (Entry, Next, Dns4CacheList) {
758     Item = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink);
759     if (StrCmp (DnsCacheEntry.HostName, Item->DnsCache.HostName) == 0 && \
760         CompareMem (DnsCacheEntry.IpAddress, Item->DnsCache.IpAddress, sizeof (EFI_IPv4_ADDRESS)) == 0) {
761       //
762       // This is the Dns cache entry
763       //
764       if (DeleteFlag) {
765         //
766         // Delete matching DNS Cache entry
767         //
768         RemoveEntryList (&Item->AllCacheLink);
769 
770         return EFI_SUCCESS;
771       } else if (Override) {
772         //
773         // Update this one
774         //
775         Item->DnsCache.Timeout = DnsCacheEntry.Timeout;
776 
777         return EFI_SUCCESS;
778       }else {
779         return EFI_ACCESS_DENIED;
780       }
781     }
782   }
783 
784   //
785   // Add new one
786   //
787   NewDnsCache = AllocatePool (sizeof (DNS4_CACHE));
788   if (NewDnsCache == NULL) {
789     return EFI_OUT_OF_RESOURCES;
790   }
791 
792   InitializeListHead (&NewDnsCache->AllCacheLink);
793 
794   NewDnsCache->DnsCache.HostName = AllocatePool (StrSize (DnsCacheEntry.HostName));
795   if (NewDnsCache->DnsCache.HostName == NULL) {
796     return EFI_OUT_OF_RESOURCES;
797   }
798 
799   CopyMem (NewDnsCache->DnsCache.HostName, DnsCacheEntry.HostName, StrSize (DnsCacheEntry.HostName));
800 
801   NewDnsCache->DnsCache.IpAddress = AllocatePool (sizeof (EFI_IPv4_ADDRESS));
802   if (NewDnsCache->DnsCache.IpAddress == NULL) {
803     return EFI_OUT_OF_RESOURCES;
804   }
805 
806   CopyMem (NewDnsCache->DnsCache.IpAddress, DnsCacheEntry.IpAddress, sizeof (EFI_IPv4_ADDRESS));
807 
808   NewDnsCache->DnsCache.Timeout = DnsCacheEntry.Timeout;
809 
810   InsertTailList (Dns4CacheList, &NewDnsCache->AllCacheLink);
811 
812   return EFI_SUCCESS;
813 }
814 
815 /**
816   Update Dns6 cache to shared list of caches of all DNSv6 instances.
817 
818   @param  Dns6CacheList      All Dns6 cache list.
819   @param  DeleteFlag         If FALSE, this function is to add one entry to the DNS Cache.
820                              If TRUE, this function will delete matching DNS Cache entry.
821   @param  Override           If TRUE, the matching DNS cache entry will be overwritten with the supplied parameter.
822                              If FALSE, EFI_ACCESS_DENIED will be returned if the entry to be added is already exists.
823   @param  DnsCacheEntry      Entry Pointer to DNS Cache entry.
824 
825   @retval EFI_SUCCESS        Update Dns6 cache successfully.
826   @retval Others             Failed to update Dns6 cache.
827 **/
828 EFI_STATUS
829 EFIAPI
UpdateDns6Cache(IN LIST_ENTRY * Dns6CacheList,IN BOOLEAN DeleteFlag,IN BOOLEAN Override,IN EFI_DNS6_CACHE_ENTRY DnsCacheEntry)830 UpdateDns6Cache (
831   IN LIST_ENTRY             *Dns6CacheList,
832   IN BOOLEAN                DeleteFlag,
833   IN BOOLEAN                Override,
834   IN EFI_DNS6_CACHE_ENTRY   DnsCacheEntry
835   )
836 {
837   DNS6_CACHE    *NewDnsCache;
838   DNS6_CACHE    *Item;
839   LIST_ENTRY    *Entry;
840   LIST_ENTRY    *Next;
841 
842   NewDnsCache = NULL;
843   Item        = NULL;
844 
845   //
846   // Search the database for the matching EFI_DNS_CACHE_ENTRY
847   //
848   NET_LIST_FOR_EACH_SAFE (Entry, Next, Dns6CacheList) {
849     Item = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink);
850     if (StrCmp (DnsCacheEntry.HostName, Item->DnsCache.HostName) == 0 && \
851         CompareMem (DnsCacheEntry.IpAddress, Item->DnsCache.IpAddress, sizeof (EFI_IPv6_ADDRESS)) == 0) {
852       //
853       // This is the Dns cache entry
854       //
855       if (DeleteFlag) {
856         //
857         // Delete matching DNS Cache entry
858         //
859         RemoveEntryList (&Item->AllCacheLink);
860 
861         return EFI_SUCCESS;
862       } else if (Override) {
863         //
864         // Update this one
865         //
866         Item->DnsCache.Timeout = DnsCacheEntry.Timeout;
867 
868         return EFI_SUCCESS;
869       }else {
870         return EFI_ACCESS_DENIED;
871       }
872     }
873   }
874 
875   //
876   // Add new one
877   //
878   NewDnsCache = AllocatePool (sizeof (DNS6_CACHE));
879   if (NewDnsCache == NULL) {
880     return EFI_OUT_OF_RESOURCES;
881   }
882 
883   InitializeListHead (&NewDnsCache->AllCacheLink);
884 
885   NewDnsCache->DnsCache.HostName = AllocatePool (StrSize (DnsCacheEntry.HostName));
886   if (NewDnsCache->DnsCache.HostName == NULL) {
887     return EFI_OUT_OF_RESOURCES;
888   }
889 
890   CopyMem (NewDnsCache->DnsCache.HostName, DnsCacheEntry.HostName, StrSize (DnsCacheEntry.HostName));
891 
892   NewDnsCache->DnsCache.IpAddress = AllocatePool (sizeof (EFI_IPv6_ADDRESS));
893   if (NewDnsCache->DnsCache.IpAddress == NULL) {
894     return EFI_OUT_OF_RESOURCES;
895   }
896 
897   CopyMem (NewDnsCache->DnsCache.IpAddress, DnsCacheEntry.IpAddress, sizeof (EFI_IPv6_ADDRESS));
898 
899   NewDnsCache->DnsCache.Timeout = DnsCacheEntry.Timeout;
900 
901   InsertTailList (Dns6CacheList, &NewDnsCache->AllCacheLink);
902 
903   return EFI_SUCCESS;
904 }
905 
906 /**
907   Add Dns4 ServerIp to common list of addresses of all configured DNSv4 server.
908 
909   @param  Dns4ServerList    Common list of addresses of all configured DNSv4 server.
910   @param  ServerIp          DNS server Ip.
911 
912   @retval EFI_SUCCESS       Add Dns4 ServerIp to common list successfully.
913   @retval Others            Failed to add Dns4 ServerIp to common list.
914 
915 **/
916 EFI_STATUS
917 EFIAPI
AddDns4ServerIp(IN LIST_ENTRY * Dns4ServerList,IN EFI_IPv4_ADDRESS ServerIp)918 AddDns4ServerIp (
919   IN LIST_ENTRY                *Dns4ServerList,
920   IN EFI_IPv4_ADDRESS           ServerIp
921   )
922 {
923   DNS4_SERVER_IP    *NewServerIp;
924   DNS4_SERVER_IP    *Item;
925   LIST_ENTRY        *Entry;
926   LIST_ENTRY        *Next;
927 
928   NewServerIp = NULL;
929   Item        = NULL;
930 
931   //
932   // Search the database for the matching ServerIp
933   //
934   NET_LIST_FOR_EACH_SAFE (Entry, Next, Dns4ServerList) {
935     Item = NET_LIST_USER_STRUCT (Entry, DNS4_SERVER_IP, AllServerLink);
936     if (CompareMem (&Item->Dns4ServerIp, &ServerIp, sizeof (EFI_IPv4_ADDRESS)) == 0) {
937       //
938       // Already done.
939       //
940       return EFI_SUCCESS;
941     }
942   }
943 
944   //
945   // Add new one
946   //
947   NewServerIp = AllocatePool (sizeof (DNS4_SERVER_IP));
948   if (NewServerIp == NULL) {
949     return EFI_OUT_OF_RESOURCES;
950   }
951 
952   InitializeListHead (&NewServerIp->AllServerLink);
953 
954   CopyMem (&NewServerIp->Dns4ServerIp, &ServerIp, sizeof (EFI_IPv4_ADDRESS));
955 
956   InsertTailList (Dns4ServerList, &NewServerIp->AllServerLink);
957 
958   return EFI_SUCCESS;
959 }
960 
961 /**
962   Add Dns6 ServerIp to common list of addresses of all configured DNSv6 server.
963 
964   @param  Dns6ServerList    Common list of addresses of all configured DNSv6 server.
965   @param  ServerIp          DNS server Ip.
966 
967   @retval EFI_SUCCESS       Add Dns6 ServerIp to common list successfully.
968   @retval Others            Failed to add Dns6 ServerIp to common list.
969 
970 **/
971 EFI_STATUS
972 EFIAPI
AddDns6ServerIp(IN LIST_ENTRY * Dns6ServerList,IN EFI_IPv6_ADDRESS ServerIp)973 AddDns6ServerIp (
974   IN LIST_ENTRY                *Dns6ServerList,
975   IN EFI_IPv6_ADDRESS           ServerIp
976   )
977 {
978   DNS6_SERVER_IP    *NewServerIp;
979   DNS6_SERVER_IP    *Item;
980   LIST_ENTRY        *Entry;
981   LIST_ENTRY        *Next;
982 
983   NewServerIp = NULL;
984   Item        = NULL;
985 
986   //
987   // Search the database for the matching ServerIp
988   //
989   NET_LIST_FOR_EACH_SAFE (Entry, Next, Dns6ServerList) {
990     Item = NET_LIST_USER_STRUCT (Entry, DNS6_SERVER_IP, AllServerLink);
991     if (CompareMem (&Item->Dns6ServerIp, &ServerIp, sizeof (EFI_IPv6_ADDRESS)) == 0) {
992       //
993       // Already done.
994       //
995       return EFI_SUCCESS;
996     }
997   }
998 
999   //
1000   // Add new one
1001   //
1002   NewServerIp = AllocatePool (sizeof (DNS6_SERVER_IP));
1003   if (NewServerIp == NULL) {
1004     return EFI_OUT_OF_RESOURCES;
1005   }
1006 
1007   InitializeListHead (&NewServerIp->AllServerLink);
1008 
1009   CopyMem (&NewServerIp->Dns6ServerIp, &ServerIp, sizeof (EFI_IPv6_ADDRESS));
1010 
1011   InsertTailList (Dns6ServerList, &NewServerIp->AllServerLink);
1012 
1013   return EFI_SUCCESS;
1014 }
1015 
1016 /**
1017   Fill QName for IP querying. QName is a domain name represented as
1018   a sequence of labels, where each label consists of a length octet
1019   followed by that number of octets. The domain name terminates with
1020   the zero length octet for the null label of the root. Caller should
1021   take responsibility to the buffer in QName.
1022 
1023   @param  HostName          Queried HostName
1024 
1025   @retval NULL      Failed to fill QName.
1026   @return           QName filled successfully.
1027 
1028 **/
1029 CHAR8 *
1030 EFIAPI
DnsFillinQNameForQueryIp(IN CHAR16 * HostName)1031 DnsFillinQNameForQueryIp (
1032   IN  CHAR16              *HostName
1033   )
1034 {
1035   CHAR8                 *QueryName;
1036   CHAR8                 *Header;
1037   CHAR8                 *Tail;
1038   UINTN                 Len;
1039   UINTN                 Index;
1040 
1041   QueryName  = NULL;
1042   Header     = NULL;
1043   Tail       = NULL;
1044 
1045   QueryName = AllocateZeroPool (DNS_DEFAULT_BLKSIZE);
1046   if (QueryName == NULL) {
1047     return NULL;
1048   }
1049 
1050   Header = QueryName;
1051   Tail = Header + 1;
1052   Len = 0;
1053   for (Index = 0; HostName[Index] != 0; Index++) {
1054     *Tail = (CHAR8) HostName[Index];
1055     if (*Tail == '.') {
1056       *Header = (CHAR8) Len;
1057       Header = Tail;
1058       Tail ++;
1059       Len = 0;
1060     } else {
1061       Tail++;
1062       Len++;
1063     }
1064   }
1065   *Header = (CHAR8) Len;
1066   *Tail = 0;
1067 
1068   return QueryName;
1069 }
1070 
1071 /**
1072   Find out whether the response is valid or invalid.
1073 
1074   @param  TokensMap       All DNS transmittal Tokens entry.
1075   @param  Identification  Identification for queried packet.
1076   @param  Type            Type for queried packet.
1077   @param  Item            Return corresponding Token entry.
1078 
1079   @retval TRUE            The response is valid.
1080   @retval FALSE           The response is invalid.
1081 
1082 **/
1083 BOOLEAN
IsValidDnsResponse(IN NET_MAP * TokensMap,IN UINT16 Identification,IN UINT16 Type,OUT NET_MAP_ITEM ** Item)1084 IsValidDnsResponse (
1085   IN     NET_MAP      *TokensMap,
1086   IN     UINT16       Identification,
1087   IN     UINT16       Type,
1088      OUT NET_MAP_ITEM **Item
1089   )
1090 {
1091   LIST_ENTRY              *Entry;
1092 
1093   NET_BUF                 *Packet;
1094   UINT8                   *TxString;
1095   DNS_HEADER              *DnsHeader;
1096   CHAR8                   *QueryName;
1097   DNS_QUERY_SECTION       *QuerySection;
1098 
1099   NET_LIST_FOR_EACH (Entry, &TokensMap->Used) {
1100     *Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
1101     Packet = (NET_BUF *) ((*Item)->Value);
1102     if (Packet == NULL){
1103 
1104       continue;
1105     } else {
1106       TxString = NetbufGetByte (Packet, 0, NULL);
1107       ASSERT (TxString != NULL);
1108       DnsHeader = (DNS_HEADER *) TxString;
1109       QueryName = (CHAR8 *) (TxString + sizeof (*DnsHeader));
1110       QuerySection = (DNS_QUERY_SECTION *) (QueryName + AsciiStrLen (QueryName) + 1);
1111 
1112       DnsHeader->Identification = NTOHS (DnsHeader->Identification);
1113       QuerySection->Type = NTOHS (QuerySection->Type);
1114 
1115       if (DnsHeader->Identification == Identification && QuerySection->Type == Type) {
1116         return TRUE;
1117       }
1118     }
1119   }
1120 
1121   *Item =NULL;
1122 
1123   return FALSE;
1124 }
1125 
1126 /**
1127   Parse Dns Response.
1128 
1129   @param  Instance              The DNS instance
1130   @param  RxString              Received buffer.
1131   @param  Completed             Flag to indicate that Dns response is valid.
1132 
1133   @retval EFI_SUCCESS           Parse Dns Response successfully.
1134   @retval Others                Failed to parse Dns Response.
1135 
1136 **/
1137 EFI_STATUS
ParseDnsResponse(IN OUT DNS_INSTANCE * Instance,IN UINT8 * RxString,OUT BOOLEAN * Completed)1138 ParseDnsResponse (
1139   IN OUT DNS_INSTANCE              *Instance,
1140   IN     UINT8                     *RxString,
1141      OUT BOOLEAN                   *Completed
1142   )
1143 {
1144   DNS_HEADER            *DnsHeader;
1145 
1146   CHAR8                 *QueryName;
1147   DNS_QUERY_SECTION     *QuerySection;
1148 
1149   CHAR8                 *AnswerName;
1150   DNS_ANSWER_SECTION    *AnswerSection;
1151   UINT8                 *AnswerData;
1152 
1153   NET_MAP_ITEM          *Item;
1154   DNS4_TOKEN_ENTRY      *Dns4TokenEntry;
1155   DNS6_TOKEN_ENTRY      *Dns6TokenEntry;
1156 
1157   UINT32                IpCount;
1158   UINT32                RRCount;
1159   UINT32                AnswerSectionNum;
1160 
1161   EFI_IPv4_ADDRESS      *HostAddr4;
1162   EFI_IPv6_ADDRESS      *HostAddr6;
1163 
1164   EFI_DNS4_CACHE_ENTRY  *Dns4CacheEntry;
1165   EFI_DNS6_CACHE_ENTRY  *Dns6CacheEntry;
1166 
1167   DNS_RESOURCE_RECORD   *Dns4RR;
1168   DNS6_RESOURCE_RECORD  *Dns6RR;
1169 
1170   EFI_STATUS            Status;
1171 
1172   EFI_TPL               OldTpl;
1173 
1174   Item             = NULL;
1175   Dns4TokenEntry   = NULL;
1176   Dns6TokenEntry   = NULL;
1177 
1178   IpCount          = 0;
1179   RRCount          = 0;
1180   AnswerSectionNum = 0;
1181 
1182   HostAddr4        = NULL;
1183   HostAddr6        = NULL;
1184 
1185   Dns4CacheEntry   = NULL;
1186   Dns6CacheEntry   = NULL;
1187 
1188   Dns4RR           = NULL;
1189   Dns6RR           = NULL;
1190 
1191   *Completed       = TRUE;
1192   Status           = EFI_SUCCESS;
1193 
1194   //
1195   // Get header
1196   //
1197   DnsHeader = (DNS_HEADER *) RxString;
1198 
1199   DnsHeader->Identification = NTOHS (DnsHeader->Identification);
1200   DnsHeader->Flags.Uint16 = NTOHS (DnsHeader->Flags.Uint16);
1201   DnsHeader->QuestionsNum = NTOHS (DnsHeader->QuestionsNum);
1202   DnsHeader->AnswersNum = NTOHS (DnsHeader->AnswersNum);
1203   DnsHeader->AuthorityNum = NTOHS (DnsHeader->AuthorityNum);
1204   DnsHeader->AditionalNum = NTOHS (DnsHeader->AditionalNum);
1205 
1206   //
1207   // Get Query name
1208   //
1209   QueryName = (CHAR8 *) (RxString + sizeof (*DnsHeader));
1210 
1211   //
1212   // Get query section
1213   //
1214   QuerySection = (DNS_QUERY_SECTION *) (QueryName + AsciiStrLen (QueryName) + 1);
1215   QuerySection->Type = NTOHS (QuerySection->Type);
1216   QuerySection->Class = NTOHS (QuerySection->Class);
1217 
1218   //
1219   // Get Answer name
1220   //
1221   AnswerName = (CHAR8 *) QuerySection + sizeof (*QuerySection);
1222 
1223   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
1224 
1225   //
1226   // Check DnsResponse Validity, if so, also get a valid NET_MAP_ITEM.
1227   //
1228   if (Instance->Service->IpVersion == IP_VERSION_4) {
1229     if (!IsValidDnsResponse (&Instance->Dns4TxTokens, DnsHeader->Identification, QuerySection->Type, &Item)) {
1230       *Completed = FALSE;
1231       Status = EFI_ABORTED;
1232       goto ON_EXIT;
1233     }
1234     ASSERT (Item != NULL);
1235     Dns4TokenEntry = (DNS4_TOKEN_ENTRY *) (Item->Key);
1236   } else {
1237     if (!IsValidDnsResponse (&Instance->Dns6TxTokens, DnsHeader->Identification, QuerySection->Type, &Item)) {
1238       *Completed = FALSE;
1239       Status = EFI_ABORTED;
1240       goto ON_EXIT;
1241     }
1242     ASSERT (Item != NULL);
1243     Dns6TokenEntry = (DNS6_TOKEN_ENTRY *) (Item->Key);
1244   }
1245 
1246   //
1247   // Continue Check Some Errors.
1248   //
1249   if (DnsHeader->Flags.Bits.RCode != DNS_FLAGS_RCODE_NO_ERROR || DnsHeader->AnswersNum < 1 || \
1250       DnsHeader->Flags.Bits.QR != DNS_FLAGS_QR_RESPONSE || QuerySection->Class != DNS_CLASS_INET) {
1251       Status = EFI_ABORTED;
1252       goto ON_EXIT;
1253   }
1254 
1255   //
1256   // Free the sending packet.
1257   //
1258   if (Item->Value != NULL) {
1259     NetbufFree ((NET_BUF *) (Item->Value));
1260   }
1261 
1262   //
1263   // Do some buffer allocations.
1264   //
1265   if (Instance->Service->IpVersion == IP_VERSION_4) {
1266     ASSERT (Dns4TokenEntry != NULL);
1267 
1268     if (Dns4TokenEntry->GeneralLookUp) {
1269       //
1270       // It's the GeneralLookUp querying.
1271       //
1272       Dns4TokenEntry->Token->RspData.GLookupData = AllocatePool (sizeof (DNS_RESOURCE_RECORD));
1273       if (Dns4TokenEntry->Token->RspData.GLookupData == NULL) {
1274         Status = EFI_OUT_OF_RESOURCES;
1275         goto ON_EXIT;
1276       }
1277       Dns4TokenEntry->Token->RspData.GLookupData->RRList = AllocatePool (DnsHeader->AnswersNum * sizeof (DNS_RESOURCE_RECORD));
1278       if (Dns4TokenEntry->Token->RspData.GLookupData->RRList == NULL) {
1279         Status = EFI_OUT_OF_RESOURCES;
1280         goto ON_EXIT;
1281       }
1282     } else {
1283       //
1284       // It's not the GeneralLookUp querying. Check the Query type.
1285       //
1286       if (QuerySection->Type == DNS_TYPE_A) {
1287         Dns4TokenEntry->Token->RspData.H2AData = AllocatePool (sizeof (DNS_HOST_TO_ADDR_DATA));
1288         if (Dns4TokenEntry->Token->RspData.H2AData == NULL) {
1289           Status = EFI_OUT_OF_RESOURCES;
1290           goto ON_EXIT;
1291         }
1292         Dns4TokenEntry->Token->RspData.H2AData->IpList = AllocatePool (DnsHeader->AnswersNum * sizeof (EFI_IPv4_ADDRESS));
1293         if (Dns4TokenEntry->Token->RspData.H2AData->IpList == NULL) {
1294           Status = EFI_OUT_OF_RESOURCES;
1295           goto ON_EXIT;
1296         }
1297       } else {
1298         Status = EFI_UNSUPPORTED;
1299         goto ON_EXIT;
1300       }
1301     }
1302   } else {
1303     ASSERT (Dns6TokenEntry != NULL);
1304 
1305     if (Dns6TokenEntry->GeneralLookUp) {
1306       //
1307       // It's the GeneralLookUp querying.
1308       //
1309       Dns6TokenEntry->Token->RspData.GLookupData = AllocatePool (sizeof (DNS_RESOURCE_RECORD));
1310       if (Dns6TokenEntry->Token->RspData.GLookupData == NULL) {
1311         Status = EFI_UNSUPPORTED;
1312         goto ON_EXIT;
1313       }
1314       Dns6TokenEntry->Token->RspData.GLookupData->RRList = AllocatePool (DnsHeader->AnswersNum * sizeof (DNS_RESOURCE_RECORD));
1315       if (Dns6TokenEntry->Token->RspData.GLookupData->RRList == NULL) {
1316         Status = EFI_UNSUPPORTED;
1317         goto ON_EXIT;
1318       }
1319     } else {
1320       //
1321       // It's not the GeneralLookUp querying. Check the Query type.
1322       //
1323       if (QuerySection->Type == DNS_TYPE_AAAA) {
1324         Dns6TokenEntry->Token->RspData.H2AData = AllocatePool (sizeof (DNS6_HOST_TO_ADDR_DATA));
1325         if (Dns6TokenEntry->Token->RspData.H2AData == NULL) {
1326           Status = EFI_UNSUPPORTED;
1327           goto ON_EXIT;
1328         }
1329         Dns6TokenEntry->Token->RspData.H2AData->IpList = AllocatePool (DnsHeader->AnswersNum * sizeof (EFI_IPv6_ADDRESS));
1330         if (Dns6TokenEntry->Token->RspData.H2AData->IpList == NULL) {
1331           Status = EFI_UNSUPPORTED;
1332           goto ON_EXIT;
1333         }
1334       } else {
1335         Status = EFI_UNSUPPORTED;
1336         goto ON_EXIT;
1337       }
1338     }
1339   }
1340 
1341   //
1342   // Processing AnswerSection.
1343   //
1344   while (AnswerSectionNum < DnsHeader->AnswersNum) {
1345     //
1346     // Answer name should be PTR.
1347     //
1348     ASSERT ((*(UINT8 *) AnswerName & 0xC0) == 0xC0);
1349 
1350     //
1351     // Get Answer section.
1352     //
1353     AnswerSection = (DNS_ANSWER_SECTION *) (AnswerName + sizeof (UINT16));
1354     AnswerSection->Type = NTOHS (AnswerSection->Type);
1355     AnswerSection->Class = NTOHS (AnswerSection->Class);
1356     AnswerSection->Ttl = NTOHL (AnswerSection->Ttl);
1357     AnswerSection->DataLength = NTOHS (AnswerSection->DataLength);
1358 
1359     //
1360     // Check whether it's the GeneralLookUp querying.
1361     //
1362     if (Instance->Service->IpVersion == IP_VERSION_4 && Dns4TokenEntry->GeneralLookUp) {
1363       Dns4RR = Dns4TokenEntry->Token->RspData.GLookupData->RRList;
1364       AnswerData = (UINT8 *) AnswerSection + sizeof (*AnswerSection);
1365 
1366       //
1367       // Fill the ResourceRecord.
1368       //
1369       Dns4RR[RRCount].QName = AllocateZeroPool (AsciiStrLen (QueryName) + 1);
1370       if (Dns4RR[RRCount].QName == NULL) {
1371         Status = EFI_UNSUPPORTED;
1372         goto ON_EXIT;
1373       }
1374       CopyMem (Dns4RR[RRCount].QName, QueryName, AsciiStrLen (QueryName));
1375       Dns4RR[RRCount].QType = AnswerSection->Type;
1376       Dns4RR[RRCount].QClass = AnswerSection->Class;
1377       Dns4RR[RRCount].TTL = AnswerSection->Ttl;
1378       Dns4RR[RRCount].DataLength = AnswerSection->DataLength;
1379       Dns4RR[RRCount].RData = AllocateZeroPool (Dns4RR[RRCount].DataLength);
1380       if (Dns4RR[RRCount].RData == NULL) {
1381         Status = EFI_UNSUPPORTED;
1382         goto ON_EXIT;
1383       }
1384       CopyMem (Dns4RR[RRCount].RData, AnswerData, Dns4RR[RRCount].DataLength);
1385 
1386       RRCount ++;
1387     } else if (Instance->Service->IpVersion == IP_VERSION_6 && Dns6TokenEntry->GeneralLookUp) {
1388       Dns6RR = Dns6TokenEntry->Token->RspData.GLookupData->RRList;
1389       AnswerData = (UINT8 *) AnswerSection + sizeof (*AnswerSection);
1390 
1391       //
1392       // Fill the ResourceRecord.
1393       //
1394       Dns6RR[RRCount].QName = AllocateZeroPool (AsciiStrLen (QueryName) + 1);
1395       if (Dns6RR[RRCount].QName == NULL) {
1396         Status = EFI_UNSUPPORTED;
1397         goto ON_EXIT;
1398       }
1399       CopyMem (Dns6RR[RRCount].QName, QueryName, AsciiStrLen (QueryName));
1400       Dns6RR[RRCount].QType = AnswerSection->Type;
1401       Dns6RR[RRCount].QClass = AnswerSection->Class;
1402       Dns6RR[RRCount].TTL = AnswerSection->Ttl;
1403       Dns6RR[RRCount].DataLength = AnswerSection->DataLength;
1404       Dns6RR[RRCount].RData = AllocateZeroPool (Dns6RR[RRCount].DataLength);
1405       if (Dns6RR[RRCount].RData == NULL) {
1406         Status = EFI_UNSUPPORTED;
1407         goto ON_EXIT;
1408       }
1409       CopyMem (Dns6RR[RRCount].RData, AnswerData, Dns6RR[RRCount].DataLength);
1410 
1411       RRCount ++;
1412     } else {
1413       //
1414       // It's not the GeneralLookUp querying.
1415       // Check the Query type, parse the response packet.
1416       //
1417       switch (AnswerSection->Type) {
1418       case DNS_TYPE_A:
1419         //
1420         // This is address entry, get Data.
1421         //
1422         ASSERT (Dns4TokenEntry != NULL && AnswerSection->DataLength == 4);
1423 
1424         HostAddr4 = Dns4TokenEntry->Token->RspData.H2AData->IpList;
1425         AnswerData = (UINT8 *) AnswerSection + sizeof (*AnswerSection);
1426         CopyMem (&HostAddr4[IpCount], AnswerData, sizeof (EFI_IPv4_ADDRESS));
1427 
1428         //
1429         // Update DNS cache dynamically.
1430         //
1431         if (Dns4CacheEntry != NULL) {
1432           if (Dns4CacheEntry->HostName != NULL) {
1433             FreePool (Dns4CacheEntry->HostName);
1434           }
1435 
1436           if (Dns4CacheEntry->IpAddress != NULL) {
1437             FreePool (Dns4CacheEntry->IpAddress);
1438           }
1439 
1440           FreePool (Dns4CacheEntry);
1441         }
1442 
1443         //
1444         // Allocate new CacheEntry pool.
1445         //
1446         Dns4CacheEntry = AllocateZeroPool (sizeof (EFI_DNS4_CACHE_ENTRY));
1447         if (Dns4CacheEntry == NULL) {
1448           Status = EFI_UNSUPPORTED;
1449           goto ON_EXIT;
1450         }
1451         Dns4CacheEntry->HostName = AllocateZeroPool (2 * (StrLen(Dns4TokenEntry->QueryHostName) + 1));
1452         if (Dns4CacheEntry->HostName == NULL) {
1453           Status = EFI_UNSUPPORTED;
1454           goto ON_EXIT;
1455         }
1456         CopyMem (Dns4CacheEntry->HostName, Dns4TokenEntry->QueryHostName, 2 * (StrLen(Dns4TokenEntry->QueryHostName) + 1));
1457         Dns4CacheEntry->IpAddress = AllocateZeroPool (sizeof (EFI_IPv4_ADDRESS));
1458         if (Dns4CacheEntry->IpAddress == NULL) {
1459           Status = EFI_UNSUPPORTED;
1460           goto ON_EXIT;
1461         }
1462         CopyMem (Dns4CacheEntry->IpAddress, AnswerData, sizeof (EFI_IPv4_ADDRESS));
1463         Dns4CacheEntry->Timeout = AnswerSection->Ttl;
1464 
1465         UpdateDns4Cache (&mDriverData->Dns4CacheList, FALSE, TRUE, *Dns4CacheEntry);
1466 
1467         IpCount ++;
1468         break;
1469       case DNS_TYPE_AAAA:
1470         //
1471         // This is address entry, get Data.
1472         //
1473         ASSERT (Dns6TokenEntry != NULL && AnswerSection->DataLength == 16);
1474 
1475         HostAddr6 = Dns6TokenEntry->Token->RspData.H2AData->IpList;
1476         AnswerData = (UINT8 *) AnswerSection + sizeof (*AnswerSection);
1477         CopyMem (&HostAddr6[IpCount], AnswerData, sizeof (EFI_IPv6_ADDRESS));
1478 
1479         //
1480         // Update DNS cache dynamically.
1481         //
1482         if (Dns6CacheEntry != NULL) {
1483           if (Dns6CacheEntry->HostName != NULL) {
1484             FreePool (Dns6CacheEntry->HostName);
1485           }
1486 
1487           if (Dns6CacheEntry->IpAddress != NULL) {
1488             FreePool (Dns6CacheEntry->IpAddress);
1489           }
1490 
1491           FreePool (Dns6CacheEntry);
1492         }
1493 
1494         //
1495         // Allocate new CacheEntry pool.
1496         //
1497         Dns6CacheEntry = AllocateZeroPool (sizeof (EFI_DNS6_CACHE_ENTRY));
1498         if (Dns6CacheEntry == NULL) {
1499           Status = EFI_UNSUPPORTED;
1500           goto ON_EXIT;
1501         }
1502         Dns6CacheEntry->HostName = AllocateZeroPool (2 * (StrLen(Dns6TokenEntry->QueryHostName) + 1));
1503         if (Dns6CacheEntry->HostName == NULL) {
1504           Status = EFI_UNSUPPORTED;
1505           goto ON_EXIT;
1506         }
1507         CopyMem (Dns6CacheEntry->HostName, Dns6TokenEntry->QueryHostName, 2 * (StrLen(Dns6TokenEntry->QueryHostName) + 1));
1508         Dns6CacheEntry->IpAddress = AllocateZeroPool (sizeof (EFI_IPv6_ADDRESS));
1509         if (Dns6CacheEntry->IpAddress == NULL) {
1510           Status = EFI_UNSUPPORTED;
1511           goto ON_EXIT;
1512         }
1513         CopyMem (Dns6CacheEntry->IpAddress, AnswerData, sizeof (EFI_IPv6_ADDRESS));
1514         Dns6CacheEntry->Timeout = AnswerSection->Ttl;
1515 
1516         UpdateDns6Cache (&mDriverData->Dns6CacheList, FALSE, TRUE, *Dns6CacheEntry);
1517 
1518         IpCount ++;
1519         break;
1520       default:
1521         Status = EFI_UNSUPPORTED;
1522         goto ON_EXIT;
1523       }
1524     }
1525 
1526     //
1527     // Find next one
1528     //
1529     AnswerName = (CHAR8 *) AnswerSection + sizeof (*AnswerSection) + AnswerSection->DataLength;
1530     AnswerSectionNum ++;
1531   }
1532 
1533   if (Instance->Service->IpVersion == IP_VERSION_4) {
1534     ASSERT (Dns4TokenEntry != NULL);
1535 
1536     if (Dns4TokenEntry->GeneralLookUp) {
1537       Dns4TokenEntry->Token->RspData.GLookupData->RRCount = RRCount;
1538     } else {
1539       if (QuerySection->Type == DNS_TYPE_A) {
1540         Dns4TokenEntry->Token->RspData.H2AData->IpCount = IpCount;
1541       } else {
1542         Status = EFI_UNSUPPORTED;
1543         goto ON_EXIT;
1544       }
1545     }
1546   } else {
1547     ASSERT (Dns6TokenEntry != NULL);
1548 
1549     if (Dns6TokenEntry->GeneralLookUp) {
1550       Dns6TokenEntry->Token->RspData.GLookupData->RRCount = RRCount;
1551     } else {
1552       if (QuerySection->Type == DNS_TYPE_AAAA) {
1553         Dns6TokenEntry->Token->RspData.H2AData->IpCount = IpCount;
1554       } else {
1555         Status = EFI_UNSUPPORTED;
1556         goto ON_EXIT;
1557       }
1558     }
1559   }
1560 
1561   //
1562   // Parsing is complete, SignalEvent here.
1563   //
1564   if (Instance->Service->IpVersion == IP_VERSION_4) {
1565     ASSERT (Dns4TokenEntry != NULL);
1566     Dns4RemoveTokenEntry (&Instance->Dns4TxTokens, Dns4TokenEntry);
1567     Dns4TokenEntry->Token->Status = EFI_SUCCESS;
1568     if (Dns4TokenEntry->Token->Event != NULL) {
1569       gBS->SignalEvent (Dns4TokenEntry->Token->Event);
1570       DispatchDpc ();
1571     }
1572   } else {
1573     ASSERT (Dns6TokenEntry != NULL);
1574     Dns6RemoveTokenEntry (&Instance->Dns6TxTokens, Dns6TokenEntry);
1575     Dns6TokenEntry->Token->Status = EFI_SUCCESS;
1576     if (Dns6TokenEntry->Token->Event != NULL) {
1577       gBS->SignalEvent (Dns6TokenEntry->Token->Event);
1578       DispatchDpc ();
1579     }
1580   }
1581 
1582   //
1583   // Free allocated CacheEntry pool.
1584   //
1585   if (Dns4CacheEntry != NULL) {
1586     if (Dns4CacheEntry->HostName != NULL) {
1587       FreePool (Dns4CacheEntry->HostName);
1588     }
1589 
1590     if (Dns4CacheEntry->IpAddress != NULL) {
1591       FreePool (Dns4CacheEntry->IpAddress);
1592     }
1593 
1594     FreePool (Dns4CacheEntry);
1595   }
1596 
1597   if (Dns6CacheEntry != NULL) {
1598     if (Dns6CacheEntry->HostName != NULL) {
1599       FreePool (Dns6CacheEntry->HostName);
1600     }
1601 
1602     if (Dns6CacheEntry->IpAddress != NULL) {
1603       FreePool (Dns6CacheEntry->IpAddress);
1604     }
1605 
1606     FreePool (Dns6CacheEntry);
1607   }
1608 
1609 ON_EXIT:
1610   gBS->RestoreTPL (OldTpl);
1611   return Status;
1612 }
1613 
1614 /**
1615   Parse response packet.
1616 
1617   @param  Packet                The packets received.
1618   @param  EndPoint              The local/remote UDP access point
1619   @param  IoStatus              The status of the UDP receive
1620   @param  Context               The opaque parameter to the function.
1621 
1622 **/
1623 VOID
1624 EFIAPI
DnsOnPacketReceived(NET_BUF * Packet,UDP_END_POINT * EndPoint,EFI_STATUS IoStatus,VOID * Context)1625 DnsOnPacketReceived (
1626   NET_BUF                   *Packet,
1627   UDP_END_POINT             *EndPoint,
1628   EFI_STATUS                IoStatus,
1629   VOID                      *Context
1630   )
1631 {
1632   DNS_INSTANCE              *Instance;
1633 
1634   UINT8                     *RcvString;
1635 
1636   BOOLEAN                   Completed;
1637 
1638   Instance  = (DNS_INSTANCE *) Context;
1639   NET_CHECK_SIGNATURE (Instance, DNS_INSTANCE_SIGNATURE);
1640 
1641   RcvString = NULL;
1642   Completed = FALSE;
1643 
1644   if (EFI_ERROR (IoStatus)) {
1645     goto ON_EXIT;
1646   }
1647 
1648   ASSERT (Packet != NULL);
1649 
1650   RcvString = NetbufGetByte (Packet, 0, NULL);
1651   ASSERT (RcvString != NULL);
1652 
1653   //
1654   // Parse Dns Response
1655   //
1656   ParseDnsResponse (Instance, RcvString, &Completed);
1657 
1658   ON_EXIT:
1659 
1660     if (Packet != NULL) {
1661       NetbufFree (Packet);
1662     }
1663 
1664     if (!Completed) {
1665       UdpIoRecvDatagram (Instance->UdpIo, DnsOnPacketReceived, Instance, 0);
1666     }
1667 }
1668 
1669 /**
1670   Release the net buffer when packet is sent.
1671 
1672   @param  Packet                The packets received.
1673   @param  EndPoint              The local/remote UDP access point
1674   @param  IoStatus              The status of the UDP receive
1675   @param  Context               The opaque parameter to the function.
1676 
1677 **/
1678 VOID
1679 EFIAPI
DnsOnPacketSent(NET_BUF * Packet,UDP_END_POINT * EndPoint,EFI_STATUS IoStatus,VOID * Context)1680 DnsOnPacketSent (
1681   NET_BUF                   *Packet,
1682   UDP_END_POINT             *EndPoint,
1683   EFI_STATUS                IoStatus,
1684   VOID                      *Context
1685   )
1686 {
1687   DNS_INSTANCE              *Instance;
1688   LIST_ENTRY                *Entry;
1689   NET_MAP_ITEM              *Item;
1690   DNS4_TOKEN_ENTRY          *Dns4TokenEntry;
1691   DNS6_TOKEN_ENTRY          *Dns6TokenEntry;
1692 
1693   Dns4TokenEntry = NULL;
1694   Dns6TokenEntry = NULL;
1695 
1696   Instance  = (DNS_INSTANCE *) Context;
1697   NET_CHECK_SIGNATURE (Instance, DNS_INSTANCE_SIGNATURE);
1698 
1699   if (Instance->Service->IpVersion == IP_VERSION_4) {
1700     NET_LIST_FOR_EACH (Entry, &Instance->Dns4TxTokens.Used) {
1701       Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
1702       if (Packet == (NET_BUF *)(Item->Value)) {
1703         Dns4TokenEntry = ((DNS4_TOKEN_ENTRY *)Item->Key);
1704         Dns4TokenEntry->PacketToLive = Dns4TokenEntry->Token->RetryInterval;
1705         break;
1706       }
1707     }
1708   } else {
1709     NET_LIST_FOR_EACH (Entry, &Instance->Dns6TxTokens.Used) {
1710       Item = NET_LIST_USER_STRUCT (Entry, NET_MAP_ITEM, Link);
1711       if (Packet == (NET_BUF *)(Item->Value)) {
1712         Dns6TokenEntry = ((DNS6_TOKEN_ENTRY *)Item->Key);
1713         Dns6TokenEntry->PacketToLive = Dns6TokenEntry->Token->RetryInterval;
1714         break;
1715       }
1716     }
1717   }
1718 
1719   NetbufFree (Packet);
1720 }
1721 
1722 /**
1723   Query request information.
1724 
1725   @param  Instance              The DNS instance
1726   @param  Packet                The packet for querying request information.
1727 
1728   @retval EFI_SUCCESS           Query request information successfully.
1729   @retval Others                Failed to query request information.
1730 
1731 **/
1732 EFI_STATUS
DoDnsQuery(IN DNS_INSTANCE * Instance,IN NET_BUF * Packet)1733 DoDnsQuery (
1734   IN  DNS_INSTANCE              *Instance,
1735   IN  NET_BUF                   *Packet
1736   )
1737 {
1738   EFI_STATUS      Status;
1739 
1740   //
1741   // Ready to receive the DNS response.
1742   //
1743   if (Instance->UdpIo->RecvRequest == NULL) {
1744     Status = UdpIoRecvDatagram (Instance->UdpIo, DnsOnPacketReceived, Instance, 0);
1745     if (EFI_ERROR (Status)) {
1746       return Status;
1747     }
1748   }
1749 
1750   //
1751   // Transmit the DNS packet.
1752   //
1753   NET_GET_REF (Packet);
1754 
1755   Status = UdpIoSendDatagram (Instance->UdpIo, Packet, NULL, NULL, DnsOnPacketSent, Instance);
1756 
1757   return Status;
1758 }
1759 
1760 /**
1761   Construct the Packet according query section.
1762 
1763   @param  Instance              The DNS instance
1764   @param  QueryName             Queried Name
1765   @param  Type                  Queried Type
1766   @param  Class                 Queried Class
1767   @param  Packet                The packet for query
1768 
1769   @retval EFI_SUCCESS           The packet is constructed.
1770   @retval Others                Failed to construct the Packet.
1771 
1772 **/
1773 EFI_STATUS
ConstructDNSQuery(IN DNS_INSTANCE * Instance,IN CHAR8 * QueryName,IN UINT16 Type,IN UINT16 Class,OUT NET_BUF ** Packet)1774 ConstructDNSQuery (
1775   IN  DNS_INSTANCE              *Instance,
1776   IN  CHAR8                     *QueryName,
1777   IN  UINT16                    Type,
1778   IN  UINT16                    Class,
1779   OUT NET_BUF                   **Packet
1780   )
1781 {
1782   NET_FRAGMENT        Frag;
1783   DNS_HEADER          *DnsHeader;
1784   DNS_QUERY_SECTION   *DnsQuery;
1785 
1786   Frag.Bulk = AllocatePool (DNS_DEFAULT_BLKSIZE * sizeof (UINT8));
1787   if (Frag.Bulk == NULL) {
1788     return EFI_OUT_OF_RESOURCES;
1789   }
1790 
1791   //
1792   // Fill header
1793   //
1794   DnsHeader = (DNS_HEADER *) Frag.Bulk;
1795   DnsHeader->Identification = (UINT16)NET_RANDOM (NetRandomInitSeed());
1796   DnsHeader->Flags.Uint16 = 0x0000;
1797   DnsHeader->Flags.Bits.RD = 1;
1798   DnsHeader->Flags.Bits.OpCode = DNS_FLAGS_OPCODE_STANDARD;
1799   DnsHeader->Flags.Bits.QR = DNS_FLAGS_QR_QUERY;
1800   DnsHeader->QuestionsNum = 1;
1801   DnsHeader->AnswersNum = 0;
1802   DnsHeader->AuthorityNum = 0;
1803   DnsHeader->AditionalNum = 0;
1804 
1805   DnsHeader->Identification = HTONS (DnsHeader->Identification);
1806   DnsHeader->Flags.Uint16 = HTONS (DnsHeader->Flags.Uint16);
1807   DnsHeader->QuestionsNum = HTONS (DnsHeader->QuestionsNum);
1808   DnsHeader->AnswersNum = HTONS (DnsHeader->AnswersNum);
1809   DnsHeader->AuthorityNum = HTONS (DnsHeader->AuthorityNum);
1810   DnsHeader->AditionalNum = HTONS (DnsHeader->AditionalNum);
1811 
1812   Frag.Len = sizeof (*DnsHeader);
1813 
1814   //
1815   // Fill Query name
1816   //
1817   CopyMem (Frag.Bulk + Frag.Len, QueryName, AsciiStrLen (QueryName));
1818   Frag.Len = (UINT32) (Frag.Len + AsciiStrLen (QueryName));
1819   *(Frag.Bulk + Frag.Len) = 0;
1820   Frag.Len ++;
1821 
1822   //
1823   // Rest query section
1824   //
1825   DnsQuery = (DNS_QUERY_SECTION *) (Frag.Bulk + Frag.Len);
1826 
1827   DnsQuery->Type = HTONS (Type);
1828   DnsQuery->Class = HTONS (Class);
1829 
1830   Frag.Len += sizeof (*DnsQuery);
1831 
1832   //
1833   // Wrap the Frag in a net buffer.
1834   //
1835   *Packet = NetbufFromExt (&Frag, 1, 0, 0, DnsDummyExtFree, NULL);
1836   if (*Packet == NULL) {
1837     FreePool (Frag.Bulk);
1838     return EFI_OUT_OF_RESOURCES;
1839   }
1840 
1841   //
1842   // Store the UdpIo in ProtoData.
1843   //
1844   *((UINTN *) &((*Packet)->ProtoData[0])) = (UINTN) (Instance->UdpIo);
1845 
1846   return EFI_SUCCESS;
1847 }
1848 
1849 /**
1850   Retransmit the packet.
1851 
1852   @param  Instance              The DNS instance
1853   @param  Packet                Retransmit the packet
1854 
1855   @retval EFI_SUCCESS           The packet is retransmitted.
1856   @retval Others                Failed to retransmit.
1857 
1858 **/
1859 EFI_STATUS
DnsRetransmit(IN DNS_INSTANCE * Instance,IN NET_BUF * Packet)1860 DnsRetransmit (
1861   IN DNS_INSTANCE        *Instance,
1862   IN NET_BUF             *Packet
1863   )
1864 {
1865   EFI_STATUS      Status;
1866 
1867   UINT8           *Buffer;
1868 
1869   ASSERT (Packet != NULL);
1870 
1871   //
1872   // Set the requests to the listening port, other packets to the connected port
1873   //
1874   Buffer = NetbufGetByte (Packet, 0, NULL);
1875   ASSERT (Buffer != NULL);
1876 
1877   NET_GET_REF (Packet);
1878 
1879   Status = UdpIoSendDatagram (
1880              Instance->UdpIo,
1881              Packet,
1882              NULL,
1883              NULL,
1884              DnsOnPacketSent,
1885              Instance
1886              );
1887 
1888   if (EFI_ERROR (Status)) {
1889     NET_PUT_REF (Packet);
1890   }
1891 
1892   return Status;
1893 }
1894 
1895 /**
1896   The timer ticking function for the DNS services.
1897 
1898   @param  Event                 The ticking event
1899   @param  Context               The DNS service instance
1900 
1901 **/
1902 VOID
1903 EFIAPI
DnsOnTimerRetransmit(IN EFI_EVENT Event,IN VOID * Context)1904 DnsOnTimerRetransmit (
1905   IN EFI_EVENT              Event,
1906   IN VOID                   *Context
1907   )
1908 {
1909   DNS_SERVICE                *Service;
1910 
1911   LIST_ENTRY                 *Entry;
1912   LIST_ENTRY                 *Next;
1913 
1914   DNS_INSTANCE               *Instance;
1915   LIST_ENTRY                 *EntryNetMap;
1916   NET_MAP_ITEM               *ItemNetMap;
1917   DNS4_TOKEN_ENTRY           *Dns4TokenEntry;
1918   DNS6_TOKEN_ENTRY           *Dns6TokenEntry;
1919 
1920   Dns4TokenEntry = NULL;
1921   Dns6TokenEntry = NULL;
1922 
1923   Service = (DNS_SERVICE *) Context;
1924 
1925 
1926   if (Service->IpVersion == IP_VERSION_4) {
1927     //
1928     // Iterate through all the children of the DNS service instance. Time
1929     // out the packet. If maximum retries reached, clean the Token up.
1930     //
1931     NET_LIST_FOR_EACH_SAFE (Entry, Next, &Service->Dns4ChildrenList) {
1932       Instance = NET_LIST_USER_STRUCT (Entry, DNS_INSTANCE, Link);
1933 
1934       EntryNetMap = Instance->Dns4TxTokens.Used.ForwardLink;
1935       while (EntryNetMap != &Instance->Dns4TxTokens.Used) {
1936         ItemNetMap = NET_LIST_USER_STRUCT (EntryNetMap, NET_MAP_ITEM, Link);
1937         Dns4TokenEntry = (DNS4_TOKEN_ENTRY *)(ItemNetMap->Key);
1938         if (Dns4TokenEntry->PacketToLive == 0 || (--Dns4TokenEntry->PacketToLive > 0)) {
1939           EntryNetMap = EntryNetMap->ForwardLink;
1940           continue;
1941         }
1942 
1943         //
1944         // Retransmit the packet if haven't reach the maxmium retry count,
1945         // otherwise exit the transfer.
1946         //
1947         if (++Dns4TokenEntry->Token->RetryCount < Instance->MaxRetry) {
1948           DnsRetransmit (Instance, (NET_BUF *)ItemNetMap->Value);
1949           EntryNetMap = EntryNetMap->ForwardLink;
1950         } else {
1951           //
1952           // Maximum retries reached, clean the Token up.
1953           //
1954           Dns4RemoveTokenEntry (&Instance->Dns4TxTokens, Dns4TokenEntry);
1955           Dns4TokenEntry->Token->Status = EFI_TIMEOUT;
1956           gBS->SignalEvent (Dns4TokenEntry->Token->Event);
1957           DispatchDpc ();
1958 
1959           //
1960           // Free the sending packet.
1961           //
1962           if (ItemNetMap->Value != NULL) {
1963             NetbufFree ((NET_BUF *)(ItemNetMap->Value));
1964           }
1965 
1966           EntryNetMap = Instance->Dns4TxTokens.Used.ForwardLink;
1967         }
1968       }
1969     }
1970   }else {
1971     //
1972     // Iterate through all the children of the DNS service instance. Time
1973     // out the packet. If maximum retries reached, clean the Token up.
1974     //
1975     NET_LIST_FOR_EACH_SAFE (Entry, Next, &Service->Dns6ChildrenList) {
1976       Instance = NET_LIST_USER_STRUCT (Entry, DNS_INSTANCE, Link);
1977 
1978       EntryNetMap = Instance->Dns6TxTokens.Used.ForwardLink;
1979       while (EntryNetMap != &Instance->Dns6TxTokens.Used) {
1980         ItemNetMap = NET_LIST_USER_STRUCT (EntryNetMap, NET_MAP_ITEM, Link);
1981         Dns6TokenEntry = (DNS6_TOKEN_ENTRY *) (ItemNetMap->Key);
1982         if (Dns6TokenEntry->PacketToLive == 0 || (--Dns6TokenEntry->PacketToLive > 0)) {
1983           EntryNetMap = EntryNetMap->ForwardLink;
1984           continue;
1985         }
1986 
1987         //
1988         // Retransmit the packet if haven't reach the maxmium retry count,
1989         // otherwise exit the transfer.
1990         //
1991         if (++Dns6TokenEntry->Token->RetryCount < Instance->MaxRetry) {
1992           DnsRetransmit (Instance, (NET_BUF *) ItemNetMap->Value);
1993           EntryNetMap = EntryNetMap->ForwardLink;
1994         } else {
1995           //
1996           // Maximum retries reached, clean the Token up.
1997           //
1998           Dns6RemoveTokenEntry (&Instance->Dns6TxTokens, Dns6TokenEntry);
1999           Dns6TokenEntry->Token->Status = EFI_TIMEOUT;
2000           gBS->SignalEvent (Dns6TokenEntry->Token->Event);
2001           DispatchDpc ();
2002 
2003           //
2004           // Free the sending packet.
2005           //
2006           if (ItemNetMap->Value != NULL) {
2007             NetbufFree ((NET_BUF *) (ItemNetMap->Value));
2008           }
2009 
2010           EntryNetMap = Instance->Dns6TxTokens.Used.ForwardLink;
2011         }
2012       }
2013     }
2014   }
2015 }
2016 
2017 /**
2018   The timer ticking function for the DNS driver.
2019 
2020   @param  Event                 The ticking event
2021   @param  Context               NULL
2022 
2023 **/
2024 VOID
2025 EFIAPI
DnsOnTimerUpdate(IN EFI_EVENT Event,IN VOID * Context)2026 DnsOnTimerUpdate (
2027   IN EFI_EVENT              Event,
2028   IN VOID                   *Context
2029   )
2030 {
2031   LIST_ENTRY                 *Entry;
2032   LIST_ENTRY                 *Next;
2033   DNS4_CACHE                 *Item4;
2034   DNS6_CACHE                 *Item6;
2035 
2036   Item4 = NULL;
2037   Item6 = NULL;
2038 
2039   //
2040   // Iterate through all the DNS4 cache list.
2041   //
2042   NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns4CacheList) {
2043     Item4 = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink);
2044     Item4->DnsCache.Timeout--;
2045   }
2046 
2047   Entry = mDriverData->Dns4CacheList.ForwardLink;
2048   while (Entry != &mDriverData->Dns4CacheList) {
2049     Item4 = NET_LIST_USER_STRUCT (Entry, DNS4_CACHE, AllCacheLink);
2050     if (Item4->DnsCache.Timeout<=0) {
2051       RemoveEntryList (&Item4->AllCacheLink);
2052       Entry = mDriverData->Dns4CacheList.ForwardLink;
2053     } else {
2054       Entry = Entry->ForwardLink;
2055     }
2056   }
2057 
2058   //
2059   // Iterate through all the DNS6 cache list.
2060   //
2061   NET_LIST_FOR_EACH_SAFE (Entry, Next, &mDriverData->Dns6CacheList) {
2062     Item6 = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink);
2063     Item6->DnsCache.Timeout--;
2064   }
2065 
2066   Entry = mDriverData->Dns6CacheList.ForwardLink;
2067   while (Entry != &mDriverData->Dns6CacheList) {
2068     Item6 = NET_LIST_USER_STRUCT (Entry, DNS6_CACHE, AllCacheLink);
2069     if (Item6->DnsCache.Timeout<=0) {
2070       RemoveEntryList (&Item6->AllCacheLink);
2071       Entry = mDriverData->Dns6CacheList.ForwardLink;
2072     } else {
2073       Entry = Entry->ForwardLink;
2074     }
2075   }
2076 }
2077 
2078