]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-rtnl/rtnl-message.c
networkd: netdev - support joining already existing netdevs
[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
33125ac5
TG
298int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
299 struct ifinfomsg *ifi;
300
301 assert_return(m, -EINVAL);
9d0db178 302 assert_return(m->hdr, -EINVAL);
3815f36f 303 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
33125ac5 304 assert_return(ifindex, -EINVAL);
33125ac5
TG
305
306 ifi = NLMSG_DATA(m->hdr);
307
308 *ifindex = ifi->ifi_index;
309
310 return 0;
311}
312
50b3c42f
TG
313int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
314 struct ifinfomsg *ifi;
315
316 assert_return(m, -EINVAL);
9d0db178 317 assert_return(m->hdr, -EINVAL);
3815f36f 318 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
50b3c42f 319 assert_return(flags, -EINVAL);
50b3c42f
TG
320
321 ifi = NLMSG_DATA(m->hdr);
322
323 *flags = ifi->ifi_flags;
324
325 return 0;
326}
327
4ebe732c
ZJS
328/* If successful the updated message will be correctly aligned, if
329 unsuccessful the old message is untouched. */
65f568bb 330static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
dabfa9d1 331 uint32_t rta_length, message_length;
65f568bb
TG
332 struct nlmsghdr *new_hdr;
333 struct rtattr *rta;
8e337e64 334 char *padding;
5a081409 335 unsigned i;
65f568bb 336
33125ac5
TG
337 assert(m);
338 assert(m->hdr);
e5c4350b 339 assert(!m->sealed);
33125ac5
TG
340 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
341 assert(!data || data_length > 0);
5a081409 342 assert(data || m->n_containers < RTNL_CONTAINER_DEPTH);
65f568bb 343
8e337e64 344 /* get the size of the new rta attribute (with padding at the end) */
65f568bb 345 rta_length = RTA_LENGTH(data_length);
4ebe732c
ZJS
346
347 /* get the new message size (with padding at the end) */
65f568bb
TG
348 message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
349
350 /* realloc to fit the new attribute */
351 new_hdr = realloc(m->hdr, message_length);
352 if (!new_hdr)
353 return -ENOMEM;
354 m->hdr = new_hdr;
355
356 /* get pointer to the attribute we are about to add */
357 rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
65f568bb 358
5a081409
TG
359 /* if we are inside containers, extend them */
360 for (i = 0; i < m->n_containers; i++)
361 GET_CONTAINER(m, i)->rta_len += message_length - m->hdr->nlmsg_len;
33125ac5 362
65f568bb
TG
363 /* fill in the attribute */
364 rta->rta_type = type;
365 rta->rta_len = rta_length;
33125ac5 366 if (!data) {
4ebe732c 367 /* this is the start of a new container */
5a081409 368 m->container_offsets[m->n_containers ++] = m->hdr->nlmsg_len;
33125ac5
TG
369 } else {
370 /* we don't deal with the case where the user lies about the type
371 * and gives us too little data (so don't do that)
372 */
373 padding = mempcpy(RTA_DATA(rta), data, data_length);
374 /* make sure also the padding at the end of the message is initialized */
4ebe732c
ZJS
375 memzero(padding,
376 (uint8_t *) m->hdr + message_length - (uint8_t *) padding);
33125ac5 377 }
65f568bb 378
4ebe732c
ZJS
379 /* update message size */
380 m->hdr->nlmsg_len = message_length;
381
65f568bb
TG
382 return 0;
383}
384
0a0dc69b 385int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data) {
dabfa9d1 386 uint16_t rtm_type;
0a0dc69b 387 int r;
65f568bb
TG
388
389 assert_return(m, -EINVAL);
e5c4350b 390 assert_return(!m->sealed, -EPERM);
65f568bb
TG
391 assert_return(data, -EINVAL);
392
0a0dc69b
TG
393 r = sd_rtnl_message_get_type(m, &rtm_type);
394 if (r < 0)
395 return r;
65f568bb 396
0a0dc69b
TG
397 /* check that the type is correct */
398 switch (rtm_type) {
399 case RTM_NEWLINK:
400 case RTM_SETLINK:
401 case RTM_GETLINK:
402 case RTM_DELLINK:
5a081409
TG
403 if (m->n_containers == 1) {
404 if (GET_CONTAINER(m, 0)->rta_type != IFLA_LINKINFO ||
0a0dc69b
TG
405 type != IFLA_INFO_KIND)
406 return -ENOTSUP;
407 } else {
408 switch (type) {
409 case IFLA_IFNAME:
410 case IFLA_IFALIAS:
411 case IFLA_QDISC:
412 break;
33125ac5
TG
413 default:
414 return -ENOTSUP;
415 }
0a0dc69b
TG
416 }
417 break;
418 case RTM_NEWADDR:
419 case RTM_GETADDR:
420 case RTM_DELADDR:
421 if (type != IFA_LABEL)
33125ac5 422 return -ENOTSUP;
0a0dc69b
TG
423 break;
424 default:
425 return -ENOTSUP;
33125ac5
TG
426 }
427
0a0dc69b
TG
428 r = add_rtattr(m, type, data, strlen(data) + 1);
429 if (r < 0)
430 return r;
431
432 return 0;
433}
434
7b179640
SS
435int sd_rtnl_message_append_u8(sd_rtnl_message *m, unsigned short type, uint8_t data) {
436 uint16_t rtm_type;
437 int r;
438
439 assert_return(m, -EINVAL);
440 assert_return(!m->sealed, -EPERM);
441
442 r = sd_rtnl_message_get_type(m, &rtm_type);
443 if (r < 0)
444 return r;
445
446 switch (rtm_type) {
447 case RTM_NEWLINK:
448 case RTM_SETLINK:
449 case RTM_GETLINK:
450 case RTM_DELLINK:
451 switch (type) {
452 case IFLA_CARRIER:
453 case IFLA_OPERSTATE:
454 case IFLA_LINKMODE:
455 break;
456 default:
457 return -ENOTSUP;
458 }
459
460 break;
461 default:
462 return -ENOTSUP;
463 }
464
465 r = add_rtattr(m, type, &data, sizeof(uint8_t));
466 if (r < 0)
467 return r;
468
469 return 0;
470}
471
472
01b36069
TG
473int sd_rtnl_message_append_u16(sd_rtnl_message *m, unsigned short type, uint16_t data) {
474 uint16_t rtm_type;
475 int r;
476
477 assert_return(m, -EINVAL);
e5c4350b 478 assert_return(!m->sealed, -EPERM);
01b36069
TG
479
480 r = sd_rtnl_message_get_type(m, &rtm_type);
481 if (r < 0)
482 return r;
483
484 /* check that the type is correct */
485 switch (rtm_type) {
486 case RTM_NEWLINK:
487 case RTM_SETLINK:
488 case RTM_GETLINK:
489 case RTM_DELLINK:
5a081409
TG
490 if (m->n_containers == 2 &&
491 GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO &&
492 GET_CONTAINER(m, 1)->rta_type == IFLA_INFO_DATA &&
493 type == IFLA_VLAN_ID)
494 break;
495 else
496 return -ENOTSUP;
bdd13f6b 497
01b36069
TG
498 default:
499 return -ENOTSUP;
500 }
501
502 r = add_rtattr(m, type, &data, sizeof(uint16_t));
503 if (r < 0)
504 return r;
505
506 return 0;
507}
508
0a0dc69b
TG
509int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) {
510 uint16_t rtm_type;
511 int r;
512
513 assert_return(m, -EINVAL);
e5c4350b 514 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
515
516 r = sd_rtnl_message_get_type(m, &rtm_type);
517 if (r < 0)
518 return r;
519
520 /* check that the type is correct */
65f568bb
TG
521 switch (rtm_type) {
522 case RTM_NEWLINK:
d2df0d0e 523 case RTM_SETLINK:
65f568bb 524 case RTM_GETLINK:
0a0dc69b 525 case RTM_DELLINK:
65f568bb 526 switch (type) {
46fabae6 527 case IFLA_MASTER:
65f568bb 528 case IFLA_MTU:
65f568bb 529 case IFLA_LINK:
7b179640
SS
530 case IFLA_GROUP:
531 case IFLA_TXQLEN:
108e131e
SS
532 case IFLA_WEIGHT:
533 case IFLA_NET_NS_FD:
534 case IFLA_NET_NS_PID:
535 case IFLA_PROMISCUITY:
7b179640
SS
536 case IFLA_NUM_TX_QUEUES:
537 case IFLA_NUM_RX_QUEUES:
c74e630d 538 case IFLA_MACVLAN_MODE:
0a0dc69b 539 break;
65f568bb
TG
540 default:
541 return -ENOTSUP;
542 }
0a0dc69b
TG
543 break;
544 case RTM_NEWROUTE:
545 case RTM_GETROUTE:
546 case RTM_DELROUTE:
547 switch (type) {
548 case RTA_TABLE:
549 case RTA_PRIORITY:
550 case RTA_IIF:
551 case RTA_OIF:
108e131e 552 case RTA_MARK:
0a0dc69b
TG
553 break;
554 default:
555 return -ENOTSUP;
556 }
557 break;
558 default:
559 return -ENOTSUP;
560 }
561
4d47756b 562 r = add_rtattr(m, type, &data, sizeof(uint32_t));
0a0dc69b
TG
563 if (r < 0)
564 return r;
565
566 return 0;
567}
568
569int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) {
570 struct ifaddrmsg *ifa;
571 struct rtmsg *rtm;
572 uint16_t rtm_type;
573 int r;
574
575 assert_return(m, -EINVAL);
e5c4350b 576 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
577 assert_return(data, -EINVAL);
578
579 r = sd_rtnl_message_get_type(m, &rtm_type);
580 if (r < 0)
581 return r;
582
583 /* check that the type is correct */
584 switch (rtm_type) {
65f568bb 585 case RTM_NEWADDR:
65f568bb 586 case RTM_GETADDR:
0a0dc69b 587 case RTM_DELADDR:
65f568bb 588 switch (type) {
65f568bb
TG
589 case IFA_ADDRESS:
590 case IFA_LOCAL:
591 case IFA_BROADCAST:
592 case IFA_ANYCAST:
593 ifa = NLMSG_DATA(m->hdr);
0a0dc69b
TG
594
595 if (ifa->ifa_family != AF_INET)
596 return -EINVAL;
597
598 break;
65f568bb
TG
599 default:
600 return -ENOTSUP;
601 }
0a0dc69b 602 break;
03d7e632 603 case RTM_NEWROUTE:
0a0dc69b 604 case RTM_GETROUTE:
03d7e632 605 case RTM_DELROUTE:
0a0dc69b
TG
606 switch (type) {
607 case RTA_DST:
608 case RTA_SRC:
609 case RTA_GATEWAY:
610 rtm = NLMSG_DATA(m->hdr);
611
612 if (rtm->rtm_family != AF_INET)
613 return -EINVAL;
614
615 break;
616 default:
617 return -ENOTSUP;
618 }
619 break;
620 default:
621 return -ENOTSUP;
622 }
623
4d47756b 624 r = add_rtattr(m, type, data, sizeof(struct in_addr));
0a0dc69b
TG
625 if (r < 0)
626 return r;
627
628 return 0;
629}
630
631int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) {
632 struct ifaddrmsg *ifa;
633 struct rtmsg *rtm;
634 uint16_t rtm_type;
635 int r;
636
637 assert_return(m, -EINVAL);
e5c4350b 638 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
639 assert_return(data, -EINVAL);
640
641 r = sd_rtnl_message_get_type(m, &rtm_type);
642 if (r < 0)
643 return r;
644
645 /* check that the type is correct */
646 switch (rtm_type) {
647 case RTM_NEWADDR:
648 case RTM_GETADDR:
649 case RTM_DELADDR:
650 switch (type) {
651 case IFA_ADDRESS:
652 case IFA_LOCAL:
653 case IFA_BROADCAST:
654 case IFA_ANYCAST:
655 ifa = NLMSG_DATA(m->hdr);
656
657 if (ifa->ifa_family != AF_INET6)
658 return -EINVAL;
659
660 break;
661 default:
662 return -ENOTSUP;
663 }
664 break;
665 case RTM_NEWROUTE:
03d7e632 666 case RTM_GETROUTE:
0a0dc69b 667 case RTM_DELROUTE:
03d7e632
TG
668 switch (type) {
669 case RTA_DST:
670 case RTA_SRC:
671 case RTA_GATEWAY:
672 rtm = NLMSG_DATA(m->hdr);
0a0dc69b
TG
673
674 if (rtm->rtm_family != AF_INET6)
675 return -EINVAL;
676
677 break;
678 default:
679 return -ENOTSUP;
680 }
681 default:
682 return -ENOTSUP;
683 }
684
4d47756b 685 r = add_rtattr(m, type, data, sizeof(struct in6_addr));
0a0dc69b
TG
686 if (r < 0)
687 return r;
688
689 return 0;
690}
691
692int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) {
693 uint16_t rtm_type;
694 int r;
695
696 assert_return(m, -EINVAL);
e5c4350b 697 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
698 assert_return(data, -EINVAL);
699
700 sd_rtnl_message_get_type(m, &rtm_type);
701
702 switch (rtm_type) {
703 case RTM_NEWLINK:
704 case RTM_SETLINK:
705 case RTM_DELLINK:
706 case RTM_GETLINK:
707 switch (type) {
708 case IFLA_ADDRESS:
709 case IFLA_BROADCAST:
710 break;
03d7e632
TG
711 default:
712 return -ENOTSUP;
713 }
0a0dc69b 714 break;
65f568bb
TG
715 default:
716 return -ENOTSUP;
717 }
0a0dc69b 718
b9eaf3d1 719 r = add_rtattr(m, type, data, ETH_ALEN);
0a0dc69b
TG
720 if (r < 0)
721 return r;
722
723 return 0;
65f568bb
TG
724}
725
ee3a6a51 726int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
33125ac5
TG
727 uint16_t rtm_type;
728
65f568bb 729 assert_return(m, -EINVAL);
e5c4350b 730 assert_return(!m->sealed, -EPERM);
33125ac5
TG
731
732 sd_rtnl_message_get_type(m, &rtm_type);
733
3815f36f 734 if (rtnl_message_type_is_link(rtm_type)) {
31a4e153 735
5a081409 736 if ((type == IFLA_LINKINFO && m->n_containers == 0) ||
ee3a6a51
TG
737 (type == IFLA_INFO_DATA && m->n_containers == 1 &&
738 GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO))
739 return add_rtattr(m, type, NULL, 0);
740 else if (type == VETH_INFO_PEER && m->n_containers == 2 &&
741 GET_CONTAINER(m, 1)->rta_type == IFLA_INFO_DATA &&
742 GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO)
743 return add_rtattr(m, type, NULL, sizeof(struct ifinfomsg));
31a4e153 744 }
33125ac5 745
31a4e153 746 return -ENOTSUP;
33125ac5
TG
747}
748
749int sd_rtnl_message_close_container(sd_rtnl_message *m) {
750 assert_return(m, -EINVAL);
e5c4350b 751 assert_return(!m->sealed, -EPERM);
5a081409 752 assert_return(m->n_containers > 0, -EINVAL);
33125ac5 753
5a081409 754 m->n_containers --;
33125ac5
TG
755
756 return 0;
757}
758
0fc7531b
TG
759int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
760 size_t remaining_size;
33125ac5
TG
761 uint16_t rtm_type;
762 int r;
763
e5c4350b
TG
764 assert_return(m, -EINVAL);
765 assert_return(m->sealed, -EPERM);
766 assert_return(m->next_rta_offset, -EINVAL);
767 assert_return(type, -EINVAL);
768 assert_return(data, -EINVAL);
65f568bb 769
e5c4350b
TG
770 /* only read until the end of the current container */
771 if (m->n_containers)
772 remaining_size = GET_CONTAINER(m, m->n_containers - 1)->rta_len -
773 (m->next_rta_offset -
774 m->container_offsets[m->n_containers - 1]);
775 else
776 remaining_size = m->hdr->nlmsg_len - m->next_rta_offset;
0fc7531b 777
4ebe732c 778 if (!RTA_OK(NEXT_RTA(m), remaining_size))
65f568bb
TG
779 return 0;
780
3b35ade3 781 /* if we read a container, return its type, but do not enter it*/
33125ac5
TG
782 r = sd_rtnl_message_get_type(m, &rtm_type);
783 if (r < 0)
784 return r;
785
4ebe732c 786 *type = NEXT_RTA(m)->rta_type;
65f568bb 787
3815f36f 788 if (rtnl_message_type_is_link(rtm_type) &&
e5c4350b
TG
789 ((m->n_containers == 0 &&
790 NEXT_RTA(m)->rta_type == IFLA_LINKINFO) ||
791 (m->n_containers == 1 &&
792 GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO &&
3b35ade3 793 NEXT_RTA(m)->rta_type == IFLA_INFO_DATA)))
e5c4350b 794 *data = NULL;
3b35ade3 795 else
e5c4350b 796 *data = RTA_DATA(NEXT_RTA(m));
3b35ade3
TG
797
798 UPDATE_RTA(m, RTA_NEXT(NEXT_RTA(m), remaining_size));
65f568bb
TG
799
800 return 1;
801}
802
44caa5e7
SS
803int rtnl_message_read_internal(sd_rtnl_message *m, unsigned short type, void **data) {
804 assert_return(m, -EINVAL);
805 assert_return(m->sealed, -EPERM);
806 assert_return(data, -EINVAL);
807 assert_return(m->rta_offset_tb, -EINVAL);
808 assert_return(type < m->rta_tb_size, -EINVAL);
809
810 if(!m->rta_offset_tb[type])
811 return -ENODATA;
812
813 *data = RTA_DATA((struct rtattr *)((uint8_t *) m->hdr + m->rta_offset_tb[type]));
814
815 return 0;
816}
817
818int sd_rtnl_message_read_string(sd_rtnl_message *m, unsigned short type, char **data) {
819 int r;
820 void *attr_data;
821
822 assert_return(data, -EINVAL);
823
824 r = rtnl_message_read_internal(m, type, &attr_data);
825 if(r < 0)
826 return r;
827
828 *data = (char *) attr_data;
829
830 return 0;
831}
832
833int sd_rtnl_message_read_u8(sd_rtnl_message *m, unsigned short type, uint8_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);
840 if(r < 0)
841 return r;
842
843 *data = *(uint8_t *) attr_data;
844
845 return 0;
846}
847
848int sd_rtnl_message_read_u16(sd_rtnl_message *m, unsigned short type, uint16_t *data) {
849 int r;
850 void *attr_data;
851
852 assert_return(data, -EINVAL);
853
854 r = rtnl_message_read_internal(m, type, &attr_data);
855 if(r < 0)
856 return r;
857
858 *data = *(uint16_t *) attr_data;
859
860 return 0;
861}
862
863int sd_rtnl_message_read_u32(sd_rtnl_message *m, unsigned short type, uint32_t *data) {
864 int r;
865 void *attr_data;
866
867 assert_return(data, -EINVAL);
868
869 r = rtnl_message_read_internal(m, type, &attr_data);
870 if(r < 0)
871 return r;
872
873 *data = *(uint32_t *) attr_data;
874
875 return 0;
876}
877
4e9e7f18
SS
878int sd_rtnl_message_read_ether_addr(sd_rtnl_message *m, unsigned short type, struct ether_addr *data) {
879 int r;
880 void *attr_data;
881
882 assert_return(data, -EINVAL);
883
884 r = rtnl_message_read_internal(m, type, &attr_data);
885 if(r < 0)
886 return r;
887
888 memcpy(data, attr_data, sizeof(struct ether_addr));
889
890 return 0;
891}
892
893int sd_rtnl_message_read_in_addr(sd_rtnl_message *m, unsigned short type, struct in_addr *data) {
894 int r;
895 void *attr_data;
896
897 assert_return(data, -EINVAL);
898
899 r = rtnl_message_read_internal(m, type, &attr_data);
900 if(r < 0)
901 return r;
902
903 memcpy(data, attr_data, sizeof(struct in_addr));
904
905 return 0;
906}
907
908int sd_rtnl_message_read_in6_addr(sd_rtnl_message *m, unsigned short type, struct in6_addr *data) {
909 int r;
910 void *attr_data;
911
912 assert_return(data, -EINVAL);
913
914 r = rtnl_message_read_internal(m, type, &attr_data);
915 if(r < 0)
916 return r;
917
918 memcpy(data, attr_data, sizeof(struct in6_addr));
919
920 return 0;
921}
922
e5c4350b
TG
923int sd_rtnl_message_exit_container(sd_rtnl_message *m) {
924 assert_return(m, -EINVAL);
925 assert_return(m->sealed, -EINVAL);
926 assert_return(m->n_containers > 0, -EINVAL);
927
928 m->n_containers --;
929
930 return 0;
931}
932
3815f36f 933uint32_t rtnl_message_get_serial(sd_rtnl_message *m) {
65f568bb 934 assert(m);
9d0db178 935 assert(m->hdr);
65f568bb
TG
936
937 return m->hdr->nlmsg_seq;
938}
939
e16bcf98 940int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
65f568bb
TG
941 struct nlmsgerr *err;
942
e16bcf98 943 assert_return(m, -EINVAL);
9d0db178 944 assert_return(m->hdr, -EINVAL);
65f568bb
TG
945
946 if (m->hdr->nlmsg_type != NLMSG_ERROR)
947 return 0;
948
949 err = NLMSG_DATA(m->hdr);
950
951 return err->error;
952}
953
3815f36f 954int rtnl_message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
e5c4350b
TG
955 int r;
956
9d0db178
TG
957 assert(m);
958 assert(m->hdr);
959
65f568bb
TG
960 if (m->sealed)
961 return -EPERM;
962
e5c4350b
TG
963 if (nl)
964 m->hdr->nlmsg_seq = nl->serial++;
965
65f568bb
TG
966 m->sealed = true;
967
e5c4350b
TG
968 r = sd_rtnl_message_rewind(m);
969 if (r < 0)
970 return r;
971
65f568bb
TG
972 return 0;
973}
974
975static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
9d0db178
TG
976 assert(rtnl);
977 assert(need);
65f568bb
TG
978
979 /* ioctl(rtnl->fd, FIONREAD, &need)
dabfa9d1
TG
980 Does not appear to work on netlink sockets. libnl uses
981 MSG_PEEK instead. I don't know if that is worth the
982 extra roundtrip.
983
984 For now we simply use the maximum message size the kernel
985 may use (NLMSG_GOODSIZE), and then realloc to the actual
986 size after reading the message (hence avoiding huge memory
987 usage in case many small messages are kept around) */
988 *need = page_size();
65f568bb
TG
989 if (*need > 8192UL)
990 *need = 8192UL;
991
992 return 0;
993}
994
44caa5e7
SS
995int rtnl_message_parse(sd_rtnl_message *m,
996 size_t **rta_offset_tb,
997 unsigned short *rta_tb_size,
998 int max,
999 struct rtattr *rta,
1000 unsigned int rt_len) {
1001 int type;
1002 size_t *tb;
1003
1004 tb = (size_t *) new0(size_t *, max);
1005 if(!tb)
1006 return -ENOMEM;
1007
1008 *rta_tb_size = max;
1009
1010 for (; RTA_OK(rta, rt_len); rta = RTA_NEXT(rta, rt_len)) {
1011 type = rta->rta_type;
1012
1013 if (type < max && !tb[type])
1014 tb[type] = (uint8_t *) rta - (uint8_t *) m->hdr;
1015 }
1016
1017 *rta_offset_tb = tb;
1018
1019 return 0;
1020}
1021
65f568bb
TG
1022/* returns the number of bytes sent, or a negative error code */
1023int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
d4bbdb77
TG
1024 union {
1025 struct sockaddr sa;
1026 struct sockaddr_nl nl;
1027 } addr = {
1028 .nl.nl_family = AF_NETLINK,
1029 };
65f568bb
TG
1030 ssize_t k;
1031
9d0db178
TG
1032 assert(nl);
1033 assert(m);
1034 assert(m->hdr);
65f568bb
TG
1035
1036 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
d4bbdb77 1037 0, &addr.sa, sizeof(addr));
65f568bb
TG
1038 if (k < 0)
1039 return (errno == EAGAIN) ? 0 : -errno;
1040
1041 return k;
1042}
1043
1044/* On success, the number of bytes received is returned and *ret points to the received message
1045 * which has a valid header and the correct size.
1046 * If nothing useful was received 0 is returned.
1047 * On failure, a negative error code is returned.
dabfa9d1 1048 */
65f568bb
TG
1049int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
1050 sd_rtnl_message *m;
d4bbdb77
TG
1051 union {
1052 struct sockaddr sa;
1053 struct sockaddr_nl nl;
1054 } addr;
1055 socklen_t addr_len;
65f568bb
TG
1056 int r;
1057 ssize_t k;
1058 size_t need;
1059
9d0db178
TG
1060 assert(nl);
1061 assert(ret);
65f568bb
TG
1062
1063 r = message_receive_need(nl, &need);
1064 if (r < 0)
1065 return r;
1066
4fb7242c 1067 r = message_new(nl, &m, need);
65f568bb
TG
1068 if (r < 0)
1069 return r;
1070
e5c4350b
TG
1071 /* don't allow sealing/appending to received messages */
1072 m->sealed = true;
1073
d4bbdb77
TG
1074 addr_len = sizeof(addr);
1075
65f568bb 1076 k = recvfrom(nl->fd, m->hdr, need,
d4bbdb77 1077 0, &addr.sa, &addr_len);
65f568bb 1078 if (k < 0)
276fc066 1079 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
65f568bb
TG
1080 else if (k == 0)
1081 k = -ECONNRESET; /* connection was closed by the kernel */
d4bbdb77
TG
1082 else if (addr_len != sizeof(addr.nl) ||
1083 addr.nl.nl_family != AF_NETLINK)
65f568bb 1084 k = -EIO; /* not a netlink message */
d4bbdb77 1085 else if (addr.nl.nl_pid != 0)
65f568bb
TG
1086 k = 0; /* not from the kernel */
1087 else if ((size_t) k < sizeof(struct nlmsghdr) ||
dabfa9d1 1088 (size_t) k < m->hdr->nlmsg_len)
65f568bb 1089 k = -EIO; /* too small (we do accept too big though) */
a02113d2
TG
1090 else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
1091 k = 0; /* not broadcast and not for us */
65f568bb
TG
1092
1093 if (k > 0)
1094 switch (m->hdr->nlmsg_type) {
1095 /* check that the size matches the message type */
1096 case NLMSG_ERROR:
1097 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
1098 k = -EIO;
03d7e632 1099 break;
65f568bb 1100 case RTM_NEWLINK:
d2df0d0e 1101 case RTM_SETLINK:
65f568bb
TG
1102 case RTM_DELLINK:
1103 case RTM_GETLINK:
1104 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
1105 k = -EIO;
0fc7531b 1106 else {
bdd13f6b
ZJS
1107 struct ifinfomsg *ifi;
1108
0fc7531b 1109 ifi = NLMSG_DATA(m->hdr);
4ebe732c 1110 UPDATE_RTA(m, IFLA_RTA(ifi));
44caa5e7
SS
1111
1112 r = rtnl_message_parse(m,
1113 &m->rta_offset_tb,
1114 &m->rta_tb_size,
1115 IFLA_MAX,
1116 IFLA_RTA(ifi),
1117 IFLA_PAYLOAD(m->hdr));
1118
0fc7531b 1119 }
03d7e632 1120 break;
65f568bb
TG
1121 case RTM_NEWADDR:
1122 case RTM_DELADDR:
1123 case RTM_GETADDR:
1124 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
1125 k = -EIO;
0fc7531b 1126 else {
bdd13f6b
ZJS
1127 struct ifaddrmsg *ifa;
1128
0fc7531b 1129 ifa = NLMSG_DATA(m->hdr);
4ebe732c 1130 UPDATE_RTA(m, IFA_RTA(ifa));
44caa5e7
SS
1131
1132 r = rtnl_message_parse(m,
1133 &m->rta_offset_tb,
1134 &m->rta_tb_size,
1135 IFA_MAX,
1136 IFA_RTA(ifa),
1137 IFA_PAYLOAD(m->hdr));
0fc7531b 1138 }
03d7e632 1139 break;
3e10a9f4
TG
1140 case RTM_NEWROUTE:
1141 case RTM_DELROUTE:
1142 case RTM_GETROUTE:
1143 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg)))
1144 k = -EIO;
0fc7531b 1145 else {
bdd13f6b
ZJS
1146 struct rtmsg *rtm;
1147
0fc7531b 1148 rtm = NLMSG_DATA(m->hdr);
4ebe732c 1149 UPDATE_RTA(m, RTM_RTA(rtm));
44caa5e7
SS
1150
1151 r = rtnl_message_parse(m,
1152 &m->rta_offset_tb,
1153 &m->rta_tb_size,
1154 RTA_MAX,
1155 RTM_RTA(rtm),
1156 RTM_PAYLOAD(m->hdr));
0fc7531b 1157 }
3e10a9f4 1158 break;
65f568bb
TG
1159 case NLMSG_NOOP:
1160 k = 0;
03d7e632 1161 break;
65f568bb
TG
1162 default:
1163 k = 0; /* ignoring message of unknown type */
1164 }
1165
1166 if (k <= 0)
1167 sd_rtnl_message_unref(m);
1168 else {
1169 /* we probably allocated way too much memory, give it back */
1170 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);
1171 *ret = m;
1172 }
1173
1174 return k;
1175}
0fc7531b
TG
1176
1177int sd_rtnl_message_rewind(sd_rtnl_message *m) {
1178 struct ifinfomsg *ifi;
1179 struct ifaddrmsg *ifa;
1180 struct rtmsg *rtm;
1181
1182 assert_return(m, -EINVAL);
e5c4350b 1183 assert_return(m->sealed, -EPERM);
0fc7531b
TG
1184 assert_return(m->hdr, -EINVAL);
1185
1186 switch(m->hdr->nlmsg_type) {
1187 case RTM_NEWLINK:
1188 case RTM_SETLINK:
1189 case RTM_GETLINK:
1190 case RTM_DELLINK:
1191 ifi = NLMSG_DATA(m->hdr);
4ebe732c 1192 UPDATE_RTA(m, IFLA_RTA(ifi));
0fc7531b 1193
0fc7531b
TG
1194 break;
1195 case RTM_NEWADDR:
1196 case RTM_GETADDR:
1197 case RTM_DELADDR:
1198 ifa = NLMSG_DATA(m->hdr);
4ebe732c 1199 UPDATE_RTA(m, IFA_RTA(ifa));
0fc7531b 1200
0fc7531b
TG
1201 break;
1202 case RTM_NEWROUTE:
1203 case RTM_GETROUTE:
1204 case RTM_DELROUTE:
1205 rtm = NLMSG_DATA(m->hdr);
4ebe732c 1206 UPDATE_RTA(m, RTM_RTA(rtm));
0fc7531b 1207
0fc7531b
TG
1208 break;
1209 default:
1210 return -ENOTSUP;
1211 }
1212
e5c4350b
TG
1213 m->n_containers = 0;
1214
0fc7531b
TG
1215 return 0;
1216}