mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-18 12:52:44 +01:00
11254577eb
If there's no IPv6 address configured so far to any interface, 6lowpan should not try to handle incoming packets. This can easily lead to looping packets.
820 lines
24 KiB
C
820 lines
24 KiB
C
/**
|
|
* IPv6 implementation
|
|
*
|
|
* Copyright (C) 2013 INRIA.
|
|
*
|
|
* This file is subject to the terms and conditions of the GNU Lesser
|
|
* General Public License v2.1. 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_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;
|
|
|
|
kernel_pid_t udp_packet_handler_pid = KERNEL_PID_UNDEF;
|
|
kernel_pid_t tcp_packet_handler_pid = KERNEL_PID_UNDEF;
|
|
static volatile kernel_pid_t _rpl_process_pid = KERNEL_PID_UNDEF;
|
|
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 */
|
|
kernel_pid_t 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;
|
|
|
|
DEBUGF("Got a packet to send to %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &packet->destaddr));
|
|
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 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;
|
|
}
|
|
|
|
DEBUG("Trying to find the next hop for %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &packet->destaddr));
|
|
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 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(kernel_pid_t 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 != KERNEL_PID_UNDEF) {
|
|
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;
|
|
unsigned counter = 0;
|
|
|
|
DEBUGF("Is this my addres: %s?\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, addr));
|
|
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) {
|
|
counter++;
|
|
DEBUGF("\tCompare with: %s?\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, (ipv6_addr_t*) myaddr->addr_data));
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!counter) {
|
|
counter = -1;
|
|
}
|
|
/* return negative value if no address is configured so far */
|
|
return counter;
|
|
}
|
|
|
|
void *ipv6_process(void *arg)
|
|
{
|
|
(void) arg;
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
int addr_match = is_our_address(&ipv6_buf->destaddr);
|
|
|
|
/* no address configured for this node so far, exit early */
|
|
if (addr_match < 1) {
|
|
msg_reply(&m_recv_lowpan, &m_send_lowpan);
|
|
continue;
|
|
}
|
|
/* destination is our address */
|
|
else if (addr_match) {
|
|
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 != KERNEL_PID_UNDEF) {
|
|
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 != KERNEL_PID_UNDEF) {
|
|
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:
|
|
DEBUG("INFO: Unknown next header\n");
|
|
break;
|
|
}
|
|
}
|
|
/* destination is foreign address */
|
|
else {
|
|
DEBUG("That's not for me, destination is %s\n", ipv6_addr_to_str(addr_str, IPV6_MAX_ADDR_STR_LEN, &ipv6_buf->destaddr));
|
|
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)) {
|
|
DEBUG("!!! Packet not for me, routing handler is set, but I "\
|
|
" have no idea where to send or the hop limit is exceeded.\n");
|
|
msg_reply(&m_recv_lowpan, &m_send_lowpan);
|
|
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);
|
|
} else {
|
|
/* XXX: this is wrong, but until ND does 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 *)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(kernel_pid_t pid)
|
|
{
|
|
tcp_packet_handler_pid = pid;
|
|
}
|
|
|
|
void set_udp_packet_handler_pid(kernel_pid_t pid)
|
|
{
|
|
udp_packet_handler_pid = pid;
|
|
}
|
|
|
|
void ipv6_register_next_header_handler(uint8_t next_header, kernel_pid_t 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(kernel_pid_t 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);
|
|
}
|