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