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 
18 UINT32 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 responsiblity 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 **/
35 EFI_STATUS
Ip6CandidateSource(IN IP6_SERVICE * IpSb,OUT LIST_ENTRY * SourceList,OUT UINT32 * SourceCount)36 Ip6CandidateSource (
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 **/
102 UINT8
Ip6CommonPrefixLen(IN EFI_IPv6_ADDRESS * AddressA,IN EFI_IPv6_ADDRESS * AddressB)103 Ip6CommonPrefixLen (
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 **/
158 EFI_STATUS
Ip6SelectSourceAddress(IN IP6_SERVICE * IpSb,IN EFI_IPv6_ADDRESS * Destination,OUT EFI_IPv6_ADDRESS * Source)159 Ip6SelectSourceAddress (
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 
271 Exit:
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 **/
291 IP6_INTERFACE *
Ip6SelectInterface(IN IP6_SERVICE * IpSb,IN EFI_IPv6_ADDRESS * Destination,IN OUT EFI_IPv6_ADDRESS * Source)292 Ip6SelectInterface (
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 **/
342 VOID
Ip6SysPacketSent(NET_BUF * Packet,EFI_STATUS IoStatus,UINT32 LinkFlag,VOID * Context)343 Ip6SysPacketSent (
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 enought room in the head space of
368                                Packet.
369   @retval EFI_SUCCESS          The operation performed successfully.
370 
371 **/
372 EFI_STATUS
Ip6PrependHead(IN IP6_SERVICE * IpSb,IN NET_BUF * Packet,IN EFI_IP6_HEADER * Head,IN UINT16 FragmentOffset,IN UINT8 * ExtHdrs,IN UINT32 ExtHdrsLen,IN UINT8 LastHeader,IN UINT32 HeadLen)373 Ip6PrependHead (
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 **/
481 EFI_STATUS
Ip6Output(IN IP6_SERVICE * IpSb,IN IP6_INTERFACE * Interface OPTIONAL,IN IP6_PROTOCOL * IpInstance OPTIONAL,IN NET_BUF * Packet,IN EFI_IP6_HEADER * Head,IN UINT8 * ExtHdrs,IN UINT32 ExtHdrsLen,IN IP6_FRAME_CALLBACK Callback,IN VOID * Context)482 Ip6Output (
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 immediatly.
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 integar 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 
981 Error:
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 **/
1000 BOOLEAN
Ip6CancelPacketFragments(IN IP6_LINK_TX_TOKEN * Frame,IN VOID * Context)1001 Ip6CancelPacketFragments (
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 **/
1025 VOID
Ip6CancelFrames(IN IP6_INTERFACE * Interface,IN EFI_STATUS IoStatus,IN IP6_FRAME_TO_CANCEL FrameToCancel OPTIONAL,IN VOID * Context OPTIONAL)1026 Ip6CancelFrames (
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 **/
1082 VOID
Ip6CancelPacket(IN IP6_INTERFACE * IpIf,IN NET_BUF * Packet,IN EFI_STATUS IoStatus)1083 Ip6CancelPacket (
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 
1092