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