test-dhcp-client.c revision 5bac5235934fabe5a3e6a9d47f4812f81034c427
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack/***
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack This file is part of systemd.
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack Copyright (C) 2013 Intel Corporation. All rights reserved.
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack systemd is free software; you can redistribute it and/or modify it
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack under the terms of the GNU Lesser General Public License as published by
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack the Free Software Foundation; either version 2.1 of the License, or
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack (at your option) any later version.
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack systemd is distributed in the hope that it will be useful, but
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack WITHOUT ANY WARRANTY; without even the implied warranty of
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack Lesser General Public License for more details.
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack You should have received a copy of the GNU Lesser General Public License
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack along with systemd; If not, see <http://www.gnu.org/licenses/>.
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack***/
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack#include <stdlib.h>
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack#include <assert.h>
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack#include <errno.h>
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack#include <stdio.h>
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack#include <sys/types.h>
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack#include <sys/socket.h>
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack#include <unistd.h>
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack#include "util.h"
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack#include "socket-util.h"
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack#include "sd-event.h"
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack#include "event-util.h"
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack#include "dhcp-identifier.h"
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack#include "dhcp-protocol.h"
96f2f3b1b5f44eb59d23d2abeac12b33a18e1e21Philippe De Swert#include "dhcp-internal.h"
96f2f3b1b5f44eb59d23d2abeac12b33a18e1e21Philippe De Swert#include "sd-dhcp-client.h"
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mackstatic uint8_t mac_addr[] = {'A', 'B', 'C', '1', '2', '3'};
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Macktypedef int (*test_callback_recv_t)(size_t size, DHCPMessage *dhcp);
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mackstatic bool verbose = true;
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mackstatic int test_fd[2];
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mackstatic test_callback_recv_t callback_recv;
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mackstatic be32_t xid;
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mackstatic sd_event_source *test_hangcheck;
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mackstatic int test_dhcp_hangcheck(sd_event_source *s, uint64_t usec,
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack void *userdata)
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack{
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack assert_not_reached("Test case should have completed in 2 seconds");
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack return 0;
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack}
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidtstatic void test_request_basic(sd_event *e)
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack{
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack int r;
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack sd_dhcp_client *client;
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack if (verbose)
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack printf("* %s\n", __FUNCTION__);
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack r = sd_dhcp_client_new(&client);
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack assert_se(r >= 0);
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack assert_se(client);
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack r = sd_dhcp_client_attach_event(client, e, 0);
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack assert_se(r >= 0);
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack assert_se(sd_dhcp_client_set_request_option(NULL, 0) == -EINVAL);
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack assert_se(sd_dhcp_client_set_request_address(NULL, NULL) == -EINVAL);
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack assert_se(sd_dhcp_client_set_index(NULL, 0) == -EINVAL);
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack assert_se(sd_dhcp_client_set_index(client, 15) == 0);
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack assert_se(sd_dhcp_client_set_index(client, -42) == -EINVAL);
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack assert_se(sd_dhcp_client_set_index(client, -1) == -EINVAL);
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack assert_se(sd_dhcp_client_set_index(client, 0) == -EINVAL);
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack assert_se(sd_dhcp_client_set_index(client, 1) == 0);
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack assert_se(sd_dhcp_client_set_request_option(client,
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack DHCP_OPTION_SUBNET_MASK) == -EEXIST);
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack assert_se(sd_dhcp_client_set_request_option(client,
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack DHCP_OPTION_ROUTER) == -EEXIST);
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack assert_se(sd_dhcp_client_set_request_option(client,
bb7dd0b04a6e89674100476eed0bbd05c6a4cbd8Daniel Mack DHCP_OPTION_HOST_NAME) == -EEXIST);
assert_se(sd_dhcp_client_set_request_option(client,
DHCP_OPTION_DOMAIN_NAME) == -EEXIST);
assert_se(sd_dhcp_client_set_request_option(client,
DHCP_OPTION_DOMAIN_NAME_SERVER)
== -EEXIST);
assert_se(sd_dhcp_client_set_request_option(client,
DHCP_OPTION_NTP_SERVER) == -EEXIST);
assert_se(sd_dhcp_client_set_request_option(client,
DHCP_OPTION_PAD) == -EINVAL);
assert_se(sd_dhcp_client_set_request_option(client,
DHCP_OPTION_END) == -EINVAL);
assert_se(sd_dhcp_client_set_request_option(client,
DHCP_OPTION_MESSAGE_TYPE) == -EINVAL);
assert_se(sd_dhcp_client_set_request_option(client,
DHCP_OPTION_OVERLOAD) == -EINVAL);
assert_se(sd_dhcp_client_set_request_option(client,
DHCP_OPTION_PARAMETER_REQUEST_LIST)
== -EINVAL);
assert_se(sd_dhcp_client_set_request_option(client, 33) == 0);
assert_se(sd_dhcp_client_set_request_option(client, 33) == -EEXIST);
assert_se(sd_dhcp_client_set_request_option(client, 44) == 0);
assert_se(sd_dhcp_client_set_request_option(client, 33) == -EEXIST);
sd_dhcp_client_unref(client);
}
static void test_checksum(void)
{
uint8_t buf[20] = {
0x45, 0x00, 0x02, 0x40, 0x00, 0x00, 0x00, 0x00,
0x40, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff
};
if (verbose)
printf("* %s\n", __FUNCTION__);
assert_se(dhcp_packet_checksum((uint8_t*)&buf, 20) == be16toh(0x78ae));
}
static int check_options(uint8_t code, uint8_t len, const uint8_t *option,
void *user_data)
{
switch(code) {
case DHCP_OPTION_CLIENT_IDENTIFIER:
{
uint32_t iaid;
struct duid duid;
size_t duid_len;
assert_se(dhcp_identifier_set_duid_en(&duid, &duid_len) >= 0);
assert_se(dhcp_identifier_set_iaid(42, mac_addr, ETH_ALEN, &iaid) >= 0);
assert_se(len == sizeof(uint8_t) + sizeof(uint32_t) + duid_len);
assert_se(len == 19);
assert_se(option[0] == 0xff);
assert_se(memcmp(&option[1], &iaid, sizeof(iaid)) == 0);
assert_se(memcmp(&option[5], &duid, duid_len) == 0);
break;
}
default:
break;
}
return 0;
}
int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link,
const void *packet, size_t len)
{
size_t size;
_cleanup_free_ DHCPPacket *discover;
uint16_t ip_check, udp_check;
assert_se(s >= 0);
assert_se(packet);
size = sizeof(DHCPPacket);
assert_se(len > size);
discover = memdup(packet, len);
assert_se(discover->ip.ttl == IPDEFTTL);
assert_se(discover->ip.protocol == IPPROTO_UDP);
assert_se(discover->ip.saddr == INADDR_ANY);
assert_se(discover->ip.daddr == INADDR_BROADCAST);
assert_se(discover->udp.source == be16toh(DHCP_PORT_CLIENT));
assert_se(discover->udp.dest == be16toh(DHCP_PORT_SERVER));
ip_check = discover->ip.check;
discover->ip.ttl = 0;
discover->ip.check = discover->udp.len;
udp_check = ~dhcp_packet_checksum((uint8_t*)&discover->ip.ttl, len - 8);
assert_se(udp_check == 0xffff);
discover->ip.ttl = IPDEFTTL;
discover->ip.check = ip_check;
ip_check = ~dhcp_packet_checksum((uint8_t*)&discover->ip, sizeof(discover->ip));
assert_se(ip_check == 0xffff);
assert_se(discover->dhcp.xid);
assert_se(memcmp(discover->dhcp.chaddr, &mac_addr, ETH_ALEN) == 0);
size = len - sizeof(struct iphdr) - sizeof(struct udphdr);
assert_se(callback_recv);
callback_recv(size, &discover->dhcp);
return 575;
}
int dhcp_network_bind_raw_socket(int index, union sockaddr_union *link,
uint32_t id, const uint8_t *addr,
size_t addr_len, uint16_t arp_type)
{
if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_fd) < 0)
return -errno;
return test_fd[0];
}
int dhcp_network_bind_udp_socket(be32_t address, uint16_t port)
{
return 0;
}
int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port,
const void *packet, size_t len)
{
return 0;
}
static int test_discover_message_verify(size_t size, struct DHCPMessage *dhcp)
{
int res;
res = dhcp_option_parse(dhcp, size, check_options, NULL);
assert_se(res == DHCP_DISCOVER);
if (verbose)
printf(" recv DHCP Discover 0x%08x\n", be32toh(dhcp->xid));
return 0;
}
static void test_discover_message(sd_event *e)
{
sd_dhcp_client *client;
int res, r;
if (verbose)
printf("* %s\n", __FUNCTION__);
r = sd_dhcp_client_new(&client);
assert_se(r >= 0);
assert_se(client);
r = sd_dhcp_client_attach_event(client, e, 0);
assert_se(r >= 0);
assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
assert_se(sd_dhcp_client_set_mac(client, mac_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
assert_se(sd_dhcp_client_set_request_option(client, 248) >= 0);
callback_recv = test_discover_message_verify;
res = sd_dhcp_client_start(client);
assert_se(res == 0 || res == -EINPROGRESS);
sd_event_run(e, (uint64_t) -1);
sd_dhcp_client_stop(client);
sd_dhcp_client_unref(client);
test_fd[1] = safe_close(test_fd[1]);
callback_recv = NULL;
}
static uint8_t test_addr_acq_offer[] = {
0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
0x6f, 0x95, 0x2f, 0x30, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
0xc0, 0xa8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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, 0x35, 0x01, 0x02, 0x36,
0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static uint8_t test_addr_acq_ack[] = {
0x45, 0x10, 0x01, 0x48, 0x00, 0x00, 0x00, 0x00,
0x80, 0x11, 0xb3, 0x84, 0xc0, 0xa8, 0x02, 0x01,
0xc0, 0xa8, 0x02, 0xbf, 0x00, 0x43, 0x00, 0x44,
0x01, 0x34, 0x00, 0x00, 0x02, 0x01, 0x06, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xc0, 0xa8, 0x02, 0xbf,
0xc0, 0xa8, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
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, 0x35, 0x01, 0x05, 0x36,
0x04, 0xc0, 0xa8, 0x02, 0x01, 0x33, 0x04, 0x00,
0x00, 0x02, 0x58, 0x01, 0x04, 0xff, 0xff, 0xff,
0x00, 0x2a, 0x04, 0xc0, 0xa8, 0x02, 0x01, 0x0f,
0x09, 0x6c, 0x61, 0x62, 0x2e, 0x69, 0x6e, 0x74,
0x72, 0x61, 0x03, 0x04, 0xc0, 0xa8, 0x02, 0x01,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static void test_addr_acq_acquired(sd_dhcp_client *client, int event,
void *userdata) {
sd_event *e = userdata;
sd_dhcp_lease *lease;
struct in_addr addr;
assert_se(client);
assert_se(event == DHCP_EVENT_IP_ACQUIRE);
assert_se(sd_dhcp_client_get_lease(client, &lease) >= 0);
assert_se(lease);
assert_se(sd_dhcp_lease_get_address(lease, &addr) >= 0);
assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[44],
sizeof(addr.s_addr)) == 0);
assert_se(sd_dhcp_lease_get_netmask(lease, &addr) >= 0);
assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[285],
sizeof(addr.s_addr)) == 0);
assert_se(sd_dhcp_lease_get_router(lease, &addr) >= 0);
assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[308],
sizeof(addr.s_addr)) == 0);
if (verbose)
printf(" DHCP address acquired\n");
sd_dhcp_lease_unref(lease);
sd_event_exit(e, 0);
}
static int test_addr_acq_recv_request(size_t size, DHCPMessage *request) {
uint16_t udp_check = 0;
uint8_t *msg_bytes = (uint8_t *)request;
int res;
res = dhcp_option_parse(request, size, check_options, NULL);
assert_se(res == DHCP_REQUEST);
assert_se(xid == request->xid);
assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
if (verbose)
printf(" recv DHCP Request 0x%08x\n", be32toh(xid));
memcpy(&test_addr_acq_ack[26], &udp_check, sizeof(udp_check));
memcpy(&test_addr_acq_ack[32], &xid, sizeof(xid));
memcpy(&test_addr_acq_ack[56], &mac_addr, ETHER_ADDR_LEN);
callback_recv = NULL;
res = write(test_fd[1], test_addr_acq_ack,
sizeof(test_addr_acq_ack));
assert_se(res == sizeof(test_addr_acq_ack));
if (verbose)
printf(" send DHCP Ack\n");
return 0;
};
static int test_addr_acq_recv_discover(size_t size, DHCPMessage *discover) {
uint16_t udp_check = 0;
uint8_t *msg_bytes = (uint8_t *)discover;
int res;
res = dhcp_option_parse(discover, size, check_options, NULL);
assert_se(res == DHCP_DISCOVER);
assert_se(msg_bytes[size - 1] == DHCP_OPTION_END);
xid = discover->xid;
if (verbose)
printf(" recv DHCP Discover 0x%08x\n", be32toh(xid));
memcpy(&test_addr_acq_offer[26], &udp_check, sizeof(udp_check));
memcpy(&test_addr_acq_offer[32], &xid, sizeof(xid));
memcpy(&test_addr_acq_offer[56], &mac_addr, ETHER_ADDR_LEN);
callback_recv = test_addr_acq_recv_request;
res = write(test_fd[1], test_addr_acq_offer,
sizeof(test_addr_acq_offer));
assert_se(res == sizeof(test_addr_acq_offer));
if (verbose)
printf(" sent DHCP Offer\n");
return 0;
}
static void test_addr_acq(sd_event *e) {
usec_t time_now = now(clock_boottime_or_monotonic());
sd_dhcp_client *client;
int res, r;
if (verbose)
printf("* %s\n", __FUNCTION__);
r = sd_dhcp_client_new(&client);
assert_se(r >= 0);
assert_se(client);
r = sd_dhcp_client_attach_event(client, e, 0);
assert_se(r >= 0);
assert_se(sd_dhcp_client_set_index(client, 42) >= 0);
assert_se(sd_dhcp_client_set_mac(client, mac_addr, ETH_ALEN, ARPHRD_ETHER) >= 0);
assert_se(sd_dhcp_client_set_callback(client, test_addr_acq_acquired, e)
>= 0);
callback_recv = test_addr_acq_recv_discover;
assert_se(sd_event_add_time(e, &test_hangcheck,
clock_boottime_or_monotonic(),
time_now + 2 * USEC_PER_SEC, 0,
test_dhcp_hangcheck, NULL) >= 0);
res = sd_dhcp_client_start(client);
assert_se(res == 0 || res == -EINPROGRESS);
assert_se(sd_event_loop(e) >= 0);
test_hangcheck = sd_event_source_unref(test_hangcheck);
assert_se(sd_dhcp_client_set_callback(client, NULL, NULL) >= 0);
assert_se(sd_dhcp_client_stop(client) >= 0);
sd_dhcp_client_unref(client);
test_fd[1] = safe_close(test_fd[1]);
callback_recv = NULL;
xid = 0;
}
int main(int argc, char *argv[]) {
_cleanup_event_unref_ sd_event *e;
log_set_max_level(LOG_DEBUG);
log_parse_environment();
log_open();
assert_se(sd_event_new(&e) >= 0);
test_request_basic(e);
test_checksum();
test_discover_message(e);
test_addr_acq(e);
return 0;
}