]> 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)
1  2 
src/dhcpv6.c
src/odhcp6c.c
src/odhcp6c.h

diff --combined src/dhcpv6.c
index 01d14942f73567337dabe9fdb0da8e07c7ce87c3,9742c39dd4316cf1c750246d19ef43319d6ec2b1..1df31cd1811c585ce35d5aa9d139abfbd2dfc31a
@@@ -142,10 -142,8 +142,10 @@@ int init_dhcpv6(const char *ifname, in
                        htons(DHCPV6_OPT_DNS_SERVERS),
                        htons(DHCPV6_OPT_DNS_DOMAIN),
                        htons(DHCPV6_OPT_NTP_SERVER),
 +                      htons(DHCPV6_OPT_SIP_SERVER_A),
                        htons(DHCPV6_OPT_AFTR_NAME),
                        htons(DHCPV6_OPT_PD_EXCLUDE),
 +                      htons(DHCPV6_OPT_PREFIX_CLASS),
        };
        odhcp6c_add_state(STATE_ORO, oro, sizeof(oro));
  
@@@ -352,14 -350,14 +352,14 @@@ static int64_t dhcpv6_rand_delay(int64_
  {
        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) {
        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 -559,12 +561,12 @@@ static int dhcpv6_handle_reconfigure(_u
  
  
  // 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) {
                                        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 -649,14 +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 -712,12 +714,12 @@@ static int dhcpv6_handle_reply(enum dhc
                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);
@@@ -802,11 -827,11 +829,11 @@@ static uint32_t dhcpv6_parse_ia(void *o
        uint16_t otype, olen;
        uint8_t *odata;
  
 -      struct odhcp6c_entry entry = {IN6ADDR_ANY_INIT,
 -                      0, 0, IN6ADDR_ANY_INIT, 0, 0};
 -
        // Update address IA
        dhcpv6_for_each_option(opt, end, otype, olen, odata) {
 +          struct odhcp6c_entry entry = {IN6ADDR_ANY_INIT,
 +                                        0, 0, IN6ADDR_ANY_INIT, 0, 0, 0};
 +
                if (otype == DHCPV6_OPT_IA_PREFIX) {
                        struct dhcpv6_ia_prefix *prefix = (void*)&odata[-4];
                        if (olen + 4U < sizeof(*prefix))
  
                        entry.length = prefix->prefix;
                        entry.target = prefix->addr;
 +                      uint16_t stype, slen;
 +                      uint8_t *sdata;
 +
 +                        // Find prefix class, if any
 +                      dhcpv6_for_each_option(&prefix[1], odata + olen,
 +                                               stype, slen, sdata)
 +                          if (stype == DHCPV6_OPT_PREFIX_CLASS && slen == 2) 
 +                            entry.prefix_class = ntohs(*((uint16_t*)sdata));
  
                        // Parse PD-exclude
                        bool ok = true;
 -                      uint16_t stype, slen;
 -                      uint8_t *sdata;
                        dhcpv6_for_each_option(odata + sizeof(*prefix) - 4U,
                                        odata + olen, stype, slen, sdata) {
                                if (stype != DHCPV6_OPT_PD_EXCLUDE || slen < 2)
                        entry.length = 128;
                        entry.target = addr->addr;
  
 +                      uint16_t stype, slen;
 +                      uint8_t *sdata;
 +                      
 +                      // Find prefix class, if any
 +                      dhcpv6_for_each_option(&addr[1], odata + olen,
 +                                             stype, slen, sdata)
 +                        if (stype == DHCPV6_OPT_PREFIX_CLASS && slen == 2) 
 +                            entry.prefix_class = ntohs(*((uint16_t*)sdata));
 +                      
                        odhcp6c_update_entry(STATE_IA_NA, &entry);
                }
  
diff --combined src/odhcp6c.c
index 6da604728c4f330d446e10c5c0e941c6ce529d65,f732d9e8fa52b36f1f2f5d314e94e98967df8851..d47e17c158ab1b8d2ffe4026954d8a4e6e934793
@@@ -192,7 -192,7 +192,7 @@@ int main(_unused int argc, char* const 
  
        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);
                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 +414,18 @@@ size_t odhcp6c_remove_state(enum odhcp6
  }
  
  
+ 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];
@@@ -439,7 -460,6 +460,7 @@@ void odhcp6c_update_entry_safe(enum odh
                if (x) {
                        x->valid = new->valid;
                        x->preferred = new->preferred;
 +                        x->prefix_class = new->prefix_class;
                } else {
                        odhcp6c_add_state(state, new, sizeof(*new));
                }
diff --combined src/odhcp6c.h
index d8a9bffdf80e0040285182cc5de6ab3f0b3d6618,ac0932fa1486eb8f3060ac49d632aaa1042187ea..e0f6f62ce386515b73df1fea85f8e7582d7e677d
@@@ -53,8 -53,6 +53,8 @@@ enum dhcvp6_opt 
        DHCPV6_OPT_SIP_SERVER_A = 22,
        DHCPV6_OPT_AFTR_NAME = 64,
        DHCPV6_OPT_PD_EXCLUDE = 67,
 +        /* draft-bhandari-dhc-class-based-prefix */
 +      DHCPV6_OPT_PREFIX_CLASS = 200, /* NOT STANDARDIZED! */
  };
  
  enum dhcpv6_opt_npt {
@@@ -160,6 -158,10 +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;
  };
  
  
@@@ -213,7 -215,6 +217,7 @@@ struct odhcp6c_entry 
        struct in6_addr target;
        uint32_t valid;
        uint32_t preferred;
 +        uint32_t prefix_class;
  };
  
  
@@@ -239,6 -240,7 +243,7 @@@ void odhcp6c_random(void *buf, size_t l
  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