3 Copyright (c) 2006, 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
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.
18 Function to validate, parse, process the DHCP options
23 #include "Dhcp4Impl.h"
26 // A list of the format of DHCP Options sorted by option tag
27 // to validate a dhcp message. Refere the comments of the
28 // DHCP_OPTION_FORMAT structure.
32 DhcpOptionFormats
[] = {
33 {DHCP_TAG_NETMASK
, DHCP_OPTION_IP
, 1, 1 , TRUE
},
34 {DHCP_TAG_TIME_OFFSET
, DHCP_OPTION_INT32
, 1, 1 , FALSE
},
35 {DHCP_TAG_ROUTER
, DHCP_OPTION_IP
, 1, -1 , TRUE
},
36 {DHCP_TAG_TIME_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
37 {DHCP_TAG_NAME_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
38 {DHCP_TAG_DNS_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
39 {DHCP_TAG_LOG_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
40 {DHCP_TAG_COOKIE_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
41 {DHCP_TAG_LPR_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
42 {DHCP_TAG_IMPRESS_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
43 {DHCP_TAG_RL_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
44 {DHCP_TAG_HOSTNAME
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
45 {DHCP_TAG_BOOTFILE_LEN
, DHCP_OPTION_INT16
, 1, 1 , FALSE
},
46 {DHCP_TAG_DUMP
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
47 {DHCP_TAG_DOMAINNAME
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
48 {DHCP_TAG_SWAP_SERVER
, DHCP_OPTION_IP
, 1, 1 , FALSE
},
49 {DHCP_TAG_ROOTPATH
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
50 {DHCP_TAG_EXTEND_PATH
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
52 {DHCP_TAG_IPFORWARD
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
53 {DHCP_TAG_NONLOCAL_SRR
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
54 {DHCP_TAG_POLICY_SRR
, DHCP_OPTION_IPPAIR
, 1, -1 , FALSE
},
55 {DHCP_TAG_EMTU
, DHCP_OPTION_INT16
, 1, 1 , FALSE
},
56 {DHCP_TAG_TTL
, DHCP_OPTION_INT8
, 1, 1 , FALSE
},
57 {DHCP_TAG_PATHMTU_AGE
, DHCP_OPTION_INT32
, 1, 1 , FALSE
},
58 {DHCP_TAG_PATHMTU_PLATEAU
,DHCP_OPTION_INT16
, 1, -1 , FALSE
},
60 {DHCP_TAG_IFMTU
, DHCP_OPTION_INT16
, 1, 1 , FALSE
},
61 {DHCP_TAG_SUBNET_LOCAL
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
62 {DHCP_TAG_BROADCAST
, DHCP_OPTION_IP
, 1, 1 , FALSE
},
63 {DHCP_TAG_DISCOVER_MASK
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
64 {DHCP_TAG_SUPPLY_MASK
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
65 {DHCP_TAG_DISCOVER_ROUTE
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
66 {DHCP_TAG_ROUTER_SOLICIT
, DHCP_OPTION_IP
, 1, 1 , FALSE
},
67 {DHCP_TAG_STATIC_ROUTE
, DHCP_OPTION_IPPAIR
, 1, -1 , FALSE
},
69 {DHCP_TAG_TRAILER
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
70 {DHCP_TAG_ARPAGE
, DHCP_OPTION_INT32
, 1, 1 , FALSE
},
71 {DHCP_TAG_ETHER_ENCAP
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
73 {DHCP_TAG_TCP_TTL
, DHCP_OPTION_INT8
, 1, 1 , FALSE
},
74 {DHCP_TAG_KEEP_INTERVAL
, DHCP_OPTION_INT32
, 1, 1 , FALSE
},
75 {DHCP_TAG_KEEP_GARBAGE
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
77 {DHCP_TAG_NIS_DOMAIN
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
78 {DHCP_TAG_NIS_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
79 {DHCP_TAG_NTP_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
80 {DHCP_TAG_VENDOR
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
81 {DHCP_TAG_NBNS
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
82 {DHCP_TAG_NBDD
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
83 {DHCP_TAG_NBTYPE
, DHCP_OPTION_INT8
, 1, 1 , FALSE
},
84 {DHCP_TAG_NBSCOPE
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
85 {DHCP_TAG_XFONT
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
86 {DHCP_TAG_XDM
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
88 {DHCP_TAG_REQUEST_IP
, DHCP_OPTION_IP
, 1, 1 , FALSE
},
89 {DHCP_TAG_LEASE
, DHCP_OPTION_INT32
, 1, 1 , TRUE
},
90 {DHCP_TAG_OVERLOAD
, DHCP_OPTION_INT8
, 1, 1 , TRUE
},
91 {DHCP_TAG_TYPE
, DHCP_OPTION_INT8
, 1, 1 , TRUE
},
92 {DHCP_TAG_SERVER_ID
, DHCP_OPTION_IP
, 1, 1 , TRUE
},
93 {DHCP_TAG_PARA_LIST
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
94 {DHCP_TAG_MESSAGE
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
95 {DHCP_TAG_MAXMSG
, DHCP_OPTION_INT16
, 1, 1 , FALSE
},
96 {DHCP_TAG_T1
, DHCP_OPTION_INT32
, 1, 1 , TRUE
},
97 {DHCP_TAG_T2
, DHCP_OPTION_INT32
, 1, 1 , TRUE
},
98 {DHCP_TAG_VENDOR_CLASS
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
99 {DHCP_TAG_CLIENT_ID
, DHCP_OPTION_INT8
, 2, -1 , FALSE
},
101 {DHCP_TAG_NISPLUS
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
102 {DHCP_TAG_NISPLUS_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
104 {DHCP_TAG_TFTP
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
105 {DHCP_TAG_BOOTFILE
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
107 {DHCP_TAG_MOBILEIP
, DHCP_OPTION_IP
, 0, -1 , FALSE
},
108 {DHCP_TAG_SMTP
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
109 {DHCP_TAG_POP3
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
110 {DHCP_TAG_NNTP
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
111 {DHCP_TAG_WWW
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
112 {DHCP_TAG_FINGER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
113 {DHCP_TAG_IRC
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
114 {DHCP_TAG_STTALK
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
115 {DHCP_TAG_STDA
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
117 {DHCP_TAG_CLASSLESS_ROUTE
,DHCP_OPTION_INT8
, 5, -1 , FALSE
},
122 Binary search the DhcpOptionFormats array to find the format
123 information about a specific option.
125 @param Tag The option's tag.
127 @return The point to the option's format, NULL if not found.
132 DhcpFindOptionFormat (
141 Right
= sizeof (DhcpOptionFormats
) / sizeof (DHCP_OPTION_FORMAT
) - 1;
143 while (Right
>= Left
) {
144 Middle
= (Left
+ Right
) / 2;
146 if (Tag
== DhcpOptionFormats
[Middle
].Tag
) {
147 return &DhcpOptionFormats
[Middle
];
150 if (Tag
< DhcpOptionFormats
[Middle
].Tag
) {
162 Validate whether a single DHCP option is valid according to its format.
164 @param Format The option's format
165 @param OptValue The value of the option
166 @param Len The length of the option value
168 @return TRUE is the option is valid, otherwise FALSE.
174 IN DHCP_OPTION_FORMAT
*Format
,
185 switch (Format
->Type
) {
186 case DHCP_OPTION_SWITCH
:
187 case DHCP_OPTION_INT8
:
191 case DHCP_OPTION_INT16
:
195 case DHCP_OPTION_INT32
:
200 case DHCP_OPTION_IPPAIR
:
208 // Validate that the option appears in the full units.
210 if ((Len
% Unit
) != 0) {
215 // Validate the occurance of the option unit is with in [MinOccur, MaxOccur]
219 if (((Format
->MinOccur
!= -1) && (Occur
< Format
->MinOccur
)) ||
220 ((Format
->MaxOccur
!= -1) && (Occur
> Format
->MaxOccur
))) {
225 // If the option is of type switch, only 0/1 are valid values.
227 if (Format
->Type
== DHCP_OPTION_SWITCH
) {
228 for (Index
= 0; Index
< Occur
; Index
++) {
229 if ((OptValue
[Index
] != 0) && (OptValue
[Index
] != 1)) {
240 Extract the client interested options, all the parameters are
241 converted to host byte order.
243 @param Tag The DHCP option tag
244 @param Len The length of the option
245 @param Data The value of the DHCP option
246 @param Para The variable to save the interested parameter
248 @retval EFI_SUCCESS The DHCP option is successfully extracted.
249 @retval EFI_INVALID_PARAMETER The DHCP option is mal-formated
258 IN DHCP_PARAMETER
*Para
262 case DHCP_TAG_NETMASK
:
263 Para
->NetMask
= NetGetUint32 (Data
);
266 case DHCP_TAG_ROUTER
:
268 // Return the first router to consumer which is the preferred one
270 Para
->Router
= NetGetUint32 (Data
);
274 Para
->Lease
= NetGetUint32 (Data
);
277 case DHCP_TAG_OVERLOAD
:
278 Para
->Overload
= *Data
;
280 if ((Para
->Overload
< 1) || (Para
->Overload
> 3)) {
281 return EFI_INVALID_PARAMETER
;
286 Para
->DhcpType
= *Data
;
288 if ((Para
->DhcpType
< 1) || (Para
->DhcpType
> 9)) {
289 return EFI_INVALID_PARAMETER
;
293 case DHCP_TAG_SERVER_ID
:
294 Para
->ServerId
= NetGetUint32 (Data
);
298 Para
->T1
= NetGetUint32 (Data
);
302 Para
->T2
= NetGetUint32 (Data
);
311 Inspect all the options in a single buffer. DHCP options may be contained
312 in several buffers, such as the BOOTP options filed, boot file or server
313 name. Each option buffer is required to end with DHCP_TAG_EOP.
315 @param Buffer The buffer which contains DHCP options
316 @param BufLen The length of the buffer
317 @param Check The callback function for each option found
318 @param Context The opaque parameter for the Check
319 @param Overload variable to save the value of DHCP_TAG_OVERLOAD
322 @retval EFI_SUCCESS All the options are valid
323 @retval EFI_INVALID_PARAMETER The options are mal-formated.
328 DhcpIterateBufferOptions (
331 IN DHCP_CHECK_OPTION Check
, OPTIONAL
333 OUT UINT8
*Overload OPTIONAL
342 while (Cur
< BufLen
) {
345 if (Tag
== DHCP_TAG_PAD
) {
348 } else if (Tag
== DHCP_TAG_EOP
) {
355 return EFI_INVALID_PARAMETER
;
360 if (Cur
+ Len
> BufLen
) {
361 return EFI_INVALID_PARAMETER
;
364 if ((Tag
== DHCP_TAG_OVERLOAD
) && (Overload
!= NULL
)) {
366 return EFI_INVALID_PARAMETER
;
369 *Overload
= Buffer
[Cur
];
372 if ((Check
!= NULL
) && EFI_ERROR (Check (Tag
, Len
, Buffer
+ Cur
, Context
))) {
373 return EFI_INVALID_PARAMETER
;
380 // Each option buffer is expected to end with an EOP
382 return EFI_INVALID_PARAMETER
;
387 Iterate through a DHCP message to visit each option. First inspect
388 all the options in the OPTION field. Then if overloaded, inspect
389 the options in FILENAME and SERVERNAME fields. One option may be
390 encoded in several places. See RFC 3396 Encoding Long Options in DHCP
392 @param Packet The DHCP packet to check the options for
393 @param Check The callback function to be called for each option
395 @param Context The opaque parameter for Check
397 @retval EFI_SUCCESS The DHCP packet's options are well formated
398 @retval Others The DHCP packet's options are not well formated
403 IN EFI_DHCP4_PACKET
*Packet
,
404 IN DHCP_CHECK_OPTION Check
, OPTIONAL
413 Status
= DhcpIterateBufferOptions (
414 Packet
->Dhcp4
.Option
,
415 Packet
->Length
- sizeof (EFI_DHCP4_HEADER
) - sizeof (UINT32
),
421 if (EFI_ERROR (Status
)) {
425 if ((Overload
== DHCP_OVERLOAD_FILENAME
) || (Overload
== DHCP_OVERLOAD_BOTH
)) {
426 Status
= DhcpIterateBufferOptions (
427 (UINT8
*) Packet
->Dhcp4
.Header
.BootFileName
,
434 if (EFI_ERROR (Status
)) {
439 if ((Overload
== DHCP_OVERLOAD_SVRNAME
) || (Overload
== DHCP_OVERLOAD_BOTH
)) {
440 Status
= DhcpIterateBufferOptions (
441 (UINT8
*) Packet
->Dhcp4
.Header
.ServerName
,
448 if (EFI_ERROR (Status
)) {
458 Call back function to DhcpiterateOptions to compute each option's
459 length. It just adds the data length of all the occurances of this
460 Tag. Context is an array of 256 DHCP_OPTION_COUNT.
462 @param Tag The current option to check
463 @param Len The length of the option data
464 @param Data The option data
465 @param Context The context, which is a array of 256
468 @retval EFI_SUCCESS It always returns EFI_SUCCESS.
480 DHCP_OPTION_COUNT
*OpCount
;
482 OpCount
= (DHCP_OPTION_COUNT
*) Context
;
483 OpCount
[Tag
].Offset
= (UINT16
) (OpCount
[Tag
].Offset
+ Len
);
490 Call back function to DhcpiterateOptions to consolidate each option's
491 data. There are maybe several occurance of the same option.
493 @param Tag The option to consolidate its data
494 @param Len The length of option data
495 @param Data The data of the option's current occurance
496 @param Context The context, which is DHCP_OPTION_CONTEXT. This
497 array is just a wrap to pass THREE parameters.
499 @retval EFI_SUCCESS It always returns EFI_SUCCESS
511 DHCP_OPTION_CONTEXT
*OptContext
;
512 DHCP_OPTION_COUNT
*OptCount
;
513 DHCP_OPTION
*Options
;
517 OptContext
= (DHCP_OPTION_CONTEXT
*) Context
;
519 OptCount
= OptContext
->OpCount
;
520 Index
= OptCount
[Tag
].Index
;
521 Options
= OptContext
->Options
;
522 Buf
= OptContext
->Buf
;
524 if (Options
[Index
].Data
== NULL
) {
525 Options
[Index
].Tag
= Tag
;
526 Options
[Index
].Data
= Buf
+ OptCount
[Tag
].Offset
;
529 CopyMem (Buf
+ OptCount
[Tag
].Offset
, Data
, Len
);
531 OptCount
[Tag
].Offset
= (UINT16
) (OptCount
[Tag
].Offset
+ Len
);
532 Options
[Index
].Len
= (UINT16
) (Options
[Index
].Len
+ Len
);
538 Parse the options of a DHCP packet. It supports RFC 3396: Encoding
539 Long Options in DHCP. That is, it will combine all the option value
540 of all the occurances of each option.
541 A little bit of implemenation:
542 It adopts the "Key indexed counting" algorithm. First, it allocates
543 an array of 256 DHCP_OPTION_COUNTs because DHCP option tag is encoded
544 as a UINT8. It then iterates the DHCP packet to get data length of
545 each option by calling DhcpIterOptions with DhcpGetOptionLen. Now, it
546 knows the number of present options and their length. It allocates a
547 array of DHCP_OPTION and a continous buffer after the array to put
548 all the options' data. Each option's data is pointed to by the Data
549 field in DHCP_OPTION structure. At last, it call DhcpIterateOptions
550 with DhcpFillOption to fill each option's data to its position in the
553 @param Packet The DHCP packet to parse the options
554 @param Count The number of valid dhcp options present in the
556 @param OptionPoint The array that contains the DHCP options. Caller
559 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory to parse the packet.
560 @retval EFI_INVALID_PARAMETER The options are mal-formated
561 @retval EFI_SUCCESS The options are parsed into OptionPoint
566 IN EFI_DHCP4_PACKET
*Packet
,
568 OUT DHCP_OPTION
**OptionPoint
571 DHCP_OPTION_CONTEXT Context
;
572 DHCP_OPTION
*Options
;
573 DHCP_OPTION_COUNT
*OptCount
;
579 ASSERT ((Count
!= NULL
) && (OptionPoint
!= NULL
));
582 // First compute how many options and how long each option is
583 // with the "Key indexed counting" algorithms.
585 OptCount
= AllocateZeroPool (DHCP_MAX_OPTIONS
* sizeof (DHCP_OPTION_COUNT
));
587 if (OptCount
== NULL
) {
588 return EFI_OUT_OF_RESOURCES
;
591 Status
= DhcpIterateOptions (Packet
, DhcpGetOptionLen
, OptCount
);
593 if (EFI_ERROR (Status
)) {
598 // Before the loop, Offset is the length of the option. After loop,
599 // OptCount[Index].Offset specifies the offset into the continuous
600 // option value buffer to put the data.
605 for (Index
= 0; Index
< DHCP_MAX_OPTIONS
; Index
++) {
606 if (OptCount
[Index
].Offset
!= 0) {
607 OptCount
[Index
].Index
= (UINT8
) OptNum
;
609 TotalLen
= (UINT16
) (TotalLen
+ OptCount
[Index
].Offset
);
610 OptCount
[Index
].Offset
= (UINT16
) (TotalLen
- OptCount
[Index
].Offset
);
624 // Allocate a buffer to hold the DHCP options, and after that, a
625 // continuous buffer to put all the options' data.
627 Options
= AllocateZeroPool (OptNum
* sizeof (DHCP_OPTION
) + TotalLen
);
629 if (Options
== NULL
) {
630 Status
= EFI_OUT_OF_RESOURCES
;
634 Context
.OpCount
= OptCount
;
635 Context
.Options
= Options
;
636 Context
.Buf
= (UINT8
*) (Options
+ OptNum
);
638 Status
= DhcpIterateOptions (Packet
, DhcpFillOption
, &Context
);
640 if (EFI_ERROR (Status
)) {
641 gBS
->FreePool (Options
);
645 *OptionPoint
= Options
;
648 gBS
->FreePool (OptCount
);
654 Validate the packet's options. If necessary, allocate
655 and fill in the interested parameters.
657 @param Packet The packet to validate the options
658 @param Para The variable to save the DHCP parameters.
660 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory to validate the packet.
661 @retval EFI_INVALID_PARAMETER The options are mal-formated
662 @retval EFI_SUCCESS The options are parsed into OptionPoint
666 DhcpValidateOptions (
667 IN EFI_DHCP4_PACKET
*Packet
,
668 OUT DHCP_PARAMETER
**Para OPTIONAL
671 DHCP_PARAMETER Parameter
;
672 DHCP_OPTION_FORMAT
*Format
;
673 DHCP_OPTION
*AllOption
;
685 Status
= DhcpParseOption (Packet
, &Count
, &AllOption
);
687 if (EFI_ERROR (Status
) || (Count
== 0)) {
692 ZeroMem (&Parameter
, sizeof (Parameter
));
694 for (Index
= 0; Index
< Count
; Index
++) {
695 Option
= &AllOption
[Index
];
698 // Find the format of the option then validate it.
700 Format
= DhcpFindOptionFormat (Option
->Tag
);
702 if (Format
== NULL
) {
706 if (!DhcpOptionIsValid (Format
, Option
->Data
, Option
->Len
)) {
707 Status
= EFI_INVALID_PARAMETER
;
712 // Get the client interested parameters
714 if (Format
->Alert
&& (Para
!= NULL
)) {
716 Status
= DhcpGetParameter (Option
->Tag
, Option
->Len
, Option
->Data
, &Parameter
);
718 if (EFI_ERROR (Status
)) {
724 if (Updated
&& (Para
!= NULL
)) {
725 if ((*Para
= AllocatePool (sizeof (DHCP_PARAMETER
))) == NULL
) {
726 Status
= EFI_OUT_OF_RESOURCES
;
730 CopyMem (*Para
, &Parameter
, sizeof (**Para
));
734 gBS
->FreePool (AllOption
);
741 Append an option to the memory, if the option is longer than
742 255 bytes, splits it into several options.
744 @param Buf The buffer to append the option to
745 @param Tag The option's tag
746 @param DataLen The length of the option's data
747 @param Data The option's data
749 @return The position to append the next option
763 ASSERT (DataLen
!= 0);
765 for (Index
= 0; Index
< (DataLen
+ 254) / 255; Index
++) {
766 Len
= MIN (255, DataLen
- Index
* 255);
769 *(Buf
++) = (UINT8
) Len
;
770 CopyMem (Buf
, Data
+ Index
* 255, Len
);
780 Build a new DHCP packet from a seed packet. Options may be deleted or
781 appended. The caller should free the NewPacket when finished using it.
783 @param SeedPacket The seed packet to start with
784 @param DeleteCount The number of options to delete
785 @param DeleteList The options to delete from the packet
786 @param AppendCount The number of options to append
787 @param AppendList The options to append to the packet
788 @param NewPacket The new packet, allocated and built by this
791 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory
792 @retval EFI_SUCCESS The packet is build.
797 IN EFI_DHCP4_PACKET
*SeedPacket
,
798 IN UINT32 DeleteCount
,
799 IN UINT8
*DeleteList OPTIONAL
,
800 IN UINT32 AppendCount
,
801 IN EFI_DHCP4_PACKET_OPTION
*AppendList
[] OPTIONAL
,
802 OUT EFI_DHCP4_PACKET
**NewPacket
806 DHCP_OPTION
*SeedOptions
;
807 EFI_DHCP4_PACKET
*Packet
;
815 // Use an array of DHCP_OPTION to mark the existance
816 // and position of each valid options.
818 Mark
= AllocatePool (sizeof (DHCP_OPTION
) * DHCP_MAX_OPTIONS
);
821 return EFI_OUT_OF_RESOURCES
;
824 for (Index
= 0; Index
< DHCP_MAX_OPTIONS
; Index
++) {
825 Mark
[Index
].Tag
= (UINT8
) Index
;
830 // Get list of the options from the seed packet, then put
831 // them to the mark array according to their tags.
834 Status
= DhcpParseOption (SeedPacket
, &Count
, &SeedOptions
);
836 if (EFI_ERROR (Status
)) {
840 for (Index
= 0; Index
< (UINT32
) Count
; Index
++) {
841 Mark
[SeedOptions
[Index
].Tag
] = SeedOptions
[Index
];
845 // Mark the option's length is zero if it is in the DeleteList.
847 for (Index
= 0; Index
< DeleteCount
; Index
++) {
848 Mark
[DeleteList
[Index
]].Len
= 0;
852 // Add or replace the option if it is in the append list.
854 for (Index
= 0; Index
< AppendCount
; Index
++) {
855 Mark
[AppendList
[Index
]->OpCode
].Len
= AppendList
[Index
]->Length
;
856 Mark
[AppendList
[Index
]->OpCode
].Data
= AppendList
[Index
]->Data
;
860 // compute the new packet length. No need to add 1 byte for
861 // EOP option since EFI_DHCP4_PACKET includes one extra byte
862 // for option. It is necessary to split the option if it is
863 // longer than 255 bytes.
865 Len
= sizeof (EFI_DHCP4_PACKET
);
867 for (Index
= 0; Index
< DHCP_MAX_OPTIONS
; Index
++) {
868 if (Mark
[Index
].Len
!= 0) {
869 Len
+= ((Mark
[Index
].Len
+ 254) / 255) * 2 + Mark
[Index
].Len
;
873 Status
= EFI_OUT_OF_RESOURCES
;
874 Packet
= (EFI_DHCP4_PACKET
*) AllocatePool (Len
);
876 if (Packet
== NULL
) {
882 CopyMem (&Packet
->Dhcp4
.Header
, &SeedPacket
->Dhcp4
.Header
, sizeof (Packet
->Dhcp4
.Header
));
883 Packet
->Dhcp4
.Magik
= DHCP_OPTION_MAGIC
;
884 Buf
= Packet
->Dhcp4
.Option
;
886 for (Index
= 0; Index
< DHCP_MAX_OPTIONS
; Index
++) {
887 if (Mark
[Index
].Len
!= 0) {
888 Buf
= DhcpAppendOption (Buf
, Mark
[Index
].Tag
, Mark
[Index
].Len
, Mark
[Index
].Data
);
892 *(Buf
++) = DHCP_TAG_EOP
;
893 Packet
->Length
= sizeof (EFI_DHCP4_HEADER
) + sizeof (UINT32
)
894 + (UINT32
) (Buf
- Packet
->Dhcp4
.Option
);
897 Status
= EFI_SUCCESS
;
900 if (SeedOptions
!= NULL
) {
901 gBS
->FreePool (SeedOptions
);
904 gBS
->FreePool (Mark
);