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