]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-rtnl/rtnl-message.c
udev: modernize net_id builtin a bit
[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
4ebe732c
ZJS
468/* If successful the updated message will be correctly aligned, if
469 unsuccessful the old message is untouched. */
65f568bb 470static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
7ca1d319
TG
471 uint32_t rta_length;
472 size_t message_length, padding_length;
65f568bb
TG
473 struct nlmsghdr *new_hdr;
474 struct rtattr *rta;
8e337e64 475 char *padding;
5a081409 476 unsigned i;
7ca1d319 477 int offset;
65f568bb 478
33125ac5
TG
479 assert(m);
480 assert(m->hdr);
e5c4350b 481 assert(!m->sealed);
33125ac5 482 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
7ca1d319
TG
483 assert(!data || data_length);
484
485 /* get offset of the new attribute */
486 offset = m->hdr->nlmsg_len;
65f568bb 487
8e337e64 488 /* get the size of the new rta attribute (with padding at the end) */
65f568bb 489 rta_length = RTA_LENGTH(data_length);
4ebe732c
ZJS
490
491 /* get the new message size (with padding at the end) */
7ca1d319 492 message_length = offset + RTA_ALIGN(rta_length);
65f568bb
TG
493
494 /* realloc to fit the new attribute */
495 new_hdr = realloc(m->hdr, message_length);
496 if (!new_hdr)
497 return -ENOMEM;
498 m->hdr = new_hdr;
499
500 /* get pointer to the attribute we are about to add */
7ca1d319 501 rta = (struct rtattr *) ((uint8_t *) m->hdr + offset);
65f568bb 502
5a081409
TG
503 /* if we are inside containers, extend them */
504 for (i = 0; i < m->n_containers; i++)
7ca1d319 505 GET_CONTAINER(m, i)->rta_len += message_length - offset;
33125ac5 506
65f568bb
TG
507 /* fill in the attribute */
508 rta->rta_type = type;
509 rta->rta_len = rta_length;
7ca1d319 510 if (data)
33125ac5
TG
511 /* we don't deal with the case where the user lies about the type
512 * and gives us too little data (so don't do that)
7ca1d319 513 */
33125ac5 514 padding = mempcpy(RTA_DATA(rta), data, data_length);
7ca1d319
TG
515 else {
516 /* if no data was passed, make sure we still initialize the padding
517 note that we can have data_length > 0 (used by some containers) */
518 padding = RTA_DATA(rta);
519 data_length = 0;
33125ac5 520 }
65f568bb 521
7ca1d319
TG
522 /* make sure also the padding at the end of the message is initialized */
523 padding_length = (uint8_t*)m->hdr + message_length - (uint8_t*)padding;
524 memzero(padding, padding_length);
525
4ebe732c
ZJS
526 /* update message size */
527 m->hdr->nlmsg_len = message_length;
528
7ca1d319 529 return offset;
65f568bb
TG
530}
531
d8e538ec
TG
532static int message_attribute_has_type(sd_rtnl_message *m, uint16_t attribute_type, uint16_t data_type) {
533 const NLType *type;
534 int r;
535
536 r = type_system_get_type(m->container_type_system[m->n_containers], &type, attribute_type);
537 if (r < 0)
538 return r;
539
540 if (type->type != data_type)
541 return -EINVAL;
542
543 return type->size;
544}
545
0a0dc69b 546int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data) {
d8e538ec 547 size_t length, size;
0a0dc69b 548 int r;
65f568bb
TG
549
550 assert_return(m, -EINVAL);
e5c4350b 551 assert_return(!m->sealed, -EPERM);
65f568bb
TG
552 assert_return(data, -EINVAL);
553
d8e538ec 554 r = message_attribute_has_type(m, type, NLA_STRING);
0a0dc69b
TG
555 if (r < 0)
556 return r;
d8e538ec
TG
557 else
558 size = (size_t)r;
65f568bb 559
d8e538ec
TG
560 if (size) {
561 length = strnlen(data, size);
562 if (length >= size)
563 return -EINVAL;
564 } else
565 length = strlen(data);
33125ac5 566
d8e538ec 567 r = add_rtattr(m, type, data, length + 1);
0a0dc69b
TG
568 if (r < 0)
569 return r;
570
571 return 0;
572}
573
7b179640 574int sd_rtnl_message_append_u8(sd_rtnl_message *m, unsigned short type, uint8_t data) {
7b179640
SS
575 int r;
576
577 assert_return(m, -EINVAL);
578 assert_return(!m->sealed, -EPERM);
579
d8e538ec 580 r = message_attribute_has_type(m, type, NLA_U8);
7b179640
SS
581 if (r < 0)
582 return r;
583
7b179640
SS
584 r = add_rtattr(m, type, &data, sizeof(uint8_t));
585 if (r < 0)
586 return r;
587
588 return 0;
589}
590
591
01b36069 592int sd_rtnl_message_append_u16(sd_rtnl_message *m, unsigned short type, uint16_t data) {
01b36069
TG
593 int r;
594
595 assert_return(m, -EINVAL);
e5c4350b 596 assert_return(!m->sealed, -EPERM);
01b36069 597
d8e538ec 598 r = message_attribute_has_type(m, type, NLA_U16);
01b36069
TG
599 if (r < 0)
600 return r;
601
01b36069
TG
602 r = add_rtattr(m, type, &data, sizeof(uint16_t));
603 if (r < 0)
604 return r;
605
606 return 0;
607}
608
0a0dc69b 609int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) {
0a0dc69b
TG
610 int r;
611
612 assert_return(m, -EINVAL);
e5c4350b 613 assert_return(!m->sealed, -EPERM);
0a0dc69b 614
d8e538ec 615 r = message_attribute_has_type(m, type, NLA_U32);
0a0dc69b
TG
616 if (r < 0)
617 return r;
618
4d47756b 619 r = add_rtattr(m, type, &data, sizeof(uint32_t));
0a0dc69b
TG
620 if (r < 0)
621 return r;
622
623 return 0;
624}
625
626int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) {
0a0dc69b
TG
627 int r;
628
629 assert_return(m, -EINVAL);
e5c4350b 630 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
631 assert_return(data, -EINVAL);
632
d8e538ec 633 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
0a0dc69b
TG
634 if (r < 0)
635 return r;
636
4d47756b 637 r = add_rtattr(m, type, data, sizeof(struct in_addr));
0a0dc69b
TG
638 if (r < 0)
639 return r;
640
641 return 0;
642}
643
644int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) {
0a0dc69b
TG
645 int r;
646
647 assert_return(m, -EINVAL);
e5c4350b 648 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
649 assert_return(data, -EINVAL);
650
d8e538ec 651 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
0a0dc69b
TG
652 if (r < 0)
653 return r;
654
4d47756b 655 r = add_rtattr(m, type, data, sizeof(struct in6_addr));
0a0dc69b
TG
656 if (r < 0)
657 return r;
658
659 return 0;
660}
661
662int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) {
0a0dc69b
TG
663 int r;
664
665 assert_return(m, -EINVAL);
e5c4350b 666 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
667 assert_return(data, -EINVAL);
668
d8e538ec
TG
669 r = message_attribute_has_type(m, type, NLA_ETHER_ADDR);
670 if (r < 0)
671 return r;
0a0dc69b 672
b9eaf3d1 673 r = add_rtattr(m, type, data, ETH_ALEN);
0a0dc69b
TG
674 if (r < 0)
675 return r;
676
677 return 0;
65f568bb
TG
678}
679
aba496a5
UTL
680int sd_rtnl_message_append_cache_info(sd_rtnl_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
681 int r;
682
683 assert_return(m, -EINVAL);
684 assert_return(!m->sealed, -EPERM);
685 assert_return(info, -EINVAL);
686
687 r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
688 if (r < 0)
689 return r;
690
691 r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
692 if (r < 0)
693 return r;
694
695 return 0;
696}
697
ee3a6a51 698int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
d8e538ec
TG
699 size_t size;
700 int r;
33125ac5 701
65f568bb 702 assert_return(m, -EINVAL);
e5c4350b 703 assert_return(!m->sealed, -EPERM);
7ca1d319 704 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -ERANGE);
33125ac5 705
d8e538ec
TG
706 r = message_attribute_has_type(m, type, NLA_NESTED);
707 if (r < 0)
708 return r;
709 else
710 size = (size_t)r;
33125ac5 711
d8e538ec
TG
712 r = type_system_get_type_system(m->container_type_system[m->n_containers],
713 &m->container_type_system[m->n_containers + 1],
714 type);
715 if (r < 0)
716 return r;
31a4e153 717
d8e538ec
TG
718 r = add_rtattr(m, type, NULL, size);
719 if (r < 0)
720 return r;
721
7ca1d319
TG
722 m->container_offsets[m->n_containers ++] = r;
723
d8e538ec
TG
724 return 0;
725}
726
727int sd_rtnl_message_open_container_union(sd_rtnl_message *m, unsigned short type, const char *key) {
728 const NLTypeSystemUnion *type_system_union;
729 int r;
730
731 assert_return(m, -EINVAL);
732 assert_return(!m->sealed, -EPERM);
733
734 r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
735 if (r < 0)
736 return r;
737
738 r = type_system_union_get_type_system(type_system_union,
739 &m->container_type_system[m->n_containers + 1],
740 key);
741 if (r < 0)
742 return r;
33125ac5 743
d8e538ec
TG
744 r = sd_rtnl_message_append_string(m, type_system_union->match, key);
745 if (r < 0)
746 return r;
747
748 /* do we evere need non-null size */
749 r = add_rtattr(m, type, NULL, 0);
750 if (r < 0)
751 return r;
752
7ca1d319
TG
753 m->container_offsets[m->n_containers ++] = r;
754
d8e538ec 755 return 0;
33125ac5
TG
756}
757
d8e538ec 758
33125ac5
TG
759int sd_rtnl_message_close_container(sd_rtnl_message *m) {
760 assert_return(m, -EINVAL);
e5c4350b 761 assert_return(!m->sealed, -EPERM);
5a081409 762 assert_return(m->n_containers > 0, -EINVAL);
33125ac5 763
d8e538ec 764 m->container_type_system[m->n_containers] = NULL;
5a081409 765 m->n_containers --;
33125ac5
TG
766
767 return 0;
768}
769
44caa5e7 770int rtnl_message_read_internal(sd_rtnl_message *m, unsigned short type, void **data) {
f66eeb6b
TG
771 struct rtattr *rta;
772
44caa5e7
SS
773 assert_return(m, -EINVAL);
774 assert_return(m->sealed, -EPERM);
775 assert_return(data, -EINVAL);
d8e538ec
TG
776 assert(m->n_containers <= RTNL_CONTAINER_DEPTH);
777 assert(m->rta_offset_tb[m->n_containers]);
778 assert(type < m->rta_tb_size[m->n_containers]);
44caa5e7 779
3dd215e0 780 if(!m->rta_offset_tb[m->n_containers][type])
44caa5e7
SS
781 return -ENODATA;
782
3dd215e0 783 rta = (struct rtattr*)((uint8_t *) m->hdr + m->rta_offset_tb[m->n_containers][type]);
44caa5e7 784
f66eeb6b
TG
785 *data = RTA_DATA(rta);
786
787 return RTA_PAYLOAD(rta);
44caa5e7
SS
788}
789
ca4e095a 790int sd_rtnl_message_read_string(sd_rtnl_message *m, unsigned short type, const char **data) {
44caa5e7
SS
791 int r;
792 void *attr_data;
793
d8e538ec
TG
794 r = message_attribute_has_type(m, type, NLA_STRING);
795 if (r < 0)
796 return r;
44caa5e7
SS
797
798 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 799 if (r < 0)
44caa5e7 800 return r;
f66eeb6b
TG
801 else if (strnlen(attr_data, r) >= (size_t) r)
802 return -EIO;
44caa5e7 803
ca4e095a 804 *data = (const char *) attr_data;
44caa5e7
SS
805
806 return 0;
807}
808
809int sd_rtnl_message_read_u8(sd_rtnl_message *m, unsigned short type, uint8_t *data) {
810 int r;
811 void *attr_data;
812
d8e538ec
TG
813 r = message_attribute_has_type(m, type, NLA_U8);
814 if (r < 0)
815 return r;
44caa5e7
SS
816
817 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 818 if (r < 0)
44caa5e7 819 return r;
f66eeb6b
TG
820 else if ((size_t) r < sizeof(uint8_t))
821 return -EIO;
44caa5e7
SS
822
823 *data = *(uint8_t *) attr_data;
824
825 return 0;
826}
827
828int sd_rtnl_message_read_u16(sd_rtnl_message *m, unsigned short type, uint16_t *data) {
829 int r;
830 void *attr_data;
831
d8e538ec
TG
832 r = message_attribute_has_type(m, type, NLA_U16);
833 if (r < 0)
834 return r;
44caa5e7
SS
835
836 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 837 if (r < 0)
44caa5e7 838 return r;
f66eeb6b
TG
839 else if ((size_t) r < sizeof(uint16_t))
840 return -EIO;
44caa5e7
SS
841
842 *data = *(uint16_t *) attr_data;
843
844 return 0;
845}
846
847int sd_rtnl_message_read_u32(sd_rtnl_message *m, unsigned short type, uint32_t *data) {
848 int r;
849 void *attr_data;
850
d8e538ec
TG
851 r = message_attribute_has_type(m, type, NLA_U32);
852 if (r < 0)
853 return r;
44caa5e7
SS
854
855 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 856 if (r < 0)
44caa5e7 857 return r;
f66eeb6b
TG
858 else if ((size_t)r < sizeof(uint32_t))
859 return -EIO;
44caa5e7
SS
860
861 *data = *(uint32_t *) attr_data;
862
863 return 0;
864}
865
4e9e7f18
SS
866int sd_rtnl_message_read_ether_addr(sd_rtnl_message *m, unsigned short type, struct ether_addr *data) {
867 int r;
868 void *attr_data;
869
d8e538ec
TG
870 r = message_attribute_has_type(m, type, NLA_ETHER_ADDR);
871 if (r < 0)
872 return r;
4e9e7f18
SS
873
874 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 875 if (r < 0)
4e9e7f18 876 return r;
f66eeb6b
TG
877 else if ((size_t)r < sizeof(struct ether_addr))
878 return -EIO;
4e9e7f18
SS
879
880 memcpy(data, attr_data, sizeof(struct ether_addr));
881
882 return 0;
883}
884
aba496a5
UTL
885int sd_rtnl_message_read_cache_info(sd_rtnl_message *m, unsigned short type, struct ifa_cacheinfo *info) {
886 int r;
887 void *attr_data;
888
889 r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
890 if (r < 0)
891 return r;
892
893 r = rtnl_message_read_internal(m, type, &attr_data);
894 if (r < 0)
895 return r;
896 else if ((size_t)r < sizeof(struct ifa_cacheinfo))
897 return -EIO;
898
899 memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
900
901 return 0;
902}
903
4e9e7f18
SS
904int sd_rtnl_message_read_in_addr(sd_rtnl_message *m, unsigned short type, struct in_addr *data) {
905 int r;
906 void *attr_data;
907
d8e538ec
TG
908 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
909 if (r < 0)
910 return r;
4e9e7f18
SS
911
912 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 913 if (r < 0)
4e9e7f18 914 return r;
f66eeb6b
TG
915 else if ((size_t)r < sizeof(struct in_addr))
916 return -EIO;
4e9e7f18
SS
917
918 memcpy(data, attr_data, sizeof(struct in_addr));
919
920 return 0;
921}
922
923int sd_rtnl_message_read_in6_addr(sd_rtnl_message *m, unsigned short type, struct in6_addr *data) {
924 int r;
925 void *attr_data;
926
d8e538ec
TG
927 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
928 if (r < 0)
929 return r;
4e9e7f18
SS
930
931 r = rtnl_message_read_internal(m, type, &attr_data);
3dd215e0 932 if (r < 0)
4e9e7f18 933 return r;
3dd215e0
TG
934 else if ((size_t)r < sizeof(struct in6_addr))
935 return -EIO;
4e9e7f18
SS
936
937 memcpy(data, attr_data, sizeof(struct in6_addr));
938
939 return 0;
940}
941
3dd215e0 942int sd_rtnl_message_enter_container(sd_rtnl_message *m, unsigned short type) {
d8e538ec
TG
943 const NLType *nl_type;
944 const NLTypeSystem *type_system;
3dd215e0 945 void *container;
d8e538ec
TG
946 size_t size;
947 int r;
3dd215e0
TG
948
949 assert_return(m, -EINVAL);
950 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
951
d8e538ec
TG
952 r = type_system_get_type(m->container_type_system[m->n_containers],
953 &nl_type,
954 type);
3dd215e0
TG
955 if (r < 0)
956 return r;
3dd215e0 957
d8e538ec
TG
958 if (nl_type->type == NLA_NESTED) {
959 r = type_system_get_type_system(m->container_type_system[m->n_containers],
960 &type_system,
961 type);
962 if (r < 0)
963 return r;
964 } else if (nl_type->type == NLA_UNION) {
965 const NLTypeSystemUnion *type_system_union;
ca4e095a 966 const char *key;
d8e538ec
TG
967
968 r = type_system_get_type_system_union(m->container_type_system[m->n_containers],
969 &type_system_union,
970 type);
971 if (r < 0)
972 return r;
973
974 r = sd_rtnl_message_read_string(m, type_system_union->match, &key);
975 if (r < 0)
976 return r;
977
978 r = type_system_union_get_type_system(type_system_union,
979 &type_system,
980 key);
981 if (r < 0)
982 return r;
983 } else
984 return -EINVAL;
985
986 r = rtnl_message_read_internal(m, type, &container);
3dd215e0
TG
987 if (r < 0)
988 return r;
d8e538ec
TG
989 else
990 size = (size_t)r;
3dd215e0 991
d8e538ec 992 m->n_containers ++;
3dd215e0
TG
993
994 r = rtnl_message_parse(m,
d8e538ec
TG
995 &m->rta_offset_tb[m->n_containers],
996 &m->rta_tb_size[m->n_containers],
997 type_system->max,
3dd215e0 998 container,
d8e538ec
TG
999 size);
1000 if (r < 0) {
1001 m->n_containers --;
3dd215e0 1002 return r;
d8e538ec 1003 }
3dd215e0 1004
d8e538ec 1005 m->container_type_system[m->n_containers] = type_system;
3dd215e0
TG
1006
1007 return 0;
1008}
1009
e5c4350b
TG
1010int sd_rtnl_message_exit_container(sd_rtnl_message *m) {
1011 assert_return(m, -EINVAL);
1012 assert_return(m->sealed, -EINVAL);
1013 assert_return(m->n_containers > 0, -EINVAL);
1014
3dd215e0
TG
1015 free(m->rta_offset_tb[m->n_containers]);
1016 m->rta_offset_tb[m->n_containers] = NULL;
d8e538ec 1017 m->container_type_system[m->n_containers] = NULL;
3dd215e0 1018
e5c4350b
TG
1019 m->n_containers --;
1020
1021 return 0;
1022}
1023
3815f36f 1024uint32_t rtnl_message_get_serial(sd_rtnl_message *m) {
65f568bb 1025 assert(m);
9d0db178 1026 assert(m->hdr);
65f568bb
TG
1027
1028 return m->hdr->nlmsg_seq;
1029}
1030
e16bcf98 1031int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
65f568bb
TG
1032 struct nlmsgerr *err;
1033
e16bcf98 1034 assert_return(m, -EINVAL);
9d0db178 1035 assert_return(m->hdr, -EINVAL);
65f568bb
TG
1036
1037 if (m->hdr->nlmsg_type != NLMSG_ERROR)
1038 return 0;
1039
1040 err = NLMSG_DATA(m->hdr);
1041
1042 return err->error;
1043}
1044
44caa5e7
SS
1045int rtnl_message_parse(sd_rtnl_message *m,
1046 size_t **rta_offset_tb,
1047 unsigned short *rta_tb_size,
1048 int max,
1049 struct rtattr *rta,
1050 unsigned int rt_len) {
e634cd40 1051 unsigned short type;
44caa5e7
SS
1052 size_t *tb;
1053
c8a7165f 1054 tb = new0(size_t, max + 1);
44caa5e7
SS
1055 if(!tb)
1056 return -ENOMEM;
1057
c8a7165f 1058 *rta_tb_size = max + 1;
44caa5e7
SS
1059
1060 for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
1061 type = rta->rta_type;
1062
aef0768e
TG
1063 /* if the kernel is newer than the headers we used
1064 when building, we ignore out-of-range attributes
1065 */
1066 if (type > max)
e634cd40 1067 continue;
e634cd40
TG
1068
1069 if (tb[type])
1070 log_debug("rtnl: message parse - overwriting repeated attribute");
1071
1072 tb[type] = (uint8_t *) rta - (uint8_t *) m->hdr;
44caa5e7
SS
1073 }
1074
1075 *rta_offset_tb = tb;
1076
1077 return 0;
1078}
1079
65f568bb
TG
1080/* returns the number of bytes sent, or a negative error code */
1081int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
d4bbdb77
TG
1082 union {
1083 struct sockaddr sa;
1084 struct sockaddr_nl nl;
1085 } addr = {
1086 .nl.nl_family = AF_NETLINK,
1087 };
65f568bb
TG
1088 ssize_t k;
1089
9d0db178
TG
1090 assert(nl);
1091 assert(m);
1092 assert(m->hdr);
65f568bb
TG
1093
1094 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
d4bbdb77 1095 0, &addr.sa, sizeof(addr));
65f568bb
TG
1096 if (k < 0)
1097 return (errno == EAGAIN) ? 0 : -errno;
1098
1099 return k;
1100}
1101
66269b05
TG
1102static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool peek) {
1103 uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred)) +
1104 CMSG_SPACE(sizeof(struct nl_pktinfo))];
bc078e71 1105 struct msghdr msg = {
26349add 1106 .msg_iov = iov,
bc078e71
TG
1107 .msg_iovlen = 1,
1108 .msg_control = cred_buffer,
1109 .msg_controllen = sizeof(cred_buffer),
1110 };
1111 struct cmsghdr *cmsg;
66269b05 1112 uint32_t group = 0;
26349add 1113 bool auth = false;
4e996881 1114 int r;
d4bbdb77 1115
26349add
TG
1116 assert(fd >= 0);
1117 assert(iov);
bc078e71 1118
26349add 1119 r = recvmsg(fd, &msg, MSG_TRUNC | (peek ? MSG_PEEK : 0));
3dd215e0 1120 if (r < 0)
bc078e71
TG
1121 /* no data */
1122 return (errno == EAGAIN) ? 0 : -errno;
3dd215e0 1123 else if (r == 0)
bc078e71
TG
1124 /* connection was closed by the kernel */
1125 return -ECONNRESET;
3dd215e0 1126
bc078e71
TG
1127 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1128 if (cmsg->cmsg_level == SOL_SOCKET &&
1129 cmsg->cmsg_type == SCM_CREDENTIALS &&
1130 cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
1131 struct ucred *ucred = (void *)CMSG_DATA(cmsg);
1132
1133 /* from the kernel */
66269b05 1134 if (ucred->uid == 0 && ucred->pid == 0)
bc078e71 1135 auth = true;
66269b05
TG
1136 } else if (cmsg->cmsg_level == SOL_NETLINK &&
1137 cmsg->cmsg_type == NETLINK_PKTINFO &&
1138 cmsg->cmsg_len == CMSG_LEN(sizeof(struct nl_pktinfo))) {
1139 struct nl_pktinfo *pktinfo = (void *)CMSG_DATA(cmsg);
1140
1141 /* multi-cast group */
1142 group = pktinfo->group;
bc078e71
TG
1143 }
1144 }
1145
1146 if (!auth)
1147 /* not from the kernel, ignore */
1148 return 0;
1149
66269b05
TG
1150 if (group)
1151 *_group = group;
1152
26349add
TG
1153 return r;
1154}
1155
1156/* On success, the number of bytes received is returned and *ret points to the received message
1157 * which has a valid header and the correct size.
1158 * If nothing useful was received 0 is returned.
1159 * On failure, a negative error code is returned.
1160 */
1161int socket_read_message(sd_rtnl *rtnl) {
1162 _cleanup_rtnl_message_unref_ sd_rtnl_message *first = NULL;
1163 struct iovec iov = {};
66269b05 1164 uint32_t group = 0;
26349add
TG
1165 bool multi_part = false, done = false;
1166 struct nlmsghdr *new_msg;
1167 size_t len;
1168 int r;
1169 unsigned i = 0;
1170
1171 assert(rtnl);
1172 assert(rtnl->rbuffer);
1173 assert(rtnl->rbuffer_allocated >= sizeof(struct nlmsghdr));
1174
1175 /* read nothing, just get the pending message size */
66269b05 1176 r = socket_recv_message(rtnl->fd, &iov, &group, true);
26349add
TG
1177 if (r <= 0)
1178 return r;
1179 else
1180 len = (size_t)r;
1181
1182 /* make room for the pending message */
1183 if (!greedy_realloc((void **)&rtnl->rbuffer,
1184 &rtnl->rbuffer_allocated,
1185 len, sizeof(uint8_t)))
1186 return -ENOMEM;
1187
1188 iov.iov_base = rtnl->rbuffer;
1189 iov.iov_len = rtnl->rbuffer_allocated;
1190
1191 /* read the pending message */
66269b05 1192 r = socket_recv_message(rtnl->fd, &iov, &group, false);
26349add
TG
1193 if (r <= 0)
1194 return r;
1195 else
1196 len = (size_t)r;
1197
127dc4ea
TG
1198 if (len > rtnl->rbuffer_allocated)
1199 /* message did not fit in read buffer */
1200 return -EIO;
1201
4e996881
TG
1202 if (NLMSG_OK(rtnl->rbuffer, len) && rtnl->rbuffer->nlmsg_flags & NLM_F_MULTI) {
1203 multi_part = true;
1204
1205 for (i = 0; i < rtnl->rqueue_partial_size; i++) {
1206 if (rtnl_message_get_serial(rtnl->rqueue_partial[i]) ==
1207 rtnl->rbuffer->nlmsg_seq) {
1208 first = rtnl->rqueue_partial[i];
1209 break;
1210 }
1211 }
1212 }
1213
a88f77c4 1214 for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len); new_msg = NLMSG_NEXT(new_msg, len)) {
1b89cf56
TG
1215 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
1216 const NLType *nl_type;
3dd215e0 1217
8fe65c03 1218 if (!group && new_msg->nlmsg_pid != rtnl->sockaddr.nl.nl_pid)
1b89cf56
TG
1219 /* not broadcast and not for us */
1220 continue;
3dd215e0 1221
1b89cf56 1222 if (new_msg->nlmsg_type == NLMSG_NOOP)
4e996881 1223 /* silently drop noop messages */
1b89cf56 1224 continue;
bdd13f6b 1225
4e996881
TG
1226 if (new_msg->nlmsg_type == NLMSG_DONE) {
1227 /* finished reading multi-part message */
1228 done = true;
1403f45a 1229 break;
4e996881 1230 }
1403f45a 1231
1b89cf56
TG
1232 /* check that we support this message type */
1233 r = type_system_get_type(NULL, &nl_type, new_msg->nlmsg_type);
1234 if (r < 0) {
1235 if (r == -ENOTSUP)
1236 log_debug("sd-rtnl: ignored message with unknown type: %u",
1237 new_msg->nlmsg_type);
d8e538ec 1238
1b89cf56
TG
1239 continue;
1240 }
bdd13f6b 1241
1b89cf56
TG
1242 /* check that the size matches the message type */
1243 if (new_msg->nlmsg_len < NLMSG_LENGTH(nl_type->size))
1244 continue;
65f568bb 1245
1b89cf56
TG
1246 r = message_new_empty(rtnl, &m);
1247 if (r < 0)
1248 return r;
1249
1250 m->hdr = memdup(new_msg, new_msg->nlmsg_len);
1251 if (!m->hdr)
1252 return -ENOMEM;
1253
1254 /* seal and parse the top-level message */
1255 r = sd_rtnl_message_rewind(m);
1256 if (r < 0)
1257 return r;
1258
4e996881
TG
1259 /* push the message onto the multi-part message stack */
1260 if (first)
1261 m->next = first;
1262 first = m;
1b89cf56 1263 m = NULL;
4e996881 1264 }
1403f45a 1265
4e996881
TG
1266 if (len)
1267 log_debug("sd-rtnl: discarding %zu bytes of incoming message", len);
1b89cf56 1268
4e996881
TG
1269 if (!first)
1270 return 0;
65f568bb 1271
4e996881
TG
1272 if (!multi_part || done) {
1273 /* we got a complete message, push it on the read queue */
24a02673
TG
1274 r = rtnl_rqueue_make_room(rtnl);
1275 if (r < 0)
1276 return r;
1277
d4ef4f46
TG
1278 rtnl->rqueue[rtnl->rqueue_size ++] = first;
1279 first = NULL;
1280
1281 if (multi_part && (i < rtnl->rqueue_partial_size)) {
4e996881
TG
1282 /* remove the message form the partial read queue */
1283 memmove(rtnl->rqueue_partial + i,rtnl->rqueue_partial + i + 1,
1284 sizeof(sd_rtnl_message*) * (rtnl->rqueue_partial_size - i - 1));
1285 rtnl->rqueue_partial_size --;
1286 }
1287
4e996881
TG
1288 return 1;
1289 } else {
1290 /* we only got a partial multi-part message, push it on the
1291 partial read queue */
1292 if (i < rtnl->rqueue_partial_size) {
1293 rtnl->rqueue_partial[i] = first;
1294 } else {
1295 r = rtnl_rqueue_partial_make_room(rtnl);
1296 if (r < 0)
1297 return r;
1298
1299 rtnl->rqueue_partial[rtnl->rqueue_partial_size ++] = first;
1300 }
1301 first = NULL;
1403f45a 1302
4e996881
TG
1303 return 0;
1304 }
65f568bb 1305}
0fc7531b
TG
1306
1307int sd_rtnl_message_rewind(sd_rtnl_message *m) {
d8e538ec 1308 const NLType *type;
3dd215e0
TG
1309 unsigned i;
1310 int r;
0fc7531b
TG
1311
1312 assert_return(m, -EINVAL);
0fc7531b 1313
3dd215e0
TG
1314 /* don't allow appending to message once parsed */
1315 if (!m->sealed)
1316 rtnl_message_seal(m);
1317
1318 for (i = 1; i <= m->n_containers; i++) {
1319 free(m->rta_offset_tb[i]);
1320 m->rta_offset_tb[i] = NULL;
1321 m->rta_tb_size[i] = 0;
d8e538ec 1322 m->container_type_system[i] = NULL;
3dd215e0
TG
1323 }
1324
1325 m->n_containers = 0;
1326
1327 if (m->rta_offset_tb[0]) {
1328 /* top-level attributes have already been parsed */
1329 return 0;
1330 }
1331
d8e538ec
TG
1332 assert(m->hdr);
1333
1334 r = type_system_get_type(NULL, &type, m->hdr->nlmsg_type);
1335 if (r < 0)
1336 return r;
1337
1338 if (type->type == NLA_NESTED) {
1339 const NLTypeSystem *type_system = type->type_system;
1340
1341 assert(type_system);
1342
1343 m->container_type_system[0] = type_system;
1344
1345 r = rtnl_message_parse(m,
1346 &m->rta_offset_tb[m->n_containers],
1347 &m->rta_tb_size[m->n_containers],
1348 type_system->max,
0834ff93
TG
1349 (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) +
1350 NLMSG_ALIGN(type->size)),
d8e538ec
TG
1351 NLMSG_PAYLOAD(m->hdr, type->size));
1352 if (r < 0)
1353 return r;
0fc7531b
TG
1354 }
1355
1356 return 0;
1357}
3dd215e0
TG
1358
1359void rtnl_message_seal(sd_rtnl_message *m) {
1360 assert(m);
1361 assert(!m->sealed);
1362
1363 m->sealed = true;
1364}
1403f45a
TG
1365
1366sd_rtnl_message *sd_rtnl_message_next(sd_rtnl_message *m) {
1367 assert_return(m, NULL);
1368
1369 return m->next;
1370}