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