diff options
| author | Michael Biebl <biebl@debian.org> | 2019-03-26 23:25:23 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2019-03-26 23:25:23 +0100 |
| commit | 9a6dcbf895f9da01768e64b73cec88c16157d91e (patch) | |
| tree | a359958930d731e9f1b59344642e10754419fe84 /src/devices/nm-acd-manager.c | |
| parent | 964ae8cc391520440cf5aa13e2b9cc34850ea6c2 (diff) | |
New upstream version 1.16.0 upstream/1.16.0
Diffstat (limited to 'src/devices/nm-acd-manager.c')
| -rw-r--r-- | src/devices/nm-acd-manager.c | 419 |
1 files changed, 191 insertions, 228 deletions
diff --git a/src/devices/nm-acd-manager.c b/src/devices/nm-acd-manager.c index 035487a3..a8f7a63a 100644 --- a/src/devices/nm-acd-manager.c +++ b/src/devices/nm-acd-manager.c @@ -39,40 +39,23 @@ typedef enum { typedef struct { in_addr_t address; gboolean duplicate; - NMAcdManager *manager; - NAcd *acd; - GIOChannel *channel; - guint event_id; + NAcdProbe *probe; } AddressInfo; -enum { - PROBE_TERMINATED, - LAST_SIGNAL, -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -typedef struct { +struct _NMAcdManager { int ifindex; guint8 hwaddr[ETH_ALEN]; State state; GHashTable *addresses; guint completed; -} NMAcdManagerPrivate; + NAcd *acd; + GIOChannel *channel; + guint event_id; -struct _NMAcdManager { - GObject parent; - NMAcdManagerPrivate _priv; + NMAcdCallbacks callbacks; + gpointer user_data; }; -struct _NMAcdManagerClass { - GObjectClass parent; -}; - -G_DEFINE_TYPE (NMAcdManager, nm_acd_manager, G_TYPE_OBJECT) - -#define NM_ACD_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMAcdManager, NM_IS_ACD_MANAGER) - /*****************************************************************************/ #define _NMLOG_DOMAIN LOGD_IP4 @@ -80,14 +63,13 @@ G_DEFINE_TYPE (NMAcdManager, nm_acd_manager, G_TYPE_OBJECT) #define _NMLOG(level, ...) \ G_STMT_START { \ char _sbuf[64]; \ - int _ifindex = (self) ? NM_ACD_MANAGER_GET_PRIVATE (self)->ifindex : 0; \ \ nm_log ((level), _NMLOG_DOMAIN, \ - nm_platform_link_get_name (NM_PLATFORM_GET, _ifindex), \ + self && self->ifindex > 0 ? nm_platform_link_get_name (NM_PLATFORM_GET, self->ifindex) : NULL, \ NULL, \ "%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ _NMLOG_PREFIX_NAME, \ - self ? nm_sprintf_buf (_sbuf, "[%p,%d]", self, _ifindex) : "" \ + self ? nm_sprintf_buf (_sbuf, "[%p,%d]", self, self->ifindex) : "" \ _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ } G_STMT_END @@ -111,32 +93,25 @@ _acd_event_to_string (unsigned int event) return NULL; } -#define acd_event_to_string(event) NM_UTILS_LOOKUP_STR (_acd_event_to_string, event) +#define acd_event_to_string_a(event) NM_UTILS_LOOKUP_STR_A (_acd_event_to_string, event) static const char * -_acd_error_to_string (int error) +acd_error_to_string (int error) { if (error < 0) - return strerror(-error); + return nm_strerror_native (-error); switch (error) { case _N_ACD_E_SUCCESS: return "success"; - case N_ACD_E_DONE: - return "no more events (engine running)"; - case N_ACD_E_STOPPED: - return "no more events (engine stopped)"; case N_ACD_E_PREEMPTED: return "preempted"; case N_ACD_E_INVALID_ARGUMENT: return "invalid argument"; - case N_ACD_E_BUSY: - return "busy"; } - return NULL; -} -#define acd_error_to_string(error) NM_UTILS_LOOKUP_STR (_acd_error_to_string, error) + g_return_val_if_reached (NULL); +} /*****************************************************************************/ @@ -152,21 +127,18 @@ _acd_error_to_string (int error) gboolean nm_acd_manager_add_address (NMAcdManager *self, in_addr_t address) { - NMAcdManagerPrivate *priv; AddressInfo *info; - g_return_val_if_fail (NM_IS_ACD_MANAGER (self), FALSE); - priv = NM_ACD_MANAGER_GET_PRIVATE (self); - g_return_val_if_fail (priv->state == STATE_INIT, FALSE); + g_return_val_if_fail (self, FALSE); + g_return_val_if_fail (self->state == STATE_INIT, FALSE); - if (g_hash_table_lookup (priv->addresses, GUINT_TO_POINTER (address))) + if (g_hash_table_lookup (self->addresses, GUINT_TO_POINTER (address))) return FALSE; info = g_slice_new0 (AddressInfo); info->address = address; - info->manager = self; - g_hash_table_insert (priv->addresses, GUINT_TO_POINTER (address), info); + g_hash_table_insert (self->addresses, GUINT_TO_POINTER (address), info); return TRUE; } @@ -174,115 +146,142 @@ nm_acd_manager_add_address (NMAcdManager *self, in_addr_t address) static gboolean acd_event (GIOChannel *source, GIOCondition condition, gpointer data) { - AddressInfo *info = data; - NMAcdManager *self = info->manager; - NMAcdManagerPrivate *priv = NM_ACD_MANAGER_GET_PRIVATE (self); + NMAcdManager *self = data; NAcdEvent *event; + AddressInfo *info; + gboolean emit_probe_terminated = FALSE; char address_str[INET_ADDRSTRLEN]; gs_free char *hwaddr_str = NULL; int r; - if ( n_acd_dispatch (info->acd) - || n_acd_pop_event (info->acd, &event)) + if (n_acd_dispatch (self->acd)) return G_SOURCE_CONTINUE; - switch (event->event) { - case N_ACD_EVENT_READY: - info->duplicate = FALSE; - if (priv->state == STATE_ANNOUNCING) { - r = n_acd_announce (info->acd, N_ACD_DEFEND_ONCE); - if (r) { - _LOGW ("couldn't announce address %s on interface '%s': %s", - nm_utils_inet4_ntop (info->address, address_str), - nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex), - acd_error_to_string (r)); - } else { - _LOGD ("announcing address %s", - nm_utils_inet4_ntop (info->address, address_str)); + while ( !n_acd_pop_event (self->acd, &event) + && event) { + gboolean check_probing_done = FALSE; + + switch (event->event) { + case N_ACD_EVENT_READY: + n_acd_probe_get_userdata (event->ready.probe, (void **) &info); + info->duplicate = FALSE; + if (self->state == STATE_ANNOUNCING) { + /* fake probe ended, start announcing */ + r = n_acd_probe_announce (info->probe, N_ACD_DEFEND_ONCE); + if (r) { + _LOGW ("couldn't announce address %s on interface '%s': %s", + nm_utils_inet4_ntop (info->address, address_str), + nm_platform_link_get_name (NM_PLATFORM_GET, self->ifindex), + acd_error_to_string (r)); + } else { + _LOGD ("announcing address %s", + nm_utils_inet4_ntop (info->address, address_str)); + } } + check_probing_done = TRUE; + break; + case N_ACD_EVENT_USED: + n_acd_probe_get_userdata (event->used.probe, (void **) &info); + info->duplicate = TRUE; + check_probing_done = TRUE; + break; + case N_ACD_EVENT_DEFENDED: + n_acd_probe_get_userdata (event->defended.probe, (void **) &info); + _LOGD ("defended address %s from host %s", + nm_utils_inet4_ntop (info->address, address_str), + (hwaddr_str = nm_utils_hwaddr_ntoa (event->defended.sender, + event->defended.n_sender))); + break; + case N_ACD_EVENT_CONFLICT: + n_acd_probe_get_userdata (event->conflict.probe, (void **) &info); + _LOGW ("conflict for address %s detected with host %s on interface '%s'", + nm_utils_inet4_ntop (info->address, address_str), + (hwaddr_str = nm_utils_hwaddr_ntoa (event->defended.sender, + event->defended.n_sender)), + nm_platform_link_get_name (NM_PLATFORM_GET, self->ifindex)); + break; + default: + _LOGD ("unhandled event '%s'", acd_event_to_string_a (event->event)); + break; + } + + if ( check_probing_done + && self->state == STATE_PROBING + && ++self->completed == g_hash_table_size (self->addresses)) { + self->state = STATE_PROBE_DONE; + emit_probe_terminated = TRUE; } - break; - case N_ACD_EVENT_USED: - info->duplicate = TRUE; - break; - case N_ACD_EVENT_DEFENDED: - _LOGD ("defended address %s from host %s", - nm_utils_inet4_ntop (info->address, address_str), - (hwaddr_str = nm_utils_hwaddr_ntoa (event->defended.sender, - event->defended.n_sender))); - break; - case N_ACD_EVENT_CONFLICT: - _LOGW ("conflict for address %s detected with host %s on interface '%s'", - nm_utils_inet4_ntop (info->address, address_str), - (hwaddr_str = nm_utils_hwaddr_ntoa (event->defended.sender, - event->defended.n_sender)), - nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex)); - break; - default: - _LOGD ("event '%s' for address %s", - acd_event_to_string (event->event), - nm_utils_inet4_ntop (info->address, address_str)); - return G_SOURCE_CONTINUE; } - if ( priv->state == STATE_PROBING - && ++priv->completed == g_hash_table_size (priv->addresses)) { - priv->state = STATE_PROBE_DONE; - g_signal_emit (self, signals[PROBE_TERMINATED], 0); + if (emit_probe_terminated) { + if (self->callbacks.probe_terminated_callback) { + self->callbacks.probe_terminated_callback (self, + self->user_data); + } } return G_SOURCE_CONTINUE; } static gboolean -acd_probe_start (NMAcdManager *self, - AddressInfo *info, - guint64 timeout) +acd_probe_add (NMAcdManager *self, + AddressInfo *info, + guint64 timeout) { - NMAcdManagerPrivate *priv = NM_ACD_MANAGER_GET_PRIVATE (self); - NAcdConfig *config; - int r, fd; + NAcdProbeConfig *probe_config; + int r; + char sbuf[NM_UTILS_INET_ADDRSTRLEN]; - r = n_acd_new (&info->acd); + r = n_acd_probe_config_new (&probe_config); if (r) { - _LOGW ("could not create ACD for %s on interface '%s': %s", - nm_utils_inet4_ntop (info->address, NULL), - nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex), + _LOGW ("could not create probe config for %s on interface '%s': %s", + nm_utils_inet4_ntop (info->address, sbuf), + nm_platform_link_get_name (NM_PLATFORM_GET, self->ifindex), acd_error_to_string (r)); return FALSE; } - n_acd_get_fd (info->acd, &fd); - info->channel = g_io_channel_unix_new (fd); - info->event_id = g_io_add_watch (info->channel, G_IO_IN, acd_event, info); - - config = &(NAcdConfig) { - .ifindex = priv->ifindex, - .mac = priv->hwaddr, - .n_mac = ETH_ALEN, - .ip = info->address, - .timeout_msec = timeout, - .transport = N_ACD_TRANSPORT_ETHERNET, - }; + n_acd_probe_config_set_ip (probe_config, (struct in_addr) { info->address }); + n_acd_probe_config_set_timeout (probe_config, timeout); - r = n_acd_start (info->acd, config); + r = n_acd_probe (self->acd, &info->probe, probe_config); if (r) { _LOGW ("could not start probe for %s on interface '%s': %s", - nm_utils_inet4_ntop (info->address, NULL), - nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex), + nm_utils_inet4_ntop (info->address, sbuf), + nm_platform_link_get_name (NM_PLATFORM_GET, self->ifindex), acd_error_to_string (r)); + n_acd_probe_config_free (probe_config); return FALSE; } - if (timeout) { - _LOGD ("started probe for %s with timeout %llu", - nm_utils_inet4_ntop (info->address, NULL), - (unsigned long long) timeout); - } + n_acd_probe_set_userdata (info->probe, info); + n_acd_probe_config_free (probe_config); return TRUE; } +static int +acd_init (NMAcdManager *self) +{ + NAcdConfig *config; + int r; + + if (self->acd) + return 0; + + r = n_acd_config_new (&config); + if (r) + return r; + + n_acd_config_set_ifindex (config, self->ifindex); + n_acd_config_set_transport (config, N_ACD_TRANSPORT_ETHERNET); + n_acd_config_set_mac (config, self->hwaddr, ETH_ALEN); + + r = n_acd_new (&self->acd, config); + n_acd_config_free (config); + return r; +} + /** * nm_acd_manager_start_probe: * @self: a #NMAcdManager @@ -297,59 +296,36 @@ acd_probe_start (NMAcdManager *self, gboolean nm_acd_manager_start_probe (NMAcdManager *self, guint timeout) { - NMAcdManagerPrivate *priv; GHashTableIter iter; AddressInfo *info; gboolean success = FALSE; + int fd, r; - g_return_val_if_fail (NM_IS_ACD_MANAGER (self), FALSE); - priv = NM_ACD_MANAGER_GET_PRIVATE (self); - g_return_val_if_fail (priv->state == STATE_INIT, FALSE); + g_return_val_if_fail (self, FALSE); + g_return_val_if_fail (self->state == STATE_INIT, FALSE); + + r = acd_init (self); + if (r) { + _LOGW ("couldn't init ACD for probing on interface '%s': %s", + nm_platform_link_get_name (NM_PLATFORM_GET, self->ifindex), + acd_error_to_string (r)); + return FALSE; + } - priv->completed = 0; + self->completed = 0; - g_hash_table_iter_init (&iter, priv->addresses); + g_hash_table_iter_init (&iter, self->addresses); while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info)) - success |= acd_probe_start (self, info, timeout); + success |= acd_probe_add (self, info, timeout); if (success) - priv->state = STATE_PROBING; + self->state = STATE_PROBING; - return success; -} - -/** - * nm_acd_manager_reset: - * @self: a #NMAcdManager - * - * Stop any operation in progress and reset @self to the initial state. - */ -void -nm_acd_manager_reset (NMAcdManager *self) -{ - NMAcdManagerPrivate *priv; - - g_return_if_fail (NM_IS_ACD_MANAGER (self)); - priv = NM_ACD_MANAGER_GET_PRIVATE (self); - - g_hash_table_remove_all (priv->addresses); + n_acd_get_fd (self->acd, &fd); + self->channel = g_io_channel_unix_new (fd); + self->event_id = g_io_add_watch (self->channel, G_IO_IN, acd_event, self); - priv->state = STATE_INIT; -} - -/** - * nm_acd_manager_destroy: - * @self: the #NMAcdManager - * - * Calls nm_acd_manager_reset() and unrefs @self. - */ -void -nm_acd_manager_destroy (NMAcdManager *self) -{ - g_return_if_fail (NM_IS_ACD_MANAGER (self)); - - nm_acd_manager_reset (self); - g_object_unref (self); + return success; } /** @@ -365,15 +341,12 @@ nm_acd_manager_destroy (NMAcdManager *self) gboolean nm_acd_manager_check_address (NMAcdManager *self, in_addr_t address) { - NMAcdManagerPrivate *priv; AddressInfo *info; - g_return_val_if_fail (NM_IS_ACD_MANAGER (self), FALSE); - priv = NM_ACD_MANAGER_GET_PRIVATE (self); - g_return_val_if_fail ( priv->state == STATE_INIT - || priv->state == STATE_PROBE_DONE, FALSE); + g_return_val_if_fail (self, FALSE); + g_return_val_if_fail (NM_IN_SET (self->state, STATE_INIT, STATE_PROBE_DONE), FALSE); - info = g_hash_table_lookup (priv->addresses, GUINT_TO_POINTER (address)); + info = g_hash_table_lookup (self->addresses, GUINT_TO_POINTER (address)); g_return_val_if_fail (info, FALSE); return !info->duplicate; @@ -388,41 +361,43 @@ nm_acd_manager_check_address (NMAcdManager *self, in_addr_t address) void nm_acd_manager_announce_addresses (NMAcdManager *self) { - NMAcdManagerPrivate *priv = NM_ACD_MANAGER_GET_PRIVATE (self); GHashTableIter iter; AddressInfo *info; int r; - if (priv->state == STATE_INIT) { + r = acd_init (self); + if (r) { + _LOGW ("couldn't init ACD for announcing addresses on interface '%s': %s", + nm_platform_link_get_name (NM_PLATFORM_GET, self->ifindex), + acd_error_to_string (r)); + return; + } + + if (self->state == STATE_INIT) { /* n-acd can't announce without probing, therefore let's * start a fake probe with zero timeout and then perform - * the announce. */ - priv->state = STATE_ANNOUNCING; - g_hash_table_iter_init (&iter, priv->addresses); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info)) { - if (!acd_probe_start (self, info, 0)) { - _LOGW ("couldn't announce address %s on interface '%s'", - nm_utils_inet4_ntop (info->address, NULL), - nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex)); - } - } - } else if (priv->state == STATE_PROBE_DONE) { - priv->state = STATE_ANNOUNCING; - g_hash_table_iter_init (&iter, priv->addresses); + * the announcement. */ + g_hash_table_iter_init (&iter, self->addresses); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info)) + acd_probe_add (self, info, 0); + self->state = STATE_ANNOUNCING; + } else if (self->state == STATE_ANNOUNCING) { + char sbuf[NM_UTILS_INET_ADDRSTRLEN]; + + g_hash_table_iter_init (&iter, self->addresses); while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info)) { if (info->duplicate) continue; - r = n_acd_announce (info->acd, N_ACD_DEFEND_ONCE); + r = n_acd_probe_announce (info->probe, N_ACD_DEFEND_ONCE); if (r) { _LOGW ("couldn't announce address %s on interface '%s': %s", - nm_utils_inet4_ntop (info->address, NULL), - nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex), + nm_utils_inet4_ntop (info->address, sbuf), + nm_platform_link_get_name (NM_PLATFORM_GET, self->ifindex), acd_error_to_string (r)); } else - _LOGD ("announcing address %s", nm_utils_inet4_ntop (info->address, NULL)); + _LOGD ("announcing address %s", nm_utils_inet4_ntop (info->address, sbuf)); } - } else - nm_assert_not_reached (); + } } static void @@ -430,64 +405,52 @@ destroy_address_info (gpointer data) { AddressInfo *info = (AddressInfo *) data; - g_clear_pointer (&info->channel, g_io_channel_unref); - g_clear_pointer (&info->acd, n_acd_free); - nm_clear_g_source (&info->event_id); + n_acd_probe_free (info->probe); g_slice_free (AddressInfo, info); } /*****************************************************************************/ -static void -nm_acd_manager_init (NMAcdManager *self) -{ - NMAcdManagerPrivate *priv = NM_ACD_MANAGER_GET_PRIVATE (self); - - priv->addresses = g_hash_table_new_full (nm_direct_hash, NULL, - NULL, destroy_address_info); - priv->state = STATE_INIT; -} - NMAcdManager * -nm_acd_manager_new (int ifindex, const guint8 *hwaddr, size_t hwaddr_len) +nm_acd_manager_new (int ifindex, + const guint8 *hwaddr, + guint hwaddr_len, + const NMAcdCallbacks *callbacks, + gpointer user_data) { NMAcdManager *self; - NMAcdManagerPrivate *priv; + g_return_val_if_fail (ifindex > 0, NULL); g_return_val_if_fail (hwaddr, NULL); g_return_val_if_fail (hwaddr_len == ETH_ALEN, NULL); - self = g_object_new (NM_TYPE_ACD_MANAGER, NULL); - priv = NM_ACD_MANAGER_GET_PRIVATE (self); - priv->ifindex = ifindex; - memcpy (priv->hwaddr, hwaddr, ETH_ALEN); + self = g_slice_new0 (NMAcdManager); + + if (callbacks) + self->callbacks = *callbacks; + self->user_data = user_data; + self->addresses = g_hash_table_new_full (nm_direct_hash, NULL, + NULL, destroy_address_info); + self->state = STATE_INIT; + self->ifindex = ifindex; + memcpy (self->hwaddr, hwaddr, ETH_ALEN); return self; } -static void -dispose (GObject *object) +void +nm_acd_manager_free (NMAcdManager *self) { - NMAcdManager *self = NM_ACD_MANAGER (object); - NMAcdManagerPrivate *priv = NM_ACD_MANAGER_GET_PRIVATE (self); + g_return_if_fail (self); - g_clear_pointer (&priv->addresses, g_hash_table_destroy); - - G_OBJECT_CLASS (nm_acd_manager_parent_class)->dispose (object); -} - -static void -nm_acd_manager_class_init (NMAcdManagerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); + if (self->callbacks.user_data_destroy) + self->callbacks.user_data_destroy (self->user_data); - object_class->dispose = dispose; + nm_clear_pointer (&self->addresses, g_hash_table_destroy); + nm_clear_pointer (&self->channel, g_io_channel_unref); + nm_clear_g_source (&self->event_id); + nm_clear_pointer (&self->acd, n_acd_unref); - signals[PROBE_TERMINATED] = - g_signal_new (NM_ACD_MANAGER_PROBE_TERMINATED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, NULL, - G_TYPE_NONE, 0); + g_slice_free (NMAcdManager, self); } |