xref: /aosp_15_r20/external/libnl/lib/route/link/inet.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2010 Thomas Graf <[email protected]>
4  */
5 
6 /**
7  * @ingroup link_API
8  * @defgroup link_inet IPv4 Link Module
9  * @brief Implementation of IPv4 specific link attributes
10  *
11  *
12  *
13  * @par Example: Reading the value of IPV4_DEVCONF_FORWARDING
14  * @code
15  * struct nl_cache *cache;
16  * struct rtnl_link *link;
17  * uint32_t value;
18  *
19  * // Allocate a link cache
20  * rtnl_link_alloc_cache(sock, AF_UNSPEC, &cache);
21  *
22  * // Search for the link we wish to see the value from
23  * link = rtnl_link_get_by_name(cache, "eth0");
24  *
25  * // Read the value of the setting IPV4_DEVCONF_FORWARDING
26  * if (rtnl_link_inet_get_conf(link, IPV4_DEVCONF_FORWARDING, &value) < 0)
27  *         // Error: Unable to read config setting
28  *
29  * printf("forwarding is %s\n", value ? "enabled" : "disabled");
30  * @endcode
31  *
32  * @par Example: Changing the value of IPV4_DEVCONF_FOWARDING
33  * @code
34  * //
35  * // ... Continueing from the previous example ...
36  * //
37  *
38  * struct rtnl_link *new;
39  *
40  * // Allocate a new link to store the changes we wish to make.
41  * new = rtnl_link_alloc();
42  *
43  * // Set IPV4_DEVCONF_FORWARDING to '1'
44  * rtnl_link_inet_set_conf(new, IPV4_DEVCONF_FORWARDING, 1);
45  *
46  * // Send the change request to the kernel.
47  * rtnl_link_change(sock, link, new, 0);
48  * @endcode
49  *
50  * @{
51  */
52 
53 
54 #include "nl-default.h"
55 
56 #include <linux/ip.h>
57 
58 #include <netlink/netlink.h>
59 #include <netlink/attr.h>
60 #include <netlink/route/rtnl.h>
61 #include <netlink/route/link/inet.h>
62 
63 #include "link-api.h"
64 
65 /** @cond SKIP */
66 struct inet_data
67 {
68 	uint8_t			i_confset[IPV4_DEVCONF_MAX];
69 	uint32_t		i_conf[IPV4_DEVCONF_MAX];
70 };
71 /** @endcond */
72 
inet_alloc(struct rtnl_link * link)73 static void *inet_alloc(struct rtnl_link *link)
74 {
75 	return calloc(1, sizeof(struct inet_data));
76 }
77 
inet_clone(struct rtnl_link * link,void * data)78 static void *inet_clone(struct rtnl_link *link, void *data)
79 {
80 	struct inet_data *id;
81 
82 	if ((id = inet_alloc(link)))
83 		memcpy(id, data, sizeof(*id));
84 
85 	return id;
86 }
87 
inet_free(struct rtnl_link * link,void * data)88 static void inet_free(struct rtnl_link *link, void *data)
89 {
90 	free(data);
91 }
92 
93 static struct nla_policy inet_policy[IFLA_INET_MAX+1] = {
94 	[IFLA_INET_CONF]	= { .minlen = 4 },
95 };
96 
inet_parse_af(struct rtnl_link * link,struct nlattr * attr,void * data)97 static int inet_parse_af(struct rtnl_link *link, struct nlattr *attr, void *data)
98 {
99 	struct inet_data *id = data;
100 	struct nlattr *tb[IFLA_INET_MAX+1];
101 	int err;
102 
103 	err = nla_parse_nested(tb, IFLA_INET_MAX, attr, inet_policy);
104 	if (err < 0)
105 		return err;
106 	if (tb[IFLA_INET_CONF] && nla_len(tb[IFLA_INET_CONF]) % 4)
107 		return -EINVAL;
108 
109 	if (tb[IFLA_INET_CONF]) {
110 		int i;
111 		int len = _NL_MIN(IPV4_DEVCONF_MAX, nla_len(tb[IFLA_INET_CONF]) / 4);
112 
113 		for (i = 0; i < len; i++)
114 			id->i_confset[i] = 1;
115 		nla_memcpy(&id->i_conf, tb[IFLA_INET_CONF], sizeof(id->i_conf));
116 	}
117 
118 	return 0;
119 }
120 
inet_fill_af(struct rtnl_link * link,struct nl_msg * msg,void * data)121 static int inet_fill_af(struct rtnl_link *link, struct nl_msg *msg, void *data)
122 {
123 	struct inet_data *id = data;
124 	struct nlattr *nla;
125 	int i;
126 
127 	if (!(nla = nla_nest_start(msg, IFLA_INET_CONF)))
128 		return -NLE_MSGSIZE;
129 
130 	for (i = 0; i < IPV4_DEVCONF_MAX; i++)
131 		if (id->i_confset[i])
132 			NLA_PUT_U32(msg, i+1, id->i_conf[i]);
133 
134 	nla_nest_end(msg, nla);
135 
136 	return 0;
137 
138 nla_put_failure:
139 	return -NLE_MSGSIZE;
140 }
141 
142 static const struct trans_tbl inet_devconf[] = {
143 	__ADD(IPV4_DEVCONF_FORWARDING, forwarding),
144 	__ADD(IPV4_DEVCONF_MC_FORWARDING, mc_forwarding),
145 	__ADD(IPV4_DEVCONF_PROXY_ARP, proxy_arp),
146 	__ADD(IPV4_DEVCONF_ACCEPT_REDIRECTS, accept_redirects),
147 	__ADD(IPV4_DEVCONF_SECURE_REDIRECTS, secure_redirects),
148 	__ADD(IPV4_DEVCONF_SEND_REDIRECTS, send_redirects),
149 	__ADD(IPV4_DEVCONF_SHARED_MEDIA, shared_media),
150 	__ADD(IPV4_DEVCONF_RP_FILTER, rp_filter),
151 	__ADD(IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE, accept_source_route),
152 	__ADD(IPV4_DEVCONF_BOOTP_RELAY, bootp_relay),
153 	__ADD(IPV4_DEVCONF_LOG_MARTIANS, log_martians),
154 	__ADD(IPV4_DEVCONF_TAG, tag),
155 	__ADD(IPV4_DEVCONF_ARPFILTER, arpfilter),
156 	__ADD(IPV4_DEVCONF_MEDIUM_ID, medium_id),
157 	__ADD(IPV4_DEVCONF_NOXFRM, noxfrm),
158 	__ADD(IPV4_DEVCONF_NOPOLICY, nopolicy),
159 	__ADD(IPV4_DEVCONF_FORCE_IGMP_VERSION, force_igmp_version),
160 	__ADD(IPV4_DEVCONF_ARP_ANNOUNCE, arp_announce),
161 	__ADD(IPV4_DEVCONF_ARP_IGNORE, arp_ignore),
162 	__ADD(IPV4_DEVCONF_PROMOTE_SECONDARIES, promote_secondaries),
163 	__ADD(IPV4_DEVCONF_ARP_ACCEPT, arp_accept),
164 	__ADD(IPV4_DEVCONF_ARP_NOTIFY, arp_notify),
165 	__ADD(IPV4_DEVCONF_ACCEPT_LOCAL, accept_local),
166 	__ADD(IPV4_DEVCONF_SRC_VMARK, src_vmark),
167 	__ADD(IPV4_DEVCONF_PROXY_ARP_PVLAN, proxy_arp_pvlan),
168 	__ADD(IPV4_DEVCONF_ROUTE_LOCALNET, route_localnet),
169 	__ADD(IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL, igmpv2_unsolicited_report_interval),
170 	__ADD(IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL, igmpv3_unsolicited_report_interval),
171 };
172 
rtnl_link_inet_devconf2str(int type,char * buf,size_t len)173 const char *rtnl_link_inet_devconf2str(int type, char *buf, size_t len)
174 {
175 	return __type2str(type, buf, len, inet_devconf,
176 			  ARRAY_SIZE(inet_devconf));
177 }
178 
rtnl_link_inet_str2devconf(const char * name)179 int rtnl_link_inet_str2devconf(const char *name)
180 {
181 	return __str2type(name, inet_devconf, ARRAY_SIZE(inet_devconf));
182 }
183 
inet_dump_details(struct rtnl_link * link,struct nl_dump_params * p,void * data)184 static void inet_dump_details(struct rtnl_link *link,
185 			      struct nl_dump_params *p, void *data)
186 {
187 	struct inet_data *id = data;
188 	char buf[64];
189 	int i, n = 0;
190 
191 	nl_dump_line(p, "    ipv4 devconf:\n");
192 	nl_dump_line(p, "      ");
193 
194 	for (i = 0; i < IPV4_DEVCONF_MAX; i++) {
195 		nl_dump_line(p, "%-19s %3u",
196 			rtnl_link_inet_devconf2str(i+1, buf, sizeof(buf)),
197 			id->i_confset[i] ? id->i_conf[i] : 0);
198 
199 		if (++n == 3) {
200 			nl_dump(p, "\n");
201 			nl_dump_line(p, "      ");
202 			n = 0;
203 		} else
204 			nl_dump(p, "  ");
205 	}
206 
207 	if (n != 0)
208 		nl_dump(p, "\n");
209 }
210 
211 static struct rtnl_link_af_ops inet_ops = {
212 	.ao_family			= AF_INET,
213 	.ao_alloc			= &inet_alloc,
214 	.ao_clone			= &inet_clone,
215 	.ao_free			= &inet_free,
216 	.ao_parse_af			= &inet_parse_af,
217 	.ao_fill_af			= &inet_fill_af,
218 	.ao_dump[NL_DUMP_DETAILS]	= &inet_dump_details,
219 };
220 
221 /**
222  * Get value of a ipv4 link configuration setting
223  * @arg link		Link object
224  * @arg cfgid		Configuration identifier
225  * @arg res		Result pointer
226  *
227  * Stores the value of the specified configuration setting in the provided
228  * result pointer.
229  *
230  * @return 0 on success or a negative error code.
231  * @return -NLE_RANGE cfgid is out of range, 1..IPV4_DEVCONF_MAX
232  * @return -NLE_NOATTR configuration setting not available
233  * @return -NLE_INVAL cfgid not set. If the link was received via netlink,
234  *                    it means that the cfgid is not supported.
235  */
rtnl_link_inet_get_conf(struct rtnl_link * link,const unsigned int cfgid,uint32_t * res)236 int rtnl_link_inet_get_conf(struct rtnl_link *link, const unsigned int cfgid,
237 			    uint32_t *res)
238 {
239 	struct inet_data *id;
240 
241 	if (cfgid == 0 || cfgid > IPV4_DEVCONF_MAX)
242 		return -NLE_RANGE;
243 
244 	if (!(id = rtnl_link_af_data(link, &inet_ops)))
245 		return -NLE_NOATTR;
246 
247 	if (!id->i_confset[cfgid - 1])
248 		return -NLE_INVAL;
249 	*res = id->i_conf[cfgid - 1];
250 
251 	return 0;
252 }
253 
254 /**
255  * Change value of a ipv4 link configuration setting
256  * @arg link		Link object
257  * @arg cfgid		Configuration identifier
258  * @arg value		New value
259  *
260  * Changes the value in the per link ipv4 configuration array.
261  *
262  * @return 0 on success or a negative error code.
263  * @return -NLE_RANGE cfgid is out of range, 1..IPV4_DEVCONF_MAX
264  * @return -NLE_NOMEM memory allocation failed
265  */
rtnl_link_inet_set_conf(struct rtnl_link * link,const unsigned int cfgid,uint32_t value)266 int rtnl_link_inet_set_conf(struct rtnl_link *link, const unsigned int cfgid,
267 			    uint32_t value)
268 {
269 	struct inet_data *id;
270 
271 	if (!(id = rtnl_link_af_alloc(link, &inet_ops)))
272 		return -NLE_NOMEM;
273 
274 	if (cfgid == 0 || cfgid > IPV4_DEVCONF_MAX)
275 		return -NLE_RANGE;
276 
277 	id->i_confset[cfgid - 1] = 1;
278 	id->i_conf[cfgid - 1] = value;
279 
280 	return 0;
281 }
282 
283 
inet_init(void)284 static void _nl_init inet_init(void)
285 {
286 	rtnl_link_af_register(&inet_ops);
287 }
288 
inet_exit(void)289 static void _nl_exit inet_exit(void)
290 {
291 	rtnl_link_af_unregister(&inet_ops);
292 }
293 
294 /** @} */
295