1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3 * Copyright (c) 2019 Eyal Birger <[email protected]>
4 *
5 * Based on lib/route/link/ipvti.c
6 */
7
8 /**
9 * @ingroup link
10 * @defgroup xfrmi XFRMI
11 * xfrmi link module
12 *
13 * @details
14 * \b Link Type Name: "xfrmi"
15 *
16 * @route_doc{link_xfrmi, XFRMI Documentation}
17 *
18 * @{
19 */
20
21 #include "nl-default.h"
22
23 #include <netlink/netlink.h>
24 #include <netlink/attr.h>
25 #include <netlink/utils.h>
26 #include <netlink/object.h>
27 #include <netlink/route/rtnl.h>
28 #include <netlink/route/link/xfrmi.h>
29
30 #include "nl-route.h"
31 #include "link-api.h"
32
33 #define XFRMI_ATTR_LINK (1 << 0)
34 #define XFRMI_ATTR_IF_ID (1 << 1)
35
36 #define XFRMI_LINK_TYPE_NAME "xfrm"
37
38 struct xfrmi_info {
39 uint32_t link;
40 uint32_t if_id;
41 uint32_t xfrmi_mask;
42 };
43
44 static struct nla_policy xfrmi_policy[IFLA_XFRM_MAX + 1] = {
45 [IFLA_XFRM_LINK] = { .type = NLA_U32 },
46 [IFLA_XFRM_IF_ID] = { .type = NLA_U32 },
47 };
48
xfrmi_alloc(struct rtnl_link * link)49 static int xfrmi_alloc(struct rtnl_link *link)
50 {
51 struct xfrmi_info *xfrmi;
52
53 if (link->l_info)
54 memset(link->l_info, 0, sizeof(*xfrmi));
55 else {
56 xfrmi = calloc(1, sizeof(*xfrmi));
57 if (!xfrmi)
58 return -NLE_NOMEM;
59
60 link->l_info = xfrmi;
61 }
62
63 return 0;
64 }
65
xfrmi_parse(struct rtnl_link * link,struct nlattr * data,struct nlattr * xstats)66 static int xfrmi_parse(struct rtnl_link *link, struct nlattr *data,
67 struct nlattr *xstats)
68 {
69 struct nlattr *tb[IFLA_XFRM_MAX + 1];
70 struct xfrmi_info *xfrmi;
71 int err;
72
73 NL_DBG(3, "Parsing XFRMI link info\n");
74
75 err = nla_parse_nested(tb, IFLA_XFRM_MAX, data, xfrmi_policy);
76 if (err < 0)
77 return err;
78
79 err = xfrmi_alloc(link);
80 if (err < 0)
81 return err;
82
83 xfrmi = link->l_info;
84
85 if (tb[IFLA_XFRM_LINK]) {
86 xfrmi->link = nla_get_u32(tb[IFLA_XFRM_LINK]);
87 xfrmi->xfrmi_mask |= XFRMI_ATTR_LINK;
88 }
89
90 if (tb[IFLA_XFRM_IF_ID]) {
91 xfrmi->if_id = nla_get_u32(tb[IFLA_XFRM_IF_ID]);
92 xfrmi->xfrmi_mask |= XFRMI_ATTR_IF_ID;
93 }
94
95 return 0;
96 }
97
xfrmi_put_attrs(struct nl_msg * msg,struct rtnl_link * link)98 static int xfrmi_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
99 {
100 struct xfrmi_info *xfrmi = link->l_info;
101 struct nlattr *data;
102
103 data = nla_nest_start(msg, IFLA_INFO_DATA);
104 if (!data)
105 return -NLE_MSGSIZE;
106
107 if (xfrmi->xfrmi_mask & XFRMI_ATTR_LINK)
108 NLA_PUT_U32(msg, IFLA_XFRM_LINK, xfrmi->link);
109
110 if (xfrmi->xfrmi_mask & XFRMI_ATTR_IF_ID)
111 NLA_PUT_U32(msg, IFLA_XFRM_IF_ID, xfrmi->if_id);
112
113 nla_nest_end(msg, data);
114
115 nla_put_failure:
116 return 0;
117 }
118
xfrmi_free(struct rtnl_link * link)119 static void xfrmi_free(struct rtnl_link *link)
120 {
121 struct xfrmi_info *xfrmi = link->l_info;
122
123 free(xfrmi);
124 link->l_info = NULL;
125 }
126
xfrmi_dump_line(struct rtnl_link * link,struct nl_dump_params * p)127 static void xfrmi_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
128 {
129 nl_dump(p, "xfrmi : %s", link->l_name);
130 }
131
xfrmi_dump_details(struct rtnl_link * link,struct nl_dump_params * p)132 static void xfrmi_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
133 {
134 struct xfrmi_info *xfrmi = link->l_info;
135
136 if (xfrmi->xfrmi_mask & XFRMI_ATTR_LINK) {
137 struct rtnl_link *parent;
138 char *name;
139
140 nl_dump(p, " link ");
141
142 name = NULL;
143 parent = link_lookup(link->ce_cache, xfrmi->link);
144 if (parent)
145 name = rtnl_link_get_name(parent);
146
147 if (name)
148 nl_dump_line(p, "%s\n", name);
149 else
150 nl_dump_line(p, "%u\n", xfrmi->link);
151 }
152
153 if (xfrmi->xfrmi_mask & XFRMI_ATTR_IF_ID) {
154 nl_dump(p, " if_id ");
155 nl_dump_line(p, "%x\n", xfrmi->if_id);
156 }
157 }
158
xfrmi_clone(struct rtnl_link * dst,struct rtnl_link * src)159 static int xfrmi_clone(struct rtnl_link *dst, struct rtnl_link *src)
160 {
161 struct xfrmi_info *xfrmi_dst, *xfrmi_src = src->l_info;
162 int err;
163
164 dst->l_info = NULL;
165
166 err = rtnl_link_set_type(dst, XFRMI_LINK_TYPE_NAME);
167 if (err < 0)
168 return err;
169
170 xfrmi_dst = dst->l_info;
171
172 if (!xfrmi_dst || !xfrmi_src)
173 BUG();
174
175 memcpy(xfrmi_dst, xfrmi_src, sizeof(struct xfrmi_info));
176
177 return 0;
178 }
179
180 static struct rtnl_link_info_ops xfrmi_info_ops = {
181 .io_name = XFRMI_LINK_TYPE_NAME,
182 .io_alloc = xfrmi_alloc,
183 .io_parse = xfrmi_parse,
184 .io_dump = {
185 [NL_DUMP_LINE] = xfrmi_dump_line,
186 [NL_DUMP_DETAILS] = xfrmi_dump_details,
187 },
188 .io_clone = xfrmi_clone,
189 .io_put_attrs = xfrmi_put_attrs,
190 .io_free = xfrmi_free,
191 };
192
193 #define IS_XFRMI_LINK_ASSERT(link) do { \
194 if ((link)->l_info_ops != &xfrmi_info_ops) { \
195 APPBUG("Link is not a xfrmi link. set type \"xfrmi\" first."); \
196 return -NLE_OPNOTSUPP; \
197 } \
198 } while(0)
199
rtnl_link_xfrmi_alloc(void)200 struct rtnl_link *rtnl_link_xfrmi_alloc(void)
201 {
202 struct rtnl_link *link;
203 int err;
204
205 link = rtnl_link_alloc();
206 if (!link)
207 return NULL;
208
209 err = rtnl_link_set_type(link, XFRMI_LINK_TYPE_NAME);
210 if (err < 0) {
211 rtnl_link_put(link);
212 return NULL;
213 }
214
215 return link;
216 }
217
218 /**
219 * Check if link is a XFRMI link
220 * @arg link Link object
221 *
222 * @return True if link is a IXFRMI link, otherwise 0 is returned.
223 */
rtnl_link_is_xfrmi(struct rtnl_link * link)224 int rtnl_link_is_xfrmi(struct rtnl_link *link)
225 {
226 return link->l_info_ops && !strcmp(link->l_info_ops->io_name,
227 XFRMI_LINK_TYPE_NAME);
228 }
229
230 /**
231 * Set XFRMI link interface index
232 * @arg link Link object
233 * @arg index interface index
234 *
235 * @return 0 on success or a negative error code
236 */
rtnl_link_xfrmi_set_link(struct rtnl_link * link,uint32_t index)237 int rtnl_link_xfrmi_set_link(struct rtnl_link *link, uint32_t index)
238 {
239 struct xfrmi_info *xfrmi = link->l_info;
240
241 IS_XFRMI_LINK_ASSERT(link);
242
243 xfrmi->link = index;
244 xfrmi->xfrmi_mask |= XFRMI_ATTR_LINK;
245
246 return 0;
247 }
248
249 /**
250 * Get XFRMI link interface index
251 * @arg link Link object
252 * @arg out_link The output value on success
253 *
254 * @return 0 on success or a negative error code
255 */
rtnl_link_xfrmi_get_link(struct rtnl_link * link,uint32_t * out_link)256 int rtnl_link_xfrmi_get_link(struct rtnl_link *link, uint32_t *out_link)
257 {
258 struct xfrmi_info *xfrmi = link->l_info;
259
260 IS_XFRMI_LINK_ASSERT(link);
261
262 if (!(xfrmi->xfrmi_mask & XFRMI_ATTR_LINK))
263 return -NLE_NOATTR;
264
265 *out_link = xfrmi->link;
266 return 0;
267 }
268
269 /**
270 * Set XFRMI if_id
271 * @arg link Link object
272 * @arg if_id xfrm if_id
273 *
274 * @return 0 on success or a negative error code
275 */
rtnl_link_xfrmi_set_if_id(struct rtnl_link * link,uint32_t if_id)276 int rtnl_link_xfrmi_set_if_id(struct rtnl_link *link, uint32_t if_id)
277 {
278 struct xfrmi_info *xfrmi = link->l_info;
279
280 IS_XFRMI_LINK_ASSERT(link);
281
282 xfrmi->if_id = if_id;
283 xfrmi->xfrmi_mask |= XFRMI_ATTR_IF_ID;
284
285 return 0;
286 }
287
288 /**
289 * Get XFRMI if_id
290 * @arg link Link object
291 * @arg out_if_id The output value on success
292 *
293 * @return 0 on success or a negative error code
294 */
rtnl_link_xfrmi_get_if_id(struct rtnl_link * link,uint32_t * out_if_id)295 int rtnl_link_xfrmi_get_if_id(struct rtnl_link *link, uint32_t *out_if_id)
296 {
297 struct xfrmi_info *xfrmi = link->l_info;
298
299 IS_XFRMI_LINK_ASSERT(link);
300
301 if (!(xfrmi->xfrmi_mask & XFRMI_ATTR_IF_ID))
302 return -NLE_NOATTR;
303
304 *out_if_id = xfrmi->if_id;
305 return 0;
306 }
307
xfrmi_init(void)308 static void _nl_init xfrmi_init(void)
309 {
310 rtnl_link_register_info(&xfrmi_info_ops);
311 }
312
xfrmi_exit(void)313 static void _nl_exit xfrmi_exit(void)
314 {
315 rtnl_link_unregister_info(&xfrmi_info_ops);
316 }
317