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