3 Copyright (c) 2006 - 2008, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
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.
30 DHCP_OPTION_FORMAT DhcpOptionFormats
[] = {
31 {DHCP_TAG_NETMASK
, DHCP_OPTION_IP
, 1, 1 , TRUE
},
32 {DHCP_TAG_TIME_OFFSET
, DHCP_OPTION_INT32
, 1, 1 , FALSE
},
33 {DHCP_TAG_ROUTER
, DHCP_OPTION_IP
, 1, -1 , TRUE
},
34 {DHCP_TAG_TIME_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
35 {DHCP_TAG_NAME_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
36 {DHCP_TAG_DNS_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
37 {DHCP_TAG_LOG_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
38 {DHCP_TAG_COOKIE_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
39 {DHCP_TAG_LPR_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
40 {DHCP_TAG_IMPRESS_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
41 {DHCP_TAG_RL_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
42 {DHCP_TAG_HOSTNAME
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
43 {DHCP_TAG_BOOTFILE_LEN
, DHCP_OPTION_INT16
, 1, 1 , FALSE
},
44 {DHCP_TAG_DUMP
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
45 {DHCP_TAG_DOMAINNAME
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
46 {DHCP_TAG_SWAP_SERVER
, DHCP_OPTION_IP
, 1, 1 , FALSE
},
47 {DHCP_TAG_ROOTPATH
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
48 {DHCP_TAG_EXTEND_PATH
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
50 {DHCP_TAG_IPFORWARD
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
51 {DHCP_TAG_NONLOCAL_SRR
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
52 {DHCP_TAG_POLICY_SRR
, DHCP_OPTION_IPPAIR
, 1, -1 , FALSE
},
53 {DHCP_TAG_EMTU
, DHCP_OPTION_INT16
, 1, 1 , FALSE
},
54 {DHCP_TAG_TTL
, DHCP_OPTION_INT8
, 1, 1 , FALSE
},
55 {DHCP_TAG_PATHMTU_AGE
, DHCP_OPTION_INT32
, 1, 1 , FALSE
},
56 {DHCP_TAG_PATHMTU_PLATEAU
,DHCP_OPTION_INT16
, 1, -1 , FALSE
},
58 {DHCP_TAG_IFMTU
, DHCP_OPTION_INT16
, 1, 1 , FALSE
},
59 {DHCP_TAG_SUBNET_LOCAL
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
60 {DHCP_TAG_BROADCAST
, DHCP_OPTION_IP
, 1, 1 , FALSE
},
61 {DHCP_TAG_DISCOVER_MASK
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
62 {DHCP_TAG_SUPPLY_MASK
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
63 {DHCP_TAG_DISCOVER_ROUTE
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
64 {DHCP_TAG_ROUTER_SOLICIT
, DHCP_OPTION_IP
, 1, 1 , FALSE
},
65 {DHCP_TAG_STATIC_ROUTE
, DHCP_OPTION_IPPAIR
, 1, -1 , FALSE
},
67 {DHCP_TAG_TRAILER
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
68 {DHCP_TAG_ARPAGE
, DHCP_OPTION_INT32
, 1, 1 , FALSE
},
69 {DHCP_TAG_ETHER_ENCAP
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
71 {DHCP_TAG_TCP_TTL
, DHCP_OPTION_INT8
, 1, 1 , FALSE
},
72 {DHCP_TAG_KEEP_INTERVAL
, DHCP_OPTION_INT32
, 1, 1 , FALSE
},
73 {DHCP_TAG_KEEP_GARBAGE
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
75 {DHCP_TAG_NIS_DOMAIN
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
76 {DHCP_TAG_NIS_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
77 {DHCP_TAG_NTP_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
78 {DHCP_TAG_VENDOR
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
79 {DHCP_TAG_NBNS
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
80 {DHCP_TAG_NBDD
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
81 {DHCP_TAG_NBTYPE
, DHCP_OPTION_INT8
, 1, 1 , FALSE
},
82 {DHCP_TAG_NBSCOPE
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
83 {DHCP_TAG_XFONT
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
84 {DHCP_TAG_XDM
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
86 {DHCP_TAG_REQUEST_IP
, DHCP_OPTION_IP
, 1, 1 , FALSE
},
87 {DHCP_TAG_LEASE
, DHCP_OPTION_INT32
, 1, 1 , TRUE
},
88 {DHCP_TAG_OVERLOAD
, DHCP_OPTION_INT8
, 1, 1 , TRUE
},
89 {DHCP_TAG_TYPE
, DHCP_OPTION_INT8
, 1, 1 , TRUE
},
90 {DHCP_TAG_SERVER_ID
, DHCP_OPTION_IP
, 1, 1 , TRUE
},
91 {DHCP_TAG_PARA_LIST
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
92 {DHCP_TAG_MESSAGE
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
93 {DHCP_TAG_MAXMSG
, DHCP_OPTION_INT16
, 1, 1 , FALSE
},
94 {DHCP_TAG_T1
, DHCP_OPTION_INT32
, 1, 1 , TRUE
},
95 {DHCP_TAG_T2
, DHCP_OPTION_INT32
, 1, 1 , TRUE
},
96 {DHCP_TAG_VENDOR_CLASS
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
97 {DHCP_TAG_CLIENT_ID
, DHCP_OPTION_INT8
, 2, -1 , FALSE
},
99 {DHCP_TAG_NISPLUS
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
100 {DHCP_TAG_NISPLUS_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
102 {DHCP_TAG_TFTP
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
103 {DHCP_TAG_BOOTFILE
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
105 {DHCP_TAG_MOBILEIP
, DHCP_OPTION_IP
, 0, -1 , FALSE
},
106 {DHCP_TAG_SMTP
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
107 {DHCP_TAG_POP3
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
108 {DHCP_TAG_NNTP
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
109 {DHCP_TAG_WWW
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
110 {DHCP_TAG_FINGER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
111 {DHCP_TAG_IRC
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
112 {DHCP_TAG_STTALK
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
113 {DHCP_TAG_STDA
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
115 {DHCP_TAG_CLASSLESS_ROUTE
,DHCP_OPTION_INT8
, 5, -1 , FALSE
},
120 Binary search the DhcpOptionFormats array to find the format
121 information about a specific option.
123 @param Tag The option's tag.
125 @return The point to the option's format, NULL if not found.
129 DhcpFindOptionFormat (
138 Right
= sizeof (DhcpOptionFormats
) / sizeof (DHCP_OPTION_FORMAT
) - 1;
140 while (Right
>= Left
) {
141 Middle
= (Left
+ Right
) / 2;
143 if (Tag
== DhcpOptionFormats
[Middle
].Tag
) {
144 return &DhcpOptionFormats
[Middle
];
147 if (Tag
< DhcpOptionFormats
[Middle
].Tag
) {
159 Validate whether a single DHCP option is valid according to its format.
161 @param Format The option's format
162 @param OptValue The value of the option
163 @param Len The length of the option value
165 @retval TRUE The option is valid.
166 @retval FALSE Otherwise.
171 IN DHCP_OPTION_FORMAT
*Format
,
182 switch (Format
->Type
) {
183 case DHCP_OPTION_SWITCH
:
184 case DHCP_OPTION_INT8
:
188 case DHCP_OPTION_INT16
:
192 case DHCP_OPTION_INT32
:
197 case DHCP_OPTION_IPPAIR
:
205 // Validate that the option appears in the full units.
207 if ((Len
% Unit
) != 0) {
212 // Validate the occurance of the option unit is with in [MinOccur, MaxOccur]
216 if (((Format
->MinOccur
!= -1) && (Occur
< Format
->MinOccur
)) ||
217 ((Format
->MaxOccur
!= -1) && (Occur
> Format
->MaxOccur
))
223 // If the option is of type switch, only 0/1 are valid values.
225 if (Format
->Type
== DHCP_OPTION_SWITCH
) {
226 for (Index
= 0; Index
< Occur
; Index
++) {
227 if ((OptValue
[Index
] != 0) && (OptValue
[Index
] != 1)) {
238 Extract the client interested options, all the parameters are
239 converted to host byte order.
241 @param Tag The DHCP option tag
242 @param Len The length of the option
243 @param Data The value of the DHCP option
244 @param Para The variable to save the interested parameter
246 @retval EFI_SUCCESS The DHCP option is successfully extracted.
247 @retval EFI_INVALID_PARAMETER The DHCP option is mal-formated
255 OUT DHCP_PARAMETER
*Para
259 case DHCP_TAG_NETMASK
:
260 Para
->NetMask
= NetGetUint32 (Data
);
263 case DHCP_TAG_ROUTER
:
265 // Return the first router to consumer which is the preferred one
267 Para
->Router
= NetGetUint32 (Data
);
271 Para
->Lease
= NetGetUint32 (Data
);
274 case DHCP_TAG_OVERLOAD
:
275 Para
->Overload
= *Data
;
277 if ((Para
->Overload
< 1) || (Para
->Overload
> 3)) {
278 return EFI_INVALID_PARAMETER
;
283 Para
->DhcpType
= *Data
;
285 if ((Para
->DhcpType
< 1) || (Para
->DhcpType
> 9)) {
286 return EFI_INVALID_PARAMETER
;
290 case DHCP_TAG_SERVER_ID
:
291 Para
->ServerId
= NetGetUint32 (Data
);
295 Para
->T1
= NetGetUint32 (Data
);
299 Para
->T2
= NetGetUint32 (Data
);
308 Inspect all the options in a single buffer. DHCP options may be contained
309 in several buffers, such as the BOOTP options filed, boot file or server
310 name. Each option buffer is required to end with DHCP_TAG_EOP.
312 @param Buffer The buffer which contains DHCP options
313 @param BufLen The length of the buffer
314 @param Check The callback function for each option found
315 @param Context The opaque parameter for the Check
316 @param Overload Variable to save the value of DHCP_TAG_OVERLOAD
319 @retval EFI_SUCCESS All the options are valid
320 @retval EFI_INVALID_PARAMETER The options are mal-formated.
324 DhcpIterateBufferOptions (
327 IN DHCP_CHECK_OPTION Check
, OPTIONAL
329 OUT UINT8
*Overload OPTIONAL
338 while (Cur
< BufLen
) {
341 if (Tag
== DHCP_TAG_PAD
) {
344 } else if (Tag
== DHCP_TAG_EOP
) {
351 return EFI_INVALID_PARAMETER
;
356 if (Cur
+ Len
> BufLen
) {
357 return EFI_INVALID_PARAMETER
;
360 if ((Tag
== DHCP_TAG_OVERLOAD
) && (Overload
!= NULL
)) {
362 return EFI_INVALID_PARAMETER
;
365 *Overload
= Buffer
[Cur
];
368 if ((Check
!= NULL
) && EFI_ERROR (Check (Tag
, Len
, Buffer
+ Cur
, Context
))) {
369 return EFI_INVALID_PARAMETER
;
376 // Each option buffer is expected to end with an EOP
378 return EFI_INVALID_PARAMETER
;
383 Iterate through a DHCP message to visit each option. First inspect
384 all the options in the OPTION field. Then if overloaded, inspect
385 the options in FILENAME and SERVERNAME fields. One option may be
386 encoded in several places. See RFC 3396 Encoding Long Options in DHCP
388 @param Packet The DHCP packet to check the options for
389 @param Check The callback function to be called for each option
391 @param Context The opaque parameter for Check
393 @retval EFI_SUCCESS The DHCP packet's options are well formated
394 @retval EFI_INVALID_PARAMETER The DHCP packet's options are not well formated
399 IN EFI_DHCP4_PACKET
*Packet
,
400 IN DHCP_CHECK_OPTION Check
, OPTIONAL
409 Status
= DhcpIterateBufferOptions (
410 Packet
->Dhcp4
.Option
,
411 Packet
->Length
- sizeof (EFI_DHCP4_HEADER
) - sizeof (UINT32
),
417 if (EFI_ERROR (Status
)) {
421 if ((Overload
== DHCP_OVERLOAD_FILENAME
) || (Overload
== DHCP_OVERLOAD_BOTH
)) {
422 Status
= DhcpIterateBufferOptions (
423 (UINT8
*) Packet
->Dhcp4
.Header
.BootFileName
,
430 if (EFI_ERROR (Status
)) {
435 if ((Overload
== DHCP_OVERLOAD_SVRNAME
) || (Overload
== DHCP_OVERLOAD_BOTH
)) {
436 Status
= DhcpIterateBufferOptions (
437 (UINT8
*) Packet
->Dhcp4
.Header
.ServerName
,
444 if (EFI_ERROR (Status
)) {
454 Call back function to DhcpIterateOptions to compute each option's
455 length. It just adds the data length of all the occurances of this
456 Tag. Context is an array of 256 DHCP_OPTION_COUNT.
458 @param Tag The current option to check
459 @param Len The length of the option data
460 @param Data The option data
461 @param Context The context, which is a array of 256
464 @retval EFI_SUCCESS It always returns EFI_SUCCESS.
475 DHCP_OPTION_COUNT
*OpCount
;
477 OpCount
= (DHCP_OPTION_COUNT
*) Context
;
478 OpCount
[Tag
].Offset
= (UINT16
) (OpCount
[Tag
].Offset
+ Len
);
485 Call back function to DhcpIterateOptions to consolidate each option's
486 data. There are maybe several occurrence of the same option.
488 @param Tag The option to consolidate its data
489 @param Len The length of option data
490 @param Data The data of the option's current occurance
491 @param Context The context, which is DHCP_OPTION_CONTEXT. This
492 array is just a wrap to pass THREE parameters.
494 @retval EFI_SUCCESS It always returns EFI_SUCCESS
505 DHCP_OPTION_CONTEXT
*OptContext
;
506 DHCP_OPTION_COUNT
*OptCount
;
507 DHCP_OPTION
*Options
;
511 OptContext
= (DHCP_OPTION_CONTEXT
*) Context
;
513 OptCount
= OptContext
->OpCount
;
514 Index
= OptCount
[Tag
].Index
;
515 Options
= OptContext
->Options
;
516 Buf
= OptContext
->Buf
;
518 if (Options
[Index
].Data
== NULL
) {
519 Options
[Index
].Tag
= Tag
;
520 Options
[Index
].Data
= Buf
+ OptCount
[Tag
].Offset
;
523 CopyMem (Buf
+ OptCount
[Tag
].Offset
, Data
, Len
);
525 OptCount
[Tag
].Offset
= (UINT16
) (OptCount
[Tag
].Offset
+ Len
);
526 Options
[Index
].Len
= (UINT16
) (Options
[Index
].Len
+ Len
);
532 Parse the options of a DHCP packet. It supports RFC 3396: Encoding
533 Long Options in DHCP. That is, it will combine all the option value
534 of all the occurances of each option.
535 A little bit of implemenation:
536 It adopts the "Key indexed counting" algorithm. First, it allocates
537 an array of 256 DHCP_OPTION_COUNTs because DHCP option tag is encoded
538 as a UINT8. It then iterates the DHCP packet to get data length of
539 each option by calling DhcpIterOptions with DhcpGetOptionLen. Now, it
540 knows the number of present options and their length. It allocates a
541 array of DHCP_OPTION and a continuous buffer after the array to put
542 all the options' data. Each option's data is pointed to by the Data
543 field in DHCP_OPTION structure. At last, it call DhcpIterateOptions
544 with DhcpFillOption to fill each option's data to its position in the
547 @param Packet The DHCP packet to parse the options
548 @param Count The number of valid dhcp options present in the
550 @param OptionPoint The array that contains the DHCP options. Caller
553 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory to parse the packet.
554 @retval EFI_INVALID_PARAMETER The options are mal-formated
555 @retval EFI_SUCCESS The options are parsed into OptionPoint
560 IN EFI_DHCP4_PACKET
*Packet
,
562 OUT DHCP_OPTION
**OptionPoint
565 DHCP_OPTION_CONTEXT Context
;
566 DHCP_OPTION
*Options
;
567 DHCP_OPTION_COUNT
*OptCount
;
573 ASSERT ((Count
!= NULL
) && (OptionPoint
!= NULL
));
576 // First compute how many options and how long each option is
577 // with the "Key indexed counting" algorithms.
579 OptCount
= AllocateZeroPool (DHCP_MAX_OPTIONS
* sizeof (DHCP_OPTION_COUNT
));
581 if (OptCount
== NULL
) {
582 return EFI_OUT_OF_RESOURCES
;
585 Status
= DhcpIterateOptions (Packet
, DhcpGetOptionLen
, OptCount
);
587 if (EFI_ERROR (Status
)) {
592 // Before the loop, Offset is the length of the option. After loop,
593 // OptCount[Index].Offset specifies the offset into the continuous
594 // option value buffer to put the data.
599 for (Index
= 0; Index
< DHCP_MAX_OPTIONS
; Index
++) {
600 if (OptCount
[Index
].Offset
!= 0) {
601 OptCount
[Index
].Index
= (UINT8
) OptNum
;
603 TotalLen
= (UINT16
) (TotalLen
+ OptCount
[Index
].Offset
);
604 OptCount
[Index
].Offset
= (UINT16
) (TotalLen
- OptCount
[Index
].Offset
);
618 // Allocate a buffer to hold the DHCP options, and after that, a
619 // continuous buffer to put all the options' data.
621 Options
= AllocateZeroPool (OptNum
* sizeof (DHCP_OPTION
) + TotalLen
);
623 if (Options
== NULL
) {
624 Status
= EFI_OUT_OF_RESOURCES
;
628 Context
.OpCount
= OptCount
;
629 Context
.Options
= Options
;
630 Context
.Buf
= (UINT8
*) (Options
+ OptNum
);
632 Status
= DhcpIterateOptions (Packet
, DhcpFillOption
, &Context
);
634 if (EFI_ERROR (Status
)) {
635 gBS
->FreePool (Options
);
639 *OptionPoint
= Options
;
642 gBS
->FreePool (OptCount
);
648 Validate the packet's options. If necessary, allocate
649 and fill in the interested parameters.
651 @param Packet The packet to validate the options
652 @param Para The variable to save the DHCP parameters.
654 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory to validate the packet.
655 @retval EFI_INVALID_PARAMETER The options are mal-formated
656 @retval EFI_SUCCESS The options are parsed into OptionPoint
660 DhcpValidateOptions (
661 IN EFI_DHCP4_PACKET
*Packet
,
662 OUT DHCP_PARAMETER
**Para OPTIONAL
665 DHCP_PARAMETER Parameter
;
666 DHCP_OPTION_FORMAT
*Format
;
667 DHCP_OPTION
*AllOption
;
679 Status
= DhcpParseOption (Packet
, &Count
, &AllOption
);
681 if (EFI_ERROR (Status
) || (Count
== 0)) {
686 ZeroMem (&Parameter
, sizeof (Parameter
));
688 for (Index
= 0; Index
< Count
; Index
++) {
689 Option
= &AllOption
[Index
];
692 // Find the format of the option then validate it.
694 Format
= DhcpFindOptionFormat (Option
->Tag
);
696 if (Format
== NULL
) {
700 if (!DhcpOptionIsValid (Format
, Option
->Data
, Option
->Len
)) {
701 Status
= EFI_INVALID_PARAMETER
;
706 // Get the client interested parameters
708 if (Format
->Alert
&& (Para
!= NULL
)) {
710 Status
= DhcpGetParameter (Option
->Tag
, Option
->Len
, Option
->Data
, &Parameter
);
712 if (EFI_ERROR (Status
)) {
718 if (Updated
&& (Para
!= NULL
)) {
719 if ((*Para
= AllocatePool (sizeof (DHCP_PARAMETER
))) == NULL
) {
720 Status
= EFI_OUT_OF_RESOURCES
;
724 CopyMem (*Para
, &Parameter
, sizeof (**Para
));
728 gBS
->FreePool (AllOption
);
735 Append an option to the memory, if the option is longer than
736 255 bytes, splits it into several options.
738 @param Buf The buffer to append the option to
739 @param Tag The option's tag
740 @param DataLen The length of the option's data
741 @param Data The option's data
743 @return The position to append the next option
757 ASSERT (DataLen
!= 0);
759 for (Index
= 0; Index
< (DataLen
+ 254) / 255; Index
++) {
760 Len
= MIN (255, DataLen
- Index
* 255);
763 *(Buf
++) = (UINT8
) Len
;
764 CopyMem (Buf
, Data
+ Index
* 255, Len
);
774 Build a new DHCP packet from a seed packet. Options may be deleted or
775 appended. The caller should free the NewPacket when finished using it.
777 @param SeedPacket The seed packet to start with
778 @param DeleteCount The number of options to delete
779 @param DeleteList The options to delete from the packet
780 @param AppendCount The number of options to append
781 @param AppendList The options to append to the packet
782 @param NewPacket The new packet, allocated and built by this
785 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory
786 @retval EFI_INVALID_PARAMETER The options in SeekPacket are mal-formated
787 @retval EFI_SUCCESS The packet is build.
792 IN EFI_DHCP4_PACKET
*SeedPacket
,
793 IN UINT32 DeleteCount
,
794 IN UINT8
*DeleteList OPTIONAL
,
795 IN UINT32 AppendCount
,
796 IN EFI_DHCP4_PACKET_OPTION
*AppendList
[] OPTIONAL
,
797 OUT EFI_DHCP4_PACKET
**NewPacket
801 DHCP_OPTION
*SeedOptions
;
802 EFI_DHCP4_PACKET
*Packet
;
810 // Use an array of DHCP_OPTION to mark the existance
811 // and position of each valid options.
813 Mark
= AllocatePool (sizeof (DHCP_OPTION
) * DHCP_MAX_OPTIONS
);
816 return EFI_OUT_OF_RESOURCES
;
819 for (Index
= 0; Index
< DHCP_MAX_OPTIONS
; Index
++) {
820 Mark
[Index
].Tag
= (UINT8
) Index
;
825 // Get list of the options from the seed packet, then put
826 // them to the mark array according to their tags.
829 Status
= DhcpParseOption (SeedPacket
, &Count
, &SeedOptions
);
831 if (EFI_ERROR (Status
)) {
835 for (Index
= 0; Index
< (UINT32
) Count
; Index
++) {
836 Mark
[SeedOptions
[Index
].Tag
] = SeedOptions
[Index
];
840 // Mark the option's length is zero if it is in the DeleteList.
842 for (Index
= 0; Index
< DeleteCount
; Index
++) {
843 Mark
[DeleteList
[Index
]].Len
= 0;
847 // Add or replace the option if it is in the append list.
849 for (Index
= 0; Index
< AppendCount
; Index
++) {
850 Mark
[AppendList
[Index
]->OpCode
].Len
= AppendList
[Index
]->Length
;
851 Mark
[AppendList
[Index
]->OpCode
].Data
= AppendList
[Index
]->Data
;
855 // compute the new packet length. No need to add 1 byte for
856 // EOP option since EFI_DHCP4_PACKET includes one extra byte
857 // for option. It is necessary to split the option if it is
858 // longer than 255 bytes.
860 Len
= sizeof (EFI_DHCP4_PACKET
);
862 for (Index
= 0; Index
< DHCP_MAX_OPTIONS
; Index
++) {
863 if (Mark
[Index
].Len
!= 0) {
864 Len
+= ((Mark
[Index
].Len
+ 254) / 255) * 2 + Mark
[Index
].Len
;
868 Status
= EFI_OUT_OF_RESOURCES
;
869 Packet
= (EFI_DHCP4_PACKET
*) AllocatePool (Len
);
871 if (Packet
== NULL
) {
877 CopyMem (&Packet
->Dhcp4
.Header
, &SeedPacket
->Dhcp4
.Header
, sizeof (Packet
->Dhcp4
.Header
));
878 Packet
->Dhcp4
.Magik
= DHCP_OPTION_MAGIC
;
879 Buf
= Packet
->Dhcp4
.Option
;
881 for (Index
= 0; Index
< DHCP_MAX_OPTIONS
; Index
++) {
882 if (Mark
[Index
].Len
!= 0) {
883 Buf
= DhcpAppendOption (Buf
, Mark
[Index
].Tag
, Mark
[Index
].Len
, Mark
[Index
].Data
);
887 *(Buf
++) = DHCP_TAG_EOP
;
888 Packet
->Length
= sizeof (EFI_DHCP4_HEADER
) + sizeof (UINT32
)
889 + (UINT32
) (Buf
- Packet
->Dhcp4
.Option
);
892 Status
= EFI_SUCCESS
;
895 if (SeedOptions
!= NULL
) {
896 gBS
->FreePool (SeedOptions
);
899 gBS
->FreePool (Mark
);