treewide: optimize syslog priority values
[project/odhcpd.git] / src / config.c
index e928536af794bc38036913df0d642b02e2e4232f..a8458a5a053152ddb24cabed4fd9bc3c1ede07af 100644 (file)
@@ -20,7 +20,7 @@
 #include "odhcpd.h"
 
 static struct blob_buf b;
-static int reload_pipe[2];
+static int reload_pipe[2] = { -1, -1 };
 
 static int lease_cmp(const void *k1, const void *k2, void *ptr);
 static void lease_update(struct vlist_tree *tree, struct vlist_node *node_new,
@@ -30,14 +30,16 @@ struct vlist_tree leases = VLIST_TREE_INIT(leases, lease_cmp, lease_update, true
 AVL_TREE(interfaces, avl_strcmp, false, NULL);
 struct config config = {.legacy = false, .main_dhcpv4 = false,
                        .dhcp_cb = NULL, .dhcp_statefile = NULL,
-                       .log_level = LOG_INFO};
+                       .log_level = LOG_WARNING};
+
+#define START_DEFAULT  100
+#define LIMIT_DEFAULT  150
 
 enum {
        IFACE_ATTR_INTERFACE,
        IFACE_ATTR_IFNAME,
        IFACE_ATTR_NETWORKID,
        IFACE_ATTR_DYNAMICDHCP,
-       IFACE_ATTR_IGNORE,
        IFACE_ATTR_LEASETIME,
        IFACE_ATTR_LIMIT,
        IFACE_ATTR_START,
@@ -58,6 +60,8 @@ enum {
        IFACE_ATTR_DHCPV6_NA,
        IFACE_ATTR_RA_DEFAULT,
        IFACE_ATTR_RA_MANAGEMENT,
+       IFACE_ATTR_RA_FLAGS,
+       IFACE_ATTR_RA_SLAAC,
        IFACE_ATTR_RA_OFFLINK,
        IFACE_ATTR_RA_PREFERENCE,
        IFACE_ATTR_RA_ADVROUTER,
@@ -83,7 +87,6 @@ static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = {
        [IFACE_ATTR_IFNAME] = { .name = "ifname", .type = BLOBMSG_TYPE_STRING },
        [IFACE_ATTR_NETWORKID] = { .name = "networkid", .type = BLOBMSG_TYPE_STRING },
        [IFACE_ATTR_DYNAMICDHCP] = { .name = "dynamicdhcp", .type = BLOBMSG_TYPE_BOOL },
-       [IFACE_ATTR_IGNORE] = { .name = "ignore", .type = BLOBMSG_TYPE_BOOL },
        [IFACE_ATTR_LEASETIME] = { .name = "leasetime", .type = BLOBMSG_TYPE_STRING },
        [IFACE_ATTR_START] = { .name = "start", .type = BLOBMSG_TYPE_INT32 },
        [IFACE_ATTR_LIMIT] = { .name = "limit", .type = BLOBMSG_TYPE_INT32 },
@@ -106,6 +109,8 @@ static const struct blobmsg_policy iface_attrs[IFACE_ATTR_MAX] = {
        [IFACE_ATTR_PD_CER] = { .name = "pd_cer", .type = BLOBMSG_TYPE_STRING },
        [IFACE_ATTR_RA_DEFAULT] = { .name = "ra_default", .type = BLOBMSG_TYPE_INT32 },
        [IFACE_ATTR_RA_MANAGEMENT] = { .name = "ra_management", .type = BLOBMSG_TYPE_INT32 },
+       [IFACE_ATTR_RA_FLAGS] = { .name = "ra_flags", . type = BLOBMSG_TYPE_ARRAY },
+       [IFACE_ATTR_RA_SLAAC] = { .name = "ra_slaac", .type = BLOBMSG_TYPE_BOOL },
        [IFACE_ATTR_RA_OFFLINK] = { .name = "ra_offlink", .type = BLOBMSG_TYPE_BOOL },
        [IFACE_ATTR_RA_PREFERENCE] = { .name = "ra_preference", .type = BLOBMSG_TYPE_STRING },
        [IFACE_ATTR_RA_ADVROUTER] = { .name = "ra_advrouter", .type = BLOBMSG_TYPE_BOOL },
@@ -181,6 +186,14 @@ const struct uci_blob_param_list odhcpd_attr_list = {
        .params = odhcpd_attrs,
 };
 
+static const struct { const char *name; uint8_t flag; } ra_flags[] = {
+       { .name = "managed-config", .flag = ND_RA_FLAG_MANAGED },
+       { .name = "other-config", .flag = ND_RA_FLAG_OTHER },
+       { .name = "home-agent", .flag = ND_RA_FLAG_HOME_AGENT },
+       { .name = "none", . flag = 0 },
+       { .name = NULL, },
+};
+
 static int mkdir_p(char *dir, mode_t mask)
 {
        char *l = strrchr(dir, '/');
@@ -208,12 +221,20 @@ static int mkdir_p(char *dir, mode_t mask)
 
 static void set_interface_defaults(struct interface *iface)
 {
+       iface->ignore = true;
+       iface->dhcpv4 = MODE_DISABLED;
+       iface->dhcpv6 = MODE_DISABLED;
+       iface->ra = MODE_DISABLED;
+       iface->ndp = MODE_DISABLED;
        iface->learn_routes = 1;
        iface->dhcpv4_leasetime = 43200;
+       iface->dhcpv4_start.s_addr = htonl(START_DEFAULT);
+       iface->dhcpv4_end.s_addr = htonl(START_DEFAULT + LIMIT_DEFAULT - 1);
        iface->dhcpv6_assignall = true;
        iface->dhcpv6_pd = true;
        iface->dhcpv6_na = true;
-       iface->ra_managed = RA_MANAGED_MFLAG;
+       iface->ra_flags = ND_RA_FLAG_OTHER;
+       iface->ra_slaac = true;
        iface->ra_maxinterval = 600;
        iface->ra_mininterval = iface->ra_maxinterval/3;
        iface->ra_lifetime = -1;
@@ -265,6 +286,34 @@ static int parse_mode(const char *mode)
                return -1;
 }
 
+static int parse_ra_flags(uint8_t *flags, struct blob_attr *attr)
+{
+       struct blob_attr *cur;
+       unsigned rem;
+
+       blobmsg_for_each_attr(cur, attr, rem) {
+               int i;
+
+               if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
+                       continue;
+
+                if (!blobmsg_check_attr(cur, false))
+                        continue;
+
+               for (i = 0; ra_flags[i].name; i++) {
+                       if (!strcmp(ra_flags[i].name, blobmsg_get_string(cur))) {
+                               *flags |= ra_flags[i].flag;
+                               break;
+                       }
+               }
+
+               if (!ra_flags[i].name)
+                       return -1;
+       }
+
+       return 0;
+}
+
 static void set_config(struct uci_section *s)
 {
        struct blob_attr *tb[ODHCPD_ATTR_MAX], *c;
@@ -430,6 +479,15 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr
 
                iface->name = strcpy(new_name, name);
                iface->avl.key = iface->name;
+               iface->router_event.uloop.fd = -1;
+               iface->dhcpv6_event.uloop.fd = -1;
+               iface->ndp_event.uloop.fd = -1;
+               iface->ndp_ping_fd = -1;
+               iface->dhcpv4_event.uloop.fd = -1;
+               INIT_LIST_HEAD(&iface->ia_assignments);
+               INIT_LIST_HEAD(&iface->dhcpv4_assignments);
+               INIT_LIST_HEAD(&iface->dhcpv4_fr_ips);
+
                set_interface_defaults(iface);
 
                avl_insert(&interfaces, &iface->avl);
@@ -482,9 +540,6 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr
        if ((c = tb[IFACE_ATTR_DYNAMICDHCP]))
                iface->no_dynamic_dhcp = !blobmsg_get_bool(c);
 
-       if (overwrite && (c = tb[IFACE_ATTR_IGNORE]))
-               iface->ignore = blobmsg_get_bool(c);
-
        if ((c = tb[IFACE_ATTR_LEASETIME])) {
                double time = parse_leasetime(c);
                if (time < 0)
@@ -495,14 +550,16 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr
 
        if ((c = tb[IFACE_ATTR_START])) {
                iface->dhcpv4_start.s_addr = htonl(blobmsg_get_u32(c));
+               iface->dhcpv4_end.s_addr = htonl(ntohl(iface->dhcpv4_start.s_addr) +
+                                                       LIMIT_DEFAULT - 1);
 
                if (config.main_dhcpv4 && config.legacy)
                        iface->dhcpv4 = MODE_SERVER;
        }
 
        if ((c = tb[IFACE_ATTR_LIMIT]))
-               iface->dhcpv4_end.s_addr = htonl(
-                               ntohl(iface->dhcpv4_start.s_addr) + blobmsg_get_u32(c));
+               iface->dhcpv4_end.s_addr = htonl(ntohl(iface->dhcpv4_start.s_addr) +
+                                                       blobmsg_get_u32(c) - 1);
 
        if ((c = tb[IFACE_ATTR_MASTER]))
                iface->master = blobmsg_get_bool(c);
@@ -527,32 +584,45 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr
 
        int mode;
        if ((c = tb[IFACE_ATTR_RA])) {
-               if ((mode = parse_mode(blobmsg_get_string(c))) >= 0)
+               if ((mode = parse_mode(blobmsg_get_string(c))) >= 0) {
                        iface->ra = mode;
-               else
+
+                       if (iface->ra != MODE_DISABLED)
+                               iface->ignore = false;
+               } else
                        goto err;
        }
 
        if ((c = tb[IFACE_ATTR_DHCPV4])) {
                if ((mode = parse_mode(blobmsg_get_string(c))) >= 0) {
-                       if (config.main_dhcpv4)
+                       if (config.main_dhcpv4) {
                                iface->dhcpv4 = mode;
+
+                               if (iface->dhcpv4 != MODE_DISABLED)
+                                       iface->ignore = false;
+                       }
                }
                else
                        goto err;
        }
 
        if ((c = tb[IFACE_ATTR_DHCPV6])) {
-               if ((mode = parse_mode(blobmsg_get_string(c))) >= 0)
+               if ((mode = parse_mode(blobmsg_get_string(c))) >= 0) {
                        iface->dhcpv6 = mode;
-               else
+
+                       if (iface->dhcpv6 != MODE_DISABLED)
+                               iface->ignore = false;
+               } else
                        goto err;
        }
 
        if ((c = tb[IFACE_ATTR_NDP])) {
-               if ((mode = parse_mode(blobmsg_get_string(c))) >= 0)
+               if ((mode = parse_mode(blobmsg_get_string(c))) >= 0) {
                        iface->ndp = mode;
-               else
+
+                       if (iface->ndp != MODE_DISABLED)
+                               iface->ignore = false;
+               } else
                        goto err;
        }
 
@@ -666,8 +736,31 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr
        if ((c = tb[IFACE_ATTR_RA_DEFAULT]))
                iface->default_router = blobmsg_get_u32(c);
 
-       if ((c = tb[IFACE_ATTR_RA_MANAGEMENT]))
-               iface->ra_managed = blobmsg_get_u32(c);
+       if (!tb[IFACE_ATTR_RA_FLAGS] && !tb[IFACE_ATTR_RA_SLAAC] &&
+           (c = tb[IFACE_ATTR_RA_MANAGEMENT])) {
+               switch (blobmsg_get_u32(c)) {
+               case 0:
+                       iface->ra_flags = ND_RA_FLAG_OTHER;
+                       iface->ra_slaac = true;
+                       break;
+               case 1:
+                       iface->ra_flags = ND_RA_FLAG_OTHER|ND_RA_FLAG_MANAGED;
+                       iface->ra_slaac = true;
+                       break;
+               case 2:
+                       iface->ra_flags = ND_RA_FLAG_OTHER|ND_RA_FLAG_MANAGED;
+                       iface->ra_slaac = false;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       if ((c = tb[IFACE_ATTR_RA_FLAGS])) {
+               iface->ra_flags = 0;
+               if (parse_ra_flags(&iface->ra_flags, c) < 0)
+                       goto err;
+       }
 
        if ((c = tb[IFACE_ATTR_RA_REACHABLETIME])) {
                uint32_t ra_reachabletime = blobmsg_get_u32(c);
@@ -701,6 +794,9 @@ int config_parse_interface(void *data, size_t len, const char *name, bool overwr
                iface->ra_mtu = ra_mtu;
        }
 
+       if ((c = tb[IFACE_ATTR_RA_SLAAC]))
+               iface->ra_slaac = blobmsg_get_bool(c);
+
        if ((c = tb[IFACE_ATTR_RA_OFFLINK]))
                iface->ra_not_onlink = blobmsg_get_bool(c);
 
@@ -865,9 +961,9 @@ static void lease_change_config(struct lease *l_old, struct lease *l_new)
 
 static void lease_delete(struct lease *l)
 {
-       struct dhcp_assignment *a;
+       struct dhcp_assignment *a, *tmp;
 
-       list_for_each_entry(a, &l->assignments, lease_list)
+       list_for_each_entry_safe(a, tmp, &l->assignments, lease_list)
                free_assignment(a);
 
        free_lease(l);
@@ -949,19 +1045,27 @@ void odhcpd_reload(void)
        struct uci_package *dhcp = NULL;
        if (!uci_load(uci, "dhcp", &dhcp)) {
                struct uci_element *e;
+
+               /* 1. Global settings */
                uci_foreach_element(&dhcp->sections, e) {
                        struct uci_section *s = uci_to_section(e);
-                       if (!strcmp(s->type, "host"))
-                               set_lease(s);
-                       else if (!strcmp(s->type, "odhcpd"))
+                       if (!strcmp(s->type, "odhcpd"))
                                set_config(s);
                }
 
+               /* 2. DHCP pools */
                uci_foreach_element(&dhcp->sections, e) {
                        struct uci_section *s = uci_to_section(e);
                        if (!strcmp(s->type, "dhcp"))
                                set_interface(s);
                }
+
+               /* 3. Static leases */
+               uci_foreach_element(&dhcp->sections, e) {
+                       struct uci_section* s = uci_to_section(e);
+                       if (!strcmp(s->type, "host"))
+                               set_lease(s);
+               }
        }
 
        if (config.dhcp_statefile) {
@@ -1043,11 +1147,11 @@ void odhcpd_reload(void)
                                i->ndp = (master && master->ndp == MODE_RELAY) ?
                                                MODE_RELAY : MODE_DISABLED;
 
-                       router_setup_interface(i, !i->ignore || i->ra != MODE_DISABLED);
-                       dhcpv6_setup_interface(i, !i->ignore || i->dhcpv6 != MODE_DISABLED);
-                       ndp_setup_interface(i, !i->ignore || i->ndp != MODE_DISABLED);
+                       router_setup_interface(i, i->ra != MODE_DISABLED);
+                       dhcpv6_setup_interface(i, i->dhcpv6 != MODE_DISABLED);
+                       ndp_setup_interface(i, i->ndp != MODE_DISABLED);
 #ifdef DHCPV4_SUPPORT
-                       dhcpv4_setup_interface(i, !i->ignore || i->dhcpv4 != MODE_DISABLED);
+                       dhcpv4_setup_interface(i, i->dhcpv4 != MODE_DISABLED);
 #endif
                } else
                        close_interface(i);
@@ -1075,7 +1179,7 @@ static void reload_cb(struct uloop_fd *u, _unused unsigned int events)
        odhcpd_reload();
 }
 
-static struct uloop_fd reload_fd = { .cb = reload_cb };
+static struct uloop_fd reload_fd = { .fd = -1, .cb = reload_cb };
 
 void odhcpd_run(void)
 {