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