/*
* 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 ejip;
/**
* Start device driver threads and poll for packets.
*/
public class Net implements Runnable {
public static final int PROT_ICMP = 1;
Ejip ejip;
Ip ip;
private Udp udp;
private Tcp tcp;
public Net(Ejip ejipRef) {
ejip = ejipRef;
ip = new Ip(ejip);
udp = new Udp(ejip);
tcp = new Tcp(ejip);
}
/**
* Look for received packets and invoke receive.
* Mark them to be sent if returned with len!=0 from TcpIp layer.
*/
public void run() {
Packet p;
PacketQueue rxQ = ejip.llRxQueue;
if (rxQ==null) {
if (Logging.LOG) Logging.wr("No link layer registered");
return;
}
// get one received packet from the receive queue
p = rxQ.deq();
if (p!=null) {
receive(p);
} else {
udp.run();
if (Ejip.TCP_ENABLED) tcp.run();
}
}
/**
* Process one IP packet. Change buffer and set length to get a packet sent
* back. called from Net.loop().
*/
public void receive(Packet p) {
int i;
int[] buf = p.buf;
int len;
i = buf[0];
len = i & 0xffff; // length from IP header
// NO options are assumed in ICMP/TCP/IP...
// => copy if options present
// but we just drop it now - too lazy
if (len > p.len || (i >>> 24 != 0x45)) {
if (Logging.LOG) Logging.wr("IP options -> discard");
ejip.returnPacket(p); // packet to short or ip options => drop it
return;
} else {
p.len = len; // correct for to long packets
}
// TODO fragmentation
if (Ip.chkSum(buf, 0, 20) != 0) {
ejip.returnPacket(p);
if (Logging.LOG) Logging.wr("wrong IP checksum ");
return;
}
int prot = (buf[2] >> 16) & 0xff; // protocol
if (prot == PROT_ICMP) {
doICMP(p);
ip.doIp(p, prot);
} else if (prot == Tcp.PROTOCOL) {
if (Ejip.TCP_ENABLED) {
// that's the new TCP processing
tcp.process(p);
} else {
ejip.returnPacket(p); // mark packet free
}
} else if (prot == Udp.PROTOCOL) {
udp.process(p); // Udp generates the reply
} else {
ejip.returnPacket(p); // mark packet free
}
}
/**
* the famous ping.
*/
private void doICMP(Packet p) {
int type_code = p.buf[5] >>> 16;
if (Logging.LOG) Logging.wr('P');
if (Logging.LOG) Logging.hexVal(type_code);
if (type_code == 0x0800) {
// TODO check received ICMP checksum
p.buf[5] = 0; // echo replay plus clear checksum,
p.buf[5] = Ip.chkSum(p.buf, 5, p.len - 20); // echo replay (0x0000)
// plus checksum
} else {
p.len = 0;
}
}
public Tcp getTcp() {
return tcp;
}
public Udp getUdp() {
return udp;
}
}