|
Packit |
eace71 |
/*
|
|
Packit |
eace71 |
* Copyright (c) 2006, Swedish Institute of Computer Science.
|
|
Packit |
eace71 |
* All rights reserved.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* Redistribution and use in source and binary forms, with or without
|
|
Packit |
eace71 |
* modification, are permitted provided that the following conditions
|
|
Packit |
eace71 |
* are met:
|
|
Packit |
eace71 |
* 1. Redistributions of source code must retain the above copyright
|
|
Packit |
eace71 |
* notice, this list of conditions and the following disclaimer.
|
|
Packit |
eace71 |
* 2. Redistributions in binary form must reproduce the above copyright
|
|
Packit |
eace71 |
* notice, this list of conditions and the following disclaimer in the
|
|
Packit |
eace71 |
* documentation and/or other materials provided with the distribution.
|
|
Packit |
eace71 |
* 3. Neither the name of the Institute nor the names of its contributors
|
|
Packit |
eace71 |
* may be used to endorse or promote products derived from this software
|
|
Packit |
eace71 |
* without specific prior written permission.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
|
Packit |
eace71 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
Packit |
eace71 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
Packit |
eace71 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
|
Packit |
eace71 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
Packit |
eace71 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
Packit |
eace71 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
Packit |
eace71 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
Packit |
eace71 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
Packit |
eace71 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
Packit |
eace71 |
* SUCH DAMAGE.
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
* This file is part of the uIP TCP/IP stack
|
|
Packit |
eace71 |
*
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/**
|
|
Packit |
eace71 |
* \file
|
|
Packit |
eace71 |
* Database of link-local neighbors, used by IPv6 code and
|
|
Packit |
eace71 |
* to be used by a future ARP code rewrite.
|
|
Packit |
eace71 |
* \author
|
|
Packit |
eace71 |
* Adam Dunkels <adam@sics.se>
|
|
Packit |
eace71 |
*/
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#include "logger.h"
|
|
Packit |
eace71 |
#include "uip.h"
|
|
Packit |
eace71 |
#include "uip-neighbor.h"
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#include <errno.h>
|
|
Packit |
eace71 |
#include <string.h>
|
|
Packit |
eace71 |
#include <arpa/inet.h>
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*******************************************************************************
|
|
Packit |
eace71 |
* Constants
|
|
Packit |
eace71 |
******************************************************************************/
|
|
Packit |
eace71 |
#define PFX "uip-neigh "
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
#define MAX_TIME 128
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
eace71 |
void uip_neighbor_init(struct uip_stack *ustack)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int i;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
pthread_mutex_lock(&ustack->lock);
|
|
Packit |
eace71 |
for (i = 0; i < UIP_NEIGHBOR_ENTRIES; ++i) {
|
|
Packit |
eace71 |
memset(&(ustack->neighbor_entries[i].ipaddr), 0,
|
|
Packit |
eace71 |
sizeof(ustack->neighbor_entries[i].ipaddr));
|
|
Packit |
eace71 |
memset(&(ustack->neighbor_entries[i].mac_addr), 0,
|
|
Packit |
eace71 |
sizeof(ustack->neighbor_entries[i].mac_addr));
|
|
Packit |
eace71 |
ustack->neighbor_entries[i].time = MAX_TIME;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
pthread_mutex_unlock(&ustack->lock);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
void uip_neighbor_add(struct uip_stack *ustack,
|
|
Packit |
eace71 |
struct in6_addr *addr6, struct uip_eth_addr *addr)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int i, oldest;
|
|
Packit |
eace71 |
u8_t oldest_time;
|
|
Packit |
eace71 |
char buf[INET6_ADDRSTRLEN];
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
inet_ntop(AF_INET6, addr6, buf, sizeof(buf));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
pthread_mutex_lock(&ustack->lock);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Find the first unused entry or the oldest used entry. */
|
|
Packit |
eace71 |
oldest_time = 0;
|
|
Packit |
eace71 |
oldest = 0;
|
|
Packit |
eace71 |
for (i = 0; i < UIP_NEIGHBOR_ENTRIES; ++i) {
|
|
Packit |
eace71 |
if (ustack->neighbor_entries[i].time == MAX_TIME) {
|
|
Packit |
eace71 |
oldest = i;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
if (uip_ip6addr_cmp
|
|
Packit |
eace71 |
(ustack->neighbor_entries[i].ipaddr.s6_addr, addr6)) {
|
|
Packit |
eace71 |
oldest = i;
|
|
Packit |
eace71 |
break;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
if (ustack->neighbor_entries[i].time > oldest_time) {
|
|
Packit |
eace71 |
oldest = i;
|
|
Packit |
eace71 |
oldest_time = ustack->neighbor_entries[i].time;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Use the oldest or first free entry (either pointed to by the
|
|
Packit |
eace71 |
"oldest" variable). */
|
|
Packit |
eace71 |
ustack->neighbor_entries[oldest].time = 0;
|
|
Packit |
eace71 |
uip_ip6addr_copy(ustack->neighbor_entries[oldest].ipaddr.s6_addr,
|
|
Packit |
eace71 |
addr6);
|
|
Packit |
eace71 |
memcpy(&ustack->neighbor_entries[oldest].mac_addr, addr,
|
|
Packit |
eace71 |
sizeof(struct uip_eth_addr));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
LOG_DEBUG("Adding neighbor %s with "
|
|
Packit |
eace71 |
"mac address %02x:%02x:%02x:%02x:%02x:%02x at %d",
|
|
Packit |
eace71 |
buf, addr->addr[0], addr->addr[1], addr->addr[2],
|
|
Packit |
eace71 |
addr->addr[3], addr->addr[4], addr->addr[5], oldest);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
pthread_mutex_unlock(&ustack->lock);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
eace71 |
static struct neighbor_entry *find_entry(struct uip_stack *ustack,
|
|
Packit |
eace71 |
struct in6_addr *addr6)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
int i;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
for (i = 0; i < UIP_NEIGHBOR_ENTRIES; ++i) {
|
|
Packit |
eace71 |
if (uip_ip6addr_cmp
|
|
Packit |
eace71 |
(ustack->neighbor_entries[i].ipaddr.s6_addr,
|
|
Packit |
eace71 |
addr6->s6_addr)) {
|
|
Packit |
eace71 |
return &ustack->neighbor_entries[i];
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
return NULL;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
eace71 |
void uip_neighbor_update(struct uip_stack *ustack, struct in6_addr *addr6)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct neighbor_entry *e;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
pthread_mutex_lock(&ustack->lock);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
e = find_entry(ustack, addr6);
|
|
Packit |
eace71 |
if (e != NULL)
|
|
Packit |
eace71 |
e->time = 0;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
pthread_mutex_unlock(&ustack->lock);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*---------------------------------------------------------------------------*/
|
|
Packit |
eace71 |
int uip_neighbor_lookup(struct uip_stack *ustack,
|
|
Packit |
eace71 |
struct in6_addr *addr6, uint8_t *mac_addr)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct neighbor_entry *e;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
pthread_mutex_lock(&ustack->lock);
|
|
Packit |
eace71 |
e = find_entry(ustack, addr6);
|
|
Packit |
eace71 |
if (e != NULL) {
|
|
Packit |
eace71 |
char addr6_str[INET6_ADDRSTRLEN];
|
|
Packit |
eace71 |
uint8_t *entry_mac_addr;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
addr6_str[0] = '\0';
|
|
Packit |
eace71 |
inet_ntop(AF_INET6, addr6->s6_addr, addr6_str,
|
|
Packit |
eace71 |
sizeof(addr6_str));
|
|
Packit |
eace71 |
entry_mac_addr = (uint8_t *)&e->mac_addr.addr;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
LOG_DEBUG(PFX
|
|
Packit |
eace71 |
"Found %s at %02x:%02x:%02x:%02x:%02x:%02x",
|
|
Packit |
eace71 |
addr6_str,
|
|
Packit |
eace71 |
entry_mac_addr[0], entry_mac_addr[1],
|
|
Packit |
eace71 |
entry_mac_addr[2], entry_mac_addr[3],
|
|
Packit |
eace71 |
entry_mac_addr[4], entry_mac_addr[5]);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memcpy(mac_addr, entry_mac_addr, sizeof(e->mac_addr));
|
|
Packit |
eace71 |
pthread_mutex_unlock(&ustack->lock);
|
|
Packit |
eace71 |
return 0;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
pthread_mutex_unlock(&ustack->lock);
|
|
Packit |
eace71 |
return -ENOENT;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
void uip_neighbor_out(struct uip_stack *ustack)
|
|
Packit |
eace71 |
{
|
|
Packit |
eace71 |
struct neighbor_entry *e;
|
|
Packit |
eace71 |
struct uip_eth_hdr *eth_hdr =
|
|
Packit |
eace71 |
(struct uip_eth_hdr *)ustack->data_link_layer;
|
|
Packit |
eace71 |
struct uip_ipv6_hdr *ipv6_hdr =
|
|
Packit |
eace71 |
(struct uip_ipv6_hdr *)ustack->network_layer;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
pthread_mutex_lock(&ustack->lock);
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/* Find the destination IP address in the neighbor table and construct
|
|
Packit |
eace71 |
the Ethernet header. If the destination IP addres isn't on the
|
|
Packit |
eace71 |
local network, we use the default router's IP address instead.
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
If not ARP table entry is found, we overwrite the original IP
|
|
Packit |
eace71 |
packet with an ARP request for the IP address. */
|
|
Packit |
eace71 |
e = find_entry(ustack, (struct in6_addr *)ipv6_hdr->destipaddr);
|
|
Packit |
eace71 |
if (e == NULL) {
|
|
Packit |
eace71 |
struct uip_eth_addr eth_addr_tmp;
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memcpy(ð_addr_tmp, eth_hdr->src.addr, sizeof(eth_addr_tmp));
|
|
Packit |
eace71 |
memcpy(eth_hdr->src.addr, ustack->uip_ethaddr.addr,
|
|
Packit |
eace71 |
sizeof(eth_hdr->src.addr));
|
|
Packit |
eace71 |
memcpy(eth_hdr->dest.addr, ð_addr_tmp,
|
|
Packit |
eace71 |
sizeof(eth_hdr->dest.addr));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
pthread_mutex_unlock(&ustack->lock);
|
|
Packit |
eace71 |
return;
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
memcpy(eth_hdr->dest.addr, &e->mac_addr, sizeof(eth_hdr->dest.addr));
|
|
Packit |
eace71 |
memcpy(eth_hdr->src.addr, ustack->uip_ethaddr.addr,
|
|
Packit |
eace71 |
sizeof(eth_hdr->src.addr));
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
pthread_mutex_unlock(&ustack->lock);
|
|
Packit |
eace71 |
}
|
|
Packit |
eace71 |
|
|
Packit |
eace71 |
/*---------------------------------------------------------------------------*/
|