dhcpv6: set cnt to correct IOV enum
[oweals/odhcp6c.git] / src / dhcpv6.c
index d70d533558abcd6525f766c35d9cef69d4c93a1a..857cbe1ce1b52c408d4ce22befc829c00e3b7b09 100644 (file)
@@ -103,7 +103,6 @@ static int ifindex = -1;
 static int64_t t1 = 0, t2 = 0, t3 = 0;
 
 // IA states
-static int request_prefix = -1;
 static enum odhcp6c_ia_mode na_mode = IA_MODE_NONE, pd_mode = IA_MODE_NONE;
 static bool accept_reconfig = false;
 // Server unicast address
@@ -183,7 +182,6 @@ int init_dhcpv6(const char *ifname, unsigned int options, int sol_timeout)
                        htons(DHCPV6_OPT_SIP_SERVER_A),
                        htons(DHCPV6_OPT_DNS_SERVERS),
                        htons(DHCPV6_OPT_DNS_DOMAIN),
-                       htons(DHCPV6_OPT_UNICAST),
                        htons(DHCPV6_OPT_SNTP_SERVERS),
                        htons(DHCPV6_OPT_NTP_SERVER),
                        htons(DHCPV6_OPT_AFTR_NAME),
@@ -199,6 +197,13 @@ int init_dhcpv6(const char *ifname, unsigned int options, int sol_timeout)
                };
                odhcp6c_add_state(STATE_ORO, oro, sizeof(oro));
        }
+       // Required oro
+       uint16_t req_oro[] = {
+               htons(DHCPV6_OPT_INF_MAX_RT),
+               htons(DHCPV6_OPT_SOL_MAX_RT),
+               htons(DHCPV6_OPT_INFO_REFRESH),
+       };
+       odhcp6c_add_state(STATE_ORO, req_oro, sizeof(req_oro));
 
        // Configure IPv6-options
        int val = 1;
@@ -232,7 +237,6 @@ failure:
 enum {
        IOV_HDR=0,
        IOV_ORO,
-       IOV_ORO_REFRESH,
        IOV_CL_ID,
        IOV_SRV_ID,
        IOV_OPTS,
@@ -394,9 +398,6 @@ static void dhcpv6_send(enum dhcpv6_msg type, uint8_t trid[3], uint32_t ecs)
                }
        }
 
-       if (ia_pd_entries > 0)
-               request_prefix = 1;
-
        // Build IA_NAs
        size_t ia_na_entries, ia_na_len = 0;
        void *ia_na = NULL;
@@ -434,16 +435,39 @@ static void dhcpv6_send(enum dhcpv6_msg type, uint8_t trid[3], uint32_t ecs)
                uint16_t length;
        } reconf_accept = {htons(DHCPV6_OPT_RECONF_ACCEPT), 0};
 
-       // Request Information Refresh
-       uint16_t oro_refresh = htons(DHCPV6_OPT_INFO_REFRESH);
-
        // Option list
        size_t opts_len;
        void *opts = odhcp6c_get_state(STATE_OPTS, &opts_len);
 
+       // Option Request List
+       size_t oro_entries, oro_len = 0;
+       uint16_t *oro, *s_oro = odhcp6c_get_state(STATE_ORO, &oro_entries);
+
+       oro_entries /= sizeof(*s_oro);
+       oro = alloca(oro_entries * sizeof(*oro));
+
+       for (size_t i = 0; i < oro_entries; i++) {
+               struct odhcp6c_opt *opt = odhcp6c_find_opt(htons(s_oro[i]));
+
+               if (opt) {
+                       if (!(opt->flags & OPT_ORO))
+                               continue;
+
+                       if ((opt->flags & OPT_ORO_SOLICIT) && type != DHCPV6_MSG_SOLICIT)
+                               continue;
+
+                       if ((opt->flags & OPT_ORO_STATELESS) && type != DHCPV6_MSG_INFO_REQ)
+                               continue;
+
+                       if ((opt->flags & OPT_ORO_STATEFUL) && type == DHCPV6_MSG_INFO_REQ)
+                               continue;
+               }
+
+               oro[oro_len++] = s_oro[i];
+       }
+       oro_len *= sizeof(*oro);
+
        // Prepare Header
-       size_t oro_len;
-       void *oro = odhcp6c_get_state(STATE_ORO, &oro_len);
        struct {
                uint8_t type;
                uint8_t trid[3];
@@ -462,7 +486,6 @@ static void dhcpv6_send(enum dhcpv6_msg type, uint8_t trid[3], uint32_t ecs)
        struct iovec iov[IOV_TOTAL] = {
                [IOV_HDR] = {&hdr, sizeof(hdr)},
                [IOV_ORO] = {oro, oro_len},
-               [IOV_ORO_REFRESH] = {&oro_refresh, 0},
                [IOV_CL_ID] = {cl_id, cl_id_len},
                [IOV_SRV_ID] = {srv_id, srv_id_len},
                [IOV_OPTS] = { opts, opts_len },
@@ -474,12 +497,8 @@ static void dhcpv6_send(enum dhcpv6_msg type, uint8_t trid[3], uint32_t ecs)
        };
 
        size_t cnt = IOV_TOTAL;
-       if (type == DHCPV6_MSG_INFO_REQ) {
-               cnt = 9;
-               iov[IOV_ORO_REFRESH].iov_len = sizeof(oro_refresh);
-               hdr.oro_len = htons(oro_len + sizeof(oro_refresh));
-       } else if (!request_prefix)
-               cnt = 13;
+       if (type == DHCPV6_MSG_INFO_REQ)
+               cnt = IOV_HDR_IA_NA;
 
        // Disable IAs if not used
        if (type != DHCPV6_MSG_SOLICIT && ia_na_len == 0)
@@ -856,7 +875,9 @@ static int dhcpv6_handle_advert(enum dhcpv6_msg orig, const int rc,
                                cand.preference >= 0) {
                        cand.preference = pref = odata[0];
                } else if (otype == DHCPV6_OPT_UNICAST && olen == sizeof(cand.server_addr)) {
-                       cand.server_addr = *(struct in6_addr *)odata;
+                       if (!(client_options & DHCPV6_IGNORE_OPT_UNICAST))
+                               cand.server_addr = *(struct in6_addr *)odata;
+
                } else if (otype == DHCPV6_OPT_RECONF_ACCEPT) {
                        cand.wants_reconfigure = true;
                } else if (otype == DHCPV6_OPT_SOL_MAX_RT && olen == 4) {
@@ -871,7 +892,7 @@ static int dhcpv6_handle_advert(enum dhcpv6_msg orig, const int rc,
                                        inf_max_rt <= DHCPV6_INF_MAX_RT_MAX)
                                cand.inf_max_rt = inf_max_rt;
 
-               } else if (otype == DHCPV6_OPT_IA_PD && request_prefix &&
+               } else if (otype == DHCPV6_OPT_IA_PD &&
                                        olen >= -4 + sizeof(struct dhcpv6_ia_hdr)) {
                        struct dhcpv6_ia_hdr *h = (struct dhcpv6_ia_hdr*)&odata[-4];
                        uint8_t *oend = odata + olen, *d;
@@ -1048,8 +1069,11 @@ static int dhcpv6_handle_reply(enum dhcpv6_msg orig, _unused const int rc,
                                        continue;
 
                                updated_IAs += dhcpv6_parse_ia(ia_hdr, odata + olen);
-                       } else if (otype == DHCPV6_OPT_UNICAST && olen == sizeof(server_addr))
-                               server_addr = *(struct in6_addr *)odata;
+                       } else if (otype == DHCPV6_OPT_UNICAST && olen == sizeof(server_addr)) {
+                               if (!(client_options & DHCPV6_IGNORE_OPT_UNICAST))
+                                       server_addr = *(struct in6_addr *)odata;
+
+                       }
                        else if (otype == DHCPV6_OPT_STATUS && olen >= 2) {
                                uint8_t *mdata = (olen > 2) ? &odata[2] : NULL;
                                uint16_t mlen = (olen > 2) ? olen - 2 : 0;
@@ -1515,7 +1539,7 @@ int dhcpv6_promote_server_cand(void)
        if (cand->ia_pd_len) {
                odhcp6c_add_state(STATE_IA_PD, cand->ia_pd, cand->ia_pd_len);
                free(cand->ia_pd);
-               if (request_prefix)
+               if (pd_mode != IA_MODE_NONE)
                        ret = DHCPV6_STATEFUL;
        }