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