]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-netlink/netlink-message.c
sd-netlink: use setsockopt_int() also for NETLINK_ADD/DROP_MEMBERSHIP
[thirdparty/systemd.git] / src / libsystemd / sd-netlink / netlink-message.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
65f568bb
TG
2
3#include <netinet/in.h>
65f568bb
TG
4#include <stdbool.h>
5#include <unistd.h>
6
07630cea
LP
7#include "sd-netlink.h"
8
b5efdb8a 9#include "alloc-util.h"
f97b34a6 10#include "format-util.h"
8f3c1859 11#include "memory-util.h"
1c4baffc
TG
12#include "netlink-internal.h"
13#include "netlink-types.h"
07630cea 14#include "netlink-util.h"
07630cea 15#include "socket-util.h"
8f3c1859 16#include "strv.h"
65f568bb 17
179b4db4 18#define GET_CONTAINER(m, i) ((struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset))
4ebe732c 19
0a2478a9 20#define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
4c641e99 21#define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK)
0a2478a9 22
89489ef7 23int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) {
1c4baffc 24 sd_netlink_message *m;
65f568bb
TG
25
26 assert_return(ret, -EINVAL);
65f568bb 27
f131770b 28 /* Note that 'rtnl' is currently unused, if we start using it internally
8c578303 29 we must take care to avoid problems due to mutual references between
ff9b60f3 30 buses and their queued messages. See sd-bus.
8c578303
TG
31 */
32
6bf8e24b 33 m = new(sd_netlink_message, 1);
65f568bb
TG
34 if (!m)
35 return -ENOMEM;
36
6bf8e24b
YW
37 *m = (sd_netlink_message) {
38 .n_ref = 1,
39 .protocol = rtnl->protocol,
40 .sealed = false,
41 };
65f568bb
TG
42
43 *ret = m;
44
45 return 0;
46}
47
1c4baffc 48int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) {
4afd3348 49 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
d8e538ec
TG
50 const NLType *nl_type;
51 size_t size;
52 int r;
53
05d0c2e3
JT
54 assert_return(rtnl, -EINVAL);
55
4e8f0ef9 56 r = type_system_root_get_type(rtnl, &nl_type, type);
d8e538ec
TG
57 if (r < 0)
58 return r;
59
12b7dff4
DH
60 if (type_get_type(nl_type) != NETLINK_TYPE_NESTED)
61 return -EINVAL;
62
1b89cf56 63 r = message_new_empty(rtnl, &m);
d8e538ec
TG
64 if (r < 0)
65 return r;
66
817d1cd8 67 size = NLMSG_SPACE(type_get_size(nl_type));
1b89cf56
TG
68
69 assert(size >= sizeof(struct nlmsghdr));
70 m->hdr = malloc0(size);
71 if (!m->hdr)
72 return -ENOMEM;
73
74 m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
75
f663aeb8 76 type_get_type_system(nl_type, &m->containers[0].type_system);
1b89cf56
TG
77 m->hdr->nlmsg_len = size;
78 m->hdr->nlmsg_type = type;
79
1cc6c93a 80 *ret = TAKE_PTR(m);
d8e538ec
TG
81
82 return 0;
83}
84
1c4baffc 85int sd_netlink_message_request_dump(sd_netlink_message *m, int dump) {
6e20c8f8
TG
86 assert_return(m, -EINVAL);
87 assert_return(m->hdr, -EINVAL);
bce67bbe 88
ffeb16f5
YW
89 assert_return(IN_SET(m->hdr->nlmsg_type,
90 RTM_GETLINK, RTM_GETLINKPROP, RTM_GETADDR, RTM_GETROUTE, RTM_GETNEIGH,
c16c7808 91 RTM_GETRULE, RTM_GETADDRLABEL, RTM_GETNEXTHOP), -EINVAL);
6e20c8f8 92
5883ff60 93 SET_FLAG(m->hdr->nlmsg_flags, NLM_F_DUMP, dump);
6e20c8f8
TG
94
95 return 0;
96}
97
f23ab4dc 98DEFINE_TRIVIAL_REF_FUNC(sd_netlink_message, sd_netlink_message);
65f568bb 99
1c4baffc 100sd_netlink_message *sd_netlink_message_unref(sd_netlink_message *m) {
f23ab4dc 101 while (m && --m->n_ref == 0) {
3dd215e0
TG
102 unsigned i;
103
65f568bb 104 free(m->hdr);
3dd215e0 105
9f5bbfe3 106 for (i = 0; i <= m->n_containers; i++)
f663aeb8 107 free(m->containers[i].attributes);
3dd215e0 108
f23ab4dc 109 sd_netlink_message *t = m;
82e4eda6
DH
110 m = m->next;
111 free(t);
65f568bb
TG
112 }
113
114 return NULL;
115}
116
de157fe2 117int sd_netlink_message_get_type(const sd_netlink_message *m, uint16_t *type) {
65f568bb
TG
118 assert_return(m, -EINVAL);
119 assert_return(type, -EINVAL);
120
121 *type = m->hdr->nlmsg_type;
122
123 return 0;
124}
125
c06cb593
SS
126int sd_netlink_message_set_flags(sd_netlink_message *m, uint16_t flags) {
127 assert_return(m, -EINVAL);
128 assert_return(flags, -EINVAL);
129
130 m->hdr->nlmsg_flags = flags;
131
132 return 0;
133}
134
de157fe2 135int sd_netlink_message_is_broadcast(const sd_netlink_message *m) {
1f0db3ed
TG
136 assert_return(m, -EINVAL);
137
3f42446d 138 return m->broadcast;
1f0db3ed
TG
139}
140
4ebe732c
ZJS
141/* If successful the updated message will be correctly aligned, if
142 unsuccessful the old message is untouched. */
1c4baffc 143static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *data, size_t data_length) {
6497a8aa 144 size_t message_length;
65f568bb
TG
145 struct nlmsghdr *new_hdr;
146 struct rtattr *rta;
5a081409 147 unsigned i;
7ca1d319 148 int offset;
65f568bb 149
33125ac5
TG
150 assert(m);
151 assert(m->hdr);
e5c4350b 152 assert(!m->sealed);
33125ac5 153 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
6497a8aa 154 assert(!data || data_length > 0);
4ebe732c
ZJS
155
156 /* get the new message size (with padding at the end) */
6497a8aa 157 message_length = m->hdr->nlmsg_len + RTA_SPACE(data_length);
65f568bb 158
05d0c2e3
JT
159 /* buffer should be smaller than both one page or 8K to be accepted by the kernel */
160 if (message_length > MIN(page_size(), 8192UL))
161 return -ENOBUFS;
162
65f568bb
TG
163 /* realloc to fit the new attribute */
164 new_hdr = realloc(m->hdr, message_length);
165 if (!new_hdr)
166 return -ENOMEM;
167 m->hdr = new_hdr;
168
169 /* get pointer to the attribute we are about to add */
6497a8aa
YW
170 rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
171
172 rtattr_append_attribute_internal(rta, type, data, data_length);
65f568bb 173
5a081409
TG
174 /* if we are inside containers, extend them */
175 for (i = 0; i < m->n_containers; i++)
6497a8aa 176 GET_CONTAINER(m, i)->rta_len += RTA_SPACE(data_length);
7ca1d319 177
4ebe732c 178 /* update message size */
6497a8aa 179 offset = m->hdr->nlmsg_len;
4ebe732c
ZJS
180 m->hdr->nlmsg_len = message_length;
181
6497a8aa 182 /* return old message size */
7ca1d319 183 return offset;
65f568bb
TG
184}
185
6c14ad61 186static int message_attribute_has_type(sd_netlink_message *m, size_t *out_size, uint16_t attribute_type, uint16_t data_type) {
d8e538ec
TG
187 const NLType *type;
188 int r;
189
6c14ad61
DH
190 assert(m);
191
f663aeb8 192 r = type_system_get_type(m->containers[m->n_containers].type_system, &type, attribute_type);
d8e538ec
TG
193 if (r < 0)
194 return r;
195
817d1cd8 196 if (type_get_type(type) != data_type)
d8e538ec
TG
197 return -EINVAL;
198
6c14ad61
DH
199 if (out_size)
200 *out_size = type_get_size(type);
201 return 0;
d8e538ec
TG
202}
203
1c4baffc 204int sd_netlink_message_append_string(sd_netlink_message *m, unsigned short type, const char *data) {
d8e538ec 205 size_t length, size;
0a0dc69b 206 int r;
65f568bb
TG
207
208 assert_return(m, -EINVAL);
e5c4350b 209 assert_return(!m->sealed, -EPERM);
65f568bb
TG
210 assert_return(data, -EINVAL);
211
6c14ad61 212 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_STRING);
0a0dc69b
TG
213 if (r < 0)
214 return r;
65f568bb 215
d8e538ec 216 if (size) {
3072eecf
LP
217 length = strnlen(data, size+1);
218 if (length > size)
d8e538ec
TG
219 return -EINVAL;
220 } else
221 length = strlen(data);
33125ac5 222
d8e538ec 223 r = add_rtattr(m, type, data, length + 1);
0a0dc69b
TG
224 if (r < 0)
225 return r;
226
227 return 0;
228}
229
6d725977
YW
230int sd_netlink_message_append_strv(sd_netlink_message *m, unsigned short type, char * const *data) {
231 size_t length, size;
232 char * const *p;
233 int r;
234
235 assert_return(m, -EINVAL);
236 assert_return(!m->sealed, -EPERM);
237 assert_return(data, -EINVAL);
238
239 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_STRING);
240 if (r < 0)
241 return r;
242
243 STRV_FOREACH(p, data) {
244 if (size) {
245 length = strnlen(*p, size+1);
246 if (length > size)
247 return -EINVAL;
248 } else
249 length = strlen(*p);
250
251 r = add_rtattr(m, type, *p, length + 1);
252 if (r < 0)
253 return r;
254 }
255
256 return 0;
257}
258
c06aead0
SS
259int sd_netlink_message_append_flag(sd_netlink_message *m, unsigned short type) {
260 size_t size;
261 int r;
262
263 assert_return(m, -EINVAL);
264 assert_return(!m->sealed, -EPERM);
265
266 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_FLAG);
267 if (r < 0)
268 return r;
269
270 r = add_rtattr(m, type, NULL, 0);
271 if (r < 0)
272 return r;
273
274 return 0;
275}
276
1c4baffc 277int sd_netlink_message_append_u8(sd_netlink_message *m, unsigned short type, uint8_t data) {
7b179640
SS
278 int r;
279
280 assert_return(m, -EINVAL);
281 assert_return(!m->sealed, -EPERM);
282
6c14ad61 283 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
7b179640
SS
284 if (r < 0)
285 return r;
286
7b179640
SS
287 r = add_rtattr(m, type, &data, sizeof(uint8_t));
288 if (r < 0)
289 return r;
290
291 return 0;
292}
293
1c4baffc 294int sd_netlink_message_append_u16(sd_netlink_message *m, unsigned short type, uint16_t data) {
01b36069
TG
295 int r;
296
297 assert_return(m, -EINVAL);
e5c4350b 298 assert_return(!m->sealed, -EPERM);
01b36069 299
6c14ad61 300 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
01b36069
TG
301 if (r < 0)
302 return r;
303
01b36069
TG
304 r = add_rtattr(m, type, &data, sizeof(uint16_t));
305 if (r < 0)
306 return r;
307
308 return 0;
309}
310
1c4baffc 311int sd_netlink_message_append_u32(sd_netlink_message *m, unsigned short type, uint32_t data) {
0a0dc69b
TG
312 int r;
313
314 assert_return(m, -EINVAL);
e5c4350b 315 assert_return(!m->sealed, -EPERM);
0a0dc69b 316
6c14ad61 317 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
0a0dc69b
TG
318 if (r < 0)
319 return r;
320
4d47756b 321 r = add_rtattr(m, type, &data, sizeof(uint32_t));
0a0dc69b
TG
322 if (r < 0)
323 return r;
324
325 return 0;
326}
327
81962db7
SS
328int sd_netlink_message_append_u64(sd_netlink_message *m, unsigned short type, uint64_t data) {
329 int r;
330
331 assert_return(m, -EINVAL);
332 assert_return(!m->sealed, -EPERM);
333
334 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U64);
335 if (r < 0)
336 return r;
337
338 r = add_rtattr(m, type, &data, sizeof(uint64_t));
339 if (r < 0)
340 return r;
341
342 return 0;
343}
344
aa550d2a
SS
345int sd_netlink_message_append_s8(sd_netlink_message *m, unsigned short type, int8_t data) {
346 int r;
347
348 assert_return(m, -EINVAL);
349 assert_return(!m->sealed, -EPERM);
350
351 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_S8);
352 if (r < 0)
353 return r;
354
355 r = add_rtattr(m, type, &data, sizeof(int8_t));
356 if (r < 0)
357 return r;
358
359 return 0;
360}
361
362int sd_netlink_message_append_s16(sd_netlink_message *m, unsigned short type, int16_t data) {
363 int r;
364
365 assert_return(m, -EINVAL);
366 assert_return(!m->sealed, -EPERM);
367
368 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_S16);
369 if (r < 0)
370 return r;
371
372 r = add_rtattr(m, type, &data, sizeof(int16_t));
373 if (r < 0)
374 return r;
375
376 return 0;
377}
378
379int sd_netlink_message_append_s32(sd_netlink_message *m, unsigned short type, int32_t data) {
380 int r;
381
382 assert_return(m, -EINVAL);
383 assert_return(!m->sealed, -EPERM);
384
385 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_S32);
386 if (r < 0)
387 return r;
388
389 r = add_rtattr(m, type, &data, sizeof(int32_t));
390 if (r < 0)
391 return r;
392
393 return 0;
394}
395
396int sd_netlink_message_append_s64(sd_netlink_message *m, unsigned short type, int64_t data) {
397 int r;
398
399 assert_return(m, -EINVAL);
400 assert_return(!m->sealed, -EPERM);
401
402 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_S64);
403 if (r < 0)
404 return r;
405
406 r = add_rtattr(m, type, &data, sizeof(int64_t));
407 if (r < 0)
408 return r;
409
410 return 0;
411}
412
17af840b
SS
413int sd_netlink_message_append_data(sd_netlink_message *m, unsigned short type, const void *data, size_t len) {
414 int r;
415
416 assert_return(m, -EINVAL);
417 assert_return(!m->sealed, -EPERM);
418
b8cc01a2 419 r = add_rtattr(m, type, data, len);
17af840b
SS
420 if (r < 0)
421 return r;
422
423 return 0;
424}
425
67b19a49 426int netlink_message_append_in_addr_union(sd_netlink_message *m, unsigned short type, int family, const union in_addr_union *data) {
0a0dc69b
TG
427 int r;
428
429 assert_return(m, -EINVAL);
e5c4350b 430 assert_return(!m->sealed, -EPERM);
0a0dc69b 431 assert_return(data, -EINVAL);
67b19a49 432 assert_return(IN_SET(family, AF_INET, AF_INET6), -EINVAL);
0a0dc69b 433
6c14ad61 434 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
0a0dc69b
TG
435 if (r < 0)
436 return r;
437
67b19a49 438 r = add_rtattr(m, type, data, FAMILY_ADDRESS_SIZE(family));
0a0dc69b
TG
439 if (r < 0)
440 return r;
441
442 return 0;
443}
444
67b19a49
YW
445int sd_netlink_message_append_in_addr(sd_netlink_message *m, unsigned short type, const struct in_addr *data) {
446 return netlink_message_append_in_addr_union(m, type, AF_INET, (const union in_addr_union *) data);
447}
abd48ec8 448
67b19a49
YW
449int sd_netlink_message_append_in6_addr(sd_netlink_message *m, unsigned short type, const struct in6_addr *data) {
450 return netlink_message_append_in_addr_union(m, type, AF_INET6, (const union in_addr_union *) data);
abd48ec8
YW
451}
452
67b19a49 453int netlink_message_append_sockaddr_union(sd_netlink_message *m, unsigned short type, const union sockaddr_union *data) {
abd48ec8
YW
454 int r;
455
456 assert_return(m, -EINVAL);
457 assert_return(!m->sealed, -EPERM);
458 assert_return(data, -EINVAL);
67b19a49 459 assert_return(IN_SET(data->sa.sa_family, AF_INET, AF_INET6), -EINVAL);
abd48ec8
YW
460
461 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_SOCKADDR);
462 if (r < 0)
463 return r;
464
67b19a49 465 r = add_rtattr(m, type, data, data->sa.sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
abd48ec8
YW
466 if (r < 0)
467 return r;
468
469 return 0;
470}
471
67b19a49
YW
472int sd_netlink_message_append_sockaddr_in(sd_netlink_message *m, unsigned short type, const struct sockaddr_in *data) {
473 return netlink_message_append_sockaddr_union(m, type, (const union sockaddr_union *) data);
474}
0a0dc69b 475
67b19a49
YW
476int sd_netlink_message_append_sockaddr_in6(sd_netlink_message *m, unsigned short type, const struct sockaddr_in6 *data) {
477 return netlink_message_append_sockaddr_union(m, type, (const union sockaddr_union *) data);
0a0dc69b
TG
478}
479
1c4baffc 480int sd_netlink_message_append_ether_addr(sd_netlink_message *m, unsigned short type, const struct ether_addr *data) {
0a0dc69b
TG
481 int r;
482
483 assert_return(m, -EINVAL);
e5c4350b 484 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
485 assert_return(data, -EINVAL);
486
6c14ad61 487 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
d8e538ec
TG
488 if (r < 0)
489 return r;
0a0dc69b 490
b9eaf3d1 491 r = add_rtattr(m, type, data, ETH_ALEN);
0a0dc69b
TG
492 if (r < 0)
493 return r;
494
495 return 0;
65f568bb
TG
496}
497
4fc8a29a
TR
498int netlink_message_append_hw_addr(sd_netlink_message *m, unsigned short type, const hw_addr_data *data) {
499 int r;
500
501 assert_return(m, -EINVAL);
502 assert_return(!m->sealed, -EPERM);
503 assert_return(data, -EINVAL);
504 assert_return(data->length > 0, -EINVAL);
505
506 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
507 if (r < 0)
508 return r;
509
510 r = add_rtattr(m, type, data->addr.bytes, data->length);
511 if (r < 0)
512 return r;
513
514 return 0;
515}
516
1c4baffc 517int sd_netlink_message_append_cache_info(sd_netlink_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
aba496a5
UTL
518 int r;
519
520 assert_return(m, -EINVAL);
521 assert_return(!m->sealed, -EPERM);
522 assert_return(info, -EINVAL);
523
6c14ad61 524 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
aba496a5
UTL
525 if (r < 0)
526 return r;
527
528 r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
529 if (r < 0)
530 return r;
531
532 return 0;
533}
534
1c4baffc 535int sd_netlink_message_open_container(sd_netlink_message *m, unsigned short type) {
d8e538ec
TG
536 size_t size;
537 int r;
33125ac5 538
65f568bb 539 assert_return(m, -EINVAL);
e5c4350b 540 assert_return(!m->sealed, -EPERM);
179b4db4
BR
541 /* m->containers[m->n_containers + 1] is accessed both in read and write. Prevent access out of bound */
542 assert_return(m->n_containers < (RTNL_CONTAINER_DEPTH - 1), -ERANGE);
33125ac5 543
6c14ad61 544 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_NESTED);
4af7b60d
TG
545 if (r < 0) {
546 const NLTypeSystemUnion *type_system_union;
547 int family;
548
6c14ad61 549 r = message_attribute_has_type(m, &size, type, NETLINK_TYPE_UNION);
4af7b60d
TG
550 if (r < 0)
551 return r;
4af7b60d 552
89489ef7 553 r = sd_rtnl_message_get_family(m, &family);
4af7b60d
TG
554 if (r < 0)
555 return r;
556
f663aeb8 557 r = type_system_get_type_system_union(m->containers[m->n_containers].type_system, &type_system_union, type);
4af7b60d
TG
558 if (r < 0)
559 return r;
560
561 r = type_system_union_protocol_get_type_system(type_system_union,
f663aeb8 562 &m->containers[m->n_containers + 1].type_system,
4af7b60d
TG
563 family);
564 if (r < 0)
565 return r;
566 } else {
f663aeb8
TG
567 r = type_system_get_type_system(m->containers[m->n_containers].type_system,
568 &m->containers[m->n_containers + 1].type_system,
4af7b60d
TG
569 type);
570 if (r < 0)
571 return r;
572 }
31a4e153 573
fcf81a54 574 r = add_rtattr(m, type | NLA_F_NESTED, NULL, size);
d8e538ec
TG
575 if (r < 0)
576 return r;
577
313cefa1 578 m->containers[m->n_containers++].offset = r;
7ca1d319 579
d8e538ec
TG
580 return 0;
581}
582
1c4baffc 583int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned short type, const char *key) {
d8e538ec
TG
584 const NLTypeSystemUnion *type_system_union;
585 int r;
586
587 assert_return(m, -EINVAL);
588 assert_return(!m->sealed, -EPERM);
179b4db4 589 assert_return(m->n_containers < (RTNL_CONTAINER_DEPTH - 1), -ERANGE);
d8e538ec 590
f663aeb8 591 r = type_system_get_type_system_union(m->containers[m->n_containers].type_system, &type_system_union, type);
d8e538ec
TG
592 if (r < 0)
593 return r;
594
595 r = type_system_union_get_type_system(type_system_union,
f663aeb8 596 &m->containers[m->n_containers + 1].type_system,
d8e538ec
TG
597 key);
598 if (r < 0)
599 return r;
33125ac5 600
1c4baffc 601 r = sd_netlink_message_append_string(m, type_system_union->match, key);
d8e538ec
TG
602 if (r < 0)
603 return r;
604
05d0c2e3 605 /* do we ever need non-null size */
da041d69 606 r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
d8e538ec
TG
607 if (r < 0)
608 return r;
609
313cefa1 610 m->containers[m->n_containers++].offset = r;
7ca1d319 611
d8e538ec 612 return 0;
33125ac5
TG
613}
614
1c4baffc 615int sd_netlink_message_close_container(sd_netlink_message *m) {
33125ac5 616 assert_return(m, -EINVAL);
e5c4350b 617 assert_return(!m->sealed, -EPERM);
5a081409 618 assert_return(m->n_containers > 0, -EINVAL);
33125ac5 619
f663aeb8 620 m->containers[m->n_containers].type_system = NULL;
05d0c2e3
JT
621 m->containers[m->n_containers].offset = 0;
622 m->n_containers--;
623
624 return 0;
625}
626
627int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type) {
628 int r;
629
630 assert_return(m, -EINVAL);
631 assert_return(!m->sealed, -EPERM);
179b4db4 632 assert_return(m->n_containers < (RTNL_CONTAINER_DEPTH - 1), -ERANGE);
05d0c2e3
JT
633
634 r = add_rtattr(m, type | NLA_F_NESTED, NULL, 0);
635 if (r < 0)
636 return r;
637
638 m->containers[m->n_containers].offset = r;
639 m->n_containers++;
640 m->containers[m->n_containers].type_system = m->containers[m->n_containers - 1].type_system;
641
642 return 0;
643}
644
645int sd_netlink_message_cancel_array(sd_netlink_message *m) {
646 unsigned i;
647 uint32_t rta_len;
648
649 assert_return(m, -EINVAL);
650 assert_return(!m->sealed, -EPERM);
651 assert_return(m->n_containers > 1, -EINVAL);
652
653 rta_len = GET_CONTAINER(m, (m->n_containers - 1))->rta_len;
654
655 for (i = 0; i < m->n_containers; i++)
656 GET_CONTAINER(m, i)->rta_len -= rta_len;
657
658 m->hdr->nlmsg_len -= rta_len;
659
313cefa1 660 m->n_containers--;
05d0c2e3 661 m->containers[m->n_containers].type_system = NULL;
33125ac5
TG
662
663 return 0;
664}
665
3b4e3ebb
YW
666static int netlink_message_read_internal(
667 sd_netlink_message *m,
668 unsigned short type,
669 void **ret_data,
670 bool *ret_net_byteorder) {
671
f663aeb8 672 struct netlink_attribute *attribute;
f66eeb6b
TG
673 struct rtattr *rta;
674
44caa5e7
SS
675 assert_return(m, -EINVAL);
676 assert_return(m->sealed, -EPERM);
f1dd72c2 677
0610939d 678 assert(m->n_containers < RTNL_CONTAINER_DEPTH);
e4a1e68d
YW
679
680 if (!m->containers[m->n_containers].attributes)
681 return -ENODATA;
48fb0d13
YW
682
683 if (type >= m->containers[m->n_containers].n_attributes)
684 return -ENODATA;
44caa5e7 685
f663aeb8
TG
686 attribute = &m->containers[m->n_containers].attributes[type];
687
f1dd72c2 688 if (attribute->offset == 0)
44caa5e7
SS
689 return -ENODATA;
690
f663aeb8 691 rta = (struct rtattr*)((uint8_t *) m->hdr + attribute->offset);
44caa5e7 692
3b4e3ebb
YW
693 if (ret_data)
694 *ret_data = RTA_DATA(rta);
f66eeb6b 695
3b4e3ebb
YW
696 if (ret_net_byteorder)
697 *ret_net_byteorder = attribute->net_byteorder;
4c641e99 698
f66eeb6b 699 return RTA_PAYLOAD(rta);
44caa5e7
SS
700}
701
926062f0
SS
702int sd_netlink_message_read(sd_netlink_message *m, unsigned short type, size_t size, void *data) {
703 void *attr_data;
704 int r;
705
706 assert_return(m, -EINVAL);
707
708 r = netlink_message_read_internal(m, type, &attr_data, NULL);
709 if (r < 0)
710 return r;
711
712 if ((size_t) r < size)
713 return -EIO;
714
715 if (data)
716 memcpy(data, attr_data, size);
717
5dc3dbe8 718 return r;
926062f0
SS
719}
720
de52a83c
YW
721int sd_netlink_message_read_data(sd_netlink_message *m, unsigned short type, size_t *ret_size, void **ret_data) {
722 void *attr_data, *data;
723 int r;
724
725 assert_return(m, -EINVAL);
726
727 r = netlink_message_read_internal(m, type, &attr_data, NULL);
728 if (r < 0)
729 return r;
730
731 if (ret_data) {
732 data = memdup(attr_data, r);
733 if (!data)
734 return -ENOMEM;
735
736 *ret_data = data;
737 }
738
739 if (ret_size)
740 *ret_size = r;
741
742 return r;
743}
744
59d4103f
YW
745int sd_netlink_message_read_string_strdup(sd_netlink_message *m, unsigned short type, char **data) {
746 void *attr_data;
747 char *str;
748 int r;
749
750 assert_return(m, -EINVAL);
751
752 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_STRING);
753 if (r < 0)
754 return r;
755
756 r = netlink_message_read_internal(m, type, &attr_data, NULL);
757 if (r < 0)
758 return r;
759
760 if (data) {
761 str = strndup(attr_data, r);
762 if (!str)
763 return -ENOMEM;
764
765 *data = str;
766 }
767
768 return 0;
769}
770
1c4baffc 771int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, const char **data) {
44caa5e7
SS
772 int r;
773 void *attr_data;
774
73ae2b7d
TG
775 assert_return(m, -EINVAL);
776
6c14ad61 777 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_STRING);
d8e538ec
TG
778 if (r < 0)
779 return r;
44caa5e7 780
4c641e99 781 r = netlink_message_read_internal(m, type, &attr_data, NULL);
f66eeb6b 782 if (r < 0)
44caa5e7 783 return r;
f66eeb6b
TG
784 else if (strnlen(attr_data, r) >= (size_t) r)
785 return -EIO;
44caa5e7 786
73ae2b7d
TG
787 if (data)
788 *data = (const char *) attr_data;
44caa5e7
SS
789
790 return 0;
791}
792
1c4baffc 793int sd_netlink_message_read_u8(sd_netlink_message *m, unsigned short type, uint8_t *data) {
44caa5e7
SS
794 int r;
795 void *attr_data;
796
73ae2b7d
TG
797 assert_return(m, -EINVAL);
798
6c14ad61 799 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U8);
d8e538ec
TG
800 if (r < 0)
801 return r;
44caa5e7 802
4c641e99 803 r = netlink_message_read_internal(m, type, &attr_data, NULL);
f66eeb6b 804 if (r < 0)
44caa5e7 805 return r;
f66eeb6b
TG
806 else if ((size_t) r < sizeof(uint8_t))
807 return -EIO;
44caa5e7 808
73ae2b7d
TG
809 if (data)
810 *data = *(uint8_t *) attr_data;
44caa5e7
SS
811
812 return 0;
813}
814
1c4baffc 815int sd_netlink_message_read_u16(sd_netlink_message *m, unsigned short type, uint16_t *data) {
44caa5e7 816 void *attr_data;
4c641e99
TG
817 bool net_byteorder;
818 int r;
44caa5e7 819
73ae2b7d
TG
820 assert_return(m, -EINVAL);
821
6c14ad61 822 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U16);
d8e538ec
TG
823 if (r < 0)
824 return r;
44caa5e7 825
4c641e99 826 r = netlink_message_read_internal(m, type, &attr_data, &net_byteorder);
f66eeb6b 827 if (r < 0)
44caa5e7 828 return r;
f66eeb6b
TG
829 else if ((size_t) r < sizeof(uint16_t))
830 return -EIO;
44caa5e7 831
4c641e99
TG
832 if (data) {
833 if (net_byteorder)
834 *data = be16toh(*(uint16_t *) attr_data);
835 else
836 *data = *(uint16_t *) attr_data;
837 }
44caa5e7
SS
838
839 return 0;
840}
841
1c4baffc 842int sd_netlink_message_read_u32(sd_netlink_message *m, unsigned short type, uint32_t *data) {
44caa5e7 843 void *attr_data;
4c641e99
TG
844 bool net_byteorder;
845 int r;
44caa5e7 846
73ae2b7d
TG
847 assert_return(m, -EINVAL);
848
6c14ad61 849 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_U32);
d8e538ec
TG
850 if (r < 0)
851 return r;
44caa5e7 852
4c641e99 853 r = netlink_message_read_internal(m, type, &attr_data, &net_byteorder);
f66eeb6b 854 if (r < 0)
44caa5e7 855 return r;
6d185cff 856 else if ((size_t) r < sizeof(uint32_t))
f66eeb6b 857 return -EIO;
44caa5e7 858
4c641e99
TG
859 if (data) {
860 if (net_byteorder)
861 *data = be32toh(*(uint32_t *) attr_data);
862 else
863 *data = *(uint32_t *) attr_data;
864 }
44caa5e7
SS
865
866 return 0;
867}
868
1c4baffc 869int sd_netlink_message_read_ether_addr(sd_netlink_message *m, unsigned short type, struct ether_addr *data) {
4e9e7f18
SS
870 int r;
871 void *attr_data;
872
73ae2b7d
TG
873 assert_return(m, -EINVAL);
874
6c14ad61 875 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
d8e538ec
TG
876 if (r < 0)
877 return r;
4e9e7f18 878
4c641e99 879 r = netlink_message_read_internal(m, type, &attr_data, NULL);
f66eeb6b 880 if (r < 0)
4e9e7f18 881 return r;
6d185cff 882 else if ((size_t) r < sizeof(struct ether_addr))
f66eeb6b 883 return -EIO;
4e9e7f18 884
73ae2b7d
TG
885 if (data)
886 memcpy(data, attr_data, sizeof(struct ether_addr));
4e9e7f18
SS
887
888 return 0;
889}
890
4fc8a29a
TR
891int netlink_message_read_hw_addr(sd_netlink_message *m, unsigned short type, hw_addr_data *data) {
892 int r;
893 void *attr_data;
894
895 assert_return(m, -EINVAL);
896
897 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_ETHER_ADDR);
898 if (r < 0)
899 return r;
900
901 r = netlink_message_read_internal(m, type, &attr_data, NULL);
902 if (r < 0)
903 return r;
904 else if ((size_t) r > sizeof(union hw_addr_union))
905 return -EIO;
906
907 if (data) {
908 memcpy(data->addr.bytes, attr_data, r);
909 data->length = r;
910 }
911
912 return 0;
913}
914
1c4baffc 915int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short type, struct ifa_cacheinfo *info) {
aba496a5
UTL
916 int r;
917 void *attr_data;
918
73ae2b7d
TG
919 assert_return(m, -EINVAL);
920
6c14ad61 921 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_CACHE_INFO);
aba496a5
UTL
922 if (r < 0)
923 return r;
924
4c641e99 925 r = netlink_message_read_internal(m, type, &attr_data, NULL);
aba496a5
UTL
926 if (r < 0)
927 return r;
6d185cff 928 else if ((size_t) r < sizeof(struct ifa_cacheinfo))
aba496a5
UTL
929 return -EIO;
930
73ae2b7d
TG
931 if (info)
932 memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
aba496a5
UTL
933
934 return 0;
935}
936
f29b6b37 937int netlink_message_read_in_addr_union(sd_netlink_message *m, unsigned short type, int family, union in_addr_union *data) {
4e9e7f18 938 void *attr_data;
f29b6b37 939 int r;
4e9e7f18 940
73ae2b7d 941 assert_return(m, -EINVAL);
f29b6b37 942 assert_return(IN_SET(family, AF_INET, AF_INET6), -EINVAL);
73ae2b7d 943
6c14ad61 944 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
d8e538ec
TG
945 if (r < 0)
946 return r;
4e9e7f18 947
4c641e99 948 r = netlink_message_read_internal(m, type, &attr_data, NULL);
f66eeb6b 949 if (r < 0)
4e9e7f18 950 return r;
f29b6b37 951 else if ((size_t) r < FAMILY_ADDRESS_SIZE(family))
f66eeb6b 952 return -EIO;
4e9e7f18 953
73ae2b7d 954 if (data)
f29b6b37 955 memcpy(data, attr_data, FAMILY_ADDRESS_SIZE(family));
4e9e7f18
SS
956
957 return 0;
958}
959
f29b6b37
YW
960int sd_netlink_message_read_in_addr(sd_netlink_message *m, unsigned short type, struct in_addr *data) {
961 union in_addr_union u;
4e9e7f18 962 int r;
4e9e7f18 963
f29b6b37
YW
964 r = netlink_message_read_in_addr_union(m, type, AF_INET, &u);
965 if (r >= 0 && data)
966 *data = u.in;
73ae2b7d 967
f29b6b37
YW
968 return r;
969}
4e9e7f18 970
f29b6b37
YW
971int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type, struct in6_addr *data) {
972 union in_addr_union u;
973 int r;
4e9e7f18 974
f29b6b37
YW
975 r = netlink_message_read_in_addr_union(m, type, AF_INET6, &u);
976 if (r >= 0 && data)
977 *data = u.in6;
4e9e7f18 978
f29b6b37 979 return r;
4e9e7f18
SS
980}
981
3b4e3ebb
YW
982int sd_netlink_message_has_flag(sd_netlink_message *m, unsigned short type) {
983 void *attr_data;
984 int r;
985
986 assert_return(m, -EINVAL);
987
988 /* This returns 1 when the flag is set, 0 when not set, negative errno on error. */
989
990 r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_FLAG);
991 if (r < 0)
992 return r;
993
994 r = netlink_message_read_internal(m, type, &attr_data, NULL);
995 if (r == -ENODATA)
996 return 0;
997 if (r < 0)
998 return r;
999
1000 return 1;
1001}
1002
8f3c1859
YW
1003int sd_netlink_message_read_strv(sd_netlink_message *m, unsigned short container_type, unsigned short type_id, char ***ret) {
1004 _cleanup_strv_free_ char **s = NULL;
1005 const NLTypeSystem *type_system;
1006 const NLType *nl_type;
1007 struct rtattr *rta;
1008 void *container;
f501c251 1009 size_t rt_len;
8f3c1859
YW
1010 int r;
1011
1012 assert_return(m, -EINVAL);
1013 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
1014
1015 r = type_system_get_type(m->containers[m->n_containers].type_system,
1016 &nl_type,
1017 container_type);
1018 if (r < 0)
1019 return r;
1020
1021 if (type_get_type(nl_type) != NETLINK_TYPE_NESTED)
1022 return -EINVAL;
1023
1024 r = type_system_get_type_system(m->containers[m->n_containers].type_system,
1025 &type_system,
1026 container_type);
1027 if (r < 0)
1028 return r;
1029
1030 r = type_system_get_type(type_system, &nl_type, type_id);
1031 if (r < 0)
1032 return r;
1033
1034 if (type_get_type(nl_type) != NETLINK_TYPE_STRING)
1035 return -EINVAL;
1036
1037 r = netlink_message_read_internal(m, container_type, &container, NULL);
1038 if (r < 0)
1039 return r;
1040
f501c251 1041 rt_len = (size_t) r;
8f3c1859
YW
1042 rta = container;
1043
f501c251
YW
1044 /* RTA_OK() macro compares with rta->rt_len, which is unsigned short, and
1045 * LGTM.com analysis does not like the type difference. Hence, here we
1046 * introduce an unsigned short variable as a workaround. */
1047 unsigned short len = rt_len;
1048 for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
8f3c1859
YW
1049 unsigned short type;
1050
1051 type = RTA_TYPE(rta);
1052 if (type != type_id)
1053 continue;
1054
1055 r = strv_extend(&s, RTA_DATA(rta));
1056 if (r < 0)
1057 return r;
1058 }
1059
1060 *ret = TAKE_PTR(s);
1061 return 0;
1062}
1063
f663aeb8
TG
1064static int netlink_container_parse(sd_netlink_message *m,
1065 struct netlink_container *container,
f663aeb8 1066 struct rtattr *rta,
f501c251 1067 size_t rt_len) {
f663aeb8 1068 _cleanup_free_ struct netlink_attribute *attributes = NULL;
5fc5e2f5 1069 size_t n_allocated = 0;
4203fc8b 1070
f501c251
YW
1071 /* RTA_OK() macro compares with rta->rt_len, which is unsigned short, and
1072 * LGTM.com analysis does not like the type difference. Hence, here we
1073 * introduce an unsigned short variable as a workaround. */
1074 unsigned short len = rt_len;
1075 for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
f663aeb8
TG
1076 unsigned short type;
1077
4203fc8b
TG
1078 type = RTA_TYPE(rta);
1079
5fc5e2f5
YW
1080 if (!GREEDY_REALLOC0(attributes, n_allocated, type + 1))
1081 return -ENOMEM;
4203fc8b 1082
f1dd72c2 1083 if (attributes[type].offset != 0)
4203fc8b
TG
1084 log_debug("rtnl: message parse - overwriting repeated attribute");
1085
f663aeb8 1086 attributes[type].offset = (uint8_t *) rta - (uint8_t *) m->hdr;
4c641e99
TG
1087 attributes[type].nested = RTA_FLAGS(rta) & NLA_F_NESTED;
1088 attributes[type].net_byteorder = RTA_FLAGS(rta) & NLA_F_NET_BYTEORDER;
4203fc8b
TG
1089 }
1090
ae2a15bc 1091 container->attributes = TAKE_PTR(attributes);
5fc5e2f5 1092 container->n_attributes = n_allocated;
4203fc8b
TG
1093
1094 return 0;
1095}
1096
817d1cd8 1097int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short type_id) {
d8e538ec
TG
1098 const NLType *nl_type;
1099 const NLTypeSystem *type_system;
3dd215e0 1100 void *container;
817d1cd8 1101 uint16_t type;
d8e538ec
TG
1102 size_t size;
1103 int r;
3dd215e0
TG
1104
1105 assert_return(m, -EINVAL);
179b4db4 1106 assert_return(m->n_containers < (RTNL_CONTAINER_DEPTH - 1), -EINVAL);
3dd215e0 1107
f663aeb8 1108 r = type_system_get_type(m->containers[m->n_containers].type_system,
d8e538ec 1109 &nl_type,
817d1cd8 1110 type_id);
3dd215e0
TG
1111 if (r < 0)
1112 return r;
3dd215e0 1113
817d1cd8
DH
1114 type = type_get_type(nl_type);
1115
1116 if (type == NETLINK_TYPE_NESTED) {
f663aeb8 1117 r = type_system_get_type_system(m->containers[m->n_containers].type_system,
d8e538ec 1118 &type_system,
817d1cd8 1119 type_id);
d8e538ec
TG
1120 if (r < 0)
1121 return r;
817d1cd8 1122 } else if (type == NETLINK_TYPE_UNION) {
d8e538ec 1123 const NLTypeSystemUnion *type_system_union;
d8e538ec 1124
f663aeb8 1125 r = type_system_get_type_system_union(m->containers[m->n_containers].type_system,
d8e538ec 1126 &type_system_union,
817d1cd8 1127 type_id);
d8e538ec
TG
1128 if (r < 0)
1129 return r;
1130
4af7b60d
TG
1131 switch (type_system_union->match_type) {
1132 case NL_MATCH_SIBLING:
1133 {
1134 const char *key;
1135
1c4baffc 1136 r = sd_netlink_message_read_string(m, type_system_union->match, &key);
4af7b60d
TG
1137 if (r < 0)
1138 return r;
1139
1140 r = type_system_union_get_type_system(type_system_union,
1141 &type_system,
1142 key);
1143 if (r < 0)
1144 return r;
1145
1146 break;
1147 }
1148 case NL_MATCH_PROTOCOL:
1149 {
1150 int family;
1151
89489ef7 1152 r = sd_rtnl_message_get_family(m, &family);
4af7b60d
TG
1153 if (r < 0)
1154 return r;
1155
1156 r = type_system_union_protocol_get_type_system(type_system_union,
1157 &type_system,
1158 family);
1159 if (r < 0)
1160 return r;
1161
1162 break;
1163 }
1164 default:
1c4baffc 1165 assert_not_reached("sd-netlink: invalid type system union type");
4af7b60d 1166 }
d8e538ec
TG
1167 } else
1168 return -EINVAL;
1169
4c641e99 1170 r = netlink_message_read_internal(m, type_id, &container, NULL);
3dd215e0
TG
1171 if (r < 0)
1172 return r;
620fd5d4 1173
6d185cff 1174 size = (size_t) r;
313cefa1 1175 m->n_containers++;
3dd215e0 1176
f663aeb8
TG
1177 r = netlink_container_parse(m,
1178 &m->containers[m->n_containers],
f663aeb8
TG
1179 container,
1180 size);
d8e538ec 1181 if (r < 0) {
313cefa1 1182 m->n_containers--;
3dd215e0 1183 return r;
d8e538ec 1184 }
3dd215e0 1185
f663aeb8 1186 m->containers[m->n_containers].type_system = type_system;
3dd215e0
TG
1187
1188 return 0;
1189}
1190
5fc5e2f5
YW
1191int sd_netlink_message_enter_array(sd_netlink_message *m, unsigned short type_id) {
1192 void *container;
1193 size_t size;
1194 int r;
1195
1196 assert_return(m, -EINVAL);
179b4db4 1197 assert_return(m->n_containers < (RTNL_CONTAINER_DEPTH - 1), -EINVAL);
5fc5e2f5
YW
1198
1199 r = netlink_message_read_internal(m, type_id, &container, NULL);
1200 if (r < 0)
1201 return r;
1202
1203 size = (size_t) r;
5fc5e2f5
YW
1204 m->n_containers++;
1205
1206 r = netlink_container_parse(m,
1207 &m->containers[m->n_containers],
1208 container,
1209 size);
1210 if (r < 0) {
1211 m->n_containers--;
1212 return r;
1213 }
1214
1215 m->containers[m->n_containers].type_system = m->containers[m->n_containers - 1].type_system;
1216
1217 return 0;
1218}
1219
1c4baffc 1220int sd_netlink_message_exit_container(sd_netlink_message *m) {
e5c4350b
TG
1221 assert_return(m, -EINVAL);
1222 assert_return(m->sealed, -EINVAL);
1223 assert_return(m->n_containers > 0, -EINVAL);
1224
a1e58e8e 1225 m->containers[m->n_containers].attributes = mfree(m->containers[m->n_containers].attributes);
f663aeb8 1226 m->containers[m->n_containers].type_system = NULL;
3dd215e0 1227
313cefa1 1228 m->n_containers--;
e5c4350b
TG
1229
1230 return 0;
1231}
1232
1c4baffc 1233uint32_t rtnl_message_get_serial(sd_netlink_message *m) {
65f568bb 1234 assert(m);
9d0db178 1235 assert(m->hdr);
65f568bb
TG
1236
1237 return m->hdr->nlmsg_seq;
1238}
1239
de157fe2 1240int sd_netlink_message_is_error(const sd_netlink_message *m) {
45af44d4
TG
1241 assert_return(m, 0);
1242 assert_return(m->hdr, 0);
1243
1244 return m->hdr->nlmsg_type == NLMSG_ERROR;
1245}
1246
de157fe2 1247int sd_netlink_message_get_errno(const sd_netlink_message *m) {
65f568bb
TG
1248 struct nlmsgerr *err;
1249
e16bcf98 1250 assert_return(m, -EINVAL);
9d0db178 1251 assert_return(m->hdr, -EINVAL);
65f568bb 1252
1c4baffc 1253 if (!sd_netlink_message_is_error(m))
65f568bb
TG
1254 return 0;
1255
1256 err = NLMSG_DATA(m->hdr);
1257
1258 return err->error;
1259}
1260
e4a1e68d
YW
1261static int netlink_message_parse_error(sd_netlink_message *m) {
1262 struct nlmsgerr *err = NLMSG_DATA(m->hdr);
1263 size_t hlen = sizeof(struct nlmsgerr);
1264
1265 /* no TLVs, nothing to do here */
1266 if (!(m->hdr->nlmsg_flags & NLM_F_ACK_TLVS))
1267 return 0;
1268
1269 /* if NLM_F_CAPPED is set then the inner err msg was capped */
1270 if (!(m->hdr->nlmsg_flags & NLM_F_CAPPED))
1271 hlen += err->msg.nlmsg_len - sizeof(struct nlmsghdr);
1272
1273 if (m->hdr->nlmsg_len <= NLMSG_SPACE(hlen))
1274 return 0;
1275
1276 return netlink_container_parse(m,
1277 &m->containers[m->n_containers],
1278 (struct rtattr*)((uint8_t*) NLMSG_DATA(m->hdr) + hlen),
1279 NLMSG_PAYLOAD(m->hdr, hlen));
1280}
1281
4e8f0ef9 1282int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *genl) {
817d1cd8
DH
1283 const NLType *nl_type;
1284 uint16_t type;
1285 size_t size;
3dd215e0
TG
1286 unsigned i;
1287 int r;
0fc7531b
TG
1288
1289 assert_return(m, -EINVAL);
4e8f0ef9 1290 assert_return(genl || m->protocol != NETLINK_GENERIC, -EINVAL);
0fc7531b 1291
3dd215e0
TG
1292 /* don't allow appending to message once parsed */
1293 if (!m->sealed)
1294 rtnl_message_seal(m);
1295
1f6b4113 1296 for (i = 1; i <= m->n_containers; i++)
a1e58e8e 1297 m->containers[i].attributes = mfree(m->containers[i].attributes);
3dd215e0
TG
1298
1299 m->n_containers = 0;
1300
ece174c5 1301 if (m->containers[0].attributes)
3dd215e0
TG
1302 /* top-level attributes have already been parsed */
1303 return 0;
3dd215e0 1304
d8e538ec
TG
1305 assert(m->hdr);
1306
4e8f0ef9 1307 r = type_system_root_get_type(genl, &nl_type, m->hdr->nlmsg_type);
d8e538ec
TG
1308 if (r < 0)
1309 return r;
1310
817d1cd8
DH
1311 type = type_get_type(nl_type);
1312 size = type_get_size(nl_type);
1313
1314 if (type == NETLINK_TYPE_NESTED) {
c658008f 1315 const NLTypeSystem *type_system;
d8e538ec 1316
817d1cd8 1317 type_get_type_system(nl_type, &type_system);
d8e538ec 1318
f663aeb8 1319 m->containers[0].type_system = type_system;
d8e538ec 1320
e4a1e68d
YW
1321 if (sd_netlink_message_is_error(m))
1322 r = netlink_message_parse_error(m);
1323 else
1324 r = netlink_container_parse(m,
1325 &m->containers[m->n_containers],
1326 (struct rtattr*)((uint8_t*) NLMSG_DATA(m->hdr) + NLMSG_ALIGN(size)),
1327 NLMSG_PAYLOAD(m->hdr, size));
d8e538ec
TG
1328 if (r < 0)
1329 return r;
0fc7531b
TG
1330 }
1331
1332 return 0;
1333}
3dd215e0 1334
1c4baffc 1335void rtnl_message_seal(sd_netlink_message *m) {
3dd215e0
TG
1336 assert(m);
1337 assert(!m->sealed);
1338
1339 m->sealed = true;
1340}
1403f45a 1341
1c4baffc 1342sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m) {
1403f45a
TG
1343 assert_return(m, NULL);
1344
1345 return m->next;
1346}