/* * 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_old; /* * Changelog: 2002-03-16 works with ethernet 2002-10-21 use Packet buffer, 4 * bytes in one word * * */ import util.Dbg; /** * A minimalistic TCP/IP stack (with ICMP). * * It's enough to handel a HTTP request (and nothing more)! */ public class TcpIp { public static final int PROTOCOL = 6; static final int FL_URG = 0x20; static final int FL_ACK = 0x10; static final int FL_PSH = 0x8; static final int FL_RST = 0x4; static final int FL_SYN = 0x2; static final int FL_FIN = 0x1; static int tcb_port; // tcp port static int tcb_st; // state static final int ST_LISTEN = 0; static final int ST_ESTAB = 2; static final int ST_FW1 = 3; static final int ST_FW2 = 4; static final int MTU = 1500 - 8; static final int WINDOW = 2680; public static void init() { tcb_st = ST_LISTEN; // select(); Html.init(); } /** * the famous ping. */ static void doICMP(Packet p) { int type_code = p.buf[5] >>> 16; Dbg.wr('P'); Dbg.hexVal(type_code); if (type_code == 0x0800) { // TODO check received ICMP checksum p.buf[5] = 0; // echo replay plus clear checksu, p.buf[5] = Ip.chkSum(p.buf, 5, p.len - 20); // echo replay (0x0000) // plus checksum } else { p.len = 0; } } // TODO:!!!!!! do a real state machine, // end is wrong (sending ack in fw1 !!!) makes remote site crazy static void doTCP(Packet p) { int i; int datlen; int[] buf = p.buf; int rcvcnt, sndcnt; int fl; Dbg.wr('T'); // Find the payload i = buf[8] >>> 16; int flags = i & 0xff; int hlen = i >>> 12; datlen = p.len - 20 - (hlen << 2); // "TCB" // In a full tcp implementation we would keep track of this per // connection. // This implementation only handles one connection at a time. // As a result, very little of this state is actually used after // the reply packet has been sent. // if (datlen < 0) return 0; // If it's not http, just drop it i = buf[5]; if ((i & 0xffff) != 80) { Dbg.lf(); Dbg.wr('T'); Dbg.intVal(i & 0xffff); p.len = 0; return; } // Get source port tcb_port = i >>> 16; rcvcnt = buf[6]; // sequence number sndcnt = buf[7]; // acknowledge number // sndcnt has to be incremented for SYN!!! fl = FL_ACK; p.len = 40; // Figure out what kind of packet this is, and respond if ((flags & FL_SYN) != 0) { // SYN sndcnt = -1; // start with -1 for SYN rcvcnt++; fl |= FL_SYN; // tcb_st = ST_ESTAB; } else if (datlen > 0) { // incoming data rcvcnt += datlen; // TODO get url if (sndcnt == 0) { p.len += Html.setText(buf, 5 + hlen, datlen, 10); // Send reply packet // if (len > MTU) len = MTU; // TODO MTU should be taken from // tcp options // Read next segment of data into buffer } else { fl |= FL_FIN; // tcb_st = ST_FW1; } fl |= FL_PSH; } else if ((flags & FL_FIN) != 0) { // FIN rcvcnt++; // Don't bother with FIN-WAIT-2, TIME-WAIT, or CLOSED; they just // cause trouble // tcb_st = ST_LISTEN; } else if ((flags & FL_ACK) != 0) { // ack with no data if (sndcnt > 0) { // calculate no of bytes left to send // i = len2send - sndnxt i = 0; if (i == 0) { // EOF; send FIN fl |= FL_FIN; // tcb_st = ST_FW1; } else if (i > 0) { // not EOF; send next segment // len += i; fl |= FL_PSH; } else { // ***** this is never used! thats bad // ack of FIN; no reply p.len = 0; return; } } else { p.len = 0; return; // No reply packet } } else { p.len = 0; return; // drop it } // Fill in TCP header buf[5] = (80 << 16) + tcb_port; buf[6] = sndcnt; buf[7] = rcvcnt; buf[8] = 0x50000000 + (fl << 16) + WINDOW; // hlen = 20, no options buf[9] = 0; // clear checksum field buf[2] = (PROTOCOL << 16) + p.len - 20; // set protocol and tcp length // in iph checksum for tcp // checksum buf[9] = Ip.chkSum(buf, 2, p.len - 8) << 16; } }