move dns server/search list parsing to interface core to support peerdns=0 + static...
[project/netifd.git] / interface.c
index 304cccf..edf9b27 100644 (file)
@@ -1,3 +1,16 @@
+/*
+ * netifd - network interface daemon
+ * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include "system.h"
 
 struct vlist_tree interfaces;
+static LIST_HEAD(iface_all_users);
 
 enum {
        IFACE_ATTR_IFNAME,
        IFACE_ATTR_PROTO,
        IFACE_ATTR_AUTO,
        IFACE_ATTR_DEFAULTROUTE,
+       IFACE_ATTR_PEERDNS,
+       IFACE_ATTR_DNS,
+       IFACE_ATTR_DNS_SEARCH,
        IFACE_ATTR_METRIC,
        IFACE_ATTR_MAX
 };
@@ -27,12 +44,20 @@ static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = {
        [IFACE_ATTR_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING },
        [IFACE_ATTR_AUTO] = { .name = "auto", .type = BLOBMSG_TYPE_BOOL },
        [IFACE_ATTR_DEFAULTROUTE] = { .name = "defaultroute", .type = BLOBMSG_TYPE_BOOL },
+       [IFACE_ATTR_PEERDNS] = { .name = "peerdns", .type = BLOBMSG_TYPE_BOOL },
        [IFACE_ATTR_METRIC] = { .name = "metric", .type = BLOBMSG_TYPE_INT32 },
+       [IFACE_ATTR_DNS] = { .name = "dns", .type = BLOBMSG_TYPE_ARRAY },
+       [IFACE_ATTR_DNS_SEARCH] = { .name = "dns_search", .type = BLOBMSG_TYPE_ARRAY },
+};
+
+static const union config_param_info iface_attr_info[IFACE_ATTR_MAX] = {
+       [IFACE_ATTR_DNS] = { .type = BLOBMSG_TYPE_STRING },
 };
 
 const struct config_param_list interface_attr_list = {
        .n_params = IFACE_ATTR_MAX,
        .params = iface_attrs,
+       .info = iface_attr_info,
 };
 
 static void
@@ -104,7 +129,7 @@ interface_add_data(struct interface *iface, const struct blob_attr *data)
        if (!blobmsg_check_attr(data, true))
                return UBUS_STATUS_INVALID_ARGUMENT;
 
-       n = calloc(1, sizeof(*data) + blob_pad_len(data));
+       n = calloc(1, sizeof(*n) + blob_pad_len(data));
        memcpy(n->data, data, blob_pad_len(data));
        n->node.key = blobmsg_name(data);
 
@@ -122,9 +147,10 @@ interface_event(struct interface *iface, enum interface_event ev)
        struct interface_user *dep, *tmp;
 
        list_for_each_entry_safe(dep, tmp, &iface->users, list)
-               dep->cb(dep, IFEV_UP);
+               dep->cb(dep, iface, ev);
 
-       interface_queue_event(iface, ev);
+       list_for_each_entry_safe(dep, tmp, &iface_all_users, list)
+               dep->cb(dep, iface, ev);
 }
 
 static void
@@ -145,6 +171,7 @@ mark_interface_down(struct interface *iface)
        interface_ip_set_enabled(&iface->config_ip, false);
        interface_ip_flush(&iface->proto_ip);
        interface_flush_state(iface);
+       system_flush_routes();
        iface->state = IFS_DOWN;
 }
 
@@ -205,10 +232,15 @@ interface_set_available(struct interface *iface, bool new_state)
 void
 interface_add_user(struct interface_user *dep, struct interface *iface)
 {
+       if (!iface) {
+               list_add(&dep->list, &iface_all_users);
+               return;
+       }
+
        dep->iface = iface;
        list_add(&dep->list, &iface->users);
        if (iface->state == IFS_UP)
-               dep->cb(dep, IFEV_UP);
+               dep->cb(dep, iface, IFEV_UP);
 }
 
 void
@@ -242,7 +274,6 @@ interface_cleanup(struct interface *iface, bool reload)
        list_for_each_entry_safe(dep, tmp, &iface->users, list)
                interface_remove_user(dep);
 
-       interface_dequeue_event(iface);
        interface_ip_flush(&iface->config_ip);
        interface_flush_state(iface);
        interface_clear_errors(iface);
@@ -255,6 +286,7 @@ interface_cleanup(struct interface *iface, bool reload)
 static void
 interface_do_free(struct interface *iface)
 {
+       interface_event(iface, IFEV_FREE);
        interface_cleanup(iface, false);
        free(iface->config);
        netifd_ubus_remove_interface(iface);
@@ -265,6 +297,7 @@ interface_do_free(struct interface *iface)
 static void
 interface_do_reload(struct interface *iface)
 {
+       interface_event(iface, IFEV_RELOAD);
        interface_cleanup(iface, true);
        proto_init_interface(iface, iface->config);
        interface_claim_device(iface);
@@ -311,7 +344,6 @@ interface_proto_cb(struct interface_proto_state *state, enum interface_proto_eve
 
                netifd_log_message(L_NOTICE, "Interface '%s' is now down\n", iface->name);
                mark_interface_down(iface);
-               system_flush_routes();
                interface_handle_config_change(iface);
                break;
        case IFPEV_LINK_LOST:
@@ -320,7 +352,6 @@ interface_proto_cb(struct interface_proto_state *state, enum interface_proto_eve
 
                netifd_log_message(L_NOTICE, "Interface '%s' has lost the connection\n", iface->name);
                mark_interface_down(iface);
-               system_flush_routes();
                iface->state = IFS_SETUP;
                break;
        }
@@ -353,8 +384,7 @@ interface_init(struct interface *iface, const char *name,
        INIT_LIST_HEAD(&iface->errors);
        INIT_LIST_HEAD(&iface->users);
        INIT_LIST_HEAD(&iface->hotplug_list);
-       interface_ip_init(&iface->proto_ip, iface);
-       interface_ip_init(&iface->config_ip, iface);
+       interface_ip_init(iface);
        avl_init(&iface->data, avl_strcmp, false, NULL);
        iface->config_ip.enabled = false;
 
@@ -371,6 +401,14 @@ interface_init(struct interface *iface, const char *name,
        iface->autostart = blobmsg_get_bool_default(tb[IFACE_ATTR_AUTO], true);
        iface->proto_ip.no_defaultroute =
                !blobmsg_get_bool_default(tb[IFACE_ATTR_DEFAULTROUTE], true);
+       iface->proto_ip.no_dns =
+               !blobmsg_get_bool_default(tb[IFACE_ATTR_PEERDNS], true);
+
+       if ((cur = tb[IFACE_ATTR_DNS]))
+               interface_add_dns_server_list(&iface->config_ip, cur);
+
+       if ((cur = tb[IFACE_ATTR_DNS_SEARCH]))
+               interface_add_dns_search_list(&iface->config_ip, cur);
 
        iface->config_autostart = iface->autostart;
 }
@@ -552,6 +590,13 @@ interface_update_complete(struct interface *iface)
 }
 
 static void
+interface_replace_dns(struct interface_ip_settings *old, struct interface_ip_settings *new)
+{
+       vlist_simple_replace(&new->dns_servers, &old->dns_servers);
+       vlist_simple_replace(&new->dns_search, &old->dns_search);
+}
+
+static void
 interface_change_config(struct interface *if_old, struct interface *if_new)
 {
        struct blob_attr *old_config = if_old->config;
@@ -598,6 +643,11 @@ interface_change_config(struct interface *if_old, struct interface *if_new)
                interface_ip_set_enabled(&if_old->proto_ip, if_new->proto_ip.enabled);
        }
 
+       UPDATE(proto_ip.no_dns);
+       interface_replace_dns(&if_old->config_ip, &if_new->config_ip);
+       interface_replace_dns(&if_old->proto_ip, &if_new->proto_ip);
+       interface_write_resolv_conf();
+
 #undef UPDATE
 
        goto out;