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
37 IN PXE_DHCP4_PRIVATE_DATA
*Private
,
38 IN DHCP4_PACKET
*tx_pkt
,
39 IN DHCP4_PACKET
*rx_pkt
,
43 EFI_STATUS efi_status
;
44 DHCP4_OP
*msg_type_op
;
48 DHCP4_OP
*lease_time_op
;
52 // Verify parameters. Unused parameters are also touched
53 // to make the compiler happy.
58 if (Private
== NULL
|| rx_pkt
== NULL
) {
63 rx_pkt_size
= rx_pkt_size
;
66 // This must be a DHCP Ack message.
68 magik
= htonl (DHCP4_MAGIK_NUMBER
);
70 if (CompareMem (&rx_pkt
->dhcp4
.magik
, &magik
, 4)) {
74 efi_status
= find_opt (rx_pkt
, DHCP4_MESSAGE_TYPE
, 0, &msg_type_op
);
76 if (EFI_ERROR (efi_status
)) {
80 if (msg_type_op
->len
!= 1) {
84 if (msg_type_op
->data
[0] != DHCP4_MESSAGE_TYPE_ACK
) {
88 // There must be a server identifier.
90 efi_status
= find_opt (rx_pkt
, DHCP4_SERVER_IDENTIFIER
, 0, &srvid_op
);
92 if (EFI_ERROR (efi_status
)) {
96 if (srvid_op
->len
!= 4) {
100 // There should be a renewal time.
101 // If there is not, we will default to the 7/8 of the rebinding time.
103 efi_status
= find_opt (rx_pkt
, DHCP4_RENEWAL_TIME
, 0, &renew_op
);
105 if (EFI_ERROR (efi_status
)) {
107 } else if (renew_op
->len
!= 4) {
111 // There should be a rebinding time.
112 // If there is not, we will default to 7/8 of the lease time.
114 efi_status
= find_opt (rx_pkt
, DHCP4_REBINDING_TIME
, 0, &rebind_op
);
116 if (EFI_ERROR (efi_status
)) {
118 } else if (rebind_op
->len
!= 4) {
122 // There should be a lease time.
123 // If there is not, we will default to one week.
125 efi_status
= find_opt (rx_pkt
, DHCP4_LEASE_TIME
, 0, &lease_time_op
);
127 if (EFI_ERROR (efi_status
)) {
128 lease_time_op
= NULL
;
129 } else if (lease_time_op
->len
!= 4) {
130 lease_time_op
= NULL
;
133 // Packet looks good. Double check the renew, rebind and lease times.
135 CopyMem (&Private
->ServerIp
, srvid_op
->data
, 4);
137 if (renew_op
!= NULL
) {
138 CopyMem (&Private
->RenewTime
, renew_op
->data
, 4);
139 Private
->RenewTime
= htonl (Private
->RenewTime
);
141 Private
->RenewTime
= 0;
144 if (rebind_op
!= NULL
) {
145 CopyMem (&Private
->RebindTime
, rebind_op
->data
, 4);
146 Private
->RebindTime
= htonl (Private
->RebindTime
);
148 Private
->RebindTime
= 0;
151 if (lease_time_op
!= NULL
) {
152 CopyMem (&Private
->LeaseTime
, lease_time_op
->data
, 4);
153 Private
->LeaseTime
= htonl (Private
->LeaseTime
);
155 Private
->LeaseTime
= 0;
158 if (Private
->LeaseTime
< 60) {
159 Private
->LeaseTime
= 7 * 86400;
162 if (Private
->RebindTime
< 52 || Private
->RebindTime
>= Private
->LeaseTime
) {
163 Private
->RebindTime
= Private
->LeaseTime
/ 2 + Private
->LeaseTime
/ 4 + Private
->LeaseTime
/ 8;
166 if (Private
->RenewTime
< 45 || Private
->RenewTime
>= Private
->RebindTime
) {
167 Private
->RenewTime
= Private
->RebindTime
/ 2 + Private
->RebindTime
/ 4 + Private
->RebindTime
/ 8;
173 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
178 IN EFI_PXE_DHCP4_PROTOCOL
*This
,
179 IN UINTN seconds_timeout
,
183 PXE_DHCP4_PRIVATE_DATA
*Private
;
184 EFI_IP_ADDRESS ServerIp
;
185 EFI_IP_ADDRESS client_ip
;
186 EFI_IP_ADDRESS subnet_mask
;
187 EFI_IP_ADDRESS gateway_ip
;
188 DHCP4_PACKET Request
;
191 EFI_STATUS efi_status
;
194 // Check for invalid parameters.
196 if (This
== NULL
|| seconds_timeout
< DHCP4_MIN_SECONDS
|| seconds_timeout
> DHCP4_MAX_SECONDS
) {
197 return EFI_INVALID_PARAMETER
;
200 // Check for proper protocol state.
202 if (This
->Data
== NULL
) {
203 return EFI_NOT_STARTED
;
206 if (!This
->Data
->SelectCompleted
) {
207 return EFI_NOT_READY
;
210 if (This
->Data
->IsBootp
) {
214 if (!This
->Data
->IsAck
) {
215 return EFI_INVALID_PARAMETER
;
218 // Get pointer to instance data.
220 Private
= PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This
);
222 if (Private
== NULL
) {
223 return EFI_INVALID_PARAMETER
;
226 if (Private
->PxeBc
== NULL
) {
227 return EFI_DEVICE_ERROR
;
230 // Copy Discover packet to temporary request packet
231 // to be used for Renew/Rebind operation.
233 CopyMem (&Request
, &This
->Data
->Discover
, sizeof (DHCP4_PACKET
));
235 CopyMem (&Request
.dhcp4
.ciaddr
, &This
->Data
->AckNak
.dhcp4
.yiaddr
, 4);
237 Request
.dhcp4
.flags
= 0; /* Reply does not need to be broadcast. */
240 // Change message type from discover to request.
242 efi_status
= find_opt (&Request
, DHCP4_MESSAGE_TYPE
, 0, &op
);
244 if (EFI_ERROR (efi_status
)) {
245 return EFI_INVALID_PARAMETER
;
249 return EFI_INVALID_PARAMETER
;
252 op
->data
[0] = DHCP4_MESSAGE_TYPE_REQUEST
;
255 // Need a subnet mask.
257 efi_status
= find_opt (
264 if (EFI_ERROR (efi_status
)) {
265 return EFI_INVALID_PARAMETER
;
269 return EFI_INVALID_PARAMETER
;
272 ZeroMem (&subnet_mask
, sizeof (EFI_IP_ADDRESS
));
273 CopyMem (&subnet_mask
, op
->data
, 4);
276 // Need a server IP address (renew) or a broadcast
277 // IP address (rebind).
279 ZeroMem (&gateway_ip
, sizeof (EFI_IP_ADDRESS
));
282 efi_status
= find_opt (
284 DHCP4_SERVER_IDENTIFIER
,
289 if (EFI_ERROR (efi_status
)) {
290 return EFI_INVALID_PARAMETER
;
294 return EFI_INVALID_PARAMETER
;
297 ZeroMem (&ServerIp
, sizeof (EFI_IP_ADDRESS
));
298 CopyMem (&ServerIp
, op
->data
, 4);
303 if (CompareMem (&This
->Data
->AckNak
.dhcp4
.giaddr
, &gateway_ip
, 4)) {
304 CopyMem (&gateway_ip
, &This
->Data
->AckNak
.dhcp4
.giaddr
, 4);
307 SetMem (&ServerIp
, sizeof (EFI_IP_ADDRESS
), 0xFF);
310 // Need a client IP address.
312 ZeroMem (&client_ip
, sizeof (EFI_IP_ADDRESS
));
313 CopyMem (&client_ip
, &Request
.dhcp4
.ciaddr
, 4);
318 efi_status
= gBS
->HandleProtocol (
320 &gEfiPxeDhcp4CallbackProtocolGuid
,
321 (VOID
*) &Private
->callback
324 if (EFI_ERROR (efi_status
)) {
325 Private
->callback
= NULL
;
328 Private
->function
= renew
? EFI_PXE_DHCP4_FUNCTION_RENEW
: EFI_PXE_DHCP4_FUNCTION_REBIND
;
331 // Transimit DHCP request and wait for DHCP ack...
333 efi_status
= tx_rx_udp (
345 if (EFI_ERROR (efi_status
)) {
346 Private
->callback
= NULL
;
350 // Copy server identifier, renewal time and rebinding time
351 // from temporary ack/nak packet into cached ack/nak packet.
353 efi_status
= find_opt (
355 DHCP4_SERVER_IDENTIFIER
,
360 if (!EFI_ERROR (efi_status
)) {
362 CopyMem (op
->data
, &Private
->ServerIp
, 4);
366 efi_status
= find_opt (&This
->Data
->AckNak
, DHCP4_RENEWAL_TIME
, 0, &op
);
368 if (!EFI_ERROR (efi_status
)) {
370 CopyMem (op
->data
, &Private
->RenewTime
, 4);
374 efi_status
= find_opt (&This
->Data
->AckNak
, DHCP4_REBINDING_TIME
, 0, &op
);
376 if (!EFI_ERROR (efi_status
)) {
378 CopyMem (op
->data
, &Private
->RebindTime
, 4);
382 Private
->callback
= NULL
;
386 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
390 IN EFI_PXE_DHCP4_PROTOCOL
*This
,
391 IN UINTN seconds_timeout
394 return renew_rebind (This
, seconds_timeout
, TRUE
);
397 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
401 IN EFI_PXE_DHCP4_PROTOCOL
*This
,
402 IN UINTN seconds_timeout
405 return renew_rebind (This
, seconds_timeout
, FALSE
);
408 /* eof - PxeDhcp4RenewRebind.c */