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