X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fnetifd.git;a=blobdiff_plain;f=interface-ip.c;h=1a22ce635206ad0cd2f85ad9c625593e11601de3;hp=715e49837266b7f68b247e10e46d5fc43f9c0f5d;hb=0b0e5e2fc5b065092644a5c4717c0a03a9098dcf;hpb=cd23fd6bf7983741b9a72bea78749278716248ec diff --git a/interface-ip.c b/interface-ip.c index 715e498..1a22ce6 100644 --- a/interface-ip.c +++ b/interface-ip.c @@ -75,8 +75,8 @@ clear_if_addr(union if_addr *a, int mask) uint8_t m_clear = (1 << (m_bytes * 8 - mask)) - 1; uint8_t *p = (uint8_t *) a; - if (m_bytes < sizeof(a)) - memset(p + m_bytes, 0, sizeof(a) - m_bytes); + if (m_bytes < sizeof(*a)) + memset(p + m_bytes, 0, sizeof(*a) - m_bytes); p[m_bytes - 1] &= ~m_clear; } @@ -365,6 +365,10 @@ interface_ip_add_route(struct interface *iface, struct blob_attr *attr, bool v6) goto error; } + /* only set the table flag if not using the main (default) table */ + if (system_is_default_rt_table(route->table)) + route->table = 0; + if (route->table) route->flags |= DEVROUTE_TABLE; } @@ -597,7 +601,7 @@ interface_update_proto_route(struct vlist_tree *tree, if (node_old && node_new) keep = !memcmp(&route_old->nexthop, &route_new->nexthop, sizeof(route_old->nexthop)) && (route_old->mtu == route_new->mtu) && (route_old->type == route_new->type) && - !route_old->failed; + (route_old->valid_until == route_new->valid_until) && !route_old->failed; if (node_old) { if (!(route_old->flags & DEVADDR_EXTERNAL) && route_old->enabled && !keep) @@ -644,6 +648,56 @@ interface_update_host_route(struct vlist_tree *tree, } } +static void +random_ifaceid(struct in6_addr *addr) +{ + static bool initialized = false; + struct timeval t; + + if (!initialized) { + long int seed = 0; + gettimeofday(&t, NULL); + seed = t.tv_sec ^ t.tv_usec ^ getpid(); + srand48(seed); + initialized = true; + } + addr->s6_addr32[2] = (uint32_t)mrand48(); + addr->s6_addr32[3] = (uint32_t)mrand48(); +} + +static void +eui64_ifaceid(struct interface *iface, struct in6_addr *addr) +{ + /* get mac address */ + uint8_t *macaddr = iface->l3_dev.dev->settings.macaddr; + uint8_t *ifaceid = addr->s6_addr + 8; + memcpy(ifaceid,macaddr,3); + memcpy(ifaceid + 5,macaddr + 3, 3); + ifaceid[3] = 0xff; + ifaceid[4] = 0xfe; + ifaceid[0] ^= 0x02; +} + +static void +generate_ifaceid(struct interface *iface, struct in6_addr *addr) +{ + /* generate new iface id */ + switch (iface->assignment_iface_id_selection) { + case IFID_FIXED: + /* fixed */ + /* copy host part from assignment_fixed_iface_id */ + memcpy(addr->s6_addr + 8, iface->assignment_fixed_iface_id.s6_addr + 8, 8); + break; + case IFID_RANDOM: + /* randomize last 64 bits */ + random_ifaceid(addr); + break; + case IFID_EUI64: + /* eui64 */ + eui64_ifaceid(iface, addr); + break; + } +} static void interface_set_prefix_address(struct device_prefix_assignment *assignment, @@ -657,21 +711,35 @@ interface_set_prefix_address(struct device_prefix_assignment *assignment, struct device_addr addr; memset(&addr, 0, sizeof(addr)); - addr.addr.in6 = prefix->addr; - addr.addr.in6.s6_addr32[1] |= htonl(assignment->assigned); - addr.addr.in6.s6_addr[15] += 1; + + if (IN6_IS_ADDR_UNSPECIFIED(&assignment->addr)) { + addr.addr.in6 = prefix->addr; + addr.addr.in6.s6_addr32[1] |= htonl(assignment->assigned); + generate_ifaceid(iface, &addr.addr.in6); + assignment->addr = addr.addr.in6; + } + else + addr.addr.in6 = assignment->addr; + addr.mask = assignment->length; addr.flags = DEVADDR_INET6; addr.preferred_until = prefix->preferred_until; addr.valid_until = prefix->valid_until; + if (addr.mask < 64) { + addr.mask = 64; + system_del_address(l3_downlink, &addr); + addr.mask = assignment->length; + } + if (!add && assignment->enabled) { time_t now = system_get_rtime(); addr.preferred_until = now; if (!addr.valid_until || addr.valid_until - now > 7200) addr.valid_until = now + 7200; + system_del_address(l3_downlink, &addr); // Work around dangling prefix routes - system_add_address(l3_downlink, &addr); + if (prefix->iface) { if (prefix->iface->ip6table) set_ip_source_policy(false, true, IPRULE_PRIORITY_NW, &addr.addr, @@ -681,9 +749,17 @@ interface_set_prefix_address(struct device_prefix_assignment *assignment, addr.mask, 0, iface, "unreachable"); } + if (addr.mask < 64) + addr.mask = 64; + + interface_handle_subnet_route(iface, &addr, false); + system_add_address(l3_downlink, &addr); + assignment->enabled = false; } else if (add && (iface->state == IFS_UP || iface->state == IFS_SETUP) && !system_add_address(l3_downlink, &addr)) { + interface_handle_subnet_route(iface, &addr, false); + if (prefix->iface && !assignment->enabled) { set_ip_source_policy(true, true, IPRULE_PRIORITY_REJECT, &addr.addr, addr.mask, 0, iface, "unreachable"); @@ -692,12 +768,19 @@ interface_set_prefix_address(struct device_prefix_assignment *assignment, set_ip_source_policy(true, true, IPRULE_PRIORITY_NW, &addr.addr, addr.mask, prefix->iface->ip6table, iface, NULL); } + + if (addr.mask < 64) + addr.mask = 64; + + interface_handle_subnet_route(iface, &addr, true); + if (uplink && uplink->l3_dev.dev) { int mtu = system_update_ipv6_mtu( uplink->l3_dev.dev, 0); if (mtu > 0) system_update_ipv6_mtu(l3_downlink, mtu); } + assignment->enabled = true; } } @@ -749,6 +832,7 @@ static void interface_update_prefix_assignments(struct device_prefix *prefix, bo c->assigned = 1 << (64 - prefix->length); c->length = 64; c->name[0] = 0; + c->addr = in6addr_any; list_add(&c->head, &prefix->assignments); // Excluded prefix @@ -758,6 +842,7 @@ static void interface_update_prefix_assignments(struct device_prefix *prefix, bo c->assigned = ntohl(prefix->excl_addr.s6_addr32[1]) & ((1 << (64 - prefix->length)) - 1); c->length = prefix->excl_length; + c->addr = in6addr_any; memcpy(c->name, name, sizeof(name)); list_add(&c->head, &prefix->assignments); } @@ -789,6 +874,7 @@ static void interface_update_prefix_assignments(struct device_prefix *prefix, bo c = malloc(sizeof(*c) + namelen); c->length = iface->assignment_length; c->assigned = iface->assignment_hint; + c->addr = in6addr_any; c->enabled = false; memcpy(c->name, iface->name, namelen); @@ -1128,9 +1214,11 @@ void interface_ip_set_enabled(struct interface_ip_settings *ip, bool enabled) struct device_addr *addr; struct device_route *route; struct device *dev; + struct interface *iface; ip->enabled = enabled; - dev = ip->iface->l3_dev.dev; + iface = ip->iface; + dev = iface->l3_dev.dev; if (!dev) return; @@ -1138,10 +1226,14 @@ void interface_ip_set_enabled(struct interface_ip_settings *ip, bool enabled) if (addr->enabled == enabled) continue; - if (enabled) + if (enabled) { system_add_address(dev, addr); - else + if ((addr->flags & DEVADDR_OFFLINK) || iface->metric) + interface_handle_subnet_route(iface, addr, true); + } else { + interface_handle_subnet_route(iface, addr, false); system_del_address(dev, addr); + } addr->enabled = enabled; }