--- 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); --- /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/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); --- 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-$(CONFIG_CMD_NET) += bootp.o COBJS-$(CONFIG_CMD_DNS) += dns.o @@ -36,6 +40,9 @@ COBJS-$(CONFIG_CMD_NET) += rarp.o COBJS-$(CONFIG_CMD_SNTP) += sntp.o COBJS-$(CONFIG_CMD_NET) += 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)) --- /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 +#include +#include +#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 --- 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 DECLARE_GLOBAL_DATA_PTR; @@ -1308,6 +1321,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; @@ -1922,3 +1942,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/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 +# +# $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/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 + * + * and GMP . It gets most of its implementation + * detail from "The Handbook of Applied Cryptography" + * + * @{ + */ + +#include "bigint.h" +#include +#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<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 +#include + +/* 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 + +/* + * 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 +#include +#include +#include +#include + +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 + * + * $Id: foncheckrsa.c 332 2007-05-02 09:45:54Z pablo.martin $ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#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 \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 + * + * Based on axTLS + * + * $Id: fonrsa.c 405 2007-09-19 15:26:17Z jesus.pico $ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 */ + 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 \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 + * + * $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 + * + * $Id: log.c 392 2007-06-25 16:24:51Z pablo.martin $ + */ +#include +#include +#include +#include +#include +#ifndef WIN32 +#include +#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 + * + * $Id: log.h 379 2007-05-28 09:17:48Z pablo.martin $ + */ +#ifndef _LOG_H +#define _LOG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +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/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 +#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 + * + * Based on axTLS + * + * $Id: fonrsa.c 405 2007-09-19 15:26:17Z jesus.pico $ + */ +#include +#include +#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 + * + * $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 + * + * $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 + * + * $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 +#include +#include +#include +#include +#include +#include +#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 \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 \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/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/fs.c @@ -0,0 +1,154 @@ +/** + * \addtogroup httpd + * @{ + */ + +/** + * \file + * HTTP server read-only file system code. + * \author Adam Dunkels + * + * 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 + * + * $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/fs.h @@ -0,0 +1,80 @@ +/** + * \addtogroup httpd + * @{ + */ + +/** + * \file + * HTTP server read-only file system header file. + * \author Adam Dunkels + */ + +/* + * 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 + * + * $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/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 + * + * $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/httpd.c @@ -0,0 +1,278 @@ +#include "uip.h" +#include "httpd.h" +#include "fs.h" +#include "fsdata.h" +#include + +#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 + */ + +/* + * 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/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 + * + * $Id: tapdev.c,v 1.7.2.1 2003/10/07 13:23:19 adam Exp $ + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef linux +#include +#include +#include +#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.c @@ -0,0 +1,1503 @@ +/** + * \addtogroup uip + * @{ + */ + +/** + * \file + * The uIP TCP/IP stack code. + * \author Adam Dunkels + */ + +/* + * 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 + * + * 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 +#include +#include +#include +#include + + +#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/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 + */ + +/* + * 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 + * + */ + +/* + * 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 + */ + + +/* + * 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/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 + * + * 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__ */