summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libsystemd-network/sd-ipv4ll.c96
1 files changed, 54 insertions, 42 deletions
diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c
index 0d5e46dd49..8f75b585e1 100644
--- a/src/libsystemd-network/sd-ipv4ll.c
+++ b/src/libsystemd-network/sd-ipv4ll.c
@@ -288,12 +288,49 @@ out:
return 1;
}
+static int ipv4ll_on_conflict(sd_ipv4ll *ll) {
+ int r;
+
+ assert(ll);
+
+ log_ipv4ll(ll, "CONFLICT");
+
+ ll = ipv4ll_client_notify(ll, IPV4LL_EVENT_CONFLICT);
+ if (!ll || ll->state == IPV4LL_STATE_STOPPED)
+ return 0;
+
+ ll->claimed_address = 0;
+
+ /* Pick a new address */
+ r = ipv4ll_pick_address(ll, &ll->address);
+ if (r < 0)
+ return r;
+
+ ll->fd = safe_close(ll->fd);
+
+ r = arp_network_bind_raw_socket(ll->index, ll->address, &ll->mac_addr);
+ if (r < 0)
+ return r;
+
+ ll->fd = r;
+
+ ll->conflict++;
+ ll->defend_window = 0;
+ ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_PROBE, 1);
+
+ if (ll->conflict >= MAX_CONFLICTS) {
+ log_ipv4ll(ll, "MAX_CONFLICTS");
+ ipv4ll_set_next_wakeup(ll, RATE_LIMIT_INTERVAL, PROBE_WAIT);
+ } else
+ ipv4ll_set_next_wakeup(ll, 0, PROBE_WAIT);
+
+ return 0;
+}
+
static int ipv4ll_on_packet(sd_event_source *s, int fd,
uint32_t revents, void *userdata) {
sd_ipv4ll *ll = userdata;
struct ether_arp packet;
- int conflicted = 0;
- usec_t time_now;
int r;
assert(ll);
@@ -306,59 +343,34 @@ static int ipv4ll_on_packet(sd_event_source *s, int fd,
if (IN_SET(ll->state, IPV4LL_STATE_ANNOUNCING, IPV4LL_STATE_RUNNING)) {
if (ipv4ll_arp_conflict(ll, &packet)) {
+ usec_t ts;
- r = sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now);
- if (r < 0)
- goto out;
+ assert_se(sd_event_now(ll->event, clock_boottime_or_monotonic(), &ts) >= 0);
/* Defend address */
- if (time_now > ll->defend_window) {
- ll->defend_window = time_now + DEFEND_INTERVAL * USEC_PER_SEC;
+ if (ts > ll->defend_window) {
+ ll->defend_window = ts + DEFEND_INTERVAL * USEC_PER_SEC;
r = arp_send_announcement(ll->fd, ll->index, ll->address, &ll->mac_addr);
if (r < 0) {
log_ipv4ll(ll, "Failed to send ARP announcement.");
goto out;
}
- } else
- conflicted = 1;
+ } else {
+ r = ipv4ll_on_conflict(ll);
+ if (r < 0)
+ goto out;
+ }
}
} else if (IN_SET(ll->state, IPV4LL_STATE_WAITING_PROBE,
IPV4LL_STATE_PROBING,
- IPV4LL_STATE_WAITING_ANNOUNCE))
- conflicted = ipv4ll_arp_probe_conflict(ll, &packet);
-
- if (conflicted) {
- log_ipv4ll(ll, "CONFLICT");
- ll = ipv4ll_client_notify(ll, IPV4LL_EVENT_CONFLICT);
- if (!ll || ll->state == IPV4LL_STATE_STOPPED)
- goto out;
-
- ll->claimed_address = 0;
-
- /* Pick a new address */
- r = ipv4ll_pick_address(ll, &ll->address);
- if (r < 0)
- goto out;
-
- ll->fd = safe_close(ll->fd);
-
- r = arp_network_bind_raw_socket(ll->index, ll->address, &ll->mac_addr);
- if (r < 0)
- goto out;
-
- ll->fd = r;
-
- ll->conflict++;
- ll->defend_window = 0;
- ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_PROBE, 1);
-
- if (ll->conflict >= MAX_CONFLICTS) {
- log_ipv4ll(ll, "MAX_CONFLICTS");
- ipv4ll_set_next_wakeup(ll, RATE_LIMIT_INTERVAL, PROBE_WAIT);
- } else
- ipv4ll_set_next_wakeup(ll, 0, PROBE_WAIT);
+ IPV4LL_STATE_WAITING_ANNOUNCE)) {
+ if (ipv4ll_arp_probe_conflict(ll, &packet)) {
+ r = ipv4ll_on_conflict(ll);
+ if (r < 0)
+ goto out;
+ }
}
out: