]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/Dhcp4Dxe/Dhcp4Impl.c
NetworkPkg: Apply uncrustify changes
[mirror_edk2.git] / NetworkPkg / Dhcp4Dxe / Dhcp4Impl.c
CommitLineData
772db4bb 1/** @file\r
3e8c18da 2 This file implement the EFI_DHCP4_PROTOCOL interface.\r
e2851998 3\r
0ba795d2 4Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
772db4bb 6\r
772db4bb 7**/\r
8\r
772db4bb 9#include "Dhcp4Impl.h"\r
10\r
f9204641 11/**\r
12 Returns the current operating mode and cached data packet for the EFI DHCPv4 Protocol driver.\r
e2851998 13\r
f9204641 14 The GetModeData() function returns the current operating mode and cached data\r
15 packet for the EFI DHCPv4 Protocol driver.\r
16\r
3e8c18da 17 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance.\r
18 @param[out] Dhcp4ModeData Pointer to storage for the EFI_DHCP4_MODE_DATA structure.\r
f9204641 19\r
20 @retval EFI_SUCCESS The mode data was returned.\r
21 @retval EFI_INVALID_PARAMETER This is NULL.\r
22\r
23**/\r
24EFI_STATUS\r
25EFIAPI\r
26EfiDhcp4GetModeData (\r
d1050b9d
MK
27 IN EFI_DHCP4_PROTOCOL *This,\r
28 OUT EFI_DHCP4_MODE_DATA *Dhcp4ModeData\r
f9204641 29 );\r
30\r
31/**\r
32 Initializes, changes, or resets the operational settings for the EFI DHCPv4 Protocol driver.\r
33\r
34 The Configure() function is used to initialize, change, or reset the operational\r
35 settings of the EFI DHCPv4 Protocol driver for the communication device on which\r
36 the EFI DHCPv4 Service Binding Protocol is installed. This function can be\r
37 successfully called only if both of the following are true:\r
38 * This instance of the EFI DHCPv4 Protocol driver is in the Dhcp4Stopped, Dhcp4Init,\r
39 Dhcp4InitReboot, or Dhcp4Bound states.\r
40 * No other EFI DHCPv4 Protocol driver instance that is controlled by this EFI\r
41 DHCPv4 Service Binding Protocol driver instance has configured this EFI DHCPv4\r
42 Protocol driver.\r
43 When this driver is in the Dhcp4Stopped state, it can transfer into one of the\r
44 following two possible initial states:\r
45 * Dhcp4Init\r
46 * Dhcp4InitReboot\r
47 The driver can transfer into these states by calling Configure() with a non-NULL\r
48 Dhcp4CfgData. The driver will transfer into the appropriate state based on the\r
49 supplied client network address in the ClientAddress parameter and DHCP options\r
50 in the OptionList parameter as described in RFC 2131.\r
51 When Configure() is called successfully while Dhcp4CfgData is set to NULL, the\r
52 default configuring data will be reset in the EFI DHCPv4 Protocol driver and\r
53 the state of the EFI DHCPv4 Protocol driver will not be changed. If one instance\r
54 wants to make it possible for another instance to configure the EFI DHCPv4 Protocol\r
55 driver, it must call this function with Dhcp4CfgData set to NULL.\r
56\r
3e8c18da 57 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance.\r
58 @param[in] Dhcp4CfgData Pointer to the EFI_DHCP4_CONFIG_DATA.\r
f9204641 59\r
60 @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the Dhcp4Init or\r
61 Dhcp4InitReboot state, if the original state of this driver\r
62 was Dhcp4Stopped and the value of Dhcp4CfgData was\r
63 not NULL. Otherwise, the state was left unchanged.\r
64 @retval EFI_ACCESS_DENIED This instance of the EFI DHCPv4 Protocol driver was not in the\r
65 Dhcp4Stopped, Dhcp4Init, Dhcp4InitReboot, or Dhcp4Bound state;\r
c194ccca 66 Or another instance of this EFI DHCPv4 Protocol driver is already\r
f9204641 67 in a valid configured state.\r
68 @retval EFI_INVALID_PARAMETER Some parameter is NULL.\r
69 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
70 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
71\r
72**/\r
73EFI_STATUS\r
74EFIAPI\r
75EfiDhcp4Configure (\r
76 IN EFI_DHCP4_PROTOCOL *This,\r
77 IN EFI_DHCP4_CONFIG_DATA *Dhcp4CfgData OPTIONAL\r
e2851998 78 );\r
f9204641 79\r
80/**\r
81 Starts the DHCP configuration process.\r
82\r
83 The Start() function starts the DHCP configuration process. This function can\r
84 be called only when the EFI DHCPv4 Protocol driver is in the Dhcp4Init or\r
85 Dhcp4InitReboot state.\r
86 If the DHCP process completes successfully, the state of the EFI DHCPv4 Protocol\r
87 driver will be transferred through Dhcp4Selecting and Dhcp4Requesting to the\r
88 Dhcp4Bound state. The CompletionEvent will then be signaled if it is not NULL.\r
89 If the process aborts, either by the user or by some unexpected network error,\r
90 the state is restored to the Dhcp4Init state. The Start() function can be called\r
91 again to restart the process.\r
92 Refer to RFC 2131 for precise state transitions during this process. At the\r
93 time when each event occurs in this process, the callback function that was set\r
94 by EFI_DHCP4_PROTOCOL.Configure() will be called and the user can take this\r
95 opportunity to control the process.\r
e2851998 96\r
3e8c18da 97 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance.\r
98 @param[in] CompletionEvent If not NULL, indicates the event that will be signaled when the\r
99 EFI DHCPv4 Protocol driver is transferred into the\r
100 Dhcp4Bound state or when the DHCP process is aborted.\r
101 EFI_DHCP4_PROTOCOL.GetModeData() can be called to\r
102 check the completion status. If NULL,\r
103 EFI_DHCP4_PROTOCOL.Start() will wait until the driver\r
104 is transferred into the Dhcp4Bound state or the process fails.\r
f9204641 105\r
106 @retval EFI_SUCCESS The DHCP configuration process has started, or it has completed\r
107 when CompletionEvent is NULL.\r
108 @retval EFI_NOT_STARTED The EFI DHCPv4 Protocol driver is in the Dhcp4Stopped\r
109 state. EFI_DHCP4_PROTOCOL. Configure() needs to be called.\r
110 @retval EFI_INVALID_PARAMETER This is NULL.\r
111 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
112 @retval EFI_TIMEOUT The DHCP configuration process failed because no response was\r
113 received from the server within the specified timeout value.\r
114 @retval EFI_ABORTED The user aborted the DHCP process.\r
115 @retval EFI_ALREADY_STARTED Some other EFI DHCPv4 Protocol instance already started the\r
116 DHCP process.\r
117 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
118\r
119**/\r
120EFI_STATUS\r
121EFIAPI\r
122EfiDhcp4Start (\r
d1050b9d
MK
123 IN EFI_DHCP4_PROTOCOL *This,\r
124 IN EFI_EVENT CompletionEvent OPTIONAL\r
f9204641 125 );\r
126\r
127/**\r
128 Extends the lease time by sending a request packet.\r
e2851998 129\r
f9204641 130 The RenewRebind() function is used to manually extend the lease time when the\r
131 EFI DHCPv4 Protocol driver is in the Dhcp4Bound state and the lease time has\r
132 not expired yet. This function will send a request packet to the previously\r
133 found server (or to any server when RebindRequest is TRUE) and transfer the\r
134 state into the Dhcp4Renewing state (or Dhcp4Rebinding when RebindingRequest is\r
135 TRUE). When a response is received, the state is returned to Dhcp4Bound.\r
136 If no response is received before the try count is exceeded (the RequestTryCount\r
137 field that is specified in EFI_DHCP4_CONFIG_DATA) but before the lease time that\r
138 was issued by the previous server expires, the driver will return to the Dhcp4Bound\r
139 state and the previous configuration is restored. The outgoing and incoming packets\r
140 can be captured by the EFI_DHCP4_CALLBACK function.\r
141\r
3e8c18da 142 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance.\r
143 @param[in] RebindRequest If TRUE, this function broadcasts the request packets and enters\r
144 the Dhcp4Rebinding state. Otherwise, it sends a unicast\r
145 request packet and enters the Dhcp4Renewing state.\r
146 @param[in] CompletionEvent If not NULL, this event is signaled when the renew/rebind phase\r
147 completes or some error occurs.\r
148 EFI_DHCP4_PROTOCOL.GetModeData() can be called to\r
149 check the completion status. If NULL,\r
150 EFI_DHCP4_PROTOCOL.RenewRebind() will busy-wait\r
151 until the DHCP process finishes.\r
f9204641 152\r
153 @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the\r
154 Dhcp4Renewing state or is back to the Dhcp4Bound state.\r
155 @retval EFI_NOT_STARTED The EFI DHCPv4 Protocol driver is in the Dhcp4Stopped\r
156 state. EFI_DHCP4_PROTOCOL.Configure() needs to\r
157 be called.\r
158 @retval EFI_INVALID_PARAMETER This is NULL.\r
159 @retval EFI_TIMEOUT There was no response from the server when the try count was\r
160 exceeded.\r
161 @retval EFI_ACCESS_DENIED The driver is not in the Dhcp4Bound state.\r
162 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
163\r
164**/\r
165EFI_STATUS\r
166EFIAPI\r
167EfiDhcp4RenewRebind (\r
d1050b9d
MK
168 IN EFI_DHCP4_PROTOCOL *This,\r
169 IN BOOLEAN RebindRequest,\r
170 IN EFI_EVENT CompletionEvent OPTIONAL\r
f9204641 171 );\r
172\r
173/**\r
174 Releases the current address configuration.\r
175\r
176 The Release() function releases the current configured IP address by doing either\r
177 of the following:\r
178 * Sending a DHCPRELEASE packet when the EFI DHCPv4 Protocol driver is in the\r
179 Dhcp4Bound state\r
180 * Setting the previously assigned IP address that was provided with the\r
181 EFI_DHCP4_PROTOCOL.Configure() function to 0.0.0.0 when the driver is in\r
182 Dhcp4InitReboot state\r
183 After a successful call to this function, the EFI DHCPv4 Protocol driver returns\r
184 to the Dhcp4Init state and any subsequent incoming packets will be discarded silently.\r
185\r
3e8c18da 186 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance.\r
f9204641 187\r
188 @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the Dhcp4Init phase.\r
189 @retval EFI_INVALID_PARAMETER This is NULL.\r
190 @retval EFI_ACCESS_DENIED The EFI DHCPv4 Protocol driver is not Dhcp4InitReboot state.\r
191 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
192\r
193**/\r
194EFI_STATUS\r
195EFIAPI\r
196EfiDhcp4Release (\r
d1050b9d 197 IN EFI_DHCP4_PROTOCOL *This\r
f9204641 198 );\r
199\r
200/**\r
201 Stops the current address configuration.\r
e2851998 202\r
f9204641 203 The Stop() function is used to stop the DHCP configuration process. After this\r
204 function is called successfully, the EFI DHCPv4 Protocol driver is transferred\r
205 into the Dhcp4Stopped state. EFI_DHCP4_PROTOCOL.Configure() needs to be called\r
206 before DHCP configuration process can be started again. This function can be\r
207 called when the EFI DHCPv4 Protocol driver is in any state.\r
208\r
3e8c18da 209 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance.\r
f9204641 210\r
211 @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the Dhcp4Stopped phase.\r
212 @retval EFI_INVALID_PARAMETER This is NULL.\r
213\r
214**/\r
215EFI_STATUS\r
216EFIAPI\r
217EfiDhcp4Stop (\r
d1050b9d 218 IN EFI_DHCP4_PROTOCOL *This\r
f9204641 219 );\r
220\r
221/**\r
222 Builds a DHCP packet, given the options to be appended or deleted or replaced.\r
223\r
224 The Build() function is used to assemble a new packet from the original packet\r
225 by replacing or deleting existing options or appending new options. This function\r
226 does not change any state of the EFI DHCPv4 Protocol driver and can be used at\r
227 any time.\r
228\r
3e8c18da 229 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance.\r
230 @param[in] SeedPacket Initial packet to be used as a base for building new packet.\r
231 @param[in] DeleteCount Number of opcodes in the DeleteList.\r
232 @param[in] DeleteList List of opcodes to be deleted from the seed packet.\r
233 Ignored if DeleteCount is zero.\r
234 @param[in] AppendCount Number of entries in the OptionList.\r
235 @param[in] AppendList Pointer to a DHCP option list to be appended to SeedPacket.\r
236 If SeedPacket also contains options in this list, they are\r
237 replaced by new options (except pad option). Ignored if\r
238 AppendCount is zero. Type EFI_DHCP4_PACKET_OPTION\r
239 @param[out] NewPacket Pointer to storage for the pointer to the new allocated packet.\r
240 Use the EFI Boot Service FreePool() on the resulting pointer\r
241 when done with the packet.\r
f9204641 242\r
243 @retval EFI_SUCCESS The new packet was built.\r
244 @retval EFI_OUT_OF_RESOURCES Storage for the new packet could not be allocated.\r
245 @retval EFI_INVALID_PARAMETER Some parameter is NULL.\r
246\r
247**/\r
248EFI_STATUS\r
249EFIAPI\r
250EfiDhcp4Build (\r
251 IN EFI_DHCP4_PROTOCOL *This,\r
252 IN EFI_DHCP4_PACKET *SeedPacket,\r
253 IN UINT32 DeleteCount,\r
254 IN UINT8 *DeleteList OPTIONAL,\r
255 IN UINT32 AppendCount,\r
256 IN EFI_DHCP4_PACKET_OPTION *AppendList[] OPTIONAL,\r
257 OUT EFI_DHCP4_PACKET **NewPacket\r
258 );\r
e2851998 259\r
3e8c18da 260/**\r
f9204641 261 Transmits a DHCP formatted packet and optionally waits for responses.\r
e2851998 262\r
f9204641 263 The TransmitReceive() function is used to transmit a DHCP packet and optionally\r
264 wait for the response from servers. This function does not change the state of\r
265 the EFI DHCPv4 Protocol driver and thus can be used at any time.\r
266\r
3e8c18da 267 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance.\r
268 @param[in] Token Pointer to the EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN structure.\r
f9204641 269\r
270 @retval EFI_SUCCESS The packet was successfully queued for transmission.\r
271 @retval EFI_INVALID_PARAMETER Some parameter is NULL.\r
272 @retval EFI_NOT_READY The previous call to this function has not finished yet. Try to call\r
273 this function after collection process completes.\r
274 @retval EFI_NO_MAPPING The default station address is not available yet.\r
275 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
276 @retval Others Some other unexpected error occurred.\r
277\r
278**/\r
279EFI_STATUS\r
280EFIAPI\r
281EfiDhcp4TransmitReceive (\r
282 IN EFI_DHCP4_PROTOCOL *This,\r
283 IN EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN *Token\r
284 );\r
285\r
286/**\r
287 Parses the packed DHCP option data.\r
e2851998 288\r
f9204641 289 The Parse() function is used to retrieve the option list from a DHCP packet.\r
51195fbe 290 If *OptionCount isn't zero, and there is enough space for all the DHCP options\r
f9204641 291 in the Packet, each element of PacketOptionList is set to point to somewhere in\r
292 the Packet->Dhcp4.Option where a new DHCP option begins. If RFC3396 is supported,\r
293 the caller should reassemble the parsed DHCP options to get the finial result.\r
51195fbe 294 If *OptionCount is zero or there isn't enough space for all of them, the number\r
f9204641 295 of DHCP options in the Packet is returned in OptionCount.\r
296\r
297 @param This Pointer to the EFI_DHCP4_PROTOCOL instance.\r
298 @param Packet Pointer to packet to be parsed.\r
299 @param OptionCount On input, the number of entries in the PacketOptionList.\r
300 On output, the number of entries that were written into the\r
301 PacketOptionList.\r
302 @param PacketOptionList List of packet option entries to be filled in. End option or pad\r
303 options are not included.\r
304\r
305 @retval EFI_SUCCESS The packet was successfully parsed.\r
306 @retval EFI_INVALID_PARAMETER Some parameter is NULL.\r
307 @retval EFI_BUFFER_TOO_SMALL One or more of the following conditions is TRUE:\r
308 1) *OptionCount is smaller than the number of options that\r
309 were found in the Packet.\r
310 2) PacketOptionList is NULL.\r
311\r
312**/\r
313EFI_STATUS\r
314EFIAPI\r
315EfiDhcp4Parse (\r
d1050b9d
MK
316 IN EFI_DHCP4_PROTOCOL *This,\r
317 IN EFI_DHCP4_PACKET *Packet,\r
318 IN OUT UINT32 *OptionCount,\r
319 OUT EFI_DHCP4_PACKET_OPTION *PacketOptionList[] OPTIONAL\r
f9204641 320 );\r
321\r
322EFI_DHCP4_PROTOCOL mDhcp4ProtocolTemplate = {\r
323 EfiDhcp4GetModeData,\r
324 EfiDhcp4Configure,\r
325 EfiDhcp4Start,\r
326 EfiDhcp4RenewRebind,\r
327 EfiDhcp4Release,\r
328 EfiDhcp4Stop,\r
329 EfiDhcp4Build,\r
330 EfiDhcp4TransmitReceive,\r
331 EfiDhcp4Parse\r
332};\r
772db4bb 333\r
334/**\r
f9204641 335 Returns the current operating mode and cached data packet for the EFI DHCPv4 Protocol driver.\r
e2851998 336\r
f9204641 337 The GetModeData() function returns the current operating mode and cached data\r
338 packet for the EFI DHCPv4 Protocol driver.\r
772db4bb 339\r
3e8c18da 340 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance.\r
341 @param[out] Dhcp4ModeData Pointer to storage for the EFI_DHCP4_MODE_DATA structure.\r
772db4bb 342\r
f9204641 343 @retval EFI_SUCCESS The mode data was returned.\r
344 @retval EFI_INVALID_PARAMETER This is NULL.\r
772db4bb 345\r
346**/\r
772db4bb 347EFI_STATUS\r
348EFIAPI\r
349EfiDhcp4GetModeData (\r
d1050b9d
MK
350 IN EFI_DHCP4_PROTOCOL *This,\r
351 OUT EFI_DHCP4_MODE_DATA *Dhcp4ModeData\r
772db4bb 352 )\r
353{\r
d1050b9d
MK
354 DHCP_PROTOCOL *Instance;\r
355 DHCP_SERVICE *DhcpSb;\r
356 DHCP_PARAMETER *Para;\r
357 EFI_TPL OldTpl;\r
358 IP4_ADDR Ip;\r
772db4bb 359\r
360 //\r
361 // First validate the parameters.\r
362 //\r
363 if ((This == NULL) || (Dhcp4ModeData == NULL)) {\r
364 return EFI_INVALID_PARAMETER;\r
365 }\r
366\r
367 Instance = DHCP_INSTANCE_FROM_THIS (This);\r
982a9eae 368\r
d1050b9d
MK
369 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
370 DhcpSb = Instance->Service;\r
772db4bb 371\r
372 //\r
373 // Caller can use GetModeData to retrieve current DHCP states\r
374 // no matter whether it is the active child or not.\r
375 //\r
d1050b9d 376 Dhcp4ModeData->State = (EFI_DHCP4_STATE)DhcpSb->DhcpState;\r
687a2e5f 377 CopyMem (&Dhcp4ModeData->ConfigData, &DhcpSb->ActiveConfig, sizeof (Dhcp4ModeData->ConfigData));\r
378 CopyMem (&Dhcp4ModeData->ClientMacAddress, &DhcpSb->Mac, sizeof (Dhcp4ModeData->ClientMacAddress));\r
772db4bb 379\r
380 Ip = HTONL (DhcpSb->ClientAddr);\r
e48e37fc 381 CopyMem (&Dhcp4ModeData->ClientAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
772db4bb 382\r
383 Ip = HTONL (DhcpSb->Netmask);\r
e48e37fc 384 CopyMem (&Dhcp4ModeData->SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
772db4bb 385\r
386 Ip = HTONL (DhcpSb->ServerAddr);\r
e48e37fc 387 CopyMem (&Dhcp4ModeData->ServerAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
772db4bb 388\r
389 Para = DhcpSb->Para;\r
390\r
391 if (Para != NULL) {\r
392 Ip = HTONL (Para->Router);\r
e48e37fc 393 CopyMem (&Dhcp4ModeData->RouterAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
f9204641 394 Dhcp4ModeData->LeaseTime = Para->Lease;\r
772db4bb 395 } else {\r
e48e37fc 396 ZeroMem (&Dhcp4ModeData->RouterAddress, sizeof (EFI_IPv4_ADDRESS));\r
f9204641 397 Dhcp4ModeData->LeaseTime = 0xffffffff;\r
772db4bb 398 }\r
399\r
400 Dhcp4ModeData->ReplyPacket = DhcpSb->Selected;\r
401\r
e48e37fc 402 gBS->RestoreTPL (OldTpl);\r
772db4bb 403 return EFI_SUCCESS;\r
404}\r
405\r
772db4bb 406/**\r
407 Free the resource related to the configure parameters.\r
408 DHCP driver will make a copy of the user's configure\r
409 such as the time out value.\r
410\r
411 @param Config The DHCP configure data\r
412\r
772db4bb 413**/\r
414VOID\r
415DhcpCleanConfigure (\r
f9204641 416 IN OUT EFI_DHCP4_CONFIG_DATA *Config\r
772db4bb 417 )\r
418{\r
d1050b9d 419 UINT32 Index;\r
772db4bb 420\r
421 if (Config->DiscoverTimeout != NULL) {\r
a4df47f1 422 FreePool (Config->DiscoverTimeout);\r
772db4bb 423 }\r
424\r
425 if (Config->RequestTimeout != NULL) {\r
a4df47f1 426 FreePool (Config->RequestTimeout);\r
772db4bb 427 }\r
428\r
429 if (Config->OptionList != NULL) {\r
430 for (Index = 0; Index < Config->OptionCount; Index++) {\r
431 if (Config->OptionList[Index] != NULL) {\r
a4df47f1 432 FreePool (Config->OptionList[Index]);\r
772db4bb 433 }\r
434 }\r
435\r
a4df47f1 436 FreePool (Config->OptionList);\r
772db4bb 437 }\r
438\r
e48e37fc 439 ZeroMem (Config, sizeof (EFI_DHCP4_CONFIG_DATA));\r
772db4bb 440}\r
441\r
772db4bb 442/**\r
443 Allocate memory for configure parameter such as timeout value for Dst,\r
444 then copy the configure parameter from Src to Dst.\r
445\r
3e8c18da 446 @param[out] Dst The destination DHCP configure data.\r
447 @param[in] Src The source DHCP configure data.\r
772db4bb 448\r
449 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
450 @retval EFI_SUCCESS The configure is copied.\r
451\r
452**/\r
453EFI_STATUS\r
454DhcpCopyConfigure (\r
f9204641 455 OUT EFI_DHCP4_CONFIG_DATA *Dst,\r
456 IN EFI_DHCP4_CONFIG_DATA *Src\r
772db4bb 457 )\r
458{\r
d1050b9d
MK
459 EFI_DHCP4_PACKET_OPTION **DstOptions;\r
460 EFI_DHCP4_PACKET_OPTION **SrcOptions;\r
461 UINTN Len;\r
462 UINT32 Index;\r
772db4bb 463\r
72030458 464 CopyMem (Dst, Src, sizeof (*Dst));\r
d1050b9d
MK
465 Dst->DiscoverTimeout = NULL;\r
466 Dst->RequestTimeout = NULL;\r
467 Dst->OptionList = NULL;\r
772db4bb 468\r
469 //\r
470 // Allocate a memory then copy DiscoverTimeout to it\r
471 //\r
472 if (Src->DiscoverTimeout != NULL) {\r
d1050b9d
MK
473 Len = Src->DiscoverTryCount * sizeof (UINT32);\r
474 Dst->DiscoverTimeout = AllocatePool (Len);\r
772db4bb 475\r
476 if (Dst->DiscoverTimeout == NULL) {\r
477 return EFI_OUT_OF_RESOURCES;\r
478 }\r
479\r
480 for (Index = 0; Index < Src->DiscoverTryCount; Index++) {\r
36ee91ca 481 Dst->DiscoverTimeout[Index] = MAX (Src->DiscoverTimeout[Index], 1);\r
772db4bb 482 }\r
483 }\r
484\r
485 //\r
486 // Allocate a memory then copy RequestTimeout to it\r
487 //\r
488 if (Src->RequestTimeout != NULL) {\r
489 Len = Src->RequestTryCount * sizeof (UINT32);\r
e48e37fc 490 Dst->RequestTimeout = AllocatePool (Len);\r
772db4bb 491\r
492 if (Dst->RequestTimeout == NULL) {\r
493 goto ON_ERROR;\r
494 }\r
495\r
496 for (Index = 0; Index < Src->RequestTryCount; Index++) {\r
36ee91ca 497 Dst->RequestTimeout[Index] = MAX (Src->RequestTimeout[Index], 1);\r
772db4bb 498 }\r
499 }\r
500\r
501 //\r
502 // Allocate an array of dhcp option point, then allocate memory\r
503 // for each option and copy the source option to it\r
504 //\r
505 if (Src->OptionList != NULL) {\r
506 Len = Src->OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *);\r
e48e37fc 507 Dst->OptionList = AllocateZeroPool (Len);\r
772db4bb 508\r
509 if (Dst->OptionList == NULL) {\r
510 goto ON_ERROR;\r
511 }\r
512\r
d1050b9d
MK
513 DstOptions = Dst->OptionList;\r
514 SrcOptions = Src->OptionList;\r
772db4bb 515\r
516 for (Index = 0; Index < Src->OptionCount; Index++) {\r
36ee91ca 517 Len = sizeof (EFI_DHCP4_PACKET_OPTION) + MAX (SrcOptions[Index]->Length - 1, 0);\r
772db4bb 518\r
e48e37fc 519 DstOptions[Index] = AllocatePool (Len);\r
772db4bb 520\r
521 if (DstOptions[Index] == NULL) {\r
522 goto ON_ERROR;\r
523 }\r
524\r
e48e37fc 525 CopyMem (DstOptions[Index], SrcOptions[Index], Len);\r
772db4bb 526 }\r
527 }\r
528\r
529 return EFI_SUCCESS;\r
530\r
531ON_ERROR:\r
532 DhcpCleanConfigure (Dst);\r
533 return EFI_OUT_OF_RESOURCES;\r
534}\r
535\r
772db4bb 536/**\r
537 Give up the control of the DHCP service to let other child\r
538 resume. Don't change the service's DHCP state and the Client\r
539 address and option list configure as required by RFC2131.\r
540\r
541 @param DhcpSb The DHCP service instance.\r
542\r
772db4bb 543**/\r
544VOID\r
545DhcpYieldControl (\r
d1050b9d 546 IN DHCP_SERVICE *DhcpSb\r
772db4bb 547 )\r
548{\r
d1050b9d 549 EFI_DHCP4_CONFIG_DATA *Config;\r
772db4bb 550\r
d1050b9d 551 Config = &DhcpSb->ActiveConfig;\r
772db4bb 552\r
d1050b9d
MK
553 DhcpSb->ServiceState = DHCP_UNCONFIGED;\r
554 DhcpSb->ActiveChild = NULL;\r
772db4bb 555\r
556 if (Config->DiscoverTimeout != NULL) {\r
a4df47f1 557 FreePool (Config->DiscoverTimeout);\r
772db4bb 558\r
d1050b9d
MK
559 Config->DiscoverTryCount = 0;\r
560 Config->DiscoverTimeout = NULL;\r
772db4bb 561 }\r
562\r
563 if (Config->RequestTimeout != NULL) {\r
a4df47f1 564 FreePool (Config->RequestTimeout);\r
772db4bb 565\r
566 Config->RequestTryCount = 0;\r
567 Config->RequestTimeout = NULL;\r
568 }\r
569\r
570 Config->Dhcp4Callback = NULL;\r
571 Config->CallbackContext = NULL;\r
572}\r
573\r
772db4bb 574/**\r
f9204641 575 Initializes, changes, or resets the operational settings for the EFI DHCPv4 Protocol driver.\r
576\r
577 The Configure() function is used to initialize, change, or reset the operational\r
578 settings of the EFI DHCPv4 Protocol driver for the communication device on which\r
579 the EFI DHCPv4 Service Binding Protocol is installed. This function can be\r
580 successfully called only if both of the following are true:\r
581 * This instance of the EFI DHCPv4 Protocol driver is in the Dhcp4Stopped, Dhcp4Init,\r
582 Dhcp4InitReboot, or Dhcp4Bound states.\r
583 * No other EFI DHCPv4 Protocol driver instance that is controlled by this EFI\r
584 DHCPv4 Service Binding Protocol driver instance has configured this EFI DHCPv4\r
585 Protocol driver.\r
586 When this driver is in the Dhcp4Stopped state, it can transfer into one of the\r
587 following two possible initial states:\r
588 * Dhcp4Init\r
589 * Dhcp4InitReboot\r
590 The driver can transfer into these states by calling Configure() with a non-NULL\r
591 Dhcp4CfgData. The driver will transfer into the appropriate state based on the\r
592 supplied client network address in the ClientAddress parameter and DHCP options\r
593 in the OptionList parameter as described in RFC 2131.\r
594 When Configure() is called successfully while Dhcp4CfgData is set to NULL, the\r
595 default configuring data will be reset in the EFI DHCPv4 Protocol driver and\r
596 the state of the EFI DHCPv4 Protocol driver will not be changed. If one instance\r
597 wants to make it possible for another instance to configure the EFI DHCPv4 Protocol\r
598 driver, it must call this function with Dhcp4CfgData set to NULL.\r
599\r
3e8c18da 600 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance.\r
601 @param[in] Dhcp4CfgData Pointer to the EFI_DHCP4_CONFIG_DATA.\r
f9204641 602\r
603 @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the Dhcp4Init or\r
604 Dhcp4InitReboot state, if the original state of this driver\r
605 was Dhcp4Stopped and the value of Dhcp4CfgData was\r
606 not NULL. Otherwise, the state was left unchanged.\r
607 @retval EFI_ACCESS_DENIED This instance of the EFI DHCPv4 Protocol driver was not in the\r
608 Dhcp4Stopped, Dhcp4Init, Dhcp4InitReboot, or Dhcp4Bound state;\r
c194ccca 609 Or another instance of this EFI DHCPv4 Protocol driver is already\r
f9204641 610 in a valid configured state.\r
611 @retval EFI_INVALID_PARAMETER Some parameter is NULL.\r
612 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
613 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
772db4bb 614\r
615**/\r
772db4bb 616EFI_STATUS\r
617EFIAPI\r
618EfiDhcp4Configure (\r
619 IN EFI_DHCP4_PROTOCOL *This,\r
620 IN EFI_DHCP4_CONFIG_DATA *Dhcp4CfgData OPTIONAL\r
621 )\r
622{\r
d1050b9d
MK
623 EFI_DHCP4_CONFIG_DATA *Config;\r
624 DHCP_PROTOCOL *Instance;\r
625 DHCP_SERVICE *DhcpSb;\r
626 EFI_STATUS Status;\r
627 EFI_TPL OldTpl;\r
628 UINT32 Index;\r
629 IP4_ADDR Ip;\r
772db4bb 630\r
631 //\r
632 // First validate the parameters\r
633 //\r
634 if (This == NULL) {\r
635 return EFI_INVALID_PARAMETER;\r
636 }\r
637\r
638 if (Dhcp4CfgData != NULL) {\r
e2851998 639 if ((Dhcp4CfgData->DiscoverTryCount != 0) && (Dhcp4CfgData->DiscoverTimeout == NULL)) {\r
772db4bb 640 return EFI_INVALID_PARAMETER;\r
641 }\r
642\r
e2851998 643 if ((Dhcp4CfgData->RequestTryCount != 0) && (Dhcp4CfgData->RequestTimeout == NULL)) {\r
772db4bb 644 return EFI_INVALID_PARAMETER;\r
645 }\r
646\r
e2851998 647 if ((Dhcp4CfgData->OptionCount != 0) && (Dhcp4CfgData->OptionList == NULL)) {\r
772db4bb 648 return EFI_INVALID_PARAMETER;\r
649 }\r
650\r
e48e37fc 651 CopyMem (&Ip, &Dhcp4CfgData->ClientAddress, sizeof (IP4_ADDR));\r
d1050b9d 652 if (IP4_IS_LOCAL_BROADCAST (NTOHL (Ip))) {\r
772db4bb 653 return EFI_INVALID_PARAMETER;\r
654 }\r
655 }\r
656\r
657 Instance = DHCP_INSTANCE_FROM_THIS (This);\r
658\r
659 if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {\r
660 return EFI_INVALID_PARAMETER;\r
661 }\r
662\r
d1050b9d 663 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
772db4bb 664\r
d1050b9d
MK
665 DhcpSb = Instance->Service;\r
666 Config = &DhcpSb->ActiveConfig;\r
772db4bb 667\r
d1050b9d 668 Status = EFI_ACCESS_DENIED;\r
772db4bb 669\r
670 if ((DhcpSb->DhcpState != Dhcp4Stopped) &&\r
671 (DhcpSb->DhcpState != Dhcp4Init) &&\r
672 (DhcpSb->DhcpState != Dhcp4InitReboot) &&\r
d1050b9d
MK
673 (DhcpSb->DhcpState != Dhcp4Bound))\r
674 {\r
772db4bb 675 goto ON_EXIT;\r
676 }\r
677\r
678 if ((DhcpSb->ActiveChild != NULL) && (DhcpSb->ActiveChild != Instance)) {\r
679 goto ON_EXIT;\r
680 }\r
681\r
682 if (Dhcp4CfgData != NULL) {\r
683 Status = EFI_OUT_OF_RESOURCES;\r
684 DhcpCleanConfigure (Config);\r
685\r
686 if (EFI_ERROR (DhcpCopyConfigure (Config, Dhcp4CfgData))) {\r
687 goto ON_EXIT;\r
688 }\r
689\r
690 DhcpSb->UserOptionLen = 0;\r
691\r
692 for (Index = 0; Index < Dhcp4CfgData->OptionCount; Index++) {\r
693 DhcpSb->UserOptionLen += Dhcp4CfgData->OptionList[Index]->Length + 2;\r
694 }\r
695\r
696 DhcpSb->ActiveChild = Instance;\r
697\r
698 if (DhcpSb->DhcpState == Dhcp4Stopped) {\r
699 DhcpSb->ClientAddr = EFI_NTOHL (Dhcp4CfgData->ClientAddress);\r
700\r
701 if (DhcpSb->ClientAddr != 0) {\r
702 DhcpSb->DhcpState = Dhcp4InitReboot;\r
703 } else {\r
704 DhcpSb->DhcpState = Dhcp4Init;\r
705 }\r
706 }\r
707\r
d1050b9d
MK
708 DhcpSb->ServiceState = DHCP_CONFIGED;\r
709 Status = EFI_SUCCESS;\r
772db4bb 710 } else if (DhcpSb->ActiveChild == Instance) {\r
711 Status = EFI_SUCCESS;\r
712 DhcpYieldControl (DhcpSb);\r
713 }\r
714\r
715ON_EXIT:\r
e48e37fc 716 gBS->RestoreTPL (OldTpl);\r
772db4bb 717 return Status;\r
718}\r
719\r
772db4bb 720/**\r
f9204641 721 Starts the DHCP configuration process.\r
722\r
723 The Start() function starts the DHCP configuration process. This function can\r
724 be called only when the EFI DHCPv4 Protocol driver is in the Dhcp4Init or\r
725 Dhcp4InitReboot state.\r
726 If the DHCP process completes successfully, the state of the EFI DHCPv4 Protocol\r
727 driver will be transferred through Dhcp4Selecting and Dhcp4Requesting to the\r
728 Dhcp4Bound state. The CompletionEvent will then be signaled if it is not NULL.\r
729 If the process aborts, either by the user or by some unexpected network error,\r
730 the state is restored to the Dhcp4Init state. The Start() function can be called\r
731 again to restart the process.\r
732 Refer to RFC 2131 for precise state transitions during this process. At the\r
733 time when each event occurs in this process, the callback function that was set\r
734 by EFI_DHCP4_PROTOCOL.Configure() will be called and the user can take this\r
735 opportunity to control the process.\r
e2851998 736\r
3e8c18da 737 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance.\r
738 @param[in] CompletionEvent If not NULL, indicates the event that will be signaled when the\r
739 EFI DHCPv4 Protocol driver is transferred into the\r
740 Dhcp4Bound state or when the DHCP process is aborted.\r
741 EFI_DHCP4_PROTOCOL.GetModeData() can be called to\r
742 check the completion status. If NULL,\r
743 EFI_DHCP4_PROTOCOL.Start() will wait until the driver\r
744 is transferred into the Dhcp4Bound state or the process fails.\r
f9204641 745\r
746 @retval EFI_SUCCESS The DHCP configuration process has started, or it has completed\r
747 when CompletionEvent is NULL.\r
748 @retval EFI_NOT_STARTED The EFI DHCPv4 Protocol driver is in the Dhcp4Stopped\r
749 state. EFI_DHCP4_PROTOCOL. Configure() needs to be called.\r
750 @retval EFI_INVALID_PARAMETER This is NULL.\r
751 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
752 @retval EFI_TIMEOUT The DHCP configuration process failed because no response was\r
753 received from the server within the specified timeout value.\r
754 @retval EFI_ABORTED The user aborted the DHCP process.\r
755 @retval EFI_ALREADY_STARTED Some other EFI DHCPv4 Protocol instance already started the\r
756 DHCP process.\r
757 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
dd29f3ed 758 @retval EFI_NO_MEDIA There was a media error.\r
772db4bb 759\r
760**/\r
772db4bb 761EFI_STATUS\r
762EFIAPI\r
763EfiDhcp4Start (\r
d1050b9d
MK
764 IN EFI_DHCP4_PROTOCOL *This,\r
765 IN EFI_EVENT CompletionEvent OPTIONAL\r
772db4bb 766 )\r
767{\r
d1050b9d
MK
768 DHCP_PROTOCOL *Instance;\r
769 DHCP_SERVICE *DhcpSb;\r
770 EFI_STATUS Status;\r
771 EFI_TPL OldTpl;\r
772 EFI_STATUS MediaStatus;\r
772db4bb 773\r
774 //\r
775 // First validate the parameters\r
776 //\r
777 if (This == NULL) {\r
778 return EFI_INVALID_PARAMETER;\r
779 }\r
780\r
781 Instance = DHCP_INSTANCE_FROM_THIS (This);\r
782\r
783 if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {\r
784 return EFI_INVALID_PARAMETER;\r
785 }\r
786\r
d1050b9d
MK
787 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
788 DhcpSb = Instance->Service;\r
772db4bb 789\r
790 if (DhcpSb->DhcpState == Dhcp4Stopped) {\r
791 Status = EFI_NOT_STARTED;\r
792 goto ON_ERROR;\r
793 }\r
794\r
795 if ((DhcpSb->DhcpState != Dhcp4Init) && (DhcpSb->DhcpState != Dhcp4InitReboot)) {\r
796 Status = EFI_ALREADY_STARTED;\r
797 goto ON_ERROR;\r
798 }\r
799\r
5d34573d 800 //\r
c194ccca 801 // Check Media Status.\r
5d34573d 802 //\r
8ce6b650 803 MediaStatus = EFI_SUCCESS;\r
804 NetLibDetectMediaWaitTimeout (DhcpSb->Controller, DHCP_CHECK_MEDIA_WAITING_TIME, &MediaStatus);\r
805 if (MediaStatus != EFI_SUCCESS) {\r
5d34573d
JW
806 Status = EFI_NO_MEDIA;\r
807 goto ON_ERROR;\r
808 }\r
809\r
772db4bb 810 DhcpSb->IoStatus = EFI_ALREADY_STARTED;\r
811\r
812 if (EFI_ERROR (Status = DhcpInitRequest (DhcpSb))) {\r
813 goto ON_ERROR;\r
814 }\r
815\r
772db4bb 816 Instance->CompletionEvent = CompletionEvent;\r
817\r
818 //\r
e48e37fc 819 // Restore the TPL now, don't call poll function at TPL_CALLBACK.\r
772db4bb 820 //\r
e48e37fc 821 gBS->RestoreTPL (OldTpl);\r
772db4bb 822\r
823 if (CompletionEvent == NULL) {\r
824 while (DhcpSb->IoStatus == EFI_ALREADY_STARTED) {\r
b45b45b2 825 DhcpSb->UdpIo->Protocol.Udp4->Poll (DhcpSb->UdpIo->Protocol.Udp4);\r
772db4bb 826 }\r
827\r
828 return DhcpSb->IoStatus;\r
829 }\r
830\r
831 return EFI_SUCCESS;\r
832\r
833ON_ERROR:\r
e48e37fc 834 gBS->RestoreTPL (OldTpl);\r
772db4bb 835 return Status;\r
836}\r
837\r
772db4bb 838/**\r
f9204641 839 Extends the lease time by sending a request packet.\r
e2851998 840\r
f9204641 841 The RenewRebind() function is used to manually extend the lease time when the\r
842 EFI DHCPv4 Protocol driver is in the Dhcp4Bound state and the lease time has\r
843 not expired yet. This function will send a request packet to the previously\r
844 found server (or to any server when RebindRequest is TRUE) and transfer the\r
845 state into the Dhcp4Renewing state (or Dhcp4Rebinding when RebindingRequest is\r
846 TRUE). When a response is received, the state is returned to Dhcp4Bound.\r
847 If no response is received before the try count is exceeded (the RequestTryCount\r
848 field that is specified in EFI_DHCP4_CONFIG_DATA) but before the lease time that\r
849 was issued by the previous server expires, the driver will return to the Dhcp4Bound\r
850 state and the previous configuration is restored. The outgoing and incoming packets\r
851 can be captured by the EFI_DHCP4_CALLBACK function.\r
852\r
3e8c18da 853 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance.\r
854 @param[in] RebindRequest If TRUE, this function broadcasts the request packets and enters\r
855 the Dhcp4Rebinding state. Otherwise, it sends a unicast\r
856 request packet and enters the Dhcp4Renewing state.\r
857 @param[in] CompletionEvent If not NULL, this event is signaled when the renew/rebind phase\r
858 completes or some error occurs.\r
859 EFI_DHCP4_PROTOCOL.GetModeData() can be called to\r
860 check the completion status. If NULL,\r
861 EFI_DHCP4_PROTOCOL.RenewRebind() will busy-wait\r
862 until the DHCP process finishes.\r
f9204641 863\r
864 @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the\r
865 Dhcp4Renewing state or is back to the Dhcp4Bound state.\r
866 @retval EFI_NOT_STARTED The EFI DHCPv4 Protocol driver is in the Dhcp4Stopped\r
867 state. EFI_DHCP4_PROTOCOL.Configure() needs to\r
868 be called.\r
869 @retval EFI_INVALID_PARAMETER This is NULL.\r
870 @retval EFI_TIMEOUT There was no response from the server when the try count was\r
871 exceeded.\r
872 @retval EFI_ACCESS_DENIED The driver is not in the Dhcp4Bound state.\r
873 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
772db4bb 874\r
875**/\r
772db4bb 876EFI_STATUS\r
877EFIAPI\r
878EfiDhcp4RenewRebind (\r
d1050b9d
MK
879 IN EFI_DHCP4_PROTOCOL *This,\r
880 IN BOOLEAN RebindRequest,\r
881 IN EFI_EVENT CompletionEvent OPTIONAL\r
772db4bb 882 )\r
883{\r
d1050b9d
MK
884 DHCP_PROTOCOL *Instance;\r
885 DHCP_SERVICE *DhcpSb;\r
886 EFI_STATUS Status;\r
887 EFI_TPL OldTpl;\r
772db4bb 888\r
889 //\r
890 // First validate the parameters\r
891 //\r
892 if (This == NULL) {\r
893 return EFI_INVALID_PARAMETER;\r
894 }\r
895\r
896 Instance = DHCP_INSTANCE_FROM_THIS (This);\r
897\r
898 if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {\r
899 return EFI_INVALID_PARAMETER;\r
900 }\r
901\r
d1050b9d
MK
902 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
903 DhcpSb = Instance->Service;\r
772db4bb 904\r
905 if (DhcpSb->DhcpState == Dhcp4Stopped) {\r
906 Status = EFI_NOT_STARTED;\r
ae0a0b06 907 goto ON_EXIT;\r
772db4bb 908 }\r
909\r
910 if (DhcpSb->DhcpState != Dhcp4Bound) {\r
911 Status = EFI_ACCESS_DENIED;\r
ae0a0b06 912 goto ON_EXIT;\r
772db4bb 913 }\r
914\r
915 if (DHCP_IS_BOOTP (DhcpSb->Para)) {\r
ae0a0b06 916 Status = EFI_SUCCESS;\r
917 goto ON_EXIT;\r
772db4bb 918 }\r
919\r
920 //\r
921 // Transit the states then send a extra DHCP request\r
922 //\r
923 if (!RebindRequest) {\r
924 DhcpSetState (DhcpSb, Dhcp4Renewing, FALSE);\r
925 } else {\r
926 DhcpSetState (DhcpSb, Dhcp4Rebinding, FALSE);\r
927 }\r
928\r
842d83d6 929 //\r
930 // Clear initial time to make sure that elapsed-time\r
931 // is set to 0 for first REQUEST in renewal process.\r
932 //\r
933 Instance->ElaspedTime = 0;\r
934\r
772db4bb 935 Status = DhcpSendMessage (\r
936 DhcpSb,\r
937 DhcpSb->Selected,\r
938 DhcpSb->Para,\r
939 DHCP_MSG_REQUEST,\r
d1050b9d 940 (UINT8 *)"Extra renew/rebind by the application"\r
772db4bb 941 );\r
942\r
943 if (EFI_ERROR (Status)) {\r
944 DhcpSetState (DhcpSb, Dhcp4Bound, FALSE);\r
ae0a0b06 945 goto ON_EXIT;\r
772db4bb 946 }\r
947\r
d1050b9d
MK
948 DhcpSb->ExtraRefresh = TRUE;\r
949 DhcpSb->IoStatus = EFI_ALREADY_STARTED;\r
950 Instance->RenewRebindEvent = CompletionEvent;\r
772db4bb 951\r
e48e37fc 952 gBS->RestoreTPL (OldTpl);\r
772db4bb 953\r
954 if (CompletionEvent == NULL) {\r
955 while (DhcpSb->IoStatus == EFI_ALREADY_STARTED) {\r
b45b45b2 956 DhcpSb->UdpIo->Protocol.Udp4->Poll (DhcpSb->UdpIo->Protocol.Udp4);\r
772db4bb 957 }\r
958\r
959 return DhcpSb->IoStatus;\r
960 }\r
961\r
962 return EFI_SUCCESS;\r
963\r
ae0a0b06 964ON_EXIT:\r
e48e37fc 965 gBS->RestoreTPL (OldTpl);\r
772db4bb 966 return Status;\r
967}\r
968\r
772db4bb 969/**\r
f9204641 970 Releases the current address configuration.\r
971\r
972 The Release() function releases the current configured IP address by doing either\r
973 of the following:\r
974 * Sending a DHCPRELEASE packet when the EFI DHCPv4 Protocol driver is in the\r
975 Dhcp4Bound state\r
976 * Setting the previously assigned IP address that was provided with the\r
977 EFI_DHCP4_PROTOCOL.Configure() function to 0.0.0.0 when the driver is in\r
978 Dhcp4InitReboot state\r
979 After a successful call to this function, the EFI DHCPv4 Protocol driver returns\r
980 to the Dhcp4Init state and any subsequent incoming packets will be discarded silently.\r
772db4bb 981\r
3e8c18da 982 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance.\r
772db4bb 983\r
f9204641 984 @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the Dhcp4Init phase.\r
985 @retval EFI_INVALID_PARAMETER This is NULL.\r
986 @retval EFI_ACCESS_DENIED The EFI DHCPv4 Protocol driver is not Dhcp4InitReboot state.\r
987 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.\r
772db4bb 988\r
989**/\r
772db4bb 990EFI_STATUS\r
991EFIAPI\r
992EfiDhcp4Release (\r
d1050b9d 993 IN EFI_DHCP4_PROTOCOL *This\r
772db4bb 994 )\r
995{\r
d1050b9d
MK
996 DHCP_PROTOCOL *Instance;\r
997 DHCP_SERVICE *DhcpSb;\r
998 EFI_STATUS Status;\r
999 EFI_TPL OldTpl;\r
772db4bb 1000\r
1001 //\r
1002 // First validate the parameters\r
1003 //\r
1004 if (This == NULL) {\r
1005 return EFI_INVALID_PARAMETER;\r
1006 }\r
1007\r
1008 Instance = DHCP_INSTANCE_FROM_THIS (This);\r
1009\r
1010 if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {\r
1011 return EFI_INVALID_PARAMETER;\r
1012 }\r
1013\r
d1050b9d
MK
1014 Status = EFI_SUCCESS;\r
1015 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
1016 DhcpSb = Instance->Service;\r
772db4bb 1017\r
1018 if ((DhcpSb->DhcpState != Dhcp4InitReboot) && (DhcpSb->DhcpState != Dhcp4Bound)) {\r
1019 Status = EFI_ACCESS_DENIED;\r
1020 goto ON_EXIT;\r
1021 }\r
1022\r
1023 if (!DHCP_IS_BOOTP (DhcpSb->Para) && (DhcpSb->DhcpState == Dhcp4Bound)) {\r
1024 Status = DhcpSendMessage (\r
1025 DhcpSb,\r
1026 DhcpSb->Selected,\r
1027 DhcpSb->Para,\r
1028 DHCP_MSG_RELEASE,\r
1029 NULL\r
1030 );\r
1031\r
1032 if (EFI_ERROR (Status)) {\r
1033 Status = EFI_DEVICE_ERROR;\r
1034 goto ON_EXIT;\r
1035 }\r
1036 }\r
1037\r
1038 DhcpCleanLease (DhcpSb);\r
1039\r
1040ON_EXIT:\r
e48e37fc 1041 gBS->RestoreTPL (OldTpl);\r
772db4bb 1042 return Status;\r
1043}\r
1044\r
772db4bb 1045/**\r
f9204641 1046 Stops the current address configuration.\r
e2851998 1047\r
f9204641 1048 The Stop() function is used to stop the DHCP configuration process. After this\r
1049 function is called successfully, the EFI DHCPv4 Protocol driver is transferred\r
1050 into the Dhcp4Stopped state. EFI_DHCP4_PROTOCOL.Configure() needs to be called\r
1051 before DHCP configuration process can be started again. This function can be\r
1052 called when the EFI DHCPv4 Protocol driver is in any state.\r
772db4bb 1053\r
3e8c18da 1054 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance.\r
772db4bb 1055\r
f9204641 1056 @retval EFI_SUCCESS The EFI DHCPv4 Protocol driver is now in the Dhcp4Stopped phase.\r
1057 @retval EFI_INVALID_PARAMETER This is NULL.\r
772db4bb 1058\r
1059**/\r
772db4bb 1060EFI_STATUS\r
1061EFIAPI\r
1062EfiDhcp4Stop (\r
d1050b9d 1063 IN EFI_DHCP4_PROTOCOL *This\r
772db4bb 1064 )\r
1065{\r
d1050b9d
MK
1066 DHCP_PROTOCOL *Instance;\r
1067 DHCP_SERVICE *DhcpSb;\r
1068 EFI_TPL OldTpl;\r
772db4bb 1069\r
1070 //\r
1071 // First validate the parameters\r
1072 //\r
1073 if (This == NULL) {\r
1074 return EFI_INVALID_PARAMETER;\r
1075 }\r
1076\r
1077 Instance = DHCP_INSTANCE_FROM_THIS (This);\r
1078\r
1079 if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {\r
1080 return EFI_INVALID_PARAMETER;\r
1081 }\r
1082\r
d1050b9d
MK
1083 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
1084 DhcpSb = Instance->Service;\r
772db4bb 1085\r
1086 DhcpCleanLease (DhcpSb);\r
1087\r
d1050b9d
MK
1088 DhcpSb->DhcpState = Dhcp4Stopped;\r
1089 DhcpSb->ServiceState = DHCP_UNCONFIGED;\r
772db4bb 1090\r
e48e37fc 1091 gBS->RestoreTPL (OldTpl);\r
772db4bb 1092 return EFI_SUCCESS;\r
1093}\r
1094\r
772db4bb 1095/**\r
f9204641 1096 Builds a DHCP packet, given the options to be appended or deleted or replaced.\r
1097\r
1098 The Build() function is used to assemble a new packet from the original packet\r
1099 by replacing or deleting existing options or appending new options. This function\r
1100 does not change any state of the EFI DHCPv4 Protocol driver and can be used at\r
1101 any time.\r
1102\r
3e8c18da 1103 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance.\r
1104 @param[in] SeedPacket Initial packet to be used as a base for building new packet.\r
1105 @param[in] DeleteCount Number of opcodes in the DeleteList.\r
1106 @param[in] DeleteList List of opcodes to be deleted from the seed packet.\r
1107 Ignored if DeleteCount is zero.\r
1108 @param[in] AppendCount Number of entries in the OptionList.\r
1109 @param[in] AppendList Pointer to a DHCP option list to be appended to SeedPacket.\r
1110 If SeedPacket also contains options in this list, they are\r
1111 replaced by new options (except pad option). Ignored if\r
1112 AppendCount is zero. Type EFI_DHCP4_PACKET_OPTION\r
1113 @param[out] NewPacket Pointer to storage for the pointer to the new allocated packet.\r
1114 Use the EFI Boot Service FreePool() on the resulting pointer\r
1115 when done with the packet.\r
f9204641 1116\r
1117 @retval EFI_SUCCESS The new packet was built.\r
1118 @retval EFI_OUT_OF_RESOURCES Storage for the new packet could not be allocated.\r
1119 @retval EFI_INVALID_PARAMETER Some parameter is NULL.\r
772db4bb 1120\r
1121**/\r
772db4bb 1122EFI_STATUS\r
1123EFIAPI\r
1124EfiDhcp4Build (\r
1125 IN EFI_DHCP4_PROTOCOL *This,\r
1126 IN EFI_DHCP4_PACKET *SeedPacket,\r
1127 IN UINT32 DeleteCount,\r
1128 IN UINT8 *DeleteList OPTIONAL,\r
1129 IN UINT32 AppendCount,\r
1130 IN EFI_DHCP4_PACKET_OPTION *AppendList[] OPTIONAL,\r
1131 OUT EFI_DHCP4_PACKET **NewPacket\r
1132 )\r
1133{\r
1134 //\r
1135 // First validate the parameters\r
1136 //\r
1137 if ((This == NULL) || (NewPacket == NULL)) {\r
1138 return EFI_INVALID_PARAMETER;\r
1139 }\r
1140\r
1141 if ((SeedPacket == NULL) || (SeedPacket->Dhcp4.Magik != DHCP_OPTION_MAGIC) ||\r
d1050b9d
MK
1142 EFI_ERROR (DhcpValidateOptions (SeedPacket, NULL)))\r
1143 {\r
772db4bb 1144 return EFI_INVALID_PARAMETER;\r
1145 }\r
1146\r
1147 if (((DeleteCount == 0) && (AppendCount == 0)) ||\r
1148 ((DeleteCount != 0) && (DeleteList == NULL)) ||\r
d1050b9d
MK
1149 ((AppendCount != 0) && (AppendList == NULL)))\r
1150 {\r
772db4bb 1151 return EFI_INVALID_PARAMETER;\r
1152 }\r
1153\r
1154 return DhcpBuild (\r
1155 SeedPacket,\r
1156 DeleteCount,\r
1157 DeleteList,\r
1158 AppendCount,\r
1159 AppendList,\r
1160 NewPacket\r
1161 );\r
1162}\r
1163\r
f9204641 1164/**\r
1165 Callback by UdpIoCreatePort() when creating UdpIo for this Dhcp4 instance.\r
e2851998 1166\r
3e8c18da 1167 @param[in] UdpIo The UdpIo being created.\r
1168 @param[in] Context Dhcp4 instance.\r
e2851998 1169\r
0ba795d2
WF
1170 @retval EFI_SUCCESS UdpIo is configured successfully.\r
1171 @retval EFI_INVALID_PARAMETER Class E IP address is not supported or other parameters\r
1172 are not valid.\r
1173 @retval other Other error occurs.\r
f9204641 1174**/\r
c4a62a12 1175EFI_STATUS\r
e798cd87 1176EFIAPI\r
c4a62a12 1177Dhcp4InstanceConfigUdpIo (\r
d1050b9d
MK
1178 IN UDP_IO *UdpIo,\r
1179 IN VOID *Context\r
c4a62a12 1180 )\r
1181{\r
1182 DHCP_PROTOCOL *Instance;\r
8c5f78a2 1183 DHCP_SERVICE *DhcpSb;\r
c4a62a12 1184 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN *Token;\r
1185 EFI_UDP4_CONFIG_DATA UdpConfigData;\r
ce964733 1186 IP4_ADDR ClientAddr;\r
d1102dba
LG
1187 IP4_ADDR Ip;\r
1188 INTN Class;\r
1189 IP4_ADDR SubnetMask;\r
c4a62a12 1190\r
d1050b9d 1191 Instance = (DHCP_PROTOCOL *)Context;\r
8c5f78a2 1192 DhcpSb = Instance->Service;\r
c4a62a12 1193 Token = Instance->Token;\r
1194\r
e48e37fc 1195 ZeroMem (&UdpConfigData, sizeof (EFI_UDP4_CONFIG_DATA));\r
c4a62a12 1196\r
1197 UdpConfigData.AcceptBroadcast = TRUE;\r
1198 UdpConfigData.AllowDuplicatePort = TRUE;\r
1199 UdpConfigData.TimeToLive = 64;\r
1200 UdpConfigData.DoNotFragment = TRUE;\r
1201\r
ce964733 1202 ClientAddr = EFI_NTOHL (Token->Packet->Dhcp4.Header.ClientAddr);\r
d1050b9d 1203 Ip = HTONL (ClientAddr);\r
e48e37fc 1204 CopyMem (&UdpConfigData.StationAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
8c5f78a2
JW
1205\r
1206 if (DhcpSb->Netmask == 0) {\r
01b5ac88
FS
1207 //\r
1208 // The Dhcp4.TransmitReceive() API should be able to used at any time according to\r
1209 // UEFI spec, while in classless addressing network, the netmask must be explicitly\r
1210 // provided together with the station address.\r
1211 // If the DHCP instance haven't be configured with a valid netmask, we could only\r
24648548 1212 // compute it according to the classful addressing rule.\r
01b5ac88 1213 //\r
8c5f78a2 1214 Class = NetGetIpClass (ClientAddr);\r
0ba795d2
WF
1215 //\r
1216 // Class E IP address is not supported here!\r
1217 //\r
8c5f78a2 1218 ASSERT (Class < IP4_ADDR_CLASSE);\r
0ba795d2
WF
1219 if (Class >= IP4_ADDR_CLASSE) {\r
1220 return EFI_INVALID_PARAMETER;\r
1221 }\r
d1102dba 1222\r
8c5f78a2
JW
1223 SubnetMask = gIp4AllMasks[Class << 3];\r
1224 } else {\r
1225 SubnetMask = DhcpSb->Netmask;\r
1226 }\r
1227\r
ce964733 1228 Ip = HTONL (SubnetMask);\r
e48e37fc 1229 CopyMem (&UdpConfigData.SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
c4a62a12 1230\r
1231 if ((Token->ListenPointCount == 0) || (Token->ListenPoints[0].ListenPort == 0)) {\r
1232 UdpConfigData.StationPort = DHCP_CLIENT_PORT;\r
1233 } else {\r
1234 UdpConfigData.StationPort = Token->ListenPoints[0].ListenPort;\r
1235 }\r
1236\r
b45b45b2 1237 return UdpIo->Protocol.Udp4->Configure (UdpIo->Protocol.Udp4, &UdpConfigData);\r
c4a62a12 1238}\r
1239\r
f9204641 1240/**\r
1241 Create UdpIo for this Dhcp4 instance.\r
e2851998 1242\r
f9204641 1243 @param Instance The Dhcp4 instance.\r
e2851998 1244\r
f9204641 1245 @retval EFI_SUCCESS UdpIo is created successfully.\r
1246 @retval EFI_OUT_OF_RESOURCES Fails to create UdpIo because of limited\r
1247 resources or configuration failure.\r
1248**/\r
c4a62a12 1249EFI_STATUS\r
1250Dhcp4InstanceCreateUdpIo (\r
f9204641 1251 IN OUT DHCP_PROTOCOL *Instance\r
c4a62a12 1252 )\r
1253{\r
1254 DHCP_SERVICE *DhcpSb;\r
216f7970 1255 EFI_STATUS Status;\r
1256 VOID *Udp4;\r
c4a62a12 1257\r
1258 ASSERT (Instance->Token != NULL);\r
1259\r
1260 DhcpSb = Instance->Service;\r
b45b45b2 1261 Instance->UdpIo = UdpIoCreateIo (\r
1262 DhcpSb->Controller,\r
1263 DhcpSb->Image,\r
1264 Dhcp4InstanceConfigUdpIo,\r
1265 UDP_IO_UDP4_VERSION,\r
1266 Instance\r
1267 );\r
c4a62a12 1268 if (Instance->UdpIo == NULL) {\r
1269 return EFI_OUT_OF_RESOURCES;\r
1270 } else {\r
216f7970 1271 Status = gBS->OpenProtocol (\r
1272 Instance->UdpIo->UdpHandle,\r
1273 &gEfiUdp4ProtocolGuid,\r
d1050b9d 1274 (VOID **)&Udp4,\r
216f7970 1275 Instance->Service->Image,\r
1276 Instance->Handle,\r
1277 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
1278 );\r
1279 if (EFI_ERROR (Status)) {\r
1280 UdpIoFreeIo (Instance->UdpIo);\r
1281 Instance->UdpIo = NULL;\r
1282 }\r
d1050b9d 1283\r
216f7970 1284 return Status;\r
c4a62a12 1285 }\r
1286}\r
1287\r
f9204641 1288/**\r
1289 Callback of Dhcp packet. Does nothing.\r
e2851998 1290\r
f9204641 1291 @param Arg The context.\r
3e8c18da 1292\r
f9204641 1293**/\r
c4a62a12 1294VOID\r
e798cd87 1295EFIAPI\r
c4a62a12 1296DhcpDummyExtFree (\r
d1050b9d 1297 IN VOID *Arg\r
c4a62a12 1298 )\r
982a9eae 1299{\r
c4a62a12 1300}\r
1301\r
f9204641 1302/**\r
1303 Callback of UdpIoRecvDatagram() that handles a Dhcp4 packet.\r
e2851998 1304\r
f9204641 1305 Only BOOTP responses will be handled that correspond to the Xid of the request\r
1306 sent out. The packet will be queued to the response queue.\r
e2851998 1307\r
f9204641 1308 @param UdpPacket The Dhcp4 packet.\r
b45b45b2 1309 @param EndPoint Udp4 address pair.\r
f9204641 1310 @param IoStatus Status of the input.\r
1311 @param Context Extra info for the input.\r
e2851998 1312\r
f9204641 1313**/\r
c4a62a12 1314VOID\r
e798cd87 1315EFIAPI\r
c4a62a12 1316PxeDhcpInput (\r
d1050b9d
MK
1317 NET_BUF *UdpPacket,\r
1318 UDP_END_POINT *EndPoint,\r
1319 EFI_STATUS IoStatus,\r
1320 VOID *Context\r
c4a62a12 1321 )\r
1322{\r
1323 DHCP_PROTOCOL *Instance;\r
c4a62a12 1324 EFI_DHCP4_HEADER *Head;\r
1325 NET_BUF *Wrap;\r
1326 EFI_DHCP4_PACKET *Packet;\r
1327 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN *Token;\r
1328 UINT32 Len;\r
1329 EFI_STATUS Status;\r
1330\r
1331 Wrap = NULL;\r
d1050b9d 1332 Instance = (DHCP_PROTOCOL *)Context;\r
c4a62a12 1333 Token = Instance->Token;\r
c4a62a12 1334\r
1335 //\r
f9204641 1336 // Don't restart receive if error occurs or DHCP is destroyed.\r
c4a62a12 1337 //\r
1338 if (EFI_ERROR (IoStatus)) {\r
d1050b9d 1339 return;\r
c4a62a12 1340 }\r
1341\r
1342 ASSERT (UdpPacket != NULL);\r
982a9eae 1343\r
c4a62a12 1344 //\r
1345 // Validate the packet received\r
1346 //\r
1347 if (UdpPacket->TotalSize < sizeof (EFI_DHCP4_HEADER)) {\r
1348 goto RESTART;\r
1349 }\r
982a9eae 1350\r
c4a62a12 1351 //\r
1352 // Copy the DHCP message to a continuous memory block, make the buffer size\r
1353 // of the EFI_DHCP4_PACKET a multiple of 4-byte.\r
1354 //\r
1355 Len = NET_ROUNDUP (sizeof (EFI_DHCP4_PACKET) + UdpPacket->TotalSize - sizeof (EFI_DHCP4_HEADER), 4);\r
1356 Wrap = NetbufAlloc (Len);\r
c4a62a12 1357 if (Wrap == NULL) {\r
1358 goto RESTART;\r
1359 }\r
1360\r
d1050b9d 1361 Packet = (EFI_DHCP4_PACKET *)NetbufAllocSpace (Wrap, Len, NET_BUF_TAIL);\r
894d038a 1362 ASSERT (Packet != NULL);\r
1363\r
c4a62a12 1364 Packet->Size = Len;\r
1365 Head = &Packet->Dhcp4.Header;\r
d1050b9d 1366 Packet->Length = NetbufCopy (UdpPacket, 0, UdpPacket->TotalSize, (UINT8 *)Head);\r
c4a62a12 1367\r
1368 if (Packet->Length != UdpPacket->TotalSize) {\r
1369 goto RESTART;\r
1370 }\r
982a9eae 1371\r
c4a62a12 1372 //\r
1373 // Is this packet the answer to our packet?\r
1374 //\r
1375 if ((Head->OpCode != BOOTP_REPLY) ||\r
1376 (Head->Xid != Token->Packet->Dhcp4.Header.Xid) ||\r
d1050b9d
MK
1377 (CompareMem (&Token->Packet->Dhcp4.Header.ClientHwAddr[0], Head->ClientHwAddr, Head->HwAddrLen) != 0))\r
1378 {\r
c4a62a12 1379 goto RESTART;\r
1380 }\r
982a9eae 1381\r
c4a62a12 1382 //\r
1383 // Validate the options and retrieve the interested options\r
1384 //\r
1385 if ((Packet->Length > sizeof (EFI_DHCP4_HEADER) + sizeof (UINT32)) &&\r
1386 (Packet->Dhcp4.Magik == DHCP_OPTION_MAGIC) &&\r
d1050b9d
MK
1387 EFI_ERROR (DhcpValidateOptions (Packet, NULL)))\r
1388 {\r
c4a62a12 1389 goto RESTART;\r
1390 }\r
1391\r
1392 //\r
1393 // Keep this packet in the ResponseQueue.\r
1394 //\r
1395 NET_GET_REF (Wrap);\r
1396 NetbufQueAppend (&Instance->ResponseQueue, Wrap);\r
1397\r
1398RESTART:\r
1399\r
1400 NetbufFree (UdpPacket);\r
1401\r
1402 if (Wrap != NULL) {\r
1403 NetbufFree (Wrap);\r
1404 }\r
1405\r
1406 Status = UdpIoRecvDatagram (Instance->UdpIo, PxeDhcpInput, Instance, 0);\r
1407 if (EFI_ERROR (Status)) {\r
1408 PxeDhcpDone (Instance);\r
1409 }\r
1410}\r
1411\r
f9204641 1412/**\r
1413 Complete a Dhcp4 transaction and signal the upper layer.\r
e2851998 1414\r
f9204641 1415 @param Instance Dhcp4 instance.\r
f9204641 1416\r
1417**/\r
c4a62a12 1418VOID\r
1419PxeDhcpDone (\r
1420 IN DHCP_PROTOCOL *Instance\r
1421 )\r
1422{\r
1423 EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN *Token;\r
1424\r
1425 Token = Instance->Token;\r
1426\r
1427 Token->ResponseCount = Instance->ResponseQueue.BufNum;\r
1428 if (Token->ResponseCount != 0) {\r
d1050b9d 1429 Token->ResponseList = (EFI_DHCP4_PACKET *)AllocatePool (Instance->ResponseQueue.BufSize);\r
c4a62a12 1430 if (Token->ResponseList == NULL) {\r
1431 Token->Status = EFI_OUT_OF_RESOURCES;\r
1432 goto SIGNAL_USER;\r
1433 }\r
1434\r
1435 //\r
f9204641 1436 // Copy the received DHCP responses.\r
c4a62a12 1437 //\r
d1050b9d 1438 NetbufQueCopy (&Instance->ResponseQueue, 0, Instance->ResponseQueue.BufSize, (UINT8 *)Token->ResponseList);\r
c4a62a12 1439 Token->Status = EFI_SUCCESS;\r
1440 } else {\r
1441 Token->ResponseList = NULL;\r
1442 Token->Status = EFI_TIMEOUT;\r
1443 }\r
1444\r
1445SIGNAL_USER:\r
1446 //\r
f9204641 1447 // Clean up the resources dedicated for this transmit receive transaction.\r
c4a62a12 1448 //\r
1449 NetbufQueFlush (&Instance->ResponseQueue);\r
b45b45b2 1450 UdpIoCleanIo (Instance->UdpIo);\r
216f7970 1451 gBS->CloseProtocol (\r
1452 Instance->UdpIo->UdpHandle,\r
1453 &gEfiUdp4ProtocolGuid,\r
1454 Instance->Service->Image,\r
1455 Instance->Handle\r
1456 );\r
b45b45b2 1457 UdpIoFreeIo (Instance->UdpIo);\r
c4a62a12 1458 Instance->UdpIo = NULL;\r
1459 Instance->Token = NULL;\r
1460\r
1461 if (Token->CompletionEvent != NULL) {\r
1462 gBS->SignalEvent (Token->CompletionEvent);\r
982a9eae 1463 }\r
c4a62a12 1464}\r
1465\r
772db4bb 1466/**\r
ba39e316 1467 Transmits a DHCP formatted packet and optionally waits for responses.\r
e2851998 1468\r
f9204641 1469 The TransmitReceive() function is used to transmit a DHCP packet and optionally\r
1470 wait for the response from servers. This function does not change the state of\r
1471 the EFI DHCPv4 Protocol driver and thus can be used at any time.\r
ba39e316 1472\r
3e8c18da 1473 @param[in] This Pointer to the EFI_DHCP4_PROTOCOL instance.\r
1474 @param[in] Token Pointer to the EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN structure.\r
ba39e316 1475\r
1476 @retval EFI_SUCCESS The packet was successfully queued for transmission.\r
1477 @retval EFI_INVALID_PARAMETER Some parameter is NULL.\r
1478 @retval EFI_NOT_READY The previous call to this function has not finished yet. Try to call\r
1479 this function after collection process completes.\r
1480 @retval EFI_NO_MAPPING The default station address is not available yet.\r
1481 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
1482 @retval Others Some other unexpected error occurred.\r
772db4bb 1483\r
1484**/\r
772db4bb 1485EFI_STATUS\r
1486EFIAPI\r
1487EfiDhcp4TransmitReceive (\r
1488 IN EFI_DHCP4_PROTOCOL *This,\r
1489 IN EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN *Token\r
1490 )\r
1491{\r
d1050b9d
MK
1492 DHCP_PROTOCOL *Instance;\r
1493 EFI_TPL OldTpl;\r
1494 EFI_STATUS Status;\r
1495 NET_FRAGMENT Frag;\r
1496 NET_BUF *Wrap;\r
1497 UDP_END_POINT EndPoint;\r
1498 IP4_ADDR Ip;\r
1499 DHCP_SERVICE *DhcpSb;\r
1500 EFI_IP_ADDRESS Gateway;\r
1501 IP4_ADDR ClientAddr;\r
c4a62a12 1502\r
1503 if ((This == NULL) || (Token == NULL) || (Token->Packet == NULL)) {\r
1504 return EFI_INVALID_PARAMETER;\r
1505 }\r
1506\r
1507 Instance = DHCP_INSTANCE_FROM_THIS (This);\r
1508 DhcpSb = Instance->Service;\r
1509\r
1510 if (Instance->Token != NULL) {\r
1511 //\r
1512 // The previous call to TransmitReceive is not finished.\r
1513 //\r
1514 return EFI_NOT_READY;\r
1515 }\r
1516\r
f9204641 1517 if ((Token->Packet->Dhcp4.Magik != DHCP_OPTION_MAGIC) ||\r
1518 (NTOHL (Token->Packet->Dhcp4.Header.Xid) == Instance->Service->Xid) ||\r
1519 (Token->TimeoutValue == 0) ||\r
1520 ((Token->ListenPointCount != 0) && (Token->ListenPoints == NULL)) ||\r
1521 EFI_ERROR (DhcpValidateOptions (Token->Packet, NULL)) ||\r
1522 EFI_IP4_EQUAL (&Token->RemoteAddress, &mZeroIp4Addr)\r
d1050b9d
MK
1523 )\r
1524 {\r
c4a62a12 1525 //\r
f9204641 1526 // The DHCP packet isn't well-formed, the Transaction ID is already used,\r
1527 // the timeout value is zero, the ListenPoint is invalid, or the\r
1528 // RemoteAddress is zero.\r
c4a62a12 1529 //\r
1530 return EFI_INVALID_PARAMETER;\r
1531 }\r
1532\r
ce964733 1533 ClientAddr = EFI_NTOHL (Token->Packet->Dhcp4.Header.ClientAddr);\r
d1102dba 1534\r
ce964733 1535 if (ClientAddr == 0) {\r
c4a62a12 1536 return EFI_NO_MAPPING;\r
1537 }\r
1538\r
e48e37fc 1539 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
c4a62a12 1540\r
1541 //\r
1542 // Save the token and the timeout value.\r
1543 //\r
1544 Instance->Token = Token;\r
1545 Instance->Timeout = Token->TimeoutValue;\r
1546\r
1547 //\r
1548 // Create a UDP IO for this transmit receive transaction.\r
1549 //\r
1550 Status = Dhcp4InstanceCreateUdpIo (Instance);\r
1551 if (EFI_ERROR (Status)) {\r
1552 goto ON_ERROR;\r
1553 }\r
1554\r
982a9eae 1555 //\r
1556 // Save the Client Address is sent out\r
1557 //\r
f9204641 1558 CopyMem (\r
1559 &DhcpSb->ClientAddressSendOut[0],\r
1560 &Token->Packet->Dhcp4.Header.ClientHwAddr[0],\r
1561 Token->Packet->Dhcp4.Header.HwAddrLen\r
1562 );\r
982a9eae 1563\r
772db4bb 1564 //\r
c4a62a12 1565 // Wrap the DHCP packet into a net buffer.\r
772db4bb 1566 //\r
d1050b9d 1567 Frag.Bulk = (UINT8 *)&Token->Packet->Dhcp4;\r
c4a62a12 1568 Frag.Len = Token->Packet->Length;\r
1569 Wrap = NetbufFromExt (&Frag, 1, 0, 0, DhcpDummyExtFree, NULL);\r
1570 if (Wrap == NULL) {\r
1571 Status = EFI_OUT_OF_RESOURCES;\r
1572 goto ON_ERROR;\r
1573 }\r
1574\r
1575 //\r
b45b45b2 1576 // Set the local address and local port to ZERO.\r
c4a62a12 1577 //\r
b45b45b2 1578 ZeroMem (&EndPoint, sizeof (UDP_END_POINT));\r
c4a62a12 1579\r
1580 //\r
1581 // Set the destination address and destination port.\r
1582 //\r
e48e37fc 1583 CopyMem (&Ip, &Token->RemoteAddress, sizeof (EFI_IPv4_ADDRESS));\r
b45b45b2 1584 EndPoint.RemoteAddr.Addr[0] = NTOHL (Ip);\r
c4a62a12 1585\r
1586 if (Token->RemotePort == 0) {\r
1587 EndPoint.RemotePort = DHCP_SERVER_PORT;\r
1588 } else {\r
1589 EndPoint.RemotePort = Token->RemotePort;\r
1590 }\r
1591\r
1592 //\r
1593 // Get the gateway.\r
1594 //\r
b45b45b2 1595 ZeroMem (&Gateway, sizeof (Gateway));\r
01b5ac88 1596 if (!IP4_NET_EQUAL (ClientAddr, EndPoint.RemoteAddr.Addr[0], DhcpSb->Netmask)) {\r
b45b45b2 1597 CopyMem (&Gateway.v4, &Token->GatewayAddress, sizeof (EFI_IPv4_ADDRESS));\r
1598 Gateway.Addr[0] = NTOHL (Gateway.Addr[0]);\r
c4a62a12 1599 }\r
1600\r
1601 //\r
1602 // Transmit the DHCP packet.\r
1603 //\r
b45b45b2 1604 Status = UdpIoSendDatagram (Instance->UdpIo, Wrap, &EndPoint, &Gateway, DhcpOnPacketSent, NULL);\r
c4a62a12 1605 if (EFI_ERROR (Status)) {\r
1606 NetbufFree (Wrap);\r
1607 goto ON_ERROR;\r
1608 }\r
1609\r
1610 //\r
1611 // Start to receive the DHCP response.\r
1612 //\r
1613 Status = UdpIoRecvDatagram (Instance->UdpIo, PxeDhcpInput, Instance, 0);\r
1614 if (EFI_ERROR (Status)) {\r
1615 goto ON_ERROR;\r
1616 }\r
1617\r
1618ON_ERROR:\r
1619\r
1620 if (EFI_ERROR (Status) && (Instance->UdpIo != NULL)) {\r
b45b45b2 1621 UdpIoCleanIo (Instance->UdpIo);\r
216f7970 1622 gBS->CloseProtocol (\r
1623 Instance->UdpIo->UdpHandle,\r
1624 &gEfiUdp4ProtocolGuid,\r
1625 Instance->Service->Image,\r
1626 Instance->Handle\r
1627 );\r
b45b45b2 1628 UdpIoFreeIo (Instance->UdpIo);\r
c4a62a12 1629 Instance->UdpIo = NULL;\r
1630 Instance->Token = NULL;\r
1631 }\r
1632\r
e48e37fc 1633 gBS->RestoreTPL (OldTpl);\r
c4a62a12 1634\r
1635 if (!EFI_ERROR (Status) && (Token->CompletionEvent == NULL)) {\r
1636 //\r
1637 // Keep polling until timeout if no error happens and the CompletionEvent\r
1638 // is NULL.\r
1639 //\r
c5bcc2e2 1640 while (TRUE) {\r
1641 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
1642 //\r
1643 // Raise TPL to protect the UDPIO in instance, in case that DhcpOnTimerTick\r
1644 // free it when timeout.\r
1645 //\r
1646 if (Instance->Timeout > 0) {\r
b45b45b2 1647 Instance->UdpIo->Protocol.Udp4->Poll (Instance->UdpIo->Protocol.Udp4);\r
c5bcc2e2 1648 gBS->RestoreTPL (OldTpl);\r
1649 } else {\r
1650 gBS->RestoreTPL (OldTpl);\r
1651 break;\r
1652 }\r
c4a62a12 1653 }\r
1654 }\r
1655\r
1656 return Status;\r
772db4bb 1657}\r
1658\r
772db4bb 1659/**\r
1660 Callback function for DhcpIterateOptions. This callback sets the\r
1661 EFI_DHCP4_PACKET_OPTION array in the DHCP_PARSE_CONTEXT to point\r
1662 the individual DHCP option in the packet.\r
1663\r
3e8c18da 1664 @param[in] Tag The DHCP option type\r
1665 @param[in] Len Length of the DHCP option data\r
1666 @param[in] Data The DHCP option data\r
1667 @param[in] Context The context, to pass several parameters in.\r
772db4bb 1668\r
1669 @retval EFI_SUCCESS It always returns EFI_SUCCESS\r
1670\r
1671**/\r
772db4bb 1672EFI_STATUS\r
1673Dhcp4ParseCheckOption (\r
d1050b9d
MK
1674 IN UINT8 Tag,\r
1675 IN UINT8 Len,\r
1676 IN UINT8 *Data,\r
1677 IN VOID *Context\r
772db4bb 1678 )\r
1679{\r
d1050b9d 1680 DHCP_PARSE_CONTEXT *Parse;\r
772db4bb 1681\r
d1050b9d 1682 Parse = (DHCP_PARSE_CONTEXT *)Context;\r
772db4bb 1683 Parse->Index++;\r
1684\r
36ee91ca 1685 if (Parse->Index <= Parse->OptionCount) {\r
772db4bb 1686 //\r
50d7ebad 1687 // Use BASE_CR to get the memory position of EFI_DHCP4_PACKET_OPTION for\r
772db4bb 1688 // the EFI_DHCP4_PACKET_OPTION->Data because DhcpIterateOptions only\r
1689 // pass in the point to option data.\r
1690 //\r
50d7ebad 1691 Parse->Option[Parse->Index - 1] = BASE_CR (Data, EFI_DHCP4_PACKET_OPTION, Data);\r
772db4bb 1692 }\r
1693\r
1694 return EFI_SUCCESS;\r
1695}\r
1696\r
772db4bb 1697/**\r
f9204641 1698 Parses the packed DHCP option data.\r
e2851998 1699\r
f9204641 1700 The Parse() function is used to retrieve the option list from a DHCP packet.\r
51195fbe 1701 If *OptionCount isn't zero, and there is enough space for all the DHCP options\r
f9204641 1702 in the Packet, each element of PacketOptionList is set to point to somewhere in\r
1703 the Packet->Dhcp4.Option where a new DHCP option begins. If RFC3396 is supported,\r
1704 the caller should reassemble the parsed DHCP options to get the finial result.\r
51195fbe 1705 If *OptionCount is zero or there isn't enough space for all of them, the number\r
f9204641 1706 of DHCP options in the Packet is returned in OptionCount.\r
1707\r
1708 @param This Pointer to the EFI_DHCP4_PROTOCOL instance.\r
1709 @param Packet Pointer to packet to be parsed.\r
1710 @param OptionCount On input, the number of entries in the PacketOptionList.\r
1711 On output, the number of entries that were written into the\r
1712 PacketOptionList.\r
1713 @param PacketOptionList List of packet option entries to be filled in. End option or pad\r
1714 options are not included.\r
1715\r
1716 @retval EFI_SUCCESS The packet was successfully parsed.\r
1717 @retval EFI_INVALID_PARAMETER Some parameter is NULL.\r
1718 @retval EFI_BUFFER_TOO_SMALL One or more of the following conditions is TRUE:\r
1719 1) *OptionCount is smaller than the number of options that\r
1720 were found in the Packet.\r
1721 2) PacketOptionList is NULL.\r
772db4bb 1722\r
1723**/\r
772db4bb 1724EFI_STATUS\r
1725EFIAPI\r
1726EfiDhcp4Parse (\r
d1050b9d
MK
1727 IN EFI_DHCP4_PROTOCOL *This,\r
1728 IN EFI_DHCP4_PACKET *Packet,\r
1729 IN OUT UINT32 *OptionCount,\r
1730 OUT EFI_DHCP4_PACKET_OPTION *PacketOptionList[] OPTIONAL\r
772db4bb 1731 )\r
1732{\r
d1050b9d
MK
1733 DHCP_PARSE_CONTEXT Context;\r
1734 EFI_STATUS Status;\r
772db4bb 1735\r
1736 //\r
1737 // First validate the parameters\r
1738 //\r
1739 if ((This == NULL) || (Packet == NULL) || (OptionCount == NULL)) {\r
1740 return EFI_INVALID_PARAMETER;\r
1741 }\r
1742\r
1743 if ((Packet->Size < Packet->Length + 2 * sizeof (UINT32)) ||\r
1744 (Packet->Dhcp4.Magik != DHCP_OPTION_MAGIC) ||\r
d1050b9d
MK
1745 EFI_ERROR (DhcpValidateOptions (Packet, NULL)))\r
1746 {\r
772db4bb 1747 return EFI_INVALID_PARAMETER;\r
1748 }\r
1749\r
1750 if ((*OptionCount != 0) && (PacketOptionList == NULL)) {\r
1751 return EFI_BUFFER_TOO_SMALL;\r
1752 }\r
1753\r
e48e37fc 1754 ZeroMem (PacketOptionList, *OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));\r
772db4bb 1755\r
1756 Context.Option = PacketOptionList;\r
1757 Context.OptionCount = *OptionCount;\r
1758 Context.Index = 0;\r
1759\r
d1050b9d 1760 Status = DhcpIterateOptions (Packet, Dhcp4ParseCheckOption, &Context);\r
772db4bb 1761\r
1762 if (EFI_ERROR (Status)) {\r
1763 return Status;\r
1764 }\r
1765\r
1766 *OptionCount = Context.Index;\r
1767\r
1768 if (Context.Index > Context.OptionCount) {\r
1769 return EFI_BUFFER_TOO_SMALL;\r
1770 }\r
1771\r
1772 return EFI_SUCCESS;\r
1773}\r
842d83d6 1774\r
1775/**\r
1776 Set the elapsed time based on the given instance and the pointer to the\r
1777 elapsed time option.\r
1778\r
1779 @param[in] Elapsed The pointer to the position to append.\r
1780 @param[in] Instance The pointer to the Dhcp4 instance.\r
1781**/\r
1782VOID\r
1783SetElapsedTime (\r
d1050b9d
MK
1784 IN UINT16 *Elapsed,\r
1785 IN DHCP_PROTOCOL *Instance\r
842d83d6 1786 )\r
1787{\r
d1050b9d 1788 WriteUnaligned16 (Elapsed, HTONS (Instance->ElaspedTime));\r
842d83d6 1789}\r