return dhcp_message_append_option_be32(message, code, addr->s_addr);
}
+int dhcp_message_append_option_addresses(sd_dhcp_message *message, uint8_t code, size_t n_addr, const struct in_addr *addr) {
+ assert(message);
+ assert(n_addr == 0 || addr);
+
+ if (n_addr == 0)
+ return 0;
+
+ if (size_multiply_overflow(sizeof(struct in_addr), n_addr))
+ return -ENOBUFS;
+
+ return dhcp_message_append_option(message, code, sizeof(struct in_addr) * n_addr, addr);
+}
+
int dhcp_message_get_option(sd_dhcp_message *message, uint8_t code, size_t length, void *ret) {
int r;
return dhcp_message_get_option_be32(message, code, ret ? &ret->s_addr : NULL);
}
+int dhcp_message_get_option_addresses(sd_dhcp_message *message, uint8_t code, size_t *ret_n_addr, struct in_addr **ret_addr) {
+ int r;
+
+ assert(message);
+ assert(ret_n_addr || !ret_addr);
+
+ _cleanup_(iovec_done) struct iovec iov = {};
+ r = dhcp_message_get_option_alloc(message, code, &iov);
+ if (r < 0)
+ return r;
+
+ if (iov.iov_len % sizeof(struct in_addr) != 0)
+ return -EBADMSG;
+
+ size_t n = iov.iov_len / sizeof(struct in_addr);
+ if (n == 0)
+ return -ENODATA;
+
+ if (ret_addr)
+ *ret_addr = (struct in_addr*) TAKE_PTR(iov.iov_base);
+ if (ret_n_addr)
+ *ret_n_addr = n;
+ return 0;
+}
+
static int dhcp_message_verify_header(
const struct iovec *iov,
uint8_t op,
int dhcp_message_append_option_be32(sd_dhcp_message *message, uint8_t code, be32_t data);
int dhcp_message_append_option_sec(sd_dhcp_message *message, uint8_t code, usec_t usec);
int dhcp_message_append_option_address(sd_dhcp_message *message, uint8_t code, const struct in_addr *addr);
+int dhcp_message_append_option_addresses(sd_dhcp_message *message, uint8_t code, size_t n_addr, const struct in_addr *addr);
int dhcp_message_get_option(sd_dhcp_message *message, uint8_t code, size_t length, void *ret);
int dhcp_message_get_option_alloc(sd_dhcp_message *message, uint8_t code, struct iovec *ret);
int dhcp_message_get_option_be32(sd_dhcp_message *message, uint8_t code, be32_t *ret);
int dhcp_message_get_option_sec(sd_dhcp_message *message, uint8_t code, bool max_as_infinity, usec_t *ret);
int dhcp_message_get_option_address(sd_dhcp_message *message, uint8_t code, struct in_addr *ret);
+int dhcp_message_get_option_addresses(sd_dhcp_message *message, uint8_t code, size_t *ret_n_addr, struct in_addr **ret_addr);
int dhcp_message_parse(
const struct iovec *iov,
ASSERT_EQ(a.s_addr, expected->s_addr);
}
+static void verify_addresses(
+ sd_dhcp_message *m,
+ size_t n_ntp, const struct in_addr *ntp) {
+
+ struct in_addr a;
+ ASSERT_OK(dhcp_message_get_option_be32(m, SD_DHCP_OPTION_NTP_SERVER, &a.s_addr));
+ ASSERT_EQ(a.s_addr, ntp->s_addr);
+ ASSERT_OK(dhcp_message_get_option_address(m, SD_DHCP_OPTION_NTP_SERVER, &a));
+ ASSERT_EQ(a.s_addr, ntp->s_addr);
+
+ size_t n;
+ _cleanup_free_ struct in_addr *addrs = NULL;
+ 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);
+}
+
TEST(dhcp_message) {
_cleanup_(sd_dhcp_message_unrefp) sd_dhcp_message *m = NULL;
/* 192.0.2.42 */
struct in_addr addr = { .s_addr = htobe32(0xC000022a) };
+ /* 192.0.2.1 - 4 */
+ struct in_addr ntp[4] = {
+ { .s_addr = htobe32(0xC0000201) },
+ { .s_addr = htobe32(0xC0000202) },
+ { .s_addr = htobe32(0xC0000203) },
+ { .s_addr = htobe32(0xC0000204) },
+ };
+
ASSERT_OK(dhcp_message_init_header(
m,
BOOTREQUEST,
ASSERT_OK(dhcp_message_append_option_address(m, SD_DHCP_OPTION_REQUESTED_IP_ADDRESS, &addr));
verify_address(m, &addr);
+ /* 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);
+
/* build and parse */
_cleanup_(iovw_done_free) struct iovec_wrapper iovw = {};
ASSERT_OK(dhcp_message_build(m, &iovw));
verify_u16(m2, 512);
verify_sec(m2, lease_time);
verify_address(m2, &addr);
+ verify_addresses(m2, ELEMENTSOF(ntp), ntp);
/* build again, and verify the packet */
_cleanup_(iovw_done_free) struct iovec_wrapper iovw2 = {};