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