]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/DnsDxe/DnsDhcp.c
NetworkPkg: Add DNS feature support over IPv4 and IPv6.
[mirror_edk2.git] / NetworkPkg / DnsDxe / DnsDhcp.c
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 software and associated documentation (if any) is furnished
6 under a license and may only be used or copied in accordance
7 with the terms of the license. Except as permitted by such
8 license, no part of this software or documentation may be
9 reproduced, stored in a retrieval system, or transmitted in any
10 form or by any means without the express written consent of
11 Intel Corporation.
12
13 **/
14
15 #include "DnsImpl.h"
16
17 /**
18 This function initialize the DHCP4 message instance.
19
20 This function will pad each item of dhcp4 message packet.
21
22 @param Seed Pointer to the message instance of the DHCP4 packet.
23 @param InterfaceInfo Pointer to the EFI_IP4_CONFIG2_INTERFACE_INFO instance.
24
25 **/
26 VOID
27 DnsInitSeedPacket (
28 OUT EFI_DHCP4_PACKET *Seed,
29 IN EFI_IP4_CONFIG2_INTERFACE_INFO *InterfaceInfo
30 )
31 {
32 EFI_DHCP4_HEADER *Header;
33
34 //
35 // Get IfType and HwAddressSize from SNP mode data.
36 //
37 Seed->Size = sizeof (EFI_DHCP4_PACKET);
38 Seed->Length = sizeof (Seed->Dhcp4);
39 Header = &Seed->Dhcp4.Header;
40 ZeroMem (Header, sizeof (EFI_DHCP4_HEADER));
41 Header->OpCode = DHCP4_OPCODE_REQUEST;
42 Header->HwType = InterfaceInfo->IfType;
43 Header->HwAddrLen = (UINT8) InterfaceInfo->HwAddressSize;
44 CopyMem (Header->ClientHwAddr, &(InterfaceInfo->HwAddress), Header->HwAddrLen);
45
46 Seed->Dhcp4.Magik = DHCP4_MAGIC;
47 Seed->Dhcp4.Option[0] = DHCP4_TAG_EOP;
48 }
49
50 /**
51 The common notify function.
52
53 @param[in] Event The event signaled.
54 @param[in] Context The context.
55
56 **/
57 VOID
58 EFIAPI
59 DhcpCommonNotify (
60 IN EFI_EVENT Event,
61 IN VOID *Context
62 )
63 {
64 if ((Event == NULL) || (Context == NULL)) {
65 return ;
66 }
67
68 *((BOOLEAN *) Context) = TRUE;
69 }
70
71 /**
72 Parse the ACK to get required information
73
74 @param Dhcp4 The DHCP4 protocol.
75 @param Packet Packet waiting for parse.
76 @param DnsServerInfor The required Dns4 server information.
77
78 @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.
79 @retval EFI_NO_MAPPING DHCP failed to acquire address and other information.
80 @retval EFI_DEVICE_ERROR Other errors as indicated.
81 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
82
83 **/
84 EFI_STATUS
85 ParseDhcp4Ack (
86 IN EFI_DHCP4_PROTOCOL *Dhcp4,
87 IN EFI_DHCP4_PACKET *Packet,
88 IN DNS4_SERVER_INFOR *DnsServerInfor
89 )
90 {
91 EFI_STATUS Status;
92 UINT32 OptionCount;
93 EFI_DHCP4_PACKET_OPTION **OptionList;
94 UINT32 ServerCount;
95 EFI_IPv4_ADDRESS *ServerList;
96 UINT32 Index;
97 UINT32 Count;
98
99 ServerCount = 0;
100 ServerList = NULL;
101
102 OptionCount = 0;
103 OptionList = NULL;
104
105 Status = Dhcp4->Parse (Dhcp4, Packet, &OptionCount, OptionList);
106 if (Status != EFI_BUFFER_TOO_SMALL) {
107 return EFI_DEVICE_ERROR;
108 }
109
110 OptionList = AllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));
111 if (OptionList == NULL) {
112 return EFI_OUT_OF_RESOURCES;
113 }
114
115 Status = Dhcp4->Parse (Dhcp4, Packet, &OptionCount, OptionList);
116 if (EFI_ERROR (Status)) {
117 gBS->FreePool (OptionList);
118 return EFI_DEVICE_ERROR;
119 }
120
121 Status = EFI_NOT_FOUND;
122
123 for (Index = 0; Index < OptionCount; Index++) {
124 //
125 // Get DNS server addresses
126 //
127 if (OptionList[Index]->OpCode == DHCP4_TAG_DNS_SERVER) {
128
129 if (((OptionList[Index]->Length & 0x3) != 0) || (OptionList[Index]->Length == 0)) {
130 Status = EFI_DEVICE_ERROR;
131 break;
132 }
133
134 ServerCount = OptionList[Index]->Length/4;
135 ServerList = AllocatePool (ServerCount * sizeof (EFI_IPv4_ADDRESS));
136 if (ServerList == NULL) {
137 return EFI_OUT_OF_RESOURCES;
138 }
139
140 for(Count=0; Count < ServerCount; Count++){
141 CopyMem (ServerList + Count, &OptionList[Index]->Data[4 * Count], sizeof (EFI_IPv4_ADDRESS));
142 }
143
144 *(DnsServerInfor->ServerCount) = ServerCount;
145 DnsServerInfor->ServerList = ServerList;
146
147 Status = EFI_SUCCESS;
148 }
149 }
150
151 gBS->FreePool (OptionList);
152
153 return Status;
154 }
155
156 /**
157 EFI_DHCP6_INFO_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol
158 instance to intercept events that occurs in the DHCPv6 Information Request
159 exchange process.
160
161 @param This Pointer to the EFI_DHCP6_PROTOCOL instance that
162 is used to configure this callback function.
163 @param Context Pointer to the context that is initialized in
164 the EFI_DHCP6_PROTOCOL.InfoRequest().
165 @param Packet Pointer to Reply packet that has been received.
166 The EFI DHCPv6 Protocol instance is responsible
167 for freeing the buffer.
168
169 @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.
170 @retval EFI_DEVICE_ERROR Other errors as indicated.
171 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
172 **/
173 EFI_STATUS
174 EFIAPI
175 ParseDhcp6Ack (
176 IN EFI_DHCP6_PROTOCOL *This,
177 IN VOID *Context,
178 IN EFI_DHCP6_PACKET *Packet
179 )
180 {
181 EFI_STATUS Status;
182 UINT32 OptionCount;
183 EFI_DHCP6_PACKET_OPTION **OptionList;
184 DNS6_SERVER_INFOR *DnsServerInfor;
185 UINT32 ServerCount;
186 EFI_IPv6_ADDRESS *ServerList;
187 UINT32 Index;
188 UINT32 Count;
189
190 OptionCount = 0;
191 ServerCount = 0;
192 ServerList = NULL;
193
194 Status = This->Parse (This, Packet, &OptionCount, NULL);
195 if (Status != EFI_BUFFER_TOO_SMALL) {
196 return EFI_DEVICE_ERROR;
197 }
198
199 OptionList = AllocateZeroPool (OptionCount * sizeof (EFI_DHCP6_PACKET_OPTION *));
200 if (OptionList == NULL) {
201 return EFI_OUT_OF_RESOURCES;
202 }
203
204 Status = This->Parse (This, Packet, &OptionCount, OptionList);
205 if (EFI_ERROR (Status)) {
206 gBS->FreePool (OptionList);
207 return EFI_DEVICE_ERROR;
208 }
209
210 DnsServerInfor = (DNS6_SERVER_INFOR *) Context;
211
212 for (Index = 0; Index < OptionCount; Index++) {
213 OptionList[Index]->OpCode = NTOHS (OptionList[Index]->OpCode);
214 OptionList[Index]->OpLen = NTOHS (OptionList[Index]->OpLen);
215
216 //
217 // Get DNS server addresses from this reply packet.
218 //
219 if (OptionList[Index]->OpCode == DHCP6_TAG_DNS_SERVER) {
220
221 if (((OptionList[Index]->OpLen & 0xf) != 0) || (OptionList[Index]->OpLen == 0)) {
222 Status = EFI_DEVICE_ERROR;
223 gBS->FreePool (OptionList);
224 return Status;
225 }
226
227 ServerCount = OptionList[Index]->OpLen/16;
228 ServerList = AllocatePool (ServerCount * sizeof (EFI_IPv6_ADDRESS));
229 if (ServerList == NULL) {
230 gBS->FreePool (OptionList);
231 return EFI_OUT_OF_RESOURCES;
232 }
233
234 for(Count=0; Count < ServerCount; Count++){
235 CopyMem (ServerList + Count, &OptionList[Index]->Data[16 * Count], sizeof (EFI_IPv6_ADDRESS));
236 }
237
238 *(DnsServerInfor->ServerCount) = ServerCount;
239 DnsServerInfor->ServerList = ServerList;
240 }
241 }
242
243 gBS->FreePool (OptionList);
244
245 return Status;
246
247 }
248
249 /**
250 Parse the DHCP ACK to get Dns4 server information.
251
252 @param Instance The DNS instance.
253 @param DnsServerCount Retrieved Dns4 server Ip count.
254 @param DnsServerList Retrieved Dns4 server Ip list.
255
256 @retval EFI_SUCCESS The Dns4 information is got from the DHCP ACK.
257 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
258 @retval EFI_NO_MEDIA There was a media error.
259 @retval Others Other errors as indicated.
260
261 **/
262 EFI_STATUS
263 GetDns4ServerFromDhcp4 (
264 IN DNS_INSTANCE *Instance,
265 OUT UINT32 *DnsServerCount,
266 OUT EFI_IPv4_ADDRESS **DnsServerList
267 )
268 {
269 EFI_STATUS Status;
270 EFI_HANDLE Image;
271 EFI_HANDLE Controller;
272 BOOLEAN MediaPresent;
273 EFI_HANDLE MnpChildHandle;
274 EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
275 EFI_MANAGED_NETWORK_CONFIG_DATA MnpConfigData;
276 EFI_HANDLE Dhcp4Handle;
277 EFI_DHCP4_PROTOCOL *Dhcp4;
278 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;
279 UINTN DataSize;
280 VOID *Data;
281 EFI_IP4_CONFIG2_INTERFACE_INFO *InterfaceInfo;
282 EFI_DHCP4_PACKET SeedPacket;
283 EFI_DHCP4_PACKET_OPTION *ParaList[2];
284 DNS4_SERVER_INFOR DnsServerInfor;
285
286 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token;
287 BOOLEAN IsDone;
288 UINTN Index;
289
290 Image = Instance->Service->ImageHandle;
291 Controller = Instance->Service->ControllerHandle;
292
293 MnpChildHandle = NULL;
294 Mnp = NULL;
295
296 Dhcp4Handle = NULL;
297 Dhcp4 = NULL;
298
299 Ip4Config2 = NULL;
300 DataSize = 0;
301 Data = NULL;
302 InterfaceInfo = NULL;
303
304 ZeroMem (&MnpConfigData, sizeof (EFI_MANAGED_NETWORK_CONFIG_DATA));
305
306 ZeroMem (&DnsServerInfor, sizeof (DNS4_SERVER_INFOR));
307
308 ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN));
309
310 DnsServerInfor.ServerCount = DnsServerCount;
311
312 IsDone = FALSE;
313
314 //
315 // Check media.
316 //
317 MediaPresent = TRUE;
318 NetLibDetectMedia (Controller, &MediaPresent);
319 if (!MediaPresent) {
320 return EFI_NO_MEDIA;
321 }
322
323 //
324 // Create a Mnp child instance, get the protocol and config for it.
325 //
326 Status = NetLibCreateServiceChild (
327 Controller,
328 Image,
329 &gEfiManagedNetworkServiceBindingProtocolGuid,
330 &MnpChildHandle
331 );
332 if (EFI_ERROR (Status)) {
333 return Status;
334 }
335
336 Status = gBS->OpenProtocol (
337 MnpChildHandle,
338 &gEfiManagedNetworkProtocolGuid,
339 (VOID **) &Mnp,
340 Image,
341 Controller,
342 EFI_OPEN_PROTOCOL_BY_DRIVER
343 );
344 if (EFI_ERROR (Status)) {
345 goto ON_EXIT;
346 }
347
348 MnpConfigData.ReceivedQueueTimeoutValue = 0;
349 MnpConfigData.TransmitQueueTimeoutValue = 0;
350 MnpConfigData.ProtocolTypeFilter = IP4_ETHER_PROTO;
351 MnpConfigData.EnableUnicastReceive = TRUE;
352 MnpConfigData.EnableMulticastReceive = TRUE;
353 MnpConfigData.EnableBroadcastReceive = TRUE;
354 MnpConfigData.EnablePromiscuousReceive = FALSE;
355 MnpConfigData.FlushQueuesOnReset = TRUE;
356 MnpConfigData.EnableReceiveTimestamps = FALSE;
357 MnpConfigData.DisableBackgroundPolling = FALSE;
358
359 Status = Mnp->Configure(Mnp, &MnpConfigData);
360 if (EFI_ERROR (Status)) {
361 goto ON_EXIT;
362 }
363
364 //
365 // Create a DHCP4 child instance and get the protocol.
366 //
367 Status = NetLibCreateServiceChild (
368 Controller,
369 Image,
370 &gEfiDhcp4ServiceBindingProtocolGuid,
371 &Dhcp4Handle
372 );
373 if (EFI_ERROR (Status)) {
374 goto ON_EXIT;
375 }
376
377 Status = gBS->OpenProtocol (
378 Dhcp4Handle,
379 &gEfiDhcp4ProtocolGuid,
380 (VOID **) &Dhcp4,
381 Image,
382 Controller,
383 EFI_OPEN_PROTOCOL_BY_DRIVER
384 );
385 if (EFI_ERROR (Status)) {
386 goto ON_EXIT;
387 }
388
389 //
390 // Get Ip4Config2 instance info.
391 //
392 Status = gBS->HandleProtocol (Controller, &gEfiIp4Config2ProtocolGuid, (VOID **) &Ip4Config2);
393 if (EFI_ERROR (Status)) {
394 goto ON_EXIT;
395 }
396
397 Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeInterfaceInfo, &DataSize, Data);
398 if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
399 goto ON_EXIT;
400 }
401
402 Data = AllocateZeroPool (DataSize);
403 if (Data == NULL) {
404 Status = EFI_OUT_OF_RESOURCES;
405 goto ON_EXIT;
406 }
407
408 Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeInterfaceInfo, &DataSize, Data);
409 if (EFI_ERROR (Status)) {
410 goto ON_EXIT;
411 }
412
413 InterfaceInfo = (EFI_IP4_CONFIG2_INTERFACE_INFO *)Data;
414
415 //
416 // Build required Token.
417 //
418 Status = gBS->CreateEvent (
419 EVT_NOTIFY_SIGNAL,
420 TPL_NOTIFY,
421 DhcpCommonNotify,
422 &IsDone,
423 &Token.CompletionEvent
424 );
425 if (EFI_ERROR (Status)) {
426 goto ON_EXIT;
427 }
428
429 SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff);
430
431 Token.RemotePort = 67;
432
433 Token.ListenPointCount = 1;
434
435 Token.ListenPoints = AllocateZeroPool (Token.ListenPointCount * sizeof (EFI_DHCP4_LISTEN_POINT));
436 if (Token.ListenPoints == NULL) {
437 Status = EFI_OUT_OF_RESOURCES;
438 goto ON_EXIT;
439 }
440
441 if (Instance->Dns4CfgData.UseDefaultSetting) {
442 CopyMem (&(Token.ListenPoints[0].ListenAddress), &(InterfaceInfo->StationAddress), sizeof (EFI_IPv4_ADDRESS));
443 CopyMem (&(Token.ListenPoints[0].SubnetMask), &(InterfaceInfo->SubnetMask), sizeof (EFI_IPv4_ADDRESS));
444 } else {
445 CopyMem (&(Token.ListenPoints[0].ListenAddress), &(Instance->Dns4CfgData.StationIp), sizeof (EFI_IPv4_ADDRESS));
446 CopyMem (&(Token.ListenPoints[0].SubnetMask), &(Instance->Dns4CfgData.SubnetMask), sizeof (EFI_IPv4_ADDRESS));
447 }
448
449 Token.ListenPoints[0].ListenPort = 68;
450
451 Token.TimeoutValue = DNS_TIME_TO_GETMAP;
452
453 DnsInitSeedPacket (&SeedPacket, InterfaceInfo);
454
455 ParaList[0] = AllocateZeroPool (sizeof (EFI_DHCP4_PACKET_OPTION));
456 if (ParaList[0] == NULL) {
457 Status = EFI_OUT_OF_RESOURCES;
458 goto ON_EXIT;
459 }
460
461 ParaList[0]->OpCode = DHCP4_TAG_TYPE;
462 ParaList[0]->Length = 1;
463 ParaList[0]->Data[0] = DHCP4_MSG_INFORM;
464
465 ParaList[1] = AllocateZeroPool (sizeof (EFI_DHCP4_PACKET_OPTION));
466 if (ParaList[1] == NULL) {
467 Status = EFI_OUT_OF_RESOURCES;
468 goto ON_EXIT;
469 }
470
471 ParaList[1]->OpCode = DHCP4_TAG_PARA_LIST;
472 ParaList[1]->Length = 1;
473 ParaList[1]->Data[0] = DHCP4_TAG_DNS_SERVER;
474
475 Status = Dhcp4->Build (Dhcp4, &SeedPacket, 0, NULL, 2, ParaList, &Token.Packet);
476
477 Token.Packet->Dhcp4.Header.Xid = HTONL(NET_RANDOM (NetRandomInitSeed ()));
478
479 Token.Packet->Dhcp4.Header.Reserved = HTONS ((UINT16)0x8000);
480
481 if (Instance->Dns4CfgData.UseDefaultSetting) {
482 CopyMem (&(Token.Packet->Dhcp4.Header.ClientAddr), &(InterfaceInfo->StationAddress), sizeof (EFI_IPv4_ADDRESS));
483 } else {
484 CopyMem (&(Token.Packet->Dhcp4.Header.ClientAddr), &(Instance->Dns4CfgData.StationIp), sizeof (EFI_IPv4_ADDRESS));
485 }
486
487 CopyMem (Token.Packet->Dhcp4.Header.ClientHwAddr, &(InterfaceInfo->HwAddress), InterfaceInfo->HwAddressSize);
488
489 Token.Packet->Dhcp4.Header.HwAddrLen = (UINT8)(InterfaceInfo->HwAddressSize);
490
491 //
492 // TransmitReceive Token
493 //
494 Status = Dhcp4->TransmitReceive (Dhcp4, &Token);
495 if (EFI_ERROR (Status)) {
496 goto ON_EXIT;
497 }
498
499 //
500 // Poll the packet
501 //
502 do {
503 Status = Mnp->Poll (Mnp);
504 } while (!IsDone);
505
506 //
507 // Parse the ACK to get required information if received done.
508 //
509 if (IsDone && !EFI_ERROR (Token.Status)) {
510 for (Index = 0; Index < Token.ResponseCount; Index++) {
511 Status = ParseDhcp4Ack (Dhcp4, &Token.ResponseList[Index], &DnsServerInfor);
512 if (!EFI_ERROR (Status)) {
513 break;
514 }
515 }
516
517 *DnsServerList = DnsServerInfor.ServerList;
518 } else {
519 Status = Token.Status;
520 }
521
522 ON_EXIT:
523
524 if (Data != NULL) {
525 FreePool (Data);
526 }
527
528 for (Index = 0; Index < 2; Index++) {
529 if (ParaList[Index] != NULL) {
530 FreePool (ParaList[Index]);
531 }
532 }
533
534 if (Token.ListenPoints) {
535 FreePool (Token.ListenPoints);
536 }
537
538 if (Token.Packet) {
539 FreePool (Token.Packet);
540 }
541
542 if (Token.ResponseList != NULL) {
543 FreePool (Token.ResponseList);
544 }
545
546 if (Token.CompletionEvent != NULL) {
547 gBS->CloseEvent (Token.CompletionEvent);
548 }
549
550 if (Dhcp4 != NULL) {
551 Dhcp4->Stop (Dhcp4);
552 Dhcp4->Configure (Dhcp4, NULL);
553
554 gBS->CloseProtocol (
555 Dhcp4Handle,
556 &gEfiDhcp4ProtocolGuid,
557 Image,
558 Controller
559 );
560 }
561
562 if (Dhcp4Handle != NULL) {
563 NetLibDestroyServiceChild (
564 Controller,
565 Image,
566 &gEfiDhcp4ServiceBindingProtocolGuid,
567 Dhcp4Handle
568 );
569 }
570
571 if (Mnp != NULL) {
572 Mnp->Configure (Mnp, NULL);
573
574 gBS->CloseProtocol (
575 MnpChildHandle,
576 &gEfiManagedNetworkProtocolGuid,
577 Image,
578 Controller
579 );
580 }
581
582 NetLibDestroyServiceChild (
583 Controller,
584 Image,
585 &gEfiManagedNetworkServiceBindingProtocolGuid,
586 MnpChildHandle
587 );
588
589 return Status;
590 }
591
592 /**
593 Parse the DHCP ACK to get Dns6 server information.
594
595 @param Image The handle of the driver image.
596 @param Controller The handle of the controller.
597 @param DnsServerCount Retrieved Dns6 server Ip count.
598 @param DnsServerList Retrieved Dns6 server Ip list.
599
600 @retval EFI_SUCCESS The Dns6 information is got from the DHCP ACK.
601 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
602 @retval EFI_NO_MEDIA There was a media error.
603 @retval Others Other errors as indicated.
604
605 **/
606 EFI_STATUS
607 GetDns6ServerFromDhcp6 (
608 IN EFI_HANDLE Image,
609 IN EFI_HANDLE Controller,
610 OUT UINT32 *DnsServerCount,
611 OUT EFI_IPv6_ADDRESS **DnsServerList
612 )
613 {
614 EFI_HANDLE Dhcp6Handle;
615 EFI_DHCP6_PROTOCOL *Dhcp6;
616 EFI_STATUS Status;
617 EFI_STATUS TimerStatus;
618 EFI_DHCP6_PACKET_OPTION *Oro;
619 EFI_DHCP6_RETRANSMISSION InfoReqReXmit;
620 EFI_EVENT Timer;
621 BOOLEAN MediaPresent;
622 DNS6_SERVER_INFOR DnsServerInfor;
623
624 Dhcp6Handle = NULL;
625 Dhcp6 = NULL;
626 Oro = NULL;
627 Timer = NULL;
628
629 ZeroMem (&DnsServerInfor, sizeof (DNS6_SERVER_INFOR));
630
631 DnsServerInfor.ServerCount = DnsServerCount;
632
633 //
634 // Check media status before doing DHCP.
635 //
636 MediaPresent = TRUE;
637 NetLibDetectMedia (Controller, &MediaPresent);
638 if (!MediaPresent) {
639 return EFI_NO_MEDIA;
640 }
641
642 //
643 // Create a DHCP6 child instance and get the protocol.
644 //
645 Status = NetLibCreateServiceChild (
646 Controller,
647 Image,
648 &gEfiDhcp6ServiceBindingProtocolGuid,
649 &Dhcp6Handle
650 );
651 if (EFI_ERROR (Status)) {
652 return Status;
653 }
654
655 Status = gBS->OpenProtocol (
656 Dhcp6Handle,
657 &gEfiDhcp6ProtocolGuid,
658 (VOID **) &Dhcp6,
659 Image,
660 Controller,
661 EFI_OPEN_PROTOCOL_BY_DRIVER
662 );
663 if (EFI_ERROR (Status)) {
664 goto ON_EXIT;
665 }
666
667 Oro = AllocateZeroPool (sizeof (EFI_DHCP6_PACKET_OPTION) + 1);
668 if (Oro == NULL) {
669 Status = EFI_OUT_OF_RESOURCES;
670 goto ON_EXIT;
671 }
672
673 //
674 // Ask the server to reply with DNS options.
675 // All members in EFI_DHCP6_PACKET_OPTION are in network order.
676 //
677 Oro->OpCode = HTONS (DHCP6_TAG_DNS_REQUEST);
678 Oro->OpLen = HTONS (2);
679 Oro->Data[1] = DHCP6_TAG_DNS_SERVER;
680
681 InfoReqReXmit.Irt = 4;
682 InfoReqReXmit.Mrc = 1;
683 InfoReqReXmit.Mrt = 10;
684 InfoReqReXmit.Mrd = 30;
685
686 Status = Dhcp6->InfoRequest (
687 Dhcp6,
688 TRUE,
689 Oro,
690 0,
691 NULL,
692 &InfoReqReXmit,
693 NULL,
694 ParseDhcp6Ack,
695 &DnsServerInfor
696 );
697 if (Status == EFI_NO_MAPPING) {
698 Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);
699 if (EFI_ERROR (Status)) {
700 goto ON_EXIT;
701 }
702
703 Status = gBS->SetTimer (
704 Timer,
705 TimerRelative,
706 DNS_TIME_TO_GETMAP * TICKS_PER_SECOND
707 );
708
709 if (EFI_ERROR (Status)) {
710 goto ON_EXIT;
711 }
712
713 do {
714 TimerStatus = gBS->CheckEvent (Timer);
715 if (!EFI_ERROR (TimerStatus)) {
716 Status = Dhcp6->InfoRequest (
717 Dhcp6,
718 TRUE,
719 Oro,
720 0,
721 NULL,
722 &InfoReqReXmit,
723 NULL,
724 ParseDhcp6Ack,
725 &DnsServerInfor
726 );
727 }
728 } while (TimerStatus == EFI_NOT_READY);
729 }
730
731 *DnsServerList = DnsServerInfor.ServerList;
732
733 ON_EXIT:
734
735 if (Oro != NULL) {
736 FreePool (Oro);
737 }
738
739 if (Timer != NULL) {
740 gBS->CloseEvent (Timer);
741 }
742
743 if (Dhcp6 != NULL) {
744 gBS->CloseProtocol (
745 Dhcp6Handle,
746 &gEfiDhcp6ProtocolGuid,
747 Image,
748 Controller
749 );
750 }
751
752 NetLibDestroyServiceChild (
753 Controller,
754 Image,
755 &gEfiDhcp6ServiceBindingProtocolGuid,
756 Dhcp6Handle
757 );
758
759 return Status;
760
761 }
762