/*
This file is part of JOP, the Java Optimized Processor
see <http://www.jopdesign.com/>
Copyright (C) 2001-2008, Martin Schoeberl (martin@jopdesign.com)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* Copyright (c) Martin Schoeberl, martin@jopdesign.com
* 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Martin Schoeberl
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS 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 REGENTS OR CONTRIBUTORS 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 jembench.udpip;
/*
* Changelog:
* 2002-10-24 creation.
*
* TODO: in Udp, TcpIp.... when to use the packet with automatic reply?
*/
/**
* @author martin
*
* To change the template for this generated type comment go to
* Window>Preferences>Java>Code Generation>Code and Comments
*/
/**
* UDP functions.
*/
public class UdpipUdp {
public static final int PROTOCOL = 17;
public static final int HEAD = 5; // offset of udp header in words
public static final int DATA = 7; // offset of data in words
private static Object monitor;
public static final int MAX_HANDLER = 8;
private static UdpipUdpHandler[] list;
private static int[] ports;
private static int loopCnt;
public static void init() {
if (monitor!=null) return;
monitor = new Object();
list = new UdpipUdpHandler[MAX_HANDLER];
ports = new int[MAX_HANDLER];
loopCnt = 0;
// addHandler(Tftp.PORT, new Tftp());
}
/**
* add a handler for UDP requests.
* returns false if list is full.
*/
public static boolean addHandler(int port, UdpipUdpHandler h) {
if (monitor==null) init();
synchronized(monitor) {
for (int i=0; i<MAX_HANDLER; ++i) {
if (list[i]==null) {
ports[i] = port;
list[i] = h;
return true;
}
}
}
return false;
}
/**
* Called periodic from Net for timeout processing.
*/
static void loop() {
int i = loopCnt;
if (list[i]!=null) {
list[i].loop();
++i;
if (i==MAX_HANDLER) i=0;
} else {
i = 0;
}
loopCnt = i;
}
/**
* process packet and generate reply if necessary.
*/
static void process(UdpipPacket p) {
int i, j;
int[] buf = p.buf;
int port = buf[HEAD];
int remport = port >>> 16;
port &= 0xffff;
buf[2] = (PROTOCOL<<16) + p.len - 20; // set protocol and udp length in iph checksum for tcp checksum
if (UdpipTcpIp.chkSum(buf, 2, p.len-8)!=0) {
// Dbg.intVal(p.len);
// Dbg.wr(" : ");
// for (int k = 0; k < (p.len+3)/4; k++) {
// Dbg.hexVal(buf[k]);
// }
p.setStatus(UdpipPacket.FREE); // mark packet free
UdpipDbg.wr("wrong UDP checksum ");
return;
}
if (port == 1625) {
// do the Dgb thing!
i = UdpipDbg.readBuffer(buf, 7);
p.len = 28+i;
// generate a reply with IP src/dst exchanged
UdpipUdp.build(p, buf[4], buf[3], remport);
} else {
if (list!=null) {
for (i=0; i<MAX_HANDLER; ++i) { // @WCA loop=8
if (list[i]!=null && ports[i]==port) {
list[i].request(p);
break;
}
}
if (i==MAX_HANDLER) {
p.setStatus(UdpipPacket.FREE); // mark packet free
UdpipDbg.lf();
UdpipDbg.wr('U');
UdpipDbg.intVal(port);
}
} else {
p.setStatus(UdpipPacket.FREE);
}
}
}
public static void getData(UdpipPacket p, StringBuffer s) {
int[] buf = p.buf;
s.setLength(0);
for (int i = UdpipUdp.DATA*4; i < p.len; i++) { // @WCA loop<=1500
s.append((char) ((buf[i>>2]>>(24 - ((i&3)<<3))) & 0xff));
}
}
public static void setData(UdpipPacket p, StringBuffer s) {
int[] buf = p.buf;
int cnt = s.length();
// copy buffer
int k = 0;
for (int i=0; i<cnt; i+=4) { // @WCA loop<=1500
for (int j=0; j<4; ++j) { // @WCA loop=4
k <<= 8;
if (i+j < cnt) k += s.charAt(i+j);
}
buf[UdpipUdp.DATA + (i>>>2)] = k;
}
p.len = UdpipUdp.DATA*4+cnt;
}
/**
* Generate a reply with IP src/dst exchanged.
* @param p
*/
public static void reply(UdpipPacket p) {
int[] buf = p.buf;
UdpipUdp.build(p, buf[4], buf[3], buf[HEAD]>>>16);
}
/**
* Get source IP from interface and build IP/UDP header.
*/
public static void build(UdpipPacket p, int dstIp, int port) {
int srcIp = p.interf.getIpAddress();
if (srcIp==0) { // interface is down
p.setStatus(UdpipPacket.FREE); // mark packet free
} else {
build(p, srcIp, dstIp, port);
}
}
/**
* Fill UDP and IP header and mark packet ready to send.
*/
public static void build(UdpipPacket p, int srcIp, int dstIp, int port) {
int i;
int[] buf = p.buf;
// read ethernet header from CS8900 driver
// for (i=0; i<7; ++i) {
// p.llh[i] = CS8900.llh[i];
// }
// IP header
// TODO unique id for sent packet
buf[0] = 0x45000000 + p.len; // ip length (header without options)
buf[1] = UdpipTcpIp.getId(); // identification, no fragmentation
buf[3] = srcIp;
buf[4] = dstIp;
// UDP header
// 'set' port numbers
buf[HEAD] = ((port+10000)<<16) + port; // src port = dst port + 10000
// Fill in UDP header
buf[HEAD+1] = (p.len-20)<<16;
buf[2] = (PROTOCOL<<16) + p.len - 20; // set protocol and udp length in iph checksum for tcp checksum
i = UdpipTcpIp.chkSum(buf, 2, p.len-8);
if (i==0) i = 0xffff;
buf[HEAD+1] |= i;
// for UDP checksum used field of IP header
buf[2] = (0x20<<24) + (PROTOCOL<<16); // ttl, protocol, clear checksum
buf[2] |= UdpipTcpIp.chkSum(buf, 0, 20);
// a VERY dummy arp/routing!
// should this be in the cs8900 ?
// TODO: This works ONLY if this packet was a RECEIVED packet!!!!!
// so it's more ore less useless here
// PLEASE add at minimum a simple ARP cache in the ethernet driver.
p.llh[0] = p.llh[3];
p.llh[1] = p.llh[4];
p.llh[2] = p.llh[5];
p.llh[6] = 0x0800;
p.setStatus(UdpipPacket.SND); // mark packet ready to send
}
}