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