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