bool address_is_ready(const Address *a) {
assert(a);
- if (FLAGS_SET(a->flags, IFA_F_TENTATIVE))
+ if (!ipv4acd_bound(a))
return false;
- if (FLAGS_SET(a->state, NETWORK_CONFIG_STATE_REMOVING))
+ if (FLAGS_SET(a->flags, IFA_F_TENTATIVE))
return false;
- if (FLAGS_SET(a->state, NETWORK_CONFIG_STATE_PROBING))
+ if (FLAGS_SET(a->state, NETWORK_CONFIG_STATE_REMOVING))
return false;
if (!FLAGS_SET(a->state, NETWORK_CONFIG_STATE_CONFIGURED))
if (!link_is_ready_to_configure(link, false))
return false;
- if (FLAGS_SET(address->state, NETWORK_CONFIG_STATE_PROBING))
+ if (!ipv4acd_bound(address))
return false;
/* Refuse adding more than the limit */
* To control DAD for IPv6 dynamic addresses, set IFA_F_NODAD to flags. */
AddressFamily duplicate_address_detection;
sd_ipv4acd *acd;
+ bool acd_bound;
/* Called when address become ready */
address_ready_callback_t callback;
int address_compare_func(const Address *a1, const Address *a2);
DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(Address, address);
-static inline void address_enter_probing(Address *address) {
- address_update_state(address, NETWORK_CONFIG_STATE_PROBING, NETWORK_CONFIG_STATE_PROBING);
-}
-static inline void address_cancel_probing(Address *address) {
- address_update_state(address, NETWORK_CONFIG_STATE_PROBING, 0);
-}
void link_mark_addresses(Link *link, NetworkConfigSource source, const struct in6_addr *router);
return true;
}
+bool ipv4acd_bound(const Address *address) {
+ assert(address);
+
+ if (!address->acd)
+ return true;
+
+ return address->acd_bound;
+}
+
static int static_ipv4acd_address_remove(Link *link, Address *address, bool on_conflict) {
int r;
assert(link);
assert(address);
- /* Prevent form the address being freed. */
- address_enter_probing(address);
-
if (!address_exists(address))
return 0; /* Not assigned. */
if (r < 0)
return log_link_warning_errno(link, r, "Failed to drop DHCPv4 lease: %m");
- /* make the address will be freed. */
- address_cancel_probing(address);
-
/* It is not necessary to call address_remove() here, as dhcp4_lease_lost() removes it. */
return 0;
}
switch (event) {
case SD_IPV4ACD_EVENT_STOP:
+ address->acd_bound = false;
+
if (address->source == NETWORK_CONFIG_SOURCE_STATIC) {
r = static_ipv4acd_address_remove(link, address, /* on_conflict = */ false);
if (r < 0)
break;
case SD_IPV4ACD_EVENT_BIND:
+ address->acd_bound = true;
+
log_link_debug(link, "Successfully claimed address "IPV4_ADDRESS_FMT_STR,
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
-
- address_cancel_probing(address);
break;
case SD_IPV4ACD_EVENT_CONFLICT:
+ address->acd_bound = false;
+
log_link_warning(link, "Dropping address "IPV4_ADDRESS_FMT_STR", as an address conflict was detected.",
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
return link_get_by_hw_addr(m, &hw_addr, NULL) >= 0;
}
+static int address_ipv4acd_start(Address *address) {
+ assert(address);
+ assert(address->link);
+
+ if (!address->acd)
+ return 0;
+
+ if (sd_ipv4acd_is_running(address->acd))
+ return 0;
+
+ if (!link_has_carrier(address->link))
+ return 0;
+
+ return sd_ipv4acd_start(address->acd, true);
+}
+
int ipv4acd_configure(Address *address) {
Link *link;
int r;
/* Currently, only static and DHCP4 addresses are supported. */
assert(IN_SET(address->source, NETWORK_CONFIG_SOURCE_STATIC, NETWORK_CONFIG_SOURCE_DHCP4));
- if (address->acd) {
- address_enter_probing(address);
- return 0;
- }
+ if (address->acd)
+ return address_ipv4acd_start(address);
log_link_debug(link, "Configuring IPv4ACD for address "IPV4_ADDRESS_FMT_STR,
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
if (r < 0)
return r;
- if (link_has_carrier(link)) {
- r = sd_ipv4acd_start(address->acd, true);
- if (r < 0)
- return r;
- }
-
- address_enter_probing(address);
- return 0;
+ return address_ipv4acd_start(address);
}
int ipv4acd_update_mac(Link *link) {
assert(link);
SET_FOREACH(address, link->addresses) {
- if (!address->acd)
- continue;
-
- if (sd_ipv4acd_is_running(address->acd))
- continue;
-
- r = sd_ipv4acd_start(address->acd, true);
+ r = address_ipv4acd_start(address);
if (r < 0)
return r;
}
typedef struct Link Link;
bool link_ipv4acd_supported(Link *link);
+bool ipv4acd_bound(const Address *address);
int ipv4acd_configure(Address *address);
int ipv4acd_update_mac(Link *link);
int ipv4acd_start(Link *link);
int network_config_state_to_string_alloc(NetworkConfigState s, char **ret) {
static const char* states[] = {
- [LOG2U(NETWORK_CONFIG_STATE_PROBING)] = "probing",
[LOG2U(NETWORK_CONFIG_STATE_REQUESTING)] = "requesting",
[LOG2U(NETWORK_CONFIG_STATE_CONFIGURING)] = "configuring",
[LOG2U(NETWORK_CONFIG_STATE_CONFIGURED)] = "configured",
} NetworkConfigSource;
typedef enum NetworkConfigState {
- NETWORK_CONFIG_STATE_PROBING = 1 << 0, /* address is probing by IPv4ACD */
- NETWORK_CONFIG_STATE_REQUESTING = 1 << 1, /* request is queued */
- NETWORK_CONFIG_STATE_CONFIGURING = 1 << 2, /* e.g. address_configure() is called, but no response is received yet */
- NETWORK_CONFIG_STATE_CONFIGURED = 1 << 3, /* e.g. address_configure() is called and received a response from kernel.
+ NETWORK_CONFIG_STATE_REQUESTING = 1 << 0, /* request is queued */
+ NETWORK_CONFIG_STATE_CONFIGURING = 1 << 1, /* e.g. address_configure() is called, but no response is received yet */
+ NETWORK_CONFIG_STATE_CONFIGURED = 1 << 2, /* e.g. address_configure() is called and received a response from kernel.
* Note that address may not be ready yet, so please use address_is_ready()
* to check whether the address can be usable or not. */
- NETWORK_CONFIG_STATE_MARKED = 1 << 4, /* used GC'ing the old config */
- NETWORK_CONFIG_STATE_REMOVING = 1 << 5, /* e.g. address_remove() is called, but no response is received yet */
+ NETWORK_CONFIG_STATE_MARKED = 1 << 3, /* used GC'ing the old config */
+ NETWORK_CONFIG_STATE_REMOVING = 1 << 4, /* e.g. address_remove() is called, but no response is received yet */
} NetworkConfigState;
static inline usec_t sec16_to_usec(uint16_t sec, usec_t timestamp_usec) {