]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-rtnl/rtnl-message.c
sd-rtnl: message - allow checking for attributes without reading out their contents
[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
73ae2b7d
TG
833 assert_return(m, -EINVAL);
834
d8e538ec
TG
835 r = message_attribute_has_type(m, type, NLA_STRING);
836 if (r < 0)
837 return r;
44caa5e7
SS
838
839 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 840 if (r < 0)
44caa5e7 841 return r;
f66eeb6b
TG
842 else if (strnlen(attr_data, r) >= (size_t) r)
843 return -EIO;
44caa5e7 844
73ae2b7d
TG
845 if (data)
846 *data = (const char *) attr_data;
44caa5e7
SS
847
848 return 0;
849}
850
851int sd_rtnl_message_read_u8(sd_rtnl_message *m, unsigned short type, uint8_t *data) {
852 int r;
853 void *attr_data;
854
73ae2b7d
TG
855 assert_return(m, -EINVAL);
856
d8e538ec
TG
857 r = message_attribute_has_type(m, type, NLA_U8);
858 if (r < 0)
859 return r;
44caa5e7
SS
860
861 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 862 if (r < 0)
44caa5e7 863 return r;
f66eeb6b
TG
864 else if ((size_t) r < sizeof(uint8_t))
865 return -EIO;
44caa5e7 866
73ae2b7d
TG
867 if (data)
868 *data = *(uint8_t *) attr_data;
44caa5e7
SS
869
870 return 0;
871}
872
873int sd_rtnl_message_read_u16(sd_rtnl_message *m, unsigned short type, uint16_t *data) {
874 int r;
875 void *attr_data;
876
73ae2b7d
TG
877 assert_return(m, -EINVAL);
878
d8e538ec
TG
879 r = message_attribute_has_type(m, type, NLA_U16);
880 if (r < 0)
881 return r;
44caa5e7
SS
882
883 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 884 if (r < 0)
44caa5e7 885 return r;
f66eeb6b
TG
886 else if ((size_t) r < sizeof(uint16_t))
887 return -EIO;
44caa5e7 888
73ae2b7d
TG
889 if (data)
890 *data = *(uint16_t *) attr_data;
44caa5e7
SS
891
892 return 0;
893}
894
895int sd_rtnl_message_read_u32(sd_rtnl_message *m, unsigned short type, uint32_t *data) {
896 int r;
897 void *attr_data;
898
73ae2b7d
TG
899 assert_return(m, -EINVAL);
900
d8e538ec
TG
901 r = message_attribute_has_type(m, type, NLA_U32);
902 if (r < 0)
903 return r;
44caa5e7
SS
904
905 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 906 if (r < 0)
44caa5e7 907 return r;
f66eeb6b
TG
908 else if ((size_t)r < sizeof(uint32_t))
909 return -EIO;
44caa5e7 910
73ae2b7d
TG
911 if (data)
912 *data = *(uint32_t *) attr_data;
44caa5e7
SS
913
914 return 0;
915}
916
4e9e7f18
SS
917int sd_rtnl_message_read_ether_addr(sd_rtnl_message *m, unsigned short type, struct ether_addr *data) {
918 int r;
919 void *attr_data;
920
73ae2b7d
TG
921 assert_return(m, -EINVAL);
922
d8e538ec
TG
923 r = message_attribute_has_type(m, type, NLA_ETHER_ADDR);
924 if (r < 0)
925 return r;
4e9e7f18
SS
926
927 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 928 if (r < 0)
4e9e7f18 929 return r;
f66eeb6b
TG
930 else if ((size_t)r < sizeof(struct ether_addr))
931 return -EIO;
4e9e7f18 932
73ae2b7d
TG
933 if (data)
934 memcpy(data, attr_data, sizeof(struct ether_addr));
4e9e7f18
SS
935
936 return 0;
937}
938
aba496a5
UTL
939int sd_rtnl_message_read_cache_info(sd_rtnl_message *m, unsigned short type, struct ifa_cacheinfo *info) {
940 int r;
941 void *attr_data;
942
73ae2b7d
TG
943 assert_return(m, -EINVAL);
944
aba496a5
UTL
945 r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
946 if (r < 0)
947 return r;
948
949 r = rtnl_message_read_internal(m, type, &attr_data);
950 if (r < 0)
951 return r;
952 else if ((size_t)r < sizeof(struct ifa_cacheinfo))
953 return -EIO;
954
73ae2b7d
TG
955 if (info)
956 memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
aba496a5
UTL
957
958 return 0;
959}
960
4e9e7f18
SS
961int sd_rtnl_message_read_in_addr(sd_rtnl_message *m, unsigned short type, struct in_addr *data) {
962 int r;
963 void *attr_data;
964
73ae2b7d
TG
965 assert_return(m, -EINVAL);
966
d8e538ec
TG
967 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
968 if (r < 0)
969 return r;
4e9e7f18
SS
970
971 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 972 if (r < 0)
4e9e7f18 973 return r;
f66eeb6b
TG
974 else if ((size_t)r < sizeof(struct in_addr))
975 return -EIO;
4e9e7f18 976
73ae2b7d
TG
977 if (data)
978 memcpy(data, attr_data, sizeof(struct in_addr));
4e9e7f18
SS
979
980 return 0;
981}
982
983int sd_rtnl_message_read_in6_addr(sd_rtnl_message *m, unsigned short type, struct in6_addr *data) {
984 int r;
985 void *attr_data;
986
73ae2b7d
TG
987 assert_return(m, -EINVAL);
988
d8e538ec
TG
989 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
990 if (r < 0)
991 return r;
4e9e7f18
SS
992
993 r = rtnl_message_read_internal(m, type, &attr_data);
3dd215e0 994 if (r < 0)
4e9e7f18 995 return r;
3dd215e0
TG
996 else if ((size_t)r < sizeof(struct in6_addr))
997 return -EIO;
4e9e7f18 998
73ae2b7d
TG
999 if (data)
1000 memcpy(data, attr_data, sizeof(struct in6_addr));
4e9e7f18
SS
1001
1002 return 0;
1003}
1004
3dd215e0 1005int sd_rtnl_message_enter_container(sd_rtnl_message *m, unsigned short type) {
d8e538ec
TG
1006 const NLType *nl_type;
1007 const NLTypeSystem *type_system;
3dd215e0 1008 void *container;
d8e538ec
TG
1009 size_t size;
1010 int r;
3dd215e0
TG
1011
1012 assert_return(m, -EINVAL);
1013 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
1014
d8e538ec
TG
1015 r = type_system_get_type(m->container_type_system[m->n_containers],
1016 &nl_type,
1017 type);
3dd215e0
TG
1018 if (r < 0)
1019 return r;
3dd215e0 1020
d8e538ec
TG
1021 if (nl_type->type == NLA_NESTED) {
1022 r = type_system_get_type_system(m->container_type_system[m->n_containers],
1023 &type_system,
1024 type);
1025 if (r < 0)
1026 return r;
1027 } else if (nl_type->type == NLA_UNION) {
1028 const NLTypeSystemUnion *type_system_union;
ca4e095a 1029 const char *key;
d8e538ec
TG
1030
1031 r = type_system_get_type_system_union(m->container_type_system[m->n_containers],
1032 &type_system_union,
1033 type);
1034 if (r < 0)
1035 return r;
1036
1037 r = sd_rtnl_message_read_string(m, type_system_union->match, &key);
1038 if (r < 0)
1039 return r;
1040
1041 r = type_system_union_get_type_system(type_system_union,
1042 &type_system,
1043 key);
1044 if (r < 0)
1045 return r;
1046 } else
1047 return -EINVAL;
1048
1049 r = rtnl_message_read_internal(m, type, &container);
3dd215e0
TG
1050 if (r < 0)
1051 return r;
d8e538ec
TG
1052 else
1053 size = (size_t)r;
3dd215e0 1054
d8e538ec 1055 m->n_containers ++;
3dd215e0
TG
1056
1057 r = rtnl_message_parse(m,
d8e538ec
TG
1058 &m->rta_offset_tb[m->n_containers],
1059 &m->rta_tb_size[m->n_containers],
1060 type_system->max,
3dd215e0 1061 container,
d8e538ec
TG
1062 size);
1063 if (r < 0) {
1064 m->n_containers --;
3dd215e0 1065 return r;
d8e538ec 1066 }
3dd215e0 1067
d8e538ec 1068 m->container_type_system[m->n_containers] = type_system;
3dd215e0
TG
1069
1070 return 0;
1071}
1072
e5c4350b
TG
1073int sd_rtnl_message_exit_container(sd_rtnl_message *m) {
1074 assert_return(m, -EINVAL);
1075 assert_return(m->sealed, -EINVAL);
1076 assert_return(m->n_containers > 0, -EINVAL);
1077
3dd215e0
TG
1078 free(m->rta_offset_tb[m->n_containers]);
1079 m->rta_offset_tb[m->n_containers] = NULL;
d8e538ec 1080 m->container_type_system[m->n_containers] = NULL;
3dd215e0 1081
e5c4350b
TG
1082 m->n_containers --;
1083
1084 return 0;
1085}
1086
3815f36f 1087uint32_t rtnl_message_get_serial(sd_rtnl_message *m) {
65f568bb 1088 assert(m);
9d0db178 1089 assert(m->hdr);
65f568bb
TG
1090
1091 return m->hdr->nlmsg_seq;
1092}
1093
e16bcf98 1094int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
65f568bb
TG
1095 struct nlmsgerr *err;
1096
e16bcf98 1097 assert_return(m, -EINVAL);
9d0db178 1098 assert_return(m->hdr, -EINVAL);
65f568bb
TG
1099
1100 if (m->hdr->nlmsg_type != NLMSG_ERROR)
1101 return 0;
1102
1103 err = NLMSG_DATA(m->hdr);
1104
1105 return err->error;
1106}
1107
44caa5e7
SS
1108int rtnl_message_parse(sd_rtnl_message *m,
1109 size_t **rta_offset_tb,
1110 unsigned short *rta_tb_size,
1111 int max,
1112 struct rtattr *rta,
1113 unsigned int rt_len) {
e634cd40 1114 unsigned short type;
44caa5e7
SS
1115 size_t *tb;
1116
c8a7165f 1117 tb = new0(size_t, max + 1);
44caa5e7
SS
1118 if(!tb)
1119 return -ENOMEM;
1120
c8a7165f 1121 *rta_tb_size = max + 1;
44caa5e7
SS
1122
1123 for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
0a2478a9 1124 type = RTA_TYPE(rta);
44caa5e7 1125
aef0768e
TG
1126 /* if the kernel is newer than the headers we used
1127 when building, we ignore out-of-range attributes
1128 */
1129 if (type > max)
e634cd40 1130 continue;
e634cd40
TG
1131
1132 if (tb[type])
1133 log_debug("rtnl: message parse - overwriting repeated attribute");
1134
1135 tb[type] = (uint8_t *) rta - (uint8_t *) m->hdr;
44caa5e7
SS
1136 }
1137
1138 *rta_offset_tb = tb;
1139
1140 return 0;
1141}
1142
65f568bb
TG
1143/* returns the number of bytes sent, or a negative error code */
1144int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
d4bbdb77
TG
1145 union {
1146 struct sockaddr sa;
1147 struct sockaddr_nl nl;
1148 } addr = {
1149 .nl.nl_family = AF_NETLINK,
1150 };
65f568bb
TG
1151 ssize_t k;
1152
9d0db178
TG
1153 assert(nl);
1154 assert(m);
1155 assert(m->hdr);
65f568bb
TG
1156
1157 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
d4bbdb77 1158 0, &addr.sa, sizeof(addr));
65f568bb
TG
1159 if (k < 0)
1160 return (errno == EAGAIN) ? 0 : -errno;
1161
1162 return k;
1163}
1164
66269b05
TG
1165static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool peek) {
1166 uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred)) +
1167 CMSG_SPACE(sizeof(struct nl_pktinfo))];
bc078e71 1168 struct msghdr msg = {
26349add 1169 .msg_iov = iov,
bc078e71
TG
1170 .msg_iovlen = 1,
1171 .msg_control = cred_buffer,
1172 .msg_controllen = sizeof(cred_buffer),
1173 };
1174 struct cmsghdr *cmsg;
66269b05 1175 uint32_t group = 0;
26349add 1176 bool auth = false;
4e996881 1177 int r;
d4bbdb77 1178
26349add
TG
1179 assert(fd >= 0);
1180 assert(iov);
bc078e71 1181
26349add 1182 r = recvmsg(fd, &msg, MSG_TRUNC | (peek ? MSG_PEEK : 0));
5968b1c3 1183 if (r < 0) {
bc078e71 1184 /* no data */
5968b1c3
TG
1185 if (errno == ENOBUFS)
1186 log_debug("rtnl: kernel receive buffer overrun");
1187
bc078e71 1188 return (errno == EAGAIN) ? 0 : -errno;
5968b1c3 1189 } else if (r == 0)
bc078e71
TG
1190 /* connection was closed by the kernel */
1191 return -ECONNRESET;
3dd215e0 1192
bc078e71
TG
1193 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
1194 if (cmsg->cmsg_level == SOL_SOCKET &&
1195 cmsg->cmsg_type == SCM_CREDENTIALS &&
1196 cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
1197 struct ucred *ucred = (void *)CMSG_DATA(cmsg);
1198
1199 /* from the kernel */
66269b05 1200 if (ucred->uid == 0 && ucred->pid == 0)
bc078e71 1201 auth = true;
66269b05
TG
1202 } else if (cmsg->cmsg_level == SOL_NETLINK &&
1203 cmsg->cmsg_type == NETLINK_PKTINFO &&
1204 cmsg->cmsg_len == CMSG_LEN(sizeof(struct nl_pktinfo))) {
1205 struct nl_pktinfo *pktinfo = (void *)CMSG_DATA(cmsg);
1206
1207 /* multi-cast group */
1208 group = pktinfo->group;
bc078e71
TG
1209 }
1210 }
1211
1212 if (!auth)
1213 /* not from the kernel, ignore */
1214 return 0;
1215
66269b05
TG
1216 if (group)
1217 *_group = group;
1218
26349add
TG
1219 return r;
1220}
1221
1222/* On success, the number of bytes received is returned and *ret points to the received message
1223 * which has a valid header and the correct size.
1224 * If nothing useful was received 0 is returned.
1225 * On failure, a negative error code is returned.
1226 */
1227int socket_read_message(sd_rtnl *rtnl) {
1228 _cleanup_rtnl_message_unref_ sd_rtnl_message *first = NULL;
1229 struct iovec iov = {};
66269b05 1230 uint32_t group = 0;
26349add
TG
1231 bool multi_part = false, done = false;
1232 struct nlmsghdr *new_msg;
1233 size_t len;
1234 int r;
1235 unsigned i = 0;
1236
1237 assert(rtnl);
1238 assert(rtnl->rbuffer);
1239 assert(rtnl->rbuffer_allocated >= sizeof(struct nlmsghdr));
1240
1241 /* read nothing, just get the pending message size */
66269b05 1242 r = socket_recv_message(rtnl->fd, &iov, &group, true);
26349add
TG
1243 if (r <= 0)
1244 return r;
1245 else
1246 len = (size_t)r;
1247
1248 /* make room for the pending message */
1249 if (!greedy_realloc((void **)&rtnl->rbuffer,
1250 &rtnl->rbuffer_allocated,
1251 len, sizeof(uint8_t)))
1252 return -ENOMEM;
1253
1254 iov.iov_base = rtnl->rbuffer;
1255 iov.iov_len = rtnl->rbuffer_allocated;
1256
1257 /* read the pending message */
66269b05 1258 r = socket_recv_message(rtnl->fd, &iov, &group, false);
26349add
TG
1259 if (r <= 0)
1260 return r;
1261 else
1262 len = (size_t)r;
1263
127dc4ea
TG
1264 if (len > rtnl->rbuffer_allocated)
1265 /* message did not fit in read buffer */
1266 return -EIO;
1267
4e996881
TG
1268 if (NLMSG_OK(rtnl->rbuffer, len) && rtnl->rbuffer->nlmsg_flags & NLM_F_MULTI) {
1269 multi_part = true;
1270
1271 for (i = 0; i < rtnl->rqueue_partial_size; i++) {
1272 if (rtnl_message_get_serial(rtnl->rqueue_partial[i]) ==
1273 rtnl->rbuffer->nlmsg_seq) {
1274 first = rtnl->rqueue_partial[i];
1275 break;
1276 }
1277 }
1278 }
1279
a88f77c4 1280 for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len); new_msg = NLMSG_NEXT(new_msg, len)) {
1b89cf56
TG
1281 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
1282 const NLType *nl_type;
3dd215e0 1283
8fe65c03 1284 if (!group && new_msg->nlmsg_pid != rtnl->sockaddr.nl.nl_pid)
1b89cf56
TG
1285 /* not broadcast and not for us */
1286 continue;
3dd215e0 1287
1b89cf56 1288 if (new_msg->nlmsg_type == NLMSG_NOOP)
4e996881 1289 /* silently drop noop messages */
1b89cf56 1290 continue;
bdd13f6b 1291
4e996881
TG
1292 if (new_msg->nlmsg_type == NLMSG_DONE) {
1293 /* finished reading multi-part message */
1294 done = true;
1403f45a 1295 break;
4e996881 1296 }
1403f45a 1297
1b89cf56
TG
1298 /* check that we support this message type */
1299 r = type_system_get_type(NULL, &nl_type, new_msg->nlmsg_type);
1300 if (r < 0) {
1301 if (r == -ENOTSUP)
1302 log_debug("sd-rtnl: ignored message with unknown type: %u",
1303 new_msg->nlmsg_type);
d8e538ec 1304
1b89cf56
TG
1305 continue;
1306 }
bdd13f6b 1307
1b89cf56
TG
1308 /* check that the size matches the message type */
1309 if (new_msg->nlmsg_len < NLMSG_LENGTH(nl_type->size))
1310 continue;
65f568bb 1311
1b89cf56
TG
1312 r = message_new_empty(rtnl, &m);
1313 if (r < 0)
1314 return r;
1315
1316 m->hdr = memdup(new_msg, new_msg->nlmsg_len);
1317 if (!m->hdr)
1318 return -ENOMEM;
1319
1320 /* seal and parse the top-level message */
1321 r = sd_rtnl_message_rewind(m);
1322 if (r < 0)
1323 return r;
1324
4e996881
TG
1325 /* push the message onto the multi-part message stack */
1326 if (first)
1327 m->next = first;
1328 first = m;
1b89cf56 1329 m = NULL;
4e996881 1330 }
1403f45a 1331
4e996881
TG
1332 if (len)
1333 log_debug("sd-rtnl: discarding %zu bytes of incoming message", len);
1b89cf56 1334
4e996881
TG
1335 if (!first)
1336 return 0;
65f568bb 1337
4e996881
TG
1338 if (!multi_part || done) {
1339 /* we got a complete message, push it on the read queue */
24a02673
TG
1340 r = rtnl_rqueue_make_room(rtnl);
1341 if (r < 0)
1342 return r;
1343
d4ef4f46
TG
1344 rtnl->rqueue[rtnl->rqueue_size ++] = first;
1345 first = NULL;
1346
1347 if (multi_part && (i < rtnl->rqueue_partial_size)) {
4e996881
TG
1348 /* remove the message form the partial read queue */
1349 memmove(rtnl->rqueue_partial + i,rtnl->rqueue_partial + i + 1,
1350 sizeof(sd_rtnl_message*) * (rtnl->rqueue_partial_size - i - 1));
1351 rtnl->rqueue_partial_size --;
1352 }
1353
4e996881
TG
1354 return 1;
1355 } else {
1356 /* we only got a partial multi-part message, push it on the
1357 partial read queue */
1358 if (i < rtnl->rqueue_partial_size) {
1359 rtnl->rqueue_partial[i] = first;
1360 } else {
1361 r = rtnl_rqueue_partial_make_room(rtnl);
1362 if (r < 0)
1363 return r;
1364
1365 rtnl->rqueue_partial[rtnl->rqueue_partial_size ++] = first;
1366 }
1367 first = NULL;
1403f45a 1368
4e996881
TG
1369 return 0;
1370 }
65f568bb 1371}
0fc7531b
TG
1372
1373int sd_rtnl_message_rewind(sd_rtnl_message *m) {
d8e538ec 1374 const NLType *type;
3dd215e0
TG
1375 unsigned i;
1376 int r;
0fc7531b
TG
1377
1378 assert_return(m, -EINVAL);
0fc7531b 1379
3dd215e0
TG
1380 /* don't allow appending to message once parsed */
1381 if (!m->sealed)
1382 rtnl_message_seal(m);
1383
1384 for (i = 1; i <= m->n_containers; i++) {
1385 free(m->rta_offset_tb[i]);
1386 m->rta_offset_tb[i] = NULL;
1387 m->rta_tb_size[i] = 0;
d8e538ec 1388 m->container_type_system[i] = NULL;
3dd215e0
TG
1389 }
1390
1391 m->n_containers = 0;
1392
1393 if (m->rta_offset_tb[0]) {
1394 /* top-level attributes have already been parsed */
1395 return 0;
1396 }
1397
d8e538ec
TG
1398 assert(m->hdr);
1399
1400 r = type_system_get_type(NULL, &type, m->hdr->nlmsg_type);
1401 if (r < 0)
1402 return r;
1403
1404 if (type->type == NLA_NESTED) {
1405 const NLTypeSystem *type_system = type->type_system;
1406
1407 assert(type_system);
1408
1409 m->container_type_system[0] = type_system;
1410
1411 r = rtnl_message_parse(m,
1412 &m->rta_offset_tb[m->n_containers],
1413 &m->rta_tb_size[m->n_containers],
1414 type_system->max,
0834ff93
TG
1415 (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) +
1416 NLMSG_ALIGN(type->size)),
d8e538ec
TG
1417 NLMSG_PAYLOAD(m->hdr, type->size));
1418 if (r < 0)
1419 return r;
0fc7531b
TG
1420 }
1421
1422 return 0;
1423}
3dd215e0
TG
1424
1425void rtnl_message_seal(sd_rtnl_message *m) {
1426 assert(m);
1427 assert(!m->sealed);
1428
1429 m->sealed = true;
1430}
1403f45a
TG
1431
1432sd_rtnl_message *sd_rtnl_message_next(sd_rtnl_message *m) {
1433 assert_return(m, NULL);
1434
1435 return m->next;
1436}