www.pudn.com > ejip.zip > Tftp.java
/*
* 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;
/*
* Changelog:
* 2002-10-24 creation.
*
*
* TODO: use a source port as TID.
* timeout and resend or cancel connection.
*
*/
import util.*;
/**
* Tftp.java: A simple TFTP Server. see rfc1350.
*/
public class Tftp {
public static final int PORT = 69;
private static final int IDLE = 0;
private static final int RRQ = 1;
private static final int WRQ = 2;
private static final int DAT = 3;
private static final int ACK = 4;
private static final int ERR = 5;
private static boolean initOk;
private static int state;
private static int fn;
private static int endBlock;
private static int block;
private static int simerr;
private static void tftpInit() {
initOk = true;
state = IDLE;
block = 0;
fn = 0;
}
private static void error(Packet p) {
p.buf[Udp.DATA] = (ERR<<16) + 4711;
p.buf[Udp.DATA+1] = 'x'<<24;
p.len = Udp.DATA+6;
tftpInit();
}
/** drop the packet end reset state */
private static void discard(Packet p) {
p.len = 0;
tftpInit();
}
static void timer() {
// TODO: retransmit DATA
}
/**
* handle the TFTP packets.
*
* filename is fixed length (2):
* 'ix' internal memory (read only)
* 'f0'..'f8' flash sector (64 KB)
*
*/
static void process(Packet p) {
if (!initOk) tftpInit();
int i, j;
int[] buf = p.buf;
Dbg.wr('T');
int op = buf[Udp.DATA]>>>16;
Dbg.intVal(op);
Dbg.intVal(buf[Udp.DATA]&0xffff);
/*
++simerr;
if (simerr%3==1) {
Dbg.wr('x');
p.len=0; return;
}
*/
if (op==RRQ) {
//Amd.sectorErase(0x20000);
/* just change state and cancel old communication
if (state!=IDLE) {
error(p);
return;
}
*/
state = RRQ;
fn = buf[Udp.DATA]&0xffff;
i = fn>>8;
if (i=='i') {
endBlock = 2+1; // (256*4)/512
} else if (i=='f') {
endBlock = 128+1; // 64K/512
} else {
endBlock = 1+1;
}
block = 1;
buf[Udp.DATA] = (DAT<<16)+block;
read(buf, block);
p.len = Udp.DATA*4+4+512;
} else if (op==ACK) {
block = (buf[Udp.DATA] & 0xffff)+1; // use one higher then last acked block
if (block>endBlock) {
discard(p);
} else {
buf[Udp.DATA] = (DAT<<16)+block;
if (block==endBlock) {
p.len = Udp.DATA*4+4; // last block is zero length
} else {
read(buf, block);
p.len = Udp.DATA*4+4+512;
}
}
} else if (op==WRQ) {
state = WRQ;
fn = buf[Udp.DATA]&0xffff;
block = 1;
buf[Udp.DATA] = (ACK<<16);
p.len = Udp.DATA*4+4;
} else if (op==DAT) {
if (state!=WRQ || block != (buf[Udp.DATA] & 0xffff)) {
discard(p);
} else {
if (p.len > Udp.DATA*4+4) {
program(buf, block);
}
buf[Udp.DATA] = (ACK<<16)+block;
boolean last = p.len != Udp.DATA*4+4+512;
p.len = Udp.DATA*4+4;
Dbg.wr('a');
Dbg.intVal(block);
++block;
if (last) { // end of write
tftpInit();
}
}
} else {
error(p);
}
}
/**
* program flash.
*/
private static void program(int[] buf, int block) {
int i, j;
int base;
block--;
i = fn>>8;
Timer.wd(); // toggle for each block?
if (i=='f') { // program flash
base = (block<<9);
base += ((fn&0xff)-'0')<<16; // 64 KB sector
if ((base & 0xffff) ==0) {
// Dbg.wr('e');
// Dbg.hexVal(base);
Amd.erase(base);
}
// Dbg.wr('p');
// Dbg.intVal(block);
// Dbg.hexVal(base);
progloop(base, buf);
}
}
private static void progloop(int base, int[] buf) {
int i, w;
for (i=1; i<129; ++i) {
w = buf[Udp.DATA+i];
Amd.program(base, w>>>24);
Amd.program(base+1, w>>>16);
Amd.program(base+2, w>>>8);
Amd.program(base+3, w);
base += 4;
}
}
/**
* read internal memory or flash.
*/
private static void read(int[] buf, int block) {
int i, j, k;
int base;
block--;
i = fn>>8;
if (i=='i') { // read internal memory
base = block<<7;
for (i=0; i<128; ++i) {
buf[Udp.DATA+1+i] = com.jopdesign.sys.Native.rdIntMem(base+i);
}
} else if (i=='f') { // read flash
base = (block<<9) + 0x80000; // add offset because we use Native.rdMem!
base += ((fn&0xff)-'0')<<16; // 64 KB sector
k = 0;
for (i=0; i<128; ++i) {
for (j=0; j<4; ++j) {
k <<= 8;
k += com.jopdesign.sys.Native.rdMem(base+(i<<2)+j);
}
buf[Udp.DATA+1+i] = k;
}
} else { // read nothing
for (i=0; i<128; ++i) {
buf[Udp.DATA+1+i] = 0;
}
}
}
}