diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/libsystemd-network/sd-ipv4ll.c | 188 |
1 files changed, 82 insertions, 106 deletions
diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c index f292a9dba9..0d5e46dd49 100644 --- a/src/libsystemd-network/sd-ipv4ll.c +++ b/src/libsystemd-network/sd-ipv4ll.c @@ -48,14 +48,6 @@ #define log_ipv4ll(ll, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "IPv4LL: " fmt, ##__VA_ARGS__) -typedef enum IPv4LLTrigger{ - IPV4LL_TRIGGER_NULL, - IPV4LL_TRIGGER_PACKET, - IPV4LL_TRIGGER_TIMEOUT, - _IPV4LL_TRIGGER_MAX, - _IPV4LL_TRIGGER_INVALID = -1 -} IPv4LLTrigger; - typedef enum IPv4LLState { IPV4LL_STATE_INIT, IPV4LL_STATE_WAITING_PROBE, @@ -93,8 +85,6 @@ struct sd_ipv4ll { void* userdata; }; -static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void *trigger_data); - static void ipv4ll_set_state(sd_ipv4ll *ll, IPv4LLState st, int reset_counter) { assert(ll); @@ -163,17 +153,6 @@ static int ipv4ll_pick_address(sd_ipv4ll *ll, be32_t *address) { return 0; } -static int ipv4ll_timer(sd_event_source *s, uint64_t usec, void *userdata) { - sd_ipv4ll *ll = (sd_ipv4ll*)userdata; - - assert(ll); - - ll->next_wakeup_valid = 0; - ipv4ll_run_state_machine(ll, IPV4LL_TRIGGER_TIMEOUT, NULL); - - return 0; -} - static void ipv4ll_set_next_wakeup(sd_ipv4ll *ll, int sec, int random_sec) { usec_t next_timeout = 0; usec_t time_now = 0; @@ -216,11 +195,11 @@ static bool ipv4ll_arp_probe_conflict (sd_ipv4ll *ll, struct ether_arp *arp) { return false; } -static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void *trigger_data) { +static int ipv4ll_on_timeout(sd_event_source *s, uint64_t usec, void *userdata) { + sd_ipv4ll *ll = userdata; int r = 0; assert(ll); - assert(trigger < _IPV4LL_TRIGGER_MAX); if (ll->state == IPV4LL_STATE_INIT) { @@ -228,8 +207,8 @@ static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_PROBE, 1); ipv4ll_set_next_wakeup(ll, 0, PROBE_WAIT); - } else if ((ll->state == IPV4LL_STATE_WAITING_PROBE && trigger == IPV4LL_TRIGGER_TIMEOUT) || - (ll->state == IPV4LL_STATE_PROBING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration < PROBE_NUM-2)) { + } else if (ll->state == IPV4LL_STATE_WAITING_PROBE || + (ll->state == IPV4LL_STATE_PROBING && ll->iteration < PROBE_NUM-2)) { /* Send a probe */ r = arp_send_probe(ll->fd, ll->index, ll->address, &ll->mac_addr); @@ -242,7 +221,7 @@ static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void ipv4ll_set_next_wakeup(ll, PROBE_MIN, (PROBE_MAX-PROBE_MIN)); - } else if (ll->state == IPV4LL_STATE_PROBING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration >= PROBE_NUM-2) { + } else if (ll->state == IPV4LL_STATE_PROBING && ll->iteration >= PROBE_NUM-2) { /* Send the last probe */ r = arp_send_probe(ll->fd, ll->index, ll->address, &ll->mac_addr); @@ -255,8 +234,8 @@ static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void ipv4ll_set_next_wakeup(ll, ANNOUNCE_WAIT, 0); - } else if ((ll->state == IPV4LL_STATE_WAITING_ANNOUNCE && trigger == IPV4LL_TRIGGER_TIMEOUT) || - (ll->state == IPV4LL_STATE_ANNOUNCING && trigger == IPV4LL_TRIGGER_TIMEOUT && ll->iteration < ANNOUNCE_NUM-1)) { + } else if (ll->state == IPV4LL_STATE_WAITING_ANNOUNCE || + (ll->state == IPV4LL_STATE_ANNOUNCING && ll->iteration < ANNOUNCE_NUM-1)) { /* Send announcement packet */ r = arp_send_announcement(ll->fd, ll->index, ll->address, &ll->mac_addr); @@ -279,117 +258,114 @@ static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void ll->conflict = 0; } - } else if ((ll->state == IPV4LL_STATE_ANNOUNCING && trigger == IPV4LL_TRIGGER_TIMEOUT && + } else if ((ll->state == IPV4LL_STATE_ANNOUNCING && ll->iteration >= ANNOUNCE_NUM-1)) { ipv4ll_set_state(ll, IPV4LL_STATE_RUNNING, 0); ll->next_wakeup_valid = 0; + } - } else if (trigger == IPV4LL_TRIGGER_PACKET) { - - int conflicted = 0; - usec_t time_now; - struct ether_arp* in_packet = (struct ether_arp*)trigger_data; - - assert(in_packet); - - if (IN_SET(ll->state, IPV4LL_STATE_ANNOUNCING, IPV4LL_STATE_RUNNING)) { - - if (ipv4ll_arp_conflict(ll, in_packet)) { + if (ll->next_wakeup_valid) { + ll->timer = sd_event_source_unref(ll->timer); + r = sd_event_add_time(ll->event, &ll->timer, clock_boottime_or_monotonic(), + ll->next_wakeup, 0, ipv4ll_on_timeout, ll); + if (r < 0) + goto out; - r = sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now); - if (r < 0) - goto out; + r = sd_event_source_set_priority(ll->timer, ll->event_priority); + if (r < 0) + goto out; - /* Defend address */ - if (time_now > ll->defend_window) { - ll->defend_window = time_now + 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; - } + r = sd_event_source_set_description(ll->timer, "ipv4ll-timer"); + if (r < 0) + goto out; + } - } else - conflicted = 1; - } +out: + if (r < 0 && ll) + ipv4ll_stop(ll, r); - } else if (IN_SET(ll->state, IPV4LL_STATE_WAITING_PROBE, - IPV4LL_STATE_PROBING, - IPV4LL_STATE_WAITING_ANNOUNCE)) { + return 1; +} - conflicted = ipv4ll_arp_probe_conflict(ll, in_packet); - } +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; - if (conflicted) { - log_ipv4ll(ll, "CONFLICT"); - ll = ipv4ll_client_notify(ll, IPV4LL_EVENT_CONFLICT); - if (!ll || ll->state == IPV4LL_STATE_STOPPED) - goto out; + assert(ll); + assert(fd >= 0); - ll->claimed_address = 0; + r = read(fd, &packet, sizeof(struct ether_arp)); + if (r < (int) sizeof(struct ether_arp)) + goto out; - /* Pick a new address */ - r = ipv4ll_pick_address(ll, &ll->address); - if (r < 0) - goto out; + if (IN_SET(ll->state, IPV4LL_STATE_ANNOUNCING, IPV4LL_STATE_RUNNING)) { - ll->fd = safe_close(ll->fd); + if (ipv4ll_arp_conflict(ll, &packet)) { - r = arp_network_bind_raw_socket(ll->index, ll->address, &ll->mac_addr); + r = sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now); if (r < 0) goto out; - ll->fd = r; - - ll->conflict++; - ll->defend_window = 0; - ipv4ll_set_state(ll, IPV4LL_STATE_WAITING_PROBE, 1); + /* Defend address */ + if (time_now > ll->defend_window) { + ll->defend_window = time_now + 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; + } - 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); + conflicted = 1; } - } - if (ll->next_wakeup_valid) { - ll->timer = sd_event_source_unref(ll->timer); - r = sd_event_add_time(ll->event, &ll->timer, clock_boottime_or_monotonic(), - ll->next_wakeup, 0, ipv4ll_timer, ll); - if (r < 0) + } 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; - r = sd_event_source_set_priority(ll->timer, ll->event_priority); + ll->claimed_address = 0; + + /* Pick a new address */ + r = ipv4ll_pick_address(ll, &ll->address); if (r < 0) goto out; - r = sd_event_source_set_description(ll->timer, "ipv4ll-timer"); + 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); } out: if (r < 0 && ll) ipv4ll_stop(ll, r); -} -static int ipv4ll_receive_message(sd_event_source *s, int fd, - uint32_t revents, void *userdata) { - int r; - struct ether_arp arp; - sd_ipv4ll *ll = (sd_ipv4ll*)userdata; - - assert(ll); - - r = read(fd, &arp, sizeof(struct ether_arp)); - if (r < (int) sizeof(struct ether_arp)) - return 0; - - ipv4ll_run_state_machine(ll, IPV4LL_TRIGGER_PACKET, &arp); - - return 0; + return 1; } int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index) { @@ -564,7 +540,7 @@ int sd_ipv4ll_start (sd_ipv4ll *ll) { ipv4ll_set_state (ll, IPV4LL_STATE_INIT, 1); r = sd_event_add_io(ll->event, &ll->receive_message, ll->fd, - EPOLLIN, ipv4ll_receive_message, ll); + EPOLLIN, ipv4ll_on_packet, ll); if (r < 0) goto out; @@ -580,7 +556,7 @@ int sd_ipv4ll_start (sd_ipv4ll *ll) { &ll->timer, clock_boottime_or_monotonic(), now(clock_boottime_or_monotonic()), 0, - ipv4ll_timer, ll); + ipv4ll_on_timeout, ll); if (r < 0) goto out; |