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;
+}