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