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