LOGIN   :::   RECOVER PASS   :::   GET ACCOUNT    
Browse
  • Projects
  • Code (CVS)
  • Forums
  • News
  • Articles
  • Polls
  •  
    OpenCores
  • FAQ
  • CVS HowTo
  • Mission
  • Media
  • Tools
  • Advertise
  • Mirrors
  • Logos
  • Contact us
  • Job Opportunity
  •  
    Tools
  • Search
      
  • Download Cores (CVSGet)
  •  
    More
  • Wishbone
  • Perlilog
  • EDA tools
  • OpenTech CD
  •  
    Navigation: All forums > Cvs-checkins > Message List > Message Post

    Message

    Reply | Reply all
    Date Prev | Date Next | Thread Prev | Thread Next Date Index | Thread Index

    From: cvs at opencores.org<cvs@o...>
    Date: Wed Jan 24 20:37:07 CET 2007
    Subject: [cvs-checkins] MODIFIED: jop ...
    Top
    Date: 00/07/01 24:20:37

    Added: jop/java/target/src/common/ejip/jtcpip Bitmap.java
    DatagramPacket.java DatagramSocket.java
    DHCPClient.java ICMP.java ICMPPacket.java IP.java
    IPPacket.java JtcpipException.java
    NwLoopRtThread.java NwLoopThread.java Payload.java
    Socket.java StackParameters.java TCP.java
    TCPConnection.java TCPInputStream.java
    TCPOutputStream.java TCPPacket.java
    TestInputStream.java TestOutputStream.java UDP.java
    UDPConnection.java UDPPacket.java Util.java
    Log:
    move from ejip2 to ejip


    Revision Changes Path
    1.1 jop/java/target/src/common/ejip/jtcpip/Bitmap.java

    http://www.opencores.org/cvsweb.shtml/jop/java/target/src/common/ejip/jtcpip/Bitmap.java?rev=1.1&content-type=text/x-cvsweb-markup

    Index: Bitmap.java
    ===================================================================
    /*
    * 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;

    import ejip.jtcpip.util.Util;

    /**
    * Class to handle Bitmaps
    *
    * @author Ulrich Feichter
    * @author Tobias Kellner
    * @author Christof Rath
    * @version $Rev: 860 $ $Date: 2007/01/24 19:37:07 $
    */
    public class Bitmap
    {
    /** Size of the bitmap in bits */
    int size;

    /** Bit pool */
    byte[] bitmap;

    /**
    * Initalizes the bitmap.
    *
    * @param size
    * Desired number of bits in the bitmap
    */
    public Bitmap(int size)
    {
    this.size = size;
    bitmap = new byte[Util.divRoundUp(size, 8)];
    // if the size doesn't fall onto a byte boundary add another byte
    }

    /**
    * Clears the complete bitmap.
    */
    public void clearBitmap()
    {
    for (int i = 0; i < bitmap.length; i++)
    bitmap[i] = 0;
    }

    /**
    * Sets a single bit in the bitmap.
    *
    * @param pos
    * Position of the bit to set
    */
    public void setBit(int pos) { if (pos < size) bitmap[pos / 8] |= (byte) (1 << (pos % 8)); } /** * Clears a single bit in the bitmap * * @param pos */ public void clearBit(int pos) { if (pos < size) bitmap[pos / 8] &= ~(byte) (1 << (pos % 8)); } /** * Sets multiple bits. Set <code>count</code> bits, starting at * <code>pos</code>. * * @param pos * Position of the first bit to set * @param count * Number of bits to set */ public void setBits(int pos, int count) { if (pos >= size) return; if ((pos + count) >= size) count = (size - pos); if (pos % 8 > 0) // pos doesn'f fall on a byte boundary { // => handle the first bits bit per bit int i; for (i = pos; i < (pos + Math.min(8 - (pos % 8), count)); i++) setBit(i); count -= (i - pos); pos = i; } if (count == 0) return; if (count % 8 > 0) // the last bits do not fall on a byte boundary { // => handle the last bits bit per bit for (int i = (pos + count - (count % 8)); i < (pos + count); i++) setBit(i); count -= (pos + count) % 8; } if (count == 0) return; for (int i = (pos / 8); i < (pos / 8) + (count / 8); i++) // handle the rest (whole bytes in the middle) bitmap[i] = (byte) 0xFF; } /** * Clears multiple bits. Clear <code>count</code> bits, starting at * <code>pos</code>. * * @param pos * Position of the first bit to clear * @param count * Number of bits to clear */ public void clearBits(int pos, int count) { if (pos >= size) return; if ((pos + count) >= size) count = (size - pos); if (pos % 8 > 0) // pos doesn'f fall on a byte boundary { // => handle the first bits bit per bit int i; for (i = pos; i < (pos + Math.min(8 - (pos % 8), count)); i++) clearBit(i); count -= (i - pos); pos = i; } if (count == 0) return; if (count % 8 > 0) // the last bits do not fall on a byte boundary { // => handle the last bits bit per bit for (int i = (pos + count - (count % 8)); i < (pos + count); i++) clearBit(i); count -= (pos + count) % 8; } if (count == 0) return; for (int i = (pos / 8); i < (pos / 8) + (count / 8); i++) // handle the rest (whole bytes in the middle) bitmap[i] = 0; } /** * Check whether a bit at a given position is set. * * @param pos * Position of the bit to check * @return Whether the bit is set */ public boolean isSet(int pos) { if (pos >= size) return false; int i = (byte) (1 << (pos % 8)) & bitmap[pos / 8]; return i != 0; } /** * Tests if all bits of the bitmap are set. * * @return True if all bits are set */ public boolean allSet() { if (size % 8 > 0) // the last byte is not filled by the bitmap { // Set all bits that exceed the bitmap to 1 int i = 0xFF << (size % 8); bitmap[bitmap.length - 1] |= i; } for (int i = 0; i < bitmap.length; i++) if (bitmap[i] != (byte) 0xFF) return false; return true; } /** * Tests if all bits of the bitmap until a certain position are set. * * @param until * Number of bits to check from the start * @return True if all bits until <code>until</code> are set */ public boolean allSet(int until) { if (until >= size) return allSet(); for (int i = 0; i < until / 8; i++) if (bitmap[i] != (byte) 0xFF) return false; if (until % 8 > 0) // the last byte is not filled by the bitmap { // Set all bits that ecxeed the bitmap to 1 byte b = bitmap[until / 8]; int m = 0xFF << (until % 8); b |= m; if (b != (byte) 0xFF) return false; } return true; } /** * Returns a string that shows every bit in the given byte. * * @param b * The byte * @return string representation of a byte */ public String byteToBitString(byte b) { String res = "|"; for (byte j = 0; j < 8; j++) res += ((b >> j) & (byte) 1) == 1 ? "1|" : "0|"; return res; } /** * Prints the content of the bitmap to {@link System#out}. */ public void print() { System.out.println("+---------------+"); for (int i = 0; i < bitmap.length; i++) if ((i == bitmap.length - 1) && (size % 8 > 0)) { char[] s = byteToBitString(bitmap[i]).toCharArray(); for (byte b = (byte) (size % 8); b < 8; b++) s[b * 2 + 1] = 'x'; System.out.println(s); } else System.out.println(byteToBitString(bitmap[i])); System.out.println("+---------------+"); } } 1.1 jop/java/target/src/common/ejip/jtcpip/DatagramPacket.java http://www.opencores.org/cvsweb.shtml/jop/java/target/src/common/ejip/jtcpip/DatagramPacket.java?rev=1.1&content-type=text/x-cvsweb-markup Index: DatagramPacket.java =================================================================== /* * 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; import java.io.DataInputStream; import java.io.EOFException; import java.io.IOException; import javax.microedition.io.Datagram; /** * Container for a UDP datagram. The DatagamPacket acts as a container for * incoming and outgoing UDP datagrams. It offers functions to read and write * data to its buffer and the remote address as truncated connector string (ÒIP * address:portÓ). The buffer that is used has to be provided at the * instantiation. This allows reuse of a buffer on systems with limited memory * (or systems without a Garbage Collector). * * @author Ulrich Feichter * @author Tobias Kellner * @author Christof Rath * @version $Rev: 994 $ $Date: 2007/01/24 19:37:07 $ */ public class DatagramPacket implements Datagram { /** * Remote address in the form IPaddress:port[options] where options is a set * of ;x=y */ private String remoteAddr = ""; /** Reference to a byte array */ private byte[] buffer; /** fixed offset within buffer given at constructor call */ private int initialOffset; /** the maximum useable space in the buffer given at constructor call */ private int maxLength; /** pointer for read operations */ private int readPtr; /** pointer for write operations */ private int writePtr; /** actual length in the buffer */ private int length; /** * Constructs a DatagramPacket for receiving packets of length length. The * length argument must be less than or equal to buffer.length * * @param buffer * buffer for holding the incoming datagram * @param length * the number of bytes to read */ public DatagramPacket(byte[] buffer, int length) { this(buffer, 0, length); } /** * Constructs a DatagramPacket for receiving packets of length length. The * length argument must be less than or equal to buffer.length * * @param buffer * buffer for holding the incoming datagram * @param offset * the offset for the buffer * @param length * the number of bytes to read */ public DatagramPacket(byte[] buffer, int offset, int length) { if (buffer == null) throw new NullPointerException(); if (offset < 0 || length < 0 || offset + length > buffer.length) throw new IndexOutOfBoundsException(); this.buffer = buffer; initialOffset = offset; maxLength = offset + length; reset(); } /** * Constructs a datagram packet for sending packets of length length to the * specified port number on the specified host. * * The length argument must be less than or equal to buffer.length * * @param buffer * the packet data * @param length * the packet length * @param remoteAddr * the destination address ([[protocol:]//]ip_addr:port[;opt=value...]) */ public DatagramPacket(byte[] buffer, int length, String remoteAddr) { this(buffer, 0, length, remoteAddr); } /** * Constructs a datagram packet for sending packets of length length to the * specified port number on the specified host. * * The length argument must be less than or equal to buffer.length * * @param buffer * the packet data * @param offset * the packet data offset * @param length * the packet length * @param remoteAddr * the destination ([//]ip_addr:port[;opt=value...]) */ public DatagramPacket(byte[] buffer, int offset, int length, String remoteAddr) { this(buffer, offset, length); this.remoteAddr = remoteAddr; this.length = length; // Set the length of data to send } /** * @see javax.microedition.io.Datagram#getAddress() */ public String getAddress() { return remoteAddr; } /** * @see javax.microedition.io.Datagram#getData() */ synchronized public byte[] getData() { byte[] data = new byte[length]; for (int i = 0; i < length; i++) data[i] = buffer[initialOffset + i]; return data; } /** * @see javax.microedition.io.Datagram#getLength() */ public int getLength() { return length; } /** * (non-Javadoc) * * @see javax.microedition.io.Datagram#getOffset() */ public int getOffset() { return readPtr; } /** * @see javax.microedition.io.Datagram#reset() */ synchronized public void reset() { length = 0; readPtr = initialOffset; writePtr = initialOffset; } /** * @see javax.microedition.io.Datagram#setAddress(java.lang.String) */ public void setAddress(String addr) throws IOException { remoteAddr = addr; } /** * @see javax.microedition.io.Datagram#setAddress(javax.microedition.io.Datagram) */ public void setAddress(Datagram reference) { try { if (reference != null) setAddress(reference.getAddress()); } catch (IOException e) { } } /** * @see javax.microedition.io.Datagram#setData(byte[], int, int) */ synchronized public void setData(byte[] buffer, int offset, int len) { try { reset(); write(buffer, offset, len); } catch (IOException e) { throw new IllegalArgumentException(e.getMessage()); } } /** * @see javax.microedition.io.Datagram#setLength(int) */ public void setLength(int len) { if (len > (maxLength - initialOffset)) throw new IllegalArgumentException(); length = len; } /** * @see java.io.DataInput#readBoolean() */ public boolean readBoolean() throws IOException { return readByte() != 0; } /* * (non-Javadoc) * * @see java.io.DataInput#readByte() */ public byte readByte() throws IOException { if (readPtr >= (initialOffset + length)) throw new EOFException(); return buffer[readPtr++]; } /** * @see java.io.DataInput#readChar() */ public char readChar() throws IOException { return (char) readByte(); } /** * @see java.io.DataInput#readFully(byte[]) */ synchronized public void readFully(byte[] b) throws IOException { readFully(b, 0, length); } /** * @see java.io.DataInput#readFully(byte[], int, int) */ public void readFully(byte[] b, int off, int len) throws IOException { if (b == null) throw new NullPointerException(); if (off < 0 || len < 0 || off + len > b.length || len > buffer.length) throw new IndexOutOfBoundsException(); for (int i = 0; i < len; i++) { if (i == length) throw new EOFException(); b[off + i] = buffer[i]; } } /** * @see java.io.DataInput#readInt() */ public int readInt() throws IOException { return (readUnsignedShort() << 16) | readUnsignedShort(); } /** * @see java.io.DataInput#readLong() */ public long readLong() throws IOException { return ((long) readInt() & 0xFFFFFFFF << 32) | ((long) readInt() & 0xFFFFFFFF); } /** * @see java.io.DataInput#readShort() */ public short readShort() throws IOException { return (short) ((readUnsignedByte() << 8) | readUnsignedByte()); } /** * @see java.io.DataInput#readUTF() */ public String readUTF() throws IOException { return DataInputStream.readUTF(this); } /** * @see java.io.DataInput#readUnsignedByte() */ public int readUnsignedByte() throws IOException { return readByte() & 0xFF; } /** * @see java.io.DataInput#readUnsignedShort() */ public int readUnsignedShort() throws IOException { return readShort() & 0xFFFF; } /** * @see java.io.DataInput#skipBytes(int) */ public int skipBytes(int n) throws IOException { //if n < 0 the readPtr must be at least initialOffset //if n > 0 the readPtr must not be greater than maxLength int res = Math.max(initialOffset - readPtr, Math.min(n, maxLength - readPtr)); readPtr += res; return res; } /** * @see java.io.DataOutput#write(int) */ synchronized public void write(int b) throws IOException { if (writePtr >= maxLength) throw new IndexOutOfBoundsException(); buffer[writePtr++] = (byte) b; length++; } /** * @see java.io.DataOutput#write(byte[]) */ public void write(byte[] b) throws IOException { write(b, 0, b.length); } /** * @see java.io.DataOutput#write(byte[], int, int) */ synchronized public void write(byte[] b, int off, int len) throws IOException { if (b == null) throw new NullPointerException(); if (off < 0 || len < 0) throw new IllegalArgumentException(); for (int i = off; i < len; i++) write(b[i]); } /** * @see java.io.DataOutput#writeBoolean(boolean) */ public void writeBoolean(boolean v) throws IOException { writeByte(v ? 1 : 0); } /** * @see java.io.DataOutput#writeByte(int) */ public void writeByte(int v) throws IOException { write(v); } /** * @see java.io.DataOutput#writeChar(int) */ public void writeChar(int v) throws IOException { writeByte(v); } /** * @see java.io.DataOutput#writeChars(java.lang.String) */ public void writeChars(String s) throws IOException { write(s.getBytes()); } /** * @see java.io.DataOutput#writeInt(int) */ public void writeInt(int v) throws IOException { writeShort((v >>> 16) & 0xFFFF); writeShort((v >>> 0) & 0xFFFF); } /** * @see java.io.DataOutput#writeLong(long) */ public void writeLong(long v) throws IOException { writeInt((int) (v >>> 32)); writeInt((int) (v >>> 0)); } /** * @see java.io.DataOutput#writeShort(int) */ public void writeShort(int v) throws IOException { writeByte((v >>> 8) & 0xFF); writeByte((v >>> 0) & 0xFF); } /** * @return the buffer */ protected byte[] getBuffer() { return buffer; } public void writeUTF(String value) throws IOException { // TODO Auto-generated method stub } } 1.1 jop/java/target/src/common/ejip/jtcpip/DatagramSocket.java http://www.opencores.org/cvsweb.shtml/jop/java/target/src/common/ejip/jtcpip/DatagramSocket.java?rev=1.1&content-type=text/x-cvsweb-markup Index: DatagramSocket.java =================================================================== /* * 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; import java.io.IOException; import javax.microedition.io.Connection; import javax.microedition.io.Connector; import javax.microedition.io.Datagram; import javax.microedition.io.DatagramConnection; import com.sun.cldc.io.ConnectionBaseInterface; import ejip.jtcpip.util.StringFunctions; /** * Application interface to the UDP layer. The DatagramSocket holds a reference * to a corresponding UDPConnection, provides some functions to create new * Datagrams and the functions to send and receive them. * * @author Ulrich Feichter * @author Tobias Kellner * @author Christof Rath * @version $Rev: 994 $ $Date: 2007/01/24 19:37:07 $ */ public class DatagramSocket implements DatagramConnection, ConnectionBaseInterface { /** Reference to the UDPConnection */ private UDPConnection conn; /** Default remote host */ private String defaultRemoteHost; /** * Dummy constructor - see {@link Connector#open(String)}. * * @param addr * Format: [[protocol:]//][ip address]:port[;opt1=val1...] * @throws IOException * @see #openPrim(String, int, boolean) */ public DatagramSocket(String addr) throws IOException { openPrim(addr, 0, false); } /** * @see javax.microedition.io.DatagramConnection#getMaximumLength() */ public int getMaximumLength() throws IOException { return StackParameters.UDP_DATA_SIZE; } /** * @see javax.microedition.io.DatagramConnection#getNominalLength() */ public int getNominalLength() throws IOException { return getMaximumLength(); } /** * @see javax.microedition.io.DatagramConnection#newDatagram(int) */ public Datagram newDatagram(int size) throws IOException { return newDatagram(size, defaultRemoteHost); } /** * @see javax.microedition.io.DatagramConnection#newDatagram(int, * java.lang.String) */ public Datagram newDatagram(int size, String addr) throws IOException { if (size < 0 || size > getMaximumLength()) throw new IllegalArgumentException(); byte[] b = new byte[size]; return newDatagram(b, size, addr); } /** * @see javax.microedition.io.DatagramConnection#newDatagram(byte[], int) */ public Datagram newDatagram(byte[] buf, int size) throws IOException { return new DatagramPacket(buf, size, defaultRemoteHost); } /** * @see javax.microedition.io.DatagramConnection#newDatagram(byte[], int, * java.lang.String) */ public Datagram newDatagram(byte[] buf, int size, String addr) throws IOException { if (size < 0 || size > getMaximumLength()) throw new IllegalArgumentException(); Datagram dg = new DatagramPacket(buf, size); if (addr != null) dg.setAddress(addr); return dg; } /** * @see javax.microedition.io.DatagramConnection#receive(javax.microedition.io.Datagram) */ public void receive(Datagram dgram) throws IOException { if (conn != null) conn.receive(dgram); } /** * @see javax.microedition.io.DatagramConnection#send(javax.microedition.io.Datagram) */ public void send(Datagram dgram) throws IOException { if (conn != null) conn.send(dgram); } /** * @see javax.microedition.io.Connection#close() */ public void close() throws IOException { if (conn != null) { conn.close(); conn = null; } } /** * Opens the datagram socket. * * <pre> * URL format: * [//][host]:port[;option1=value1[;option2=value2[...]]] * </pre> * * If the host is given a connection will be established to the given * host:port the local port will be random. Else a listening connection will * be opened on the given port * * <p> * Examples: (Note that 'datagram:' will be removed by * {@link Connector#open(String)}) * <p> * A datagram connection for accepting datagrams<br> * datagram://:1234 * <p> * A datagram connection for sending to a server:<br> * datagram://123.456.789.12:1234 * <p> * * <b>Note: </b> Even in "client mode" is the actual destination always set * in the DatagramPacket! The given remote address is used as default * destination. * * <p> * Note that the port number in "server mode" (unspecified host name) is * that of the receiving port. The port number in "client mode" (host name * specified) is that of the target port. The reply-to port in both cases is * never unspecified. In "server mode", the same port number is used for * both receiving and sending. In "client mode", the reply-to port is always * dynamically allocated. * * @param name * The URL for the connection * @param mode * The access mode * @param timeouts * A flag to indicate that the caller wants timeout exceptions * @return A new Connection object */ public Connection openPrim(String name, int mode, boolean timeouts) throws IOException { int addr = StringFunctions.getAddrFromConnectorStr(name); int port; if (addr == 0) port = StringFunctions.getPortFromConnectorStr(name); else { port = UDPConnection.newLocalPort(); defaultRemoteHost = name; } conn = UDPConnection.newConnection(port); if (conn == null) throw new JtcpipException("No connection available!"); return this; } } 1.1 jop/java/target/src/common/ejip/jtcpip/DHCPClient.java http://www.opencores.org/cvsweb.shtml/jop/java/target/src/common/ejip/jtcpip/DHCPClient.java?rev=1.1&content-type=text/x-cvsweb-markup Index: DHCPClient.java =================================================================== /* * 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; import java.io.IOException; import javax.microedition.io.Datagram; import ejip.CS8900; import ejip.Net; import ejip.jtcpip.util.Debug; import ejip.jtcpip.util.NumFunctions; /** * Implements a basic DHCP client * * @author Ulrich Feichter * @author Tobias Kellner * @author Christof Rath * @version $Rev: 975 $ $Date: 2007/01/24 19:37:07 $ */ public class DHCPClient { /** * UDP connection to the DHCP server to the server port 67 from the server * port 68 */ private static UDPConnection conn; /** buffer for the datagram */ private static byte[] buffer; /** datagram for the communication */ private static Datagram dg; /** transaction id */ private static int transID; /** Timeout when we have to renew the lease */ private static long renewalTimeout; /** IP address lease time */ private static int leaseTimeSec; /** Server identifier (ip address) */ private static int serverID; /** Time when we got the lease (required for the lease timeout) */ private static long ackTime; /** time in seconds between two trys */ public static int retryTimeout = 15; public static void init(){ buffer = new byte[StackParameters.UDP_DATA_SIZE]; conn = UDPConnection.newConnection(68, 0xFFFFFFFF, 67); dg = new DatagramPacket(buffer, buffer.length, "//255.255.255.255:67"); } /** * forbids instantiation */ private DHCPClient() { } /** * Creates a new transaction ID and resets the datagram */ private static void start() { transID = NumFunctions.rand.nextInt(); renewalTimeout = 0; leaseTimeSec = 0; serverID = 0; ackTime = 0; Net.linkLayer.gateway = 0; Net.linkLayer.netmask = 0; } /** * Sends a DHCP discover datagram. * * @return the datagram with the DHCP server answer * @throws IOException */ private static Datagram discover() throws IOException { dg.reset(); dg.write(1); // OP: request dg.write(1); // hw_type: ethernet dg.write(6); // hw_addr_len: 6 for ethernet dg.write(0); // hops dg.writeInt(transID); // transaction ID dg.writeShort(0); // secs: time elapsed since start of DHCP request dg.writeShort(0); // flags: MSB set rest must be zero dg.writeInt(0); // client ip address dg.writeInt(0); // your (client) ip address dg.writeInt(0); // server ip address dg.writeInt(0); // relay agent ip address dg.write(CS8900.eth[0]); // client hardware address dg.write(CS8900.eth[1]); // s.a.a. dg.write(CS8900.eth[2]); // s.a.a. dg.write(CS8900.eth[3]); // s.a.a. dg.write(CS8900.eth[4]); // s.a.a. dg.write(CS8900.eth[5]); // s.a.a. dg.writeShort(0); // s.a.a. dg.writeInt(0); // s.a.a. dg.writeInt(0); // s.a.a. dg.writeLong(0); // server host name dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); // boot file name dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); // Options (1 byte option type, 1 byte option length in bytes, n bytes // option value) dg.writeInt(0x63825363); // Magic cookie dg.write(53); // DHCP Msg type dg.write(1); // only one byte of data dg.write(1); // DHCP discover dg.write(61); // Client identifier dg.write(7); // 7 bytes of data dg.write(1); // 1 for Ethernet addr dg.write(CS8900.eth[0]); // client hardware address dg.write(CS8900.eth[1]); // s.a.a. dg.write(CS8900.eth[2]); // s.a.a. dg.write(CS8900.eth[3]); // s.a.a. dg.write(CS8900.eth[4]); // s.a.a. dg.write(CS8900.eth[5]); // s.a.a. dg.write(12); // Host name dg.write(6); // 6 bytes of data dg.writeChar('j'); // jcpip dg.writeChar('t'); dg.writeChar('c'); dg.writeChar('p'); dg.writeChar('i'); dg.writeChar('p'); dg.write(55); // Parameter Request List dg.write(2); // 2 bytes of data dg.write(1); // Subnetmask dg.write(3); // Gateway dg.write(0xFF); // End of Options conn.send(dg); conn.receive(dg); if (dg.getLength() != 0) { dg.skipBytes(28); //jump to chaddr (client hardware address) //and check if the received datagram is for our MAC address boolean isOurs = true; for (int i = 0; i < 6; i++) if (dg.readUnsignedByte() != CS8900.eth[i]) { isOurs = false; break; } if (!isOurs) dg.reset(); else dg.skipBytes(-34); } return dg; } /** * Sends a DHCP request for a given IP address * * @param ipAddr * @return DHCP server answer * @throws IOException */ private static Datagram request(int ipAddr) throws IOException { dg.reset(); dg.write(1); // OP: request dg.write(1); // hw_type: ethernet dg.write(6); // hw_addr_len: 6 for ethernet dg.write(0); // hops dg.writeInt(transID); // transaction ID dg.writeShort(0); // secs: time elapsed since start of DHCP request // but must be the same as at discover!!!! dg.writeShort(0x0000); // flags: MSB = uni/broadcast; rest must be zero dg.writeInt(ipAddr); // client ip address dg.writeInt(0); // your (client) ip address dg.writeInt(0); // server ip address dg.writeInt(0); // relay agent ip address dg.write(CS8900.eth[0]); // client hardware address dg.write(CS8900.eth[1]); // s.a.a. dg.write(CS8900.eth[2]); // s.a.a. dg.write(CS8900.eth[3]); // s.a.a. dg.write(CS8900.eth[4]); // s.a.a. dg.write(CS8900.eth[5]); // s.a.a. dg.writeShort(0); // s.a.a. dg.writeInt(0); // s.a.a. dg.writeInt(0); // s.a.a. dg.writeLong(0); // server host name dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); // boot file name dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); dg.writeLong(0); // Options (1 byte option type, 1 byte option length in bytes, n bytes // option value) dg.writeInt(0x63825363); // Magic cookie dg.write(53); // DHCP Msg type dg.write(1); // only one byte of data dg.write(3); // DHCP request dg.write(61); // Client identifier dg.write(7); // 7 bytes of data dg.write(1); // 1 for Ethernet addr dg.write(CS8900.eth[0]); // client hardware address dg.write(CS8900.eth[1]); // s.a.a. dg.write(CS8900.eth[2]); // s.a.a. dg.write(CS8900.eth[3]); // s.a.a. dg.write(CS8900.eth[4]); // s.a.a. dg.write(CS8900.eth[5]); // s.a.a. dg.write(12); // Host name dg.write(6); // 6 bytes of data dg.writeChar('j'); // jcpip dg.writeChar('t'); dg.writeChar('c'); dg.writeChar('p'); dg.writeChar('i'); dg.writeChar('p'); dg.write(55); // Parameter Request List dg.write(3); // 2 bytes of data dg.write(1); // Subnetmask dg.write(3); // Gateway dg.write(51); // Lease time dg.write(0xFF); // End of Options conn.send(dg); conn.receive(dg); if (dg.getLength() != 0) { dg.skipBytes(28); //jump to chaddr (client hardware address) //and check if the received datagram is for our MAC address boolean isOurs = true; for (int i = 0; i < 6; i++) if (dg.readUnsignedByte() != CS8900.eth[i]) { isOurs = false; break; } if (!isOurs) dg.reset(); else dg.skipBytes(-34); } return dg; } /** * Sets the IP address, the Subnet mask and the Gateway * * @return true if the DHCP ACK has been received */ public static boolean setNetParams() { try { int offeredIP = 0; start(); discover(); if (dg.getLength() == 0) { return false; } dg.setAddress("//255.255.255.255:67"); // send again a broadcast dg.skipBytes(16); // jump to yiaddr offeredIP = dg.readInt(); dg.skipBytes(8); // jump to chaddr (client MAC) request(offeredIP); if (dg.getLength() == 0) { return false; } return processOptions(); } catch (IOException e) { e.printStackTrace(); return false; } } /** * Checks if the renewalTimeout has been reached and send a DHCP request in * case * * @return true if everything went right */ public static boolean renewIfNecessary() { if (renewalTimeout > System.currentTimeMillis()) return true; try { start(); request(Net.linkLayer.ip); if (dg.getLength() == 0) { return false; } return processOptions(); } catch (IOException e) { e.printStackTrace(); return false; } } /** * @return true if the processed datagram was a DHCP ACK packet * @throws IOException */ private static boolean processOptions() throws IOException { int offeredIP; dg.skipBytes(16); // jump to yiaddr offeredIP = dg.readInt(); // read yiaddr Net.linkLayer.ip = offeredIP; dg.skipBytes(220); // jump to options (after magic cookie) int opt; // DHCP option int cnt; // count of option value bytes int value = 0; // option value; boolean result = false; while ((opt = dg.readUnsignedByte()) != 0xFF) { cnt = dg.readUnsignedByte(); switch (cnt) { case 1: value = dg.readUnsignedByte(); break; case 2: value = dg.readUnsignedShort(); break; case 4: value = dg.readInt(); break; default: for (int i = 0; i < cnt; i++) dg.readByte(); } // if (Debug.enabled) // Debug.println("DHCP opt: " + opt + " cnt: " + cnt + " val: " + value, Debug.DBG_OTHER); if (Debug.enabled) Debug.println("DHCP opt", Debug.DBG_OTHER); // interpret the options switch (opt) { case 53: // DHCP Msg type result = (value == 5); // 5: DHCP ACK if (result) ackTime = System.currentTimeMillis(); break; case 58: // renewal time renewalTimeout = value; break; case 51: // address lease time leaseTimeSec = value; break; case 54: // server identifier serverID = value; break; case 1: // subnet mask Net.linkLayer.netmask = value; break; case 3: // gateway Net.linkLayer.gateway = value; break; } } if (renewalTimeout > 0) // there has been a 'renewal time'-option renewalTimeout = ackTime + renewalTimeout * 1000; // as the // ackTime is in // seconds else if (leaseTimeSec > 0) // at least there has been an 'address lease // time'-option renewalTimeout = ackTime + leaseTimeSec * 500; // according to RFC // if not given by // the server it // should be 0.5 of // the leas time else renewalTimeout = ackTime + 3600000; // send renewal every hour return result; } /** * @return the address lease time in hours */ public static int getLeaseTime() { return leaseTimeSec / 3600; } /** * @return the renewal time in hours */ public static int getRenewalTime() { return (int) (renewalTimeout - ackTime) / 3600000; } /** * @return the server IP address */ public static int getServerIP() { return serverID; } } 1.1 jop/java/target/src/common/ejip/jtcpip/ICMP.java http://www.opencores.org/cvsweb.shtml/jop/java/target/src/common/ejip/jtcpip/ICMP.java?rev=1.1&content-type=text/x-cvsweb-markup Index: ICMP.java =================================================================== /* * 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; import ejip.jtcpip.util.Debug; /** * Class to handle ICMP packets. * * @author Ulrich Feichter * @author Tobias Kellner * @author Christof Rath * @version $Rev: 984 $ $Date: 2007/01/24 19:37:07 $ */ class ICMP { /** 0 */ protected final static byte TYPE_ECHO_REPLY = 0; /** 3: Destination unreachable */ protected final static byte TYPE_DEST_UNREACH = 3; /** 4: Source quench */ protected final static byte TYPE_SRC_QUENCH = 4; /** 8 */ protected final static byte TYPE_ECHO = 8; /** 11: Time exceeded */ protected final static byte TYPE_TIME_EXCEEDED = 11; /** * Answers to an incoming ICMP ECHO. * * @param pay */ private static void answerToEcho(Payload pay) { // if (Debug.enabled) // Debug.println("ECHO REPLY to: " + IP.ipIntToString(IPPacket.getSrcAddr(pay)), Debug.DBG_ICMP); if (Debug.enabled) Debug.println("ECHO REPLY", Debug.DBG_ICMP); ICMPPacket.setType(pay, TYPE_ECHO_REPLY); IP.asyncSendPayload(pay, IPPacket.getSrcAddr(pay), IP.PROT_ICMP); } /** * Answers ICMP DESTINATION UNREACHABLE. * * @param pay * @param code */ protected static void sendDestUnreach(Payload pay, int code) { // if (Debug.enabled) // Debug.println("DEST UNREACHABLE to: " + IP.ipIntToString(IPPacket.getSrcAddr(pay)), Debug.DBG_ICMP); if (Debug.enabled) Debug.println("DEST UNREACHABLE", Debug.DBG_ICMP); ICMPPacket.ipToICMPPacket(pay); ICMPPacket.setType(pay, ICMP.TYPE_DEST_UNREACH); ICMPPacket.setCode(pay, code); IP.asyncSendPayload(pay, IPPacket.getSrcAddr(pay), IP.PROT_ICMP); } /** * Answers ICMP SOURCE QUENCHE. * * TODO: call this function if we have to close the TCP window * * @param pay */ protected static void sendSrcQuenche(Payload pay) { // if (Debug.enabled) // Debug.println("SOURCHE QUENCHE to: " + IP.ipIntToString(IPPacket.getSrcAddr(pay)), Debug.DBG_ICMP); if (Debug.enabled) Debug.println("SOURCHE QUENCHE ", Debug.DBG_ICMP); ICMPPacket.ipToICMPPacket(pay); ICMPPacket.setType(pay, ICMP.TYPE_SRC_QUENCH); IP.asyncSendPayload(pay, IPPacket.getSrcAddr(pay), IP.PROT_ICMP); } /** * Answers ICMP TIME EXCEEDED. * * @param pay */ protected static void sendTimeExceeded(Payload pay) { // if (Debug.enabled) // Debug.println("TIME EXCEEDED to: " + IP.ipIntToString(IPPacket.getSrcAddr(pay)), Debug.DBG_ICMP); if (Debug.enabled) Debug.println("TIME EXCEEDED ", Debug.DBG_ICMP); ICMPPacket.ipToICMPPacket(pay); ICMPPacket.setType(pay, ICMP.TYPE_TIME_EXCEEDED); ICMPPacket.setCode(pay, 1); // 1: fragment reassembly time exceeded. IP.asyncSendPayload(pay, IPPacket.getSrcAddr(pay), IP.PROT_ICMP); } /** * By now we just print (if Debug.enabled == true) the information, that an IP packet * hasn't reached its destination. * * TODO: do something if one of our IP packets has not reached its destination * * @param pay */ private static void handleDestUnreach(Payload pay) { byte code = ICMPPacket.getCode(pay); ICMPPacket.icmpToIPPacket(pay); if (Debug.enabled) switch (code) { case 0: // net unreachable; Debug.println("The network of the IP address ",Debug.DBG_ICMP); // + IP.ipIntToString(IPPacket.getDestAddr(pay)) + " is unreachable", // Debug.DBG_ICMP); break; case 1: // host unreachable; Debug.println("The host with the IP address ",Debug.DBG_ICMP); // + IP.ipIntToString(IPPacket.getDestAddr(pay)) + " is unreachable", // Debug.DBG_ICMP); break; case 2: // protocol unreachable; Debug.println("The protocol " ,Debug.DBG_ICMP); // + IPPacket.getProtocol(pay) + "is unreachable", // Debug.DBG_ICMP); break; case 3: // port unreachable; Debug.println("The port IP address ",Debug.DBG_ICMP); // + IP.ipIntToString(IPPacket.getDestAddr(pay)) // + ":" + UDPPacket.getDestPort(pay) + " is unreachable", Debug.DBG_ICMP); break; case 4: // fragmentation needed and DF set; Debug.println("Fragmentation is needed but the Don't Fragment flag is set", Debug.DBG_ICMP); break; case 5: // source route failed. Debug.println("Source route failed", Debug.DBG_ICMP); break; } } /** * Handles an incoming ICMP packet. * * @param pay */ protected static void receivePayload(Payload pay) { if (Debug.enabled) Debug.println("ICMP received",Debug.DBG_ICMP); // Debug.println("Type: " + ICMPPacket.getType(pay) + " Code: " + ICMPPacket.getCode(pay), Debug.DBG_ICMP); switch (ICMPPacket.getType(pay)) { case TYPE_ECHO: answerToEcho(pay); break; case TYPE_DEST_UNREACH: handleDestUnreach(pay); Payload.freePayload(pay); break; default: if (Debug.enabled) Debug.println("Datagram unhandled...", Debug.DBG_ICMP); Payload.freePayload(pay); } } } 1.1 jop/java/target/src/common/ejip/jtcpip/ICMPPacket.java http://www.opencores.org/cvsweb.shtml/jop/java/target/src/common/ejip/jtcpip/ICMPPacket.java?rev=1.1&content-type=text/x-cvsweb-markup Index: ICMPPacket.java =================================================================== /* * 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; } } 1.1 jop/java/target/src/common/ejip/jtcpip/IP.java http://www.opencores.org/cvsweb.shtml/jop/java/target/src/common/ejip/jtcpip/IP.java?rev=1.1&content-type=text/x-cvsweb-markup Index: IP.java =================================================================== /* * 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; import util.Dbg; import ejip.Net; import ejip.Packet; import ejip.jtcpip.util.Debug; import ejip.jtcpip.util.NumFunctions; /** * Represents the network layer. Contains methods for Packet sending and * receiving (including reassembly). Received Packets are then handed to the * upper (transport) layer. * * @see ejip2.jtcpip.TCP * @see ejip2.jtcpip.UDP * * @author Tobias Kellner * @author Ulrich Feichter * @author Christof Rath * @version $Rev: 994 $ $Date: 2007/01/24 19:37:07 $ */ public class IP { /** Default Time To Live Value */ private static final byte TTL = (byte) 128; /** Protocol Constant for IP Header: ICMP */ public static final byte PROT_ICMP = 1; /** Protocol Constant for IP Header: TCP */ public static final byte PROT_TCP = 6; /** Protocol Constant for IP Header: UDP */ public static final byte PROT_UDP = 17; /** * Packet identification for IP Header. Incremented after each send. (From a * security point of view, this is questionable) TODO */ private static short packetID = 0; /** Exception that gets thrown when there is an error in the IP Address */ private static JtcpipException ipException; public static void init() { ipException = new JtcpipException("Invalid IP Address String"); } /** * Stores the content of a fragment into a reassembling payload * * @param rsmblPay * @param fragmtPay */ private static void rsmblStore(Payload rsmblPay, Payload fragmtPay) { int pLen = IPPacket.getLength(fragmtPay) - IPPacket.getIHL(fragmtPay) * 4; int ofs = IPPacket.getFragOfs(fragmtPay) * 2; int maxIndex = NumFunctions.divRoundUp(pLen, 4); if (ofs + maxIndex > rsmblPay.payload.length) { // if (Debug.enabled) // Debug // .println( // "Reassembled Payload would be greater than max. Payload size! // Offset: " // + ofs + " max. index: " + maxIndex // + " Payload.length: " // + rsmblPay.payload.length, Debug.DBG_IP); ICMP.sendDestUnreach(rsmblPay, 4); // fragmentation needed and DF // set; return; } /* * To prevent data overwriting (as for the first call rsmblPay == * fragmtPay) we copy the data back to front */ switch (pLen % 4) {// copy the last bytes but don't overwrite the // previous content case 1: fragmtPay.payload[maxIndex] &= 0xFF000000; rsmblPay.payload[ofs + maxIndex] &= 0x00FFFFFF; rsmblPay.payload[ofs + maxIndex] |= fragmtPay.payload[maxIndex]; break; case 2: fragmtPay.payload[maxIndex] &= 0xFFFF0000; rsmblPay.payload[ofs + maxIndex] &= 0x0000FFFF; rsmblPay.payload[ofs + maxIndex] |= fragmtPay.payload[maxIndex]; break; case 3: fragmtPay.payload[maxIndex] &= 0xFFFFFF00; rsmblPay.payload[ofs + maxIndex] &= 0x000000FF; rsmblPay.payload[ofs + maxIndex] |= fragmtPay.payload[maxIndex]; break; } for (int i = pLen / 4 - 1; i >= 0; i--) rsmblPay.payload[ofs + i] = fragmtPay.payload[i]; // if the offset == 0 the first fragment is stored and we can send an // ICMP message in case of a time out rsmblPay.setOffset(IPPacket.getFragOfs(fragmtPay)); rsmblPay.reassembledBitMap.setBits(IPPacket.getFragOfs(fragmtPay), pLen / 8); if (!IPPacket.isMFSet(fragmtPay)) {// last fragment => calculate bytes // of unfragmented packet rsmblPay.length = pLen + IPPacket.getFragOfs(fragmtPay) * 8; // Only the very last datablock that doesn't fall on an eight byte // boundary _may_ mark a block in the bitmap (else we wait for a // fragment // that holds the complete datablock) if (pLen % 8 > 0) rsmblPay.reassembledBitMap.setBit(IPPacket .getFragOfs(fragmtPay) + (pLen / 8)); } if (Debug.enabled && (Debug.dbgFlagsToDisplay & Debug.DBG_IP) > 0) rsmblPay.reassembledBitMap.print(); } /** * Handles the reassembling of a IP packet fragment * * @param pay */ private static void reassemblePayload(Payload pay) { for (int i = 0; i < StackParameters.PAYLOAD_POOL_SIZE; i++) { if (Payload.pool[i] != null && Payload.pool[i].getStatus() == Payload.PAYLOAD_RESMBL && (IPPacket.getID(pay) == IPPacket.getID(Payload.pool[i]))) { // just // received // a // packet // with // the // same // ID rsmblStore(Payload.pool[i], pay); Payload.freePayload(pay); // if (Debug.enabled) // if (Payload.pool[i].length != -1) // Debug.println("Seeing if all " // + NumFunctions.divRoundUp( // Payload.pool[i].length, 8) // + " bits are set", Debug.DBG_IP); if (Payload.pool[i].length != -1 // length is -1 until we got // the last fragment. && Payload.pool[i].reassembledBitMap .allSet(NumFunctions.divRoundUp( Payload.pool[i].length, 8))) { Payload.pool[i].setStatus(Payload.PAYLOAD_USED, 0); //handlePayload(Payload.pool[i]); byte prot = IPPacket.getProtocol(Payload.pool[i]); switch (prot) { case PROT_TCP: TCP.receivePayload(Payload.pool[i]); break; case PROT_UDP: UDP.receivePayload(Payload.pool[i]); break; case PROT_ICMP: ICMP.receivePayload(Payload.pool[i]); break; } } return; } } // No matching payload found => this is the first part of a fragmented // payload pay.length = -1; // the payload length is invalid until we got the // last fragment pay.setStatus(Payload.PAYLOAD_RESMBL, StackParameters.REASSEMBLE_TIMEOUT); pay.setOffset(StackParameters.PAYLOAD_MAX_DATA_SIZE); // No fragments // stored yet rsmblStore(pay, pay); // move the payload to the correct position } /** * Hands a Packet to the upper (transport) layer. Which layer that is is * read from the Protocol entry in the IP header. If the protocol is unknown * (not handled), the packet is dropped. * * NOTE: this function has been inlined!! * * @param pay * Packet */ private static void handlePayload(Payload pay) { byte prot = IPPacket.getProtocol(pay); switch (prot) { case PROT_TCP: TCP.receivePayload(pay); break; case PROT_UDP: UDP.receivePayload(pay); break; case PROT_ICMP: ICMP.receivePayload(pay); break; } } /** * Copies the data stored in a <code>Payload</code> object to a * <code>Packet</code> object. Also sets the protocol field in the * Ethernet header to IP. * * @param pay * Payload to copy from * @param p * Packet to write to * * @return Zero if the full payload fitted into the packet else the number * of already copied bytes */ protected static int payloadToPacket(Payload pay, Packet p) { return payloadToPacket(pay, p, 0); } /** * Copies the data (up to the size of a Ethernet packet) stored in a * <code>Payload</code> object to a <code>Packet</code> object. Also * sets the protocol field in the Ethernet header to IP. * * @param pay * Payload to copy from * @param p * Packet to write to * @param offset * in 4-byte-blocks (i.e. already sent blocks) * @return The offset where the data for the next Packet starts (if * fragmentation needed, else 0) */ protected static int payloadToPacket(Payload pay, Packet p, int offset) { byte headerLength = IPPacket.getIHL(pay); boolean isFragmt = (pay.length + headerLength * 4) > p.buf.length * 4 && pay.getStatus() != Payload.PAYLOAD_ARP_WT; if (isFragmt && IPPacket.isDFSet(pay)) { ICMP.sendDestUnreach(pay, 4); // Code 4: fragmentation needed and // DF set return 0; } /* * if (isFragmt && (offset % 2 != 0)) //Should not be needed anymore { * if (Debug.enabled) Debug.println("ALERT! Fragment not on boundary", * Debug.DBG_IP); offset--; // Fragmentation Offset not on an 8-byte * boundary -> overlap } */ int dataInPayload = headerLength * 4 + pay.length - offset * 4; // Size // of // the // (rest // of // the) // payload p.len = Math.min(p.buf.length * 4, dataInPayload); p.llh[6] = 0x0800; // IP code for ethernet header if (isFragmt) // IP Fragmentation! { if (p.len == dataInPayload) // Last fragment of the Payload IPPacket.clearMF(pay); else { p.len -= (p.len - headerLength * 4) % 8; // Fragmentation // offset - 8 byte // boundary! IPPacket.setMF(pay); } IPPacket.setLength(pay, (short) p.len); IPPacket.setFragOfs(pay, (short) (offset / 2)); } IPPacket.setChecksum(pay); // copy the IP header into the Ethernet packet for (byte i = 0; i < headerLength; i++) p.buf[i] = pay.ipHeader[i]; int i = 0; int lastPayloadIndex = NumFunctions.divRoundUp(pay.length, 4); int limit = Math.min(NumFunctions.divRoundUp(p.len, 4) - headerLength, lastPayloadIndex - offset); for (i = 0; i < limit; i++) p.buf[i + headerLength] = pay.payload[offset + i]; // TODO: maybe padding if too short if (p.len == dataInPayload) return 0; return offset + 1; // return p.len == dataInPayload ? 0 : offset + i; // if the size of the // (rest of the) payload // == the packet length // return 0 else the // offset } /** * Takes a newly received Packet from the network driver. The content is * then stored in a <code>Payload</code> object. If the Packet is valid * (checksum, ehternet header...) it will be delivered to to the next layer * (via {@link IP#handlePayload}). If a packet is fragmented, it will be * reassembled here. <b>Note:</b> After the method returns, the passed * Packet will be marked as FREE! * * @see #handlePayload * @param p * Packet to process */ public static void receivePacket(Packet p) { if (Debug.enabled) Debug.println("Received a packet", Debug.DBG_IP); if (p.len < 20) { if (Debug.enabled) Debug.println("Packet is shorter than 20 bytes, dropping!!", Debug.DBG_IP); p.setStatus(Packet.FREE); return; } if (p.llh[6] != 0x0800) { if (Debug.enabled) Debug.println("PACKET IS NOT AN IP PACKET!!", Debug.DBG_IP); p.setStatus(Packet.FREE); return; } Payload pay = Payload.newPayload(); if (pay == null) { if (Debug.enabled) Debug.println("No more Payloads available - packet dropped", Debug.DBG_IP); p.setStatus(Packet.FREE); return; } for (int i = 0; i < 5; i++) // copy first 20 byte of header to ipHeader (therefore we are not // able do read out IPPacket.getIHL(pay)) pay.ipHeader[i] = p.buf[i]; // accept only packets for our ip or eth broadcasts if (IPPacket.getDestAddr(pay) != Net.linkLayer.getIpAddress() && !(p.llh[0] == 0xFFFF && p.llh[1] == 0xFFFF && p.llh[2] == 0xFFFF)) { // System.out.println(IPPacket.getDestAddr(pay)); // System.out.println(Net.linkLayer.ip); if (Debug.enabled) Debug.println("Packet is not for us... dropping", Debug.DBG_IP); p.setStatus(Packet.FREE); Payload.freePayload(pay); return; } int headerLength = (int) (IPPacket.getIHL(pay) & 0xFF); if (headerLength > 5) // if header is longer than 20 byte copy the // rest for (int i = 5; i < headerLength; i++) pay.ipHeader[i] = p.buf[i]; // if (Debug.enabled) // Debug.println("Captured packet length: ", Debug.DBG_IP); // check if the packet length is acceptable, drop the packet if wrong int payloadLengtFromIPHeader = ((int) (IPPacket.getLength(pay) & 0xFFFF) - headerLength * 4); if (payloadLengtFromIPHeader > p.len - headerLength * 4 || payloadLengtFromIPHeader > StackParameters.PAYLOAD_MAX_DATA_SIZE) { if (Debug.enabled) Debug.println("Packet is too long, dropping", Debug.DBG_IP); p.setStatus(Packet.FREE); Payload.freePayload(pay); return; } for (int i = 0; i < (NumFunctions.divRoundUp(p.len, 4) - headerLength); i++) // copy // payload { pay.payload[i] = p.buf[i + headerLength]; // if (Debug.enabled) // Debug.print(Debug.intToHexString(pay.payload[i]), Debug.DBG_IP); } // Take the min of the length specified in the IP header and the real // captured data as Payload length pay.length = payloadLengtFromIPHeader; p.setStatus(Packet.FREE); if (!IPPacket.isValidPacket(pay)) { if (Debug.enabled) Debug.println("Checksum not valid; dropping packet", Debug.DBG_IP); Payload.freePayload(pay); return; } if (IPPacket.isMFSet(pay) || IPPacket.getFragOfs(pay) != 0) { if (Debug.enabled) Debug.println("Valid Packet, FRAGMENTED", Debug.DBG_IP); reassemblePayload(pay); } else { // not fragmented if (Debug.enabled) Debug.println("Valid Packet, not fragmented", Debug.DBG_IP); // TODO: inlined //handlePayload(pay); byte prot = IPPacket.getProtocol(pay); switch (prot) { case PROT_TCP: TCP.receivePayload(pay); break; case PROT_UDP: UDP.receivePayload(pay); break; case PROT_ICMP: ICMP.receivePayload(pay); break; } } /* * if (Debug.enabled){ Debug.println("version " + * IPPacket.getVersion(pay)); Debug.println("ihl " + * IPPacket.getIHL(pay)); Debug.println("tos " + * Debug.IntegerToHexString(IPPacket.getToS(pay))); * Debug.println("length: " + IPPacket.getLength(pay)); * Debug.println("id: " + IPPacket.getID(pay)); Debug.println("res: " + * IPPacket.isReservedSet(pay)); Debug.println("fragm: " + * IPPacket.isDFSet(pay)); Debug.println("more frag: " + * IPPacket.isMFSet(pay)); Debug.println("frag ofs: " + * IPPacket.getFragOfs(pay)); Debug.println("ttl: " + * IPPacket.getTTL(pay)); Debug.println("protocol: " + * Debug.IntegerToHexString(IPPacket.getProtocol(pay))); * Debug.println("src: " + * Debug.IntegerToHexString(IPPacket.getSrcAddr(pay))); * Debug.println("dest addr: " + * Debug.IntegerToHexString(IPPacket.getDestAddr(pay))); } */ } /** * Prepares the IP header. In order to send a packet * * @param pay * The packet payload * @param destIP * The destination IP * @param protocol * The transport protocol id */ private static void prepareIPPacket(Payload pay, int destIP, byte protocol) { IPPacket.setIHL(pay, (byte) 0x5); IPPacket.setToS(pay, (byte) 0x0); IPPacket .setLength(pay, (short) (pay.length + IPPacket.getIHL(pay) * 4)); IPPacket.setID(pay, packetID++); IPPacket.clearDF(pay); IPPacket.clearMF(pay); IPPacket.clearReserved(pay); IPPacket.setFragOfs(pay, (short) 0x0); IPPacket.setTTL(pay, (byte) TTL); IPPacket.setProtocol(pay, protocol); if ((destIP >= 2130706432) && (destIP <= 2147483647)) // 127.0.0.0/8 { IPPacket.setDestAddr(pay, Net.linkLayer.getIpAddress()); // Swapping // addresses for // loopback IPPacket.setSrcAddr(pay, destIP); } else { IPPacket.setDestAddr(pay, destIP); IPPacket.setSrcAddr(pay, Net.linkLayer.getIpAddress()); } switch (IPPacket.getProtocol(pay)) { case PROT_TCP: TCPPacket.setChecksum(pay); break; case PROT_UDP: UDPPacket.setChecksum(pay); break; case PROT_ICMP: ICMPPacket.setChecksum(pay); break; } } /** * @deprecated * * Sends a Packet by handing it to the network driver. Takes a payload, a * destination ip and a protocol number (e.g. <code>IP.PROT_TCP</code>). * <b>Note:</b> After the method returns, the passed Payload will be marked * as free! * * @param pay * The packet payload * @param destIP * The destination IP * @param protocol * The transport protocol id * * @return Whether send was successful */ public static boolean sendPayload(Payload pay, int destIP, byte protocol) { prepareIPPacket(pay, destIP, protocol); if (pay.length > StackParameters.PACKET_MTU_SIZE) { // TODO: Implement fragmentation here? Would this make sense? if (Debug.enabled) Debug.println("Fragmentation not implemented here!", Debug.DBG_IP); return false; } Packet p = Packet.getPacket(Packet.FREE, Packet.ALLOC, Net.linkLayer); if (p == null) return false; // TODO: Retransmit payloadToPacket(pay, p); Payload.freePayload(pay); p.setStatus(Packet.SND); return true; } /** * Prepares and marks a Payload for sending * * @param pay * The packet payload * @param destIP * The destination IP * @param protocol * The transport protocol id */ public synchronized static void asyncSendPayload(Payload pay, int destIP, byte protocol) { if (Debug.enabled) Debug.println("asyncSendPayload", Debug.DBG_IP); prepareIPPacket(pay, destIP, protocol); if (Debug.enabled) Debug.println("asyncSendPayload2", Debug.DBG_IP); pay.setStatus(Payload.PAYLOAD_SND_RD, 0); if (Debug.enabled) Debug.println("asyncSendPayload3", Debug.DBG_IP); } /** * Converts an IP address of the format [xx]x.[xx]x.[xx]x.[xx]x to an * integer. Throws an exception if the format of the String is faulty. * * @param ipAddr * The IP address String * @return The IP address as an int * @throws JtcpipException * Invalid IP Address String */ public static int ipStringToInt(String ipAddr) throws JtcpipException { byte dots = 0; short ipOctet = 0; int ipInt = 0; for (int i = 0; i <= ipAddr.length(); i++) { if (i == ipAddr.length() || ipAddr.charAt(i) == '.') { if (i < ipAddr.length() && ++dots == 4) { // if (Debug.enabled) // Debug.println("Too many dots in " + ipAddr, // Debug.DBG_IP); throw ipException; } if (ipOctet < 0 || ipOctet > 255) { // if (Debug.enabled) // Debug.println("Wrong IP values in " + ipAddr, // Debug.DBG_IP); throw ipException; } ipInt = (ipInt << 8) | (ipOctet & 0xFF); ipOctet = 0; } else if (ipAddr.charAt(i) >= '0' && ipAddr.charAt(i) <= '9') ipOctet = (short) (ipOctet * 10 + (ipAddr.charAt(i) - '0')); else { if (Debug.enabled) Debug.println("Wrong char in IP address ", Debug.DBG_IP); throw ipException; } } if (dots != 3) { if (Debug.enabled) Debug.println("IP address too short ", Debug.DBG_IP); throw ipException; } return ipInt; } /** * @param ipAddr * @return the String representation of an IP address */ public static String ipIntToString(int ipAddr) { return "" + ((ipAddr >>> 24) & 0xFF) + "." + ((ipAddr >>> 16) & 0xFF) + "." + ((ipAddr >>> 8) & 0xFF) + "." + ((ipAddr) & 0xFF); } } 1.1 jop/java/target/src/common/ejip/jtcpip/IPPacket.java http://www.opencores.org/cvsweb.shtml/jop/java/target/src/common/ejip/jtcpip/IPPacket.java?rev=1.1&content-type=text/x-cvsweb-markup Index: IPPacket.java =================================================================== /* * 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; /** * The IP Packet Class encapsulating methods to handle a Payload as an IP * Packet. All methods are static and get a {@link Payload} as a parameter. * There are get and set methods for all fields of the IP header. * * @author Tobias Kellner * @author Ulrich Feichter * @author Christof Rath * @version $Rev: 849 $ $Date: 2007/01/24 19:37:07 $ */ public class IPPacket { /** Position of the Reserved Flag in the 2nd word of the IP header */ private static final int RESERVED_MASK = 0x8000; /** Position of the Don't Fragment Flag in the 2nd word of the IP header */ private static final int DF_MASK = 0x4000; /** Position of the More Fragments Flag in the 2nd word of the IP header */ private static final int MF_MASK = 0x2000; /** * Get the IP Version. Should be 4 for IPv4 * * @param pay * The Payload * @return The IP Version */ public static byte getVersion(Payload pay) { return (byte) (pay.ipHeader[0] >>> 28); } /** * Set the IP Version Should be 4 for IPv4 * * @param pay * The Payload * @param ver * The IP Version to set */ public static void setVersion(Payload pay, byte ver) { int i = pay.ipHeader[0] & 0x0FFFFFFF; pay.ipHeader[0] = i | ((ver & 0xF) << 28); } /** * Get the Internet Header Length. This is the size of the IP header in * 32-bit words. (min. 5, max. 15) * * @param pay * The Payload * @return The Internet Header Length */ public static byte getIHL(Payload pay) { return (byte) ((pay.ipHeader[0] >>> 24) & 0x0F); } /** * Set the Internet Header Length. This is the size of the IP header in * 32-bit words. (min. 5, max. 15) * * @param pay * The Payload * @param len * The Internet Header Length */ public static void setIHL(Payload pay, byte len) { int i = pay.ipHeader[0] & 0xF0FFFFFF; pay.ipHeader[0] = i | ((len & 0xF) << 24); } /** * Get the Type of Service. * <ul> * <li> bits 0-2: precedence * <li> bit 3: 0 = Normal Delay, 1 = Low Delay * <li> bit 4: 0 = Normal Throughput, 1 = High Throughput * <li> bit 5: 0 = Normal Reliability, 1 = High Reliability * <li> bits 6-7: Reserved for future use * </ul> * * @param pay * The Payload * @return The Type of Service */ public static byte getToS(Payload pay) { return (byte) ((pay.ipHeader[0] >>> 16) & 0xFF); } /** * Set the Type of Service. * <ul> * <li> bits 0-2: precedence * <li> bit 3: 0 = Normal Delay, 1 = Low Delay * <li> bit 4: 0 = Normal Throughput, 1 = High Throughput * <li> bit 5: 0 = Normal Reliability, 1 = High Reliability * <li> bits 6-7: Reserved for future use * </ul> * * @param pay * The Payload * @param tos * The Type of Service */ public static void setToS(Payload pay, byte tos) { int i = pay.ipHeader[0] & 0xFF00FFFF; pay.ipHeader[0] = i | ((tos & 0xFF) << 16); } /** * Get the Total Length of the Packet. Entire size of the datagram, * including header and data, in bytes. (min. 20, max. 65535) * * @param pay * The Payload * @return The Total Length */ public static short getLength(Payload pay) { return (short) (pay.ipHeader[0] & 0xFFFF); } /** * Set the Total Length of the Packet. Entire size of the datagram, * including header and data, in bytes. (min. 20, max. 65535) * * @param pay * The Payload * @param len * The Total Length */ public static void setLength(Payload pay, short len) { int i = pay.ipHeader[0] & 0xFFFF0000; pay.ipHeader[0] = i | (len & 0xFFFF); } /** * Get the Identification. Used for uniquely identifying individual * fragments of a fragmented IP Packet. * * @param pay * The Payload * @return The Identification */ public static short getID(Payload pay) { return (short) (pay.ipHeader[1] >>> 16); } /** * Set the Identification. Used for uniquely identifying individual * fragments of a fragmented IP Packet. * * @param pay * The Payload * @param id * The Identification */ public static void setID(Payload pay, short id) { int i = pay.ipHeader[1] & 0x0000FFFF; pay.ipHeader[1] = i | ((id & 0xFFFF) << 16); } /** * Check whether the Reserved Flag is set. This Flag must be zero. <b>Note:</b> * because this is a benign IP Stack, setting this flag is not possible. * * @param pay * The Payload * @return Whether the Reserved Flag is set */ public static boolean isReservedSet(Payload pay) { return (pay.ipHeader[1] & RESERVED_MASK) != 0; } /** * Clear the Reserved Flag. This Flag must be zero. <b>Note:</b> because * this is a benign IP Stack, setting this flag is not possible. * * @param pay * The Payload */ public static void clearReserved(Payload pay) { pay.ipHeader[1] = pay.ipHeader[1] & ~RESERVED_MASK; } /** * Check whether the Don't Fragment Flag is set. A Packet with DF set must * not be fragmented. If it would have to be, it is dropped instead. * * @param pay * The Payload * @return Whether the Don't Fragment Flag is set */ public static boolean isDFSet(Payload pay) { return (pay.ipHeader[1] & DF_MASK) != 0; } /** * Set the Don't Fragment Flag. A Packet with DF set must not be fragmented. * If it would have to be, it is dropped instead. * * @param pay * The Payload */ public static void setDF(Payload pay) { pay.ipHeader[1] = pay.ipHeader[1] | DF_MASK; } /** * Clear the Don't Fragment Flag. A Packet with DF set must not be * fragmented. If it would have to be, it is dropped instead. * * @param pay * The Payload */ public static void clearDF(Payload pay) { pay.ipHeader[1] = pay.ipHeader[1] & ~DF_MASK; } /** * Check whether the More Fragments Flag is set. In a fragmented IP Packet, * all split Packets except the last one have this flag set. * * @param pay * The Payload * @return Whether the More Fragments Flag is set */ public static boolean isMFSet(Payload pay) { return (pay.ipHeader[1] & MF_MASK) != 0; } /** * Set the More Fragments Flag. In a fragmented IP Packet, all split Packets * except the last one have this flag set. * * @param pay * The Payload */ public static void setMF(Payload pay) { pay.ipHeader[1] = pay.ipHeader[1] | MF_MASK; } /** * Clear the More Fragments Flag. In a fragmented IP Packet, all split * Packets except the last one have this flag set. * * @param pay * The Payload */ public static void clearMF(Payload pay) { pay.ipHeader[1] = pay.ipHeader[1] & ~MF_MASK; } /** * Get the Fragment Offset. The place of a particular fragment in the * original IP datagram, measured in units of 8-byte blocks. * * @param pay * The Payload * @return The Fragment Offset */ public static short getFragOfs(Payload pay) { return (short) (pay.ipHeader[1] & 0x1FFF); } /** * Set the Fragment Offset. The place of a particular fragment in the * original IP datagram, measured in units of 8-byte blocks. * * @param pay * The Payload * @param ofs * The Fragment Offset */ public static void setFragOfs(Payload pay, short ofs) { int i = pay.ipHeader[1] & 0xFFFFE000; pay.ipHeader[1] = i | (ofs & 0x1FFF); } /** * Get the Time To Live. Each packet switch (or router) that a datagram * crosses decrements the TTL field by one. When the TTL field hits zero, * the Packet is no longer forwarded by a packet switch and is discarded. * * @param pay * The Payload * @return The Time To Live */ public static byte getTTL(Payload pay) { return (byte) (pay.ipHeader[2] >>> 24); } /** * Set the Time To Live. Each packet switch (or router) that a datagram * crosses decrements the TTL field by one. When the TTL field hits zero, * the Packet is no longer forwarded by a packet switch and is discarded. * * @param pay * The Payload * @param ttl * The Time To Live */ public static void setTTL(Payload pay, byte ttl) { int i = pay.ipHeader[2] & 0x00FFFFFF; pay.ipHeader[2] = i | ((ttl & 0xFF) << 24); } /** * Get the Protocol. The protocol used in the data part of the datagram. * * @see IP#PROT_ICMP * @see IP#PROT_TCP * @see IP#PROT_UDP * * @param pay * The Payload * @return The Protocol */ public static byte getProtocol(Payload pay) { return (byte) ((pay.ipHeader[2] >>> 16) & 0xFF); } /** * Set the Protocol. The protocol used in the data part of the datagram. * * @see IP#PROT_ICMP * @see IP#PROT_TCP * @see IP#PROT_UDP * * @param pay * The Payload * @param proto * The Protocol */ public static void setProtocol(Payload pay, byte proto) { int i = pay.ipHeader[2] & 0xFF00FFFF; pay.ipHeader[2] = i | ((proto & 0xFF) << 16); } /** * Get the Header Checksum. The checksum is calculated over the IP Header. * * @param pay * The Payload * @return The Header Checksum */ public static short getChecksum(Payload pay) { return (short) (pay.ipHeader[2] & 0xFFFF); } /** * Set the Header Checksum to the correct value. The checksum is calculated * over the IP Header (with the checksum field assumed to be zero). The * calculation is done in {@link IPPacket#calculateChecksum}. * * @param pay * The Payload */ public static void setChecksum(Payload pay) { pay.ipHeader[2] = pay.ipHeader[2] & 0xFFFF0000; pay.ipHeader[2] = pay.ipHeader[2] | (calculateChecksum(pay) & 0xFFFF); } /** * Get the Source address. The IP address the Packet originated from. * * @param pay * The Payload * @return The Source address as 32-bit value */ public static int getSrcAddr(Payload pay) { return pay.ipHeader[3]; } /** * Set the Source address. The IP address the Packet originated from. * * @param pay * The Payload * @param addr * The Source address as 32-bit value */ public static void setSrcAddr(Payload pay, int addr) { pay.ipHeader[3] = addr; } /** * Get the Destination address. The IP address the Packet is headed to. * * @param pay * The Payload * @return The Destination address as 32-bit value */ public static int getDestAddr(Payload pay) { return pay.ipHeader[4]; } /** * Set the Destination address. The IP address the Packet is headed to. * * @param pay * The Payload * @param addr * The Destination address as 32-bit value */ public static void setDestAddr(Payload pay, int addr) { pay.ipHeader[4] = addr; } /** * Calculate the correct Checksum. The checksum is calculated over the IP * Header (with the checksum field assumed to be zero). * * @param pay * The Payload * @return The Checksum */ public static short calculateChecksum(Payload pay) { int i; int ofs = 0; int sum = 0; byte cnt = getIHL(pay); while (cnt != 0) { i = pay.ipHeader[ofs]; sum += i & 0xffff; sum += i >>> 16; ++ofs; --cnt; } while ((sum >> 16) != 0) sum = (sum & 0xffff) + (sum >> 16); sum = (~sum) & 0xffff; return (short) sum; } /** * Check whether the checksum is valid. * * @param pay * The Payload * @return Whether the checksum is valid. */ public static boolean isChecksumValid(Payload pay) { return calculateChecksum(pay) == 0; // Checksum with checksum field // correctly set should equal 0 } /** * Check whether the Packet is valid. Checks the checksum and whether the * Reserved Flag is cleared. * * @param pay * The Payload * @return Whether the Packet is valid. */ public static boolean isValidPacket(Payload pay) { return (!isReservedSet(pay) && isChecksumValid(pay)); } } 1.1 jop/java/target/src/common/ejip/jtcpip/JtcpipException.java http://www.opencores.org/cvsweb.shtml/jop/java/target/src/common/ejip/jtcpip/JtcpipException.java?rev=1.1&content-type=text/x-cvsweb-markup Index: JtcpipException.java =================================================================== /* * 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; import java.io.IOException; /** * TCP / IP Stack Exception. * * @author Tobias Kellner * @author Ulrich Feichter * @author Christof Rath * @version $Rev: 849 $ $Date: 2007/01/24 19:37:07 $ */ public class JtcpipException extends IOException { /** serial version UID - required for serialization */ private static final long serialVersionUID = 1L; /** * TCP / IP Stack Exception. * * @param errorMessage * The error message */ public JtcpipException(String errorMessage) { super(errorMessage); } } 1.1 jop/java/target/src/common/ejip/jtcpip/NwLoopRtThread.java http://www.opencores.org/cvsweb.shtml/jop/java/target/src/common/ejip/jtcpip/NwLoopRtThread.java?rev=1.1&content-type=text/x-cvsweb-markup Index: NwLoopRtThread.java =================================================================== /* * 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; import util.Dbg; import joprt.RtThread; import ejip.Arp; import ejip.LinkLayer; import ejip.Net; import ejip.Packet; import ejip.jtcpip.util.Debug; /** * Network loop class. Creates a thread for a given Net and LinkLayer instance * * @author Ulrich Feichter * @author Tobias Kellner * @author Christof Rath * @version $Rev: 984 $ $Date: 2007/01/24 19:37:07 $ */ public class NwLoopRtThread extends RtThread { public static TCPConnection conn = null; public static Payload pay = null; /** Holds the instance for the singelton pattern */ private static NwLoopRtThread nwLoop; /** * Holds a references to the LinkLayer instances to call the * LinkLayer.loop() */ private LinkLayer linkLayer; /** counts the loop cycles up to StackParameters.NW_LOOP_CYCLES */ private int cycleCnt = 0; /** * if the cycleCnt % tcpModulus == 0 the next TCP connection is tested to * send new data of the oStream */ private int tcpModulus = StackParameters.NW_LOOP_CYCLES / StackParameters.TCP_CONNECTION_POOL_SIZE; /** * Creates the network loop instance * * @param linkLayer * Instances to the link layers * @param msDelay * Delay in milli seconds between two calls */ private NwLoopRtThread(LinkLayer linkLayer, int msDelay) { super(10, 10000); Packet.init(); this.linkLayer = linkLayer; } public void run() { for (;;) { // Dbg.wr("NWLOOP\n"); waitForNextPeriod(); if (cycleCnt % tcpModulus == 0) { int conToTest = cycleCnt / tcpModulus; if (TCPConnection.pool[conToTest] != null && TCPConnection.pool[conToTest].getState() != TCPConnection.STATE_CLOSED) { if (!TCPConnection.pool[conToTest].pollConnection()) TCPConnection.retryToSendData = conToTest; } } else { if (TCPConnection.retryToSendData > -1) { if (TCPConnection.pool[TCPConnection.retryToSendData] .pollConnection()) TCPConnection.retryToSendData = -1; } } int cnt = Payload.waitingPayloadCount(); if (cnt > 0) { byte status; for (int i = 0; i < StackParameters.PAYLOAD_POOL_SIZE; i++) { status = Payload.pool[i].getStatus(); if (status > Payload.PAYLOAD_WND_RX) { cnt--; switch (status) { case Payload.PAYLOAD_FRAGMT: case Payload.PAYLOAD_SND_RD: if (preparedSend(Payload.pool[i])) { // Everything ok -> free payload Payload.freePayload(Payload.pool[i]); } break; case Payload.PAYLOAD_ARP_WT: if (Arp.inCache(IPPacket .getDestAddr(Payload.pool[i]))) { if (Payload.pool[i].getOffset() == 0) Payload.pool[i].setStatus( Payload.PAYLOAD_SND_RD, 0); else Payload.pool[i].setStatus( Payload.PAYLOAD_FRAGMT, Payload.pool[i].getOffset()); } if (Payload.pool[i].isTimeout()) { if (Debug.enabled) Debug.println("ARP timeout!", Debug.DBG_OTHER); Payload.freePayload(Payload.pool[i]); // No one to inform (ICMP) -> free payload } break; case Payload.PAYLOAD_RESMBL: if (Payload.pool[i].isTimeout()) { if (Payload.pool[i].getOffset() == 0) // The first fragment has been received // -> So we can inform the remote host ICMP.sendTimeExceeded(Payload.pool[i]); else Payload.freePayload(Payload.pool[i]); // Just free the payload } break; default: if (Debug.enabled) Debug.println("Unknown Payload status: ", Debug.DBG_OTHER); } } if (cnt <= 0) break; } } Packet p = Packet.getPacket(Packet.RCV, Packet.ALLOC); if (p != null) { IP.receivePacket(p); Dbg.wr("Ip.receive returned\n"); } if ((conn != null) && (pay != null)) { TCP.sendPackets(conn, pay); conn = null; pay = null; } cycleCnt++; if (cycleCnt >= StackParameters.NW_LOOP_CYCLES) cycleCnt = 0; } } /** * Tries to send a payload that is in the PAYLOAD_SND_RD state * * @param pay * @return true if the complete payload has been sent */ protected static boolean preparedSend(Payload pay) { if (Debug.enabled) Debug.println("prepared send", Debug.DBG_OTHER); // TODO for Dhcp // int firstHopDest = (LinkLayer.isSameSubnet(IPPacket.getDestAddr(pay)) // ? IPPacket // .getDestAddr(pay) // : Net.linkLayer.gateway); int firstHopDest = IPPacket.getDestAddr(pay); // System.out.println(IPPacket.getDestAddr(pay)); // FIXME: For LinkLayers that do not require ARP (e.g. Slip, Loopback) // this has to be modified boolean inCache = (Arp.inCache(firstHopDest) || (firstHopDest == Net.linkLayer.getIpAddress()) // loopback to same addr || (firstHopDest >= 2130706433 && firstHopDest <= 2147483646)); // loopback to 127.x.x.x Packet p = Packet.getPacket(Packet.FREE, Packet.ALLOC, Net.linkLayer); if (p == null) return false; if (!inCache) pay.setStatus(Payload.PAYLOAD_ARP_WT, StackParameters.ARP_TIMEOUT); int offset = 0; if (inCache) offset = pay.getOffset(); else offset = Math.max(pay.length / 4 - 1, 0); // int offset = inCache ? pay.getOffset() : Math // .max(pay.length / 4 - 1, 0); // // If ARP request use just the minimum of Payload offset = IP.payloadToPacket(pay, p, offset); if (firstHopDest == Net.linkLayer.getIpAddress() // loopback to same // addr || (firstHopDest >= 2130706433 && firstHopDest <= 2147483646)) // loopback // to // 127.x.x.x p.setStatus(Packet.RCV); else { if (!inCache && IPPacket.getDestAddr(pay) != firstHopDest) { // Request // ARP // resolution // for // gateway // IP destination address (without gateway) is // at position 4 for IP packets and at 6 for ARP packets int addrPos = p.llh[6] == 0x0806 ? 6 : 4; p.buf[addrPos] = firstHopDest; } p.setStatus(Packet.SND); } if (offset > 0) pay.setStatus(Payload.PAYLOAD_FRAGMT, offset); return inCache && offset == 0; } /** * Creates and start the network loop thread * * @param linkLayer * @return The instance of the network loop */ public static NwLoopRtThread createInstance(LinkLayer linkLayer) { if (nwLoop == null) { nwLoop = new NwLoopRtThread(linkLayer, StackParameters.NW_LOOP_TIMEOUT); // nwLoop.start(); } return nwLoop; } /** * Returns the instance of the network loop * * @return NwLoopThread */ public static NwLoopRtThread getInstance() { return nwLoop; } } 1.1 jop/java/target/src/common/ejip/jtcpip/NwLoopThread.java http://www.opencores.org/cvsweb.shtml/jop