aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clients/net-snk/app/netapps/netboot.c155
-rw-r--r--clients/net-snk/app/netlib/Makefile2
-rw-r--r--clients/net-snk/app/netlib/dhcpv6.c211
-rw-r--r--clients/net-snk/app/netlib/dhcpv6.h158
-rw-r--r--clients/net-snk/app/netlib/ethernet.c6
-rw-r--r--clients/net-snk/app/netlib/icmpv6.c379
-rw-r--r--clients/net-snk/app/netlib/icmpv6.h134
-rw-r--r--clients/net-snk/app/netlib/ipv6.c756
-rw-r--r--clients/net-snk/app/netlib/ipv6.h196
-rw-r--r--clients/net-snk/app/netlib/ndp.c147
-rw-r--r--clients/net-snk/app/netlib/ndp.h70
-rw-r--r--clients/net-snk/app/netlib/tftp.c18
-rw-r--r--clients/net-snk/app/netlib/tftp.h8
-rw-r--r--clients/net-snk/app/netlib/udp.c4
14 files changed, 2191 insertions, 53 deletions
diff --git a/clients/net-snk/app/netapps/netboot.c b/clients/net-snk/app/netapps/netboot.c
index 952bb33..7bef542 100644
--- a/clients/net-snk/app/netapps/netboot.c
+++ b/clients/net-snk/app/netapps/netboot.c
@@ -13,9 +13,9 @@
#include <netlib/tftp.h>
#include <netlib/ethernet.h>
#include <netlib/dhcp.h>
-//#include <netlib/dhcpv6.h>
+#include <netlib/dhcpv6.h>
#include <netlib/ipv4.h>
-//#include <netlib/ipv6.h>
+#include <netlib/ipv6.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
@@ -41,11 +41,11 @@ typedef struct {
char filename[100];
int ip_init;
char siaddr[4];
- //ip6_addr_t si6addr;
+ ip6_addr_t si6addr;
char ciaddr[4];
- //ip6_addr_t ci6addr;
+ ip6_addr_t ci6addr;
char giaddr[4];
- //ip6_addr_t gi6addr;
+ ip6_addr_t gi6addr;
int bootp_retries;
int tftp_retries;
} obp_tftp_args_t;
@@ -60,7 +60,6 @@ typedef struct {
* @param obp_tftp_args structure which contains the result
* @return updated arg_str
*/
-/*
static const char *
parse_ipv6args (const char *arg_str, unsigned int argc,
obp_tftp_args_t *obp_tftp_args)
@@ -73,7 +72,7 @@ parse_ipv6args (const char *arg_str, unsigned int argc,
memset(&obp_tftp_args->si6addr.addr, 0, 16);
else {
argncpy(arg_str, 0, arg_buf, 100);
- if(parseip6(arg_buf, (uint8_t *) &(obp_tftp_args->si6addr.addr[0]))) {
+ if(str_to_ipv6(arg_buf, (uint8_t *) &(obp_tftp_args->si6addr.addr[0]))) {
arg_str = get_arg_ptr(arg_str, 1);
--argc;
}
@@ -104,7 +103,7 @@ parse_ipv6args (const char *arg_str, unsigned int argc,
memset(&obp_tftp_args->ci6addr, 0, 16);
else {
argncpy(arg_str, 0, arg_buf, 100);
- if (parseip6(arg_buf, (uint8_t *) &(obp_tftp_args->ci6addr.addr)) ) {
+ if (str_to_ipv6(arg_buf, (uint8_t *) &(obp_tftp_args->ci6addr.addr[0]))) {
arg_str = get_arg_ptr(arg_str, 1);
--argc;
}
@@ -122,7 +121,7 @@ parse_ipv6args (const char *arg_str, unsigned int argc,
memset(&obp_tftp_args->gi6addr, 0, 16);
else {
argncpy(arg_str, 0, arg_buf, 100);
- if (parseip6(arg_buf, (uint8_t *) &(obp_tftp_args->gi6addr.addr)) ) {
+ if (str_to_ipv6(arg_buf, (uint8_t *) &(obp_tftp_args->gi6addr.addr)) ) {
arg_str = get_arg_ptr(arg_str, 1);
--argc;
}
@@ -137,7 +136,6 @@ parse_ipv6args (const char *arg_str, unsigned int argc,
return arg_str;
}
-*/
/**
@@ -272,11 +270,9 @@ parse_args(const char *arg_str, obp_tftp_args_t *obp_tftp_args)
if (ip_version == 4) {
arg_str = parse_ipv4args (arg_str, argc, obp_tftp_args);
}
-/*
else if (ip_version == 6) {
arg_str = parse_ipv6args (arg_str, argc, obp_tftp_args);
}
-*/
// find out bootp-retries
if (argc == 0)
@@ -324,12 +320,10 @@ netboot(int argc, char *argv[])
tftp_err_t tftp_err;
obp_tftp_args_t obp_tftp_args;
char null_ip[4] = { 0x00, 0x00, 0x00, 0x00 };
-/*
char null_ip6[16] = { 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };
-*/
int huge_load = strtol(argv[4], 0, 10);
int32_t block_size = strtol(argv[5], 0, 10);
uint8_t own_mac[6];
@@ -411,21 +405,20 @@ netboot(int argc, char *argv[])
obp_tftp_args.ip_init = IP_INIT_NONE;
}
}
-/*
else if (ip_version == 6) {
if (memcmp(&obp_tftp_args.ci6addr, null_ip6, 16) != 0
&& memcmp(&obp_tftp_args.si6addr, null_ip6, 16) != 0
&& obp_tftp_args.filename[0] != 0) {
- memcpy(&fn_ip.server_ip6.addr[0],
+ memcpy(&fn_ip.server_ip6.addr[0],
&obp_tftp_args.si6addr.addr, 16);
obp_tftp_args.ip_init = IP_INIT_IPV6_MANUAL;
- }
+ }
else {
obp_tftp_args.ip_init = IP_INIT_DHCPV6_STATELESS;
}
}
-*/
+
// construction of fn_ip from parameter
switch(obp_tftp_args.ip_init) {
case IP_INIT_BOOTP:
@@ -447,15 +440,14 @@ netboot(int argc, char *argv[])
printf(" Requesting IP address via DHCP: ");
rc = dhcp(ret_buffer, &fn_ip, obp_tftp_args.bootp_retries);
break;
-/*
case IP_INIT_DHCPV6_STATELESS:
set_ipv6_address(0);
rc = do_dhcpv6 (ret_buffer, &fn_ip, 10, DHCPV6_STATELESS);
+ memcpy(&fn_ip.own_ip6, get_ipv6_address(), 16);
break;
case IP_INIT_IPV6_MANUAL:
set_ipv6_address(&obp_tftp_args.ci6addr);
break;
-*/
case IP_INIT_NONE:
default:
break;
@@ -473,7 +465,6 @@ netboot(int argc, char *argv[])
// init IPv4 layer
set_ipv4_address(fn_ip.own_ip);
}
-/*
else if (rc >= 0 && ip_version == 6) {
if(memcmp(&obp_tftp_args.ci6addr.addr, null_ip6, 16) != 0
&& memcmp(&obp_tftp_args.ci6addr.addr, &fn_ip.own_ip6, 16) != 0)
@@ -483,7 +474,6 @@ netboot(int argc, char *argv[])
&& memcmp(&obp_tftp_args.si6addr.addr, &fn_ip.server_ip6.addr, 16) != 0)
memcpy(&fn_ip.server_ip6.addr, &obp_tftp_args.si6addr.addr, 16);
}
-*/
if (rc == -1) {
strcpy(buf,"E3001: (net) Could not get IP address");
bootmsg_error(0x3001, &buf[7]);
@@ -492,9 +482,10 @@ netboot(int argc, char *argv[])
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(ip_version == 4)
+ 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,
@@ -529,12 +520,19 @@ netboot(int argc, char *argv[])
fn_ip.filename[sizeof(fn_ip.filename)-1] = 0;
}
- printf(" Requesting file \"%s\" via TFTP from %d.%d.%d.%d\n",
- fn_ip.filename,
- ((fn_ip.server_ip >> 24) & 0xFF),
- ((fn_ip.server_ip >> 16) & 0xFF),
- ((fn_ip.server_ip >> 8) & 0xFF),
- ( fn_ip.server_ip & 0xFF));
+ if (ip_version == 4) {
+ printf(" Requesting file \"%s\" via TFTP from %d.%d.%d.%d\n",
+ fn_ip.filename,
+ ((fn_ip.server_ip >> 24) & 0xFF),
+ ((fn_ip.server_ip >> 16) & 0xFF),
+ ((fn_ip.server_ip >> 8) & 0xFF),
+ ( fn_ip.server_ip & 0xFF));
+ } else if (ip_version == 6) {
+ char ip6_str[40];
+ printf(" Requesting file \"%s\" via TFTP from ", fn_ip.filename);
+ ipv6_to_str(fn_ip.server_ip6.addr, ip6_str);
+ printf("%s\n", ip6_str);
+ }
// accept at most 20 bad packets
// wait at most for 40 packets
@@ -661,3 +659,98 @@ netboot(int argc, char *argv[])
}
return rc;
}
+
+/**
+ * Parses a tftp arguments, extracts all
+ * parameters and fills server ip according to this
+ *
+ * Parameters:
+ * @param buffer string with arguments,
+ * @param server_ip server ip as result
+ * @param filename default filename
+ * @param len len of the buffer,
+ * @return 0 on SUCCESS and -1 on failure
+ */
+int parse_tftp_args(char buffer[], char *server_ip, char filename[], int len)
+{
+ char *raw;
+ char *tmp, *tmp1;
+ int i, j = 0;
+
+ raw = malloc(len);
+ if (raw == NULL) {
+ printf("\n unable to allocate memory, parsing failed\n");
+ return -1;
+ }
+ strncpy(raw,(const char *)buffer,len);
+ /*tftp url contains tftp://[fd00:4f53:4444:90:214:5eff:fed9:b200]/testfile*/
+ if(strncmp(raw,"tftp://",7)){
+ printf("\n tftp missing in %s\n",raw);
+ free(raw);
+ return -1;
+ }
+ tmp = strchr(raw,'[');
+ if(tmp != NULL && *tmp == '[') {
+ /*check for valid ipv6 address*/
+ tmp1 = strchr(tmp,']');
+ if (tmp1 == NULL) {
+ printf("\n missing ] in %s\n",raw);
+ free(raw);
+ return -1;
+ }
+ i = tmp1 - tmp;
+ /*look for file name*/
+ tmp1 = strchr(tmp,'/');
+ if (tmp1 == NULL) {
+ printf("\n missing filename in %s\n",raw);
+ free(raw);
+ return -1;
+ }
+ tmp[i] = '\0';
+ /*check for 16 byte ipv6 address */
+ if (!str_to_ipv6((tmp+1), (uint8_t *)(server_ip))) {
+ printf("\n wrong format IPV6 address in %s\n",raw);
+ free(raw);
+ return -1;;
+ }
+ else {
+ /*found filename */
+ strcpy(filename,(tmp1+1));
+ free(raw);
+ return 0;
+ }
+ }
+ else {
+ /*here tftp://hostname/testfile from option request of dhcp*/
+ /*look for dns server name */
+ tmp1 = strchr(raw,'.');
+ if(tmp1 == NULL && *tmp1 != '.') {
+ printf("\n missing . seperator in %s\n",raw);
+ free(raw);
+ return -1;
+ }
+ /*look for domain name beyond dns server name
+ * so ignore the current . and look for one more
+ */
+ tmp = strchr((tmp1+1),'.');
+ if(tmp == NULL) {
+ printf("\n missing domain in %s\n",raw);
+ free(raw);
+ return -1;
+ }
+ tmp1 = strchr(tmp1,'/');
+ if (tmp1 == NULL) {
+ printf("\n missing filename in %s\n",raw);
+ free(raw);
+ return -1;
+ }
+ j = tmp1 - (raw + 7);
+ tmp = raw + 7;
+ tmp[j] = '\0';
+ strcpy(server_ip,tmp);
+ strcpy(filename,(tmp1+1));
+ free(raw);
+ return 0;
+ }
+
+}
diff --git a/clients/net-snk/app/netlib/Makefile b/clients/net-snk/app/netlib/Makefile
index 5b91470..df09bf8 100644
--- a/clients/net-snk/app/netlib/Makefile
+++ b/clients/net-snk/app/netlib/Makefile
@@ -23,7 +23,7 @@ CFLAGS += -DUSE_MTFTP
endif
OBJS = ethernet.o ipv4.o udp.o tcp.o dns.o bootp.o \
- dhcp.o
+ dhcp.o ipv6.o dhcpv6.o icmpv6.o ndp.o
ifeq ($(SNK_USE_MTFTP), 1)
OBJS += mtftp.o
diff --git a/clients/net-snk/app/netlib/dhcpv6.c b/clients/net-snk/app/netlib/dhcpv6.c
new file mode 100644
index 0000000..2b571c1
--- /dev/null
+++ b/clients/net-snk/app/netlib/dhcpv6.c
@@ -0,0 +1,211 @@
+/******************************************************************************
+ * Copyright (c) 2013 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <netlib/ethernet.h>
+#include <netlib/ipv6.h>
+#include <netlib/udp.h>
+#include <netlib/dhcpv6.h>
+#include <netlib/tftp.h>
+
+static uint8_t tid[3];
+static uint32_t dhcpv6_state = -1;
+static filename_ip_t *my_fn_ip;
+
+static void
+generate_transaction_id(void)
+{
+ /* TODO: as per RFC 3315 transaction IDs should be generated randomly */
+ tid[0] = 1;
+ tid[1] = 2;
+ tid[2] = 4;
+}
+
+static void
+send_info_request(void)
+{
+ uint8_t ether_packet[ETH_MTU_SIZE];
+ uint32_t payload_length;
+ struct dhcp_message_header *dhcph;
+
+ memset(ether_packet, 0, ETH_MTU_SIZE);
+
+ generate_transaction_id();
+
+ /* Get an IPv6 packet */
+ payload_length = sizeof(struct udphdr) + sizeof(struct dhcp_message_header);
+ fill_ip6hdr (ether_packet + sizeof(struct ethhdr),
+ payload_length, IPTYPE_UDP,
+ get_ipv6_address(), &(all_dhcpv6_ll.addr));
+ fill_udphdr ( ether_packet + sizeof(struct ethhdr) + sizeof(struct ip6hdr),
+ payload_length, DHCP_CLIENT_PORT, DHCP_SERVER_PORT);
+ dhcph = (struct dhcp_message_header *) (ether_packet +
+ sizeof(struct ethhdr) +
+ sizeof(struct ip6hdr) +
+ sizeof(struct udphdr));
+
+ /* Fill in DHCPv6 data */
+ dhcph->type = DHCP_INFORMATION_REQUEST;
+ memcpy( &(dhcph->transaction_id), &tid, 3);
+ dhcph->option.client_id.code = DHCPV6_OPTION_CLIENTID;
+ dhcph->option.client_id.length = 10;
+ dhcph->option.client_id.duid_type = DUID_LL;
+ dhcph->option.client_id.hardware_type = 1;
+ memcpy( &(dhcph->option.client_id.mac),
+ get_mac_address(), 6);
+ dhcph->option.el_time.code = DHCPV6_OPTION_ELAPSED_TIME;
+ dhcph->option.el_time.length = 2;
+ dhcph->option.el_time.time = 0x190; /* 4000 ms */
+ dhcph->option.option_request_option.code = DHCPV6_OPTION_ORO;
+ dhcph->option.option_request_option.length= 6;
+ dhcph->option.option_request_option.option_code[0] = DHCPV6_OPTION_DNS_SERVERS;
+ dhcph->option.option_request_option.option_code[1] = DHCPV6_OPTION_DOMAIN_LIST;
+ dhcph->option.option_request_option.option_code[2] = DHCPV6_OPTION_BOOT_URL;
+
+
+ send_ipv6( ether_packet + sizeof(struct ethhdr),
+ sizeof(struct ethhdr)+ sizeof(struct ip6hdr)
+ + sizeof(struct udphdr)
+ + sizeof( struct dhcp_message_header) );
+
+ return;
+
+}
+
+static int32_t
+dhcpv6_attempt(void)
+{
+ int sec;
+
+ // Send information request
+ send_info_request();
+
+ dhcpv6_state = DHCPV6_STATE_SELECT;
+
+ // setting up a timer with a timeout of two seconds
+ for (sec = 0; sec < 4; sec++) {
+ set_timer(TICKS_SEC);
+ do {
+ receive_ether();
+
+ // Wait until client will switch to Final state or Timeout occurs
+ switch (dhcpv6_state) {
+ case DHCP_STATUSCODE_SUCCESS:
+ return 1;
+ case DHCP_STATUSCODE_UNSPECFAIL: //FIXME
+ return 0;
+ }
+ } while (get_timer() > 0);
+ }
+
+ // timeout
+ return 0;
+}
+
+int32_t
+do_dhcpv6 ( char *ret_buffer, void *fn_ip,
+ unsigned int retries, uint8_t mode)
+{
+ my_fn_ip = (filename_ip_t *) fn_ip;
+ if( !dhcpv6_attempt()) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static struct dhcp6_received_options *
+dhcp6_process_options (uint8_t *option, int32_t option_length)
+{
+ struct dhcp_boot_url *option_boot_url;
+ struct client_identifier *option_clientid;
+ struct server_identifier *option_serverid;
+ struct dhcp_dns *option_dns;
+ struct dhcp_dns_list *option_dns_list;
+ struct dhcp6_received_options *received_options;
+ char buffer[256];
+
+
+ received_options = (struct dhcp6_received_options *) malloc (sizeof(struct dhcp6_received_options));
+ while (option_length > 0) {
+ switch ((uint16_t) *(option+1)) {
+ case DHCPV6_OPTION_CLIENTID:
+ option_clientid = (struct client_identifier *) option;
+ option = option + option_clientid->length + 4;
+ option_length = option_length - option_clientid->length - 4;
+ received_options->client_id = 1;
+ break;
+ case DHCPV6_OPTION_SERVERID:
+ option_serverid = (struct server_identifier *) option;
+ option = option + option_serverid->length + 4;
+ option_length = option_length - option_serverid->length - 4;
+ received_options->server_id = 1;
+ break;
+ case DHCPV6_OPTION_DNS_SERVERS:
+ option_dns = (struct dhcp_dns *) option;
+ option = option + option_dns->length + 4;
+ option_length = option_length - option_dns->length - 4;
+ memcpy( &(my_fn_ip->dns_ip6),
+ &(option_dns->p_ip6),
+ IPV6_ADDR_LENGTH);
+ break;
+ case DHCPV6_OPTION_DOMAIN_LIST:
+ option_dns_list = (struct dhcp_dns_list *) option;
+ option = option + option_dns_list->length + 4;
+ option_length = option_length - option_dns_list->length - 4;
+ break;
+ case DHCPV6_OPTION_BOOT_URL:
+ option_boot_url = (struct dhcp_boot_url *) option;
+ option = option + option_boot_url->length + 4;
+ option_length = option_length - option_boot_url->length - 4;
+ strncpy((char *)buffer,
+ (const char *)option_boot_url->url,
+ (size_t)option_boot_url->length);
+ buffer[option_boot_url->length] = 0;
+ if (parse_tftp_args(buffer,
+ (char *)my_fn_ip->server_ip6.addr,
+ (char *)my_fn_ip->filename,
+ option_boot_url->length) == -1)
+ return NULL;
+ break;
+
+ default:
+ return received_options;
+ }
+ }
+
+ return received_options;
+}
+
+uint32_t
+handle_dhcpv6(uint8_t * packet, int32_t packetsize)
+{
+
+ uint8_t *first_option;
+ int32_t option_length;
+ struct dhcp_message_reply *reply;
+ reply = (struct dhcp_message_reply *) packet;
+
+ if (reply->type == 7)
+ dhcpv6_state = DHCP_STATUSCODE_SUCCESS;
+
+ first_option = packet + 4;
+ option_length = packet + packetsize - first_option;
+ dhcp6_process_options(first_option, option_length);
+
+ return 0;
+}
diff --git a/clients/net-snk/app/netlib/dhcpv6.h b/clients/net-snk/app/netlib/dhcpv6.h
new file mode 100644
index 0000000..22a72ba
--- /dev/null
+++ b/clients/net-snk/app/netlib/dhcpv6.h
@@ -0,0 +1,158 @@
+/******************************************************************************
+ * Copyright (c) 2013 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 _DHCPV6_H_
+#define _DHCPV6_H_
+
+#include <stdint.h>
+#include <netlib/ethernet.h>
+
+#define DHCPV6_STATELESS 0
+#define DHCPV6_STATEFUL 1
+
+/* DHCP port numbers */
+#define DHCP_CLIENT_PORT 546
+#define DHCP_SERVER_PORT 547
+
+/* DHCPv6 message types */
+#define DHCP_SOLICIT 1
+#define DHCP_ADVERTISE 2
+#define DHCP_REQUEST 3
+#define DHCP_CONFIRM 4
+#define DHCP_RENEW 5
+#define DHCP_REBIND 6
+#define DHCP_REPLY 7
+#define DHCP_RELEASE 8
+#define DHCP_DECLINE 9
+#define DHCP_RECONFIGURE 10
+#define DHCP_INFORMATION_REQUEST 11
+#define RELAY_FORW 12
+#define RELAY_REPL 13
+
+/* DHCPv6 option types */
+#define DHCPV6_OPTION_CLIENTID 0x0001
+#define DHCPV6_OPTION_SERVERID 0x0002
+#define DHCPV6_OPTION_IA_NA 3
+#define DHCPV6_OPTION_IA_TA 4
+#define DHCPV6_OPTION_IAADDR 5
+#define DHCPV6_OPTION_ORO 6
+#define DHCPV6_OPTION_PREFEREN 7
+#define DHCPV6_OPTION_ELAPSED_TIME 8
+#define DHCPV6_OPTION_RELAY_MS 9
+#define DHCPV6_OPTION_AUTH 11
+#define DHCPV6_OPTION_UNICAST 12
+#define DHCPV6_OPTION_STATUS_C 13
+#define DHCPV6_OPTION_RAPID_CO 14
+#define DHCPV6_OPTION_USER_CLA 15
+#define DHCPV6_OPTION_VENDOR_C 16
+#define DHCPV6_OPTION_VENDOR_O 17
+#define DHCPV6_OPTION_INTERFAC 18
+#define DHCPV6_OPTION_RECONF_M 19
+#define DHCPV6_OPTION_RECONF_A 20
+#define DHCPV6_OPTION_DNS_SERVERS 23
+#define DHCPV6_OPTION_DOMAIN_LIST 24
+#define DHCPV6_OPTION_BOOT_URL 59
+
+/* DHCPv6 status codes */
+#define DHCP_STATUSCODE_SUCCESS 0
+#define DHCP_STATUSCODE_UNSPECFAIL 1
+#define DHCP_STATUSCODE_NOADDRAVAIL 2
+#define DHCP_STATUSCODE_NOBINDING 3
+#define DHCP_STATUSCODE_NOTONLINK 4
+#define DHCP_STATUSCODE_USEMULTICAST 5
+#define DHCPV6_STATE_SELECT 6
+
+/* DUID types */
+#define DUID_LLT 1 /* DUID based on Link-layer Address Plus Time */
+#define DUID_EN 2 /* DUID based on Assigned by Vendor Based on Enterprise Number */
+#define DUID_LL 3 /* DUID based on Link-layer Address */
+
+/* Prototypes */
+int32_t do_dhcpv6 ( char *ret_buffer, void *fn_ip,
+ unsigned int retries, uint8_t mode);
+uint32_t handle_dhcpv6(uint8_t * , int32_t);
+
+struct dhcp6_option_tftpserver {
+ uint16_t code;
+ uint16_t length;
+};
+
+struct client_identifier {
+ uint16_t code;
+ uint16_t length;
+ uint16_t duid_type;
+ uint16_t hardware_type;
+ uint8_t mac[6];
+};
+
+struct server_identifier {
+ uint16_t code;
+ uint16_t length;
+ uint16_t duid_type;
+ uint16_t hardware_type;
+ uint32_t time;
+ uint8_t mac[6];
+};
+
+struct dhcp_info_request {
+ struct client_identifier client_id;
+ struct elapsed_time {
+ uint16_t code;
+ uint16_t length;
+ uint16_t time;
+ } el_time;
+ struct option_request {
+ uint16_t code;
+ uint16_t length;
+ uint16_t option_code[5];
+ } option_request_option;
+};
+
+struct dhcp_message_header {
+ uint8_t type; /* Message type */
+ uint8_t transaction_id[3]; /* Transaction id */
+ struct dhcp_info_request option;
+};
+
+struct dhcp_dns {
+ uint16_t code;
+ uint16_t length;
+ uint8_t p_ip6[16];
+ uint8_t s_ip6[16];
+}__attribute((packed));
+
+struct dhcp_dns_list {
+ uint16_t code;
+ uint16_t length;
+ uint8_t domain[256];
+}__attribute((packed));
+
+struct dhcp_boot_url {
+ uint16_t type;
+ uint16_t length;
+ uint8_t url[256];
+};
+
+struct dhcp6_received_options {
+ uint8_t filename;
+ uint8_t ip;
+ uint8_t client_id;
+ uint8_t server_id;
+};
+struct dhcp_message_reply {
+ uint8_t type; /* Message type */
+ uint8_t transaction_id[3]; /* Transaction id */
+ struct client_identifier client_id;
+ struct server_identifier server_id;
+};
+
+#endif
diff --git a/clients/net-snk/app/netlib/ethernet.c b/clients/net-snk/app/netlib/ethernet.c
index cc77457..c52583c 100644
--- a/clients/net-snk/app/netlib/ethernet.c
+++ b/clients/net-snk/app/netlib/ethernet.c
@@ -47,7 +47,7 @@
#include <string.h>
#include <sys/socket.h>
#include <ipv4.h>
-//#include <ipv6.h>
+#include <ipv6.h>
/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> LOCAL VARIABLES <<<<<<<<<<<<<<<<<<<<<<<<<*/
@@ -132,11 +132,11 @@ receive_ether(void) {
case ETHERTYPE_IP:
return handle_ipv4((uint8_t*) (ethh + 1),
bytes_received - sizeof(struct ethhdr));
-/*
+
case ETHERTYPE_IPv6:
return handle_ipv6(ether_packet + sizeof(struct ethhdr),
bytes_received - sizeof(struct ethhdr));
-*/
+
case ETHERTYPE_ARP:
return handle_arp((uint8_t*) (ethh + 1),
bytes_received - sizeof(struct ethhdr));
diff --git a/clients/net-snk/app/netlib/icmpv6.c b/clients/net-snk/app/netlib/icmpv6.c
new file mode 100644
index 0000000..80f1dc6
--- /dev/null
+++ b/clients/net-snk/app/netlib/icmpv6.c
@@ -0,0 +1,379 @@
+/******************************************************************************
+ * Copyright (c) 2013 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 <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netlib/ethernet.h>
+#include <netlib/ipv6.h>
+#include <netlib/icmpv6.h>
+#include <netlib/ndp.h>
+#include <netlib/dhcpv6.h>
+
+/**
+ * NET:
+ *
+ */
+void
+send_router_solicitation ()
+{
+ ip6_addr_t dest_addr;
+ uint8_t ether_packet[ETH_MTU_SIZE];
+ struct packeth headers;
+
+ headers.ip6h = (struct ip6hdr *) (ether_packet + sizeof(struct ethhdr));
+ headers.icmp6h = (struct icmp6hdr *) (ether_packet +
+ sizeof(struct ethhdr) +
+ sizeof(struct ip6hdr));
+
+ /* Destination is "All routers multicast address" (link-local) */
+ dest_addr.part.prefix = all_routers_ll.addr.part.prefix;
+ dest_addr.part.interface_id = all_routers_ll.addr.part.interface_id;
+
+
+ /* Fill IPv6 header */
+ fill_ip6hdr (ether_packet + sizeof(struct ethhdr),
+ ICMPv6_HEADER_SIZE + sizeof(struct router_solicitation),
+ 0x3a, //ICMPV6
+ get_ipv6_address(), &dest_addr);
+
+ /* Fill ICMPv6 message */
+ headers.icmp6h->type = ICMPV6_ROUTER_SOLICITATION;
+ headers.icmp6h->code = 0;
+ headers.icmp6h->icmp6body.router_solicit.lladdr.type = 1;
+ headers.icmp6h->icmp6body.router_solicit.lladdr.length = 1;
+ memcpy( &(headers.icmp6h->icmp6body.router_solicit.lladdr.mac),
+ get_mac_address(), 6);
+
+ send_ip (headers.ip6h, sizeof(struct ip6hdr) +
+ ICMPv6_HEADER_SIZE + sizeof(struct router_solicitation));
+}
+
+/**
+ * NET: Process prefix option in Router Advertisements
+ *
+ * @param ip6_packet pointer to an IPv6 packet
+ */
+static void
+handle_prefixoption (uint8_t *option)
+{
+ ip6_addr_t prefix;
+ struct ip6addr_list_entry *new_address;
+ struct option_prefix *prefix_option;
+ struct prefix_info *prfx_info;
+
+ prefix_option = (struct option_prefix *) option;
+ memcpy( &(prefix.addr), &(prefix_option->prefix.addr), IPV6_ADDR_LENGTH);
+
+ /* Link-local adresses in RAs are nonsense */
+ if ( (IPV6_LL_PREFIX & (prefix_option->prefix.part.prefix)) == IPV6_LL_PREFIX )
+ return;
+
+ if (prefix_option->preferred_lifetime > prefix_option->valid_lifetime)
+ return;
+
+ /* Add address created from prefix to IPv6 address list */
+ new_address = ip6_prefix2addr (prefix);
+ if (!new_address)
+ return;
+
+ /* Process only prefixes we don't already have an adress from */
+ if (!unknown_prefix (&new_address->addr)) {
+ return;
+ }
+
+ /* Fill struct prefix_info from data in RA and store it in new_address */
+ prfx_info = ip6_create_prefix_info();
+ if (!prfx_info)
+ return;
+ memcpy (&(new_address->prfx_info), prfx_info, sizeof(struct prefix_info));
+
+ /* Add prefix received in RA to list of known prefixes */
+ ip6addr_add (new_address);
+}
+
+/**
+ * NET: Process source link layer addresses in Router Advertisements
+ *
+ * @param ip6_packet pointer to an IPv6 packet
+ */
+static void
+handle_source_lladdr ( struct option_ll_address *option, struct router *rtr)
+{
+ memcpy (&(rtr->mac), &(option->mac), 6);
+}
+
+/**
+ * NET: Process ICMPv6 options in Router Advertisements
+ *
+ * @param ip6_packet pointer to an IPv6 packet
+ */
+static void
+process_ra_options (uint8_t *option, int32_t option_length, struct router *r)
+{
+ while (option_length > 0) {
+ switch (*option) {
+ case ND_OPTION_SOURCE_LL_ADDR:
+ handle_source_lladdr ((struct option_ll_address *) option, r);
+ //option+1 is the length field. length is in units of 8 bytes
+ option = option + (*(option+1) * 8);
+ option_length = option_length - (*(option+1) * 8);
+ break;
+ case ND_OPTION_PREFIX_INFO:
+ handle_prefixoption(option);
+ option = option + (*(option+1) * 8);
+ option_length = option_length - (*(option+1) * 8);
+ break;
+ }
+ }
+
+ return;
+}
+
+/**
+ * NET: Process Router Advertisements
+ *
+ * @param ip6_packet pointer to an IPv6 packet
+ */
+static void
+handle_ra (struct icmp6hdr *icmp6h, uint8_t *ip6_packet)
+{
+ uint8_t *first_option;
+ int32_t option_length;
+ struct ip6hdr *ip6h;
+ struct router_advertisement *ra;
+ struct router *rtr;
+ ip6_addr_t *rtr_ip;
+ uint8_t rtr_mac[] = {0, 0, 0, 0, 0, 0};
+
+ ip6h = (struct ip6hdr *) ip6_packet;
+ ra = (struct router_advertisement *) &icmp6h->icmp6body.ra;
+ rtr_ip = (ip6_addr_t *) &ip6h->src;
+
+ rtr = find_router (&(ip6h->src));
+ if (!rtr) {
+ rtr = router_create (rtr_mac, rtr_ip);
+ router_add (rtr);
+ }
+
+ /* store info from router advertisement in router struct */
+ rtr->lifetime = ra->router_lifetime;
+ rtr->reachable_time = ra->reachable_time;
+ rtr->retrans_timer = ra->retrans_timer;
+
+ /* save flags concerning address (auto-) configuration */
+ ip6_state.managed_mode = ra->flags.managed;
+ ip6_state.other_config = ra->flags.other;
+
+ /* Process ICMPv6 options in Router Advertisement */
+ first_option = (uint8_t *) icmp6h + ICMPv6_HEADER_SIZE + 12;
+ option_length = (uint8_t *) icmp6h + ip6h->pl - first_option;
+ process_ra_options( (uint8_t *) first_option, option_length, rtr);
+
+}
+
+/**
+ * NET:
+ *
+ * @param ip6_addr_t *dest_ip6
+ */
+void
+send_neighbour_solicitation (ip6_addr_t *dest_ip6)
+{
+ ip6_addr_t snma;
+
+ uint8_t ether_packet[ETH_MTU_SIZE];
+ struct packeth headers;
+
+ memset(ether_packet, 0, ETH_MTU_SIZE);
+ headers.ethh = (struct ethhdr *) ether_packet;
+ headers.ip6h = (struct ip6hdr *) (ether_packet + sizeof(struct ethhdr));
+ headers.icmp6h = (struct icmp6hdr *) (ether_packet +
+ sizeof(struct ethhdr) +
+ sizeof(struct ip6hdr));
+
+ /* Fill IPv6 header */
+ snma.part.prefix = IPV6_SOLIC_NODE_PREFIX;
+ snma.part.interface_id = IPV6_SOLIC_NODE_IFACE_ID;
+ snma.addr[13] = dest_ip6->addr[13];
+ snma.addr[14] = dest_ip6->addr[14];
+ snma.addr[15] = dest_ip6->addr[15];
+ fill_ip6hdr((uint8_t *) headers.ip6h,
+ ICMPv6_HEADER_SIZE +
+ sizeof(struct neighbour_solicitation),
+ 0x3a, //ICMPv6
+ get_ipv6_address(), &snma);
+
+ /* Fill ICMPv6 message */
+ headers.icmp6h->type = ICMPV6_NEIGHBOUR_SOLICITATION;
+ headers.icmp6h->code = 0;
+ memcpy( &(headers.icmp6h->icmp6body.nghb_solicit.target),
+ dest_ip6, IPV6_ADDR_LENGTH );
+ headers.icmp6h->icmp6body.nghb_solicit.lladdr.type = 1;
+ headers.icmp6h->icmp6body.nghb_solicit.lladdr.length = 1;
+ memcpy( &(headers.icmp6h->icmp6body.nghb_solicit.lladdr.mac),
+ get_mac_address(), 6);
+
+ send_ip (ether_packet + sizeof(struct ethhdr),
+ sizeof(struct ip6hdr) + ICMPv6_HEADER_SIZE +
+ sizeof(struct neighbour_solicitation));
+}
+
+/**
+ * NET:
+ *
+ * @param ip6_packet pointer to an IPv6 packet
+ * @param icmp6hdr pointer to the icmp6 header in ip6_packet
+ * @param na_flags Neighbour advertisment flags
+ */
+static void
+send_neighbour_advertisement (struct neighbor *target)
+{
+ struct na_flags na_adv_flags;
+ uint8_t ether_packet[ETH_MTU_SIZE];
+ struct packeth headers;
+
+
+ headers.ip6h = (struct ip6hdr *) (ether_packet + sizeof(struct ethhdr));
+ headers.icmp6h = (struct icmp6hdr *) (ether_packet +
+ sizeof(struct ethhdr) +
+ sizeof(struct ip6hdr));
+
+ /* Fill IPv6 header */
+ fill_ip6hdr(ether_packet + sizeof(struct ethhdr),
+ ICMPv6_HEADER_SIZE +
+ sizeof(struct neighbour_advertisement),
+ 0x3a, //ICMPv6
+ get_ipv6_address(), (ip6_addr_t *) &(target->ip.addr));
+
+ /* Fill ICMPv6 message */
+ memcpy( &(headers.icmp6h->icmp6body.nghb_adv.target),
+ &(target->ip.addr), IPV6_ADDR_LENGTH );
+ headers.icmp6h->icmp6body.nghb_adv.lladdr.type = 1;
+ headers.icmp6h->icmp6body.nghb_adv.lladdr.length = 1;
+ memcpy( &(headers.icmp6h->icmp6body.nghb_adv.lladdr.mac),
+ get_mac_address(), 6);
+
+ na_adv_flags.is_router = 0;
+ na_adv_flags.na_is_solicited = 1;
+ na_adv_flags.override = 1;
+
+ headers.icmp6h->type = ICMPV6_NEIGHBOUR_ADVERTISEMENT;
+ headers.icmp6h->code = 0;
+ headers.icmp6h->icmp6body.nghb_adv.router = na_adv_flags.is_router;
+
+ headers.icmp6h->icmp6body.nghb_adv.solicited = na_adv_flags.na_is_solicited;
+ headers.icmp6h->icmp6body.nghb_adv.override = na_adv_flags.override;
+ headers.icmp6h->icmp6body.nghb_adv.lladdr.type = 2;
+ headers.icmp6h->icmp6body.nghb_adv.lladdr.length = 1;
+
+ memset( &(headers.icmp6h->icmp6body.nghb_adv.target), 0,
+ IPV6_ADDR_LENGTH );
+
+ if( na_adv_flags.na_is_solicited ) {
+ memcpy( &(headers.icmp6h->icmp6body.nghb_adv.target),
+ get_ipv6_address(), IPV6_ADDR_LENGTH);
+ }
+
+ memcpy( &(headers.icmp6h->icmp6body.nghb_adv.lladdr.mac),
+ get_mac_address(), 6);
+
+ send_ip (ether_packet + sizeof(struct ethhdr),
+ sizeof(struct ip6hdr) + ICMPv6_HEADER_SIZE +
+ sizeof(struct neighbour_advertisement));
+}
+
+/**
+ * NET:
+ *
+ * @param ip6_packet pointer to an IPv6 packet
+ */
+static int8_t
+handle_na (uint8_t *packet)
+{
+ struct neighbor *n = NULL;
+ struct packeth headers;
+ ip6_addr_t ip;
+
+ headers.ethh = (struct ethhdr *) packet;
+ headers.ip6h = (struct ip6hdr *) ((unsigned char *) headers.ethh +
+ sizeof(struct ethhdr));
+ headers.icmp6h = (struct icmp6hdr *) (packet +
+ sizeof(struct ethhdr) +
+ sizeof(struct ip6hdr));
+
+ memcpy(&(ip.addr), &(headers.ip6h->src), IPV6_ADDR_LENGTH);
+
+ n = find_neighbor (&ip);
+
+ if (!n) {
+ n= (struct neighbor *)
+ neighbor_create( packet, &headers );
+ if (!n)
+ return 0;
+ if (!neighbor_add(n))
+ return 0;
+ } else {
+ memcpy (&(n->mac), &(headers.ethh->src_mac[0]), 6);
+
+ if (n->eth_len > 0) {
+ struct ethhdr * ethh = (struct ethhdr *) &(n->eth_frame);
+ memcpy(ethh->dest_mac, &(n->mac), 6);
+ send_ether (&(n->eth_frame), n->eth_len + sizeof(struct ethhdr));
+ n->eth_len = 0;
+ }
+ }
+
+ return 1;
+}
+
+/**
+ * NET: Handles ICMPv6 messages
+ *
+ * @param ip6_packet pointer to an IPv6 packet
+ * @param packetsize size of ipv6_packet
+ */
+int8_t
+handle_icmpv6 (struct ethhdr *etherhdr,
+ uint8_t *ip6_packet)
+{
+
+ struct icmp6hdr *received_icmp6 = NULL;
+ struct ip6hdr *received_ip6 = NULL;
+ struct neighbor target;
+
+ received_ip6 = (struct ip6hdr *) ip6_packet;
+ received_icmp6 = (struct icmp6hdr *) (ip6_packet +
+ sizeof(struct ip6hdr));
+ memcpy( &(target.ip.addr), &(received_ip6->src),
+ IPV6_ADDR_LENGTH );
+ memcpy( &(target.mac), etherhdr->src_mac, 6);
+
+ /* process ICMPv6 types */
+ switch(received_icmp6->type) {
+ case ICMPV6_NEIGHBOUR_SOLICITATION:
+ send_neighbour_advertisement( &target );
+ break;
+ case ICMPV6_NEIGHBOUR_ADVERTISEMENT:
+ handle_na((uint8_t *) ip6_packet - sizeof(struct ethhdr));
+ break;
+ case ICMPV6_ROUTER_ADVERTISEMENT:
+ handle_ra(received_icmp6, (uint8_t *) received_ip6);
+ break;
+ default:
+ return -1;
+ }
+
+ return 1;
+}
diff --git a/clients/net-snk/app/netlib/icmpv6.h b/clients/net-snk/app/netlib/icmpv6.h
new file mode 100644
index 0000000..f080047
--- /dev/null
+++ b/clients/net-snk/app/netlib/icmpv6.h
@@ -0,0 +1,134 @@
+/******************************************************************************
+ * Copyright (c) 2013 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 _ICMPV6_H_
+#define _ICMPV6_H_
+
+#include <stdint.h>
+#include <netlib/ethernet.h>
+#include <netlib/ipv6.h>
+
+#define __ICMPV6_DEBUG__
+
+#ifdef __ICMPV6_DEBUG__
+#define ICMPV6_DEBUG_PRINT(format, ...) printf(format, ## __VA_ARGS__)
+#else
+#define ICMPV6_DEBUG_PRINT(format, ...)
+#endif
+
+#define ICMPv6_HEADER_SIZE 4 /* Size of common fields */
+#define IPTYPE_ICMPV6 0x3a
+
+/* Error message types */
+#define ICMPV6_DEST_UNREACHABLE 1 /* Destination unreachable */
+#define ICMPV6_PACKET_TOO_BIG 2 /* Packet too big */
+#define ICMPV6_TIME_EXCEEDED 3 /* Time exceeded */
+#define ICMPV6_PARAM_PROBLEM 4 /* Parameter problem */
+
+/* Informational message types */
+#define ICMPV6_ECHO_REQUEST 128 /* Echo request */
+#define ICMPV6_ECHO_REPLY 129 /* Echo reply */
+#define ICMPV6_MCAST_LISTENER_QUERY 130 /* Multicast listener query */
+#define ICMPV6_MCAST_LISTENER_REPORT 131 /* Multicast listener report */
+#define ICMPv6 MCAST_LISTENER_DONE 132 /* Multicast listener done */
+#define ICMPV6_ROUTER_SOLICITATION 133 /* Router solicitation */
+#define ICMPV6_ROUTER_ADVERTISEMENT 134 /* Router advertisement */
+#define ICMPV6_NEIGHBOUR_SOLICITATION 135 /* Neighbor solicitation */
+#define ICMPV6_NEIGHBOUR_ADVERTISEMENT 136 /* Neighbor advertisement */
+#define ICMPV6_REDIRECT_MSG 137 /* Redirect message */
+
+/******** Functions *******************/
+int8_t handle_icmpv6 (struct ethhdr *etherhdr, uint8_t *ip6_packet);
+void send_neighbour_solicitation( ip6_addr_t *target_ip6);
+void send_router_solicitation(void);
+
+/* Prefix information */
+struct option_prefix {
+ uint8_t type;
+ uint8_t length;
+ uint8_t prefix_length;
+ uint8_t onlink:1,
+ autom:1,
+ not_router:1,
+ not_site_prefix:1,
+ reserved:4;
+ uint32_t valid_lifetime;
+ uint32_t preferred_lifetime;
+ uint32_t reserved2;
+ ip6_addr_t prefix;
+} __attribute((packed));
+
+/* Neighbour advertisement/solicitation flags */
+struct na_flags {
+ uint8_t is_router:1, /* sender (we) is a router */
+ na_is_solicited:1, /* this NA was solicited (asked for) */
+ override:1, /* receiver shall override its cache entries */
+ unused:5;
+}__attribute((packed));
+
+/* Source/Target Link-layer address */
+struct option_ll_address{
+ uint8_t type;
+ uint8_t length;
+ uint8_t mac[ETH_ALEN];
+} __attribute((packed));
+
+struct neighbour_solicitation {
+ uint32_t router:1,
+ solicited:1,
+ override:1,
+ reserved:29;
+ ip6_addr_t target;
+ struct option_ll_address lladdr;
+} __attribute((packed));
+
+struct neighbour_advertisement {
+ uint32_t router:1,
+ solicited:1,
+ override:1,
+ reserved:29;
+ ip6_addr_t target;
+ struct option_ll_address lladdr;
+} __attribute((packed));
+
+struct router_solicitation {
+ uint32_t reserved;
+ struct option_ll_address lladdr;
+} __attribute((packed));
+
+struct router_advertisement {
+ uint8_t curr_hop_limit;
+ struct raflags {
+ uint8_t managed:1,
+ other:1,
+ reserved:6;
+ } flags;
+ uint16_t router_lifetime;
+ uint32_t reachable_time;
+ uint32_t retrans_timer;
+ struct option_prefix prefix;
+ struct option_ll_address ll_addr;
+} __attribute((packed));
+
+struct icmp6hdr {
+ uint8_t type;
+ uint8_t code;
+ uint16_t checksum;
+ union {
+ struct neighbour_solicitation nghb_solicit;
+ struct neighbour_advertisement nghb_adv;
+ struct router_solicitation router_solicit;
+ struct router_advertisement ra;
+ } icmp6body;
+} __attribute((packed));
+
+#endif
diff --git a/clients/net-snk/app/netlib/ipv6.c b/clients/net-snk/app/netlib/ipv6.c
new file mode 100644
index 0000000..46b8110
--- /dev/null
+++ b/clients/net-snk/app/netlib/ipv6.c
@@ -0,0 +1,756 @@
+/******************************************************************************
+ * Copyright (c) 2013 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 <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <ctype.h>
+#include <sys/socket.h>
+#include <netlib/ethernet.h>
+#include <netlib/ipv6.h>
+#include <netlib/icmpv6.h>
+#include <netlib/ndp.h>
+#include <netlib/udp.h>
+
+#undef IPV6_DEBUG
+//#define IPV6_DEBUG
+#ifdef IPV6_DEBUG
+#define dprintf(_x ...) do { printf(_x); } while (0)
+#else
+#define dprintf(_x ...)
+#endif
+
+/****************************** PROTOTYPES *******************************/
+int8_t ip6addr_add (struct ip6addr_list_entry *new_address);
+static void ipv6_init(void);
+static int ip6_is_multicast (ip6_addr_t * ip);
+
+/****************************** LOCAL VARIABLES **************************/
+
+/* Own IPv6 address */
+static struct ip6addr_list_entry *own_ip6;
+
+/* Null IPv6 address */
+static ip6_addr_t null_ip6;
+
+/* helper variables */
+static uint8_t null_mac[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+
+/****************************** IMPLEMENTATION ***************************/
+
+/**
+ * IPv6: Set the own IPv6 address.
+ *
+ * @param _own_ip client IPv6 address (e.g. ::1)
+ */
+void
+set_ipv6_address (ip6_addr_t *_own_ip6)
+{
+
+ own_ip6 = malloc (sizeof(struct ip6addr_list_entry));
+
+ /* If no address was passed as a parameter generate a link-local
+ * address from our MAC address.*/
+ if (_own_ip6 == NULL)
+ memcpy(&(own_ip6->addr.addr),
+ ip6_create_ll_address(get_mac_address()),
+ IPV6_ADDR_LENGTH);
+ else
+ memcpy (&(own_ip6->addr.addr), _own_ip6, 16);
+
+ /* Add to our list of IPv6 addresses */
+ ip6addr_add (own_ip6);
+
+ ipv6_init();
+}
+
+/**
+ * IPv6: Get pointer to own IPv6 address.
+ *
+ * @return pointer to client IPv6 address (e.g. ::1)
+ */
+ip6_addr_t *
+get_ipv6_address (void)
+{
+ return (ip6_addr_t *) &(own_ip6->addr);
+}
+
+/**
+ * IPv6: Search for IPv6 address in list
+ *
+ * @return 0 - IPv6 address is not in list
+ * 1 - IPv6 address is in list
+ */
+static int8_t
+find_ip6addr (ip6_addr_t *ip)
+{
+ struct ip6addr_list_entry *n = NULL;
+
+ if (ip == NULL)
+ return 0;
+
+ for (n = first_ip6; n != NULL ; n=n->next)
+ if (ip6_cmp (&(n->addr), ip))
+ return 1; /* IPv6 address is in our list*/
+
+ return 0; /* not one of our IPv6 addresses*/
+}
+
+/**
+ * NET: Handles IPv6-packets
+ *
+ * @param ip6_packet - Pointer to IPv6 header
+ * @param packetsize - Size of Ipv6 packet
+ * @return ERROR - -1 if packet is too small or unknown protocol
+ * return value of handle_udp
+ *
+ * @see handle_udp
+ * @see ip6hdr
+ */
+int8_t
+handle_ipv6 (uint8_t * ip6_packet, int32_t packetsize)
+{
+
+ struct ip6hdr *ip6 = NULL;
+ ip6 = (struct ip6hdr *) ip6_packet;
+
+ /* Only handle packets which are for us */
+ if (! find_ip6addr(&(ip6->dst)))
+ return -1;
+
+ if (packetsize < sizeof(struct ip6hdr))
+ return -1; // packet is too small
+
+ switch (ip6->nh) {
+ case IPTYPE_UDP:
+ return handle_udp (ip6_packet + sizeof (struct ip6hdr),
+ ip6->pl);
+ case IPTYPE_ICMPV6:
+ return handle_icmpv6 ((struct ethhdr *) ip6_packet - sizeof(struct ethhdr),
+ ip6_packet);
+ }
+
+ return -1; // unknown protocol
+}
+
+ /**
+ * NET: Creates IPv6-packet. Places IPv6-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 IPv6-header must be placed.
+ * @param packetsize Size of payload (i.e. excluding ethhdr and ip6hdr)
+ * @param ip_proto Type of the next level protocol (e.g. UDP).
+ * @param ip6_src Sender IPv6 address
+ * @param ip6_dst Receiver IPv6 address
+ * @see ip6hdr
+ * @see fill_iphdr
+ * @see fill_ethhdr
+ * @see fill_udphdr
+ * @see fill_dnshdr
+ * @see fill_btphdr
+ */
+void
+fill_ip6hdr (uint8_t * packet, uint16_t packetsize,
+ uint8_t ip_proto, ip6_addr_t *ip6_src, ip6_addr_t *ip6_dst)
+{
+
+ struct ip6hdr * ip6h = (struct ip6hdr *) packet;
+
+ ip6h->ver_tc_fl = 6 << 28; // set version to 6
+ ip6h->pl = packetsize; // IPv6 payload size
+ ip6h->nh = ip_proto;
+ ip6h->hl = 255;
+ memcpy (&(ip6h->src), ip6_src, IPV6_ADDR_LENGTH);
+ memcpy (&(ip6h->dst), ip6_dst, IPV6_ADDR_LENGTH);
+}
+
+/**
+ * NET: For a given MAC calculates EUI64-Identifier.
+ * See RFC 4291 "IP Version 6 Addressing Architecture"
+ *
+ */
+uint64_t
+mac2eui64 (const uint8_t *mac)
+{
+ uint8_t eui64id[8];
+ uint64_t retid;
+
+ memcpy (eui64id, mac, 3);
+ memcpy (eui64id + 5, mac + 3, 3);
+ eui64id[3] = 0xff;
+ eui64id[4] = 0xfe;
+
+ memcpy(&retid, eui64id, 8);
+ return retid;
+}
+
+/**
+ * NET: create link-local IPv6 address
+ *
+ * @param own_mac MAC of NIC
+ * @return ll_addr pointer to newly created link-local address
+ */
+ip6_addr_t *
+ip6_create_ll_address (const uint8_t *own_mac)
+{
+ ip6_addr_t *ll_addr;
+
+ ll_addr = malloc (sizeof (struct ip6addr_list_entry));
+ memset (ll_addr, 0, IPV6_ADDR_LENGTH);
+ ll_addr->part.prefix |= IPV6_LL_PREFIX;
+ ll_addr->part.interface_id |= mac2eui64((uint8_t *) own_mac);
+
+ return ll_addr;
+}
+
+/*
+ * NET: check if we already have an address with the same prefix.
+ * @param struct ip6_addr_list_entry *ip6
+ * @return true or false
+ */
+int8_t
+unknown_prefix (ip6_addr_t *ip)
+{
+ struct ip6addr_list_entry *node;
+
+ for( node = first_ip6; node != NULL; node=node->next )
+ if( node->addr.part.prefix == ip->part.prefix )
+ return 0; /* address is one of ours */
+
+ return 1; /* prefix not yet in our list */
+}
+
+/*
+ * NET: Create empty element for prefix list and return a pointer to it;
+ * @return NULL - malloc failed
+ * ! NULL - pointer to new prefix_info
+ */
+struct prefix_info *
+ip6_create_prefix_info ()
+{
+ struct prefix_info *prfx_info;
+
+ prfx_info = malloc (sizeof(struct prefix_info));
+ if (!prfx_info)
+ return NULL;
+
+ return prfx_info;
+}
+
+/*
+ * NET: create a new IPv6 address with a given network prefix
+ * and add it to our IPv6 address list
+ *
+ * @param ip6_addr prefix (as received in RA)
+ * @return NULL - pointer to new ip6addr_list entry
+ */
+void *
+ip6_prefix2addr (ip6_addr_t prefix)
+{
+ struct ip6addr_list_entry *new_address;
+ uint64_t interface_id;
+
+ new_address = malloc (sizeof(struct ip6addr_list_entry));
+ if( !new_address )
+ return NULL;
+
+ /* fill new addr struct */
+ /* extract prefix from Router Advertisement */
+ memcpy (&(new_address->addr.part.prefix), &prefix, 8 );
+
+ /* interface id is generated from MAC address */
+ interface_id = mac2eui64 (get_mac_address());
+ memcpy (&(new_address->addr.part.interface_id), &interface_id, 8);
+
+ return new_address;
+}
+
+/**
+ * NET: add new IPv6 adress to list
+ *
+ * @param ip6_addr *new_address
+ * @return 0 - passed pointer = NULL;
+ * 1 - ok
+ */
+int8_t
+ip6addr_add (struct ip6addr_list_entry *new_address)
+{
+ struct ip6addr_list_entry *solicited_node;
+
+
+ if (new_address == NULL)
+ return 0;
+
+ /* Don't add the same address twice */
+ if (find_ip6addr (&(new_address->addr)))
+ return 0;
+
+ /* If address is a unicast address, we also have to process packets
+ * for its solicited-node multicast address.
+ * See RFC 2373 - IP Version 6 Adressing Architecture */
+ if (! ip6_is_multicast(&(new_address->addr))) {
+
+
+ solicited_node = malloc(sizeof(struct ip6addr_list_entry));
+ if (! solicited_node)
+ return 0;
+
+ solicited_node->addr.part.prefix = IPV6_SOLIC_NODE_PREFIX;
+ solicited_node->addr.part.interface_id = IPV6_SOLIC_NODE_IFACE_ID;
+ solicited_node->addr.addr[13] = new_address->addr.addr[13];
+ solicited_node->addr.addr[14] = new_address->addr.addr[14];
+ solicited_node->addr.addr[15] = new_address->addr.addr[15];
+ ip6addr_add (solicited_node);
+ }
+
+ if (NULL == first_ip6)
+ first_ip6 = new_address;
+ last_ip6->next = new_address;
+ last_ip6 = new_address;
+ last_ip6->next = NULL;
+
+ return 1; /* no error */
+}
+
+/**
+ * NET: Initialize IPv6
+ *
+ */
+static void
+ipv6_init ()
+{
+ int i = 0;
+
+ send_ip = &send_ipv6;
+
+ /* Address configuration parameters */
+ ip6_state.managed_mode = 0;
+
+ /* Null IPv6 address */
+ null_ip6.part.prefix = 0;
+ null_ip6.part.interface_id = 0;
+
+ /* Multicast addresses */
+ all_nodes_ll.addr.part.prefix = 0xff02000000000000;
+ all_nodes_ll.addr.part.interface_id = 1;
+ all_dhcpv6_ll.addr.part.prefix = 0xff02000000000000ULL;
+ all_dhcpv6_ll.addr.part.interface_id = 0x10002ULL;
+ all_routers_ll.addr.part.prefix = 0xff02000000000000;
+ all_routers_ll.addr.part.interface_id = 2;
+
+ ip6addr_add(&all_nodes_ll);
+ /* ... */
+
+ /* Router list */
+ first_router = NULL;
+ last_router = first_router;
+
+ /* Init Neighbour cache */
+ first_neighbor = NULL;
+ last_neighbor = first_neighbor;
+
+ send_router_solicitation ();
+ for(i=0; i < 4; i++) {
+ set_timer(TICKS_SEC);
+ while (get_timer() > 0);
+ receive_ether();
+ }
+}
+
+/**
+ * NET: compare IPv6 adresses
+ *
+ * @param ip6_addr ip_1
+ * @param ip6_addr ip_2
+ */
+int8_t
+ip6_cmp (ip6_addr_t *ip_1, ip6_addr_t *ip_2)
+{
+ return ((int8_t) !memcmp( &(ip_1->addr[0]), &(ip_2->addr[0]),
+ IPV6_ADDR_LENGTH ));
+}
+
+/**
+ * NET: Calculate checksum over IPv6 header and upper-layer protocol
+ * (e.g. UDP or ICMPv6)
+ *
+ * @param *ip - pointer to IPv6 address
+ * @return true or false
+ */
+int
+ip6_is_multicast (ip6_addr_t * ip)
+{
+ uint8_t mc = 0xFF;
+ return ! memcmp(&ip->addr[0], &mc, 1);
+}
+
+/**
+ * NET: Generate multicast MAC address from IPv6 address
+ * (e.g. UDP or ICMPv6)
+ *
+ * @param *ip - pointer to IPv6 address
+ * @return pointer to Multicast MAC address
+ */
+static uint8_t *
+ip6_to_multicast_mac (ip6_addr_t * ip)
+{
+ uint8_t *mc_mac;
+
+ mc_mac = malloc(ETH_ALEN);
+ if (!mc_mac)
+ return NULL;
+
+ mc_mac[0] = 0x33;
+ mc_mac[1] = 0x33;
+ memcpy (mc_mac+2, (uint8_t *) &(ip->addr)+12, 4);
+
+ return mc_mac;
+}
+
+/**
+ * NET: calculate checksum over IPv6 header and upper-layer protocol
+ * (e.g. UDP or ICMPv6)
+ *
+ * @param struct ip6hdr *ip6h - pointer to IPv6 header
+ * @param unsigned short *packet - pointer to header of upper-layer
+ * protocol
+ * @param int words - number of words (as in 2 bytes)
+ * starting from *packet
+ * @return checksum
+ */
+static unsigned short
+ip6_checksum (struct ip6hdr *ip6h, unsigned short *packet, int words)
+{
+ int i=0;
+ unsigned long checksum;
+ struct ip6hdr pseudo_ip6h;
+ unsigned short *pip6h;
+
+ memcpy (&pseudo_ip6h, ip6h, sizeof(struct ip6hdr));
+ pseudo_ip6h.hl = ip6h->nh;
+ pseudo_ip6h.ver_tc_fl = 0;
+ pseudo_ip6h.nh = 0;
+ pip6h = (unsigned short *) &pseudo_ip6h;
+
+ for (checksum = 0; words > 0; words--) {
+ checksum += *packet++;
+ i++;
+ }
+
+ for (i = 0; i < 20; i++) {
+ checksum += *pip6h++;
+ }
+
+ checksum = (checksum >> 16) + (checksum & 0xffff);
+ checksum += (checksum >> 16);
+
+ return ~checksum;
+}
+
+/**
+ * NET: Handles IPv6-packets
+ *
+ * @param ip6_packet Pointer to IPv6 header in packet
+ * @param packetsize Size of IPv6 packet
+ * @return -1 == ERRROR
+ * return of handle_udp() or handle_icmp6()
+ *
+ * @see receive_ether
+ * @see ip6hdr
+ */
+int
+send_ipv6 (void* buffer, int len)
+{
+ struct neighbor *n;
+ struct ip6hdr *ip6h;
+ struct udphdr *udph;
+ struct icmp6hdr *icmp6h;
+ ip6_addr_t ip_dst;
+ uint8_t *mac_addr, mac[6];
+
+ mac_addr = mac;
+
+ ip6h = (struct ip6hdr *) buffer;
+ udph = (struct udphdr *) ((uint8_t *) ip6h + sizeof (struct ip6hdr));
+ icmp6h = (struct icmp6hdr *) ((uint8_t *) ip6h + sizeof (struct ip6hdr));
+
+ memcpy(&ip_dst, &ip6h->dst, 16);
+
+ if(len + sizeof(struct ethhdr) > 1500)
+ return -1;
+
+ if ( ip6_cmp (&ip6h->src, &null_ip6))
+ memcpy (&(ip6h->src), get_ipv6_address(), IPV6_ADDR_LENGTH);
+
+ if (ip6h->nh == 17) {//UDP
+ udph->uh_sum = ip6_checksum (ip6h, (unsigned short *) udph ,
+ ip6h->pl >> 1);
+ }
+ else if (ip6h->nh == 0x3a) //ICMPv6
+ icmp6h->checksum = ip6_checksum (ip6h,
+ (unsigned short *) icmp6h,
+ ip6h->pl >> 1);
+
+ n = find_neighbor (&ip_dst);
+
+ // If packet is a neighbor solicitation
+ if (icmp6h->type == ICMPV6_NEIGHBOUR_SOLICITATION) {
+ mac_addr = ip6_to_multicast_mac (&ip_dst);
+ fill_ethhdr( buffer-sizeof(struct ethhdr), htons(ETHERTYPE_IPv6),
+ get_mac_address(),
+ mac_addr);
+ }
+
+ // If address is a multicast address, create a proper mac address
+ else if (ip6_is_multicast (&ip_dst)) {
+ mac_addr = ip6_to_multicast_mac (&ip_dst);
+ }
+ else {
+ // Check if the MAC address is already cached
+ if (n) {
+ if (memcmp(n->mac, null_mac, ETH_ALEN) != 0)
+ memcpy (mac_addr, &(n->mac), ETH_ALEN); /* found it */
+ } else {
+ mac_addr = null_mac;
+ n = malloc(sizeof(struct neighbor));
+ memcpy(&(n->ip.addr[0]), &ip_dst, 16);
+ n->status = NB_PROBE;
+ n->times_asked += 1;
+ neighbor_add(n);
+ }
+
+ if (! memcmp (mac_addr, &null_mac, 6)) {
+ if (n->eth_len == 0) {
+ send_neighbour_solicitation (&ip_dst);
+
+ // Store the packet until we know the MAC address
+ memset(n->eth_frame, 0, 1500);
+ fill_ethhdr (n->eth_frame,
+ htons(ETHERTYPE_IPv6),
+ get_mac_address(),
+ mac_addr);
+ memcpy (&(n->eth_frame[sizeof(struct ethhdr)]),
+ buffer, len);
+ n->eth_len = len;
+ set_timer(TICKS_SEC);
+ do {
+ receive_ether();
+ } while (get_timer() > 0);
+ }
+ }
+ }
+
+ fill_ethhdr (n->eth_frame, htons(ETHERTYPE_IPv6), get_mac_address(),
+ mac_addr);
+ memcpy (&(n->eth_frame[sizeof(struct ethhdr)]), buffer, len);
+ return send_ether (n->eth_frame, len + sizeof(struct ethhdr));
+}
+
+static int
+check_colons(const char *str)
+{
+ char *pch, *prv;
+ int col = 0;
+ int dcol = 0;
+
+ dprintf("str : %s\n",str);
+ pch = strchr(str, ':');
+ while(pch != NULL){
+ prv = pch;
+ pch = strchr(pch+1, ':');
+ if((pch-prv) != 1) {
+ col++;
+ } else {
+ col--; /* Its part of double colon */
+ dcol++;
+ }
+ }
+
+ dprintf("The number of col : %d \n",col);
+ dprintf("The number of dcol : %d \n",dcol);
+
+ if((dcol > 1) || /* Cannot have 2 "::" */
+ ((dcol == 1) && (col > 5)) || /* Too many ':'s */
+ ((dcol == 0) && (col != 7)) ) { /* Too few ':'s */
+ dprintf(" exiting for check_colons \n");
+ return 0;
+ }
+
+ return (col+dcol);
+}
+
+static int
+ipv6str_to_bytes(const char *str, char *ip)
+{
+ char block[5];
+ int res;
+ char *pos;
+ uint32_t cnt = 0, len;
+
+ dprintf("str : %s \n",str);
+
+ while (*str != 0) {
+ if (cnt > 15 || !isxdigit(*str)){
+ return 0;
+ }
+ if ((pos = strchr(str, ':')) != NULL) {
+ len = (int16_t) (pos - str);
+ dprintf("\t len is : %d \n",len);
+ if (len > 4)
+ return 0;
+ strncpy(block, str, len);
+ block[len] = 0;
+ dprintf("\t str : %s \n",str);
+ dprintf("\t block : %s \n",block);
+ str += len;
+ } else {
+ strncpy(block, str, 4);
+ block[4] = 0;
+ dprintf("\t str : %s \n",str);
+ dprintf("\t block : %s \n",block);
+ str += strlen(block);
+ }
+ res = strtol(block, NULL, 16);
+ dprintf("\t res : %x \n",res);
+ if ((res > 0xFFFF) || (res < 0))
+ return 0;
+ ip[cnt++] = (res & 0xFF00) >> 8;
+ ip[cnt++] = (res & 0x00FF);
+ if (*str == ':'){
+ str++;
+ }
+ }
+
+ dprintf("cnt : %d\n",cnt);
+ return cnt;
+}
+
+int str_to_ipv6(const char *str, uint8_t *ip)
+{
+ int i, k;
+ uint16_t len;
+ char *ptr;
+ char tmp[30], buf[16];
+
+ memset(ip,0,16);
+
+ if(!check_colons(str))
+ return 0;
+
+ if ((ptr = strstr(str, "::")) != NULL) {
+ /* Handle the ::1 IPv6 loopback */
+ if(!strcmp(str,"::1")) {
+ ip[15] = 1;
+ return 16;
+ }
+ len = (ptr-str);
+ dprintf(" len : %d \n",len);
+ if (len >= sizeof(tmp))
+ return 0;
+ strncpy(tmp, str, len);
+ tmp[len] = 0;
+ ptr += 2;
+
+ i = ipv6str_to_bytes(ptr, buf);
+ if(i == 0)
+ return i;
+
+ #if defined(ARGS_DEBUG)
+ int j;
+ dprintf("=========== bottom part i : %d \n",i);
+ for(j=0; j<i; j++)
+ dprintf("%02x \t",buf[j]);
+ #endif
+
+ /* Copy the bottom part i.e bytes following "::" */
+ memcpy(ip+(16-i), buf, i);
+
+ k = ipv6str_to_bytes(tmp, buf);
+ if(k == 0)
+ return k;
+
+ #if defined(ARGS_DEBUG)
+ dprintf("=========== top part k : %d \n",k);
+ for(j=0; j<k; j++)
+ printf("%02x \t",buf[j]);
+ #endif
+
+ /* Copy the top part i.e bytes before "::" */
+ memcpy(ip, buf, k);
+ #if defined(ARGS_DEBUG)
+ dprintf("\n");
+ for(j=0; j<16; j++)
+ dprintf("%02x \t",ip[j]);
+ #endif
+
+ } else {
+ i = ipv6str_to_bytes(str, (char *)ip);
+ }
+ return i;
+}
+
+void ipv6_to_str(const uint8_t *ip, char *str)
+{
+ int i, len;
+ uint8_t byte_even, byte_odd;
+ char *consec_zero, *strptr;
+
+ *str = 0;
+ for (i = 0; i < 16; i+=2) {
+ byte_even = ip[i];
+ byte_odd = ip[i+1];
+ if (byte_even)
+ sprintf(str, "%s%x%02x", str, byte_even, byte_odd);
+ else if (byte_odd)
+ sprintf(str, "%s%x", str, byte_odd);
+ else
+ strcat(str, "0");
+ if (i != 14)
+ strcat(str, ":");
+ }
+ strptr = str;
+ do {
+ consec_zero = strstr(strptr, "0:0:");
+ if (consec_zero) {
+ len = consec_zero - strptr;
+ if (!len)
+ break;
+ else if (strptr[len-1] == ':')
+ break;
+ else
+ strptr = consec_zero + 2;
+ }
+ } while (consec_zero);
+ if (consec_zero) {
+ len = consec_zero - str;
+ str[len] = 0;
+ if (len)
+ strcat(str, ":");
+ else
+ strcat(str, "::");
+ strptr = consec_zero + 4;
+ while (*strptr) {
+ if (!strncmp(strptr, "0:", 2))
+ strptr += 2;
+ else
+ break;
+ }
+ strcat(str, strptr);
+ if (!strcmp(str, "::0"))
+ strcpy(str, "::");
+ }
+}
diff --git a/clients/net-snk/app/netlib/ipv6.h b/clients/net-snk/app/netlib/ipv6.h
new file mode 100644
index 0000000..82f2cb0
--- /dev/null
+++ b/clients/net-snk/app/netlib/ipv6.h
@@ -0,0 +1,196 @@
+/******************************************************************************
+ * Copyright (c) 2013 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 _IPV6_H_
+#define _IPV6_H_
+
+#include <stdint.h>
+#include <netlib/ethernet.h>
+
+#define __IPV6_DEBUG__
+
+#ifdef __IPV6_DEBUG__
+#define IPV6_DEBUG_PRINT(format, ...) do { printf(format, ## __VA_ARGS__); } while (0)
+#else
+#define IPV6_DEBUG_PRINT(format, ...)
+#endif
+
+#define IPV6_ADDR_LENGTH 16 /* Size of IPv6 adress in bytes */
+#define IPV6_LL_PREFIX 0xFE80000000000000ULL
+#define IPV6_SOLIC_NODE_PREFIX 0xFF02000000000000ULL
+#define IPV6_SOLIC_NODE_IFACE_ID 0x00000001FF000000ULL
+
+/**
+ * An IPv6 Address
+ */
+typedef union {
+ uint8_t addr[IPV6_ADDR_LENGTH];
+ struct {
+ uint64_t prefix;
+ uint64_t interface_id;
+ } part;
+} ip6_addr_t;
+
+typedef struct {
+ uint8_t type;
+ uint8_t pad[7];
+ union {
+ ip6_addr_t v6;
+ char v4[4];
+ } addr;
+} netaddr_t;
+
+/** \struct prefix_info
+ *
+ * List of Prefixes we have adresses from
+ * Used for internal purposes, information derived from prefix option
+ * in Router Advertisements
+ * See RFC 4861 section 4.6.2
+ */
+struct prefix_info {
+ uint64_t prefix;
+ uint8_t on_link:1, /* When set prefix can be used for on-link
+ * determination */
+ autoconf:1, /* Prefix can be used for stateless address
+ * configuration */
+ reserved1:6;
+ uint32_t valid_lifetime; /* Time until prefix expires */
+ uint32_t preferred_lifetime; /* Time until prefix becomes deprecated */
+ uint32_t start_time; /* Time when received */
+ uint32_t reserved2;
+ struct prefix_info *next;
+};
+
+
+/* List of IPv6 addresses */
+struct ip6addr_list_entry {
+ ip6_addr_t addr;
+ struct prefix_info prfx_info;
+ struct ip6addr_list_entry *next;
+};
+
+/** \struct ip6hdr
+ * A header for IPv6 packets.
+ * For more information see RFC 2460
+ */
+struct ip6hdr {
+ uint32_t ver_tc_fl; /**< Version, Traffic class, Flow label */
+ uint16_t pl; /**< Payload length */
+ uint8_t nh; /**< Next header */
+ uint8_t hl; /**< Hop limit */
+ ip6_addr_t src; /**< IPv6 source address */
+ ip6_addr_t dst; /**< IPv6 destination address */
+} __attribute((packed));
+
+/** \struct packeth
+ * Struct with pointers to headers within a packet
+ */
+struct packeth {
+ struct ethhdr *ethh;
+ struct ip6hdr *ip6h;
+ struct icmp6hdr *icmp6h;
+ struct udphdr *udph;
+ /* ... */
+};
+
+/** \struct parseip6_state
+ * Stores information about state of IPv6 address parser
+ */
+struct parseip6_state {
+ char *lookahead;
+ char *ptr;
+ const char *addr;
+ int state;
+ int s1ctr;
+ int s2ctr;
+ int blocknr;
+ int zeroblocks;
+ int i;
+ int done;
+ int errorcode;
+};
+
+/** \struct ip6_config
+ * Stores flags wheter we use Stateless- or Stateful Autoconfiguration or DHCPv6
+ */
+struct ip6_config {
+ uint8_t managed_mode:1,
+ other_config:1,
+ reserved:6;
+} ip6_state;
+
+/******************** VARIABLES **********************************************/
+/* Function pointer send_ip. Points either to send_ipv4() or send_ipv6() */
+extern int (*send_ip) (void *, int);
+
+/* IPv6 link-local multicast addresses */
+struct ip6addr_list_entry all_routers_ll; // Routers
+struct ip6addr_list_entry all_dhcpv6_ll; // DHCPv6 servers
+struct ip6addr_list_entry all_nodes_ll; // All IPv6 nodes
+
+/* List of Ipv6 Addresses */
+struct ip6addr_list_entry *first_ip6;
+struct ip6addr_list_entry *last_ip6;
+
+/* Neighbor cache */
+struct neighbor *first_neighbor;
+struct neighbor *last_neighbor;
+
+/* Router list */
+struct router *first_router;
+struct router *last_router;
+
+/******************** FUNCTIONS *********************************************/
+/* Handles IPv6-packets that are detected by receive_ether. */
+int8_t handle_ipv6(uint8_t * ip6_packet, int32_t packetsize);
+
+/* Fill IPv6 header */
+void fill_ip6hdr(uint8_t * packet, uint16_t packetsize,
+ uint8_t ip_proto, ip6_addr_t *ip6_src, ip6_addr_t *ip6_dst);
+
+/* Set own IPv6 address */
+void set_ipv6_address(ip6_addr_t *own_ip6);
+
+/* Get own IPv6 address */
+ip6_addr_t *get_ipv6_address(void);
+
+/* Create link-local address from a given Mac Address */
+ip6_addr_t * ip6_create_ll_address (const uint8_t *own_mac);
+
+/* For a given MAC calculates EUI64-Identifier.*/
+uint64_t mac2eui64 (const uint8_t *mac);
+
+/* Create empty element for prefix list and return a pointer to it */
+struct prefix_info * ip6_create_prefix_info(void);
+
+/* Create a new IPv6 address with a given network prefix
+ * and add it to our IPv6 address list */
+void * ip6_prefix2addr (ip6_addr_t prefix);
+
+/* Compare IPv6 adresses */
+int8_t ip6_cmp( ip6_addr_t *ip_1, ip6_addr_t *ip_2 );
+
+/* Check if prefix is already in our list */
+int8_t unknown_prefix (ip6_addr_t *ip);
+
+/* Send IPv6 packet */
+int send_ipv6 (void* buffer, int len);
+
+/* Add IPv6 address to list */
+int8_t ip6addr_add (struct ip6addr_list_entry *new_address);
+
+/* Parse an IPv6 address */
+int parseip6(const char *addr, uint8_t *parsedaddr);
+int str_to_ipv6(const char *str, uint8_t *ip);
+void ipv6_to_str(const uint8_t *ip, char *str);
+
+#endif
diff --git a/clients/net-snk/app/netlib/ndp.c b/clients/net-snk/app/netlib/ndp.c
new file mode 100644
index 0000000..ed9d61f
--- /dev/null
+++ b/clients/net-snk/app/netlib/ndp.c
@@ -0,0 +1,147 @@
+/******************************************************************************
+ * Copyright (c) 2013 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>
+#include <stdio.h>
+#include <netlib/ipv6.h>
+#include <netlib/icmpv6.h>
+#include <netlib/ndp.h>
+
+/*
+ * NET: add new router to list
+ * @param struct router nghb - new router
+ * @return true or false
+ */
+int8_t
+router_add (struct router *nghb )
+{
+ if (nghb == NULL)
+ return -1;
+
+ if (first_router == NULL) {
+ first_router= nghb;
+ last_router = first_router;
+ last_router->next = NULL;
+ } else {
+ last_router->next = nghb;
+ last_router = nghb;
+ last_router->next = NULL;
+ }
+ return 1; /* no error */
+}
+
+/*
+ * NET: create a new router
+ * @param uint8_t *packet - received packet (Ethernet/IPv6/ICMPv6/ND_NghSlct)
+ * @param struct packeth - pointers to headers in packet
+ * @return pointer to new router
+ */
+void *
+router_create (uint8_t *mac, ip6_addr_t *ip)
+{
+ struct router *new_router;
+
+ new_router = malloc (sizeof(struct router));
+ if( !new_router) {
+ return 0;
+ }
+ memset (new_router, 0, sizeof(struct router));
+
+ /* fill neighbor struct */
+ memcpy (new_router->mac, mac, 6);
+ memcpy (&(new_router->ip.addr[0]), &(ip->addr[0]), IPV6_ADDR_LENGTH);
+
+ return new_router;
+}
+
+struct router *
+find_router( ip6_addr_t *ip )
+{
+ struct router *n = NULL;
+
+ for (n = first_router; n != NULL ; n=n->next)
+ if (ip6_cmp (&(n->ip), ip))
+ return n; /* router is already in list*/
+
+ return NULL; /* router is unknown */
+}
+
+/*
+ * NET: add new neighbor to list
+ * @param struct neighbor nghb - new neighbor
+ * @return true or false
+ */
+int8_t
+neighbor_add (struct neighbor *nghb)
+{
+ if (nghb == NULL)
+ return -1;
+
+ if (first_neighbor == NULL) {
+ first_neighbor = nghb;
+ last_neighbor = first_neighbor;
+ last_neighbor->next = NULL;
+ } else {
+ last_neighbor->next = nghb;
+ last_neighbor = nghb;
+ last_neighbor->next = NULL;
+ }
+
+ return 1; /* no error */
+}
+
+/*
+ * NET: create a new neighbor
+ * @param uint8_t *packet - received packet (Ethernet/IPv6/ICMPv6/ND_NghSlct)
+ * @param struct packeth - pointers to headers in packet
+ * @return pointer - pointer to new neighbor
+ * NULL - malloc failed
+ */
+void *
+neighbor_create (uint8_t *packet, struct packeth *headers)
+{
+ struct neighbor *new_neighbor;
+
+ new_neighbor = malloc (sizeof(struct neighbor));
+ if( !new_neighbor )
+ return NULL;
+
+ /* fill neighbor struct */
+ memcpy (&(new_neighbor->mac),
+ &(headers->ethh->src_mac[0]), 6);
+ memcpy (&(new_neighbor->ip.addr), &(headers->ip6h->src), IPV6_ADDR_LENGTH);
+ new_neighbor->status = NB_INCOMPLETE;
+
+ return new_neighbor;
+}
+
+/**
+ * NET: Find neighbor with given IPv6 address in Neighbor Cache
+ *
+ * @param ip - Pointer to IPv6 address
+ * @return pointer - pointer to client IPv6 address (e.g. ::1)
+ * NULL - Neighbor not found
+ */
+struct neighbor *
+find_neighbor (ip6_addr_t *ip)
+{
+ struct neighbor *n = NULL;
+
+ for (n = first_neighbor; n != NULL ; n=n->next) {
+ if (ip6_cmp (&(n->ip), ip)) {
+ return n; /* neighbor is already in cache */
+ }
+ }
+
+ return NULL; /* neighbor is unknown */
+}
diff --git a/clients/net-snk/app/netlib/ndp.h b/clients/net-snk/app/netlib/ndp.h
new file mode 100644
index 0000000..ee5235f
--- /dev/null
+++ b/clients/net-snk/app/netlib/ndp.h
@@ -0,0 +1,70 @@
+/******************************************************************************
+ * Copyright (c) 2013 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 _NDP_H_
+#define _NDP_H_
+
+#include <netlib/ipv6.h>
+
+#define __NDP_DEBUG__
+
+#ifdef __NDP_DEBUG__
+#define NDP_DEBUG_PRINT(format, ...) do { printf(format, ## __VA_ARGS__); } while (0)
+#else
+#define NDP_DEBUG_PRINT(format, ...)
+#endif
+
+#define ND_OPTION_SOURCE_LL_ADDR 1
+#define ND_OPTION_TARGET_LL_ADDR 2
+#define ND_OPTION_PREFIX_INFO 3
+#define ND_OPTION_REDIRECT_HDR 4
+#define ND_OPTION_MTU 5
+
+/* Default Router List */
+struct router {
+ uint8_t mac[6];
+ ip6_addr_t ip;
+ uint32_t lifetime;
+ uint32_t reachable_time;
+ uint32_t retrans_timer;
+ struct router *next;
+};
+
+/* Neighbor cache */
+struct neighbor {
+ uint8_t mac[6];
+ ip6_addr_t ip;
+ uint8_t is_router;
+ uint8_t status;
+ uint8_t times_asked;
+ /* ... */
+ struct neighbor *next;
+ uint8_t eth_frame[1500]; //FIXME
+ uint32_t eth_len;
+
+#define NB_INCOMPLETE 1
+#define NB_REACHABLE 2
+#define NB_STALE 3
+#define NB_DELAY 4
+#define NB_PROBE 5
+};
+
+/******************** FUNCTIONS *********************************************/
+int8_t neighbor_add (struct neighbor *);
+void * neighbor_create (uint8_t *packet, struct packeth *headers);
+struct neighbor * find_neighbor (ip6_addr_t *);
+
+int8_t router_add(struct router*);
+void * router_create(uint8_t *mac, ip6_addr_t *ip);
+struct router * find_router(ip6_addr_t *);
+
+#endif //_NDP_H_
diff --git a/clients/net-snk/app/netlib/tftp.c b/clients/net-snk/app/netlib/tftp.c
index bf94662..8a39a15 100644
--- a/clients/net-snk/app/netlib/tftp.c
+++ b/clients/net-snk/app/netlib/tftp.c
@@ -19,7 +19,7 @@
#include <ethernet.h>
#include <ipv4.h>
-//#include <ipv6.h>
+#include <ipv6.h>
#include <udp.h>
//#define __DEBUG__
@@ -91,12 +91,12 @@ static void
send_rrq(void)
{
int ip_len = 0;
- //int ip6_payload_len = 0;
+ int ip6_payload_len = 0;
unsigned short udp_len = 0;
unsigned char mode[] = "octet";
char *ptr = NULL;
struct iphdr *ip = NULL;
- //struct ip6hdr *ip6 = NULL;
+ struct ip6hdr *ip6 = NULL;
struct udphdr *udph = NULL;
struct tftphdr *tftp = NULL;
@@ -111,7 +111,6 @@ send_rrq(void)
fill_iphdr ((uint8_t *) ip, ip_len, IPTYPE_UDP, 0,
fn_ip->server_ip);
}
-/*
else if (6 == ip_version) {
ip6 = (struct ip6hdr *) packet;
udph = (struct udphdr *) (ip6 + 1);
@@ -123,7 +122,6 @@ send_rrq(void)
&(fn_ip->server_ip6));
}
-*/
udp_len = htons(sizeof(struct udphdr)
+ strlen((char *) fn_ip->filename) + strlen((char *) mode) + 4
+ strlen("blksize") + strlen(blocksize_str) + 2);
@@ -162,10 +160,10 @@ static void
send_ack(int blckno, unsigned short dport)
{
int ip_len = 0;
- //int ip6_payload_len = 0;
+ int ip6_payload_len = 0;
unsigned short udp_len = 0;
struct iphdr *ip = NULL;
- //struct ip6hdr *ip6 = NULL;
+ struct ip6hdr *ip6 = NULL;
struct udphdr *udph = NULL;
struct tftphdr *tftp = NULL;
@@ -178,7 +176,6 @@ send_ack(int blckno, unsigned short dport)
fill_iphdr ((uint8_t *) ip, ip_len, IPTYPE_UDP, 0,
fn_ip->server_ip);
}
-/*
else if (6 == ip_version) {
ip6 = (struct ip6hdr *) packet;
udph = (struct udphdr *) (ip6 + 1);
@@ -188,7 +185,6 @@ send_ack(int blckno, unsigned short dport)
fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(),
&(fn_ip->server_ip6));
}
-*/
udp_len = htons(sizeof(struct udphdr) + 4);
fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(dport));
@@ -215,7 +211,7 @@ static void
send_error(int error_code, unsigned short dport)
{
int ip_len = 0;
- //int ip6_payload_len = 0;
+ int ip6_payload_len = 0;
unsigned short udp_len = 0;
struct ip6hdr *ip6 = NULL;
struct iphdr *ip = NULL;
@@ -231,7 +227,6 @@ send_error(int error_code, unsigned short dport)
fill_iphdr ((uint8_t *) ip, ip_len, IPTYPE_UDP, 0,
fn_ip->server_ip);
}
-/*
else if (6 == ip_version) {
ip6 = (struct ip6hdr *) packet;
udph = (struct udphdr *) (ip6 + 1);
@@ -241,7 +236,6 @@ send_error(int error_code, unsigned short dport)
fill_ip6hdr ((uint8_t *) ip6, ip6_payload_len, IPTYPE_UDP, get_ipv6_address(),
&(fn_ip->server_ip6));
}
-*/
udp_len = htons(sizeof(struct udphdr) + 5);
fill_udphdr ((uint8_t *) udph, udp_len, htons(2001), htons(dport));
diff --git a/clients/net-snk/app/netlib/tftp.h b/clients/net-snk/app/netlib/tftp.h
index ebcabdf..a5ae948 100644
--- a/clients/net-snk/app/netlib/tftp.h
+++ b/clients/net-snk/app/netlib/tftp.h
@@ -15,7 +15,7 @@
#define _TFTP_H_
#include <stdint.h>
-//#include <netlib/ipv6.h>
+#include <netlib/ipv6.h>
struct tftphdr {
int16_t th_opcode;
@@ -24,9 +24,10 @@ struct tftphdr {
typedef struct {
uint32_t own_ip;
- //ip6_addr_t own_ip6;
+ ip6_addr_t own_ip6;
uint32_t server_ip;
- //ip6_addr_t server_ip6;
+ ip6_addr_t server_ip6;
+ ip6_addr_t dns_ip6;
int8_t filename[256];
} __attribute__ ((packed)) filename_ip_t ;
@@ -44,5 +45,6 @@ int tftp_netsave(filename_ip_t *, uint8_t * buffer, int len,
int32_t handle_tftp(uint8_t *, int32_t);
void handle_tftp_dun(uint8_t err_code);
+int parse_tftp_args(char buffer[], char *server_ip, char filename[], int len);
#endif
diff --git a/clients/net-snk/app/netlib/udp.c b/clients/net-snk/app/netlib/udp.c
index 3bc20ef..134a29e 100644
--- a/clients/net-snk/app/netlib/udp.c
+++ b/clients/net-snk/app/netlib/udp.c
@@ -15,7 +15,7 @@
#include <udp.h>
#include <sys/socket.h>
#include <dhcp.h>
-//#include <dhcpv6.h>
+#include <dhcpv6.h>
#include <dns.h>
#ifdef USE_MTFTP
#include <mtftp.h>
@@ -76,11 +76,9 @@ handle_udp(uint8_t * udp_packet, int32_t packetsize) {
packetsize - sizeof(struct udphdr));
else
return -1;
-/*
case UDPPORT_DHCPV6C:
return handle_dhcpv6(udp_packet+sizeof(struct udphdr),
packetsize - sizeof(struct udphdr));
-*/
case UDPPORT_TFTPC:
#ifdef USE_MTFTP
return handle_tftp(udp_packet + sizeof(struct udphdr),