/*
* Copyright (c) 2006-2007 Graz University of Technology. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The names "Graz University of Technology" and "IAIK of Graz University of
* Technology" must not be used to endorse or promote products derived from
* this software without prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package ejip.jtcpip;
/**
* Interprets a Payload as ICMP packet. See RFC792
*
* @author Ulrich Feichter
* @author Tobias Kellner
* @author Christof Rath
* @version $Rev: 938 $ $Date: 2007/01/24 19:37:07 $
*/
public class ICMPPacket
{
/**
* Returns the ICMP type
*
* @param pay
* @return the type of an ICMP packet
*/
protected static byte getType(Payload pay)
{
return (byte) (pay.payload[0] >> 24);
}
/**
* Sets the ICMP type
*
* @param pay
* @param type
*/
protected static void setType(Payload pay, byte type)
{
pay.payload[0] &= 0x00FFFFFF;
pay.payload[0] |= type << 24;
}
/**
* Returns the code of an ICMP packet. The code is used to specify a certain
* ICMP type (e.g. Type 3 = 'destination unreachable' and Code 1 = 'host
* unreachable' or Code 3 = 'port unreachable'
*
* @param pay
* @return the code of an ICMP packet
*/
protected static byte getCode(Payload pay)
{
return (byte) (pay.payload[0] >> 16);
}
/**
* Sets the ICMP type
*
* @param pay
* @param code
*/
protected static void setCode(Payload pay, int code)
{
pay.payload[0] &= 0xFF00FFFF;
pay.payload[0] |= (code & 0xFF) << 16;
}
/**
* Get the Header Checksum. The checksum is calculated over the ICMP header
* and the data. The value is read from the ICMP header.
*
* @param pay
* The Payload
* @return The Header Checksum
*/
public static short getChecksum(Payload pay)
{
return (short) (pay.payload[0] & 0xFFFF);
}
/**
* Set the Header Checksum to the correct value. The checksum is calculated
* over the UDP header (+IP Pseudoheader) and the data (with the checksum
* field set to zero). The calculation is done in
* {@link UDPPacket#calculateChecksum}. The value is set in the UDP header.
*
* @param pay
* The Payload
*/
public static void setChecksum(Payload pay)
{
pay.payload[0] = pay.payload[0] & 0xFFFF0000;
pay.payload[0] = pay.payload[0] | (calculateChecksum(pay) & 0xFFFF);
}
/**
* Calculate the correct Checksum. The checksum is calculated over the ICMP
* header and the data (with the checksum field assumed to be zero).
*
* @param pay
* The Payload
* @return The Checksum
*/
public static short calculateChecksum(Payload pay)
{
// compute over ICMP Header and Payload, except the last bytes which
// don't
// fall on an int boundary
int packetLength = pay.length;
int cnt = packetLength / 4;
int i = 0;
int sum = 0;
int ofs = 0;
while (cnt != 0)
{
i = pay.payload[ofs];
sum += i & 0xFFFF;
sum += i >>> 16;
++ofs;
--cnt;
}
int modulo = packetLength % 4;
if (modulo != 0)
{
i = pay.payload[ofs];
// compute over the last int of the payload
switch (modulo)
{
case 1:
sum += (i >>> 16) & 0xFF00;
break;
case 2:
sum += (i >>> 16) & 0xFFFF;
break;
case 3:
sum += i & 0xFF00;
sum += (i >>> 16) & 0xFFFF;
}
}
while ((sum >> 16) != 0)
sum = (sum & 0xffff) + (sum >> 16);
sum = (~sum) & 0xffff;
return (short) sum;
}
/**
* Capsulates the original IP Datagram as part of some ICMP messages
* <b>Note:</b> The function trucenates the original IP datagram
*
* @param pay
*/
protected static void ipToICMPPacket(Payload pay)
{
int ofs = IPPacket.getIHL(pay);
for (int i = 0; i < 2; i++)
{
pay.payload[ofs + i + 2] = pay.payload[i]; // Two bytes of ICMP
// header...
pay.payload[i] = 0; // Clear the ICMP header fields
}
for (int i = 0; i < ofs; i++)
pay.payload[i + 2] = pay.ipHeader[i];
pay.length = (ofs + 4) * 4;
}
/**
* Restores the original IP Datagram as sent as part of some ICMP messages
* <b>Note:</b> The function destroys the ICMP Datagram
*
* @param pay
*/
protected static void icmpToIPPacket(Payload pay)
{
byte i;
for (i = 2; i < pay.length / 4 - 2; i++)
pay.ipHeader[i - 2] = pay.payload[i];
for (byte j = i; j < pay.length / 4; j++)
pay.payload[j - i] = pay.payload[j];
pay.length -= 8;
}
}