diff options
Diffstat (limited to 'clients/net-snk')
70 files changed, 8801 insertions, 0 deletions
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(ðer_packet[sizeof(struct ethhdr)], ARP_REQUEST, + arp_own_mac, arp_own_ip, dest_mac, dest_ip); + fill_ethhdr(ðer_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(ðer_packet[0], ETHERTYPE_ARP, arp_own_mac, src_mac); + fill_arphdr(ðer_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, ðh->src_mac, 6); + strcpy((char *) fn_ip->filename, (char *) btph->file); + +#if DEBUG + printf("\nThese are the details of the bootp reply:\n"); + printf("Our IP address: "); + print_ip(&fn_ip->own_ip); + 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 *) (ðer_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(ðer_packet[sizeof(struct ethhdr) + sizeof(struct iphdr)], + sizeof(struct btphdr) + sizeof(struct udphdr), + UDPPORT_BOOTPC, UDPPORT_BOOTPS); + fill_iphdr(ðer_packet[sizeof(struct ethhdr)], sizeof(struct btphdr) + + sizeof(struct udphdr) + sizeof(struct iphdr), + IPTYPE_UDP, dhcp_own_ip, 0xFFFFFFFF); + fill_ethhdr(ðer_packet[0], ETHERTYPE_IP, dhcp_own_mac, dest_mac); + + PRINT_SENDING(ether_packet, packetsize); + + send(dhcp_device_socket, ether_packet, packetsize, 0); +} + +/** + * 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 *) (ðer_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(ðer_packet[sizeof(struct ethhdr) + sizeof(struct iphdr)], + sizeof(struct btphdr) + sizeof(struct udphdr), + UDPPORT_BOOTPC, UDPPORT_BOOTPS); + fill_iphdr(ðer_packet[sizeof(struct ethhdr)], sizeof(struct btphdr) + + sizeof(struct udphdr) + sizeof(struct iphdr), + IPTYPE_UDP, 0, 0xFFFFFFFF); + fill_ethhdr(ðer_packet[0], ETHERTYPE_IP, dhcp_own_mac, dest_mac); + + PRINT_SENDING(ether_packet, packetsize); + + send(dhcp_device_socket, ether_packet, packetsize, 0); +} + + +/** + * 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 *) (ðer_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(ðer_packet[sizeof(struct ethhdr) + sizeof(struct iphdr)], + sizeof(struct btphdr) + sizeof(struct udphdr), + UDPPORT_BOOTPC, UDPPORT_BOOTPS); + fill_iphdr(ðer_packet[sizeof(struct ethhdr)], sizeof(struct btphdr) + + sizeof(struct udphdr) + sizeof(struct iphdr), IPTYPE_UDP, + dhcp_own_ip, dhcp_server_ip); + fill_ethhdr(ðer_packet[0], ETHERTYPE_IP, dhcp_own_mac, dhcp_server_mac); + + PRINT_SENDING(ether_packet, packetsize); + + send(dhcp_device_socket, ether_packet, packetsize, 0); +} + +/** + * 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(ðer_packet[sizeof(struct ethhdr) + + sizeof(struct iphdr) + sizeof(struct udphdr)], + domain_name); + fill_udphdr(ðer_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", ®, 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 = .; + } +} |