X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fnetifd.git;a=blobdiff_plain;f=interface-ip.c;h=fa84fc76ed0a63f13dabb09f8e53fcb20b9932d2;hp=b681b817e3787700bc98d59096bd94c64250e2ee;hb=6094417533d97662f693d134ab04595a292de30c;hpb=0079ac42fcff0e703467c188c37db902ee8cead8 diff --git a/interface-ip.c b/interface-ip.c index b681b81..fa84fc7 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 @@ -131,14 +141,19 @@ interface_ip_add_target_route(union if_addr *addr, bool v6) { struct interface *iface; struct device_route *route, *r_next = NULL; + bool defaultroute_target = false; + int addrsize = v6 ? sizeof(addr->in6) : sizeof(addr->in); route = calloc(1, sizeof(*route)); if (!route) - return false; + return NULL; route->flags = v6 ? DEVADDR_INET6 : DEVADDR_INET4; route->mask = v6 ? 128 : 32; - memcpy(&route->addr, addr, v6 ? sizeof(addr->in6) : sizeof(addr->in)); + if (memcmp(&route->addr, addr, addrsize) == 0) + defaultroute_target = true; + else + memcpy(&route->addr, addr, addrsize); vlist_for_each_element(&interfaces, iface, node) { /* look for locally addressable target first */ @@ -150,8 +165,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)); @@ -160,7 +177,10 @@ interface_ip_add_target_route(union if_addr *addr, bool v6) done: route->iface = iface; - vlist_add(&iface->host_routes, &route->node, &route->flags); + if (defaultroute_target) + free(route); + else + vlist_add(&iface->host_routes, &route->node, &route->flags); return iface; } @@ -200,7 +220,7 @@ interface_ip_add_route(struct interface *iface, struct blob_attr *attr, bool v6) } if ((cur = tb[ROUTE_TARGET]) != NULL) { - if (!inet_pton(af, blobmsg_data(cur), &route->addr)) { + if (!parse_ip_and_netmask(af, blobmsg_data(cur), &route->addr, &route->mask)) { DPRINTF("Failed to parse route target: %s\n", (char *) blobmsg_data(cur)); goto error; } @@ -218,8 +238,10 @@ interface_ip_add_route(struct interface *iface, struct blob_attr *attr, bool v6) route->flags |= DEVROUTE_METRIC; } - if ((cur = tb[ROUTE_MTU]) != NULL) + if ((cur = tb[ROUTE_MTU]) != NULL) { route->mtu = blobmsg_get_u32(cur); + route->flags |= DEVROUTE_MTU; + } vlist_add(&ip->route, &route->node, &route->flags); return; @@ -243,6 +265,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 +313,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 +332,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); + } } }