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