git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@4693 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			373 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			373 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
| 
 | |
| Copyright (c) 2005 - 2006, Intel Corporation
 | |
| All rights reserved. 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.
 | |
| 
 | |
| 
 | |
| Module Name:
 | |
| 
 | |
|   Ip4Icmp.c
 | |
| 
 | |
| Abstract:
 | |
| 
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "Ip4Impl.h"
 | |
| 
 | |
| IP4_ICMP_CLASS
 | |
| mIcmpClass[] = {
 | |
|   {ICMP_ECHO_REPLY,         ICMP_QUERY_MESSAGE  },
 | |
|   {1,                       ICMP_INVALID_MESSAGE},
 | |
|   {2,                       ICMP_INVALID_MESSAGE},
 | |
|   {ICMP_DEST_UNREACHABLE,   ICMP_ERROR_MESSAGE  },
 | |
|   {ICMP_SOURCE_QUENCH,      ICMP_ERROR_MESSAGE  },
 | |
|   {ICMP_REDIRECT,           ICMP_ERROR_MESSAGE  },
 | |
|   {6,                       ICMP_INVALID_MESSAGE},
 | |
|   {7,                       ICMP_INVALID_MESSAGE},
 | |
|   {ICMP_ECHO_REQUEST,       ICMP_QUERY_MESSAGE  },
 | |
|   {9,                       ICMP_INVALID_MESSAGE},
 | |
|   {10,                      ICMP_INVALID_MESSAGE},
 | |
|   {ICMP_TIME_EXCEEDED,      ICMP_ERROR_MESSAGE  },
 | |
|   {ICMP_PARAMETER_PROBLEM,  ICMP_ERROR_MESSAGE  },
 | |
|   {ICMP_TIMESTAMP ,         ICMP_QUERY_MESSAGE  },
 | |
|   {14,                      ICMP_INVALID_MESSAGE},
 | |
|   {ICMP_INFO_REQUEST ,      ICMP_QUERY_MESSAGE  },
 | |
|   {ICMP_INFO_REPLY ,        ICMP_QUERY_MESSAGE  },
 | |
| };
 | |
| 
 | |
| EFI_IP4_ICMP_TYPE
 | |
| mIp4SupportedIcmp [23] = {
 | |
|   {ICMP_ECHO_REPLY,        ICMP_DEFAULT_CODE      },
 | |
| 
 | |
|   {ICMP_DEST_UNREACHABLE,  ICMP_NET_UNREACHABLE   },
 | |
|   {ICMP_DEST_UNREACHABLE,  ICMP_HOST_UNREACHABLE  },
 | |
|   {ICMP_DEST_UNREACHABLE,  ICMP_PROTO_UNREACHABLE },
 | |
|   {ICMP_DEST_UNREACHABLE,  ICMP_PORT_UNREACHABLE  },
 | |
|   {ICMP_DEST_UNREACHABLE,  ICMP_FRAGMENT_FAILED   },
 | |
|   {ICMP_DEST_UNREACHABLE,  ICMP_SOURCEROUTE_FAILED},
 | |
|   {ICMP_DEST_UNREACHABLE,  ICMP_NET_UNKNOWN       },
 | |
|   {ICMP_DEST_UNREACHABLE,  ICMP_HOST_UNKNOWN      },
 | |
|   {ICMP_DEST_UNREACHABLE,  ICMP_SOURCE_ISOLATED   },
 | |
|   {ICMP_DEST_UNREACHABLE,  ICMP_NET_PROHIBITED    },
 | |
|   {ICMP_DEST_UNREACHABLE,  ICMP_HOST_PROHIBITED   },
 | |
|   {ICMP_DEST_UNREACHABLE,  ICMP_NET_UNREACHABLE_TOS },
 | |
|   {ICMP_DEST_UNREACHABLE,  ICMP_HOST_UNREACHABLE_TOS},
 | |
| 
 | |
|   {ICMP_SOURCE_QUENCH,     ICMP_DEFAULT_CODE      },
 | |
| 
 | |
|   {ICMP_REDIRECT,          ICMP_NET_REDIRECT      },
 | |
|   {ICMP_REDIRECT,          ICMP_HOST_REDIRECT     },
 | |
|   {ICMP_REDIRECT,          ICMP_NET_TOS_REDIRECT  },
 | |
|   {ICMP_REDIRECT,          ICMP_HOST_TOS_REDIRECT },
 | |
| 
 | |
|   {ICMP_ECHO_REQUEST,      ICMP_DEFAULT_CODE      },
 | |
| 
 | |
|   {ICMP_TIME_EXCEEDED,     ICMP_TIMEOUT_IN_TRANSIT},
 | |
|   {ICMP_TIME_EXCEEDED,     ICMp_TIMEOUT_REASSEMBLE},
 | |
| 
 | |
|   {ICMP_PARAMETER_PROBLEM, ICMP_DEFAULT_CODE      },
 | |
| };
 | |
| 
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Process the ICMP redirect. Find the instance then update
 | |
|   its route cache.
 | |
|   All kinds of redirect is treated as host redirect as
 | |
|   specified by RFC1122 3.3.1.2:
 | |
|   "Since the subnet mask appropriate to the destination
 | |
|   address is generally not known, a Network Redirect
 | |
|   message SHOULD be treated identically to a Host Redirect
 | |
|   message;"
 | |
| 
 | |
|   @param  IpSb                   The IP4 service binding instance that received the
 | |
|                                  packet
 | |
|   @param  Head                   The IP head of the received ICMPpacket.
 | |
|   @param  Packet                 The content of the ICMP redirect packet with IP
 | |
|                                  head removed.
 | |
|   @param  Icmp                   The buffer to store the ICMP error message if
 | |
|                                  something is wrong.
 | |
| 
 | |
|   @retval EFI_INVALID_PARAMETER  The parameter is invalid
 | |
|   @retval EFI_SUCCESS            Successfully updated the route caches
 | |
| 
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| Ip4ProcessIcmpRedirect (
 | |
|   IN IP4_SERVICE            *IpSb,
 | |
|   IN IP4_HEAD               *Head,
 | |
|   IN NET_BUF                *Packet,
 | |
|   IN IP4_ICMP_ERROR_HEAD    *Icmp
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY                *Entry;
 | |
|   IP4_PROTOCOL              *Ip4Instance;
 | |
|   IP4_ROUTE_CACHE_ENTRY     *CacheEntry;
 | |
|   IP4_INTERFACE             *IpIf;
 | |
|   IP4_ADDR                  Gateway;
 | |
| 
 | |
|   //
 | |
|   // Find the interface whose IP address is the source of the
 | |
|   // orgianl IP packet.
 | |
|   //
 | |
|   IpIf    = Ip4FindInterface (IpSb, NTOHL (Icmp->IpHead.Src));
 | |
|   Gateway = NTOHL (Icmp->Fourth);
 | |
| 
 | |
|   //
 | |
|   // discard the packet if the new gateway address it specifies
 | |
|   // is not on the same connected net through which the Redirect
 | |
|   // arrived. (RFC1122 3.2.2.2).
 | |
|   //
 | |
|   if ((IpIf == NULL) || !IP4_NET_EQUAL (Gateway, IpIf->Ip, IpIf->SubnetMask)) {
 | |
|     NetbufFree (Packet);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Update each IP child's route cache on the interface.
 | |
|   //
 | |
|   NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {
 | |
|     Ip4Instance = NET_LIST_USER_STRUCT (Entry, IP4_PROTOCOL, AddrLink);
 | |
| 
 | |
|     if (Ip4Instance->RouteTable == NULL) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     CacheEntry = Ip4FindRouteCache (
 | |
|                    Ip4Instance->RouteTable,
 | |
|                    NTOHL (Icmp->IpHead.Dst),
 | |
|                    NTOHL (Icmp->IpHead.Src)
 | |
|                    );
 | |
| 
 | |
|     //
 | |
|     // Only update the route cache's gateway if the source of the
 | |
|     // Redirect is the current first-hop gateway
 | |
|     //
 | |
|     if ((CacheEntry != NULL) && (NTOHL (Head->Src) == CacheEntry->NextHop)) {
 | |
|       CacheEntry->NextHop = Gateway;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   NetbufFree (Packet);
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Process the ICMP error packet. If it is an ICMP redirect packet,
 | |
|   update call Ip4ProcessIcmpRedirect to update the IP instance's
 | |
|   route cache, otherwise, deliver the packet to upper layer.
 | |
| 
 | |
|   @param  IpSb                   The IP service that received the packet.
 | |
|   @param  Head                   The IP head of the ICMP error packet
 | |
|   @param  Packet                 The content of the ICMP error with IP head
 | |
|                                  removed.
 | |
| 
 | |
|   @retval EFI_INVALID_PARAMETER  The packet is invalid
 | |
|   @retval Others                 Failed to process the packet.
 | |
|   @retval EFI_SUCCESS            The ICMP error is processed successfully.
 | |
| 
 | |
| **/
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| Ip4ProcessIcmpError (
 | |
|   IN IP4_SERVICE            *IpSb,
 | |
|   IN IP4_HEAD               *Head,
 | |
|   IN NET_BUF                *Packet
 | |
|   )
 | |
| {
 | |
|   IP4_ICMP_ERROR_HEAD       Icmp;
 | |
| 
 | |
|   if (Packet->TotalSize < sizeof (Icmp)) {
 | |
|     NetbufFree (Packet);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
 | |
| 
 | |
|   //
 | |
|   // If it is an ICMP redirect error, update the route cache
 | |
|   // as RFC1122. Otherwise, demultiplex it to IP instances.
 | |
|   //
 | |
|   if (Icmp.Head.Type == ICMP_REDIRECT) {
 | |
|     return Ip4ProcessIcmpRedirect (IpSb, Head, Packet, &Icmp);
 | |
|   }
 | |
| 
 | |
|   IP4_GET_CLIP_INFO (Packet)->Status = EFI_ICMP_ERROR;
 | |
|   return Ip4Demultiplex (IpSb, Head, Packet);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Replay an ICMP echo request.
 | |
| 
 | |
|   @param  IpSb                   The IP service that receivd the packet
 | |
|   @param  Head                   The IP head of the ICMP error packet
 | |
|   @param  Packet                 The content of the ICMP error with IP head
 | |
|                                  removed.
 | |
| 
 | |
|   @retval EFI_OUT_OF_RESOURCES   Failed to allocate resource.
 | |
|   @retval EFI_SUCCESS            The ICMP Echo request is successfully answered.
 | |
|   @retval Others                 Failed to answer the ICMP echo request.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| Ip4IcmpReplyEcho (
 | |
|   IN IP4_SERVICE            *IpSb,
 | |
|   IN IP4_HEAD               *Head,
 | |
|   IN NET_BUF                *Packet
 | |
|   )
 | |
| {
 | |
|   IP4_ICMP_QUERY_HEAD       *Icmp;
 | |
|   NET_BUF                   *Data;
 | |
|   EFI_STATUS                Status;
 | |
|   IP4_HEAD                  ReplyHead;
 | |
| 
 | |
|   //
 | |
|   // make a copy the packet, it is really a bad idea to
 | |
|   // send the MNP's buffer back to MNP.
 | |
|   //
 | |
|   Data = NetbufDuplicate (Packet, NULL, IP4_MAX_HEADLEN);
 | |
| 
 | |
|   if (Data == NULL) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Change the ICMP type to echo reply, exchange the source
 | |
|   // and destination, then send it. The source is updated to
 | |
|   // use specific destination. See RFC1122. SRR/RR option
 | |
|   // update is omitted.
 | |
|   //
 | |
|   Icmp                = (IP4_ICMP_QUERY_HEAD *) NetbufGetByte (Data, 0, NULL);
 | |
|   Icmp->Head.Type     = ICMP_ECHO_REPLY;
 | |
|   Icmp->Head.Checksum = 0;
 | |
|   Icmp->Head.Checksum = (UINT16) (~NetblockChecksum ((UINT8 *) Icmp, Data->TotalSize));
 | |
| 
 | |
|   ReplyHead.Tos       = 0;
 | |
|   ReplyHead.Fragment  = 0;
 | |
|   ReplyHead.Ttl       = 64;
 | |
|   ReplyHead.Protocol  = IP4_PROTO_ICMP;
 | |
|   ReplyHead.Src       = 0;
 | |
| 
 | |
|   //
 | |
|   // Ip4Output will select a source for us
 | |
|   //
 | |
|   ReplyHead.Dst = Head->Src;
 | |
| 
 | |
|   Status = Ip4Output (
 | |
|              IpSb,
 | |
|              NULL,
 | |
|              Data,
 | |
|              &ReplyHead,
 | |
|              NULL,
 | |
|              0,
 | |
|              IP4_ALLZERO_ADDRESS,
 | |
|              Ip4SysPacketSent,
 | |
|              NULL
 | |
|              );
 | |
| 
 | |
| ON_EXIT:
 | |
|   NetbufFree (Packet);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Process the ICMP query message. If it is an ICMP echo
 | |
|   request, answer it. Otherwise deliver it to upper layer.
 | |
| 
 | |
|   @param  IpSb                   The IP service that receivd the packet
 | |
|   @param  Head                   The IP head of the ICMP query packet
 | |
|   @param  Packet                 The content of the ICMP query with IP head
 | |
|                                  removed.
 | |
| 
 | |
|   @retval EFI_INVALID_PARAMETER  The packet is invalid
 | |
|   @retval EFI_SUCCESS            The ICMP query message is processed
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| Ip4ProcessIcmpQuery (
 | |
|   IN IP4_SERVICE            *IpSb,
 | |
|   IN IP4_HEAD               *Head,
 | |
|   IN NET_BUF                *Packet
 | |
|   )
 | |
| {
 | |
|   IP4_ICMP_QUERY_HEAD       Icmp;
 | |
| 
 | |
|   if (Packet->TotalSize < sizeof (Icmp)) {
 | |
|     NetbufFree (Packet);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
 | |
| 
 | |
|   if (Icmp.Head.Type == ICMP_ECHO_REQUEST) {
 | |
|     return Ip4IcmpReplyEcho (IpSb, Head, Packet);
 | |
|   }
 | |
| 
 | |
|   return Ip4Demultiplex (IpSb, Head, Packet);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Handle the ICMP packet. First validate the message format,
 | |
|   then according to the message types, process it as query or
 | |
|   error packet.
 | |
| 
 | |
|   @param  IpSb                   The IP service that receivd the packet
 | |
|   @param  Head                   The IP head of the ICMP query packet
 | |
|   @param  Packet                 The content of the ICMP query with IP head
 | |
|                                  removed.
 | |
| 
 | |
|   @retval EFI_INVALID_PARAMETER  The packet is malformated.
 | |
|   @retval EFI_SUCCESS            The ICMP message is successfully processed.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| Ip4IcmpHandle (
 | |
|   IN IP4_SERVICE            *IpSb,
 | |
|   IN IP4_HEAD               *Head,
 | |
|   IN NET_BUF                *Packet
 | |
|   )
 | |
| {
 | |
|   IP4_ICMP_HEAD             Icmp;
 | |
|   UINT16                    Checksum;
 | |
| 
 | |
|   if (Packet->TotalSize < sizeof (Icmp)) {
 | |
|     goto DROP;
 | |
|   }
 | |
| 
 | |
|   NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
 | |
| 
 | |
|   if (Icmp.Type > ICMP_TYPE_MAX) {
 | |
|     goto DROP;
 | |
|   }
 | |
| 
 | |
|   Checksum = (UINT16) (~NetbufChecksum (Packet));
 | |
|   if ((Icmp.Checksum != 0) && (Checksum != 0)) {
 | |
|     goto DROP;
 | |
|   }
 | |
| 
 | |
|   if (mIcmpClass[Icmp.Type].IcmpClass == ICMP_ERROR_MESSAGE) {
 | |
|     return Ip4ProcessIcmpError (IpSb, Head, Packet);
 | |
| 
 | |
|   } else if (mIcmpClass[Icmp.Type].IcmpClass == ICMP_QUERY_MESSAGE) {
 | |
|     return Ip4ProcessIcmpQuery (IpSb, Head, Packet);
 | |
| 
 | |
|   }
 | |
| 
 | |
| DROP:
 | |
|   NetbufFree (Packet);
 | |
|   return EFI_INVALID_PARAMETER;
 | |
| }
 |