xref: /aosp_15_r20/external/libnl/lib/route/link/xfrmi.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
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