]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-rtnl/rtnl-message.c
rtnl: message - move code around
[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
1101/* On success, the number of bytes received is returned and *ret points to the received message
1102 * which has a valid header and the correct size.
1103 * If nothing useful was received 0 is returned.
1104 * On failure, a negative error code is returned.
dabfa9d1 1105 */
1b89cf56 1106int socket_read_message(sd_rtnl *rtnl) {
1403f45a 1107 _cleanup_rtnl_message_unref_ sd_rtnl_message *first = NULL;
bc078e71
TG
1108 uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred))];
1109 struct iovec iov = {};
1110 struct msghdr msg = {
1111 .msg_iov = &iov,
1112 .msg_iovlen = 1,
1113 .msg_control = cred_buffer,
1114 .msg_controllen = sizeof(cred_buffer),
1115 };
1116 struct cmsghdr *cmsg;
4e996881 1117 bool auth = false, multi_part = false, done = false;
1b89cf56 1118 struct nlmsghdr *new_msg;
a88f77c4 1119 size_t len;
4e996881 1120 int r;
6e37cd2f 1121 unsigned i = 0;
65f568bb 1122
1b89cf56 1123 assert(rtnl);
a88f77c4 1124 assert(rtnl->rbuffer);
6fc51883 1125 assert(rtnl->rbuffer_allocated >= sizeof(struct nlmsghdr));
65f568bb 1126
6fc51883
TG
1127 /* read nothing, just get the pending message size */
1128 r = recvmsg(rtnl->fd, &msg, MSG_PEEK | MSG_TRUNC);
65f568bb 1129 if (r < 0)
a88f77c4
TG
1130 /* no data */
1131 return (errno == EAGAIN) ? 0 : -errno;
1132 else if (r == 0)
1133 /* connection was closed by the kernel */
1134 return -ECONNRESET;
6fc51883
TG
1135 else
1136 len = (size_t)r;
65f568bb 1137
a88f77c4
TG
1138 /* make room for the pending message */
1139 if (!greedy_realloc((void **)&rtnl->rbuffer,
1140 &rtnl->rbuffer_allocated,
6fc51883 1141 len, sizeof(uint8_t)))
1b89cf56 1142 return -ENOMEM;
d4bbdb77 1143
a88f77c4
TG
1144 iov.iov_base = rtnl->rbuffer;
1145 iov.iov_len = rtnl->rbuffer_allocated;
bc078e71 1146
a88f77c4 1147 r = recvmsg(rtnl->fd, &msg, MSG_TRUNC);
3dd215e0 1148 if (r < 0)
bc078e71
TG
1149 /* no data */
1150 return (errno == EAGAIN) ? 0 : -errno;
3dd215e0 1151 else if (r == 0)
bc078e71
TG
1152 /* connection was closed by the kernel */
1153 return -ECONNRESET;
3dd215e0 1154 else
1b89cf56 1155 len = (size_t)r;
3dd215e0 1156
bc078e71
TG
1157 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1158 if (cmsg->cmsg_level == SOL_SOCKET &&
1159 cmsg->cmsg_type == SCM_CREDENTIALS &&
1160 cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
1161 struct ucred *ucred = (void *)CMSG_DATA(cmsg);
1162
1163 /* from the kernel */
1164 if (ucred->uid == 0 && ucred->pid == 0) {
1165 auth = true;
1166 break;
1167 }
1168 }
1169 }
1170
1171 if (!auth)
1172 /* not from the kernel, ignore */
1173 return 0;
1174
127dc4ea
TG
1175 if (len > rtnl->rbuffer_allocated)
1176 /* message did not fit in read buffer */
1177 return -EIO;
1178
4e996881
TG
1179 if (NLMSG_OK(rtnl->rbuffer, len) && rtnl->rbuffer->nlmsg_flags & NLM_F_MULTI) {
1180 multi_part = true;
1181
1182 for (i = 0; i < rtnl->rqueue_partial_size; i++) {
1183 if (rtnl_message_get_serial(rtnl->rqueue_partial[i]) ==
1184 rtnl->rbuffer->nlmsg_seq) {
1185 first = rtnl->rqueue_partial[i];
1186 break;
1187 }
1188 }
1189 }
1190
a88f77c4 1191 for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len); new_msg = NLMSG_NEXT(new_msg, len)) {
1b89cf56
TG
1192 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
1193 const NLType *nl_type;
3dd215e0 1194
1b89cf56
TG
1195 if (new_msg->nlmsg_pid && new_msg->nlmsg_pid != rtnl->sockaddr.nl.nl_pid)
1196 /* not broadcast and not for us */
1197 continue;
3dd215e0 1198
1b89cf56 1199 if (new_msg->nlmsg_type == NLMSG_NOOP)
4e996881 1200 /* silently drop noop messages */
1b89cf56 1201 continue;
bdd13f6b 1202
4e996881
TG
1203 if (new_msg->nlmsg_type == NLMSG_DONE) {
1204 /* finished reading multi-part message */
1205 done = true;
1403f45a 1206 break;
4e996881 1207 }
1403f45a 1208
1b89cf56
TG
1209 /* check that we support this message type */
1210 r = type_system_get_type(NULL, &nl_type, new_msg->nlmsg_type);
1211 if (r < 0) {
1212 if (r == -ENOTSUP)
1213 log_debug("sd-rtnl: ignored message with unknown type: %u",
1214 new_msg->nlmsg_type);
d8e538ec 1215
1b89cf56
TG
1216 continue;
1217 }
bdd13f6b 1218
1b89cf56
TG
1219 /* check that the size matches the message type */
1220 if (new_msg->nlmsg_len < NLMSG_LENGTH(nl_type->size))
1221 continue;
65f568bb 1222
1b89cf56
TG
1223 r = message_new_empty(rtnl, &m);
1224 if (r < 0)
1225 return r;
1226
1227 m->hdr = memdup(new_msg, new_msg->nlmsg_len);
1228 if (!m->hdr)
1229 return -ENOMEM;
1230
1231 /* seal and parse the top-level message */
1232 r = sd_rtnl_message_rewind(m);
1233 if (r < 0)
1234 return r;
1235
4e996881
TG
1236 /* push the message onto the multi-part message stack */
1237 if (first)
1238 m->next = first;
1239 first = m;
1b89cf56 1240 m = NULL;
4e996881 1241 }
1403f45a 1242
4e996881
TG
1243 if (len)
1244 log_debug("sd-rtnl: discarding %zu bytes of incoming message", len);
1b89cf56 1245
4e996881
TG
1246 if (!first)
1247 return 0;
65f568bb 1248
4e996881
TG
1249 if (!multi_part || done) {
1250 /* we got a complete message, push it on the read queue */
24a02673
TG
1251 r = rtnl_rqueue_make_room(rtnl);
1252 if (r < 0)
1253 return r;
1254
d4ef4f46
TG
1255 rtnl->rqueue[rtnl->rqueue_size ++] = first;
1256 first = NULL;
1257
1258 if (multi_part && (i < rtnl->rqueue_partial_size)) {
4e996881
TG
1259 /* remove the message form the partial read queue */
1260 memmove(rtnl->rqueue_partial + i,rtnl->rqueue_partial + i + 1,
1261 sizeof(sd_rtnl_message*) * (rtnl->rqueue_partial_size - i - 1));
1262 rtnl->rqueue_partial_size --;
1263 }
1264
4e996881
TG
1265 return 1;
1266 } else {
1267 /* we only got a partial multi-part message, push it on the
1268 partial read queue */
1269 if (i < rtnl->rqueue_partial_size) {
1270 rtnl->rqueue_partial[i] = first;
1271 } else {
1272 r = rtnl_rqueue_partial_make_room(rtnl);
1273 if (r < 0)
1274 return r;
1275
1276 rtnl->rqueue_partial[rtnl->rqueue_partial_size ++] = first;
1277 }
1278 first = NULL;
1403f45a 1279
4e996881
TG
1280 return 0;
1281 }
65f568bb 1282}
0fc7531b
TG
1283
1284int sd_rtnl_message_rewind(sd_rtnl_message *m) {
d8e538ec 1285 const NLType *type;
3dd215e0
TG
1286 unsigned i;
1287 int r;
0fc7531b
TG
1288
1289 assert_return(m, -EINVAL);
0fc7531b 1290
3dd215e0
TG
1291 /* don't allow appending to message once parsed */
1292 if (!m->sealed)
1293 rtnl_message_seal(m);
1294
1295 for (i = 1; i <= m->n_containers; i++) {
1296 free(m->rta_offset_tb[i]);
1297 m->rta_offset_tb[i] = NULL;
1298 m->rta_tb_size[i] = 0;
d8e538ec 1299 m->container_type_system[i] = NULL;
3dd215e0
TG
1300 }
1301
1302 m->n_containers = 0;
1303
1304 if (m->rta_offset_tb[0]) {
1305 /* top-level attributes have already been parsed */
1306 return 0;
1307 }
1308
d8e538ec
TG
1309 assert(m->hdr);
1310
1311 r = type_system_get_type(NULL, &type, m->hdr->nlmsg_type);
1312 if (r < 0)
1313 return r;
1314
1315 if (type->type == NLA_NESTED) {
1316 const NLTypeSystem *type_system = type->type_system;
1317
1318 assert(type_system);
1319
1320 m->container_type_system[0] = type_system;
1321
1322 r = rtnl_message_parse(m,
1323 &m->rta_offset_tb[m->n_containers],
1324 &m->rta_tb_size[m->n_containers],
1325 type_system->max,
0834ff93
TG
1326 (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) +
1327 NLMSG_ALIGN(type->size)),
d8e538ec
TG
1328 NLMSG_PAYLOAD(m->hdr, type->size));
1329 if (r < 0)
1330 return r;
0fc7531b
TG
1331 }
1332
1333 return 0;
1334}
3dd215e0
TG
1335
1336void rtnl_message_seal(sd_rtnl_message *m) {
1337 assert(m);
1338 assert(!m->sealed);
1339
1340 m->sealed = true;
1341}
1403f45a
TG
1342
1343sd_rtnl_message *sd_rtnl_message_next(sd_rtnl_message *m) {
1344 assert_return(m, NULL);
1345
1346 return m->next;
1347}