Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <netinet/in.h>
4 : : #include <stdbool.h>
5 : : #include <unistd.h>
6 : :
7 : : #include "sd-netlink.h"
8 : :
9 : : #include "alloc-util.h"
10 : : #include "format-util.h"
11 : : #include "missing.h"
12 : : #include "netlink-internal.h"
13 : : #include "netlink-types.h"
14 : : #include "netlink-util.h"
15 : : #include "socket-util.h"
16 : : #include "memory-util.h"
17 : :
18 : : #define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset) : NULL)
19 : : #define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
20 : :
21 : : #define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
22 : : #define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK)
23 : :
24 : 452 : int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) {
25 : : sd_netlink_message *m;
26 : :
27 [ - + - + ]: 452 : assert_return(ret, -EINVAL);
28 : :
29 : : /* Note that 'rtnl' is currently unused, if we start using it internally
30 : : we must take care to avoid problems due to mutual references between
31 : : buses and their queued messages. See sd-bus.
32 : : */
33 : :
34 : 452 : m = new0(sd_netlink_message, 1);
35 [ - + ]: 452 : if (!m)
36 : 0 : return -ENOMEM;
37 : :
38 : 452 : m->n_ref = 1;
39 : 452 : m->protocol = rtnl->protocol;
40 : 452 : m->sealed = false;
41 : :
42 : 452 : *ret = m;
43 : :
44 : 452 : return 0;
45 : : }
46 : :
47 : 124 : int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) {
48 : 124 : _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
49 : : const NLType *nl_type;
50 : : const NLTypeSystem *type_system_root;
51 : : size_t size;
52 : : int r;
53 : :
54 [ - + - + ]: 124 : assert_return(rtnl, -EINVAL);
55 : :
56 : 124 : type_system_root = type_system_get_root(rtnl->protocol);
57 : :
58 : 124 : r = type_system_get_type(type_system_root, &nl_type, type);
59 [ - + ]: 124 : if (r < 0)
60 : 0 : return r;
61 : :
62 [ - + ]: 124 : if (type_get_type(nl_type) != NETLINK_TYPE_NESTED)
63 : 0 : return -EINVAL;
64 : :
65 : 124 : r = message_new_empty(rtnl, &m);
66 [ - + ]: 124 : if (r < 0)
67 : 0 : return r;
68 : :
69 : 124 : size = NLMSG_SPACE(type_get_size(nl_type));
70 : :
71 [ - + ]: 124 : assert(size >= sizeof(struct nlmsghdr));
72 : 124 : m->hdr = malloc0(size);
73 [ - + ]: 124 : if (!m->hdr)
74 : 0 : return -ENOMEM;
75 : :
76 : 124 : m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
77 : :
78 : 124 : type_get_type_system(nl_type, &m->containers[0].type_system);
79 : 124 : m->hdr->nlmsg_len = size;
80 : 124 : m->hdr->nlmsg_type = type;
81 : :
82 : 124 : *ret = TAKE_PTR(m);
83 : :
84 : 124 : return 0;
85 : : }
86 : :
87 : 8 : int sd_netlink_message_request_dump(sd_netlink_message *m, int dump) {
88 [ - + - + ]: 8 : assert_return(m, -EINVAL);
89 [ - + - + ]: 8 : assert_return(m->hdr, -EINVAL);
90 : :
91 [ + - - + : 8 : assert_return(IN_SET(m->hdr->nlmsg_type, RTM_GETLINK, RTM_GETADDR, RTM_GETROUTE, RTM_GETNEIGH, RTM_GETRULE, RTM_GETADDRLABEL), -EINVAL);
- + ]
92 : :
93 [ + - ]: 8 : SET_FLAG(m->hdr->nlmsg_flags, NLM_F_DUMP, dump);
94 : :
95 : 8 : return 0;
96 : : }
97 : :
98 [ # # # # ]: 0 : DEFINE_TRIVIAL_REF_FUNC(sd_netlink_message, sd_netlink_message);
99 : :
100 : 228 : sd_netlink_message *sd_netlink_message_unref(sd_netlink_message *m) {
101 [ + + + - ]: 680 : while (m && --m->n_ref == 0) {
102 : : unsigned i;
103 : :
104 : 452 : free(m->hdr);
105 : :
106 [ + + ]: 904 : for (i = 0; i <= m->n_containers; i++)
107 : 452 : free(m->containers[i].attributes);
108 : :
109 : 452 : sd_netlink_message *t = m;
110 : 452 : m = m->next;
111 : 452 : free(t);
112 : : }
113 : :
114 : 228 : return NULL;
115 : : }
116 : :
117 : 344 : int sd_netlink_message_get_type(sd_netlink_message *m, uint16_t *type) {
118 [ - + - + ]: 344 : assert_return(m, -EINVAL);
119 [ - + - + ]: 344 : assert_return(type, -EINVAL);
120 : :
121 : 344 : *type = m->hdr->nlmsg_type;
122 : :
123 : 344 : return 0;
124 : : }
125 : :
126 : 0 : int sd_netlink_message_set_flags(sd_netlink_message *m, uint16_t flags) {
127 [ # # # # ]: 0 : assert_return(m, -EINVAL);
128 [ # # # # ]: 0 : assert_return(flags, -EINVAL);
129 : :
130 : 0 : m->hdr->nlmsg_flags = flags;
131 : :
132 : 0 : return 0;
133 : : }
134 : :
135 : 40 : int sd_netlink_message_is_broadcast(sd_netlink_message *m) {
136 [ - + - + ]: 40 : assert_return(m, -EINVAL);
137 : :
138 : 40 : return m->broadcast;
139 : : }
140 : :
141 : : /* If successful the updated message will be correctly aligned, if
142 : : unsuccessful the old message is untouched. */
143 : 212 : static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *data, size_t data_length) {
144 : : uint32_t rta_length;
145 : : size_t message_length, padding_length;
146 : : struct nlmsghdr *new_hdr;
147 : : struct rtattr *rta;
148 : : char *padding;
149 : : unsigned i;
150 : : int offset;
151 : :
152 [ - + ]: 212 : assert(m);
153 [ - + ]: 212 : assert(m->hdr);
154 [ - + ]: 212 : assert(!m->sealed);
155 [ - + ]: 212 : assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
156 [ + + - + ]: 212 : assert(!data || data_length);
157 : :
158 : : /* get offset of the new attribute */
159 : 212 : offset = m->hdr->nlmsg_len;
160 : :
161 : : /* get the size of the new rta attribute (with padding at the end) */
162 : 212 : rta_length = RTA_LENGTH(data_length);
163 : :
164 : : /* get the new message size (with padding at the end) */
165 : 212 : message_length = offset + RTA_ALIGN(rta_length);
166 : :
167 : : /* buffer should be smaller than both one page or 8K to be accepted by the kernel */
168 [ - + ]: 212 : if (message_length > MIN(page_size(), 8192UL))
169 : 0 : return -ENOBUFS;
170 : :
171 : : /* realloc to fit the new attribute */
172 : 212 : new_hdr = realloc(m->hdr, message_length);
173 [ - + ]: 212 : if (!new_hdr)
174 : 0 : return -ENOMEM;
175 : 212 : m->hdr = new_hdr;
176 : :
177 : : /* get pointer to the attribute we are about to add */
178 : 212 : rta = (struct rtattr *) ((uint8_t *) m->hdr + offset);
179 : :
180 : : /* if we are inside containers, extend them */
181 [ + + ]: 436 : for (i = 0; i < m->n_containers; i++)
182 [ + - + - ]: 224 : GET_CONTAINER(m, i)->rta_len += message_length - offset;
183 : :
184 : : /* fill in the attribute */
185 : 212 : rta->rta_type = type;
186 : 212 : rta->rta_len = rta_length;
187 [ + + ]: 212 : if (data)
188 : : /* we don't deal with the case where the user lies about the type
189 : : * and gives us too little data (so don't do that)
190 : : */
191 : 156 : padding = mempcpy(RTA_DATA(rta), data, data_length);
192 : :
193 : : else
194 : : /* if no data was passed, make sure we still initialize the padding
195 : : note that we can have data_length > 0 (used by some containers) */
196 : 56 : padding = RTA_DATA(rta);
197 : :
198 : : /* make sure also the padding at the end of the message is initialized */
199 : 212 : padding_length = (uint8_t*)m->hdr + message_length - (uint8_t*)padding;
200 [ + + ]: 212 : memzero(padding, padding_length);
201 : :
202 : : /* update message size */
203 : 212 : m->hdr->nlmsg_len = message_length;
204 : :
205 : 212 : return offset;
206 : : }
207 : :
208 : 720 : static int message_attribute_has_type(sd_netlink_message *m, size_t *out_size, uint16_t attribute_type, uint16_t data_type) {
209 : : const NLType *type;
210 : : int r;
211 : :
212 [ - + ]: 720 : assert(m);
213 : :
214 : 720 : r = type_system_get_type(m->containers[m->n_containers].type_system, &type, attribute_type);
215 [ - + ]: 720 : if (r < 0)
216 : 0 : return r;
217 : :
218 [ + + ]: 720 : if (type_get_type(type) != data_type)
219 : 8 : return -EINVAL;
220 : :
221 [ + + ]: 712 : if (out_size)
222 : 64 : *out_size = type_get_size(type);
223 : 712 : return 0;
224 : : }
225 : :
226 : 52 : int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type, const char *data) {
227 : : size_t length, size;
228 : : int r;
229 : :
230 [ - + - + ]: 52 : assert_return(m, -EINVAL);
231 [ - + - + ]: 52 : assert_return(!m->sealed, -EPERM);
232 [ - + - + ]: 52 : assert_return(data, -EINVAL);
233 : :
234 : 52 : r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_STRING);
235 [ - + ]: 52 : if (r < 0)
236 : 0 : return r;
237 : :
238 [ + + ]: 52 : if (size) {
239 : 4 : length = strnlen(data, size+1);
240 [ - + ]: 4 : if (length > size)
241 : 0 : return -EINVAL;
242 : : } else
243 : 48 : length = strlen(data);
244 : :
245 : 52 : r = add_rtattr(m, type, data, length + 1);
246 [ - + ]: 52 : if (r < 0)
247 : 0 : return r;
248 : :
249 : 52 : return 0;
250 : : }
251 : :
252 : 0 : int sd_netlink_message_append_flag(sd_netlink_message *m, unsigned short type) {
253 : : size_t size;
254 : : int r;
255 : :
256 [ # # # # ]: 0 : assert_return(m, -EINVAL);
257 [ # # # # ]: 0 : assert_return(!m->sealed, -EPERM);
258 : :
259 : 0 : r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_FLAG);
260 [ # # ]: 0 : if (r < 0)
261 : 0 : return r;
262 : :
263 : 0 : r = add_rtattr(m, type, NULL, 0);
264 [ # # ]: 0 : if (r < 0)
265 : 0 : return r;
266 : :
267 : 0 : return 0;
268 : : }
269 : :
270 : 12 : int sd_netlink_message_append_u8(sd_netlink_message *m, unsigned short type, uint8_t data) {
271 : : int r;
272 : :
273 [ - + - + ]: 12 : assert_return(m, -EINVAL);
274 [ - + - + ]: 12 : assert_return(!m->sealed, -EPERM);
275 : :
276 : 12 : r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
277 [ - + ]: 12 : if (r < 0)
278 : 0 : return r;
279 : :
280 : 12 : r = add_rtattr(m, type, &data, sizeof(uint8_t));
281 [ - + ]: 12 : if (r < 0)
282 : 0 : return r;
283 : :
284 : 12 : return 0;
285 : : }
286 : :
287 : 4 : int sd_netlink_message_append_u16(sd_netlink_message *m, unsigned short type, uint16_t data) {
288 : : int r;
289 : :
290 [ - + - + ]: 4 : assert_return(m, -EINVAL);
291 [ - + - + ]: 4 : assert_return(!m->sealed, -EPERM);
292 : :
293 : 4 : r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
294 [ - + ]: 4 : if (r < 0)
295 : 0 : return r;
296 : :
297 : 4 : r = add_rtattr(m, type, &data, sizeof(uint16_t));
298 [ - + ]: 4 : if (r < 0)
299 : 0 : return r;
300 : :
301 : 4 : return 0;
302 : : }
303 : :
304 : 72 : int sd_netlink_message_append_u32(sd_netlink_message *m, unsigned short type, uint32_t data) {
305 : : int r;
306 : :
307 [ - + - + ]: 72 : assert_return(m, -EINVAL);
308 [ - + - + ]: 72 : assert_return(!m->sealed, -EPERM);
309 : :
310 : 72 : r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
311 [ - + ]: 72 : if (r < 0)
312 : 0 : return r;
313 : :
314 : 72 : r = add_rtattr(m, type, &data, sizeof(uint32_t));
315 [ - + ]: 72 : if (r < 0)
316 : 0 : return r;
317 : :
318 : 72 : return 0;
319 : : }
320 : :
321 : 0 : int sd_netlink_message_append_u64(sd_netlink_message *m, unsigned short type, uint64_t data) {
322 : : int r;
323 : :
324 [ # # # # ]: 0 : assert_return(m, -EINVAL);
325 [ # # # # ]: 0 : assert_return(!m->sealed, -EPERM);
326 : :
327 : 0 : r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U64);
328 [ # # ]: 0 : if (r < 0)
329 : 0 : return r;
330 : :
331 : 0 : r = add_rtattr(m, type, &data, sizeof(uint64_t));
332 [ # # ]: 0 : if (r < 0)
333 : 0 : return r;
334 : :
335 : 0 : return 0;
336 : : }
337 : :
338 : 0 : int sd_netlink_message_append_data(sd_netlink_message *m, unsigned short type, const void *data, size_t len) {
339 : : int r;
340 : :
341 [ # # # # ]: 0 : assert_return(m, -EINVAL);
342 [ # # # # ]: 0 : assert_return(!m->sealed, -EPERM);
343 : :
344 : 0 : r = add_rtattr(m, type, data, len);
345 [ # # ]: 0 : if (r < 0)
346 : 0 : return r;
347 : :
348 : 0 : return 0;
349 : : }
350 : :
351 : 12 : int netlink_message_append_in_addr_union(sd_netlink_message *m, unsigned short type, int family, const union in_addr_union *data) {
352 : : int r;
353 : :
354 [ - + - + ]: 12 : assert_return(m, -EINVAL);
355 [ - + - + ]: 12 : assert_return(!m->sealed, -EPERM);
356 [ - + - + ]: 12 : assert_return(data, -EINVAL);
357 [ + - - + : 12 : assert_return(IN_SET(family, AF_INET, AF_INET6), -EINVAL);
- + ]
358 : :
359 : 12 : r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
360 [ - + ]: 12 : if (r < 0)
361 : 0 : return r;
362 : :
363 : 12 : r = add_rtattr(m, type, data, FAMILY_ADDRESS_SIZE(family));
364 [ - + ]: 12 : if (r < 0)
365 : 0 : return r;
366 : :
367 : 12 : return 0;
368 : : }
369 : :
370 : 8 : int sd_netlink_message_append_in_addr(sd_netlink_message *m, unsigned short type, const struct in_addr *data) {
371 : 8 : return netlink_message_append_in_addr_union(m, type, AF_INET, (const union in_addr_union *) data);
372 : : }
373 : :
374 : 4 : int sd_netlink_message_append_in6_addr(sd_netlink_message *m, unsigned short type, const struct in6_addr *data) {
375 : 4 : return netlink_message_append_in_addr_union(m, type, AF_INET6, (const union in_addr_union *) data);
376 : : }
377 : :
378 : 0 : int netlink_message_append_sockaddr_union(sd_netlink_message *m, unsigned short type, const union sockaddr_union *data) {
379 : : int r;
380 : :
381 [ # # # # ]: 0 : assert_return(m, -EINVAL);
382 [ # # # # ]: 0 : assert_return(!m->sealed, -EPERM);
383 [ # # # # ]: 0 : assert_return(data, -EINVAL);
384 [ # # # # : 0 : assert_return(IN_SET(data->sa.sa_family, AF_INET, AF_INET6), -EINVAL);
# # ]
385 : :
386 : 0 : r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_SOCKADDR);
387 [ # # ]: 0 : if (r < 0)
388 : 0 : return r;
389 : :
390 [ # # ]: 0 : r = add_rtattr(m, type, data, data->sa.sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
391 [ # # ]: 0 : if (r < 0)
392 : 0 : return r;
393 : :
394 : 0 : return 0;
395 : : }
396 : :
397 : 0 : int sd_netlink_message_append_sockaddr_in(sd_netlink_message *m, unsigned short type, const struct sockaddr_in *data) {
398 : 0 : return netlink_message_append_sockaddr_union(m, type, (const union sockaddr_union *) data);
399 : : }
400 : :
401 : 0 : int sd_netlink_message_append_sockaddr_in6(sd_netlink_message *m, unsigned short type, const struct sockaddr_in6 *data) {
402 : 0 : return netlink_message_append_sockaddr_union(m, type, (const union sockaddr_union *) data);
403 : : }
404 : :
405 : 4 : int sd_netlink_message_append_ether_addr(sd_netlink_message *m, unsigned short type, const struct ether_addr *data) {
406 : : int r;
407 : :
408 [ - + - + ]: 4 : assert_return(m, -EINVAL);
409 [ - + - + ]: 4 : assert_return(!m->sealed, -EPERM);
410 [ - + - + ]: 4 : assert_return(data, -EINVAL);
411 : :
412 : 4 : r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
413 [ - + ]: 4 : if (r < 0)
414 : 0 : return r;
415 : :
416 : 4 : r = add_rtattr(m, type, data, ETH_ALEN);
417 [ - + ]: 4 : if (r < 0)
418 : 0 : return r;
419 : :
420 : 4 : return 0;
421 : : }
422 : :
423 : 0 : int sd_netlink_message_append_cache_info(sd_netlink_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
424 : : int r;
425 : :
426 [ # # # # ]: 0 : assert_return(m, -EINVAL);
427 [ # # # # ]: 0 : assert_return(!m->sealed, -EPERM);
428 [ # # # # ]: 0 : assert_return(info, -EINVAL);
429 : :
430 : 0 : r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
431 [ # # ]: 0 : if (r < 0)
432 : 0 : return r;
433 : :
434 : 0 : r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
435 [ # # ]: 0 : if (r < 0)
436 : 0 : return r;
437 : :
438 : 0 : return 0;
439 : : }
440 : :
441 : 12 : int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type) {
442 : : size_t size;
443 : : int r;
444 : :
445 [ - + - + ]: 12 : assert_return(m, -EINVAL);
446 [ - + - + ]: 12 : assert_return(!m->sealed, -EPERM);
447 [ - + - + ]: 12 : assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE);
448 : :
449 : 12 : r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_NESTED);
450 [ + + ]: 12 : if (r < 0) {
451 : : const NLTypeSystemUnion *type_system_union;
452 : : int family;
453 : :
454 : 4 : r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_UNION);
455 [ - + ]: 4 : if (r < 0)
456 : 0 : return r;
457 : :
458 : 4 : r = sd_rtnl_message_get_family(m, &family);
459 [ - + ]: 4 : if (r < 0)
460 : 0 : return r;
461 : :
462 : 4 : r = type_system_get_type_system_union(m->containers[m->n_containers].type_system, &type_system_union, type);
463 [ - + ]: 4 : if (r < 0)
464 : 0 : return r;
465 : :
466 : 8 : r = type_system_union_protocol_get_type_system(type_system_union,
467 : 4 : &m->containers[m->n_containers + 1].type_system,
468 : : family);
469 [ - + ]: 4 : if (r < 0)
470 : 0 : return r;
471 : : } else {
472 : 16 : r = type_system_get_type_system(m->containers[m->n_containers].type_system,
473 : 8 : &m->containers[m->n_containers + 1].type_system,
474 : : type);
475 [ - + ]: 8 : if (r < 0)
476 : 0 : return r;
477 : : }
478 : :
479 : 12 : r = add_rtattr(m, type | NLA_F_NESTED, NULL, size);
480 [ - + ]: 12 : if (r < 0)
481 : 0 : return r;
482 : :
483 : 12 : m->containers[m->n_containers++].offset = r;
484 : :
485 : 12 : return 0;
486 : : }
487 : :
488 : 4 : int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned short type, const char *key) {
489 : : const NLTypeSystemUnion *type_system_union;
490 : : int r;
491 : :
492 [ - + - + ]: 4 : assert_return(m, -EINVAL);
493 [ - + - + ]: 4 : assert_return(!m->sealed, -EPERM);
494 : :
495 : 4 : r = type_system_get_type_system_union(m->containers[m->n_containers].type_system, &type_system_union, type);
496 [ - + ]: 4 : if (r < 0)
497 : 0 : return r;
498 : :
499 : 4 : r = type_system_union_get_type_system(type_system_union,
500 : 4 : &m->containers[m->n_containers + 1].type_system,
501 : : key);
502 [ - + ]: 4 : if (r < 0)
503 : 0 : return r;
504 : :
505 : 4 : r = sd_netlink_message_append_string(m, type_system_union->match, key);
506 [ - + ]: 4 : if (r < 0)
507 : 0 : return r;
508 : :
509 : : /* do we ever need non-null size */
510 : 4 : r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
511 [ - + ]: 4 : if (r < 0)
512 : 0 : return r;
513 : :
514 : 4 : m->containers[m->n_containers++].offset = r;
515 : :
516 : 4 : return 0;
517 : : }
518 : :
519 : 60 : int sd_netlink_message_close_container(sd_netlink_message *m) {
520 [ - + - + ]: 60 : assert_return(m, -EINVAL);
521 [ - + - + ]: 60 : assert_return(!m->sealed, -EPERM);
522 [ + + + + ]: 60 : assert_return(m->n_containers > 0, -EINVAL);
523 : :
524 : 56 : m->containers[m->n_containers].type_system = NULL;
525 : 56 : m->containers[m->n_containers].offset = 0;
526 : 56 : m->n_containers--;
527 : :
528 : 56 : return 0;
529 : : }
530 : :
531 : 40 : int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type) {
532 : : int r;
533 : :
534 [ - + - + ]: 40 : assert_return(m, -EINVAL);
535 [ - + - + ]: 40 : assert_return(!m->sealed, -EPERM);
536 [ - + - + ]: 40 : assert_return(m->n_containers > 0, -EINVAL);
537 : :
538 : 40 : r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
539 [ - + ]: 40 : if (r < 0)
540 : 0 : return r;
541 : :
542 : 40 : m->containers[m->n_containers].offset = r;
543 : 40 : m->n_containers++;
544 : 40 : m->containers[m->n_containers].type_system = m->containers[m->n_containers - 1].type_system;
545 : :
546 : 40 : return 0;
547 : : }
548 : :
549 : 0 : int sd_netlink_message_cancel_array(sd_netlink_message *m) {
550 : : unsigned i;
551 : : uint32_t rta_len;
552 : :
553 [ # # # # ]: 0 : assert_return(m, -EINVAL);
554 [ # # # # ]: 0 : assert_return(!m->sealed, -EPERM);
555 [ # # # # ]: 0 : assert_return(m->n_containers > 1, -EINVAL);
556 : :
557 [ # # ]: 0 : rta_len = GET_CONTAINER(m, (m->n_containers - 1))->rta_len;
558 : :
559 [ # # ]: 0 : for (i = 0; i < m->n_containers; i++)
560 [ # # # # ]: 0 : GET_CONTAINER(m, i)->rta_len -= rta_len;
561 : :
562 : 0 : m->hdr->nlmsg_len -= rta_len;
563 : :
564 : 0 : m->n_containers--;
565 : 0 : m->containers[m->n_containers].type_system = NULL;
566 : :
567 : 0 : return 0;
568 : : }
569 : :
570 : 628 : static int netlink_message_read_internal(sd_netlink_message *m, unsigned short type, void **data, bool *net_byteorder) {
571 : : struct netlink_attribute *attribute;
572 : : struct rtattr *rta;
573 : :
574 [ - + - + ]: 628 : assert_return(m, -EINVAL);
575 [ + + + + ]: 628 : assert_return(m->sealed, -EPERM);
576 [ - + - + ]: 624 : assert_return(data, -EINVAL);
577 : :
578 [ - + ]: 624 : assert(m->n_containers < RTNL_CONTAINER_DEPTH);
579 [ - + ]: 624 : assert(m->containers[m->n_containers].attributes);
580 [ - + ]: 624 : assert(type < m->containers[m->n_containers].n_attributes);
581 : :
582 : 624 : attribute = &m->containers[m->n_containers].attributes[type];
583 : :
584 [ + + ]: 624 : if (attribute->offset == 0)
585 : 88 : return -ENODATA;
586 : :
587 : 536 : rta = (struct rtattr*)((uint8_t *) m->hdr + attribute->offset);
588 : :
589 : 536 : *data = RTA_DATA(rta);
590 : :
591 [ + + ]: 536 : if (net_byteorder)
592 : 120 : *net_byteorder = attribute->net_byteorder;
593 : :
594 : 536 : return RTA_PAYLOAD(rta);
595 : : }
596 : :
597 : 0 : int sd_netlink_message_read(sd_netlink_message *m, unsigned short type, size_t size, void *data) {
598 : : void *attr_data;
599 : : int r;
600 : :
601 [ # # # # ]: 0 : assert_return(m, -EINVAL);
602 : :
603 : 0 : r = netlink_message_read_internal(m, type, &attr_data, NULL);
604 [ # # ]: 0 : if (r < 0)
605 : 0 : return r;
606 : :
607 [ # # ]: 0 : if ((size_t) r < size)
608 : 0 : return -EIO;
609 : :
610 [ # # ]: 0 : if (data)
611 : 0 : memcpy(data, attr_data, size);
612 : :
613 : 0 : return r;
614 : : }
615 : :
616 : 184 : int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, const char **data) {
617 : : int r;
618 : : void *attr_data;
619 : :
620 [ - + - + ]: 184 : assert_return(m, -EINVAL);
621 : :
622 : 184 : r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_STRING);
623 [ - + ]: 184 : if (r < 0)
624 : 0 : return r;
625 : :
626 : 184 : r = netlink_message_read_internal(m, type, &attr_data, NULL);
627 [ + + ]: 184 : if (r < 0)
628 : 4 : return r;
629 [ - + ]: 180 : else if (strnlen(attr_data, r) >= (size_t) r)
630 : 0 : return -EIO;
631 : :
632 [ + - ]: 180 : if (data)
633 : 180 : *data = (const char *) attr_data;
634 : :
635 : 180 : return 0;
636 : : }
637 : :
638 : 68 : int sd_netlink_message_read_u8(sd_netlink_message *m, unsigned short type, uint8_t *data) {
639 : : int r;
640 : : void *attr_data;
641 : :
642 [ - + - + ]: 68 : assert_return(m, -EINVAL);
643 : :
644 : 68 : r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
645 [ - + ]: 68 : if (r < 0)
646 : 0 : return r;
647 : :
648 : 68 : r = netlink_message_read_internal(m, type, &attr_data, NULL);
649 [ - + ]: 68 : if (r < 0)
650 : 0 : return r;
651 [ - + ]: 68 : else if ((size_t) r < sizeof(uint8_t))
652 : 0 : return -EIO;
653 : :
654 [ + - ]: 68 : if (data)
655 : 68 : *data = *(uint8_t *) attr_data;
656 : :
657 : 68 : return 0;
658 : : }
659 : :
660 : 4 : int sd_netlink_message_read_u16(sd_netlink_message *m, unsigned short type, uint16_t *data) {
661 : : void *attr_data;
662 : : bool net_byteorder;
663 : : int r;
664 : :
665 [ - + - + ]: 4 : assert_return(m, -EINVAL);
666 : :
667 : 4 : r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
668 [ - + ]: 4 : if (r < 0)
669 : 0 : return r;
670 : :
671 : 4 : r = netlink_message_read_internal(m, type, &attr_data, &net_byteorder);
672 [ - + ]: 4 : if (r < 0)
673 : 0 : return r;
674 [ - + ]: 4 : else if ((size_t) r < sizeof(uint16_t))
675 : 0 : return -EIO;
676 : :
677 [ + - ]: 4 : if (data) {
678 [ - + ]: 4 : if (net_byteorder)
679 : 0 : *data = be16toh(*(uint16_t *) attr_data);
680 : : else
681 : 4 : *data = *(uint16_t *) attr_data;
682 : : }
683 : :
684 : 4 : return 0;
685 : : }
686 : :
687 : 168 : int sd_netlink_message_read_u32(sd_netlink_message *m, unsigned short type, uint32_t *data) {
688 : : void *attr_data;
689 : : bool net_byteorder;
690 : : int r;
691 : :
692 [ - + - + ]: 168 : assert_return(m, -EINVAL);
693 : :
694 : 168 : r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
695 [ + + ]: 168 : if (r < 0)
696 : 4 : return r;
697 : :
698 : 164 : r = netlink_message_read_internal(m, type, &attr_data, &net_byteorder);
699 [ + + ]: 164 : if (r < 0)
700 : 48 : return r;
701 [ - + ]: 116 : else if ((size_t)r < sizeof(uint32_t))
702 : 0 : return -EIO;
703 : :
704 [ + - ]: 116 : if (data) {
705 [ - + ]: 116 : if (net_byteorder)
706 : 0 : *data = be32toh(*(uint32_t *) attr_data);
707 : : else
708 : 116 : *data = *(uint32_t *) attr_data;
709 : : }
710 : :
711 : 116 : return 0;
712 : : }
713 : :
714 : 64 : int sd_netlink_message_read_ether_addr(sd_netlink_message *m, unsigned short type, struct ether_addr *data) {
715 : : int r;
716 : : void *attr_data;
717 : :
718 [ - + - + ]: 64 : assert_return(m, -EINVAL);
719 : :
720 : 64 : r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
721 [ - + ]: 64 : if (r < 0)
722 : 0 : return r;
723 : :
724 : 64 : r = netlink_message_read_internal(m, type, &attr_data, NULL);
725 [ + + ]: 64 : if (r < 0)
726 : 16 : return r;
727 [ - + ]: 48 : else if ((size_t)r < sizeof(struct ether_addr))
728 : 0 : return -EIO;
729 : :
730 [ + - ]: 48 : if (data)
731 : 48 : memcpy(data, attr_data, sizeof(struct ether_addr));
732 : :
733 : 48 : return 0;
734 : : }
735 : :
736 : 4 : int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short type, struct ifa_cacheinfo *info) {
737 : : int r;
738 : : void *attr_data;
739 : :
740 [ - + - + ]: 4 : assert_return(m, -EINVAL);
741 : :
742 : 4 : r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
743 [ - + ]: 4 : if (r < 0)
744 : 0 : return r;
745 : :
746 : 4 : r = netlink_message_read_internal(m, type, &attr_data, NULL);
747 [ - + ]: 4 : if (r < 0)
748 : 0 : return r;
749 [ - + ]: 4 : else if ((size_t)r < sizeof(struct ifa_cacheinfo))
750 : 0 : return -EIO;
751 : :
752 [ + - ]: 4 : if (info)
753 : 4 : memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
754 : :
755 : 4 : return 0;
756 : : }
757 : :
758 : 32 : int sd_netlink_message_read_in_addr(sd_netlink_message *m, unsigned short type, struct in_addr *data) {
759 : : int r;
760 : : void *attr_data;
761 : :
762 [ - + - + ]: 32 : assert_return(m, -EINVAL);
763 : :
764 : 32 : r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
765 [ - + ]: 32 : if (r < 0)
766 : 0 : return r;
767 : :
768 : 32 : r = netlink_message_read_internal(m, type, &attr_data, NULL);
769 [ - + ]: 32 : if (r < 0)
770 : 0 : return r;
771 [ - + ]: 32 : else if ((size_t)r < sizeof(struct in_addr))
772 : 0 : return -EIO;
773 : :
774 [ + - ]: 32 : if (data)
775 : 32 : memcpy(data, attr_data, sizeof(struct in_addr));
776 : :
777 : 32 : return 0;
778 : : }
779 : :
780 : 24 : int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type, struct in6_addr *data) {
781 : : int r;
782 : : void *attr_data;
783 : :
784 [ - + - + ]: 24 : assert_return(m, -EINVAL);
785 : :
786 : 24 : r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
787 [ - + ]: 24 : if (r < 0)
788 : 0 : return r;
789 : :
790 : 24 : r = netlink_message_read_internal(m, type, &attr_data, NULL);
791 [ + + ]: 24 : if (r < 0)
792 : 12 : return r;
793 [ - + ]: 12 : else if ((size_t)r < sizeof(struct in6_addr))
794 : 0 : return -EIO;
795 : :
796 [ + - ]: 12 : if (data)
797 : 12 : memcpy(data, attr_data, sizeof(struct in6_addr));
798 : :
799 : 12 : return 0;
800 : : }
801 : :
802 : 416 : static int netlink_container_parse(sd_netlink_message *m,
803 : : struct netlink_container *container,
804 : : struct rtattr *rta,
805 : : unsigned rt_len) {
806 : 416 : _cleanup_free_ struct netlink_attribute *attributes = NULL;
807 : 416 : size_t n_allocated = 0;
808 : :
809 [ + + + + : 3480 : for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
+ + ]
810 : : unsigned short type;
811 : :
812 : 3064 : type = RTA_TYPE(rta);
813 : :
814 [ - + ]: 3064 : if (!GREEDY_REALLOC0(attributes, n_allocated, type + 1))
815 : 0 : return -ENOMEM;
816 : :
817 [ + + ]: 3064 : if (attributes[type].offset != 0)
818 [ - + ]: 4 : log_debug("rtnl: message parse - overwriting repeated attribute");
819 : :
820 : 3064 : attributes[type].offset = (uint8_t *) rta - (uint8_t *) m->hdr;
821 : 3064 : attributes[type].nested = RTA_FLAGS(rta) & NLA_F_NESTED;
822 : 3064 : attributes[type].net_byteorder = RTA_FLAGS(rta) & NLA_F_NET_BYTEORDER;
823 : : }
824 : :
825 : 416 : container->attributes = TAKE_PTR(attributes);
826 : 416 : container->n_attributes = n_allocated;
827 : :
828 : 416 : return 0;
829 : : }
830 : :
831 : 44 : int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short type_id) {
832 : : const NLType *nl_type;
833 : : const NLTypeSystem *type_system;
834 : : void *container;
835 : : uint16_t type;
836 : : size_t size;
837 : : int r;
838 : :
839 [ - + - + ]: 44 : assert_return(m, -EINVAL);
840 [ - + - + ]: 44 : assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
841 : :
842 : 44 : r = type_system_get_type(m->containers[m->n_containers].type_system,
843 : : &nl_type,
844 : : type_id);
845 [ - + ]: 44 : if (r < 0)
846 : 0 : return r;
847 : :
848 : 44 : type = type_get_type(nl_type);
849 : :
850 [ + + ]: 44 : if (type == NETLINK_TYPE_NESTED) {
851 : 36 : r = type_system_get_type_system(m->containers[m->n_containers].type_system,
852 : : &type_system,
853 : : type_id);
854 [ - + ]: 36 : if (r < 0)
855 : 0 : return r;
856 [ + - ]: 8 : } else if (type == NETLINK_TYPE_UNION) {
857 : : const NLTypeSystemUnion *type_system_union;
858 : :
859 : 8 : r = type_system_get_type_system_union(m->containers[m->n_containers].type_system,
860 : : &type_system_union,
861 : : type_id);
862 [ - + ]: 8 : if (r < 0)
863 : 0 : return r;
864 : :
865 [ + + - ]: 8 : switch (type_system_union->match_type) {
866 : 4 : case NL_MATCH_SIBLING:
867 : : {
868 : : const char *key;
869 : :
870 : 4 : r = sd_netlink_message_read_string(m, type_system_union->match, &key);
871 [ - + ]: 4 : if (r < 0)
872 : 0 : return r;
873 : :
874 : 4 : r = type_system_union_get_type_system(type_system_union,
875 : : &type_system,
876 : : key);
877 [ - + ]: 4 : if (r < 0)
878 : 0 : return r;
879 : :
880 : 4 : break;
881 : : }
882 : 4 : case NL_MATCH_PROTOCOL:
883 : : {
884 : : int family;
885 : :
886 : 4 : r = sd_rtnl_message_get_family(m, &family);
887 [ - + ]: 4 : if (r < 0)
888 : 0 : return r;
889 : :
890 : 4 : r = type_system_union_protocol_get_type_system(type_system_union,
891 : : &type_system,
892 : : family);
893 [ - + ]: 4 : if (r < 0)
894 : 0 : return r;
895 : :
896 : 4 : break;
897 : : }
898 : 0 : default:
899 : 0 : assert_not_reached("sd-netlink: invalid type system union type");
900 : : }
901 : : } else
902 : 0 : return -EINVAL;
903 : :
904 : 44 : r = netlink_message_read_internal(m, type_id, &container, NULL);
905 [ + + ]: 44 : if (r < 0)
906 : 12 : return r;
907 : :
908 : 32 : size = (size_t)r;
909 : :
910 : 32 : m->n_containers++;
911 : :
912 : 64 : r = netlink_container_parse(m,
913 : 32 : &m->containers[m->n_containers],
914 : : container,
915 : : size);
916 [ - + ]: 32 : if (r < 0) {
917 : 0 : m->n_containers--;
918 : 0 : return r;
919 : : }
920 : :
921 : 32 : m->containers[m->n_containers].type_system = type_system;
922 : :
923 : 32 : return 0;
924 : : }
925 : :
926 : 40 : int sd_netlink_message_enter_array(sd_netlink_message *m, unsigned short type_id) {
927 : : void *container;
928 : : size_t size;
929 : : int r;
930 : :
931 [ - + - + ]: 40 : assert_return(m, -EINVAL);
932 [ - + - + ]: 40 : assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
933 : :
934 : 40 : r = netlink_message_read_internal(m, type_id, &container, NULL);
935 [ - + ]: 40 : if (r < 0)
936 : 0 : return r;
937 : :
938 : 40 : size = (size_t) r;
939 : :
940 : 40 : m->n_containers++;
941 : :
942 : 80 : r = netlink_container_parse(m,
943 : 40 : &m->containers[m->n_containers],
944 : : container,
945 : : size);
946 [ - + ]: 40 : if (r < 0) {
947 : 0 : m->n_containers--;
948 : 0 : return r;
949 : : }
950 : :
951 : 40 : m->containers[m->n_containers].type_system = m->containers[m->n_containers - 1].type_system;
952 : :
953 : 40 : return 0;
954 : : }
955 : :
956 : 76 : int sd_netlink_message_exit_container(sd_netlink_message *m) {
957 [ - + - + ]: 76 : assert_return(m, -EINVAL);
958 [ - + - + ]: 76 : assert_return(m->sealed, -EINVAL);
959 [ + + + + ]: 76 : assert_return(m->n_containers > 0, -EINVAL);
960 : :
961 : 72 : m->containers[m->n_containers].attributes = mfree(m->containers[m->n_containers].attributes);
962 : 72 : m->containers[m->n_containers].type_system = NULL;
963 : :
964 : 72 : m->n_containers--;
965 : :
966 : 72 : return 0;
967 : : }
968 : :
969 : 312 : uint32_t rtnl_message_get_serial(sd_netlink_message *m) {
970 [ - + ]: 312 : assert(m);
971 [ - + ]: 312 : assert(m->hdr);
972 : :
973 : 312 : return m->hdr->nlmsg_seq;
974 : : }
975 : :
976 : 260 : int sd_netlink_message_is_error(sd_netlink_message *m) {
977 [ - + - + ]: 260 : assert_return(m, 0);
978 [ - + - + ]: 260 : assert_return(m->hdr, 0);
979 : :
980 : 260 : return m->hdr->nlmsg_type == NLMSG_ERROR;
981 : : }
982 : :
983 : 232 : int sd_netlink_message_get_errno(sd_netlink_message *m) {
984 : : struct nlmsgerr *err;
985 : :
986 [ - + - + ]: 232 : assert_return(m, -EINVAL);
987 [ - + - + ]: 232 : assert_return(m->hdr, -EINVAL);
988 : :
989 [ + + ]: 232 : if (!sd_netlink_message_is_error(m))
990 : 216 : return 0;
991 : :
992 : 16 : err = NLMSG_DATA(m->hdr);
993 : :
994 : 16 : return err->error;
995 : : }
996 : :
997 : 344 : int sd_netlink_message_rewind(sd_netlink_message *m) {
998 : : const NLType *nl_type;
999 : : const NLTypeSystem *type_system_root;
1000 : : uint16_t type;
1001 : : size_t size;
1002 : : unsigned i;
1003 : : int r;
1004 : :
1005 [ - + - + ]: 344 : assert_return(m, -EINVAL);
1006 : :
1007 : : /* don't allow appending to message once parsed */
1008 [ + + ]: 344 : if (!m->sealed)
1009 : 336 : rtnl_message_seal(m);
1010 : :
1011 : 344 : type_system_root = type_system_get_root(m->protocol);
1012 : :
1013 [ - + ]: 344 : for (i = 1; i <= m->n_containers; i++)
1014 : 0 : m->containers[i].attributes = mfree(m->containers[i].attributes);
1015 : :
1016 : 344 : m->n_containers = 0;
1017 : :
1018 [ - + ]: 344 : if (m->containers[0].attributes)
1019 : : /* top-level attributes have already been parsed */
1020 : 0 : return 0;
1021 : :
1022 [ - + ]: 344 : assert(m->hdr);
1023 : :
1024 : 344 : r = type_system_get_type(type_system_root, &nl_type, m->hdr->nlmsg_type);
1025 [ - + ]: 344 : if (r < 0)
1026 : 0 : return r;
1027 : :
1028 : 344 : type = type_get_type(nl_type);
1029 : 344 : size = type_get_size(nl_type);
1030 : :
1031 [ + - ]: 344 : if (type == NETLINK_TYPE_NESTED) {
1032 : : const NLTypeSystem *type_system;
1033 : :
1034 : 344 : type_get_type_system(nl_type, &type_system);
1035 : :
1036 : 344 : m->containers[0].type_system = type_system;
1037 : :
1038 : 1032 : r = netlink_container_parse(m,
1039 : 344 : &m->containers[m->n_containers],
1040 : 344 : (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
1041 : 344 : NLMSG_PAYLOAD(m->hdr, size));
1042 [ - + ]: 344 : if (r < 0)
1043 : 0 : return r;
1044 : : }
1045 : :
1046 : 344 : return 0;
1047 : : }
1048 : :
1049 : 448 : void rtnl_message_seal(sd_netlink_message *m) {
1050 [ - + ]: 448 : assert(m);
1051 [ - + ]: 448 : assert(!m->sealed);
1052 : :
1053 : 448 : m->sealed = true;
1054 : 448 : }
1055 : :
1056 : 236 : sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m) {
1057 [ - + - + ]: 236 : assert_return(m, NULL);
1058 : :
1059 : 236 : return m->next;
1060 : : }
|