blob: 7cd30aa30003af23b415bb8b47a5571a3c61635c [file] [log] [blame]
Timo Teräsdafa05e2017-01-19 17:27:01 +02001/* NHRP netlink/GRE tunnel configuration code
2 * Copyright (c) 2014-2016 Timo Teräs
3 *
4 * This file is free software: you may copy, redistribute and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 */
9
10#include <netinet/in.h>
11#include <linux/netlink.h>
12#include <linux/rtnetlink.h>
13#include <linux/if.h>
14#include <linux/ip.h>
15#include <linux/ipv6.h>
16#include <linux/if_tunnel.h>
17
18#include "debug.h"
19#include "netlink.h"
20#include "znl.h"
21
22static int __netlink_gre_get_data(struct zbuf *zb, struct zbuf *data, int ifindex)
23{
24 struct nlmsghdr *n;
25 struct ifinfomsg *ifi;
26 struct zbuf payload, rtapayload;
27 struct rtattr *rta;
28
29 debugf(NHRP_DEBUG_KERNEL, "netlink-link-gre: get-info %u", ifindex);
30
31 n = znl_nlmsg_push(zb, RTM_GETLINK, NLM_F_REQUEST);
32 ifi = znl_push(zb, sizeof(*ifi));
33 *ifi = (struct ifinfomsg) {
34 .ifi_index = ifindex,
35 };
36 znl_nlmsg_complete(zb, n);
37
38 if (zbuf_send(zb, netlink_req_fd) < 0 ||
39 zbuf_recv(zb, netlink_req_fd) < 0)
40 return -1;
41
42 n = znl_nlmsg_pull(zb, &payload);
43 if (!n) return -1;
44
45 if (n->nlmsg_type != RTM_NEWLINK)
46 return -1;
47
48 ifi = znl_pull(&payload, sizeof(struct ifinfomsg));
49 if (!ifi)
50 return -1;
51
52 debugf(NHRP_DEBUG_KERNEL, "netlink-link-gre: ifindex %u, receive msg_type %u, msg_flags %u",
53 ifi->ifi_index, n->nlmsg_type, n->nlmsg_flags);
54
55 if (ifi->ifi_index != ifindex)
56 return -1;
57
58 while ((rta = znl_rta_pull(&payload, &rtapayload)) != NULL)
59 if (rta->rta_type == IFLA_LINKINFO)
60 break;
61 if (!rta) return -1;
62
63 payload = rtapayload;
64 while ((rta = znl_rta_pull(&payload, &rtapayload)) != NULL)
65 if (rta->rta_type == IFLA_INFO_DATA)
66 break;
67 if (!rta) return -1;
68
69 *data = rtapayload;
70 return 0;
71}
72
73void netlink_gre_get_info(unsigned int ifindex, uint32_t *gre_key, unsigned int *link_index, struct in_addr *saddr)
74{
75 struct zbuf *zb = zbuf_alloc(8192), data, rtapl;
76 struct rtattr *rta;
77
78 *link_index = 0;
79 *gre_key = 0;
80 saddr->s_addr = 0;
81
82 if (__netlink_gre_get_data(zb, &data, ifindex) < 0)
83 goto err;
84
85 while ((rta = znl_rta_pull(&data, &rtapl)) != NULL) {
86 switch (rta->rta_type) {
87 case IFLA_GRE_LINK:
88 *link_index = zbuf_get32(&rtapl);
89 break;
90 case IFLA_GRE_IKEY:
91 case IFLA_GRE_OKEY:
92 *gre_key = zbuf_get32(&rtapl);
93 break;
94 case IFLA_GRE_LOCAL:
95 saddr->s_addr = zbuf_get32(&rtapl);
96 break;
97 }
98 }
99err:
100 zbuf_free(zb);
101}
102
103void netlink_gre_set_link(unsigned int ifindex, unsigned int link_index)
104{
105 struct nlmsghdr *n;
106 struct ifinfomsg *ifi;
107 struct rtattr *rta_info, *rta_data, *rta;
108 struct zbuf *zr = zbuf_alloc(8192), data, rtapl;
109 struct zbuf *zb = zbuf_alloc(8192);
110 size_t len;
111
112 if (__netlink_gre_get_data(zr, &data, ifindex) < 0)
113 goto err;
114
115 n = znl_nlmsg_push(zb, RTM_NEWLINK, NLM_F_REQUEST);
116 ifi = znl_push(zb, sizeof(*ifi));
117 *ifi = (struct ifinfomsg) {
118 .ifi_index = ifindex,
119 };
120 rta_info = znl_rta_nested_push(zb, IFLA_LINKINFO);
121 znl_rta_push(zb, IFLA_INFO_KIND, "gre", 3);
122 rta_data = znl_rta_nested_push(zb, IFLA_INFO_DATA);
123
124 znl_rta_push_u32(zb, IFLA_GRE_LINK, link_index);
125 while ((rta = znl_rta_pull(&data, &rtapl)) != NULL) {
126 if (rta->rta_type == IFLA_GRE_LINK)
127 continue;
128 len = zbuf_used(&rtapl);
129 znl_rta_push(zb, rta->rta_type, zbuf_pulln(&rtapl, len), len);
130 }
131
132 znl_rta_nested_complete(zb, rta_data);
133 znl_rta_nested_complete(zb, rta_info);
134
135 znl_nlmsg_complete(zb, n);
136 zbuf_send(zb, netlink_req_fd);
137 zbuf_recv(zb, netlink_req_fd);
138err:
139 zbuf_free(zb);
140 zbuf_free(zr);
141}