IPv6: fix prefix assignment with continuous hints
[project/netifd.git] / ubus.c
diff --git a/ubus.c b/ubus.c
index 2fd9e92..f203fd1 100644 (file)
--- a/ubus.c
+++ b/ubus.c
@@ -50,12 +50,14 @@ netifd_handle_reload(struct ubus_context *ctx, struct ubus_object *obj,
 enum {
        HR_TARGET,
        HR_V6,
+       HR_INTERFACE,
        __HR_MAX
 };
 
 static const struct blobmsg_policy route_policy[__HR_MAX] = {
        [HR_TARGET] = { .name = "target", .type = BLOBMSG_TYPE_STRING },
        [HR_V6] = { .name = "v6", .type = BLOBMSG_TYPE_BOOL },
+       [HR_INTERFACE] = { .name = "interface", .type = BLOBMSG_TYPE_STRING },
 };
 
 static int
@@ -64,7 +66,7 @@ netifd_add_host_route(struct ubus_context *ctx, struct ubus_object *obj,
                      struct blob_attr *msg)
 {
        struct blob_attr *tb[__HR_MAX];
-       struct interface *iface;
+       struct interface *iface = NULL;
        union if_addr a;
        bool v6 = false;
 
@@ -75,12 +77,15 @@ netifd_add_host_route(struct ubus_context *ctx, struct ubus_object *obj,
        if (tb[HR_V6])
                v6 = blobmsg_get_bool(tb[HR_V6]);
 
+       if (tb[HR_INTERFACE])
+               iface = vlist_find(&interfaces, blobmsg_data(tb[HR_INTERFACE]), iface, node);
+
        memset(&a, 0, sizeof(a));
        if (!inet_pton(v6 ? AF_INET6 : AF_INET, blobmsg_data(tb[HR_TARGET]), &a))
                return UBUS_STATUS_INVALID_ARGUMENT;
 
 
-       iface = interface_ip_add_target_route(&a, v6);
+       iface = interface_ip_add_target_route(&a, v6, iface);
        if (!iface)
                return UBUS_STATUS_NOT_FOUND;
 
@@ -347,6 +352,7 @@ interface_ip_dump_address_list(struct interface_ip_settings *ip, bool v6,
        int buflen = 128;
        int af;
 
+       time_t now = system_get_rtime();
        vlist_for_each_element(&ip->addr, addr, node) {
                if (addr->enabled != enabled)
                        continue;
@@ -367,6 +373,16 @@ interface_ip_dump_address_list(struct interface_ip_settings *ip, bool v6,
 
                blobmsg_add_u32(&b, "mask", addr->mask);
 
+               if (addr->preferred_until) {
+                       int preferred = addr->preferred_until - now;
+                       if (preferred < 0)
+                               preferred = 0;
+                       blobmsg_add_u32(&b, "preferred", preferred);
+               }
+
+               if (addr->valid_until)
+                       blobmsg_add_u32(&b, "valid", addr->valid_until - now);
+
                blobmsg_close_table(&b, a);
        }
 }
@@ -380,6 +396,7 @@ interface_ip_dump_route_list(struct interface_ip_settings *ip, bool enabled)
        void *r;
        int af;
 
+       time_t now = system_get_rtime();
        vlist_for_each_element(&ip->route, route, node) {
                if (route->enabled != enabled)
                        continue;
@@ -407,6 +424,12 @@ interface_ip_dump_route_list(struct interface_ip_settings *ip, bool enabled)
                if (route->flags & DEVROUTE_METRIC)
                        blobmsg_add_u32(&b, "metric", route->metric);
 
+               if (route->flags & DEVROUTE_TABLE)
+                       blobmsg_add_u32(&b, "table", route->table);
+
+               if (route->valid_until)
+                       blobmsg_add_u32(&b, "valid", route->valid_until - now);
+
                blobmsg_close_table(&b, r);
        }
 }
@@ -420,6 +443,7 @@ interface_ip_dump_prefix_list(struct interface_ip_settings *ip)
        void *a, *c;
        const int buflen = INET6_ADDRSTRLEN;
 
+       time_t now = system_get_rtime();
        vlist_for_each_element(&ip->prefix, prefix, node) {
                a = blobmsg_open_table(&b, NULL);
 
@@ -429,7 +453,6 @@ interface_ip_dump_prefix_list(struct interface_ip_settings *ip)
 
                blobmsg_add_u32(&b, "mask", prefix->length);
 
-               time_t now = system_get_rtime();
                if (prefix->preferred_until) {
                        int preferred = prefix->preferred_until - now;
                        if (preferred < 0)
@@ -437,20 +460,24 @@ interface_ip_dump_prefix_list(struct interface_ip_settings *ip)
                        blobmsg_add_u32(&b, "preferred", preferred);
                }
 
-               if (prefix->valid_until) {
-                       int valid = prefix->valid_until - now;
-                       if (valid < 0)
-                               valid = 0;
-                       blobmsg_add_u32(&b, "valid", valid);
-               }
+               if (prefix->valid_until)
+                       blobmsg_add_u32(&b, "valid", prefix->valid_until - now);
+
+               blobmsg_add_string(&b, "class", prefix->pclass);
 
                c = blobmsg_open_table(&b, "assigned");
                struct device_prefix_assignment *assign;
-               vlist_for_each_element(prefix->assignments, assign, node) {
+               list_for_each_entry(assign, &prefix->assignments, head) {
+                       if (!assign->name[0])
+                               continue;
+
+                       struct in6_addr addr = prefix->addr;
+                       addr.s6_addr32[1] |= htonl(assign->assigned);
+
                        void *d = blobmsg_open_table(&b, assign->name);
 
                        buf = blobmsg_alloc_string_buffer(&b, "address", buflen);
-                       inet_ntop(AF_INET6, &assign->addr, buf, buflen);
+                       inet_ntop(AF_INET6, &addr, buf, buflen);
                        blobmsg_add_string_buffer(&b);
 
                        blobmsg_add_u32(&b, "mask", assign->length);
@@ -465,6 +492,48 @@ interface_ip_dump_prefix_list(struct interface_ip_settings *ip)
 
 
 static void
+interface_ip_dump_prefix_assignment_list(struct interface *iface)
+{
+       void *a;
+       char *buf;
+       const int buflen = INET6_ADDRSTRLEN;
+       time_t now = system_get_rtime();
+
+       struct device_prefix *prefix;
+       list_for_each_entry(prefix, &prefixes, head) {
+               struct device_prefix_assignment *assign;
+               list_for_each_entry(assign, &prefix->assignments, head) {
+                       if (strcmp(assign->name, iface->name))
+                               continue;
+
+                       struct in6_addr addr = prefix->addr;
+                       addr.s6_addr32[1] |= htonl(assign->assigned);
+
+                       a = blobmsg_open_table(&b, NULL);
+
+                       buf = blobmsg_alloc_string_buffer(&b, "address", buflen);
+                       inet_ntop(AF_INET6, &addr, buf, buflen);
+                       blobmsg_add_string_buffer(&b);
+
+                       blobmsg_add_u32(&b, "mask", assign->length);
+
+                       if (prefix->preferred_until) {
+                               int preferred = prefix->preferred_until - now;
+                               if (preferred < 0)
+                                       preferred = 0;
+                               blobmsg_add_u32(&b, "preferred", preferred);
+                       }
+
+                       if (prefix->valid_until)
+                               blobmsg_add_u32(&b, "valid", prefix->valid_until - now);
+
+                       blobmsg_close_table(&b, a);
+               }
+       }
+}
+
+
+static void
 interface_ip_dump_dns_server_list(struct interface_ip_settings *ip,
                                   bool enabled)
 {
@@ -542,6 +611,9 @@ netifd_handle_status(struct ubus_context *ctx, struct ubus_object *obj,
                interface_ip_dump_prefix_list(&iface->config_ip);
                interface_ip_dump_prefix_list(&iface->proto_ip);
                blobmsg_close_array(&b, a);
+               a = blobmsg_open_array(&b, "ipv6-prefix-assignment");
+               interface_ip_dump_prefix_assignment_list(iface);
+               blobmsg_close_array(&b, a);
                a = blobmsg_open_array(&b, "route");
                interface_ip_dump_route_list(&iface->config_ip, true);
                interface_ip_dump_route_list(&iface->proto_ip, true);