sd-ipv4ll: split out on_conflict() from on_packet()

This commit is contained in:
Tom Gundersen
2015-09-18 15:14:42 +02:00
parent 8e5787b5e0
commit b26f7e8ec9
+54 -42
View File
@@ -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: