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
;
54 *ret
= TAKE_PTR(address
);
58 static int ipv4ll_address_lost(Link
*link
) {
59 _cleanup_(address_freep
) Address
*address
= NULL
;
65 link
->ipv4ll_address_configured
= false;
67 r
= address_new_from_ipv4ll(link
, &address
);
73 if (address_get(link
, address
, &existing
) < 0)
76 if (existing
->source
!= NETWORK_CONFIG_SOURCE_IPV4LL
)
79 if (!address_exists(existing
))
82 log_link_debug(link
, "IPv4 link-local release "IPV4_ADDRESS_FMT_STR
,
83 IPV4_ADDRESS_FMT_VAL(address
->in_addr
.in
));
85 return address_remove(existing
);
88 static int ipv4ll_address_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Request
*req
, Link
*link
, Address
*address
) {
92 assert(!link
->ipv4ll_address_configured
);
94 r
= address_configure_handler_internal(rtnl
, m
, link
, "Could not set ipv4ll address");
98 link
->ipv4ll_address_configured
= true;
99 link_check_ready(link
);
104 static int ipv4ll_address_claimed(sd_ipv4ll
*ll
, Link
*link
) {
105 _cleanup_(address_freep
) Address
*address
= NULL
;
111 link
->ipv4ll_address_configured
= false;
113 r
= address_new_from_ipv4ll(link
, &address
);
119 log_link_debug(link
, "IPv4 link-local claim "IPV4_ADDRESS_FMT_STR
,
120 IPV4_ADDRESS_FMT_VAL(address
->in_addr
.in
));
122 return link_request_address(link
, address
, NULL
, ipv4ll_address_handler
, NULL
);
125 static void ipv4ll_handler(sd_ipv4ll
*ll
, int event
, void *userdata
) {
126 Link
*link
= ASSERT_PTR(userdata
);
129 assert(link
->network
);
131 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
135 case SD_IPV4LL_EVENT_STOP
:
136 r
= ipv4ll_address_lost(link
);
138 link_enter_failed(link
);
142 case SD_IPV4LL_EVENT_CONFLICT
:
143 r
= ipv4ll_address_lost(link
);
145 link_enter_failed(link
);
149 r
= sd_ipv4ll_restart(ll
);
151 log_link_warning_errno(link
, r
, "Could not acquire IPv4 link-local address: %m");
152 link_enter_failed(link
);
155 case SD_IPV4LL_EVENT_BIND
:
156 r
= ipv4ll_address_claimed(ll
, link
);
158 log_link_error(link
, "Failed to configure ipv4ll address: %m");
159 link_enter_failed(link
);
164 log_link_warning(link
, "IPv4 link-local unknown event: %d", event
);
169 static int ipv4ll_check_mac(sd_ipv4ll
*ll
, const struct ether_addr
*mac
, void *userdata
) {
170 Manager
*m
= ASSERT_PTR(userdata
);
171 struct hw_addr_data hw_addr
;
175 hw_addr
= (struct hw_addr_data
) {
180 return link_get_by_hw_addr(m
, &hw_addr
, NULL
) >= 0;
183 int ipv4ll_configure(Link
*link
) {
189 if (!link_ipv4ll_enabled(link
))
195 r
= sd_ipv4ll_new(&link
->ipv4ll
);
199 r
= sd_ipv4ll_attach_event(link
->ipv4ll
, link
->manager
->event
, 0);
204 net_get_unique_predictable_data(link
->dev
, true, &seed
) >= 0) {
205 r
= sd_ipv4ll_set_address_seed(link
->ipv4ll
, seed
);
210 r
= sd_ipv4ll_set_mac(link
->ipv4ll
, &link
->hw_addr
.ether
);
214 r
= sd_ipv4ll_set_ifindex(link
->ipv4ll
, link
->ifindex
);
218 r
= sd_ipv4ll_set_callback(link
->ipv4ll
, ipv4ll_handler
, link
);
222 return sd_ipv4ll_set_check_mac_callback(link
->ipv4ll
, ipv4ll_check_mac
, link
->manager
);
225 int ipv4ll_update_mac(Link
*link
) {
228 if (link
->hw_addr
.length
!= ETH_ALEN
)
230 if (ether_addr_is_null(&link
->hw_addr
.ether
))
235 return sd_ipv4ll_set_mac(link
->ipv4ll
, &link
->hw_addr
.ether
);
238 int config_parse_ipv4ll(
240 const char *filename
,
243 unsigned section_line
,
250 AddressFamily
*link_local
= ASSERT_PTR(data
);
257 /* Note that this is mostly like
258 * config_parse_address_family(), except that it
259 * applies only to IPv4 */
261 r
= parse_boolean(rvalue
);
263 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
264 "Failed to parse %s=%s, ignoring assignment. "
265 "Note that the setting %s= is deprecated, please use LinkLocalAddressing= instead.",
266 lvalue
, rvalue
, lvalue
);
270 SET_FLAG(*link_local
, ADDRESS_FAMILY_IPV4
, r
);
272 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
273 "%s=%s is deprecated, please use LinkLocalAddressing=%s instead.",
274 lvalue
, rvalue
, address_family_to_string(*link_local
));
279 int config_parse_ipv4ll_address(
281 const char *filename
,
284 unsigned section_line
,
291 union in_addr_union a
;
292 struct in_addr
*ipv4ll_address
= ASSERT_PTR(data
);
299 if (isempty(rvalue
)) {
300 *ipv4ll_address
= (struct in_addr
) {};
304 r
= in_addr_from_string(AF_INET
, rvalue
, &a
);
306 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
307 "Failed to parse %s=, ignoring assignment: %s", lvalue
, rvalue
);
310 if (!in4_addr_is_link_local_dynamic(&a
.in
)) {
311 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
312 "Specified address cannot be used as an IPv4 link local address, ignoring assignment: %s",
317 *ipv4ll_address
= a
.in
;