diff options
Diffstat (limited to 'Core/NetworkPkg/Ip6Dxe/Ip6Output.c')
-rw-r--r-- | Core/NetworkPkg/Ip6Dxe/Ip6Output.c | 1091 |
1 files changed, 0 insertions, 1091 deletions
diff --git a/Core/NetworkPkg/Ip6Dxe/Ip6Output.c b/Core/NetworkPkg/Ip6Dxe/Ip6Output.c deleted file mode 100644 index 8330e37935..0000000000 --- a/Core/NetworkPkg/Ip6Dxe/Ip6Output.c +++ /dev/null @@ -1,1091 +0,0 @@ -/** @file
- The internal functions and routines to transmit the IP6 packet.
-
- Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
-
- This program and the accompanying materials
- are licensed and made available under the terms and conditions of the BSD License
- which accompanies this distribution. The full text of the license may be found at
- http://opensource.org/licenses/bsd-license.php.
-
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
-
-**/
-
-#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 UnFragnmentLen 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);
-}
-
|