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