1 /** @file
2 Functions implementation related with DHCPv4/v6 for DNS driver.
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   The callback function for the timer event used to get map.
19 
20   @param[in] Event    The event this function is registered to.
21   @param[in] Context  The context registered to the event.
22 **/
23 VOID
24 EFIAPI
TimeoutToGetMap(IN EFI_EVENT Event,IN VOID * Context)25 TimeoutToGetMap (
26   IN EFI_EVENT      Event,
27   IN VOID           *Context
28   )
29 {
30   *((BOOLEAN *) Context) = TRUE;
31   return ;
32 }
33 
34 /**
35   Create an IP child, use it to start the auto configuration, then destroy it.
36 
37   @param[in] Controller       The controller which has the service installed.
38   @param[in] Image            The image handle used to open service.
39 
40   @retval EFI_SUCCESS         The configuration is done.
41   @retval Others              Other errors as indicated.
42 **/
43 EFI_STATUS
44 EFIAPI
DnsStartIp4(IN EFI_HANDLE Controller,IN EFI_HANDLE Image)45 DnsStartIp4(
46   IN  EFI_HANDLE            Controller,
47   IN  EFI_HANDLE            Image
48   )
49 {
50   EFI_IP4_PROTOCOL              *Ip4;
51   EFI_HANDLE                    Ip4Handle;
52   EFI_EVENT                     TimerToGetMap;
53   EFI_IP4_CONFIG_DATA           Ip4ConfigData;
54   EFI_IP4_MODE_DATA             Ip4Mode;
55   EFI_STATUS                    Status;
56 
57   BOOLEAN                       Timeout;
58 
59   //
60   // Get the Ip4ServiceBinding Protocol
61   //
62   Ip4Handle     = NULL;
63   Ip4           = NULL;
64   TimerToGetMap = NULL;
65 
66   Timeout      = FALSE;
67 
68   Status = NetLibCreateServiceChild (
69              Controller,
70              Image,
71              &gEfiIp4ServiceBindingProtocolGuid,
72              &Ip4Handle
73              );
74 
75   if (EFI_ERROR (Status)) {
76     return Status;
77   }
78 
79   Status = gBS->OpenProtocol (
80                  Ip4Handle,
81                  &gEfiIp4ProtocolGuid,
82                  (VOID **) &Ip4,
83                  Controller,
84                  Image,
85                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
86                  );
87 
88   if (EFI_ERROR (Status)) {
89     goto ON_EXIT;
90   }
91 
92   Ip4ConfigData.DefaultProtocol          = EFI_IP_PROTO_ICMP;
93   Ip4ConfigData.AcceptAnyProtocol        = FALSE;
94   Ip4ConfigData.AcceptIcmpErrors         = FALSE;
95   Ip4ConfigData.AcceptBroadcast          = FALSE;
96   Ip4ConfigData.AcceptPromiscuous        = FALSE;
97   Ip4ConfigData.UseDefaultAddress        = TRUE;
98   ZeroMem (&Ip4ConfigData.StationAddress, sizeof (EFI_IPv4_ADDRESS));
99   ZeroMem (&Ip4ConfigData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
100   Ip4ConfigData.TypeOfService            = 0;
101   Ip4ConfigData.TimeToLive               = 1;
102   Ip4ConfigData.DoNotFragment            = FALSE;
103   Ip4ConfigData.RawData                  = FALSE;
104   Ip4ConfigData.ReceiveTimeout           = 0;
105   Ip4ConfigData.TransmitTimeout          = 0;
106 
107   Status = Ip4->Configure (Ip4, &Ip4ConfigData);
108 
109   if (Status == EFI_NO_MAPPING) {
110     Status  = gBS->CreateEvent (
111                     EVT_NOTIFY_SIGNAL | EVT_TIMER,
112                     TPL_CALLBACK,
113                     TimeoutToGetMap,
114                     &Timeout,
115                     &TimerToGetMap
116                     );
117 
118     if (EFI_ERROR (Status)) {
119       goto ON_EXIT;
120     }
121 
122     Status = gBS->SetTimer (
123                    TimerToGetMap,
124                    TimerRelative,
125                    MultU64x32 (10000000, 5)
126                    );
127 
128     if (EFI_ERROR (Status)) {
129       goto ON_EXIT;
130     }
131 
132     while (!Timeout) {
133       Ip4->Poll (Ip4);
134 
135       if (!EFI_ERROR (Ip4->GetModeData (Ip4, &Ip4Mode, NULL, NULL)) &&
136           Ip4Mode.IsConfigured) {
137         break;
138       }
139     }
140 
141     if (Timeout) {
142       Status = EFI_DEVICE_ERROR;
143     }
144   }
145 
146 ON_EXIT:
147 
148   if (TimerToGetMap != NULL) {
149     gBS->SetTimer (TimerToGetMap, TimerCancel, 0);
150     gBS->CloseEvent (TimerToGetMap);
151   }
152 
153   NetLibDestroyServiceChild (
154     Controller,
155     Image,
156     &gEfiIp4ServiceBindingProtocolGuid,
157     Ip4Handle
158     );
159 
160   return Status;
161 }
162 
163 /**
164   This function initialize the DHCP4 message instance.
165 
166   This function will pad each item of dhcp4 message packet.
167 
168   @param  Seed             Pointer to the message instance of the DHCP4 packet.
169   @param  InterfaceInfo    Pointer to the EFI_IP4_CONFIG2_INTERFACE_INFO instance.
170 
171 **/
172 VOID
DnsInitSeedPacket(OUT EFI_DHCP4_PACKET * Seed,IN EFI_IP4_CONFIG2_INTERFACE_INFO * InterfaceInfo)173 DnsInitSeedPacket (
174   OUT EFI_DHCP4_PACKET               *Seed,
175   IN  EFI_IP4_CONFIG2_INTERFACE_INFO *InterfaceInfo
176   )
177 {
178   EFI_DHCP4_HEADER           *Header;
179 
180   //
181   // Get IfType and HwAddressSize from SNP mode data.
182   //
183   Seed->Size            = sizeof (EFI_DHCP4_PACKET);
184   Seed->Length          = sizeof (Seed->Dhcp4);
185   Header                = &Seed->Dhcp4.Header;
186   ZeroMem (Header, sizeof (EFI_DHCP4_HEADER));
187   Header->OpCode        = DHCP4_OPCODE_REQUEST;
188   Header->HwType        = InterfaceInfo->IfType;
189   Header->HwAddrLen     = (UINT8) InterfaceInfo->HwAddressSize;
190   CopyMem (Header->ClientHwAddr, &(InterfaceInfo->HwAddress), Header->HwAddrLen);
191 
192   Seed->Dhcp4.Magik     = DHCP4_MAGIC;
193   Seed->Dhcp4.Option[0] = DHCP4_TAG_EOP;
194 }
195 
196 /**
197   The common notify function.
198 
199   @param[in]  Event   The event signaled.
200   @param[in]  Context The context.
201 
202 **/
203 VOID
204 EFIAPI
DhcpCommonNotify(IN EFI_EVENT Event,IN VOID * Context)205 DhcpCommonNotify (
206   IN EFI_EVENT  Event,
207   IN VOID       *Context
208   )
209 {
210   if ((Event == NULL) || (Context == NULL)) {
211     return ;
212   }
213 
214   *((BOOLEAN *) Context) = TRUE;
215 }
216 
217 /**
218   Parse the ACK to get required information
219 
220   @param  Dhcp4            The DHCP4 protocol.
221   @param  Packet           Packet waiting for parse.
222   @param  DnsServerInfor   The required Dns4 server information.
223 
224   @retval EFI_SUCCESS           The DNS information is got from the DHCP ACK.
225   @retval EFI_NO_MAPPING        DHCP failed to acquire address and other information.
226   @retval EFI_DEVICE_ERROR      Other errors as indicated.
227   @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory.
228 
229 **/
230 EFI_STATUS
ParseDhcp4Ack(IN EFI_DHCP4_PROTOCOL * Dhcp4,IN EFI_DHCP4_PACKET * Packet,IN DNS4_SERVER_INFOR * DnsServerInfor)231 ParseDhcp4Ack (
232   IN EFI_DHCP4_PROTOCOL         *Dhcp4,
233   IN EFI_DHCP4_PACKET           *Packet,
234   IN DNS4_SERVER_INFOR          *DnsServerInfor
235   )
236 {
237   EFI_STATUS              Status;
238   UINT32                  OptionCount;
239   EFI_DHCP4_PACKET_OPTION **OptionList;
240   UINT32                  ServerCount;
241   EFI_IPv4_ADDRESS        *ServerList;
242   UINT32                  Index;
243   UINT32                  Count;
244 
245   ServerCount = 0;
246   ServerList = NULL;
247 
248   OptionCount = 0;
249   OptionList  = NULL;
250 
251   Status      = Dhcp4->Parse (Dhcp4, Packet, &OptionCount, OptionList);
252   if (Status != EFI_BUFFER_TOO_SMALL) {
253     return EFI_DEVICE_ERROR;
254   }
255 
256   OptionList = AllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));
257   if (OptionList == NULL) {
258     return EFI_OUT_OF_RESOURCES;
259   }
260 
261   Status = Dhcp4->Parse (Dhcp4, Packet, &OptionCount, OptionList);
262   if (EFI_ERROR (Status)) {
263     gBS->FreePool (OptionList);
264     return EFI_DEVICE_ERROR;
265   }
266 
267   Status = EFI_NOT_FOUND;
268 
269   for (Index = 0; Index < OptionCount; Index++) {
270     //
271     // Get DNS server addresses
272     //
273     if (OptionList[Index]->OpCode == DHCP4_TAG_DNS_SERVER) {
274 
275       if (((OptionList[Index]->Length & 0x3) != 0) || (OptionList[Index]->Length == 0)) {
276         Status = EFI_DEVICE_ERROR;
277         break;
278       }
279 
280       ServerCount = OptionList[Index]->Length/4;
281       ServerList = AllocatePool (ServerCount * sizeof (EFI_IPv4_ADDRESS));
282       if (ServerList == NULL) {
283         return EFI_OUT_OF_RESOURCES;
284       }
285 
286       for(Count=0; Count < ServerCount; Count++){
287         CopyMem (ServerList + Count, &OptionList[Index]->Data[4 * Count], sizeof (EFI_IPv4_ADDRESS));
288       }
289 
290       *(DnsServerInfor->ServerCount) = ServerCount;
291       DnsServerInfor->ServerList     = ServerList;
292 
293       Status = EFI_SUCCESS;
294     }
295   }
296 
297   gBS->FreePool (OptionList);
298 
299   return Status;
300 }
301 
302 /**
303   EFI_DHCP6_INFO_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol
304   instance to intercept events that occurs in the DHCPv6 Information Request
305   exchange process.
306 
307   @param  This                  Pointer to the EFI_DHCP6_PROTOCOL instance that
308                                 is used to configure this  callback function.
309   @param  Context               Pointer to the context that is initialized in
310                                 the EFI_DHCP6_PROTOCOL.InfoRequest().
311   @param  Packet                Pointer to Reply packet that has been received.
312                                 The EFI DHCPv6 Protocol instance is responsible
313                                 for freeing the buffer.
314 
315   @retval EFI_SUCCESS           The DNS information is got from the DHCP ACK.
316   @retval EFI_DEVICE_ERROR      Other errors as indicated.
317   @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory.
318 **/
319 EFI_STATUS
320 EFIAPI
ParseDhcp6Ack(IN EFI_DHCP6_PROTOCOL * This,IN VOID * Context,IN EFI_DHCP6_PACKET * Packet)321 ParseDhcp6Ack (
322   IN EFI_DHCP6_PROTOCOL          *This,
323   IN VOID                        *Context,
324   IN EFI_DHCP6_PACKET            *Packet
325   )
326 {
327   EFI_STATUS                  Status;
328   UINT32                      OptionCount;
329   EFI_DHCP6_PACKET_OPTION     **OptionList;
330   DNS6_SERVER_INFOR           *DnsServerInfor;
331   UINT32                      ServerCount;
332   EFI_IPv6_ADDRESS            *ServerList;
333   UINT32                      Index;
334   UINT32                      Count;
335 
336   OptionCount = 0;
337   ServerCount = 0;
338   ServerList  = NULL;
339 
340   Status      = This->Parse (This, Packet, &OptionCount, NULL);
341   if (Status != EFI_BUFFER_TOO_SMALL) {
342     return EFI_DEVICE_ERROR;
343   }
344 
345   OptionList = AllocateZeroPool (OptionCount * sizeof (EFI_DHCP6_PACKET_OPTION *));
346   if (OptionList == NULL) {
347     return EFI_OUT_OF_RESOURCES;
348   }
349 
350   Status = This->Parse (This, Packet, &OptionCount, OptionList);
351   if (EFI_ERROR (Status)) {
352     gBS->FreePool (OptionList);
353     return EFI_DEVICE_ERROR;
354   }
355 
356   DnsServerInfor = (DNS6_SERVER_INFOR *) Context;
357 
358   for (Index = 0; Index < OptionCount; Index++) {
359     OptionList[Index]->OpCode = NTOHS (OptionList[Index]->OpCode);
360     OptionList[Index]->OpLen  = NTOHS (OptionList[Index]->OpLen);
361 
362     //
363     // Get DNS server addresses from this reply packet.
364     //
365     if (OptionList[Index]->OpCode == DHCP6_TAG_DNS_SERVER) {
366 
367       if (((OptionList[Index]->OpLen & 0xf) != 0) || (OptionList[Index]->OpLen == 0)) {
368         Status = EFI_DEVICE_ERROR;
369         gBS->FreePool (OptionList);
370         return Status;
371       }
372 
373       ServerCount = OptionList[Index]->OpLen/16;
374       ServerList = AllocatePool (ServerCount * sizeof (EFI_IPv6_ADDRESS));
375       if (ServerList == NULL) {
376         gBS->FreePool (OptionList);
377         return EFI_OUT_OF_RESOURCES;
378       }
379 
380       for(Count=0; Count < ServerCount; Count++){
381         CopyMem (ServerList + Count, &OptionList[Index]->Data[16 * Count], sizeof (EFI_IPv6_ADDRESS));
382       }
383 
384       *(DnsServerInfor->ServerCount) = ServerCount;
385       DnsServerInfor->ServerList     = ServerList;
386     }
387   }
388 
389   gBS->FreePool (OptionList);
390 
391   return Status;
392 
393 }
394 
395 /**
396   Parse the DHCP ACK to get Dns4 server information.
397 
398   @param  Instance         The DNS instance.
399   @param  DnsServerCount   Retrieved Dns4 server Ip count.
400   @param  DnsServerList    Retrieved Dns4 server Ip list.
401 
402   @retval EFI_SUCCESS           The Dns4 information is got from the DHCP ACK.
403   @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory.
404   @retval EFI_NO_MEDIA          There was a media error.
405   @retval Others                Other errors as indicated.
406 
407 **/
408 EFI_STATUS
GetDns4ServerFromDhcp4(IN DNS_INSTANCE * Instance,OUT UINT32 * DnsServerCount,OUT EFI_IPv4_ADDRESS ** DnsServerList)409 GetDns4ServerFromDhcp4 (
410   IN  DNS_INSTANCE               *Instance,
411   OUT UINT32                     *DnsServerCount,
412   OUT EFI_IPv4_ADDRESS           **DnsServerList
413   )
414 {
415   EFI_STATUS                          Status;
416   EFI_HANDLE                          Image;
417   EFI_HANDLE                          Controller;
418   BOOLEAN                             MediaPresent;
419   EFI_HANDLE                          MnpChildHandle;
420   EFI_MANAGED_NETWORK_PROTOCOL        *Mnp;
421   EFI_MANAGED_NETWORK_CONFIG_DATA     MnpConfigData;
422   EFI_HANDLE                          Dhcp4Handle;
423   EFI_DHCP4_PROTOCOL                  *Dhcp4;
424   EFI_IP4_CONFIG2_PROTOCOL            *Ip4Config2;
425   UINTN                               DataSize;
426   VOID                                *Data;
427   EFI_IP4_CONFIG2_INTERFACE_INFO      *InterfaceInfo;
428   EFI_DHCP4_PACKET                    SeedPacket;
429   EFI_DHCP4_PACKET_OPTION             *ParaList[2];
430   DNS4_SERVER_INFOR                   DnsServerInfor;
431 
432   EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN    Token;
433   BOOLEAN                             IsDone;
434   UINTN                               Index;
435 
436   Image                      = Instance->Service->ImageHandle;
437   Controller                 = Instance->Service->ControllerHandle;
438 
439   MnpChildHandle             = NULL;
440   Mnp                        = NULL;
441 
442   Dhcp4Handle                = NULL;
443   Dhcp4                      = NULL;
444 
445   Ip4Config2                 = NULL;
446   DataSize                   = 0;
447   Data                       = NULL;
448   InterfaceInfo              = NULL;
449 
450   ZeroMem ((UINT8 *) ParaList, sizeof (ParaList));
451 
452   ZeroMem (&MnpConfigData, sizeof (EFI_MANAGED_NETWORK_CONFIG_DATA));
453 
454   ZeroMem (&DnsServerInfor, sizeof (DNS4_SERVER_INFOR));
455 
456   ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN));
457 
458   DnsServerInfor.ServerCount = DnsServerCount;
459 
460   IsDone = FALSE;
461 
462   //
463   // Check media.
464   //
465   MediaPresent = TRUE;
466   NetLibDetectMedia (Controller, &MediaPresent);
467   if (!MediaPresent) {
468     return EFI_NO_MEDIA;
469   }
470 
471   //
472   // Start the auto configuration if UseDefaultSetting.
473   //
474   if (Instance->Dns4CfgData.UseDefaultSetting) {
475     Status = DnsStartIp4 (Controller, Image);
476     if (EFI_ERROR(Status)) {
477       return Status;
478     }
479   }
480 
481   //
482   // Create a Mnp child instance, get the protocol and config for it.
483   //
484   Status = NetLibCreateServiceChild (
485              Controller,
486              Image,
487              &gEfiManagedNetworkServiceBindingProtocolGuid,
488              &MnpChildHandle
489              );
490   if (EFI_ERROR (Status)) {
491     return Status;
492   }
493 
494   Status = gBS->OpenProtocol (
495                   MnpChildHandle,
496                   &gEfiManagedNetworkProtocolGuid,
497                   (VOID **) &Mnp,
498                   Image,
499                   Controller,
500                   EFI_OPEN_PROTOCOL_BY_DRIVER
501                   );
502   if (EFI_ERROR (Status)) {
503     goto ON_EXIT;
504   }
505 
506   MnpConfigData.ReceivedQueueTimeoutValue = 0;
507   MnpConfigData.TransmitQueueTimeoutValue = 0;
508   MnpConfigData.ProtocolTypeFilter        = IP4_ETHER_PROTO;
509   MnpConfigData.EnableUnicastReceive      = TRUE;
510   MnpConfigData.EnableMulticastReceive    = TRUE;
511   MnpConfigData.EnableBroadcastReceive    = TRUE;
512   MnpConfigData.EnablePromiscuousReceive  = FALSE;
513   MnpConfigData.FlushQueuesOnReset        = TRUE;
514   MnpConfigData.EnableReceiveTimestamps   = FALSE;
515   MnpConfigData.DisableBackgroundPolling  = FALSE;
516 
517   Status = Mnp->Configure(Mnp, &MnpConfigData);
518   if (EFI_ERROR (Status)) {
519     goto ON_EXIT;
520   }
521 
522   //
523   // Create a DHCP4 child instance and get the protocol.
524   //
525   Status = NetLibCreateServiceChild (
526              Controller,
527              Image,
528              &gEfiDhcp4ServiceBindingProtocolGuid,
529              &Dhcp4Handle
530              );
531   if (EFI_ERROR (Status)) {
532     goto ON_EXIT;
533   }
534 
535   Status = gBS->OpenProtocol (
536                   Dhcp4Handle,
537                   &gEfiDhcp4ProtocolGuid,
538                   (VOID **) &Dhcp4,
539                   Image,
540                   Controller,
541                   EFI_OPEN_PROTOCOL_BY_DRIVER
542                   );
543   if (EFI_ERROR (Status)) {
544     goto ON_EXIT;
545   }
546 
547   //
548   // Get Ip4Config2 instance info.
549   //
550   Status = gBS->HandleProtocol (Controller, &gEfiIp4Config2ProtocolGuid, (VOID **) &Ip4Config2);
551   if (EFI_ERROR (Status)) {
552     goto ON_EXIT;
553   }
554 
555   Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeInterfaceInfo, &DataSize, Data);
556   if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
557     goto ON_EXIT;
558   }
559 
560   Data = AllocateZeroPool (DataSize);
561   if (Data == NULL) {
562     Status = EFI_OUT_OF_RESOURCES;
563     goto ON_EXIT;
564   }
565 
566   Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeInterfaceInfo, &DataSize, Data);
567   if (EFI_ERROR (Status)) {
568     goto ON_EXIT;
569   }
570 
571   InterfaceInfo = (EFI_IP4_CONFIG2_INTERFACE_INFO *)Data;
572 
573   //
574   // Build required Token.
575   //
576   Status = gBS->CreateEvent (
577                   EVT_NOTIFY_SIGNAL,
578                   TPL_NOTIFY,
579                   DhcpCommonNotify,
580                   &IsDone,
581                   &Token.CompletionEvent
582                   );
583   if (EFI_ERROR (Status)) {
584     goto ON_EXIT;
585   }
586 
587   SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff);
588 
589   Token.RemotePort = 67;
590 
591   Token.ListenPointCount = 1;
592 
593   Token.ListenPoints = AllocateZeroPool (Token.ListenPointCount * sizeof (EFI_DHCP4_LISTEN_POINT));
594   if (Token.ListenPoints == NULL) {
595     Status = EFI_OUT_OF_RESOURCES;
596     goto ON_EXIT;
597   }
598 
599   if (Instance->Dns4CfgData.UseDefaultSetting) {
600     CopyMem (&(Token.ListenPoints[0].ListenAddress), &(InterfaceInfo->StationAddress), sizeof (EFI_IPv4_ADDRESS));
601     CopyMem (&(Token.ListenPoints[0].SubnetMask), &(InterfaceInfo->SubnetMask), sizeof (EFI_IPv4_ADDRESS));
602   } else {
603     CopyMem (&(Token.ListenPoints[0].ListenAddress), &(Instance->Dns4CfgData.StationIp), sizeof (EFI_IPv4_ADDRESS));
604     CopyMem (&(Token.ListenPoints[0].SubnetMask), &(Instance->Dns4CfgData.SubnetMask), sizeof (EFI_IPv4_ADDRESS));
605   }
606 
607   Token.ListenPoints[0].ListenPort = 68;
608 
609   Token.TimeoutValue = DNS_TIME_TO_GETMAP;
610 
611   DnsInitSeedPacket (&SeedPacket, InterfaceInfo);
612 
613   ParaList[0] = AllocateZeroPool (sizeof (EFI_DHCP4_PACKET_OPTION));
614   if (ParaList[0] == NULL) {
615     Status = EFI_OUT_OF_RESOURCES;
616     goto ON_EXIT;
617   }
618 
619   ParaList[0]->OpCode  = DHCP4_TAG_TYPE;
620   ParaList[0]->Length  = 1;
621   ParaList[0]->Data[0] = DHCP4_MSG_INFORM;
622 
623   ParaList[1] = AllocateZeroPool (sizeof (EFI_DHCP4_PACKET_OPTION));
624   if (ParaList[1] == NULL) {
625     Status = EFI_OUT_OF_RESOURCES;
626     goto ON_EXIT;
627   }
628 
629   ParaList[1]->OpCode  = DHCP4_TAG_PARA_LIST;
630   ParaList[1]->Length  = 1;
631   ParaList[1]->Data[0] = DHCP4_TAG_DNS_SERVER;
632 
633   Status = Dhcp4->Build (Dhcp4, &SeedPacket, 0, NULL, 2, ParaList, &Token.Packet);
634 
635   Token.Packet->Dhcp4.Header.Xid      = HTONL(NET_RANDOM (NetRandomInitSeed ()));
636 
637   Token.Packet->Dhcp4.Header.Reserved = HTONS ((UINT16)0x8000);
638 
639   if (Instance->Dns4CfgData.UseDefaultSetting) {
640     CopyMem (&(Token.Packet->Dhcp4.Header.ClientAddr), &(InterfaceInfo->StationAddress), sizeof (EFI_IPv4_ADDRESS));
641   } else {
642     CopyMem (&(Token.Packet->Dhcp4.Header.ClientAddr), &(Instance->Dns4CfgData.StationIp), sizeof (EFI_IPv4_ADDRESS));
643   }
644 
645   CopyMem (Token.Packet->Dhcp4.Header.ClientHwAddr, &(InterfaceInfo->HwAddress), InterfaceInfo->HwAddressSize);
646 
647   Token.Packet->Dhcp4.Header.HwAddrLen = (UINT8)(InterfaceInfo->HwAddressSize);
648 
649   //
650   // TransmitReceive Token
651   //
652   Status = Dhcp4->TransmitReceive (Dhcp4, &Token);
653   if (EFI_ERROR (Status)) {
654     goto ON_EXIT;
655   }
656 
657   //
658   // Poll the packet
659   //
660   do {
661     Status = Mnp->Poll (Mnp);
662   } while (!IsDone);
663 
664   //
665   // Parse the ACK to get required information if received done.
666   //
667   if (IsDone && !EFI_ERROR (Token.Status)) {
668     for (Index = 0; Index < Token.ResponseCount; Index++) {
669       Status = ParseDhcp4Ack (Dhcp4, &Token.ResponseList[Index], &DnsServerInfor);
670       if (!EFI_ERROR (Status)) {
671         break;
672       }
673     }
674 
675     *DnsServerList = DnsServerInfor.ServerList;
676   } else {
677     Status = Token.Status;
678   }
679 
680 ON_EXIT:
681 
682   if (Data != NULL) {
683     FreePool (Data);
684   }
685 
686   for (Index = 0; Index < 2; Index++) {
687     if (ParaList[Index] != NULL) {
688       FreePool (ParaList[Index]);
689     }
690   }
691 
692   if (Token.ListenPoints) {
693     FreePool (Token.ListenPoints);
694   }
695 
696   if (Token.Packet) {
697     FreePool (Token.Packet);
698   }
699 
700   if (Token.ResponseList != NULL) {
701     FreePool (Token.ResponseList);
702   }
703 
704   if (Token.CompletionEvent != NULL) {
705     gBS->CloseEvent (Token.CompletionEvent);
706   }
707 
708   if (Dhcp4 != NULL) {
709     Dhcp4->Stop (Dhcp4);
710     Dhcp4->Configure (Dhcp4, NULL);
711 
712     gBS->CloseProtocol (
713            Dhcp4Handle,
714            &gEfiDhcp4ProtocolGuid,
715            Image,
716            Controller
717            );
718   }
719 
720   if (Dhcp4Handle != NULL) {
721     NetLibDestroyServiceChild (
722       Controller,
723       Image,
724       &gEfiDhcp4ServiceBindingProtocolGuid,
725       Dhcp4Handle
726       );
727   }
728 
729   if (Mnp != NULL) {
730     Mnp->Configure (Mnp, NULL);
731 
732     gBS->CloseProtocol (
733            MnpChildHandle,
734            &gEfiManagedNetworkProtocolGuid,
735            Image,
736            Controller
737            );
738   }
739 
740   NetLibDestroyServiceChild (
741     Controller,
742     Image,
743     &gEfiManagedNetworkServiceBindingProtocolGuid,
744     MnpChildHandle
745     );
746 
747   return Status;
748 }
749 
750 /**
751   Parse the DHCP ACK to get Dns6 server information.
752 
753   @param  Image            The handle of the driver image.
754   @param  Controller       The handle of the controller.
755   @param  DnsServerCount   Retrieved Dns6 server Ip count.
756   @param  DnsServerList    Retrieved Dns6 server Ip list.
757 
758   @retval EFI_SUCCESS           The Dns6 information is got from the DHCP ACK.
759   @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory.
760   @retval EFI_NO_MEDIA          There was a media error.
761   @retval Others                Other errors as indicated.
762 
763 **/
764 EFI_STATUS
GetDns6ServerFromDhcp6(IN EFI_HANDLE Image,IN EFI_HANDLE Controller,OUT UINT32 * DnsServerCount,OUT EFI_IPv6_ADDRESS ** DnsServerList)765 GetDns6ServerFromDhcp6 (
766   IN  EFI_HANDLE                 Image,
767   IN  EFI_HANDLE                 Controller,
768   OUT UINT32                     *DnsServerCount,
769   OUT EFI_IPv6_ADDRESS           **DnsServerList
770   )
771 {
772   EFI_HANDLE                Dhcp6Handle;
773   EFI_DHCP6_PROTOCOL        *Dhcp6;
774   EFI_STATUS                Status;
775   EFI_STATUS                TimerStatus;
776   EFI_DHCP6_PACKET_OPTION   *Oro;
777   EFI_DHCP6_RETRANSMISSION  InfoReqReXmit;
778   EFI_EVENT                 Timer;
779   BOOLEAN                   MediaPresent;
780   DNS6_SERVER_INFOR         DnsServerInfor;
781 
782   Dhcp6Handle = NULL;
783   Dhcp6       = NULL;
784   Oro         = NULL;
785   Timer       = NULL;
786 
787   ZeroMem (&DnsServerInfor, sizeof (DNS6_SERVER_INFOR));
788 
789   DnsServerInfor.ServerCount = DnsServerCount;
790 
791   //
792   // Check media status before doing DHCP.
793   //
794   MediaPresent = TRUE;
795   NetLibDetectMedia (Controller, &MediaPresent);
796   if (!MediaPresent) {
797     return EFI_NO_MEDIA;
798   }
799 
800   //
801   // Create a DHCP6 child instance and get the protocol.
802   //
803   Status = NetLibCreateServiceChild (
804              Controller,
805              Image,
806              &gEfiDhcp6ServiceBindingProtocolGuid,
807              &Dhcp6Handle
808              );
809   if (EFI_ERROR (Status)) {
810     return Status;
811   }
812 
813   Status = gBS->OpenProtocol (
814                   Dhcp6Handle,
815                   &gEfiDhcp6ProtocolGuid,
816                   (VOID **) &Dhcp6,
817                   Image,
818                   Controller,
819                   EFI_OPEN_PROTOCOL_BY_DRIVER
820                   );
821   if (EFI_ERROR (Status)) {
822     goto ON_EXIT;
823   }
824 
825   Oro = AllocateZeroPool (sizeof (EFI_DHCP6_PACKET_OPTION) + 1);
826   if (Oro == NULL) {
827     Status = EFI_OUT_OF_RESOURCES;
828     goto ON_EXIT;
829   }
830 
831   //
832   // Ask the server to reply with DNS options.
833   // All members in EFI_DHCP6_PACKET_OPTION are in network order.
834   //
835   Oro->OpCode  = HTONS (DHCP6_TAG_DNS_REQUEST);
836   Oro->OpLen   = HTONS (2);
837   Oro->Data[1] = DHCP6_TAG_DNS_SERVER;
838 
839   InfoReqReXmit.Irt = 4;
840   InfoReqReXmit.Mrc = 1;
841   InfoReqReXmit.Mrt = 10;
842   InfoReqReXmit.Mrd = 30;
843 
844   Status = Dhcp6->InfoRequest (
845                     Dhcp6,
846                     TRUE,
847                     Oro,
848                     0,
849                     NULL,
850                     &InfoReqReXmit,
851                     NULL,
852                     ParseDhcp6Ack,
853                     &DnsServerInfor
854                     );
855   if (Status == EFI_NO_MAPPING) {
856     Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);
857     if (EFI_ERROR (Status)) {
858       goto ON_EXIT;
859     }
860 
861     Status = gBS->SetTimer (
862                     Timer,
863                     TimerRelative,
864                     DNS_TIME_TO_GETMAP * TICKS_PER_SECOND
865                     );
866 
867     if (EFI_ERROR (Status)) {
868       goto ON_EXIT;
869     }
870 
871     do {
872       TimerStatus = gBS->CheckEvent (Timer);
873       if (!EFI_ERROR (TimerStatus)) {
874         Status = Dhcp6->InfoRequest (
875                           Dhcp6,
876                           TRUE,
877                           Oro,
878                           0,
879                           NULL,
880                           &InfoReqReXmit,
881                           NULL,
882                           ParseDhcp6Ack,
883                           &DnsServerInfor
884                           );
885       }
886     } while (TimerStatus == EFI_NOT_READY);
887   }
888 
889   *DnsServerList  = DnsServerInfor.ServerList;
890 
891 ON_EXIT:
892 
893   if (Oro != NULL) {
894     FreePool (Oro);
895   }
896 
897   if (Timer != NULL) {
898     gBS->CloseEvent (Timer);
899   }
900 
901   if (Dhcp6 != NULL) {
902     gBS->CloseProtocol (
903            Dhcp6Handle,
904            &gEfiDhcp6ProtocolGuid,
905            Image,
906            Controller
907            );
908   }
909 
910   NetLibDestroyServiceChild (
911     Controller,
912     Image,
913     &gEfiDhcp6ServiceBindingProtocolGuid,
914     Dhcp6Handle
915     );
916 
917   return Status;
918 
919 }
920 
921