return 0;
}
-int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia) {
+int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_status_code) {
+ uint32_t lt_t1, lt_t2, lt_valid = 0, lt_min = UINT32_MAX;
uint16_t iatype, optlen;
- size_t i, len;
+ size_t iaaddr_offset;
int r = 0, status;
+ size_t i, len;
uint16_t opt;
- size_t iaaddr_offset;
- uint32_t lt_t1, lt_t2, lt_valid = 0, lt_min = UINT32_MAX;
assert_return(ia, -EINVAL);
assert_return(!ia->addresses, -EINVAL);
status = dhcp6_option_parse_status(option, optlen + offsetof(DHCP6Option, data));
if (status < 0)
return status;
+
if (status > 0) {
+ if (ret_status_code)
+ *ret_status_code = status;
+
log_dhcp6_client(client, "IA status %s",
dhcp6_message_status_to_string(status));
- return -EINVAL;
+ return 0;
}
break;
break;
}
- return 0;
+ if (ret_status_code)
+ *ret_status_code = 0;
+
+ return 1;
}
int dhcp6_option_parse_ip6addrs(uint8_t *optval, uint16_t optlen,
size_t len,
sd_dhcp6_lease *lease) {
+ uint16_t ia_na_status = 0, ia_pd_status = 0;
uint32_t lt_t1 = ~0, lt_t2 = ~0;
+ usec_t irt = IRT_DEFAULT;
bool clientid = false;
size_t pos = 0;
- usec_t irt = IRT_DEFAULT;
int r;
assert(client);
DHCP6Option *option = (DHCP6Option *) &message->options[pos];
uint16_t optcode, optlen;
be32_t iaid_lease;
+ int status;
uint8_t *optval;
- int status;
if (len < pos + offsetof(DHCP6Option, data))
return -ENOBUFS;
break;
}
- r = dhcp6_option_parse_ia(option, &lease->ia);
+ r = dhcp6_option_parse_ia(option, &lease->ia, &ia_na_status);
if (r < 0 && r != -ENOMSG)
return r;
+ if (ia_na_status == DHCP6_STATUS_NO_ADDRS_AVAIL) {
+ pos += offsetof(DHCP6Option, data) + optlen;
+ continue;
+ }
+
r = dhcp6_lease_get_iaid(lease, &iaid_lease);
if (r < 0)
return r;
break;
}
- r = dhcp6_option_parse_ia(option, &lease->pd);
+ r = dhcp6_option_parse_ia(option, &lease->pd, &ia_pd_status);
if (r < 0 && r != -ENOMSG)
return r;
+ if (ia_pd_status == DHCP6_STATUS_NO_PREFIX_AVAIL) {
+ pos += offsetof(DHCP6Option, data) + optlen;
+ continue;
+ }
+
r = dhcp6_lease_get_pd_iaid(lease, &iaid_lease);
if (r < 0)
return r;
pos += offsetof(DHCP6Option, data) + optlen;
}
+ if (ia_na_status > 0 && ia_pd_status > 0) {
+ log_dhcp6_client(client, "No IA_PD prefix or IA_NA address received. Ignoring.");
+ return -EINVAL;
+ }
+
if (!clientid) {
log_dhcp6_client(client, "%s has incomplete options",
dhcp6_message_type_to_string(message->type));
option = (DHCP6Option *)option1;
assert_se(sizeof(option1) == sizeof(DHCP6Option) + be16toh(option->len));
- r = dhcp6_option_parse_ia(option, &ia);
- assert_se(r == -EINVAL);
+ r = dhcp6_option_parse_ia(option, &ia, NULL);
+ assert_se(r == 0);
assert_se(ia.addresses == NULL);
option->len = htobe16(17);
- r = dhcp6_option_parse_ia(option, &ia);
+ r = dhcp6_option_parse_ia(option, &ia, NULL);
assert_se(r == -ENOBUFS);
assert_se(ia.addresses == NULL);
option->len = htobe16(sizeof(DHCP6Option));
- r = dhcp6_option_parse_ia(option, &ia);
+ r = dhcp6_option_parse_ia(option, &ia, NULL);
assert_se(r == -ENOBUFS);
assert_se(ia.addresses == NULL);
option = (DHCP6Option *)option2;
assert_se(sizeof(option2) == sizeof(DHCP6Option) + be16toh(option->len));
- r = dhcp6_option_parse_ia(option, &ia);
+ r = dhcp6_option_parse_ia(option, &ia, NULL);
assert_se(r >= 0);
assert_se(ia.addresses == NULL);
option = (DHCP6Option *)option3;
assert_se(sizeof(option3) == sizeof(DHCP6Option) + be16toh(option->len));
- r = dhcp6_option_parse_ia(option, &ia);
+ r = dhcp6_option_parse_ia(option, &ia, NULL);
assert_se(r >= 0);
assert_se(ia.addresses != NULL);
dhcp6_lease_free_ia(&ia);
option = (DHCP6Option *)option4;
assert_se(sizeof(option4) == sizeof(DHCP6Option) + be16toh(option->len));
- r = dhcp6_option_parse_ia(option, &pd);
- assert_se(r == 0);
+ r = dhcp6_option_parse_ia(option, &pd, NULL);
+ assert_se(r >= 0);
assert_se(pd.addresses != NULL);
assert_se(memcmp(&pd.ia_pd.id, &option4[4], 4) == 0);
assert_se(memcmp(&pd.ia_pd.lifetime_t1, &option4[8], 4) == 0);
option = (DHCP6Option *)option5;
assert_se(sizeof(option5) == sizeof(DHCP6Option) + be16toh(option->len));
- r = dhcp6_option_parse_ia(option, &pd);
- assert_se(r == 0);
+ r = dhcp6_option_parse_ia(option, &pd, NULL);
+ assert_se(r >= 0);
assert_se(pd.addresses != NULL);
dhcp6_lease_free_ia(&pd);
_cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
DHCP6Message *advertise = (DHCP6Message *)msg_advertise;
size_t len = sizeof(msg_advertise) - sizeof(DHCP6Message), pos = 0;
- be32_t val;
- uint8_t preference = 255;
- struct in6_addr addr;
uint32_t lt_pref, lt_valid;
- int r;
- uint8_t *opt;
bool opt_clientid = false;
const struct in6_addr *addrs;
+ uint8_t preference = 255;
+ struct in6_addr addr;
char **domains;
+ uint8_t *opt;
+ int r;
+ be32_t val;
log_debug("/* %s */", __func__);
val = htobe32(120);
assert_se(!memcmp(optval + 8, &val, sizeof(val)));
- assert_se(dhcp6_option_parse_ia(option, &lease->ia) >= 0);
+ assert_se(dhcp6_option_parse_ia(option, &lease->ia, NULL) >= 0);
break;
static int test_client_verify_request(DHCP6Message *request, size_t len) {
_cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL;
- size_t pos = 0;
bool found_clientid = false, found_iana = false, found_serverid = false,
found_elapsed_time = false, found_fqdn = false;
+ uint32_t lt_pref, lt_valid;
struct in6_addr addr;
+ size_t pos = 0;
be32_t val;
- uint32_t lt_pref, lt_valid;
log_debug("/* %s */", __func__);
val = htobe32(120);
assert_se(!memcmp(optval + 8, &val, sizeof(val)));
- assert_se(!dhcp6_option_parse_ia(option, &lease->ia));
+ assert_se(dhcp6_option_parse_ia(option, &lease->ia, NULL) >= 0);
break;