blob: e619883f0a7ab3f2e1730689632cf22056142a82 [file] [log] [blame]
Harald Weltef7365592020-04-15 21:48:45 +02001/* SPDX-License-Identifier: GPL-2.0 */
2#include <unistd.h>
3#include <stdint.h>
4#include <stdbool.h>
5#include <stdlib.h>
6#include <string.h>
7#include <stdio.h>
8#include <errno.h>
9#include <sys/types.h>
10#include <sys/socket.h>
11
12#include <netinet/ip.h>
13#include <netinet/ip6.h>
14
15#include <linux/if.h>
16#include <linux/if_tun.h>
17#include <sys/ioctl.h>
18
Harald Weltef2be0992020-04-20 11:12:42 +000019#include <linux/netlink.h>
Harald Weltef7365592020-04-15 21:48:45 +020020#include <netlink/socket.h>
21#include <netlink/route/link.h>
22#include <netlink/route/addr.h>
23#include <netlink/route/route.h>
24#include <netlink/route/nexthop.h>
25
26#include <osmocom/core/utils.h>
27
28/***********************************************************************
29 * netlink helper functions
30 ***********************************************************************/
31
32static int _netdev_addr(struct nl_sock *nlsk, int ifindex, const struct sockaddr_storage *ss, bool add)
33{
34 const struct sockaddr_in6 *sin6;
35 const struct sockaddr_in *sin;
36 struct nl_addr *local = NULL;
37 struct rtnl_addr *addr;
38 int rc;
39
40 switch (ss->ss_family) {
41 case AF_INET:
42 sin = (struct sockaddr_in *) ss;
43 local = nl_addr_build(AF_INET, &sin->sin_addr, 4);
44 break;
45 case AF_INET6:
46 sin6 = (struct sockaddr_in6 *) ss;
47 local = nl_addr_build(AF_INET6, &sin6->sin6_addr, 16);
48 break;
49 }
50 OSMO_ASSERT(local);
51
52 addr = rtnl_addr_alloc();
53 OSMO_ASSERT(addr);
54 rtnl_addr_set_ifindex(addr, ifindex);
55 OSMO_ASSERT(rtnl_addr_set_local(addr, local) == 0);
56
57 if (add)
58 rc = rtnl_addr_add(nlsk, addr, 0);
59 else
60 rc = rtnl_addr_delete(nlsk, addr, 0);
61
62 rtnl_addr_put(addr);
63
64 return rc;
65}
66
67int netdev_add_addr(struct nl_sock *nlsk, int ifindex, const struct sockaddr_storage *ss)
68{
69 return _netdev_addr(nlsk, ifindex, ss, true);
70}
71
72int netdev_del_addr(struct nl_sock *nlsk, int ifindex, const struct sockaddr_storage *ss)
73{
74 return _netdev_addr(nlsk, ifindex, ss, false);
75}
76
77int netdev_set_link(struct nl_sock *nlsk, int ifindex, bool up)
78{
79 struct rtnl_link *link, *change;
80 int rc;
81
82 rc = rtnl_link_get_kernel(nlsk, ifindex, NULL, &link);
83 if (rc < 0)
84 return rc;
85
86 change = rtnl_link_alloc();
87 OSMO_ASSERT(change);
88
89 if (up)
90 rtnl_link_set_flags(change, IFF_UP);
91 else
92 rtnl_link_unset_flags(change, IFF_UP);
93
94 rc = rtnl_link_change(nlsk, link, change, 0);
95
96 rtnl_link_put(change);
97 rtnl_link_put(link);
98
99 return rc;
100}
101
102int netdev_add_defaultroute(struct nl_sock *nlsk, int ifindex, uint8_t family)
103{
104 struct rtnl_route *route = rtnl_route_alloc();
105 struct rtnl_nexthop *nhop = rtnl_route_nh_alloc();
106 struct nl_addr *dst, *gw;
107 uint8_t buf[16];
108 int rc;
109
110 OSMO_ASSERT(route);
111 OSMO_ASSERT(nhop);
112
113 /* destination address of route: all-zero */
114 memset(buf, 0, sizeof(buf));
115 dst = nl_addr_build(family, buf, family == AF_INET ? 4 : 16);
116 OSMO_ASSERT(dst);
117 nl_addr_set_prefixlen(dst, 0);
118
119 /* gateway address of route: also all-zero */
120 gw = nl_addr_clone(dst);
121 OSMO_ASSERT(gw);
122
123 /* nexthop for route */
124 rtnl_route_nh_set_ifindex(nhop, ifindex);
125 rtnl_route_nh_set_gateway(nhop, gw);
126
127 /* tie everything together in the route */
128 rtnl_route_set_dst(route, dst);
129 rtnl_route_set_family(route, family);
130 rtnl_route_add_nexthop(route, nhop);
131
132 rc = rtnl_route_add(nlsk, route, NLM_F_CREATE);
133
134 //rtnl_route_nh_free(nhop);
135 nl_addr_put(gw);
136 nl_addr_put(dst);
137 rtnl_route_put(route);
138
139 return rc;
140}