VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/NetworkPkg/Ip6Dxe/Ip6Option.c

Last change on this file was 105670, checked in by vboxsync, 5 months ago

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

  • Property svn:eol-style set to native
File size: 23.6 KB
Line 
1/** @file
2 IP6 option support functions and routines.
3
4 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8**/
9
10#include "Ip6Impl.h"
11
12/**
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.
16
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 all options, expressed in byte length of octets.
21 Maximum length is 2046 bytes or ((n + 1) * 8) - 2 where n is 255.
22 @param[in] Pointer Identifies the octet offset within
23 the invoking packet where the error was detected.
24
25
26 @retval TRUE The option is properly formatted.
27 @retval FALSE The option is malformatted.
28
29**/
30BOOLEAN
31Ip6IsOptionValid (
32 IN IP6_SERVICE *IpSb,
33 IN NET_BUF *Packet,
34 IN UINT8 *Option,
35 IN UINT16 OptionLen,
36 IN UINT32 Pointer
37 )
38{
39 UINT16 Offset;
40 UINT8 OptionType;
41 UINT8 OptDataLen;
42
43 if (Option == NULL) {
44 ASSERT (Option != NULL);
45 return FALSE;
46 }
47
48 if ((OptionLen <= 0) || (OptionLen > IP6_MAX_EXT_DATA_LENGTH)) {
49 ASSERT (OptionLen > 0 && OptionLen <= IP6_MAX_EXT_DATA_LENGTH);
50 return FALSE;
51 }
52
53 if (Packet == NULL) {
54 ASSERT (Packet != NULL);
55 return FALSE;
56 }
57
58 if (IpSb == NULL) {
59 ASSERT (IpSb != NULL);
60 return FALSE;
61 }
62
63 Offset = 0;
64
65 while (Offset < OptionLen) {
66 OptionType = *(Option + Offset);
67
68 switch (OptionType) {
69 case Ip6OptionPad1:
70 //
71 // It is a Pad1 option
72 //
73 Offset++;
74 break;
75 case Ip6OptionPadN:
76 //
77 // It is a PadN option
78 //
79 OptDataLen = ((IP6_OPTION_HEADER *)(Option + Offset))->Length;
80 Offset = IP6_NEXT_OPTION_OFFSET (Offset, OptDataLen);
81 break;
82 case Ip6OptionRouterAlert:
83 //
84 // It is a Router Alert Option
85 //
86 Offset += 4;
87 break;
88 default:
89 //
90 // The highest-order two bits specify the action must be taken if
91 // the processing IPv6 node does not recognize the option type.
92 //
93 switch (OptionType & Ip6OptionMask) {
94 case Ip6OptionSkip:
95 OptDataLen = ((IP6_OPTION_HEADER *)(Option + Offset))->Length;
96 Offset = IP6_NEXT_OPTION_OFFSET (Offset, OptDataLen);
97 break;
98 case Ip6OptionDiscard:
99 return FALSE;
100 case Ip6OptionParameterProblem:
101 Pointer = Pointer + Offset + sizeof (EFI_IP6_HEADER);
102 Ip6SendIcmpError (
103 IpSb,
104 Packet,
105 NULL,
106 &Packet->Ip.Ip6->SourceAddress,
107 ICMP_V6_PARAMETER_PROBLEM,
108 2,
109 &Pointer
110 );
111 return FALSE;
112 case Ip6OptionMask:
113 if (!IP6_IS_MULTICAST (&Packet->Ip.Ip6->DestinationAddress)) {
114 Pointer = Pointer + Offset + sizeof (EFI_IP6_HEADER);
115 Ip6SendIcmpError (
116 IpSb,
117 Packet,
118 NULL,
119 &Packet->Ip.Ip6->SourceAddress,
120 ICMP_V6_PARAMETER_PROBLEM,
121 2,
122 &Pointer
123 );
124 }
125
126 return FALSE;
127 break;
128 }
129
130 break;
131 }
132 }
133
134 return TRUE;
135}
136
137/**
138 Validate the IP6 option format for both the packets we received
139 and that we will transmit. It supports the defined options in Neighbor
140 Discovery messages.
141
142 @param[in] Option The first byte of the option.
143 @param[in] OptionLen The length of the whole option.
144
145 @retval TRUE The option is properly formatted.
146 @retval FALSE The option is malformatted.
147
148**/
149BOOLEAN
150Ip6IsNDOptionValid (
151 IN UINT8 *Option,
152 IN UINT16 OptionLen
153 )
154{
155 UINT32 Offset;
156 UINT16 Length;
157 IP6_OPTION_HEADER *OptionHeader;
158
159 if (Option == NULL) {
160 ASSERT (Option != NULL);
161 return FALSE;
162 }
163
164 //
165 // Cannot process truncated options.
166 // Cannot process options with a length of 0 as there is no Type field.
167 //
168 if (OptionLen < sizeof (IP6_OPTION_HEADER)) {
169 return FALSE;
170 }
171
172 Offset = 0;
173
174 //
175 // RFC 4861 states that Neighbor Discovery packet can contain zero or more
176 // options. Start processing the options if at least Type + Length fields
177 // fit within the input buffer.
178 //
179 while (Offset + sizeof (IP6_OPTION_HEADER) - 1 < OptionLen) {
180 OptionHeader = (IP6_OPTION_HEADER *)(Option + Offset);
181 Length = (UINT16)OptionHeader->Length * 8;
182
183 switch (OptionHeader->Type) {
184 case Ip6OptionPrefixInfo:
185 if (Length != 32) {
186 return FALSE;
187 }
188
189 break;
190
191 case Ip6OptionMtu:
192 if (Length != 8) {
193 return FALSE;
194 }
195
196 break;
197
198 default:
199 // RFC 4861 states that Length field cannot be 0.
200 if (Length == 0) {
201 return FALSE;
202 }
203
204 break;
205 }
206
207 //
208 // Check whether recognized options are within the input buffer's scope.
209 //
210 switch (OptionHeader->Type) {
211 case Ip6OptionEtherSource:
212 case Ip6OptionEtherTarget:
213 case Ip6OptionPrefixInfo:
214 case Ip6OptionRedirected:
215 case Ip6OptionMtu:
216 if (Offset + Length > (UINT32)OptionLen) {
217 return FALSE;
218 }
219
220 break;
221
222 default:
223 //
224 // Unrecognized options can be either valid (but unused) or invalid
225 // (garbage in between or right after valid options). Silently ignore.
226 //
227 break;
228 }
229
230 //
231 // Advance to the next option.
232 // Length already considers option header's Type + Length.
233 //
234 Offset += Length;
235 }
236
237 return TRUE;
238}
239
240/**
241 Validate whether the NextHeader is a known valid protocol or one of the user configured
242 protocols from the upper layer.
243
244 @param[in] IpSb The IP6 service instance.
245 @param[in] NextHeader The next header field.
246
247 @retval TRUE The NextHeader is a known valid protocol or user configured.
248 @retval FALSE The NextHeader is not a known valid protocol.
249
250**/
251BOOLEAN
252Ip6IsValidProtocol (
253 IN IP6_SERVICE *IpSb,
254 IN UINT8 NextHeader
255 )
256{
257 LIST_ENTRY *Entry;
258 IP6_PROTOCOL *IpInstance;
259
260 if ((NextHeader == EFI_IP_PROTO_TCP) ||
261 (NextHeader == EFI_IP_PROTO_UDP) ||
262 (NextHeader == IP6_ICMP) ||
263 (NextHeader == IP6_ESP)
264 )
265 {
266 return TRUE;
267 }
268
269 if (IpSb == NULL) {
270 return FALSE;
271 }
272
273 if (IpSb->Signature != IP6_SERVICE_SIGNATURE) {
274 return FALSE;
275 }
276
277 NET_LIST_FOR_EACH (Entry, &IpSb->Children) {
278 IpInstance = NET_LIST_USER_STRUCT_S (Entry, IP6_PROTOCOL, Link, IP6_PROTOCOL_SIGNATURE);
279 if (IpInstance->State == IP6_STATE_CONFIGED) {
280 if (IpInstance->ConfigData.DefaultProtocol == NextHeader) {
281 return TRUE;
282 }
283 }
284 }
285
286 return FALSE;
287}
288
289/**
290 Validate the IP6 extension header format for both the packets we received
291 and that we will transmit. It will compute the ICMPv6 error message fields
292 if the option is mal-formatted.
293
294 @param[in] IpSb The IP6 service instance. This is an optional parameter.
295 @param[in] Packet The data of the packet. Ignored if NULL.
296 @param[in] NextHeader The next header field in IPv6 basic header.
297 @param[in] ExtHdrs The first byte of the option.
298 @param[in] ExtHdrsLen The length of the whole option.
299 @param[in] Rcvd The option is from the packet we received if TRUE,
300 otherwise, the option we want to transmit.
301 @param[out] FormerHeader The offset of NextHeader which points to Fragment
302 Header when we received, of the ExtHdrs.
303 Ignored if we transmit.
304 @param[out] LastHeader The pointer of NextHeader of the last extension
305 header processed by IP6.
306 @param[out] RealExtsLen The length of extension headers processed by IP6 layer.
307 This is an optional parameter that may be NULL.
308 @param[out] UnFragmentLen The length of unfragmented length of extension headers.
309 This is an optional parameter that may be NULL.
310 @param[out] Fragmented Indicate whether the packet is fragmented.
311 This is an optional parameter that may be NULL.
312
313 @retval TRUE The option is properly formatted.
314 @retval FALSE The option is malformatted.
315
316**/
317BOOLEAN
318Ip6IsExtsValid (
319 IN IP6_SERVICE *IpSb OPTIONAL,
320 IN NET_BUF *Packet OPTIONAL,
321 IN UINT8 *NextHeader,
322 IN UINT8 *ExtHdrs,
323 IN UINT32 ExtHdrsLen,
324 IN BOOLEAN Rcvd,
325 OUT UINT32 *FormerHeader OPTIONAL,
326 OUT UINT8 **LastHeader,
327 OUT UINT32 *RealExtsLen OPTIONAL,
328 OUT UINT32 *UnFragmentLen OPTIONAL,
329 OUT BOOLEAN *Fragmented OPTIONAL
330 )
331{
332 UINT32 Pointer;
333 UINT32 Offset;
334 UINT8 *Option;
335 UINT16 OptionLen;
336 BOOLEAN Flag;
337 UINT8 CountD;
338 UINT8 CountA;
339 IP6_FRAGMENT_HEADER *FragmentHead;
340 UINT16 FragmentOffset;
341 IP6_ROUTING_HEADER *RoutingHead;
342
343 if (RealExtsLen != NULL) {
344 *RealExtsLen = 0;
345 }
346
347 if (UnFragmentLen != NULL) {
348 *UnFragmentLen = 0;
349 }
350
351 if (Fragmented != NULL) {
352 *Fragmented = FALSE;
353 }
354
355 *LastHeader = NextHeader;
356
357 if ((ExtHdrs == NULL) && (ExtHdrsLen == 0)) {
358 return TRUE;
359 }
360
361 if (((ExtHdrs == NULL) && (ExtHdrsLen != 0)) || ((ExtHdrs != NULL) && (ExtHdrsLen == 0))) {
362 return FALSE;
363 }
364
365 Pointer = 0;
366 Offset = 0;
367 Flag = FALSE;
368 CountD = 0;
369 CountA = 0;
370
371 while (Offset <= ExtHdrsLen) {
372 switch (*NextHeader) {
373 case IP6_HOP_BY_HOP:
374 if (Offset != 0) {
375 if (!Rcvd) {
376 return FALSE;
377 }
378
379 //
380 // Hop-by-Hop Options header is restricted to appear immediately after an IPv6 header only.
381 // If not, generate a ICMP parameter problem message with code value of 1.
382 //
383 if (Pointer == 0) {
384 Pointer = sizeof (EFI_IP6_HEADER);
385 } else {
386 Pointer = Offset + sizeof (EFI_IP6_HEADER);
387 }
388
389 if ((IpSb != NULL) && (Packet != NULL) &&
390 !IP6_IS_MULTICAST (&Packet->Ip.Ip6->DestinationAddress))
391 {
392 Ip6SendIcmpError (
393 IpSb,
394 Packet,
395 NULL,
396 &Packet->Ip.Ip6->SourceAddress,
397 ICMP_V6_PARAMETER_PROBLEM,
398 1,
399 &Pointer
400 );
401 }
402
403 return FALSE;
404 }
405
406 Flag = TRUE;
407
408 //
409 // Fall through
410 //
411 case IP6_DESTINATION:
412 //
413 // See https://www.rfc-editor.org/rfc/rfc2460#section-4.2 page 23
414 //
415 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
416 // | Next Header | Hdr Ext Len | |
417 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +
418 // | |
419 // . .
420 // . Options .
421 // . .
422 // | |
423 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
424 //
425 //
426 // Next Header 8-bit selector. Identifies the type of header
427 // immediately following the Destination Options
428 // header. Uses the same values as the IPv4
429 // Protocol field [RFC-1700 et seq.].
430 //
431 // Hdr Ext Len 8-bit unsigned integer. Length of the
432 // Destination Options header in 8-octet units, not
433 // including the first 8 octets.
434 //
435 // Options Variable-length field, of length such that the
436 // complete Destination Options header is an
437 // integer multiple of 8 octets long. Contains one
438 // or more TLV-encoded options, as described in
439 // section 4.2.
440 //
441
442 if (*NextHeader == IP6_DESTINATION) {
443 CountD++;
444 }
445
446 if (CountD > 2) {
447 return FALSE;
448 }
449
450 NextHeader = ExtHdrs + Offset;
451 Pointer = Offset;
452
453 Offset++;
454 Option = ExtHdrs + Offset;
455 OptionLen = IP6_HDR_EXT_LEN (*Option) - sizeof (IP6_EXT_HDR);
456 Option++;
457 Offset++;
458
459 if ((IpSb != NULL) && (Packet != NULL) && !Ip6IsOptionValid (IpSb, Packet, Option, OptionLen, Offset)) {
460 return FALSE;
461 }
462
463 Offset = Offset + OptionLen;
464
465 if (Flag) {
466 if (UnFragmentLen != NULL) {
467 *UnFragmentLen = Offset;
468 }
469
470 Flag = FALSE;
471 }
472
473 break;
474
475 case IP6_ROUTING:
476 NextHeader = ExtHdrs + Offset;
477 RoutingHead = (IP6_ROUTING_HEADER *)NextHeader;
478
479 //
480 // Type 0 routing header is defined in RFC2460 and deprecated in RFC5095.
481 // Thus all routing types are processed as unrecognized.
482 //
483 if (RoutingHead->SegmentsLeft == 0) {
484 //
485 // Ignore the routing header and proceed to process the next header.
486 //
487 Offset = Offset + IP6_HDR_EXT_LEN (RoutingHead->HeaderLen);
488
489 if (UnFragmentLen != NULL) {
490 *UnFragmentLen = Offset;
491 }
492 } else {
493 //
494 // Discard the packet and send an ICMP Parameter Problem, Code 0, message
495 // to the packet's source address, pointing to the unrecognized routing
496 // type.
497 //
498 Pointer = Offset + sizeof (IP6_EXT_HDR) + sizeof (EFI_IP6_HEADER);
499 if ((IpSb != NULL) && (Packet != NULL) &&
500 !IP6_IS_MULTICAST (&Packet->Ip.Ip6->DestinationAddress))
501 {
502 Ip6SendIcmpError (
503 IpSb,
504 Packet,
505 NULL,
506 &Packet->Ip.Ip6->SourceAddress,
507 ICMP_V6_PARAMETER_PROBLEM,
508 0,
509 &Pointer
510 );
511 }
512
513 return FALSE;
514 }
515
516 break;
517
518 case IP6_FRAGMENT:
519
520 //
521 // RFC2402, AH header should after fragment header.
522 //
523 if (CountA > 1) {
524 return FALSE;
525 }
526
527 //
528 // RFC2460, ICMP Parameter Problem message with code 0 should be sent
529 // if the length of a fragment is not a multiple of 8 octets and the M
530 // flag of that fragment is 1, pointing to the Payload length field of the
531 // fragment packet.
532 //
533 if ((IpSb != NULL) && (Packet != NULL) && ((ExtHdrsLen % 8) != 0)) {
534 //
535 // Check whether it is the last fragment.
536 //
537 FragmentHead = (IP6_FRAGMENT_HEADER *)(ExtHdrs + Offset);
538 if (FragmentHead == NULL) {
539 return FALSE;
540 }
541
542 FragmentOffset = NTOHS (FragmentHead->FragmentOffset);
543
544 if (((FragmentOffset & 0x1) == 0x1) &&
545 !IP6_IS_MULTICAST (&Packet->Ip.Ip6->DestinationAddress))
546 {
547 Pointer = sizeof (UINT32);
548 Ip6SendIcmpError (
549 IpSb,
550 Packet,
551 NULL,
552 &Packet->Ip.Ip6->SourceAddress,
553 ICMP_V6_PARAMETER_PROBLEM,
554 0,
555 &Pointer
556 );
557 return FALSE;
558 }
559 }
560
561 if (Fragmented != NULL) {
562 *Fragmented = TRUE;
563 }
564
565 if (Rcvd && (FormerHeader != NULL)) {
566 *FormerHeader = (UINT32)(NextHeader - ExtHdrs);
567 }
568
569 NextHeader = ExtHdrs + Offset;
570 Offset = Offset + 8;
571 break;
572
573 case IP6_AH:
574 if (++CountA > 1) {
575 return FALSE;
576 }
577
578 Option = ExtHdrs + Offset;
579 NextHeader = Option;
580 Option++;
581 //
582 // RFC2402, Payload length is specified in 32-bit words, minus "2".
583 //
584 OptionLen = ((UINT16)(*Option + 2) * 4);
585 Offset = Offset + OptionLen;
586 break;
587
588 case IP6_NO_NEXT_HEADER:
589 *LastHeader = NextHeader;
590 return FALSE;
591 break;
592
593 default:
594 if (Ip6IsValidProtocol (IpSb, *NextHeader)) {
595 *LastHeader = NextHeader;
596
597 if (RealExtsLen != NULL) {
598 *RealExtsLen = Offset;
599 }
600
601 return TRUE;
602 }
603
604 //
605 // The Next Header value is unrecognized by the node, discard the packet and
606 // send an ICMP parameter problem message with code value of 1.
607 //
608 if (Offset == 0) {
609 //
610 // The Next Header directly follows IPv6 basic header.
611 //
612 Pointer = 6;
613 } else {
614 if (Pointer == 0) {
615 Pointer = sizeof (EFI_IP6_HEADER);
616 } else {
617 Pointer = Offset + sizeof (EFI_IP6_HEADER);
618 }
619 }
620
621 if ((IpSb != NULL) && (Packet != NULL) &&
622 !IP6_IS_MULTICAST (&Packet->Ip.Ip6->DestinationAddress))
623 {
624 Ip6SendIcmpError (
625 IpSb,
626 Packet,
627 NULL,
628 &Packet->Ip.Ip6->SourceAddress,
629 ICMP_V6_PARAMETER_PROBLEM,
630 1,
631 &Pointer
632 );
633 }
634
635 return FALSE;
636 }
637 }
638
639 *LastHeader = NextHeader;
640
641 if (RealExtsLen != NULL) {
642 *RealExtsLen = Offset;
643 }
644
645 return TRUE;
646}
647
648/**
649 Generate an IPv6 router alert option in network order and output it through Buffer.
650
651 @param[out] Buffer Points to a buffer to record the generated option.
652 @param[in, out] BufferLen The length of Buffer, in bytes.
653 @param[in] NextHeader The 8-bit selector indicates the type of header
654 immediately following the Hop-by-Hop Options header.
655
656 @retval EFI_BUFFER_TOO_SMALL The Buffer is too small to contain the generated
657 option. BufferLen is updated for the required size.
658
659 @retval EFI_SUCCESS The option is generated and filled in to Buffer.
660
661**/
662EFI_STATUS
663Ip6FillHopByHop (
664 OUT UINT8 *Buffer,
665 IN OUT UINTN *BufferLen,
666 IN UINT8 NextHeader
667 )
668{
669 UINT8 BufferArray[8];
670
671 if (*BufferLen < 8) {
672 *BufferLen = 8;
673 return EFI_BUFFER_TOO_SMALL;
674 }
675
676 //
677 // Form the Hop-By-Hop option in network order.
678 // NextHeader (1 octet) + HdrExtLen (1 octet) + RouterAlertOption(4 octets) + PadN
679 // The Hdr Ext Len is the length in 8-octet units, and does not including the first 8 octets.
680 //
681 ZeroMem (BufferArray, sizeof (BufferArray));
682 BufferArray[0] = NextHeader;
683 BufferArray[2] = 0x5;
684 BufferArray[3] = 0x2;
685 BufferArray[6] = 1;
686
687 CopyMem (Buffer, BufferArray, sizeof (BufferArray));
688 return EFI_SUCCESS;
689}
690
691/**
692 Insert a Fragment Header to the Extension headers and output it in UpdatedExtHdrs.
693
694 @param[in] IpSb The IP6 service instance to transmit the packet.
695 @param[in] NextHeader The extension header type of first extension header.
696 @param[in] LastHeader The extension header type of last extension header.
697 @param[in] ExtHdrs The length of the original extension header.
698 @param[in] ExtHdrsLen The length of the extension headers.
699 @param[in] FragmentOffset The fragment offset of the data following the header.
700 @param[out] UpdatedExtHdrs The updated ExtHdrs with Fragment header inserted.
701 It's caller's responsibility to free this buffer.
702
703 @retval EFI_OUT_OF_RESOURCES Failed to finish the operation due to lake of
704 resource.
705 @retval EFI_UNSUPPORTED The extension header specified in ExtHdrs is not
706 supported currently.
707 @retval EFI_SUCCESS The operation performed successfully.
708
709**/
710EFI_STATUS
711Ip6FillFragmentHeader (
712 IN IP6_SERVICE *IpSb,
713 IN UINT8 NextHeader,
714 IN UINT8 LastHeader,
715 IN UINT8 *ExtHdrs,
716 IN UINT32 ExtHdrsLen,
717 IN UINT16 FragmentOffset,
718 OUT UINT8 **UpdatedExtHdrs
719 )
720{
721 UINT32 Length;
722 UINT8 *Buffer;
723 UINT32 FormerHeader;
724 UINT32 Offset;
725 UINT32 Part1Len;
726 UINT32 HeaderLen;
727 UINT8 Current;
728 IP6_FRAGMENT_HEADER FragmentHead;
729
730 if (UpdatedExtHdrs == NULL) {
731 return EFI_INVALID_PARAMETER;
732 }
733
734 Length = ExtHdrsLen + sizeof (IP6_FRAGMENT_HEADER);
735 Buffer = AllocatePool (Length);
736 if (Buffer == NULL) {
737 return EFI_OUT_OF_RESOURCES;
738 }
739
740 Offset = 0;
741 Part1Len = 0;
742 FormerHeader = 0;
743 Current = NextHeader;
744
745 while ((ExtHdrs != NULL) && (Offset <= ExtHdrsLen)) {
746 switch (NextHeader) {
747 case IP6_ROUTING:
748 case IP6_HOP_BY_HOP:
749 case IP6_DESTINATION:
750 Current = NextHeader;
751 NextHeader = *(ExtHdrs + Offset);
752
753 if ((Current == IP6_DESTINATION) && (NextHeader != IP6_ROUTING)) {
754 //
755 // Destination Options header should occur at most twice, once before
756 // a Routing header and once before the upper-layer header. Here we
757 // find the one before the upper-layer header. Insert the Fragment
758 // Header before it.
759 //
760 CopyMem (Buffer, ExtHdrs, Part1Len);
761 *(Buffer + FormerHeader) = IP6_FRAGMENT;
762 //
763 // Exit the loop.
764 //
765 Offset = ExtHdrsLen + 1;
766 break;
767 }
768
769 FormerHeader = Offset;
770 HeaderLen = (*(ExtHdrs + Offset + 1) + 1) * 8;
771 Part1Len = Part1Len + HeaderLen;
772 Offset = Offset + HeaderLen;
773 break;
774
775 case IP6_FRAGMENT:
776 Current = NextHeader;
777
778 if (Part1Len != 0) {
779 CopyMem (Buffer, ExtHdrs, Part1Len);
780 }
781
782 *(Buffer + FormerHeader) = IP6_FRAGMENT;
783
784 //
785 // Exit the loop.
786 //
787 Offset = ExtHdrsLen + 1;
788 break;
789
790 case IP6_AH:
791 Current = NextHeader;
792 NextHeader = *(ExtHdrs + Offset);
793 //
794 // RFC2402, Payload length is specified in 32-bit words, minus "2".
795 //
796 HeaderLen = (*(ExtHdrs + Offset + 1) + 2) * 4;
797 Part1Len = Part1Len + HeaderLen;
798 Offset = Offset + HeaderLen;
799 break;
800
801 default:
802 if (Ip6IsValidProtocol (IpSb, NextHeader)) {
803 Current = NextHeader;
804 CopyMem (Buffer, ExtHdrs, Part1Len);
805 *(Buffer + FormerHeader) = IP6_FRAGMENT;
806 //
807 // Exit the loop.
808 //
809 Offset = ExtHdrsLen + 1;
810 break;
811 }
812
813 FreePool (Buffer);
814 return EFI_UNSUPPORTED;
815 }
816 }
817
818 //
819 // Append the Fragment header. If the fragment offset indicates the fragment
820 // is the first fragment.
821 //
822 if ((FragmentOffset & IP6_FRAGMENT_OFFSET_MASK) == 0) {
823 FragmentHead.NextHeader = Current;
824 } else {
825 FragmentHead.NextHeader = LastHeader;
826 }
827
828 FragmentHead.Reserved = 0;
829 FragmentHead.FragmentOffset = HTONS (FragmentOffset);
830 FragmentHead.Identification = mIp6Id;
831
832 CopyMem (Buffer + Part1Len, &FragmentHead, sizeof (IP6_FRAGMENT_HEADER));
833
834 if ((ExtHdrs != NULL) && (Part1Len < ExtHdrsLen)) {
835 //
836 // Append the part2 (fragmentable part) of Extension headers
837 //
838 CopyMem (
839 Buffer + Part1Len + sizeof (IP6_FRAGMENT_HEADER),
840 ExtHdrs + Part1Len,
841 ExtHdrsLen - Part1Len
842 );
843 }
844
845 *UpdatedExtHdrs = Buffer;
846
847 return EFI_SUCCESS;
848}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette