]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-rtnl/rtnl-message.c
sd-rtnl: add multi-part message test
[thirdparty/systemd.git] / src / libsystemd / sd-rtnl / rtnl-message.c
CommitLineData
65f568bb
TG
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <netinet/in.h>
23#include <netinet/ether.h>
24#include <stdbool.h>
25#include <unistd.h>
d8e538ec 26#include <linux/netlink.h>
31a4e153 27#include <linux/veth.h>
9a6704a8
SS
28#include <linux/if.h>
29#include <linux/ip.h>
30#include <linux/if_tunnel.h>
3dd215e0 31#include <linux/if_bridge.h>
65f568bb
TG
32
33#include "util.h"
34#include "refcnt.h"
d5eff740 35#include "missing.h"
65f568bb
TG
36
37#include "sd-rtnl.h"
3815f36f 38#include "rtnl-util.h"
65f568bb 39#include "rtnl-internal.h"
d8e538ec 40#include "rtnl-types.h"
65f568bb 41
31a4e153 42#define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL)
e5c4350b 43#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
4ebe732c 44
1b89cf56 45static int message_new_empty(sd_rtnl *rtnl, sd_rtnl_message **ret) {
65f568bb
TG
46 sd_rtnl_message *m;
47
48 assert_return(ret, -EINVAL);
65f568bb 49
8c578303
TG
50 /* Note that 'rtnl' is curretly unused, if we start using it internally
51 we must take care to avoid problems due to mutual references between
52 busses and their queued messages. See sd-bus.
53 */
54
65f568bb
TG
55 m = new0(sd_rtnl_message, 1);
56 if (!m)
57 return -ENOMEM;
58
65f568bb
TG
59 m->n_ref = REFCNT_INIT;
60
65f568bb
TG
61 m->sealed = false;
62
63 *ret = m;
64
65 return 0;
66}
67
d8e538ec 68int message_new(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t type) {
1b89cf56 69 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
d8e538ec
TG
70 const NLType *nl_type;
71 size_t size;
72 int r;
73
74 r = type_system_get_type(NULL, &nl_type, type);
75 if (r < 0)
76 return r;
77
78 assert(nl_type->type == NLA_NESTED);
79
1b89cf56 80 r = message_new_empty(rtnl, &m);
d8e538ec
TG
81 if (r < 0)
82 return r;
83
1b89cf56
TG
84 size = NLMSG_SPACE(nl_type->size);
85
86 assert(size >= sizeof(struct nlmsghdr));
87 m->hdr = malloc0(size);
88 if (!m->hdr)
89 return -ENOMEM;
90
91 m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
92
93 m->container_type_system[0] = nl_type->type_system;
94 m->hdr->nlmsg_len = size;
95 m->hdr->nlmsg_type = type;
96
97 *ret = m;
98 m = NULL;
d8e538ec
TG
99
100 return 0;
101}
102
1f01fb4f
TG
103int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
104 struct rtmsg *rtm;
105
5a723174
TG
106 assert_return(m, -EINVAL);
107 assert_return(m->hdr, -EINVAL);
3815f36f 108 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
5a723174 109
1f01fb4f
TG
110 rtm = NLMSG_DATA(m->hdr);
111
5a723174
TG
112 if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
113 (rtm->rtm_family == AF_INET6 && prefixlen > 128))
114 return -ERANGE;
115
1f01fb4f
TG
116 rtm->rtm_dst_len = prefixlen;
117
5c1d3fc9
UTL
118 return 0;
119}
120
121int sd_rtnl_message_route_set_scope(sd_rtnl_message *m, unsigned char scope) {
122 struct rtmsg *rtm;
123
124 assert_return(m, -EINVAL);
125 assert_return(m->hdr, -EINVAL);
126 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
127
128 rtm = NLMSG_DATA(m->hdr);
129
130 rtm->rtm_scope = scope;
131
1f01fb4f
TG
132 return 0;
133}
134
151b9b96
LP
135int sd_rtnl_message_new_route(sd_rtnl *rtnl, sd_rtnl_message **ret,
136 uint16_t nlmsg_type, unsigned char rtm_family) {
03d7e632
TG
137 struct rtmsg *rtm;
138 int r;
139
3815f36f 140 assert_return(rtnl_message_type_is_route(nlmsg_type), -EINVAL);
1f01fb4f 141 assert_return(rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
03d7e632
TG
142 assert_return(ret, -EINVAL);
143
d8e538ec 144 r = message_new(rtnl, ret, nlmsg_type);
03d7e632
TG
145 if (r < 0)
146 return r;
147
03d7e632
TG
148 if (nlmsg_type == RTM_NEWROUTE)
149 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
150
151 rtm = NLMSG_DATA((*ret)->hdr);
152
153 rtm->rtm_family = rtm_family;
1f01fb4f
TG
154 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
155 rtm->rtm_type = RTN_UNICAST;
156 rtm->rtm_table = RT_TABLE_MAIN;
157 rtm->rtm_protocol = RTPROT_BOOT;
03d7e632
TG
158
159 return 0;
160}
161
5d4795f3 162int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags, unsigned change) {
fc25d7f8
TG
163 struct ifinfomsg *ifi;
164
5a723174
TG
165 assert_return(m, -EINVAL);
166 assert_return(m->hdr, -EINVAL);
3815f36f 167 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
a7b74db6 168 assert_return(change, -EINVAL);
5a723174 169
fc25d7f8
TG
170 ifi = NLMSG_DATA(m->hdr);
171
172 ifi->ifi_flags = flags;
a7b74db6 173 ifi->ifi_change = change;
fc25d7f8
TG
174
175 return 0;
176}
177
178int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) {
179 struct ifinfomsg *ifi;
180
5a723174
TG
181 assert_return(m, -EINVAL);
182 assert_return(m->hdr, -EINVAL);
3815f36f 183 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
5a723174 184
fc25d7f8
TG
185 ifi = NLMSG_DATA(m->hdr);
186
187 ifi->ifi_type = type;
188
189 return 0;
190}
191
151b9b96
LP
192int sd_rtnl_message_new_link(sd_rtnl *rtnl, sd_rtnl_message **ret,
193 uint16_t nlmsg_type, int index) {
65f568bb
TG
194 struct ifinfomsg *ifi;
195 int r;
196
3815f36f 197 assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL);
6a8402d9 198 assert_return(nlmsg_type != RTM_DELLINK || index > 0, -EINVAL);
65f568bb
TG
199 assert_return(ret, -EINVAL);
200
d8e538ec 201 r = message_new(rtnl, ret, nlmsg_type);
65f568bb
TG
202 if (r < 0)
203 return r;
204
33125ac5 205 if (nlmsg_type == RTM_NEWLINK)
6a8402d9 206 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
65f568bb 207
dabfa9d1 208 ifi = NLMSG_DATA((*ret)->hdr);
65f568bb
TG
209
210 ifi->ifi_family = AF_UNSPEC;
211 ifi->ifi_index = index;
65f568bb
TG
212
213 return 0;
214}
215
5a723174
TG
216int sd_rtnl_message_addr_set_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
217 struct ifaddrmsg *ifa;
218
219 assert_return(m, -EINVAL);
220 assert_return(m->hdr, -EINVAL);
3815f36f 221 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
5a723174
TG
222
223 ifa = NLMSG_DATA(m->hdr);
224
225 if ((ifa->ifa_family == AF_INET && prefixlen > 32) ||
226 (ifa->ifa_family == AF_INET6 && prefixlen > 128))
227 return -ERANGE;
228
229 ifa->ifa_prefixlen = prefixlen;
230
231 return 0;
232}
233
234int sd_rtnl_message_addr_set_flags(sd_rtnl_message *m, unsigned char flags) {
235 struct ifaddrmsg *ifa;
236
237 assert_return(m, -EINVAL);
238 assert_return(m->hdr, -EINVAL);
3815f36f 239 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
5a723174
TG
240
241 ifa = NLMSG_DATA(m->hdr);
242
243 ifa->ifa_flags = flags;
244
245 return 0;
246}
247
248int sd_rtnl_message_addr_set_scope(sd_rtnl_message *m, unsigned char scope) {
249 struct ifaddrmsg *ifa;
250
251 assert_return(m, -EINVAL);
252 assert_return(m->hdr, -EINVAL);
3815f36f 253 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
5a723174
TG
254
255 ifa = NLMSG_DATA(m->hdr);
256
257 ifa->ifa_scope = scope;
258
259 return 0;
260}
261
e00d77dd
TG
262int sd_rtnl_message_addr_get_family(sd_rtnl_message *m, unsigned char *family) {
263 struct ifaddrmsg *ifa;
264
265 assert_return(m, -EINVAL);
266 assert_return(m->hdr, -EINVAL);
267 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
268 assert_return(family, -EINVAL);
269
270 ifa = NLMSG_DATA(m->hdr);
271
272 *family = ifa->ifa_family;
273
274 return 0;
275}
276
277int sd_rtnl_message_addr_get_scope(sd_rtnl_message *m, unsigned char *scope) {
278 struct ifaddrmsg *ifa;
279
280 assert_return(m, -EINVAL);
281 assert_return(m->hdr, -EINVAL);
282 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
283 assert_return(scope, -EINVAL);
284
285 ifa = NLMSG_DATA(m->hdr);
286
287 *scope = ifa->ifa_scope;
288
289 return 0;
290}
291
292int sd_rtnl_message_addr_get_flags(sd_rtnl_message *m, unsigned char *flags) {
293 struct ifaddrmsg *ifa;
294
295 assert_return(m, -EINVAL);
296 assert_return(m->hdr, -EINVAL);
297 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
298 assert_return(flags, -EINVAL);
299
300 ifa = NLMSG_DATA(m->hdr);
301
302 *flags = ifa->ifa_flags;
303
304 return 0;
305}
306
307int sd_rtnl_message_addr_get_ifindex(sd_rtnl_message *m, int *ifindex) {
308 struct ifaddrmsg *ifa;
309
310 assert_return(m, -EINVAL);
311 assert_return(m->hdr, -EINVAL);
312 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
313 assert_return(ifindex, -EINVAL);
314
315 ifa = NLMSG_DATA(m->hdr);
316
317 *ifindex = ifa->ifa_index;
318
319 return 0;
320}
321
151b9b96
LP
322int sd_rtnl_message_new_addr(sd_rtnl *rtnl, sd_rtnl_message **ret,
323 uint16_t nlmsg_type, int index,
324 unsigned char family) {
65f568bb
TG
325 struct ifaddrmsg *ifa;
326 int r;
327
3815f36f 328 assert_return(rtnl_message_type_is_addr(nlmsg_type), -EINVAL);
b9ef681b
TG
329 assert_return((nlmsg_type == RTM_GETADDR && index == 0) ||
330 index > 0, -EINVAL);
331 assert_return((nlmsg_type == RTM_GETADDR && family == AF_UNSPEC) ||
332 family == AF_INET || family == AF_INET6, -EINVAL);
65f568bb
TG
333 assert_return(ret, -EINVAL);
334
d8e538ec 335 r = message_new(rtnl, ret, nlmsg_type);
65f568bb
TG
336 if (r < 0)
337 return r;
338
b9ef681b 339 if (nlmsg_type == RTM_GETADDR)
818dc5e7 340 (*ret)->hdr->nlmsg_flags |= NLM_F_DUMP;
65f568bb 341
dabfa9d1 342 ifa = NLMSG_DATA((*ret)->hdr);
65f568bb 343
65f568bb 344 ifa->ifa_index = index;
5a723174
TG
345 ifa->ifa_family = family;
346 if (family == AF_INET)
347 ifa->ifa_prefixlen = 32;
348 else if (family == AF_INET6)
349 ifa->ifa_prefixlen = 128;
65f568bb
TG
350
351 return 0;
352}
353
aba496a5
UTL
354int sd_rtnl_message_new_addr_update(sd_rtnl *rtnl, sd_rtnl_message **ret,
355 int index, unsigned char family) {
356 int r;
357
358 r = sd_rtnl_message_new_addr(rtnl, ret, RTM_NEWADDR, index, family);
359 if (r < 0)
360 return r;
361
362 (*ret)->hdr->nlmsg_flags |= NLM_F_REPLACE;
363
364 return 0;
365}
366
65f568bb
TG
367sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
368 if (m)
369 assert_se(REFCNT_INC(m->n_ref) >= 2);
370
371 return m;
372}
373
374sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
375 if (m && REFCNT_DEC(m->n_ref) <= 0) {
3dd215e0
TG
376 unsigned i;
377
65f568bb 378 free(m->hdr);
3dd215e0 379
9f5bbfe3 380 for (i = 0; i <= m->n_containers; i++)
3dd215e0
TG
381 free(m->rta_offset_tb[i]);
382
1403f45a
TG
383 sd_rtnl_message_unref(m->next);
384
65f568bb
TG
385 free(m);
386 }
387
388 return NULL;
389}
390
dabfa9d1 391int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
65f568bb
TG
392 assert_return(m, -EINVAL);
393 assert_return(type, -EINVAL);
394
395 *type = m->hdr->nlmsg_type;
396
397 return 0;
398}
399
1f0db3ed
TG
400int sd_rtnl_message_is_broadcast(sd_rtnl_message *m) {
401 assert_return(m, -EINVAL);
402
403 return !m->hdr->nlmsg_pid;
404}
405
33125ac5
TG
406int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
407 struct ifinfomsg *ifi;
408
409 assert_return(m, -EINVAL);
9d0db178 410 assert_return(m->hdr, -EINVAL);
3815f36f 411 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
33125ac5 412 assert_return(ifindex, -EINVAL);
33125ac5
TG
413
414 ifi = NLMSG_DATA(m->hdr);
415
416 *ifindex = ifi->ifi_index;
417
418 return 0;
419}
420
50b3c42f
TG
421int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
422 struct ifinfomsg *ifi;
423
424 assert_return(m, -EINVAL);
9d0db178 425 assert_return(m->hdr, -EINVAL);
3815f36f 426 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
50b3c42f 427 assert_return(flags, -EINVAL);
50b3c42f
TG
428
429 ifi = NLMSG_DATA(m->hdr);
430
431 *flags = ifi->ifi_flags;
432
433 return 0;
434}
435
4ebe732c
ZJS
436/* If successful the updated message will be correctly aligned, if
437 unsuccessful the old message is untouched. */
65f568bb 438static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
dabfa9d1 439 uint32_t rta_length, message_length;
65f568bb
TG
440 struct nlmsghdr *new_hdr;
441 struct rtattr *rta;
8e337e64 442 char *padding;
5a081409 443 unsigned i;
65f568bb 444
33125ac5
TG
445 assert(m);
446 assert(m->hdr);
e5c4350b 447 assert(!m->sealed);
33125ac5
TG
448 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
449 assert(!data || data_length > 0);
5a081409 450 assert(data || m->n_containers < RTNL_CONTAINER_DEPTH);
65f568bb 451
8e337e64 452 /* get the size of the new rta attribute (with padding at the end) */
65f568bb 453 rta_length = RTA_LENGTH(data_length);
4ebe732c
ZJS
454
455 /* get the new message size (with padding at the end) */
65f568bb
TG
456 message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
457
458 /* realloc to fit the new attribute */
459 new_hdr = realloc(m->hdr, message_length);
460 if (!new_hdr)
461 return -ENOMEM;
462 m->hdr = new_hdr;
463
464 /* get pointer to the attribute we are about to add */
465 rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
65f568bb 466
5a081409
TG
467 /* if we are inside containers, extend them */
468 for (i = 0; i < m->n_containers; i++)
469 GET_CONTAINER(m, i)->rta_len += message_length - m->hdr->nlmsg_len;
33125ac5 470
65f568bb
TG
471 /* fill in the attribute */
472 rta->rta_type = type;
473 rta->rta_len = rta_length;
33125ac5 474 if (!data) {
d8e538ec 475 //TODO: simply return this value rather than check for !data
4ebe732c 476 /* this is the start of a new container */
5a081409 477 m->container_offsets[m->n_containers ++] = m->hdr->nlmsg_len;
33125ac5
TG
478 } else {
479 /* we don't deal with the case where the user lies about the type
480 * and gives us too little data (so don't do that)
481 */
482 padding = mempcpy(RTA_DATA(rta), data, data_length);
483 /* make sure also the padding at the end of the message is initialized */
4ebe732c
ZJS
484 memzero(padding,
485 (uint8_t *) m->hdr + message_length - (uint8_t *) padding);
33125ac5 486 }
65f568bb 487
4ebe732c
ZJS
488 /* update message size */
489 m->hdr->nlmsg_len = message_length;
490
65f568bb
TG
491 return 0;
492}
493
d8e538ec
TG
494static int message_attribute_has_type(sd_rtnl_message *m, uint16_t attribute_type, uint16_t data_type) {
495 const NLType *type;
496 int r;
497
498 r = type_system_get_type(m->container_type_system[m->n_containers], &type, attribute_type);
499 if (r < 0)
500 return r;
501
502 if (type->type != data_type)
503 return -EINVAL;
504
505 return type->size;
506}
507
0a0dc69b 508int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data) {
d8e538ec 509 size_t length, size;
0a0dc69b 510 int r;
65f568bb
TG
511
512 assert_return(m, -EINVAL);
e5c4350b 513 assert_return(!m->sealed, -EPERM);
65f568bb
TG
514 assert_return(data, -EINVAL);
515
d8e538ec 516 r = message_attribute_has_type(m, type, NLA_STRING);
0a0dc69b
TG
517 if (r < 0)
518 return r;
d8e538ec
TG
519 else
520 size = (size_t)r;
65f568bb 521
d8e538ec
TG
522 if (size) {
523 length = strnlen(data, size);
524 if (length >= size)
525 return -EINVAL;
526 } else
527 length = strlen(data);
33125ac5 528
d8e538ec 529 r = add_rtattr(m, type, data, length + 1);
0a0dc69b
TG
530 if (r < 0)
531 return r;
532
533 return 0;
534}
535
7b179640 536int sd_rtnl_message_append_u8(sd_rtnl_message *m, unsigned short type, uint8_t data) {
7b179640
SS
537 int r;
538
539 assert_return(m, -EINVAL);
540 assert_return(!m->sealed, -EPERM);
541
d8e538ec 542 r = message_attribute_has_type(m, type, NLA_U8);
7b179640
SS
543 if (r < 0)
544 return r;
545
7b179640
SS
546 r = add_rtattr(m, type, &data, sizeof(uint8_t));
547 if (r < 0)
548 return r;
549
550 return 0;
551}
552
553
01b36069 554int sd_rtnl_message_append_u16(sd_rtnl_message *m, unsigned short type, uint16_t data) {
01b36069
TG
555 int r;
556
557 assert_return(m, -EINVAL);
e5c4350b 558 assert_return(!m->sealed, -EPERM);
01b36069 559
d8e538ec 560 r = message_attribute_has_type(m, type, NLA_U16);
01b36069
TG
561 if (r < 0)
562 return r;
563
01b36069
TG
564 r = add_rtattr(m, type, &data, sizeof(uint16_t));
565 if (r < 0)
566 return r;
567
568 return 0;
569}
570
0a0dc69b 571int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) {
0a0dc69b
TG
572 int r;
573
574 assert_return(m, -EINVAL);
e5c4350b 575 assert_return(!m->sealed, -EPERM);
0a0dc69b 576
d8e538ec 577 r = message_attribute_has_type(m, type, NLA_U32);
0a0dc69b
TG
578 if (r < 0)
579 return r;
580
4d47756b 581 r = add_rtattr(m, type, &data, sizeof(uint32_t));
0a0dc69b
TG
582 if (r < 0)
583 return r;
584
585 return 0;
586}
587
588int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) {
0a0dc69b
TG
589 int r;
590
591 assert_return(m, -EINVAL);
e5c4350b 592 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
593 assert_return(data, -EINVAL);
594
d8e538ec 595 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
0a0dc69b
TG
596 if (r < 0)
597 return r;
598
4d47756b 599 r = add_rtattr(m, type, data, sizeof(struct in_addr));
0a0dc69b
TG
600 if (r < 0)
601 return r;
602
603 return 0;
604}
605
606int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) {
0a0dc69b
TG
607 int r;
608
609 assert_return(m, -EINVAL);
e5c4350b 610 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
611 assert_return(data, -EINVAL);
612
d8e538ec 613 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
0a0dc69b
TG
614 if (r < 0)
615 return r;
616
4d47756b 617 r = add_rtattr(m, type, data, sizeof(struct in6_addr));
0a0dc69b
TG
618 if (r < 0)
619 return r;
620
621 return 0;
622}
623
624int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) {
0a0dc69b
TG
625 int r;
626
627 assert_return(m, -EINVAL);
e5c4350b 628 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
629 assert_return(data, -EINVAL);
630
d8e538ec
TG
631 r = message_attribute_has_type(m, type, NLA_ETHER_ADDR);
632 if (r < 0)
633 return r;
0a0dc69b 634
b9eaf3d1 635 r = add_rtattr(m, type, data, ETH_ALEN);
0a0dc69b
TG
636 if (r < 0)
637 return r;
638
639 return 0;
65f568bb
TG
640}
641
aba496a5
UTL
642int sd_rtnl_message_append_cache_info(sd_rtnl_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
643 int r;
644
645 assert_return(m, -EINVAL);
646 assert_return(!m->sealed, -EPERM);
647 assert_return(info, -EINVAL);
648
649 r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
650 if (r < 0)
651 return r;
652
653 r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
654 if (r < 0)
655 return r;
656
657 return 0;
658}
659
ee3a6a51 660int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
d8e538ec
TG
661 size_t size;
662 int r;
33125ac5 663
65f568bb 664 assert_return(m, -EINVAL);
e5c4350b 665 assert_return(!m->sealed, -EPERM);
33125ac5 666
d8e538ec
TG
667 r = message_attribute_has_type(m, type, NLA_NESTED);
668 if (r < 0)
669 return r;
670 else
671 size = (size_t)r;
33125ac5 672
d8e538ec
TG
673 r = type_system_get_type_system(m->container_type_system[m->n_containers],
674 &m->container_type_system[m->n_containers + 1],
675 type);
676 if (r < 0)
677 return r;
31a4e153 678
d8e538ec
TG
679 r = add_rtattr(m, type, NULL, size);
680 if (r < 0)
681 return r;
682
683 return 0;
684}
685
686int sd_rtnl_message_open_container_union(sd_rtnl_message *m, unsigned short type, const char *key) {
687 const NLTypeSystemUnion *type_system_union;
688 int r;
689
690 assert_return(m, -EINVAL);
691 assert_return(!m->sealed, -EPERM);
692
693 r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
694 if (r < 0)
695 return r;
696
697 r = type_system_union_get_type_system(type_system_union,
698 &m->container_type_system[m->n_containers + 1],
699 key);
700 if (r < 0)
701 return r;
33125ac5 702
d8e538ec
TG
703 r = sd_rtnl_message_append_string(m, type_system_union->match, key);
704 if (r < 0)
705 return r;
706
707 /* do we evere need non-null size */
708 r = add_rtattr(m, type, NULL, 0);
709 if (r < 0)
710 return r;
711
712 return 0;
33125ac5
TG
713}
714
d8e538ec 715
33125ac5
TG
716int sd_rtnl_message_close_container(sd_rtnl_message *m) {
717 assert_return(m, -EINVAL);
e5c4350b 718 assert_return(!m->sealed, -EPERM);
5a081409 719 assert_return(m->n_containers > 0, -EINVAL);
33125ac5 720
d8e538ec 721 m->container_type_system[m->n_containers] = NULL;
5a081409 722 m->n_containers --;
33125ac5
TG
723
724 return 0;
725}
726
44caa5e7 727int rtnl_message_read_internal(sd_rtnl_message *m, unsigned short type, void **data) {
f66eeb6b
TG
728 struct rtattr *rta;
729
44caa5e7
SS
730 assert_return(m, -EINVAL);
731 assert_return(m->sealed, -EPERM);
732 assert_return(data, -EINVAL);
d8e538ec
TG
733 assert(m->n_containers <= RTNL_CONTAINER_DEPTH);
734 assert(m->rta_offset_tb[m->n_containers]);
735 assert(type < m->rta_tb_size[m->n_containers]);
44caa5e7 736
3dd215e0 737 if(!m->rta_offset_tb[m->n_containers][type])
44caa5e7
SS
738 return -ENODATA;
739
3dd215e0 740 rta = (struct rtattr*)((uint8_t *) m->hdr + m->rta_offset_tb[m->n_containers][type]);
44caa5e7 741
f66eeb6b
TG
742 *data = RTA_DATA(rta);
743
744 return RTA_PAYLOAD(rta);
44caa5e7
SS
745}
746
747int sd_rtnl_message_read_string(sd_rtnl_message *m, unsigned short type, char **data) {
748 int r;
749 void *attr_data;
750
d8e538ec
TG
751 r = message_attribute_has_type(m, type, NLA_STRING);
752 if (r < 0)
753 return r;
44caa5e7
SS
754
755 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 756 if (r < 0)
44caa5e7 757 return r;
f66eeb6b
TG
758 else if (strnlen(attr_data, r) >= (size_t) r)
759 return -EIO;
44caa5e7
SS
760
761 *data = (char *) attr_data;
762
763 return 0;
764}
765
766int sd_rtnl_message_read_u8(sd_rtnl_message *m, unsigned short type, uint8_t *data) {
767 int r;
768 void *attr_data;
769
d8e538ec
TG
770 r = message_attribute_has_type(m, type, NLA_U8);
771 if (r < 0)
772 return r;
44caa5e7
SS
773
774 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 775 if (r < 0)
44caa5e7 776 return r;
f66eeb6b
TG
777 else if ((size_t) r < sizeof(uint8_t))
778 return -EIO;
44caa5e7
SS
779
780 *data = *(uint8_t *) attr_data;
781
782 return 0;
783}
784
785int sd_rtnl_message_read_u16(sd_rtnl_message *m, unsigned short type, uint16_t *data) {
786 int r;
787 void *attr_data;
788
d8e538ec
TG
789 r = message_attribute_has_type(m, type, NLA_U16);
790 if (r < 0)
791 return r;
44caa5e7
SS
792
793 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 794 if (r < 0)
44caa5e7 795 return r;
f66eeb6b
TG
796 else if ((size_t) r < sizeof(uint16_t))
797 return -EIO;
44caa5e7
SS
798
799 *data = *(uint16_t *) attr_data;
800
801 return 0;
802}
803
804int sd_rtnl_message_read_u32(sd_rtnl_message *m, unsigned short type, uint32_t *data) {
805 int r;
806 void *attr_data;
807
d8e538ec
TG
808 r = message_attribute_has_type(m, type, NLA_U32);
809 if (r < 0)
810 return r;
44caa5e7
SS
811
812 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 813 if (r < 0)
44caa5e7 814 return r;
f66eeb6b
TG
815 else if ((size_t)r < sizeof(uint32_t))
816 return -EIO;
44caa5e7
SS
817
818 *data = *(uint32_t *) attr_data;
819
820 return 0;
821}
822
4e9e7f18
SS
823int sd_rtnl_message_read_ether_addr(sd_rtnl_message *m, unsigned short type, struct ether_addr *data) {
824 int r;
825 void *attr_data;
826
d8e538ec
TG
827 r = message_attribute_has_type(m, type, NLA_ETHER_ADDR);
828 if (r < 0)
829 return r;
4e9e7f18
SS
830
831 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 832 if (r < 0)
4e9e7f18 833 return r;
f66eeb6b
TG
834 else if ((size_t)r < sizeof(struct ether_addr))
835 return -EIO;
4e9e7f18
SS
836
837 memcpy(data, attr_data, sizeof(struct ether_addr));
838
839 return 0;
840}
841
aba496a5
UTL
842int sd_rtnl_message_read_cache_info(sd_rtnl_message *m, unsigned short type, struct ifa_cacheinfo *info) {
843 int r;
844 void *attr_data;
845
846 r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
847 if (r < 0)
848 return r;
849
850 r = rtnl_message_read_internal(m, type, &attr_data);
851 if (r < 0)
852 return r;
853 else if ((size_t)r < sizeof(struct ifa_cacheinfo))
854 return -EIO;
855
856 memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
857
858 return 0;
859}
860
4e9e7f18
SS
861int sd_rtnl_message_read_in_addr(sd_rtnl_message *m, unsigned short type, struct in_addr *data) {
862 int r;
863 void *attr_data;
864
d8e538ec
TG
865 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
866 if (r < 0)
867 return r;
4e9e7f18
SS
868
869 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 870 if (r < 0)
4e9e7f18 871 return r;
f66eeb6b
TG
872 else if ((size_t)r < sizeof(struct in_addr))
873 return -EIO;
4e9e7f18
SS
874
875 memcpy(data, attr_data, sizeof(struct in_addr));
876
877 return 0;
878}
879
880int sd_rtnl_message_read_in6_addr(sd_rtnl_message *m, unsigned short type, struct in6_addr *data) {
881 int r;
882 void *attr_data;
883
d8e538ec
TG
884 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
885 if (r < 0)
886 return r;
4e9e7f18
SS
887
888 r = rtnl_message_read_internal(m, type, &attr_data);
3dd215e0 889 if (r < 0)
4e9e7f18 890 return r;
3dd215e0
TG
891 else if ((size_t)r < sizeof(struct in6_addr))
892 return -EIO;
4e9e7f18
SS
893
894 memcpy(data, attr_data, sizeof(struct in6_addr));
895
896 return 0;
897}
898
3dd215e0 899int sd_rtnl_message_enter_container(sd_rtnl_message *m, unsigned short type) {
d8e538ec
TG
900 const NLType *nl_type;
901 const NLTypeSystem *type_system;
3dd215e0 902 void *container;
d8e538ec
TG
903 size_t size;
904 int r;
3dd215e0
TG
905
906 assert_return(m, -EINVAL);
907 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
908
d8e538ec
TG
909 r = type_system_get_type(m->container_type_system[m->n_containers],
910 &nl_type,
911 type);
3dd215e0
TG
912 if (r < 0)
913 return r;
3dd215e0 914
d8e538ec
TG
915 if (nl_type->type == NLA_NESTED) {
916 r = type_system_get_type_system(m->container_type_system[m->n_containers],
917 &type_system,
918 type);
919 if (r < 0)
920 return r;
921 } else if (nl_type->type == NLA_UNION) {
922 const NLTypeSystemUnion *type_system_union;
923 char *key;
924
925 r = type_system_get_type_system_union(m->container_type_system[m->n_containers],
926 &type_system_union,
927 type);
928 if (r < 0)
929 return r;
930
931 r = sd_rtnl_message_read_string(m, type_system_union->match, &key);
932 if (r < 0)
933 return r;
934
935 r = type_system_union_get_type_system(type_system_union,
936 &type_system,
937 key);
938 if (r < 0)
939 return r;
940 } else
941 return -EINVAL;
942
943 r = rtnl_message_read_internal(m, type, &container);
3dd215e0
TG
944 if (r < 0)
945 return r;
d8e538ec
TG
946 else
947 size = (size_t)r;
3dd215e0 948
d8e538ec 949 m->n_containers ++;
3dd215e0
TG
950
951 r = rtnl_message_parse(m,
d8e538ec
TG
952 &m->rta_offset_tb[m->n_containers],
953 &m->rta_tb_size[m->n_containers],
954 type_system->max,
3dd215e0 955 container,
d8e538ec
TG
956 size);
957 if (r < 0) {
958 m->n_containers --;
3dd215e0 959 return r;
d8e538ec 960 }
3dd215e0 961
d8e538ec 962 m->container_type_system[m->n_containers] = type_system;
3dd215e0
TG
963
964 return 0;
965}
966
e5c4350b
TG
967int sd_rtnl_message_exit_container(sd_rtnl_message *m) {
968 assert_return(m, -EINVAL);
969 assert_return(m->sealed, -EINVAL);
970 assert_return(m->n_containers > 0, -EINVAL);
971
3dd215e0
TG
972 free(m->rta_offset_tb[m->n_containers]);
973 m->rta_offset_tb[m->n_containers] = NULL;
d8e538ec 974 m->container_type_system[m->n_containers] = NULL;
3dd215e0 975
e5c4350b
TG
976 m->n_containers --;
977
978 return 0;
979}
980
3815f36f 981uint32_t rtnl_message_get_serial(sd_rtnl_message *m) {
65f568bb 982 assert(m);
9d0db178 983 assert(m->hdr);
65f568bb
TG
984
985 return m->hdr->nlmsg_seq;
986}
987
e16bcf98 988int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
65f568bb
TG
989 struct nlmsgerr *err;
990
e16bcf98 991 assert_return(m, -EINVAL);
9d0db178 992 assert_return(m->hdr, -EINVAL);
65f568bb
TG
993
994 if (m->hdr->nlmsg_type != NLMSG_ERROR)
995 return 0;
996
997 err = NLMSG_DATA(m->hdr);
998
999 return err->error;
1000}
1001
44caa5e7
SS
1002int rtnl_message_parse(sd_rtnl_message *m,
1003 size_t **rta_offset_tb,
1004 unsigned short *rta_tb_size,
1005 int max,
1006 struct rtattr *rta,
1007 unsigned int rt_len) {
e634cd40 1008 unsigned short type;
44caa5e7
SS
1009 size_t *tb;
1010
c8a7165f 1011 tb = new0(size_t, max + 1);
44caa5e7
SS
1012 if(!tb)
1013 return -ENOMEM;
1014
c8a7165f 1015 *rta_tb_size = max + 1;
44caa5e7
SS
1016
1017 for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
1018 type = rta->rta_type;
1019
aef0768e
TG
1020 /* if the kernel is newer than the headers we used
1021 when building, we ignore out-of-range attributes
1022 */
1023 if (type > max)
e634cd40 1024 continue;
e634cd40
TG
1025
1026 if (tb[type])
1027 log_debug("rtnl: message parse - overwriting repeated attribute");
1028
1029 tb[type] = (uint8_t *) rta - (uint8_t *) m->hdr;
44caa5e7
SS
1030 }
1031
1032 *rta_offset_tb = tb;
1033
1034 return 0;
1035}
1036
65f568bb
TG
1037/* returns the number of bytes sent, or a negative error code */
1038int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
d4bbdb77
TG
1039 union {
1040 struct sockaddr sa;
1041 struct sockaddr_nl nl;
1042 } addr = {
1043 .nl.nl_family = AF_NETLINK,
1044 };
65f568bb
TG
1045 ssize_t k;
1046
9d0db178
TG
1047 assert(nl);
1048 assert(m);
1049 assert(m->hdr);
65f568bb
TG
1050
1051 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
d4bbdb77 1052 0, &addr.sa, sizeof(addr));
65f568bb
TG
1053 if (k < 0)
1054 return (errno == EAGAIN) ? 0 : -errno;
1055
1056 return k;
1057}
1058
1059/* On success, the number of bytes received is returned and *ret points to the received message
1060 * which has a valid header and the correct size.
1061 * If nothing useful was received 0 is returned.
1062 * On failure, a negative error code is returned.
dabfa9d1 1063 */
1b89cf56 1064int socket_read_message(sd_rtnl *rtnl) {
1403f45a 1065 _cleanup_rtnl_message_unref_ sd_rtnl_message *first = NULL;
bc078e71
TG
1066 uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred))];
1067 struct iovec iov = {};
1068 struct msghdr msg = {
1069 .msg_iov = &iov,
1070 .msg_iovlen = 1,
1071 .msg_control = cred_buffer,
1072 .msg_controllen = sizeof(cred_buffer),
1073 };
1074 struct cmsghdr *cmsg;
4e996881 1075 bool auth = false, multi_part = false, done = false;
1b89cf56 1076 struct nlmsghdr *new_msg;
a88f77c4 1077 size_t len;
4e996881
TG
1078 int r;
1079 unsigned i;
65f568bb 1080
1b89cf56 1081 assert(rtnl);
a88f77c4 1082 assert(rtnl->rbuffer);
6fc51883 1083 assert(rtnl->rbuffer_allocated >= sizeof(struct nlmsghdr));
65f568bb 1084
6fc51883
TG
1085 /* read nothing, just get the pending message size */
1086 r = recvmsg(rtnl->fd, &msg, MSG_PEEK | MSG_TRUNC);
65f568bb 1087 if (r < 0)
a88f77c4
TG
1088 /* no data */
1089 return (errno == EAGAIN) ? 0 : -errno;
1090 else if (r == 0)
1091 /* connection was closed by the kernel */
1092 return -ECONNRESET;
6fc51883
TG
1093 else
1094 len = (size_t)r;
65f568bb 1095
a88f77c4
TG
1096 /* make room for the pending message */
1097 if (!greedy_realloc((void **)&rtnl->rbuffer,
1098 &rtnl->rbuffer_allocated,
6fc51883 1099 len, sizeof(uint8_t)))
1b89cf56 1100 return -ENOMEM;
d4bbdb77 1101
a88f77c4
TG
1102 iov.iov_base = rtnl->rbuffer;
1103 iov.iov_len = rtnl->rbuffer_allocated;
bc078e71 1104
a88f77c4 1105 r = recvmsg(rtnl->fd, &msg, MSG_TRUNC);
3dd215e0 1106 if (r < 0)
bc078e71
TG
1107 /* no data */
1108 return (errno == EAGAIN) ? 0 : -errno;
3dd215e0 1109 else if (r == 0)
bc078e71
TG
1110 /* connection was closed by the kernel */
1111 return -ECONNRESET;
3dd215e0 1112 else
1b89cf56 1113 len = (size_t)r;
3dd215e0 1114
a88f77c4
TG
1115 if (len > rtnl->rbuffer_allocated)
1116 /* message did not fit in read buffer */
1117 return -EIO;
1118
bc078e71
TG
1119 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1120 if (cmsg->cmsg_level == SOL_SOCKET &&
1121 cmsg->cmsg_type == SCM_CREDENTIALS &&
1122 cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
1123 struct ucred *ucred = (void *)CMSG_DATA(cmsg);
1124
1125 /* from the kernel */
1126 if (ucred->uid == 0 && ucred->pid == 0) {
1127 auth = true;
1128 break;
1129 }
1130 }
1131 }
1132
1133 if (!auth)
1134 /* not from the kernel, ignore */
1135 return 0;
1136
4e996881
TG
1137 if (NLMSG_OK(rtnl->rbuffer, len) && rtnl->rbuffer->nlmsg_flags & NLM_F_MULTI) {
1138 multi_part = true;
1139
1140 for (i = 0; i < rtnl->rqueue_partial_size; i++) {
1141 if (rtnl_message_get_serial(rtnl->rqueue_partial[i]) ==
1142 rtnl->rbuffer->nlmsg_seq) {
1143 first = rtnl->rqueue_partial[i];
1144 break;
1145 }
1146 }
1147 }
1148
a88f77c4 1149 for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len); new_msg = NLMSG_NEXT(new_msg, len)) {
1b89cf56
TG
1150 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
1151 const NLType *nl_type;
3dd215e0 1152
1b89cf56
TG
1153 if (new_msg->nlmsg_pid && new_msg->nlmsg_pid != rtnl->sockaddr.nl.nl_pid)
1154 /* not broadcast and not for us */
1155 continue;
3dd215e0 1156
1b89cf56 1157 if (new_msg->nlmsg_type == NLMSG_NOOP)
4e996881 1158 /* silently drop noop messages */
1b89cf56 1159 continue;
bdd13f6b 1160
4e996881
TG
1161 if (new_msg->nlmsg_type == NLMSG_DONE) {
1162 /* finished reading multi-part message */
1163 done = true;
1403f45a 1164 break;
4e996881 1165 }
1403f45a 1166
1b89cf56
TG
1167 /* check that we support this message type */
1168 r = type_system_get_type(NULL, &nl_type, new_msg->nlmsg_type);
1169 if (r < 0) {
1170 if (r == -ENOTSUP)
1171 log_debug("sd-rtnl: ignored message with unknown type: %u",
1172 new_msg->nlmsg_type);
d8e538ec 1173
1b89cf56
TG
1174 continue;
1175 }
bdd13f6b 1176
1b89cf56
TG
1177 /* check that the size matches the message type */
1178 if (new_msg->nlmsg_len < NLMSG_LENGTH(nl_type->size))
1179 continue;
65f568bb 1180
1b89cf56
TG
1181 r = message_new_empty(rtnl, &m);
1182 if (r < 0)
1183 return r;
1184
1185 m->hdr = memdup(new_msg, new_msg->nlmsg_len);
1186 if (!m->hdr)
1187 return -ENOMEM;
1188
1189 /* seal and parse the top-level message */
1190 r = sd_rtnl_message_rewind(m);
1191 if (r < 0)
1192 return r;
1193
4e996881
TG
1194 /* push the message onto the multi-part message stack */
1195 if (first)
1196 m->next = first;
1197 first = m;
1b89cf56 1198 m = NULL;
4e996881 1199 }
1403f45a 1200
4e996881
TG
1201 if (len)
1202 log_debug("sd-rtnl: discarding %zu bytes of incoming message", len);
1b89cf56 1203
4e996881
TG
1204 if (!first)
1205 return 0;
65f568bb 1206
4e996881
TG
1207 if (!multi_part || done) {
1208 /* we got a complete message, push it on the read queue */
24a02673
TG
1209 r = rtnl_rqueue_make_room(rtnl);
1210 if (r < 0)
1211 return r;
1212
4e996881
TG
1213 if (i < rtnl->rqueue_partial_size) {
1214 /* remove the message form the partial read queue */
1215 memmove(rtnl->rqueue_partial + i,rtnl->rqueue_partial + i + 1,
1216 sizeof(sd_rtnl_message*) * (rtnl->rqueue_partial_size - i - 1));
1217 rtnl->rqueue_partial_size --;
1218 }
1219
24a02673
TG
1220 rtnl->rqueue[rtnl->rqueue_size ++] = first;
1221 first = NULL;
1403f45a 1222
4e996881
TG
1223 return 1;
1224 } else {
1225 /* we only got a partial multi-part message, push it on the
1226 partial read queue */
1227 if (i < rtnl->rqueue_partial_size) {
1228 rtnl->rqueue_partial[i] = first;
1229 } else {
1230 r = rtnl_rqueue_partial_make_room(rtnl);
1231 if (r < 0)
1232 return r;
1233
1234 rtnl->rqueue_partial[rtnl->rqueue_partial_size ++] = first;
1235 }
1236 first = NULL;
1403f45a 1237
4e996881
TG
1238 return 0;
1239 }
65f568bb 1240}
0fc7531b
TG
1241
1242int sd_rtnl_message_rewind(sd_rtnl_message *m) {
d8e538ec 1243 const NLType *type;
3dd215e0
TG
1244 unsigned i;
1245 int r;
0fc7531b
TG
1246
1247 assert_return(m, -EINVAL);
0fc7531b 1248
3dd215e0
TG
1249 /* don't allow appending to message once parsed */
1250 if (!m->sealed)
1251 rtnl_message_seal(m);
1252
1253 for (i = 1; i <= m->n_containers; i++) {
1254 free(m->rta_offset_tb[i]);
1255 m->rta_offset_tb[i] = NULL;
1256 m->rta_tb_size[i] = 0;
d8e538ec 1257 m->container_type_system[i] = NULL;
3dd215e0
TG
1258 }
1259
1260 m->n_containers = 0;
1261
1262 if (m->rta_offset_tb[0]) {
1263 /* top-level attributes have already been parsed */
1264 return 0;
1265 }
1266
d8e538ec
TG
1267 assert(m->hdr);
1268
1269 r = type_system_get_type(NULL, &type, m->hdr->nlmsg_type);
1270 if (r < 0)
1271 return r;
1272
1273 if (type->type == NLA_NESTED) {
1274 const NLTypeSystem *type_system = type->type_system;
1275
1276 assert(type_system);
1277
1278 m->container_type_system[0] = type_system;
1279
1280 r = rtnl_message_parse(m,
1281 &m->rta_offset_tb[m->n_containers],
1282 &m->rta_tb_size[m->n_containers],
1283 type_system->max,
0834ff93
TG
1284 (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) +
1285 NLMSG_ALIGN(type->size)),
d8e538ec
TG
1286 NLMSG_PAYLOAD(m->hdr, type->size));
1287 if (r < 0)
1288 return r;
0fc7531b
TG
1289 }
1290
1291 return 0;
1292}
3dd215e0
TG
1293
1294void rtnl_message_seal(sd_rtnl_message *m) {
1295 assert(m);
1296 assert(!m->sealed);
1297
1298 m->sealed = true;
1299}
1403f45a
TG
1300
1301sd_rtnl_message *sd_rtnl_message_next(sd_rtnl_message *m) {
1302 assert_return(m, NULL);
1303
1304 return m->next;
1305}