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