mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
05ebad4380
So far the entry was looked up, but ignored in the case where the packet has to be forwarded.
792 lines
22 KiB
C
792 lines
22 KiB
C
/**
|
|
* IPv6 implementation
|
|
*
|
|
* Copyright (C) 2013 INRIA.
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU Lesser General
|
|
* Public License. See the file LICENSE in the top level directory for more
|
|
* details.
|
|
*
|
|
* @ingroup sixlowpan
|
|
* @{
|
|
* @file sixlowip.c
|
|
* @brief 6lowpan IP layer functions
|
|
* @author Stephan Zeisberg <zeisberg@mi.fu-berlin.de>
|
|
* @author Martin Lenders <mlenders@inf.fu-berlin.de>
|
|
* @author Eric Engel <eric.engel@fu-berlin.de>
|
|
* @author Oliver Gesch <oliver.gesch@googlemail.com>
|
|
* @}
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#include "vtimer.h"
|
|
#include "mutex.h"
|
|
#include "msg.h"
|
|
#include "net_help.h"
|
|
#include "net_if.h"
|
|
#include "sixlowpan/mac.h"
|
|
|
|
#include "ip.h"
|
|
#include "icmp.h"
|
|
#include "lowpan.h"
|
|
|
|
#include "net_help.h"
|
|
|
|
#define ENABLE_DEBUG (0)
|
|
#if ENABLE_DEBUG
|
|
#define DEBUG_ENABLED
|
|
char addr_str[IPV6_MAX_ADDR_STR_LEN];
|
|
#endif
|
|
#include "debug.h"
|
|
|
|
#define IP_PKT_RECV_BUF_SIZE (64)
|
|
#define LLHDR_IPV6HDR_LEN (LL_HDR_LEN + IPV6_HDR_LEN)
|
|
#define IPV6_NET_IF_ADDR_BUFFER_LEN (NET_IF_MAX * IPV6_NET_IF_ADDR_LIST_LEN)
|
|
|
|
uint8_t ip_send_buffer[BUFFER_SIZE];
|
|
uint8_t buffer[BUFFER_SIZE];
|
|
msg_t ip_msg_queue[IP_PKT_RECV_BUF_SIZE];
|
|
ipv6_hdr_t *ipv6_buf;
|
|
icmpv6_hdr_t *icmp_buf;
|
|
uint8_t *nextheader;
|
|
|
|
int udp_packet_handler_pid = 0;
|
|
int tcp_packet_handler_pid = 0;
|
|
int rpl_process_pid = 0;
|
|
ipv6_addr_t *(*ip_get_next_hop)(ipv6_addr_t *) = 0;
|
|
|
|
static ipv6_net_if_ext_t ipv6_net_if_ext[NET_IF_MAX];
|
|
static ipv6_net_if_addr_t ipv6_net_if_addr_buffer[IPV6_NET_IF_ADDR_BUFFER_LEN];
|
|
static ipv6_addr_t ipv6_addr_buffer[IPV6_NET_IF_ADDR_BUFFER_LEN];
|
|
static uint8_t ipv6_net_if_addr_buffer_count = 0;
|
|
|
|
static uint8_t default_hop_limit = MULTIHOP_HOPLIMIT;
|
|
|
|
/* registered upper layer threads */
|
|
int sixlowip_reg[SIXLOWIP_MAX_REGISTERED];
|
|
|
|
int ipv6_send_packet(ipv6_hdr_t *packet)
|
|
{
|
|
uint16_t length = IPV6_HDR_LEN + NTOHS(packet->length);
|
|
ndp_neighbor_cache_t *nce;
|
|
|
|
ipv6_net_if_get_best_src_addr(&packet->srcaddr, &packet->destaddr);
|
|
|
|
if (!ipv6_addr_is_multicast(&packet->destaddr) &&
|
|
ndp_addr_is_on_link(&packet->destaddr)) {
|
|
/* not multicast, on-link */
|
|
nce = ndp_get_ll_address(&packet->destaddr);
|
|
|
|
if (nce == NULL || sixlowpan_lowpan_sendto(nce->if_id, &nce->lladdr,
|
|
nce->lladdr_len,
|
|
(uint8_t *)packet,
|
|
length) < 0) {
|
|
/* XXX: this is wrong, but until ND does not work correctly,
|
|
* this is the only way (aka the old way)*/
|
|
uint16_t raddr = NTOHS(packet->destaddr.uint16[7]);
|
|
sixlowpan_lowpan_sendto(0, &raddr, 2, (uint8_t *)packet, length);
|
|
/* return -1; */
|
|
}
|
|
|
|
return length;
|
|
}
|
|
else {
|
|
/* see if dest should be routed to a different next hop */
|
|
if (ipv6_addr_is_multicast(&packet->destaddr)) {
|
|
/* if_id will be ignored */
|
|
uint16_t addr = 0xffff;
|
|
return sixlowpan_lowpan_sendto(0, &addr, 2, (uint8_t *)packet,
|
|
length);
|
|
}
|
|
|
|
if (ip_get_next_hop == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
ipv6_addr_t *dest = ip_get_next_hop(&packet->destaddr);
|
|
|
|
if (dest == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
nce = ndp_get_ll_address(dest);
|
|
|
|
if (nce == NULL || sixlowpan_lowpan_sendto(nce->if_id, &nce->lladdr,
|
|
nce->lladdr_len,
|
|
(uint8_t *)packet, length) < 0) {
|
|
/* XXX: this is wrong, but until ND does not work correctly,
|
|
* this is the only way (aka the old way)*/
|
|
uint16_t raddr = dest->uint16[7];
|
|
sixlowpan_lowpan_sendto(0, &raddr, 2, (uint8_t *)packet, length);
|
|
/* return -1; */
|
|
}
|
|
|
|
return length;
|
|
}
|
|
}
|
|
|
|
ipv6_hdr_t *ipv6_get_buf_send(void)
|
|
{
|
|
return ((ipv6_hdr_t *) &ip_send_buffer[LL_HDR_LEN]);
|
|
}
|
|
|
|
uint8_t *get_payload_buf_send(uint8_t ext_len)
|
|
{
|
|
return &(ip_send_buffer[LLHDR_IPV6HDR_LEN + ext_len]);
|
|
}
|
|
|
|
ipv6_hdr_t *ipv6_get_buf(void)
|
|
{
|
|
return ((ipv6_hdr_t *) &buffer[LL_HDR_LEN]);
|
|
}
|
|
|
|
icmpv6_hdr_t *get_icmpv6_buf(uint8_t ext_len)
|
|
{
|
|
return ((icmpv6_hdr_t *) &buffer[LLHDR_IPV6HDR_LEN + ext_len]);
|
|
}
|
|
|
|
uint8_t *get_payload_buf(uint8_t ext_len)
|
|
{
|
|
return &(buffer[LLHDR_IPV6HDR_LEN + ext_len]);
|
|
}
|
|
|
|
int ipv6_sendto(const ipv6_addr_t *dest, uint8_t next_header,
|
|
const uint8_t *payload, uint16_t payload_length)
|
|
{
|
|
uint8_t *p_ptr;
|
|
|
|
if (next_header == IPV6_PROTO_NUM_TCP) {
|
|
p_ptr = get_payload_buf_send(ipv6_ext_hdr_len);
|
|
ipv6_buf = ipv6_get_buf_send();
|
|
}
|
|
else {
|
|
ipv6_buf = ipv6_get_buf();
|
|
p_ptr = get_payload_buf(ipv6_ext_hdr_len);
|
|
}
|
|
|
|
ipv6_buf->version_trafficclass = IPV6_VER;
|
|
ipv6_buf->trafficclass_flowlabel = 0;
|
|
ipv6_buf->flowlabel = 0;
|
|
ipv6_buf->nextheader = next_header;
|
|
ipv6_buf->hoplimit = MULTIHOP_HOPLIMIT;
|
|
ipv6_buf->length = HTONS(payload_length);
|
|
|
|
memcpy(&(ipv6_buf->destaddr), dest, 16);
|
|
|
|
memcpy(p_ptr, payload, payload_length);
|
|
|
|
return ipv6_send_packet(ipv6_buf);
|
|
}
|
|
|
|
void ipv6_set_default_hop_limit(uint8_t hop_limit)
|
|
{
|
|
default_hop_limit = hop_limit;
|
|
}
|
|
|
|
uint8_t ipv6_get_default_hop_limit(void)
|
|
{
|
|
return default_hop_limit;
|
|
}
|
|
|
|
/* Register an upper layer thread */
|
|
uint8_t ipv6_register_packet_handler(int pid)
|
|
{
|
|
uint8_t i;
|
|
|
|
for (i = 0; ((i < SIXLOWIP_MAX_REGISTERED) && (sixlowip_reg[i] != pid) &&
|
|
(sixlowip_reg[i] != 0)); i++) {
|
|
;
|
|
}
|
|
|
|
if (i >= SIXLOWIP_MAX_REGISTERED) {
|
|
return ENOMEM;
|
|
}
|
|
else {
|
|
sixlowip_reg[i] = pid;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
int icmpv6_demultiplex(const icmpv6_hdr_t *hdr)
|
|
{
|
|
switch (hdr->type) {
|
|
case (ICMPV6_TYPE_ECHO_REQUEST): {
|
|
DEBUG("INFO: packet type: icmp echo request\n");
|
|
/* processing echo request */
|
|
recv_echo_req();
|
|
break;
|
|
}
|
|
|
|
case (ICMPV6_TYPE_ECHO_REPLY): {
|
|
DEBUG("INFO: packet type: icmp echo reply\n");
|
|
/* processing echo reply */
|
|
recv_echo_repl();
|
|
break;
|
|
}
|
|
|
|
case (ICMPV6_TYPE_ROUTER_SOL): {
|
|
DEBUG("INFO: packet type: icmp router solicitation\n");
|
|
/* processing router solicitation */
|
|
recv_rtr_sol();
|
|
/* init solicited router advertisment*/
|
|
break;
|
|
}
|
|
|
|
case (ICMPV6_TYPE_ROUTER_ADV): {
|
|
DEBUG("INFO: packet type: icmp router advertisment\n");
|
|
/* processing router advertisment */
|
|
recv_rtr_adv();
|
|
/* init neighbor solicitation */
|
|
break;
|
|
}
|
|
|
|
case (ICMPV6_TYPE_NEIGHBOR_SOL): {
|
|
DEBUG("INFO: packet type: icmp neighbor solicitation\n");
|
|
recv_nbr_sol();
|
|
break;
|
|
}
|
|
|
|
case (ICMPV6_TYPE_NEIGHBOR_ADV): {
|
|
DEBUG("INFO: packet type: icmp neighbor advertisment\n");
|
|
recv_nbr_adv();
|
|
break;
|
|
}
|
|
|
|
case (ICMPV6_TYPE_RPL_CONTROL): {
|
|
DEBUG("INFO: packet type: RPL message\n");
|
|
|
|
if (rpl_process_pid != 0) {
|
|
msg_t m_send;
|
|
m_send.content.ptr = (char *) &hdr->code;
|
|
msg_send(&m_send, rpl_process_pid, 1);
|
|
}
|
|
else {
|
|
DEBUG("INFO: no RPL handler registered\n");
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
uint8_t ipv6_get_addr_match(const ipv6_addr_t *src,
|
|
const ipv6_addr_t *dst)
|
|
{
|
|
uint8_t val = 0, xor;
|
|
|
|
for (int i = 0; i < 16; i++) {
|
|
/* if bytes are equal add 8 */
|
|
if (src->uint8[i] == dst->uint8[i]) {
|
|
val += 8;
|
|
}
|
|
else {
|
|
xor = src->uint8[i] ^ dst->uint8[i];
|
|
|
|
/* while bits from byte equal add 1 */
|
|
for (int j = 0; j < 8; j++) {
|
|
if ((xor & 0x80) == 0) {
|
|
val++;
|
|
xor = xor << 1;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return val;
|
|
}
|
|
|
|
int is_our_address(ipv6_addr_t *addr)
|
|
{
|
|
ipv6_net_if_ext_t *net_if_ext;
|
|
ipv6_net_if_addr_t *myaddr;
|
|
uint8_t prefix, suffix;
|
|
int if_id = -1;
|
|
|
|
while ((if_id = net_if_iter_interfaces(if_id)) >= 0) {
|
|
net_if_ext = ipv6_net_if_get_ext(if_id);
|
|
myaddr = NULL;
|
|
prefix = net_if_ext->prefix / 8;
|
|
suffix = IPV6_ADDR_LEN - prefix;
|
|
|
|
while ((myaddr = (ipv6_net_if_addr_t *)net_if_iter_addresses(if_id,
|
|
(net_if_addr_t **) &myaddr)) != NULL) {
|
|
if ((ipv6_get_addr_match(myaddr->addr_data, addr) >= net_if_ext->prefix) &&
|
|
(memcmp(&addr->uint8[prefix], &myaddr->addr_data->uint8[prefix], suffix) == 0)) {
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void ipv6_process(void)
|
|
{
|
|
msg_t m_recv_lowpan, m_send_lowpan;
|
|
msg_t m_recv, m_send;
|
|
uint8_t i;
|
|
uint16_t packet_length;
|
|
|
|
msg_init_queue(ip_msg_queue, IP_PKT_RECV_BUF_SIZE);
|
|
|
|
while (1) {
|
|
msg_receive(&m_recv_lowpan);
|
|
|
|
ipv6_buf = (ipv6_hdr_t *)m_recv_lowpan.content.ptr;
|
|
|
|
/* identifiy packet */
|
|
nextheader = &ipv6_buf->nextheader;
|
|
|
|
for (i = 0; i < SIXLOWIP_MAX_REGISTERED; i++) {
|
|
if (sixlowip_reg[i]) {
|
|
msg_t m_send;
|
|
m_send.type = IPV6_PACKET_RECEIVED;
|
|
m_send.content.ptr = (char *) ipv6_buf;
|
|
msg_send(&m_send, sixlowip_reg[i], 1);
|
|
}
|
|
}
|
|
|
|
/* destination is our address */
|
|
if (is_our_address(&ipv6_buf->destaddr)) {
|
|
switch (*nextheader) {
|
|
case (IPV6_PROTO_NUM_ICMPV6): {
|
|
icmp_buf = get_icmpv6_buf(ipv6_ext_hdr_len);
|
|
|
|
/* checksum test*/
|
|
if (ipv6_csum(ipv6_buf, (uint8_t *) icmp_buf, NTOHS(ipv6_buf->length),
|
|
IPV6_PROTO_NUM_ICMPV6) != 0xffff) {
|
|
DEBUG("ERROR: wrong checksum\n");
|
|
}
|
|
|
|
icmpv6_demultiplex(icmp_buf);
|
|
break;
|
|
}
|
|
|
|
case (IPV6_PROTO_NUM_TCP): {
|
|
if (tcp_packet_handler_pid != 0) {
|
|
m_send.content.ptr = (char *) ipv6_buf;
|
|
msg_send_receive(&m_send, &m_recv, tcp_packet_handler_pid);
|
|
}
|
|
else {
|
|
DEBUG("INFO: No TCP handler registered.\n");
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case (IPV6_PROTO_NUM_UDP): {
|
|
if (udp_packet_handler_pid != 0) {
|
|
m_send.content.ptr = (char *) ipv6_buf;
|
|
msg_send_receive(&m_send, &m_recv, udp_packet_handler_pid);
|
|
}
|
|
else {
|
|
DEBUG("INFO: No UDP handler registered.\n");
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case (IPV6_PROTO_NUM_NONE): {
|
|
DEBUG("INFO: Packet with no Header following the IPv6 Header received.\n");
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
/* destination is foreign address */
|
|
else {
|
|
packet_length = IPV6_HDR_LEN + NTOHS(ipv6_buf->length);
|
|
ndp_neighbor_cache_t *nce;
|
|
|
|
ipv6_addr_t *dest;
|
|
|
|
if (ip_get_next_hop == NULL) {
|
|
dest = &ipv6_buf->destaddr;
|
|
}
|
|
else {
|
|
dest = ip_get_next_hop(&ipv6_buf->destaddr);
|
|
}
|
|
|
|
if ((dest == NULL) || ((--ipv6_buf->hoplimit) == 0)) {
|
|
continue;
|
|
}
|
|
|
|
nce = ndp_get_ll_address(dest);
|
|
|
|
/* copy received packet to send buffer */
|
|
memcpy(ipv6_get_buf_send(), ipv6_get_buf(), packet_length);
|
|
|
|
/* send packet to node ID derived from dest IP */
|
|
if (nce != NULL) {
|
|
sixlowpan_lowpan_sendto(nce->if_id, &nce->lladdr,
|
|
nce->lladdr_len,
|
|
(uint8_t *)ipv6_get_buf_send(),
|
|
packet_length);
|
|
}
|
|
}
|
|
|
|
msg_reply(&m_recv_lowpan, &m_send_lowpan);
|
|
}
|
|
}
|
|
|
|
ipv6_net_if_ext_t *ipv6_net_if_get_ext(int if_id)
|
|
{
|
|
if (net_if_get_interface(if_id)) {
|
|
return &ipv6_net_if_ext[if_id];
|
|
}
|
|
else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
int ipv6_net_if_add_addr(int if_id, const ipv6_addr_t *addr,
|
|
ndp_addr_state_t state, uint32_t val_ltime,
|
|
uint32_t pref_ltime, uint8_t is_anycast)
|
|
{
|
|
ipv6_net_if_addr_t *addr_entry;
|
|
ipv6_net_if_hit_t hit;
|
|
|
|
if (ipv6_addr_is_unspecified(addr) == 128) {
|
|
DEBUG("ERROR: unspecified address (::) can't be assigned to interface.\n");
|
|
return 0;
|
|
}
|
|
|
|
if (ipv6_addr_is_multicast(addr) && is_anycast) {
|
|
DEBUG("ERROR: anycast addresses must not be multicast addresses "
|
|
"(i.e. start with ff::/2)\n");
|
|
return 0;
|
|
}
|
|
|
|
if (ipv6_net_if_addr_match(&hit, addr)) {
|
|
return 1;
|
|
}
|
|
|
|
if (ipv6_net_if_addr_buffer_count < IPV6_NET_IF_ADDR_BUFFER_LEN) {
|
|
timex_t valtime = {val_ltime, 0};
|
|
timex_t preftime = {pref_ltime, 0};
|
|
timex_t now;
|
|
|
|
vtimer_now(&now);
|
|
|
|
ipv6_addr_t *addr_data = &ipv6_addr_buffer[ipv6_net_if_addr_buffer_count];
|
|
memcpy(addr_data, addr, sizeof(ipv6_addr_t));
|
|
|
|
addr_entry = &ipv6_net_if_addr_buffer[ipv6_net_if_addr_buffer_count];
|
|
addr_entry->addr_data = addr_data;
|
|
addr_entry->addr_len = 128;
|
|
|
|
if (is_anycast) {
|
|
addr_entry->addr_protocol = NET_IF_L3P_IPV6_ANYCAST;
|
|
}
|
|
else if (ipv6_addr_is_multicast(addr_data)) {
|
|
addr_entry->addr_protocol = NET_IF_L3P_IPV6_MULTICAST;
|
|
}
|
|
else {
|
|
addr_entry->addr_protocol = NET_IF_L3P_IPV6_UNICAST;
|
|
}
|
|
|
|
addr_entry->ndp_state = state;
|
|
addr_entry->valid_lifetime = timex_add(now, valtime);
|
|
addr_entry->preferred_lifetime = timex_add(now, preftime);
|
|
addr_entry->is_anycast = is_anycast;
|
|
|
|
ipv6_net_if_addr_buffer_count++;
|
|
|
|
net_if_add_address(if_id, (net_if_addr_t *)addr_entry);
|
|
|
|
/* Register to Solicited-Node multicast address according to RFC 4291 */
|
|
if (is_anycast || !ipv6_addr_is_multicast(addr)) {
|
|
ipv6_addr_t sol_node_mcast_addr;
|
|
ipv6_addr_set_solicited_node_addr(&sol_node_mcast_addr, addr);
|
|
|
|
if (ipv6_net_if_addr_match(&hit, &sol_node_mcast_addr) == NULL) {
|
|
ipv6_net_if_add_addr(if_id, &sol_node_mcast_addr, state,
|
|
val_ltime, pref_ltime, 0);
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
ipv6_net_if_hit_t *ipv6_net_if_addr_match(ipv6_net_if_hit_t *hit,
|
|
const ipv6_addr_t *addr)
|
|
{
|
|
int if_id = -1;
|
|
ipv6_net_if_addr_t *addr_entry = NULL;
|
|
|
|
while ((if_id = net_if_iter_interfaces(if_id)) >= 0) {
|
|
while (net_if_iter_addresses(if_id, (net_if_addr_t **) &addr_entry) != NULL) {
|
|
if (addr_entry->addr_protocol & NET_IF_L3P_IPV6) {
|
|
uint8_t byte_al = addr_entry->addr_len / 8;
|
|
uint8_t mask[] = {0x00, 0x80, 0xc0, 0xe0,
|
|
0xf0, 0xf8, 0xfc, 0xfe
|
|
};
|
|
|
|
if (memcmp(addr_entry->addr_data, addr, byte_al) == 0 &&
|
|
(addr_entry->addr_len % 8 == 0 ||
|
|
((addr_entry->addr_data->uint8[byte_al] - addr->uint8[byte_al]) & mask[addr_entry->addr_len - (byte_al * 8)]))) {
|
|
hit->if_id = if_id;
|
|
hit->addr = addr_entry;
|
|
return hit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
ipv6_net_if_hit_t *ipv6_net_if_addr_prefix_eq(ipv6_net_if_hit_t *hit,
|
|
ipv6_addr_t *addr)
|
|
{
|
|
int if_id = -1;
|
|
ipv6_net_if_addr_t *addr_entry = NULL;
|
|
|
|
while ((if_id = net_if_iter_interfaces(if_id)) >= 0) {
|
|
while (net_if_iter_addresses(if_id, (net_if_addr_t **) &addr_entry) != NULL) {
|
|
if (addr_entry->addr_protocol & NET_IF_L3P_IPV6) {
|
|
if (memcmp(addr_entry->addr_data, &addr, 8) == 0) {
|
|
hit->if_id = if_id;
|
|
hit->addr = addr_entry;
|
|
return hit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* TODO ipv6_net_if_hit_t returning function similar wrapping
|
|
* ipv6_net_if_get_best_src_addr() to search on all interfaces */
|
|
|
|
ipv6_addr_t *ipv6_addr_set_by_eui64(ipv6_addr_t *out, int if_id,
|
|
const ipv6_addr_t *prefix)
|
|
{
|
|
uint8_t force_generation = 0;
|
|
out->uint16[0] = prefix->uint16[0];
|
|
out->uint16[1] = prefix->uint16[1];
|
|
out->uint16[2] = prefix->uint16[2];
|
|
out->uint16[3] = prefix->uint16[3];
|
|
|
|
if (net_if_get_src_address_mode(if_id) == NET_IF_TRANS_ADDR_M_SHORT) {
|
|
force_generation = 1;
|
|
}
|
|
|
|
if (net_if_get_eui64((net_if_eui64_t *) &out->uint8[8], if_id,
|
|
force_generation)) {
|
|
#ifdef MODULE_SIXLOWPAN
|
|
|
|
if (!sixlowpan_lowpan_eui64_to_short_addr((net_if_eui64_t *)&out->uint8[8])) {
|
|
out->uint8[8] ^= 0x02;
|
|
}
|
|
|
|
#else
|
|
out->uint8[8] ^= 0x02;
|
|
#endif
|
|
return out;
|
|
}
|
|
else {
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
void ipv6_addr_init_prefix(ipv6_addr_t *out, const ipv6_addr_t *prefix,
|
|
uint8_t bits)
|
|
{
|
|
if (bits > 128) {
|
|
bits = 128;
|
|
}
|
|
|
|
uint8_t bytes = bits / 8, mask;
|
|
|
|
if (bits % 8) {
|
|
mask = 0xff << (bits - (bytes * 8));
|
|
}
|
|
else {
|
|
mask = 0x00;
|
|
}
|
|
|
|
bytes++;
|
|
memset(out, 0, 16);
|
|
memcpy(out, prefix, bytes);
|
|
out->uint8[bytes] = prefix->uint8[bytes] & mask;
|
|
}
|
|
|
|
void ipv6_net_if_get_best_src_addr(ipv6_addr_t *src, const ipv6_addr_t *dest)
|
|
{
|
|
/* try to find best match if dest is not mcast or link local */
|
|
int if_id = 0; // TODO: get this somehow
|
|
uint8_t tmp = 0;
|
|
uint8_t bmatch = 0;
|
|
ipv6_net_if_addr_t *addr = NULL;
|
|
ipv6_net_if_addr_t *tmp_addr = NULL;
|
|
|
|
if (!(ipv6_addr_is_link_local(dest)) && !(ipv6_addr_is_multicast(dest))) {
|
|
while ((addr = (ipv6_net_if_addr_t *)net_if_iter_addresses(if_id,
|
|
(net_if_addr_t **)&addr))) {
|
|
if (addr->ndp_state == NDP_ADDR_STATE_PREFERRED) {
|
|
if (!ipv6_addr_is_link_local(addr->addr_data) &&
|
|
!ipv6_addr_is_multicast(addr->addr_data) &&
|
|
!ipv6_addr_is_unique_local_unicast(addr->addr_data)) {
|
|
tmp = ipv6_get_addr_match(dest, addr->addr_data);
|
|
|
|
if (tmp >= bmatch) {
|
|
bmatch = tmp;
|
|
tmp_addr = addr;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
while ((addr = (ipv6_net_if_addr_t *)net_if_iter_addresses(if_id,
|
|
(net_if_addr_t **)&addr))) {
|
|
if (addr->ndp_state == NDP_ADDR_STATE_PREFERRED &&
|
|
ipv6_addr_is_link_local(addr->addr_data) &&
|
|
!ipv6_addr_is_multicast(addr->addr_data)) {
|
|
tmp_addr = addr;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (tmp_addr == NULL) {
|
|
memset(src, 0, 16);
|
|
}
|
|
else {
|
|
memcpy(src, tmp_addr->addr_data, 16);
|
|
}
|
|
}
|
|
|
|
void ipv6_addr_init(ipv6_addr_t *out, uint16_t addr0, uint16_t addr1,
|
|
uint16_t addr2, uint16_t addr3, uint16_t addr4,
|
|
uint16_t addr5, uint16_t addr6, uint16_t addr7)
|
|
{
|
|
out->uint16[0] = HTONS(addr0);
|
|
out->uint16[1] = HTONS(addr1);
|
|
out->uint16[2] = HTONS(addr2);
|
|
out->uint16[3] = HTONS(addr3);
|
|
out->uint16[4] = HTONS(addr4);
|
|
out->uint16[5] = HTONS(addr5);
|
|
out->uint16[6] = HTONS(addr6);
|
|
out->uint16[7] = HTONS(addr7);
|
|
}
|
|
|
|
uint32_t get_remaining_time(timex_t *t)
|
|
{
|
|
timex_t now;
|
|
vtimer_now(&now);
|
|
|
|
return (timex_sub(*t, now).seconds);
|
|
}
|
|
|
|
void set_remaining_time(timex_t *t, uint32_t time)
|
|
{
|
|
timex_t tmp = {time, 0};
|
|
|
|
timex_t now;
|
|
vtimer_now(&now);
|
|
*t = timex_add(now, tmp);
|
|
}
|
|
|
|
int ipv6_init_as_router(void)
|
|
{
|
|
ipv6_addr_t addr;
|
|
int if_id = -1;
|
|
|
|
ipv6_addr_set_all_routers_addr(&addr);
|
|
|
|
while ((if_id = net_if_iter_interfaces(if_id)) >= 0) {
|
|
if (!ipv6_net_if_add_addr(if_id, &addr, NDP_ADDR_STATE_PREFERRED, 0, 0,
|
|
0)) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
uint8_t ipv6_is_router(void)
|
|
{
|
|
ipv6_addr_t addr;
|
|
ipv6_net_if_hit_t hit;
|
|
|
|
ipv6_addr_set_all_routers_addr(&addr);
|
|
|
|
if (ipv6_net_if_addr_match(&hit, &addr) != NULL) {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void set_tcp_packet_handler_pid(int pid)
|
|
{
|
|
tcp_packet_handler_pid = pid;
|
|
}
|
|
|
|
void set_udp_packet_handler_pid(int pid)
|
|
{
|
|
udp_packet_handler_pid = pid;
|
|
}
|
|
|
|
void ipv6_register_next_header_handler(uint8_t next_header, int pid)
|
|
{
|
|
switch (next_header) {
|
|
case (IPV6_PROTO_NUM_TCP):
|
|
set_tcp_packet_handler_pid(pid);
|
|
break;
|
|
|
|
case (IPV6_PROTO_NUM_UDP):
|
|
set_udp_packet_handler_pid(pid);
|
|
break;
|
|
|
|
default:
|
|
/* TODO */
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* register routing function */
|
|
void ipv6_iface_set_routing_provider(ipv6_addr_t *(*next_hop)(ipv6_addr_t *dest))
|
|
{
|
|
ip_get_next_hop = next_hop;
|
|
}
|
|
|
|
void ipv6_register_rpl_handler(int pid)
|
|
{
|
|
rpl_process_pid = pid;
|
|
}
|
|
|
|
uint16_t ipv6_csum(ipv6_hdr_t *ipv6_header, uint8_t *buf, uint16_t len, uint8_t proto)
|
|
{
|
|
uint16_t sum = 0;
|
|
DEBUG("Calculate checksum over src: %s, dst: %s, len: %04X, buf: %p, proto: %u\n",
|
|
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN,
|
|
&ipv6_header->srcaddr),
|
|
ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN,
|
|
&ipv6_header->destaddr),
|
|
len, buf, proto);
|
|
sum = len + proto;
|
|
sum = csum(sum, (uint8_t *)&ipv6_header->srcaddr, 2 * sizeof(ipv6_addr_t));
|
|
sum = csum(sum, buf, len);
|
|
return (sum == 0) ? 0xffff : HTONS(sum);
|
|
}
|