]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-rtnl/rtnl-message.c
Generate systemd-fsck-root.service in the initramfs
[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>
65f568bb
TG
23#include <stdbool.h>
24#include <unistd.h>
25
26#include "util.h"
6482f626 27#include "formats-util.h"
65f568bb 28#include "refcnt.h"
d5eff740 29#include "missing.h"
65f568bb
TG
30
31#include "sd-rtnl.h"
3815f36f 32#include "rtnl-util.h"
65f568bb 33#include "rtnl-internal.h"
d8e538ec 34#include "rtnl-types.h"
65f568bb 35
31a4e153 36#define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL)
e5c4350b 37#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
4ebe732c 38
0a2478a9
TG
39#define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
40
1b89cf56 41static int message_new_empty(sd_rtnl *rtnl, sd_rtnl_message **ret) {
65f568bb
TG
42 sd_rtnl_message *m;
43
44 assert_return(ret, -EINVAL);
65f568bb 45
f131770b 46 /* Note that 'rtnl' is currently unused, if we start using it internally
8c578303
TG
47 we must take care to avoid problems due to mutual references between
48 busses and their queued messages. See sd-bus.
49 */
50
65f568bb
TG
51 m = new0(sd_rtnl_message, 1);
52 if (!m)
53 return -ENOMEM;
54
65f568bb
TG
55 m->n_ref = REFCNT_INIT;
56
65f568bb
TG
57 m->sealed = false;
58
59 *ret = m;
60
61 return 0;
62}
63
d8e538ec 64int message_new(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t type) {
1b89cf56 65 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
d8e538ec
TG
66 const NLType *nl_type;
67 size_t size;
68 int r;
69
70 r = type_system_get_type(NULL, &nl_type, type);
71 if (r < 0)
72 return r;
73
1b89cf56 74 r = message_new_empty(rtnl, &m);
d8e538ec
TG
75 if (r < 0)
76 return r;
77
1b89cf56
TG
78 size = NLMSG_SPACE(nl_type->size);
79
80 assert(size >= sizeof(struct nlmsghdr));
81 m->hdr = malloc0(size);
82 if (!m->hdr)
83 return -ENOMEM;
84
85 m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
86
87 m->container_type_system[0] = nl_type->type_system;
88 m->hdr->nlmsg_len = size;
89 m->hdr->nlmsg_type = type;
90
91 *ret = m;
92 m = NULL;
d8e538ec
TG
93
94 return 0;
95}
96
1f01fb4f
TG
97int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
98 struct rtmsg *rtm;
99
5a723174
TG
100 assert_return(m, -EINVAL);
101 assert_return(m->hdr, -EINVAL);
3815f36f 102 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
5a723174 103
1f01fb4f
TG
104 rtm = NLMSG_DATA(m->hdr);
105
5a723174
TG
106 if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
107 (rtm->rtm_family == AF_INET6 && prefixlen > 128))
108 return -ERANGE;
109
1f01fb4f
TG
110 rtm->rtm_dst_len = prefixlen;
111
5c1d3fc9
UTL
112 return 0;
113}
114
9e7e4408
TG
115int sd_rtnl_message_route_set_src_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
116 struct rtmsg *rtm;
117
118 assert_return(m, -EINVAL);
119 assert_return(m->hdr, -EINVAL);
120 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
121
122 rtm = NLMSG_DATA(m->hdr);
123
124 if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
125 (rtm->rtm_family == AF_INET6 && prefixlen > 128))
126 return -ERANGE;
127
128 rtm->rtm_src_len = prefixlen;
129
130 return 0;
131}
132
5c1d3fc9
UTL
133int sd_rtnl_message_route_set_scope(sd_rtnl_message *m, unsigned char scope) {
134 struct rtmsg *rtm;
135
136 assert_return(m, -EINVAL);
137 assert_return(m->hdr, -EINVAL);
138 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
139
140 rtm = NLMSG_DATA(m->hdr);
141
142 rtm->rtm_scope = scope;
143
1f01fb4f
TG
144 return 0;
145}
146
dae4de9d
TG
147int sd_rtnl_message_route_get_family(sd_rtnl_message *m, int *family) {
148 struct rtmsg *rtm;
149
150 assert_return(m, -EINVAL);
151 assert_return(m->hdr, -EINVAL);
152 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
153 assert_return(family, -EINVAL);
154
155 rtm = NLMSG_DATA(m->hdr);
156
157 *family = rtm->rtm_family;
158
159 return 0;
160}
161
584d0d2a 162int sd_rtnl_message_route_get_dst_prefixlen(sd_rtnl_message *m, unsigned char *dst_len) {
e9140aff
LP
163 struct rtmsg *rtm;
164
165 assert_return(m, -EINVAL);
166 assert_return(m->hdr, -EINVAL);
167 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
168 assert_return(dst_len, -EINVAL);
169
170 rtm = NLMSG_DATA(m->hdr);
171
172 *dst_len = rtm->rtm_dst_len;
173
174 return 0;
175}
176
584d0d2a 177int sd_rtnl_message_route_get_src_prefixlen(sd_rtnl_message *m, unsigned char *src_len) {
a98433c0
LP
178 struct rtmsg *rtm;
179
180 assert_return(m, -EINVAL);
181 assert_return(m->hdr, -EINVAL);
182 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
183 assert_return(src_len, -EINVAL);
184
185 rtm = NLMSG_DATA(m->hdr);
186
187 *src_len = rtm->rtm_src_len;
188
189 return 0;
190}
191
151b9b96 192int sd_rtnl_message_new_route(sd_rtnl *rtnl, sd_rtnl_message **ret,
28cc555d
DW
193 uint16_t nlmsg_type, int rtm_family,
194 unsigned char rtm_protocol) {
03d7e632
TG
195 struct rtmsg *rtm;
196 int r;
197
3815f36f 198 assert_return(rtnl_message_type_is_route(nlmsg_type), -EINVAL);
722f7cc9
TG
199 assert_return((nlmsg_type == RTM_GETROUTE && rtm_family == AF_UNSPEC) ||
200 rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
03d7e632
TG
201 assert_return(ret, -EINVAL);
202
d8e538ec 203 r = message_new(rtnl, ret, nlmsg_type);
03d7e632
TG
204 if (r < 0)
205 return r;
206
03d7e632 207 if (nlmsg_type == RTM_NEWROUTE)
3f781aa8 208 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
03d7e632
TG
209
210 rtm = NLMSG_DATA((*ret)->hdr);
211
212 rtm->rtm_family = rtm_family;
1f01fb4f
TG
213 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
214 rtm->rtm_type = RTN_UNICAST;
215 rtm->rtm_table = RT_TABLE_MAIN;
28cc555d 216 rtm->rtm_protocol = rtm_protocol;
03d7e632
TG
217
218 return 0;
219}
220
b98b483b
AR
221int sd_rtnl_message_neigh_set_flags(sd_rtnl_message *m, uint8_t flags) {
222 struct ndmsg *ndm;
223
224 assert_return(m, -EINVAL);
225 assert_return(m->hdr, -EINVAL);
226 assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
227
228 ndm = NLMSG_DATA(m->hdr);
229 ndm->ndm_flags |= flags;
230
231 return 0;
232}
233
234int sd_rtnl_message_neigh_set_state(sd_rtnl_message *m, uint16_t state) {
235 struct ndmsg *ndm;
236
237 assert_return(m, -EINVAL);
238 assert_return(m->hdr, -EINVAL);
239 assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
240
241 ndm = NLMSG_DATA(m->hdr);
242 ndm->ndm_state |= state;
243
244 return 0;
245}
246
247int sd_rtnl_message_neigh_get_flags(sd_rtnl_message *m, uint8_t *flags) {
248 struct ndmsg *ndm;
249
250 assert_return(m, -EINVAL);
251 assert_return(m->hdr, -EINVAL);
252 assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
253
254 ndm = NLMSG_DATA(m->hdr);
255 *flags = ndm->ndm_flags;
256
257 return 0;
258}
259
260int sd_rtnl_message_neigh_get_state(sd_rtnl_message *m, uint16_t *state) {
261 struct ndmsg *ndm;
262
263 assert_return(m, -EINVAL);
264 assert_return(m->hdr, -EINVAL);
265 assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
266
267 ndm = NLMSG_DATA(m->hdr);
268 *state = ndm->ndm_state;
269
270 return 0;
271}
272
20dff6c4
TG
273int sd_rtnl_message_neigh_get_family(sd_rtnl_message *m, int *family) {
274 struct ndmsg *ndm;
275
276 assert_return(m, -EINVAL);
277 assert_return(m->hdr, -EINVAL);
278 assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
279 assert_return(family, -EINVAL);
280
281 ndm = NLMSG_DATA(m->hdr);
282
283 *family = ndm->ndm_family;
284
285 return 0;
286}
287
288int sd_rtnl_message_neigh_get_ifindex(sd_rtnl_message *m, int *index) {
289 struct ndmsg *ndm;
290
291 assert_return(m, -EINVAL);
292 assert_return(m->hdr, -EINVAL);
293 assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
294 assert_return(index, -EINVAL);
295
296 ndm = NLMSG_DATA(m->hdr);
297
298 *index = ndm->ndm_ifindex;
299
300 return 0;
301}
302
303int sd_rtnl_message_new_neigh(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t nlmsg_type, int index, int ndm_family) {
304 struct ndmsg *ndm;
305 int r;
306
307 assert_return(rtnl_message_type_is_neigh(nlmsg_type), -EINVAL);
b98b483b
AR
308 assert_return(ndm_family == AF_INET ||
309 ndm_family == AF_INET6 ||
310 ndm_family == PF_BRIDGE, -EINVAL);
20dff6c4
TG
311 assert_return(ret, -EINVAL);
312
313 r = message_new(rtnl, ret, nlmsg_type);
314 if (r < 0)
315 return r;
316
317 if (nlmsg_type == RTM_NEWNEIGH)
318 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
319
320 ndm = NLMSG_DATA((*ret)->hdr);
321
322 ndm->ndm_family = ndm_family;
323 ndm->ndm_ifindex = index;
324
325 return 0;
326}
327
5d4795f3 328int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags, unsigned change) {
fc25d7f8
TG
329 struct ifinfomsg *ifi;
330
5a723174
TG
331 assert_return(m, -EINVAL);
332 assert_return(m->hdr, -EINVAL);
3815f36f 333 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
a7b74db6 334 assert_return(change, -EINVAL);
5a723174 335
fc25d7f8
TG
336 ifi = NLMSG_DATA(m->hdr);
337
338 ifi->ifi_flags = flags;
a7b74db6 339 ifi->ifi_change = change;
fc25d7f8
TG
340
341 return 0;
342}
343
344int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) {
345 struct ifinfomsg *ifi;
346
5a723174
TG
347 assert_return(m, -EINVAL);
348 assert_return(m->hdr, -EINVAL);
3815f36f 349 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
5a723174 350
fc25d7f8
TG
351 ifi = NLMSG_DATA(m->hdr);
352
353 ifi->ifi_type = type;
354
355 return 0;
356}
357
64c84071
SS
358int sd_rtnl_message_link_set_family(sd_rtnl_message *m, unsigned family) {
359 struct ifinfomsg *ifi;
360
361 assert_return(m, -EINVAL);
362 assert_return(m->hdr, -EINVAL);
363 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
364
365 ifi = NLMSG_DATA(m->hdr);
366
367 ifi->ifi_family = family;
368
369 return 0;
370}
371
151b9b96
LP
372int sd_rtnl_message_new_link(sd_rtnl *rtnl, sd_rtnl_message **ret,
373 uint16_t nlmsg_type, int index) {
65f568bb
TG
374 struct ifinfomsg *ifi;
375 int r;
376
3815f36f 377 assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL);
6a8402d9 378 assert_return(nlmsg_type != RTM_DELLINK || index > 0, -EINVAL);
65f568bb
TG
379 assert_return(ret, -EINVAL);
380
d8e538ec 381 r = message_new(rtnl, ret, nlmsg_type);
65f568bb
TG
382 if (r < 0)
383 return r;
384
33125ac5 385 if (nlmsg_type == RTM_NEWLINK)
6a8402d9 386 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
65f568bb 387
dabfa9d1 388 ifi = NLMSG_DATA((*ret)->hdr);
65f568bb
TG
389
390 ifi->ifi_family = AF_UNSPEC;
391 ifi->ifi_index = index;
65f568bb
TG
392
393 return 0;
394}
395
6e20c8f8
TG
396int sd_rtnl_message_request_dump(sd_rtnl_message *m, int dump) {
397 assert_return(m, -EINVAL);
398 assert_return(m->hdr, -EINVAL);
20dff6c4
TG
399 assert_return(m->hdr->nlmsg_type == RTM_GETLINK ||
400 m->hdr->nlmsg_type == RTM_GETADDR ||
401 m->hdr->nlmsg_type == RTM_GETROUTE ||
402 m->hdr->nlmsg_type == RTM_GETNEIGH,
6e20c8f8
TG
403 -EINVAL);
404
405 if (dump)
406 m->hdr->nlmsg_flags |= NLM_F_DUMP;
407 else
408 m->hdr->nlmsg_flags &= ~NLM_F_DUMP;
409
410 return 0;
411}
412
5a723174
TG
413int sd_rtnl_message_addr_set_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
414 struct ifaddrmsg *ifa;
415
416 assert_return(m, -EINVAL);
417 assert_return(m->hdr, -EINVAL);
3815f36f 418 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
5a723174
TG
419
420 ifa = NLMSG_DATA(m->hdr);
421
422 if ((ifa->ifa_family == AF_INET && prefixlen > 32) ||
423 (ifa->ifa_family == AF_INET6 && prefixlen > 128))
424 return -ERANGE;
425
426 ifa->ifa_prefixlen = prefixlen;
427
428 return 0;
429}
430
431int sd_rtnl_message_addr_set_flags(sd_rtnl_message *m, unsigned char flags) {
432 struct ifaddrmsg *ifa;
433
434 assert_return(m, -EINVAL);
435 assert_return(m->hdr, -EINVAL);
3815f36f 436 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
5a723174
TG
437
438 ifa = NLMSG_DATA(m->hdr);
439
440 ifa->ifa_flags = flags;
441
442 return 0;
443}
444
445int sd_rtnl_message_addr_set_scope(sd_rtnl_message *m, unsigned char scope) {
446 struct ifaddrmsg *ifa;
447
448 assert_return(m, -EINVAL);
449 assert_return(m->hdr, -EINVAL);
3815f36f 450 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
5a723174
TG
451
452 ifa = NLMSG_DATA(m->hdr);
453
454 ifa->ifa_scope = scope;
455
456 return 0;
457}
458
0dd25fb9 459int sd_rtnl_message_addr_get_family(sd_rtnl_message *m, int *family) {
e00d77dd
TG
460 struct ifaddrmsg *ifa;
461
462 assert_return(m, -EINVAL);
463 assert_return(m->hdr, -EINVAL);
464 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
465 assert_return(family, -EINVAL);
466
467 ifa = NLMSG_DATA(m->hdr);
468
469 *family = ifa->ifa_family;
470
471 return 0;
472}
473
f4e884dd
TG
474int sd_rtnl_message_addr_get_prefixlen(sd_rtnl_message *m, unsigned char *prefixlen) {
475 struct ifaddrmsg *ifa;
476
477 assert_return(m, -EINVAL);
478 assert_return(m->hdr, -EINVAL);
479 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
480 assert_return(prefixlen, -EINVAL);
481
482 ifa = NLMSG_DATA(m->hdr);
483
484 *prefixlen = ifa->ifa_prefixlen;
485
486 return 0;
487}
488
e00d77dd
TG
489int sd_rtnl_message_addr_get_scope(sd_rtnl_message *m, unsigned char *scope) {
490 struct ifaddrmsg *ifa;
491
492 assert_return(m, -EINVAL);
493 assert_return(m->hdr, -EINVAL);
494 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
495 assert_return(scope, -EINVAL);
496
497 ifa = NLMSG_DATA(m->hdr);
498
499 *scope = ifa->ifa_scope;
500
501 return 0;
502}
503
504int sd_rtnl_message_addr_get_flags(sd_rtnl_message *m, unsigned char *flags) {
505 struct ifaddrmsg *ifa;
506
507 assert_return(m, -EINVAL);
508 assert_return(m->hdr, -EINVAL);
509 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
510 assert_return(flags, -EINVAL);
511
512 ifa = NLMSG_DATA(m->hdr);
513
514 *flags = ifa->ifa_flags;
515
516 return 0;
517}
518
519int sd_rtnl_message_addr_get_ifindex(sd_rtnl_message *m, int *ifindex) {
520 struct ifaddrmsg *ifa;
521
522 assert_return(m, -EINVAL);
523 assert_return(m->hdr, -EINVAL);
524 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
525 assert_return(ifindex, -EINVAL);
526
527 ifa = NLMSG_DATA(m->hdr);
528
529 *ifindex = ifa->ifa_index;
530
531 return 0;
532}
533
151b9b96
LP
534int sd_rtnl_message_new_addr(sd_rtnl *rtnl, sd_rtnl_message **ret,
535 uint16_t nlmsg_type, int index,
0dd25fb9 536 int family) {
65f568bb
TG
537 struct ifaddrmsg *ifa;
538 int r;
539
3815f36f 540 assert_return(rtnl_message_type_is_addr(nlmsg_type), -EINVAL);
b9ef681b
TG
541 assert_return((nlmsg_type == RTM_GETADDR && index == 0) ||
542 index > 0, -EINVAL);
543 assert_return((nlmsg_type == RTM_GETADDR && family == AF_UNSPEC) ||
544 family == AF_INET || family == AF_INET6, -EINVAL);
65f568bb
TG
545 assert_return(ret, -EINVAL);
546
d8e538ec 547 r = message_new(rtnl, ret, nlmsg_type);
65f568bb
TG
548 if (r < 0)
549 return r;
550
b9ef681b 551 if (nlmsg_type == RTM_GETADDR)
818dc5e7 552 (*ret)->hdr->nlmsg_flags |= NLM_F_DUMP;
65f568bb 553
dabfa9d1 554 ifa = NLMSG_DATA((*ret)->hdr);
65f568bb 555
65f568bb 556 ifa->ifa_index = index;
5a723174
TG
557 ifa->ifa_family = family;
558 if (family == AF_INET)
559 ifa->ifa_prefixlen = 32;
560 else if (family == AF_INET6)
561 ifa->ifa_prefixlen = 128;
65f568bb
TG
562
563 return 0;
564}
565
aba496a5 566int sd_rtnl_message_new_addr_update(sd_rtnl *rtnl, sd_rtnl_message **ret,
0dd25fb9 567 int index, int family) {
aba496a5
UTL
568 int r;
569
570 r = sd_rtnl_message_new_addr(rtnl, ret, RTM_NEWADDR, index, family);
571 if (r < 0)
572 return r;
573
574 (*ret)->hdr->nlmsg_flags |= NLM_F_REPLACE;
575
576 return 0;
577}
578
65f568bb
TG
579sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
580 if (m)
581 assert_se(REFCNT_INC(m->n_ref) >= 2);
582
583 return m;
584}
585
586sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
f0c4b1c3 587 if (m && REFCNT_DEC(m->n_ref) == 0) {
3dd215e0
TG
588 unsigned i;
589
65f568bb 590 free(m->hdr);
3dd215e0 591
9f5bbfe3 592 for (i = 0; i <= m->n_containers; i++)
3dd215e0
TG
593 free(m->rta_offset_tb[i]);
594
1403f45a
TG
595 sd_rtnl_message_unref(m->next);
596
65f568bb
TG
597 free(m);
598 }
599
600 return NULL;
601}
602
dabfa9d1 603int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
65f568bb
TG
604 assert_return(m, -EINVAL);
605 assert_return(type, -EINVAL);
606
607 *type = m->hdr->nlmsg_type;
608
609 return 0;
610}
611
4af7b60d
TG
612int sd_rtnl_message_get_family(sd_rtnl_message *m, int *family) {
613 assert_return(m, -EINVAL);
614 assert_return(family, -EINVAL);
615
616 assert(m->hdr);
617
618 if (rtnl_message_type_is_link(m->hdr->nlmsg_type)) {
619 struct ifinfomsg *ifi;
620
621 ifi = NLMSG_DATA(m->hdr);
622
623 *family = ifi->ifi_family;
624
625 return 0;
626 } else if (rtnl_message_type_is_route(m->hdr->nlmsg_type)) {
627 struct rtmsg *rtm;
628
629 rtm = NLMSG_DATA(m->hdr);
630
631 *family = rtm->rtm_family;
632
633 return 0;
634 } else if (rtnl_message_type_is_neigh(m->hdr->nlmsg_type)) {
635 struct ndmsg *ndm;
636
637 ndm = NLMSG_DATA(m->hdr);
638
639 *family = ndm->ndm_family;
640
641 return 0;
642 } else if (rtnl_message_type_is_addr(m->hdr->nlmsg_type)) {
643 struct ifaddrmsg *ifa;
644
645 ifa = NLMSG_DATA(m->hdr);
646
647 *family = ifa->ifa_family;
648
649 return 0;
650 }
651
15411c0c 652 return -EOPNOTSUPP;
4af7b60d
TG
653}
654
1f0db3ed
TG
655int sd_rtnl_message_is_broadcast(sd_rtnl_message *m) {
656 assert_return(m, -EINVAL);
657
3f42446d 658 return m->broadcast;
1f0db3ed
TG
659}
660
33125ac5
TG
661int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
662 struct ifinfomsg *ifi;
663
664 assert_return(m, -EINVAL);
9d0db178 665 assert_return(m->hdr, -EINVAL);
3815f36f 666 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
33125ac5 667 assert_return(ifindex, -EINVAL);
33125ac5
TG
668
669 ifi = NLMSG_DATA(m->hdr);
670
671 *ifindex = ifi->ifi_index;
672
673 return 0;
674}
675
50b3c42f
TG
676int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
677 struct ifinfomsg *ifi;
678
679 assert_return(m, -EINVAL);
9d0db178 680 assert_return(m->hdr, -EINVAL);
3815f36f 681 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
50b3c42f 682 assert_return(flags, -EINVAL);
50b3c42f
TG
683
684 ifi = NLMSG_DATA(m->hdr);
685
686 *flags = ifi->ifi_flags;
687
688 return 0;
689}
690
ee8c4568
LP
691int sd_rtnl_message_link_get_type(sd_rtnl_message *m, unsigned *type) {
692 struct ifinfomsg *ifi;
693
694 assert_return(m, -EINVAL);
695 assert_return(m->hdr, -EINVAL);
696 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
697 assert_return(type, -EINVAL);
698
699 ifi = NLMSG_DATA(m->hdr);
700
701 *type = ifi->ifi_type;
702
703 return 0;
704}
705
4ebe732c
ZJS
706/* If successful the updated message will be correctly aligned, if
707 unsuccessful the old message is untouched. */
65f568bb 708static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
7ca1d319
TG
709 uint32_t rta_length;
710 size_t message_length, padding_length;
65f568bb
TG
711 struct nlmsghdr *new_hdr;
712 struct rtattr *rta;
8e337e64 713 char *padding;
5a081409 714 unsigned i;
7ca1d319 715 int offset;
65f568bb 716
33125ac5
TG
717 assert(m);
718 assert(m->hdr);
e5c4350b 719 assert(!m->sealed);
33125ac5 720 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
7ca1d319
TG
721 assert(!data || data_length);
722
723 /* get offset of the new attribute */
724 offset = m->hdr->nlmsg_len;
65f568bb 725
8e337e64 726 /* get the size of the new rta attribute (with padding at the end) */
65f568bb 727 rta_length = RTA_LENGTH(data_length);
4ebe732c
ZJS
728
729 /* get the new message size (with padding at the end) */
7ca1d319 730 message_length = offset + RTA_ALIGN(rta_length);
65f568bb
TG
731
732 /* realloc to fit the new attribute */
733 new_hdr = realloc(m->hdr, message_length);
734 if (!new_hdr)
735 return -ENOMEM;
736 m->hdr = new_hdr;
737
738 /* get pointer to the attribute we are about to add */
7ca1d319 739 rta = (struct rtattr *) ((uint8_t *) m->hdr + offset);
65f568bb 740
5a081409
TG
741 /* if we are inside containers, extend them */
742 for (i = 0; i < m->n_containers; i++)
7ca1d319 743 GET_CONTAINER(m, i)->rta_len += message_length - offset;
33125ac5 744
65f568bb
TG
745 /* fill in the attribute */
746 rta->rta_type = type;
747 rta->rta_len = rta_length;
7ca1d319 748 if (data)
33125ac5
TG
749 /* we don't deal with the case where the user lies about the type
750 * and gives us too little data (so don't do that)
7ca1d319 751 */
33125ac5 752 padding = mempcpy(RTA_DATA(rta), data, data_length);
7ca1d319
TG
753 else {
754 /* if no data was passed, make sure we still initialize the padding
755 note that we can have data_length > 0 (used by some containers) */
756 padding = RTA_DATA(rta);
33125ac5 757 }
65f568bb 758
7ca1d319
TG
759 /* make sure also the padding at the end of the message is initialized */
760 padding_length = (uint8_t*)m->hdr + message_length - (uint8_t*)padding;
761 memzero(padding, padding_length);
762
4ebe732c
ZJS
763 /* update message size */
764 m->hdr->nlmsg_len = message_length;
765
7ca1d319 766 return offset;
65f568bb
TG
767}
768
d8e538ec
TG
769static int message_attribute_has_type(sd_rtnl_message *m, uint16_t attribute_type, uint16_t data_type) {
770 const NLType *type;
771 int r;
772
773 r = type_system_get_type(m->container_type_system[m->n_containers], &type, attribute_type);
774 if (r < 0)
775 return r;
776
777 if (type->type != data_type)
778 return -EINVAL;
779
780 return type->size;
781}
782
0a0dc69b 783int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data) {
d8e538ec 784 size_t length, size;
0a0dc69b 785 int r;
65f568bb
TG
786
787 assert_return(m, -EINVAL);
e5c4350b 788 assert_return(!m->sealed, -EPERM);
65f568bb
TG
789 assert_return(data, -EINVAL);
790
d8e538ec 791 r = message_attribute_has_type(m, type, NLA_STRING);
0a0dc69b
TG
792 if (r < 0)
793 return r;
d8e538ec
TG
794 else
795 size = (size_t)r;
65f568bb 796
d8e538ec 797 if (size) {
3072eecf
LP
798 length = strnlen(data, size+1);
799 if (length > size)
d8e538ec
TG
800 return -EINVAL;
801 } else
802 length = strlen(data);
33125ac5 803
d8e538ec 804 r = add_rtattr(m, type, data, length + 1);
0a0dc69b
TG
805 if (r < 0)
806 return r;
807
808 return 0;
809}
810
7b179640 811int sd_rtnl_message_append_u8(sd_rtnl_message *m, unsigned short type, uint8_t data) {
7b179640
SS
812 int r;
813
814 assert_return(m, -EINVAL);
815 assert_return(!m->sealed, -EPERM);
816
d8e538ec 817 r = message_attribute_has_type(m, type, NLA_U8);
7b179640
SS
818 if (r < 0)
819 return r;
820
7b179640
SS
821 r = add_rtattr(m, type, &data, sizeof(uint8_t));
822 if (r < 0)
823 return r;
824
825 return 0;
826}
827
828
01b36069 829int sd_rtnl_message_append_u16(sd_rtnl_message *m, unsigned short type, uint16_t data) {
01b36069
TG
830 int r;
831
832 assert_return(m, -EINVAL);
e5c4350b 833 assert_return(!m->sealed, -EPERM);
01b36069 834
d8e538ec 835 r = message_attribute_has_type(m, type, NLA_U16);
01b36069
TG
836 if (r < 0)
837 return r;
838
01b36069
TG
839 r = add_rtattr(m, type, &data, sizeof(uint16_t));
840 if (r < 0)
841 return r;
842
843 return 0;
844}
845
0a0dc69b 846int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) {
0a0dc69b
TG
847 int r;
848
849 assert_return(m, -EINVAL);
e5c4350b 850 assert_return(!m->sealed, -EPERM);
0a0dc69b 851
d8e538ec 852 r = message_attribute_has_type(m, type, NLA_U32);
0a0dc69b
TG
853 if (r < 0)
854 return r;
855
4d47756b 856 r = add_rtattr(m, type, &data, sizeof(uint32_t));
0a0dc69b
TG
857 if (r < 0)
858 return r;
859
860 return 0;
861}
862
863int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) {
0a0dc69b
TG
864 int r;
865
866 assert_return(m, -EINVAL);
e5c4350b 867 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
868 assert_return(data, -EINVAL);
869
d8e538ec 870 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
0a0dc69b
TG
871 if (r < 0)
872 return r;
873
4d47756b 874 r = add_rtattr(m, type, data, sizeof(struct in_addr));
0a0dc69b
TG
875 if (r < 0)
876 return r;
877
878 return 0;
879}
880
881int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) {
0a0dc69b
TG
882 int r;
883
884 assert_return(m, -EINVAL);
e5c4350b 885 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
886 assert_return(data, -EINVAL);
887
d8e538ec 888 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
0a0dc69b
TG
889 if (r < 0)
890 return r;
891
4d47756b 892 r = add_rtattr(m, type, data, sizeof(struct in6_addr));
0a0dc69b
TG
893 if (r < 0)
894 return r;
895
896 return 0;
897}
898
899int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) {
0a0dc69b
TG
900 int r;
901
902 assert_return(m, -EINVAL);
e5c4350b 903 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
904 assert_return(data, -EINVAL);
905
d8e538ec
TG
906 r = message_attribute_has_type(m, type, NLA_ETHER_ADDR);
907 if (r < 0)
908 return r;
0a0dc69b 909
b9eaf3d1 910 r = add_rtattr(m, type, data, ETH_ALEN);
0a0dc69b
TG
911 if (r < 0)
912 return r;
913
914 return 0;
65f568bb
TG
915}
916
aba496a5
UTL
917int sd_rtnl_message_append_cache_info(sd_rtnl_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
918 int r;
919
920 assert_return(m, -EINVAL);
921 assert_return(!m->sealed, -EPERM);
922 assert_return(info, -EINVAL);
923
924 r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
925 if (r < 0)
926 return r;
927
928 r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
929 if (r < 0)
930 return r;
931
932 return 0;
933}
934
ee3a6a51 935int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
d8e538ec
TG
936 size_t size;
937 int r;
33125ac5 938
65f568bb 939 assert_return(m, -EINVAL);
e5c4350b 940 assert_return(!m->sealed, -EPERM);
7ca1d319 941 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE);
33125ac5 942
d8e538ec 943 r = message_attribute_has_type(m, type, NLA_NESTED);
4af7b60d
TG
944 if (r < 0) {
945 const NLTypeSystemUnion *type_system_union;
946 int family;
947
948 r = message_attribute_has_type(m, type, NLA_UNION);
949 if (r < 0)
950 return r;
951 size = (size_t) r;
952
953 r = sd_rtnl_message_get_family(m, &family);
954 if (r < 0)
955 return r;
956
957 r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
958 if (r < 0)
959 return r;
960
961 r = type_system_union_protocol_get_type_system(type_system_union,
962 &m->container_type_system[m->n_containers + 1],
963 family);
964 if (r < 0)
965 return r;
966 } else {
d8e538ec 967 size = (size_t)r;
33125ac5 968
4af7b60d
TG
969 r = type_system_get_type_system(m->container_type_system[m->n_containers],
970 &m->container_type_system[m->n_containers + 1],
971 type);
972 if (r < 0)
973 return r;
974 }
31a4e153 975
fcf81a54 976 r = add_rtattr(m, type | NLA_F_NESTED, NULL, size);
d8e538ec
TG
977 if (r < 0)
978 return r;
979
7ca1d319
TG
980 m->container_offsets[m->n_containers ++] = r;
981
d8e538ec
TG
982 return 0;
983}
984
985int sd_rtnl_message_open_container_union(sd_rtnl_message *m, unsigned short type, const char *key) {
986 const NLTypeSystemUnion *type_system_union;
987 int r;
988
989 assert_return(m, -EINVAL);
990 assert_return(!m->sealed, -EPERM);
991
992 r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
993 if (r < 0)
994 return r;
995
996 r = type_system_union_get_type_system(type_system_union,
997 &m->container_type_system[m->n_containers + 1],
998 key);
999 if (r < 0)
1000 return r;
33125ac5 1001
d8e538ec
TG
1002 r = sd_rtnl_message_append_string(m, type_system_union->match, key);
1003 if (r < 0)
1004 return r;
1005
1006 /* do we evere need non-null size */
1007 r = add_rtattr(m, type, NULL, 0);
1008 if (r < 0)
1009 return r;
1010
7ca1d319
TG
1011 m->container_offsets[m->n_containers ++] = r;
1012
d8e538ec 1013 return 0;
33125ac5
TG
1014}
1015
d8e538ec 1016
33125ac5
TG
1017int sd_rtnl_message_close_container(sd_rtnl_message *m) {
1018 assert_return(m, -EINVAL);
e5c4350b 1019 assert_return(!m->sealed, -EPERM);
5a081409 1020 assert_return(m->n_containers > 0, -EINVAL);
33125ac5 1021
d8e538ec 1022 m->container_type_system[m->n_containers] = NULL;
5a081409 1023 m->n_containers --;
33125ac5
TG
1024
1025 return 0;
1026}
1027
44caa5e7 1028int rtnl_message_read_internal(sd_rtnl_message *m, unsigned short type, void **data) {
f66eeb6b
TG
1029 struct rtattr *rta;
1030
44caa5e7
SS
1031 assert_return(m, -EINVAL);
1032 assert_return(m->sealed, -EPERM);
1033 assert_return(data, -EINVAL);
d8e538ec
TG
1034 assert(m->n_containers <= RTNL_CONTAINER_DEPTH);
1035 assert(m->rta_offset_tb[m->n_containers]);
1036 assert(type < m->rta_tb_size[m->n_containers]);
44caa5e7 1037
3dd215e0 1038 if(!m->rta_offset_tb[m->n_containers][type])
44caa5e7
SS
1039 return -ENODATA;
1040
3dd215e0 1041 rta = (struct rtattr*)((uint8_t *) m->hdr + m->rta_offset_tb[m->n_containers][type]);
44caa5e7 1042
f66eeb6b
TG
1043 *data = RTA_DATA(rta);
1044
1045 return RTA_PAYLOAD(rta);
44caa5e7
SS
1046}
1047
ca4e095a 1048int sd_rtnl_message_read_string(sd_rtnl_message *m, unsigned short type, const char **data) {
44caa5e7
SS
1049 int r;
1050 void *attr_data;
1051
73ae2b7d
TG
1052 assert_return(m, -EINVAL);
1053
d8e538ec
TG
1054 r = message_attribute_has_type(m, type, NLA_STRING);
1055 if (r < 0)
1056 return r;
44caa5e7
SS
1057
1058 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 1059 if (r < 0)
44caa5e7 1060 return r;
f66eeb6b
TG
1061 else if (strnlen(attr_data, r) >= (size_t) r)
1062 return -EIO;
44caa5e7 1063
73ae2b7d
TG
1064 if (data)
1065 *data = (const char *) attr_data;
44caa5e7
SS
1066
1067 return 0;
1068}
1069
1070int sd_rtnl_message_read_u8(sd_rtnl_message *m, unsigned short type, uint8_t *data) {
1071 int r;
1072 void *attr_data;
1073
73ae2b7d
TG
1074 assert_return(m, -EINVAL);
1075
d8e538ec
TG
1076 r = message_attribute_has_type(m, type, NLA_U8);
1077 if (r < 0)
1078 return r;
44caa5e7
SS
1079
1080 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 1081 if (r < 0)
44caa5e7 1082 return r;
f66eeb6b
TG
1083 else if ((size_t) r < sizeof(uint8_t))
1084 return -EIO;
44caa5e7 1085
73ae2b7d
TG
1086 if (data)
1087 *data = *(uint8_t *) attr_data;
44caa5e7
SS
1088
1089 return 0;
1090}
1091
1092int sd_rtnl_message_read_u16(sd_rtnl_message *m, unsigned short type, uint16_t *data) {
1093 int r;
1094 void *attr_data;
1095
73ae2b7d
TG
1096 assert_return(m, -EINVAL);
1097
d8e538ec
TG
1098 r = message_attribute_has_type(m, type, NLA_U16);
1099 if (r < 0)
1100 return r;
44caa5e7
SS
1101
1102 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 1103 if (r < 0)
44caa5e7 1104 return r;
f66eeb6b
TG
1105 else if ((size_t) r < sizeof(uint16_t))
1106 return -EIO;
44caa5e7 1107
73ae2b7d
TG
1108 if (data)
1109 *data = *(uint16_t *) attr_data;
44caa5e7
SS
1110
1111 return 0;
1112}
1113
1114int sd_rtnl_message_read_u32(sd_rtnl_message *m, unsigned short type, uint32_t *data) {
1115 int r;
1116 void *attr_data;
1117
73ae2b7d
TG
1118 assert_return(m, -EINVAL);
1119
d8e538ec
TG
1120 r = message_attribute_has_type(m, type, NLA_U32);
1121 if (r < 0)
1122 return r;
44caa5e7
SS
1123
1124 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 1125 if (r < 0)
44caa5e7 1126 return r;
f66eeb6b
TG
1127 else if ((size_t)r < sizeof(uint32_t))
1128 return -EIO;
44caa5e7 1129
73ae2b7d
TG
1130 if (data)
1131 *data = *(uint32_t *) attr_data;
44caa5e7
SS
1132
1133 return 0;
1134}
1135
4e9e7f18
SS
1136int sd_rtnl_message_read_ether_addr(sd_rtnl_message *m, unsigned short type, struct ether_addr *data) {
1137 int r;
1138 void *attr_data;
1139
73ae2b7d
TG
1140 assert_return(m, -EINVAL);
1141
d8e538ec
TG
1142 r = message_attribute_has_type(m, type, NLA_ETHER_ADDR);
1143 if (r < 0)
1144 return r;
4e9e7f18
SS
1145
1146 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 1147 if (r < 0)
4e9e7f18 1148 return r;
f66eeb6b
TG
1149 else if ((size_t)r < sizeof(struct ether_addr))
1150 return -EIO;
4e9e7f18 1151
73ae2b7d
TG
1152 if (data)
1153 memcpy(data, attr_data, sizeof(struct ether_addr));
4e9e7f18
SS
1154
1155 return 0;
1156}
1157
aba496a5
UTL
1158int sd_rtnl_message_read_cache_info(sd_rtnl_message *m, unsigned short type, struct ifa_cacheinfo *info) {
1159 int r;
1160 void *attr_data;
1161
73ae2b7d
TG
1162 assert_return(m, -EINVAL);
1163
aba496a5
UTL
1164 r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
1165 if (r < 0)
1166 return r;
1167
1168 r = rtnl_message_read_internal(m, type, &attr_data);
1169 if (r < 0)
1170 return r;
1171 else if ((size_t)r < sizeof(struct ifa_cacheinfo))
1172 return -EIO;
1173
73ae2b7d
TG
1174 if (info)
1175 memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
aba496a5
UTL
1176
1177 return 0;
1178}
1179
4e9e7f18
SS
1180int sd_rtnl_message_read_in_addr(sd_rtnl_message *m, unsigned short type, struct in_addr *data) {
1181 int r;
1182 void *attr_data;
1183
73ae2b7d
TG
1184 assert_return(m, -EINVAL);
1185
d8e538ec
TG
1186 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
1187 if (r < 0)
1188 return r;
4e9e7f18
SS
1189
1190 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 1191 if (r < 0)
4e9e7f18 1192 return r;
f66eeb6b
TG
1193 else if ((size_t)r < sizeof(struct in_addr))
1194 return -EIO;
4e9e7f18 1195
73ae2b7d
TG
1196 if (data)
1197 memcpy(data, attr_data, sizeof(struct in_addr));
4e9e7f18
SS
1198
1199 return 0;
1200}
1201
1202int sd_rtnl_message_read_in6_addr(sd_rtnl_message *m, unsigned short type, struct in6_addr *data) {
1203 int r;
1204 void *attr_data;
1205
73ae2b7d
TG
1206 assert_return(m, -EINVAL);
1207
d8e538ec
TG
1208 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
1209 if (r < 0)
1210 return r;
4e9e7f18
SS
1211
1212 r = rtnl_message_read_internal(m, type, &attr_data);
3dd215e0 1213 if (r < 0)
4e9e7f18 1214 return r;
3dd215e0
TG
1215 else if ((size_t)r < sizeof(struct in6_addr))
1216 return -EIO;
4e9e7f18 1217
73ae2b7d
TG
1218 if (data)
1219 memcpy(data, attr_data, sizeof(struct in6_addr));
4e9e7f18
SS
1220
1221 return 0;
1222}
1223
3dd215e0 1224int sd_rtnl_message_enter_container(sd_rtnl_message *m, unsigned short type) {
d8e538ec
TG
1225 const NLType *nl_type;
1226 const NLTypeSystem *type_system;
3dd215e0 1227 void *container;
d8e538ec
TG
1228 size_t size;
1229 int r;
3dd215e0
TG
1230
1231 assert_return(m, -EINVAL);
1232 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
1233
d8e538ec
TG
1234 r = type_system_get_type(m->container_type_system[m->n_containers],
1235 &nl_type,
1236 type);
3dd215e0
TG
1237 if (r < 0)
1238 return r;
3dd215e0 1239
d8e538ec
TG
1240 if (nl_type->type == NLA_NESTED) {
1241 r = type_system_get_type_system(m->container_type_system[m->n_containers],
1242 &type_system,
1243 type);
1244 if (r < 0)
1245 return r;
1246 } else if (nl_type->type == NLA_UNION) {
1247 const NLTypeSystemUnion *type_system_union;
d8e538ec
TG
1248
1249 r = type_system_get_type_system_union(m->container_type_system[m->n_containers],
1250 &type_system_union,
1251 type);
1252 if (r < 0)
1253 return r;
1254
4af7b60d
TG
1255 switch (type_system_union->match_type) {
1256 case NL_MATCH_SIBLING:
1257 {
1258 const char *key;
1259
1260 r = sd_rtnl_message_read_string(m, type_system_union->match, &key);
1261 if (r < 0)
1262 return r;
1263
1264 r = type_system_union_get_type_system(type_system_union,
1265 &type_system,
1266 key);
1267 if (r < 0)
1268 return r;
1269
1270 break;
1271 }
1272 case NL_MATCH_PROTOCOL:
1273 {
1274 int family;
1275
1276 r = sd_rtnl_message_get_family(m, &family);
1277 if (r < 0)
1278 return r;
1279
1280 r = type_system_union_protocol_get_type_system(type_system_union,
1281 &type_system,
1282 family);
1283 if (r < 0)
1284 return r;
1285
1286 break;
1287 }
1288 default:
1289 assert_not_reached("sd-rtnl: invalid type system union type");
1290 }
d8e538ec
TG
1291 } else
1292 return -EINVAL;
1293
1294 r = rtnl_message_read_internal(m, type, &container);
3dd215e0
TG
1295 if (r < 0)
1296 return r;
d8e538ec
TG
1297 else
1298 size = (size_t)r;
3dd215e0 1299
d8e538ec 1300 m->n_containers ++;
3dd215e0
TG
1301
1302 r = rtnl_message_parse(m,
d8e538ec
TG
1303 &m->rta_offset_tb[m->n_containers],
1304 &m->rta_tb_size[m->n_containers],
1305 type_system->max,
3dd215e0 1306 container,
d8e538ec
TG
1307 size);
1308 if (r < 0) {
1309 m->n_containers --;
3dd215e0 1310 return r;
d8e538ec 1311 }
3dd215e0 1312
d8e538ec 1313 m->container_type_system[m->n_containers] = type_system;
3dd215e0
TG
1314
1315 return 0;
1316}
1317
e5c4350b
TG
1318int sd_rtnl_message_exit_container(sd_rtnl_message *m) {
1319 assert_return(m, -EINVAL);
1320 assert_return(m->sealed, -EINVAL);
1321 assert_return(m->n_containers > 0, -EINVAL);
1322
3dd215e0
TG
1323 free(m->rta_offset_tb[m->n_containers]);
1324 m->rta_offset_tb[m->n_containers] = NULL;
d8e538ec 1325 m->container_type_system[m->n_containers] = NULL;
3dd215e0 1326
e5c4350b
TG
1327 m->n_containers --;
1328
1329 return 0;
1330}
1331
3815f36f 1332uint32_t rtnl_message_get_serial(sd_rtnl_message *m) {
65f568bb 1333 assert(m);
9d0db178 1334 assert(m->hdr);
65f568bb
TG
1335
1336 return m->hdr->nlmsg_seq;
1337}
1338
45af44d4
TG
1339int sd_rtnl_message_is_error(sd_rtnl_message *m) {
1340 assert_return(m, 0);
1341 assert_return(m->hdr, 0);
1342
1343 return m->hdr->nlmsg_type == NLMSG_ERROR;
1344}
1345
e16bcf98 1346int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
65f568bb
TG
1347 struct nlmsgerr *err;
1348
e16bcf98 1349 assert_return(m, -EINVAL);
9d0db178 1350 assert_return(m->hdr, -EINVAL);
65f568bb 1351
45af44d4 1352 if (!sd_rtnl_message_is_error(m))
65f568bb
TG
1353 return 0;
1354
1355 err = NLMSG_DATA(m->hdr);
1356
1357 return err->error;
1358}
1359
44caa5e7
SS
1360int rtnl_message_parse(sd_rtnl_message *m,
1361 size_t **rta_offset_tb,
1362 unsigned short *rta_tb_size,
1363 int max,
1364 struct rtattr *rta,
1365 unsigned int rt_len) {
e634cd40 1366 unsigned short type;
44caa5e7
SS
1367 size_t *tb;
1368
c8a7165f 1369 tb = new0(size_t, max + 1);
44caa5e7
SS
1370 if(!tb)
1371 return -ENOMEM;
1372
c8a7165f 1373 *rta_tb_size = max + 1;
44caa5e7
SS
1374
1375 for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
0a2478a9 1376 type = RTA_TYPE(rta);
44caa5e7 1377
aef0768e
TG
1378 /* if the kernel is newer than the headers we used
1379 when building, we ignore out-of-range attributes
1380 */
1381 if (type > max)
e634cd40 1382 continue;
e634cd40
TG
1383
1384 if (tb[type])
1385 log_debug("rtnl: message parse - overwriting repeated attribute");
1386
1387 tb[type] = (uint8_t *) rta - (uint8_t *) m->hdr;
44caa5e7
SS
1388 }
1389
1390 *rta_offset_tb = tb;
1391
1392 return 0;
1393}
1394
65f568bb
TG
1395/* returns the number of bytes sent, or a negative error code */
1396int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
d4bbdb77
TG
1397 union {
1398 struct sockaddr sa;
1399 struct sockaddr_nl nl;
1400 } addr = {
1401 .nl.nl_family = AF_NETLINK,
1402 };
65f568bb
TG
1403 ssize_t k;
1404
9d0db178
TG
1405 assert(nl);
1406 assert(m);
1407 assert(m->hdr);
65f568bb
TG
1408
1409 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
d4bbdb77 1410 0, &addr.sa, sizeof(addr));
65f568bb
TG
1411 if (k < 0)
1412 return (errno == EAGAIN) ? 0 : -errno;
1413
1414 return k;
1415}
1416
66269b05
TG
1417static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool peek) {
1418 uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred)) +
1419 CMSG_SPACE(sizeof(struct nl_pktinfo))];
bc078e71 1420 struct msghdr msg = {
26349add 1421 .msg_iov = iov,
bc078e71
TG
1422 .msg_iovlen = 1,
1423 .msg_control = cred_buffer,
1424 .msg_controllen = sizeof(cred_buffer),
1425 };
1426 struct cmsghdr *cmsg;
66269b05 1427 uint32_t group = 0;
26349add 1428 bool auth = false;
4e996881 1429 int r;
d4bbdb77 1430
26349add
TG
1431 assert(fd >= 0);
1432 assert(iov);
bc078e71 1433
a38d9945 1434 r = recvmsg(fd, &msg, MSG_TRUNC | (peek ? MSG_PEEK : 0));
5968b1c3 1435 if (r < 0) {
bc078e71 1436 /* no data */
5968b1c3
TG
1437 if (errno == ENOBUFS)
1438 log_debug("rtnl: kernel receive buffer overrun");
0b2bbbdf
TG
1439 else if (errno == EAGAIN)
1440 log_debug("rtnl: no data in socket");
5968b1c3 1441
0b2bbbdf 1442 return (errno == EAGAIN || errno == EINTR) ? 0 : -errno;
da53c551 1443 }
3dd215e0 1444
bc078e71
TG
1445 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1446 if (cmsg->cmsg_level == SOL_SOCKET &&
1447 cmsg->cmsg_type == SCM_CREDENTIALS &&
1448 cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
1449 struct ucred *ucred = (void *)CMSG_DATA(cmsg);
1450
1451 /* from the kernel */
09773ef4 1452 if (ucred->pid == 0)
bc078e71 1453 auth = true;
2263bb9a 1454 else
1fa2f38f 1455 log_debug("rtnl: ignoring message from PID "PID_FMT, ucred->pid);
66269b05
TG
1456 } else if (cmsg->cmsg_level == SOL_NETLINK &&
1457 cmsg->cmsg_type == NETLINK_PKTINFO &&
1458 cmsg->cmsg_len == CMSG_LEN(sizeof(struct nl_pktinfo))) {
1459 struct nl_pktinfo *pktinfo = (void *)CMSG_DATA(cmsg);
1460
1461 /* multi-cast group */
1462 group = pktinfo->group;
bc078e71
TG
1463 }
1464 }
1465
c7460cce 1466 if (!auth) {
bc078e71 1467 /* not from the kernel, ignore */
c7460cce
TG
1468 if (peek) {
1469 /* drop the message */
a38d9945 1470 r = recvmsg(fd, &msg, 0);
c7460cce
TG
1471 if (r < 0)
1472 return (errno == EAGAIN || errno == EINTR) ? 0 : -errno;
1473 }
1474
bc078e71 1475 return 0;
c7460cce 1476 }
bc078e71 1477
0964dcd7 1478 if (_group)
66269b05
TG
1479 *_group = group;
1480
26349add
TG
1481 return r;
1482}
1483
1484/* On success, the number of bytes received is returned and *ret points to the received message
1485 * which has a valid header and the correct size.
1486 * If nothing useful was received 0 is returned.
1487 * On failure, a negative error code is returned.
1488 */
1489int socket_read_message(sd_rtnl *rtnl) {
1490 _cleanup_rtnl_message_unref_ sd_rtnl_message *first = NULL;
1491 struct iovec iov = {};
66269b05 1492 uint32_t group = 0;
26349add
TG
1493 bool multi_part = false, done = false;
1494 struct nlmsghdr *new_msg;
1495 size_t len;
1496 int r;
1497 unsigned i = 0;
1498
1499 assert(rtnl);
1500 assert(rtnl->rbuffer);
1501 assert(rtnl->rbuffer_allocated >= sizeof(struct nlmsghdr));
1502
1503 /* read nothing, just get the pending message size */
0964dcd7 1504 r = socket_recv_message(rtnl->fd, &iov, NULL, true);
26349add
TG
1505 if (r <= 0)
1506 return r;
1507 else
1508 len = (size_t)r;
1509
1510 /* make room for the pending message */
1511 if (!greedy_realloc((void **)&rtnl->rbuffer,
1512 &rtnl->rbuffer_allocated,
1513 len, sizeof(uint8_t)))
1514 return -ENOMEM;
1515
1516 iov.iov_base = rtnl->rbuffer;
1517 iov.iov_len = rtnl->rbuffer_allocated;
1518
1519 /* read the pending message */
66269b05 1520 r = socket_recv_message(rtnl->fd, &iov, &group, false);
26349add
TG
1521 if (r <= 0)
1522 return r;
1523 else
1524 len = (size_t)r;
1525
127dc4ea
TG
1526 if (len > rtnl->rbuffer_allocated)
1527 /* message did not fit in read buffer */
1528 return -EIO;
1529
4e996881
TG
1530 if (NLMSG_OK(rtnl->rbuffer, len) && rtnl->rbuffer->nlmsg_flags & NLM_F_MULTI) {
1531 multi_part = true;
1532
1533 for (i = 0; i < rtnl->rqueue_partial_size; i++) {
1534 if (rtnl_message_get_serial(rtnl->rqueue_partial[i]) ==
1535 rtnl->rbuffer->nlmsg_seq) {
1536 first = rtnl->rqueue_partial[i];
1537 break;
1538 }
1539 }
1540 }
1541
0e707326 1542 for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) {
1b89cf56
TG
1543 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
1544 const NLType *nl_type;
3dd215e0 1545
8fe65c03 1546 if (!group && new_msg->nlmsg_pid != rtnl->sockaddr.nl.nl_pid)
1b89cf56
TG
1547 /* not broadcast and not for us */
1548 continue;
3dd215e0 1549
1b89cf56 1550 if (new_msg->nlmsg_type == NLMSG_NOOP)
4e996881 1551 /* silently drop noop messages */
1b89cf56 1552 continue;
bdd13f6b 1553
4e996881
TG
1554 if (new_msg->nlmsg_type == NLMSG_DONE) {
1555 /* finished reading multi-part message */
1556 done = true;
0e707326 1557
ea342a99
AR
1558 /* if first is not defined, put NLMSG_DONE into the receive queue. */
1559 if (first)
1560 continue;
4e996881 1561 }
1403f45a 1562
1b89cf56
TG
1563 /* check that we support this message type */
1564 r = type_system_get_type(NULL, &nl_type, new_msg->nlmsg_type);
1565 if (r < 0) {
15411c0c 1566 if (r == -EOPNOTSUPP)
8facc349 1567 log_debug("sd-rtnl: ignored message with unknown type: %i",
1b89cf56 1568 new_msg->nlmsg_type);
d8e538ec 1569
1b89cf56
TG
1570 continue;
1571 }
bdd13f6b 1572
1b89cf56 1573 /* check that the size matches the message type */
64918838
TG
1574 if (new_msg->nlmsg_len < NLMSG_LENGTH(nl_type->size)) {
1575 log_debug("sd-rtnl: message larger than expected, dropping");
1b89cf56 1576 continue;
64918838 1577 }
65f568bb 1578
1b89cf56
TG
1579 r = message_new_empty(rtnl, &m);
1580 if (r < 0)
1581 return r;
1582
3f42446d
TG
1583 m->broadcast = !!group;
1584
1b89cf56
TG
1585 m->hdr = memdup(new_msg, new_msg->nlmsg_len);
1586 if (!m->hdr)
1587 return -ENOMEM;
1588
1589 /* seal and parse the top-level message */
1590 r = sd_rtnl_message_rewind(m);
1591 if (r < 0)
1592 return r;
1593
4e996881
TG
1594 /* push the message onto the multi-part message stack */
1595 if (first)
1596 m->next = first;
1597 first = m;
1b89cf56 1598 m = NULL;
4e996881 1599 }
1403f45a 1600
4e996881
TG
1601 if (len)
1602 log_debug("sd-rtnl: discarding %zu bytes of incoming message", len);
1b89cf56 1603
4e996881
TG
1604 if (!first)
1605 return 0;
65f568bb 1606
4e996881
TG
1607 if (!multi_part || done) {
1608 /* we got a complete message, push it on the read queue */
24a02673
TG
1609 r = rtnl_rqueue_make_room(rtnl);
1610 if (r < 0)
1611 return r;
1612
d4ef4f46
TG
1613 rtnl->rqueue[rtnl->rqueue_size ++] = first;
1614 first = NULL;
1615
1616 if (multi_part && (i < rtnl->rqueue_partial_size)) {
4e996881
TG
1617 /* remove the message form the partial read queue */
1618 memmove(rtnl->rqueue_partial + i,rtnl->rqueue_partial + i + 1,
1619 sizeof(sd_rtnl_message*) * (rtnl->rqueue_partial_size - i - 1));
1620 rtnl->rqueue_partial_size --;
1621 }
1622
4e996881
TG
1623 return 1;
1624 } else {
1625 /* we only got a partial multi-part message, push it on the
1626 partial read queue */
1627 if (i < rtnl->rqueue_partial_size) {
1628 rtnl->rqueue_partial[i] = first;
1629 } else {
1630 r = rtnl_rqueue_partial_make_room(rtnl);
1631 if (r < 0)
1632 return r;
1633
1634 rtnl->rqueue_partial[rtnl->rqueue_partial_size ++] = first;
1635 }
1636 first = NULL;
1403f45a 1637
4e996881
TG
1638 return 0;
1639 }
65f568bb 1640}
0fc7531b
TG
1641
1642int sd_rtnl_message_rewind(sd_rtnl_message *m) {
d8e538ec 1643 const NLType *type;
3dd215e0
TG
1644 unsigned i;
1645 int r;
0fc7531b
TG
1646
1647 assert_return(m, -EINVAL);
0fc7531b 1648
3dd215e0
TG
1649 /* don't allow appending to message once parsed */
1650 if (!m->sealed)
1651 rtnl_message_seal(m);
1652
1653 for (i = 1; i <= m->n_containers; i++) {
1654 free(m->rta_offset_tb[i]);
1655 m->rta_offset_tb[i] = NULL;
1656 m->rta_tb_size[i] = 0;
d8e538ec 1657 m->container_type_system[i] = NULL;
3dd215e0
TG
1658 }
1659
1660 m->n_containers = 0;
1661
1662 if (m->rta_offset_tb[0]) {
1663 /* top-level attributes have already been parsed */
1664 return 0;
1665 }
1666
d8e538ec
TG
1667 assert(m->hdr);
1668
1669 r = type_system_get_type(NULL, &type, m->hdr->nlmsg_type);
1670 if (r < 0)
1671 return r;
1672
1673 if (type->type == NLA_NESTED) {
1674 const NLTypeSystem *type_system = type->type_system;
1675
1676 assert(type_system);
1677
1678 m->container_type_system[0] = type_system;
1679
1680 r = rtnl_message_parse(m,
1681 &m->rta_offset_tb[m->n_containers],
1682 &m->rta_tb_size[m->n_containers],
1683 type_system->max,
0834ff93
TG
1684 (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) +
1685 NLMSG_ALIGN(type->size)),
d8e538ec
TG
1686 NLMSG_PAYLOAD(m->hdr, type->size));
1687 if (r < 0)
1688 return r;
0fc7531b
TG
1689 }
1690
1691 return 0;
1692}
3dd215e0
TG
1693
1694void rtnl_message_seal(sd_rtnl_message *m) {
1695 assert(m);
1696 assert(!m->sealed);
1697
1698 m->sealed = true;
1699}
1403f45a
TG
1700
1701sd_rtnl_message *sd_rtnl_message_next(sd_rtnl_message *m) {
1702 assert_return(m, NULL);
1703
1704 return m->next;
1705}