+enum {
+ OPT_IPADDR,
+ OPT_IP6ADDR,
+ OPT_NETMASK,
+ OPT_BROADCAST,
+ OPT_GATEWAY,
+ OPT_IP6GW,
+ OPT_IP6PREFIX,
+ __OPT_MAX,
+};
+
+static const struct blobmsg_policy proto_ip_attributes[__OPT_MAX] = {
+ [OPT_IPADDR] = { .name = "ipaddr", .type = BLOBMSG_TYPE_ARRAY },
+ [OPT_IP6ADDR] = { .name = "ip6addr", .type = BLOBMSG_TYPE_ARRAY },
+ [OPT_NETMASK] = { .name = "netmask", .type = BLOBMSG_TYPE_STRING },
+ [OPT_BROADCAST] = { .name = "broadcast", .type = BLOBMSG_TYPE_STRING },
+ [OPT_GATEWAY] = { .name = "gateway", .type = BLOBMSG_TYPE_STRING },
+ [OPT_IP6GW] = { .name = "ip6gw", .type = BLOBMSG_TYPE_STRING },
+ [OPT_IP6PREFIX] = { .name = "ip6prefix", .type = BLOBMSG_TYPE_ARRAY },
+};
+
+static const struct uci_blob_param_info proto_ip_attr_info[__OPT_MAX] = {
+ [OPT_IPADDR] = { .type = BLOBMSG_TYPE_STRING },
+ [OPT_IP6ADDR] = { .type = BLOBMSG_TYPE_STRING },
+ [OPT_IP6PREFIX] = { .type = BLOBMSG_TYPE_STRING },
+};
+
+const struct uci_blob_param_list proto_ip_attr = {
+ .n_params = __OPT_MAX,
+ .params = proto_ip_attributes,
+ .info = proto_ip_attr_info,
+};
+
+enum {
+ ADDR_IPADDR,
+ ADDR_MASK,
+ ADDR_BROADCAST,
+ ADDR_PTP,
+ ADDR_PREFERRED,
+ ADDR_VALID,
+ ADDR_OFFLINK,
+ __ADDR_MAX
+};
+
+static const struct blobmsg_policy proto_ip_addr[__ADDR_MAX] = {
+ [ADDR_IPADDR] = { .name = "ipaddr", .type = BLOBMSG_TYPE_STRING },
+ [ADDR_MASK] = { .name = "mask", .type = BLOBMSG_TYPE_STRING },
+ [ADDR_BROADCAST] = { .name = "broadcast", .type = BLOBMSG_TYPE_STRING },
+ [ADDR_PTP] = { .name = "ptp", .type = BLOBMSG_TYPE_STRING },
+ [ADDR_PREFERRED] = { .name = "preferred", .type = BLOBMSG_TYPE_INT32 },
+ [ADDR_VALID] = { .name = "valid", .type = BLOBMSG_TYPE_INT32 },
+ [ADDR_OFFLINK] = { .name = "offlink", .type = BLOBMSG_TYPE_BOOL },
+};
+
+static struct device_addr *
+alloc_device_addr(bool v6, bool ext)
+{
+ struct device_addr *addr;
+
+ addr = calloc(1, sizeof(*addr));
+ addr->flags = v6 ? DEVADDR_INET6 : DEVADDR_INET4;
+ if (ext)
+ addr->flags |= DEVADDR_EXTERNAL;
+
+ return addr;
+}
+
+static bool
+parse_addr(struct interface *iface, const char *str, bool v6, int mask,
+ bool ext, uint32_t broadcast)
+{
+ struct device_addr *addr;
+ int af = v6 ? AF_INET6 : AF_INET;
+
+ addr = alloc_device_addr(v6, ext);
+ if (!addr)
+ return false;
+
+ addr->mask = mask;
+ if (!parse_ip_and_netmask(af, str, &addr->addr, &addr->mask)) {
+ interface_add_error(iface, "proto", "INVALID_ADDRESS", &str, 1);
+ free(addr);
+ return false;
+ }
+
+ if (broadcast)
+ addr->broadcast = broadcast;
+
+ vlist_add(&iface->proto_ip.addr, &addr->node, &addr->flags);
+ return true;
+}
+
+static int
+parse_static_address_option(struct interface *iface, struct blob_attr *attr,
+ bool v6, int netmask, bool ext, uint32_t broadcast)
+{
+ struct blob_attr *cur;
+ int n_addr = 0;
+ int rem;
+
+ blobmsg_for_each_attr(cur, attr, rem) {
+ if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
+ return -1;
+
+ n_addr++;
+ if (!parse_addr(iface, blobmsg_data(cur), v6, netmask, ext,
+ broadcast))
+ return -1;
+ }
+
+ return n_addr;
+}
+
+static struct device_addr *
+parse_address_item(struct blob_attr *attr, bool v6, bool ext)