1. Add EFI LOADED IMAGE DEVICE PATH Protocol in LoadImage() service, per UEFI 2.1b.
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Universal / Network / Dhcp4Dxe / Dhcp4Impl.c
1 /** @file\r
2 \r
3 Copyright (c) 2006 - 2007, 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 /**\r
28   Get the current operation parameter and lease for the network interface.\r
29 \r
30   @param  This                   The DHCP protocol instance\r
31   @param  Dhcp4ModeData          The variable to save the DHCP mode data.\r
32 \r
33   @retval EFI_INVALID_PARAMETER  The parameter is invalid\r
34   @retval EFI_SUCCESS            The Dhcp4ModeData is updated with the current\r
35                                  operation parameter.\r
36 \r
37 **/\r
38 STATIC\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   DHCP_PROTOCOL             *Instance;\r
47   DHCP_SERVICE              *DhcpSb;\r
48   DHCP_PARAMETER            *Para;\r
49   EFI_TPL                   OldTpl;\r
50   IP4_ADDR                  Ip;\r
51 \r
52   //\r
53   // First validate the parameters.\r
54   //\r
55   if ((This == NULL) || (Dhcp4ModeData == NULL)) {\r
56     return EFI_INVALID_PARAMETER;\r
57   }\r
58 \r
59   Instance = DHCP_INSTANCE_FROM_THIS (This);\r
60   \r
61   OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);\r
62   DhcpSb  = Instance->Service;\r
63 \r
64   //\r
65   // Caller can use GetModeData to retrieve current DHCP states\r
66   // no matter whether it is the active child or not.\r
67   //\r
68   Dhcp4ModeData->State                     = (EFI_DHCP4_STATE) DhcpSb->DhcpState;\r
69   CopyMem (&Dhcp4ModeData->ConfigData, &DhcpSb->ActiveConfig, sizeof (Dhcp4ModeData->ConfigData));\r
70   CopyMem (&Dhcp4ModeData->ClientMacAddress, &DhcpSb->Mac, sizeof (Dhcp4ModeData->ClientMacAddress));\r
71 \r
72   Ip = HTONL (DhcpSb->ClientAddr);\r
73   CopyMem (&Dhcp4ModeData->ClientAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
74 \r
75   Ip = HTONL (DhcpSb->Netmask);\r
76   CopyMem (&Dhcp4ModeData->SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
77 \r
78   Ip = HTONL (DhcpSb->ServerAddr);\r
79   CopyMem (&Dhcp4ModeData->ServerAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
80 \r
81   Para = DhcpSb->Para;\r
82 \r
83   if (Para != NULL) {\r
84     Ip = HTONL (Para->Router);\r
85     CopyMem (&Dhcp4ModeData->RouterAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
86     Dhcp4ModeData->LeaseTime               = Para->Lease;\r
87   } else {\r
88     ZeroMem (&Dhcp4ModeData->RouterAddress, sizeof (EFI_IPv4_ADDRESS));\r
89     Dhcp4ModeData->LeaseTime               = 0xffffffff;\r
90   }\r
91 \r
92   Dhcp4ModeData->ReplyPacket = DhcpSb->Selected;\r
93 \r
94   gBS->RestoreTPL (OldTpl);\r
95   return EFI_SUCCESS;\r
96 }\r
97 \r
98 \r
99 /**\r
100   Free the resource related to the configure parameters.\r
101   DHCP driver will make a copy of the user's configure\r
102   such as the time out value.\r
103 \r
104   @param  Config                 The DHCP configure data\r
105 \r
106   @return None\r
107 \r
108 **/\r
109 VOID\r
110 DhcpCleanConfigure (\r
111   IN EFI_DHCP4_CONFIG_DATA  *Config\r
112   )\r
113 {\r
114   UINT32                    Index;\r
115 \r
116   if (Config->DiscoverTimeout != NULL) {\r
117     gBS->FreePool (Config->DiscoverTimeout);\r
118   }\r
119 \r
120   if (Config->RequestTimeout != NULL) {\r
121     gBS->FreePool (Config->RequestTimeout);\r
122   }\r
123 \r
124   if (Config->OptionList != NULL) {\r
125     for (Index = 0; Index < Config->OptionCount; Index++) {\r
126       if (Config->OptionList[Index] != NULL) {\r
127         gBS->FreePool (Config->OptionList[Index]);\r
128       }\r
129     }\r
130 \r
131     gBS->FreePool (Config->OptionList);\r
132   }\r
133 \r
134   ZeroMem (Config, sizeof (EFI_DHCP4_CONFIG_DATA));\r
135 }\r
136 \r
137 \r
138 /**\r
139   Allocate memory for configure parameter such as timeout value for Dst,\r
140   then copy the configure parameter from Src to Dst.\r
141 \r
142   @param  Dst                    The destination DHCP configure data.\r
143   @param  Src                    The source DHCP configure data.\r
144 \r
145   @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory.\r
146   @retval EFI_SUCCESS            The configure is copied.\r
147 \r
148 **/\r
149 EFI_STATUS\r
150 DhcpCopyConfigure (\r
151   IN EFI_DHCP4_CONFIG_DATA  *Dst,\r
152   IN EFI_DHCP4_CONFIG_DATA  *Src\r
153   )\r
154 {\r
155   EFI_DHCP4_PACKET_OPTION   **DstOptions;\r
156   EFI_DHCP4_PACKET_OPTION   **SrcOptions;\r
157   INTN                      Len;\r
158   UINT32                    Index;\r
159 \r
160   CopyMem (Dst, Src, sizeof (*Dst));\r
161   Dst->DiscoverTimeout  = NULL;\r
162   Dst->RequestTimeout   = NULL;\r
163   Dst->OptionList       = NULL;\r
164 \r
165   //\r
166   // Allocate a memory then copy DiscoverTimeout to it\r
167   //\r
168   if (Src->DiscoverTimeout != NULL) {\r
169     Len                   = Src->DiscoverTryCount * sizeof (UINT32);\r
170     Dst->DiscoverTimeout  = AllocatePool (Len);\r
171 \r
172     if (Dst->DiscoverTimeout == NULL) {\r
173       return EFI_OUT_OF_RESOURCES;\r
174     }\r
175 \r
176     for (Index = 0; Index < Src->DiscoverTryCount; Index++) {\r
177       Dst->DiscoverTimeout[Index] = MAX (Src->DiscoverTimeout[Index], 1);\r
178     }\r
179   }\r
180 \r
181   //\r
182   // Allocate a memory then copy RequestTimeout to it\r
183   //\r
184   if (Src->RequestTimeout != NULL) {\r
185     Len                 = Src->RequestTryCount * sizeof (UINT32);\r
186     Dst->RequestTimeout = AllocatePool (Len);\r
187 \r
188     if (Dst->RequestTimeout == NULL) {\r
189       goto ON_ERROR;\r
190     }\r
191 \r
192     for (Index = 0; Index < Src->RequestTryCount; Index++) {\r
193       Dst->RequestTimeout[Index] = MAX (Src->RequestTimeout[Index], 1);\r
194     }\r
195   }\r
196 \r
197   //\r
198   // Allocate an array of dhcp option point, then allocate memory\r
199   // for each option and copy the source option to it\r
200   //\r
201   if (Src->OptionList != NULL) {\r
202     Len             = Src->OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *);\r
203     Dst->OptionList = AllocateZeroPool (Len);\r
204 \r
205     if (Dst->OptionList == NULL) {\r
206       goto ON_ERROR;\r
207     }\r
208 \r
209     DstOptions  = Dst->OptionList;\r
210     SrcOptions  = Src->OptionList;\r
211 \r
212     for (Index = 0; Index < Src->OptionCount; Index++) {\r
213       Len = sizeof (EFI_DHCP4_PACKET_OPTION) + MAX (SrcOptions[Index]->Length - 1, 0);\r
214 \r
215       DstOptions[Index] = AllocatePool (Len);\r
216 \r
217       if (DstOptions[Index] == NULL) {\r
218         goto ON_ERROR;\r
219       }\r
220 \r
221       CopyMem (DstOptions[Index], SrcOptions[Index], Len);\r
222     }\r
223   }\r
224 \r
225   return EFI_SUCCESS;\r
226 \r
227 ON_ERROR:\r
228   DhcpCleanConfigure (Dst);\r
229   return EFI_OUT_OF_RESOURCES;\r
230 }\r
231 \r
232 \r
233 /**\r
234   Give up the control of the DHCP service to let other child\r
235   resume. Don't change the service's DHCP state and the Client\r
236   address and option list configure as required by RFC2131.\r
237 \r
238   @param  DhcpSb                 The DHCP service instance.\r
239 \r
240   @return None\r
241 \r
242 **/\r
243 VOID\r
244 DhcpYieldControl (\r
245   IN DHCP_SERVICE           *DhcpSb\r
246   )\r
247 {\r
248   EFI_DHCP4_CONFIG_DATA     *Config;\r
249 \r
250   Config    = &DhcpSb->ActiveConfig;\r
251 \r
252   DhcpSb->ServiceState  = DHCP_UNCONFIGED;\r
253   DhcpSb->ActiveChild   = NULL;\r
254 \r
255   if (Config->DiscoverTimeout != NULL) {\r
256     gBS->FreePool (Config->DiscoverTimeout);\r
257 \r
258     Config->DiscoverTryCount  = 0;\r
259     Config->DiscoverTimeout   = NULL;\r
260   }\r
261 \r
262   if (Config->RequestTimeout != NULL) {\r
263     gBS->FreePool (Config->RequestTimeout);\r
264 \r
265     Config->RequestTryCount = 0;\r
266     Config->RequestTimeout  = NULL;\r
267   }\r
268 \r
269   Config->Dhcp4Callback   = NULL;\r
270   Config->CallbackContext = NULL;\r
271 }\r
272 \r
273 \r
274 /**\r
275   Configure the DHCP protocol instance and its underlying DHCP service\r
276   for operation. If Dhcp4CfgData is NULL and the child is currently\r
277   controlling the DHCP service, release the control.\r
278 \r
279   @param  This                   The DHCP protocol instance\r
280   @param  Dhcp4CfgData           The DHCP configure data.\r
281 \r
282   @retval EFI_INVALID_PARAMETER  The parameters are invalid.\r
283   @retval EFI_ACCESS_DENIED      The service isn't in one of configurable states,\r
284                                  or there is already an active child.\r
285   @retval EFI_OUT_OF_RESOURCE    Failed to allocate some resources.\r
286   @retval EFI_SUCCESS            The child is configured.\r
287 \r
288 **/\r
289 STATIC\r
290 EFI_STATUS\r
291 EFIAPI\r
292 EfiDhcp4Configure (\r
293   IN EFI_DHCP4_PROTOCOL     *This,\r
294   IN EFI_DHCP4_CONFIG_DATA  *Dhcp4CfgData       OPTIONAL\r
295   )\r
296 {\r
297   EFI_DHCP4_CONFIG_DATA     *Config;\r
298   DHCP_PROTOCOL             *Instance;\r
299   DHCP_SERVICE              *DhcpSb;\r
300   EFI_STATUS                Status;\r
301   EFI_TPL                   OldTpl;\r
302   UINT32                    Index;\r
303   IP4_ADDR                  Ip;\r
304 \r
305   //\r
306   // First validate the parameters\r
307   //\r
308   if (This == NULL) {\r
309     return EFI_INVALID_PARAMETER;\r
310   }\r
311 \r
312   if (Dhcp4CfgData != NULL) {\r
313     if (Dhcp4CfgData->DiscoverTryCount && (Dhcp4CfgData->DiscoverTimeout == NULL)) {\r
314       return EFI_INVALID_PARAMETER;\r
315     }\r
316 \r
317     if (Dhcp4CfgData->RequestTryCount && (Dhcp4CfgData->RequestTimeout == NULL)) {\r
318       return EFI_INVALID_PARAMETER;\r
319     }\r
320 \r
321     if (Dhcp4CfgData->OptionCount && (Dhcp4CfgData->OptionList == NULL)) {\r
322       return EFI_INVALID_PARAMETER;\r
323     }\r
324 \r
325     CopyMem (&Ip, &Dhcp4CfgData->ClientAddress, sizeof (IP4_ADDR));\r
326 \r
327     if ((Ip != 0) && !Ip4IsUnicast (NTOHL (Ip), 0)) {\r
328 \r
329       return EFI_INVALID_PARAMETER;\r
330     }\r
331   }\r
332 \r
333   Instance = DHCP_INSTANCE_FROM_THIS (This);\r
334 \r
335   if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {\r
336     return EFI_INVALID_PARAMETER;\r
337   }\r
338 \r
339   OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);\r
340 \r
341   DhcpSb  = Instance->Service;\r
342   Config  = &DhcpSb->ActiveConfig;\r
343 \r
344   Status  = EFI_ACCESS_DENIED;\r
345 \r
346   if ((DhcpSb->DhcpState != Dhcp4Stopped) &&\r
347       (DhcpSb->DhcpState != Dhcp4Init) &&\r
348       (DhcpSb->DhcpState != Dhcp4InitReboot) &&\r
349       (DhcpSb->DhcpState != Dhcp4Bound)) {\r
350 \r
351     goto ON_EXIT;\r
352   }\r
353 \r
354   if ((DhcpSb->ActiveChild != NULL) && (DhcpSb->ActiveChild != Instance)) {\r
355     goto ON_EXIT;\r
356   }\r
357 \r
358   if (Dhcp4CfgData != NULL) {\r
359     Status = EFI_OUT_OF_RESOURCES;\r
360     DhcpCleanConfigure (Config);\r
361 \r
362     if (EFI_ERROR (DhcpCopyConfigure (Config, Dhcp4CfgData))) {\r
363       goto ON_EXIT;\r
364     }\r
365 \r
366     DhcpSb->UserOptionLen = 0;\r
367 \r
368     for (Index = 0; Index < Dhcp4CfgData->OptionCount; Index++) {\r
369       DhcpSb->UserOptionLen += Dhcp4CfgData->OptionList[Index]->Length + 2;\r
370     }\r
371 \r
372     DhcpSb->ActiveChild = Instance;\r
373 \r
374     if (DhcpSb->DhcpState == Dhcp4Stopped) {\r
375       DhcpSb->ClientAddr = EFI_NTOHL (Dhcp4CfgData->ClientAddress);\r
376 \r
377       if (DhcpSb->ClientAddr != 0) {\r
378         DhcpSb->DhcpState = Dhcp4InitReboot;\r
379       } else {\r
380         DhcpSb->DhcpState = Dhcp4Init;\r
381       }\r
382     }\r
383 \r
384     DhcpSb->ServiceState  = DHCP_CONFIGED;\r
385     Status                = EFI_SUCCESS;\r
386 \r
387   } else if (DhcpSb->ActiveChild == Instance) {\r
388     Status = EFI_SUCCESS;\r
389     DhcpYieldControl (DhcpSb);\r
390   }\r
391 \r
392 ON_EXIT:\r
393   gBS->RestoreTPL (OldTpl);\r
394   return Status;\r
395 }\r
396 \r
397 \r
398 /**\r
399   Start the DHCP process.\r
400 \r
401   @param  This                   The DHCP protocol instance\r
402   @param  CompletionEvent        The event to signal is address is acquired.\r
403 \r
404   @retval EFI_INVALID_PARAMETER  The parameters are invalid.\r
405   @retval EFI_NOT_STARTED        The protocol hasn't been configured.\r
406   @retval EFI_ALREADY_STARTED    The DHCP process has already been started.\r
407   @retval EFI_SUCCESS            The DHCP process is started.\r
408 \r
409 **/\r
410 STATIC\r
411 EFI_STATUS\r
412 EFIAPI\r
413 EfiDhcp4Start (\r
414   IN EFI_DHCP4_PROTOCOL     *This,\r
415   IN EFI_EVENT              CompletionEvent   OPTIONAL\r
416   )\r
417 {\r
418   DHCP_PROTOCOL             *Instance;\r
419   DHCP_SERVICE              *DhcpSb;\r
420   EFI_STATUS                Status;\r
421   EFI_TPL                   OldTpl;\r
422 \r
423   //\r
424   // First validate the parameters\r
425   //\r
426   if (This == NULL) {\r
427     return EFI_INVALID_PARAMETER;\r
428   }\r
429 \r
430   Instance = DHCP_INSTANCE_FROM_THIS (This);\r
431 \r
432   if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {\r
433     return EFI_INVALID_PARAMETER;\r
434   }\r
435 \r
436   OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);\r
437   DhcpSb  = Instance->Service;\r
438 \r
439   if (DhcpSb->DhcpState == Dhcp4Stopped) {\r
440     Status = EFI_NOT_STARTED;\r
441     goto ON_ERROR;\r
442   }\r
443 \r
444   if ((DhcpSb->DhcpState != Dhcp4Init) && (DhcpSb->DhcpState != Dhcp4InitReboot)) {\r
445     Status = EFI_ALREADY_STARTED;\r
446     goto ON_ERROR;\r
447   }\r
448 \r
449   DhcpSb->IoStatus = EFI_ALREADY_STARTED;\r
450 \r
451   if (EFI_ERROR (Status = DhcpInitRequest (DhcpSb))) {\r
452     goto ON_ERROR;\r
453   }\r
454 \r
455   //\r
456   // Start/Restart the receiving.\r
457   //\r
458   Status = UdpIoRecvDatagram (DhcpSb->UdpIo, DhcpInput, DhcpSb, 0);\r
459 \r
460   if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
461     goto ON_ERROR;\r
462   }\r
463 \r
464   Instance->CompletionEvent = CompletionEvent;\r
465 \r
466   //\r
467   // Restore the TPL now, don't call poll function at TPL_CALLBACK.\r
468   //\r
469   gBS->RestoreTPL (OldTpl);\r
470 \r
471   if (CompletionEvent == NULL) {\r
472     while (DhcpSb->IoStatus == EFI_ALREADY_STARTED) {\r
473       DhcpSb->UdpIo->Udp->Poll (DhcpSb->UdpIo->Udp);\r
474     }\r
475 \r
476     return DhcpSb->IoStatus;\r
477   }\r
478 \r
479   return EFI_SUCCESS;\r
480 \r
481 ON_ERROR:\r
482   gBS->RestoreTPL (OldTpl);\r
483   return Status;\r
484 }\r
485 \r
486 \r
487 /**\r
488   Request an extra manual renew/rebind.\r
489 \r
490   @param  This                   The DHCP protocol instance\r
491   @param  RebindRequest          TRUE if request a rebind, otherwise renew it\r
492   @param  CompletionEvent        Event to signal when complete\r
493 \r
494   @retval EFI_INVALID_PARAMETER  The parameters are invalid\r
495   @retval EFI_NOT_STARTED        The DHCP protocol hasn't been started.\r
496   @retval EFI_ACCESS_DENIED      The DHCP protocol isn't in Bound state.\r
497   @retval EFI_SUCCESS            The DHCP is renewed/rebound.\r
498 \r
499 **/\r
500 STATIC\r
501 EFI_STATUS\r
502 EFIAPI\r
503 EfiDhcp4RenewRebind (\r
504   IN EFI_DHCP4_PROTOCOL     *This,\r
505   IN BOOLEAN                RebindRequest,\r
506   IN EFI_EVENT              CompletionEvent   OPTIONAL\r
507   )\r
508 {\r
509   DHCP_PROTOCOL             *Instance;\r
510   DHCP_SERVICE              *DhcpSb;\r
511   EFI_STATUS                Status;\r
512   EFI_TPL                   OldTpl;\r
513 \r
514   //\r
515   // First validate the parameters\r
516   //\r
517   if (This == NULL) {\r
518     return EFI_INVALID_PARAMETER;\r
519   }\r
520 \r
521   Instance = DHCP_INSTANCE_FROM_THIS (This);\r
522 \r
523   if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {\r
524     return EFI_INVALID_PARAMETER;\r
525   }\r
526 \r
527   OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);\r
528   DhcpSb  = Instance->Service;\r
529 \r
530   if (DhcpSb->DhcpState == Dhcp4Stopped) {\r
531     Status = EFI_NOT_STARTED;\r
532     goto ON_ERROR;\r
533   }\r
534 \r
535   if (DhcpSb->DhcpState != Dhcp4Bound) {\r
536     Status = EFI_ACCESS_DENIED;\r
537     goto ON_ERROR;\r
538   }\r
539 \r
540   if (DHCP_IS_BOOTP (DhcpSb->Para)) {\r
541     return EFI_SUCCESS;\r
542   }\r
543 \r
544   //\r
545   // Transit the states then send a extra DHCP request\r
546   //\r
547   if (!RebindRequest) {\r
548     DhcpSetState (DhcpSb, Dhcp4Renewing, FALSE);\r
549   } else {\r
550     DhcpSetState (DhcpSb, Dhcp4Rebinding, FALSE);\r
551   }\r
552 \r
553   Status = DhcpSendMessage (\r
554              DhcpSb,\r
555              DhcpSb->Selected,\r
556              DhcpSb->Para,\r
557              DHCP_MSG_REQUEST,\r
558              (UINT8 *) "Extra renew/rebind by the application"\r
559              );\r
560 \r
561   if (EFI_ERROR (Status)) {\r
562     DhcpSetState (DhcpSb, Dhcp4Bound, FALSE);\r
563     goto ON_ERROR;\r
564   }\r
565 \r
566   DhcpSb->ExtraRefresh        = TRUE;\r
567   DhcpSb->IoStatus            = EFI_ALREADY_STARTED;\r
568   Instance->RenewRebindEvent  = CompletionEvent;\r
569 \r
570   gBS->RestoreTPL (OldTpl);\r
571 \r
572   if (CompletionEvent == NULL) {\r
573     while (DhcpSb->IoStatus == EFI_ALREADY_STARTED) {\r
574       DhcpSb->UdpIo->Udp->Poll (DhcpSb->UdpIo->Udp);\r
575     }\r
576 \r
577     return DhcpSb->IoStatus;\r
578   }\r
579 \r
580   return EFI_SUCCESS;\r
581 \r
582 ON_ERROR:\r
583   gBS->RestoreTPL (OldTpl);\r
584   return Status;\r
585 }\r
586 \r
587 \r
588 /**\r
589   Release the current acquired lease.\r
590 \r
591   @param  This                   The DHCP protocol instance\r
592 \r
593   @retval EFI_INVALID_PARAMETER  The parameter is invalid\r
594   @retval EFI_DEVICE_ERROR       Failed to transmit the DHCP release packet\r
595   @retval EFI_ACCESS_DENIED      The DHCP service isn't in one of the connected\r
596                                  state.\r
597   @retval EFI_SUCCESS            The lease is released.\r
598 \r
599 **/\r
600 STATIC\r
601 EFI_STATUS\r
602 EFIAPI\r
603 EfiDhcp4Release (\r
604   IN EFI_DHCP4_PROTOCOL     *This\r
605   )\r
606 {\r
607   DHCP_PROTOCOL             *Instance;\r
608   DHCP_SERVICE              *DhcpSb;\r
609   EFI_STATUS                Status;\r
610   EFI_TPL                   OldTpl;\r
611 \r
612   //\r
613   // First validate the parameters\r
614   //\r
615   if (This == NULL) {\r
616     return EFI_INVALID_PARAMETER;\r
617   }\r
618 \r
619   Instance = DHCP_INSTANCE_FROM_THIS (This);\r
620 \r
621   if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {\r
622     return EFI_INVALID_PARAMETER;\r
623   }\r
624 \r
625   Status  = EFI_SUCCESS;\r
626   OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);\r
627   DhcpSb  = Instance->Service;\r
628 \r
629   if ((DhcpSb->DhcpState != Dhcp4InitReboot) && (DhcpSb->DhcpState != Dhcp4Bound)) {\r
630     Status = EFI_ACCESS_DENIED;\r
631     goto ON_EXIT;\r
632   }\r
633 \r
634   if (!DHCP_IS_BOOTP (DhcpSb->Para) && (DhcpSb->DhcpState == Dhcp4Bound)) {\r
635     Status = DhcpSendMessage (\r
636                DhcpSb,\r
637                DhcpSb->Selected,\r
638                DhcpSb->Para,\r
639                DHCP_MSG_RELEASE,\r
640                NULL\r
641                );\r
642 \r
643     if (EFI_ERROR (Status)) {\r
644       Status = EFI_DEVICE_ERROR;\r
645       goto ON_EXIT;\r
646     }\r
647   }\r
648 \r
649   DhcpCleanLease (DhcpSb);\r
650 \r
651 ON_EXIT:\r
652   gBS->RestoreTPL (OldTpl);\r
653   return Status;\r
654 }\r
655 \r
656 \r
657 /**\r
658   Stop the current DHCP process. After this, other DHCP child\r
659   can gain control of the service, configure and use it.\r
660 \r
661   @param  This                   The DHCP protocol instance\r
662 \r
663   @retval EFI_INVALID_PARAMETER  The parameter is invalid.\r
664   @retval EFI_SUCCESS            The DHCP process is stopped.\r
665 \r
666 **/\r
667 STATIC\r
668 EFI_STATUS\r
669 EFIAPI\r
670 EfiDhcp4Stop (\r
671   IN EFI_DHCP4_PROTOCOL     *This\r
672   )\r
673 {\r
674   DHCP_PROTOCOL             *Instance;\r
675   DHCP_SERVICE              *DhcpSb;\r
676   EFI_TPL                   OldTpl;\r
677 \r
678   //\r
679   // First validate the parameters\r
680   //\r
681   if (This == NULL) {\r
682     return EFI_INVALID_PARAMETER;\r
683   }\r
684 \r
685   Instance = DHCP_INSTANCE_FROM_THIS (This);\r
686 \r
687   if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {\r
688     return EFI_INVALID_PARAMETER;\r
689   }\r
690 \r
691   OldTpl  = gBS->RaiseTPL (TPL_CALLBACK);\r
692   DhcpSb  = Instance->Service;\r
693 \r
694   DhcpCleanLease (DhcpSb);\r
695 \r
696   DhcpSb->DhcpState     = Dhcp4Stopped;\r
697   DhcpSb->ServiceState  = DHCP_UNCONFIGED;\r
698 \r
699   gBS->RestoreTPL (OldTpl);\r
700   return EFI_SUCCESS;\r
701 }\r
702 \r
703 \r
704 /**\r
705   Build a new DHCP packet from the seed packet. Options may be deleted or\r
706   appended. The caller should free the NewPacket when finished using it.\r
707 \r
708   @param  This                   The DHCP protocol instance.\r
709   @param  SeedPacket             The seed packet to start with\r
710   @param  DeleteCount            The number of options to delete\r
711   @param  DeleteList             The options to delete from the packet\r
712   @param  AppendCount            The number of options to append\r
713   @param  AppendList             The options to append to the packet\r
714   @param  NewPacket              The new packet, allocated and built by this\r
715                                  function.\r
716 \r
717   @retval EFI_INVALID_PARAMETER  The parameters are invalid.\r
718   @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory\r
719   @retval EFI_SUCCESS            The packet is build.\r
720 \r
721 **/\r
722 STATIC\r
723 EFI_STATUS\r
724 EFIAPI\r
725 EfiDhcp4Build (\r
726   IN EFI_DHCP4_PROTOCOL       *This,\r
727   IN EFI_DHCP4_PACKET         *SeedPacket,\r
728   IN UINT32                   DeleteCount,\r
729   IN UINT8                    *DeleteList OPTIONAL,\r
730   IN UINT32                   AppendCount,\r
731   IN EFI_DHCP4_PACKET_OPTION  *AppendList[] OPTIONAL,\r
732   OUT EFI_DHCP4_PACKET        **NewPacket\r
733   )\r
734 {\r
735   //\r
736   // First validate the parameters\r
737   //\r
738   if ((This == NULL) || (NewPacket == NULL)) {\r
739     return EFI_INVALID_PARAMETER;\r
740   }\r
741 \r
742   if ((SeedPacket == NULL) || (SeedPacket->Dhcp4.Magik != DHCP_OPTION_MAGIC) ||\r
743       EFI_ERROR (DhcpValidateOptions (SeedPacket, NULL))) {\r
744 \r
745     return EFI_INVALID_PARAMETER;\r
746   }\r
747 \r
748   if (((DeleteCount == 0) && (AppendCount == 0)) ||\r
749       ((DeleteCount != 0) && (DeleteList == NULL)) ||\r
750       ((AppendCount != 0) && (AppendList == NULL))) {\r
751 \r
752     return EFI_INVALID_PARAMETER;\r
753   }\r
754 \r
755   return DhcpBuild (\r
756            SeedPacket,\r
757            DeleteCount,\r
758            DeleteList,\r
759            AppendCount,\r
760            AppendList,\r
761            NewPacket\r
762            );\r
763 }\r
764 \r
765 STATIC\r
766 EFI_STATUS\r
767 Dhcp4InstanceConfigUdpIo (\r
768   IN UDP_IO_PORT  *UdpIo,\r
769   IN VOID         *Context\r
770   )\r
771 {\r
772   DHCP_PROTOCOL                     *Instance;\r
773   DHCP_SERVICE                      *DhcpSb;\r
774   EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN  *Token;\r
775   EFI_UDP4_CONFIG_DATA              UdpConfigData;\r
776   IP4_ADDR                          Ip;\r
777 \r
778   Instance = (DHCP_PROTOCOL *) Context;\r
779   DhcpSb   = Instance->Service;\r
780   Token    = Instance->Token;\r
781 \r
782   ZeroMem (&UdpConfigData, sizeof (EFI_UDP4_CONFIG_DATA));\r
783 \r
784   UdpConfigData.AcceptBroadcast    = TRUE;\r
785   UdpConfigData.AllowDuplicatePort = TRUE;\r
786   UdpConfigData.TimeToLive         = 64;\r
787   UdpConfigData.DoNotFragment      = TRUE;\r
788 \r
789   Ip = HTONL (DhcpSb->ClientAddr);\r
790   CopyMem (&UdpConfigData.StationAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
791 \r
792   Ip = HTONL (DhcpSb->Netmask);\r
793   CopyMem (&UdpConfigData.SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
794 \r
795   if ((Token->ListenPointCount == 0) || (Token->ListenPoints[0].ListenPort == 0)) {\r
796     UdpConfigData.StationPort = DHCP_CLIENT_PORT;\r
797   } else {\r
798     UdpConfigData.StationPort = Token->ListenPoints[0].ListenPort;\r
799   }\r
800 \r
801   return UdpIo->Udp->Configure (UdpIo->Udp, &UdpConfigData);\r
802 }\r
803 \r
804 STATIC\r
805 EFI_STATUS\r
806 Dhcp4InstanceCreateUdpIo (\r
807   IN DHCP_PROTOCOL  *Instance\r
808   )\r
809 {\r
810   DHCP_SERVICE  *DhcpSb;\r
811 \r
812   ASSERT (Instance->Token != NULL);\r
813 \r
814   DhcpSb          = Instance->Service;\r
815   Instance->UdpIo = UdpIoCreatePort (DhcpSb->Controller, DhcpSb->Image, Dhcp4InstanceConfigUdpIo, Instance);\r
816   if (Instance->UdpIo == NULL) {\r
817     return EFI_OUT_OF_RESOURCES;\r
818   } else {\r
819     return EFI_SUCCESS;\r
820   }\r
821 }\r
822 \r
823 STATIC\r
824 VOID\r
825 DhcpDummyExtFree (\r
826   IN VOID                   *Arg\r
827   )\r
828 /*++\r
829 \r
830 Routine Description:\r
831 \r
832   Release the packet.\r
833 \r
834 Arguments:\r
835 \r
836   Arg - The packet to release\r
837 \r
838 Returns:\r
839 \r
840   None\r
841 \r
842 --*/\r
843 {  \r
844 }\r
845 \r
846 VOID\r
847 PxeDhcpInput (\r
848   NET_BUF                   *UdpPacket,\r
849   UDP_POINTS                *Points,\r
850   EFI_STATUS                IoStatus,\r
851   VOID                      *Context\r
852   )\r
853 {\r
854   DHCP_PROTOCOL                     *Instance;\r
855   DHCP_SERVICE                      *DhcpSb;\r
856   EFI_DHCP4_HEADER                  *Head;\r
857   NET_BUF                           *Wrap;\r
858   EFI_DHCP4_PACKET                  *Packet;\r
859   EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN  *Token;\r
860   UINT32                            Len;\r
861   EFI_STATUS                        Status;\r
862 \r
863   Wrap     = NULL;\r
864   Instance = (DHCP_PROTOCOL *) Context;\r
865   Token    = Instance->Token;\r
866   DhcpSb   = Instance->Service;\r
867 \r
868   //\r
869   // Don't restart receive if error occurs or DHCP is destoried.\r
870   //\r
871   if (EFI_ERROR (IoStatus)) {\r
872     return ;\r
873   }\r
874 \r
875   ASSERT (UdpPacket != NULL);\r
876   \r
877   //\r
878   // Validate the packet received\r
879   //\r
880   if (UdpPacket->TotalSize < sizeof (EFI_DHCP4_HEADER)) {\r
881     goto RESTART;\r
882   }\r
883   \r
884   //\r
885   // Copy the DHCP message to a continuous memory block, make the buffer size\r
886   // of the EFI_DHCP4_PACKET a multiple of 4-byte.\r
887   //\r
888   Len  = NET_ROUNDUP (sizeof (EFI_DHCP4_PACKET) + UdpPacket->TotalSize - sizeof (EFI_DHCP4_HEADER), 4);\r
889   Wrap = NetbufAlloc (Len);\r
890 \r
891   if (Wrap == NULL) {\r
892     goto RESTART;\r
893   }\r
894 \r
895   Packet         = (EFI_DHCP4_PACKET *) NetbufAllocSpace (Wrap, Len, NET_BUF_TAIL);\r
896   Packet->Size   = Len;\r
897   Head           = &Packet->Dhcp4.Header;\r
898   Packet->Length = NetbufCopy (UdpPacket, 0, UdpPacket->TotalSize, (UINT8 *) Head);\r
899 \r
900   if (Packet->Length != UdpPacket->TotalSize) {\r
901     goto RESTART;\r
902   }\r
903   \r
904   //\r
905   // Is this packet the answer to our packet?\r
906   //\r
907   if ((Head->OpCode != BOOTP_REPLY) ||\r
908       (Head->Xid != Token->Packet->Dhcp4.Header.Xid) ||\r
909       !NET_MAC_EQUAL (&DhcpSb->Mac, Head->ClientHwAddr, DhcpSb->HwLen)) {\r
910     goto RESTART;\r
911   }\r
912   \r
913   //\r
914   // Validate the options and retrieve the interested options\r
915   //\r
916   if ((Packet->Length > sizeof (EFI_DHCP4_HEADER) + sizeof (UINT32)) &&\r
917       (Packet->Dhcp4.Magik == DHCP_OPTION_MAGIC) &&\r
918       EFI_ERROR (DhcpValidateOptions (Packet, NULL))) {\r
919 \r
920     goto RESTART;\r
921   }\r
922 \r
923   //\r
924   // Keep this packet in the ResponseQueue.\r
925   //\r
926   NET_GET_REF (Wrap);\r
927   NetbufQueAppend (&Instance->ResponseQueue, Wrap);\r
928 \r
929 RESTART:\r
930 \r
931   NetbufFree (UdpPacket);\r
932 \r
933   if (Wrap != NULL) {\r
934     NetbufFree (Wrap);\r
935   }\r
936 \r
937   Status = UdpIoRecvDatagram (Instance->UdpIo, PxeDhcpInput, Instance, 0);\r
938   if (EFI_ERROR (Status)) {\r
939     PxeDhcpDone (Instance);\r
940   }\r
941 }\r
942 \r
943 VOID\r
944 PxeDhcpDone (\r
945   IN DHCP_PROTOCOL  *Instance\r
946   )\r
947 {\r
948   EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN  *Token;\r
949 \r
950   Token = Instance->Token;\r
951 \r
952   Token->ResponseCount = Instance->ResponseQueue.BufNum;\r
953   if (Token->ResponseCount != 0) {\r
954     Token->ResponseList = (EFI_DHCP4_PACKET *) AllocatePool (Instance->ResponseQueue.BufSize);\r
955     if (Token->ResponseList == NULL) {\r
956       Token->Status = EFI_OUT_OF_RESOURCES;\r
957       goto SIGNAL_USER;\r
958     }\r
959 \r
960     //\r
961     // Copy the recieved DHCP responses.\r
962     //\r
963     NetbufQueCopy (&Instance->ResponseQueue, 0, Instance->ResponseQueue.BufSize, (UINT8 *) Token->ResponseList);\r
964     Token->Status = EFI_SUCCESS;\r
965   } else {\r
966     Token->ResponseList = NULL;\r
967     Token->Status       = EFI_TIMEOUT;\r
968   }\r
969 \r
970 SIGNAL_USER:\r
971   //\r
972   // Clean the resources dedicated for this transmit receive transaction.\r
973   //\r
974   NetbufQueFlush (&Instance->ResponseQueue);\r
975   UdpIoCleanPort (Instance->UdpIo);\r
976   UdpIoFreePort (Instance->UdpIo);\r
977   Instance->UdpIo = NULL;\r
978   Instance->Token = NULL;\r
979 \r
980   if (Token->CompletionEvent != NULL) {\r
981     gBS->SignalEvent (Token->CompletionEvent);\r
982   }  \r
983 }\r
984 \r
985 \r
986 /**\r
987   Transmits a DHCP formatted packet and optionally waits for responses.\r
988 \r
989   @param  This    Pointer to the EFI_DHCP4_PROTOCOL instance.\r
990   @param  Token   Pointer to the EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN structure.\r
991 \r
992   @retval EFI_SUCCESS           The packet was successfully queued for transmission.\r
993   @retval EFI_INVALID_PARAMETER Some parameter is NULL.\r
994   @retval EFI_NOT_READY         The previous call to this function has not finished yet. Try to call\r
995                                 this function after collection process completes.\r
996   @retval EFI_NO_MAPPING        The default station address is not available yet.\r
997   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.\r
998   @retval Others                Some other unexpected error occurred.\r
999 \r
1000 **/\r
1001 STATIC\r
1002 EFI_STATUS\r
1003 EFIAPI\r
1004 EfiDhcp4TransmitReceive (\r
1005   IN EFI_DHCP4_PROTOCOL                *This,\r
1006   IN EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN  *Token\r
1007   )\r
1008 {\r
1009   DHCP_PROTOCOL  *Instance;\r
1010   EFI_TPL        OldTpl;\r
1011   EFI_STATUS     Status;\r
1012   NET_FRAGMENT   Frag;\r
1013   NET_BUF        *Wrap;\r
1014   UDP_POINTS     EndPoint;\r
1015   IP4_ADDR       Ip;\r
1016   DHCP_SERVICE   *DhcpSb;\r
1017   IP4_ADDR       Gateway;\r
1018   IP4_ADDR       SubnetMask;\r
1019 \r
1020   if ((This == NULL) || (Token == NULL) || (Token->Packet == NULL)) {\r
1021     return EFI_INVALID_PARAMETER;\r
1022   }\r
1023 \r
1024   Instance = DHCP_INSTANCE_FROM_THIS (This);\r
1025   DhcpSb   = Instance->Service;\r
1026 \r
1027   if (Instance->Token != NULL) {\r
1028     //\r
1029     // The previous call to TransmitReceive is not finished.\r
1030     //\r
1031     return EFI_NOT_READY;\r
1032   }\r
1033 \r
1034   if ((Token->Packet->Dhcp4.Magik != DHCP_OPTION_MAGIC) ||\r
1035     (NTOHL (Token->Packet->Dhcp4.Header.Xid) == Instance->Service->Xid) ||\r
1036     (Token->TimeoutValue == 0) ||\r
1037     ((Token->ListenPointCount != 0) && (Token->ListenPoints == NULL)) ||\r
1038     EFI_ERROR (DhcpValidateOptions (Token->Packet, NULL)) ||\r
1039     EFI_IP4_EQUAL (&Token->RemoteAddress, &mZeroIp4Addr)) {\r
1040     //\r
1041     // The DHCP packet isn't well-formed, the Transaction ID is already used\r
1042     // , the timeout value is zero, the ListenPoint is invalid,\r
1043     // or the RemoteAddress is zero.\r
1044     //\r
1045     return EFI_INVALID_PARAMETER;\r
1046   }\r
1047 \r
1048   if (DhcpSb->ClientAddr == 0) {\r
1049 \r
1050     return EFI_NO_MAPPING;\r
1051   }\r
1052 \r
1053   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
1054 \r
1055   //\r
1056   // Save the token and the timeout value.\r
1057   //\r
1058   Instance->Token   = Token;\r
1059   Instance->Timeout = Token->TimeoutValue;\r
1060 \r
1061   //\r
1062   // Create a UDP IO for this transmit receive transaction.\r
1063   //\r
1064   Status = Dhcp4InstanceCreateUdpIo (Instance);\r
1065   if (EFI_ERROR (Status)) {\r
1066     goto ON_ERROR;\r
1067   }\r
1068 \r
1069   //\r
1070   // Wrap the DHCP packet into a net buffer.\r
1071   //\r
1072   Frag.Bulk = (UINT8 *) &Token->Packet->Dhcp4;\r
1073   Frag.Len  = Token->Packet->Length;\r
1074   Wrap      = NetbufFromExt (&Frag, 1, 0, 0, DhcpDummyExtFree, NULL);\r
1075   if (Wrap == NULL) {\r
1076     Status = EFI_OUT_OF_RESOURCES;\r
1077     goto ON_ERROR;\r
1078   }\r
1079 \r
1080   //\r
1081   // Set the local address and local port.\r
1082   //\r
1083   EndPoint.LocalAddr = 0;\r
1084   EndPoint.LocalPort = 0;\r
1085 \r
1086   //\r
1087   // Set the destination address and destination port.\r
1088   //\r
1089   CopyMem (&Ip, &Token->RemoteAddress, sizeof (EFI_IPv4_ADDRESS));\r
1090   EndPoint.RemoteAddr = NTOHL (Ip);\r
1091 \r
1092   if (Token->RemotePort == 0) {\r
1093     EndPoint.RemotePort = DHCP_SERVER_PORT;\r
1094   } else {\r
1095     EndPoint.RemotePort = Token->RemotePort;\r
1096   }\r
1097 \r
1098   //\r
1099   // Get the gateway.\r
1100   //\r
1101   SubnetMask = DhcpSb->Netmask;\r
1102   Gateway    = 0;\r
1103   if (!IP4_NET_EQUAL (DhcpSb->ClientAddr, EndPoint.RemoteAddr, SubnetMask)) {\r
1104     CopyMem (&Gateway, &Token->GatewayAddress, sizeof (EFI_IPv4_ADDRESS));\r
1105     Gateway = NTOHL (Gateway);\r
1106   }\r
1107 \r
1108   //\r
1109   // Transmit the DHCP packet.\r
1110   //\r
1111   Status = UdpIoSendDatagram (Instance->UdpIo, Wrap, &EndPoint, Gateway, DhcpOnPacketSent, NULL);\r
1112   if (EFI_ERROR (Status)) {\r
1113     NetbufFree (Wrap);\r
1114     goto ON_ERROR;\r
1115   }\r
1116 \r
1117   //\r
1118   // Start to receive the DHCP response.\r
1119   //\r
1120   Status = UdpIoRecvDatagram (Instance->UdpIo, PxeDhcpInput, Instance, 0);\r
1121   if (EFI_ERROR (Status)) {\r
1122     goto ON_ERROR;\r
1123   }\r
1124 \r
1125 ON_ERROR:\r
1126 \r
1127   if (EFI_ERROR (Status) && (Instance->UdpIo != NULL)) {\r
1128     UdpIoCleanPort (Instance->UdpIo);\r
1129     UdpIoFreePort (Instance->UdpIo);\r
1130     Instance->UdpIo = NULL;\r
1131     Instance->Token = NULL;\r
1132   }\r
1133 \r
1134   gBS->RestoreTPL (OldTpl);\r
1135 \r
1136   if (!EFI_ERROR (Status) && (Token->CompletionEvent == NULL)) {\r
1137     //\r
1138     // Keep polling until timeout if no error happens and the CompletionEvent\r
1139     // is NULL.\r
1140     //\r
1141     while (Instance->Timeout != 0) {\r
1142       Instance->UdpIo->Udp->Poll (Instance->UdpIo->Udp);\r
1143     }\r
1144   }\r
1145 \r
1146   return Status;\r
1147 }\r
1148 \r
1149 \r
1150 /**\r
1151   Callback function for DhcpIterateOptions. This callback sets the\r
1152   EFI_DHCP4_PACKET_OPTION array in the DHCP_PARSE_CONTEXT to point\r
1153   the individual DHCP option in the packet.\r
1154 \r
1155   @param  Tag                    The DHCP option type\r
1156   @param  Len                    length of the DHCP option data\r
1157   @param  Data                   The DHCP option data\r
1158   @param  Context                The context, to pass several parameters in.\r
1159 \r
1160   @retval EFI_SUCCESS            It always returns EFI_SUCCESS\r
1161 \r
1162 **/\r
1163 STATIC\r
1164 EFI_STATUS\r
1165 Dhcp4ParseCheckOption (\r
1166   IN UINT8                  Tag,\r
1167   IN UINT8                  Len,\r
1168   IN UINT8                  *Data,\r
1169   IN VOID                   *Context\r
1170   )\r
1171 {\r
1172   DHCP_PARSE_CONTEXT        *Parse;\r
1173 \r
1174   Parse = (DHCP_PARSE_CONTEXT *) Context;\r
1175   Parse->Index++;\r
1176 \r
1177   if (Parse->Index <= Parse->OptionCount) {\r
1178     //\r
1179     // Use _CR to get the memory position of EFI_DHCP4_PACKET_OPTION for\r
1180     // the EFI_DHCP4_PACKET_OPTION->Data because DhcpIterateOptions only\r
1181     // pass in the point to option data.\r
1182     //\r
1183     Parse->Option[Parse->Index - 1] = _CR (Data, EFI_DHCP4_PACKET_OPTION, Data);\r
1184   }\r
1185 \r
1186   return EFI_SUCCESS;\r
1187 }\r
1188 \r
1189 \r
1190 /**\r
1191   Parse the DHCP options in the Packet into the PacketOptionList.\r
1192   User should allocate this array of EFI_DHCP4_PACKET_OPTION points.\r
1193 \r
1194   @param  This                   The DHCP protocol instance\r
1195   @param  Packet                 The DHCP packet to parse\r
1196   @param  OptionCount            On input, the size of the PacketOptionList; On\r
1197                                  output,  the actual number of options processed.\r
1198   @param  PacketOptionList       The array of EFI_DHCP4_PACKET_OPTION points\r
1199 \r
1200   @retval EFI_INVALID_PARAMETER  The parameters are invalid.\r
1201   @retval EFI_BUFFER_TOO_SMALL   A bigger array of points is needed.\r
1202   @retval EFI_SUCCESS            The options are parsed.\r
1203 \r
1204 **/\r
1205 STATIC\r
1206 EFI_STATUS\r
1207 EFIAPI\r
1208 EfiDhcp4Parse (\r
1209   IN EFI_DHCP4_PROTOCOL       *This,\r
1210   IN EFI_DHCP4_PACKET         *Packet,\r
1211   IN OUT UINT32               *OptionCount,\r
1212   OUT EFI_DHCP4_PACKET_OPTION *PacketOptionList[] OPTIONAL\r
1213   )\r
1214 {\r
1215   DHCP_PARSE_CONTEXT        Context;\r
1216   EFI_STATUS                Status;\r
1217 \r
1218   //\r
1219   // First validate the parameters\r
1220   //\r
1221   if ((This == NULL) || (Packet == NULL) || (OptionCount == NULL)) {\r
1222     return EFI_INVALID_PARAMETER;\r
1223   }\r
1224 \r
1225   if ((Packet->Size < Packet->Length + 2 * sizeof (UINT32)) ||\r
1226       (Packet->Dhcp4.Magik != DHCP_OPTION_MAGIC) ||\r
1227       EFI_ERROR (DhcpValidateOptions (Packet, NULL))) {\r
1228 \r
1229     return EFI_INVALID_PARAMETER;\r
1230   }\r
1231 \r
1232   if ((*OptionCount != 0) && (PacketOptionList == NULL)) {\r
1233     return EFI_BUFFER_TOO_SMALL;\r
1234   }\r
1235 \r
1236   ZeroMem (PacketOptionList, *OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));\r
1237 \r
1238   Context.Option      = PacketOptionList;\r
1239   Context.OptionCount = *OptionCount;\r
1240   Context.Index       = 0;\r
1241 \r
1242   Status              = DhcpIterateOptions (Packet, Dhcp4ParseCheckOption, &Context);\r
1243 \r
1244   if (EFI_ERROR (Status)) {\r
1245     return Status;\r
1246   }\r
1247 \r
1248   *OptionCount = Context.Index;\r
1249 \r
1250   if (Context.Index > Context.OptionCount) {\r
1251     return EFI_BUFFER_TOO_SMALL;\r
1252   }\r
1253 \r
1254   return EFI_SUCCESS;\r
1255 }\r
1256 \r
1257 EFI_DHCP4_PROTOCOL  mDhcp4ProtocolTemplate = {\r
1258   EfiDhcp4GetModeData,\r
1259   EfiDhcp4Configure,\r
1260   EfiDhcp4Start,\r
1261   EfiDhcp4RenewRebind,\r
1262   EfiDhcp4Release,\r
1263   EfiDhcp4Stop,\r
1264   EfiDhcp4Build,\r
1265   EfiDhcp4TransmitReceive,\r
1266   EfiDhcp4Parse\r
1267 };\r
1268 \r