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
},
106 Binary search the DhcpOptionFormats array to find the format
107 information about a specific option.
109 @param[in] Tag The option's tag.
111 @return The point to the option's format, NULL if not found.
115 DhcpFindOptionFormat (
124 Right
= sizeof (DhcpOptionFormats
) / sizeof (DHCP_OPTION_FORMAT
) - 1;
126 while (Right
>= Left
) {
127 Middle
= (Left
+ Right
) / 2;
129 if (Tag
== DhcpOptionFormats
[Middle
].Tag
) {
130 return &DhcpOptionFormats
[Middle
];
133 if (Tag
< DhcpOptionFormats
[Middle
].Tag
) {
145 Validate whether a single DHCP option is valid according to its format.
147 @param[in] Format The option's format
148 @param[in] OptValue The value of the option
149 @param[in] Len The length of the option value
151 @retval TRUE The option is valid.
152 @retval FALSE Otherwise.
157 IN DHCP_OPTION_FORMAT
*Format
,
168 switch (Format
->Type
) {
169 case DHCP_OPTION_SWITCH
:
170 case DHCP_OPTION_INT8
:
174 case DHCP_OPTION_INT16
:
178 case DHCP_OPTION_INT32
:
183 case DHCP_OPTION_IPPAIR
:
191 // Validate that the option appears in the full units.
193 if ((Len
% Unit
) != 0) {
198 // Validate the occurance of the option unit is with in [MinOccur, MaxOccur]
202 if (((Format
->MinOccur
!= -1) && (Occur
< Format
->MinOccur
)) ||
203 ((Format
->MaxOccur
!= -1) && (Occur
> Format
->MaxOccur
))
209 // If the option is of type switch, only 0/1 are valid values.
211 if (Format
->Type
== DHCP_OPTION_SWITCH
) {
212 for (Index
= 0; Index
< Occur
; Index
++) {
213 if ((OptValue
[Index
] != 0) && (OptValue
[Index
] != 1)) {
224 Extract the client interested options, all the parameters are
225 converted to host byte order.
227 @param[in] Tag The DHCP option tag
228 @param[in] Len The length of the option
229 @param[in] Data The value of the DHCP option
230 @param[out] Para The variable to save the interested parameter
232 @retval EFI_SUCCESS The DHCP option is successfully extracted.
233 @retval EFI_INVALID_PARAMETER The DHCP option is mal-formated
241 OUT DHCP_PARAMETER
*Para
245 case DHCP4_TAG_NETMASK
:
246 Para
->NetMask
= NetGetUint32 (Data
);
249 case DHCP4_TAG_ROUTER
:
251 // Return the first router to consumer which is the preferred one
253 Para
->Router
= NetGetUint32 (Data
);
256 case DHCP4_TAG_LEASE
:
257 Para
->Lease
= NetGetUint32 (Data
);
260 case DHCP4_TAG_OVERLOAD
:
261 Para
->Overload
= *Data
;
263 if ((Para
->Overload
< 1) || (Para
->Overload
> 3)) {
264 return EFI_INVALID_PARAMETER
;
268 case DHCP4_TAG_MSG_TYPE
:
269 Para
->DhcpType
= *Data
;
271 if ((Para
->DhcpType
< 1) || (Para
->DhcpType
> 9)) {
272 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
);
294 Inspect all the options in a single buffer. DHCP options may be contained
295 in several buffers, such as the BOOTP options filed, boot file or server
296 name. Each option buffer is required to end with DHCP4_TAG_EOP.
298 @param[in] Buffer The buffer which contains DHCP options
299 @param[in] BufLen The length of the buffer
300 @param[in] Check The callback function for each option found
301 @param[in] Context The opaque parameter for the Check
302 @param[out] Overload Variable to save the value of DHCP4_TAG_OVERLOAD
305 @retval EFI_SUCCESS All the options are valid
306 @retval EFI_INVALID_PARAMETER The options are mal-formated.
310 DhcpIterateBufferOptions (
313 IN DHCP_CHECK_OPTION Check OPTIONAL
,
315 OUT UINT8
*Overload OPTIONAL
324 while (Cur
< BufLen
) {
327 if (Tag
== DHCP4_TAG_PAD
) {
330 } else if (Tag
== DHCP4_TAG_EOP
) {
337 return EFI_INVALID_PARAMETER
;
342 if (Cur
+ Len
> BufLen
) {
343 return EFI_INVALID_PARAMETER
;
346 if ((Tag
== DHCP4_TAG_OVERLOAD
) && (Overload
!= NULL
)) {
348 return EFI_INVALID_PARAMETER
;
351 *Overload
= Buffer
[Cur
];
354 if ((Check
!= NULL
) && EFI_ERROR (Check (Tag
, Len
, Buffer
+ Cur
, Context
))) {
355 return EFI_INVALID_PARAMETER
;
362 // Each option buffer is expected to end with an EOP
364 return EFI_INVALID_PARAMETER
;
369 Iterate through a DHCP message to visit each option. First inspect
370 all the options in the OPTION field. Then if overloaded, inspect
371 the options in FILENAME and SERVERNAME fields. One option may be
372 encoded in several places. See RFC 3396 Encoding Long Options in DHCP
374 @param[in] Packet The DHCP packet to check the options for
375 @param[in] Check The callback function to be called for each option
377 @param[in] Context The opaque parameter for Check
379 @retval EFI_SUCCESS The DHCP packet's options are well formated
380 @retval EFI_INVALID_PARAMETER The DHCP packet's options are not well formated
385 IN EFI_DHCP4_PACKET
*Packet
,
386 IN DHCP_CHECK_OPTION Check OPTIONAL
,
395 Status
= DhcpIterateBufferOptions (
396 Packet
->Dhcp4
.Option
,
397 Packet
->Length
- sizeof (EFI_DHCP4_HEADER
) - sizeof (UINT32
),
403 if (EFI_ERROR (Status
)) {
407 if ((Overload
== DHCP_OVERLOAD_FILENAME
) || (Overload
== DHCP_OVERLOAD_BOTH
)) {
408 Status
= DhcpIterateBufferOptions (
409 (UINT8
*) Packet
->Dhcp4
.Header
.BootFileName
,
416 if (EFI_ERROR (Status
)) {
421 if ((Overload
== DHCP_OVERLOAD_SVRNAME
) || (Overload
== DHCP_OVERLOAD_BOTH
)) {
422 Status
= DhcpIterateBufferOptions (
423 (UINT8
*) Packet
->Dhcp4
.Header
.ServerName
,
430 if (EFI_ERROR (Status
)) {
440 Call back function to DhcpIterateOptions to compute each option's
441 length. It just adds the data length of all the occurances of this
442 Tag. Context is an array of 256 DHCP_OPTION_COUNT.
444 @param[in] Tag The current option to check
445 @param[in] Len The length of the option data
446 @param[in] Data The option data
447 @param[in] Context The context, which is a array of 256
450 @retval EFI_SUCCESS It always returns EFI_SUCCESS.
461 DHCP_OPTION_COUNT
*OpCount
;
463 OpCount
= (DHCP_OPTION_COUNT
*) Context
;
464 OpCount
[Tag
].Offset
= (UINT16
) (OpCount
[Tag
].Offset
+ Len
);
471 Call back function to DhcpIterateOptions to consolidate each option's
472 data. There are maybe several occurrence of the same option.
474 @param[in] Tag The option to consolidate its data
475 @param[in] Len The length of option data
476 @param[in] Data The data of the option's current occurance
477 @param[in] Context The context, which is DHCP_OPTION_CONTEXT. This
478 array is just a wrap to pass THREE parameters.
480 @retval EFI_SUCCESS It always returns EFI_SUCCESS
491 DHCP_OPTION_CONTEXT
*OptContext
;
492 DHCP_OPTION_COUNT
*OptCount
;
493 DHCP_OPTION
*Options
;
497 OptContext
= (DHCP_OPTION_CONTEXT
*) Context
;
499 OptCount
= OptContext
->OpCount
;
500 Index
= OptCount
[Tag
].Index
;
501 Options
= OptContext
->Options
;
502 Buf
= OptContext
->Buf
;
504 if (Options
[Index
].Data
== NULL
) {
505 Options
[Index
].Tag
= Tag
;
506 Options
[Index
].Data
= Buf
+ OptCount
[Tag
].Offset
;
509 CopyMem (Buf
+ OptCount
[Tag
].Offset
, Data
, Len
);
511 OptCount
[Tag
].Offset
= (UINT16
) (OptCount
[Tag
].Offset
+ Len
);
512 Options
[Index
].Len
= (UINT16
) (Options
[Index
].Len
+ Len
);
518 Parse the options of a DHCP packet. It supports RFC 3396: Encoding
519 Long Options in DHCP. That is, it will combine all the option value
520 of all the occurances of each option.
521 A little bit of implemenation:
522 It adopts the "Key indexed counting" algorithm. First, it allocates
523 an array of 256 DHCP_OPTION_COUNTs because DHCP option tag is encoded
524 as a UINT8. It then iterates the DHCP packet to get data length of
525 each option by calling DhcpIterOptions with DhcpGetOptionLen. Now, it
526 knows the number of present options and their length. It allocates a
527 array of DHCP_OPTION and a continuous buffer after the array to put
528 all the options' data. Each option's data is pointed to by the Data
529 field in DHCP_OPTION structure. At last, it call DhcpIterateOptions
530 with DhcpFillOption to fill each option's data to its position in the
533 @param[in] Packet The DHCP packet to parse the options
534 @param[out] Count The number of valid dhcp options present in the
536 @param[out] OptionPoint The array that contains the DHCP options. Caller
539 @retval EFI_NOT_FOUND Cannot find any option.
540 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory to parse the packet.
541 @retval EFI_INVALID_PARAMETER The options are mal-formated
542 @retval EFI_SUCCESS The options are parsed into OptionPoint
547 IN EFI_DHCP4_PACKET
*Packet
,
549 OUT DHCP_OPTION
**OptionPoint
552 DHCP_OPTION_CONTEXT Context
;
553 DHCP_OPTION
*Options
;
554 DHCP_OPTION_COUNT
*OptCount
;
560 ASSERT ((Count
!= NULL
) && (OptionPoint
!= NULL
));
563 // First compute how many options and how long each option is
564 // with the "Key indexed counting" algorithms.
566 OptCount
= AllocateZeroPool (DHCP_MAX_OPTIONS
* sizeof (DHCP_OPTION_COUNT
));
568 if (OptCount
== NULL
) {
569 return EFI_OUT_OF_RESOURCES
;
572 Status
= DhcpIterateOptions (Packet
, DhcpGetOptionLen
, OptCount
);
574 if (EFI_ERROR (Status
)) {
579 // Before the loop, Offset is the length of the option. After loop,
580 // OptCount[Index].Offset specifies the offset into the continuous
581 // option value buffer to put the data.
586 for (Index
= 0; Index
< DHCP_MAX_OPTIONS
; Index
++) {
587 if (OptCount
[Index
].Offset
!= 0) {
588 OptCount
[Index
].Index
= (UINT8
) OptNum
;
590 TotalLen
= (UINT16
) (TotalLen
+ OptCount
[Index
].Offset
);
591 OptCount
[Index
].Offset
= (UINT16
) (TotalLen
- OptCount
[Index
].Offset
);
605 // Allocate a buffer to hold the DHCP options, and after that, a
606 // continuous buffer to put all the options' data.
608 Options
= AllocateZeroPool ((UINTN
) (OptNum
* sizeof (DHCP_OPTION
)) + TotalLen
);
610 if (Options
== NULL
) {
611 Status
= EFI_OUT_OF_RESOURCES
;
615 Context
.OpCount
= OptCount
;
616 Context
.Options
= Options
;
617 Context
.Buf
= (UINT8
*) (Options
+ OptNum
);
619 Status
= DhcpIterateOptions (Packet
, DhcpFillOption
, &Context
);
621 if (EFI_ERROR (Status
)) {
626 *OptionPoint
= Options
;
635 Validate the packet's options. If necessary, allocate
636 and fill in the interested parameters.
638 @param[in] Packet The packet to validate the options
639 @param[out] Para The variable to save the DHCP parameters.
641 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory to validate the packet.
642 @retval EFI_INVALID_PARAMETER The options are mal-formated
643 @retval EFI_SUCCESS The options are parsed into OptionPoint
647 DhcpValidateOptions (
648 IN EFI_DHCP4_PACKET
*Packet
,
649 OUT DHCP_PARAMETER
**Para OPTIONAL
652 DHCP_PARAMETER Parameter
;
653 DHCP_OPTION_FORMAT
*Format
;
654 DHCP_OPTION
*AllOption
;
667 Status
= DhcpParseOption (Packet
, &Count
, &AllOption
);
668 if (EFI_ERROR (Status
) || (Count
== 0)) {
671 ASSERT (AllOption
!= NULL
);
674 ZeroMem (&Parameter
, sizeof (Parameter
));
676 for (Index
= 0; Index
< Count
; Index
++) {
677 Option
= &AllOption
[Index
];
680 // Find the format of the option then validate it.
682 Format
= DhcpFindOptionFormat (Option
->Tag
);
684 if (Format
== NULL
) {
688 if (!DhcpOptionIsValid (Format
, Option
->Data
, Option
->Len
)) {
689 Status
= EFI_INVALID_PARAMETER
;
694 // Get the client interested parameters
696 if (Format
->Alert
&& (Para
!= NULL
)) {
698 Status
= DhcpGetParameter (Option
->Tag
, Option
->Len
, Option
->Data
, &Parameter
);
700 if (EFI_ERROR (Status
)) {
706 if (Updated
&& (Para
!= NULL
)) {
707 *Para
= AllocateCopyPool (sizeof (DHCP_PARAMETER
), &Parameter
);
709 Status
= EFI_OUT_OF_RESOURCES
;
715 FreePool (AllOption
);
722 Append an option to the memory, if the option is longer than
723 255 bytes, splits it into several options.
725 @param[out] Buf The buffer to append the option to
726 @param[in] Tag The option's tag
727 @param[in] DataLen The length of the option's data
728 @param[in] Data The option's data
730 @return The position to append the next option
744 ASSERT (DataLen
!= 0);
746 for (Index
= 0; Index
< (DataLen
+ 254) / 255; Index
++) {
747 Len
= MIN (255, DataLen
- Index
* 255);
750 *(Buf
++) = (UINT8
) Len
;
751 CopyMem (Buf
, Data
+ Index
* 255, (UINTN
) Len
);
761 Build a new DHCP packet from a seed packet. Options may be deleted or
762 appended. The caller should free the NewPacket when finished using it.
764 @param[in] SeedPacket The seed packet to start with
765 @param[in] DeleteCount The number of options to delete
766 @param[in] DeleteList The options to delete from the packet
767 @param[in] AppendCount The number of options to append
768 @param[in] AppendList The options to append to the packet
769 @param[out] NewPacket The new packet, allocated and built by this
772 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory
773 @retval EFI_INVALID_PARAMETER The options in SeekPacket are mal-formated
774 @retval EFI_SUCCESS The packet is build.
779 IN EFI_DHCP4_PACKET
*SeedPacket
,
780 IN UINT32 DeleteCount
,
781 IN UINT8
*DeleteList OPTIONAL
,
782 IN UINT32 AppendCount
,
783 IN EFI_DHCP4_PACKET_OPTION
*AppendList
[] OPTIONAL
,
784 OUT EFI_DHCP4_PACKET
**NewPacket
788 DHCP_OPTION
*SeedOptions
;
789 EFI_DHCP4_PACKET
*Packet
;
797 // Use an array of DHCP_OPTION to mark the existance
798 // and position of each valid options.
800 Mark
= AllocatePool (sizeof (DHCP_OPTION
) * DHCP_MAX_OPTIONS
);
803 return EFI_OUT_OF_RESOURCES
;
806 for (Index
= 0; Index
< DHCP_MAX_OPTIONS
; Index
++) {
807 Mark
[Index
].Tag
= (UINT8
) Index
;
812 // Get list of the options from the seed packet, then put
813 // them to the mark array according to their tags.
816 Status
= DhcpParseOption (SeedPacket
, &Count
, &SeedOptions
);
818 if (EFI_ERROR (Status
)) {
822 if (SeedOptions
!= NULL
) {
823 for (Index
= 0; Index
< (UINT32
) Count
; Index
++) {
824 Mark
[SeedOptions
[Index
].Tag
] = SeedOptions
[Index
];
829 // Mark the option's length is zero if it is in the DeleteList.
831 for (Index
= 0; Index
< DeleteCount
; Index
++) {
832 Mark
[DeleteList
[Index
]].Len
= 0;
836 // Add or replace the option if it is in the append list.
838 for (Index
= 0; Index
< AppendCount
; Index
++) {
839 Mark
[AppendList
[Index
]->OpCode
].Len
= AppendList
[Index
]->Length
;
840 Mark
[AppendList
[Index
]->OpCode
].Data
= AppendList
[Index
]->Data
;
844 // compute the new packet length. No need to add 1 byte for
845 // EOP option since EFI_DHCP4_PACKET includes one extra byte
846 // for option. It is necessary to split the option if it is
847 // longer than 255 bytes.
849 Len
= sizeof (EFI_DHCP4_PACKET
);
851 for (Index
= 0; Index
< DHCP_MAX_OPTIONS
; Index
++) {
852 if (Mark
[Index
].Len
!= 0) {
853 Len
+= ((Mark
[Index
].Len
+ 254) / 255) * 2 + Mark
[Index
].Len
;
857 Status
= EFI_OUT_OF_RESOURCES
;
858 Packet
= (EFI_DHCP4_PACKET
*) AllocatePool (Len
);
860 if (Packet
== NULL
) {
866 CopyMem (&Packet
->Dhcp4
.Header
, &SeedPacket
->Dhcp4
.Header
, sizeof (Packet
->Dhcp4
.Header
));
867 Packet
->Dhcp4
.Magik
= DHCP_OPTION_MAGIC
;
868 Buf
= Packet
->Dhcp4
.Option
;
870 for (Index
= 0; Index
< DHCP_MAX_OPTIONS
; Index
++) {
871 if (Mark
[Index
].Len
!= 0) {
872 Buf
= DhcpAppendOption (Buf
, Mark
[Index
].Tag
, Mark
[Index
].Len
, Mark
[Index
].Data
);
876 *(Buf
++) = DHCP4_TAG_EOP
;
877 Packet
->Length
= sizeof (EFI_DHCP4_HEADER
) + sizeof (UINT32
)
878 + (UINT32
) (Buf
- Packet
->Dhcp4
.Option
);
881 Status
= EFI_SUCCESS
;
884 if (SeedOptions
!= NULL
) {
885 FreePool (SeedOptions
);