7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen/***
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen This file is part of systemd.
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen Copyright (C) 2014 Tom Gundersen <teg@jklm.no>
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen systemd is free software; you can redistribute it and/or modify it
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen under the terms of the GNU Lesser General Public License as published by
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen the Free Software Foundation; either version 2.1 of the License, or
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen (at your option) any later version.
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen systemd is distributed in the hope that it will be useful, but
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen Lesser General Public License for more details.
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen You should have received a copy of the GNU Lesser General Public License
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen***/
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen#include <errno.h>
cf0fbc49e67b55f8d346fc94de28c90113505297Thomas Hindoe Paaboel Andersen#include <stdlib.h>
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen#include <unistd.h>
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen#include <linux/veth.h>
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen#include <net/if.h>
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen#include "sd-event.h"
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen#include "sd-ipv4acd.h"
cf0fbc49e67b55f8d346fc94de28c90113505297Thomas Hindoe Paaboel Andersen#include "sd-netlink.h"
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen#include "in-addr-util.h"
cf0fbc49e67b55f8d346fc94de28c90113505297Thomas Hindoe Paaboel Andersen#include "netlink-util.h"
cf0fbc49e67b55f8d346fc94de28c90113505297Thomas Hindoe Paaboel Andersen#include "util.h"
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersenstatic void acd_handler(sd_ipv4acd *acd, int event, void *userdata) {
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(acd);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen switch (event) {
2237aa02f3e2739a1ebe9c0bc224b5125f5eb292David Herrmann case SD_IPV4ACD_EVENT_BIND:
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen log_info("bound");
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen break;
2237aa02f3e2739a1ebe9c0bc224b5125f5eb292David Herrmann case SD_IPV4ACD_EVENT_CONFLICT:
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen log_info("conflict");
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen break;
2237aa02f3e2739a1ebe9c0bc224b5125f5eb292David Herrmann case SD_IPV4ACD_EVENT_STOP:
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen log_error("the client was stopped");
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen break;
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen default:
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_not_reached("invalid ACD event");
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen }
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen}
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersenstatic int client_run(int ifindex, const struct in_addr *pa, const struct ether_addr *ha, sd_event *e) {
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen sd_ipv4acd *acd;
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_ipv4acd_new(&acd) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_ipv4acd_attach_event(acd, e, 0) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_ipv4acd_set_index(acd, ifindex) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_ipv4acd_set_mac(acd, ha) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_ipv4acd_set_address(acd, pa) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_ipv4acd_set_callback(acd, acd_handler, NULL) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen log_info("starting IPv4ACD client");
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_ipv4acd_start(acd) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_event_loop(e) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(!sd_ipv4acd_unref(acd));
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen return EXIT_SUCCESS;
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen}
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersenstatic int test_acd(const char *ifname, const char *address) {
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_event_unrefp) sd_event *e = NULL;
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
4afd3348c7506dd1d36305b7bcb9feb8952b9d6bLennart Poettering _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL;
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen union in_addr_union pa;
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen struct ether_addr ha;
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen int ifindex;
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(in_addr_from_string(AF_INET, address, &pa) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_event_new(&e) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_netlink_open(&rtnl) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_netlink_attach_event(rtnl, e, 0) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_rtnl_message_new_link(rtnl, &m, RTM_GETLINK, 0) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_netlink_message_append_string(m, IFLA_IFNAME, ifname) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_netlink_call(rtnl, m, 0, &reply) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_rtnl_message_link_get_ifindex(reply, &ifindex) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen assert_se(sd_netlink_message_read_ether_addr(reply, IFLA_ADDRESS, &ha) >= 0);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen client_run(ifindex, &pa.in, &ha, e);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen return EXIT_SUCCESS;
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen}
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersenint main(int argc, char *argv[]) {
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen log_set_max_level(LOG_DEBUG);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen log_parse_environment();
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen log_open();
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen if (argc == 3)
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen return test_acd(argv[1], argv[2]);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen else {
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen log_error("This program takes two arguments.\n"
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen "\t %s <ifname> <IPv4 address>", program_invocation_short_name);
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen return EXIT_FAILURE;
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen }
7b713b81c27277f37420c121f2c9eeb10646ff5aTom Gundersen}