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
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),
};
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;
enum {
IOV_HDR=0,
IOV_ORO,
- IOV_ORO_REFRESH,
IOV_CL_ID,
IOV_SRV_ID,
IOV_OPTS,
}
}
- if (ia_pd_entries > 0)
- request_prefix = 1;
-
// Build IA_NAs
size_t ia_na_entries, ia_na_len = 0;
void *ia_na = NULL;
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];
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 },
};
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)
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) {
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;
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;
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;
}