diff options
Diffstat (limited to 'interface-ip.c')
-rw-r--r-- | interface-ip.c | 149 |
1 files changed, 148 insertions, 1 deletions
diff --git a/interface-ip.c b/interface-ip.c index 83f1dfa..22c21d7 100644 --- a/interface-ip.c +++ b/interface-ip.c @@ -20,6 +20,10 @@ #include <arpa/inet.h> #include <netinet/in.h> +#ifdef linux +#include <netinet/ether.h> +#endif + #include "netifd.h" #include "device.h" #include "interface.h" @@ -64,6 +68,28 @@ const struct uci_blob_param_list route_attr_list = { .params = route_attr, }; +enum { + NEIGHBOR_INTERFACE, + NEIGHBOR_ADDRESS, + NEIGHBOR_MAC, + NEIGHBOR_PROXY, + NEIGHBOR_ROUTER, + __NEIGHBOR_MAX +}; + +static const struct blobmsg_policy neighbor_attr[__NEIGHBOR_MAX]={ + [NEIGHBOR_INTERFACE]= { .name = "interface", .type = BLOBMSG_TYPE_STRING}, + [NEIGHBOR_ADDRESS]= { .name = "ipaddr", .type = BLOBMSG_TYPE_STRING}, + [NEIGHBOR_MAC]= { .name = "mac", .type = BLOBMSG_TYPE_STRING}, + [NEIGHBOR_PROXY]= { .name = "proxy", .type = BLOBMSG_TYPE_BOOL}, + [NEIGHBOR_ROUTER]= {.name = "router", .type = BLOBMSG_TYPE_BOOL}, +}; + +const struct uci_blob_param_list neighbor_attr_list = { + .n_params = __NEIGHBOR_MAX, + .params = neighbor_attr, +}; + struct list_head prefixes = LIST_HEAD_INIT(prefixes); static struct device_prefix *ula_prefix = NULL; @@ -299,6 +325,64 @@ interface_set_route_info(struct interface *iface, struct device_route *route) } void +interface_ip_add_neighbor(struct interface *iface, struct blob_attr *attr, bool v6) +{ + struct interface_ip_settings *ip; + struct blob_attr *tb[__NEIGHBOR_MAX], *cur; + struct device_neighbor *neighbor; + int af = v6 ? AF_INET6: AF_INET; + struct ether_addr *ea; + + blobmsg_parse(neighbor_attr, __NEIGHBOR_MAX, tb, blobmsg_data(attr), blobmsg_data_len(attr)); + + if (!iface) { + if ((cur = tb[NEIGHBOR_INTERFACE]) == NULL) + return; + + iface = vlist_find(&interfaces, blobmsg_data(cur), iface, node); + + if (!iface) + return; + + ip = &iface->config_ip; + } else + ip = &iface->proto_ip; + + neighbor = calloc(1,sizeof(*neighbor)); + neighbor->flags = v6 ? DEVADDR_INET6 : DEVADDR_INET4; + + if (!neighbor) + return; + + if ((cur = tb[NEIGHBOR_ADDRESS]) != NULL){ + if (!inet_pton(af, blobmsg_data(cur), &neighbor->addr)) + goto error; + } else + goto error; + + if ((cur = tb[NEIGHBOR_MAC]) != NULL) { + neighbor->flags |= DEVNEIGH_MAC; + ea = ether_aton(blobmsg_data(cur)); + if (!ea) + goto error; + + memcpy(neighbor->macaddr, ea, 6); + } + + if ((cur = tb[NEIGHBOR_PROXY]) != NULL) + neighbor->proxy = blobmsg_get_bool(cur); + + if ((cur = tb[NEIGHBOR_ROUTER]) != NULL) + neighbor->router = blobmsg_get_bool(cur); + + vlist_add(&ip->neighbor, &neighbor->node, neighbor); + return; + +error: + free(neighbor); +} + +void interface_ip_add_route(struct interface *iface, struct blob_attr *attr, bool v6) { struct interface_ip_settings *ip; @@ -429,6 +513,14 @@ addr_cmp(const void *k1, const void *k2, void *ptr) } static int +neighbor_cmp(const void *k1, const void *k2, void *ptr) +{ + const struct device_neighbor *n1 = k1, *n2 = k2; + + return memcmp(&n1->addr, &n2->addr, sizeof(n2->addr)); +} + +static int route_cmp(const void *k1, const void *k2, void *ptr) { const struct device_route *r1 = k1, *r2 = k2; @@ -625,6 +717,44 @@ enable_route(struct interface_ip_settings *ip, struct device_route *route) } static void +interface_update_proto_neighbor(struct vlist_tree *tree, + struct vlist_node * node_new, + struct vlist_node *node_old) +{ + struct device *dev; + struct device_neighbor *neighbor_old, *neighbor_new; + struct interface_ip_settings *ip; + bool keep = false; + + ip = container_of(tree, struct interface_ip_settings, neighbor); + dev = ip->iface->l3_dev.dev; + + neighbor_old = container_of(node_old, struct device_neighbor, node); + neighbor_new = container_of(node_new, struct device_neighbor, node); + + if (node_old && node_new) { + keep = (!memcmp(neighbor_old->macaddr, neighbor_new->macaddr, sizeof(neighbor_old->macaddr)) && + (neighbor_old->proxy == neighbor_new->proxy) && + (neighbor_old->router == neighbor_new->router)); + } + + if (node_old) { + if (!keep && neighbor_old->enabled) + system_del_neighbor(dev, neighbor_old); + + free(neighbor_old); + } + + if (node_new) { + if (!keep && ip->enabled) + if (system_add_neighbor(dev, neighbor_new)) + neighbor_new->failed = true; + + neighbor_new->enabled = ip->enabled; + } +} + +static void interface_update_proto_route(struct vlist_tree *tree, struct vlist_node *node_new, struct vlist_node *node_old) @@ -1394,6 +1524,7 @@ void interface_ip_set_enabled(struct interface_ip_settings *ip, bool enabled) { struct device_addr *addr; struct device_route *route; + struct device_neighbor *neighbor; struct device *dev; struct interface *iface; @@ -1439,7 +1570,6 @@ void interface_ip_set_enabled(struct interface_ip_settings *ip, bool enabled) if (!enable_route(ip, route)) _enabled = false; - if (route->enabled == _enabled) continue; @@ -1453,6 +1583,19 @@ void interface_ip_set_enabled(struct interface_ip_settings *ip, bool enabled) route->enabled = _enabled; } + vlist_for_each_element(&ip->neighbor, neighbor, node) { + if (neighbor->enabled == enabled) + continue; + + if (enabled) { + if(system_add_neighbor(dev, neighbor)) + neighbor->failed = true; + } else + system_del_neighbor(dev, neighbor); + + neighbor->enabled = enabled; + } + struct device_prefix *c; struct device_prefix_assignment *a; list_for_each_entry(c, &prefixes, head) @@ -1481,6 +1624,7 @@ interface_ip_update_start(struct interface_ip_settings *ip) vlist_update(&ip->route); vlist_update(&ip->addr); vlist_update(&ip->prefix); + vlist_update(&ip->neighbor); } void @@ -1491,6 +1635,7 @@ interface_ip_update_complete(struct interface_ip_settings *ip) vlist_flush(&ip->route); vlist_flush(&ip->addr); vlist_flush(&ip->prefix); + vlist_flush(&ip->neighbor); interface_write_resolv_conf(); } @@ -1503,6 +1648,7 @@ interface_ip_flush(struct interface_ip_settings *ip) vlist_simple_flush_all(&ip->dns_search); vlist_flush_all(&ip->route); vlist_flush_all(&ip->addr); + vlist_flush_all(&ip->neighbor); vlist_flush_all(&ip->prefix); } @@ -1514,6 +1660,7 @@ __interface_ip_init(struct interface_ip_settings *ip, struct interface *iface) vlist_simple_init(&ip->dns_search, struct dns_search_domain, node); vlist_simple_init(&ip->dns_servers, struct dns_server, node); vlist_init(&ip->route, route_cmp, interface_update_proto_route); + vlist_init(&ip->neighbor, neighbor_cmp, interface_update_proto_neighbor); vlist_init(&ip->addr, addr_cmp, interface_update_proto_addr); vlist_init(&ip->prefix, prefix_cmp, interface_update_prefix); } |