]> git.proxmox.com Git - systemd.git/blame - src/libsystemd/sd-netlink/rtnl-message.c
Merge tag 'upstream/229'
[systemd.git] / src / libsystemd / sd-netlink / rtnl-message.c
CommitLineData
86f210e9
MP
1/***
2 This file is part of systemd.
3
4 Copyright 2013 Tom Gundersen <teg@jklm.no>
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
20#include <netinet/in.h>
21#include <stdbool.h>
22#include <unistd.h>
23
db2df898
MP
24#include "sd-netlink.h"
25
86f210e9 26#include "formats-util.h"
86f210e9 27#include "missing.h"
86f210e9
MP
28#include "netlink-internal.h"
29#include "netlink-types.h"
db2df898
MP
30#include "netlink-util.h"
31#include "refcnt.h"
32#include "socket-util.h"
33#include "util.h"
86f210e9
MP
34
35int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
36 struct rtmsg *rtm;
37
38 assert_return(m, -EINVAL);
39 assert_return(m->hdr, -EINVAL);
40 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
41
42 rtm = NLMSG_DATA(m->hdr);
43
44 if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
45 (rtm->rtm_family == AF_INET6 && prefixlen > 128))
46 return -ERANGE;
47
48 rtm->rtm_dst_len = prefixlen;
49
50 return 0;
51}
52
53int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
54 struct rtmsg *rtm;
55
56 assert_return(m, -EINVAL);
57 assert_return(m->hdr, -EINVAL);
58 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
59
60 rtm = NLMSG_DATA(m->hdr);
61
62 if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
63 (rtm->rtm_family == AF_INET6 && prefixlen > 128))
64 return -ERANGE;
65
66 rtm->rtm_src_len = prefixlen;
67
68 return 0;
69}
70
71int sd_rtnl_message_route_set_scope(sd_netlink_message *m, unsigned char scope) {
72 struct rtmsg *rtm;
73
74 assert_return(m, -EINVAL);
75 assert_return(m->hdr, -EINVAL);
76 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
77
78 rtm = NLMSG_DATA(m->hdr);
79
80 rtm->rtm_scope = scope;
81
82 return 0;
83}
84
db2df898
MP
85int sd_rtnl_message_route_set_flags(sd_netlink_message *m, unsigned flags) {
86 struct rtmsg *rtm;
87
88 assert_return(m, -EINVAL);
89 assert_return(m->hdr, -EINVAL);
90 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
91
92 rtm = NLMSG_DATA(m->hdr);
93
94 rtm->rtm_flags = flags;
95
96 return 0;
97}
98
99int sd_rtnl_message_route_get_flags(sd_netlink_message *m, unsigned *flags) {
100 struct rtmsg *rtm;
101
102 assert_return(m, -EINVAL);
103 assert_return(m->hdr, -EINVAL);
104 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
105 assert_return(flags, -EINVAL);
106
107 rtm = NLMSG_DATA(m->hdr);
108
109 *flags = rtm->rtm_flags;
110
111 return 0;
112}
113
86f210e9
MP
114int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family) {
115 struct rtmsg *rtm;
116
117 assert_return(m, -EINVAL);
118 assert_return(m->hdr, -EINVAL);
119 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
120 assert_return(family, -EINVAL);
121
122 rtm = NLMSG_DATA(m->hdr);
123
124 *family = rtm->rtm_family;
125
126 return 0;
127}
128
db2df898
MP
129int sd_rtnl_message_route_get_protocol(sd_netlink_message *m, unsigned char *protocol) {
130 struct rtmsg *rtm;
131
132 assert_return(m, -EINVAL);
133 assert_return(m->hdr, -EINVAL);
134 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
135 assert_return(protocol, -EINVAL);
136
137 rtm = NLMSG_DATA(m->hdr);
138
139 *protocol = rtm->rtm_protocol;
140
141 return 0;
142}
143
144int sd_rtnl_message_route_get_scope(sd_netlink_message *m, unsigned char *scope) {
145 struct rtmsg *rtm;
146
147 assert_return(m, -EINVAL);
148 assert_return(m->hdr, -EINVAL);
149 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
150 assert_return(scope, -EINVAL);
151
152 rtm = NLMSG_DATA(m->hdr);
153
154 *scope = rtm->rtm_scope;
155
156 return 0;
157}
158
159int sd_rtnl_message_route_get_tos(sd_netlink_message *m, unsigned char *tos) {
160 struct rtmsg *rtm;
161
162 assert_return(m, -EINVAL);
163 assert_return(m->hdr, -EINVAL);
164 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
165 assert_return(tos, -EINVAL);
166
167 rtm = NLMSG_DATA(m->hdr);
168
169 *tos = rtm->rtm_tos;
170
171 return 0;
172}
173
174int sd_rtnl_message_route_get_table(sd_netlink_message *m, unsigned char *table) {
175 struct rtmsg *rtm;
176
177 assert_return(m, -EINVAL);
178 assert_return(m->hdr, -EINVAL);
179 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
180 assert_return(table, -EINVAL);
181
182 rtm = NLMSG_DATA(m->hdr);
183
184 *table = rtm->rtm_table;
185
186 return 0;
187}
188
86f210e9
MP
189int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char *dst_len) {
190 struct rtmsg *rtm;
191
192 assert_return(m, -EINVAL);
193 assert_return(m->hdr, -EINVAL);
194 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
195 assert_return(dst_len, -EINVAL);
196
197 rtm = NLMSG_DATA(m->hdr);
198
199 *dst_len = rtm->rtm_dst_len;
200
201 return 0;
202}
203
204int sd_rtnl_message_route_get_src_prefixlen(sd_netlink_message *m, unsigned char *src_len) {
205 struct rtmsg *rtm;
206
207 assert_return(m, -EINVAL);
208 assert_return(m->hdr, -EINVAL);
209 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
210 assert_return(src_len, -EINVAL);
211
212 rtm = NLMSG_DATA(m->hdr);
213
214 *src_len = rtm->rtm_src_len;
215
216 return 0;
217}
218
219int sd_rtnl_message_new_route(sd_netlink *rtnl, sd_netlink_message **ret,
220 uint16_t nlmsg_type, int rtm_family,
221 unsigned char rtm_protocol) {
222 struct rtmsg *rtm;
223 int r;
224
225 assert_return(rtnl_message_type_is_route(nlmsg_type), -EINVAL);
226 assert_return((nlmsg_type == RTM_GETROUTE && rtm_family == AF_UNSPEC) ||
227 rtm_family == AF_INET || rtm_family == AF_INET6, -EINVAL);
228 assert_return(ret, -EINVAL);
229
230 r = message_new(rtnl, ret, nlmsg_type);
231 if (r < 0)
232 return r;
233
234 if (nlmsg_type == RTM_NEWROUTE)
235 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
236
237 rtm = NLMSG_DATA((*ret)->hdr);
238
239 rtm->rtm_family = rtm_family;
240 rtm->rtm_scope = RT_SCOPE_UNIVERSE;
241 rtm->rtm_type = RTN_UNICAST;
242 rtm->rtm_table = RT_TABLE_MAIN;
243 rtm->rtm_protocol = rtm_protocol;
244
245 return 0;
246}
247
248int sd_rtnl_message_neigh_set_flags(sd_netlink_message *m, uint8_t flags) {
249 struct ndmsg *ndm;
250
251 assert_return(m, -EINVAL);
252 assert_return(m->hdr, -EINVAL);
253 assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
254
255 ndm = NLMSG_DATA(m->hdr);
256 ndm->ndm_flags |= flags;
257
258 return 0;
259}
260
261int sd_rtnl_message_neigh_set_state(sd_netlink_message *m, uint16_t state) {
262 struct ndmsg *ndm;
263
264 assert_return(m, -EINVAL);
265 assert_return(m->hdr, -EINVAL);
266 assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
267
268 ndm = NLMSG_DATA(m->hdr);
269 ndm->ndm_state |= state;
270
271 return 0;
272}
273
274int sd_rtnl_message_neigh_get_flags(sd_netlink_message *m, uint8_t *flags) {
275 struct ndmsg *ndm;
276
277 assert_return(m, -EINVAL);
278 assert_return(m->hdr, -EINVAL);
279 assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
280
281 ndm = NLMSG_DATA(m->hdr);
282 *flags = ndm->ndm_flags;
283
284 return 0;
285}
286
287int sd_rtnl_message_neigh_get_state(sd_netlink_message *m, uint16_t *state) {
288 struct ndmsg *ndm;
289
290 assert_return(m, -EINVAL);
291 assert_return(m->hdr, -EINVAL);
292 assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
293
294 ndm = NLMSG_DATA(m->hdr);
295 *state = ndm->ndm_state;
296
297 return 0;
298}
299
300int sd_rtnl_message_neigh_get_family(sd_netlink_message *m, int *family) {
301 struct ndmsg *ndm;
302
303 assert_return(m, -EINVAL);
304 assert_return(m->hdr, -EINVAL);
305 assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
306 assert_return(family, -EINVAL);
307
308 ndm = NLMSG_DATA(m->hdr);
309
310 *family = ndm->ndm_family;
311
312 return 0;
313}
314
315int sd_rtnl_message_neigh_get_ifindex(sd_netlink_message *m, int *index) {
316 struct ndmsg *ndm;
317
318 assert_return(m, -EINVAL);
319 assert_return(m->hdr, -EINVAL);
320 assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
321 assert_return(index, -EINVAL);
322
323 ndm = NLMSG_DATA(m->hdr);
324
325 *index = ndm->ndm_ifindex;
326
327 return 0;
328}
329
330int sd_rtnl_message_new_neigh(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int index, int ndm_family) {
331 struct ndmsg *ndm;
332 int r;
333
334 assert_return(rtnl_message_type_is_neigh(nlmsg_type), -EINVAL);
335 assert_return(ndm_family == AF_INET ||
336 ndm_family == AF_INET6 ||
337 ndm_family == PF_BRIDGE, -EINVAL);
338 assert_return(ret, -EINVAL);
339
340 r = message_new(rtnl, ret, nlmsg_type);
341 if (r < 0)
342 return r;
343
344 if (nlmsg_type == RTM_NEWNEIGH)
345 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
346
347 ndm = NLMSG_DATA((*ret)->hdr);
348
349 ndm->ndm_family = ndm_family;
350 ndm->ndm_ifindex = index;
351
352 return 0;
353}
354
355int sd_rtnl_message_link_set_flags(sd_netlink_message *m, unsigned flags, unsigned change) {
356 struct ifinfomsg *ifi;
357
358 assert_return(m, -EINVAL);
359 assert_return(m->hdr, -EINVAL);
360 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
361 assert_return(change, -EINVAL);
362
363 ifi = NLMSG_DATA(m->hdr);
364
365 ifi->ifi_flags = flags;
366 ifi->ifi_change = change;
367
368 return 0;
369}
370
371int sd_rtnl_message_link_set_type(sd_netlink_message *m, unsigned type) {
372 struct ifinfomsg *ifi;
373
374 assert_return(m, -EINVAL);
375 assert_return(m->hdr, -EINVAL);
376 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
377
378 ifi = NLMSG_DATA(m->hdr);
379
380 ifi->ifi_type = type;
381
382 return 0;
383}
384
385int sd_rtnl_message_link_set_family(sd_netlink_message *m, unsigned family) {
386 struct ifinfomsg *ifi;
387
388 assert_return(m, -EINVAL);
389 assert_return(m->hdr, -EINVAL);
390 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
391
392 ifi = NLMSG_DATA(m->hdr);
393
394 ifi->ifi_family = family;
395
396 return 0;
397}
398
399int sd_rtnl_message_new_link(sd_netlink *rtnl, sd_netlink_message **ret,
400 uint16_t nlmsg_type, int index) {
401 struct ifinfomsg *ifi;
402 int r;
403
404 assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL);
405 assert_return(nlmsg_type != RTM_DELLINK || index > 0, -EINVAL);
406 assert_return(ret, -EINVAL);
407
408 r = message_new(rtnl, ret, nlmsg_type);
409 if (r < 0)
410 return r;
411
412 if (nlmsg_type == RTM_NEWLINK)
413 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
414
415 ifi = NLMSG_DATA((*ret)->hdr);
416
417 ifi->ifi_family = AF_UNSPEC;
418 ifi->ifi_index = index;
419
420 return 0;
421}
422
423int sd_rtnl_message_addr_set_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
424 struct ifaddrmsg *ifa;
425
426 assert_return(m, -EINVAL);
427 assert_return(m->hdr, -EINVAL);
428 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
429
430 ifa = NLMSG_DATA(m->hdr);
431
432 if ((ifa->ifa_family == AF_INET && prefixlen > 32) ||
433 (ifa->ifa_family == AF_INET6 && prefixlen > 128))
434 return -ERANGE;
435
436 ifa->ifa_prefixlen = prefixlen;
437
438 return 0;
439}
440
441int sd_rtnl_message_addr_set_flags(sd_netlink_message *m, unsigned char flags) {
442 struct ifaddrmsg *ifa;
443
444 assert_return(m, -EINVAL);
445 assert_return(m->hdr, -EINVAL);
446 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
447
448 ifa = NLMSG_DATA(m->hdr);
449
450 ifa->ifa_flags = flags;
451
452 return 0;
453}
454
455int sd_rtnl_message_addr_set_scope(sd_netlink_message *m, unsigned char scope) {
456 struct ifaddrmsg *ifa;
457
458 assert_return(m, -EINVAL);
459 assert_return(m->hdr, -EINVAL);
460 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
461
462 ifa = NLMSG_DATA(m->hdr);
463
464 ifa->ifa_scope = scope;
465
466 return 0;
467}
468
469int sd_rtnl_message_addr_get_family(sd_netlink_message *m, int *family) {
470 struct ifaddrmsg *ifa;
471
472 assert_return(m, -EINVAL);
473 assert_return(m->hdr, -EINVAL);
474 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
475 assert_return(family, -EINVAL);
476
477 ifa = NLMSG_DATA(m->hdr);
478
479 *family = ifa->ifa_family;
480
481 return 0;
482}
483
484int sd_rtnl_message_addr_get_prefixlen(sd_netlink_message *m, unsigned char *prefixlen) {
485 struct ifaddrmsg *ifa;
486
487 assert_return(m, -EINVAL);
488 assert_return(m->hdr, -EINVAL);
489 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
490 assert_return(prefixlen, -EINVAL);
491
492 ifa = NLMSG_DATA(m->hdr);
493
494 *prefixlen = ifa->ifa_prefixlen;
495
496 return 0;
497}
498
499int sd_rtnl_message_addr_get_scope(sd_netlink_message *m, unsigned char *scope) {
500 struct ifaddrmsg *ifa;
501
502 assert_return(m, -EINVAL);
503 assert_return(m->hdr, -EINVAL);
504 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
505 assert_return(scope, -EINVAL);
506
507 ifa = NLMSG_DATA(m->hdr);
508
509 *scope = ifa->ifa_scope;
510
511 return 0;
512}
513
514int sd_rtnl_message_addr_get_flags(sd_netlink_message *m, unsigned char *flags) {
515 struct ifaddrmsg *ifa;
516
517 assert_return(m, -EINVAL);
518 assert_return(m->hdr, -EINVAL);
519 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
520 assert_return(flags, -EINVAL);
521
522 ifa = NLMSG_DATA(m->hdr);
523
524 *flags = ifa->ifa_flags;
525
526 return 0;
527}
528
529int sd_rtnl_message_addr_get_ifindex(sd_netlink_message *m, int *ifindex) {
530 struct ifaddrmsg *ifa;
531
532 assert_return(m, -EINVAL);
533 assert_return(m->hdr, -EINVAL);
534 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
535 assert_return(ifindex, -EINVAL);
536
537 ifa = NLMSG_DATA(m->hdr);
538
539 *ifindex = ifa->ifa_index;
540
541 return 0;
542}
543
544int sd_rtnl_message_new_addr(sd_netlink *rtnl, sd_netlink_message **ret,
545 uint16_t nlmsg_type, int index,
546 int family) {
547 struct ifaddrmsg *ifa;
548 int r;
549
550 assert_return(rtnl_message_type_is_addr(nlmsg_type), -EINVAL);
551 assert_return((nlmsg_type == RTM_GETADDR && index == 0) ||
552 index > 0, -EINVAL);
553 assert_return((nlmsg_type == RTM_GETADDR && family == AF_UNSPEC) ||
554 family == AF_INET || family == AF_INET6, -EINVAL);
555 assert_return(ret, -EINVAL);
556
557 r = message_new(rtnl, ret, nlmsg_type);
558 if (r < 0)
559 return r;
560
561 if (nlmsg_type == RTM_GETADDR)
562 (*ret)->hdr->nlmsg_flags |= NLM_F_DUMP;
563
564 ifa = NLMSG_DATA((*ret)->hdr);
565
566 ifa->ifa_index = index;
567 ifa->ifa_family = family;
568 if (family == AF_INET)
569 ifa->ifa_prefixlen = 32;
570 else if (family == AF_INET6)
571 ifa->ifa_prefixlen = 128;
572
573 return 0;
574}
575
576int sd_rtnl_message_new_addr_update(sd_netlink *rtnl, sd_netlink_message **ret,
577 int index, int family) {
578 int r;
579
580 r = sd_rtnl_message_new_addr(rtnl, ret, RTM_NEWADDR, index, family);
581 if (r < 0)
582 return r;
583
584 (*ret)->hdr->nlmsg_flags |= NLM_F_REPLACE;
585
586 return 0;
587}
588
589int sd_rtnl_message_link_get_ifindex(sd_netlink_message *m, int *ifindex) {
590 struct ifinfomsg *ifi;
591
592 assert_return(m, -EINVAL);
593 assert_return(m->hdr, -EINVAL);
594 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
595 assert_return(ifindex, -EINVAL);
596
597 ifi = NLMSG_DATA(m->hdr);
598
599 *ifindex = ifi->ifi_index;
600
601 return 0;
602}
603
604int sd_rtnl_message_link_get_flags(sd_netlink_message *m, unsigned *flags) {
605 struct ifinfomsg *ifi;
606
607 assert_return(m, -EINVAL);
608 assert_return(m->hdr, -EINVAL);
609 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
610 assert_return(flags, -EINVAL);
611
612 ifi = NLMSG_DATA(m->hdr);
613
614 *flags = ifi->ifi_flags;
615
616 return 0;
617}
618
619int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned *type) {
620 struct ifinfomsg *ifi;
621
622 assert_return(m, -EINVAL);
623 assert_return(m->hdr, -EINVAL);
624 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
625 assert_return(type, -EINVAL);
626
627 ifi = NLMSG_DATA(m->hdr);
628
629 *type = ifi->ifi_type;
630
631 return 0;
632}
633
634int sd_rtnl_message_get_family(sd_netlink_message *m, int *family) {
635 assert_return(m, -EINVAL);
636 assert_return(family, -EINVAL);
637
638 assert(m->hdr);
639
640 if (rtnl_message_type_is_link(m->hdr->nlmsg_type)) {
641 struct ifinfomsg *ifi;
642
643 ifi = NLMSG_DATA(m->hdr);
644
645 *family = ifi->ifi_family;
646
647 return 0;
648 } else if (rtnl_message_type_is_route(m->hdr->nlmsg_type)) {
649 struct rtmsg *rtm;
650
651 rtm = NLMSG_DATA(m->hdr);
652
653 *family = rtm->rtm_family;
654
655 return 0;
656 } else if (rtnl_message_type_is_neigh(m->hdr->nlmsg_type)) {
657 struct ndmsg *ndm;
658
659 ndm = NLMSG_DATA(m->hdr);
660
661 *family = ndm->ndm_family;
662
663 return 0;
664 } else if (rtnl_message_type_is_addr(m->hdr->nlmsg_type)) {
665 struct ifaddrmsg *ifa;
666
667 ifa = NLMSG_DATA(m->hdr);
668
669 *family = ifa->ifa_family;
670
671 return 0;
672 }
673
674 return -EOPNOTSUPP;
675}