+static int
+addr_cmp(const void *k1, const void *k2, void *ptr)
+{
+ return memcmp(k1, k2, sizeof(struct device_addr) -
+ offsetof(struct device_addr, mask));
+}
+
+static int
+route_cmp(const void *k1, const void *k2, void *ptr)
+{
+ return memcmp(k1, k2, sizeof(struct device_route) -
+ offsetof(struct device_route, mask));
+}
+
+static void
+interface_update_proto_addr(struct vlist_tree *tree,
+ struct vlist_node *node_new,
+ struct vlist_node *node_old)
+{
+ struct interface *iface;
+ struct device *dev;
+ struct device_addr *addr;
+
+ iface = container_of(tree, struct interface, proto_addr);
+ dev = iface->l3_dev->dev;
+
+ if (node_old) {
+ addr = container_of(node_old, struct device_addr, node);
+ if (!(addr->flags & DEVADDR_EXTERNAL))
+ system_del_address(dev, addr);
+ free(addr);
+ }
+
+ if (node_new) {
+ addr = container_of(node_new, struct device_addr, node);
+ if (!(addr->flags & DEVADDR_EXTERNAL))
+ system_add_address(dev, addr);
+ }
+}
+
+static void
+interface_update_proto_route(struct vlist_tree *tree,
+ struct vlist_node *node_new,
+ struct vlist_node *node_old)
+{
+ struct interface *iface;
+ struct device *dev;
+ struct device_route *route;
+
+ iface = container_of(tree, struct interface, proto_route);
+ dev = iface->l3_dev->dev;
+
+ if (node_old) {
+ route = container_of(node_old, struct device_route, node);
+ if (!(route->flags & DEVADDR_EXTERNAL))
+ system_del_route(dev, route);
+ free(route);
+ }
+
+ if (node_new) {
+ route = container_of(node_new, struct device_route, node);
+ if (!(route->flags & DEVADDR_EXTERNAL))
+ system_add_route(dev, route);
+ }
+}
+
+void
+interface_add_dns_server(struct interface *iface, const char *str)
+{
+ struct dns_server *s;
+
+ s = calloc(1, sizeof(*s));
+ s->af = AF_INET;
+ if (inet_pton(s->af, str, &s->addr.in))
+ goto add;
+
+ s->af = AF_INET6;
+ if (inet_pton(s->af, str, &s->addr.in))
+ goto add;
+
+ free(s);
+ return;
+
+add:
+ D(INTERFACE, "Add IPv%c DNS server: %s\n",
+ s->af == AF_INET6 ? '6' : '4', str);
+ list_add_tail(&s->list, &iface->proto_dns_servers);
+}
+
+void
+interface_add_dns_server_list(struct interface *iface, struct blob_attr *list)
+{
+ struct blob_attr *cur;
+ int rem;
+
+ blobmsg_for_each_attr(cur, list, rem) {
+ if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
+ continue;
+
+ if (!blobmsg_check_attr(cur, NULL))
+ continue;
+
+ interface_add_dns_server(iface, blobmsg_data(cur));
+ }
+}
+
+void
+interface_add_dns_search_domain(struct interface *iface, const char *str)