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