X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flibsystemd-network%2Fsd-ipv4ll.c;h=8626d4afa993a32df288c8ced0ac91e3b582dab4;hb=820aced6f6067a6b7c57b7d36e44f64378870cbf;hp=7431af729e6cbcc999f3d52f62121197d0e01a25;hpb=b5db00e52ee2e20578839e4e4488f7b9af9abc38;p=elogind.git diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c index 7431af729..8626d4afa 100644 --- a/src/libsystemd-network/sd-ipv4ll.c +++ b/src/libsystemd-network/sd-ipv4ll.c @@ -26,6 +26,7 @@ #include "util.h" #include "siphash24.h" #include "list.h" +#include "refcnt.h" #include "ipv4ll-internal.h" #include "sd-ipv4ll.h" @@ -60,11 +61,14 @@ typedef enum IPv4LLState { IPV4LL_STATE_WAITING_ANNOUNCE, IPV4LL_STATE_ANNOUNCING, IPV4LL_STATE_RUNNING, + IPV4LL_STATE_STOPPED, _IPV4LL_STATE_MAX, _IPV4LL_STATE_INVALID = -1 } IPv4LLState; struct sd_ipv4ll { + RefCount n_ref; + IPv4LLState state; int index; int fd; @@ -103,16 +107,19 @@ static void ipv4ll_set_state(sd_ipv4ll *ll, IPv4LLState st, int reset_counter) { } } -static int ipv4ll_client_notify(sd_ipv4ll *ll, int event) { +static sd_ipv4ll *ipv4ll_client_notify(sd_ipv4ll *ll, int event) { assert(ll); - if (ll->cb) + if (ll->cb) { + ll = sd_ipv4ll_ref(ll); ll->cb(ll, event, ll->userdata); + ll = sd_ipv4ll_unref(ll); + } - return 0; + return ll; } -static int ipv4ll_stop(sd_ipv4ll *ll, int event) { +static sd_ipv4ll *ipv4ll_stop(sd_ipv4ll *ll, int event) { assert(ll); ll->receive_message = sd_event_source_unref(ll->receive_message); @@ -120,15 +127,16 @@ static int ipv4ll_stop(sd_ipv4ll *ll, int event) { ll->timer = sd_event_source_unref(ll->timer); - ipv4ll_client_notify(ll, event); - - ll->claimed_address = 0; + log_ipv4ll(ll, "STOPPED"); - ipv4ll_set_state (ll, IPV4LL_STATE_INIT, 1); + ll = ipv4ll_client_notify(ll, event); - log_ipv4ll(ll, "STOPPED"); + if (ll) { + ll->claimed_address = 0; + ipv4ll_set_state (ll, IPV4LL_STATE_INIT, 1); + } - return 0; + return ll; } static int ipv4ll_pick_address(sd_ipv4ll *ll, be32_t *address) { @@ -165,7 +173,7 @@ static int ipv4ll_timer(sd_event_source *s, uint64_t usec, void *userdata) { return 0; } -static void ipv4ll_set_next_wakeup (sd_ipv4ll *ll, int sec, int random_sec) { +static void ipv4ll_set_next_wakeup(sd_ipv4ll *ll, int sec, int random_sec) { usec_t next_timeout = 0; usec_t time_now = 0; @@ -178,8 +186,8 @@ static void ipv4ll_set_next_wakeup (sd_ipv4ll *ll, int sec, int random_sec) { if (random_sec) next_timeout += random_u32() % (random_sec * USEC_PER_SEC); - if (sd_event_get_now_monotonic(ll->event, &time_now) < 0) - time_now = now(CLOCK_MONOTONIC); + if (sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now) < 0) + time_now = now(clock_boottime_or_monotonic()); ll->next_wakeup = time_now + next_timeout; ll->next_wakeup_valid = 1; @@ -256,7 +264,10 @@ static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void if (ll->iteration == 0) { log_ipv4ll(ll, "ANNOUNCE"); ll->claimed_address = ll->address; - r = ipv4ll_client_notify(ll, IPV4LL_EVENT_BIND); + ll = ipv4ll_client_notify(ll, IPV4LL_EVENT_BIND); + if (!ll || ll->state == IPV4LL_STATE_STOPPED) + goto out; + ll->conflict = 0; } @@ -278,7 +289,7 @@ static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void if (ipv4ll_arp_conflict(ll, in_packet)) { - r = sd_event_get_now_monotonic(ll->event, &time_now); + r = sd_event_now(ll->event, clock_boottime_or_monotonic(), &time_now); if (r < 0) goto out; @@ -300,7 +311,10 @@ static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void if (conflicted) { log_ipv4ll(ll, "CONFLICT"); - r = ipv4ll_client_notify(ll, IPV4LL_EVENT_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 */ @@ -330,18 +344,22 @@ static void ipv4ll_run_state_machine(sd_ipv4ll *ll, IPv4LLTrigger trigger, void if (ll->next_wakeup_valid) { ll->timer = sd_event_source_unref(ll->timer); - r = sd_event_add_monotonic(ll->event, &ll->timer, - ll->next_wakeup, 0, ipv4ll_timer, ll); + r = sd_event_add_time(ll->event, &ll->timer, clock_boottime_or_monotonic(), + ll->next_wakeup, 0, ipv4ll_timer, ll); if (r < 0) goto out; r = sd_event_source_set_priority(ll->timer, ll->event_priority); if (r < 0) goto out; + + r = sd_event_source_set_description(ll->timer, "ipv4ll-timer"); + if (r < 0) + goto out; } out: - if (r < 0) + if (r < 0 && ll) ipv4ll_stop(ll, r); } @@ -368,8 +386,9 @@ static int ipv4ll_receive_message(sd_event_source *s, int fd, int sd_ipv4ll_set_index(sd_ipv4ll *ll, int interface_index) { assert_return(ll, -EINVAL); - assert_return(interface_index >= -1, -EINVAL); - assert_return(ll->state == IPV4LL_STATE_INIT, -EBUSY); + assert_return(interface_index > 0, -EINVAL); + assert_return(IN_SET(ll->state, IPV4LL_STATE_INIT, + IPV4LL_STATE_STOPPED), -EBUSY); ll->index = interface_index; @@ -385,13 +404,16 @@ int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr) { if (memcmp(&ll->mac_addr, addr, ETH_ALEN) == 0) return 0; - if (ll->state != IPV4LL_STATE_INIT) { + if (!IN_SET(ll->state, IPV4LL_STATE_INIT, IPV4LL_STATE_STOPPED)) { log_ipv4ll(ll, "Changing MAC address on running IPv4LL " "client, restarting"); - sd_ipv4ll_stop(ll); + ll = ipv4ll_stop(ll, IPV4LL_EVENT_STOP); need_restart = true; } + if (!ll) + return 0; + memcpy(&ll->mac_addr, addr, ETH_ALEN); if (need_restart) @@ -451,10 +473,13 @@ int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address){ } int sd_ipv4ll_set_address_seed (sd_ipv4ll *ll, uint8_t seed[8]) { - unsigned int entropy = *seed; + unsigned int entropy; int r; assert_return(ll, -EINVAL); + assert_return(seed, -EINVAL); + + entropy = *seed; free(ll->random_data); free(ll->random_data_state); @@ -481,6 +506,12 @@ error: return r; } +bool sd_ipv4ll_is_running(sd_ipv4ll *ll) { + assert_return(ll, -EINVAL); + + return !IN_SET(ll->state, IPV4LL_STATE_INIT, IPV4LL_STATE_STOPPED); +} + #define HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2) int sd_ipv4ll_start (sd_ipv4ll *ll) { @@ -489,7 +520,10 @@ int sd_ipv4ll_start (sd_ipv4ll *ll) { assert_return(ll, -EINVAL); assert_return(ll->event, -EINVAL); assert_return(ll->index > 0, -EINVAL); - assert_return(ll->state == IPV4LL_STATE_INIT, -EBUSY); + assert_return(IN_SET(ll->state, IPV4LL_STATE_INIT, + IPV4LL_STATE_STOPPED), -EBUSY); + + ll->state = IPV4LL_STATE_INIT; r = arp_network_bind_raw_socket(ll->index, &ll->link); @@ -530,14 +564,24 @@ int sd_ipv4ll_start (sd_ipv4ll *ll) { if (r < 0) goto out; - r = sd_event_add_monotonic(ll->event, &ll->timer, now(CLOCK_MONOTONIC), 0, - ipv4ll_timer, ll); + r = sd_event_source_set_description(ll->receive_message, "ipv4ll-receive-message"); + if (r < 0) + goto out; + + r = sd_event_add_time(ll->event, + &ll->timer, + clock_boottime_or_monotonic(), + now(clock_boottime_or_monotonic()), 0, + ipv4ll_timer, ll); if (r < 0) goto out; r = sd_event_source_set_priority(ll->timer, ll->event_priority); + if (r < 0) + goto out; + r = sd_event_source_set_description(ll->timer, "ipv4ll-timer"); out: if (r < 0) ipv4ll_stop(ll, IPV4LL_EVENT_STOP); @@ -546,23 +590,42 @@ out: } int sd_ipv4ll_stop(sd_ipv4ll *ll) { - return ipv4ll_stop(ll, IPV4LL_EVENT_STOP); + ipv4ll_stop(ll, IPV4LL_EVENT_STOP); + if (ll) + ipv4ll_set_state(ll, IPV4LL_STATE_STOPPED, 1); + + return 0; } -void sd_ipv4ll_free (sd_ipv4ll *ll) { - if (!ll) - return; +sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll) { + if (ll) + assert_se(REFCNT_INC(ll->n_ref) >= 2); - sd_ipv4ll_stop(ll); - sd_ipv4ll_detach_event(ll); + return ll; +} - free(ll->random_data); - free(ll->random_data_state); - free(ll); +sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll) { + if (ll && REFCNT_DEC(ll->n_ref) <= 0) { + ll->receive_message = + sd_event_source_unref(ll->receive_message); + ll->fd = safe_close(ll->fd); + + ll->timer = sd_event_source_unref(ll->timer); + + sd_ipv4ll_detach_event(ll); + + free(ll->random_data); + free(ll->random_data_state); + free(ll); + + return NULL; + } + + return ll; } -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_ipv4ll*, sd_ipv4ll_free); -#define _cleanup_ipv4ll_free_ _cleanup_(sd_ipv4ll_freep) +DEFINE_TRIVIAL_CLEANUP_FUNC(sd_ipv4ll*, sd_ipv4ll_unref); +#define _cleanup_ipv4ll_free_ _cleanup_(sd_ipv4ll_unrefp) int sd_ipv4ll_new(sd_ipv4ll **ret) { _cleanup_ipv4ll_free_ sd_ipv4ll *ll = NULL; @@ -573,6 +636,7 @@ int sd_ipv4ll_new(sd_ipv4ll **ret) { if (!ll) return -ENOMEM; + ll->n_ref = REFCNT_INIT; ll->state = IPV4LL_STATE_INIT; ll->index = -1; ll->fd = -1;