blob: e619883f0a7ab3f2e1730689632cf22056142a82 [file] [log] [blame]
/* 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 <linux/netlink.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;
}