1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <netinet/in.h>
4 #include <linux/if.h>
5
6 #include "netif-util.h"
7 #include "networkd-address.h"
8 #include "networkd-ipv4ll.h"
9 #include "networkd-link.h"
10 #include "networkd-manager.h"
11 #include "networkd-queue.h"
12 #include "parse-util.h"
13
address_new_from_ipv4ll(Link * link,Address ** ret)14 static int address_new_from_ipv4ll(Link *link, Address **ret) {
15 _cleanup_(address_freep) Address *address = NULL;
16 struct in_addr addr;
17 int r;
18
19 assert(link);
20 assert(link->ipv4ll);
21 assert(ret);
22
23 r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
24 if (r < 0)
25 return r;
26
27 r = address_new(&address);
28 if (r < 0)
29 return -ENOMEM;
30
31 address->source = NETWORK_CONFIG_SOURCE_IPV4LL;
32 address->family = AF_INET;
33 address->in_addr.in = addr;
34 address->prefixlen = 16;
35 address->scope = RT_SCOPE_LINK;
36 address->route_metric = IPV4LL_ROUTE_METRIC;
37 address_set_broadcast(address, link);
38
39 *ret = TAKE_PTR(address);
40 return 0;
41 }
42
ipv4ll_address_lost(Link * link)43 static int ipv4ll_address_lost(Link *link) {
44 _cleanup_(address_freep) Address *address = NULL;
45 Address *existing;
46 int r;
47
48 assert(link);
49
50 link->ipv4ll_address_configured = false;
51
52 r = address_new_from_ipv4ll(link, &address);
53 if (r == -ENOENT)
54 return 0;
55 if (r < 0)
56 return r;
57
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
67 log_link_debug(link, "IPv4 link-local release "IPV4_ADDRESS_FMT_STR,
68 IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
69
70 return address_remove(existing);
71 }
72
ipv4ll_address_handler(sd_netlink * rtnl,sd_netlink_message * m,Request * req,Link * link,Address * address)73 static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) {
74 int r;
75
76 assert(link);
77 assert(!link->ipv4ll_address_configured);
78
79 r = address_configure_handler_internal(rtnl, m, link, "Could not set ipv4ll address");
80 if (r <= 0)
81 return r;
82
83 link->ipv4ll_address_configured = true;
84 link_check_ready(link);
85
86 return 1;
87 }
88
ipv4ll_address_claimed(sd_ipv4ll * ll,Link * link)89 static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
90 _cleanup_(address_freep) Address *address = NULL;
91 int r;
92
93 assert(ll);
94 assert(link);
95
96 link->ipv4ll_address_configured = false;
97
98 r = address_new_from_ipv4ll(link, &address);
99 if (r == -ENOENT)
100 return 0;
101 if (r < 0)
102 return r;
103
104 log_link_debug(link, "IPv4 link-local claim "IPV4_ADDRESS_FMT_STR,
105 IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
106
107 return link_request_address(link, TAKE_PTR(address), true, NULL, ipv4ll_address_handler, NULL);
108 }
109
ipv4ll_handler(sd_ipv4ll * ll,int event,void * userdata)110 static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
111 Link *link = userdata;
112 int r;
113
114 assert(link);
115 assert(link->network);
116
117 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
118 return;
119
120 switch (event) {
121 case SD_IPV4LL_EVENT_STOP:
122 r = ipv4ll_address_lost(link);
123 if (r < 0) {
124 link_enter_failed(link);
125 return;
126 }
127 break;
128 case SD_IPV4LL_EVENT_CONFLICT:
129 r = ipv4ll_address_lost(link);
130 if (r < 0) {
131 link_enter_failed(link);
132 return;
133 }
134
135 r = sd_ipv4ll_restart(ll);
136 if (r < 0) {
137 log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
138 link_enter_failed(link);
139 }
140 break;
141 case SD_IPV4LL_EVENT_BIND:
142 r = ipv4ll_address_claimed(ll, link);
143 if (r < 0) {
144 log_link_error(link, "Failed to configure ipv4ll address: %m");
145 link_enter_failed(link);
146 return;
147 }
148 break;
149 default:
150 log_link_warning(link, "IPv4 link-local unknown event: %d", event);
151 break;
152 }
153 }
154
ipv4ll_check_mac(sd_ipv4ll * ll,const struct ether_addr * mac,void * userdata)155 static 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
ipv4ll_configure(Link * link)170 int ipv4ll_configure(Link *link) {
171 uint64_t seed;
172 int r;
173
174 assert(link);
175
176 if (!link_ipv4ll_enabled(link))
177 return 0;
178
179 if (link->ipv4ll)
180 return -EBUSY;
181
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;
189
190 if (link->sd_device &&
191 net_get_unique_predictable_data(link->sd_device, true, &seed) >= 0) {
192 r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed);
193 if (r < 0)
194 return r;
195 }
196
197 r = sd_ipv4ll_set_mac(link->ipv4ll, &link->hw_addr.ether);
198 if (r < 0)
199 return r;
200
201 r = sd_ipv4ll_set_ifindex(link->ipv4ll, link->ifindex);
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
209 return sd_ipv4ll_set_check_mac_callback(link->ipv4ll, ipv4ll_check_mac, link->manager);
210 }
211
ipv4ll_update_mac(Link * link)212 int ipv4ll_update_mac(Link *link) {
213 assert(link);
214
215 if (link->hw_addr.length != ETH_ALEN)
216 return 0;
217 if (ether_addr_is_null(&link->hw_addr.ether))
218 return 0;
219 if (!link->ipv4ll)
220 return 0;
221
222 return sd_ipv4ll_set_mac(link->ipv4ll, &link->hw_addr.ether);
223 }
224
config_parse_ipv4ll(const char * unit,const char * filename,unsigned line,const char * section,unsigned section_line,const char * lvalue,int ltype,const char * rvalue,void * data,void * userdata)225 int 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
237 AddressFamily *link_local = data;
238 int r;
239
240 assert(filename);
241 assert(lvalue);
242 assert(rvalue);
243 assert(data);
244
245 /* Note that this is mostly like
246 * config_parse_address_family(), except that it
247 * applies only to IPv4 */
248
249 r = parse_boolean(rvalue);
250 if (r < 0) {
251 log_syntax(unit, LOG_WARNING, filename, line, r,
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.",
262 lvalue, rvalue, address_family_to_string(*link_local));
263
264 return 0;
265 }
266