1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <netinet/in.h>
6 #include "netif-util.h"
7 #include "networkd-address.h"
8 #include "networkd-ipv4acd.h"
9 #include "networkd-ipv4ll.h"
10 #include "networkd-link.h"
11 #include "networkd-manager.h"
12 #include "networkd-queue.h"
13 #include "parse-util.h"
15 bool link_ipv4ll_enabled(Link
*link
) {
18 if (!link_ipv4acd_supported(link
))
24 if (link
->network
->bond
)
27 return link
->network
->link_local
& ADDRESS_FAMILY_IPV4
;
30 static int address_new_from_ipv4ll(Link
*link
, Address
**ret
) {
31 _cleanup_(address_freep
) Address
*address
= NULL
;
39 r
= sd_ipv4ll_get_address(link
->ipv4ll
, &addr
);
43 r
= address_new(&address
);
47 address
->source
= NETWORK_CONFIG_SOURCE_IPV4LL
;
48 address
->family
= AF_INET
;
49 address
->in_addr
.in
= addr
;
50 address
->prefixlen
= 16;
51 address
->scope
= RT_SCOPE_LINK
;
52 address
->route_metric
= IPV4LL_ROUTE_METRIC
;
53 address_set_broadcast(address
, link
);
55 *ret
= TAKE_PTR(address
);
59 static int ipv4ll_address_lost(Link
*link
) {
60 _cleanup_(address_freep
) Address
*address
= NULL
;
66 link
->ipv4ll_address_configured
= false;
68 r
= address_new_from_ipv4ll(link
, &address
);
74 if (address_get(link
, address
, &existing
) < 0)
77 if (existing
->source
!= NETWORK_CONFIG_SOURCE_IPV4LL
)
80 if (!address_exists(existing
))
83 log_link_debug(link
, "IPv4 link-local release "IPV4_ADDRESS_FMT_STR
,
84 IPV4_ADDRESS_FMT_VAL(address
->in_addr
.in
));
86 return address_remove(existing
);
89 static int ipv4ll_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Request
*req
, Link
*link
, Address
*address
) {
93 assert(!link
->ipv4ll_address_configured
);
95 r
= address_configure_handler_internal(rtnl
, m
, link
, "Could not set ipv4ll address");
99 link
->ipv4ll_address_configured
= true;
100 link_check_ready(link
);
105 static int ipv4ll_address_claimed(sd_ipv4ll
*ll
, Link
*link
) {
106 _cleanup_(address_freep
) Address
*address
= NULL
;
112 link
->ipv4ll_address_configured
= false;
114 r
= address_new_from_ipv4ll(link
, &address
);
120 log_link_debug(link
, "IPv4 link-local claim "IPV4_ADDRESS_FMT_STR
,
121 IPV4_ADDRESS_FMT_VAL(address
->in_addr
.in
));
123 return link_request_address(link
, address
, NULL
, ipv4ll_address_handler
, NULL
);
126 static void ipv4ll_handler(sd_ipv4ll
*ll
, int event
, void *userdata
) {
127 Link
*link
= ASSERT_PTR(userdata
);
130 assert(link
->network
);
132 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
136 case SD_IPV4LL_EVENT_STOP
:
137 r
= ipv4ll_address_lost(link
);
139 link_enter_failed(link
);
143 case SD_IPV4LL_EVENT_CONFLICT
:
144 r
= ipv4ll_address_lost(link
);
146 link_enter_failed(link
);
150 r
= sd_ipv4ll_restart(ll
);
152 log_link_warning_errno(link
, r
, "Could not acquire IPv4 link-local address: %m");
153 link_enter_failed(link
);
156 case SD_IPV4LL_EVENT_BIND
:
157 r
= ipv4ll_address_claimed(ll
, link
);
159 log_link_error(link
, "Failed to configure ipv4ll address: %m");
160 link_enter_failed(link
);
165 log_link_warning(link
, "IPv4 link-local unknown event: %d", event
);
170 static int ipv4ll_check_mac(sd_ipv4ll
*ll
, const struct ether_addr
*mac
, void *userdata
) {
171 Manager
*m
= ASSERT_PTR(userdata
);
172 struct hw_addr_data hw_addr
;
176 hw_addr
= (struct hw_addr_data
) {
181 return link_get_by_hw_addr(m
, &hw_addr
, NULL
) >= 0;
184 int ipv4ll_configure(Link
*link
) {
190 if (!link_ipv4ll_enabled(link
))
196 r
= sd_ipv4ll_new(&link
->ipv4ll
);
200 r
= sd_ipv4ll_attach_event(link
->ipv4ll
, link
->manager
->event
, 0);
205 net_get_unique_predictable_data(link
->dev
, true, &seed
) >= 0) {
206 r
= sd_ipv4ll_set_address_seed(link
->ipv4ll
, seed
);
211 r
= sd_ipv4ll_set_mac(link
->ipv4ll
, &link
->hw_addr
.ether
);
215 r
= sd_ipv4ll_set_ifindex(link
->ipv4ll
, link
->ifindex
);
219 r
= sd_ipv4ll_set_callback(link
->ipv4ll
, ipv4ll_handler
, link
);
223 return sd_ipv4ll_set_check_mac_callback(link
->ipv4ll
, ipv4ll_check_mac
, link
->manager
);
226 int ipv4ll_update_mac(Link
*link
) {
229 if (link
->hw_addr
.length
!= ETH_ALEN
)
231 if (ether_addr_is_null(&link
->hw_addr
.ether
))
236 return sd_ipv4ll_set_mac(link
->ipv4ll
, &link
->hw_addr
.ether
);
239 int config_parse_ipv4ll(
241 const char *filename
,
244 unsigned section_line
,
251 AddressFamily
*link_local
= ASSERT_PTR(data
);
258 /* Note that this is mostly like
259 * config_parse_address_family(), except that it
260 * applies only to IPv4 */
262 r
= parse_boolean(rvalue
);
264 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
265 "Failed to parse %s=%s, ignoring assignment. "
266 "Note that the setting %s= is deprecated, please use LinkLocalAddressing= instead.",
267 lvalue
, rvalue
, lvalue
);
271 SET_FLAG(*link_local
, ADDRESS_FAMILY_IPV4
, r
);
273 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
274 "%s=%s is deprecated, please use LinkLocalAddressing=%s instead.",
275 lvalue
, rvalue
, address_family_to_string(*link_local
));
280 int config_parse_ipv4ll_address(
282 const char *filename
,
285 unsigned section_line
,
292 union in_addr_union a
;
293 struct in_addr
*ipv4ll_address
= ASSERT_PTR(data
);
300 if (isempty(rvalue
)) {
301 *ipv4ll_address
= (struct in_addr
) {};
305 r
= in_addr_from_string(AF_INET
, rvalue
, &a
);
307 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
308 "Failed to parse %s=, ignoring assignment: %s", lvalue
, rvalue
);
311 if (!in4_addr_is_link_local_dynamic(&a
.in
)) {
312 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
313 "Specified address cannot be used as an IPv4 link local address, ignoring assignment: %s",
318 *ipv4ll_address
= a
.in
;