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