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