09de4cdaab5dd1767a66c8d0e94bbc1921b0f117
[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   Transmit and receive a packet through this DHCP service.\r
988   This is unsupported.\r
989 \r
990   @param  This                   The DHCP protocol instance\r
991   @param  Token                  The transmit and receive instance\r
992 \r
993   @retval EFI_UNSUPPORTED        It always returns unsupported.\r
994 \r
995 **/\r
996 STATIC\r
997 EFI_STATUS\r
998 EFIAPI\r
999 EfiDhcp4TransmitReceive (\r
1000   IN EFI_DHCP4_PROTOCOL                *This,\r
1001   IN EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN  *Token\r
1002   )\r
1003 {\r
1004   DHCP_PROTOCOL  *Instance;\r
1005   EFI_TPL        OldTpl;\r
1006   EFI_STATUS     Status;\r
1007   NET_FRAGMENT   Frag;\r
1008   NET_BUF        *Wrap;\r
1009   UDP_POINTS     EndPoint;\r
1010   IP4_ADDR       Ip;\r
1011   DHCP_SERVICE   *DhcpSb;\r
1012   IP4_ADDR       Gateway;\r
1013   IP4_ADDR       SubnetMask;\r
1014 \r
1015   if ((This == NULL) || (Token == NULL) || (Token->Packet == NULL)) {\r
1016     return EFI_INVALID_PARAMETER;\r
1017   }\r
1018 \r
1019   Instance = DHCP_INSTANCE_FROM_THIS (This);\r
1020   DhcpSb   = Instance->Service;\r
1021 \r
1022   if (Instance->Token != NULL) {\r
1023     //\r
1024     // The previous call to TransmitReceive is not finished.\r
1025     //\r
1026     return EFI_NOT_READY;\r
1027   }\r
1028 \r
1029   if ((Token->Packet->Dhcp4.Magik != DHCP_OPTION_MAGIC) ||\r
1030     (NTOHL (Token->Packet->Dhcp4.Header.Xid) == Instance->Service->Xid) ||\r
1031     (Token->TimeoutValue == 0) ||\r
1032     ((Token->ListenPointCount != 0) && (Token->ListenPoints == NULL)) ||\r
1033     EFI_ERROR (DhcpValidateOptions (Token->Packet, NULL)) ||\r
1034     EFI_IP4_EQUAL (&Token->RemoteAddress, &mZeroIp4Addr)) {\r
1035     //\r
1036     // The DHCP packet isn't well-formed, the Transaction ID is already used\r
1037     // , the timeout value is zero, the ListenPoint is invalid,\r
1038     // or the RemoteAddress is zero.\r
1039     //\r
1040     return EFI_INVALID_PARAMETER;\r
1041   }\r
1042 \r
1043   if (DhcpSb->ClientAddr == 0) {\r
1044 \r
1045     return EFI_NO_MAPPING;\r
1046   }\r
1047 \r
1048   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
1049 \r
1050   //\r
1051   // Save the token and the timeout value.\r
1052   //\r
1053   Instance->Token   = Token;\r
1054   Instance->Timeout = Token->TimeoutValue;\r
1055 \r
1056   //\r
1057   // Create a UDP IO for this transmit receive transaction.\r
1058   //\r
1059   Status = Dhcp4InstanceCreateUdpIo (Instance);\r
1060   if (EFI_ERROR (Status)) {\r
1061     goto ON_ERROR;\r
1062   }\r
1063 \r
1064   //\r
1065   // Wrap the DHCP packet into a net buffer.\r
1066   //\r
1067   Frag.Bulk = (UINT8 *) &Token->Packet->Dhcp4;\r
1068   Frag.Len  = Token->Packet->Length;\r
1069   Wrap      = NetbufFromExt (&Frag, 1, 0, 0, DhcpDummyExtFree, NULL);\r
1070   if (Wrap == NULL) {\r
1071     Status = EFI_OUT_OF_RESOURCES;\r
1072     goto ON_ERROR;\r
1073   }\r
1074 \r
1075   //\r
1076   // Set the local address and local port.\r
1077   //\r
1078   EndPoint.LocalAddr = 0;\r
1079   EndPoint.LocalPort = 0;\r
1080 \r
1081   //\r
1082   // Set the destination address and destination port.\r
1083   //\r
1084   CopyMem (&Ip, &Token->RemoteAddress, sizeof (EFI_IPv4_ADDRESS));\r
1085   EndPoint.RemoteAddr = NTOHL (Ip);\r
1086 \r
1087   if (Token->RemotePort == 0) {\r
1088     EndPoint.RemotePort = DHCP_SERVER_PORT;\r
1089   } else {\r
1090     EndPoint.RemotePort = Token->RemotePort;\r
1091   }\r
1092 \r
1093   //\r
1094   // Get the gateway.\r
1095   //\r
1096   SubnetMask = DhcpSb->Netmask;\r
1097   Gateway    = 0;\r
1098   if (!IP4_NET_EQUAL (DhcpSb->ClientAddr, EndPoint.RemoteAddr, SubnetMask)) {\r
1099     CopyMem (&Gateway, &Token->GatewayAddress, sizeof (EFI_IPv4_ADDRESS));\r
1100     Gateway = NTOHL (Gateway);\r
1101   }\r
1102 \r
1103   //\r
1104   // Transmit the DHCP packet.\r
1105   //\r
1106   Status = UdpIoSendDatagram (Instance->UdpIo, Wrap, &EndPoint, Gateway, DhcpOnPacketSent, NULL);\r
1107   if (EFI_ERROR (Status)) {\r
1108     NetbufFree (Wrap);\r
1109     goto ON_ERROR;\r
1110   }\r
1111 \r
1112   //\r
1113   // Start to receive the DHCP response.\r
1114   //\r
1115   Status = UdpIoRecvDatagram (Instance->UdpIo, PxeDhcpInput, Instance, 0);\r
1116   if (EFI_ERROR (Status)) {\r
1117     goto ON_ERROR;\r
1118   }\r
1119 \r
1120 ON_ERROR:\r
1121 \r
1122   if (EFI_ERROR (Status) && (Instance->UdpIo != NULL)) {\r
1123     UdpIoCleanPort (Instance->UdpIo);\r
1124     UdpIoFreePort (Instance->UdpIo);\r
1125     Instance->UdpIo = NULL;\r
1126     Instance->Token = NULL;\r
1127   }\r
1128 \r
1129   gBS->RestoreTPL (OldTpl);\r
1130 \r
1131   if (!EFI_ERROR (Status) && (Token->CompletionEvent == NULL)) {\r
1132     //\r
1133     // Keep polling until timeout if no error happens and the CompletionEvent\r
1134     // is NULL.\r
1135     //\r
1136     while (Instance->Timeout != 0) {\r
1137       Instance->UdpIo->Udp->Poll (Instance->UdpIo->Udp);\r
1138     }\r
1139   }\r
1140 \r
1141   return Status;\r
1142 }\r
1143 \r
1144 \r
1145 /**\r
1146   Callback function for DhcpIterateOptions. This callback sets the\r
1147   EFI_DHCP4_PACKET_OPTION array in the DHCP_PARSE_CONTEXT to point\r
1148   the individual DHCP option in the packet.\r
1149 \r
1150   @param  Tag                    The DHCP option type\r
1151   @param  Len                    length of the DHCP option data\r
1152   @param  Data                   The DHCP option data\r
1153   @param  Context                The context, to pass several parameters in.\r
1154 \r
1155   @retval EFI_SUCCESS            It always returns EFI_SUCCESS\r
1156 \r
1157 **/\r
1158 STATIC\r
1159 EFI_STATUS\r
1160 Dhcp4ParseCheckOption (\r
1161   IN UINT8                  Tag,\r
1162   IN UINT8                  Len,\r
1163   IN UINT8                  *Data,\r
1164   IN VOID                   *Context\r
1165   )\r
1166 {\r
1167   DHCP_PARSE_CONTEXT        *Parse;\r
1168 \r
1169   Parse = (DHCP_PARSE_CONTEXT *) Context;\r
1170   Parse->Index++;\r
1171 \r
1172   if (Parse->Index <= Parse->OptionCount) {\r
1173     //\r
1174     // Use _CR to get the memory position of EFI_DHCP4_PACKET_OPTION for\r
1175     // the EFI_DHCP4_PACKET_OPTION->Data because DhcpIterateOptions only\r
1176     // pass in the point to option data.\r
1177     //\r
1178     Parse->Option[Parse->Index - 1] = _CR (Data, EFI_DHCP4_PACKET_OPTION, Data);\r
1179   }\r
1180 \r
1181   return EFI_SUCCESS;\r
1182 }\r
1183 \r
1184 \r
1185 /**\r
1186   Parse the DHCP options in the Packet into the PacketOptionList.\r
1187   User should allocate this array of EFI_DHCP4_PACKET_OPTION points.\r
1188 \r
1189   @param  This                   The DHCP protocol instance\r
1190   @param  Packet                 The DHCP packet to parse\r
1191   @param  OptionCount            On input, the size of the PacketOptionList; On\r
1192                                  output,  the actual number of options processed.\r
1193   @param  PacketOptionList       The array of EFI_DHCP4_PACKET_OPTION points\r
1194 \r
1195   @retval EFI_INVALID_PARAMETER  The parameters are invalid.\r
1196   @retval EFI_BUFFER_TOO_SMALL   A bigger array of points is needed.\r
1197   @retval EFI_SUCCESS            The options are parsed.\r
1198 \r
1199 **/\r
1200 STATIC\r
1201 EFI_STATUS\r
1202 EFIAPI\r
1203 EfiDhcp4Parse (\r
1204   IN EFI_DHCP4_PROTOCOL       *This,\r
1205   IN EFI_DHCP4_PACKET         *Packet,\r
1206   IN OUT UINT32               *OptionCount,\r
1207   OUT EFI_DHCP4_PACKET_OPTION *PacketOptionList[] OPTIONAL\r
1208   )\r
1209 {\r
1210   DHCP_PARSE_CONTEXT        Context;\r
1211   EFI_STATUS                Status;\r
1212 \r
1213   //\r
1214   // First validate the parameters\r
1215   //\r
1216   if ((This == NULL) || (Packet == NULL) || (OptionCount == NULL)) {\r
1217     return EFI_INVALID_PARAMETER;\r
1218   }\r
1219 \r
1220   if ((Packet->Size < Packet->Length + 2 * sizeof (UINT32)) ||\r
1221       (Packet->Dhcp4.Magik != DHCP_OPTION_MAGIC) ||\r
1222       EFI_ERROR (DhcpValidateOptions (Packet, NULL))) {\r
1223 \r
1224     return EFI_INVALID_PARAMETER;\r
1225   }\r
1226 \r
1227   if ((*OptionCount != 0) && (PacketOptionList == NULL)) {\r
1228     return EFI_BUFFER_TOO_SMALL;\r
1229   }\r
1230 \r
1231   ZeroMem (PacketOptionList, *OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));\r
1232 \r
1233   Context.Option      = PacketOptionList;\r
1234   Context.OptionCount = *OptionCount;\r
1235   Context.Index       = 0;\r
1236 \r
1237   Status              = DhcpIterateOptions (Packet, Dhcp4ParseCheckOption, &Context);\r
1238 \r
1239   if (EFI_ERROR (Status)) {\r
1240     return Status;\r
1241   }\r
1242 \r
1243   *OptionCount = Context.Index;\r
1244 \r
1245   if (Context.Index > Context.OptionCount) {\r
1246     return EFI_BUFFER_TOO_SMALL;\r
1247   }\r
1248 \r
1249   return EFI_SUCCESS;\r
1250 }\r
1251 \r
1252 EFI_DHCP4_PROTOCOL  mDhcp4ProtocolTemplate = {\r
1253   EfiDhcp4GetModeData,\r
1254   EfiDhcp4Configure,\r
1255   EfiDhcp4Start,\r
1256   EfiDhcp4RenewRebind,\r
1257   EfiDhcp4Release,\r
1258   EfiDhcp4Stop,\r
1259   EfiDhcp4Build,\r
1260   EfiDhcp4TransmitReceive,\r
1261   EfiDhcp4Parse\r
1262 };\r
1263 \r