]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-rtnl/rtnl-message.c
generators: make automatic discovery generators work correctly when reloading
[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);
489e4fbb
TG
169 assert_return(nlmsg_type == RTM_NEWLINK ||
170 nlmsg_type == RTM_SETLINK || index > 0, -EINVAL);
65f568bb
TG
171 assert_return(ret, -EINVAL);
172
4fb7242c 173 r = message_new(rtnl, ret, NLMSG_SPACE(sizeof(struct ifinfomsg)));
65f568bb
TG
174 if (r < 0)
175 return r;
176
177 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
178 (*ret)->hdr->nlmsg_type = nlmsg_type;
33125ac5
TG
179 if (nlmsg_type == RTM_NEWLINK)
180 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE;
65f568bb 181
dabfa9d1 182 ifi = NLMSG_DATA((*ret)->hdr);
65f568bb
TG
183
184 ifi->ifi_family = AF_UNSPEC;
185 ifi->ifi_index = index;
65f568bb 186
4ebe732c 187 UPDATE_RTA(*ret, IFLA_RTA(ifi));
0fc7531b 188
65f568bb
TG
189 return 0;
190}
191
5a723174
TG
192int sd_rtnl_message_addr_set_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
193 struct ifaddrmsg *ifa;
194
195 assert_return(m, -EINVAL);
196 assert_return(m->hdr, -EINVAL);
3815f36f 197 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
5a723174
TG
198
199 ifa = NLMSG_DATA(m->hdr);
200
201 if ((ifa->ifa_family == AF_INET && prefixlen > 32) ||
202 (ifa->ifa_family == AF_INET6 && prefixlen > 128))
203 return -ERANGE;
204
205 ifa->ifa_prefixlen = prefixlen;
206
207 return 0;
208}
209
210int sd_rtnl_message_addr_set_flags(sd_rtnl_message *m, unsigned char flags) {
211 struct ifaddrmsg *ifa;
212
213 assert_return(m, -EINVAL);
214 assert_return(m->hdr, -EINVAL);
3815f36f 215 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
5a723174
TG
216
217 ifa = NLMSG_DATA(m->hdr);
218
219 ifa->ifa_flags = flags;
220
221 return 0;
222}
223
224int sd_rtnl_message_addr_set_scope(sd_rtnl_message *m, unsigned char scope) {
225 struct ifaddrmsg *ifa;
226
227 assert_return(m, -EINVAL);
228 assert_return(m->hdr, -EINVAL);
3815f36f 229 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
5a723174
TG
230
231 ifa = NLMSG_DATA(m->hdr);
232
233 ifa->ifa_scope = scope;
234
235 return 0;
236}
237
151b9b96
LP
238int sd_rtnl_message_new_addr(sd_rtnl *rtnl, sd_rtnl_message **ret,
239 uint16_t nlmsg_type, int index,
240 unsigned char family) {
65f568bb
TG
241 struct ifaddrmsg *ifa;
242 int r;
243
3815f36f 244 assert_return(rtnl_message_type_is_addr(nlmsg_type), -EINVAL);
65f568bb 245 assert_return(index > 0, -EINVAL);
5a723174 246 assert_return(family == AF_INET || family == AF_INET6, -EINVAL);
65f568bb
TG
247 assert_return(ret, -EINVAL);
248
4fb7242c 249 r = message_new(rtnl, ret, NLMSG_SPACE(sizeof(struct ifaddrmsg)));
65f568bb
TG
250 if (r < 0)
251 return r;
252
253 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
254 (*ret)->hdr->nlmsg_type = nlmsg_type;
818dc5e7
TG
255 if (nlmsg_type == RTM_GETADDR && family == AF_INET)
256 (*ret)->hdr->nlmsg_flags |= NLM_F_DUMP;
65f568bb 257
dabfa9d1 258 ifa = NLMSG_DATA((*ret)->hdr);
65f568bb 259
65f568bb 260 ifa->ifa_index = index;
5a723174
TG
261 ifa->ifa_family = family;
262 if (family == AF_INET)
263 ifa->ifa_prefixlen = 32;
264 else if (family == AF_INET6)
265 ifa->ifa_prefixlen = 128;
65f568bb 266
4ebe732c 267 UPDATE_RTA(*ret, IFA_RTA(ifa));
0fc7531b 268
65f568bb
TG
269 return 0;
270}
271
272sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
273 if (m)
274 assert_se(REFCNT_INC(m->n_ref) >= 2);
275
276 return m;
277}
278
279sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
280 if (m && REFCNT_DEC(m->n_ref) <= 0) {
4fb7242c 281 sd_rtnl_unref(m->rtnl);
65f568bb
TG
282 free(m->hdr);
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
e5c4350b
TG
803int sd_rtnl_message_exit_container(sd_rtnl_message *m) {
804 assert_return(m, -EINVAL);
805 assert_return(m->sealed, -EINVAL);
806 assert_return(m->n_containers > 0, -EINVAL);
807
808 m->n_containers --;
809
810 return 0;
811}
812
3815f36f 813uint32_t rtnl_message_get_serial(sd_rtnl_message *m) {
65f568bb 814 assert(m);
9d0db178 815 assert(m->hdr);
65f568bb
TG
816
817 return m->hdr->nlmsg_seq;
818}
819
e16bcf98 820int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
65f568bb
TG
821 struct nlmsgerr *err;
822
e16bcf98 823 assert_return(m, -EINVAL);
9d0db178 824 assert_return(m->hdr, -EINVAL);
65f568bb
TG
825
826 if (m->hdr->nlmsg_type != NLMSG_ERROR)
827 return 0;
828
829 err = NLMSG_DATA(m->hdr);
830
831 return err->error;
832}
833
3815f36f 834int rtnl_message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
e5c4350b
TG
835 int r;
836
9d0db178
TG
837 assert(m);
838 assert(m->hdr);
839
65f568bb
TG
840 if (m->sealed)
841 return -EPERM;
842
e5c4350b
TG
843 if (nl)
844 m->hdr->nlmsg_seq = nl->serial++;
845
65f568bb
TG
846 m->sealed = true;
847
e5c4350b
TG
848 r = sd_rtnl_message_rewind(m);
849 if (r < 0)
850 return r;
851
65f568bb
TG
852 return 0;
853}
854
855static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
9d0db178
TG
856 assert(rtnl);
857 assert(need);
65f568bb
TG
858
859 /* ioctl(rtnl->fd, FIONREAD, &need)
dabfa9d1
TG
860 Does not appear to work on netlink sockets. libnl uses
861 MSG_PEEK instead. I don't know if that is worth the
862 extra roundtrip.
863
864 For now we simply use the maximum message size the kernel
865 may use (NLMSG_GOODSIZE), and then realloc to the actual
866 size after reading the message (hence avoiding huge memory
867 usage in case many small messages are kept around) */
868 *need = page_size();
65f568bb
TG
869 if (*need > 8192UL)
870 *need = 8192UL;
871
872 return 0;
873}
874
875/* returns the number of bytes sent, or a negative error code */
876int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
d4bbdb77
TG
877 union {
878 struct sockaddr sa;
879 struct sockaddr_nl nl;
880 } addr = {
881 .nl.nl_family = AF_NETLINK,
882 };
65f568bb
TG
883 ssize_t k;
884
9d0db178
TG
885 assert(nl);
886 assert(m);
887 assert(m->hdr);
65f568bb
TG
888
889 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
d4bbdb77 890 0, &addr.sa, sizeof(addr));
65f568bb
TG
891 if (k < 0)
892 return (errno == EAGAIN) ? 0 : -errno;
893
894 return k;
895}
896
897/* On success, the number of bytes received is returned and *ret points to the received message
898 * which has a valid header and the correct size.
899 * If nothing useful was received 0 is returned.
900 * On failure, a negative error code is returned.
dabfa9d1 901 */
65f568bb
TG
902int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
903 sd_rtnl_message *m;
d4bbdb77
TG
904 union {
905 struct sockaddr sa;
906 struct sockaddr_nl nl;
907 } addr;
908 socklen_t addr_len;
65f568bb
TG
909 int r;
910 ssize_t k;
911 size_t need;
912
9d0db178
TG
913 assert(nl);
914 assert(ret);
65f568bb
TG
915
916 r = message_receive_need(nl, &need);
917 if (r < 0)
918 return r;
919
4fb7242c 920 r = message_new(nl, &m, need);
65f568bb
TG
921 if (r < 0)
922 return r;
923
e5c4350b
TG
924 /* don't allow sealing/appending to received messages */
925 m->sealed = true;
926
d4bbdb77
TG
927 addr_len = sizeof(addr);
928
65f568bb 929 k = recvfrom(nl->fd, m->hdr, need,
d4bbdb77 930 0, &addr.sa, &addr_len);
65f568bb 931 if (k < 0)
276fc066 932 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
65f568bb
TG
933 else if (k == 0)
934 k = -ECONNRESET; /* connection was closed by the kernel */
d4bbdb77
TG
935 else if (addr_len != sizeof(addr.nl) ||
936 addr.nl.nl_family != AF_NETLINK)
65f568bb 937 k = -EIO; /* not a netlink message */
d4bbdb77 938 else if (addr.nl.nl_pid != 0)
65f568bb
TG
939 k = 0; /* not from the kernel */
940 else if ((size_t) k < sizeof(struct nlmsghdr) ||
dabfa9d1 941 (size_t) k < m->hdr->nlmsg_len)
65f568bb 942 k = -EIO; /* too small (we do accept too big though) */
a02113d2
TG
943 else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
944 k = 0; /* not broadcast and not for us */
65f568bb
TG
945
946 if (k > 0)
947 switch (m->hdr->nlmsg_type) {
948 /* check that the size matches the message type */
949 case NLMSG_ERROR:
950 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
951 k = -EIO;
03d7e632 952 break;
65f568bb 953 case RTM_NEWLINK:
d2df0d0e 954 case RTM_SETLINK:
65f568bb
TG
955 case RTM_DELLINK:
956 case RTM_GETLINK:
957 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
958 k = -EIO;
0fc7531b 959 else {
bdd13f6b
ZJS
960 struct ifinfomsg *ifi;
961
0fc7531b 962 ifi = NLMSG_DATA(m->hdr);
4ebe732c 963 UPDATE_RTA(m, IFLA_RTA(ifi));
0fc7531b 964 }
03d7e632 965 break;
65f568bb
TG
966 case RTM_NEWADDR:
967 case RTM_DELADDR:
968 case RTM_GETADDR:
969 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
970 k = -EIO;
0fc7531b 971 else {
bdd13f6b
ZJS
972 struct ifaddrmsg *ifa;
973
0fc7531b 974 ifa = NLMSG_DATA(m->hdr);
4ebe732c 975 UPDATE_RTA(m, IFA_RTA(ifa));
0fc7531b 976 }
03d7e632 977 break;
3e10a9f4
TG
978 case RTM_NEWROUTE:
979 case RTM_DELROUTE:
980 case RTM_GETROUTE:
981 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg)))
982 k = -EIO;
0fc7531b 983 else {
bdd13f6b
ZJS
984 struct rtmsg *rtm;
985
0fc7531b 986 rtm = NLMSG_DATA(m->hdr);
4ebe732c 987 UPDATE_RTA(m, RTM_RTA(rtm));
0fc7531b 988 }
3e10a9f4 989 break;
65f568bb
TG
990 case NLMSG_NOOP:
991 k = 0;
03d7e632 992 break;
65f568bb
TG
993 default:
994 k = 0; /* ignoring message of unknown type */
995 }
996
997 if (k <= 0)
998 sd_rtnl_message_unref(m);
999 else {
1000 /* we probably allocated way too much memory, give it back */
1001 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);
1002 *ret = m;
1003 }
1004
1005 return k;
1006}
0fc7531b
TG
1007
1008int sd_rtnl_message_rewind(sd_rtnl_message *m) {
1009 struct ifinfomsg *ifi;
1010 struct ifaddrmsg *ifa;
1011 struct rtmsg *rtm;
1012
1013 assert_return(m, -EINVAL);
e5c4350b 1014 assert_return(m->sealed, -EPERM);
0fc7531b
TG
1015 assert_return(m->hdr, -EINVAL);
1016
1017 switch(m->hdr->nlmsg_type) {
1018 case RTM_NEWLINK:
1019 case RTM_SETLINK:
1020 case RTM_GETLINK:
1021 case RTM_DELLINK:
1022 ifi = NLMSG_DATA(m->hdr);
4ebe732c 1023 UPDATE_RTA(m, IFLA_RTA(ifi));
0fc7531b 1024
0fc7531b
TG
1025 break;
1026 case RTM_NEWADDR:
1027 case RTM_GETADDR:
1028 case RTM_DELADDR:
1029 ifa = NLMSG_DATA(m->hdr);
4ebe732c 1030 UPDATE_RTA(m, IFA_RTA(ifa));
0fc7531b 1031
0fc7531b
TG
1032 break;
1033 case RTM_NEWROUTE:
1034 case RTM_GETROUTE:
1035 case RTM_DELROUTE:
1036 rtm = NLMSG_DATA(m->hdr);
4ebe732c 1037 UPDATE_RTA(m, RTM_RTA(rtm));
0fc7531b 1038
0fc7531b
TG
1039 break;
1040 default:
1041 return -ENOTSUP;
1042 }
1043
e5c4350b
TG
1044 m->n_containers = 0;
1045
0fc7531b
TG
1046 return 0;
1047}