odhcp6c: add -K option to set packet kernel priority
[project/odhcp6c.git] / src / dhcpv6.c
index 51b99924991e1ea46f06142a1f9e20bf3c65ff9e..ca5957e3611c7d08ad0e6a6feba37ffea250dd93 100644 (file)
@@ -104,6 +104,7 @@ static int64_t t1 = 0, t2 = 0, t3 = 0;
 
 // IA states
 static enum odhcp6c_ia_mode na_mode = IA_MODE_NONE, pd_mode = IA_MODE_NONE;
+static bool stateful_only_mode = false;
 static bool accept_reconfig = false;
 // Server unicast address
 static struct in6_addr server_addr = IN6ADDR_ANY_INIT;
@@ -193,7 +194,7 @@ static char *dhcpv6_status_code_to_str(uint16_t code)
        return "Unknown";
 }
 
-int init_dhcpv6(const char *ifname, unsigned int options, int sol_timeout)
+int init_dhcpv6(const char *ifname, unsigned int options, int sk_prio, int sol_timeout)
 {
        client_options = options;
        dhcpv6_retx[DHCPV6_MSG_SOLICIT].max_timeo = sol_timeout;
@@ -288,6 +289,9 @@ int init_dhcpv6(const char *ifname, unsigned int options, int sol_timeout)
        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)
+               goto failure;
+
        struct sockaddr_in6 client_addr = { .sin6_family = AF_INET6,
                .sin6_port = htons(DHCPV6_CLIENT_PORT), .sin6_flowinfo = 0 };
 
@@ -317,12 +321,13 @@ enum {
        IOV_TOTAL
 };
 
-int dhcpv6_set_ia_mode(enum odhcp6c_ia_mode na, enum odhcp6c_ia_mode pd)
+int dhcpv6_set_ia_mode(enum odhcp6c_ia_mode na, enum odhcp6c_ia_mode pd, bool stateful_only)
 {
        int mode = DHCPV6_UNKNOWN;
 
        na_mode = na;
        pd_mode = pd;
+       stateful_only_mode = stateful_only;
 
        if (na_mode == IA_MODE_NONE && pd_mode == IA_MODE_NONE)
                mode = DHCPV6_STATELESS;
@@ -1004,7 +1009,8 @@ static int dhcpv6_handle_advert(enum dhcpv6_msg orig, const int rc,
                }
        }
 
-       if ((!have_na && na_mode == IA_MODE_FORCE) ||
+       if ((stateful_only_mode && !have_na && !have_pd) ||
+                       (!have_na && na_mode == IA_MODE_FORCE) ||
                        (!have_pd && pd_mode == IA_MODE_FORCE)) {
                /*
                 * RFC7083 states to process the SOL_MAX_RT and
@@ -1063,7 +1069,7 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc,
        unsigned int updated_IAs = 0;
        bool handled_status_codes[_DHCPV6_Status_Max] = { false, };
 
-       odhcp6c_expire();
+       odhcp6c_expire(true);
 
        if (orig == DHCPV6_MSG_UNKNOWN) {
                static time_t last_update = 0;
@@ -1343,7 +1349,7 @@ static unsigned int dhcpv6_parse_ia(void *opt, void *end)
        t1 = ntohl(ia_hdr->t1);
        t2 = ntohl(ia_hdr->t2);
 
-       if (t1 > t2)
+       if (t1 > t2 && t1 > 0 && t2 > 0)
                return 0;
 
        syslog(LOG_INFO, "%s %04x T1 %d T2 %d", ntohs(ia_hdr->type) == DHCPV6_OPT_IA_PD ? "IA_PD" : "IA_NA", ntohl(ia_hdr->iaid), t1, t2);
@@ -1458,12 +1464,19 @@ static unsigned int dhcpv6_calc_refresh_timers(void)
 {
        struct odhcp6c_entry *e;
        size_t ia_na_entries, ia_pd_entries, i;
+       size_t invalid_entries = 0;
        int64_t l_t1 = UINT32_MAX, l_t2 = UINT32_MAX, l_t3 = 0;
 
        e = odhcp6c_get_state(STATE_IA_NA, &ia_na_entries);
        ia_na_entries /= sizeof(*e);
 
        for (i = 0; i < ia_na_entries; i++) {
+               /* Exclude invalid IA_NA entries */
+               if (!e[i].valid) {
+                       invalid_entries++;
+                       continue;
+               }
+
                if (e[i].t1 < l_t1)
                        l_t1 = e[i].t1;
 
@@ -1478,6 +1491,12 @@ static unsigned int dhcpv6_calc_refresh_timers(void)
        ia_pd_entries /= sizeof(*e);
 
        for (i = 0; i < ia_pd_entries; i++) {
+               /* Exclude invalid IA_PD entries */
+               if (!e[i].valid) {
+                       invalid_entries++;
+                       continue;
+               }
+
                if (e[i].t1 < l_t1)
                        l_t1 = e[i].t1;
 
@@ -1488,7 +1507,7 @@ static unsigned int dhcpv6_calc_refresh_timers(void)
                        l_t3 = e[i].valid;
        }
 
-       if (ia_pd_entries || ia_na_entries) {
+       if (ia_pd_entries + ia_na_entries - invalid_entries) {
                t1 = l_t1;
                t2 = l_t2;
                t3 = l_t3;