if (size_multiply_overflow(sizeof(struct in_addr), n_addr))
return -ENOBUFS;
+ if (code == SD_DHCP_OPTION_SIP_SERVER) {
+ if (dhcp_message_has_option(message, SD_DHCP_OPTION_SIP_SERVER))
+ return -EEXIST;
+
+ size_t len = size_add(1, sizeof(struct in_addr) * n_addr);
+ if (len == SIZE_MAX)
+ return -ENOBUFS;
+
+ _cleanup_free_ uint8_t *buf = new(uint8_t, len);
+ if (!buf)
+ return -ENOMEM;
+
+ buf[0] = 1; /* 'enc' field, 0: domains, 1: addresses */
+ memcpy(buf + 1, addr, sizeof(struct in_addr) * n_addr);
+
+ return dhcp_message_append_option(message, code, len, buf);
+ }
+
return dhcp_message_append_option(message, code, sizeof(struct in_addr) * n_addr, addr);
}
assert(message);
assert(ret_n_addr || !ret_addr);
- _cleanup_(iovec_done) struct iovec iov = {};
- r = dhcp_message_get_option_alloc(message, code, &iov);
+ _cleanup_(iovec_done) struct iovec iov_free = {};
+ r = dhcp_message_get_option_alloc(message, code, &iov_free);
if (r < 0)
return r;
+ struct iovec iov = iov_free;
+ if (code == SD_DHCP_OPTION_SIP_SERVER) {
+ if (!iovec_is_set(&iov))
+ return -EBADMSG;
+
+ if (*(uint8_t*) iov.iov_base != 1) /* 'enc' field, 0: domains, 1: addresses */
+ return -ENODATA;
+
+ iovec_inc(&iov, 1);
+ }
+
if (iov.iov_len % sizeof(struct in_addr) != 0)
return -EBADMSG;
if (n == 0)
return -ENODATA;
- if (ret_addr)
- *ret_addr = (struct in_addr*) TAKE_PTR(iov.iov_base);
+ if (ret_addr) {
+ if (code == SD_DHCP_OPTION_SIP_SERVER) {
+ struct in_addr *addr = newdup(struct in_addr, iov.iov_base, n);
+ if (!addr)
+ return -ENOMEM;
+ *ret_addr = addr;
+ } else {
+ *ret_addr = iov.iov_base;
+ TAKE_STRUCT(iov_free);
+ }
+ }
if (ret_n_addr)
*ret_n_addr = n;
return 0;
assert(message);
- /* This is mostly for SD_DHCP_OPTION_DOMAIN_SEARCH. */
+ /* This is mostly for SD_DHCP_OPTION_DOMAIN_SEARCH and SD_DHCP_OPTION_SIP_SERVER. */
_cleanup_(iovec_done) struct iovec iov = {};
r = dhcp_message_get_option_alloc(message, code, &iov);
const uint8_t *buf = iov.iov_base;
size_t len = iov.iov_len;
+ if (code == SD_DHCP_OPTION_SIP_SERVER) {
+ if (len == 0)
+ return -EBADMSG;
+
+ if (buf[0] != 0) /* 'enc' field, 0: domains, 1: addresses */
+ return -ENODATA;
+
+ len--;
+ buf++;
+ }
+
_cleanup_strv_free_ char **names = NULL;
size_t n_names = 0;
static void verify_addresses(
sd_dhcp_message *m,
- size_t n_ntp, const struct in_addr *ntp) {
+ size_t n_ntp, const struct in_addr *ntp,
+ size_t n_sip, const struct in_addr *sip) {
struct in_addr a;
ASSERT_OK(dhcp_message_get_option_be32(m, SD_DHCP_OPTION_NTP_SERVER, &a.s_addr));
ASSERT_OK(dhcp_message_get_option_addresses(m, SD_DHCP_OPTION_NTP_SERVER, &n, &addrs));
ASSERT_EQ(n, n_ntp);
ASSERT_EQ(memcmp(addrs, ntp, sizeof(struct in_addr) * n), 0);
+
+ ASSERT_ERROR(dhcp_message_get_option_be32(m, SD_DHCP_OPTION_SIP_SERVER, NULL), ENODATA);
+ ASSERT_ERROR(dhcp_message_get_option_address(m, SD_DHCP_OPTION_SIP_SERVER, NULL), ENODATA);
+
+ addrs = mfree(addrs);
+ ASSERT_OK(dhcp_message_get_option_addresses(m, SD_DHCP_OPTION_SIP_SERVER, &n, &addrs));
+ ASSERT_EQ(n, n_sip);
+ ASSERT_EQ(memcmp(addrs, sip, sizeof(struct in_addr) * n), 0);
}
static void verify_string(sd_dhcp_message *m, const char *expected) {
{ .s_addr = htobe32(0xC0000204) },
};
+ /* 192.0.2.17 - 20 */
+ struct in_addr sip[4] = {
+ { .s_addr = htobe32(0xC0000211) },
+ { .s_addr = htobe32(0xC0000212) },
+ { .s_addr = htobe32(0xC0000213) },
+ { .s_addr = htobe32(0xC0000214) },
+ };
+
sd_dhcp_client_id id = {
.raw = { 1, 3, 3, 3, 3, 3, 3, },
.size = 7,
/* multiple addresses */
ASSERT_OK(dhcp_message_append_option_address(m, SD_DHCP_OPTION_NTP_SERVER, &ntp[0]));
ASSERT_OK(dhcp_message_append_option_addresses(m, SD_DHCP_OPTION_NTP_SERVER, ELEMENTSOF(ntp) - 1, ntp + 1));
- verify_addresses(m, ELEMENTSOF(ntp), ntp);
+ ASSERT_OK(dhcp_message_append_option_addresses(m, SD_DHCP_OPTION_SIP_SERVER, ELEMENTSOF(sip), sip));
+ ASSERT_ERROR(dhcp_message_append_option_addresses(m, SD_DHCP_OPTION_SIP_SERVER, ELEMENTSOF(sip), sip), EEXIST);
+ ASSERT_OK(dhcp_message_append_option_addresses(m, SD_DHCP_OPTION_SIP_SERVER, 0, NULL));
+ verify_addresses(m, ELEMENTSOF(ntp), ntp, ELEMENTSOF(sip), sip);
/* string */
ASSERT_ERROR(dhcp_message_get_option_string(m, SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER, NULL), ENODATA);
verify_u16(m2, 512);
verify_sec(m2, lease_time);
verify_address(m2, &addr);
- verify_addresses(m2, ELEMENTSOF(ntp), ntp);
+ verify_addresses(m2, ELEMENTSOF(ntp), ntp, ELEMENTSOF(sip), sip);
verify_string(m2, vendor_class);
verify_client_id(m2, &id);
verify_prl(m2, prl);
ASSERT_OK(dhcp_message_append_option(m, SD_DHCP_OPTION_DOMAIN_SEARCH, len - len / 2, data + len / 2));
ASSERT_OK(dhcp_message_get_option_domains(m, SD_DHCP_OPTION_DOMAIN_SEARCH, &strv));
ASSERT_TRUE(strv_equal(strv, expected));
+
+ strv = strv_free(strv);
+
+ _cleanup_free_ uint8_t *sip = new(uint8_t, len + 1);
+ sip[0] = 0;
+ memcpy(sip + 1, data, len);
+
+ ASSERT_OK(dhcp_message_append_option(m, SD_DHCP_OPTION_SIP_SERVER, len + 1, sip));
+ ASSERT_OK(dhcp_message_get_option_domains(m, SD_DHCP_OPTION_SIP_SERVER, &strv));
+ ASSERT_TRUE(strv_equal(strv, expected));
+
+ dhcp_message_remove_option(m, SD_DHCP_OPTION_SIP_SERVER);
+ strv = strv_free(strv);
+
+ ASSERT_OK(dhcp_message_append_option(m, SD_DHCP_OPTION_SIP_SERVER, (len + 1) / 2, sip));
+ ASSERT_OK(dhcp_message_append_option(m, SD_DHCP_OPTION_SIP_SERVER, len + 1 - (len + 1) / 2, sip + (len + 1) / 2));
+ ASSERT_OK(dhcp_message_get_option_domains(m, SD_DHCP_OPTION_SIP_SERVER, &strv));
+ ASSERT_TRUE(strv_equal(strv, expected));
}
static void test_domains_fail(size_t len, const uint8_t *data) {