};
typedef int (*test_callback_recv_t)(size_t size, DHCPMessage *dhcp);
+struct bootp_addr_data {
+ uint8_t *offer_buf;
+ size_t offer_len;
+ int netmask_offset;
+ int ip_offset;
+};
+struct bootp_addr_data *bootp_test_context;
+
static bool verbose = true;
static int test_fd[2];
static test_callback_recv_t callback_recv;
xid = 0;
}
+static uint8_t test_addr_bootp_reply[] = {
+ 0x45, 0x00, 0x01, 0x48, 0x00, 0x00, 0x40, 0x00,
+ 0xff, 0x11, 0x70, 0xa3, 0x0a, 0x00, 0x00, 0x02,
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x43, 0x00, 0x44,
+ 0x01, 0x2c, 0x2b, 0x91, 0x02, 0x01, 0x06, 0x00,
+ 0x69, 0xd3, 0x79, 0x11, 0x17, 0x00, 0x80, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x0a, 0x46, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x50, 0x2d, 0xf4, 0x1f, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x63, 0x82, 0x53, 0x63, 0x01, 0x04, 0xff, 0x00,
+ 0x00, 0x00, 0x36, 0x04, 0x0a, 0x00, 0x00, 0x02,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+};
+
+static uint8_t test_addr_bootp_reply_bootpd[] = {
+ 0x45, 0x00, 0x01, 0x48, 0xbe, 0xad, 0x40, 0x00,
+ 0x40, 0x11, 0x73, 0x43, 0xc0, 0xa8, 0x43, 0x31,
+ 0xc0, 0xa8, 0x43, 0x32, 0x00, 0x43, 0x00, 0x44,
+ 0x01, 0x34, 0x08, 0xfa, 0x02, 0x01, 0x06, 0x00,
+ 0x82, 0x57, 0xda, 0xf1, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x43, 0x32,
+ 0xc0, 0xa8, 0x43, 0x31, 0x00, 0x00, 0x00, 0x00,
+ 0xc2, 0x3e, 0xa5, 0x53, 0x57, 0x72, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x64, 0x65, 0x62, 0x69, 0x61, 0x6e, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x63, 0x82, 0x53, 0x63, 0x01, 0x04, 0xff, 0xff,
+ 0xff, 0xf0, 0x03, 0x04, 0xc0, 0xa8, 0x43, 0x31,
+ 0x06, 0x04, 0x0a, 0x00, 0x01, 0x01, 0x0c, 0x15,
+ 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2d, 0x64,
+ 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x2d, 0x74,
+ 0x72, 0x69, 0x78, 0x69, 0x65, 0xff, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static struct bootp_addr_data bootp_addr_data[] = {
+ {
+ .offer_buf = test_addr_bootp_reply,
+ .offer_len = sizeof(test_addr_bootp_reply),
+ .netmask_offset = 270,
+ .ip_offset = 44,
+ },
+ {
+ .offer_buf = test_addr_bootp_reply_bootpd,
+ .offer_len = sizeof(test_addr_bootp_reply_bootpd),
+ .netmask_offset = 270,
+ .ip_offset = 44,
+ },
+};
+
+static int test_bootp_acquired(sd_dhcp_client *client, int event,
+ void *userdata) {
+ sd_dhcp_lease *lease = NULL;
+ sd_event *e = userdata;
+ struct in_addr addr;
+
+ ASSERT_NOT_NULL(client);
+ assert_se(IN_SET(event, SD_DHCP_CLIENT_EVENT_IP_ACQUIRE, SD_DHCP_CLIENT_EVENT_SELECTING));
+
+ ASSERT_OK(sd_dhcp_client_get_lease(client, &lease));
+ ASSERT_NOT_NULL(lease);
+
+ ASSERT_OK(sd_dhcp_lease_get_address(lease, &addr));
+ ASSERT_EQ(memcmp(&addr.s_addr, &bootp_test_context->offer_buf[bootp_test_context->ip_offset],
+ sizeof(addr.s_addr)), 0);
+
+ ASSERT_OK(sd_dhcp_lease_get_netmask(lease, &addr));
+ ASSERT_EQ(memcmp(&addr.s_addr, &bootp_test_context->offer_buf[bootp_test_context->netmask_offset],
+ sizeof(addr.s_addr)), 0);
+
+ if (verbose)
+ log_info(" BOOTP address acquired");
+
+ sd_event_exit(e, 0);
+
+ return 0;
+}
+
+static int test_bootp_recv_request(size_t size, DHCPMessage *request) {
+ uint16_t udp_check = 0;
+ size_t res;
+
+ xid = request->xid;
+
+ if (verbose)
+ log_info(" recv BOOTP Request 0x%08x", be32toh(xid));
+
+ callback_recv = NULL;
+
+ memcpy(&bootp_test_context->offer_buf[26], &udp_check, sizeof(udp_check));
+ memcpy(&bootp_test_context->offer_buf[32], &xid, sizeof(xid));
+ memcpy(&bootp_test_context->offer_buf[56], hw_addr.bytes, hw_addr.length);
+
+ res = write(test_fd[1], bootp_test_context->offer_buf,
+ bootp_test_context->offer_len);
+ ASSERT_EQ(res, bootp_test_context->offer_len);
+
+ if (verbose)
+ log_info(" sent BOOTP Reply");
+
+ return 0;
+};
+
+static void test_acquire_bootp(sd_event *e) {
+ sd_dhcp_client *client = NULL;
+ int res;
+
+ if (verbose)
+ log_info("* %s", __func__);
+
+ ASSERT_OK(sd_dhcp_client_new(&client, false));
+ ASSERT_NOT_NULL(client);
+
+ ASSERT_OK(sd_dhcp_client_attach_event(client, e, 0));
+
+ ASSERT_OK(sd_dhcp_client_set_bootp(client, true));
+
+ ASSERT_OK(sd_dhcp_client_set_ifindex(client, 42));
+ ASSERT_OK(sd_dhcp_client_set_mac(client, hw_addr.bytes, bcast_addr.bytes, hw_addr.length, ARPHRD_ETHER));
+
+ ASSERT_OK(sd_dhcp_client_set_callback(client, test_bootp_acquired, e));
+
+ callback_recv = test_bootp_recv_request;
+
+ ASSERT_OK(sd_event_add_time_relative(e, NULL, CLOCK_BOOTTIME,
+ 30 * USEC_PER_SEC, 0,
+ NULL, INT_TO_PTR(-ETIMEDOUT)));
+
+ res = sd_dhcp_client_start(client);
+ assert_se(IN_SET(res, 0, -EINPROGRESS));
+
+ ASSERT_OK(sd_event_loop(e));
+
+ ASSERT_OK(sd_dhcp_client_set_callback(client, NULL, NULL));
+ ASSERT_OK(sd_dhcp_client_stop(client));
+ client = sd_dhcp_client_unref(client);
+ ASSERT_NULL(client);
+
+ test_fd[1] = safe_close(test_fd[1]);
+
+ callback_recv = NULL;
+ xid = 0;
+}
+
int main(int argc, char *argv[]) {
_cleanup_(sd_event_unrefp) sd_event *e;
test_discover_message(e);
test_addr_acq(e);
+ FOREACH_ELEMENT(i, bootp_addr_data) {
+ sd_event_unref(e);
+ ASSERT_OK(sd_event_new(&e));
+ bootp_test_context = i;
+ test_acquire_bootp(e);
+ }
+
#if HAVE_VALGRIND_VALGRIND_H
/* Make sure the async_close thread has finished.
* valgrind would report some of the phread_* structures