From aee78336b9f4b06ab1b8aa2e093f4e7e67c9a515 Mon Sep 17 00:00:00 2001 From: Avik Sil Date: Sun, 17 Nov 2013 16:22:03 +0530 Subject: Add ipv6 support in net-snk This patch adds support for booting from a IPv6 network. It gets the boot information (tftp server, boot file name) from DHCPv6 server or can be specified manually using obp-tftp arguments. To boot from a IPv6 network, type "boot net:ipv6" from the SLOF prompt. To specify ipaddresses manually, type "boot net:ipv6,,," from the SLOF prompt. This patch is based on the IPv6 code written by the former SLOF team. Signed-off-by: Avik Sil --- clients/net-snk/app/netapps/netboot.c | 155 +++++-- clients/net-snk/app/netlib/Makefile | 2 +- clients/net-snk/app/netlib/dhcpv6.c | 211 ++++++++++ clients/net-snk/app/netlib/dhcpv6.h | 158 +++++++ clients/net-snk/app/netlib/ethernet.c | 6 +- clients/net-snk/app/netlib/icmpv6.c | 379 +++++++++++++++++ clients/net-snk/app/netlib/icmpv6.h | 134 ++++++ clients/net-snk/app/netlib/ipv6.c | 756 ++++++++++++++++++++++++++++++++++ clients/net-snk/app/netlib/ipv6.h | 196 +++++++++ clients/net-snk/app/netlib/ndp.c | 147 +++++++ clients/net-snk/app/netlib/ndp.h | 70 ++++ clients/net-snk/app/netlib/tftp.c | 18 +- clients/net-snk/app/netlib/tftp.h | 8 +- clients/net-snk/app/netlib/udp.c | 4 +- 14 files changed, 2191 insertions(+), 53 deletions(-) create mode 100644 clients/net-snk/app/netlib/dhcpv6.c create mode 100644 clients/net-snk/app/netlib/dhcpv6.h create mode 100644 clients/net-snk/app/netlib/icmpv6.c create mode 100644 clients/net-snk/app/netlib/icmpv6.h create mode 100644 clients/net-snk/app/netlib/ipv6.c create mode 100644 clients/net-snk/app/netlib/ipv6.h create mode 100644 clients/net-snk/app/netlib/ndp.c create mode 100644 clients/net-snk/app/netlib/ndp.h 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 #include #include -//#include +#include #include -//#include +#include #include #include #include @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 +#include + +#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 #include #include -//#include +#include /*>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * 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 +#include +#include + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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. + *

+ * 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 +#include + +#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 +#include +#include +#include +#include +#include + +/* + * 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 + +#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 #include -//#include +#include #include //#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 -//#include +#include 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 #include #include -//#include +#include #include #ifdef USE_MTFTP #include @@ -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), -- cgit v1.1