]> git.decadent.org.uk Git - odhcp6c.git/commitdiff
Merge remote-tracking branch 'up/master' into hnet
authorMarkus Stenberg <markus.stenberg@iki.fi>
Wed, 31 Jul 2013 21:58:33 +0000 (23:58 +0200)
committerMarkus Stenberg <markus.stenberg@iki.fi>
Wed, 31 Jul 2013 21:58:33 +0000 (23:58 +0200)
src/dhcpv6.c
src/odhcp6c.c
src/odhcp6c.h

index 01d14942f73567337dabe9fdb0da8e07c7ce87c3..1df31cd1811c585ce35d5aa9d139abfbd2dfc31a 100644 (file)
@@ -352,14 +352,14 @@ static int64_t dhcpv6_rand_delay(int64_t time)
 {
        int random;
        odhcp6c_random(&random, sizeof(random));
-       return (time * (random % 1000)) / 10000;
+       return (time * ((int64_t)random % 1000LL)) / 10000LL;
 }
 
 
 int dhcpv6_request(enum dhcpv6_msg type)
 {
        uint8_t buf[1536];
-       uint32_t timeout = UINT32_MAX;
+       uint64_t timeout = UINT32_MAX;
        struct dhcpv6_retx *retx = &dhcpv6_retx[type];
 
        if (retx->delay) {
@@ -380,7 +380,7 @@ int dhcpv6_request(enum dhcpv6_msg type)
        if (timeout == 0)
                return -1;
 
-       syslog(LOG_NOTICE, "Sending %s (timeout %us)", retx->name, timeout);
+       syslog(LOG_NOTICE, "Sending %s (timeout %us)", retx->name, (unsigned)timeout);
 
        uint64_t start = odhcp6c_get_milli_time(), round_start = start, elapsed;
 
@@ -561,12 +561,12 @@ static int dhcpv6_handle_reconfigure(_unused enum dhcpv6_msg orig,
 
 
 // Collect all advertised servers
-static int dhcpv6_handle_advert(_unused enum dhcpv6_msg orig,
+static int dhcpv6_handle_advert(enum dhcpv6_msg orig,
                const void *opt, const void *end)
 {
        uint16_t olen, otype;
        uint8_t *odata;
-       struct dhcpv6_server_cand cand = {false, false, 0, 0, {0}};
+       struct dhcpv6_server_cand cand = {false, false, 0, 0, {0}, NULL, NULL, 0, 0};
 
        dhcpv6_for_each_option(opt, end, otype, olen, odata) {
                if (otype == DHCPV6_OPT_SERVERID && olen <= 130) {
@@ -600,10 +600,25 @@ static int dhcpv6_handle_advert(_unused enum dhcpv6_msg orig,
                                        cand.preference -= 2000;
                        }
                }
+
+               if (orig == DHCPV6_MSG_SOLICIT &&
+                               (otype == DHCPV6_OPT_IA_PD || otype == DHCPV6_OPT_IA_NA) &&
+                               olen > sizeof(struct dhcpv6_ia_hdr)) {
+                       struct dhcpv6_ia_hdr *ia_hdr = (void*)(&odata[-4]);
+                       dhcpv6_parse_ia(&ia_hdr[1], odata + olen);
+               }
        }
 
-       if (cand.duid_len > 0)
+       if (cand.duid_len > 0) {
+               cand.ia_na = odhcp6c_move_state(STATE_IA_NA, &cand.ia_na_len);
+               cand.ia_pd = odhcp6c_move_state(STATE_IA_PD, &cand.ia_pd_len);
                odhcp6c_add_state(STATE_SERVER_CAND, &cand, sizeof(cand));
+       }
+
+       if (orig == DHCPV6_MSG_SOLICIT) {
+               odhcp6c_clear_state(STATE_IA_NA);
+               odhcp6c_clear_state(STATE_IA_PD);
+       }
 
        return -1;
 }
@@ -636,8 +651,14 @@ static int dhcpv6_commit_advert(void)
                odhcp6c_add_state(STATE_SERVER_ID, hdr, sizeof(hdr));
                odhcp6c_add_state(STATE_SERVER_ID, c->duid, c->duid_len);
                accept_reconfig = c->wants_reconfigure;
+               odhcp6c_add_state(STATE_IA_NA, c->ia_na, c->ia_na_len);
+               odhcp6c_add_state(STATE_IA_PD, c->ia_pd, c->ia_pd_len);
        }
 
+       for (size_t i = 0; i < cand_len / sizeof(*c); ++i) {
+               free(cand[i].ia_na);
+               free(cand[i].ia_pd);
+       }
        odhcp6c_clear_state(STATE_SERVER_CAND);
 
        if (!c)
@@ -693,6 +714,12 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig,
                t1 = t2 = t3 = UINT32_MAX;
        }
 
+       if (orig == DHCPV6_MSG_REQUEST) {
+               // Delete NA and PD we have in the state from the Advert
+               odhcp6c_clear_state(STATE_IA_NA);
+               odhcp6c_clear_state(STATE_IA_PD);
+       }
+
        if (opt) {
                odhcp6c_clear_state(STATE_DNS);
                odhcp6c_clear_state(STATE_SEARCH);
index 6da604728c4f330d446e10c5c0e941c6ce529d65..d47e17c158ab1b8d2ffe4026954d8a4e6e934793 100644 (file)
@@ -192,7 +192,7 @@ int main(_unused int argc, char* const argv[])
 
        while (do_signal != SIGTERM) { // Main logic
                odhcp6c_clear_state(STATE_SERVER_ID);
-               odhcp6c_clear_state(STATE_SERVER_CAND);
+               odhcp6c_clear_state(STATE_IA_NA);
                odhcp6c_clear_state(STATE_IA_PD);
                odhcp6c_clear_state(STATE_SNTP_IP);
                odhcp6c_clear_state(STATE_SNTP_FQDN);
@@ -201,6 +201,15 @@ int main(_unused int argc, char* const argv[])
                dhcpv6_set_ia_na_mode(ia_na_mode);
                bound = false;
 
+               // Server candidates need deep-delete
+               size_t cand_len;
+               struct dhcpv6_server_cand *cand = odhcp6c_get_state(STATE_SERVER_CAND, &cand_len);
+               for (size_t i = 0; i < cand_len / sizeof(*cand); ++i) {
+                       free(cand[i].ia_na);
+                       free(cand[i].ia_pd);
+               }
+               odhcp6c_clear_state(STATE_SERVER_CAND);
+
                syslog(LOG_NOTICE, "(re)starting transaction on %s", ifname);
 
                do_signal = 0;
@@ -405,6 +414,18 @@ size_t odhcp6c_remove_state(enum odhcp6c_state state, size_t offset, size_t len)
 }
 
 
+void* odhcp6c_move_state(enum odhcp6c_state state, size_t *len)
+{
+       *len = state_len[state];
+       void *data = state_data[state];
+
+       state_len[state] = 0;
+       state_data[state] = NULL;
+
+       return data;
+}
+
+
 void* odhcp6c_get_state(enum odhcp6c_state state, size_t *len)
 {
        *len = state_len[state];
index d8a9bffdf80e0040285182cc5de6ab3f0b3d6618..e0f6f62ce386515b73df1fea85f8e7582d7e677d 100644 (file)
@@ -160,6 +160,10 @@ struct dhcpv6_server_cand {
        int16_t preference;
        uint8_t duid_len;
        uint8_t duid[130];
+       void *ia_na;
+       void *ia_pd;
+       size_t ia_na_len;
+       size_t ia_pd_len;
 };
 
 
@@ -239,6 +243,7 @@ void odhcp6c_random(void *buf, size_t len);
 void odhcp6c_clear_state(enum odhcp6c_state state);
 void odhcp6c_add_state(enum odhcp6c_state state, const void *data, size_t len);
 size_t odhcp6c_remove_state(enum odhcp6c_state state, size_t offset, size_t len);
+void* odhcp6c_move_state(enum odhcp6c_state state, size_t *len);
 void* odhcp6c_get_state(enum odhcp6c_state state, size_t *len);
 
 // Entry manipulation