From c77bc6d3f133895a4a2899ba22fb1b3a32dffd8a Mon Sep 17 00:00:00 2001 From: Adam Dunkels Date: Sun, 14 Sep 2014 21:26:23 +0200 Subject: [PATCH 1/2] NAT64 / DNS64 code for Contiki that makes connecting an IPv6 Contiki network to IPv4 networks really easy --- core/net/ip64/ip64-addrmap.c | 249 ++++++++ core/net/ip64/ip64-addrmap.h | 101 ++++ core/net/ip64/ip64-arp.c | 417 +++++++++++++ core/net/ip64/ip64-arp.h | 84 +++ core/net/ip64/ip64-conf-example.h | 42 ++ core/net/ip64/ip64-dhcpc.c | 450 ++++++++++++++ core/net/ip64/ip64-dhcpc.h | 62 ++ core/net/ip64/ip64-driver.h | 40 ++ core/net/ip64/ip64-eth-interface.c | 125 ++++ core/net/ip64/ip64-eth-interface.h | 40 ++ core/net/ip64/ip64-eth.c | 43 ++ core/net/ip64/ip64-eth.h | 61 ++ core/net/ip64/ip64-interface.h | 41 ++ core/net/ip64/ip64-ipv4-dhcp.c | 95 +++ core/net/ip64/ip64-ipv4-dhcp.h | 36 ++ core/net/ip64/ip64-null-driver.c | 49 ++ core/net/ip64/ip64-null-driver.h | 38 ++ core/net/ip64/ip64-slip-interface.c | 150 +++++ core/net/ip64/ip64-slip-interface.h | 38 ++ core/net/ip64/ip64-special-ports.c | 76 +++ core/net/ip64/ip64-special-ports.h | 64 ++ core/net/ip64/ip64.c | 873 ++++++++++++++++++++++++++++ core/net/ip64/ip64.h | 76 +++ 23 files changed, 3250 insertions(+) create mode 100644 core/net/ip64/ip64-addrmap.c create mode 100644 core/net/ip64/ip64-addrmap.h create mode 100644 core/net/ip64/ip64-arp.c create mode 100644 core/net/ip64/ip64-arp.h create mode 100644 core/net/ip64/ip64-conf-example.h create mode 100644 core/net/ip64/ip64-dhcpc.c create mode 100644 core/net/ip64/ip64-dhcpc.h create mode 100644 core/net/ip64/ip64-driver.h create mode 100644 core/net/ip64/ip64-eth-interface.c create mode 100644 core/net/ip64/ip64-eth-interface.h create mode 100644 core/net/ip64/ip64-eth.c create mode 100644 core/net/ip64/ip64-eth.h create mode 100644 core/net/ip64/ip64-interface.h create mode 100644 core/net/ip64/ip64-ipv4-dhcp.c create mode 100644 core/net/ip64/ip64-ipv4-dhcp.h create mode 100644 core/net/ip64/ip64-null-driver.c create mode 100644 core/net/ip64/ip64-null-driver.h create mode 100644 core/net/ip64/ip64-slip-interface.c create mode 100644 core/net/ip64/ip64-slip-interface.h create mode 100644 core/net/ip64/ip64-special-ports.c create mode 100644 core/net/ip64/ip64-special-ports.h create mode 100644 core/net/ip64/ip64.c create mode 100644 core/net/ip64/ip64.h diff --git a/core/net/ip64/ip64-addrmap.c b/core/net/ip64/ip64-addrmap.c new file mode 100644 index 000000000..4578d1296 --- /dev/null +++ b/core/net/ip64/ip64-addrmap.c @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include "ip64-addrmap.h" + +#include "lib/memb.h" +#include "lib/list.h" + +#include "ip64-conf.h" + +#include + +#ifdef IP64_ADDRMAP_CONF_ENTRIES +#define NUM_ENTRIES IP64_ADDRMAP_CONF_ENTRIES +#else /* IP64_ADDRMAP_CONF_ENTRIES */ +#define NUM_ENTRIES 32 +#endif /* IP64_ADDRMAP_CONF_ENTRIES */ + +MEMB(entrymemb, struct ip64_addrmap_entry, NUM_ENTRIES); +LIST(entrylist); + +#define FIRST_MAPPED_PORT 10000 +#define LAST_MAPPED_PORT 20000 +static uint16_t mapped_port = FIRST_MAPPED_PORT; + +#define printf(...) + +/*---------------------------------------------------------------------------*/ +struct ip64_addrmap_entry * +ip64_addrmap_list(void) +{ + return list_head(entrylist); +} +/*---------------------------------------------------------------------------*/ +void +ip64_addrmap_init(void) +{ + memb_init(&entrymemb); + list_init(entrylist); + mapped_port = FIRST_MAPPED_PORT; +} +/*---------------------------------------------------------------------------*/ +static void +check_age(void) +{ + struct ip64_addrmap_entry *m; + + /* Walk through the list of address mappings, throw away the ones + that are too old. */ + m = list_head(entrylist); + while(m != NULL) { + if(timer_expired(&m->timer)) { + list_remove(entrylist, m); + memb_free(&entrymemb, m); + m = list_head(entrylist); + } else { + m = list_item_next(m); + } + } +} +/*---------------------------------------------------------------------------*/ +static int +recycle(void) +{ + /* Find the oldest recyclable mapping and remove it. */ + struct ip64_addrmap_entry *m, *oldest; + + /* Walk through the list of address mappings, throw away the ones + that are too old. */ + + oldest = NULL; + for(m = list_head(entrylist); + m != NULL; + m = list_item_next(m)) { + if(m->flags & FLAGS_RECYCLABLE) { + if(oldest == NULL) { + oldest = m; + } else { + if(timer_remaining(&m->timer) < + timer_remaining(&oldest->timer)) { + oldest = m; + } + } + } + } + + /* If we found an oldest recyclable entry, remove it and return + non-zero. */ + if(oldest != NULL) { + list_remove(entrylist, oldest); + memb_free(&entrymemb, oldest); + return 1; + } + + return 0; +} +/*---------------------------------------------------------------------------*/ +struct ip64_addrmap_entry * +ip64_addrmap_lookup(const uip_ip6addr_t *ip6addr, + uint16_t ip6port, + const uip_ip4addr_t *ip4addr, + uint16_t ip4port, + uint8_t protocol) +{ + struct ip64_addrmap_entry *m; + + printf("lookup ip4port %d ip6port %d\n", uip_htons(ip4port), + uip_htons(ip6port)); + check_age(); + for(m = list_head(entrylist); m != NULL; m = list_item_next(m)) { + printf("protocol %d %d, ip4port %d %d, ip6port %d %d, ip4 %d ip6 %d\n", + m->protocol, protocol, + m->ip4port, ip4port, + m->ip6port, ip6port, + uip_ip4addr_cmp(&m->ip4addr, ip4addr), + uip_ip6addr_cmp(&m->ip6addr, ip6addr)); + if(m->protocol == protocol && + m->ip4port == ip4port && + m->ip6port == ip6port && + uip_ip4addr_cmp(&m->ip4addr, ip4addr) && + uip_ip6addr_cmp(&m->ip6addr, ip6addr)) { + return m; + } + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +struct ip64_addrmap_entry * +ip64_addrmap_lookup_port(uint16_t mapped_port, uint8_t protocol) +{ + struct ip64_addrmap_entry *m; + + check_age(); + for(m = list_head(entrylist); m != NULL; m = list_item_next(m)) { + printf("mapped port %d %d, protocol %d %d\n", + m->mapped_port, mapped_port, + m->protocol, protocol); + if(m->mapped_port == mapped_port && + m->protocol == protocol) { + return m; + } + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +static void +increase_mapped_port(void) +{ + mapped_port++; + if(mapped_port >= LAST_MAPPED_PORT) { + mapped_port = FIRST_MAPPED_PORT; + } +} +/*---------------------------------------------------------------------------*/ +struct ip64_addrmap_entry * +ip64_addrmap_create(const uip_ip6addr_t *ip6addr, + uint16_t ip6port, + const uip_ip4addr_t *ip4addr, + uint16_t ip4port, + uint8_t protocol) +{ + struct ip64_addrmap_entry *m; + + check_age(); + m = memb_alloc(&entrymemb); + if(m == NULL) { + /* We could not allocate an entry, try to recycle one and try to + allocate again. */ + if(recycle()) { + m = memb_alloc(&entrymemb); + } + } + if(m != NULL) { + uip_ip4addr_copy(&m->ip4addr, ip4addr); + m->ip4port = ip4port; + uip_ip6addr_copy(&m->ip6addr, ip6addr); + m->ip6port = ip6port; + m->protocol = protocol; + m->flags = FLAGS_NONE; + timer_set(&m->timer, 0); + + /* Pick a new, unused local port. First make sure that the + mapped_port number does not belong to any active connection. If + so, we keep increasing the mapped_port until we're free. */ + { + struct ip64_addrmap_entry *n; + n = list_head(entrylist); + while(n != NULL) { + if(n->mapped_port == mapped_port) { + increase_mapped_port(); + n = list_head(entrylist); + } else { + n = list_item_next(m); + } + } + } + m->mapped_port = mapped_port; + increase_mapped_port(); + + list_add(entrylist, m); + return m; + } + return NULL; +} +/*---------------------------------------------------------------------------*/ +void +ip64_addrmap_set_lifetime(struct ip64_addrmap_entry *e, + clock_time_t time) +{ + if(e != NULL) { + timer_set(&e->timer, time); + } +} +/*---------------------------------------------------------------------------*/ +void +ip64_addrmap_set_recycleble(struct ip64_addrmap_entry *e) +{ + if(e != NULL) { + e->flags |= FLAGS_RECYCLABLE; + } +} +/*---------------------------------------------------------------------------*/ diff --git a/core/net/ip64/ip64-addrmap.h b/core/net/ip64/ip64-addrmap.h new file mode 100644 index 000000000..a055efdd0 --- /dev/null +++ b/core/net/ip64/ip64-addrmap.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef IP64_ADDRMAP_H +#define IP64_ADDRMAP_H + + +#include "sys/timer.h" +#include "net/ip/uip.h" + +struct ip64_addrmap_entry { + struct ip64_addrmap_entry *next; + struct timer timer; + uip_ip6addr_t ip6addr; + uip_ip4addr_t ip4addr; + uint16_t mapped_port; + uint16_t ip6port; + uint16_t ip4port; + uint8_t protocol; + uint8_t flags; +}; + +#define FLAGS_NONE 0 +#define FLAGS_RECYCLABLE 1 + +/** + * Initialize the ip64_addrmap module. + */ +void ip64_addrmap_init(void); + + +/** + * Look up an address mapping from inside the IPv6 network, given the + * IPv6 address/port, the IPv4 address/port, and the protocol. + */ +struct ip64_addrmap_entry *ip64_addrmap_lookup(const uip_ip6addr_t *ip6addr, + uint16_t ip6port, + const uip_ip4addr_t *ip4addr, + uint16_t ip4port, + uint8_t protocol); + +/** + * Look up an address mapping from the outside IPv4 network, given the + * mapped port number and protocol. + */ +struct ip64_addrmap_entry *ip64_addrmap_lookup_port(uint16_t mappedport, + uint8_t protocol); + +/** + * Create a new address mapping from an IPv6 address/port, an IPv4 + * address/port, and a protocol number. + */ +struct ip64_addrmap_entry *ip64_addrmap_create(const uip_ip6addr_t *ip6addr, + uint16_t ip6port, + const uip_ip4addr_t *ip4addr, + uint16_t ip4port, + uint8_t protocol); + +/** + * Set the lifetime of an address mapping. + */ +void ip64_addrmap_set_lifetime(struct ip64_addrmap_entry *e, + clock_time_t lifetime); + +/** + * Mark an address mapping to be recyclable. + */ +void ip64_addrmap_set_recycleble(struct ip64_addrmap_entry *e); + +/** + * Obtain the list of all address mappings. + */ +struct ip64_addrmap_entry *ip64_addrmap_list(void); +#endif /* IP64_ADDRMAP_H */ diff --git a/core/net/ip64/ip64-arp.c b/core/net/ip64/ip64-arp.c new file mode 100644 index 000000000..996773e1d --- /dev/null +++ b/core/net/ip64/ip64-arp.c @@ -0,0 +1,417 @@ +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: uip_arp.c,v 1.8 2010/12/14 22:45:22 dak664 Exp $ + * + */ + +#include "ip64.h" +#include "ip64-eth.h" +#include "ip64-arp.h" + +#include +#include + +#define printf(...) + +struct arp_hdr { + struct ip64_eth_hdr ethhdr; + uint16_t hwtype; + uint16_t protocol; + uint8_t hwlen; + uint8_t protolen; + uint16_t opcode; + struct uip_eth_addr shwaddr; + uip_ip4addr_t sipaddr; + struct uip_eth_addr dhwaddr; + uip_ip4addr_t dipaddr; +}; + +struct ethip_hdr { + struct ip64_eth_hdr ethhdr; + /* IP header. */ + uint8_t vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + uint16_t ipchksum; + uip_ip4addr_t srcipaddr, destipaddr; +}; + +struct ipv4_hdr { + /* IP header. */ + uint8_t vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + uint16_t ipchksum; + uip_ip4addr_t srcipaddr, destipaddr; +}; + +#define ARP_REQUEST 1 +#define ARP_REPLY 2 + +#define ARP_HWTYPE_ETH 1 + +struct arp_entry { + uip_ip4addr_t ipaddr; + struct uip_eth_addr ethaddr; + uint8_t time; +}; + +static const struct ip64_eth_addr broadcast_ethaddr = + {{0xff,0xff,0xff,0xff,0xff,0xff}}; +static const uint16_t broadcast_ipaddr[2] = {0xffff,0xffff}; + +static struct arp_entry arp_table[UIP_ARPTAB_SIZE]; + +static uint8_t arptime; +static uint8_t tmpage; + +#define DEBUG 0 +#if DEBUG +#include +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif + +const uip_ipaddr_t uip_all_zeroes_addr; + +/*---------------------------------------------------------------------------*/ +/** + * Initialize the ARP module. + * + */ +/*---------------------------------------------------------------------------*/ +void +ip64_arp_init(void) +{ + int i; + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + memset(&arp_table[i].ipaddr, 0, 4); + } +} +/*---------------------------------------------------------------------------*/ +/** + * Periodic ARP processing function. + * + * This function performs periodic timer processing in the ARP module + * and should be called at regular intervals. The recommended interval + * is 10 seconds between the calls. + * + */ +/*---------------------------------------------------------------------------*/ +void +ip64_arp_timer(void) +{ + struct arp_entry *tabptr; + int i; + + ++arptime; + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + tabptr = &arp_table[i]; + if(uip_ip4addr_cmp(&tabptr->ipaddr, &uip_all_zeroes_addr) && + arptime - tabptr->time >= UIP_ARP_MAXAGE) { + memset(&tabptr->ipaddr, 0, 4); + } + } + +} + +/*---------------------------------------------------------------------------*/ +static void +arp_update(uip_ip4addr_t *ipaddr, struct uip_eth_addr *ethaddr) +{ + register struct arp_entry *tabptr = arp_table; + int i, c; + + /* Walk through the ARP mapping table and try to find an entry to + update. If none is found, the IP -> MAC address mapping is + inserted in the ARP table. */ + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + tabptr = &arp_table[i]; + + /* Only check those entries that are actually in use. */ + if(!uip_ip4addr_cmp(&tabptr->ipaddr, &uip_all_zeroes_addr)) { + + /* Check if the source IP address of the incoming packet matches + the IP address in this ARP table entry. */ + if(uip_ip4addr_cmp(ipaddr, &tabptr->ipaddr)) { + + /* An old entry found, update this and return. */ + memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6); + tabptr->time = arptime; + + return; + } + } + tabptr++; + } + + /* If we get here, no existing ARP table entry was found, so we + create one. */ + + /* First, we try to find an unused entry in the ARP table. */ + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + tabptr = &arp_table[i]; + if(uip_ip4addr_cmp(&tabptr->ipaddr, &uip_all_zeroes_addr)) { + break; + } + } + + /* If no unused entry is found, we try to find the oldest entry and + throw it away. */ + if(i == UIP_ARPTAB_SIZE) { + tmpage = 0; + c = 0; + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + tabptr = &arp_table[i]; + if(arptime - tabptr->time > tmpage) { + tmpage = arptime - tabptr->time; + c = i; + } + } + i = c; + tabptr = &arp_table[i]; + } + + /* Now, i is the ARP table entry which we will fill with the new + information. */ + uip_ip4addr_copy(&tabptr->ipaddr, ipaddr); + memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6); + tabptr->time = arptime; +} +/*---------------------------------------------------------------------------*/ +uint16_t +ip64_arp_arp_input(const uint8_t *packet, uint16_t packet_len) +{ + struct arp_hdr *arphdr = (struct arp_hdr *)packet; + + if(packet_len < sizeof(struct arp_hdr)) { + printf("ip64_arp_arp_input: len too small %d\n", packet_len); + return 0; + } + + switch(arphdr->opcode) { + case UIP_HTONS(ARP_REQUEST): + /* ARP request. If it asked for our address, we send out a + reply. */ + printf("ip64_arp_arp_input: request for %d.%d.%d.%d (we are %d.%d.%d.%d)\n", + arphdr->dipaddr.u8[0], arphdr->dipaddr.u8[1], + arphdr->dipaddr.u8[2], arphdr->dipaddr.u8[3], + ip64_get_hostaddr()->u8[0], ip64_get_hostaddr()->u8[1], + ip64_get_hostaddr()->u8[2], ip64_get_hostaddr()->u8[3]); + if(uip_ip4addr_cmp(&arphdr->dipaddr, ip64_get_hostaddr())) { + /* First, we register the one who made the request in our ARP + table, since it is likely that we will do more communication + with this host in the future. */ + arp_update(&arphdr->sipaddr, &arphdr->shwaddr); + + arphdr->opcode = UIP_HTONS(ARP_REPLY); + + memcpy(arphdr->dhwaddr.addr, arphdr->shwaddr.addr, 6); + memcpy(arphdr->shwaddr.addr, ip64_eth_addr.addr, 6); + memcpy(arphdr->ethhdr.src.addr, ip64_eth_addr.addr, 6); + memcpy(arphdr->ethhdr.dest.addr, arphdr->dhwaddr.addr, 6); + + uip_ip4addr_copy(&arphdr->dipaddr, &arphdr->sipaddr); + uip_ip4addr_copy(&arphdr->sipaddr, ip64_get_hostaddr()); + + arphdr->ethhdr.type = UIP_HTONS(IP64_ETH_TYPE_ARP); + return sizeof(struct arp_hdr); + } + break; + case UIP_HTONS(ARP_REPLY): + /* ARP reply. We insert or update the ARP table if it was meant + for us. */ + if(uip_ip4addr_cmp(&arphdr->dipaddr, ip64_get_hostaddr())) { + arp_update(&arphdr->sipaddr, &arphdr->shwaddr); + } + break; + } + + return 0; +} +/*---------------------------------------------------------------------------*/ +int +ip64_arp_check_cache(const uint8_t *nlhdr) +{ + struct ipv4_hdr *ipv4_hdr = (struct ipv4_hdr *)nlhdr; + uip_ip4addr_t broadcast_addr; + struct arp_entry *tabptr = arp_table; + + printf("check cache %d.%d.%d.%d\n", + uip_ipaddr_to_quad(&ipv4_hdr->destipaddr)); + + /* First check if destination is a local broadcast. */ + uip_ipaddr(&broadcast_addr, 255,255,255,255); + if(uip_ip4addr_cmp(&ipv4_hdr->destipaddr, &broadcast_addr)) { + printf("Return 1\n"); + return 1; + } else if(ipv4_hdr->destipaddr.u8[0] == 224) { + /* Multicast. */ + return 1; + } else { + uip_ip4addr_t ipaddr; + int i; + /* Check if the destination address is on the local network. */ + if(!uip_ipaddr_maskcmp(&ipv4_hdr->destipaddr, + ip64_get_hostaddr(), + ip64_get_netmask())) { + /* Destination address was not on the local network, so we need to + use the default router's IP address instead of the destination + address when determining the MAC address. */ + uip_ip4addr_copy(&ipaddr, ip64_get_draddr()); + } else { + /* Else, we use the destination IP address. */ + uip_ip4addr_copy(&ipaddr, &ipv4_hdr->destipaddr); + } + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + if(uip_ip4addr_cmp(&ipaddr, &tabptr->ipaddr)) { + break; + } + tabptr++; + } + + if(i == UIP_ARPTAB_SIZE) { + return 0; + } + return 1; + } + return 0; +} +/*---------------------------------------------------------------------------*/ +int +ip64_arp_create_ethhdr(uint8_t *llhdr, const uint8_t *nlhdr) +{ + struct arp_entry *tabptr = arp_table; + struct ipv4_hdr *ipv4_hdr = (struct ipv4_hdr *)nlhdr; + struct ip64_eth_hdr *ethhdr = (struct ip64_eth_hdr *)llhdr; + uip_ip4addr_t broadcast_addr; + + /* Find the destination IP address in the ARP table and construct + the Ethernet header. If the destination IP addres isn't on the + local network, we use the default router's IP address instead. + + If not ARP table entry is found, we overwrite the original IP + packet with an ARP request for the IP address. */ + + /* First check if destination is a local broadcast. */ + uip_ipaddr(&broadcast_addr, 255,255,255,255); + if(uip_ip4addr_cmp(&ipv4_hdr->destipaddr, &broadcast_addr)) { + memcpy(ðhdr->dest.addr, &broadcast_ethaddr.addr, 6); + } else if(ipv4_hdr->destipaddr.u8[0] == 224) { + /* Multicast. */ + ethhdr->dest.addr[0] = 0x01; + ethhdr->dest.addr[1] = 0x00; + ethhdr->dest.addr[2] = 0x5e; + ethhdr->dest.addr[3] = ipv4_hdr->destipaddr.u8[1]; + ethhdr->dest.addr[4] = ipv4_hdr->destipaddr.u8[2]; + ethhdr->dest.addr[5] = ipv4_hdr->destipaddr.u8[3]; + } else { + uip_ip4addr_t ipaddr; + int i; + /* Check if the destination address is on the local network. */ + if(!uip_ipaddr_maskcmp(&ipv4_hdr->destipaddr, + ip64_get_hostaddr(), + ip64_get_netmask())) { + /* Destination address was not on the local network, so we need to + use the default router's IP address instead of the destination + address when determining the MAC address. */ + uip_ip4addr_copy(&ipaddr, ip64_get_draddr()); + } else { + /* Else, we use the destination IP address. */ + uip_ip4addr_copy(&ipaddr, &ipv4_hdr->destipaddr); + } + for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { + if(uip_ip4addr_cmp(&ipaddr, &tabptr->ipaddr)) { + break; + } + tabptr++; + } + + if(i == UIP_ARPTAB_SIZE) { + return 0; + } + + memcpy(ethhdr->dest.addr, tabptr->ethaddr.addr, 6); + + } + memcpy(ethhdr->src.addr, ip64_eth_addr.addr, 6); + + ethhdr->type = UIP_HTONS(IP64_ETH_TYPE_IP); + return sizeof(struct ip64_eth_hdr); +} +/*---------------------------------------------------------------------------*/ +int +ip64_arp_create_arp_request(uint8_t *llhdr, const uint8_t *nlhdr) +{ + struct ipv4_hdr *ipv4_hdr = (struct ipv4_hdr *)nlhdr; + struct arp_hdr *arp_hdr = (struct arp_hdr *)llhdr; + uip_ip4addr_t ipaddr; + + if(!uip_ipaddr_maskcmp(&ipv4_hdr->destipaddr, + ip64_get_hostaddr(), + ip64_get_netmask())) { + /* Destination address was not on the local network, so we need to + use the default router's IP address instead of the destination + address when determining the MAC address. */ + uip_ip4addr_copy(&ipaddr, ip64_get_draddr()); + } else { + /* Else, we use the destination IP address. */ + uip_ip4addr_copy(&ipaddr, &ipv4_hdr->destipaddr); + } + + memset(arp_hdr->ethhdr.dest.addr, 0xff, 6); + memset(arp_hdr->dhwaddr.addr, 0x00, 6); + memcpy(arp_hdr->ethhdr.src.addr, ip64_eth_addr.addr, 6); + memcpy(arp_hdr->shwaddr.addr, ip64_eth_addr.addr, 6); + + uip_ip4addr_copy(&arp_hdr->dipaddr, &ipaddr); + uip_ip4addr_copy(&arp_hdr->sipaddr, ip64_get_hostaddr()); + arp_hdr->opcode = UIP_HTONS(ARP_REQUEST); + arp_hdr->hwtype = UIP_HTONS(ARP_HWTYPE_ETH); + arp_hdr->protocol = UIP_HTONS(IP64_ETH_TYPE_IP); + arp_hdr->hwlen = 6; + arp_hdr->protolen = 4; + arp_hdr->ethhdr.type = UIP_HTONS(IP64_ETH_TYPE_ARP); + + uip_appdata = &uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN]; + + return sizeof(struct arp_hdr); +} +/*---------------------------------------------------------------------------*/ diff --git a/core/net/ip64/ip64-arp.h b/core/net/ip64/ip64-arp.h new file mode 100644 index 000000000..1da84e519 --- /dev/null +++ b/core/net/ip64/ip64-arp.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2001-2003, Adam Dunkels. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the uIP TCP/IP stack. + * + * $Id: uip_arp.h,v 1.2 2006/08/26 23:58:45 oliverschmidt Exp $ + * + */ + +#ifndef IP64_ARP_H +#define IP64_ARP_H + +#include "net/ip/uip.h" + +#include "ip64-eth.h" + + +/* The uip_arp_init() function must be called before any of the other + ARP functions. */ +void ip64_arp_init(void); + +/* The uip_arp_ipin() function should be called whenever an IP packet + arrives from the Ethernet. This function refreshes the ARP table or + inserts a new mapping if none exists. The function assumes that an + IP packet with an Ethernet header is present in the uip_buf buffer + and that the length of the packet is in the uip_len variable. */ +void ip64_arp_ip_input(const uint8_t *packet, uint16_t packet_len); + +/* The uip_arp_arpin() should be called when an ARP packet is received + by the Ethernet driver. This function also assumes that the + Ethernet frame is present in the uip_buf buffer. When the + uip_arp_arpin() function returns, the contents of the uip_buf + buffer should be sent out on the Ethernet if the uip_len variable + is > 0. */ +uint16_t ip64_arp_arp_input(const uint8_t *packet, uint16_t packet_len); + +/* The uip_arp_out() function should be called when an IP packet + should be sent out on the Ethernet. This function creates an + Ethernet header before the IP header in the uip_buf buffer. The + Ethernet header will have the correct Ethernet MAC destination + address filled in if an ARP table entry for the destination IP + address (or the IP address of the default router) is present. If no + such table entry is found, the IP packet is overwritten with an ARP + request and we rely on TCP to retransmit the packet that was + overwritten. In any case, the uip_len variable holds the length of + the Ethernet frame that should be transmitted. */ +void ip64_arp_ip_output(uint8_t *packet, uint16_t packet_len); + + +int ip64_arp_create_ethhdr(uint8_t *link_header, + const uint8_t *network_header); + +int ip64_arp_create_arp_request(uint8_t *link_header, + const uint8_t *network_header); + +int ip64_arp_check_cache(const uint8_t *nlhdr); + + +#endif /* IP64_ARP_H */ diff --git a/core/net/ip64/ip64-conf-example.h b/core/net/ip64/ip64-conf-example.h new file mode 100644 index 000000000..33c1ff285 --- /dev/null +++ b/core/net/ip64/ip64-conf-example.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef IP64_CONF_H +#define IP64_CONF_H + +#include "ip64-tap-driver.h" +#include "ip64-eth-interface.h" + +#define IP64_CONF_UIP_FALLBACK_INTERFACE ip64_eth_interface +#define IP64_CONF_INPUT ip64_eth_interface_input + +#define IP64_CONF_ETH_DRIVER ip64_tap_driver + +#endif /* IP64_CONF_H */ diff --git a/core/net/ip64/ip64-dhcpc.c b/core/net/ip64/ip64-dhcpc.c new file mode 100644 index 000000000..fdb1dd0ec --- /dev/null +++ b/core/net/ip64/ip64-dhcpc.c @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2005, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + * @(#)$Id: dhcpc.c,v 1.9 2010/10/19 18:29:04 adamdunkels Exp $ + */ + +#include +#include + +#include "contiki.h" +#include "contiki-net.h" +#include "ip64-dhcpc.h" + +#include "ip64-addr.h" + +#define STATE_INITIAL 0 +#define STATE_SENDING 1 +#define STATE_OFFER_RECEIVED 2 +#define STATE_CONFIG_RECEIVED 3 + +static struct ip64_dhcpc_state s; + +struct dhcp_msg { + uint8_t op, htype, hlen, hops; + uint8_t xid[4]; + uint16_t secs, flags; + uint8_t ciaddr[4]; + uint8_t yiaddr[4]; + uint8_t siaddr[4]; + uint8_t giaddr[4]; + uint8_t chaddr[16]; + uint8_t sname[64]; + uint8_t file[128]; + uint8_t options[312]; +}; + +#if (UIP_BUFSIZE - UIP_UDPIP_HLEN) < 548 +#error UIP_CONF_BUFFER_SIZE may be too small to accomodate DHCPv4 packets +#error Increase UIP_CONF_BUFFER_SIZE in your project-conf.h, platform-conf.h, or contiki-conf.h +#error A good size is 600 bytes +#endif + +#define BOOTP_BROADCAST 0x8000 + +#define DHCP_REQUEST 1 +#define DHCP_REPLY 2 +#define DHCP_HTYPE_ETHERNET 1 +#define DHCP_HLEN_ETHERNET 6 +#define DHCP_MSG_LEN 236 + +#define IP64_DHCPC_SERVER_PORT 67 +#define IP64_DHCPC_CLIENT_PORT 68 + +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPDECLINE 4 +#define DHCPACK 5 +#define DHCPNAK 6 +#define DHCPRELEASE 7 + +#define DHCP_OPTION_SUBNET_MASK 1 +#define DHCP_OPTION_ROUTER 3 +#define DHCP_OPTION_DNS_SERVER 6 +#define DHCP_OPTION_REQ_IPADDR 50 +#define DHCP_OPTION_LEASE_TIME 51 +#define DHCP_OPTION_MSG_TYPE 53 +#define DHCP_OPTION_SERVER_ID 54 +#define DHCP_OPTION_REQ_LIST 55 +#define DHCP_OPTION_END 255 + +static uint32_t xid; +static const uint8_t magic_cookie[4] = {99, 130, 83, 99}; +/*---------------------------------------------------------------------------*/ +static uint8_t * +add_msg_type(uint8_t *optptr, uint8_t type) +{ + *optptr++ = DHCP_OPTION_MSG_TYPE; + *optptr++ = 1; + *optptr++ = type; + return optptr; +} +/*---------------------------------------------------------------------------*/ +static uint8_t * +add_server_id(uint8_t *optptr) +{ + *optptr++ = DHCP_OPTION_SERVER_ID; + *optptr++ = 4; + memcpy(optptr, s.serverid, 4); + return optptr + 4; +} +/*---------------------------------------------------------------------------*/ +static uint8_t * +add_req_ipaddr(uint8_t *optptr) +{ + *optptr++ = DHCP_OPTION_REQ_IPADDR; + *optptr++ = 4; + memcpy(optptr, s.ipaddr.u16, 4); + return optptr + 4; +} +/*---------------------------------------------------------------------------*/ +static uint8_t * +add_req_options(uint8_t *optptr) +{ + *optptr++ = DHCP_OPTION_REQ_LIST; + *optptr++ = 3; + *optptr++ = DHCP_OPTION_SUBNET_MASK; + *optptr++ = DHCP_OPTION_ROUTER; + *optptr++ = DHCP_OPTION_DNS_SERVER; + return optptr; +} +/*---------------------------------------------------------------------------*/ +static uint8_t * +add_end(uint8_t *optptr) +{ + *optptr++ = DHCP_OPTION_END; + return optptr; +} +/*---------------------------------------------------------------------------*/ +static void +create_msg(CC_REGISTER_ARG struct dhcp_msg *m) +{ + m->op = DHCP_REQUEST; + m->htype = DHCP_HTYPE_ETHERNET; + m->hlen = s.mac_len; + m->hops = 0; + memcpy(m->xid, &xid, sizeof(m->xid)); + m->secs = 0; + m->flags = UIP_HTONS(BOOTP_BROADCAST); /* Broadcast bit. */ + /* uip_ipaddr_copy(m->ciaddr, uip_hostaddr);*/ + memcpy(m->ciaddr, uip_hostaddr.u16, sizeof(m->ciaddr)); + memset(m->yiaddr, 0, sizeof(m->yiaddr)); + memset(m->siaddr, 0, sizeof(m->siaddr)); + memset(m->giaddr, 0, sizeof(m->giaddr)); + memcpy(m->chaddr, s.mac_addr, s.mac_len); + memset(&m->chaddr[s.mac_len], 0, sizeof(m->chaddr) - s.mac_len); + + memset(m->sname, 0, sizeof(m->sname)); + strcpy((char *)m->sname, "Thingsquare"); + memset(m->file, 0, sizeof(m->file)); + + + memcpy(m->options, magic_cookie, sizeof(magic_cookie)); +} +/*---------------------------------------------------------------------------*/ +static void +send_discover(void) +{ + uint8_t *end; + struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; + + create_msg(m); + + end = add_msg_type(&m->options[4], DHCPDISCOVER); + end = add_req_options(end); + end = add_end(end); + + uip_send(uip_appdata, (int)(end - (uint8_t *)uip_appdata)); +} +/*---------------------------------------------------------------------------*/ +static void +send_request(void) +{ + uint8_t *end; + struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; + + create_msg(m); + + end = add_msg_type(&m->options[4], DHCPREQUEST); + end = add_server_id(end); + end = add_req_ipaddr(end); + end = add_end(end); + + uip_send(uip_appdata, (int)(end - (uint8_t *)uip_appdata)); +} +/*---------------------------------------------------------------------------*/ +static uint8_t +parse_options(uint8_t *optptr, int len) +{ + uint8_t *end = optptr + len; + uint8_t type = 0; + + while(optptr < end) { + switch(*optptr) { + case DHCP_OPTION_SUBNET_MASK: + memcpy(s.netmask.u16, optptr + 2, 4); + break; + case DHCP_OPTION_ROUTER: + memcpy(s.default_router.u16, optptr + 2, 4); + break; + case DHCP_OPTION_DNS_SERVER: + memcpy(s.dnsaddr.u16, optptr + 2, 4); + break; + case DHCP_OPTION_MSG_TYPE: + type = *(optptr + 2); + break; + case DHCP_OPTION_SERVER_ID: + memcpy(s.serverid, optptr + 2, 4); + break; + case DHCP_OPTION_LEASE_TIME: + memcpy(s.lease_time, optptr + 2, 4); + break; + case DHCP_OPTION_END: + return type; + } + + optptr += optptr[1] + 2; + } + return type; +} +/*---------------------------------------------------------------------------*/ +static uint8_t +parse_msg(void) +{ + struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; + + if(m->op == DHCP_REPLY && + memcmp(m->xid, &xid, sizeof(xid)) == 0 && + memcmp(m->chaddr, s.mac_addr, s.mac_len) == 0) { + memcpy(s.ipaddr.u16, m->yiaddr, 4); + return parse_options(&m->options[4], uip_datalen()); + } + return 0; +} +/*---------------------------------------------------------------------------*/ +/* + * Is this a "fresh" reply for me? If it is, return the type. + */ +static int +msg_for_me(void) +{ + struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata; + uint8_t *optptr = &m->options[4]; + uint8_t *end = (uint8_t*)uip_appdata + uip_datalen(); + + if(m->op == DHCP_REPLY && + memcmp(m->xid, &xid, sizeof(xid)) == 0 && + memcmp(m->chaddr, s.mac_addr, s.mac_len) == 0) { + while(optptr < end) { + if(*optptr == DHCP_OPTION_MSG_TYPE) { + return *(optptr + 2); + } else if (*optptr == DHCP_OPTION_END) { + return -1; + } + optptr += optptr[1] + 2; + } + } + return -1; +} +/*---------------------------------------------------------------------------*/ +static +PT_THREAD(handle_dhcp(process_event_t ev, void *data)) +{ + clock_time_t ticks; + + PT_BEGIN(&s.pt); + + init: + xid++; + s.state = STATE_SENDING; + s.ticks = CLOCK_SECOND * 4; + while(1) { + while(ev != tcpip_event) { + tcpip_poll_udp(s.conn); + PT_YIELD(&s.pt); + } + send_discover(); + etimer_set(&s.etimer, s.ticks); + do { + PT_YIELD(&s.pt); + if(ev == tcpip_event && uip_newdata() && msg_for_me() == DHCPOFFER) { + parse_msg(); + s.state = STATE_OFFER_RECEIVED; + goto selecting; + } + } while(!etimer_expired(&s.etimer)); + + if(s.ticks < CLOCK_SECOND * 60) { + s.ticks *= 2; + } + } + + selecting: + xid++; + s.ticks = CLOCK_SECOND; + do { + while(ev != tcpip_event) { + tcpip_poll_udp(s.conn); + PT_YIELD(&s.pt); + } + send_request(); + etimer_set(&s.etimer, s.ticks); + do { + PT_YIELD(&s.pt); + if(ev == tcpip_event && uip_newdata() && msg_for_me() == DHCPACK) { + parse_msg(); + s.state = STATE_CONFIG_RECEIVED; + goto bound; + } + } while (!etimer_expired(&s.etimer)); + + if(s.ticks <= CLOCK_SECOND * 10) { + s.ticks += CLOCK_SECOND; + } else { + goto init; + } + } while(s.state != STATE_CONFIG_RECEIVED); + + bound: +#if 0 + printf("Got IP address %d.%d.%d.%d\n", uip_ipaddr_to_quad(&s.ipaddr)); + printf("Got netmask %d.%d.%d.%d\n", uip_ipaddr_to_quad(&s.netmask)); + printf("Got DNS server %d.%d.%d.%d\n", uip_ipaddr_to_quad(&s.dnsaddr)); + printf("Got default router %d.%d.%d.%d\n", + uip_ipaddr_to_quad(&s.default_router)); + printf("Lease expires in %ld seconds\n", + uip_ntohs(s.lease_time[0])*65536ul + uip_ntohs(s.lease_time[1])); +#endif + + ip64_dhcpc_configured(&s); + +#define MAX_TICKS (~((clock_time_t)0) / 2) +#define MAX_TICKS32 (~((uint32_t)0)) +#define IMIN(a, b) ((a) < (b) ? (a) : (b)) + + if((uip_ntohs(s.lease_time[0])*65536ul + uip_ntohs(s.lease_time[1]))*CLOCK_SECOND/2 + <= MAX_TICKS32) { + s.ticks = (uip_ntohs(s.lease_time[0])*65536ul + uip_ntohs(s.lease_time[1]) + )*CLOCK_SECOND/2; + } else { + s.ticks = MAX_TICKS32; + } + + while(s.ticks > 0) { + ticks = IMIN(s.ticks, MAX_TICKS); + s.ticks -= ticks; + etimer_set(&s.etimer, ticks); + PT_YIELD_UNTIL(&s.pt, etimer_expired(&s.etimer)); + } + + if((uip_ntohs(s.lease_time[0])*65536ul + uip_ntohs(s.lease_time[1]))*CLOCK_SECOND/2 + <= MAX_TICKS32) { + s.ticks = (uip_ntohs(s.lease_time[0])*65536ul + uip_ntohs(s.lease_time[1]) + )*CLOCK_SECOND/2; + } else { + s.ticks = MAX_TICKS32; + } + + /* renewing: */ + xid++; + do { + while(ev != tcpip_event) { + tcpip_poll_udp(s.conn); + PT_YIELD(&s.pt); + } + send_request(); + ticks = IMIN(s.ticks / 2, MAX_TICKS); + s.ticks -= ticks; + etimer_set(&s.etimer, ticks); + do { + PT_YIELD(&s.pt); + if(ev == tcpip_event && uip_newdata() && msg_for_me() == DHCPACK) { + parse_msg(); + goto bound; + } + } while(!etimer_expired(&s.etimer)); + } while(s.ticks >= CLOCK_SECOND*3); + + /* rebinding: */ + + /* lease_expired: */ + ip64_dhcpc_unconfigured(&s); + goto init; + + PT_END(&s.pt); +} +/*---------------------------------------------------------------------------*/ +void +ip64_dhcpc_init(const void *mac_addr, int mac_len) +{ + /* Although this is DHCPv4, we explicitly bind the socket to an IPv6 + address so that it can operate over the ip64 bridge. */ + uip_ip6addr_t v6addr; + uip_ip4addr_t v4addr; + struct uip_udp_conn *conn2; + + s.mac_addr = mac_addr; + s.mac_len = mac_len; + + s.state = STATE_INITIAL; + uip_ipaddr(&v4addr, 255,255,255,255); + ip64_addr_4to6(&v4addr, &v6addr); + s.conn = udp_new(&v6addr, UIP_HTONS(IP64_DHCPC_SERVER_PORT), NULL); + conn2 = udp_new(NULL, UIP_HTONS(IP64_DHCPC_SERVER_PORT), NULL); + if(s.conn != NULL) { + udp_bind(s.conn, UIP_HTONS(IP64_DHCPC_CLIENT_PORT)); + } + if(conn2 != NULL) { + udp_bind(conn2, UIP_HTONS(IP64_DHCPC_CLIENT_PORT)); + } + PT_INIT(&s.pt); +} +/*---------------------------------------------------------------------------*/ +void +ip64_dhcpc_appcall(process_event_t ev, void *data) +{ + if(ev == tcpip_event || ev == PROCESS_EVENT_TIMER) { + handle_dhcp(ev, data); + } +} +/*---------------------------------------------------------------------------*/ +void +ip64_dhcpc_request(void) +{ + uip_ipaddr_t ipaddr; + + if(s.state == STATE_INITIAL) { + uip_ipaddr(&ipaddr, 0,0,0,0); + uip_sethostaddr(&ipaddr); + handle_dhcp(PROCESS_EVENT_NONE, NULL); + } +} +/*---------------------------------------------------------------------------*/ diff --git a/core/net/ip64/ip64-dhcpc.h b/core/net/ip64/ip64-dhcpc.h new file mode 100644 index 000000000..1bc88daf6 --- /dev/null +++ b/core/net/ip64/ip64-dhcpc.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2005, Swedish Institute of Computer Science + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ +#ifndef __IP64_DHCPC_H__ +#define __IP64_DHCPC_H__ + +struct ip64_dhcpc_state { + struct pt pt; + char state; + struct uip_udp_conn *conn; + struct etimer etimer; + uint32_t ticks; + const void *mac_addr; + int mac_len; + + uint8_t serverid[4]; + + uint16_t lease_time[2]; + uip_ipaddr_t ipaddr; + uip_ipaddr_t netmask; + uip_ipaddr_t dnsaddr; + uip_ipaddr_t default_router; +}; + +void ip64_dhcpc_init(const void *mac_addr, int mac_len); +void ip64_dhcpc_request(void); + +void ip64_dhcpc_appcall(process_event_t ev, void *data); + +/* Mandatory callbacks provided by the user. */ +void ip64_dhcpc_configured(const struct ip64_dhcpc_state *s); +void ip64_dhcpc_unconfigured(const struct ip64_dhcpc_state *s); + +#endif /* __IP64_DHCPC_H__ */ diff --git a/core/net/ip64/ip64-driver.h b/core/net/ip64/ip64-driver.h new file mode 100644 index 000000000..9de5d44a3 --- /dev/null +++ b/core/net/ip64/ip64-driver.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef IP64_DRIVER_H +#define IP64_DRIVER_H + +struct ip64_driver { + void (* init)(void); + int (* output)(uint8_t *packet, uint16_t packet_len); +}; + + +#endif /* IP64_DRIVER_H */ diff --git a/core/net/ip64/ip64-eth-interface.c b/core/net/ip64/ip64-eth-interface.c new file mode 100644 index 000000000..d2d941e2a --- /dev/null +++ b/core/net/ip64/ip64-eth-interface.c @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include "net/ip/uip.h" +#include "net/ipv6/uip-ds6.h" +#include "dev/slip.h" + +#include "ip64.h" +#include "ip64-arp.h" +#include "ip64-eth-interface.h" + +#include + +#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) + +#define DEBUG DEBUG_NONE +#include "net/ip/uip-debug.h" +#define printf(...) +/*---------------------------------------------------------------------------*/ +void +ip64_eth_interface_input(uint8_t *packet, uint16_t len) +{ + struct ip64_eth_hdr *ethhdr; + ethhdr = (struct ip64_eth_hdr *)packet; + + if(ethhdr->type == UIP_HTONS(IP64_ETH_TYPE_ARP)) { + len = ip64_arp_arp_input(packet, len); + + if(len > 0) { + IP64_ETH_DRIVER.output(packet, len); + } + } else if(ethhdr->type == UIP_HTONS(IP64_ETH_TYPE_IP) && + len > sizeof(struct ip64_eth_hdr)) { + printf("-------------->\n"); + uip_len = ip64_4to6(&packet[sizeof(struct ip64_eth_hdr)], + len - sizeof(struct ip64_eth_hdr), + &uip_buf[UIP_LLH_LEN]); + if(uip_len > 0) { + printf("ip64_interface_process: converted %d bytes\n", uip_len); + + printf("ip64-interface: input source "); + PRINT6ADDR(&UIP_IP_BUF->srcipaddr); + PRINTF(" destination "); + PRINT6ADDR(&UIP_IP_BUF->destipaddr); + PRINTF("\n"); + + tcpip_input(); + printf("Done\n"); + } + } +} +/*---------------------------------------------------------------------------*/ +static void +init(void) +{ + printf("ip64-eth-interface: init\n"); +} +/*---------------------------------------------------------------------------*/ +static void +output(void) +{ + int len, ret; + + + printf("ip64-interface: output source "); + PRINT6ADDR(&UIP_IP_BUF->srcipaddr); + PRINTF(" destination "); + PRINT6ADDR(&UIP_IP_BUF->destipaddr); + PRINTF("\n"); + + printf("<--------------\n"); + len = ip64_6to4(&uip_buf[UIP_LLH_LEN], uip_len, + &ip64_packet_buffer[sizeof(struct ip64_eth_hdr)]); + + printf("ip64-interface: output len %d\n", len); + if(len > 0) { + if(ip64_arp_check_cache(&ip64_packet_buffer[sizeof(struct ip64_eth_hdr)])) { + printf("Create header\n"); + ret = ip64_arp_create_ethhdr(ip64_packet_buffer, + &ip64_packet_buffer[sizeof(struct ip64_eth_hdr)]); + if(ret > 0) { + len += ret; + IP64_ETH_DRIVER.output(ip64_packet_buffer, len); + } + } else { + printf("Create request\n"); + len = ip64_arp_create_arp_request(ip64_packet_buffer, + &ip64_packet_buffer[sizeof(struct ip64_eth_hdr)]); + IP64_ETH_DRIVER.output(ip64_packet_buffer, len); + } + } +} +/*---------------------------------------------------------------------------*/ +const struct uip_fallback_interface ip64_eth_interface = { + init, + output +}; +/*---------------------------------------------------------------------------*/ diff --git a/core/net/ip64/ip64-eth-interface.h b/core/net/ip64/ip64-eth-interface.h new file mode 100644 index 000000000..83dc6ab53 --- /dev/null +++ b/core/net/ip64/ip64-eth-interface.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef IP64_ETH_INTERFACE_H +#define IP64_ETH_INTERFACE_H + +#include "net/ip/uip.h" + +void ip64_eth_interface_input(uint8_t *packet, uint16_t len); + +extern const struct uip_fallback_interface ip64_eth_interface; + +#endif /* IP64_ETH_INTERFACE_H */ diff --git a/core/net/ip64/ip64-eth.c b/core/net/ip64/ip64-eth.c new file mode 100644 index 000000000..1f6c67525 --- /dev/null +++ b/core/net/ip64/ip64-eth.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include "ip64-eth.h" + +#include + +struct ip64_eth_addr ip64_eth_addr; + +/*---------------------------------------------------------------------------*/ +void +ip64_eth_addr_set(struct ip64_eth_addr *addr) +{ + memcpy(&ip64_eth_addr, addr, sizeof(struct ip64_eth_addr)); +} +/*---------------------------------------------------------------------------*/ diff --git a/core/net/ip64/ip64-eth.h b/core/net/ip64/ip64-eth.h new file mode 100644 index 000000000..3f5982df3 --- /dev/null +++ b/core/net/ip64/ip64-eth.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef IP64_ETH_H +#define IP64_ETH_H + +#include "contiki-conf.h" + +/** + * The Ethernet address. + */ +struct ip64_eth_addr { + uint8_t addr[6]; +}; + +extern struct ip64_eth_addr ip64_eth_addr; + +void ip64_eth_addr_set(struct ip64_eth_addr *addr); + +/** + * The Ethernet header. + */ +struct ip64_eth_hdr { + struct ip64_eth_addr dest; + struct ip64_eth_addr src; + uint16_t type; +}; + +#define IP64_ETH_TYPE_ARP 0x0806 +#define IP64_ETH_TYPE_IP 0x0800 +#define IP64_ETH_TYPE_IPV6 0x86dd + + +#endif /* IP64_ETH_H */ diff --git a/core/net/ip64/ip64-interface.h b/core/net/ip64/ip64-interface.h new file mode 100644 index 000000000..0e304ed37 --- /dev/null +++ b/core/net/ip64/ip64-interface.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef IP64_INTERFACE_H +#define IP64_INTERFACE_H + +struct ip64_interface { + void (* init)(void); + int (* input)(uint8_t *packet, uint16_t packet_len); + int (* output)(uint8_t *packet, uint16_t packet_len); +}; + + +#endif /* IP64_INTERFACE_H */ diff --git a/core/net/ip64/ip64-ipv4-dhcp.c b/core/net/ip64/ip64-ipv4-dhcp.c new file mode 100644 index 000000000..6381fa179 --- /dev/null +++ b/core/net/ip64/ip64-ipv4-dhcp.c @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include "contiki.h" +#include "contiki-net.h" +#include "ip64-dhcpc.h" + +#include "ip64.h" +#include "ip64-eth.h" +#include "ip64-addr.h" + +#include + +PROCESS(ip64_ipv4_dhcp_process, "IPv4 DHCP"); + +uip_ipaddr_t uip_hostaddr; /* Needed because it is referenced by dhcpc.c */ + + +/*---------------------------------------------------------------------------*/ +void +ip64_ipv4_dhcp_init(void) +{ + printf("Starting DHCPv4\n"); + process_start(&ip64_ipv4_dhcp_process, NULL); +} +/*---------------------------------------------------------------------------*/ +PROCESS_THREAD(ip64_ipv4_dhcp_process, ev, data) +{ + PROCESS_BEGIN(); + + ip64_dhcpc_init(&ip64_eth_addr, sizeof(ip64_eth_addr)); + + printf("Inited\n"); + + ip64_dhcpc_request(); + printf("Requested\n"); + while(1) { + PROCESS_WAIT_EVENT(); + + if(ev == tcpip_event || + ev == PROCESS_EVENT_TIMER) { + ip64_dhcpc_appcall(ev, data); + } + } + + PROCESS_END(); +} +/*---------------------------------------------------------------------------*/ +void +ip64_dhcpc_configured(const struct ip64_dhcpc_state *s) +{ + uip_ip6addr_t ip6dnsaddr; + printf("DHCP Configured with %d.%d.%d.%d\n", + s->ipaddr.u8[0], s->ipaddr.u8[1], + s->ipaddr.u8[2], s->ipaddr.u8[3]); + + ip64_set_hostaddr((uip_ip4addr_t *)&s->ipaddr); + ip64_set_netmask((uip_ip4addr_t *)&s->netmask); + ip64_set_draddr((uip_ip4addr_t *)&s->default_router); + ip64_addr_4to6((uip_ip4addr_t *)&s->dnsaddr, &ip6dnsaddr); + // mdns_conf(&ip6dnsaddr); +} +/*---------------------------------------------------------------------------*/ +void +ip64_dhcpc_unconfigured(const struct ip64_dhcpc_state *s) +{ +} +/*---------------------------------------------------------------------------*/ diff --git a/core/net/ip64/ip64-ipv4-dhcp.h b/core/net/ip64/ip64-ipv4-dhcp.h new file mode 100644 index 000000000..c0ebdf52f --- /dev/null +++ b/core/net/ip64/ip64-ipv4-dhcp.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef IP64_IPV4_DHCP_H +#define IP64_IPV4_DHCP_H + +void ip64_ipv4_dhcp_init(void); + +#endif /* IP64_IPV4_DHCP_H */ diff --git a/core/net/ip64/ip64-null-driver.c b/core/net/ip64/ip64-null-driver.c new file mode 100644 index 000000000..95f2b1f72 --- /dev/null +++ b/core/net/ip64/ip64-null-driver.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include "contiki-net.h" + +#include "ip64-driver.h" +/*---------------------------------------------------------------------------*/ +static void +init(void) +{ +} +/*---------------------------------------------------------------------------*/ +static int +output(uint8_t *packet, uint16_t len) +{ + return 0; +} +/*---------------------------------------------------------------------------*/ +const struct ip64_driver ip64_null_driver = { + init, + output +}; diff --git a/core/net/ip64/ip64-null-driver.h b/core/net/ip64/ip64-null-driver.h new file mode 100644 index 000000000..2a9ad0711 --- /dev/null +++ b/core/net/ip64/ip64-null-driver.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef IP64_NULL_DRIVER_H +#define IP64_NULL_DRIVER_H + +#include "ip64-driver.h" + +extern const struct ip64_driver ip64_null_driver; + +#endif /* IP64_NULL_DRIVER_H */ diff --git a/core/net/ip64/ip64-slip-interface.c b/core/net/ip64/ip64-slip-interface.c new file mode 100644 index 000000000..dab563f51 --- /dev/null +++ b/core/net/ip64/ip64-slip-interface.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include "net/ip/uip.h" +#include "net/ipv6/uip-ds6.h" +#include "dev/slip.h" + +#include "ip64.h" + +#include +#include + +#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN]) + +#define DEBUG DEBUG_NONE +#include "net/ip/uip-debug.h" + +static uip_ipaddr_t last_sender; + +/*---------------------------------------------------------------------------*/ +void +ip64_slip_interface_input(uint8_t *packet, uint16_t len) +{ + /* Dummy definition: this function is not actually called, but must + be here to conform to the ip65-interface.h structure. */ +} +/*---------------------------------------------------------------------------*/ +static void +input_callback(void) +{ + /*PRINTF("SIN: %u\n", uip_len);*/ + if(uip_buf[0] == '!') { + PRINTF("Got configuration message of type %c\n", uip_buf[1]); + uip_len = 0; +#if 0 + if(uip_buf[1] == 'P') { + uip_ipaddr_t prefix; + /* Here we set a prefix !!! */ + memset(&prefix, 0, 16); + memcpy(&prefix, &uip_buf[2], 8); + PRINTF("Setting prefix "); + PRINT6ADDR(&prefix); + PRINTF("\n"); + set_prefix_64(&prefix); + } +#endif + } else if(uip_buf[0] == '?') { + PRINTF("Got request message of type %c\n", uip_buf[1]); + if(uip_buf[1] == 'M') { + const char *hexchar = "0123456789abcdef"; + int j; + /* this is just a test so far... just to see if it works */ + uip_buf[0] = '!'; + for(j = 0; j < 8; j++) { + uip_buf[2 + j * 2] = hexchar[uip_lladdr.addr[j] >> 4]; + uip_buf[3 + j * 2] = hexchar[uip_lladdr.addr[j] & 15]; + } + uip_len = 18; + slip_send(); + + } + uip_len = 0; + } else { + + /* Save the last sender received over SLIP to avoid bouncing the + packet back if no route is found */ + uip_ipaddr_copy(&last_sender, &UIP_IP_BUF->srcipaddr); + + uint16_t len = ip64_4to6(&uip_buf[UIP_LLH_LEN], uip_len, + ip64_packet_buffer); + if(len > 0) { + memcpy(&uip_buf[UIP_LLH_LEN], ip64_packet_buffer, len); + uip_len = len; + /* PRINTF("send len %d\n", len); */ + } else { + uip_len = 0; + } + } +} +/*---------------------------------------------------------------------------*/ +static void +init(void) +{ + PRINTF("ip64-slip-interface: init\n"); + // slip_arch_init(BAUD2UBR(115200)); + process_start(&slip_process, NULL); + slip_set_input_callback(input_callback); +} +/*---------------------------------------------------------------------------*/ +static void +output(void) +{ + int len; + + PRINTF("ip64-slip-interface: output source "); + + /* + PRINT6ADDR(&UIP_IP_BUF->srcipaddr); + PRINTF(" destination "); + PRINT6ADDR(&UIP_IP_BUF->destipaddr); + PRINTF("\n"); + */ + if(uip_ipaddr_cmp(&last_sender, &UIP_IP_BUF->srcipaddr)) { + PRINTF("ip64-interface: output, not sending bounced message\n"); + } else { + len = ip64_6to4(&uip_buf[UIP_LLH_LEN], uip_len, + ip64_packet_buffer); + PRINTF("ip64-interface: output len %d\n", len); + if(len > 0) { + memcpy(&uip_buf[UIP_LLH_LEN], ip64_packet_buffer, len); + uip_len = len; + slip_send(); + } + } +} +/*---------------------------------------------------------------------------*/ +const struct uip_fallback_interface ip64_slip_interface = { + init, output +}; +/*---------------------------------------------------------------------------*/ + + + diff --git a/core/net/ip64/ip64-slip-interface.h b/core/net/ip64/ip64-slip-interface.h new file mode 100644 index 000000000..eecb14395 --- /dev/null +++ b/core/net/ip64/ip64-slip-interface.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef IP64_SLIP_INTERFACE_H +#define IP64_SLIP_INTERFACE_H + +void ip64_slip_interface_input(uint8_t *packet, uint16_t len); + +extern const struct uip_fallback_interface ip64_slip_interface; + +#endif /* IP64_SLIP_INTERFACE_H */ diff --git a/core/net/ip64/ip64-special-ports.c b/core/net/ip64/ip64-special-ports.c new file mode 100644 index 000000000..cea1571ea --- /dev/null +++ b/core/net/ip64/ip64-special-ports.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include "ip64.h" +#include "ip64-special-ports.h" + +#ifndef IP64_SPECIAL_PORTS_CONF_ENABLE +#define EMPTY_DEFINITIONS 1 +#else +#if IP64_SPECIAL_PORTS_CONF_ENABLE == 0 +#define EMPTY_DEFINITIONS 1 +#endif /* IP64_SPECIAL_PORTS_CONF_ENABLE */ +#endif /* IP64_SPECIAL_PORTS_CONF_ENABLE */ + + + +#if EMPTY_DEFINITIONS +/*---------------------------------------------------------------------------*/ +int +ip64_special_ports_translate_incoming(uint16_t incoming_port, + uip_ip6addr_t *newaddr, + uint16_t *newport) +{ + return 0; +} +/*---------------------------------------------------------------------------*/ +int +ip64_special_ports_translate_outgoing(uint16_t incoming_port, + const uip_ip6addr_t *ip6addr, + uint16_t *newport) +{ + return 0; +} +/*---------------------------------------------------------------------------*/ +int +ip64_special_ports_incoming_is_special(uint16_t port) +{ + /* Default is to have no special ports. */ + return 0; +} +/*---------------------------------------------------------------------------*/ +int +ip64_special_ports_outgoing_is_special(uint16_t port) +{ + /* Default is to have no special ports. */ + return 0; +} +/*---------------------------------------------------------------------------*/ +#endif /* EMPTY_DEFINITIONS */ diff --git a/core/net/ip64/ip64-special-ports.h b/core/net/ip64/ip64-special-ports.h new file mode 100644 index 000000000..312a24366 --- /dev/null +++ b/core/net/ip64/ip64-special-ports.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef IP64_SPECIAL_PORTS_H +#define IP64_SPECIAL_PORTS_H + +/* The IP64 special ports module allows specific ports on the IP64 + translator to be mapped to specific address in the IPv6 + network. The module provides three function prototypes that must be + implemented by the user. + + The IP64 special ports module must be enabled by + +#define IP64_SPECIAL_PORTS_CONF_ENABLE 1 + + Otherwise, the functions are replaced by empty default definitions + in the ip64-special-ports.c module. + + Port numbers are always in network byte order. */ + + +/* Translate the special port to an IPv6 address for inbound + packets. */ +int ip64_special_ports_translate_incoming(uint16_t incoming_port, + uip_ip6addr_t *newaddr, + uint16_t *newport); +int ip64_special_ports_translate_outgoing(uint16_t incoming_port, + const uip_ip6addr_t *ip6addr, + uint16_t *newport); +/* Check if an incoming (destination) port is special. */ +int ip64_special_ports_incoming_is_special(uint16_t port); + +/* Check if an outgoing (source) port is special. */ +int ip64_special_ports_outgoing_is_special(uint16_t port); + + +#endif /* IP64_SPECIAL_PORTS_H */ diff --git a/core/net/ip64/ip64.c b/core/net/ip64/ip64.c new file mode 100644 index 000000000..f058f1d22 --- /dev/null +++ b/core/net/ip64/ip64.c @@ -0,0 +1,873 @@ +/* + * Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* The ip64 module is a translator between IPv6 and IPv4 packets. The + IPv6 packets come from an IPv6 network and are translated into a + single IPv4 host, as shown in the ASCII graphics below. The IPv6 + network typically is a low-power RF network and the IPv4 network + typically is an Ethernet. + + +----------------+ + | | + | | +------+ + | IPv6 network |---| ip64 |-- IPv4 network + | | +------+ + | | + +----------------+ + + ip64 maps all IPv6 addresses from inside the IPv6 network to its + own IPv4 address. This IPv4 address would typically have been + obtained with DHCP from the IPv4 network, but the exact way this + has been obtained is outside the scope of the ip64 module. The IPv4 + address is given to the ip64 module through the + ip64_set_ipv4_address() function. +*/ + +#include "ip64.h" +#include "ip64-addr.h" +#include "ip64-addrmap.h" +#include "ip64-conf.h" +#include "ip64-special-ports.h" +#include "ip64-eth-interface.h" +#include "ip64-slip-interface.h" + +#include "ip64-ipv4-dhcp.h" +#include "contiki-net.h" + +#include "net/ip/uip-debug.h" + +#include /* for memcpy() */ +#include /* for printf() */ + +#define DEBUG 0 + +#if DEBUG +#undef PRINTF +#define PRINTF(...) printf(__VA_ARGS__) +#else /* DEBUG */ +#define PRINTF(...) +#endif /* DEBUG */ + +struct ipv6_hdr { + uint8_t vtc; + uint8_t tcflow; + uint16_t flow; + uint8_t len[2]; + uint8_t nxthdr, hoplim; + uip_ip6addr_t srcipaddr, destipaddr; +}; + +struct ipv4_hdr { + uint8_t vhl, + tos, + len[2], + ipid[2], + ipoffset[2], + ttl, + proto; + uint16_t ipchksum; + uip_ip4addr_t srcipaddr, destipaddr; +}; + +#define EPHEMERAL_PORTRANGE 1024 + +#define IPV6_HDRLEN 40 +#define IPV4_HDRLEN 20 + +#define IP_PROTO_ICMPV4 1 +#define IP_PROTO_TCP 6 +#define IP_PROTO_UDP 17 +#define IP_PROTO_ICMPV6 58 + +#define ICMP_ECHO_REPLY 0 +#define ICMP_ECHO 8 +#define ICMP6_ECHO_REPLY 129 +#define ICMP6_ECHO 128 + +struct tcp_hdr { + uint16_t srcport; + uint16_t destport; + uint8_t seqno[4]; + uint8_t ackno[4]; + uint8_t tcpoffset; + uint8_t flags; + uint8_t wnd[2]; + uint16_t tcpchksum; + uint8_t urgp[2]; + uint8_t optdata[4]; +}; + +struct udp_hdr { + uint16_t srcport; + uint16_t destport; + uint16_t udplen; + uint16_t udpchksum; +}; + +struct icmpv4_hdr { + uint8_t type, icode; + uint16_t icmpchksum; +}; + +struct icmpv6_hdr { + uint8_t type, icode; + uint16_t icmpchksum; + uint16_t id, seqno; +}; + +#define BUFSIZE UIP_BUFSIZE + +uip_buf_t ip64_packet_buffer_aligned; +uint8_t *ip64_packet_buffer = ip64_packet_buffer_aligned.u8; + +uint16_t ip64_packet_buffer_maxlen = BUFSIZE; + +static uip_ip4addr_t ip64_hostaddr; +static uip_ip4addr_t ip64_netmask; +static uip_ip4addr_t ip64_draddr; + +static uint16_t ipid; +static uint8_t ip64_hostaddr_configured = 0; + +static uip_ip6addr_t ipv6_local_address; +static uint8_t ipv6_local_address_configured = 0; + +static uip_ip4addr_t ipv4_broadcast_addr; + +/* Lifetimes for address mappings. */ +#define SYN_LIFETIME (CLOCK_SECOND * 20) +#define RST_LIFETIME (CLOCK_SECOND * 30) +#define DEFAULT_LIFETIME (CLOCK_SECOND * 60 * 5) + +/* TCP flag defines */ +#define TCP_FIN 0x01 +#define TCP_SYN 0x02 +#define TCP_RST 0x04 + +/*---------------------------------------------------------------------------*/ +void +ip64_init(void) +{ + int i; + uint8_t state; + + uip_ipaddr(&ipv4_broadcast_addr, 255,255,255,255); + ip64_hostaddr_configured = 0; + + PRINTF("ip64_init\n"); + IP64_ETH_DRIVER.init(); +#if IP64_CONF_DHCP + ip64_ipv4_dhcp_init(); +#endif /* IP64_CONF_DHCP */ + + /* Specify an IPv6 address for local communication to the + host. We'll just pick the first one we find in our list. */ + for(i = 0; i < UIP_DS6_ADDR_NB; i++) { + state = uip_ds6_if.addr_list[i].state; + PRINTF("i %d used %d\n", i, uip_ds6_if.addr_list[i].isused); + if(uip_ds6_if.addr_list[i].isused && + (state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) { + ip64_set_ipv6_address(&uip_ds6_if.addr_list[i].ipaddr); + break; + } + } + +} +/*---------------------------------------------------------------------------*/ +void +ip64_set_hostaddr(const uip_ip4addr_t *hostaddr) +{ + ip64_hostaddr_configured = 1; + ip64_addr_copy4(&ip64_hostaddr, hostaddr); +} +/*---------------------------------------------------------------------------*/ +void +ip64_set_netmask(const uip_ip4addr_t *netmask) +{ + ip64_addr_copy4(&ip64_netmask, netmask); +} +/*---------------------------------------------------------------------------*/ +void +ip64_set_draddr(const uip_ip4addr_t *draddr) +{ + ip64_addr_copy4(&ip64_draddr, draddr); +} +/*---------------------------------------------------------------------------*/ +const uip_ip4addr_t * +ip64_get_hostaddr(void) +{ + return &ip64_hostaddr; +} +/*---------------------------------------------------------------------------*/ +const uip_ip4addr_t * +ip64_get_netmask(void) +{ + return &ip64_netmask; +} +/*---------------------------------------------------------------------------*/ +const uip_ip4addr_t * +ip64_get_draddr(void) +{ + return &ip64_draddr; +} +/*---------------------------------------------------------------------------*/ +void +ip64_set_ipv4_address(const uip_ip4addr_t *addr, const uip_ip4addr_t *netmask) +{ + ip64_set_hostaddr(addr); + ip64_set_netmask(netmask); + + PRINTF("ip64_set_ipv4_address: configuring address %d.%d.%d.%d/%d.%d.%d.%d\n", + ip64_hostaddr.u8[0], ip64_hostaddr.u8[1], + ip64_hostaddr.u8[2], ip64_hostaddr.u8[3], + ip64_netmask.u8[0], ip64_netmask.u8[1], + ip64_netmask.u8[2], ip64_netmask.u8[3]); +} +/*---------------------------------------------------------------------------*/ +void +ip64_set_ipv6_address(const uip_ip6addr_t *addr) +{ + ip64_addr_copy6(&ipv6_local_address, (const uip_ip6addr_t *)addr); + ipv6_local_address_configured = 1; +#if DEBUG + PRINTF("ip64_set_ipv6_address: configuring address "); + uip_debug_ipaddr_print(addr); + PRINTF("\n"); +#endif /* DEBUG */ +} +/*---------------------------------------------------------------------------*/ +static uint16_t +chksum(uint16_t sum, const uint8_t *data, uint16_t len) +{ + uint16_t t; + const uint8_t *dataptr; + const uint8_t *last_byte; + + dataptr = data; + last_byte = data + len - 1; + + while(dataptr < last_byte) { /* At least two more bytes */ + t = (dataptr[0] << 8) + dataptr[1]; + sum += t; + if(sum < t) { + sum++; /* carry */ + } + dataptr += 2; + } + + if(dataptr == last_byte) { + t = (dataptr[0] << 8) + 0; + sum += t; + if(sum < t) { + sum++; /* carry */ + } + } + + /* Return sum in host byte order. */ + return sum; +} +/*---------------------------------------------------------------------------*/ +static uint16_t +ipv4_checksum(struct ipv4_hdr *hdr) +{ + uint16_t sum; + + sum = chksum(0, (uint8_t *)hdr, IPV4_HDRLEN); + return (sum == 0) ? 0xffff : uip_htons(sum); +} +/*---------------------------------------------------------------------------*/ +static uint16_t +ipv4_transport_checksum(const uint8_t *packet, uint16_t len, uint8_t proto) +{ + uint16_t transport_layer_len; + uint16_t sum; + struct ipv4_hdr *v4hdr = (struct ipv4_hdr *)packet; + + transport_layer_len = len - IPV4_HDRLEN; + + /* First sum pseudoheader. */ + + if(proto != IP_PROTO_ICMPV4) { + /* IP protocol and length fields. This addition cannot carry. */ + sum = transport_layer_len + proto; + /* Sum IP source and destination addresses. */ + sum = chksum(sum, (uint8_t *)&v4hdr->srcipaddr, 2 * sizeof(uip_ip4addr_t)); + } else { + /* ping replies' checksums are calculated over the icmp-part only */ + sum = 0; + } + + /* Sum transport layer header and data. */ + sum = chksum(sum, &packet[IPV4_HDRLEN], transport_layer_len); + + return (sum == 0) ? 0xffff : uip_htons(sum); +} +/*---------------------------------------------------------------------------*/ +static uint16_t +ipv6_transport_checksum(const uint8_t *packet, uint16_t len, uint8_t proto) +{ + uint16_t transport_layer_len; + uint16_t sum; + struct ipv6_hdr *v6hdr = (struct ipv6_hdr *)packet; + + transport_layer_len = len - IPV6_HDRLEN; + + /* First sum pseudoheader. */ + + /* IP protocol and length fields. This addition cannot carry. */ + sum = transport_layer_len + proto; + /* Sum IP source and destination addresses. */ + sum = chksum(sum, (uint8_t *)&v6hdr->srcipaddr, sizeof(uip_ip6addr_t)); + sum = chksum(sum, (uint8_t *)&v6hdr->destipaddr, sizeof(uip_ip6addr_t)); + + /* Sum transport layer header and data. */ + sum = chksum(sum, &packet[IPV6_HDRLEN], transport_layer_len); + + return (sum == 0) ? 0xffff : uip_htons(sum); +} +/*---------------------------------------------------------------------------*/ +int +ip64_6to4(const uint8_t *ipv6packet, const uint16_t ipv6packet_len, + uint8_t *resultpacket) +{ + struct ipv4_hdr *v4hdr; + struct ipv6_hdr *v6hdr; + struct udp_hdr *udphdr; + struct tcp_hdr *tcphdr; + struct icmpv4_hdr *icmpv4hdr; + struct icmpv6_hdr *icmpv6hdr; + uint16_t ipv6len, ipv4len; + struct ip64_addrmap_entry *m; + + v6hdr = (struct ipv6_hdr *)ipv6packet; + v4hdr = (struct ipv4_hdr *)resultpacket; + + if((v6hdr->len[0] << 8) + v6hdr->len[1] <= ipv6packet_len) { + ipv6len = (v6hdr->len[0] << 8) + v6hdr->len[1] + IPV6_HDRLEN; + } else { + PRINTF("ip64_6to4: packet smaller than reported in IPv6 header, dropping\n"); + return 0; + } + + /* We copy the data from the IPv6 packet into the IPv4 packet. We do + not modify the data in any way. */ + memcpy(&resultpacket[IPV4_HDRLEN], + &ipv6packet[IPV6_HDRLEN], + ipv6len - IPV6_HDRLEN); + + udphdr = (struct udp_hdr *)&resultpacket[IPV4_HDRLEN]; + tcphdr = (struct tcp_hdr *)&resultpacket[IPV4_HDRLEN]; + icmpv4hdr = (struct icmpv4_hdr *)&resultpacket[IPV4_HDRLEN]; + icmpv6hdr = (struct icmpv6_hdr *)&ipv6packet[IPV6_HDRLEN]; + + /* Translate the IPv6 header into an IPv4 header. */ + + /* First the basics: the IPv4 version, header length, type of + service, and offset fields. Those are the same for all IPv4 + packets we send, regardless of the values found in the IPv6 + packet. */ + v4hdr->vhl = 0x45; + v4hdr->tos = 0; + v4hdr->ipoffset[0] = v4hdr->ipoffset[1] = 0; + + /* We assume that the IPv6 packet has a fixed size header with no + extension headers, and compute the length of the IPv4 packet and + place the resulting value in the IPv4 packet header. */ + ipv4len = ipv6len - IPV6_HDRLEN + IPV4_HDRLEN; + v4hdr->len[0] = ipv4len >> 8; + v4hdr->len[1] = ipv4len & 0xff; + + /* For simplicity, we set a unique IP id for each outgoing IPv4 + packet. */ + ipid++; + v4hdr->ipid[0] = ipid >> 8; + v4hdr->ipid[1] = ipid & 0xff; + + /* Set the IPv4 protocol. We only support TCP, UDP, and ICMP at this + point. While the IPv4 header protocol numbers are the same as the + IPv6 next header numbers, the ICMPv4 and ICMPv6 numbers are + different so we cannot simply copy the contents of the IPv6 next + header field. */ + switch(v6hdr->nxthdr) { + case IP_PROTO_TCP: + PRINTF("ip64_6to4: TCP header\n"); + v4hdr->proto = IP_PROTO_TCP; + + /* Compute and check the TCP checksum - since we're going to + recompute it ourselves, we must ensure that it was correct in + the first place. */ + if(ipv6_transport_checksum(ipv6packet, ipv6len, + IP_PROTO_TCP) != 0xffff) { + PRINTF("Bad TCP checksum, dropping packet\n"); + } + + break; + + case IP_PROTO_UDP: + PRINTF("ip64_6to4: UDP header\n"); + v4hdr->proto = IP_PROTO_UDP; + /* Compute and check the UDP checksum - since we're going to + recompute it ourselves, we must ensure that it was correct in + the first place. */ + if(ipv6_transport_checksum(ipv6packet, ipv6len, + IP_PROTO_UDP) != 0xffff) { + PRINTF("Bad UDP checksum, dropping packet\n"); + } + break; + + case IP_PROTO_ICMPV6: + PRINTF("ip64_6to4: ICMPv6 header\n"); + v4hdr->proto = IP_PROTO_ICMPV4; + /* Translate only ECHO_REPLY messages. */ + if(icmpv6hdr->type == ICMP6_ECHO_REPLY) { + icmpv4hdr->type = ICMP_ECHO_REPLY; + } else { + PRINTF("ip64_6to4: ICMPv6 mapping for type %d not implemented.\n", + icmpv6hdr->type); + return 0; + } + break; + + default: + /* We did not recognize the next header, and we do not attempt to + translate something we do not understand, so we return 0 to + indicate that no successful translation could be made. */ + PRINTF("ip64_6to4: Could not convert IPv6 next hop %d to an IPv4 protocol number.\n", + v6hdr->nxthdr); + return 0; + } + + /* We set the IPv4 ttl value to the hoplim number from the IPv6 + header. This means that information about the IPv6 topology is + transported into to the IPv4 network. */ + v4hdr->ttl = v6hdr->hoplim; + + /* We next convert the destination address. We make this conversion + with the ip64_addr_6to4() function. If the conversion + fails, ip64_addr_6to4() returns 0. If so, we also return 0 to + indicate failure. */ + if(ip64_addr_6to4(&v6hdr->destipaddr, + &v4hdr->destipaddr) == 0) { +#if DEBUG + PRINTF("ip64_6to4: Could not convert IPv6 destination address.\n"); + uip_debug_ipaddr_print(&v6hdr->destipaddr); + PRINTF("\n"); +#endif /* DEBUG */ + return 0; + } + + /* We set the source address in the IPv4 packet to be the IPv4 + address that we have been configured with through the + ip64_set_ipv4_address() function. Only let broadcasts through. */ + if(!ip64_hostaddr_configured && + !uip_ip4addr_cmp(&v4hdr->destipaddr, &ipv4_broadcast_addr)) { + PRINTF("ip64_6to4: no IPv4 address configured.\n"); + return 0; + } + ip64_addr_copy4(&v4hdr->srcipaddr, &ip64_hostaddr); + + + /* Next we update the transport layer header. This must be updated + in two ways: the source port number is changed and the transport + layer checksum must be recomputed. The reason why we change the + source port number is so that we can remember what IPv6 address + this packet came from, in case the packet will result in a reply + from the host on the IPv4 network. If a reply would be sent, it + would be sent to the port number that we chose, and we will be + able to map this back to the IPv6 address of the original sender + of the packet. + */ + + /* We check to see if we already have an existing IP address mapping + for this connection. If not, we create a new one. */ + if((v4hdr->proto == IP_PROTO_UDP || v4hdr->proto == IP_PROTO_TCP)) { + + if(ip64_special_ports_outgoing_is_special(uip_ntohs(udphdr->srcport))) { + uint16_t newport; + if(ip64_special_ports_translate_outgoing(uip_ntohs(udphdr->srcport), + &v6hdr->srcipaddr, + &newport)) { + udphdr->srcport = uip_htons(newport); + } + } else if(uip_ntohs(udphdr->srcport) >= EPHEMERAL_PORTRANGE) { + m = ip64_addrmap_lookup(&v6hdr->srcipaddr, + uip_ntohs(udphdr->srcport), + &v4hdr->destipaddr, + uip_ntohs(udphdr->destport), + v4hdr->proto); + if(m == NULL) { + PRINTF("Lookup failed\n"); + m = ip64_addrmap_create(&v6hdr->srcipaddr, + uip_ntohs(udphdr->srcport), + &v4hdr->destipaddr, + uip_ntohs(udphdr->destport), + v4hdr->proto); + if(m == NULL) { + PRINTF("Could not create new map\n"); + return 0; + } else { + PRINTF("Could create new local port %d\n", m->mapped_port); + } + } else { + PRINTF("Lookup: found local port %d (%d)\n", m->mapped_port, + uip_htons(m->mapped_port)); + } + + /* Update the lifetime of the address mapping. We need to be + frugal with address mapping table entries, so we assign + different lifetimes depending on the type of packet we see. + + For TCP connections, we don't want to have a lot of failed + connection attmpts lingering around, so we assign mappings + with TCP SYN segments a short lifetime. If we see a RST + segment, this indicates that the connection might be dead, + and we'll assign a shorter lifetime. + + For UDP packets and for non-SYN/non-RST segments, we assign + the default lifetime. */ + if(v4hdr->proto == IP_PROTO_TCP) { + if((tcphdr->flags & TCP_SYN)) { + ip64_addrmap_set_lifetime(m, SYN_LIFETIME); + } else if((tcphdr->flags & TCP_RST)) { + ip64_addrmap_set_lifetime(m, RST_LIFETIME); + } else { + ip64_addrmap_set_lifetime(m, DEFAULT_LIFETIME); + } + + /* Also check if we see a FIN segment. If so, we'll mark the + address mapping as being candidate for recycling. Same for + RST segments. */ + if((tcphdr->flags & TCP_FIN) || + (tcphdr->flags & TCP_RST)) { + ip64_addrmap_set_recycleble(m); + } + } else { + ip64_addrmap_set_lifetime(m, DEFAULT_LIFETIME); + + /* Treat DNS requests specially: since the are one-shot, we + mark them as recyclable. */ + if(udphdr->destport == UIP_HTONS(53)) { + ip64_addrmap_set_recycleble(m); + } + } + + /* Set the source port of the packet to be the mapped port + number. */ + udphdr->srcport = uip_htons(m->mapped_port); + } + } + + /* The IPv4 header is now complete, so we can compute the IPv4 + header checksum. */ + v4hdr->ipchksum = 0; + v4hdr->ipchksum = ~(ipv4_checksum(v4hdr)); + + + + /* The checksum is in different places in the different protocol + headers, so we need to be sure that we update the correct + field. */ + switch(v4hdr->proto) { + case IP_PROTO_TCP: + tcphdr->tcpchksum = 0; + tcphdr->tcpchksum = ~(ipv4_transport_checksum(resultpacket, ipv4len, + IP_PROTO_TCP)); + break; + case IP_PROTO_UDP: + udphdr->udpchksum = 0; + udphdr->udpchksum = ~(ipv4_transport_checksum(resultpacket, ipv4len, + IP_PROTO_UDP)); + if(udphdr->udpchksum == 0) { + udphdr->udpchksum = 0xffff; + } + break; + case IP_PROTO_ICMPV4: + icmpv4hdr->icmpchksum = 0; + icmpv4hdr->icmpchksum = ~(ipv4_transport_checksum(resultpacket, ipv4len, + IP_PROTO_ICMPV4)); + break; + + default: + PRINTF("ip64_6to4: transport protocol %d not implemented\n", v4hdr->proto); + return 0; + } + + /* Finally, we return the length of the resulting IPv4 packet. */ + PRINTF("ip64_6to4: ipv4len %d\n", ipv4len); + return ipv4len; +} +/*---------------------------------------------------------------------------*/ +int +ip64_4to6(const uint8_t *ipv4packet, const uint16_t ipv4packet_len, + uint8_t *resultpacket) +{ + struct ipv4_hdr *v4hdr; + struct ipv6_hdr *v6hdr; + struct udp_hdr *udphdr; + struct tcp_hdr *tcphdr; + struct icmpv4_hdr *icmpv4hdr; + struct icmpv6_hdr *icmpv6hdr; + uint16_t ipv4len, ipv6len, ipv6_packet_len; + struct ip64_addrmap_entry *m; + + v6hdr = (struct ipv6_hdr *)resultpacket; + v4hdr = (struct ipv4_hdr *)ipv4packet; + + if((v4hdr->len[0] << 8) + v4hdr->len[1] <= ipv4packet_len) { + ipv4len = (v4hdr->len[0] << 8) + v4hdr->len[1]; + } else { + PRINTF("ip64_4to6: packet smaller than reported in IPv4 header, dropping\n"); + return 0; + } + + if(ipv4len <= IPV4_HDRLEN) { + return 0; + } + + /* Make sure that the resulting packet fits in the ip64 packet + buffer. If not, we drop it. */ + if(ipv4len - IPV4_HDRLEN + IPV6_HDRLEN > BUFSIZE) { + PRINTF("ip64_4to6: packet too big to fit in buffer, dropping\n"); + return 0; + } + /* We copy the data from the IPv4 packet into the IPv6 packet. */ + memcpy(&resultpacket[IPV6_HDRLEN], + &ipv4packet[IPV4_HDRLEN], + ipv4len - IPV4_HDRLEN); + + udphdr = (struct udp_hdr *)&resultpacket[IPV6_HDRLEN]; + tcphdr = (struct tcp_hdr *)&resultpacket[IPV6_HDRLEN]; + icmpv4hdr = (struct icmpv4_hdr *)&ipv4packet[IPV4_HDRLEN]; + icmpv6hdr = (struct icmpv6_hdr *)&resultpacket[IPV6_HDRLEN]; + + ipv6len = ipv4len - IPV4_HDRLEN + IPV6_HDRLEN; + ipv6_packet_len = ipv6len - IPV6_HDRLEN; + + /* Translate the IPv4 header into an IPv6 header. */ + + /* We first fill in the simple fields: IP header version, traffic + class and flow label, and length fields. */ + v6hdr->vtc = 0x60; + v6hdr->tcflow = 0; + v6hdr->flow = 0; + v6hdr->len[0] = ipv6_packet_len >> 8; + v6hdr->len[1] = ipv6_packet_len & 0xff; + + /* We use the IPv4 TTL field as the IPv6 hop limit field. */ + v6hdr->hoplim = v4hdr->ttl; + + + /* We now translate the IPv4 source and destination addresses to + IPv6 source and destination addresses. We translate the IPv4 + source address into an IPv6-encoded IPv4 address. The IPv4 + destination address will be the address with which we have + previously been configured, through the ip64_set_ipv4_address() + function. We use the mapping table to look up the new IPv6 + destination address. As we assume that the IPv4 packet is a + response to a previously sent IPv6 packet, we should have a + mapping between the (protocol, destport, srcport, srcaddress) + tuple. If not, we'll return 0 to indicate that we failed to + translate the packet. */ + if(ip64_addr_4to6(&v4hdr->srcipaddr, &v6hdr->srcipaddr) == 0) { + PRINTF("ip64_packet_4to6: failed to convert source IP address\n"); + return 0; + } + + /* For the next header field, we simply use the IPv4 protocol + field. We only support UDP and TCP packets. */ + switch(v4hdr->proto) { + case IP_PROTO_UDP: + v6hdr->nxthdr = IP_PROTO_UDP; + break; + + case IP_PROTO_TCP: + v6hdr->nxthdr = IP_PROTO_TCP; + break; + + case IP_PROTO_ICMPV4: + /* Allow only ICMPv4 ECHO_REQUESTS (ping packets) through to the + local IPv6 host. */ + if(icmpv4hdr->type == ICMP_ECHO) { + PRINTF("ip64_4to6: translating ICMPv4 ECHO packet\n"); + v6hdr->nxthdr = IP_PROTO_ICMPV6; + icmpv6hdr->type = ICMP6_ECHO; + ip64_addr_copy6(&v6hdr->destipaddr, &ipv6_local_address); + } else { + PRINTF("ip64_packet_4to6: ICMPv4 packet type %d not supported\n", + icmpv4hdr->type); + return 0; + } + break; + + default: + /* For protocol types that we do not support, we return 0 to + indicate that we failed to translate the packet to an IPv6 + packet. */ + PRINTF("ip64_packet_4to6: protocol type %d not supported\n", + v4hdr->proto); + return 0; + } + + /* Translate IPv4 broadcasts to IPv6 all-nodes multicasts. */ + if(uip_ip4addr_cmp(&v4hdr->destipaddr, &ipv4_broadcast_addr) || + (uip_ipaddr_maskcmp(&v4hdr->destipaddr, &ip64_hostaddr, + &ip64_netmask) && + ((v4hdr->destipaddr.u16[0] & (~ip64_netmask.u16[0])) == + (ipv4_broadcast_addr.u16[0] & (~ip64_netmask.u16[0]))) && + ((v4hdr->destipaddr.u16[1] & (~ip64_netmask.u16[1])) == + (ipv4_broadcast_addr.u16[1] & (~ip64_netmask.u16[1]))))) { + uip_create_linklocal_allnodes_mcast(&v6hdr->destipaddr); + } else { + + if(!ip64_hostaddr_configured) { + PRINTF("ip64_packet_4to6: no local IPv4 address configured, dropping incoming packet.\n"); + return 0; + } + + if(!uip_ip4addr_cmp(&v4hdr->destipaddr, &ip64_hostaddr)) { + PRINTF("ip64_packet_4to6: the IPv4 destination address %d.%d.%d.%d did not match our IPv4 address %d.%d.%d.%d\n", + uip_ipaddr_to_quad(&v4hdr->destipaddr), + uip_ipaddr_to_quad(&ip64_hostaddr)); + return 0; + } + + + /* Now we translate the transport layer port numbers. We assume that + the IPv4 packet is a response to a packet that has previously + been translated from IPv6 to IPv4. If this is the case, the tuple + (protocol, destport, srcport, srcaddress) corresponds to an address/port + pair in our mapping table. If we do not find a mapping, we return + 0 to indicate that we could not translate the IPv4 packet to an + IPv6 packet. */ + + /* XXX treat a few ports differently: those ports should be let + through to the local host. For those ports, we set up an address + mapping that ensures that the local port number is retained. */ + + if((v4hdr->proto == IP_PROTO_TCP || v4hdr->proto == IP_PROTO_UDP)) { + if(uip_htons(tcphdr->destport) < EPHEMERAL_PORTRANGE) { + /* This packet should go to the local host. */ + PRINTF("Port is in the non-ephemeral port range %d (%d)\n", + tcphdr->destport, uip_htons(tcphdr->destport)); + ip64_addr_copy6(&v6hdr->destipaddr, &ipv6_local_address); + } else if(ip64_special_ports_incoming_is_special(uip_htons(tcphdr->destport))) { + uip_ip6addr_t newip6addr; + uint16_t newport; + PRINTF("ip64 port %d (%d) is special, treating it differently\n", + tcphdr->destport, uip_htons(tcphdr->destport)); + if(ip64_special_ports_translate_incoming(uip_htons(tcphdr->destport), + &newip6addr, &newport)) { + ip64_addr_copy6(&v6hdr->destipaddr, &newip6addr); + tcphdr->destport = uip_htons(newport); + PRINTF("New port %d (%d)\n", + tcphdr->destport, uip_htons(tcphdr->destport)); + } else { + ip64_addr_copy6(&v6hdr->destipaddr, &ipv6_local_address); + PRINTF("No new port\n"); + } + } else { + /* The TCP or UDP port numbers were not non-ephemeral and not + special, so we map the port number according to the address + mapping table. */ + + m = ip64_addrmap_lookup_port(uip_ntohs(udphdr->destport), + v4hdr->proto); + if(m == NULL) { + PRINTF("Inbound lookup failed\n"); + return 0; + } else { + PRINTF("Inbound lookup did not fail\n"); + } + ip64_addr_copy6(&v6hdr->destipaddr, &m->ip6addr); + udphdr->destport = uip_htons(m->ip6port); + } + } + } + + /* The checksum is in different places in the different protocol + headers, so we need to be sure that we update the correct + field. */ + switch(v6hdr->nxthdr) { + case IP_PROTO_TCP: + tcphdr->tcpchksum = 0; + tcphdr->tcpchksum = ~(ipv6_transport_checksum(resultpacket, + ipv6len, + IP_PROTO_TCP)); + break; + case IP_PROTO_UDP: + udphdr->udpchksum = 0; + udphdr->udpchksum = ~(ipv6_transport_checksum(resultpacket, + ipv6len, + IP_PROTO_UDP)); + if(udphdr->udpchksum == 0) { + udphdr->udpchksum = 0xffff; + } + break; + + case IP_PROTO_ICMPV6: + icmpv6hdr->icmpchksum = 0; + icmpv6hdr->icmpchksum = ~(ipv6_transport_checksum(resultpacket, + ipv6len, + IP_PROTO_ICMPV6)); + break; + default: + PRINTF("ip64_4to6: transport protocol %d not implemented\n", v4hdr->proto); + return 0; + } + + /* Finally, we return the length of the resulting IPv6 packet. */ + PRINTF("ip64_4to6: ipv6len %d\n", ipv6len); + return ipv6len; +} +/*---------------------------------------------------------------------------*/ +int +ip64_hostaddr_is_configured(void) +{ + return ip64_hostaddr_configured; +} +/*---------------------------------------------------------------------------*/ +static void +interface_init(void) +{ + IP64_CONF_UIP_FALLBACK_INTERFACE.init(); +} +/*---------------------------------------------------------------------------*/ +static void +interface_output(void) +{ + PRINTF("ip64: interface_output len %d\n", uip_len); + IP64_CONF_UIP_FALLBACK_INTERFACE.output(); +} +/*---------------------------------------------------------------------------*/ +const struct uip_fallback_interface ip64_uip_fallback_interface = { + interface_init, interface_output +}; + diff --git a/core/net/ip64/ip64.h b/core/net/ip64/ip64.h new file mode 100644 index 000000000..58cda4511 --- /dev/null +++ b/core/net/ip64/ip64.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef IP64_H +#define IP64_H + +#include "net/ip/uip.h" + +void ip64_init(void); +int ip64_6to4(const uint8_t *ipv6packet, const uint16_t ipv6len, + uint8_t *resultpacket); +int ip64_4to6(const uint8_t *ipv4packet, const uint16_t ipv4len, + uint8_t *resultpacket); + +void ip64_set_ipv4_address(const uip_ip4addr_t *ipv4addr, + const uip_ip4addr_t *netmask); +void ip64_set_ipv6_address(const uip_ip6addr_t *ipv6addr); + +const uip_ip4addr_t *ip64_get_hostaddr(void); +const uip_ip4addr_t *ip64_get_netmask(void); +const uip_ip4addr_t *ip64_get_draddr(void); + +void ip64_set_hostaddr(const uip_ip4addr_t *hostaddr); +void ip64_set_netmask(const uip_ip4addr_t *netmask); +void ip64_set_draddr(const uip_ip4addr_t *draddr); + +int ip64_hostaddr_is_configured(void); + +extern uint8_t *ip64_packet_buffer; +extern uint16_t ip64_packet_buffer_maxlen; + +#include "ip64-conf.h" + +#ifndef IP64_CONF_ETH_DRIVER +#error IP64_CONF_ETH_DRIVER must be #defined in ip64-conf.h +#else /* IP64_CONF_ETH_DRIVER */ +#define IP64_ETH_DRIVER IP64_CONF_ETH_DRIVER +#endif /* IP64_CONF_ETH_DRIVER */ + +#ifndef IP64_CONF_INPUT +#error IP64_CONF_INPUT must be #defined in ip64-conf.h +#else /* IP64_CONF_INPUT */ +#define IP64_INPUT IP64_CONF_INPUT +#endif /* IP64_CONF_INPUT */ + + + +#endif /* IP64_H */ + From 49cb87025e92bfdeb09f24fdec557805be69bdd7 Mon Sep 17 00:00:00 2001 From: Adam Dunkels Date: Sun, 14 Sep 2014 21:26:33 +0200 Subject: [PATCH 2/2] README file for the IP64 module --- core/net/ip64/README.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 core/net/ip64/README.md diff --git a/core/net/ip64/README.md b/core/net/ip64/README.md new file mode 100644 index 000000000..8f2607337 --- /dev/null +++ b/core/net/ip64/README.md @@ -0,0 +1,29 @@ +The `ip64` module lets an IPv6 Contiki network be connected to an IPv4 +network without any additional configuration or outside software. The +`ip64` module runs on the RPL root node and translates outgoing IPv6 +packets into IPv4 packets nd incoming IPv4 packets to IPv6 packets. + +The `ip64` module uses stateful NAT64 (RFC6164) to do the packet +translation and DNS64 (RFC6147) to catch DNS requests for IPv6 +addresses, turn them into requests for IPv4 addresses, and turn the +replies into responses for IPv6 addresses. This allows devices on the +inside IPv6 network to connect to named servers on the outside IPv4 +network. + +The `ip64` module hooks into the IPv6 stack via a fallback +interface. Any packet that can not be routed into the local RPL mesh +will be sent over the fallback interface, where `ip64` picks it up, +translates it into an IPv4 packet, and sends it over its outgoing +interface. + +In addition to providing NAT64 and DNS64 services, the `ip64` module +also performs DHCPv4 to request IPv4 address for devices connected to +a medium such as Ethernet. The `ip64` module also performs ARP +processing to communicate over the Ethernet. + +The `ip64` module uses a configuration file called `ip64-conf.h` that +specifies what device to use for the IPv4 network. This file is +intended to be placed in the platform directory. An example +configuration file called `ip64-conf-example.h` is provided in this +directory. +