initial check-in of the UECUPS daemon and the related TTCN3 code

Change-Id: I5acf7059722b58e6f57dbf31e18abcc385533970
diff --git a/daemon/netdev.c b/daemon/netdev.c
new file mode 100644
index 0000000..2022d24
--- /dev/null
+++ b/daemon/netdev.c
@@ -0,0 +1,139 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <unistd.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <sys/ioctl.h>
+
+#include <netlink/socket.h>
+#include <netlink/route/link.h>
+#include <netlink/route/addr.h>
+#include <netlink/route/route.h>
+#include <netlink/route/nexthop.h>
+
+#include <osmocom/core/utils.h>
+
+/***********************************************************************
+ * netlink helper functions
+ ***********************************************************************/
+
+static int _netdev_addr(struct nl_sock *nlsk, int ifindex, const struct sockaddr_storage *ss, bool add)
+{
+	const struct sockaddr_in6 *sin6;
+	const struct sockaddr_in *sin;
+	struct nl_addr *local = NULL;
+	struct rtnl_addr *addr;
+	int rc;
+
+	switch (ss->ss_family) {
+	case AF_INET:
+		sin = (struct sockaddr_in *) ss;
+		local = nl_addr_build(AF_INET, &sin->sin_addr, 4);
+		break;
+	case AF_INET6:
+		sin6 = (struct sockaddr_in6 *) ss;
+		local = nl_addr_build(AF_INET6, &sin6->sin6_addr, 16);
+		break;
+	}
+	OSMO_ASSERT(local);
+
+	addr = rtnl_addr_alloc();
+	OSMO_ASSERT(addr);
+	rtnl_addr_set_ifindex(addr, ifindex);
+	OSMO_ASSERT(rtnl_addr_set_local(addr, local) == 0);
+
+	if (add)
+		rc = rtnl_addr_add(nlsk, addr, 0);
+	else
+		rc = rtnl_addr_delete(nlsk, addr, 0);
+
+	rtnl_addr_put(addr);
+
+	return rc;
+}
+
+int netdev_add_addr(struct nl_sock *nlsk, int ifindex, const struct sockaddr_storage *ss)
+{
+	return _netdev_addr(nlsk, ifindex, ss, true);
+}
+
+int netdev_del_addr(struct nl_sock *nlsk, int ifindex, const struct sockaddr_storage *ss)
+{
+	return _netdev_addr(nlsk, ifindex, ss, false);
+}
+
+int netdev_set_link(struct nl_sock *nlsk, int ifindex, bool up)
+{
+	struct rtnl_link *link, *change;
+	int rc;
+
+	rc = rtnl_link_get_kernel(nlsk, ifindex, NULL, &link);
+	if (rc < 0)
+		return rc;
+
+	change = rtnl_link_alloc();
+	OSMO_ASSERT(change);
+
+	if (up)
+		rtnl_link_set_flags(change, IFF_UP);
+	else
+		rtnl_link_unset_flags(change, IFF_UP);
+
+	rc = rtnl_link_change(nlsk, link, change, 0);
+
+	rtnl_link_put(change);
+	rtnl_link_put(link);
+
+	return rc;
+}
+
+int netdev_add_defaultroute(struct nl_sock *nlsk, int ifindex, uint8_t family)
+{
+	struct rtnl_route *route = rtnl_route_alloc();
+	struct rtnl_nexthop *nhop = rtnl_route_nh_alloc();
+	struct nl_addr *dst, *gw;
+	uint8_t buf[16];
+	int rc;
+
+	OSMO_ASSERT(route);
+	OSMO_ASSERT(nhop);
+
+	/* destination address of route: all-zero */
+	memset(buf, 0, sizeof(buf));
+	dst = nl_addr_build(family, buf, family == AF_INET ? 4 : 16);
+	OSMO_ASSERT(dst);
+	nl_addr_set_prefixlen(dst, 0);
+
+	/* gateway address of route: also all-zero */
+	gw = nl_addr_clone(dst);
+	OSMO_ASSERT(gw);
+
+	/* nexthop for route */
+	rtnl_route_nh_set_ifindex(nhop, ifindex);
+	rtnl_route_nh_set_gateway(nhop, gw);
+
+	/* tie everything together in the route */
+	rtnl_route_set_dst(route, dst);
+	rtnl_route_set_family(route, family);
+	rtnl_route_add_nexthop(route, nhop);
+
+	rc = rtnl_route_add(nlsk, route, NLM_F_CREATE);
+
+	//rtnl_route_nh_free(nhop);
+	nl_addr_put(gw);
+	nl_addr_put(dst);
+	rtnl_route_put(route);
+
+	return rc;
+}