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