]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/DnsDxe/DnsDhcp.c
NetworkPkg: Fix issue in dns driver when building DHCP packet.
[mirror_edk2.git] / NetworkPkg / DnsDxe / DnsDhcp.c
1 /** @file
2 Functions implementation related with DHCPv4/v6 for DNS driver.
3
4 Copyright (c) 2015 - 2017, 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 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 ((UINT8 *) ParaList, sizeof (ParaList));
305
306 ZeroMem (&MnpConfigData, sizeof (EFI_MANAGED_NETWORK_CONFIG_DATA));
307
308 ZeroMem (&DnsServerInfor, sizeof (DNS4_SERVER_INFOR));
309
310 ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN));
311
312 DnsServerInfor.ServerCount = DnsServerCount;
313
314 IsDone = FALSE;
315
316 //
317 // Check media.
318 //
319 MediaPresent = TRUE;
320 NetLibDetectMedia (Controller, &MediaPresent);
321 if (!MediaPresent) {
322 return EFI_NO_MEDIA;
323 }
324
325 //
326 // Create a Mnp child instance, get the protocol and config for it.
327 //
328 Status = NetLibCreateServiceChild (
329 Controller,
330 Image,
331 &gEfiManagedNetworkServiceBindingProtocolGuid,
332 &MnpChildHandle
333 );
334 if (EFI_ERROR (Status)) {
335 return Status;
336 }
337
338 Status = gBS->OpenProtocol (
339 MnpChildHandle,
340 &gEfiManagedNetworkProtocolGuid,
341 (VOID **) &Mnp,
342 Image,
343 Controller,
344 EFI_OPEN_PROTOCOL_BY_DRIVER
345 );
346 if (EFI_ERROR (Status)) {
347 goto ON_EXIT;
348 }
349
350 MnpConfigData.ReceivedQueueTimeoutValue = 0;
351 MnpConfigData.TransmitQueueTimeoutValue = 0;
352 MnpConfigData.ProtocolTypeFilter = IP4_ETHER_PROTO;
353 MnpConfigData.EnableUnicastReceive = TRUE;
354 MnpConfigData.EnableMulticastReceive = TRUE;
355 MnpConfigData.EnableBroadcastReceive = TRUE;
356 MnpConfigData.EnablePromiscuousReceive = FALSE;
357 MnpConfigData.FlushQueuesOnReset = TRUE;
358 MnpConfigData.EnableReceiveTimestamps = FALSE;
359 MnpConfigData.DisableBackgroundPolling = FALSE;
360
361 Status = Mnp->Configure(Mnp, &MnpConfigData);
362 if (EFI_ERROR (Status)) {
363 goto ON_EXIT;
364 }
365
366 //
367 // Create a DHCP4 child instance and get the protocol.
368 //
369 Status = NetLibCreateServiceChild (
370 Controller,
371 Image,
372 &gEfiDhcp4ServiceBindingProtocolGuid,
373 &Dhcp4Handle
374 );
375 if (EFI_ERROR (Status)) {
376 goto ON_EXIT;
377 }
378
379 Status = gBS->OpenProtocol (
380 Dhcp4Handle,
381 &gEfiDhcp4ProtocolGuid,
382 (VOID **) &Dhcp4,
383 Image,
384 Controller,
385 EFI_OPEN_PROTOCOL_BY_DRIVER
386 );
387 if (EFI_ERROR (Status)) {
388 goto ON_EXIT;
389 }
390
391 //
392 // Get Ip4Config2 instance info.
393 //
394 Status = gBS->HandleProtocol (Controller, &gEfiIp4Config2ProtocolGuid, (VOID **) &Ip4Config2);
395 if (EFI_ERROR (Status)) {
396 goto ON_EXIT;
397 }
398
399 Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeInterfaceInfo, &DataSize, Data);
400 if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
401 goto ON_EXIT;
402 }
403
404 Data = AllocateZeroPool (DataSize);
405 if (Data == NULL) {
406 Status = EFI_OUT_OF_RESOURCES;
407 goto ON_EXIT;
408 }
409
410 Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeInterfaceInfo, &DataSize, Data);
411 if (EFI_ERROR (Status)) {
412 goto ON_EXIT;
413 }
414
415 InterfaceInfo = (EFI_IP4_CONFIG2_INTERFACE_INFO *)Data;
416
417 //
418 // Build required Token.
419 //
420 Status = gBS->CreateEvent (
421 EVT_NOTIFY_SIGNAL,
422 TPL_NOTIFY,
423 DhcpCommonNotify,
424 &IsDone,
425 &Token.CompletionEvent
426 );
427 if (EFI_ERROR (Status)) {
428 goto ON_EXIT;
429 }
430
431 SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff);
432
433 Token.RemotePort = 67;
434
435 Token.ListenPointCount = 1;
436
437 Token.ListenPoints = AllocateZeroPool (Token.ListenPointCount * sizeof (EFI_DHCP4_LISTEN_POINT));
438 if (Token.ListenPoints == NULL) {
439 Status = EFI_OUT_OF_RESOURCES;
440 goto ON_EXIT;
441 }
442
443 if (Instance->Dns4CfgData.UseDefaultSetting) {
444 CopyMem (&(Token.ListenPoints[0].ListenAddress), &(InterfaceInfo->StationAddress), sizeof (EFI_IPv4_ADDRESS));
445 CopyMem (&(Token.ListenPoints[0].SubnetMask), &(InterfaceInfo->SubnetMask), sizeof (EFI_IPv4_ADDRESS));
446 } else {
447 CopyMem (&(Token.ListenPoints[0].ListenAddress), &(Instance->Dns4CfgData.StationIp), sizeof (EFI_IPv4_ADDRESS));
448 CopyMem (&(Token.ListenPoints[0].SubnetMask), &(Instance->Dns4CfgData.SubnetMask), sizeof (EFI_IPv4_ADDRESS));
449 }
450
451 Token.ListenPoints[0].ListenPort = 68;
452
453 Token.TimeoutValue = DNS_TIME_TO_GETMAP;
454
455 DnsInitSeedPacket (&SeedPacket, InterfaceInfo);
456
457 ParaList[0] = AllocateZeroPool (sizeof (EFI_DHCP4_PACKET_OPTION));
458 if (ParaList[0] == NULL) {
459 Status = EFI_OUT_OF_RESOURCES;
460 goto ON_EXIT;
461 }
462
463 ParaList[0]->OpCode = DHCP4_TAG_TYPE;
464 ParaList[0]->Length = 1;
465 ParaList[0]->Data[0] = DHCP4_MSG_REQUEST;
466
467 ParaList[1] = AllocateZeroPool (sizeof (EFI_DHCP4_PACKET_OPTION));
468 if (ParaList[1] == NULL) {
469 Status = EFI_OUT_OF_RESOURCES;
470 goto ON_EXIT;
471 }
472
473 ParaList[1]->OpCode = DHCP4_TAG_PARA_LIST;
474 ParaList[1]->Length = 1;
475 ParaList[1]->Data[0] = DHCP4_TAG_DNS_SERVER;
476
477 Status = Dhcp4->Build (Dhcp4, &SeedPacket, 0, NULL, 2, ParaList, &Token.Packet);
478
479 Token.Packet->Dhcp4.Header.Xid = HTONL(NET_RANDOM (NetRandomInitSeed ()));
480
481 Token.Packet->Dhcp4.Header.Reserved = HTONS ((UINT16)0x8000);
482
483 if (Instance->Dns4CfgData.UseDefaultSetting) {
484 CopyMem (&(Token.Packet->Dhcp4.Header.ClientAddr), &(InterfaceInfo->StationAddress), sizeof (EFI_IPv4_ADDRESS));
485 } else {
486 CopyMem (&(Token.Packet->Dhcp4.Header.ClientAddr), &(Instance->Dns4CfgData.StationIp), sizeof (EFI_IPv4_ADDRESS));
487 }
488
489 CopyMem (Token.Packet->Dhcp4.Header.ClientHwAddr, &(InterfaceInfo->HwAddress), InterfaceInfo->HwAddressSize);
490
491 Token.Packet->Dhcp4.Header.HwAddrLen = (UINT8)(InterfaceInfo->HwAddressSize);
492
493 //
494 // TransmitReceive Token
495 //
496 Status = Dhcp4->TransmitReceive (Dhcp4, &Token);
497 if (EFI_ERROR (Status)) {
498 goto ON_EXIT;
499 }
500
501 //
502 // Poll the packet
503 //
504 do {
505 Status = Mnp->Poll (Mnp);
506 } while (!IsDone);
507
508 //
509 // Parse the ACK to get required information if received done.
510 //
511 if (IsDone && !EFI_ERROR (Token.Status)) {
512 for (Index = 0; Index < Token.ResponseCount; Index++) {
513 Status = ParseDhcp4Ack (Dhcp4, &Token.ResponseList[Index], &DnsServerInfor);
514 if (!EFI_ERROR (Status)) {
515 break;
516 }
517 }
518
519 *DnsServerList = DnsServerInfor.ServerList;
520 } else {
521 Status = Token.Status;
522 }
523
524 ON_EXIT:
525
526 if (Data != NULL) {
527 FreePool (Data);
528 }
529
530 for (Index = 0; Index < 2; Index++) {
531 if (ParaList[Index] != NULL) {
532 FreePool (ParaList[Index]);
533 }
534 }
535
536 if (Token.ListenPoints) {
537 FreePool (Token.ListenPoints);
538 }
539
540 if (Token.Packet) {
541 FreePool (Token.Packet);
542 }
543
544 if (Token.ResponseList != NULL) {
545 FreePool (Token.ResponseList);
546 }
547
548 if (Token.CompletionEvent != NULL) {
549 gBS->CloseEvent (Token.CompletionEvent);
550 }
551
552 if (Dhcp4 != NULL) {
553 Dhcp4->Stop (Dhcp4);
554 Dhcp4->Configure (Dhcp4, NULL);
555
556 gBS->CloseProtocol (
557 Dhcp4Handle,
558 &gEfiDhcp4ProtocolGuid,
559 Image,
560 Controller
561 );
562 }
563
564 if (Dhcp4Handle != NULL) {
565 NetLibDestroyServiceChild (
566 Controller,
567 Image,
568 &gEfiDhcp4ServiceBindingProtocolGuid,
569 Dhcp4Handle
570 );
571 }
572
573 if (Mnp != NULL) {
574 Mnp->Configure (Mnp, NULL);
575
576 gBS->CloseProtocol (
577 MnpChildHandle,
578 &gEfiManagedNetworkProtocolGuid,
579 Image,
580 Controller
581 );
582 }
583
584 NetLibDestroyServiceChild (
585 Controller,
586 Image,
587 &gEfiManagedNetworkServiceBindingProtocolGuid,
588 MnpChildHandle
589 );
590
591 return Status;
592 }
593
594 /**
595 Parse the DHCP ACK to get Dns6 server information.
596
597 @param Image The handle of the driver image.
598 @param Controller The handle of the controller.
599 @param DnsServerCount Retrieved Dns6 server Ip count.
600 @param DnsServerList Retrieved Dns6 server Ip list.
601
602 @retval EFI_SUCCESS The Dns6 information is got from the DHCP ACK.
603 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
604 @retval EFI_NO_MEDIA There was a media error.
605 @retval Others Other errors as indicated.
606
607 **/
608 EFI_STATUS
609 GetDns6ServerFromDhcp6 (
610 IN EFI_HANDLE Image,
611 IN EFI_HANDLE Controller,
612 OUT UINT32 *DnsServerCount,
613 OUT EFI_IPv6_ADDRESS **DnsServerList
614 )
615 {
616 EFI_HANDLE Dhcp6Handle;
617 EFI_DHCP6_PROTOCOL *Dhcp6;
618 EFI_STATUS Status;
619 EFI_STATUS TimerStatus;
620 EFI_DHCP6_PACKET_OPTION *Oro;
621 EFI_DHCP6_RETRANSMISSION InfoReqReXmit;
622 EFI_EVENT Timer;
623 BOOLEAN MediaPresent;
624 DNS6_SERVER_INFOR DnsServerInfor;
625
626 Dhcp6Handle = NULL;
627 Dhcp6 = NULL;
628 Oro = NULL;
629 Timer = NULL;
630
631 ZeroMem (&DnsServerInfor, sizeof (DNS6_SERVER_INFOR));
632
633 DnsServerInfor.ServerCount = DnsServerCount;
634
635 //
636 // Check media status before doing DHCP.
637 //
638 MediaPresent = TRUE;
639 NetLibDetectMedia (Controller, &MediaPresent);
640 if (!MediaPresent) {
641 return EFI_NO_MEDIA;
642 }
643
644 //
645 // Create a DHCP6 child instance and get the protocol.
646 //
647 Status = NetLibCreateServiceChild (
648 Controller,
649 Image,
650 &gEfiDhcp6ServiceBindingProtocolGuid,
651 &Dhcp6Handle
652 );
653 if (EFI_ERROR (Status)) {
654 return Status;
655 }
656
657 Status = gBS->OpenProtocol (
658 Dhcp6Handle,
659 &gEfiDhcp6ProtocolGuid,
660 (VOID **) &Dhcp6,
661 Image,
662 Controller,
663 EFI_OPEN_PROTOCOL_BY_DRIVER
664 );
665 if (EFI_ERROR (Status)) {
666 goto ON_EXIT;
667 }
668
669 Oro = AllocateZeroPool (sizeof (EFI_DHCP6_PACKET_OPTION) + 1);
670 if (Oro == NULL) {
671 Status = EFI_OUT_OF_RESOURCES;
672 goto ON_EXIT;
673 }
674
675 //
676 // Ask the server to reply with DNS options.
677 // All members in EFI_DHCP6_PACKET_OPTION are in network order.
678 //
679 Oro->OpCode = HTONS (DHCP6_TAG_DNS_REQUEST);
680 Oro->OpLen = HTONS (2);
681 Oro->Data[1] = DHCP6_TAG_DNS_SERVER;
682
683 InfoReqReXmit.Irt = 4;
684 InfoReqReXmit.Mrc = 1;
685 InfoReqReXmit.Mrt = 10;
686 InfoReqReXmit.Mrd = 30;
687
688 Status = Dhcp6->InfoRequest (
689 Dhcp6,
690 TRUE,
691 Oro,
692 0,
693 NULL,
694 &InfoReqReXmit,
695 NULL,
696 ParseDhcp6Ack,
697 &DnsServerInfor
698 );
699 if (Status == EFI_NO_MAPPING) {
700 Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);
701 if (EFI_ERROR (Status)) {
702 goto ON_EXIT;
703 }
704
705 Status = gBS->SetTimer (
706 Timer,
707 TimerRelative,
708 DNS_TIME_TO_GETMAP * TICKS_PER_SECOND
709 );
710
711 if (EFI_ERROR (Status)) {
712 goto ON_EXIT;
713 }
714
715 do {
716 TimerStatus = gBS->CheckEvent (Timer);
717 if (!EFI_ERROR (TimerStatus)) {
718 Status = Dhcp6->InfoRequest (
719 Dhcp6,
720 TRUE,
721 Oro,
722 0,
723 NULL,
724 &InfoReqReXmit,
725 NULL,
726 ParseDhcp6Ack,
727 &DnsServerInfor
728 );
729 }
730 } while (TimerStatus == EFI_NOT_READY);
731 }
732
733 *DnsServerList = DnsServerInfor.ServerList;
734
735 ON_EXIT:
736
737 if (Oro != NULL) {
738 FreePool (Oro);
739 }
740
741 if (Timer != NULL) {
742 gBS->CloseEvent (Timer);
743 }
744
745 if (Dhcp6 != NULL) {
746 gBS->CloseProtocol (
747 Dhcp6Handle,
748 &gEfiDhcp6ProtocolGuid,
749 Image,
750 Controller
751 );
752 }
753
754 NetLibDestroyServiceChild (
755 Controller,
756 Image,
757 &gEfiDhcp6ServiceBindingProtocolGuid,
758 Dhcp6Handle
759 );
760
761 return Status;
762
763 }
764