141 lines
3.2 KiB
C
141 lines
3.2 KiB
C
/* 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;
|
|
}
|