reconfigure: move all configuration functions to a new file
authorNicolas BESNARD <[email protected]>
Fri, 6 Dec 2024 10:26:07 +0000 (10:26 +0000)
committerÁlvaro Fernández Rojas <[email protected]>
Mon, 3 Nov 2025 15:21:24 +0000 (16:21 +0100)
Tidy up.

Signed-off-by: Nicolas BESNARD <[email protected]>
Signed-off-by: Paul Donald <[email protected]>
Link: https://github.com/openwrt/odhcp6c/pull/106
Signed-off-by: Álvaro Fernández Rojas <[email protected]>
CMakeLists.txt
src/config.c [new file with mode: 0644]
src/config.h [new file with mode: 0644]
src/odhcp6c.c
src/odhcp6c.h

index 0c3d1be9f3cf0e85a6f8163802f4ea28eeb1ebbd..fc60a84b6671716b677b2d17d05ecbf22e02551f 100644 (file)
@@ -6,8 +6,9 @@ cmake_policy(SET CMP0015 NEW)
 project(odhcp6c LANGUAGES C)
 add_executable(${PROJECT_NAME})
 target_sources(${PROJECT_NAME} PRIVATE
-       src/odhcp6c.c
+       src/config.c
        src/dhcpv6.c
+       src/odhcp6c.c
        src/ra.c
        src/script.c
 )
diff --git a/src/config.c b/src/config.c
new file mode 100644 (file)
index 0000000..1b18730
--- /dev/null
@@ -0,0 +1,483 @@
+/**
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ * SPDX-FileCopyrightText: Copyright (c) 2024 SoftAtHome
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * Subject to the terms and conditions of this license, each
+ * copyright holder and contributor hereby grants to those receiving
+ * rights under this license a perpetual, worldwide, non-exclusive,
+ * no-charge, royalty-free, irrevocable (except for failure to
+ * satisfy the conditions of this license) patent license to make,
+ * have made, use, offer to sell, sell, import, and otherwise
+ * transfer this software, where such license applies only to those
+ * patent claims, already acquired or hereafter acquired, licensable
+ * by such copyright holder or contributor that are necessarily
+ * infringed by:
+ *
+ * (a) their Contribution(s) (the licensed copyrights of copyright
+ * holders and non-copyrightable additions of contributors, in
+ * source or binary form) alone; or
+ *
+ * (b) combination of their Contribution(s) with the work of
+ * authorship to which such Contribution(s) was added by such
+ * copyright holder or contributor, if, at the time the Contribution
+ * is added, such addition causes such combination to be necessarily
+ * infringed. The patent license shall not apply to any other
+ * combinations which include the Contribution.
+ *
+ * Except as expressly stated above, no rights or licenses from any
+ * copyright holder or contributor is granted under this license,
+ * whether expressly, by implication, estoppel or otherwise.
+ *
+ * DISCLAIMER
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+#include <string.h>
+#include <resolv.h>
+#include <limits.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <syslog.h>
+
+#include "config.h"
+#include "odhcp6c.h"
+
+#define ARRAY_SEP " ,\t"
+
+static struct config_dhcp config_dhcp;
+
+struct config_dhcp *config_dhcp_get(void) {
+       return &config_dhcp;
+}
+
+void config_dhcp_reset(void) {
+       config_dhcp.release = true;
+       config_dhcp.dscp = 0;
+       config_dhcp.sol_timeout = DHCPV6_SOL_MAX_RT;
+       config_dhcp.sk_prio = 0;
+       config_dhcp.stateful_only_mode = false;
+       config_dhcp.ia_na_mode = IA_MODE_TRY;
+       config_dhcp.ia_pd_mode = IA_MODE_NONE;
+       config_dhcp.client_options = DHCPV6_CLIENT_FQDN | DHCPV6_ACCEPT_RECONFIGURE;
+       config_dhcp.allow_slaac_only = -1;
+       config_dhcp.oro_user_cnt = 0;
+}
+
+void config_set_release(bool enable) {
+       config_dhcp.release = enable;
+}
+
+bool config_set_dscp(unsigned int value) {
+       if (value > 63)
+               return false;
+       config_dhcp.dscp = value;
+       return true;
+}
+
+bool config_set_solicit_timeout(unsigned int timeout) {
+       if (timeout > INT32_MAX)
+               return false;
+
+       config_dhcp.sol_timeout = timeout;
+       return true;
+}
+
+bool config_set_sk_priority(unsigned int priority) {
+       if (priority > 6)
+               return false;
+
+       config_dhcp.sk_prio = priority;
+       return true;
+}
+
+void config_set_client_options(enum dhcpv6_config option, bool enable) {
+       if (enable) {
+               config_dhcp.client_options |= option;
+       } else {
+               config_dhcp.client_options &= ~option;
+       }
+}
+
+bool config_set_request_addresses(char* mode) {
+       if (!strcmp(mode, "force")) {
+               config_dhcp.ia_na_mode = IA_MODE_FORCE;
+               config_dhcp.allow_slaac_only = -1;
+       } else if (!strcmp(mode, "none")) {
+               config_dhcp.ia_na_mode = IA_MODE_NONE;
+       } else if (!strcmp(mode, "try")) {
+               config_dhcp.ia_na_mode = IA_MODE_TRY;
+       } else {
+               return false;
+       }
+
+       return true;
+}
+
+bool config_set_request_prefix(unsigned int length, unsigned int id) {
+       struct odhcp6c_request_prefix prefix = {0};
+
+       odhcp6c_clear_state(STATE_IA_PD_INIT);
+
+       if (config_dhcp.ia_pd_mode != IA_MODE_FORCE)
+               config_dhcp.ia_pd_mode = length > 128 ? IA_MODE_NONE : IA_MODE_TRY;
+
+       if (length <= 128) {
+               if (config_dhcp.allow_slaac_only >= 0 && config_dhcp.allow_slaac_only < 10)
+                       config_dhcp.allow_slaac_only = 10;
+
+               prefix.length = length;
+               prefix.iaid = htonl(id);
+
+               if (odhcp6c_add_state(STATE_IA_PD_INIT, &prefix, sizeof(prefix))) {
+                       syslog(LOG_ERR, "Failed to set request IPv6-Prefix");
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+void config_set_force_prefix(bool enable) {
+       if (enable) {
+               config_dhcp.allow_slaac_only = -1;
+               config_dhcp.ia_pd_mode = IA_MODE_FORCE;
+       } else {
+               config_dhcp.ia_pd_mode = IA_MODE_NONE;
+       }
+}
+
+void config_set_stateful_only(bool enable) {
+       config_dhcp.stateful_only_mode = enable;
+}
+
+void config_set_allow_slaac_only(int value) {
+       config_dhcp.allow_slaac_only = value;
+}
+
+void config_clear_requested_options(void) {
+       config_dhcp.oro_user_cnt = 0;
+}
+
+bool config_add_requested_options(unsigned int option) {
+       if (option > UINT16_MAX)
+               return false;
+
+       option = htons(option);
+       if (odhcp6c_insert_state(STATE_ORO, 0, &option, 2)) {
+               return false;
+       }
+       config_dhcp.oro_user_cnt++;
+       return true;
+}
+
+void config_clear_send_options(void) {
+       odhcp6c_clear_state(STATE_OPTS);
+}
+
+bool config_add_send_options(char* option) {
+       return (config_parse_opt(option) == 0);
+}
+
+static int config_parse_opt_u8(const char *src, uint8_t **dst)
+{
+       int len = strlen(src);
+
+       *dst = realloc(*dst, len/2);
+       if (!*dst)
+               return -1;
+
+       return script_unhexlify(*dst, len, src);
+}
+
+static int config_parse_opt_string(const char *src, uint8_t **dst, const bool array)
+{
+       int o_len = 0;
+       char *sep = strpbrk(src, ARRAY_SEP);
+
+       if (sep && !array)
+               return -1;
+
+       do {
+               if (sep) {
+                       *sep = 0;
+                       sep++;
+               }
+
+               int len = strlen(src);
+
+               *dst = realloc(*dst, o_len + len);
+               if (!*dst)
+                       return -1;
+
+               memcpy(&((*dst)[o_len]), src, len);
+
+               o_len += len;
+               src = sep;
+
+               if (sep)
+                       sep = strpbrk(src, ARRAY_SEP);
+       } while (src);
+
+       return o_len;
+}
+
+static int config_parse_opt_dns_string(const char *src, uint8_t **dst, const bool array)
+{
+       int o_len = 0;
+       char *sep = strpbrk(src, ARRAY_SEP);
+
+       if (sep && !array)
+               return -1;
+
+       do {
+               uint8_t tmp[256];
+
+               if (sep) {
+                       *sep = 0;
+                       sep++;
+               }
+
+               int len = dn_comp(src, tmp, sizeof(tmp), NULL, NULL);
+               if (len < 0)
+                       return -1;
+
+               *dst = realloc(*dst, o_len + len);
+               if (!*dst)
+                       return -1;
+
+               memcpy(&((*dst)[o_len]), tmp, len);
+
+               o_len += len;
+               src = sep;
+
+               if (sep)
+                       sep = strpbrk(src, ARRAY_SEP);
+       } while (src);
+
+       return o_len;
+}
+
+static int config_parse_opt_ip6(const char *src, uint8_t **dst, const bool array)
+{
+       int o_len = 0;
+       char *sep = strpbrk(src, ARRAY_SEP);
+
+       if (sep && !array)
+               return -1;
+
+       do {
+               int len = sizeof(struct in6_addr);
+
+               if (sep) {
+                       *sep = 0;
+                       sep++;
+               }
+
+               *dst = realloc(*dst, o_len + len);
+               if (!*dst)
+                       return -1;
+
+               if (inet_pton(AF_INET6, src, &((*dst)[o_len])) < 1)
+                       return -1;
+
+               o_len += len;
+               src = sep;
+
+               if (sep)
+                       sep = strpbrk(src, ARRAY_SEP);
+       } while (src);
+
+       return o_len;
+}
+
+static int config_parse_opt_user_class(const char *src, uint8_t **dst, const bool array)
+{
+       int o_len = 0;
+       char *sep = strpbrk(src, ARRAY_SEP);
+
+       if (sep && !array)
+               return -1;
+
+       do {
+               if (sep) {
+                       *sep = 0;
+                       sep++;
+               }
+               uint16_t str_len = strlen(src);
+
+               *dst = realloc(*dst, o_len + str_len + 2);
+               if (!*dst)
+                       return -1;
+
+               struct user_class {
+                       uint16_t len;
+                       uint8_t data[];
+               } *e = (struct user_class *)&((*dst)[o_len]);
+
+               e->len = ntohs(str_len);
+               memcpy(e->data, src, str_len);
+
+               o_len += str_len + 2;
+               src = sep;
+
+               if (sep)
+                       sep = strpbrk(src, ARRAY_SEP);
+       } while (src);
+
+       return o_len;
+}
+
+static uint8_t *config_state_find_opt(const uint16_t code)
+{
+       size_t opts_len;
+       uint8_t *odata, *opts = odhcp6c_get_state(STATE_OPTS, &opts_len);
+       uint16_t otype, olen;
+
+       dhcpv6_for_each_option(opts, &opts[opts_len], otype, olen, odata) {
+               if (otype == code)
+                       return &odata[-4];
+       }
+
+       return NULL;
+}
+
+int config_add_opt(const uint16_t code, const uint8_t *data, const uint16_t len)
+{
+       struct {
+               uint16_t code;
+               uint16_t len;
+       } opt_hdr = { htons(code), htons(len) };
+
+       if (config_state_find_opt(code))
+               return -1;
+
+       if (odhcp6c_add_state(STATE_OPTS, &opt_hdr, sizeof(opt_hdr)) ||
+                       odhcp6c_add_state(STATE_OPTS, data, len)) {
+               syslog(LOG_ERR, "Failed to add option %hu", code);
+               return 1;
+       }
+
+       return 0;
+}
+
+int config_parse_opt_data(const char *data, uint8_t **dst, const unsigned int type,
+               const bool array)
+{
+       int ret = 0;
+
+       switch (type) {
+       case OPT_U8:
+               ret = config_parse_opt_u8(data, dst);
+               break;
+
+       case OPT_STR:
+               ret = config_parse_opt_string(data, dst, array);
+               break;
+
+       case OPT_DNS_STR:
+               ret = config_parse_opt_dns_string(data, dst, array);
+               break;
+
+       case OPT_IP6:
+               ret = config_parse_opt_ip6(data, dst, array);
+               break;
+
+       case OPT_USER_CLASS:
+               ret = config_parse_opt_user_class(data, dst, array);
+               break;
+
+       default:
+               ret = -1;
+               break;
+       }
+
+       return ret;
+}
+
+int config_parse_opt(const char *opt)
+{
+       uint32_t optn;
+       char *data;
+       uint8_t *payload = NULL;
+       int payload_len;
+       unsigned int type = OPT_U8;
+       bool array = false;
+       struct odhcp6c_opt *dopt = NULL;
+       int ret = -1;
+
+       data = strpbrk(opt, ":");
+       if (!data)
+               return -1;
+
+       *data = '\0';
+       data++;
+
+       if (strlen(opt) == 0 || strlen(data) == 0)
+               return -1;
+
+       dopt = odhcp6c_find_opt_by_name(opt);
+       if (!dopt) {
+               char *e;
+               optn = strtoul(opt, &e, 0);
+               if (*e || e == opt || optn > USHRT_MAX)
+                       return -1;
+
+               dopt = odhcp6c_find_opt(optn);
+       } else {
+               optn = dopt->code;
+       }
+
+       /* Check if the type for the content is well-known */
+       if (dopt) {
+               /* Refuse internal options */
+               if (dopt->flags & OPT_INTERNAL)
+                       return -1;
+
+               type = dopt->flags & OPT_MASK_SIZE;
+               array = ((dopt->flags & OPT_ARRAY) == OPT_ARRAY) ? true : false;
+       } else if (data[0] == '"' || data[0] == '\'') {
+               char *end = strrchr(data + 1, data[0]);
+
+               if (end && (end == (data + strlen(data) - 1))) {
+                       /* Raw option is specified as a string */
+                       type = OPT_STR;
+                       data++;
+                       *end = '\0';
+               }
+       }
+
+       payload_len = config_parse_opt_data(data, &payload, type, array);
+       if (payload_len > 0)
+               ret = config_add_opt(optn, payload, payload_len);
+
+       free(payload);
+
+       return ret;
+}
diff --git a/src/config.h b/src/config.h
new file mode 100644 (file)
index 0000000..a664e45
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ *
+ * SPDX-License-Identifier: BSD-2-Clause-Patent
+ *
+ * SPDX-FileCopyrightText: Copyright (c) 2024 SoftAtHome
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * Subject to the terms and conditions of this license, each
+ * copyright holder and contributor hereby grants to those receiving
+ * rights under this license a perpetual, worldwide, non-exclusive,
+ * no-charge, royalty-free, irrevocable (except for failure to
+ * satisfy the conditions of this license) patent license to make,
+ * have made, use, offer to sell, sell, import, and otherwise
+ * transfer this software, where such license applies only to those
+ * patent claims, already acquired or hereafter acquired, licensable
+ * by such copyright holder or contributor that are necessarily
+ * infringed by:
+ *
+ * (a) their Contribution(s) (the licensed copyrights of copyright
+ * holders and non-copyrightable additions of contributors, in
+ * source or binary form) alone; or
+ *
+ * (b) combination of their Contribution(s) with the work of
+ * authorship to which such Contribution(s) was added by such
+ * copyright holder or contributor, if, at the time the Contribution
+ * is added, such addition causes such combination to be necessarily
+ * infringed. The patent license shall not apply to any other
+ * combinations which include the Contribution.
+ *
+ * Except as expressly stated above, no rights or licenses from any
+ * copyright holder or contributor is granted under this license,
+ * whether expressly, by implication, estoppel or otherwise.
+ *
+ * DISCLAIMER
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef _CONFIG_H_
+#define _CONFIG_H_
+
+#include "odhcp6c.h"
+
+struct config_dhcp {
+       bool release;
+       int dscp;
+       int sol_timeout;
+       int sk_prio;
+       bool stateful_only_mode;
+       enum odhcp6c_ia_mode ia_na_mode;
+       enum odhcp6c_ia_mode ia_pd_mode;
+       unsigned int client_options;
+       int allow_slaac_only;
+       unsigned int oro_user_cnt;
+};
+
+struct config_dhcp *config_dhcp_get(void);
+void config_dhcp_reset(void);
+void config_set_release(bool enable);
+bool config_set_dscp(unsigned int value) ;
+bool config_set_solicit_timeout(unsigned int timeout);
+bool config_set_sk_priority(unsigned int priority);
+void config_set_client_options(enum dhcpv6_config option, bool enable);
+bool config_set_request_addresses(char *mode);
+bool config_set_request_prefix(unsigned int length, unsigned int id);
+void config_set_force_prefix(bool enable);
+void config_set_stateful_only(bool enable);
+void config_set_allow_slaac_only(int value);
+void config_clear_requested_options(void) ;
+bool config_add_requested_options(unsigned int option);
+void config_clear_send_options(void);
+bool config_add_send_options(char *option);
+
+int config_add_opt(const uint16_t code, const uint8_t *data, const uint16_t len);
+int config_parse_opt_data(const char *data, uint8_t **dst, const unsigned int type, const bool array);
+int config_parse_opt(const char *opt);
+
+#endif /* _CONFIG_H_ */
index c5b8cb4573f7cd9142d65acd97cf6df1122e51f0..361de814d37722e8ebf99cb9f218950a2a7c9274 100644 (file)
@@ -35,6 +35,7 @@
 #include <arpa/inet.h>
 #include <linux/if_addr.h>
 
+#include "config.h"
 #include "odhcp6c.h"
 #include "ra.h"
 #include "ubus.h"
        ((((__const uint32_t *) (a))[0] & htonl (0xfe000000)) \
         == htonl (0xfc000000))
 #endif
-#define ARRAY_SEP " ,\t"
 
 static void sighandler(int signal);
 static int usage(void);
-static int add_opt(const uint16_t code, const uint8_t *data,
-               const uint16_t len);
-static int parse_opt_data(const char *data, uint8_t **dst,
-               const unsigned int type, const bool array);
-static int parse_opt(const char *opt);
 
 static uint8_t *state_data[_STATE_MAX] = {NULL};
 static size_t state_len[_STATE_MAX] = {0};
@@ -65,18 +60,11 @@ static volatile bool signal_usr1 = false;
 static volatile bool signal_usr2 = false;
 static volatile bool signal_term = false;
 
-static int urandom_fd = -1, allow_slaac_only = 0;
-static bool bound = false, release = true, ra = false;
+static int urandom_fd = -1;
+static bool bound = false, ra = false;
 static time_t last_update = 0;
 static char *ifname = NULL;
-static unsigned int dscp = 0;
-static int sol_timeout = DHCPV6_SOL_MAX_RT;
-static int sk_prio = 0;
-bool stateful_only_mode = 0;
-static enum odhcp6c_ia_mode ia_na_mode = IA_MODE_TRY;
-static enum odhcp6c_ia_mode ia_pd_mode = IA_MODE_NONE;
-static unsigned int client_options = DHCPV6_CLIENT_FQDN | DHCPV6_ACCEPT_RECONFIGURE;
-static unsigned int oro_user_cnt = 0;
+struct config_dhcp *config_dhcp = NULL;
 
 static unsigned int script_sync_delay = 10;
 static unsigned int script_accu_delay = 1;
@@ -196,26 +184,21 @@ int main(_unused int argc, char* const argv[])
        unsigned int ra_options = RA_RDNSS_DEFAULT_LIFETIME;
        unsigned int ra_holdoff_interval = RA_MIN_ADV_INTERVAL;
        bool terminate = false;
+       config_dhcp = config_dhcp_get();
+       config_dhcp_reset();
 
        while ((c = getopt(argc, argv, "S::DN:V:P:FB:c:i:r:Ru:Ux:s:kK:t:C:m:Lhedp:fav")) != -1) {
                switch (c) {
                case 'S':
-                       allow_slaac_only = (optarg) ? atoi(optarg) : -1;
+                       config_set_allow_slaac_only((optarg) ? atoi(optarg) : -1);
                        break;
 
                case 'D':
-                       stateful_only_mode = 1;
+                       config_set_stateful_only(true);
                        break;
 
                case 'N':
-                       if (!strcmp(optarg, "force")) {
-                               ia_na_mode = IA_MODE_FORCE;
-                               allow_slaac_only = -1;
-                       } else if (!strcmp(optarg, "none"))
-                               ia_na_mode = IA_MODE_NONE;
-                       else if (!strcmp(optarg, "try"))
-                               ia_na_mode = IA_MODE_TRY;
-                       else
+                       if (!config_set_request_addresses(optarg))
                                help = true;
                        break;
 
@@ -227,10 +210,10 @@ int main(_unused int argc, char* const argv[])
                        }
 
                        o_data = NULL;
-                       res = parse_opt_data(optarg, &o_data, opt->flags & OPT_MASK_SIZE,
+                       res = config_parse_opt_data(optarg, &o_data, opt->flags & OPT_MASK_SIZE,
                                                (opt->flags & OPT_ARRAY) == OPT_ARRAY);
                        if (res > 0) {
-                               res = add_opt(opt->code, o_data, res);
+                               res = config_add_opt(opt->code, o_data, res);
                                if (res) {
                                        if (res > 0)
                                                return 1;
@@ -244,11 +227,11 @@ int main(_unused int argc, char* const argv[])
                        break;
 
                case 'P':
-                       if (ia_pd_mode == IA_MODE_NONE)
-                               ia_pd_mode = IA_MODE_TRY;
+                       if (config_dhcp->ia_pd_mode == IA_MODE_NONE)
+                               config_dhcp->ia_pd_mode = IA_MODE_TRY;
 
-                       if (allow_slaac_only >= 0 && allow_slaac_only < 10)
-                               allow_slaac_only = 10;
+                       if (config_dhcp->allow_slaac_only >= 0 && config_dhcp->allow_slaac_only < 10)
+                               config_dhcp->allow_slaac_only = 10;
 
                        struct odhcp6c_request_prefix prefix = { 0 };
 
@@ -287,8 +270,7 @@ int main(_unused int argc, char* const argv[])
                        break;
 
                case 'F':
-                       allow_slaac_only = -1;
-                       ia_pd_mode = IA_MODE_FORCE;
+                       config_set_force_prefix(true);
                        break;
 
                case 'c':
@@ -328,7 +310,7 @@ int main(_unused int argc, char* const argv[])
                        break;
 
                case 'R':
-                       client_options |= DHCPV6_STRICT_OPTIONS;
+                       config_set_client_options(DHCPV6_STRICT_OPTIONS, true);
                        break;
 
                case 'u':
@@ -339,10 +321,10 @@ int main(_unused int argc, char* const argv[])
                        }
 
                        o_data = NULL;
-                       res = parse_opt_data(optarg, &o_data, opt->flags & OPT_MASK_SIZE,
+                       res = config_parse_opt_data(optarg, &o_data, opt->flags & OPT_MASK_SIZE,
                                                (opt->flags & OPT_ARRAY) == OPT_ARRAY);
                        if (res > 0) {
-                               res = add_opt(opt->code, o_data, res);
+                               res = config_add_opt(opt->code, o_data, res);
                                if (res) {
                                        if (res > 0)
                                                return 1;
@@ -356,7 +338,7 @@ int main(_unused int argc, char* const argv[])
                        break;
 
                case 'U':
-                       client_options |= DHCPV6_IGNORE_OPT_UNICAST;
+                       config_set_client_options(DHCPV6_IGNORE_OPT_UNICAST, true);
                        break;
 
                case 's':
@@ -364,21 +346,19 @@ int main(_unused int argc, char* const argv[])
                        break;
 
                case 'k':
-                       release = false;
+                       config_set_release(false);
                        break;
 
                case 'K':
-                       sk_prio = atoi(optarg);
+                       config_set_sk_priority(atoi(optarg));
                        break;
 
                case 't':
-                       sol_timeout = atoi(optarg);
+                       config_set_solicit_timeout(atoi(optarg));
                        break;
 
                case 'C':
-                       dscp = atoi(optarg);
-                       if (dscp > 63) {
-                               dscp = 0;
+                       if (!config_set_dscp(atoi(optarg))) {
                                syslog(LOG_ERR, "Invalid DSCP value, using default (0)");
                        }
                        break;
@@ -404,11 +384,11 @@ int main(_unused int argc, char* const argv[])
                        break;
 
                case 'f':
-                       client_options &= ~DHCPV6_CLIENT_FQDN;
+                       config_set_client_options(DHCPV6_CLIENT_FQDN, false);
                        break;
 
                case 'a':
-                       client_options &= ~DHCPV6_ACCEPT_RECONFIGURE;
+                       config_set_client_options(DHCPV6_ACCEPT_RECONFIGURE, false);
                        break;
 
                case 'v':
@@ -416,7 +396,7 @@ int main(_unused int argc, char* const argv[])
                        break;
 
                case 'x':
-                       res = parse_opt(optarg);
+                       res = config_parse_opt(optarg);
                        if (res) {
                                if (res > 0)
                                        return res;
@@ -431,8 +411,8 @@ int main(_unused int argc, char* const argv[])
                }
        }
 
-       if (allow_slaac_only > 0)
-               script_sync_delay = allow_slaac_only;
+       if (config_dhcp->allow_slaac_only > 0)
+               script_sync_delay = config_dhcp->allow_slaac_only;
 
        openlog("odhcp6c", logopt, LOG_DAEMON);
        if (!verbosity)
@@ -526,11 +506,9 @@ int main(_unused int argc, char* const argv[])
 
                        size_t oro_len = 0;
                        odhcp6c_get_state(STATE_ORO, &oro_len);
-                       oro_user_cnt = oro_len / sizeof(uint16_t);
-
-                       syslog(LOG_NOTICE, "number of user requested options %u", oro_user_cnt);
+                       config_dhcp->oro_user_cnt = oro_len / sizeof(uint16_t);
 
-                       if (init_dhcpv6(ifname, client_options, sk_prio, sol_timeout, dscp)) {
+                       if (init_dhcpv6(ifname, config_dhcp->client_options, config_dhcp->sk_prio, config_dhcp->sol_timeout, config_dhcp->dscp)) {
                                syslog(LOG_ERR, "failed to initialize: %s", strerror(errno));
                                return 1;
                        }
@@ -544,7 +522,7 @@ int main(_unused int argc, char* const argv[])
                        break;
 
                case DHCPV6_SOLICIT:
-                       mode = dhcpv6_set_ia_mode(ia_na_mode, ia_pd_mode, stateful_only_mode);
+                       mode = dhcpv6_set_ia_mode(config_dhcp->ia_na_mode, config_dhcp->ia_pd_mode, config_dhcp->stateful_only_mode);
                        if (mode == DHCPV6_STATELESS) {
                                dhcpv6_set_state(DHCPV6_REQUEST);
                                break;
@@ -560,7 +538,7 @@ int main(_unused int argc, char* const argv[])
                                dhcpv6_set_state(DHCPV6_REQUEST);
                        } else {
                                mode = DHCPV6_UNKNOWN;
-                               dhcpv6_set_state(DHCPV6_INIT);
+                               dhcpv6_set_state(DHCPV6_RESET);
                        }
                        break;
 
@@ -577,12 +555,12 @@ int main(_unused int argc, char* const argv[])
 
                        if ((res < 0) && signalled) {
                                mode = DHCPV6_UNKNOWN;
-                               dhcpv6_set_state(DHCPV6_INIT);
+                               dhcpv6_set_state(DHCPV6_RESET);
                                break;
                        }
 
                        mode = dhcpv6_promote_server_cand();
-                       dhcpv6_set_state(mode > DHCPV6_UNKNOWN ? DHCPV6_REQUEST : DHCPV6_INIT);
+                       dhcpv6_set_state(mode > DHCPV6_UNKNOWN ? DHCPV6_REQUEST : DHCPV6_RESET);
                        break;
 
                case DHCPV6_BOUND:
@@ -717,7 +695,7 @@ int main(_unused int argc, char* const argv[])
                        bound = false;
                        notify_state_change("unbound", 0, true);
 
-                       if (server_id_len > 0 && (ia_pd_len > 0 || ia_na_len > 0) && release)
+                       if (server_id_len > 0 && (ia_pd_len > 0 || ia_na_len > 0) && config_dhcp->release)
                                dhcpv6_send_request(DHCPV6_MSG_RELEASE);
 
                        odhcp6c_clear_state(STATE_IA_NA);
@@ -736,7 +714,7 @@ int main(_unused int argc, char* const argv[])
 
                        size_t oro_user_len, oro_total_len;
                        odhcp6c_get_state(STATE_ORO, &oro_total_len);
-                       oro_user_len = oro_user_cnt * sizeof(uint16_t);
+                       oro_user_len = config_dhcp->oro_user_cnt * sizeof(uint16_t);
                        odhcp6c_remove_state(STATE_ORO, oro_user_len, oro_total_len - oro_user_len);
 
                        close(dhcpv6_get_socket());
@@ -856,7 +834,7 @@ bool odhcp6c_signal_process(void)
                        ra = false;
                }
 
-               if (ra_updated && (bound || allow_slaac_only >= 0)) {
+               if (ra_updated && (bound || config_dhcp->allow_slaac_only >= 0)) {
                        notify_state_change("ra-updated", (!ra && !bound) ?
                                        script_sync_delay : script_accu_delay, false);
                        ra = true;
@@ -1013,20 +991,6 @@ static void odhcp6c_expire_list(enum odhcp6c_state state, uint32_t elapsed, bool
        }
 }
 
-static uint8_t *odhcp6c_state_find_opt(const uint16_t code)
-{
-       size_t opts_len;
-       uint8_t *odata, *opts = odhcp6c_get_state(STATE_OPTS, &opts_len);
-       uint16_t otype, olen;
-
-       dhcpv6_for_each_option(opts, &opts[opts_len], otype, olen, odata) {
-               if (otype == code)
-                       return &odata[-4];
-       }
-
-       return NULL;
-}
-
 void odhcp6c_expire(bool expire_ia_pd)
 {
        time_t now = odhcp6c_get_milli_time() / 1000;
@@ -1125,23 +1089,13 @@ static void sighandler(int signal)
                signal_term = true;
 }
 
-static int add_opt(const uint16_t code, const uint8_t *data, const uint16_t len)
+void notify_state_change(const char *status, int delay, bool resume)
 {
-       struct {
-               uint16_t code;
-               uint16_t len;
-       } opt_hdr = { htons(code), htons(len) };
-
-       if (odhcp6c_state_find_opt(code))
-               return -1;
-
-       if (odhcp6c_add_state(STATE_OPTS, &opt_hdr, sizeof(opt_hdr)) ||
-                       odhcp6c_add_state(STATE_OPTS, data, len)) {
-               syslog(LOG_ERR, "Failed to add option %hu", code);
-               return 1;
-       }
+       script_call(status, delay, resume);
 
-       return 0;
+#ifdef WITH_UBUS
+       ubus_dhcp_event(status);
+#endif /* WITH_UBUS */
 }
 
 struct odhcp6c_opt *odhcp6c_find_opt(const uint16_t code)
@@ -1158,7 +1112,7 @@ struct odhcp6c_opt *odhcp6c_find_opt(const uint16_t code)
        return NULL;
 }
 
-static struct odhcp6c_opt *odhcp6c_find_opt_by_name(const char *name)
+struct odhcp6c_opt *odhcp6c_find_opt_by_name(const char *name)
 {
        struct odhcp6c_opt *opt = opts;
 
@@ -1170,359 +1124,3 @@ static struct odhcp6c_opt *odhcp6c_find_opt_by_name(const char *name)
 
        return (opt->code > 0 ? opt : NULL);
 }
-
-static int parse_opt_u8(const char *src, uint8_t **dst)
-{
-       int len = strlen(src);
-
-       *dst = realloc(*dst, len/2);
-       if (!*dst)
-               return -1;
-
-       return script_unhexlify(*dst, len, src);
-}
-
-static int parse_opt_string(const char *src, uint8_t **dst, const bool array)
-{
-       int o_len = 0;
-       char *sep = strpbrk(src, ARRAY_SEP);
-
-       if (sep && !array)
-               return -1;
-
-       do {
-               if (sep) {
-                       *sep = 0;
-                       sep++;
-               }
-
-               int len = strlen(src);
-
-               *dst = realloc(*dst, o_len + len);
-               if (!*dst)
-                       return -1;
-
-               memcpy(&((*dst)[o_len]), src, len);
-
-               o_len += len;
-               src = sep;
-
-               if (sep)
-                       sep = strpbrk(src, ARRAY_SEP);
-       } while (src);
-
-       return o_len;
-}
-
-static int parse_opt_dns_string(const char *src, uint8_t **dst, const bool array)
-{
-       int o_len = 0;
-       char *sep = strpbrk(src, ARRAY_SEP);
-
-       if (sep && !array)
-               return -1;
-
-       do {
-               uint8_t tmp[256];
-
-               if (sep) {
-                       *sep = 0;
-                       sep++;
-               }
-
-               int len = dn_comp(src, tmp, sizeof(tmp), NULL, NULL);
-               if (len < 0)
-                       return -1;
-
-               *dst = realloc(*dst, o_len + len);
-               if (!*dst)
-                       return -1;
-
-               memcpy(&((*dst)[o_len]), tmp, len);
-
-               o_len += len;
-               src = sep;
-
-               if (sep)
-                       sep = strpbrk(src, ARRAY_SEP);
-       } while (src);
-
-       return o_len;
-}
-
-static int parse_opt_ip6(const char *src, uint8_t **dst, const bool array)
-{
-       int o_len = 0;
-       char *sep = strpbrk(src, ARRAY_SEP);
-
-       if (sep && !array)
-               return -1;
-
-       do {
-               int len = sizeof(struct in6_addr);
-
-               if (sep) {
-                       *sep = 0;
-                       sep++;
-               }
-
-               *dst = realloc(*dst, o_len + len);
-               if (!*dst)
-                       return -1;
-
-               if (inet_pton(AF_INET6, src, &((*dst)[o_len])) < 1)
-                       return -1;
-
-               o_len += len;
-               src = sep;
-
-               if (sep)
-                       sep = strpbrk(src, ARRAY_SEP);
-       } while (src);
-
-       return o_len;
-}
-
-static int parse_opt_user_class(const char *src, uint8_t **dst, const bool array)
-{
-       int o_len = 0;
-       char *sep = strpbrk(src, ARRAY_SEP);
-
-       if (sep && !array)
-               return -1;
-
-       do {
-               if (sep) {
-                       *sep = 0;
-                       sep++;
-               }
-               uint16_t str_len = strlen(src);
-
-               *dst = realloc(*dst, o_len + str_len + 2);
-               if (!*dst)
-                       return -1;
-
-               struct user_class {
-                       uint16_t len;
-                       uint8_t data[];
-               } *e = (struct user_class *)&((*dst)[o_len]);
-
-               e->len = ntohs(str_len);
-               memcpy(e->data, src, str_len);
-
-               o_len += str_len + 2;
-               src = sep;
-
-               if (sep)
-                       sep = strpbrk(src, ARRAY_SEP);
-       } while (src);
-
-       return o_len;
-}
-
-static int parse_opt_data(const char *data, uint8_t **dst, const unsigned int type,
-               const bool array)
-{
-       int ret = 0;
-
-       switch (type) {
-       case OPT_U8:
-               ret = parse_opt_u8(data, dst);
-               break;
-
-       case OPT_STR:
-               ret = parse_opt_string(data, dst, array);
-               break;
-
-       case OPT_DNS_STR:
-               ret = parse_opt_dns_string(data, dst, array);
-               break;
-
-       case OPT_IP6:
-               ret = parse_opt_ip6(data, dst, array);
-               break;
-
-       case OPT_USER_CLASS:
-               ret = parse_opt_user_class(data, dst, array);
-               break;
-
-       default:
-               ret = -1;
-               break;
-       }
-
-       return ret;
-}
-
-static int parse_opt(const char *opt)
-{
-       uint32_t optn;
-       char *data;
-       uint8_t *payload = NULL;
-       int payload_len;
-       unsigned int type = OPT_U8;
-       bool array = false;
-       struct odhcp6c_opt *dopt = NULL;
-       int ret = -1;
-
-       data = strpbrk(opt, ":");
-       if (!data)
-               return -1;
-
-       *data = '\0';
-       data++;
-
-       if (strlen(opt) == 0 || strlen(data) == 0)
-               return -1;
-
-       dopt = odhcp6c_find_opt_by_name(opt);
-       if (!dopt) {
-               char *e;
-               optn = strtoul(opt, &e, 0);
-               if (*e || e == opt || optn > USHRT_MAX)
-                       return -1;
-
-               dopt = odhcp6c_find_opt(optn);
-       } else
-               optn = dopt->code;
-
-       /* Check if the type for the content is well-known */
-       if (dopt) {
-               /* Refuse internal options */
-               if (dopt->flags & OPT_INTERNAL)
-                       return -1;
-
-               type = dopt->flags & OPT_MASK_SIZE;
-               array = ((dopt->flags & OPT_ARRAY) == OPT_ARRAY) ? true : false;
-       } else if (data[0] == '"' || data[0] == '\'') {
-               char *end = strrchr(data + 1, data[0]);
-
-               if (end && (end == (data + strlen(data) - 1))) {
-                       /* Raw option is specified as a string */
-                       type = OPT_STR;
-                       data++;
-                       *end = '\0';
-               }
-
-       }
-
-       payload_len = parse_opt_data(data, &payload, type, array);
-       if (payload_len > 0)
-               ret = add_opt(optn, payload, payload_len);
-
-       free(payload);
-
-       return ret;
-}
-
-void notify_state_change(const char *status, int delay, bool resume)
-{
-       script_call(status, delay, resume);
-
-#ifdef WITH_UBUS
-       ubus_dhcp_event(status);
-#endif /* WITH_UBUS */
-}
-
-void config_set_release(bool enable) {
-       release = enable;
-}
-
-bool config_set_dscp(unsigned int value) {
-       if (value > 63)
-               return false;
-       dscp = value;
-       return true;
-}
-
-bool config_set_solicit_timeout(unsigned int timeout) {
-       if (timeout > INT32_MAX)
-               return false;
-
-       sol_timeout = timeout;
-       return true;
-}
-
-bool config_set_sk_priority(unsigned int priority) {
-       if (priority > 6)
-               return false;
-
-       sk_prio = priority;
-       return true;
-}
-
-void config_set_client_options(enum dhcpv6_config option, bool enable) {
-       if (enable) {
-               client_options |= option;
-       } else {
-               client_options &= ~option;
-       }
-}
-
-bool config_set_request_addresses(char* mode) {
-       if (!strcmp(mode, "force")) {
-               ia_na_mode = IA_MODE_FORCE;
-               allow_slaac_only = -1;
-       } else if (!strcmp(mode, "none")) {
-               ia_na_mode = IA_MODE_NONE;
-       } else if (!strcmp(mode, "try")) {
-               ia_na_mode = IA_MODE_TRY;
-       } else {
-               return false;
-       }
-
-       return true;
-}
-
-bool config_set_request_prefix(unsigned int length, unsigned int id) {
-       struct odhcp6c_request_prefix prefix = {0};
-
-       odhcp6c_clear_state(STATE_IA_PD_INIT);
-
-       if (ia_pd_mode != IA_MODE_FORCE)
-               ia_pd_mode = length > 128 ? IA_MODE_NONE : IA_MODE_TRY;
-
-       if (length <= 128) {
-               if (allow_slaac_only >= 0 && allow_slaac_only < 10)
-                       allow_slaac_only = 10;
-
-               prefix.length = length;
-               prefix.iaid = htonl(id);
-
-               if (odhcp6c_add_state(STATE_IA_PD_INIT, &prefix, sizeof(prefix))) {
-                       syslog(LOG_ERR, "Failed to set request IPv6-Prefix");
-                       return false;
-               }
-       }
-
-       return true;
-}
-
-void config_set_stateful_only(bool enable) {
-       stateful_only_mode = enable;
-}
-
-void config_clear_requested_options(void) {
-       oro_user_cnt = 0;
-}
-
-bool config_add_requested_options(unsigned int option) {
-       if (option > UINT16_MAX)
-               return false;
-
-       option = htons(option);
-       if (odhcp6c_insert_state(STATE_ORO, 0, &option, 2)) {
-               syslog(LOG_ERR, "Failed to add requested option");
-               return false;
-       }
-       oro_user_cnt++;
-       return true;
-}
-
-void config_clear_send_options(void) {
-       odhcp6c_clear_state(STATE_OPTS);
-}
-
-bool config_add_send_options(char* option) {
-       return (parse_opt(option) == 0);
-}
index fc751c62e30f8a1a41c2d751f319abcb557dae6a..c398269f64cfe10cce0330534724df20d88b4a8d 100644 (file)
@@ -477,13 +477,13 @@ bool config_set_dscp(unsigned int value);
 bool config_set_solicit_timeout(unsigned int timeout);
 bool config_set_sk_priority(unsigned int value);
 void config_set_client_options(enum dhcpv6_config option, bool enable);
-bool config_set_request_addresses(charmode);
+bool config_set_request_addresses(char *mode);
 bool config_set_request_prefix(unsigned int length, unsigned int id);
 void config_set_stateful_only(bool enable);
 void config_clear_requested_options(void);
 bool config_add_requested_options(unsigned int option);
 void config_clear_send_options(void);
-bool config_add_send_options(charoption);
+bool config_add_send_options(char *option);
 
 int script_init(const char *path, const char *ifname);
 ssize_t script_unhexlify(uint8_t *dst, size_t len, const char *src);
@@ -512,3 +512,4 @@ bool odhcp6c_update_entry(enum odhcp6c_state state, struct odhcp6c_entry *new,
 void odhcp6c_expire(bool expire_ia_pd);
 uint32_t odhcp6c_elapsed(void);
 struct odhcp6c_opt *odhcp6c_find_opt(const uint16_t code);
+struct odhcp6c_opt *odhcp6c_find_opt_by_name(const char *name);