ubus: implement retransmission configuration via ubus
authorNicolas BESNARD <[email protected]>
Mon, 20 Jan 2025 16:05:29 +0000 (16:05 +0000)
committerÁlvaro Fernández Rojas <[email protected]>
Mon, 3 Nov 2025 15:21:24 +0000 (16:21 +0100)
Problem: odhcp6c uses static retransmission parameters defined in
RFC3315.

Solution: Make retransmission parameters configurable via ubus and
update the default values based on RFC8815.

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]>
src/config.c
src/config.h
src/dhcpv6.c
src/odhcp6c.c
src/odhcp6c.h
src/ubus.c

index 1b187304dd88077736d0ecacb43b125860a0591c..b0ba835bfc9338402768e741a1f6f2edc340738b 100644 (file)
@@ -80,7 +80,6 @@ struct config_dhcp *config_dhcp_get(void) {
 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;
@@ -88,6 +87,27 @@ void config_dhcp_reset(void) {
        config_dhcp.client_options = DHCPV6_CLIENT_FQDN | DHCPV6_ACCEPT_RECONFIGURE;
        config_dhcp.allow_slaac_only = -1;
        config_dhcp.oro_user_cnt = 0;
+       memset(config_dhcp.message_rtx, 0, sizeof(config_dhcp.message_rtx));
+       config_dhcp.message_rtx[CONFIG_DHCP_SOLICIT].delay_max = DHCPV6_MAX_DELAY;
+       config_dhcp.message_rtx[CONFIG_DHCP_SOLICIT].timeout_init = DHCPV6_SOL_INIT_RT;
+       config_dhcp.message_rtx[CONFIG_DHCP_SOLICIT].timeout_max = DHCPV6_SOL_MAX_RT;
+       config_dhcp.message_rtx[CONFIG_DHCP_REQUEST].timeout_init = DHCPV6_REQ_INIT_RT;
+       config_dhcp.message_rtx[CONFIG_DHCP_REQUEST].timeout_max = DHCPV6_REQ_MAX_RT;
+       config_dhcp.message_rtx[CONFIG_DHCP_REQUEST].rc_max = DHCPV6_REQ_MAX_RC;
+       config_dhcp.message_rtx[CONFIG_DHCP_RENEW].timeout_init = DHCPV6_REN_INIT_RT;
+       config_dhcp.message_rtx[CONFIG_DHCP_RENEW].timeout_max = DHCPV6_REN_MAX_RT;
+       config_dhcp.message_rtx[CONFIG_DHCP_REBIND].timeout_init = DHCPV6_REB_INIT_RT;
+       config_dhcp.message_rtx[CONFIG_DHCP_REBIND].timeout_max = DHCPV6_REB_MAX_RT;
+       config_dhcp.message_rtx[CONFIG_DHCP_INFO_REQ].delay_max = DHCPV6_MAX_DELAY;
+       config_dhcp.message_rtx[CONFIG_DHCP_INFO_REQ].timeout_init = DHCPV6_INF_INIT_RT;
+       config_dhcp.message_rtx[CONFIG_DHCP_INFO_REQ].timeout_max = DHCPV6_INF_MAX_RT;
+       config_dhcp.message_rtx[CONFIG_DHCP_RELEASE].timeout_init = DHCPV6_REL_INIT_RT;
+       config_dhcp.message_rtx[CONFIG_DHCP_RELEASE].rc_max = DHCPV6_REL_MAX_RC;
+       config_dhcp.message_rtx[CONFIG_DHCP_DECLINE].timeout_init = DHCPV6_DEC_INIT_RT;
+       config_dhcp.message_rtx[CONFIG_DHCP_DECLINE].rc_max = DHCPV6_DEC_MAX_RC;
+       config_dhcp.irt_default = DHCPV6_IRT_DEFAULT;
+       config_dhcp.irt_min = DHCPV6_IRT_MIN;
+       config_dhcp.rand_factor = DHCPV6_RAND_FACTOR;
 }
 
 void config_set_release(bool enable) {
@@ -95,24 +115,19 @@ void config_set_release(bool enable) {
 }
 
 bool config_set_dscp(unsigned int value) {
-       if (value > 63)
+       if (value > 63) {
+               syslog(LOG_ERR, "Invalid DSCP value");
                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)
+       if (priority > 6) {
+               syslog(LOG_ERR, "Invalid SK priority value");
                return false;
-
+       }
        config_dhcp.sk_prio = priority;
        return true;
 }
@@ -134,6 +149,7 @@ bool config_set_request_addresses(char* mode) {
        } else if (!strcmp(mode, "try")) {
                config_dhcp.ia_na_mode = IA_MODE_TRY;
        } else {
+               syslog(LOG_ERR, "Invalid IA_NA Request Addresses mode");
                return false;
        }
 
@@ -186,11 +202,14 @@ void config_clear_requested_options(void) {
 }
 
 bool config_add_requested_options(unsigned int option) {
-       if (option > UINT16_MAX)
+       if (option > UINT16_MAX) {
+               syslog(LOG_ERR, "Invalid requested option");
                return false;
+       }
 
        option = htons(option);
        if (odhcp6c_insert_state(STATE_ORO, 0, &option, 2)) {
+               syslog(LOG_ERR, "Failed to set requested option");
                return false;
        }
        config_dhcp.oro_user_cnt++;
@@ -205,6 +224,76 @@ bool config_add_send_options(char* option) {
        return (config_parse_opt(option) == 0);
 }
 
+bool config_set_rtx_delay_max(enum config_dhcp_msg msg, unsigned int value)
+{
+       if (msg >= CONFIG_DHCP_MAX || value > UINT8_MAX) {
+               syslog(LOG_ERR, "Invalid retransmission Maximum Delay value");
+               return false;
+       }
+       config_dhcp.message_rtx[msg].delay_max = value;
+       return true;
+}
+
+bool config_set_rtx_timeout_init(enum config_dhcp_msg msg, unsigned int value)
+{
+       if (msg >= CONFIG_DHCP_MAX || value > UINT8_MAX || value == 0) {
+               syslog(LOG_ERR, "Invalid retransmission Initial Timeout value");
+               return false;
+       }
+       config_dhcp.message_rtx[msg].timeout_init = value;
+       return true;
+}
+
+bool config_set_rtx_timeout_max(enum config_dhcp_msg msg, unsigned int value)
+{
+       if (msg >= CONFIG_DHCP_MAX || value > UINT16_MAX) {
+               syslog(LOG_ERR, "Invalid retransmission Maximum Timeout value");
+               return false;
+       }
+       config_dhcp.message_rtx[msg].timeout_max = value;
+       return true;
+}
+
+bool config_set_rtx_rc_max(enum config_dhcp_msg msg, unsigned int value)
+{
+       if (msg >= CONFIG_DHCP_MAX || value > UINT8_MAX) {
+               syslog(LOG_ERR, "Invalid retransmission Retry Attempt value");
+               return false;
+       }
+       config_dhcp.message_rtx[msg].rc_max = value;
+       return true;
+}
+
+bool config_set_irt_default(unsigned int value)
+{
+       if (value == 0) {
+               syslog(LOG_ERR, "Invalid Default Information Refresh Time value");
+               return false;
+       }
+       config_dhcp.irt_default = value;
+       return true;
+}
+
+bool config_set_irt_min(unsigned int value)
+{
+       if (value == 0) {
+               syslog(LOG_ERR, "Invalid Minimum Information Refresh Time value");
+               return false;
+       }
+       config_dhcp.irt_min = value;
+       return true;
+}
+
+bool config_set_rand_factor(unsigned int value)
+{
+       if (value > 999 || value < 10) {
+               syslog(LOG_ERR, "Invalid Random Factor value");
+               return false;
+       }
+       config_dhcp.rand_factor = value;
+       return true;
+}
+
 static int config_parse_opt_u8(const char *src, uint8_t **dst)
 {
        int len = strlen(src);
@@ -481,3 +570,24 @@ int config_parse_opt(const char *opt)
 
        return ret;
 }
+
+void config_apply_dhcp_rtx(struct dhcpv6_retx* dhcpv6_retx)
+{
+       dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_delay = config_dhcp.message_rtx[CONFIG_DHCP_SOLICIT].delay_max;
+       dhcpv6_retx[DHCPV6_MSG_SOLICIT].init_timeo = config_dhcp.message_rtx[CONFIG_DHCP_SOLICIT].timeout_init;
+       dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = config_dhcp.message_rtx[CONFIG_DHCP_SOLICIT].timeout_max;
+       dhcpv6_retx[DHCPV6_MSG_REQUEST].init_timeo = config_dhcp.message_rtx[CONFIG_DHCP_REQUEST].timeout_init;
+       dhcpv6_retx[DHCPV6_MSG_REQUEST].max_timeo = config_dhcp.message_rtx[CONFIG_DHCP_REQUEST].timeout_max;
+       dhcpv6_retx[DHCPV6_MSG_REQUEST].max_rc = config_dhcp.message_rtx[CONFIG_DHCP_REQUEST].rc_max;
+       dhcpv6_retx[DHCPV6_MSG_RENEW].init_timeo = config_dhcp.message_rtx[CONFIG_DHCP_RENEW].timeout_init;
+       dhcpv6_retx[DHCPV6_MSG_RENEW].max_timeo = config_dhcp.message_rtx[CONFIG_DHCP_RENEW].timeout_max;
+       dhcpv6_retx[DHCPV6_MSG_REBIND].init_timeo = config_dhcp.message_rtx[CONFIG_DHCP_REBIND].timeout_init;
+       dhcpv6_retx[DHCPV6_MSG_REBIND].max_timeo = config_dhcp.message_rtx[CONFIG_DHCP_REBIND].timeout_max;
+       dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_delay = config_dhcp.message_rtx[CONFIG_DHCP_INFO_REQ].delay_max;
+       dhcpv6_retx[DHCPV6_MSG_INFO_REQ].init_timeo = config_dhcp.message_rtx[CONFIG_DHCP_INFO_REQ].timeout_init;
+       dhcpv6_retx[DHCPV6_MSG_INFO_REQ].max_timeo = config_dhcp.message_rtx[CONFIG_DHCP_INFO_REQ].timeout_max;
+       dhcpv6_retx[DHCPV6_MSG_RELEASE].init_timeo = config_dhcp.message_rtx[CONFIG_DHCP_RELEASE].timeout_init;
+       dhcpv6_retx[DHCPV6_MSG_RELEASE].max_rc = config_dhcp.message_rtx[CONFIG_DHCP_RELEASE].rc_max;
+       dhcpv6_retx[DHCPV6_MSG_DECLINE].init_timeo = config_dhcp.message_rtx[CONFIG_DHCP_DECLINE].timeout_init;
+       dhcpv6_retx[DHCPV6_MSG_DECLINE].max_rc = config_dhcp.message_rtx[CONFIG_DHCP_DECLINE].rc_max;
+}
\ No newline at end of file
index a664e45ce4bd6c65acf6910221e1543b3bd77ce0..f0edade16f135acdad469e348a085d4b55018d78 100644 (file)
 
 #include "odhcp6c.h"
 
+struct config_dhcp_rtx {
+       uint8_t delay_max;
+       uint8_t timeout_init;
+       uint16_t timeout_max;
+       uint8_t rc_max;
+};
+
+enum config_dhcp_msg {
+       CONFIG_DHCP_SOLICIT,
+       CONFIG_DHCP_REQUEST,
+       CONFIG_DHCP_RENEW,
+       CONFIG_DHCP_REBIND,
+       CONFIG_DHCP_RELEASE,
+       CONFIG_DHCP_DECLINE,
+       CONFIG_DHCP_INFO_REQ,
+       CONFIG_DHCP_MAX
+};
+
 struct config_dhcp {
        bool release;
        int dscp;
-       int sol_timeout;
        int sk_prio;
        bool stateful_only_mode;
        enum odhcp6c_ia_mode ia_na_mode;
@@ -76,13 +93,16 @@ struct config_dhcp {
        unsigned int client_options;
        int allow_slaac_only;
        unsigned int oro_user_cnt;
+       struct config_dhcp_rtx message_rtx[CONFIG_DHCP_MAX];
+       uint32_t irt_default;
+       uint32_t irt_min;
+       uint16_t rand_factor;
 };
 
 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);
@@ -94,9 +114,18 @@ 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);
+bool config_set_rtx_delay_max(enum config_dhcp_msg msg, unsigned int value);
+bool config_set_rtx_timeout_init(enum config_dhcp_msg msg, unsigned int value);
+bool config_set_rtx_timeout_max(enum config_dhcp_msg msg, unsigned int value);
+bool config_set_rtx_rc_max(enum config_dhcp_msg msg, unsigned int value);
+bool config_set_irt_default(unsigned int value);
+bool config_set_irt_min(unsigned int value);
+bool config_set_rand_factor(unsigned int value);
 
 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);
 
+void config_apply_dhcp_rtx(struct dhcpv6_retx* dhcpv6_retx);
+
 #endif /* _CONFIG_H_ */
index 50ec027a6bb43e85d722048b16deb2fc5e2bd13e..f2f3cd9f9159ada38d3eb6c4b3de7cf9743f2d8b 100644 (file)
@@ -36,6 +36,7 @@
 #include <net/ethernet.h>
 
 #include <libubox/md5.h>
+#include "config.h"
 #include "odhcp6c.h"
 
 
@@ -44,7 +45,6 @@
 #define DHCPV6_CLIENT_PORT 546
 #define DHCPV6_SERVER_PORT 547
 #define DHCPV6_DUID_LLADDR 3
-#define DHCPV6_REQ_DELAY 1
 
 #define DHCPV6_SOL_MAX_RT_MIN 60
 #define DHCPV6_SOL_MAX_RT_MAX 86400
@@ -80,20 +80,158 @@ static int dhcpv6_commit_advert(void);
 
 // RFC 3315 - 5.5 Timeout and Delay values
 static const struct dhcpv6_retx dhcpv6_retx_default[_DHCPV6_MSG_MAX] = {
-       [DHCPV6_MSG_UNKNOWN] = {false, 1, 120, 0, "<POLL>",
-                       dhcpv6_handle_reconfigure, NULL, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1, 0},
-       [DHCPV6_MSG_SOLICIT] = {true, 1, DHCPV6_SOL_MAX_RT, 0, "SOLICIT",
-                       dhcpv6_handle_advert, dhcpv6_commit_advert, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1, 0},
-       [DHCPV6_MSG_REQUEST] = {true, 1, DHCPV6_REQ_MAX_RT, 10, "REQUEST",
-                       dhcpv6_handle_reply, NULL, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1, 0},
-       [DHCPV6_MSG_RENEW] = {false, 10, DHCPV6_REN_MAX_RT, 0, "RENEW",
-                       dhcpv6_handle_reply, NULL, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1, 0},
-       [DHCPV6_MSG_REBIND] = {false, 10, DHCPV6_REB_MAX_RT, 0, "REBIND",
-                       dhcpv6_handle_rebind_reply, NULL, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1, 0},
-       [DHCPV6_MSG_RELEASE] = {false, 1, 0, 5, "RELEASE", NULL, NULL, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1, 0},
-       [DHCPV6_MSG_DECLINE] = {false, 1, 0, 5, "DECLINE", NULL, NULL, false, 0, 0, 0,{0, 0, 0}, 0, 0, 0, -1, 0},
-       [DHCPV6_MSG_INFO_REQ] = {true, 1, DHCPV6_INF_MAX_RT, 0, "INFOREQ",
-                       dhcpv6_handle_reply, NULL, false, 0, 0, 0, {0, 0, 0}, 0, 0, 0, -1, 0},
+       [DHCPV6_MSG_UNKNOWN] = {
+               0,
+               1,
+               120,
+               0,
+               "<POLL>",
+               dhcpv6_handle_reconfigure,
+               NULL,
+               false,
+               0,
+               0,
+               0,
+               {0, 0, 0},
+               0,
+               0,
+               0,
+               -1,
+               0
+       },
+       [DHCPV6_MSG_SOLICIT] = {
+               DHCPV6_MAX_DELAY,
+               DHCPV6_SOL_INIT_RT,
+               DHCPV6_SOL_MAX_RT,
+               0,
+               "SOLICIT",
+               dhcpv6_handle_advert,
+               dhcpv6_commit_advert,
+               false,
+               0,
+               0,
+               0,
+               {0, 0, 0},
+               0,
+               0,
+               0,
+               -1,
+               0
+       },
+       [DHCPV6_MSG_REQUEST] = {
+               0,
+               DHCPV6_REQ_INIT_RT,
+               DHCPV6_REQ_MAX_RT,
+               DHCPV6_REQ_MAX_RC,
+               "REQUEST",
+               dhcpv6_handle_reply,
+               NULL,
+               false,
+               0,
+               0,
+               0,
+               {0, 0, 0},
+               0,
+               0,
+               0,
+               -1,
+               0
+       },
+       [DHCPV6_MSG_RENEW] = {
+               0,
+               DHCPV6_REN_INIT_RT,
+               DHCPV6_REN_MAX_RT,
+               0,
+               "RENEW",
+               dhcpv6_handle_reply,
+               NULL,
+               false,
+               0,
+               0,
+               0,
+               {0, 0, 0},
+               0,
+               0,
+               0,
+               -1,
+               0
+       },
+       [DHCPV6_MSG_REBIND] = {
+               0,
+               DHCPV6_REB_INIT_RT,
+               DHCPV6_REB_MAX_RT,
+               0,
+               "REBIND",
+                       dhcpv6_handle_rebind_reply,
+               NULL,
+               false,
+               0,
+               0,
+               0,
+               {0, 0, 0},
+               0,
+               0,
+               0,
+               -1,
+               0
+       },
+       [DHCPV6_MSG_RELEASE] = {
+               0,
+               DHCPV6_REL_INIT_RT,
+               0,
+               DHCPV6_REL_MAX_RC,
+               "RELEASE",
+               NULL,
+               NULL,
+               false,
+               0,
+               0,
+               0,
+               {0, 0, 0},
+               0,
+               0,
+               0,
+               -1,
+               0
+       },
+       [DHCPV6_MSG_DECLINE] = {
+               0,
+               DHCPV6_DEC_INIT_RT,
+               0,
+               DHCPV6_DEC_MAX_RC,
+               "DECLINE",
+               NULL,
+               NULL,
+               false,
+               0,
+               0,
+               0,
+               {0, 0, 0},
+               0,
+               0,
+               0,
+               -1,
+               0
+       },
+       [DHCPV6_MSG_INFO_REQ] = {
+               DHCPV6_MAX_DELAY,
+               DHCPV6_INF_INIT_RT,
+               DHCPV6_INF_MAX_RT,
+               0,
+               "INFOREQ",
+               dhcpv6_handle_reply,
+               NULL,
+               false,
+               0,
+               0,
+               0,
+               {0, 0, 0},
+               0,
+               0,
+               0,
+               -1,
+               0
+       },
 };
 static struct dhcpv6_retx dhcpv6_retx[_DHCPV6_MSG_MAX] = {0};
 
@@ -122,6 +260,9 @@ static unsigned int client_options = 0;
 // counters for statistics
 static struct dhcpv6_stats dhcpv6_stats = {0};
 
+// config
+static struct config_dhcp* config_dhcp = NULL;
+
 static uint32_t ntohl_unaligned(const uint8_t *data)
 {
        uint32_t buf;
@@ -402,11 +543,14 @@ void dhcpv6_reset_stats(void)
        memset(&dhcpv6_stats, 0, sizeof(dhcpv6_stats));
 }
 
-int init_dhcpv6(const char *ifname, unsigned int options, int sk_prio, int sol_timeout, unsigned int dscp)
+int init_dhcpv6(const char *ifname)
 {
+       config_dhcp = config_dhcp_get();
+
        memcpy(dhcpv6_retx, dhcpv6_retx_default, sizeof(dhcpv6_retx));
-       client_options = options;
-       dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = sol_timeout;
+       config_apply_dhcp_rtx(dhcpv6_retx);
+
+       client_options = config_dhcp->client_options;
 
        sock = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
        if (sock < 0)
@@ -498,10 +642,10 @@ int init_dhcpv6(const char *ifname, unsigned int options, int sk_prio, int sol_t
        if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname)) < 0)
                goto failure;
 
-       if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, &sk_prio, sizeof(sk_prio)) < 0)
+       if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, &(config_dhcp->sk_prio), sizeof(config_dhcp->sk_prio)) < 0)
                goto failure;
 
-       val = dscp << 2;
+       val = config_dhcp->dscp << 2;
        if (setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof(val)) < 0) {
                goto failure;
        }
@@ -868,7 +1012,7 @@ static int64_t dhcpv6_rand_delay(int64_t time)
        int random;
        odhcp6c_random(&random, sizeof(random));
 
-       return (time * ((int64_t)random % 1000LL)) / 10000LL;
+       return (time * ((int64_t)random % (config_dhcp->rand_factor*10LL))) / 10000LL;
 }
 
 // Message validation checks according to RFC3315 chapter 15
@@ -1134,7 +1278,7 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc,
 {
        uint8_t *odata;
        uint16_t otype, olen;
-       uint32_t refresh = 86400;
+       uint32_t refresh = config_dhcp->irt_default;
        int ret = 1;
        unsigned int state_IAs;
        unsigned int updated_IAs = 0;
@@ -1401,7 +1545,7 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc,
                odhcp6c_clear_state(STATE_SERVER_ADDR);
                odhcp6c_add_state(STATE_SERVER_ADDR, &from->sin6_addr, 16);
 
-               t1 = refresh;
+               t1 = (refresh < config_dhcp->irt_min) ? config_dhcp->irt_min : refresh;
                break;
 
        default:
@@ -1838,23 +1982,23 @@ int dhcpv6_send_request(enum dhcpv6_msg type)
        struct dhcpv6_retx *retx = &dhcpv6_retx[type];
        uint64_t current_milli_time = 0;
 
-       if (retx->delay ) {
-               if (retx->delay_msec == 0) {
-                       retx->delay_msec = (dhcpv6_rand_delay((10000 * DHCPV6_REQ_DELAY) / 2) + (1000 * DHCPV6_REQ_DELAY) / 2);
-                       dhcpv6_set_state_timeout(retx->delay_msec);
-                       retx->delay_msec += odhcp6c_get_milli_time();
-                       return 1;
-               } else {
-                       current_milli_time = odhcp6c_get_milli_time();
-                       if (current_milli_time < retx->delay_msec) {
-                               dhcpv6_set_state_timeout(retx->delay_msec - current_milli_time);
+       if (!retx->is_retransmit) {
+               if (retx->max_delay) {
+                       if (retx->delay_msec == 0) {
+                               retx->delay_msec = (dhcpv6_rand_delay((10000 * retx->max_delay) / 2) + (1000 * retx->max_delay) / 2);
+                               dhcpv6_set_state_timeout(retx->delay_msec);
+                               retx->delay_msec += odhcp6c_get_milli_time();
                                return 1;
+                       } else {
+                               current_milli_time = odhcp6c_get_milli_time();
+                               if (current_milli_time < retx->delay_msec) {
+                                       dhcpv6_set_state_timeout(retx->delay_msec - current_milli_time);
+                                       return 1;
+                               }
+                               retx->delay_msec = 0;
                        }
-                       retx->delay_msec = 0;
                }
-       }
-
-       if (!retx->is_retransmit) {
+               
                retx->is_retransmit = true;
                retx->rc = 0;
                retx->timeout = UINT32_MAX;
index c36e3e30995f1ffe9efcc2e8cb2e858c55e27097..78de3b7e39aa02636c8aee2d5bbb638c39b099ab 100644 (file)
@@ -363,13 +363,11 @@ int main(_unused int argc, char* const argv[])
                        break;
 
                case 't':
-                       config_set_solicit_timeout(atoi(optarg));
+                       config_set_rtx_timeout_max(CONFIG_DHCP_SOLICIT, atoi(optarg));
                        break;
 
                case 'C':
-                       if (!config_set_dscp(atoi(optarg))) {
-                               syslog(LOG_ERR, "Invalid DSCP value, using default (0)");
-                       }
+                       config_set_dscp(atoi(optarg));
                        break;
 
                case 'm':
@@ -517,7 +515,7 @@ int main(_unused int argc, char* const argv[])
                        odhcp6c_get_state(STATE_ORO, &oro_len);
                        config_dhcp->oro_user_cnt = oro_len / sizeof(uint16_t);
 
-                       if (init_dhcpv6(ifname, config_dhcp->client_options, config_dhcp->sk_prio, config_dhcp->sol_timeout, config_dhcp->dscp)) {
+                       if (init_dhcpv6(ifname)) {
                                syslog(LOG_ERR, "failed to initialize: %s", strerror(errno));
                                return 1;
                        }
@@ -666,9 +664,6 @@ int main(_unused int argc, char* const argv[])
                case DHCPV6_SOLICIT_PROCESSING:
                case DHCPV6_REQUEST_PROCESSING:
                        res = dhcpv6_state_processing(msg_type);
-
-                       if (signal_usr2 || signal_term)
-                               dhcpv6_set_state(DHCPV6_EXIT);
                        break;
 
                case DHCPV6_BOUND_PROCESSING:
@@ -678,8 +673,6 @@ int main(_unused int argc, char* const argv[])
 
                        if (signal_usr1)
                                dhcpv6_set_state(mode == DHCPV6_STATELESS ? DHCPV6_INFO : DHCPV6_RENEW);
-                       if (signal_usr2 || signal_term)
-                               dhcpv6_set_state(DHCPV6_EXIT);
                        break;
                
                case DHCPV6_RENEW_PROCESSING:
@@ -688,8 +681,6 @@ int main(_unused int argc, char* const argv[])
 
                        if (signal_usr1)
                                signal_usr1 = false;    // Acknowledged
-                       if (signal_usr2 || signal_term)
-                               dhcpv6_set_state(DHCPV6_EXIT);
                        break;
                
                case DHCPV6_EXIT:
@@ -736,6 +727,9 @@ int main(_unused int argc, char* const argv[])
                        break;
                }
 
+               if (signal_usr2 || signal_term)
+                       dhcpv6_set_state(DHCPV6_EXIT);
+
                poll_res = poll(fds, nfds, dhcpv6_get_state_timeout());
                dhcpv6_reset_state_timeout();
                if (poll_res == -1 && (errno == EINTR || errno == EAGAIN)) {
index c398269f64cfe10cce0330534724df20d88b4a8d..ac2dd32ddc571f01de6f6a85e66cc6ed356478d9 100644 (file)
 #define ND_OPT_RECURSIVE_DNS 25
 #define ND_OPT_DNSSL 31
 
+#define DHCPV6_MAX_DELAY 1
+#define DHCPV6_IRT_DEFAULT 86400
+#define DHCPV6_IRT_MIN 600
+#define DHCPV6_RAND_FACTOR 100
+
+#define DHCPV6_SOL_INIT_RT 1
 #define DHCPV6_SOL_MAX_RT 120
+
+#define DHCPV6_REQ_INIT_RT 1
 #define DHCPV6_REQ_MAX_RT 30
-#define DHCPV6_CNF_MAX_RT 4
+#define DHCPV6_REQ_MAX_RC 10
+
+#define DHCPV6_REN_INIT_RT 10
 #define DHCPV6_REN_MAX_RT 600
+
+#define DHCPV6_REB_INIT_RT 10
 #define DHCPV6_REB_MAX_RT 600
-#define DHCPV6_INF_MAX_RT 120
+
+#define DHCPV6_INF_INIT_RT 1
+#define DHCPV6_INF_MAX_RT 3600
+
+#define DHCPV6_REL_INIT_RT 1
+#define DHCPV6_REL_MAX_RC 4
+
+#define DHCPV6_DEC_INIT_RT 1
+#define DHCPV6_DEC_MAX_RC 4
 
 #define RA_MIN_ADV_INTERVAL 3   /* RFC 4861 paragraph 6.2.1 */
 
@@ -202,7 +222,7 @@ typedef int(reply_handler)(enum dhcpv6_msg orig, const int rc,
 
 // retransmission strategy
 struct dhcpv6_retx {
-       bool delay;
+       uint8_t max_delay;
        uint8_t init_timeo;
        uint16_t max_timeo;
        uint8_t max_rc;
@@ -445,7 +465,7 @@ struct odhcp6c_opt {
        const char *str;
 };
 
-int init_dhcpv6(const char *ifname, unsigned int client_options, int sk_prio, int sol_timeout, unsigned int dscp);
+int init_dhcpv6(const char *ifname);
 int dhcpv6_set_ia_mode(enum odhcp6c_ia_mode na, enum odhcp6c_ia_mode pd, bool stateful_only);
 int dhcpv6_promote_server_cand(void);
 int dhcpv6_send_request(enum dhcpv6_msg type);
@@ -472,19 +492,6 @@ int ra_get_retransmit(void);
 
 void notify_state_change(const char *status, int delay, bool resume);
 
-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 value);
-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_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(char *option);
-
 int script_init(const char *path, const char *ifname);
 ssize_t script_unhexlify(uint8_t *dst, size_t len, const char *src);
 void script_hexlify(char *dst, const uint8_t *src, size_t len);
index 71418a4eaf6226dac3af6d81b66b0b160b21cc69..fde51bf7f273be6e6435f9c715d7536b9ebe91a9 100644 (file)
@@ -71,6 +71,7 @@
 #include <libubox/blobmsg.h>
 
 #include "ubus.h"
+#include "config.h"
 
 #define CHECK(stmt) \
        do { \
@@ -111,6 +112,16 @@ enum {
        RECONFIGURE_DHCP_ATTR_REQ_ADDRESSES,
        RECONFIGURE_DHCP_ATTR_REQ_PREFIXES,
        RECONFIGURE_DHCP_ATTR_STATEFUL,
+       RECONFIGURE_DHCP_ATTR_MSG_SOLICIT,
+       RECONFIGURE_DHCP_ATTR_MSG_REQUEST,
+       RECONFIGURE_DHCP_ATTR_MSG_RENEW,
+       RECONFIGURE_DHCP_ATTR_MSG_REBIND,
+       RECONFIGURE_DHCP_ATTR_MSG_RELEASE,
+       RECONFIGURE_DHCP_ATTR_MSG_DECLINE,
+       RECONFIGURE_DHCP_ATTR_MSG_INFO_REQ,
+       RECONFIGURE_DHCP_ATTR_IRT_DEFAULT,
+       RECONFIGURE_DHCP_ATTR_IRT_MIN,
+       RECONFIGURE_DHCP_ATTR_RAND_FACTOR,
        RECONFIGURE_DHCP_ATTR_MAX,
 };
 
@@ -141,6 +152,16 @@ static const struct blobmsg_policy reconfigure_dhcp_policy[RECONFIGURE_DHCP_ATTR
        [RECONFIGURE_DHCP_ATTR_REQ_ADDRESSES] = { .name = "req_addresses", .type = BLOBMSG_TYPE_STRING},
        [RECONFIGURE_DHCP_ATTR_REQ_PREFIXES] = { .name = "req_prefixes", .type = BLOBMSG_TYPE_INT32},
        [RECONFIGURE_DHCP_ATTR_STATEFUL] = { .name = "stateful_only", .type = BLOBMSG_TYPE_BOOL},
+       [RECONFIGURE_DHCP_ATTR_MSG_SOLICIT] = { .name = "msg_solicit", .type = BLOBMSG_TYPE_TABLE},
+       [RECONFIGURE_DHCP_ATTR_MSG_REQUEST] = { .name = "msg_request", .type = BLOBMSG_TYPE_TABLE},
+       [RECONFIGURE_DHCP_ATTR_MSG_RENEW] = { .name = "msg_renew", .type = BLOBMSG_TYPE_TABLE},
+       [RECONFIGURE_DHCP_ATTR_MSG_REBIND] = { .name = "msg_rebind", .type = BLOBMSG_TYPE_TABLE},
+       [RECONFIGURE_DHCP_ATTR_MSG_RELEASE] = { .name = "msg_release", .type = BLOBMSG_TYPE_TABLE},
+       [RECONFIGURE_DHCP_ATTR_MSG_DECLINE] = { .name = "msg_decline", .type = BLOBMSG_TYPE_TABLE},
+       [RECONFIGURE_DHCP_ATTR_MSG_INFO_REQ] = { .name = "msg_inforeq", .type = BLOBMSG_TYPE_TABLE},
+       [RECONFIGURE_DHCP_ATTR_IRT_DEFAULT] = { .name = "irt_default", .type = BLOBMSG_TYPE_INT32},
+       [RECONFIGURE_DHCP_ATTR_IRT_MIN] = { .name = "irt_min", .type = BLOBMSG_TYPE_INT32},
+       [RECONFIGURE_DHCP_ATTR_RAND_FACTOR] = { .name = "rand_factor", .type = BLOBMSG_TYPE_INT32},
 };
 
 static struct ubus_method odhcp6c_object_methods[] = {
@@ -606,7 +627,6 @@ static int ubus_handle_reset_stats(_unused struct ubus_context *ctx, _unused str
        return UBUS_STATUS_OK;
 }
 
-
 static int ubus_handle_get_state(struct ubus_context *ctx, _unused struct ubus_object *obj,
                struct ubus_request_data *req, _unused const char *method,
                _unused struct blob_attr *msg)
@@ -618,6 +638,44 @@ static int ubus_handle_get_state(struct ubus_context *ctx, _unused struct ubus_o
        return UBUS_STATUS_OK;
 }
 
+static int ubus_handle_reconfigure_dhcp_rtx(enum config_dhcp_msg msg, struct blob_attr* table)
+{
+       struct blob_attr *cur = NULL;
+       uint32_t value = 0;
+       size_t rem = 0;
+
+       if (msg >= CONFIG_DHCP_MAX || blobmsg_data_len(table) == 0)
+               return UBUS_STATUS_INVALID_ARGUMENT;
+
+       blobmsg_for_each_attr(cur, table, rem) {
+               if (!blobmsg_check_attr(cur, true) || blobmsg_type(cur) != BLOBMSG_TYPE_INT32)
+                       return UBUS_STATUS_INVALID_ARGUMENT;
+
+               const char* name = blobmsg_name(cur);
+               if (strcmp("delay_max", name) == 0) {
+                       value = blobmsg_get_u32(cur);
+                       if (!config_set_rtx_delay_max(msg, value))
+                               return UBUS_STATUS_INVALID_ARGUMENT;
+               } else if (strcmp("timeout_init", name) == 0 ) {
+                       value = blobmsg_get_u32(cur);
+                       if (!config_set_rtx_timeout_init(msg, value))
+                               return UBUS_STATUS_INVALID_ARGUMENT;
+               } else if (strcmp("timeout_max", name) == 0 ) {
+                       value = blobmsg_get_u32(cur);
+                       if (!config_set_rtx_timeout_max(msg, value))
+                               return UBUS_STATUS_INVALID_ARGUMENT;
+               } else if (strcmp("rc_max", name) == 0) {
+                       value = blobmsg_get_u32(cur);
+                       if (!config_set_rtx_rc_max(msg, value))
+                               return UBUS_STATUS_INVALID_ARGUMENT;
+               } else {
+                       return UBUS_STATUS_INVALID_ARGUMENT;
+               }
+    }
+
+       return UBUS_STATUS_OK;
+}
+
 static int ubus_handle_reconfigure_dhcp(_unused struct ubus_context *ctx, _unused struct ubus_object *obj,
                _unused struct ubus_request_data *req, _unused const char *method,
                struct blob_attr *msg)
@@ -652,7 +710,7 @@ static int ubus_handle_reconfigure_dhcp(_unused struct ubus_context *ctx, _unuse
 
        if ((cur = tb[RECONFIGURE_DHCP_ATTR_SOL_TIMEOUT])) {
                value = blobmsg_get_u32(cur);
-               if (!config_set_solicit_timeout(value))
+               if (!config_set_rtx_timeout_max(CONFIG_DHCP_SOLICIT, value))
                        return UBUS_STATUS_INVALID_ARGUMENT;
                need_reinit = true;
                valid_args = true;
@@ -755,6 +813,92 @@ static int ubus_handle_reconfigure_dhcp(_unused struct ubus_context *ctx, _unuse
                valid_args = true;
        }
 
+       if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_SOLICIT])) {
+               if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_SOLICIT, cur))
+                       return UBUS_STATUS_INVALID_ARGUMENT;
+
+               need_reinit = true;
+               valid_args = true;
+       }
+
+       if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_REQUEST])) {
+               if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_REQUEST, cur))
+                       return UBUS_STATUS_INVALID_ARGUMENT;
+
+               need_reinit = true;
+               valid_args = true;
+       }
+
+       if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_RENEW])) {
+               if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_RENEW, cur))
+                       return UBUS_STATUS_INVALID_ARGUMENT;
+
+               need_reinit = true;
+               valid_args = true;
+       }
+
+       if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_REBIND])) {
+               if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_REBIND, cur))
+                       return UBUS_STATUS_INVALID_ARGUMENT;
+
+               need_reinit = true;
+               valid_args = true;
+       }
+
+       if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_RELEASE])) {
+               if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_RELEASE, cur))
+                       return UBUS_STATUS_INVALID_ARGUMENT;
+
+               need_reinit = true;
+               valid_args = true;
+       }
+
+       if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_DECLINE])) {
+               if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_DECLINE, cur))
+                       return UBUS_STATUS_INVALID_ARGUMENT;
+
+               need_reinit = true;
+               valid_args = true;
+       }
+
+       if ((cur = tb[RECONFIGURE_DHCP_ATTR_MSG_INFO_REQ])) {
+               if (ubus_handle_reconfigure_dhcp_rtx(CONFIG_DHCP_INFO_REQ, cur))
+                       return UBUS_STATUS_INVALID_ARGUMENT;
+
+               need_reinit = true;
+               valid_args = true;
+       }
+
+       if ((cur = tb[RECONFIGURE_DHCP_ATTR_IRT_MIN])) {
+               value = blobmsg_get_u32(cur);
+
+               if (!config_set_irt_min(value))
+                       return UBUS_STATUS_INVALID_ARGUMENT;
+
+               need_reinit = true;
+               valid_args = true;
+       }
+
+       if ((cur = tb[RECONFIGURE_DHCP_ATTR_IRT_DEFAULT])) {
+               value = blobmsg_get_u32(cur);
+
+               if (!config_set_irt_default(value))
+                       return UBUS_STATUS_INVALID_ARGUMENT;
+
+               need_reinit = true;
+               valid_args = true;
+       }
+
+       if ((cur = tb[RECONFIGURE_DHCP_ATTR_RAND_FACTOR])) {
+               value = blobmsg_get_u32(cur);
+
+               if (!config_set_rand_factor(value))
+                       return UBUS_STATUS_INVALID_ARGUMENT;
+
+               need_reinit = true;
+               valid_args = true;
+       }
+
        if (need_reinit)
                raise(SIGUSR2);