REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the NetworkPkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Maciej Rabeda <maciej.rabeda@linux.intel.com>
		
			
				
	
	
		
			1089 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1089 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  The internal functions and routines to transmit the IP6 packet.
 | 
						|
 | 
						|
  Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
 | 
						|
 | 
						|
  SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "Ip6Impl.h"
 | 
						|
 | 
						|
UINT32  mIp6Id;
 | 
						|
 | 
						|
/**
 | 
						|
  Output all the available source addresses to a list entry head SourceList. The
 | 
						|
  number of source addresses are also returned.
 | 
						|
 | 
						|
  @param[in]       IpSb             Points to an IP6 service binding instance.
 | 
						|
  @param[out]      SourceList       The list entry head of all source addresses.
 | 
						|
                                    It is the caller's responsibility to free the
 | 
						|
                                    resources.
 | 
						|
  @param[out]      SourceCount      The number of source addresses.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The source addresses were copied to a list entry head
 | 
						|
                                SourceList.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  Failed to allocate resources to complete the operation.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
Ip6CandidateSource (
 | 
						|
  IN IP6_SERVICE  *IpSb,
 | 
						|
  OUT LIST_ENTRY  *SourceList,
 | 
						|
  OUT UINT32      *SourceCount
 | 
						|
  )
 | 
						|
{
 | 
						|
  IP6_INTERFACE     *IpIf;
 | 
						|
  LIST_ENTRY        *Entry;
 | 
						|
  LIST_ENTRY        *Entry2;
 | 
						|
  IP6_ADDRESS_INFO  *AddrInfo;
 | 
						|
  IP6_ADDRESS_INFO  *Copy;
 | 
						|
 | 
						|
  *SourceCount = 0;
 | 
						|
 | 
						|
  if (IpSb->LinkLocalOk) {
 | 
						|
    Copy = AllocatePool (sizeof (IP6_ADDRESS_INFO));
 | 
						|
    if (Copy == NULL) {
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
 | 
						|
    Copy->Signature = IP6_ADDR_INFO_SIGNATURE;
 | 
						|
    IP6_COPY_ADDRESS (&Copy->Address, &IpSb->LinkLocalAddr);
 | 
						|
    Copy->IsAnycast         = FALSE;
 | 
						|
    Copy->PrefixLength      = IP6_LINK_LOCAL_PREFIX_LENGTH;
 | 
						|
    Copy->ValidLifetime     = (UINT32)IP6_INFINIT_LIFETIME;
 | 
						|
    Copy->PreferredLifetime = (UINT32)IP6_INFINIT_LIFETIME;
 | 
						|
 | 
						|
    InsertTailList (SourceList, &Copy->Link);
 | 
						|
    (*SourceCount)++;
 | 
						|
  }
 | 
						|
 | 
						|
  NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
 | 
						|
    IpIf = NET_LIST_USER_STRUCT (Entry, IP6_INTERFACE, Link);
 | 
						|
 | 
						|
    NET_LIST_FOR_EACH (Entry2, &IpIf->AddressList) {
 | 
						|
      AddrInfo = NET_LIST_USER_STRUCT_S (Entry2, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);
 | 
						|
 | 
						|
      if (AddrInfo->IsAnycast) {
 | 
						|
        //
 | 
						|
        // Never use an anycast address.
 | 
						|
        //
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      Copy = AllocateCopyPool (sizeof (IP6_ADDRESS_INFO), AddrInfo);
 | 
						|
      if (Copy == NULL) {
 | 
						|
        return EFI_OUT_OF_RESOURCES;
 | 
						|
      }
 | 
						|
 | 
						|
      InsertTailList (SourceList, &Copy->Link);
 | 
						|
      (*SourceCount)++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Calculate how many bits are the same between two IPv6 addresses.
 | 
						|
 | 
						|
  @param[in]       AddressA         Points to an IPv6 address.
 | 
						|
  @param[in]       AddressB         Points to another IPv6 address.
 | 
						|
 | 
						|
  @return The common bits of the AddressA and AddressB.
 | 
						|
 | 
						|
**/
 | 
						|
UINT8
 | 
						|
Ip6CommonPrefixLen (
 | 
						|
  IN EFI_IPv6_ADDRESS  *AddressA,
 | 
						|
  IN EFI_IPv6_ADDRESS  *AddressB
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8  Count;
 | 
						|
  UINT8  Index;
 | 
						|
  UINT8  ByteA;
 | 
						|
  UINT8  ByteB;
 | 
						|
  UINT8  NumBits;
 | 
						|
 | 
						|
  Count = 0;
 | 
						|
  Index = 0;
 | 
						|
 | 
						|
  while (Index < 16) {
 | 
						|
    ByteA = AddressA->Addr[Index];
 | 
						|
    ByteB = AddressB->Addr[Index];
 | 
						|
 | 
						|
    if (ByteA == ByteB) {
 | 
						|
      Count += 8;
 | 
						|
      Index++;
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Check how many bits are common between the two bytes.
 | 
						|
    //
 | 
						|
    NumBits = 8;
 | 
						|
    ByteA   = (UINT8)(ByteA ^ ByteB);
 | 
						|
 | 
						|
    while (ByteA != 0) {
 | 
						|
      NumBits--;
 | 
						|
      ByteA = (UINT8)(ByteA >> 1);
 | 
						|
    }
 | 
						|
 | 
						|
    return (UINT8)(Count + NumBits);
 | 
						|
  }
 | 
						|
 | 
						|
  return Count;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Output all the available source addresses to a list entry head SourceList. The
 | 
						|
  number of source addresses are also returned.
 | 
						|
 | 
						|
  @param[in]       IpSb             Points to a IP6 service binding instance.
 | 
						|
  @param[in]       Destination      The IPv6 destination address.
 | 
						|
  @param[out]      Source           The selected IPv6 source address according to
 | 
						|
                                    the Destination.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The source addresses were copied to a list entry
 | 
						|
                                head SourceList.
 | 
						|
  @retval EFI_NO_MAPPING        The IPv6 stack is not auto configured.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
Ip6SelectSourceAddress (
 | 
						|
  IN IP6_SERVICE        *IpSb,
 | 
						|
  IN EFI_IPv6_ADDRESS   *Destination,
 | 
						|
  OUT EFI_IPv6_ADDRESS  *Source
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS             Status;
 | 
						|
  LIST_ENTRY             SourceList;
 | 
						|
  UINT32                 SourceCount;
 | 
						|
  UINT8                  ScopeD;
 | 
						|
  LIST_ENTRY             *Entry;
 | 
						|
  IP6_ADDRESS_INFO       *AddrInfo;
 | 
						|
  IP6_PREFIX_LIST_ENTRY  *Prefix;
 | 
						|
  UINT8                  LastCommonLength;
 | 
						|
  UINT8                  CurrentCommonLength;
 | 
						|
  EFI_IPv6_ADDRESS       *TmpAddress;
 | 
						|
 | 
						|
  NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
  InitializeListHead (&SourceList);
 | 
						|
 | 
						|
  if (!IpSb->LinkLocalOk) {
 | 
						|
    return EFI_NO_MAPPING;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Rule 1: Prefer same address.
 | 
						|
  //
 | 
						|
  if (Ip6IsOneOfSetAddress (IpSb, Destination, NULL, NULL)) {
 | 
						|
    IP6_COPY_ADDRESS (Source, Destination);
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Rule 2: Prefer appropriate scope.
 | 
						|
  //
 | 
						|
  if (IP6_IS_MULTICAST (Destination)) {
 | 
						|
    ScopeD = (UINT8)(Destination->Addr[1] >> 4);
 | 
						|
  } else if (NetIp6IsLinkLocalAddr (Destination)) {
 | 
						|
    ScopeD = 0x2;
 | 
						|
  } else {
 | 
						|
    ScopeD = 0xE;
 | 
						|
  }
 | 
						|
 | 
						|
  if (ScopeD <= 0x2) {
 | 
						|
    //
 | 
						|
    // Return the link-local address if it exists
 | 
						|
    // One IP6_SERVICE only has one link-local address.
 | 
						|
    //
 | 
						|
    IP6_COPY_ADDRESS (Source, &IpSb->LinkLocalAddr);
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // All candidate source addresses are global unicast address.
 | 
						|
  //
 | 
						|
  Ip6CandidateSource (IpSb, &SourceList, &SourceCount);
 | 
						|
 | 
						|
  if (SourceCount == 0) {
 | 
						|
    Status = EFI_NO_MAPPING;
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  IP6_COPY_ADDRESS (Source, &IpSb->LinkLocalAddr);
 | 
						|
 | 
						|
  if (SourceCount == 1) {
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Rule 3: Avoid deprecated addresses.
 | 
						|
  // TODO: check the "deprecated" state of the stateful configured address
 | 
						|
  //
 | 
						|
  NET_LIST_FOR_EACH (Entry, &IpSb->AutonomousPrefix) {
 | 
						|
    Prefix = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
 | 
						|
    if (Prefix->PreferredLifetime == 0) {
 | 
						|
      Ip6RemoveAddr (NULL, &SourceList, &SourceCount, &Prefix->Prefix, Prefix->PrefixLength);
 | 
						|
 | 
						|
      if (SourceCount == 1) {
 | 
						|
        goto Exit;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // TODO: Rule 4: Prefer home addresses.
 | 
						|
  // TODO: Rule 5: Prefer outgoing interface.
 | 
						|
  // TODO: Rule 6: Prefer matching label.
 | 
						|
  // TODO: Rule 7: Prefer public addresses.
 | 
						|
  //
 | 
						|
 | 
						|
  //
 | 
						|
  // Rule 8: Use longest matching prefix.
 | 
						|
  //
 | 
						|
  LastCommonLength = Ip6CommonPrefixLen (Source, Destination);
 | 
						|
  TmpAddress       = NULL;
 | 
						|
 | 
						|
  for (Entry = SourceList.ForwardLink; Entry != &SourceList; Entry = Entry->ForwardLink) {
 | 
						|
    AddrInfo = NET_LIST_USER_STRUCT_S (Entry, IP6_ADDRESS_INFO, Link, IP6_ADDR_INFO_SIGNATURE);
 | 
						|
 | 
						|
    CurrentCommonLength = Ip6CommonPrefixLen (&AddrInfo->Address, Destination);
 | 
						|
    if (CurrentCommonLength > LastCommonLength) {
 | 
						|
      LastCommonLength = CurrentCommonLength;
 | 
						|
      TmpAddress       = &AddrInfo->Address;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (TmpAddress != NULL) {
 | 
						|
    IP6_COPY_ADDRESS (Source, TmpAddress);
 | 
						|
  }
 | 
						|
 | 
						|
Exit:
 | 
						|
 | 
						|
  Ip6RemoveAddr (NULL, &SourceList, &SourceCount, NULL, 0);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Select an interface to send the packet generated in the IP6 driver
 | 
						|
  itself: that is, not by the requests of the IP6 child's consumer. Such
 | 
						|
  packets include the ICMPv6 echo replies and other ICMPv6 error packets.
 | 
						|
 | 
						|
  @param[in]  IpSb                 The IP4 service that wants to send the packets.
 | 
						|
  @param[in]  Destination          The destination of the packet.
 | 
						|
  @param[in, out]  Source          The source of the packet.
 | 
						|
 | 
						|
  @return NULL if no proper interface is found, otherwise, the interface that
 | 
						|
          can be used to send the system packet from.
 | 
						|
 | 
						|
**/
 | 
						|
IP6_INTERFACE *
 | 
						|
Ip6SelectInterface (
 | 
						|
  IN IP6_SERVICE           *IpSb,
 | 
						|
  IN EFI_IPv6_ADDRESS      *Destination,
 | 
						|
  IN OUT EFI_IPv6_ADDRESS  *Source
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS        Status;
 | 
						|
  EFI_IPv6_ADDRESS  SelectedSource;
 | 
						|
  IP6_INTERFACE     *IpIf;
 | 
						|
  BOOLEAN           Exist;
 | 
						|
 | 
						|
  NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
 | 
						|
  ASSERT (Destination != NULL && Source != NULL);
 | 
						|
 | 
						|
  if (NetIp6IsUnspecifiedAddr (Destination)) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!NetIp6IsUnspecifiedAddr (Source)) {
 | 
						|
    Exist = Ip6IsOneOfSetAddress (IpSb, Source, &IpIf, NULL);
 | 
						|
    ASSERT (Exist);
 | 
						|
 | 
						|
    return IpIf;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // If source is unspecified, select a source according to the destination.
 | 
						|
  //
 | 
						|
  Status = Ip6SelectSourceAddress (IpSb, Destination, &SelectedSource);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return IpSb->DefaultInterface;
 | 
						|
  }
 | 
						|
 | 
						|
  Ip6IsOneOfSetAddress (IpSb, &SelectedSource, &IpIf, NULL);
 | 
						|
  IP6_COPY_ADDRESS (Source, &SelectedSource);
 | 
						|
 | 
						|
  return IpIf;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  The default callback function for the system generated packet.
 | 
						|
  It will free the packet.
 | 
						|
 | 
						|
  @param[in]  Packet        The packet that transmitted.
 | 
						|
  @param[in]  IoStatus      The result of the transmission, succeeded or failed.
 | 
						|
  @param[in]  LinkFlag      Not used when transmitted. Check IP6_FRAME_CALLBACK
 | 
						|
                            for reference.
 | 
						|
  @param[in]  Context       The context provided by us.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
Ip6SysPacketSent (
 | 
						|
  NET_BUF     *Packet,
 | 
						|
  EFI_STATUS  IoStatus,
 | 
						|
  UINT32      LinkFlag,
 | 
						|
  VOID        *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  NetbufFree (Packet);
 | 
						|
  Packet = NULL;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Prefix an IP6 basic head and unfragmentable extension headers and a fragment header
 | 
						|
  to the Packet. Used for IP6 fragmentation.
 | 
						|
 | 
						|
  @param[in]  IpSb             The IP6 service instance to transmit the packet.
 | 
						|
  @param[in]  Packet           The packet to prefix the IP6 header to.
 | 
						|
  @param[in]  Head             The caller supplied header.
 | 
						|
  @param[in]  FragmentOffset   The fragment offset of the data following the header.
 | 
						|
  @param[in]  ExtHdrs          The length of the original extension header.
 | 
						|
  @param[in]  ExtHdrsLen       The length of the extension headers.
 | 
						|
  @param[in]  LastHeader       The pointer of next header of last extension header.
 | 
						|
  @param[in]  HeadLen          The length of the unfragmented part of the IP6 header.
 | 
						|
 | 
						|
  @retval EFI_BAD_BUFFER_SIZE  There is no enough room in the head space of
 | 
						|
                               Packet.
 | 
						|
  @retval EFI_SUCCESS          The operation performed successfully.
 | 
						|
 | 
						|
**/
 | 
						|
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
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32          Len;
 | 
						|
  UINT32          UnFragExtHdrsLen;
 | 
						|
  EFI_IP6_HEADER  *PacketHead;
 | 
						|
  UINT8           *UpdatedExtHdrs;
 | 
						|
  EFI_STATUS      Status;
 | 
						|
  UINT8           NextHeader;
 | 
						|
 | 
						|
  UpdatedExtHdrs = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // HeadLen is the length of the fixed part of the sequences of fragments, i.e.
 | 
						|
  // the unfragment part.
 | 
						|
  //
 | 
						|
  PacketHead = (EFI_IP6_HEADER *)NetbufAllocSpace (Packet, HeadLen, NET_BUF_HEAD);
 | 
						|
  if (PacketHead == NULL) {
 | 
						|
    return EFI_BAD_BUFFER_SIZE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Set the head up, convert the host byte order to network byte order
 | 
						|
  //
 | 
						|
  CopyMem (PacketHead, Head, sizeof (EFI_IP6_HEADER));
 | 
						|
  PacketHead->PayloadLength = HTONS ((UINT16)(Packet->TotalSize - sizeof (EFI_IP6_HEADER)));
 | 
						|
  Packet->Ip.Ip6            = PacketHead;
 | 
						|
 | 
						|
  Len              = HeadLen - sizeof (EFI_IP6_HEADER);
 | 
						|
  UnFragExtHdrsLen = Len - sizeof (IP6_FRAGMENT_HEADER);
 | 
						|
 | 
						|
  if (UnFragExtHdrsLen == 0) {
 | 
						|
    PacketHead->NextHeader = IP6_FRAGMENT;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Append the extension headers: firstly copy the unfragmentable headers, then append
 | 
						|
  // fragmentation header.
 | 
						|
  //
 | 
						|
  if ((FragmentOffset & IP6_FRAGMENT_OFFSET_MASK) == 0) {
 | 
						|
    NextHeader = Head->NextHeader;
 | 
						|
  } else {
 | 
						|
    NextHeader = PacketHead->NextHeader;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = Ip6FillFragmentHeader (
 | 
						|
             IpSb,
 | 
						|
             NextHeader,
 | 
						|
             LastHeader,
 | 
						|
             ExtHdrs,
 | 
						|
             ExtHdrsLen,
 | 
						|
             FragmentOffset,
 | 
						|
             &UpdatedExtHdrs
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  CopyMem (
 | 
						|
    (UINT8 *)(PacketHead + 1),
 | 
						|
    UpdatedExtHdrs,
 | 
						|
    UnFragExtHdrsLen + sizeof (IP6_FRAGMENT_HEADER)
 | 
						|
    );
 | 
						|
 | 
						|
  FreePool (UpdatedExtHdrs);
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Transmit an IP6 packet. The packet comes either from the IP6
 | 
						|
  child's consumer (IpInstance != NULL) or the IP6 driver itself
 | 
						|
  (IpInstance == NULL). It will route the packet, fragment it,
 | 
						|
  then transmit all the fragments through an interface.
 | 
						|
 | 
						|
  @param[in]  IpSb             The IP6 service instance to transmit the packet.
 | 
						|
  @param[in]  Interface        The IP6 interface to transmit the packet. Ignored
 | 
						|
                               if NULL.
 | 
						|
  @param[in]  IpInstance       The IP6 child that issues the transmission.  It is
 | 
						|
                               NULL if the packet is from the system.
 | 
						|
  @param[in]  Packet           The user data to send, excluding the IP header.
 | 
						|
  @param[in]  Head             The caller supplied header. The caller should set
 | 
						|
                               the  following header fields: NextHeader, HopLimit,
 | 
						|
                               Src, Dest, FlowLabel, PayloadLength. This function
 | 
						|
                               will fill in the Ver, TrafficClass.
 | 
						|
  @param[in]  ExtHdrs          The extension headers to append to the IPv6 basic
 | 
						|
                               header.
 | 
						|
  @param[in]  ExtHdrsLen       The length of the extension headers.
 | 
						|
  @param[in]  Callback         The callback function to issue when transmission
 | 
						|
                               completed.
 | 
						|
  @param[in]  Context          The opaque context for the callback.
 | 
						|
 | 
						|
  @retval EFI_INVALID_PARAMETER Any input parameter or the packet is invalid.
 | 
						|
  @retval EFI_NO_MAPPING        There is no interface to the destination.
 | 
						|
  @retval EFI_NOT_FOUND         There is no route to the destination.
 | 
						|
  @retval EFI_SUCCESS           The packet successfully transmitted.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  Failed to finish the operation due to lack of
 | 
						|
                                resources.
 | 
						|
  @retval Others                Failed to transmit the packet.
 | 
						|
 | 
						|
**/
 | 
						|
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
 | 
						|
  )
 | 
						|
{
 | 
						|
  IP6_INTERFACE          *IpIf;
 | 
						|
  EFI_IPv6_ADDRESS       NextHop;
 | 
						|
  IP6_NEIGHBOR_ENTRY     *NeighborCache;
 | 
						|
  IP6_ROUTE_CACHE_ENTRY  *RouteCache;
 | 
						|
  EFI_STATUS             Status;
 | 
						|
  UINT32                 Mtu;
 | 
						|
  UINT32                 HeadLen;
 | 
						|
  UINT16                 FragmentOffset;
 | 
						|
  UINT8                  *LastHeader;
 | 
						|
  UINT32                 UnFragmentLen;
 | 
						|
  UINT32                 UnFragmentHdrsLen;
 | 
						|
  UINT32                 FragmentHdrsLen;
 | 
						|
  UINT16                 *Checksum;
 | 
						|
  UINT16                 PacketChecksum;
 | 
						|
  UINT16                 PseudoChecksum;
 | 
						|
  UINT32                 Index;
 | 
						|
  UINT32                 PacketLen;
 | 
						|
  UINT32                 RealExtLen;
 | 
						|
  UINT32                 Offset;
 | 
						|
  NET_BUF                *TmpPacket;
 | 
						|
  NET_BUF                *Fragment;
 | 
						|
  UINT32                 Num;
 | 
						|
  UINT8                  *Buf;
 | 
						|
  EFI_IP6_HEADER         *PacketHead;
 | 
						|
  IP6_ICMP_HEAD          *IcmpHead;
 | 
						|
  IP6_TXTOKEN_WRAP       *Wrap;
 | 
						|
  IP6_ROUTE_ENTRY        *RouteEntry;
 | 
						|
  UINT8                  *UpdatedExtHdrs;
 | 
						|
  UINT8                  NextHeader;
 | 
						|
  UINT8                  LastHeaderBackup;
 | 
						|
  BOOLEAN                FragmentHeadInserted;
 | 
						|
  UINT8                  *ExtHdrsBackup;
 | 
						|
  UINT8                  NextHeaderBackup;
 | 
						|
  EFI_IPv6_ADDRESS       Source;
 | 
						|
  EFI_IPv6_ADDRESS       Destination;
 | 
						|
 | 
						|
  NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
 | 
						|
 | 
						|
  //
 | 
						|
  // RFC2460: Each extension header is an integer multiple of 8 octets long,
 | 
						|
  // in order to retain 8-octet alignment for subsequent headers.
 | 
						|
  //
 | 
						|
  if ((ExtHdrsLen & 0x7) != 0) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  LastHeader = NULL;
 | 
						|
 | 
						|
  Ip6IsExtsValid (
 | 
						|
    NULL,
 | 
						|
    NULL,
 | 
						|
    &Head->NextHeader,
 | 
						|
    ExtHdrs,
 | 
						|
    ExtHdrsLen,
 | 
						|
    FALSE,
 | 
						|
    NULL,
 | 
						|
    &LastHeader,
 | 
						|
    NULL,
 | 
						|
    NULL,
 | 
						|
    NULL
 | 
						|
    );
 | 
						|
 | 
						|
  //
 | 
						|
  // Select an interface/source for system packet, application
 | 
						|
  // should select them itself.
 | 
						|
  //
 | 
						|
  IpIf = Interface;
 | 
						|
  if (IpIf == NULL) {
 | 
						|
    //
 | 
						|
    // IpInstance->Interface is NULL when IpInstance is configured with both stationaddress
 | 
						|
    // and destinationaddress is unspecified.
 | 
						|
    //
 | 
						|
    if ((IpInstance == NULL) || (IpInstance->Interface == NULL)) {
 | 
						|
      IpIf = Ip6SelectInterface (IpSb, &Head->DestinationAddress, &Head->SourceAddress);
 | 
						|
      if (IpInstance != NULL) {
 | 
						|
        IpInstance->Interface = IpIf;
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      IpIf = IpInstance->Interface;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (IpIf == NULL) {
 | 
						|
    return EFI_NO_MAPPING;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Update the common field in Head here.
 | 
						|
  //
 | 
						|
  Head->Version       = 6;
 | 
						|
  Head->TrafficClassL = 0;
 | 
						|
  Head->TrafficClassH = 0;
 | 
						|
 | 
						|
  Checksum   = NULL;
 | 
						|
  NextHeader = *LastHeader;
 | 
						|
 | 
						|
  switch (NextHeader) {
 | 
						|
    case EFI_IP_PROTO_UDP:
 | 
						|
      Packet->Udp = (EFI_UDP_HEADER *)NetbufGetByte (Packet, 0, NULL);
 | 
						|
      ASSERT (Packet->Udp != NULL);
 | 
						|
      if (Packet->Udp->Checksum == 0) {
 | 
						|
        Checksum = &Packet->Udp->Checksum;
 | 
						|
      }
 | 
						|
 | 
						|
      break;
 | 
						|
 | 
						|
    case EFI_IP_PROTO_TCP:
 | 
						|
      Packet->Tcp = (TCP_HEAD *)NetbufGetByte (Packet, 0, NULL);
 | 
						|
      ASSERT (Packet->Tcp != NULL);
 | 
						|
      if (Packet->Tcp->Checksum == 0) {
 | 
						|
        Checksum = &Packet->Tcp->Checksum;
 | 
						|
      }
 | 
						|
 | 
						|
      break;
 | 
						|
 | 
						|
    case IP6_ICMP:
 | 
						|
      //
 | 
						|
      // Don't send ICMP packet to an IPv6 anycast address.
 | 
						|
      //
 | 
						|
      if (Ip6IsAnycast (IpSb, &Head->DestinationAddress)) {
 | 
						|
        return EFI_INVALID_PARAMETER;
 | 
						|
      }
 | 
						|
 | 
						|
      IcmpHead = (IP6_ICMP_HEAD *)NetbufGetByte (Packet, 0, NULL);
 | 
						|
      ASSERT (IcmpHead != NULL);
 | 
						|
      if (IcmpHead->Checksum == 0) {
 | 
						|
        Checksum = &IcmpHead->Checksum;
 | 
						|
      }
 | 
						|
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Checksum != NULL) {
 | 
						|
    //
 | 
						|
    // Calculate the checksum for upper layer protocol if it is not calculated due to lack of
 | 
						|
    // IPv6 source address.
 | 
						|
    //
 | 
						|
    PacketChecksum = NetbufChecksum (Packet);
 | 
						|
    PseudoChecksum = NetIp6PseudoHeadChecksum (
 | 
						|
                       &Head->SourceAddress,
 | 
						|
                       &Head->DestinationAddress,
 | 
						|
                       NextHeader,
 | 
						|
                       Packet->TotalSize
 | 
						|
                       );
 | 
						|
    *Checksum = (UINT16) ~NetAddChecksum (PacketChecksum, PseudoChecksum);
 | 
						|
  }
 | 
						|
 | 
						|
  Status = Ip6IpSecProcessPacket (
 | 
						|
             IpSb,
 | 
						|
             &Head,
 | 
						|
             LastHeader, // no need get the lasthead value for output
 | 
						|
             &Packet,
 | 
						|
             &ExtHdrs,
 | 
						|
             &ExtHdrsLen,
 | 
						|
             EfiIPsecOutBound,
 | 
						|
             Context
 | 
						|
             );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  LastHeader = NULL;
 | 
						|
  //
 | 
						|
  // Check incoming parameters.
 | 
						|
  //
 | 
						|
  if (!Ip6IsExtsValid (
 | 
						|
         IpSb,
 | 
						|
         Packet,
 | 
						|
         &Head->NextHeader,
 | 
						|
         ExtHdrs,
 | 
						|
         ExtHdrsLen,
 | 
						|
         FALSE,
 | 
						|
         NULL,
 | 
						|
         &LastHeader,
 | 
						|
         &RealExtLen,
 | 
						|
         &UnFragmentHdrsLen,
 | 
						|
         NULL
 | 
						|
         ))
 | 
						|
  {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((RealExtLen & 0x7) != 0) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  LastHeaderBackup = *LastHeader;
 | 
						|
 | 
						|
  //
 | 
						|
  // Perform next hop determination:
 | 
						|
  // For multicast packets, the next-hop is always the destination address and
 | 
						|
  // is considered to be on-link.
 | 
						|
  //
 | 
						|
  if (IP6_IS_MULTICAST (&Head->DestinationAddress)) {
 | 
						|
    IP6_COPY_ADDRESS (&NextHop, &Head->DestinationAddress);
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // For unicast packets, use a combination of the Destination Cache, the Prefix List
 | 
						|
    // and the Default Router List to determine the IP address of the appropriate next hop.
 | 
						|
    //
 | 
						|
 | 
						|
    NeighborCache = Ip6FindNeighborEntry (IpSb, &Head->DestinationAddress);
 | 
						|
    if (NeighborCache != NULL) {
 | 
						|
      //
 | 
						|
      // Hit Neighbor Cache.
 | 
						|
      //
 | 
						|
      IP6_COPY_ADDRESS (&NextHop, &Head->DestinationAddress);
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // Not in Neighbor Cache, check Router cache
 | 
						|
      //
 | 
						|
      RouteCache = Ip6Route (IpSb, &Head->DestinationAddress, &Head->SourceAddress);
 | 
						|
      if (RouteCache == NULL) {
 | 
						|
        return EFI_NOT_FOUND;
 | 
						|
      }
 | 
						|
 | 
						|
      IP6_COPY_ADDRESS (&NextHop, &RouteCache->NextHop);
 | 
						|
      Ip6FreeRouteCacheEntry (RouteCache);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Examines the Neighbor Cache for link-layer information about that neighbor.
 | 
						|
  // DO NOT create neighbor cache if neighbor is itself - when reporting ICMP error.
 | 
						|
  //
 | 
						|
  if (!IP6_IS_MULTICAST (&NextHop) && !EFI_IP6_EQUAL (&Head->DestinationAddress, &Head->SourceAddress)) {
 | 
						|
    NeighborCache = Ip6FindNeighborEntry (IpSb, &NextHop);
 | 
						|
    if (NeighborCache == NULL) {
 | 
						|
      NeighborCache = Ip6CreateNeighborEntry (IpSb, Ip6OnArpResolved, &NextHop, NULL);
 | 
						|
 | 
						|
      if (NeighborCache == NULL) {
 | 
						|
        return EFI_OUT_OF_RESOURCES;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Send out multicast neighbor solicitation for address resolution immediately.
 | 
						|
      //
 | 
						|
      Ip6CreateSNMulticastAddr (&NeighborCache->Neighbor, &Destination);
 | 
						|
      Status = Ip6SelectSourceAddress (IpSb, &NeighborCache->Neighbor, &Source);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        return Status;
 | 
						|
      }
 | 
						|
 | 
						|
      Status = Ip6SendNeighborSolicit (
 | 
						|
                 IpSb,
 | 
						|
                 &Source,
 | 
						|
                 &Destination,
 | 
						|
                 &NeighborCache->Neighbor,
 | 
						|
                 &IpSb->SnpMode.CurrentAddress
 | 
						|
                 );
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        return Status;
 | 
						|
      }
 | 
						|
 | 
						|
      --NeighborCache->Transmit;
 | 
						|
      NeighborCache->Ticks = IP6_GET_TICKS (IpSb->RetransTimer) + 1;
 | 
						|
    }
 | 
						|
 | 
						|
    NeighborCache->Interface = IpIf;
 | 
						|
  }
 | 
						|
 | 
						|
  UpdatedExtHdrs       = NULL;
 | 
						|
  ExtHdrsBackup        = NULL;
 | 
						|
  NextHeaderBackup     = 0;
 | 
						|
  FragmentHeadInserted = FALSE;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check whether we received Packet Too Big message for the packet sent to the
 | 
						|
  // Destination. If yes include a Fragment Header in the subsequent packets.
 | 
						|
  //
 | 
						|
  RouteEntry = Ip6FindRouteEntry (
 | 
						|
                 IpSb->RouteTable,
 | 
						|
                 &Head->DestinationAddress,
 | 
						|
                 NULL
 | 
						|
                 );
 | 
						|
  if (RouteEntry != NULL) {
 | 
						|
    if ((RouteEntry->Flag & IP6_PACKET_TOO_BIG) == IP6_PACKET_TOO_BIG) {
 | 
						|
      //
 | 
						|
      // FragmentHead is inserted after Hop-by-Hop Options header, Destination
 | 
						|
      // Options header (first occur), Routing header, and before Fragment header,
 | 
						|
      // Authentication header, Encapsulating Security Payload header, and
 | 
						|
      // Destination Options header (last occur), and upper-layer header.
 | 
						|
      //
 | 
						|
      Status = Ip6FillFragmentHeader (
 | 
						|
                 IpSb,
 | 
						|
                 Head->NextHeader,
 | 
						|
                 LastHeaderBackup,
 | 
						|
                 ExtHdrs,
 | 
						|
                 ExtHdrsLen,
 | 
						|
                 0,
 | 
						|
                 &UpdatedExtHdrs
 | 
						|
                 );
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        return Status;
 | 
						|
      }
 | 
						|
 | 
						|
      if ((ExtHdrs == NULL) && (ExtHdrsLen == 0)) {
 | 
						|
        NextHeaderBackup = Head->NextHeader;
 | 
						|
        Head->NextHeader = IP6_FRAGMENT;
 | 
						|
      }
 | 
						|
 | 
						|
      ExtHdrsBackup = ExtHdrs;
 | 
						|
      ExtHdrs       = UpdatedExtHdrs;
 | 
						|
      ExtHdrsLen    = ExtHdrsLen + sizeof (IP6_FRAGMENT_HEADER);
 | 
						|
      RealExtLen    = RealExtLen + sizeof (IP6_FRAGMENT_HEADER);
 | 
						|
 | 
						|
      mIp6Id++;
 | 
						|
 | 
						|
      FragmentHeadInserted = TRUE;
 | 
						|
    }
 | 
						|
 | 
						|
    Ip6FreeRouteEntry (RouteEntry);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // OK, selected the source and route, fragment the packet then send
 | 
						|
  // them. Tag each fragment other than the first one as spawn from it.
 | 
						|
  // Each extension header is an integer multiple of 8 octets long, in
 | 
						|
  // order to retain 8-octet alignment for subsequent headers.
 | 
						|
  //
 | 
						|
  Mtu     = IpSb->MaxPacketSize + sizeof (EFI_IP6_HEADER);
 | 
						|
  HeadLen = sizeof (EFI_IP6_HEADER) + RealExtLen;
 | 
						|
 | 
						|
  if (Packet->TotalSize + HeadLen > Mtu) {
 | 
						|
    //
 | 
						|
    // Remove the inserted Fragment Header since we need fragment the packet.
 | 
						|
    //
 | 
						|
    if (FragmentHeadInserted) {
 | 
						|
      ExtHdrs    = ExtHdrsBackup;
 | 
						|
      ExtHdrsLen = ExtHdrsLen - sizeof (IP6_FRAGMENT_HEADER);
 | 
						|
 | 
						|
      if ((ExtHdrs == NULL) && (ExtHdrsLen == 0)) {
 | 
						|
        Head->NextHeader = NextHeaderBackup;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    FragmentHdrsLen = ExtHdrsLen - UnFragmentHdrsLen;
 | 
						|
 | 
						|
    //
 | 
						|
    // The packet is beyond the maximum which can be described through the
 | 
						|
    // fragment offset field in Fragment header.
 | 
						|
    //
 | 
						|
    if ((((Packet->TotalSize + FragmentHdrsLen) >> 3) & (~0x1fff)) != 0) {
 | 
						|
      Status = EFI_BAD_BUFFER_SIZE;
 | 
						|
      goto Error;
 | 
						|
    }
 | 
						|
 | 
						|
    if (FragmentHdrsLen != 0) {
 | 
						|
      //
 | 
						|
      // Append the fragmentable extension hdrs before the upper layer payload
 | 
						|
      // to form a new NET_BUF. This NET_BUF contains all the buffer which will
 | 
						|
      // be fragmented below.
 | 
						|
      //
 | 
						|
      TmpPacket = NetbufGetFragment (Packet, 0, Packet->TotalSize, FragmentHdrsLen);
 | 
						|
      ASSERT (TmpPacket != NULL);
 | 
						|
 | 
						|
      //
 | 
						|
      // Allocate the space to contain the fragmentable hdrs and copy the data.
 | 
						|
      //
 | 
						|
      Buf = NetbufAllocSpace (TmpPacket, FragmentHdrsLen, TRUE);
 | 
						|
      ASSERT (Buf != NULL);
 | 
						|
      CopyMem (Buf, ExtHdrs + UnFragmentHdrsLen, FragmentHdrsLen);
 | 
						|
 | 
						|
      //
 | 
						|
      // Free the old Packet.
 | 
						|
      //
 | 
						|
      NetbufFree (Packet);
 | 
						|
      Packet = TmpPacket;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // The unfragment part which appears in every fragmented IPv6 packet includes
 | 
						|
    // the IPv6 header, the unfragmentable extension hdrs and the fragment header.
 | 
						|
    //
 | 
						|
    UnFragmentLen = sizeof (EFI_IP6_HEADER) + UnFragmentHdrsLen + sizeof (IP6_FRAGMENT_HEADER);
 | 
						|
 | 
						|
    //
 | 
						|
    // Mtu now is the length of the fragment part in a full-length fragment.
 | 
						|
    //
 | 
						|
    Mtu = (Mtu - UnFragmentLen) & (~0x07);
 | 
						|
    Num = (Packet->TotalSize + Mtu - 1) / Mtu;
 | 
						|
 | 
						|
    for (Index = 0, Offset = 0, PacketLen = Mtu; Index < Num; Index++) {
 | 
						|
      //
 | 
						|
      // Get fragment from the Packet, append UnFragmentLen spare buffer
 | 
						|
      // before the fragmented data, the corresponding data is filled in later.
 | 
						|
      //
 | 
						|
      Fragment = NetbufGetFragment (Packet, Offset, PacketLen, UnFragmentLen);
 | 
						|
      if (Fragment == NULL) {
 | 
						|
        Status = EFI_OUT_OF_RESOURCES;
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
 | 
						|
      FragmentOffset = (UINT16)((UINT16)Offset | 0x1);
 | 
						|
      if (Index == Num - 1) {
 | 
						|
        //
 | 
						|
        // The last fragment, clear the M flag.
 | 
						|
        //
 | 
						|
        FragmentOffset &= (~0x1);
 | 
						|
      }
 | 
						|
 | 
						|
      Status = Ip6PrependHead (
 | 
						|
                 IpSb,
 | 
						|
                 Fragment,
 | 
						|
                 Head,
 | 
						|
                 FragmentOffset,
 | 
						|
                 ExtHdrs,
 | 
						|
                 ExtHdrsLen,
 | 
						|
                 LastHeaderBackup,
 | 
						|
                 UnFragmentLen
 | 
						|
                 );
 | 
						|
      ASSERT (Status == EFI_SUCCESS);
 | 
						|
 | 
						|
      Status = Ip6SendFrame (
 | 
						|
                 IpIf,
 | 
						|
                 IpInstance,
 | 
						|
                 Fragment,
 | 
						|
                 &NextHop,
 | 
						|
                 Ip6SysPacketSent,
 | 
						|
                 Packet
 | 
						|
                 );
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        goto Error;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // The last fragment of upper layer packet, update the IP6 token status.
 | 
						|
      //
 | 
						|
      if ((Index == Num -1) && (Context != NULL)) {
 | 
						|
        Wrap                = (IP6_TXTOKEN_WRAP *)Context;
 | 
						|
        Wrap->Token->Status = Status;
 | 
						|
      }
 | 
						|
 | 
						|
      Offset   += PacketLen;
 | 
						|
      PacketLen = Packet->TotalSize - Offset;
 | 
						|
      if (PacketLen > Mtu) {
 | 
						|
        PacketLen = Mtu;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    NetbufFree (Packet);
 | 
						|
    mIp6Id++;
 | 
						|
 | 
						|
    if (UpdatedExtHdrs != NULL) {
 | 
						|
      FreePool (UpdatedExtHdrs);
 | 
						|
    }
 | 
						|
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Need not fragment the packet, send it in one frame.
 | 
						|
  //
 | 
						|
  PacketHead = (EFI_IP6_HEADER *)NetbufAllocSpace (Packet, HeadLen, NET_BUF_HEAD);
 | 
						|
  if (PacketHead == NULL) {
 | 
						|
    Status = EFI_BAD_BUFFER_SIZE;
 | 
						|
    goto Error;
 | 
						|
  }
 | 
						|
 | 
						|
  CopyMem (PacketHead, Head, sizeof (EFI_IP6_HEADER));
 | 
						|
  Packet->Ip.Ip6 = PacketHead;
 | 
						|
 | 
						|
  if (ExtHdrs != NULL) {
 | 
						|
    Buf = (UINT8 *)(PacketHead + 1);
 | 
						|
    CopyMem (Buf, ExtHdrs, ExtHdrsLen);
 | 
						|
  }
 | 
						|
 | 
						|
  if (UpdatedExtHdrs != NULL) {
 | 
						|
    //
 | 
						|
    // A Fragment Header is inserted to the packet, update the payload length.
 | 
						|
    //
 | 
						|
    PacketHead->PayloadLength = (UINT16)(NTOHS (PacketHead->PayloadLength) +
 | 
						|
                                         sizeof (IP6_FRAGMENT_HEADER));
 | 
						|
    PacketHead->PayloadLength = HTONS (PacketHead->PayloadLength);
 | 
						|
    FreePool (UpdatedExtHdrs);
 | 
						|
  }
 | 
						|
 | 
						|
  return Ip6SendFrame (
 | 
						|
           IpIf,
 | 
						|
           IpInstance,
 | 
						|
           Packet,
 | 
						|
           &NextHop,
 | 
						|
           Callback,
 | 
						|
           Context
 | 
						|
           );
 | 
						|
 | 
						|
Error:
 | 
						|
  if (UpdatedExtHdrs != NULL) {
 | 
						|
    FreePool (UpdatedExtHdrs);
 | 
						|
  }
 | 
						|
 | 
						|
  Ip6CancelPacket (IpIf, Packet, Status);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  The filter function to find a packet and all its fragments.
 | 
						|
  The packet's fragments have their Context set to the packet.
 | 
						|
 | 
						|
  @param[in]  Frame            The frames hold by the low level interface.
 | 
						|
  @param[in]  Context          Context to the function, which is the packet.
 | 
						|
 | 
						|
  @retval TRUE                 This is the packet to cancel or its fragments.
 | 
						|
  @retval FALSE                This is an unrelated packet.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
Ip6CancelPacketFragments (
 | 
						|
  IN IP6_LINK_TX_TOKEN  *Frame,
 | 
						|
  IN VOID               *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  if ((Frame->Packet == (NET_BUF *)Context) || (Frame->Context == Context)) {
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  return FALSE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Remove all the frames on the interface that pass the FrameToCancel,
 | 
						|
  either queued on ARP queues or that have already been delivered to
 | 
						|
  MNP and not yet recycled.
 | 
						|
 | 
						|
  @param[in]  Interface     Interface to remove the frames from.
 | 
						|
  @param[in]  IoStatus      The transmit status returned to the frames' callback.
 | 
						|
  @param[in]  FrameToCancel Function to select the frame to cancel; NULL to select all.
 | 
						|
  @param[in]  Context       Opaque parameters passed to FrameToCancel. Ignored if
 | 
						|
                            FrameToCancel is NULL.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
Ip6CancelFrames (
 | 
						|
  IN IP6_INTERFACE        *Interface,
 | 
						|
  IN EFI_STATUS           IoStatus,
 | 
						|
  IN IP6_FRAME_TO_CANCEL  FrameToCancel   OPTIONAL,
 | 
						|
  IN VOID                 *Context        OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  LIST_ENTRY          *Entry;
 | 
						|
  LIST_ENTRY          *Next;
 | 
						|
  IP6_LINK_TX_TOKEN   *Token;
 | 
						|
  IP6_SERVICE         *IpSb;
 | 
						|
  IP6_NEIGHBOR_ENTRY  *ArpQue;
 | 
						|
  EFI_STATUS          Status;
 | 
						|
 | 
						|
  IpSb = Interface->Service;
 | 
						|
  NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
 | 
						|
 | 
						|
  //
 | 
						|
  // Cancel all the pending frames on ARP requests
 | 
						|
  //
 | 
						|
  NET_LIST_FOR_EACH_SAFE (Entry, Next, &Interface->ArpQues) {
 | 
						|
    ArpQue = NET_LIST_USER_STRUCT (Entry, IP6_NEIGHBOR_ENTRY, ArpList);
 | 
						|
 | 
						|
    Status = Ip6FreeNeighborEntry (
 | 
						|
               IpSb,
 | 
						|
               ArpQue,
 | 
						|
               FALSE,
 | 
						|
               FALSE,
 | 
						|
               IoStatus,
 | 
						|
               FrameToCancel,
 | 
						|
               Context
 | 
						|
               );
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Cancel all the frames that have been delivered to MNP
 | 
						|
  // but not yet recycled.
 | 
						|
  //
 | 
						|
  NET_LIST_FOR_EACH_SAFE (Entry, Next, &Interface->SentFrames) {
 | 
						|
    Token = NET_LIST_USER_STRUCT (Entry, IP6_LINK_TX_TOKEN, Link);
 | 
						|
 | 
						|
    if ((FrameToCancel == NULL) || FrameToCancel (Token, Context)) {
 | 
						|
      IpSb->Mnp->Cancel (IpSb->Mnp, &Token->MnpToken);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Cancel the Packet and all its fragments.
 | 
						|
 | 
						|
  @param[in]  IpIf                 The interface from which the Packet is sent.
 | 
						|
  @param[in]  Packet               The Packet to cancel.
 | 
						|
  @param[in]  IoStatus             The status returns to the sender.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
Ip6CancelPacket (
 | 
						|
  IN IP6_INTERFACE  *IpIf,
 | 
						|
  IN NET_BUF        *Packet,
 | 
						|
  IN EFI_STATUS     IoStatus
 | 
						|
  )
 | 
						|
{
 | 
						|
  Ip6CancelFrames (IpIf, IoStatus, Ip6CancelPacketFragments, Packet);
 | 
						|
}
 |