--- a/common/cmd_net.c
+++ b/common/cmd_net.c
@@ -43,6 +43,18 @@ U_BOOT_CMD(
 	"[loadAddress] [[hostIPaddr:]bootfilename]"
 );
 
+#if defined(CONFIG_CMD_HTTPD)
+int do_httpd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	return NetLoopHttpd();
+}
+
+U_BOOT_CMD(
+	httpd,	1,	1,	do_httpd,
+	"httpd\t- start webserver", ""
+);
+#endif
+
 int do_tftpb (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 {
 	return netboot_common (TFTP, cmdtp, argc, argv);
--- a/include/net.h
+++ b/include/net.h
@@ -383,7 +383,8 @@ extern int NetTimeOffset;			/* offset ti
 
 /* Initialize the network adapter */
 extern int	NetLoop(proto_t);
-
+extern int	NetLoopHttpd(void);
+extern void NetSendHttpd(void);
 /* Shutdown adapters and cleanup */
 extern void	NetStop(void);
 
--- /dev/null
+++ b/net/httpd.c
@@ -0,0 +1,52 @@
+/*
+ *	Copyright 1994, 1995, 2000 Neil Russell.
+ *	(See License)
+ *	Copyright 2000, 2001 DENX Software Engineering, Wolfgang Denk, wd@denx.de
+ */
+
+#include <common.h>
+#include <command.h>
+#include <net.h>
+#include "uip-0.9/uipopt.h"
+#include "uip-0.9/uip.h"
+#include "uip-0.9/uip_arp.h"
+
+
+#if defined(CONFIG_CMD_HTTPD)
+
+#define TIMEOUT		5
+
+static int arptimer = 0;
+
+void
+HttpdHandler (void)
+{
+	int i;
+	for(i = 0; i < UIP_CONNS; i++) {
+		uip_periodic(i);
+		if(uip_len > 0) {
+			uip_arp_out();
+			NetSendHttpd();
+		}
+	}
+	if(++arptimer == 20) {
+		uip_arp_timer();
+		arptimer = 0;
+	}
+}
+
+static void
+HttpdTimeout (void)
+{
+	puts ("T ");
+	NetSetTimeout (TIMEOUT * 1000, HttpdTimeout);
+}
+
+void
+HttpdStart (void)
+{
+	uip_init();
+	httpd_init();
+}
+
+#endif
--- /dev/null
+++ b/include/httpd.h
@@ -0,0 +1,17 @@
+#ifndef _UIP_HTTPD_H__
+#define _UIP_HTTPD_H__
+
+void HttpdStart (void);
+void HttpdHandler (void);
+
+/* board specific implementation */
+extern int do_http_upgrade(const unsigned char *data, const ulong size);
+
+#define HTTP_PROGRESS_START		0
+#define HTTP_PROGRESS_TIMEOUT		1
+#define HTTP_PROGRESS_UPLOAD_READY	2
+#define HTTP_PROGRESS_UGRADE_READY	3
+#define HTTP_PROGRESS_UGRADE_FAILED	4
+extern int do_http_progress(const int state);
+
+#endif
--- a/net/Makefile
+++ b/net/Makefile
@@ -26,6 +26,10 @@ include $(TOPDIR)/config.mk
 # CFLAGS += -DDEBUG
 
 LIB	= $(obj)libnet.a
+UIPDIR  = uip-0.9
+RSADIR  = uip-0.9
+$(shell mkdir -p $(obj)$(UIPDIR)) 
+$(shell mkdir -p $(obj)$(RSADIR)) 
 
 COBJS-y += bootp.o
 COBJS-$(CONFIG_CMD_DNS)  += dns.o
@@ -36,6 +40,9 @@ COBJS-y += rarp.o
 COBJS-$(CONFIG_CMD_SNTP) += sntp.o
 COBJS-y += tftp.o
 
+COBJS-$(CONFIG_CMD_HTTPD) += httpd.o $(UIPDIR)/fs.o $(UIPDIR)/httpd.o $(UIPDIR)/uip_arp.o $(UIPDIR)/uip_arch.o $(UIPDIR)/uip.o
+COBJS-$(CONFIG_CMD_RSA) += $(RSADIR)/bigint.o $(RSADIR)/base64.o $(RSADIR)/rmd160.o $(RSADIR)/rsa.o
+
 COBJS	:= $(COBJS-y)
 SRCS	:= $(COBJS:.o=.c)
 OBJS	:= $(addprefix $(obj),$(COBJS))
--- a/net/net.c
+++ b/net/net.c
@@ -95,6 +95,19 @@
 #if defined(CONFIG_CMD_DNS)
 #include "dns.h"
 #endif
+#if defined(CONFIG_CMD_HTTPD)
+#include "httpd.h"
+#include "uip-0.9/uipopt.h"
+#include "uip-0.9/uip.h"
+#include "uip-0.9/uip_arp.h"
+static int https_running = 0;
+int httpd_upload_complete = 0;
+unsigned char *httpd_upload_data = 0;
+extern int upload_running;
+void NetReceiveHttpd(volatile uchar * inpkt, int len);
+void NetSendHttpd(void);
+extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]); 
+#endif
 
 #if defined(CONFIG_CMD_NET)
 
@@ -1310,6 +1323,13 @@ NetReceive(volatile uchar * inpkt, int l
 
 	debug("packet received\n");
 
+#if defined(CONFIG_CMD_HTTPD)
+	if(https_running) {
+		NetReceiveHttpd(inpkt, len);
+		return;
+	}
+#endif
+
 	NetRxPacket = inpkt;
 	NetRxPacketLen = len;
 	et = (Ethernet_t *)inpkt;
@@ -1952,3 +1972,162 @@ ushort getenv_VLAN(char *var)
 {
 	return (string_to_VLAN(getenv(var)));
 }
+
+#if defined(CONFIG_CMD_HTTPD)
+
+void
+NetSendHttpd(void)
+{
+	volatile uchar *tmpbuf = NetTxPacket;
+	int i;
+
+	for(i = 0; i < 40 + UIP_LLH_LEN; i++) {
+		tmpbuf[i] = uip_buf[i];
+	}
+
+	for(; i < uip_len; i++) {
+		tmpbuf[i] = uip_appdata[i - 40 - UIP_LLH_LEN];
+	}
+	eth_send(NetTxPacket, uip_len);
+}
+
+#define BUF ((struct uip_eth_hdr *)&uip_buf[0])
+
+void
+NetReceiveHttpd(volatile uchar * inpkt, int len)
+{
+	memcpy(uip_buf, inpkt, len);
+	uip_len = len;
+	if(BUF->type == htons(UIP_ETHTYPE_IP)) {
+		uip_arp_ipin();
+		uip_input();
+		if(uip_len > 0) {
+			uip_arp_out();
+			NetSendHttpd();
+		}
+	} else if(BUF->type == htons(UIP_ETHTYPE_ARP)) {
+		uip_arp_arpin();
+		if(uip_len > 0) {
+			NetSendHttpd();
+		}
+	}
+}
+
+int
+NetLoopHttpd(void)
+{
+	unsigned long long tout = 0;
+	bd_t *bd = gd->bd;
+	unsigned short int ip[2];
+
+#ifdef CONFIG_NET_MULTI
+	NetRestarted = 0;
+	NetDevExists = 0;
+#endif
+
+	/* XXX problem with bss workaround */
+	NetArpWaitPacketMAC = NULL;
+	NetArpWaitTxPacket = NULL;
+	NetArpWaitPacketIP = 0;
+	NetArpWaitReplyIP = 0;
+	NetArpWaitTxPacket = NULL;
+	NetTxPacket = NULL;
+	NetTryCount = 1;
+
+	if (!NetTxPacket) {
+		int	i;
+		/*
+		 *	Setup packet buffers, aligned correctly.
+		 */
+		NetTxPacket = &PktBuf[0] + (PKTALIGN - 1);
+		NetTxPacket -= (ulong)NetTxPacket % PKTALIGN;
+		for (i = 0; i < PKTBUFSRX; i++) {
+			NetRxPackets[i] = NetTxPacket + (i+1)*PKTSIZE_ALIGN;
+		}
+	}
+
+	if (!NetArpWaitTxPacket) {
+		NetArpWaitTxPacket = &NetArpWaitPacketBuf[0] + (PKTALIGN - 1);
+		NetArpWaitTxPacket -= (ulong)NetArpWaitTxPacket % PKTALIGN;
+		NetArpWaitTxPacketSize = 0;
+	}
+
+restart:
+
+	eth_halt();
+#ifdef CONFIG_NET_MULTI
+	eth_set_current();
+#endif
+	if (eth_init(bd) < 0) {
+		eth_halt();
+		return(-1);
+	}
+
+#ifdef CONFIG_NET_MULTI
+	memcpy (NetOurEther, eth_get_dev()->enetaddr, 6);
+#else
+	eth_getenv_enetaddr("ethaddr", NetOurEther);
+#endif
+
+	NetCopyIP(&NetOurIP, &bd->bi_ip_addr);
+	NetOurGatewayIP = getenv_IPaddr ("gatewayip");
+	NetOurSubnetMask= getenv_IPaddr ("netmask");
+	NetOurVLAN = getenv_VLAN("vlan");
+	NetOurNativeVLAN = getenv_VLAN("nvlan");
+
+	printf("starting httpd server from server %ld.%ld.%ld.%ld\n",
+		(bd->bi_ip_addr & 0xff000000) >> 24,
+		(bd->bi_ip_addr & 0x00ff0000) >> 16,
+		(bd->bi_ip_addr & 0x0000ff00) >> 8,
+		(bd->bi_ip_addr & 0x000000ff));
+
+	HttpdStart();
+
+	ip[0] = ((bd->bi_ip_addr & 0xffff0000) >> 16);
+	ip[1] = (bd->bi_ip_addr & 0x0000ffff);
+	uip_sethostaddr(ip);
+
+	do_http_progress(HTTP_PROGRESS_START);
+
+	https_running = 1;
+	for (;;) {
+		unsigned long long t1;
+		WATCHDOG_RESET();
+		if(eth_rx() > 0) {
+			HttpdHandler();
+		} else {
+			t1 = get_ticks();
+			if(t1 - tout > 1000) {
+				do_http_progress(HTTP_PROGRESS_TIMEOUT);
+				tout = t1;
+			}
+		}
+		if(!httpd_upload_complete)
+			continue;
+		printf("Bytes transferred = %ld (%lx hex)\n",
+			NetBootFileXferSize,
+			NetBootFileXferSize);
+		eth_halt();
+		do_http_progress(HTTP_PROGRESS_UPLOAD_READY);
+		if(do_http_upgrade(&httpd_upload_data[0], NetBootFileXferSize) == 0) {
+			do_http_progress(HTTP_PROGRESS_UGRADE_READY);
+			udelay(1000 * 10);
+			do_reset (0,0,0,0);
+			return 0;
+		}
+		break;
+	}
+	https_running = 0;
+	NetBootFileXferSize = 0;
+	httpd_upload_complete = 0;
+	upload_running = 0;
+//	free(httpd_upload_data);
+
+	do_http_progress(HTTP_PROGRESS_UGRADE_FAILED);
+
+	goto restart;
+
+	return -1;
+}
+
+#endif
--- /dev/null
+++ b/net/rsa/base64.c
@@ -0,0 +1,137 @@
+#include "base64.h"
+
+static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+/* Note that '=' (padding) is 0 */
+static const unsigned char fb64[256] = {
+	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+	255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63,
+	52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255,  0,255,255,
+	255,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
+	15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255,
+	255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+	41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255,
+	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+};
+
+static int encodeblock( unsigned char *in, char *out, int len )
+{
+	char s[3];
+	int i;
+
+	for (i = 0; i < len; i++)
+		s[i] = in[i];
+	for (i = len; i < 3; i++)
+		s[i] = 0;
+	out[0] = (unsigned char)(cb64[(s[0] & 0xfc) >> 2 ]);
+	out[1] = (unsigned char)(cb64[((s[0] & 0x03) << 4) | ((s[1] & 0xf0) >> 4) ]);
+	out[2] = (unsigned char)(cb64[((s[1] & 0x0f) << 2) | ((s[2] & 0xc0) >> 6) ]);
+	out[3] = (unsigned char)(cb64[s[2] & 0x3f ]);
+	switch (len) {
+		case 1:
+			out[3] = '=';
+		case 2:
+			out[2] = '=';
+			break;
+		default:
+			break;
+	}
+
+	return 4;
+}
+
+static int decodeblock(char *ins, unsigned char *out, int len)
+{
+	int i;
+	unsigned char in[4];
+	int skip = 0;
+
+	if (len != 4)
+		return -1;
+	for (i = 0; i < len; i++) {
+		if (ins[i] == '=') {
+			in[i] = 0;
+			skip++;  
+		} else
+			in[i] = fb64[(int)(ins[i])];
+		if (in[i] == 255) {
+			return -1;
+		}
+	}
+	out[0] = (unsigned char ) (in[0] << 2 | in[1] >> 4);
+	if (skip == 2) {
+		return 1;
+	}
+	out[1] = (unsigned char )((in[1] & 0x0f) << 4 | in[2] >> 2);
+	if (skip == 1) {
+		return 2;
+	}
+	out[2] = (unsigned char ) (((in[2] << 6) & 0xc0) | in[3]);
+
+	return 3;
+}
+
+int B64_encode(char *source, char *destination, int size_source, int size_destination)
+{
+	int chunks, reminder, size, d, i, size_expected;
+	char *s;
+	unsigned char *t;
+
+	chunks = size_source / 3;
+	reminder = size_source % 3;
+	size = 0;
+	size_expected = (chunks * 4) + (reminder?(reminder + 1):0);
+	if (size_destination < ((chunks * 4) + (reminder?4:0))) {
+		return 1;
+	}
+	for (i = 0; i < chunks; i++) {
+		s = source + (i * 3); 
+		t = destination + (i * 4);
+		d = encodeblock(s, t, 3);
+		if (d == -1) {
+			return 1;
+		}
+		size += d;
+	}
+	if (reminder) {
+		d = encodeblock(source + (chunks * 3), destination + (chunks * 4), reminder);
+		if (d == -1) {
+			return 1;
+		}
+		size += d;
+	}
+	return size;
+}
+
+int B64_decode(char *source, char *destination, int size_source, int size_destination)
+{
+	int chunks, reminder, size, d, i;
+
+	chunks = size_source / 4;
+	reminder = size_source % 4;
+	size = 0;
+	if (reminder) {
+		return 1;
+	}
+	if (size_destination < ((chunks * 3))) {
+		printf("%d, %d\n",
+			size_destination, ((chunks * 3) + reminder));
+		return -1;
+	}
+	for (i = 0; i < chunks; i++) {
+		d = decodeblock(source + (i * 4), destination + (i * 3), 4);
+		if (d == -1) {
+			return -1;
+		}
+		size += d;
+	}
+	return size;
+}
+
--- /dev/null
+++ b/net/rsa/base64.h
@@ -0,0 +1,11 @@
+#ifndef _BASE64_H_
+#define _BASE64_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+int B64_encode(char *source, char *destination, int size_source, int size_destination);
+int B64_decode(char *source, char *destination, int size_source, int size_destination);
+#ifdef __cplusplus
+}
+#endif
+#endif
--- /dev/null
+++ b/net/rsa/bigint.c
@@ -0,0 +1,906 @@
+/*
+ *  Copyright(C) 2006
+ *
+ *  This library is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Lesser General Public License as published by
+ *  the Free Software Foundation; either version 2.1 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This library 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public License
+ *  along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/**
+ * @defgroup bigint_api Big Integer API
+ * @brief The bigint implementation as used by the axTLS project.
+ *
+ * The bigint library is for RSA encryption/decryption as well as signing.
+ * This code tries to minimise use of malloc/free by maintaining a small 
+ * cache. A bigint context may maintain state by being made "permanent". 
+ * It be be later released with a bi_depermanent() and bi_free() call.
+ *
+ * It supports the following reduction techniques:
+ * - Classical
+ * - Barrett
+ * - Montgomery
+ *
+ * It also implements the following:
+ * - Karatsuba multiplication
+ * - Squaring
+ * - Sliding window exponentiation
+ * - Chinese Remainder Theorem (implemented in rsa.c).
+ *
+ * All the algorithms used are pretty standard, and designed for different
+ * data bus sizes. Negative numbers are not dealt with at all, so a subtraction
+ * may need to be tested for negativity.
+ *
+ * This library steals some ideas from Jef Poskanzer
+ * <http://cs.marlboro.edu/term/cs-fall02/algorithms/crypto/RSA/bigint>
+ * and GMP <http://www.swox.com/gmp>. It gets most of its implementation
+ * detail from "The Handbook of Applied Cryptography"
+ * <http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf>
+ * @{
+ */
+
+#include "bigint.h"
+#include <malloc.h>
+#include "div64.h"
+
+static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bi, comp i);
+static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom);
+static bigint *alloc(BI_CTX *ctx, int size);
+static bigint *trim(bigint *bi);
+static void more_comps(bigint *bi, int n);
+
+/**
+ * @brief Start a new bigint context.
+ * @return A bigint context.
+ */
+BI_CTX *bi_initialize(void)
+{
+    BI_CTX *ctx = (BI_CTX *)calloc(1, sizeof(BI_CTX));
+
+    ctx->active_list = NULL;
+    ctx->active_count = 0;
+    ctx->free_list = NULL;
+    ctx->free_count = 0;
+    ctx->mod_offset = 0;
+
+    /* the radix */
+    ctx->bi_radix = alloc(ctx, 2); 
+    ctx->bi_radix->comps[0] = 0;
+    ctx->bi_radix->comps[1] = 1;
+    bi_permanent(ctx->bi_radix);
+
+    return ctx;
+}
+
+/**
+ * @brief Close the bigint context and free any resources.
+ *
+ * Free up any used memory - a check is done if all objects were not 
+ * properly freed.
+ * @param ctx [in]   The bigint session context.
+ */
+void bi_terminate(BI_CTX *ctx)
+{
+    bigint *p, *pn;
+
+    bi_depermanent(ctx->bi_radix); 
+    bi_free(ctx, ctx->bi_radix);
+
+    if (ctx->active_count != 0)
+    {
+    	printf("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
+		printf("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
+		printf("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
+		printf("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
+		printf("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
+		printf("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
+		return;
+	}
+
+    for (p = ctx->free_list; p != NULL; p = pn)
+    {
+        pn = p->next;
+        free(p->comps);
+        free(p);
+    }
+
+    free(ctx);
+}
+
+/**
+ * @brief Increment the number of references to this object. 
+ * It does not do a full copy.
+ * @param bi [in]   The bigint to copy.
+ * @return A referent to the same bigint.
+ */
+bigint *bi_copy(bigint *bi)
+{
+    check(bi);
+    if (bi->refs != PERMANENT)
+        bi->refs++;
+    return bi;
+}
+
+/**
+ * @brief Simply make a bigint object "unfreeable" if bi_free() is called on it.
+ *
+ * For this object to be freed, bi_depermanent() must be called.
+ * @param bi [in]   The bigint to be made permanent.
+ */
+void bi_permanent(bigint *bi)
+{
+    check(bi);
+    if (bi->refs != 1)
+    {
+		printf("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
+		printf("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
+		printf("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
+		return;
+	}
+
+    bi->refs = PERMANENT;
+}
+
+/**
+ * @brief Take a permanent object and make it elligible for freedom.
+ * @param bi [in]   The bigint to be made back to temporary.
+ */
+void bi_depermanent(bigint *bi)
+{
+    check(bi);
+    if (bi->refs != PERMANENT)
+    {
+        printf("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
+		printf("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
+		printf("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
+		printf("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
+		return;
+	}
+
+    bi->refs = 1;
+}
+
+/**
+ * @brief Free a bigint object so it can be used again. 
+ *
+ * The memory itself it not actually freed, just tagged as being available 
+ * @param ctx [in]   The bigint session context.
+ * @param bi [in]    The bigint to be freed.
+ */
+void bi_free(BI_CTX *ctx, bigint *bi)
+{
+    check(bi);
+    if (bi->refs == PERMANENT)
+    {
+        return;
+    }
+
+    if (--bi->refs > 0)
+    {
+        return;
+    }
+
+    bi->next = ctx->free_list;
+    ctx->free_list = bi;
+    ctx->free_count++;
+
+    if (--ctx->active_count < 0)
+    {
+        printf("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
+		printf("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
+		printf("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
+		printf("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
+		return;
+	}
+}
+
+/**
+ * @brief Convert an (unsigned) integer into a bigint.
+ * @param ctx [in]   The bigint session context.
+ * @param i [in]     The (unsigned) integer to be converted.
+ * 
+ */
+bigint *int_to_bi(BI_CTX *ctx, comp i)
+{
+    bigint *biR = alloc(ctx, 1);
+    biR->comps[0] = i;
+    return biR;
+}
+
+/**
+ * @brief Do a full copy of the bigint object.
+ * @param ctx [in]   The bigint session context.
+ * @param bi  [in]   The bigint object to be copied.
+ */
+bigint *bi_clone(BI_CTX *ctx, const bigint *bi)
+{
+    bigint *biR = alloc(ctx, bi->size);
+    check(bi);
+    memcpy(biR->comps, bi->comps, bi->size*COMP_BYTE_SIZE);
+    return biR;
+}
+
+/**
+ * @brief Perform an additon operation between two bigints.
+ * @param ctx [in]  The bigint session context.
+ * @param bia [in]  A bigint.
+ * @param bib [in]  Another bigint.
+ * @return The result of the addition.
+ */
+bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib)
+{
+    int n;
+    comp carry = 0;
+    comp *pa, *pb;
+
+    check(bia);
+    check(bib);
+
+    if (bia->size > bib->size)
+        n = bia->size;
+    else
+        n = bib->size;
+    more_comps(bia, n+1);
+    more_comps(bib, n);
+    pa = bia->comps;
+    pb = bib->comps;
+
+    do
+    {
+        comp  sl, rl, cy1;
+        sl = *pa + *pb++;
+        rl = sl + carry;
+        cy1 = sl < *pa;
+        carry = cy1 | (rl < sl);
+        *pa++ = rl;
+    } while (--n != 0);
+
+    *pa = carry;                  /* do overflow */
+    bi_free(ctx, bib);
+    return trim(bia);
+}
+
+/**
+ * @brief Perform a subtraction operation between two bigints.
+ * @param ctx [in]  The bigint session context.
+ * @param bia [in]  A bigint.
+ * @param bib [in]  Another bigint.
+ * @param is_negative [out] If defined, indicates that the result was negative.
+ * is_negative may be NULL.
+ * @return The result of the subtraction. The result is always positive.
+ */
+bigint *bi_subtract(BI_CTX *ctx, 
+        bigint *bia, bigint *bib, int *is_negative)
+{
+    int n = bia->size;
+    comp *pa, *pb, carry = 0;
+
+    check(bia);
+    check(bib);
+
+    more_comps(bib, n);
+    pa = bia->comps;
+    pb = bib->comps;
+
+    do 
+    {
+        comp sl, rl, cy1;
+        sl = *pa - *pb++;
+        rl = sl - carry;
+        cy1 = sl > *pa;
+        carry = cy1 | (rl > sl);
+        *pa++ = rl;
+    } while (--n != 0);
+
+    if (is_negative)    /* indicate a negative result */
+    {
+        *is_negative = carry;
+    }
+
+    bi_free(ctx, trim(bib));    /* put bib back to the way it was */
+    return trim(bia);
+}
+
+/**
+ * Perform a multiply between a bigint an an (unsigned) integer
+ */
+static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bia, comp b)
+{
+    int j = 0, n = bia->size;
+    bigint *biR = alloc(ctx, n + 1);
+    comp carry = 0;
+    comp *r = biR->comps;
+    comp *a = bia->comps;
+
+    check(bia);
+
+    /* clear things to start with */
+    memset(r, 0, ((n+1)*COMP_BYTE_SIZE));
+
+    do
+    {
+        long_comp tmp = *r + (long_comp)a[j]*b + carry;
+        *r++ = (comp)tmp;              /* downsize */
+        carry = (comp)(tmp >> COMP_BIT_SIZE);
+    } while (++j < n);
+
+    *r = carry;
+    bi_free(ctx, bia);
+    return trim(biR);
+}
+
+/**
+ * @brief Does both division and modulo calculations. 
+ *
+ * Used extensively when doing classical reduction.
+ * @param ctx [in]  The bigint session context.
+ * @param u [in]    A bigint which is the numerator.
+ * @param v [in]    Either the denominator or the modulus depending on the mode.
+ * @param is_mod [n] Determines if this is a normal division (0) or a reduction
+ * (1).
+ * @return  The result of the division/reduction.
+ */
+bigint *bi_divide(BI_CTX *ctx, bigint *u, bigint *v, int is_mod)
+{
+    int n = v->size, m = u->size-n;
+    int j = 0, orig_u_size = u->size;
+    uint8_t mod_offset = ctx->mod_offset;
+    comp d;
+    bigint *quotient, *tmp_u;
+    comp q_dash;
+
+    check(u);
+    check(v);
+
+    /* if doing reduction and we are < mod, then return mod */
+    if (is_mod && bi_compare(v, u) > 0)
+    {
+        bi_free(ctx, v);
+        return u;
+    }
+
+	quotient = alloc(ctx, m+1);
+    tmp_u = alloc(ctx, n+1);
+    v = trim(v);        /* make sure we have no leading 0's */
+	// d = (comp)((long_comp)COMP_RADIX/(V1+1));
+	long_comp x = COMP_RADIX; do_div(x, V1+1); d = x;
+
+    /* clear things to start with */
+    memset(quotient->comps, 0, ((quotient->size)*COMP_BYTE_SIZE));
+
+    /* normalise */
+    if (d > 1)
+    {
+		u = bi_int_multiply(ctx, u, d);
+
+		if (is_mod)
+        {
+			v = ctx->bi_normalised_mod[mod_offset];
+        }
+        else
+        {
+			v = bi_int_multiply(ctx, v, d);
+        }
+	}
+
+	if (orig_u_size == u->size)  /* new digit position u0 */
+    {
+		more_comps(u, orig_u_size + 1);
+    }
+
+	do
+    {
+        /* get a temporary short version of u */
+		memcpy(tmp_u->comps, &u->comps[u->size-n-1-j], (n+1)*COMP_BYTE_SIZE);
+
+        /* calculate q' */
+        if (U(0) == V1)
+        {
+			q_dash = COMP_RADIX-1;
+        }
+        else
+        {
+            //q_dash = (comp)(((long_comp)U(0)*COMP_RADIX + U(1))/V1);
+			long_comp x = U(0)*COMP_RADIX + U(1); do_div(x, V1); q_dash = x;
+
+        }
+
+		if (v->size > 1 && V2)
+        {
+            /* we are implementing the following
+            if (V2*q_dash > (((U(0)*COMP_RADIX + U(1) - 
+                    q_dash*V1)*COMP_RADIX) + U(2))) ... */
+			comp inner = (comp)((long_comp)COMP_RADIX*U(0) + U(1) - 
+                                        (long_comp)q_dash*V1);
+			if ((long_comp)V2*q_dash > (long_comp)inner*COMP_RADIX + U(2))
+            {
+				q_dash--;
+            }
+        }
+
+        /* multiply and subtract */
+        if (q_dash)
+        {
+            int is_negative;
+			tmp_u = bi_subtract(ctx, tmp_u, 
+                    bi_int_multiply(ctx, bi_copy(v), q_dash), &is_negative);
+			more_comps(tmp_u, n+1);
+
+			Q(j) = q_dash; 
+
+            /* add back */
+            if (is_negative)
+            {
+				Q(j)--;
+                tmp_u = bi_add(ctx, tmp_u, bi_copy(v));
+                /* lop off the carry */
+                tmp_u->size--;
+                v->size--;
+            }
+		}
+        else
+        {
+			Q(j) = 0; 
+        }
+
+        /* copy back to u */
+		memcpy(&u->comps[u->size-n-1-j], tmp_u->comps, (n+1)*COMP_BYTE_SIZE);
+    } while (++j <= m);
+
+    bi_free(ctx, tmp_u);
+    bi_free(ctx, v);
+
+    if (is_mod)     /* get the remainder */
+    {
+		bi_free(ctx, quotient);
+		return bi_int_divide(ctx, trim(u), d);
+    }
+    else            /* get the quotient */
+    {
+		bi_free(ctx, u);
+		return trim(quotient);
+    }
+}
+
+/**
+ * Perform an integer divide on a bigint.
+ */
+static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom)
+{
+    int i = biR->size - 1;
+    long_comp r = 0;
+
+    check(biR);
+
+	do
+    {
+		r = (r<<COMP_BIT_SIZE) + biR->comps[i];
+		//biR->comps[i] = (comp)(r / denom);
+		long_comp x = r; do_div(x, denom); biR->comps[i] = x;
+/*		while(r > denom)
+		{
+			r -= denom;
+		}*/
+		r%=denom;
+	} while (--i != 0);
+
+    return trim(biR);
+}
+
+/**
+ * @brief Allow a binary sequence to be imported as a bigint.
+ * @param ctx [in]  The bigint session context.
+ * @param data [in] The data to be converted.
+ * @param size [in] The number of bytes of data.
+ * @return A bigint representing this data.
+ */
+bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int size)
+{
+    bigint *biR = alloc(ctx, (size+COMP_BYTE_SIZE-1)/COMP_BYTE_SIZE);
+    int i, j = 0, offset = 0;
+
+    memset(biR->comps, 0, biR->size*COMP_BYTE_SIZE);
+
+    for (i = size-1; i >= 0; i--)
+    {
+        biR->comps[offset] += data[i] << (j*8);
+
+        if (++j == COMP_BYTE_SIZE)
+        {
+            j = 0;
+            offset ++;
+        }
+    }
+
+    return trim(biR);
+}
+
+/**
+ * @brief Take a bigint and convert it into a byte sequence. 
+ *
+ * This is useful after a decrypt operation.
+ * @param ctx [in]  The bigint session context.
+ * @param x [in]  The bigint to be converted.
+ * @param data [out] The converted data as a byte stream.
+ * @param size [in] The maximum size of the byte stream. Unused bytes will be
+ * zeroed.
+ */
+void bi_export(BI_CTX *ctx, bigint *x, uint8_t *data, int size)
+{
+    int i, j, k = size-1;
+
+    check(x);
+    memset(data, 0, size);  /* ensure all leading 0's are cleared */
+
+    for (i = 0; i < x->size; i++)
+    {
+        for (j = 0; j < COMP_BYTE_SIZE; j++)
+        {
+            comp mask = 0xff << (j*8);
+            int num = (x->comps[i] & mask) >> (j*8);
+            data[k--] = num;
+
+            if (k < 0)
+            {
+                break;
+            }
+        }
+    }
+
+    bi_free(ctx, x);
+}
+
+/**
+ * @brief Pre-calculate some of the expensive steps in reduction. 
+ *
+ * This function should only be called once (normally when a session starts).
+ * When the session is over, bi_free_mod() should be called. bi_mod_power()
+ * relies on this function being called.
+ * @param ctx [in]  The bigint session context.
+ * @param bim [in]  The bigint modulus that will be used.
+ * @param mod_offset [in] There are three moduluii that can be stored - the
+ * standard modulus, and it's two primes p and q. This offset refers to which
+ * modulus we are referring to.
+ * @see bi_free_mod(), bi_mod_power().
+ */
+void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset)
+{
+    int k = bim->size;
+	comp d;
+//    comp d = (comp)((long_comp)COMP_RADIX/(bim->comps[k-1]+1));
+	long_comp x = COMP_RADIX; do_div(x, bim->comps[k-1]+1); d = x;
+
+    ctx->bi_mod[mod_offset] = bim;
+    bi_permanent(ctx->bi_mod[mod_offset]);
+    ctx->bi_normalised_mod[mod_offset] = bi_int_multiply(ctx, bim, d);
+    bi_permanent(ctx->bi_normalised_mod[mod_offset]);
+}
+
+/**
+ * @brief Used when cleaning various bigints at the end of a session.
+ * @param ctx [in]  The bigint session context.
+ * @param mod_offset [in] The offset to use.
+ * @see bi_set_mod().
+ */
+void bi_free_mod(BI_CTX *ctx, int mod_offset)
+{
+    bi_depermanent(ctx->bi_mod[mod_offset]);
+    bi_free(ctx, ctx->bi_mod[mod_offset]);
+    bi_depermanent(ctx->bi_normalised_mod[mod_offset]); 
+    bi_free(ctx, ctx->bi_normalised_mod[mod_offset]);
+}
+
+/** 
+ * Perform a standard multiplication between two bigints.
+ */
+static bigint *regular_multiply(BI_CTX *ctx, bigint *bia, bigint *bib)
+{
+    int i, j, i_plus_j, n = bia->size, t = bib->size;
+    bigint *biR = alloc(ctx, n + t);
+    comp *sr = biR->comps;
+    comp *sa = bia->comps;
+    comp *sb = bib->comps;
+
+    check(bia);
+    check(bib);
+
+    /* clear things to start with */
+    memset(biR->comps, 0, ((n+t)*COMP_BYTE_SIZE));
+    i = 0;
+
+    do 
+    {
+        comp carry = 0;
+        comp b = *sb++;
+        i_plus_j = i;
+        j = 0;
+
+        do
+        {
+            long_comp tmp = sr[i_plus_j] + (long_comp)sa[j]*b + carry;
+            sr[i_plus_j++] = (comp)tmp;              /* downsize */
+            carry = (comp)(tmp >> COMP_BIT_SIZE);
+        } while (++j < n);
+
+        sr[i_plus_j] = carry;
+    } while (++i < t);
+
+    bi_free(ctx, bia);
+    bi_free(ctx, bib);
+    return trim(biR);
+}
+
+/**
+ * @brief Perform a multiplication operation between two bigints.
+ * @param ctx [in]  The bigint session context.
+ * @param bia [in]  A bigint.
+ * @param bib [in]  Another bigint.
+ * @return The result of the multiplication.
+ */
+bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib)
+{
+    check(bia);
+    check(bib);
+
+    return regular_multiply(ctx, bia, bib);
+}
+
+
+/**
+ * @brief Compare two bigints.
+ * @param bia [in]  A bigint.
+ * @param bib [in]  Another bigint.
+ * @return -1 if smaller, 1 if larger and 0 if equal.
+ */
+int bi_compare(bigint *bia, bigint *bib)
+{
+    int r, i;
+
+    check(bia);
+    check(bib);
+
+    if (bia->size > bib->size)
+        r = 1;
+    else if (bia->size < bib->size)
+        r = -1;
+    else
+    {
+        comp *a = bia->comps; 
+        comp *b = bib->comps; 
+
+        /* Same number of components.  Compare starting from the high end
+         * and working down. */
+        r = 0;
+        i = bia->size - 1;
+
+        do 
+        {
+            if (a[i] > b[i])
+            { 
+                r = 1;
+                break; 
+            }
+            else if (a[i] < b[i])
+            { 
+                r = -1;
+                break; 
+            }
+        } while (--i >= 0);
+    }
+
+    return r;
+}
+
+/**
+ * Allocate and zero more components.  Does not consume bi. 
+ */
+static void more_comps(bigint *bi, int n)
+{
+    if (n > bi->max_comps)
+    {
+        if ((bi->max_comps * 2) > n) {
+	    bi->max_comps = bi->max_comps * 2;
+	} else {
+	    bi->max_comps = n;
+	}
+        bi->comps = (comp*)realloc(bi->comps, bi->max_comps * COMP_BYTE_SIZE);
+    }
+
+    if (n > bi->size)
+    {
+        memset(&bi->comps[bi->size], 0, (n-bi->size)*COMP_BYTE_SIZE);
+    }
+
+    bi->size = n;
+}
+
+/*
+ * Make a new empty bigint. It may just use an old one if one is available.
+ * Otherwise get one of the heap.
+ */
+static bigint *alloc(BI_CTX *ctx, int size)
+{
+    bigint *biR;
+
+    /* Can we recycle an old bigint? */
+    if (ctx->free_list != NULL)
+    {
+        biR = ctx->free_list;
+        ctx->free_list = biR->next;
+        ctx->free_count--;
+        if (biR->refs != 0)
+        {
+            printf("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
+			printf("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
+			printf("%s:%s[%d]\n", __FILE__, __func__, __LINE__);
+			return 0;
+		}
+
+        more_comps(biR, size);
+    }
+    else
+    {
+        /* No free bigints available - create a new one. */
+        biR = (bigint *)malloc(sizeof(bigint));
+        biR->comps = (comp*) malloc(size * COMP_BYTE_SIZE);
+        biR->max_comps = size;  /* give some space to spare */
+    }
+
+    biR->size = size;
+    biR->refs = 1;
+    biR->next = NULL;
+    ctx->active_count++;
+    return biR;
+}
+
+/*
+ * Work out the highest '1' bit in an exponent. Used when doing sliding-window
+ * exponentiation.
+ */
+static int find_max_exp_index(bigint *biexp)
+{
+    int i = COMP_BIT_SIZE-1;
+    comp shift = COMP_RADIX/2;
+    comp test = biexp->comps[biexp->size-1];    /* assume no leading zeroes */
+
+    check(biexp);
+
+    do
+    {
+        if (test & shift)
+        {
+            return i+(biexp->size-1)*COMP_BIT_SIZE;
+        }
+
+        shift >>= 1;
+    } while (--i != 0);
+
+    return -1;      /* error - must have been a leading 0 */
+}
+
+/*
+ * Is a particular bit is an exponent 1 or 0? Used when doing sliding-window
+ * exponentiation.
+ */
+static int exp_bit_is_one(bigint *biexp, int offset)
+{
+    comp test = biexp->comps[offset / COMP_BIT_SIZE];
+    int num_shifts = offset % COMP_BIT_SIZE;
+    comp shift = 1;
+    int i;
+
+    check(biexp);
+
+    for (i = 0; i < num_shifts; i++)
+    {
+        shift <<= 1;
+    }
+
+    return test & shift;
+}
+
+/*
+ * Delete any leading 0's (and allow for 0).
+ */
+static bigint *trim(bigint *bi)
+{
+    check(bi);
+
+    while (bi->comps[bi->size-1] == 0 && bi->size > 1)
+    {
+        bi->size--;
+    }
+
+    return bi;
+}
+
+/**
+ * @brief Perform a modular exponentiation.
+ *
+ * This function requires bi_set_mod() to have been called previously. This is 
+ * one of the optimisations used for performance.
+ * @param ctx [in]  The bigint session context.
+ * @param bi  [in]  The bigint on which to perform the mod power operation.
+ * @param biexp [in] The bigint exponent.
+ * @see bi_set_mod().
+ */
+bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp)
+{
+    int i = find_max_exp_index(biexp), j, window_size = 1;
+    bigint *biR = int_to_bi(ctx, 1);
+
+	check(bi);
+	check(biexp);
+
+    ctx->g = (bigint **)malloc(sizeof(bigint *));
+    ctx->g[0] = bi_clone(ctx, bi);
+    ctx->window = 1;
+	bi_permanent(ctx->g[0]);
+
+	/* if sliding-window is off, then only one bit will be done at a time and
+     * will reduce to standard left-to-right exponentiation */
+    do
+    {
+		if (exp_bit_is_one(biexp, i))
+        {
+            int l = i-window_size+1;
+            int part_exp = 0;
+
+			if (l < 0)  /* LSB of exponent will always be 1 */
+            {
+				l = 0;
+            }
+            else
+            {
+				while (exp_bit_is_one(biexp, l) == 0)
+                {
+					l++;    /* go back up */
+                }
+            }
+
+            /* build up the section of the exponent */
+            for (j = i; j >= l; j--)
+            {
+				biR = bi_residue(ctx, bi_square(ctx, biR));
+                if (exp_bit_is_one(biexp, j))
+                    part_exp++;
+
+                if (j != l)
+                    part_exp <<= 1;
+            }
+
+            part_exp = (part_exp-1)/2;  /* adjust for array */
+            biR = bi_residue(ctx, 
+                    bi_multiply(ctx, biR, ctx->g[part_exp]));
+			i = l-1;
+        }
+        else    /* square it */
+        {
+			biR = bi_residue(ctx, bi_square(ctx, biR));
+			i--;
+        }
+	} while (i >= 0);
+     
+    /* cleanup */
+	for (i = 0; i < ctx->window; i++)
+    {
+		bi_depermanent(ctx->g[i]);
+        bi_free(ctx, ctx->g[i]);
+    }
+
+    free(ctx->g);
+	bi_free(ctx, bi);
+	bi_free(ctx, biexp);
+	return biR;
+}
+
+/** @} */
--- /dev/null
+++ b/net/rsa/bigint.h
@@ -0,0 +1,73 @@
+/*
+ *  Copyright(C) 2006
+ *
+ *  This library is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Lesser General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This library 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public License
+ *  along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Trimmed down from axTLS
+ * 
+ * $Id: bigint.h 392 2007-06-25 16:24:51Z pablo.martin $
+ *
+ */
+
+#ifndef BIGINT_HEADER
+#define BIGINT_HEADER
+
+#define CONFIG_BIGINT_CLASSICAL 1
+
+#define SOCKET_READ(A,B,C)      read(A,B,C)
+#define SOCKET_WRITE(A,B,C)     write(A,B,C)
+#define SOCKET_CLOSE(A)         close(A)
+#define TTY_FLUSH()
+
+#include "bigint_impl.h"
+
+#ifndef CONFIG_BIGINT_CHECK_ON
+#define check(A)                /**< disappears in normal production mode */
+#endif
+BI_CTX *bi_initialize(void);
+void bi_terminate(BI_CTX *ctx);
+void bi_permanent(bigint *bi);
+void bi_depermanent(bigint *bi);
+void bi_free(BI_CTX *ctx, bigint *bi);
+bigint *bi_copy(bigint *bi);
+bigint *bi_clone(BI_CTX *ctx, const bigint *bi);
+void bi_export(BI_CTX *ctx, bigint *bi, uint8_t *data, int size);
+bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int len);
+bigint *int_to_bi(BI_CTX *ctx, comp i);
+
+/* the functions that actually do something interesting */
+bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib);
+bigint *bi_subtract(BI_CTX *ctx, bigint *bia, 
+        bigint *bib, int *is_negative);
+bigint *bi_divide(BI_CTX *ctx, bigint *bia, bigint *bim, int is_mod);
+bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib);
+bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp);
+bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp);
+int bi_compare(bigint *bia, bigint *bib);
+void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset);
+void bi_free_mod(BI_CTX *ctx, int mod_offset);
+
+/**
+ * @def bi_mod
+ * Find the residue of B. bi_set_mod() must be called before hand.
+ */
+#define bi_mod(A, B)      bi_divide(A, B, ctx->bi_mod[ctx->mod_offset], 1)
+
+#define bi_residue(A, B)         bi_mod(A, B)
+
+#define bi_square(A, B)     bi_multiply(A, bi_copy(B), B)
+
+#endif
+
--- /dev/null
+++ b/net/rsa/bigint_impl.h
@@ -0,0 +1,109 @@
+/*
+ *  Copyright(C) 2006
+ *
+ *  This library is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU Lesser General Public License as published by
+ *  the Free Software Foundation; either version 2.1 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This library 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 Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public License
+ *  along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef BIGINT_IMPL_HEADER
+#define BIGINT_IMPL_HEADER
+
+#include <linux/types.h>
+#include <common.h>
+
+/* Maintain a number of precomputed variables when doing reduction */
+#define BIGINT_M_OFFSET     0    /**< Normal modulo offset. */
+#ifdef CONFIG_BIGINT_CRT
+#define BIGINT_P_OFFSET     1    /**< p modulo offset. */
+#define BIGINT_Q_OFFSET     2    /**< q module offset. */
+#define BIGINT_NUM_MODS     3    /**< The number of modulus constants used. */
+#else
+#define BIGINT_NUM_MODS     1    
+#endif
+
+/* Architecture specific functions for big ints */
+// #ifdef WIN32
+// #define COMP_RADIX          4294967296i64         
+// #define COMP_BIG_MSB        0x8000000000000000i64 
+// #else
+#define COMP_RADIX          4294967296ULL         /**< Max component + 1 */
+#define COMP_BIG_MSB        0x8000000000000000ULL /**< (Max dbl comp + 1)/ 2 */
+//#endif
+#define COMP_BIT_SIZE       32  /**< Number of bits in a component. */
+#define COMP_BYTE_SIZE      4   /**< Number of bytes in a component. */
+#define COMP_NUM_NIBBLES    8   /**< Used For diagnostics only. */
+
+typedef uint32_t comp;	        /**< A single precision component. */
+typedef uint64_t long_comp;     /**< A double precision component. */
+typedef int64_t slong_comp;     /**< A signed double precision component. */
+
+/**
+ * @struct  _bigint
+ * @brief A big integer basic object
+ */
+struct _bigint
+{
+    struct _bigint* next;       /**< The next bigint in the cache. */
+    short size;                 /**< The number of components in this bigint. */
+    short max_comps;            /**< The heapsize allocated for this bigint */
+    int refs;                   /**< An internal reference count. */
+    comp* comps;                /**< A ptr to the actual component data */
+};
+
+typedef struct _bigint bigint;  /**< An alias for _bigint */
+
+/**
+ * Maintains the state of the cache, and a number of variables used in 
+ * reduction.
+ */
+typedef struct /**< A big integer "session" context. */
+{
+    bigint *active_list;                    /**< Bigints currently used. */
+    bigint *free_list;                      /**< Bigints not used. */
+    bigint *bi_radix;                       /**< The radix used. */
+    bigint *bi_mod[BIGINT_NUM_MODS];        /**< modulus */
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+    bigint *bi_RR_mod_m[BIGINT_NUM_MODS];   /**< R^2 mod m */
+    bigint *bi_R_mod_m[BIGINT_NUM_MODS];    /**< R mod m */
+    comp N0_dash[BIGINT_NUM_MODS];
+#elif defined(CONFIG_BIGINT_BARRETT)
+    bigint *bi_mu[BIGINT_NUM_MODS];         /**< Storage for mu */
+#endif
+    bigint *bi_normalised_mod[BIGINT_NUM_MODS]; /**< Normalised mod storage. */
+    bigint **g;                 /**< Used by sliding-window. */
+    int window;                 /**< The size of the sliding window */
+
+    int active_count;           /**< Number of active bigints. */
+    int free_count;             /**< Number of free bigints. */
+
+#ifdef CONFIG_BIGINT_MONTGOMERY
+    uint8_t use_classical;      /**< Use classical reduction. */
+#endif
+    uint8_t mod_offset;         /**< The mod offset we are using */
+} BI_CTX;
+
+#if 0
+#define max(a,b) ((a)>(b)?(a):(b))  /**< Find the maximum of 2 numbers. */
+#define min(a,b) ((a)<(b)?(a):(b))  /**< Find the minimum of 2 numbers. */
+#endif
+
+#define PERMANENT           0x7FFF55AA  /**< A magic number for permanents. */
+
+#define V1      v->comps[v->size-1]                 /**< v1 for division */
+#define V2      v->comps[v->size-2]                 /**< v2 for division */
+#define U(j)    tmp_u->comps[tmp_u->size-j-1]       /**< uj for division */
+#define Q(j)    quotient->comps[quotient->size-j-1] /**< qj for division */
+
+#endif
--- /dev/null
+++ b/net/rsa/div64.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2000, 2004  Maciej W. Rozycki
+ * Copyright (C) 2003 Ralf Baechle
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#ifndef _ASM_DIV64_H
+#define _ASM_DIV64_H
+
+#if (_MIPS_SZLONG == 32)
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+#define GCC_REG_ACCUM "$0"
+#else
+#define GCC_REG_ACCUM "accum"
+#endif
+
+
+//#include <asm/compiler.h>
+
+/*
+ * No traps on overflows for any of these...
+ */
+
+#define do_div64_32(res, high, low, base) ({ \
+	unsigned long __quot, __mod; \
+	unsigned long __cf, __tmp, __tmp2, __i; \
+	\
+	__asm__(".set	push\n\t" \
+		".set	noat\n\t" \
+		".set	noreorder\n\t" \
+		"move	%2, $0\n\t" \
+		"move	%3, $0\n\t" \
+		"b	1f\n\t" \
+		" li	%4, 0x21\n" \
+		"0:\n\t" \
+		"sll	$1, %0, 0x1\n\t" \
+		"srl	%3, %0, 0x1f\n\t" \
+		"or	%0, $1, %5\n\t" \
+		"sll	%1, %1, 0x1\n\t" \
+		"sll	%2, %2, 0x1\n" \
+		"1:\n\t" \
+		"bnez	%3, 2f\n\t" \
+		" sltu	%5, %0, %z6\n\t" \
+		"bnez	%5, 3f\n" \
+		"2:\n\t" \
+		" addiu	%4, %4, -1\n\t" \
+		"subu	%0, %0, %z6\n\t" \
+		"addiu	%2, %2, 1\n" \
+		"3:\n\t" \
+		"bnez	%4, 0b\n\t" \
+		" srl	%5, %1, 0x1f\n\t" \
+		".set	pop" \
+		: "=&r" (__mod), "=&r" (__tmp), "=&r" (__quot), "=&r" (__cf), \
+		  "=&r" (__i), "=&r" (__tmp2) \
+		: "Jr" (base), "0" (high), "1" (low)); \
+	\
+	(res) = __quot; \
+	__mod; })
+
+#define do_div(n, base) ({ \
+	unsigned long long __quot; \
+	unsigned long __mod; \
+	unsigned long long __div; \
+	unsigned long __upper, __low, __high, __base; \
+	\
+	__div = (n); \
+	__base = (base); \
+	\
+	__high = __div >> 32; \
+	__low = __div; \
+	__upper = __high; \
+	\
+	if (__high) \
+		__asm__("divu	$0, %z2, %z3" \
+			: "=h" (__upper), "=l" (__high) \
+			: "Jr" (__high), "Jr" (__base) \
+			: GCC_REG_ACCUM); \
+	\
+	__mod = do_div64_32(__low, __upper, __low, __base); \
+	\
+	__quot = __high; \
+	__quot = __quot << 32 | __low; \
+	(n) = __quot; \
+	__mod; })
+#endif /* (_MIPS_SZLONG == 32) */
+
+#if (_MIPS_SZLONG == 64)
+
+/*
+ * Hey, we're already 64-bit, no
+ * need to play games..
+ */
+#define do_div(n, base) ({ \
+	unsigned long __quot; \
+	unsigned int __mod; \
+	unsigned long __div; \
+	unsigned int __base; \
+	\
+	__div = (n); \
+	__base = (base); \
+	\
+	__mod = __div % __base; \
+	__quot = __div / __base; \
+	\
+	(n) = __quot; \
+	__mod; })
+
+#endif /* (_MIPS_SZLONG == 64) */
+
+#endif /* _ASM_DIV64_H */
--- /dev/null
+++ b/net/rsa/dump_key.c
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+int main(int argc, char **argv)
+{
+	FILE *fp = fopen("public_fon_rsa_key_6.pem", "r");
+	struct stat s;
+	unsigned char *b;
+	int i;
+	if(!fp)
+		return 1;
+	stat("public_fon_rsa_key_6.pem", &s);
+	b = malloc(s.st_size);
+	fread(b, s.st_size, 1, fp);
+	fclose(fp);
+	printf("unsigned char public_key[] = {\n\t");
+	for(i = 0;i < s.st_size; i++)
+	{
+		printf("0x%02X,", b[i]);
+		if(i%16 == 15)
+			printf("\n\t");
+	}
+	printf("};\n");
+//	printf("\n%d %d\n", i, s.st_size);
+	return 0;
+}
--- /dev/null
+++ b/net/rsa/foncheckrsa.c
@@ -0,0 +1,79 @@
+/*
+ * RSA + RIPEMD160 signature verification command
+ *
+ * Copyright (C) 2007 FON Wireless Ltd.
+ *
+ * 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Created: 20060728 Pablo Martín Medrano <pablo@fon.com>
+ *
+ * $Id: foncheckrsa.c 332 2007-05-02 09:45:54Z pablo.martin $
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include "fonrsa.h"
+
+int main(int argc, char **argv)
+{
+	int fd, i;
+	FONRSA_ERROR fonrsa_error;
+	void *handle;
+
+	if (argc != 4) {
+		fprintf(stderr, " Usage: foncheckrsa [public_key.der] [signature] [file]\n");
+		fprintf(stderr, "  Pablo Martín Medrano <pablo@fon.com>\n");
+		fprintf(stderr, "  RIPEMD-160 software written by Antoon Bosselaers,\n");
+		fprintf(stderr, "  available at http://www.esat.kuleuven.be/~cosicart/ps/AB-9601/.\n");
+		fprintf(stderr, "  Uses the axTLS library bigint implementation (libfonrsa)\n");
+		fprintf(stderr, "  http://www.leroc.com.au/axTLS/\n");
+		return -1;
+	}
+	/* Check the existence of input files */
+	for (i = 1; i < 4; i++) {
+		if ((fd = open(argv[i], O_RDONLY)) == -1) {
+			fprintf(stderr, "Error: opening \"%s\": %s\n", argv[i],
+				strerror(errno));
+			fprintf(stderr, "Bailing out...");
+			exit(-2);
+		}
+		close(fd);
+	}
+	handle = FR_init(argv[1]);
+	if (handle == NULL) {
+		printf("Error loading keys in %s\n", argv[1]);
+		return 1;
+	}
+	fonrsa_error = FR_verify_file(handle, argv[3], argv[2]);
+	FR_end(handle);
+	switch (fonrsa_error) {
+		case FONRSA_OK:
+			printf("Verified OK\n");
+			return 0;
+		case FONRSA_VERIFICATION_FAILURE:
+			printf("Verification failure\n");
+			return 1;
+		default:
+			printf("Verification error\n");
+			return -1;
+	}
+	return -1;
+}
+
--- /dev/null
+++ b/net/rsa/fonrsa.c
@@ -0,0 +1,584 @@
+/*
+ * FONSM RSA handling library
+ *
+ * This file is part of FONUCS. Copyright (C) 2007 FON Wireless Ltd.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Created: 20070306 Pablo Martin Medrano <pablo@fon.com>
+ *
+ * Based on axTLS
+ *
+ * $Id: fonrsa.c 405 2007-09-19 15:26:17Z jesus.pico $
+ */
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include "rmd160.h"
+#include "bigint.h"
+#include "fonrsa.h"
+#include "base64.h"
+
+typedef struct {
+	uint8_t *buffer;
+	size_t size;
+} DER_key;
+
+typedef struct {
+	bigint *m;              /* modulus */
+	bigint *e;              /* public exponent */
+	int num_octets;
+	BI_CTX *bi_ctx;         /* big integer handle */
+} RSA_parameters;
+
+typedef struct {
+	DER_key *derkey;
+	RSA_parameters *rsaparms;
+} RSA;
+
+static uint8_t *CH_load_raw_file(char *filename, size_t *size);
+static DER_key *CH_load_der_key(char *filename);
+static void CH_free_der_key(DER_key *key);
+static int asn1_get_public_key(const uint8_t *buf, int len, RSA_parameters **rsa_parameters);
+void CH_pub_key_new(RSA_parameters **rsa_parameters, const uint8_t *modulus, int mod_len, const uint8_t *pub_exp, int pub_len);
+int CH_decrypt(RSA_parameters *rsa, uint8_t *buffer_in, uint8_t *buffer_out);
+byte *RMDbinary(char *fname);
+int CH_get_rmd160_hash_from_signature(byte *hash, char *signature_file, char *public_key_file);
+static unsigned char *load_file_in_buffer(char *path, int *size);
+static int save_file_from_buffer(char *path, unsigned char *buffer, int size);
+int ExtractPadding(uint8_t* OutputBuffer, uint8_t* InputBuffer, int LengthOfInputBuffer);
+
+#define RMDsize 160		/* A RIPEMD-160 hash has 160 bits */
+
+/*
+ * returns RMD(message in file fname) fname is read as binary data.
+ * non-reentrant
+ */
+byte *RMDbinary(char *fname)
+{
+	FILE *mf;		/* pointer to file <fname>      */
+	byte data[1024];	/* contains current mess. block */
+	dword nbytes;		/* length of this block         */
+	dword MDbuf[RMDsize / 32];	/* contains (A, B, C, D(, E))   */
+	static byte hashcode[RMDsize / 8];	/* for final hash-value         */
+	dword X[16];		/* current 16-word chunk        */
+	unsigned int i, j;	/* counters                     */
+	dword length[2];	/* length in bytes of message   */
+	dword offset;		/* # of unprocessed bytes at    */
+	/*          call of MDfinish    */
+
+	/* initialize */
+	if ((mf = fopen(fname, "rb")) == NULL) {
+		fprintf(stderr, "\nRMDbinary: cannot open file \"%s\".\n",
+			fname);
+		exit(1);
+	}
+	MDinit(MDbuf);
+	length[0] = 0;
+	length[1] = 0;
+	while ((nbytes = fread(data, 1, 1024, mf)) != 0) {
+		/* process all complete blocks */
+		for (i = 0; i < (nbytes >> 6); i++) {
+			for (j = 0; j < 16; j++)
+				X[j] = BYTES_TO_DWORD(data + 64 * i + 4 * j);
+			compress(MDbuf, X);
+		}
+		/* update length[] */
+		if (length[0] + nbytes < length[0])
+			length[1]++;	/* overflow to msb of length */
+		length[0] += nbytes;
+	}
+	/* finish: */
+	offset = length[0] & 0x3C0;	/* extract bytes 6 to 10 inclusive */
+	MDfinish(MDbuf, data + offset, length[0], length[1]);
+
+	for (i = 0; i < RMDsize / 8; i += 4) {
+		hashcode[i] = MDbuf[i >> 2];
+		hashcode[i + 1] = (MDbuf[i >> 2] >> 8);
+		hashcode[i + 2] = (MDbuf[i >> 2] >> 16);
+		hashcode[i + 3] = (MDbuf[i >> 2] >> 24);
+	}
+	fclose(mf);
+
+	return (byte *) hashcode;
+}
+byte *RMDbinary_buffer(char *buffer, int size_buffer)
+{
+	return NULL;
+}
+
+/*
+ * Extracts the RMD 160 hash from the signature file
+ */
+int CH_get_rmd160_hash_from_signature(byte *hash, char *signature_file, char *public_key_file)
+{
+	RSA_parameters *rsa_parameters;
+	DER_key *derkey;
+	uint8_t *signature;
+	size_t signature_size;
+	uint8_t *decrypted;
+
+	signature = CH_load_raw_file(signature_file, &signature_size);
+	if ((signature == NULL)||(signature_size != 512)) {
+		fprintf(stderr, "Error: Loading signature key '%s'\n", signature_file);
+		exit(-1);
+	}
+	derkey = CH_load_der_key(public_key_file);
+	if (derkey == NULL) {
+		fprintf(stderr, "Error: opening DER key file '%s'\n", public_key_file);
+		exit(-1);
+	}
+	if ((asn1_get_public_key(derkey->buffer, derkey->size, &rsa_parameters)) != 0) {
+		fprintf(stderr, "Error: Extracting public key from DER file\n");
+		exit(-1);
+	}
+	CH_free_der_key(derkey);
+	if (rsa_parameters->num_octets != 512)
+		fprintf(stderr, "Error: The RSA public key size is not 4096 bits %d\n", rsa_parameters->num_octets);
+	decrypted = (uint8_t *)malloc(rsa_parameters->num_octets);
+	if (CH_decrypt(rsa_parameters, signature, decrypted)) {
+		fprintf(stderr, "Error: Decrypting signature\n");
+		exit(-1);
+	}
+	memcpy(hash, decrypted + 492, 20);		
+	free(decrypted);
+	free(signature);
+	return 0;
+}
+
+/*
+ * Decrypts the signature buffer using the rsa public key loaded
+ */
+int CH_decrypt(RSA_parameters *rsa, uint8_t *buffer_in, uint8_t *buffer_out)
+{
+	bigint *dat_bi;
+	bigint *decrypted_bi;
+	int byte_size;
+
+	byte_size = rsa->num_octets; 
+	dat_bi = bi_import(rsa->bi_ctx, buffer_in, byte_size);
+	rsa->bi_ctx->mod_offset = BIGINT_M_OFFSET;
+	bi_copy(rsa->m);
+	decrypted_bi = bi_mod_power(rsa->bi_ctx, dat_bi, rsa->e);
+	bi_export(rsa->bi_ctx, decrypted_bi, buffer_out, byte_size);
+	return 0;
+}
+/*
+ * Loads a file in a uint8_t buffer
+ */
+static uint8_t *CH_load_raw_file(char *filename, size_t *size)
+{
+	struct stat st;
+	int fd;
+	ssize_t br;
+	uint8_t *ret;
+
+	if ((stat(filename, &st)) == -1)
+		return NULL;
+	if ((ret = (uint8_t *)malloc(st.st_size)) == NULL)
+		return NULL;
+	fd = open(filename, O_RDONLY);
+	if (fd == -1) {
+		free(ret);
+		return NULL;
+	}
+	br = read(fd, ret, st.st_size);
+	close(fd);
+	if (br != st.st_size) {
+		free(ret);
+		return NULL;
+	}
+	*size = st.st_size;
+	return ret;
+}
+/*
+ * Loads a .der file in a buffer
+ */
+static DER_key *CH_load_der_key(char *filename)
+{
+	DER_key *ret;
+
+	if ((ret = (DER_key *)malloc(sizeof(DER_key))) == NULL)
+		return NULL;
+	if ((ret->buffer = CH_load_raw_file(filename, &(ret->size))) == NULL) {
+		free(ret);
+		return NULL;
+	}
+	return ret;
+}
+/*
+ * CH_load_pem_key
+ */
+static DER_key *CH_load_pem_key(char *filename)
+{
+	DER_key *ret;
+	uint8_t *buffer;
+	char *b64,*p,*t;
+	char key[1024];
+	size_t filesize;
+	int size;
+
+	if ((ret = (DER_key *)malloc(sizeof(DER_key))) == NULL)
+		return NULL;
+	if ((buffer = CH_load_raw_file(filename, &filesize)) == NULL) {
+		free(ret);
+		return NULL;
+	}
+	p = (char *)buffer;
+	while ((*p != '\n') && (*p != '\0'))
+		p++;
+	if (*p == '\0') {
+		free(ret);
+		return NULL;
+	}
+	p++;
+	b64 = t = p;
+	while((p - b64) <= filesize) {
+		if ((*p == '-')) {
+			break;
+		} else if ((*p != '\n') && (*p != ' ') && (*p != '\t')) {
+			*t = *p;
+			t++;
+		}
+		p++;
+	}
+	*t = '\0';
+	size = B64_decode(b64, key, strlen(b64), 1024);
+	if (size < 0) {
+		free(buffer);
+		free(ret);
+		return NULL;
+	}
+	free(buffer);
+	ret->buffer = (char *)malloc(size);
+	ret->size = size;
+	memcpy((void *)ret->buffer, (void *)key, size);
+	return ret;
+}
+
+/*
+ * CH_free_der_key
+ */
+static void CH_free_der_key(DER_key *key)
+{
+	free(key->buffer);
+	free(key);
+}
+
+/*
+ * Get the public key specifics from an ASN.1 encoded file
+ * A function lacking in the exported axTLS API
+ *
+ * This is a really weird hack that only works with RSA public key
+ * files
+ */
+static int asn1_get_public_key(const uint8_t *buf, int len, RSA_parameters **rsa_parameters)
+{
+	uint8_t *modulus, *pub_exp;
+	int mod_len, pub_len;
+
+	pub_len = 3;
+	mod_len = len - 37;
+	if (buf[0] != 0x30) {
+		return -1;
+	}
+
+	pub_exp = (uint8_t *)malloc(3);
+	modulus = (uint8_t *)malloc(mod_len);
+	memcpy(modulus, buf + 32 , mod_len);
+	memcpy(pub_exp, buf + 34 + mod_len, 3); 
+	if (mod_len <= 0 || pub_len <= 0 )
+		return -1;
+	CH_pub_key_new(rsa_parameters, modulus, mod_len, pub_exp, pub_len);
+
+	free(modulus);
+	free(pub_exp);
+	return 0;
+}
+
+/*
+ * Similar to RSA_pub_key_new, rewritten to make this program depend only on bi module
+ */
+void CH_pub_key_new(RSA_parameters **rsa, const uint8_t *modulus, int mod_len, const uint8_t *pub_exp, int pub_len)
+{
+	RSA_parameters *rsa_parameters;
+
+	BI_CTX *bi_ctx = bi_initialize();
+	*rsa = (RSA_parameters *)calloc(1, sizeof(RSA_parameters));
+	rsa_parameters = *rsa;
+	rsa_parameters->bi_ctx = bi_ctx;
+	rsa_parameters->num_octets = (mod_len & 0xFFF0);
+	rsa_parameters->m = bi_import(bi_ctx, modulus, mod_len);
+	bi_set_mod(bi_ctx, rsa_parameters->m, BIGINT_M_OFFSET);
+	rsa_parameters->e = bi_import(bi_ctx, pub_exp, pub_len);
+	bi_permanent(rsa_parameters->e);
+}
+
+static unsigned char *load_file_in_buffer(char *path, int *size)
+{
+	unsigned char *buffer;
+	struct stat st;
+	int fd;
+
+	if (stat(path, &st))
+		return NULL;
+	buffer = (unsigned char *)malloc(st.st_size);
+	if (buffer == NULL)
+		return NULL;
+ 	if ((fd = open(path, O_RDONLY)) == -1) {
+		free(buffer);
+		return NULL;
+	}
+	if (read(fd, (void *)buffer,st.st_size) != (ssize_t)st.st_size) {
+		free(buffer);
+		close(fd);
+		return NULL;
+	}
+	*size = (int)st.st_size;
+	close(fd);
+	return buffer;
+}
+
+static int save_file_from_buffer(char *path, unsigned char *buffer, int size)
+{
+	int fd;
+
+	if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) == -1)
+		return -1;
+	if (write(fd, buffer, (size_t)size) != ((ssize_t)size)) {
+		close(fd);
+		return -1;
+	}
+	close(fd);
+	return 0;
+}
+
+/* FR_init */
+void *FR_init(char *public_key_path)
+{
+	DER_key *derkey;
+	RSA_parameters *rsa_parameters;
+	char *ending;
+
+	ending = public_key_path + strlen(public_key_path) - 3;
+	if (!strcmp(ending, "der"))
+		derkey = CH_load_der_key(public_key_path);	
+	else if (!strcmp(ending, "pem"))
+		derkey = CH_load_pem_key(public_key_path);
+	else {
+		fprintf(stderr, "Error: unknown key format\n");
+		exit(-1);
+	}
+	if (derkey == NULL) {
+		fprintf(stderr, "Error: opening key file '%s'\n", public_key_path);
+		exit(-1);
+	}
+	if ((asn1_get_public_key(derkey->buffer, derkey->size, &rsa_parameters)) != 0) {
+		fprintf(stderr, "Error: Extracting public key from file\n");
+		exit(-1);
+	}
+	CH_free_der_key(derkey);
+	return (void *)rsa_parameters;
+}
+
+/* FR_end */
+FONRSA_ERROR FR_end(void *handle)
+{
+	RSA_parameters *rsa_parameters = (RSA_parameters *)handle;
+
+	free(rsa_parameters);
+	return FONRSA_OK;
+}
+
+/* FR_decrypt_buffer */
+FONRSA_ERROR FR_decrypt_buffer(void *handler, unsigned char *cryptext, int cryptext_size,
+	unsigned char *plaintext, int plaintext_buffer_size, int *plaintext_size)
+{
+	RSA_parameters *rsaparms = (RSA_parameters *)handler;
+
+	if (cryptext_size != rsaparms->num_octets) {
+		return FONRSA_SIZE;
+	}
+	if (plaintext_buffer_size < cryptext_size) {
+		return FONRSA_SIZE;
+	}
+	if (CH_decrypt(rsaparms, (uint8_t *)cryptext, (uint8_t *)plaintext)) {
+		return FONRSA_DECRYPT;
+	}
+	*plaintext_size = cryptext_size;
+	return FONRSA_OK;
+}
+
+FONRSA_ERROR FR_decrypt_buffer_v2(void *handler, unsigned char *cryptext, int cryptext_size,
+	unsigned char *plaintext, int plaintext_buffer_size, int *plaintext_size)
+{
+	unsigned char* AuxBuffer;
+	int AuxSize;
+
+	AuxBuffer = (unsigned char*)malloc(cryptext_size);
+
+	RSA_parameters *rsaparms = (RSA_parameters *)handler;
+
+        if (cryptext_size != rsaparms->num_octets) {
+                return FONRSA_SIZE;
+        }
+        if (plaintext_buffer_size < cryptext_size) {
+                return FONRSA_SIZE;
+        }
+        if (CH_decrypt(rsaparms, (uint8_t *)cryptext, (uint8_t *)AuxBuffer)) {
+                return FONRSA_DECRYPT;
+        }
+	if ((AuxSize = ExtractPadding((uint8_t*)plaintext, (uint8_t*)AuxBuffer, cryptext_size)) < 0)
+	{
+		printf("Incorrect Padding decrypting buffer");
+		return FONRSA_DECRYPT;
+	}
+        *plaintext_size = AuxSize;
+        return FONRSA_OK;
+}
+
+/*
+ *
+ * Implementation of  PKCS 1.5 padding, borrowed from
+ * Tom's code (public domain)
+ */
+
+/* Standalone FR_verify_file */
+FONRSA_ERROR FR_verify_file(void *handler, char *file_path, char *signature_file_path)
+{
+	int j;
+	byte *hashcode;
+	byte hash[20];
+	uint8_t *decrypted;
+	RSA_parameters *rsa_parameters = (RSA_parameters *)handler;
+	char *signature_buffer;
+	int signature_size;
+
+	/* Calculates the RIPEMD-160 hash of the file */
+	hashcode = RMDbinary (file_path);
+	/* Decrypts the signature file using the RSA public key */
+	signature_buffer = load_file_in_buffer(signature_file_path, &signature_size);
+	if (signature_buffer == NULL)
+		return FONRSA_OPENKEY;
+
+	if (rsa_parameters->num_octets != signature_size)
+		return FONRSA_SIZE;
+	decrypted = (uint8_t *)malloc(rsa_parameters->num_octets);
+	if (CH_decrypt(rsa_parameters, signature_buffer, decrypted)) {
+		fprintf(stderr, "Error: Decrypting signature\n");
+		exit(-1);
+	}
+	memcpy(hash, decrypted + 492, 20);
+	free(decrypted);
+	free(signature_buffer);
+	for (j = 0; j < RMDsize/8; j++) {
+		if (hash[j] != hashcode[j])
+			return FONRSA_VERIFICATION_FAILURE;
+	}
+	return FONRSA_OK;
+}
+
+/* FR_decrypt_file */
+FONRSA_ERROR FR_decrypt_file(void *handle, char *crypted_file_path, char *plaintext_file_path)
+{
+	int size;
+	FONRSA_ERROR ret;
+	char *filebuffer;
+	char crypted[1024];
+	int crypted_size;
+
+	if ((filebuffer = load_file_in_buffer(crypted_file_path, &size)) == NULL) {
+		return FONRSA_LOADFILE;
+	}
+
+	ret = FR_decrypt_buffer(handle, filebuffer, size, crypted, 1024, &crypted_size);
+	if (ret != FONRSA_OK) {
+		free(filebuffer);
+		return ret;
+	}
+	free(filebuffer);
+
+	if (save_file_from_buffer(plaintext_file_path, crypted, crypted_size)) {
+		printf("Error writing %lu bytes into %s", crypted_size, plaintext_file_path);
+		return FONRSA_SAVEFILE;
+	}
+	return FONRSA_OK;
+}
+
+int ExtractPadding(uint8_t* OutputBuffer, uint8_t* InputBuffer, int LengthOfInputBuffer)
+{
+	int i;
+
+	//First typical checks...
+	if (LengthOfInputBuffer < MINIMUM_PADING_BYTES_PKCS_1_5)
+	{
+		fprintf(stderr, "Error:ExtractPadding: Error, Length of input buffer is too short.\n");
+		return -1;
+	}
+	else if((InputBuffer[0] != 0) || (InputBuffer[1] > 2)) //Necessary header of Padding...
+	{
+		fprintf(stderr, "Error:ExtractPadding: Error, Padding header is incorrect.\n");
+		return -1;
+	}
+	for (i=2; i < LengthOfInputBuffer; i++) //Variable size of non-zero padding....
+	{
+		if (InputBuffer[i] == 0) break; //This is the end of Padding.
+	}
+	//We need to evaluate if there is an existing message...
+	if (i < LengthOfInputBuffer - 2)
+	{//Ok, Padding is extracted... copying the message and finishing...
+		memcpy(OutputBuffer, &(InputBuffer[i + 1]), LengthOfInputBuffer - (i + 1));
+		return LengthOfInputBuffer - (i + 1);
+	}
+	//If we have reached to this point, then an error has occurred...
+	return -1;	
+}
+
+#ifdef __MAINTEST__
+int main(int argc, char **argv)
+{
+	void *handle = NULL;
+	FONRSA_ERROR ret;
+	char *filebuffer = NULL;
+	char crypted[1024];
+	int size, crypted_size;
+
+	if (argc != 4) {
+		printf("Usage: %s <key_file> <crypted_file> <output_file>\n", argv[0]);
+		return 1;
+	}
+
+	handle = FR_init(argv[1]);
+	if (handle == NULL) {
+		printf("Error loading keys\n");
+		return 1;
+	}
+	ret = FR_decrypt_file(handle, argv[2], argv[3]);
+	if (ret != FONRSA_OK) {
+		printf("FR_decrypt_file returns %d\n", ret);
+	}
+	FR_end(handle);
+	return (int)ret;
+}
+
+#endif
+
+
--- /dev/null
+++ b/net/rsa/fonrsa.h
@@ -0,0 +1,53 @@
+/*
+ * FONSM RSA handling library, used by fonsmcd and foncheckrsa
+ *
+ * This file is part of FONUCS. Copyright (C) 2007 FON Wireless Ltd.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Created: 20070306 Pablo Martin Medrano <pablo@fon.com>
+ *
+ * $Id: fonrsa.h 404 2007-09-17 10:41:31Z jesus.pico $
+ */
+#ifndef _FONRSA_H
+#define _FONRSA_H
+
+#define MINIMUM_PADING_BYTES_PKCS_1_5 3
+
+typedef enum {
+	FONRSA_OK = 0,
+	FONRSA_VERIFICATION_FAILURE = 1,
+	FONRSA_OPENKEY = 2,
+	FONRSA_SIZE = 3,
+	FONRSA_LOADFILE = 4,
+	FONRSA_CRYPT = 5,
+	FONRSA_DECRYPT = 6,
+	FONRSA_SAVEFILE = 7,
+	FONRSA_NOSYS = 8,
+	FONRSA_VERIFY = 9
+} FONRSA_ERROR;
+
+void *FR_init(char *public_key_path);
+FONRSA_ERROR FR_end(void *handle);
+FONRSA_ERROR FR_decrypt_buffer(void *handler, unsigned char *cryptext, int cryptext_size,
+	unsigned char *plaintext, int plaintext_buffer_size, int *plaintext_size);
+FONRSA_ERROR FR_decrypt_buffer_v2(void *handler, unsigned char *cryptext, int cryptext_size,
+	unsigned char *plaintext, int plaintext_buffer_size, int *plaintext_size);
+FONRSA_ERROR FR_verify_file(void *handler, char *file_path, char *signature_file_path);
+FONRSA_ERROR FR_decrypt_file(void *handler, char *crypted_file_path, char *plaintext_file_path);
+
+#endif
+
+
--- /dev/null
+++ b/net/rsa/log.c
@@ -0,0 +1,138 @@
+/*
+ * Fonsm log module. Used inside the fonsm backend module and on the client.
+ *
+ * This file is part of FONUCS. Copyright (C) 2007 FON Wireless Ltd.
+ *
+ * Created: 20070202 Pablo Martin Medrano <pablo@fon.com>
+ *
+ * $Id: log.c 392 2007-06-25 16:24:51Z pablo.martin $
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#ifndef WIN32
+#include <syslog.h>
+#endif
+#include "log.h"
+
+#define MAX_SESSION_PREFIX 256
+
+typedef struct {
+	char domain[256];
+	LG_LEVEL watermark;
+	int mode;
+	LG_log_function_pointer function;
+} ST_fslog;
+
+static ST_fslog fslog;
+static void LG_log_string(LG_LEVEL level, const char *message);
+
+/*! 
+ \brief Starts the log subsystem, redirecting glog() to stderr/syslog depending
+ on mode
+ \retval FSLOG_ERROR : FSLOG_OK if everything goes well
+ \param lg : handle that will be returned
+ \param ident : program identifier, any string 
+ \param low_watermark : if the log level is less than this value, it will not be logged
+ \param mode : FSLOG_MODE_SYSLOG (log to syslog) or FSLOG_MODE_STDERR (log to stderr)
+*/
+FSLOG_ERROR LG_start(const char *domain, LG_LEVEL watermark, int mode,
+	LG_log_function_pointer log_function, int facility)
+{
+#ifndef WIN32
+	strncpy(fslog.domain, domain, MAX_LG_DOMAIN);
+	fslog.domain[MAX_LG_DOMAIN - 1] = '\0';
+	fslog.watermark = watermark;
+	fslog.mode = mode;
+	fslog.function = log_function?log_function:LG_log_string;
+	if (fslog.mode & LG_SYSLOG)
+		openlog(domain, LOG_NDELAY, facility);
+	return FSLOG_OK;
+#else
+	return FSLOG_OK;
+#endif
+}
+
+/*! 
+ \brief Set the low watermark
+ \retval FSLOG_ERROR : FSLOG_OK
+ \param lg : log handle
+ \param low_watermark : new watermark 
+*/
+FSLOG_ERROR LG_set_loglevel(LG_LEVEL watermark)
+{
+	fslog.watermark = watermark;
+	return FSLOG_OK;
+}
+
+/*! 
+ \brief  Ends the log subsystem, unregisteing glog handle
+ \retval FSLOG_ERROR : FSLOG_OK if everything goes well
+ \param handle : log handle to free
+*/
+FSLOG_ERROR LG_end(void)
+{
+#ifndef WIN32
+	if (fslog.mode & LG_SYSLOG)
+		closelog();
+#endif
+	return FSLOG_OK;
+}
+
+
+void LG_log(LG_LEVEL loglevel, const char *message, ...)
+{
+#ifndef WIN32
+	va_list ap;
+	char buffer[4096];
+	int n;
+
+	va_start(ap, message);
+	n = vsnprintf(buffer, MAX_LOG_STRING, message, ap);
+	va_end(ap);
+	if (n > -1 && n < MAX_LOG_STRING)
+		fslog.function(loglevel, buffer);
+	else
+		fon_critical("%s: Message too big to be logged", __FUNCTION__);
+#else
+	return;
+#endif
+}
+
+/* Default log function (when mode is LG_SYSLOG or LG_STDERR) */
+static void LG_log_string(LG_LEVEL level, const char *message) 
+{
+#ifndef WIN32
+        static struct {
+                int syslog_level;
+                char *log_string;
+        } fonlog_to_syslog[] = {
+                [LG_DEBUG] = {LOG_ERR, "DEBUG"},
+                [LG_MESSAGE] = {LOG_ERR, "MESSAGE"},
+                [LG_WARNING] = {LOG_ERR, "WARNING"},
+                [LG_CRITICAL] = {LOG_ERR, "CRITICAL"},
+                [LG_ERROR] = {LOG_ERR, "ERROR"}
+        };
+
+	if (level < fslog.watermark)
+		return;
+	if (fslog.mode & LG_SYSLOG) {
+		if (level == LG_MESSAGE) {
+			syslog(LOG_INFO, "%s", message);
+		} else {
+			syslog(fonlog_to_syslog[level].syslog_level, "%s: %s", fonlog_to_syslog[level].log_string, message);
+		}
+	}
+	if (fslog.mode & LG_STDERR) {
+		fprintf(stderr, "%s[%d]: %8.8s: %s\n", fslog.domain, 
+				getpid(), fonlog_to_syslog[level].log_string, 
+				message);
+	}
+#else
+	/* FIXE: todo */
+	return;
+#endif
+}
+
--- /dev/null
+++ b/net/rsa/log.h
@@ -0,0 +1,77 @@
+/*
+ * Fonsm log module. Used inside the fonsm backend module and on the client.
+ *
+ * This file is part of FONUCS. Copyright (C) 2007 FON Wireless Ltd.
+ *
+ * Created: 20070202 Pablo Martin Medrano <pablo@fon.com>
+ *
+ * $Id: log.h 379 2007-05-28 09:17:48Z pablo.martin $
+ */
+#ifndef _LOG_H
+#define _LOG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+
+typedef enum {
+        FSLOG_OK = 0,
+        FSLOG_UNKNOWN = -1
+} FSLOG_ERROR;
+
+
+typedef void * LG_HANDLE;
+
+typedef enum {
+        LG_DEBUG = 0,
+        LG_MESSAGE = 1,
+        LG_INFO = 2,
+        LG_WARNING = 3,
+        LG_CRITICAL = 4,
+        LG_ERROR = 5
+} LG_LEVEL;
+
+#define LG_SYSLOG 0x01
+#define LG_STDERR 0x02
+#define LG_CUSTOM 0x04
+
+#define MAX_LG_DOMAIN 256
+#define MAX_LOG_STRING 4096
+
+#ifndef NDEBUG
+#ifndef LOGPRINTF
+#define fon_debug(...) LG_log (LG_DEBUG, __VA_ARGS__)
+#else
+#define fon_debug(...) { printf("DEBUG: "); printf(__VA_ARGS__); printf("\n"); }
+#endif
+#else
+/* fon_debug evaluates to nothing when NDEBUG is defined */
+#define fon_debug(...)
+#endif
+#ifndef LOGPRINTF
+#define fon_message(...) LG_log (LG_MESSAGE, __VA_ARGS__)
+#define fon_warning(...) LG_log (LG_WARNING, __VA_ARGS__) 
+#define fon_critical(...) LG_log (LG_CRITICAL, __VA_ARGS__)
+#define fon_error(...) LG_log (LG_ERROR, __VA_ARGS__)
+#else
+#define fon_message(...) { printf("MESSAGE: "); printf(__VA_ARGS__); printf("\n"); }
+#define fon_warning(...)  { printf("WARNING: "); printf(__VA_ARGS__); printf("\n"); }
+#define fon_critical(...) { printf("CRITICAL: "); printf(__VA_ARGS__); printf("\n"); }
+#define fon_error(...) { printf("ERROR: "); printf(__VA_ARGS__); printf("\n"); }
+#endif
+
+typedef void (*LG_log_function_pointer)(LG_LEVEL level, const char *message);
+
+FSLOG_ERROR LG_start(const char *domain, LG_LEVEL watermark, int mode, LG_log_function_pointer log_function, int facility);
+FSLOG_ERROR LG_set_loglevel(LG_LEVEL watermark);
+FSLOG_ERROR LG_end(void);
+void LG_log(LG_LEVEL loglevel, const char *message, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
--- /dev/null
+++ b/net/rsa/Makefile
@@ -0,0 +1,31 @@
+#
+# FONRSA & FONSIGN libraries unit testing
+# 
+# This file is part of FONUCS. Copyright (C) 2007 FON Wireless Ltd.
+#
+# Execute in this directory
+#
+# Created: 20070422 Pablo Martin Medrano <pablo@fon.com>
+#
+# $Id: Makefile 389 2007-06-11 08:29:56Z pablo.martin $
+#
+# FIXME: Put this in the main Makefile.am
+# 
+all: fonsign dump_key
+
+fonsign:
+	gcc -g sign_openssl.c -D__MAINTEST__ -o fonsign -lssl
+
+dump_key:
+	gcc -o dump_key dump_key.c
+	./dump_key > public_key.h
+
+foncheckrsa:
+	gcc -g bigint.c  fonrsa.c  rmd160.c foncheckrsa.c base64.c log.c  -o foncheckrsa 
+
+#private_fon_rsa_key.pem:
+#	openssl genrsa -out private_fon_rsa_key.pem 4096
+#	openssl rsa -in private_fon_rsa_key.pem -pubout -out public_fon_rsa_key.pem
+
+clean:
+	rm fonsign dump_key 
--- /dev/null
+++ b/net/rsa/public_key.h
@@ -0,0 +1,52 @@
+unsigned char public_key[] = {
+	0x2D,0x2D,0x2D,0x2D,0x2D,0x42,0x45,0x47,0x49,0x4E,0x20,0x50,0x55,0x42,0x4C,0x49,
+	0x43,0x20,0x4B,0x45,0x59,0x2D,0x2D,0x2D,0x2D,0x2D,0x0A,0x4D,0x49,0x49,0x43,0x49,
+	0x6A,0x41,0x4E,0x42,0x67,0x6B,0x71,0x68,0x6B,0x69,0x47,0x39,0x77,0x30,0x42,0x41,
+	0x51,0x45,0x46,0x41,0x41,0x4F,0x43,0x41,0x67,0x38,0x41,0x4D,0x49,0x49,0x43,0x43,
+	0x67,0x4B,0x43,0x41,0x67,0x45,0x41,0x34,0x4C,0x42,0x76,0x59,0x43,0x4B,0x38,0x38,
+	0x6D,0x75,0x57,0x61,0x73,0x31,0x4F,0x53,0x73,0x71,0x30,0x0A,0x38,0x39,0x38,0x79,
+	0x76,0x54,0x4B,0x71,0x41,0x6E,0x4F,0x37,0x78,0x2F,0x44,0x53,0x57,0x72,0x46,0x53,
+	0x30,0x42,0x72,0x47,0x53,0x51,0x31,0x52,0x69,0x44,0x39,0x55,0x62,0x78,0x77,0x6F,
+	0x64,0x76,0x36,0x65,0x51,0x4B,0x55,0x30,0x67,0x36,0x52,0x6B,0x2F,0x39,0x54,0x70,
+	0x4C,0x6E,0x4F,0x2F,0x76,0x51,0x4B,0x70,0x69,0x41,0x30,0x30,0x0A,0x2B,0x32,0x59,
+	0x30,0x74,0x6B,0x4C,0x39,0x73,0x6A,0x37,0x64,0x33,0x57,0x4B,0x47,0x39,0x62,0x6A,
+	0x64,0x51,0x58,0x2F,0x43,0x49,0x35,0x57,0x46,0x42,0x42,0x64,0x77,0x57,0x73,0x74,
+	0x4D,0x43,0x38,0x77,0x74,0x4C,0x6A,0x6A,0x45,0x59,0x79,0x43,0x58,0x46,0x32,0x31,
+	0x30,0x39,0x7A,0x31,0x47,0x54,0x4C,0x73,0x53,0x44,0x34,0x57,0x4F,0x0A,0x45,0x50,
+	0x6D,0x45,0x37,0x34,0x63,0x6E,0x6F,0x35,0x78,0x53,0x43,0x71,0x71,0x33,0x74,0x54,
+	0x49,0x6D,0x38,0x50,0x78,0x49,0x77,0x54,0x46,0x6D,0x46,0x6F,0x6D,0x6A,0x76,0x31,
+	0x4F,0x56,0x50,0x32,0x73,0x42,0x49,0x70,0x35,0x4E,0x2B,0x59,0x6F,0x56,0x61,0x53,
+	0x58,0x6A,0x47,0x66,0x4E,0x63,0x54,0x36,0x4E,0x6B,0x39,0x76,0x6B,0x56,0x0A,0x57,
+	0x69,0x67,0x39,0x30,0x71,0x50,0x4E,0x4C,0x58,0x6E,0x39,0x39,0x50,0x78,0x48,0x61,
+	0x49,0x31,0x36,0x52,0x7A,0x78,0x48,0x4C,0x39,0x54,0x42,0x2B,0x50,0x43,0x33,0x68,
+	0x33,0x61,0x58,0x33,0x71,0x57,0x30,0x4B,0x4C,0x4A,0x41,0x66,0x6F,0x35,0x70,0x48,
+	0x6C,0x39,0x79,0x75,0x55,0x70,0x37,0x66,0x46,0x65,0x6A,0x4A,0x2B,0x41,0x58,0x0A,
+	0x51,0x4F,0x4A,0x62,0x53,0x45,0x67,0x56,0x74,0x76,0x72,0x68,0x44,0x39,0x73,0x55,
+	0x6D,0x4B,0x30,0x74,0x36,0x63,0x51,0x44,0x65,0x32,0x32,0x4E,0x4E,0x6E,0x77,0x37,
+	0x43,0x4F,0x4F,0x61,0x59,0x49,0x57,0x55,0x55,0x6A,0x79,0x6A,0x68,0x35,0x50,0x4B,
+	0x64,0x64,0x45,0x4B,0x5A,0x38,0x68,0x62,0x62,0x47,0x65,0x61,0x5A,0x4A,0x6F,0x76,
+	0x0A,0x63,0x6F,0x51,0x64,0x55,0x56,0x51,0x6D,0x71,0x44,0x53,0x2B,0x6B,0x63,0x2F,
+	0x41,0x51,0x6C,0x65,0x55,0x36,0x68,0x51,0x6A,0x63,0x55,0x4C,0x57,0x44,0x6B,0x4E,
+	0x2F,0x6F,0x4F,0x6C,0x33,0x43,0x53,0x65,0x70,0x67,0x54,0x37,0x6B,0x67,0x73,0x52,
+	0x63,0x63,0x47,0x74,0x66,0x4B,0x65,0x37,0x77,0x4D,0x70,0x35,0x66,0x59,0x4A,0x2B,
+	0x41,0x0A,0x43,0x46,0x44,0x41,0x6F,0x4C,0x6E,0x58,0x4E,0x6A,0x4E,0x56,0x6C,0x65,
+	0x73,0x43,0x6B,0x78,0x74,0x6A,0x62,0x4C,0x62,0x49,0x72,0x66,0x32,0x6E,0x43,0x62,
+	0x32,0x61,0x4D,0x65,0x64,0x31,0x5A,0x48,0x4E,0x4A,0x51,0x75,0x6F,0x4E,0x58,0x67,
+	0x72,0x43,0x41,0x44,0x31,0x71,0x2B,0x58,0x6E,0x66,0x77,0x63,0x69,0x6D,0x57,0x50,
+	0x64,0x51,0x0A,0x44,0x59,0x6A,0x6D,0x65,0x44,0x70,0x35,0x77,0x36,0x41,0x4A,0x33,
+	0x2F,0x35,0x59,0x39,0x55,0x74,0x78,0x47,0x34,0x72,0x51,0x72,0x61,0x68,0x78,0x53,
+	0x42,0x77,0x43,0x4B,0x57,0x39,0x4B,0x79,0x53,0x31,0x71,0x53,0x76,0x73,0x37,0x7A,
+	0x59,0x2F,0x52,0x59,0x37,0x4A,0x66,0x36,0x63,0x56,0x6B,0x54,0x43,0x78,0x69,0x33,
+	0x7A,0x32,0x53,0x0A,0x50,0x46,0x33,0x51,0x64,0x6B,0x30,0x50,0x44,0x2F,0x73,0x2B,
+	0x6B,0x77,0x39,0x71,0x4F,0x4E,0x79,0x69,0x33,0x67,0x6E,0x61,0x42,0x46,0x6E,0x54,
+	0x77,0x48,0x7A,0x59,0x69,0x77,0x34,0x2F,0x77,0x6A,0x46,0x33,0x64,0x47,0x68,0x47,
+	0x4E,0x6B,0x78,0x36,0x70,0x63,0x4E,0x4F,0x52,0x55,0x46,0x4E,0x65,0x4F,0x7A,0x59,
+	0x76,0x39,0x6F,0x6A,0x0A,0x51,0x59,0x70,0x73,0x55,0x31,0x33,0x6A,0x6D,0x30,0x33,
+	0x42,0x6F,0x45,0x2B,0x42,0x31,0x64,0x38,0x50,0x47,0x75,0x57,0x2B,0x49,0x7A,0x2F,
+	0x41,0x4F,0x44,0x7A,0x6B,0x6F,0x56,0x6B,0x39,0x2B,0x57,0x79,0x49,0x33,0x37,0x50,
+	0x30,0x53,0x7A,0x47,0x4B,0x72,0x2B,0x53,0x33,0x72,0x72,0x74,0x61,0x50,0x6C,0x41,
+	0x70,0x71,0x4B,0x48,0x55,0x0A,0x6E,0x64,0x35,0x6C,0x30,0x63,0x76,0x75,0x59,0x66,
+	0x31,0x4C,0x37,0x45,0x52,0x75,0x49,0x58,0x64,0x47,0x4C,0x6A,0x30,0x43,0x41,0x77,
+	0x45,0x41,0x41,0x51,0x3D,0x3D,0x0A,0x2D,0x2D,0x2D,0x2D,0x2D,0x45,0x4E,0x44,0x20,
+	0x50,0x55,0x42,0x4C,0x49,0x43,0x20,0x4B,0x45,0x59,0x2D,0x2D,0x2D,0x2D,0x2D,0x0A,
+	};
--- /dev/null
+++ b/net/rsa/rmd160.c
@@ -0,0 +1,292 @@
+/********************************************************************\
+ *
+ *      FILE:     rmd160.c
+ *
+ *      CONTENTS: A sample C-implementation of the RIPEMD-160
+ *                hash-function.
+ *      TARGET:   any computer with an ANSI C compiler
+ *
+ *      AUTHOR:   Antoon Bosselaers, ESAT-COSIC
+ *      DATE:     1 March 1996
+ *      VERSION:  1.0
+ *
+ *      Copyright (c) Katholieke Universiteit Leuven
+ *      1996, All Rights Reserved
+ *
+ *  Conditions for use of the RIPEMD-160 Software
+ *
+ *  The RIPEMD-160 software is freely available for use under the terms and
+ *  conditions described hereunder, which shall be deemed to be accepted by
+ *  any user of the software and applicable on any use of the software:
+ * 
+ *  1. K.U.Leuven Department of Electrical Engineering-ESAT/COSIC shall for
+ *     all purposes be considered the owner of the RIPEMD-160 software and of
+ *     all copyright, trade secret, patent or other intellectual property
+ *     rights therein.
+ *  2. The RIPEMD-160 software is provided on an "as is" basis without
+ *     warranty of any sort, express or implied. K.U.Leuven makes no
+ *     representation that the use of the software will not infringe any
+ *     patent or proprietary right of third parties. User will indemnify
+ *     K.U.Leuven and hold K.U.Leuven harmless from any claims or liabilities
+ *     which may arise as a result of its use of the software. In no
+ *     circumstances K.U.Leuven R&D will be held liable for any deficiency,
+ *     fault or other mishappening with regard to the use or performance of
+ *     the software.
+ *  3. User agrees to give due credit to K.U.Leuven in scientific publications 
+ *     or communications in relation with the use of the RIPEMD-160 software 
+ *     as follows: RIPEMD-160 software written by Antoon Bosselaers, 
+ *     available at http://www.esat.kuleuven.be/~cosicart/ps/AB-9601/.
+ *
+\********************************************************************/
+
+/*  header files */
+#include <common.h>
+#include "rmd160.h"      
+
+/********************************************************************/
+
+void MDinit(dword *MDbuf)
+{
+   MDbuf[0] = 0x67452301UL;
+   MDbuf[1] = 0xefcdab89UL;
+   MDbuf[2] = 0x98badcfeUL;
+   MDbuf[3] = 0x10325476UL;
+   MDbuf[4] = 0xc3d2e1f0UL;
+
+   return;
+}
+
+/********************************************************************/
+
+void compress(dword *MDbuf, dword *X)
+{
+   dword aa = MDbuf[0],  bb = MDbuf[1],  cc = MDbuf[2],
+         dd = MDbuf[3],  ee = MDbuf[4];
+   dword aaa = MDbuf[0], bbb = MDbuf[1], ccc = MDbuf[2],
+         ddd = MDbuf[3], eee = MDbuf[4];
+
+   /* round 1 */
+   FF(aa, bb, cc, dd, ee, X[ 0], 11);
+   FF(ee, aa, bb, cc, dd, X[ 1], 14);
+   FF(dd, ee, aa, bb, cc, X[ 2], 15);
+   FF(cc, dd, ee, aa, bb, X[ 3], 12);
+   FF(bb, cc, dd, ee, aa, X[ 4],  5);
+   FF(aa, bb, cc, dd, ee, X[ 5],  8);
+   FF(ee, aa, bb, cc, dd, X[ 6],  7);
+   FF(dd, ee, aa, bb, cc, X[ 7],  9);
+   FF(cc, dd, ee, aa, bb, X[ 8], 11);
+   FF(bb, cc, dd, ee, aa, X[ 9], 13);
+   FF(aa, bb, cc, dd, ee, X[10], 14);
+   FF(ee, aa, bb, cc, dd, X[11], 15);
+   FF(dd, ee, aa, bb, cc, X[12],  6);
+   FF(cc, dd, ee, aa, bb, X[13],  7);
+   FF(bb, cc, dd, ee, aa, X[14],  9);
+   FF(aa, bb, cc, dd, ee, X[15],  8);
+                             
+   /* round 2 */
+   GG(ee, aa, bb, cc, dd, X[ 7],  7);
+   GG(dd, ee, aa, bb, cc, X[ 4],  6);
+   GG(cc, dd, ee, aa, bb, X[13],  8);
+   GG(bb, cc, dd, ee, aa, X[ 1], 13);
+   GG(aa, bb, cc, dd, ee, X[10], 11);
+   GG(ee, aa, bb, cc, dd, X[ 6],  9);
+   GG(dd, ee, aa, bb, cc, X[15],  7);
+   GG(cc, dd, ee, aa, bb, X[ 3], 15);
+   GG(bb, cc, dd, ee, aa, X[12],  7);
+   GG(aa, bb, cc, dd, ee, X[ 0], 12);
+   GG(ee, aa, bb, cc, dd, X[ 9], 15);
+   GG(dd, ee, aa, bb, cc, X[ 5],  9);
+   GG(cc, dd, ee, aa, bb, X[ 2], 11);
+   GG(bb, cc, dd, ee, aa, X[14],  7);
+   GG(aa, bb, cc, dd, ee, X[11], 13);
+   GG(ee, aa, bb, cc, dd, X[ 8], 12);
+
+   /* round 3 */
+   HH(dd, ee, aa, bb, cc, X[ 3], 11);
+   HH(cc, dd, ee, aa, bb, X[10], 13);
+   HH(bb, cc, dd, ee, aa, X[14],  6);
+   HH(aa, bb, cc, dd, ee, X[ 4],  7);
+   HH(ee, aa, bb, cc, dd, X[ 9], 14);
+   HH(dd, ee, aa, bb, cc, X[15],  9);
+   HH(cc, dd, ee, aa, bb, X[ 8], 13);
+   HH(bb, cc, dd, ee, aa, X[ 1], 15);
+   HH(aa, bb, cc, dd, ee, X[ 2], 14);
+   HH(ee, aa, bb, cc, dd, X[ 7],  8);
+   HH(dd, ee, aa, bb, cc, X[ 0], 13);
+   HH(cc, dd, ee, aa, bb, X[ 6],  6);
+   HH(bb, cc, dd, ee, aa, X[13],  5);
+   HH(aa, bb, cc, dd, ee, X[11], 12);
+   HH(ee, aa, bb, cc, dd, X[ 5],  7);
+   HH(dd, ee, aa, bb, cc, X[12],  5);
+
+   /* round 4 */
+   II(cc, dd, ee, aa, bb, X[ 1], 11);
+   II(bb, cc, dd, ee, aa, X[ 9], 12);
+   II(aa, bb, cc, dd, ee, X[11], 14);
+   II(ee, aa, bb, cc, dd, X[10], 15);
+   II(dd, ee, aa, bb, cc, X[ 0], 14);
+   II(cc, dd, ee, aa, bb, X[ 8], 15);
+   II(bb, cc, dd, ee, aa, X[12],  9);
+   II(aa, bb, cc, dd, ee, X[ 4],  8);
+   II(ee, aa, bb, cc, dd, X[13],  9);
+   II(dd, ee, aa, bb, cc, X[ 3], 14);
+   II(cc, dd, ee, aa, bb, X[ 7],  5);
+   II(bb, cc, dd, ee, aa, X[15],  6);
+   II(aa, bb, cc, dd, ee, X[14],  8);
+   II(ee, aa, bb, cc, dd, X[ 5],  6);
+   II(dd, ee, aa, bb, cc, X[ 6],  5);
+   II(cc, dd, ee, aa, bb, X[ 2], 12);
+
+   /* round 5 */
+   JJ(bb, cc, dd, ee, aa, X[ 4],  9);
+   JJ(aa, bb, cc, dd, ee, X[ 0], 15);
+   JJ(ee, aa, bb, cc, dd, X[ 5],  5);
+   JJ(dd, ee, aa, bb, cc, X[ 9], 11);
+   JJ(cc, dd, ee, aa, bb, X[ 7],  6);
+   JJ(bb, cc, dd, ee, aa, X[12],  8);
+   JJ(aa, bb, cc, dd, ee, X[ 2], 13);
+   JJ(ee, aa, bb, cc, dd, X[10], 12);
+   JJ(dd, ee, aa, bb, cc, X[14],  5);
+   JJ(cc, dd, ee, aa, bb, X[ 1], 12);
+   JJ(bb, cc, dd, ee, aa, X[ 3], 13);
+   JJ(aa, bb, cc, dd, ee, X[ 8], 14);
+   JJ(ee, aa, bb, cc, dd, X[11], 11);
+   JJ(dd, ee, aa, bb, cc, X[ 6],  8);
+   JJ(cc, dd, ee, aa, bb, X[15],  5);
+   JJ(bb, cc, dd, ee, aa, X[13],  6);
+
+   /* parallel round 1 */
+   JJJ(aaa, bbb, ccc, ddd, eee, X[ 5],  8);
+   JJJ(eee, aaa, bbb, ccc, ddd, X[14],  9);
+   JJJ(ddd, eee, aaa, bbb, ccc, X[ 7],  9);
+   JJJ(ccc, ddd, eee, aaa, bbb, X[ 0], 11);
+   JJJ(bbb, ccc, ddd, eee, aaa, X[ 9], 13);
+   JJJ(aaa, bbb, ccc, ddd, eee, X[ 2], 15);
+   JJJ(eee, aaa, bbb, ccc, ddd, X[11], 15);
+   JJJ(ddd, eee, aaa, bbb, ccc, X[ 4],  5);
+   JJJ(ccc, ddd, eee, aaa, bbb, X[13],  7);
+   JJJ(bbb, ccc, ddd, eee, aaa, X[ 6],  7);
+   JJJ(aaa, bbb, ccc, ddd, eee, X[15],  8);
+   JJJ(eee, aaa, bbb, ccc, ddd, X[ 8], 11);
+   JJJ(ddd, eee, aaa, bbb, ccc, X[ 1], 14);
+   JJJ(ccc, ddd, eee, aaa, bbb, X[10], 14);
+   JJJ(bbb, ccc, ddd, eee, aaa, X[ 3], 12);
+   JJJ(aaa, bbb, ccc, ddd, eee, X[12],  6);
+
+   /* parallel round 2 */
+   III(eee, aaa, bbb, ccc, ddd, X[ 6],  9); 
+   III(ddd, eee, aaa, bbb, ccc, X[11], 13);
+   III(ccc, ddd, eee, aaa, bbb, X[ 3], 15);
+   III(bbb, ccc, ddd, eee, aaa, X[ 7],  7);
+   III(aaa, bbb, ccc, ddd, eee, X[ 0], 12);
+   III(eee, aaa, bbb, ccc, ddd, X[13],  8);
+   III(ddd, eee, aaa, bbb, ccc, X[ 5],  9);
+   III(ccc, ddd, eee, aaa, bbb, X[10], 11);
+   III(bbb, ccc, ddd, eee, aaa, X[14],  7);
+   III(aaa, bbb, ccc, ddd, eee, X[15],  7);
+   III(eee, aaa, bbb, ccc, ddd, X[ 8], 12);
+   III(ddd, eee, aaa, bbb, ccc, X[12],  7);
+   III(ccc, ddd, eee, aaa, bbb, X[ 4],  6);
+   III(bbb, ccc, ddd, eee, aaa, X[ 9], 15);
+   III(aaa, bbb, ccc, ddd, eee, X[ 1], 13);
+   III(eee, aaa, bbb, ccc, ddd, X[ 2], 11);
+
+   /* parallel round 3 */
+   HHH(ddd, eee, aaa, bbb, ccc, X[15],  9);
+   HHH(ccc, ddd, eee, aaa, bbb, X[ 5],  7);
+   HHH(bbb, ccc, ddd, eee, aaa, X[ 1], 15);
+   HHH(aaa, bbb, ccc, ddd, eee, X[ 3], 11);
+   HHH(eee, aaa, bbb, ccc, ddd, X[ 7],  8);
+   HHH(ddd, eee, aaa, bbb, ccc, X[14],  6);
+   HHH(ccc, ddd, eee, aaa, bbb, X[ 6],  6);
+   HHH(bbb, ccc, ddd, eee, aaa, X[ 9], 14);
+   HHH(aaa, bbb, ccc, ddd, eee, X[11], 12);
+   HHH(eee, aaa, bbb, ccc, ddd, X[ 8], 13);
+   HHH(ddd, eee, aaa, bbb, ccc, X[12],  5);
+   HHH(ccc, ddd, eee, aaa, bbb, X[ 2], 14);
+   HHH(bbb, ccc, ddd, eee, aaa, X[10], 13);
+   HHH(aaa, bbb, ccc, ddd, eee, X[ 0], 13);
+   HHH(eee, aaa, bbb, ccc, ddd, X[ 4],  7);
+   HHH(ddd, eee, aaa, bbb, ccc, X[13],  5);
+
+   /* parallel round 4 */   
+   GGG(ccc, ddd, eee, aaa, bbb, X[ 8], 15);
+   GGG(bbb, ccc, ddd, eee, aaa, X[ 6],  5);
+   GGG(aaa, bbb, ccc, ddd, eee, X[ 4],  8);
+   GGG(eee, aaa, bbb, ccc, ddd, X[ 1], 11);
+   GGG(ddd, eee, aaa, bbb, ccc, X[ 3], 14);
+   GGG(ccc, ddd, eee, aaa, bbb, X[11], 14);
+   GGG(bbb, ccc, ddd, eee, aaa, X[15],  6);
+   GGG(aaa, bbb, ccc, ddd, eee, X[ 0], 14);
+   GGG(eee, aaa, bbb, ccc, ddd, X[ 5],  6);
+   GGG(ddd, eee, aaa, bbb, ccc, X[12],  9);
+   GGG(ccc, ddd, eee, aaa, bbb, X[ 2], 12);
+   GGG(bbb, ccc, ddd, eee, aaa, X[13],  9);
+   GGG(aaa, bbb, ccc, ddd, eee, X[ 9], 12);
+   GGG(eee, aaa, bbb, ccc, ddd, X[ 7],  5);
+   GGG(ddd, eee, aaa, bbb, ccc, X[10], 15);
+   GGG(ccc, ddd, eee, aaa, bbb, X[14],  8);
+
+   /* parallel round 5 */
+   FFF(bbb, ccc, ddd, eee, aaa, X[12] ,  8);
+   FFF(aaa, bbb, ccc, ddd, eee, X[15] ,  5);
+   FFF(eee, aaa, bbb, ccc, ddd, X[10] , 12);
+   FFF(ddd, eee, aaa, bbb, ccc, X[ 4] ,  9);
+   FFF(ccc, ddd, eee, aaa, bbb, X[ 1] , 12);
+   FFF(bbb, ccc, ddd, eee, aaa, X[ 5] ,  5);
+   FFF(aaa, bbb, ccc, ddd, eee, X[ 8] , 14);
+   FFF(eee, aaa, bbb, ccc, ddd, X[ 7] ,  6);
+   FFF(ddd, eee, aaa, bbb, ccc, X[ 6] ,  8);
+   FFF(ccc, ddd, eee, aaa, bbb, X[ 2] , 13);
+   FFF(bbb, ccc, ddd, eee, aaa, X[13] ,  6);
+   FFF(aaa, bbb, ccc, ddd, eee, X[14] ,  5);
+   FFF(eee, aaa, bbb, ccc, ddd, X[ 0] , 15);
+   FFF(ddd, eee, aaa, bbb, ccc, X[ 3] , 13);
+   FFF(ccc, ddd, eee, aaa, bbb, X[ 9] , 11);
+   FFF(bbb, ccc, ddd, eee, aaa, X[11] , 11);
+
+   /* combine results */
+   ddd += cc + MDbuf[1];               /* final result for MDbuf[0] */
+   MDbuf[1] = MDbuf[2] + dd + eee;
+   MDbuf[2] = MDbuf[3] + ee + aaa;
+   MDbuf[3] = MDbuf[4] + aa + bbb;
+   MDbuf[4] = MDbuf[0] + bb + ccc;
+   MDbuf[0] = ddd;
+
+   return;
+}
+
+/********************************************************************/
+
+void MDfinish(dword *MDbuf, byte *strptr, dword lswlen, dword mswlen)
+{
+   unsigned int i;                                 /* counter       */
+   dword        X[16];                             /* message words */
+
+   memset(X, 0, 16*sizeof(dword));
+
+   /* put bytes from strptr into X */
+   for (i=0; i<(lswlen&63); i++) {
+      /* byte i goes into word X[i div 4] at pos.  8*(i mod 4)  */
+      X[i>>2] ^= (dword) *strptr++ << (8 * (i&3));
+   }
+
+   /* append the bit m_n == 1 */
+   X[(lswlen>>2)&15] ^= (dword)1 << (8*(lswlen&3) + 7);
+
+   if ((lswlen & 63) > 55) {
+      /* length goes to next block */
+      compress(MDbuf, X);
+      memset(X, 0, 16*sizeof(dword));
+   }
+
+   /* append length in bits*/
+   X[14] = lswlen << 3;
+   X[15] = (lswlen >> 29) | (mswlen << 3);
+   compress(MDbuf, X);
+
+   return;
+}
+
+/************************ end of file rmd160.c **********************/
+
--- /dev/null
+++ b/net/rsa/rmd160.h
@@ -0,0 +1,154 @@
+/********************************************************************\
+ *
+ *      FILE:     rmd160.h
+ *
+ *      CONTENTS: Header file for a sample C-implementation of the
+ *                RIPEMD-160 hash-function. 
+ *      TARGET:   any computer with an ANSI C compiler
+ *
+ *      AUTHOR:   Antoon Bosselaers, ESAT-COSIC
+ *      DATE:     1 March 1996
+ *      VERSION:  1.0
+ *
+ *      Copyright (c) Katholieke Universiteit Leuven
+ *      1996, All Rights Reserved
+ *
+ *  Conditions for use of the RIPEMD-160 Software
+ *
+ *  The RIPEMD-160 software is freely available for use under the terms and
+ *  conditions described hereunder, which shall be deemed to be accepted by
+ *  any user of the software and applicable on any use of the software:
+ * 
+ *  1. K.U.Leuven Department of Electrical Engineering-ESAT/COSIC shall for
+ *     all purposes be considered the owner of the RIPEMD-160 software and of
+ *     all copyright, trade secret, patent or other intellectual property
+ *     rights therein.
+ *  2. The RIPEMD-160 software is provided on an "as is" basis without
+ *     warranty of any sort, express or implied. K.U.Leuven makes no
+ *     representation that the use of the software will not infringe any
+ *     patent or proprietary right of third parties. User will indemnify
+ *     K.U.Leuven and hold K.U.Leuven harmless from any claims or liabilities
+ *     which may arise as a result of its use of the software. In no
+ *     circumstances K.U.Leuven R&D will be held liable for any deficiency,
+ *     fault or other mishappening with regard to the use or performance of
+ *     the software.
+ *  3. User agrees to give due credit to K.U.Leuven in scientific publications 
+ *     or communications in relation with the use of the RIPEMD-160 software 
+ *     as follows: RIPEMD-160 software written by Antoon Bosselaers, 
+ *     available at http://www.esat.kuleuven.be/~cosicart/ps/AB-9601/.
+ *
+\********************************************************************/
+
+#ifndef  RMD160H           /* make sure this file is read only once */
+#define  RMD160H
+
+/********************************************************************/
+
+/* typedef 8 and 32 bit types, resp.  */
+/* adapt these, if necessary, 
+   for your operating system and compiler */
+typedef    unsigned char        byte;
+typedef    unsigned long        dword;
+
+
+/********************************************************************/
+
+/* macro definitions */
+
+/* collect four bytes into one word: */
+#define BYTES_TO_DWORD(strptr)                    \
+            (((dword) *((strptr)+3) << 24) | \
+             ((dword) *((strptr)+2) << 16) | \
+             ((dword) *((strptr)+1) <<  8) | \
+             ((dword) *(strptr)))
+
+/* ROL(x, n) cyclically rotates x over n bits to the left */
+/* x must be of an unsigned 32 bits type and 0 <= n < 32. */
+#define ROL(x, n)        (((x) << (n)) | ((x) >> (32-(n))))
+
+/* the five basic functions F(), G() and H() */
+#define F(x, y, z)        ((x) ^ (y) ^ (z)) 
+#define G(x, y, z)        (((x) & (y)) | (~(x) & (z))) 
+#define H(x, y, z)        (((x) | ~(y)) ^ (z))
+#define I(x, y, z)        (((x) & (z)) | ((y) & ~(z))) 
+#define J(x, y, z)        ((x) ^ ((y) | ~(z)))
+  
+/* the ten basic operations FF() through III() */
+#define FF(a, b, c, d, e, x, s)        {\
+      (a) += F((b), (c), (d)) + (x);\
+      (a) = ROL((a), (s)) + (e);\
+      (c) = ROL((c), 10);\
+   }
+#define GG(a, b, c, d, e, x, s)        {\
+      (a) += G((b), (c), (d)) + (x) + 0x5a827999UL;\
+      (a) = ROL((a), (s)) + (e);\
+      (c) = ROL((c), 10);\
+   }
+#define HH(a, b, c, d, e, x, s)        {\
+      (a) += H((b), (c), (d)) + (x) + 0x6ed9eba1UL;\
+      (a) = ROL((a), (s)) + (e);\
+      (c) = ROL((c), 10);\
+   }
+#define II(a, b, c, d, e, x, s)        {\
+      (a) += I((b), (c), (d)) + (x) + 0x8f1bbcdcUL;\
+      (a) = ROL((a), (s)) + (e);\
+      (c) = ROL((c), 10);\
+   }
+#define JJ(a, b, c, d, e, x, s)        {\
+      (a) += J((b), (c), (d)) + (x) + 0xa953fd4eUL;\
+      (a) = ROL((a), (s)) + (e);\
+      (c) = ROL((c), 10);\
+   }
+#define FFF(a, b, c, d, e, x, s)        {\
+      (a) += F((b), (c), (d)) + (x);\
+      (a) = ROL((a), (s)) + (e);\
+      (c) = ROL((c), 10);\
+   }
+#define GGG(a, b, c, d, e, x, s)        {\
+      (a) += G((b), (c), (d)) + (x) + 0x7a6d76e9UL;\
+      (a) = ROL((a), (s)) + (e);\
+      (c) = ROL((c), 10);\
+   }
+#define HHH(a, b, c, d, e, x, s)        {\
+      (a) += H((b), (c), (d)) + (x) + 0x6d703ef3UL;\
+      (a) = ROL((a), (s)) + (e);\
+      (c) = ROL((c), 10);\
+   }
+#define III(a, b, c, d, e, x, s)        {\
+      (a) += I((b), (c), (d)) + (x) + 0x5c4dd124UL;\
+      (a) = ROL((a), (s)) + (e);\
+      (c) = ROL((c), 10);\
+   }
+#define JJJ(a, b, c, d, e, x, s)        {\
+      (a) += J((b), (c), (d)) + (x) + 0x50a28be6UL;\
+      (a) = ROL((a), (s)) + (e);\
+      (c) = ROL((c), 10);\
+   }
+
+/********************************************************************/
+
+/* function prototypes */
+
+void MDinit(dword *MDbuf);
+/*
+ *  initializes MDbuffer to "magic constants"
+ */
+
+void compress(dword *MDbuf, dword *X);
+/*
+ *  the compression function.
+ *  transforms MDbuf using message bytes X[0] through X[15]
+ */
+
+void MDfinish(dword *MDbuf, byte *strptr, dword lswlen, dword mswlen);
+/*
+ *  puts bytes from strptr into X and pad out; appends length 
+ *  and finally, compresses the last block(s)
+ *  note: length in bits == 8 * (lswlen + 2^32 mswlen).
+ *  note: there are (lswlen mod 64) bytes left in strptr.
+ */
+
+#endif  /* RMD160H */
+
+/*********************** end of file rmd160.h ***********************/
+
--- /dev/null
+++ b/net/rsa/rsa.c
@@ -0,0 +1,303 @@
+/*
+ * FONSM RSA handling library
+ *
+ * This file is part of FONUCS. Copyright (C) 2007 FON Wireless Ltd.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Created: 20070306 Pablo Martin Medrano <pablo@fon.com>
+ *
+ * Based on axTLS
+ *
+ * $Id: fonrsa.c 405 2007-09-19 15:26:17Z jesus.pico $
+ */
+#include <malloc.h>
+#include <common.h>
+#include "rsa.h"
+#include "rmd160.h"
+#include "bigint.h"
+#include "base64.h"
+
+#include "public_key.h"
+
+#define RMDsize 160		/* A RIPEMD-160 hash has 160 bits */
+
+typedef struct {
+	uint8_t *buffer;
+	size_t size;
+} DER_key;
+
+typedef struct {
+	bigint *m;              /* modulus */
+	bigint *e;              /* public exponent */
+	int num_octets;
+	BI_CTX *bi_ctx;         /* big integer handle */
+} RSA_parameters;
+
+typedef struct {
+	DER_key *derkey;
+	RSA_parameters *rsaparms;
+} RSA;
+
+static void CH_free_der_key(DER_key *key)
+{
+	free(key->buffer);
+	free(key);
+}
+
+int CH_decrypt(RSA_parameters *rsa, uint8_t *buffer_in, uint8_t *buffer_out)
+{
+	bigint *dat_bi;
+	bigint *decrypted_bi;
+	int byte_size;
+
+	byte_size = rsa->num_octets; 
+	dat_bi = bi_import(rsa->bi_ctx, buffer_in, byte_size);
+	rsa->bi_ctx->mod_offset = BIGINT_M_OFFSET;
+	bi_copy(rsa->m);
+	decrypted_bi = bi_mod_power(rsa->bi_ctx, dat_bi, rsa->e);
+	bi_export(rsa->bi_ctx, decrypted_bi, buffer_out, byte_size);
+	return 0;
+}
+
+byte *RMDbinary(char *buffer, int len)
+{
+	byte data[1024];	/* contains current mess. block */
+	dword nbytes;		/* length of this block         */
+	dword MDbuf[RMDsize / 32];	/* contains (A, B, C, D(, E))   */
+	static byte hashcode[RMDsize / 8];	/* for final hash-value         */
+	dword X[16];		/* current 16-word chunk        */
+	unsigned int i, j;	/* counters                     */
+	dword length[2];	/* length in bytes of message   */
+	dword offset;		/* # of unprocessed bytes at    */
+	/*          call of MDfinish    */
+	int total = len;
+	char *tmp = buffer;
+	MDinit(MDbuf);
+	length[0] = 0;
+	length[1] = 0;
+	while ( len) {
+		memcpy(data, tmp, 1024);
+		if(len > 1024)
+		{
+			nbytes = 1024;
+			len -= 1024;
+			tmp += 1024;
+		} else {
+			nbytes = len;
+			len = 0;
+		}
+		/* process all complete blocks */
+		for (i = 0; i < (nbytes >> 6); i++) {
+			for (j = 0; j < 16; j++)
+				X[j] = BYTES_TO_DWORD(data + 64 * i + 4 * j);
+			compress(MDbuf, X);
+		}
+		/* update length[] */
+		if (length[0] + nbytes < length[0])
+			length[1]++;	/* overflow to msb of length */
+		length[0] += nbytes;
+	}
+	/* finish: */
+	offset = length[0] & 0x3C0;	/* extract bytes 6 to 10 inclusive */
+	MDfinish(MDbuf, data + offset, length[0], length[1]);
+
+	for (i = 0; i < RMDsize / 8; i += 4) {
+		hashcode[i] = MDbuf[i >> 2];
+		hashcode[i + 1] = (MDbuf[i >> 2] >> 8);
+		hashcode[i + 2] = (MDbuf[i >> 2] >> 16);
+		hashcode[i + 3] = (MDbuf[i >> 2] >> 24);
+	}
+
+	return (byte *) hashcode;
+}
+
+static DER_key *CH_load_pem_key(void)
+{
+	DER_key *ret;
+	uint8_t *buffer;
+	char *b64,*p,*t;
+	char key[1024];
+	size_t filesize;
+	int size;
+
+	if ((ret = (DER_key *)malloc(sizeof(DER_key))) == NULL)
+		return NULL;
+	buffer = public_key;
+	p = (char *)buffer;
+	while ((*p != '\n') && (*p != '\0'))
+		p++;
+	if (*p == '\0') {
+		free(ret);
+		return NULL;
+	}
+	p++;
+	b64 = t = p;
+	while((p - b64) <= filesize) {
+		if ((*p == '-')) {
+			break;
+		} else if ((*p != '\n') && (*p != ' ') && (*p != '\t')) {
+			*t = *p;
+			t++;
+		}
+		p++;
+	}
+	*t = '\0';
+	size = B64_decode(b64, key, strlen(b64), 1024);
+	if (size < 0) {
+		free(buffer);
+		free(ret);
+		return NULL;
+	}
+	//free(buffer);
+	ret->buffer = (char *)malloc(size);
+	ret->size = size;
+	memcpy((void *)ret->buffer, (void *)key, size);
+	return ret;
+}
+
+/*
+ * Similar to RSA_pub_key_new, rewritten to make this program depend only on bi module
+ */
+void CH_pub_key_new(RSA_parameters **rsa, const uint8_t *modulus, int mod_len, const uint8_t *pub_exp, int pub_len)
+{
+	RSA_parameters *rsa_parameters;
+
+	BI_CTX *bi_ctx = bi_initialize();
+	*rsa = (RSA_parameters *)calloc(1, sizeof(RSA_parameters));
+	rsa_parameters = *rsa;
+	rsa_parameters->bi_ctx = bi_ctx;
+	rsa_parameters->num_octets = (mod_len & 0xFFF0);
+	rsa_parameters->m = bi_import(bi_ctx, modulus, mod_len);
+	bi_set_mod(bi_ctx, rsa_parameters->m, BIGINT_M_OFFSET);
+	rsa_parameters->e = bi_import(bi_ctx, pub_exp, pub_len);
+	bi_permanent(rsa_parameters->e);
+}
+
+/*
+ * Get the public key specifics from an ASN.1 encoded file
+ * A function lacking in the exported axTLS API
+ *
+ * This is a really weird hack that only works with RSA public key
+ * files
+ */
+static int asn1_get_public_key(const uint8_t *buf, int len, RSA_parameters **rsa_parameters)
+{
+	uint8_t *modulus, *pub_exp;
+	int mod_len, pub_len;
+
+	pub_len = 3;
+	mod_len = len - 37;
+	if (buf[0] != 0x30) {
+		return -1;
+	}
+
+	pub_exp = (uint8_t *)malloc(3);
+	modulus = (uint8_t *)malloc(mod_len);
+	memcpy(modulus, buf + 32 , mod_len);
+	memcpy(pub_exp, buf + 34 + mod_len, 3); 
+	if (mod_len <= 0 || pub_len <= 0 )
+		return -1;
+	CH_pub_key_new(rsa_parameters, modulus, mod_len, pub_exp, pub_len);
+
+	free(modulus);
+	free(pub_exp);
+	return 0;
+}
+
+
+/* FR_init */
+void *FR_init(void)
+{
+	DER_key *derkey;
+	RSA_parameters *rsa_parameters;
+
+	derkey = CH_load_pem_key();
+	if ((asn1_get_public_key(derkey->buffer, derkey->size, &rsa_parameters)) != 0) {
+		fprintf(stderr, "Error: Extracting public key from file\n");
+		return 0;
+	}
+	CH_free_der_key(derkey);
+	return (void *)rsa_parameters;
+}
+
+FONRSA_ERROR FR_end(void *handle)
+{
+	RSA_parameters *rsa_parameters = (RSA_parameters *)handle;
+
+	free(rsa_parameters);
+	return FONRSA_OK;
+}
+
+/*
+ *
+ * Implementation of  PKCS 1.5 padding, borrowed from
+ * Tom's code (public domain)
+ */
+
+/* Standalone FR_verify_file */
+FONRSA_ERROR FR_verify_file(void *handler, char *file_data, int file_len,
+	char *signature_buffer, int signature_size)
+{
+	int j;
+	byte *hashcode;
+	byte hash[20];
+	uint8_t *decrypted;
+	RSA_parameters *rsa_parameters = (RSA_parameters *)handler;
+
+	/* Calculates the RIPEMD-160 hash of the file */
+	hashcode = RMDbinary (file_data, file_len);
+
+	if (rsa_parameters->num_octets != signature_size)
+		return FONRSA_SIZE;
+	decrypted = (uint8_t *)malloc(rsa_parameters->num_octets);
+	if (CH_decrypt(rsa_parameters, signature_buffer, decrypted)) {
+		printf("Error: Decrypting signature\n");
+		return FONRSA_VERIFICATION_FAILURE;
+	}
+	memcpy(hash, decrypted + 492, 20);
+	//free(decrypted);
+	//free(signature_buffer);
+	for (j = 0; j < RMDsize/8; j++) {
+		if (hash[j] != hashcode[j])
+			return FONRSA_VERIFICATION_FAILURE;
+	}
+	return FONRSA_OK;
+}
+
+int rsa_check_signature(char *signature, int signature_len, char *buffer, int buffer_len)
+{
+	FONRSA_ERROR fonrsa_error;
+	void *handle;
+	handle = FR_init();
+	if (handle == NULL) {
+		printf("Error loading keys\n");
+		return 1;
+	}
+	fonrsa_error = FR_verify_file(handle, buffer, buffer_len, signature, signature_len);
+	FR_end(handle);
+	switch (fonrsa_error) {
+		case FONRSA_OK:
+			printf("Verified OK\n");
+			return 0;
+		case FONRSA_VERIFICATION_FAILURE:
+			printf("Verification failure\n");
+			return 1;
+		default:
+			printf("Verification error\n");
+			return -1;
+	}
+
+}
--- /dev/null
+++ b/net/rsa/rsa.h
@@ -0,0 +1,46 @@
+/*
+ * FONSM RSA handling library, used by fonsmcd and foncheckrsa
+ *
+ * This file is part of FONUCS. Copyright (C) 2007 FON Wireless Ltd.
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Created: 20070306 Pablo Martin Medrano <pablo@fon.com>
+ *
+ * $Id: fonrsa.h 404 2007-09-17 10:41:31Z jesus.pico $
+ */
+#ifndef _FONRSA_H
+#define _FONRSA_H
+
+#define MINIMUM_PADING_BYTES_PKCS_1_5 3
+
+typedef enum {
+	FONRSA_OK = 0,
+	FONRSA_VERIFICATION_FAILURE = 1,
+	FONRSA_OPENKEY = 2,
+	FONRSA_SIZE = 3,
+	FONRSA_LOADFILE = 4,
+	FONRSA_CRYPT = 5,
+	FONRSA_DECRYPT = 6,
+	FONRSA_SAVEFILE = 7,
+	FONRSA_NOSYS = 8,
+	FONRSA_VERIFY = 9
+} FONRSA_ERROR;
+
+int rsa_check_signature(char *signature, int signature_len, char *buffer, int buffer_len);
+
+#endif
+
+
--- /dev/null
+++ b/net/rsa/sign.h
@@ -0,0 +1,27 @@
+/*
+ * Signature interface
+ *
+ * This file is part of FONUCS. Copyright (C) 2007 FON Wireless Ltd.
+ *
+ * Created: 20070417 Pablo Martín Medrano <pablo@fon.com>
+ *
+ * $Id: sign.h 389 2007-06-11 08:29:56Z pablo.martin $
+ */
+#ifndef __SIGN_H__
+#define __SIGN_H__
+#ifdef __cplusplus
+	extern "C" {
+#endif
+
+void SG_init(void);
+void *SG_start(char *private_key_path, char *public_key_path);
+void SG_stop(void *handle);
+int SG_crypt(void *data, unsigned char *text, int size_text, unsigned char *crypted_text,
+	unsigned int crypted_text_buffer_size, int *crypted_size);
+int SG_crypt_v2(void *data, unsigned char *text, int size_text, unsigned char *crypted_text,
+	unsigned int crypted_text_buffer_size, int *crypted_size);
+#ifdef __cplusplus
+}
+#endif
+#endif /* #ifdef __SIGN_H__ */
+
--- /dev/null
+++ b/net/rsa/sign_openssl.c
@@ -0,0 +1,437 @@
+/*
+ * Signature using OpenSSL 
+ *
+ * This file is part of FONUCS. Copyright (C) 2007 FON Wireless Ltd.
+ *
+ * Created: 20070417 Pablo Martín Medrano <pablo@fon.com>
+ *
+ * $Id: sign_openssl.c 346 2007-05-10 19:51:38Z pablo.martin $
+ */
+/*
+ *
+ * How the RSA public and private key was generated
+ * To check .FON files
+ * openssl genrsa -out private_fon_rsa_key.pem 4096
+ * openssl rsa -in private_fon_rsa_key.pem -pubout -out public_fon_rsa_key.pem
+ *
+ * How the Status Manager public and private key was generated
+ * openssl genrsa -out private_sm_rsa_key.pem 2048
+ * openssl rsa -in private_sm_rsa_key.pem -pubout -out public_sm_rsa_key.pem
+ *
+ * How to sign using the RSA private key (This is what fonsign does)
+ *  openssl dgst -rmd160 -sign private_fon_rsa_key.pem FILE > SIGNATURE
+ * How to verify using the RSA public key (This is what fonverify + foncheckrsa does)
+ *  openssl dgst -rmd160 -verify public_fon_rsa_key.pem -signature SIGNATURE FILE
+ * Convert to DER file (to use it in La Fonera)
+ *  openssl rsa -inform PEM -outform DER -pubin -in public_fon_rsa_key.pem -pubout -out public_fon_rsa_key.der
+ */
+#include <openssl/rsa.h>
+#include <openssl/ssl.h>
+#include <openssl/bn.h>
+#include <openssl/pem.h>
+#include <openssl/evp.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#ifndef __MAINTEST__
+#include "log.h"
+#else
+#define fon_warning printf
+#define fon_debug printf
+#define fon_critical printf
+#endif
+#include "sign.h"
+
+typedef struct {
+	RSA *rsa;
+	int rsa_size;
+	EVP_PKEY *pkey;
+	int pkey_size;
+	RSA *public_rsa;
+	int public_rsa_size;
+	EVP_PKEY *public_pkey;
+	int public_pkey_size;
+} Sign;
+
+typedef enum {
+	KEY_PUBLIC = 0,
+	KEY_PRIVATE
+} KEY_TYPE;
+
+static EVP_PKEY *SG_load_key(char *key_path, KEY_TYPE type);
+static unsigned char *load_file_in_buffer(char *path, int *size);
+static int save_file_from_buffer(char *path, char *buffer, int size);
+
+void SG_init(void)
+{
+	SSL_load_error_strings();
+	SSL_library_init();
+	OpenSSL_add_all_algorithms();
+	OpenSSL_add_all_ciphers();
+	OpenSSL_add_all_digests();
+}
+
+static unsigned char *load_file_in_buffer(char *path, int *size)
+{
+	char *buffer;
+	struct stat st;
+	int fd;
+
+	if (stat(path, &st))
+		return NULL;
+	buffer = (char *)malloc(st.st_size);
+	if (buffer == NULL)
+		return NULL;
+ 	if ((fd = open(path, O_RDONLY)) == -1) {
+		free(buffer);
+		return NULL;
+	}
+	if (read(fd,buffer,st.st_size) != (ssize_t)st.st_size) {
+		free(buffer);
+		close(fd);
+		return NULL;
+	}
+	*size = (int)st.st_size;
+	close(fd);
+	return buffer;
+}
+
+static int save_file_from_buffer(char *path, char *buffer, int size)
+{
+	int fd;
+
+	if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) == -1)
+		return -1;
+	if (write(fd, buffer, (size_t)size) != ((ssize_t)size)) {
+		close(fd);
+		return -1;
+	}
+	close(fd);
+	return 0;
+}
+
+static EVP_PKEY *SG_load_key(char *key_path, KEY_TYPE type)
+{
+	BIO *key = NULL;
+	EVP_PKEY *pkey;
+
+	if ((key = BIO_new(BIO_s_file())) == NULL) {
+		//ERR_print_errors(err);
+		fon_warning("%s: Error calling BIO_new()\n", __FUNCTION__);
+		return NULL;
+	}
+	if (BIO_read_filename(key, key_path) <= 0) {
+		fon_warning("%s: Error opening %s\n", __FUNCTION__, key_path);
+		// ERR_print_errors(err);
+		BIO_free(key);	
+	}
+	if (type == KEY_PUBLIC) {
+		pkey = PEM_read_bio_PUBKEY(key, NULL, NULL, NULL);
+	} else if (type == KEY_PRIVATE) {
+		pkey = PEM_read_bio_PrivateKey(key, NULL, NULL, NULL); 
+	} else {
+		return NULL;
+	}
+
+	if (pkey == NULL) {
+		fon_warning("%s: Error reading %s\n", __FUNCTION__, key_path);
+		BIO_free(key);
+		return NULL;
+	}
+	BIO_free(key);
+	return pkey;
+}
+
+void *SG_start(char *private_key_path, char *public_key_path)
+{
+	Sign *sign;
+
+	if ((sign = (Sign *)malloc(sizeof(Sign))) == NULL)
+		return NULL;
+	memset(sign, 0, sizeof(Sign));
+	if (private_key_path != NULL) {
+		if ((sign->pkey = SG_load_key(private_key_path, KEY_PRIVATE)) == NULL) {
+			fon_warning("%s: Error loading %s", __FUNCTION__, private_key_path);
+			return NULL;
+		}
+	}
+	if (public_key_path != NULL) {
+		if ((sign->public_pkey = SG_load_key(public_key_path, KEY_PUBLIC)) == NULL) {
+			fon_warning("%s: Error loading %s", __FUNCTION__, public_key_path);
+			return NULL;
+		}
+	}
+	if (sign->pkey != NULL) {
+		sign->pkey_size = EVP_PKEY_size(sign->pkey);
+		if ((sign->rsa = EVP_PKEY_get1_RSA(sign->pkey)) == NULL) {
+			EVP_PKEY_free(sign->pkey);
+			return NULL;
+		}
+	}
+	if (sign->public_pkey != NULL) {
+		sign->public_pkey_size = EVP_PKEY_size(sign->public_pkey);
+		if ((sign->public_rsa = EVP_PKEY_get1_RSA(sign->public_pkey)) == NULL) {
+			EVP_PKEY_free(sign->pkey);
+			return NULL;
+		}
+	}
+	if (((sign->rsa == NULL) && (private_key_path != NULL)) || 
+	   ((sign->public_rsa == NULL) && (public_key_path != NULL))) {
+		fon_warning("%s: Error calling EVP_PKEY_get1_RSA()", __FUNCTION__);
+		return NULL;
+	}
+	if (sign->rsa != NULL) {
+		sign->rsa_size = RSA_size(sign->rsa);
+		if (RSA_check_key(sign->rsa) != 1) {
+			fon_warning("%s: RSA key failure", __FUNCTION__);
+			return NULL;
+		}
+	}
+
+	return (void *)sign;
+}
+
+void SG_stop(void *handle)
+{
+	Sign *sign = (Sign *)handle;
+
+	EVP_PKEY_free(sign->pkey);
+	EVP_PKEY_free(sign->public_pkey);
+	if (sign->rsa != NULL)
+		RSA_free(sign->rsa);
+	if (sign->public_rsa != NULL)
+		RSA_free(sign->public_rsa);
+	free(sign);
+}
+
+int SG_verify(void *data, unsigned char *text, unsigned int size_text,
+	unsigned char *signature, unsigned int size_signature)
+{
+	EVP_MD_CTX mdctx;
+	EVP_MD *md;
+	EVP_PKEY *pkey;
+	int ret;
+	Sign *sign = (Sign *)data;
+
+	md = (EVP_MD *)EVP_ripemd160();
+	if(!EVP_VerifyInit(&mdctx, md))
+		return 4;
+	if (!EVP_VerifyUpdate(&mdctx, (const void *)text, (unsigned int)size_text)) {
+		return 5;
+	}
+	ret = EVP_VerifyFinal(&mdctx, (const char *)signature, size_signature, sign->public_pkey);
+	EVP_PKEY_free(pkey);
+	EVP_MD_CTX_cleanup(&mdctx);
+	return ret;
+}
+
+int SG_sign(void *data, void *text, unsigned int size_text, void *signature_buffer,
+	unsigned int size_signature_buffer, unsigned int *size_signature)
+{
+	unsigned char *digest[EVP_MAX_MD_SIZE];
+	EVP_MD_CTX mdctx;
+	EVP_MD *md;
+	int ret;
+	Sign *sign = (Sign *)data;
+
+	if (size_signature_buffer < sign->pkey_size) 
+		return 1;
+
+	md = (EVP_MD *)EVP_ripemd160();
+	EVP_SignInit(&mdctx, md);
+	if (!EVP_SignUpdate(&mdctx, (const void *)text, (unsigned int)size_text)) {
+		return 2;
+	}
+	if (!EVP_SignFinal(&mdctx, (unsigned char *)signature_buffer, (unsigned int *)size_signature, sign->pkey)) {
+		return 3;
+	}
+	EVP_MD_CTX_cleanup(&mdctx);
+
+	return 0;
+}
+
+/*
+ * It's not advised to crypt using RAW ... unless you have crypted the buffer using AES before.
+ */
+int SG_crypt(void *data, unsigned char *text, int size_text,
+	unsigned char *crypted_text, unsigned int crypted_text_buffer_size,
+	int *crypted_size)
+{
+	EVP_MD_CTX mdctx;
+	EVP_MD *md;
+	int retsize;
+	Sign *sign = (Sign *)data;
+
+	if (crypted_text_buffer_size < sign->pkey_size) {
+		fon_critical("%s: size_signature_buffer [%u] < %u", __FUNCTION__, size_text, sign->pkey_size);
+		return 1;
+	}
+	if (size_text != sign->pkey_size) {
+		fon_critical("%s: size_text [%u] != %u", __FUNCTION__, size_text, sign->pkey_size);
+		return 2;
+	}
+	/* The buffer is pre-padded with random data ... */
+	fon_debug("%s: About to call RSA_private_encrypt(%d, %x, %x, %x, %d)",
+			__FUNCTION__, size_text, crypted_text, sign->rsa, RSA_NO_PADDING);
+	retsize = RSA_private_encrypt(size_text, text, crypted_text, sign->rsa, RSA_NO_PADDING);
+	if (retsize == -1) {
+		fon_critical("%s: Error calling RSA_private_encrypt(%d, %x, %x, %x, %d)",
+			__FUNCTION__, size_text, crypted_text, sign->rsa, RSA_NO_PADDING);    
+		return 1;
+	}
+	*crypted_size = retsize;
+	return 0;
+}
+
+/* SG_decrypt */
+int SG_decrypt(void *data, unsigned char *cryptext, int cryptext_size, unsigned char *plaintext,
+	int plaintext_buffer_size, int *plaintext_size)
+{
+	EVP_MD_CTX mdctx;
+	EVP_MD *md;
+	int retsize;
+	Sign *sign = (Sign *)data;
+
+	if (plaintext_buffer_size < sign->public_pkey_size) {
+		fon_critical("%s: plaintext_buffer_size [%u] < %u", __FUNCTION__, plaintext_buffer_size, sign->public_pkey_size);
+		return 1;
+	}
+	if (cryptext_size != sign->public_pkey_size) {
+		fon_critical("%s: cryptext_size [%u] != %u", __FUNCTION__, cryptext_size, sign->public_pkey_size);
+		return 2;
+	}
+	retsize = RSA_public_decrypt(cryptext_size, cryptext, plaintext, sign->public_rsa, RSA_NO_PADDING);
+	if (retsize == -1)
+		return 1;
+	*plaintext_size = retsize;
+	return 0;
+}
+
+#ifdef __MAINTEST__
+int main(int argc, char **argv)
+{
+	size_t argv0_size;
+	char *token;
+
+	argv0_size = strlen(argv[0]);
+	if (argv0_size < 7) {
+		fprintf(stderr, "%s?", argv[0]);
+		return 1;
+	}
+	token =  argv[0] + argv0_size - 7;
+
+	SG_init();
+	if (!strcmp(token, "fonsign")) {
+		return main_fonsign(argc, argv);
+	} else if (!strcmp(token, "foncryp")) {
+		return main_foncryp(argc, argv);
+	}
+	fprintf(stderr, "%s?", argv[0]);
+	return 1;
+}
+
+int main_foncryp(int argc, char **argv)
+{
+	void *handle = NULL;
+	int encrypt = 0;
+	char *filebuffer = NULL;
+	char crypted[1024];
+	int size, crypted_size, ret;
+
+	if (argc != 5) {
+		printf("Usage: %s encrypt|decrypt <key_file> <file> <crypted_file>\n", argv[0]);
+		return 1;
+	}
+	if (!strcmp(argv[1], "encrypt")) {
+		printf("Encryption mode\n");
+		encrypt = 1;
+	} else
+		printf("Decryption mode\n");
+	if (encrypt)
+		handle = SG_start(argv[2], NULL);
+	else
+		handle = SG_start(NULL, argv[2]);
+	if (handle == NULL) {
+		printf("Error loading keys\n");
+		return 1;
+	}
+	
+	filebuffer = load_file_in_buffer(argv[3], &size); 
+	if (filebuffer == NULL) {
+		printf("Error reading %s\n", argv[3]);
+		SG_stop(handle);
+		return 1;
+	}
+	if (encrypt)
+		ret = SG_crypt(handle, filebuffer, size, crypted, 1024, &crypted_size);
+	else
+		ret = SG_decrypt(handle, filebuffer, size, crypted, 1024, &crypted_size);
+
+	if (ret) {
+		printf("Error crypting %d bytes\n", size);
+		SG_stop(handle);
+		return 1;
+	}
+	printf("Crypted size %d\n", crypted_size);
+	if (save_file_from_buffer(argv[4], crypted, crypted_size)) {
+		printf("Error saving file\n");
+		SG_stop(handle);
+		return 1;
+	}
+
+	SG_stop(handle);
+	return 0;
+}
+
+int main_fonsign(int argc, char **argv)
+{
+	void *handle = NULL;
+	char signature_buffer[4096];
+	char *signature;
+	unsigned int signature_size;
+	struct stat st;
+	char *filebuffer = NULL;
+	int size;
+	int ret = -1;
+
+	if (argc != 5) {
+		fprintf(stderr, "usage: %s <private_key_file> <public_key_file> <file_to_sign> <signature_file>\n", argv[0]);
+		goto end;
+	}
+	handle = SG_start(argv[1], argv[2]);
+	if (handle == NULL) {
+		fprintf(stderr, "Error calling SG_start(%s)\n", argv[1]);
+		goto end;	
+	}
+	filebuffer = load_file_in_buffer(argv[3], &size); 
+	if (filebuffer == NULL) {
+		fprintf(stderr, "Error reading %s\n", argv[3]);
+		goto end;
+	}
+	if (SG_sign(handle, filebuffer, size, signature_buffer, 4096, &signature_size)) {
+		fprintf(stderr, "Error calling SG_sign()\n");
+		goto end;
+	}
+	ret = SG_verify(handle, filebuffer, size, signature_buffer, signature_size); 
+	if (ret == 0)
+		fprintf(stderr, "signature failure\n");
+	else if (ret == 1) {
+		fprintf(stderr, "signature ok\n");
+		ret = 0;
+	} else {
+		fprintf(stderr, "signature error\n");
+		goto end;
+	}
+	if (save_file_from_buffer(argv[4], signature_buffer, signature_size)) {
+		fprintf(stderr, "Error writing to %s\n", argv[4]);
+		goto end;
+	}
+	ret = 0;
+end:
+	if (filebuffer != NULL)
+		free(filebuffer);
+	if (handle != NULL)
+		SG_stop(handle);
+	return ret;
+}
+#endif
+
--- /dev/null
+++ b/net/uip-0.9/fs.c
@@ -0,0 +1,154 @@
+/**
+ * \addtogroup httpd
+ * @{
+ */
+
+/**
+ * \file
+ * HTTP server read-only file system code.
+ * \author Adam Dunkels <adam@dunkels.com>
+ *
+ * A simple read-only filesystem. 
+ */
+ 
+/*
+ * Copyright (c) 2001, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE 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 INSTITUTE 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. 
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: fs.c,v 1.7.2.3 2003/10/07 13:22:27 adam Exp $
+ */
+
+#include "uip.h"
+#include "httpd.h"
+#include "fs.h"
+#include "fsdata.h"
+
+#include "fsdata.c"
+
+#ifdef FS_STATISTICS
+#if FS_STATISTICS == 1
+static u16_t count[FS_NUMFILES];
+#endif /* FS_STATISTICS */
+#endif /* FS_STATISTICS */
+
+/*-----------------------------------------------------------------------------------*/
+static u8_t
+fs_strcmp(const char *str1, const char *str2)
+{
+  u8_t i;
+  i = 0;
+ loop:
+
+  if(str2[i] == 0 ||
+     str1[i] == '\r' || 
+     str1[i] == '\n') {
+    return 0;
+  }
+
+  if(str1[i] != str2[i]) {
+    return 1;
+  }
+
+
+  ++i;
+  goto loop;
+}
+/*-----------------------------------------------------------------------------------*/
+int
+fs_open(const char *name, struct fs_file *file)
+{
+#ifdef FS_STATISTICS
+#if FS_STATISTICS == 1
+  u16_t i = 0;
+#endif /* FS_STATISTICS */
+#endif /* FS_STATISTICS */
+  struct fsdata_file_noconst *f;
+
+  for(f = (struct fsdata_file_noconst *)FS_ROOT;
+      f != NULL;
+      f = (struct fsdata_file_noconst *)f->next) {
+
+    if(fs_strcmp(name, f->name) == 0) {
+      file->data = f->data;
+      file->len = f->len;
+#ifdef FS_STATISTICS
+#if FS_STATISTICS == 1
+      ++count[i];
+#endif /* FS_STATISTICS */
+#endif /* FS_STATISTICS */
+      return 1;
+    }
+#ifdef FS_STATISTICS
+#if FS_STATISTICS == 1
+    ++i;
+#endif /* FS_STATISTICS */
+#endif /* FS_STATISTICS */
+
+  }
+  return 0;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+fs_init(void)
+{
+#ifdef FS_STATISTICS
+#if FS_STATISTICS == 1
+  u16_t i;
+  for(i = 0; i < FS_NUMFILES; i++) {
+    count[i] = 0;
+  }
+#endif /* FS_STATISTICS */
+#endif /* FS_STATISTICS */
+}
+/*-----------------------------------------------------------------------------------*/
+#ifdef FS_STATISTICS
+#if FS_STATISTICS == 1  
+u16_t fs_count
+(char *name)
+{
+  struct fsdata_file_noconst *f;
+  u16_t i;
+
+  i = 0;
+  for(f = (struct fsdata_file_noconst *)FS_ROOT;
+      f != NULL;
+      f = (struct fsdata_file_noconst *)f->next) {
+
+    if(fs_strcmp(name, f->name) == 0) {
+      return count[i];
+    }
+    ++i;
+  }
+  return 0;
+}
+#endif /* FS_STATISTICS */
+#endif /* FS_STATISTICS */
+/*-----------------------------------------------------------------------------------*/
--- /dev/null
+++ b/net/uip-0.9/fsdata.c
@@ -0,0 +1,199 @@
+static const char data_flashing_html[] = {
+	/* /flashing.html */
+	0x2f, 0x66, 0x6c, 0x61, 0x73, 0x68, 0x69, 0x6e, 0x67, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0,
+	0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, 
+	0x30, 0x30, 0x20, 0x4f, 0x4b, 0xd, 0xa, 0x53, 0x65, 0x72, 
+	0x76, 0x65, 0x72, 0x3a, 0x20, 0x75, 0x49, 0x50, 0x2f, 0x30, 
+	0x2e, 0x39, 0x20, 0x28, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 
+	0x2f, 0x64, 0x75, 0x6e, 0x6b, 0x65, 0x6c, 0x73, 0x2e, 0x63, 
+	0x6f, 0x6d, 0x2f, 0x61, 0x64, 0x61, 0x6d, 0x2f, 0x75, 0x69, 
+	0x70, 0x2f, 0x29, 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x74, 0x65, 
+	0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 
+	0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0xd, 0xa, 
+	0xd, 0xa, 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0x3c, 0x62, 
+	0x6f, 0x64, 0x79, 0x20, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3d, 
+	0x22, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 0x20, 0x30, 
+	0x70, 0x74, 0x20, 0x61, 0x75, 0x74, 0x6f, 0x3b, 0x20, 0x68, 
+	0x65, 0x69, 0x67, 0x68, 0x74, 0x3a, 0x31, 0x30, 0x30, 0x25, 
+	0x3b, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, 
+	0x66, 0x66, 0x66, 0x3b, 0x20, 0x62, 0x61, 0x63, 0x6b, 0x67, 
+	0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, 0x6f, 0x6c, 0x6f, 
+	0x72, 0x3a, 0x20, 0x23, 0x66, 0x62, 0x62, 0x30, 0x33, 0x34, 
+	0x3b, 0x22, 0x3e, 0x3c, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 
+	0x3e, 0x3c, 0x68, 0x31, 0x3e, 0x55, 0x70, 0x67, 0x72, 0x61, 
+	0x64, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 
+	0x6d, 0x20, 0x2e, 0x2e, 0x2e, 0x2e, 0x3c, 0x2f, 0x68, 0x31, 
+	0x3e, 0x3c, 0x2f, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3e, 
+	0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x2f, 0x68, 
+	0x74, 0x6d, 0x6c, 0x3e, 0xa, };
+
+static const char data_fail_html[] = {
+	/* /fail.html */
+	0x2f, 0x66, 0x61, 0x69, 0x6c, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0,
+	0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, 
+	0x30, 0x30, 0x20, 0x4f, 0x4b, 0xd, 0xa, 0x53, 0x65, 0x72, 
+	0x76, 0x65, 0x72, 0x3a, 0x20, 0x75, 0x49, 0x50, 0x2f, 0x30, 
+	0x2e, 0x39, 0x20, 0x28, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 
+	0x2f, 0x64, 0x75, 0x6e, 0x6b, 0x65, 0x6c, 0x73, 0x2e, 0x63, 
+	0x6f, 0x6d, 0x2f, 0x61, 0x64, 0x61, 0x6d, 0x2f, 0x75, 0x69, 
+	0x70, 0x2f, 0x29, 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x74, 0x65, 
+	0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 
+	0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0xd, 0xa, 
+	0xd, 0xa, 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, 0x9, 
+	0x3c, 0x68, 0x65, 0x61, 0x64, 0x3e, 0xa, 0x9, 0x9, 0x3c, 
+	0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0xa, 0x9, 0x9, 0x9, 
+	0x4c, 0x61, 0x46, 0x6f, 0x6e, 0x65, 0x72, 0x61, 0x20, 0x46, 
+	0x61, 0x69, 0x6c, 0x73, 0x61, 0x66, 0x65, 0x20, 0x55, 0x49, 
+	0xa, 0x9, 0x9, 0x3c, 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65, 
+	0x3e, 0xa, 0x9, 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0xa, 
+	0x9, 0x9, 0x3c, 0x68, 0x31, 0x3e, 0x46, 0x6c, 0x61, 0x73, 
+	0x68, 0x69, 0x6e, 0x67, 0x20, 0x66, 0x61, 0x69, 0x6c, 0x65, 
+	0x64, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0xa, 0x9, 0x9, 0x45, 
+	0x52, 0x52, 0x4f, 0x52, 0x20, 0x2d, 0x20, 0x74, 0x68, 0x65, 
+	0x20, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x20, 0x79, 0x6f, 0x75, 
+	0x20, 0x75, 0x70, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x20, 
+	0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 
+	0x70, 0x61, 0x73, 0x73, 0x20, 0x76, 0x65, 0x72, 0x69, 0x66, 
+	0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x20, 0x50, 
+	0x6c, 0x65, 0x61, 0x73, 0x65, 0x20, 0x6d, 0x61, 0x6b, 0x65, 
+	0x20, 0x73, 0x75, 0x72, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x75, 
+	0x73, 0x65, 0x20, 0x61, 0x6e, 0x20, 0x6f, 0x66, 0x66, 0x69, 
+	0x63, 0x69, 0x61, 0x6c, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 
+	0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x64, 
+	0x20, 0x62, 0x79, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 
+	0x2f, 0x64, 0x6f, 0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x2e, 
+	0x66, 0x6f, 0x6e, 0x6f, 0x73, 0x66, 0x65, 0x72, 0x61, 0x2e, 
+	0x6f, 0x72, 0x67, 0x2f, 0xa, 0x9, 0x3c, 0x2f, 0x62, 0x6f, 
+	0x64, 0x79, 0x3e, 0xa, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 
+	0x3e, 0xa, };
+
+static const char data_404_html[] = {
+	/* /404.html */
+	0x2f, 0x34, 0x30, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0,
+	0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x34, 
+	0x30, 0x34, 0x20, 0x46, 0x69, 0x6c, 0x65, 0x20, 0x6e, 0x6f, 
+	0x74, 0x20, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0xd, 0xa, 0x53, 
+	0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x20, 0x75, 0x49, 0x50, 
+	0x2f, 0x30, 0x2e, 0x39, 0x20, 0x28, 0x68, 0x74, 0x74, 0x70, 
+	0x3a, 0x2f, 0x2f, 0x64, 0x75, 0x6e, 0x6b, 0x65, 0x6c, 0x73, 
+	0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x64, 0x61, 0x6d, 0x2f, 
+	0x75, 0x69, 0x70, 0x2f, 0x29, 0xd, 0xa, 0x43, 0x6f, 0x6e, 
+	0x74, 0x65, 0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 
+	0x20, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 
+	0xd, 0xa, 0xd, 0xa, 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 
+	0x3c, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x62, 0x67, 0x63, 0x6f, 
+	0x6c, 0x6f, 0x72, 0x3d, 0x22, 0x77, 0x68, 0x69, 0x74, 0x65, 
+	0x22, 0x3e, 0x3c, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3e, 
+	0x3c, 0x68, 0x31, 0x3e, 0x34, 0x30, 0x34, 0x20, 0x2d, 0x20, 
+	0x66, 0x69, 0x6c, 0x65, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x66, 
+	0x6f, 0x75, 0x6e, 0x64, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 
+	0x2f, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x3e, 0x3c, 0x2f, 
+	0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x2f, 0x68, 0x74, 0x6d, 
+	0x6c, 0x3e, };
+
+static const char data_index_html[] = {
+	/* /index.html */
+	0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0,
+	0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, 
+	0x30, 0x30, 0x20, 0x4f, 0x4b, 0xd, 0xa, 0x53, 0x65, 0x72, 
+	0x76, 0x65, 0x72, 0x3a, 0x20, 0x75, 0x49, 0x50, 0x2f, 0x30, 
+	0x2e, 0x39, 0x20, 0x28, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 
+	0x2f, 0x64, 0x75, 0x6e, 0x6b, 0x65, 0x6c, 0x73, 0x2e, 0x63, 
+	0x6f, 0x6d, 0x2f, 0x61, 0x64, 0x61, 0x6d, 0x2f, 0x75, 0x69, 
+	0x70, 0x2f, 0x29, 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x74, 0x65, 
+	0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 
+	0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0xd, 0xa, 
+	0xd, 0xa, 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, 0x9, 
+	0x3c, 0x68, 0x65, 0x61, 0x64, 0x3e, 0xa, 0x9, 0x9, 0x3c, 
+	0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0xa, 0x9, 0x9, 0x9, 
+	0x4c, 0x61, 0x46, 0x6f, 0x6e, 0x65, 0x72, 0x61, 0x20, 0x46, 
+	0x61, 0x69, 0x6c, 0x73, 0x61, 0x66, 0x65, 0x20, 0x55, 0x49, 
+	0xa, 0x9, 0x9, 0x3c, 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65, 
+	0x3e, 0xa, 0x9, 0x3c, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x3e, 
+	0xa, 0x9, 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x73, 0x74, 
+	0x79, 0x6c, 0x65, 0x3d, 0x22, 0x6d, 0x61, 0x72, 0x67, 0x69, 
+	0x6e, 0x3a, 0x20, 0x30, 0x70, 0x74, 0x20, 0x61, 0x75, 0x74, 
+	0x6f, 0x3b, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3a, 
+	0x31, 0x30, 0x30, 0x25, 0x3b, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 
+	0x72, 0x3a, 0x20, 0x23, 0x30, 0x30, 0x30, 0x3b, 0x20, 0x62, 
+	0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 
+	0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, 0x66, 0x62, 
+	0x62, 0x30, 0x33, 0x34, 0x3b, 0x22, 0x3e, 0xa, 0x9, 0x9, 
+	0x3c, 0x68, 0x31, 0x3e, 0x4c, 0x61, 0x46, 0x6f, 0x6e, 0x65, 
+	0x72, 0x61, 0x20, 0x46, 0x61, 0x69, 0x6c, 0x73, 0x61, 0x66, 
+	0x65, 0x20, 0x55, 0x49, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0xa, 
+	0x9, 0x9, 0x3c, 0x66, 0x6f, 0x72, 0x6d, 0x20, 0x6d, 0x65, 
+	0x74, 0x68, 0x6f, 0x64, 0x3d, 0x22, 0x70, 0x6f, 0x73, 0x74, 
+	0x22, 0x20, 0x65, 0x6e, 0x63, 0x74, 0x79, 0x70, 0x65, 0x3d, 
+	0x22, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x61, 0x72, 0x74, 
+	0x2f, 0x66, 0x6f, 0x72, 0x6d, 0x2d, 0x64, 0x61, 0x74, 0x61, 
+	0x22, 0x3e, 0xa, 0x9, 0x9, 0x9, 0x3c, 0x69, 0x6e, 0x70, 
+	0x75, 0x74, 0x20, 0x74, 0x79, 0x70, 0x65, 0x3d, 0x66, 0x69, 
+	0x6c, 0x65, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x3d, 0x66, 0x69, 
+	0x72, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x3e, 0xa, 0x9, 0x9, 
+	0x9, 0x3c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x20, 0x74, 0x79, 
+	0x70, 0x65, 0x3d, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x74, 0x3e, 
+	0xa, 0x9, 0x9, 0x3c, 0x2f, 0x66, 0x6f, 0x72, 0x6d, 0x3e, 
+	0xa, 0x9, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0xa, 
+	0x3c, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, };
+
+static const char data_flash_html[] = {
+	/* /flash.html */
+	0x2f, 0x66, 0x6c, 0x61, 0x73, 0x68, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0,
+	0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x30, 0x20, 0x32, 
+	0x30, 0x30, 0x20, 0x4f, 0x4b, 0xd, 0xa, 0x53, 0x65, 0x72, 
+	0x76, 0x65, 0x72, 0x3a, 0x20, 0x75, 0x49, 0x50, 0x2f, 0x30, 
+	0x2e, 0x39, 0x20, 0x28, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 
+	0x2f, 0x64, 0x75, 0x6e, 0x6b, 0x65, 0x6c, 0x73, 0x2e, 0x63, 
+	0x6f, 0x6d, 0x2f, 0x61, 0x64, 0x61, 0x6d, 0x2f, 0x75, 0x69, 
+	0x70, 0x2f, 0x29, 0xd, 0xa, 0x43, 0x6f, 0x6e, 0x74, 0x65, 
+	0x6e, 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x3a, 0x20, 0x74, 
+	0x65, 0x78, 0x74, 0x2f, 0x68, 0x74, 0x6d, 0x6c, 0xd, 0xa, 
+	0xd, 0xa, 0x3c, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0xa, 0x9, 
+	0x3c, 0x68, 0x65, 0x61, 0x64, 0x3e, 0xa, 0x9, 0x9, 0x3c, 
+	0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0xa, 0x9, 0x9, 0x9, 
+	0x4c, 0x61, 0x46, 0x6f, 0x6e, 0x65, 0x72, 0x61, 0x20, 0x46, 
+	0x61, 0x69, 0x6c, 0x73, 0x61, 0x66, 0x65, 0x20, 0x55, 0x49, 
+	0xa, 0x9, 0x9, 0x3c, 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65, 
+	0x3e, 0xa, 0x9, 0x3c, 0x2f, 0x68, 0x65, 0x61, 0x64, 0x3e, 
+	0xa, 0x9, 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x73, 0x74, 
+	0x79, 0x6c, 0x65, 0x3d, 0x22, 0x6d, 0x61, 0x72, 0x67, 0x69, 
+	0x6e, 0x3a, 0x20, 0x30, 0x70, 0x74, 0x20, 0x61, 0x75, 0x74, 
+	0x6f, 0x3b, 0x20, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3a, 
+	0x31, 0x30, 0x30, 0x25, 0x3b, 0x20, 0x63, 0x6f, 0x6c, 0x6f, 
+	0x72, 0x3a, 0x20, 0x23, 0x30, 0x30, 0x30, 0x3b, 0x20, 0x62, 
+	0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 
+	0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x20, 0x23, 0x66, 0x62, 
+	0x62, 0x30, 0x33, 0x34, 0x3b, 0x22, 0x3e, 0xa, 0x9, 0x9, 
+	0x3c, 0x68, 0x31, 0x3e, 0x46, 0x6c, 0x61, 0x73, 0x68, 0x69, 
+	0x6e, 0x67, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0xa, 0x9, 0x9, 
+	0x54, 0x68, 0x65, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 
+	0x20, 0x69, 0x73, 0x20, 0x6e, 0x6f, 0x77, 0x20, 0x74, 0x72, 
+	0x79, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x20, 0x66, 0x6c, 
+	0x61, 0x73, 0x68, 0x2e, 0x20, 0x49, 0x66, 0x20, 0x74, 0x68, 
+	0x65, 0x72, 0x65, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x70, 
+	0x72, 0x6f, 0x62, 0x6c, 0x65, 0x6d, 0x2c, 0x20, 0x74, 0x68, 
+	0x65, 0x20, 0x6c, 0x65, 0x64, 0x73, 0x20, 0x77, 0x69, 0x6c, 
+	0x6c, 0x20, 0x73, 0x74, 0x61, 0x72, 0x74, 0x20, 0x74, 0x6f, 
+	0x20, 0x62, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0xa, 0xa, 0x9, 
+	0x9, 0x41, 0x66, 0x74, 0x65, 0x72, 0x20, 0x61, 0x20, 0x73, 
+	0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x66, 0x75, 0x6c, 0x6c, 
+	0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x74, 0x68, 
+	0x65, 0x20, 0x62, 0x6f, 0x78, 0x20, 0x77, 0x69, 0x6c, 0x6c, 
+	0x20, 0x72, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0xa, 0x9, 0x3c, 
+	0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0xa, 0x3c, 0x2f, 0x68, 
+	0x74, 0x6d, 0x6c, 0x3e, 0xa, };
+
+const struct fsdata_file file_flashing_html[] = {{NULL, data_flashing_html, data_flashing_html + 15, sizeof(data_flashing_html) - 15}};
+
+const struct fsdata_file file_fail_html[] = {{file_flashing_html, data_fail_html, data_fail_html + 11, sizeof(data_fail_html) - 11}};
+
+const struct fsdata_file file_404_html[] = {{file_fail_html, data_404_html, data_404_html + 10, sizeof(data_404_html) - 10}};
+
+const struct fsdata_file file_index_html[] = {{file_404_html, data_index_html, data_index_html + 12, sizeof(data_index_html) - 12}};
+
+const struct fsdata_file file_flash_html[] = {{file_index_html, data_flash_html, data_flash_html + 12, sizeof(data_flash_html) - 12}};
+
+#define FS_ROOT file_flash_html
+
+#define FS_NUMFILES 5
\ No newline at end of file
--- /dev/null
+++ b/net/uip-0.9/fsdata.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2001, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE 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 INSTITUTE 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. 
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: fsdata.h,v 1.4.2.1 2003/10/04 22:54:06 adam Exp $
+ */
+#ifndef __FSDATA_H__
+#define __FSDATA_H__
+
+#include "uipopt.h"
+
+struct fsdata_file {
+  const struct fsdata_file *next;
+  const char *name;
+  const char *data;
+  const int len;
+#ifdef FS_STATISTICS
+#if FS_STATISTICS == 1
+  u16_t count;
+#endif /* FS_STATISTICS */
+#endif /* FS_STATISTICS */
+};
+
+struct fsdata_file_noconst {
+  struct fsdata_file *next;
+  char *name;
+  char *data;
+  int len;
+#ifdef FS_STATISTICS
+#if FS_STATISTICS == 1
+  u16_t count;
+#endif /* FS_STATISTICS */
+#endif /* FS_STATISTICS */
+};
+
+#endif /* __FSDATA_H__ */
--- /dev/null
+++ b/net/uip-0.9/fs.h
@@ -0,0 +1,80 @@
+/**
+ * \addtogroup httpd
+ * @{
+ */
+
+/**
+ * \file
+ * HTTP server read-only file system header file.
+ * \author Adam Dunkels <adam@dunkels.com>
+ */
+ 
+/*
+ * Copyright (c) 2001, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE 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 INSTITUTE 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. 
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ * 
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: fs.h,v 1.6.2.3 2003/10/07 13:22:27 adam Exp $
+ */
+#ifndef __FS_H__
+#define __FS_H__
+
+#include "uip.h"
+
+/**
+ * An open file in the read-only file system.
+ */
+struct fs_file {
+  char *data;  /**< The actual file data. */
+  int len;     /**< The length of the file data. */
+};
+
+/**
+ * Open a file in the read-only file system.
+ *
+ * \param name The name of the file.
+ *
+ * \param file The file pointer, which must be allocated by caller and
+ * will be filled in by the function.
+ */
+int fs_open(const char *name, struct fs_file *file);
+
+#ifdef FS_STATISTICS
+#if FS_STATISTICS == 1  
+u16_t fs_count(char *name);
+#endif /* FS_STATISTICS */
+#endif /* FS_STATISTICS */
+
+/**
+ * Initialize the read-only file system.
+ */
+void fs_init(void);
+
+#endif /* __FS_H__ */
--- /dev/null
+++ b/net/uip-0.9/httpd.c
@@ -0,0 +1,278 @@
+#include "uip.h"
+#include "httpd.h"
+#include "fs.h"
+#include "fsdata.h"
+#include <asm/addrspace.h>
+
+#define HTTP_NONE		0
+#define HTTP_FILE		1
+#define HTTP_FIRMWARE		2
+
+#define PRINT(x) printf("%s", x)
+#define PRINTLN(x) printf("%s\n", x)
+
+extern unsigned long do_http_tmp_address(void);
+
+struct httpd_state *hs;
+
+extern const struct fsdata_file file_index_html;
+extern const struct fsdata_file file_404_html;
+extern const struct fsdata_file file_flash_html;
+extern int httpd_upload_complete;
+extern unsigned char *httpd_upload_data;
+unsigned char *upload_data;
+extern ulong		NetBootFileXferSize;
+int upload_running = 0;
+
+#define ISO_G        0x47
+#define ISO_E        0x45
+#define ISO_T        0x54
+#define ISO_P        0x50
+#define ISO_O        0x4f
+#define ISO_S        0x53
+#define ISO_T        0x54
+#define ISO_slash    0x2f
+#define ISO_c        0x63
+#define ISO_g        0x67
+#define ISO_i        0x69
+#define ISO_space    0x20
+#define ISO_nl       0x0a
+#define ISO_cr       0x0d
+#define ISO_a        0x61
+#define ISO_t        0x74
+#define ISO_hash     0x23
+#define ISO_period   0x2e
+
+static char eol[3] = { 0x0d, 0x0a, 0x00 };
+static char eol2[5] = { 0x0d, 0x0a, 0x0d, 0x0a, 0x00 };
+static char boundary[128];
+static int boundary_len = 0;
+
+/* we use this so that we can do without the ctype library */
+#define is_digit(c)	((c) >= '0' && (c) <= '9')
+static int atoi(const char *s)
+{
+	int i=0;
+
+	while (is_digit(*s))
+		i = i*10 + *(s++) - '0';
+	return i;
+}
+
+void
+httpd_init(void)
+{
+	fs_init();
+	uip_listen(HTONS(80));
+}
+
+void
+httpd_appcall(void)
+{
+	struct fs_file fsfile;
+	u8_t i;
+	switch(uip_conn->lport) {
+	case HTONS(80):
+		hs = (struct httpd_state *)(uip_conn->appstate);
+		if(uip_connected())
+		{
+			hs->state = HTTP_NONE;
+			hs->count = 0;
+			return;
+		} else if(uip_poll())
+		{
+			if(hs->count++ >= 1000) {
+				uip_abort();
+			}
+			return;
+		} else if(uip_newdata() && hs->state == HTTP_NONE)
+		{
+			if(uip_appdata[0] == ISO_G &&
+				uip_appdata[1] == ISO_E &&
+				uip_appdata[2] == ISO_T &&
+				uip_appdata[3] == ISO_space)
+			{
+				hs->state = HTTP_FILE;
+			}
+			if(uip_appdata[0] == ISO_P &&
+				uip_appdata[1] == ISO_O &&
+				uip_appdata[2] == ISO_S &&
+				uip_appdata[3] == ISO_T &&
+				uip_appdata[4] == ISO_space)
+			{
+				hs->state = HTTP_FIRMWARE;
+			}
+			if(hs->state == HTTP_NONE)
+			{
+				uip_abort();
+				return;
+			}
+			if(hs->state == HTTP_FILE)
+			{
+				for(i = 4; i < 40; ++i)
+				{
+					if(uip_appdata[i] == ISO_space ||
+						uip_appdata[i] == ISO_cr ||
+						uip_appdata[i] == ISO_nl)
+					{
+						uip_appdata[i] = 0;
+						break;
+					}
+				}
+
+				PRINT("request for file ");
+				PRINTLN(&uip_appdata[4]);
+				if(uip_appdata[4] == ISO_slash &&
+					uip_appdata[5] == 0)
+				{
+					fs_open(file_index_html.name, &fsfile);
+				} else {
+					if(!fs_open((const char *)&uip_appdata[4], &fsfile))
+					{
+						PRINTLN("couldn't open file");
+						fs_open(file_index_html.name, &fsfile);
+					}
+				}
+				hs->script = 0;
+				hs->state = HTTP_FILE;
+				hs->dataptr = fsfile.data;
+				hs->count = fsfile.len;
+			}
+			if(hs->state == HTTP_FIRMWARE)
+			{
+				unsigned char *start = (unsigned char*)uip_appdata;
+				char *clen = strstr(start, "Content-Length:");
+				int len = 0;
+				unsigned char *next, *end;
+				unsigned char *boundary_start;
+				int i;
+				uip_appdata[uip_len] = '\0';
+				if(clen)
+				{
+					clen += sizeof("Content-Length:");
+					next = strstr(clen, eol);
+					if(next)
+					{
+						len = atoi(clen);
+						next++;
+						printf("expecting %d bytes\n", len);
+						upload_data = httpd_upload_data = (unsigned char *)do_http_tmp_address();
+						printf("received data will be stored at 0x%08X\n", upload_data);
+						if(!upload_data)
+						{
+							printf("failed to allocate memory\n");
+							uip_close();
+							return;
+						}
+					} else {
+						uip_close();
+						return;
+					}
+				}
+				if(len < 4 * 1024)
+				{
+					uip_close();
+					return;
+				}
+				boundary_start = strstr(next, "---");
+				if(!boundary_start)
+				{
+					uip_close();
+					return;
+				}
+				end = strstr(boundary_start, eol);
+				if(!eol)
+				{
+					uip_close();
+					return;
+				}
+				boundary_len = end - boundary_start;
+				memcpy(boundary, boundary_start, boundary_len);
+				boundary[boundary_len] = 0;
+				next = strstr(boundary_start, "name=\"firmware\";");
+				if(!next)
+				{
+					uip_close();
+					return;
+				}
+				next = strstr(next, eol2);
+				if(!next)
+				{
+					printf("could not find start of data\n");
+					uip_close();
+					return;
+				}
+				next += 4;
+				hs->script = 0;
+				hs->state = HTTP_FIRMWARE;
+				hs->upload = uip_len - (next - start);
+				hs->upload_total = len - (int)(next - boundary_start);
+				hs->upload_total -= (strlen(boundary) + 6);
+				//printf("storing %d bytes at %p\n", (int)hs->upload, upload_data);
+				for(i = 0; i < hs->upload; i++)
+					upload_data[i] = next[i];
+				upload_data += (int)hs->upload;
+				printf("%d / %d\n", (int)hs->upload, hs->upload_total);
+				uip_slen = 0;
+				return;
+			}
+		}
+
+		if(hs->state == HTTP_FIRMWARE)
+		{
+			if(uip_newdata())
+			{
+				int i;
+				hs->count = 0;
+				uip_appdata[uip_len] = '\0';
+				hs->upload += uip_len;
+				//printf("storing %d bytes at %p\n", uip_len, upload_data);
+				printf("%d / %d\n", (int)hs->upload, hs->upload_total);
+				for(i = 0; i < uip_len; i++)
+					upload_data[i] = uip_appdata[i];
+				upload_data += uip_len;
+				uip_slen = 0;
+				if(hs->upload >= hs->upload_total)
+				{
+					upload_running = 1;
+					NetBootFileXferSize = hs->upload_total;
+					fs_open(file_flash_html.name, &fsfile);
+					hs->script = 0;
+					hs->state = HTTP_FILE;
+					hs->dataptr = fsfile.data;
+					hs->count = fsfile.len;
+				}
+			}
+		}
+		if(hs->state == HTTP_FILE)
+		{
+			if(uip_acked())
+			{
+				if(hs->count >= uip_conn->len)
+				{
+					hs->count -= uip_conn->len;
+					hs->dataptr += uip_conn->len;
+				} else {
+					hs->count = 0;
+				}
+				if(hs->count == 0)
+				{
+					if(upload_running)
+					{
+						int i;
+						httpd_upload_complete = 1;
+					//	for(i = 0; i < hs->upload_total; i++)
+					//		printf("%c", httpd_upload_data[i]);
+					}
+					uip_close();
+				}
+			}
+			uip_send(hs->dataptr, hs->count);
+		}
+		break;
+
+	default:
+		uip_abort();
+		break;
+	}
+}
--- /dev/null
+++ b/net/uip-0.9/httpd.h
@@ -0,0 +1,83 @@
+/**
+ * \addtogroup httpd
+ * @{
+ */
+
+/**
+ * \file
+ * HTTP server header file.
+ * \author Adam Dunkels <adam@dunkels.com>
+ */
+
+/*
+ * Copyright (c) 2001, Adam Dunkels.
+ * 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. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.  
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.  
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: httpd.h,v 1.4.2.3 2003/10/06 22:56:44 adam Exp $
+ *
+ */
+
+#ifndef __HTTPD_H__
+#define __HTTPD_H__
+
+void httpd_init(void);
+void httpd_appcall(void);
+
+/* UIP_APPCALL: the name of the application function. This function
+   must return void and take no arguments (i.e., C type "void
+   appfunc(void)"). */
+#ifndef UIP_APPCALL
+#define UIP_APPCALL		httpd_appcall
+#endif
+
+struct httpd_state {
+  u8_t state;
+  u16_t count;
+  char *dataptr;
+  char *script;
+  unsigned int upload;
+  unsigned int upload_total;
+};
+
+
+/* UIP_APPSTATE_SIZE: The size of the application-specific state
+   stored in the uip_conn structure. */
+#ifndef UIP_APPSTATE_SIZE
+#define UIP_APPSTATE_SIZE (sizeof(struct httpd_state))
+#endif
+
+#define FS_STATISTICS 1
+
+extern struct httpd_state *hs;
+
+
+/* we copy the data to RAM+10MB */
+#define TMP_DATA 0x8A100000
+
+#endif /* __HTTPD_H__ */
--- /dev/null
+++ b/net/uip-0.9/main.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2001-2003, Adam Dunkels.
+ * 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. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.  
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.  
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: main.c,v 1.10.2.1 2003/10/04 22:54:17 adam Exp $
+ *
+ */
+
+
+#include "uip.h"
+#include "uip_arp.h"
+#include "tapdev.h"
+#include "httpd.h"
+
+#define BUF ((struct uip_eth_hdr *)&uip_buf[0])
+
+#ifndef NULL
+#define NULL (void *)0
+#endif /* NULL */
+
+/*-----------------------------------------------------------------------------------*/
+int
+main(void)
+{
+	u8_t i, arptimer;
+	tapdev_init();
+	uip_init();
+	httpd_init();
+	arptimer = 0;
+	while(1) {
+		uip_len = tapdev_read();
+		if(uip_len == 0) {
+			for(i = 0; i < UIP_CONNS; i++) {
+				uip_periodic(i);
+				if(uip_len > 0) {
+					uip_arp_out();
+					tapdev_send();
+				}
+			}
+
+			if(++arptimer == 20) {
+				uip_arp_timer();
+				arptimer = 0;
+			}
+		} else {
+			if(BUF->type == htons(UIP_ETHTYPE_IP)) {
+				uip_arp_ipin();
+				uip_input();
+				if(uip_len > 0) {
+					uip_arp_out();
+					tapdev_send();
+				}
+			} else if(BUF->type == htons(UIP_ETHTYPE_ARP)) {
+				uip_arp_arpin();
+				if(uip_len > 0) {
+					tapdev_send();
+				}
+			}
+		}
+	}
+	return 0;
+}
--- /dev/null
+++ b/net/uip-0.9/Makefile
@@ -0,0 +1,54 @@
+# Copyright (c) 2001, Adam Dunkels.
+# 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 Adam Dunkels.
+# 4. The name of the author may not be used to endorse or promote
+#    products derived from this software without specific prior
+#    written permission.  
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.  
+#
+# This file is part of the uIP TCP/IP stack.
+#
+# $Id: Makefile,v 1.8.2.2 2003/10/04 22:54:17 adam Exp $
+#
+
+CC=gcc
+CFLAGS=-Wall -fpack-struct -DDUMP=0
+
+all: uip
+
+uip: uip.o uip_arch.o tapdev.o httpd.o main.o fs.o uip_arp.o
+	$(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@
+
+%.o: %.c
+	$(CC) $(CFLAGS) -c  $^ -o $@
+
+clean:
+	rm -f *.o *~ *core uip
+
+
+
+
+
+
--- /dev/null
+++ b/net/uip-0.9/tapdev.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2001, Swedish Institute of Computer Science.
+ * 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. Neither the name of the Institute nor the names of its contributors 
+ *    may be used to endorse or promote products derived from this software 
+ *    without specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE 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 INSTITUTE 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. 
+ *
+ * Author: Adam Dunkels <adam@sics.se>
+ *
+ * $Id: tapdev.c,v 1.7.2.1 2003/10/07 13:23:19 adam Exp $
+ */
+
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+
+#ifdef linux
+#include <sys/ioctl.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#define DEVTAP "/dev/net/tun"
+#else  /* linux */
+#define DEVTAP "/dev/tap0"
+#endif /* linux */
+
+#include "uip.h"
+
+static int fd;
+
+static unsigned long lasttime;
+static struct timezone tz;
+
+/*-----------------------------------------------------------------------------------*/
+void
+tapdev_init(void)
+{
+  char buf[1024];
+  
+  fd = open(DEVTAP, O_RDWR);
+  if(fd == -1) {
+    perror("tapdev: tapdev_init: open");
+    exit(1);
+  }
+
+#ifdef linux
+  {
+    struct ifreq ifr;
+    memset(&ifr, 0, sizeof(ifr));
+    ifr.ifr_flags = IFF_TAP|IFF_NO_PI;
+    if (ioctl(fd, TUNSETIFF, (void *) &ifr) < 0) {
+      perror(buf);
+      exit(1);
+    }
+  }
+#endif /* Linux */
+
+  snprintf(buf, sizeof(buf), "ifconfig tap0 inet %d.%d.%d.%d",
+	   UIP_DRIPADDR0, UIP_DRIPADDR1, UIP_DRIPADDR2, UIP_DRIPADDR3);
+  system(buf);
+
+  lasttime = 0;
+}
+
+void dump_mem(int type, int len)
+{
+#if DUMP == 1
+	int i;
+	for(i = 0; i < len; i++)
+		printf("%c", uip_buf[i]);
+	if(type)
+	{
+		printf("\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01");
+		printf("\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01");
+	} else {
+		printf("\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02");
+		printf("\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02");
+	}
+	fflush(stdout);
+#endif
+}
+
+/*-----------------------------------------------------------------------------------*/
+unsigned int
+tapdev_read(void)
+{
+  fd_set fdset;
+  struct timeval tv, now;
+  int ret;
+  
+  if(lasttime >= 500000) {
+    lasttime = 0;
+    return 0;
+  }
+  
+  tv.tv_sec = 0;
+  tv.tv_usec = 500000 - lasttime;
+
+
+  FD_ZERO(&fdset);
+  FD_SET(fd, &fdset);
+
+  gettimeofday(&now, &tz);  
+  ret = select(fd + 1, &fdset, NULL, NULL, &tv);
+  if(ret == 0) {
+    lasttime = 0;    
+    return 0;
+  } 
+  ret = read(fd, uip_buf, UIP_BUFSIZE);  
+  if(ret == -1) {
+    perror("tap_dev: tapdev_read: read");
+  }
+  gettimeofday(&tv, &tz);
+  lasttime += (tv.tv_sec - now.tv_sec) * 1000000 + (tv.tv_usec - now.tv_usec);
+  dump_mem(0, ret);
+  return ret;
+}
+/*-----------------------------------------------------------------------------------*/
+void
+tapdev_send(void)
+{
+  int ret;
+  struct iovec iov[2];
+  
+#ifdef linux
+  {
+    char tmpbuf[UIP_BUFSIZE];
+    int i;
+
+    for(i = 0; i < 40 + UIP_LLH_LEN; i++) {
+      tmpbuf[i] = uip_buf[i];
+    }
+    
+    for(; i < uip_len; i++) {
+      tmpbuf[i] = uip_appdata[i - 40 - UIP_LLH_LEN];
+    }
+    
+    ret = write(fd, tmpbuf, uip_len);
+  }  
+#else 
+
+  if(uip_len < 40 + UIP_LLH_LEN) {
+    ret = write(fd, uip_buf, uip_len + UIP_LLH_LEN);
+  } else {
+    iov[0].iov_base = uip_buf;
+    iov[0].iov_len = 40 + UIP_LLH_LEN;
+    iov[1].iov_base = (char *)uip_appdata;
+    iov[1].iov_len = uip_len - (40 + UIP_LLH_LEN);  
+    
+    ret = writev(fd, iov, 2);
+  }
+#endif
+  dump_mem(1, ret);
+
+  if(ret == -1) {
+    perror("tap_dev: tapdev_send: writev");
+    exit(1);
+  }
+}  
+/*-----------------------------------------------------------------------------------*/
--- /dev/null
+++ b/net/uip-0.9/tapdev.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2001, Adam Dunkels.
+ * 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. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.  
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.  
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: tapdev.h,v 1.1.2.1 2003/10/04 22:54:17 adam Exp $
+ *
+ */
+
+#ifndef __TAPDEV_H__
+#define __TAPDEV_H__
+
+void tapdev_init(void);
+unsigned int tapdev_read(void);
+void tapdev_send(void);
+
+#endif /* __TAPDEV_H__ */
--- /dev/null
+++ b/net/uip-0.9/uip_arch.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2001, Adam Dunkels.
+ * 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. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.  
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.  
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: uip_arch.c,v 1.2.2.1 2003/10/04 22:54:17 adam Exp $
+ *
+ */
+
+
+#include "uip.h"
+#include "uip_arch.h"
+
+#define BUF ((uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
+#define IP_PROTO_TCP    6
+
+/*-----------------------------------------------------------------------------------*/
+void
+uip_add32(u8_t *op32, u16_t op16)
+{
+  
+  uip_acc32[3] = op32[3] + (op16 & 0xff);
+  uip_acc32[2] = op32[2] + (op16 >> 8);
+  uip_acc32[1] = op32[1];
+  uip_acc32[0] = op32[0];
+  
+  if(uip_acc32[2] < (op16 >> 8)) {
+    ++uip_acc32[1];    
+    if(uip_acc32[1] == 0) {
+      ++uip_acc32[0];
+    }
+  }
+  
+  
+  if(uip_acc32[3] < (op16 & 0xff)) {
+    ++uip_acc32[2];  
+    if(uip_acc32[2] == 0) {
+      ++uip_acc32[1];    
+      if(uip_acc32[1] == 0) {
+	++uip_acc32[0];
+      }
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+u16_t
+uip_chksum(u16_t *sdata, u16_t len)
+{
+  u16_t acc;
+  
+  for(acc = 0; len > 1; len -= 2) {
+    acc += *sdata;
+    if(acc < *sdata) {
+      /* Overflow, so we add the carry to acc (i.e., increase by
+         one). */
+      ++acc;
+    }
+    ++sdata;
+  }
+
+  /* add up any odd byte */
+  if(len == 1) {
+    acc += htons(((u16_t)(*(u8_t *)sdata)) << 8);
+    if(acc < htons(((u16_t)(*(u8_t *)sdata)) << 8)) {
+      ++acc;
+    }
+  }
+
+  return acc;
+}
+/*-----------------------------------------------------------------------------------*/
+u16_t
+uip_ipchksum(void)
+{
+  return uip_chksum((u16_t *)&uip_buf[UIP_LLH_LEN], 20);
+}
+/*-----------------------------------------------------------------------------------*/
+u16_t
+uip_tcpchksum(void)
+{
+  u16_t hsum, sum;
+
+  
+  /* Compute the checksum of the TCP header. */
+  hsum = uip_chksum((u16_t *)&uip_buf[20 + UIP_LLH_LEN], 20);
+
+  /* Compute the checksum of the data in the TCP packet and add it to
+     the TCP header checksum. */
+  sum = uip_chksum((u16_t *)uip_appdata,
+		   (u16_t)(((((u16_t)(BUF->len[0]) << 8) + BUF->len[1]) - 40)));
+
+  if((sum += hsum) < hsum) {
+    ++sum;
+  }
+  
+  if((sum += BUF->srcipaddr[0]) < BUF->srcipaddr[0]) {
+    ++sum;
+  }
+  if((sum += BUF->srcipaddr[1]) < BUF->srcipaddr[1]) {
+    ++sum;
+  }
+  if((sum += BUF->destipaddr[0]) < BUF->destipaddr[0]) {
+    ++sum;
+  }
+  if((sum += BUF->destipaddr[1]) < BUF->destipaddr[1]) {
+    ++sum;
+  }
+  if((sum += (u16_t)htons((u16_t)IP_PROTO_TCP)) < (u16_t)htons((u16_t)IP_PROTO_TCP)) {
+    ++sum;
+  }
+
+  hsum = (u16_t)htons((((u16_t)(BUF->len[0]) << 8) + BUF->len[1]) - 20);
+  
+  if((sum += hsum) < hsum) {
+    ++sum;
+  }
+  
+  return sum;
+}
+/*-----------------------------------------------------------------------------------*/
--- /dev/null
+++ b/net/uip-0.9/uip_arch.h
@@ -0,0 +1,130 @@
+/**
+ * \defgroup uiparch Architecture specific uIP functions
+ * @{
+ *
+ * The functions in the architecture specific module implement the IP
+ * check sum and 32-bit additions.
+ *
+ * The IP checksum calculation is the most computationally expensive
+ * operation in the TCP/IP stack and it therefore pays off to
+ * implement this in efficient assembler. The purpose of the uip-arch
+ * module is to let the checksum functions to be implemented in
+ * architecture specific assembler.
+ *
+ */
+
+/**
+ * \file
+ * Declarations of architecture specific functions.
+ * \author Adam Dunkels <adam@dunkels.com>
+ */
+
+/*
+ * Copyright (c) 2001, Adam Dunkels.
+ * 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. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.  
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.  
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: uip_arch.h,v 1.1.2.2 2003/10/06 15:10:22 adam Exp $
+ *
+ */
+
+#ifndef __UIP_ARCH_H__
+#define __UIP_ARCH_H__
+
+#include "uip.h"
+
+/**
+ * Carry out a 32-bit addition.
+ *
+ * Because not all architectures for which uIP is intended has native
+ * 32-bit arithmetic, uIP uses an external C function for doing the
+ * required 32-bit additions in the TCP protocol processing. This
+ * function should add the two arguments and place the result in the
+ * global variable uip_acc32.
+ *
+ * \note The 32-bit integer pointed to by the op32 parameter and the
+ * result in the uip_acc32 variable are in network byte order (big
+ * endian).
+ *
+ * \param op32 A pointer to a 4-byte array representing a 32-bit
+ * integer in network byte order (big endian).
+ *
+ * \param op16 A 16-bit integer in host byte order.
+ */
+void uip_add32(u8_t *op32, u16_t op16);
+
+/**
+ * Calculate the Internet checksum over a buffer.
+ *
+ * The Internet checksum is the one's complement of the one's
+ * complement sum of all 16-bit words in the buffer.
+ *
+ * See RFC1071.
+ *
+ * \note This function is not called in the current version of uIP,
+ * but future versions might make use of it.
+ *
+ * \param buf A pointer to the buffer over which the checksum is to be
+ * computed.
+ *
+ * \param len The length of the buffer over which the checksum is to
+ * be computed.
+ *
+ * \return The Internet checksum of the buffer.
+ */
+u16_t uip_chksum(u16_t *buf, u16_t len);
+
+/**
+ * Calculate the IP header checksum of the packet header in uip_buf.
+ *
+ * The IP header checksum is the Internet checksum of the 20 bytes of
+ * the IP header.
+ *
+ * \return The IP header checksum of the IP header in the uip_buf
+ * buffer.
+ */
+u16_t uip_ipchksum(void);
+
+/**
+ * Calculate the TCP checksum of the packet in uip_buf and uip_appdata.
+ *
+ * The TCP checksum is the Internet checksum of data contents of the
+ * TCP segment, and a pseudo-header as defined in RFC793.
+ *
+ * \note The uip_appdata pointer that points to the packet data may
+ * point anywhere in memory, so it is not possible to simply calculate
+ * the Internet checksum of the contents of the uip_buf buffer.
+ *
+ * \return The TCP checksum of the TCP segment in uip_buf and pointed
+ * to by uip_appdata.
+ */
+u16_t uip_tcpchksum(void);
+
+/** @} */
+
+#endif /* __UIP_ARCH_H__ */
--- /dev/null
+++ b/net/uip-0.9/uip_arp.c
@@ -0,0 +1,421 @@
+/**
+ * \addtogroup uip
+ * @{
+ */
+
+/**
+ * \defgroup uiparp uIP Address Resolution Protocol
+ * @{
+ * 
+ * The Address Resolution Protocol ARP is used for mapping between IP
+ * addresses and link level addresses such as the Ethernet MAC
+ * addresses. ARP uses broadcast queries to ask for the link level
+ * address of a known IP address and the host which is configured with
+ * the IP address for which the query was meant, will respond with its
+ * link level address.
+ *
+ * \note This ARP implementation only supports Ethernet.
+ */
+ 
+/**
+ * \file
+ * Implementation of the ARP Address Resolution Protocol.
+ * \author Adam Dunkels <adam@dunkels.com>
+ *
+ */
+
+/*
+ * Copyright (c) 2001-2003, Adam Dunkels.
+ * 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. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.  
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.  
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: uip_arp.c,v 1.7.2.3 2003/10/06 22:42:30 adam Exp $
+ *
+ */
+
+
+#include "uip_arp.h"
+
+struct arp_hdr {
+  struct uip_eth_hdr ethhdr;
+  u16_t hwtype;
+  u16_t protocol;
+  u8_t hwlen;
+  u8_t protolen;
+  u16_t opcode;
+  struct uip_eth_addr shwaddr;
+  u16_t sipaddr[2];
+  struct uip_eth_addr dhwaddr;
+  u16_t dipaddr[2]; 
+};
+
+struct ethip_hdr {
+  struct uip_eth_hdr ethhdr;
+  /* IP header. */
+  u8_t vhl,
+    tos,          
+    len[2],       
+    ipid[2],        
+    ipoffset[2],  
+    ttl,          
+    proto;     
+  u16_t ipchksum;
+  u16_t srcipaddr[2], 
+    destipaddr[2];
+};
+
+#define ARP_REQUEST 1
+#define ARP_REPLY   2
+
+#define ARP_HWTYPE_ETH 1
+
+struct arp_entry {
+  u16_t ipaddr[2];
+  struct uip_eth_addr ethaddr;
+  u8_t time;
+};
+
+struct uip_eth_addr uip_ethaddr = {{UIP_ETHADDR0,
+				    UIP_ETHADDR1,
+				    UIP_ETHADDR2,
+				    UIP_ETHADDR3,
+				    UIP_ETHADDR4,
+				    UIP_ETHADDR5}};
+
+static struct arp_entry arp_table[UIP_ARPTAB_SIZE];
+static u16_t ipaddr[2];
+static u8_t i, c;
+
+static u8_t arptime;
+static u8_t tmpage;
+
+#define BUF   ((struct arp_hdr *)&uip_buf[0])
+#define IPBUF ((struct ethip_hdr *)&uip_buf[0])
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Initialize the ARP module.
+ *
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+uip_arp_init(void)
+{
+  for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
+    memset(arp_table[i].ipaddr, 0, 4);
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Periodic ARP processing function.
+ *
+ * This function performs periodic timer processing in the ARP module
+ * and should be called at regular intervals. The recommended interval
+ * is 10 seconds between the calls.
+ *
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+uip_arp_timer(void)
+{
+  struct arp_entry *tabptr;
+  
+  ++arptime;
+  for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
+    tabptr = &arp_table[i];
+    if((tabptr->ipaddr[0] | tabptr->ipaddr[1]) != 0 &&
+       arptime - tabptr->time >= UIP_ARP_MAXAGE) {
+      memset(tabptr->ipaddr, 0, 4);
+    }
+  }
+
+}
+/*-----------------------------------------------------------------------------------*/
+static void
+uip_arp_update(u16_t *ipaddr, struct uip_eth_addr *ethaddr)
+{
+  register struct arp_entry *tabptr;
+  /* Walk through the ARP mapping table and try to find an entry to
+     update. If none is found, the IP -> MAC address mapping is
+     inserted in the ARP table. */
+  for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
+
+    tabptr = &arp_table[i];
+    /* Only check those entries that are actually in use. */
+    if(tabptr->ipaddr[0] != 0 &&
+       tabptr->ipaddr[1] != 0) {
+
+      /* Check if the source IP address of the incoming packet matches
+         the IP address in this ARP table entry. */
+      if(ipaddr[0] == tabptr->ipaddr[0] &&
+	 ipaddr[1] == tabptr->ipaddr[1]) {
+	 
+	/* An old entry found, update this and return. */
+	memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);
+	tabptr->time = arptime;
+
+	return;
+      }
+    }
+  }
+
+  /* If we get here, no existing ARP table entry was found, so we
+     create one. */
+
+  /* First, we try to find an unused entry in the ARP table. */
+  for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
+    tabptr = &arp_table[i];
+    if(tabptr->ipaddr[0] == 0 &&
+       tabptr->ipaddr[1] == 0) {
+      break;
+    }
+  }
+
+  /* If no unused entry is found, we try to find the oldest entry and
+     throw it away. */
+  if(i == UIP_ARPTAB_SIZE) {
+    tmpage = 0;
+    c = 0;
+    for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
+      tabptr = &arp_table[i];
+      if(arptime - tabptr->time > tmpage) {
+	tmpage = arptime - tabptr->time;
+	c = i;
+      }
+    }
+    i = c;
+  }
+
+  /* Now, i is the ARP table entry which we will fill with the new
+     information. */
+  memcpy(tabptr->ipaddr, ipaddr, 4);
+  memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);
+  tabptr->time = arptime;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * ARP processing for incoming IP packets
+ *
+ * This function should be called by the device driver when an IP
+ * packet has been received. The function will check if the address is
+ * in the ARP cache, and if so the ARP cache entry will be
+ * refreshed. If no ARP cache entry was found, a new one is created.
+ *
+ * This function expects an IP packet with a prepended Ethernet header
+ * in the uip_buf[] buffer, and the length of the packet in the global
+ * variable uip_len.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+uip_arp_ipin(void)
+{
+  uip_len -= sizeof(struct uip_eth_hdr);
+	
+  /* Only insert/update an entry if the source IP address of the
+     incoming IP packet comes from a host on the local network. */
+  if((IPBUF->srcipaddr[0] & uip_arp_netmask[0]) !=
+     (uip_hostaddr[0] & uip_arp_netmask[0])) {
+    return;
+  }
+  if((IPBUF->srcipaddr[1] & uip_arp_netmask[1]) !=
+     (uip_hostaddr[1] & uip_arp_netmask[1])) {
+    return;
+  }
+  uip_arp_update(IPBUF->srcipaddr, &(IPBUF->ethhdr.src));
+  
+  return;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * ARP processing for incoming ARP packets.
+ *
+ * This function should be called by the device driver when an ARP
+ * packet has been received. The function will act differently
+ * depending on the ARP packet type: if it is a reply for a request
+ * that we previously sent out, the ARP cache will be filled in with
+ * the values from the ARP reply. If the incoming ARP packet is an ARP
+ * request for our IP address, an ARP reply packet is created and put
+ * into the uip_buf[] buffer.
+ *
+ * When the function returns, the value of the global variable uip_len
+ * indicates whether the device driver should send out a packet or
+ * not. If uip_len is zero, no packet should be sent. If uip_len is
+ * non-zero, it contains the length of the outbound packet that is
+ * present in the uip_buf[] buffer.
+ *
+ * This function expects an ARP packet with a prepended Ethernet
+ * header in the uip_buf[] buffer, and the length of the packet in the
+ * global variable uip_len.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+uip_arp_arpin(void)
+{
+
+  if(uip_len < sizeof(struct arp_hdr)) {
+    uip_len = 0;
+    return;
+  }
+
+  uip_len = 0;
+
+  switch(BUF->opcode) {
+  case HTONS(ARP_REQUEST):
+    /* ARP request. If it asked for our address, we send out a
+       reply. */
+    if(BUF->dipaddr[0] == uip_hostaddr[0] &&
+       BUF->dipaddr[1] == uip_hostaddr[1]) {
+      /* The reply opcode is 2. */
+      BUF->opcode = HTONS(2);
+
+      memcpy(BUF->dhwaddr.addr, BUF->shwaddr.addr, 6);
+      memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6);
+      memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6);
+      memcpy(BUF->ethhdr.dest.addr, BUF->dhwaddr.addr, 6);
+      
+      BUF->dipaddr[0] = BUF->sipaddr[0];
+      BUF->dipaddr[1] = BUF->sipaddr[1];
+      BUF->sipaddr[0] = uip_hostaddr[0];
+      BUF->sipaddr[1] = uip_hostaddr[1];
+
+      BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP);      
+      uip_len = sizeof(struct arp_hdr);
+    }      
+    break;
+  case HTONS(ARP_REPLY):
+    /* ARP reply. We insert or update the ARP table if it was meant
+       for us. */
+    if(BUF->dipaddr[0] == uip_hostaddr[0] &&
+       BUF->dipaddr[1] == uip_hostaddr[1]) {
+
+      uip_arp_update(BUF->sipaddr, &BUF->shwaddr);
+    }
+    break;
+  }
+
+  return;
+}
+/*-----------------------------------------------------------------------------------*/
+/**
+ * Prepend Ethernet header to an outbound IP packet and see if we need
+ * to send out an ARP request.
+ *
+ * This function should be called before sending out an IP packet. The
+ * function checks the destination IP address of the IP packet to see
+ * what Ethernet MAC address that should be used as a destination MAC
+ * address on the Ethernet.
+ *
+ * If the destination IP address is in the local network (determined
+ * by logical ANDing of netmask and our IP address), the function
+ * checks the ARP cache to see if an entry for the destination IP
+ * address is found. If so, an Ethernet header is prepended and the
+ * function returns. If no ARP cache entry is found for the
+ * destination IP address, the packet in the uip_buf[] is replaced by
+ * an ARP request packet for the IP address. The IP packet is dropped
+ * and it is assumed that they higher level protocols (e.g., TCP)
+ * eventually will retransmit the dropped packet.
+ *
+ * If the destination IP address is not on the local network, the IP
+ * address of the default router is used instead.
+ *
+ * When the function returns, a packet is present in the uip_buf[]
+ * buffer, and the length of the packet is in the global variable
+ * uip_len.
+ */
+/*-----------------------------------------------------------------------------------*/
+void
+uip_arp_out(void)
+{
+  struct arp_entry *tabptr;
+  /* Find the destination IP address in the ARP table and construct
+     the Ethernet header. If the destination IP addres isn't on the
+     local network, we use the default router's IP address instead.
+
+     If not ARP table entry is found, we overwrite the original IP
+     packet with an ARP request for the IP address. */
+
+  /* Check if the destination address is on the local network. */
+  if((IPBUF->destipaddr[0] & uip_arp_netmask[0]) !=
+     (uip_hostaddr[0] & uip_arp_netmask[0]) ||
+     (IPBUF->destipaddr[1] & uip_arp_netmask[1]) !=
+     (uip_hostaddr[1] & uip_arp_netmask[1])) {
+    /* Destination address was not on the local network, so we need to
+       use the default router's IP address instead of the destination
+       address when determining the MAC address. */
+    ipaddr[0] = uip_arp_draddr[0];
+    ipaddr[1] = uip_arp_draddr[1];
+  } else {
+    /* Else, we use the destination IP address. */
+    ipaddr[0] = IPBUF->destipaddr[0];
+    ipaddr[1] = IPBUF->destipaddr[1];
+  }
+      
+  for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
+    tabptr = &arp_table[i];
+    if(ipaddr[0] == tabptr->ipaddr[0] &&
+       ipaddr[1] == tabptr->ipaddr[1])
+      break;
+  }
+
+  if(i == UIP_ARPTAB_SIZE) {
+    /* The destination address was not in our ARP table, so we
+       overwrite the IP packet with an ARP request. */
+
+    memset(BUF->ethhdr.dest.addr, 0xff, 6);
+    memset(BUF->dhwaddr.addr, 0x00, 6);
+    memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6);
+    memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6);
+    
+    BUF->dipaddr[0] = ipaddr[0];
+    BUF->dipaddr[1] = ipaddr[1];
+    BUF->sipaddr[0] = uip_hostaddr[0];
+    BUF->sipaddr[1] = uip_hostaddr[1];
+    BUF->opcode = HTONS(ARP_REQUEST); /* ARP request. */
+    BUF->hwtype = HTONS(ARP_HWTYPE_ETH);
+    BUF->protocol = HTONS(UIP_ETHTYPE_IP);
+    BUF->hwlen = 6;
+    BUF->protolen = 4;
+    BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP);
+
+    uip_appdata = &uip_buf[40 + UIP_LLH_LEN];
+    
+    uip_len = sizeof(struct arp_hdr);
+    return;
+  }
+
+  /* Build an ethernet header. */
+  memcpy(IPBUF->ethhdr.dest.addr, tabptr->ethaddr.addr, 6);
+  memcpy(IPBUF->ethhdr.src.addr, uip_ethaddr.addr, 6);
+  
+  IPBUF->ethhdr.type = HTONS(UIP_ETHTYPE_IP);
+
+  uip_len += sizeof(struct uip_eth_hdr);
+}
+/*-----------------------------------------------------------------------------------*/
+
+/** @} */
+/** @} */
--- /dev/null
+++ b/net/uip-0.9/uip_arp.h
@@ -0,0 +1,201 @@
+/**
+ * \addtogroup uip
+ * @{
+ */
+
+/**
+ * \addtogroup uiparp 
+ * @{
+ */
+ 
+/**
+ * \file
+ * Macros and definitions for the ARP module.
+ * \author Adam Dunkels <adam@dunkels.com>
+ */
+  
+
+/*
+ * Copyright (c) 2001-2003, Adam Dunkels.
+ * 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. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.  
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.  
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: uip_arp.h,v 1.3.2.2 2003/10/06 15:10:22 adam Exp $
+ *
+ */
+
+#ifndef __UIP_ARP_H__
+#define __UIP_ARP_H__
+
+#include "uip.h"
+
+
+/**
+ * Representation of a 48-bit Ethernet address.
+ */
+struct uip_eth_addr {
+  u8_t addr[6];
+};
+
+extern struct uip_eth_addr uip_ethaddr;
+
+/**
+ * The Ethernet header. 
+ */
+struct uip_eth_hdr {
+  struct uip_eth_addr dest;
+  struct uip_eth_addr src;
+  u16_t type;
+};
+
+#define UIP_ETHTYPE_ARP 0x0806
+#define UIP_ETHTYPE_IP  0x0800
+#define UIP_ETHTYPE_IP6 0x86dd 
+
+
+/* The uip_arp_init() function must be called before any of the other
+   ARP functions. */
+void uip_arp_init(void);
+
+/* The uip_arp_ipin() function should be called whenever an IP packet
+   arrives from the Ethernet. This function refreshes the ARP table or
+   inserts a new mapping if none exists. The function assumes that an
+   IP packet with an Ethernet header is present in the uip_buf buffer
+   and that the length of the packet is in the uip_len variable. */
+void uip_arp_ipin(void);
+
+/* The uip_arp_arpin() should be called when an ARP packet is received
+   by the Ethernet driver. This function also assumes that the
+   Ethernet frame is present in the uip_buf buffer. When the
+   uip_arp_arpin() function returns, the contents of the uip_buf
+   buffer should be sent out on the Ethernet if the uip_len variable
+   is > 0. */
+void uip_arp_arpin(void);
+
+/* The uip_arp_out() function should be called when an IP packet
+   should be sent out on the Ethernet. This function creates an
+   Ethernet header before the IP header in the uip_buf buffer. The
+   Ethernet header will have the correct Ethernet MAC destination
+   address filled in if an ARP table entry for the destination IP
+   address (or the IP address of the default router) is present. If no
+   such table entry is found, the IP packet is overwritten with an ARP
+   request and we rely on TCP to retransmit the packet that was
+   overwritten. In any case, the uip_len variable holds the length of
+   the Ethernet frame that should be transmitted. */
+void uip_arp_out(void);
+
+/* The uip_arp_timer() function should be called every ten seconds. It
+   is responsible for flushing old entries in the ARP table. */
+void uip_arp_timer(void);
+
+/** @} */
+
+/**
+ * \addtogroup uipconffunc
+ * @{
+ */
+
+/**
+ * Set the default router's IP address.
+ *
+ * \param addr A pointer to a 4-byte array containing the IP address
+ * of the default router.
+ *
+ * \hideinitializer
+ */
+#define uip_setdraddr(addr) do { uip_arp_draddr[0] = addr[0]; \
+                                 uip_arp_draddr[1] = addr[1]; } while(0)
+
+/**
+ * Set the netmask.
+ *
+ * \param addr A pointer to a 4-byte array containing the IP address
+ * of the netmask.
+ *
+ * \hideinitializer
+ */
+#define uip_setnetmask(addr) do { uip_arp_netmask[0] = addr[0]; \
+                                  uip_arp_netmask[1] = addr[1]; } while(0)
+
+
+/**
+ * Get the default router's IP address.
+ *
+ * \param addr A pointer to a 4-byte array that will be filled in with
+ * the IP address of the default router.
+ *
+ * \hideinitializer
+ */
+#define uip_getdraddr(addr) do { addr[0] = uip_arp_draddr[0]; \
+                                 addr[1] = uip_arp_draddr[1]; } while(0)
+
+/**
+ * Get the netmask.
+ *
+ * \param addr A pointer to a 4-byte array that will be filled in with
+ * the value of the netmask.
+ *
+ * \hideinitializer
+ */
+#define uip_getnetmask(addr) do { addr[0] = uip_arp_netmask[0]; \
+                                  addr[1] = uip_arp_netmask[1]; } while(0)
+
+
+/**
+ * Specifiy the Ethernet MAC address.
+ *
+ * The ARP code needs to know the MAC address of the Ethernet card in
+ * order to be able to respond to ARP queries and to generate working
+ * Ethernet headers.
+ *
+ * \note This macro only specifies the Ethernet MAC address to the ARP
+ * code. It cannot be used to change the MAC address of the Ethernet
+ * card.
+ *
+ * \param eaddr A pointer to a struct uip_eth_addr containing the
+ * Ethernet MAC address of the Ethernet card.
+ *
+ * \hideinitializer
+ */
+#define uip_setethaddr(eaddr) do {uip_ethaddr.addr[0] = eaddr.addr[0]; \
+                              uip_ethaddr.addr[1] = eaddr.addr[1];\
+                              uip_ethaddr.addr[2] = eaddr.addr[2];\
+                              uip_ethaddr.addr[3] = eaddr.addr[3];\
+                              uip_ethaddr.addr[4] = eaddr.addr[4];\
+                              uip_ethaddr.addr[5] = eaddr.addr[5];} while(0)
+
+/** @} */
+
+/**
+ * \internal Internal variables that are set using the macros
+ * uip_setdraddr and uip_setnetmask.
+ */
+extern u16_t uip_arp_draddr[2], uip_arp_netmask[2];
+#endif /* __UIP_ARP_H__ */
+
+
--- /dev/null
+++ b/net/uip-0.9/uip.c
@@ -0,0 +1,1503 @@
+/**
+ * \addtogroup uip
+ * @{
+ */
+
+/**
+ * \file
+ * The uIP TCP/IP stack code.
+ * \author Adam Dunkels <adam@dunkels.com>
+ */
+
+/*
+ * Copyright (c) 2001-2003, Adam Dunkels.
+ * 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. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.  
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.  
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: uip.c,v 1.62.2.10 2003/10/07 13:23:01 adam Exp $
+ *
+ */
+
+/*
+This is a small implementation of the IP and TCP protocols (as well as
+some basic ICMP stuff). The implementation couples the IP, TCP and the
+application layers very tightly. To keep the size of the compiled code
+down, this code also features heavy usage of the goto statement.
+
+The principle is that we have a small buffer, called the uip_buf, in
+which the device driver puts an incoming packet. The TCP/IP stack
+parses the headers in the packet, and calls upon the application. If
+the remote host has sent data to the application, this data is present
+in the uip_buf and the application read the data from there. It is up
+to the application to put this data into a byte stream if needed. The
+application will not be fed with data that is out of sequence.
+
+If the application whishes to send data to the peer, it should put its
+data into the uip_buf, 40 bytes from the start of the buffer. The
+TCP/IP stack will calculate the checksums, and fill in the necessary
+header fields and finally send the packet back to the peer.
+*/
+
+#include "uip.h"
+#include "uipopt.h"
+#include "uip_arch.h"
+
+/*-----------------------------------------------------------------------------------*/
+/* Variable definitions. */
+
+
+/* The IP address of this host. If it is defined to be fixed (by setting UIP_FIXEDADDR to 1 in uipopt.h), the address is set here. Otherwise, the address */
+#if UIP_FIXEDADDR > 0
+const unsigned short int uip_hostaddr[2] =
+  {HTONS((UIP_IPADDR0 << 8) | UIP_IPADDR1),
+   HTONS((UIP_IPADDR2 << 8) | UIP_IPADDR3)};
+const unsigned short int uip_arp_draddr[2] =
+  {HTONS((UIP_DRIPADDR0 << 8) | UIP_DRIPADDR1),
+   HTONS((UIP_DRIPADDR2 << 8) | UIP_DRIPADDR3)};
+const unsigned short int uip_arp_netmask[2] =
+  {HTONS((UIP_NETMASK0 << 8) | UIP_NETMASK1),
+   HTONS((UIP_NETMASK2 << 8) | UIP_NETMASK3)};
+#else
+unsigned short int uip_hostaddr[2];       
+unsigned short int uip_arp_draddr[2], uip_arp_netmask[2];
+#endif /* UIP_FIXEDADDR */
+
+u8_t uip_buf[UIP_BUFSIZE+2];   /* The packet buffer that contains
+				incoming packets. */
+volatile u8_t *uip_appdata;  /* The uip_appdata pointer points to
+				application data. */
+volatile u8_t *uip_sappdata;  /* The uip_appdata pointer points to the
+				 application data which is to be sent. */
+#if UIP_URGDATA > 0
+volatile u8_t *uip_urgdata;  /* The uip_urgdata pointer points to
+				urgent data (out-of-band data), if
+				present. */
+volatile u8_t uip_urglen, uip_surglen;
+#endif /* UIP_URGDATA > 0 */
+
+volatile unsigned short int uip_len, uip_slen;
+                             /* The uip_len is either 8 or 16 bits,
+				depending on the maximum packet
+				size. */
+
+volatile u8_t uip_flags;     /* The uip_flags variable is used for
+				communication between the TCP/IP stack
+				and the application program. */
+struct uip_conn *uip_conn;   /* uip_conn always points to the current
+				connection. */
+
+struct uip_conn uip_conns[UIP_CONNS];
+                             /* The uip_conns array holds all TCP
+				connections. */
+unsigned short int uip_listenports[UIP_LISTENPORTS];
+                             /* The uip_listenports list all currently
+				listning ports. */
+#if UIP_UDP
+struct uip_udp_conn *uip_udp_conn;
+struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];
+#endif /* UIP_UDP */
+
+
+static unsigned short int ipid;           /* Ths ipid variable is an increasing
+				number that is used for the IP ID
+				field. */
+
+static u8_t iss[4];          /* The iss variable is used for the TCP
+				initial sequence number. */
+
+#if UIP_ACTIVE_OPEN
+static unsigned short int lastport;       /* Keeps track of the last port used for
+				a new connection. */
+#endif /* UIP_ACTIVE_OPEN */
+
+/* Temporary variables. */
+volatile u8_t uip_acc32[4];
+static u8_t c, opt;
+static unsigned short int tmp16;
+
+/* Structures and definitions. */
+#define TCP_FIN 0x01
+#define TCP_SYN 0x02
+#define TCP_RST 0x04
+#define TCP_PSH 0x08
+#define TCP_ACK 0x10
+#define TCP_URG 0x20
+#define TCP_CTL 0x3f
+
+#define ICMP_ECHO_REPLY 0
+#define ICMP_ECHO       8     
+
+/* Macros. */
+#define BUF ((uip_tcpip_hdr *)&uip_buf[UIP_LLH_LEN])
+#define FBUF ((uip_tcpip_hdr *)&uip_reassbuf[0])
+#define ICMPBUF ((uip_icmpip_hdr *)&uip_buf[UIP_LLH_LEN])
+#define UDPBUF ((uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN])
+
+#if UIP_STATISTICS == 1
+struct uip_stats uip_stat;
+#define UIP_STAT(s) s
+#else
+#define UIP_STAT(s)
+#endif /* UIP_STATISTICS == 1 */
+
+#if UIP_LOGGING == 1
+extern void puts(const char *s);
+#define UIP_LOG(m) puts(m)
+#else
+#define UIP_LOG(m)
+#endif /* UIP_LOGGING == 1 */
+
+/*-----------------------------------------------------------------------------------*/
+void
+uip_init(void)
+{
+  for(c = 0; c < UIP_LISTENPORTS; ++c) {
+    uip_listenports[c] = 0;
+  }
+  for(c = 0; c < UIP_CONNS; ++c) {
+    uip_conns[c].tcpstateflags = CLOSED;
+  }
+#if UIP_ACTIVE_OPEN
+  lastport = 1024;
+#endif /* UIP_ACTIVE_OPEN */
+
+#if UIP_UDP
+  for(c = 0; c < UIP_UDP_CONNS; ++c) {
+    uip_udp_conns[c].lport = 0;
+  }
+#endif /* UIP_UDP */
+  
+
+  /* IPv4 initialization. */
+#if UIP_FIXEDADDR == 0
+  uip_hostaddr[0] = uip_hostaddr[1] = 0;
+#endif /* UIP_FIXEDADDR */
+
+}
+/*-----------------------------------------------------------------------------------*/
+#if UIP_ACTIVE_OPEN
+struct uip_conn *
+uip_connect(unsigned short int *ripaddr, unsigned short int rport)
+{
+  register struct uip_conn *conn, *cconn;
+  
+  /* Find an unused local port. */
+ again:
+  ++lastport;
+
+  if(lastport >= 32000) {
+    lastport = 4096;
+  }
+
+  /* Check if this port is already in use, and if so try to find
+     another one. */
+  for(c = 0; c < UIP_CONNS; ++c) {
+    conn = &uip_conns[c];
+    if(conn->tcpstateflags != CLOSED &&
+       conn->lport == htons(lastport)) {
+      goto again;
+    }
+  }
+
+
+  conn = 0;
+  for(c = 0; c < UIP_CONNS; ++c) {
+    cconn = &uip_conns[c]; 
+    if(cconn->tcpstateflags == CLOSED) {
+      conn = cconn;
+      break;
+    }
+    if(cconn->tcpstateflags == TIME_WAIT) {
+      if(conn == 0 ||
+	 cconn->timer > uip_conn->timer) {
+	conn = cconn;
+      }
+    }
+  }
+
+  if(conn == 0) {
+    return 0;
+  }
+  
+  conn->tcpstateflags = SYN_SENT;
+
+  conn->snd_nxt[0] = iss[0];
+  conn->snd_nxt[1] = iss[1];
+  conn->snd_nxt[2] = iss[2];
+  conn->snd_nxt[3] = iss[3];
+
+  conn->initialmss = conn->mss = UIP_TCP_MSS;
+  
+  conn->len = 1;   /* TCP length of the SYN is one. */
+  conn->nrtx = 0;
+  conn->timer = 1; /* Send the SYN next time around. */
+  conn->rto = UIP_RTO;
+  conn->sa = 0;
+  conn->sv = 16;
+  conn->lport = htons(lastport);
+  conn->rport = rport;
+  conn->ripaddr[0] = ripaddr[0];
+  conn->ripaddr[1] = ripaddr[1];
+  
+  return conn;
+}
+#endif /* UIP_ACTIVE_OPEN */
+/*-----------------------------------------------------------------------------------*/
+#if UIP_UDP
+struct uip_udp_conn *
+uip_udp_new(unsigned short int *ripaddr, unsigned short int rport)
+{
+  register struct uip_udp_conn *conn;
+  
+  /* Find an unused local port. */
+ again:
+  ++lastport;
+
+  if(lastport >= 32000) {
+    lastport = 4096;
+  }
+  
+  for(c = 0; c < UIP_UDP_CONNS; ++c) {
+    if(uip_udp_conns[c].lport == lastport) {
+      goto again;
+    }
+  }
+
+
+  conn = 0;
+  for(c = 0; c < UIP_UDP_CONNS; ++c) {
+    if(uip_udp_conns[c].lport == 0) {
+      conn = &uip_udp_conns[c]; 
+      break;
+    }
+  }
+
+  if(conn == 0) {
+    return 0;
+  }
+  
+  conn->lport = HTONS(lastport);
+  conn->rport = HTONS(rport);
+  conn->ripaddr[0] = ripaddr[0];
+  conn->ripaddr[1] = ripaddr[1];
+  
+  return conn;
+}
+#endif /* UIP_UDP */
+/*-----------------------------------------------------------------------------------*/
+void
+uip_unlisten(unsigned short int port)
+{
+  for(c = 0; c < UIP_LISTENPORTS; ++c) {
+    if(uip_listenports[c] == port) {
+      uip_listenports[c] = 0;
+      return;
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+void
+uip_listen(unsigned short int port)
+{
+  for(c = 0; c < UIP_LISTENPORTS; ++c) {
+    if(uip_listenports[c] == 0) {
+      uip_listenports[c] = port;
+      return;
+    }
+  }
+}
+/*-----------------------------------------------------------------------------------*/
+/* XXX: IP fragment reassembly: not well-tested. */
+
+#if UIP_REASSEMBLY
+#define UIP_REASS_BUFSIZE (UIP_BUFSIZE - UIP_LLH_LEN)
+static u8_t uip_reassbuf[UIP_REASS_BUFSIZE];
+static u8_t uip_reassbitmap[UIP_REASS_BUFSIZE / (8 * 8)];
+static const u8_t bitmap_bits[8] = {0xff, 0x7f, 0x3f, 0x1f,
+				    0x0f, 0x07, 0x03, 0x01};
+static unsigned short int uip_reasslen;
+static u8_t uip_reassflags;
+#define UIP_REASS_FLAG_LASTFRAG 0x01
+static u8_t uip_reasstmr;
+
+#define IP_HLEN 20
+#define IP_MF   0x20
+
+static u8_t
+uip_reass(void)
+{
+  unsigned short int offset, len;
+  unsigned short int i;
+
+  /* If ip_reasstmr is zero, no packet is present in the buffer, so we
+     write the IP header of the fragment into the reassembly
+     buffer. The timer is updated with the maximum age. */
+  if(uip_reasstmr == 0) {
+    memcpy(uip_reassbuf, &BUF->vhl, IP_HLEN);
+    uip_reasstmr = UIP_REASS_MAXAGE;
+    uip_reassflags = 0;
+    /* Clear the bitmap. */
+    memset(uip_reassbitmap, sizeof(uip_reassbitmap), 0);
+  }
+
+  /* Check if the incoming fragment matches the one currently present
+     in the reasembly buffer. If so, we proceed with copying the
+     fragment into the buffer. */
+  if(BUF->srcipaddr[0] == FBUF->srcipaddr[0] &&
+     BUF->srcipaddr[1] == FBUF->srcipaddr[1] &&
+     BUF->destipaddr[0] == FBUF->destipaddr[0] &&
+     BUF->destipaddr[1] == FBUF->destipaddr[1] &&
+     BUF->ipid[0] == FBUF->ipid[0] &&
+     BUF->ipid[1] == FBUF->ipid[1]) {
+
+    len = (BUF->len[0] << 8) + BUF->len[1] - (BUF->vhl & 0x0f) * 4;
+    offset = (((BUF->ipoffset[0] & 0x3f) << 8) + BUF->ipoffset[1]) * 8;
+
+    /* If the offset or the offset + fragment length overflows the
+       reassembly buffer, we discard the entire packet. */
+    if(offset > UIP_REASS_BUFSIZE ||
+       offset + len > UIP_REASS_BUFSIZE) {
+      uip_reasstmr = 0;
+      goto nullreturn;
+    }
+
+    /* Copy the fragment into the reassembly buffer, at the right
+       offset. */
+    memcpy(&uip_reassbuf[IP_HLEN + offset],
+	   (char *)BUF + (int)((BUF->vhl & 0x0f) * 4),
+	   len);
+      
+    /* Update the bitmap. */
+    if(offset / (8 * 8) == (offset + len) / (8 * 8)) {
+      /* If the two endpoints are in the same byte, we only update
+	 that byte. */
+	     
+      uip_reassbitmap[offset / (8 * 8)] |=
+	     bitmap_bits[(offset / 8 ) & 7] &
+	     ~bitmap_bits[((offset + len) / 8 ) & 7];
+    } else {
+      /* If the two endpoints are in different bytes, we update the
+	 bytes in the endpoints and fill the stuff inbetween with
+	 0xff. */
+      uip_reassbitmap[offset / (8 * 8)] |=
+	bitmap_bits[(offset / 8 ) & 7];
+      for(i = 1 + offset / (8 * 8); i < (offset + len) / (8 * 8); ++i) {
+	uip_reassbitmap[i] = 0xff;
+      }      
+      uip_reassbitmap[(offset + len) / (8 * 8)] |=
+	~bitmap_bits[((offset + len) / 8 ) & 7];
+    }
+    
+    /* If this fragment has the More Fragments flag set to zero, we
+       know that this is the last fragment, so we can calculate the
+       size of the entire packet. We also set the
+       IP_REASS_FLAG_LASTFRAG flag to indicate that we have received
+       the final fragment. */
+
+    if((BUF->ipoffset[0] & IP_MF) == 0) {
+      uip_reassflags |= UIP_REASS_FLAG_LASTFRAG;
+      uip_reasslen = offset + len;
+    }
+    
+    /* Finally, we check if we have a full packet in the buffer. We do
+       this by checking if we have the last fragment and if all bits
+       in the bitmap are set. */
+    if(uip_reassflags & UIP_REASS_FLAG_LASTFRAG) {
+      /* Check all bytes up to and including all but the last byte in
+	 the bitmap. */
+      for(i = 0; i < uip_reasslen / (8 * 8) - 1; ++i) {
+	if(uip_reassbitmap[i] != 0xff) {
+	  goto nullreturn;
+	}
+      }
+      /* Check the last byte in the bitmap. It should contain just the
+	 right amount of bits. */
+      if(uip_reassbitmap[uip_reasslen / (8 * 8)] !=
+	 (u8_t)~bitmap_bits[uip_reasslen / 8 & 7]) {
+	goto nullreturn;
+      }
+
+      /* If we have come this far, we have a full packet in the
+	 buffer, so we allocate a pbuf and copy the packet into it. We
+	 also reset the timer. */
+      uip_reasstmr = 0;
+      memcpy(BUF, FBUF, uip_reasslen);
+
+      /* Pretend to be a "normal" (i.e., not fragmented) IP packet
+	 from now on. */
+      BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
+      BUF->len[0] = uip_reasslen >> 8;
+      BUF->len[1] = uip_reasslen & 0xff;
+      BUF->ipchksum = 0;
+      BUF->ipchksum = ~(uip_ipchksum());
+
+      return uip_reasslen;
+    }
+  }
+
+ nullreturn:
+  return 0;
+}
+#endif /* UIP_REASSEMBL */
+/*-----------------------------------------------------------------------------------*/
+static void
+uip_add_rcv_nxt(unsigned short int n)
+{
+  uip_add32(uip_conn->rcv_nxt, n);
+  uip_conn->rcv_nxt[0] = uip_acc32[0];
+  uip_conn->rcv_nxt[1] = uip_acc32[1];
+  uip_conn->rcv_nxt[2] = uip_acc32[2];
+  uip_conn->rcv_nxt[3] = uip_acc32[3];
+}
+/*-----------------------------------------------------------------------------------*/
+void
+uip_process(u8_t flag)
+{
+  register struct uip_conn *uip_connr = uip_conn;
+  
+  uip_appdata = &uip_buf[40 + UIP_LLH_LEN];
+
+  
+  /* Check if we were invoked because of the perodic timer fireing. */
+  if(flag == UIP_TIMER) {
+#if UIP_REASSEMBLY
+    if(uip_reasstmr != 0) {
+      --uip_reasstmr;
+    }
+#endif /* UIP_REASSEMBLY */
+    /* Increase the initial sequence number. */
+    if(++iss[3] == 0) {
+      if(++iss[2] == 0) {
+	if(++iss[1] == 0) {
+	  ++iss[0];
+	}
+      }
+    }    
+    uip_len = 0;
+    if(uip_connr->tcpstateflags == TIME_WAIT ||
+       uip_connr->tcpstateflags == FIN_WAIT_2) {
+      ++(uip_connr->timer);
+      if(uip_connr->timer == UIP_TIME_WAIT_TIMEOUT) {
+	uip_connr->tcpstateflags = CLOSED;
+      }
+    } else if(uip_connr->tcpstateflags != CLOSED) {
+      /* If the connection has outstanding data, we increase the
+	 connection's timer and see if it has reached the RTO value
+	 in which case we retransmit. */
+      if(uip_outstanding(uip_connr)) {
+	if(uip_connr->timer-- == 0) {
+	  if(uip_connr->nrtx == UIP_MAXRTX ||
+	     ((uip_connr->tcpstateflags == SYN_SENT ||
+	       uip_connr->tcpstateflags == SYN_RCVD) &&
+	      uip_connr->nrtx == UIP_MAXSYNRTX)) {
+	    uip_connr->tcpstateflags = CLOSED;
+
+	    /* We call UIP_APPCALL() with uip_flags set to
+	       UIP_TIMEDOUT to inform the application that the
+	       connection has timed out. */
+	    uip_flags = UIP_TIMEDOUT;
+	    UIP_APPCALL();
+
+	    /* We also send a reset packet to the remote host. */
+	    BUF->flags = TCP_RST | TCP_ACK;
+	    goto tcp_send_nodata;
+	  }
+
+	  /* Exponential backoff. */
+	  uip_connr->timer = UIP_RTO << (uip_connr->nrtx > 4?
+					 4:
+					 uip_connr->nrtx);
+	  ++(uip_connr->nrtx);
+	  
+	  /* Ok, so we need to retransmit. We do this differently
+	     depending on which state we are in. In ESTABLISHED, we
+	     call upon the application so that it may prepare the
+	     data for the retransmit. In SYN_RCVD, we resend the
+	     SYNACK that we sent earlier and in LAST_ACK we have to
+	     retransmit our FINACK. */
+	  UIP_STAT(++uip_stat.tcp.rexmit);
+	  switch(uip_connr->tcpstateflags & TS_MASK) {
+	  case SYN_RCVD:
+	    /* In the SYN_RCVD state, we should retransmit our
+               SYNACK. */
+	    goto tcp_send_synack;
+	    
+#if UIP_ACTIVE_OPEN
+	  case SYN_SENT:
+	    /* In the SYN_SENT state, we retransmit out SYN. */
+	    BUF->flags = 0;
+	    goto tcp_send_syn;
+#endif /* UIP_ACTIVE_OPEN */
+	    
+	  case ESTABLISHED:
+	    /* In the ESTABLISHED state, we call upon the application
+               to do the actual retransmit after which we jump into
+               the code for sending out the packet (the apprexmit
+               label). */
+	    uip_len = 0;
+	    uip_slen = 0;
+	    uip_flags = UIP_REXMIT;
+	    UIP_APPCALL();
+	    goto apprexmit;
+	    
+	  case FIN_WAIT_1:
+	  case CLOSING:
+	  case LAST_ACK:
+	    /* In all these states we should retransmit a FINACK. */
+	    goto tcp_send_finack;
+	    
+	  }
+	}
+      } else if((uip_connr->tcpstateflags & TS_MASK) == ESTABLISHED) {
+	/* If there was no need for a retransmission, we poll the
+           application for new data. */
+	uip_len = 0;
+	uip_slen = 0;
+	uip_flags = UIP_POLL;
+	UIP_APPCALL();
+	goto appsend;
+      }
+    }
+    goto drop;
+  }
+#if UIP_UDP 
+  if(flag == UIP_UDP_TIMER) {
+    if(uip_udp_conn->lport != 0) {
+      uip_appdata = &uip_buf[UIP_LLH_LEN + 28];
+      uip_len = uip_slen = 0;
+      uip_flags = UIP_POLL;
+      UIP_UDP_APPCALL();
+      goto udp_send;
+    } else {
+      goto drop;
+    }
+  }
+#endif
+
+  /* This is where the input processing starts. */
+  UIP_STAT(++uip_stat.ip.recv);
+
+
+  /* Start of IPv4 input header processing code. */
+  
+  /* Check validity of the IP header. */  
+  if(BUF->vhl != 0x45)  { /* IP version and header length. */
+    UIP_STAT(++uip_stat.ip.drop);
+    UIP_STAT(++uip_stat.ip.vhlerr);
+    UIP_LOG("ip: invalid version or header length.");
+    goto drop;
+  }
+  
+  /* Check the size of the packet. If the size reported to us in
+     uip_len doesn't match the size reported in the IP header, there
+     has been a transmission error and we drop the packet. */
+  
+  if(BUF->len[0] != (uip_len >> 8)) { /* IP length, high byte. */
+    uip_len = (uip_len & 0xff) | (BUF->len[0] << 8);
+  }
+  if(BUF->len[1] != (uip_len & 0xff)) { /* IP length, low byte. */
+    uip_len = (uip_len & 0xff00) | BUF->len[1];
+  }
+
+  /* Check the fragment flag. */
+  if((BUF->ipoffset[0] & 0x3f) != 0 ||
+     BUF->ipoffset[1] != 0) { 
+#if UIP_REASSEMBLY
+    uip_len = uip_reass();
+    if(uip_len == 0) {
+      goto drop;
+    }
+#else
+    UIP_STAT(++uip_stat.ip.drop);
+    UIP_STAT(++uip_stat.ip.fragerr);
+    UIP_LOG("ip: fragment dropped.");    
+    goto drop;
+#endif /* UIP_REASSEMBLY */
+  }
+
+  /* If we are configured to use ping IP address configuration and
+     hasn't been assigned an IP address yet, we accept all ICMP
+     packets. */
+#if UIP_PINGADDRCONF
+  if((uip_hostaddr[0] | uip_hostaddr[1]) == 0) {
+    if(BUF->proto == UIP_PROTO_ICMP) {
+      UIP_LOG("ip: possible ping config packet received.");
+      goto icmp_input;
+    } else {
+      UIP_LOG("ip: packet dropped since no address assigned.");
+      goto drop;
+    }
+  }
+#endif /* UIP_PINGADDRCONF */
+  
+  /* Check if the packet is destined for our IP address. */  
+  if(BUF->destipaddr[0] != uip_hostaddr[0]) {
+    UIP_STAT(++uip_stat.ip.drop);
+    UIP_LOG("ip: packet not for us.");        
+    goto drop;
+  }
+  if(BUF->destipaddr[1] != uip_hostaddr[1]) {
+    UIP_STAT(++uip_stat.ip.drop);
+    UIP_LOG("ip: packet not for us.");        
+    goto drop;
+  }
+
+  if(uip_ipchksum() != 0xffff) { /* Compute and check the IP header
+				    checksum. */
+    UIP_STAT(++uip_stat.ip.drop);
+    UIP_STAT(++uip_stat.ip.chkerr);
+    UIP_LOG("ip: bad checksum.");    
+    goto drop;
+  }
+
+  if(BUF->proto == UIP_PROTO_TCP)  /* Check for TCP packet. If so, jump
+                                     to the tcp_input label. */
+    goto tcp_input;
+
+#if UIP_UDP
+  if(BUF->proto == UIP_PROTO_UDP)
+    goto udp_input;
+#endif /* UIP_UDP */
+
+  if(BUF->proto != UIP_PROTO_ICMP) { /* We only allow ICMP packets from
+					here. */
+    UIP_STAT(++uip_stat.ip.drop);
+    UIP_STAT(++uip_stat.ip.protoerr);
+    UIP_LOG("ip: neither tcp nor icmp.");        
+    goto drop;
+  }
+  
+ //icmp_input:
+  UIP_STAT(++uip_stat.icmp.recv);
+  
+  /* ICMP echo (i.e., ping) processing. This is simple, we only change
+     the ICMP type from ECHO to ECHO_REPLY and adjust the ICMP
+     checksum before we return the packet. */
+  if(ICMPBUF->type != ICMP_ECHO) {
+    UIP_STAT(++uip_stat.icmp.drop);
+    UIP_STAT(++uip_stat.icmp.typeerr);
+    UIP_LOG("icmp: not icmp echo.");
+    goto drop;
+  }
+
+  /* If we are configured to use ping IP address assignment, we use
+     the destination IP address of this ping packet and assign it to
+     ourself. */
+#if UIP_PINGADDRCONF
+  if((uip_hostaddr[0] | uip_hostaddr[1]) == 0) {
+    uip_hostaddr[0] = BUF->destipaddr[0];
+    uip_hostaddr[1] = BUF->destipaddr[1];
+  }
+#endif /* UIP_PINGADDRCONF */  
+  
+  ICMPBUF->type = ICMP_ECHO_REPLY;
+  
+  if(ICMPBUF->icmpchksum >= HTONS(0xffff - (ICMP_ECHO << 8))) {
+    ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8) + 1;
+  } else {
+    ICMPBUF->icmpchksum += HTONS(ICMP_ECHO << 8);
+  }
+  
+  /* Swap IP addresses. */
+  tmp16 = BUF->destipaddr[0];
+  BUF->destipaddr[0] = BUF->srcipaddr[0];
+  BUF->srcipaddr[0] = tmp16;
+  tmp16 = BUF->destipaddr[1];
+  BUF->destipaddr[1] = BUF->srcipaddr[1];
+  BUF->srcipaddr[1] = tmp16;
+
+  UIP_STAT(++uip_stat.icmp.sent);
+  goto send;
+
+  /* End of IPv4 input header processing code. */
+  
+
+#if UIP_UDP
+  /* UDP input processing. */
+ udp_input:
+  /* UDP processing is really just a hack. We don't do anything to the
+     UDP/IP headers, but let the UDP application do all the hard
+     work. If the application sets uip_slen, it has a packet to
+     send. */
+#if UIP_UDP_CHECKSUMS
+  if(uip_udpchksum() != 0xffff) { 
+    UIP_STAT(++uip_stat.udp.drop);
+    UIP_STAT(++uip_stat.udp.chkerr);
+    UIP_LOG("udp: bad checksum.");    
+    goto drop;
+  }  
+#endif /* UIP_UDP_CHECKSUMS */
+
+  /* Demultiplex this UDP packet between the UDP "connections". */
+  for(uip_udp_conn = &uip_udp_conns[0];
+      uip_udp_conn < &uip_udp_conns[UIP_UDP_CONNS];
+      ++uip_udp_conn) {
+    if(uip_udp_conn->lport != 0 &&
+       UDPBUF->destport == uip_udp_conn->lport &&
+       (uip_udp_conn->rport == 0 ||
+        UDPBUF->srcport == uip_udp_conn->rport) &&
+       BUF->srcipaddr[0] == uip_udp_conn->ripaddr[0] &&
+       BUF->srcipaddr[1] == uip_udp_conn->ripaddr[1]) {
+      goto udp_found; 
+    }
+  }
+  goto drop;
+  
+ udp_found:
+  uip_len = uip_len - 28;
+  uip_appdata = &uip_buf[UIP_LLH_LEN + 28];
+  uip_flags = UIP_NEWDATA;
+  uip_slen = 0;
+  UIP_UDP_APPCALL();
+ udp_send:
+  if(uip_slen == 0) {
+    goto drop;      
+  }
+  uip_len = uip_slen + 28;
+
+  BUF->len[0] = (uip_len >> 8);
+  BUF->len[1] = (uip_len & 0xff);
+  
+  BUF->proto = UIP_PROTO_UDP;
+
+  UDPBUF->udplen = HTONS(uip_slen + 8);
+  UDPBUF->udpchksum = 0;
+#if UIP_UDP_CHECKSUMS 
+  /* Calculate UDP checksum. */
+  UDPBUF->udpchksum = ~(uip_udpchksum());
+  if(UDPBUF->udpchksum == 0) {
+    UDPBUF->udpchksum = 0xffff;
+  }
+#endif /* UIP_UDP_CHECKSUMS */
+
+  BUF->srcport  = uip_udp_conn->lport;
+  BUF->destport = uip_udp_conn->rport;
+
+  BUF->srcipaddr[0] = uip_hostaddr[0];
+  BUF->srcipaddr[1] = uip_hostaddr[1];
+  BUF->destipaddr[0] = uip_udp_conn->ripaddr[0];
+  BUF->destipaddr[1] = uip_udp_conn->ripaddr[1];
+ 
+  uip_appdata = &uip_buf[UIP_LLH_LEN + 40];
+  goto ip_send_nolen;
+#endif /* UIP_UDP */
+  
+  /* TCP input processing. */  
+ tcp_input:
+  UIP_STAT(++uip_stat.tcp.recv);
+
+  /* Start of TCP input header processing code. */
+  
+  if(uip_tcpchksum() != 0xffff) {   /* Compute and check the TCP
+				       checksum. */
+    UIP_STAT(++uip_stat.tcp.drop);
+    UIP_STAT(++uip_stat.tcp.chkerr);
+    UIP_LOG("tcp: bad checksum.");    
+    goto drop;
+  }
+  
+  /* Demultiplex this segment. */
+  /* First check any active connections. */
+  for(uip_connr = &uip_conns[0]; uip_connr < &uip_conns[UIP_CONNS]; ++uip_connr) {
+    if(uip_connr->tcpstateflags != CLOSED &&
+       BUF->destport == uip_connr->lport &&
+       BUF->srcport == uip_connr->rport &&
+       BUF->srcipaddr[0] == uip_connr->ripaddr[0] &&
+       BUF->srcipaddr[1] == uip_connr->ripaddr[1]) {
+      goto found;    
+    }
+  }
+
+  /* If we didn't find and active connection that expected the packet,
+     either this packet is an old duplicate, or this is a SYN packet
+     destined for a connection in LISTEN. If the SYN flag isn't set,
+     it is an old packet and we send a RST. */
+  if((BUF->flags & TCP_CTL) != TCP_SYN)
+    goto reset;
+  
+  tmp16 = BUF->destport;
+  /* Next, check listening connections. */  
+  for(c = 0; c < UIP_LISTENPORTS; ++c) {
+    if(tmp16 == uip_listenports[c])
+      goto found_listen;
+  }
+  
+  /* No matching connection found, so we send a RST packet. */
+  UIP_STAT(++uip_stat.tcp.synrst);
+ reset:
+
+  /* We do not send resets in response to resets. */
+  if(BUF->flags & TCP_RST) 
+    goto drop;
+
+  UIP_STAT(++uip_stat.tcp.rst);
+  
+  BUF->flags = TCP_RST | TCP_ACK;
+  uip_len = 40;
+  BUF->tcpoffset = 5 << 4;
+
+  /* Flip the seqno and ackno fields in the TCP header. */
+  c = BUF->seqno[3];
+  BUF->seqno[3] = BUF->ackno[3];  
+  BUF->ackno[3] = c;
+  
+  c = BUF->seqno[2];
+  BUF->seqno[2] = BUF->ackno[2];  
+  BUF->ackno[2] = c;
+  
+  c = BUF->seqno[1];
+  BUF->seqno[1] = BUF->ackno[1];
+  BUF->ackno[1] = c;
+  
+  c = BUF->seqno[0];
+  BUF->seqno[0] = BUF->ackno[0];  
+  BUF->ackno[0] = c;
+
+  /* We also have to increase the sequence number we are
+     acknowledging. If the least significant byte overflowed, we need
+     to propagate the carry to the other bytes as well. */
+  if(++BUF->ackno[3] == 0) {
+    if(++BUF->ackno[2] == 0) {
+      if(++BUF->ackno[1] == 0) {
+	++BUF->ackno[0];
+      }
+    }
+  }
+ 
+  /* Swap port numbers. */
+  tmp16 = BUF->srcport;
+  BUF->srcport = BUF->destport;
+  BUF->destport = tmp16;
+  
+  /* Swap IP addresses. */
+  tmp16 = BUF->destipaddr[0];
+  BUF->destipaddr[0] = BUF->srcipaddr[0];
+  BUF->srcipaddr[0] = tmp16;
+  tmp16 = BUF->destipaddr[1];
+  BUF->destipaddr[1] = BUF->srcipaddr[1];
+  BUF->srcipaddr[1] = tmp16;
+
+  
+  /* And send out the RST packet! */
+  goto tcp_send_noconn;
+
+  /* This label will be jumped to if we matched the incoming packet
+     with a connection in LISTEN. In that case, we should create a new
+     connection and send a SYNACK in return. */
+ found_listen:
+  /* First we check if there are any connections avaliable. Unused
+     connections are kept in the same table as used connections, but
+     unused ones have the tcpstate set to CLOSED. Also, connections in
+     TIME_WAIT are kept track of and we'll use the oldest one if no
+     CLOSED connections are found. Thanks to Eddie C. Dost for a very
+     nice algorithm for the TIME_WAIT search. */
+  uip_connr = 0;
+  for(c = 0; c < UIP_CONNS; ++c) {
+    if(uip_conns[c].tcpstateflags == CLOSED) {
+      uip_connr = &uip_conns[c];
+      break;
+    }
+    if(uip_conns[c].tcpstateflags == TIME_WAIT) {
+      if(uip_connr == 0 ||
+	 uip_conns[c].timer > uip_connr->timer) {
+	uip_connr = &uip_conns[c];
+      }
+    }
+  }
+
+  if(uip_connr == 0) {
+    /* All connections are used already, we drop packet and hope that
+       the remote end will retransmit the packet at a time when we
+       have more spare connections. */
+    UIP_STAT(++uip_stat.tcp.syndrop);
+    UIP_LOG("tcp: found no unused connections.");
+    goto drop;
+  }
+  uip_conn = uip_connr;
+  
+  /* Fill in the necessary fields for the new connection. */
+  uip_connr->rto = uip_connr->timer = UIP_RTO;
+  uip_connr->sa = 0;
+  uip_connr->sv = 4;  
+  uip_connr->nrtx = 0;
+  uip_connr->lport = BUF->destport;
+  uip_connr->rport = BUF->srcport;
+  uip_connr->ripaddr[0] = BUF->srcipaddr[0];
+  uip_connr->ripaddr[1] = BUF->srcipaddr[1];
+  uip_connr->tcpstateflags = SYN_RCVD;
+
+  uip_connr->snd_nxt[0] = iss[0];
+  uip_connr->snd_nxt[1] = iss[1];
+  uip_connr->snd_nxt[2] = iss[2];
+  uip_connr->snd_nxt[3] = iss[3];
+  uip_connr->len = 1;
+
+  /* rcv_nxt should be the seqno from the incoming packet + 1. */
+  uip_connr->rcv_nxt[3] = BUF->seqno[3];
+  uip_connr->rcv_nxt[2] = BUF->seqno[2];
+  uip_connr->rcv_nxt[1] = BUF->seqno[1];
+  uip_connr->rcv_nxt[0] = BUF->seqno[0];
+  uip_add_rcv_nxt(1);
+
+  /* Parse the TCP MSS option, if present. */
+  if((BUF->tcpoffset & 0xf0) > 0x50) {
+    for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) {
+      opt = uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + c];
+      if(opt == 0x00) {
+	/* End of options. */	
+	break;
+      } else if(opt == 0x01) {
+	++c;
+	/* NOP option. */
+      } else if(opt == 0x02 &&
+		uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0x04) {
+	/* An MSS option with the right option length. */	
+	tmp16 = ((unsigned short int)uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
+	  (unsigned short int)uip_buf[40 + UIP_LLH_LEN + 3 + c];
+	uip_connr->initialmss = uip_connr->mss =
+	  tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
+	
+	/* And we are done processing options. */
+	break;
+      } else {
+	/* All other options have a length field, so that we easily
+	   can skip past them. */
+	if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
+	  /* If the length field is zero, the options are malformed
+	     and we don't process them further. */
+	  break;
+	}
+	c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
+      }      
+    }
+  }
+  
+  /* Our response will be a SYNACK. */
+#if UIP_ACTIVE_OPEN
+ tcp_send_synack:
+  BUF->flags = TCP_ACK;    
+  
+ tcp_send_syn:
+  BUF->flags |= TCP_SYN;    
+#else /* UIP_ACTIVE_OPEN */
+ tcp_send_synack:
+  BUF->flags = TCP_SYN | TCP_ACK;    
+#endif /* UIP_ACTIVE_OPEN */
+  
+  /* We send out the TCP Maximum Segment Size option with our
+     SYNACK. */
+  BUF->optdata[0] = 2;
+  BUF->optdata[1] = 4;
+  BUF->optdata[2] = (UIP_TCP_MSS) / 256;
+  BUF->optdata[3] = (UIP_TCP_MSS) & 255;
+  uip_len = 44;
+  BUF->tcpoffset = 6 << 4;
+  goto tcp_send;
+
+  /* This label will be jumped to if we found an active connection. */
+ found:
+  uip_conn = uip_connr;
+  uip_flags = 0;
+
+  /* We do a very naive form of TCP reset processing; we just accept
+     any RST and kill our connection. We should in fact check if the
+     sequence number of this reset is wihtin our advertised window
+     before we accept the reset. */
+  if(BUF->flags & TCP_RST) {
+    uip_connr->tcpstateflags = CLOSED;
+    UIP_LOG("tcp: got reset, aborting connection.");
+    uip_flags = UIP_ABORT;
+    UIP_APPCALL();
+    goto drop;
+  }      
+  /* Calculated the length of the data, if the application has sent
+     any data to us. */
+  c = (BUF->tcpoffset >> 4) << 2;
+  /* uip_len will contain the length of the actual TCP data. This is
+     calculated by subtracing the length of the TCP header (in
+     c) and the length of the IP header (20 bytes). */
+  uip_len = uip_len - c - 20;
+
+  /* First, check if the sequence number of the incoming packet is
+     what we're expecting next. If not, we send out an ACK with the
+     correct numbers in. */
+  if(uip_len > 0 &&
+     (BUF->seqno[0] != uip_connr->rcv_nxt[0] ||
+      BUF->seqno[1] != uip_connr->rcv_nxt[1] ||
+      BUF->seqno[2] != uip_connr->rcv_nxt[2] ||
+      BUF->seqno[3] != uip_connr->rcv_nxt[3])) {
+    goto tcp_send_ack;
+  }
+
+  /* Next, check if the incoming segment acknowledges any outstanding
+     data. If so, we update the sequence number, reset the length of
+     the outstanding data, calculate RTT estimations, and reset the
+     retransmission timer. */
+  if((BUF->flags & TCP_ACK) && uip_outstanding(uip_connr)) {
+    uip_add32(uip_connr->snd_nxt, uip_connr->len);
+    if(BUF->ackno[0] == uip_acc32[0] &&
+       BUF->ackno[1] == uip_acc32[1] &&
+       BUF->ackno[2] == uip_acc32[2] &&
+       BUF->ackno[3] == uip_acc32[3]) {
+      /* Update sequence number. */
+      uip_connr->snd_nxt[0] = uip_acc32[0];
+      uip_connr->snd_nxt[1] = uip_acc32[1];
+      uip_connr->snd_nxt[2] = uip_acc32[2];
+      uip_connr->snd_nxt[3] = uip_acc32[3];
+	
+
+      /* Do RTT estimation, unless we have done retransmissions. */
+      if(uip_connr->nrtx == 0) {
+	signed char m;
+	m = uip_connr->rto - uip_connr->timer;
+	/* This is taken directly from VJs original code in his paper */
+	m = m - (uip_connr->sa >> 3);
+	uip_connr->sa += m;
+	if(m < 0) {
+	  m = -m;
+	}
+	m = m - (uip_connr->sv >> 2);
+	uip_connr->sv += m;
+	uip_connr->rto = (uip_connr->sa >> 3) + uip_connr->sv;
+
+      }
+      /* Set the acknowledged flag. */
+      uip_flags = UIP_ACKDATA;
+      /* Reset the retransmission timer. */
+      uip_connr->timer = uip_connr->rto;
+    }
+    
+  }
+
+  /* Do different things depending on in what state the connection is. */
+  switch(uip_connr->tcpstateflags & TS_MASK) {
+    /* CLOSED and LISTEN are not handled here. CLOSE_WAIT is not
+	implemented, since we force the application to close when the
+	peer sends a FIN (hence the application goes directly from
+	ESTABLISHED to LAST_ACK). */
+  case SYN_RCVD:
+    /* In SYN_RCVD we have sent out a SYNACK in response to a SYN, and
+       we are waiting for an ACK that acknowledges the data we sent
+       out the last time. Therefore, we want to have the UIP_ACKDATA
+       flag set. If so, we enter the ESTABLISHED state. */
+    if(uip_flags & UIP_ACKDATA) {
+      uip_connr->tcpstateflags = ESTABLISHED;
+      uip_flags = UIP_CONNECTED;
+      uip_connr->len = 0;
+      if(uip_len > 0) {
+        uip_flags |= UIP_NEWDATA;
+        uip_add_rcv_nxt(uip_len);
+      }
+      uip_slen = 0;
+      UIP_APPCALL();
+      goto appsend;
+    }
+    goto drop;
+#if UIP_ACTIVE_OPEN
+  case SYN_SENT:
+    /* In SYN_SENT, we wait for a SYNACK that is sent in response to
+       our SYN. The rcv_nxt is set to sequence number in the SYNACK
+       plus one, and we send an ACK. We move into the ESTABLISHED
+       state. */
+    if((uip_flags & UIP_ACKDATA) &&
+       BUF->flags == (TCP_SYN | TCP_ACK)) {
+
+      /* Parse the TCP MSS option, if present. */
+      if((BUF->tcpoffset & 0xf0) > 0x50) {
+	for(c = 0; c < ((BUF->tcpoffset >> 4) - 5) << 2 ;) {
+	  opt = uip_buf[40 + UIP_LLH_LEN + c];
+	  if(opt == 0x00) {
+	    /* End of options. */	
+	    break;
+	  } else if(opt == 0x01) {
+	    ++c;
+	    /* NOP option. */
+	  } else if(opt == 0x02 &&
+		    uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0x04) {
+	    /* An MSS option with the right option length. */
+	    tmp16 = (uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 2 + c] << 8) |
+	      uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 3 + c];
+	    uip_connr->initialmss =
+	      uip_connr->mss = tmp16 > UIP_TCP_MSS? UIP_TCP_MSS: tmp16;
+
+	    /* And we are done processing options. */
+	    break;
+	  } else {
+	    /* All other options have a length field, so that we easily
+	       can skip past them. */
+	    if(uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c] == 0) {
+	      /* If the length field is zero, the options are malformed
+		 and we don't process them further. */
+	      break;
+	    }
+	    c += uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN + 1 + c];
+	  }      
+	}
+      }
+      uip_connr->tcpstateflags = ESTABLISHED;      
+      uip_connr->rcv_nxt[0] = BUF->seqno[0];
+      uip_connr->rcv_nxt[1] = BUF->seqno[1];
+      uip_connr->rcv_nxt[2] = BUF->seqno[2];
+      uip_connr->rcv_nxt[3] = BUF->seqno[3];
+      uip_add_rcv_nxt(1);
+      uip_flags = UIP_CONNECTED | UIP_NEWDATA;
+      uip_connr->len = 0;
+      uip_len = 0;
+      uip_slen = 0;
+      UIP_APPCALL();
+      goto appsend;
+    }
+    goto reset;
+#endif /* UIP_ACTIVE_OPEN */
+    
+  case ESTABLISHED:
+    /* In the ESTABLISHED state, we call upon the application to feed
+    data into the uip_buf. If the UIP_ACKDATA flag is set, the
+    application should put new data into the buffer, otherwise we are
+    retransmitting an old segment, and the application should put that
+    data into the buffer.
+
+    If the incoming packet is a FIN, we should close the connection on
+    this side as well, and we send out a FIN and enter the LAST_ACK
+    state. We require that there is no outstanding data; otherwise the
+    sequence numbers will be screwed up. */
+
+    if(BUF->flags & TCP_FIN) {
+      if(uip_outstanding(uip_connr)) {
+	goto drop;
+      }
+      uip_add_rcv_nxt(1 + uip_len);      
+      uip_flags = UIP_CLOSE;
+      if(uip_len > 0) {
+	uip_flags |= UIP_NEWDATA;
+      }
+      UIP_APPCALL();
+      uip_connr->len = 1;
+      uip_connr->tcpstateflags = LAST_ACK;
+      uip_connr->nrtx = 0;
+    tcp_send_finack:
+      BUF->flags = TCP_FIN | TCP_ACK;      
+      goto tcp_send_nodata;
+    }
+
+    /* Check the URG flag. If this is set, the segment carries urgent
+       data that we must pass to the application. */
+    if(BUF->flags & TCP_URG) {
+#if UIP_URGDATA > 0
+      uip_urglen = (BUF->urgp[0] << 8) | BUF->urgp[1];
+      if(uip_urglen > uip_len) {
+	/* There is more urgent data in the next segment to come. */
+	uip_urglen = uip_len;
+      }
+      uip_add_rcv_nxt(uip_urglen);
+      uip_len -= uip_urglen;
+      uip_urgdata = uip_appdata;
+      uip_appdata += uip_urglen;
+    } else {
+      uip_urglen = 0;
+#endif /* UIP_URGDATA > 0 */
+      uip_appdata += (BUF->urgp[0] << 8) | BUF->urgp[1];
+      uip_len -= (BUF->urgp[0] << 8) | BUF->urgp[1];
+    }
+    
+    
+    /* If uip_len > 0 we have TCP data in the packet, and we flag this
+       by setting the UIP_NEWDATA flag and update the sequence number
+       we acknowledge. If the application has stopped the dataflow
+       using uip_stop(), we must not accept any data packets from the
+       remote host. */
+    if(uip_len > 0 && !(uip_connr->tcpstateflags & UIP_STOPPED)) {
+      uip_flags |= UIP_NEWDATA;
+      uip_add_rcv_nxt(uip_len);
+    }
+
+    /* Check if the available buffer space advertised by the other end
+       is smaller than the initial MSS for this connection. If so, we
+       set the current MSS to the window size to ensure that the
+       application does not send more data than the other end can
+       handle.
+
+       If the remote host advertises a zero window, we set the MSS to
+       the initial MSS so that the application will send an entire MSS
+       of data. This data will not be acknowledged by the receiver,
+       and the application will retransmit it. This is called the
+       "persistent timer" and uses the retransmission mechanim.
+    */
+    tmp16 = ((unsigned short int)BUF->wnd[0] << 8) + (unsigned short int)BUF->wnd[1];
+    if(tmp16 > uip_connr->initialmss ||
+       tmp16 == 0) {
+      tmp16 = uip_connr->initialmss;
+    }
+    uip_connr->mss = tmp16;
+
+    /* If this packet constitutes an ACK for outstanding data (flagged
+       by the UIP_ACKDATA flag, we should call the application since it
+       might want to send more data. If the incoming packet had data
+       from the peer (as flagged by the UIP_NEWDATA flag), the
+       application must also be notified.
+
+       When the application is called, the global variable uip_len
+       contains the length of the incoming data. The application can
+       access the incoming data through the global pointer
+       uip_appdata, which usually points 40 bytes into the uip_buf
+       array.
+
+       If the application wishes to send any data, this data should be
+       put into the uip_appdata and the length of the data should be
+       put into uip_len. If the application don't have any data to
+       send, uip_len must be set to 0. */
+	if(uip_flags & (UIP_NEWDATA | UIP_ACKDATA)) {
+      uip_slen = 0;
+      UIP_APPCALL();
+
+    appsend:
+      
+	  if(uip_flags & UIP_ABORT) {
+	uip_slen = 0;
+	uip_connr->tcpstateflags = CLOSED;
+	BUF->flags = TCP_RST | TCP_ACK;
+	goto tcp_send_nodata;
+      }
+
+      if(uip_flags & UIP_CLOSE) {
+	uip_slen = 0;
+	uip_connr->len = 1;
+	uip_connr->tcpstateflags = FIN_WAIT_1;
+	uip_connr->nrtx = 0;
+	BUF->flags = TCP_FIN | TCP_ACK;
+	goto tcp_send_nodata;	
+      }
+
+	  /* If uip_slen > 0, the application has data to be sent. */
+      if(uip_slen > 0) {
+
+	/* If the connection has acknowledged data, the contents of
+	   the ->len variable should be discarded. */ 
+	if((uip_flags & UIP_ACKDATA) != 0) {
+	  uip_connr->len = 0;
+	}
+
+	/* If the ->len variable is non-zero the connection has
+	   already data in transit and cannot send anymore right
+	   now. */
+	if(uip_connr->len == 0) {
+
+	  /* The application cannot send more than what is allowed by
+	     the mss (the minumum of the MSS and the available
+	     window). */
+	  if(uip_slen > uip_connr->mss) {
+		uip_slen = uip_connr->mss;
+	  }
+
+	  /* Remember how much data we send out now so that we know
+	     when everything has been acknowledged. */
+	  uip_connr->len = uip_slen;
+	} else {
+
+	  /* If the application already had unacknowledged data, we
+	     make sure that the application does not send (i.e.,
+	     retransmit) out more than it previously sent out. */
+	  uip_slen = uip_connr->len;
+	}
+      } else {
+	uip_connr->len = 0;
+      }
+      uip_connr->nrtx = 0;
+    apprexmit:
+      uip_appdata = uip_sappdata;
+
+      /* If the application has data to be sent, or if the incoming
+         packet had new data in it, we must send out a packet. */
+      if(uip_slen > 0 && uip_connr->len > 0) {
+	/* Add the length of the IP and TCP headers. */
+	uip_len = uip_connr->len + UIP_TCPIP_HLEN;
+	/* We always set the ACK flag in response packets. */
+	BUF->flags = TCP_ACK | TCP_PSH;
+	/* Send the packet. */
+	goto tcp_send_noopts;
+      }
+      /* If there is no data to send, just send out a pure ACK if
+	 there is newdata. */
+      if(uip_flags & UIP_NEWDATA) {
+	uip_len = UIP_TCPIP_HLEN;
+	BUF->flags = TCP_ACK;
+	goto tcp_send_noopts;
+      }
+    }
+	goto drop;
+  case LAST_ACK:
+    /* We can close this connection if the peer has acknowledged our
+       FIN. This is indicated by the UIP_ACKDATA flag. */     
+    if(uip_flags & UIP_ACKDATA) {
+      uip_connr->tcpstateflags = CLOSED;
+      uip_flags = UIP_CLOSE;
+      UIP_APPCALL();
+    }
+    break;
+    
+  case FIN_WAIT_1:
+    /* The application has closed the connection, but the remote host
+       hasn't closed its end yet. Thus we do nothing but wait for a
+       FIN from the other side. */
+    if(uip_len > 0) {
+      uip_add_rcv_nxt(uip_len);
+    }
+    if(BUF->flags & TCP_FIN) {
+      if(uip_flags & UIP_ACKDATA) {
+	uip_connr->tcpstateflags = TIME_WAIT;
+	uip_connr->timer = 0;
+	uip_connr->len = 0;
+      } else {
+	uip_connr->tcpstateflags = CLOSING;
+      }
+      uip_add_rcv_nxt(1);
+      uip_flags = UIP_CLOSE;
+      UIP_APPCALL();
+      goto tcp_send_ack;
+    } else if(uip_flags & UIP_ACKDATA) {
+      uip_connr->tcpstateflags = FIN_WAIT_2;
+      uip_connr->len = 0;
+      goto drop;
+    }
+    if(uip_len > 0) {
+      goto tcp_send_ack;
+    }
+    goto drop;
+      
+  case FIN_WAIT_2:
+    if(uip_len > 0) {
+      uip_add_rcv_nxt(uip_len);
+    }
+    if(BUF->flags & TCP_FIN) {
+      uip_connr->tcpstateflags = TIME_WAIT;
+      uip_connr->timer = 0;
+      uip_add_rcv_nxt(1);
+      uip_flags = UIP_CLOSE;
+      UIP_APPCALL();
+      goto tcp_send_ack;
+    }
+    if(uip_len > 0) {
+      goto tcp_send_ack;
+    }
+    goto drop;
+
+  case TIME_WAIT:
+    goto tcp_send_ack;
+    
+  case CLOSING:
+    if(uip_flags & UIP_ACKDATA) {
+      uip_connr->tcpstateflags = TIME_WAIT;
+      uip_connr->timer = 0;
+    }
+  }  
+  goto drop;
+  
+
+  /* We jump here when we are ready to send the packet, and just want
+     to set the appropriate TCP sequence numbers in the TCP header. */
+ tcp_send_ack:
+  BUF->flags = TCP_ACK;
+ tcp_send_nodata:
+  uip_len = 40;
+ tcp_send_noopts:
+  BUF->tcpoffset = 5 << 4;
+ tcp_send:
+  /* We're done with the input processing. We are now ready to send a
+     reply. Our job is to fill in all the fields of the TCP and IP
+     headers before calculating the checksum and finally send the
+     packet. */
+  BUF->ackno[0] = uip_connr->rcv_nxt[0];
+  BUF->ackno[1] = uip_connr->rcv_nxt[1];
+  BUF->ackno[2] = uip_connr->rcv_nxt[2];
+  BUF->ackno[3] = uip_connr->rcv_nxt[3];
+  
+  BUF->seqno[0] = uip_connr->snd_nxt[0];
+  BUF->seqno[1] = uip_connr->snd_nxt[1];
+  BUF->seqno[2] = uip_connr->snd_nxt[2];
+  BUF->seqno[3] = uip_connr->snd_nxt[3];
+
+  BUF->proto = UIP_PROTO_TCP;
+  
+  BUF->srcport  = uip_connr->lport;
+  BUF->destport = uip_connr->rport;
+
+  BUF->srcipaddr[0] = uip_hostaddr[0];
+  BUF->srcipaddr[1] = uip_hostaddr[1];
+  BUF->destipaddr[0] = uip_connr->ripaddr[0];
+  BUF->destipaddr[1] = uip_connr->ripaddr[1];
+ 
+
+  if(uip_connr->tcpstateflags & UIP_STOPPED) {
+    /* If the connection has issued uip_stop(), we advertise a zero
+       window so that the remote host will stop sending data. */
+    BUF->wnd[0] = BUF->wnd[1] = 0;
+  } else {
+    BUF->wnd[0] = ((UIP_RECEIVE_WINDOW) >> 8);
+    BUF->wnd[1] = ((UIP_RECEIVE_WINDOW) & 0xff); 
+  }
+
+ tcp_send_noconn:
+
+  BUF->len[0] = (uip_len >> 8);
+  BUF->len[1] = (uip_len & 0xff);
+
+  /* Calculate TCP checksum. */
+  BUF->tcpchksum = 0;
+  BUF->tcpchksum = ~(uip_tcpchksum());
+  
+ //ip_send_nolen:
+
+  BUF->vhl = 0x45;
+  BUF->tos = 0;
+  BUF->ipoffset[0] = BUF->ipoffset[1] = 0;
+  BUF->ttl  = UIP_TTL;
+  ++ipid;
+  BUF->ipid[0] = ipid >> 8;
+  BUF->ipid[1] = ipid & 0xff;
+  
+  /* Calculate IP checksum. */
+  BUF->ipchksum = 0;
+  BUF->ipchksum = ~(uip_ipchksum());
+
+  UIP_STAT(++uip_stat.tcp.sent);
+ send:
+  UIP_STAT(++uip_stat.ip.sent);
+  /* Return and let the caller do the actual transmission. */
+  return;
+ drop:
+  uip_len = 0;
+  return;
+}
+/*-----------------------------------------------------------------------------------*/
+/*unsigned short int
+htons(unsigned short int val)
+{
+  return HTONS(val);
+}*/
+/*-----------------------------------------------------------------------------------*/
+/** @} */
--- /dev/null
+++ b/net/uip-0.9/uip.h
@@ -0,0 +1,1066 @@
+/**
+ * \addtogroup uip
+ * @{
+ */
+
+/**
+ * \file
+ * Header file for the uIP TCP/IP stack.
+ * \author Adam Dunkels <adam@dunkels.com>
+ *
+ * The uIP TCP/IP stack header file contains definitions for a number
+ * of C macros that are used by uIP programs as well as internal uIP
+ * structures, TCP/IP header structures and function declarations.
+ *
+ */
+
+
+/*
+ * Copyright (c) 2001-2003, Adam Dunkels.
+ * 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. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.  
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.  
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: uip.h,v 1.36.2.7 2003/10/07 13:47:51 adam Exp $
+ *
+ */
+
+#ifndef __UIP_H__
+#define __UIP_H__
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <malloc.h>
+#include <common.h>
+
+
+#include "uipopt.h"
+
+/*-----------------------------------------------------------------------------------*/
+/* First, the functions that should be called from the
+ * system. Initialization, the periodic timer and incoming packets are
+ * handled by the following three functions.
+ */
+
+/**
+ * \defgroup uipconffunc uIP configuration functions
+ * @{
+ *
+ * The uIP configuration functions are used for setting run-time
+ * parameters in uIP such as IP addresses. 
+ */
+
+/**
+ * Set the IP address of this host.
+ *
+ * The IP address is represented as a 4-byte array where the first
+ * octet of the IP address is put in the first member of the 4-byte
+ * array.
+ *
+ * \param addr A pointer to a 4-byte representation of the IP address.
+ *
+ * \hideinitializer
+ */
+#define uip_sethostaddr(addr) do { uip_hostaddr[0] = addr[0]; \
+                              uip_hostaddr[1] = addr[1]; } while(0)
+
+/**
+ * Get the IP address of this host.
+ *
+ * The IP address is represented as a 4-byte array where the first
+ * octet of the IP address is put in the first member of the 4-byte
+ * array.
+ *
+ * \param addr A pointer to a 4-byte array that will be filled in with
+ * the currently configured IP address.
+ *
+ * \hideinitializer
+ */
+#define uip_gethostaddr(addr) do { addr[0] = uip_hostaddr[0]; \
+                              addr[1] = uip_hostaddr[1]; } while(0)
+
+/** @} */
+
+/**
+ * \defgroup uipinit uIP initialization functions
+ * @{
+ *
+ * The uIP initialization functions are used for booting uIP.
+ */
+
+/**
+ * uIP initialization function.
+ *
+ * This function should be called at boot up to initilize the uIP
+ * TCP/IP stack.
+ */
+void uip_init(void);
+
+/** @} */
+
+/**
+ * \defgroup uipdevfunc uIP device driver functions
+ * @{
+ *
+ * These functions are used by a network device driver for interacting
+ * with uIP.
+ */
+
+/**
+ * Process an incoming packet.
+ *
+ * This function should be called when the device driver has received
+ * a packet from the network. The packet from the device driver must
+ * be present in the uip_buf buffer, and the length of the packet
+ * should be placed in the uip_len variable.
+ *
+ * When the function returns, there may be an outbound packet placed
+ * in the uip_buf packet buffer. If so, the uip_len variable is set to
+ * the length of the packet. If no packet is to be sent out, the
+ * uip_len variable is set to 0.
+ *
+ * The usual way of calling the function is presented by the source
+ * code below.
+ \code
+  uip_len = devicedriver_poll();
+  if(uip_len > 0) {
+    uip_input();
+    if(uip_len > 0) {
+      devicedriver_send();
+    }
+  }
+ \endcode
+ *
+ * \note If you are writing a uIP device driver that needs ARP
+ * (Address Resolution Protocol), e.g., when running uIP over
+ * Ethernet, you will need to call the uIP ARP code before calling
+ * this function:
+ \code
+  #define BUF ((struct uip_eth_hdr *)&uip_buf[0])
+  uip_len = ethernet_devicedrver_poll();
+  if(uip_len > 0) {
+    if(BUF->type == HTONS(UIP_ETHTYPE_IP)) {
+      uip_arp_ipin();
+      uip_input();
+      if(uip_len > 0) {
+        uip_arp_out();
+	ethernet_devicedriver_send();
+      }
+    } else if(BUF->type == HTONS(UIP_ETHTYPE_ARP)) {
+      uip_arp_arpin();
+      if(uip_len > 0) {
+	ethernet_devicedriver_send();
+      }
+    }
+ \endcode
+ *
+ * \hideinitializer
+ */
+#define uip_input()        uip_process(UIP_DATA)
+
+/**
+ * Periodic processing for a connection identified by its number.
+ * 
+ * This function does the necessary periodic processing (timers,
+ * polling) for a uIP TCP conneciton, and should be called when the
+ * periodic uIP timer goes off. It should be called for every
+ * connection, regardless of whether they are open of closed.
+ *
+ * When the function returns, it may have an outbound packet waiting
+ * for service in the uIP packet buffer, and if so the uip_len
+ * variable is set to a value larger than zero. The device driver
+ * should be called to send out the packet.
+ *
+ * The ususal way of calling the function is through a for() loop like
+ * this:
+ \code
+  for(i = 0; i < UIP_CONNS; ++i) {
+    uip_periodic(i);
+    if(uip_len > 0) {
+      devicedriver_send();
+    }
+  }
+ \endcode
+ *
+ * \note If you are writing a uIP device driver that needs ARP
+ * (Address Resolution Protocol), e.g., when running uIP over
+ * Ethernet, you will need to call the uip_arp_out() function before
+ * calling the device driver:
+ \code
+  for(i = 0; i < UIP_CONNS; ++i) {
+    uip_periodic(i);
+    if(uip_len > 0) {
+      uip_arp_out();
+      ethernet_devicedriver_send();
+    }
+  }
+ \endcode 
+ *
+ * \param conn The number of the connection which is to be periodically polled.
+ *
+ * \hideinitializer
+ */
+#define uip_periodic(conn) do { uip_conn = &uip_conns[conn]; \
+                                uip_process(UIP_TIMER); } while (0)
+
+/**
+ * Periodic processing for a connection identified by a pointer to its structure.
+ *
+ * Same as uip_periodic() but takes a pointer to the actual uip_conn
+ * struct instead of an integer as its argument. This function can be
+ * used to force periodic processing of a specific connection.
+ *
+ * \param conn A pointer to the uip_conn struct for the connection to
+ * be processed.
+ *
+ * \hideinitializer
+ */
+#define uip_periodic_conn(conn) do { uip_conn = conn; \
+                                     uip_process(UIP_TIMER); } while (0)
+
+#if UIP_UDP
+/**
+ * Periodic processing for a UDP connection identified by its number.
+ *
+ * This function is essentially the same as uip_prerioic(), but for
+ * UDP connections. It is called in a similar fashion as the
+ * uip_periodic() function:
+ \code
+  for(i = 0; i < UIP_UDP_CONNS; i++) {
+    uip_udp_periodic(i);
+    if(uip_len > 0) {
+      devicedriver_send();
+    }
+  }   
+ \endcode
+ *
+ * \note As for the uip_periodic() function, special care has to be
+ * taken when using uIP together with ARP and Ethernet:
+ \code
+  for(i = 0; i < UIP_UDP_CONNS; i++) {
+    uip_udp_periodic(i);
+    if(uip_len > 0) {
+      uip_arp_out();
+      ethernet_devicedriver_send();
+    }
+  }   
+ \endcode
+ *
+ * \param conn The number of the UDP connection to be processed.
+ *
+ * \hideinitializer
+ */
+#define uip_udp_periodic(conn) do { uip_udp_conn = &uip_udp_conns[conn]; \
+                                uip_process(UIP_UDP_TIMER); } while (0)
+
+/**
+ * Periodic processing for a UDP connection identified by a pointer to
+ * its structure.
+ *
+ * Same as uip_udp_periodic() but takes a pointer to the actual
+ * uip_conn struct instead of an integer as its argument. This
+ * function can be used to force periodic processing of a specific
+ * connection.
+ *
+ * \param conn A pointer to the uip_udp_conn struct for the connection
+ * to be processed.
+ *
+ * \hideinitializer
+ */
+#define uip_udp_periodic_conn(conn) do { uip_udp_conn = conn; \
+                                         uip_process(UIP_UDP_TIMER); } while (0)
+
+
+#endif /* UIP_UDP */
+
+/**
+ * The uIP packet buffer.
+ *
+ * The uip_buf array is used to hold incoming and outgoing
+ * packets. The device driver should place incoming data into this
+ * buffer. When sending data, the device driver should read the link
+ * level headers and the TCP/IP headers from this buffer. The size of
+ * the link level headers is configured by the UIP_LLH_LEN define.
+ *
+ * \note The application data need not be placed in this buffer, so
+ * the device driver must read it from the place pointed to by the
+ * uip_appdata pointer as illustrated by the following example:
+ \code
+ void
+ devicedriver_send(void)
+ {
+    hwsend(&uip_buf[0], UIP_LLH_LEN);
+    hwsend(&uip_buf[UIP_LLH_LEN], 40);
+    hwsend(uip_appdata, uip_len - 40 - UIP_LLH_LEN);
+ }
+ \endcode
+ */
+extern u8_t uip_buf[UIP_BUFSIZE+2];
+
+/** @} */
+
+/*-----------------------------------------------------------------------------------*/
+/* Functions that are used by the uIP application program. Opening and
+ * closing connections, sending and receiving data, etc. is all
+ * handled by the functions below.
+*/
+/**
+ * \defgroup uipappfunc uIP application functions
+ * @{
+ *
+ * Functions used by an application running of top of uIP.
+ */
+
+/**
+ * Start listening to the specified port.
+ *
+ * \note Since this function expects the port number in network byte
+ * order, a conversion using HTONS() or htons() is necessary.
+ *
+ \code
+ uip_listen(HTONS(80)); 
+ \endcode
+ *
+ * \param port A 16-bit port number in network byte order.
+ */
+void uip_listen(u16_t port);
+
+/**
+ * Stop listening to the specified port.
+ *
+ * \note Since this function expects the port number in network byte
+ * order, a conversion using HTONS() or htons() is necessary.
+ *
+ \code
+ uip_unlisten(HTONS(80)); 
+ \endcode
+ *
+ * \param port A 16-bit port number in network byte order.
+ */
+void uip_unlisten(u16_t port);
+
+/**
+ * Connect to a remote host using TCP.
+ *
+ * This function is used to start a new connection to the specified
+ * port on the specied host. It allocates a new connection identifier,
+ * sets the connection to the SYN_SENT state and sets the
+ * retransmission timer to 0. This will cause a TCP SYN segment to be
+ * sent out the next time this connection is periodically processed,
+ * which usually is done within 0.5 seconds after the call to
+ * uip_connect().
+ *
+ * \note This function is avaliable only if support for active open
+ * has been configured by defining UIP_ACTIVE_OPEN to 1 in uipopt.h.
+ *
+ * \note Since this function requires the port number to be in network
+ * byte order, a convertion using HTONS() or htons() is necessary.
+ *
+ \code
+ u16_t ipaddr[2];
+
+ uip_ipaddr(ipaddr, 192,168,1,2);
+ uip_connect(ipaddr, HTONS(80)); 
+ \endcode
+ * 
+ * \param ripaddr A pointer to a 4-byte array representing the IP
+ * address of the remote hot.
+ *
+ * \param port A 16-bit port number in network byte order.
+ *
+ * \return A pointer to the uIP connection identifier for the new connection,
+ * or NULL if no connection could be allocated.   
+ *
+ */
+struct uip_conn *uip_connect(u16_t *ripaddr, u16_t port);
+
+
+
+/**
+ * \internal
+ *
+ * Check if a connection has outstanding (i.e., unacknowledged) data.
+ *
+ * \param conn A pointer to the uip_conn structure for the connection.
+ *
+ * \hideinitializer
+ */
+#define uip_outstanding(conn) ((conn)->len)
+
+/**
+ * Send data on the current connection.
+ *
+ * This function is used to send out a single segment of TCP
+ * data. Only applications that have been invoked by uIP for event
+ * processing can send data. 
+ *
+ * The amount of data that actually is sent out after a call to this
+ * funcion is determined by the maximum amount of data TCP allows. uIP
+ * will automatically crop the data so that only the appropriate
+ * amount of data is sent. The function uip_mss() can be used to query
+ * uIP for the amount of data that actually will be sent.
+ * 
+ * \note This function does not guarantee that the sent data will
+ * arrive at the destination. If the data is lost in the network, the
+ * application will be invoked with the uip_rexmit() event being
+ * set. The application will then have to resend the data using this
+ * function.
+ * 
+ * \param data A pointer to the data which is to be sent.
+ *
+ * \param len The maximum amount of data bytes to be sent.
+ *
+ * \hideinitializer
+ */
+#define uip_send(data, len) do { uip_sappdata = (data); uip_slen = (len);} while(0)   
+
+/**
+ * The length of any incoming data that is currently avaliable (if avaliable)
+ * in the uip_appdata buffer.
+ *
+ * The test function uip_data() must first be used to check if there
+ * is any data available at all.
+ *
+ * \hideinitializer
+ */
+#define uip_datalen()       uip_len
+
+/**
+ * The length of any out-of-band data (urgent data) that has arrived
+ * on the connection.
+ *
+ * \note The configuration parameter UIP_URGDATA must be set for this
+ * function to be enabled.
+ *
+ * \hideinitializer
+ */
+#define uip_urgdatalen()    uip_urglen
+
+/**
+ * Close the current connection.
+ *
+ * This function will close the current connection in a nice way.
+ *
+ * \hideinitializer
+ */
+#define uip_close()         (uip_flags = UIP_CLOSE)
+
+/**
+ * Abort the current connection.
+ *
+ * This function will abort (reset) the current connection, and is
+ * usually used when an error has occured that prevents using the
+ * uip_close() function.
+ *
+ * \hideinitializer
+ */
+#define uip_abort()         (uip_flags = UIP_ABORT)
+
+/**
+ * Tell the sending host to stop sending data.
+ *
+ * This function will close our receiver's window so that we stop
+ * receiving data for the current connection.
+ *
+ * \hideinitializer
+ */
+#define uip_stop()          (uip_conn->tcpstateflags |= UIP_STOPPED)
+
+/**
+ * Find out if the current connection has been previously stopped with
+ * uip_stop().
+ *
+ * \hideinitializer
+ */
+#define uip_stopped(conn)   ((conn)->tcpstateflags & UIP_STOPPED)
+
+/**
+ * Restart the current connection, if is has previously been stopped
+ * with uip_stop().
+ *
+ * This function will open the receiver's window again so that we
+ * start receiving data for the current connection.
+ *
+ * \hideinitializer
+ */
+#define uip_restart()         do { uip_flags |= UIP_NEWDATA; \
+                                   uip_conn->tcpstateflags &= ~UIP_STOPPED; \
+                              } while(0)
+
+
+/* uIP tests that can be made to determine in what state the current
+   connection is, and what the application function should do. */
+
+/**
+ * Is new incoming data available?
+ *
+ * Will reduce to non-zero if there is new data for the application
+ * present at the uip_appdata pointer. The size of the data is
+ * avaliable through the uip_len variable.
+ *
+ * \hideinitializer
+ */
+#define uip_newdata()   (uip_flags & UIP_NEWDATA)
+
+/**
+ * Has previously sent data been acknowledged?
+ *
+ * Will reduce to non-zero if the previously sent data has been
+ * acknowledged by the remote host. This means that the application
+ * can send new data. 
+ *
+ * \hideinitializer
+ */
+#define uip_acked()   (uip_flags & UIP_ACKDATA)
+
+/**
+ * Has the connection just been connected?  
+ *
+ * Reduces to non-zero if the current connection has been connected to
+ * a remote host. This will happen both if the connection has been
+ * actively opened (with uip_connect()) or passively opened (with
+ * uip_listen()).
+ *
+ * \hideinitializer
+ */
+#define uip_connected() (uip_flags & UIP_CONNECTED)
+
+/**
+ * Has the connection been closed by the other end?
+ *
+ * Is non-zero if the connection has been closed by the remote
+ * host. The application may then do the necessary clean-ups.
+ *
+ * \hideinitializer
+ */
+#define uip_closed()    (uip_flags & UIP_CLOSE)
+
+/**
+ * Has the connection been aborted by the other end?
+ *
+ * Non-zero if the current connection has been aborted (reset) by the
+ * remote host.
+ *
+ * \hideinitializer
+ */
+#define uip_aborted()    (uip_flags & UIP_ABORT)
+
+/**
+ * Has the connection timed out?
+ *
+ * Non-zero if the current connection has been aborted due to too many
+ * retransmissions.
+ *
+ * \hideinitializer
+ */
+#define uip_timedout()    (uip_flags & UIP_TIMEDOUT)
+
+/**
+ * Do we need to retransmit previously data?
+ *
+ * Reduces to non-zero if the previously sent data has been lost in
+ * the network, and the application should retransmit it. The
+ * application should send the exact same data as it did the last
+ * time, using the uip_send() function.
+ *
+ * \hideinitializer
+ */
+#define uip_rexmit()     (uip_flags & UIP_REXMIT)
+
+/**
+ * Is the connection being polled by uIP?
+ *
+ * Is non-zero if the reason the application is invoked is that the
+ * current connection has been idle for a while and should be
+ * polled.
+ *
+ * The polling event can be used for sending data without having to
+ * wait for the remote host to send data.
+ *
+ * \hideinitializer
+ */ 
+#define uip_poll()       (uip_flags & UIP_POLL)
+
+/**
+ * Get the initial maxium segment size (MSS) of the current
+ * connection.
+ *
+ * \hideinitializer
+ */
+#define uip_initialmss()             (uip_conn->initialmss)
+
+/**
+ * Get the current maxium segment size that can be sent on the current
+ * connection.
+ *
+ * The current maxiumum segment size that can be sent on the
+ * connection is computed from the receiver's window and the MSS of
+ * the connection (which also is available by calling
+ * uip_initialmss()).
+ *
+ * \hideinitializer
+ */
+#define uip_mss()             (uip_conn->mss)
+
+/**
+ * Set up a new UDP connection.
+ *
+ * \param ripaddr A pointer to a 4-byte structure representing the IP
+ * address of the remote host.
+ *
+ * \param rport The remote port number in network byte order.
+ *
+ * \return The uip_udp_conn structure for the new connection or NULL
+ * if no connection could be allocated.
+ */
+struct uip_udp_conn *uip_udp_new(u16_t *ripaddr, u16_t rport);
+
+/**
+ * Removed a UDP connection.
+ *
+ * \param conn A pointer to the uip_udp_conn structure for the connection.
+ *
+ * \hideinitializer
+ */
+#define uip_udp_remove(conn) (conn)->lport = 0
+
+/**
+ * Send a UDP datagram of length len on the current connection.
+ *
+ * This function can only be called in response to a UDP event (poll
+ * or newdata). The data must be present in the uip_buf buffer, at the
+ * place pointed to by the uip_appdata pointer.
+ *
+ * \param len The length of the data in the uip_buf buffer.
+ *
+ * \hideinitializer
+ */
+#define uip_udp_send(len) uip_slen = (len)
+
+/** @} */
+
+/* uIP convenience and converting functions. */
+
+/**
+ * \defgroup uipconvfunc uIP conversion functions
+ * @{
+ *
+ * These functions can be used for converting between different data
+ * formats used by uIP.
+ */
+ 
+/**
+ * Pack an IP address into a 4-byte array which is used by uIP to
+ * represent IP addresses.
+ *
+ * Example:
+ \code
+ u16_t ipaddr[2];
+
+ uip_ipaddr(&ipaddr, 192,168,1,2); 
+ \endcode
+ *
+ * \param addr A pointer to a 4-byte array that will be filled in with
+ * the IP addres.
+ * \param addr0 The first octet of the IP address.
+ * \param addr1 The second octet of the IP address.
+ * \param addr2 The third octet of the IP address.
+ * \param addr3 The forth octet of the IP address. 
+ *
+ * \hideinitializer
+ */
+#define uip_ipaddr(addr, addr0,addr1,addr2,addr3) do { \
+                     (addr)[0] = HTONS(((addr0) << 8) | (addr1)); \
+                     (addr)[1] = HTONS(((addr2) << 8) | (addr3)); \
+                  } while(0)
+
+/**
+ * Convert 16-bit quantity from host byte order to network byte order.
+ *
+ * This macro is primarily used for converting constants from host
+ * byte order to network byte order. For converting variables to
+ * network byte order, use the htons() function instead.
+ *
+ * \hideinitializer
+ */
+#ifndef HTONS
+#   if BYTE_ORDER == BIG_ENDIAN
+#      define HTONS(n) (n)
+#   else /* BYTE_ORDER == BIG_ENDIAN */
+#      define HTONS(n) ((((u16_t)((n) & 0xff)) << 8) | (((n) & 0xff00) >> 8))
+#   endif /* BYTE_ORDER == BIG_ENDIAN */
+#endif /* HTONS */
+
+/**
+ * Convert 16-bit quantity from host byte order to network byte order.
+ *
+ * This function is primarily used for converting variables from host
+ * byte order to network byte order. For converting constants to
+ * network byte order, use the HTONS() macro instead.
+ */
+#ifndef htons
+u16_t htons(u16_t val);
+#endif /* htons */
+
+/** @} */
+
+/**
+ * Pointer to the application data in the packet buffer.
+ *
+ * This pointer points to the application data when the application is
+ * called. If the application wishes to send data, the application may
+ * use this space to write the data into before calling uip_send().
+ */
+extern volatile u8_t *uip_appdata;
+extern volatile u8_t *uip_sappdata; 
+
+#if UIP_URGDATA > 0 
+/* u8_t *uip_urgdata:
+ *
+ * This pointer points to any urgent data that has been received. Only
+ * present if compiled with support for urgent data (UIP_URGDATA).
+ */
+extern volatile u8_t *uip_urgdata; 
+#endif /* UIP_URGDATA > 0 */
+
+
+/* u[8|16]_t uip_len:
+ *
+ * When the application is called, uip_len contains the length of any
+ * new data that has been received from the remote host. The
+ * application should set this variable to the size of any data that
+ * the application wishes to send. When the network device driver
+ * output function is called, uip_len should contain the length of the
+ * outgoing packet.
+ */
+extern volatile u16_t uip_len, uip_slen;
+
+#if UIP_URGDATA > 0 
+extern volatile u8_t uip_urglen, uip_surglen;
+#endif /* UIP_URGDATA > 0 */
+
+
+/**
+ * Representation of a uIP TCP connection.
+ *
+ * The uip_conn structure is used for identifying a connection. All
+ * but one field in the structure are to be considered read-only by an
+ * application. The only exception is the appstate field whos purpose
+ * is to let the application store application-specific state (e.g.,
+ * file pointers) for the connection. The size of this field is
+ * configured in the "uipopt.h" header file.
+ */
+struct uip_conn {
+  u16_t ripaddr[2];   /**< The IP address of the remote host. */
+  
+  u16_t lport;        /**< The local TCP port, in network byte order. */
+  u16_t rport;        /**< The local remote TCP port, in network byte
+			 order. */  
+  
+  u8_t rcv_nxt[4];    /**< The sequence number that we expect to
+			 receive next. */
+  u8_t snd_nxt[4];    /**< The sequence number that was last sent by
+                         us. */
+  u16_t len;          /**< Length of the data that was previously sent. */
+  u16_t mss;          /**< Current maximum segment size for the
+			 connection. */
+  u16_t initialmss;   /**< Initial maximum segment size for the
+			 connection. */  
+  u8_t sa;            /**< Retransmission time-out calculation state
+			 variable. */
+  u8_t sv;            /**< Retransmission time-out calculation state
+			 variable. */
+  u8_t rto;           /**< Retransmission time-out. */
+  u8_t tcpstateflags; /**< TCP state and flags. */
+  u8_t timer;         /**< The retransmission timer. */
+  u8_t nrtx;          /**< The number of retransmissions for the last
+			 segment sent. */
+
+  /** The application state. */
+  u8_t appstate[UIP_APPSTATE_SIZE];  
+};
+
+
+/* Pointer to the current connection. */
+extern struct uip_conn *uip_conn;
+/* The array containing all uIP connections. */
+extern struct uip_conn uip_conns[UIP_CONNS];
+/**
+ * \addtogroup uiparch
+ * @{
+ */
+
+/**
+ * 4-byte array used for the 32-bit sequence number calculations.
+ */
+extern volatile u8_t uip_acc32[4];
+
+/** @} */
+
+
+#if UIP_UDP
+/**
+ * Representation of a uIP UDP connection.
+ */
+struct uip_udp_conn {
+  u16_t ripaddr[2];   /**< The IP address of the remote peer. */
+  u16_t lport;        /**< The local port number in network byte order. */
+  u16_t rport;        /**< The remote port number in network byte order. */
+};
+
+extern struct uip_udp_conn *uip_udp_conn;
+extern struct uip_udp_conn uip_udp_conns[UIP_UDP_CONNS];
+#endif /* UIP_UDP */
+
+/**
+ * The structure holding the TCP/IP statistics that are gathered if
+ * UIP_STATISTICS is set to 1.
+ *
+ */
+struct uip_stats {
+  struct {
+    uip_stats_t drop;     /**< Number of dropped packets at the IP
+			     layer. */
+    uip_stats_t recv;     /**< Number of received packets at the IP
+			     layer. */
+    uip_stats_t sent;     /**< Number of sent packets at the IP
+			     layer. */
+    uip_stats_t vhlerr;   /**< Number of packets dropped due to wrong
+			     IP version or header length. */
+    uip_stats_t hblenerr; /**< Number of packets dropped due to wrong
+			     IP length, high byte. */
+    uip_stats_t lblenerr; /**< Number of packets dropped due to wrong
+			     IP length, low byte. */
+    uip_stats_t fragerr;  /**< Number of packets dropped since they
+			     were IP fragments. */
+    uip_stats_t chkerr;   /**< Number of packets dropped due to IP
+			     checksum errors. */
+    uip_stats_t protoerr; /**< Number of packets dropped since they
+			     were neither ICMP, UDP nor TCP. */
+  } ip;                   /**< IP statistics. */
+  struct {
+    uip_stats_t drop;     /**< Number of dropped ICMP packets. */
+    uip_stats_t recv;     /**< Number of received ICMP packets. */
+    uip_stats_t sent;     /**< Number of sent ICMP packets. */
+    uip_stats_t typeerr;  /**< Number of ICMP packets with a wrong
+			     type. */
+  } icmp;                 /**< ICMP statistics. */
+  struct {
+    uip_stats_t drop;     /**< Number of dropped TCP segments. */
+    uip_stats_t recv;     /**< Number of recived TCP segments. */
+    uip_stats_t sent;     /**< Number of sent TCP segments. */
+    uip_stats_t chkerr;   /**< Number of TCP segments with a bad
+			     checksum. */
+    uip_stats_t ackerr;   /**< Number of TCP segments with a bad ACK
+			     number. */
+    uip_stats_t rst;      /**< Number of recevied TCP RST (reset) segments. */
+    uip_stats_t rexmit;   /**< Number of retransmitted TCP segments. */
+    uip_stats_t syndrop;  /**< Number of dropped SYNs due to too few
+			     connections was avaliable. */
+    uip_stats_t synrst;   /**< Number of SYNs for closed ports,
+			     triggering a RST. */
+  } tcp;                  /**< TCP statistics. */
+};
+
+/**
+ * The uIP TCP/IP statistics.
+ *
+ * This is the variable in which the uIP TCP/IP statistics are gathered.
+ */
+extern struct uip_stats uip_stat;
+
+
+/*-----------------------------------------------------------------------------------*/
+/* All the stuff below this point is internal to uIP and should not be
+ * used directly by an application or by a device driver.
+ */
+/*-----------------------------------------------------------------------------------*/
+/* u8_t uip_flags:
+ *
+ * When the application is called, uip_flags will contain the flags
+ * that are defined in this file. Please read below for more
+ * infomation.
+ */
+extern volatile u8_t uip_flags;
+
+/* The following flags may be set in the global variable uip_flags
+   before calling the application callback. The UIP_ACKDATA and
+   UIP_NEWDATA flags may both be set at the same time, whereas the
+   others are mutualy exclusive. Note that these flags should *NOT* be
+   accessed directly, but through the uIP functions/macros. */
+
+#define UIP_ACKDATA   1     /* Signifies that the outstanding data was
+			       acked and the application should send
+			       out new data instead of retransmitting
+			       the last data. */
+#define UIP_NEWDATA   2     /* Flags the fact that the peer has sent
+			       us new data. */
+#define UIP_REXMIT    4     /* Tells the application to retransmit the
+			       data that was last sent. */
+#define UIP_POLL      8     /* Used for polling the application, to
+			       check if the application has data that
+			       it wants to send. */
+#define UIP_CLOSE     16    /* The remote host has closed the
+			       connection, thus the connection has
+			       gone away. Or the application signals
+			       that it wants to close the
+			       connection. */
+#define UIP_ABORT     32    /* The remote host has aborted the
+			       connection, thus the connection has
+			       gone away. Or the application signals
+			       that it wants to abort the
+			       connection. */
+#define UIP_CONNECTED 64    /* We have got a connection from a remote
+                               host and have set up a new connection
+                               for it, or an active connection has
+                               been successfully established. */
+
+#define UIP_TIMEDOUT  128   /* The connection has been aborted due to
+			       too many retransmissions. */
+
+
+/* uip_process(flag):
+ *
+ * The actual uIP function which does all the work.
+ */
+void uip_process(u8_t flag);
+
+/* The following flags are passed as an argument to the uip_process()
+   function. They are used to distinguish between the two cases where
+   uip_process() is called. It can be called either because we have
+   incoming data that should be processed, or because the periodic
+   timer has fired. */
+
+#define UIP_DATA    1     /* Tells uIP that there is incoming data in
+                             the uip_buf buffer. The length of the
+                             data is stored in the global variable
+                             uip_len. */
+#define UIP_TIMER   2     /* Tells uIP that the periodic timer has
+                             fired. */
+#if UIP_UDP
+#define UIP_UDP_TIMER 3
+#endif /* UIP_UDP */
+
+/* The TCP states used in the uip_conn->tcpstateflags. */
+#define CLOSED      0
+#define SYN_RCVD    1
+#define SYN_SENT    2
+#define ESTABLISHED 3
+#define FIN_WAIT_1  4
+#define FIN_WAIT_2  5
+#define CLOSING     6
+#define TIME_WAIT   7
+#define LAST_ACK    8
+#define TS_MASK     15
+  
+#define UIP_STOPPED      16
+
+#define UIP_TCPIP_HLEN 40
+
+/* The TCP and IP headers. */
+typedef struct {
+  /* IP header. */
+  u8_t vhl,
+    tos,          
+    len[2],       
+    ipid[2],        
+    ipoffset[2],  
+    ttl,          
+    proto;     
+  u16_t ipchksum;
+  u16_t srcipaddr[2], 
+    destipaddr[2];
+  
+  /* TCP header. */
+  u16_t srcport,
+    destport;
+  u8_t seqno[4],  
+    ackno[4],
+    tcpoffset,
+    flags,
+    wnd[2];     
+  u16_t tcpchksum;
+  u8_t urgp[2];
+  u8_t optdata[4];
+} uip_tcpip_hdr;
+
+/* The ICMP and IP headers. */
+typedef struct {
+  /* IP header. */
+  u8_t vhl,
+    tos,          
+    len[2],       
+    ipid[2],        
+    ipoffset[2],  
+    ttl,          
+    proto;     
+  u16_t ipchksum;
+  u16_t srcipaddr[2], 
+    destipaddr[2];
+  /* ICMP (echo) header. */
+  u8_t type, icode;
+  u16_t icmpchksum;
+  u16_t id, seqno;  
+} uip_icmpip_hdr;
+
+
+/* The UDP and IP headers. */
+typedef struct {
+  /* IP header. */
+  u8_t vhl,
+    tos,          
+    len[2],       
+    ipid[2],        
+    ipoffset[2],  
+    ttl,          
+    proto;     
+  u16_t ipchksum;
+  u16_t srcipaddr[2], 
+    destipaddr[2];
+  
+  /* UDP header. */
+  u16_t srcport,
+    destport;
+  u16_t udplen;
+  u16_t udpchksum;
+} uip_udpip_hdr;
+
+#define UIP_PROTO_ICMP  1
+#define UIP_PROTO_TCP   6
+#define UIP_PROTO_UDP   17
+
+#if UIP_FIXEDADDR
+extern const u16_t uip_hostaddr[2];
+#else /* UIP_FIXEDADDR */
+extern u16_t uip_hostaddr[2];
+#endif /* UIP_FIXEDADDR */
+
+#endif /* __UIP_H__ */
+
+
+/** @} */
+
--- /dev/null
+++ b/net/uip-0.9/uipopt.h
@@ -0,0 +1,557 @@
+/**
+ * \defgroup uipopt Configuration options for uIP
+ * @{
+ *
+ * uIP is configured using the per-project configuration file
+ * "uipopt.h". This file contains all compile-time options for uIP and
+ * should be tweaked to match each specific project. The uIP
+ * distribution contains a documented example "uipopt.h" that can be
+ * copied and modified for each project.
+ */
+
+/**
+ * \file
+ * Configuration options for uIP.
+ * \author Adam Dunkels <adam@dunkels.com>
+ *
+ * This file is used for tweaking various configuration options for
+ * uIP. You should make a copy of this file into one of your project's
+ * directories instead of editing this example "uipopt.h" file that
+ * comes with the uIP distribution.
+ */
+
+/*
+ * Copyright (c) 2001-2003, Adam Dunkels.
+ * 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. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.  
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.  
+ *
+ * This file is part of the uIP TCP/IP stack.
+ *
+ * $Id: uipopt.h,v 1.16.2.5 2003/10/07 13:22:51 adam Exp $
+ *
+ */
+
+#ifndef __UIPOPT_H__
+#define __UIPOPT_H__
+
+/*------------------------------------------------------------------------------*/
+/**
+ * \defgroup uipopttypedef uIP type definitions
+ * @{
+ */
+
+/**
+ * The 8-bit unsigned data type.
+ *
+ * This may have to be tweaked for your particular compiler. "unsigned
+ * char" works for most compilers.
+ */
+typedef unsigned char u8_t;
+
+/**
+ * The 16-bit unsigned data type.
+ *
+ * This may have to be tweaked for your particular compiler. "unsigned
+ * short" works for most compilers.
+ */
+typedef unsigned short u16_t;
+
+/**
+ * The statistics data type.
+ *
+ * This datatype determines how high the statistics counters are able
+ * to count.
+ */
+typedef unsigned short uip_stats_t;
+
+/** @} */
+
+/*------------------------------------------------------------------------------*/
+
+/**
+ * \defgroup uipoptstaticconf Static configuration options
+ * @{
+ *
+ * These configuration options can be used for setting the IP address
+ * settings statically, but only if UIP_FIXEDADDR is set to 1. The
+ * configuration options for a specific node includes IP address,
+ * netmask and default router as well as the Ethernet address. The
+ * netmask, default router and Ethernet address are appliciable only
+ * if uIP should be run over Ethernet.
+ *
+ * All of these should be changed to suit your project.
+*/
+
+/**
+ * Determines if uIP should use a fixed IP address or not.
+ *
+ * If uIP should use a fixed IP address, the settings are set in the
+ * uipopt.h file. If not, the macros uip_sethostaddr(),
+ * uip_setdraddr() and uip_setnetmask() should be used instead.
+ *
+ * \hideinitializer
+ */
+#define UIP_FIXEDADDR    0
+
+/**
+ * Ping IP address asignment.
+ *
+ * uIP uses a "ping" packets for setting its own IP address if this
+ * option is set. If so, uIP will start with an empty IP address and
+ * the destination IP address of the first incoming "ping" (ICMP echo)
+ * packet will be used for setting the hosts IP address.
+ *
+ * \note This works only if UIP_FIXEDADDR is 0.
+ *
+ * \hideinitializer
+ */
+#define UIP_PINGADDRCONF 0
+
+#define UIP_IPADDR0     192 /**< The first octet of the IP address of
+			       this uIP node, if UIP_FIXEDADDR is
+			       1. \hideinitializer */
+#define UIP_IPADDR1     168 /**< The second octet of the IP address of
+			       this uIP node, if UIP_FIXEDADDR is
+			       1. \hideinitializer */
+#define UIP_IPADDR2     0   /**< The third octet of the IP address of
+			       this uIP node, if UIP_FIXEDADDR is
+			       1. \hideinitializer */
+#define UIP_IPADDR3     250   /**< The fourth octet of the IP address of
+			       this uIP node, if UIP_FIXEDADDR is
+			       1. \hideinitializer */
+
+#define UIP_NETMASK0    255 /**< The first octet of the netmask of
+			       this uIP node, if UIP_FIXEDADDR is
+			       1. \hideinitializer */
+#define UIP_NETMASK1    255 /**< The second octet of the netmask of
+			       this uIP node, if UIP_FIXEDADDR is
+			       1. \hideinitializer */
+#define UIP_NETMASK2    255 /**< The third octet of the netmask of
+			       this uIP node, if UIP_FIXEDADDR is
+			       1. \hideinitializer */
+#define UIP_NETMASK3    0   /**< The fourth octet of the netmask of
+			       this uIP node, if UIP_FIXEDADDR is
+			       1. \hideinitializer */
+
+#define UIP_DRIPADDR0   192 /**< The first octet of the IP address of
+			       the default router, if UIP_FIXEDADDR is
+			       1. \hideinitializer */
+#define UIP_DRIPADDR1   168 /**< The second octet of the IP address of
+			       the default router, if UIP_FIXEDADDR is
+			       1. \hideinitializer */
+#define UIP_DRIPADDR2   0   /**< The third octet of the IP address of
+			       the default router, if UIP_FIXEDADDR is
+			       1. \hideinitializer */
+#define UIP_DRIPADDR3   1   /**< The fourth octet of the IP address of
+			       the default router, if UIP_FIXEDADDR is
+			       1. \hideinitializer */
+
+/**
+ * Specifies if the uIP ARP module should be compiled with a fixed
+ * Ethernet MAC address or not.
+ *
+ * If this configuration option is 0, the macro uip_setethaddr() can
+ * be used to specify the Ethernet address at run-time.
+ *
+ * \hideinitializer
+ */
+#define UIP_FIXEDETHADDR 0
+
+#define UIP_ETHADDR0    0x00  /**< The first octet of the Ethernet
+				 address if UIP_FIXEDETHADDR is
+				 1. \hideinitializer */
+#define UIP_ETHADDR1    0xbd  /**< The second octet of the Ethernet
+				 address if UIP_FIXEDETHADDR is
+				 1. \hideinitializer */
+#define UIP_ETHADDR2    0x3b  /**< The third octet of the Ethernet
+				 address if UIP_FIXEDETHADDR is
+				 1. \hideinitializer */
+#define UIP_ETHADDR3    0x33  /**< The fourth octet of the Ethernet
+				 address if UIP_FIXEDETHADDR is
+				 1. \hideinitializer */
+#define UIP_ETHADDR4    0x05  /**< The fifth octet of the Ethernet
+				 address if UIP_FIXEDETHADDR is
+				 1. \hideinitializer */
+#define UIP_ETHADDR5    0x71  /**< The sixth octet of the Ethernet
+				 address if UIP_FIXEDETHADDR is
+				 1. \hideinitializer */
+
+/** @} */
+/*------------------------------------------------------------------------------*/
+/**
+ * \defgroup uipoptip IP configuration options
+ * @{
+ *
+ */
+/**
+ * The IP TTL (time to live) of IP packets sent by uIP.
+ *
+ * This should normally not be changed.
+ */
+#define UIP_TTL         255
+
+/**
+ * Turn on support for IP packet reassembly.
+ *
+ * uIP supports reassembly of fragmented IP packets. This features
+ * requires an additonal amount of RAM to hold the reassembly buffer
+ * and the reassembly code size is approximately 700 bytes.  The
+ * reassembly buffer is of the same size as the uip_buf buffer
+ * (configured by UIP_BUFSIZE).
+ *
+ * \note IP packet reassembly is not heavily tested.
+ *
+ * \hideinitializer
+ */
+#define UIP_REASSEMBLY 0
+
+/**
+ * The maximum time an IP fragment should wait in the reassembly
+ * buffer before it is dropped.
+ *
+ */
+#define UIP_REASS_MAXAGE 40
+
+/** @} */
+
+/*------------------------------------------------------------------------------*/
+/**
+ * \defgroup uipoptudp UDP configuration options
+ * @{
+ *
+ * \note The UDP support in uIP is still not entirely complete; there
+ * is no support for sending or receiving broadcast or multicast
+ * packets, but it works well enough to support a number of vital
+ * applications such as DNS queries, though
+ */
+
+/**
+ * Toggles wether UDP support should be compiled in or not.
+ *
+ * \hideinitializer
+ */
+#define UIP_UDP           0
+
+/**
+ * Toggles if UDP checksums should be used or not.
+ *
+ * \note Support for UDP checksums is currently not included in uIP,
+ * so this option has no function.
+ *
+ * \hideinitializer
+ */
+#define UIP_UDP_CHECKSUMS 0
+
+/**
+ * The maximum amount of concurrent UDP connections.
+ *
+ * \hideinitializer
+ */
+#define UIP_UDP_CONNS    10
+
+/**
+ * The name of the function that should be called when UDP datagrams arrive.
+ *
+ * \hideinitializer
+ */
+#define UIP_UDP_APPCALL  udp_appcall
+
+/** @} */
+/*------------------------------------------------------------------------------*/
+/**
+ * \defgroup uipopttcp TCP configuration options
+ * @{
+ */
+
+/**
+ * Determines if support for opening connections from uIP should be
+ * compiled in.
+ *
+ * If the applications that are running on top of uIP for this project
+ * do not need to open outgoing TCP connections, this configration
+ * option can be turned off to reduce the code size of uIP.
+ *
+ * \hideinitializer
+ */
+#define UIP_ACTIVE_OPEN 1
+
+/**
+ * The maximum number of simultaneously open TCP connections.
+ *
+ * Since the TCP connections are statically allocated, turning this
+ * configuration knob down results in less RAM used. Each TCP
+ * connection requires approximatly 30 bytes of memory.
+ *
+ * \hideinitializer
+ */
+#define UIP_CONNS       10
+
+/**
+ * The maximum number of simultaneously listening TCP ports.
+ *
+ * Each listening TCP port requires 2 bytes of memory.
+ *
+ * \hideinitializer
+ */
+#define UIP_LISTENPORTS 10
+
+/**
+ * The size of the advertised receiver's window.
+ *
+ * Should be set low (i.e., to the size of the uip_buf buffer) is the
+ * application is slow to process incoming data, or high (32768 bytes)
+ * if the application processes data quickly.
+ *
+ * \hideinitializer
+ */
+#define UIP_RECEIVE_WINDOW   32768
+
+/**
+ * Determines if support for TCP urgent data notification should be
+ * compiled in.
+ *
+ * Urgent data (out-of-band data) is a rarely used TCP feature that
+ * very seldom would be required.
+ *
+ * \hideinitializer
+ */
+#define UIP_URGDATA      1
+
+/**
+ * The initial retransmission timeout counted in timer pulses.
+ *
+ * This should not be changed.
+ */
+#define UIP_RTO         3
+
+/**
+ * The maximum number of times a segment should be retransmitted
+ * before the connection should be aborted.
+ *
+ * This should not be changed.
+ */
+#define UIP_MAXRTX      8
+
+/**
+ * The maximum number of times a SYN segment should be retransmitted
+ * before a connection request should be deemed to have been
+ * unsuccessful.
+ *
+ * This should not need to be changed.
+ */
+#define UIP_MAXSYNRTX      3
+
+/**
+ * The TCP maximum segment size.
+ *
+ * This is should not be to set to more than UIP_BUFSIZE - UIP_LLH_LEN - 40.
+ */
+#define UIP_TCP_MSS     (UIP_BUFSIZE - UIP_LLH_LEN - 40)
+
+/**
+ * How long a connection should stay in the TIME_WAIT state.
+ *
+ * This configiration option has no real implication, and it should be
+ * left untouched.
+ */ 
+#define UIP_TIME_WAIT_TIMEOUT 120
+
+
+/** @} */
+/*------------------------------------------------------------------------------*/
+/**
+ * \defgroup uipoptarp ARP configuration options
+ * @{
+ */
+
+/**
+ * The size of the ARP table.
+ *
+ * This option should be set to a larger value if this uIP node will
+ * have many connections from the local network.
+ *
+ * \hideinitializer
+ */
+#define UIP_ARPTAB_SIZE 8
+
+/**
+ * The maxium age of ARP table entries measured in 10ths of seconds.
+ *
+ * An UIP_ARP_MAXAGE of 120 corresponds to 20 minutes (BSD
+ * default).
+ */
+#define UIP_ARP_MAXAGE 120
+
+/** @} */
+
+/*------------------------------------------------------------------------------*/
+
+/**
+ * \defgroup uipoptgeneral General configuration options
+ * @{
+ */
+
+/**
+ * The size of the uIP packet buffer.
+ *
+ * The uIP packet buffer should not be smaller than 60 bytes, and does
+ * not need to be larger than 1500 bytes. Lower size results in lower
+ * TCP throughput, larger size results in higher TCP throughput.
+ *
+ * \hideinitializer
+ */
+#define UIP_BUFSIZE     1500
+
+
+/**
+ * Determines if statistics support should be compiled in.
+ *
+ * The statistics is useful for debugging and to show the user.
+ *
+ * \hideinitializer
+ */
+#define UIP_STATISTICS  1
+
+/**
+ * Determines if logging of certain events should be compiled in.
+ *
+ * This is useful mostly for debugging. The function uip_log()
+ * must be implemented to suit the architecture of the project, if
+ * logging is turned on.
+ *
+ * \hideinitializer
+ */
+#define UIP_LOGGING     0
+
+/**
+ * Print out a uIP log message.
+ *
+ * This function must be implemented by the module that uses uIP, and
+ * is called by uIP whenever a log message is generated.
+ */
+void uip_log(char *msg);
+
+/**
+ * The link level header length.
+ *
+ * This is the offset into the uip_buf where the IP header can be
+ * found. For Ethernet, this should be set to 14. For SLIP, this
+ * should be set to 0.
+ *
+ * \hideinitializer
+ */
+#define UIP_LLH_LEN     14
+
+
+/** @} */
+/*------------------------------------------------------------------------------*/
+/**
+ * \defgroup uipoptcpu CPU architecture configuration
+ * @{
+ *
+ * The CPU architecture configuration is where the endianess of the
+ * CPU on which uIP is to be run is specified. Most CPUs today are
+ * little endian, and the most notable exception are the Motorolas
+ * which are big endian. The BYTE_ORDER macro should be changed to
+ * reflect the CPU architecture on which uIP is to be run.
+ */
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN  3412
+#endif /* LITTLE_ENDIAN */
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN     1234
+#endif /* BIGE_ENDIAN */
+
+/**
+ * The byte order of the CPU architecture on which uIP is to be run.
+ *
+ * This option can be either BIG_ENDIAN (Motorola byte order) or
+ * LITTLE_ENDIAN (Intel byte order).
+ *
+ * \hideinitializer
+ */
+/*#ifndef BYTE_ORDER*/
+#define BYTE_ORDER     BIG_ENDIAN
+/*#endif*/ /* BYTE_ORDER */
+
+/** @} */
+/*------------------------------------------------------------------------------*/
+
+/**
+ * \defgroup uipoptapp Appication specific configurations
+ * @{
+ *
+ * An uIP application is implemented using a single application
+ * function that is called by uIP whenever a TCP/IP event occurs. The
+ * name of this function must be registered with uIP at compile time
+ * using the UIP_APPCALL definition.
+ *
+ * uIP applications can store the application state within the
+ * uip_conn structure by specifying the size of the application
+ * structure with the UIP_APPSTATE_SIZE macro.
+ *
+ * The file containing the definitions must be included in the
+ * uipopt.h file.
+ *
+ * The following example illustrates how this can look.
+ \code
+
+void httpd_appcall(void);
+#define UIP_APPCALL     httpd_appcall
+
+struct httpd_state {
+  u8_t state; 
+  u16_t count;
+  char *dataptr;
+  char *script;
+};
+#define UIP_APPSTATE_SIZE (sizeof(struct httpd_state))
+ \endcode
+ */
+
+/**
+ * \var #define UIP_APPCALL
+ *
+ * The name of the application function that uIP should call in
+ * response to TCP/IP events.
+ *
+ */
+
+/**
+ * \var #define UIP_APPSTATE_SIZE
+ *
+ * The size of the application state that is to be stored in the
+ * uip_conn structure.
+ */
+/** @} */
+
+/* Include the header file for the application program that should be
+   used. If you don't use the example web server, you should change
+   this. */
+#include "httpd.h"
+
+
+#endif /* __UIPOPT_H__ */
