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