aboutsummaryrefslogtreecommitdiff
path: root/clients/net-snk/app
diff options
context:
space:
mode:
Diffstat (limited to 'clients/net-snk/app')
-rw-r--r--clients/net-snk/app/Makefile17
-rw-r--r--clients/net-snk/app/biosemu/Makefile4
-rw-r--r--clients/net-snk/app/biosemu/biosemu.c267
-rw-r--r--clients/net-snk/app/biosemu/biosemu.h40
-rw-r--r--clients/net-snk/app/biosemu/debug.c4
-rw-r--r--clients/net-snk/app/biosemu/debug.h75
-rw-r--r--clients/net-snk/app/biosemu/device.c101
-rw-r--r--clients/net-snk/app/biosemu/device.h50
-rw-r--r--clients/net-snk/app/biosemu/interrupt.c375
-rw-r--r--clients/net-snk/app/biosemu/interrupt.h4
-rw-r--r--clients/net-snk/app/biosemu/io.c401
-rw-r--r--clients/net-snk/app/biosemu/io.h4
-rw-r--r--clients/net-snk/app/biosemu/mem.c212
-rw-r--r--clients/net-snk/app/biosemu/mem.h4
-rw-r--r--clients/net-snk/app/biosemu/vbe.c498
-rw-r--r--clients/net-snk/app/biosemu/vbe.h2
-rw-r--r--clients/net-snk/app/main.c23
-rw-r--r--clients/net-snk/app/netapps/Makefile2
-rw-r--r--clients/net-snk/app/netapps/args.c2
-rw-r--r--clients/net-snk/app/netapps/args.h2
-rw-r--r--clients/net-snk/app/netapps/netapps.h2
-rw-r--r--clients/net-snk/app/netapps/netboot.c303
-rw-r--r--clients/net-snk/app/netapps/netflash.c37
-rw-r--r--clients/net-snk/app/netapps/ping.c51
-rw-r--r--clients/net-snk/app/netlib/Makefile15
-rw-r--r--clients/net-snk/app/netlib/bootp.c93
-rw-r--r--clients/net-snk/app/netlib/dhcp.c131
-rw-r--r--clients/net-snk/app/netlib/dhcp.h41
-rw-r--r--clients/net-snk/app/netlib/dns.c67
-rw-r--r--clients/net-snk/app/netlib/dns.h11
-rw-r--r--clients/net-snk/app/netlib/ethernet.c186
-rw-r--r--clients/net-snk/app/netlib/ethernet.h47
-rw-r--r--clients/net-snk/app/netlib/ipv4.c871
-rw-r--r--clients/net-snk/app/netlib/ipv4.h96
-rw-r--r--clients/net-snk/app/netlib/tcp.c50
-rw-r--r--clients/net-snk/app/netlib/tcp.h27
-rw-r--r--clients/net-snk/app/netlib/tftp.c766
-rw-r--r--clients/net-snk/app/netlib/tftp.h48
-rw-r--r--clients/net-snk/app/netlib/udp.c153
-rw-r--r--clients/net-snk/app/netlib/udp.h58
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, &ethh->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 *) (&ether_packet[sizeof(struct ethhdr) +
+ btph = (struct btphdr *) (&ether_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(&ether_packet[sizeof(struct ethhdr) + sizeof(struct iphdr)],
+ fill_udphdr(&ether_packet[sizeof(struct iphdr)],
sizeof(struct btphdr) + sizeof(struct udphdr),
UDPPORT_BOOTPC, UDPPORT_BOOTPS);
- fill_iphdr(&ether_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(&ether_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 *) (&ether_packet[sizeof(struct ethhdr) +
+ btph = (struct btphdr *) (&ether_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(&ether_packet[sizeof(struct ethhdr) + sizeof(struct iphdr)],
+ fill_udphdr(&ether_packet[sizeof(struct iphdr)],
sizeof(struct btphdr) + sizeof(struct udphdr),
UDPPORT_BOOTPC, UDPPORT_BOOTPS);
- fill_iphdr(&ether_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(&ether_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 *) (&ether_packet[sizeof(struct ethhdr) +
+ btph = (struct btphdr *) (&ether_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(&ether_packet[sizeof(struct ethhdr) + sizeof(struct iphdr)],
+ fill_udphdr(&ether_packet[sizeof(struct iphdr)],
sizeof(struct btphdr) + sizeof(struct udphdr),
UDPPORT_BOOTPC, UDPPORT_BOOTPS);
- fill_iphdr(&ether_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(&ether_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(&ether_packet[sizeof(struct ethhdr) +
+ fill_dnshdr(&ether_packet[
sizeof(struct iphdr) + sizeof(struct udphdr)],
domain_name);
- fill_udphdr(&ether_packet[sizeof(struct ethhdr) +
+ fill_udphdr(&ether_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