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 STATIC 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 @return TRUE is the option is valid, otherwise FALSE.
170 IN DHCP_OPTION_FORMAT
*Format
,
181 switch (Format
->Type
) {
182 case DHCP_OPTION_SWITCH
:
183 case DHCP_OPTION_INT8
:
187 case DHCP_OPTION_INT16
:
191 case DHCP_OPTION_INT32
:
196 case DHCP_OPTION_IPPAIR
:
204 // Validate that the option appears in the full units.
206 if ((Len
% Unit
) != 0) {
211 // Validate the occurance of the option unit is with in [MinOccur, MaxOccur]
215 if (((Format
->MinOccur
!= -1) && (Occur
< Format
->MinOccur
)) ||
216 ((Format
->MaxOccur
!= -1) && (Occur
> Format
->MaxOccur
))) {
221 // If the option is of type switch, only 0/1 are valid values.
223 if (Format
->Type
== DHCP_OPTION_SWITCH
) {
224 for (Index
= 0; Index
< Occur
; Index
++) {
225 if ((OptValue
[Index
] != 0) && (OptValue
[Index
] != 1)) {
236 Extract the client interested options, all the parameters are
237 converted to host byte order.
239 @param Tag The DHCP option tag
240 @param Len The length of the option
241 @param Data The value of the DHCP option
242 @param Para The variable to save the interested parameter
244 @retval EFI_SUCCESS The DHCP option is successfully extracted.
245 @retval EFI_INVALID_PARAMETER The DHCP option is mal-formated
253 IN DHCP_PARAMETER
*Para
257 case DHCP_TAG_NETMASK
:
258 Para
->NetMask
= NetGetUint32 (Data
);
261 case DHCP_TAG_ROUTER
:
263 // Return the first router to consumer which is the preferred one
265 Para
->Router
= NetGetUint32 (Data
);
269 Para
->Lease
= NetGetUint32 (Data
);
272 case DHCP_TAG_OVERLOAD
:
273 Para
->Overload
= *Data
;
275 if ((Para
->Overload
< 1) || (Para
->Overload
> 3)) {
276 return EFI_INVALID_PARAMETER
;
281 Para
->DhcpType
= *Data
;
283 if ((Para
->DhcpType
< 1) || (Para
->DhcpType
> 9)) {
284 return EFI_INVALID_PARAMETER
;
288 case DHCP_TAG_SERVER_ID
:
289 Para
->ServerId
= NetGetUint32 (Data
);
293 Para
->T1
= NetGetUint32 (Data
);
297 Para
->T2
= NetGetUint32 (Data
);
306 Inspect all the options in a single buffer. DHCP options may be contained
307 in several buffers, such as the BOOTP options filed, boot file or server
308 name. Each option buffer is required to end with DHCP_TAG_EOP.
310 @param Buffer The buffer which contains DHCP options
311 @param BufLen The length of the buffer
312 @param Check The callback function for each option found
313 @param Context The opaque parameter for the Check
314 @param Overload variable to save the value of DHCP_TAG_OVERLOAD
317 @retval EFI_SUCCESS All the options are valid
318 @retval EFI_INVALID_PARAMETER The options are mal-formated.
322 DhcpIterateBufferOptions (
325 IN DHCP_CHECK_OPTION Check
, OPTIONAL
327 OUT UINT8
*Overload OPTIONAL
336 while (Cur
< BufLen
) {
339 if (Tag
== DHCP_TAG_PAD
) {
342 } else if (Tag
== DHCP_TAG_EOP
) {
349 return EFI_INVALID_PARAMETER
;
354 if (Cur
+ Len
> BufLen
) {
355 return EFI_INVALID_PARAMETER
;
358 if ((Tag
== DHCP_TAG_OVERLOAD
) && (Overload
!= NULL
)) {
360 return EFI_INVALID_PARAMETER
;
363 *Overload
= Buffer
[Cur
];
366 if ((Check
!= NULL
) && EFI_ERROR (Check (Tag
, Len
, Buffer
+ Cur
, Context
))) {
367 return EFI_INVALID_PARAMETER
;
374 // Each option buffer is expected to end with an EOP
376 return EFI_INVALID_PARAMETER
;
381 Iterate through a DHCP message to visit each option. First inspect
382 all the options in the OPTION field. Then if overloaded, inspect
383 the options in FILENAME and SERVERNAME fields. One option may be
384 encoded in several places. See RFC 3396 Encoding Long Options in DHCP
386 @param Packet The DHCP packet to check the options for
387 @param Check The callback function to be called for each option
389 @param Context The opaque parameter for Check
391 @retval EFI_SUCCESS The DHCP packet's options are well formated
392 @retval Others The DHCP packet's options are not well formated
397 IN EFI_DHCP4_PACKET
*Packet
,
398 IN DHCP_CHECK_OPTION Check
, OPTIONAL
407 Status
= DhcpIterateBufferOptions (
408 Packet
->Dhcp4
.Option
,
409 Packet
->Length
- sizeof (EFI_DHCP4_HEADER
) - sizeof (UINT32
),
415 if (EFI_ERROR (Status
)) {
419 if ((Overload
== DHCP_OVERLOAD_FILENAME
) || (Overload
== DHCP_OVERLOAD_BOTH
)) {
420 Status
= DhcpIterateBufferOptions (
421 (UINT8
*) Packet
->Dhcp4
.Header
.BootFileName
,
428 if (EFI_ERROR (Status
)) {
433 if ((Overload
== DHCP_OVERLOAD_SVRNAME
) || (Overload
== DHCP_OVERLOAD_BOTH
)) {
434 Status
= DhcpIterateBufferOptions (
435 (UINT8
*) Packet
->Dhcp4
.Header
.ServerName
,
442 if (EFI_ERROR (Status
)) {
452 Call back function to DhcpiterateOptions to compute each option's
453 length. It just adds the data length of all the occurances of this
454 Tag. Context is an array of 256 DHCP_OPTION_COUNT.
456 @param Tag The current option to check
457 @param Len The length of the option data
458 @param Data The option data
459 @param Context The context, which is a array of 256
462 @retval EFI_SUCCESS It always returns EFI_SUCCESS.
473 DHCP_OPTION_COUNT
*OpCount
;
475 OpCount
= (DHCP_OPTION_COUNT
*) Context
;
476 OpCount
[Tag
].Offset
= (UINT16
) (OpCount
[Tag
].Offset
+ Len
);
483 Call back function to DhcpiterateOptions to consolidate each option's
484 data. There are maybe several occurance of the same option.
486 @param Tag The option to consolidate its data
487 @param Len The length of option data
488 @param Data The data of the option's current occurance
489 @param Context The context, which is DHCP_OPTION_CONTEXT. This
490 array is just a wrap to pass THREE parameters.
492 @retval EFI_SUCCESS It always returns EFI_SUCCESS
503 DHCP_OPTION_CONTEXT
*OptContext
;
504 DHCP_OPTION_COUNT
*OptCount
;
505 DHCP_OPTION
*Options
;
509 OptContext
= (DHCP_OPTION_CONTEXT
*) Context
;
511 OptCount
= OptContext
->OpCount
;
512 Index
= OptCount
[Tag
].Index
;
513 Options
= OptContext
->Options
;
514 Buf
= OptContext
->Buf
;
516 if (Options
[Index
].Data
== NULL
) {
517 Options
[Index
].Tag
= Tag
;
518 Options
[Index
].Data
= Buf
+ OptCount
[Tag
].Offset
;
521 CopyMem (Buf
+ OptCount
[Tag
].Offset
, Data
, Len
);
523 OptCount
[Tag
].Offset
= (UINT16
) (OptCount
[Tag
].Offset
+ Len
);
524 Options
[Index
].Len
= (UINT16
) (Options
[Index
].Len
+ Len
);
530 Parse the options of a DHCP packet. It supports RFC 3396: Encoding
531 Long Options in DHCP. That is, it will combine all the option value
532 of all the occurances of each option.
533 A little bit of implemenation:
534 It adopts the "Key indexed counting" algorithm. First, it allocates
535 an array of 256 DHCP_OPTION_COUNTs because DHCP option tag is encoded
536 as a UINT8. It then iterates the DHCP packet to get data length of
537 each option by calling DhcpIterOptions with DhcpGetOptionLen. Now, it
538 knows the number of present options and their length. It allocates a
539 array of DHCP_OPTION and a continous buffer after the array to put
540 all the options' data. Each option's data is pointed to by the Data
541 field in DHCP_OPTION structure. At last, it call DhcpIterateOptions
542 with DhcpFillOption to fill each option's data to its position in the
545 @param Packet The DHCP packet to parse the options
546 @param Count The number of valid dhcp options present in the
548 @param OptionPoint The array that contains the DHCP options. Caller
551 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory to parse the packet.
552 @retval EFI_INVALID_PARAMETER The options are mal-formated
553 @retval EFI_SUCCESS The options are parsed into OptionPoint
558 IN EFI_DHCP4_PACKET
*Packet
,
560 OUT DHCP_OPTION
**OptionPoint
563 DHCP_OPTION_CONTEXT Context
;
564 DHCP_OPTION
*Options
;
565 DHCP_OPTION_COUNT
*OptCount
;
571 ASSERT ((Count
!= NULL
) && (OptionPoint
!= NULL
));
574 // First compute how many options and how long each option is
575 // with the "Key indexed counting" algorithms.
577 OptCount
= AllocateZeroPool (DHCP_MAX_OPTIONS
* sizeof (DHCP_OPTION_COUNT
));
579 if (OptCount
== NULL
) {
580 return EFI_OUT_OF_RESOURCES
;
583 Status
= DhcpIterateOptions (Packet
, DhcpGetOptionLen
, OptCount
);
585 if (EFI_ERROR (Status
)) {
590 // Before the loop, Offset is the length of the option. After loop,
591 // OptCount[Index].Offset specifies the offset into the continuous
592 // option value buffer to put the data.
597 for (Index
= 0; Index
< DHCP_MAX_OPTIONS
; Index
++) {
598 if (OptCount
[Index
].Offset
!= 0) {
599 OptCount
[Index
].Index
= (UINT8
) OptNum
;
601 TotalLen
= (UINT16
) (TotalLen
+ OptCount
[Index
].Offset
);
602 OptCount
[Index
].Offset
= (UINT16
) (TotalLen
- OptCount
[Index
].Offset
);
616 // Allocate a buffer to hold the DHCP options, and after that, a
617 // continuous buffer to put all the options' data.
619 Options
= AllocateZeroPool (OptNum
* sizeof (DHCP_OPTION
) + TotalLen
);
621 if (Options
== NULL
) {
622 Status
= EFI_OUT_OF_RESOURCES
;
626 Context
.OpCount
= OptCount
;
627 Context
.Options
= Options
;
628 Context
.Buf
= (UINT8
*) (Options
+ OptNum
);
630 Status
= DhcpIterateOptions (Packet
, DhcpFillOption
, &Context
);
632 if (EFI_ERROR (Status
)) {
633 gBS
->FreePool (Options
);
637 *OptionPoint
= Options
;
640 gBS
->FreePool (OptCount
);
646 Validate the packet's options. If necessary, allocate
647 and fill in the interested parameters.
649 @param Packet The packet to validate the options
650 @param Para The variable to save the DHCP parameters.
652 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory to validate the packet.
653 @retval EFI_INVALID_PARAMETER The options are mal-formated
654 @retval EFI_SUCCESS The options are parsed into OptionPoint
658 DhcpValidateOptions (
659 IN EFI_DHCP4_PACKET
*Packet
,
660 OUT DHCP_PARAMETER
**Para OPTIONAL
663 DHCP_PARAMETER Parameter
;
664 DHCP_OPTION_FORMAT
*Format
;
665 DHCP_OPTION
*AllOption
;
677 Status
= DhcpParseOption (Packet
, &Count
, &AllOption
);
679 if (EFI_ERROR (Status
) || (Count
== 0)) {
684 ZeroMem (&Parameter
, sizeof (Parameter
));
686 for (Index
= 0; Index
< Count
; Index
++) {
687 Option
= &AllOption
[Index
];
690 // Find the format of the option then validate it.
692 Format
= DhcpFindOptionFormat (Option
->Tag
);
694 if (Format
== NULL
) {
698 if (!DhcpOptionIsValid (Format
, Option
->Data
, Option
->Len
)) {
699 Status
= EFI_INVALID_PARAMETER
;
704 // Get the client interested parameters
706 if (Format
->Alert
&& (Para
!= NULL
)) {
708 Status
= DhcpGetParameter (Option
->Tag
, Option
->Len
, Option
->Data
, &Parameter
);
710 if (EFI_ERROR (Status
)) {
716 if (Updated
&& (Para
!= NULL
)) {
717 if ((*Para
= AllocatePool (sizeof (DHCP_PARAMETER
))) == NULL
) {
718 Status
= EFI_OUT_OF_RESOURCES
;
722 CopyMem (*Para
, &Parameter
, sizeof (**Para
));
726 gBS
->FreePool (AllOption
);
733 Append an option to the memory, if the option is longer than
734 255 bytes, splits it into several options.
736 @param Buf The buffer to append the option to
737 @param Tag The option's tag
738 @param DataLen The length of the option's data
739 @param Data The option's data
741 @return The position to append the next option
755 ASSERT (DataLen
!= 0);
757 for (Index
= 0; Index
< (DataLen
+ 254) / 255; Index
++) {
758 Len
= MIN (255, DataLen
- Index
* 255);
761 *(Buf
++) = (UINT8
) Len
;
762 CopyMem (Buf
, Data
+ Index
* 255, Len
);
772 Build a new DHCP packet from a seed packet. Options may be deleted or
773 appended. The caller should free the NewPacket when finished using it.
775 @param SeedPacket The seed packet to start with
776 @param DeleteCount The number of options to delete
777 @param DeleteList The options to delete from the packet
778 @param AppendCount The number of options to append
779 @param AppendList The options to append to the packet
780 @param NewPacket The new packet, allocated and built by this
783 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory
784 @retval EFI_SUCCESS The packet is build.
789 IN EFI_DHCP4_PACKET
*SeedPacket
,
790 IN UINT32 DeleteCount
,
791 IN UINT8
*DeleteList OPTIONAL
,
792 IN UINT32 AppendCount
,
793 IN EFI_DHCP4_PACKET_OPTION
*AppendList
[] OPTIONAL
,
794 OUT EFI_DHCP4_PACKET
**NewPacket
798 DHCP_OPTION
*SeedOptions
;
799 EFI_DHCP4_PACKET
*Packet
;
807 // Use an array of DHCP_OPTION to mark the existance
808 // and position of each valid options.
810 Mark
= AllocatePool (sizeof (DHCP_OPTION
) * DHCP_MAX_OPTIONS
);
813 return EFI_OUT_OF_RESOURCES
;
816 for (Index
= 0; Index
< DHCP_MAX_OPTIONS
; Index
++) {
817 Mark
[Index
].Tag
= (UINT8
) Index
;
822 // Get list of the options from the seed packet, then put
823 // them to the mark array according to their tags.
826 Status
= DhcpParseOption (SeedPacket
, &Count
, &SeedOptions
);
828 if (EFI_ERROR (Status
)) {
832 for (Index
= 0; Index
< (UINT32
) Count
; Index
++) {
833 Mark
[SeedOptions
[Index
].Tag
] = SeedOptions
[Index
];
837 // Mark the option's length is zero if it is in the DeleteList.
839 for (Index
= 0; Index
< DeleteCount
; Index
++) {
840 Mark
[DeleteList
[Index
]].Len
= 0;
844 // Add or replace the option if it is in the append list.
846 for (Index
= 0; Index
< AppendCount
; Index
++) {
847 Mark
[AppendList
[Index
]->OpCode
].Len
= AppendList
[Index
]->Length
;
848 Mark
[AppendList
[Index
]->OpCode
].Data
= AppendList
[Index
]->Data
;
852 // compute the new packet length. No need to add 1 byte for
853 // EOP option since EFI_DHCP4_PACKET includes one extra byte
854 // for option. It is necessary to split the option if it is
855 // longer than 255 bytes.
857 Len
= sizeof (EFI_DHCP4_PACKET
);
859 for (Index
= 0; Index
< DHCP_MAX_OPTIONS
; Index
++) {
860 if (Mark
[Index
].Len
!= 0) {
861 Len
+= ((Mark
[Index
].Len
+ 254) / 255) * 2 + Mark
[Index
].Len
;
865 Status
= EFI_OUT_OF_RESOURCES
;
866 Packet
= (EFI_DHCP4_PACKET
*) AllocatePool (Len
);
868 if (Packet
== NULL
) {
874 CopyMem (&Packet
->Dhcp4
.Header
, &SeedPacket
->Dhcp4
.Header
, sizeof (Packet
->Dhcp4
.Header
));
875 Packet
->Dhcp4
.Magik
= DHCP_OPTION_MAGIC
;
876 Buf
= Packet
->Dhcp4
.Option
;
878 for (Index
= 0; Index
< DHCP_MAX_OPTIONS
; Index
++) {
879 if (Mark
[Index
].Len
!= 0) {
880 Buf
= DhcpAppendOption (Buf
, Mark
[Index
].Tag
, Mark
[Index
].Len
, Mark
[Index
].Data
);
884 *(Buf
++) = DHCP_TAG_EOP
;
885 Packet
->Length
= sizeof (EFI_DHCP4_HEADER
) + sizeof (UINT32
)
886 + (UINT32
) (Buf
- Packet
->Dhcp4
.Option
);
889 Status
= EFI_SUCCESS
;
892 if (SeedOptions
!= NULL
) {
893 gBS
->FreePool (SeedOptions
);
896 gBS
->FreePool (Mark
);