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