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 
12 UINT32 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 **/
29 EFI_STATUS
Ip6CandidateSource(IN IP6_SERVICE * IpSb,OUT LIST_ENTRY * SourceList,OUT UINT32 * SourceCount)30 Ip6CandidateSource (
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 **/
96 UINT8
Ip6CommonPrefixLen(IN EFI_IPv6_ADDRESS * AddressA,IN EFI_IPv6_ADDRESS * AddressB)97 Ip6CommonPrefixLen (
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 **/
152 EFI_STATUS
Ip6SelectSourceAddress(IN IP6_SERVICE * IpSb,IN EFI_IPv6_ADDRESS * Destination,OUT EFI_IPv6_ADDRESS * Source)153 Ip6SelectSourceAddress (
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 
265 Exit:
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 **/
285 IP6_INTERFACE *
Ip6SelectInterface(IN IP6_SERVICE * IpSb,IN EFI_IPv6_ADDRESS * Destination,IN OUT EFI_IPv6_ADDRESS * Source)286 Ip6SelectInterface (
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 **/
336 VOID
Ip6SysPacketSent(NET_BUF * Packet,EFI_STATUS IoStatus,UINT32 LinkFlag,VOID * Context)337 Ip6SysPacketSent (
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 **/
366 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)367 Ip6PrependHead (
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 **/
475 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)476 Ip6Output (
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 UnFragmentLen 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 
975 Error:
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 **/
994 BOOLEAN
Ip6CancelPacketFragments(IN IP6_LINK_TX_TOKEN * Frame,IN VOID * Context)995 Ip6CancelPacketFragments (
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 **/
1019 VOID
Ip6CancelFrames(IN IP6_INTERFACE * Interface,IN EFI_STATUS IoStatus,IN IP6_FRAME_TO_CANCEL FrameToCancel OPTIONAL,IN VOID * Context OPTIONAL)1020 Ip6CancelFrames (
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 **/
1076 VOID
Ip6CancelPacket(IN IP6_INTERFACE * IpIf,IN NET_BUF * Packet,IN EFI_STATUS IoStatus)1077 Ip6CancelPacket (
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 
1086