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