aboutsummaryrefslogtreecommitdiff
path: root/clients
diff options
context:
space:
mode:
authorAdrian Reber <adrian@lisas.de>2008-11-21 12:45:38 +0100
committerAdrian Reber <adrian@lisas.de>2008-11-21 12:45:38 +0100
commit1015f69140c36be1c56653075636be60ca433a6d (patch)
tree23c81fb82a757758186b8ad9adab8f48badd3a16 /clients
parent07ec038eec68116cbfcc42b4eea568fd334e8c88 (diff)
downloadSLOF-slof-JX-1.4.0-0.zip
SLOF-slof-JX-1.4.0-0.tar.gz
SLOF-slof-JX-1.4.0-0.tar.bz2
imported slof-JX-1.4.0-0 releaseslof-JX-1.4.0-0
Diffstat (limited to 'clients')
-rw-r--r--clients/Makefile29
-rw-r--r--clients/clients.mk13
-rw-r--r--clients/net-snk/Makefile57
-rw-r--r--clients/net-snk/app/Makefile44
-rw-r--r--clients/net-snk/app/main.c65
-rw-r--r--clients/net-snk/app/netapps/Makefile29
-rw-r--r--clients/net-snk/app/netapps/args.c142
-rw-r--r--clients/net-snk/app/netapps/args.h22
-rw-r--r--clients/net-snk/app/netapps/netapps.h19
-rw-r--r--clients/net-snk/app/netapps/netboot.c502
-rw-r--r--clients/net-snk/app/netapps/netflash.c190
-rw-r--r--clients/net-snk/app/netapps/ping.c198
-rw-r--r--clients/net-snk/app/netlib/Makefile31
-rw-r--r--clients/net-snk/app/netlib/arp.c231
-rw-r--r--clients/net-snk/app/netlib/arp.h20
-rw-r--r--clients/net-snk/app/netlib/bootp.c254
-rw-r--r--clients/net-snk/app/netlib/dhcp.c1049
-rw-r--r--clients/net-snk/app/netlib/dhcp.h14
-rw-r--r--clients/net-snk/app/netlib/dns.c522
-rw-r--r--clients/net-snk/app/netlib/dns.h21
-rw-r--r--clients/net-snk/app/netlib/icmp.c98
-rw-r--r--clients/net-snk/app/netlib/icmp.h75
-rw-r--r--clients/net-snk/app/netlib/netbase.c451
-rw-r--r--clients/net-snk/app/netlib/netbase.h138
-rw-r--r--clients/net-snk/app/netlib/netlib.h146
-rw-r--r--clients/net-snk/app/netlib/tftp.c658
-rw-r--r--clients/net-snk/client.lds51
-rw-r--r--clients/net-snk/include/crt0.h20
-rw-r--r--clients/net-snk/include/endian.h46
-rw-r--r--clients/net-snk/include/fcntl.h25
-rw-r--r--clients/net-snk/include/ioctl.h19
-rw-r--r--clients/net-snk/include/kernel.h32
-rw-r--r--clients/net-snk/include/macros.h72
-rw-r--r--clients/net-snk/include/net.h30
-rw-r--r--clients/net-snk/include/netdriver_int.h119
-rw-r--r--clients/net-snk/include/of.h56
-rw-r--r--clients/net-snk/include/pci.h26
-rw-r--r--clients/net-snk/include/rtas.h45
-rw-r--r--clients/net-snk/include/socket.h25
-rw-r--r--clients/net-snk/include/sys/socket.h28
-rw-r--r--clients/net-snk/include/systemcall.h148
-rw-r--r--clients/net-snk/include/time.h36
-rw-r--r--clients/net-snk/include/types.h34
-rw-r--r--clients/net-snk/kernel/Makefile43
-rw-r--r--clients/net-snk/kernel/crt0.c74
-rw-r--r--clients/net-snk/kernel/driver/Makefile40
-rw-r--r--clients/net-snk/kernel/driver/net/Makefile38
-rw-r--r--clients/net-snk/kernel/driver/net/netmodule.c138
-rw-r--r--clients/net-snk/kernel/driver/net_support.c534
-rw-r--r--clients/net-snk/kernel/endian.c30
-rw-r--r--clients/net-snk/kernel/entry.S167
-rw-r--r--clients/net-snk/kernel/init.c175
-rw-r--r--clients/net-snk/kernel/lowmem.S186
-rw-r--r--clients/net-snk/kernel/systemcall.c171
-rw-r--r--clients/net-snk/kernel/timer.c67
-rw-r--r--clients/net-snk/libc/Makefile48
-rw-r--r--clients/net-snk/libc/io.c53
-rw-r--r--clients/net-snk/libc/ioctl.c20
-rw-r--r--clients/net-snk/libc/sbrk.c37
-rw-r--r--clients/net-snk/libc/socket/Makefile41
-rw-r--r--clients/net-snk/libc/socket/send.c36
-rw-r--r--clients/net-snk/libc/time/Makefile43
-rw-r--r--clients/net-snk/libc/time/ftime.c38
-rw-r--r--clients/net-snk/libc/time/timer.c39
-rw-r--r--clients/net-snk/make.depend36
-rw-r--r--clients/net-snk/make.rules43
-rw-r--r--clients/net-snk/oflib/Makefile41
-rw-r--r--clients/net-snk/oflib/entry.S37
-rw-r--r--clients/net-snk/oflib/of.c357
-rw-r--r--clients/net-snk/oflib/pci.c97
-rw-r--r--clients/net-snk/oflib/rtas.c334
-rw-r--r--clients/net-snk/sec-client.lds50
-rw-r--r--clients/takeover/Makefile60
-rw-r--r--clients/takeover/client.lds60
-rw-r--r--clients/takeover/entry.S93
-rw-r--r--clients/takeover/main.c157
-rw-r--r--clients/takeover/ppc32wrap.S30
-rw-r--r--clients/takeover/takeover.h23
78 files changed, 9266 insertions, 0 deletions
diff --git a/clients/Makefile b/clients/Makefile
new file mode 100644
index 0000000..3198176
--- /dev/null
+++ b/clients/Makefile
@@ -0,0 +1,29 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2007 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
+# ****************************************************************************/
+
+include clients.mk
+
+all:
+ for dir in $(CLIENTS); do \
+ if [ -r $$dir/Makefile ]; then \
+ $(MAKE) -C $$dir "FLAG=$(FLAG)" || exit 1; \
+ cp $$dir/client $$dir.client; \
+ fi; \
+ done
+
+clean distclean:
+ @for dir in $(CLIENTS); do \
+ if [ -r $$dir/Makefile ]; then \
+ $(MAKE) -C $$dir $@ || exit 1; \
+ rm -f $$dir.client; \
+ fi; \
+ done
diff --git a/clients/clients.mk b/clients/clients.mk
new file mode 100644
index 0000000..45a8534
--- /dev/null
+++ b/clients/clients.mk
@@ -0,0 +1,13 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2007 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
+# ****************************************************************************/
+
+CLIENTS = net-snk
diff --git a/clients/net-snk/Makefile b/clients/net-snk/Makefile
new file mode 100644
index 0000000..4636cec
--- /dev/null
+++ b/clients/net-snk/Makefile
@@ -0,0 +1,57 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2007 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
+# ****************************************************************************/
+
+TOP=$(shell pwd)
+export TOP
+include $(TOP)/make.rules
+
+OBJS = kernel/kernel.o oflib/oflib.o libc/libc-glue.o app/app.o
+.PHONY : subdirs clean depend mrproper
+
+client : subdirs $(OBJS) $(LIBCMNDIR)/libc.a
+ $(LD) $(LDFLAGS) -o $@ -Tclient.lds $(OBJS) $(LIBCMNDIR)/libc.a
+ $(OBJDUMP) -DSsx $@ > $@.dis
+ cp $@ $@.unstripped
+ $(STRIP) $@
+
+sec-client : subdirs $(OBJS) $(LIBCMNDIR)/libc.a
+ $(LD) $(LDFLAGS) -o $@ -Tsec-client.lds $(OBJS) $(LIBCMNDIR)/libc.a
+
+subdirs :
+ @for dir in $(dir $(OBJS)); do \
+ $(MAKE) -C $$dir || exit 1; \
+ done
+
+$(LIBCMNDIR)/libc.a:
+ $(MAKE) -C $(LIBCMNDIR) libc
+
+clean:
+ @for dir in $(dir $(OBJS)); do \
+ $(MAKE) -C $$dir clean; \
+ done
+ rm -f $(OBJS) client diag netboot sec-client net-diag \
+ *.dis client.unstripped
+
+mrproper : clean
+ $(MAKE) -C app mrproper
+ $(MAKE) -C libc mrproper
+ $(MAKE) -C kernel mrproper
+ $(MAKE) -C oflib mrproper
+ find -name .*.bak | xargs rm -rf
+
+distclean: mrproper
+
+depend :
+ $(MAKE) -C app depend
+ $(MAKE) -C libc depend
+ $(MAKE) -C kernel depend
+ $(MAKE) -C oflib depend
diff --git a/clients/net-snk/app/Makefile b/clients/net-snk/app/Makefile
new file mode 100644
index 0000000..aa768fc
--- /dev/null
+++ b/clients/net-snk/app/Makefile
@@ -0,0 +1,44 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2007 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 TOP
+TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd)
+export TOP
+endif
+include $(TOP)/make.rules
+
+CFLAGS +=$(ADDCFLAGS)
+
+OBJS = main.o
+OBJDIRS = netlib/netlib.o netapps/netboot.o
+OBJDIRS += netapps/netflash.o
+OBJDIRS += netapps/ping.o
+OBJDIRS += netapps/args.o
+
+all: app.o
+
+subdirs:
+ for dir in $(dir $(OBJDIRS)); do \
+ $(MAKE) -C $$dir DIRECTORY=$(DIRECTORY)$$dir || exit 1; \
+ done
+
+app.o: subdirs $(OBJS)
+ $(LD) $(LDFLAGS) $(OBJDIRS) $(OBJS) -o $@ -r
+
+clean :
+ $(RM) -f *.o *.a *.i
+ for dir in $(dir $(OBJDIRS)); do \
+ $(CLEAN) ; \
+ $(MAKE) -C $$dir DIRECTORY=$(DIRECTORY)$$dir clean; \
+ done
+
+include $(TOP)/make.depend
diff --git a/clients/net-snk/app/main.c b/clients/net-snk/app/main.c
new file mode 100644
index 0000000..a9dc0f9
--- /dev/null
+++ b/clients/net-snk/app/main.c
@@ -0,0 +1,65 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include <of.h>
+#include <netapps/netapps.h>
+#include <libbootmsg.h>
+
+extern void _callback_entry(void);
+
+int
+main(int argc, char *argv[])
+{
+ int i;
+ of_set_callback((void *) &_callback_entry);
+
+ if (strcmp(argv[0], "netboot") == 0 && argc >= 3)
+ return netboot(argc, argv);
+ if (strcmp(argv[0], "netflash") == 0)
+ return netflash(argc, argv);
+ if (strcmp(argv[0], "ping") == 0)
+ return ping(argc, argv);
+
+ printf("Unknown client application called\n");
+ for (i = 0; i < argc; i++)
+ printf("argv[%d] %s\n", i, argv[i]);
+
+ return -1;
+}
+
+int
+callback(int argc, char *argv[])
+{
+ int i;
+
+ printf("\n");
+
+ /*
+ * Register your application's callback handler here, similar to
+ * the way you would register an application.
+ * Please note that callback functions can be called safely only after
+ * your application has called of_yield(). If you return or exit() from
+ * your client application, the callback can no longer be used.
+ */
+#if 0
+ if (strcmp(argv[0], "example") == 0)
+ return example(argc, argv);
+#endif
+
+ printf("No such callback function\n");
+ for (i = 0; i < argc; i++)
+ printf("argv[%d] %s\n", i, argv[i]);
+
+ return (-1);
+}
diff --git a/clients/net-snk/app/netapps/Makefile b/clients/net-snk/app/netapps/Makefile
new file mode 100644
index 0000000..9882a18
--- /dev/null
+++ b/clients/net-snk/app/netapps/Makefile
@@ -0,0 +1,29 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2007 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 TOP
+ TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd)
+ export TOP
+endif
+include $(TOP)/make.rules
+
+CFLAGS += -I../ -I../../../../lib/ -Wall -W
+OBJS = netboot.o netflash.o
+OBJS += ping.o
+OBJS += args.o
+
+all: $(OBJS)
+
+clean:
+ $(RM) -f *.o *.a *.i
+
+include $(TOP)/make.depend
diff --git a/clients/net-snk/app/netapps/args.c b/clients/net-snk/app/netapps/args.c
new file mode 100644
index 0000000..ac71342
--- /dev/null
+++ b/clients/net-snk/app/netapps/args.c
@@ -0,0 +1,142 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+#include <types.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+/**
+ * Returns pointer of the n'th argument within a string.
+ *
+ * @param arg_str string with arguments, seperated with ','
+ * @param index index of the requested arguments whithin arg_str
+ * @return pointer of argument[index] on success
+ * NULL if index is out of range
+ */
+const char *
+get_arg_ptr(const char *arg_str, unsigned int index)
+{
+ unsigned int i;
+
+ for (i = 0; i < index; ++i) {
+ for (; *arg_str != ',' && *arg_str != 0; ++arg_str);
+ if (*arg_str == 0)
+ return 0;
+ ++arg_str;
+ }
+ return arg_str;
+}
+
+/**
+ * Returns number of arguments within a string.
+ *
+ * @param arg_str string with arguments, seperated with ','
+ * @return number of arguments
+ */
+unsigned int
+get_args_count(const char *arg_str)
+{
+ unsigned int count = 1;
+
+ while ((arg_str = get_arg_ptr(arg_str, 1)) != 0)
+ ++count;
+ return count;
+}
+
+/**
+ * Returns the length of the first argument.
+ *
+ * @param arg_str string with arguments, seperated with ','
+ * @return length of first argument
+ */
+unsigned int
+get_arg_length(const char *arg_str)
+{
+ unsigned int i;
+
+ for (i = 0; *arg_str != ',' && *arg_str != 0; ++i)
+ ++arg_str;
+ return i;
+}
+
+/**
+ * Copy the n'th argument within a string into a buffer in respect
+ * to a limited buffer size
+ *
+ * @param arg_str string with arguments, seperated with ','
+ * @param index index of the requested arguments whithin arg_str
+ * @param buffer pointer to the buffer
+ * @param length size of the buffer
+ * @return pointer of buffer on success
+ * NULL if index is out of range.
+ */
+char *
+argncpy(const char *arg_str, unsigned int index, char *buffer,
+ unsigned int length)
+{
+ const char *ptr = get_arg_ptr(arg_str, index);
+ unsigned int len;
+
+ if (!ptr)
+ return 0;
+ len = get_arg_length(ptr);
+ if (!strncpy(buffer, ptr, length))
+ return 0;
+ buffer[len] = 0;
+ return buffer;
+}
+
+/**
+ * Converts "255.255.255.255" -> char[4] = { 0xff, 0xff, 0xff, 0xff }
+ *
+ * @param str string to be converted
+ * @param ip in case of SUCCESS - 32-bit long IP
+ in case of FAULT - zero
+ * @return TRUE - IP converted successfully;
+ * FALSE - error condition occurs (e.g. bad format)
+ */
+int
+strtoip(const char *str, char ip[4])
+{
+ char octet[10];
+ int res;
+ unsigned int i = 0, len;
+
+ while (*str != 0) {
+ if (i > 3 || !isdigit(*str))
+ return 0;
+ if (strstr(str, ".") != NULL) {
+ len = (int16_t) (strstr(str, ".") - str);
+ if (len >= 10)
+ return 0;
+ strncpy(octet, str, len);
+ octet[len] = 0;
+ str += len;
+ } else {
+ strncpy(octet, str, 9);
+ octet[9] = 0;
+ str += strlen(octet);
+ }
+ res = strtol(octet, NULL, 10);
+ if ((res > 255) || (res < 0))
+ return 0;
+ ip[i] = (char) res;
+ i++;
+ if (*str == '.')
+ str++;
+ }
+
+ if (i != 4)
+ return 0;
+ return -1;
+}
diff --git a/clients/net-snk/app/netapps/args.h b/clients/net-snk/app/netapps/args.h
new file mode 100644
index 0000000..99c1c78
--- /dev/null
+++ b/clients/net-snk/app/netapps/args.h
@@ -0,0 +1,22 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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 _ARGS_H
+#define _ARGS_H
+
+const char *get_arg_ptr(const char *, unsigned int);
+unsigned int get_args_count(const char *);
+unsigned int get_arg_length(const char *);
+char *argncpy(const char *, unsigned int, char *, unsigned int);
+int strtoip(const char *, char[4]);
+
+#endif /* _ARGS_H */
diff --git a/clients/net-snk/app/netapps/netapps.h b/clients/net-snk/app/netapps/netapps.h
new file mode 100644
index 0000000..836edd4
--- /dev/null
+++ b/clients/net-snk/app/netapps/netapps.h
@@ -0,0 +1,19 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+int netboot(int argc, char *argv[]);
+int netsave(int argc, char *argv[]);
+int netflash(int argc, char *argv[]);
+int bcmflash(int argc, char *argv[]);
+int mac_sync(int argc, char *argv[]);
+int net_eeprom_version( void );
+int ping(int argc, char *argv[]);
diff --git a/clients/net-snk/app/netapps/netboot.c b/clients/net-snk/app/netapps/netboot.c
new file mode 100644
index 0000000..07a1392
--- /dev/null
+++ b/clients/net-snk/app/netapps/netboot.c
@@ -0,0 +1,502 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+#include <netlib/netlib.h>
+#include <netlib/netbase.h>
+#include <netlib/icmp.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.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 DEFAULT_BOOT_RETRIES 600
+#define DEFAULT_TFTP_RETRIES 20
+
+typedef struct {
+ int ip_init;
+ char siaddr[4];
+ char filename[100];
+ char ciaddr[4];
+ char giaddr[4];
+ 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
+ *
+ * @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];
+ char *ptr;
+
+ 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
+ obp_tftp_args->ip_init = IP_INIT_DEFAULT;
+ }
+
+ // find out siaddr
+ if(argc==0)
+ memset(obp_tftp_args->siaddr, 0, 4);
+ else {
+ argncpy(arg_str, 0, arg_buf, 100);
+ if(strtoip(arg_buf, obp_tftp_args->siaddr)) {
+ arg_str = get_arg_ptr(arg_str, 1);
+ --argc;
+ }
+ else if(arg_buf[0] == 0) {
+ memset(obp_tftp_args->siaddr, 0, 4);
+ arg_str = get_arg_ptr(arg_str, 1);
+ --argc;
+ }
+ else
+ memset(obp_tftp_args->siaddr, 0, 4);
+ }
+
+ // 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->ciaddr, 0, 4);
+ else {
+ argncpy(arg_str, 0, arg_buf, 100);
+ if(strtoip(arg_buf, obp_tftp_args->ciaddr)) {
+ arg_str = get_arg_ptr(arg_str, 1);
+ --argc;
+ }
+ else if(arg_buf[0] == 0) {
+ memset(obp_tftp_args->ciaddr, 0, 4);
+ arg_str = get_arg_ptr(arg_str, 1);
+ --argc;
+ }
+ else
+ memset(obp_tftp_args->ciaddr, 0, 4);
+ }
+
+ // find out giaddr
+ if(argc==0)
+ memset(obp_tftp_args->giaddr, 0, 4);
+ else {
+ argncpy(arg_str, 0, arg_buf, 100);
+ if(strtoip(arg_buf, obp_tftp_args->giaddr)) {
+ arg_str = get_arg_ptr(arg_str, 1);
+ --argc;
+ }
+ else if(arg_buf[0] == 0) {
+ memset(obp_tftp_args->giaddr, 0, 4);
+ arg_str = get_arg_ptr(arg_str, 1);
+ --argc;
+ }
+ else
+ memset(obp_tftp_args->giaddr, 0, 4);
+ }
+
+ // find out bootp-retries
+ if(argc==0)
+ obp_tftp_args->bootp_retries = DEFAULT_BOOT_RETRIES;
+ else {
+ argncpy(arg_str, 0, arg_buf, 100);
+ if(arg_buf[0] == 0)
+ obp_tftp_args->bootp_retries = DEFAULT_BOOT_RETRIES;
+ else {
+ obp_tftp_args->bootp_retries = strtol(arg_buf, 0, 10);
+ if(obp_tftp_args->bootp_retries < 0)
+ obp_tftp_args->bootp_retries = DEFAULT_BOOT_RETRIES;
+ }
+ arg_str = get_arg_ptr(arg_str, 1);
+ --argc;
+ }
+
+ // find out tftp-retries
+ if(argc==0)
+ obp_tftp_args->tftp_retries = DEFAULT_TFTP_RETRIES;
+ else {
+ argncpy(arg_str, 0, arg_buf, 100);
+ if(arg_buf[0] == 0)
+ obp_tftp_args->tftp_retries = DEFAULT_TFTP_RETRIES;
+ else {
+ obp_tftp_args->tftp_retries = strtol(arg_buf, 0, 10);
+ if(obp_tftp_args->tftp_retries < 0)
+ obp_tftp_args->tftp_retries = DEFAULT_TFTP_RETRIES;
+ }
+ arg_str = get_arg_ptr(arg_str, 1);
+ --argc;
+ }
+}
+
+int
+netboot(int argc, char *argv[])
+{
+ char buf[256];
+ int rc;
+ int len = strtol(argv[2], 0, 16);
+ char *buffer = (char *) strtol(argv[1], 0, 16);
+ filename_ip_t fn_ip;
+ int fd_device;
+ tftp_err_t tftp_err;
+ obp_tftp_args_t obp_tftp_args;
+ char null_ip[4] = { 0x00, 0x00, 0x00, 0x00 };
+
+ printf("\n");
+ printf(" Bootloader 1.5 \n");
+ memset(&fn_ip, 0, sizeof(filename_ip_t));
+
+ /***********************************************************
+ *
+ * Initialize network stuff and retrieve boot informations
+ *
+ ***********************************************************/
+
+ /* Wait for link up and get mac_addr from device */
+ for(rc=0; rc<DEFAULT_BOOT_RETRIES; ++rc) {
+ if(rc > 0) {
+ set_timer(TICKS_SEC);
+ while (get_timer() > 0);
+ }
+ fd_device = socket(0, 0, 0, (char *) fn_ip.own_mac);
+ if(fd_device != -2)
+ break;
+ if(getchar() == 27) {
+ fd_device = -2;
+ break;
+ }
+ }
+
+ if (fd_device == -1) {
+ strcpy(buf,"E3000: (net) Could not read MAC address");
+ bootmsg_error(0x3000, &buf[7]);
+
+ write_mm_log(buf, strlen(buf), 0x91);
+ return -100;
+ }
+ else if (fd_device == -2) {
+ strcpy(buf,"E3006: (net) Could not initialize network device");
+ bootmsg_error(0x3006, &buf[7]);
+
+ write_mm_log(buf, strlen(buf), 0x91);
+ return -101;
+ }
+
+ 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]);
+
+ if (argc >= 4) {
+ parse_args(argv[3], &obp_tftp_args);
+ if(obp_tftp_args.bootp_retries - rc < DEFAULT_BOOT_RETRIES)
+ obp_tftp_args.bootp_retries = DEFAULT_BOOT_RETRIES;
+ else
+ obp_tftp_args.bootp_retries -= rc;
+ }
+ else {
+ memset(&obp_tftp_args, 0, sizeof(obp_tftp_args_t));
+ obp_tftp_args.ip_init = IP_INIT_DEFAULT;
+ obp_tftp_args.bootp_retries = DEFAULT_BOOT_RETRIES;
+ obp_tftp_args.tftp_retries = DEFAULT_TFTP_RETRIES;
+ }
+ 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
+ obp_tftp_args.ip_init = IP_INIT_NONE;
+ }
+ 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;
+ }
+ }
+ }
+
+ // construction of fn_ip from parameter
+ switch(obp_tftp_args.ip_init) {
+ case IP_INIT_BOOTP:
+ printf(" Requesting IP address via BOOTP: ");
+ // if giaddr in not specified, then we have to identify
+ // the BOOTP server via broadcasts
+ 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, &fn_ip, obp_tftp_args.bootp_retries);
+ break;
+ case IP_INIT_DHCP:
+ printf(" Requesting IP address via DHCP: ");
+ rc = dhcp(fd_device, &fn_ip, obp_tftp_args.bootp_retries);
+ break;
+ case IP_INIT_NONE:
+ default:
+ break;
+ }
+
+ if(rc >= 0) {
+ 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);
+
+ if(memcmp(obp_tftp_args.siaddr, null_ip, 4) != 0
+ && 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;
+ }
+ }
+
+ if (rc == -1) {
+ strcpy(buf,"E3001: (net) Could not get IP address");
+ bootmsg_error(0x3001, &buf[7]);
+
+ write_mm_log(buf, strlen(buf), 0x91);
+ return -101;
+ }
+
+ printf("%d.%d.%d.%d\n",
+ ((fn_ip.own_ip >> 24) & 0xFF), ((fn_ip.own_ip >> 16) & 0xFF),
+ ((fn_ip.own_ip >> 8) & 0xFF), ( fn_ip.own_ip & 0xFF));
+
+ if (rc == -2) {
+ sprintf(buf,
+ "E3002: (net) ARP request to TFTP server "
+ "(%d.%d.%d.%d) failed",
+ ((fn_ip.server_ip >> 24) & 0xFF),
+ ((fn_ip.server_ip >> 16) & 0xFF),
+ ((fn_ip.server_ip >> 8) & 0xFF),
+ ( fn_ip.server_ip & 0xFF));
+ bootmsg_error(0x3002, &buf[7]);
+
+ write_mm_log(buf, strlen(buf), 0x91);
+ return -102;
+ }
+ if (rc == -4 || rc == -3) {
+ strcpy(buf,"E3008: (net) Can't obtain TFTP server IP address");
+ bootmsg_error(0x3008, &buf[7]);
+
+ write_mm_log(buf, strlen(buf), 0x91);
+ return -107;
+ }
+
+
+ /***********************************************************
+ *
+ * Load file via TFTP into buffer provided by OpenFirmware
+ *
+ ***********************************************************/
+
+ if (obp_tftp_args.filename[0] != 0) {
+ strncpy((char *) fn_ip.filename, obp_tftp_args.filename, sizeof(fn_ip.filename)-1);
+ fn_ip.filename[sizeof(fn_ip.filename)-1] = 0;
+ }
+
+ printf(" Requesting file \"%s\" via TFTP\n", fn_ip.filename);
+
+ // 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);
+
+ if(obp_tftp_args.ip_init == IP_INIT_DHCP)
+ dhcp_send_release();
+
+ if (rc > 0) {
+ printf(" TFTP: Received %s (%d KBytes)\n", fn_ip.filename,
+ rc / 1024);
+ } else if (rc == -1) {
+ bootmsg_error(0x3003, "(net) unknown TFTP error");
+ return -103;
+ } else if (rc == -2) {
+ sprintf(buf,
+ "E3004: (net) TFTP buffer of %d bytes "
+ "is too small for %s",
+ len, fn_ip.filename);
+ bootmsg_error(0x3004, &buf[7]);
+
+ write_mm_log(buf, strlen(buf), 0x91);
+ return -104;
+ } else if (rc == -3) {
+ sprintf(buf,"E3009: (net) file not found: %s",
+ fn_ip.filename);
+ bootmsg_error(0x3009, &buf[7]);
+
+ write_mm_log(buf, strlen(buf), 0x91);
+ return -108;
+ } else if (rc == -4) {
+ strcpy(buf,"E3010: (net) TFTP access violation");
+ bootmsg_error(0x3010, &buf[7]);
+
+ write_mm_log(buf, strlen(buf), 0x91);
+ return -109;
+ } else if (rc == -5) {
+ strcpy(buf,"E3011: (net) illegal TFTP operation");
+ bootmsg_error(0x3011, &buf[7]);
+
+ write_mm_log(buf, strlen(buf), 0x91);
+ return -110;
+ } else if (rc == -6) {
+ strcpy(buf, "E3012: (net) unknown TFTP transfer ID");
+ bootmsg_error(0x3012, &buf[7]);
+
+ write_mm_log(buf, strlen(buf), 0x91);
+ return -111;
+ } else if (rc == -7) {
+ strcpy(buf, "E3013: (net) no such TFTP user");
+ bootmsg_error(0x3013, &buf[7]);
+
+ write_mm_log(buf, strlen(buf), 0x91);
+ return -112;
+ } else if (rc == -8) {
+ strcpy(buf, "E3017: (net) TFTP blocksize negotiation failed");
+ bootmsg_error(0x3017, &buf[7]);
+
+ write_mm_log(buf, strlen(buf), 0x91);
+ return -116;
+ } else if (rc == -9) {
+ strcpy(buf,"E3018: (net) file exceeds maximum TFTP transfer size");
+ bootmsg_error(0x3018, &buf[7]);
+
+ write_mm_log(buf, strlen(buf), 0x91);
+ return -117;
+ } else if (rc <= -10 && rc >= -15) {
+ sprintf(buf,"E3005: (net) ICMP ERROR \"");
+ switch (rc) {
+ case -ICMP_NET_UNREACHABLE - 10:
+ sprintf(buf+strlen(buf),"net unreachable");
+ break;
+ case -ICMP_HOST_UNREACHABLE - 10:
+ sprintf(buf+strlen(buf),"host unreachable");
+ break;
+ case -ICMP_PROTOCOL_UNREACHABLE - 10:
+ sprintf(buf+strlen(buf),"protocol unreachable");
+ break;
+ case -ICMP_PORT_UNREACHABLE - 10:
+ sprintf(buf+strlen(buf),"port unreachable");
+ break;
+ case -ICMP_FRAGMENTATION_NEEDED - 10:
+ sprintf(buf+strlen(buf),"fragmentation needed and DF set");
+ break;
+ case -ICMP_SOURCE_ROUTE_FAILED - 10:
+ sprintf(buf+strlen(buf),"source route failed");
+ break;
+ default:
+ sprintf(buf+strlen(buf)," UNKNOWN");
+ break;
+ }
+ sprintf(buf+strlen(buf),"\"");
+ bootmsg_error(0x3005, &buf[7]);
+
+ write_mm_log(buf, strlen(buf), 0x91);
+ return -105;
+ } else if (rc == -40) {
+ sprintf(buf,
+ "E3014: (net) TFTP error occurred after "
+ "%d bad packets received",
+ tftp_err.bad_tftp_packets);
+ bootmsg_error(0x3014, &buf[7]);
+ write_mm_log(buf, strlen(buf), 0x91);
+ return -113;
+ } else if (rc == -41) {
+ sprintf(buf,
+ "E3015: (net) TFTP error occurred after "
+ "missing %d responses",
+ tftp_err.no_packets);
+ bootmsg_error(0x3015, &buf[7]);
+ write_mm_log(buf, strlen(buf), 0x91);
+ return -114;
+ } else if (rc == -42) {
+ sprintf(buf,
+ "E3016: (net) TFTP error missing block %d, "
+ "expected block was %d",
+ tftp_err.blocks_missed,
+ tftp_err.blocks_received);
+ bootmsg_error(0x3016, &buf[7]);
+ write_mm_log(buf, strlen(buf), 0x91);
+ return -115;
+ }
+ return rc;
+}
diff --git a/clients/net-snk/app/netapps/netflash.c b/clients/net-snk/app/netapps/netflash.c
new file mode 100644
index 0000000..351fdda
--- /dev/null
+++ b/clients/net-snk/app/netapps/netflash.c
@@ -0,0 +1,190 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+#include <netlib/netlib.h>
+#include <netlib/netbase.h>
+#include <netlib/icmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <string.h>
+
+#include <rtas.h>
+
+int netflash(int argc, char * argv[])
+{
+ char buf[256];
+ int rc;
+ int manage_mode = 0;
+ static int len = 0x800000; //max flash size
+ char * buffer = NULL;
+ short arp_failed = 0;
+ filename_ip_t fn_ip;
+ int fd_device;
+ tftp_err_t tftp_err;
+ char * ptr;
+
+ printf("\n Flasher 1.4 \n");
+ memset(&fn_ip, 0, sizeof(filename_ip_t));
+
+ if (argc == 3 && argv[2][0] == '-' && argv[2][1] == 'c' && argv[2][2] == 0)
+ manage_mode = 1;
+ else if (argc == 3 &&
+ argv[2][0] == '-' && argv[2][1] == 'r' && argv[2][2] == 0)
+ manage_mode = 1;
+ else if (argc == 4 &&
+ argv[2][0] == '-' && argv[2][1] == 'f' && argv[2][2] == 0)
+ {
+ manage_mode = 0;
+ buffer = (char *)strtol(argv[1],0,16);
+ if ((long)buffer == -1) {
+ printf(" Bad buffer address. Exiting...\n");
+ return -1;
+ }
+ }
+ else
+ {
+ printf(" Usage: netflash [options] [<filename>]\n");
+ printf(" Options:\n");
+ printf(" -f <filename> flash temporary image\n");
+ printf(" -c commit temporary image\n");
+ printf(" -r reject temporary image\n");
+ printf(" Bad arguments. Exiting...\n\n");
+ return -1;
+ }
+
+ if (manage_mode == 1) {
+ if (argv[2][1] == 99)
+ return rtas_ibm_manage_flash(1);
+ else
+ return rtas_ibm_manage_flash(0);
+ }
+
+ /* Get mac_addr from device */
+ printf(" Reading MAC address from device: ");
+ fd_device = socket(0, 0, 0, (char *) fn_ip.own_mac);
+ if (fd_device == -1) {
+ printf("\nE3000: Could not read MAC address\n");
+ return -100;
+ }
+ else if (fd_device == -2) {
+ printf("\nE3006: Could not initialize network device\n");
+ return -101;
+ }
+
+ 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]);
+
+ // 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;
+ // memset(fn_ip.server_mac, 0xff, 6);
+
+ /* Get ip address for our mac address */
+ printf(" Requesting IP address via DHCP: ");
+ arp_failed = dhcp(fd_device, &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;
+ }
+ }
+
+ if (arp_failed == -1) {
+ printf("\n DHCP: Could not get ip address\n");
+ return 1;
+ }
+
+ if (arp_failed == -2) {
+ sprintf
+ (buf,"\n ARP request to TFTP server (%d.%d.%d.%d) failed",
+ ((fn_ip.server_ip >> 24) & 0xFF), ((fn_ip.server_ip >> 16) & 0xFF),
+ ((fn_ip.server_ip >> 8) & 0xFF), ( fn_ip.server_ip & 0xFF));
+ return 1;
+ }
+
+ printf("%d.%d.%d.%d\n",
+ ((fn_ip.own_ip >> 24) & 0xFF), ((fn_ip.own_ip >> 16) & 0xFF),
+ ((fn_ip.own_ip >> 8) & 0xFF), (fn_ip.own_ip & 0xFF));
+
+ /* Load file via TFTP into buffer provided by OpenFirmware */
+
+ for(ptr = argv[3]; *ptr != 0; ++ptr)
+ if(*ptr == '\\')
+ *ptr = '/';
+
+ printf(" Requesting file \"%s\" via TFTP\n",argv[3]);
+
+ strcpy((char *) fn_ip.filename,argv[3]);
+
+ rc = tftp (fd_device, &fn_ip, (unsigned char *) buffer, len, 20, &tftp_err);
+
+ dhcp_send_release();
+
+ if (rc > 0)
+ {
+ printf (" TFTP: Received %s (%d KBytes)\n", fn_ip.filename, rc/1024);
+ printf (" Now flashing:\n");
+ rc = rtas_ibm_update_flash_64((long long)buffer, rc);
+ return rc;
+ }
+ else if (rc == -1)
+ {
+ printf (" Tftp: Could not load file %s\n", fn_ip.filename);
+ return 1;
+ }
+ else if (rc == -2)
+ {
+ printf (" Tftp: Buffer to small for %s\n", fn_ip.filename);
+ return 1;
+ }
+ else if (rc <= -10 && rc >= -15)
+ {
+ printf("\n ICMP ERROR: Destination unreachable: ");
+ switch(rc) {
+ case -ICMP_NET_UNREACHABLE-10:
+ printf("net unreachable");
+ break;
+ case -ICMP_HOST_UNREACHABLE-10:
+ printf("host unreachable");
+ break;
+ case -ICMP_PROTOCOL_UNREACHABLE-10:
+ printf("protocol unreachable");
+ break;
+ case -ICMP_PORT_UNREACHABLE-10:
+ printf("port unreachable");
+ break;
+ case -ICMP_FRAGMENTATION_NEEDED-10:
+ printf("fragmentation needed and DF set");
+ break;
+ case -ICMP_SOURCE_ROUTE_FAILED-10:
+ printf("source route failed");
+ break;
+ default:
+ printf(" UNKNOWN: this should not happen!");
+ break;
+ }
+ printf("\n");
+ return 1;
+ }
+ else if(rc < 0)
+ printf(" UNKNOWN: rc = %d!", rc);
+
+ return 0;
+}
diff --git a/clients/net-snk/app/netapps/ping.c b/clients/net-snk/app/netapps/ping.c
new file mode 100644
index 0000000..2194768
--- /dev/null
+++ b/clients/net-snk/app/netapps/ping.c
@@ -0,0 +1,198 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+#include <netlib/icmp.h>
+#include <netlib/arp.h>
+#include <netlib/netlib.h>
+#include <sys/socket.h>
+#include <netlib/netbase.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <netapps/args.h>
+
+struct ping_args {
+ union {
+ char string[4];
+ unsigned int integer;
+ } server_ip;
+ union {
+ char string[4];
+ unsigned int integer;
+ } client_ip;
+ union {
+ char string[4];
+ unsigned int integer;
+ } gateway_ip;
+ unsigned int timeout;
+};
+
+static void
+usage()
+{
+ printf
+ ("\nping device-path:[device-args,]server-ip,[client-ip],[gateway-ip][,timeout]\n");
+
+}
+
+static int
+parse_args(const char *args, struct ping_args *ping_args)
+{
+ unsigned int argc = get_args_count(args);
+ char buf[64];
+ ping_args->timeout = 10;
+ if (argc == 0)
+ /* at least server-ip has to be specified */
+ return -1;
+ if (argc == 1) {
+ /* probably only server ip is specified */
+ argncpy(args, 0, buf, 64);
+ if (!strtoip(buf, ping_args->server_ip.string))
+ return -1;
+ return 0;
+ }
+ /* get first option from list */
+ argncpy(args, 0, buf, 64);
+ if (!strtoip(buf, ping_args->server_ip.string)) {
+ /* it is not an IP address
+ * therefore it has to be device-args
+ * device-args are not supported and just ignored */
+ args = get_arg_ptr(args, 1);
+ argc--;
+ }
+
+ argncpy(args, 0, buf, 64);
+ if (!strtoip(buf, ping_args->server_ip.string)) {
+ /* this should have been the server IP address */
+ return -1;
+ } else {
+ args = get_arg_ptr(args, 1);
+ if (!--argc)
+ return 0;
+ }
+
+ argncpy(args, 0, buf, 64);
+ if (!strtoip(buf, ping_args->client_ip.string)) {
+ /* this should have been the client (our) IP address */
+ return -1;
+ } else {
+ args = get_arg_ptr(args, 1);
+ if (!--argc)
+ return 0;
+ }
+ argncpy(args, 0, buf, 64);
+ if (!strtoip(buf, ping_args->gateway_ip.string)) {
+ /* this should have been the gateway IP address */
+ return -1;
+ } else {
+ args = get_arg_ptr(args, 1);
+ if (!--argc)
+ return 0;
+ }
+ argncpy(args, 0, buf, 64);
+ ping_args->timeout = strtol(args, 0, 10);
+ return 0;
+}
+
+int
+ping(int argc, char *argv[])
+{
+ short arp_failed = 0;
+ filename_ip_t fn_ip;
+ int fd_device;
+ struct ping_args ping_args;
+
+ memset(&ping_args, 0, sizeof(struct ping_args));
+
+ if (argc == 2) {
+ if (parse_args(argv[1], &ping_args)) {
+ usage();
+ return -1;
+ }
+ } else {
+ usage();
+ return -1;
+ }
+
+ memset(&fn_ip, 0, sizeof(filename_ip_t));
+
+ /* Get mac_addr from device */
+ printf("\n Reading MAC address from device: ");
+ fd_device = socket(0, 0, 0, (char *) fn_ip.own_mac);
+ if (fd_device == -1) {
+ printf("\nE3000: Could not read MAC address\n");
+ return -100;
+ } else if (fd_device == -2) {
+ printf("\nE3006: Could not initialize network device\n");
+ return -101;
+ }
+
+ 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]);
+
+ // 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;
+ // memset(fn_ip.server_mac, 0xff, 6);
+
+ if (!ping_args.client_ip.integer) {
+ /* Get ip address for our mac address */
+ printf(" Requesting IP address via DHCP: ");
+ arp_failed = dhcp(fd_device, &fn_ip, 30);
+
+ if (arp_failed == -1) {
+ printf("\n DHCP: Could not get ip address\n");
+ return -1;
+ }
+
+ } else {
+ memcpy(&fn_ip.own_ip, &ping_args.client_ip.integer, 4);
+ arp_failed = 1;
+ printf(" Own IP address: ");
+ }
+
+ // reinit network stack
+ netbase_init(fd_device, fn_ip.own_mac, fn_ip.own_ip);
+
+ printf("%d.%d.%d.%d\n",
+ ((fn_ip.own_ip >> 24) & 0xFF), ((fn_ip.own_ip >> 16) & 0xFF),
+ ((fn_ip.own_ip >> 8) & 0xFF), (fn_ip.own_ip & 0xFF));
+
+ memcpy(&fn_ip.server_ip, &ping_args.server_ip.integer, 4);
+ printf(" Ping to %d.%d.%d.%d ", ((fn_ip.server_ip >> 24) & 0xFF),
+ ((fn_ip.server_ip >> 16) & 0xFF),
+ ((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;
+ }
+ }
+
+ if (!echo_request(fd_device, &fn_ip, ping_args.timeout)) {
+ printf("success\n");
+ return 0;
+ } else {
+ printf("failed\n");
+ return -1;
+ }
+}
diff --git a/clients/net-snk/app/netlib/Makefile b/clients/net-snk/app/netlib/Makefile
new file mode 100644
index 0000000..b88d06c
--- /dev/null
+++ b/clients/net-snk/app/netlib/Makefile
@@ -0,0 +1,31 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2007 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 TOP
+ TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd)
+ export TOP
+endif
+include $(TOP)/make.rules
+
+CFLAGS += -I../
+
+OBJS = tftp.o netbase.o arp.o dns.o bootp.o dhcp.o icmp.o
+
+all: netlib.o
+
+netlib.o: $(OBJS)
+ $(LD) $(LDFLAGS) $^ -o $@ -r
+
+clean:
+ $(RM) -f *.o *.a *.i
+
+include $(TOP)/make.depend
diff --git a/clients/net-snk/app/netlib/arp.c b/clients/net-snk/app/netlib/arp.c
new file mode 100644
index 0000000..0792d99
--- /dev/null
+++ b/clients/net-snk/app/netlib/arp.c
@@ -0,0 +1,231 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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 <types.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netlib/netlib.h>
+#include <netlib/netbase.h>
+#include <netlib/arp.h>
+#include <time.h>
+
+/* ARP Message types */
+#define ARP_REQUEST 1
+#define ARP_REPLY 2
+
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PROTOTYPES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+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,
+ uint8_t * src_mac, uint32_t src_ip,
+ uint8_t * dest_mac, uint32_t dest_ip);
+
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+static uint8_t ether_packet[ETH_MTU_SIZE];
+static int32_t arp_device_socket = 0;
+static uint8_t arp_own_mac[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+static uint32_t arp_own_ip = 0;
+static uint8_t arp_result_mac[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+/**
+ * ARP: Initialize the environment for ARP client.
+ * To perform ARP-requests use the function arp_getmac.
+ *
+ * @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)
+ * @see arp_getmac
+ */
+void
+arp_init(int32_t device_socket, uint8_t own_mac[], uint32_t own_ip) {
+ arp_device_socket = device_socket;
+ memcpy(arp_own_mac, own_mac, 6);
+ arp_own_ip = own_ip;
+}
+
+/**
+ * ARP: For given IPv4 retrieves MAC via ARP (makes several attempts)
+ *
+ * @param dest_ip IP for the ARP-request
+ * @param dest_mac In case of SUCCESS stores MAC
+ * In case of FAULT stores zeros (0.0.0.0.0.0).
+ * @return TRUE - MAC successfuly retrieved;
+ * FALSE - error condition occurs.
+ */
+int8_t
+arp_getmac(uint32_t dest_ip, uint8_t dest_mac[]) {
+ // this counter is used so that we abort after 30 ARP request
+ // int32_t i;
+
+ // clearing the result buffer to detect an ARP answer
+ memset(arp_result_mac, 0, 6);
+
+// for(i = 0; i<30; ++i) {
+ arp_send_request(dest_ip);
+
+ // setting up a timer with a timeout of one second
+ set_timer(TICKS_SEC);
+
+ do {
+ receive_ether();
+ if (arp_result_mac[0] != 0 || arp_result_mac[1] != 0 ||
+ arp_result_mac[2] != 0 || arp_result_mac[3] != 0 ||
+ arp_result_mac[4] != 0 || arp_result_mac[5] != 0) {
+ memcpy(dest_mac, arp_result_mac, 6);
+ return 1; // no error
+ }
+ } while (get_timer() > 0);
+
+ // time is up
+// }
+
+// printf("\nGiving up after %d ARP requests\n", i);
+ return 0; // error
+}
+
+/**
+ * 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) {
+ uint8_t dest_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+ memset(ether_packet, 0, sizeof(struct ethhdr) + sizeof(struct arphdr));
+
+ fill_arphdr(&ether_packet[sizeof(struct ethhdr)], ARP_REQUEST,
+ arp_own_mac, arp_own_ip, dest_mac, dest_ip);
+ fill_ethhdr(&ether_packet[0], ETHERTYPE_ARP, arp_own_mac, dest_mac);
+
+ PRINT_SENDING(ether_packet,
+ sizeof(struct ethhdr) + sizeof(struct arphdr));
+
+ send(arp_device_socket, ether_packet,
+ sizeof(struct ethhdr) + sizeof(struct arphdr), 0);
+}
+
+/**
+ * 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) {
+ memset(ether_packet, 0, sizeof(struct ethhdr) + sizeof(struct arphdr));
+
+ fill_ethhdr(&ether_packet[0], ETHERTYPE_ARP, arp_own_mac, src_mac);
+ fill_arphdr(&ether_packet[sizeof(struct ethhdr)], ARP_REPLY,
+ arp_own_mac, arp_own_ip, src_mac, src_ip);
+
+ PRINT_SENDING(ether_packet,
+ sizeof(struct ethhdr) + sizeof(struct arphdr));
+
+ send(arp_device_socket, ether_packet,
+ sizeof(struct ethhdr) + sizeof(struct arphdr), 0);
+};
+
+/**
+ * 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,
+ uint8_t * src_mac, uint32_t src_ip,
+ 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.
+ * Sets arp_result_mac for given dest_ip (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(arp_own_ip))
+ return -1; // receiver IP doesn't match our IP
+
+ switch(htons(arph -> opcode)) {
+ case ARP_REQUEST:
+ // foreign request
+ if(arp_own_ip != 0)
+ arp_send_reply(htonl(arph->src_ip), arph -> src_mac);
+ return 0; // no error
+ case ARP_REPLY:
+ // if it is for us -> fill server MAC
+ if (!memcmp(arp_own_mac, arph -> dest_mac, 6))
+ memcpy(arp_result_mac, arph -> src_mac, 6);
+ return 0; // no error
+ default:
+ break;
+ }
+ return -1; // Invalid message type
+}
diff --git a/clients/net-snk/app/netlib/arp.h b/clients/net-snk/app/netlib/arp.h
new file mode 100644
index 0000000..c26c62a
--- /dev/null
+++ b/clients/net-snk/app/netlib/arp.h
@@ -0,0 +1,20 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+/* Initialize the environment for ARP client. */
+extern void arp_init(int32_t device_socket, uint8_t own_mac[], uint32_t own_ip);
+
+/* For given IPv4 retrieves MAC via ARP */
+extern int8_t arp_getmac(uint32_t dest_ip, uint8_t dest_mac[]);
+
+/* Handles ARP-packets, which are detected by receive_ether. */
+extern int8_t handle_arp(uint8_t * packet, int32_t packetsize);
diff --git a/clients/net-snk/app/netlib/bootp.c b/clients/net-snk/app/netlib/bootp.c
new file mode 100644
index 0000000..ce2ae5f
--- /dev/null
+++ b/clients/net-snk/app/netlib/bootp.c
@@ -0,0 +1,254 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+#include <types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netlib/netlib.h>
+#include <time.h>
+
+#define DEBUG 0
+
+void
+print_ip(char *ip)
+{
+ printf("%d.%d.%d.%d\n", ip[0], ip[1], ip[2], ip[3]);
+}
+
+
+/* IP header checksum calculation */
+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 int
+send_bootp(int boot_device, filename_ip_t * fn_ip)
+{
+ int i;
+ 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));
+
+ 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;
+ btph->op = 1;
+ btph->htype = 1;
+ btph->hlen = 6;
+ strcpy((char *) btph->file, "bla");
+ memcpy(btph->chaddr, ethh->src_mac, 6);
+
+#if DEBUG
+ printf("Sending packet\n");
+ printf("Packet is ");
+ for (i = 0; i < packetsize; i++)
+ printf(" %02x", packet[i]);
+ printf(".\n");
+#endif
+
+ i = send(boot_device, packet, packetsize, 0);
+#if DEBUG
+ printf("%d bytes transmitted over socket.\n", i);
+#endif
+
+ return 0;
+}
+
+
+static int
+receive_bootp(int boot_device, filename_ip_t * fn_ip)
+{
+ int len, old_sum;
+ unsigned int packetsize = 2000;
+ unsigned char packet[packetsize];
+ struct ethhdr *ethh;
+ struct iphdr *iph;
+ struct udphdr *udph;
+ struct btphdr *btph;
+
+ 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));
+
+ memset(packet, 0, packetsize);
+
+ /* setting up a timer with a timeout of one second */
+ set_timer(TICKS_SEC);
+
+ do {
+
+ /* let's receive a packet */
+ len = recv(boot_device, packet, packetsize, 0);
+
+#if DEBUG
+ int j;
+ printf("%d bytes received, %d expected \n", len, packetsize);
+ if (len == 346) {
+ printf("Rec packet\n");
+ printf("Packet is ");
+ for (j = 0; j < len; j++) {
+ if (j % 16 == 0)
+ printf("\n");
+ printf(" %02x", packet[j]);
+ }
+ printf(".\n");
+ }
+#endif
+ /* check if the ip checksum is correct */
+ old_sum = iph->ip_sum;
+ iph->ip_sum = 0x00;
+ if (old_sum !=
+ checksum((unsigned short *) iph, sizeof(struct iphdr) >> 1))
+ /* checksum failed */
+ continue;
+ /* is it a udp packet */
+ if (iph->ip_p != IPTYPE_UDP)
+ continue;
+ /* check if the source port and destination port and the packet
+ * say that it is a bootp answer */
+ if (udph->uh_dport != htons(UDPPORT_BOOTPC) || udph->uh_sport != htons(UDPPORT_BOOTPS))
+ continue;
+ /* check if it is a Boot Reply */
+ 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))
+ continue;
+
+ 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);
+ printf("Next server IP address: ");
+ print_ip(&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++) {
+ if (j % 16 == 0)
+ printf("\n");
+ printf(" %02x", packet[j]);
+ }
+ 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]);
+ 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]);
+ 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]);
+ 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);
+ printf("Header iph->ip_id: %x\n",iph->ip_id);
+ printf("Header iph->ip_off: %x\n",iph->ip_off);
+ printf("Header iph->ip_ttl: %x\n",iph->ip_ttl);
+ printf("Header iph->ip_p: %x\n",iph->ip_p);
+ printf("Header iph->ip_sum: %x\n",iph->ip_sum);
+ printf("Header iph->ip_src: %x\n",iph->ip_src);
+ printf("Header iph->ip_dst: %x\n",iph->ip_dst);
+
+ printf("Header btph->op: %x\n",btph->op);
+ printf("Header btph->htype: %x\n",btph->htype);
+ printf("Header btph->hlen: %x\n",btph->hlen);
+ printf("Header btph->hops: %x\n",btph->hops);
+ printf("Header btph->xid: %x\n",btph->xid);
+ printf("Header btph->secs: %x\n",btph->secs);
+ printf("Header btph->ciaddr: %x\n",btph->ciaddr);
+ printf("Header btph->yiaddr: %x\n",btph->yiaddr);
+ 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]);
+
+
+#endif
+ return 0;
+
+ /* only do this for the time specified during set_timer() */
+ } while (get_timer() > 0);
+ return -1;
+}
+
+
+int
+bootp(int boot_device, filename_ip_t * fn_ip, unsigned int retries)
+{
+ int i = (int) retries+1;
+ fn_ip->own_ip = 0;
+
+ printf(" ");
+
+ do {
+ printf("\b\b%02d", i);
+ if (!i--) {
+ printf("\nGiving up after %d bootp requests\n",
+ retries+1);
+ return -1;
+ }
+ send_bootp(boot_device, 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);
+ printf("\b\b\b");
+ return 0;
+}
diff --git a/clients/net-snk/app/netlib/dhcp.c b/clients/net-snk/app/netlib/dhcp.c
new file mode 100644
index 0000000..8aa995e
--- /dev/null
+++ b/clients/net-snk/app/netlib/dhcp.c
@@ -0,0 +1,1049 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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 dhcp.c <pre>
+ * **************** State-transition diagram for DHCP client *************
+ *
+ * +---------+ Note: DHCP-server msg / DHCP-client msg
+ * | INIT |
+ * +---------+
+ * |
+ * | - / Discover
+ * V
+ * +---------+
+ * | SELECT | Timeout
+ * +---------+ |
+ * | |
+ * | Offer / Request |
+ * | |
+ * V V
+ * +---------+ NACK / - ***********
+ * | REQUEST | ----------------> * FAULT *
+ * +---------+ ***********
+ * |
+ * | ACK / - ***********
+ * +----------------------> * SUCCESS *
+ * ***********
+ *
+ * ************************************************************************
+ * </pre> */
+
+
+/*>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<<<*/
+
+#include <types.h>
+#include <ctype.h>
+#include <stdlib.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>
+
+/* DHCP Message Types */
+#define DHCPDISCOVER 1
+#define DHCPOFFER 2
+#define DHCPREQUEST 3
+#define DHCPDECLINE 4
+#define DHCPACK 5
+#define DHCPNACK 6
+#define DHCPRELEASE 7
+#define DHCPINFORM 8
+
+/* DHCP Option Codes */
+#define DHCP_MASK 1
+#define DHCP_ROUTER 3
+#define DHCP_DNS 6
+#define DHCP_REQUESTED_IP 50
+#define DHCP_OVERLOAD 52
+#define DHCP_MSG_TYPE 53
+#define DHCP_SERVER_ID 54
+#define DHCP_REQUEST_LIST 55
+#define DHCP_TFTP_SERVER 66
+#define DHCP_BOOTFILE 67
+#define DHCP_ENDOPT 0xFF
+#define DHCP_PADOPT 0x00
+
+/* "file/sname" overload option values */
+#define DHCP_OVERLOAD_FILE 1
+#define DHCP_OVERLOAD_SNAME 2
+#define DHCP_OVERLOAD_BOTH 3
+
+/* DHCP states codes */
+#define DHCP_STATE_SELECT 1
+#define DHCP_STATE_REQUEST 2
+#define DHCP_STATE_SUCCESS 3
+#define DHCP_STATE_FAULT 4
+
+static uint8_t dhcp_magic[] = {0x63, 0x82, 0x53, 0x63};
+/**< DHCP_magic is a cookie, that identifies DHCP options (see RFC 2132) */
+
+/** \struct dhcp_options_t
+ * This structure is used to fill options in DHCP-msg during transmitting
+ * or to retrieve options from DHCP-msg during receiving.
+ * <p>
+ * If flag[i] == TRUE then field for i-th option retains valid value and
+ * information from this field may retrived (in case of receiving) or will
+ * be transmitted (in case of transmitting).
+ *
+ */
+typedef struct {
+ uint8_t flag[256]; /**< Show if corresponding opt. is valid */
+ uint8_t request_list[256]; /**< o.55 If i-th member is TRUE, then i-th
+ option will be requested from server */
+ uint32_t server_ID; /**< o.54 Identifies DHCP-server */
+ uint32_t requested_IP; /**< o.50 Must be filled in DHCP-Request */
+ uint32_t dns_IP; /**< o. 6 DNS IP */
+ uint32_t router_IP; /**< o. 3 Router IP */
+ uint32_t subnet_mask; /**< o. 1 Subnet mask */
+ uint8_t msg_type; /**< o.53 DHCP-message type */
+ uint8_t overload; /**< o.52 Overload sname/file fields */
+ int8_t tftp_server[256]; /**< o.66 TFTP server name */
+ int8_t bootfile[256]; /**< o.67 Boot file name */
+} dhcp_options_t;
+
+/** Stores state of DHCP-client (refer to State-transition diagram) */
+static uint8_t dhcp_state;
+
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> PROTOTYPES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+static int32_t
+dhcp_attempt(void);
+
+static int32_t
+dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct);
+
+static int32_t
+dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len,
+ dhcp_options_t * opt_struct);
+
+static int8_t
+dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len,
+ uint8_t src_options[], uint32_t src_len);
+
+static int8_t
+dhcp_find_option(uint8_t options[], uint32_t len,
+ uint8_t op_code, uint32_t * op_offset);
+
+static void
+dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len,
+ uint8_t * new_option);
+
+static void
+dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len,
+ uint32_t dst_offset, uint8_t * new_option);
+
+static void
+dhcp_send_discover(void);
+
+static void
+dhcp_send_request(void);
+
+static uint8_t
+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];
+static int8_t dhcp_tftp_name[256];
+
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+/**
+ * DHCP: Obtains IP and configuration info from DHCP server
+ * (makes several attempts).
+ *
+ * @param boot_device a socket number used to send and recieve packets
+ * @param fn_ip contains the following configuration information:
+ * client MAC, client IP, TFTP-server MAC,
+ * TFTP-server IP, Boot file name
+ * @return ZERO - IP and configuration info obtained;
+ * NON ZERO - error condition occurs.
+ */
+int32_t
+dhcp(int32_t boot_device, 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, "");
+
+ dhcp_device_socket = boot_device;
+ memcpy(dhcp_own_mac, fn_ip -> own_mac, 6);
+
+ printf(" ");
+
+ do {
+ printf("\b\b\b%03d", i-1);
+ if (getchar() == 27) {
+ printf("\nAborted\n");
+ return -1;
+ }
+ if (!--i) {
+ printf("\nGiving up after %d DHCP requests\n", retries);
+ return -1;
+ }
+ } while (!dhcp_attempt());
+ printf("\b\b\b\b");
+
+ if (fn_ip->own_ip) {
+ dhcp_own_ip = fn_ip->own_ip;
+ }
+ if (fn_ip->server_ip) {
+ dhcp_siaddr_ip = fn_ip->server_ip;
+ }
+ if(fn_ip->filename[0] != 0) {
+ 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) {
+ // ERROR: TFTP name is not presented
+ return -3;
+ }
+
+ // take TFTP-ip from siaddr field
+ dhcp_tftp_ip = dhcp_siaddr_ip;
+ }
+ 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
+ // Use TFTP-ip from siaddr field, if presented
+ if (dhcp_siaddr_ip) {
+ dhcp_tftp_ip = dhcp_siaddr_ip;
+ }
+ else {
+ // ERROR: Can't obtain TFTP server IP
+ return -4;
+ }
+ }
+ }
+ }
+
+ 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;
+}
+
+/**
+ * DHCP: Tries o obtain DHCP parameters, refer to state-transition diagram
+ */
+static int32_t
+dhcp_attempt(void) {
+ int sec;
+
+ // Send DISCOVER message and switch DHCP-client to SELECT state
+ dhcp_send_discover();
+
+ dhcp_state = DHCP_STATE_SELECT;
+
+ // setting up a timer with a timeout of two seconds
+ for (sec = 0; sec < 2; sec++) {
+ set_timer(TICKS_SEC);
+ do {
+ receive_ether();
+
+ // Wait until client will switch to Final state or Timeout occurs
+ switch (dhcp_state) {
+ case DHCP_STATE_SUCCESS :
+ return 1;
+ case DHCP_STATE_FAULT :
+ return 0;
+ }
+ } while (get_timer() > 0);
+ }
+
+ // timeout
+ return 0;
+}
+
+/**
+ * DHCP: Supplements DHCP-message with options stored in structure.
+ * For more information about option coding see dhcp_options_t.
+ *
+ * @param opt_field Points to the "vend" field of DHCP-message
+ * (destination)
+ * @param opt_struct this structure stores info about the options wich
+ * will be added to DHCP-message (source)
+ * @return TRUE - options packed;
+ * FALSE - error condition occurs.
+ * @see dhcp_options_t
+ */
+static int32_t
+dhcp_encode_options(uint8_t * opt_field, dhcp_options_t * opt_struct) {
+ uint8_t * options = opt_field;
+ uint16_t i, sum; // used to define is any options set
+
+ // magic
+ memcpy(options, dhcp_magic, 4);
+ options += 4;
+
+ // fill message type
+ switch (opt_struct -> msg_type) {
+ case DHCPDISCOVER :
+ case DHCPREQUEST :
+ case DHCPDECLINE :
+ case DHCPINFORM :
+ case DHCPRELEASE :
+ options[0] = DHCP_MSG_TYPE;
+ options[1] = 1;
+ options[2] = opt_struct -> msg_type;
+ options += 3;
+ break;
+ default :
+ return 0; // Unsupported DHCP-message
+ }
+
+ if (opt_struct -> overload) {
+ options[0] = DHCP_OVERLOAD;
+ options[1] = 0x01;
+ options[2] = opt_struct -> overload;
+ options +=3;
+ }
+
+ if (opt_struct -> flag[DHCP_REQUESTED_IP]) {
+ options[0] = DHCP_REQUESTED_IP;
+ options[1] = 0x04;
+ * (uint32_t *) (options + 2) = htonl (opt_struct -> requested_IP);
+ options +=6;
+ }
+
+ if (opt_struct -> flag[DHCP_SERVER_ID]) {
+ options[0] = DHCP_SERVER_ID;
+ options[1] = 0x04;
+ * (uint32_t *) (options + 2) = htonl (opt_struct -> server_ID);
+ options +=6;
+ }
+
+ sum = 0;
+ for (i = 0; i < 256; i++)
+ sum += opt_struct -> request_list[i];
+
+ if (sum) {
+ options[0] = DHCP_REQUEST_LIST;
+ options[1] = sum;
+ options += 2;
+ for (i = 0; i < 256; i++) {
+ if (opt_struct -> request_list[i]) {
+ options[0] = i; options++;
+ }
+ }
+ }
+
+ if (opt_struct -> flag[DHCP_TFTP_SERVER]) {
+ options[0] = DHCP_TFTP_SERVER;
+ options[1] = strlen((char *) opt_struct -> tftp_server) + 1;
+ memcpy(options + 2, opt_struct -> tftp_server, options[1]);
+ options += options[1] + 2;
+ }
+
+ if (opt_struct -> flag[DHCP_BOOTFILE]) {
+ options[0] = DHCP_BOOTFILE;
+ options[1] = strlen((char *) opt_struct -> bootfile) + 1;
+ memcpy(options + 2, opt_struct -> bootfile, options[1]);
+ options += options[1] + 2;
+ }
+
+ // end options
+ options[0] = 0xFF;
+ options++;
+
+ return 1;
+}
+
+/**
+ * DHCP: Extracts encoded options from DHCP-message into the structure.
+ * For more information about option coding see dhcp_options_t.
+ *
+ * @param opt_field Points to the "options" field of DHCP-message
+ * (source).
+ * @param opt_len Length of "options" field.
+ * @param opt_struct this structure stores info about the options wich
+ * was extracted from DHCP-message (destination).
+ * @return TRUE - options extracted;
+ * FALSE - error condition occurs.
+ * @see dhcp_options_t
+ */
+static int32_t
+dhcp_decode_options(uint8_t opt_field[], uint32_t opt_len,
+ dhcp_options_t * opt_struct) {
+ int32_t offset = 0;
+
+ memset(opt_struct, 0, sizeof(dhcp_options_t));
+
+ // magic
+ if (memcmp(opt_field, dhcp_magic, 4)) {
+ return 0;
+ }
+
+ offset += 4;
+ while (offset < opt_len) {
+ opt_struct -> flag[opt_field[offset]] = 1;
+ switch(opt_field[offset]) {
+ case DHCP_OVERLOAD :
+ opt_struct -> overload = opt_field[offset + 2];
+ offset += 2 + opt_field[offset + 1];
+ break;
+
+ case DHCP_REQUESTED_IP :
+ opt_struct -> requested_IP = htonl(* (uint32_t *) (opt_field + offset + 2));
+ offset += 2 + opt_field[offset + 1];
+ break;
+
+ case DHCP_MASK :
+ opt_struct -> flag[DHCP_MASK] = 1;
+ opt_struct -> subnet_mask = htonl(* (uint32_t *) (opt_field + offset + 2));
+ offset += 2 + opt_field[offset + 1];
+ break;
+
+ case DHCP_DNS :
+ opt_struct -> flag[DHCP_DNS] = 1;
+ opt_struct -> dns_IP = htonl(* (uint32_t *) (opt_field + offset + 2));
+ offset += 2 + opt_field[offset + 1];
+ break;
+
+ case DHCP_ROUTER :
+ opt_struct -> flag[DHCP_ROUTER] = 1;
+ opt_struct -> router_IP = htonl(* (uint32_t *) (opt_field + offset + 2));
+ offset += 2 + opt_field[offset + 1];
+ break;
+
+ case DHCP_MSG_TYPE :
+ if ((opt_field[offset + 2] > 0) && (opt_field[offset + 2] < 9))
+ opt_struct -> msg_type = opt_field[offset + 2];
+ else
+ return 0;
+ offset += 2 + opt_field[offset + 1];
+ break;
+
+ case DHCP_SERVER_ID :
+ opt_struct -> server_ID = htonl(* (uint32_t *) (opt_field + offset + 2));
+ offset += 2 + opt_field[offset + 1];
+ break;
+
+ case DHCP_TFTP_SERVER :
+ memcpy(opt_struct -> tftp_server, opt_field + offset + 2, opt_field[offset + 1]);
+ (opt_struct -> tftp_server)[opt_field[offset + 1]] = 0;
+ offset += 2 + opt_field[offset + 1];
+ break;
+
+ case DHCP_BOOTFILE :
+ memcpy(opt_struct -> bootfile, opt_field + offset + 2, opt_field[offset + 1]);
+ (opt_struct -> bootfile)[opt_field[offset + 1]] = 0;
+ offset += 2 + opt_field[offset + 1];
+ break;
+
+ case DHCP_PADOPT :
+ offset++;
+ break;
+
+ case DHCP_ENDOPT : // End of options
+ return 1;
+
+ default :
+ offset += 2 + opt_field[offset + 1]; // Unsupported opt. - do nothing
+ }
+ }
+ if (offset == opt_len)
+ return 1; // options finished without 0xFF
+
+ return 0;
+}
+
+/**
+ * DHCP: Appends information from source "options" into dest "options".
+ * This function is used to support "file/sname" overloading.
+ *
+ * @param dst_options destanation "options" field
+ * @param dst_len size of dst_options (modified by this function)
+ * @param src_options source "options" field
+ * @param src_len size of src_options
+ * @return TRUE - options merged;
+ * FALSE - error condition occurs.
+ */
+static int8_t dhcp_merge_options(uint8_t dst_options[], uint32_t * dst_len,
+ uint8_t src_options[], uint32_t src_len) {
+ int32_t dst_offset, src_offset = 0;
+
+ // remove ENDOPT if presented
+ if (dhcp_find_option(dst_options, * dst_len, DHCP_ENDOPT, (uint32_t *) &dst_offset))
+ * dst_len = dst_offset;
+
+ while (src_offset < src_len) {
+ switch(src_options[src_offset]) {
+ case DHCP_PADOPT:
+ src_offset++;
+ break;
+ case DHCP_ENDOPT:
+ return 1;
+ default:
+ if (dhcp_find_option(dst_options, * dst_len,
+ src_options[src_offset],
+ (uint32_t *) &dst_offset)) {
+ dhcp_combine_option(dst_options, dst_len,
+ dst_offset,
+ (uint8_t *) src_options +
+ src_offset);
+ }
+ else {
+ dhcp_append_option(dst_options, dst_len, src_options + src_offset);
+ }
+ src_offset += 2 + src_options[src_offset + 1];
+ }
+ }
+
+ if (src_offset == src_len)
+ return 1;
+ return 0;
+}
+
+/**
+ * DHCP: Finds given occurence of the option with the given code (op_code)
+ * in "options" field of DHCP-message.
+ *
+ * @param options "options" field of DHCP-message
+ * @param len length of the "options" field
+ * @param op_code code of the option to find
+ * @param op_offset SUCCESS - offset to an option occurence;
+ * FAULT - offset is set to zero.
+ * @return TRUE - option was find;
+ * FALSE - option wasn't find.
+ */
+static int8_t dhcp_find_option(uint8_t options[], uint32_t len,
+ uint8_t op_code, uint32_t * op_offset) {
+ uint32_t srch_offset = 0;
+ * op_offset = 0;
+
+ while (srch_offset < len) {
+ if (options[srch_offset] == op_code) {
+ * op_offset = srch_offset;
+ return 1;
+ }
+ if (options[srch_offset] == DHCP_ENDOPT)
+ return 0;
+
+ if (options[srch_offset] == DHCP_PADOPT)
+ srch_offset++;
+ else
+ srch_offset += 2 + options[srch_offset + 1];
+ }
+ return 0;
+}
+
+/**
+ * DHCP: Appends new option from one list (src) into the tail
+ * of another option list (dst)
+ *
+ * @param dst_options "options" field of DHCP-message
+ * @param dst_len length of the "options" field (modified)
+ * @param new_option points to an option in another list (src)
+ */
+static void
+dhcp_append_option(uint8_t dst_options[], uint32_t * dst_len,
+ uint8_t * new_option) {
+ memcpy(dst_options + ( * dst_len), new_option, 2 + (* (new_option + 1)));
+ * dst_len += 2 + *(new_option + 1);
+}
+
+/**
+ * DHCP: This function is used when options with the same code are
+ * presented in both merged lists. In this case information
+ * about the option from one list (src) is combined (complemented)
+ * with information about the option in another list (dst).
+ *
+ * @param dst_options "options" field of DHCP-message
+ * @param dst_len length of the "options" field (modified)
+ * @param dst_offset offset of the option from beggining of the list
+ * @param new_option points to an option in another list (src)
+ */
+static void
+dhcp_combine_option(uint8_t dst_options[], uint32_t * dst_len,
+ uint32_t dst_offset, uint8_t * new_option) {
+
+ uint8_t tmp_buffer[1024]; // use to provide safe memcpy
+ uint32_t tail_len;
+
+ // move all subsequent options (allocate size for additional info)
+ tail_len = (* dst_len) - dst_offset - 2 - dst_options[dst_offset + 1];
+
+ memcpy(tmp_buffer, dst_options + (* dst_len) - tail_len, tail_len);
+ memcpy(dst_options + (* dst_len) - tail_len + (* (new_option + 1)),
+ tmp_buffer, tail_len);
+
+ // add new_content to option
+ memcpy(dst_options + (* dst_len) - tail_len, new_option + 2,
+ * (new_option + 1));
+ dst_options[dst_offset + 1] += * (new_option + 1);
+
+ // correct dst_len
+ * dst_len += * (new_option + 1);
+}
+
+/**
+ * DHCP: Sends DHCP-Discover message. Looks for DHCP servers.
+ */
+static void
+dhcp_send_discover(void) {
+ uint32_t packetsize = sizeof(struct ethhdr) + 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) +
+ sizeof(struct iphdr) + sizeof(struct udphdr)]);
+
+ btph -> op = 1;
+ btph -> htype = 1;
+ btph -> hlen = 6;
+ memcpy(btph -> chaddr, dhcp_own_mac, 6);
+
+ memset(&opt, 0, sizeof(dhcp_options_t));
+
+ opt.msg_type = DHCPDISCOVER;
+
+ opt.request_list[DHCP_MASK] = 1;
+ opt.request_list[DHCP_DNS] = 1;
+ opt.request_list[DHCP_ROUTER] = 1;
+ opt.request_list[DHCP_TFTP_SERVER] = 1;
+ opt.request_list[DHCP_BOOTFILE] = 1;
+
+ dhcp_encode_options(btph -> vend, &opt);
+
+ fill_udphdr(&ether_packet[sizeof(struct ethhdr) + sizeof(struct iphdr)],
+ sizeof(struct btphdr) + sizeof(struct udphdr),
+ UDPPORT_BOOTPC, UDPPORT_BOOTPS);
+ fill_iphdr(&ether_packet[sizeof(struct ethhdr)], 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);
+}
+
+/**
+ * DHCP: Sends DHCP-Request message. Asks for acknowledgment to occupy IP.
+ */
+static void
+dhcp_send_request(void) {
+ uint32_t packetsize = sizeof(struct ethhdr) + 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) +
+ sizeof(struct iphdr) + sizeof(struct udphdr)]);
+
+ btph -> op = 1;
+ btph -> htype = 1;
+ btph -> hlen = 6;
+ memcpy(btph -> chaddr, dhcp_own_mac, 6);
+
+ memset(&opt, 0, sizeof(dhcp_options_t));
+
+ opt.msg_type = DHCPREQUEST;
+ memcpy(&(opt.requested_IP), &dhcp_own_ip, 4);
+ opt.flag[DHCP_REQUESTED_IP] = 1;
+ memcpy(&(opt.server_ID), &dhcp_server_ip, 4);
+ opt.flag[DHCP_SERVER_ID] = 1;
+
+ opt.request_list[DHCP_MASK] = 1;
+ opt.request_list[DHCP_DNS] = 1;
+ opt.request_list[DHCP_ROUTER] = 1;
+ opt.request_list[DHCP_TFTP_SERVER] = 1;
+ opt.request_list[DHCP_BOOTFILE] = 1;
+
+ dhcp_encode_options(btph -> vend, &opt);
+
+ fill_udphdr(&ether_packet[sizeof(struct ethhdr) + sizeof(struct iphdr)],
+ sizeof(struct btphdr) + sizeof(struct udphdr),
+ UDPPORT_BOOTPC, UDPPORT_BOOTPS);
+ fill_iphdr(&ether_packet[sizeof(struct ethhdr)], 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);
+}
+
+
+/**
+ * DHCP: Sends DHCP-Release message. Releases occupied IP.
+ */
+void dhcp_send_release(void) {
+ uint32_t packetsize = sizeof(struct ethhdr) + sizeof(struct iphdr) +
+ sizeof(struct udphdr) + sizeof(struct btphdr);
+ struct btphdr *btph;
+ dhcp_options_t opt;
+
+ btph = (struct btphdr *) (&ether_packet[sizeof(struct ethhdr) +
+ sizeof(struct iphdr) + sizeof(struct udphdr)]);
+
+ memset(ether_packet, 0, packetsize);
+
+ btph -> op = 1;
+ btph -> htype = 1;
+ btph -> hlen = 6;
+ strcpy((char *) btph -> file, "");
+ memcpy(btph -> chaddr, dhcp_own_mac, 6);
+ btph -> ciaddr = htonl(dhcp_own_ip);
+
+ memset(&opt, 0, sizeof(dhcp_options_t));
+
+ opt.msg_type = DHCPRELEASE;
+ opt.server_ID = dhcp_server_ip;
+ opt.flag[DHCP_SERVER_ID] = 1;
+
+ dhcp_encode_options(btph -> vend, &opt);
+
+ fill_udphdr(&ether_packet[sizeof(struct ethhdr) + sizeof(struct iphdr)],
+ sizeof(struct btphdr) + sizeof(struct udphdr),
+ UDPPORT_BOOTPC, UDPPORT_BOOTPS);
+ fill_iphdr(&ether_packet[sizeof(struct ethhdr)], 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);
+}
+
+/**
+ * DHCP: Handles DHCP-messages according to Receive-handle diagram.
+ * Changes the state of DHCP-client.
+ *
+ * @param packet BootP/DHCP-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 btphdr
+ */
+
+int8_t
+handle_dhcp(uint8_t * packet, int32_t packetsize) {
+ struct btphdr * btph;
+ struct iphdr * iph;
+ dhcp_options_t opt;
+
+ memset(&opt, 0, sizeof(dhcp_options_t));
+ btph = (struct btphdr *) packet;
+ iph = (struct iphdr *) packet - sizeof(struct udphdr) -
+ sizeof(struct iphdr);
+ if (btph -> op != 2)
+ return -1; // it is not Boot Reply
+
+ 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);
+
+ if (strlen((char *) btph -> sname) && !dhcp_siaddr_ip) {
+ strncpy((char *) dhcp_tftp_name, (char *) btph -> sname,
+ sizeof(btph -> sname));
+ dhcp_tftp_name[sizeof(btph -> sname)] = 0;
+ }
+
+ if (strlen((char *) btph -> file)) {
+ strncpy((char *) dhcp_filename, (char *) btph -> file, sizeof(btph -> file));
+ dhcp_filename[sizeof(btph -> file)] = 0;
+ }
+
+ dhcp_state = DHCP_STATE_SUCCESS;
+ return 0;
+ }
+
+
+ // decode options
+ if (!dhcp_decode_options(btph -> vend, packetsize -
+ sizeof(struct btphdr) + sizeof(btph -> vend),
+ &opt)) {
+ return -1; // can't decode options
+ }
+
+ if (opt.overload) {
+ int16_t decode_res = 0;
+ uint8_t options[1024]; // buffer for merged options
+ uint32_t opt_len;
+
+ // move 1-st part of options from vend field into buffer
+ opt_len = packetsize - sizeof(struct btphdr) +
+ sizeof(btph -> vend) - 4;
+ memcpy(options, btph -> vend, opt_len + 4);
+
+ // add other parts
+ switch (opt.overload) {
+ case DHCP_OVERLOAD_FILE:
+ decode_res = dhcp_merge_options(options + 4, &opt_len,
+ btph -> file,
+ sizeof(btph -> file));
+ break;
+ case DHCP_OVERLOAD_SNAME:
+ decode_res = dhcp_merge_options(options + 4, &opt_len,
+ btph -> sname,
+ sizeof(btph -> sname));
+ break;
+ case DHCP_OVERLOAD_BOTH:
+ decode_res = dhcp_merge_options(options + 4, &opt_len,
+ btph -> file,
+ sizeof(btph -> file));
+ if (!decode_res)
+ break;
+ decode_res = dhcp_merge_options(options + 4, &opt_len,
+ btph -> sname,
+ sizeof(btph -> sname));
+ break;
+ }
+
+ if (!decode_res)
+ return -1; // bad options in sname/file fields
+
+ // decode merged options
+ if (!dhcp_decode_options(options, opt_len + 4, &opt)) {
+ return -1; // can't decode options
+ }
+ }
+
+ 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);
+ if (strlen((char *) btph -> sname) && !dhcp_siaddr_ip) {
+ strncpy((char *) dhcp_tftp_name, (char *) btph -> sname, sizeof(btph -> sname));
+ dhcp_tftp_name[sizeof(btph -> sname)] = 0;
+ }
+
+ if (strlen((char *) btph -> file)) {
+ strncpy((char *) dhcp_filename, (char *) btph -> file, sizeof(btph -> file));
+ dhcp_filename[sizeof(btph -> file)] = 0;
+ }
+
+ // retrieve DHCP-server IP from IP-header
+ dhcp_server_ip = iph -> htonl(ip_src);
+
+ dhcp_state = DHCP_STATE_SUCCESS;
+ }
+ else {
+ // It is DHCP - RFC 2131 & RFC 2132
+ // opt contains parameters from server
+ switch (dhcp_state) {
+ case DHCP_STATE_SELECT :
+ if (opt.msg_type == DHCPOFFER) {
+ dhcp_own_ip = htonl(btph -> yiaddr);
+ dhcp_server_ip = opt.server_ID;
+ dhcp_send_request();
+ dhcp_state = DHCP_STATE_REQUEST;
+ }
+ return 0;
+ case DHCP_STATE_REQUEST :
+ switch (opt.msg_type) {
+ case DHCPNACK :
+ dhcp_own_ip = 0;
+ dhcp_server_ip = 0;
+ dhcp_state = DHCP_STATE_FAULT;
+ break;
+ case DHCPACK :
+ dhcp_own_ip = htonl(btph -> yiaddr);
+ dhcp_server_ip = opt.server_ID;
+ dhcp_siaddr_ip = htonl(btph -> siaddr);
+ if (opt.flag[DHCP_TFTP_SERVER]) {
+ strcpy((char *) dhcp_tftp_name, (char *) opt.tftp_server);
+ }
+ else {
+ strcpy((char *) dhcp_tftp_name, "");
+ if ((opt.overload != DHCP_OVERLOAD_SNAME &&
+ opt.overload != DHCP_OVERLOAD_BOTH) &&
+ !dhcp_siaddr_ip) {
+ strncpy((char *) dhcp_tftp_name,
+ (char *) btph->sname,
+ sizeof(btph -> sname));
+ dhcp_tftp_name[sizeof(btph->sname)] = 0;
+ }
+ }
+
+ if (opt.flag[DHCP_BOOTFILE]) {
+ strcpy((char *) dhcp_filename, (char *) opt.bootfile);
+ }
+ else {
+ strcpy((char *) dhcp_filename, "");
+ if (opt.overload != DHCP_OVERLOAD_FILE &&
+ opt.overload != DHCP_OVERLOAD_BOTH &&
+ strlen((char *) btph -> file)) {
+ strncpy((char *) dhcp_filename,
+ (char *) btph->file,
+ sizeof(btph->file));
+ dhcp_filename[sizeof(btph -> file)] = 0;
+ }
+ }
+
+ dhcp_state = DHCP_STATE_SUCCESS;
+ break;
+ default:
+ break; // Unused DHCP-message - do nothing
+ }
+ break;
+ default :
+ return -1; // Illegal DHCP-client state
+ }
+ }
+
+ if (dhcp_state == DHCP_STATE_SUCCESS) {
+
+ // 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);
+
+ /* 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);
+ }
+ }
+
+ 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");
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * DHCP: Converts "255.255.255.255" -> 32-bit long IP
+ *
+ * @param str string to be converted
+ * @param ip in case of SUCCESS - 32-bit long IP
+ in case of FAULT - zero
+ * @return TRUE - IP converted successfully;
+ * FALSE - error condition occurs (e.g. bad format)
+ */
+static uint8_t
+strtoip(int8_t * str, uint32_t * ip) {
+ int8_t ** ptr = &str;
+ int16_t i = 0, res, len;
+ char octet[256];
+
+ * ip = 0;
+
+ while (**ptr != 0) {
+ if (i > 3 || !isdigit(**ptr))
+ return 0;
+ if (strstr((char *) * ptr, ".") != NULL) {
+ len = (int16_t) ((int8_t *) strstr((char *) * ptr, ".") -
+ (int8_t *) (* ptr));
+ strncpy(octet, (char *) * ptr, len); octet[len] = 0;
+ * ptr += len;
+ }
+ else {
+ strcpy(octet, (char *) * ptr);
+ * ptr += strlen(octet);
+ }
+ res = strtol(octet, NULL, 10);
+ if ((res > 255) || (res < 0))
+ return 0;
+ * ip = ((* ip) << 8) + res;
+ i++;
+ if (** ptr == '.')
+ (*ptr)++;
+ }
+
+ if (i != 4)
+ return 0;
+ return 1;
+}
diff --git a/clients/net-snk/app/netlib/dhcp.h b/clients/net-snk/app/netlib/dhcp.h
new file mode 100644
index 0000000..5d0d636
--- /dev/null
+++ b/clients/net-snk/app/netlib/dhcp.h
@@ -0,0 +1,14 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+/* Handles DHCP-packets, which are detected by receive_ether. */
+extern int8_t handle_dhcp(uint8_t * packet, int32_t packetsize);
diff --git a/clients/net-snk/app/netlib/dns.c b/clients/net-snk/app/netlib/dns.c
new file mode 100644
index 0000000..d0eb7b0
--- /dev/null
+++ b/clients/net-snk/app/netlib/dns.c
@@ -0,0 +1,522 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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 <types.h>
+#include <ctype.h>
+#include <stdlib.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>
+
+#define DNS_FLAG_MSGTYPE 0xF800 /**< Message type mask (opcode) */
+#define DNS_FLAG_SQUERY 0x0000 /**< Standard query type */
+#define DNS_FLAG_SRESPONSE 0x8000 /**< Standard response type */
+#define DNS_FLAG_RD 0x0100 /**< Recursion desired flag */
+#define DNS_FLAG_RCODE 0x000F /**< Response code mask
+ (stores err.cond.) code */
+#define DNS_RCODE_NERROR 0 /**< "No errors" code */
+
+#define DNS_QTYPE_A 1 /**< A 32-bit IP record type */
+#define DNS_QTYPE_CNAME 5 /**< Canonical name record type */
+
+#define DNS_QCLASS_IN 1 /**< Query class for internet msgs */
+
+/** \struct dnshdr
+ * A header for DNS-messages (see RFC 1035, paragraph 4.1.1).
+ * <p>
+ * DNS-message consist of DNS-header and 4 optional sections,
+ * arranged in the following order:<ul>
+ * <li> DNS-header
+ * <li> question section
+ * <li> answer section
+ * <li> authority section
+ * <li> additional section
+ * </ul>
+ */
+struct dnshdr {
+ uint16_t id; /**< an identifier used to match up replies */
+ uint16_t flags; /**< contains op_code, err_code, etc. */
+ uint16_t qdcount; /**< specifies the number of entries in the
+ question section */
+ uint16_t ancount; /**< specifies the number of entries in the
+ answer section */
+ uint16_t nscount; /**< specifies the number of entries in the
+ authority section */
+ uint16_t arcount; /**< specifies the number of entries in the
+ additional section */
+};
+
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>> PROTOTYPES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+static void
+dns_send_query(int8_t * domain_name);
+
+static void
+fill_dnshdr(uint8_t * packet, int8_t * domain_name);
+
+static uint8_t *
+dns_extract_name(uint8_t * dnsh, int8_t * head, int8_t * domain_name);
+
+static int8_t
+urltohost(char * url, char * host_name);
+
+static int8_t
+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 */
+static int8_t dns_domain_name[0x100]; /**< Raw domain name */
+static int8_t dns_domain_cname[0x100]; /**< Canonical domain name */
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+/**
+ * DNS: Initialize the environment for DNS client.
+ * 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");
+ return 0;
+}
+
+/**
+ * DNS: For given URL retrieves IPv4 from DNS-server.
+ * <p>
+ * URL can be given in one of the following form: <ul>
+ * <li> scheme with full path with (without) user and password
+ * <br>(e.g. "http://user:pass@www.host.org/url-path");
+ * <li> host name with url-path
+ * <br>(e.g. "www.host.org/url-path");
+ * <li> nothing but host name
+ * <br>(e.g. "www.host.org");
+ * </ul>
+ *
+ * @param url the URL to be resolved
+ * @param domain_ip In case of SUCCESS stores extracted IP.
+ * In case of FAULT stores zeros (0.0.0.0).
+ * @return TRUE - IP successfuly retrieved;
+ * FALSE - error condition occurs.
+ */
+int8_t
+dns_get_ip(int8_t * url, uint32_t * domain_ip) {
+ /* this counter is used so that we abort after 30 DNS request */
+ int32_t i;
+ /* this buffer stores host name retrieved from url */
+ static int8_t host_name[0x100];
+
+ (* domain_ip) = 0;
+
+ // Retrieve host name from URL
+ if (!urltohost((char *) url, (char *) host_name)) {
+ printf("\nERROR:\t\t\tBad URL!\n");
+ return 0;
+ }
+
+ // Reformat host name into a series of labels
+ if (!hosttodomain((char *) host_name, (char *) dns_domain_name)) {
+ printf("\nERROR:\t\t\tBad host name!\n");
+ return 0;
+ }
+
+ // Check if DNS server is presented and accessable
+ if (dns_server_ip == 0) {
+ printf("\nERROR:\t\t\tCan't resolve domain name "
+ "(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;
+ dns_error = 0;
+ strcpy((char *) dns_domain_cname, "");
+
+ for(i = 0; i < 30; ++i) {
+ // Use canonical name in case we obtained it
+ if (strlen((char *) dns_domain_cname))
+ dns_send_query(dns_domain_cname);
+ else
+ dns_send_query(dns_domain_name);
+
+ // setting up a timer with a timeout of one seconds
+ set_timer(TICKS_SEC);
+ do {
+ receive_ether();
+ if (dns_error)
+ return 0; // FALSE - error
+ if (dns_result_ip != 0) {
+ (* domain_ip) = dns_result_ip;
+ return 1; // TRUE - success (domain IP retrieved)
+ }
+ } while (get_timer() > 0);
+ }
+
+ printf("\nGiving up after %d DNS requests\n", i);
+ return 0; // FALSE - domain name wasn't retrieved
+}
+
+/**
+ * DNS: Handles DNS-messages according to Receive-handle diagram.
+ * Sets dns_result_ip for given dns_domain_name (see dns_get_ip)
+ * or signals error condition occurs during DNS-resolving proccess
+ * by setting dns_error flag.
+ *
+ * @param packet DNS-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 dns_get_ip
+ * @see receive_ether
+ * @see dnshdr
+ */
+int32_t
+handle_dns(uint8_t * packet, int32_t packetsize) {
+ struct dnshdr * dnsh = (struct dnshdr *) packet;
+ uint8_t * resp_section = packet + sizeof(struct dnshdr);
+ /* This string stores domain name from DNS-packets */
+ static int8_t handle_domain_name[0x100];
+ int i;
+
+ // verify ID - is it response for our query?
+ if (dnsh -> id != htons(0x1234))
+ return 0;
+
+ // Is it DNS response?
+ if ((dnsh -> flags & htons(DNS_FLAG_MSGTYPE)) != htons(DNS_FLAG_SRESPONSE))
+ return 0;
+
+ // 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;
+ }
+
+ /* Pass all (qdcount) records in question section */
+
+ for (i = 0; i < htons(dnsh -> qdcount); i++) {
+ // pass QNAME
+ resp_section = dns_extract_name((uint8_t *) dnsh, (int8_t *) resp_section,
+ handle_domain_name);
+ if (resp_section == NULL) {
+ return -1; // incorrect domain name (bad packet)
+ }
+ // pass QTYPE & QCLASS
+ resp_section += 4;
+ }
+
+ /* Handle all (ancount) records in answer section */
+
+ for (i = 0; i < htons(dnsh -> ancount); i++) {
+ // retrieve domain name from the packet
+ resp_section = dns_extract_name((uint8_t *) dnsh, (int8_t *) resp_section,
+ handle_domain_name);
+
+ if (resp_section == NULL) {
+ return -1; // incorrect domain name (bad packet)
+ }
+
+ // Check the class of the query (should be IN for Internet)
+ if (* (uint16_t *) (resp_section + 2) == htons(DNS_QCLASS_IN)) {
+ // check if retrieved name fit raw or canonical domain name
+ if (!strcmp((char *) handle_domain_name, (char *) dns_domain_name) ||
+ !strcmp((char *) handle_domain_name, (char *) dns_domain_cname)) {
+ switch (htons(* (uint16_t *) resp_section)) {
+
+ case DNS_QTYPE_A :
+ // rdata contains IP
+ dns_result_ip = htonl(* (uint32_t *) (resp_section + 10));
+ return 0; // IP successfully obtained
+
+ case DNS_QTYPE_CNAME :
+ // rdata contains canonical name, store it for further requests
+ if (dns_extract_name((uint8_t *) dnsh, (int8_t *) resp_section + 10,
+ dns_domain_cname) == NULL) {
+ // incorrect domain name (bad packet)
+ return -1;
+ }
+ break;
+ }
+ }
+ // continue with next record in answer section
+ resp_section += htons(* (uint16_t *) (resp_section + 8)) + 10;
+ }
+ }
+ return 0; // Packet succesfuly handled but IP wasn't obtained
+}
+
+/**
+ * DNS: Sends a standard DNS-query (read request package) to a DNS-server.
+ * DNS-server respones with host IP or signals some error condition.
+ * Responses from the server are handled by handle_dns function.
+ *
+ * @param domain_name the domain name given as series of labels preceded
+ * with length(label) and terminated with 0
+ * <br>(e.g. "\3,w,w,w,\4,h,o,s,t,\3,o,r,g,\0")
+ * @see handle_dns
+ */
+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) +
+ sizeof(struct udphdr) + sizeof(struct dnshdr) +
+ qry_len;
+
+ memset(ether_packet, 0, packetsize);
+ fill_dnshdr(&ether_packet[sizeof(struct ethhdr) +
+ sizeof(struct iphdr) + sizeof(struct udphdr)],
+ domain_name);
+ fill_udphdr(&ether_packet[sizeof(struct ethhdr) +
+ sizeof(struct iphdr)], sizeof(struct dnshdr) +
+ sizeof(struct udphdr) + qry_len,
+ UDPPORT_DNSC, UDPPORT_DNSS);
+ fill_iphdr(ether_packet + sizeof(struct ethhdr),
+ 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);
+
+ send(dns_device_socket, ether_packet, packetsize, 0);
+}
+
+/**
+ * DNS: Creates standard DNS-query package. Places DNS-header
+ * and question section in a packet and fills it with
+ * corresponding information.
+ * <p>
+ * Use this function with similar functions for other network layers
+ * (fill_udphdr, fill_iphdr, fill_ethhdr).
+ *
+ * @param packet Points to the place where ARP-header must be placed.
+ * @param domain_name the domain name given as series of labels preceded
+ * with length(label) and terminated with 0
+ * <br>(e.g. "\3,w,w,w,\4,h,o,s,t,\3,o,r,g,\0")
+ * @see fill_udphdr
+ * @see fill_iphdr
+ * @see fill_ethhdr
+ */
+static void
+fill_dnshdr(uint8_t * packet, int8_t * domain_name) {
+ struct dnshdr * dnsh = (struct dnshdr *) packet;
+ uint8_t * qry_section = packet + sizeof(struct dnshdr);
+
+ dnsh -> id = htons(0x1234);
+ dnsh -> flags = htons(DNS_FLAG_SQUERY) | htons(DNS_FLAG_RD);
+ dnsh -> qdcount = htons(1);
+
+ strcpy((char *) qry_section, (char *) domain_name);
+ qry_section += strlen((char *) domain_name) + 1;
+
+ // fill QTYPE (ask for IP)
+ * (uint16_t *) qry_section = htons(DNS_QTYPE_A);
+ qry_section += 2;
+ // fill QCLASS (IN is a standard class for Internet)
+ * (uint16_t *) qry_section = htons(DNS_QCLASS_IN);
+}
+
+/**
+ * DNS: Extracts domain name from the question or answer section of
+ * the DNS-message. This function is need to support message
+ * compression requirement (see RFC 1035, paragraph 4.1.4).
+ *
+ * @param dnsh Points at the DNS-header.
+ * @param head Points at the beginning of the domain_name
+ * which has to be extracted.
+ * @param domain_name In case of SUCCESS this string stores extracted name.
+ * In case of FAULT this string is empty.
+ * @return NULL in case of FAULT (domain name > 255 octets);
+ * otherwise pointer to the data following the name.
+ * @see dnshdr
+ */
+static uint8_t *
+dns_extract_name(uint8_t * dnsh, int8_t * head, int8_t * domain_name) {
+ int8_t * tail = domain_name;
+ int8_t * ptr = head;
+ int8_t * next_section = NULL;
+
+ while (1) {
+ if ((ptr[0] & 0xC0) == 0xC0) {
+ // message compressed (reference is used)
+ next_section = ptr + 2;
+ ptr = (int8_t *) dnsh + (htons(* (uint16_t *) ptr) & 0x3FFF);
+ continue;
+ }
+ if (ptr[0] == 0) {
+ // message termination
+ tail[0] = 0;
+ ptr += 1;
+ break;
+ }
+ // maximum length for domain name is 255 octets w/o termination sym
+ if (tail - domain_name + ptr[0] + 1 > 255) {
+ strcpy((char *) domain_name, "");
+ return NULL;
+ }
+ memcpy(tail, ptr, ptr[0] + 1);
+ tail += ptr[0] + 1;
+ ptr += ptr[0] + 1;
+ }
+
+ if (next_section == NULL)
+ next_section = ptr;
+
+ return (uint8_t *) next_section;
+}
+
+/**
+ * DNS: Parses URL and returns host name.
+ * Input string can be given as: <ul>
+ * <li> scheme with full path with (without) user and password
+ * <br>(e.g. "http://user:pass@www.host.org/url-path");
+ * <li> host name with url-path
+ * <br>(e.g. "www.host.org/url-path");
+ * <li> nothing but host name
+ * <br>(e.g. "www.host.org");
+ * </ul>
+ *
+ * @param url string that stores incoming URL
+ * @param host_name In case of SUCCESS this string stores the host name,
+ * In case of FAULT this string is empty.
+ * @return TRUE - host name retrieved,
+ * FALSE - host name > 255 octets or empty.
+ */
+static int8_t
+urltohost(char * url, char * host_name) {
+ uint16_t length1;
+ uint16_t length2;
+
+ strcpy(host_name, "");
+
+ if (strstr(url, "://") != NULL)
+ url = strstr(url, "//") + 2; // URL
+
+ if (strstr(url, "@") != NULL) // truncate user & password
+ url = strstr(url, "@") + 1;
+
+ if (strstr(url, "/") != NULL) // truncate url path
+ length1 = strstr(url, "/") - url;
+ else
+ length1 = strlen(url);
+
+ if (strstr(url, ":") != NULL) // truncate port path
+ length2 = strstr(url, ":") - url;
+ else
+ length2 = strlen(url);
+
+ if(length1 > length2)
+ length1 = length2;
+
+ if (length1 == 0)
+ return 0; // string is empty
+ if(length1 >= 256)
+ return 0; // host name is too big
+
+ strncpy(host_name, url, length1);
+ host_name[length1] = 0;
+
+ return 1; // Host name is retrieved
+}
+
+/**
+ * DNS: Transforms host name string into a series of labels
+ * each of them preceded with length(label). 0 is a terminator.
+ * "www.domain.dom" -> "\3,w,w,w,\6,d,o,m,a,i,n,\3,c,o,m,\0"
+ * <p>
+ * This format is used in DNS-messages.
+ *
+ * @param host_name incoming string with the host name
+ * @param domain_name resulting string with series of labels
+ * or empty string in case of FAULT
+ * @return TRUE - host name transformed,
+ * FALSE - host name > 255 octets or label > 63 octets.
+ */
+static int8_t
+hosttodomain(char * host_name, char * domain_name) {
+ char * domain_iter = domain_name;
+ char * host_iter = host_name;
+
+ strcpy(domain_name, "");
+
+ if(strlen(host_name) > 255)
+ return 0; // invalid host name (refer to RFC 1035)
+
+ for(; 1; ++host_iter) {
+ if(*host_iter != '.' && *host_iter != 0)
+ continue;
+ *domain_iter = host_iter - host_name;
+ if (*domain_iter > 63) {
+ strcpy(domain_name, "");
+ return 0; // invalid host name (refer to RFC 1035)
+ }
+ ++domain_iter;
+ strncpy(domain_iter, host_name, host_iter - host_name);
+ domain_iter += (host_iter - host_name);
+ if(*host_iter == 0) {
+ *domain_iter = 0;
+ break;
+ }
+ host_name = host_iter + 1;
+ }
+ return 1; // ok
+}
diff --git a/clients/net-snk/app/netlib/dns.h b/clients/net-snk/app/netlib/dns.h
new file mode 100644
index 0000000..5bf0f84
--- /dev/null
+++ b/clients/net-snk/app/netlib/dns.h
@@ -0,0 +1,21 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+
+/* 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);
+
+/* 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);
diff --git a/clients/net-snk/app/netlib/icmp.c b/clients/net-snk/app/netlib/icmp.c
new file mode 100644
index 0000000..a767de4
--- /dev/null
+++ b/clients/net-snk/app/netlib/icmp.c
@@ -0,0 +1,98 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+#include <netlib/icmp.h>
+#include <netlib/arp.h>
+#include <netlib/netbase.h>
+#include <sys/socket.h>
+#include <string.h>
+#include <time.h>
+
+/* from bootp.c */
+unsigned short checksum(unsigned short *, int);
+
+int
+handle_icmp(struct icmphdr *icmp)
+{
+ /* we currently only handle type 3 (detination unreachable)
+ * ICMP messages */
+ if (icmp->type != 3)
+ return 0;
+ return -icmp->code - 10;
+}
+
+static void
+fill_icmp_echo_data(unsigned char *data, int length)
+{
+ char *filler = "SLOF";
+ if (length <= 0)
+ return;
+ do {
+ memcpy(data, filler,
+ (length >= strlen(filler)) ? strlen(filler) : length);
+ data += strlen(filler);
+ } while ((length -= strlen(filler)) > 0);
+}
+
+int
+echo_request(int device, filename_ip_t * fn_ip, unsigned int timeout)
+{
+ unsigned int packetsize =
+ sizeof(struct ethhdr) + sizeof(struct iphdr) +
+ sizeof(struct icmphdr);
+ unsigned char packet[packetsize * 2];
+ struct icmphdr *icmp;
+ int i;
+ struct iphdr *ip;
+ struct ethhdr *ethh;
+ memset(packet, 0, packetsize);
+ fill_ethhdr(packet, htons(ETHERTYPE_IP), fn_ip->own_mac,
+ fn_ip->server_mac);
+ ethh = (struct ethhdr *) packet;
+ fill_iphdr(packet + sizeof(struct ethhdr),
+ sizeof(struct iphdr) + sizeof(struct icmphdr), IPTYPE_ICMP,
+ fn_ip->own_ip, fn_ip->server_ip);
+ icmp =
+ (struct icmphdr *) ((void *) (packet + sizeof(struct ethhdr)) +
+ sizeof(struct iphdr));
+ ip = (struct iphdr *) (packet + sizeof(struct ethhdr));
+ icmp->type = 8;
+ icmp->code = 0;
+ icmp->checksum = 0;
+ icmp->options.echo.id = 0xd476;
+ icmp->options.echo.seq = 1;
+ fill_icmp_echo_data(icmp->payload.data, sizeof(icmp->payload.data));
+ icmp->checksum =
+ checksum((unsigned short *) icmp, sizeof(struct icmphdr) >> 1);
+ send(device, packet, packetsize, 0);
+ set_timer(TICKS_SEC / 10 * timeout);
+ do {
+ memset(packet, 0, packetsize);
+ i = recv(device, packet, packetsize * 2, 0);
+ if (i == 0)
+ continue;
+ if (ethh->type == htons(ETHERTYPE_ARP)) {
+ handle_arp(packet + sizeof(struct ethhdr), i);
+ continue;
+ }
+ if (ip->ip_p != PROTO_ICMP)
+ continue;
+ if (icmp->type != 0)
+ continue;
+ if (icmp->options.echo.id != 0xd476)
+ continue;
+ if (icmp->options.echo.seq != 1)
+ continue;
+ return 0;
+ } while (get_timer() > 0);
+ return -1;
+}
diff --git a/clients/net-snk/app/netlib/icmp.h b/clients/net-snk/app/netlib/icmp.h
new file mode 100644
index 0000000..ad98eba
--- /dev/null
+++ b/clients/net-snk/app/netlib/icmp.h
@@ -0,0 +1,75 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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 _ICMP_H_
+#define _ICMP_H_
+
+#include <netlib/netlib.h>
+
+/* RFC 792 - Internet Control Message Protocol
+
+ http://www.faqs.org/rfcs/rfc792.html
+
+Summary of Message Types
+ 0 Echo Reply
+ 3 Destination Unreachable
+ 4 Source Quench
+ 5 Redirect
+ 8 Echo
+ 11 Time Exceeded
+ 12 Parameter Problem
+ 13 Timestamp
+ 14 Timestamp Reply
+ 15 Information Request
+ 16 Information Reply
+*/
+
+#define PROTO_ICMP 1
+
+#define ICMP_TYPE_DEST_UNREACHABLE 3
+
+#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 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;
+};
+
+int handle_icmp(struct icmphdr *);
+int echo_request(int, filename_ip_t *, unsigned int);
+
+#endif /* _ICMP_H_ */
diff --git a/clients/net-snk/app/netlib/netbase.c b/clients/net-snk/app/netlib/netbase.c
new file mode 100644
index 0000000..a82522d
--- /dev/null
+++ b/clients/net-snk/app/netlib/netbase.c
@@ -0,0 +1,451 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ * Receive packet (receive_ether)
+ * | |
+ * | |
+ * | Ethernet (handle_ether)
+ * | |
+ * | +-----------+---------+
+ * | | |
+ * | ARP (handle_arp) IP (handle_ip)
+ * | |
+ * | |
+ * | UDP (handle_udp)
+ * | |
+ * V +----------------+-----------+
+ * | |
+ * upper DNS (handle_dns) BootP / DHCP (handle_bootp_client)
+ *
+ * ************************************************************************
+ * </pre> */
+
+
+/*>>>>>>>>>>>>>>>>>>>>>>> DEFINITIONS & DECLARATIONS <<<<<<<<<<<<<<<<<<<<*/
+
+#include <types.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <sys/socket.h>
+#include <netlib/netlib.h>
+#include <netlib/netbase.h>
+#include <netlib/arp.h>
+#include <netlib/dhcp.h>
+#include <netlib/dns.h>
+
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> PROTOTYPES <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+static int8_t
+handle_ip(uint8_t * packet, int32_t packetsize);
+
+static int8_t
+handle_udp(uint8_t * packet, int32_t packetsize);
+
+static unsigned short
+checksum(unsigned short *packet, int words);
+
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+static uint8_t ether_packet[ETH_MTU_SIZE];
+static int32_t net_device_socket = 0;
+static uint8_t net_own_mac[6];
+static uint32_t net_own_ip = 0;
+
+/* Routing parameters */
+static uint32_t net_router_ip = 0;
+static uint8_t net_router_mac[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+static uint32_t net_subnet_mask = 0;
+
+
+
+/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> IMPLEMENTATION <<<<<<<<<<<<<<<<<<<<<<<<<<*/
+
+/**
+ * NET: Initializes basic network enviroment and ARP-client.
+ *
+ * @param device_socket a socket number used to send and recieve packets
+ * @param own_mac own hardware-address (MAC)
+ * @param own_ip own IPv4 address (e.g. 127.0.0.1)
+ */
+void
+netbase_init(int32_t device_socket, uint8_t * own_mac, uint32_t own_ip) {
+ net_device_socket = device_socket;
+ if (own_mac)
+ memcpy(net_own_mac, own_mac, 6);
+ else
+ memset(net_own_mac, 0, 6);
+ net_own_ip = own_ip;
+ arp_init(device_socket, own_mac, own_ip);
+}
+
+/**
+ * NET: Sets routing parameters.
+ * For more information see net_iptomac function.
+ *
+ * @param router_ip IP address of the router
+ * @param subnet_mask Subnet mask
+ * @see net_iptomac
+ * @return TRUE - router was installed;
+ * FALSE - error condition occurs.
+ */
+int8_t
+net_setrouter(uint32_t router_ip, uint32_t subnet_mask) {
+ net_subnet_mask = subnet_mask;
+ net_router_ip = router_ip;
+
+ if(router_ip != 0) {
+ PRINT_MSGIP("\nRouter IP:\t\t", net_router_ip);
+ if (arp_getmac(net_router_ip, net_router_mac)) {
+ PRINT_MSGMAC("Router MAC:\t\t", net_router_mac);
+ return 1;
+ }
+ }
+
+ memset(net_router_mac, 0, 6);
+ NET_DEBUG_PRINTF("WARNING:\t\tCan't obtain router MAC!\n");
+ return 0;
+}
+
+/**
+ * NET: For given IP retrieves MAC address (or sets router MAC).
+ * To set routing parameters use net_setrouter function.
+ *
+ * @param dest_ip IP address of the host
+ * @param dest_mac in case of SUCCESS stores MAC address of the host;
+ * in case of FAULT filled with zeros.
+ * @see net_setrouter
+ * @return TRUE - destination MAC address was obtained;
+ * FALSE - can't obtain destination MAC address
+ */
+int8_t
+net_iptomac(uint32_t dest_ip, uint8_t dest_mac[]) {
+ /* check if dest_ip and own_ip are in the same subnet */
+ if ((net_subnet_mask & net_own_ip) ==
+ (net_subnet_mask & dest_ip)) {
+ /* In the same subnet - use ARP to obtain DNS-server MAC */
+ if (!arp_getmac(dest_ip, dest_mac)) {
+ NET_DEBUG_PRINTF("\nWARNING:\t\tCan't retrieve MAC!\n");
+ memset(dest_mac, 0, 6);
+ return 0;
+ }
+ return 1;
+ }
+
+ /* In different subnets - check if router is presented */
+ if (net_router_mac[0] != 0 || net_router_mac[1] != 0
+ || net_router_mac[2] != 0 || net_router_mac[3] != 0
+ || net_router_mac[4] != 0 || net_router_mac[5] != 0) {
+ /* Use router MAC-address for DNS-connections */
+ memcpy(dest_mac, net_router_mac, 6);
+ return 1;
+ }
+
+ NET_DEBUG_PRINTF("\nWARNING:\t\tCan't obtain MAC (router is not presented)!\n");
+ return 0;
+}
+
+/**
+ * NET: 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(net_device_socket, ether_packet, ETH_MTU_SIZE, 0);
+
+ if (!bytes_received) // No messages
+ return 0;
+
+ PRINT_RECEIVED(ether_packet, bytes_received);
+
+ if (bytes_received < sizeof(struct ethhdr))
+ return -1; // packet is too small
+
+ ethh = (struct ethhdr *) ether_packet;
+
+ switch (htons(ethh -> type)) {
+ case ETHERTYPE_IP:
+ return handle_ip(ether_packet + sizeof(struct ethhdr),
+ bytes_received - sizeof(struct ethhdr));
+ case ETHERTYPE_ARP:
+ return handle_arp(ether_packet + sizeof(struct ethhdr),
+ bytes_received - sizeof(struct ethhdr));
+ default:
+ break;
+ }
+ return -1; // unknown protocol
+}
+
+/**
+ * NET: Handles IP-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
+ */
+static int8_t
+handle_ip(uint8_t * ip_packet, int32_t packetsize) {
+ struct iphdr * iph;
+ int32_t old_sum;
+
+ if (packetsize < sizeof(struct iphdr))
+ return -1; // packet is too small
+
+ iph = (struct iphdr * ) ip_packet;
+
+ 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
+
+ switch (iph -> ip_p) {
+ case IPTYPE_UDP:
+ return handle_udp(ip_packet + sizeof(struct iphdr),
+ iph -> ip_len - sizeof(struct iphdr));
+ default:
+ break;
+ }
+ return -1; // Unknown protocol
+}
+
+/**
+ * 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
+ */
+static 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;
+ default:
+ return -1;
+ }
+}
+
+/**
+ * NET: 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,
+ uint8_t * src_mac, 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);
+}
+
+/**
+ * NET: 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;
+ iph -> ip_sum = checksum((unsigned short *) iph, sizeof(struct iphdr) >> 1);
+}
+
+/**
+ * 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);
+}
+
+/**
+ * NET: 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;
+}
+
+
+#ifdef NET_DEBUG // Printing for debugging purposes
+
+/**
+ * DEBUG: Dumps ethernet-packet with appropriate header names.
+ *
+ * @param packet Points to the ethernet-packet.
+ * @param packetsize Size of the packet in bytes.
+ */
+void
+net_print_packet(uint8_t * packet, uint16_t packetsize) {
+ struct ethhdr * ethh = (struct ethhdr *) packet;
+ struct iphdr * iph;
+ struct udphdr * udph;
+ struct btphdr * btph;
+ struct dnshdr * dnsh;
+ struct arphdr * arph;
+
+ PRINT_HDR("ETH:\t\t", (uint8_t *) ethh, sizeof(struct ethhdr));
+
+ switch (htons(ethh -> type)) {
+ case ETHERTYPE_IP :
+ iph = (struct iphdr *) (packet + sizeof(struct ethhdr));
+ PRINT_HDR("IP:\t\t", (uint8_t *) iph, sizeof(struct iphdr));
+ switch (iph -> ip_p) {
+ case IPTYPE_UDP:
+ udph = (struct udphdr *) (packet +
+ sizeof(struct ethhdr) +
+ sizeof(struct iphdr));
+ PRINT_HDR("UDP:\t\t", (uint8_t *) udph, sizeof(struct udphdr));
+ switch (htons(udph -> uh_dport)) {
+ case UDPPORT_BOOTPC: case UDPPORT_BOOTPS:
+ btph = (struct btphdr *) (packet +
+ sizeof(struct ethhdr) +
+ sizeof(struct iphdr) +
+ sizeof(struct udphdr));
+ PRINT_HDR("DHCP/BootP:\t", (uint8_t *) btph,
+ packetsize - sizeof(struct ethhdr) -
+ sizeof(struct iphdr) -
+ sizeof(struct udphdr));
+ break;
+ case UDPPORT_DNSC: case UDPPORT_DNSS:
+ dnsh = (struct dnshdr *) (packet +
+ sizeof(struct ethhdr) +
+ sizeof(struct iphdr) +
+ sizeof(struct udphdr));
+ PRINT_HDR("DNS:\t\t", (uint8_t *) dnsh,
+ packetsize - sizeof(struct ethhdr) -
+ sizeof(struct iphdr) -
+ sizeof(struct udphdr));
+ break;
+ }
+ break;
+ }
+ break;
+ case ETHERTYPE_ARP:
+ arph = (struct arphdr *) (packet + sizeof(struct ethhdr));
+ PRINT_HDR("ARP:\t\t", (uint8_t *) arph, sizeof(struct arphdr));
+ break;
+ }
+}
+
+#endif
diff --git a/clients/net-snk/app/netlib/netbase.h b/clients/net-snk/app/netlib/netbase.h
new file mode 100644
index 0000000..c0f5afb
--- /dev/null
+++ b/clients/net-snk/app/netlib/netbase.h
@@ -0,0 +1,138 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+/* Network debug switches */
+
+/* main debug switch, without this switch the others don't work */
+// #define NET_DEBUG
+
+/* show received data */
+// #define NET_SHOW_RECV
+
+/* show transmitted data */
+// #define NET_SHOW_XMIT
+
+#include <types.h>
+
+/* Initializes basic network enviroment and ARP-client */
+extern void netbase_init(int32_t device_socket, uint8_t * own_mac, uint32_t own_ip);
+
+/* Sets routing parameters */
+extern int8_t net_setrouter(uint32_t router_ip, uint32_t subnet_mask);
+
+/* For given IP retrieves MAC address (or sets router MAC) */
+extern int8_t net_iptomac(uint32_t dest_ip, uint8_t dest_mac[]);
+
+/* Receives and handles packets, according to Receive-handle diagram */
+extern int32_t receive_ether(void);
+
+/* fills ethernet header */
+extern void fill_ethhdr(uint8_t * packet, uint16_t eth_type,
+ uint8_t * src_mac, uint8_t * dest_mac);
+
+/* 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);
+
+/* fills udp header */
+extern void fill_udphdr(uint8_t *packet, uint16_t packetsize,
+ uint16_t src_port, uint16_t dest_port);
+
+#ifdef NET_DEBUG
+
+
+/* DEBUG: Dumps ethernet-packet with appropriate header names */
+extern void net_print_packet(uint8_t * packet, uint16_t packetsize);
+
+
+#define NET_DEBUG_PRINTF(format, ...) printf(format, ## __VA_ARGS__)
+
+
+/* Prints message and IP in the following format: "DDD.DDD.DDD.DDD" */
+#define PRINT_MSGIP(msg, ip) \
+ do { \
+ printf("%s%03d.%03d.%03d.%03d\n", msg, \
+ (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, \
+ (ip >> 8) & 0xFF, (ip >> 0) & 0xFF); \
+ } while (0)
+
+
+/* Prints message and MAC in the following format "XX.XX.XX.XX.XX.XX" */
+#define PRINT_MSGMAC(msg, mac) \
+ do { \
+ printf("%s%02X:%02X:%02X:%02X:%02X:%02X\n", msg, \
+ mac[0], mac[1], mac[2], \
+ mac[3], mac[4], mac[5]); \
+ } while (0)
+
+
+/* Prints packet header in the following form: "msg: XX XX XX ... XX" */
+#define PRINT_HDR(msg, hdr, hdrsize) \
+ do { \
+ uint16_t i, j; \
+ printf("%s", msg); \
+ for (i = 0; i < hdrsize; ) { \
+ for (j = 0; j < 20; j++, i++) \
+ printf("%2x ", * (hdr + i)); \
+ printf("\n\t\t"); \
+ } \
+ printf("\n"); \
+ } while (0)
+
+
+#ifdef NET_SHOW_XMIT
+
+/* Prints "sending" packet with approp. header names */
+#define PRINT_SENDING(packet, packetsize) \
+ do { \
+ printf("\nSending packet, size:\t%d\n", packetsize); \
+ net_print_packet(packet, packetsize); \
+ } while (0)
+
+#else
+
+#define PRINT_SENDING(packet, packetsize)
+
+#endif
+
+#ifdef NET_SHOW_RECV
+
+/* Prints "received" packet with approp. header names */
+#define PRINT_RECEIVED(packet, packetsize) \
+ do { \
+ printf("\nReceived packet, size:\t%d\n", packetsize); \
+ net_print_packet(packet, packetsize); \
+ } while (0)
+
+#else
+
+#define PRINT_RECEIVED(packet, packetsize)
+
+#endif
+
+#else // NET_DEBUG not defined
+
+#define NET_DEBUG_PRINTF(format, ...)
+
+#define PRINT_MSGIP(msg, ip)
+
+#define PRINT_MSGMAC(msg, mac)
+
+#define PRINT_HDR(msg, hdr, hdrsize)
+
+#define NET_PRINT_PACKET(packet, packetsize)
+
+#define PRINT_SENDING(packet, packetsize)
+
+#define PRINT_RECEIVED(packet, packetsize)
+
+#endif
diff --git a/clients/net-snk/app/netlib/netlib.h b/clients/net-snk/app/netlib/netlib.h
new file mode 100644
index 0000000..752df1f
--- /dev/null
+++ b/clients/net-snk/app/netlib/netlib.h
@@ -0,0 +1,146 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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 _NETLIB_H_
+#define _NETLIB_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_ARP 0x0806
+
+#define IPTYPE_ICMP 1
+#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 */
+
+typedef int32_t socklen_t;
+
+/** \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 */
+};
+
+/** \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 */
+};
+
+struct pseudo_iphdr {
+ uint32_t ip_src;
+ uint32_t ip_dst;
+ int8_t ip_unused;
+ uint8_t ip_p;
+ uint16_t ip_ulen;
+};
+
+/** \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 */
+};
+
+/** \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) */
+};
+
+struct tftphdr {
+ int16_t th_opcode;
+ uint16_t th_data;
+};
+
+
+/** \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));
+
+typedef struct {
+ uint32_t own_ip;
+ uint32_t server_ip;
+ uint8_t own_mac[6]; // unsigned
+ uint8_t server_mac[6]; // unsigned
+ int8_t filename[256];
+} filename_ip_t;
+
+int dhcp(int32_t, filename_ip_t *, unsigned int);
+void dhcp_send_release(void);
+
+int bootp(int32_t, filename_ip_t *, unsigned int);
+
+typedef struct {
+ uint32_t bad_tftp_packets;
+ uint32_t no_packets;
+ uint32_t blocks_missed;
+ uint32_t blocks_received;
+} tftp_err_t;
+
+int tftp(int, filename_ip_t *, unsigned char *, int, unsigned int, tftp_err_t *);
+int tftp_netsave(int32_t, filename_ip_t *, uint8_t * buffer, int32_t len,
+ int use_ci, unsigned int retries, tftp_err_t * tftp_err);
+
+#endif /* _NETLIB_H_ */
diff --git a/clients/net-snk/app/netlib/tftp.c b/clients/net-snk/app/netlib/tftp.c
new file mode 100644
index 0000000..7536770
--- /dev/null
+++ b/clients/net-snk/app/netlib/tftp.c
@@ -0,0 +1,658 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/socket.h>
+
+#include <netlib/netlib.h>
+#include <netlib/icmp.h>
+
+//#define __DEBUG__
+
+#define BUFFER_LEN 2048
+#define ACK_BUFFER_LEN 256
+#define READ_BUFFER_LEN 256
+
+#define ENOTFOUND 1
+#define EACCESS 2
+#define EBADOP 4
+#define EBADID 5
+#define ENOUSER 7
+//#define EUNDEF 0
+//#define ENOSPACE 3
+//#define EEXISTS 6
+
+#define RRQ 1
+#define WRQ 2
+#define DATA 3
+#define ACK 4
+#define ERROR 5
+#define OACK 6
+
+/**
+ * dump_package - Prints a package.
+ *
+ * @package: package which is to print
+ * @len: length of the package
+ */
+#ifdef __DEBUG__
+
+static void
+dump_package(unsigned char *buffer, unsigned int len)
+{
+ int i;
+
+ for (i = 1; i <= len; i++) {
+ printf("%02x%02x ", buffer[i - 1], buffer[i]);
+ i++;
+ if ((i % 16) == 0)
+ printf("\n");
+ }
+ printf("\n");
+}
+#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)
+{
+ int i;
+ 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 };
+
+ 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)
+ + strlen((char *) fn_ip->filename) + strlen((char *) mode) + 4
+ + strlen("blksize") + strlen("1432") + 2);
+
+ tftp = (struct tftphdr *) (udph + 1);
+ tftp->th_opcode = htons(RRQ);
+
+ ptr = (char *) &tftp->th_data;
+ memcpy(ptr, fn_ip->filename, strlen((char *) fn_ip->filename) + 1);
+
+ ptr += strlen((char *) fn_ip->filename) + 1;
+ memcpy(ptr, mode, strlen((char *) mode) + 1);
+
+ ptr += strlen((char *) mode) + 1;
+ memcpy(ptr, "blksize", strlen("blksize") + 1);
+
+ ptr += strlen("blksize") + 1;
+ memcpy(ptr, "1432", strlen("1432") + 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;
+
+ 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);
+#endif
+ return;
+}
+
+/**
+ * send_ack - Sends a acknowlege package.
+ *
+ * @boot_device:
+ * @fn_ip:
+ * @blckno: block number
+ */
+static void
+send_ack(int boot_device, filename_ip_t * fn_ip,
+ int blckno, unsigned short dport)
+{
+ int i;
+ unsigned char packet[ACK_BUFFER_LEN];
+ struct ethhdr *ethh;
+ struct iphdr *ip;
+ struct udphdr *udph;
+ struct tftphdr *tftp;
+ struct pseudo_iphdr piph = { 0 };
+
+ 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);
+
+ 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);
+
+#ifdef __DEBUG__
+ printf("tftp ACK %d bytes transmitted over socket.\n", i);
+#endif
+
+ return;
+}
+
+/**
+ * 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)
+{
+ int i;
+ unsigned char packet[256];
+ struct ethhdr *ethh;
+ struct iphdr *ip;
+ struct udphdr *udph;
+ struct tftphdr *tftp;
+ struct pseudo_iphdr piph = { 0 };
+
+ 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);
+
+ 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);
+
+#ifdef __DEBUG__
+ printf("tftp ERROR %d bytes transmitted over socket.\n", i);
+#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)
+{
+ static unsigned int i = 1;
+ static int first = -1;
+ static int last_bytes = 0;
+ char buffer[100];
+ char *ptr;
+
+ // 1MB steps or 0x400 times or urgent
+ if(((received_bytes - last_bytes) >> 20) > 0
+ || (i & 0x3FF) == 0 || urgent) {
+ if(!first) {
+ sprintf(buffer, "%d KBytes", (last_bytes >> 10));
+ for(ptr = buffer; *ptr != 0; ++ptr)
+ *ptr = '\b';
+ printf(buffer);
+ }
+ printf("%d KBytes", (received_bytes >> 10));
+ i = 1;
+ first = 0;
+ last_bytes = received_bytes;
+ }
+ ++i;
+}
+
+/**
+ * get_blksize tries to extract the blksize from the OACK package
+ * the TFTP returned. From RFC 1782
+ * The OACK packet has the following format:
+ *
+ * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+
+ * | opc | opt1 | 0 | value1 | 0 | optN | 0 | valueN | 0 |
+ * +-------+---~~---+---+---~~---+---+---~~---+---+---~~---+---+
+ *
+ * @param buffer the network packet
+ * @param len the length of the network packet
+ * @return the blocksize the server supports or 0 for error
+ */
+static int
+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;
+ while (buffer < orig + len) {
+ if (!memcmp(buffer, "blksize", strlen("blksize") + 1))
+ return (unsigned short) strtoul((char *) (buffer +
+ strlen("blksize") + 1),
+ (char **) NULL, 10);
+ else {
+ /* skip the option name */
+ buffer = (unsigned char *) strchr((char *) buffer, 0);
+ if (!buffer)
+ return 0;
+ buffer++;
+ /* skip the option value */
+ buffer = (unsigned char *) strchr((char *) buffer, 0);
+ if (!buffer)
+ return 0;
+ buffer++;
+ }
+ }
+ return 0;
+}
+
+/**
+ * this 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)
+ */
+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 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;
+
+ 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);
+#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;
+ }
+
+ 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 ");
+#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;
+ }
+
+ /* only IPv4 UDP packets we want */
+ if (ip->ip_hlv != 0x45 || ip->ip_p != 0x11) {
+#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);
+#endif
+ continue;
+ }
+
+ /* 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) {
+#ifdef __DEBUG__
+ printf("tftp->th_opcode : %x\n", tftp->th_opcode);
+ printf("tftp->th_data : %x\n", tftp->th_data);
+#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 (tftp->th_data == block + 1)
+ block++;
+ 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+ ");
+#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) {
+#ifdef __DEBUG__
+ printf
+ ("\nTFTP: Received block %x, expected block was %x\n",
+ tftp->th_data, block + 1);
+ 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)
+ return -9;
+ } else {
+#ifdef __DEBUG__
+ printf("Unknown packet %x\n", tftp->th_opcode);
+ printf("\b# ");
+#endif
+ tftp_err->bad_tftp_packets++;
+ continue;
+ }
+ }
+ 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)
+{
+ return the_real_tftp(boot_device, fn_ip, buffer, len, retries,
+ tftp_err);
+}
diff --git a/clients/net-snk/client.lds b/clients/net-snk/client.lds
new file mode 100644
index 0000000..5943897
--- /dev/null
+++ b/clients/net-snk/client.lds
@@ -0,0 +1,51 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", "elf64-powerpc")
+OUTPUT_ARCH(powerpc:common64)
+ENTRY(_entry)
+
+SECTIONS {
+ .client 0xF000000:
+ {
+ __client_start = .;
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ *(.sfpr .glink)
+ *(.rodata .rodata.* .gnu.linkonce.r.*)
+ KEEP (*(.opd))
+ . = ALIGN(256);
+ *(.data .data.* .gnu.linkonce.d.*)
+ . = ALIGN(256);
+ } =0x60000000
+
+ .lowmem :
+ {
+ _lowmem_start = .;
+ *(.lowmem)
+ _lowmem_end = .;
+ }
+
+ .got :
+ {
+ . = ALIGN(8);
+ _got = .;
+ *(.got .toc)
+ _got_end = .;
+ }
+ .comment : { *(.comment) }
+ .branch_lt : { *(.branch_lt) }
+ .bss :
+ {
+ *(*COM* .bss .gnu.linkonce.b.*)
+ __client_end = .;
+ }
+}
diff --git a/clients/net-snk/include/crt0.h b/clients/net-snk/include/crt0.h
new file mode 100644
index 0000000..4b8ee89
--- /dev/null
+++ b/clients/net-snk/include/crt0.h
@@ -0,0 +1,20 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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 _CRT0_H
+#define _CRT0_H
+
+int gen_argv(const char *, int, char **);
+
+
+#endif
diff --git a/clients/net-snk/include/endian.h b/clients/net-snk/include/endian.h
new file mode 100644
index 0000000..e57317d
--- /dev/null
+++ b/clients/net-snk/include/endian.h
@@ -0,0 +1,46 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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 MY_ENDIAN_H
+#define MY_ENDIAN_H
+
+#include "types.h"
+
+extern inline uint16_t bswap_16 (uint16_t x);
+extern inline uint32_t bswap_32 (uint32_t x);
+extern inline uint64_t bswap_64 (uint64_t x);
+#define CPU_BIG_ENDIAN
+
+#ifndef CPU_BIG_ENDIAN
+#define cpu_to_le64(x) (x)
+#define cpu_to_le32(x) (x)
+#define cpu_to_le16(x) (x)
+#define cpu_to_be16(x) bswap_16(x)
+#define cpu_to_be32(x) bswap_32(x)
+#define le64_to_cpu(x) (x)
+#define le32_to_cpu(x) (x)
+#define le16_to_cpu(x) (x)
+#define be32_to_cpu(x) bswap_32(x)
+#else
+#define cpu_to_le64(x) bswap_64(x)
+#define cpu_to_le32(x) bswap_32(x)
+#define cpu_to_le16(x) bswap_16(x)
+#define cpu_to_be16(x) (x)
+#define cpu_to_be32(x) (x)
+#define le64_to_cpu(x) bswap_64(x)
+#define le32_to_cpu(x) bswap_32(x)
+#define le16_to_cpu(x) bswap_16(x)
+#define be32_to_cpu(x) (x)
+#endif
+
+#endif
diff --git a/clients/net-snk/include/fcntl.h b/clients/net-snk/include/fcntl.h
new file mode 100644
index 0000000..80b7846
--- /dev/null
+++ b/clients/net-snk/include/fcntl.h
@@ -0,0 +1,25 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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 _FCNTL_H
+#define _FCNTL_H
+
+#define O_RDONLY 00
+#define O_WRONLY 01
+#define O_RDRW 02
+
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
+#endif /* fcntl.h */
diff --git a/clients/net-snk/include/ioctl.h b/clients/net-snk/include/ioctl.h
new file mode 100644
index 0000000..1991bfc
--- /dev/null
+++ b/clients/net-snk/include/ioctl.h
@@ -0,0 +1,19 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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 _IOCTL_H
+#define _IOCTL_H
+
+extern int ioctl(int fd, int request, void *data);
+
+#endif
diff --git a/clients/net-snk/include/kernel.h b/clients/net-snk/include/kernel.h
new file mode 100644
index 0000000..531d82c
--- /dev/null
+++ b/clients/net-snk/include/kernel.h
@@ -0,0 +1,32 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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 KERNEL_H
+#define KERNEL_H
+#include <stddef.h>
+
+int printk(const char *, ...);
+void *memcpy(void *, const void *, size_t);
+void *memset(void *, int, size_t);
+void udelay(unsigned int);
+void mdelay(unsigned int);
+int getchar(void);
+
+int strcmp(const char *, const char *);
+char *strcpy(char *, const char *);
+int printf(const char *, ...);
+void *malloc_aligned(size_t size, int align);
+
+void exception_forward(void);
+void undo_exception(void);
+
+#endif
diff --git a/clients/net-snk/include/macros.h b/clients/net-snk/include/macros.h
new file mode 100644
index 0000000..9c86ea5
--- /dev/null
+++ b/clients/net-snk/include/macros.h
@@ -0,0 +1,72 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+
+#define LOAD64(rn,name) \
+ lis rn,name##@highest; \
+ ori rn,rn,name##@higher; \
+ rldicr rn,rn,32,31; \
+ oris rn,rn,name##@h; \
+ ori rn,rn,name##@l
+
+#define LOAD32(rn, name) \
+ lis rn,name##@h; \
+ ori rn,rn,name##@l
+
+// load 32 bit constant in little endian order
+#define LOAD32le(rn,name) \
+ lis rn,(((name>>8)&0x00FF)|((name<<8)&0xFF00)); \
+ ori rn,rn,(((name>>24)&0x00FF)|((name>>8)&0xFF00))
+
+// load 16 bit constant in little endian order
+#define LOAD16le(rn,name) \
+ li rn,(((name>>8)&0x00FF)|(name<<8))
+
+#define SET_CI(rn) \
+ sync; \
+ mfspr rn,LPCR; \
+ ori rn,rn,2; \
+ mtspr LPCR,rn; \
+ sync
+
+#define CLR_CI(rn) \
+ sync; \
+ mfspr rn,LPCR; \
+ ori rn,rn,2; \
+ xori rn,rn,2; \
+ mtspr LPCR,rn; \
+ sync
+
+#define SAVE_AND_SET_CI(rn,rx) \
+ sync; \
+ mfspr rx,LPCR; \
+ ori rn,rx,2; \
+ mtspr LPCR,rn; \
+ sync
+
+#define RESTORE_CI(rx) \
+ sync; \
+ mtspr LPCR,rx; \
+ sync
+
+#define ENTRY(func_name) \
+ .text; \
+ .align 2; \
+ .globl .func_name; \
+ .func_name: \
+ .globl func_name; \
+ func_name:
+
+#define ASM_ENTRY(fn) \
+ .globl fn; \
+fn:
+
diff --git a/clients/net-snk/include/net.h b/clients/net-snk/include/net.h
new file mode 100644
index 0000000..d54501f
--- /dev/null
+++ b/clients/net-snk/include/net.h
@@ -0,0 +1,30 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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 _NET_H
+#define _NET_H
+#include <pci.h>
+
+typedef struct {
+ int device_id;
+ int vendor_id;
+
+ int (*net_init) (pci_config_t *pciconf, char *mac_addr);
+ int (*net_term) (pci_config_t *pciconf);
+ int (*net_transmit) (pci_config_t *pciconf, char *buffer, int len);
+ int (*net_receive) (pci_config_t *pciconf, char *buffer, int len);
+ int (*net_ioctl) (pci_config_t *pciconf, int request, void* data);
+
+} net_driver_t;
+
+#endif
diff --git a/clients/net-snk/include/netdriver_int.h b/clients/net-snk/include/netdriver_int.h
new file mode 100644
index 0000000..68c1cc9
--- /dev/null
+++ b/clients/net-snk/include/netdriver_int.h
@@ -0,0 +1,119 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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 _NETDRIVER_INT_H
+#define _NETDRIVER_INT_H
+#include <stddef.h>
+
+/* Constants for different kinds of IOCTL requests
+ */
+
+#define SIOCETHTOOL 0x1000
+
+typedef struct {
+ unsigned int addr;
+ unsigned int size;
+ int type;
+} bar_t;
+
+typedef struct {
+ unsigned long long puid;
+ unsigned int bus;
+ unsigned int devfn;
+ unsigned int vendor_id;
+ unsigned int device_id;
+ unsigned int revision_id;
+ unsigned int class_code;
+ bar_t bars[6];
+ unsigned int interrupt_line;
+} pci_config_t;
+
+typedef int (*net_init_t) (pci_config_t * conf, char *mac_addr);
+typedef int (*net_term_t) (pci_config_t * conf);
+typedef int (*net_receive_t) (pci_config_t * conf, char *buffer, int len);
+typedef int (*net_xmit_t) (pci_config_t * conf, char *buffer, int len);
+typedef int (*net_ioctl_t) (pci_config_t * conf, int request, void *data);
+
+typedef struct {
+ int version;
+ net_init_t net_init;
+ net_term_t net_term;
+ net_receive_t net_receive;
+ net_xmit_t net_xmit;
+ net_ioctl_t net_ioctl;
+} snk_module_t;
+
+
+typedef int (*print_t) (const char *, ...);
+typedef void (*us_delay_t) (unsigned int);
+typedef void (*ms_delay_t) (unsigned int);
+typedef int (*pci_config_read_t) (long long puid, int size,
+ int bus, int devfn, int offset);
+typedef int (*pci_config_write_t) (long long puid, int size,
+ int bus, int devfn, int offset, int value);
+typedef void *(*malloc_aligned_t) (size_t, int);
+typedef unsigned int (*io_read_t) (void *, size_t);
+typedef int (*io_write_t) (void *, unsigned int, size_t);
+typedef unsigned int (*romfs_lookup_t) (const char *name, void **addr);
+typedef void (*translate_addr_t) (unsigned long *);
+
+typedef struct {
+ int version;
+ print_t print;
+ us_delay_t us_delay;
+ ms_delay_t ms_delay;
+ pci_config_read_t pci_config_read;
+ pci_config_write_t pci_config_write;
+ malloc_aligned_t k_malloc_aligned;
+ io_read_t io_read;
+ io_write_t io_write;
+ romfs_lookup_t k_romfs_lookup;
+ translate_addr_t translate_addr;
+} snk_kernel_t;
+
+
+/* special structure and constants for IOCTL requests of type ETHTOOL
+ */
+
+#define ETHTOOL_GMAC 0x03
+#define ETHTOOL_SMAC 0x04
+#define ETHTOOL_VERSION 0x05
+
+typedef struct {
+ int idx;
+ char address[6];
+} ioctl_ethtool_mac_t;
+
+typedef struct {
+ unsigned int length;
+ char *text;
+} ioctl_ethtool_version_t;
+
+
+/* default structure and constants for IOCTL requests
+ */
+
+#define IF_NAME_SIZE 0xFF
+
+typedef struct {
+ char if_name[IF_NAME_SIZE];
+ int subcmd;
+ union {
+ ioctl_ethtool_mac_t mac;
+ ioctl_ethtool_version_t version;
+ } data;
+} ioctl_net_data_t;
+
+/* Entry of module */
+snk_module_t *module_init(snk_kernel_t * snk_kernel_int,
+ pci_config_t * pciconf);
+#endif /* _NETDRIVER_INT_H */
diff --git a/clients/net-snk/include/of.h b/clients/net-snk/include/of.h
new file mode 100644
index 0000000..c638dd3
--- /dev/null
+++ b/clients/net-snk/include/of.h
@@ -0,0 +1,56 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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 OF_H
+#define OF_H
+#define p32 int
+#define p32cast (int) (unsigned long) (void*)
+
+#define phandle_t p32
+#define ihandle_t p32
+
+typedef struct
+{
+ unsigned int serv;
+ int nargs;
+ int nrets;
+ unsigned int args[16];
+} of_arg_t;
+
+
+phandle_t of_finddevice (const char *);
+phandle_t of_peer (phandle_t);
+phandle_t of_child (phandle_t);
+phandle_t of_parent (phandle_t);
+int of_getprop (phandle_t, const char *, void *, int);
+void * of_call_method_3 (const char *, ihandle_t, int);
+
+
+ihandle_t of_open (const char *);
+void of_close(ihandle_t);
+int of_read (ihandle_t , void*, int);
+int of_write (ihandle_t, void*, int);
+int of_seek (ihandle_t, int, int);
+
+void * of_claim(void *, unsigned int , unsigned int );
+void of_release(void *, unsigned int );
+
+int of_yield(void);
+void * of_set_callback(void *);
+
+unsigned int romfs_lookup(const char *, void **);
+int vpd_read(unsigned int , unsigned int , char *);
+int vpd_write(unsigned int , unsigned int , char *);
+int write_mm_log(char *, unsigned int , unsigned short );
+
+#endif
diff --git a/clients/net-snk/include/pci.h b/clients/net-snk/include/pci.h
new file mode 100644
index 0000000..4c2c18b
--- /dev/null
+++ b/clients/net-snk/include/pci.h
@@ -0,0 +1,26 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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 _PCI_H
+#define _PCI_H
+#include <netdriver_int.h>
+#include <of.h>
+
+int pci_calc_bar_size (long long puid, int bus, int devfn, int bar);
+int pci_get_bar_start (long long puid, int bus, int devfn, int bar);
+void pci_set_bar_start (long long puid, int bus, int devfn, int bar, int value);
+int pci_bus_scan_puid(long long puid, int class_to_check,
+ pci_config_t *pci_devices, int max_devs);
+long long get_next_phb (phandle_t *phb);
+
+#endif
diff --git a/clients/net-snk/include/rtas.h b/clients/net-snk/include/rtas.h
new file mode 100644
index 0000000..5591050
--- /dev/null
+++ b/clients/net-snk/include/rtas.h
@@ -0,0 +1,45 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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 RTAS_H
+#define RTAS_H
+
+#include "of.h"
+
+typedef struct dtime {
+ unsigned int year;
+ unsigned int month;
+ unsigned int day;
+ unsigned int hour;
+ unsigned int minute;
+ unsigned int second;
+ unsigned int nano;
+} dtime;
+
+typedef void (*thread_t) (int);
+
+int rtas_token(const char *);
+int rtas_call(int, int, int, int *, ...);
+void rtas_init();
+int rtas_pci_config_read (long long, int, int, int, int);
+int rtas_pci_config_write (long long, int, int, int, int, int);
+int rtas_set_time_of_day(dtime *);
+int rtas_get_time_of_day(dtime *);
+int rtas_ibm_update_flash_64(long long, long long);
+int rtas_ibm_update_flash_64_and_reboot(long long, long long);
+int rtas_system_reboot();
+int rtas_start_cpu (int, thread_t, int);
+int rtas_stop_self (void);
+int rtas_ibm_manage_flash(int);
+
+#endif
diff --git a/clients/net-snk/include/socket.h b/clients/net-snk/include/socket.h
new file mode 100644
index 0000000..b39f113
--- /dev/null
+++ b/clients/net-snk/include/socket.h
@@ -0,0 +1,25 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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 _SOCKET_H
+#define _SOCKET_H
+extern int socket(int dom, int type, int proto, char *mac_addr);
+extern int sendto(int fd, const void* buffer, int len,
+ int flags, const void* sock_addr, int sock_addr_len);
+extern int send(int fd, void* buffer, int len, int flags);
+extern int recv(int fd, void* buffer, int len, int flags);
+
+#define htonl(x) x
+#define htons(x) x
+
+#endif
diff --git a/clients/net-snk/include/sys/socket.h b/clients/net-snk/include/sys/socket.h
new file mode 100644
index 0000000..5c38e0a
--- /dev/null
+++ b/clients/net-snk/include/sys/socket.h
@@ -0,0 +1,28 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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 _SOCKET_H
+#define _SOCKET_H
+
+#include "systemcall.h"
+
+int socket(int, int, int, char *);
+int sendto(int, const void *, int, int, const void *, int);
+int send(int, void *, int, int);
+int recv(int, void *, int, int);
+
+#define htonl(x) x
+#define htons(x) x
+
+#endif
+
diff --git a/clients/net-snk/include/systemcall.h b/clients/net-snk/include/systemcall.h
new file mode 100644
index 0000000..265d7d2
--- /dev/null
+++ b/clients/net-snk/include/systemcall.h
@@ -0,0 +1,148 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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 SYSTEMCALL_H
+#define SYSTEMCALL_H
+
+extern inline int
+syscall (int nr)
+{
+ register unsigned long r0 asm("r0") = nr;
+ register unsigned long r3 asm("r3");
+ asm volatile ("sc" : "=r" (r3)
+ : "r" (r0));
+ return r3;
+}
+
+extern inline long
+syscall_1 (int nr, long arg0)
+{
+ register unsigned long r0 asm("r0") = nr;
+ register unsigned long r3 asm("r3") = arg0;
+ asm volatile ("sc" : "=r" (r3)
+ : "0" (r3), "r" (r0));
+ return r3;
+}
+
+extern inline long
+syscall_2 (int nr, long arg0, long arg1)
+{
+ register unsigned long r0 asm("r0") = nr;
+ register unsigned long r3 asm("r3") = arg0;
+ register unsigned long r4 asm("r4") = arg1;
+ asm volatile ("sc" : "=r" (r3)
+ : "0" (r3), "r" (r4), "r" (r0));
+ return r3;
+}
+
+extern inline long
+syscall_3 (int nr, long arg0, long arg1, long arg2)
+{
+ register unsigned long r0 asm("r0") = nr;
+ register unsigned long r3 asm("r3") = arg0;
+ register unsigned long r4 asm("r4") = arg1;
+ register unsigned long r5 asm("r5") = arg2;
+ asm volatile ("sc" : "=r" (r3)
+ : "0" (r3), "r" (r4), "r" (r5), "r" (r0));
+ return r3;
+}
+
+extern inline long
+syscall_4 (int nr, long arg0, long arg1, long arg2, long arg3)
+{
+ register unsigned long r0 asm("r0") = nr;
+ register unsigned long r3 asm("r3") = arg0;
+ register unsigned long r4 asm("r4") = arg1;
+ register unsigned long r5 asm("r5") = arg2;
+ register unsigned long r6 asm("r6") = arg3;
+ asm volatile ("sc" : "=r" (r3)
+ : "0" (r3), "r" (r4), "r" (r5), "r" (r6), "r" (r0));
+ return r3;
+}
+
+extern inline long
+syscall_5 (int nr, long arg0, long arg1, long arg2, long arg3,
+ long arg4)
+{
+ register unsigned long r0 asm("r0") = nr;
+ register unsigned long r3 asm("r3") = arg0;
+ register unsigned long r4 asm("r4") = arg1;
+ register unsigned long r5 asm("r5") = arg2;
+ register unsigned long r6 asm("r6") = arg3;
+ register unsigned long r7 asm("r7") = arg4;
+ asm volatile ("sc" : "=r" (r3)
+ : "0" (r3), "r" (r4), "r" (r5),
+ "r" (r6), "r" (r7), "r" (r0));
+ return r3;
+}
+
+extern inline long
+syscall_6 (int nr, long arg0, long arg1, long arg2, long arg3,
+ long arg4, long arg5)
+{
+ register unsigned long r0 asm("r0") = nr;
+ register unsigned long r3 asm("r3") = arg0;
+ register unsigned long r4 asm("r4") = arg1;
+ register unsigned long r5 asm("r5") = arg2;
+ register unsigned long r6 asm("r6") = arg3;
+ register unsigned long r7 asm("r7") = arg4;
+ register unsigned long r8 asm("r8") = arg5;
+ asm volatile ("sc" : "=r" (r3)
+ : "0" (r3), "r" (r4), "r" (r5),
+ "r" (r6), "r" (r7), "r" (r8), "r" (r0));
+ return r3;
+}
+
+extern inline long
+syscall_7 (int nr, long arg0, long arg1, long arg2, long arg3,
+ long arg4, long arg5, long arg6)
+{
+ register unsigned long r0 asm("r0") = nr;
+ register unsigned long r3 asm("r3") = arg0;
+ register unsigned long r4 asm("r4") = arg1;
+ register unsigned long r5 asm("r5") = arg2;
+ register unsigned long r6 asm("r6") = arg3;
+ register unsigned long r7 asm("r7") = arg4;
+ register unsigned long r8 asm("r8") = arg5;
+ register unsigned long r9 asm("r9") = arg6;
+ asm volatile ("sc" : "=r" (r3)
+ : "0" (r3), "r" (r4), "r" (r5),
+ "r" (r6), "r" (r7), "r" (r8),
+ "r" (r9), "r" (r0));
+ return r3;
+}
+
+
+#define _exit_sc_nr 1
+#define _read_sc_nr 2
+#define _write_sc_nr 3
+#define _open_sc_nr 4
+#define _close_sc_nr 5
+#define _getpid_sc_nr 6
+#define _brk_sc_nr 7
+#define _ioctl_sc_nr 8
+#define _socket_sc_nr 9
+#define _wait4_sc_nr 10
+#define _sigreturn_sc_nr 11
+#define _rt_sigaction_sc_nr 12
+#define _lseek_sc_nr 13
+
+#define _sock_sc_nr 1
+#define _sendto_sc_nr 2
+#define _send_sc_nr 3
+#define _recv_sc_nr 4
+
+
+//typedef unsigned long size_t;
+
+#endif
diff --git a/clients/net-snk/include/time.h b/clients/net-snk/include/time.h
new file mode 100644
index 0000000..d57c2f9
--- /dev/null
+++ b/clients/net-snk/include/time.h
@@ -0,0 +1,36 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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 _TIME_H_
+#define _TIME_H_
+
+typedef unsigned long clock_t;
+typedef unsigned long time_t;
+
+time_t time(time_t *);
+
+extern unsigned long tb_freq;
+
+/* setup the timer to start counting from the given parameter */
+void set_timer(int);
+/* read the current value from the decrementer */
+int get_timer();
+/* get the number of ticks for which the decrementer needs 1 second */
+int get_sec_ticks();
+/* get the number of ticks for which the decrementer needs 1 millisecond */
+int get_msec_ticks();
+
+#define TICKS_MSEC get_msec_ticks()
+#define TICKS_SEC get_sec_ticks()
+
+#endif
diff --git a/clients/net-snk/include/types.h b/clients/net-snk/include/types.h
new file mode 100644
index 0000000..0036387
--- /dev/null
+++ b/clients/net-snk/include/types.h
@@ -0,0 +1,34 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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 _TYPES_H
+#define _TYPES_H
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+
+typedef signed char int8_t;
+typedef signed short int16_t;
+typedef signed int int32_t;
+typedef signed long long int64_t;
+
+#ifndef u32
+typedef unsigned int u32;
+#endif
+#ifndef u64
+typedef unsigned long long u64;
+#endif
+
+#endif
diff --git a/clients/net-snk/kernel/Makefile b/clients/net-snk/kernel/Makefile
new file mode 100644
index 0000000..73e8127
--- /dev/null
+++ b/clients/net-snk/kernel/Makefile
@@ -0,0 +1,43 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2007 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 TOP
+ TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd)
+ export TOP
+endif
+include $(TOP)/make.rules
+
+OBJS = entry.o init.o systemcall.o lowmem.o crt0.o endian.o timer.o
+OBJDIRS = driver/net.o
+
+all: kernel.o
+
+driver/net.o:
+ make -C driver
+
+kernel.o: subdirs $(OBJS)
+ $(LD) $(LDFLAGS) $(OBJDIRS) $(OBJS) -o $@ -r
+
+subdirs:
+ for dir in $(dir $(OBJDIRS)); do \
+ $(MAKE) -C $$dir DIRECTORY=$(DIRECTORY)$$dir || exit 1; \
+ done
+
+clean:
+ $(RM) -f *.o *.a *.i
+ @for dir in $(dir $(OBJDIRS)); do \
+ $(CLEAN); \
+ $(MAKE) -C $$dir DIRECTORY=$(DIRECTORY)$$dir clean; \
+ done
+
+include $(TOP)/make.depend
diff --git a/clients/net-snk/kernel/crt0.c b/clients/net-snk/kernel/crt0.c
new file mode 100644
index 0000000..e3c443b
--- /dev/null
+++ b/clients/net-snk/kernel/crt0.c
@@ -0,0 +1,74 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+
+#include <stdlib.h>
+#include <string.h>
+extern int main (int, char**);
+extern int callback (int, char **);
+
+#define MAX_ARGV 10
+int
+gen_argv(const char *arg_string, int len, char* argv[])
+{
+ const char *str, *str_end, *arg_string_end = arg_string + len;
+ int i;
+
+ str = arg_string;
+ for (i = 0; i < MAX_ARGV; i++)
+ {
+ str_end = str;
+
+ while((*str_end++ != ' ') && (str_end <= arg_string_end));
+
+ argv[i] = malloc(str_end-str);
+
+ memcpy (argv[i], str, str_end-str-1);
+ argv[i][str_end-str-1] = '\0';
+ str = str_end-1;
+ while(*(++str) == ' ');
+ if (str >= arg_string_end)
+ break;
+ }
+ return i+1;
+}
+
+
+
+int
+_start(char * arg_string, long len)
+{
+ int rc;
+ int argc;
+ char* argv[MAX_ARGV];
+
+ argc = gen_argv(arg_string, len, argv);
+
+ rc = main(argc, argv);
+
+ return rc;
+}
+
+/*
+ * Takes a Forth representation of a string and generates an argument array,
+ * then calls callback().
+ */
+unsigned long
+callback_entry(void *base, unsigned long len) {
+ char *argv[MAX_ARGV];
+ int argc;
+
+ argc = gen_argv(base, len, argv);
+
+ return (callback(argc, argv));
+}
+
diff --git a/clients/net-snk/kernel/driver/Makefile b/clients/net-snk/kernel/driver/Makefile
new file mode 100644
index 0000000..6c2c8d4
--- /dev/null
+++ b/clients/net-snk/kernel/driver/Makefile
@@ -0,0 +1,40 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2007 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 TOP
+ TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd)
+ export TOP
+endif
+include $(TOP)/make.rules
+
+OBJS = net_support.o
+OBJDIRS = net/net_driver.o
+
+all: net.o
+
+net.o: subdirs $(OBJS)
+ $(LD) $(LDFLAGS) $(OBJDIRS) $(OBJS) -o $@ -r
+
+subdirs:
+ for dir in $(dir $(OBJDIRS)); do \
+ $(MAKE) -C $$dir DIRECTORY=$(DIRECTORY)$$dir || exit 1; \
+ done
+
+clean:
+ $(RM) -f *.o *.a *.i
+ @for dir in $(dir $(OBJDIRS)); do \
+ $(CLEAN); \
+ $(MAKE) -C $$dir DIRECTORY=$(DIRECTORY)$$dir clean; \
+ done
+
+-include $(TOP)/make.depend
diff --git a/clients/net-snk/kernel/driver/net/Makefile b/clients/net-snk/kernel/driver/net/Makefile
new file mode 100644
index 0000000..95efa2b
--- /dev/null
+++ b/clients/net-snk/kernel/driver/net/Makefile
@@ -0,0 +1,38 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2007 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 TOP
+ TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd)
+ export TOP
+endif
+include $(TOP)/make.rules
+
+OBJS = netmodule.o
+
+all: net_driver.o
+
+net_driver.o: $(OBJS)
+ $(LD) $(LDFLAGS) $^ -o $@ -r
+
+clean:
+ $(RM) -f *.o *.a *.i
+
+include $(TOP)/make.depend
+
+#depend :
+# @echo "create .depend file"
+# @touch .depend ; \
+# makedepend -v -f.depend -- $(CFLAGS) -- $(OBJS:.o=.c) 2> /dev/null
+
+#mrproper : clean
+# rm -rf .depend
diff --git a/clients/net-snk/kernel/driver/net/netmodule.c b/clients/net-snk/kernel/driver/net/netmodule.c
new file mode 100644
index 0000000..e81628e
--- /dev/null
+++ b/clients/net-snk/kernel/driver/net/netmodule.c
@@ -0,0 +1,138 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+#include <netdriver_int.h>
+#include <kernel.h>
+#include <of.h>
+#include <rtas.h>
+#include <cpu.h>
+
+# define MODULE_ADDR 0xF800000
+
+unsigned int read_io(void *, size_t);
+int write_io(void *, unsigned int, size_t);
+void translate_address(unsigned long *);
+
+static snk_kernel_t snk_kernel_interface = {
+ .version = 1,
+ .print = printk,
+ .us_delay = udelay,
+ .ms_delay = mdelay,
+ .pci_config_read = rtas_pci_config_read,
+ .pci_config_write = rtas_pci_config_write,
+ .k_malloc_aligned = malloc_aligned,
+ .k_romfs_lookup = romfs_lookup,
+ .translate_addr = translate_address
+};
+
+static snk_module_t *snk_module_interface;
+
+typedef snk_module_t *(*module_init_t) (snk_kernel_t *, pci_config_t *);
+
+/* Load module and call init code.
+ Init code will check, if module is responsible for device.
+ Returns -1, if not responsible for device, 0 otherwise.
+*/
+
+int
+load_module(const char *name, pci_config_t * pciconf)
+{
+ int len;
+ void *addr;
+ module_init_t module_init;
+
+ /* Read module from FLASH */
+ len = romfs_lookup(name, &addr);
+
+ if (len <= 0) {
+ return -1;
+ }
+ /* Copy image from flash to RAM
+ * FIXME fix address 8MB
+ */
+
+ memcpy((void *) MODULE_ADDR, addr, len);
+
+ flush_cache((void *) MODULE_ADDR, len);
+
+ /* Module starts with opd structure of the module_init
+ * function.
+ */
+ module_init = (module_init_t) MODULE_ADDR;
+ snk_module_interface = module_init(&snk_kernel_interface, pciconf);
+ if (snk_module_interface == 0)
+ return -1;
+ return 0;
+}
+
+int
+net_init(pci_config_t * pciconf, char *mac_addr)
+{
+ snk_kernel_interface.io_read = read_io;
+ snk_kernel_interface.io_write = write_io;
+
+ if (snk_module_interface->net_init){
+ return snk_module_interface->net_init(pciconf, mac_addr);
+ }
+ else {
+ printk("No net_init function available");
+ return -1;
+ }
+}
+
+int
+net_term(pci_config_t * pciconf)
+{
+ if (snk_module_interface->net_term)
+ return snk_module_interface->net_term(pciconf);
+ else {
+ printk("No net_term function available");
+ return -1;
+ }
+}
+
+
+int
+net_xmit(pci_config_t * pciconf, char *buffer, int len)
+{
+ if (snk_module_interface->net_xmit)
+ return snk_module_interface->net_xmit(pciconf, buffer, len);
+ else {
+ printk("No net_xmit function available");
+ return -1;
+ }
+}
+
+int
+net_receive(pci_config_t * pciconf, char *buffer, int len)
+{
+ if (snk_module_interface->net_receive)
+ return snk_module_interface->net_receive(pciconf, buffer, len);
+ else {
+ printk("No net_receive function available");
+ return -1;
+ }
+}
+
+int
+net_ioctl(pci_config_t * pciconf, int request, void* data)
+{
+ snk_kernel_interface.io_read = read_io;
+ snk_kernel_interface.io_write = write_io;
+
+ if (snk_module_interface->net_ioctl)
+ return snk_module_interface->net_ioctl(pciconf, request, data);
+ else {
+ printk("No net_ioctl function available");
+ return -1;
+ }
+}
diff --git a/clients/net-snk/kernel/driver/net_support.c b/clients/net-snk/kernel/driver/net_support.c
new file mode 100644
index 0000000..983374a
--- /dev/null
+++ b/clients/net-snk/kernel/driver/net_support.c
@@ -0,0 +1,534 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+
+#include <pci.h>
+#include <net.h>
+#include <netdriver_int.h>
+#include <kernel.h>
+#include <rtas.h>
+#include <stdlib.h>
+#include <of.h>
+#include <types.h>
+
+extern int net_init(pci_config_t * pciconf, char *mac_addr);
+extern int net_term(pci_config_t * pciconf);
+extern int net_xmit(pci_config_t * pciconf, char *buffer, int len);
+extern int net_receive(pci_config_t * pciconf, char *buffer, int len);
+extern int net_ioctl(pci_config_t * conf, int request, void *data);
+extern int load_module(const char *, pci_config_t *);
+
+
+static char *mod_names[] = {
+ "net_e1000",
+ "net_bcm",
+ "net_nx203x",
+ "net_mcmal",
+ "net_spider",
+ 0
+};
+
+net_driver_t *
+find_net_driver(pci_config_t pci_conf)
+{
+ int rc;
+ int i = 0;
+ static net_driver_t module_net_driver;
+
+ /* Loop over module name */
+ while (mod_names[i]) {
+ rc = load_module(mod_names[i], &pci_conf);
+ if (rc == 0) {
+ module_net_driver.net_init = net_init;
+ module_net_driver.net_term = net_term;
+ module_net_driver.net_transmit = net_xmit;
+ module_net_driver.net_receive = net_receive;
+ module_net_driver.net_ioctl = net_ioctl;
+ return &module_net_driver;
+ }
+ i++;
+ }
+ return 0;
+}
+
+static phandle_t
+get_boot_device(void)
+{
+ static int nameprinted = 1;
+ char buf[1024];
+ phandle_t dev = of_finddevice("/chosen");
+
+ if (dev == -1) {
+ printk("/chosen not found\n");
+ dev = of_finddevice("/aliases");
+ if (dev == -1)
+ return dev;
+ printk("/aliases found, net=%s\n", buf);
+ of_getprop(dev, "net", buf, 1024);
+ } else
+ of_getprop(dev, "bootpath", buf, 1024);
+
+// FIXME: This printk is nice add to "Reading MAC from device" from netboot
+// However it is too hackish having "kernel" code finish the application
+// output line
+ if (!nameprinted++)
+ printk("%s: ", buf);
+
+ return of_finddevice(buf);
+}
+
+static void
+get_mac(char *mac)
+{
+ phandle_t net = get_boot_device();
+
+ if (net == -1)
+ return;
+
+ of_getprop(net, "local-mac-address", mac, 6);
+}
+
+void translate_address_dev(uint64_t *, phandle_t);
+
+/**
+ * get_puid walks up in the device tree until it finds a parent
+ * node without a reg property. get_puid is assuming that if the
+ * parent node has no reg property it has found the pci host bridge
+ *
+ * this is not the correct way to find PHBs but it seems to work
+ * for all our systems
+ *
+ * @param node the device for which to find the puid
+ *
+ * @return the puid or 0
+ */
+uint64_t
+get_puid(phandle_t node)
+{
+ uint64_t puid = 0;
+ uint64_t tmp = 0;
+ phandle_t curr_node = of_parent(node);
+ if (!curr_node)
+ /* no parent found */
+ return 0;
+ for (;;) {
+ puid = tmp;
+ if (of_getprop(curr_node, "reg", &tmp, 8) < 8) {
+ /* if the found PHB is not directly under
+ * root we need to translate the found address */
+ translate_address_dev(&puid, node);
+ return puid;
+ }
+ curr_node = of_parent(curr_node);
+ if (!curr_node)
+ return 0;
+ }
+ return 0;
+}
+
+/* Fill in the pci config structure from the device tree */
+int
+set_pci_config(pci_config_t * pci_config)
+{
+ unsigned char buf[1024];
+ int len, bar_nr;
+ unsigned int *assigned_ptr;
+ phandle_t net = get_boot_device();
+
+ if (net == -1)
+ return -1;
+ of_getprop(net, "vendor-id", &pci_config->vendor_id, 4);
+ of_getprop(net, "device-id", &pci_config->device_id, 4);
+ of_getprop(net, "revision-id", &pci_config->revision_id, 4);
+ of_getprop(net, "class-code", &pci_config->class_code, 4);
+ of_getprop(net, "interrupts", &pci_config->interrupt_line, 4);
+
+ len = of_getprop(net, "assigned-addresses", buf, 400);
+ if (len <= 0)
+ return -1;
+ assigned_ptr = (unsigned int *) &buf[0];
+ pci_config->bus = (assigned_ptr[0] & 0x00ff0000) >> 16;
+ pci_config->devfn = (assigned_ptr[0] & 0x0000ff00) >> 8;
+
+ while (len > 0) {
+ /* Fixme 64 bit bars */
+ bar_nr = ((assigned_ptr[0] & 0xff) - 0x10) / 4;
+ pci_config->bars[bar_nr].type =
+ (assigned_ptr[0] & 0x0f000000) >> 24;
+ pci_config->bars[bar_nr].addr = assigned_ptr[2];
+ pci_config->bars[bar_nr].size = assigned_ptr[4];
+ assigned_ptr += 5;
+ len -= 5 * sizeof(int);
+ }
+
+ pci_config->puid = get_puid(net);
+
+ return 0;
+}
+
+
+typedef struct {
+ pci_config_t pci_conf;
+ net_driver_t net_driv;
+
+ char mac_addr[6];
+ int running;
+} net_status_t;
+
+static net_status_t net_status;
+
+int
+init_net_driver()
+{
+ int result = 0;
+ net_driver_t *net_driver;
+
+ /* Find net device and initialize pci config */
+ if (set_pci_config(&net_status.pci_conf) == -1) {
+ printk(" No net device found \n");
+ return -1;
+ }
+
+ /* Get mac address from device tree */
+ get_mac(net_status.mac_addr);
+
+ /* Find net device driver */
+
+ net_driver = find_net_driver(net_status.pci_conf);
+ if (net_driver == 0) {
+ printk(" No net device driver found \n");
+ return -1;
+ }
+ net_status.net_driv = *net_driver;
+ /* Init net device driver */
+ result = net_status.net_driv.net_init(&net_status.pci_conf,
+ &net_status.mac_addr[0]);
+ if (result == -1) {
+ net_status.running = 0;
+ return -2;
+ } else {
+ net_status.running = 1;
+ }
+ return 0;
+}
+
+
+void
+term_net_driver()
+{
+ if (net_status.running == 1)
+ net_status.net_driv.net_term(&net_status.pci_conf);
+}
+
+
+int
+_socket(int domain, int type, int proto, char *mac_addr)
+{
+ static int first_time = 1;
+ if (first_time) {
+ switch (init_net_driver()) {
+ case -1:
+ return -1;
+ case -2:
+ return -2;
+ default:
+ break;
+ }
+ first_time = 0;
+ }
+
+ memcpy(mac_addr, &net_status.mac_addr[0], 6);
+ return 0;
+}
+
+
+long
+_recv(int fd, void *packet, int packet_len, int flags)
+{
+ return net_status.net_driv.net_receive(&net_status.pci_conf,
+ packet, packet_len);
+}
+
+
+long
+_sendto(int fd, void *packet, int packet_len, int flags,
+ void *sock_addr, int sock_addr_len)
+{
+ return net_status.net_driv.net_transmit(&net_status.pci_conf,
+ packet, packet_len);
+}
+
+long
+_send(int fd, void *packet, int packet_len, int flags)
+{
+ return net_status.net_driv.net_transmit(&net_status.pci_conf,
+ packet, packet_len);
+}
+
+long
+_ioctl(int fd, int request, void *data)
+{
+ net_driver_t *net_driver;
+
+ /* Find net device and initialize pci config */
+ if (set_pci_config(&net_status.pci_conf) == -1) {
+ printk(" No net device found \n");
+ return -1;
+ }
+
+ /* Find net device driver */
+
+ net_driver = find_net_driver(net_status.pci_conf);
+ if (net_driver == 0) {
+ printk(" No net device driver found \n");
+ return -1;
+ }
+ net_status.net_driv = *net_driver;
+
+ return net_status.net_driv.net_ioctl(&net_status.pci_conf,
+ request, data);
+}
+
+
+void *
+malloc_aligned(size_t size, int align)
+{
+ unsigned long p = (unsigned long) malloc(size + align - 1);
+ p = p + align - 1;
+ p = p & ~(align - 1);
+
+ return (void *) p;
+}
+
+#define CONFIG_SPACE 0
+#define IO_SPACE 1
+#define MEM_SPACE 2
+
+#define ASSIGNED_ADDRESS_PROPERTY 0
+#define REG_PROPERTY 1
+
+#define DEBUG_TRANSLATE_ADDRESS 0
+#if DEBUG_TRANSLATE_ADDRESS != 0
+#define DEBUG_TR(str...) printk(str)
+#else
+#define DEBUG_TR(str...)
+#endif
+
+/**
+ * pci_address_type tries to find the type for which a
+ * mapping should be done. This is PCI specific and is done by
+ * looking at the first 32bit of the phys-addr in
+ * assigned-addresses
+ *
+ * @param node the node of the device which requests
+ * translatation
+ * @param address the address which needs to be translated
+ * @param prop_type the type of the property to search in (either REG_PROPERTY or ASSIGNED_ADDRESS_PROPERTY)
+ * @return the corresponding type (config, i/o, mem)
+ */
+static int
+pci_address_type(phandle_t node, uint64_t address, uint8_t prop_type)
+{
+ char *prop_name = "assigned-addresses";
+ if (prop_type == REG_PROPERTY)
+ prop_name = "reg";
+ /* #address-cells */
+ const unsigned int nac = 3; //PCI
+ /* #size-cells */
+ const unsigned int nsc = 2; //PCI
+ /* up to 11 pairs of (phys-addr(3) size(2)) */
+ unsigned char buf[11 * (nac + nsc) * sizeof(int)];
+ unsigned int *assigned_ptr;
+ int result = -1;
+ int len;
+ len = of_getprop(node, prop_name, buf, 11 * (nac + nsc) * sizeof(int));
+ assigned_ptr = (unsigned int *) &buf[0];
+ while (len > 0) {
+ if ((prop_type == REG_PROPERTY)
+ && ((assigned_ptr[0] & 0xFF) != 0)) {
+ //BARs and Expansion ROM must be in assigned-addresses... so in reg
+ // we only look for those without config space offset set...
+ assigned_ptr += (nac + nsc);
+ len -= (nac + nsc) * sizeof(int);
+ continue;
+ }
+ DEBUG_TR("%s %x size %x\n", prop_name, assigned_ptr[2],
+ assigned_ptr[4]);
+ if (address >= assigned_ptr[2]
+ && address <= assigned_ptr[2] + assigned_ptr[4]) {
+ DEBUG_TR("found a match\n");
+ result = (assigned_ptr[0] & 0x03000000) >> 24;
+ break;
+ }
+ assigned_ptr += (nac + nsc);
+ len -= (nac + nsc) * sizeof(int);
+ }
+ /* this can only handle 32bit memory space and should be
+ * removed as soon as translations for 64bit are available */
+ return (result == 3) ? MEM_SPACE : result;
+}
+
+/**
+ * this is a hack which returns the lower 64 bit of any number of cells
+ * all the higher bits will silently discarded
+ * right now this works pretty good as long 64 bit addresses is all we want
+ *
+ * @param addr a pointer to the first address cell
+ * @param nc number of cells addr points to
+ * @return the lower 64 bit to which addr points
+ */
+static uint64_t
+get_dt_address(uint32_t *addr, uint32_t nc)
+{
+ uint64_t result = 0;
+ while (nc--)
+ result = (result << 32) | *(addr++);
+ return result;
+}
+
+/**
+ * this functions tries to find a mapping for the given address
+ * it assumes that if we have #address-cells == 3 that we are trying
+ * to do a PCI translation
+ *
+ * @param addr a pointer to the address that should be translated
+ * if a translation has been found the address will
+ * be modified
+ * @param type this is required for PCI devices to find the
+ * correct translation
+ * @param ranges this is one "range" containing the translation
+ * information (one range = nac + pnac + nsc)
+ * @param nac the OF property #address-cells
+ * @param nsc the OF property #size-cells
+ * @param pnac the OF property #address-cells from the parent node
+ * @return -1 if no translation was possible; else 0
+ */
+static int
+map_one_range(uint64_t *addr, int type, uint32_t *ranges, uint32_t nac,
+ uint32_t nsc, uint32_t pnac)
+{
+ long offset;
+ /* cm - child mapping */
+ /* pm - parent mapping */
+ uint64_t cm, size, pm;
+ /* only check for the type if nac == 3 (PCI) */
+ DEBUG_TR("type %x, nac %x\n", ranges[0], nac);
+ if (((ranges[0] & 0x03000000) >> 24) != type && nac == 3)
+ return -1;
+ /* okay, it is the same type let's see if we find a mapping */
+ size = get_dt_address(ranges + nac + pnac, nsc);
+ if (nac == 3) /* skip type if PCI */
+ cm = get_dt_address(ranges + 1, nac - 1);
+ else
+ cm = get_dt_address(ranges, nac);
+
+ DEBUG_TR("\t\tchild_mapping %lx\n", cm);
+ DEBUG_TR("\t\tsize %lx\n", size);
+ DEBUG_TR("\t\t*address %lx\n", (uint64_t) * addr);
+ if (cm + size <= (uint64_t) * addr || cm > (uint64_t) * addr)
+ /* it is not inside the mapping range */
+ return -1;
+ /* get the offset */
+ offset = *addr - cm;
+ /* and add the offset on the parent mapping */
+ if (pnac == 3) /* skip type if PCI */
+ pm = get_dt_address(ranges + nac + 1, pnac - 1);
+ else
+ pm = get_dt_address(ranges + nac, pnac);
+ DEBUG_TR("\t\tparent_mapping %lx\n", pm);
+ *addr = pm + offset;
+ DEBUG_TR("\t\t*address %lx\n", *addr);
+ return 0;
+}
+
+/**
+ * translate_address_dev tries to translate the device specific address
+ * to a host specific address by walking up in the device tree
+ *
+ * @param address a pointer to a 64 bit value which will be
+ * translated
+ * @param current_node phandle of the device from which the
+ * translation will be started
+ */
+void
+translate_address_dev(uint64_t *addr, phandle_t current_node)
+{
+ unsigned char buf[1024];
+ phandle_t parent;
+ unsigned int pnac;
+ unsigned int nac;
+ unsigned int nsc;
+ int addr_type;
+ int len;
+ unsigned int *ranges;
+ unsigned int one_range;
+ DEBUG_TR("translate address %lx, node: %lx\n", *addr, current_node);
+ of_getprop(current_node, "name", buf, 400);
+ DEBUG_TR("current node: %s\n", buf);
+ addr_type =
+ pci_address_type(current_node, *addr, ASSIGNED_ADDRESS_PROPERTY);
+ if (addr_type == -1) {
+ // check in "reg" property if not found in "assigned-addresses"
+ addr_type = pci_address_type(current_node, *addr, REG_PROPERTY);
+ }
+ DEBUG_TR("address_type %x\n", addr_type);
+ current_node = of_parent(current_node);
+ while (1) {
+ parent = of_parent(current_node);
+ if (!parent) {
+ DEBUG_TR("reached root node...\n");
+ break;
+ }
+ of_getprop(current_node, "#address-cells", &nac, 4);
+ of_getprop(current_node, "#size-cells", &nsc, 4);
+ of_getprop(parent, "#address-cells", &pnac, 4);
+ one_range = nac + pnac + nsc;
+ len = of_getprop(current_node, "ranges", buf, 400);
+ if (len < 0) {
+ DEBUG_TR("no 'ranges' property; not translatable\n");
+ return;
+ }
+ ranges = (unsigned int *) &buf[0];
+ while (len > 0) {
+ if (!map_one_range
+ ((uint64_t *) addr, addr_type, ranges, nac, nsc,
+ pnac))
+ /* after a successful mapping we stop
+ * going through the ranges */
+ break;
+ ranges += one_range;
+ len -= one_range * sizeof(int);
+ }
+ DEBUG_TR("address %lx\n", *addr);
+ of_getprop(current_node, "name", buf, 400);
+ DEBUG_TR("current node: %s\n", buf);
+ DEBUG_TR("\t#address-cells: %x\n", nac);
+ DEBUG_TR("\t#size-cells: %x\n", nsc);
+ of_getprop(parent, "name", buf, 400);
+ DEBUG_TR("parent node: %s\n", buf);
+ DEBUG_TR("\t#address-cells: %x\n", pnac);
+ current_node = parent;
+ }
+}
+
+/**
+ * translate_address tries to translate the device specific address
+ * of the boot device to a host specific address
+ *
+ * @param address a pointer to a 64 bit value which will be
+ * translated
+ */
+void
+translate_address(uint64_t *addr)
+{
+ translate_address_dev(addr, get_boot_device());
+}
diff --git a/clients/net-snk/kernel/endian.c b/clients/net-snk/kernel/endian.c
new file mode 100644
index 0000000..9748778
--- /dev/null
+++ b/clients/net-snk/kernel/endian.c
@@ -0,0 +1,30 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+
+#include "endian.h"
+
+inline uint16_t bswap_16 (uint16_t x)
+{
+ return ((x&0xff00) >> 8) | ((x&0xff) << 8);
+}
+
+inline uint32_t bswap_32 (uint32_t x)
+{
+ return bswap_16((x&0xffff0000) >> 16) | (bswap_16(x&0xffff) << 16);
+}
+
+inline uint64_t bswap_64 (uint64_t x)
+{
+ return (unsigned long long) bswap_32((x&0xffffffff00000000ULL) >> 32) |
+ (unsigned long long) bswap_32(x&0xffffffffULL) << 32;
+}
diff --git a/clients/net-snk/kernel/entry.S b/clients/net-snk/kernel/entry.S
new file mode 100644
index 0000000..8db10af
--- /dev/null
+++ b/clients/net-snk/kernel/entry.S
@@ -0,0 +1,167 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+#define STACKSIZE 0x100000
+#include <macros.h>
+
+/*
+Function:
+ Input:
+ r3:
+ r4:
+ r5: prom entry
+ Output:
+
+Decription: Main entry point, called from OF
+
+*/
+ .globl _entry
+ .section ".opd","aw"
+ .align 3
+_entry:
+ .quad ._entry,.TOC.@tocbase,0
+ .previous
+ .size main,24
+ .globl ._entry
+._entry:
+ mr r3, r6 # parm 0 passed in r6
+ mr r4, r7 # parm 1 passed in r7
+ mr r6, r1 # save stack pointer
+ mflr r7 # save link register
+ bcl 20,31,over # branch after pointer table
+base:
+ .align 3
+.LCgot: .quad _got-base+0x8000
+.LCstack: .quad _stack+STACKSIZE-0x80-base
+over:
+ mflr r8 # gpr 8 is the base
+ ld r1,.LCstack-base(r8) # load new stack pointer
+ add r1, r1, r8 # add base
+ std r2, 64(r1) # save got
+ std r7, 56(r1) # save link register
+# ld r2, .LCgot-base(r8) # load got pointer
+# add r2, r2, r8 # add base
+ std r6, 0(r1) # save stack pointer
+
+ ld r6, _prom_entry@got(r2)
+ std r5, 0(r6) # Save prom handle
+
+ ld r10, _exit_sp@got(r2) # save stack pointer for exit call
+ std r1, 0(r10)
+
+ bl ._start_kernel # call kernel init code
+
+the_end:
+ ld r4, 56(r1) # Restore link register
+ mtlr r4
+ ld r2, 64(r1) # restore got
+ ld r1, 0(r1)
+
+ blr
+
+/*
+ * Function: _callback_entry
+ * Input: r6 start address of parameter string
+ * r7 length of parameter string.
+ *
+ * Description: If a client application wants to register a callback function,
+ * this function is registered w/ SLOF, not the application's function. SLOF
+ * passes the parameter string in Forth representation in R6 and R7. This
+ * function moves R6 to R3 and R7 to R4 and then calls callback_entry().
+ *
+ */
+ .globl _callback_entry
+ .section ".opd", "aw"
+ .align 3
+_callback_entry:
+ .quad ._callback_entry,.TOC.@tocbase,0
+ .previous
+ .size callback,24
+ .type ._callback_entry, @function
+ .globl ._callback_entry
+._callback_entry:
+ # Save the LR
+ mflr r0
+ std r0, 16(r1)
+
+ # Reserve stack space
+ stdu r1, -32(r1)
+
+ # SLOF passes the parameters in Registers R6 and R7 but the target
+ # wants them in registers R3 and R4
+ mr r3, r6
+ mr r4, r7
+
+ # Branch to the callback_entry function
+ bl .callback_entry
+
+ # Destroy stack frame
+ ld r1, 0(r1)
+
+ # Restore LR
+ ld r0, 16(r1)
+ mtlr r0
+
+ # Return to caller
+ blr
+
+
+ .globl _exit_sp
+_exit_sp: .quad 0
+ .globl _prom_entry
+_prom_entry: .quad 0
+
+ENTRY(_exit)
+ ld r1, _exit_sp@got(r2)
+ ld r1, 0(r1)
+ b the_end
+
+ .globl .undo_exception
+.undo_exception:
+ .globl undo_exception
+undo_exception:
+
+/*
+ unwind stack
+*/
+ ld r3,exception_stack_frame@got(r2)
+ ld r1,0(r3)
+
+ ld r14,0x130(r1)
+ mtctr r14
+
+// restore regs same as in _exception_handler:
+
+ .irp i, 2,3,4,5,6,7,8,9,10,12,13,14,15,16, \
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \
+ 27, 28, 29, 30, 31
+ ld r\i, 0x30+\i*8 (r1)
+ .endr
+ addi r1, r1, 0x130
+
+// restore regs as in default handler
+
+ ld r0, 0x48(r1)
+ mtsrr0 r0
+ ld r0, 0x50(r1)
+ mtsrr1 r0
+// 20
+ ld r0, 0x38(r1)
+ mtlr r0
+ ld r0, 0x30(r1)
+ ld r11, 0x40(r1)
+// 30
+ addi r1, r1, 0x58
+
+ rfid
+
+ .lcomm _stack,STACKSIZE,16
diff --git a/clients/net-snk/kernel/init.c b/clients/net-snk/kernel/init.c
new file mode 100644
index 0000000..76b35ed
--- /dev/null
+++ b/clients/net-snk/kernel/init.c
@@ -0,0 +1,175 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+#include <of.h>
+#include <rtas.h>
+#include <pci.h>
+#include <kernel.h>
+#include <types.h>
+#include <string.h>
+#include <cpu.h>
+
+/* Application entry point .*/
+extern int _start(unsigned char *arg_string, long len);
+
+unsigned long exception_stack_frame;
+
+ihandle_t fd_array[32];
+pci_config_t pci_device_array[32];
+
+extern uint64_t tb_freq;
+
+void term_net_driver(void);
+
+static int
+init_io()
+{
+ phandle_t chosen = of_finddevice("/chosen");
+
+ if (chosen == -1)
+ return -1;
+
+ of_getprop(chosen, "stdin", &fd_array[0], sizeof(ihandle_t));
+ of_getprop(chosen, "stdout", &fd_array[1], sizeof(ihandle_t));
+
+ if (of_write(fd_array[1], " ", 1) < 0)
+ return -2;
+
+ return 0;
+}
+
+static char save_vector[0x4000];
+extern char _lowmem_start;
+extern char _lowmem_end;
+extern char __client_start;
+extern char __client_end;
+
+static void
+copy_exception_vectors()
+{
+ char *dest;
+ char *src;
+ int len;
+
+ dest = save_vector;
+ src = (char *) 0x200;
+ len = &_lowmem_end - &_lowmem_start;
+ memcpy(dest, src, len);
+
+ dest = (char *) 0x200;
+ src = &_lowmem_start;
+ memcpy(dest, src, len);
+ flush_cache(dest, len);
+}
+
+static void
+restore_exception_vectors()
+{
+ char *dest;
+ char *src;
+ int len;
+
+ dest = (char *) 0x200;
+ src = save_vector;
+ len = &_lowmem_end - &_lowmem_start;
+ memcpy(dest, src, len);
+ flush_cache(dest, len);
+}
+
+static long memory_size;
+
+static void
+checkmemorysize()
+{
+ char buf[255];
+ phandle_t ph;
+ memory_size = 0;
+
+ struct reg {
+ long adr;
+ long size;
+ } reg;
+
+ ph = of_peer(0); // begin from root-node
+ ph = of_child(ph); // get a child
+
+ while (ph != 0) {
+ if (of_getprop(ph, "device_type", buf, 255) != -1) {
+ /* if device_type == memory */
+ if (strcmp(buf, "memory") == 0)
+ if (of_getprop(ph, "reg", &reg, 16) != -1) {
+ memory_size += reg.size;
+ }
+ }
+ ph = of_peer(ph); // get next siblings
+ }
+}
+
+long
+getmemsize()
+{
+ return memory_size;
+}
+
+static void
+get_timebase()
+{
+ unsigned int timebase;
+ phandle_t cpu;
+ phandle_t cpus = of_finddevice("/cpus");
+
+ if (cpus == -1)
+ return;
+
+ cpu = of_child(cpus);
+
+ if (cpu == -1)
+ return;
+
+ of_getprop(cpu, "timebase-frequency", &timebase, 4);
+ tb_freq = (uint64_t) timebase;
+}
+
+int
+_start_kernel(unsigned long p0, unsigned long p1)
+{
+ int rc,claim_rc;
+ size_t _client_start = (size_t)&__client_start;
+ size_t _client_size = (size_t)&__client_end - (size_t)&__client_start;
+
+ claim_rc=(int)(long)of_claim((void *)(long)_client_start, _client_size, 0);
+
+ if (init_io() <= -1)
+ return -1;
+ copy_exception_vectors();
+
+ checkmemorysize();
+ get_timebase();
+ rtas_init();
+ rc = _start((unsigned char *) p0, p1);
+
+ term_net_driver();
+
+ restore_exception_vectors();
+ if (claim_rc >= 0) {
+ of_release((void *)(long)_client_start, _client_size);
+ }
+ return rc;
+}
+
+
+void
+exception_forward(void)
+{
+ restore_exception_vectors();
+ undo_exception();
+}
diff --git a/clients/net-snk/kernel/lowmem.S b/clients/net-snk/kernel/lowmem.S
new file mode 100644
index 0000000..ad5127f
--- /dev/null
+++ b/clients/net-snk/kernel/lowmem.S
@@ -0,0 +1,186 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+
+#include <macros.h>
+.section .lowmem,"aw",@progbits
+
+ .irp i, 0x0200,0x0300,0x0380,0x0400,0x0480,0x0500,0x0600,0x0700, \
+ 0x0800,0x0900,0x0a00,0x0b00
+ . = \i - 0x200
+// 0
+ stdu r1, -0x58(r1)
+ std r0, 0x30(r1)
+ mflr r0
+ std r0, 0x38(r1)
+// 10
+ mfsrr0 r0
+ std r0, 0x48(r1)
+ mfsrr1 r0
+ std r0, 0x50(r1)
+// 20
+ std r11, 0x40(r1)
+ li r0, \i
+ ld r11, 0x60 + \i(0)
+ bl _exception_handler
+
+// 30
+ ld r0, 0x48(r1)
+ mtsrr0 r0
+ ld r0, 0x50(r1)
+ mtsrr1 r0
+
+// 40
+ ld r0, 0x38(r1)
+ mtlr r0
+ ld r0, 0x30(r1)
+ ld r11, 0x40(r1)
+// 50
+ addi r1, r1, 0x58
+ rfid
+ nop
+ nop
+// 60
+// .quad \i+0x68
+ .quad .exception_forward
+// 68
+ blr
+ .endr
+
+ # System call entry
+ . = 0xc00 - 0x200
+
+ stdu r1, -0x50(r1)
+ mflr r11
+ std r11, 0x30(r1)
+ mfsrr0 r11
+ std r11, 0x40(r1)
+ mfsrr1 r11
+ std r11, 0x48(r1)
+ ld r11, _system_call@got(r2)
+ ld r11, 0(r11)
+ mtctr r11
+ mr r10, r0
+ bctrl
+ ld r11, 0x30(r1)
+ mtlr r11
+ ld r11, 0x40(r1)
+ mtsrr0 r11
+ ld r11, 0x48(r1)
+ mtsrr1 r11
+ addi r1, r1, 0x50
+ rfid
+
+ .irp i, 0x0d00,0x0e00,0x0f00, \
+ 0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,0x1700, \
+ 0x1800,0x1900,0x1a00,0x1b00,0x1c00,0x1d00,0x1e00,0x1f00, \
+ 0x2000,0x2100,0x2200,0x2300,0x2400,0x2500,0x2600,0x2700, \
+ 0x2800,0x2900,0x2a00,0x2b00,0x2c00,0x2d00,0x2e00,0x2f00
+ . = \i - 0x200
+// 0
+ stdu r1, -0x58(r1)
+ std r0, 0x30(r1)
+ mflr r0
+ std r0, 0x38(r1)
+// 10
+ mfsrr0 r0
+ std r0, 0x48(r1)
+ mfsrr1 r0
+ std r0, 0x50(r1)
+// 20
+ std r11, 0x40(r1)
+ li r0, \i
+ ld r11, 0x60 + \i(0)
+ bl _exception_handler
+
+// 30
+ ld r0, 0x48(r1)
+ mtsrr0 r0
+ ld r0, 0x50(r1)
+ mtsrr1 r0
+
+// 40
+ ld r0, 0x38(r1)
+ mtlr r0
+ ld r0, 0x30(r1)
+ ld r11, 0x40(r1)
+// 50
+ addi r1, r1, 0x58
+ rfid
+ nop
+ nop
+// 60
+// .quad \i+0x68
+ .quad .exception_forward
+// 68
+ blr
+ .endr
+
+/* Saves all register potential clobbered in exception handler.
+ In r0 the pointer to the function is passed.
+ */
+
+_exception_handler:
+ stdu r1, -0x130(r1)
+ .irp i, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, \
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \
+ 27, 28, 29, 30, 31
+ std r\i, 0x30+\i*8 (r1)
+ .endr
+ mfctr r14
+ std r14,0x130(r1)
+ mtctr r11
+
+ LOAD64(r3,_entry)
+ ld r2,8(r3)
+
+ ld r3,exception_stack_frame@got(r2)
+ std r1,0(r3)
+
+
+ mflr r14
+ bctrl
+ mtlr r14
+
+ ld r14,0x130(r1)
+ mtctr r14
+/*
+ mfsrr0 r2
+ addi r2, r2, 4
+ mtsrr0 r2
+*/
+ .irp i, 2,3,4,5,6,7,8,9,10,12,13,14,15,16, \
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \
+ 27, 28, 29, 30, 31
+ ld r\i, 0x30+\i*8 (r1)
+ .endr
+ addi r1, r1, 0x130
+ blr
+
+ .text
+
+/* Set exception handler for given exception vector.
+ r3: exception vector offset
+ r4: exception handler
+*/
+ .globl .set_exception
+.set_exception:
+ .globl set_exception
+set_exception:
+ ld r4,0x0(r4)
+ .globl .set_exception_asm
+.set_exception_asm:
+ .globl set_exception_asm
+set_exception_asm:
+ std r4, 0x60(r3) # fixme diff 1f - 0b
+ blr
+
diff --git a/clients/net-snk/kernel/systemcall.c b/clients/net-snk/kernel/systemcall.c
new file mode 100644
index 0000000..f15cae1
--- /dev/null
+++ b/clients/net-snk/kernel/systemcall.c
@@ -0,0 +1,171 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+
+#include <of.h>
+#include <systemcall.h>
+#include <stdarg.h>
+
+extern ihandle_t fd_array[32];
+
+int _socket (int, int, int, char*);
+long _recv (int, void*, int, int);
+long _sendto (int, void*, int, int, void*, int);
+long _send (int, void*, int, int);
+long _ioctl (int, int, void*);
+int vsprintf(char *, const char *, va_list);
+
+long
+_syscall_write (int fd, char *buf, long len)
+{
+ char dest_buf[512];
+ char *dest_buf_ptr;
+ int i;
+ if (fd == 1 || fd == 2)
+ {
+ dest_buf_ptr = &dest_buf[0];
+ for (i = 0; i < len && i < 256; i++)
+ {
+ *dest_buf_ptr++ = *buf++;
+ if (buf[-1] == '\n')
+ *dest_buf_ptr++ = '\r';
+ }
+ len = dest_buf_ptr - &dest_buf[0];
+ buf = &dest_buf[0];
+ }
+ return of_write (fd_array[fd], buf, len);
+}
+
+int
+printk(const char* fmt, ...)
+{
+ int count;
+ va_list ap;
+ char buffer[256];
+ va_start (ap, fmt);
+ count=vsprintf(buffer, fmt, ap);
+ _syscall_write (1, buffer, count);
+ va_end (ap);
+ return count;
+}
+
+long
+_syscall_read (int fd, char *buf, long len)
+{
+ return of_read (fd_array[fd], buf, len);
+}
+
+long
+_syscall_lseek (int fd, long offset, int whence)
+{
+ if (whence != 0)
+ return -1;
+
+ of_seek (fd_array[fd], (unsigned int) (offset>>32), (unsigned int) (offset & 0xffffffffULL));
+
+ return offset;
+}
+
+void
+_syscall_close(int fd)
+{
+ of_close(fd_array[fd]);
+}
+
+int
+_syscall_ioctl (int fd, int request, void* data)
+{
+ return _ioctl (fd, request, data);
+}
+
+long
+_syscall_socket (long which, long arg0, long arg1, long arg2,
+ long arg3, long arg4, long arg5)
+{
+ long rc = -1;
+ switch (which)
+ {
+ case _sock_sc_nr:
+ rc = _socket (arg0, arg1, arg2, (char*) arg3);
+ break;
+ case _recv_sc_nr:
+ rc = _recv (arg0, (void *) arg1, arg2, arg3);
+ break;
+ case _send_sc_nr:
+ rc = _send (arg0, (void *) arg1, arg2, arg3);
+ break;
+ case _sendto_sc_nr:
+ rc = _sendto (arg0, (void *) arg1, arg2, arg3, (void *) arg4, arg5);
+ break;
+ }
+ return rc;
+}
+
+int
+_syscall_open(const char* name, int flags)
+{
+ static int fd = 2;
+ ihandle_t ihandle;
+
+ if ((ihandle = of_open (name)) == 0)
+ {
+ printk ("Cannot open %s\n", name);
+ return -1;
+ }
+
+ fd++;
+ fd_array[fd] = ihandle;
+
+ return fd;
+}
+
+long
+_system_call(long arg0, long arg1, long arg2, long arg3,
+ long arg4, long arg5, long arg6, int nr)
+{
+ long rc = -1;
+ switch (nr)
+ {
+
+ case _open_sc_nr:
+ rc = _syscall_open ((void *) arg0, arg1);
+ break;
+ case _read_sc_nr:
+ rc = _syscall_read (arg0, (void *) arg1, arg2);
+ break;
+ case _close_sc_nr:
+ _syscall_close (arg0);
+ break;
+ case _lseek_sc_nr:
+ rc = _syscall_lseek (arg0, arg1, arg2);
+ break;
+ case _write_sc_nr:
+ rc = _syscall_write (arg0, (void *) arg1, arg2);
+ break;
+ case _ioctl_sc_nr:
+ rc = _syscall_ioctl (arg0, arg1, (void *) arg2);
+ break;
+ case _socket_sc_nr:
+ rc = _syscall_socket (arg0, arg1, arg2, arg3,
+ arg4, arg5, arg6);
+ break;
+ }
+ return rc;
+}
+
+void _exit(int status);
+
+void
+exit(int status)
+{
+ _exit(status);
+}
diff --git a/clients/net-snk/kernel/timer.c b/clients/net-snk/kernel/timer.c
new file mode 100644
index 0000000..a57a463
--- /dev/null
+++ b/clients/net-snk/kernel/timer.c
@@ -0,0 +1,67 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+#include <types.h>
+
+//*******************************************************************
+// variable "tb_freq" contains the frequency in Hz
+// and is read from the device tree (setup by LLFW) in "init.c"
+uint64_t tb_freq;
+
+//-------------------------------------------------------------------
+// Read the current timebase
+uint64_t get_time(void)
+{
+ uint64_t act;
+
+ __asm__ __volatile__(
+ "0: mftbu %0 ;\
+ mftbl %%r0 ; \
+ mftbu %%r4 ; \
+ cmpw %0,%%r4 ; \
+ bne 0b; \
+ sldi %0,%0,32; \
+ or %0,%0,%%r0"
+ : "=r"(act)
+ : /* no inputs */
+ : "r0", "r4");
+ return act;
+}
+
+//-------------------------------------------------------------------
+// wait for ticks/scale timebase ticks
+void wait_ticks(uint64_t ticks)
+{
+ uint64_t timeout = get_time() + ticks;
+ while (get_time() < timeout) {
+ unsigned int i;
+ for (i = 1000; i > 0; i--)
+ __asm__ __volatile__ ("" : : : "memory");
+ }
+}
+
+//-------------------------------------------------------------------
+// wait for (at least) usecs microseconds
+void udelay(unsigned int usecs)
+{
+ // first multiply the usec with timebase and then devide
+ // because 1.000.000 is relatively huge compared to usecs
+ wait_ticks((usecs*tb_freq)/1000000);
+}
+
+//-------------------------------------------------------------------
+// wait for (at least) msecs milliseconds
+void mdelay(unsigned int msecs)
+{
+ // first multiply the msec and timebase and then devide
+ // because 1.000 is relatively huge compared to msecs
+ wait_ticks((msecs*tb_freq)/1000);
+}
diff --git a/clients/net-snk/libc/Makefile b/clients/net-snk/libc/Makefile
new file mode 100644
index 0000000..82e2b4c
--- /dev/null
+++ b/clients/net-snk/libc/Makefile
@@ -0,0 +1,48 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2007 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 TOP
+ TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd)
+ export TOP
+endif
+include $(TOP)/make.rules
+
+
+CFLAGS = -g -I$(TOP)/include -I$(LIBCMNDIR)/libc/include -O2 \
+ -fno-builtin -ffreestanding -nostdinc -msoft-float -Wall
+LDFLAGS= -nostdlib
+
+OBJS = socket/socket.o time/time.o sbrk.o io.o ioctl.o
+SUBDIRS = $(filter-out ./,$(dir $(OBJS)))
+
+
+all: libc-glue.o
+
+libc-glue.o: subdirs sbrk.o io.o ioctl.o
+ $(LD) $(LDFLAGS) $(OBJS) -o $@ -r
+
+
+subdirs :
+ for dir in $(SUBDIRS); do \
+ $(MAKE) -C $$dir DIRECTORY=$(DIRECTORY)$$dir || exit 1; \
+ done
+
+clean:
+ $(RM) -f *.a *.o
+ @for dir in $(SUBDIRS); do \
+ $(CLEAN) ; \
+ $(MAKE) -C $$dir DIRECTORY=$(DIRECTORY)$$dir clean; \
+ done
+
+include $(TOP)/make.depend
+
diff --git a/clients/net-snk/libc/io.c b/clients/net-snk/libc/io.c
new file mode 100644
index 0000000..937e51a
--- /dev/null
+++ b/clients/net-snk/libc/io.c
@@ -0,0 +1,53 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+
+#include "stddef.h"
+#include "systemcall.h"
+#include "unistd.h"
+
+
+ssize_t write(int fd, const void *buf, size_t count)
+{
+ return syscall_3 (_write_sc_nr, fd, (long) buf, count);
+}
+
+ssize_t read(int fd, void *buf, size_t count)
+{
+ return syscall_3 (_read_sc_nr, fd, (long) buf, count);
+}
+
+ssize_t lseek(int fd, long off, int whence)
+{
+ return syscall_3 (_lseek_sc_nr, fd, off, whence);
+}
+
+int open(const char *name, int flags)
+{
+ return syscall_2 (_open_sc_nr, (long int) name, flags);
+}
+
+int close(int fd)
+{
+ return syscall_1(_close_sc_nr,fd);
+}
+
+int
+getchar(void)
+{
+ char buf;
+ int i;
+
+ if((i = read (1, &buf, 1)) == 1)
+ return (int) buf;
+ return -1;
+}
diff --git a/clients/net-snk/libc/ioctl.c b/clients/net-snk/libc/ioctl.c
new file mode 100644
index 0000000..64d666c
--- /dev/null
+++ b/clients/net-snk/libc/ioctl.c
@@ -0,0 +1,20 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+
+#include "systemcall.h"
+
+
+int ioctl(int fd, int request, void *data)
+{
+ return syscall_3 (_ioctl_sc_nr, fd, request, (long) data);
+}
diff --git a/clients/net-snk/libc/sbrk.c b/clients/net-snk/libc/sbrk.c
new file mode 100644
index 0000000..2969018
--- /dev/null
+++ b/clients/net-snk/libc/sbrk.c
@@ -0,0 +1,37 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+#define HEAP_SIZE 0x200000
+
+
+static char heap[HEAP_SIZE];
+static char *actptr;
+
+void *sbrk(int increment)
+{
+ char *oldptr;
+
+ /* Called for the first time? Then init the actual pointer */
+ if (!actptr) {
+ actptr = heap;
+ }
+
+ if (actptr + increment > heap + HEAP_SIZE) {
+ /* Out of memory */
+ return (void *)-1;
+ }
+
+ oldptr = actptr;
+ actptr += increment;
+
+ return oldptr;
+}
diff --git a/clients/net-snk/libc/socket/Makefile b/clients/net-snk/libc/socket/Makefile
new file mode 100644
index 0000000..c18fe15
--- /dev/null
+++ b/clients/net-snk/libc/socket/Makefile
@@ -0,0 +1,41 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2007 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 TOP
+ TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd)
+ export TOP
+endif
+include $(TOP)/make.rules
+
+
+CFLAGS = -g -I$(TOP)/include -O2 -fno-builtin -ffreestanding -msoft-float -Wall
+LDFLAGS= -nostdlib
+
+
+OBJS=send.c
+
+
+all: socket.o
+
+
+socket.o: $(OBJS:.c=.o)
+ $(LD) $(LDFLAGS) -r $^ -o $@
+
+%.o : %.c
+ $(CC) $(CFLAGS) -c $^ -o $@
+
+
+clean:
+ $(RM) -f *.o *.i *.s
+
+distclean mrproper: clean
diff --git a/clients/net-snk/libc/socket/send.c b/clients/net-snk/libc/socket/send.c
new file mode 100644
index 0000000..0095822
--- /dev/null
+++ b/clients/net-snk/libc/socket/send.c
@@ -0,0 +1,36 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+
+#include "sys/socket.h"
+
+int socket(int dom, int type, int proto, char *mac_addr)
+{
+ return syscall_5 (_socket_sc_nr, _sock_sc_nr, dom, type, proto, (long)mac_addr);
+}
+
+int sendto(int fd, const void* buffer, int len, int flags, const void* sock_addr, int sock_addr_len)
+{
+ return syscall_7 (_socket_sc_nr, _sendto_sc_nr, fd, (long) buffer, len, flags, (long) sock_addr, sock_addr_len);
+}
+
+int send(int fd, void* buffer, int len, int flags)
+{
+ return syscall_5 (_socket_sc_nr, _send_sc_nr, fd, (long) buffer, len, flags);
+}
+
+int recv(int fd, void* buffer, int len, int flags)
+{
+ return syscall_5 (_socket_sc_nr, _recv_sc_nr, fd, (long) buffer, len, flags);
+}
+
+
diff --git a/clients/net-snk/libc/time/Makefile b/clients/net-snk/libc/time/Makefile
new file mode 100644
index 0000000..1db98e7
--- /dev/null
+++ b/clients/net-snk/libc/time/Makefile
@@ -0,0 +1,43 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2007 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 TOP
+ TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd)
+ export TOP
+
+endif
+include $(TOP)/make.rules
+
+
+CFLAGS = -g -I$(TOP)/include -I$(LIBCMNDIR)/libc/include -O2 -msoft-float \
+ -Wall -fno-builtin -ffreestanding -nostdinc
+LDFLAGS= -nostdlib
+
+
+OBJS=timer.c ftime.c
+
+
+all: time.o
+
+
+time.o: $(OBJS:.c=.o)
+ $(LD) $(LDFLAGS) -r $^ -o $@
+
+%.o : %.c
+ $(CC) $(CFLAGS) -c $^ -o $@
+
+
+clean:
+ $(RM) -f *.o *.i *.s
+
+distclean mrproper: clean
diff --git a/clients/net-snk/libc/time/ftime.c b/clients/net-snk/libc/time/ftime.c
new file mode 100644
index 0000000..139988e
--- /dev/null
+++ b/clients/net-snk/libc/time/ftime.c
@@ -0,0 +1,38 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+
+#include <time.h>
+#include <rtas.h>
+#include <stdio.h>
+
+time_t
+time(time_t *tod)
+{
+ dtime ts;
+
+ rtas_get_time_of_day(&ts);
+ printf("debug!!\n");
+
+ printf("year : %d\n", ts.year);
+ printf("month : %d\n", ts.month);
+ printf("day : %d\n", ts.day);
+ printf("hour : %d\n", ts.hour);
+ printf("minute: %d\n", ts.minute);
+ printf("second: %d\n", ts.second);
+ printf("nano : %d\n", ts.nano);
+ printf("debug ende\n");
+
+// if(tod)
+// *tod = t;
+ return 0;
+}
diff --git a/clients/net-snk/libc/time/timer.c b/clients/net-snk/libc/time/timer.c
new file mode 100644
index 0000000..b0effaa
--- /dev/null
+++ b/clients/net-snk/libc/time/timer.c
@@ -0,0 +1,39 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+
+#include "time.h"
+
+int get_msec_ticks()
+{
+ return tb_freq/1000;
+}
+
+int get_sec_ticks()
+{
+ return tb_freq;
+}
+
+void set_timer(int val)
+{
+ asm volatile ("mtdec %0"::"r" (val));
+}
+
+int get_timer()
+{
+ int val;
+ asm volatile ("mfdec %0":"=r" (val));
+ return val;
+}
+
+
+
diff --git a/clients/net-snk/make.depend b/clients/net-snk/make.depend
new file mode 100644
index 0000000..31997fc
--- /dev/null
+++ b/clients/net-snk/make.depend
@@ -0,0 +1,36 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2007 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
+# ****************************************************************************/
+
+-include .depend
+
+depend :
+ @rm -rf .depend
+ifdef OBJS
+ @touch .depend && \
+ $(CC) -M $(CFLAGS) $(OBJS:.o=.c) >> .depend
+#else
+# @echo "OBJ is NOT defined"
+endif
+ifdef OBJS2
+ @$(CC) -M $(CFLAGS) $(OBJS2:.o=.S) >> .depend
+#else
+# @echo "OBJ2 is NOT definde"
+endif
+ @for dir in $(SUBDIRS); do \
+ $(MAKE) -C $$dir depend ; \
+ done
+
+mrproper :
+ @rm -rf .depend ; \
+ for dir in $(SUBDIRS); do \
+ $(MAKE) -C $$dir mrproper ; \
+ done
diff --git a/clients/net-snk/make.rules b/clients/net-snk/make.rules
new file mode 100644
index 0000000..1343d82
--- /dev/null
+++ b/clients/net-snk/make.rules
@@ -0,0 +1,43 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2007 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
+# ****************************************************************************/
+
+CROSS ?= powerpc64-linux-
+
+HOSTCC ?= gcc
+HOSTCFLAGS = -g -Wall -W -O2 -I. -I../include
+
+INCLCMNDIR ?= $(TOP)/../../include
+LIBCMNDIR ?= $(TOP)/../../lib
+CFLAGS = -g -I. -I$(TOP)/include -I$(LIBCMNDIR)/libc/include \
+ -I$(LIBCMNDIR)/libbootmsg -I$(INCLCMNDIR)/$(CPUARCH) \
+ -O2 -fno-builtin -ffreestanding -msoft-float -mno-altivec \
+ -Wall $(FLAG)
+LDFLAGS = -nostdlib
+ASFLAGS = -I. -I$(TOP)/include -Wa,-mregnames -I$(INCLCMNDIR)/$(CPUARCH)
+DD = dd
+
+ifdef NEW_BUILD
+MAKEFLAGS = --silent
+CC = echo -e "\t[CC]\t$(DIRECTORY)$@"; $(CROSS)gcc -m64
+AS = echo -e "\t[AS]\t$(DIRECTORY)$@"; $(CROSS)as -m64
+LD = echo -e "\t[LD]\t$(DIRECTORY)$@"; $(CROSS)ld -melf64ppc
+CLEAN = echo -e "\t[CLEAN]\t$(DIRECTORY)$$dir"
+else
+CC = $(CROSS)gcc -m64
+AS = $(CROSS)as -m64
+LD = $(CROSS)ld -melf64ppc
+CLEAN = echo -n
+endif
+
+OBJCOPY = $(CROSS)objcopy
+OBJDUMP = $(CROSS)objdump
+STRIP = $(CROSS)strip
diff --git a/clients/net-snk/oflib/Makefile b/clients/net-snk/oflib/Makefile
new file mode 100644
index 0000000..c4a8219
--- /dev/null
+++ b/clients/net-snk/oflib/Makefile
@@ -0,0 +1,41 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2007 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 TOP
+ TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd)
+ export TOP
+endif
+include $(TOP)/make.rules
+
+OBJS = rtas.o of.o pci.o
+OBJS2 = entry.o
+
+all: oflib.o
+
+
+oflib.o: $(OBJS) $(OBJS2)
+ $(LD) $(LDFLAGS) $^ -o oflib.o -r
+
+clean:
+ $(RM) -f $(OBJS) $(OBJS2) oflib.o
+
+include $(TOP)/make.depend
+
+
+#mrproper : clean
+# rm -rf .depend
+#
+#depend :
+# @rm -rf .depend ; touch .depend ; \
+# makedepend -v -f.depend -- $(CFLAGS) -- $(OBJS:.o=.c) 2> /dev/null ; \
+# $(CC) -M $(CFLAGS) $(OBJS2:.o=.S) >> .depend
diff --git a/clients/net-snk/oflib/entry.S b/clients/net-snk/oflib/entry.S
new file mode 100644
index 0000000..e88c617
--- /dev/null
+++ b/clients/net-snk/oflib/entry.S
@@ -0,0 +1,37 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+
+ .globl call_client_interface
+call_client_interface:
+ .globl .call_client_interface
+.call_client_interface:
+ ld r4, _prom_entry@got(r2) # Load prom entry point
+ mflr r0
+ ld r4, 0(r4)
+ stdu r1, -16(r1)
+ mtctr r4
+ std r0, 8(r1)
+ bctrl
+ ld r0, 8(r1)
+ mtlr r0
+ addi r1, r1, 16
+ blr
+
+ .globl rtas_call_entry
+rtas_call_entry:
+ .globl .rtas_call_entry
+.rtas_call_entry:
+ mtctr r5
+ bctr
+
+
diff --git a/clients/net-snk/oflib/of.c b/clients/net-snk/oflib/of.c
new file mode 100644
index 0000000..7c65c2e
--- /dev/null
+++ b/clients/net-snk/oflib/of.c
@@ -0,0 +1,357 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+
+#include <of.h>
+#include <string.h>
+
+extern void call_client_interface(of_arg_t *);
+
+extern inline int
+of_0_1(const char *serv)
+{
+ of_arg_t arg = {
+ p32cast serv,
+ 0, 1,
+ { 0 }
+ };
+
+ call_client_interface(&arg);
+
+ return arg.args[0];
+}
+
+extern inline void
+of_1_0(const char *serv, int arg0)
+{
+ of_arg_t arg = {
+ p32cast serv,
+ 1, 0,
+ {arg0, 0}
+ };
+
+ call_client_interface(&arg);
+}
+
+extern inline unsigned int
+of_1_1(const char *serv, int arg0)
+{
+ of_arg_t arg = {
+ p32cast serv,
+ 1, 1,
+ {arg0, 0}
+ };
+
+ call_client_interface(&arg);
+ return arg.args[1];
+}
+
+extern inline unsigned int
+of_1_2(const char *serv, int arg0, int *ret0)
+{
+ of_arg_t arg = {
+ p32cast serv,
+ 1, 2,
+ {arg0, 0, 0}
+ };
+
+ call_client_interface(&arg);
+ *ret0 = arg.args[2];
+ return arg.args[1];
+}
+
+extern inline void
+of_2_0(const char *serv, int arg0, int arg1)
+{
+ of_arg_t arg = {
+ p32cast serv,
+ 2, 0,
+ {arg0, arg1, 0}
+ };
+
+ call_client_interface(&arg);
+}
+
+extern inline unsigned int
+of_2_1(const char *serv, int arg0, int arg1)
+{
+ of_arg_t arg = {
+ p32cast serv,
+ 2, 1,
+ {arg0, arg1, 0}
+ };
+
+ call_client_interface(&arg);
+ return arg.args[2];
+}
+
+extern inline unsigned int
+of_2_2(const char *serv, int arg0, int arg1, int *ret0)
+{
+ of_arg_t arg = {
+ p32cast serv,
+ 2, 2,
+ {arg0, arg1, 0, 0}
+ };
+
+ call_client_interface(&arg);
+ *ret0 = arg.args[3];
+ return arg.args[2];
+}
+
+extern inline unsigned int
+of_2_3(const char *serv, int arg0, int arg1, int *ret0, int *ret1)
+{
+ of_arg_t arg = {
+ p32cast serv,
+ 2, 3,
+ {arg0, arg1, 0, 0, 0}
+ };
+
+ call_client_interface(&arg);
+ *ret0 = arg.args[3];
+ *ret1 = arg.args[4];
+ return arg.args[2];
+}
+
+extern inline void
+of_3_0(const char *serv, int arg0, int arg1, int arg2)
+{
+ of_arg_t arg = {
+ p32cast serv,
+ 3, 0,
+ {arg0, arg1, arg2, 0}
+ };
+
+ call_client_interface(&arg);
+ return;
+}
+
+extern inline unsigned int
+of_3_1(const char *serv, int arg0, int arg1, int arg2)
+{
+ of_arg_t arg = {
+ p32cast serv,
+ 3, 1,
+ {arg0, arg1, arg2, 0}
+ };
+
+ call_client_interface(&arg);
+ return arg.args[3];
+}
+
+extern inline unsigned int
+of_3_2(const char *serv, int arg0, int arg1, int arg2, int *ret0)
+{
+ of_arg_t arg = {
+ p32cast serv,
+ 3, 2,
+ {arg0, arg1, arg2, 0, 0}
+ };
+
+ call_client_interface(&arg);
+ *ret0 = arg.args[4];
+ return arg.args[3];
+}
+
+extern inline unsigned int
+of_3_3(const char *serv, int arg0, int arg1, int arg2, int *ret0, int *ret1)
+{
+ of_arg_t arg = {
+ p32cast serv,
+ 3, 3,
+ {arg0, arg1, arg2, 0, 0, 0}
+ };
+
+ call_client_interface(&arg);
+ *ret0 = arg.args[4];
+ *ret1 = arg.args[5];
+ return arg.args[3];
+}
+
+extern inline unsigned int
+of_4_1(const char *serv, int arg0, int arg1, int arg2, int arg3)
+{
+ of_arg_t arg = {
+ p32cast serv,
+ 4, 1,
+ {arg0, arg1, arg2, arg3, 0}
+ };
+
+ call_client_interface(&arg);
+ return arg.args[4];
+}
+
+int
+of_interpret_1(void *s, void *ret)
+{
+ return of_1_2("interpret", p32cast s, ret);
+}
+
+void
+of_close(ihandle_t ihandle)
+{
+ of_1_0("close", ihandle);
+}
+
+int
+of_write(ihandle_t ihandle, void *s, int len)
+{
+ return of_3_1("write", ihandle, p32cast s, len);
+}
+
+int
+of_read(ihandle_t ihandle, void *s, int len)
+{
+ return of_3_1("read", ihandle, p32cast s, len);
+}
+
+int
+of_seek(ihandle_t ihandle, int poshi, int poslo)
+{
+ return of_3_1("seek", ihandle, poshi, poslo);
+}
+
+int
+of_getprop(phandle_t phandle, const char *name, void *buf, int len)
+{
+ return of_4_1("getprop", phandle, p32cast name, p32cast buf, len);
+}
+
+phandle_t
+of_peer(phandle_t phandle)
+{
+ return (phandle_t) of_1_1("peer", phandle);
+}
+
+phandle_t
+of_child(phandle_t phandle)
+{
+ return (phandle_t) of_1_1("child", phandle);
+}
+
+phandle_t
+of_parent(phandle_t phandle)
+{
+ return (phandle_t) of_1_1("parent", phandle);
+}
+
+phandle_t
+of_finddevice(const char *name)
+{
+ return (phandle_t) of_1_1("finddevice", p32cast name);
+}
+
+ihandle_t
+of_open(const char *name)
+{
+ return (ihandle_t) of_1_1("open", p32cast name);
+}
+
+void *
+of_claim(void *start, unsigned int size, unsigned int align)
+{
+ return(void *)(long)(size_t)of_3_1("claim", p32cast start, size, align);
+}
+
+void
+of_release(void *start, unsigned int size)
+{
+ (void) of_2_0("release", p32cast start, size);
+}
+
+unsigned int
+romfs_lookup(const char *name, void **addr)
+{
+ unsigned int high, low;
+ unsigned int i = of_2_3("ibm,romfs-lookup", p32cast name, strlen(name),
+ (int *) &high, (int *) &low);
+ *addr = (void*)(((unsigned long) high << 32) | (unsigned long) low);
+ return i;
+}
+
+void *
+of_call_method_3(const char *name, ihandle_t ihandle, int arg0)
+{
+ int entry, rc;
+ rc = of_3_2("call-method", p32cast name, ihandle, arg0, &entry);
+ return rc != 0 ? 0 : (void *) (long) entry;
+}
+
+int
+vpd_read(unsigned int offset, unsigned int length, char *data)
+{
+ int result;
+ long tmp = (long) data;
+ result = of_3_1("rtas-read-vpd", offset, length, (int) tmp);
+ return result;
+}
+
+int
+vpd_write(unsigned int offset, unsigned int length, char *data)
+{
+ int result;
+ long tmp = (long) data;
+ result = of_3_1("rtas-write-vpd", offset, length, (int) tmp);
+ return result;
+}
+
+static void
+ipmi_oem_led_set(int type, int instance, int state)
+{
+ return of_3_0("set-led", type, instance, state);
+}
+
+int
+write_mm_log(char *data, unsigned int length, unsigned short type)
+{
+ long tmp = (long) data;
+
+ ipmi_oem_led_set(2, 0, 1);
+ return of_3_1("write-mm-log", (int) tmp, length, type);
+}
+
+int
+of_yield(void)
+{
+ return of_0_1("yield");
+}
+
+void *
+of_set_callback(void *addr)
+{
+ return (void *) (long) (size_t) of_1_1("set-callback", p32cast addr);
+}
+
+void
+bootmsg_warning(short id, const char *str, short lvl)
+{
+ (void) of_3_0("bootmsg-warning", id, lvl, p32cast str);
+}
+
+void
+bootmsg_error(short id, const char *str)
+{
+ (void) of_2_0("bootmsg-error", id, p32cast str);
+}
+
+void
+bootmsg_debugcp(short id, const char *str, short lvl)
+{
+ (void) of_3_0("bootmsg-debugcp", id, lvl, p32cast str);
+}
+
+void
+bootmsg_cp(short id)
+{
+ (void) of_1_0("bootmsg-cp", id);
+}
diff --git a/clients/net-snk/oflib/pci.c b/clients/net-snk/oflib/pci.c
new file mode 100644
index 0000000..6b774fa
--- /dev/null
+++ b/clients/net-snk/oflib/pci.c
@@ -0,0 +1,97 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+#include <rtas.h>
+#include <of.h>
+#include <pci.h>
+#include <string.h>
+#include <kernel.h>
+#include <cpu.h>
+
+int
+pci_calc_bar_size(long long puid, int bus, int devfn, int bar)
+{
+ int size;
+ int old;
+ bar = bar * 4 + 0x10;
+ old = rtas_pci_config_read(puid, 4, bus, devfn, bar);
+ rtas_pci_config_write(puid, 4, bus, devfn, bar, 0xffffffff);
+ size = (rtas_pci_config_read(puid, 4, bus, devfn, bar) & (-4)) * -1;
+ rtas_pci_config_write(puid, 4, bus, devfn, bar, old);
+ return size;
+}
+
+int
+pci_get_bar_start(long long puid, int bus, int devfn, int bar)
+{
+ return rtas_pci_config_read(puid, 4, bus, devfn, bar * 4 + 0x10);
+}
+
+void
+pci_set_bar_start(long long puid, int bus, int devfn, int bar, int value)
+{
+ rtas_pci_config_write(puid, 4, bus, devfn, bar * 4 + 0x10, value);
+}
+
+unsigned int
+read_io(void *addr, size_t sz)
+{
+ unsigned int ret;
+
+ switch (sz) {
+ case 1:
+ set_ci();
+ ret = (unsigned int) *((unsigned char *) addr);
+ clr_ci();
+ break;
+ case 2:
+ set_ci();
+ ret = (unsigned int) *((unsigned short *) addr);
+ clr_ci();
+ break;
+ case 4:
+ set_ci();
+ ret = *((unsigned int *) addr);
+ clr_ci();
+ break;
+ default:
+ ret = 0;
+ }
+
+ return ret;
+}
+
+int
+write_io(void *addr, unsigned int value, size_t sz)
+{
+ switch (sz) {
+ case 1:
+ set_ci();
+ *((unsigned char *) addr) = (unsigned char) value;
+ clr_ci();
+ break;
+ case 2:
+ set_ci();
+ *((unsigned short *) addr) = (unsigned short) value;
+ clr_ci();
+ break;
+ case 4:
+ set_ci();
+ *((unsigned int *) addr) = value;
+ clr_ci();
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/clients/net-snk/oflib/rtas.c b/clients/net-snk/oflib/rtas.c
new file mode 100644
index 0000000..037baf0
--- /dev/null
+++ b/clients/net-snk/oflib/rtas.c
@@ -0,0 +1,334 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <rtas.h>
+#include <of.h>
+#include <types.h>
+#include "kernel.h"
+
+typedef int rtas_arg_t;
+
+typedef struct {
+ int token;
+ int nargs;
+ int nret;
+ rtas_arg_t args[16];
+ rtas_arg_t *rets; /* Pointer to return values in args[]. */
+} rtas_args_t;
+
+rtas_args_t rtas_args;
+
+typedef struct {
+ void *rtas_start;
+ void *rtas_entry;
+ int rtas_size;
+ phandle_t dev;
+} rtas_t;
+
+extern rtas_t _rtas;
+static int instantiate_rtas(void);
+void rtas_call_entry(rtas_args_t *, void *, void *);
+
+int
+rtas_token(const char *service)
+{
+ int token;
+ int retVal;
+ if (_rtas.dev == 0)
+ instantiate_rtas();
+
+ retVal = of_getprop(_rtas.dev, service, &token, sizeof(token));
+ if (retVal == -1) {
+ token = 0;
+ }
+ return token;
+}
+
+int
+rtas_call(int token, int nargs, int nret, int *outputs, ...)
+{
+ va_list list;
+ int i;
+
+ rtas_args.token = token;
+ rtas_args.nargs = nargs;
+ rtas_args.nret = nret;
+ rtas_args.rets = (rtas_arg_t *) & (rtas_args.args[nargs]);
+ va_start(list, outputs);
+ for (i = 0; i < nargs; ++i) {
+ rtas_args.args[i] = (rtas_arg_t) (va_arg(list, unsigned int));
+ }
+ va_end(list);
+
+ for (i = 0; i < nret; ++i)
+ rtas_args.rets[i] = 0;
+
+ rtas_call_entry(&rtas_args, _rtas.rtas_start, _rtas.rtas_entry);
+ if (nret > 0 && outputs != 0)
+ for (i = 0; i < nret; i++)
+ outputs[i] = rtas_args.rets[i];
+#if 0
+ printf("rtas call %x %x %x args: %x %x %x %x %x %x %x %x\n",
+ token, nargs, nret,
+ rtas_args.args[0],
+ rtas_args.args[1],
+ rtas_args.args[2],
+ rtas_args.args[3],
+ rtas_args.args[4], rtas_args.args[5], outputs[0], outputs[1]);
+#endif
+ return ((nret > 0) ? rtas_args.rets[0] : 0);
+}
+
+rtas_t _rtas;
+
+static int
+instantiate_rtas(void)
+{
+ long long *rtas_mem_space;
+ ihandle_t ihandle;
+ _rtas.dev = of_finddevice("/rtas");
+ if ((long) _rtas.dev < 0) {
+ printf("Could not open /rtas\n");
+ return -1;
+ }
+
+ of_getprop(_rtas.dev, "rtas-size", &_rtas.rtas_size,
+ sizeof(_rtas.rtas_size));
+
+ if (_rtas.rtas_size <= 0) {
+ printf("Size of rtas (%x) too small to make sense\n",
+ _rtas.rtas_size);
+ return -1;
+ }
+
+ rtas_mem_space = (long long *) malloc_aligned(_rtas.rtas_size, 0x100);
+
+ if (!rtas_mem_space) {
+ printf("Failed to allocated memory for RTAS\n");
+ return -1;
+ }
+
+ ihandle = of_open("/rtas");
+
+ if ((long) ihandle < 0) {
+ printf("Could not open /rtas\n");
+ return -1;
+ }
+
+ if ((long) (_rtas.rtas_entry = of_call_method_3("instantiate-rtas",
+ ihandle,
+ p32cast rtas_mem_space))
+ > 0) {
+ _rtas.rtas_start = rtas_mem_space;
+ } else {
+ printf("instantiate-rtas failed\n");
+ return -1;
+ }
+#if 0
+ printf("\ninstantiate-rtas at %x size %x entry %x\n",
+ _rtas.rtas_start, _rtas.rtas_size, _rtas.rtas_entry);
+#endif
+ return 0;
+}
+
+static int read_pci_config_token = 0;
+static int write_pci_config_token = 0;
+static int ibm_read_pci_config_token = 0;
+static int ibm_write_pci_config_token = 0;
+static int ibm_update_flash_64_and_reboot_token = 0;
+static int ibm_update_flash_64_token = 0;
+static int manage_flash_token = 0;
+static int system_reboot_token = 0;
+static int get_time_of_day_token = 0;
+static int set_time_of_day_token = 0;
+static int start_cpu_token = 0;
+static int stop_self_token = 0;
+
+void
+rtas_init()
+{
+ int ret;
+ ret = instantiate_rtas();
+ if (ret)
+ return;
+ read_pci_config_token = rtas_token("read-pci-config");
+ ibm_read_pci_config_token = rtas_token("ibm,read-pci-config");
+ write_pci_config_token = rtas_token("write-pci-config");
+ ibm_write_pci_config_token = rtas_token("ibm,write-pci-config");
+ ibm_update_flash_64_and_reboot_token =
+ rtas_token("ibm,update-flash-64-and-reboot");
+ ibm_update_flash_64_token = rtas_token("ibm,update-flash-64");
+ manage_flash_token = rtas_token("ibm,manage-flash-image");
+ system_reboot_token = rtas_token("system-reboot");
+ get_time_of_day_token = rtas_token("get-time-of-day");
+ set_time_of_day_token = rtas_token("set-time-of-day");
+ start_cpu_token = rtas_token("start-cpu");
+ stop_self_token = rtas_token("stop-self");
+}
+
+
+int
+rtas_pci_config_read(long long puid, int size, int bus, int devfn, int offset)
+{
+ int value[2];
+
+ if (ibm_read_pci_config_token && puid) {
+ rtas_call(ibm_read_pci_config_token, 4, 2, value,
+ bus << 16 | devfn << 8 | offset,
+ puid >> 32, puid & 0xffffffffULL, size);
+ } else if (read_pci_config_token) {
+ rtas_call(read_pci_config_token, 2, 2, value,
+ bus << 16 | devfn << 8 | offset, size);
+ }
+
+ return value[1];
+}
+
+int
+rtas_pci_config_write(long long puid, int size, int bus, int devfn,
+ int offset, int value)
+{
+ int rc;
+
+ if (ibm_write_pci_config_token && puid) {
+ rtas_call(ibm_write_pci_config_token, 5, 1, &rc,
+ bus << 16 | devfn << 8 | offset,
+ puid >> 32, puid & 0xffffffffULL, size, value);
+ } else
+ rtas_call(write_pci_config_token, 3, 1, &rc,
+ bus << 16 | devfn << 8 | offset, size, value);
+
+ return rc;
+}
+
+/* a simple blocklist like this will us give no animation during flashing */
+
+struct block_list {
+ long long size; //size of blocklist in bytes
+ long long address; //address of memory area
+ long long length; //lenght of memory area
+};
+
+int
+rtas_ibm_update_flash_64_and_reboot(long long address, long long length)
+{
+ int rc;
+ struct block_list block_list;
+ block_list.size = sizeof(block_list);
+ block_list.address = address;
+ block_list.length = length;
+ if (ibm_update_flash_64_and_reboot_token)
+ rtas_call(ibm_update_flash_64_and_reboot_token, 1, 1, &rc,
+ &block_list);
+
+ return rc;
+}
+
+int
+rtas_ibm_manage_flash(int mode)
+{
+ int rc;
+ if (manage_flash_token)
+ rtas_call(manage_flash_token, 1, 1, &rc, mode);
+ return rc;
+}
+
+int
+rtas_ibm_update_flash_64(long long address, long long length)
+{
+ int rc;
+ struct block_list block_list;
+ block_list.size = sizeof(block_list);
+ block_list.address = address;
+ block_list.length = length;
+ if (ibm_update_flash_64_token)
+ rtas_call(ibm_update_flash_64_token, 1, 1, &rc, &block_list);
+
+ return rc;
+}
+
+int
+rtas_system_reboot()
+{
+ int rc;
+ if (system_reboot_token)
+ rtas_call(system_reboot_token, 0, 1, &rc);
+ return rc;
+}
+
+
+int
+rtas_get_time_of_day(dtime * get)
+{
+ int rc = -1;
+ unsigned int year;
+ unsigned int month;
+ unsigned int day;
+ unsigned int hour;
+ unsigned int minute;
+ unsigned int second;
+ unsigned int nano;
+
+ if (get_time_of_day_token)
+ rtas_call(get_time_of_day_token, 0, 8, &rc, &year, &month, &day,
+ &hour, &minute, &second, &nano);
+
+ get->year = year;
+ get->month = month;
+ get->day = day;
+ get->hour = hour;
+ get->minute = minute;
+ get->second = second;
+ get->nano = nano;
+
+ return rc;
+}
+
+int
+rtas_set_time_of_day(dtime * set)
+{
+ int rc = -1;
+ if (set_time_of_day_token)
+ rtas_call(set_time_of_day_token, 7, 1, &rc, set->year,
+ set->month, set->day, set->hour, set->minute,
+ set->second, set->nano);
+ return rc;
+}
+
+
+int
+rtas_start_cpu(int pid, thread_t func_ptr, int r3)
+{
+ int rc;
+ if (start_cpu_token)
+ rtas_call(start_cpu_token, 3, 1, &rc, pid,
+ (int) (long) func_ptr, (int) r3);
+ printk("start-cpu called %d %x %x %x\n", rc, start_cpu_token, pid,
+ (long) func_ptr);
+ return rc;
+}
+
+int
+rtas_stop_self()
+{
+ int rc;
+ // fixme
+ stop_self_token = 0x20;
+
+ if (stop_self_token) {
+ rtas_call(stop_self_token, 0, 1, &rc);
+ printk("TOK\n");
+ }
+ return rc;
+}
diff --git a/clients/net-snk/sec-client.lds b/clients/net-snk/sec-client.lds
new file mode 100644
index 0000000..a1b13a4
--- /dev/null
+++ b/clients/net-snk/sec-client.lds
@@ -0,0 +1,50 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", "elf64-powerpc")
+OUTPUT_ARCH(powerpc:common64)
+ENTRY(_entry)
+
+SECTIONS {
+ .client 0x200000:
+ {
+ __client_start = .;
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ *(.sfpr .glink)
+ *(.rodata .rodata.* .gnu.linkonce.r.*)
+ KEEP (*(.opd))
+ . = ALIGN(256);
+ *(.data .data.* .gnu.linkonce.d.*)
+ . = ALIGN(256);
+/* *(*COM* .bss .gnu.linkonce.b.*) */
+ } =0x60000000
+
+ .lowmem :
+ {
+ _lowmem_start = .;
+ *(.lowmem)
+ _lowmem_end = .;
+ }
+
+ .got :
+ {
+ . = ALIGN(8);
+ _got = .;
+ *(.got .toc)
+ _got_end = .;
+ }
+ .bss :
+ {
+ *(*COM* .bss .gnu.linkonce.b.*)
+ __client_end = .;
+ }
+}
diff --git a/clients/takeover/Makefile b/clients/takeover/Makefile
new file mode 100644
index 0000000..acd6c48
--- /dev/null
+++ b/clients/takeover/Makefile
@@ -0,0 +1,60 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2007 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
+# ****************************************************************************/
+
+include $(TOPCMNDIR)/make.rules
+
+SNKDIR = $(TOPCMNDIR)/clients/net-snk
+
+CFLAGS += -fno-builtin -I$(LIBCMNDIR)/libc/include
+CFLAGS += -I$(SNKDIR)/include -I. $(CPUARCHDEF)
+CFLAGS += -I$(INCLBRDDIR) -I.. -O2 -msoft-float
+CFLAGS += $(PLATFORM) -I$(INCLCMNDIR)/$(CPUARCH)
+CFLAGS += $(BOOT) -Wa,-mregnames $(RELEASE)
+
+OBJS = $(SNKDIR)/kernel/kernel.o
+OBJS += $(SNKDIR)/oflib/oflib.o
+OBJS += $(SNKDIR)/libc/time/timer.o
+OBJS += $(LIBCMNDIR)/libc.a entry.o main.o of.elf takeover.o
+
+%.o: %.S
+ $(CC) $(CFLAGS) -c $^
+
+all: takeover.elf
+
+takeover.elf: ppc32wrap.o takeover.elf32
+ @echo " ====== Building $@ ======"
+ $(CROSS)gcc -m32 -N -Wl,-melf32ppclinux -static -nostdlib \
+ -Wl,-Ttext,0x400000 -Wl,-Tdata,0x400100 \
+ $(CFLAGS) $^ -o $@
+
+takeover.elf64: entry.o main.o takeover.o $(SNKDIR)/libc/time/timer.o of.elf
+ make -C $(LIBCMNDIR) libc
+ make -C $(CLIENTSDIR)
+ $(LD) $(LDFLAGS) -o $@ -Tclient.lds $(OBJS)
+
+of.elf: ../../boot_rom.bin
+ $(OBJCOPY) --input-target=binary --binary-architecture=powerpc -O elf64-powerpc $< $@
+
+takeover.elf32: takeover.elf64
+ $(OBJCOPY) -O binary $^ takeover.tmp
+ $(OBJCOPY) --input-target=binary --binary-architecture=powerpc -O elf32-powerpc takeover.tmp $@
+
+ppc32wrap.o: ppc32wrap.S
+ $(CROSS)gcc -m32 -a32 $(CFLAGS) -c $< -o $@
+
+clean distclean:
+ make -C $(LIBCMNDIR) clean
+ make -C $(CLIENTSDIR) clean
+ $(RM) *.o *.bin *.elf
+ $(RM) takeover.elf32 takeover.elf64 takeover.tmp
+%.o: %.oco
+ cp -f $< $@
diff --git a/clients/takeover/client.lds b/clients/takeover/client.lds
new file mode 100644
index 0000000..2352db5
--- /dev/null
+++ b/clients/takeover/client.lds
@@ -0,0 +1,60 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+OUTPUT_FORMAT("elf64-powerpc", "elf64-powerpc", "elf64-powerpc")
+OUTPUT_ARCH(powerpc:common64)
+ENTRY(_entry)
+
+SECTIONS {
+ .client 0x400100:
+ {
+ __client_start = .;
+ *(.start)
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ *(.sfpr .glink)
+ *(.rodata .rodata.* .gnu.linkonce.r.*)
+ KEEP (*(.opd))
+ . = ALIGN(256);
+ *(.data .data.* .gnu.linkonce.d.*)
+ . = ALIGN(256);
+ } =0x60000000
+
+ .diag_table :
+ {
+ _diag_init_start = .;
+ *(.diag_init)
+ _diag_init_end = .;
+ }
+ .lowmem :
+ {
+ _lowmem_start = .;
+ *(.lowmem)
+ _lowmem_end = .;
+ }
+
+ .got :
+ {
+ . = ALIGN(8);
+ _got = .;
+ *(.got .toc)
+ _got_end = .;
+ }
+ .comment : { *(.comment) }
+ .branch_lt : { *(.branch_lt) }
+ .bss :
+ {
+ __bssStart = .;
+ *(*COM* .bss .gnu.linkonce.b.*)
+ __client_end = .;
+ __bssSize = . - __bssStart;
+ }
+}
diff --git a/clients/takeover/entry.S b/clients/takeover/entry.S
new file mode 100644
index 0000000..32f2300
--- /dev/null
+++ b/clients/takeover/entry.S
@@ -0,0 +1,93 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+#include <macros.h>
+#include "takeover.h"
+
+ .globl _wrapclient
+ .section ".start"
+ .align 3
+
+_wrapclient:
+ bcl 20,31,over # branch after pointer table
+base:
+ .align 3
+.LCgot: .quad _got-base+0x8000
+over:
+ mflr r8 # gpr 8 is the base
+ ld r2, .LCgot-base(r8) # load got pointer
+ add r2, r2, r8 # add base
+ li 14, 0
+ oris 14, 14, __bssSize@h
+ ori 14, 14, __bssSize@l
+ addi 14,14,7
+ srwi 14,14,3
+ mtctr 14
+ li 14, 0
+ oris 14, 14, __bssStart@h
+ ori 14, 14, __bssStart@l
+ subi 14, 14, 8
+ li 15, 0
+1:
+ stdu 15,8(14)
+ bdnz 1b
+
+ bl ._entry
+
+
+
+ .globl slaveLoopNoTakeover
+slaveLoopNoTakeover:
+ mr 28,3
+
+ li 14,0
+ oris 14, 14, slaveQuitt@h
+ ori 14, 14, slaveQuitt@l
+
+ li 3,0
+ std 3,0(14)
+1:
+ ld 3,0(14)
+ cmpld 3,28
+ bne 1b
+
+ li 3,0
+ std 3,0(14)
+
+ LOAD64(r3, (TAKEOVERBASEADDRESS+0x150))
+ mtctr r3
+ bctr
+
+
+ .globl slaveLoop
+slaveLoop:
+ mr 28,3
+ li r3, 0x5124
+ li r0, -1; .long 0x44000022
+
+ li 14,0
+ oris 14, 14, slaveQuitt@h
+ ori 14, 14, slaveQuitt@l
+ li 3,0
+ std 3,0(14)
+1:
+ ld 3,0(14)
+ cmpld 3,28
+ bne 1b
+
+ li 3,0
+ std 3,0(14)
+
+ LOAD64(r3, (TAKEOVERBASEADDRESS+0x150))
+ mtctr r3
+ bctr
+
diff --git a/clients/takeover/main.c b/clients/takeover/main.c
new file mode 100644
index 0000000..3568a1f
--- /dev/null
+++ b/clients/takeover/main.c
@@ -0,0 +1,157 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <of.h>
+#include <pci.h>
+#include <cpu.h>
+#include <takeover.h>
+
+#define boot_rom_bin_start _binary_______boot_rom_bin_start
+#define boot_rom_bin_end _binary_______boot_rom_bin_end
+
+extern char boot_rom_bin_start;
+extern char boot_rom_bin_end;
+extern ihandle_t fd_array[32];
+
+size_t
+write(int fd, void *buf, size_t cnt)
+{
+ of_write((ihandle_t) fd_array[1], buf, cnt);
+ return 0;
+}
+
+void *
+sbrk(int incr)
+{
+ return (void *) -1;
+}
+
+void
+doWait(void)
+{
+ static const char *wheel = "|/-\\";
+ static int i = 0;
+ volatile int dly = 0xf0000;
+ while (dly--);
+ printf("\b%c", wheel[i++]);
+ i &= 0x3;
+}
+
+void
+quiesce(void)
+{
+ of_arg_t arg = {
+ p32cast "quiesce",
+ 0, 0,
+ };
+ call_client_interface(&arg);
+}
+
+int
+startCpu(int num, int addr, int reg)
+{
+ of_arg_t arg = {
+ p32cast "start-cpu",
+ 3, 0,
+ {num, addr, reg}
+ };
+ call_client_interface(&arg);
+ return arg.args[3];
+}
+
+volatile unsigned long slaveQuitt;
+int takeoverFlag;
+
+int
+main(int argc, char *argv[])
+{
+ phandle_t cpus;
+ phandle_t cpu;
+ unsigned long slaveMask;
+ extern int slaveLoop[];
+ extern int slaveLoopNoTakeover[];
+ char devtype[100];
+ int rcode;
+ int index = 0;
+ int delay = 100;
+ unsigned long reg;
+ unsigned long msr;
+ asm volatile ("mfmsr %0":"=r" (msr));
+ if (msr & 0x1000000000000000)
+ takeoverFlag = 0;
+ else
+ takeoverFlag = 1;
+
+ cpus = of_finddevice("/cpus");
+ cpu = of_child(cpus);
+ slaveMask = 0;
+ while (cpu) {
+ char devType[100];
+ *devType = '\0';
+ of_getprop(cpu, "device_type", devType, sizeof(devType));
+ if (strcmp(devType, "cpu") == 0) {
+ of_getprop(cpu, "reg", &reg, sizeof(reg));
+ if (index) {
+ printf("\r\n takeover on cpu%d (%x, %x) ", index,
+ cpu, reg);
+ slaveQuitt = -1;
+ if (takeoverFlag)
+ startCpu(cpu, (int) slaveLoop, index);
+ else
+ startCpu(cpu, (int) slaveLoopNoTakeover,
+ index);
+ slaveMask |= 0x1 << index;
+ delay = 100;
+ while (delay-- && slaveQuitt)
+ doWait();
+ }
+ index++;
+ }
+ cpu = of_peer(cpu);
+ }
+
+
+ printf("\r\n takeover on master cpu ");
+ quiesce();
+
+ delay = 5;
+ while (delay--)
+ doWait();
+ if (takeoverFlag)
+ rcode = takeover();
+
+ memcpy((void*)TAKEOVERBASEADDRESS, &boot_rom_bin_start, &boot_rom_bin_end - &boot_rom_bin_start);
+ flush_cache((void *)TAKEOVERBASEADDRESS, &boot_rom_bin_end - &boot_rom_bin_start);
+ index = 0;
+
+ while (slaveMask) {
+ unsigned long shifter = 0x1 << index;
+ if (shifter & slaveMask) {
+ slaveQuitt = index;
+ while (slaveQuitt);
+ slaveMask &= ~shifter;
+ }
+ index++;
+ }
+
+ asm volatile(" mtctr %0 ; bctr " : : "r" (TAKEOVERBASEADDRESS+0x180) );
+}
+
+int
+callback(int argc, char *argv[])
+{
+ /* Dummy, only for takeover */
+ return (0);
+}
diff --git a/clients/takeover/ppc32wrap.S b/clients/takeover/ppc32wrap.S
new file mode 100644
index 0000000..ff96095
--- /dev/null
+++ b/clients/takeover/ppc32wrap.S
@@ -0,0 +1,30 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+ .globl _start
+ .section ".text"
+ .align 3
+
+_start:
+ nop
+ bl over
+ .llong 0x9000000000003000
+over:
+ li 14, 0
+ oris 14, 14, _binary_takeover_tmp_start@h
+ ori 14, 14, _binary_takeover_tmp_start@l
+ mtsrr0 14
+ mflr 15
+ ld 14,0(15)
+ mtsrr1 14
+ rfid
+
diff --git a/clients/takeover/takeover.h b/clients/takeover/takeover.h
new file mode 100644
index 0000000..f5201ef
--- /dev/null
+++ b/clients/takeover/takeover.h
@@ -0,0 +1,23 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 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
+ *****************************************************************************/
+
+#if defined(CPU_CBEA)
+#define TAKEOVERBASEADDRESS 0x0e000000
+#elif defined(CPU_PPC970)
+#define TAKEOVERBASEADDRESS 0x00000000
+#else
+#error no processor specified
+#endif
+
+#ifndef __ASSEMBLER__
+int takeover();
+#endif