3 Copyright (c) 2006 - 2008, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 This file implement the EFI_DHCP4_PROTOCOL interface.
24 #include "Dhcp4Impl.h"
28 Get the current operation parameter and lease for the network interface.
30 @param This The DHCP protocol instance
31 @param Dhcp4ModeData The variable to save the DHCP mode data.
33 @retval EFI_INVALID_PARAMETER The parameter is invalid
34 @retval EFI_SUCCESS The Dhcp4ModeData is updated with the current
41 IN EFI_DHCP4_PROTOCOL
*This
,
42 OUT EFI_DHCP4_MODE_DATA
*Dhcp4ModeData
45 DHCP_PROTOCOL
*Instance
;
52 // First validate the parameters.
54 if ((This
== NULL
) || (Dhcp4ModeData
== NULL
)) {
55 return EFI_INVALID_PARAMETER
;
58 Instance
= DHCP_INSTANCE_FROM_THIS (This
);
60 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
61 DhcpSb
= Instance
->Service
;
64 // Caller can use GetModeData to retrieve current DHCP states
65 // no matter whether it is the active child or not.
67 Dhcp4ModeData
->State
= (EFI_DHCP4_STATE
) DhcpSb
->DhcpState
;
68 CopyMem (&Dhcp4ModeData
->ConfigData
, &DhcpSb
->ActiveConfig
, sizeof (Dhcp4ModeData
->ConfigData
));
69 CopyMem (&Dhcp4ModeData
->ClientMacAddress
, &DhcpSb
->Mac
, sizeof (Dhcp4ModeData
->ClientMacAddress
));
71 Ip
= HTONL (DhcpSb
->ClientAddr
);
72 CopyMem (&Dhcp4ModeData
->ClientAddress
, &Ip
, sizeof (EFI_IPv4_ADDRESS
));
74 Ip
= HTONL (DhcpSb
->Netmask
);
75 CopyMem (&Dhcp4ModeData
->SubnetMask
, &Ip
, sizeof (EFI_IPv4_ADDRESS
));
77 Ip
= HTONL (DhcpSb
->ServerAddr
);
78 CopyMem (&Dhcp4ModeData
->ServerAddress
, &Ip
, sizeof (EFI_IPv4_ADDRESS
));
83 Ip
= HTONL (Para
->Router
);
84 CopyMem (&Dhcp4ModeData
->RouterAddress
, &Ip
, sizeof (EFI_IPv4_ADDRESS
));
85 Dhcp4ModeData
->LeaseTime
= Para
->Lease
;
87 ZeroMem (&Dhcp4ModeData
->RouterAddress
, sizeof (EFI_IPv4_ADDRESS
));
88 Dhcp4ModeData
->LeaseTime
= 0xffffffff;
91 Dhcp4ModeData
->ReplyPacket
= DhcpSb
->Selected
;
93 gBS
->RestoreTPL (OldTpl
);
99 Free the resource related to the configure parameters.
100 DHCP driver will make a copy of the user's configure
101 such as the time out value.
103 @param Config The DHCP configure data
110 IN EFI_DHCP4_CONFIG_DATA
*Config
115 if (Config
->DiscoverTimeout
!= NULL
) {
116 gBS
->FreePool (Config
->DiscoverTimeout
);
119 if (Config
->RequestTimeout
!= NULL
) {
120 gBS
->FreePool (Config
->RequestTimeout
);
123 if (Config
->OptionList
!= NULL
) {
124 for (Index
= 0; Index
< Config
->OptionCount
; Index
++) {
125 if (Config
->OptionList
[Index
] != NULL
) {
126 gBS
->FreePool (Config
->OptionList
[Index
]);
130 gBS
->FreePool (Config
->OptionList
);
133 ZeroMem (Config
, sizeof (EFI_DHCP4_CONFIG_DATA
));
138 Allocate memory for configure parameter such as timeout value for Dst,
139 then copy the configure parameter from Src to Dst.
141 @param Dst The destination DHCP configure data.
142 @param Src The source DHCP configure data.
144 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
145 @retval EFI_SUCCESS The configure is copied.
150 IN EFI_DHCP4_CONFIG_DATA
*Dst
,
151 IN EFI_DHCP4_CONFIG_DATA
*Src
154 EFI_DHCP4_PACKET_OPTION
**DstOptions
;
155 EFI_DHCP4_PACKET_OPTION
**SrcOptions
;
159 CopyMem (Dst
, Src
, sizeof (*Dst
));
160 Dst
->DiscoverTimeout
= NULL
;
161 Dst
->RequestTimeout
= NULL
;
162 Dst
->OptionList
= NULL
;
165 // Allocate a memory then copy DiscoverTimeout to it
167 if (Src
->DiscoverTimeout
!= NULL
) {
168 Len
= Src
->DiscoverTryCount
* sizeof (UINT32
);
169 Dst
->DiscoverTimeout
= AllocatePool (Len
);
171 if (Dst
->DiscoverTimeout
== NULL
) {
172 return EFI_OUT_OF_RESOURCES
;
175 for (Index
= 0; Index
< Src
->DiscoverTryCount
; Index
++) {
176 Dst
->DiscoverTimeout
[Index
] = MAX (Src
->DiscoverTimeout
[Index
], 1);
181 // Allocate a memory then copy RequestTimeout to it
183 if (Src
->RequestTimeout
!= NULL
) {
184 Len
= Src
->RequestTryCount
* sizeof (UINT32
);
185 Dst
->RequestTimeout
= AllocatePool (Len
);
187 if (Dst
->RequestTimeout
== NULL
) {
191 for (Index
= 0; Index
< Src
->RequestTryCount
; Index
++) {
192 Dst
->RequestTimeout
[Index
] = MAX (Src
->RequestTimeout
[Index
], 1);
197 // Allocate an array of dhcp option point, then allocate memory
198 // for each option and copy the source option to it
200 if (Src
->OptionList
!= NULL
) {
201 Len
= Src
->OptionCount
* sizeof (EFI_DHCP4_PACKET_OPTION
*);
202 Dst
->OptionList
= AllocateZeroPool (Len
);
204 if (Dst
->OptionList
== NULL
) {
208 DstOptions
= Dst
->OptionList
;
209 SrcOptions
= Src
->OptionList
;
211 for (Index
= 0; Index
< Src
->OptionCount
; Index
++) {
212 Len
= sizeof (EFI_DHCP4_PACKET_OPTION
) + MAX (SrcOptions
[Index
]->Length
- 1, 0);
214 DstOptions
[Index
] = AllocatePool (Len
);
216 if (DstOptions
[Index
] == NULL
) {
220 CopyMem (DstOptions
[Index
], SrcOptions
[Index
], Len
);
227 DhcpCleanConfigure (Dst
);
228 return EFI_OUT_OF_RESOURCES
;
233 Give up the control of the DHCP service to let other child
234 resume. Don't change the service's DHCP state and the Client
235 address and option list configure as required by RFC2131.
237 @param DhcpSb The DHCP service instance.
244 IN DHCP_SERVICE
*DhcpSb
247 EFI_DHCP4_CONFIG_DATA
*Config
;
249 Config
= &DhcpSb
->ActiveConfig
;
251 DhcpSb
->ServiceState
= DHCP_UNCONFIGED
;
252 DhcpSb
->ActiveChild
= NULL
;
254 if (Config
->DiscoverTimeout
!= NULL
) {
255 gBS
->FreePool (Config
->DiscoverTimeout
);
257 Config
->DiscoverTryCount
= 0;
258 Config
->DiscoverTimeout
= NULL
;
261 if (Config
->RequestTimeout
!= NULL
) {
262 gBS
->FreePool (Config
->RequestTimeout
);
264 Config
->RequestTryCount
= 0;
265 Config
->RequestTimeout
= NULL
;
268 Config
->Dhcp4Callback
= NULL
;
269 Config
->CallbackContext
= NULL
;
274 Configure the DHCP protocol instance and its underlying DHCP service
275 for operation. If Dhcp4CfgData is NULL and the child is currently
276 controlling the DHCP service, release the control.
278 @param This The DHCP protocol instance
279 @param Dhcp4CfgData The DHCP configure data.
281 @retval EFI_INVALID_PARAMETER The parameters are invalid.
282 @retval EFI_ACCESS_DENIED The service isn't in one of configurable states,
283 or there is already an active child.
284 @retval EFI_OUT_OF_RESOURCE Failed to allocate some resources.
285 @retval EFI_SUCCESS The child is configured.
291 IN EFI_DHCP4_PROTOCOL
*This
,
292 IN EFI_DHCP4_CONFIG_DATA
*Dhcp4CfgData OPTIONAL
295 EFI_DHCP4_CONFIG_DATA
*Config
;
296 DHCP_PROTOCOL
*Instance
;
297 DHCP_SERVICE
*DhcpSb
;
304 // First validate the parameters
307 return EFI_INVALID_PARAMETER
;
310 if (Dhcp4CfgData
!= NULL
) {
311 if (Dhcp4CfgData
->DiscoverTryCount
&& (Dhcp4CfgData
->DiscoverTimeout
== NULL
)) {
312 return EFI_INVALID_PARAMETER
;
315 if (Dhcp4CfgData
->RequestTryCount
&& (Dhcp4CfgData
->RequestTimeout
== NULL
)) {
316 return EFI_INVALID_PARAMETER
;
319 if (Dhcp4CfgData
->OptionCount
&& (Dhcp4CfgData
->OptionList
== NULL
)) {
320 return EFI_INVALID_PARAMETER
;
323 CopyMem (&Ip
, &Dhcp4CfgData
->ClientAddress
, sizeof (IP4_ADDR
));
325 if ((Ip
!= 0) && !Ip4IsUnicast (NTOHL (Ip
), 0)) {
327 return EFI_INVALID_PARAMETER
;
331 Instance
= DHCP_INSTANCE_FROM_THIS (This
);
333 if (Instance
->Signature
!= DHCP_PROTOCOL_SIGNATURE
) {
334 return EFI_INVALID_PARAMETER
;
337 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
339 DhcpSb
= Instance
->Service
;
340 Config
= &DhcpSb
->ActiveConfig
;
342 Status
= EFI_ACCESS_DENIED
;
344 if ((DhcpSb
->DhcpState
!= Dhcp4Stopped
) &&
345 (DhcpSb
->DhcpState
!= Dhcp4Init
) &&
346 (DhcpSb
->DhcpState
!= Dhcp4InitReboot
) &&
347 (DhcpSb
->DhcpState
!= Dhcp4Bound
)) {
352 if ((DhcpSb
->ActiveChild
!= NULL
) && (DhcpSb
->ActiveChild
!= Instance
)) {
356 if (Dhcp4CfgData
!= NULL
) {
357 Status
= EFI_OUT_OF_RESOURCES
;
358 DhcpCleanConfigure (Config
);
360 if (EFI_ERROR (DhcpCopyConfigure (Config
, Dhcp4CfgData
))) {
364 DhcpSb
->UserOptionLen
= 0;
366 for (Index
= 0; Index
< Dhcp4CfgData
->OptionCount
; Index
++) {
367 DhcpSb
->UserOptionLen
+= Dhcp4CfgData
->OptionList
[Index
]->Length
+ 2;
370 DhcpSb
->ActiveChild
= Instance
;
372 if (DhcpSb
->DhcpState
== Dhcp4Stopped
) {
373 DhcpSb
->ClientAddr
= EFI_NTOHL (Dhcp4CfgData
->ClientAddress
);
375 if (DhcpSb
->ClientAddr
!= 0) {
376 DhcpSb
->DhcpState
= Dhcp4InitReboot
;
378 DhcpSb
->DhcpState
= Dhcp4Init
;
382 DhcpSb
->ServiceState
= DHCP_CONFIGED
;
383 Status
= EFI_SUCCESS
;
385 } else if (DhcpSb
->ActiveChild
== Instance
) {
386 Status
= EFI_SUCCESS
;
387 DhcpYieldControl (DhcpSb
);
391 gBS
->RestoreTPL (OldTpl
);
397 Start the DHCP process.
399 @param This The DHCP protocol instance
400 @param CompletionEvent The event to signal is address is acquired.
402 @retval EFI_INVALID_PARAMETER The parameters are invalid.
403 @retval EFI_NOT_STARTED The protocol hasn't been configured.
404 @retval EFI_ALREADY_STARTED The DHCP process has already been started.
405 @retval EFI_SUCCESS The DHCP process is started.
411 IN EFI_DHCP4_PROTOCOL
*This
,
412 IN EFI_EVENT CompletionEvent OPTIONAL
415 DHCP_PROTOCOL
*Instance
;
416 DHCP_SERVICE
*DhcpSb
;
421 // First validate the parameters
424 return EFI_INVALID_PARAMETER
;
427 Instance
= DHCP_INSTANCE_FROM_THIS (This
);
429 if (Instance
->Signature
!= DHCP_PROTOCOL_SIGNATURE
) {
430 return EFI_INVALID_PARAMETER
;
433 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
434 DhcpSb
= Instance
->Service
;
436 if (DhcpSb
->DhcpState
== Dhcp4Stopped
) {
437 Status
= EFI_NOT_STARTED
;
441 if ((DhcpSb
->DhcpState
!= Dhcp4Init
) && (DhcpSb
->DhcpState
!= Dhcp4InitReboot
)) {
442 Status
= EFI_ALREADY_STARTED
;
446 DhcpSb
->IoStatus
= EFI_ALREADY_STARTED
;
448 if (EFI_ERROR (Status
= DhcpInitRequest (DhcpSb
))) {
453 // Start/Restart the receiving.
455 Status
= UdpIoRecvDatagram (DhcpSb
->UdpIo
, DhcpInput
, DhcpSb
, 0);
457 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
461 Instance
->CompletionEvent
= CompletionEvent
;
464 // Restore the TPL now, don't call poll function at TPL_CALLBACK.
466 gBS
->RestoreTPL (OldTpl
);
468 if (CompletionEvent
== NULL
) {
469 while (DhcpSb
->IoStatus
== EFI_ALREADY_STARTED
) {
470 DhcpSb
->UdpIo
->Udp
->Poll (DhcpSb
->UdpIo
->Udp
);
473 return DhcpSb
->IoStatus
;
479 gBS
->RestoreTPL (OldTpl
);
485 Request an extra manual renew/rebind.
487 @param This The DHCP protocol instance
488 @param RebindRequest TRUE if request a rebind, otherwise renew it
489 @param CompletionEvent Event to signal when complete
491 @retval EFI_INVALID_PARAMETER The parameters are invalid
492 @retval EFI_NOT_STARTED The DHCP protocol hasn't been started.
493 @retval EFI_ACCESS_DENIED The DHCP protocol isn't in Bound state.
494 @retval EFI_SUCCESS The DHCP is renewed/rebound.
499 EfiDhcp4RenewRebind (
500 IN EFI_DHCP4_PROTOCOL
*This
,
501 IN BOOLEAN RebindRequest
,
502 IN EFI_EVENT CompletionEvent OPTIONAL
505 DHCP_PROTOCOL
*Instance
;
506 DHCP_SERVICE
*DhcpSb
;
511 // First validate the parameters
514 return EFI_INVALID_PARAMETER
;
517 Instance
= DHCP_INSTANCE_FROM_THIS (This
);
519 if (Instance
->Signature
!= DHCP_PROTOCOL_SIGNATURE
) {
520 return EFI_INVALID_PARAMETER
;
523 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
524 DhcpSb
= Instance
->Service
;
526 if (DhcpSb
->DhcpState
== Dhcp4Stopped
) {
527 Status
= EFI_NOT_STARTED
;
531 if (DhcpSb
->DhcpState
!= Dhcp4Bound
) {
532 Status
= EFI_ACCESS_DENIED
;
536 if (DHCP_IS_BOOTP (DhcpSb
->Para
)) {
541 // Transit the states then send a extra DHCP request
543 if (!RebindRequest
) {
544 DhcpSetState (DhcpSb
, Dhcp4Renewing
, FALSE
);
546 DhcpSetState (DhcpSb
, Dhcp4Rebinding
, FALSE
);
549 Status
= DhcpSendMessage (
554 (UINT8
*) "Extra renew/rebind by the application"
557 if (EFI_ERROR (Status
)) {
558 DhcpSetState (DhcpSb
, Dhcp4Bound
, FALSE
);
562 DhcpSb
->ExtraRefresh
= TRUE
;
563 DhcpSb
->IoStatus
= EFI_ALREADY_STARTED
;
564 Instance
->RenewRebindEvent
= CompletionEvent
;
566 gBS
->RestoreTPL (OldTpl
);
568 if (CompletionEvent
== NULL
) {
569 while (DhcpSb
->IoStatus
== EFI_ALREADY_STARTED
) {
570 DhcpSb
->UdpIo
->Udp
->Poll (DhcpSb
->UdpIo
->Udp
);
573 return DhcpSb
->IoStatus
;
579 gBS
->RestoreTPL (OldTpl
);
585 Release the current acquired lease.
587 @param This The DHCP protocol instance
589 @retval EFI_INVALID_PARAMETER The parameter is invalid
590 @retval EFI_DEVICE_ERROR Failed to transmit the DHCP release packet
591 @retval EFI_ACCESS_DENIED The DHCP service isn't in one of the connected
593 @retval EFI_SUCCESS The lease is released.
599 IN EFI_DHCP4_PROTOCOL
*This
602 DHCP_PROTOCOL
*Instance
;
603 DHCP_SERVICE
*DhcpSb
;
608 // First validate the parameters
611 return EFI_INVALID_PARAMETER
;
614 Instance
= DHCP_INSTANCE_FROM_THIS (This
);
616 if (Instance
->Signature
!= DHCP_PROTOCOL_SIGNATURE
) {
617 return EFI_INVALID_PARAMETER
;
620 Status
= EFI_SUCCESS
;
621 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
622 DhcpSb
= Instance
->Service
;
624 if ((DhcpSb
->DhcpState
!= Dhcp4InitReboot
) && (DhcpSb
->DhcpState
!= Dhcp4Bound
)) {
625 Status
= EFI_ACCESS_DENIED
;
629 if (!DHCP_IS_BOOTP (DhcpSb
->Para
) && (DhcpSb
->DhcpState
== Dhcp4Bound
)) {
630 Status
= DhcpSendMessage (
638 if (EFI_ERROR (Status
)) {
639 Status
= EFI_DEVICE_ERROR
;
644 DhcpCleanLease (DhcpSb
);
647 gBS
->RestoreTPL (OldTpl
);
653 Stop the current DHCP process. After this, other DHCP child
654 can gain control of the service, configure and use it.
656 @param This The DHCP protocol instance
658 @retval EFI_INVALID_PARAMETER The parameter is invalid.
659 @retval EFI_SUCCESS The DHCP process is stopped.
665 IN EFI_DHCP4_PROTOCOL
*This
668 DHCP_PROTOCOL
*Instance
;
669 DHCP_SERVICE
*DhcpSb
;
673 // First validate the parameters
676 return EFI_INVALID_PARAMETER
;
679 Instance
= DHCP_INSTANCE_FROM_THIS (This
);
681 if (Instance
->Signature
!= DHCP_PROTOCOL_SIGNATURE
) {
682 return EFI_INVALID_PARAMETER
;
685 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
686 DhcpSb
= Instance
->Service
;
688 DhcpCleanLease (DhcpSb
);
690 DhcpSb
->DhcpState
= Dhcp4Stopped
;
691 DhcpSb
->ServiceState
= DHCP_UNCONFIGED
;
693 gBS
->RestoreTPL (OldTpl
);
699 Build a new DHCP packet from the seed packet. Options may be deleted or
700 appended. The caller should free the NewPacket when finished using it.
702 @param This The DHCP protocol instance.
703 @param SeedPacket The seed packet to start with
704 @param DeleteCount The number of options to delete
705 @param DeleteList The options to delete from the packet
706 @param AppendCount The number of options to append
707 @param AppendList The options to append to the packet
708 @param NewPacket The new packet, allocated and built by this
711 @retval EFI_INVALID_PARAMETER The parameters are invalid.
712 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory
713 @retval EFI_SUCCESS The packet is build.
719 IN EFI_DHCP4_PROTOCOL
*This
,
720 IN EFI_DHCP4_PACKET
*SeedPacket
,
721 IN UINT32 DeleteCount
,
722 IN UINT8
*DeleteList OPTIONAL
,
723 IN UINT32 AppendCount
,
724 IN EFI_DHCP4_PACKET_OPTION
*AppendList
[] OPTIONAL
,
725 OUT EFI_DHCP4_PACKET
**NewPacket
729 // First validate the parameters
731 if ((This
== NULL
) || (NewPacket
== NULL
)) {
732 return EFI_INVALID_PARAMETER
;
735 if ((SeedPacket
== NULL
) || (SeedPacket
->Dhcp4
.Magik
!= DHCP_OPTION_MAGIC
) ||
736 EFI_ERROR (DhcpValidateOptions (SeedPacket
, NULL
))) {
738 return EFI_INVALID_PARAMETER
;
741 if (((DeleteCount
== 0) && (AppendCount
== 0)) ||
742 ((DeleteCount
!= 0) && (DeleteList
== NULL
)) ||
743 ((AppendCount
!= 0) && (AppendList
== NULL
))) {
745 return EFI_INVALID_PARAMETER
;
759 Dhcp4InstanceConfigUdpIo (
760 IN UDP_IO_PORT
*UdpIo
,
764 DHCP_PROTOCOL
*Instance
;
765 DHCP_SERVICE
*DhcpSb
;
766 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN
*Token
;
767 EFI_UDP4_CONFIG_DATA UdpConfigData
;
770 Instance
= (DHCP_PROTOCOL
*) Context
;
771 DhcpSb
= Instance
->Service
;
772 Token
= Instance
->Token
;
774 ZeroMem (&UdpConfigData
, sizeof (EFI_UDP4_CONFIG_DATA
));
776 UdpConfigData
.AcceptBroadcast
= TRUE
;
777 UdpConfigData
.AllowDuplicatePort
= TRUE
;
778 UdpConfigData
.TimeToLive
= 64;
779 UdpConfigData
.DoNotFragment
= TRUE
;
781 Ip
= HTONL (DhcpSb
->ClientAddr
);
782 CopyMem (&UdpConfigData
.StationAddress
, &Ip
, sizeof (EFI_IPv4_ADDRESS
));
784 Ip
= HTONL (DhcpSb
->Netmask
);
785 CopyMem (&UdpConfigData
.SubnetMask
, &Ip
, sizeof (EFI_IPv4_ADDRESS
));
787 if ((Token
->ListenPointCount
== 0) || (Token
->ListenPoints
[0].ListenPort
== 0)) {
788 UdpConfigData
.StationPort
= DHCP_CLIENT_PORT
;
790 UdpConfigData
.StationPort
= Token
->ListenPoints
[0].ListenPort
;
793 return UdpIo
->Udp
->Configure (UdpIo
->Udp
, &UdpConfigData
);
797 Dhcp4InstanceCreateUdpIo (
798 IN DHCP_PROTOCOL
*Instance
801 DHCP_SERVICE
*DhcpSb
;
803 ASSERT (Instance
->Token
!= NULL
);
805 DhcpSb
= Instance
->Service
;
806 Instance
->UdpIo
= UdpIoCreatePort (DhcpSb
->Controller
, DhcpSb
->Image
, Dhcp4InstanceConfigUdpIo
, Instance
);
807 if (Instance
->UdpIo
== NULL
) {
808 return EFI_OUT_OF_RESOURCES
;
826 Arg - The packet to release
844 DHCP_PROTOCOL
*Instance
;
845 DHCP_SERVICE
*DhcpSb
;
846 EFI_DHCP4_HEADER
*Head
;
848 EFI_DHCP4_PACKET
*Packet
;
849 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN
*Token
;
854 Instance
= (DHCP_PROTOCOL
*) Context
;
855 Token
= Instance
->Token
;
856 DhcpSb
= Instance
->Service
;
859 // Don't restart receive if error occurs or DHCP is destoried.
861 if (EFI_ERROR (IoStatus
)) {
865 ASSERT (UdpPacket
!= NULL
);
868 // Validate the packet received
870 if (UdpPacket
->TotalSize
< sizeof (EFI_DHCP4_HEADER
)) {
875 // Copy the DHCP message to a continuous memory block, make the buffer size
876 // of the EFI_DHCP4_PACKET a multiple of 4-byte.
878 Len
= NET_ROUNDUP (sizeof (EFI_DHCP4_PACKET
) + UdpPacket
->TotalSize
- sizeof (EFI_DHCP4_HEADER
), 4);
879 Wrap
= NetbufAlloc (Len
);
885 Packet
= (EFI_DHCP4_PACKET
*) NetbufAllocSpace (Wrap
, Len
, NET_BUF_TAIL
);
887 Head
= &Packet
->Dhcp4
.Header
;
888 Packet
->Length
= NetbufCopy (UdpPacket
, 0, UdpPacket
->TotalSize
, (UINT8
*) Head
);
890 if (Packet
->Length
!= UdpPacket
->TotalSize
) {
895 // Is this packet the answer to our packet?
897 if ((Head
->OpCode
!= BOOTP_REPLY
) ||
898 (Head
->Xid
!= Token
->Packet
->Dhcp4
.Header
.Xid
) ||
899 (CompareMem (DhcpSb
->ClientAddressSendOut
, Head
->ClientHwAddr
, Head
->HwAddrLen
) != 0)) {
904 // Validate the options and retrieve the interested options
906 if ((Packet
->Length
> sizeof (EFI_DHCP4_HEADER
) + sizeof (UINT32
)) &&
907 (Packet
->Dhcp4
.Magik
== DHCP_OPTION_MAGIC
) &&
908 EFI_ERROR (DhcpValidateOptions (Packet
, NULL
))) {
914 // Keep this packet in the ResponseQueue.
917 NetbufQueAppend (&Instance
->ResponseQueue
, Wrap
);
921 NetbufFree (UdpPacket
);
927 Status
= UdpIoRecvDatagram (Instance
->UdpIo
, PxeDhcpInput
, Instance
, 0);
928 if (EFI_ERROR (Status
)) {
929 PxeDhcpDone (Instance
);
935 IN DHCP_PROTOCOL
*Instance
938 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN
*Token
;
940 Token
= Instance
->Token
;
942 Token
->ResponseCount
= Instance
->ResponseQueue
.BufNum
;
943 if (Token
->ResponseCount
!= 0) {
944 Token
->ResponseList
= (EFI_DHCP4_PACKET
*) AllocatePool (Instance
->ResponseQueue
.BufSize
);
945 if (Token
->ResponseList
== NULL
) {
946 Token
->Status
= EFI_OUT_OF_RESOURCES
;
951 // Copy the recieved DHCP responses.
953 NetbufQueCopy (&Instance
->ResponseQueue
, 0, Instance
->ResponseQueue
.BufSize
, (UINT8
*) Token
->ResponseList
);
954 Token
->Status
= EFI_SUCCESS
;
956 Token
->ResponseList
= NULL
;
957 Token
->Status
= EFI_TIMEOUT
;
962 // Clean the resources dedicated for this transmit receive transaction.
964 NetbufQueFlush (&Instance
->ResponseQueue
);
965 UdpIoCleanPort (Instance
->UdpIo
);
966 UdpIoFreePort (Instance
->UdpIo
);
967 Instance
->UdpIo
= NULL
;
968 Instance
->Token
= NULL
;
970 if (Token
->CompletionEvent
!= NULL
) {
971 gBS
->SignalEvent (Token
->CompletionEvent
);
977 Transmits a DHCP formatted packet and optionally waits for responses.
979 @param This Pointer to the EFI_DHCP4_PROTOCOL instance.
980 @param Token Pointer to the EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN structure.
982 @retval EFI_SUCCESS The packet was successfully queued for transmission.
983 @retval EFI_INVALID_PARAMETER Some parameter is NULL.
984 @retval EFI_NOT_READY The previous call to this function has not finished yet. Try to call
985 this function after collection process completes.
986 @retval EFI_NO_MAPPING The default station address is not available yet.
987 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
988 @retval Others Some other unexpected error occurred.
993 EfiDhcp4TransmitReceive (
994 IN EFI_DHCP4_PROTOCOL
*This
,
995 IN EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN
*Token
998 DHCP_PROTOCOL
*Instance
;
1003 UDP_POINTS EndPoint
;
1005 DHCP_SERVICE
*DhcpSb
;
1007 IP4_ADDR SubnetMask
;
1009 if ((This
== NULL
) || (Token
== NULL
) || (Token
->Packet
== NULL
)) {
1010 return EFI_INVALID_PARAMETER
;
1013 Instance
= DHCP_INSTANCE_FROM_THIS (This
);
1014 DhcpSb
= Instance
->Service
;
1016 if (Instance
->Token
!= NULL
) {
1018 // The previous call to TransmitReceive is not finished.
1020 return EFI_NOT_READY
;
1023 if ((Token
->Packet
->Dhcp4
.Magik
!= DHCP_OPTION_MAGIC
) ||
1024 (NTOHL (Token
->Packet
->Dhcp4
.Header
.Xid
) == Instance
->Service
->Xid
) ||
1025 (Token
->TimeoutValue
== 0) ||
1026 ((Token
->ListenPointCount
!= 0) && (Token
->ListenPoints
== NULL
)) ||
1027 EFI_ERROR (DhcpValidateOptions (Token
->Packet
, NULL
)) ||
1028 EFI_IP4_EQUAL (&Token
->RemoteAddress
, &mZeroIp4Addr
)) {
1030 // The DHCP packet isn't well-formed, the Transaction ID is already used
1031 // , the timeout value is zero, the ListenPoint is invalid,
1032 // or the RemoteAddress is zero.
1034 return EFI_INVALID_PARAMETER
;
1037 if (DhcpSb
->ClientAddr
== 0) {
1039 return EFI_NO_MAPPING
;
1042 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1045 // Save the token and the timeout value.
1047 Instance
->Token
= Token
;
1048 Instance
->Timeout
= Token
->TimeoutValue
;
1051 // Create a UDP IO for this transmit receive transaction.
1053 Status
= Dhcp4InstanceCreateUdpIo (Instance
);
1054 if (EFI_ERROR (Status
)) {
1059 // Save the Client Address is sent out
1061 CopyMem (&DhcpSb
->ClientAddressSendOut
[0], &Token
->Packet
->Dhcp4
.Header
.ClientHwAddr
[0], Token
->Packet
->Dhcp4
.Header
.HwAddrLen
);
1064 // Wrap the DHCP packet into a net buffer.
1066 Frag
.Bulk
= (UINT8
*) &Token
->Packet
->Dhcp4
;
1067 Frag
.Len
= Token
->Packet
->Length
;
1068 Wrap
= NetbufFromExt (&Frag
, 1, 0, 0, DhcpDummyExtFree
, NULL
);
1070 Status
= EFI_OUT_OF_RESOURCES
;
1075 // Set the local address and local port.
1077 EndPoint
.LocalAddr
= 0;
1078 EndPoint
.LocalPort
= 0;
1081 // Set the destination address and destination port.
1083 CopyMem (&Ip
, &Token
->RemoteAddress
, sizeof (EFI_IPv4_ADDRESS
));
1084 EndPoint
.RemoteAddr
= NTOHL (Ip
);
1086 if (Token
->RemotePort
== 0) {
1087 EndPoint
.RemotePort
= DHCP_SERVER_PORT
;
1089 EndPoint
.RemotePort
= Token
->RemotePort
;
1095 SubnetMask
= DhcpSb
->Netmask
;
1097 if (!IP4_NET_EQUAL (DhcpSb
->ClientAddr
, EndPoint
.RemoteAddr
, SubnetMask
)) {
1098 CopyMem (&Gateway
, &Token
->GatewayAddress
, sizeof (EFI_IPv4_ADDRESS
));
1099 Gateway
= NTOHL (Gateway
);
1103 // Transmit the DHCP packet.
1105 Status
= UdpIoSendDatagram (Instance
->UdpIo
, Wrap
, &EndPoint
, Gateway
, DhcpOnPacketSent
, NULL
);
1106 if (EFI_ERROR (Status
)) {
1112 // Start to receive the DHCP response.
1114 Status
= UdpIoRecvDatagram (Instance
->UdpIo
, PxeDhcpInput
, Instance
, 0);
1115 if (EFI_ERROR (Status
)) {
1121 if (EFI_ERROR (Status
) && (Instance
->UdpIo
!= NULL
)) {
1122 UdpIoCleanPort (Instance
->UdpIo
);
1123 UdpIoFreePort (Instance
->UdpIo
);
1124 Instance
->UdpIo
= NULL
;
1125 Instance
->Token
= NULL
;
1128 gBS
->RestoreTPL (OldTpl
);
1130 if (!EFI_ERROR (Status
) && (Token
->CompletionEvent
== NULL
)) {
1132 // Keep polling until timeout if no error happens and the CompletionEvent
1135 while (Instance
->Timeout
!= 0) {
1136 Instance
->UdpIo
->Udp
->Poll (Instance
->UdpIo
->Udp
);
1145 Callback function for DhcpIterateOptions. This callback sets the
1146 EFI_DHCP4_PACKET_OPTION array in the DHCP_PARSE_CONTEXT to point
1147 the individual DHCP option in the packet.
1149 @param Tag The DHCP option type
1150 @param Len length of the DHCP option data
1151 @param Data The DHCP option data
1152 @param Context The context, to pass several parameters in.
1154 @retval EFI_SUCCESS It always returns EFI_SUCCESS
1158 Dhcp4ParseCheckOption (
1165 DHCP_PARSE_CONTEXT
*Parse
;
1167 Parse
= (DHCP_PARSE_CONTEXT
*) Context
;
1170 if (Parse
->Index
<= Parse
->OptionCount
) {
1172 // Use _CR to get the memory position of EFI_DHCP4_PACKET_OPTION for
1173 // the EFI_DHCP4_PACKET_OPTION->Data because DhcpIterateOptions only
1174 // pass in the point to option data.
1176 Parse
->Option
[Parse
->Index
- 1] = _CR (Data
, EFI_DHCP4_PACKET_OPTION
, Data
);
1184 Parse the DHCP options in the Packet into the PacketOptionList.
1185 User should allocate this array of EFI_DHCP4_PACKET_OPTION points.
1187 @param This The DHCP protocol instance
1188 @param Packet The DHCP packet to parse
1189 @param OptionCount On input, the size of the PacketOptionList; On
1190 output, the actual number of options processed.
1191 @param PacketOptionList The array of EFI_DHCP4_PACKET_OPTION points
1193 @retval EFI_INVALID_PARAMETER The parameters are invalid.
1194 @retval EFI_BUFFER_TOO_SMALL A bigger array of points is needed.
1195 @retval EFI_SUCCESS The options are parsed.
1201 IN EFI_DHCP4_PROTOCOL
*This
,
1202 IN EFI_DHCP4_PACKET
*Packet
,
1203 IN OUT UINT32
*OptionCount
,
1204 OUT EFI_DHCP4_PACKET_OPTION
*PacketOptionList
[] OPTIONAL
1207 DHCP_PARSE_CONTEXT Context
;
1211 // First validate the parameters
1213 if ((This
== NULL
) || (Packet
== NULL
) || (OptionCount
== NULL
)) {
1214 return EFI_INVALID_PARAMETER
;
1217 if ((Packet
->Size
< Packet
->Length
+ 2 * sizeof (UINT32
)) ||
1218 (Packet
->Dhcp4
.Magik
!= DHCP_OPTION_MAGIC
) ||
1219 EFI_ERROR (DhcpValidateOptions (Packet
, NULL
))) {
1221 return EFI_INVALID_PARAMETER
;
1224 if ((*OptionCount
!= 0) && (PacketOptionList
== NULL
)) {
1225 return EFI_BUFFER_TOO_SMALL
;
1228 ZeroMem (PacketOptionList
, *OptionCount
* sizeof (EFI_DHCP4_PACKET_OPTION
*));
1230 Context
.Option
= PacketOptionList
;
1231 Context
.OptionCount
= *OptionCount
;
1234 Status
= DhcpIterateOptions (Packet
, Dhcp4ParseCheckOption
, &Context
);
1236 if (EFI_ERROR (Status
)) {
1240 *OptionCount
= Context
.Index
;
1242 if (Context
.Index
> Context
.OptionCount
) {
1243 return EFI_BUFFER_TOO_SMALL
;
1249 EFI_DHCP4_PROTOCOL mDhcp4ProtocolTemplate
= {
1250 EfiDhcp4GetModeData
,
1253 EfiDhcp4RenewRebind
,
1257 EfiDhcp4TransmitReceive
,