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