]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-ipv4ll.c
network: compare addresses more strictly
[thirdparty/systemd.git] / src / network / networkd-ipv4ll.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
b22d8a00 2
9aa5d8ba 3#include <netinet/in.h>
b22d8a00
TG
4#include <linux/if.h>
5
b5cc5591 6#include "netif-util.h"
23f53b99 7#include "networkd-address.h"
ca5ad760 8#include "networkd-ipv4ll.h"
23f53b99 9#include "networkd-link.h"
ca5ad760 10#include "networkd-manager.h"
76c5a0f2 11#include "networkd-queue.h"
ca5ad760 12#include "parse-util.h"
b22d8a00 13
76c5a0f2 14static int address_new_from_ipv4ll(Link *link, Address **ret) {
8e766630 15 _cleanup_(address_freep) Address *address = NULL;
b22d8a00
TG
16 struct in_addr addr;
17 int r;
18
19 assert(link);
76c5a0f2
YW
20 assert(link->ipv4ll);
21 assert(ret);
b22d8a00
TG
22
23 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
24 if (r < 0)
76c5a0f2 25 return r;
b22d8a00 26
f0213e37 27 r = address_new(&address);
fc95c359 28 if (r < 0)
76c5a0f2 29 return -ENOMEM;
b22d8a00 30
3b6a3bde 31 address->source = NETWORK_CONFIG_SOURCE_IPV4LL;
b22d8a00
TG
32 address->family = AF_INET;
33 address->in_addr.in = addr;
34 address->prefixlen = 16;
35 address->scope = RT_SCOPE_LINK;
76c5a0f2 36 address->route_metric = IPV4LL_ROUTE_METRIC;
473680be 37 address_set_broadcast(address);
76c5a0f2
YW
38
39 *ret = TAKE_PTR(address);
40 return 0;
41}
42
43static int ipv4ll_address_lost(Link *link) {
44 _cleanup_(address_freep) Address *address = NULL;
3b6a3bde 45 Address *existing;
76c5a0f2
YW
46 int r;
47
48 assert(link);
b22d8a00 49
76c5a0f2
YW
50 link->ipv4ll_address_configured = false;
51
52 r = address_new_from_ipv4ll(link, &address);
53 if (r == -ENOENT)
54 return 0;
807341ec
YW
55 if (r < 0)
56 return r;
b22d8a00 57
3b6a3bde
YW
58 if (address_get(link, address, &existing) < 0)
59 return 0;
60
61 if (existing->source != NETWORK_CONFIG_SOURCE_IPV4LL)
62 return 0;
63
64 if (!address_exists(existing))
65 return 0;
66
76c5a0f2
YW
67 log_link_debug(link, "IPv4 link-local release "IPV4_ADDRESS_FMT_STR,
68 IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
b22d8a00 69
3b6a3bde 70 return address_remove(existing);
b22d8a00
TG
71}
72
302a796f 73static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
b22d8a00
TG
74 int r;
75
76 assert(link);
1c09d84e 77 assert(!link->ipv4ll_address_configured);
b22d8a00 78
5a07fa9d
YW
79 r = address_configure_handler_internal(rtnl, m, link, "Could not set ipv4ll address");
80 if (r <= 0)
81 return r;
b22d8a00 82
1c09d84e 83 link->ipv4ll_address_configured = true;
2aa7d367 84 link_check_ready(link);
b22d8a00
TG
85
86 return 1;
87}
88
89static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
76c5a0f2 90 _cleanup_(address_freep) Address *address = NULL;
b22d8a00
TG
91 int r;
92
93 assert(ll);
94 assert(link);
95
1c09d84e 96 link->ipv4ll_address_configured = false;
79316750 97
76c5a0f2 98 r = address_new_from_ipv4ll(link, &address);
b22d8a00
TG
99 if (r == -ENOENT)
100 return 0;
b22d8a00
TG
101 if (r < 0)
102 return r;
103
76c5a0f2
YW
104 log_link_debug(link, "IPv4 link-local claim "IPV4_ADDRESS_FMT_STR,
105 IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
b22d8a00 106
76c5a0f2 107 return link_request_address(link, TAKE_PTR(address), true, NULL, ipv4ll_address_handler, NULL);
b22d8a00
TG
108}
109
9ed794a3 110static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
b22d8a00
TG
111 Link *link = userdata;
112 int r;
113
114 assert(link);
115 assert(link->network);
b22d8a00
TG
116
117 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
118 return;
119
89346ac6 120 switch (event) {
be19c5b5 121 case SD_IPV4LL_EVENT_STOP:
0698ff41
JR
122 r = ipv4ll_address_lost(link);
123 if (r < 0) {
124 link_enter_failed(link);
125 return;
126 }
127 break;
be19c5b5 128 case SD_IPV4LL_EVENT_CONFLICT:
b22d8a00
TG
129 r = ipv4ll_address_lost(link);
130 if (r < 0) {
131 link_enter_failed(link);
132 return;
133 }
0698ff41
JR
134
135 r = sd_ipv4ll_restart(ll);
89d8ed99 136 if (r < 0) {
aa5f4c77 137 log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
89d8ed99
YW
138 link_enter_failed(link);
139 }
b22d8a00 140 break;
be19c5b5 141 case SD_IPV4LL_EVENT_BIND:
b22d8a00
TG
142 r = ipv4ll_address_claimed(ll, link);
143 if (r < 0) {
79316750 144 log_link_error(link, "Failed to configure ipv4ll address: %m");
b22d8a00
TG
145 link_enter_failed(link);
146 return;
147 }
148 break;
149 default:
b45e4eb6 150 log_link_warning(link, "IPv4 link-local unknown event: %d", event);
b22d8a00
TG
151 break;
152 }
153}
154
d7ab6ef0
YW
155static int ipv4ll_check_mac(sd_ipv4ll *ll, const struct ether_addr *mac, void *userdata) {
156 Manager *m = userdata;
157 struct hw_addr_data hw_addr;
158
159 assert(m);
160 assert(mac);
161
162 hw_addr = (struct hw_addr_data) {
163 .length = ETH_ALEN,
164 .ether = *mac,
165 };
166
167 return link_get_by_hw_addr(m, &hw_addr, NULL) >= 0;
168}
169
b22d8a00 170int ipv4ll_configure(Link *link) {
dbe81cbd 171 uint64_t seed;
b22d8a00
TG
172 int r;
173
174 assert(link);
2ffd6d73 175
3ca1fab7 176 if (!link_ipv4ll_enabled(link))
2ffd6d73 177 return 0;
b22d8a00 178
bc9e40c9
YW
179 if (link->ipv4ll)
180 return -EBUSY;
ca97e7cd 181
bc9e40c9
YW
182 r = sd_ipv4ll_new(&link->ipv4ll);
183 if (r < 0)
184 return r;
185
186 r = sd_ipv4ll_attach_event(link->ipv4ll, link->manager->event, 0);
187 if (r < 0)
188 return r;
b22d8a00 189
51517f9e 190 if (link->sd_device &&
96848152 191 net_get_unique_predictable_data(link->sd_device, true, &seed) >= 0) {
51517f9e
YW
192 r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
193 if (r < 0)
194 return r;
b22d8a00
TG
195 }
196
ca2b7cd8 197 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->hw_addr.ether);
b22d8a00
TG
198 if (r < 0)
199 return r;
200
2f8e7633 201 r = sd_ipv4ll_set_ifindex(link->ipv4ll, link->ifindex);
b22d8a00
TG
202 if (r < 0)
203 return r;
204
205 r = sd_ipv4ll_set_callback(link->ipv4ll, ipv4ll_handler, link);
206 if (r < 0)
207 return r;
208
d7ab6ef0 209 return sd_ipv4ll_set_check_mac_callback(link->ipv4ll, ipv4ll_check_mac, link->manager);
b22d8a00 210}
ca5ad760 211
a3adb4a6 212int ipv4ll_update_mac(Link *link) {
a3adb4a6
YW
213 assert(link);
214
f8d6397a
YW
215 if (link->hw_addr.length != ETH_ALEN)
216 return 0;
217 if (ether_addr_is_null(&link->hw_addr.ether))
218 return 0;
a3adb4a6
YW
219 if (!link->ipv4ll)
220 return 0;
221
f8d6397a 222 return sd_ipv4ll_set_mac(link->ipv4ll, &link->hw_addr.ether);
a3adb4a6
YW
223}
224
ca5ad760
YW
225int config_parse_ipv4ll(
226 const char* unit,
227 const char *filename,
228 unsigned line,
229 const char *section,
230 unsigned section_line,
231 const char *lvalue,
232 int ltype,
233 const char *rvalue,
234 void *data,
235 void *userdata) {
236
2d792895 237 AddressFamily *link_local = data;
ca5ad760
YW
238 int r;
239
240 assert(filename);
241 assert(lvalue);
242 assert(rvalue);
243 assert(data);
244
245 /* Note that this is mostly like
2d792895 246 * config_parse_address_family(), except that it
ca5ad760
YW
247 * applies only to IPv4 */
248
249 r = parse_boolean(rvalue);
250 if (r < 0) {
d96edb2c 251 log_syntax(unit, LOG_WARNING, filename, line, r,
ca5ad760
YW
252 "Failed to parse %s=%s, ignoring assignment. "
253 "Note that the setting %s= is deprecated, please use LinkLocalAddressing= instead.",
254 lvalue, rvalue, lvalue);
255 return 0;
256 }
257
258 SET_FLAG(*link_local, ADDRESS_FAMILY_IPV4, r);
259
260 log_syntax(unit, LOG_WARNING, filename, line, 0,
261 "%s=%s is deprecated, please use LinkLocalAddressing=%s instead.",
2d792895 262 lvalue, rvalue, address_family_to_string(*link_local));
ca5ad760
YW
263
264 return 0;
265}