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