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