3 Copyright (c) 2004, 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.
23 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
28 @return -2 = ignore, stop waiting
29 @return -1 = ignore, keep waiting
30 @return 0 = accept, keep waiting
31 @return 1 = accept, stop waiting
35 acknak_verify_renewrebind (
36 IN PXE_DHCP4_PRIVATE_DATA
*Private
,
37 IN DHCP4_PACKET
*tx_pkt
,
38 IN DHCP4_PACKET
*rx_pkt
,
42 EFI_STATUS efi_status
;
43 DHCP4_OP
*msg_type_op
;
47 DHCP4_OP
*lease_time_op
;
51 // Verify parameters. Unused parameters are also touched
52 // to make the compiler happy.
57 if (Private
== NULL
|| rx_pkt
== NULL
) {
62 rx_pkt_size
= rx_pkt_size
;
65 // This must be a DHCP Ack message.
67 magik
= htonl (DHCP4_MAGIK_NUMBER
);
69 if (CompareMem (&rx_pkt
->dhcp4
.magik
, &magik
, 4)) {
73 efi_status
= find_opt (rx_pkt
, DHCP4_MESSAGE_TYPE
, 0, &msg_type_op
);
75 if (EFI_ERROR (efi_status
)) {
79 if (msg_type_op
->len
!= 1) {
83 if (msg_type_op
->data
[0] != DHCP4_MESSAGE_TYPE_ACK
) {
87 // There must be a server identifier.
89 efi_status
= find_opt (rx_pkt
, DHCP4_SERVER_IDENTIFIER
, 0, &srvid_op
);
91 if (EFI_ERROR (efi_status
)) {
95 if (srvid_op
->len
!= 4) {
99 // There should be a renewal time.
100 // If there is not, we will default to the 7/8 of the rebinding time.
102 efi_status
= find_opt (rx_pkt
, DHCP4_RENEWAL_TIME
, 0, &renew_op
);
104 if (EFI_ERROR (efi_status
)) {
106 } else if (renew_op
->len
!= 4) {
110 // There should be a rebinding time.
111 // If there is not, we will default to 7/8 of the lease time.
113 efi_status
= find_opt (rx_pkt
, DHCP4_REBINDING_TIME
, 0, &rebind_op
);
115 if (EFI_ERROR (efi_status
)) {
117 } else if (rebind_op
->len
!= 4) {
121 // There should be a lease time.
122 // If there is not, we will default to one week.
124 efi_status
= find_opt (rx_pkt
, DHCP4_LEASE_TIME
, 0, &lease_time_op
);
126 if (EFI_ERROR (efi_status
)) {
127 lease_time_op
= NULL
;
128 } else if (lease_time_op
->len
!= 4) {
129 lease_time_op
= NULL
;
132 // Packet looks good. Double check the renew, rebind and lease times.
134 CopyMem (&Private
->ServerIp
, srvid_op
->data
, 4);
136 if (renew_op
!= NULL
) {
137 CopyMem (&Private
->RenewTime
, renew_op
->data
, 4);
138 Private
->RenewTime
= htonl (Private
->RenewTime
);
140 Private
->RenewTime
= 0;
143 if (rebind_op
!= NULL
) {
144 CopyMem (&Private
->RebindTime
, rebind_op
->data
, 4);
145 Private
->RebindTime
= htonl (Private
->RebindTime
);
147 Private
->RebindTime
= 0;
150 if (lease_time_op
!= NULL
) {
151 CopyMem (&Private
->LeaseTime
, lease_time_op
->data
, 4);
152 Private
->LeaseTime
= htonl (Private
->LeaseTime
);
154 Private
->LeaseTime
= 0;
157 if (Private
->LeaseTime
< 60) {
158 Private
->LeaseTime
= 7 * 86400;
161 if (Private
->RebindTime
< 52 || Private
->RebindTime
>= Private
->LeaseTime
) {
162 Private
->RebindTime
= Private
->LeaseTime
/ 2 + Private
->LeaseTime
/ 4 + Private
->LeaseTime
/ 8;
165 if (Private
->RenewTime
< 45 || Private
->RenewTime
>= Private
->RebindTime
) {
166 Private
->RenewTime
= Private
->RebindTime
/ 2 + Private
->RebindTime
/ 4 + Private
->RebindTime
/ 8;
172 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
176 IN EFI_PXE_DHCP4_PROTOCOL
*This
,
177 IN UINTN seconds_timeout
,
181 PXE_DHCP4_PRIVATE_DATA
*Private
;
182 EFI_IP_ADDRESS ServerIp
;
183 EFI_IP_ADDRESS client_ip
;
184 EFI_IP_ADDRESS subnet_mask
;
185 EFI_IP_ADDRESS gateway_ip
;
186 DHCP4_PACKET Request
;
189 EFI_STATUS efi_status
;
192 // Check for invalid parameters.
194 if (This
== NULL
|| seconds_timeout
< DHCP4_MIN_SECONDS
|| seconds_timeout
> DHCP4_MAX_SECONDS
) {
195 return EFI_INVALID_PARAMETER
;
198 // Check for proper protocol state.
200 if (This
->Data
== NULL
) {
201 return EFI_NOT_STARTED
;
204 if (!This
->Data
->SelectCompleted
) {
205 return EFI_NOT_READY
;
208 if (This
->Data
->IsBootp
) {
212 if (!This
->Data
->IsAck
) {
213 return EFI_INVALID_PARAMETER
;
216 // Get pointer to instance data.
218 Private
= PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This
);
220 if (Private
== NULL
) {
221 return EFI_INVALID_PARAMETER
;
224 if (Private
->PxeBc
== NULL
) {
225 return EFI_DEVICE_ERROR
;
228 // Copy Discover packet to temporary request packet
229 // to be used for Renew/Rebind operation.
231 CopyMem (&Request
, &This
->Data
->Discover
, sizeof (DHCP4_PACKET
));
233 CopyMem (&Request
.dhcp4
.ciaddr
, &This
->Data
->AckNak
.dhcp4
.yiaddr
, 4);
235 Request
.dhcp4
.flags
= 0; /* Reply does not need to be broadcast. */
238 // Change message type from discover to request.
240 efi_status
= find_opt (&Request
, DHCP4_MESSAGE_TYPE
, 0, &op
);
242 if (EFI_ERROR (efi_status
)) {
243 return EFI_INVALID_PARAMETER
;
247 return EFI_INVALID_PARAMETER
;
250 op
->data
[0] = DHCP4_MESSAGE_TYPE_REQUEST
;
253 // Need a subnet mask.
255 efi_status
= find_opt (
262 if (EFI_ERROR (efi_status
)) {
263 return EFI_INVALID_PARAMETER
;
267 return EFI_INVALID_PARAMETER
;
270 ZeroMem (&subnet_mask
, sizeof (EFI_IP_ADDRESS
));
271 CopyMem (&subnet_mask
, op
->data
, 4);
274 // Need a server IP address (renew) or a broadcast
275 // IP address (rebind).
277 ZeroMem (&gateway_ip
, sizeof (EFI_IP_ADDRESS
));
280 efi_status
= find_opt (
282 DHCP4_SERVER_IDENTIFIER
,
287 if (EFI_ERROR (efi_status
)) {
288 return EFI_INVALID_PARAMETER
;
292 return EFI_INVALID_PARAMETER
;
295 ZeroMem (&ServerIp
, sizeof (EFI_IP_ADDRESS
));
296 CopyMem (&ServerIp
, op
->data
, 4);
301 if (CompareMem (&This
->Data
->AckNak
.dhcp4
.giaddr
, &gateway_ip
, 4)) {
302 CopyMem (&gateway_ip
, &This
->Data
->AckNak
.dhcp4
.giaddr
, 4);
305 SetMem (&ServerIp
, sizeof (EFI_IP_ADDRESS
), 0xFF);
308 // Need a client IP address.
310 ZeroMem (&client_ip
, sizeof (EFI_IP_ADDRESS
));
311 CopyMem (&client_ip
, &Request
.dhcp4
.ciaddr
, 4);
316 efi_status
= gBS
->HandleProtocol (
318 &gEfiPxeDhcp4CallbackProtocolGuid
,
319 (VOID
*) &Private
->callback
322 if (EFI_ERROR (efi_status
)) {
323 Private
->callback
= NULL
;
326 Private
->function
= renew
? EFI_PXE_DHCP4_FUNCTION_RENEW
: EFI_PXE_DHCP4_FUNCTION_REBIND
;
329 // Transimit DHCP request and wait for DHCP ack...
331 efi_status
= tx_rx_udp (
339 &acknak_verify_renewrebind
,
343 if (EFI_ERROR (efi_status
)) {
344 Private
->callback
= NULL
;
348 // Copy server identifier, renewal time and rebinding time
349 // from temporary ack/nak packet into cached ack/nak packet.
351 efi_status
= find_opt (
353 DHCP4_SERVER_IDENTIFIER
,
358 if (!EFI_ERROR (efi_status
)) {
360 CopyMem (op
->data
, &Private
->ServerIp
, 4);
364 efi_status
= find_opt (&This
->Data
->AckNak
, DHCP4_RENEWAL_TIME
, 0, &op
);
366 if (!EFI_ERROR (efi_status
)) {
368 CopyMem (op
->data
, &Private
->RenewTime
, 4);
372 efi_status
= find_opt (&This
->Data
->AckNak
, DHCP4_REBINDING_TIME
, 0, &op
);
374 if (!EFI_ERROR (efi_status
)) {
376 CopyMem (op
->data
, &Private
->RebindTime
, 4);
380 Private
->callback
= NULL
;
384 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
388 IN EFI_PXE_DHCP4_PROTOCOL
*This
,
389 IN UINTN seconds_timeout
392 return renew_rebind (This
, seconds_timeout
, TRUE
);
395 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
399 IN EFI_PXE_DHCP4_PROTOCOL
*This
,
400 IN UINTN seconds_timeout
403 return renew_rebind (This
, seconds_timeout
, FALSE
);
406 /* eof - PxeDhcp4RenewRebind.c */