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