mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-28 06:20:10 +01:00
merge: automatic VPN reconnect support (bgo #349151)
This commit is contained in:
commit
b062632474
12 changed files with 335 additions and 41 deletions
|
|
@ -57,6 +57,11 @@ typedef struct {
|
|||
*/
|
||||
char *user_name;
|
||||
|
||||
/* Whether the VPN stays up across link changes, until the user
|
||||
* explicitly disconnects it.
|
||||
*/
|
||||
gboolean persistent;
|
||||
|
||||
/* The hash table is created at setting object
|
||||
* init time and should not be replaced. It is
|
||||
* a char * -> char * mapping, and both the key
|
||||
|
|
@ -80,6 +85,7 @@ enum {
|
|||
PROP_0,
|
||||
PROP_SERVICE_TYPE,
|
||||
PROP_USER_NAME,
|
||||
PROP_PERSISTENT,
|
||||
PROP_DATA,
|
||||
PROP_SECRETS,
|
||||
|
||||
|
|
@ -130,6 +136,20 @@ nm_setting_vpn_get_user_name (NMSettingVpn *setting)
|
|||
return NM_SETTING_VPN_GET_PRIVATE (setting)->user_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_setting_vpn_get_persistent:
|
||||
* @setting: the #NMSettingVpn
|
||||
*
|
||||
* Returns: the #NMSettingVpn:persistent property of the setting
|
||||
**/
|
||||
gboolean
|
||||
nm_setting_vpn_get_persistent (NMSettingVpn *setting)
|
||||
{
|
||||
g_return_val_if_fail (NM_IS_SETTING_VPN (setting), FALSE);
|
||||
|
||||
return NM_SETTING_VPN_GET_PRIVATE (setting)->persistent;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_setting_vpn_get_num_data_items:
|
||||
* @setting: the #NMSettingVpn
|
||||
|
|
@ -721,6 +741,9 @@ set_property (GObject *object, guint prop_id,
|
|||
g_free (priv->user_name);
|
||||
priv->user_name = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_PERSISTENT:
|
||||
priv->persistent = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_DATA:
|
||||
g_hash_table_unref (priv->data);
|
||||
priv->data = _nm_utils_copy_strdict (g_value_get_boxed (value));
|
||||
|
|
@ -749,6 +772,9 @@ get_property (GObject *object, guint prop_id,
|
|||
case PROP_USER_NAME:
|
||||
g_value_set_string (value, nm_setting_vpn_get_user_name (setting));
|
||||
break;
|
||||
case PROP_PERSISTENT:
|
||||
g_value_set_boolean (value, priv->persistent);
|
||||
break;
|
||||
case PROP_DATA:
|
||||
g_value_take_boxed (value, _nm_utils_copy_strdict (priv->data));
|
||||
break;
|
||||
|
|
@ -814,6 +840,20 @@ nm_setting_vpn_class_init (NMSettingVpnClass *setting_class)
|
|||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* NMSettingVpn:persistent:
|
||||
*
|
||||
* If the VPN service supports persistence, and this property is %TRUE,
|
||||
* the VPN will attempt to stay connected across link changes and outages,
|
||||
* until explicitly disconnected.
|
||||
**/
|
||||
g_object_class_install_property
|
||||
(object_class, PROP_PERSISTENT,
|
||||
g_param_spec_boolean (NM_SETTING_VPN_PERSISTENT, "", "",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* NMSettingVpn:data:
|
||||
*
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ G_BEGIN_DECLS
|
|||
|
||||
#define NM_SETTING_VPN_SERVICE_TYPE "service-type"
|
||||
#define NM_SETTING_VPN_USER_NAME "user-name"
|
||||
#define NM_SETTING_VPN_PERSISTENT "persistent"
|
||||
#define NM_SETTING_VPN_DATA "data"
|
||||
#define NM_SETTING_VPN_SECRETS "secrets"
|
||||
|
||||
|
|
@ -70,6 +71,7 @@ GType nm_setting_vpn_get_type (void);
|
|||
NMSetting *nm_setting_vpn_new (void);
|
||||
const char *nm_setting_vpn_get_service_type (NMSettingVpn *setting);
|
||||
const char *nm_setting_vpn_get_user_name (NMSettingVpn *setting);
|
||||
gboolean nm_setting_vpn_get_persistent (NMSettingVpn *setting);
|
||||
|
||||
guint32 nm_setting_vpn_get_num_data_items (NMSettingVpn *setting);
|
||||
void nm_setting_vpn_add_data_item (NMSettingVpn *setting,
|
||||
|
|
|
|||
|
|
@ -206,6 +206,11 @@ typedef enum {
|
|||
/* boolean: Has IP6 configuration? */
|
||||
#define NM_VPN_PLUGIN_CONFIG_HAS_IP6 "has-ip6"
|
||||
|
||||
/* boolean: If %TRUE the VPN plugin can persist/reconnect the connection over
|
||||
* link changes and VPN server dropouts.
|
||||
*/
|
||||
#define NM_VPN_PLUGIN_CAN_PERSIST "can-persist"
|
||||
|
||||
|
||||
/*** Ip4Config ***/
|
||||
|
||||
|
|
|
|||
|
|
@ -206,6 +206,11 @@ typedef enum {
|
|||
/* boolean: Has IP6 configuration? */
|
||||
#define NM_VPN_PLUGIN_CONFIG_HAS_IP6 "has-ip6"
|
||||
|
||||
/* boolean: If %TRUE the VPN plugin can persist/reconnect the connection over
|
||||
* link changes and VPN server dropouts.
|
||||
*/
|
||||
#define NM_VPN_PLUGIN_CAN_PERSIST "can-persist"
|
||||
|
||||
|
||||
/*** Ip4Config ***/
|
||||
|
||||
|
|
|
|||
|
|
@ -81,6 +81,11 @@ typedef struct {
|
|||
*/
|
||||
char *user_name;
|
||||
|
||||
/* Whether the VPN stays up across link changes, until the user
|
||||
* explicitly disconnects it.
|
||||
*/
|
||||
gboolean persistent;
|
||||
|
||||
/* The hash table is created at setting object
|
||||
* init time and should not be replaced. It is
|
||||
* a char * -> char * mapping, and both the key
|
||||
|
|
@ -104,6 +109,7 @@ enum {
|
|||
PROP_0,
|
||||
PROP_SERVICE_TYPE,
|
||||
PROP_USER_NAME,
|
||||
PROP_PERSISTENT,
|
||||
PROP_DATA,
|
||||
PROP_SECRETS,
|
||||
|
||||
|
|
@ -154,6 +160,20 @@ nm_setting_vpn_get_user_name (NMSettingVPN *setting)
|
|||
return NM_SETTING_VPN_GET_PRIVATE (setting)->user_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_setting_vpn_get_persistent:
|
||||
* @setting: the #NMSettingVPN
|
||||
*
|
||||
* Returns: the #NMSettingVPN:persistent property of the setting
|
||||
**/
|
||||
gboolean
|
||||
nm_setting_vpn_get_persistent (NMSettingVPN *setting)
|
||||
{
|
||||
g_return_val_if_fail (NM_IS_SETTING_VPN (setting), FALSE);
|
||||
|
||||
return NM_SETTING_VPN_GET_PRIVATE (setting)->persistent;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_setting_vpn_get_num_data_items:
|
||||
* @setting: the #NMSettingVPN
|
||||
|
|
@ -744,6 +764,9 @@ set_property (GObject *object, guint prop_id,
|
|||
g_free (priv->user_name);
|
||||
priv->user_name = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_PERSISTENT:
|
||||
priv->persistent = g_value_get_boolean (value);
|
||||
break;
|
||||
case PROP_DATA:
|
||||
/* Must make a deep copy of the hash table here... */
|
||||
g_hash_table_remove_all (priv->data);
|
||||
|
|
@ -778,6 +801,9 @@ get_property (GObject *object, guint prop_id,
|
|||
case PROP_USER_NAME:
|
||||
g_value_set_string (value, nm_setting_vpn_get_user_name (setting));
|
||||
break;
|
||||
case PROP_PERSISTENT:
|
||||
g_value_set_boolean (value, priv->persistent);
|
||||
break;
|
||||
case PROP_DATA:
|
||||
g_value_set_boxed (value, priv->data);
|
||||
break;
|
||||
|
|
@ -843,6 +869,20 @@ nm_setting_vpn_class_init (NMSettingVPNClass *setting_class)
|
|||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* NMSettingVPN:persistent:
|
||||
*
|
||||
* If the VPN service supports persistence, and this property is %TRUE,
|
||||
* the VPN will attempt to stay connected across link changes and outages,
|
||||
* until explicitly disconnected.
|
||||
**/
|
||||
g_object_class_install_property
|
||||
(object_class, PROP_PERSISTENT,
|
||||
g_param_spec_boolean (NM_SETTING_VPN_PERSISTENT, "", "",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
/**
|
||||
* NMSettingVPN:data:
|
||||
*
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ GQuark nm_setting_vpn_error_quark (void);
|
|||
|
||||
#define NM_SETTING_VPN_SERVICE_TYPE "service-type"
|
||||
#define NM_SETTING_VPN_USER_NAME "user-name"
|
||||
#define NM_SETTING_VPN_PERSISTENT "persistent"
|
||||
#define NM_SETTING_VPN_DATA "data"
|
||||
#define NM_SETTING_VPN_SECRETS "secrets"
|
||||
|
||||
|
|
@ -85,6 +86,7 @@ GType nm_setting_vpn_get_type (void);
|
|||
NMSetting *nm_setting_vpn_new (void);
|
||||
const char *nm_setting_vpn_get_service_type (NMSettingVPN *setting);
|
||||
const char *nm_setting_vpn_get_user_name (NMSettingVPN *setting);
|
||||
gboolean nm_setting_vpn_get_persistent (NMSettingVPN *setting);
|
||||
|
||||
guint32 nm_setting_vpn_get_num_data_items (NMSettingVPN *setting);
|
||||
void nm_setting_vpn_add_data_item (NMSettingVPN *setting,
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "nm-types.h"
|
||||
#include "nm-active-connection.h"
|
||||
#include "nm-dbus-interface.h"
|
||||
|
|
@ -30,7 +31,7 @@
|
|||
#include "nm-auth-utils.h"
|
||||
#include "nm-auth-subject.h"
|
||||
#include "NetworkManagerUtils.h"
|
||||
|
||||
#include "gsystem-local-alloc.h"
|
||||
#include "nm-active-connection-glue.h"
|
||||
|
||||
/* Base class for anything implementing the Connection.Active D-Bus interface */
|
||||
|
|
@ -94,6 +95,12 @@ enum {
|
|||
LAST_PROP
|
||||
};
|
||||
|
||||
enum {
|
||||
DEVICE_CHANGED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void check_master_ready (NMActiveConnection *self);
|
||||
static void _device_cleanup (NMActiveConnection *self);
|
||||
|
||||
|
|
@ -395,20 +402,23 @@ gboolean
|
|||
nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device)
|
||||
{
|
||||
NMActiveConnectionPrivate *priv;
|
||||
gs_unref_object NMDevice *old_device = NULL;
|
||||
|
||||
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);
|
||||
g_return_val_if_fail (!device || NM_IS_DEVICE (device), FALSE);
|
||||
|
||||
priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
|
||||
if (device == priv->device)
|
||||
return TRUE;
|
||||
|
||||
old_device = priv->device ? g_object_ref (priv->device) : NULL;
|
||||
_device_cleanup (self);
|
||||
|
||||
if (device) {
|
||||
g_return_val_if_fail (priv->device == NULL, FALSE);
|
||||
|
||||
/* Device obviously can't be its own master */
|
||||
g_return_val_if_fail (!priv->master || device != nm_active_connection_get_device (priv->master), FALSE);
|
||||
|
||||
priv->device = g_object_ref (device);
|
||||
g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_INT_DEVICE);
|
||||
|
||||
g_signal_connect (device, "state-changed",
|
||||
G_CALLBACK (device_state_changed), self);
|
||||
|
|
@ -419,7 +429,14 @@ nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device)
|
|||
priv->pending_activation_id = g_strdup_printf ("activation::%p", (void *)self);
|
||||
nm_device_add_pending_action (device, priv->pending_activation_id, TRUE);
|
||||
}
|
||||
}
|
||||
} else
|
||||
priv->device = NULL;
|
||||
g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_INT_DEVICE);
|
||||
|
||||
g_signal_emit (self, signals[DEVICE_CHANGED], 0, priv->device, old_device);
|
||||
|
||||
g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEVICES);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -1014,6 +1031,14 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class)
|
|||
FALSE, G_PARAM_READABLE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
signals[DEVICE_CHANGED] =
|
||||
g_signal_new (NM_ACTIVE_CONNECTION_DEVICE_CHANGED,
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (NMActiveConnectionClass, device_changed),
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 2, NM_TYPE_DEVICE, NM_TYPE_DEVICE);
|
||||
|
||||
nm_dbus_manager_register_exported_type (nm_dbus_manager_get (),
|
||||
G_TYPE_FROM_CLASS (ac_class),
|
||||
&dbus_glib_nm_active_connection_object_info);
|
||||
|
|
|
|||
|
|
@ -56,6 +56,9 @@
|
|||
#define NM_ACTIVE_CONNECTION_INT_MASTER "int-master"
|
||||
#define NM_ACTIVE_CONNECTION_INT_MASTER_READY "int-master-ready"
|
||||
|
||||
/* Internal signals*/
|
||||
#define NM_ACTIVE_CONNECTION_DEVICE_CHANGED "device-changed"
|
||||
|
||||
struct _NMActiveConnection {
|
||||
GObject parent;
|
||||
};
|
||||
|
|
@ -71,6 +74,10 @@ typedef struct {
|
|||
NMDeviceState new_state,
|
||||
NMDeviceState old_state);
|
||||
void (*master_failed) (NMActiveConnection *connection);
|
||||
|
||||
void (*device_changed) (NMActiveConnection *connection,
|
||||
NMDevice *new_device,
|
||||
NMDevice *old_device);
|
||||
} NMActiveConnectionClass;
|
||||
|
||||
GType nm_active_connection_get_type (void);
|
||||
|
|
|
|||
|
|
@ -658,6 +658,20 @@ update_ip4_routing (NMPolicy *policy, gboolean force_update)
|
|||
|
||||
gw_addr = nm_ip4_config_get_gateway (ip4_config);
|
||||
|
||||
if (best) {
|
||||
const GSList *connections, *iter;
|
||||
|
||||
connections = nm_manager_get_active_connections (priv->manager);
|
||||
for (iter = connections; iter; iter = g_slist_next (iter)) {
|
||||
NMActiveConnection *active = iter->data;
|
||||
|
||||
if ( NM_IS_VPN_CONNECTION (active)
|
||||
&& nm_vpn_connection_get_ip4_config (NM_VPN_CONNECTION (active))
|
||||
&& !nm_active_connection_get_device (active))
|
||||
nm_active_connection_set_device (active, best);
|
||||
}
|
||||
}
|
||||
|
||||
if (vpn) {
|
||||
NMDevice *parent = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
|
||||
int parent_ifindex = nm_device_get_ip_ifindex (parent);
|
||||
|
|
@ -861,6 +875,20 @@ update_ip6_routing (NMPolicy *policy, gboolean force_update)
|
|||
if (!gw_addr)
|
||||
gw_addr = &in6addr_any;
|
||||
|
||||
if (best) {
|
||||
const GSList *connections, *iter;
|
||||
|
||||
connections = nm_manager_get_active_connections (priv->manager);
|
||||
for (iter = connections; iter; iter = g_slist_next (iter)) {
|
||||
NMActiveConnection *active = iter->data;
|
||||
|
||||
if ( NM_IS_VPN_CONNECTION (active)
|
||||
&& nm_vpn_connection_get_ip6_config (NM_VPN_CONNECTION (active))
|
||||
&& !nm_active_connection_get_device (active))
|
||||
nm_active_connection_set_device (active, best);
|
||||
}
|
||||
}
|
||||
|
||||
if (vpn) {
|
||||
NMDevice *parent = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
|
||||
int parent_ifindex = nm_device_get_ip_ifindex (parent);
|
||||
|
|
@ -1807,6 +1835,28 @@ vpn_connection_state_changed (NMVpnConnection *vpn,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
vpn_connection_retry_after_failure (NMVpnConnection *vpn, NMPolicy *policy)
|
||||
{
|
||||
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy);
|
||||
NMActiveConnection *ac = NM_ACTIVE_CONNECTION (vpn);
|
||||
NMConnection *connection = nm_active_connection_get_connection (ac);
|
||||
GError *error = NULL;
|
||||
|
||||
/* Attempt to reconnect VPN connections that failed after being connected */
|
||||
if (!nm_manager_activate_connection (priv->manager,
|
||||
connection,
|
||||
NULL,
|
||||
NULL,
|
||||
nm_active_connection_get_subject (ac),
|
||||
&error)) {
|
||||
nm_log_warn (LOGD_DEVICE, "VPN '%s' reconnect failed: %s",
|
||||
nm_connection_get_id (connection),
|
||||
error->message ? error->message : "unknown");
|
||||
g_clear_error (&error);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
active_connection_state_changed (NMActiveConnection *active,
|
||||
GParamSpec *pspec,
|
||||
|
|
@ -1831,6 +1881,9 @@ active_connection_added (NMManager *manager,
|
|||
g_signal_connect (active, NM_VPN_CONNECTION_INTERNAL_STATE_CHANGED,
|
||||
G_CALLBACK (vpn_connection_state_changed),
|
||||
policy);
|
||||
g_signal_connect (active, NM_VPN_CONNECTION_INTERNAL_RETRY_AFTER_FAILURE,
|
||||
G_CALLBACK (vpn_connection_retry_after_failure),
|
||||
policy);
|
||||
}
|
||||
|
||||
g_signal_connect (active, "notify::" NM_ACTIVE_CONNECTION_STATE,
|
||||
|
|
@ -1848,6 +1901,9 @@ active_connection_removed (NMManager *manager,
|
|||
g_signal_handlers_disconnect_by_func (active,
|
||||
vpn_connection_state_changed,
|
||||
policy);
|
||||
g_signal_handlers_disconnect_by_func (active,
|
||||
vpn_connection_retry_after_failure,
|
||||
policy);
|
||||
g_signal_handlers_disconnect_by_func (active,
|
||||
active_connection_state_changed,
|
||||
policy);
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "reader.h"
|
||||
#include "common.h"
|
||||
#include "utils.h"
|
||||
#include "nm-core-internal.h"
|
||||
|
||||
/* Some setting properties also contain setting names, such as
|
||||
* NMSettingConnection's 'type' property (which specifies the base type of the
|
||||
|
|
@ -616,7 +617,8 @@ read_hash_of_string (GKeyFile *file, NMSetting *setting, const char *key)
|
|||
continue;
|
||||
|
||||
if (NM_IS_SETTING_VPN (setting)) {
|
||||
if (strcmp (*iter, NM_SETTING_VPN_SERVICE_TYPE) && strcmp (*iter, NM_SETTING_VPN_USER_NAME))
|
||||
/* Add any item that's not a class property to the data hash */
|
||||
if (!g_object_class_find_property (G_OBJECT_GET_CLASS (setting), *iter))
|
||||
nm_setting_vpn_add_data_item (NM_SETTING_VPN (setting), *iter, value);
|
||||
}
|
||||
if (NM_IS_SETTING_BOND (setting)) {
|
||||
|
|
|
|||
|
|
@ -76,6 +76,8 @@ typedef enum {
|
|||
|
||||
typedef struct {
|
||||
NMConnection *connection;
|
||||
gboolean service_can_persist;
|
||||
gboolean connection_can_persist;
|
||||
|
||||
guint32 secrets_id;
|
||||
SecretsReq secrets_idx;
|
||||
|
|
@ -85,6 +87,8 @@ typedef struct {
|
|||
guint dispatcher_id;
|
||||
NMVpnConnectionStateReason failure_reason;
|
||||
|
||||
NMVpnServiceState service_state;
|
||||
|
||||
DBusGProxy *proxy;
|
||||
GHashTable *connect_hash;
|
||||
guint connect_timeout;
|
||||
|
|
@ -107,6 +111,7 @@ typedef struct {
|
|||
enum {
|
||||
VPN_STATE_CHANGED,
|
||||
INTERNAL_STATE_CHANGED,
|
||||
INTERNAL_RETRY_AFTER_FAILURE,
|
||||
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
|
@ -431,12 +436,34 @@ _set_vpn_state (NMVpnConnection *connection,
|
|||
g_object_unref (parent_dev);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_service_and_connection_can_persist (NMVpnConnection *self)
|
||||
{
|
||||
return NM_VPN_CONNECTION_GET_PRIVATE (self)->connection_can_persist &&
|
||||
NM_VPN_CONNECTION_GET_PRIVATE (self)->service_can_persist;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_connection_only_can_persist (NMVpnConnection *self)
|
||||
{
|
||||
return NM_VPN_CONNECTION_GET_PRIVATE (self)->connection_can_persist &&
|
||||
!NM_VPN_CONNECTION_GET_PRIVATE (self)->service_can_persist;
|
||||
}
|
||||
|
||||
static void
|
||||
device_state_changed (NMActiveConnection *active,
|
||||
NMDevice *device,
|
||||
NMDeviceState new_state,
|
||||
NMDeviceState old_state)
|
||||
{
|
||||
if (_service_and_connection_can_persist (NM_VPN_CONNECTION (active))) {
|
||||
if (new_state <= NM_DEVICE_STATE_DISCONNECTED ||
|
||||
new_state == NM_DEVICE_STATE_FAILED) {
|
||||
nm_active_connection_set_device (active, NULL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (new_state <= NM_DEVICE_STATE_DISCONNECTED) {
|
||||
_set_vpn_state (NM_VPN_CONNECTION (active),
|
||||
STATE_DISCONNECTED,
|
||||
|
|
@ -699,29 +726,45 @@ vpn_reason_to_string (NMVpnConnectionStateReason reason)
|
|||
|
||||
static void
|
||||
plugin_state_changed (DBusGProxy *proxy,
|
||||
NMVpnServiceState state,
|
||||
NMVpnServiceState new_service_state,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMVpnConnection *connection = NM_VPN_CONNECTION (user_data);
|
||||
NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
|
||||
NMVpnServiceState old_service_state = priv->service_state;
|
||||
|
||||
nm_log_info (LOGD_VPN, "VPN plugin state changed: %s (%d)",
|
||||
vpn_service_state_to_string (state), state);
|
||||
vpn_service_state_to_string (new_service_state), new_service_state);
|
||||
priv->service_state = new_service_state;
|
||||
|
||||
if (state == NM_VPN_SERVICE_STATE_STOPPED) {
|
||||
if (new_service_state == NM_VPN_SERVICE_STATE_STOPPED) {
|
||||
/* Clear connection secrets to ensure secrets get requested each time the
|
||||
* connection is activated.
|
||||
*/
|
||||
nm_connection_clear_secrets (priv->connection);
|
||||
|
||||
if ((priv->vpn_state >= STATE_WAITING) && (priv->vpn_state <= STATE_ACTIVATED)) {
|
||||
VpnState old_state = priv->vpn_state;
|
||||
|
||||
nm_log_info (LOGD_VPN, "VPN plugin state change reason: %s (%d)",
|
||||
vpn_reason_to_string (priv->failure_reason), priv->failure_reason);
|
||||
_set_vpn_state (connection, STATE_FAILED, priv->failure_reason, FALSE);
|
||||
|
||||
/* Reset the failure reason */
|
||||
priv->failure_reason = NM_VPN_CONNECTION_STATE_REASON_UNKNOWN;
|
||||
|
||||
/* If the connection failed, the service cannot persist, but the
|
||||
* connection can persist, ask listeners to re-activate the connection.
|
||||
*/
|
||||
if ( old_state == STATE_ACTIVATED
|
||||
&& priv->vpn_state == STATE_FAILED
|
||||
&& _connection_only_can_persist (connection))
|
||||
g_signal_emit (connection, signals[INTERNAL_RETRY_AFTER_FAILURE], 0);
|
||||
}
|
||||
} else if (new_service_state == NM_VPN_SERVICE_STATE_STARTING &&
|
||||
old_service_state == NM_VPN_SERVICE_STATE_STARTED) {
|
||||
/* The VPN service got disconnected and is attempting to reconnect */
|
||||
_set_vpn_state (connection, STATE_CONNECT, NM_VPN_CONNECTION_STATE_REASON_CONNECT_TIMEOUT, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -829,41 +872,29 @@ print_vpn_config (NMVpnConnection *connection)
|
|||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
nm_vpn_connection_apply_config (NMVpnConnection *connection)
|
||||
static void
|
||||
apply_parent_device_config (NMVpnConnection *connection)
|
||||
{
|
||||
NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
|
||||
NMDevice *parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (connection));
|
||||
NMIP4Config *vpn4_parent_config = NULL;
|
||||
NMIP6Config *vpn6_parent_config = NULL;
|
||||
|
||||
if (priv->ip_ifindex > 0) {
|
||||
nm_platform_link_set_up (priv->ip_ifindex);
|
||||
if (priv->ip4_config)
|
||||
vpn4_parent_config = nm_ip4_config_new ();
|
||||
if (priv->ip6_config)
|
||||
vpn6_parent_config = nm_ip6_config_new ();
|
||||
|
||||
if (priv->ip4_config) {
|
||||
if (!nm_ip4_config_commit (priv->ip4_config, priv->ip_ifindex))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (priv->ip6_config) {
|
||||
if (!nm_ip6_config_commit (priv->ip6_config, priv->ip_ifindex))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (priv->ip4_config)
|
||||
vpn4_parent_config = nm_ip4_config_new ();
|
||||
if (priv->ip6_config)
|
||||
vpn6_parent_config = nm_ip6_config_new ();
|
||||
} else {
|
||||
if (priv->ip_ifindex <= 0) {
|
||||
/* If the VPN didn't return a network interface, it is a route-based
|
||||
* VPN (like kernel IPSec) and all IP addressing and routing should
|
||||
* be done on the parent interface instead.
|
||||
*/
|
||||
|
||||
if (priv->ip4_config)
|
||||
vpn4_parent_config = g_object_ref (priv->ip4_config);
|
||||
if (priv->ip6_config)
|
||||
vpn6_parent_config = g_object_ref (priv->ip6_config);
|
||||
if (vpn4_parent_config)
|
||||
nm_ip4_config_merge (vpn4_parent_config, priv->ip4_config);
|
||||
if (vpn6_parent_config)
|
||||
nm_ip6_config_merge (vpn6_parent_config, priv->ip6_config);
|
||||
}
|
||||
|
||||
if (vpn4_parent_config) {
|
||||
|
|
@ -882,6 +913,28 @@ nm_vpn_connection_apply_config (NMVpnConnection *connection)
|
|||
nm_device_set_vpn6_config (parent_dev, vpn6_parent_config);
|
||||
g_object_unref (vpn6_parent_config);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
nm_vpn_connection_apply_config (NMVpnConnection *connection)
|
||||
{
|
||||
NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
|
||||
|
||||
if (priv->ip_ifindex > 0) {
|
||||
nm_platform_link_set_up (priv->ip_ifindex);
|
||||
|
||||
if (priv->ip4_config) {
|
||||
if (!nm_ip4_config_commit (priv->ip4_config, priv->ip_ifindex))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (priv->ip6_config) {
|
||||
if (!nm_ip6_config_commit (priv->ip6_config, priv->ip_ifindex))
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
apply_parent_device_config (connection);
|
||||
|
||||
nm_log_info (LOGD_VPN, "VPN connection '%s' (IP Config Get) complete.",
|
||||
nm_connection_get_id (priv->connection));
|
||||
|
|
@ -895,12 +948,8 @@ nm_vpn_connection_config_maybe_complete (NMVpnConnection *connection,
|
|||
{
|
||||
NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
|
||||
|
||||
if (priv->connect_timeout == 0) {
|
||||
/* config_complete() was already called with an error;
|
||||
* ignore further calls.
|
||||
*/
|
||||
if (priv->vpn_state < STATE_IP_CONFIG_GET || priv->vpn_state > STATE_ACTIVATED)
|
||||
return;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
if ( (priv->has_ip4 && !priv->ip4_config)
|
||||
|
|
@ -910,8 +959,10 @@ nm_vpn_connection_config_maybe_complete (NMVpnConnection *connection,
|
|||
}
|
||||
}
|
||||
|
||||
g_source_remove (priv->connect_timeout);
|
||||
priv->connect_timeout = 0;
|
||||
if (priv->connect_timeout == 0) {
|
||||
g_source_remove (priv->connect_timeout);
|
||||
priv->connect_timeout = 0;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
print_vpn_config (connection);
|
||||
|
|
@ -939,6 +990,12 @@ process_generic_config (NMVpnConnection *connection,
|
|||
NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
|
||||
GValue *val;
|
||||
|
||||
val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CAN_PERSIST);
|
||||
if (val && G_VALUE_HOLDS_BOOLEAN (val) && g_value_get_boolean (val)) {
|
||||
/* Defaults to FALSE, so only let service indicate TRUE */
|
||||
priv->service_can_persist = TRUE;
|
||||
}
|
||||
|
||||
g_clear_pointer (&priv->ip_iface, g_free);
|
||||
val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_CONFIG_TUNDEV);
|
||||
if (val) {
|
||||
|
|
@ -1210,6 +1267,7 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
|
|||
nm_connection_get_setting_ip4_config (priv->connection),
|
||||
vpn_routing_metric (connection));
|
||||
|
||||
g_clear_object (&priv->ip4_config);
|
||||
priv->ip4_config = config;
|
||||
nm_ip4_config_export (config);
|
||||
g_object_notify (G_OBJECT (connection), NM_ACTIVE_CONNECTION_IP4_CONFIG);
|
||||
|
|
@ -1356,6 +1414,7 @@ nm_vpn_connection_ip6_config_get (DBusGProxy *proxy,
|
|||
nm_connection_get_setting_ip6_config (priv->connection),
|
||||
vpn_routing_metric (connection));
|
||||
|
||||
g_clear_object (&priv->ip6_config);
|
||||
priv->ip6_config = config;
|
||||
nm_ip6_config_export (config);
|
||||
g_object_notify (G_OBJECT (connection), NM_ACTIVE_CONNECTION_IP6_CONFIG);
|
||||
|
|
@ -1551,12 +1610,17 @@ void
|
|||
nm_vpn_connection_activate (NMVpnConnection *connection)
|
||||
{
|
||||
NMVpnConnectionPrivate *priv;
|
||||
NMSettingVpn *s_vpn;
|
||||
DBusGConnection *bus;
|
||||
|
||||
g_return_if_fail (NM_IS_VPN_CONNECTION (connection));
|
||||
|
||||
priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
|
||||
|
||||
s_vpn = nm_connection_get_setting_vpn (priv->connection);
|
||||
g_assert (s_vpn);
|
||||
priv->connection_can_persist = nm_setting_vpn_get_persistent (s_vpn);
|
||||
|
||||
_set_vpn_state (connection, STATE_PREPARE, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE);
|
||||
|
||||
bus = nm_dbus_manager_get_connection (nm_dbus_manager_get ());
|
||||
|
|
@ -1751,7 +1815,9 @@ plugin_new_secrets_cb (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data
|
|||
NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
|
||||
GError *error = NULL;
|
||||
|
||||
if (!dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID)) {
|
||||
if (dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID)) {
|
||||
_set_vpn_state (self, STATE_CONNECT, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE);
|
||||
} else {
|
||||
nm_log_err (LOGD_VPN, "(%s/%s) sending new secrets to the plugin failed: %s %s",
|
||||
nm_connection_get_uuid (priv->connection),
|
||||
nm_connection_get_id (priv->connection),
|
||||
|
|
@ -1905,6 +1971,39 @@ plugin_interactive_secrets_required (DBusGProxy *proxy,
|
|||
|
||||
/******************************************************************************/
|
||||
|
||||
static void
|
||||
device_changed (NMActiveConnection *active,
|
||||
NMDevice *new_device,
|
||||
NMDevice *old_device)
|
||||
{
|
||||
NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (active);
|
||||
|
||||
if (!_service_and_connection_can_persist (NM_VPN_CONNECTION (active)))
|
||||
return;
|
||||
if (priv->vpn_state < STATE_CONNECT || priv->vpn_state > STATE_ACTIVATED)
|
||||
return;
|
||||
|
||||
/* Route-based VPNs must update their routing and send a new IP config
|
||||
* since all their routes need to be adjusted for new_device.
|
||||
*/
|
||||
if (priv->ip_ifindex <= 0)
|
||||
return;
|
||||
|
||||
/* Device changed underneath the VPN connection. Let the plugin figure
|
||||
* out that connectivity is down and start its reconnect attempt if it
|
||||
* needs to.
|
||||
*/
|
||||
if (old_device) {
|
||||
nm_device_set_vpn4_config (old_device, NULL);
|
||||
nm_device_set_vpn6_config (old_device, NULL);
|
||||
}
|
||||
|
||||
if (new_device)
|
||||
apply_parent_device_config (NM_VPN_CONNECTION (active));
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void
|
||||
nm_vpn_connection_init (NMVpnConnection *self)
|
||||
{
|
||||
|
|
@ -2026,6 +2125,7 @@ nm_vpn_connection_class_init (NMVpnConnectionClass *connection_class)
|
|||
object_class->dispose = dispose;
|
||||
object_class->finalize = finalize;
|
||||
active_class->device_state_changed = device_state_changed;
|
||||
active_class->device_changed = device_changed;
|
||||
|
||||
g_object_class_override_property (object_class, PROP_MASTER, NM_ACTIVE_CONNECTION_MASTER);
|
||||
|
||||
|
|
@ -2066,6 +2166,13 @@ nm_vpn_connection_class_init (NMVpnConnectionClass *connection_class)
|
|||
0, NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
|
||||
|
||||
signals[INTERNAL_RETRY_AFTER_FAILURE] =
|
||||
g_signal_new (NM_VPN_CONNECTION_INTERNAL_RETRY_AFTER_FAILURE,
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
nm_dbus_manager_register_exported_type (nm_dbus_manager_get (),
|
||||
G_TYPE_FROM_CLASS (object_class),
|
||||
&dbus_glib_nm_vpn_connection_object_info);
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@
|
|||
|
||||
/* Signals */
|
||||
/* not exported: includes old reason code */
|
||||
#define NM_VPN_CONNECTION_INTERNAL_STATE_CHANGED "internal-state-changed"
|
||||
#define NM_VPN_CONNECTION_INTERNAL_STATE_CHANGED "internal-state-changed"
|
||||
#define NM_VPN_CONNECTION_INTERNAL_RETRY_AFTER_FAILURE "internal-retry-after-failure"
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -62,6 +63,8 @@ typedef struct {
|
|||
NMVpnConnectionState new_state,
|
||||
NMVpnConnectionState old_state,
|
||||
NMVpnConnectionStateReason reason);
|
||||
|
||||
void (*internal_failed_retry) (NMVpnConnection *connection);
|
||||
} NMVpnConnectionClass;
|
||||
|
||||
GType nm_vpn_connection_get_type (void);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue