VirtualBox

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

Last change on this file since 77662 was 77662, checked in by vboxsync, 6 years ago

EFI: First step in UDK2018 merge. Does not build yet.

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