]> git.cryptolib.org Git - avr-crypto-lib.git/commitdiff
+ noekeon
authorbg <bg@b1d182e4-1ff8-0310-901f-bddb46175740>
Fri, 11 Apr 2008 17:54:24 +0000 (17:54 +0000)
committerbg <bg@b1d182e4-1ff8-0310-901f-bddb46175740>
Fri, 11 Apr 2008 17:54:24 +0000 (17:54 +0000)
Makefile
avr-makefile.inc
config.h
main-noekeon-test.c [new file with mode: 0644]
noekeon.c [new file with mode: 0644]
noekeon.h [new file with mode: 0644]
performance_test.c
uart.c

index 169eb668bfac7dbed48e70aeebdfaa4b82c906b6..79b333821d710e5e3df741132fa26a2b90dac29c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -7,7 +7,8 @@ HASHES         :=
 MACS           :=
 PRNGS          := 
 
-
+# we use the gnu make standard library
+include gmsl
 include avr-makefile.inc
 include *.mk
 
@@ -23,6 +24,9 @@ ALGORITHMS_TEST_BIN_IMM =  $(foreach a, $(ALGORITHMS_TEST_BIN), $($(a)))
 ALGORITHMS_NESSIE_TEST = $(patsubst %,%_NESSIE_TEST, $(ALGORITHMS))
 ALGORITHMS_PERFORMANCE_TEST = $(patsubst %,%_PERORMANCE_TEST, $(ALGORITHMS))
 
+#ALGORITHMS_LC = #algorithm names in lowercase 
+#ALGORITHMS_LC = $(foreach a, $(ALGORITHMS), $$(lc Text))
+ALGORITHMS_LC = $(call lc,$(ALGORITHMS))
 PRG = remove_me
 
 DEFS      =
@@ -53,6 +57,9 @@ info:
        @echo "    $(MACS)"
        @echo "  PRNG functions:"
        @echo "    $(PRNGS)"
+       @echo "  LC functions:"
+       @echo "    $(ALGORITHMS_LC)"
+       
 #      echo $(ALGORITHMS_TEST_BIN_MAIN)
 #      echo $(ALGORITHMS)
 #      echo $(firstword $(XTEA_TEST_BIN))
@@ -110,6 +117,18 @@ $(PRNGS_OBJ): $(patsubst %,%_OBJ, $(PRNGS))
 $(MACS_OBJ): $(patsubst %,%_OBJ, $(MACS))
 
 $(ALGORITHMS_TEST_BIN): $(ALGORITHMS_TEST_BIN_IMM)
+
+
+define SIZE_TEMPLATE
+$(1)_size.txt: $(2)
+       @echo " ALGO: $(1)"
+       @echo " REQ:  $(2)"
+       $(SIZE) $(2) > $(1)_size.txt
+endef
+
+$(foreach algo, $(ALGORITHMS), $(eval $(call SIZE_TEMPLATE, $(call lc,$(algo)), $($(algo)_OBJ))))
+
+
        
 .PHONY: all
 all: $(PRG).elf lst text eeprom
@@ -163,8 +182,8 @@ esrec: $(PRG)_eeprom.srec
 %_eeprom.bin: %.elf
        $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O binary $< $@
 
-%_size.txt: %.o
-       $(SIZE)  $< > $@
+#%_size.txt: %.o
+#      $(SIZE)  $< > $@
        
        
        
index 4db26068ae73a2706916cbd9be2f6ea795d5c990..dfc3474f8f695666b4b1d0dfb9ef0be8a25ba3a0 100644 (file)
@@ -1,8 +1,8 @@
 
 OBJ = $(SERPENT_OBJ)
-MCU_TARGET     = atmega32
+MCU_TARGET     = atmega644
 OPTIMIZE       = -Os
-
+DEFS           = -DATMEGA644
 FLASHCMD       = avrdude -p $(MCU_TARGET) -P /dev/ttyUSB0 -c avr911 -U flash:w:$(PRG).hex
 #  -U eeprom:w:$(PRG)_eeprom.hex
 #uisp -dprog=bsd -dlpt=/dev/parport1 --upload if=$(PRG).hex
@@ -10,8 +10,8 @@ ERASECMD       =
 
 CC          = avr-gcc
 
-override CFLAGS        = -pedantic -std=c99 -Wall -Wstrict-prototypes  $(OPTIMIZE) -mmcu=$(MCU_TARGET) 
-$(DEFS)
+override CFLAGS        = -pedantic -std=c99 -Wall -Wstrict-prototypes  $(OPTIMIZE) -mmcu=$(MCU_TARGET) $(DEFS)
+
 override LDFLAGS       = -Wl,-Map,
 override ASFLAGS          = -mmcu=$(MCU_TARGET)
 
index 5586a329a5f1a188ff0a3928ba2ea675be310136..09cbf61bb83961146737400d5cdf192736bc6394 100644 (file)
--- a/config.h
+++ b/config.h
@@ -23,5 +23,7 @@
 #define UART_CTS_BIT 1
 */
 
+#define ATMEGA644
+
 #endif
 
diff --git a/main-noekeon-test.c b/main-noekeon-test.c
new file mode 100644 (file)
index 0000000..43eb3a9
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * serpent test-suit
+ * 
+*/
+
+#include "config.h"
+#include "serial-tools.h"
+#include "uart.h"
+#include "debug.h"
+
+#include "noekeon.h"
+#include "nessie_bc_test.h"
+#include "cli.h"
+#include "performance_test.h"
+
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+
+char* cipher_name = "Noekeon";
+
+/*****************************************************************************
+ *  additional validation-functions                                                                                     *
+ *****************************************************************************/
+void noekeon_genctx_dummy(uint8_t* key, uint16_t keysize, void* ctx){
+       noekeon_init(key, ctx);
+}
+
+void testrun_nessie_noekeon_indirect(void){
+       char str[strlen(cipher_name)+10];
+       strcpy(str, cipher_name);
+       strcat(str, "-indirect");
+       
+       nessie_bc_ctx.blocksize_B =  16;
+       nessie_bc_ctx.keysize_b   = 128;
+       nessie_bc_ctx.name        = str;
+       nessie_bc_ctx.ctx_size_B  = sizeof(noekeon_ctx_t);
+       nessie_bc_ctx.cipher_enc  = (nessie_bc_enc_fpt)noekeon_enc;
+       nessie_bc_ctx.cipher_dec  = (nessie_bc_dec_fpt)noekeon_dec;
+       nessie_bc_ctx.cipher_genctx  = (nessie_bc_gen_fpt)noekeon_genctx_dummy;
+       
+       nessie_bc_run();
+}
+
+void noekeon_genctx_dummy_direct(uint8_t* key, uint16_t keysize, void* ctx){
+       memcpy(ctx, key, 16);
+}
+
+void testrun_nessie_noekeon_direct(void){
+       char str[strlen(cipher_name)+10];
+       strcpy(str, cipher_name);
+       strcat(str, "-Direct");
+       
+       nessie_bc_ctx.blocksize_B =  16;
+       nessie_bc_ctx.keysize_b   = 128;
+       nessie_bc_ctx.name        = str;
+       nessie_bc_ctx.ctx_size_B  = sizeof(noekeon_ctx_t);
+       nessie_bc_ctx.cipher_enc  = (nessie_bc_enc_fpt)noekeon_enc;
+       nessie_bc_ctx.cipher_dec  = (nessie_bc_dec_fpt)noekeon_dec;
+       nessie_bc_ctx.cipher_genctx  = (nessie_bc_gen_fpt)noekeon_genctx_dummy_direct;
+       
+       nessie_bc_run();
+}
+
+void testrun_stdtest_rundirect(void* data, void* key){
+       uart_putstr_P(PSTR("\r\n                     "));
+       uart_putstr_P(PSTR("k = "));
+       uart_hexdump(key,16);
+       
+       uart_putstr_P(PSTR("\r\n                     "));
+       uart_putstr_P(PSTR("a = "));
+       uart_hexdump(data,16);
+       
+       noekeon_enc(data, key);
+       uart_putstr_P(PSTR("\r\nafter NESSIEencrypt, b = "));
+       uart_hexdump(data,16);
+       
+       noekeon_dec(data, key);
+       uart_putstr_P(PSTR("\r\nafter NESSIEdecrypt, a?= "));
+       uart_hexdump(data,16);
+       uart_putstr_P(PSTR("\r\n"));
+}
+
+void testrun_stdtest_runindirect(void* data, void* key){
+       noekeon_ctx_t ctx;
+       uart_putstr_P(PSTR("\r\n                     "));
+       uart_putstr_P(PSTR("k = "));
+       uart_hexdump(key,16);
+       
+       uart_putstr_P(PSTR("\r\n                     "));
+       uart_putstr_P(PSTR("a = "));
+       uart_hexdump(data,16);
+       noekeon_init(key, &ctx);
+       noekeon_enc(data, &ctx);
+       uart_putstr_P(PSTR("\r\nafter NESSIEencrypt, b = "));
+       uart_hexdump(data,16);
+       
+       noekeon_dec(data, &ctx);
+       uart_putstr_P(PSTR("\r\nafter NESSIEdecrypt, a?= "));
+       uart_hexdump(data,16);
+       uart_putstr_P(PSTR("\r\n"));
+}
+
+void testrun_stdtest_noekeon(void){
+       uint8_t key[16], data[16];
+       uint8_t key3[16];
+       noekeon_ctx_t ctx;
+       
+       uart_putstr_P(PSTR("\r\nTest vectors for block cipher Noekeon in Indirect-Key Mode:\r\n"));
+       
+       memset(key,  0, 16);
+       memset(data, 0, 16);
+       testrun_stdtest_runindirect(data, key);
+       
+       memset(key,  0xFF, 16);
+       memset(data, 0xFF, 16);
+       testrun_stdtest_runindirect(data, key);
+       
+       memset(key,  0, 16);
+       memset(data, 0, 16);
+       noekeon_init(key, &ctx);
+       noekeon_enc(data, &ctx);
+       memcpy(key3, data, 16);
+       memset(key,  0xFF, 16);
+       memset(data, 0xFF, 16);
+       noekeon_init(key, &ctx);
+       noekeon_enc(data, &ctx);
+       testrun_stdtest_runindirect(data, key3);
+       
+       
+       uart_putstr_P(PSTR("\r\nTest vectors for block cipher Noekeon in Direct-Key Mode:\r\n"));
+       
+       memset(key,  0, 16);
+       memset(data, 0, 16);
+       testrun_stdtest_rundirect(data, key);
+       
+       memset(key,  0xFF, 16);
+       memset(data, 0xFF, 16);
+       testrun_stdtest_rundirect(data, key);
+       
+       memset(key,  0, 16);
+       memset(data, 0, 16);
+       noekeon_enc(data, key);
+       memcpy(key3, data, 16);
+       memset(key,  0xFF, 16);
+       memset(data, 0xFF, 16);
+       noekeon_enc(data, key);
+       testrun_stdtest_rundirect(data, key3);
+       
+}
+
+void testrun_performance_noekeon(void){
+       uint16_t i,c;
+       uint64_t t;
+       char str[6];
+       uint8_t key[16], data[16];
+       noekeon_ctx_t ctx;
+       
+       calibrateTimer();
+       getOverhead(&c, &i);
+       uart_putstr_P(PSTR("\r\n\r\n=== benchmark ==="));
+       utoa(c, str, 10);
+       uart_putstr_P(PSTR("\r\n\tconst overhead:     "));
+       uart_putstr(str);
+       utoa(i, str, 10);
+       uart_putstr_P(PSTR("\r\n\tinterrupt overhead: "));
+       uart_putstr(str);
+       
+       memset(key,  0, 16);
+       memset(data, 0, 16);
+       
+       startTimer(1);
+       noekeon_init(key, &ctx);
+       t = stopTimer();
+       uart_putstr_P(PSTR("\r\n\tctx-gen time: "));
+       uart_hexdump(&t, 8);
+       
+       
+       startTimer(1);
+       noekeon_enc(data, ctx);
+       t = stopTimer();
+       uart_putstr_P(PSTR("\r\n\tencrypt time: "));
+       uart_hexdump(&t, 8);
+       
+       
+       startTimer(1);
+       noekeon_dec(data, ctx);
+       t = stopTimer();
+       uart_putstr_P(PSTR("\r\n\tdecrypt time: "));
+       uart_hexdump(&t, 8);
+       uart_putstr_P(PSTR("\r\n"));
+}
+/*****************************************************************************
+ *  main                                                                                                                                        *
+ *****************************************************************************/
+
+typedef void(*void_fpt)(void);
+
+int main (void){
+       char  str[20];
+       DEBUG_INIT();
+       uart_putstr("\r\n");
+
+       uart_putstr_P(PSTR("\r\n\r\nCrypto-VS ("));
+       uart_putstr(cipher_name);
+       uart_putstr_P(PSTR(")\r\nloaded and running\r\n"));
+
+       PGM_P    u   = PSTR("nessie\0test\0direct\0indirect\0performance\0");
+       void_fpt v[] = {testrun_nessie_noekeon_direct, 
+                           testrun_stdtest_noekeon,
+                           testrun_nessie_noekeon_direct, 
+                           testrun_nessie_noekeon_indirect,  
+                           testrun_performance_noekeon};
+
+       while(1){ 
+               if (!getnextwordn(str,20)){DEBUG_S("DBG: W1\r\n"); goto error;}
+               if(execcommand_d0_P(str, u, v)<0){
+                       uart_putstr_P(PSTR("\r\nunknown command\r\n"));
+               }
+               continue;
+       error:
+               uart_putstr("ERROR\r\n");
+       }
+       
+}
+
diff --git a/noekeon.c b/noekeon.c
new file mode 100644 (file)
index 0000000..dd68b65
--- /dev/null
+++ b/noekeon.c
@@ -0,0 +1,160 @@
+/*
+ * author: Daniel Otte
+ * email:  daniel.otte@rub.de
+ * license: GPLv3
+ * 
+ * 
+ * 
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <avr/pgmspace.h>
+#include "noekeon.h"
+
+#define ROUND_NR 16
+
+#define RC_POS 0
+
+static
+void gamma(uint32_t* a){
+       uint32_t tmp;
+       
+       a[1] ^= ~((a[3]) | (a[2]));
+       a[0] ^=   a[2] & a[1];  
+       
+       tmp=a[3]; a[3]=a[0]; a[0]=tmp;
+       a[2] ^= a[0] ^ a[1] ^ a[3];
+       
+       a[1] ^= ~((a[3]) | (a[2]));
+       a[0] ^=   a[2] & a[1];  
+}      
+
+#define ROTL32(a,n) (((a)<<n)|((a)>>(32-n)))
+#define ROTR32(a,n) (((a)>>n)|((a)<<(32-n)))
+
+static
+void pi1(uint32_t* a){
+       a[1] = ROTL32(a[1], 1);
+       a[2] = ROTL32(a[2], 5);
+       a[3] = ROTL32(a[3], 2);
+}
+
+static
+void pi2(uint32_t* a){
+       a[1] = ROTR32(a[1], 1);
+       a[2] = ROTR32(a[2], 5);
+       a[3] = ROTR32(a[3], 2);
+}
+
+static
+void theta(uint32_t* k, uint32_t* a){
+       uint32_t temp;
+       temp = a[0] ^ a[2]; temp ^= ROTR32(temp, 8) ^ ROTL32(temp, 8);
+       a[1] ^= temp;
+       a[3] ^= temp;
+       
+       a[0] ^= k[0];
+       a[1] ^= k[1];
+       a[2] ^= k[2];
+       a[3] ^= k[3];
+
+       temp = a[1] ^ a[3]; temp ^= ROTR32(temp, 8) ^ ROTL32(temp, 8);
+       a[0] ^= temp;
+       a[2] ^= temp;   
+}
+
+static 
+void noekeon_round(uint32_t* key, uint32_t* state, uint8_t const1, uint8_t const2){
+       ((uint8_t*)state)[RC_POS] ^= const1;
+       theta(key, state);
+       ((uint8_t*)state)[RC_POS] ^= const2;
+       pi1(state);
+       gamma(state);
+       pi2(state);
+}
+
+uint8_t rc_tab[] PROGMEM = {
+/*     0x80, */
+             0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D, 0x9A,
+       0x2F, 0x5E, 0xBC, 0x63, 0xC6, 0x97, 0x35, 0x6A,
+       0xD4
+};
+/* for more rounds
+ 0xD4, 0xB3, 0x7D, 0xFA, 0xEF, 0xC5, 0x91, 0x39,
+ 0x72, 0xE4, 0xD3, 0xBD, 0x61, 0xC2, 0x9F, 0x25,
+*/
+
+static
+void changendian32(void* a){
+       ((uint8_t*)a)[0] ^= ((uint8_t*)a)[3];
+       ((uint8_t*)a)[3] ^= ((uint8_t*)a)[0];
+       ((uint8_t*)a)[0] ^= ((uint8_t*)a)[3];
+       
+       ((uint8_t*)a)[1] ^= ((uint8_t*)a)[2];
+       ((uint8_t*)a)[2] ^= ((uint8_t*)a)[1];
+       ((uint8_t*)a)[1] ^= ((uint8_t*)a)[2];
+}
+
+static
+void changendian(void* a){
+       changendian32((uint32_t*)(&(((uint32_t*)a)[0])));
+       changendian32((uint32_t*)(&(((uint32_t*)a)[1])));
+       changendian32((uint32_t*)(&(((uint32_t*)a)[2])));
+       changendian32((uint32_t*)(&(((uint32_t*)a)[3])));
+}
+
+/******************************************************************************/
+
+void noekeon_enc(void* buffer, void* key){
+       uint8_t rc=0x80;
+       int8_t i;
+       
+       changendian(buffer);
+       changendian(key);
+
+       for(i=0; i<ROUND_NR; ++i){
+               noekeon_round((uint32_t*)key, (uint32_t*)buffer, rc, 0);
+               rc = pgm_read_byte(rc_tab+i);
+       }
+       ((uint8_t*)buffer)[RC_POS] ^= rc;
+       theta((uint32_t*)key, (uint32_t*)buffer);
+
+       changendian(buffer);
+       changendian(key);
+}
+
+
+void noekeon_dec(void* buffer, void* key){
+       uint8_t rc;
+       int8_t i;
+       uint8_t nullv[16];
+       uint8_t dkey[16];
+       
+
+       changendian(buffer);
+       changendian(key);
+       
+       memset(nullv, 0, 16);
+       memcpy(dkey, key, 16);
+       
+       theta((uint32_t*)nullv, (uint32_t*)dkey);
+       for(i=ROUND_NR-1; i>=0; --i){
+               rc = pgm_read_byte(rc_tab+i);
+               noekeon_round((uint32_t*)dkey, (uint32_t*)buffer, 0, rc);
+       }
+       theta((uint32_t*)dkey, (uint32_t*)buffer);
+       ((uint8_t*)buffer)[RC_POS] ^= 0x80;
+
+       changendian(buffer);
+       changendian(key);
+}
+
+void noekeon_init(void* key, noekeon_ctx_t* ctx){
+       uint8_t nullv[16];
+       
+       memset(nullv, 0, 16);
+       memcpy(ctx, key, 16);
+       noekeon_enc(ctx, nullv);
+}
+
diff --git a/noekeon.h b/noekeon.h
new file mode 100644 (file)
index 0000000..14714ff
--- /dev/null
+++ b/noekeon.h
@@ -0,0 +1,21 @@
+#ifndef NOEKEON_H_
+#define NOEKEON_H_
+
+/*
+ * author: Daniel Otte
+ * email:  daniel.otte@rub.de
+ * license: GPLv3
+ * 
+ * 
+ * 
+ */
+
+#include <stdint.h>
+
+typedef uint8_t noekeon_ctx_t[16];
+
+void noekeon_enc(void* buffer, void* key);
+void noekeon_dec(void* buffer, void* key);
+void noekeon_init(void* key, noekeon_ctx_t* ctx);
+
+#endif /*NOEKEON_H_*/
index 91d4f1cdb5c7164e1ca01ce5a697acd3d152aacc..0728827cf75a9f085c5b8c708901074fba9181ba 100644 (file)
@@ -1,15 +1,25 @@
 /*
+ * author: Daniel Otte
+ * email:  daniel.otte@rub.de
+ * license: GPLv3
  * 
  * 
- * 
- */
-
+ **/
+#include "config.h"
 #include <stdint.h>
 #include <stdlib.h>
 #include <avr/io.h>
 #include <avr/interrupt.h>
 #include "performance_test.h"
 
+
+#ifdef ATMEGA644
+       #define TIMSK TIMSK1
+#endif
+
+
+
 uint32_t ovfcounter;
 
 uint16_t const_overhead=0;
@@ -37,7 +47,7 @@ void startTimer(uint8_t granularity){
        ovfcounter = 0;
        TCCR1A = 0x00;
        TIMSK &= 0xC3;
-       TIMSK |= _BV(2); /* enable TOIE1 */
+       TIMSK |= _BV(TOIE1); /* enable TOIE1 */
        TCCR1B = granularity & 0x7;     /* start timer */
 }
 
diff --git a/uart.c b/uart.c
index 68aaac48e006d7ee48bbc3248586e1f42ba45453..94de47e43bc3e4b05a52d14f04d37445eecd805e 100644 (file)
--- a/uart.c
+++ b/uart.c
@@ -3,7 +3,6 @@
 #include "config.h"
 
 #include <avr/io.h>
-//#include <avr/signal.h>
 #include <avr/interrupt.h>
 #include <stdlib.h>
 
 #define URSEL UMSEL
 #endif
 
+#ifdef ATMEGA644
+#define UCSRB UCSR0B
+#define UCSRC UCSR0C
+#define UDR UDR0
+#define UBRRH UBRR0H
+#define UBRRL UBRR0L
+#define URSEL UMSEL00
+#define USART_UDRE_vect USART0_UDRE_vect
+#define USART_RXC_vect USART0_RX_vect
+#define UDRIE UDRIE0
+#define TXEN TXEN0
+#define UMSEL UMSEL0
+#define RXEN RXEN0
+#define RXCIE RXCIE0
+#define UCSZ0 UCSZ00
+#define UCSRA UCSR0A
+#define UDRE UDRE0
+#define RXC RXC0
+#endif
+
+
+#ifdef UART_XON_XOFF
+ #ifdef UART_INTERRUPT
+  void uart_insertc(char c);
+ #else
+  #define uart_insertc uart_putc
+ #endif /* UART_INTERRUPT */
+#endif
 
 #define UART_BAUD_CALC(UART_BAUD_RATE,F_OSC) ((F_OSC)/((UART_BAUD_RATE)*16L)-1)
 
+#ifdef UART_XON_XOFF
+       typedef enum{go=1,nogo=0} gonogo;
+       static gonogo txon=go;
+       static gonogo rxon=go;
+#endif
 
 #ifdef UART_INTERRUPT
 volatile static char rxbuf[UART_RXBUFSIZE];
@@ -28,8 +60,11 @@ volatile static char txbuf[UART_TXBUFSIZE];
 volatile static char *volatile rxhead, *volatile rxtail;
 volatile static char *volatile txhead, *volatile txtail;
 
+#ifdef UART_HOOK       
+        void (*uart_hook) (uint8_t) = (void*)0;        /* this is a pointer to a function ;-) */
+#endif
 
-SIGNAL(SIG_UART_DATA) {
+ISR(USART_UDRE_vect) {
 #ifdef UART_LEDS       
        PORTC ^= 0x01;
 #endif
@@ -37,39 +72,89 @@ SIGNAL(SIG_UART_DATA) {
        if ( txhead == txtail ) {
                UCSRB &= ~(1 << UDRIE);         /* disable data register empty IRQ */
        } else {
+               #ifdef UART_XON_XOFF
+                       while(txon==nogo)
+                               ;
+               #endif
                UDR = *txtail;                  /* schreibt das Zeichen x auf die Schnittstelle */
                if (++txtail == (txbuf + UART_TXBUFSIZE)) txtail = txbuf;
        }
 }
 
-SIGNAL(SIG_UART_RECV) {
+ISR(USART_RXC_vect) {
        int diff; 
-
+       char c;
+#ifdef UART_HOOK       
+       static volatile uint8_t hook_running=0;
+#endif
 #ifdef UART_LEDS
        PORTC ^= 0x02;
 #endif
-       
+       c=UDR;
+       #ifdef UART_XON_XOFF
+        if (c==XON){
+                 txon=go;
+                 return;
+        }
+        if (c==XOFF){
+                txon=nogo;
+                return;
+        }
+       #endif
        /* buffer full? */
        diff = rxhead - rxtail;
-       if ( diff < 0 ) diff += UART_RXBUFSIZE;
+       if (diff < 0) diff += UART_RXBUFSIZE; /* diff is the amount of bytes in buffer */
        if (diff < UART_RXBUFSIZE -1) {
                // buffer NOT full
-               *rxhead = UDR;
-               if (++rxhead == (rxbuf + UART_RXBUFSIZE)) rxhead = rxbuf;
+#ifdef UART_HOOK
+               if(!hook_running && uart_hook){
+                       uint8_t t=c;    
+                       hook_running = 1;
+                       sei(); /* reenable interrupts, avoid recursion!!! */
+                       do {
+                               uart_hook(t);
+                       } while(uart_getc_nb((char*)&t));
+                       hook_running = 0;
+               } else {
+                       *rxhead = c;
+                       ++rxhead;
+                       if (rxhead == (rxbuf + UART_RXBUFSIZE)) rxhead = rxbuf;
+               }
+#else  
+               *rxhead = c;
+               ++rxhead;
+               if (rxhead == (rxbuf + UART_RXBUFSIZE))
+                       rxhead = rxbuf;
+#endif
        } else {
-               UDR;                            //reads the buffer to clear the interrupt condition
+                                               //reads the buffer to clear the interrupt condition
        }
+#ifdef UART_XON_XOFF   
+       if((diff > UART_XON_XOFF_THRESHOLD_1) && (rxon==go)){
+               rxon=nogo;
+               uart_insertc(XOFF);
+       }
+       if((diff < UART_XON_XOFF_THRESHOLD_2) && (rxon==nogo)){
+               rxon=go;
+               uart_insertc(XON);
+       }
+#endif
 }
 
 #endif // UART_INTERRUPT
 
 
-void uart_init(void) {
+void uart_init() {
        PORTD |= 0x01;                          //Pullup an RXD an
-
+       
        UCSRB |= (1<<TXEN);                     //UART TX einschalten
+#ifdef ATMEGA644
+       UCSRA = 0;
+       UCSRC = (3<<UCSZ0);                 //Asynchron 8N1
+#else  
+    UCSRA = 0;
        UCSRC |= (1<<URSEL)|(3<<UCSZ0);         //Asynchron 8N1
-
+#endif
        UCSRB |= ( 1 << RXEN );                 //Uart RX einschalten
 
        UBRRH=(uint8_t)(UART_BAUD_CALC(UART_BAUD_RATE,F_CPU)>>8);
@@ -81,11 +166,32 @@ void uart_init(void) {
        txhead = txtail = txbuf;
 
        // activate rx IRQ
-       UCSRB |= (1 << RXCIE);
+       UCSRB |= _BV(RXCIE) | _BV(UDRIE);
+       sei();
+//     #ifdef ATMEGA644
+//     UCSRB |= _BV(UDRIE);
+//     #endif
 #endif // UART_INTERRUPT
 }
 
 #ifdef UART_INTERRUPT
+#ifdef UART_XON_XOFF
+
+void uart_insertc(char c){
+       volatile int diff;
+       do {
+               diff = txhead - txtail;
+               if ( diff < 0 ) diff += UART_TXBUFSIZE;
+       } while ( diff >= UART_TXBUFSIZE -1 );
+
+       cli();
+       if (--txtail == (txbuf-1)) txtail += UART_TXBUFSIZE;
+       *txtail = c;
+       
+       UCSRB |= (1 << UDRIE);          /* enable data register empty IRQ */
+       sei();
+}
+#endif /* UART_XON_XOFF */
 void uart_putc(char c) {
        volatile int diff;
 
@@ -104,8 +210,13 @@ void uart_putc(char c) {
 }
 #else  // WITHOUT INTERRUPT
 void uart_putc(char c) {
-       while (!(UCSRA & (1<<UDRE))); /* warten bis Senden moeglich                   */
-       UDR = c;                      /* schreibt das Zeichen x auf die Schnittstelle */
+       while (!(UCSRA & (1<<UDRE))) /* warten bis Senden moeglich */
+               ; 
+       #ifdef UART_XON_XOFF
+       while (txon==nogo)                       /* warte bis XON empfangen */
+               ;
+       #endif
+       UDR = c;                  /* schreibt das Zeichen x auf die Schnittstelle */
 }
 #endif // UART_INTERRUPT
 
@@ -126,13 +237,13 @@ void uart_putstr_P(PGM_P str) {
 
 void uart_hexdump(void* buf, int len)
 {
-       unsigned char table[]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
-       
+       unsigned char table[]={'0','1','2','3','4','5','6','7',
+                                  '8','9','a','b','c','d','e','f'};
        while(len--){
                uart_putc(table[((*((char*)buf))>>4)&0xf]);
                uart_putc(table[(*((char*)buf))&0xf]);
                uart_putc(' ');
-               buf=(char*)buf+1;
+               buf=(uint8_t*)buf+1;
        }
 }
 
@@ -142,18 +253,28 @@ char uart_getc(void)
 {
        char val;
 
-       while(rxhead==rxtail) ;
+       while(rxhead==rxtail)
+               ;
 
        val = *rxtail;
-       if (++rxtail == (rxbuf + UART_RXBUFSIZE)) rxtail = rxbuf;
+       ++rxtail;
+       if (rxtail == (rxbuf + UART_RXBUFSIZE))
+               rxtail = rxbuf;
 
        return val;
 }
 #else  // WITHOUT INTERRUPT
 char uart_getc(void)
 {
-       while (!(UCSRA & (1<<RXC)));    // warten bis Zeichen verfuegbar
-       return UDR;                     // Zeichen aus UDR zurueckgeben
+       char t;
+       while (!(UCSRA & (1<<RXC)))
+               ;       // warten bis Zeichen verfuegbar
+       t=UDR;
+       #ifdef UART_XON_XOFF
+       if (t==XON)  txon=go;
+       if (t==XOFF) txon=nogo;
+       #endif
+       return t;                       // Zeichen aus UDR zurueckgeben
 }
 #endif // UART_INTERRUPT
 
@@ -173,6 +294,10 @@ char uart_getc_nb(char *c)
 {
        if (UCSRA & (1<<RXC)) {         // Zeichen verfuegbar
                *c = UDR;
+               #ifdef UART_XON_XOFF
+                       if (*c==XON)  txon=go;
+                       if (*c==XOFF) txon=nogo;
+               #endif
                return 1;
        }