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