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