Commit 451d8749 authored by Roel Postelmans's avatar Roel Postelmans Committed by GitHub

Merge pull request #470 from tass-belgium/tahi_fix

IPv6 neighbour discovery + MTU path discovery Tahi fix 
parents 642c6020 de273e2d
......@@ -23,6 +23,7 @@ cscope.out
*.gcda
*.gcno
*.expand
.hg
*.pcap
.ycm_extra_conf.py
.clang_complete
......@@ -430,6 +430,7 @@ units: mod core lib $(UNITS_OBJ) $(MOD_OBJ)
@$(CC) -o $(PREFIX)/test/modunit_dns_sd.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_dns_sd.c $(UNIT_LDFLAGS) $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
@$(CC) -o $(PREFIX)/test/modunit_dev_loop.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_dev_loop.c $(UNIT_LDFLAGS) $(UNITS_OBJ)
@$(CC) -o $(PREFIX)/test/modunit_ipv6_nd.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_ipv6_nd.c $(UNIT_LDFLAGS) $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
@$(CC) -o $(PREFIX)/test/modunit_ipv6_pmtu.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_ipv6_pmtu.c $(UNIT_LDFLAGS) $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
@$(CC) -o $(PREFIX)/test/modunit_ethernet.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_ethernet.c $(UNIT_LDFLAGS) $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
@$(CC) -o $(PREFIX)/test/modunit_pico_stack.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_stack.c $(UNIT_LDFLAGS) $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
@$(CC) -o $(PREFIX)/test/modunit_tftp.elf $(UNIT_CFLAGS) -I. test/unit/modunit_pico_tftp.c $(UNIT_LDFLAGS) $(UNITS_OBJ) $(PREFIX)/lib/libpicotcp.a
......
......@@ -53,6 +53,7 @@
#define short_be(x) (x)
#define long_be(x) (x)
#define long_long_be(x) (x)
#define be_to_host_long(x) (x)
static inline uint16_t short_from(void *_p)
{
......@@ -164,6 +165,10 @@ static inline uint64_t long_long_be(uint64_t le)
}
# endif /* BYTESWAP_GCC */
static inline uint32_t be_to_host_long(uint32_t be)
{
return long_be(be);
}
#endif
/* Mockables */
......
......@@ -46,7 +46,7 @@ struct pico_frame {
uint8_t *app_hdr;
uint16_t app_len;
/* Pointer to the phisical device this packet belongs to.
/* Pointer to the physical device this packet belongs to.
* Should be valid in both routing directions
*/
struct pico_device *dev;
......
......@@ -60,6 +60,7 @@ enum pico_err_e {
PICO_ERR_ECONNREFUSED = 111,
PICO_ERR_EHOSTDOWN = 112,
PICO_ERR_EHOSTUNREACH = 113,
PICO_ERR_EMSGSIZE = 114,
};
typedef enum pico_err_e pico_err_t;
......
......@@ -371,6 +371,7 @@ int32_t MOCKABLE pico_ethernet_send(struct pico_frame *f)
/* Enqueue copy of frame in IPv6 ND-module to retry later. Discard
* frame, otherwise we have a duplicate in IPv6-ND */
pico_ipv6_nd_postpone(f);
pico_frame_discard(f);
return (int32_t)f->len;
}
......
......@@ -17,6 +17,7 @@
#include "pico_tree.h"
#include "pico_socket.h"
#include "pico_mld.h"
#include "pico_ipv6_pmtu.h"
#ifdef DEBUG_ICMP6
#define icmp6_dbg dbg
......@@ -35,7 +36,7 @@ static struct pico_queue icmp6_out;
static int pico_6lp_nd_neighbor_solicitation(struct pico_device *dev, struct pico_ip6 *tgt, uint8_t type, struct pico_ip6 *dst);
#endif
uint16_t pico_icmp6_checksum(struct pico_frame *f)
MOCKABLE uint16_t pico_icmp6_checksum(struct pico_frame *f)
{
struct pico_ipv6_hdr *ipv6_hdr = (struct pico_ipv6_hdr *)f->net_hdr;
......@@ -58,7 +59,11 @@ uint16_t pico_icmp6_checksum(struct pico_frame *f)
static void pico_icmp6_ping_recv_reply(struct pico_frame *f);
#endif
static int pico_icmp6_send_echoreply(struct pico_frame *echo)
#ifdef PICO_SUPPORT_IPV6PMTU
static void pico_icmp6_update_pmtu(struct pico_frame *f);
#endif
static int pico_icmp6_send_echoreply_not_frag(struct pico_frame *echo)
{
struct pico_frame *reply = NULL;
struct pico_icmp6_hdr *ehdr = NULL, *rhdr = NULL;
......@@ -74,6 +79,7 @@ static int pico_icmp6_send_echoreply(struct pico_frame *echo)
echo->payload = echo->transport_hdr + PICO_ICMP6HDR_ECHO_REQUEST_SIZE;
reply->payload = reply->transport_hdr + PICO_ICMP6HDR_ECHO_REQUEST_SIZE;
reply->payload_len = echo->transport_len;
reply->timestamp = pico_tick;
ehdr = (struct pico_icmp6_hdr *)echo->transport_hdr;
rhdr = (struct pico_icmp6_hdr *)reply->transport_hdr;
......@@ -87,10 +93,108 @@ static int pico_icmp6_send_echoreply(struct pico_frame *echo)
/* Get destination and source swapped */
memcpy(dst.addr, ((struct pico_ipv6_hdr *)echo->net_hdr)->src.addr, PICO_SIZE_IP6);
memcpy(src.addr, ((struct pico_ipv6_hdr *)echo->net_hdr)->dst.addr, PICO_SIZE_IP6);
pico_ipv6_frame_push(reply, &src, &dst, PICO_PROTO_ICMP6, 0);
return 0;
}
static int pico_icmp6_send_echoreply_frag(struct pico_frame *echo)
{
uint16_t offset = 0;
uint16_t frag_payload = (uint16_t) (echo->transport_len);
uint16_t header_overhead = (uint16_t) (echo->net_len + (echo->net_hdr - echo->buffer));
static uint32_t frag_id = 0;
uint32_t mtu = echo->dev->mtu;
struct pico_frame *reply = NULL;
struct pico_icmp6_hdr *ehdr = NULL, *rhdr = NULL;
struct pico_ip6 src;
struct pico_ip6 dst;
echo->payload = echo->transport_hdr + PICO_ICMP6HDR_ECHO_REQUEST_SIZE;
ehdr = (struct pico_icmp6_hdr *)echo->transport_hdr;
/* Get destination and source swapped */
memcpy(dst.addr, ((struct pico_ipv6_hdr *)echo->net_hdr)->src.addr, PICO_SIZE_IP6);
memcpy(src.addr, ((struct pico_ipv6_hdr *)echo->net_hdr)->dst.addr, PICO_SIZE_IP6);
while (offset < frag_payload) {
uint16_t size = (uint16_t) (frag_payload - offset);
const uint16_t icmp_mss = (uint16_t) (mtu - PICO_IPV6_EXTHDR_FRAG_SIZE - header_overhead);
if (size > icmp_mss) {
size = (uint16_t) (icmp_mss - (icmp_mss % 8));
}
/* Allocate ipv6 with fragmentation header */
reply = pico_proto_ipv6.alloc(&pico_proto_ipv6, echo->dev, (uint16_t) (size + PICO_IPV6_EXTHDR_FRAG_SIZE));
if (!reply) {
pico_err = PICO_ERR_ENOMEM;
return -1;
}
reply->net_len = (uint16_t) (reply->net_len + PICO_IPV6_EXTHDR_FRAG_SIZE);
reply->transport_hdr += PICO_IPV6_EXTHDR_FRAG_SIZE;
reply->transport_len = (uint16_t) (reply->transport_len - PICO_IPV6_EXTHDR_FRAG_SIZE);
/* Populate fragmentation header */
{
struct pico_ipv6_exthdr * frag_header = (struct pico_ipv6_exthdr *) (reply->transport_hdr-PICO_IPV6_EXTHDR_FRAG_SIZE);
uint16_t octet_offset = short_be((uint16_t)(offset));
if (offset + size < frag_payload) {
octet_offset = octet_offset | short_be(1);
}
frag_header->nxthdr = PICO_PROTO_ICMP6;
memcpy(frag_header->ext.frag.id, (uint8_t *)(&frag_id), 4);
memcpy(frag_header->ext.frag.om, (uint8_t *)(&octet_offset), 2);
}
/* Prepare for sending */
memcpy(reply->transport_hdr, echo->transport_hdr + offset, size);
if (offset == 0){
rhdr = (struct pico_icmp6_hdr *)reply->transport_hdr;
rhdr->type = PICO_ICMP6_ECHO_REPLY;
rhdr->code = 0;
rhdr->msg.info.echo_reply.id = ehdr->msg.info.echo_reply.id;
rhdr->msg.info.echo_reply.seq = ehdr->msg.info.echo_request.seq;
/* Received echo packet used for checksum calculation */
memcpy(((struct pico_ipv6_hdr *)echo->net_hdr)->src.addr, src.addr, PICO_SIZE_IP6);
memcpy(((struct pico_ipv6_hdr *)echo->net_hdr)->dst.addr, dst.addr, PICO_SIZE_IP6);
ehdr->type = PICO_ICMP6_ECHO_REPLY;
ehdr->code = 0;
ehdr->crc = 0;
rhdr->crc = short_be(pico_icmp6_checksum(echo));
}
pico_ipv6_frame_push(reply, &src, &dst, PICO_IPV6_EXTHDR_FRAG, 0);
offset = (uint16_t)(offset + size);
}
return 0;
}
static int pico_icmp6_send_echoreply(struct pico_frame *echo)
{
uint32_t mtu = echo->dev->mtu;
uint16_t header_overhead = (uint16_t) (echo->net_len + (echo->net_hdr - echo->buffer));
#ifdef PICO_SUPPORT_IPV6PMTU
struct pico_ipv6_path_id path_id = {((struct pico_ipv6_hdr *)echo->net_hdr)->src};
mtu = pico_ipv6_pmtu_get(&path_id);
if (mtu == 0) {
mtu = echo->dev->mtu;
pico_ipv6_path_add(&path_id, mtu);
}
#endif
if (echo->transport_len < mtu - header_overhead) {
return pico_icmp6_send_echoreply_not_frag(echo);
} else {
return pico_icmp6_send_echoreply_frag(echo);
}
}
static void pico_icmp6_ping_echo_recv_request(struct pico_frame *f)
{
icmp6_dbg("ICMP6: Received ECHO REQ\n");
f->transport_len = (uint16_t)(f->len - f->net_len - (uint16_t)(f->net_hdr - f->buffer));
pico_icmp6_send_echoreply(f);
pico_frame_discard(f);
}
static int pico_icmp6_process_in(struct pico_protocol *self, struct pico_frame *f)
{
struct pico_icmp6_hdr *hdr = (struct pico_icmp6_hdr *)f->transport_hdr;
......@@ -106,10 +210,7 @@ static int pico_icmp6_process_in(struct pico_protocol *self, struct pico_frame *
break;
case PICO_ICMP6_ECHO_REQUEST:
icmp6_dbg("ICMP6: Received ECHO REQ\n");
f->transport_len = (uint16_t)(f->len - f->net_len - (uint16_t)(f->net_hdr - f->buffer));
pico_icmp6_send_echoreply(f);
pico_frame_discard(f);
pico_icmp6_ping_echo_recv_request(f);
break;
case PICO_ICMP6_ECHO_REPLY:
......@@ -118,6 +219,11 @@ static int pico_icmp6_process_in(struct pico_protocol *self, struct pico_frame *
#endif
pico_frame_discard(f);
break;
#ifdef PICO_SUPPORT_IPV6PMTU
case PICO_ICMP6_PKT_TOO_BIG:
pico_icmp6_update_pmtu(f);
break;
#endif
#if defined(PICO_SUPPORT_MCAST) && defined(PICO_SUPPORT_MLD)
case PICO_MLD_QUERY:
case PICO_MLD_REPORT:
......@@ -349,7 +455,7 @@ static struct pico_frame *pico_icmp6_neigh_sol_prep(struct pico_device *dev, str
}
/* RFC 4861 $7.2.2: sending neighbor solicitations */
int pico_icmp6_neighbor_solicitation(struct pico_device *dev, struct pico_ip6 *tgt, uint8_t type, struct pico_ip6 *dst)
MOCKABLE int pico_icmp6_neighbor_solicitation(struct pico_device *dev, struct pico_ip6 *tgt, uint8_t type, struct pico_ip6 *dst)
{
struct pico_ip6 daddr = {{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0xff, 0x00, 0x00, 0x00 }};
......@@ -514,7 +620,7 @@ int pico_icmp6_neighbor_advertisement(struct pico_frame *f, struct pico_ip6 *tar
}
/* RFC 4861 $6.3.7: sending router solicitations */
int pico_icmp6_router_solicitation(struct pico_device *dev, struct pico_ip6 *src, struct pico_ip6 *dst)
MOCKABLE int pico_icmp6_router_solicitation(struct pico_device *dev, struct pico_ip6 *src, struct pico_ip6 *dst)
{
struct pico_ip6 daddr = {{ 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }};
struct pico_icmp6_opt_lladdr *lladdr = NULL;
......@@ -698,6 +804,7 @@ static int pico_icmp6_send_echo(struct pico_icmp6_ping_cookie *cookie)
echo->payload = echo->transport_hdr + PICO_ICMP6HDR_ECHO_REQUEST_SIZE;
echo->payload_len = cookie->size;
echo->timestamp = pico_tick;
hdr = (struct pico_icmp6_hdr *)echo->transport_hdr;
hdr->type = PICO_ICMP6_ECHO_REQUEST;
......@@ -897,5 +1004,28 @@ int pico_icmp6_ping_abort(int id)
pico_err = PICO_ERR_ENOENT;
return -1;
}
#endif
#ifdef PICO_SUPPORT_IPV6PMTU
static void pico_icmp6_update_pmtu(struct pico_frame *f)
{
const struct pico_icmp6_hdr *icmp_hdr = (struct pico_icmp6_hdr *)f->transport_hdr;
const struct pico_ipv6_hdr *icmp_payload = NULL;
struct pico_ipv6_path_id path_id;
f->net_hdr = f->transport_hdr + PICO_ICMP6HDR_PKT_TOO_BIG_SIZE;
icmp_payload = (struct pico_ipv6_hdr *)f->net_hdr;
path_id.dst = icmp_payload->dst;
if (pico_ipv6_path_update(&path_id, be_to_host_long(icmp_hdr->msg.err.pkt_too_big.mtu)) == PICO_PMTU_OK){
#if defined PICO_SUPPORT_TCP || defined PICO_SUPPORT_UDP
f->transport_hdr = f->net_hdr + PICO_SIZE_IP6HDR;
f->transport_len = (uint16_t) (f->transport_len - ((uint16_t)PICO_SIZE_IP6HDR + PICO_ICMP6HDR_PKT_TOO_BIG_SIZE));
pico_transport_error(f, icmp_payload->nxthdr, PICO_ICMP6_ERR_PKT_TOO_BIG);
#endif
} else {
pico_frame_discard(f);
}
}
#endif
......@@ -22,6 +22,7 @@
#define PICO_ICMP6HDR_ROUTER_SOL_SIZE_6LP 16
#define PICO_ICMP6HDR_ROUTER_ADV_SIZE 16
#define PICO_ICMP6HDR_REDIRECT_SIZE 40
#define PICO_ICMP6HDR_PKT_TOO_BIG_SIZE (8)
/* ICMP types */
#define PICO_ICMP6_DEST_UNREACH 1
......@@ -45,6 +46,9 @@
#define PICO_ICMP6_UNREACH_SRCFILTER 5
#define PICO_ICMP6_UNREACH_REJROUTE 6
/* packet too big received */
#define PICO_ICMP6_ERR_PKT_TOO_BIG 6002
/* time exceeded codes */
#define PICO_ICMP6_TIMXCEED_INTRANS 0
#define PICO_ICMP6_TIMXCEED_REASS 1
......@@ -65,7 +69,8 @@
#define PICO_ND_MAX_FRAMES_QUEUED 4 /* max frames queued while awaiting address resolution */
/* ND RFC constants */
#define PICO_ND_MAX_SOLICIT 3
#define PICO_ND_MAX_UNICAST_SOLICIT 3
#define PICO_ND_MAX_MULTICAST_SOLICIT 3
#define PICO_ND_MAX_NEIGHBOR_ADVERT 3
#define PICO_ND_DELAY_INCOMPLETE 1000 /* msec */
#define PICO_ND_DELAY_FIRST_PROBE_TIME 5000 /* msec */
......@@ -85,9 +90,12 @@
#define PICO_ND_ROUTER 0x80000000
#define PICO_ND_SOLICITED 0x40000000
#define PICO_ND_OVERRIDE 0x20000000
#define IS_ROUTER(x) (long_be(x->msg.info.neigh_adv.rsor) & (PICO_ND_ROUTER)) /* router flag set? */
#define IS_SOLICITED(x) (long_be(x->msg.info.neigh_adv.rsor) & (PICO_ND_SOLICITED)) /* solicited flag set? */
#define IS_OVERRIDE(x) (long_be(x->msg.info.neigh_adv.rsor) & (PICO_ND_OVERRIDE)) /* override flag set? */
/* router flag set? */
#define IS_ROUTER(x) (((long_be(x->msg.info.neigh_adv.rsor) & (PICO_ND_ROUTER)) >> 31) & 0x1)
/* solicited flag set? */
#define IS_SOLICITED(x) (((long_be(x->msg.info.neigh_adv.rsor) & (PICO_ND_SOLICITED)) >> 30) & 0x1)
/* override flag set? */
#define IS_OVERRIDE(x) (((long_be(x->msg.info.neigh_adv.rsor) & (PICO_ND_OVERRIDE)) >> 29) & 0x1)
#define PICO_ND_PREFIX_LIFETIME_INF 0xFFFFFFFFu
/* #define PICO_ND_DESTINATION_LRU_TIME 600000u / * msecs (10min) * / */
......
......@@ -65,7 +65,7 @@ static int pico_ipv6_mcast_filter(struct pico_frame *f);
#endif
int pico_ipv6_compare(struct pico_ip6 *a, struct pico_ip6 *b)
int pico_ipv6_compare(const struct pico_ip6 *a, const struct pico_ip6 *b)
{
uint32_t i;
for (i = 0; i < sizeof(struct pico_ip6); i++) {
......@@ -134,7 +134,7 @@ static int ipv6_route_compare(void *ka, void *kb)
static PICO_TREE_DECLARE(Tree_dev_ip6_link, ipv6_link_compare);
PICO_TREE_DECLARE(IPV6Routes, ipv6_route_compare);
static PICO_TREE_DECLARE(IPV6Links, ipv6_link_compare);
PICO_TREE_DECLARE(IPV6Links, ipv6_link_compare);
static char pico_ipv6_dec_to_char(uint8_t u)
{
......@@ -1321,6 +1321,10 @@ static inline void ipv6_push_hdr_adjust(struct pico_frame *f, struct pico_ipv6_l
#else
IGNORE_PARAMETER(hbh);
#endif
case PICO_IPV6_EXTHDR_FRAG:
{
break;
}
case PICO_PROTO_ICMP6:
{
icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr;
......@@ -1330,10 +1334,11 @@ static inline void ipv6_push_hdr_adjust(struct pico_frame *f, struct pico_ipv6_l
/* RFC6775 $5.5.1:
* ... An unspecified source address MUST NOT be used in NS messages.
*/
if (f->dev->mode == LL_MODE_ETHERNET && (is_dad || link->istentative) && icmp6_hdr->type == PICO_ICMP6_NEIGH_SOL) {
if (f->dev->mode == LL_MODE_ETHERNET && (is_dad || link->istentative) && (icmp6_hdr->type == PICO_ICMP6_NEIGH_SOL || icmp6_hdr->type == PICO_ICMP6_ROUTER_SOL)) {
memcpy(hdr->src.addr, PICO_IP6_ANY, PICO_SIZE_IP6);
}
icmp6_hdr->crc = 0;
icmp6_hdr->crc = short_be(pico_icmp6_checksum(f));
break;
......@@ -1638,7 +1643,7 @@ int pico_ipv6_route_del(struct pico_ip6 address, struct pico_ip6 netmask, struct
return -1;
}
void pico_ipv6_router_down(struct pico_ip6 *address)
void pico_ipv6_router_down(const struct pico_ip6 *address)
{
struct pico_tree_node *index = NULL, *_tmp = NULL;
struct pico_ipv6_route *route = NULL;
......@@ -1648,8 +1653,11 @@ void pico_ipv6_router_down(struct pico_ip6 *address)
pico_tree_foreach_safe(index, &IPV6Routes, _tmp)
{
route = index->keyValue;
if (pico_ipv6_compare(address, &route->gateway) == 0)
pico_ipv6_route_del(route->dest, route->netmask, route->gateway, (int)route->metric, route->link);
if (pico_ipv6_compare(address, &route->gateway) == 0) {
if (pico_ipv6_route_del(route->dest, route->netmask, route->gateway, (int)route->metric, route->link) != 0) {
dbg("Route del FAILED\n");
}
}
}
}
......@@ -1751,6 +1759,8 @@ static struct pico_ipv6_link *pico_ipv6_do_link_add(struct pico_device *dev, str
new->dev = dev;
new->istentative = 1;
new->isduplicate = 0;
new->rs_retries = 0;
new->rs_expire_time = PICO_TIME_MS() + pico_rand() % 1000;
#ifdef PICO_SUPPORT_MCAST
new->MCASTGroups = PICO_ZALLOC(sizeof(struct pico_tree));
if (!new->MCASTGroups) {
......@@ -1762,6 +1772,7 @@ static struct pico_ipv6_link *pico_ipv6_do_link_add(struct pico_device *dev, str
new->MCASTGroups->root = &LEAF;
new->MCASTGroups->compare = ipv6_mcast_groups_cmp;
new->mtu = 0;
#ifdef PICO_SUPPORT_MLD
new->mcast_compatibility = PICO_MLDV2;
new->mcast_last_query_interval = MLD_QUERY_INTERVAL;
......@@ -1883,6 +1894,11 @@ int pico_ipv6_link_del(struct pico_device *dev, struct pico_ip6 address)
struct pico_ipv6_link test = {
0
}, *found = NULL;
#ifdef PICO_SUPPORT_MCAST
struct pico_ip6 all_hosts = {{ 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }};
struct pico_mcast_group *g = NULL;
struct pico_tree_node *index, *_tmp;
#endif
if (!dev) {
pico_err = PICO_ERR_EINVAL;
......@@ -1901,6 +1917,26 @@ int pico_ipv6_link_del(struct pico_device *dev, struct pico_ip6 address)
if (found->dad_timer)
pico_timer_cancel(found->dad_timer);
#ifdef PICO_SUPPORT_MCAST
/* TODO: Not sure how to properly delete MCAST groups, etc
* this makes asan happy for now
*/
if (found == mcast_default_link_ipv6) {
mcast_default_link_ipv6 = NULL;
pico_ipv6_mcast_leave(&found->address, &all_hosts, 1, PICO_IP_MULTICAST_EXCLUDE, NULL);
}
pico_tree_foreach_safe(index, found->MCASTGroups, _tmp)
{
g = index->keyValue;
pico_tree_delete(found->MCASTGroups, g);
PICO_FREE(g);
}
PICO_FREE(found->MCASTGroups);
#endif
pico_tree_delete(&IPV6Links, found);
/* XXX MUST leave the solicited-node multicast address corresponding to the address (RFC 4861 $7.2.1) */
PICO_FREE(found);
......@@ -2066,7 +2102,7 @@ struct pico_ipv6_link *pico_ipv6_global_get(struct pico_device *dev)
#define TWO_HOURS ((pico_time)(1000 * 60 * 60 * 2))
void pico_ipv6_check_lifetime_expired(pico_time now, void *arg)
void pico_ipv6_check_link_lifetime_expired(pico_time now, void *arg)
{
struct pico_tree_node *index = NULL, *temp;
struct pico_ipv6_link *link = NULL;
......@@ -2091,8 +2127,8 @@ void pico_ipv6_check_lifetime_expired(pico_time now, void *arg)
}
#endif
}
if (!pico_timer_add(1000, pico_ipv6_check_lifetime_expired, NULL)) {
dbg("IPv6: Failed to start check_lifetime timer\n");
if (!pico_timer_add(1000, pico_ipv6_check_link_lifetime_expired, NULL)) {
dbg("IPv6: Failed to start check_link_lifetime timer\n");
/* TODO No more link lifetime checking now */
}
}
......
......@@ -24,6 +24,8 @@
#define PICO_IPV6_EXTHDR_NONE 59
#define PICO_IPV6_EXTHDR_DESTOPT 60
#define PICO_IPV6_EXTHDR_FRAG_SIZE 8
#define PICO_IPV6_EXTHDR_OPT_ROUTER_ALERT 5
#define PICO_IPV6_EXTHDR_OPT_ROUTER_ALERT_DATALEN 2
......@@ -59,15 +61,18 @@ struct pico_ipv6_link
struct pico_ip6 netmask;
uint8_t istentative : 1;
uint8_t isduplicate : 1;
uint8_t rs_retries;
uint32_t dad_timer;
uint16_t dup_detect_retrans;
uint8_t retrans;
pico_time expire_time;
pico_time rs_expire_time;
#ifdef PICO_SUPPORT_MCAST
struct pico_tree *MCASTGroups;
uint8_t mcast_compatibility;
uint8_t mcast_last_query_interval;
#endif
uint32_t mtu;
};
union pico_link {
......@@ -129,7 +134,7 @@ PACKED_STRUCT_DEF pico_ipv6_exthdr {
} ext;
};
int pico_ipv6_compare(struct pico_ip6 *a, struct pico_ip6 *b);
int pico_ipv6_compare(const struct pico_ip6 *a, const struct pico_ip6 *b);
int pico_string_to_ipv6(const char *ipstr, uint8_t *ip);
int pico_ipv6_to_string(char *ipbuf, const uint8_t ip[PICO_SIZE_IP6]);
int pico_ipv6_is_unicast(struct pico_ip6 *a);
......@@ -168,10 +173,10 @@ struct pico_ipv6_link *pico_ipv6_prefix_configured(struct pico_ip6 *prefix);
struct pico_ipv6_route *pico_ipv6_gateway_by_dev(struct pico_device *dev);
struct pico_ipv6_route *pico_ipv6_gateway_by_dev_next(struct pico_device *dev, struct pico_ipv6_route *last);
int pico_ipv6_lifetime_set(struct pico_ipv6_link *l, pico_time expire);
void pico_ipv6_check_lifetime_expired(pico_time now, void *arg);
void pico_ipv6_check_link_lifetime_expired(pico_time now, void *arg);
int pico_ipv6_dev_routing_enable(struct pico_device *dev);
int pico_ipv6_dev_routing_disable(struct pico_device *dev);
void pico_ipv6_router_down(struct pico_ip6 *address);
void pico_ipv6_router_down(const struct pico_ip6 *address);
int pico_ipv6_mcast_join(struct pico_ip6 *mcast_link, struct pico_ip6 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *_MCASTFilter);
int pico_ipv6_mcast_leave(struct pico_ip6 *mcast_link, struct pico_ip6 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *_MCASTFilter);
......
This diff is collapsed.
/*********************************************************************
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
See LICENSE and COPYING for usage.
.
Authors: Milan Platisa
*********************************************************************/
#include "pico_config.h"
#include "pico_stack.h"
#include "pico_tree.h"
#include "pico_ipv6.h"
#include "pico_ipv6_pmtu.h"
#define PICO_PMTU_CACHE_NEW (0)
#define PICO_PMTU_CACHE_UPDATED (1)
#define PICO_PMTU_CACHE_OLD (2)
#ifdef PICO_SUPPORT_IPV6PMTU
struct pico_ipv6_path_mtu {
struct pico_ipv6_path_id path;
uint32_t mtu;
int cache_status;
};
struct pico_ipv6_path_timer {
pico_time interval;
uint32_t id;
};
static int pico_ipv6_path_compare(void *ka, void *kb)
{
struct pico_ipv6_path_mtu *a = ka, *b = kb;
return pico_ipv6_compare(&((a->path).dst), &((b->path).dst));
}
static PICO_TREE_DECLARE(PathCache, pico_ipv6_path_compare);
static struct pico_ipv6_path_timer gc_timer = {
PICO_PMTU_CACHE_CLEANUP_INTERVAL, 0
};
uint32_t pico_ipv6_pmtu_get(const struct pico_ipv6_path_id *path)
{
struct pico_ipv6_path_mtu test;
struct pico_ipv6_path_mtu *found = NULL;
uint32_t mtu = 0;
if (path != NULL) {
test.path = *path;
found = pico_tree_findKey(&PathCache, &test);
if (found) {
mtu = found->mtu;
}
}
return mtu;
}
int pico_ipv6_path_add(const struct pico_ipv6_path_id *path, uint32_t mtu)
{
int status = PICO_PMTU_ERROR;
if (path != NULL && mtu >= PICO_IPV6_MIN_MTU) {
struct pico_ipv6_path_mtu test;
struct pico_ipv6_path_mtu *new = NULL;
test.path = *path;
new = pico_tree_findKey(&PathCache, &test);
if (new == NULL) {
new = PICO_ZALLOC(sizeof(struct pico_ipv6_path_mtu));
if (new != NULL) {
new->path = *path;
new->mtu = mtu;
new->cache_status = PICO_PMTU_CACHE_NEW;
pico_tree_insert(&PathCache, new);
status = PICO_PMTU_OK;
}
}
else {
new->mtu = mtu;
new->cache_status = PICO_PMTU_CACHE_NEW;
status = PICO_PMTU_OK;
}
}
return status;
}
int pico_ipv6_path_update(const struct pico_ipv6_path_id *path, uint32_t mtu)
{
int status = PICO_PMTU_ERROR;
if (path != NULL) {
struct pico_ipv6_path_mtu test;
struct pico_ipv6_path_mtu *found = NULL;
test.path = *path;
found = pico_tree_findKey(&PathCache, &test);
if (found) {
if (found->mtu > mtu) {
if (mtu < PICO_IPV6_MIN_MTU) {
mtu = PICO_IPV6_MIN_MTU;
}
found->mtu = mtu;
found->cache_status = PICO_PMTU_CACHE_UPDATED;
status = PICO_PMTU_OK;
}
}
}
return status;
}
int pico_ipv6_path_del(const struct pico_ipv6_path_id *path)
{
int status = PICO_PMTU_ERROR;
if (path != NULL) {
struct pico_ipv6_path_mtu test;
struct pico_ipv6_path_mtu *found = NULL;
test.path = *path;
found = pico_tree_findKey(&PathCache, &test);
if (found) {
pico_tree_delete(&PathCache, found);
PICO_FREE(found);
status = PICO_PMTU_OK;
}
}
return status;
}
static void pico_ipv6_path_gc(pico_time now, void *unused)
{
struct pico_tree_node *index = NULL, *_tmp = NULL;
IGNORE_PARAMETER(now);
IGNORE_PARAMETER(unused);
if(!pico_tree_empty(&PathCache)) {
pico_tree_foreach_safe(index, &PathCache, _tmp)
{
if(((struct pico_ipv6_path_mtu *)index->keyValue)->cache_status == PICO_PMTU_CACHE_OLD) {
pico_tree_delete(&PathCache, index->keyValue);
} else {
((struct pico_ipv6_path_mtu *)index->keyValue)->cache_status = PICO_PMTU_CACHE_OLD;
}
}
}
gc_timer.id = pico_timer_add(gc_timer.interval, &pico_ipv6_path_gc, NULL);
}
void pico_ipv6_path_init(pico_time interval)
{
gc_timer.interval = interval;
if (gc_timer.id != 0) {
pico_timer_cancel(gc_timer.id);
}
gc_timer.id = pico_timer_add(gc_timer.interval, &pico_ipv6_path_gc, NULL);
}
#endif
/*********************************************************************
PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
See LICENSE and COPYING for usage.
*********************************************************************/
#ifndef _INCLUDE_PICO_IPV6_PMTU
#define _INCLUDE_PICO_IPV6_PMTU
#include "pico_addressing.h"
#define PICO_PMTU_OK (0)
#define PICO_PMTU_ERROR (-1)
#define PICO_PMTU_CACHE_CLEANUP_INTERVAL (10 * (60 * 1000))
struct pico_ipv6_path_id {
struct pico_ip6 dst;
};
uint32_t pico_ipv6_pmtu_get(const struct pico_ipv6_path_id *path);
int pico_ipv6_path_add(const struct pico_ipv6_path_id *path, uint32_t mtu);
int pico_ipv6_path_update(const struct pico_ipv6_path_id *path, uint32_t mtu);
int pico_ipv6_path_del(const struct pico_ipv6_path_id *path);
void pico_ipv6_path_init(pico_time interval);
#endif
OPTIONS+=-DPICO_SUPPORT_IPV6 -DPICO_SUPPORT_ICMP6
MOD_OBJ+=$(LIBBASE)modules/pico_ipv6.o $(LIBBASE)modules/pico_ipv6_nd.o $(LIBBASE)modules/pico_icmp6.o
include rules/ipv6frag.mk
include rules/ipv6pmtu.mk
OPTIONS+=-DPICO_SUPPORT_IPV6PMTU
MOD_OBJ+=$(LIBBASE)modules/pico_ipv6_pmtu.o
......@@ -85,11 +85,12 @@ static int pico_6lowpan_store_info(struct pico_device *dev, const uint8_t *mac)
#ifdef PICO_SUPPORT_IPV6
static void device_init_ipv6_final(struct pico_device *dev, struct pico_ip6 *linklocal)
{
IGNORE_PARAMETER(linklocal);
dev->hostvars.basetime = PICO_ND_REACHABLE_TIME;
/* RFC 4861 $6.3.2 value between 0.5 and 1.5 times basetime */
dev->hostvars.reachabletime = ((5 + (pico_rand() % 10)) * PICO_ND_REACHABLE_TIME) / 10;
dev->hostvars.reachabletime = ((5 + (pico_rand() % 10)) * dev->hostvars.basetime) / 10;
dev->hostvars.retranstime = PICO_ND_RETRANS_TIMER;
pico_icmp6_router_solicitation(dev, linklocal, NULL);