1. clean up codes.
[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   if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {\r
62     return EFI_INVALID_PARAMETER;\r
63   }\r
64 \r
65   OldTpl  = NET_RAISE_TPL (NET_TPL_LOCK);\r
66   DhcpSb  = Instance->Service;\r
67 \r
68   //\r
69   // Caller can use GetModeData to retrieve current DHCP states\r
70   // no matter whether it is the active child or not.\r
71   //\r
72   Dhcp4ModeData->State                     = (EFI_DHCP4_STATE) DhcpSb->DhcpState;\r
73   CopyMem (&Dhcp4ModeData->ConfigData, &DhcpSb->ActiveConfig, sizeof (Dhcp4ModeData->ConfigData));\r
74   CopyMem (&Dhcp4ModeData->ClientMacAddress, &DhcpSb->Mac, sizeof (Dhcp4ModeData->ClientMacAddress));\r
75 \r
76   Ip = HTONL (DhcpSb->ClientAddr);\r
77   NetCopyMem (&Dhcp4ModeData->ClientAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
78 \r
79   Ip = HTONL (DhcpSb->Netmask);\r
80   NetCopyMem (&Dhcp4ModeData->SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
81 \r
82   Ip = HTONL (DhcpSb->ServerAddr);\r
83   NetCopyMem (&Dhcp4ModeData->ServerAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
84 \r
85   Para = DhcpSb->Para;\r
86 \r
87   if (Para != NULL) {\r
88     Ip = HTONL (Para->Router);\r
89     NetCopyMem (&Dhcp4ModeData->RouterAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
90     Dhcp4ModeData->LeaseTime               = Para->Lease;\r
91   } else {\r
92     NetZeroMem (&Dhcp4ModeData->RouterAddress, sizeof (EFI_IPv4_ADDRESS));\r
93     Dhcp4ModeData->LeaseTime               = 0xffffffff;\r
94   }\r
95 \r
96   Dhcp4ModeData->ReplyPacket = DhcpSb->Selected;\r
97 \r
98   NET_RESTORE_TPL (OldTpl);\r
99   return EFI_SUCCESS;\r
100 }\r
101 \r
102 \r
103 /**\r
104   Free the resource related to the configure parameters.\r
105   DHCP driver will make a copy of the user's configure\r
106   such as the time out value.\r
107 \r
108   @param  Config                 The DHCP configure data\r
109 \r
110   @return None\r
111 \r
112 **/\r
113 VOID\r
114 DhcpCleanConfigure (\r
115   IN EFI_DHCP4_CONFIG_DATA  *Config\r
116   )\r
117 {\r
118   UINT32                    Index;\r
119 \r
120   if (Config->DiscoverTimeout != NULL) {\r
121     NetFreePool (Config->DiscoverTimeout);\r
122   }\r
123 \r
124   if (Config->RequestTimeout != NULL) {\r
125     NetFreePool (Config->RequestTimeout);\r
126   }\r
127 \r
128   if (Config->OptionList != NULL) {\r
129     for (Index = 0; Index < Config->OptionCount; Index++) {\r
130       if (Config->OptionList[Index] != NULL) {\r
131         NetFreePool (Config->OptionList[Index]);\r
132       }\r
133     }\r
134 \r
135     NetFreePool (Config->OptionList);\r
136   }\r
137 \r
138   NetZeroMem (Config, sizeof (EFI_DHCP4_CONFIG_DATA));\r
139 }\r
140 \r
141 \r
142 /**\r
143   Allocate memory for configure parameter such as timeout value for Dst,\r
144   then copy the configure parameter from Src to Dst.\r
145 \r
146   @param  Dst                    The destination DHCP configure data.\r
147   @param  Src                    The source DHCP configure data.\r
148 \r
149   @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory.\r
150   @retval EFI_SUCCESS            The configure is copied.\r
151 \r
152 **/\r
153 EFI_STATUS\r
154 DhcpCopyConfigure (\r
155   IN EFI_DHCP4_CONFIG_DATA  *Dst,\r
156   IN EFI_DHCP4_CONFIG_DATA  *Src\r
157   )\r
158 {\r
159   EFI_DHCP4_PACKET_OPTION   **DstOptions;\r
160   EFI_DHCP4_PACKET_OPTION   **SrcOptions;\r
161   INTN                      Len;\r
162   UINT32                    Index;\r
163 \r
164   CopyMem (Dst, Src, sizeof (*Dst));\r
165   Dst->DiscoverTimeout  = NULL;\r
166   Dst->RequestTimeout   = NULL;\r
167   Dst->OptionList       = NULL;\r
168 \r
169   //\r
170   // Allocate a memory then copy DiscoverTimeout to it\r
171   //\r
172   if (Src->DiscoverTimeout != NULL) {\r
173     Len                   = Src->DiscoverTryCount * sizeof (UINT32);\r
174     Dst->DiscoverTimeout  = NetAllocatePool (Len);\r
175 \r
176     if (Dst->DiscoverTimeout == NULL) {\r
177       return EFI_OUT_OF_RESOURCES;\r
178     }\r
179 \r
180     for (Index = 0; Index < Src->DiscoverTryCount; Index++) {\r
181       Dst->DiscoverTimeout[Index] = NET_MAX (Src->DiscoverTimeout[Index], 1);\r
182     }\r
183   }\r
184 \r
185   //\r
186   // Allocate a memory then copy RequestTimeout to it\r
187   //\r
188   if (Src->RequestTimeout != NULL) {\r
189     Len                 = Src->RequestTryCount * sizeof (UINT32);\r
190     Dst->RequestTimeout = NetAllocatePool (Len);\r
191 \r
192     if (Dst->RequestTimeout == NULL) {\r
193       goto ON_ERROR;\r
194     }\r
195 \r
196     for (Index = 0; Index < Src->RequestTryCount; Index++) {\r
197       Dst->RequestTimeout[Index] = NET_MAX (Src->RequestTimeout[Index], 1);\r
198     }\r
199   }\r
200 \r
201   //\r
202   // Allocate an array of dhcp option point, then allocate memory\r
203   // for each option and copy the source option to it\r
204   //\r
205   if (Src->OptionList != NULL) {\r
206     Len             = Src->OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *);\r
207     Dst->OptionList = NetAllocateZeroPool (Len);\r
208 \r
209     if (Dst->OptionList == NULL) {\r
210       goto ON_ERROR;\r
211     }\r
212 \r
213     DstOptions  = Dst->OptionList;\r
214     SrcOptions  = Src->OptionList;\r
215 \r
216     for (Index = 0; Index < Src->OptionCount; Index++) {\r
217       Len = sizeof (EFI_DHCP4_PACKET_OPTION) + NET_MAX (SrcOptions[Index]->Length - 1, 0);\r
218 \r
219       DstOptions[Index] = NetAllocatePool (Len);\r
220 \r
221       if (DstOptions[Index] == NULL) {\r
222         goto ON_ERROR;\r
223       }\r
224 \r
225       NetCopyMem (DstOptions[Index], SrcOptions[Index], Len);\r
226     }\r
227   }\r
228 \r
229   return EFI_SUCCESS;\r
230 \r
231 ON_ERROR:\r
232   DhcpCleanConfigure (Dst);\r
233   return EFI_OUT_OF_RESOURCES;\r
234 }\r
235 \r
236 \r
237 /**\r
238   Give up the control of the DHCP service to let other child\r
239   resume. Don't change the service's DHCP state and the Client\r
240   address and option list configure as required by RFC2131.\r
241 \r
242   @param  DhcpSb                 The DHCP service instance.\r
243 \r
244   @return None\r
245 \r
246 **/\r
247 VOID\r
248 DhcpYieldControl (\r
249   IN DHCP_SERVICE           *DhcpSb\r
250   )\r
251 {\r
252   EFI_DHCP4_CONFIG_DATA     *Config;\r
253 \r
254   Config    = &DhcpSb->ActiveConfig;\r
255 \r
256   DhcpSb->ServiceState  = DHCP_UNCONFIGED;\r
257   DhcpSb->ActiveChild   = NULL;\r
258 \r
259   if (Config->DiscoverTimeout != NULL) {\r
260     NetFreePool (Config->DiscoverTimeout);\r
261 \r
262     Config->DiscoverTryCount  = 0;\r
263     Config->DiscoverTimeout   = NULL;\r
264   }\r
265 \r
266   if (Config->RequestTimeout != NULL) {\r
267     NetFreePool (Config->RequestTimeout);\r
268 \r
269     Config->RequestTryCount = 0;\r
270     Config->RequestTimeout  = NULL;\r
271   }\r
272 \r
273   Config->Dhcp4Callback   = NULL;\r
274   Config->CallbackContext = NULL;\r
275 }\r
276 \r
277 \r
278 /**\r
279   Configure the DHCP protocol instance and its underlying DHCP service\r
280   for operation. If Dhcp4CfgData is NULL and the child is currently\r
281   controlling the DHCP service, release the control.\r
282 \r
283   @param  This                   The DHCP protocol instance\r
284   @param  Dhcp4CfgData           The DHCP configure data.\r
285 \r
286   @retval EFI_INVALID_PARAMETER  The parameters are invalid.\r
287   @retval EFI_ACCESS_DENIED      The service isn't in one of configurable states,\r
288                                  or there is already an active child.\r
289   @retval EFI_OUT_OF_RESOURCE    Failed to allocate some resources.\r
290   @retval EFI_SUCCESS            The child is configured.\r
291 \r
292 **/\r
293 STATIC\r
294 EFI_STATUS\r
295 EFIAPI\r
296 EfiDhcp4Configure (\r
297   IN EFI_DHCP4_PROTOCOL     *This,\r
298   IN EFI_DHCP4_CONFIG_DATA  *Dhcp4CfgData       OPTIONAL\r
299   )\r
300 {\r
301   EFI_DHCP4_CONFIG_DATA     *Config;\r
302   DHCP_PROTOCOL             *Instance;\r
303   DHCP_SERVICE              *DhcpSb;\r
304   EFI_STATUS                Status;\r
305   EFI_TPL                   OldTpl;\r
306   UINT32                    Index;\r
307   IP4_ADDR                  Ip;\r
308 \r
309   //\r
310   // First validate the parameters\r
311   //\r
312   if (This == NULL) {\r
313     return EFI_INVALID_PARAMETER;\r
314   }\r
315 \r
316   if (Dhcp4CfgData != NULL) {\r
317     if (Dhcp4CfgData->DiscoverTryCount && (Dhcp4CfgData->DiscoverTimeout == NULL)) {\r
318       return EFI_INVALID_PARAMETER;\r
319     }\r
320 \r
321     if (Dhcp4CfgData->RequestTryCount && (Dhcp4CfgData->RequestTimeout == NULL)) {\r
322       return EFI_INVALID_PARAMETER;\r
323     }\r
324 \r
325     if (Dhcp4CfgData->OptionCount && (Dhcp4CfgData->OptionList == NULL)) {\r
326       return EFI_INVALID_PARAMETER;\r
327     }\r
328 \r
329     NetCopyMem (&Ip, &Dhcp4CfgData->ClientAddress, sizeof (IP4_ADDR));\r
330 \r
331     if ((Ip != 0) && !Ip4IsUnicast (NTOHL (Ip), 0)) {\r
332 \r
333       return EFI_INVALID_PARAMETER;\r
334     }\r
335   }\r
336 \r
337   Instance = DHCP_INSTANCE_FROM_THIS (This);\r
338 \r
339   if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {\r
340     return EFI_INVALID_PARAMETER;\r
341   }\r
342 \r
343   OldTpl  = NET_RAISE_TPL (NET_TPL_LOCK);\r
344 \r
345   DhcpSb  = Instance->Service;\r
346   Config  = &DhcpSb->ActiveConfig;\r
347 \r
348   Status  = EFI_ACCESS_DENIED;\r
349 \r
350   if ((DhcpSb->DhcpState != Dhcp4Stopped) &&\r
351       (DhcpSb->DhcpState != Dhcp4Init) &&\r
352       (DhcpSb->DhcpState != Dhcp4InitReboot) &&\r
353       (DhcpSb->DhcpState != Dhcp4Bound)) {\r
354 \r
355     goto ON_EXIT;\r
356   }\r
357 \r
358   if ((DhcpSb->ActiveChild != NULL) && (DhcpSb->ActiveChild != Instance)) {\r
359     goto ON_EXIT;\r
360   }\r
361 \r
362   if (Dhcp4CfgData != NULL) {\r
363     Status = EFI_OUT_OF_RESOURCES;\r
364     DhcpCleanConfigure (Config);\r
365 \r
366     if (EFI_ERROR (DhcpCopyConfigure (Config, Dhcp4CfgData))) {\r
367       goto ON_EXIT;\r
368     }\r
369 \r
370     DhcpSb->UserOptionLen = 0;\r
371 \r
372     for (Index = 0; Index < Dhcp4CfgData->OptionCount; Index++) {\r
373       DhcpSb->UserOptionLen += Dhcp4CfgData->OptionList[Index]->Length + 2;\r
374     }\r
375 \r
376     DhcpSb->ActiveChild = Instance;\r
377 \r
378     if (DhcpSb->DhcpState == Dhcp4Stopped) {\r
379       DhcpSb->ClientAddr = EFI_NTOHL (Dhcp4CfgData->ClientAddress);\r
380 \r
381       if (DhcpSb->ClientAddr != 0) {\r
382         DhcpSb->DhcpState = Dhcp4InitReboot;\r
383       } else {\r
384         DhcpSb->DhcpState = Dhcp4Init;\r
385       }\r
386     }\r
387 \r
388     DhcpSb->ServiceState  = DHCP_CONFIGED;\r
389     Status                = EFI_SUCCESS;\r
390 \r
391   } else if (DhcpSb->ActiveChild == Instance) {\r
392     Status = EFI_SUCCESS;\r
393     DhcpYieldControl (DhcpSb);\r
394   }\r
395 \r
396 ON_EXIT:\r
397   NET_RESTORE_TPL (OldTpl);\r
398   return Status;\r
399 }\r
400 \r
401 \r
402 /**\r
403   Start the DHCP process.\r
404 \r
405   @param  This                   The DHCP protocol instance\r
406   @param  CompletionEvent        The event to signal is address is acquired.\r
407 \r
408   @retval EFI_INVALID_PARAMETER  The parameters are invalid.\r
409   @retval EFI_NOT_STARTED        The protocol hasn't been configured.\r
410   @retval EFI_ALREADY_STARTED    The DHCP process has already been started.\r
411   @retval EFI_SUCCESS            The DHCP process is started.\r
412 \r
413 **/\r
414 STATIC\r
415 EFI_STATUS\r
416 EFIAPI\r
417 EfiDhcp4Start (\r
418   IN EFI_DHCP4_PROTOCOL     *This,\r
419   IN EFI_EVENT              CompletionEvent   OPTIONAL\r
420   )\r
421 {\r
422   DHCP_PROTOCOL             *Instance;\r
423   DHCP_SERVICE              *DhcpSb;\r
424   EFI_STATUS                Status;\r
425   EFI_TPL                   OldTpl;\r
426 \r
427   //\r
428   // First validate the parameters\r
429   //\r
430   if (This == NULL) {\r
431     return EFI_INVALID_PARAMETER;\r
432   }\r
433 \r
434   Instance = DHCP_INSTANCE_FROM_THIS (This);\r
435 \r
436   if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {\r
437     return EFI_INVALID_PARAMETER;\r
438   }\r
439 \r
440   OldTpl  = NET_RAISE_TPL (NET_TPL_LOCK);\r
441   DhcpSb  = Instance->Service;\r
442 \r
443   if (DhcpSb->DhcpState == Dhcp4Stopped) {\r
444     Status = EFI_NOT_STARTED;\r
445     goto ON_ERROR;\r
446   }\r
447 \r
448   if ((DhcpSb->DhcpState != Dhcp4Init) && (DhcpSb->DhcpState != Dhcp4InitReboot)) {\r
449     Status = EFI_ALREADY_STARTED;\r
450     goto ON_ERROR;\r
451   }\r
452 \r
453   DhcpSb->IoStatus = EFI_ALREADY_STARTED;\r
454 \r
455   if (EFI_ERROR (Status = DhcpInitRequest (DhcpSb))) {\r
456     goto ON_ERROR;\r
457   }\r
458 \r
459   //\r
460   // Start/Restart the receiving.\r
461   //\r
462   Status = UdpIoRecvDatagram (DhcpSb->UdpIo, DhcpInput, DhcpSb, 0);\r
463 \r
464   if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {\r
465     goto ON_ERROR;\r
466   }\r
467 \r
468   Instance->CompletionEvent = CompletionEvent;\r
469 \r
470   //\r
471   // Restore the TPL now, don't call poll function at NET_TPL_LOCK.\r
472   //\r
473   NET_RESTORE_TPL (OldTpl);\r
474 \r
475   if (CompletionEvent == NULL) {\r
476     while (DhcpSb->IoStatus == EFI_ALREADY_STARTED) {\r
477       DhcpSb->UdpIo->Udp->Poll (DhcpSb->UdpIo->Udp);\r
478     }\r
479 \r
480     return DhcpSb->IoStatus;\r
481   }\r
482 \r
483   return EFI_SUCCESS;\r
484 \r
485 ON_ERROR:\r
486   NET_RESTORE_TPL (OldTpl);\r
487   return Status;\r
488 }\r
489 \r
490 \r
491 /**\r
492   Request an extra manual renew/rebind.\r
493 \r
494   @param  This                   The DHCP protocol instance\r
495   @param  RebindRequest          TRUE if request a rebind, otherwise renew it\r
496   @param  CompletionEvent        Event to signal when complete\r
497 \r
498   @retval EFI_INVALID_PARAMETER  The parameters are invalid\r
499   @retval EFI_NOT_STARTED        The DHCP protocol hasn't been started.\r
500   @retval EFI_ACCESS_DENIED      The DHCP protocol isn't in Bound state.\r
501   @retval EFI_SUCCESS            The DHCP is renewed/rebound.\r
502 \r
503 **/\r
504 STATIC\r
505 EFI_STATUS\r
506 EFIAPI\r
507 EfiDhcp4RenewRebind (\r
508   IN EFI_DHCP4_PROTOCOL     *This,\r
509   IN BOOLEAN                RebindRequest,\r
510   IN EFI_EVENT              CompletionEvent   OPTIONAL\r
511   )\r
512 {\r
513   DHCP_PROTOCOL             *Instance;\r
514   DHCP_SERVICE              *DhcpSb;\r
515   EFI_STATUS                Status;\r
516   EFI_TPL                   OldTpl;\r
517 \r
518   //\r
519   // First validate the parameters\r
520   //\r
521   if (This == NULL) {\r
522     return EFI_INVALID_PARAMETER;\r
523   }\r
524 \r
525   Instance = DHCP_INSTANCE_FROM_THIS (This);\r
526 \r
527   if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {\r
528     return EFI_INVALID_PARAMETER;\r
529   }\r
530 \r
531   OldTpl  = NET_RAISE_TPL (NET_TPL_LOCK);\r
532   DhcpSb  = Instance->Service;\r
533 \r
534   if (DhcpSb->DhcpState == Dhcp4Stopped) {\r
535     Status = EFI_NOT_STARTED;\r
536     goto ON_ERROR;\r
537   }\r
538 \r
539   if (DhcpSb->DhcpState != Dhcp4Bound) {\r
540     Status = EFI_ACCESS_DENIED;\r
541     goto ON_ERROR;\r
542   }\r
543 \r
544   if (DHCP_IS_BOOTP (DhcpSb->Para)) {\r
545     return EFI_SUCCESS;\r
546   }\r
547 \r
548   //\r
549   // Transit the states then send a extra DHCP request\r
550   //\r
551   if (!RebindRequest) {\r
552     DhcpSetState (DhcpSb, Dhcp4Renewing, FALSE);\r
553   } else {\r
554     DhcpSetState (DhcpSb, Dhcp4Rebinding, FALSE);\r
555   }\r
556 \r
557   Status = DhcpSendMessage (\r
558              DhcpSb,\r
559              DhcpSb->Selected,\r
560              DhcpSb->Para,\r
561              DHCP_MSG_REQUEST,\r
562              "Extra renew/rebind by the application"\r
563              );\r
564 \r
565   if (EFI_ERROR (Status)) {\r
566     DhcpSetState (DhcpSb, Dhcp4Bound, FALSE);\r
567     goto ON_ERROR;\r
568   }\r
569 \r
570   DhcpSb->ExtraRefresh        = TRUE;\r
571   DhcpSb->IoStatus            = EFI_ALREADY_STARTED;\r
572   Instance->RenewRebindEvent  = CompletionEvent;\r
573 \r
574   NET_RESTORE_TPL (OldTpl);\r
575 \r
576   if (CompletionEvent == NULL) {\r
577     while (DhcpSb->IoStatus == EFI_ALREADY_STARTED) {\r
578       DhcpSb->UdpIo->Udp->Poll (DhcpSb->UdpIo->Udp);\r
579     }\r
580 \r
581     return DhcpSb->IoStatus;\r
582   }\r
583 \r
584   return EFI_SUCCESS;\r
585 \r
586 ON_ERROR:\r
587   NET_RESTORE_TPL (OldTpl);\r
588   return Status;\r
589 }\r
590 \r
591 \r
592 /**\r
593   Release the current acquired lease.\r
594 \r
595   @param  This                   The DHCP protocol instance\r
596 \r
597   @retval EFI_INVALID_PARAMETER  The parameter is invalid\r
598   @retval EFI_DEVICE_ERROR       Failed to transmit the DHCP release packet\r
599   @retval EFI_ACCESS_DENIED      The DHCP service isn't in one of the connected\r
600                                  state.\r
601   @retval EFI_SUCCESS            The lease is released.\r
602 \r
603 **/\r
604 STATIC\r
605 EFI_STATUS\r
606 EFIAPI\r
607 EfiDhcp4Release (\r
608   IN EFI_DHCP4_PROTOCOL     *This\r
609   )\r
610 {\r
611   DHCP_PROTOCOL             *Instance;\r
612   DHCP_SERVICE              *DhcpSb;\r
613   EFI_STATUS                Status;\r
614   EFI_TPL                   OldTpl;\r
615 \r
616   //\r
617   // First validate the parameters\r
618   //\r
619   if (This == NULL) {\r
620     return EFI_INVALID_PARAMETER;\r
621   }\r
622 \r
623   Instance = DHCP_INSTANCE_FROM_THIS (This);\r
624 \r
625   if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {\r
626     return EFI_INVALID_PARAMETER;\r
627   }\r
628 \r
629   Status  = EFI_SUCCESS;\r
630   OldTpl  = NET_RAISE_TPL (NET_TPL_LOCK);\r
631   DhcpSb  = Instance->Service;\r
632 \r
633   if ((DhcpSb->DhcpState != Dhcp4InitReboot) && (DhcpSb->DhcpState != Dhcp4Bound)) {\r
634     Status = EFI_ACCESS_DENIED;\r
635     goto ON_EXIT;\r
636   }\r
637 \r
638   if (!DHCP_IS_BOOTP (DhcpSb->Para) && (DhcpSb->DhcpState == Dhcp4Bound)) {\r
639     Status = DhcpSendMessage (\r
640                DhcpSb,\r
641                DhcpSb->Selected,\r
642                DhcpSb->Para,\r
643                DHCP_MSG_RELEASE,\r
644                NULL\r
645                );\r
646 \r
647     if (EFI_ERROR (Status)) {\r
648       Status = EFI_DEVICE_ERROR;\r
649       goto ON_EXIT;\r
650     }\r
651   }\r
652 \r
653   DhcpCleanLease (DhcpSb);\r
654 \r
655 ON_EXIT:\r
656   NET_RESTORE_TPL (OldTpl);\r
657   return Status;\r
658 }\r
659 \r
660 \r
661 /**\r
662   Stop the current DHCP process. After this, other DHCP child\r
663   can gain control of the service, configure and use it.\r
664 \r
665   @param  This                   The DHCP protocol instance\r
666 \r
667   @retval EFI_INVALID_PARAMETER  The parameter is invalid.\r
668   @retval EFI_SUCCESS            The DHCP process is stopped.\r
669 \r
670 **/\r
671 STATIC\r
672 EFI_STATUS\r
673 EFIAPI\r
674 EfiDhcp4Stop (\r
675   IN EFI_DHCP4_PROTOCOL     *This\r
676   )\r
677 {\r
678   DHCP_PROTOCOL             *Instance;\r
679   DHCP_SERVICE              *DhcpSb;\r
680   EFI_TPL                   OldTpl;\r
681 \r
682   //\r
683   // First validate the parameters\r
684   //\r
685   if (This == NULL) {\r
686     return EFI_INVALID_PARAMETER;\r
687   }\r
688 \r
689   Instance = DHCP_INSTANCE_FROM_THIS (This);\r
690 \r
691   if (Instance->Signature != DHCP_PROTOCOL_SIGNATURE) {\r
692     return EFI_INVALID_PARAMETER;\r
693   }\r
694 \r
695   OldTpl  = NET_RAISE_TPL (NET_TPL_LOCK);\r
696   DhcpSb  = Instance->Service;\r
697 \r
698   DhcpCleanLease (DhcpSb);\r
699 \r
700   DhcpSb->DhcpState     = Dhcp4Stopped;\r
701   DhcpSb->ServiceState  = DHCP_UNCONFIGED;\r
702 \r
703   NET_RESTORE_TPL (OldTpl);\r
704   return EFI_SUCCESS;\r
705 }\r
706 \r
707 \r
708 /**\r
709   Build a new DHCP packet from the seed packet. Options may be deleted or\r
710   appended. The caller should free the NewPacket when finished using it.\r
711 \r
712   @param  This                   The DHCP protocol instance.\r
713   @param  SeedPacket             The seed packet to start with\r
714   @param  DeleteCount            The number of options to delete\r
715   @param  DeleteList             The options to delete from the packet\r
716   @param  AppendCount            The number of options to append\r
717   @param  AppendList             The options to append to the packet\r
718   @param  NewPacket              The new packet, allocated and built by this\r
719                                  function.\r
720 \r
721   @retval EFI_INVALID_PARAMETER  The parameters are invalid.\r
722   @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory\r
723   @retval EFI_SUCCESS            The packet is build.\r
724 \r
725 **/\r
726 STATIC\r
727 EFI_STATUS\r
728 EFIAPI\r
729 EfiDhcp4Build (\r
730   IN EFI_DHCP4_PROTOCOL       *This,\r
731   IN EFI_DHCP4_PACKET         *SeedPacket,\r
732   IN UINT32                   DeleteCount,\r
733   IN UINT8                    *DeleteList OPTIONAL,\r
734   IN UINT32                   AppendCount,\r
735   IN EFI_DHCP4_PACKET_OPTION  *AppendList[] OPTIONAL,\r
736   OUT EFI_DHCP4_PACKET        **NewPacket\r
737   )\r
738 {\r
739   //\r
740   // First validate the parameters\r
741   //\r
742   if ((This == NULL) || (NewPacket == NULL)) {\r
743     return EFI_INVALID_PARAMETER;\r
744   }\r
745 \r
746   if ((SeedPacket == NULL) || (SeedPacket->Dhcp4.Magik != DHCP_OPTION_MAGIC) ||\r
747       EFI_ERROR (DhcpValidateOptions (SeedPacket, NULL))) {\r
748 \r
749     return EFI_INVALID_PARAMETER;\r
750   }\r
751 \r
752   if (((DeleteCount == 0) && (AppendCount == 0)) ||\r
753       ((DeleteCount != 0) && (DeleteList == NULL)) ||\r
754       ((AppendCount != 0) && (AppendList == NULL))) {\r
755 \r
756     return EFI_INVALID_PARAMETER;\r
757   }\r
758 \r
759   return DhcpBuild (\r
760            SeedPacket,\r
761            DeleteCount,\r
762            DeleteList,\r
763            AppendCount,\r
764            AppendList,\r
765            NewPacket\r
766            );\r
767 }\r
768 \r
769 \r
770 /**\r
771   Transmit and receive a packet through this DHCP service.\r
772   This is unsupported.\r
773 \r
774   @param  This                   The DHCP protocol instance\r
775   @param  Token                  The transmit and receive instance\r
776 \r
777   @retval EFI_UNSUPPORTED        It always returns unsupported.\r
778 \r
779 **/\r
780 STATIC\r
781 EFI_STATUS\r
782 EFIAPI\r
783 EfiDhcp4TransmitReceive (\r
784   IN EFI_DHCP4_PROTOCOL                *This,\r
785   IN EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN  *Token\r
786   )\r
787 {\r
788   //\r
789   // This function is for PXE, leave it for now\r
790   //\r
791   return EFI_UNSUPPORTED;\r
792 }\r
793 \r
794 \r
795 /**\r
796   Callback function for DhcpIterateOptions. This callback sets the\r
797   EFI_DHCP4_PACKET_OPTION array in the DHCP_PARSE_CONTEXT to point\r
798   the individual DHCP option in the packet.\r
799 \r
800   @param  Tag                    The DHCP option type\r
801   @param  Len                    length of the DHCP option data\r
802   @param  Data                   The DHCP option data\r
803   @param  Context                The context, to pass several parameters in.\r
804 \r
805   @retval EFI_SUCCESS            It always returns EFI_SUCCESS\r
806 \r
807 **/\r
808 STATIC\r
809 EFI_STATUS\r
810 Dhcp4ParseCheckOption (\r
811   IN UINT8                  Tag,\r
812   IN UINT8                  Len,\r
813   IN UINT8                  *Data,\r
814   IN VOID                   *Context\r
815   )\r
816 {\r
817   DHCP_PARSE_CONTEXT        *Parse;\r
818 \r
819   Parse = (DHCP_PARSE_CONTEXT *) Context;\r
820   Parse->Index++;\r
821 \r
822   if (Parse->Index < Parse->OptionCount) {\r
823     //\r
824     // Use _CR to get the memory position of EFI_DHCP4_PACKET_OPTION for\r
825     // the EFI_DHCP4_PACKET_OPTION->Data because DhcpIterateOptions only\r
826     // pass in the point to option data.\r
827     //\r
828     Parse->Option[Parse->Index - 1] = _CR (Data, EFI_DHCP4_PACKET_OPTION, Data);\r
829   }\r
830 \r
831   return EFI_SUCCESS;\r
832 }\r
833 \r
834 \r
835 /**\r
836   Parse the DHCP options in the Packet into the PacketOptionList.\r
837   User should allocate this array of EFI_DHCP4_PACKET_OPTION points.\r
838 \r
839   @param  This                   The DHCP protocol instance\r
840   @param  Packet                 The DHCP packet to parse\r
841   @param  OptionCount            On input, the size of the PacketOptionList; On\r
842                                  output,  the actual number of options processed.\r
843   @param  PacketOptionList       The array of EFI_DHCP4_PACKET_OPTION points\r
844 \r
845   @retval EFI_INVALID_PARAMETER  The parameters are invalid.\r
846   @retval EFI_BUFFER_TOO_SMALL   A bigger array of points is needed.\r
847   @retval EFI_SUCCESS            The options are parsed.\r
848 \r
849 **/\r
850 STATIC\r
851 EFI_STATUS\r
852 EFIAPI\r
853 EfiDhcp4Parse (\r
854   IN EFI_DHCP4_PROTOCOL       *This,\r
855   IN EFI_DHCP4_PACKET         *Packet,\r
856   IN OUT UINT32               *OptionCount,\r
857   OUT EFI_DHCP4_PACKET_OPTION *PacketOptionList[] OPTIONAL\r
858   )\r
859 {\r
860   DHCP_PARSE_CONTEXT        Context;\r
861   EFI_STATUS                Status;\r
862 \r
863   //\r
864   // First validate the parameters\r
865   //\r
866   if ((This == NULL) || (Packet == NULL) || (OptionCount == NULL)) {\r
867     return EFI_INVALID_PARAMETER;\r
868   }\r
869 \r
870   if ((Packet->Size < Packet->Length + 2 * sizeof (UINT32)) ||\r
871       (Packet->Dhcp4.Magik != DHCP_OPTION_MAGIC) ||\r
872       EFI_ERROR (DhcpValidateOptions (Packet, NULL))) {\r
873 \r
874     return EFI_INVALID_PARAMETER;\r
875   }\r
876 \r
877   if ((*OptionCount != 0) && (PacketOptionList == NULL)) {\r
878     return EFI_BUFFER_TOO_SMALL;\r
879   }\r
880 \r
881   NetZeroMem (PacketOptionList, *OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));\r
882 \r
883   Context.Option      = PacketOptionList;\r
884   Context.OptionCount = *OptionCount;\r
885   Context.Index       = 0;\r
886 \r
887   Status              = DhcpIterateOptions (Packet, Dhcp4ParseCheckOption, &Context);\r
888 \r
889   if (EFI_ERROR (Status)) {\r
890     return Status;\r
891   }\r
892 \r
893   *OptionCount = Context.Index;\r
894 \r
895   if (Context.Index > Context.OptionCount) {\r
896     return EFI_BUFFER_TOO_SMALL;\r
897   }\r
898 \r
899   return EFI_SUCCESS;\r
900 }\r
901 \r
902 EFI_DHCP4_PROTOCOL  mDhcp4ProtocolTemplate = {\r
903   EfiDhcp4GetModeData,\r
904   EfiDhcp4Configure,\r
905   EfiDhcp4Start,\r
906   EfiDhcp4RenewRebind,\r
907   EfiDhcp4Release,\r
908   EfiDhcp4Stop,\r
909   EfiDhcp4Build,\r
910   EfiDhcp4TransmitReceive,\r
911   EfiDhcp4Parse\r
912 };\r