]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-rtnl/rtnl-message.c
sd-rtnl: use GREEDY_REALLOC for message queues
[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>
d8e538ec 26#include <linux/netlink.h>
31a4e153 27#include <linux/veth.h>
9a6704a8
SS
28#include <linux/if.h>
29#include <linux/ip.h>
30#include <linux/if_tunnel.h>
3dd215e0 31#include <linux/if_bridge.h>
65f568bb
TG
32
33#include "util.h"
34#include "refcnt.h"
d5eff740 35#include "missing.h"
65f568bb
TG
36
37#include "sd-rtnl.h"
3815f36f 38#include "rtnl-util.h"
65f568bb 39#include "rtnl-internal.h"
d8e538ec 40#include "rtnl-types.h"
65f568bb 41
31a4e153 42#define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL)
e5c4350b 43#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
4ebe732c 44
d8e538ec 45static int message_new_empty(sd_rtnl *rtnl, sd_rtnl_message **ret, size_t initial_size) {
65f568bb
TG
46 sd_rtnl_message *m;
47
48 assert_return(ret, -EINVAL);
dabfa9d1 49 assert_return(initial_size >= sizeof(struct nlmsghdr), -EINVAL);
65f568bb 50
8c578303
TG
51 /* Note that 'rtnl' is curretly unused, if we start using it internally
52 we must take care to avoid problems due to mutual references between
53 busses and their queued messages. See sd-bus.
54 */
55
65f568bb
TG
56 m = new0(sd_rtnl_message, 1);
57 if (!m)
58 return -ENOMEM;
59
dc7d8997 60 m->hdr = malloc0(initial_size);
65f568bb
TG
61 if (!m->hdr) {
62 free(m);
63 return -ENOMEM;
64 }
65
66 m->n_ref = REFCNT_INIT;
67
68 m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
69 m->sealed = false;
70
71 *ret = m;
72
73 return 0;
74}
75
d8e538ec
TG
76int message_new(sd_rtnl *rtnl, sd_rtnl_message **ret, uint16_t type) {
77 const NLType *nl_type;
78 size_t size;
79 int r;
80
81 r = type_system_get_type(NULL, &nl_type, type);
82 if (r < 0)
83 return r;
84
85 assert(nl_type->type == NLA_NESTED);
86
87 size = NLMSG_SPACE(nl_type->size);
88
89 r = message_new_empty(rtnl, ret, size);
90 if (r < 0)
91 return r;
92
93 (*ret)->container_type_system[0] = nl_type->type_system;
94 (*ret)->hdr->nlmsg_len = size;
95 (*ret)->hdr->nlmsg_type = type;
96
97 return 0;
98}
99
1f01fb4f
TG
100int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
101 struct rtmsg *rtm;
102
5a723174
TG
103 assert_return(m, -EINVAL);
104 assert_return(m->hdr, -EINVAL);
3815f36f 105 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
5a723174 106
1f01fb4f
TG
107 rtm = NLMSG_DATA(m->hdr);
108
5a723174
TG
109 if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
110 (rtm->rtm_family == AF_INET6 && prefixlen > 128))
111 return -ERANGE;
112
1f01fb4f
TG
113 rtm->rtm_dst_len = prefixlen;
114
5c1d3fc9
UTL
115 return 0;
116}
117
118int sd_rtnl_message_route_set_scope(sd_rtnl_message *m, unsigned char scope) {
119 struct rtmsg *rtm;
120
121 assert_return(m, -EINVAL);
122 assert_return(m->hdr, -EINVAL);
123 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
124
125 rtm = NLMSG_DATA(m->hdr);
126
127 rtm->rtm_scope = scope;
128
1f01fb4f
TG
129 return 0;
130}
131
151b9b96
LP
132int sd_rtnl_message_new_route(sd_rtnl *rtnl, sd_rtnl_message **ret,
133 uint16_t nlmsg_type, unsigned char rtm_family) {
03d7e632
TG
134 struct rtmsg *rtm;
135 int r;
136
3815f36f 137 assert_return(rtnl_message_type_is_route(nlmsg_type), -EINVAL);
1f01fb4f 138 assert_return(rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
03d7e632
TG
139 assert_return(ret, -EINVAL);
140
d8e538ec 141 r = message_new(rtnl, ret, nlmsg_type);
03d7e632
TG
142 if (r < 0)
143 return r;
144
03d7e632
TG
145 if (nlmsg_type == RTM_NEWROUTE)
146 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
147
148 rtm = NLMSG_DATA((*ret)->hdr);
149
150 rtm->rtm_family = rtm_family;
1f01fb4f
TG
151 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
152 rtm->rtm_type = RTN_UNICAST;
153 rtm->rtm_table = RT_TABLE_MAIN;
154 rtm->rtm_protocol = RTPROT_BOOT;
03d7e632
TG
155
156 return 0;
157}
158
5d4795f3 159int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags, unsigned change) {
fc25d7f8
TG
160 struct ifinfomsg *ifi;
161
5a723174
TG
162 assert_return(m, -EINVAL);
163 assert_return(m->hdr, -EINVAL);
3815f36f 164 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
a7b74db6 165 assert_return(change, -EINVAL);
5a723174 166
fc25d7f8
TG
167 ifi = NLMSG_DATA(m->hdr);
168
169 ifi->ifi_flags = flags;
a7b74db6 170 ifi->ifi_change = change;
fc25d7f8
TG
171
172 return 0;
173}
174
175int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) {
176 struct ifinfomsg *ifi;
177
5a723174
TG
178 assert_return(m, -EINVAL);
179 assert_return(m->hdr, -EINVAL);
3815f36f 180 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
5a723174 181
fc25d7f8
TG
182 ifi = NLMSG_DATA(m->hdr);
183
184 ifi->ifi_type = type;
185
186 return 0;
187}
188
151b9b96
LP
189int sd_rtnl_message_new_link(sd_rtnl *rtnl, sd_rtnl_message **ret,
190 uint16_t nlmsg_type, int index) {
65f568bb
TG
191 struct ifinfomsg *ifi;
192 int r;
193
3815f36f 194 assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL);
6a8402d9 195 assert_return(nlmsg_type != RTM_DELLINK || index > 0, -EINVAL);
65f568bb
TG
196 assert_return(ret, -EINVAL);
197
d8e538ec 198 r = message_new(rtnl, ret, nlmsg_type);
65f568bb
TG
199 if (r < 0)
200 return r;
201
33125ac5 202 if (nlmsg_type == RTM_NEWLINK)
6a8402d9 203 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
65f568bb 204
dabfa9d1 205 ifi = NLMSG_DATA((*ret)->hdr);
65f568bb
TG
206
207 ifi->ifi_family = AF_UNSPEC;
208 ifi->ifi_index = index;
65f568bb
TG
209
210 return 0;
211}
212
5a723174
TG
213int sd_rtnl_message_addr_set_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
214 struct ifaddrmsg *ifa;
215
216 assert_return(m, -EINVAL);
217 assert_return(m->hdr, -EINVAL);
3815f36f 218 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
5a723174
TG
219
220 ifa = NLMSG_DATA(m->hdr);
221
222 if ((ifa->ifa_family == AF_INET && prefixlen > 32) ||
223 (ifa->ifa_family == AF_INET6 && prefixlen > 128))
224 return -ERANGE;
225
226 ifa->ifa_prefixlen = prefixlen;
227
228 return 0;
229}
230
231int sd_rtnl_message_addr_set_flags(sd_rtnl_message *m, unsigned char flags) {
232 struct ifaddrmsg *ifa;
233
234 assert_return(m, -EINVAL);
235 assert_return(m->hdr, -EINVAL);
3815f36f 236 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
5a723174
TG
237
238 ifa = NLMSG_DATA(m->hdr);
239
240 ifa->ifa_flags = flags;
241
242 return 0;
243}
244
245int sd_rtnl_message_addr_set_scope(sd_rtnl_message *m, unsigned char scope) {
246 struct ifaddrmsg *ifa;
247
248 assert_return(m, -EINVAL);
249 assert_return(m->hdr, -EINVAL);
3815f36f 250 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
5a723174
TG
251
252 ifa = NLMSG_DATA(m->hdr);
253
254 ifa->ifa_scope = scope;
255
256 return 0;
257}
258
151b9b96
LP
259int sd_rtnl_message_new_addr(sd_rtnl *rtnl, sd_rtnl_message **ret,
260 uint16_t nlmsg_type, int index,
261 unsigned char family) {
65f568bb
TG
262 struct ifaddrmsg *ifa;
263 int r;
264
3815f36f 265 assert_return(rtnl_message_type_is_addr(nlmsg_type), -EINVAL);
65f568bb 266 assert_return(index > 0, -EINVAL);
5a723174 267 assert_return(family == AF_INET || family == AF_INET6, -EINVAL);
65f568bb
TG
268 assert_return(ret, -EINVAL);
269
d8e538ec 270 r = message_new(rtnl, ret, nlmsg_type);
65f568bb
TG
271 if (r < 0)
272 return r;
273
818dc5e7
TG
274 if (nlmsg_type == RTM_GETADDR && family == AF_INET)
275 (*ret)->hdr->nlmsg_flags |= NLM_F_DUMP;
65f568bb 276
dabfa9d1 277 ifa = NLMSG_DATA((*ret)->hdr);
65f568bb 278
65f568bb 279 ifa->ifa_index = index;
5a723174
TG
280 ifa->ifa_family = family;
281 if (family == AF_INET)
282 ifa->ifa_prefixlen = 32;
283 else if (family == AF_INET6)
284 ifa->ifa_prefixlen = 128;
65f568bb
TG
285
286 return 0;
287}
288
aba496a5
UTL
289int sd_rtnl_message_new_addr_update(sd_rtnl *rtnl, sd_rtnl_message **ret,
290 int index, unsigned char family) {
291 int r;
292
293 r = sd_rtnl_message_new_addr(rtnl, ret, RTM_NEWADDR, index, family);
294 if (r < 0)
295 return r;
296
297 (*ret)->hdr->nlmsg_flags |= NLM_F_REPLACE;
298
299 return 0;
300}
301
65f568bb
TG
302sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
303 if (m)
304 assert_se(REFCNT_INC(m->n_ref) >= 2);
305
306 return m;
307}
308
309sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
310 if (m && REFCNT_DEC(m->n_ref) <= 0) {
3dd215e0
TG
311 unsigned i;
312
65f568bb 313 free(m->hdr);
3dd215e0 314
9f5bbfe3 315 for (i = 0; i <= m->n_containers; i++)
3dd215e0
TG
316 free(m->rta_offset_tb[i]);
317
65f568bb
TG
318 free(m);
319 }
320
321 return NULL;
322}
323
dabfa9d1 324int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
65f568bb
TG
325 assert_return(m, -EINVAL);
326 assert_return(type, -EINVAL);
327
328 *type = m->hdr->nlmsg_type;
329
330 return 0;
331}
332
1f0db3ed
TG
333int sd_rtnl_message_is_broadcast(sd_rtnl_message *m) {
334 assert_return(m, -EINVAL);
335
336 return !m->hdr->nlmsg_pid;
337}
338
33125ac5
TG
339int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
340 struct ifinfomsg *ifi;
341
342 assert_return(m, -EINVAL);
9d0db178 343 assert_return(m->hdr, -EINVAL);
3815f36f 344 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
33125ac5 345 assert_return(ifindex, -EINVAL);
33125ac5
TG
346
347 ifi = NLMSG_DATA(m->hdr);
348
349 *ifindex = ifi->ifi_index;
350
351 return 0;
352}
353
50b3c42f
TG
354int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
355 struct ifinfomsg *ifi;
356
357 assert_return(m, -EINVAL);
9d0db178 358 assert_return(m->hdr, -EINVAL);
3815f36f 359 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
50b3c42f 360 assert_return(flags, -EINVAL);
50b3c42f
TG
361
362 ifi = NLMSG_DATA(m->hdr);
363
364 *flags = ifi->ifi_flags;
365
366 return 0;
367}
368
4ebe732c
ZJS
369/* If successful the updated message will be correctly aligned, if
370 unsuccessful the old message is untouched. */
65f568bb 371static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
dabfa9d1 372 uint32_t rta_length, message_length;
65f568bb
TG
373 struct nlmsghdr *new_hdr;
374 struct rtattr *rta;
8e337e64 375 char *padding;
5a081409 376 unsigned i;
65f568bb 377
33125ac5
TG
378 assert(m);
379 assert(m->hdr);
e5c4350b 380 assert(!m->sealed);
33125ac5
TG
381 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
382 assert(!data || data_length > 0);
5a081409 383 assert(data || m->n_containers < RTNL_CONTAINER_DEPTH);
65f568bb 384
8e337e64 385 /* get the size of the new rta attribute (with padding at the end) */
65f568bb 386 rta_length = RTA_LENGTH(data_length);
4ebe732c
ZJS
387
388 /* get the new message size (with padding at the end) */
65f568bb
TG
389 message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
390
391 /* realloc to fit the new attribute */
392 new_hdr = realloc(m->hdr, message_length);
393 if (!new_hdr)
394 return -ENOMEM;
395 m->hdr = new_hdr;
396
397 /* get pointer to the attribute we are about to add */
398 rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
65f568bb 399
5a081409
TG
400 /* if we are inside containers, extend them */
401 for (i = 0; i < m->n_containers; i++)
402 GET_CONTAINER(m, i)->rta_len += message_length - m->hdr->nlmsg_len;
33125ac5 403
65f568bb
TG
404 /* fill in the attribute */
405 rta->rta_type = type;
406 rta->rta_len = rta_length;
33125ac5 407 if (!data) {
d8e538ec 408 //TODO: simply return this value rather than check for !data
4ebe732c 409 /* this is the start of a new container */
5a081409 410 m->container_offsets[m->n_containers ++] = m->hdr->nlmsg_len;
33125ac5
TG
411 } else {
412 /* we don't deal with the case where the user lies about the type
413 * and gives us too little data (so don't do that)
414 */
415 padding = mempcpy(RTA_DATA(rta), data, data_length);
416 /* make sure also the padding at the end of the message is initialized */
4ebe732c
ZJS
417 memzero(padding,
418 (uint8_t *) m->hdr + message_length - (uint8_t *) padding);
33125ac5 419 }
65f568bb 420
4ebe732c
ZJS
421 /* update message size */
422 m->hdr->nlmsg_len = message_length;
423
65f568bb
TG
424 return 0;
425}
426
d8e538ec
TG
427static int message_attribute_has_type(sd_rtnl_message *m, uint16_t attribute_type, uint16_t data_type) {
428 const NLType *type;
429 int r;
430
431 r = type_system_get_type(m->container_type_system[m->n_containers], &type, attribute_type);
432 if (r < 0)
433 return r;
434
435 if (type->type != data_type)
436 return -EINVAL;
437
438 return type->size;
439}
440
0a0dc69b 441int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data) {
d8e538ec 442 size_t length, size;
0a0dc69b 443 int r;
65f568bb
TG
444
445 assert_return(m, -EINVAL);
e5c4350b 446 assert_return(!m->sealed, -EPERM);
65f568bb
TG
447 assert_return(data, -EINVAL);
448
d8e538ec 449 r = message_attribute_has_type(m, type, NLA_STRING);
0a0dc69b
TG
450 if (r < 0)
451 return r;
d8e538ec
TG
452 else
453 size = (size_t)r;
65f568bb 454
d8e538ec
TG
455 if (size) {
456 length = strnlen(data, size);
457 if (length >= size)
458 return -EINVAL;
459 } else
460 length = strlen(data);
33125ac5 461
d8e538ec 462 r = add_rtattr(m, type, data, length + 1);
0a0dc69b
TG
463 if (r < 0)
464 return r;
465
466 return 0;
467}
468
7b179640 469int sd_rtnl_message_append_u8(sd_rtnl_message *m, unsigned short type, uint8_t data) {
7b179640
SS
470 int r;
471
472 assert_return(m, -EINVAL);
473 assert_return(!m->sealed, -EPERM);
474
d8e538ec 475 r = message_attribute_has_type(m, type, NLA_U8);
7b179640
SS
476 if (r < 0)
477 return r;
478
7b179640
SS
479 r = add_rtattr(m, type, &data, sizeof(uint8_t));
480 if (r < 0)
481 return r;
482
483 return 0;
484}
485
486
01b36069 487int sd_rtnl_message_append_u16(sd_rtnl_message *m, unsigned short type, uint16_t data) {
01b36069
TG
488 int r;
489
490 assert_return(m, -EINVAL);
e5c4350b 491 assert_return(!m->sealed, -EPERM);
01b36069 492
d8e538ec 493 r = message_attribute_has_type(m, type, NLA_U16);
01b36069
TG
494 if (r < 0)
495 return r;
496
01b36069
TG
497 r = add_rtattr(m, type, &data, sizeof(uint16_t));
498 if (r < 0)
499 return r;
500
501 return 0;
502}
503
0a0dc69b 504int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) {
0a0dc69b
TG
505 int r;
506
507 assert_return(m, -EINVAL);
e5c4350b 508 assert_return(!m->sealed, -EPERM);
0a0dc69b 509
d8e538ec 510 r = message_attribute_has_type(m, type, NLA_U32);
0a0dc69b
TG
511 if (r < 0)
512 return r;
513
4d47756b 514 r = add_rtattr(m, type, &data, sizeof(uint32_t));
0a0dc69b
TG
515 if (r < 0)
516 return r;
517
518 return 0;
519}
520
521int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) {
0a0dc69b
TG
522 int r;
523
524 assert_return(m, -EINVAL);
e5c4350b 525 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
526 assert_return(data, -EINVAL);
527
d8e538ec 528 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
0a0dc69b
TG
529 if (r < 0)
530 return r;
531
4d47756b 532 r = add_rtattr(m, type, data, sizeof(struct in_addr));
0a0dc69b
TG
533 if (r < 0)
534 return r;
535
536 return 0;
537}
538
539int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) {
0a0dc69b
TG
540 int r;
541
542 assert_return(m, -EINVAL);
e5c4350b 543 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
544 assert_return(data, -EINVAL);
545
d8e538ec 546 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
0a0dc69b
TG
547 if (r < 0)
548 return r;
549
4d47756b 550 r = add_rtattr(m, type, data, sizeof(struct in6_addr));
0a0dc69b
TG
551 if (r < 0)
552 return r;
553
554 return 0;
555}
556
557int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) {
0a0dc69b
TG
558 int r;
559
560 assert_return(m, -EINVAL);
e5c4350b 561 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
562 assert_return(data, -EINVAL);
563
d8e538ec
TG
564 r = message_attribute_has_type(m, type, NLA_ETHER_ADDR);
565 if (r < 0)
566 return r;
0a0dc69b 567
b9eaf3d1 568 r = add_rtattr(m, type, data, ETH_ALEN);
0a0dc69b
TG
569 if (r < 0)
570 return r;
571
572 return 0;
65f568bb
TG
573}
574
aba496a5
UTL
575int sd_rtnl_message_append_cache_info(sd_rtnl_message *m, unsigned short type, const struct ifa_cacheinfo *info) {
576 int r;
577
578 assert_return(m, -EINVAL);
579 assert_return(!m->sealed, -EPERM);
580 assert_return(info, -EINVAL);
581
582 r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
583 if (r < 0)
584 return r;
585
586 r = add_rtattr(m, type, info, sizeof(struct ifa_cacheinfo));
587 if (r < 0)
588 return r;
589
590 return 0;
591}
592
ee3a6a51 593int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
d8e538ec
TG
594 size_t size;
595 int r;
33125ac5 596
65f568bb 597 assert_return(m, -EINVAL);
e5c4350b 598 assert_return(!m->sealed, -EPERM);
33125ac5 599
d8e538ec
TG
600 r = message_attribute_has_type(m, type, NLA_NESTED);
601 if (r < 0)
602 return r;
603 else
604 size = (size_t)r;
33125ac5 605
d8e538ec
TG
606 r = type_system_get_type_system(m->container_type_system[m->n_containers],
607 &m->container_type_system[m->n_containers + 1],
608 type);
609 if (r < 0)
610 return r;
31a4e153 611
d8e538ec
TG
612 r = add_rtattr(m, type, NULL, size);
613 if (r < 0)
614 return r;
615
616 return 0;
617}
618
619int sd_rtnl_message_open_container_union(sd_rtnl_message *m, unsigned short type, const char *key) {
620 const NLTypeSystemUnion *type_system_union;
621 int r;
622
623 assert_return(m, -EINVAL);
624 assert_return(!m->sealed, -EPERM);
625
626 r = type_system_get_type_system_union(m->container_type_system[m->n_containers], &type_system_union, type);
627 if (r < 0)
628 return r;
629
630 r = type_system_union_get_type_system(type_system_union,
631 &m->container_type_system[m->n_containers + 1],
632 key);
633 if (r < 0)
634 return r;
33125ac5 635
d8e538ec
TG
636 r = sd_rtnl_message_append_string(m, type_system_union->match, key);
637 if (r < 0)
638 return r;
639
640 /* do we evere need non-null size */
641 r = add_rtattr(m, type, NULL, 0);
642 if (r < 0)
643 return r;
644
645 return 0;
33125ac5
TG
646}
647
d8e538ec 648
33125ac5
TG
649int sd_rtnl_message_close_container(sd_rtnl_message *m) {
650 assert_return(m, -EINVAL);
e5c4350b 651 assert_return(!m->sealed, -EPERM);
5a081409 652 assert_return(m->n_containers > 0, -EINVAL);
33125ac5 653
d8e538ec 654 m->container_type_system[m->n_containers] = NULL;
5a081409 655 m->n_containers --;
33125ac5
TG
656
657 return 0;
658}
659
44caa5e7 660int rtnl_message_read_internal(sd_rtnl_message *m, unsigned short type, void **data) {
f66eeb6b
TG
661 struct rtattr *rta;
662
44caa5e7
SS
663 assert_return(m, -EINVAL);
664 assert_return(m->sealed, -EPERM);
665 assert_return(data, -EINVAL);
d8e538ec
TG
666 assert(m->n_containers <= RTNL_CONTAINER_DEPTH);
667 assert(m->rta_offset_tb[m->n_containers]);
668 assert(type < m->rta_tb_size[m->n_containers]);
44caa5e7 669
3dd215e0 670 if(!m->rta_offset_tb[m->n_containers][type])
44caa5e7
SS
671 return -ENODATA;
672
3dd215e0 673 rta = (struct rtattr*)((uint8_t *) m->hdr + m->rta_offset_tb[m->n_containers][type]);
44caa5e7 674
f66eeb6b
TG
675 *data = RTA_DATA(rta);
676
677 return RTA_PAYLOAD(rta);
44caa5e7
SS
678}
679
680int sd_rtnl_message_read_string(sd_rtnl_message *m, unsigned short type, char **data) {
681 int r;
682 void *attr_data;
683
d8e538ec
TG
684 r = message_attribute_has_type(m, type, NLA_STRING);
685 if (r < 0)
686 return r;
44caa5e7
SS
687
688 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 689 if (r < 0)
44caa5e7 690 return r;
f66eeb6b
TG
691 else if (strnlen(attr_data, r) >= (size_t) r)
692 return -EIO;
44caa5e7
SS
693
694 *data = (char *) attr_data;
695
696 return 0;
697}
698
699int sd_rtnl_message_read_u8(sd_rtnl_message *m, unsigned short type, uint8_t *data) {
700 int r;
701 void *attr_data;
702
d8e538ec
TG
703 r = message_attribute_has_type(m, type, NLA_U8);
704 if (r < 0)
705 return r;
44caa5e7
SS
706
707 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 708 if (r < 0)
44caa5e7 709 return r;
f66eeb6b
TG
710 else if ((size_t) r < sizeof(uint8_t))
711 return -EIO;
44caa5e7
SS
712
713 *data = *(uint8_t *) attr_data;
714
715 return 0;
716}
717
718int sd_rtnl_message_read_u16(sd_rtnl_message *m, unsigned short type, uint16_t *data) {
719 int r;
720 void *attr_data;
721
d8e538ec
TG
722 r = message_attribute_has_type(m, type, NLA_U16);
723 if (r < 0)
724 return r;
44caa5e7
SS
725
726 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 727 if (r < 0)
44caa5e7 728 return r;
f66eeb6b
TG
729 else if ((size_t) r < sizeof(uint16_t))
730 return -EIO;
44caa5e7
SS
731
732 *data = *(uint16_t *) attr_data;
733
734 return 0;
735}
736
737int sd_rtnl_message_read_u32(sd_rtnl_message *m, unsigned short type, uint32_t *data) {
738 int r;
739 void *attr_data;
740
d8e538ec
TG
741 r = message_attribute_has_type(m, type, NLA_U32);
742 if (r < 0)
743 return r;
44caa5e7
SS
744
745 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 746 if (r < 0)
44caa5e7 747 return r;
f66eeb6b
TG
748 else if ((size_t)r < sizeof(uint32_t))
749 return -EIO;
44caa5e7
SS
750
751 *data = *(uint32_t *) attr_data;
752
753 return 0;
754}
755
4e9e7f18
SS
756int sd_rtnl_message_read_ether_addr(sd_rtnl_message *m, unsigned short type, struct ether_addr *data) {
757 int r;
758 void *attr_data;
759
d8e538ec
TG
760 r = message_attribute_has_type(m, type, NLA_ETHER_ADDR);
761 if (r < 0)
762 return r;
4e9e7f18
SS
763
764 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 765 if (r < 0)
4e9e7f18 766 return r;
f66eeb6b
TG
767 else if ((size_t)r < sizeof(struct ether_addr))
768 return -EIO;
4e9e7f18
SS
769
770 memcpy(data, attr_data, sizeof(struct ether_addr));
771
772 return 0;
773}
774
aba496a5
UTL
775int sd_rtnl_message_read_cache_info(sd_rtnl_message *m, unsigned short type, struct ifa_cacheinfo *info) {
776 int r;
777 void *attr_data;
778
779 r = message_attribute_has_type(m, type, NLA_CACHE_INFO);
780 if (r < 0)
781 return r;
782
783 r = rtnl_message_read_internal(m, type, &attr_data);
784 if (r < 0)
785 return r;
786 else if ((size_t)r < sizeof(struct ifa_cacheinfo))
787 return -EIO;
788
789 memcpy(info, attr_data, sizeof(struct ifa_cacheinfo));
790
791 return 0;
792}
793
4e9e7f18
SS
794int sd_rtnl_message_read_in_addr(sd_rtnl_message *m, unsigned short type, struct in_addr *data) {
795 int r;
796 void *attr_data;
797
d8e538ec
TG
798 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
799 if (r < 0)
800 return r;
4e9e7f18
SS
801
802 r = rtnl_message_read_internal(m, type, &attr_data);
f66eeb6b 803 if (r < 0)
4e9e7f18 804 return r;
f66eeb6b
TG
805 else if ((size_t)r < sizeof(struct in_addr))
806 return -EIO;
4e9e7f18
SS
807
808 memcpy(data, attr_data, sizeof(struct in_addr));
809
810 return 0;
811}
812
813int sd_rtnl_message_read_in6_addr(sd_rtnl_message *m, unsigned short type, struct in6_addr *data) {
814 int r;
815 void *attr_data;
816
d8e538ec
TG
817 r = message_attribute_has_type(m, type, NLA_IN_ADDR);
818 if (r < 0)
819 return r;
4e9e7f18
SS
820
821 r = rtnl_message_read_internal(m, type, &attr_data);
3dd215e0 822 if (r < 0)
4e9e7f18 823 return r;
3dd215e0
TG
824 else if ((size_t)r < sizeof(struct in6_addr))
825 return -EIO;
4e9e7f18
SS
826
827 memcpy(data, attr_data, sizeof(struct in6_addr));
828
829 return 0;
830}
831
3dd215e0 832int sd_rtnl_message_enter_container(sd_rtnl_message *m, unsigned short type) {
d8e538ec
TG
833 const NLType *nl_type;
834 const NLTypeSystem *type_system;
3dd215e0 835 void *container;
d8e538ec
TG
836 size_t size;
837 int r;
3dd215e0
TG
838
839 assert_return(m, -EINVAL);
840 assert_return(m->n_containers < RTNL_CONTAINER_DEPTH, -EINVAL);
841
d8e538ec
TG
842 r = type_system_get_type(m->container_type_system[m->n_containers],
843 &nl_type,
844 type);
3dd215e0
TG
845 if (r < 0)
846 return r;
3dd215e0 847
d8e538ec
TG
848 if (nl_type->type == NLA_NESTED) {
849 r = type_system_get_type_system(m->container_type_system[m->n_containers],
850 &type_system,
851 type);
852 if (r < 0)
853 return r;
854 } else if (nl_type->type == NLA_UNION) {
855 const NLTypeSystemUnion *type_system_union;
856 char *key;
857
858 r = type_system_get_type_system_union(m->container_type_system[m->n_containers],
859 &type_system_union,
860 type);
861 if (r < 0)
862 return r;
863
864 r = sd_rtnl_message_read_string(m, type_system_union->match, &key);
865 if (r < 0)
866 return r;
867
868 r = type_system_union_get_type_system(type_system_union,
869 &type_system,
870 key);
871 if (r < 0)
872 return r;
873 } else
874 return -EINVAL;
875
876 r = rtnl_message_read_internal(m, type, &container);
3dd215e0
TG
877 if (r < 0)
878 return r;
d8e538ec
TG
879 else
880 size = (size_t)r;
3dd215e0 881
d8e538ec 882 m->n_containers ++;
3dd215e0
TG
883
884 r = rtnl_message_parse(m,
d8e538ec
TG
885 &m->rta_offset_tb[m->n_containers],
886 &m->rta_tb_size[m->n_containers],
887 type_system->max,
3dd215e0 888 container,
d8e538ec
TG
889 size);
890 if (r < 0) {
891 m->n_containers --;
3dd215e0 892 return r;
d8e538ec 893 }
3dd215e0 894
d8e538ec 895 m->container_type_system[m->n_containers] = type_system;
3dd215e0
TG
896
897 return 0;
898}
899
e5c4350b
TG
900int sd_rtnl_message_exit_container(sd_rtnl_message *m) {
901 assert_return(m, -EINVAL);
902 assert_return(m->sealed, -EINVAL);
903 assert_return(m->n_containers > 0, -EINVAL);
904
3dd215e0
TG
905 free(m->rta_offset_tb[m->n_containers]);
906 m->rta_offset_tb[m->n_containers] = NULL;
d8e538ec 907 m->container_type_system[m->n_containers] = NULL;
3dd215e0 908
e5c4350b
TG
909 m->n_containers --;
910
911 return 0;
912}
913
3815f36f 914uint32_t rtnl_message_get_serial(sd_rtnl_message *m) {
65f568bb 915 assert(m);
9d0db178 916 assert(m->hdr);
65f568bb
TG
917
918 return m->hdr->nlmsg_seq;
919}
920
e16bcf98 921int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
65f568bb
TG
922 struct nlmsgerr *err;
923
e16bcf98 924 assert_return(m, -EINVAL);
9d0db178 925 assert_return(m->hdr, -EINVAL);
65f568bb
TG
926
927 if (m->hdr->nlmsg_type != NLMSG_ERROR)
928 return 0;
929
930 err = NLMSG_DATA(m->hdr);
931
932 return err->error;
933}
934
65f568bb 935static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
9d0db178
TG
936 assert(rtnl);
937 assert(need);
65f568bb
TG
938
939 /* ioctl(rtnl->fd, FIONREAD, &need)
dabfa9d1
TG
940 Does not appear to work on netlink sockets. libnl uses
941 MSG_PEEK instead. I don't know if that is worth the
942 extra roundtrip.
943
944 For now we simply use the maximum message size the kernel
945 may use (NLMSG_GOODSIZE), and then realloc to the actual
946 size after reading the message (hence avoiding huge memory
947 usage in case many small messages are kept around) */
948 *need = page_size();
65f568bb
TG
949 if (*need > 8192UL)
950 *need = 8192UL;
951
952 return 0;
953}
954
44caa5e7
SS
955int rtnl_message_parse(sd_rtnl_message *m,
956 size_t **rta_offset_tb,
957 unsigned short *rta_tb_size,
958 int max,
959 struct rtattr *rta,
960 unsigned int rt_len) {
e634cd40 961 unsigned short type;
44caa5e7
SS
962 size_t *tb;
963
c8a7165f 964 tb = new0(size_t, max + 1);
44caa5e7
SS
965 if(!tb)
966 return -ENOMEM;
967
c8a7165f 968 *rta_tb_size = max + 1;
44caa5e7
SS
969
970 for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
971 type = rta->rta_type;
972
aef0768e
TG
973 /* if the kernel is newer than the headers we used
974 when building, we ignore out-of-range attributes
975 */
976 if (type > max)
e634cd40 977 continue;
e634cd40
TG
978
979 if (tb[type])
980 log_debug("rtnl: message parse - overwriting repeated attribute");
981
982 tb[type] = (uint8_t *) rta - (uint8_t *) m->hdr;
44caa5e7
SS
983 }
984
985 *rta_offset_tb = tb;
986
987 return 0;
988}
989
65f568bb
TG
990/* returns the number of bytes sent, or a negative error code */
991int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
d4bbdb77
TG
992 union {
993 struct sockaddr sa;
994 struct sockaddr_nl nl;
995 } addr = {
996 .nl.nl_family = AF_NETLINK,
997 };
65f568bb
TG
998 ssize_t k;
999
9d0db178
TG
1000 assert(nl);
1001 assert(m);
1002 assert(m->hdr);
65f568bb
TG
1003
1004 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
d4bbdb77 1005 0, &addr.sa, sizeof(addr));
65f568bb
TG
1006 if (k < 0)
1007 return (errno == EAGAIN) ? 0 : -errno;
1008
1009 return k;
1010}
1011
1012/* On success, the number of bytes received is returned and *ret points to the received message
1013 * which has a valid header and the correct size.
1014 * If nothing useful was received 0 is returned.
1015 * On failure, a negative error code is returned.
dabfa9d1 1016 */
65f568bb 1017int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
3dd215e0 1018 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
d8e538ec 1019 const NLType *nl_type;
3dd215e0 1020 struct nlmsghdr *new_hdr;
d4bbdb77
TG
1021 union {
1022 struct sockaddr sa;
1023 struct sockaddr_nl nl;
1024 } addr;
1025 socklen_t addr_len;
3dd215e0 1026 size_t need, len;
65f568bb 1027 int r;
65f568bb 1028
9d0db178
TG
1029 assert(nl);
1030 assert(ret);
65f568bb
TG
1031
1032 r = message_receive_need(nl, &need);
1033 if (r < 0)
1034 return r;
1035
d8e538ec 1036 r = message_new_empty(nl, &m, need);
65f568bb
TG
1037 if (r < 0)
1038 return r;
1039
d4bbdb77
TG
1040 addr_len = sizeof(addr);
1041
3dd215e0 1042 r = recvfrom(nl->fd, m->hdr, need,
d4bbdb77 1043 0, &addr.sa, &addr_len);
3dd215e0
TG
1044 if (r < 0)
1045 return (errno == EAGAIN) ? 0 : -errno; /* no data */
1046 else if (r == 0)
1047 return -ECONNRESET; /* connection was closed by the kernel */
d4bbdb77
TG
1048 else if (addr_len != sizeof(addr.nl) ||
1049 addr.nl.nl_family != AF_NETLINK)
3dd215e0 1050 return -EIO; /* not a netlink message */
d4bbdb77 1051 else if (addr.nl.nl_pid != 0)
3dd215e0
TG
1052 return 0; /* not from the kernel */
1053 else if ((size_t) r < sizeof(struct nlmsghdr) ||
1054 (size_t) r < m->hdr->nlmsg_len)
1055 return -EIO; /* too small (we do accept too big though) */
a02113d2 1056 else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
3dd215e0
TG
1057 return 0; /* not broadcast and not for us */
1058 else
1059 len = (size_t) r;
1060
d8e538ec
TG
1061 /* silently drop noop messages */
1062 if (m->hdr->nlmsg_type == NLMSG_NOOP)
1063 return 0;
3dd215e0 1064
d8e538ec
TG
1065 /* check that we support this message type */
1066 r = type_system_get_type(NULL, &nl_type, m->hdr->nlmsg_type);
1067 if (r < 0) {
1068 if (r == -ENOTSUP)
1069 log_debug("sd-rtnl: ignored message with unknown type: %u",
1070 m->hdr->nlmsg_type);
3dd215e0 1071
3dd215e0
TG
1072 return 0;
1073 }
bdd13f6b 1074
d8e538ec
TG
1075 /* check that the size matches the message type */
1076 if (len < NLMSG_LENGTH(nl_type->size))
1077 return -EIO;
1078
3dd215e0
TG
1079 /* we probably allocated way too much memory, give it back */
1080 new_hdr = realloc(m->hdr, len);
1081 if (!new_hdr)
1082 return -ENOMEM;
1083 m->hdr = new_hdr;
bdd13f6b 1084
3dd215e0
TG
1085 /* seal and parse the top-level message */
1086 r = sd_rtnl_message_rewind(m);
1087 if (r < 0)
1088 return r;
65f568bb 1089
3dd215e0
TG
1090 *ret = m;
1091 m = NULL;
65f568bb 1092
3dd215e0 1093 return len;
65f568bb 1094}
0fc7531b
TG
1095
1096int sd_rtnl_message_rewind(sd_rtnl_message *m) {
d8e538ec 1097 const NLType *type;
3dd215e0
TG
1098 unsigned i;
1099 int r;
0fc7531b
TG
1100
1101 assert_return(m, -EINVAL);
0fc7531b 1102
3dd215e0
TG
1103 /* don't allow appending to message once parsed */
1104 if (!m->sealed)
1105 rtnl_message_seal(m);
1106
1107 for (i = 1; i <= m->n_containers; i++) {
1108 free(m->rta_offset_tb[i]);
1109 m->rta_offset_tb[i] = NULL;
1110 m->rta_tb_size[i] = 0;
d8e538ec 1111 m->container_type_system[i] = NULL;
3dd215e0
TG
1112 }
1113
1114 m->n_containers = 0;
1115
1116 if (m->rta_offset_tb[0]) {
1117 /* top-level attributes have already been parsed */
1118 return 0;
1119 }
1120
d8e538ec
TG
1121 assert(m->hdr);
1122
1123 r = type_system_get_type(NULL, &type, m->hdr->nlmsg_type);
1124 if (r < 0)
1125 return r;
1126
1127 if (type->type == NLA_NESTED) {
1128 const NLTypeSystem *type_system = type->type_system;
1129
1130 assert(type_system);
1131
1132 m->container_type_system[0] = type_system;
1133
1134 r = rtnl_message_parse(m,
1135 &m->rta_offset_tb[m->n_containers],
1136 &m->rta_tb_size[m->n_containers],
1137 type_system->max,
0834ff93
TG
1138 (struct rtattr*)((uint8_t*)NLMSG_DATA(m->hdr) +
1139 NLMSG_ALIGN(type->size)),
d8e538ec
TG
1140 NLMSG_PAYLOAD(m->hdr, type->size));
1141 if (r < 0)
1142 return r;
0fc7531b
TG
1143 }
1144
1145 return 0;
1146}
3dd215e0
TG
1147
1148void rtnl_message_seal(sd_rtnl_message *m) {
1149 assert(m);
1150 assert(!m->sealed);
1151
1152 m->sealed = true;
1153}