libnl  3.6.0
inet.c
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2010 Thomas Graf <tgraf@suug.ch>
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 <netlink-private/netlink.h>
55 #include <netlink/netlink.h>
56 #include <netlink/attr.h>
57 #include <netlink/route/rtnl.h>
58 #include <netlink/route/link/inet.h>
59 #include <netlink-private/route/link/api.h>
60 
61 /** @cond SKIP */
62 struct inet_data
63 {
64  uint8_t i_confset[IPV4_DEVCONF_MAX];
65  uint32_t i_conf[IPV4_DEVCONF_MAX];
66 };
67 /** @endcond */
68 
69 static void *inet_alloc(struct rtnl_link *link)
70 {
71  return calloc(1, sizeof(struct inet_data));
72 }
73 
74 static void *inet_clone(struct rtnl_link *link, void *data)
75 {
76  struct inet_data *id;
77 
78  if ((id = inet_alloc(link)))
79  memcpy(id, data, sizeof(*id));
80 
81  return id;
82 }
83 
84 static void inet_free(struct rtnl_link *link, void *data)
85 {
86  free(data);
87 }
88 
89 static struct nla_policy inet_policy[IFLA_INET_MAX+1] = {
90  [IFLA_INET_CONF] = { .minlen = 4 },
91 };
92 
93 static int inet_parse_af(struct rtnl_link *link, struct nlattr *attr, void *data)
94 {
95  struct inet_data *id = data;
96  struct nlattr *tb[IFLA_INET_MAX+1];
97  int err;
98 
99  err = nla_parse_nested(tb, IFLA_INET_MAX, attr, inet_policy);
100  if (err < 0)
101  return err;
102  if (tb[IFLA_INET_CONF] && nla_len(tb[IFLA_INET_CONF]) % 4)
103  return -EINVAL;
104 
105  if (tb[IFLA_INET_CONF]) {
106  int i;
107  int len = min_t(int, IPV4_DEVCONF_MAX, nla_len(tb[IFLA_INET_CONF]) / 4);
108 
109  for (i = 0; i < len; i++)
110  id->i_confset[i] = 1;
111  nla_memcpy(&id->i_conf, tb[IFLA_INET_CONF], sizeof(id->i_conf));
112  }
113 
114  return 0;
115 }
116 
117 static int inet_fill_af(struct rtnl_link *link, struct nl_msg *msg, void *data)
118 {
119  struct inet_data *id = data;
120  struct nlattr *nla;
121  int i;
122 
123  if (!(nla = nla_nest_start(msg, IFLA_INET_CONF)))
124  return -NLE_MSGSIZE;
125 
126  for (i = 0; i < IPV4_DEVCONF_MAX; i++)
127  if (id->i_confset[i])
128  NLA_PUT_U32(msg, i+1, id->i_conf[i]);
129 
130  nla_nest_end(msg, nla);
131 
132  return 0;
133 
134 nla_put_failure:
135  return -NLE_MSGSIZE;
136 }
137 
138 static const struct trans_tbl inet_devconf[] = {
139  __ADD(IPV4_DEVCONF_FORWARDING, forwarding),
140  __ADD(IPV4_DEVCONF_MC_FORWARDING, mc_forwarding),
141  __ADD(IPV4_DEVCONF_PROXY_ARP, proxy_arp),
142  __ADD(IPV4_DEVCONF_ACCEPT_REDIRECTS, accept_redirects),
143  __ADD(IPV4_DEVCONF_SECURE_REDIRECTS, secure_redirects),
144  __ADD(IPV4_DEVCONF_SEND_REDIRECTS, send_redirects),
145  __ADD(IPV4_DEVCONF_SHARED_MEDIA, shared_media),
146  __ADD(IPV4_DEVCONF_RP_FILTER, rp_filter),
147  __ADD(IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE, accept_source_route),
148  __ADD(IPV4_DEVCONF_BOOTP_RELAY, bootp_relay),
149  __ADD(IPV4_DEVCONF_LOG_MARTIANS, log_martians),
150  __ADD(IPV4_DEVCONF_TAG, tag),
151  __ADD(IPV4_DEVCONF_ARPFILTER, arpfilter),
152  __ADD(IPV4_DEVCONF_MEDIUM_ID, medium_id),
153  __ADD(IPV4_DEVCONF_NOXFRM, noxfrm),
154  __ADD(IPV4_DEVCONF_NOPOLICY, nopolicy),
155  __ADD(IPV4_DEVCONF_FORCE_IGMP_VERSION, force_igmp_version),
156  __ADD(IPV4_DEVCONF_ARP_ANNOUNCE, arp_announce),
157  __ADD(IPV4_DEVCONF_ARP_IGNORE, arp_ignore),
158  __ADD(IPV4_DEVCONF_PROMOTE_SECONDARIES, promote_secondaries),
159  __ADD(IPV4_DEVCONF_ARP_ACCEPT, arp_accept),
160  __ADD(IPV4_DEVCONF_ARP_NOTIFY, arp_notify),
161  __ADD(IPV4_DEVCONF_ACCEPT_LOCAL, accept_local),
162  __ADD(IPV4_DEVCONF_SRC_VMARK, src_vmark),
163  __ADD(IPV4_DEVCONF_PROXY_ARP_PVLAN, proxy_arp_pvlan),
164  __ADD(IPV4_DEVCONF_ROUTE_LOCALNET, route_localnet),
165  __ADD(IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL, igmpv2_unsolicited_report_interval),
166  __ADD(IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL, igmpv3_unsolicited_report_interval),
167 };
168 
169 const char *rtnl_link_inet_devconf2str(int type, char *buf, size_t len)
170 {
171  return __type2str(type, buf, len, inet_devconf,
172  ARRAY_SIZE(inet_devconf));
173 }
174 
175 int rtnl_link_inet_str2devconf(const char *name)
176 {
177  return __str2type(name, inet_devconf, ARRAY_SIZE(inet_devconf));
178 }
179 
180 static void inet_dump_details(struct rtnl_link *link,
181  struct nl_dump_params *p, void *data)
182 {
183  struct inet_data *id = data;
184  char buf[64];
185  int i, n = 0;
186 
187  nl_dump_line(p, " ipv4 devconf:\n");
188  nl_dump_line(p, " ");
189 
190  for (i = 0; i < IPV4_DEVCONF_MAX; i++) {
191  nl_dump_line(p, "%-19s %3u",
192  rtnl_link_inet_devconf2str(i+1, buf, sizeof(buf)),
193  id->i_confset[i] ? id->i_conf[i] : 0);
194 
195  if (++n == 3) {
196  nl_dump(p, "\n");
197  nl_dump_line(p, " ");
198  n = 0;
199  } else
200  nl_dump(p, " ");
201  }
202 
203  if (n != 0)
204  nl_dump(p, "\n");
205 }
206 
207 static struct rtnl_link_af_ops inet_ops = {
208  .ao_family = AF_INET,
209  .ao_alloc = &inet_alloc,
210  .ao_clone = &inet_clone,
211  .ao_free = &inet_free,
212  .ao_parse_af = &inet_parse_af,
213  .ao_fill_af = &inet_fill_af,
214  .ao_dump[NL_DUMP_DETAILS] = &inet_dump_details,
215 };
216 
217 /**
218  * Get value of a ipv4 link configuration setting
219  * @arg link Link object
220  * @arg cfgid Configuration identifier
221  * @arg res Result pointer
222  *
223  * Stores the value of the specified configuration setting in the provided
224  * result pointer.
225  *
226  * @return 0 on success or a negative error code.
227  * @return -NLE_RANGE cfgid is out of range, 1..IPV4_DEVCONF_MAX
228  * @return -NLE_NOATTR configuration setting not available
229  * @return -NLE_INVAL cfgid not set. If the link was received via netlink,
230  * it means that the cfgid is not supported.
231  */
232 int rtnl_link_inet_get_conf(struct rtnl_link *link, const unsigned int cfgid,
233  uint32_t *res)
234 {
235  struct inet_data *id;
236 
237  if (cfgid == 0 || cfgid > IPV4_DEVCONF_MAX)
238  return -NLE_RANGE;
239 
240  if (!(id = rtnl_link_af_data(link, &inet_ops)))
241  return -NLE_NOATTR;
242 
243  if (!id->i_confset[cfgid - 1])
244  return -NLE_INVAL;
245  *res = id->i_conf[cfgid - 1];
246 
247  return 0;
248 }
249 
250 /**
251  * Change value of a ipv4 link configuration setting
252  * @arg link Link object
253  * @arg cfgid Configuration identifier
254  * @arg value New value
255  *
256  * Changes the value in the per link ipv4 configuration array.
257  *
258  * @return 0 on success or a negative error code.
259  * @return -NLE_RANGE cfgid is out of range, 1..IPV4_DEVCONF_MAX
260  * @return -NLE_NOMEM memory allocation failed
261  */
262 int rtnl_link_inet_set_conf(struct rtnl_link *link, const unsigned int cfgid,
263  uint32_t value)
264 {
265  struct inet_data *id;
266 
267  if (!(id = rtnl_link_af_alloc(link, &inet_ops)))
268  return -NLE_NOMEM;
269 
270  if (cfgid == 0 || cfgid > IPV4_DEVCONF_MAX)
271  return -NLE_RANGE;
272 
273  id->i_confset[cfgid - 1] = 1;
274  id->i_conf[cfgid - 1] = value;
275 
276  return 0;
277 }
278 
279 
280 static void __init inet_init(void)
281 {
282  rtnl_link_af_register(&inet_ops);
283 }
284 
285 static void __exit inet_exit(void)
286 {
287  rtnl_link_af_unregister(&inet_ops);
288 }
289 
290 /** @} */
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
Definition: attr.h:230
int nla_memcpy(void *dest, const struct nlattr *src, int count)
Copy attribute payload to another memory area.
Definition: attr.c:346
struct nlattr * nla_nest_start(struct nl_msg *msg, int attrtype)
Start a new level of nested attributes.
Definition: attr.c:895
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, const struct nla_policy *policy)
Create attribute index based on nested attribute.
Definition: attr.c:1013
int nla_len(const struct nlattr *nla)
Return length of the payload .
Definition: attr.c:125
int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
Finalize nesting of attributes.
Definition: attr.c:958
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Definition: utils.c:955
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
Definition: types.h:17
Dumping parameters.
Definition: types.h:28
Attribute validation policy.
Definition: attr.h:63
uint16_t minlen
Minimal length of payload required.
Definition: attr.h:68