2 IP6 option support functions and routines.
4 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
13 Validate the IP6 option format for both the packets we received
14 and that we will transmit. It will compute the ICMPv6 error message fields
15 if the option is malformatted.
17 @param[in] IpSb The IP6 service data.
18 @param[in] Packet The to be validated packet.
19 @param[in] Option The first byte of the option.
20 @param[in] OptionLen The length of the whole option.
21 @param[in] Pointer Identifies the octet offset within
22 the invoking packet where the error was detected.
25 @retval TRUE The option is properly formatted.
26 @retval FALSE The option is malformatted.
43 while (Offset
< OptionLen
) {
44 OptionType
= *(Option
+ Offset
);
49 // It is a Pad1 option
55 // It is a PadN option
57 Offset
= (UINT8
) (Offset
+ *(Option
+ Offset
+ 1) + 2);
59 case Ip6OptionRouterAlert
:
61 // It is a Router Alert Option
67 // The highest-order two bits specify the action must be taken if
68 // the processing IPv6 node does not recognize the option type.
70 switch (OptionType
& Ip6OptionMask
) {
72 Offset
= (UINT8
) (Offset
+ *(Option
+ Offset
+ 1));
74 case Ip6OptionDiscard
:
76 case Ip6OptionParameterProblem
:
77 Pointer
= Pointer
+ Offset
+ sizeof (EFI_IP6_HEADER
);
82 &Packet
->Ip
.Ip6
->SourceAddress
,
83 ICMP_V6_PARAMETER_PROBLEM
,
89 if (!IP6_IS_MULTICAST (&Packet
->Ip
.Ip6
->DestinationAddress
)) {
90 Pointer
= Pointer
+ Offset
+ sizeof (EFI_IP6_HEADER
);
95 &Packet
->Ip
.Ip6
->SourceAddress
,
96 ICMP_V6_PARAMETER_PROBLEM
,
115 Validate the IP6 option format for both the packets we received
116 and that we will transmit. It supports the defined options in Neighbor
119 @param[in] Option The first byte of the option.
120 @param[in] OptionLen The length of the whole option.
122 @retval TRUE The option is properly formatted.
123 @retval FALSE The option is malformatted.
138 while (Offset
< OptionLen
) {
139 OptionType
= *(Option
+ Offset
);
140 Length
= (UINT16
) (*(Option
+ Offset
+ 1) * 8);
142 switch (OptionType
) {
143 case Ip6OptionPrefixInfo
:
159 // Check the length of Ip6OptionEtherSource, Ip6OptionEtherTarget, and
160 // Ip6OptionRedirected here. For unrecognized options, silently ignore
161 // and continue processing the message.
170 Offset
= (UINT16
) (Offset
+ Length
);
178 Validate whether the NextHeader is a known valid protocol or one of the user configured
179 protocols from the upper layer.
181 @param[in] IpSb The IP6 service instance.
182 @param[in] NextHeader The next header field.
184 @retval TRUE The NextHeader is a known valid protocol or user configured.
185 @retval FALSE The NextHeader is not a known valid protocol.
190 IN IP6_SERVICE
*IpSb
,
195 IP6_PROTOCOL
*IpInstance
;
197 if (NextHeader
== EFI_IP_PROTO_TCP
||
198 NextHeader
== EFI_IP_PROTO_UDP
||
199 NextHeader
== IP6_ICMP
||
200 NextHeader
== IP6_ESP
209 if (IpSb
->Signature
!= IP6_SERVICE_SIGNATURE
) {
213 NET_LIST_FOR_EACH (Entry
, &IpSb
->Children
) {
214 IpInstance
= NET_LIST_USER_STRUCT_S (Entry
, IP6_PROTOCOL
, Link
, IP6_PROTOCOL_SIGNATURE
);
215 if (IpInstance
->State
== IP6_STATE_CONFIGED
) {
216 if (IpInstance
->ConfigData
.DefaultProtocol
== NextHeader
) {
226 Validate the IP6 extension header format for both the packets we received
227 and that we will transmit. It will compute the ICMPv6 error message fields
228 if the option is mal-formatted.
230 @param[in] IpSb The IP6 service instance. This is an optional parameter.
231 @param[in] Packet The data of the packet. Ignored if NULL.
232 @param[in] NextHeader The next header field in IPv6 basic header.
233 @param[in] ExtHdrs The first byte of the option.
234 @param[in] ExtHdrsLen The length of the whole option.
235 @param[in] Rcvd The option is from the packet we received if TRUE,
236 otherwise, the option we want to transmit.
237 @param[out] FormerHeader The offset of NextHeader which points to Fragment
238 Header when we received, of the ExtHdrs.
239 Ignored if we transmit.
240 @param[out] LastHeader The pointer of NextHeader of the last extension
241 header processed by IP6.
242 @param[out] RealExtsLen The length of extension headers processed by IP6 layer.
243 This is an optional parameter that may be NULL.
244 @param[out] UnFragmentLen The length of unfragmented length of extension headers.
245 This is an optional parameter that may be NULL.
246 @param[out] Fragmented Indicate whether the packet is fragmented.
247 This is an optional parameter that may be NULL.
249 @retval TRUE The option is properly formatted.
250 @retval FALSE The option is malformatted.
255 IN IP6_SERVICE
*IpSb OPTIONAL
,
256 IN NET_BUF
*Packet OPTIONAL
,
257 IN UINT8
*NextHeader
,
259 IN UINT32 ExtHdrsLen
,
261 OUT UINT32
*FormerHeader OPTIONAL
,
262 OUT UINT8
**LastHeader
,
263 OUT UINT32
*RealExtsLen OPTIONAL
,
264 OUT UINT32
*UnFragmentLen OPTIONAL
,
265 OUT BOOLEAN
*Fragmented OPTIONAL
275 IP6_FRAGMENT_HEADER
*FragmentHead
;
276 UINT16 FragmentOffset
;
277 IP6_ROUTING_HEADER
*RoutingHead
;
279 if (RealExtsLen
!= NULL
) {
283 if (UnFragmentLen
!= NULL
) {
287 if (Fragmented
!= NULL
) {
291 *LastHeader
= NextHeader
;
293 if (ExtHdrs
== NULL
&& ExtHdrsLen
== 0) {
297 if ((ExtHdrs
== NULL
&& ExtHdrsLen
!= 0) || (ExtHdrs
!= NULL
&& ExtHdrsLen
== 0)) {
307 while (Offset
<= ExtHdrsLen
) {
309 switch (*NextHeader
) {
316 // Hop-by-Hop Options header is restricted to appear immediately after an IPv6 header only.
317 // If not, generate a ICMP parameter problem message with code value of 1.
320 Pointer
= sizeof (EFI_IP6_HEADER
);
322 Pointer
= Offset
+ sizeof (EFI_IP6_HEADER
);
325 if ((IpSb
!= NULL
) && (Packet
!= NULL
) &&
326 !IP6_IS_MULTICAST (&Packet
->Ip
.Ip6
->DestinationAddress
)) {
331 &Packet
->Ip
.Ip6
->SourceAddress
,
332 ICMP_V6_PARAMETER_PROBLEM
,
345 case IP6_DESTINATION
:
346 if (*NextHeader
== IP6_DESTINATION
) {
354 NextHeader
= ExtHdrs
+ Offset
;
358 Option
= ExtHdrs
+ Offset
;
359 OptionLen
= (UINT8
) ((*Option
+ 1) * 8 - 2);
363 if (IpSb
!= NULL
&& Packet
!= NULL
&& !Ip6IsOptionValid (IpSb
, Packet
, Option
, OptionLen
, Offset
)) {
367 Offset
= Offset
+ OptionLen
;
370 if (UnFragmentLen
!= NULL
) {
371 *UnFragmentLen
= Offset
;
380 NextHeader
= ExtHdrs
+ Offset
;
381 RoutingHead
= (IP6_ROUTING_HEADER
*) NextHeader
;
384 // Type 0 routing header is defined in RFC2460 and deprecated in RFC5095.
385 // Thus all routing types are processed as unrecognized.
387 if (RoutingHead
->SegmentsLeft
== 0) {
389 // Ignore the routing header and proceed to process the next header.
391 Offset
= Offset
+ (RoutingHead
->HeaderLen
+ 1) * 8;
393 if (UnFragmentLen
!= NULL
) {
394 *UnFragmentLen
= Offset
;
399 // Discard the packet and send an ICMP Parameter Problem, Code 0, message
400 // to the packet's source address, pointing to the unrecognized routing
403 Pointer
= Offset
+ 2 + sizeof (EFI_IP6_HEADER
);
404 if ((IpSb
!= NULL
) && (Packet
!= NULL
) &&
405 !IP6_IS_MULTICAST (&Packet
->Ip
.Ip6
->DestinationAddress
)) {
410 &Packet
->Ip
.Ip6
->SourceAddress
,
411 ICMP_V6_PARAMETER_PROBLEM
,
425 // RFC2402, AH header should after fragment header.
432 // RFC2460, ICMP Parameter Problem message with code 0 should be sent
433 // if the length of a fragment is not a multiple of 8 octets and the M
434 // flag of that fragment is 1, pointing to the Payload length field of the
437 if (IpSb
!= NULL
&& Packet
!= NULL
&& (ExtHdrsLen
% 8) != 0) {
439 // Check whether it is the last fragment.
441 FragmentHead
= (IP6_FRAGMENT_HEADER
*) (ExtHdrs
+ Offset
);
442 if (FragmentHead
== NULL
) {
446 FragmentOffset
= NTOHS (FragmentHead
->FragmentOffset
);
448 if (((FragmentOffset
& 0x1) == 0x1) &&
449 !IP6_IS_MULTICAST (&Packet
->Ip
.Ip6
->DestinationAddress
)) {
450 Pointer
= sizeof (UINT32
);
455 &Packet
->Ip
.Ip6
->SourceAddress
,
456 ICMP_V6_PARAMETER_PROBLEM
,
464 if (Fragmented
!= NULL
) {
468 if (Rcvd
&& FormerHeader
!= NULL
) {
469 *FormerHeader
= (UINT32
) (NextHeader
- ExtHdrs
);
472 NextHeader
= ExtHdrs
+ Offset
;
481 Option
= ExtHdrs
+ Offset
;
485 // RFC2402, Payload length is specified in 32-bit words, minus "2".
487 OptionLen
= (UINT8
) ((*Option
+ 2) * 4);
488 Offset
= Offset
+ OptionLen
;
491 case IP6_NO_NEXT_HEADER
:
492 *LastHeader
= NextHeader
;
497 if (Ip6IsValidProtocol (IpSb
, *NextHeader
)) {
499 *LastHeader
= NextHeader
;
501 if (RealExtsLen
!= NULL
) {
502 *RealExtsLen
= Offset
;
509 // The Next Header value is unrecognized by the node, discard the packet and
510 // send an ICMP parameter problem message with code value of 1.
514 // The Next Header directly follows IPv6 basic header.
519 Pointer
= sizeof (EFI_IP6_HEADER
);
521 Pointer
= Offset
+ sizeof (EFI_IP6_HEADER
);
525 if ((IpSb
!= NULL
) && (Packet
!= NULL
) &&
526 !IP6_IS_MULTICAST (&Packet
->Ip
.Ip6
->DestinationAddress
)) {
531 &Packet
->Ip
.Ip6
->SourceAddress
,
532 ICMP_V6_PARAMETER_PROBLEM
,
541 *LastHeader
= NextHeader
;
543 if (RealExtsLen
!= NULL
) {
544 *RealExtsLen
= Offset
;
551 Generate an IPv6 router alert option in network order and output it through Buffer.
553 @param[out] Buffer Points to a buffer to record the generated option.
554 @param[in, out] BufferLen The length of Buffer, in bytes.
555 @param[in] NextHeader The 8-bit selector indicates the type of header
556 immediately following the Hop-by-Hop Options header.
558 @retval EFI_BUFFER_TOO_SMALL The Buffer is too small to contain the generated
559 option. BufferLen is updated for the required size.
561 @retval EFI_SUCCESS The option is generated and filled in to Buffer.
567 IN OUT UINTN
*BufferLen
,
571 UINT8 BufferArray
[8];
573 if (*BufferLen
< 8) {
575 return EFI_BUFFER_TOO_SMALL
;
579 // Form the Hop-By-Hop option in network order.
580 // NextHeader (1 octet) + HdrExtLen (1 octet) + RouterAlertOption(4 octets) + PadN
581 // The Hdr Ext Len is the length in 8-octet units, and does not including the first 8 octets.
583 ZeroMem (BufferArray
, sizeof (BufferArray
));
584 BufferArray
[0] = NextHeader
;
585 BufferArray
[2] = 0x5;
586 BufferArray
[3] = 0x2;
589 CopyMem (Buffer
, BufferArray
, sizeof (BufferArray
));
594 Insert a Fragment Header to the Extension headers and output it in UpdatedExtHdrs.
596 @param[in] IpSb The IP6 service instance to transmit the packet.
597 @param[in] NextHeader The extension header type of first extension header.
598 @param[in] LastHeader The extension header type of last extension header.
599 @param[in] ExtHdrs The length of the original extension header.
600 @param[in] ExtHdrsLen The length of the extension headers.
601 @param[in] FragmentOffset The fragment offset of the data following the header.
602 @param[out] UpdatedExtHdrs The updated ExtHdrs with Fragment header inserted.
603 It's caller's responsibility to free this buffer.
605 @retval EFI_OUT_OF_RESOURCES Failed to finish the operation due to lake of
607 @retval EFI_UNSUPPORTED The extension header specified in ExtHdrs is not
609 @retval EFI_SUCCESS The operation performed successfully.
613 Ip6FillFragmentHeader (
614 IN IP6_SERVICE
*IpSb
,
618 IN UINT32 ExtHdrsLen
,
619 IN UINT16 FragmentOffset
,
620 OUT UINT8
**UpdatedExtHdrs
630 IP6_FRAGMENT_HEADER FragmentHead
;
632 if (UpdatedExtHdrs
== NULL
) {
633 return EFI_INVALID_PARAMETER
;
636 Length
= ExtHdrsLen
+ sizeof (IP6_FRAGMENT_HEADER
);
637 Buffer
= AllocatePool (Length
);
638 if (Buffer
== NULL
) {
639 return EFI_OUT_OF_RESOURCES
;
645 Current
= NextHeader
;
647 while ((ExtHdrs
!= NULL
) && (Offset
<= ExtHdrsLen
)) {
648 switch (NextHeader
) {
651 case IP6_DESTINATION
:
652 Current
= NextHeader
;
653 NextHeader
= *(ExtHdrs
+ Offset
);
655 if ((Current
== IP6_DESTINATION
) && (NextHeader
!= IP6_ROUTING
)) {
657 // Destination Options header should occur at most twice, once before
658 // a Routing header and once before the upper-layer header. Here we
659 // find the one before the upper-layer header. Insert the Fragment
662 CopyMem (Buffer
, ExtHdrs
, Part1Len
);
663 *(Buffer
+ FormerHeader
) = IP6_FRAGMENT
;
667 Offset
= ExtHdrsLen
+ 1;
672 FormerHeader
= Offset
;
673 HeaderLen
= (*(ExtHdrs
+ Offset
+ 1) + 1) * 8;
674 Part1Len
= Part1Len
+ HeaderLen
;
675 Offset
= Offset
+ HeaderLen
;
679 Current
= NextHeader
;
682 CopyMem (Buffer
, ExtHdrs
, Part1Len
);
685 *(Buffer
+ FormerHeader
) = IP6_FRAGMENT
;
690 Offset
= ExtHdrsLen
+ 1;
694 Current
= NextHeader
;
695 NextHeader
= *(ExtHdrs
+ Offset
);
697 // RFC2402, Payload length is specified in 32-bit words, minus "2".
699 HeaderLen
= (*(ExtHdrs
+ Offset
+ 1) + 2) * 4;
700 Part1Len
= Part1Len
+ HeaderLen
;
701 Offset
= Offset
+ HeaderLen
;
705 if (Ip6IsValidProtocol (IpSb
, NextHeader
)) {
706 Current
= NextHeader
;
707 CopyMem (Buffer
, ExtHdrs
, Part1Len
);
708 *(Buffer
+ FormerHeader
) = IP6_FRAGMENT
;
712 Offset
= ExtHdrsLen
+ 1;
717 return EFI_UNSUPPORTED
;
722 // Append the Fragment header. If the fragment offset indicates the fragment
723 // is the first fragment.
725 if ((FragmentOffset
& IP6_FRAGMENT_OFFSET_MASK
) == 0) {
726 FragmentHead
.NextHeader
= Current
;
728 FragmentHead
.NextHeader
= LastHeader
;
731 FragmentHead
.Reserved
= 0;
732 FragmentHead
.FragmentOffset
= HTONS (FragmentOffset
);
733 FragmentHead
.Identification
= mIp6Id
;
735 CopyMem (Buffer
+ Part1Len
, &FragmentHead
, sizeof (IP6_FRAGMENT_HEADER
));
737 if ((ExtHdrs
!= NULL
) && (Part1Len
< ExtHdrsLen
)) {
739 // Append the part2 (fragmentable part) of Extension headers
742 Buffer
+ Part1Len
+ sizeof (IP6_FRAGMENT_HEADER
),
744 ExtHdrsLen
- Part1Len
748 *UpdatedExtHdrs
= Buffer
;