netifd: Add mldversion config support
[project/netifd.git] / config.c
index 682db54..6691e61 100644 (file)
--- a/config.c
+++ b/config.c
@@ -11,6 +11,7 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
+#define _GNU_SOURCE
 #include <string.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include "interface-ip.h"
 #include "iprule.h"
 #include "proto.h"
+#include "wireless.h"
 #include "config.h"
 
 bool config_init = false;
 
 static struct uci_context *uci_ctx;
 static struct uci_package *uci_network;
+static struct uci_package *uci_wireless;
 static struct blob_buf b;
 
 static int
+config_section_idx(struct uci_section *s)
+{
+       struct uci_element *e;
+       int idx = 0;
+
+       uci_foreach_element(&uci_wireless->sections, e) {
+               struct uci_section *cur = uci_to_section(e);
+
+               if (s == cur)
+                       return idx;
+
+               if (!strcmp(cur->type, s->type))
+                       idx++;
+       }
+
+       return -1;
+}
+
+static int
 config_parse_bridge_interface(struct uci_section *s)
 {
        char *name;
@@ -54,11 +76,15 @@ static void
 config_parse_interface(struct uci_section *s, bool alias)
 {
        struct interface *iface;
-       const char *type = NULL;
+       const char *type = NULL, *disabled;
        struct blob_attr *config;
        struct device *dev;
        bool bridge = false;
 
+       disabled = uci_lookup_option_string(uci_ctx, s, "disabled");
+       if (disabled && !strcmp(disabled, "1"))
+               return;
+
        blob_buf_init(&b, 0);
 
        if (!alias)
@@ -71,12 +97,11 @@ config_parse_interface(struct uci_section *s, bool alias)
        }
 
        uci_to_blob(&b, s, &interface_attr_list);
-       iface = calloc(1, sizeof(*iface));
+
+       iface = interface_alloc(s->e.name, b.head);
        if (!iface)
                return;
 
-       interface_init(iface, s->e.name, b.head);
-
        if (iface->proto_handler && iface->proto_handler->config_params)
                uci_to_blob(&b, s, iface->proto_handler->config_params);
 
@@ -162,12 +187,16 @@ config_init_devices(void)
 
                type = uci_lookup_option_string(uci_ctx, s, "type");
                if (type) {
-                       if (!strcmp(type, "bridge"))
+                       if (!strcmp(type, "8021ad"))
+                               devtype = &vlandev_device_type;
+                       else if (!strcmp(type, "8021q"))
+                               devtype = &vlandev_device_type;
+                       else if (!strcmp(type, "bridge"))
                                devtype = &bridge_device_type;
-                       else if (!strcmp(type, "tunnel"))
-                               devtype = &tunnel_device_type;
                        else if (!strcmp(type, "macvlan"))
                                devtype = &macvlan_device_type;
+                       else if (!strcmp(type, "tunnel"))
+                               devtype = &tunnel_device_type;
                }
 
                if (!devtype)
@@ -189,8 +218,11 @@ config_init_package(const char *config)
                ctx = uci_alloc_context();
                uci_ctx = ctx;
 
+               ctx->flags &= ~UCI_FLAG_STRICT;
+               if (config_path)
+                       uci_set_confdir(ctx, config_path);
+
 #ifdef DUMMY_MODE
-               uci_set_confdir(ctx, "./config");
                uci_set_savedir(ctx, "./tmp");
 #endif
        } else {
@@ -279,6 +311,90 @@ config_init_globals(void)
        interface_ip_set_ula_prefix(ula_prefix);
 }
 
+static void
+config_parse_wireless_device(struct uci_section *s)
+{
+       struct wireless_driver *drv;
+       const char *driver_name;
+
+       driver_name = uci_lookup_option_string(uci_ctx, s, "type");
+       if (!driver_name)
+               return;
+
+       drv = avl_find_element(&wireless_drivers, driver_name, drv, node);
+       if (!drv)
+               return;
+
+       blob_buf_init(&b, 0);
+       uci_to_blob(&b, s, drv->device.config);
+       wireless_device_create(drv, s->e.name, b.head);
+}
+
+static void
+config_parse_wireless_interface(struct wireless_device *wdev, struct uci_section *s)
+{
+       char *name;
+
+       name = alloca(strlen(s->type) + 16);
+       sprintf(name, "@%s[%d]", s->type, config_section_idx(s));
+
+       blob_buf_init(&b, 0);
+       uci_to_blob(&b, s, wdev->drv->interface.config);
+       wireless_interface_create(wdev, b.head, s->anonymous ? name : s->e.name);
+}
+
+static void
+config_init_wireless(void)
+{
+       struct wireless_device *wdev;
+       struct uci_element *e;
+       const char *dev_name;
+
+       if (!uci_wireless) {
+               DPRINTF("No wireless configuration found\n");
+               return;
+       }
+
+       vlist_update(&wireless_devices);
+
+       uci_foreach_element(&uci_wireless->sections, e) {
+               struct uci_section *s = uci_to_section(e);
+               if (strcmp(s->type, "wifi-device") != 0)
+                       continue;
+
+               config_parse_wireless_device(s);
+       }
+
+       vlist_flush(&wireless_devices);
+
+       vlist_for_each_element(&wireless_devices, wdev, node) {
+               wdev->vif_idx = 0;
+               vlist_update(&wdev->interfaces);
+       }
+
+       uci_foreach_element(&uci_wireless->sections, e) {
+               struct uci_section *s = uci_to_section(e);
+
+               if (strcmp(s->type, "wifi-iface") != 0)
+                       continue;
+
+               dev_name = uci_lookup_option_string(uci_ctx, s, "device");
+               if (!dev_name)
+                       continue;
+
+               wdev = vlist_find(&wireless_devices, dev_name, wdev, node);
+               if (!wdev) {
+                       DPRINTF("device %s not found!\n", dev_name);
+                       continue;
+               }
+
+               config_parse_wireless_interface(wdev, s);
+       }
+
+       vlist_for_each_element(&wireless_devices, wdev, node)
+               vlist_flush(&wdev->interfaces);
+}
+
 void
 config_init_all(void)
 {
@@ -288,6 +404,8 @@ config_init_all(void)
                return;
        }
 
+       uci_wireless = config_init_package("wireless");
+
        vlist_update(&interfaces);
        config_init = true;
        device_lock();
@@ -298,6 +416,7 @@ config_init_all(void)
        config_init_routes();
        config_init_rules();
        config_init_globals();
+       config_init_wireless();
 
        config_init = false;
        device_unlock();
@@ -308,4 +427,5 @@ config_init_all(void)
        device_free_unused(NULL);
        interface_refresh_assignments(false);
        interface_start_pending();
+       wireless_start_pending();
 }