X-Git-Url: https://git.archive.openwrt.org/?p=project%2Fnetifd.git;a=blobdiff_plain;f=interface-ip.c;h=6699d2e5616992c22c8c8236d152db6069a04ecd;hp=1a22980d81848016dda4652d993f753a729fd42e;hb=44c23888ad36a340ed6314728e073873240fcf0d;hpb=69c5043fdcea724f59055630eb0cf593c41732cb diff --git a/interface-ip.c b/interface-ip.c index 1a22980..6699d2e 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 @@ -134,7 +144,7 @@ interface_ip_add_target_route(union if_addr *addr, bool v6) route = calloc(1, sizeof(*route)); if (!route) - return false; + return NULL; route->flags = v6 ? DEVADDR_INET6 : DEVADDR_INET4; route->mask = v6 ? 128 : 32; @@ -150,8 +160,10 @@ interface_ip_add_target_route(union if_addr *addr, bool v6) interface_ip_find_route_target(iface, addr, v6, &r_next); } - if (!r_next) + if (!r_next) { + free(route); return NULL; + } iface = r_next->iface; memcpy(&route->nexthop, &r_next->nexthop, sizeof(route->nexthop)); @@ -243,6 +255,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 +303,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 +322,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 +378,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); @@ -544,8 +588,10 @@ void interface_ip_set_enabled(struct interface_ip_settings *ip, bool enabled) void interface_ip_update_start(struct interface_ip_settings *ip) { - vlist_simple_update(&ip->dns_servers); - vlist_simple_update(&ip->dns_search); + if (ip != &ip->iface->config_ip) { + vlist_simple_update(&ip->dns_servers); + vlist_simple_update(&ip->dns_search); + } vlist_update(&ip->route); vlist_update(&ip->addr); }