]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
b22d8a00 | 2 | |
9aa5d8ba | 3 | #include <netinet/in.h> |
b22d8a00 TG |
4 | #include <linux/if.h> |
5 | ||
b22d8a00 | 6 | #include "network-internal.h" |
23f53b99 | 7 | #include "networkd-address.h" |
ca5ad760 | 8 | #include "networkd-ipv4ll.h" |
23f53b99 | 9 | #include "networkd-link.h" |
ca5ad760 YW |
10 | #include "networkd-manager.h" |
11 | #include "parse-util.h" | |
b22d8a00 TG |
12 | |
13 | static int ipv4ll_address_lost(Link *link) { | |
8e766630 | 14 | _cleanup_(address_freep) Address *address = NULL; |
b22d8a00 TG |
15 | struct in_addr addr; |
16 | int r; | |
17 | ||
18 | assert(link); | |
19 | ||
920b52e4 | 20 | link->ipv4ll_address = false; |
b22d8a00 TG |
21 | |
22 | r = sd_ipv4ll_get_address(link->ipv4ll, &addr); | |
23 | if (r < 0) | |
24 | return 0; | |
25 | ||
79008bdd | 26 | log_link_debug(link, "IPv4 link-local release %u.%u.%u.%u", ADDRESS_FMT_VAL(addr)); |
b22d8a00 | 27 | |
f0213e37 | 28 | r = address_new(&address); |
fc95c359 YW |
29 | if (r < 0) |
30 | return log_link_error_errno(link, r, "Could not allocate address: %m"); | |
b22d8a00 TG |
31 | |
32 | address->family = AF_INET; | |
33 | address->in_addr.in = addr; | |
34 | address->prefixlen = 16; | |
35 | address->scope = RT_SCOPE_LINK; | |
36 | ||
807341ec YW |
37 | r = address_remove(address, link, NULL); |
38 | if (r < 0) | |
39 | return r; | |
b22d8a00 | 40 | |
8012cd39 | 41 | link_check_ready(link); |
b22d8a00 TG |
42 | |
43 | return 0; | |
44 | } | |
45 | ||
302a796f | 46 | static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { |
b22d8a00 TG |
47 | int r; |
48 | ||
49 | assert(link); | |
50 | assert(!link->ipv4ll_address); | |
51 | ||
1c4baffc | 52 | r = sd_netlink_message_get_errno(m); |
b22d8a00 | 53 | if (r < 0 && r != -EEXIST) { |
5ecb131d | 54 | log_link_message_warning_errno(link, m, r, "could not set ipv4ll address"); |
b22d8a00 | 55 | link_enter_failed(link); |
4ff296b0 | 56 | return 1; |
45af44d4 | 57 | } else if (r >= 0) |
4ff296b0 | 58 | (void) manager_rtnl_process_address(rtnl, m, link->manager); |
b22d8a00 TG |
59 | |
60 | link->ipv4ll_address = true; | |
2aa7d367 | 61 | link_check_ready(link); |
b22d8a00 TG |
62 | |
63 | return 1; | |
64 | } | |
65 | ||
66 | static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) { | |
8e766630 | 67 | _cleanup_(address_freep) Address *ll_addr = NULL; |
b22d8a00 TG |
68 | struct in_addr address; |
69 | int r; | |
70 | ||
71 | assert(ll); | |
72 | assert(link); | |
73 | ||
79316750 | 74 | link->ipv4ll_address = false; |
79316750 | 75 | |
b22d8a00 TG |
76 | r = sd_ipv4ll_get_address(ll, &address); |
77 | if (r == -ENOENT) | |
78 | return 0; | |
79 | else if (r < 0) | |
80 | return r; | |
81 | ||
79008bdd | 82 | log_link_debug(link, "IPv4 link-local claim %u.%u.%u.%u", |
b22d8a00 TG |
83 | ADDRESS_FMT_VAL(address)); |
84 | ||
f0213e37 | 85 | r = address_new(&ll_addr); |
b22d8a00 TG |
86 | if (r < 0) |
87 | return r; | |
88 | ||
89 | ll_addr->family = AF_INET; | |
90 | ll_addr->in_addr.in = address; | |
91 | ll_addr->prefixlen = 16; | |
8e38570e | 92 | ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htobe32(0xfffffffflu >> ll_addr->prefixlen); |
b22d8a00 TG |
93 | ll_addr->scope = RT_SCOPE_LINK; |
94 | ||
66669078 | 95 | r = address_configure(ll_addr, link, ipv4ll_address_handler, false); |
b22d8a00 TG |
96 | if (r < 0) |
97 | return r; | |
98 | ||
b22d8a00 TG |
99 | return 0; |
100 | } | |
101 | ||
9ed794a3 | 102 | static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata) { |
b22d8a00 TG |
103 | Link *link = userdata; |
104 | int r; | |
105 | ||
106 | assert(link); | |
107 | assert(link->network); | |
b22d8a00 TG |
108 | |
109 | if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) | |
110 | return; | |
111 | ||
112 | switch(event) { | |
be19c5b5 | 113 | case SD_IPV4LL_EVENT_STOP: |
0698ff41 JR |
114 | r = ipv4ll_address_lost(link); |
115 | if (r < 0) { | |
116 | link_enter_failed(link); | |
117 | return; | |
118 | } | |
119 | break; | |
be19c5b5 | 120 | case SD_IPV4LL_EVENT_CONFLICT: |
b22d8a00 TG |
121 | r = ipv4ll_address_lost(link); |
122 | if (r < 0) { | |
123 | link_enter_failed(link); | |
124 | return; | |
125 | } | |
0698ff41 JR |
126 | |
127 | r = sd_ipv4ll_restart(ll); | |
128 | if (r < 0) | |
aa5f4c77 | 129 | log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m"); |
b22d8a00 | 130 | break; |
be19c5b5 | 131 | case SD_IPV4LL_EVENT_BIND: |
b22d8a00 TG |
132 | r = ipv4ll_address_claimed(ll, link); |
133 | if (r < 0) { | |
79316750 | 134 | log_link_error(link, "Failed to configure ipv4ll address: %m"); |
b22d8a00 TG |
135 | link_enter_failed(link); |
136 | return; | |
137 | } | |
138 | break; | |
139 | default: | |
b45e4eb6 | 140 | log_link_warning(link, "IPv4 link-local unknown event: %d", event); |
b22d8a00 TG |
141 | break; |
142 | } | |
143 | } | |
144 | ||
145 | int ipv4ll_configure(Link *link) { | |
dbe81cbd | 146 | uint64_t seed; |
b22d8a00 TG |
147 | int r; |
148 | ||
149 | assert(link); | |
150 | assert(link->network); | |
8bc17bb3 | 151 | assert(link->network->link_local & (ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4)); |
b22d8a00 | 152 | |
0bc70f1d TG |
153 | if (!link->ipv4ll) { |
154 | r = sd_ipv4ll_new(&link->ipv4ll); | |
155 | if (r < 0) | |
156 | return r; | |
08c588d1 YW |
157 | |
158 | r = sd_ipv4ll_attach_event(link->ipv4ll, NULL, 0); | |
159 | if (r < 0) | |
160 | return r; | |
0bc70f1d | 161 | } |
b22d8a00 | 162 | |
51517f9e | 163 | if (link->sd_device && |
96848152 | 164 | net_get_unique_predictable_data(link->sd_device, true, &seed) >= 0) { |
51517f9e YW |
165 | r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed); |
166 | if (r < 0) | |
167 | return r; | |
b22d8a00 TG |
168 | } |
169 | ||
b22d8a00 TG |
170 | r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac); |
171 | if (r < 0) | |
172 | return r; | |
173 | ||
2f8e7633 | 174 | r = sd_ipv4ll_set_ifindex(link->ipv4ll, link->ifindex); |
b22d8a00 TG |
175 | if (r < 0) |
176 | return r; | |
177 | ||
178 | r = sd_ipv4ll_set_callback(link->ipv4ll, ipv4ll_handler, link); | |
179 | if (r < 0) | |
180 | return r; | |
181 | ||
182 | return 0; | |
183 | } | |
ca5ad760 YW |
184 | |
185 | int config_parse_ipv4ll( | |
186 | const char* unit, | |
187 | const char *filename, | |
188 | unsigned line, | |
189 | const char *section, | |
190 | unsigned section_line, | |
191 | const char *lvalue, | |
192 | int ltype, | |
193 | const char *rvalue, | |
194 | void *data, | |
195 | void *userdata) { | |
196 | ||
2d792895 | 197 | AddressFamily *link_local = data; |
ca5ad760 YW |
198 | int r; |
199 | ||
200 | assert(filename); | |
201 | assert(lvalue); | |
202 | assert(rvalue); | |
203 | assert(data); | |
204 | ||
205 | /* Note that this is mostly like | |
2d792895 | 206 | * config_parse_address_family(), except that it |
ca5ad760 YW |
207 | * applies only to IPv4 */ |
208 | ||
209 | r = parse_boolean(rvalue); | |
210 | if (r < 0) { | |
211 | log_syntax(unit, LOG_ERR, filename, line, r, | |
212 | "Failed to parse %s=%s, ignoring assignment. " | |
213 | "Note that the setting %s= is deprecated, please use LinkLocalAddressing= instead.", | |
214 | lvalue, rvalue, lvalue); | |
215 | return 0; | |
216 | } | |
217 | ||
218 | SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, r); | |
219 | ||
220 | log_syntax(unit, LOG_WARNING, filename, line, 0, | |
221 | "%s=%s is deprecated, please use LinkLocalAddressing=%s instead.", | |
2d792895 | 222 | lvalue, rvalue, address_family_to_string(*link_local)); |
ca5ad760 YW |
223 | |
224 | return 0; | |
225 | } |