]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-rtnl/local-addresses.c
udev: modernize net_id builtin a bit
[thirdparty/systemd.git] / src / libsystemd / sd-rtnl / local-addresses.c
CommitLineData
8041b5ba
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
cbc06dcd 4 This file is part of systemd.
8041b5ba
LP
5
6 Copyright 2008-2011 Lennart Poettering
d1ca51b1 7 Copyright 2014 Tom Gundersen
8041b5ba 8
cbc06dcd
TG
9 systemd is free software; you can redistribute it and/or modify it
10 under the terms of the GNU Lesser General Public License as published by
11 the Free Software Foundation; either version 2.1 of the License, or
12 (at your option) any later version.
8041b5ba 13
cbc06dcd
TG
14 systemd is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
8041b5ba
LP
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 Lesser General Public License for more details.
18
cbc06dcd
TG
19 You should have received a copy of the GNU Lesser General Public License
20 along with systemd; If not, see <http://www.gnu.org/licenses/>.
8041b5ba
LP
21***/
22
d1ca51b1
TG
23#include "sd-rtnl.h"
24#include "rtnl-util.h"
25#include "macro.h"
e80af1bd 26#include "local-addresses.h"
8041b5ba 27
5502f0d9 28static int address_compare(const void *_a, const void *_b) {
e80af1bd 29 const struct local_address *a = _a, *b = _b;
5502f0d9
LP
30
31 /* Order lowest scope first, IPv4 before IPv6, lowest interface index first */
32
33 if (a->scope < b->scope)
34 return -1;
35 if (a->scope > b->scope)
36 return 1;
37
38 if (a->family == AF_INET && b->family == AF_INET6)
39 return -1;
40 if (a->family == AF_INET6 && b->family == AF_INET)
41 return 1;
42
43 if (a->ifindex < b->ifindex)
44 return -1;
45 if (a->ifindex > b->ifindex)
46 return 1;
47
48 return 0;
49}
50
e80af1bd 51int local_addresses(struct local_address **ret) {
d1ca51b1 52 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
5502f0d9 53 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
e80af1bd 54 _cleanup_free_ struct local_address *list = NULL;
5502f0d9
LP
55 size_t n_list = 0, n_allocated = 0;
56 sd_rtnl_message *m;
d1ca51b1 57 int r;
d73c3269 58
e80af1bd
LP
59 assert(ret);
60
d1ca51b1
TG
61 r = sd_rtnl_open(&rtnl, 0);
62 if (r < 0)
63 return r;
8041b5ba 64
d1ca51b1
TG
65 r = sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC);
66 if (r < 0)
67 return r;
8041b5ba 68
d1ca51b1
TG
69 r = sd_rtnl_call(rtnl, req, 0, &reply);
70 if (r < 0)
71 return r;
d1ca51b1 72
5502f0d9 73 for (m = reply; m; m = sd_rtnl_message_next(m)) {
e80af1bd 74 struct local_address *a;
d1ca51b1 75 unsigned char flags;
5502f0d9 76 uint16_t type;
d1ca51b1
TG
77
78 r = sd_rtnl_message_get_errno(m);
79 if (r < 0)
80 return r;
81
82 r = sd_rtnl_message_get_type(m, &type);
83 if (r < 0)
84 return r;
85
86 if (type != RTM_NEWADDR)
8041b5ba
LP
87 continue;
88
5502f0d9 89 r = sd_rtnl_message_addr_get_flags(m, &flags);
d1ca51b1
TG
90 if (r < 0)
91 return r;
8041b5ba 92
5502f0d9 93 if (flags & IFA_F_DEPRECATED)
d73c3269 94 continue;
8041b5ba 95
5502f0d9
LP
96 if (!GREEDY_REALLOC(list, n_allocated, n_list+1))
97 return -ENOMEM;
98
99 a = list + n_list;
100
101 r = sd_rtnl_message_addr_get_scope(m, &a->scope);
d1ca51b1
TG
102 if (r < 0)
103 return r;
8041b5ba 104
5502f0d9 105 if (a->scope == RT_SCOPE_HOST || a->scope == RT_SCOPE_NOWHERE)
d73c3269 106 continue;
8041b5ba 107
5502f0d9 108 r = sd_rtnl_message_addr_get_family(m, &a->family);
d1ca51b1
TG
109 if (r < 0)
110 return r;
111
5502f0d9
LP
112 switch (a->family) {
113
d1ca51b1 114 case AF_INET:
5502f0d9 115 r = sd_rtnl_message_read_in_addr(m, IFA_LOCAL, &a->address.in);
d1ca51b1 116 if (r < 0) {
5502f0d9 117 r = sd_rtnl_message_read_in_addr(m, IFA_ADDRESS, &a->address.in);
d1ca51b1
TG
118 if (r < 0)
119 continue;
120 }
121 break;
5502f0d9 122
d1ca51b1 123 case AF_INET6:
5502f0d9 124 r = sd_rtnl_message_read_in6_addr(m, IFA_LOCAL, &a->address.in6);
d1ca51b1 125 if (r < 0) {
5502f0d9 126 r = sd_rtnl_message_read_in6_addr(m, IFA_ADDRESS, &a->address.in6);
d1ca51b1
TG
127 if (r < 0)
128 continue;
129 }
130 break;
5502f0d9 131
d1ca51b1 132 default:
d73c3269 133 continue;
d73c3269 134 }
8041b5ba 135
5502f0d9 136 r = sd_rtnl_message_addr_get_ifindex(m, &a->ifindex);
d1ca51b1
TG
137 if (r < 0)
138 return r;
8041b5ba 139
d1ca51b1 140 n_list++;
5502f0d9 141 };
8041b5ba 142
7ff7394d 143 if (n_list)
e80af1bd 144 qsort(list, n_list, sizeof(struct local_address), address_compare);
d73c3269 145
e80af1bd 146 *ret = list;
d1ca51b1 147 list = NULL;
d73c3269 148
e80af1bd 149 return (int) n_list;
8041b5ba 150}