X-Git-Url: http://git.openwrt.org/?a=blobdiff_plain;f=interface-ip.c;h=14feb6fa6ddcdf41b353d6cd82c0c2347c1f9701;hb=1850d0350d3af11514744961d827a8b9facdaf00;hp=ed68116662f084942d0f27ebe42174cb3dce0468;hpb=23bb091077348d3b87b9900ae3ff923cdd25a662;p=project%2Fnetifd.git diff --git a/interface-ip.c b/interface-ip.c index ed68116..14feb6f 100644 --- a/interface-ip.c +++ b/interface-ip.c @@ -1,3 +1,16 @@ +/* + * netifd - network interface daemon + * Copyright (C) 2012 Felix Fietkau + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ #include #include #include @@ -37,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; - p1 = alloca(m_bytes); - p2 = alloca(m_bytes); + if (m_bytes < sizeof(a)) + memset(p + m_bytes, 0, sizeof(a) - m_bytes); - memcpy(p1, a1, m_bytes); - memcpy(p2, a2, m_bytes); + p[m_bytes - 1] &= ~m_clear; +} - p1[m_bytes - 1] &= ~m_clear; - p2[m_bytes - 1] &= ~m_clear; +static bool +match_if_addr(union if_addr *a1, union if_addr *a2, int mask) +{ + union if_addr *p1, *p2; + + p1 = alloca(sizeof(*a1)); + p2 = alloca(sizeof(*a2)); + + 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 @@ -229,6 +252,30 @@ route_cmp(const void *k1, const void *k2, void *ptr) offsetof(struct device_route, flags)); } +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, @@ -254,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); } } @@ -273,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); + } } } @@ -324,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); @@ -476,7 +531,8 @@ interface_write_resolv_conf(void) fprintf(f, "# Interface %s\n", iface->name); write_resolv_conf_entries(f, &iface->config_ip); - write_resolv_conf_entries(f, &iface->proto_ip); + if (!iface->proto_ip.no_dns) + write_resolv_conf_entries(f, &iface->proto_ip); } fclose(f); if (rename(path, resolv_conf) < 0) { @@ -530,8 +586,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); }