/*
* $Id: ICMPPacket.java 5347 2005-05-25 22:45:54Z dfs $
*
* Copyright 2004-2005 Daniel F. Savarese
* Contact Information: http://www.savarese.org/contact.html
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.savarese.org/software/ApacheLicense-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.savarese.vserv.tcpip;
/**
* ICMPPacket extends {@link IPPacket} to handle ICMP packets. The ICMP
* packet structure is described in
* <a href="http://www.ietf.org/rfc/rfc0792.txt?number=792">RFC 792</a>.
*
* @author <a href="http://www.savarese.org/">Daniel F. Savarese</a>
*/
public abstract class ICMPPacket extends IPPacket {
/** Offset into the ICMP packet of the type header value. */
public static final int OFFSET_TYPE = 0;
/** Offset into the ICMP packet of the code header value. */
public static final int OFFSET_CODE = 1;
/** Offset into the ICMP packet of the ICMP checksum. */
public static final int OFFSET_ICMP_CHECKSUM = 2;
/** Offset into the ICMP packet of the identifier header value. */
public static final int OFFSET_IDENTIFIER = 4;
/** Offset into the ICMP packet of the sequence number header value. */
public static final int OFFSET_SEQUENCE = 6;
/** The ICMP type number for an echo request. */
public static final int TYPE_ECHO_REQUEST = 8;
/** The ICMP type number for an echo reply. */
public static final int TYPE_ECHO_REPLY = 0;
/** The byte offset into the IP packet where the ICMP packet begins. */
int _offset;
/**
* Creates a new ICMP packet of a given size.
*
* @param size The number of bytes in the packet.
*/
public ICMPPacket(int size) {
super(size);
_offset = 0;
}
/**
* Creates a new ICMP packet that is a copy of a given packet.
*
* @param packet The packet to replicate.
*/
public ICMPPacket(ICMPPacket packet) {
super(packet.size());
copy(packet);
_offset = packet._offset;
}
/** @return The number of bytes in the ICMP packet header. */
public abstract int getICMPHeaderByteLength();
public void setIPHeaderLength(int length) {
super.setIPHeaderLength(length);
_offset = getIPHeaderByteLength();
}
/**
* @return The total number of bytes in the IP and ICMP headers.
*/
public final int getCombinedHeaderByteLength() {
return _offset + getICMPHeaderByteLength();
}
/**
* Sets the length of the ICMP data payload.
*
* @param length The length of the ICMP data payload in bytes.
*/
public final void setICMPDataByteLength(int length) {
if(length < 0)
length = 0;
setIPPacketLength(getCombinedHeaderByteLength() + length);
}
/**
* @return The number of bytes in the ICMP data payload.
*/
public final int getICMPDataByteLength() {
return getIPPacketLength() - getCombinedHeaderByteLength();
}
/**
* @return The ICMP packet length. This is the size of the IP packet
* minus the size of the IP header.
*/
public final int getICMPPacketByteLength() {
return getIPPacketLength() - _offset;
}
/**
* Copies the contents of an ICMPPacket. If the current data array is
* of insufficient length to store the contents, a new array is
* allocated.
*
* @param packet The TCPPacket to copy.
*/
public final void copyData(ICMPPacket packet) {
if(_data_.length < packet._data_.length) {
byte[] data = new byte[packet._data_.length];
System.arraycopy(_data_, 0, data, 0, getCombinedHeaderByteLength());
_data_ = data;
}
int length = packet.getICMPDataByteLength();
System.arraycopy(packet._data_, packet.getCombinedHeaderByteLength(),
_data_, getCombinedHeaderByteLength(), length);
setICMPDataByteLength(length);
}
public void setData(byte[] data) {
super.setData(data);
_offset = getIPHeaderByteLength();
}
/**
* Sets the ICMP type header field.
*
* @param type The new type.
*/
public final void setType(int type) {
_data_[_offset + OFFSET_TYPE] = (byte)(type & 0xff);
}
/**
* @return The ICMP type header field.
*/
public final int getType() {
return (_data_[_offset + OFFSET_TYPE] & 0xff);
}
/**
* Sets the ICMP code header field.
*
* @param code The new type.
*/
public final void setCode(int code) {
_data_[_offset + OFFSET_CODE] = (byte)(code & 0xff);
}
/**
* @return The ICMP code header field.
*/
public final int getCode() {
return (_data_[_offset + OFFSET_CODE] & 0xff);
}
/**
* @return The ICMP checksum.
*/
public final int getICMPChecksum() {
return (((_data_[_offset + OFFSET_ICMP_CHECKSUM] & 0xff) << 8) |
(_data_[_offset + OFFSET_ICMP_CHECKSUM + 1] & 0xff));
}
/**
* Computes the ICMP checksum, optionally updating the ICMP checksum header.
*
* @param update Specifies whether or not to update the ICMP checksum
* header after computing the checksum. A value of true indicates
* the header should be updated, a value of false indicates it
* should not be updated.
* @return The computed ICMP checksum.
*/
public final int computeICMPChecksum(boolean update) {
return _computeChecksum_(_offset, _offset + OFFSET_ICMP_CHECKSUM,
getIPPacketLength(), 0, update);
}
/**
* Same as <code>computeICMPChecksum(true);</code>
*
* @return The computed ICMP checksum value.
*/
public final int computeICMPChecksum() {
return computeICMPChecksum(true);
}
}