diff -Naur busybox.orig/include/usage.h busybox/include/usage.h
--- busybox.orig/include/usage.h	2008-03-17 18:23:32 +0000
+++ busybox/include/usage.h	2008-03-17 21:21:09 +0000
@@ -3966,6 +3966,7 @@
      "\nOptions:" \
      "\n	-l FILE	Local FILE" \
      "\n	-r FILE	Remote FILE" \
+     "\n	-v	Be verbose" \
 	USE_FEATURE_TFTP_GET( \
      "\n	-g	Get file" \
 	) \
@@ -3974,7 +3975,9 @@
 	) \
 	USE_FEATURE_TFTP_BLOCKSIZE( \
      "\n	-b SIZE	Transfer blocks of SIZE octets" \
-	)
+	) \
+     "\n	-n RETRIES Set retries counter" \
+     "\n	-t MS	Set timeout, milliseconds"
 
 #define tftpd_trivial_usage \
        "[DIR]"
diff -Naur busybox.orig/networking/tftp.c busybox/networking/tftp.c
--- busybox.orig/networking/tftp.c	2008-03-17 18:23:14 +0000
+++ busybox/networking/tftp.c	2008-03-17 23:29:35 +0000
@@ -16,7 +16,7 @@
  *
  * utftp:  Copyright (C) 1999 Uwe Ohse <uwe@ohse.de>
  *
- * tftpd added by Denys Vlasenko
+ * tftpd added by Denys Vlasenko & Vladimir Dronnikov
  *
  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  * ------------------------------------------------------------------------- */
@@ -26,17 +26,31 @@
 #if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT
 
 #define TFTP_BLOCKSIZE_DEFAULT 512      /* according to RFC 1350, don't change */
-#define TFTP_TIMEOUT_MS         50
-#define TFTP_MAXTIMEOUT_MS    2000
-#define TFTP_NUM_RETRIES        12      /* number of backed-off retries */
+#define TFTP_TIMEOUT_MS         5000 // WOW! Another pure arbitrary timeout! Should be cmdline option then!
+#define TFTP_MAXTIMEOUT_MS    20000
+#define TFTP_NUM_RETRIES 	12      /* DEFAULT number of backed-off retries */
 
 /* opcodes we support */
-#define TFTP_RRQ   1
-#define TFTP_WRQ   2
-#define TFTP_DATA  3
-#define TFTP_ACK   4
-#define TFTP_ERROR 5
-#define TFTP_OACK  6
+enum {
+	TFTP_RRQ = 1,
+	TFTP_WRQ,
+	TFTP_DATA,
+	TFTP_ACK,
+	TFTP_ERROR,
+	TFTP_OACK,
+};
+
+/* errcodes we support */
+enum {
+	ERR_NOT_FOUND = 1,
+	ERR_ACCESS,
+	ERR_NO_ROOM,
+	ERR_OPCODE,
+	ERR_TID,
+	ERR_EXISTS,
+	ERR_USER,
+	ERR_OPTION,
+};
 
 #if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT
 #define USE_GETPUT(...)
@@ -51,6 +65,7 @@
 /* masks coming from getopt32 */
 #define CMD_GET(cmd) ((cmd) & 1)
 #define CMD_PUT(cmd) ((cmd) & 2)
+#define VERBOSE(cmd) ((cmd) & 4)
 #endif
 /* NB: in the code below
  * CMD_GET(cmd) and CMD_PUT(cmd) are mutually exclusive
@@ -118,7 +133,8 @@
 		len_and_sockaddr *peer_lsa,
 		USE_TFTP(const char *remote_file,)
 		int local_fd,
-		int blocksize)
+		int blocksize,
+		unsigned opt_retries, unsigned opt_timeout)
 {
 #if !ENABLE_TFTP
 #define remote_file NULL
@@ -248,15 +264,17 @@
 		/* NB: send_len value is preserved in code below
 		 * for potential resend */
 
-		retries = TFTP_NUM_RETRIES;	/* re-initialize */
-		waittime_ms = TFTP_TIMEOUT_MS;
+		retries = opt_retries;	/* re-initialize */
+		waittime_ms = opt_timeout;
 
  send_again:
 #if ENABLE_DEBUG_TFTP
-		fprintf(stderr, "sending %u bytes\n", send_len);
-		for (cp = xbuf; cp < &xbuf[send_len]; cp++)
-			fprintf(stderr, "%02x ", (unsigned char) *cp);
-		fprintf(stderr, "\n");
+		if (VERBOSE(cmd)) {
+			fprintf(stderr, "sending %u bytes\n", send_len);
+			for (cp = xbuf; cp < &xbuf[send_len]; cp++)
+				fprintf(stderr, "%02x ", (unsigned char) *cp);
+			fprintf(stderr, "\n");
+		}
 #endif
 		xsendto(socket_fd, xbuf, send_len, &peer_lsa->u.sa, peer_lsa->len);
 		/* Was it final ACK? then exit */
@@ -313,7 +331,9 @@
 		recv_blk = ntohs( ((uint16_t*)rbuf)[1] );
 
 #if ENABLE_DEBUG_TFTP
-		fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, recv_blk);
+		if (VERBOSE(cmd)) {
+			fprintf(stderr, "received %d bytes: %04x %04x\n", len, opcode, recv_blk);
+		}
 #endif
 
 		if (opcode == TFTP_ERROR) {
@@ -363,8 +383,10 @@
 						goto ret;
 					}
 #if ENABLE_DEBUG_TFTP
-					fprintf(stderr, "using blksize %u\n",
-							blksize);
+					if (VERBOSE(cmd)) {
+						fprintf(stderr, "using blksize %u\n",
+								blksize);
+					}
 #endif
 					tftp_bufsize = blksize + 4;
 					/* Send ACK for OACK ("block" no: 0) */
@@ -447,17 +469,22 @@
 	int flags = 0;
 	int result;
 	int blocksize = TFTP_BLOCKSIZE_DEFAULT;
+	unsigned opt_retries = TFTP_NUM_RETRIES;
+	unsigned opt_timeout = TFTP_TIMEOUT_MS;
 
 	/* -p or -g is mandatory, and they are mutually exclusive */
 	opt_complementary = "" USE_FEATURE_TFTP_GET("g:") USE_FEATURE_TFTP_PUT("p:")
 			USE_GETPUT("g--p:p--g:")
-			USE_FEATURE_TFTP_BLOCKSIZE("b+");
+			USE_FEATURE_TFTP_BLOCKSIZE("b+")
+			"n+:t+";
 
 	USE_GETPUT(cmd =) getopt32(argv,
 			USE_FEATURE_TFTP_GET("g") USE_FEATURE_TFTP_PUT("p")
-				"l:r:" USE_FEATURE_TFTP_BLOCKSIZE("b:"),
+				"vl:r:" USE_FEATURE_TFTP_BLOCKSIZE("b:") "n:t:",
 			&local_file, &remote_file
-			USE_FEATURE_TFTP_BLOCKSIZE(, &blocksize));
+			USE_FEATURE_TFTP_BLOCKSIZE(, &blocksize)
+			, &opt_retries, &opt_timeout
+	);
 	argv += optind;
 
 	flags = O_RDONLY;
@@ -486,16 +513,19 @@
 	peer_lsa = xhost2sockaddr(argv[0], port);
 
 #if ENABLE_DEBUG_TFTP
-	fprintf(stderr, "using server '%s', remote_file '%s', local_file '%s'\n",
+	if (VERBOSE(cmd)) {
+		fprintf(stderr, "using server '%s', remote_file '%s', local_file '%s'\n",
 			xmalloc_sockaddr2dotted(&peer_lsa->u.sa),
 			remote_file, local_file);
+	}
 #endif
 
 	result = tftp_protocol(
 			USE_GETPUT(cmd,)
 			NULL /* our_lsa*/,
 			peer_lsa,
-			remote_file, local_fd, blocksize);
+			remote_file, local_fd, blocksize,
+			opt_retries, opt_timeout);
 
 	if (ENABLE_FEATURE_CLEAN_UP)
 		close(local_fd);
@@ -507,102 +537,136 @@
 
 #endif /* ENABLE_TFTP */
 
-#if ENABLE_TFTPD
-
-/* TODO: libbb candidate? */
-static len_and_sockaddr *get_sock_lsa(int s)
-{
-	len_and_sockaddr *lsa;
-	socklen_t len = 0;
+/* vi: set sw=4 ts=4: */
+/*
+ * bare bones TFTP daemon
+ *
+ * Copyright (C) 2008 by Vladimir Dronnikov <dronnikov@gmail.com>
+ *
+ * Licensed under GPLv2, see file LICENSE in this tarball for details.
+ */
 
-	if (getsockname(s, NULL, &len) != 0)
-		return NULL;
-	lsa = xzalloc(LSA_LEN_SIZE + len);
-	lsa->len = len;
-	getsockname(s, &lsa->u.sa, &lsa->len);
-	return lsa;
-}
+#if ENABLE_TFTPD
 
 int tftpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
+int tftpd_main(int argc ATTRIBUTE_UNUSED, char **argv)
 {
-	struct stat statbuf;
-	char block_buf[TFTP_BLOCKSIZE_DEFAULT];
-	len_and_sockaddr *our_lsa;
-	len_and_sockaddr *peer_lsa;
-	char *filename, *mode, *opt_str;
-	int result, opcode, cmd, req_modebits, open_mode, local_fd, blksize;
-
-	our_lsa = get_sock_lsa(STDIN_FILENO);
-	if (!our_lsa)
-		bb_perror_msg_and_die("stdin is not a socket");
-	peer_lsa = xzalloc(LSA_LEN_SIZE + our_lsa->len);
-	peer_lsa->len = our_lsa->len;
+	int fd = -1;
+	unsigned seq = 0;
+	ssize_t len;
+#if ENABLE_FEATURE_TFTP_BLOCKSIZE // +212 octets
+	size_t blksize = TFTP_BLOCKSIZE_DEFAULT;
+#else
+#	define blksize TFTP_BLOCKSIZE_DEFAULT
+#endif
+	char *buf;
 
+	// chdir to target location
 	if (argv[1])
 		xchdir(argv[1]);
 
-	result = recv_from_to(STDIN_FILENO, block_buf, sizeof(block_buf),
-			0 /* flags */,
-			&peer_lsa->u.sa, &our_lsa->u.sa, our_lsa->len);
-
-	opcode = ntohs(*(uint16_t*)block_buf);
-	if (result < 4 || result >= sizeof(block_buf)
-	 || block_buf[result-1] != '\0'
-	 || (opcode != TFTP_RRQ && opcode != TFTP_WRQ)
-	) {
-		bb_error_msg_and_die("malformed packet");
-	}
-	filename = block_buf + 2;
-	if (filename[0] == '.' || strstr(filename, "/.")) {
-		bb_error_msg_and_die("dot in filename");
-	}
-	mode = filename + strlen(filename) + 1;
-	if (mode >= block_buf + sizeof(block_buf)
-	 || strcmp(mode, "octet") != 0
-	) {
-		bb_error_msg_and_die("malformed packet");
-	}
-	blksize = TFTP_BLOCKSIZE_DEFAULT;
+	// allocate transfer buffer
+	//
+	buf = xmalloc(blksize+4);
+
+	// read packets: stdin, stdout -- network.
+	// packets of length < 5 indicate terminal condition
+	while ((len = safe_read(STDIN_FILENO, buf, blksize+4)) >= 4) {
+		uint8_t cmd = ntohs(*((uint16_t *)buf));
+#define err cmd
+		// read or write requested?
+		if (TFTP_RRQ == cmd || TFTP_WRQ == cmd) {
 #if ENABLE_FEATURE_TFTP_BLOCKSIZE
-	opt_str = mode + 6;
-	if (opt_str < block_buf + sizeof(block_buf)) {
-		char *res = tftp_option_get(opt_str, block_buf + sizeof(block_buf) - opt_str, "blksize");
-		if (res) {
-			int sz = xatoi_u(res);
-			if (tftp_blocksize_check(sz, 0))
-				blksize = sz;
-		}
-	}
+			char *s;
+			// buf: 0? filename 0 "octet" 0 ["blksize" 0 #octets 0]
+			// we support only "octet" binary mode
+			s = buf+2;
+			s += strlen(s)+1;
+			if (0 != strcmp("octet", s)) {
+				err = ERR_OPCODE;
+				goto bad;
+
+			}
 #endif
-	xstat(filename, &statbuf);
-	/* if opcode == TFTP_WRQ: */
-	cmd = 1; /* CMD_GET: we will receive file's data */
-	req_modebits = 0222; /* writable by anyone */
-	open_mode = O_WRONLY | O_TRUNC;
-	if (opcode == TFTP_RRQ) {
-		cmd = 2; /* CMD_PUT */
-		req_modebits = 0444; /* readable by anyone */
-		open_mode = O_RDONLY;
-	}
-	if (!S_ISREG(statbuf.st_mode)
-	 || (statbuf.st_mode & req_modebits) != req_modebits
-	) {
-		bb_error_msg_and_die("access to '%s' is denied", filename);
+			cmd -= TFTP_RRQ;
+			// open or create requested file
+			fd = open_or_warn(buf+2, (cmd) ? (O_CREAT | O_WRONLY | O_TRUNC | O_EXCL) : O_RDONLY);
+			if (fd < 0) {
+				err = cmd ? ERR_EXISTS : ERR_NOT_FOUND;
+				goto bad;
+			}
+#if ENABLE_FEATURE_TFTP_BLOCKSIZE
+			// check if blksize option is given
+			s = tftp_option_get(buf+2, len-2, "blksize");
+			if (s) {
+				// reallocate transfer buffer
+				blksize = xatoi_u(s);
+				if (tftp_blocksize_check(blksize, blksize)) {
+					buf = xrealloc(buf, blksize+4);
+					// send OACK
+					buf[1] = TFTP_OACK;
+					strcpy(buf+2, "blksize");
+					s = utoa_to_buf(blksize, buf+2+sizeof("blksize"), 6);
+					*s = '\0';
+					len = (s-buf+1)-4; // send sends len+4 bytes
+					goto send;
+				}
+				// blocksize is bad... -> who cares?
+			}
+#endif
+			// no blksize option is given or it is not valid ->
+			// perform vanilla processing
+			// read requested?
+			if (!cmd) {
+				// RRQ should be acknowledged with data packet of seq num 1
+				goto send_data;
+			// write requested?
+			} else {
+				// WRQ should be acknowledged with seq num 0
+				*((uint16_t *)(buf+2)) = 0;
+				// ack
+				goto send_ack;
+			}
+		// data packet?
+		} else if (TFTP_DATA == cmd) {
+			// ... dump contents to the file being written
+			if (full_write(fd, buf+4, len-4) < 0) {
+				err = ERR_NO_ROOM;
+				goto bad;
+			}
+ send_ack:
+ 			// send ACK
+			buf[1] = TFTP_ACK;
+			len = 0;
+			goto send;
+		// ack packet?
+		} else if (TFTP_ACK == cmd) {
+ send_data:
+			// ... send next data chunk
+			len = full_read(fd, buf+4, blksize);
+			if (len < 0) {
+				err = ERR_ACCESS;
+				goto bad;
+			}
+ 			// send DATA
+			buf[1] = TFTP_DATA;
+			*((uint16_t *)(buf+2)) = htons(++seq);
+ send:
+			xwrite(STDOUT_FILENO, buf, len+4);
+		// bad packet!
+		} else {
+			err = ERR_OPCODE;
+ bad:
+			buf[1] = TFTP_ERROR;
+			*((uint16_t *)(buf+2)) = htons(err);
+			buf[4] = 0; // error string = ""
+			full_write(STDOUT_FILENO, buf, 5);
+			xfunc_die();
+		}
 	}
-	local_fd = xopen(filename, open_mode);
+	close(fd);
 
-	close(STDIN_FILENO); /* close old, possibly wildcard socket */
-	/* tftp_protocol() will create new one, bound to particular local IP */
-	result = tftp_protocol(
-		USE_GETPUT(cmd,)
-		our_lsa, peer_lsa,
-		USE_TFTP(NULL /*remote_file*/,)
-		local_fd,
-		blksize
-	);
-
-	return result;
+	return EXIT_SUCCESS;
 }
 
 #endif /* ENABLE_TFTPD */
