]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Dhcp4Dxe/Dhcp4Impl.c
enhanced UefiPxeBcDxe to support
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Dhcp4Dxe / Dhcp4Impl.c
CommitLineData
772db4bb 1/** @file\r
2\r
3Copyright (c) 2006 - 2007, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12Module Name:\r
13\r
14 Dhcp4Impl.c\r
15\r
16Abstract:\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
38STATIC\r
39EFI_STATUS\r
40EFIAPI\r
41EfiDhcp4GetModeData (\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
982a9eae 60\r
e48e37fc 61 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
772db4bb 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
687a2e5f 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
772db4bb 71\r
72 Ip = HTONL (DhcpSb->ClientAddr);\r
e48e37fc 73 CopyMem (&Dhcp4ModeData->ClientAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
772db4bb 74\r
75 Ip = HTONL (DhcpSb->Netmask);\r
e48e37fc 76 CopyMem (&Dhcp4ModeData->SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
772db4bb 77\r
78 Ip = HTONL (DhcpSb->ServerAddr);\r
e48e37fc 79 CopyMem (&Dhcp4ModeData->ServerAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
772db4bb 80\r
81 Para = DhcpSb->Para;\r
82\r
83 if (Para != NULL) {\r
84 Ip = HTONL (Para->Router);\r
e48e37fc 85 CopyMem (&Dhcp4ModeData->RouterAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
772db4bb 86 Dhcp4ModeData->LeaseTime = Para->Lease;\r
87 } else {\r
e48e37fc 88 ZeroMem (&Dhcp4ModeData->RouterAddress, sizeof (EFI_IPv4_ADDRESS));\r
772db4bb 89 Dhcp4ModeData->LeaseTime = 0xffffffff;\r
90 }\r
91\r
92 Dhcp4ModeData->ReplyPacket = DhcpSb->Selected;\r
93\r
e48e37fc 94 gBS->RestoreTPL (OldTpl);\r
772db4bb 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
109VOID\r
110DhcpCleanConfigure (\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
e48e37fc 117 gBS->FreePool (Config->DiscoverTimeout);\r
772db4bb 118 }\r
119\r
120 if (Config->RequestTimeout != NULL) {\r
e48e37fc 121 gBS->FreePool (Config->RequestTimeout);\r
772db4bb 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
e48e37fc 127 gBS->FreePool (Config->OptionList[Index]);\r
772db4bb 128 }\r
129 }\r
130\r
e48e37fc 131 gBS->FreePool (Config->OptionList);\r
772db4bb 132 }\r
133\r
e48e37fc 134 ZeroMem (Config, sizeof (EFI_DHCP4_CONFIG_DATA));\r
772db4bb 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
149EFI_STATUS\r
150DhcpCopyConfigure (\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
72030458 160 CopyMem (Dst, Src, sizeof (*Dst));\r
772db4bb 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
e48e37fc 170 Dst->DiscoverTimeout = AllocatePool (Len);\r
772db4bb 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
36ee91ca 177 Dst->DiscoverTimeout[Index] = MAX (Src->DiscoverTimeout[Index], 1);\r
772db4bb 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
e48e37fc 186 Dst->RequestTimeout = AllocatePool (Len);\r
772db4bb 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
36ee91ca 193 Dst->RequestTimeout[Index] = MAX (Src->RequestTimeout[Index], 1);\r
772db4bb 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
e48e37fc 203 Dst->OptionList = AllocateZeroPool (Len);\r
772db4bb 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
36ee91ca 213 Len = sizeof (EFI_DHCP4_PACKET_OPTION) + MAX (SrcOptions[Index]->Length - 1, 0);\r
772db4bb 214\r
e48e37fc 215 DstOptions[Index] = AllocatePool (Len);\r
772db4bb 216\r
217 if (DstOptions[Index] == NULL) {\r
218 goto ON_ERROR;\r
219 }\r
220\r
e48e37fc 221 CopyMem (DstOptions[Index], SrcOptions[Index], Len);\r
772db4bb 222 }\r
223 }\r
224\r
225 return EFI_SUCCESS;\r
226\r
227ON_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
243VOID\r
244DhcpYieldControl (\r
245 IN DHCP_SERVICE *DhcpSb\r
246 )\r
247{\r
248 EFI_DHCP4_CONFIG_DATA *Config;\r
772db4bb 249\r
772db4bb 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
e48e37fc 256 gBS->FreePool (Config->DiscoverTimeout);\r
772db4bb 257\r
258 Config->DiscoverTryCount = 0;\r
259 Config->DiscoverTimeout = NULL;\r
260 }\r
261\r
262 if (Config->RequestTimeout != NULL) {\r
e48e37fc 263 gBS->FreePool (Config->RequestTimeout);\r
772db4bb 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
289STATIC\r
290EFI_STATUS\r
291EFIAPI\r
292EfiDhcp4Configure (\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
e48e37fc 325 CopyMem (&Ip, &Dhcp4CfgData->ClientAddress, sizeof (IP4_ADDR));\r
772db4bb 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
e48e37fc 339 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
772db4bb 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
392ON_EXIT:\r
e48e37fc 393 gBS->RestoreTPL (OldTpl);\r
772db4bb 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
410STATIC\r
411EFI_STATUS\r
412EFIAPI\r
413EfiDhcp4Start (\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
e48e37fc 436 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
772db4bb 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
e48e37fc 467 // Restore the TPL now, don't call poll function at TPL_CALLBACK.\r
772db4bb 468 //\r
e48e37fc 469 gBS->RestoreTPL (OldTpl);\r
772db4bb 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
481ON_ERROR:\r
e48e37fc 482 gBS->RestoreTPL (OldTpl);\r
772db4bb 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
500STATIC\r
501EFI_STATUS\r
502EFIAPI\r
503EfiDhcp4RenewRebind (\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
e48e37fc 527 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
772db4bb 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
67a58d0f 558 (UINT8 *) "Extra renew/rebind by the application"\r
772db4bb 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
e48e37fc 570 gBS->RestoreTPL (OldTpl);\r
772db4bb 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
582ON_ERROR:\r
e48e37fc 583 gBS->RestoreTPL (OldTpl);\r
772db4bb 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
600STATIC\r
601EFI_STATUS\r
602EFIAPI\r
603EfiDhcp4Release (\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
e48e37fc 626 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
772db4bb 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
651ON_EXIT:\r
e48e37fc 652 gBS->RestoreTPL (OldTpl);\r
772db4bb 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
667STATIC\r
668EFI_STATUS\r
669EFIAPI\r
670EfiDhcp4Stop (\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
e48e37fc 691 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
772db4bb 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
e48e37fc 699 gBS->RestoreTPL (OldTpl);\r
772db4bb 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
722STATIC\r
723EFI_STATUS\r
724EFIAPI\r
725EfiDhcp4Build (\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
c4a62a12 765STATIC\r
766EFI_STATUS\r
767Dhcp4InstanceConfigUdpIo (\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
e48e37fc 782 ZeroMem (&UdpConfigData, sizeof (EFI_UDP4_CONFIG_DATA));\r
c4a62a12 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
e48e37fc 790 CopyMem (&UdpConfigData.StationAddress, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
c4a62a12 791\r
792 Ip = HTONL (DhcpSb->Netmask);\r
e48e37fc 793 CopyMem (&UdpConfigData.SubnetMask, &Ip, sizeof (EFI_IPv4_ADDRESS));\r
c4a62a12 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
804STATIC\r
805EFI_STATUS\r
806Dhcp4InstanceCreateUdpIo (\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
823STATIC\r
824VOID\r
825DhcpDummyExtFree (\r
826 IN VOID *Arg\r
827 )\r
828/*++\r
829\r
830Routine Description:\r
831\r
832 Release the packet.\r
833\r
834Arguments:\r
835\r
836 Arg - The packet to release\r
837\r
838Returns:\r
839\r
840 None\r
841\r
842--*/\r
982a9eae 843{\r
c4a62a12 844}\r
845\r
846VOID\r
847PxeDhcpInput (\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
982a9eae 876\r
c4a62a12 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
982a9eae 883\r
c4a62a12 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
982a9eae 903\r
c4a62a12 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
982a9eae 909 (CompareMem (DhcpSb->ClientAddressSendOut, Head->ClientHwAddr, Head->HwAddrLen) != 0)) {\r
c4a62a12 910 goto RESTART;\r
911 }\r
982a9eae 912\r
c4a62a12 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
929RESTART:\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
943VOID\r
944PxeDhcpDone (\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
e48e37fc 954 Token->ResponseList = (EFI_DHCP4_PACKET *) AllocatePool (Instance->ResponseQueue.BufSize);\r
c4a62a12 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
970SIGNAL_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
982a9eae 982 }\r
c4a62a12 983}\r
984\r
772db4bb 985\r
986/**\r
ba39e316 987 Transmits a DHCP formatted packet and optionally waits for responses.\r
988\r
989 @param This Pointer to the EFI_DHCP4_PROTOCOL instance.\r
990 @param Token Pointer to the EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN structure.\r
991\r
992 @retval EFI_SUCCESS The packet was successfully queued for transmission.\r
993 @retval EFI_INVALID_PARAMETER Some parameter is NULL.\r
994 @retval EFI_NOT_READY The previous call to this function has not finished yet. Try to call\r
995 this function after collection process completes.\r
996 @retval EFI_NO_MAPPING The default station address is not available yet.\r
997 @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
998 @retval Others Some other unexpected error occurred.\r
772db4bb 999\r
1000**/\r
1001STATIC\r
1002EFI_STATUS\r
1003EFIAPI\r
1004EfiDhcp4TransmitReceive (\r
1005 IN EFI_DHCP4_PROTOCOL *This,\r
1006 IN EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN *Token\r
1007 )\r
1008{\r
c4a62a12 1009 DHCP_PROTOCOL *Instance;\r
1010 EFI_TPL OldTpl;\r
1011 EFI_STATUS Status;\r
1012 NET_FRAGMENT Frag;\r
1013 NET_BUF *Wrap;\r
1014 UDP_POINTS EndPoint;\r
1015 IP4_ADDR Ip;\r
1016 DHCP_SERVICE *DhcpSb;\r
1017 IP4_ADDR Gateway;\r
1018 IP4_ADDR SubnetMask;\r
1019\r
1020 if ((This == NULL) || (Token == NULL) || (Token->Packet == NULL)) {\r
1021 return EFI_INVALID_PARAMETER;\r
1022 }\r
1023\r
1024 Instance = DHCP_INSTANCE_FROM_THIS (This);\r
1025 DhcpSb = Instance->Service;\r
1026\r
1027 if (Instance->Token != NULL) {\r
1028 //\r
1029 // The previous call to TransmitReceive is not finished.\r
1030 //\r
1031 return EFI_NOT_READY;\r
1032 }\r
1033\r
1034 if ((Token->Packet->Dhcp4.Magik != DHCP_OPTION_MAGIC) ||\r
1035 (NTOHL (Token->Packet->Dhcp4.Header.Xid) == Instance->Service->Xid) ||\r
1036 (Token->TimeoutValue == 0) ||\r
1037 ((Token->ListenPointCount != 0) && (Token->ListenPoints == NULL)) ||\r
1038 EFI_ERROR (DhcpValidateOptions (Token->Packet, NULL)) ||\r
1039 EFI_IP4_EQUAL (&Token->RemoteAddress, &mZeroIp4Addr)) {\r
1040 //\r
1041 // The DHCP packet isn't well-formed, the Transaction ID is already used\r
1042 // , the timeout value is zero, the ListenPoint is invalid,\r
1043 // or the RemoteAddress is zero.\r
1044 //\r
1045 return EFI_INVALID_PARAMETER;\r
1046 }\r
1047\r
1048 if (DhcpSb->ClientAddr == 0) {\r
1049\r
1050 return EFI_NO_MAPPING;\r
1051 }\r
1052\r
e48e37fc 1053 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
c4a62a12 1054\r
1055 //\r
1056 // Save the token and the timeout value.\r
1057 //\r
1058 Instance->Token = Token;\r
1059 Instance->Timeout = Token->TimeoutValue;\r
1060\r
1061 //\r
1062 // Create a UDP IO for this transmit receive transaction.\r
1063 //\r
1064 Status = Dhcp4InstanceCreateUdpIo (Instance);\r
1065 if (EFI_ERROR (Status)) {\r
1066 goto ON_ERROR;\r
1067 }\r
1068\r
982a9eae 1069 //\r
1070 // Save the Client Address is sent out\r
1071 //\r
1072 CopyMem (&DhcpSb->ClientAddressSendOut[0], &Token->Packet->Dhcp4.Header.ClientHwAddr[0], Token->Packet->Dhcp4.Header.HwAddrLen);\r
1073\r
772db4bb 1074 //\r
c4a62a12 1075 // Wrap the DHCP packet into a net buffer.\r
772db4bb 1076 //\r
c4a62a12 1077 Frag.Bulk = (UINT8 *) &Token->Packet->Dhcp4;\r
1078 Frag.Len = Token->Packet->Length;\r
1079 Wrap = NetbufFromExt (&Frag, 1, 0, 0, DhcpDummyExtFree, NULL);\r
1080 if (Wrap == NULL) {\r
1081 Status = EFI_OUT_OF_RESOURCES;\r
1082 goto ON_ERROR;\r
1083 }\r
1084\r
1085 //\r
1086 // Set the local address and local port.\r
1087 //\r
1088 EndPoint.LocalAddr = 0;\r
1089 EndPoint.LocalPort = 0;\r
1090\r
1091 //\r
1092 // Set the destination address and destination port.\r
1093 //\r
e48e37fc 1094 CopyMem (&Ip, &Token->RemoteAddress, sizeof (EFI_IPv4_ADDRESS));\r
c4a62a12 1095 EndPoint.RemoteAddr = NTOHL (Ip);\r
1096\r
1097 if (Token->RemotePort == 0) {\r
1098 EndPoint.RemotePort = DHCP_SERVER_PORT;\r
1099 } else {\r
1100 EndPoint.RemotePort = Token->RemotePort;\r
1101 }\r
1102\r
1103 //\r
1104 // Get the gateway.\r
1105 //\r
1106 SubnetMask = DhcpSb->Netmask;\r
1107 Gateway = 0;\r
1108 if (!IP4_NET_EQUAL (DhcpSb->ClientAddr, EndPoint.RemoteAddr, SubnetMask)) {\r
e48e37fc 1109 CopyMem (&Gateway, &Token->GatewayAddress, sizeof (EFI_IPv4_ADDRESS));\r
c4a62a12 1110 Gateway = NTOHL (Gateway);\r
1111 }\r
1112\r
1113 //\r
1114 // Transmit the DHCP packet.\r
1115 //\r
1116 Status = UdpIoSendDatagram (Instance->UdpIo, Wrap, &EndPoint, Gateway, DhcpOnPacketSent, NULL);\r
1117 if (EFI_ERROR (Status)) {\r
1118 NetbufFree (Wrap);\r
1119 goto ON_ERROR;\r
1120 }\r
1121\r
1122 //\r
1123 // Start to receive the DHCP response.\r
1124 //\r
1125 Status = UdpIoRecvDatagram (Instance->UdpIo, PxeDhcpInput, Instance, 0);\r
1126 if (EFI_ERROR (Status)) {\r
1127 goto ON_ERROR;\r
1128 }\r
1129\r
1130ON_ERROR:\r
1131\r
1132 if (EFI_ERROR (Status) && (Instance->UdpIo != NULL)) {\r
1133 UdpIoCleanPort (Instance->UdpIo);\r
1134 UdpIoFreePort (Instance->UdpIo);\r
1135 Instance->UdpIo = NULL;\r
1136 Instance->Token = NULL;\r
1137 }\r
1138\r
e48e37fc 1139 gBS->RestoreTPL (OldTpl);\r
c4a62a12 1140\r
1141 if (!EFI_ERROR (Status) && (Token->CompletionEvent == NULL)) {\r
1142 //\r
1143 // Keep polling until timeout if no error happens and the CompletionEvent\r
1144 // is NULL.\r
1145 //\r
1146 while (Instance->Timeout != 0) {\r
1147 Instance->UdpIo->Udp->Poll (Instance->UdpIo->Udp);\r
1148 }\r
1149 }\r
1150\r
1151 return Status;\r
772db4bb 1152}\r
1153\r
1154\r
1155/**\r
1156 Callback function for DhcpIterateOptions. This callback sets the\r
1157 EFI_DHCP4_PACKET_OPTION array in the DHCP_PARSE_CONTEXT to point\r
1158 the individual DHCP option in the packet.\r
1159\r
1160 @param Tag The DHCP option type\r
1161 @param Len length of the DHCP option data\r
1162 @param Data The DHCP option data\r
1163 @param Context The context, to pass several parameters in.\r
1164\r
1165 @retval EFI_SUCCESS It always returns EFI_SUCCESS\r
1166\r
1167**/\r
1168STATIC\r
1169EFI_STATUS\r
1170Dhcp4ParseCheckOption (\r
1171 IN UINT8 Tag,\r
1172 IN UINT8 Len,\r
1173 IN UINT8 *Data,\r
1174 IN VOID *Context\r
1175 )\r
1176{\r
1177 DHCP_PARSE_CONTEXT *Parse;\r
1178\r
1179 Parse = (DHCP_PARSE_CONTEXT *) Context;\r
1180 Parse->Index++;\r
1181\r
36ee91ca 1182 if (Parse->Index <= Parse->OptionCount) {\r
772db4bb 1183 //\r
1184 // Use _CR to get the memory position of EFI_DHCP4_PACKET_OPTION for\r
1185 // the EFI_DHCP4_PACKET_OPTION->Data because DhcpIterateOptions only\r
1186 // pass in the point to option data.\r
1187 //\r
1188 Parse->Option[Parse->Index - 1] = _CR (Data, EFI_DHCP4_PACKET_OPTION, Data);\r
1189 }\r
1190\r
1191 return EFI_SUCCESS;\r
1192}\r
1193\r
1194\r
1195/**\r
1196 Parse the DHCP options in the Packet into the PacketOptionList.\r
1197 User should allocate this array of EFI_DHCP4_PACKET_OPTION points.\r
1198\r
1199 @param This The DHCP protocol instance\r
1200 @param Packet The DHCP packet to parse\r
1201 @param OptionCount On input, the size of the PacketOptionList; On\r
1202 output, the actual number of options processed.\r
1203 @param PacketOptionList The array of EFI_DHCP4_PACKET_OPTION points\r
1204\r
1205 @retval EFI_INVALID_PARAMETER The parameters are invalid.\r
1206 @retval EFI_BUFFER_TOO_SMALL A bigger array of points is needed.\r
1207 @retval EFI_SUCCESS The options are parsed.\r
1208\r
1209**/\r
1210STATIC\r
1211EFI_STATUS\r
1212EFIAPI\r
1213EfiDhcp4Parse (\r
1214 IN EFI_DHCP4_PROTOCOL *This,\r
1215 IN EFI_DHCP4_PACKET *Packet,\r
1216 IN OUT UINT32 *OptionCount,\r
1217 OUT EFI_DHCP4_PACKET_OPTION *PacketOptionList[] OPTIONAL\r
1218 )\r
1219{\r
1220 DHCP_PARSE_CONTEXT Context;\r
1221 EFI_STATUS Status;\r
1222\r
1223 //\r
1224 // First validate the parameters\r
1225 //\r
1226 if ((This == NULL) || (Packet == NULL) || (OptionCount == NULL)) {\r
1227 return EFI_INVALID_PARAMETER;\r
1228 }\r
1229\r
1230 if ((Packet->Size < Packet->Length + 2 * sizeof (UINT32)) ||\r
1231 (Packet->Dhcp4.Magik != DHCP_OPTION_MAGIC) ||\r
1232 EFI_ERROR (DhcpValidateOptions (Packet, NULL))) {\r
1233\r
1234 return EFI_INVALID_PARAMETER;\r
1235 }\r
1236\r
1237 if ((*OptionCount != 0) && (PacketOptionList == NULL)) {\r
1238 return EFI_BUFFER_TOO_SMALL;\r
1239 }\r
1240\r
e48e37fc 1241 ZeroMem (PacketOptionList, *OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));\r
772db4bb 1242\r
1243 Context.Option = PacketOptionList;\r
1244 Context.OptionCount = *OptionCount;\r
1245 Context.Index = 0;\r
1246\r
1247 Status = DhcpIterateOptions (Packet, Dhcp4ParseCheckOption, &Context);\r
1248\r
1249 if (EFI_ERROR (Status)) {\r
1250 return Status;\r
1251 }\r
1252\r
1253 *OptionCount = Context.Index;\r
1254\r
1255 if (Context.Index > Context.OptionCount) {\r
1256 return EFI_BUFFER_TOO_SMALL;\r
1257 }\r
1258\r
1259 return EFI_SUCCESS;\r
1260}\r
1261\r
1262EFI_DHCP4_PROTOCOL mDhcp4ProtocolTemplate = {\r
1263 EfiDhcp4GetModeData,\r
1264 EfiDhcp4Configure,\r
1265 EfiDhcp4Start,\r
1266 EfiDhcp4RenewRebind,\r
1267 EfiDhcp4Release,\r
1268 EfiDhcp4Stop,\r
1269 EfiDhcp4Build,\r
1270 EfiDhcp4TransmitReceive,\r
1271 EfiDhcp4Parse\r
1272};\r
c4a62a12 1273\r