2 Functions implementation related with DHCPv4/v6 for DNS driver.
4 Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
12 This function initialize the DHCP4 message instance.
14 This function will pad each item of dhcp4 message packet.
16 @param Seed Pointer to the message instance of the DHCP4 packet.
17 @param InterfaceInfo Pointer to the EFI_IP4_CONFIG2_INTERFACE_INFO instance.
22 OUT EFI_DHCP4_PACKET
*Seed
,
23 IN EFI_IP4_CONFIG2_INTERFACE_INFO
*InterfaceInfo
26 EFI_DHCP4_HEADER
*Header
;
29 // Get IfType and HwAddressSize from SNP mode data.
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
);
40 Seed
->Dhcp4
.Magik
= DHCP4_MAGIC
;
41 Seed
->Dhcp4
.Option
[0] = DHCP4_TAG_EOP
;
45 The common notify function.
47 @param[in] Event The event signaled.
48 @param[in] Context The context.
58 if ((Event
== NULL
) || (Context
== NULL
)) {
62 *((BOOLEAN
*)Context
) = TRUE
;
66 Parse the ACK to get required information
68 @param Dhcp4 The DHCP4 protocol.
69 @param Packet Packet waiting for parse.
70 @param DnsServerInfor The required Dns4 server information.
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.
80 IN EFI_DHCP4_PROTOCOL
*Dhcp4
,
81 IN EFI_DHCP4_PACKET
*Packet
,
82 IN DNS4_SERVER_INFOR
*DnsServerInfor
87 EFI_DHCP4_PACKET_OPTION
**OptionList
;
89 EFI_IPv4_ADDRESS
*ServerList
;
99 Status
= Dhcp4
->Parse (Dhcp4
, Packet
, &OptionCount
, OptionList
);
100 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
101 return EFI_DEVICE_ERROR
;
104 OptionList
= AllocatePool (OptionCount
* sizeof (EFI_DHCP4_PACKET_OPTION
*));
105 if (OptionList
== NULL
) {
106 return EFI_OUT_OF_RESOURCES
;
109 Status
= Dhcp4
->Parse (Dhcp4
, Packet
, &OptionCount
, OptionList
);
110 if (EFI_ERROR (Status
)) {
111 gBS
->FreePool (OptionList
);
112 return EFI_DEVICE_ERROR
;
115 Status
= EFI_NOT_FOUND
;
117 for (Index
= 0; Index
< OptionCount
; Index
++) {
119 // Get DNS server addresses
121 if (OptionList
[Index
]->OpCode
== DHCP4_TAG_DNS_SERVER
) {
122 if (((OptionList
[Index
]->Length
& 0x3) != 0) || (OptionList
[Index
]->Length
== 0)) {
123 Status
= EFI_DEVICE_ERROR
;
127 ServerCount
= OptionList
[Index
]->Length
/4;
128 ServerList
= AllocatePool (ServerCount
* sizeof (EFI_IPv4_ADDRESS
));
129 if (ServerList
== NULL
) {
130 return EFI_OUT_OF_RESOURCES
;
133 for (Count
= 0; Count
< ServerCount
; Count
++) {
134 CopyMem (ServerList
+ Count
, &OptionList
[Index
]->Data
[4 * Count
], sizeof (EFI_IPv4_ADDRESS
));
137 *(DnsServerInfor
->ServerCount
) = ServerCount
;
138 DnsServerInfor
->ServerList
= ServerList
;
140 Status
= EFI_SUCCESS
;
144 gBS
->FreePool (OptionList
);
150 EFI_DHCP6_INFO_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol
151 instance to intercept events that occurs in the DHCPv6 Information Request
154 @param This Pointer to the EFI_DHCP6_PROTOCOL instance that
155 is used to configure this callback function.
156 @param Context Pointer to the context that is initialized in
157 the EFI_DHCP6_PROTOCOL.InfoRequest().
158 @param Packet Pointer to Reply packet that has been received.
159 The EFI DHCPv6 Protocol instance is responsible
160 for freeing the buffer.
162 @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.
163 @retval EFI_DEVICE_ERROR Other errors as indicated.
164 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
169 IN EFI_DHCP6_PROTOCOL
*This
,
171 IN EFI_DHCP6_PACKET
*Packet
176 EFI_DHCP6_PACKET_OPTION
**OptionList
;
177 DNS6_SERVER_INFOR
*DnsServerInfor
;
179 EFI_IPv6_ADDRESS
*ServerList
;
187 Status
= This
->Parse (This
, Packet
, &OptionCount
, NULL
);
188 if (Status
!= EFI_BUFFER_TOO_SMALL
) {
189 return EFI_DEVICE_ERROR
;
192 OptionList
= AllocateZeroPool (OptionCount
* sizeof (EFI_DHCP6_PACKET_OPTION
*));
193 if (OptionList
== NULL
) {
194 return EFI_OUT_OF_RESOURCES
;
197 Status
= This
->Parse (This
, Packet
, &OptionCount
, OptionList
);
198 if (EFI_ERROR (Status
)) {
199 gBS
->FreePool (OptionList
);
200 return EFI_DEVICE_ERROR
;
203 DnsServerInfor
= (DNS6_SERVER_INFOR
*)Context
;
205 for (Index
= 0; Index
< OptionCount
; Index
++) {
206 OptionList
[Index
]->OpCode
= NTOHS (OptionList
[Index
]->OpCode
);
207 OptionList
[Index
]->OpLen
= NTOHS (OptionList
[Index
]->OpLen
);
210 // Get DNS server addresses from this reply packet.
212 if (OptionList
[Index
]->OpCode
== DHCP6_TAG_DNS_SERVER
) {
213 if (((OptionList
[Index
]->OpLen
& 0xf) != 0) || (OptionList
[Index
]->OpLen
== 0)) {
214 Status
= EFI_DEVICE_ERROR
;
215 gBS
->FreePool (OptionList
);
219 ServerCount
= OptionList
[Index
]->OpLen
/16;
220 ServerList
= AllocatePool (ServerCount
* sizeof (EFI_IPv6_ADDRESS
));
221 if (ServerList
== NULL
) {
222 gBS
->FreePool (OptionList
);
223 return EFI_OUT_OF_RESOURCES
;
226 for (Count
= 0; Count
< ServerCount
; Count
++) {
227 CopyMem (ServerList
+ Count
, &OptionList
[Index
]->Data
[16 * Count
], sizeof (EFI_IPv6_ADDRESS
));
230 *(DnsServerInfor
->ServerCount
) = ServerCount
;
231 DnsServerInfor
->ServerList
= ServerList
;
235 gBS
->FreePool (OptionList
);
241 Parse the DHCP ACK to get Dns4 server information.
243 @param Instance The DNS instance.
244 @param DnsServerCount Retrieved Dns4 server Ip count.
245 @param DnsServerList Retrieved Dns4 server Ip list.
247 @retval EFI_SUCCESS The Dns4 information is got from the DHCP ACK.
248 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
249 @retval EFI_NO_MEDIA There was a media error.
250 @retval Others Other errors as indicated.
254 GetDns4ServerFromDhcp4 (
255 IN DNS_INSTANCE
*Instance
,
256 OUT UINT32
*DnsServerCount
,
257 OUT EFI_IPv4_ADDRESS
**DnsServerList
262 EFI_HANDLE Controller
;
263 EFI_STATUS MediaStatus
;
264 EFI_HANDLE MnpChildHandle
;
265 EFI_MANAGED_NETWORK_PROTOCOL
*Mnp
;
266 EFI_MANAGED_NETWORK_CONFIG_DATA MnpConfigData
;
267 EFI_HANDLE Dhcp4Handle
;
268 EFI_DHCP4_PROTOCOL
*Dhcp4
;
269 EFI_IP4_CONFIG2_PROTOCOL
*Ip4Config2
;
272 EFI_IP4_CONFIG2_INTERFACE_INFO
*InterfaceInfo
;
273 EFI_DHCP4_PACKET SeedPacket
;
274 EFI_DHCP4_PACKET_OPTION
*ParaList
[2];
275 DNS4_SERVER_INFOR DnsServerInfor
;
277 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token
;
281 Image
= Instance
->Service
->ImageHandle
;
282 Controller
= Instance
->Service
->ControllerHandle
;
284 MnpChildHandle
= NULL
;
293 InterfaceInfo
= NULL
;
295 ZeroMem ((UINT8
*)ParaList
, sizeof (ParaList
));
297 ZeroMem (&MnpConfigData
, sizeof (EFI_MANAGED_NETWORK_CONFIG_DATA
));
299 ZeroMem (&DnsServerInfor
, sizeof (DNS4_SERVER_INFOR
));
301 ZeroMem (&Token
, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN
));
303 DnsServerInfor
.ServerCount
= DnsServerCount
;
310 MediaStatus
= EFI_SUCCESS
;
311 NetLibDetectMediaWaitTimeout (Controller
, DNS_CHECK_MEDIA_GET_DHCP_WAITING_TIME
, &MediaStatus
);
312 if (MediaStatus
!= EFI_SUCCESS
) {
317 // Create a Mnp child instance, get the protocol and config for it.
319 Status
= NetLibCreateServiceChild (
322 &gEfiManagedNetworkServiceBindingProtocolGuid
,
325 if (EFI_ERROR (Status
)) {
329 Status
= gBS
->OpenProtocol (
331 &gEfiManagedNetworkProtocolGuid
,
335 EFI_OPEN_PROTOCOL_BY_DRIVER
337 if (EFI_ERROR (Status
)) {
341 MnpConfigData
.ReceivedQueueTimeoutValue
= 0;
342 MnpConfigData
.TransmitQueueTimeoutValue
= 0;
343 MnpConfigData
.ProtocolTypeFilter
= IP4_ETHER_PROTO
;
344 MnpConfigData
.EnableUnicastReceive
= TRUE
;
345 MnpConfigData
.EnableMulticastReceive
= TRUE
;
346 MnpConfigData
.EnableBroadcastReceive
= TRUE
;
347 MnpConfigData
.EnablePromiscuousReceive
= FALSE
;
348 MnpConfigData
.FlushQueuesOnReset
= TRUE
;
349 MnpConfigData
.EnableReceiveTimestamps
= FALSE
;
350 MnpConfigData
.DisableBackgroundPolling
= FALSE
;
352 Status
= Mnp
->Configure (Mnp
, &MnpConfigData
);
353 if (EFI_ERROR (Status
)) {
358 // Create a DHCP4 child instance and get the protocol.
360 Status
= NetLibCreateServiceChild (
363 &gEfiDhcp4ServiceBindingProtocolGuid
,
366 if (EFI_ERROR (Status
)) {
370 Status
= gBS
->OpenProtocol (
372 &gEfiDhcp4ProtocolGuid
,
376 EFI_OPEN_PROTOCOL_BY_DRIVER
378 if (EFI_ERROR (Status
)) {
383 // Get Ip4Config2 instance info.
385 Status
= gBS
->HandleProtocol (Controller
, &gEfiIp4Config2ProtocolGuid
, (VOID
**)&Ip4Config2
);
386 if (EFI_ERROR (Status
)) {
390 Status
= Ip4Config2
->GetData (Ip4Config2
, Ip4Config2DataTypeInterfaceInfo
, &DataSize
, Data
);
391 if (EFI_ERROR (Status
) && (Status
!= EFI_BUFFER_TOO_SMALL
)) {
395 Data
= AllocateZeroPool (DataSize
);
397 Status
= EFI_OUT_OF_RESOURCES
;
401 Status
= Ip4Config2
->GetData (Ip4Config2
, Ip4Config2DataTypeInterfaceInfo
, &DataSize
, Data
);
402 if (EFI_ERROR (Status
)) {
406 InterfaceInfo
= (EFI_IP4_CONFIG2_INTERFACE_INFO
*)Data
;
409 // Build required Token.
411 Status
= gBS
->CreateEvent (
416 &Token
.CompletionEvent
418 if (EFI_ERROR (Status
)) {
422 SetMem (&Token
.RemoteAddress
, sizeof (EFI_IPv4_ADDRESS
), 0xff);
424 Token
.RemotePort
= 67;
426 Token
.ListenPointCount
= 1;
428 Token
.ListenPoints
= AllocateZeroPool (Token
.ListenPointCount
* sizeof (EFI_DHCP4_LISTEN_POINT
));
429 if (Token
.ListenPoints
== NULL
) {
430 Status
= EFI_OUT_OF_RESOURCES
;
434 if (Instance
->Dns4CfgData
.UseDefaultSetting
) {
435 CopyMem (&(Token
.ListenPoints
[0].ListenAddress
), &(InterfaceInfo
->StationAddress
), sizeof (EFI_IPv4_ADDRESS
));
436 CopyMem (&(Token
.ListenPoints
[0].SubnetMask
), &(InterfaceInfo
->SubnetMask
), sizeof (EFI_IPv4_ADDRESS
));
438 CopyMem (&(Token
.ListenPoints
[0].ListenAddress
), &(Instance
->Dns4CfgData
.StationIp
), sizeof (EFI_IPv4_ADDRESS
));
439 CopyMem (&(Token
.ListenPoints
[0].SubnetMask
), &(Instance
->Dns4CfgData
.SubnetMask
), sizeof (EFI_IPv4_ADDRESS
));
442 Token
.ListenPoints
[0].ListenPort
= 68;
444 Token
.TimeoutValue
= DNS_TIME_TO_GETMAP
;
446 DnsInitSeedPacket (&SeedPacket
, InterfaceInfo
);
448 ParaList
[0] = AllocateZeroPool (sizeof (EFI_DHCP4_PACKET_OPTION
));
449 if (ParaList
[0] == NULL
) {
450 Status
= EFI_OUT_OF_RESOURCES
;
454 ParaList
[0]->OpCode
= DHCP4_TAG_TYPE
;
455 ParaList
[0]->Length
= 1;
456 ParaList
[0]->Data
[0] = DHCP4_MSG_REQUEST
;
458 ParaList
[1] = AllocateZeroPool (sizeof (EFI_DHCP4_PACKET_OPTION
));
459 if (ParaList
[1] == NULL
) {
460 Status
= EFI_OUT_OF_RESOURCES
;
464 ParaList
[1]->OpCode
= DHCP4_TAG_PARA_LIST
;
465 ParaList
[1]->Length
= 1;
466 ParaList
[1]->Data
[0] = DHCP4_TAG_DNS_SERVER
;
468 Status
= Dhcp4
->Build (Dhcp4
, &SeedPacket
, 0, NULL
, 2, ParaList
, &Token
.Packet
);
470 Token
.Packet
->Dhcp4
.Header
.Xid
= HTONL (NET_RANDOM (NetRandomInitSeed ()));
472 Token
.Packet
->Dhcp4
.Header
.Reserved
= HTONS ((UINT16
)0x8000);
474 if (Instance
->Dns4CfgData
.UseDefaultSetting
) {
475 CopyMem (&(Token
.Packet
->Dhcp4
.Header
.ClientAddr
), &(InterfaceInfo
->StationAddress
), sizeof (EFI_IPv4_ADDRESS
));
477 CopyMem (&(Token
.Packet
->Dhcp4
.Header
.ClientAddr
), &(Instance
->Dns4CfgData
.StationIp
), sizeof (EFI_IPv4_ADDRESS
));
480 CopyMem (Token
.Packet
->Dhcp4
.Header
.ClientHwAddr
, &(InterfaceInfo
->HwAddress
), InterfaceInfo
->HwAddressSize
);
482 Token
.Packet
->Dhcp4
.Header
.HwAddrLen
= (UINT8
)(InterfaceInfo
->HwAddressSize
);
485 // TransmitReceive Token
487 Status
= Dhcp4
->TransmitReceive (Dhcp4
, &Token
);
488 if (EFI_ERROR (Status
)) {
496 Status
= Mnp
->Poll (Mnp
);
500 // Parse the ACK to get required information if received done.
502 if (IsDone
&& !EFI_ERROR (Token
.Status
)) {
503 for (Index
= 0; Index
< Token
.ResponseCount
; Index
++) {
504 Status
= ParseDhcp4Ack (Dhcp4
, &Token
.ResponseList
[Index
], &DnsServerInfor
);
505 if (!EFI_ERROR (Status
)) {
510 *DnsServerList
= DnsServerInfor
.ServerList
;
512 Status
= Token
.Status
;
521 for (Index
= 0; Index
< 2; Index
++) {
522 if (ParaList
[Index
] != NULL
) {
523 FreePool (ParaList
[Index
]);
527 if (Token
.ListenPoints
) {
528 FreePool (Token
.ListenPoints
);
532 FreePool (Token
.Packet
);
535 if (Token
.ResponseList
!= NULL
) {
536 FreePool (Token
.ResponseList
);
539 if (Token
.CompletionEvent
!= NULL
) {
540 gBS
->CloseEvent (Token
.CompletionEvent
);
545 Dhcp4
->Configure (Dhcp4
, NULL
);
549 &gEfiDhcp4ProtocolGuid
,
555 if (Dhcp4Handle
!= NULL
) {
556 NetLibDestroyServiceChild (
559 &gEfiDhcp4ServiceBindingProtocolGuid
,
565 Mnp
->Configure (Mnp
, NULL
);
569 &gEfiManagedNetworkProtocolGuid
,
575 NetLibDestroyServiceChild (
578 &gEfiManagedNetworkServiceBindingProtocolGuid
,
586 Parse the DHCP ACK to get Dns6 server information.
588 @param Image The handle of the driver image.
589 @param Controller The handle of the controller.
590 @param DnsServerCount Retrieved Dns6 server Ip count.
591 @param DnsServerList Retrieved Dns6 server Ip list.
593 @retval EFI_SUCCESS The Dns6 information is got from the DHCP ACK.
594 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
595 @retval EFI_NO_MEDIA There was a media error.
596 @retval Others Other errors as indicated.
600 GetDns6ServerFromDhcp6 (
602 IN EFI_HANDLE Controller
,
603 OUT UINT32
*DnsServerCount
,
604 OUT EFI_IPv6_ADDRESS
**DnsServerList
607 EFI_HANDLE Dhcp6Handle
;
608 EFI_DHCP6_PROTOCOL
*Dhcp6
;
610 EFI_STATUS TimerStatus
;
611 EFI_DHCP6_PACKET_OPTION
*Oro
;
612 EFI_DHCP6_RETRANSMISSION InfoReqReXmit
;
614 EFI_STATUS MediaStatus
;
615 DNS6_SERVER_INFOR DnsServerInfor
;
622 ZeroMem (&DnsServerInfor
, sizeof (DNS6_SERVER_INFOR
));
624 DnsServerInfor
.ServerCount
= DnsServerCount
;
627 // Check media status before doing DHCP.
629 MediaStatus
= EFI_SUCCESS
;
630 NetLibDetectMediaWaitTimeout (Controller
, DNS_CHECK_MEDIA_GET_DHCP_WAITING_TIME
, &MediaStatus
);
631 if (MediaStatus
!= EFI_SUCCESS
) {
636 // Create a DHCP6 child instance and get the protocol.
638 Status
= NetLibCreateServiceChild (
641 &gEfiDhcp6ServiceBindingProtocolGuid
,
644 if (EFI_ERROR (Status
)) {
648 Status
= gBS
->OpenProtocol (
650 &gEfiDhcp6ProtocolGuid
,
654 EFI_OPEN_PROTOCOL_BY_DRIVER
656 if (EFI_ERROR (Status
)) {
660 Oro
= AllocateZeroPool (sizeof (EFI_DHCP6_PACKET_OPTION
) + 1);
662 Status
= EFI_OUT_OF_RESOURCES
;
667 // Ask the server to reply with DNS options.
668 // All members in EFI_DHCP6_PACKET_OPTION are in network order.
670 Oro
->OpCode
= HTONS (DHCP6_TAG_DNS_REQUEST
);
671 Oro
->OpLen
= HTONS (2);
672 Oro
->Data
[1] = DHCP6_TAG_DNS_SERVER
;
674 InfoReqReXmit
.Irt
= 4;
675 InfoReqReXmit
.Mrc
= 1;
676 InfoReqReXmit
.Mrt
= 10;
677 InfoReqReXmit
.Mrd
= 30;
679 Status
= Dhcp6
->InfoRequest (
690 if (Status
== EFI_NO_MAPPING
) {
691 Status
= gBS
->CreateEvent (EVT_TIMER
, TPL_CALLBACK
, NULL
, NULL
, &Timer
);
692 if (EFI_ERROR (Status
)) {
696 Status
= gBS
->SetTimer (
699 DNS_TIME_TO_GETMAP
* TICKS_PER_SECOND
702 if (EFI_ERROR (Status
)) {
707 TimerStatus
= gBS
->CheckEvent (Timer
);
708 if (!EFI_ERROR (TimerStatus
)) {
709 Status
= Dhcp6
->InfoRequest (
721 } while (TimerStatus
== EFI_NOT_READY
);
724 *DnsServerList
= DnsServerInfor
.ServerList
;
733 gBS
->CloseEvent (Timer
);
739 &gEfiDhcp6ProtocolGuid
,
745 NetLibDestroyServiceChild (
748 &gEfiDhcp6ServiceBindingProtocolGuid
,