Commit c9a53e3c authored by Daniele Lacamera's avatar Daniele Lacamera

Implemented RA address lifetime.

parent acd11af5
......@@ -47,6 +47,8 @@ struct pico_device*pico_get_device(const char*name);
int32_t pico_device_broadcast(struct pico_frame *f);
int pico_device_link_state(struct pico_device *dev);
int pico_device_ipv6_random_ll(struct pico_device *dev);
int pico_ipv6_link_add_local(struct pico_device *dev, const struct pico_ip6 *prefix);
#ifdef PICO_SUPPORT_IPV6
struct pico_ipv6_link *pico_ipv6_link_add_local(struct pico_device *dev, const struct pico_ip6 *prefix);
#endif
#endif
......@@ -1284,7 +1284,7 @@ void pico_ipv6_nd_dad(pico_time now, void *arg)
}
int pico_ipv6_link_add(struct pico_device *dev, struct pico_ip6 address, struct pico_ip6 netmask)
struct pico_ipv6_link *pico_ipv6_link_add(struct pico_device *dev, struct pico_ip6 address, struct pico_ip6 netmask)
{
struct pico_ipv6_link test = {
0
......@@ -1300,7 +1300,7 @@ int pico_ipv6_link_add(struct pico_device *dev, struct pico_ip6 address, struct
if (!dev) {
pico_err = PICO_ERR_EINVAL;
return -1;
return NULL;
}
test.address = address;
......@@ -1310,7 +1310,7 @@ int pico_ipv6_link_add(struct pico_device *dev, struct pico_ip6 address, struct
if (pico_tree_findKey(&IPV6Links, &test)) {
dbg("IPv6: trying to assign an invalid address (in use)\n");
pico_err = PICO_ERR_EADDRINUSE;
return -1;
return NULL;
}
/** XXX: Check for network already in use (e.g. trying to assign 10.0.0.1/24 where 10.1.0.1/8 is in use) **/
......@@ -1318,7 +1318,7 @@ int pico_ipv6_link_add(struct pico_device *dev, struct pico_ip6 address, struct
if (!new) {
dbg("IPv6: out of memory!\n");
pico_err = PICO_ERR_ENOMEM;
return -1;
return NULL;
}
new->address = address;
......@@ -1349,7 +1349,7 @@ int pico_ipv6_link_add(struct pico_device *dev, struct pico_ip6 address, struct
pico_ipv6_to_string(ipstr, new->address.addr);
dbg("Assigned ipv6 %s to device %s\n", ipstr, new->dev->name);
return 0;
return new;
}
int pico_ipv6_cleanup_routes(struct pico_ipv6_link *link)
......@@ -1401,6 +1401,8 @@ int pico_ipv6_link_del(struct pico_device *dev, struct pico_ip6 address)
pico_ipv6_cleanup_routes(found);
pico_tree_delete(&IPV6Links, found);
if (found->lifetimer)
pico_timer_cancel(found->lifetimer);
/* XXX MUST leave the solicited-node multicast address corresponding to the address (RFC 4861 $7.2.1) */
PICO_FREE(found);
return 0;
......@@ -1560,7 +1562,36 @@ struct pico_ipv6_link *pico_ipv6_global_get(struct pico_device *dev)
return link;
}
#define TWO_HOURS ((pico_time)(1000 * 60 * 60 * 2))
void pico_ipv6_lifetime_expired(pico_time now, void *arg)
{
struct pico_ipv6_link *link = (struct pico_ipv6_link *)arg;
(void)now;
dbg("Warning: IPv6 address has expired.\n");
link->lifetimer = NULL;
pico_ipv6_link_del(link->dev, link->address);
}
int pico_ipv6_lifetime_set(struct pico_ipv6_link *l, pico_time expire)
{
pico_time now = PICO_TIME_MS();
if (expire <= now) {
return -1;
}
if (l->lifetimer) {
pico_timer_cancel(l->lifetimer);
}
if (expire > 0xFFFFFFFE) {
return 0;
}else if ((expire > (now + TWO_HOURS)) || (expire > l->expire_time)) {
l->expire_time = expire;
} else {
l->expire_time = now + TWO_HOURS;
}
l->lifetimer = pico_timer_add(l->expire_time - now, pico_ipv6_lifetime_expired, l);
return 0;
}
int pico_ipv6_dev_routing_enable(struct pico_device *dev)
{
......
......@@ -44,6 +44,8 @@ struct pico_ipv6_link
struct pico_ip6 netmask;
uint8_t istentative : 1;
uint8_t isduplicate : 1;
pico_time expire_time;
struct pico_timer *lifetimer;
};
struct pico_ipv6_hbhoption {
......@@ -112,7 +114,7 @@ int pico_ipv6_frame_push(struct pico_frame *f, struct pico_ip6 *dst, uint8_t pro
int pico_ipv6_route_add(struct pico_ip6 address, struct pico_ip6 netmask, struct pico_ip6 gateway, int metric, struct pico_ipv6_link *link);
void pico_ipv6_unreachable(struct pico_frame *f, uint8_t code);
int pico_ipv6_link_add(struct pico_device *dev, struct pico_ip6 address, struct pico_ip6 netmask);
struct pico_ipv6_link *pico_ipv6_link_add(struct pico_device *dev, struct pico_ip6 address, struct pico_ip6 netmask);
int pico_ipv6_link_del(struct pico_device *dev, struct pico_ip6 address);
int pico_ipv6_cleanup_links(struct pico_device *dev);
struct pico_ipv6_link *pico_ipv6_link_istentative(struct pico_ip6 *address);
......@@ -127,6 +129,7 @@ struct pico_ipv6_link *pico_ipv6_global_get(struct pico_device *dev);
struct pico_ipv6_link *pico_ipv6_linklocal_get(struct pico_device *dev);
struct pico_ipv6_link *pico_ipv6_sitelocal_get(struct pico_device *dev);
struct pico_ipv6_link *pico_ipv6_prefix_configured(struct pico_ip6 *prefix);
int pico_ipv6_lifetime_set(struct pico_ipv6_link *l, pico_time expire);
int pico_ipv6_dev_routing_enable(struct pico_device *dev);
int pico_ipv6_dev_routing_disable(struct pico_device *dev);
#endif
......@@ -554,6 +554,7 @@ static int radv_process(struct pico_frame *f)
{
struct pico_icmp6_hdr *icmp6_hdr = NULL;
uint8_t *nxtopt, *opt_start;
struct pico_ipv6_link *link;
int optlen;
icmp6_hdr = (struct pico_icmp6_hdr *)f->transport_hdr;
......@@ -566,6 +567,7 @@ static int radv_process(struct pico_frame *f)
switch (*type) {
case PICO_ND_OPT_PREFIX:
{
pico_time now = PICO_TIME_MS();
struct pico_icmp6_opt_prefix *prefix =
(struct pico_icmp6_opt_prefix *) nxtopt;
/* RFC4862 5.5.3 */
......@@ -582,9 +584,11 @@ static int radv_process(struct pico_frame *f)
/* c) If the preferred lifetime is greater than the valid lifetime,
* silently ignore the Prefix Information option
*/
if (prefix->val_lifetime <= 0)
if (long_be(prefix->pref_lifetime) > long_be(prefix->val_lifetime))
goto ignore_opt_prefix;
if (prefix->val_lifetime <= 0)
goto ignore_opt_prefix;
if (prefix->prefix_len != 64) {
......@@ -593,10 +597,14 @@ static int radv_process(struct pico_frame *f)
return -1;
}
if (pico_ipv6_prefix_configured(&prefix->prefix)) {
link = pico_ipv6_prefix_configured(&prefix->prefix);
if (link) {
pico_ipv6_lifetime_set(link, now + (pico_time)(1000 * (long_be(prefix->pref_lifetime))));
goto ignore_opt_prefix;
}
pico_ipv6_link_add_local(f->dev, &prefix->prefix);
link = pico_ipv6_link_add_local(f->dev, &prefix->prefix);
if (link)
pico_ipv6_lifetime_set(link, now + (pico_time)(1000 * (long_be(prefix->val_lifetime))));
ignore_opt_prefix:
optlen -= (prefix->len << 3);
nxtopt += (prefix->len << 3);
......
......@@ -51,10 +51,11 @@ static void device_init_ipv6_final(struct pico_device *dev, struct pico_ip6 *lin
dev->hostvars.hoplimit = PICO_IPV6_DEFAULT_HOP;
}
int pico_ipv6_link_add_local(struct pico_device *dev, const struct pico_ip6 *prefix)
struct pico_ipv6_link *pico_ipv6_link_add_local(struct pico_device *dev, const struct pico_ip6 *prefix)
{
struct pico_ip6 newaddr;
struct pico_ip6 netmask64 = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
struct pico_ipv6_link *link;
memcpy(newaddr.addr, prefix->addr, PICO_SIZE_IP6);
/* modified EUI-64 + invert universal/local bit */
newaddr.addr[8] = (dev->eth->mac.addr[0] ^ 0x02);
......@@ -65,11 +66,11 @@ int pico_ipv6_link_add_local(struct pico_device *dev, const struct pico_ip6 *pre
newaddr.addr[13] = dev->eth->mac.addr[3];
newaddr.addr[14] = dev->eth->mac.addr[4];
newaddr.addr[15] = dev->eth->mac.addr[5];
if (pico_ipv6_link_add(dev, newaddr, netmask64) == 0) {
link = pico_ipv6_link_add(dev, newaddr, netmask64);
if (link) {
device_init_ipv6_final(dev, &newaddr);
return 0;
}
return -1;
return link;
}
#endif
......@@ -82,7 +83,7 @@ static int device_init_mac(struct pico_device *dev, uint8_t *mac)
if (dev->eth) {
memcpy(dev->eth->mac.addr, mac, PICO_SIZE_ETH);
#ifdef PICO_SUPPORT_IPV6
if (pico_ipv6_link_add_local(dev, &linklocal)) {
if (pico_ipv6_link_add_local(dev, &linklocal) == NULL) {
PICO_FREE(dev->q_in);
PICO_FREE(dev->q_out);
PICO_FREE(dev->eth);
......@@ -118,7 +119,7 @@ int pico_device_ipv6_random_ll(struct pico_device *dev)
pico_rand_feed(dev->hash);
} while (pico_ipv6_link_get(&linklocal));
if (pico_ipv6_link_add(dev, linklocal, netmask6)) {
if (pico_ipv6_link_add(dev, linklocal, netmask6) == NULL) {
return -1;
}
}
......
......@@ -226,7 +226,7 @@ START_TEST (test_ipv6)
dev[i] = pico_null_create(devname);
a[i] = iphex_a;
a[i].addr[4] += i;
fail_if(pico_ipv6_link_add(dev[i], a[i], nm64) != 0, "Error adding link");
fail_if(pico_ipv6_link_add(dev[i], a[i], nm64) == NULL, "Error adding link");
}
/*link_find + link_get + route_add*/
for (i = 0; i < 10; ++i) {
......@@ -252,10 +252,10 @@ START_TEST (test_ipv6)
fail_if(pico_ipv6_link_del(dev[i], a[i]) != 0, "Error deleting link");
}
/* add 2 links to dev[0] */
ret = pico_ipv6_link_add(dev[0], a[0], nm64);
fail_if(ret != 0, "Error adding link");
ret = pico_ipv6_link_add(dev[0], a[1], nm64);
fail_if(ret != 0, "Error adding link");
_link = pico_ipv6_link_add(dev[0], a[0], nm64);
fail_if (!_link, "Error adding link");
_link = pico_ipv6_link_add(dev[0], a[1], nm64);
fail_if (!_link, "Error adding link");
/* add 2 routes to each of the links */
ret = pico_ipv6_route_add(r[0], nm128, a[0], 1, l[0]);
fail_if(ret != 0, "Error adding route");
......@@ -267,10 +267,10 @@ START_TEST (test_ipv6)
fail_if(ret != 0, "Error adding route");
/* add 2 links to dev[1] */
ret = pico_ipv6_link_add(dev[1], a[8], nm64);
fail_if(ret != 0, "Error adding link");
ret = pico_ipv6_link_add(dev[1], a[9], nm64);
fail_if(ret != 0, "Error adding link");
_link = pico_ipv6_link_add(dev[1], a[8], nm64);
fail_if (!_link, "Error adding link");
_link = pico_ipv6_link_add(dev[1], a[9], nm64);
fail_if (!_link, "Error adding link");
/* add 2 routes to each of the links */
ret = pico_ipv6_route_add(r[6], nm128, a[8], 1, l[8]);
fail_if(ret != 0, "Error adding route");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment