chiark / gitweb /
sd-dhcp6-client: Add DHCPv6 Solicit test case
[elogind.git] / src / libsystemd-network / test-dhcp6-client.c
index b52f40792be32ba32b2f529849f3912ec493b906..43b127582682f524a34cfaa04396c1bb530f60bc 100644 (file)
 
 #include <stdbool.h>
 #include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <net/ethernet.h>
 
+#include "socket-util.h"
 #include "macro.h"
 #include "sd-event.h"
 #include "event-util.h"
+#include "virt.h"
 
 #include "sd-dhcp6-client.h"
 #include "dhcp6-protocol.h"
@@ -36,6 +42,11 @@ static struct ether_addr mac_addr = {
 
 static bool verbose = false;
 
+static sd_event_source *hangcheck;
+static int test_dhcp_fd[2];
+static int test_index = 42;
+static sd_event *e_solicit;
+
 static int test_client_basic(sd_event *e) {
         sd_dhcp6_client *client;
 
@@ -128,6 +139,145 @@ static int test_option(sd_event *e) {
         return 0;
 }
 
+static int test_hangcheck(sd_event_source *s, uint64_t usec, void *userdata) {
+        assert_not_reached("Test case should have completed in 2 seconds");
+
+        return 0;
+}
+
+int detect_vm(const char **id) {
+        return 1;
+}
+
+int detect_container(const char **id) {
+        return 1;
+}
+
+int detect_virtualization(const char **id) {
+        return 1;
+}
+
+int dhcp6_network_bind_udp_socket(int index, struct in6_addr *local_address) {
+        assert_se(index == test_index);
+
+        if (socketpair(AF_UNIX, SOCK_STREAM, 0, test_dhcp_fd) < 0)
+                return -errno;
+
+        return test_dhcp_fd[0];
+}
+
+static int verify_solicit(DHCP6Message *solicit, uint8_t *option, size_t len) {
+        uint8_t *optval;
+        uint16_t optcode;
+        size_t optlen;
+        bool found_clientid = false, found_iana = false;
+        int r;
+
+        assert_se(solicit->type == DHCP6_SOLICIT);
+
+        while ((r = dhcp6_option_parse(&option, &len,
+                                       &optcode, &optlen, &optval)) >= 0) {
+                switch(optcode) {
+                case DHCP6_OPTION_CLIENTID:
+                        assert_se(!found_clientid);
+                        found_clientid = true;
+
+                        assert_se(optlen == 14);
+
+                        break;
+
+                case DHCP6_OPTION_IA_NA:
+                        assert_se(!found_iana);
+                        found_iana = true;
+
+                        assert_se(optlen == 12);
+
+                        break;
+                }
+        }
+
+        assert_se(r == -ENOMSG);
+        assert_se(found_clientid && found_iana);
+
+        sd_event_exit(e_solicit, 0);
+
+        return 0;
+}
+
+int dhcp6_network_send_udp_socket(int s, struct in6_addr *server_address,
+                                  const void *packet, size_t len) {
+        struct in6_addr mcast =
+                IN6ADDR_ALL_DHCP6_RELAY_AGENTS_AND_SERVERS_INIT;
+        DHCP6Message *message;
+        uint8_t *option;
+
+        assert_se(s == test_dhcp_fd[0]);
+        assert_se(server_address);
+        assert_se(packet);
+        assert_se(len > sizeof(DHCP6Message) + 4);
+
+        assert_se(IN6_ARE_ADDR_EQUAL(server_address, &mcast));
+
+        message = (DHCP6Message *)packet;
+        option = (uint8_t *)(message + 1);
+        len -= sizeof(DHCP6Message);
+
+        assert_se(message->transaction_id & 0x00ffffff);
+
+        verify_solicit(message, option, len);
+
+        return len;
+}
+
+static void test_client_solicit_cb(sd_dhcp6_client *client, int event,
+                                   void *userdata) {
+        sd_event *e = userdata;
+
+        assert_se(e);
+
+        if (verbose)
+                printf("  got DHCPv6 event %d\n", event);
+
+        sd_event_exit(e, 0);
+}
+
+static int test_client_solicit(sd_event *e) {
+        sd_dhcp6_client *client;
+        usec_t time_now = now(CLOCK_MONOTONIC);
+
+        if (verbose)
+                printf("* %s\n", __FUNCTION__);
+
+        assert_se(sd_dhcp6_client_new(&client) >= 0);
+        assert_se(client);
+
+        assert_se(sd_dhcp6_client_attach_event(client, e, 0) >= 0);
+
+        assert_se(sd_dhcp6_client_set_index(client, test_index) == 0);
+        assert_se(sd_dhcp6_client_set_mac(client, &mac_addr) >= 0);
+
+        assert_se(sd_dhcp6_client_set_callback(client,
+                                               test_client_solicit_cb, e) >= 0);
+
+        assert_se(sd_event_add_time(e, &hangcheck, CLOCK_MONOTONIC,
+                                    time_now + 2 * USEC_PER_SEC, 0,
+                                    test_hangcheck, NULL) >= 0);
+
+        e_solicit = e;
+
+        assert_se(sd_dhcp6_client_start(client) >= 0);
+
+        sd_event_loop(e);
+
+        hangcheck = sd_event_source_unref(hangcheck);
+
+        assert_se(!sd_dhcp6_client_unref(client));
+
+        test_dhcp_fd[1] = safe_close(test_dhcp_fd[1]);
+
+        return 0;
+}
+
 int main(int argc, char *argv[]) {
         _cleanup_event_unref_ sd_event *e;
 
@@ -139,6 +289,7 @@ int main(int argc, char *argv[]) {
 
         test_client_basic(e);
         test_option(e);
+        test_client_solicit(e);
 
         assert_se(!sd_event_unref(e));