static void
dispose (GObject *object)
{
	NMVPNPlugin *plugin = NM_VPN_PLUGIN (object);
	NMVPNPluginPrivate *priv = NM_VPN_PLUGIN_GET_PRIVATE (plugin);
	NMVPNServiceState state;
	GError *err = NULL;

	nm_clear_g_source (&priv->fail_stop_id);
	nm_clear_g_source (&priv->quit_timer);
	nm_clear_g_source (&priv->connect_timer);

	state = nm_vpn_plugin_get_state (plugin);

	if (state == NM_VPN_SERVICE_STATE_STARTED ||
	    state == NM_VPN_SERVICE_STATE_STARTING)
		nm_vpn_plugin_disconnect (plugin, &err);

	if (err) {
		g_warning ("Error disconnecting VPN connection: %s", err->message);
		g_error_free (err);
	}

	G_OBJECT_CLASS (nm_vpn_plugin_parent_class)->dispose (object);
}
static void
dispose (GObject *object)
{
    NMArpingManager *self = NM_ARPING_MANAGER (object);
    NMArpingManagerPrivate *priv = NM_ARPING_MANAGER_GET_PRIVATE (self);

    nm_clear_g_source (&priv->timer);
    nm_clear_g_source (&priv->round2_id);
    g_clear_pointer (&priv->addresses, g_hash_table_destroy);

    G_OBJECT_CLASS (nm_arping_manager_parent_class)->dispose (object);
}
/**
 * nm_arping_manager_reset:
 * @self: a #NMArpingManager
 *
 * Stop any operation in progress and reset @self to the initial state.
 */
void
nm_arping_manager_reset (NMArpingManager *self)
{
    NMArpingManagerPrivate *priv;

    g_return_if_fail (NM_IS_ARPING_MANAGER (self));
    priv = NM_ARPING_MANAGER_GET_PRIVATE (self);

    nm_clear_g_source (&priv->timer);
    nm_clear_g_source (&priv->round2_id);
    g_hash_table_remove_all (priv->addresses);

    priv->state = STATE_INIT;
}
static gboolean
arping_timeout_cb (gpointer user_data)
{
    NMArpingManager *self = user_data;
    NMArpingManagerPrivate *priv = NM_ARPING_MANAGER_GET_PRIVATE (self);
    GHashTableIter iter;
    AddressInfo *info;

    priv->timer = 0;

    g_hash_table_iter_init (&iter, priv->addresses);
    while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info)) {
        nm_clear_g_source (&info->watch);
        if (info->pid) {
            _LOGD ("DAD timed out for %s",
                   nm_utils_inet4_ntop (info->address, NULL));
            nm_utils_kill_child_async (info->pid, SIGTERM, LOGD_IP4,
                                       "arping", 1000, NULL, NULL);
            info->pid = 0;
        }
    }

    priv->state = STATE_PROBE_DONE;
    g_signal_emit (self, signals[PROBE_TERMINATED], 0);

    return G_SOURCE_REMOVE;
}
static void
remove_timeout_handler (NMPPPManager *manager)
{
	NMPPPManagerPrivate *priv = NM_PPP_MANAGER_GET_PRIVATE (manager);

	nm_clear_g_source (&priv->ppp_timeout_handler);
}
void
nm_lldp_listener_stop (NMLldpListener *self)
{
	NMLldpListenerPrivate *priv;
	guint size;

	g_return_if_fail (NM_IS_LLDP_LISTENER (self));
	priv = NM_LLDP_LISTENER_GET_PRIVATE (self);

	if (priv->lldp_handle) {
		sd_lldp_stop (priv->lldp_handle);
		sd_lldp_detach_event (priv->lldp_handle);
		sd_lldp_unref (priv->lldp_handle);
		g_clear_pointer (&priv->iface, g_free);
		priv->lldp_handle = NULL;

		size = g_hash_table_size (priv->lldp_neighbors);
		g_hash_table_remove_all (priv->lldp_neighbors);
		if (size) {
			nm_clear_g_variant (&priv->variant);
			g_object_notify (G_OBJECT (self), NM_LLDP_LISTENER_NEIGHBORS);
		}
	}

	nm_clear_g_source (&priv->timer);
}
static void
adsl_cleanup (NMDeviceAdsl *self)
{
	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);

	if (priv->ppp_manager) {
		g_signal_handlers_disconnect_by_func (priv->ppp_manager, G_CALLBACK (ppp_state_changed), self);
		g_signal_handlers_disconnect_by_func (priv->ppp_manager, G_CALLBACK (ppp_ip4_config), self);
		nm_exported_object_clear_and_unexport (&priv->ppp_manager);
	}

	g_signal_handlers_disconnect_by_func (NM_PLATFORM_GET, G_CALLBACK (link_changed_cb), self);

	if (priv->brfd >= 0) {
		close (priv->brfd);
		priv->brfd = -1;
	}

	nm_clear_g_source (&priv->nas_update_id);

	/* FIXME: kernel has no way of explicitly deleting the 'nasX' interface yet,
	 * so it gets leaked.  It does get destroyed when it's no longer in use,
	 * but we have no control over that.
	 */
	priv->nas_ifindex = -1;
	g_clear_pointer (&priv->nas_ifname, g_free);
}
static void
arping_watch_cb (GPid pid, gint status, gpointer user_data)
{
    AddressInfo *info = user_data;
    NMArpingManager *self = info->manager;
    NMArpingManagerPrivate *priv = NM_ARPING_MANAGER_GET_PRIVATE (self);
    const char *addr;

    info->pid = 0;
    info->watch = 0;
    addr = nm_utils_inet4_ntop (info->address, NULL);

    if (WIFEXITED (status)) {
        if (WEXITSTATUS (status) != 0) {
            _LOGD ("%s already used in the %s network",
                   addr, nm_platform_link_get_name (NM_PLATFORM_GET, priv->ifindex));
            info->duplicate = TRUE;
        } else
            _LOGD ("DAD succeeded for %s", addr);
    } else {
        _LOGD ("stopped unexpectedly with status %d for %s", status, addr);
    }

    if (++priv->completed == g_hash_table_size (priv->addresses)) {
        priv->state = STATE_PROBE_DONE;
        nm_clear_g_source (&priv->timer);
        g_signal_emit (self, signals[PROBE_TERMINATED], 0);
    }
}
static void
dispose (GObject *object)
{
	NMSupplicantManager *self = (NMSupplicantManager *) object;
	NMSupplicantManagerPrivate *priv = NM_SUPPLICANT_MANAGER_GET_PRIVATE (self);
	GSList *ifaces;

	nm_clear_g_source (&priv->die_count_reset_id);

	if (priv->cancellable) {
		g_cancellable_cancel (priv->cancellable);
		g_clear_object (&priv->cancellable);
	}

	if (priv->ifaces) {
		for (ifaces = priv->ifaces; ifaces; ifaces = ifaces->next)
			g_object_remove_toggle_ref (ifaces->data, _sup_iface_last_ref, self);
		g_slist_free (priv->ifaces);
		priv->ifaces = NULL;
	}

	g_clear_object (&priv->proxy);

	G_OBJECT_CLASS (nm_supplicant_manager_parent_class)->dispose (object);
}
static void
connect_timer_start (NMVPNPlugin *plugin)
{
	NMVPNPluginPrivate *priv = NM_VPN_PLUGIN_GET_PRIVATE (plugin);

	nm_clear_g_source (&priv->connect_timer);
	priv->connect_timer = g_timeout_add_seconds (60, connect_timer_expired, plugin);
}
static void
schedule_fail_stop (NMVPNPlugin *plugin)
{
	NMVPNPluginPrivate *priv = NM_VPN_PLUGIN_GET_PRIVATE (plugin);

	nm_clear_g_source (&priv->fail_stop_id);
	priv->fail_stop_id = g_idle_add (fail_stop, plugin);
}
static void
dispose (GObject *object)
{
	adsl_cleanup (NM_DEVICE_ADSL (object));

	nm_clear_g_source (&NM_DEVICE_ADSL_GET_PRIVATE (object)->carrier_poll_id);

	G_OBJECT_CLASS (nm_device_adsl_parent_class)->dispose (object);
}
static void
schedule_quit_timer (NMVPNPlugin *self)
{
	NMVPNPluginPrivate *priv = NM_VPN_PLUGIN_GET_PRIVATE (self);

	nm_clear_g_source (&priv->quit_timer);
	priv->quit_timer = g_timeout_add_seconds (NM_VPN_PLUGIN_QUIT_TIMER,
	                                          quit_timer_expired,
	                                          self);
}
static void
teamd_cleanup (NMDevice *device, gboolean free_tdc)
{
	NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE (device);

	nm_clear_g_source (&priv->teamd_process_watch);
	nm_clear_g_source (&priv->teamd_timeout);

	if (priv->teamd_pid > 0) {
		nm_utils_kill_child_async (priv->teamd_pid, SIGTERM, LOGD_TEAM, "teamd", 2000, NULL, NULL);
		priv->teamd_pid = 0;
	}

	if (priv->tdc && free_tdc) {
		teamdctl_disconnect (priv->tdc);
		teamdctl_free (priv->tdc);
		priv->tdc = NULL;
	}
}
void
nm_checkpoint_manager_unref (NMCheckpointManager *self)
{
	if (!self)
		return;

	nm_clear_g_source (&self->rollback_timeout_id);
	g_hash_table_destroy (self->checkpoints);

	g_slice_free (NMCheckpointManager, self);
}
static void
state_changed (NMVPNPlugin *plugin, NMVPNServiceState state)
{
	NMVPNPluginPrivate *priv = NM_VPN_PLUGIN_GET_PRIVATE (plugin);

	switch (state) {
	case NM_VPN_SERVICE_STATE_STARTING:
		nm_clear_g_source (&priv->quit_timer);
		nm_clear_g_source (&priv->fail_stop_id);
		break;
	case NM_VPN_SERVICE_STATE_STOPPED:
		schedule_quit_timer (plugin);
		break;
	default:
		/* Clean up all timers we might have set up. */
		nm_clear_g_source (&priv->connect_timer);
		nm_clear_g_source (&priv->quit_timer);
		nm_clear_g_source (&priv->fail_stop_id);
		break;
	}
}
/**
 * nm_arping_manager_announce_addresses:
 * @self: a #NMArpingManager
 *
 * Start announcing addresses.
 */
void
nm_arping_manager_announce_addresses (NMArpingManager *self)
{
    NMArpingManagerPrivate *priv = NM_ARPING_MANAGER_GET_PRIVATE (self);

    g_return_if_fail (   priv->state == STATE_INIT
                         || priv->state == STATE_PROBE_DONE);

    send_announcements (self, "-A");
    nm_clear_g_source (&priv->round2_id);
    priv->round2_id = g_timeout_add_seconds (2, arp_announce_round2, self);
    priv->state = STATE_ANNOUNCING;
}
static void
destroy_address_info (gpointer data)
{
    AddressInfo *info = (AddressInfo *) data;

    nm_clear_g_source (&info->watch);

    if (info->pid) {
        nm_utils_kill_child_async (info->pid, SIGTERM, LOGD_IP4, "arping",
                                   1000, NULL, NULL);
    }

    g_slice_free (AddressInfo, info);
}
static void
_ppp_cleanup (NMPPPManager *manager)
{
	NMPPPManagerPrivate *priv;

	g_return_if_fail (NM_IS_PPP_MANAGER (manager));

	priv = NM_PPP_MANAGER_GET_PRIVATE (manager);

	cancel_get_secrets (manager);

	nm_clear_g_source (&priv->monitor_id);

	if (priv->monitor_fd >= 0) {
		/* Get the stats one last time */
		monitor_cb (manager);
		close (priv->monitor_fd);
		priv->monitor_fd = -1;
	}

	nm_clear_g_source (&priv->ppp_timeout_handler);
	nm_clear_g_source (&priv->ppp_watch_id);
}
static void
dispose (GObject *object)
{
	NMConnectionEditor *editor = NM_CONNECTION_EDITOR (object);

	editor->disposed = TRUE;

	if (active_editors && editor->orig_connection)
		g_hash_table_remove (active_editors, editor->orig_connection);

	g_slist_free_full (editor->initializing_pages, g_object_unref);
	editor->initializing_pages = NULL;

	g_slist_free_full (editor->pages, g_object_unref);
	editor->pages = NULL;

	/* Mark any in-progress secrets call as canceled; it will clean up after itself. */
	if (editor->secrets_call)
		editor->secrets_call->canceled = TRUE;

	while (editor->pending_secrets_calls) {
		get_secrets_info_free ((GetSecretsInfo *) editor->pending_secrets_calls->data);
		editor->pending_secrets_calls = g_slist_delete_link (editor->pending_secrets_calls, editor->pending_secrets_calls);
	}

	nm_clear_g_source (&editor->validate_id);

	g_clear_object (&editor->connection);
	g_clear_object (&editor->orig_connection);

	if (editor->window) {
		gtk_widget_destroy (editor->window);
		editor->window = NULL;
	}
	g_clear_object (&editor->parent_window);
	g_clear_object (&editor->builder);

	nm_clear_g_signal_handler (editor->client, &editor->permission_id);
	g_clear_object (&editor->client);

	g_clear_pointer (&editor->last_validation_error, g_free);

	if (editor->inter_page_hash) {
		g_hash_table_destroy (editor->inter_page_hash);
		editor->inter_page_hash = NULL;
	}

	G_OBJECT_CLASS (nm_connection_editor_parent_class)->dispose (object);
}
/**
 * nm_vpn_plugin_secrets_required:
 * @plugin: the #NMVPNPlugin
 * @message: an information message about why secrets are required, if any
 * @hints: VPN specific secret names for required new secrets
 *
 * Called by VPN plugin implementations to signal to NetworkManager that secrets
 * are required during the connection process.  This signal may be used to
 * request new secrets when the secrets originally provided by NetworkManager
 * are insufficient, or the VPN process indicates that it needs additional
 * information to complete the request.
 *
 * Since: 0.9.10
 */
void
nm_vpn_plugin_secrets_required (NMVPNPlugin *plugin,
                                const char *message,
                                const char **hints)
{
	NMVPNPluginPrivate *priv = NM_VPN_PLUGIN_GET_PRIVATE (plugin);

	/* Plugin must be able to accept the new secrets if it calls this method */
	g_return_if_fail (NM_VPN_PLUGIN_GET_CLASS (plugin)->new_secrets);

	/* Plugin cannot call this method if NetworkManager didn't originally call
	 * ConnectInteractive().
	 */
	g_return_if_fail (priv->interactive == TRUE);

	/* Cancel the connect timer since secrets might take a while.  It'll
	 * get restarted when the secrets come back via NewSecrets().
	 */
	nm_clear_g_source (&priv->connect_timer);

	g_signal_emit (plugin, signals[SECRETS_REQUIRED], 0, message, hints);
}
Beispiel #22
0
static void
dispose (GObject *object)
{
	NMVpnService *self = NM_VPN_SERVICE (object);
	NMVpnServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (self);

	nm_clear_g_source (&priv->start_timeout);

	g_clear_object (&priv->plugin_info);

	/* VPNService owner is required to stop connections before releasing */
	g_assert (priv->active == NULL);
	g_assert (priv->pending == NULL);

	if (priv->proxy) {
		g_signal_handlers_disconnect_by_func (priv->proxy,
		                                      G_CALLBACK (_name_owner_changed),
		                                      self);
		g_clear_object (&priv->proxy);
	}

	G_OBJECT_CLASS (nm_vpn_service_parent_class)->dispose (object);
}
static void
update_rollback_timeout (NMCheckpointManager *self)
{
	NMCheckpoint *checkpoint;
	GHashTableIter iter;
	gint64 ts, delta, next = G_MAXINT64;

	g_hash_table_iter_init (&iter, self->checkpoints);
	while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &checkpoint)) {
		ts = nm_checkpoint_get_rollback_ts (checkpoint);
		if (ts && ts < next)
			next = ts;
	}

	nm_clear_g_source (&self->rollback_timeout_id);

	if (next != G_MAXINT64) {
		delta = MAX (next - nm_utils_get_monotonic_timestamp_ms (), 0);
		self->rollback_timeout_id = g_timeout_add (delta,
		                                           (GSourceFunc) rollback_timeout_cb,
		                                           self);
		_LOGT ("update timeout: next check in %" G_GINT64_FORMAT " ms", delta);
	}
}
Beispiel #24
0
/*
 * main
 *
 */
int
main (int argc, char *argv[])
{
    gboolean wifi_enabled = TRUE, net_enabled = TRUE, wwan_enabled = TRUE;
    gboolean success = FALSE;
    NMConfig *config;
    GError *error = NULL;
    gboolean wrote_pidfile = FALSE;
    char *bad_domains = NULL;
    NMConfigCmdLineOptions *config_cli;
    guint sd_id = 0;

    nm_g_type_init ();

    /* Known to cause a possible deadlock upon GDBus initialization:
     * https://bugzilla.gnome.org/show_bug.cgi?id=674885 */
    g_type_ensure (G_TYPE_SOCKET);
    g_type_ensure (G_TYPE_DBUS_CONNECTION);
    g_type_ensure (NM_TYPE_BUS_MANAGER);

    _nm_utils_is_manager_process = TRUE;

    main_loop = g_main_loop_new (NULL, FALSE);

    config_cli = nm_config_cmd_line_options_new ();
    do_early_setup (&argc, &argv, config_cli);

    if (global_opt.g_fatal_warnings)
        _set_g_fatal_warnings ();

    if (global_opt.show_version) {
        fprintf (stdout, NM_DIST_VERSION "\n");
        exit (0);
    }

    if (global_opt.print_config) {
        int result;

        result = print_config (config_cli);
        nm_config_cmd_line_options_free (config_cli);
        exit (result);
    }

    nm_main_utils_ensure_root ();

    nm_main_utils_ensure_not_running_pidfile (global_opt.pidfile);

    nm_main_utils_ensure_statedir ();
    nm_main_utils_ensure_rundir ();

    /* When running from the build directory, determine our build directory
     * base and set helper paths in the build tree */
    if (global_opt.run_from_build_dir) {
        char *path, *slash;
        int g;

        /* exe is <basedir>/src/.libs/lt-NetworkManager, so chop off
         * the last three components */
        path = realpath ("/proc/self/exe", NULL);
        g_assert (path != NULL);
        for (g = 0; g < 3; ++g) {
            slash = strrchr (path, '/');
            g_assert (slash != NULL);
            *slash = '\0';
        }

        /* don't free these strings, we need them for the entire
         * process lifetime */
        nm_dhcp_helper_path = g_strdup_printf ("%s/src/dhcp-manager/nm-dhcp-helper", path);

        g_free (path);
    }

    if (!nm_logging_setup (global_opt.opt_log_level,
                           global_opt.opt_log_domains,
                           &bad_domains,
                           &error)) {
        fprintf (stderr,
                 _("%s.  Please use --help to see a list of valid options.\n"),
                 error->message);
        exit (1);
    } else if (bad_domains) {
        fprintf (stderr,
                 _("Ignoring unrecognized log domain(s) '%s' passed on command line.\n"),
                 bad_domains);
        g_clear_pointer (&bad_domains, g_free);
    }

    /* Read the config file and CLI overrides */
    config = nm_config_setup (config_cli, NULL, &error);
    nm_config_cmd_line_options_free (config_cli);
    config_cli = NULL;
    if (config == NULL) {
        fprintf (stderr, _("Failed to read configuration: %s\n"),
                 error->message);
        exit (1);
    }

    _init_nm_debug (nm_config_get_debug (config));

    /* Initialize logging from config file *only* if not explicitly
     * specified by commandline.
     */
    if (global_opt.opt_log_level == NULL && global_opt.opt_log_domains == NULL) {
        if (!nm_logging_setup (nm_config_get_log_level (config),
                               nm_config_get_log_domains (config),
                               &bad_domains,
                               &error)) {
            fprintf (stderr, _("Error in configuration file: %s.\n"),
                     error->message);
            exit (1);
        } else if (bad_domains) {
            fprintf (stderr,
                     _("Ignoring unrecognized log domain(s) '%s' from config files.\n"),
                     bad_domains);
            g_clear_pointer (&bad_domains, g_free);
        }
    }

    if (global_opt.become_daemon && !nm_config_get_is_debug (config)) {
        if (daemon (0, 0) < 0) {
            int saved_errno;

            saved_errno = errno;
            fprintf (stderr, _("Could not daemonize: %s [error %u]\n"),
                     g_strerror (saved_errno),
                     saved_errno);
            exit (1);
        }
        wrote_pidfile = nm_main_utils_write_pidfile (global_opt.pidfile);
    }

    /* Set up unix signal handling - before creating threads, but after daemonizing! */
    nm_main_utils_setup_signals (main_loop);

    nm_logging_syslog_openlog (nm_config_get_is_debug (config)
                               ? "debug"
                               : nm_config_data_get_value_cached (NM_CONFIG_GET_DATA_ORIG,
                                       NM_CONFIG_KEYFILE_GROUP_LOGGING,
                                       NM_CONFIG_KEYFILE_KEY_LOGGING_BACKEND,
                                       NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY));

    nm_log_info (LOGD_CORE, "NetworkManager (version " NM_DIST_VERSION ") is starting...");

    /* Parse the state file */
    if (!parse_state_file (global_opt.state_file, &net_enabled, &wifi_enabled, &wwan_enabled, &error)) {
        nm_log_err (LOGD_CORE, "State file %s parsing failed: %s",
                    global_opt.state_file,
                    error->message);
        /* Not a hard failure */
    }
    g_clear_error (&error);

    nm_log_info (LOGD_CORE, "Read config: %s", nm_config_data_get_config_description (nm_config_get_data (config)));
    nm_config_data_log (nm_config_get_data (config), "CONFIG: ", "  ", NULL);
    nm_log_dbg (LOGD_CORE, "WEXT support is %s",
#if HAVE_WEXT
                "enabled"
#else
                "disabled"
#endif
               );

    nm_auth_manager_setup (nm_config_get_auth_polkit (config));

    nm_manager_setup (global_opt.state_file,
                      net_enabled,
                      wifi_enabled,
                      wwan_enabled);

    if (!nm_bus_manager_get_connection (nm_bus_manager_get ())) {
        nm_log_warn (LOGD_CORE, "Failed to connect to D-Bus; only private bus is available");
    } else {
        /* Start our DBus service */
        if (!nm_bus_manager_start_service (nm_bus_manager_get ())) {
            nm_log_err (LOGD_CORE, "failed to start the dbus service.");
            goto done;
        }
    }

    /* Set up platform interaction layer */
    nm_linux_platform_setup ();

    NM_UTILS_KEEP_ALIVE (config, NM_PLATFORM_GET, "NMConfig-depends-on-NMPlatform");

    nm_dispatcher_init ();

    g_signal_connect (nm_manager_get (), NM_MANAGER_CONFIGURE_QUIT, G_CALLBACK (manager_configure_quit), config);

    if (!nm_manager_start (nm_manager_get (), &error)) {
        nm_log_err (LOGD_CORE, "failed to initialize: %s", error->message);
        goto done;
    }

    /* Make sure the loopback interface is up. If interface is down, we bring
     * it up and kernel will assign it link-local IPv4 and IPv6 addresses. If
     * it was already up, we assume is in clean state.
     *
     * TODO: it might be desirable to check the list of addresses and compare
     * it with a list of expected addresses (one of the protocol families
     * could be disabled). The 'lo' interface is sometimes used for assigning
     * global addresses so their availability doesn't depend on the state of
     * physical interfaces.
     */
    nm_log_dbg (LOGD_CORE, "setting up local loopback");
    nm_platform_link_set_up (NM_PLATFORM_GET, 1, NULL);

    success = TRUE;

    if (configure_and_quit == FALSE) {
        sd_id = nm_sd_event_attach_default ();

        g_main_loop_run (main_loop);
    }

done:
    nm_exported_object_class_set_quitting ();

    nm_manager_stop (nm_manager_get ());

    if (global_opt.pidfile && wrote_pidfile)
        unlink (global_opt.pidfile);

    nm_log_info (LOGD_CORE, "exiting (%s)", success ? "success" : "error");

    nm_clear_g_source (&sd_id);

    exit (success ? 0 : 1);
}
int
main (int argc, char *argv[])
{
    char *bad_domains = NULL;
    GError *error = NULL;
    gboolean wrote_pidfile = FALSE;
    gs_free char *pidfile = NULL;
    gs_unref_object NMDhcpClient *dhcp4_client = NULL;
    gs_unref_object NMRDisc *rdisc = NULL;
    GByteArray *hwaddr = NULL;
    size_t hwaddr_len = 0;
    gconstpointer tmp;
    gs_free NMUtilsIPv6IfaceId *iid = NULL;
    guint sd_id;

    nm_g_type_init ();

    setpgid (getpid (), getpid ());

    do_early_setup (&argc, &argv);

    if (global_opt.g_fatal_warnings) {
        GLogLevelFlags fatal_mask;

        fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
        fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
        g_log_set_always_fatal (fatal_mask);
    }

    if (global_opt.show_version) {
        fprintf (stdout, NM_DIST_VERSION "\n");
        exit (0);
    }

    nm_main_utils_ensure_root ();

    if (!global_opt.ifname || !global_opt.uuid) {
        fprintf (stderr, _("An interface name and UUID are required\n"));
        exit (1);
    }

    ifindex = if_nametoindex (global_opt.ifname);
    if (ifindex <= 0) {
        fprintf (stderr, _("Failed to find interface index for %s (%s)\n"), global_opt.ifname, strerror (errno));
        exit (1);
    }
    pidfile = g_strdup_printf (NMIH_PID_FILE_FMT, ifindex);
    nm_main_utils_ensure_not_running_pidfile (pidfile);

    nm_main_utils_ensure_rundir ();

    if (!nm_logging_setup (global_opt.opt_log_level,
                           global_opt.opt_log_domains,
                           &bad_domains,
                           &error)) {
        fprintf (stderr,
                 _("%s.  Please use --help to see a list of valid options.\n"),
                 error->message);
        exit (1);
    } else if (bad_domains) {
        fprintf (stderr,
                 _("Ignoring unrecognized log domain(s) '%s' passed on command line.\n"),
                 bad_domains);
        g_clear_pointer (&bad_domains, g_free);
    }

    if (global_opt.become_daemon && !global_opt.debug) {
        if (daemon (0, 0) < 0) {
            int saved_errno;

            saved_errno = errno;
            fprintf (stderr, _("Could not daemonize: %s [error %u]\n"),
                     g_strerror (saved_errno),
                     saved_errno);
            exit (1);
        }
        if (nm_main_utils_write_pidfile (pidfile))
            wrote_pidfile = TRUE;
    }

    /* Set up unix signal handling - before creating threads, but after daemonizing! */
    main_loop = g_main_loop_new (NULL, FALSE);
    setup_signals ();

    nm_logging_syslog_openlog (global_opt.logging_backend
                               ? global_opt.logging_backend
                               : (global_opt.debug ? "debug" : NULL));

    nm_log_info (LOGD_CORE, "nm-iface-helper (version " NM_DIST_VERSION ") is starting...");

    /* Set up platform interaction layer */
    nm_linux_platform_setup ();

    tmp = nm_platform_link_get_address (NM_PLATFORM_GET, ifindex, &hwaddr_len);
    if (tmp) {
        hwaddr = g_byte_array_sized_new (hwaddr_len);
        g_byte_array_append (hwaddr, tmp, hwaddr_len);
    }

    if (global_opt.iid_str) {
        GBytes *bytes;
        gsize ignored = 0;

        bytes = nm_utils_hexstr2bin (global_opt.iid_str);
        if (!bytes || g_bytes_get_size (bytes) != sizeof (*iid)) {
            fprintf (stderr, _("(%s): Invalid IID %s\n"), global_opt.ifname, global_opt.iid_str);
            exit (1);
        }
        iid = g_bytes_unref_to_data (bytes, &ignored);
    }

    if (global_opt.dhcp4_address) {
        nm_platform_sysctl_set (NM_PLATFORM_GET, nm_utils_ip4_property_path (global_opt.ifname, "promote_secondaries"), "1");

        dhcp4_client = nm_dhcp_manager_start_ip4 (nm_dhcp_manager_get (),
                       global_opt.ifname,
                       ifindex,
                       hwaddr,
                       global_opt.uuid,
                       global_opt.priority_v4,
                       !!global_opt.dhcp4_hostname,
                       global_opt.dhcp4_hostname,
                       global_opt.dhcp4_fqdn,
                       global_opt.dhcp4_clientid,
                       45,
                       NULL,
                       global_opt.dhcp4_address);
        g_assert (dhcp4_client);
        g_signal_connect (dhcp4_client,
                          NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED,
                          G_CALLBACK (dhcp4_state_changed),
                          NULL);
    }

    if (global_opt.slaac) {
        nm_platform_link_set_user_ipv6ll_enabled (NM_PLATFORM_GET, ifindex, TRUE);

        rdisc = nm_lndp_rdisc_new (NM_PLATFORM_GET, ifindex, global_opt.ifname, global_opt.uuid, global_opt.addr_gen_mode, NULL);
        g_assert (rdisc);

        if (iid)
            nm_rdisc_set_iid (rdisc, *iid);

        nm_platform_sysctl_set (NM_PLATFORM_GET, nm_utils_ip6_property_path (global_opt.ifname, "accept_ra"), "1");
        nm_platform_sysctl_set (NM_PLATFORM_GET, nm_utils_ip6_property_path (global_opt.ifname, "accept_ra_defrtr"), "0");
        nm_platform_sysctl_set (NM_PLATFORM_GET, nm_utils_ip6_property_path (global_opt.ifname, "accept_ra_pinfo"), "0");
        nm_platform_sysctl_set (NM_PLATFORM_GET, nm_utils_ip6_property_path (global_opt.ifname, "accept_ra_rtr_pref"), "0");

        g_signal_connect (NM_PLATFORM_GET,
                          NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED,
                          G_CALLBACK (ip6_address_changed),
                          rdisc);
        g_signal_connect (rdisc,
                          NM_RDISC_CONFIG_CHANGED,
                          G_CALLBACK (rdisc_config_changed),
                          NULL);
        g_signal_connect (rdisc,
                          NM_RDISC_RA_TIMEOUT,
                          G_CALLBACK (rdisc_ra_timeout),
                          NULL);
        nm_rdisc_start (rdisc);
    }

    sd_id = nm_sd_event_attach_default ();

    g_main_loop_run (main_loop);

    g_clear_pointer (&hwaddr, g_byte_array_unref);

    if (pidfile && wrote_pidfile)
        unlink (pidfile);

    nm_log_info (LOGD_CORE, "exiting");

    nm_clear_g_source (&sd_id);
    exit (0);
}
static NMActStageReturn
br2684_create_iface (NMDeviceAdsl *self,
                     NMSettingAdsl *s_adsl,
                     NMDeviceStateReason *out_reason)
{
	NMDeviceAdslPrivate *priv = NM_DEVICE_ADSL_GET_PRIVATE (self);
	struct atm_newif_br2684 ni;
	int err, fd, errsv;
	NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
	guint num = 0;

	g_return_val_if_fail (s_adsl != NULL, FALSE);

	if (priv->nas_update_id) {
		g_warn_if_fail (priv->nas_update_id == 0);
		nm_clear_g_source (&priv->nas_update_id);
	}

	fd = socket (PF_ATMPVC, SOCK_DGRAM, ATM_AAL5);
	if (fd < 0) {
		errsv = errno;
		_LOGE (LOGD_ADSL, "failed to open ATM control socket (%d)", errsv);
		*out_reason = NM_DEVICE_STATE_REASON_BR2684_FAILED;
		return NM_ACT_STAGE_RETURN_FAILURE;
	}

	memset (&ni, 0, sizeof (ni));
	ni.backend_num = ATM_BACKEND_BR2684;
	ni.media = BR2684_MEDIA_ETHERNET;
	ni.mtu = 1500;

	/* Loop attempting to create an interface that doesn't exist yet.  The
	 * kernel can create one for us automatically, but due to API issues it
	 * cannot return that name to us.  Since we want to know the name right
	 * away, just brute-force it.
	 */
	while (num < 10000) {
		memset (&ni.ifname, 0, sizeof (ni.ifname));
		g_snprintf (ni.ifname, sizeof (ni.ifname), "nas%d", num++);

		err = ioctl (fd, ATM_NEWBACKENDIF, &ni);
		if (err == 0) {
			g_free (priv->nas_ifname);
			priv->nas_ifname = g_strdup (ni.ifname);
			_LOGD (LOGD_ADSL, "waiting for br2684 iface '%s' to appear", priv->nas_ifname);

			priv->nas_update_count = 0;
			priv->nas_update_id = g_timeout_add (100, nas_update_cb, self);
			ret = NM_ACT_STAGE_RETURN_POSTPONE;
			break;
		} else if (errno != EEXIST) {
			errsv = errno;
			_LOGW (LOGD_ADSL, "failed to create br2684 interface (%d)", errsv);
			*out_reason = NM_DEVICE_STATE_REASON_BR2684_FAILED;
			break;
		}
	}

	close (fd);
	return ret;
}