mirror of https://github.com/acidanthera/audk.git
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;
|
|
}
|