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