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