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