3 Copyright (c) 2006 - 2007, 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
42 IN EFI_DHCP4_PROTOCOL
*This
,
43 OUT EFI_DHCP4_MODE_DATA
*Dhcp4ModeData
46 DHCP_PROTOCOL
*Instance
;
53 // First validate the parameters.
55 if ((This
== NULL
) || (Dhcp4ModeData
== NULL
)) {
56 return EFI_INVALID_PARAMETER
;
59 Instance
= DHCP_INSTANCE_FROM_THIS (This
);
61 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
62 DhcpSb
= Instance
->Service
;
65 // Caller can use GetModeData to retrieve current DHCP states
66 // no matter whether it is the active child or not.
68 Dhcp4ModeData
->State
= (EFI_DHCP4_STATE
) DhcpSb
->DhcpState
;
69 CopyMem (&Dhcp4ModeData
->ConfigData
, &DhcpSb
->ActiveConfig
, sizeof (Dhcp4ModeData
->ConfigData
));
70 CopyMem (&Dhcp4ModeData
->ClientMacAddress
, &DhcpSb
->Mac
, sizeof (Dhcp4ModeData
->ClientMacAddress
));
72 Ip
= HTONL (DhcpSb
->ClientAddr
);
73 CopyMem (&Dhcp4ModeData
->ClientAddress
, &Ip
, sizeof (EFI_IPv4_ADDRESS
));
75 Ip
= HTONL (DhcpSb
->Netmask
);
76 CopyMem (&Dhcp4ModeData
->SubnetMask
, &Ip
, sizeof (EFI_IPv4_ADDRESS
));
78 Ip
= HTONL (DhcpSb
->ServerAddr
);
79 CopyMem (&Dhcp4ModeData
->ServerAddress
, &Ip
, sizeof (EFI_IPv4_ADDRESS
));
84 Ip
= HTONL (Para
->Router
);
85 CopyMem (&Dhcp4ModeData
->RouterAddress
, &Ip
, sizeof (EFI_IPv4_ADDRESS
));
86 Dhcp4ModeData
->LeaseTime
= Para
->Lease
;
88 ZeroMem (&Dhcp4ModeData
->RouterAddress
, sizeof (EFI_IPv4_ADDRESS
));
89 Dhcp4ModeData
->LeaseTime
= 0xffffffff;
92 Dhcp4ModeData
->ReplyPacket
= DhcpSb
->Selected
;
94 gBS
->RestoreTPL (OldTpl
);
100 Free the resource related to the configure parameters.
101 DHCP driver will make a copy of the user's configure
102 such as the time out value.
104 @param Config The DHCP configure data
111 IN EFI_DHCP4_CONFIG_DATA
*Config
116 if (Config
->DiscoverTimeout
!= NULL
) {
117 gBS
->FreePool (Config
->DiscoverTimeout
);
120 if (Config
->RequestTimeout
!= NULL
) {
121 gBS
->FreePool (Config
->RequestTimeout
);
124 if (Config
->OptionList
!= NULL
) {
125 for (Index
= 0; Index
< Config
->OptionCount
; Index
++) {
126 if (Config
->OptionList
[Index
] != NULL
) {
127 gBS
->FreePool (Config
->OptionList
[Index
]);
131 gBS
->FreePool (Config
->OptionList
);
134 ZeroMem (Config
, sizeof (EFI_DHCP4_CONFIG_DATA
));
139 Allocate memory for configure parameter such as timeout value for Dst,
140 then copy the configure parameter from Src to Dst.
142 @param Dst The destination DHCP configure data.
143 @param Src The source DHCP configure data.
145 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
146 @retval EFI_SUCCESS The configure is copied.
151 IN EFI_DHCP4_CONFIG_DATA
*Dst
,
152 IN EFI_DHCP4_CONFIG_DATA
*Src
155 EFI_DHCP4_PACKET_OPTION
**DstOptions
;
156 EFI_DHCP4_PACKET_OPTION
**SrcOptions
;
160 CopyMem (Dst
, Src
, sizeof (*Dst
));
161 Dst
->DiscoverTimeout
= NULL
;
162 Dst
->RequestTimeout
= NULL
;
163 Dst
->OptionList
= NULL
;
166 // Allocate a memory then copy DiscoverTimeout to it
168 if (Src
->DiscoverTimeout
!= NULL
) {
169 Len
= Src
->DiscoverTryCount
* sizeof (UINT32
);
170 Dst
->DiscoverTimeout
= AllocatePool (Len
);
172 if (Dst
->DiscoverTimeout
== NULL
) {
173 return EFI_OUT_OF_RESOURCES
;
176 for (Index
= 0; Index
< Src
->DiscoverTryCount
; Index
++) {
177 Dst
->DiscoverTimeout
[Index
] = MAX (Src
->DiscoverTimeout
[Index
], 1);
182 // Allocate a memory then copy RequestTimeout to it
184 if (Src
->RequestTimeout
!= NULL
) {
185 Len
= Src
->RequestTryCount
* sizeof (UINT32
);
186 Dst
->RequestTimeout
= AllocatePool (Len
);
188 if (Dst
->RequestTimeout
== NULL
) {
192 for (Index
= 0; Index
< Src
->RequestTryCount
; Index
++) {
193 Dst
->RequestTimeout
[Index
] = MAX (Src
->RequestTimeout
[Index
], 1);
198 // Allocate an array of dhcp option point, then allocate memory
199 // for each option and copy the source option to it
201 if (Src
->OptionList
!= NULL
) {
202 Len
= Src
->OptionCount
* sizeof (EFI_DHCP4_PACKET_OPTION
*);
203 Dst
->OptionList
= AllocateZeroPool (Len
);
205 if (Dst
->OptionList
== NULL
) {
209 DstOptions
= Dst
->OptionList
;
210 SrcOptions
= Src
->OptionList
;
212 for (Index
= 0; Index
< Src
->OptionCount
; Index
++) {
213 Len
= sizeof (EFI_DHCP4_PACKET_OPTION
) + MAX (SrcOptions
[Index
]->Length
- 1, 0);
215 DstOptions
[Index
] = AllocatePool (Len
);
217 if (DstOptions
[Index
] == NULL
) {
221 CopyMem (DstOptions
[Index
], SrcOptions
[Index
], Len
);
228 DhcpCleanConfigure (Dst
);
229 return EFI_OUT_OF_RESOURCES
;
234 Give up the control of the DHCP service to let other child
235 resume. Don't change the service's DHCP state and the Client
236 address and option list configure as required by RFC2131.
238 @param DhcpSb The DHCP service instance.
245 IN DHCP_SERVICE
*DhcpSb
248 EFI_DHCP4_CONFIG_DATA
*Config
;
250 Config
= &DhcpSb
->ActiveConfig
;
252 DhcpSb
->ServiceState
= DHCP_UNCONFIGED
;
253 DhcpSb
->ActiveChild
= NULL
;
255 if (Config
->DiscoverTimeout
!= NULL
) {
256 gBS
->FreePool (Config
->DiscoverTimeout
);
258 Config
->DiscoverTryCount
= 0;
259 Config
->DiscoverTimeout
= NULL
;
262 if (Config
->RequestTimeout
!= NULL
) {
263 gBS
->FreePool (Config
->RequestTimeout
);
265 Config
->RequestTryCount
= 0;
266 Config
->RequestTimeout
= NULL
;
269 Config
->Dhcp4Callback
= NULL
;
270 Config
->CallbackContext
= NULL
;
275 Configure the DHCP protocol instance and its underlying DHCP service
276 for operation. If Dhcp4CfgData is NULL and the child is currently
277 controlling the DHCP service, release the control.
279 @param This The DHCP protocol instance
280 @param Dhcp4CfgData The DHCP configure data.
282 @retval EFI_INVALID_PARAMETER The parameters are invalid.
283 @retval EFI_ACCESS_DENIED The service isn't in one of configurable states,
284 or there is already an active child.
285 @retval EFI_OUT_OF_RESOURCE Failed to allocate some resources.
286 @retval EFI_SUCCESS The child is configured.
293 IN EFI_DHCP4_PROTOCOL
*This
,
294 IN EFI_DHCP4_CONFIG_DATA
*Dhcp4CfgData OPTIONAL
297 EFI_DHCP4_CONFIG_DATA
*Config
;
298 DHCP_PROTOCOL
*Instance
;
299 DHCP_SERVICE
*DhcpSb
;
306 // First validate the parameters
309 return EFI_INVALID_PARAMETER
;
312 if (Dhcp4CfgData
!= NULL
) {
313 if (Dhcp4CfgData
->DiscoverTryCount
&& (Dhcp4CfgData
->DiscoverTimeout
== NULL
)) {
314 return EFI_INVALID_PARAMETER
;
317 if (Dhcp4CfgData
->RequestTryCount
&& (Dhcp4CfgData
->RequestTimeout
== NULL
)) {
318 return EFI_INVALID_PARAMETER
;
321 if (Dhcp4CfgData
->OptionCount
&& (Dhcp4CfgData
->OptionList
== NULL
)) {
322 return EFI_INVALID_PARAMETER
;
325 CopyMem (&Ip
, &Dhcp4CfgData
->ClientAddress
, sizeof (IP4_ADDR
));
327 if ((Ip
!= 0) && !Ip4IsUnicast (NTOHL (Ip
), 0)) {
329 return EFI_INVALID_PARAMETER
;
333 Instance
= DHCP_INSTANCE_FROM_THIS (This
);
335 if (Instance
->Signature
!= DHCP_PROTOCOL_SIGNATURE
) {
336 return EFI_INVALID_PARAMETER
;
339 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
341 DhcpSb
= Instance
->Service
;
342 Config
= &DhcpSb
->ActiveConfig
;
344 Status
= EFI_ACCESS_DENIED
;
346 if ((DhcpSb
->DhcpState
!= Dhcp4Stopped
) &&
347 (DhcpSb
->DhcpState
!= Dhcp4Init
) &&
348 (DhcpSb
->DhcpState
!= Dhcp4InitReboot
) &&
349 (DhcpSb
->DhcpState
!= Dhcp4Bound
)) {
354 if ((DhcpSb
->ActiveChild
!= NULL
) && (DhcpSb
->ActiveChild
!= Instance
)) {
358 if (Dhcp4CfgData
!= NULL
) {
359 Status
= EFI_OUT_OF_RESOURCES
;
360 DhcpCleanConfigure (Config
);
362 if (EFI_ERROR (DhcpCopyConfigure (Config
, Dhcp4CfgData
))) {
366 DhcpSb
->UserOptionLen
= 0;
368 for (Index
= 0; Index
< Dhcp4CfgData
->OptionCount
; Index
++) {
369 DhcpSb
->UserOptionLen
+= Dhcp4CfgData
->OptionList
[Index
]->Length
+ 2;
372 DhcpSb
->ActiveChild
= Instance
;
374 if (DhcpSb
->DhcpState
== Dhcp4Stopped
) {
375 DhcpSb
->ClientAddr
= EFI_NTOHL (Dhcp4CfgData
->ClientAddress
);
377 if (DhcpSb
->ClientAddr
!= 0) {
378 DhcpSb
->DhcpState
= Dhcp4InitReboot
;
380 DhcpSb
->DhcpState
= Dhcp4Init
;
384 DhcpSb
->ServiceState
= DHCP_CONFIGED
;
385 Status
= EFI_SUCCESS
;
387 } else if (DhcpSb
->ActiveChild
== Instance
) {
388 Status
= EFI_SUCCESS
;
389 DhcpYieldControl (DhcpSb
);
393 gBS
->RestoreTPL (OldTpl
);
399 Start the DHCP process.
401 @param This The DHCP protocol instance
402 @param CompletionEvent The event to signal is address is acquired.
404 @retval EFI_INVALID_PARAMETER The parameters are invalid.
405 @retval EFI_NOT_STARTED The protocol hasn't been configured.
406 @retval EFI_ALREADY_STARTED The DHCP process has already been started.
407 @retval EFI_SUCCESS The DHCP process is started.
414 IN EFI_DHCP4_PROTOCOL
*This
,
415 IN EFI_EVENT CompletionEvent OPTIONAL
418 DHCP_PROTOCOL
*Instance
;
419 DHCP_SERVICE
*DhcpSb
;
424 // First validate the parameters
427 return EFI_INVALID_PARAMETER
;
430 Instance
= DHCP_INSTANCE_FROM_THIS (This
);
432 if (Instance
->Signature
!= DHCP_PROTOCOL_SIGNATURE
) {
433 return EFI_INVALID_PARAMETER
;
436 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
437 DhcpSb
= Instance
->Service
;
439 if (DhcpSb
->DhcpState
== Dhcp4Stopped
) {
440 Status
= EFI_NOT_STARTED
;
444 if ((DhcpSb
->DhcpState
!= Dhcp4Init
) && (DhcpSb
->DhcpState
!= Dhcp4InitReboot
)) {
445 Status
= EFI_ALREADY_STARTED
;
449 DhcpSb
->IoStatus
= EFI_ALREADY_STARTED
;
451 if (EFI_ERROR (Status
= DhcpInitRequest (DhcpSb
))) {
456 // Start/Restart the receiving.
458 Status
= UdpIoRecvDatagram (DhcpSb
->UdpIo
, DhcpInput
, DhcpSb
, 0);
460 if (EFI_ERROR (Status
) && (Status
!= EFI_ALREADY_STARTED
)) {
464 Instance
->CompletionEvent
= CompletionEvent
;
467 // Restore the TPL now, don't call poll function at TPL_CALLBACK.
469 gBS
->RestoreTPL (OldTpl
);
471 if (CompletionEvent
== NULL
) {
472 while (DhcpSb
->IoStatus
== EFI_ALREADY_STARTED
) {
473 DhcpSb
->UdpIo
->Udp
->Poll (DhcpSb
->UdpIo
->Udp
);
476 return DhcpSb
->IoStatus
;
482 gBS
->RestoreTPL (OldTpl
);
488 Request an extra manual renew/rebind.
490 @param This The DHCP protocol instance
491 @param RebindRequest TRUE if request a rebind, otherwise renew it
492 @param CompletionEvent Event to signal when complete
494 @retval EFI_INVALID_PARAMETER The parameters are invalid
495 @retval EFI_NOT_STARTED The DHCP protocol hasn't been started.
496 @retval EFI_ACCESS_DENIED The DHCP protocol isn't in Bound state.
497 @retval EFI_SUCCESS The DHCP is renewed/rebound.
503 EfiDhcp4RenewRebind (
504 IN EFI_DHCP4_PROTOCOL
*This
,
505 IN BOOLEAN RebindRequest
,
506 IN EFI_EVENT CompletionEvent OPTIONAL
509 DHCP_PROTOCOL
*Instance
;
510 DHCP_SERVICE
*DhcpSb
;
515 // First validate the parameters
518 return EFI_INVALID_PARAMETER
;
521 Instance
= DHCP_INSTANCE_FROM_THIS (This
);
523 if (Instance
->Signature
!= DHCP_PROTOCOL_SIGNATURE
) {
524 return EFI_INVALID_PARAMETER
;
527 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
528 DhcpSb
= Instance
->Service
;
530 if (DhcpSb
->DhcpState
== Dhcp4Stopped
) {
531 Status
= EFI_NOT_STARTED
;
535 if (DhcpSb
->DhcpState
!= Dhcp4Bound
) {
536 Status
= EFI_ACCESS_DENIED
;
540 if (DHCP_IS_BOOTP (DhcpSb
->Para
)) {
545 // Transit the states then send a extra DHCP request
547 if (!RebindRequest
) {
548 DhcpSetState (DhcpSb
, Dhcp4Renewing
, FALSE
);
550 DhcpSetState (DhcpSb
, Dhcp4Rebinding
, FALSE
);
553 Status
= DhcpSendMessage (
558 (UINT8
*) "Extra renew/rebind by the application"
561 if (EFI_ERROR (Status
)) {
562 DhcpSetState (DhcpSb
, Dhcp4Bound
, FALSE
);
566 DhcpSb
->ExtraRefresh
= TRUE
;
567 DhcpSb
->IoStatus
= EFI_ALREADY_STARTED
;
568 Instance
->RenewRebindEvent
= CompletionEvent
;
570 gBS
->RestoreTPL (OldTpl
);
572 if (CompletionEvent
== NULL
) {
573 while (DhcpSb
->IoStatus
== EFI_ALREADY_STARTED
) {
574 DhcpSb
->UdpIo
->Udp
->Poll (DhcpSb
->UdpIo
->Udp
);
577 return DhcpSb
->IoStatus
;
583 gBS
->RestoreTPL (OldTpl
);
589 Release the current acquired lease.
591 @param This The DHCP protocol instance
593 @retval EFI_INVALID_PARAMETER The parameter is invalid
594 @retval EFI_DEVICE_ERROR Failed to transmit the DHCP release packet
595 @retval EFI_ACCESS_DENIED The DHCP service isn't in one of the connected
597 @retval EFI_SUCCESS The lease is released.
604 IN EFI_DHCP4_PROTOCOL
*This
607 DHCP_PROTOCOL
*Instance
;
608 DHCP_SERVICE
*DhcpSb
;
613 // First validate the parameters
616 return EFI_INVALID_PARAMETER
;
619 Instance
= DHCP_INSTANCE_FROM_THIS (This
);
621 if (Instance
->Signature
!= DHCP_PROTOCOL_SIGNATURE
) {
622 return EFI_INVALID_PARAMETER
;
625 Status
= EFI_SUCCESS
;
626 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
627 DhcpSb
= Instance
->Service
;
629 if ((DhcpSb
->DhcpState
!= Dhcp4InitReboot
) && (DhcpSb
->DhcpState
!= Dhcp4Bound
)) {
630 Status
= EFI_ACCESS_DENIED
;
634 if (!DHCP_IS_BOOTP (DhcpSb
->Para
) && (DhcpSb
->DhcpState
== Dhcp4Bound
)) {
635 Status
= DhcpSendMessage (
643 if (EFI_ERROR (Status
)) {
644 Status
= EFI_DEVICE_ERROR
;
649 DhcpCleanLease (DhcpSb
);
652 gBS
->RestoreTPL (OldTpl
);
658 Stop the current DHCP process. After this, other DHCP child
659 can gain control of the service, configure and use it.
661 @param This The DHCP protocol instance
663 @retval EFI_INVALID_PARAMETER The parameter is invalid.
664 @retval EFI_SUCCESS The DHCP process is stopped.
671 IN EFI_DHCP4_PROTOCOL
*This
674 DHCP_PROTOCOL
*Instance
;
675 DHCP_SERVICE
*DhcpSb
;
679 // First validate the parameters
682 return EFI_INVALID_PARAMETER
;
685 Instance
= DHCP_INSTANCE_FROM_THIS (This
);
687 if (Instance
->Signature
!= DHCP_PROTOCOL_SIGNATURE
) {
688 return EFI_INVALID_PARAMETER
;
691 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
692 DhcpSb
= Instance
->Service
;
694 DhcpCleanLease (DhcpSb
);
696 DhcpSb
->DhcpState
= Dhcp4Stopped
;
697 DhcpSb
->ServiceState
= DHCP_UNCONFIGED
;
699 gBS
->RestoreTPL (OldTpl
);
705 Build a new DHCP packet from the seed packet. Options may be deleted or
706 appended. The caller should free the NewPacket when finished using it.
708 @param This The DHCP protocol instance.
709 @param SeedPacket The seed packet to start with
710 @param DeleteCount The number of options to delete
711 @param DeleteList The options to delete from the packet
712 @param AppendCount The number of options to append
713 @param AppendList The options to append to the packet
714 @param NewPacket The new packet, allocated and built by this
717 @retval EFI_INVALID_PARAMETER The parameters are invalid.
718 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory
719 @retval EFI_SUCCESS The packet is build.
726 IN EFI_DHCP4_PROTOCOL
*This
,
727 IN EFI_DHCP4_PACKET
*SeedPacket
,
728 IN UINT32 DeleteCount
,
729 IN UINT8
*DeleteList OPTIONAL
,
730 IN UINT32 AppendCount
,
731 IN EFI_DHCP4_PACKET_OPTION
*AppendList
[] OPTIONAL
,
732 OUT EFI_DHCP4_PACKET
**NewPacket
736 // First validate the parameters
738 if ((This
== NULL
) || (NewPacket
== NULL
)) {
739 return EFI_INVALID_PARAMETER
;
742 if ((SeedPacket
== NULL
) || (SeedPacket
->Dhcp4
.Magik
!= DHCP_OPTION_MAGIC
) ||
743 EFI_ERROR (DhcpValidateOptions (SeedPacket
, NULL
))) {
745 return EFI_INVALID_PARAMETER
;
748 if (((DeleteCount
== 0) && (AppendCount
== 0)) ||
749 ((DeleteCount
!= 0) && (DeleteList
== NULL
)) ||
750 ((AppendCount
!= 0) && (AppendList
== NULL
))) {
752 return EFI_INVALID_PARAMETER
;
767 Dhcp4InstanceConfigUdpIo (
768 IN UDP_IO_PORT
*UdpIo
,
772 DHCP_PROTOCOL
*Instance
;
773 DHCP_SERVICE
*DhcpSb
;
774 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN
*Token
;
775 EFI_UDP4_CONFIG_DATA UdpConfigData
;
778 Instance
= (DHCP_PROTOCOL
*) Context
;
779 DhcpSb
= Instance
->Service
;
780 Token
= Instance
->Token
;
782 ZeroMem (&UdpConfigData
, sizeof (EFI_UDP4_CONFIG_DATA
));
784 UdpConfigData
.AcceptBroadcast
= TRUE
;
785 UdpConfigData
.AllowDuplicatePort
= TRUE
;
786 UdpConfigData
.TimeToLive
= 64;
787 UdpConfigData
.DoNotFragment
= TRUE
;
789 Ip
= HTONL (DhcpSb
->ClientAddr
);
790 CopyMem (&UdpConfigData
.StationAddress
, &Ip
, sizeof (EFI_IPv4_ADDRESS
));
792 Ip
= HTONL (DhcpSb
->Netmask
);
793 CopyMem (&UdpConfigData
.SubnetMask
, &Ip
, sizeof (EFI_IPv4_ADDRESS
));
795 if ((Token
->ListenPointCount
== 0) || (Token
->ListenPoints
[0].ListenPort
== 0)) {
796 UdpConfigData
.StationPort
= DHCP_CLIENT_PORT
;
798 UdpConfigData
.StationPort
= Token
->ListenPoints
[0].ListenPort
;
801 return UdpIo
->Udp
->Configure (UdpIo
->Udp
, &UdpConfigData
);
806 Dhcp4InstanceCreateUdpIo (
807 IN DHCP_PROTOCOL
*Instance
810 DHCP_SERVICE
*DhcpSb
;
812 ASSERT (Instance
->Token
!= NULL
);
814 DhcpSb
= Instance
->Service
;
815 Instance
->UdpIo
= UdpIoCreatePort (DhcpSb
->Controller
, DhcpSb
->Image
, Dhcp4InstanceConfigUdpIo
, Instance
);
816 if (Instance
->UdpIo
== NULL
) {
817 return EFI_OUT_OF_RESOURCES
;
836 Arg - The packet to release
854 DHCP_PROTOCOL
*Instance
;
855 DHCP_SERVICE
*DhcpSb
;
856 EFI_DHCP4_HEADER
*Head
;
858 EFI_DHCP4_PACKET
*Packet
;
859 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN
*Token
;
864 Instance
= (DHCP_PROTOCOL
*) Context
;
865 Token
= Instance
->Token
;
866 DhcpSb
= Instance
->Service
;
869 // Don't restart receive if error occurs or DHCP is destoried.
871 if (EFI_ERROR (IoStatus
)) {
875 ASSERT (UdpPacket
!= NULL
);
878 // Validate the packet received
880 if (UdpPacket
->TotalSize
< sizeof (EFI_DHCP4_HEADER
)) {
885 // Copy the DHCP message to a continuous memory block, make the buffer size
886 // of the EFI_DHCP4_PACKET a multiple of 4-byte.
888 Len
= NET_ROUNDUP (sizeof (EFI_DHCP4_PACKET
) + UdpPacket
->TotalSize
- sizeof (EFI_DHCP4_HEADER
), 4);
889 Wrap
= NetbufAlloc (Len
);
895 Packet
= (EFI_DHCP4_PACKET
*) NetbufAllocSpace (Wrap
, Len
, NET_BUF_TAIL
);
897 Head
= &Packet
->Dhcp4
.Header
;
898 Packet
->Length
= NetbufCopy (UdpPacket
, 0, UdpPacket
->TotalSize
, (UINT8
*) Head
);
900 if (Packet
->Length
!= UdpPacket
->TotalSize
) {
905 // Is this packet the answer to our packet?
907 if ((Head
->OpCode
!= BOOTP_REPLY
) ||
908 (Head
->Xid
!= Token
->Packet
->Dhcp4
.Header
.Xid
) ||
909 (CompareMem (DhcpSb
->ClientAddressSendOut
, Head
->ClientHwAddr
, Head
->HwAddrLen
) != 0)) {
914 // Validate the options and retrieve the interested options
916 if ((Packet
->Length
> sizeof (EFI_DHCP4_HEADER
) + sizeof (UINT32
)) &&
917 (Packet
->Dhcp4
.Magik
== DHCP_OPTION_MAGIC
) &&
918 EFI_ERROR (DhcpValidateOptions (Packet
, NULL
))) {
924 // Keep this packet in the ResponseQueue.
927 NetbufQueAppend (&Instance
->ResponseQueue
, Wrap
);
931 NetbufFree (UdpPacket
);
937 Status
= UdpIoRecvDatagram (Instance
->UdpIo
, PxeDhcpInput
, Instance
, 0);
938 if (EFI_ERROR (Status
)) {
939 PxeDhcpDone (Instance
);
945 IN DHCP_PROTOCOL
*Instance
948 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN
*Token
;
950 Token
= Instance
->Token
;
952 Token
->ResponseCount
= Instance
->ResponseQueue
.BufNum
;
953 if (Token
->ResponseCount
!= 0) {
954 Token
->ResponseList
= (EFI_DHCP4_PACKET
*) AllocatePool (Instance
->ResponseQueue
.BufSize
);
955 if (Token
->ResponseList
== NULL
) {
956 Token
->Status
= EFI_OUT_OF_RESOURCES
;
961 // Copy the recieved DHCP responses.
963 NetbufQueCopy (&Instance
->ResponseQueue
, 0, Instance
->ResponseQueue
.BufSize
, (UINT8
*) Token
->ResponseList
);
964 Token
->Status
= EFI_SUCCESS
;
966 Token
->ResponseList
= NULL
;
967 Token
->Status
= EFI_TIMEOUT
;
972 // Clean the resources dedicated for this transmit receive transaction.
974 NetbufQueFlush (&Instance
->ResponseQueue
);
975 UdpIoCleanPort (Instance
->UdpIo
);
976 UdpIoFreePort (Instance
->UdpIo
);
977 Instance
->UdpIo
= NULL
;
978 Instance
->Token
= NULL
;
980 if (Token
->CompletionEvent
!= NULL
) {
981 gBS
->SignalEvent (Token
->CompletionEvent
);
987 Transmits a DHCP formatted packet and optionally waits for responses.
989 @param This Pointer to the EFI_DHCP4_PROTOCOL instance.
990 @param Token Pointer to the EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN structure.
992 @retval EFI_SUCCESS The packet was successfully queued for transmission.
993 @retval EFI_INVALID_PARAMETER Some parameter is NULL.
994 @retval EFI_NOT_READY The previous call to this function has not finished yet. Try to call
995 this function after collection process completes.
996 @retval EFI_NO_MAPPING The default station address is not available yet.
997 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.
998 @retval Others Some other unexpected error occurred.
1004 EfiDhcp4TransmitReceive (
1005 IN EFI_DHCP4_PROTOCOL
*This
,
1006 IN EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN
*Token
1009 DHCP_PROTOCOL
*Instance
;
1014 UDP_POINTS EndPoint
;
1016 DHCP_SERVICE
*DhcpSb
;
1018 IP4_ADDR SubnetMask
;
1020 if ((This
== NULL
) || (Token
== NULL
) || (Token
->Packet
== NULL
)) {
1021 return EFI_INVALID_PARAMETER
;
1024 Instance
= DHCP_INSTANCE_FROM_THIS (This
);
1025 DhcpSb
= Instance
->Service
;
1027 if (Instance
->Token
!= NULL
) {
1029 // The previous call to TransmitReceive is not finished.
1031 return EFI_NOT_READY
;
1034 if ((Token
->Packet
->Dhcp4
.Magik
!= DHCP_OPTION_MAGIC
) ||
1035 (NTOHL (Token
->Packet
->Dhcp4
.Header
.Xid
) == Instance
->Service
->Xid
) ||
1036 (Token
->TimeoutValue
== 0) ||
1037 ((Token
->ListenPointCount
!= 0) && (Token
->ListenPoints
== NULL
)) ||
1038 EFI_ERROR (DhcpValidateOptions (Token
->Packet
, NULL
)) ||
1039 EFI_IP4_EQUAL (&Token
->RemoteAddress
, &mZeroIp4Addr
)) {
1041 // The DHCP packet isn't well-formed, the Transaction ID is already used
1042 // , the timeout value is zero, the ListenPoint is invalid,
1043 // or the RemoteAddress is zero.
1045 return EFI_INVALID_PARAMETER
;
1048 if (DhcpSb
->ClientAddr
== 0) {
1050 return EFI_NO_MAPPING
;
1053 OldTpl
= gBS
->RaiseTPL (TPL_CALLBACK
);
1056 // Save the token and the timeout value.
1058 Instance
->Token
= Token
;
1059 Instance
->Timeout
= Token
->TimeoutValue
;
1062 // Create a UDP IO for this transmit receive transaction.
1064 Status
= Dhcp4InstanceCreateUdpIo (Instance
);
1065 if (EFI_ERROR (Status
)) {
1070 // Save the Client Address is sent out
1072 CopyMem (&DhcpSb
->ClientAddressSendOut
[0], &Token
->Packet
->Dhcp4
.Header
.ClientHwAddr
[0], Token
->Packet
->Dhcp4
.Header
.HwAddrLen
);
1075 // Wrap the DHCP packet into a net buffer.
1077 Frag
.Bulk
= (UINT8
*) &Token
->Packet
->Dhcp4
;
1078 Frag
.Len
= Token
->Packet
->Length
;
1079 Wrap
= NetbufFromExt (&Frag
, 1, 0, 0, DhcpDummyExtFree
, NULL
);
1081 Status
= EFI_OUT_OF_RESOURCES
;
1086 // Set the local address and local port.
1088 EndPoint
.LocalAddr
= 0;
1089 EndPoint
.LocalPort
= 0;
1092 // Set the destination address and destination port.
1094 CopyMem (&Ip
, &Token
->RemoteAddress
, sizeof (EFI_IPv4_ADDRESS
));
1095 EndPoint
.RemoteAddr
= NTOHL (Ip
);
1097 if (Token
->RemotePort
== 0) {
1098 EndPoint
.RemotePort
= DHCP_SERVER_PORT
;
1100 EndPoint
.RemotePort
= Token
->RemotePort
;
1106 SubnetMask
= DhcpSb
->Netmask
;
1108 if (!IP4_NET_EQUAL (DhcpSb
->ClientAddr
, EndPoint
.RemoteAddr
, SubnetMask
)) {
1109 CopyMem (&Gateway
, &Token
->GatewayAddress
, sizeof (EFI_IPv4_ADDRESS
));
1110 Gateway
= NTOHL (Gateway
);
1114 // Transmit the DHCP packet.
1116 Status
= UdpIoSendDatagram (Instance
->UdpIo
, Wrap
, &EndPoint
, Gateway
, DhcpOnPacketSent
, NULL
);
1117 if (EFI_ERROR (Status
)) {
1123 // Start to receive the DHCP response.
1125 Status
= UdpIoRecvDatagram (Instance
->UdpIo
, PxeDhcpInput
, Instance
, 0);
1126 if (EFI_ERROR (Status
)) {
1132 if (EFI_ERROR (Status
) && (Instance
->UdpIo
!= NULL
)) {
1133 UdpIoCleanPort (Instance
->UdpIo
);
1134 UdpIoFreePort (Instance
->UdpIo
);
1135 Instance
->UdpIo
= NULL
;
1136 Instance
->Token
= NULL
;
1139 gBS
->RestoreTPL (OldTpl
);
1141 if (!EFI_ERROR (Status
) && (Token
->CompletionEvent
== NULL
)) {
1143 // Keep polling until timeout if no error happens and the CompletionEvent
1146 while (Instance
->Timeout
!= 0) {
1147 Instance
->UdpIo
->Udp
->Poll (Instance
->UdpIo
->Udp
);
1156 Callback function for DhcpIterateOptions. This callback sets the
1157 EFI_DHCP4_PACKET_OPTION array in the DHCP_PARSE_CONTEXT to point
1158 the individual DHCP option in the packet.
1160 @param Tag The DHCP option type
1161 @param Len length of the DHCP option data
1162 @param Data The DHCP option data
1163 @param Context The context, to pass several parameters in.
1165 @retval EFI_SUCCESS It always returns EFI_SUCCESS
1170 Dhcp4ParseCheckOption (
1177 DHCP_PARSE_CONTEXT
*Parse
;
1179 Parse
= (DHCP_PARSE_CONTEXT
*) Context
;
1182 if (Parse
->Index
<= Parse
->OptionCount
) {
1184 // Use _CR to get the memory position of EFI_DHCP4_PACKET_OPTION for
1185 // the EFI_DHCP4_PACKET_OPTION->Data because DhcpIterateOptions only
1186 // pass in the point to option data.
1188 Parse
->Option
[Parse
->Index
- 1] = _CR (Data
, EFI_DHCP4_PACKET_OPTION
, Data
);
1196 Parse the DHCP options in the Packet into the PacketOptionList.
1197 User should allocate this array of EFI_DHCP4_PACKET_OPTION points.
1199 @param This The DHCP protocol instance
1200 @param Packet The DHCP packet to parse
1201 @param OptionCount On input, the size of the PacketOptionList; On
1202 output, the actual number of options processed.
1203 @param PacketOptionList The array of EFI_DHCP4_PACKET_OPTION points
1205 @retval EFI_INVALID_PARAMETER The parameters are invalid.
1206 @retval EFI_BUFFER_TOO_SMALL A bigger array of points is needed.
1207 @retval EFI_SUCCESS The options are parsed.
1214 IN EFI_DHCP4_PROTOCOL
*This
,
1215 IN EFI_DHCP4_PACKET
*Packet
,
1216 IN OUT UINT32
*OptionCount
,
1217 OUT EFI_DHCP4_PACKET_OPTION
*PacketOptionList
[] OPTIONAL
1220 DHCP_PARSE_CONTEXT Context
;
1224 // First validate the parameters
1226 if ((This
== NULL
) || (Packet
== NULL
) || (OptionCount
== NULL
)) {
1227 return EFI_INVALID_PARAMETER
;
1230 if ((Packet
->Size
< Packet
->Length
+ 2 * sizeof (UINT32
)) ||
1231 (Packet
->Dhcp4
.Magik
!= DHCP_OPTION_MAGIC
) ||
1232 EFI_ERROR (DhcpValidateOptions (Packet
, NULL
))) {
1234 return EFI_INVALID_PARAMETER
;
1237 if ((*OptionCount
!= 0) && (PacketOptionList
== NULL
)) {
1238 return EFI_BUFFER_TOO_SMALL
;
1241 ZeroMem (PacketOptionList
, *OptionCount
* sizeof (EFI_DHCP4_PACKET_OPTION
*));
1243 Context
.Option
= PacketOptionList
;
1244 Context
.OptionCount
= *OptionCount
;
1247 Status
= DhcpIterateOptions (Packet
, Dhcp4ParseCheckOption
, &Context
);
1249 if (EFI_ERROR (Status
)) {
1253 *OptionCount
= Context
.Index
;
1255 if (Context
.Index
> Context
.OptionCount
) {
1256 return EFI_BUFFER_TOO_SMALL
;
1262 EFI_DHCP4_PROTOCOL mDhcp4ProtocolTemplate
= {
1263 EfiDhcp4GetModeData
,
1266 EfiDhcp4RenewRebind
,
1270 EfiDhcp4TransmitReceive
,