2 Function to validate, parse, process the DHCP options.
4 Copyright (c) 2006 - 2009, Intel Corporation.<BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "Dhcp4Impl.h"
18 /// A list of the format of DHCP Options sorted by option tag
19 /// to validate a dhcp message. Refere the comments of the
20 /// DHCP_OPTION_FORMAT structure.
22 DHCP_OPTION_FORMAT DhcpOptionFormats
[] = {
23 {DHCP_TAG_NETMASK
, DHCP_OPTION_IP
, 1, 1 , TRUE
},
24 {DHCP_TAG_TIME_OFFSET
, DHCP_OPTION_INT32
, 1, 1 , FALSE
},
25 {DHCP_TAG_ROUTER
, DHCP_OPTION_IP
, 1, -1 , TRUE
},
26 {DHCP_TAG_TIME_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
27 {DHCP_TAG_NAME_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
28 {DHCP_TAG_DNS_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
29 {DHCP_TAG_LOG_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
30 {DHCP_TAG_COOKIE_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
31 {DHCP_TAG_LPR_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
32 {DHCP_TAG_IMPRESS_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
33 {DHCP_TAG_RL_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
34 {DHCP_TAG_HOSTNAME
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
35 {DHCP_TAG_BOOTFILE_LEN
, DHCP_OPTION_INT16
, 1, 1 , FALSE
},
36 {DHCP_TAG_DUMP
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
37 {DHCP_TAG_DOMAINNAME
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
38 {DHCP_TAG_SWAP_SERVER
, DHCP_OPTION_IP
, 1, 1 , FALSE
},
39 {DHCP_TAG_ROOTPATH
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
40 {DHCP_TAG_EXTEND_PATH
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
42 {DHCP_TAG_IPFORWARD
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
43 {DHCP_TAG_NONLOCAL_SRR
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
44 {DHCP_TAG_POLICY_SRR
, DHCP_OPTION_IPPAIR
, 1, -1 , FALSE
},
45 {DHCP_TAG_EMTU
, DHCP_OPTION_INT16
, 1, 1 , FALSE
},
46 {DHCP_TAG_TTL
, DHCP_OPTION_INT8
, 1, 1 , FALSE
},
47 {DHCP_TAG_PATHMTU_AGE
, DHCP_OPTION_INT32
, 1, 1 , FALSE
},
48 {DHCP_TAG_PATHMTU_PLATEAU
,DHCP_OPTION_INT16
, 1, -1 , FALSE
},
50 {DHCP_TAG_IFMTU
, DHCP_OPTION_INT16
, 1, 1 , FALSE
},
51 {DHCP_TAG_SUBNET_LOCAL
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
52 {DHCP_TAG_BROADCAST
, DHCP_OPTION_IP
, 1, 1 , FALSE
},
53 {DHCP_TAG_DISCOVER_MASK
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
54 {DHCP_TAG_SUPPLY_MASK
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
55 {DHCP_TAG_DISCOVER_ROUTE
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
56 {DHCP_TAG_ROUTER_SOLICIT
, DHCP_OPTION_IP
, 1, 1 , FALSE
},
57 {DHCP_TAG_STATIC_ROUTE
, DHCP_OPTION_IPPAIR
, 1, -1 , FALSE
},
59 {DHCP_TAG_TRAILER
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
60 {DHCP_TAG_ARPAGE
, DHCP_OPTION_INT32
, 1, 1 , FALSE
},
61 {DHCP_TAG_ETHER_ENCAP
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
63 {DHCP_TAG_TCP_TTL
, DHCP_OPTION_INT8
, 1, 1 , FALSE
},
64 {DHCP_TAG_KEEP_INTERVAL
, DHCP_OPTION_INT32
, 1, 1 , FALSE
},
65 {DHCP_TAG_KEEP_GARBAGE
, DHCP_OPTION_SWITCH
, 1, 1 , FALSE
},
67 {DHCP_TAG_NIS_DOMAIN
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
68 {DHCP_TAG_NIS_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
69 {DHCP_TAG_NTP_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
70 {DHCP_TAG_VENDOR
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
71 {DHCP_TAG_NBNS
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
72 {DHCP_TAG_NBDD
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
73 {DHCP_TAG_NBTYPE
, DHCP_OPTION_INT8
, 1, 1 , FALSE
},
74 {DHCP_TAG_NBSCOPE
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
75 {DHCP_TAG_XFONT
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
76 {DHCP_TAG_XDM
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
78 {DHCP_TAG_REQUEST_IP
, DHCP_OPTION_IP
, 1, 1 , FALSE
},
79 {DHCP_TAG_LEASE
, DHCP_OPTION_INT32
, 1, 1 , TRUE
},
80 {DHCP_TAG_OVERLOAD
, DHCP_OPTION_INT8
, 1, 1 , TRUE
},
81 {DHCP_TAG_TYPE
, DHCP_OPTION_INT8
, 1, 1 , TRUE
},
82 {DHCP_TAG_SERVER_ID
, DHCP_OPTION_IP
, 1, 1 , TRUE
},
83 {DHCP_TAG_PARA_LIST
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
84 {DHCP_TAG_MESSAGE
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
85 {DHCP_TAG_MAXMSG
, DHCP_OPTION_INT16
, 1, 1 , FALSE
},
86 {DHCP_TAG_T1
, DHCP_OPTION_INT32
, 1, 1 , TRUE
},
87 {DHCP_TAG_T2
, DHCP_OPTION_INT32
, 1, 1 , TRUE
},
88 {DHCP_TAG_VENDOR_CLASS
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
89 {DHCP_TAG_CLIENT_ID
, DHCP_OPTION_INT8
, 2, -1 , FALSE
},
91 {DHCP_TAG_NISPLUS
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
92 {DHCP_TAG_NISPLUS_SERVER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
94 {DHCP_TAG_TFTP
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
95 {DHCP_TAG_BOOTFILE
, DHCP_OPTION_INT8
, 1, -1 , FALSE
},
97 {DHCP_TAG_MOBILEIP
, DHCP_OPTION_IP
, 0, -1 , FALSE
},
98 {DHCP_TAG_SMTP
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
99 {DHCP_TAG_POP3
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
100 {DHCP_TAG_NNTP
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
101 {DHCP_TAG_WWW
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
102 {DHCP_TAG_FINGER
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
103 {DHCP_TAG_IRC
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
104 {DHCP_TAG_STTALK
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
105 {DHCP_TAG_STDA
, DHCP_OPTION_IP
, 1, -1 , FALSE
},
107 {DHCP_TAG_CLASSLESS_ROUTE
,DHCP_OPTION_INT8
, 5, -1 , FALSE
},
112 Binary search the DhcpOptionFormats array to find the format
113 information about a specific option.
115 @param[in] Tag The option's tag.
117 @return The point to the option's format, NULL if not found.
121 DhcpFindOptionFormat (
130 Right
= sizeof (DhcpOptionFormats
) / sizeof (DHCP_OPTION_FORMAT
) - 1;
132 while (Right
>= Left
) {
133 Middle
= (Left
+ Right
) / 2;
135 if (Tag
== DhcpOptionFormats
[Middle
].Tag
) {
136 return &DhcpOptionFormats
[Middle
];
139 if (Tag
< DhcpOptionFormats
[Middle
].Tag
) {
151 Validate whether a single DHCP option is valid according to its format.
153 @param[in] Format The option's format
154 @param[in] OptValue The value of the option
155 @param[in] Len The length of the option value
157 @retval TRUE The option is valid.
158 @retval FALSE Otherwise.
163 IN DHCP_OPTION_FORMAT
*Format
,
174 switch (Format
->Type
) {
175 case DHCP_OPTION_SWITCH
:
176 case DHCP_OPTION_INT8
:
180 case DHCP_OPTION_INT16
:
184 case DHCP_OPTION_INT32
:
189 case DHCP_OPTION_IPPAIR
:
197 // Validate that the option appears in the full units.
199 if ((Len
% Unit
) != 0) {
204 // Validate the occurance of the option unit is with in [MinOccur, MaxOccur]
208 if (((Format
->MinOccur
!= -1) && (Occur
< Format
->MinOccur
)) ||
209 ((Format
->MaxOccur
!= -1) && (Occur
> Format
->MaxOccur
))
215 // If the option is of type switch, only 0/1 are valid values.
217 if (Format
->Type
== DHCP_OPTION_SWITCH
) {
218 for (Index
= 0; Index
< Occur
; Index
++) {
219 if ((OptValue
[Index
] != 0) && (OptValue
[Index
] != 1)) {
230 Extract the client interested options, all the parameters are
231 converted to host byte order.
233 @param[in] Tag The DHCP option tag
234 @param[in] Len The length of the option
235 @param[in] Data The value of the DHCP option
236 @param[out] Para The variable to save the interested parameter
238 @retval EFI_SUCCESS The DHCP option is successfully extracted.
239 @retval EFI_INVALID_PARAMETER The DHCP option is mal-formated
247 OUT DHCP_PARAMETER
*Para
251 case DHCP_TAG_NETMASK
:
252 Para
->NetMask
= NetGetUint32 (Data
);
255 case DHCP_TAG_ROUTER
:
257 // Return the first router to consumer which is the preferred one
259 Para
->Router
= NetGetUint32 (Data
);
263 Para
->Lease
= NetGetUint32 (Data
);
266 case DHCP_TAG_OVERLOAD
:
267 Para
->Overload
= *Data
;
269 if ((Para
->Overload
< 1) || (Para
->Overload
> 3)) {
270 return EFI_INVALID_PARAMETER
;
275 Para
->DhcpType
= *Data
;
277 if ((Para
->DhcpType
< 1) || (Para
->DhcpType
> 9)) {
278 return EFI_INVALID_PARAMETER
;
282 case DHCP_TAG_SERVER_ID
:
283 Para
->ServerId
= NetGetUint32 (Data
);
287 Para
->T1
= NetGetUint32 (Data
);
291 Para
->T2
= NetGetUint32 (Data
);
300 Inspect all the options in a single buffer. DHCP options may be contained
301 in several buffers, such as the BOOTP options filed, boot file or server
302 name. Each option buffer is required to end with DHCP_TAG_EOP.
304 @param[in] Buffer The buffer which contains DHCP options
305 @param[in] BufLen The length of the buffer
306 @param[in] Check The callback function for each option found
307 @param[in] Context The opaque parameter for the Check
308 @param[out] Overload Variable to save the value of DHCP_TAG_OVERLOAD
311 @retval EFI_SUCCESS All the options are valid
312 @retval EFI_INVALID_PARAMETER The options are mal-formated.
316 DhcpIterateBufferOptions (
319 IN DHCP_CHECK_OPTION Check OPTIONAL
,
321 OUT UINT8
*Overload OPTIONAL
330 while (Cur
< BufLen
) {
333 if (Tag
== DHCP_TAG_PAD
) {
336 } else if (Tag
== DHCP_TAG_EOP
) {
343 return EFI_INVALID_PARAMETER
;
348 if (Cur
+ Len
> BufLen
) {
349 return EFI_INVALID_PARAMETER
;
352 if ((Tag
== DHCP_TAG_OVERLOAD
) && (Overload
!= NULL
)) {
354 return EFI_INVALID_PARAMETER
;
357 *Overload
= Buffer
[Cur
];
360 if ((Check
!= NULL
) && EFI_ERROR (Check (Tag
, Len
, Buffer
+ Cur
, Context
))) {
361 return EFI_INVALID_PARAMETER
;
368 // Each option buffer is expected to end with an EOP
370 return EFI_INVALID_PARAMETER
;
375 Iterate through a DHCP message to visit each option. First inspect
376 all the options in the OPTION field. Then if overloaded, inspect
377 the options in FILENAME and SERVERNAME fields. One option may be
378 encoded in several places. See RFC 3396 Encoding Long Options in DHCP
380 @param[in] Packet The DHCP packet to check the options for
381 @param[in] Check The callback function to be called for each option
383 @param[in] Context The opaque parameter for Check
385 @retval EFI_SUCCESS The DHCP packet's options are well formated
386 @retval EFI_INVALID_PARAMETER The DHCP packet's options are not well formated
391 IN EFI_DHCP4_PACKET
*Packet
,
392 IN DHCP_CHECK_OPTION Check OPTIONAL
,
401 Status
= DhcpIterateBufferOptions (
402 Packet
->Dhcp4
.Option
,
403 Packet
->Length
- sizeof (EFI_DHCP4_HEADER
) - sizeof (UINT32
),
409 if (EFI_ERROR (Status
)) {
413 if ((Overload
== DHCP_OVERLOAD_FILENAME
) || (Overload
== DHCP_OVERLOAD_BOTH
)) {
414 Status
= DhcpIterateBufferOptions (
415 (UINT8
*) Packet
->Dhcp4
.Header
.BootFileName
,
422 if (EFI_ERROR (Status
)) {
427 if ((Overload
== DHCP_OVERLOAD_SVRNAME
) || (Overload
== DHCP_OVERLOAD_BOTH
)) {
428 Status
= DhcpIterateBufferOptions (
429 (UINT8
*) Packet
->Dhcp4
.Header
.ServerName
,
436 if (EFI_ERROR (Status
)) {
446 Call back function to DhcpIterateOptions to compute each option's
447 length. It just adds the data length of all the occurances of this
448 Tag. Context is an array of 256 DHCP_OPTION_COUNT.
450 @param[in] Tag The current option to check
451 @param[in] Len The length of the option data
452 @param[in] Data The option data
453 @param[in] Context The context, which is a array of 256
456 @retval EFI_SUCCESS It always returns EFI_SUCCESS.
467 DHCP_OPTION_COUNT
*OpCount
;
469 OpCount
= (DHCP_OPTION_COUNT
*) Context
;
470 OpCount
[Tag
].Offset
= (UINT16
) (OpCount
[Tag
].Offset
+ Len
);
477 Call back function to DhcpIterateOptions to consolidate each option's
478 data. There are maybe several occurrence of the same option.
480 @param[in] Tag The option to consolidate its data
481 @param[in] Len The length of option data
482 @param[in] Data The data of the option's current occurance
483 @param[in] Context The context, which is DHCP_OPTION_CONTEXT. This
484 array is just a wrap to pass THREE parameters.
486 @retval EFI_SUCCESS It always returns EFI_SUCCESS
497 DHCP_OPTION_CONTEXT
*OptContext
;
498 DHCP_OPTION_COUNT
*OptCount
;
499 DHCP_OPTION
*Options
;
503 OptContext
= (DHCP_OPTION_CONTEXT
*) Context
;
505 OptCount
= OptContext
->OpCount
;
506 Index
= OptCount
[Tag
].Index
;
507 Options
= OptContext
->Options
;
508 Buf
= OptContext
->Buf
;
510 if (Options
[Index
].Data
== NULL
) {
511 Options
[Index
].Tag
= Tag
;
512 Options
[Index
].Data
= Buf
+ OptCount
[Tag
].Offset
;
515 CopyMem (Buf
+ OptCount
[Tag
].Offset
, Data
, Len
);
517 OptCount
[Tag
].Offset
= (UINT16
) (OptCount
[Tag
].Offset
+ Len
);
518 Options
[Index
].Len
= (UINT16
) (Options
[Index
].Len
+ Len
);
524 Parse the options of a DHCP packet. It supports RFC 3396: Encoding
525 Long Options in DHCP. That is, it will combine all the option value
526 of all the occurances of each option.
527 A little bit of implemenation:
528 It adopts the "Key indexed counting" algorithm. First, it allocates
529 an array of 256 DHCP_OPTION_COUNTs because DHCP option tag is encoded
530 as a UINT8. It then iterates the DHCP packet to get data length of
531 each option by calling DhcpIterOptions with DhcpGetOptionLen. Now, it
532 knows the number of present options and their length. It allocates a
533 array of DHCP_OPTION and a continuous buffer after the array to put
534 all the options' data. Each option's data is pointed to by the Data
535 field in DHCP_OPTION structure. At last, it call DhcpIterateOptions
536 with DhcpFillOption to fill each option's data to its position in the
539 @param[in] Packet The DHCP packet to parse the options
540 @param[out] Count The number of valid dhcp options present in the
542 @param[out] OptionPoint The array that contains the DHCP options. Caller
545 @retval EFI_NOT_FOUND Cannot find any option.
546 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory to parse the packet.
547 @retval EFI_INVALID_PARAMETER The options are mal-formated
548 @retval EFI_SUCCESS The options are parsed into OptionPoint
553 IN EFI_DHCP4_PACKET
*Packet
,
555 OUT DHCP_OPTION
**OptionPoint
558 DHCP_OPTION_CONTEXT Context
;
559 DHCP_OPTION
*Options
;
560 DHCP_OPTION_COUNT
*OptCount
;
566 ASSERT ((Count
!= NULL
) && (OptionPoint
!= NULL
));
569 // First compute how many options and how long each option is
570 // with the "Key indexed counting" algorithms.
572 OptCount
= AllocateZeroPool (DHCP_MAX_OPTIONS
* sizeof (DHCP_OPTION_COUNT
));
574 if (OptCount
== NULL
) {
575 return EFI_OUT_OF_RESOURCES
;
578 Status
= DhcpIterateOptions (Packet
, DhcpGetOptionLen
, OptCount
);
580 if (EFI_ERROR (Status
)) {
585 // Before the loop, Offset is the length of the option. After loop,
586 // OptCount[Index].Offset specifies the offset into the continuous
587 // option value buffer to put the data.
592 for (Index
= 0; Index
< DHCP_MAX_OPTIONS
; Index
++) {
593 if (OptCount
[Index
].Offset
!= 0) {
594 OptCount
[Index
].Index
= (UINT8
) OptNum
;
596 TotalLen
= (UINT16
) (TotalLen
+ OptCount
[Index
].Offset
);
597 OptCount
[Index
].Offset
= (UINT16
) (TotalLen
- OptCount
[Index
].Offset
);
607 Status
= EFI_NOT_FOUND
;
612 // Allocate a buffer to hold the DHCP options, and after that, a
613 // continuous buffer to put all the options' data.
615 Options
= AllocateZeroPool (OptNum
* sizeof (DHCP_OPTION
) + TotalLen
);
617 if (Options
== NULL
) {
618 Status
= EFI_OUT_OF_RESOURCES
;
622 Context
.OpCount
= OptCount
;
623 Context
.Options
= Options
;
624 Context
.Buf
= (UINT8
*) (Options
+ OptNum
);
626 Status
= DhcpIterateOptions (Packet
, DhcpFillOption
, &Context
);
628 if (EFI_ERROR (Status
)) {
629 gBS
->FreePool (Options
);
633 *OptionPoint
= Options
;
636 gBS
->FreePool (OptCount
);
642 Validate the packet's options. If necessary, allocate
643 and fill in the interested parameters.
645 @param[in] Packet The packet to validate the options
646 @param[out] Para The variable to save the DHCP parameters.
648 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory to validate the packet.
649 @retval EFI_INVALID_PARAMETER The options are mal-formated
650 @retval EFI_SUCCESS The options are parsed into OptionPoint
654 DhcpValidateOptions (
655 IN EFI_DHCP4_PACKET
*Packet
,
656 OUT DHCP_PARAMETER
**Para OPTIONAL
659 DHCP_PARAMETER Parameter
;
660 DHCP_OPTION_FORMAT
*Format
;
661 DHCP_OPTION
*AllOption
;
674 Status
= DhcpParseOption (Packet
, &Count
, &AllOption
);
675 if (EFI_ERROR (Status
) || (Count
== 0)) {
680 ZeroMem (&Parameter
, sizeof (Parameter
));
682 for (Index
= 0; Index
< Count
; Index
++) {
683 Option
= &AllOption
[Index
];
686 // Find the format of the option then validate it.
688 Format
= DhcpFindOptionFormat (Option
->Tag
);
690 if (Format
== NULL
) {
694 if (!DhcpOptionIsValid (Format
, Option
->Data
, Option
->Len
)) {
695 Status
= EFI_INVALID_PARAMETER
;
700 // Get the client interested parameters
702 if (Format
->Alert
&& (Para
!= NULL
)) {
704 Status
= DhcpGetParameter (Option
->Tag
, Option
->Len
, Option
->Data
, &Parameter
);
706 if (EFI_ERROR (Status
)) {
712 if (Updated
&& (Para
!= NULL
)) {
713 if ((*Para
= AllocatePool (sizeof (DHCP_PARAMETER
))) == NULL
) {
714 Status
= EFI_OUT_OF_RESOURCES
;
718 CopyMem (*Para
, &Parameter
, sizeof (**Para
));
722 gBS
->FreePool (AllOption
);
729 Append an option to the memory, if the option is longer than
730 255 bytes, splits it into several options.
732 @param[out] Buf The buffer to append the option to
733 @param[in] Tag The option's tag
734 @param[in] DataLen The length of the option's data
735 @param[in] Data The option's data
737 @return The position to append the next option
751 ASSERT (DataLen
!= 0);
753 for (Index
= 0; Index
< (DataLen
+ 254) / 255; Index
++) {
754 Len
= MIN (255, DataLen
- Index
* 255);
757 *(Buf
++) = (UINT8
) Len
;
758 CopyMem (Buf
, Data
+ Index
* 255, Len
);
768 Build a new DHCP packet from a seed packet. Options may be deleted or
769 appended. The caller should free the NewPacket when finished using it.
771 @param[in] SeedPacket The seed packet to start with
772 @param[in] DeleteCount The number of options to delete
773 @param[in] DeleteList The options to delete from the packet
774 @param[in] AppendCount The number of options to append
775 @param[in] AppendList The options to append to the packet
776 @param[out] NewPacket The new packet, allocated and built by this
779 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory
780 @retval EFI_INVALID_PARAMETER The options in SeekPacket are mal-formated
781 @retval EFI_SUCCESS The packet is build.
786 IN EFI_DHCP4_PACKET
*SeedPacket
,
787 IN UINT32 DeleteCount
,
788 IN UINT8
*DeleteList OPTIONAL
,
789 IN UINT32 AppendCount
,
790 IN EFI_DHCP4_PACKET_OPTION
*AppendList
[] OPTIONAL
,
791 OUT EFI_DHCP4_PACKET
**NewPacket
795 DHCP_OPTION
*SeedOptions
;
796 EFI_DHCP4_PACKET
*Packet
;
804 // Use an array of DHCP_OPTION to mark the existance
805 // and position of each valid options.
807 Mark
= AllocatePool (sizeof (DHCP_OPTION
) * DHCP_MAX_OPTIONS
);
810 return EFI_OUT_OF_RESOURCES
;
813 for (Index
= 0; Index
< DHCP_MAX_OPTIONS
; Index
++) {
814 Mark
[Index
].Tag
= (UINT8
) Index
;
819 // Get list of the options from the seed packet, then put
820 // them to the mark array according to their tags.
823 Status
= DhcpParseOption (SeedPacket
, &Count
, &SeedOptions
);
825 if (EFI_ERROR (Status
)) {
828 ASSERT (SeedOptions
!= NULL
);
830 for (Index
= 0; Index
< (UINT32
) Count
; Index
++) {
831 Mark
[SeedOptions
[Index
].Tag
] = SeedOptions
[Index
];
835 // Mark the option's length is zero if it is in the DeleteList.
837 for (Index
= 0; Index
< DeleteCount
; Index
++) {
838 Mark
[DeleteList
[Index
]].Len
= 0;
842 // Add or replace the option if it is in the append list.
844 for (Index
= 0; Index
< AppendCount
; Index
++) {
845 Mark
[AppendList
[Index
]->OpCode
].Len
= AppendList
[Index
]->Length
;
846 Mark
[AppendList
[Index
]->OpCode
].Data
= AppendList
[Index
]->Data
;
850 // compute the new packet length. No need to add 1 byte for
851 // EOP option since EFI_DHCP4_PACKET includes one extra byte
852 // for option. It is necessary to split the option if it is
853 // longer than 255 bytes.
855 Len
= sizeof (EFI_DHCP4_PACKET
);
857 for (Index
= 0; Index
< DHCP_MAX_OPTIONS
; Index
++) {
858 if (Mark
[Index
].Len
!= 0) {
859 Len
+= ((Mark
[Index
].Len
+ 254) / 255) * 2 + Mark
[Index
].Len
;
863 Status
= EFI_OUT_OF_RESOURCES
;
864 Packet
= (EFI_DHCP4_PACKET
*) AllocatePool (Len
);
866 if (Packet
== NULL
) {
872 CopyMem (&Packet
->Dhcp4
.Header
, &SeedPacket
->Dhcp4
.Header
, sizeof (Packet
->Dhcp4
.Header
));
873 Packet
->Dhcp4
.Magik
= DHCP_OPTION_MAGIC
;
874 Buf
= Packet
->Dhcp4
.Option
;
876 for (Index
= 0; Index
< DHCP_MAX_OPTIONS
; Index
++) {
877 if (Mark
[Index
].Len
!= 0) {
878 Buf
= DhcpAppendOption (Buf
, Mark
[Index
].Tag
, Mark
[Index
].Len
, Mark
[Index
].Data
);
882 *(Buf
++) = DHCP_TAG_EOP
;
883 Packet
->Length
= sizeof (EFI_DHCP4_HEADER
) + sizeof (UINT32
)
884 + (UINT32
) (Buf
- Packet
->Dhcp4
.Option
);
887 Status
= EFI_SUCCESS
;
890 if (SeedOptions
!= NULL
) {
891 gBS
->FreePool (SeedOptions
);
894 gBS
->FreePool (Mark
);