2 Function to validate, parse, process the DHCP options.
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
12 /// A list of the format of DHCP Options sorted by option tag
13 /// to validate a dhcp message. Refere the comments of the
14 /// DHCP_OPTION_FORMAT structure.
16 DHCP_OPTION_FORMAT DhcpOptionFormats
[] = {
17 { DHCP4_TAG_NETMASK
, DHCP_OPTION_IP
, 1, 1, TRUE
},
18 { DHCP4_TAG_TIME_OFFSET
, DHCP_OPTION_INT32
, 1, 1, FALSE
},
19 { DHCP4_TAG_ROUTER
, DHCP_OPTION_IP
, 1, -1, TRUE
},
20 { DHCP4_TAG_TIME_SERVER
, DHCP_OPTION_IP
, 1, -1, FALSE
},
21 { DHCP4_TAG_NAME_SERVER
, DHCP_OPTION_IP
, 1, -1, FALSE
},
22 { DHCP4_TAG_DNS_SERVER
, DHCP_OPTION_IP
, 1, -1, FALSE
},
23 { DHCP4_TAG_LOG_SERVER
, DHCP_OPTION_IP
, 1, -1, FALSE
},
24 { DHCP4_TAG_COOKIE_SERVER
, DHCP_OPTION_IP
, 1, -1, FALSE
},
25 { DHCP4_TAG_LPR_SERVER
, DHCP_OPTION_IP
, 1, -1, FALSE
},
26 { DHCP4_TAG_IMPRESS_SERVER
, DHCP_OPTION_IP
, 1, -1, FALSE
},
27 { DHCP4_TAG_RL_SERVER
, DHCP_OPTION_IP
, 1, -1, FALSE
},
28 { DHCP4_TAG_HOSTNAME
, DHCP_OPTION_INT8
, 1, -1, FALSE
},
29 { DHCP4_TAG_BOOTFILE_LEN
, DHCP_OPTION_INT16
, 1, 1, FALSE
},
30 { DHCP4_TAG_DUMP
, DHCP_OPTION_INT8
, 1, -1, FALSE
},
31 { DHCP4_TAG_DOMAINNAME
, DHCP_OPTION_INT8
, 1, -1, FALSE
},
32 { DHCP4_TAG_SWAP_SERVER
, DHCP_OPTION_IP
, 1, 1, FALSE
},
33 { DHCP4_TAG_ROOTPATH
, DHCP_OPTION_INT8
, 1, -1, FALSE
},
34 { DHCP4_TAG_EXTEND_PATH
, DHCP_OPTION_INT8
, 1, -1, FALSE
},
36 { DHCP4_TAG_IPFORWARD
, DHCP_OPTION_SWITCH
, 1, 1, FALSE
},
37 { DHCP4_TAG_NONLOCAL_SRR
, DHCP_OPTION_SWITCH
, 1, 1, FALSE
},
38 { DHCP4_TAG_POLICY_SRR
, DHCP_OPTION_IPPAIR
, 1, -1, FALSE
},
39 { DHCP4_TAG_EMTU
, DHCP_OPTION_INT16
, 1, 1, FALSE
},
40 { DHCP4_TAG_TTL
, DHCP_OPTION_INT8
, 1, 1, FALSE
},
41 { DHCP4_TAG_PATHMTU_AGE
, DHCP_OPTION_INT32
, 1, 1, FALSE
},
42 { DHCP4_TAG_PATHMTU_PLATEAU
, DHCP_OPTION_INT16
, 1, -1, FALSE
},
44 { DHCP4_TAG_IFMTU
, DHCP_OPTION_INT16
, 1, 1, FALSE
},
45 { DHCP4_TAG_SUBNET_LOCAL
, DHCP_OPTION_SWITCH
, 1, 1, FALSE
},
46 { DHCP4_TAG_BROADCAST
, DHCP_OPTION_IP
, 1, 1, FALSE
},
47 { DHCP4_TAG_DISCOVER_MASK
, DHCP_OPTION_SWITCH
, 1, 1, FALSE
},
48 { DHCP4_TAG_SUPPLY_MASK
, DHCP_OPTION_SWITCH
, 1, 1, FALSE
},
49 { DHCP4_TAG_DISCOVER_ROUTE
, DHCP_OPTION_SWITCH
, 1, 1, FALSE
},
50 { DHCP4_TAG_ROUTER_SOLICIT
, DHCP_OPTION_IP
, 1, 1, FALSE
},
51 { DHCP4_TAG_STATIC_ROUTE
, DHCP_OPTION_IPPAIR
, 1, -1, FALSE
},
53 { DHCP4_TAG_TRAILER
, DHCP_OPTION_SWITCH
, 1, 1, FALSE
},
54 { DHCP4_TAG_ARPAGE
, DHCP_OPTION_INT32
, 1, 1, FALSE
},
55 { DHCP4_TAG_ETHER_ENCAP
, DHCP_OPTION_SWITCH
, 1, 1, FALSE
},
57 { DHCP4_TAG_TCP_TTL
, DHCP_OPTION_INT8
, 1, 1, FALSE
},
58 { DHCP4_TAG_KEEP_INTERVAL
, DHCP_OPTION_INT32
, 1, 1, FALSE
},
59 { DHCP4_TAG_KEEP_GARBAGE
, DHCP_OPTION_SWITCH
, 1, 1, FALSE
},
61 { DHCP4_TAG_NIS_DOMAIN
, DHCP_OPTION_INT8
, 1, -1, FALSE
},
62 { DHCP4_TAG_NIS_SERVER
, DHCP_OPTION_IP
, 1, -1, FALSE
},
63 { DHCP4_TAG_NTP_SERVER
, DHCP_OPTION_IP
, 1, -1, FALSE
},
64 { DHCP4_TAG_VENDOR
, DHCP_OPTION_INT8
, 1, -1, FALSE
},
65 { DHCP4_TAG_NBNS
, DHCP_OPTION_IP
, 1, -1, FALSE
},
66 { DHCP4_TAG_NBDD
, DHCP_OPTION_IP
, 1, -1, FALSE
},
67 { DHCP4_TAG_NBTYPE
, DHCP_OPTION_INT8
, 1, 1, FALSE
},
68 { DHCP4_TAG_NBSCOPE
, DHCP_OPTION_INT8
, 1, -1, FALSE
},
69 { DHCP4_TAG_XFONT
, DHCP_OPTION_IP
, 1, -1, FALSE
},
70 { DHCP4_TAG_XDM
, DHCP_OPTION_IP
, 1, -1, FALSE
},
72 { DHCP4_TAG_REQUEST_IP
, DHCP_OPTION_IP
, 1, 1, FALSE
},
73 { DHCP4_TAG_LEASE
, DHCP_OPTION_INT32
, 1, 1, TRUE
},
74 { DHCP4_TAG_OVERLOAD
, DHCP_OPTION_INT8
, 1, 1, TRUE
},
75 { DHCP4_TAG_MSG_TYPE
, DHCP_OPTION_INT8
, 1, 1, TRUE
},
76 { DHCP4_TAG_SERVER_ID
, DHCP_OPTION_IP
, 1, 1, TRUE
},
77 { DHCP4_TAG_PARA_LIST
, DHCP_OPTION_INT8
, 1, -1, FALSE
},
78 { DHCP4_TAG_MESSAGE
, DHCP_OPTION_INT8
, 1, -1, FALSE
},
79 { DHCP4_TAG_MAXMSG
, DHCP_OPTION_INT16
, 1, 1, FALSE
},
80 { DHCP4_TAG_T1
, DHCP_OPTION_INT32
, 1, 1, TRUE
},
81 { DHCP4_TAG_T2
, DHCP_OPTION_INT32
, 1, 1, TRUE
},
82 { DHCP4_TAG_VENDOR_CLASS_ID
, DHCP_OPTION_INT8
, 1, -1, FALSE
},
83 { DHCP4_TAG_CLIENT_ID
, DHCP_OPTION_INT8
, 2, -1, FALSE
},
85 { DHCP4_TAG_NISPLUS
, DHCP_OPTION_INT8
, 1, -1, FALSE
},
86 { DHCP4_TAG_NISPLUS_SERVER
, DHCP_OPTION_IP
, 1, -1, FALSE
},
88 { DHCP4_TAG_TFTP
, DHCP_OPTION_INT8
, 1, -1, FALSE
},
89 { DHCP4_TAG_BOOTFILE
, DHCP_OPTION_INT8
, 1, -1, FALSE
},
91 { DHCP4_TAG_MOBILEIP
, DHCP_OPTION_IP
, 0, -1, FALSE
},
92 { DHCP4_TAG_SMTP
, DHCP_OPTION_IP
, 1, -1, FALSE
},
93 { DHCP4_TAG_POP3
, DHCP_OPTION_IP
, 1, -1, FALSE
},
94 { DHCP4_TAG_NNTP
, DHCP_OPTION_IP
, 1, -1, FALSE
},
95 { DHCP4_TAG_WWW
, DHCP_OPTION_IP
, 1, -1, FALSE
},
96 { DHCP4_TAG_FINGER
, DHCP_OPTION_IP
, 1, -1, FALSE
},
97 { DHCP4_TAG_IRC
, DHCP_OPTION_IP
, 1, -1, FALSE
},
98 { DHCP4_TAG_STTALK
, DHCP_OPTION_IP
, 1, -1, FALSE
},
99 { DHCP4_TAG_STDA
, DHCP_OPTION_IP
, 1, -1, FALSE
},
101 { DHCP4_TAG_CLASSLESS_ROUTE
, DHCP_OPTION_INT8
, 5, -1, FALSE
},
105 Binary search the DhcpOptionFormats array to find the format
106 information about a specific option.
108 @param[in] Tag The option's tag.
110 @return The point to the option's format, NULL if not found.
114 DhcpFindOptionFormat (
123 Right
= sizeof (DhcpOptionFormats
) / sizeof (DHCP_OPTION_FORMAT
) - 1;
125 while (Right
>= Left
) {
126 Middle
= (Left
+ Right
) / 2;
128 if (Tag
== DhcpOptionFormats
[Middle
].Tag
) {
129 return &DhcpOptionFormats
[Middle
];
132 if (Tag
< DhcpOptionFormats
[Middle
].Tag
) {
143 Validate whether a single DHCP option is valid according to its format.
145 @param[in] Format The option's format
146 @param[in] OptValue The value of the option
147 @param[in] Len The length of the option value
149 @retval TRUE The option is valid.
150 @retval FALSE Otherwise.
155 IN DHCP_OPTION_FORMAT
*Format
,
166 switch (Format
->Type
) {
167 case DHCP_OPTION_SWITCH
:
168 case DHCP_OPTION_INT8
:
172 case DHCP_OPTION_INT16
:
176 case DHCP_OPTION_INT32
:
181 case DHCP_OPTION_IPPAIR
:
189 // Validate that the option appears in the full units.
191 if ((Len
% Unit
) != 0) {
196 // Validate the occurrence of the option unit is with in [MinOccur, MaxOccur]
200 if (((Format
->MinOccur
!= -1) && (Occur
< Format
->MinOccur
)) ||
201 ((Format
->MaxOccur
!= -1) && (Occur
> Format
->MaxOccur
))
208 // If the option is of type switch, only 0/1 are valid values.
210 if (Format
->Type
== DHCP_OPTION_SWITCH
) {
211 for (Index
= 0; Index
< Occur
; Index
++) {
212 if ((OptValue
[Index
] != 0) && (OptValue
[Index
] != 1)) {
222 Extract the client interested options, all the parameters are
223 converted to host byte order.
225 @param[in] Tag The DHCP option tag
226 @param[in] Len The length of the option
227 @param[in] Data The value of the DHCP option
228 @param[out] Para The variable to save the interested parameter
230 @retval EFI_SUCCESS The DHCP option is successfully extracted.
231 @retval EFI_INVALID_PARAMETER The DHCP option is mal-formatted
239 OUT DHCP_PARAMETER
*Para
243 case DHCP4_TAG_NETMASK
:
244 Para
->NetMask
= NetGetUint32 (Data
);
247 case DHCP4_TAG_ROUTER
:
249 // Return the first router to consumer which is the preferred one
251 Para
->Router
= NetGetUint32 (Data
);
254 case DHCP4_TAG_LEASE
:
255 Para
->Lease
= NetGetUint32 (Data
);
258 case DHCP4_TAG_OVERLOAD
:
259 Para
->Overload
= *Data
;
261 if ((Para
->Overload
< 1) || (Para
->Overload
> 3)) {
262 return EFI_INVALID_PARAMETER
;
267 case DHCP4_TAG_MSG_TYPE
:
268 Para
->DhcpType
= *Data
;
270 if ((Para
->DhcpType
< 1) || (Para
->DhcpType
> 9)) {
271 return EFI_INVALID_PARAMETER
;
276 case DHCP4_TAG_SERVER_ID
:
277 Para
->ServerId
= NetGetUint32 (Data
);
281 Para
->T1
= NetGetUint32 (Data
);
285 Para
->T2
= NetGetUint32 (Data
);
293 Inspect all the options in a single buffer. DHCP options may be contained
294 in several buffers, such as the BOOTP options filed, boot file or server
295 name. Each option buffer is required to end with DHCP4_TAG_EOP.
297 @param[in] Buffer The buffer which contains DHCP options
298 @param[in] BufLen The length of the buffer
299 @param[in] Check The callback function for each option found
300 @param[in] Context The opaque parameter for the Check
301 @param[out] Overload Variable to save the value of DHCP4_TAG_OVERLOAD
304 @retval EFI_SUCCESS All the options are valid
305 @retval EFI_INVALID_PARAMETER The options are mal-formatted.
309 DhcpIterateBufferOptions (
312 IN DHCP_CHECK_OPTION Check OPTIONAL
,
314 OUT UINT8
*Overload OPTIONAL
323 while (Cur
< BufLen
) {
326 if (Tag
== DHCP4_TAG_PAD
) {
329 } else if (Tag
== DHCP4_TAG_EOP
) {
336 return EFI_INVALID_PARAMETER
;
341 if (Cur
+ Len
> BufLen
) {
342 return EFI_INVALID_PARAMETER
;
345 if ((Tag
== DHCP4_TAG_OVERLOAD
) && (Overload
!= NULL
)) {
347 return EFI_INVALID_PARAMETER
;
350 *Overload
= Buffer
[Cur
];
353 if ((Check
!= NULL
) && EFI_ERROR (Check (Tag
, Len
, Buffer
+ Cur
, Context
))) {
354 return EFI_INVALID_PARAMETER
;
361 // Each option buffer is expected to end with an EOP
363 return EFI_INVALID_PARAMETER
;
367 Iterate through a DHCP message to visit each option. First inspect
368 all the options in the OPTION field. Then if overloaded, inspect
369 the options in FILENAME and SERVERNAME fields. One option may be
370 encoded in several places. See RFC 3396 Encoding Long Options in DHCP
372 @param[in] Packet The DHCP packet to check the options for
373 @param[in] Check The callback function to be called for each option
375 @param[in] Context The opaque parameter for Check
377 @retval EFI_SUCCESS The DHCP packet's options are well formatted
378 @retval EFI_INVALID_PARAMETER The DHCP packet's options are not well formatted
383 IN EFI_DHCP4_PACKET
*Packet
,
384 IN DHCP_CHECK_OPTION Check OPTIONAL
,
393 Status
= DhcpIterateBufferOptions (
394 Packet
->Dhcp4
.Option
,
395 Packet
->Length
- sizeof (EFI_DHCP4_HEADER
) - sizeof (UINT32
),
401 if (EFI_ERROR (Status
)) {
405 if ((Overload
== DHCP_OVERLOAD_FILENAME
) || (Overload
== DHCP_OVERLOAD_BOTH
)) {
406 Status
= DhcpIterateBufferOptions (
407 (UINT8
*)Packet
->Dhcp4
.Header
.BootFileName
,
414 if (EFI_ERROR (Status
)) {
419 if ((Overload
== DHCP_OVERLOAD_SVRNAME
) || (Overload
== DHCP_OVERLOAD_BOTH
)) {
420 Status
= DhcpIterateBufferOptions (
421 (UINT8
*)Packet
->Dhcp4
.Header
.ServerName
,
428 if (EFI_ERROR (Status
)) {
437 Call back function to DhcpIterateOptions to compute each option's
438 length. It just adds the data length of all the occurrences of this
439 Tag. Context is an array of 256 DHCP_OPTION_COUNT.
441 @param[in] Tag The current option to check
442 @param[in] Len The length of the option data
443 @param[in] Data The option data
444 @param[in] Context The context, which is a array of 256
447 @retval EFI_SUCCESS It always returns EFI_SUCCESS.
458 DHCP_OPTION_COUNT
*OpCount
;
460 OpCount
= (DHCP_OPTION_COUNT
*)Context
;
461 OpCount
[Tag
].Offset
= (UINT16
)(OpCount
[Tag
].Offset
+ Len
);
467 Call back function to DhcpIterateOptions to consolidate each option's
468 data. There are maybe several occurrence of the same option.
470 @param[in] Tag The option to consolidate its data
471 @param[in] Len The length of option data
472 @param[in] Data The data of the option's current occurrence
473 @param[in] Context The context, which is DHCP_OPTION_CONTEXT. This
474 array is just a wrap to pass THREE parameters.
476 @retval EFI_SUCCESS It always returns EFI_SUCCESS
487 DHCP_OPTION_CONTEXT
*OptContext
;
488 DHCP_OPTION_COUNT
*OptCount
;
489 DHCP_OPTION
*Options
;
493 OptContext
= (DHCP_OPTION_CONTEXT
*)Context
;
495 OptCount
= OptContext
->OpCount
;
496 Index
= OptCount
[Tag
].Index
;
497 Options
= OptContext
->Options
;
498 Buf
= OptContext
->Buf
;
500 if (Options
[Index
].Data
== NULL
) {
501 Options
[Index
].Tag
= Tag
;
502 Options
[Index
].Data
= Buf
+ OptCount
[Tag
].Offset
;
505 CopyMem (Buf
+ OptCount
[Tag
].Offset
, Data
, Len
);
507 OptCount
[Tag
].Offset
= (UINT16
)(OptCount
[Tag
].Offset
+ Len
);
508 Options
[Index
].Len
= (UINT16
)(Options
[Index
].Len
+ Len
);
513 Parse the options of a DHCP packet. It supports RFC 3396: Encoding
514 Long Options in DHCP. That is, it will combine all the option value
515 of all the occurrences of each option.
516 A little bit of implementation:
517 It adopts the "Key indexed counting" algorithm. First, it allocates
518 an array of 256 DHCP_OPTION_COUNTs because DHCP option tag is encoded
519 as a UINT8. It then iterates the DHCP packet to get data length of
520 each option by calling DhcpIterOptions with DhcpGetOptionLen. Now, it
521 knows the number of present options and their length. It allocates a
522 array of DHCP_OPTION and a continuous buffer after the array to put
523 all the options' data. Each option's data is pointed to by the Data
524 field in DHCP_OPTION structure. At last, it call DhcpIterateOptions
525 with DhcpFillOption to fill each option's data to its position in the
528 @param[in] Packet The DHCP packet to parse the options
529 @param[out] Count The number of valid dhcp options present in the
531 @param[out] OptionPoint The array that contains the DHCP options. Caller
534 @retval EFI_NOT_FOUND Cannot find any option.
535 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory to parse the packet.
536 @retval EFI_INVALID_PARAMETER The options are mal-formatted
537 @retval EFI_SUCCESS The options are parsed into OptionPoint
542 IN EFI_DHCP4_PACKET
*Packet
,
544 OUT DHCP_OPTION
**OptionPoint
547 DHCP_OPTION_CONTEXT Context
;
548 DHCP_OPTION
*Options
;
549 DHCP_OPTION_COUNT
*OptCount
;
555 ASSERT ((Count
!= NULL
) && (OptionPoint
!= NULL
));
558 // First compute how many options and how long each option is
559 // with the "Key indexed counting" algorithms.
561 OptCount
= AllocateZeroPool (DHCP_MAX_OPTIONS
* sizeof (DHCP_OPTION_COUNT
));
563 if (OptCount
== NULL
) {
564 return EFI_OUT_OF_RESOURCES
;
567 Status
= DhcpIterateOptions (Packet
, DhcpGetOptionLen
, OptCount
);
569 if (EFI_ERROR (Status
)) {
574 // Before the loop, Offset is the length of the option. After loop,
575 // OptCount[Index].Offset specifies the offset into the continuous
576 // option value buffer to put the data.
581 for (Index
= 0; Index
< DHCP_MAX_OPTIONS
; Index
++) {
582 if (OptCount
[Index
].Offset
!= 0) {
583 OptCount
[Index
].Index
= (UINT8
)OptNum
;
585 TotalLen
= (UINT16
)(TotalLen
+ OptCount
[Index
].Offset
);
586 OptCount
[Index
].Offset
= (UINT16
)(TotalLen
- OptCount
[Index
].Offset
);
600 // Allocate a buffer to hold the DHCP options, and after that, a
601 // continuous buffer to put all the options' data.
603 Options
= AllocateZeroPool ((UINTN
)(OptNum
* sizeof (DHCP_OPTION
)) + TotalLen
);
605 if (Options
== NULL
) {
606 Status
= EFI_OUT_OF_RESOURCES
;
610 Context
.OpCount
= OptCount
;
611 Context
.Options
= Options
;
612 Context
.Buf
= (UINT8
*)(Options
+ OptNum
);
614 Status
= DhcpIterateOptions (Packet
, DhcpFillOption
, &Context
);
616 if (EFI_ERROR (Status
)) {
621 *OptionPoint
= Options
;
629 Validate the packet's options. If necessary, allocate
630 and fill in the interested parameters.
632 @param[in] Packet The packet to validate the options
633 @param[out] Para The variable to save the DHCP parameters.
635 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory to validate the packet.
636 @retval EFI_INVALID_PARAMETER The options are mal-formatted
637 @retval EFI_SUCCESS The options are parsed into OptionPoint
641 DhcpValidateOptions (
642 IN EFI_DHCP4_PACKET
*Packet
,
643 OUT DHCP_PARAMETER
**Para OPTIONAL
646 DHCP_PARAMETER Parameter
;
647 DHCP_OPTION_FORMAT
*Format
;
648 DHCP_OPTION
*AllOption
;
661 Status
= DhcpParseOption (Packet
, &Count
, &AllOption
);
662 if (EFI_ERROR (Status
) || (Count
== 0)) {
666 ASSERT (AllOption
!= NULL
);
669 ZeroMem (&Parameter
, sizeof (Parameter
));
671 for (Index
= 0; Index
< Count
; Index
++) {
672 Option
= &AllOption
[Index
];
675 // Find the format of the option then validate it.
677 Format
= DhcpFindOptionFormat (Option
->Tag
);
679 if (Format
== NULL
) {
683 if (!DhcpOptionIsValid (Format
, Option
->Data
, Option
->Len
)) {
684 Status
= EFI_INVALID_PARAMETER
;
689 // Get the client interested parameters
691 if (Format
->Alert
&& (Para
!= NULL
)) {
693 Status
= DhcpGetParameter (Option
->Tag
, Option
->Len
, Option
->Data
, &Parameter
);
695 if (EFI_ERROR (Status
)) {
701 if (Updated
&& (Para
!= NULL
)) {
702 *Para
= AllocateCopyPool (sizeof (DHCP_PARAMETER
), &Parameter
);
704 Status
= EFI_OUT_OF_RESOURCES
;
710 FreePool (AllOption
);
715 Append an option to the memory, if the option is longer than
716 255 bytes, splits it into several options.
718 @param[out] Buf The buffer to append the option to
719 @param[in] Tag The option's tag
720 @param[in] DataLen The length of the option's data
721 @param[in] Data The option's data
723 @return The position to append the next option
737 ASSERT (DataLen
!= 0);
739 for (Index
= 0; Index
< (DataLen
+ 254) / 255; Index
++) {
740 Len
= MIN (255, DataLen
- Index
* 255);
743 *(Buf
++) = (UINT8
)Len
;
744 CopyMem (Buf
, Data
+ Index
* 255, (UINTN
)Len
);
753 Build a new DHCP packet from a seed packet. Options may be deleted or
754 appended. The caller should free the NewPacket when finished using it.
756 @param[in] SeedPacket The seed packet to start with
757 @param[in] DeleteCount The number of options to delete
758 @param[in] DeleteList The options to delete from the packet
759 @param[in] AppendCount The number of options to append
760 @param[in] AppendList The options to append to the packet
761 @param[out] NewPacket The new packet, allocated and built by this
764 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory
765 @retval EFI_INVALID_PARAMETER The options in SeekPacket are mal-formatted
766 @retval EFI_SUCCESS The packet is build.
771 IN EFI_DHCP4_PACKET
*SeedPacket
,
772 IN UINT32 DeleteCount
,
773 IN UINT8
*DeleteList OPTIONAL
,
774 IN UINT32 AppendCount
,
775 IN EFI_DHCP4_PACKET_OPTION
*AppendList
[] OPTIONAL
,
776 OUT EFI_DHCP4_PACKET
**NewPacket
780 DHCP_OPTION
*SeedOptions
;
781 EFI_DHCP4_PACKET
*Packet
;
789 // Use an array of DHCP_OPTION to mark the existence
790 // and position of each valid options.
792 Mark
= AllocatePool (sizeof (DHCP_OPTION
) * DHCP_MAX_OPTIONS
);
795 return EFI_OUT_OF_RESOURCES
;
798 for (Index
= 0; Index
< DHCP_MAX_OPTIONS
; Index
++) {
799 Mark
[Index
].Tag
= (UINT8
)Index
;
804 // Get list of the options from the seed packet, then put
805 // them to the mark array according to their tags.
808 Status
= DhcpParseOption (SeedPacket
, &Count
, &SeedOptions
);
810 if (EFI_ERROR (Status
)) {
814 if (SeedOptions
!= NULL
) {
815 for (Index
= 0; Index
< (UINT32
)Count
; Index
++) {
816 Mark
[SeedOptions
[Index
].Tag
] = SeedOptions
[Index
];
821 // Mark the option's length is zero if it is in the DeleteList.
823 for (Index
= 0; Index
< DeleteCount
; Index
++) {
824 Mark
[DeleteList
[Index
]].Len
= 0;
828 // Add or replace the option if it is in the append list.
830 for (Index
= 0; Index
< AppendCount
; Index
++) {
831 Mark
[AppendList
[Index
]->OpCode
].Len
= AppendList
[Index
]->Length
;
832 Mark
[AppendList
[Index
]->OpCode
].Data
= AppendList
[Index
]->Data
;
836 // compute the new packet length. No need to add 1 byte for
837 // EOP option since EFI_DHCP4_PACKET includes one extra byte
838 // for option. It is necessary to split the option if it is
839 // longer than 255 bytes.
841 Len
= sizeof (EFI_DHCP4_PACKET
);
843 for (Index
= 0; Index
< DHCP_MAX_OPTIONS
; Index
++) {
844 if (Mark
[Index
].Len
!= 0) {
845 Len
+= ((Mark
[Index
].Len
+ 254) / 255) * 2 + Mark
[Index
].Len
;
849 Status
= EFI_OUT_OF_RESOURCES
;
850 Packet
= (EFI_DHCP4_PACKET
*)AllocatePool (Len
);
852 if (Packet
== NULL
) {
858 CopyMem (&Packet
->Dhcp4
.Header
, &SeedPacket
->Dhcp4
.Header
, sizeof (Packet
->Dhcp4
.Header
));
859 Packet
->Dhcp4
.Magik
= DHCP_OPTION_MAGIC
;
860 Buf
= Packet
->Dhcp4
.Option
;
862 for (Index
= 0; Index
< DHCP_MAX_OPTIONS
; Index
++) {
863 if (Mark
[Index
].Len
!= 0) {
864 Buf
= DhcpAppendOption (Buf
, Mark
[Index
].Tag
, Mark
[Index
].Len
, Mark
[Index
].Data
);
868 *(Buf
++) = DHCP4_TAG_EOP
;
869 Packet
->Length
= sizeof (EFI_DHCP4_HEADER
) + sizeof (UINT32
)
870 + (UINT32
)(Buf
- Packet
->Dhcp4
.Option
);
873 Status
= EFI_SUCCESS
;
876 if (SeedOptions
!= NULL
) {
877 FreePool (SeedOptions
);