]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-rtnl/rtnl-message.c
rtnl: message - verify that we read the pending message size from the kernel
[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 148 if (nlmsg_type == RTM_NEWROUTE)
3f781aa8 149 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
03d7e632
TG
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
6e20c8f8
TG
216int sd_rtnl_message_request_dump(sd_rtnl_message *m, int dump) {
217 assert_return(m, -EINVAL);
218 assert_return(m->hdr, -EINVAL);
219 assert_return(m->hdr->nlmsg_type == RTM_GETLINK ||
220 m->hdr->nlmsg_type == RTM_GETADDR ||
221 m->hdr->nlmsg_type == RTM_GETROUTE,
222 -EINVAL);
223
224 if (dump)
225 m->hdr->nlmsg_flags |= NLM_F_DUMP;
226 else
227 m->hdr->nlmsg_flags &= ~NLM_F_DUMP;
228
229 return 0;
230}
231
5a723174
TG
232int sd_rtnl_message_addr_set_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
233 struct ifaddrmsg *ifa;
234
235 assert_return(m, -EINVAL);
236 assert_return(m->hdr, -EINVAL);
3815f36f 237 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
5a723174
TG
238
239 ifa = NLMSG_DATA(m->hdr);
240
241 if ((ifa->ifa_family == AF_INET && prefixlen > 32) ||
242 (ifa->ifa_family == AF_INET6 && prefixlen > 128))
243 return -ERANGE;
244
245 ifa->ifa_prefixlen = prefixlen;
246
247 return 0;
248}
249
250int sd_rtnl_message_addr_set_flags(sd_rtnl_message *m, unsigned char flags) {
251 struct ifaddrmsg *ifa;
252
253 assert_return(m, -EINVAL);
254 assert_return(m->hdr, -EINVAL);
3815f36f 255 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
5a723174
TG
256
257 ifa = NLMSG_DATA(m->hdr);
258
259 ifa->ifa_flags = flags;
260
261 return 0;
262}
263
264int sd_rtnl_message_addr_set_scope(sd_rtnl_message *m, unsigned char scope) {
265 struct ifaddrmsg *ifa;
266
267 assert_return(m, -EINVAL);
268 assert_return(m->hdr, -EINVAL);
3815f36f 269 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
5a723174
TG
270
271 ifa = NLMSG_DATA(m->hdr);
272
273 ifa->ifa_scope = scope;
274
275 return 0;
276}
277
e00d77dd
TG
278int sd_rtnl_message_addr_get_family(sd_rtnl_message *m, unsigned char *family) {
279 struct ifaddrmsg *ifa;
280
281 assert_return(m, -EINVAL);
282 assert_return(m->hdr, -EINVAL);
283 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
284 assert_return(family, -EINVAL);
285
286 ifa = NLMSG_DATA(m->hdr);
287
288 *family = ifa->ifa_family;
289
290 return 0;
291}
292
f4e884dd
TG
293int sd_rtnl_message_addr_get_prefixlen(sd_rtnl_message *m, unsigned char *prefixlen) {
294 struct ifaddrmsg *ifa;
295
296 assert_return(m, -EINVAL);
297 assert_return(m->hdr, -EINVAL);
298 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
299 assert_return(prefixlen, -EINVAL);
300
301 ifa = NLMSG_DATA(m->hdr);
302
303 *prefixlen = ifa->ifa_prefixlen;
304
305 return 0;
306}
307
e00d77dd
TG
308int sd_rtnl_message_addr_get_scope(sd_rtnl_message *m, unsigned char *scope) {
309 struct ifaddrmsg *ifa;
310
311 assert_return(m, -EINVAL);
312 assert_return(m->hdr, -EINVAL);
313 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
314 assert_return(scope, -EINVAL);
315
316 ifa = NLMSG_DATA(m->hdr);
317
318 *scope = ifa->ifa_scope;
319
320 return 0;
321}
322
323int sd_rtnl_message_addr_get_flags(sd_rtnl_message *m, unsigned char *flags) {
324 struct ifaddrmsg *ifa;
325
326 assert_return(m, -EINVAL);
327 assert_return(m->hdr, -EINVAL);
328 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
329 assert_return(flags, -EINVAL);
330
331 ifa = NLMSG_DATA(m->hdr);
332
333 *flags = ifa->ifa_flags;
334
335 return 0;
336}
337
338int sd_rtnl_message_addr_get_ifindex(sd_rtnl_message *m, int *ifindex) {
339 struct ifaddrmsg *ifa;
340
341 assert_return(m, -EINVAL);
342 assert_return(m->hdr, -EINVAL);
343 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
344 assert_return(ifindex, -EINVAL);
345
346 ifa = NLMSG_DATA(m->hdr);
347
348 *ifindex = ifa->ifa_index;
349
350 return 0;
351}
352
151b9b96
LP
353int sd_rtnl_message_new_addr(sd_rtnl *rtnl, sd_rtnl_message **ret,
354 uint16_t nlmsg_type, int index,
355 unsigned char family) {
65f568bb
TG
356 struct ifaddrmsg *ifa;
357 int r;
358
3815f36f 359 assert_return(rtnl_message_type_is_addr(nlmsg_type), -EINVAL);
b9ef681b
TG
360 assert_return((nlmsg_type == RTM_GETADDR && index == 0) ||
361 index > 0, -EINVAL);
362 assert_return((nlmsg_type == RTM_GETADDR && family == AF_UNSPEC) ||
363 family == AF_INET || family == AF_INET6, -EINVAL);
65f568bb
TG
364 assert_return(ret, -EINVAL);
365
d8e538ec 366 r = message_new(rtnl, ret, nlmsg_type);
65f568bb
TG
367 if (r < 0)
368 return r;
369
b9ef681b 370 if (nlmsg_type == RTM_GETADDR)
818dc5e7 371 (*ret)->hdr->nlmsg_flags |= NLM_F_DUMP;
65f568bb 372
dabfa9d1 373 ifa = NLMSG_DATA((*ret)->hdr);
65f568bb 374
65f568bb 375 ifa->ifa_index = index;
5a723174
TG
376 ifa->ifa_family = family;
377 if (family == AF_INET)
378 ifa->ifa_prefixlen = 32;
379 else if (family == AF_INET6)
380 ifa->ifa_prefixlen = 128;
65f568bb
TG
381
382 return 0;
383}
384
aba496a5
UTL
385int sd_rtnl_message_new_addr_update(sd_rtnl *rtnl, sd_rtnl_message **ret,
386 int index, unsigned char family) {
387 int r;
388
389 r = sd_rtnl_message_new_addr(rtnl, ret, RTM_NEWADDR, index, family);
390 if (r < 0)
391 return r;
392
393 (*ret)->hdr->nlmsg_flags |= NLM_F_REPLACE;
394
395 return 0;
396}
397
65f568bb
TG
398sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
399 if (m)
400 assert_se(REFCNT_INC(m->n_ref) >= 2);
401
402 return m;
403}
404
405sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
406 if (m && REFCNT_DEC(m->n_ref) <= 0) {
3dd215e0
TG
407 unsigned i;
408
65f568bb 409 free(m->hdr);
3dd215e0 410
9f5bbfe3 411 for (i = 0; i <= m->n_containers; i++)
3dd215e0
TG
412 free(m->rta_offset_tb[i]);
413
1403f45a
TG
414 sd_rtnl_message_unref(m->next);
415
65f568bb
TG
416 free(m);
417 }
418
419 return NULL;
420}
421
dabfa9d1 422int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
65f568bb
TG
423 assert_return(m, -EINVAL);
424 assert_return(type, -EINVAL);
425
426 *type = m->hdr->nlmsg_type;
427
428 return 0;
429}
430
1f0db3ed
TG
431int sd_rtnl_message_is_broadcast(sd_rtnl_message *m) {
432 assert_return(m, -EINVAL);
433
434 return !m->hdr->nlmsg_pid;
435}
436
33125ac5
TG
437int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
438 struct ifinfomsg *ifi;
439
440 assert_return(m, -EINVAL);
9d0db178 441 assert_return(m->hdr, -EINVAL);
3815f36f 442 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
33125ac5 443 assert_return(ifindex, -EINVAL);
33125ac5
TG
444
445 ifi = NLMSG_DATA(m->hdr);
446
447 *ifindex = ifi->ifi_index;
448
449 return 0;
450}
451
50b3c42f
TG
452int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
453 struct ifinfomsg *ifi;
454
455 assert_return(m, -EINVAL);
9d0db178 456 assert_return(m->hdr, -EINVAL);
3815f36f 457 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
50b3c42f 458 assert_return(flags, -EINVAL);
50b3c42f
TG
459
460 ifi = NLMSG_DATA(m->hdr);
461
462 *flags = ifi->ifi_flags;
463
464 return 0;
465}
466
4ebe732c
ZJS
467/* If successful the updated message will be correctly aligned, if
468 unsuccessful the old message is untouched. */
65f568bb 469static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
7ca1d319
TG
470 uint32_t rta_length;
471 size_t message_length, padding_length;
65f568bb
TG
472 struct nlmsghdr *new_hdr;
473 struct rtattr *rta;
8e337e64 474 char *padding;
5a081409 475 unsigned i;
7ca1d319 476 int offset;
65f568bb 477
33125ac5
TG
478 assert(m);
479 assert(m->hdr);
e5c4350b 480 assert(!m->sealed);
33125ac5 481 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
7ca1d319
TG
482 assert(!data || data_length);
483
484 /* get offset of the new attribute */
485 offset = m->hdr->nlmsg_len;
65f568bb 486
8e337e64 487 /* get the size of the new rta attribute (with padding at the end) */
65f568bb 488 rta_length = RTA_LENGTH(data_length);
4ebe732c
ZJS
489
490 /* get the new message size (with padding at the end) */
7ca1d319 491 message_length = offset + RTA_ALIGN(rta_length);
65f568bb
TG
492
493 /* realloc to fit the new attribute */
494 new_hdr = realloc(m->hdr, message_length);
495 if (!new_hdr)
496 return -ENOMEM;
497 m->hdr = new_hdr;
498
499 /* get pointer to the attribute we are about to add */
7ca1d319 500 rta = (struct rtattr *) ((uint8_t *) m->hdr + offset);
65f568bb 501
5a081409
TG
502 /* if we are inside containers, extend them */
503 for (i = 0; i < m->n_containers; i++)
7ca1d319 504 GET_CONTAINER(m, i)->rta_len += message_length - offset;
33125ac5 505
65f568bb
TG
506 /* fill in the attribute */
507 rta->rta_type = type;
508 rta->rta_len = rta_length;
7ca1d319 509 if (data)
33125ac5
TG
510 /* we don't deal with the case where the user lies about the type
511 * and gives us too little data (so don't do that)
7ca1d319 512 */
33125ac5 513 padding = mempcpy(RTA_DATA(rta), data, data_length);
7ca1d319
TG
514 else {
515 /* if no data was passed, make sure we still initialize the padding
516 note that we can have data_length > 0 (used by some containers) */
517 padding = RTA_DATA(rta);
518 data_length = 0;
33125ac5 519 }
65f568bb 520
7ca1d319
TG
521 /* make sure also the padding at the end of the message is initialized */
522 padding_length = (uint8_t*)m->hdr + message_length - (uint8_t*)padding;
523 memzero(padding, padding_length);
524
4ebe732c
ZJS
525 /* update message size */
526 m->hdr->nlmsg_len = message_length;
527
7ca1d319 528 return offset;
65f568bb
TG
529}
530
d8e538ec
TG
531static int message_attribute_has_type(sd_rtnl_message *m, uint16_t attribute_type, uint16_t data_type) {
532 const NLType *type;
533 int r;
534
535 r = type_system_get_type(m->container_type_system[m->n_containers], &type, attribute_type);
536 if (r < 0)
537 return r;
538
539 if (type->type != data_type)
540 return -EINVAL;
541
542 return type->size;
543}
544
0a0dc69b 545int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data) {
d8e538ec 546 size_t length, size;
0a0dc69b 547 int r;
65f568bb
TG
548
549 assert_return(m, -EINVAL);
e5c4350b 550 assert_return(!m->sealed, -EPERM);
65f568bb
TG
551 assert_return(data, -EINVAL);
552
d8e538ec 553 r = message_attribute_has_type(m, type, NLA_STRING);
0a0dc69b
TG
554 if (r < 0)
555 return r;
d8e538ec
TG
556 else
557 size = (size_t)r;
65f568bb 558
d8e538ec
TG
559 if (size) {
560 length = strnlen(data, size);
561 if (length >= size)
562 return -EINVAL;
563 } else
564 length = strlen(data);
33125ac5 565
d8e538ec 566 r = add_rtattr(m, type, data, length + 1);
0a0dc69b
TG
567 if (r < 0)
568 return r;
569
570 return 0;
571}
572
7b179640 573int sd_rtnl_message_append_u8(sd_rtnl_message *m, unsigned short type, uint8_t data) {
7b179640
SS
574 int r;
575
576 assert_return(m, -EINVAL);
577 assert_return(!m->sealed, -EPERM);
578
d8e538ec 579 r = message_attribute_has_type(m, type, NLA_U8);
7b179640
SS
580 if (r < 0)
581 return r;
582
7b179640
SS
583 r = add_rtattr(m, type, &data, sizeof(uint8_t));
584 if (r < 0)
585 return r;
586
587 return 0;
588}
589
590
01b36069 591int sd_rtnl_message_append_u16(sd_rtnl_message *m, unsigned short type, uint16_t data) {
01b36069
TG
592 int r;
593
594 assert_return(m, -EINVAL);
e5c4350b 595 assert_return(!m->sealed, -EPERM);
01b36069 596
d8e538ec 597 r = message_attribute_has_type(m, type, NLA_U16);
01b36069
TG
598 if (r < 0)
599 return r;
600
01b36069
TG
601 r = add_rtattr(m, type, &data, sizeof(uint16_t));
602 if (r < 0)
603 return r;
604
605 return 0;
606}
607
0a0dc69b 608int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) {
0a0dc69b
TG
609 int r;
610
611 assert_return(m, -EINVAL);
e5c4350b 612 assert_return(!m->sealed, -EPERM);
0a0dc69b 613
d8e538ec 614 r = message_attribute_has_type(m, type, NLA_U32);
0a0dc69b
TG
615 if (r < 0)
616 return r;
617
4d47756b 618 r = add_rtattr(m, type, &data, sizeof(uint32_t));
0a0dc69b
TG
619 if (r < 0)
620 return r;
621
622 return 0;
623}
624
625int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) {
0a0dc69b
TG
626 int r;
627
628 assert_return(m, -EINVAL);
e5c4350b 629 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
630 assert_return(data, -EINVAL);
631
d8e538ec 632 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
0a0dc69b
TG
633 if (r < 0)
634 return r;
635
4d47756b 636 r = add_rtattr(m, type, data, sizeof(struct in_addr));
0a0dc69b
TG
637 if (r < 0)
638 return r;
639
640 return 0;
641}
642
643int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) {
0a0dc69b
TG
644 int r;
645
646 assert_return(m, -EINVAL);
e5c4350b 647 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
648 assert_return(data, -EINVAL);
649
d8e538ec 650 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
0a0dc69b
TG
651 if (r < 0)
652 return r;
653
4d47756b 654 r = add_rtattr(m, type, data, sizeof(struct in6_addr));
0a0dc69b
TG
655 if (r < 0)
656 return r;
657
658 return 0;
659}
660
661int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) {
0a0dc69b
TG
662 int r;
663
664 assert_return(m, -EINVAL);
e5c4350b 665 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
666 assert_return(data, -EINVAL);
667
d8e538ec
TG
668 r = message_attribute_has_type(m, type, NLA_ETHER_ADDR);
669 if (r < 0)
670 return r;
0a0dc69b 671
b9eaf3d1 672 r = add_rtattr(m, type, data, ETH_ALEN);
0a0dc69b
TG
673 if (r < 0)
674 return r;
675
676 return 0;
65f568bb
TG
677}
678
aba496a5
UTL
679int sd_rtnl_message_append_cache_info(sd_rtnl_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
680 int r;
681
682 assert_return(m, -EINVAL);
683 assert_return(!m->sealed, -EPERM);
684 assert_return(info, -EINVAL);
685
686 r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
687 if (r < 0)
688 return r;
689
690 r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
691 if (r < 0)
692 return r;
693
694 return 0;
695}
696
ee3a6a51 697int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
d8e538ec
TG
698 size_t size;
699 int r;
33125ac5 700
65f568bb 701 assert_return(m, -EINVAL);
e5c4350b 702 assert_return(!m->sealed, -EPERM);
7ca1d319 703 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE);
33125ac5 704
d8e538ec
TG
705 r = message_attribute_has_type(m, type, NLA_NESTED);
706 if (r < 0)
707 return r;
708 else
709 size = (size_t)r;
33125ac5 710
d8e538ec
TG
711 r = type_system_get_type_system(m->container_type_system[m->n_containers],
712 &m->container_type_system[m->n_containers + 1],
713 type);
714 if (r < 0)
715 return r;
31a4e153 716
d8e538ec
TG
717 r = add_rtattr(m, type, NULL, size);
718 if (r < 0)
719 return r;
720
7ca1d319
TG
721 m->container_offsets[m->n_containers ++] = r;
722
d8e538ec
TG
723 return 0;
724}
725
726int sd_rtnl_message_open_container_union(sd_rtnl_message *m, unsigned short type, const char *key) {
727 const NLTypeSystemUnion *type_system_union;
728 int r;
729
730 assert_return(m, -EINVAL);
731 assert_return(!m->sealed, -EPERM);
732
733 r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
734 if (r < 0)
735 return r;
736
737 r = type_system_union_get_type_system(type_system_union,
738 &m->container_type_system[m->n_containers + 1],
739 key);
740 if (r < 0)
741 return r;
33125ac5 742
d8e538ec
TG
743 r = sd_rtnl_message_append_string(m, type_system_union->match, key);
744 if (r < 0)
745 return r;
746
747 /* do we evere need non-null size */
748 r = add_rtattr(m, type, NULL, 0);
749 if (r < 0)
750 return r;
751
7ca1d319
TG
752 m->container_offsets[m->n_containers ++] = r;
753
d8e538ec 754 return 0;
33125ac5
TG
755}
756
d8e538ec 757
33125ac5
TG
758int sd_rtnl_message_close_container(sd_rtnl_message *m) {
759 assert_return(m, -EINVAL);
e5c4350b 760 assert_return(!m->sealed, -EPERM);
5a081409 761 assert_return(m->n_containers > 0, -EINVAL);
33125ac5 762
d8e538ec 763 m->container_type_system[m->n_containers] = NULL;
5a081409 764 m->n_containers --;
33125ac5
TG
765
766 return 0;
767}
768
44caa5e7 769int rtnl_message_read_internal(sd_rtnl_message *m, unsigned short type, void **data) {
f66eeb6b
TG
770 struct rtattr *rta;
771
44caa5e7
SS
772 assert_return(m, -EINVAL);
773 assert_return(m->sealed, -EPERM);
774 assert_return(data, -EINVAL);
d8e538ec
TG
775 assert(m->n_containers <= RTNL_CONTAINER_DEPTH);
776 assert(m->rta_offset_tb[m->n_containers]);
777 assert(type < m->rta_tb_size[m->n_containers]);
44caa5e7 778
3dd215e0 779 if(!m->rta_offset_tb[m->n_containers][type])
44caa5e7
SS
780 return -ENODATA;
781
3dd215e0 782 rta = (struct rtattr*)((uint8_t *) m->hdr + m->rta_offset_tb[m->n_containers][type]);
44caa5e7 783
f66eeb6b
TG
784 *data = RTA_DATA(rta);
785
786 return RTA_PAYLOAD(rta);
44caa5e7
SS
787}
788
789int sd_rtnl_message_read_string(sd_rtnl_message *m, unsigned short type, char **data) {
790 int r;
791 void *attr_data;
792
d8e538ec
TG
793 r = message_attribute_has_type(m, type, NLA_STRING);
794 if (r < 0)
795 return r;
44caa5e7
SS
796
797 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 798 if (r < 0)
44caa5e7 799 return r;
f66eeb6b
TG
800 else if (strnlen(attr_data, r) >= (size_t) r)
801 return -EIO;
44caa5e7
SS
802
803 *data = (char *) attr_data;
804
805 return 0;
806}
807
808int sd_rtnl_message_read_u8(sd_rtnl_message *m, unsigned short type, uint8_t *data) {
809 int r;
810 void *attr_data;
811
d8e538ec
TG
812 r = message_attribute_has_type(m, type, NLA_U8);
813 if (r < 0)
814 return r;
44caa5e7
SS
815
816 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 817 if (r < 0)
44caa5e7 818 return r;
f66eeb6b
TG
819 else if ((size_t) r < sizeof(uint8_t))
820 return -EIO;
44caa5e7
SS
821
822 *data = *(uint8_t *) attr_data;
823
824 return 0;
825}
826
827int sd_rtnl_message_read_u16(sd_rtnl_message *m, unsigned short type, uint16_t *data) {
828 int r;
829 void *attr_data;
830
d8e538ec
TG
831 r = message_attribute_has_type(m, type, NLA_U16);
832 if (r < 0)
833 return r;
44caa5e7
SS
834
835 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 836 if (r < 0)
44caa5e7 837 return r;
f66eeb6b
TG
838 else if ((size_t) r < sizeof(uint16_t))
839 return -EIO;
44caa5e7
SS
840
841 *data = *(uint16_t *) attr_data;
842
843 return 0;
844}
845
846int sd_rtnl_message_read_u32(sd_rtnl_message *m, unsigned short type, uint32_t *data) {
847 int r;
848 void *attr_data;
849
d8e538ec
TG
850 r = message_attribute_has_type(m, type, NLA_U32);
851 if (r < 0)
852 return r;
44caa5e7
SS
853
854 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 855 if (r < 0)
44caa5e7 856 return r;
f66eeb6b
TG
857 else if ((size_t)r < sizeof(uint32_t))
858 return -EIO;
44caa5e7
SS
859
860 *data = *(uint32_t *) attr_data;
861
862 return 0;
863}
864
4e9e7f18
SS
865int sd_rtnl_message_read_ether_addr(sd_rtnl_message *m, unsigned short type, struct ether_addr *data) {
866 int r;
867 void *attr_data;
868
d8e538ec
TG
869 r = message_attribute_has_type(m, type, NLA_ETHER_ADDR);
870 if (r < 0)
871 return r;
4e9e7f18
SS
872
873 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 874 if (r < 0)
4e9e7f18 875 return r;
f66eeb6b
TG
876 else if ((size_t)r < sizeof(struct ether_addr))
877 return -EIO;
4e9e7f18
SS
878
879 memcpy(data, attr_data, sizeof(struct ether_addr));
880
881 return 0;
882}
883
aba496a5
UTL
884int sd_rtnl_message_read_cache_info(sd_rtnl_message *m, unsigned short type, struct ifa_cacheinfo *info) {
885 int r;
886 void *attr_data;
887
888 r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
889 if (r < 0)
890 return r;
891
892 r = rtnl_message_read_internal(m, type, &attr_data);
893 if (r < 0)
894 return r;
895 else if ((size_t)r < sizeof(struct ifa_cacheinfo))
896 return -EIO;
897
898 memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
899
900 return 0;
901}
902
4e9e7f18
SS
903int sd_rtnl_message_read_in_addr(sd_rtnl_message *m, unsigned short type, struct in_addr *data) {
904 int r;
905 void *attr_data;
906
d8e538ec
TG
907 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
908 if (r < 0)
909 return r;
4e9e7f18
SS
910
911 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 912 if (r < 0)
4e9e7f18 913 return r;
f66eeb6b
TG
914 else if ((size_t)r < sizeof(struct in_addr))
915 return -EIO;
4e9e7f18
SS
916
917 memcpy(data, attr_data, sizeof(struct in_addr));
918
919 return 0;
920}
921
922int sd_rtnl_message_read_in6_addr(sd_rtnl_message *m, unsigned short type, struct in6_addr *data) {
923 int r;
924 void *attr_data;
925
d8e538ec
TG
926 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
927 if (r < 0)
928 return r;
4e9e7f18
SS
929
930 r = rtnl_message_read_internal(m, type, &attr_data);
3dd215e0 931 if (r < 0)
4e9e7f18 932 return r;
3dd215e0
TG
933 else if ((size_t)r < sizeof(struct in6_addr))
934 return -EIO;
4e9e7f18
SS
935
936 memcpy(data, attr_data, sizeof(struct in6_addr));
937
938 return 0;
939}
940
3dd215e0 941int sd_rtnl_message_enter_container(sd_rtnl_message *m, unsigned short type) {
d8e538ec
TG
942 const NLType *nl_type;
943 const NLTypeSystem *type_system;
3dd215e0 944 void *container;
d8e538ec
TG
945 size_t size;
946 int r;
3dd215e0
TG
947
948 assert_return(m, -EINVAL);
949 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
950
d8e538ec
TG
951 r = type_system_get_type(m->container_type_system[m->n_containers],
952 &nl_type,
953 type);
3dd215e0
TG
954 if (r < 0)
955 return r;
3dd215e0 956
d8e538ec
TG
957 if (nl_type->type == NLA_NESTED) {
958 r = type_system_get_type_system(m->container_type_system[m->n_containers],
959 &type_system,
960 type);
961 if (r < 0)
962 return r;
963 } else if (nl_type->type == NLA_UNION) {
964 const NLTypeSystemUnion *type_system_union;
965 char *key;
966
967 r = type_system_get_type_system_union(m->container_type_system[m->n_containers],
968 &type_system_union,
969 type);
970 if (r < 0)
971 return r;
972
973 r = sd_rtnl_message_read_string(m, type_system_union->match, &key);
974 if (r < 0)
975 return r;
976
977 r = type_system_union_get_type_system(type_system_union,
978 &type_system,
979 key);
980 if (r < 0)
981 return r;
982 } else
983 return -EINVAL;
984
985 r = rtnl_message_read_internal(m, type, &container);
3dd215e0
TG
986 if (r < 0)
987 return r;
d8e538ec
TG
988 else
989 size = (size_t)r;
3dd215e0 990
d8e538ec 991 m->n_containers ++;
3dd215e0
TG
992
993 r = rtnl_message_parse(m,
d8e538ec
TG
994 &m->rta_offset_tb[m->n_containers],
995 &m->rta_tb_size[m->n_containers],
996 type_system->max,
3dd215e0 997 container,
d8e538ec
TG
998 size);
999 if (r < 0) {
1000 m->n_containers --;
3dd215e0 1001 return r;
d8e538ec 1002 }
3dd215e0 1003
d8e538ec 1004 m->container_type_system[m->n_containers] = type_system;
3dd215e0
TG
1005
1006 return 0;
1007}
1008
e5c4350b
TG
1009int sd_rtnl_message_exit_container(sd_rtnl_message *m) {
1010 assert_return(m, -EINVAL);
1011 assert_return(m->sealed, -EINVAL);
1012 assert_return(m->n_containers > 0, -EINVAL);
1013
3dd215e0
TG
1014 free(m->rta_offset_tb[m->n_containers]);
1015 m->rta_offset_tb[m->n_containers] = NULL;
d8e538ec 1016 m->container_type_system[m->n_containers] = NULL;
3dd215e0 1017
e5c4350b
TG
1018 m->n_containers --;
1019
1020 return 0;
1021}
1022
3815f36f 1023uint32_t rtnl_message_get_serial(sd_rtnl_message *m) {
65f568bb 1024 assert(m);
9d0db178 1025 assert(m->hdr);
65f568bb
TG
1026
1027 return m->hdr->nlmsg_seq;
1028}
1029
e16bcf98 1030int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
65f568bb
TG
1031 struct nlmsgerr *err;
1032
e16bcf98 1033 assert_return(m, -EINVAL);
9d0db178 1034 assert_return(m->hdr, -EINVAL);
65f568bb
TG
1035
1036 if (m->hdr->nlmsg_type != NLMSG_ERROR)
1037 return 0;
1038
1039 err = NLMSG_DATA(m->hdr);
1040
1041 return err->error;
1042}
1043
44caa5e7
SS
1044int rtnl_message_parse(sd_rtnl_message *m,
1045 size_t **rta_offset_tb,
1046 unsigned short *rta_tb_size,
1047 int max,
1048 struct rtattr *rta,
1049 unsigned int rt_len) {
e634cd40 1050 unsigned short type;
44caa5e7
SS
1051 size_t *tb;
1052
c8a7165f 1053 tb = new0(size_t, max + 1);
44caa5e7
SS
1054 if(!tb)
1055 return -ENOMEM;
1056
c8a7165f 1057 *rta_tb_size = max + 1;
44caa5e7
SS
1058
1059 for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
1060 type = rta->rta_type;
1061
aef0768e
TG
1062 /* if the kernel is newer than the headers we used
1063 when building, we ignore out-of-range attributes
1064 */
1065 if (type > max)
e634cd40 1066 continue;
e634cd40
TG
1067
1068 if (tb[type])
1069 log_debug("rtnl: message parse - overwriting repeated attribute");
1070
1071 tb[type] = (uint8_t *) rta - (uint8_t *) m->hdr;
44caa5e7
SS
1072 }
1073
1074 *rta_offset_tb = tb;
1075
1076 return 0;
1077}
1078
65f568bb
TG
1079/* returns the number of bytes sent, or a negative error code */
1080int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
d4bbdb77
TG
1081 union {
1082 struct sockaddr sa;
1083 struct sockaddr_nl nl;
1084 } addr = {
1085 .nl.nl_family = AF_NETLINK,
1086 };
65f568bb
TG
1087 ssize_t k;
1088
9d0db178
TG
1089 assert(nl);
1090 assert(m);
1091 assert(m->hdr);
65f568bb
TG
1092
1093 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
d4bbdb77 1094 0, &addr.sa, sizeof(addr));
65f568bb
TG
1095 if (k < 0)
1096 return (errno == EAGAIN) ? 0 : -errno;
1097
1098 return k;
1099}
1100
26349add 1101static int socket_recv_message(int fd, struct iovec *iov, bool peek) {
bc078e71 1102 uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred))];
bc078e71 1103 struct msghdr msg = {
26349add 1104 .msg_iov = iov,
bc078e71
TG
1105 .msg_iovlen = 1,
1106 .msg_control = cred_buffer,
1107 .msg_controllen = sizeof(cred_buffer),
1108 };
1109 struct cmsghdr *cmsg;
26349add 1110 bool auth = false;
4e996881 1111 int r;
d4bbdb77 1112
26349add
TG
1113 assert(fd >= 0);
1114 assert(iov);
bc078e71 1115
26349add 1116 r = recvmsg(fd, &msg, MSG_TRUNC | (peek ? MSG_PEEK : 0));
3dd215e0 1117 if (r < 0)
bc078e71
TG
1118 /* no data */
1119 return (errno == EAGAIN) ? 0 : -errno;
3dd215e0 1120 else if (r == 0)
bc078e71
TG
1121 /* connection was closed by the kernel */
1122 return -ECONNRESET;
3dd215e0 1123
bc078e71
TG
1124 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1125 if (cmsg->cmsg_level == SOL_SOCKET &&
1126 cmsg->cmsg_type == SCM_CREDENTIALS &&
1127 cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
1128 struct ucred *ucred = (void *)CMSG_DATA(cmsg);
1129
1130 /* from the kernel */
1131 if (ucred->uid == 0 && ucred->pid == 0) {
1132 auth = true;
1133 break;
1134 }
1135 }
1136 }
1137
1138 if (!auth)
1139 /* not from the kernel, ignore */
1140 return 0;
1141
26349add
TG
1142 return r;
1143}
1144
1145/* On success, the number of bytes received is returned and *ret points to the received message
1146 * which has a valid header and the correct size.
1147 * If nothing useful was received 0 is returned.
1148 * On failure, a negative error code is returned.
1149 */
1150int socket_read_message(sd_rtnl *rtnl) {
1151 _cleanup_rtnl_message_unref_ sd_rtnl_message *first = NULL;
1152 struct iovec iov = {};
1153 bool multi_part = false, done = false;
1154 struct nlmsghdr *new_msg;
1155 size_t len;
1156 int r;
1157 unsigned i = 0;
1158
1159 assert(rtnl);
1160 assert(rtnl->rbuffer);
1161 assert(rtnl->rbuffer_allocated >= sizeof(struct nlmsghdr));
1162
1163 /* read nothing, just get the pending message size */
1164 r = socket_recv_message(rtnl->fd, &iov, true);
1165 if (r <= 0)
1166 return r;
1167 else
1168 len = (size_t)r;
1169
1170 /* make room for the pending message */
1171 if (!greedy_realloc((void **)&rtnl->rbuffer,
1172 &rtnl->rbuffer_allocated,
1173 len, sizeof(uint8_t)))
1174 return -ENOMEM;
1175
1176 iov.iov_base = rtnl->rbuffer;
1177 iov.iov_len = rtnl->rbuffer_allocated;
1178
1179 /* read the pending message */
1180 r = socket_recv_message(rtnl->fd, &iov, false);
1181 if (r <= 0)
1182 return r;
1183 else
1184 len = (size_t)r;
1185
127dc4ea
TG
1186 if (len > rtnl->rbuffer_allocated)
1187 /* message did not fit in read buffer */
1188 return -EIO;
1189
4e996881
TG
1190 if (NLMSG_OK(rtnl->rbuffer, len) && rtnl->rbuffer->nlmsg_flags & NLM_F_MULTI) {
1191 multi_part = true;
1192
1193 for (i = 0; i < rtnl->rqueue_partial_size; i++) {
1194 if (rtnl_message_get_serial(rtnl->rqueue_partial[i]) ==
1195 rtnl->rbuffer->nlmsg_seq) {
1196 first = rtnl->rqueue_partial[i];
1197 break;
1198 }
1199 }
1200 }
1201
a88f77c4 1202 for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len); new_msg = NLMSG_NEXT(new_msg, len)) {
1b89cf56
TG
1203 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
1204 const NLType *nl_type;
3dd215e0 1205
1b89cf56
TG
1206 if (new_msg->nlmsg_pid && new_msg->nlmsg_pid != rtnl->sockaddr.nl.nl_pid)
1207 /* not broadcast and not for us */
1208 continue;
3dd215e0 1209
1b89cf56 1210 if (new_msg->nlmsg_type == NLMSG_NOOP)
4e996881 1211 /* silently drop noop messages */
1b89cf56 1212 continue;
bdd13f6b 1213
4e996881
TG
1214 if (new_msg->nlmsg_type == NLMSG_DONE) {
1215 /* finished reading multi-part message */
1216 done = true;
1403f45a 1217 break;
4e996881 1218 }
1403f45a 1219
1b89cf56
TG
1220 /* check that we support this message type */
1221 r = type_system_get_type(NULL, &nl_type, new_msg->nlmsg_type);
1222 if (r < 0) {
1223 if (r == -ENOTSUP)
1224 log_debug("sd-rtnl: ignored message with unknown type: %u",
1225 new_msg->nlmsg_type);
d8e538ec 1226
1b89cf56
TG
1227 continue;
1228 }
bdd13f6b 1229
1b89cf56
TG
1230 /* check that the size matches the message type */
1231 if (new_msg->nlmsg_len < NLMSG_LENGTH(nl_type->size))
1232 continue;
65f568bb 1233
1b89cf56
TG
1234 r = message_new_empty(rtnl, &m);
1235 if (r < 0)
1236 return r;
1237
1238 m->hdr = memdup(new_msg, new_msg->nlmsg_len);
1239 if (!m->hdr)
1240 return -ENOMEM;
1241
1242 /* seal and parse the top-level message */
1243 r = sd_rtnl_message_rewind(m);
1244 if (r < 0)
1245 return r;
1246
4e996881
TG
1247 /* push the message onto the multi-part message stack */
1248 if (first)
1249 m->next = first;
1250 first = m;
1b89cf56 1251 m = NULL;
4e996881 1252 }
1403f45a 1253
4e996881
TG
1254 if (len)
1255 log_debug("sd-rtnl: discarding %zu bytes of incoming message", len);
1b89cf56 1256
4e996881
TG
1257 if (!first)
1258 return 0;
65f568bb 1259
4e996881
TG
1260 if (!multi_part || done) {
1261 /* we got a complete message, push it on the read queue */
24a02673
TG
1262 r = rtnl_rqueue_make_room(rtnl);
1263 if (r < 0)
1264 return r;
1265
d4ef4f46
TG
1266 rtnl->rqueue[rtnl->rqueue_size ++] = first;
1267 first = NULL;
1268
1269 if (multi_part && (i < rtnl->rqueue_partial_size)) {
4e996881
TG
1270 /* remove the message form the partial read queue */
1271 memmove(rtnl->rqueue_partial + i,rtnl->rqueue_partial + i + 1,
1272 sizeof(sd_rtnl_message*) * (rtnl->rqueue_partial_size - i - 1));
1273 rtnl->rqueue_partial_size --;
1274 }
1275
4e996881
TG
1276 return 1;
1277 } else {
1278 /* we only got a partial multi-part message, push it on the
1279 partial read queue */
1280 if (i < rtnl->rqueue_partial_size) {
1281 rtnl->rqueue_partial[i] = first;
1282 } else {
1283 r = rtnl_rqueue_partial_make_room(rtnl);
1284 if (r < 0)
1285 return r;
1286
1287 rtnl->rqueue_partial[rtnl->rqueue_partial_size ++] = first;
1288 }
1289 first = NULL;
1403f45a 1290
4e996881
TG
1291 return 0;
1292 }
65f568bb 1293}
0fc7531b
TG
1294
1295int sd_rtnl_message_rewind(sd_rtnl_message *m) {
d8e538ec 1296 const NLType *type;
3dd215e0
TG
1297 unsigned i;
1298 int r;
0fc7531b
TG
1299
1300 assert_return(m, -EINVAL);
0fc7531b 1301
3dd215e0
TG
1302 /* don't allow appending to message once parsed */
1303 if (!m->sealed)
1304 rtnl_message_seal(m);
1305
1306 for (i = 1; i <= m->n_containers; i++) {
1307 free(m->rta_offset_tb[i]);
1308 m->rta_offset_tb[i] = NULL;
1309 m->rta_tb_size[i] = 0;
d8e538ec 1310 m->container_type_system[i] = NULL;
3dd215e0
TG
1311 }
1312
1313 m->n_containers = 0;
1314
1315 if (m->rta_offset_tb[0]) {
1316 /* top-level attributes have already been parsed */
1317 return 0;
1318 }
1319
d8e538ec
TG
1320 assert(m->hdr);
1321
1322 r = type_system_get_type(NULL, &type, m->hdr->nlmsg_type);
1323 if (r < 0)
1324 return r;
1325
1326 if (type->type == NLA_NESTED) {
1327 const NLTypeSystem *type_system = type->type_system;
1328
1329 assert(type_system);
1330
1331 m->container_type_system[0] = type_system;
1332
1333 r = rtnl_message_parse(m,
1334 &m->rta_offset_tb[m->n_containers],
1335 &m->rta_tb_size[m->n_containers],
1336 type_system->max,
0834ff93
TG
1337 (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) +
1338 NLMSG_ALIGN(type->size)),
d8e538ec
TG
1339 NLMSG_PAYLOAD(m->hdr, type->size));
1340 if (r < 0)
1341 return r;
0fc7531b
TG
1342 }
1343
1344 return 0;
1345}
3dd215e0
TG
1346
1347void rtnl_message_seal(sd_rtnl_message *m) {
1348 assert(m);
1349 assert(!m->sealed);
1350
1351 m->sealed = true;
1352}
1403f45a
TG
1353
1354sd_rtnl_message *sd_rtnl_message_next(sd_rtnl_message *m) {
1355 assert_return(m, NULL);
1356
1357 return m->next;
1358}