]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-rtnl/rtnl-message.c
nspawn: various fixes in selinux hookup
[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
a33dece5 22#include <linux/rtnetlink.h>
65f568bb
TG
23#include <netinet/in.h>
24#include <netinet/ether.h>
25#include <stdbool.h>
26#include <unistd.h>
27
28#include "util.h"
29#include "refcnt.h"
30
31#include "sd-rtnl.h"
3815f36f 32#include "rtnl-util.h"
65f568bb
TG
33#include "rtnl-internal.h"
34
5a081409 35#define GET_CONTAINER(m, i) (i < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->container_offsets[i]) : NULL)
4ebe732c
ZJS
36#define NEXT_RTA(m) ((struct rtattr*)((uint8_t*)(m)->hdr + (m)->next_rta_offset))
37#define UPDATE_RTA(m, new) (m)->next_rta_offset = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
e5c4350b 38#define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers ++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
4ebe732c 39
3815f36f 40int message_new(sd_rtnl_message **ret, size_t initial_size) {
65f568bb
TG
41 sd_rtnl_message *m;
42
43 assert_return(ret, -EINVAL);
dabfa9d1 44 assert_return(initial_size >= sizeof(struct nlmsghdr), -EINVAL);
65f568bb
TG
45
46 m = new0(sd_rtnl_message, 1);
47 if (!m)
48 return -ENOMEM;
49
dc7d8997 50 m->hdr = malloc0(initial_size);
65f568bb
TG
51 if (!m->hdr) {
52 free(m);
53 return -ENOMEM;
54 }
55
56 m->n_ref = REFCNT_INIT;
57
58 m->hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
59 m->sealed = false;
60
61 *ret = m;
62
63 return 0;
64}
65
1f01fb4f
TG
66int sd_rtnl_message_route_set_dst_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
67 struct rtmsg *rtm;
68
5a723174
TG
69 assert_return(m, -EINVAL);
70 assert_return(m->hdr, -EINVAL);
3815f36f 71 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
5a723174 72
1f01fb4f
TG
73 rtm = NLMSG_DATA(m->hdr);
74
5a723174
TG
75 if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
76 (rtm->rtm_family == AF_INET6 && prefixlen > 128))
77 return -ERANGE;
78
1f01fb4f
TG
79 rtm->rtm_dst_len = prefixlen;
80
81 return 0;
82}
83
03d7e632 84int sd_rtnl_message_route_new(uint16_t nlmsg_type, unsigned char rtm_family,
1f01fb4f 85 sd_rtnl_message **ret) {
03d7e632
TG
86 struct rtmsg *rtm;
87 int r;
88
3815f36f 89 assert_return(rtnl_message_type_is_route(nlmsg_type), -EINVAL);
1f01fb4f 90 assert_return(rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
03d7e632
TG
91 assert_return(ret, -EINVAL);
92
93 r = message_new(ret, NLMSG_SPACE(sizeof(struct rtmsg)));
94 if (r < 0)
95 return r;
96
97 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
98 (*ret)->hdr->nlmsg_type = nlmsg_type;
99 if (nlmsg_type == RTM_NEWROUTE)
100 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
101
102 rtm = NLMSG_DATA((*ret)->hdr);
103
4ebe732c 104 UPDATE_RTA(*ret, RTM_RTA(rtm));
0fc7531b 105
03d7e632 106 rtm->rtm_family = rtm_family;
1f01fb4f
TG
107 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
108 rtm->rtm_type = RTN_UNICAST;
109 rtm->rtm_table = RT_TABLE_MAIN;
110 rtm->rtm_protocol = RTPROT_BOOT;
03d7e632
TG
111
112 return 0;
113}
114
5d4795f3 115int sd_rtnl_message_link_set_flags(sd_rtnl_message *m, unsigned flags, unsigned change) {
fc25d7f8
TG
116 struct ifinfomsg *ifi;
117
5a723174
TG
118 assert_return(m, -EINVAL);
119 assert_return(m->hdr, -EINVAL);
3815f36f 120 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
5a723174 121
fc25d7f8
TG
122 ifi = NLMSG_DATA(m->hdr);
123
124 ifi->ifi_flags = flags;
5d4795f3
TG
125 if (change)
126 ifi->ifi_change = change;
127 else
128 ifi->ifi_change = 0xffffffff;
fc25d7f8
TG
129
130 return 0;
131}
132
133int sd_rtnl_message_link_set_type(sd_rtnl_message *m, unsigned type) {
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);
5a723174 139
fc25d7f8
TG
140 ifi = NLMSG_DATA(m->hdr);
141
142 ifi->ifi_type = type;
143
144 return 0;
145}
146
147int sd_rtnl_message_link_new(uint16_t nlmsg_type, int index, sd_rtnl_message **ret) {
65f568bb
TG
148 struct ifinfomsg *ifi;
149 int r;
150
3815f36f 151 assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL);
33125ac5 152 assert_return(nlmsg_type == RTM_NEWLINK || index > 0, -EINVAL);
65f568bb
TG
153 assert_return(ret, -EINVAL);
154
155 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifinfomsg)));
156 if (r < 0)
157 return r;
158
159 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
160 (*ret)->hdr->nlmsg_type = nlmsg_type;
33125ac5
TG
161 if (nlmsg_type == RTM_NEWLINK)
162 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE;
65f568bb 163
dabfa9d1 164 ifi = NLMSG_DATA((*ret)->hdr);
65f568bb
TG
165
166 ifi->ifi_family = AF_UNSPEC;
167 ifi->ifi_index = index;
65f568bb 168
4ebe732c 169 UPDATE_RTA(*ret, IFLA_RTA(ifi));
0fc7531b 170
65f568bb
TG
171 return 0;
172}
173
5a723174
TG
174int sd_rtnl_message_addr_set_prefixlen(sd_rtnl_message *m, unsigned char prefixlen) {
175 struct ifaddrmsg *ifa;
176
177 assert_return(m, -EINVAL);
178 assert_return(m->hdr, -EINVAL);
3815f36f 179 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
5a723174
TG
180
181 ifa = NLMSG_DATA(m->hdr);
182
183 if ((ifa->ifa_family == AF_INET && prefixlen > 32) ||
184 (ifa->ifa_family == AF_INET6 && prefixlen > 128))
185 return -ERANGE;
186
187 ifa->ifa_prefixlen = prefixlen;
188
189 return 0;
190}
191
192int sd_rtnl_message_addr_set_flags(sd_rtnl_message *m, unsigned char flags) {
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 ifa->ifa_flags = flags;
202
203 return 0;
204}
205
206int sd_rtnl_message_addr_set_scope(sd_rtnl_message *m, unsigned char scope) {
207 struct ifaddrmsg *ifa;
208
209 assert_return(m, -EINVAL);
210 assert_return(m->hdr, -EINVAL);
3815f36f 211 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
5a723174
TG
212
213 ifa = NLMSG_DATA(m->hdr);
214
215 ifa->ifa_scope = scope;
216
217 return 0;
218}
219
220int sd_rtnl_message_addr_new(uint16_t nlmsg_type, int index, unsigned char family,
221 sd_rtnl_message **ret) {
65f568bb
TG
222 struct ifaddrmsg *ifa;
223 int r;
224
3815f36f 225 assert_return(rtnl_message_type_is_addr(nlmsg_type), -EINVAL);
65f568bb 226 assert_return(index > 0, -EINVAL);
5a723174 227 assert_return(family == AF_INET || family == AF_INET6, -EINVAL);
65f568bb
TG
228 assert_return(ret, -EINVAL);
229
230 r = message_new(ret, NLMSG_SPACE(sizeof(struct ifaddrmsg)));
231 if (r < 0)
232 return r;
233
234 (*ret)->hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
235 (*ret)->hdr->nlmsg_type = nlmsg_type;
236
dabfa9d1 237 ifa = NLMSG_DATA((*ret)->hdr);
65f568bb 238
65f568bb 239 ifa->ifa_index = index;
5a723174
TG
240 ifa->ifa_family = family;
241 if (family == AF_INET)
242 ifa->ifa_prefixlen = 32;
243 else if (family == AF_INET6)
244 ifa->ifa_prefixlen = 128;
65f568bb 245
4ebe732c 246 UPDATE_RTA(*ret, IFA_RTA(ifa));
0fc7531b 247
65f568bb
TG
248 return 0;
249}
250
251sd_rtnl_message *sd_rtnl_message_ref(sd_rtnl_message *m) {
252 if (m)
253 assert_se(REFCNT_INC(m->n_ref) >= 2);
254
255 return m;
256}
257
258sd_rtnl_message *sd_rtnl_message_unref(sd_rtnl_message *m) {
259 if (m && REFCNT_DEC(m->n_ref) <= 0) {
260 free(m->hdr);
261 free(m);
262 }
263
264 return NULL;
265}
266
dabfa9d1 267int sd_rtnl_message_get_type(sd_rtnl_message *m, uint16_t *type) {
65f568bb
TG
268 assert_return(m, -EINVAL);
269 assert_return(type, -EINVAL);
270
271 *type = m->hdr->nlmsg_type;
272
273 return 0;
274}
275
33125ac5
TG
276int sd_rtnl_message_link_get_ifindex(sd_rtnl_message *m, int *ifindex) {
277 struct ifinfomsg *ifi;
278
279 assert_return(m, -EINVAL);
9d0db178 280 assert_return(m->hdr, -EINVAL);
3815f36f 281 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
33125ac5 282 assert_return(ifindex, -EINVAL);
33125ac5
TG
283
284 ifi = NLMSG_DATA(m->hdr);
285
286 *ifindex = ifi->ifi_index;
287
288 return 0;
289}
290
50b3c42f
TG
291int sd_rtnl_message_link_get_flags(sd_rtnl_message *m, unsigned *flags) {
292 struct ifinfomsg *ifi;
293
294 assert_return(m, -EINVAL);
9d0db178 295 assert_return(m->hdr, -EINVAL);
3815f36f 296 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
50b3c42f 297 assert_return(flags, -EINVAL);
50b3c42f
TG
298
299 ifi = NLMSG_DATA(m->hdr);
300
301 *flags = ifi->ifi_flags;
302
303 return 0;
304}
305
4ebe732c
ZJS
306/* If successful the updated message will be correctly aligned, if
307 unsuccessful the old message is untouched. */
65f568bb 308static int add_rtattr(sd_rtnl_message *m, unsigned short type, const void *data, size_t data_length) {
dabfa9d1 309 uint32_t rta_length, message_length;
65f568bb
TG
310 struct nlmsghdr *new_hdr;
311 struct rtattr *rta;
8e337e64 312 char *padding;
5a081409 313 unsigned i;
65f568bb 314
33125ac5
TG
315 assert(m);
316 assert(m->hdr);
e5c4350b 317 assert(!m->sealed);
33125ac5
TG
318 assert(NLMSG_ALIGN(m->hdr->nlmsg_len) == m->hdr->nlmsg_len);
319 assert(!data || data_length > 0);
5a081409 320 assert(data || m->n_containers < RTNL_CONTAINER_DEPTH);
65f568bb 321
8e337e64 322 /* get the size of the new rta attribute (with padding at the end) */
65f568bb 323 rta_length = RTA_LENGTH(data_length);
4ebe732c
ZJS
324
325 /* get the new message size (with padding at the end) */
65f568bb
TG
326 message_length = m->hdr->nlmsg_len + RTA_ALIGN(rta_length);
327
328 /* realloc to fit the new attribute */
329 new_hdr = realloc(m->hdr, message_length);
330 if (!new_hdr)
331 return -ENOMEM;
332 m->hdr = new_hdr;
333
334 /* get pointer to the attribute we are about to add */
335 rta = (struct rtattr *) ((uint8_t *) m->hdr + m->hdr->nlmsg_len);
65f568bb 336
5a081409
TG
337 /* if we are inside containers, extend them */
338 for (i = 0; i < m->n_containers; i++)
339 GET_CONTAINER(m, i)->rta_len += message_length - m->hdr->nlmsg_len;
33125ac5 340
65f568bb
TG
341 /* fill in the attribute */
342 rta->rta_type = type;
343 rta->rta_len = rta_length;
33125ac5 344 if (!data) {
4ebe732c 345 /* this is the start of a new container */
5a081409 346 m->container_offsets[m->n_containers ++] = m->hdr->nlmsg_len;
33125ac5
TG
347 } else {
348 /* we don't deal with the case where the user lies about the type
349 * and gives us too little data (so don't do that)
350 */
351 padding = mempcpy(RTA_DATA(rta), data, data_length);
352 /* make sure also the padding at the end of the message is initialized */
4ebe732c
ZJS
353 memzero(padding,
354 (uint8_t *) m->hdr + message_length - (uint8_t *) padding);
33125ac5 355 }
65f568bb 356
4ebe732c
ZJS
357 /* update message size */
358 m->hdr->nlmsg_len = message_length;
359
65f568bb
TG
360 return 0;
361}
362
0a0dc69b 363int sd_rtnl_message_append_string(sd_rtnl_message *m, unsigned short type, const char *data) {
dabfa9d1 364 uint16_t rtm_type;
0a0dc69b 365 int r;
65f568bb
TG
366
367 assert_return(m, -EINVAL);
e5c4350b 368 assert_return(!m->sealed, -EPERM);
65f568bb
TG
369 assert_return(data, -EINVAL);
370
0a0dc69b
TG
371 r = sd_rtnl_message_get_type(m, &rtm_type);
372 if (r < 0)
373 return r;
65f568bb 374
0a0dc69b
TG
375 /* check that the type is correct */
376 switch (rtm_type) {
377 case RTM_NEWLINK:
378 case RTM_SETLINK:
379 case RTM_GETLINK:
380 case RTM_DELLINK:
5a081409
TG
381 if (m->n_containers == 1) {
382 if (GET_CONTAINER(m, 0)->rta_type != IFLA_LINKINFO ||
0a0dc69b
TG
383 type != IFLA_INFO_KIND)
384 return -ENOTSUP;
385 } else {
386 switch (type) {
387 case IFLA_IFNAME:
388 case IFLA_IFALIAS:
389 case IFLA_QDISC:
390 break;
33125ac5
TG
391 default:
392 return -ENOTSUP;
393 }
0a0dc69b
TG
394 }
395 break;
396 case RTM_NEWADDR:
397 case RTM_GETADDR:
398 case RTM_DELADDR:
399 if (type != IFA_LABEL)
33125ac5 400 return -ENOTSUP;
0a0dc69b
TG
401 break;
402 default:
403 return -ENOTSUP;
33125ac5
TG
404 }
405
0a0dc69b
TG
406 r = add_rtattr(m, type, data, strlen(data) + 1);
407 if (r < 0)
408 return r;
409
410 return 0;
411}
412
01b36069
TG
413int sd_rtnl_message_append_u16(sd_rtnl_message *m, unsigned short type, uint16_t data) {
414 uint16_t rtm_type;
415 int r;
416
417 assert_return(m, -EINVAL);
e5c4350b 418 assert_return(!m->sealed, -EPERM);
01b36069
TG
419
420 r = sd_rtnl_message_get_type(m, &rtm_type);
421 if (r < 0)
422 return r;
423
424 /* check that the type is correct */
425 switch (rtm_type) {
426 case RTM_NEWLINK:
427 case RTM_SETLINK:
428 case RTM_GETLINK:
429 case RTM_DELLINK:
5a081409
TG
430 if (m->n_containers == 2 &&
431 GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO &&
432 GET_CONTAINER(m, 1)->rta_type == IFLA_INFO_DATA &&
433 type == IFLA_VLAN_ID)
434 break;
435 else
436 return -ENOTSUP;
01b36069
TG
437 break;
438 default:
439 return -ENOTSUP;
440 }
441
442 r = add_rtattr(m, type, &data, sizeof(uint16_t));
443 if (r < 0)
444 return r;
445
446 return 0;
447}
448
0a0dc69b
TG
449int sd_rtnl_message_append_u32(sd_rtnl_message *m, unsigned short type, uint32_t data) {
450 uint16_t rtm_type;
451 int r;
452
453 assert_return(m, -EINVAL);
e5c4350b 454 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
455
456 r = sd_rtnl_message_get_type(m, &rtm_type);
457 if (r < 0)
458 return r;
459
460 /* check that the type is correct */
65f568bb
TG
461 switch (rtm_type) {
462 case RTM_NEWLINK:
d2df0d0e 463 case RTM_SETLINK:
65f568bb 464 case RTM_GETLINK:
0a0dc69b 465 case RTM_DELLINK:
65f568bb 466 switch (type) {
46fabae6 467 case IFLA_MASTER:
65f568bb 468 case IFLA_MTU:
65f568bb 469 case IFLA_LINK:
0a0dc69b 470 break;
65f568bb
TG
471 default:
472 return -ENOTSUP;
473 }
0a0dc69b
TG
474 break;
475 case RTM_NEWROUTE:
476 case RTM_GETROUTE:
477 case RTM_DELROUTE:
478 switch (type) {
479 case RTA_TABLE:
480 case RTA_PRIORITY:
481 case RTA_IIF:
482 case RTA_OIF:
483 break;
484 default:
485 return -ENOTSUP;
486 }
487 break;
488 default:
489 return -ENOTSUP;
490 }
491
4d47756b 492 r = add_rtattr(m, type, &data, sizeof(uint32_t));
0a0dc69b
TG
493 if (r < 0)
494 return r;
495
496 return 0;
497}
498
499int sd_rtnl_message_append_in_addr(sd_rtnl_message *m, unsigned short type, const struct in_addr *data) {
500 struct ifaddrmsg *ifa;
501 struct rtmsg *rtm;
502 uint16_t rtm_type;
503 int r;
504
505 assert_return(m, -EINVAL);
e5c4350b 506 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
507 assert_return(data, -EINVAL);
508
509 r = sd_rtnl_message_get_type(m, &rtm_type);
510 if (r < 0)
511 return r;
512
513 /* check that the type is correct */
514 switch (rtm_type) {
65f568bb 515 case RTM_NEWADDR:
65f568bb 516 case RTM_GETADDR:
0a0dc69b 517 case RTM_DELADDR:
65f568bb 518 switch (type) {
65f568bb
TG
519 case IFA_ADDRESS:
520 case IFA_LOCAL:
521 case IFA_BROADCAST:
522 case IFA_ANYCAST:
523 ifa = NLMSG_DATA(m->hdr);
0a0dc69b
TG
524
525 if (ifa->ifa_family != AF_INET)
526 return -EINVAL;
527
528 break;
65f568bb
TG
529 default:
530 return -ENOTSUP;
531 }
0a0dc69b 532 break;
03d7e632 533 case RTM_NEWROUTE:
0a0dc69b 534 case RTM_GETROUTE:
03d7e632 535 case RTM_DELROUTE:
0a0dc69b
TG
536 switch (type) {
537 case RTA_DST:
538 case RTA_SRC:
539 case RTA_GATEWAY:
540 rtm = NLMSG_DATA(m->hdr);
541
542 if (rtm->rtm_family != AF_INET)
543 return -EINVAL;
544
545 break;
546 default:
547 return -ENOTSUP;
548 }
549 break;
550 default:
551 return -ENOTSUP;
552 }
553
4d47756b 554 r = add_rtattr(m, type, data, sizeof(struct in_addr));
0a0dc69b
TG
555 if (r < 0)
556 return r;
557
558 return 0;
559}
560
561int sd_rtnl_message_append_in6_addr(sd_rtnl_message *m, unsigned short type, const struct in6_addr *data) {
562 struct ifaddrmsg *ifa;
563 struct rtmsg *rtm;
564 uint16_t rtm_type;
565 int r;
566
567 assert_return(m, -EINVAL);
e5c4350b 568 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
569 assert_return(data, -EINVAL);
570
571 r = sd_rtnl_message_get_type(m, &rtm_type);
572 if (r < 0)
573 return r;
574
575 /* check that the type is correct */
576 switch (rtm_type) {
577 case RTM_NEWADDR:
578 case RTM_GETADDR:
579 case RTM_DELADDR:
580 switch (type) {
581 case IFA_ADDRESS:
582 case IFA_LOCAL:
583 case IFA_BROADCAST:
584 case IFA_ANYCAST:
585 ifa = NLMSG_DATA(m->hdr);
586
587 if (ifa->ifa_family != AF_INET6)
588 return -EINVAL;
589
590 break;
591 default:
592 return -ENOTSUP;
593 }
594 break;
595 case RTM_NEWROUTE:
03d7e632 596 case RTM_GETROUTE:
0a0dc69b 597 case RTM_DELROUTE:
03d7e632
TG
598 switch (type) {
599 case RTA_DST:
600 case RTA_SRC:
601 case RTA_GATEWAY:
602 rtm = NLMSG_DATA(m->hdr);
0a0dc69b
TG
603
604 if (rtm->rtm_family != AF_INET6)
605 return -EINVAL;
606
607 break;
608 default:
609 return -ENOTSUP;
610 }
611 default:
612 return -ENOTSUP;
613 }
614
4d47756b 615 r = add_rtattr(m, type, data, sizeof(struct in6_addr));
0a0dc69b
TG
616 if (r < 0)
617 return r;
618
619 return 0;
620}
621
622int sd_rtnl_message_append_ether_addr(sd_rtnl_message *m, unsigned short type, const struct ether_addr *data) {
623 uint16_t rtm_type;
624 int r;
625
626 assert_return(m, -EINVAL);
e5c4350b 627 assert_return(!m->sealed, -EPERM);
0a0dc69b
TG
628 assert_return(data, -EINVAL);
629
630 sd_rtnl_message_get_type(m, &rtm_type);
631
632 switch (rtm_type) {
633 case RTM_NEWLINK:
634 case RTM_SETLINK:
635 case RTM_DELLINK:
636 case RTM_GETLINK:
637 switch (type) {
638 case IFLA_ADDRESS:
639 case IFLA_BROADCAST:
640 break;
03d7e632
TG
641 default:
642 return -ENOTSUP;
643 }
0a0dc69b 644 break;
65f568bb
TG
645 default:
646 return -ENOTSUP;
647 }
0a0dc69b 648
b9eaf3d1 649 r = add_rtattr(m, type, data, ETH_ALEN);
0a0dc69b
TG
650 if (r < 0)
651 return r;
652
653 return 0;
65f568bb
TG
654}
655
33125ac5
TG
656int sd_rtnl_message_open_container(sd_rtnl_message *m, unsigned short type) {
657 uint16_t rtm_type;
658
65f568bb 659 assert_return(m, -EINVAL);
e5c4350b 660 assert_return(!m->sealed, -EPERM);
33125ac5
TG
661
662 sd_rtnl_message_get_type(m, &rtm_type);
663
3815f36f 664 if (rtnl_message_type_is_link(rtm_type)) {
5a081409
TG
665 if ((type == IFLA_LINKINFO && m->n_containers == 0) ||
666 (type == IFLA_INFO_DATA && m->n_containers == 1 &&
667 GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO))
9d0db178
TG
668 return add_rtattr(m, type, NULL, 0);
669 else
33125ac5 670 return -ENOTSUP;
9d0db178
TG
671 } else
672 return -ENOTSUP;
33125ac5
TG
673
674 return 0;
675}
676
677int sd_rtnl_message_close_container(sd_rtnl_message *m) {
678 assert_return(m, -EINVAL);
e5c4350b 679 assert_return(!m->sealed, -EPERM);
5a081409 680 assert_return(m->n_containers > 0, -EINVAL);
33125ac5 681
5a081409 682 m->n_containers --;
33125ac5
TG
683
684 return 0;
685}
686
0fc7531b
TG
687int sd_rtnl_message_read(sd_rtnl_message *m, unsigned short *type, void **data) {
688 size_t remaining_size;
33125ac5
TG
689 uint16_t rtm_type;
690 int r;
691
e5c4350b
TG
692 assert_return(m, -EINVAL);
693 assert_return(m->sealed, -EPERM);
694 assert_return(m->next_rta_offset, -EINVAL);
695 assert_return(type, -EINVAL);
696 assert_return(data, -EINVAL);
65f568bb 697
e5c4350b
TG
698 /* only read until the end of the current container */
699 if (m->n_containers)
700 remaining_size = GET_CONTAINER(m, m->n_containers - 1)->rta_len -
701 (m->next_rta_offset -
702 m->container_offsets[m->n_containers - 1]);
703 else
704 remaining_size = m->hdr->nlmsg_len - m->next_rta_offset;
0fc7531b 705
4ebe732c 706 if (!RTA_OK(NEXT_RTA(m), remaining_size))
65f568bb
TG
707 return 0;
708
e5c4350b 709 /* if we read a container, enter it and return its type */
33125ac5
TG
710 r = sd_rtnl_message_get_type(m, &rtm_type);
711 if (r < 0)
712 return r;
713
4ebe732c 714 *type = NEXT_RTA(m)->rta_type;
65f568bb 715
3815f36f 716 if (rtnl_message_type_is_link(rtm_type) &&
e5c4350b
TG
717 ((m->n_containers == 0 &&
718 NEXT_RTA(m)->rta_type == IFLA_LINKINFO) ||
719 (m->n_containers == 1 &&
720 GET_CONTAINER(m, 0)->rta_type == IFLA_LINKINFO &&
721 NEXT_RTA(m)->rta_type == IFLA_INFO_DATA))) {
722 *data = NULL;
723 PUSH_CONTAINER(m, NEXT_RTA(m));
724 UPDATE_RTA(m, RTA_DATA(NEXT_RTA(m)));
725 } else {
726 *data = RTA_DATA(NEXT_RTA(m));
727 UPDATE_RTA(m, RTA_NEXT(NEXT_RTA(m), remaining_size));
728 }
65f568bb
TG
729
730 return 1;
731}
732
e5c4350b
TG
733int sd_rtnl_message_exit_container(sd_rtnl_message *m) {
734 assert_return(m, -EINVAL);
735 assert_return(m->sealed, -EINVAL);
736 assert_return(m->n_containers > 0, -EINVAL);
737
738 m->n_containers --;
739
740 return 0;
741}
742
3815f36f 743uint32_t rtnl_message_get_serial(sd_rtnl_message *m) {
65f568bb 744 assert(m);
9d0db178 745 assert(m->hdr);
65f568bb
TG
746
747 return m->hdr->nlmsg_seq;
748}
749
e16bcf98 750int sd_rtnl_message_get_errno(sd_rtnl_message *m) {
65f568bb
TG
751 struct nlmsgerr *err;
752
e16bcf98 753 assert_return(m, -EINVAL);
9d0db178 754 assert_return(m->hdr, -EINVAL);
65f568bb
TG
755
756 if (m->hdr->nlmsg_type != NLMSG_ERROR)
757 return 0;
758
759 err = NLMSG_DATA(m->hdr);
760
761 return err->error;
762}
763
3815f36f 764int rtnl_message_seal(sd_rtnl *nl, sd_rtnl_message *m) {
e5c4350b
TG
765 int r;
766
9d0db178
TG
767 assert(m);
768 assert(m->hdr);
769
65f568bb
TG
770 if (m->sealed)
771 return -EPERM;
772
e5c4350b
TG
773 if (nl)
774 m->hdr->nlmsg_seq = nl->serial++;
775
65f568bb
TG
776 m->sealed = true;
777
e5c4350b
TG
778 r = sd_rtnl_message_rewind(m);
779 if (r < 0)
780 return r;
781
65f568bb
TG
782 return 0;
783}
784
785static int message_receive_need(sd_rtnl *rtnl, size_t *need) {
9d0db178
TG
786 assert(rtnl);
787 assert(need);
65f568bb
TG
788
789 /* ioctl(rtnl->fd, FIONREAD, &need)
dabfa9d1
TG
790 Does not appear to work on netlink sockets. libnl uses
791 MSG_PEEK instead. I don't know if that is worth the
792 extra roundtrip.
793
794 For now we simply use the maximum message size the kernel
795 may use (NLMSG_GOODSIZE), and then realloc to the actual
796 size after reading the message (hence avoiding huge memory
797 usage in case many small messages are kept around) */
798 *need = page_size();
65f568bb
TG
799 if (*need > 8192UL)
800 *need = 8192UL;
801
802 return 0;
803}
804
805/* returns the number of bytes sent, or a negative error code */
806int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
d4bbdb77
TG
807 union {
808 struct sockaddr sa;
809 struct sockaddr_nl nl;
810 } addr = {
811 .nl.nl_family = AF_NETLINK,
812 };
65f568bb
TG
813 ssize_t k;
814
9d0db178
TG
815 assert(nl);
816 assert(m);
817 assert(m->hdr);
65f568bb
TG
818
819 k = sendto(nl->fd, m->hdr, m->hdr->nlmsg_len,
d4bbdb77 820 0, &addr.sa, sizeof(addr));
65f568bb
TG
821 if (k < 0)
822 return (errno == EAGAIN) ? 0 : -errno;
823
824 return k;
825}
826
827/* On success, the number of bytes received is returned and *ret points to the received message
828 * which has a valid header and the correct size.
829 * If nothing useful was received 0 is returned.
830 * On failure, a negative error code is returned.
dabfa9d1 831 */
65f568bb
TG
832int socket_read_message(sd_rtnl *nl, sd_rtnl_message **ret) {
833 sd_rtnl_message *m;
d4bbdb77
TG
834 union {
835 struct sockaddr sa;
836 struct sockaddr_nl nl;
837 } addr;
838 socklen_t addr_len;
65f568bb
TG
839 int r;
840 ssize_t k;
841 size_t need;
842
9d0db178
TG
843 assert(nl);
844 assert(ret);
65f568bb
TG
845
846 r = message_receive_need(nl, &need);
847 if (r < 0)
848 return r;
849
850 r = message_new(&m, need);
851 if (r < 0)
852 return r;
853
e5c4350b
TG
854 /* don't allow sealing/appending to received messages */
855 m->sealed = true;
856
d4bbdb77
TG
857 addr_len = sizeof(addr);
858
65f568bb 859 k = recvfrom(nl->fd, m->hdr, need,
d4bbdb77 860 0, &addr.sa, &addr_len);
65f568bb 861 if (k < 0)
276fc066 862 k = (errno == EAGAIN) ? 0 : -errno; /* no data */
65f568bb
TG
863 else if (k == 0)
864 k = -ECONNRESET; /* connection was closed by the kernel */
d4bbdb77
TG
865 else if (addr_len != sizeof(addr.nl) ||
866 addr.nl.nl_family != AF_NETLINK)
65f568bb 867 k = -EIO; /* not a netlink message */
d4bbdb77 868 else if (addr.nl.nl_pid != 0)
65f568bb
TG
869 k = 0; /* not from the kernel */
870 else if ((size_t) k < sizeof(struct nlmsghdr) ||
dabfa9d1 871 (size_t) k < m->hdr->nlmsg_len)
65f568bb 872 k = -EIO; /* too small (we do accept too big though) */
a02113d2
TG
873 else if (m->hdr->nlmsg_pid && m->hdr->nlmsg_pid != nl->sockaddr.nl.nl_pid)
874 k = 0; /* not broadcast and not for us */
65f568bb
TG
875
876 if (k > 0)
877 switch (m->hdr->nlmsg_type) {
0fc7531b
TG
878 struct ifinfomsg *ifi;
879 struct ifaddrmsg *ifa;
880 struct rtmsg *rtm;
881
65f568bb
TG
882 /* check that the size matches the message type */
883 case NLMSG_ERROR:
884 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
885 k = -EIO;
03d7e632 886 break;
65f568bb 887 case RTM_NEWLINK:
d2df0d0e 888 case RTM_SETLINK:
65f568bb
TG
889 case RTM_DELLINK:
890 case RTM_GETLINK:
891 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg)))
892 k = -EIO;
0fc7531b
TG
893 else {
894 ifi = NLMSG_DATA(m->hdr);
4ebe732c 895 UPDATE_RTA(m, IFLA_RTA(ifi));
0fc7531b 896 }
03d7e632 897 break;
65f568bb
TG
898 case RTM_NEWADDR:
899 case RTM_DELADDR:
900 case RTM_GETADDR:
901 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifaddrmsg)))
902 k = -EIO;
0fc7531b
TG
903 else {
904 ifa = NLMSG_DATA(m->hdr);
4ebe732c 905 UPDATE_RTA(m, IFA_RTA(ifa));
0fc7531b 906 }
03d7e632 907 break;
3e10a9f4
TG
908 case RTM_NEWROUTE:
909 case RTM_DELROUTE:
910 case RTM_GETROUTE:
911 if (m->hdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtmsg)))
912 k = -EIO;
0fc7531b
TG
913 else {
914 rtm = NLMSG_DATA(m->hdr);
4ebe732c 915 UPDATE_RTA(m, RTM_RTA(rtm));
0fc7531b 916 }
3e10a9f4 917 break;
65f568bb
TG
918 case NLMSG_NOOP:
919 k = 0;
03d7e632 920 break;
65f568bb
TG
921 default:
922 k = 0; /* ignoring message of unknown type */
923 }
924
925 if (k <= 0)
926 sd_rtnl_message_unref(m);
927 else {
928 /* we probably allocated way too much memory, give it back */
929 m->hdr = realloc(m->hdr, m->hdr->nlmsg_len);
930 *ret = m;
931 }
932
933 return k;
934}
0fc7531b
TG
935
936int sd_rtnl_message_rewind(sd_rtnl_message *m) {
937 struct ifinfomsg *ifi;
938 struct ifaddrmsg *ifa;
939 struct rtmsg *rtm;
940
941 assert_return(m, -EINVAL);
e5c4350b 942 assert_return(m->sealed, -EPERM);
0fc7531b
TG
943 assert_return(m->hdr, -EINVAL);
944
945 switch(m->hdr->nlmsg_type) {
946 case RTM_NEWLINK:
947 case RTM_SETLINK:
948 case RTM_GETLINK:
949 case RTM_DELLINK:
950 ifi = NLMSG_DATA(m->hdr);
4ebe732c 951 UPDATE_RTA(m, IFLA_RTA(ifi));
0fc7531b 952
0fc7531b
TG
953 break;
954 case RTM_NEWADDR:
955 case RTM_GETADDR:
956 case RTM_DELADDR:
957 ifa = NLMSG_DATA(m->hdr);
4ebe732c 958 UPDATE_RTA(m, IFA_RTA(ifa));
0fc7531b 959
0fc7531b
TG
960 break;
961 case RTM_NEWROUTE:
962 case RTM_GETROUTE:
963 case RTM_DELROUTE:
964 rtm = NLMSG_DATA(m->hdr);
4ebe732c 965 UPDATE_RTA(m, RTM_RTA(rtm));
0fc7531b 966
0fc7531b
TG
967 break;
968 default:
969 return -ENOTSUP;
970 }
971
e5c4350b
TG
972 m->n_containers = 0;
973
0fc7531b
TG
974 return 0;
975}