diff options
Diffstat (limited to 'clients/net-snk/app')
40 files changed, 3845 insertions, 1295 deletions
diff --git a/clients/net-snk/app/Makefile b/clients/net-snk/app/Makefile index d65216c..294ec15 100644 --- a/clients/net-snk/app/Makefile +++ b/clients/net-snk/app/Makefile @@ -1,5 +1,5 @@ # ***************************************************************************** -# * Copyright (c) 2004, 2007 IBM Corporation +# * Copyright (c) 2004, 2008 IBM Corporation # * All rights reserved. # * This program and the accompanying materials # * are made available under the terms of the BSD License @@ -19,6 +19,10 @@ include $(TOP)/make.rules CFLAGS +=$(ADDCFLAGS) OBJS = main.o +ifeq ($(SNK_LJTAG_PROCESS), 1) +OBJDIRS = ljtag/ljtag.o +CFLAGS += -DSNK_LJTAG_PROCESS +else OBJDIRS = netlib/netlib.o netapps/netboot.o OBJDIRS += netapps/netflash.o OBJDIRS += netapps/ping.o @@ -27,11 +31,18 @@ ifeq ($(SNK_BIOSEMU_APPS), 1) OBJDIRS += biosemu/biosemu_app.o CFLAGS += -DSNK_BIOSEMU_APPS endif +ifeq ($(SNK_GENMODULE_APPS), 1) +OBJDIRS += forth/forth.o snkshell/snkshell.o +CFLAGS += -DSNK_GENMODULE_APPS +endif +endif + +SUBDIRS = $(dir $(OBJDIRS)) all: app.o subdirs: - for dir in $(dir $(OBJDIRS)); do \ + for dir in $(SUBDIRS); do \ $(MAKE) -C $$dir DIRECTORY=$(DIRECTORY)$$dir || exit 1; \ done @@ -40,7 +51,7 @@ app.o: subdirs $(OBJS) clean : $(RM) -f *.o *.a *.i - for dir in $(dir $(OBJDIRS)); do \ + for dir in $(SUBDIRS); do \ $(CLEAN) ; \ $(MAKE) -C $$dir DIRECTORY=$(DIRECTORY)$$dir clean; \ done diff --git a/clients/net-snk/app/biosemu/Makefile b/clients/net-snk/app/biosemu/Makefile index 8fe149d..3a07ada 100644 --- a/clients/net-snk/app/biosemu/Makefile +++ b/clients/net-snk/app/biosemu/Makefile @@ -1,5 +1,5 @@ # ***************************************************************************** -# * Copyright (c) 2004, 2007 IBM Corporation +# * Copyright (c) 2004, 2008 IBM Corporation # * All rights reserved. # * This program and the accompanying materials # * are made available under the terms of the BSD License @@ -16,7 +16,7 @@ ifndef TOP endif include $(TOP)/make.rules -CFLAGS += -I$(ROOTDIR)/other-licence/x86emu -I$(ROOTDIR)/other-licence/x86emu/include -save-temps +CFLAGS += -I$(ROOTDIR)/other-licence/x86emu -I$(ROOTDIR)/other-licence/x86emu/include OBJS = biosemu.o debug.o device.o mem.o io.o interrupt.o vbe.o LIBX86EMU = $(ROOTDIR)/other-licence/x86emu/libx86emu.a diff --git a/clients/net-snk/app/biosemu/biosemu.c b/clients/net-snk/app/biosemu/biosemu.c index 1d9b3da..428f8d4 100644 --- a/clients/net-snk/app/biosemu/biosemu.c +++ b/clients/net-snk/app/biosemu/biosemu.c @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License @@ -15,7 +15,7 @@ #include <stdlib.h> #include <string.h> -#include <types.h> +#include <stdint.h> #include <cpu.h> #include "debug.h" @@ -24,13 +24,14 @@ #include <x86emu/regs.h> #include <x86emu/prim_ops.h> // for push_word +#include "biosemu.h" #include "io.h" #include "mem.h" #include "interrupt.h" +#include "device.h" #include <rtas.h> -#include "device.h" static X86EMU_memFuncs my_mem_funcs = { my_rdb, my_rdw, my_rdl, @@ -49,9 +50,11 @@ biosemu(char argc, char **argv) { uint8_t *rom_image; int i = 0; - int32_t len; uint8_t *biosmem; uint32_t biosmem_size; +#ifdef DEBUG + debug_flags = DEBUG_PRINT_INT10 | DEBUG_PNP;// | DEBUG_PMM;// | DEBUG_INTR | DEBUG_CHECK_VMEM_ACCESS | DEBUG_MEM | DEBUG_IO;// | DEBUG_TRACE_X86EMU | DEBUG_JMP; +#endif if (argc < 3) { printf("Usage %s <vmem_base> <device_path>\n", argv[0]); for (i = 0; i < argc; i++) { @@ -59,82 +62,71 @@ biosemu(char argc, char **argv) } return -1; } - // argv[1] is address of virtual BIOS mem... it should be 1MB large... + // argv[1] is address of virtual BIOS mem... + // argv[2] is the size biosmem = (uint8_t *) strtoul(argv[1], 0, 16); - biosmem_size = 0x100000; - // argv[2] is the device to open and use... - if (dev_init(argv[2]) != 0) { + biosmem_size = strtoul(argv[2], 0, 16); + if (biosmem_size < MIN_REQUIRED_VMEM_SIZE) { + printf("Error: Not enough virtual memory: %x, required: %x!\n", + biosmem_size, MIN_REQUIRED_VMEM_SIZE); + return -1; + } + // argv[3] is the device to open and use... + if (dev_init(argv[3]) != 0) { printf("Error initializing device!\n"); return -1; } - // get expROM address using rtas_pci_config_read - uint64_t rom_base_addr = - rtas_pci_config_read(bios_device.puid, 4, bios_device.bus, - bios_device.devfn, 0x30); - if ((rom_base_addr & 0x1) != 1) { - printf("Error: invalid Expansion ROM address: 0x%llx!\n", - rom_base_addr); + if (dev_check_exprom() != 0) { + printf("Error: Device Expansion ROM invalid!\n"); return -1; } - // unset lowest bit... - rom_base_addr = rom_base_addr & 0xFFFFFFFE; - DEBUG_PRINTF("rom_base: %llx\n", rom_base_addr); - - dev_translate_address(&rom_base_addr); - DEBUG_PRINTF("translated rom_base: %llx\n", rom_base_addr); - - rom_image = (uint8_t *) rom_base_addr; + rom_image = (uint8_t *) bios_device.img_addr; DEBUG_PRINTF("executing rom_image from %p\n", rom_image); DEBUG_PRINTF("biosmem at %p\n", biosmem); - // first of all, we need the size (3rd byte) - set_ci(); - len = *(rom_image + 2); - clr_ci(); - // size is in 512 byte blocks - len = len * 512; - DEBUG_PRINTF("Length: %d\n", len); + DEBUG_PRINTF("Image Size: %d\n", bios_device.img_size); // in case we jump somewhere unexpected, or execution is finished, // fill the biosmem with hlt instructions (0xf4) - memset(biosmem, 0xf4, sizeof(biosmem)); + memset(biosmem, 0xf4, biosmem_size); M.mem_base = (long) biosmem; M.mem_size = biosmem_size; DEBUG_PRINTF("membase set: %08x, size: %08x\n", (int) M.mem_base, (int) M.mem_size); - // copy expansion ROM image to segment C000 + // copy expansion ROM image to segment OPTION_ROM_CODE_SEGMENT // NOTE: this sometimes fails, some bytes are 0x00... so we compare // after copying and do some retries... - uint8_t *vga_img = biosmem + 0xc0000; + uint8_t *mem_img = biosmem + (OPTION_ROM_CODE_SEGMENT << 4); uint8_t copy_count = 0; uint8_t cmp_result = 0; do { #if 0 set_ci(); - memcpy(vga_img, rom_image, len); + memcpy(mem_img, rom_image, len); clr_ci(); #else // memcpy fails... try copy byte-by-byte with set/clr_ci uint8_t c; - for (i = 0; i < len; i++) { + for (i = 0; i < bios_device.img_size; i++) { set_ci(); c = *(rom_image + i); if (c != *(rom_image + i)) { clr_ci(); - printf("Copy failed at: %x/%x\n", i, len); - printf("rom_image(%x): %x, vga_img(%x): %x\n", - i, *(rom_image + i), i, *(vga_img + i)); + printf("Copy failed at: %x/%x\n", i, + bios_device.img_size); + printf("rom_image(%x): %x, mem_img(%x): %x\n", + i, *(rom_image + i), i, *(mem_img + i)); break; } clr_ci(); - *(vga_img + i) = c; + *(mem_img + i) = c; } #endif copy_count++; set_ci(); - cmp_result = memcmp(vga_img, rom_image, len); + cmp_result = memcmp(mem_img, rom_image, bios_device.img_size); clr_ci(); } while ((copy_count < 5) && (cmp_result != 0)); @@ -143,18 +135,80 @@ biosemu(char argc, char **argv) ("\nCopying Expansion ROM Image to Memory failed after %d retries! (%x)\n", copy_count, cmp_result); dump(rom_image, 0x20); - dump(vga_img, 0x20); + dump(mem_img, 0x20); return 0; } - // setup BIOS area + // setup default Interrupt Vectors + // some expansion ROMs seem to check for these addresses.. + // each handler is only an IRET (0xCF) instruction + // ROM BIOS Int 10 Handler F000:F065 + my_wrl(0x10 * 4, 0xf000f065); + my_wrb(0x000ff065, 0xcf); + // ROM BIOS Int 11 Handler F000:F84D + my_wrl(0x11 * 4, 0xf000f84d); + my_wrb(0x000ff84d, 0xcf); + // ROM BIOS Int 12 Handler F000:F841 + my_wrl(0x12 * 4, 0xf000f841); + my_wrb(0x000ff841, 0xcf); + // ROM BIOS Int 13 Handler F000:EC59 + my_wrl(0x13 * 4, 0xf000ec59); + my_wrb(0x000fec59, 0xcf); + // ROM BIOS Int 14 Handler F000:E739 + my_wrl(0x14 * 4, 0xf000e739); + my_wrb(0x000fe739, 0xcf); + // ROM BIOS Int 15 Handler F000:F859 + my_wrl(0x15 * 4, 0xf000f859); + my_wrb(0x000ff859, 0xcf); + // ROM BIOS Int 16 Handler F000:E82E + my_wrl(0x16 * 4, 0xf000e82e); + my_wrb(0x000fe82e, 0xcf); + // ROM BIOS Int 17 Handler F000:EFD2 + my_wrl(0x17 * 4, 0xf000efd2); + my_wrb(0x000fefd2, 0xcf); + // ROM BIOS Int 1A Handler F000:FE6E + my_wrl(0x1a * 4, 0xf000fe6e); + my_wrb(0x000ffe6e, 0xcf); + + // setup BIOS Data Area (0000:04xx, or 0040:00xx) + // we currently 0 this area, meaning "we dont have + // any hardware" :-) no serial/parallel ports, floppys, ... + memset(biosmem + 0x400, 0x0, 0x100); + + // at offset 13h in BDA is the memory size in kbytes + my_wrw(0x413, biosmem_size / 1024); + // at offset 0eh in BDA is the segment of the Extended BIOS Data Area + // see setup further down + my_wrw(0x40e, INITIAL_EBDA_SEGMENT); + // TODO: setup BDA Video Data ( offset 49h-66h) + // e.g. to store video mode, cursor position, ... + // in int10 (done) handler and VBE Functions + + // TODO: setup BDA Fixed Disk Data + // 74h: Fixed Disk Last Operation Status + // 75h: Fixed Disk Number of Disk Drives + + // TODO: check BDA for further needed data... + + //setup Extended BIOS Data Area + //we currently 0 this area + memset(biosmem + (INITIAL_EBDA_SEGMENT << 4), 0, INITIAL_EBDA_SIZE); + // at offset 0h in EBDA is the size of the EBDA in KB + my_wrw((INITIAL_EBDA_SEGMENT << 4) + 0x0, INITIAL_EBDA_SIZE / 1024); + //TODO: check for further needed EBDA data... + + // setup original ROM BIOS Area (F000:xxxx) char *date = "06/11/99"; for (i = 0; date[i]; i++) my_wrb(0xffff5 + i, date[i]); - /* set up eisa ident string */ - strcpy((char *) (biosmem + 0x0FFD9), "PCI_ISA"); + // set up eisa ident string + char *ident = "PCI_ISA"; + for (i = 0; ident[i]; i++) + my_wrb(0xfffd9 + i, ident[i]); - /* write system model id for IBM-AT */ - *((unsigned char *) (biosmem + 0x0FFFE)) = 0xfc; + // write system model id for IBM-AT + // according to "Ralf Browns Interrupt List" Int15 AH=C0 Table 515, + // model FC is the original AT and also used in all DOSEMU Versions. + my_wrb(0xFFFFE, 0xfc); //setup interrupt handler X86EMU_intrFuncs intrFuncs[256]; @@ -169,12 +223,12 @@ biosemu(char argc, char **argv) M.x86.R_AL = bios_device.devfn; M.x86.R_DX = 0x80; M.x86.R_EIP = 3; - M.x86.R_CS = 0xc000; + M.x86.R_CS = OPTION_ROM_CODE_SEGMENT; // Initialize stack and data segment - M.x86.R_SS = 0x0030; - M.x86.R_DS = 0x0040; - M.x86.R_SP = 0xfffe; + M.x86.R_SS = STACK_SEGMENT; + M.x86.R_SP = STACK_START_OFFSET; + M.x86.R_DS = DATA_SEGMENT; // push a HLT instruction and a pointer to it onto the stack // any return will pop the pointer and jump to the HLT, thus @@ -183,29 +237,104 @@ biosemu(char argc, char **argv) push_word(M.x86.R_SS); push_word(M.x86.R_SP + 2); - M.x86.R_ES = 0x0000; -#ifdef DEBUG_TRACE_X86EMU - X86EMU_trace_on(); - //since we have our own mem and io functions and dont use the x86emu functions, - // we dont need to enabled the debug... - //M.x86.debug |= DEBUG_MEM_TRACE_F; - //M.x86.debug |= DEBUG_IO_TRACE_F; -#endif -#ifdef DEBUG_JMP - M.x86.debug |= DEBUG_TRACEJMP_F; - M.x86.debug |= DEBUG_TRACEJMP_REGS_F; - M.x86.debug |= DEBUG_TRACECALL_F; - M.x86.debug |= DEBUG_TRACECALL_REGS_F; -#endif + CHECK_DBG(DEBUG_TRACE_X86EMU) { + X86EMU_trace_on(); + } else { #ifdef DEBUG - M.x86.debug |= DEBUG_SAVE_IP_CS_F; - M.x86.debug |= DEBUG_DECODE_F; - M.x86.debug |= DEBUG_DECODE_NOPRINT_F; + M.x86.debug |= DEBUG_SAVE_IP_CS_F; + M.x86.debug |= DEBUG_DECODE_F; + M.x86.debug |= DEBUG_DECODE_NOPRINT_F; #endif + } + CHECK_DBG(DEBUG_JMP) { + M.x86.debug |= DEBUG_TRACEJMP_F; + M.x86.debug |= DEBUG_TRACEJMP_REGS_F; + M.x86.debug |= DEBUG_TRACECALL_F; + M.x86.debug |= DEBUG_TRACECALL_REGS_F; + } - DEBUG_PRINTF("Los gehts...\n"); + DEBUG_PRINTF("Executing Initialization Vector...\n"); X86EMU_exec(); - DEBUG_PRINTF("Fertig\n"); + DEBUG_PRINTF("done\n"); + + // according to PNP BIOS Spec, Option ROMs should upon exit, return some boot device status in + // AX (see PNP BIOS Spec Section 3.3 + DEBUG_PRINTF_CS_IP("Option ROM Exit Status: %04x\n", M.x86.R_AX); +#ifdef DEBUG + DEBUG_PRINTF("Exit Status Decode:\n"); + if (M.x86.R_AX & 0x100) { // bit 8 + DEBUG_PRINTF + (" IPL Device supporting INT 13h Block Device Format:\n"); + switch (((M.x86.R_AX >> 4) & 0x3)) { // bits 5:4 + case 0: + DEBUG_PRINTF(" No IPL Device attached\n"); + break; + case 1: + DEBUG_PRINTF(" IPL Device status unknown\n"); + break; + case 2: + DEBUG_PRINTF(" IPL Device attached\n"); + break; + case 3: + DEBUG_PRINTF(" IPL Device status RESERVED!!\n"); + break; + } + } + if (M.x86.R_AX & 0x80) { // bit 7 + DEBUG_PRINTF + (" Output Device supporting INT 10h Character Output:\n"); + switch (((M.x86.R_AX >> 4) & 0x3)) { // bits 5:4 + case 0: + DEBUG_PRINTF(" No Display Device attached\n"); + break; + case 1: + DEBUG_PRINTF(" Display Device status unknown\n"); + break; + case 2: + DEBUG_PRINTF(" Display Device attached\n"); + break; + case 3: + DEBUG_PRINTF(" Display Device status RESERVED!!\n"); + break; + } + } + if (M.x86.R_AX & 0x40) { // bit 6 + DEBUG_PRINTF + (" Input Device supporting INT 9h Character Input:\n"); + switch (((M.x86.R_AX >> 4) & 0x3)) { // bits 5:4 + case 0: + DEBUG_PRINTF(" No Input Device attached\n"); + break; + case 1: + DEBUG_PRINTF(" Input Device status unknown\n"); + break; + case 2: + DEBUG_PRINTF(" Input Device attached\n"); + break; + case 3: + DEBUG_PRINTF(" Input Device status RESERVED!!\n"); + break; + } + } +#endif + // check wether the stack is "clean" i.e. containing the HLT instruction + // we pushed before executing, and pointing to the original stack address... + // indicating that the initialization probably was successful + if ((pop_word() == 0xf4f4) && (M.x86.R_SS == STACK_SEGMENT) + && (M.x86.R_SP == STACK_START_OFFSET)) { + DEBUG_PRINTF("Stack is clean, initialization successfull!\n"); + } else { + DEBUG_PRINTF + ("Stack unclean, initialization probably NOT COMPLETE!!!\n"); + DEBUG_PRINTF("SS:SP = %04x:%04x, expected: %04x:%04x\n", + M.x86.R_SS, M.x86.R_SP, STACK_SEGMENT, + STACK_START_OFFSET); + } + + // TODO: according to the BIOS Boot Spec initializations may be ended using INT18h and setting + // the status. + // We need to implement INT18 accordingly, pseudo code is in specsbbs101.pdf page 30 + // (also for Int19) return 0; } diff --git a/clients/net-snk/app/biosemu/biosemu.h b/clients/net-snk/app/biosemu/biosemu.h new file mode 100644 index 0000000..7ffd5bc --- /dev/null +++ b/clients/net-snk/app/biosemu/biosemu.h @@ -0,0 +1,40 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _BIOSEMU_BIOSEMU_H_ +#define _BIOSEMU_BIOSEMU_H_ + +#define MIN_REQUIRED_VMEM_SIZE 0x100000 // 1MB + +//define default segments for different components +#define STACK_SEGMENT 0x1000 //1000:xxxx +#define STACK_START_OFFSET 0xfffe + +#define DATA_SEGMENT 0x2000 +#define VBE_SEGMENT 0x3000 + +#define PMM_CONV_SEGMENT 0x4000 // 4000:xxxx is PMM conventional memory area, extended memory area + // will be anything beyound MIN_REQUIRED_MEMORY_SIZE +#define PNP_DATA_SEGMENT 0x5000 + +#define OPTION_ROM_CODE_SEGMENT 0xc000 + +#define BIOS_DATA_SEGMENT 0xF000 +// both EBDA values are _initial_ values, they may (and will be) changed at runtime by option ROMs!! +#define INITIAL_EBDA_SEGMENT 0xF600 // segment of the Extended BIOS Data Area +#define INITIAL_EBDA_SIZE 0x400 // size of the EBDA (at least 1KB!! since size is stored in KB!) + +#define PMM_INT_NUM 0xFC // we misuse INT FC for PMM functionality, at the PMM Entry Point + // Address, there will only be a call to this INT and a RETF +#define PNP_INT_NUM 0xFD + +#endif diff --git a/clients/net-snk/app/biosemu/debug.c b/clients/net-snk/app/biosemu/debug.c index 4346dda..2fce244 100644 --- a/clients/net-snk/app/biosemu/debug.c +++ b/clients/net-snk/app/biosemu/debug.c @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License @@ -14,6 +14,8 @@ #include "debug.h" +uint32_t debug_flags = 0; + void dump(uint8_t * addr, uint32_t len) { diff --git a/clients/net-snk/app/biosemu/debug.h b/clients/net-snk/app/biosemu/debug.h index 71e69fe..c056190 100644 --- a/clients/net-snk/app/biosemu/debug.h +++ b/clients/net-snk/app/biosemu/debug.h @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License @@ -13,50 +13,61 @@ #define _BIOSEMU_DEBUG_H_ #include <stdio.h> -#include <types.h> +#include <stdint.h> -//#define DEBUG_TRACE_X86EMU -//#undef DEBUG_TRACE_X86EMU +extern uint32_t debug_flags; +// from x86emu...needed for debugging +extern void x86emu_dump_xregs(); + +#define DEBUG_IO 0x1 +#define DEBUG_MEM 0x2 +// set this to print messages for certain virtual memory accesses (Interrupt Vectors, ...) +#define DEBUG_CHECK_VMEM_ACCESS 0x4 +#define DEBUG_INTR 0x8 +#define DEBUG_PRINT_INT10 0x10 // set to have the INT10 routine print characters +#define DEBUG_VBE 0x20 +#define DEBUG_PMM 0x40 +#define DEBUG_DISK 0x80 +#define DEBUG_PNP 0x100 + +#define DEBUG_TRACE_X86EMU 0x1000 +// set to enable tracing of JMPs in x86emu +#define DEBUG_JMP 0x2000 //#define DEBUG #ifdef DEBUG -//#define DEBUG_IO -//#define DEBUG_MEM -//#define DEBUG_INTR -//#define DEBUG_VBE -// define to enable tracing of JMPs in x86emu -//#define DEBUG_JMP +#define CHECK_DBG(_flag) if (debug_flags & _flag) -#define DEBUG_PRINTF(_x...) printf(_x) -#else -#define DEBUG_PRINTF(_x...) +#define DEBUG_PRINTF(_x...) printf(_x); +// prints the CS:IP before the printout, NOTE: actually its CS:IP of the _next_ instruction +// to be executed, since the x86emu advances CS:IP _before_ actually executing an instruction +#define DEBUG_PRINTF_CS_IP(_x...) DEBUG_PRINTF("%x:%x ", M.x86.R_CS, M.x86.R_IP); DEBUG_PRINTF(_x); -#endif //DEBUG +#define DEBUG_PRINTF_IO(_x...) CHECK_DBG(DEBUG_IO) { DEBUG_PRINTF_CS_IP(_x) } +#define DEBUG_PRINTF_MEM(_x...) CHECK_DBG(DEBUG_MEM) { DEBUG_PRINTF_CS_IP(_x) } +#define DEBUG_PRINTF_INTR(_x...) CHECK_DBG(DEBUG_INTR) { DEBUG_PRINTF_CS_IP(_x) } +#define DEBUG_PRINTF_VBE(_x...) CHECK_DBG(DEBUG_VBE) { DEBUG_PRINTF_CS_IP(_x) } +#define DEBUG_PRINTF_PMM(_x...) CHECK_DBG(DEBUG_PMM) { DEBUG_PRINTF_CS_IP(_x) } +#define DEBUG_PRINTF_DISK(_x...) CHECK_DBG(DEBUG_DISK) { DEBUG_PRINTF_CS_IP(_x) } +#define DEBUG_PRINTF_PNP(_x...) CHECK_DBG(DEBUG_PNP) { DEBUG_PRINTF_CS_IP(_x) } -#ifdef DEBUG_IO -#define DEBUG_PRINTF_IO(_x...) DEBUG_PRINTF("%x:%x ", M.x86.R_CS, M.x86.R_IP); DEBUG_PRINTF(_x) #else -#define DEBUG_PRINTF_IO(_x...) -#endif -#ifdef DEBUG_MEM -#define DEBUG_PRINTF_MEM(_x...) DEBUG_PRINTF("%x:%x ", M.x86.R_CS, M.x86.R_IP); DEBUG_PRINTF(_x) -#else -#define DEBUG_PRINTF_MEM(_x...) -#endif +#define CHECK_DBG(_flag) if (0) -#ifdef DEBUG_INTR -#define DEBUG_PRINTF_INTR(_x...) DEBUG_PRINTF("%x:%x ", M.x86.R_CS, M.x86.R_IP); DEBUG_PRINTF(_x) -#else -#define DEBUG_PRINTF_INTR(_x...) -#endif +#define DEBUG_PRINTF(_x...) +#define DEBUG_PRINTF_CS_IP(_x...) -#ifdef DEBUG_VBE -#define DEBUG_PRINTF_VBE(_x...) DEBUG_PRINTF("%x:%x ", M.x86.R_CS, M.x86.R_IP); DEBUG_PRINTF(_x) -#else +#define DEBUG_PRINTF_IO(_x...) +#define DEBUG_PRINTF_MEM(_x...) +#define DEBUG_PRINTF_INTR(_x...) #define DEBUG_PRINTF_VBE(_x...) -#endif +#define DEBUG_PRINTF_PMM(_x...) +#define DEBUG_PRINTF_DISK(_x...) +#define DEBUG_PRINTF_PNP(_x...) + +#endif //DEBUG void dump(uint8_t * addr, uint32_t len); diff --git a/clients/net-snk/app/biosemu/device.c b/clients/net-snk/app/biosemu/device.c index 3a60818..71402d5 100644 --- a/clients/net-snk/app/biosemu/device.c +++ b/clients/net-snk/app/biosemu/device.c @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License @@ -177,10 +177,107 @@ dev_get_device_vendor_id() bios_device.pci_device_id, bios_device.pci_vendor_id); } +/* check, wether the device has a valid Expansion ROM, also search the PCI Data Structure and + * any Expansion ROM Header (using dev_scan_exp_header()) for needed information */ +uint8_t +dev_check_exprom() +{ + int i = 0; + translate_address_t ta; + uint64_t rom_base_addr = 0; + uint16_t pci_ds_offset; + pci_data_struct_t pci_ds; + // check for ExpROM Address (Offset 30) in taa + for (i = 0; i <= taa_last_entry; i++) { + ta = translate_address_array[i]; + if (ta.cfg_space_offset == 0x30) { + rom_base_addr = ta.address + ta.address_offset; //translated address + break; + } + } + // in the ROM there could be multiple Expansion ROM Images... start searching + // them for a x86 image + do { + if (rom_base_addr == 0) { + printf("Error: no Expansion ROM address found!\n"); + return -1; + } + set_ci(); + uint16_t rom_signature = *((uint16_t *) rom_base_addr); + clr_ci(); + if (rom_signature != 0x55aa) { + printf + ("Error: invalid Expansion ROM signature: %02x!\n", + *((uint16_t *) rom_base_addr)); + return -1; + } + set_ci(); + // at offset 0x18 is the (16bit little-endian) pointer to the PCI Data Structure + pci_ds_offset = in16le((void *) (rom_base_addr + 0x18)); + //copy the PCI Data Structure + memcpy(&pci_ds, (void *) (rom_base_addr + pci_ds_offset), + sizeof(pci_ds)); + clr_ci(); +#ifdef DEBUG + DEBUG_PRINTF("PCI Data Structure @%llx:\n", + rom_base_addr + pci_ds_offset); + dump((void *) &pci_ds, sizeof(pci_ds)); +#endif + if (strncmp((const char *) pci_ds.signature, "PCIR", 4) != 0) { + printf("Invalid PCI Data Structure found!\n"); + break; + } + //little-endian conversion + pci_ds.vendor_id = in16le(&pci_ds.vendor_id); + pci_ds.device_id = in16le(&pci_ds.device_id); + pci_ds.img_length = in16le(&pci_ds.img_length); + pci_ds.pci_ds_length = in16le(&pci_ds.pci_ds_length); + if (pci_ds.vendor_id != bios_device.pci_vendor_id) { + printf + ("Image has invalid Vendor ID: %04x, expected: %04x\n", + pci_ds.vendor_id, bios_device.pci_vendor_id); + break; + } + if (pci_ds.device_id != bios_device.pci_device_id) { + printf + ("Image has invalid Device ID: %04x, expected: %04x\n", + pci_ds.device_id, bios_device.pci_device_id); + break; + } + //DEBUG_PRINTF("Image Length: %d\n", pci_ds.img_length * 512); + //DEBUG_PRINTF("Image Code Type: %d\n", pci_ds.code_type); + if (pci_ds.code_type == 0) { + //x86 image + //store image address and image length in bios_device struct + bios_device.img_addr = rom_base_addr; + bios_device.img_size = pci_ds.img_length * 512; + // we found the image, exit the loop + break; + } else { + // no x86 image, check next image (if any) + rom_base_addr += pci_ds.img_length * 512; + } + if ((pci_ds.indicator & 0x80) == 0x80) { + //last image found, exit the loop + DEBUG_PRINTF("Last PCI Expansion ROM Image found.\n"); + break; + } + } + while (bios_device.img_addr == 0); + // in case we did not find a valid x86 Expansion ROM Image + if (bios_device.img_addr == 0) { + printf("Error: no valid x86 Expansion ROM Image found!\n"); + return -1; + } + return 0; +} + uint8_t dev_init(char *device_name) { + uint8_t rval = 0; //init bios_device struct + DEBUG_PRINTF("%s(%s)\n", __FUNCTION__, device_name); memset(&bios_device, 0, sizeof(bios_device)); bios_device.ihandle = of_open(device_name); if (bios_device.ihandle == 0) { @@ -192,7 +289,7 @@ dev_init(char *device_name) dev_find_vmem_addr(); dev_get_puid(); dev_get_device_vendor_id(); - return 0; + return rval; } // translate address function using translate_address_array assembled diff --git a/clients/net-snk/app/biosemu/device.h b/clients/net-snk/app/biosemu/device.h index 04bd34e..074bd69 100644 --- a/clients/net-snk/app/biosemu/device.h +++ b/clients/net-snk/app/biosemu/device.h @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License @@ -13,11 +13,50 @@ #ifndef DEVICE_LIB_H #define DEVICE_LIB_H -#include "types.h" +#include <stdint.h> #include <cpu.h> #include "of.h" #include <stdio.h> +// a Expansion Header Struct as defined in Plug and Play BIOS Spec 1.0a Chapter 3.2 +typedef struct { + char signature[4]; // signature + uint8_t structure_revision; + uint8_t length; // in 16 byte blocks + uint16_t next_header_offset; // offset to next Expansion Header as 16bit little-endian value, as offset from the start of the Expansion ROM + uint8_t reserved; + uint8_t checksum; // the sum of all bytes of the Expansion Header must be 0 + uint32_t device_id; // PnP Device ID as 32bit little-endian value + uint16_t p_manufacturer_string; //16bit little-endian offset from start of Expansion ROM + uint16_t p_product_string; //16bit little-endian offset from start of Expansion ROM + uint8_t device_base_type; + uint8_t device_sub_type; + uint8_t device_if_type; + uint8_t device_indicators; + // the following vectors are all 16bit little-endian offsets from start of Expansion ROM + uint16_t bcv; // Boot Connection Vector + uint16_t dv; // Disconnect Vector + uint16_t bev; // Bootstrap Entry Vector + uint16_t reserved_2; + uint16_t sriv; // Static Resource Information Vector +} __attribute__ ((__packed__)) exp_header_struct_t; + +// a PCI Data Struct as defined in PCI 2.3 Spec Chapter 6.3.1.2 +typedef struct { + uint8_t signature[4]; // signature, the String "PCIR" + uint16_t vendor_id; + uint16_t device_id; + uint16_t reserved; + uint16_t pci_ds_length; // PCI Data Structure Length, 16bit little-endian value + uint8_t pci_ds_revision; + uint8_t class_code[3]; + uint16_t img_length; // length of the Exp.ROM Image, 16bit little-endian value in 512 bytes + uint16_t img_revision; + uint8_t code_type; + uint8_t indicator; + uint16_t reserved_2; +} __attribute__ ((__packed__)) pci_data_struct_t; + typedef struct { uint8_t bus; uint8_t devfn; @@ -25,7 +64,7 @@ typedef struct { phandle_t phandle; ihandle_t ihandle; // store the address of the BAR that is used to simulate - // legacy memory accesses + // legacy VGA memory accesses uint64_t vmem_addr; uint64_t vmem_size; // used to buffer I/O Accesses, that do not access the I/O Range of the device... @@ -33,6 +72,9 @@ typedef struct { uint8_t io_buffer[64 * 1024]; uint16_t pci_vendor_id; uint16_t pci_device_id; + // translated address of the "PC-Compatible" Expansion ROM Image for this device + uint64_t img_addr; + uint32_t img_size; // size of the Expansion ROM Image (read from the PCI Data Structure) } device_t; typedef struct { @@ -61,6 +103,8 @@ uint8_t taa_last_entry; device_t bios_device; uint8_t dev_init(char *device_name); +// NOTE: for dev_check_exprom to work, dev_init MUST be called first! +uint8_t dev_check_exprom(); uint8_t dev_translate_address(uint64_t * addr); diff --git a/clients/net-snk/app/biosemu/interrupt.c b/clients/net-snk/app/biosemu/interrupt.c index b0ad12f..f1137fe 100644 --- a/clients/net-snk/app/biosemu/interrupt.c +++ b/clients/net-snk/app/biosemu/interrupt.c @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License @@ -14,6 +14,7 @@ #include <rtas.h> +#include "biosemu.h" #include "mem.h" #include "device.h" #include "debug.h" @@ -42,6 +43,273 @@ setupInt(int intNum) M.x86.R_IP = my_rdw(intNum * 4); } +// handle int10 (VGA BIOS Interrupt) +void +handleInt10() +{ + // the data for INT10 is stored in BDA (0000:0400h) offset 49h-66h + // function number in AH + //DEBUG_PRINTF_CS_IP("%s:\n", __FUNCTION__); + //x86emu_dump_xregs(); + //if ((M.x86.R_IP == 0x32c2) && (M.x86.R_SI == 0x1ce2)){ + //X86EMU_trace_on(); + //M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F; + //} + switch (M.x86.R_AH) { + case 0x00: + // set video mode + // BDA offset 49h is current video mode + my_wrb(0x449, M.x86.R_AL); + if (M.x86.R_AL > 7) + M.x86.R_AL = 0x20; + else if (M.x86.R_AL == 6) + M.x86.R_AL = 0x3f; + else + M.x86.R_AL = 0x30; + break; + case 0x01: + // set cursor shape + // ignore + break; + case 0x02: + // set cursor position + // BH: pagenumber, DX: cursor_pos (DH:row, DL:col) + // BDA offset 50h-60h are 8 cursor position words for + // eight possible video pages + my_wrw(0x450 + (M.x86.R_BH * 2), M.x86.R_DX); + break; + case 0x03: + //get cursor position + // BH: pagenumber + // BDA offset 50h-60h are 8 cursor position words for + // eight possible video pages + M.x86.R_AX = 0; + M.x86.R_CH = 0; // start scan line ??? + M.x86.R_CL = 0; // end scan line ??? + M.x86.R_DX = my_rdw(0x450 + (M.x86.R_BH * 2)); + break; + case 0x05: + // set active page + // BDA offset 62h is current page number + my_wrb(0x462, M.x86.R_AL); + break; + case 0x06: + //scroll up windows + break; + case 0x07: + //scroll down windows + break; + case 0x08: + //read character and attribute at position + M.x86.R_AH = 0x07; // white-on-black + M.x86.R_AL = 0x20; // a space... + break; + case 0x09: + // write character and attribute + //AL: char, BH: page number, BL: attribute, CX: number of times to write + //BDA offset 62h is current page number + CHECK_DBG(DEBUG_PRINT_INT10) { + uint32_t i = 0; + if (M.x86.R_BH == my_rdb(0x462)) { + for (i = 0; i < M.x86.R_CX; i++) + printf("%c", M.x86.R_AL); + } + } + break; + case 0x0a: + // write character + //AL: char, BH: page number, BL: attribute, CX: number of times to write + //BDA offset 62h is current page number + CHECK_DBG(DEBUG_PRINT_INT10) { + uint32_t i = 0; + if (M.x86.R_BH == my_rdb(0x462)) { + for (i = 0; i < M.x86.R_CX; i++) + printf("%c", M.x86.R_AL); + } + } + break; + case 0x0e: + // teletype output: write character and advance cursor... + //AL: char, BH: page number, BL: attribute + //BDA offset 62h is current page number + CHECK_DBG(DEBUG_PRINT_INT10) { + // we ignore the pagenumber on this call... + //if (M.x86.R_BH == my_rdb(0x462)) + { + printf("%c", M.x86.R_AL); + // for debugging, to read all lines + //if (M.x86.R_AL == 0xd) // carriage return + // printf("\n"); + } + } + break; + case 0x0f: + // get video mode + // BDA offset 49h is current video mode + // BDA offset 62h is current page number + // BDA offset 4ah is columns on screen + M.x86.R_AH = 80; //number of character columns... we hardcode it to 80 + M.x86.R_AL = my_rdb(0x449); + M.x86.R_BH = my_rdb(0x462); + break; + default: + printf("%s(): unknown function (%x) for int10 handler.\n", + __FUNCTION__, M.x86.R_AH); + DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n", + M.x86.R_AX, M.x86.R_BX, M.x86.R_CX, + M.x86.R_DX); + HALT_SYS(); + break; + } +} + +// this table translates ASCII chars into their XT scan codes: +static uint8_t keycode_table[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0 - 7 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 8 - 15 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 16 - 23 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 24 - 31 + 0x39, 0x02, 0x28, 0x04, 0x05, 0x06, 0x08, 0x28, // 32 - 39 + 0x0a, 0x0b, 0x09, 0x2b, 0x33, 0x0d, 0x34, 0x35, // 40 - 47 + 0x0b, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, // 48 - 55 + 0x09, 0x0a, 0x27, 0x27, 0x33, 0x2b, 0x34, 0x35, // 56 - 63 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 64 - 71 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 72 - 79 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 80 - 87 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 88 - 95 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 96 - 103 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 104 - 111 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 112 - 119 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 120 - 127 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ... + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +} + +; + +void +translate_keycode(uint64_t * keycode) +{ + uint8_t scan_code = 0; + uint8_t char_code = 0; + if (*keycode < 256) { + scan_code = keycode_table[*keycode]; + char_code = (uint8_t) * keycode & 0xff; + } else { + switch (*keycode) { + case 0x1b50: + // F1 + scan_code = 0x3b; + char_code = 0x0; + break; + default: + printf("%s(): unknown multibyte keycode: %llx\n", + __FUNCTION__, *keycode); + break; + } + } + //assemble scan/char code in keycode + *keycode = (uint64_t) ((((uint16_t) scan_code) << 8) | char_code); +} + +// handle int16 (Keyboard BIOS Interrupt) +void +handleInt16() +{ + // keyboard buffer is in BIOS Memory Area: + // offset 0x1a (WORD) pointer to next char in keybuffer + // offset 0x1c (WORD) pointer to next insert slot in keybuffer + // offset 0x1e-0x3e: 16 WORD Ring Buffer + // since we currently always read the char from the FW buffer, + // we misuse the ring buffer, we use it as pointer to a uint64_t that stores + // multi-byte keys (e.g. special keys in VT100 terminal) + // and as long as a key is available (not 0) we dont read further keys + uint64_t *keycode = (uint64_t *) (M.mem_base + 0x41e); + int8_t c; + // function number in AH + DEBUG_PRINTF_INTR("%s(): Keyboard Interrupt: function: %x.\n", + __FUNCTION__, M.x86.R_AH); + DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n", M.x86.R_AX, + M.x86.R_BX, M.x86.R_CX, M.x86.R_DX); + switch (M.x86.R_AH) { + case 0x00: + // get keystroke + if (*keycode) { + M.x86.R_AX = (uint16_t) * keycode; + // clear keycode + *keycode = 0; + } else { + M.x86.R_AH = 0x61; // scancode for space key + M.x86.R_AL = 0x20; // a space + } + break; + case 0x01: + // check keystroke + // ZF set = no keystroke + // read first byte of key code + if (*keycode) { + // already read, but not yet taken + CLEAR_FLAG(F_ZF); + M.x86.R_AX = (uint16_t) * keycode; + } else { + c = getchar(); + if (c == -1) { + // no key available + SET_FLAG(F_ZF); + } else { + *keycode = c; + + // since after an ESC it may take a while to receive the next char, + // we send something that is not shown on the screen, and then try to get + // the next char + // TODO: only after ESC?? what about other multibyte keys + printf("tt%c%c", 0x08, 0x08); // 0x08 == Backspace + + while ((c = getchar()) != -1) { + *keycode = (*keycode << 8) | c; + DEBUG_PRINTF(" key read: %0llx\n", + *keycode); + } + translate_keycode(keycode); + DEBUG_PRINTF(" translated key: %0llx\n", + *keycode); + if (*keycode == 0) { + //not found + SET_FLAG(F_ZF); + } else { + CLEAR_FLAG(F_ZF); + M.x86.R_AX = (uint16_t) * keycode; + //X86EMU_trace_on(); + //M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F; + } + } + } + break; + default: + printf("%s(): unknown function (%x) for int16 handler.\n", + __FUNCTION__, M.x86.R_AH); + DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n", + M.x86.R_AX, M.x86.R_BX, M.x86.R_CX, + M.x86.R_DX); + HALT_SYS(); + break; + } +} + // handle int1a (PCI BIOS Interrupt) void handleInt1a() @@ -62,10 +330,14 @@ handleInt1a() // NOTE: we currently only allow the device to find itself... // it SHOULD be all we ever need... // device_id in CX, vendor_id in DX + // device index in SI (i.e. if multiple devices with same vendor/device id + // are connected). We currently only support device index 0 DEBUG_PRINTF_INTR("%s(): function: %x: PCI Find Device\n", __FUNCTION__, M.x86.R_AX); if ((M.x86.R_CX == bios_device.pci_device_id) - && (M.x86.R_DX == bios_device.pci_vendor_id)) { + && (M.x86.R_DX == bios_device.pci_vendor_id) + // device index must be 0 + && (M.x86.R_SI == 0)) { CLEAR_FLAG(F_CF); M.x86.R_AH = 0x00; // return code: success M.x86.R_BH = bios_device.bus; @@ -75,9 +347,9 @@ handleInt1a() __FUNCTION__, M.x86.R_AX, M.x86.R_BX); } else { DEBUG_PRINTF_INTR - ("%s(): function %x: invalid device/vendor! (%04x/%04x expected: %04x/%04x) \n", + ("%s(): function %x: invalid device/vendor/device index! (%04x/%04x/%02x expected: %04x/%04x/0) \n", __FUNCTION__, M.x86.R_AX, M.x86.R_CX, M.x86.R_DX, - bios_device.pci_device_id, + M.x86.R_SI, bios_device.pci_device_id, bios_device.pci_vendor_id); SET_FLAG(F_CF); M.x86.R_AH = 0x86; // return code: device not found @@ -189,16 +461,14 @@ handleInt1a() } break; default: - DEBUG_PRINTF_INTR - ("%s(): unknown function (%x) for int1a handler.\n", - __FUNCTION__, M.x86.R_AX); + printf("%s(): unknown function (%x) for int1a handler.\n", + __FUNCTION__, M.x86.R_AX); DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n", M.x86.R_AX, M.x86.R_BX, M.x86.R_CX, M.x86.R_DX); HALT_SYS(); break; } - } // main Interrupt Handler routine, should be registered as x86emu interrupt handler @@ -206,32 +476,49 @@ void handleInterrupt(int intNum) { uint8_t int_handled = 0; +#ifndef DEBUG_PRINT_INT10 + // this printf makes output by int 10 unreadable... + // so we only enable it, if int10 print is disabled DEBUG_PRINTF_INTR("%s(%x)\n", __FUNCTION__, intNum); +#endif switch (intNum) { case 0x10: //BIOS video interrupt case 0x42: // INT 10h relocated by EGA/VGA BIOS case 0x6d: // INT 10h relocated by VGA BIOS // get interrupt vector from IDT (4 bytes per Interrupt starting at address 0 - if (my_rdl(intNum * 4) == 0xF000F065) //F000:F065 is default BIOS interrupt handler address + if ((my_rdl(intNum * 4) == 0xF000F065) || //F000:F065 is default BIOS interrupt handler address + (my_rdl(intNum * 4) == 0xF4F4F4F4)) //invalid { - // default handler called, ignore interrupt... +#if 0 + // ignore interrupt... DEBUG_PRINTF_INTR - ("%s(%x): default interrupt Vector (%08x) found, interrupt ignored...\n", + ("%s(%x): invalid interrupt Vector (%08x) found, interrupt ignored...\n", __FUNCTION__, intNum, my_rdl(intNum * 4)); DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n", M.x86.R_AX, M.x86.R_BX, M.x86.R_CX, M.x86.R_DX); //HALT_SYS(); +#endif + handleInt10(); int_handled = 1; } break; + case 0x16: + // Keyboard BIOS Interrupt + handleInt16(); + int_handled = 1; + break; case 0x1a: // PCI BIOS Interrupt handleInt1a(); int_handled = 1; break; default: - DEBUG_PRINTF_INTR("Interrupt %#x (Vector: %x) not implemented\n", intNum, my_rdl(intNum * 4)); // 4bytes per interrupt vector... + printf("Interrupt %#x (Vector: %x) not implemented\n", intNum, + my_rdl(intNum * 4)); + DEBUG_PRINTF_INTR("AX=%04x BX=%04x CX=%04x DX=%04x\n", + M.x86.R_AX, M.x86.R_BX, M.x86.R_CX, + M.x86.R_DX); int_handled = 1; HALT_SYS(); break; @@ -247,9 +534,9 @@ void runInt10() { // Initialize stack and data segment - M.x86.R_SS = 0x0030; - M.x86.R_DS = 0x0040; - M.x86.R_SP = 0xfffe; + M.x86.R_SS = STACK_SEGMENT; + M.x86.R_DS = DATA_SEGMENT; + M.x86.R_SP = STACK_START_OFFSET; // push a HLT instruction and a pointer to it onto the stack // any return will pop the pointer and jump to the HLT, thus @@ -264,19 +551,57 @@ runInt10() M.x86.R_CS = M.x86.R_SS; M.x86.R_IP = M.x86.R_SP; // + 4; -#ifdef DEBUG_TRACE_X86EMU - X86EMU_trace_on(); -#endif -#ifdef DEBUG_JMP - M.x86.debug |= DEBUG_TRACEJMP_REGS_F; - M.x86.debug |= DEBUG_TRACEJMP_REGS_F; - M.x86.debug |= DEBUG_TRACECALL_F; - M.x86.debug |= DEBUG_TRACECALL_REGS_F; -#endif - + CHECK_DBG(DEBUG_TRACE_X86EMU) { + X86EMU_trace_on(); + } + CHECK_DBG(DEBUG_JMP) { + M.x86.debug |= DEBUG_TRACEJMP_REGS_F; + M.x86.debug |= DEBUG_TRACEJMP_REGS_F; + M.x86.debug |= DEBUG_TRACECALL_F; + M.x86.debug |= DEBUG_TRACECALL_REGS_F; + } setupInt(0x10); DEBUG_PRINTF_INTR("%s(): starting execution of INT10...\n", __FUNCTION__); X86EMU_exec(); DEBUG_PRINTF_INTR("%s(): execution finished\n", __FUNCTION__); } + +// prepare and execute Interrupt 13 (Disk Interrupt) +void +runInt13() +{ + // Initialize stack and data segment + M.x86.R_SS = STACK_SEGMENT; + M.x86.R_DS = DATA_SEGMENT; + M.x86.R_SP = STACK_START_OFFSET; + + // push a HLT instruction and a pointer to it onto the stack + // any return will pop the pointer and jump to the HLT, thus + // exiting (more or less) cleanly + push_word(0xf4f4); //F4=HLT + //push_word(M.x86.R_SS); + //push_word(M.x86.R_SP + 2); + + // setupInt will push the current CS and IP to the stack to return to it, + // but we want to halt, so set CS:IP to the HLT instruction we just pushed + // to the stack + M.x86.R_CS = M.x86.R_SS; + M.x86.R_IP = M.x86.R_SP; + + CHECK_DBG(DEBUG_TRACE_X86EMU) { + X86EMU_trace_on(); + } + CHECK_DBG(DEBUG_JMP) { + M.x86.debug |= DEBUG_TRACEJMP_REGS_F; + M.x86.debug |= DEBUG_TRACEJMP_REGS_F; + M.x86.debug |= DEBUG_TRACECALL_F; + M.x86.debug |= DEBUG_TRACECALL_REGS_F; + } + + setupInt(0x13); + DEBUG_PRINTF_INTR("%s(): starting execution of INT13...\n", + __FUNCTION__); + X86EMU_exec(); + DEBUG_PRINTF_INTR("%s(): execution finished\n", __FUNCTION__); +} diff --git a/clients/net-snk/app/biosemu/interrupt.h b/clients/net-snk/app/biosemu/interrupt.h index 2d3f979..9c09086 100644 --- a/clients/net-snk/app/biosemu/interrupt.h +++ b/clients/net-snk/app/biosemu/interrupt.h @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License @@ -16,4 +16,6 @@ void handleInterrupt(int intNum); void runInt10(); +void runInt13(); + #endif diff --git a/clients/net-snk/app/biosemu/io.c b/clients/net-snk/app/biosemu/io.c index 9329eca..53653d3 100644 --- a/clients/net-snk/app/biosemu/io.c +++ b/clients/net-snk/app/biosemu/io.c @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License @@ -16,13 +16,16 @@ #include "rtas.h" #include "debug.h" #include "device.h" -#include <types.h> +#include <stdint.h> #include <x86emu/x86emu.h> +#include <time.h> // those are defined in net-snk/oflib/pci.c -// currently not used... -//extern unsigned int read_io(void *, size_t); -//extern int write_io(void *, unsigned int, size_t); +extern unsigned int read_io(void *, size_t); +extern int write_io(void *, unsigned int, size_t); + +//defined in net-snk/kernel/timer.c +extern uint64_t get_time(void); // these are not used, only needed for linking, must be overridden using X86emu_setupPioFuncs // with the functions and struct below @@ -71,29 +74,57 @@ inl(uint16_t port) return 0; } +uint32_t pci_cfg_read(X86EMU_pioAddr addr, uint8_t size); +void pci_cfg_write(X86EMU_pioAddr addr, uint32_t val, uint8_t size); +uint8_t handle_port_61h(); + uint8_t my_inb(X86EMU_pioAddr addr) { + uint8_t rval = 0xFF; uint64_t translated_addr = addr; uint8_t translated = dev_translate_address(&translated_addr); if (translated != 0) { - //translation successfull, access VGA I/O (BAR or Legacy...) - DEBUG_PRINTF_IO("%s(%x): access to VGA I/O\n", __FUNCTION__, + //translation successfull, access Device I/O (BAR or Legacy...) + DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __FUNCTION__, addr); //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr); - set_ci(); - uint8_t rval = *((uint8_t *) translated_addr); - DEBUG_PRINTF_IO("%s(%04x) VGA I/O --> %02x\n", __FUNCTION__, + rval = read_io((void *)translated_addr, 1); + DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %02x\n", __FUNCTION__, addr, rval); - clr_ci(); return rval; } else { - DEBUG_PRINTF_IO("%s(%04x) reading from bios_device.io_buffer\n", - __FUNCTION__, addr); - uint8_t rval = *((uint8_t *) (bios_device.io_buffer + addr)); - DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %02x\n", __FUNCTION__, - addr, rval); - return rval; + switch (addr) { + case 0x61: + //8254 KB Controller / Timer Port + rval = handle_port_61h(); + //DEBUG_PRINTF_IO("%s(%04x) KB / Timer Port B --> %02x\n", __FUNCTION__, addr, rval); + return rval; + break; + case 0xCFC: + case 0xCFD: + case 0xCFE: + case 0xCFF: + // PCI Config Mechanism 1 Ports + return (uint8_t) pci_cfg_read(addr, 1); + break; + case 0x0a: + CHECK_DBG(DEBUG_INTR) { + X86EMU_trace_on(); + } + M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F; + //HALT_SYS(); + // no break, intentional fall-through to default!! + default: + DEBUG_PRINTF_IO + ("%s(%04x) reading from bios_device.io_buffer\n", + __FUNCTION__, addr); + rval = *((uint8_t *) (bios_device.io_buffer + addr)); + DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %02x\n", + __FUNCTION__, addr, rval); + return rval; + break; + } } } @@ -103,33 +134,42 @@ my_inw(X86EMU_pioAddr addr) uint64_t translated_addr = addr; uint8_t translated = dev_translate_address(&translated_addr); if (translated != 0) { - //translation successfull, access VGA I/O (BAR or Legacy...) - DEBUG_PRINTF_IO("%s(%x): access to VGA I/O\n", __FUNCTION__, + //translation successfull, access Device I/O (BAR or Legacy...) + DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __FUNCTION__, addr); //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr); uint16_t rval; if ((translated_addr & (uint64_t) 0x1) == 0) { // 16 bit aligned access... - set_ci(); - rval = in16le((void *) translated_addr); - clr_ci(); + uint16_t tempval = read_io((void *)translated_addr, 2); + //little endian conversion + rval = in16le((void *) &tempval); } else { - // unaligned access, read single bytes - set_ci(); - rval = (*((uint8_t *) translated_addr)) | - (*((uint8_t *) translated_addr + 1) << 8); - clr_ci(); + // unaligned access, read single bytes, little-endian + rval = (read_io((void *)translated_addr, 1) << 8) + | (read_io((void *)(translated_addr + 1), 1)); } - DEBUG_PRINTF_IO("%s(%04x) VGA I/O --> %04x\n", __FUNCTION__, + DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %04x\n", __FUNCTION__, addr, rval); return rval; } else { - DEBUG_PRINTF_IO("%s(%04x) reading from bios_device.io_buffer\n", - __FUNCTION__, addr); - uint16_t rval = in16le((void *) bios_device.io_buffer + addr); - DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %04x\n", __FUNCTION__, - addr, rval); - return rval; + switch (addr) { + case 0xCFC: + case 0xCFE: + //PCI Config Mechanism 1 + return (uint16_t) pci_cfg_read(addr, 2); + break; + default: + DEBUG_PRINTF_IO + ("%s(%04x) reading from bios_device.io_buffer\n", + __FUNCTION__, addr); + uint16_t rval = + in16le((void *) bios_device.io_buffer + addr); + DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %04x\n", + __FUNCTION__, addr, rval); + return rval; + break; + } } } @@ -139,70 +179,43 @@ my_inl(X86EMU_pioAddr addr) uint64_t translated_addr = addr; uint8_t translated = dev_translate_address(&translated_addr); if (translated != 0) { - //translation successfull, access VGA I/O (BAR or Legacy...) - DEBUG_PRINTF_IO("%s(%x): access to VGA I/O\n", __FUNCTION__, + //translation successfull, access Device I/O (BAR or Legacy...) + DEBUG_PRINTF_IO("%s(%x): access to Device I/O\n", __FUNCTION__, addr); //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr); uint32_t rval; if ((translated_addr & (uint64_t) 0x2) == 0) { // 32 bit aligned access... - set_ci(); - rval = in32le((void *) translated_addr); - clr_ci(); + uint32_t tempval = read_io((void *) translated_addr, 4); + //little endian conversion + rval = in32le((void *) &tempval); } else { - // unaligned access, read single bytes - set_ci(); - rval = (*((uint8_t *) translated_addr)) | - (*((uint8_t *) translated_addr + 1) << 8) | - (*((uint8_t *) translated_addr + 2) << 16) | - (*((uint8_t *) translated_addr + 3) << 24); - clr_ci(); + // unaligned access, read single bytes, little-endian + rval = (read_io((void *)(translated_addr), 1) << 24) + | (read_io((void *)(translated_addr + 1), 1) << 16) + | (read_io((void *)(translated_addr + 2), 1) << 8) + | (read_io((void *)(translated_addr + 3), 1)); } - DEBUG_PRINTF_IO("%s(%04x) VGA I/O --> %08x\n", __FUNCTION__, + DEBUG_PRINTF_IO("%s(%04x) Device I/O --> %08x\n", __FUNCTION__, addr, rval); return rval; - } else if (addr == 0xcfc) { - // PCI Configuration Mechanism 1 step 1 - // write to 0xCF8, sets bus, device, function and Config Space offset - // later read from 0xCFC returns the value... - uint8_t bus, devfn, offs; - uint32_t port_cf8_val = my_inl(0xcf8); - if ((port_cf8_val & 0x80000000) != 0) { - //highest bit enables config space mapping - bus = (port_cf8_val & 0x00FF0000) >> 16; - devfn = (port_cf8_val & 0x0000FF00) >> 8; - offs = (port_cf8_val & 0x000000FF); - if ((bus != bios_device.bus) - || (devfn != bios_device.devfn)) { - // fail accesses to any device but ours... - printf - ("Config access invalid! bus: %x, devfn: %x, offs: %x\n", - bus, devfn, offs); - HALT_SYS(); - return 0xFFFFFFFF; - } else { - DEBUG_PRINTF_IO("%s(%04x) PCI Config Access\n", - __FUNCTION__, addr); - uint32_t rval = - (uint32_t) rtas_pci_config_read(bios_device. - puid, 4, - bus, devfn, - offs); - DEBUG_PRINTF_IO - ("%s(%04x) PCI Config Access --> 0x%08x\n", - __FUNCTION__, addr, rval); - return rval; - } - } else { - return 0xFFFFFFFF; - } } else { - DEBUG_PRINTF_IO("%s(%04x) reading from bios_device.io_buffer\n", - __FUNCTION__, addr); - uint32_t rval = in32le((void *) bios_device.io_buffer + addr); - DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %08x\n", __FUNCTION__, - addr, rval); - return rval; + switch (addr) { + case 0xCFC: + //PCI Config Mechanism 1 + return pci_cfg_read(addr, 4); + break; + default: + DEBUG_PRINTF_IO + ("%s(%04x) reading from bios_device.io_buffer\n", + __FUNCTION__, addr); + uint32_t rval = + in32le((void *) bios_device.io_buffer + addr); + DEBUG_PRINTF_IO("%s(%04x) I/O Buffer --> %08x\n", + __FUNCTION__, addr, rval); + return rval; + break; + } } } @@ -212,18 +225,29 @@ my_outb(X86EMU_pioAddr addr, uint8_t val) uint64_t translated_addr = addr; uint8_t translated = dev_translate_address(&translated_addr); if (translated != 0) { - //translation successfull, access VGA I/O (BAR or Legacy...) - DEBUG_PRINTF_IO("%s(%x, %x): access to VGA I/O\n", + //translation successfull, access Device I/O (BAR or Legacy...) + DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n", __FUNCTION__, addr, val); //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr); - set_ci(); - *((uint8_t *) translated_addr) = val; - clr_ci(); + write_io((void *) translated_addr, val, 1); + DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %02x\n", __FUNCTION__, + addr, val); } else { - DEBUG_PRINTF_IO - ("%s(%04x,%02x) writing to bios_device.io_buffer\n", - __FUNCTION__, addr, val); - *((uint8_t *) (bios_device.io_buffer + addr)) = val; + switch (addr) { + case 0xCFC: + case 0xCFD: + case 0xCFE: + case 0xCFF: + // PCI Config Mechanism 1 Ports + pci_cfg_write(addr, val, 1); + break; + default: + DEBUG_PRINTF_IO + ("%s(%04x,%02x) writing to bios_device.io_buffer\n", + __FUNCTION__, addr, val); + *((uint8_t *) (bios_device.io_buffer + addr)) = val; + break; + } } } @@ -233,27 +257,38 @@ my_outw(X86EMU_pioAddr addr, uint16_t val) uint64_t translated_addr = addr; uint8_t translated = dev_translate_address(&translated_addr); if (translated != 0) { - //translation successfull, access VGA I/O (BAR or Legacy...) + //translation successfull, access Device I/O (BAR or Legacy...) + DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n", + __FUNCTION__, addr, val); //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr); if ((translated_addr & (uint64_t) 0x1) == 0) { + // little-endian conversion + uint16_t tempval = in16le((void *) &val); // 16 bit aligned access... - set_ci(); - out16le((void *) translated_addr, val); - clr_ci(); + write_io((void *) translated_addr, tempval, 2); } else { - // unaligned access, write single bytes - set_ci(); - *((uint8_t *) translated_addr) = - (uint8_t) (val & 0x00FF); - *((uint8_t *) translated_addr + 1) = - (uint8_t) ((val & 0xFF00) >> 8); - clr_ci(); + // unaligned access, write single bytes, little-endian + write_io(((void *) (translated_addr + 1)), + (uint8_t) ((val & 0xFF00) >> 8), 1); + write_io(((void *) translated_addr), + (uint8_t) (val & 0x00FF), 1); } + DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %04x\n", __FUNCTION__, + addr, val); } else { - DEBUG_PRINTF_IO - ("%s(%04x,%04x) writing to bios_device.io_buffer\n", - __FUNCTION__, addr, val); - out16le((void *) bios_device.io_buffer + addr, val); + switch (addr) { + case 0xCFC: + case 0xCFE: + // PCI Config Mechanism 1 Ports + pci_cfg_write(addr, val, 2); + break; + default: + DEBUG_PRINTF_IO + ("%s(%04x,%04x) writing to bios_device.io_buffer\n", + __FUNCTION__, addr, val); + out16le((void *) bios_device.io_buffer + addr, val); + break; + } } } @@ -263,30 +298,134 @@ my_outl(X86EMU_pioAddr addr, uint32_t val) uint64_t translated_addr = addr; uint8_t translated = dev_translate_address(&translated_addr); if (translated != 0) { - //translation successfull, access VGA I/O (BAR or Legacy...) + //translation successfull, access Device I/O (BAR or Legacy...) + DEBUG_PRINTF_IO("%s(%x, %x): access to Device I/O\n", + __FUNCTION__, addr, val); //DEBUG_PRINTF_IO("%s(%04x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr); if ((translated_addr & (uint64_t) 0x3) == 0) { + // little-endian conversion + uint32_t tempval = in32le((void *) &val); // 32 bit aligned access... - set_ci(); - out32le((void *) translated_addr, val); - clr_ci(); + write_io((void *) translated_addr, tempval, 4); } else { - // unaligned access, write single bytes - set_ci(); - *((uint8_t *) translated_addr) = - (uint8_t) (val & 0x000000FF); - *((uint8_t *) translated_addr + 1) = - (uint8_t) ((val & 0x0000FF00) >> 8); - *((uint8_t *) translated_addr + 2) = - (uint8_t) ((val & 0x00FF0000) >> 16); - *((uint8_t *) translated_addr + 3) = - (uint8_t) ((val & 0xFF000000) >> 24); - clr_ci(); + // unaligned access, write single bytes, little-endian + write_io(((void *) translated_addr + 3), + (uint8_t) ((val & 0xFF000000) >> 24), 1); + write_io(((void *) translated_addr + 2), + (uint8_t) ((val & 0x00FF0000) >> 16), 1); + write_io(((void *) translated_addr + 1), + (uint8_t) ((val & 0x0000FF00) >> 8), 1); + write_io(((void *) translated_addr), + (uint8_t) (val & 0x000000FF), 1); } + DEBUG_PRINTF_IO("%s(%04x) Device I/O <-- %08x\n", __FUNCTION__, + addr, val); } else { - DEBUG_PRINTF_IO - ("%s(%04x,%08x) writing to bios_device.io_buffer\n", - __FUNCTION__, addr, val); - out32le((void *) bios_device.io_buffer + addr, val); + switch (addr) { + case 0xCFC: + // PCI Config Mechanism 1 Ports + pci_cfg_write(addr, val, 4); + break; + default: + DEBUG_PRINTF_IO + ("%s(%04x,%08x) writing to bios_device.io_buffer\n", + __FUNCTION__, addr, val); + out32le((void *) bios_device.io_buffer + addr, val); + break; + } + } +} + +uint32_t +pci_cfg_read(X86EMU_pioAddr addr, uint8_t size) +{ + uint32_t rval = 0xFFFFFFFF; + if ((addr >= 0xCFC) && ((addr + size) <= 0xCFF)) { + // PCI Configuration Mechanism 1 step 1 + // write to 0xCF8, sets bus, device, function and Config Space offset + // later read from 0xCFC-0xCFF returns the value... + uint8_t bus, devfn, offs; + uint32_t port_cf8_val = my_inl(0xCF8); + if ((port_cf8_val & 0x80000000) != 0) { + //highest bit enables config space mapping + bus = (port_cf8_val & 0x00FF0000) >> 16; + devfn = (port_cf8_val & 0x0000FF00) >> 8; + offs = (port_cf8_val & 0x000000FF); + offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly + if ((bus != bios_device.bus) + || (devfn != bios_device.devfn)) { + // fail accesses to any device but ours... + printf + ("Config access invalid! bus: %x, devfn: %x, offs: %x\n", + bus, devfn, offs); + HALT_SYS(); + } else { + rval = + (uint32_t) rtas_pci_config_read(bios_device. + puid, size, + bus, devfn, + offs); + DEBUG_PRINTF_IO + ("%s(%04x) PCI Config Read @%02x, size: %d --> 0x%08x\n", + __FUNCTION__, addr, offs, size, rval); + } + } + } + return rval; +} + +void +pci_cfg_write(X86EMU_pioAddr addr, uint32_t val, uint8_t size) +{ + if ((addr >= 0xCFC) && ((addr + size) <= 0xCFF)) { + // PCI Configuration Mechanism 1 step 1 + // write to 0xCF8, sets bus, device, function and Config Space offset + // later write to 0xCFC-0xCFF sets the value... + uint8_t bus, devfn, offs; + uint32_t port_cf8_val = my_inl(0xCF8); + if ((port_cf8_val & 0x80000000) != 0) { + //highest bit enables config space mapping + bus = (port_cf8_val & 0x00FF0000) >> 16; + devfn = (port_cf8_val & 0x0000FF00) >> 8; + offs = (port_cf8_val & 0x000000FF); + offs += (addr - 0xCFC); // if addr is not 0xcfc, the offset is moved accordingly + if ((bus != bios_device.bus) + || (devfn != bios_device.devfn)) { + // fail accesses to any device but ours... + printf + ("Config access invalid! bus: %x, devfn: %x, offs: %x\n", + bus, devfn, offs); + HALT_SYS(); + } else { + rtas_pci_config_write(bios_device.puid, + size, bus, devfn, offs, + val); + DEBUG_PRINTF_IO + ("%s(%04x) PCI Config Write @%02x, size: %d <-- 0x%08x\n", + __FUNCTION__, addr, offs, size, val); + } + } + } +} + +uint8_t +handle_port_61h() +{ + static uint64_t last_time = 0; + uint64_t curr_time = get_time(); + uint64_t time_diff; // time since last call + uint32_t period_ticks; // length of a period in ticks + uint32_t nr_periods; //number of periods passed since last call + // bit 4 should toggle with every (DRAM) refresh cycle... (66kHz??) + time_diff = curr_time - last_time; + // at 66kHz a period is ~ 15 ns long, converted to ticks: (tb_freq is ticks/second) + // TODO: as long as the frequency does not change, we should not calculate this every time + period_ticks = (15 * tb_freq) / 1000000; + nr_periods = time_diff / period_ticks; + // if the number if ticks passed since last call is odd, we toggle bit 4 + if ((nr_periods % 2) != 0) { + *((uint8_t *) (bios_device.io_buffer + 0x61)) ^= 0x10; } + //finally read the value from the io_buffer + return *((uint8_t *) (bios_device.io_buffer + 0x61)); } diff --git a/clients/net-snk/app/biosemu/io.h b/clients/net-snk/app/biosemu/io.h index d01f82b..5a0bb4b 100644 --- a/clients/net-snk/app/biosemu/io.h +++ b/clients/net-snk/app/biosemu/io.h @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License @@ -13,7 +13,7 @@ #ifndef _BIOSEMU_IO_H_ #define _BIOSEMU_IO_H_ #include <x86emu/x86emu.h> -#include <types.h> +#include <stdint.h> uint8_t my_inb(X86EMU_pioAddr addr); diff --git a/clients/net-snk/app/biosemu/mem.c b/clients/net-snk/app/biosemu/mem.c index 3e29b38..d9ad46d 100644 --- a/clients/net-snk/app/biosemu/mem.c +++ b/clients/net-snk/app/biosemu/mem.c @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License @@ -11,11 +11,163 @@ *****************************************************************************/ #include <stdio.h> -#include <types.h> +#include <stdint.h> #include <cpu.h> #include "debug.h" #include "device.h" #include "x86emu/x86emu.h" +#include "biosemu.h" +#include <time.h> + +// define a check for access to certain (virtual) memory regions (interrupt handlers, BIOS Data Area, ...) +#ifdef DEBUG +static uint8_t in_check = 0; // to avoid recursion... +uint16_t ebda_segment; +uint32_t ebda_size; + +//TODO: these macros have grown so large, that they should be changed to an inline function, +//just for the sake of readability... + +//declare prototypes of the functions to follow, for use in DEBUG_CHECK_VMEM_ACCESS +uint8_t my_rdb(uint32_t); +uint16_t my_rdw(uint32_t); +uint32_t my_rdl(uint32_t); + +#define DEBUG_CHECK_VMEM_READ(_addr, _rval) \ + if ((debug_flags & DEBUG_CHECK_VMEM_ACCESS) && (in_check == 0)) { \ + in_check = 1; \ + /* determine ebda_segment and size \ + * since we are using my_rdx calls, make sure, this is after setting in_check! */ \ + /* offset 03 in BDA is EBDA segment */ \ + ebda_segment = my_rdw(0x40e); \ + /* first value in ebda is size in KB */ \ + ebda_size = my_rdb(ebda_segment << 4) * 1024; \ + /* check Interrupt Vector Access (0000:0000h - 0000:0400h) */ \ + if (_addr < 0x400) { \ + DEBUG_PRINTF_CS_IP("%s: read from Interrupt Vector %x --> %x\n", \ + __FUNCTION__, _addr / 4, _rval); \ + } \ + /* access to BIOS Data Area (0000:0400h - 0000:0500h)*/ \ + else if ((_addr >= 0x400) && (addr < 0x500)) { \ + DEBUG_PRINTF_CS_IP("%s: read from BIOS Data Area: addr: %x --> %x\n", \ + __FUNCTION__, _addr, _rval); \ + /* dump registers */ \ + /* x86emu_dump_xregs(); */ \ + } \ + /* access to first 64k of memory... */ \ + else if (_addr < 0x10000) { \ + DEBUG_PRINTF_CS_IP("%s: read from segment 0000h: addr: %x --> %x\n", \ + __FUNCTION__, _addr, _rval); \ + /* dump registers */ \ + /* x86emu_dump_xregs(); */ \ + } \ + /* read from PMM_CONV_SEGMENT */ \ + else if ((_addr <= ((PMM_CONV_SEGMENT << 4) | 0xffff)) && (_addr >= (PMM_CONV_SEGMENT << 4))) { \ + DEBUG_PRINTF_CS_IP("%s: read from PMM Segment %04xh: addr: %x --> %x\n", \ + __FUNCTION__, PMM_CONV_SEGMENT, _addr, _rval); \ + /* HALT_SYS(); */ \ + /* dump registers */ \ + /* x86emu_dump_xregs(); */ \ + } \ + /* read from PNP_DATA_SEGMENT */ \ + else if ((_addr <= ((PNP_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (PNP_DATA_SEGMENT << 4))) { \ + DEBUG_PRINTF_CS_IP("%s: read from PnP Data Segment %04xh: addr: %x --> %x\n", \ + __FUNCTION__, PNP_DATA_SEGMENT, _addr, _rval); \ + /* HALT_SYS(); */ \ + /* dump registers */ \ + /* x86emu_dump_xregs(); */ \ + } \ + /* read from EBDA Segment */ \ + else if ((_addr <= ((ebda_segment << 4) | (ebda_size - 1))) && (_addr >= (ebda_segment << 4))) { \ + DEBUG_PRINTF_CS_IP("%s: read from Extended BIOS Data Area %04xh, size: %04x: addr: %x --> %x\n", \ + __FUNCTION__, ebda_segment, ebda_size, _addr, _rval); \ + } \ + /* read from BIOS_DATA_SEGMENT */ \ + else if ((_addr <= ((BIOS_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (BIOS_DATA_SEGMENT << 4))) { \ + DEBUG_PRINTF_CS_IP("%s: read from BIOS Data Segment %04xh: addr: %x --> %x\n", \ + __FUNCTION__, BIOS_DATA_SEGMENT, _addr, _rval); \ + /* for PMM debugging */ \ + /*if (_addr == BIOS_DATA_SEGMENT << 4) { \ + X86EMU_trace_on(); \ + M.x86.debug &= ~DEBUG_DECODE_NOPRINT_F; \ + }*/ \ + /* dump registers */ \ + /* x86emu_dump_xregs(); */ \ + } \ + in_check = 0; \ + } +#define DEBUG_CHECK_VMEM_WRITE(_addr, _val) \ + if ((debug_flags & DEBUG_CHECK_VMEM_ACCESS) && (in_check == 0)) { \ + in_check = 1; \ + /* determine ebda_segment and size \ + * since we are using my_rdx calls, make sure, this is after setting in_check! */ \ + /* offset 03 in BDA is EBDA segment */ \ + ebda_segment = my_rdw(0x40e); \ + /* first value in ebda is size in KB */ \ + ebda_size = my_rdb(ebda_segment << 4) * 1024; \ + /* check Interrupt Vector Access (0000:0000h - 0000:0400h) */ \ + if (_addr < 0x400) { \ + DEBUG_PRINTF_CS_IP("%s: write to Interrupt Vector %x <-- %x\n", \ + __FUNCTION__, _addr / 4, _val); \ + } \ + /* access to BIOS Data Area (0000:0400h - 0000:0500h)*/ \ + else if ((_addr >= 0x400) && (addr < 0x500)) { \ + DEBUG_PRINTF_CS_IP("%s: write to BIOS Data Area: addr: %x <-- %x\n", \ + __FUNCTION__, _addr, _val); \ + /* dump registers */ \ + /* x86emu_dump_xregs(); */ \ + } \ + /* access to first 64k of memory...*/ \ + else if (_addr < 0x10000) { \ + DEBUG_PRINTF_CS_IP("%s: write to segment 0000h: addr: %x <-- %x\n", \ + __FUNCTION__, _addr, _val); \ + /* dump registers */ \ + /* x86emu_dump_xregs(); */ \ + } \ + /* write to PMM_CONV_SEGMENT... */ \ + else if ((_addr <= ((PMM_CONV_SEGMENT << 4) | 0xffff)) && (_addr >= (PMM_CONV_SEGMENT << 4))) { \ + DEBUG_PRINTF_CS_IP("%s: write to PMM Segment %04xh: addr: %x <-- %x\n", \ + __FUNCTION__, PMM_CONV_SEGMENT, _addr, _val); \ + /* dump registers */ \ + /* x86emu_dump_xregs(); */ \ + } \ + /* write to PNP_DATA_SEGMENT... */ \ + else if ((_addr <= ((PNP_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (PNP_DATA_SEGMENT << 4))) { \ + DEBUG_PRINTF_CS_IP("%s: write to PnP Data Segment %04xh: addr: %x <-- %x\n", \ + __FUNCTION__, PNP_DATA_SEGMENT, _addr, _val); \ + /* dump registers */ \ + /* x86emu_dump_xregs(); */ \ + } \ + /* write to EBDA Segment... */ \ + else if ((_addr <= ((ebda_segment << 4) | (ebda_size - 1))) && (_addr >= (ebda_segment << 4))) { \ + DEBUG_PRINTF_CS_IP("%s: write to Extended BIOS Data Area %04xh, size: %04x: addr: %x <-- %x\n", \ + __FUNCTION__, ebda_segment, ebda_size, _addr, _val); \ + } \ + /* write to BIOS_DATA_SEGMENT... */ \ + else if ((_addr <= ((BIOS_DATA_SEGMENT << 4) | 0xffff)) && (_addr >= (BIOS_DATA_SEGMENT << 4))) { \ + DEBUG_PRINTF_CS_IP("%s: write to BIOS Data Segment %04xh: addr: %x <-- %x\n", \ + __FUNCTION__, BIOS_DATA_SEGMENT, _addr, _val); \ + /* dump registers */ \ + /* x86emu_dump_xregs(); */ \ + } \ + /* write to current CS segment... */ \ + else if ((_addr < ((M.x86.R_CS << 4) | 0xffff)) && (_addr > (M.x86.R_CS << 4))) { \ + DEBUG_PRINTF_CS_IP("%s: write to CS segment %04xh: addr: %x <-- %x\n", \ + __FUNCTION__, M.x86.R_CS, _addr, _val); \ + /* dump registers */ \ + /* x86emu_dump_xregs(); */ \ + } \ + in_check = 0; \ + } +#else +#define DEBUG_CHECK_VMEM_READ(_addr, _rval) +#define DEBUG_CHECK_VMEM_WRITE(_addr, _val) +#endif + +//defined in net-snk/kernel/timer.c +extern uint64_t get_time(void); + +void update_time(uint32_t); // read byte from memory uint8_t @@ -23,13 +175,14 @@ my_rdb(uint32_t addr) { uint64_t translated_addr = addr; uint8_t translated = dev_translate_address(&translated_addr); + uint8_t rval; if (translated != 0) { //translation successfull, access VGA Memory (BAR or Legacy...) DEBUG_PRINTF_MEM("%s(%08x): access to VGA Memory\n", __FUNCTION__, addr); //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr); set_ci(); - uint8_t rval = *((uint8_t *) translated_addr); + rval = *((uint8_t *) translated_addr); clr_ci(); DEBUG_PRINTF_MEM("%s(%08x) VGA --> %02x\n", __FUNCTION__, addr, rval); @@ -41,9 +194,10 @@ my_rdb(uint32_t addr) HALT_SYS(); } else { /* read from virtual memory */ - return *((uint8_t *) (M.mem_base + addr)); + rval = *((uint8_t *) (M.mem_base + addr)); + DEBUG_CHECK_VMEM_READ(addr, rval); + return rval; } - // never reached return -1; } @@ -53,12 +207,12 @@ my_rdw(uint32_t addr) { uint64_t translated_addr = addr; uint8_t translated = dev_translate_address(&translated_addr); + uint16_t rval; if (translated != 0) { //translation successfull, access VGA Memory (BAR or Legacy...) DEBUG_PRINTF_MEM("%s(%08x): access to VGA Memory\n", __FUNCTION__, addr); //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr); - uint16_t rval; // check for legacy memory, because of the remapping to BARs, the reads must // be byte reads... if ((addr >= 0xa0000) && (addr < 0xc0000)) { @@ -91,9 +245,10 @@ my_rdw(uint32_t addr) HALT_SYS(); } else { /* read from virtual memory */ - return in16le((void *) (M.mem_base + addr)); + rval = in16le((void *) (M.mem_base + addr)); + DEBUG_CHECK_VMEM_READ(addr, rval); + return rval; } - // never reached return -1; } @@ -103,12 +258,12 @@ my_rdl(uint32_t addr) { uint64_t translated_addr = addr; uint8_t translated = dev_translate_address(&translated_addr); + uint32_t rval; if (translated != 0) { //translation successfull, access VGA Memory (BAR or Legacy...) DEBUG_PRINTF_MEM("%s(%x): access to VGA Memory\n", __FUNCTION__, addr); //DEBUG_PRINTF_MEM("%s(%08x): translated_addr: %llx\n", __FUNCTION__, addr, translated_addr); - uint32_t rval; // check for legacy memory, because of the remapping to BARs, the reads must // be byte reads... if ((addr >= 0xa0000) && (addr < 0xc0000)) { @@ -146,9 +301,17 @@ my_rdl(uint32_t addr) HALT_SYS(); } else { /* read from virtual memory */ - return in32le((void *) (M.mem_base + addr)); + rval = in32le((void *) (M.mem_base + addr)); + switch (addr) { + case 0x46c: + //BDA Time Data, update it, before reading + update_time(rval); + rval = in32le((void *) (M.mem_base + addr)); + break; + } + DEBUG_CHECK_VMEM_READ(addr, rval); + return rval; } - // never reached return -1; } @@ -173,6 +336,7 @@ my_wrb(uint32_t addr, uint8_t val) HALT_SYS(); } else { /* write to virtual memory */ + DEBUG_CHECK_VMEM_WRITE(addr, val); *((uint8_t *) (M.mem_base + addr)) = val; } } @@ -218,6 +382,7 @@ my_wrw(uint32_t addr, uint16_t val) HALT_SYS(); } else { /* write to virtual memory */ + DEBUG_CHECK_VMEM_WRITE(addr, val); out16le((void *) (M.mem_base + addr), val); } } @@ -268,6 +433,31 @@ my_wrl(uint32_t addr, uint32_t val) HALT_SYS(); } else { /* write to virtual memory */ + DEBUG_CHECK_VMEM_WRITE(addr, val); out32le((void *) (M.mem_base + addr), val); } } + +//update time in BIOS Data Area +//DWord at offset 0x6c is the timer ticks since midnight, timer is running at 18Hz +//byte at 0x70 is timer overflow (set if midnight passed since last call to interrupt 1a function 00 +//cur_val is the current value, of offset 6c... +void +update_time(uint32_t cur_val) +{ + //for convenience, we let the start of timebase be at midnight, we currently dont support + //real daytime anyway... + uint64_t ticks_per_day = tb_freq * 60 * 24; + // at 18Hz a period is ~55ms, converted to ticks (tb_freq is ticks/second) + uint32_t period_ticks = (55 * tb_freq) / 1000; + uint64_t curr_time = get_time(); + uint64_t ticks_since_midnight = curr_time % ticks_per_day; + uint32_t periods_since_midnight = ticks_since_midnight / period_ticks; + // if periods since midnight is smaller than last value, set overflow + // at BDA Offset 0x70 + if (periods_since_midnight < cur_val) { + my_wrb(0x470, 1); + } + // store periods since midnight at BDA offset 0x6c + my_wrl(0x46c, periods_since_midnight); +} diff --git a/clients/net-snk/app/biosemu/mem.h b/clients/net-snk/app/biosemu/mem.h index efce891..f0fbad9 100644 --- a/clients/net-snk/app/biosemu/mem.h +++ b/clients/net-snk/app/biosemu/mem.h @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License @@ -13,7 +13,7 @@ #ifndef _BIOSEMU_MEM_H_ #define _BIOSEMU_MEM_H_ #include <x86emu/x86emu.h> -#include <types.h> +#include <stdint.h> // read byte from memory uint8_t my_rdb(uint32_t addr); diff --git a/clients/net-snk/app/biosemu/vbe.c b/clients/net-snk/app/biosemu/vbe.c index 7f9ebe7..06b1b18 100644 --- a/clients/net-snk/app/biosemu/vbe.c +++ b/clients/net-snk/app/biosemu/vbe.c @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License @@ -14,7 +14,7 @@ #include <stdlib.h> #include <string.h> -#include <types.h> +#include <stdint.h> #include <cpu.h> #include "debug.h" @@ -23,10 +23,10 @@ #include <x86emu/regs.h> #include <x86emu/prim_ops.h> // for push_word +#include "biosemu.h" #include "io.h" #include "mem.h" #include "interrupt.h" - #include "device.h" static X86EMU_memFuncs my_mem_funcs = { @@ -99,7 +99,7 @@ typedef struct { static inline uint8_t vbe_prepare() { - vbe_info_buffer = biosmem + 0x10000; // segment:offset 1000:0000 + vbe_info_buffer = biosmem + (VBE_SEGMENT << 4); // segment:offset off VBE Data Area //clear buffer memset(vbe_info_buffer, 0, 512); //set VbeSignature to "VBE2" to indicate VBE 2.0+ request @@ -107,9 +107,9 @@ vbe_prepare() vbe_info_buffer[0] = 'B'; vbe_info_buffer[0] = 'E'; vbe_info_buffer[0] = '2'; - // ES:DI store pointer to buffer in virtual mem (@ 0x10000) see vbe_info_buffer above... + // ES:DI store pointer to buffer in virtual mem see vbe_info_buffer above... M.x86.R_EDI = 0x0; - M.x86.R_ES = 0x1000; + M.x86.R_ES = VBE_SEGMENT; return 0; // successfull init } @@ -123,10 +123,9 @@ vbe_info(vbe_info_t * info) M.x86.R_EAX = 0x4f00; // enable trace -#ifdef DEBUG_TRACE_X86EMU - X86EMU_trace_on(); -#endif - + CHECK_DBG(DEBUG_TRACE_X86EMU) { + X86EMU_trace_on(); + } // run VESA Interrupt runInt10(); @@ -194,10 +193,9 @@ vbe_get_mode_info(vbe_mode_info_t * mode_info) M.x86.R_CX = mode_info->video_mode; // enable trace -#ifdef DEBUG_TRACE_X86EMU - X86EMU_trace_on(); -#endif - + CHECK_DBG(DEBUG_TRACE_X86EMU) { + X86EMU_trace_on(); + } // run VESA Interrupt runInt10(); @@ -268,10 +266,9 @@ vbe_set_mode(vbe_mode_info_t * mode_info) M.x86.R_BX); // enable trace -#ifdef DEBUG_TRACE_X86EMU - X86EMU_trace_on(); -#endif - + CHECK_DBG(DEBUG_TRACE_X86EMU) { + X86EMU_trace_on(); + } // run VESA Interrupt runInt10(); @@ -305,10 +302,9 @@ vbe_set_palette_format(uint8_t format) format); // enable trace -#ifdef DEBUG_TRACE_X86EMU - X86EMU_trace_on(); -#endif - + CHECK_DBG(DEBUG_TRACE_X86EMU) { + X86EMU_trace_on(); + } // run VESA Interrupt runInt10(); @@ -349,10 +345,9 @@ vbe_set_color(uint16_t color_number, uint32_t color_value) color_number, color_value); // enable trace -#ifdef DEBUG_TRACE_X86EMU - X86EMU_trace_on(); -#endif - + CHECK_DBG(DEBUG_TRACE_X86EMU) { + X86EMU_trace_on(); + } // run VESA Interrupt runInt10(); @@ -386,10 +381,9 @@ vbe_get_color(uint16_t color_number, uint32_t * color_value) M.x86.R_DI = 0x0; // enable trace -#ifdef DEBUG_TRACE_X86EMU - X86EMU_trace_on(); -#endif - + CHECK_DBG(DEBUG_TRACE_X86EMU) { + X86EMU_trace_on(); + } // run VESA Interrupt runInt10(); @@ -428,10 +422,9 @@ vbe_get_ddc_info(vbe_ddc_info_t * ddc_info) M.x86.R_DI = 0x0; // enable trace -#ifdef DEBUG_TRACE_X86EMU - X86EMU_trace_on(); -#endif - + CHECK_DBG(DEBUG_TRACE_X86EMU) { + X86EMU_trace_on(); + } // run VESA Interrupt runInt10(); @@ -464,10 +457,9 @@ vbe_get_ddc_info(vbe_ddc_info_t * ddc_info) M.x86.R_DI = 0x0; // enable trace -#ifdef DEBUG_TRACE_X86EMU - X86EMU_trace_on(); -#endif - + CHECK_DBG(DEBUG_TRACE_X86EMU) { + X86EMU_trace_on(); + } // run VESA Interrupt runInt10(); @@ -493,11 +485,11 @@ vbe_get_ddc_info(vbe_ddc_info_t * ddc_info) } uint32_t -vbe_get_info(uint8_t argc, uint8_t ** argv) +vbe_get_info(uint8_t argc, char ** argv) { uint8_t rval; uint32_t i; - if (argc < 3) { + if (argc < 4) { printf ("Usage %s <vmem_base> <device_path> <address of screen_info_t>\n", argv[0]); @@ -507,23 +499,29 @@ vbe_get_info(uint8_t argc, uint8_t ** argv) } return -1; } - // argv[1] is address of virtual BIOS mem... it should be 1MB large... - biosmem = (uint8_t *) strtoul((char *) argv[1], 0, 16); - biosmem_size = 0x100000; - // argv[2] is the device to open and use... - if (dev_init((char *) argv[2]) != 0) { - printf("Error initializing device!\n"); - return -1; - } // get a copy of input struct... screen_info_input_t input = - *((screen_info_input_t *) strtoul((char *) argv[3], 0, 16)); - // output is pointer to the address passed as argv[3] + *((screen_info_input_t *) strtoul((char *) argv[4], 0, 16)); + // output is pointer to the address passed as argv[4] screen_info_t *output = - (screen_info_t *) strtoul((char *) argv[3], 0, 16); + (screen_info_t *) strtoul((char *) argv[4], 0, 16); // zero output memset(output, 0, sizeof(screen_info_t)); + // argv[1] is address of virtual BIOS mem... + // argv[2] is the size + biosmem = (uint8_t *) strtoul(argv[1], 0, 16); + biosmem_size = strtoul(argv[2], 0, 16);; + if (biosmem_size < MIN_REQUIRED_VMEM_SIZE) { + printf("Error: Not enough virtual memory: %x, required: %x!\n", + biosmem_size, MIN_REQUIRED_VMEM_SIZE); + return -1; + } + // argv[3] is the device to open and use... + if (dev_init((char *) argv[3]) != 0) { + printf("Error initializing device!\n"); + return -1; + } //setup interrupt handler X86EMU_intrFuncs intrFuncs[256]; for (i = 0; i < 256; i++) @@ -557,7 +555,7 @@ vbe_get_info(uint8_t argc, uint8_t ** argv) (info.capabilities & 0x4) == 0 ? "normal" : "use blank bit in Function 09h"); - // argv[3] may be a pointer with enough space to return screen_info_t + // argv[4] may be a pointer with enough space to return screen_info_t // as input, it must contain a screen_info_input_t with the following content: // byte[0:3] = "DDC\0" (zero-terminated signature header) // byte[4:5] = reserved space for the return struct... just in case we ever change @@ -566,224 +564,212 @@ vbe_get_info(uint8_t argc, uint8_t ** argv) // byte[6] = monitor port number for DDC requests ("only" one byte... so lets hope we never have more than 255 monitors... // byte[7:8] = max. screen width (OF may want to limit this) // byte[9] = required color depth in bpp - if (argc >= 4) { - if (strncmp((char *) input.signature, "DDC", 4) != 0) { - printf - ("%s: Invalid input signature! expected: %s, is: %s\n", - __FUNCTION__, "DDC", input.signature); - return -1; - } - if (input.size_reserved != sizeof(screen_info_t)) { - printf - ("%s: Size of return struct is wrong, required: %d, available: %d\n", - __FUNCTION__, (int) sizeof(screen_info_t), - input.size_reserved); - return -1; - } + if (strncmp((char *) input.signature, "DDC", 4) != 0) { + printf + ("%s: Invalid input signature! expected: %s, is: %s\n", + __FUNCTION__, "DDC", input.signature); + return -1; + } + if (input.size_reserved != sizeof(screen_info_t)) { + printf + ("%s: Size of return struct is wrong, required: %d, available: %d\n", + __FUNCTION__, (int) sizeof(screen_info_t), + input.size_reserved); + return -1; + } - vbe_ddc_info_t ddc_info; - ddc_info.port_number = input.monitor_number; - vbe_get_ddc_info(&ddc_info); + vbe_ddc_info_t ddc_info; + ddc_info.port_number = input.monitor_number; + vbe_get_ddc_info(&ddc_info); #if 0 - DEBUG_PRINTF_VBE("DDC: edid_tranfer_time: %d\n", - ddc_info.edid_transfer_time); - DEBUG_PRINTF_VBE("DDC: ddc_level: %x\n", ddc_info.ddc_level); - DEBUG_PRINTF_VBE("DDC: EDID: \n"); -#ifdef DEBUG_VBE + DEBUG_PRINTF_VBE("DDC: edid_tranfer_time: %d\n", + ddc_info.edid_transfer_time); + DEBUG_PRINTF_VBE("DDC: ddc_level: %x\n", ddc_info.ddc_level); + DEBUG_PRINTF_VBE("DDC: EDID: \n"); + CHECK_DBG(DEBUG_VBE) { dump(ddc_info.edid_block_zero, sizeof(ddc_info.edid_block_zero)); + } #endif -#endif - if (*((uint64_t *) ddc_info.edid_block_zero) != - (uint64_t) 0x00FFFFFFFFFFFF00) { - // invalid EDID signature... probably no monitor - - output->display_type = 0x0; - return 0; - } else if ((ddc_info.edid_block_zero[20] & 0x80) != 0) { - // digital display - output->display_type = 2; - } else { - // analog - output->display_type = 1; - } - DEBUG_PRINTF_VBE("DDC: found display type %d\n", - output->display_type); - memcpy(output->edid_block_zero, ddc_info.edid_block_zero, - sizeof(ddc_info.edid_block_zero)); - i = 0; - vbe_mode_info_t mode_info; - vbe_mode_info_t best_mode_info; - // initialize best_mode to 0 - memset(&best_mode_info, 0, sizeof(best_mode_info)); - while ((mode_info.video_mode = - info.video_mode_list[i]) != 0xFFFF) { - //DEBUG_PRINTF_VBE("%x: Mode: %04x\n", i, mode_info.video_mode); - vbe_get_mode_info(&mode_info); + if (*((uint64_t *) ddc_info.edid_block_zero) != + (uint64_t) 0x00FFFFFFFFFFFF00) { + // invalid EDID signature... probably no monitor + + output->display_type = 0x0; + return 0; + } else if ((ddc_info.edid_block_zero[20] & 0x80) != 0) { + // digital display + output->display_type = 2; + } else { + // analog + output->display_type = 1; + } + DEBUG_PRINTF_VBE("DDC: found display type %d\n", output->display_type); + memcpy(output->edid_block_zero, ddc_info.edid_block_zero, + sizeof(ddc_info.edid_block_zero)); + i = 0; + vbe_mode_info_t mode_info; + vbe_mode_info_t best_mode_info; + // initialize best_mode to 0 + memset(&best_mode_info, 0, sizeof(best_mode_info)); + while ((mode_info.video_mode = info.video_mode_list[i]) != 0xFFFF) { + //DEBUG_PRINTF_VBE("%x: Mode: %04x\n", i, mode_info.video_mode); + vbe_get_mode_info(&mode_info); #if 0 - DEBUG_PRINTF_VBE("Video Mode 0x%04x available, %s\n", - mode_info.video_mode, - (mode_info.attributes & 0x1) == - 0 ? "not supported" : "supported"); - DEBUG_PRINTF_VBE("\tTTY: %s\n", - (mode_info.attributes & 0x4) == - 0 ? "no" : "yes"); - DEBUG_PRINTF_VBE("\tMode: %s %s\n", - (mode_info.attributes & 0x8) == - 0 ? "monochrome" : "color", - (mode_info.attributes & 0x10) == - 0 ? "text" : "graphics"); - DEBUG_PRINTF_VBE("\tVGA: %s\n", - (mode_info.attributes & 0x20) == - 0 ? "compatible" : "not compatible"); - DEBUG_PRINTF_VBE("\tWindowed Mode: %s\n", - (mode_info.attributes & 0x40) == - 0 ? "yes" : "no"); - DEBUG_PRINTF_VBE("\tFramebuffer: %s\n", - (mode_info.attributes & 0x80) == - 0 ? "no" : "yes"); - DEBUG_PRINTF_VBE("\tResolution: %dx%d\n", - mode_info.x_resolution, - mode_info.y_resolution); - DEBUG_PRINTF_VBE("\tChar Size: %dx%d\n", - mode_info.x_charsize, - mode_info.y_charsize); - DEBUG_PRINTF_VBE("\tColor Depth: %dbpp\n", - mode_info.bits_per_pixel); - DEBUG_PRINTF_VBE("\tMemory Model: 0x%x\n", - mode_info.memory_model); - DEBUG_PRINTF_VBE("\tFramebuffer Offset: %08x\n", - mode_info.framebuffer_address); + DEBUG_PRINTF_VBE("Video Mode 0x%04x available, %s\n", + mode_info.video_mode, + (mode_info.attributes & 0x1) == + 0 ? "not supported" : "supported"); + DEBUG_PRINTF_VBE("\tTTY: %s\n", + (mode_info.attributes & 0x4) == + 0 ? "no" : "yes"); + DEBUG_PRINTF_VBE("\tMode: %s %s\n", + (mode_info.attributes & 0x8) == + 0 ? "monochrome" : "color", + (mode_info.attributes & 0x10) == + 0 ? "text" : "graphics"); + DEBUG_PRINTF_VBE("\tVGA: %s\n", + (mode_info.attributes & 0x20) == + 0 ? "compatible" : "not compatible"); + DEBUG_PRINTF_VBE("\tWindowed Mode: %s\n", + (mode_info.attributes & 0x40) == + 0 ? "yes" : "no"); + DEBUG_PRINTF_VBE("\tFramebuffer: %s\n", + (mode_info.attributes & 0x80) == + 0 ? "no" : "yes"); + DEBUG_PRINTF_VBE("\tResolution: %dx%d\n", + mode_info.x_resolution, + mode_info.y_resolution); + DEBUG_PRINTF_VBE("\tChar Size: %dx%d\n", + mode_info.x_charsize, mode_info.y_charsize); + DEBUG_PRINTF_VBE("\tColor Depth: %dbpp\n", + mode_info.bits_per_pixel); + DEBUG_PRINTF_VBE("\tMemory Model: 0x%x\n", + mode_info.memory_model); + DEBUG_PRINTF_VBE("\tFramebuffer Offset: %08x\n", + mode_info.framebuffer_address); #endif - if ((mode_info.bits_per_pixel == input.color_depth) - && (mode_info.x_resolution <= - input.max_screen_width) - && ((mode_info.attributes & 0x80) != 0) // framebuffer mode - && ((mode_info.attributes & 0x10) != 0) // graphics - && ((mode_info.attributes & 0x8) != 0) // color - && (mode_info.x_resolution > best_mode_info.x_resolution)) // better than previous best_mode - { - // yiiiihaah... we found a new best mode - memcpy(&best_mode_info, &mode_info, - sizeof(mode_info)); - } - i++; + if ((mode_info.bits_per_pixel == input.color_depth) + && (mode_info.x_resolution <= input.max_screen_width) + && ((mode_info.attributes & 0x80) != 0) // framebuffer mode + && ((mode_info.attributes & 0x10) != 0) // graphics + && ((mode_info.attributes & 0x8) != 0) // color + && (mode_info.x_resolution > best_mode_info.x_resolution)) // better than previous best_mode + { + // yiiiihaah... we found a new best mode + memcpy(&best_mode_info, &mode_info, sizeof(mode_info)); } + i++; + } - if (best_mode_info.video_mode != 0) { - DEBUG_PRINTF_VBE - ("Best Video Mode found: 0x%x, %dx%d, %dbpp, framebuffer_address: 0x%x\n", - best_mode_info.video_mode, - best_mode_info.x_resolution, - best_mode_info.y_resolution, - best_mode_info.bits_per_pixel, - best_mode_info.framebuffer_address); - - //printf("Mode Info Dump:"); - //dump(best_mode_info.mode_info_block, 64); - - // set the video mode - vbe_set_mode(&best_mode_info); - - if ((info.capabilities & 0x1) != 0) { - // switch to 8 bit palette format - vbe_set_palette_format(8); - } - // setup a palette: - // - first 216 colors are mixed colors for each component in 6 steps - // (6*6*6=216) - // - then 10 shades of the three primary colors - // - then 10 shades of grey - // ------- - // = 256 colors - // - // - finally black is color 0 and white color FF (because SLOF expects it - // this way...) - // this resembles the palette that the kernel/X Server seems to expect... - - uint8_t mixed_color_values[6] = - { 0xFF, 0xDA, 0xB3, 0x87, 0x54, 0x00 }; - uint8_t primary_color_values[10] = - { 0xF3, 0xE7, 0xCD, 0xC0, 0xA5, 0x96, 0x77, 0x66, - 0x3F, 0x27 }; - uint8_t mc_size = sizeof(mixed_color_values); - uint8_t prim_size = sizeof(primary_color_values); - - uint8_t curr_color_index; - uint32_t curr_color; - - uint8_t r, g, b; - // 216 mixed colors - for (r = 0; r < mc_size; r++) { - for (g = 0; g < mc_size; g++) { - for (b = 0; b < mc_size; b++) { - curr_color_index = - (r * mc_size * mc_size) + - (g * mc_size) + b; - curr_color = 0; - curr_color |= ((uint32_t) mixed_color_values[r]) << 16; //red value - curr_color |= ((uint32_t) mixed_color_values[g]) << 8; //green value - curr_color |= (uint32_t) mixed_color_values[b]; //blue value - vbe_set_color(curr_color_index, - curr_color); - } + if (best_mode_info.video_mode != 0) { + DEBUG_PRINTF_VBE + ("Best Video Mode found: 0x%x, %dx%d, %dbpp, framebuffer_address: 0x%x\n", + best_mode_info.video_mode, + best_mode_info.x_resolution, + best_mode_info.y_resolution, + best_mode_info.bits_per_pixel, + best_mode_info.framebuffer_address); + + //printf("Mode Info Dump:"); + //dump(best_mode_info.mode_info_block, 64); + + // set the video mode + vbe_set_mode(&best_mode_info); + + if ((info.capabilities & 0x1) != 0) { + // switch to 8 bit palette format + vbe_set_palette_format(8); + } + // setup a palette: + // - first 216 colors are mixed colors for each component in 6 steps + // (6*6*6=216) + // - then 10 shades of the three primary colors + // - then 10 shades of grey + // ------- + // = 256 colors + // + // - finally black is color 0 and white color FF (because SLOF expects it + // this way...) + // this resembles the palette that the kernel/X Server seems to expect... + + uint8_t mixed_color_values[6] = + { 0xFF, 0xDA, 0xB3, 0x87, 0x54, 0x00 }; + uint8_t primary_color_values[10] = + { 0xF3, 0xE7, 0xCD, 0xC0, 0xA5, 0x96, 0x77, 0x66, 0x3F, + 0x27 + }; + uint8_t mc_size = sizeof(mixed_color_values); + uint8_t prim_size = sizeof(primary_color_values); + + uint8_t curr_color_index; + uint32_t curr_color; + + uint8_t r, g, b; + // 216 mixed colors + for (r = 0; r < mc_size; r++) { + for (g = 0; g < mc_size; g++) { + for (b = 0; b < mc_size; b++) { + curr_color_index = + (r * mc_size * mc_size) + + (g * mc_size) + b; + curr_color = 0; + curr_color |= ((uint32_t) mixed_color_values[r]) << 16; //red value + curr_color |= ((uint32_t) mixed_color_values[g]) << 8; //green value + curr_color |= (uint32_t) mixed_color_values[b]; //blue value + vbe_set_color(curr_color_index, + curr_color); } } + } - // 10 shades of each primary color - // red - for (r = 0; r < prim_size; r++) { - curr_color_index = - mc_size * mc_size * mc_size + r; - curr_color = - ((uint32_t) primary_color_values[r]) << 16; - vbe_set_color(curr_color_index, curr_color); - } - //green - for (g = 0; g < prim_size; g++) { - curr_color_index = - mc_size * mc_size * mc_size + prim_size + g; - curr_color = - ((uint32_t) primary_color_values[g]) << 8; - vbe_set_color(curr_color_index, curr_color); - } - //blue - for (b = 0; b < prim_size; b++) { - curr_color_index = - mc_size * mc_size * mc_size + - prim_size * 2 + b; - curr_color = (uint32_t) primary_color_values[b]; - vbe_set_color(curr_color_index, curr_color); - } - // 10 shades of grey - for (i = 0; i < prim_size; i++) { - curr_color_index = - mc_size * mc_size * mc_size + - prim_size * 3 + i; - curr_color = 0; - curr_color |= ((uint32_t) primary_color_values[i]) << 16; //red - curr_color |= ((uint32_t) primary_color_values[i]) << 8; //green - curr_color |= ((uint32_t) primary_color_values[i]); //blue - vbe_set_color(curr_color_index, curr_color); - } - - // SLOF is using color 0x0 (black) and 0xFF (white) to draw to the screen... - vbe_set_color(0x00, 0x00000000); - vbe_set_color(0xFF, 0x00FFFFFF); - - output->screen_width = best_mode_info.x_resolution; - output->screen_height = best_mode_info.y_resolution; - output->screen_linebytes = best_mode_info.linebytes; - output->color_depth = best_mode_info.bits_per_pixel; - output->framebuffer_address = - best_mode_info.framebuffer_address; - } else { - printf("%s: No suitable video mode found!\n", - __FUNCTION__); - //unset display_type... - output->display_type = 0; + // 10 shades of each primary color + // red + for (r = 0; r < prim_size; r++) { + curr_color_index = mc_size * mc_size * mc_size + r; + curr_color = ((uint32_t) primary_color_values[r]) << 16; + vbe_set_color(curr_color_index, curr_color); } + //green + for (g = 0; g < prim_size; g++) { + curr_color_index = + mc_size * mc_size * mc_size + prim_size + g; + curr_color = ((uint32_t) primary_color_values[g]) << 8; + vbe_set_color(curr_color_index, curr_color); + } + //blue + for (b = 0; b < prim_size; b++) { + curr_color_index = + mc_size * mc_size * mc_size + prim_size * 2 + b; + curr_color = (uint32_t) primary_color_values[b]; + vbe_set_color(curr_color_index, curr_color); + } + // 10 shades of grey + for (i = 0; i < prim_size; i++) { + curr_color_index = + mc_size * mc_size * mc_size + prim_size * 3 + i; + curr_color = 0; + curr_color |= ((uint32_t) primary_color_values[i]) << 16; //red + curr_color |= ((uint32_t) primary_color_values[i]) << 8; //green + curr_color |= ((uint32_t) primary_color_values[i]); //blue + vbe_set_color(curr_color_index, curr_color); + } + + // SLOF is using color 0x0 (black) and 0xFF (white) to draw to the screen... + vbe_set_color(0x00, 0x00000000); + vbe_set_color(0xFF, 0x00FFFFFF); + + output->screen_width = best_mode_info.x_resolution; + output->screen_height = best_mode_info.y_resolution; + output->screen_linebytes = best_mode_info.linebytes; + output->color_depth = best_mode_info.bits_per_pixel; + output->framebuffer_address = + best_mode_info.framebuffer_address; + } else { + printf("%s: No suitable video mode found!\n", __FUNCTION__); + //unset display_type... + output->display_type = 0; } return 0; } diff --git a/clients/net-snk/app/biosemu/vbe.h b/clients/net-snk/app/biosemu/vbe.h index 3fe3c8a..07daedb 100644 --- a/clients/net-snk/app/biosemu/vbe.h +++ b/clients/net-snk/app/biosemu/vbe.h @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License diff --git a/clients/net-snk/app/main.c b/clients/net-snk/app/main.c index 2910901..ed0a291 100644 --- a/clients/net-snk/app/main.c +++ b/clients/net-snk/app/main.c @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License @@ -21,6 +21,15 @@ extern int biosemu(char argc, char**argv); extern int vbe_get_info(char argc, char**argv); #endif +#ifdef SNK_GENMODULE_APPS +extern int forth(int, char*[]); +extern int snkshell(void); +#endif + +#ifdef SNK_LJTAG_PROCESS +extern int ljtag(char argc, char**argv); +#endif + extern void _callback_entry(void); int @@ -29,7 +38,10 @@ main(int argc, char *argv[]) int i; of_set_callback((void *) &_callback_entry); - if (strcmp(argv[0], "netboot") == 0 && argc >= 4) +#ifdef SNK_LJTAG_PROCESS + return ljtag(argc, argv); +#else + if (strcmp(argv[0], "netboot") == 0 && argc >= 5) return netboot(argc, argv); if (strcmp(argv[0], "netflash") == 0) return netflash(argc, argv); @@ -42,6 +54,13 @@ main(int argc, char *argv[]) if (strcmp(argv[0], "get_vbe_info") == 0) return vbe_get_info(argc, argv); #endif +#ifdef SNK_GENMODULE_APPS + if (strcmp(argv[0], "forth") == 0) + return forth(argc, argv); + if (strcmp(argv[0], "snkshell") == 0) + return snkshell(); +#endif +#endif printf("Unknown client application called\n"); for (i = 0; i < argc; i++) diff --git a/clients/net-snk/app/netapps/Makefile b/clients/net-snk/app/netapps/Makefile index 9882a18..a40cb95 100644 --- a/clients/net-snk/app/netapps/Makefile +++ b/clients/net-snk/app/netapps/Makefile @@ -1,5 +1,5 @@ # ***************************************************************************** -# * Copyright (c) 2004, 2007 IBM Corporation +# * Copyright (c) 2004, 2008 IBM Corporation # * All rights reserved. # * This program and the accompanying materials # * are made available under the terms of the BSD License diff --git a/clients/net-snk/app/netapps/args.c b/clients/net-snk/app/netapps/args.c index ac71342..2f4a615 100644 --- a/clients/net-snk/app/netapps/args.c +++ b/clients/net-snk/app/netapps/args.c @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License diff --git a/clients/net-snk/app/netapps/args.h b/clients/net-snk/app/netapps/args.h index 99c1c78..b80982a 100644 --- a/clients/net-snk/app/netapps/args.h +++ b/clients/net-snk/app/netapps/args.h @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License diff --git a/clients/net-snk/app/netapps/netapps.h b/clients/net-snk/app/netapps/netapps.h index 836edd4..8b0a5e7 100644 --- a/clients/net-snk/app/netapps/netapps.h +++ b/clients/net-snk/app/netapps/netapps.h @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License diff --git a/clients/net-snk/app/netapps/netboot.c b/clients/net-snk/app/netapps/netboot.c index b0f8c87..13202a7 100644 --- a/clients/net-snk/app/netapps/netboot.c +++ b/clients/net-snk/app/netapps/netboot.c @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License @@ -10,78 +10,155 @@ * IBM Corporation - initial implementation *****************************************************************************/ -#include <netlib/netlib.h> -#include <netlib/netbase.h> -#include <netlib/icmp.h> -#include <ctype.h> -#include <stdio.h> -#include <stdlib.h> +#include <netlib/tftp.h> +#include <netlib/ethernet.h> +#include <netlib/dhcp.h> +//#include <netlib/dhcpv6.h> +#include <netlib/ipv4.h> +//#include <netlib/ipv6.h> #include <string.h> +#include <stdio.h> #include <time.h> +#include <stdlib.h> +#include <sys/socket.h> #include <netapps/args.h> #include <libbootmsg/libbootmsg.h> -#include <sys/socket.h> #include <of.h> #define IP_INIT_DEFAULT 2 #define IP_INIT_NONE 0 #define IP_INIT_BOOTP 1 #define IP_INIT_DHCP 2 +#define IP_INIT_DHCPV6_STATELESS 3 +#define IP_INIT_IPV6_MANUAL 4 #define DEFAULT_BOOT_RETRIES 600 #define DEFAULT_TFTP_RETRIES 20 +static int ip_version = 4; typedef struct { + char filename[100]; int ip_init; char siaddr[4]; - char filename[100]; + //ip6_addr_t si6addr; char ciaddr[4]; + //ip6_addr_t ci6addr; char giaddr[4]; + //ip6_addr_t gi6addr; int bootp_retries; int tftp_retries; } obp_tftp_args_t; + /** - * Parses a argument string which is given by netload, extracts all - * parameters and fills a structure according to this - * - * Netload-Parameters: - * [bootp,]siaddr,filename,ciaddr,giaddr,bootp-retries,tftp-retries + * Parses a argument string for IPv6 booting, extracts all + * parameters and fills a structure accordingly * * @param arg_str string with arguments, seperated with ',' + * @param argc number of arguments * @param obp_tftp_args structure which contains the result - * @return none + * @return updated arg_str */ -static void parse_args(const char *arg_str, obp_tftp_args_t *obp_tftp_args) { - unsigned int argc; +/* +static const char * +parse_ipv6args (const char *arg_str, unsigned int argc, + obp_tftp_args_t *obp_tftp_args) +{ + char *ptr = NULL; char arg_buf[100]; - char *ptr; - argc = get_args_count(arg_str); + // find out siaddr + if (argc == 0) + memset(&obp_tftp_args->si6addr.addr, 0, 16); + else { + argncpy(arg_str, 0, arg_buf, 100); + if(parseip6(arg_buf, (uint8_t *) &(obp_tftp_args->si6addr.addr[0]))) { + arg_str = get_arg_ptr(arg_str, 1); + --argc; + } + else if(arg_buf[0] == 0) { + memset(&obp_tftp_args->si6addr.addr, 0, 16); + arg_str = get_arg_ptr(arg_str, 1); + --argc; + } + else + memset(&obp_tftp_args->si6addr.addr, 0, 16); + } - // find out if we should use BOOTP or DHCP - if(argc==0) - obp_tftp_args->ip_init = IP_INIT_DEFAULT; + // find out filename + if (argc == 0) + obp_tftp_args->filename[0] = 0; + else { + argncpy(arg_str, 0, obp_tftp_args->filename, 100); + for(ptr = obp_tftp_args->filename; *ptr != 0; ++ptr) + if(*ptr == '\\') { + *ptr = '/'; + } + arg_str = get_arg_ptr(arg_str, 1); + --argc; + } + + // find out ciaddr + if (argc == 0) + memset(&obp_tftp_args->ci6addr, 0, 16); else { argncpy(arg_str, 0, arg_buf, 100); - if(strcasecmp(arg_buf, "bootp") == 0) { - obp_tftp_args->ip_init = IP_INIT_BOOTP; + if (parseip6(arg_buf, (uint8_t *) &(obp_tftp_args->ci6addr.addr)) ) { arg_str = get_arg_ptr(arg_str, 1); --argc; } - else if(strcasecmp(arg_buf, "dhcp") == 0) { - obp_tftp_args->ip_init = IP_INIT_DHCP; + else if(arg_buf[0] == 0) { + memset(&obp_tftp_args->ci6addr.addr, 0, 16); arg_str = get_arg_ptr(arg_str, 1); --argc; } else - obp_tftp_args->ip_init = IP_INIT_DEFAULT; + memset(&obp_tftp_args->ci6addr.addr, 0, 16); } + // find out giaddr + if (argc == 0) + memset(&obp_tftp_args->gi6addr, 0, 16); + else { + argncpy(arg_str, 0, arg_buf, 100); + if (parseip6(arg_buf, (uint8_t *) &(obp_tftp_args->gi6addr.addr)) ) { + arg_str = get_arg_ptr(arg_str, 1); + --argc; + } + else if(arg_buf[0] == 0) { + memset(&obp_tftp_args->gi6addr, 0, 16); + arg_str = get_arg_ptr(arg_str, 1); + --argc; + } + else + memset(&obp_tftp_args->gi6addr.addr, 0, 16); + } + + return arg_str; +} +*/ + + +/** + * Parses a argument string for IPv4 booting, extracts all + * parameters and fills a structure accordingly + * + * @param arg_str string with arguments, seperated with ',' + * @param argc number of arguments + * @param obp_tftp_args structure which contains the result + * @return updated arg_str + */ +static const char * +parse_ipv4args (const char *arg_str, unsigned int argc, + obp_tftp_args_t *obp_tftp_args) +{ + char *ptr = NULL; + char arg_buf[100]; + // find out siaddr - if(argc==0) + if(argc==0) { memset(obp_tftp_args->siaddr, 0, 4); - else { + } else { argncpy(arg_str, 0, arg_buf, 100); if(strtoip(arg_buf, obp_tftp_args->siaddr)) { arg_str = get_arg_ptr(arg_str, 1); @@ -144,8 +221,64 @@ static void parse_args(const char *arg_str, obp_tftp_args_t *obp_tftp_args) { memset(obp_tftp_args->giaddr, 0, 4); } - // find out bootp-retries + return arg_str; +} + +/** + * Parses a argument string which is given by netload, extracts all + * parameters and fills a structure according to this + * + * Netload-Parameters: + * [bootp,]siaddr,filename,ciaddr,giaddr,bootp-retries,tftp-retries + * + * @param arg_str string with arguments, seperated with ',' + * @param obp_tftp_args structure which contains the result + * @return none + */ +static void +parse_args(const char *arg_str, obp_tftp_args_t *obp_tftp_args) +{ + unsigned int argc; + char arg_buf[100]; + + argc = get_args_count(arg_str); + + // find out if we should use BOOTP or DHCP if(argc==0) + obp_tftp_args->ip_init = IP_INIT_DEFAULT; + else { + argncpy(arg_str, 0, arg_buf, 100); + if (strcasecmp(arg_buf, "bootp") == 0) { + obp_tftp_args->ip_init = IP_INIT_BOOTP; + arg_str = get_arg_ptr(arg_str, 1); + --argc; + } + else if(strcasecmp(arg_buf, "dhcp") == 0) { + obp_tftp_args->ip_init = IP_INIT_DHCP; + arg_str = get_arg_ptr(arg_str, 1); + --argc; + } + else if(strcasecmp(arg_buf, "ipv6") == 0) { + obp_tftp_args->ip_init = IP_INIT_DHCPV6_STATELESS; + arg_str = get_arg_ptr(arg_str, 1); + --argc; + ip_version = 6; + } + else + obp_tftp_args->ip_init = IP_INIT_DEFAULT; + } + + if (ip_version == 4) { + arg_str = parse_ipv4args (arg_str, argc, obp_tftp_args); + } +/* + else if (ip_version == 6) { + arg_str = parse_ipv6args (arg_str, argc, obp_tftp_args); + } +*/ + + // find out bootp-retries + if (argc == 0) obp_tftp_args->bootp_retries = DEFAULT_BOOT_RETRIES; else { argncpy(arg_str, 0, arg_buf, 100); @@ -161,7 +294,7 @@ static void parse_args(const char *arg_str, obp_tftp_args_t *obp_tftp_args) { } // find out tftp-retries - if(argc==0) + if (argc == 0) obp_tftp_args->tftp_retries = DEFAULT_TFTP_RETRIES; else { argncpy(arg_str, 0, arg_buf, 100); @@ -190,10 +323,18 @@ netboot(int argc, char *argv[]) tftp_err_t tftp_err; obp_tftp_args_t obp_tftp_args; char null_ip[4] = { 0x00, 0x00, 0x00, 0x00 }; +/* + char null_ip6[16] = { 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; +*/ int huge_load = strtol(argv[4], 0, 10); + int32_t block_size = strtol(argv[5], 0, 10); + uint8_t own_mac[6]; printf("\n"); - printf(" Bootloader 1.5 \n"); + printf(" Bootloader 1.6 \n"); memset(&fn_ip, 0, sizeof(filename_ip_t)); /*********************************************************** @@ -208,7 +349,7 @@ netboot(int argc, char *argv[]) set_timer(TICKS_SEC); while (get_timer() > 0); } - fd_device = socket(0, 0, 0, (char *) fn_ip.own_mac); + fd_device = socket(0, 0, 0, (char*) own_mac); if(fd_device != -2) break; if(getchar() == 27) { @@ -234,11 +375,14 @@ netboot(int argc, char *argv[]) printf(" Reading MAC address from device: " "%02x:%02x:%02x:%02x:%02x:%02x\n", - fn_ip.own_mac[0], fn_ip.own_mac[1], fn_ip.own_mac[2], - fn_ip.own_mac[3], fn_ip.own_mac[4], fn_ip.own_mac[5]); + own_mac[0], own_mac[1], own_mac[2], + own_mac[3], own_mac[4], own_mac[5]); - if (argc >= 5) { - parse_args(argv[5], &obp_tftp_args); + // init ethernet layer + set_mac_address(own_mac); + + if (argc > 6) { + parse_args(argv[6], &obp_tftp_args); if(obp_tftp_args.bootp_retries - rc < DEFAULT_BOOT_RETRIES) obp_tftp_args.bootp_retries = DEFAULT_BOOT_RETRIES; else @@ -252,40 +396,35 @@ netboot(int argc, char *argv[]) } memcpy(&fn_ip.own_ip, obp_tftp_args.ciaddr, 4); - // init network stack - netbase_init(fd_device, fn_ip.own_mac, fn_ip.own_ip); - // reset of error code rc = 0; /* if we still have got all necessary parameters, then we don't need to perform an BOOTP/DHCP-Request */ - if(memcmp(obp_tftp_args.ciaddr, null_ip, 4) != 0 - && memcmp(obp_tftp_args.siaddr, null_ip, 4) != 0 - && obp_tftp_args.filename[0] != 0) { - memcpy(&fn_ip.server_ip, obp_tftp_args.siaddr, 4); - - // try to get the MAC address of the TFTP server - if (net_iptomac(fn_ip.server_ip, fn_ip.server_mac)) { - // we got it + if (ip_version == 4) { + if (memcmp(obp_tftp_args.ciaddr, null_ip, 4) != 0 + && memcmp(obp_tftp_args.siaddr, null_ip, 4) != 0 + && obp_tftp_args.filename[0] != 0) { + + memcpy(&fn_ip.server_ip, &obp_tftp_args.siaddr, 4); obp_tftp_args.ip_init = IP_INIT_NONE; } + } +/* + else if (ip_version == 6) { + if (memcmp(&obp_tftp_args.ci6addr, null_ip6, 16) != 0 + && memcmp(&obp_tftp_args.si6addr, null_ip6, 16) != 0 + && obp_tftp_args.filename[0] != 0) { + + memcpy(&fn_ip.server_ip6.addr[0], + &obp_tftp_args.si6addr.addr, 16); + obp_tftp_args.ip_init = IP_INIT_IPV6_MANUAL; + } else { - // figure out if there is a change to get it somehow else - switch(obp_tftp_args.ip_init) { - case IP_INIT_NONE: - case IP_INIT_BOOTP: // BOOTP doesn't help - obp_tftp_args.ip_init = IP_INIT_NONE; - rc = -2; - break; - case IP_INIT_DHCP: // the DHCP server might tell us an - // appropriate router and netmask - default: - break; - } + obp_tftp_args.ip_init = IP_INIT_DHCPV6_STATELESS; } } - +*/ // construction of fn_ip from parameter switch(obp_tftp_args.ip_init) { case IP_INIT_BOOTP: @@ -295,26 +434,33 @@ netboot(int argc, char *argv[]) if(memcmp(obp_tftp_args.giaddr, null_ip, 4) == 0) { // don't do this, when using DHCP !!! fn_ip.server_ip = 0xFFFFFFFF; - memset(fn_ip.server_mac, 0xff, 6); } // if giaddr is specified, then we have to use this // IP address as proxy to identify the BOOTP server else { memcpy(&fn_ip.server_ip, obp_tftp_args.giaddr, 4); - memset(fn_ip.server_mac, 0xff, 6); } - rc = bootp(fd_device, ret_buffer, &fn_ip, obp_tftp_args.bootp_retries); + rc = bootp(ret_buffer, &fn_ip, obp_tftp_args.bootp_retries); break; case IP_INIT_DHCP: printf(" Requesting IP address via DHCP: "); - rc = dhcp(fd_device, ret_buffer, &fn_ip, obp_tftp_args.bootp_retries); + rc = dhcp(ret_buffer, &fn_ip, obp_tftp_args.bootp_retries); + break; +/* + case IP_INIT_DHCPV6_STATELESS: + set_ipv6_address(0); + rc = do_dhcpv6 (ret_buffer, &fn_ip, 10, DHCPV6_STATELESS); + break; + case IP_INIT_IPV6_MANUAL: + set_ipv6_address(&obp_tftp_args.ci6addr); break; +*/ case IP_INIT_NONE: default: break; } - if(rc >= 0) { + if(rc >= 0 && ip_version == 4) { if(memcmp(obp_tftp_args.ciaddr, null_ip, 4) != 0 && memcmp(obp_tftp_args.ciaddr, &fn_ip.own_ip, 4) != 0) memcpy(&fn_ip.own_ip, obp_tftp_args.ciaddr, 4); @@ -323,15 +469,20 @@ netboot(int argc, char *argv[]) && memcmp(obp_tftp_args.siaddr, &fn_ip.server_ip, 4) != 0) memcpy(&fn_ip.server_ip, obp_tftp_args.siaddr, 4); - // reinit network stack - netbase_init(fd_device, fn_ip.own_mac, fn_ip.own_ip); - - if (!net_iptomac(fn_ip.server_ip, fn_ip.server_mac)) { - // printf("\nERROR:\t\t\tCan't obtain TFTP server MAC!\n"); - rc = -2; - } + // init IPv4 layer + set_ipv4_address(fn_ip.own_ip); } - +/* + else if (rc >= 0 && ip_version == 6) { + if(memcmp(&obp_tftp_args.ci6addr.addr, null_ip6, 16) != 0 + && memcmp(&obp_tftp_args.ci6addr.addr, &fn_ip.own_ip6, 16) != 0) + memcpy(&fn_ip.own_ip6, &obp_tftp_args.ci6addr.addr, 16); + + if(memcmp(&obp_tftp_args.si6addr.addr, null_ip6, 16) != 0 + && memcmp(&obp_tftp_args.si6addr.addr, &fn_ip.server_ip6.addr, 16) != 0) + memcpy(&fn_ip.server_ip6.addr, &obp_tftp_args.si6addr.addr, 16); + } +*/ if (rc == -1) { strcpy(buf,"E3001: (net) Could not get IP address"); bootmsg_error(0x3001, &buf[7]); @@ -386,7 +537,9 @@ netboot(int argc, char *argv[]) // accept at most 20 bad packets // wait at most for 40 packets - rc = tftp(fd_device, &fn_ip, (unsigned char *) buffer, len, obp_tftp_args.tftp_retries, &tftp_err, huge_load); + rc = tftp(&fn_ip, (unsigned char *) buffer, + len, obp_tftp_args.tftp_retries, + &tftp_err, huge_load, block_size, ip_version); if(obp_tftp_args.ip_init == IP_INIT_DHCP) dhcp_send_release(); diff --git a/clients/net-snk/app/netapps/netflash.c b/clients/net-snk/app/netapps/netflash.c index 8cdcdad..6865ecb 100644 --- a/clients/net-snk/app/netapps/netflash.c +++ b/clients/net-snk/app/netapps/netflash.c @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License @@ -10,15 +10,15 @@ * IBM Corporation - initial implementation *****************************************************************************/ -#include <netlib/netlib.h> -#include <netlib/netbase.h> -#include <netlib/icmp.h> +#include <netlib/tftp.h> +#include <netlib/dhcp.h> +#include <netlib/ethernet.h> +#include <netlib/ipv4.h> +#include <rtas.h> #include <stdio.h> +#include <string.h> #include <stdlib.h> #include <sys/socket.h> -#include <string.h> - -#include <rtas.h> int netflash(int argc, char * argv[]) { @@ -32,6 +32,7 @@ int netflash(int argc, char * argv[]) int fd_device; tftp_err_t tftp_err; char * ptr; + uint8_t own_mac[6]; printf("\n Flasher 1.4 \n"); memset(&fn_ip, 0, sizeof(filename_ip_t)); @@ -71,7 +72,7 @@ int netflash(int argc, char * argv[]) /* Get mac_addr from device */ printf(" Reading MAC address from device: "); - fd_device = socket(0, 0, 0, (char *) fn_ip.own_mac); + fd_device = socket(0, 0, 0, (char *) own_mac); if (fd_device == -1) { printf("\nE3000: Could not read MAC address\n"); return -100; @@ -82,11 +83,12 @@ int netflash(int argc, char * argv[]) } printf("%02x:%02x:%02x:%02x:%02x:%02x\n", - fn_ip.own_mac[0], fn_ip.own_mac[1], fn_ip.own_mac[2], - fn_ip.own_mac[3], fn_ip.own_mac[4], fn_ip.own_mac[5]); + own_mac[0], own_mac[1], own_mac[2], + own_mac[3], own_mac[4], own_mac[5]); + + // init ethernet layer + set_mac_address(own_mac); - // init network stack - netbase_init(fd_device, fn_ip.own_mac, fn_ip.own_ip); // identify the BOOTP/DHCP server via broadcasts // don't do this, when using DHCP !!! // fn_ip.server_ip = 0xFFFFFFFF; @@ -94,16 +96,11 @@ int netflash(int argc, char * argv[]) /* Get ip address for our mac address */ printf(" Requesting IP address via DHCP: "); - arp_failed = dhcp(fd_device, 0, &fn_ip, 30); + arp_failed = dhcp(0, &fn_ip, 30); if(arp_failed >= 0) { // reinit network stack - netbase_init(fd_device, fn_ip.own_mac, fn_ip.own_ip); - - if (!net_iptomac(fn_ip.server_ip, fn_ip.server_mac)) { - // printf("\nERROR:\t\t\tCan't obtain TFTP server MAC!\n"); - arp_failed = -2; - } + set_ipv4_address(fn_ip.own_ip); } if (arp_failed == -1) { @@ -133,7 +130,7 @@ int netflash(int argc, char * argv[]) strcpy((char *) fn_ip.filename,argv[3]); - rc = tftp (fd_device, &fn_ip, (unsigned char *) buffer, len, 20, &tftp_err, 0); + rc = tftp(&fn_ip, (unsigned char*) buffer, len, 20, &tftp_err, 0, 512, 4); dhcp_send_release(); diff --git a/clients/net-snk/app/netapps/ping.c b/clients/net-snk/app/netapps/ping.c index 9d98b24..5557baf 100644 --- a/clients/net-snk/app/netapps/ping.c +++ b/clients/net-snk/app/netapps/ping.c @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License @@ -10,14 +10,14 @@ * IBM Corporation - initial implementation *****************************************************************************/ -#include <netlib/icmp.h> -#include <netlib/arp.h> -#include <netlib/netlib.h> +#include <netlib/ipv4.h> +#include <netlib/dhcp.h> +#include <netlib/ethernet.h> #include <sys/socket.h> -#include <netlib/netbase.h> #include <string.h> #include <stdio.h> #include <stdlib.h> +#include <time.h> #include <netapps/args.h> struct ping_args { @@ -110,6 +110,7 @@ ping(int argc, char *argv[]) filename_ip_t fn_ip; int fd_device; struct ping_args ping_args; + uint8_t own_mac[6]; memset(&ping_args, 0, sizeof(struct ping_args)); @@ -127,7 +128,7 @@ ping(int argc, char *argv[]) /* Get mac_addr from device */ printf("\n Reading MAC address from device: "); - fd_device = socket(0, 0, 0, (char *) fn_ip.own_mac); + fd_device = socket(0, 0, 0, (char *) own_mac); if (fd_device == -1) { printf("\nE3000: Could not read MAC address\n"); return -100; @@ -137,11 +138,11 @@ ping(int argc, char *argv[]) } printf("%02x:%02x:%02x:%02x:%02x:%02x\n", - fn_ip.own_mac[0], fn_ip.own_mac[1], fn_ip.own_mac[2], - fn_ip.own_mac[3], fn_ip.own_mac[4], fn_ip.own_mac[5]); + own_mac[0], own_mac[1], own_mac[2], + own_mac[3], own_mac[4], own_mac[5]); - // init network stack - netbase_init(fd_device, fn_ip.own_mac, fn_ip.own_ip); + // init ethernet layer + set_mac_address(own_mac); // identify the BOOTP/DHCP server via broadcasts // don't do this, when using DHCP !!! // fn_ip.server_ip = 0xFFFFFFFF; @@ -150,7 +151,7 @@ ping(int argc, char *argv[]) if (!ping_args.client_ip.integer) { /* Get ip address for our mac address */ printf(" Requesting IP address via DHCP: "); - arp_failed = dhcp(fd_device, 0, &fn_ip, 30); + arp_failed = dhcp(0, &fn_ip, 30); if (arp_failed == -1) { printf("\n DHCP: Could not get ip address\n"); @@ -164,7 +165,7 @@ ping(int argc, char *argv[]) } // reinit network stack - netbase_init(fd_device, fn_ip.own_mac, fn_ip.own_ip); + set_ipv4_address(fn_ip.own_ip); printf("%d.%d.%d.%d\n", ((fn_ip.own_ip >> 24) & 0xFF), ((fn_ip.own_ip >> 16) & 0xFF), @@ -176,23 +177,17 @@ ping(int argc, char *argv[]) ((fn_ip.server_ip >> 8) & 0xFF), (fn_ip.server_ip & 0xFF)); - if (ping_args.gateway_ip.integer) { - if (!arp_getmac(ping_args.gateway_ip.integer, fn_ip.server_mac)) { - printf("failed\n"); - return -1; - } - } else { - if (!arp_getmac(fn_ip.server_ip, fn_ip.server_mac)) { - printf("failed\n"); - return -1; + ping_ipv4(fn_ip.server_ip); + + set_timer(TICKS_SEC / 10 * ping_args.timeout); + while(get_timer() > 0) { + receive_ether(); + if(pong_ipv4() == 0) { + printf("success\n"); + return 0; } } - if (!echo_request(fd_device, &fn_ip, ping_args.timeout)) { - printf("success\n"); - return 0; - } else { - printf("failed\n"); - return -1; - } + printf("failed\n"); + return -1; } diff --git a/clients/net-snk/app/netlib/Makefile b/clients/net-snk/app/netlib/Makefile index b88d06c..5b91470 100644 --- a/clients/net-snk/app/netlib/Makefile +++ b/clients/net-snk/app/netlib/Makefile @@ -1,5 +1,5 @@ # ***************************************************************************** -# * Copyright (c) 2004, 2007 IBM Corporation +# * Copyright (c) 2004, 2008 IBM Corporation # * All rights reserved. # * This program and the accompanying materials # * are made available under the terms of the BSD License @@ -18,7 +18,18 @@ include $(TOP)/make.rules CFLAGS += -I../ -OBJS = tftp.o netbase.o arp.o dns.o bootp.o dhcp.o icmp.o +ifeq ($(SNK_USE_MTFTP), 1) +CFLAGS += -DUSE_MTFTP +endif + +OBJS = ethernet.o ipv4.o udp.o tcp.o dns.o bootp.o \ + dhcp.o + +ifeq ($(SNK_USE_MTFTP), 1) +OBJS += mtftp.o +else +OBJS += tftp.o +endif all: netlib.o diff --git a/clients/net-snk/app/netlib/bootp.c b/clients/net-snk/app/netlib/bootp.c index b89f0bf..b1e97ed 100644 --- a/clients/net-snk/app/netlib/bootp.c +++ b/clients/net-snk/app/netlib/bootp.c @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License @@ -10,14 +10,17 @@ * IBM Corporation - initial implementation *****************************************************************************/ -#include <types.h> -#include <stdlib.h> + #include <stdio.h> #include <string.h> #include <sys/socket.h> -#include <netlib/netlib.h> #include <time.h> +#include <ethernet.h> +#include <ipv4.h> +#include <udp.h> +#include <dhcp.h> + #define DEBUG 0 static char * response_buffer; @@ -43,50 +46,35 @@ checksum(unsigned short *packet, int words) static int -send_bootp(int boot_device, filename_ip_t * fn_ip) +send_bootp(filename_ip_t * fn_ip) { +#if DEBUG int i; +#endif unsigned int packetsize = sizeof(struct iphdr) + sizeof(struct ethhdr) + sizeof(struct udphdr) + sizeof(struct btphdr); unsigned char packet[packetsize]; - struct ethhdr *ethh; struct iphdr *iph; struct udphdr *udph; struct btphdr *btph; - ethh = (struct ethhdr *) packet; - iph = (struct iphdr *) ((void *) ethh + sizeof(struct ethhdr)); - udph = (struct udphdr *) ((void *) iph + sizeof(struct iphdr)); - btph = (struct btphdr *) ((void *) udph + sizeof(struct udphdr)); + iph = (struct iphdr *) packet; + udph = (struct udphdr *) (iph + 1); + btph = (struct btphdr *) (udph + 1); memset(packet, 0, packetsize); - memcpy(ethh->src_mac, fn_ip->own_mac, 6); - memcpy(ethh->dest_mac, fn_ip->server_mac, 6); - - ethh->type = htons(ETHERTYPE_IP); - iph->ip_hlv = 0x45; - iph->ip_tos = 0; - iph->ip_len = htons(packetsize - sizeof(struct ethhdr)); - iph->ip_id = htons(54321); - iph->ip_off = 0; - iph->ip_ttl = 255; - iph->ip_p = IPTYPE_UDP; - iph->ip_src = fn_ip->own_ip; - iph->ip_dst = fn_ip->server_ip; - iph->ip_sum = - checksum((unsigned short *) iph, sizeof(struct iphdr) >> 1); - - udph->uh_sport = htons(UDPPORT_BOOTPC); - udph->uh_dport = htons(UDPPORT_BOOTPS); - udph->uh_ulen = htons(sizeof(struct udphdr) + sizeof(struct btphdr)); - udph->uh_sum = 0; + fill_iphdr((uint8_t *) iph, htons(packetsize - sizeof(struct ethhdr)), + IPTYPE_UDP, 0, fn_ip->server_ip); + fill_udphdr((uint8_t *) udph, + htons(sizeof(struct udphdr) + sizeof(struct btphdr)), + htons(UDPPORT_BOOTPC), htons(UDPPORT_BOOTPS)); btph->op = 1; btph->htype = 1; btph->hlen = 6; strcpy((char *) btph->file, "bla"); - memcpy(btph->chaddr, ethh->src_mac, 6); + memcpy(btph->chaddr, get_mac_address(), 6); #if DEBUG printf("Sending packet\n"); @@ -96,7 +84,7 @@ send_bootp(int boot_device, filename_ip_t * fn_ip) printf(".\n"); #endif - i = send(boot_device, packet, packetsize, 0); + send_ipv4(packet, iph->ip_len); #if DEBUG printf("%d bytes transmitted over socket.\n", i); #endif @@ -106,7 +94,7 @@ send_bootp(int boot_device, filename_ip_t * fn_ip) static int -receive_bootp(int boot_device, filename_ip_t * fn_ip) +receive_bootp(filename_ip_t * fn_ip) { int len, old_sum; unsigned int packetsize = 2000; @@ -118,8 +106,8 @@ receive_bootp(int boot_device, filename_ip_t * fn_ip) ethh = (struct ethhdr *) packet; iph = (struct iphdr *) (packet + sizeof(struct ethhdr)); - udph = (struct udphdr *) ((void *) iph + sizeof(struct iphdr)); - btph = (struct btphdr *) ((void *) udph + sizeof(struct udphdr)); + udph = (struct udphdr *) (iph + 1); + btph = (struct btphdr *) (udph + 1); memset(packet, 0, packetsize); @@ -129,7 +117,7 @@ receive_bootp(int boot_device, filename_ip_t * fn_ip) do { /* let's receive a packet */ - len = recv(boot_device, packet, packetsize, 0); + len = recv(0, packet, packetsize, 0); #if DEBUG int j; @@ -163,7 +151,7 @@ receive_bootp(int boot_device, filename_ip_t * fn_ip) if (btph->op != 2) continue; /* Comparing our mac address with the one in the bootp reply */ - if (memcmp(fn_ip->own_mac, btph->chaddr, ETH_ALEN)) + if (memcmp(get_mac_address(), btph->chaddr, ETH_ALEN)) continue; if(response_buffer) @@ -171,15 +159,14 @@ receive_bootp(int boot_device, filename_ip_t * fn_ip) fn_ip->own_ip = btph->yiaddr; fn_ip->server_ip = btph->siaddr; - memcpy(fn_ip->server_mac, ðh->src_mac, 6); strcpy((char *) fn_ip->filename, (char *) btph->file); #if DEBUG printf("\nThese are the details of the bootp reply:\n"); printf("Our IP address: "); - print_ip(&fn_ip->own_ip); + print_ip((char*) &fn_ip->own_ip); printf("Next server IP address: "); - print_ip(&fn_ip->server_ip); + print_ip((char*) &fn_ip->server_ip); printf("Boot file name: %s\n", btph->file); printf("Packet is: %s\n", btph->file); for (j = 0; j < len; j++) { @@ -189,14 +176,15 @@ receive_bootp(int boot_device, filename_ip_t * fn_ip) } printf(".\n"); printf("fn_ip->own_mac: %02x:%02x:%02x:%02x:%02x:%02x\n", - fn_ip->own_mac[0], fn_ip->own_mac[1], fn_ip->own_mac[2], - fn_ip->own_mac[3], fn_ip->own_mac[4], fn_ip->own_mac[5]); + get_mac_address()[0], get_mac_address()[1], + get_mac_address()[2], get_mac_address()[3], + get_mac_address()[4], get_mac_address()[5]); printf("Header ethh->dest_mac: %02x:%02x:%02x:%02x:%02x:%02x\n", - ethh->dest_mac[0], ethh->dest_mac[1], ethh->dest_mac[2], - ethh->dest_mac[3], ethh->dest_mac[4], ethh->dest_mac[5]); + ethh->dest_mac[0], ethh->dest_mac[1], ethh->dest_mac[2], + ethh->dest_mac[3], ethh->dest_mac[4], ethh->dest_mac[5]); printf("Header ethh->src_mac: %02x:%02x:%02x:%02x:%02x:%02x\n", - ethh->src_mac[0], ethh->src_mac[1], ethh->src_mac[2], - ethh->src_mac[3], ethh->src_mac[4], ethh->src_mac[5]); + ethh->src_mac[0], ethh->src_mac[1], ethh->src_mac[2], + ethh->src_mac[3], ethh->src_mac[4], ethh->src_mac[5]); printf("Header ethh->typ: %x\n",ethh->type); printf("Header iph->ip_hlv: %x\n",iph->ip_hlv); printf("Header iph->ip_len: %x\n",iph->ip_len); @@ -219,10 +207,9 @@ receive_bootp(int boot_device, filename_ip_t * fn_ip) printf("Header btph->siaddr: %x\n",btph->siaddr); printf("Header btph->giaddr: %x\n",btph->giaddr); - printf("Header btph->chaddr: %02x:%02x:%02x:%02x:%02x:%02x:\n", - btph->chaddr[0], btph->chaddr[1], btph->chaddr[2], - btph->chaddr[3], btph->chaddr[4], btph->chaddr[5]); - + printf("Header btph->chaddr: %02x:%02x:%02x:%02x:%02x:%02x:\n", + btph->chaddr[0], btph->chaddr[1], btph->chaddr[2], + btph->chaddr[3], btph->chaddr[4], btph->chaddr[5]); #endif return 0; @@ -234,7 +221,7 @@ receive_bootp(int boot_device, filename_ip_t * fn_ip) int -bootp(int boot_device, char *ret_buffer, filename_ip_t * fn_ip, unsigned int retries) +bootp(char *ret_buffer, filename_ip_t * fn_ip, unsigned int retries) { int i = (int) retries+1; fn_ip->own_ip = 0; @@ -250,12 +237,12 @@ bootp(int boot_device, char *ret_buffer, filename_ip_t * fn_ip, unsigned int ret retries+1); return -1; } - send_bootp(boot_device, fn_ip); + send_bootp(fn_ip); /* if the timer in receive_bootp expired it will return * -1 and we will just send another bootp request just * in case the previous one was lost. And because we don't * trust the network cable we keep on doing this 30 times */ - } while (receive_bootp(boot_device, fn_ip) != 0); + } while (receive_bootp(fn_ip) != 0); printf("\b\b\b"); return 0; } diff --git a/clients/net-snk/app/netlib/dhcp.c b/clients/net-snk/app/netlib/dhcp.c index 8f27cf6..8f81bf3 100644 --- a/clients/net-snk/app/netlib/dhcp.c +++ b/clients/net-snk/app/netlib/dhcp.c @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License @@ -43,17 +43,18 @@ /*>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<<<*/ -#include <types.h> -#include <ctype.h> -#include <stdlib.h> +#include <dhcp.h> +#include <ethernet.h> +#include <ipv4.h> +#include <udp.h> +#include <dns.h> + #include <stdio.h> #include <string.h> -#include <sys/socket.h> -#include <netlib/netlib.h> -#include <netlib/netbase.h> -#include <netlib/arp.h> -#include <netlib/dns.h> #include <time.h> +#include <sys/socket.h> +#include <ctype.h> +#include <stdlib.h> /* DHCP Message Types */ #define DHCPDISCOVER 1 @@ -162,10 +163,7 @@ strtoip(int8_t * str, uint32_t * ip); /*>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<<*/ static uint8_t ether_packet[ETH_MTU_SIZE]; -static int32_t dhcp_device_socket = 0; -static uint8_t dhcp_own_mac[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static uint32_t dhcp_own_ip = 0; -static uint8_t dhcp_server_mac[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static uint32_t dhcp_server_ip = 0; static uint32_t dhcp_siaddr_ip = 0; static int8_t dhcp_filename[256]; @@ -187,17 +185,14 @@ static char * response_buffer; * NON ZERO - error condition occurs. */ int32_t -dhcp(int32_t boot_device, char *ret_buffer, filename_ip_t * fn_ip, unsigned int retries) { +dhcp(char *ret_buffer, filename_ip_t * fn_ip, unsigned int retries) { int i = (int) retries+1; - uint8_t dhcp_tftp_mac[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint32_t dhcp_tftp_ip = 0; strcpy((char *) dhcp_filename, ""); strcpy((char *) dhcp_tftp_name, ""); response_buffer = ret_buffer; - dhcp_device_socket = boot_device; - memcpy(dhcp_own_mac, fn_ip -> own_mac, 6); printf(" "); @@ -224,15 +219,6 @@ dhcp(int32_t boot_device, char *ret_buffer, filename_ip_t * fn_ip, unsigned int strcpy((char *) dhcp_filename, (char *) fn_ip->filename); } - // Information from DHCP server were obtained - PRINT_MSGIP("\n\nClient IP:\t\t", dhcp_own_ip); - PRINT_MSGMAC("Client MAC:\t\t", dhcp_own_mac); - PRINT_MSGIP("\nDHCP Server IP:\t\t", dhcp_server_ip); - - // Obtain DHCP-server MAC to be able to send dhcp_release - net_iptomac(dhcp_server_ip, dhcp_server_mac); - PRINT_MSGMAC("DHCP Server MAC:\t", dhcp_server_mac); - // TFTP SERVER if (!strlen((char *) dhcp_tftp_name)) { if (!dhcp_siaddr_ip) { @@ -245,7 +231,6 @@ dhcp(int32_t boot_device, char *ret_buffer, filename_ip_t * fn_ip, unsigned int } else { // TFTP server defined by its name - NET_DEBUG_PRINTF("\nTFTP server name:\t%s\n", dhcp_tftp_name); if (!strtoip(dhcp_tftp_name, &(dhcp_tftp_ip))) { if (!dns_get_ip(dhcp_tftp_name, &(dhcp_tftp_ip))) { // DNS error - can't obtain TFTP-server name @@ -261,26 +246,9 @@ dhcp(int32_t boot_device, char *ret_buffer, filename_ip_t * fn_ip, unsigned int } } - PRINT_MSGIP("\nTFTP server IP:\t\t", dhcp_tftp_ip); - if (!net_iptomac(dhcp_tftp_ip, dhcp_tftp_mac)) { - // printf("\nERROR:\t\t\tCan't obtain TFTP server MAC!\n"); - return -2; - } - - PRINT_MSGMAC("TFTP server MAC:\t", dhcp_tftp_mac); - -// // Bootfile name -// if (!strlen(dhcp_filename)) { -// // ERROR: Bootfile name is not presented -// return -5; -// } - - NET_DEBUG_PRINTF("\nBootfile name:\t\t%s\n\n", dhcp_filename); - // Store configuration info into filename_ip strucutre fn_ip -> own_ip = dhcp_own_ip; fn_ip -> server_ip = dhcp_tftp_ip; - memcpy(fn_ip -> server_mac, dhcp_tftp_mac, 6); strcpy((char *) fn_ip -> filename, (char *) dhcp_filename); return 0; @@ -645,21 +613,20 @@ dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len, */ static void dhcp_send_discover(void) { - uint32_t packetsize = sizeof(struct ethhdr) + sizeof(struct iphdr) + + uint32_t packetsize = sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct btphdr); struct btphdr *btph; - uint8_t dest_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; dhcp_options_t opt; memset(ether_packet, 0, packetsize); - btph = (struct btphdr *) (ðer_packet[sizeof(struct ethhdr) + + btph = (struct btphdr *) (ðer_packet[ sizeof(struct iphdr) + sizeof(struct udphdr)]); btph -> op = 1; btph -> htype = 1; btph -> hlen = 6; - memcpy(btph -> chaddr, dhcp_own_mac, 6); + memcpy(btph -> chaddr, get_mac_address(), 6); memset(&opt, 0, sizeof(dhcp_options_t)); @@ -673,17 +640,14 @@ dhcp_send_discover(void) { dhcp_encode_options(btph -> vend, &opt); - fill_udphdr(ðer_packet[sizeof(struct ethhdr) + sizeof(struct iphdr)], + fill_udphdr(ðer_packet[sizeof(struct iphdr)], sizeof(struct btphdr) + sizeof(struct udphdr), UDPPORT_BOOTPC, UDPPORT_BOOTPS); - fill_iphdr(ðer_packet[sizeof(struct ethhdr)], sizeof(struct btphdr) + + fill_iphdr(ether_packet, sizeof(struct btphdr) + sizeof(struct udphdr) + sizeof(struct iphdr), IPTYPE_UDP, dhcp_own_ip, 0xFFFFFFFF); - fill_ethhdr(ðer_packet[0], ETHERTYPE_IP, dhcp_own_mac, dest_mac); - - PRINT_SENDING(ether_packet, packetsize); - send(dhcp_device_socket, ether_packet, packetsize, 0); + send_ipv4(ether_packet, packetsize); } /** @@ -691,21 +655,20 @@ dhcp_send_discover(void) { */ static void dhcp_send_request(void) { - uint32_t packetsize = sizeof(struct ethhdr) + sizeof(struct iphdr) + + uint32_t packetsize = sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct btphdr); struct btphdr *btph; - uint8_t dest_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; dhcp_options_t opt; memset(ether_packet, 0, packetsize); - btph = (struct btphdr *) (ðer_packet[sizeof(struct ethhdr) + + btph = (struct btphdr *) (ðer_packet[ sizeof(struct iphdr) + sizeof(struct udphdr)]); btph -> op = 1; btph -> htype = 1; btph -> hlen = 6; - memcpy(btph -> chaddr, dhcp_own_mac, 6); + memcpy(btph -> chaddr, get_mac_address(), 6); memset(&opt, 0, sizeof(dhcp_options_t)); @@ -723,17 +686,14 @@ dhcp_send_request(void) { dhcp_encode_options(btph -> vend, &opt); - fill_udphdr(ðer_packet[sizeof(struct ethhdr) + sizeof(struct iphdr)], + fill_udphdr(ðer_packet[sizeof(struct iphdr)], sizeof(struct btphdr) + sizeof(struct udphdr), UDPPORT_BOOTPC, UDPPORT_BOOTPS); - fill_iphdr(ðer_packet[sizeof(struct ethhdr)], sizeof(struct btphdr) + + fill_iphdr(ether_packet, sizeof(struct btphdr) + sizeof(struct udphdr) + sizeof(struct iphdr), IPTYPE_UDP, 0, 0xFFFFFFFF); - fill_ethhdr(ðer_packet[0], ETHERTYPE_IP, dhcp_own_mac, dest_mac); - PRINT_SENDING(ether_packet, packetsize); - - send(dhcp_device_socket, ether_packet, packetsize, 0); + send_ipv4(ether_packet, packetsize); } @@ -741,12 +701,12 @@ dhcp_send_request(void) { * DHCP: Sends DHCP-Release message. Releases occupied IP. */ void dhcp_send_release(void) { - uint32_t packetsize = sizeof(struct ethhdr) + sizeof(struct iphdr) + + uint32_t packetsize = sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct btphdr); struct btphdr *btph; dhcp_options_t opt; - btph = (struct btphdr *) (ðer_packet[sizeof(struct ethhdr) + + btph = (struct btphdr *) (ðer_packet[ sizeof(struct iphdr) + sizeof(struct udphdr)]); memset(ether_packet, 0, packetsize); @@ -755,7 +715,7 @@ void dhcp_send_release(void) { btph -> htype = 1; btph -> hlen = 6; strcpy((char *) btph -> file, ""); - memcpy(btph -> chaddr, dhcp_own_mac, 6); + memcpy(btph -> chaddr, get_mac_address(), 6); btph -> ciaddr = htonl(dhcp_own_ip); memset(&opt, 0, sizeof(dhcp_options_t)); @@ -766,17 +726,14 @@ void dhcp_send_release(void) { dhcp_encode_options(btph -> vend, &opt); - fill_udphdr(ðer_packet[sizeof(struct ethhdr) + sizeof(struct iphdr)], + fill_udphdr(ðer_packet[sizeof(struct iphdr)], sizeof(struct btphdr) + sizeof(struct udphdr), UDPPORT_BOOTPC, UDPPORT_BOOTPS); - fill_iphdr(ðer_packet[sizeof(struct ethhdr)], sizeof(struct btphdr) + + fill_iphdr(ether_packet, sizeof(struct btphdr) + sizeof(struct udphdr) + sizeof(struct iphdr), IPTYPE_UDP, dhcp_own_ip, dhcp_server_ip); - fill_ethhdr(ðer_packet[0], ETHERTYPE_IP, dhcp_own_mac, dhcp_server_mac); - - PRINT_SENDING(ether_packet, packetsize); - send(dhcp_device_socket, ether_packet, packetsize, 0); + send_ipv4(ether_packet, packetsize); } /** @@ -813,8 +770,6 @@ handle_dhcp(uint8_t * packet, int32_t packetsize) { if (memcmp(btph -> vend, dhcp_magic, 4)) { // It is BootP - RFC 951 - NET_DEBUG_PRINTF("WARNING:\t\tBooting via BootP 951\n"); - dhcp_own_ip = htonl(btph -> yiaddr); dhcp_siaddr_ip = htonl(btph -> siaddr); dhcp_server_ip = htonl(iph -> ip_src); @@ -887,8 +842,6 @@ handle_dhcp(uint8_t * packet, int32_t packetsize) { if (!opt.msg_type) { // It is BootP with Extensions - RFC 1497 - NET_DEBUG_PRINTF("WARNING:\t\tBooting via BootP 1497\n"); - // retrieve conf. settings from BootP - reply dhcp_own_ip = htonl(btph -> yiaddr); dhcp_siaddr_ip = htonl(btph -> siaddr); @@ -975,38 +928,20 @@ handle_dhcp(uint8_t * packet, int32_t packetsize) { // initialize network entity with real own_ip // to be able to answer for foreign requests - netbase_init(dhcp_device_socket, dhcp_own_mac, dhcp_own_ip); + set_ipv4_address(dhcp_own_ip); /* Subnet mask */ if (opt.flag[DHCP_MASK]) { /* Router */ if (opt.flag[DHCP_ROUTER]) { - if(net_setrouter(opt.router_IP, opt.subnet_mask) - == 0) { - // don't abort if ARP faild - // dhcp_state = DHCP_STATE_FAULT; - // return -1; - - // pretend like no router was specified - opt.flag[DHCP_ROUTER] = 0; - net_setrouter(0, opt.subnet_mask); - } + set_ipv4_router(opt.router_IP); + set_ipv4_netmask(opt.subnet_mask); } - - if (! opt.flag[DHCP_ROUTER]) { - NET_DEBUG_PRINTF("WARNING:\t\tRouter IP is not presented!\n"); - } - } - else { - NET_DEBUG_PRINTF("\nWARNING:\t\tSubnet mask is not presented!\n"); } /* DNS-server */ if (opt.flag[DHCP_DNS]) { - dns_init(dhcp_device_socket, dhcp_own_mac, dhcp_own_ip, opt.dns_IP); - } - else { - NET_DEBUG_PRINTF("WARNING:\t\tDomain Name Server IP is not presented!\n"); + dns_init(opt.dns_IP); } } diff --git a/clients/net-snk/app/netlib/dhcp.h b/clients/net-snk/app/netlib/dhcp.h index 5d0d636..853200c 100644 --- a/clients/net-snk/app/netlib/dhcp.h +++ b/clients/net-snk/app/netlib/dhcp.h @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License @@ -10,5 +10,44 @@ * IBM Corporation - initial implementation *****************************************************************************/ +#ifndef _DHCP_H_ +#define _DHCP_H_ + +#include <types.h> + +#ifdef USE_MTFTP +#include <netlib/mtftp.h> +#else +#include <netlib/tftp.h> +#endif + +/** \struct btphdr + * A header for BootP/DHCP-messages. + * For more information see RFC 951 / RFC 2131. + */ +struct btphdr { + uint8_t op; /**< Identifies is it request (1) or reply (2) */ + uint8_t htype; /**< HW address type (ethernet usually) */ + uint8_t hlen; /**< HW address length */ + uint8_t hops; /**< This info used by relay agents (not used) */ + uint32_t xid; /**< This ID is used to match queries and replies */ + uint16_t secs; /**< Unused */ + uint16_t unused; /**< Unused */ + uint32_t ciaddr; /**< Client IP address (if client knows it) */ + uint32_t yiaddr; /**< "Your" (client) IP address */ + uint32_t siaddr; /**< Next server IP address (TFTP server IP) */ + uint32_t giaddr; /**< Gateway IP address (used by relay agents) */ + uint8_t chaddr[16]; /**< Client HW address */ + uint8_t sname[64]; /**< Server host name (TFTP server name) */ + uint8_t file[128]; /**< Boot file name */ + uint8_t vend[64]; /**< Optional parameters field (DHCP-options) */ +}; + +int bootp(char *ret_buffer, filename_ip_t *, unsigned int); +int dhcp(char *ret_buffer, filename_ip_t *, unsigned int); +void dhcp_send_release(void); + /* Handles DHCP-packets, which are detected by receive_ether. */ extern int8_t handle_dhcp(uint8_t * packet, int32_t packetsize); + +#endif diff --git a/clients/net-snk/app/netlib/dns.c b/clients/net-snk/app/netlib/dns.c index d0eb7b0..5a931d5 100644 --- a/clients/net-snk/app/netlib/dns.c +++ b/clients/net-snk/app/netlib/dns.c @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License @@ -12,17 +12,15 @@ /*>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<<<*/ -#include <types.h> -#include <ctype.h> -#include <stdlib.h> +#include <dns.h> #include <stdio.h> #include <string.h> -#include <sys/socket.h> -#include <netlib/netlib.h> -#include <netlib/netbase.h> -#include <netlib/arp.h> -#include <netlib/dns.h> #include <time.h> +#include <sys/socket.h> + +#include <ethernet.h> +#include <ipv4.h> +#include <udp.h> #define DNS_FLAG_MSGTYPE 0xF800 /**< Message type mask (opcode) */ #define DNS_FLAG_SQUERY 0x0000 /**< Standard query type */ @@ -83,10 +81,6 @@ hosttodomain(char * host_name, char * domain_name); /*>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<<<*/ static uint8_t ether_packet[ETH_MTU_SIZE]; -static int32_t dns_device_socket = 0; -static uint8_t dns_own_mac[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -static int32_t dns_own_ip = 0; -static uint8_t dns_server_mac[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static int32_t dns_server_ip = 0; static int32_t dns_result_ip = 0; static int8_t dns_error = 0; /**< Stores error code or 0 */ @@ -100,32 +94,14 @@ static int8_t dns_domain_cname[0x100]; /**< Canonical domain name */ * To perfrom DNS-queries use the function dns_get_ip. * * @param device_socket a socket number used to send and recieve packets - * @param own_mac client hardware-address (MAC) - * @param own_ip client IPv4 address (e.g. 127.0.0.1) * @param server_ip DNS-server IPv4 address (e.g. 127.0.0.1) * @return TRUE in case of successful initialization; * FALSE in case of fault (e.g. can't obtain MAC). * @see dns_get_ip */ int8_t -dns_init(int32_t device_socket, uint8_t own_mac[], uint32_t own_ip, - uint32_t server_ip) { - dns_device_socket = device_socket; - memcpy(dns_own_mac, own_mac, 6); - dns_own_ip = own_ip; - dns_server_ip = server_ip; - - PRINT_MSGIP("\nDomain Name Server IP:\t", dns_server_ip); - if (net_iptomac(dns_server_ip, dns_server_mac)) { - PRINT_MSGMAC("DNS Server MAC:\t\t", dns_server_mac); - return 1; - } - - dns_server_ip = 0; - dns_own_ip = 0; - memset(dns_server_mac, 0, 6); - - NET_DEBUG_PRINTF("\nWARNING:\t\tCan't obtain DNS server MAC!\n"); +dns_init(uint32_t _dns_server_ip) { + dns_server_ip = _dns_server_ip; return 0; } @@ -174,15 +150,6 @@ dns_get_ip(int8_t * url, uint32_t * domain_ip) { "(DNS server is not presented)!\n"); return 0; } - if (dns_server_mac[0] == 0 && dns_server_mac[1] == 0 && - dns_server_mac[2] == 0 && dns_server_mac[3] == 0 && - dns_server_mac[4] == 0 && dns_server_mac[5] == 0) { - if(!net_iptomac(dns_server_ip, dns_server_mac)) { - printf("\nERROR:\t\t\tCan't resolve domain name " - "(DNS server is not presented)!\n"); - return 0; - } - } // Use DNS-server to obtain IP dns_result_ip = 0; @@ -245,7 +212,6 @@ handle_dns(uint8_t * packet, int32_t packetsize) { // Is error condition occurs? (check error field in incoming packet) if ((dnsh -> flags & htons(DNS_FLAG_RCODE)) != DNS_RCODE_NERROR) { - NET_DEBUG_PRINTF("\nERROR:\t\t\tDNS error - can't obtain IP!\n"); dns_error = 1; return 0; } @@ -317,27 +283,24 @@ static void dns_send_query(int8_t * domain_name) { int qry_len = strlen((char *) domain_name) + 5; - uint32_t packetsize = sizeof(struct iphdr) + sizeof(struct ethhdr) + + uint32_t packetsize = sizeof(struct iphdr) + sizeof(struct udphdr) + sizeof(struct dnshdr) + qry_len; memset(ether_packet, 0, packetsize); - fill_dnshdr(ðer_packet[sizeof(struct ethhdr) + + fill_dnshdr(ðer_packet[ sizeof(struct iphdr) + sizeof(struct udphdr)], domain_name); - fill_udphdr(ðer_packet[sizeof(struct ethhdr) + + fill_udphdr(ðer_packet[ sizeof(struct iphdr)], sizeof(struct dnshdr) + sizeof(struct udphdr) + qry_len, UDPPORT_DNSC, UDPPORT_DNSS); - fill_iphdr(ether_packet + sizeof(struct ethhdr), + fill_iphdr(ether_packet, sizeof(struct dnshdr) + sizeof(struct udphdr) + sizeof(struct iphdr) + qry_len, - IPTYPE_UDP, dns_own_ip, dns_server_ip); - fill_ethhdr(ether_packet, ETHERTYPE_IP, dns_own_mac, dns_server_mac); - - PRINT_SENDING(ether_packet, packetsize); + IPTYPE_UDP, 0, dns_server_ip); - send(dns_device_socket, ether_packet, packetsize, 0); + send_ipv4(ether_packet, packetsize); } /** diff --git a/clients/net-snk/app/netlib/dns.h b/clients/net-snk/app/netlib/dns.h index 5bf0f84..ef9f48e 100644 --- a/clients/net-snk/app/netlib/dns.h +++ b/clients/net-snk/app/netlib/dns.h @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License @@ -11,11 +11,18 @@ *****************************************************************************/ +#ifndef _DNS_H_ +#define _DNS_H_ + +#include <types.h> + /* Initialize the environment for DNS client. */ -extern int8_t dns_init(int32_t device_socket, uint8_t own_mac[], uint32_t own_ip, uint32_t server_ip); +extern int8_t dns_init(uint32_t dns_server_ip); /* For given URL retrieves IPv4 from DNS-server. */ extern int8_t dns_get_ip(int8_t * domain_name, uint32_t * domain_ip); /* Handles DNS-packets, which are detected by receive_ether. */ extern int32_t handle_dns(uint8_t * packet, int32_t packetsize); + +#endif diff --git a/clients/net-snk/app/netlib/ethernet.c b/clients/net-snk/app/netlib/ethernet.c new file mode 100644 index 0000000..cc77457 --- /dev/null +++ b/clients/net-snk/app/netlib/ethernet.c @@ -0,0 +1,186 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ALGORITHMS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ + +/** \file netbase.c <pre> + * *********************** Receive-handle diagram ************************* + * + * Note: Every layer calls out required upper layer + * + * lower + * | MAC/LLC Receive packet (receive_ether) + * | | + * | NETWORK +-----------+---------+ + * | | | + * | IPv4 (handle_ipv4) IPv6 (handle_ipv4) + * | ARP (handle_arp) ICMP & NDP + * | ICMP | + * | | | + * | +---------+---------+ + * | | + * | TRANSPORT +---------+---------+ + * | | | + * | TCP (handle_tcp) UDP (handle_udp) + * | | + * | APPLICATION +----------------+-----------+ + * V | | + * upper DNS (handle_dns) BootP / DHCP (handle_bootp_client) + * + * ************************************************************************ + * </pre> */ + + +/*>>>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<*/ + +#include <ethernet.h> +#include <string.h> +#include <sys/socket.h> +#include <ipv4.h> +//#include <ipv6.h> + + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/ + +static uint8_t ether_packet[ETH_MTU_SIZE]; +static uint8_t own_mac[6] = {0, 0, 0, 0, 0, 0}; +static uint8_t multicast_mac[] = {0x01, 0x00, 0x5E}; +static const uint8_t broadcast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<*/ + +/** + * Ethernet: Set the own MAC address to initializes ethernet layer. + * + * @param own_mac own hardware-address (MAC) + */ +void +set_mac_address(const uint8_t * _own_mac) { + if (_own_mac) + memcpy(own_mac, _own_mac, 6); + else + memset(own_mac, 0, 6); +} + +/** + * Ethernet: Set the own MAC address to initializes ethernet layer. + * + * @return own hardware-address (MAC) + */ +const uint8_t * +get_mac_address(void) { + return own_mac; +} + +/** + * Ethernet: Check if given multicast address is a multicast MAC address + * starting with 0x3333 + * + * @return true or false + */ +static uint8_t +is_multicast_mac(uint8_t * mac) { + + uint16_t mc = 0x3333; + if (memcmp(mac, &mc, 2) == 0) + return 1; + + return 0; +} + + +/** + * Ethernet: Receives an ethernet-packet and handles it according to + * Receive-handle diagram. + * + * @return ZERO - packet was handled or no packets received; + * NON ZERO - error condition occurs. + */ +int32_t +receive_ether(void) { + int32_t bytes_received; + struct ethhdr * ethh; + + memset(ether_packet, 0, ETH_MTU_SIZE); + bytes_received = recv(0, ether_packet, ETH_MTU_SIZE, 0); + + if (!bytes_received) // No messages + return 0; + + if (bytes_received < sizeof(struct ethhdr)) + return -1; // packet is too small + + ethh = (struct ethhdr *) ether_packet; + + if(memcmp(ethh->dest_mac, broadcast_mac, 6) != 0 + && memcmp(ethh->dest_mac, multicast_mac, 3) != 0 + && memcmp(ethh->dest_mac, own_mac, 6 ) != 0 + && !is_multicast_mac(ethh->dest_mac)) + return -1; // packet is too small + + switch (htons(ethh -> type)) { + case ETHERTYPE_IP: + return handle_ipv4((uint8_t*) (ethh + 1), + bytes_received - sizeof(struct ethhdr)); +/* + case ETHERTYPE_IPv6: + return handle_ipv6(ether_packet + sizeof(struct ethhdr), + bytes_received - sizeof(struct ethhdr)); +*/ + case ETHERTYPE_ARP: + return handle_arp((uint8_t*) (ethh + 1), + bytes_received - sizeof(struct ethhdr)); + default: + break; + } + return -1; // unknown protocol +} + +/** + * Ethernet: Sends an ethernet frame via the initialized file descriptor. + * + * @return number of transmitted bytes + */ +int +send_ether(void* buffer, int len) +{ + return send(0, buffer, len, 0); +} + +/** + * Ethernet: Creates Ethernet-packet. Places Ethernet-header in a packet and + * fills it with corresponding information. + * <p> + * Use this function with similar functions for other network layers + * (fill_arphdr, fill_iphdr, fill_udphdr, fill_dnshdr, fill_btphdr). + * + * @param packet Points to the place where eth-header must be placed. + * @param eth_type Type of the next level protocol (e.g. IP or ARP). + * @param src_mac Sender MAC address + * @param dest_mac Receiver MAC address + * @see ethhdr + * @see fill_arphdr + * @see fill_iphdr + * @see fill_udphdr + * @see fill_dnshdr + * @see fill_btphdr + */ +void +fill_ethhdr(uint8_t * packet, uint16_t eth_type, + const uint8_t * src_mac, const uint8_t * dest_mac) { + struct ethhdr * ethh = (struct ethhdr *) packet; + + ethh -> type = htons(eth_type); + memcpy(ethh -> src_mac, src_mac, 6); + memcpy(ethh -> dest_mac, dest_mac, 6); +} diff --git a/clients/net-snk/app/netlib/ethernet.h b/clients/net-snk/app/netlib/ethernet.h new file mode 100644 index 0000000..e305a66 --- /dev/null +++ b/clients/net-snk/app/netlib/ethernet.h @@ -0,0 +1,47 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _ETHERNET_H +#define _ETHERNET_H + +#include <types.h> + +#define ETH_MTU_SIZE 1518 /**< Maximum Transfer Unit */ +#define ETH_ALEN 6 /**< HW address length */ +#define ETHERTYPE_IP 0x0800 +#define ETHERTYPE_IPv6 0x86DD +#define ETHERTYPE_ARP 0x0806 + +/** \struct ethhdr + * A header for Ethernet-packets. + */ +struct ethhdr { + uint8_t dest_mac[ETH_ALEN]; /**< Destination HW address */ + uint8_t src_mac[ETH_ALEN]; /**< Source HW address */ + uint16_t type; /**< Next level protocol type */ +}; + +/* Initializes ethernet layer */ +extern void set_mac_address(const uint8_t * own_mac); +extern const uint8_t * get_mac_address(void); + +/* Receives and handles packets, according to Receive-handle diagram */ +extern int32_t receive_ether(void); + +/* Sends an ethernet frame. */ +extern int send_ether(void* buffer, int len); + +/* fills ethernet header */ +extern void fill_ethhdr(uint8_t * packet, uint16_t eth_type, + const uint8_t * src_mac, const uint8_t * dest_mac); + +#endif diff --git a/clients/net-snk/app/netlib/ipv4.c b/clients/net-snk/app/netlib/ipv4.c new file mode 100644 index 0000000..df18970 --- /dev/null +++ b/clients/net-snk/app/netlib/ipv4.c @@ -0,0 +1,871 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +/*>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<<<*/ + +#include <ipv4.h> +#include <udp.h> +#include <tcp.h> +#include <ethernet.h> +#include <sys/socket.h> +#include <string.h> + +/* ARP Message types */ +#define ARP_REQUEST 1 +#define ARP_REPLY 2 + +/* ARP talbe size (+1) */ +#define ARP_ENTRIES 10 + +/* ICMP Message types */ +#define ICMP_ECHO_REPLY 0 +#define ICMP_DST_UNREACHABLE 3 +#define ICMP_SRC_QUENCH 4 +#define ICMP_REDIRECT 5 +#define ICMP_ECHO_REQUEST 8 +#define ICMP_TIME_EXCEEDED 11 +#define ICMP_PARAMETER_PROBLEM 12 +#define ICMP_TIMESTAMP_REQUEST 13 +#define ICMP_TIMESTAMP_REPLY 14 +#define ICMP_INFORMATION_REQUEST 15 +#define ICMP_INFORMATION_REPLY 16 + +/** \struct arp_entry + * A entry that describes a mapping between IPv4- and MAC-address. + */ +typedef struct arp_entry arp_entry_t; +struct arp_entry { + uint32_t ipv4_addr; + uint8_t mac_addr[6]; + uint8_t eth_frame[ETH_MTU_SIZE]; + int eth_len; +}; + +/** \struct icmphdr + * ICMP packet + */ +struct icmphdr { + unsigned char type; + unsigned char code; + unsigned short int checksum; + union { + /* for type 3 "Destination Unreachable" */ + unsigned int unused; + /* for type 0 and 8 */ + struct echo { + unsigned short int id; + unsigned short int seq; + } echo; + } options; + union { + /* payload for destination unreachable */ + struct dun { + unsigned char iphdr[20]; + unsigned char data[64]; + } dun; + /* payload for echo or echo reply */ + /* maximum size supported is 84 */ + unsigned char data[84]; + } payload; +}; + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PROTOTYPES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/ + +static unsigned short +checksum(unsigned short *packet, int words); + +static void +arp_send_request(uint32_t dest_ip); + +static void +arp_send_reply(uint32_t src_ip, uint8_t * src_mac); + +static void +fill_arphdr(uint8_t * packet, uint8_t opcode, + const uint8_t * src_mac, uint32_t src_ip, + const uint8_t * dest_mac, uint32_t dest_ip); + +static arp_entry_t* +lookup_mac_addr(uint32_t ipv4_addr); + +static void +fill_udp_checksum(struct iphdr *ipv4_hdr); + +static int8_t +handle_icmp(struct iphdr * iph, uint8_t * packet, int32_t packetsize); + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/ + +/* Routing parameters */ +static uint32_t own_ip = 0; +static uint32_t multicast_ip = 0; +static uint32_t router_ip = 0; +static uint32_t subnet_mask = 0; + +/* helper variables */ +static uint32_t ping_dst_ip; +static const uint8_t null_mac_addr[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +static const uint8_t broadcast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; +static uint8_t multicast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + +/* There are only (ARP_ENTRIES-1) effective entries because + * the entry that is pointed by arp_producer is never used. + */ +static unsigned int arp_consumer = 0; +static unsigned int arp_producer = 0; +static arp_entry_t arp_table[ARP_ENTRIES]; + +/* Function pointer send_ip. Points either to send_ipv4() or send_ipv6() */ +int (*send_ip) (void *, int); + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<*/ + +/** + * IPv4: Initialize the environment for the IPv4 layer. + */ +static void +ipv4_init(void) +{ + int i; + + ping_dst_ip = 0; + + // clear ARP table + arp_consumer = 0; + arp_producer = 0; + for(i=0; i<ARP_ENTRIES; ++i) { + arp_table[i].ipv4_addr = 0; + memset(arp_table[i].mac_addr, 0, 6); + arp_table[i].eth_len = 0; + } + + /* Set IP send function to send_ipv4() */ + send_ip = &send_ipv4; +} + +/** + * IPv4: Set the own IPv4 address. + * + * @param _own_ip client IPv4 address (e.g. 127.0.0.1) + */ +void +set_ipv4_address(uint32_t _own_ip) +{ + own_ip = _own_ip; + ipv4_init(); +} + +/** + * IPv4: Get the own IPv4 address. + * + * @return client IPv4 address (e.g. 127.0.0.1) + */ +uint32_t +get_ipv4_address(void) +{ + return own_ip; +} + +/** + * IPv4: Set the IPv4 multicast address. + * + * @param _own_ip multicast IPv4 address (224.0.0.0 - 239.255.255.255) + */ +void +set_ipv4_multicast(uint32_t _multicast_ip) +{ + // is this IP Multicast out of range (224.0.0.0 - 239.255.255.255) + if((htonl(_multicast_ip) < 0xE0000000) + || (htonl(_multicast_ip) > 0xEFFFFFFF)) { + multicast_ip = 0; + memset(multicast_mac, 0xFF, 6); + return; + } + + multicast_ip = _multicast_ip; + multicast_mac[0] = 0x01; + multicast_mac[1] = 0x00; + multicast_mac[2] = 0x5E; + multicast_mac[3] = (uint8_t) 0x7F & (multicast_ip >> 16); + multicast_mac[4] = (uint8_t) 0xFF & (multicast_ip >> 8); + multicast_mac[5] = (uint8_t) 0xFF & (multicast_ip >> 0); +} + +/** + * IPv4: Get the IPv4 multicast address. + * + * @return multicast IPv4 address (224.0.0.0 - 239.255.255.255 or 0 if not set) + */ +uint32_t +get_ipv4_multicast(void) +{ + return multicast_ip; +} + +/** + * IPv4: Set the routers IPv4 address. + * + * @param _router_ip router IPv4 address + */ +void +set_ipv4_router(uint32_t _router_ip) +{ + router_ip = _router_ip; + ipv4_init(); +} + +/** + * IPv4: Get the routers IPv4 address. + * + * @return router IPv4 address + */ +uint32_t +get_ipv4_router(void) +{ + return router_ip; +} + +/** + * IPv4: Set the subnet mask. + * + * @param _subnet_mask netmask of the own IPv4 address + */ +void +set_ipv4_netmask(uint32_t _subnet_mask) +{ + subnet_mask = _subnet_mask; + ipv4_init(); +} + +/** + * IPv4: Get the subnet mask. + * + * @return netmask of the own IPv4 address + */ +uint32_t +get_ipv4_netmask(void) +{ + return subnet_mask; +} + +/** + * IPv4: Creates IP-packet. Places IP-header in a packet and fills it + * with corresponding information. + * <p> + * Use this function with similar functions for other network layers + * (fill_ethhdr, fill_udphdr, fill_dnshdr, fill_btphdr). + * + * @param packet Points to the place where IP-header must be placed. + * @param packetsize Size of the packet in bytes incl. this hdr and data. + * @param ip_proto Type of the next level protocol (e.g. UDP). + * @param ip_src Sender IP address + * @param ip_dst Receiver IP address + * @see iphdr + * @see fill_ethhdr + * @see fill_udphdr + * @see fill_dnshdr + * @see fill_btphdr + */ +void +fill_iphdr(uint8_t * packet, uint16_t packetsize, + uint8_t ip_proto, uint32_t ip_src, uint32_t ip_dst) { + struct iphdr * iph = (struct iphdr *) packet; + + iph -> ip_hlv = 0x45; + iph -> ip_tos = 0x10; + iph -> ip_len = htons(packetsize); + iph -> ip_id = htons(0); + iph -> ip_off = 0; + iph -> ip_ttl = 0xFF; + iph -> ip_p = ip_proto; + iph -> ip_src = htonl(ip_src); + iph -> ip_dst = htonl(ip_dst); + iph -> ip_sum = 0; +} + +/** + * IPv4: Handles IPv4-packets according to Receive-handle diagram. + * + * @param ip_packet IP-packet to be handled + * @param packetsize Length of the packet + * @return ZERO - packet handled successfully; + * NON ZERO - packet was not handled (e.g. bad format) + * @see receive_ether + * @see iphdr + */ +int8_t +handle_ipv4(uint8_t * ip_packet, int32_t packetsize) +{ + struct iphdr * iph; + int32_t old_sum; + static uint8_t ip_heap[65536 + ETH_MTU_SIZE]; + + if (packetsize < sizeof(struct iphdr)) + return -1; // packet is too small + + iph = (struct iphdr * ) ip_packet; + + /* Drop it if destination IPv4 address is no IPv4 Broadcast, no + * registered IPv4 Multicast and not our Unicast address + */ + if((multicast_ip == 0 && iph->ip_dst >= 0xE0000000 && iph->ip_dst <= 0xEFFFFFFF) + || (multicast_ip != iph->ip_dst && iph->ip_dst != 0xFFFFFFFF && + own_ip != 0 && iph->ip_dst != own_ip)) { + return -1; + } + + old_sum = iph -> ip_sum; + iph -> ip_sum = 0; + if (old_sum != checksum((uint16_t *) iph, sizeof (struct iphdr) >> 1)) + return -1; // Wrong IP checksum + + // is it the first fragment in a packet? + if (((iph -> ip_off) & 0x1FFF) == 0) { + // is it part of more fragments? + if (((iph -> ip_off) & 0x2000) == 0x2000) { + memcpy(ip_heap, ip_packet, iph->ip_len); + return 0; + } + } + // it's not the first fragment + else { + // get the first fragment + struct iphdr * iph_first = (struct iphdr * ) ip_heap; + + // is this fragment not part of the first one, then exit + if ((iph_first->ip_id != iph->ip_id ) || + (iph_first->ip_p != iph->ip_p ) || + (iph_first->ip_src != iph->ip_src) || + (iph_first->ip_dst != iph->ip_dst)) { + return 0; + } + + // this fragment is part of the first one! + memcpy(ip_heap + sizeof(struct iphdr) + + ((iph -> ip_off) & 0x1FFF) * 8, + ip_packet + sizeof(struct iphdr), + iph -> ip_len - sizeof(struct iphdr)); + + // is it part of more fragments? Then return. + if (((iph -> ip_off) & 0x2000) == 0x2000) { + return 0; + } + + // packet is completly reassambled now! + + // recalculate ip_len and set iph and ip_packet to the + iph_first->ip_len = iph->ip_len + ((iph->ip_off) & 0x1FFF) * 8; + + // set iph and ip_packet to the resulting packet. + ip_packet = ip_heap; + iph = (struct iphdr * ) ip_packet; + } + + switch (iph -> ip_p) { + case IPTYPE_ICMP: + return handle_icmp(iph, ip_packet + sizeof(struct iphdr), + iph -> ip_len - sizeof(struct iphdr)); + case IPTYPE_UDP: + return handle_udp(ip_packet + sizeof(struct iphdr), + iph -> ip_len - sizeof(struct iphdr)); + case IPTYPE_TCP: + return handle_tcp(ip_packet + sizeof(struct iphdr), + iph -> ip_len - sizeof(struct iphdr)); + default: + break; + } + return -1; // Unknown protocol +} + +/** + * IPv4: Send IPv4-packets. + * + * Before the packet is sent there are some patcches performed: + * - IPv4 source address is replaced by our unicast IPV4 address + * if it is set to 0 or 1 + * - IPv4 destination address is replaced by our multicast IPV4 address + * if it is set to 1 + * - IPv4 checksum is calculaded. + * - If payload type is UDP, then the UDP checksum is calculated also. + * + * We sent an ARP request first, if this is the first packet sent to + * the declared IPv4 destination address. In this case we store the + * the packet and sent it later if we receive the ARP response. + * If the MAC address is known already, then we send the packet immediatly. + * If there is already an ARP request pending, then we drop this packet + * and send again an ARP request. + * + * @param ip_packet IP-packet to be handled + * @param packetsize Length of the packet + * @return -2 - packet dropped (MAC address not resolved - ARP request pending) + * -1 - packet dropped (bad format) + * 0 - packet stored (ARP request sent - packet will be sent if + * ARP response is received) + * >0 - packet send (number of transmitted bytes is returned) + * + * @see receive_ether + * @see iphdr + */ +int +send_ipv4(void* buffer, int len) +{ + arp_entry_t *arp_entry; + struct iphdr *ip; + const uint8_t *mac_addr = 0; + + if(len + sizeof(struct ethhdr) > ETH_MTU_SIZE) + return -1; + + ip = (struct iphdr *) buffer; + + /* Replace source IPv4 address with our own unicast IPv4 address + * if it's 0 (= own unicast source address not specified). + */ + if(ip->ip_src == 0) { + ip->ip_src = htonl( own_ip ); + } + /* Replace source IPv4 address with our unicast IPv4 address and + * replace destination IPv4 address with our multicast IPv4 address + * if source address is set to 1. + */ + else if(ip->ip_src == 1) { + ip->ip_src = htonl( own_ip ); + ip->ip_dst = htonl( multicast_ip ); + } + + // Calculate the IPv4 checksum + ip->ip_sum = 0; + ip->ip_sum = checksum((uint16_t *) ip, sizeof (struct iphdr) >> 1); + + // if payload type is UDP, then we need to calculate the + // UDP checksum that depends on the IP header + if(ip->ip_p == IPTYPE_UDP) { + fill_udp_checksum(ip); + } + + // Check if the MAC address is already cached + if(~ip->ip_dst == 0 + || ( ((~subnet_mask) & ip->ip_dst) == ~subnet_mask && + ( subnet_mask & ip->ip_dst) == (subnet_mask & own_ip))) { + arp_entry = &arp_table[arp_producer]; + mac_addr = broadcast_mac; + } + else if(ip->ip_dst == multicast_ip) { + arp_entry = &arp_table[arp_producer]; + mac_addr = multicast_mac; + } + else { + // Check if IP address is in the same subnet as we are + if((subnet_mask & own_ip) == (subnet_mask & ip->ip_dst)) + arp_entry = lookup_mac_addr(ip->ip_dst); + // if not then we need to know the router's IP address + else + arp_entry = lookup_mac_addr(router_ip); + if(arp_entry && memcmp(arp_entry->mac_addr, null_mac_addr, 6) != 0) + mac_addr = arp_entry->mac_addr; + } + + // If we could not resolv the MAC address by our own... + if(!mac_addr) { + // send the ARP request + arp_send_request(ip->ip_dst); + + // drop the current packet if there is already a ARP request pending + if(arp_entry) + return -2; + + // take the next entry in the ARP table to prepare a the new ARP entry. + arp_entry = &arp_table[arp_producer]; + arp_producer = (arp_producer+1)%ARP_ENTRIES; + + // if ARP table is full then we must drop the oldes entry. + if(arp_consumer == arp_producer) + arp_consumer = (arp_consumer+1)%ARP_ENTRIES; + + // store the packet to be send if the ARP reply is received + arp_entry->ipv4_addr = ip->ip_dst; + memset(arp_entry->mac_addr, 0, 6); + fill_ethhdr (arp_entry->eth_frame, htons(ETHERTYPE_IP), + get_mac_address(), null_mac_addr); + memcpy(&arp_entry->eth_frame[sizeof(struct ethhdr)], + buffer, len); + arp_entry->eth_len = len + sizeof(struct ethhdr); + + return 0; + } + + // Send the packet with the known MAC address + fill_ethhdr(arp_entry->eth_frame, htons(ETHERTYPE_IP), + get_mac_address(), mac_addr); + memcpy(&arp_entry->eth_frame[sizeof(struct ethhdr)], buffer, len); + return send_ether(arp_entry->eth_frame, len + sizeof(struct ethhdr)); +} + +/** + * IPv4: Calculate UDP checksum. Places the result into the UDP-header. + * <p> + * Use this function after filling the UDP payload. + * + * @param ipv4_hdr Points to the place where IPv4-header starts. + */ + +static void +fill_udp_checksum(struct iphdr *ipv4_hdr) +{ + int i; + unsigned long checksum = 0; + struct iphdr ip_hdr; + char *ptr; + udp_hdr_t *udp_hdr; + + udp_hdr = (udp_hdr_t *) (ipv4_hdr + 1); + udp_hdr->uh_sum = 0; + + memset(&ip_hdr, 0, sizeof(struct iphdr)); + ip_hdr.ip_src = ipv4_hdr->ip_src; + ip_hdr.ip_dst = ipv4_hdr->ip_dst; + ip_hdr.ip_len = udp_hdr->uh_ulen; + ip_hdr.ip_p = ipv4_hdr->ip_p; + + ptr = (char*) udp_hdr; + for (i = 0; i < udp_hdr->uh_ulen; i+=2) + checksum += *((uint16_t*) &ptr[i]); + + ptr = (char*) &ip_hdr; + for (i = 0; i < sizeof(struct iphdr); i+=2) + checksum += *((uint16_t*) &ptr[i]); + + checksum = (checksum >> 16) + (checksum & 0xffff); + checksum += (checksum >> 16); + udp_hdr->uh_sum = ~checksum; +} + +/** + * IPv4: Calculates checksum for IP header. + * + * @param packet Points to the IP-header + * @param words Size of the packet in words incl. IP-header and data. + * @return Checksum + * @see iphdr + */ +static unsigned short +checksum(unsigned short * packet, int words) +{ + unsigned long checksum; + + for (checksum = 0; words > 0; words--) + checksum += *packet++; + checksum = (checksum >> 16) + (checksum & 0xffff); + checksum += (checksum >> 16); + + return ~checksum; +} + +static arp_entry_t* +lookup_mac_addr(uint32_t ipv4_addr) +{ + unsigned int i; + + for(i=arp_consumer; i != arp_producer; i = ((i+1)%ARP_ENTRIES) ) { + if(arp_table[i].ipv4_addr == ipv4_addr) + return &arp_table[i]; + } + return 0; +} + + +/** + * ARP: Sends an ARP-request package. + * For given IPv4 retrieves MAC via ARP (makes several attempts) + * + * @param dest_ip IP of the host which MAC should be obtained + */ +static void +arp_send_request(uint32_t dest_ip) +{ + arp_entry_t *arp_entry = &arp_table[arp_producer]; + + memset(arp_entry->eth_frame, 0, sizeof(struct ethhdr) + sizeof(struct arphdr)); + fill_arphdr(&arp_entry->eth_frame[sizeof(struct ethhdr)], ARP_REQUEST, + get_mac_address(), own_ip, broadcast_mac, dest_ip); + fill_ethhdr(arp_entry->eth_frame, ETHERTYPE_ARP, + get_mac_address(), broadcast_mac); + + send_ether(arp_entry->eth_frame, + sizeof(struct ethhdr) + sizeof(struct arphdr)); +} + +/** + * ARP: Sends an ARP-reply package. + * This package is used to serve foreign requests (in case IP in + * foreign request matches our host IP). + * + * @param src_ip requester IP address (foreign IP) + * @param src_mac requester MAC address (foreign MAC) + */ +static void +arp_send_reply(uint32_t src_ip, uint8_t * src_mac) +{ + arp_entry_t *arp_entry = &arp_table[arp_producer]; + + memset(arp_entry->eth_frame, 0, sizeof(struct ethhdr) + sizeof(struct arphdr)); + fill_ethhdr(arp_entry->eth_frame, ETHERTYPE_ARP, + get_mac_address(), src_mac); + fill_arphdr(&arp_entry->eth_frame[sizeof(struct ethhdr)], ARP_REPLY, + get_mac_address(), own_ip, src_mac, src_ip); + + send_ether(arp_entry->eth_frame, + sizeof(struct ethhdr) + sizeof(struct arphdr)); +} + +/** + * ARP: Creates ARP package. Places ARP-header in a packet and fills it + * with corresponding information. + * <p> + * Use this function with similar functions for other network layers + * (fill_ethhdr). + * + * @param packet Points to the place where ARP-header must be placed. + * @param opcode Identifies is it request (ARP_REQUEST) + * or reply (ARP_REPLY) package. + * @param src_mac sender MAC address + * @param src_ip sender IP address + * @param dest_mac receiver MAC address + * @param dest_ip receiver IP address + * @see arphdr + * @see fill_ethhdr + */ +static void +fill_arphdr(uint8_t * packet, uint8_t opcode, + const uint8_t * src_mac, uint32_t src_ip, + const uint8_t * dest_mac, uint32_t dest_ip) +{ + struct arphdr * arph = (struct arphdr *) packet; + + arph -> hw_type = htons(1); + arph -> proto_type = htons(ETHERTYPE_IP); + arph -> hw_len = 6; + arph -> proto_len = 4; + arph -> opcode = htons(opcode); + + memcpy(arph->src_mac, src_mac, 6); + arph->src_ip = htonl(src_ip); + memcpy(arph->dest_mac, dest_mac, 6); + arph->dest_ip = htonl(dest_ip); +} + +/** + * ARP: Handles ARP-messages according to Receive-handle diagram. + * Updates arp_table for outstanding ARP requests (see arp_getmac). + * + * @param packet ARP-packet to be handled + * @param packetsize length of the packet + * @return ZERO - packet handled successfully; + * NON ZERO - packet was not handled (e.g. bad format) + * @see arp_getmac + * @see receive_ether + * @see arphdr + */ +int8_t +handle_arp(uint8_t * packet, int32_t packetsize) +{ + struct arphdr * arph = (struct arphdr *) packet; + + if (packetsize < sizeof(struct arphdr)) + return -1; // Packet is too small + + if (arph -> hw_type != htons(1) || arph -> proto_type != htons(ETHERTYPE_IP)) + return -1; // Unknown hardware or unsupported protocol + + if (arph -> dest_ip != htonl(own_ip)) + return -1; // receiver IP doesn't match our IP + + switch(htons(arph -> opcode)) { + case ARP_REQUEST: + // foreign request + if(own_ip != 0) + arp_send_reply(htonl(arph->src_ip), arph -> src_mac); + return 0; // no error + case ARP_REPLY: { + unsigned int i; + // if it is not for us -> return immediately + if(memcmp(get_mac_address(), arph->dest_mac, 6)) { + return 0; // no error + } + + if(arph->src_ip == 0) { + // we are not interested for a MAC address if + // the IPv4 address is 0.0.0.0 or ff.ff.ff.ff + return -1; + } + + // now let's find the corresponding entry in the ARP table + + for(i=arp_consumer; i != arp_producer; i = ((i+1)%ARP_ENTRIES) ) { + if(arp_table[i].ipv4_addr == arph->src_ip) + break; + } + if(i == arp_producer || memcmp(arp_table[i].mac_addr, null_mac_addr, 6) != 0) { + // we have not asked to resolve this IPv4 address ! + return -1; + } + + memcpy(arp_table[i].mac_addr, arph->src_mac, 6); + + // do we have something to send + if(arp_table[i].eth_len > 0) { + struct ethhdr * ethh = (struct ethhdr *) arp_table[i].eth_frame; + memcpy(ethh -> dest_mac, arp_table[i].mac_addr, 6); + + send_ether(arp_table[i].eth_frame, arp_table[i].eth_len); + arp_table[i].eth_len = 0; + } + return 0; // no error + } + default: + break; + } + return -1; // Invalid message type +} + +/** + * ICMP: Send an ICMP Echo request to destination IPv4 address. + * This function does also set a global variable to the + * destination IPv4 address. If there is an ICMP Echo Reply + * received later then the variable is set back to 0. + * In other words, reading a value of 0 form this variable + * means that an answer to the request has been arrived. + * + * @param _ping_dst_ip destination IPv4 address + */ +void +ping_ipv4(uint32_t _ping_dst_ip) +{ + unsigned char packet[sizeof(struct iphdr) + sizeof(struct icmphdr)]; + struct icmphdr *icmp; + + ping_dst_ip = _ping_dst_ip; + + if(ping_dst_ip == 0) + return; + + fill_iphdr(packet, sizeof(struct iphdr) + sizeof(struct icmphdr), IPTYPE_ICMP, + 0, ping_dst_ip); + icmp = (struct icmphdr *) (packet + sizeof(struct iphdr)); + icmp->type = ICMP_ECHO_REQUEST; + icmp->code = 0; + icmp->checksum = 0; + icmp->options.echo.id = 0xd476; + icmp->options.echo.seq = 1; + + memset(icmp->payload.data, '*', sizeof(icmp->payload.data)); + + icmp->checksum = + checksum((unsigned short *) icmp, sizeof(struct icmphdr) >> 1); + send_ipv4(packet, sizeof(struct iphdr) + sizeof(struct icmphdr)); +} + +/** + * ICMP: Return host IPv4 address that we are waiting for a + * ICMP Echo reply message. If this value is 0 then we have + * received an reply. + * + * @return ping_dst_ip host IPv4 address + */ +uint32_t +pong_ipv4(void) +{ + return ping_dst_ip; +} + +/** + * ICMP: Handles ICMP-packets according to Receive-handle diagram. + * + * @param icmp_packet ICMP-packet to be handled + * @param packetsize Length of the packet + * @return ZERO - packet handled successfully; + * NON ZERO - packet was not handled (e.g. bad format) + * @see handle_ipv4 + */ +static int8_t +handle_icmp(struct iphdr * iph, uint8_t * packet, int32_t packetsize) +{ + struct icmphdr *icmp = (struct icmphdr *) packet; + + switch(icmp->type) { + case ICMP_ECHO_REPLY: + if (icmp->options.echo.id != 0xd476) + return -1; + if (icmp->options.echo.seq != 1) + return -1; + if(ping_dst_ip != iph->ip_src + || ping_dst_ip == 0) + return -1; + ping_dst_ip = 0; + break; + case ICMP_DST_UNREACHABLE: { + // We've got Destination Unreachable msg + // Inform corresponding upper network layers + struct iphdr * bad_iph = (struct iphdr * ) &icmp->payload; + + switch(bad_iph->ip_p) { + case IPTYPE_TCP: + handle_tcp_dun((uint8_t *) (bad_iph + 1), packetsize + - sizeof(struct icmphdr) + - sizeof(struct iphdr), icmp->code); + break; + case IPTYPE_UDP: + handle_udp_dun((uint8_t *) (bad_iph + 1), packetsize + - sizeof(struct icmphdr) + - sizeof(struct iphdr), icmp->code); + break; + } + break; + } + case ICMP_SRC_QUENCH: + break; + case ICMP_REDIRECT: + break; + case ICMP_ECHO_REQUEST: { + // We've got an Echo Request - answer with Echo Replay msg + unsigned char reply_packet[sizeof(struct iphdr) + packetsize]; + struct icmphdr *reply_icmph; + + fill_iphdr(reply_packet, sizeof(struct iphdr) + packetsize, + IPTYPE_ICMP, 0, iph->ip_src); + + reply_icmph = (struct icmphdr *) &reply_packet[sizeof(struct iphdr)]; + memcpy(reply_icmph, packet, packetsize); + reply_icmph -> type = ICMP_ECHO_REPLY; + reply_icmph -> checksum = 0; + reply_icmph->checksum = checksum((unsigned short *) reply_icmph, + sizeof(struct icmphdr) >> 1); + + send_ipv4(reply_packet, sizeof(struct iphdr) + packetsize); + break; + } + case ICMP_TIME_EXCEEDED: + break; + case ICMP_PARAMETER_PROBLEM: + break; + case ICMP_TIMESTAMP_REQUEST: + break; + case ICMP_TIMESTAMP_REPLY: + break; + case ICMP_INFORMATION_REQUEST: + break; + case ICMP_INFORMATION_REPLY: + break; + } + return 0; +} diff --git a/clients/net-snk/app/netlib/ipv4.h b/clients/net-snk/app/netlib/ipv4.h new file mode 100644 index 0000000..0e5a408 --- /dev/null +++ b/clients/net-snk/app/netlib/ipv4.h @@ -0,0 +1,96 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +#ifndef _IPV4_H_ +#define _IPV4_H_ + +#include <types.h> + +#define IPTYPE_ICMP 1 + +/** \struct iphdr + * A header for IP-packets. + * For more information see RFC 791. + */ +struct iphdr { + uint8_t ip_hlv; /**< Header length and version of the header */ + uint8_t ip_tos; /**< Type of Service */ + uint16_t ip_len; /**< Length in octets, inlc. this header and data */ + uint16_t ip_id; /**< ID is used to aid in assembling framents */ + uint16_t ip_off; /**< Info about fragmentation (control, offset) */ + uint8_t ip_ttl; /**< Time to Live */ + uint8_t ip_p; /**< Next level protocol type */ + uint16_t ip_sum; /**< Header checksum */ + uint32_t ip_src; /**< Source IP address */ + uint32_t ip_dst; /**< Destination IP address */ +}; +typedef struct iphdr ipv4_hdr_t; + +/* ICMP Error Codes */ +#define ICMP_NET_UNREACHABLE 0 +#define ICMP_HOST_UNREACHABLE 1 +#define ICMP_PROTOCOL_UNREACHABLE 2 +#define ICMP_PORT_UNREACHABLE 3 +#define ICMP_FRAGMENTATION_NEEDED 4 +#define ICMP_SOURCE_ROUTE_FAILED 5 + +/** \struct arphdr + * A header for ARP-messages, retains info about HW and proto addresses. + * For more information see RFC 826. + */ +struct arphdr { + uint16_t hw_type; /**< HW address space (1 for Ethernet) */ + uint16_t proto_type; /**< Protocol address space */ + uint8_t hw_len; /**< Byte length of each HW address */ + uint8_t proto_len; /**< Byte length of each proto address */ + uint16_t opcode; /**< Identifies is it request (1) or reply (2) */ + uint8_t src_mac[6]; /**< HW address of sender of this packet */ + uint32_t src_ip; /**< Proto address of sender of this packet */ + uint8_t dest_mac[6]; /**< HW address of target of this packet */ + uint32_t dest_ip; /**< Proto address of target of this packet */ +} __attribute((packed)); + +/*>>>>>>>>>>>>> Initialization of the IPv4 network layer. <<<<<<<<<<<<<*/ +extern void set_ipv4_address(uint32_t own_ip); +extern uint32_t get_ipv4_address(void); +extern void set_ipv4_multicast(uint32_t multicast_ip); +extern uint32_t get_ipv4_multicast(void); +extern void set_ipv4_router(uint32_t router_ip); +extern uint32_t get_ipv4_router(void); +extern void set_ipv4_netmask(uint32_t subnet_mask); +extern uint32_t get_ipv4_netmask(void); + +extern int (*send_ip) (void *, int); + +/* fills ip header */ +extern void fill_iphdr(uint8_t * packet, uint16_t packetsize, + uint8_t ip_proto, uint32_t ip_src, uint32_t ip_dst); + +/* Send a IPv4 packet. Adding the Ethernet-Header and resolving the + * MAC address is done transparent in the background if necessary. + */ +extern int send_ipv4(void* buffer, int len); + +/* Sends an ICMP Echo request to destination IPv4 address */ +extern void ping_ipv4(uint32_t _ping_dst_ip); + +/* Returns host IPv4 address that we are waiting for a response */ +extern uint32_t pong_ipv4(void); + +/* Handles IPv4-packets that are detected by receive_ether. */ +extern int8_t handle_ipv4(uint8_t * packet, int32_t packetsize); + +/* Handles ARP-packets that are detected by receive_ether. */ +extern int8_t handle_arp(uint8_t * packet, int32_t packetsize); + +#endif diff --git a/clients/net-snk/app/netlib/tcp.c b/clients/net-snk/app/netlib/tcp.c new file mode 100644 index 0000000..5511aa0 --- /dev/null +++ b/clients/net-snk/app/netlib/tcp.c @@ -0,0 +1,50 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/*>>>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<*/ + +#include <tcp.h> +#include <sys/socket.h> + + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/ + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<*/ + + +/** + * TCP: Handles TCP-packets according to Receive-handle diagram. + * + * @param tcp_packet TCP-packet to be handled + * @param packetsize Length of the packet + * @return ZERO - packet handled successfully; + * NON ZERO - packet was not handled (e.g. bad format) + */ +int8_t +handle_tcp(uint8_t * tcp_packet, int32_t packetsize) +{ + return -1; +} + + +/** + * NET: This function handles situation when "Destination unreachable" + * ICMP-error occurs during sending TCP-packet. + * + * @param err_code Error Code (e.g. "Host unreachable") + * @param packet original TCP-packet + * @param packetsize length of the packet + * @see handle_icmp + */ +void +handle_tcp_dun(uint8_t * tcp_packet, uint32_t packetsize, uint8_t err_code) { +} diff --git a/clients/net-snk/app/netlib/tcp.h b/clients/net-snk/app/netlib/tcp.h new file mode 100644 index 0000000..7d0c906 --- /dev/null +++ b/clients/net-snk/app/netlib/tcp.h @@ -0,0 +1,27 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _TCP_H +#define _TCP_H + +#include <types.h> + +#define IPTYPE_TCP 6 + +/* Handles TCP-packets that are detected by any network layer. */ +extern int8_t handle_tcp(uint8_t * udp_packet, int32_t packetsize); + +/* Handles TCP related ICMP-Dest.Unreachable packets that are detected by + * the network layers. */ +extern void handle_tcp_dun(uint8_t * tcp_packet, uint32_t packetsize, uint8_t err_code); + +#endif diff --git a/clients/net-snk/app/netlib/tftp.c b/clients/net-snk/app/netlib/tftp.c index 017558e..e8e9d09 100644 --- a/clients/net-snk/app/netlib/tftp.c +++ b/clients/net-snk/app/netlib/tftp.c @@ -1,5 +1,5 @@ /****************************************************************************** - * Copyright (c) 2004, 2007 IBM Corporation + * Copyright (c) 2004, 2008 IBM Corporation * All rights reserved. * This program and the accompanying materials * are made available under the terms of the BSD License @@ -10,17 +10,21 @@ * IBM Corporation - initial implementation *****************************************************************************/ +#include <tftp.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <sys/socket.h> -#include <netlib/netlib.h> -#include <netlib/icmp.h> +#include <ethernet.h> +#include <ipv4.h> +//#include <ipv6.h> +#include <udp.h> //#define __DEBUG__ +#define MAX_BLOCKSIZE 1428 #define BUFFER_LEN 2048 #define ACK_BUFFER_LEN 256 #define READ_BUFFER_LEN 256 @@ -41,6 +45,23 @@ #define ERROR 5 #define OACK 6 +/* Local variables */ +static unsigned char *buffer = NULL; +static unsigned short block = 0; +static unsigned short blocksize; +static char blocksize_str[6]; /* Blocksize string for read request */ +static int received_len = 0; +static int retries = 0; +static int huge_load; +static int len; +static int tftp_finished = 0; +static int lost_packets = 0; +static int tftp_errno = 0; +static int ip_version = 0; +static short port_number = -1; +static tftp_err_t *tftp_err; +static filename_ip_t *fn_ip; + /** * dump_package - Prints a package. * @@ -64,73 +85,51 @@ dump_package(unsigned char *buffer, unsigned int len) } #endif -/* UDP header checksum calculation */ - -static unsigned short -checksum(unsigned short *packet, int words, unsigned short *pseudo_ip) -{ - int i; - unsigned long checksum; - for (checksum = 0; words > 0; words--) - checksum += *packet++; - if (pseudo_ip) { - for (i = 0; i < 6; i++) - checksum += *pseudo_ip++; - } - checksum = (checksum >> 16) + (checksum & 0xffff); - checksum += (checksum >> 16); - return ~checksum; -} - - /** * send_rrq - Sends a read request package. - * - * @client: client IPv4 address (e.g. 127.0.0.1) - * @server: server IPv4 address (e.g. 127.0.0.1) - * @filename: name of the file which should be downloaded */ static void -send_rrq(int boot_device, filename_ip_t * fn_ip) +send_rrq(void) { - int i; + int ip_len = 0; + //int ip6_payload_len = 0; + unsigned short udp_len = 0; unsigned char mode[] = "octet"; unsigned char packet[READ_BUFFER_LEN]; - char *ptr; - struct ethhdr *ethh; - struct iphdr *ip; - struct udphdr *udph; - struct tftphdr *tftp; - struct pseudo_iphdr piph = { 0 }; + char *ptr = NULL; + struct iphdr *ip = NULL; + //struct ip6hdr *ip6 = NULL; + struct udphdr *udph = NULL; + struct tftphdr *tftp = NULL; memset(packet, 0, READ_BUFFER_LEN); - ethh = (struct ethhdr *) packet; - - memcpy(ethh->src_mac, fn_ip->own_mac, 6); - memcpy(ethh->dest_mac, fn_ip->server_mac, 6); - ethh->type = htons(ETHERTYPE_IP); - - ip = (struct iphdr *) ((unsigned char *) ethh + sizeof(struct ethhdr)); - ip->ip_hlv = 0x45; - ip->ip_tos = 0x00; - ip->ip_len = sizeof(struct iphdr) + sizeof(struct udphdr) - + strlen((char *) fn_ip->filename) + strlen((char *) mode) + 4 - + strlen("blksize") + strlen("1432") + 2; - ip->ip_id = 0x0; - ip->ip_off = 0x0000; - ip->ip_ttl = 60; - ip->ip_p = 17; - ip->ip_src = fn_ip->own_ip; - ip->ip_dst = fn_ip->server_ip; - ip->ip_sum = 0; - - udph = (struct udphdr *) (ip + 1); - udph->uh_sport = htons(2001); - udph->uh_dport = htons(69); - udph->uh_ulen = htons(sizeof(struct udphdr) + if (4 == ip_version) { + ip = (struct iphdr *) packet; + udph = (struct udphdr *) (ip + 1); + ip_len = sizeof(struct iphdr) + sizeof(struct udphdr) + + strlen((char *) fn_ip->filename) + strlen((char *) mode) + 4 + + strlen("blksize") + strlen(blocksize_str) + 2; + fill_iphdr ((uint8_t *) ip, ip_len, IPTYPE_UDP, 0, + fn_ip->server_ip); + } +/* + else if (6 == ip_version) { + ip6 = (struct ip6hdr *) packet; + udph = (struct udphdr *) (ip6 + 1); + ip6_payload_len = sizeof(struct udphdr) + + strlen((char *) fn_ip->filename) + strlen((char *) mode) + 4 + + strlen("blksize") + strlen(blocksize_str) + 2; + ip_len = sizeof(struct ip6hdr) + ip6_payload_len; + fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(), + &(fn_ip->server_ip6)); + + } +*/ + udp_len = htons(sizeof(struct udphdr) + strlen((char *) fn_ip->filename) + strlen((char *) mode) + 4 - + strlen("blksize") + strlen("1432") + 2); + + strlen("blksize") + strlen(blocksize_str) + 2); + fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(69)); tftp = (struct tftphdr *) (udph + 1); tftp->th_opcode = htons(RRQ); @@ -145,23 +144,12 @@ send_rrq(int boot_device, filename_ip_t * fn_ip) memcpy(ptr, "blksize", strlen("blksize") + 1); ptr += strlen("blksize") + 1; - memcpy(ptr, "1432", strlen("1432") + 1); + memcpy(ptr, blocksize_str, strlen(blocksize_str) + 1); - piph.ip_src = ip->ip_src; - piph.ip_dst = ip->ip_dst; - piph.ip_p = ip->ip_p; - piph.ip_ulen = udph->uh_ulen; + send_ip (packet, ip_len); - udph->uh_sum = 0; - udph->uh_sum = - checksum((unsigned short *) udph, udph->uh_ulen >> 1, - (unsigned short *) &piph); - - ip->ip_sum = - checksum((unsigned short *) ip, sizeof(struct iphdr) >> 1, 0); - i = send(boot_device, packet, ip->ip_len + sizeof(struct ethhdr), 0); #ifdef __DEBUG__ - printf("tftp RRQ %d bytes transmitted over socket.\n", i); + printf("tftp RRQ with %d bytes transmitted.\n", ip_len); #endif return; } @@ -169,68 +157,52 @@ send_rrq(int boot_device, filename_ip_t * fn_ip) /** * send_ack - Sends a acknowlege package. * - * @boot_device: - * @fn_ip: * @blckno: block number + * @dport: UDP destination port */ static void -send_ack(int boot_device, filename_ip_t * fn_ip, - int blckno, unsigned short dport) +send_ack(int blckno, unsigned short dport) { - int i; + int ip_len = 0; + //int ip6_payload_len = 0; + unsigned short udp_len = 0; unsigned char packet[ACK_BUFFER_LEN]; - struct ethhdr *ethh; - struct iphdr *ip; - struct udphdr *udph; - struct tftphdr *tftp; - struct pseudo_iphdr piph = { 0 }; + struct iphdr *ip = NULL; + //struct ip6hdr *ip6 = NULL; + struct udphdr *udph = NULL; + struct tftphdr *tftp = NULL; memset(packet, 0, ACK_BUFFER_LEN); - ethh = (struct ethhdr *) packet; - memcpy(ethh->src_mac, fn_ip->own_mac, 6); - memcpy(ethh->dest_mac, fn_ip->server_mac, 6); - ethh->type = htons(ETHERTYPE_IP); - - ip = (struct iphdr *) ((unsigned char *) ethh + sizeof(struct ethhdr)); - ip->ip_hlv = 0x45; - ip->ip_tos = 0x00; - ip->ip_len = sizeof(struct iphdr) + sizeof(struct udphdr) + 4; - ip->ip_id = 0; - ip->ip_off = 0x0000; - ip->ip_ttl = 60; - ip->ip_p = 17; - ip->ip_src = fn_ip->own_ip; - ip->ip_dst = fn_ip->server_ip; - - ip->ip_sum = 0; - - udph = (struct udphdr *) (ip + 1); - udph->uh_sport = htons(2001); - udph->uh_dport = htons(dport); - udph->uh_ulen = htons(sizeof(struct udphdr) + 4); + if (4 == ip_version) { + ip = (struct iphdr *) packet; + udph = (struct udphdr *) (ip + 1); + ip_len = sizeof(struct iphdr) + sizeof(struct udphdr) + 4; + fill_iphdr ((uint8_t *) ip, ip_len, IPTYPE_UDP, 0, + fn_ip->server_ip); + } +/* + else if (6 == ip_version) { + ip6 = (struct ip6hdr *) packet; + udph = (struct udphdr *) (ip6 + 1); + ip6_payload_len = sizeof(struct udphdr) + 4; + ip_len = sizeof(struct ethhdr) + sizeof(struct ip6hdr) + + ip6_payload_len; + fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(), + &(fn_ip->server_ip6)); + } +*/ + udp_len = htons(sizeof(struct udphdr) + 4); + fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(dport)); tftp = (struct tftphdr *) (udph + 1); tftp->th_opcode = htons(ACK); tftp->th_data = htons(blckno); - piph.ip_src = ip->ip_src; - piph.ip_dst = ip->ip_dst; - piph.ip_p = ip->ip_p; - piph.ip_ulen = udph->uh_ulen; - - udph->uh_sum = 0; - udph->uh_sum = - checksum((unsigned short *) udph, udph->uh_ulen >> 1, - (unsigned short *) &piph); - - ip->ip_sum = - checksum((unsigned short *) ip, sizeof(struct iphdr) >> 1, 0); - - i = send(boot_device, packet, ip->ip_len + sizeof(struct ethhdr), 0); + send_ip(packet, ip_len); #ifdef __DEBUG__ - printf("tftp ACK %d bytes transmitted over socket.\n", i); + printf("tftp ACK %d bytes transmitted.\n", ip_len); #endif return; @@ -239,120 +211,58 @@ send_ack(int boot_device, filename_ip_t * fn_ip, /** * send_error - Sends an error package. * - * @boot_device: socket handle - * @fn_ip: some OSI CEP-IDs * @error_code: Used sub code for error packet * @dport: UDP destination port */ static void -send_error(int boot_device, filename_ip_t * fn_ip, - int error_code, unsigned short dport) +send_error(int error_code, unsigned short dport) { - int i; + int ip_len = 0; + //int ip6_payload_len = 0; + unsigned short udp_len = 0; unsigned char packet[256]; - struct ethhdr *ethh; - struct iphdr *ip; - struct udphdr *udph; - struct tftphdr *tftp; - struct pseudo_iphdr piph = { 0 }; + //struct ip6hdr *ip6 = NULL; + struct iphdr *ip = NULL; + struct udphdr *udph = NULL; + struct tftphdr *tftp = NULL; memset(packet, 0, 256); - ethh = (struct ethhdr *) packet; - memcpy(ethh->src_mac, fn_ip->own_mac, 6); - memcpy(ethh->dest_mac, fn_ip->server_mac, 6); - ethh->type = htons(ETHERTYPE_IP); - - ip = (struct iphdr *) ((unsigned char *) ethh + sizeof(struct ethhdr)); - ip->ip_hlv = 0x45; - ip->ip_tos = 0x00; - ip->ip_len = sizeof(struct iphdr) + sizeof(struct udphdr) + 5; - ip->ip_id = 0; - ip->ip_off = 0x0000; - ip->ip_ttl = 60; - ip->ip_p = 17; - ip->ip_src = fn_ip->own_ip; - ip->ip_dst = fn_ip->server_ip; - - ip->ip_sum = 0; - - udph = (struct udphdr *) (ip + 1); - udph->uh_sport = htons(2001); - udph->uh_dport = htons(dport); - udph->uh_ulen = htons(sizeof(struct udphdr) + 5); + if (4 == ip_version) { + ip = (struct iphdr *) packet; + udph = (struct udphdr *) (ip + 1); + ip_len = sizeof(struct iphdr) + sizeof(struct udphdr) + 5; + fill_iphdr ((uint8_t *) ip, ip_len, IPTYPE_UDP, 0, + fn_ip->server_ip); + } +/* + else if (6 == ip_version) { + ip6 = (struct ip6hdr *) packet; + udph = (struct udphdr *) (ip6 + 1); + ip6_payload_len = sizeof(struct udphdr) + 5; + ip_len = sizeof(struct ethhdr) + sizeof(struct ip6hdr) + + ip6_payload_len; + fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(), + &(fn_ip->server_ip6)); + } +*/ + udp_len = htons(sizeof(struct udphdr) + 5); + fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(dport)); tftp = (struct tftphdr *) (udph + 1); tftp->th_opcode = htons(ERROR); tftp->th_data = htons(error_code); ((char *) &tftp->th_data)[2] = 0; - piph.ip_src = ip->ip_src; - piph.ip_dst = ip->ip_dst; - piph.ip_p = ip->ip_p; - piph.ip_ulen = udph->uh_ulen; - - udph->uh_sum = 0; - udph->uh_sum = - checksum((unsigned short *) udph, udph->uh_ulen >> 1, - (unsigned short *) &piph); - - ip->ip_sum = - checksum((unsigned short *) ip, sizeof(struct iphdr) >> 1, 0); - - i = send(boot_device, packet, ip->ip_len + sizeof(struct ethhdr), 0); + send_ip(packet, ip_len); #ifdef __DEBUG__ - printf("tftp ERROR %d bytes transmitted over socket.\n", i); + printf("tftp ERROR %d bytes transmitted.\n", ip_len); #endif return; } - -static int -send_arp_reply(int boot_device, filename_ip_t * fn_ip) -{ - int i; - unsigned int packetsize = sizeof(struct ethhdr) + sizeof(struct arphdr); - unsigned char packet[packetsize]; - struct ethhdr *ethh; - struct arphdr *arph; - - ethh = (struct ethhdr *) packet; - arph = (struct arphdr *) ((void *) ethh + sizeof(struct ethhdr)); - - memset(packet, 0, packetsize); - - memcpy(ethh->src_mac, fn_ip->own_mac, 6); - memcpy(ethh->dest_mac, fn_ip->server_mac, 6); - ethh->type = htons(ETHERTYPE_ARP); - - arph->hw_type = 1; - arph->proto_type = 0x800; - arph->hw_len = 6; - arph->proto_len = 4; - - memcpy(arph->src_mac, fn_ip->own_mac, 6); - arph->src_ip = fn_ip->own_ip; - - arph->dest_ip = fn_ip->server_ip; - - arph->opcode = 2; -#ifdef __DEBUG__ - printf("send arp reply\n"); -#endif -#if 0 - printf("Sending packet\n"); - printf("Packet is "); - for (i = 0; i < packetsize; i++) - printf(" %2.2x", packet[i]); - printf(".\n"); -#endif - - i = send(boot_device, packet, packetsize, 0); - return i; -} - static void print_progress(int urgent, int received_bytes) { @@ -397,8 +307,6 @@ get_blksize(unsigned char *buffer, unsigned int len) { unsigned char *orig = buffer; /* skip all headers until tftp has been reached */ - buffer += sizeof(struct ethhdr); - buffer += sizeof(struct iphdr); buffer += sizeof(struct udphdr); /* skip opc */ buffer += 2; @@ -424,242 +332,266 @@ get_blksize(unsigned char *buffer, unsigned int len) } /** - * this prints out some status characters + * Handle incoming tftp packets after read request was sent + * + * this function also prints out some status characters * \|-/ for each packet received * A for an arp packet * I for an ICMP packet * #+* for different unexpected TFTP packets (not very good) + * + * @param packet points to the UDP header of the packet + * @param len the length of the network packet + * @return ZERO if packet was handled successfully + * ERRORCODE if error occurred */ -static int -the_real_tftp(int boot_device, filename_ip_t * fn_ip, unsigned char *buffer, - int len, unsigned int retries, tftp_err_t * tftp_err, int huge_load) +int32_t +handle_tftp(uint8_t *packet, int32_t packetsize) { - int i, j = 0; - int received_len = 0; - struct ethhdr *ethh; - struct arphdr *arph; - - struct iphdr *ip; struct udphdr *udph; struct tftphdr *tftp; - struct icmphdr *icmp; - unsigned char packet[BUFFER_LEN]; - short port_number = -1; - unsigned short block = 0; - unsigned short blocksize = 512; - int lost_packets = 0; + /* buffer is only set if we are handling TFTP */ + if (buffer == NULL ) + return 0; - tftp_err->bad_tftp_packets = 0; - tftp_err->no_packets = 0; - - send_rrq(boot_device, fn_ip); - - printf(" Receiving data: "); - print_progress(-1, 0); - - set_timer(TICKS_SEC); - while (j++ < 0x100000) { - /* bad_tftp_packets are counted whenever we receive a TFTP packet - * which was not expected; if this gets larger than 'retries' - * we just exit */ - if (tftp_err->bad_tftp_packets > retries) { - return -40; - } - /* no_packets counts the times we have returned from recv() without - * any packet received; if this gets larger than 'retries' - * we also just exit */ - if (tftp_err->no_packets > retries) { - return -41; - } - /* don't wait longer than 0.5 seconds for packet to be recevied */ - do { - i = recv(boot_device, packet, BUFFER_LEN, 0); - if (i != 0) - break; - } while (get_timer() > 0); - - /* no packet received; no processing */ - if (i == 0) { - /* the server doesn't seem to retry let's help out a bit */ - if (tftp_err->no_packets > 4 && port_number != -1 - && block > 1) - send_ack(boot_device, fn_ip, block, - port_number); - tftp_err->no_packets++; - set_timer(TICKS_SEC); - continue; - } #ifndef __DEBUG__ - print_progress(0, received_len); + print_progress(0, received_len); #endif - ethh = (struct ethhdr *) packet; - arph = - (struct arphdr *) ((void *) ethh + sizeof(struct ethhdr)); - ip = (struct iphdr *) (packet + sizeof(struct ethhdr)); - udph = (struct udphdr *) ((void *) ip + sizeof(struct iphdr)); - tftp = - (struct tftphdr *) ((void *) udph + sizeof(struct udphdr)); - icmp = (struct icmphdr *) ((void *) ip + sizeof(struct iphdr)); - - if (memcmp(ethh->dest_mac, fn_ip->own_mac, 6) == 0) { - set_timer(TICKS_SEC); - tftp_err->no_packets = 0; - } + udph = (struct udphdr *) packet; + tftp = (struct tftphdr *) ((void *) udph + sizeof(struct udphdr)); + set_timer(TICKS_SEC); - if (ethh->type == htons(ETHERTYPE_ARP) && - arph->hw_type == 1 && - arph->proto_type == 0x800 && arph->opcode == 1) { - /* let's see if the arp request asks for our IP address - * else we will not answer */ - if (fn_ip->own_ip == arph->dest_ip) { #ifdef __DEBUG__ - printf("\bA "); + dump_package(packet, packetsize); #endif - send_arp_reply(boot_device, fn_ip); - } - continue; - } - /* check if packet is an ICMP packet */ - if (ip->ip_p == PROTO_ICMP) { -#ifdef __DEBUG__ - printf("\bI "); -#endif - i = handle_icmp(icmp); - if (i) - return i; + port_number = udph->uh_sport; + if (tftp->th_opcode == htons(OACK)) { + /* an OACK means that the server answers our blocksize request */ + blocksize = get_blksize(packet, packetsize); + if (!blocksize || blocksize > MAX_BLOCKSIZE) { + send_error(8, port_number); + tftp_errno = -8; + goto error; } - - /* only IPv4 UDP packets we want */ - if (ip->ip_hlv != 0x45 || ip->ip_p != 0x11) { + send_ack(0, port_number); + } else if (tftp->th_opcode == htons(ACK)) { + /* an ACK means that the server did not answers + * our blocksize request, therefore we will set the blocksize + * to the default value of 512 */ + blocksize = 512; + send_ack(0, port_number); + } else if ((unsigned char) tftp->th_opcode == ERROR) { #ifdef __DEBUG__ - printf("Unknown packet %x %x %x %x %x \n", ethh->type, - ip->ip_hlv, ip->ip_p, ip->ip_dst, fn_ip->own_ip); + printf("tftp->th_opcode : %x\n", tftp->th_opcode); + printf("tftp->th_data : %x\n", tftp->th_data); #endif - continue; + switch ( (uint8_t) tftp->th_data) { + case ENOTFOUND: + tftp_errno = -3; // ERROR: file not found + break; + case EACCESS: + tftp_errno = -4; // ERROR: access violation + break; + case EBADOP: + tftp_errno = -5; // ERROR: illegal TFTP operation + break; + case EBADID: + tftp_errno = -6; // ERROR: unknown transfer ID + break; + case ENOUSER: + tftp_errno = -7; // ERROR: no such user + break; + default: + tftp_errno = -1; // ERROR: unknown error } - - /* we only want packets for our own IP and broadcast UDP packets - * there will be probably never be a broadcast UDP TFTP packet - * but the RFC talks about it (crazy RFC) */ - if (!(ip->ip_dst == fn_ip->own_ip || ip->ip_dst == 0xFFFFFFFF)) - continue; -#ifdef __DEBUG__ - dump_package(packet, i); -#endif - - port_number = udph->uh_sport; - if (tftp->th_opcode == htons(OACK)) { - /* an OACK means that the server answers our blocksize request */ - blocksize = get_blksize(packet, i); - if (!blocksize || blocksize > 1432) { - send_error(boot_device, fn_ip, 8, port_number); - return -8; - } - send_ack(boot_device, fn_ip, 0, port_number); - } else if (tftp->th_opcode == htons(ACK)) { - /* an ACK means that the server did not answers - * our blocksize request, therefore we will set the blocksize - * to the default value of 512 */ - blocksize = 512; - send_ack(boot_device, fn_ip, 0, port_number); - } else if ((unsigned char) tftp->th_opcode == ERROR) { + goto error; + } else if (tftp->th_opcode == DATA) { + /* DATA PACKAGE */ + if (block + 1 == tftp->th_data) { + ++block; + } + else if( block == 0xffff && huge_load != 0 + && (tftp->th_data == 0 || tftp->th_data == 1) ) { + block = tftp->th_data; + } + else if (tftp->th_data == block) { #ifdef __DEBUG__ - printf("tftp->th_opcode : %x\n", tftp->th_opcode); - printf("tftp->th_data : %x\n", tftp->th_data); + printf + ("\nTFTP: Received block %x, expected block was %x\n", + tftp->th_data, block + 1); + printf("\b+ "); #endif - if ((unsigned char) tftp->th_data == ENOTFOUND) /* 1 */ - return -3; // ERROR: file not found - else if ((unsigned char) tftp->th_data == EACCESS) /* 2 */ - return -4; // ERROR: access violation - else if ((unsigned char) tftp->th_data == EBADOP) /* 4 */ - return -5; // ERROR: illegal TFTP operation - else if ((unsigned char) tftp->th_data == EBADID) /* 5 */ - return -6; // ERROR: unknown transfer ID - else if ((unsigned char) tftp->th_data == ENOUSER) /* 7 */ - return -7; // ERROR: no such user - return -1; // ERROR: unknown error - } else if (tftp->th_opcode == DATA) { - /* DATA PACKAGE */ - if (block + 1 == tftp->th_data) { - ++block; - } - else if( block == 0xffff && huge_load != 0 - && (tftp->th_data == 0 || tftp->th_data == 1) ) { - block = tftp->th_data; - } - else if (tftp->th_data == block) { + send_ack(tftp->th_data, port_number); + lost_packets++; + tftp_err->bad_tftp_packets++; + return 0; + } else if (tftp->th_data < block) { #ifdef __DEBUG__ - printf - ("\nTFTP: Received block %x, expected block was %x\n", - tftp->th_data, block + 1); - printf("\b+ "); + printf + ("\nTFTP: Received block %x, expected block was %x\n", + tftp->th_data, block + 1); + printf("\b* "); #endif - send_ack(boot_device, fn_ip, tftp->th_data, - port_number); - lost_packets++; - tftp_err->bad_tftp_packets++; - continue; - } else if (tftp->th_data < block) { + /* This means that an old data packet appears (again); + * this happens sometimes if we don't answer fast enough + * and a timeout is generated on the server side; + * as we already have this packet we just ignore it */ + tftp_err->bad_tftp_packets++; + return 0; + } else { + tftp_err->blocks_missed = block + 1; + tftp_err->blocks_received = tftp->th_data; + tftp_errno = -42; + goto error; + } + tftp_err->bad_tftp_packets = 0; + /* check if our buffer is large enough */ + if (received_len + udph->uh_ulen - 12 > len) { + tftp_errno = -2; + goto error; + } + memcpy(buffer + received_len, &tftp->th_data + 1, + udph->uh_ulen - 12); + send_ack(tftp->th_data, port_number); + received_len += udph->uh_ulen - 12; + /* Last packet reached if the payload of the UDP packet + * is smaller than blocksize + 12 + * 12 = UDP header (8) + 4 bytes TFTP payload */ + if (udph->uh_ulen < blocksize + 12) { + tftp_finished = 1; + return 0; + } + /* 0xffff is the highest block number possible + * see the TFTP RFCs */ + + if (block >= 0xffff && huge_load == 0) { + tftp_errno = -9; + goto error; + } + } else { #ifdef __DEBUG__ - printf - ("\nTFTP: Received block %x, expected block was %x\n", - tftp->th_data, block + 1); - printf("\b* "); + printf("Unknown packet %x\n", tftp->th_opcode); + printf("\b# "); #endif - /* This means that an old data packet appears (again); - * this happens sometimes if we don't answer fast enough - * and a timeout is generated on the server side; - * as we already have this packet we just ignore it */ - tftp_err->bad_tftp_packets++; - continue; - } else { - tftp_err->blocks_missed = block + 1; - tftp_err->blocks_received = tftp->th_data; - return -42; - } - - tftp_err->bad_tftp_packets = 0; - /* check if our buffer is large enough */ - if (received_len + udph->uh_ulen - 12 > len) - return -2; - memcpy(buffer + received_len, &tftp->th_data + 1, - udph->uh_ulen - 12); - send_ack(boot_device, fn_ip, tftp->th_data, - port_number); - received_len += udph->uh_ulen - 12; - /* Last packet reached if the payload of the UDP packet - * is smaller than blocksize + 12 - * 12 = UDP header (8) + 4 bytes TFTP payload */ - if (udph->uh_ulen < blocksize + 12) - break; - /* 0xffff is the highest block number possible - * see the TFTP RFCs */ - - if (block >= 0xffff && huge_load == 0) { - return -9; - } - } else { + tftp_err->bad_tftp_packets++; + return 0; + } + + return 0; + +error: #ifdef __DEBUG__ - printf("Unknown packet %x\n", tftp->th_opcode); - printf("\b# "); + printf("\nTFTP errno: %d\n", tftp_errno); #endif - tftp_err->bad_tftp_packets++; - continue; + tftp_finished = 1; + return tftp_errno; +} + +/** + * TFTP: This function handles situation when "Destination unreachable" + * ICMP-error occurs during sending TFTP-packet. + * + * @param err_code Error Code (e.g. "Host unreachable") + */ +void +handle_tftp_dun(uint8_t err_code) +{ + tftp_errno = - err_code - 10; + tftp_finished = 1; +} + +/** + * TFTP: Interface function to load files via TFTP. + * + * @param _fn_ip contains the following configuration information: + * client IP, TFTP-server IP, filename to be loaded + * @param _buffer destination buffer for the file + * @param _len size of destination buffer + * @param _retries max number of retries + * @param _tftp_err contains info about TFTP-errors (e.g. lost packets) + * @param _mode NON ZERO - multicast, ZERO - unicast + * @param _blocksize blocksize for DATA-packets + * @return ZERO - error condition occurs + * NON ZERO - size of received file + */ +int +tftp(filename_ip_t * _fn_ip, unsigned char *_buffer, int _len, + unsigned int _retries, tftp_err_t * _tftp_err, + int32_t _mode, int32_t _blocksize, int _ip_version) +{ + retries = _retries; + fn_ip = _fn_ip; + len = _len; + huge_load = _mode; + ip_version = _ip_version; + tftp_errno = 0; + tftp_err = _tftp_err; + tftp_err->bad_tftp_packets = 0; + tftp_err->no_packets = 0; + + /* Default blocksize must be 512 for TFTP servers + * which do not support the RRQ blocksize option */ + blocksize = 512; + + /* Prefered blocksize - used as option for the read request */ + if (_blocksize < 8) + _blocksize = 8; + else if (_blocksize > MAX_BLOCKSIZE) + _blocksize = MAX_BLOCKSIZE; + sprintf(blocksize_str, "%d", _blocksize); + + printf(" Receiving data: "); + print_progress(-1, 0); + + // Setting buffer to a non-zero address enabled handling of received TFTP packets. + buffer = _buffer; + + set_timer(TICKS_SEC); + send_rrq(); + + while (! tftp_finished) { + /* if timeout (no packet received) */ + if(get_timer() <= 0) { + /* the server doesn't seem to retry let's help out a bit */ + if (tftp_err->no_packets > 4 && port_number != -1 + && block > 1) + send_ack(block, port_number); + tftp_err->no_packets++; + set_timer(TICKS_SEC); + } + + /* handle received packets */ + receive_ether(); + + /* bad_tftp_packets are counted whenever we receive a TFTP packet + * which was not expected; if this gets larger than 'retries' + * we just exit */ + if (tftp_err->bad_tftp_packets > retries) { + tftp_errno = -40; + break; + } + + /* no_packets counts the times we have returned from receive_ether() + * without any packet received; if this gets larger than 'retries' + * we also just exit */ + if (tftp_err->no_packets > retries) { + tftp_errno = -41; + break; } } + + // Setting buffer to NULL disables handling of received TFTP packets. + buffer = NULL; + + if (tftp_errno) + return tftp_errno; + print_progress(-1, received_len); printf("\n"); if (lost_packets) printf("Lost ACK packets: %d\n", lost_packets); + return received_len; } - -int -tftp(int boot_device, filename_ip_t * fn_ip, unsigned char *buffer, int len, - unsigned int retries, tftp_err_t * tftp_err, int huge_load) -{ - return the_real_tftp(boot_device, fn_ip, buffer, len, retries, - tftp_err, huge_load); -} diff --git a/clients/net-snk/app/netlib/tftp.h b/clients/net-snk/app/netlib/tftp.h new file mode 100644 index 0000000..3f573b1 --- /dev/null +++ b/clients/net-snk/app/netlib/tftp.h @@ -0,0 +1,48 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + + +#ifndef _TFTP_H_ +#define _TFTP_H_ + +#include <types.h> +//#include <netlib/ipv6.h> + +struct tftphdr { + int16_t th_opcode; + uint16_t th_data; +}; + +typedef struct { + uint32_t own_ip; + //ip6_addr_t own_ip6; + uint32_t server_ip; + //ip6_addr_t server_ip6; + int8_t filename[256]; +} __attribute__ ((packed)) filename_ip_t ; + +typedef struct { + uint32_t bad_tftp_packets; + uint32_t no_packets; + uint32_t blocks_missed; + uint32_t blocks_received; +} tftp_err_t; + +int tftp(filename_ip_t *, unsigned char *, int, unsigned int, + tftp_err_t *, int32_t mode, int32_t blocksize, int ip_version); +int tftp_netsave(filename_ip_t *, uint8_t * buffer, int len, + int use_ci, unsigned int retries, tftp_err_t * tftp_err); + +int32_t handle_tftp(uint8_t *, int32_t); +void handle_tftp_dun(uint8_t err_code); + +#endif diff --git a/clients/net-snk/app/netlib/udp.c b/clients/net-snk/app/netlib/udp.c new file mode 100644 index 0000000..3bc20ef --- /dev/null +++ b/clients/net-snk/app/netlib/udp.c @@ -0,0 +1,153 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +/*>>>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<*/ + +#include <udp.h> +#include <sys/socket.h> +#include <dhcp.h> +//#include <dhcpv6.h> +#include <dns.h> +#ifdef USE_MTFTP +#include <mtftp.h> +#else +#include <tftp.h> +#endif + + + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/ + + +#ifdef USE_MTFTP + +uint16_t net_tftp_uport; +uint16_t net_mtftp_uport; + +void net_set_tftp_port(uint16_t tftp_port) { + net_tftp_uport = tftp_port; +} + +void net_set_mtftp_port(uint16_t tftp_port) { + net_mtftp_uport = tftp_port; +} + +#endif + +/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<*/ + + +/** + * NET: Handles UDP-packets according to Receive-handle diagram. + * + * @param udp_packet UDP-packet to be handled + * @param packetsize Length of the packet + * @return ZERO - packet handled successfully; + * NON ZERO - packet was not handled (e.g. bad format) + * @see receive_ether + * @see udphdr + */ +int8_t +handle_udp(uint8_t * udp_packet, int32_t packetsize) { + struct udphdr * udph = (struct udphdr *) udp_packet; + + if (packetsize < sizeof(struct udphdr)) + return -1; // packet is too small + + switch (htons(udph -> uh_dport)) { + case UDPPORT_BOOTPC: + if (udph -> uh_sport == htons(UDPPORT_BOOTPS)) + return handle_dhcp(udp_packet + sizeof(struct udphdr), + packetsize - sizeof(struct udphdr)); + else + return -1; + case UDPPORT_DNSC: + if (udph -> uh_sport == htons(UDPPORT_DNSS)) + return handle_dns(udp_packet + sizeof(struct udphdr), + packetsize - sizeof(struct udphdr)); + else + return -1; +/* + case UDPPORT_DHCPV6C: + return handle_dhcpv6(udp_packet+sizeof(struct udphdr), + packetsize - sizeof(struct udphdr)); +*/ + case UDPPORT_TFTPC: +#ifdef USE_MTFTP + return handle_tftp(udp_packet + sizeof(struct udphdr), + packetsize - sizeof(struct udphdr)); +#else + return handle_tftp(udp_packet, packetsize); +#endif + default: +#ifdef USE_MTFTP + if (htons(udph -> uh_dport) == net_tftp_uport) + return handle_tftp(udp_packet + sizeof(struct udphdr), + packetsize - sizeof(struct udphdr)); + else if (htons(udph -> uh_dport) == net_mtftp_uport) + return handle_tftp(udp_packet + sizeof(struct udphdr), + packetsize - sizeof(struct udphdr)); +#endif + return -1; + } +} + +/** + * NET: This function handles situation when "Destination unreachable" + * ICMP-error occurs during sending UDP-packet. + * + * @param err_code Error Code (e.g. "Host unreachable") + * @param packet original UDP-packet + * @param packetsize length of the packet + * @see handle_icmp + */ +void +handle_udp_dun(uint8_t * udp_packet, uint32_t packetsize, uint8_t err_code) { + struct udphdr * udph = (struct udphdr *) udp_packet; + + if (packetsize < sizeof(struct udphdr)) + return; // packet is too small + + switch (htons(udph -> uh_sport)) { + case UDPPORT_TFTPC: + handle_tftp_dun(err_code); + break; + } +} + +/** + * NET: Creates UDP-packet. Places UDP-header in a packet and fills it + * with corresponding information. + * <p> + * Use this function with similar functions for other network layers + * (fill_ethhdr, fill_iphdr, fill_dnshdr, fill_btphdr). + * + * @param packet Points to the place where UDP-header must be placed. + * @param packetsize Size of the packet in bytes incl. this hdr and data. + * @param src_port UDP source port + * @param dest_port UDP destination port + * @see udphdr + * @see fill_ethhdr + * @see fill_iphdr + * @see fill_dnshdr + * @see fill_btphdr + */ +void +fill_udphdr(uint8_t * packet, uint16_t packetsize, + uint16_t src_port, uint16_t dest_port) { + struct udphdr * udph = (struct udphdr *) packet; + + udph -> uh_sport = htons(src_port); + udph -> uh_dport = htons(dest_port); + udph -> uh_ulen = htons(packetsize); + udph -> uh_sum = htons(0); +} diff --git a/clients/net-snk/app/netlib/udp.h b/clients/net-snk/app/netlib/udp.h new file mode 100644 index 0000000..0432f52 --- /dev/null +++ b/clients/net-snk/app/netlib/udp.h @@ -0,0 +1,58 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 IBM Corporation + * All rights reserved. + * This program and the accompanying materials + * are made available under the terms of the BSD License + * which accompanies this distribution, and is available at + * http://www.opensource.org/licenses/bsd-license.php + * + * Contributors: + * IBM Corporation - initial implementation + *****************************************************************************/ + +#ifndef _UDP_H +#define _UDP_H + +#include <types.h> + +#define IPTYPE_UDP 17 + +#define UDPPORT_BOOTPS 67 /**< UDP port of BootP/DHCP-server */ +#define UDPPORT_BOOTPC 68 /**< UDP port of BootP/DHCP-client */ +#define UDPPORT_DNSS 53 /**< UDP port of DNS-server */ +#define UDPPORT_DNSC 32769 /**< UDP port of DNS-client */ +#define UDPPORT_TFTPC 2001 /**< UDP port of TFTP-client */ +#define UDPPORT_DHCPV6C 546 /**< UDP port of DHCPv6-client */ + +/** \struct udphdr + * A header for UDP-packets. + * For more information see RFC 768. + */ +struct udphdr { + uint16_t uh_sport; /**< Source port */ + uint16_t uh_dport; /**< Destinantion port */ + uint16_t uh_ulen; /**< Length in octets, incl. this header and data */ + uint16_t uh_sum; /**< Checksum */ +}; +typedef struct udphdr udp_hdr_t; + +typedef int32_t *(*handle_upper_udp_t)(uint8_t *, int32_t); +typedef void *(*handle_upper_udp_dun_t)(uint8_t); + +/* Handles UDP-packets that are detected by any network layer. */ +extern int8_t handle_udp(uint8_t * udp_packet, int32_t packetsize); + +/* Handles UDP related ICMP-Dest.Unreachable packets that are detected by + * the network layers. */ +extern void handle_udp_dun(uint8_t * udp_packet, uint32_t packetsize, uint8_t err_code); + +/* fills udp header */ +extern void fill_udphdr(uint8_t *packet, uint16_t packetsize, + uint16_t src_port, uint16_t dest_port); + +#ifdef USE_MTFTP +extern void net_set_tftp_port(uint16_t tftp_port); +extern void net_set_mtftp_port(uint16_t tftp_port); +#endif + +#endif |