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