xref: /aosp_15_r20/external/libnl/lib/route/link/ip6tnl.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2014 Susant Sahani <[email protected]>
4  */
5 
6 /**
7  * @ingroup link
8  * @defgroup ip6tnl IP6TNL
9  * ip6tnl link module
10  *
11  * @details
12  * \b Link Type Name: "ip6tnl"
13  *
14  * @route_doc{link_ip6tnl, IP6TNL Documentation}
15  *
16  * @{
17  */
18 
19 #include "nl-default.h"
20 
21 #include <linux/if_tunnel.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/ip6tnl.h>
29 
30 #include "nl-route.h"
31 #include "link-api.h"
32 
33 #define IP6_TNL_ATTR_LINK          (1 << 0)
34 #define IP6_TNL_ATTR_LOCAL         (1 << 1)
35 #define IP6_TNL_ATTR_REMOTE        (1 << 2)
36 #define IP6_TNL_ATTR_TTL           (1 << 3)
37 #define IP6_TNL_ATTR_TOS           (1 << 4)
38 #define IP6_TNL_ATTR_ENCAPLIMIT    (1 << 5)
39 #define IP6_TNL_ATTR_FLAGS         (1 << 6)
40 #define IP6_TNL_ATTR_PROTO         (1 << 7)
41 #define IP6_TNL_ATTR_FLOWINFO      (1 << 8)
42 #define IP6_TNL_ATTR_FWMARK        (1 << 9)
43 
44 struct ip6_tnl_info
45 {
46 	uint8_t                 ttl;
47 	uint8_t                 tos;
48 	uint8_t                 encap_limit;
49 	uint8_t                 proto;
50 	uint32_t                flags;
51 	uint32_t                link;
52 	uint32_t                flowinfo;
53 	struct in6_addr         local;
54 	struct in6_addr         remote;
55 	uint32_t                fwmark;
56 	uint32_t                ip6_tnl_mask;
57 };
58 
59 static struct nla_policy ip6_tnl_policy[IFLA_IPTUN_MAX + 1] = {
60 	[IFLA_IPTUN_LINK]         = { .type = NLA_U32 },
61 	[IFLA_IPTUN_LOCAL]        = { .minlen = sizeof(struct in6_addr) },
62 	[IFLA_IPTUN_REMOTE]       = { .minlen = sizeof(struct in6_addr) },
63 	[IFLA_IPTUN_TTL]          = { .type = NLA_U8 },
64 	[IFLA_IPTUN_TOS]          = { .type = NLA_U8 },
65 	[IFLA_IPTUN_ENCAP_LIMIT]  = { .type = NLA_U8 },
66 	[IFLA_IPTUN_FLOWINFO]     = { .type = NLA_U32 },
67 	[IFLA_IPTUN_FLAGS]        = { .type = NLA_U32 },
68 	[IFLA_IPTUN_PROTO]        = { .type = NLA_U8 },
69 	[IFLA_IPTUN_FWMARK]       = { .type = NLA_U32 },
70 };
71 
ip6_tnl_alloc(struct rtnl_link * link)72 static int ip6_tnl_alloc(struct rtnl_link *link)
73 {
74 	struct ip6_tnl_info *ip6_tnl;
75 
76 	if (link->l_info)
77 		memset(link->l_info, 0, sizeof(*ip6_tnl));
78 	else {
79 		ip6_tnl = calloc(1, sizeof(*ip6_tnl));
80 		if (!ip6_tnl)
81 			return -NLE_NOMEM;
82 
83 		link->l_info = ip6_tnl;
84 	}
85 
86 	return 0;
87 }
88 
ip6_tnl_parse(struct rtnl_link * link,struct nlattr * data,struct nlattr * xstats)89 static int ip6_tnl_parse(struct rtnl_link *link, struct nlattr *data,
90 			 struct nlattr *xstats)
91 {
92 	struct nlattr *tb[IFLA_IPTUN_MAX + 1];
93 	struct ip6_tnl_info *ip6_tnl;
94 	int err;
95 
96 	NL_DBG(3, "Parsing IP6_TNL link info\n");
97 
98 	err = nla_parse_nested(tb, IFLA_IPTUN_MAX, data, ip6_tnl_policy);
99 	if (err < 0)
100 		goto errout;
101 
102 	err = ip6_tnl_alloc(link);
103 	if (err < 0)
104 		goto errout;
105 
106 	ip6_tnl = link->l_info;
107 
108 	if (tb[IFLA_IPTUN_LINK]) {
109 		ip6_tnl->link = nla_get_u32(tb[IFLA_IPTUN_LINK]);
110 		ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_LINK;
111 	}
112 
113 	if (tb[IFLA_IPTUN_LOCAL]) {
114 		nla_memcpy(&ip6_tnl->local, tb[IFLA_IPTUN_LOCAL], sizeof(struct in6_addr));
115 		ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_LOCAL;
116 	}
117 
118 	if (tb[IFLA_IPTUN_REMOTE]) {
119 		nla_memcpy(&ip6_tnl->remote, tb[IFLA_IPTUN_REMOTE], sizeof(struct in6_addr));
120 		ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_REMOTE;
121 	}
122 
123 	if (tb[IFLA_IPTUN_TTL]) {
124 		ip6_tnl->ttl = nla_get_u8(tb[IFLA_IPTUN_TTL]);
125 		ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_TTL;
126 	}
127 
128 	if (tb[IFLA_IPTUN_TOS]) {
129 		ip6_tnl->tos = nla_get_u8(tb[IFLA_IPTUN_TOS]);
130 		ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_TOS;
131 	}
132 
133 	if (tb[IFLA_IPTUN_ENCAP_LIMIT]) {
134 		ip6_tnl->encap_limit = nla_get_u8(tb[IFLA_IPTUN_ENCAP_LIMIT]);
135 		ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_ENCAPLIMIT;
136 	}
137 
138 	if (tb[IFLA_IPTUN_FLAGS]) {
139 		ip6_tnl->flags = nla_get_u32(tb[IFLA_IPTUN_FLAGS]);
140 		ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_FLAGS;
141 	}
142 
143 	if (tb[IFLA_IPTUN_FLOWINFO]) {
144 		ip6_tnl->flowinfo = nla_get_u32(tb[IFLA_IPTUN_FLOWINFO]);
145 		ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_FLOWINFO;
146 	}
147 
148 	if (tb[IFLA_IPTUN_PROTO]) {
149 		ip6_tnl->proto = nla_get_u8(tb[IFLA_IPTUN_PROTO]);
150 		ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_PROTO;
151 	}
152 
153 	if (tb[IFLA_IPTUN_FWMARK]) {
154 		ip6_tnl->fwmark = nla_get_u32(tb[IFLA_IPTUN_FWMARK]);
155 		ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_FWMARK;
156 	}
157 
158 	err = 0;
159 
160 errout:
161 	return err;
162 }
163 
ip6_tnl_put_attrs(struct nl_msg * msg,struct rtnl_link * link)164 static int ip6_tnl_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
165 {
166 	struct ip6_tnl_info *ip6_tnl = link->l_info;
167 	struct nlattr *data;
168 
169 	data = nla_nest_start(msg, IFLA_INFO_DATA);
170 	if (!data)
171 		return -NLE_MSGSIZE;
172 
173 	if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_LINK)
174 		NLA_PUT_U32(msg, IFLA_IPTUN_LINK, ip6_tnl->link);
175 
176 	if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_LOCAL)
177 		NLA_PUT(msg, IFLA_IPTUN_LOCAL, sizeof(struct in6_addr), &ip6_tnl->local);
178 
179 	if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_REMOTE)
180 		NLA_PUT(msg, IFLA_IPTUN_REMOTE, sizeof(struct in6_addr), &ip6_tnl->remote);
181 
182 	if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_TTL)
183 		NLA_PUT_U8(msg, IFLA_IPTUN_TTL, ip6_tnl->ttl);
184 
185 	if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_TOS)
186 		NLA_PUT_U8(msg, IFLA_IPTUN_TOS, ip6_tnl->tos);
187 
188 	if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_ENCAPLIMIT)
189 		NLA_PUT_U8(msg, IFLA_IPTUN_ENCAP_LIMIT, ip6_tnl->encap_limit);
190 
191 	if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_FLAGS)
192 		NLA_PUT_U32(msg, IFLA_IPTUN_FLAGS, ip6_tnl->flags);
193 
194 	if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_FLOWINFO)
195 		NLA_PUT_U32(msg, IFLA_IPTUN_FLOWINFO, ip6_tnl->flowinfo);
196 
197 	/* kernel crashes if this attribure is missing  temporary fix */
198 	if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_PROTO)
199 		NLA_PUT_U8(msg, IFLA_IPTUN_PROTO, ip6_tnl->proto);
200 	else
201 		NLA_PUT_U8(msg, IFLA_IPTUN_PROTO, 0);
202 
203 	if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_FWMARK)
204 		NLA_PUT_U32(msg, IFLA_IPTUN_FWMARK, ip6_tnl->fwmark);
205 
206 	nla_nest_end(msg, data);
207 
208 nla_put_failure:
209 	return 0;
210 }
211 
ip6_tnl_free(struct rtnl_link * link)212 static void ip6_tnl_free(struct rtnl_link *link)
213 {
214 	struct ip6_tnl_info *ip6_tnl = link->l_info;
215 
216 	free(ip6_tnl);
217 	link->l_info = NULL;
218 }
219 
ip6_tnl_dump_line(struct rtnl_link * link,struct nl_dump_params * p)220 static void ip6_tnl_dump_line(struct rtnl_link *link, struct nl_dump_params *p)
221 {
222 	nl_dump(p, "ip6_tnl : %s", link->l_name);
223 }
224 
ip6_tnl_dump_details(struct rtnl_link * link,struct nl_dump_params * p)225 static void ip6_tnl_dump_details(struct rtnl_link *link, struct nl_dump_params *p)
226 {
227 	struct ip6_tnl_info *ip6_tnl = link->l_info;
228 	char *name, addr[INET6_ADDRSTRLEN];
229 	struct rtnl_link *parent;
230 
231 	if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_LINK) {
232 		nl_dump(p, "      link ");
233 
234 		name = NULL;
235 		parent = link_lookup(link->ce_cache, ip6_tnl->link);
236 		if (parent)
237 			name = rtnl_link_get_name(parent);
238 
239 		if (name)
240 			nl_dump_line(p, "%s\n", name);
241 		else
242 			nl_dump_line(p, "%u\n", ip6_tnl->link);
243 	}
244 
245 	if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_LOCAL) {
246 		nl_dump(p, "      local ");
247 		nl_dump_line(p, "%s\n",
248 			     _nl_inet_ntop(AF_INET6, &ip6_tnl->local, addr));
249 	}
250 
251 	if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_REMOTE) {
252 		nl_dump(p, "      remote ");
253 		nl_dump_line(p, "%s\n",
254 			     _nl_inet_ntop(AF_INET6, &ip6_tnl->remote, addr));
255 	}
256 
257 	if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_TTL) {
258 		nl_dump(p, "      ttl ");
259 		nl_dump_line(p, "%d\n", ip6_tnl->ttl);
260 	}
261 
262 	if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_TOS) {
263 		nl_dump(p, "      tos ");
264 		nl_dump_line(p, "%d\n", ip6_tnl->tos);
265 	}
266 
267 	if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_ENCAPLIMIT) {
268 		nl_dump(p, "      encaplimit ");
269 		nl_dump_line(p, "%d\n", ip6_tnl->encap_limit);
270 	}
271 
272 	if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_FLAGS) {
273 		nl_dump(p, "      flags ");
274 		nl_dump_line(p, " (%x)\n", ip6_tnl->flags);
275 	}
276 
277 	if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_FLOWINFO) {
278 		nl_dump(p, "      flowinfo ");
279 		nl_dump_line(p, " (%x)\n", ip6_tnl->flowinfo);
280 	}
281 
282 	if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_PROTO) {
283 		nl_dump(p, "    proto   ");
284 		nl_dump_line(p, " (%x)\n", ip6_tnl->proto);
285 	}
286 
287 	if (ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_FWMARK) {
288 		nl_dump(p, "      fwmark ");
289 		nl_dump_line(p, "%x\n", ip6_tnl->fwmark);
290 	}
291 }
292 
ip6_tnl_clone(struct rtnl_link * dst,struct rtnl_link * src)293 static int ip6_tnl_clone(struct rtnl_link *dst, struct rtnl_link *src)
294 {
295 	struct ip6_tnl_info *ip6_tnl_dst, *ip6_tnl_src = src->l_info;
296 	int err;
297 
298 	dst->l_info = NULL;
299 
300 	err = rtnl_link_set_type(dst, "ip6tnl");
301 	if (err < 0)
302 		return err;
303 
304 	ip6_tnl_dst = dst->l_info;
305 
306 	if (!ip6_tnl_dst || !ip6_tnl_src)
307 		BUG();
308 
309 	memcpy(ip6_tnl_dst, ip6_tnl_src, sizeof(struct ip6_tnl_info));
310 
311 	return 0;
312 }
313 
314 static struct rtnl_link_info_ops ip6_tnl_info_ops = {
315 	.io_name                = "ip6tnl",
316 	.io_alloc               = ip6_tnl_alloc,
317 	.io_parse               = ip6_tnl_parse,
318 	.io_dump = {
319 		[NL_DUMP_LINE]  = ip6_tnl_dump_line,
320 		[NL_DUMP_DETAILS] = ip6_tnl_dump_details,
321 	},
322 	.io_clone               = ip6_tnl_clone,
323 	.io_put_attrs           = ip6_tnl_put_attrs,
324 	.io_free                = ip6_tnl_free,
325 };
326 
327 #define IS_IP6_TNL_LINK_ASSERT(link)\
328 	if ((link)->l_info_ops != &ip6_tnl_info_ops) {\
329 		APPBUG("Link is not a ip6_tnl link. set type \"ip6tnl\" first.");\
330 		return -NLE_OPNOTSUPP;\
331 	}
332 
rtnl_link_ip6_tnl_alloc(void)333 struct rtnl_link *rtnl_link_ip6_tnl_alloc(void)
334 {
335 	struct rtnl_link *link;
336 	int err;
337 
338 	link = rtnl_link_alloc();
339 	if (!link)
340 		return NULL;
341 
342 	err = rtnl_link_set_type(link, "ip6tnl");
343 	if (err < 0) {
344 		rtnl_link_put(link);
345 		return NULL;
346 	}
347 
348 	return link;
349 }
350 
351 /**
352  * Check if link is a IP6_TNL link
353  * @arg link            Link object
354  *
355  * @return True if link is a IP6_TNL link, otherwise false is returned.
356  */
rtnl_link_is_ip6_tnl(struct rtnl_link * link)357 int rtnl_link_is_ip6_tnl(struct rtnl_link *link)
358 {
359 	return link->l_info_ops && !strcmp(link->l_info_ops->io_name, "ip6tnl");
360 }
361 
362 /**
363  * Create a new ip6_tnl tunnel device
364  * @arg sock            netlink socket
365  * @arg name            name of the tunnel device
366  *
367  * Creates a new ip6_tnl tunnel device in the kernel
368  * @return 0 on success or a negative error code
369  */
rtnl_link_ip6_tnl_add(struct nl_sock * sk,const char * name)370 int rtnl_link_ip6_tnl_add(struct nl_sock *sk, const char *name)
371 {
372 	struct rtnl_link *link;
373 	int err;
374 
375 	link = rtnl_link_ip6_tnl_alloc();
376 	if (!link)
377 		return -NLE_NOMEM;
378 
379 	if(name)
380 		rtnl_link_set_name(link, name);
381 
382 	err = rtnl_link_add(sk, link, NLM_F_CREATE);
383 	rtnl_link_put(link);
384 
385 	return err;
386 }
387 
388 /**
389  * Set IP6_TNL tunnel interface index
390  * @arg link            Link object
391  * @arg index           interface index
392  *
393  * @return 0 on success or a negative error code
394  */
rtnl_link_ip6_tnl_set_link(struct rtnl_link * link,uint32_t index)395 int rtnl_link_ip6_tnl_set_link(struct rtnl_link *link, uint32_t index)
396 {
397 	struct ip6_tnl_info *ip6_tnl = link->l_info;
398 
399 	IS_IP6_TNL_LINK_ASSERT(link);
400 
401 	ip6_tnl->link = index;
402 	ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_LINK;
403 
404 	return 0;
405 }
406 
407 /**
408  * Get IP6_TNL tunnel interface index
409  * @arg link            Link object
410  *
411  * @return interface index value
412  */
rtnl_link_ip6_tnl_get_link(struct rtnl_link * link)413 uint32_t rtnl_link_ip6_tnl_get_link(struct rtnl_link *link)
414 {
415 	struct ip6_tnl_info *ip6_tnl = link->l_info;
416 
417 	IS_IP6_TNL_LINK_ASSERT(link);
418 
419 	return ip6_tnl->link;
420 }
421 
422 /**
423  * Set IP6_TNL tunnel local address
424  * @arg link            Link object
425  * @arg addr            local address
426  *
427  * @return 0 on success or a negative error code
428  */
rtnl_link_ip6_tnl_set_local(struct rtnl_link * link,struct in6_addr * addr)429 int rtnl_link_ip6_tnl_set_local(struct rtnl_link *link, struct in6_addr *addr)
430 {
431 	struct ip6_tnl_info *ip6_tnl = link->l_info;
432 
433 	IS_IP6_TNL_LINK_ASSERT(link);
434 
435 	memcpy(&ip6_tnl->local, addr, sizeof(struct in6_addr));
436 	ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_LOCAL;
437 
438 	return 0;
439 }
440 
441 /**
442  * Get IP6_TNL tunnel local address
443  * @arg link            Link object
444  *
445  * @return 0 on success or a negative error code
446  */
rtnl_link_ip6_tnl_get_local(struct rtnl_link * link,struct in6_addr * addr)447 int rtnl_link_ip6_tnl_get_local(struct rtnl_link *link, struct in6_addr *addr)
448 {
449 	struct ip6_tnl_info *ip6_tnl = link->l_info;
450 
451 	IS_IP6_TNL_LINK_ASSERT(link);
452 
453 	memcpy(addr, &ip6_tnl->local, sizeof(struct in6_addr));
454 
455 	return 0;
456 }
457 
458 /**
459  * Set IP6_TNL tunnel remote address
460  * @arg link            Link object
461  * @arg remote          remote address
462  *
463  * @return 0 on success or a negative error code
464  */
rtnl_link_ip6_tnl_set_remote(struct rtnl_link * link,struct in6_addr * addr)465 int rtnl_link_ip6_tnl_set_remote(struct rtnl_link *link, struct in6_addr *addr)
466 {
467 	struct ip6_tnl_info *ip6_tnl = link->l_info;
468 
469 	IS_IP6_TNL_LINK_ASSERT(link);
470 
471 	memcpy(&ip6_tnl->remote, addr, sizeof(struct in6_addr));
472 	ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_REMOTE;
473 
474 	return 0;
475 }
476 
477 /**
478  * Get IP6_TNL tunnel remote address
479  * @arg link            Link object
480  *
481  * @return 0 on success or a negative error code
482  */
rtnl_link_ip6_tnl_get_remote(struct rtnl_link * link,struct in6_addr * addr)483 int rtnl_link_ip6_tnl_get_remote(struct rtnl_link *link, struct in6_addr *addr)
484 {
485 	struct ip6_tnl_info *ip6_tnl = link->l_info;
486 
487 	IS_IP6_TNL_LINK_ASSERT(link);
488 
489 	memcpy(addr, &ip6_tnl->remote, sizeof(struct in6_addr));
490 
491 	return 0;
492 }
493 
494 /**
495  * Set IP6_TNL tunnel ttl
496  * @arg link            Link object
497  * @arg ttl             tunnel ttl
498  *
499  * @return 0 on success or a negative error code
500  */
rtnl_link_ip6_tnl_set_ttl(struct rtnl_link * link,uint8_t ttl)501 int rtnl_link_ip6_tnl_set_ttl(struct rtnl_link *link, uint8_t ttl)
502 {
503 	struct ip6_tnl_info *ip6_tnl = link->l_info;
504 
505 	IS_IP6_TNL_LINK_ASSERT(link);
506 
507 	ip6_tnl->ttl = ttl;
508 	ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_TTL;
509 
510 	return 0;
511 }
512 
513 /**
514  * Get IP6_TNL tunnel ttl
515  * @arg link            Link object
516  *
517  * @return ttl value
518  */
rtnl_link_ip6_tnl_get_ttl(struct rtnl_link * link)519 uint8_t rtnl_link_ip6_tnl_get_ttl(struct rtnl_link *link)
520 {
521 	struct ip6_tnl_info *ip6_tnl = link->l_info;
522 
523 	IS_IP6_TNL_LINK_ASSERT(link);
524 
525 	return ip6_tnl->ttl;
526 }
527 
528 /**
529  * Set IP6_TNL tunnel tos
530  * @arg link            Link object
531  * @arg tos             tunnel tos
532  *
533  * @return 0 on success or a negative error code
534  */
rtnl_link_ip6_tnl_set_tos(struct rtnl_link * link,uint8_t tos)535 int rtnl_link_ip6_tnl_set_tos(struct rtnl_link *link, uint8_t tos)
536 {
537 	struct ip6_tnl_info *ip6_tnl = link->l_info;
538 
539 	IS_IP6_TNL_LINK_ASSERT(link);
540 
541 	ip6_tnl->tos = tos;
542 	ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_TOS;
543 
544 	return 0;
545 }
546 
547 /**
548  * Get IP6_TNL tunnel tos
549  * @arg link            Link object
550  *
551  * @return tos value
552  */
rtnl_link_ip6_tnl_get_tos(struct rtnl_link * link)553 uint8_t rtnl_link_ip6_tnl_get_tos(struct rtnl_link *link)
554 {
555 	struct ip6_tnl_info *ip6_tnl = link->l_info;
556 
557 	IS_IP6_TNL_LINK_ASSERT(link);
558 
559 	return ip6_tnl->tos;
560 }
561 
562 /**
563  * Set IP6_TNL tunnel encap limit
564  * @arg link            Link object
565  * @arg encap_limit     encaplimit value
566  *
567  * @return 0 on success or a negative error code
568  */
rtnl_link_ip6_tnl_set_encaplimit(struct rtnl_link * link,uint8_t encap_limit)569 int rtnl_link_ip6_tnl_set_encaplimit(struct rtnl_link *link, uint8_t encap_limit)
570 {
571 	struct ip6_tnl_info *ip6_tnl = link->l_info;
572 
573 	IS_IP6_TNL_LINK_ASSERT(link);
574 
575 	ip6_tnl->encap_limit = encap_limit;
576 	ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_ENCAPLIMIT;
577 
578 	return 0;
579 }
580 
581 /**
582  * Get IP6_TNL encaplimit
583  * @arg link            Link object
584  *
585  * @return encaplimit value
586  */
rtnl_link_ip6_tnl_get_encaplimit(struct rtnl_link * link)587 uint8_t rtnl_link_ip6_tnl_get_encaplimit(struct rtnl_link *link)
588 {
589 	struct ip6_tnl_info *ip6_tnl = link->l_info;
590 
591 	IS_IP6_TNL_LINK_ASSERT(link);
592 
593 	return ip6_tnl->encap_limit;
594 }
595 
596 /**
597  * Set IP6_TNL tunnel flowinfo
598  * @arg link            Link object
599  * @arg flowinfo        flowinfo value
600  *
601  * @return 0 on success or a negative error code
602  */
rtnl_link_ip6_tnl_set_flowinfo(struct rtnl_link * link,uint32_t flowinfo)603 int rtnl_link_ip6_tnl_set_flowinfo(struct rtnl_link *link, uint32_t flowinfo)
604 {
605 	struct ip6_tnl_info *ip6_tnl = link->l_info;
606 
607 	IS_IP6_TNL_LINK_ASSERT(link);
608 
609 	ip6_tnl->flowinfo = flowinfo;
610 	ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_FLOWINFO;
611 
612 	return 0;
613 }
614 
615 /**
616  * Get IP6_TNL flowinfo
617  * @arg link            Link object
618  *
619  * @return flowinfo value
620  */
rtnl_link_ip6_tnl_get_flowinfo(struct rtnl_link * link)621 uint32_t rtnl_link_ip6_tnl_get_flowinfo(struct rtnl_link *link)
622 {
623 	struct ip6_tnl_info *ip6_tnl = link->l_info;
624 
625 	IS_IP6_TNL_LINK_ASSERT(link);
626 
627 	return ip6_tnl->flowinfo;
628 }
629 
630 /**
631  * Set IP6_TNL tunnel flags
632  * @arg link            Link object
633  * @arg flags           tunnel flags
634  *
635  * @return 0 on success or a negative error code
636  */
rtnl_link_ip6_tnl_set_flags(struct rtnl_link * link,uint32_t flags)637 int rtnl_link_ip6_tnl_set_flags(struct rtnl_link *link, uint32_t flags)
638 {
639 	struct ip6_tnl_info *ip6_tnl = link->l_info;
640 
641 	IS_IP6_TNL_LINK_ASSERT(link);
642 
643 	ip6_tnl->flags = flags;
644 	ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_FLAGS;
645 
646 	return 0;
647 }
648 
649 /**
650  * Get IP6_TNL path flags
651  * @arg link            Link object
652  *
653  * @return flags value
654  */
rtnl_link_ip6_tnl_get_flags(struct rtnl_link * link)655 uint32_t rtnl_link_ip6_tnl_get_flags(struct rtnl_link *link)
656 {
657 	struct ip6_tnl_info *ip6_tnl = link->l_info;
658 
659 	IS_IP6_TNL_LINK_ASSERT(link);
660 
661 	return ip6_tnl->flags;
662 }
663 
664 /**
665  * Set IP6_TNL tunnel proto
666  * @arg link            Link object
667  * @arg proto           tunnel proto
668  *
669  * @return 0 on success or a negative error code
670  */
rtnl_link_ip6_tnl_set_proto(struct rtnl_link * link,uint8_t proto)671 int rtnl_link_ip6_tnl_set_proto(struct rtnl_link *link, uint8_t proto)
672 {
673 	struct ip6_tnl_info *ip6_tnl = link->l_info;
674 
675 	IS_IP6_TNL_LINK_ASSERT(link);
676 
677 	ip6_tnl->proto = proto;
678 	ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_PROTO;
679 
680 	return 0;
681 }
682 
683 /**
684  * Get IP6_TNL proto
685  * @arg link            Link object
686  *
687  * @return proto value
688  */
rtnl_link_ip6_tnl_get_proto(struct rtnl_link * link)689 uint8_t rtnl_link_ip6_tnl_get_proto(struct rtnl_link *link)
690 {
691 	struct ip6_tnl_info *ip6_tnl = link->l_info;
692 
693 	IS_IP6_TNL_LINK_ASSERT(link);
694 
695 	return ip6_tnl->proto;
696 }
697 
698 /**
699  * Set IP6_TNL tunnel fwmark
700  * @arg link            Link object
701  * @arg fwmark          fwmark
702  *
703  * @return 0 on success or a negative error code
704  */
rtnl_link_ip6_tnl_set_fwmark(struct rtnl_link * link,uint32_t fwmark)705 int rtnl_link_ip6_tnl_set_fwmark(struct rtnl_link *link, uint32_t fwmark)
706 {
707 	struct ip6_tnl_info *ip6_tnl = link->l_info;
708 
709 	IS_IP6_TNL_LINK_ASSERT(link);
710 
711 	ip6_tnl->fwmark = fwmark;
712 	ip6_tnl->ip6_tnl_mask |= IP6_TNL_ATTR_FWMARK;
713 
714 	return 0;
715 }
716 
717 /**
718  * Get IP6_TNL tunnel fwmark
719  * @arg link            Link object
720  * @arg fwmark          addr to fill in with the fwmark
721  *
722  * @return 0 on success or a negative error code
723  */
rtnl_link_ip6_tnl_get_fwmark(struct rtnl_link * link,uint32_t * fwmark)724 int rtnl_link_ip6_tnl_get_fwmark(struct rtnl_link *link, uint32_t *fwmark)
725 {
726 	struct ip6_tnl_info *ip6_tnl = link->l_info;
727 
728 	IS_IP6_TNL_LINK_ASSERT(link);
729 
730 	if (!(ip6_tnl->ip6_tnl_mask & IP6_TNL_ATTR_FWMARK))
731 		return -NLE_NOATTR;
732 
733 	*fwmark = ip6_tnl->fwmark;
734 
735 	return 0;
736 }
737 
ip6_tnl_init(void)738 static void _nl_init ip6_tnl_init(void)
739 {
740 	rtnl_link_register_info(&ip6_tnl_info_ops);
741 }
742 
ip6_tnl_exit(void)743 static void _nl_exit ip6_tnl_exit(void)
744 {
745 	rtnl_link_unregister_info(&ip6_tnl_info_ops);
746 }
747