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