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