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