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