VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/NetworkPkg/Ip6Dxe/Ip6Output.c@ 80721

Last change on this file since 80721 was 80721, checked in by vboxsync, 5 years ago

Devices/EFI/FirmwareNew: Start upgrade process to edk2-stable201908 (compiles on Windows and works to some extent), bugref:4643

  • Property svn:eol-style set to native
File size: 31.0 KB
Line 
1/** @file
2 The internal functions and routines to transmit the IP6 packet.
3
4 Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8**/
9
10#include "Ip6Impl.h"
11
12UINT32 mIp6Id;
13
14/**
15 Output all the available source addresses to a list entry head SourceList. The
16 number of source addresses are also returned.
17
18 @param[in] IpSb Points to an IP6 service binding instance.
19 @param[out] SourceList The list entry head of all source addresses.
20 It is the caller's responsibility to free the
21 resources.
22 @param[out] SourceCount The number of source addresses.
23
24 @retval EFI_SUCCESS The source addresses were copied to a list entry head
25 SourceList.
26 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to complete the operation.
27
28**/
29EFI_STATUS
30Ip6CandidateSource (
31 IN IP6_SERVICE *IpSb,
32 OUT LIST_ENTRY *SourceList,
33 OUT UINT32 *SourceCount
34 )
35{
36 IP6_INTERFACE *IpIf;
37 LIST_ENTRY *Entry;
38 LIST_ENTRY *Entry2;
39 IP6_ADDRESS_INFO *AddrInfo;
40 IP6_ADDRESS_INFO *Copy;
41
42 *SourceCount = 0;
43
44 if (IpSb->LinkLocalOk) {
45 Copy = AllocatePool (sizeof (IP6_ADDRESS_INFO));
46 if (Copy == NULL) {
47 return EFI_OUT_OF_RESOURCES;
48 }
49
50 Copy->Signature = IP6_ADDR_INFO_SIGNATURE;
51 IP6_COPY_ADDRESS (&Copy->Address, &IpSb->LinkLocalAddr);
52 Copy->IsAnycast = FALSE;
53 Copy->PrefixLength = IP6_LINK_LOCAL_PREFIX_LENGTH;
54 Copy->ValidLifetime = (UINT32) IP6_INFINIT_LIFETIME;
55 Copy->PreferredLifetime = (UINT32) IP6_INFINIT_LIFETIME;
56
57 InsertTailList (SourceList, &Copy->Link);
58 (*SourceCount)++;
59 }
60
61 NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
62 IpIf = NET_LIST_USER_STRUCT (Entry, IP6_INTERFACE, Link);
63
64 NET_LIST_FOR_EACH (Entry2, &IpIf->AddressList) {
65 AddrInfo = NET_LIST_USER_STRUCT_S (Entry2, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);
66
67 if (AddrInfo->IsAnycast) {
68 //
69 // Never use an anycast address.
70 //
71 continue;
72 }
73
74 Copy = AllocateCopyPool (sizeof (IP6_ADDRESS_INFO), AddrInfo);
75 if (Copy == NULL) {
76 return EFI_OUT_OF_RESOURCES;
77 }
78
79 InsertTailList (SourceList, &Copy->Link);
80 (*SourceCount)++;
81 }
82 }
83
84 return EFI_SUCCESS;
85}
86
87/**
88 Calculate how many bits are the same between two IPv6 addresses.
89
90 @param[in] AddressA Points to an IPv6 address.
91 @param[in] AddressB Points to another IPv6 address.
92
93 @return The common bits of the AddressA and AddressB.
94
95**/
96UINT8
97Ip6CommonPrefixLen (
98 IN EFI_IPv6_ADDRESS *AddressA,
99 IN EFI_IPv6_ADDRESS *AddressB
100 )
101{
102 UINT8 Count;
103 UINT8 Index;
104 UINT8 ByteA;
105 UINT8 ByteB;
106 UINT8 NumBits;
107
108 Count = 0;
109 Index = 0;
110
111 while (Index < 16) {
112 ByteA = AddressA->Addr[Index];
113 ByteB = AddressB->Addr[Index];
114
115 if (ByteA == ByteB) {
116 Count += 8;
117 Index++;
118 continue;
119 }
120
121 //
122 // Check how many bits are common between the two bytes.
123 //
124 NumBits = 8;
125 ByteA = (UINT8) (ByteA ^ ByteB);
126
127 while (ByteA != 0) {
128 NumBits--;
129 ByteA = (UINT8) (ByteA >> 1);
130 }
131
132 return (UINT8) (Count + NumBits);
133 }
134
135 return Count;
136}
137
138/**
139 Output all the available source addresses to a list entry head SourceList. The
140 number of source addresses are also returned.
141
142 @param[in] IpSb Points to a IP6 service binding instance.
143 @param[in] Destination The IPv6 destination address.
144 @param[out] Source The selected IPv6 source address according to
145 the Destination.
146
147 @retval EFI_SUCCESS The source addresses were copied to a list entry
148 head SourceList.
149 @retval EFI_NO_MAPPING The IPv6 stack is not auto configured.
150
151**/
152EFI_STATUS
153Ip6SelectSourceAddress (
154 IN IP6_SERVICE *IpSb,
155 IN EFI_IPv6_ADDRESS *Destination,
156 OUT EFI_IPv6_ADDRESS *Source
157 )
158{
159 EFI_STATUS Status;
160 LIST_ENTRY SourceList;
161 UINT32 SourceCount;
162 UINT8 ScopeD;
163 LIST_ENTRY *Entry;
164 IP6_ADDRESS_INFO *AddrInfo;
165 IP6_PREFIX_LIST_ENTRY *Prefix;
166 UINT8 LastCommonLength;
167 UINT8 CurrentCommonLength;
168 EFI_IPv6_ADDRESS *TmpAddress;
169
170 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
171
172 Status = EFI_SUCCESS;
173 InitializeListHead (&SourceList);
174
175 if (!IpSb->LinkLocalOk) {
176 return EFI_NO_MAPPING;
177 }
178
179 //
180 // Rule 1: Prefer same address.
181 //
182 if (Ip6IsOneOfSetAddress (IpSb, Destination, NULL, NULL)) {
183 IP6_COPY_ADDRESS (Source, Destination);
184 goto Exit;
185 }
186
187 //
188 // Rule 2: Prefer appropriate scope.
189 //
190 if (IP6_IS_MULTICAST (Destination)) {
191 ScopeD = (UINT8) (Destination->Addr[1] >> 4);
192 } else if (NetIp6IsLinkLocalAddr (Destination)) {
193 ScopeD = 0x2;
194 } else {
195 ScopeD = 0xE;
196 }
197
198 if (ScopeD <= 0x2) {
199 //
200 // Return the link-local address if it exists
201 // One IP6_SERVICE only has one link-local address.
202 //
203 IP6_COPY_ADDRESS (Source, &IpSb->LinkLocalAddr);
204 goto Exit;
205 }
206
207 //
208 // All candidate source addresses are global unicast address.
209 //
210 Ip6CandidateSource (IpSb, &SourceList, &SourceCount);
211
212 if (SourceCount == 0) {
213 Status = EFI_NO_MAPPING;
214 goto Exit;
215 }
216
217 IP6_COPY_ADDRESS (Source, &IpSb->LinkLocalAddr);
218
219 if (SourceCount == 1) {
220 goto Exit;
221 }
222
223 //
224 // Rule 3: Avoid deprecated addresses.
225 // TODO: check the "deprecated" state of the stateful configured address
226 //
227 NET_LIST_FOR_EACH (Entry, &IpSb->AutonomousPrefix) {
228 Prefix = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
229 if (Prefix->PreferredLifetime == 0) {
230 Ip6RemoveAddr (NULL, &SourceList, &SourceCount, &Prefix->Prefix, Prefix->PrefixLength);
231
232 if (SourceCount == 1) {
233 goto Exit;
234 }
235 }
236 }
237
238 //
239 // TODO: Rule 4: Prefer home addresses.
240 // TODO: Rule 5: Prefer outgoing interface.
241 // TODO: Rule 6: Prefer matching label.
242 // TODO: Rule 7: Prefer public addresses.
243 //
244
245 //
246 // Rule 8: Use longest matching prefix.
247 //
248 LastCommonLength = Ip6CommonPrefixLen (Source, Destination);
249 TmpAddress = NULL;
250
251 for (Entry = SourceList.ForwardLink; Entry != &SourceList; Entry = Entry->ForwardLink) {
252 AddrInfo = NET_LIST_USER_STRUCT_S (Entry, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);
253
254 CurrentCommonLength = Ip6CommonPrefixLen (&AddrInfo->Address, Destination);
255 if (CurrentCommonLength > LastCommonLength) {
256 LastCommonLength = CurrentCommonLength;
257 TmpAddress = &AddrInfo->Address;
258 }
259 }
260
261 if (TmpAddress != NULL) {
262 IP6_COPY_ADDRESS (Source, TmpAddress);
263 }
264
265Exit:
266
267 Ip6RemoveAddr (NULL, &SourceList, &SourceCount, NULL, 0);
268
269 return Status;
270}
271
272/**
273 Select an interface to send the packet generated in the IP6 driver
274 itself: that is, not by the requests of the IP6 child's consumer. Such
275 packets include the ICMPv6 echo replies and other ICMPv6 error packets.
276
277 @param[in] IpSb The IP4 service that wants to send the packets.
278 @param[in] Destination The destination of the packet.
279 @param[in, out] Source The source of the packet.
280
281 @return NULL if no proper interface is found, otherwise, the interface that
282 can be used to send the system packet from.
283
284**/
285IP6_INTERFACE *
286Ip6SelectInterface (
287 IN IP6_SERVICE *IpSb,
288 IN EFI_IPv6_ADDRESS *Destination,
289 IN OUT EFI_IPv6_ADDRESS *Source
290 )
291{
292 EFI_STATUS Status;
293 EFI_IPv6_ADDRESS SelectedSource;
294 IP6_INTERFACE *IpIf;
295 BOOLEAN Exist;
296
297 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
298 ASSERT (Destination != NULL && Source != NULL);
299
300 if (NetIp6IsUnspecifiedAddr (Destination)) {
301 return NULL;
302 }
303
304 if (!NetIp6IsUnspecifiedAddr (Source)) {
305 Exist = Ip6IsOneOfSetAddress (IpSb, Source, &IpIf, NULL);
306 ASSERT (Exist);
307
308 return IpIf;
309 }
310
311 //
312 // If source is unspecified, select a source according to the destination.
313 //
314 Status = Ip6SelectSourceAddress (IpSb, Destination, &SelectedSource);
315 if (EFI_ERROR (Status)) {
316 return IpSb->DefaultInterface;
317 }
318
319 Ip6IsOneOfSetAddress (IpSb, &SelectedSource, &IpIf, NULL);
320 IP6_COPY_ADDRESS (Source, &SelectedSource);
321
322 return IpIf;
323}
324
325/**
326 The default callback function for the system generated packet.
327 It will free the packet.
328
329 @param[in] Packet The packet that transmitted.
330 @param[in] IoStatus The result of the transmission, succeeded or failed.
331 @param[in] LinkFlag Not used when transmitted. Check IP6_FRAME_CALLBACK
332 for reference.
333 @param[in] Context The context provided by us.
334
335**/
336VOID
337Ip6SysPacketSent (
338 NET_BUF *Packet,
339 EFI_STATUS IoStatus,
340 UINT32 LinkFlag,
341 VOID *Context
342 )
343{
344 NetbufFree (Packet);
345 Packet = NULL;
346}
347
348/**
349 Prefix an IP6 basic head and unfragmentable extension headers and a fragment header
350 to the Packet. Used for IP6 fragmentation.
351
352 @param[in] IpSb The IP6 service instance to transmit the packet.
353 @param[in] Packet The packet to prefix the IP6 header to.
354 @param[in] Head The caller supplied header.
355 @param[in] FragmentOffset The fragment offset of the data following the header.
356 @param[in] ExtHdrs The length of the original extension header.
357 @param[in] ExtHdrsLen The length of the extension headers.
358 @param[in] LastHeader The pointer of next header of last extension header.
359 @param[in] HeadLen The length of the unfragmented part of the IP6 header.
360
361 @retval EFI_BAD_BUFFER_SIZE There is no enough room in the head space of
362 Packet.
363 @retval EFI_SUCCESS The operation performed successfully.
364
365**/
366EFI_STATUS
367Ip6PrependHead (
368 IN IP6_SERVICE *IpSb,
369 IN NET_BUF *Packet,
370 IN EFI_IP6_HEADER *Head,
371 IN UINT16 FragmentOffset,
372 IN UINT8 *ExtHdrs,
373 IN UINT32 ExtHdrsLen,
374 IN UINT8 LastHeader,
375 IN UINT32 HeadLen
376 )
377{
378 UINT32 Len;
379 UINT32 UnFragExtHdrsLen;
380 EFI_IP6_HEADER *PacketHead;
381 UINT8 *UpdatedExtHdrs;
382 EFI_STATUS Status;
383 UINT8 NextHeader;
384
385 UpdatedExtHdrs = NULL;
386
387 //
388 // HeadLen is the length of the fixed part of the sequences of fragments, i.e.
389 // the unfragment part.
390 //
391 PacketHead = (EFI_IP6_HEADER *) NetbufAllocSpace (Packet, HeadLen, NET_BUF_HEAD);
392 if (PacketHead == NULL) {
393 return EFI_BAD_BUFFER_SIZE;
394 }
395
396 //
397 // Set the head up, convert the host byte order to network byte order
398 //
399 CopyMem (PacketHead, Head, sizeof (EFI_IP6_HEADER));
400 PacketHead->PayloadLength = HTONS ((UINT16) (Packet->TotalSize - sizeof (EFI_IP6_HEADER)));
401 Packet->Ip.Ip6 = PacketHead;
402
403 Len = HeadLen - sizeof (EFI_IP6_HEADER);
404 UnFragExtHdrsLen = Len - sizeof (IP6_FRAGMENT_HEADER);
405
406 if (UnFragExtHdrsLen == 0) {
407 PacketHead->NextHeader = IP6_FRAGMENT;
408 }
409
410 //
411 // Append the extension headers: firstly copy the unfragmentable headers, then append
412 // fragmentation header.
413 //
414 if ((FragmentOffset & IP6_FRAGMENT_OFFSET_MASK) == 0) {
415 NextHeader = Head->NextHeader;
416 } else {
417 NextHeader = PacketHead->NextHeader;
418 }
419
420 Status = Ip6FillFragmentHeader (
421 IpSb,
422 NextHeader,
423 LastHeader,
424 ExtHdrs,
425 ExtHdrsLen,
426 FragmentOffset,
427 &UpdatedExtHdrs
428 );
429 if (EFI_ERROR (Status)) {
430 return Status;
431 }
432
433 CopyMem (
434 (UINT8 *) (PacketHead + 1),
435 UpdatedExtHdrs,
436 UnFragExtHdrsLen + sizeof (IP6_FRAGMENT_HEADER)
437 );
438
439 FreePool (UpdatedExtHdrs);
440 return EFI_SUCCESS;
441}
442
443/**
444 Transmit an IP6 packet. The packet comes either from the IP6
445 child's consumer (IpInstance != NULL) or the IP6 driver itself
446 (IpInstance == NULL). It will route the packet, fragment it,
447 then transmit all the fragments through an interface.
448
449 @param[in] IpSb The IP6 service instance to transmit the packet.
450 @param[in] Interface The IP6 interface to transmit the packet. Ignored
451 if NULL.
452 @param[in] IpInstance The IP6 child that issues the transmission. It is
453 NULL if the packet is from the system.
454 @param[in] Packet The user data to send, excluding the IP header.
455 @param[in] Head The caller supplied header. The caller should set
456 the following header fields: NextHeader, HopLimit,
457 Src, Dest, FlowLabel, PayloadLength. This function
458 will fill in the Ver, TrafficClass.
459 @param[in] ExtHdrs The extension headers to append to the IPv6 basic
460 header.
461 @param[in] ExtHdrsLen The length of the extension headers.
462 @param[in] Callback The callback function to issue when transmission
463 completed.
464 @param[in] Context The opaque context for the callback.
465
466 @retval EFI_INVALID_PARAMETER Any input parameter or the packet is invalid.
467 @retval EFI_NO_MAPPING There is no interface to the destination.
468 @retval EFI_NOT_FOUND There is no route to the destination.
469 @retval EFI_SUCCESS The packet successfully transmitted.
470 @retval EFI_OUT_OF_RESOURCES Failed to finish the operation due to lack of
471 resources.
472 @retval Others Failed to transmit the packet.
473
474**/
475EFI_STATUS
476Ip6Output (
477 IN IP6_SERVICE *IpSb,
478 IN IP6_INTERFACE *Interface OPTIONAL,
479 IN IP6_PROTOCOL *IpInstance OPTIONAL,
480 IN NET_BUF *Packet,
481 IN EFI_IP6_HEADER *Head,
482 IN UINT8 *ExtHdrs,
483 IN UINT32 ExtHdrsLen,
484 IN IP6_FRAME_CALLBACK Callback,
485 IN VOID *Context
486 )
487{
488 IP6_INTERFACE *IpIf;
489 EFI_IPv6_ADDRESS NextHop;
490 IP6_NEIGHBOR_ENTRY *NeighborCache;
491 IP6_ROUTE_CACHE_ENTRY *RouteCache;
492 EFI_STATUS Status;
493 UINT32 Mtu;
494 UINT32 HeadLen;
495 UINT16 FragmentOffset;
496 UINT8 *LastHeader;
497 UINT32 UnFragmentLen;
498 UINT32 UnFragmentHdrsLen;
499 UINT32 FragmentHdrsLen;
500 UINT16 *Checksum;
501 UINT16 PacketChecksum;
502 UINT16 PseudoChecksum;
503 UINT32 Index;
504 UINT32 PacketLen;
505 UINT32 RealExtLen;
506 UINT32 Offset;
507 NET_BUF *TmpPacket;
508 NET_BUF *Fragment;
509 UINT32 Num;
510 UINT8 *Buf;
511 EFI_IP6_HEADER *PacketHead;
512 IP6_ICMP_HEAD *IcmpHead;
513 IP6_TXTOKEN_WRAP *Wrap;
514 IP6_ROUTE_ENTRY *RouteEntry;
515 UINT8 *UpdatedExtHdrs;
516 UINT8 NextHeader;
517 UINT8 LastHeaderBackup;
518 BOOLEAN FragmentHeadInserted;
519 UINT8 *ExtHdrsBackup;
520 UINT8 NextHeaderBackup;
521 EFI_IPv6_ADDRESS Source;
522 EFI_IPv6_ADDRESS Destination;
523
524 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
525
526 //
527 // RFC2460: Each extension header is an integer multiple of 8 octets long,
528 // in order to retain 8-octet alignment for subsequent headers.
529 //
530 if ((ExtHdrsLen & 0x7) != 0) {
531 return EFI_INVALID_PARAMETER;
532 }
533
534 LastHeader = NULL;
535
536 Ip6IsExtsValid (
537 NULL,
538 NULL,
539 &Head->NextHeader,
540 ExtHdrs,
541 ExtHdrsLen,
542 FALSE,
543 NULL,
544 &LastHeader,
545 NULL,
546 NULL,
547 NULL
548 );
549
550 //
551 // Select an interface/source for system packet, application
552 // should select them itself.
553 //
554 IpIf = Interface;
555 if (IpIf == NULL) {
556 //
557 // IpInstance->Interface is NULL when IpInstance is configured with both stationaddress
558 // and destinationaddress is unspecified.
559 //
560 if (IpInstance == NULL || IpInstance->Interface == NULL) {
561 IpIf = Ip6SelectInterface (IpSb, &Head->DestinationAddress, &Head->SourceAddress);
562 if (IpInstance != NULL) {
563 IpInstance->Interface = IpIf;
564 }
565 } else {
566 IpIf = IpInstance->Interface;
567 }
568 }
569
570 if (IpIf == NULL) {
571 return EFI_NO_MAPPING;
572 }
573
574 //
575 // Update the common field in Head here.
576 //
577 Head->Version = 6;
578 Head->TrafficClassL = 0;
579 Head->TrafficClassH = 0;
580
581 Checksum = NULL;
582 NextHeader = *LastHeader;
583
584 switch (NextHeader) {
585 case EFI_IP_PROTO_UDP:
586 Packet->Udp = (EFI_UDP_HEADER *) NetbufGetByte (Packet, 0, NULL);
587 ASSERT (Packet->Udp != NULL);
588 if (Packet->Udp->Checksum == 0) {
589 Checksum = &Packet->Udp->Checksum;
590 }
591 break;
592
593 case EFI_IP_PROTO_TCP:
594 Packet->Tcp = (TCP_HEAD *) NetbufGetByte (Packet, 0, NULL);
595 ASSERT (Packet->Tcp != NULL);
596 if (Packet->Tcp->Checksum == 0) {
597 Checksum = &Packet->Tcp->Checksum;
598 }
599 break;
600
601 case IP6_ICMP:
602 //
603 // Don't send ICMP packet to an IPv6 anycast address.
604 //
605 if (Ip6IsAnycast (IpSb, &Head->DestinationAddress)) {
606 return EFI_INVALID_PARAMETER;
607 }
608
609 IcmpHead = (IP6_ICMP_HEAD *) NetbufGetByte (Packet, 0, NULL);
610 ASSERT (IcmpHead != NULL);
611 if (IcmpHead->Checksum == 0) {
612 Checksum = &IcmpHead->Checksum;
613 }
614 break;
615
616 default:
617 break;
618 }
619
620 if (Checksum != NULL) {
621 //
622 // Calculate the checksum for upper layer protocol if it is not calculated due to lack of
623 // IPv6 source address.
624 //
625 PacketChecksum = NetbufChecksum (Packet);
626 PseudoChecksum = NetIp6PseudoHeadChecksum (
627 &Head->SourceAddress,
628 &Head->DestinationAddress,
629 NextHeader,
630 Packet->TotalSize
631 );
632 *Checksum = (UINT16) ~NetAddChecksum (PacketChecksum, PseudoChecksum);
633 }
634
635 Status = Ip6IpSecProcessPacket (
636 IpSb,
637 &Head,
638 LastHeader, // no need get the lasthead value for output
639 &Packet,
640 &ExtHdrs,
641 &ExtHdrsLen,
642 EfiIPsecOutBound,
643 Context
644 );
645
646 if (EFI_ERROR(Status)) {
647 return Status;
648 }
649
650 LastHeader = NULL;
651 //
652 // Check incoming parameters.
653 //
654 if (!Ip6IsExtsValid (
655 IpSb,
656 Packet,
657 &Head->NextHeader,
658 ExtHdrs,
659 ExtHdrsLen,
660 FALSE,
661 NULL,
662 &LastHeader,
663 &RealExtLen,
664 &UnFragmentHdrsLen,
665 NULL
666 )) {
667 return EFI_INVALID_PARAMETER;
668 }
669
670 if ((RealExtLen & 0x7) != 0) {
671 return EFI_INVALID_PARAMETER;
672 }
673
674 LastHeaderBackup = *LastHeader;
675
676 //
677 // Perform next hop determination:
678 // For multicast packets, the next-hop is always the destination address and
679 // is considered to be on-link.
680 //
681 if (IP6_IS_MULTICAST (&Head->DestinationAddress)) {
682 IP6_COPY_ADDRESS (&NextHop, &Head->DestinationAddress);
683 } else {
684 //
685 // For unicast packets, use a combination of the Destination Cache, the Prefix List
686 // and the Default Router List to determine the IP address of the appropriate next hop.
687 //
688
689 NeighborCache = Ip6FindNeighborEntry (IpSb, &Head->DestinationAddress);
690 if (NeighborCache != NULL) {
691 //
692 // Hit Neighbor Cache.
693 //
694 IP6_COPY_ADDRESS (&NextHop, &Head->DestinationAddress);
695 } else {
696 //
697 // Not in Neighbor Cache, check Router cache
698 //
699 RouteCache = Ip6Route (IpSb, &Head->DestinationAddress, &Head->SourceAddress);
700 if (RouteCache == NULL) {
701 return EFI_NOT_FOUND;
702 }
703
704 IP6_COPY_ADDRESS (&NextHop, &RouteCache->NextHop);
705 Ip6FreeRouteCacheEntry (RouteCache);
706 }
707 }
708
709 //
710 // Examines the Neighbor Cache for link-layer information about that neighbor.
711 // DO NOT create neighbor cache if neighbor is itself - when reporting ICMP error.
712 //
713 if (!IP6_IS_MULTICAST (&NextHop) && !EFI_IP6_EQUAL (&Head->DestinationAddress, &Head->SourceAddress)) {
714 NeighborCache = Ip6FindNeighborEntry (IpSb, &NextHop);
715 if (NeighborCache == NULL) {
716 NeighborCache = Ip6CreateNeighborEntry (IpSb, Ip6OnArpResolved, &NextHop, NULL);
717
718 if (NeighborCache == NULL) {
719 return EFI_OUT_OF_RESOURCES;
720 }
721
722 //
723 // Send out multicast neighbor solicitation for address resolution immediately.
724 //
725 Ip6CreateSNMulticastAddr (&NeighborCache->Neighbor, &Destination);
726 Status = Ip6SelectSourceAddress (IpSb, &NeighborCache->Neighbor, &Source);
727 if (EFI_ERROR (Status)) {
728 return Status;
729 }
730
731 Status = Ip6SendNeighborSolicit (
732 IpSb,
733 &Source,
734 &Destination,
735 &NeighborCache->Neighbor,
736 &IpSb->SnpMode.CurrentAddress
737 );
738 if (EFI_ERROR (Status)) {
739 return Status;
740 }
741
742 --NeighborCache->Transmit;
743 NeighborCache->Ticks = IP6_GET_TICKS (IpSb->RetransTimer) + 1;
744 }
745
746 NeighborCache->Interface = IpIf;
747 }
748
749 UpdatedExtHdrs = NULL;
750 ExtHdrsBackup = NULL;
751 NextHeaderBackup = 0;
752 FragmentHeadInserted = FALSE;
753
754 //
755 // Check whether we received Packet Too Big message for the packet sent to the
756 // Destination. If yes include a Fragment Header in the subsequent packets.
757 //
758 RouteEntry = Ip6FindRouteEntry (
759 IpSb->RouteTable,
760 &Head->DestinationAddress,
761 NULL
762 );
763 if (RouteEntry != NULL) {
764 if ((RouteEntry->Flag & IP6_PACKET_TOO_BIG) == IP6_PACKET_TOO_BIG) {
765
766 //
767 // FragmentHead is inserted after Hop-by-Hop Options header, Destination
768 // Options header (first occur), Routing header, and before Fragment header,
769 // Authentication header, Encapsulating Security Payload header, and
770 // Destination Options header (last occur), and upper-layer header.
771 //
772 Status = Ip6FillFragmentHeader (
773 IpSb,
774 Head->NextHeader,
775 LastHeaderBackup,
776 ExtHdrs,
777 ExtHdrsLen,
778 0,
779 &UpdatedExtHdrs
780 );
781 if (EFI_ERROR (Status)) {
782 return Status;
783 }
784
785 if ((ExtHdrs == NULL) && (ExtHdrsLen == 0)) {
786 NextHeaderBackup = Head->NextHeader;
787 Head->NextHeader = IP6_FRAGMENT;
788 }
789
790 ExtHdrsBackup = ExtHdrs;
791 ExtHdrs = UpdatedExtHdrs;
792 ExtHdrsLen = ExtHdrsLen + sizeof (IP6_FRAGMENT_HEADER);
793 RealExtLen = RealExtLen + sizeof (IP6_FRAGMENT_HEADER);
794
795 mIp6Id++;
796
797 FragmentHeadInserted = TRUE;
798 }
799
800 Ip6FreeRouteEntry (RouteEntry);
801 }
802
803 //
804 // OK, selected the source and route, fragment the packet then send
805 // them. Tag each fragment other than the first one as spawn from it.
806 // Each extension header is an integer multiple of 8 octets long, in
807 // order to retain 8-octet alignment for subsequent headers.
808 //
809 Mtu = IpSb->MaxPacketSize + sizeof (EFI_IP6_HEADER);
810 HeadLen = sizeof (EFI_IP6_HEADER) + RealExtLen;
811
812 if (Packet->TotalSize + HeadLen > Mtu) {
813 //
814 // Remove the inserted Fragment Header since we need fragment the packet.
815 //
816 if (FragmentHeadInserted) {
817 ExtHdrs = ExtHdrsBackup;
818 ExtHdrsLen = ExtHdrsLen - sizeof (IP6_FRAGMENT_HEADER);
819
820 if ((ExtHdrs == NULL) && (ExtHdrsLen == 0)) {
821 Head->NextHeader = NextHeaderBackup;
822 }
823 }
824
825 FragmentHdrsLen = ExtHdrsLen - UnFragmentHdrsLen;
826
827 //
828 // The packet is beyond the maximum which can be described through the
829 // fragment offset field in Fragment header.
830 //
831 if ((((Packet->TotalSize + FragmentHdrsLen) >> 3) & (~0x1fff)) != 0) {
832 Status = EFI_BAD_BUFFER_SIZE;
833 goto Error;
834 }
835
836 if (FragmentHdrsLen != 0) {
837 //
838 // Append the fragmentable extension hdrs before the upper layer payload
839 // to form a new NET_BUF. This NET_BUF contains all the buffer which will
840 // be fragmented below.
841 //
842 TmpPacket = NetbufGetFragment (Packet, 0, Packet->TotalSize, FragmentHdrsLen);
843 ASSERT (TmpPacket != NULL);
844
845 //
846 // Allocate the space to contain the fragmentable hdrs and copy the data.
847 //
848 Buf = NetbufAllocSpace (TmpPacket, FragmentHdrsLen, TRUE);
849 ASSERT (Buf != NULL);
850 CopyMem (Buf, ExtHdrs + UnFragmentHdrsLen, FragmentHdrsLen);
851
852 //
853 // Free the old Packet.
854 //
855 NetbufFree (Packet);
856 Packet = TmpPacket;
857 }
858
859 //
860 // The unfragment part which appears in every fragmented IPv6 packet includes
861 // the IPv6 header, the unfragmentable extension hdrs and the fragment header.
862 //
863 UnFragmentLen = sizeof (EFI_IP6_HEADER) + UnFragmentHdrsLen + sizeof (IP6_FRAGMENT_HEADER);
864
865 //
866 // Mtu now is the length of the fragment part in a full-length fragment.
867 //
868 Mtu = (Mtu - UnFragmentLen) & (~0x07);
869 Num = (Packet->TotalSize + Mtu - 1) / Mtu;
870
871 for (Index = 0, Offset = 0, PacketLen = Mtu; Index < Num; Index++) {
872 //
873 // Get fragment from the Packet, append UnFragnmentLen spare buffer
874 // before the fragmented data, the corresponding data is filled in later.
875 //
876 Fragment = NetbufGetFragment (Packet, Offset, PacketLen, UnFragmentLen);
877 if (Fragment == NULL) {
878 Status = EFI_OUT_OF_RESOURCES;
879 goto Error;
880 }
881
882 FragmentOffset = (UINT16) ((UINT16) Offset | 0x1);
883 if (Index == Num - 1){
884 //
885 // The last fragment, clear the M flag.
886 //
887 FragmentOffset &= (~0x1);
888 }
889
890 Status = Ip6PrependHead (
891 IpSb,
892 Fragment,
893 Head,
894 FragmentOffset,
895 ExtHdrs,
896 ExtHdrsLen,
897 LastHeaderBackup,
898 UnFragmentLen
899 );
900 ASSERT (Status == EFI_SUCCESS);
901
902 Status = Ip6SendFrame (
903 IpIf,
904 IpInstance,
905 Fragment,
906 &NextHop,
907 Ip6SysPacketSent,
908 Packet
909 );
910 if (EFI_ERROR (Status)) {
911 goto Error;
912 }
913
914 //
915 // The last fragment of upper layer packet, update the IP6 token status.
916 //
917 if ((Index == Num -1) && (Context != NULL)) {
918 Wrap = (IP6_TXTOKEN_WRAP *) Context;
919 Wrap->Token->Status = Status;
920 }
921
922 Offset += PacketLen;
923 PacketLen = Packet->TotalSize - Offset;
924 if (PacketLen > Mtu) {
925 PacketLen = Mtu;
926 }
927 }
928
929 NetbufFree (Packet);
930 mIp6Id++;
931
932 if (UpdatedExtHdrs != NULL) {
933 FreePool (UpdatedExtHdrs);
934 }
935
936 return EFI_SUCCESS;
937 }
938
939 //
940 // Need not fragment the packet, send it in one frame.
941 //
942 PacketHead = (EFI_IP6_HEADER *) NetbufAllocSpace (Packet, HeadLen, NET_BUF_HEAD);
943 if (PacketHead == NULL) {
944 Status = EFI_BAD_BUFFER_SIZE;
945 goto Error;
946 }
947
948 CopyMem (PacketHead, Head, sizeof (EFI_IP6_HEADER));
949 Packet->Ip.Ip6 = PacketHead;
950
951 if (ExtHdrs != NULL) {
952 Buf = (UINT8 *) (PacketHead + 1);
953 CopyMem (Buf, ExtHdrs, ExtHdrsLen);
954 }
955
956 if (UpdatedExtHdrs != NULL) {
957 //
958 // A Fragment Header is inserted to the packet, update the payload length.
959 //
960 PacketHead->PayloadLength = (UINT16) (NTOHS (PacketHead->PayloadLength) +
961 sizeof (IP6_FRAGMENT_HEADER));
962 PacketHead->PayloadLength = HTONS (PacketHead->PayloadLength);
963 FreePool (UpdatedExtHdrs);
964 }
965
966 return Ip6SendFrame (
967 IpIf,
968 IpInstance,
969 Packet,
970 &NextHop,
971 Callback,
972 Context
973 );
974
975Error:
976 if (UpdatedExtHdrs != NULL) {
977 FreePool (UpdatedExtHdrs);
978 }
979 Ip6CancelPacket (IpIf, Packet, Status);
980 return Status;
981}
982
983/**
984 The filter function to find a packet and all its fragments.
985 The packet's fragments have their Context set to the packet.
986
987 @param[in] Frame The frames hold by the low level interface.
988 @param[in] Context Context to the function, which is the packet.
989
990 @retval TRUE This is the packet to cancel or its fragments.
991 @retval FALSE This is an unrelated packet.
992
993**/
994BOOLEAN
995Ip6CancelPacketFragments (
996 IN IP6_LINK_TX_TOKEN *Frame,
997 IN VOID *Context
998 )
999{
1000 if ((Frame->Packet == (NET_BUF *) Context) || (Frame->Context == Context)) {
1001 return TRUE;
1002 }
1003
1004 return FALSE;
1005}
1006
1007/**
1008 Remove all the frames on the interface that pass the FrameToCancel,
1009 either queued on ARP queues or that have already been delivered to
1010 MNP and not yet recycled.
1011
1012 @param[in] Interface Interface to remove the frames from.
1013 @param[in] IoStatus The transmit status returned to the frames' callback.
1014 @param[in] FrameToCancel Function to select the frame to cancel; NULL to select all.
1015 @param[in] Context Opaque parameters passed to FrameToCancel. Ignored if
1016 FrameToCancel is NULL.
1017
1018**/
1019VOID
1020Ip6CancelFrames (
1021 IN IP6_INTERFACE *Interface,
1022 IN EFI_STATUS IoStatus,
1023 IN IP6_FRAME_TO_CANCEL FrameToCancel OPTIONAL,
1024 IN VOID *Context OPTIONAL
1025 )
1026{
1027 LIST_ENTRY *Entry;
1028 LIST_ENTRY *Next;
1029 IP6_LINK_TX_TOKEN *Token;
1030 IP6_SERVICE *IpSb;
1031 IP6_NEIGHBOR_ENTRY *ArpQue;
1032 EFI_STATUS Status;
1033
1034 IpSb = Interface->Service;
1035 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
1036
1037 //
1038 // Cancel all the pending frames on ARP requests
1039 //
1040 NET_LIST_FOR_EACH_SAFE (Entry, Next, &Interface->ArpQues) {
1041 ArpQue = NET_LIST_USER_STRUCT (Entry, IP6_NEIGHBOR_ENTRY, ArpList);
1042
1043 Status = Ip6FreeNeighborEntry (
1044 IpSb,
1045 ArpQue,
1046 FALSE,
1047 FALSE,
1048 IoStatus,
1049 FrameToCancel,
1050 Context
1051 );
1052 ASSERT_EFI_ERROR (Status);
1053 }
1054
1055 //
1056 // Cancel all the frames that have been delivered to MNP
1057 // but not yet recycled.
1058 //
1059 NET_LIST_FOR_EACH_SAFE (Entry, Next, &Interface->SentFrames) {
1060 Token = NET_LIST_USER_STRUCT (Entry, IP6_LINK_TX_TOKEN, Link);
1061
1062 if ((FrameToCancel == NULL) || FrameToCancel (Token, Context)) {
1063 IpSb->Mnp->Cancel (IpSb->Mnp, &Token->MnpToken);
1064 }
1065 }
1066}
1067
1068/**
1069 Cancel the Packet and all its fragments.
1070
1071 @param[in] IpIf The interface from which the Packet is sent.
1072 @param[in] Packet The Packet to cancel.
1073 @param[in] IoStatus The status returns to the sender.
1074
1075**/
1076VOID
1077Ip6CancelPacket (
1078 IN IP6_INTERFACE *IpIf,
1079 IN NET_BUF *Packet,
1080 IN EFI_STATUS IoStatus
1081 )
1082{
1083 Ip6CancelFrames (IpIf, IoStatus, Ip6CancelPacketFragments, Packet);
1084}
1085
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