X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fnetifd.git;a=blobdiff_plain;f=interface-ip.c;h=14feb6fa6ddcdf41b353d6cd82c0c2347c1f9701;hp=3b545ca1dfec2db4c520b6e3b2323e374140540f;hb=8758677c03d3c94d3fd81c8e44b3a7307b693e9c;hpb=b0b11b2295fbb8399949139d82156e123e005902 diff --git a/interface-ip.c b/interface-ip.c index 3b545ca..14feb6f 100644 --- a/interface-ip.c +++ b/interface-ip.c @@ -50,23 +50,33 @@ const struct config_param_list route_attr_list = { .params = route_attr, }; -static bool -match_if_addr(union if_addr *a1, union if_addr *a2, int mask) +static void +clear_if_addr(union if_addr *a, int mask) { - uint8_t *p1, *p2; int m_bytes = (mask + 7) / 8; 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); + + p[m_bytes - 1] &= ~m_clear; +} - p1 = alloca(m_bytes); - p2 = alloca(m_bytes); +static bool +match_if_addr(union if_addr *a1, union if_addr *a2, int mask) +{ + union if_addr *p1, *p2; - memcpy(p1, a1, m_bytes); - memcpy(p2, a2, m_bytes); + p1 = alloca(sizeof(*a1)); + p2 = alloca(sizeof(*a2)); - p1[m_bytes - 1] &= ~m_clear; - p2[m_bytes - 1] &= ~m_clear; + memcpy(p1, a1, sizeof(*a1)); + clear_if_addr(p1, mask); + memcpy(p2, a2, sizeof(*a2)); + clear_if_addr(p2, mask); - return !memcmp(p1, p2, m_bytes); + return !memcmp(p1, p2, sizeof(*p1)); } static bool @@ -243,6 +253,30 @@ route_cmp(const void *k1, const void *k2, void *ptr) } static void +interface_handle_subnet_route(struct interface *iface, struct device_addr *addr, bool add) +{ + struct device *dev = iface->l3_dev.dev; + struct device_route route; + + route.iface = iface; + route.flags = addr->flags; + route.mask = addr->mask; + memcpy(&route.addr, &addr->addr, sizeof(route.addr)); + clear_if_addr(&route.addr, route.mask); + + if (add) { + route.flags |= DEVADDR_KERNEL; + system_del_route(dev, &route); + + route.flags &= ~DEVADDR_KERNEL; + route.metric = iface->metric; + system_add_route(dev, &route); + } else { + system_del_route(dev, &route); + } +} + +static void interface_update_proto_addr(struct vlist_tree *tree, struct vlist_node *node_new, struct vlist_node *node_old) @@ -267,7 +301,7 @@ interface_update_proto_addr(struct vlist_tree *tree, uint32_t *a = (uint32_t *) &a_new->addr; mask >>= a_new->mask; - a_new->broadcast = *a | mask; + a_new->broadcast = *a | htonl(mask); } } @@ -286,15 +320,20 @@ interface_update_proto_addr(struct vlist_tree *tree, } if (node_old) { - if (!(a_old->flags & DEVADDR_EXTERNAL) && a_old->enabled && !keep) + if (!(a_old->flags & DEVADDR_EXTERNAL) && a_old->enabled && !keep) { + interface_handle_subnet_route(iface, a_old, false); system_del_address(dev, a_old); + } free(a_old); } if (node_new) { - if (!(a_new->flags & DEVADDR_EXTERNAL) && !keep) - system_add_address(dev, a_new); a_new->enabled = true; + if (!(a_new->flags & DEVADDR_EXTERNAL) && !keep) { + system_add_address(dev, a_new); + if (iface->metric) + interface_handle_subnet_route(iface, a_new, true); + } } } @@ -337,6 +376,9 @@ interface_update_proto_route(struct vlist_tree *tree, if (node_new) { bool _enabled = enable_route(ip, route_new); + if (!(route_new->flags & DEVROUTE_METRIC)) + route_new->metric = iface->metric; + if (!(route_new->flags & DEVADDR_EXTERNAL) && !keep && _enabled) system_add_route(dev, route_new);