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