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