]> git.decadent.org.uk Git - odhcp6c.git/blobdiff - src/dhcpv6.c
Restart transaction if server returns IAID error code
[odhcp6c.git] / src / dhcpv6.c
index 9742c39dd4316cf1c750246d19ef43319d6ec2b1..ee2031d1a81d8abc999a9625235a5ea69fc631c3 100644 (file)
@@ -142,8 +142,12 @@ int init_dhcpv6(const char *ifname, int request_pd)
                        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),
+#ifdef EXT_PREFIX_CLASS
+                       htons(DHCPV6_OPT_PREFIX_CLASS),
+#endif
        };
        odhcp6c_add_state(STATE_ORO, oro, sizeof(oro));
 
@@ -567,6 +571,13 @@ static int dhcpv6_handle_advert(enum dhcpv6_msg orig,
        struct dhcpv6_server_cand cand = {false, false, 0, 0, {0}, NULL, NULL, 0, 0};
 
        dhcpv6_for_each_option(opt, end, otype, olen, odata) {
+               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 (otype == DHCPV6_OPT_SERVERID && olen <= 130) {
                        memcpy(cand.duid, odata, olen);
                        cand.duid_len = olen;
@@ -598,13 +609,6 @@ static int dhcpv6_handle_advert(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) {
@@ -740,18 +744,20 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig,
                        if (ia_hdr->iaid != 1 || l_t2 < l_t1)
                                continue;
 
-                       bool error = false;
+                       int error = 0;
                        uint16_t stype, slen;
                        uint8_t *sdata;
                        // Test status and bail if error
                        dhcpv6_for_each_option(&ia_hdr[1], odata + olen,
                                        stype, slen, sdata)
-                               if (stype == DHCPV6_OPT_STATUS && slen >= 2 &&
-                                               (sdata[0] || sdata[1]))
-                                       error = true;
+                               if (stype == DHCPV6_OPT_STATUS && slen >= 2)
+                                       error = ((int)sdata[0]) << 8 | ((int)sdata[1]);
 
-                       if (error)
-                               continue;
+                       if (error) {
+                               syslog(LOG_WARNING, "Server returned IAID status %i!", error);
+                               raise(SIGUSR2);
+                               break;
+                       }
 
                        uint32_t n = dhcpv6_parse_ia(&ia_hdr[1], odata + olen);
 
@@ -817,6 +823,15 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig,
                }
        }
 
+       if (t1 == UINT32_MAX)
+               t1 = 300;
+
+       if (t2 == UINT32_MAX)
+               t2 = 600;
+
+       if (t3 == UINT32_MAX)
+               t3 = 3600;
+
        return true;
 }
 
@@ -827,11 +842,11 @@ static uint32_t dhcpv6_parse_ia(void *opt, void *end)
        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))
@@ -845,11 +860,19 @@ static uint32_t dhcpv6_parse_ia(void *opt, void *end)
 
                        entry.length = prefix->prefix;
                        entry.target = prefix->addr;
+                       uint16_t stype, slen;
+                       uint8_t *sdata;
+
+#ifdef EXT_PREFIX_CLASS
+                        // 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.class = sdata[0] << 8 | sdata[1];
+#endif
 
                        // 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)
@@ -904,9 +927,18 @@ static uint32_t dhcpv6_parse_ia(void *opt, void *end)
                        entry.length = 128;
                        entry.target = addr->addr;
 
+#ifdef EXT_PREFIX_CLASS
+                       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.class = sdata[0] << 8 | sdata[1];
+#endif
+
                        odhcp6c_update_entry(STATE_IA_NA, &entry);
                }
-
                if (entry.valid > 0 && timeout > entry.valid)
                        timeout = entry.valid;
        }