2 EFI DHCP protocol implementation.
4 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "Dhcp4Impl.h"
18 UINT32 mDhcp4DefaultTimeout
[4] = { 4, 8, 16, 32 };
22 Send an initial DISCOVER or REQUEST message according to the
23 DHCP service's current state.
25 @param[in] DhcpSb The DHCP service instance
27 @retval EFI_SUCCESS The request has been sent
28 @retval other Some error occurs when sending the request.
33 IN DHCP_SERVICE
*DhcpSb
38 ASSERT ((DhcpSb
->DhcpState
== Dhcp4Init
) || (DhcpSb
->DhcpState
== Dhcp4InitReboot
));
41 // Clear initial time to make sure that elapsed-time is set to 0 for first Discover or REQUEST message.
43 DhcpSb
->ActiveChild
->ElaspedTime
= 0;
45 if (DhcpSb
->DhcpState
== Dhcp4Init
) {
46 DhcpSetState (DhcpSb
, Dhcp4Selecting
, FALSE
);
47 Status
= DhcpSendMessage (DhcpSb
, NULL
, NULL
, DHCP_MSG_DISCOVER
, NULL
);
49 if (EFI_ERROR (Status
)) {
50 DhcpSb
->DhcpState
= Dhcp4Init
;
54 DhcpSetState (DhcpSb
, Dhcp4Rebooting
, FALSE
);
55 Status
= DhcpSendMessage (DhcpSb
, NULL
, NULL
, DHCP_MSG_REQUEST
, NULL
);
57 if (EFI_ERROR (Status
)) {
58 DhcpSb
->DhcpState
= Dhcp4InitReboot
;
68 Call user provided callback function, and return the value the
69 function returns. If the user doesn't provide a callback, a
70 proper return value is selected to let the caller continue the
73 @param[in] DhcpSb The DHCP service instance
74 @param[in] Event The event as defined in the spec
75 @param[in] Packet The current packet trigger the event
76 @param[out] NewPacket The user's return new packet
78 @retval EFI_NOT_READY Direct the caller to continue collecting the offer.
79 @retval EFI_SUCCESS The user function returns success.
80 @retval EFI_ABORTED The user function ask it to abort.
85 IN DHCP_SERVICE
*DhcpSb
,
86 IN EFI_DHCP4_EVENT Event
,
87 IN EFI_DHCP4_PACKET
*Packet
, OPTIONAL
88 OUT EFI_DHCP4_PACKET
**NewPacket OPTIONAL
91 EFI_DHCP4_CONFIG_DATA
*Config
;
94 if (NewPacket
!= NULL
) {
99 // If user doesn't provide the call back function, return the value
100 // that directs the client to continue the normal process.
101 // In Dhcp4Selecting EFI_SUCCESS tells the client to stop collecting
102 // the offers and select a offer, EFI_NOT_READY tells the client to
103 // collect more offers.
105 Config
= &DhcpSb
->ActiveConfig
;
107 if (Config
->Dhcp4Callback
== NULL
) {
108 if (Event
== Dhcp4RcvdOffer
) {
109 return EFI_NOT_READY
;
115 Status
= Config
->Dhcp4Callback (
116 &DhcpSb
->ActiveChild
->Dhcp4Protocol
,
117 Config
->CallbackContext
,
118 (EFI_DHCP4_STATE
) DhcpSb
->DhcpState
,
125 // User's callback should only return EFI_SUCCESS, EFI_NOT_READY,
126 // and EFI_ABORTED. If it returns values other than those, assume
127 // it to be EFI_ABORTED.
129 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_NOT_READY
)) {
138 Notify the user about the operation result.
140 @param DhcpSb DHCP service instance
141 @param Which Which notify function to signal
146 IN DHCP_SERVICE
*DhcpSb
,
150 DHCP_PROTOCOL
*Child
;
152 if ((Child
= DhcpSb
->ActiveChild
) == NULL
) {
156 if ((Child
->CompletionEvent
!= NULL
) &&
157 ((Which
== DHCP_NOTIFY_COMPLETION
) || (Which
== DHCP_NOTIFY_ALL
))
160 gBS
->SignalEvent (Child
->CompletionEvent
);
161 Child
->CompletionEvent
= NULL
;
164 if ((Child
->RenewRebindEvent
!= NULL
) &&
165 ((Which
== DHCP_NOTIFY_RENEWREBIND
) || (Which
== DHCP_NOTIFY_ALL
))
168 gBS
->SignalEvent (Child
->RenewRebindEvent
);
169 Child
->RenewRebindEvent
= NULL
;
176 Set the DHCP state. If CallUser is true, it will try to notify
177 the user before change the state by DhcpNotifyUser. It returns
178 EFI_ABORTED if the user return EFI_ABORTED, otherwise, it returns
179 EFI_SUCCESS. If CallUser is FALSE, it isn't necessary to test
180 the return value of this function.
182 @param DhcpSb The DHCP service instance
183 @param State The new DHCP state to change to
184 @param CallUser Whether we need to call user
186 @retval EFI_SUCCESS The state is changed
187 @retval EFI_ABORTED The user asks to abort the DHCP process.
192 IN OUT DHCP_SERVICE
*DhcpSb
,
200 Status
= EFI_SUCCESS
;
202 if (State
== Dhcp4Renewing
) {
203 Status
= DhcpCallUser (DhcpSb
, Dhcp4EnterRenewing
, NULL
, NULL
);
205 } else if (State
== Dhcp4Rebinding
) {
206 Status
= DhcpCallUser (DhcpSb
, Dhcp4EnterRebinding
, NULL
, NULL
);
208 } else if (State
== Dhcp4Bound
) {
209 Status
= DhcpCallUser (DhcpSb
, Dhcp4BoundCompleted
, NULL
, NULL
);
213 if (EFI_ERROR (Status
)) {
219 // Update the retransmission timer during the state transition.
220 // This will clear the retry count. This is also why the rule
221 // first transit the state, then send packets.
223 if (State
== Dhcp4Selecting
) {
224 DhcpSb
->MaxRetries
= DhcpSb
->ActiveConfig
.DiscoverTryCount
;
226 DhcpSb
->MaxRetries
= DhcpSb
->ActiveConfig
.RequestTryCount
;
229 if (DhcpSb
->MaxRetries
== 0) {
230 DhcpSb
->MaxRetries
= 4;
233 DhcpSb
->CurRetry
= 0;
234 DhcpSb
->PacketToLive
= 0;
235 DhcpSb
->LastTimeout
= 0;
236 DhcpSb
->DhcpState
= State
;
242 Set the retransmit timer for the packet. It will select from either
243 the discover timeouts/request timeouts or the default timeout values.
245 @param DhcpSb The DHCP service instance.
249 DhcpSetTransmitTimer (
250 IN OUT DHCP_SERVICE
*DhcpSb
255 ASSERT (DhcpSb
->MaxRetries
> DhcpSb
->CurRetry
);
257 if (DhcpSb
->DhcpState
== Dhcp4Selecting
) {
258 Times
= DhcpSb
->ActiveConfig
.DiscoverTimeout
;
260 Times
= DhcpSb
->ActiveConfig
.RequestTimeout
;
264 Times
= mDhcp4DefaultTimeout
;
267 DhcpSb
->PacketToLive
= Times
[DhcpSb
->CurRetry
];
268 DhcpSb
->LastTimeout
= DhcpSb
->PacketToLive
;
274 Compute the lease. If the server grants a permanent lease, just
275 process it as a normal timeout value since the lease will last
278 @param DhcpSb The DHCP service instance
279 @param Para The DHCP parameter extracted from the server's
284 IN OUT DHCP_SERVICE
*DhcpSb
,
285 IN DHCP_PARAMETER
*Para
288 ASSERT (Para
!= NULL
);
290 DhcpSb
->Lease
= Para
->Lease
;
291 DhcpSb
->T2
= Para
->T2
;
292 DhcpSb
->T1
= Para
->T1
;
294 if (DhcpSb
->Lease
== 0) {
295 DhcpSb
->Lease
= DHCP_DEFAULT_LEASE
;
298 if ((DhcpSb
->T2
== 0) || (DhcpSb
->T2
>= Para
->Lease
)) {
299 DhcpSb
->T2
= Para
->Lease
- (Para
->Lease
>> 3);
302 if ((DhcpSb
->T1
== 0) || (DhcpSb
->T1
>= Para
->T2
)) {
303 DhcpSb
->T1
= DhcpSb
->Lease
>> 1;
309 Configure a UDP IO port to use the acquired lease address.
310 DHCP driver needs this port to unicast packet to the server
311 such as DHCP release.
313 @param[in] UdpIo The UDP IO to configure
314 @param[in] Context Dhcp service instance.
316 @retval EFI_SUCCESS The UDP IO port is successfully configured.
317 @retval Others It failed to configure the port.
322 DhcpConfigLeaseIoPort (
327 EFI_UDP4_CONFIG_DATA UdpConfigData
;
328 EFI_IPv4_ADDRESS Subnet
;
329 EFI_IPv4_ADDRESS Gateway
;
330 DHCP_SERVICE
*DhcpSb
;
334 DhcpSb
= (DHCP_SERVICE
*) Context
;
336 UdpConfigData
.AcceptBroadcast
= FALSE
;
337 UdpConfigData
.AcceptPromiscuous
= FALSE
;
338 UdpConfigData
.AcceptAnyPort
= FALSE
;
339 UdpConfigData
.AllowDuplicatePort
= TRUE
;
340 UdpConfigData
.TypeOfService
= 0;
341 UdpConfigData
.TimeToLive
= 64;
342 UdpConfigData
.DoNotFragment
= FALSE
;
343 UdpConfigData
.ReceiveTimeout
= 1;
344 UdpConfigData
.TransmitTimeout
= 0;
346 UdpConfigData
.UseDefaultAddress
= FALSE
;
347 UdpConfigData
.StationPort
= DHCP_CLIENT_PORT
;
348 UdpConfigData
.RemotePort
= DHCP_SERVER_PORT
;
350 Ip
= HTONL (DhcpSb
->ClientAddr
);
351 CopyMem (&UdpConfigData
.StationAddress
, &Ip
, sizeof (EFI_IPv4_ADDRESS
));
353 Ip
= HTONL (DhcpSb
->Netmask
);
354 CopyMem (&UdpConfigData
.SubnetMask
, &Ip
, sizeof (EFI_IPv4_ADDRESS
));
356 ZeroMem (&UdpConfigData
.RemoteAddress
, sizeof (EFI_IPv4_ADDRESS
));
358 Status
= UdpIo
->Protocol
.Udp4
->Configure (UdpIo
->Protocol
.Udp4
, &UdpConfigData
);
360 if (EFI_ERROR (Status
)) {
365 // Add a default route if received from the server.
367 if ((DhcpSb
->Para
!= NULL
) && (DhcpSb
->Para
->Router
!= 0)) {
368 ZeroMem (&Subnet
, sizeof (EFI_IPv4_ADDRESS
));
370 Ip
= HTONL (DhcpSb
->Para
->Router
);
371 CopyMem (&Gateway
, &Ip
, sizeof (EFI_IPv4_ADDRESS
));
373 UdpIo
->Protocol
.Udp4
->Routes (UdpIo
->Protocol
.Udp4
, FALSE
, &Subnet
, &Subnet
, &Gateway
);
381 Update the lease states when a new lease is acquired. It will not only
382 save the acquired the address and lease time, it will also create a UDP
383 child to provide address resolution for the address.
385 @param DhcpSb The DHCP service instance
387 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
388 @retval EFI_SUCCESS The lease is recorded.
393 IN OUT DHCP_SERVICE
*DhcpSb
396 DhcpSb
->ClientAddr
= EFI_NTOHL (DhcpSb
->Selected
->Dhcp4
.Header
.YourAddr
);
398 if (DhcpSb
->Para
!= NULL
) {
399 DhcpSb
->Netmask
= DhcpSb
->Para
->NetMask
;
400 DhcpSb
->ServerAddr
= DhcpSb
->Para
->ServerId
;
403 if (DhcpSb
->Netmask
== 0) {
407 if (DhcpSb
->LeaseIoPort
!= NULL
) {
408 UdpIoFreeIo (DhcpSb
->LeaseIoPort
);
412 // Create a UDP/IP child to provide ARP service for the Leased IP,
413 // and transmit unicast packet with it as source address. Don't
414 // start receive on this port, the queued packet will be timeout.
416 DhcpSb
->LeaseIoPort
= UdpIoCreateIo (
419 DhcpConfigLeaseIoPort
,
424 if (DhcpSb
->LeaseIoPort
== NULL
) {
425 return EFI_OUT_OF_RESOURCES
;
428 if (!DHCP_IS_BOOTP (DhcpSb
->Para
)) {
429 DhcpComputeLease (DhcpSb
, DhcpSb
->Para
);
432 return DhcpSetState (DhcpSb
, Dhcp4Bound
, TRUE
);
437 Clean up the DHCP related states, IoStatus isn't reset.
439 @param DhcpSb The DHCP instance service.
444 IN DHCP_SERVICE
*DhcpSb
447 DhcpSb
->DhcpState
= Dhcp4Init
;
448 DhcpSb
->Xid
= DhcpSb
->Xid
+ 1;
449 DhcpSb
->ClientAddr
= 0;
451 DhcpSb
->ServerAddr
= 0;
453 if (DhcpSb
->LastOffer
!= NULL
) {
454 FreePool (DhcpSb
->LastOffer
);
455 DhcpSb
->LastOffer
= NULL
;
458 if (DhcpSb
->Selected
!= NULL
) {
459 FreePool (DhcpSb
->Selected
);
460 DhcpSb
->Selected
= NULL
;
463 if (DhcpSb
->Para
!= NULL
) {
464 FreePool (DhcpSb
->Para
);
471 DhcpSb
->ExtraRefresh
= FALSE
;
473 if (DhcpSb
->LeaseIoPort
!= NULL
) {
474 UdpIoFreeIo (DhcpSb
->LeaseIoPort
);
475 DhcpSb
->LeaseIoPort
= NULL
;
478 if (DhcpSb
->LastPacket
!= NULL
) {
479 FreePool (DhcpSb
->LastPacket
);
480 DhcpSb
->LastPacket
= NULL
;
483 DhcpSb
->PacketToLive
= 0;
484 DhcpSb
->LastTimeout
= 0;
485 DhcpSb
->CurRetry
= 0;
486 DhcpSb
->MaxRetries
= 0;
487 DhcpSb
->LeaseLife
= 0;
490 // Clean active config data.
492 DhcpCleanConfigure (&DhcpSb
->ActiveConfig
);
497 Select a offer among all the offers collected. If the offer selected is
498 of BOOTP, the lease is recorded and user notified. If the offer is of
499 DHCP, it will request the offer from the server.
501 @param[in] DhcpSb The DHCP service instance.
503 @retval EFI_SUCCESS One of the offer is selected.
508 IN DHCP_SERVICE
*DhcpSb
511 EFI_DHCP4_PACKET
*Selected
;
512 EFI_DHCP4_PACKET
*NewPacket
;
513 EFI_DHCP4_PACKET
*TempPacket
;
516 ASSERT (DhcpSb
->LastOffer
!= NULL
);
519 // User will cache previous offers if he wants to select
520 // from multiple offers. If user provides an invalid packet,
521 // use the last offer, otherwise use the provided packet.
524 Status
= DhcpCallUser (DhcpSb
, Dhcp4SelectOffer
, DhcpSb
->LastOffer
, &NewPacket
);
526 if (EFI_ERROR (Status
)) {
530 Selected
= DhcpSb
->LastOffer
;
532 if ((NewPacket
!= NULL
) && !EFI_ERROR (DhcpValidateOptions (NewPacket
, NULL
))) {
533 TempPacket
= (EFI_DHCP4_PACKET
*) AllocatePool (NewPacket
->Size
);
534 if (TempPacket
!= NULL
) {
535 CopyMem (TempPacket
, NewPacket
, NewPacket
->Size
);
537 Selected
= TempPacket
;
541 DhcpSb
->Selected
= Selected
;
542 DhcpSb
->LastOffer
= NULL
;
544 DhcpValidateOptions (Selected
, &DhcpSb
->Para
);
547 // A bootp offer has been selected, save the lease status,
548 // enter bound state then notify the user.
550 if (DHCP_IS_BOOTP (DhcpSb
->Para
)) {
551 Status
= DhcpLeaseAcquired (DhcpSb
);
553 if (EFI_ERROR (Status
)) {
557 DhcpSb
->IoStatus
= EFI_SUCCESS
;
558 DhcpNotifyUser (DhcpSb
, DHCP_NOTIFY_ALL
);
563 // Send a DHCP requests
565 Status
= DhcpSetState (DhcpSb
, Dhcp4Requesting
, TRUE
);
567 if (EFI_ERROR (Status
)) {
571 return DhcpSendMessage (DhcpSb
, Selected
, DhcpSb
->Para
, DHCP_MSG_REQUEST
, NULL
);
576 Terminate the current address acquire. All the allocated resources
577 are released. Be careful when calling this function. A rule related
578 to this is: only call DhcpEndSession at the highest level, such as
579 DhcpInput, DhcpOnTimerTick...At the other level, just return error.
581 @param[in] DhcpSb The DHCP service instance
582 @param[in] Status The result of the DHCP process.
587 IN DHCP_SERVICE
*DhcpSb
,
591 if (DHCP_CONNECTED (DhcpSb
->DhcpState
)) {
592 DhcpCallUser (DhcpSb
, Dhcp4AddressLost
, NULL
, NULL
);
594 DhcpCallUser (DhcpSb
, Dhcp4Fail
, NULL
, NULL
);
597 DhcpCleanLease (DhcpSb
);
599 DhcpSb
->IoStatus
= Status
;
600 DhcpNotifyUser (DhcpSb
, DHCP_NOTIFY_ALL
);
605 Handle packets in DHCP select state.
607 @param[in] DhcpSb The DHCP service instance
608 @param[in] Packet The DHCP packet received
609 @param[in] Para The DHCP parameter extracted from the packet. That
610 is, all the option value that we care.
612 @retval EFI_SUCCESS The packet is successfully processed.
613 @retval Others Some error occured.
618 IN DHCP_SERVICE
*DhcpSb
,
619 IN EFI_DHCP4_PACKET
*Packet
,
620 IN DHCP_PARAMETER
*Para
625 Status
= EFI_SUCCESS
;
628 // First validate the message:
629 // 1. the offer is a unicast
630 // 2. if it is a DHCP message, it must contains a server ID.
631 // Don't return a error for these two case otherwise the session is ended.
633 if (!DHCP_IS_BOOTP (Para
) &&
634 ((Para
->DhcpType
!= DHCP_MSG_OFFER
) || (Para
->ServerId
== 0))
640 // Call the user's callback. The action according to the return is as:
641 // 1. EFI_SUCESS: stop waiting for more offers, select the offer now
642 // 2. EFI_NOT_READY: wait for more offers
643 // 3. EFI_ABORTED: abort the address acquiring.
645 Status
= DhcpCallUser (DhcpSb
, Dhcp4RcvdOffer
, Packet
, NULL
);
647 if (Status
== EFI_SUCCESS
) {
648 if (DhcpSb
->LastOffer
!= NULL
) {
649 FreePool (DhcpSb
->LastOffer
);
652 DhcpSb
->LastOffer
= Packet
;
654 return DhcpChooseOffer (DhcpSb
);
656 } else if (Status
== EFI_NOT_READY
) {
657 if (DhcpSb
->LastOffer
!= NULL
) {
658 FreePool (DhcpSb
->LastOffer
);
661 DhcpSb
->LastOffer
= Packet
;
663 } else if (Status
== EFI_ABORTED
) {
665 // DhcpInput will end the session upon error return. Remember
666 // only to call DhcpEndSession at the top level call.
680 Handle packets in DHCP request state.
682 @param[in] DhcpSb The DHCP service instance
683 @param[in] Packet The DHCP packet received
684 @param[in] Para The DHCP parameter extracted from the packet. That
685 is, all the option value that we care.
687 @retval EFI_SUCCESS The packet is successfully processed.
688 @retval Others Some error occured.
693 IN DHCP_SERVICE
*DhcpSb
,
694 IN EFI_DHCP4_PACKET
*Packet
,
695 IN DHCP_PARAMETER
*Para
698 EFI_DHCP4_HEADER
*Head
;
699 EFI_DHCP4_HEADER
*Selected
;
703 ASSERT (!DHCP_IS_BOOTP (DhcpSb
->Para
));
705 Head
= &Packet
->Dhcp4
.Header
;
706 Selected
= &DhcpSb
->Selected
->Dhcp4
.Header
;
709 // Ignore the BOOTP message and DHCP messages other than DHCP ACK/NACK.
711 if (DHCP_IS_BOOTP (Para
) ||
712 (Para
->ServerId
!= DhcpSb
->Para
->ServerId
) ||
713 ((Para
->DhcpType
!= DHCP_MSG_ACK
) && (Para
->DhcpType
!= DHCP_MSG_NAK
))
716 Status
= EFI_SUCCESS
;
721 // Received a NAK, end the session no matter what the user returns
723 Status
= EFI_DEVICE_ERROR
;
725 if (Para
->DhcpType
== DHCP_MSG_NAK
) {
726 DhcpCallUser (DhcpSb
, Dhcp4RcvdNak
, Packet
, NULL
);
731 // Check whether the ACK matches the selected offer
735 if (!EFI_IP4_EQUAL (&Head
->YourAddr
, &Selected
->YourAddr
)) {
736 Message
= (UINT8
*) "Lease confirmed isn't the same as that in the offer";
740 Status
= DhcpCallUser (DhcpSb
, Dhcp4RcvdAck
, Packet
, NULL
);
742 if (EFI_ERROR (Status
)) {
743 Message
= (UINT8
*) "Lease is denied upon received ACK";
748 // Record the lease, transit to BOUND state, then notify the user
750 Status
= DhcpLeaseAcquired (DhcpSb
);
752 if (EFI_ERROR (Status
)) {
753 Message
= (UINT8
*) "Lease is denied upon entering bound";
757 DhcpSb
->IoStatus
= EFI_SUCCESS
;
758 DhcpNotifyUser (DhcpSb
, DHCP_NOTIFY_COMPLETION
);
764 DhcpSendMessage (DhcpSb
, DhcpSb
->Selected
, DhcpSb
->Para
, DHCP_MSG_DECLINE
, Message
);
773 Handle packets in DHCP renew/rebound state.
775 @param[in] DhcpSb The DHCP service instance
776 @param[in] Packet The DHCP packet received
777 @param[in] Para The DHCP parameter extracted from the packet. That
778 is, all the option value that we care.
780 @retval EFI_SUCCESS The packet is successfully processed.
781 @retval Others Some error occured.
785 DhcpHandleRenewRebind (
786 IN DHCP_SERVICE
*DhcpSb
,
787 IN EFI_DHCP4_PACKET
*Packet
,
788 IN DHCP_PARAMETER
*Para
791 EFI_DHCP4_HEADER
*Head
;
792 EFI_DHCP4_HEADER
*Selected
;
795 ASSERT (!DHCP_IS_BOOTP (DhcpSb
->Para
));
797 Head
= &Packet
->Dhcp4
.Header
;
798 Selected
= &DhcpSb
->Selected
->Dhcp4
.Header
;
801 // Ignore the BOOTP message and DHCP messages other than DHCP ACK/NACK
803 if (DHCP_IS_BOOTP (Para
) ||
804 (Para
->ServerId
!= DhcpSb
->Para
->ServerId
) ||
805 ((Para
->DhcpType
!= DHCP_MSG_ACK
) && (Para
->DhcpType
!= DHCP_MSG_NAK
))
808 Status
= EFI_SUCCESS
;
813 // Received a NAK, ignore the user's return then terminate the process
815 Status
= EFI_DEVICE_ERROR
;
817 if (Para
->DhcpType
== DHCP_MSG_NAK
) {
818 DhcpCallUser (DhcpSb
, Dhcp4RcvdNak
, Packet
, NULL
);
823 // The lease is different from the selected. Don't send a DECLINE
824 // since it isn't existed in the client's FSM.
826 if (!EFI_IP4_EQUAL (&Head
->YourAddr
, &Selected
->YourAddr
)) {
830 Status
= DhcpCallUser (DhcpSb
, Dhcp4RcvdAck
, Packet
, NULL
);
832 if (EFI_ERROR (Status
)) {
837 // Record the lease, start timer for T1 and T2,
839 DhcpComputeLease (DhcpSb
, Para
);
840 DhcpSb
->LeaseLife
= 0;
841 DhcpSetState (DhcpSb
, Dhcp4Bound
, TRUE
);
843 if (DhcpSb
->ExtraRefresh
!= 0) {
844 DhcpSb
->ExtraRefresh
= FALSE
;
846 DhcpSb
->IoStatus
= EFI_SUCCESS
;
847 DhcpNotifyUser (DhcpSb
, DHCP_NOTIFY_RENEWREBIND
);
857 Handle packets in DHCP reboot state.
859 @param[in] DhcpSb The DHCP service instance
860 @param[in] Packet The DHCP packet received
861 @param[in] Para The DHCP parameter extracted from the packet. That
862 is, all the option value that we care.
864 @retval EFI_SUCCESS The packet is successfully processed.
865 @retval Others Some error occured.
870 IN DHCP_SERVICE
*DhcpSb
,
871 IN EFI_DHCP4_PACKET
*Packet
,
872 IN DHCP_PARAMETER
*Para
875 EFI_DHCP4_HEADER
*Head
;
878 Head
= &Packet
->Dhcp4
.Header
;
881 // Ignore the BOOTP message and DHCP messages other than DHCP ACK/NACK
883 if (DHCP_IS_BOOTP (Para
) ||
884 ((Para
->DhcpType
!= DHCP_MSG_ACK
) && (Para
->DhcpType
!= DHCP_MSG_NAK
))
887 Status
= EFI_SUCCESS
;
892 // If a NAK is received, transit to INIT and try again.
894 if (Para
->DhcpType
== DHCP_MSG_NAK
) {
895 DhcpCallUser (DhcpSb
, Dhcp4RcvdNak
, Packet
, NULL
);
897 DhcpSb
->ClientAddr
= 0;
898 DhcpSb
->DhcpState
= Dhcp4Init
;
900 Status
= DhcpInitRequest (DhcpSb
);
905 // Check whether the ACK matches the selected offer
907 if (EFI_NTOHL (Head
->YourAddr
) != DhcpSb
->ClientAddr
) {
908 Status
= EFI_DEVICE_ERROR
;
912 Status
= DhcpCallUser (DhcpSb
, Dhcp4RcvdAck
, Packet
, NULL
);
913 if (EFI_ERROR (Status
)) {
918 // OK, get the parameter from server, record the lease
920 DhcpSb
->Para
= AllocateCopyPool (sizeof (DHCP_PARAMETER
), Para
);
921 if (DhcpSb
->Para
== NULL
) {
922 Status
= EFI_OUT_OF_RESOURCES
;
926 DhcpSb
->Selected
= Packet
;
927 Status
= DhcpLeaseAcquired (DhcpSb
);
928 if (EFI_ERROR (Status
)) {
932 DhcpSb
->IoStatus
= EFI_SUCCESS
;
933 DhcpNotifyUser (DhcpSb
, DHCP_NOTIFY_COMPLETION
);
943 Handle the received DHCP packets. This function drives the DHCP
946 @param UdpPacket The UDP packets received.
947 @param EndPoint The local/remote UDP access point
948 @param IoStatus The status of the UDP receive
949 @param Context The opaque parameter to the function.
956 UDP_END_POINT
*EndPoint
,
961 DHCP_SERVICE
*DhcpSb
;
962 EFI_DHCP4_HEADER
*Head
;
963 EFI_DHCP4_PACKET
*Packet
;
964 DHCP_PARAMETER
*Para
;
969 DhcpSb
= (DHCP_SERVICE
*) Context
;
972 // Don't restart receive if error occurs or DHCP is destroyed.
974 if (EFI_ERROR (IoStatus
)) {
976 } else if (DhcpSb
->ServiceState
== DHCP_DESTROY
) {
977 NetbufFree (UdpPacket
);
981 ASSERT (UdpPacket
!= NULL
);
983 if (DhcpSb
->DhcpState
== Dhcp4Stopped
) {
988 // Validate the packet received
990 if (UdpPacket
->TotalSize
< sizeof (EFI_DHCP4_HEADER
)) {
995 // Copy the DHCP message to a continuous memory block
997 Len
= sizeof (EFI_DHCP4_PACKET
) + UdpPacket
->TotalSize
- sizeof (EFI_DHCP4_HEADER
);
998 Packet
= (EFI_DHCP4_PACKET
*) AllocatePool (Len
);
1000 if (Packet
== NULL
) {
1005 Head
= &Packet
->Dhcp4
.Header
;
1006 Packet
->Length
= NetbufCopy (UdpPacket
, 0, UdpPacket
->TotalSize
, (UINT8
*) Head
);
1008 if (Packet
->Length
!= UdpPacket
->TotalSize
) {
1013 // Is this packet the answer to our packet?
1015 if ((Head
->OpCode
!= BOOTP_REPLY
) ||
1016 (NTOHL (Head
->Xid
) != DhcpSb
->Xid
) ||
1017 (CompareMem (DhcpSb
->ClientAddressSendOut
, Head
->ClientHwAddr
, Head
->HwAddrLen
) != 0)) {
1022 // Validate the options and retrieve the interested options
1025 if ((Packet
->Length
> sizeof (EFI_DHCP4_HEADER
) + sizeof (UINT32
)) &&
1026 (Packet
->Dhcp4
.Magik
== DHCP_OPTION_MAGIC
) &&
1027 EFI_ERROR (DhcpValidateOptions (Packet
, &Para
))) {
1033 // Call the handler for each state. The handler should return
1034 // EFI_SUCCESS if the process can go on no matter whether the
1035 // packet is ignored or not. If the return is EFI_ERROR, the
1036 // session will be terminated. Packet's ownership is handled
1037 // over to the handlers. If operation succeeds, the handler
1038 // must notify the user. It isn't necessary to do if EFI_ERROR
1039 // is returned because the DhcpEndSession will notify the user.
1041 Status
= EFI_SUCCESS
;
1043 switch (DhcpSb
->DhcpState
) {
1044 case Dhcp4Selecting
:
1045 Status
= DhcpHandleSelect (DhcpSb
, Packet
, Para
);
1048 case Dhcp4Requesting
:
1049 Status
= DhcpHandleRequest (DhcpSb
, Packet
, Para
);
1052 case Dhcp4InitReboot
:
1056 // Ignore the packet in INITREBOOT, INIT and BOUND states
1059 Status
= EFI_SUCCESS
;
1063 case Dhcp4Rebinding
:
1064 Status
= DhcpHandleRenewRebind (DhcpSb
, Packet
, Para
);
1067 case Dhcp4Rebooting
:
1068 Status
= DhcpHandleReboot (DhcpSb
, Packet
, Para
);
1078 if (EFI_ERROR (Status
)) {
1079 NetbufFree (UdpPacket
);
1080 UdpIoRecvDatagram (DhcpSb
->UdpIo
, DhcpInput
, DhcpSb
, 0);
1081 DhcpEndSession (DhcpSb
, Status
);
1086 NetbufFree (UdpPacket
);
1088 if (Packet
!= NULL
) {
1092 Status
= UdpIoRecvDatagram (DhcpSb
->UdpIo
, DhcpInput
, DhcpSb
, 0);
1094 if (EFI_ERROR (Status
)) {
1095 DhcpEndSession (DhcpSb
, EFI_DEVICE_ERROR
);
1103 @param[in] Arg The packet to release
1117 Release the net buffer when packet is sent.
1119 @param UdpPacket The UDP packets received.
1120 @param EndPoint The local/remote UDP access point
1121 @param IoStatus The status of the UDP receive
1122 @param Context The opaque parameter to the function.
1129 UDP_END_POINT
*EndPoint
,
1130 EFI_STATUS IoStatus
,
1134 NetbufFree (Packet
);
1140 Build and transmit a DHCP message according to the current states.
1141 This function implement the Table 5. of RFC 2131. Always transits
1142 the state (as defined in Figure 5. of the same RFC) before sending
1143 a DHCP message. The table is adjusted accordingly.
1145 @param[in] DhcpSb The DHCP service instance
1146 @param[in] Seed The seed packet which the new packet is based on
1147 @param[in] Para The DHCP parameter of the Seed packet
1148 @param[in] Type The message type to send
1149 @param[in] Msg The human readable message to include in the packet
1152 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources for the packet
1153 @retval EFI_ACCESS_DENIED Failed to transmit the packet through UDP
1154 @retval EFI_SUCCESS The message is sent
1155 @retval other Other error occurs
1160 IN DHCP_SERVICE
*DhcpSb
,
1161 IN EFI_DHCP4_PACKET
*Seed
,
1162 IN DHCP_PARAMETER
*Para
,
1167 EFI_DHCP4_CONFIG_DATA
*Config
;
1168 EFI_DHCP4_PACKET
*Packet
;
1169 EFI_DHCP4_PACKET
*NewPacket
;
1170 EFI_DHCP4_HEADER
*Head
;
1171 EFI_DHCP4_HEADER
*SeedHead
;
1173 UDP_END_POINT EndPoint
;
1184 // Allocate a big enough memory block to hold the DHCP packet
1186 Len
= sizeof (EFI_DHCP4_PACKET
) + 128 + DhcpSb
->UserOptionLen
;
1189 Len
+= (UINT32
)AsciiStrLen ((CHAR8
*) Msg
);
1192 Packet
= AllocatePool (Len
);
1194 if (Packet
== NULL
) {
1195 return EFI_OUT_OF_RESOURCES
;
1199 Packet
->Length
= sizeof (EFI_DHCP4_HEADER
) + sizeof (UINT32
);
1202 // Fill in the DHCP header fields
1204 Config
= &DhcpSb
->ActiveConfig
;
1208 SeedHead
= &Seed
->Dhcp4
.Header
;
1211 Head
= &Packet
->Dhcp4
.Header
;
1212 ZeroMem (Head
, sizeof (EFI_DHCP4_HEADER
));
1214 Head
->OpCode
= BOOTP_REQUEST
;
1215 Head
->HwType
= DhcpSb
->HwType
;
1216 Head
->HwAddrLen
= DhcpSb
->HwLen
;
1217 Head
->Xid
= HTONL (DhcpSb
->Xid
);
1218 Head
->Reserved
= HTONS (0x8000); //Server, broadcast the message please.
1220 EFI_IP4 (Head
->ClientAddr
) = HTONL (DhcpSb
->ClientAddr
);
1221 CopyMem (Head
->ClientHwAddr
, DhcpSb
->Mac
.Addr
, DhcpSb
->HwLen
);
1223 if ((Type
== DHCP_MSG_DECLINE
) || (Type
== DHCP_MSG_RELEASE
)) {
1225 } else if ((Type
== DHCP_MSG_REQUEST
) && (DhcpSb
->DhcpState
== Dhcp4Requesting
)) {
1227 // Use the same value as the original DHCPDISCOVER message.
1229 Head
->Seconds
= DhcpSb
->LastPacket
->Dhcp4
.Header
.Seconds
;
1231 SetElapsedTime(&Head
->Seconds
, DhcpSb
->ActiveChild
);
1235 // Append the DHCP message type
1237 Packet
->Dhcp4
.Magik
= DHCP_OPTION_MAGIC
;
1238 Buf
= Packet
->Dhcp4
.Option
;
1239 Buf
= DhcpAppendOption (Buf
, DHCP4_TAG_MSG_TYPE
, 1, &Type
);
1242 // Append the serverid option if necessary:
1243 // 1. DHCP decline message
1244 // 2. DHCP release message
1245 // 3. DHCP request to confirm one lease.
1247 if ((Type
== DHCP_MSG_DECLINE
) || (Type
== DHCP_MSG_RELEASE
) ||
1248 ((Type
== DHCP_MSG_REQUEST
) && (DhcpSb
->DhcpState
== Dhcp4Requesting
))
1251 ASSERT ((Para
!= NULL
) && (Para
->ServerId
!= 0));
1253 IpAddr
= HTONL (Para
->ServerId
);
1254 Buf
= DhcpAppendOption (Buf
, DHCP4_TAG_SERVER_ID
, 4, (UINT8
*) &IpAddr
);
1258 // Append the requested IP option if necessary:
1259 // 1. DHCP request to use the previously allocated address
1260 // 2. DHCP request to confirm one lease
1261 // 3. DHCP decline to decline one lease
1265 if (Type
== DHCP_MSG_REQUEST
) {
1266 if (DhcpSb
->DhcpState
== Dhcp4Rebooting
) {
1267 IpAddr
= EFI_IP4 (Config
->ClientAddress
);
1269 } else if (DhcpSb
->DhcpState
== Dhcp4Requesting
) {
1270 ASSERT (SeedHead
!= NULL
);
1271 IpAddr
= EFI_IP4 (SeedHead
->YourAddr
);
1274 } else if (Type
== DHCP_MSG_DECLINE
) {
1275 ASSERT (SeedHead
!= NULL
);
1276 IpAddr
= EFI_IP4 (SeedHead
->YourAddr
);
1280 Buf
= DhcpAppendOption (Buf
, DHCP4_TAG_REQUEST_IP
, 4, (UINT8
*) &IpAddr
);
1284 // Append the Max Message Length option if it isn't a DECLINE
1285 // or RELEASE to direct the server use large messages instead of
1286 // override the BOOTFILE and SERVER fields in the message head.
1288 if ((Type
!= DHCP_MSG_DECLINE
) && (Type
!= DHCP_MSG_RELEASE
)) {
1289 MaxMsg
= HTONS (0xFF00);
1290 Buf
= DhcpAppendOption (Buf
, DHCP4_TAG_MAXMSG
, 2, (UINT8
*) &MaxMsg
);
1294 // Append the user's message if it isn't NULL
1297 Len
= MIN ((UINT32
) AsciiStrLen ((CHAR8
*) Msg
), 255);
1298 Buf
= DhcpAppendOption (Buf
, DHCP4_TAG_MESSAGE
, (UINT16
) Len
, Msg
);
1302 // Append the user configured options
1304 if (DhcpSb
->UserOptionLen
!= 0) {
1305 for (Index
= 0; Index
< Config
->OptionCount
; Index
++) {
1307 // We can't use any option other than the client ID from user
1308 // if it is a DHCP decline or DHCP release .
1310 if (((Type
== DHCP_MSG_DECLINE
) || (Type
== DHCP_MSG_RELEASE
)) &&
1311 (Config
->OptionList
[Index
]->OpCode
!= DHCP4_TAG_CLIENT_ID
)) {
1315 Buf
= DhcpAppendOption (
1317 Config
->OptionList
[Index
]->OpCode
,
1318 Config
->OptionList
[Index
]->Length
,
1319 Config
->OptionList
[Index
]->Data
1324 *(Buf
++) = DHCP4_TAG_EOP
;
1325 Packet
->Length
+= (UINT32
) (Buf
- Packet
->Dhcp4
.Option
);
1328 // OK, the message is built, call the user to override it.
1330 Status
= EFI_SUCCESS
;
1333 if (Type
== DHCP_MSG_DISCOVER
) {
1334 Status
= DhcpCallUser (DhcpSb
, Dhcp4SendDiscover
, Packet
, &NewPacket
);
1336 } else if (Type
== DHCP_MSG_REQUEST
) {
1337 Status
= DhcpCallUser (DhcpSb
, Dhcp4SendRequest
, Packet
, &NewPacket
);
1339 } else if (Type
== DHCP_MSG_DECLINE
) {
1340 Status
= DhcpCallUser (DhcpSb
, Dhcp4SendDecline
, Packet
, &NewPacket
);
1343 if (EFI_ERROR (Status
)) {
1348 if (NewPacket
!= NULL
) {
1354 // Save the Client Address will be sent out
1357 &DhcpSb
->ClientAddressSendOut
[0],
1358 &Packet
->Dhcp4
.Header
.ClientHwAddr
[0],
1359 Packet
->Dhcp4
.Header
.HwAddrLen
1364 // Wrap it into a netbuf then send it.
1366 Frag
.Bulk
= (UINT8
*) &Packet
->Dhcp4
.Header
;
1367 Frag
.Len
= Packet
->Length
;
1368 Wrap
= NetbufFromExt (&Frag
, 1, 0, 0, DhcpReleasePacket
, Packet
);
1372 return EFI_OUT_OF_RESOURCES
;
1376 // Save it as the last sent packet for retransmission
1378 if (DhcpSb
->LastPacket
!= NULL
) {
1379 FreePool (DhcpSb
->LastPacket
);
1382 DhcpSb
->LastPacket
= Packet
;
1383 DhcpSetTransmitTimer (DhcpSb
);
1386 // Broadcast the message, unless we know the server address.
1387 // Use the lease UdpIo port to send the unicast packet.
1389 EndPoint
.RemoteAddr
.Addr
[0] = 0xffffffff;
1390 EndPoint
.LocalAddr
.Addr
[0] = 0;
1391 EndPoint
.RemotePort
= DHCP_SERVER_PORT
;
1392 EndPoint
.LocalPort
= DHCP_CLIENT_PORT
;
1393 UdpIo
= DhcpSb
->UdpIo
;
1395 if ((DhcpSb
->DhcpState
== Dhcp4Renewing
) || (Type
== DHCP_MSG_RELEASE
)) {
1396 EndPoint
.RemoteAddr
.Addr
[0] = DhcpSb
->ServerAddr
;
1397 EndPoint
.LocalAddr
.Addr
[0] = DhcpSb
->ClientAddr
;
1398 UdpIo
= DhcpSb
->LeaseIoPort
;
1401 ASSERT (UdpIo
!= NULL
);
1404 Status
= UdpIoSendDatagram (
1413 if (EFI_ERROR (Status
)) {
1415 return EFI_ACCESS_DENIED
;
1423 Retransmit a saved packet. Only DISCOVER and REQUEST messages
1424 will be retransmitted.
1426 @param[in] DhcpSb The DHCP service instance
1428 @retval EFI_ACCESS_DENIED Failed to transmit packet through UDP port
1429 @retval EFI_SUCCESS The packet is retransmitted.
1434 IN DHCP_SERVICE
*DhcpSb
1438 UDP_END_POINT EndPoint
;
1443 ASSERT (DhcpSb
->LastPacket
!= NULL
);
1446 // For REQUEST message in Dhcp4Requesting state, do not change the secs fields.
1448 if (DhcpSb
->DhcpState
!= Dhcp4Requesting
) {
1449 SetElapsedTime(&DhcpSb
->LastPacket
->Dhcp4
.Header
.Seconds
, DhcpSb
->ActiveChild
);
1453 // Wrap it into a netbuf then send it.
1455 Frag
.Bulk
= (UINT8
*) &DhcpSb
->LastPacket
->Dhcp4
.Header
;
1456 Frag
.Len
= DhcpSb
->LastPacket
->Length
;
1457 Wrap
= NetbufFromExt (&Frag
, 1, 0, 0, DhcpReleasePacket
, DhcpSb
->LastPacket
);
1460 return EFI_OUT_OF_RESOURCES
;
1464 // Broadcast the message, unless we know the server address.
1466 EndPoint
.RemotePort
= DHCP_SERVER_PORT
;
1467 EndPoint
.LocalPort
= DHCP_CLIENT_PORT
;
1468 EndPoint
.RemoteAddr
.Addr
[0] = 0xffffffff;
1469 EndPoint
.LocalAddr
.Addr
[0] = 0;
1470 UdpIo
= DhcpSb
->UdpIo
;
1472 if (DhcpSb
->DhcpState
== Dhcp4Renewing
) {
1473 EndPoint
.RemoteAddr
.Addr
[0] = DhcpSb
->ServerAddr
;
1474 EndPoint
.LocalAddr
.Addr
[0] = DhcpSb
->ClientAddr
;
1475 UdpIo
= DhcpSb
->LeaseIoPort
;
1478 ASSERT (UdpIo
!= NULL
);
1481 Status
= UdpIoSendDatagram (
1490 if (EFI_ERROR (Status
)) {
1492 return EFI_ACCESS_DENIED
;
1500 Each DHCP service has three timer. Two of them are count down timer.
1501 One for the packet retransmission. The other is to collect the offers.
1502 The third timer increaments the lease life which is compared to T1, T2,
1503 and lease to determine the time to renew and rebind the lease.
1504 DhcpOnTimerTick will be called once every second.
1506 @param[in] Event The timer event
1507 @param[in] Context The context, which is the DHCP service instance.
1519 DHCP_SERVICE
*DhcpSb
;
1520 DHCP_PROTOCOL
*Instance
;
1523 DhcpSb
= (DHCP_SERVICE
*) Context
;
1524 Instance
= DhcpSb
->ActiveChild
;
1527 // 0xffff is the maximum supported value for elapsed time according to RFC.
1529 if (Instance
!= NULL
&& Instance
->ElaspedTime
< 0xffff) {
1530 Instance
->ElaspedTime
++;
1534 // Check the retransmit timer
1536 if ((DhcpSb
->PacketToLive
> 0) && (--DhcpSb
->PacketToLive
== 0)) {
1539 // Select offer at each timeout if any offer received.
1541 if (DhcpSb
->DhcpState
== Dhcp4Selecting
&& DhcpSb
->LastOffer
!= NULL
) {
1543 Status
= DhcpChooseOffer (DhcpSb
);
1545 if (EFI_ERROR(Status
)) {
1546 if (DhcpSb
->LastOffer
!= NULL
) {
1547 FreePool (DhcpSb
->LastOffer
);
1548 DhcpSb
->LastOffer
= NULL
;
1555 if (++DhcpSb
->CurRetry
< DhcpSb
->MaxRetries
) {
1557 // Still has another try
1559 DhcpRetransmit (DhcpSb
);
1560 DhcpSetTransmitTimer (DhcpSb
);
1562 } else if (DHCP_CONNECTED (DhcpSb
->DhcpState
)) {
1565 // Retransmission failed, if the DHCP request is initiated by
1566 // user, adjust the current state according to the lease life.
1567 // Otherwise do nothing to wait the lease to timeout
1569 if (DhcpSb
->ExtraRefresh
!= 0) {
1570 Status
= EFI_SUCCESS
;
1572 if (DhcpSb
->LeaseLife
< DhcpSb
->T1
) {
1573 Status
= DhcpSetState (DhcpSb
, Dhcp4Bound
, FALSE
);
1575 } else if (DhcpSb
->LeaseLife
< DhcpSb
->T2
) {
1576 Status
= DhcpSetState (DhcpSb
, Dhcp4Renewing
, FALSE
);
1578 } else if (DhcpSb
->LeaseLife
< DhcpSb
->Lease
) {
1579 Status
= DhcpSetState (DhcpSb
, Dhcp4Rebinding
, FALSE
);
1586 DhcpSb
->IoStatus
= EFI_TIMEOUT
;
1587 DhcpNotifyUser (DhcpSb
, DHCP_NOTIFY_RENEWREBIND
);
1595 // If an address has been acquired, check whether need to
1596 // refresh or whether it has expired.
1598 if (DHCP_CONNECTED (DhcpSb
->DhcpState
)) {
1599 DhcpSb
->LeaseLife
++;
1602 // Don't timeout the lease, only count the life if user is
1603 // requesting extra renew/rebind. Adjust the state after that.
1605 if (DhcpSb
->ExtraRefresh
!= 0) {
1609 if (DhcpSb
->LeaseLife
== DhcpSb
->Lease
) {
1611 // Lease expires, end the session
1615 } else if (DhcpSb
->LeaseLife
== DhcpSb
->T2
) {
1617 // T2 expires, transit to rebinding then send a REQUEST to any server
1619 if (EFI_ERROR (DhcpSetState (DhcpSb
, Dhcp4Rebinding
, TRUE
))) {
1623 if (Instance
!= NULL
) {
1624 Instance
->ElaspedTime
= 0;
1627 Status
= DhcpSendMessage (
1635 if (EFI_ERROR (Status
)) {
1639 } else if (DhcpSb
->LeaseLife
== DhcpSb
->T1
) {
1641 // T1 expires, transit to renewing, then send a REQUEST to the server
1643 if (EFI_ERROR (DhcpSetState (DhcpSb
, Dhcp4Renewing
, TRUE
))) {
1647 if (Instance
!= NULL
) {
1648 Instance
->ElaspedTime
= 0;
1651 Status
= DhcpSendMessage (
1659 if (EFI_ERROR (Status
)) {
1667 // Iterate through all the DhcpSb Children.
1669 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &DhcpSb
->Children
) {
1670 Instance
= NET_LIST_USER_STRUCT (Entry
, DHCP_PROTOCOL
, Link
);
1672 if ((Instance
!= NULL
) && (Instance
->Token
!= NULL
)) {
1673 Instance
->Timeout
--;
1674 if (Instance
->Timeout
== 0) {
1675 PxeDhcpDone (Instance
);
1683 DhcpEndSession (DhcpSb
, EFI_TIMEOUT
);