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