merge branch 'th/bgo580018_autoconnect_priority'

Add configuration option NMSettingConnection:autoconnect-priority.
This new option is only relevant for connections that are set to
autoconnect. When having more then one candicate for autoconnect, this
new setting allows to always prefer one connection over the other.

If both connections have the same priority setting, the previous
automatism is used to choose the best candidate. That is, NM will
choose the least recently connected candidate.
See also the still unresolved but related bug bgo#737356 that asks
for providing a different automatism.

https://bugzilla.gnome.org/show_bug.cgi?id=580018

Signed-off-by: Thomas Haller <thaller@redhat.com>
This commit is contained in:
Thomas Haller 2014-10-12 20:15:42 +02:00
commit a7c8e5c6e9
21 changed files with 360 additions and 93 deletions

View file

@ -61,15 +61,16 @@ static NmcOutputField nmc_fields_con_show[] = {
{"TIMESTAMP", N_("TIMESTAMP"), 12}, /* 3 */
{"TIMESTAMP-REAL", N_("TIMESTAMP-REAL"), 34}, /* 4 */
{"AUTOCONNECT", N_("AUTOCONNECT"), 13}, /* 5 */
{"READONLY", N_("READONLY"), 10}, /* 6 */
{"DBUS-PATH", N_("DBUS-PATH"), 42}, /* 7 */
{"ACTIVE", N_("ACTIVE"), 10}, /* 8 */
{"DEVICE", N_("DEVICE"), 10}, /* 9 */
{"STATE", N_("STATE"), 12}, /* 10 */
{"ACTIVE-PATH", N_("ACTIVE-PATH"), 51}, /* 11 */
{"AUTOCONNECT-PRIORITY", N_("AUTOCONNECT-PRIORITY"), 10}, /* 6 */
{"READONLY", N_("READONLY"), 10}, /* 7 */
{"DBUS-PATH", N_("DBUS-PATH"), 42}, /* 8 */
{"ACTIVE", N_("ACTIVE"), 10}, /* 9 */
{"DEVICE", N_("DEVICE"), 10}, /* 10 */
{"STATE", N_("STATE"), 12}, /* 11 */
{"ACTIVE-PATH", N_("ACTIVE-PATH"), 51}, /* 12 */
{NULL, NULL, 0}
};
#define NMC_FIELDS_CON_SHOW_ALL "NAME,UUID,TYPE,TIMESTAMP,TIMESTAMP-REAL,AUTOCONNECT,READONLY,DBUS-PATH,"\
#define NMC_FIELDS_CON_SHOW_ALL "NAME,UUID,TYPE,TIMESTAMP,TIMESTAMP-REAL,AUTOCONNECT,AUTOCONNECT-PRIORITY,READONLY,DBUS-PATH,"\
"ACTIVE,DEVICE,STATE,ACTIVE-PATH"
#define NMC_FIELDS_CON_SHOW_COMMON "NAME,UUID,TYPE,DEVICE"
@ -745,6 +746,7 @@ fill_output_connection (gpointer data, gpointer user_data, gboolean active_only)
time_t timestamp_real;
char *timestamp_str;
char *timestamp_real_str = "";
char *prio_str;
NmcOutputField *arr;
NMActiveConnection *ac = NULL;
const char *ac_path = NULL;
@ -772,6 +774,7 @@ fill_output_connection (gpointer data, gpointer user_data, gboolean active_only)
timestamp_real_str = g_malloc0 (64);
strftime (timestamp_real_str, 64, "%c", localtime (&timestamp_real));
}
prio_str = g_strdup_printf ("%u", nm_setting_connection_get_autoconnect_priority (s_con));
arr = nmc_dup_fields_array (nmc_fields_con_show,
sizeof (nmc_fields_con_show),
@ -782,12 +785,13 @@ fill_output_connection (gpointer data, gpointer user_data, gboolean active_only)
set_val_str (arr, 3, timestamp_str);
set_val_str (arr, 4, timestamp ? timestamp_real_str : g_strdup (_("never")));
set_val_strc (arr, 5, nm_setting_connection_get_autoconnect (s_con) ? _("yes") : _("no"));
set_val_strc (arr, 6, nm_setting_connection_get_read_only (s_con) ? _("yes") : _("no"));
set_val_strc (arr, 7, nm_connection_get_path (connection));
set_val_strc (arr, 8, ac ? _("yes") : _("no"));
set_val_str (arr, 9, ac_dev);
set_val_strc (arr, 10, ac_state);
set_val_strc (arr, 11, ac_path);
set_val_str (arr, 6, prio_str);
set_val_strc (arr, 7, nm_setting_connection_get_read_only (s_con) ? _("yes") : _("no"));
set_val_strc (arr, 8, nm_connection_get_path (connection));
set_val_strc (arr, 9, ac ? _("yes") : _("no"));
set_val_str (arr, 10, ac_dev);
set_val_strc (arr, 11, ac_state);
set_val_strc (arr, 12, ac_path);
g_ptr_array_add (nmc->output_data, arr);
}

View file

@ -43,14 +43,15 @@ NmcOutputField nmc_fields_setting_connection[] = {
SETTING_FIELD (NM_SETTING_CONNECTION_INTERFACE_NAME, 20), /* 3 */
SETTING_FIELD (NM_SETTING_CONNECTION_TYPE, 17), /* 4 */
SETTING_FIELD (NM_SETTING_CONNECTION_AUTOCONNECT, 13), /* 5 */
SETTING_FIELD (NM_SETTING_CONNECTION_TIMESTAMP, 10), /* 6 */
SETTING_FIELD (NM_SETTING_CONNECTION_READ_ONLY, 10), /* 7 */
SETTING_FIELD (NM_SETTING_CONNECTION_PERMISSIONS, 30), /* 8 */
SETTING_FIELD (NM_SETTING_CONNECTION_ZONE, 10), /* 9 */
SETTING_FIELD (NM_SETTING_CONNECTION_MASTER, 20), /* 10 */
SETTING_FIELD (NM_SETTING_CONNECTION_SLAVE_TYPE, 20), /* 11 */
SETTING_FIELD (NM_SETTING_CONNECTION_SECONDARIES, 40), /* 12 */
SETTING_FIELD (NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT, 30), /* 13 */
SETTING_FIELD (NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY, 10), /* 6 */
SETTING_FIELD (NM_SETTING_CONNECTION_TIMESTAMP, 10), /* 7 */
SETTING_FIELD (NM_SETTING_CONNECTION_READ_ONLY, 10), /* 8 */
SETTING_FIELD (NM_SETTING_CONNECTION_PERMISSIONS, 30), /* 9 */
SETTING_FIELD (NM_SETTING_CONNECTION_ZONE, 10), /* 10 */
SETTING_FIELD (NM_SETTING_CONNECTION_MASTER, 20), /* 11 */
SETTING_FIELD (NM_SETTING_CONNECTION_SLAVE_TYPE, 20), /* 12 */
SETTING_FIELD (NM_SETTING_CONNECTION_SECONDARIES, 40), /* 13 */
SETTING_FIELD (NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT, 30), /* 14 */
{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
};
#define NMC_FIELDS_SETTING_CONNECTION_ALL "name"","\
@ -59,6 +60,7 @@ NmcOutputField nmc_fields_setting_connection[] = {
NM_SETTING_CONNECTION_INTERFACE_NAME","\
NM_SETTING_CONNECTION_TYPE","\
NM_SETTING_CONNECTION_AUTOCONNECT","\
NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY","\
NM_SETTING_CONNECTION_TIMESTAMP","\
NM_SETTING_CONNECTION_READ_ONLY","\
NM_SETTING_CONNECTION_PERMISSIONS","\
@ -1004,6 +1006,7 @@ DEFINE_GETTER (nmc_property_connection_get_uuid, NM_SETTING_CONNECTION_UUID)
DEFINE_GETTER (nmc_property_connection_get_interface_name, NM_SETTING_CONNECTION_INTERFACE_NAME)
DEFINE_GETTER (nmc_property_connection_get_type, NM_SETTING_CONNECTION_TYPE)
DEFINE_GETTER (nmc_property_connection_get_autoconnect, NM_SETTING_CONNECTION_AUTOCONNECT)
DEFINE_GETTER (nmc_property_connection_get_autoconnect_priority, NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY)
DEFINE_GETTER (nmc_property_connection_get_timestamp, NM_SETTING_CONNECTION_TIMESTAMP)
DEFINE_GETTER (nmc_property_connection_get_read_only, NM_SETTING_CONNECTION_READ_ONLY)
@ -2155,7 +2158,27 @@ nmc_property_set_uint (NMSetting *setting, const char *prop, const char *val, GE
if (!validate_uint (setting, prop, (guint) val_int, error))
return FALSE;
g_object_set (setting, prop, val_int, NULL);
g_object_set (setting, prop, (guint) val_int, NULL);
return TRUE;
}
static gboolean
nmc_property_set_int (NMSetting *setting, const char *prop, const char *val, GError **error)
{
long int val_int;
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
if (!nmc_string_to_int (val, TRUE, G_MININT, G_MAXINT, &val_int)) {
g_set_error (error, 1, 0, _("'%s' is not a valid number (or out of range)"), val);
return FALSE;
}
/* Validate the number according to the property spec */
if (!validate_int (setting, prop, (gint) val_int, error))
return FALSE;
g_object_set (setting, prop, (gint) val_int, NULL);
return TRUE;
}
@ -5115,6 +5138,13 @@ nmc_properties_init (void)
NULL,
NULL,
NULL);
nmc_add_prop_funcs (GLUE (CONNECTION, AUTOCONNECT_PRIORITY),
nmc_property_connection_get_autoconnect_priority,
nmc_property_set_int,
NULL,
NULL,
NULL,
NULL);
nmc_add_prop_funcs (GLUE (CONNECTION, TIMESTAMP),
nmc_property_connection_get_timestamp,
NULL, /* read-only */
@ -6482,14 +6512,15 @@ setting_connection_details (NMSetting *setting, NmCli *nmc, const char *one_prop
set_val_str (arr, 3, nmc_property_connection_get_interface_name (setting));
set_val_str (arr, 4, nmc_property_connection_get_type (setting));
set_val_str (arr, 5, nmc_property_connection_get_autoconnect (setting));
set_val_str (arr, 6, nmc_property_connection_get_timestamp (setting));
set_val_str (arr, 7, nmc_property_connection_get_read_only (setting));
set_val_str (arr, 8, nmc_property_connection_get_permissions (setting));
set_val_str (arr, 9, nmc_property_connection_get_zone (setting));
set_val_str (arr, 10, nmc_property_connection_get_master (setting));
set_val_str (arr, 11, nmc_property_connection_get_slave_type (setting));
set_val_str (arr, 12, nmc_property_connection_get_secondaries (setting));
set_val_str (arr, 13, nmc_property_connection_get_gateway_ping_timeout (setting));
set_val_str (arr, 6, nmc_property_connection_get_autoconnect_priority (setting));
set_val_str (arr, 7, nmc_property_connection_get_timestamp (setting));
set_val_str (arr, 8, nmc_property_connection_get_read_only (setting));
set_val_str (arr, 9, nmc_property_connection_get_permissions (setting));
set_val_str (arr, 10, nmc_property_connection_get_zone (setting));
set_val_str (arr, 11, nmc_property_connection_get_master (setting));
set_val_str (arr, 12, nmc_property_connection_get_slave_type (setting));
set_val_str (arr, 13, nmc_property_connection_get_secondaries (setting));
set_val_str (arr, 14, nmc_property_connection_get_gateway_ping_timeout (setting));
g_ptr_array_add (nmc->output_data, arr);
print_data (nmc); /* Print all data */

View file

@ -871,9 +871,8 @@ nmtst_assert_connection_verifies_without_normalization (NMConnection *con)
success = nm_connection_normalize (con, NULL, &was_modified, &error);
g_assert_no_error (error);
g_assert (success);
g_assert (!was_modified);
nmtst_assert_connection_equals (con, FALSE, clone, FALSE);
g_assert (!was_modified);
}
inline static void

View file

@ -80,6 +80,7 @@ typedef struct {
char *slave_type;
GSList *permissions; /* list of Permission structs */
gboolean autoconnect;
gint autoconnect_priority;
guint64 timestamp;
gboolean read_only;
char *zone;
@ -95,6 +96,7 @@ enum {
PROP_TYPE,
PROP_PERMISSIONS,
PROP_AUTOCONNECT,
PROP_AUTOCONNECT_PRIORITY,
PROP_TIMESTAMP,
PROP_READ_ONLY,
PROP_ZONE,
@ -497,6 +499,23 @@ nm_setting_connection_get_autoconnect (NMSettingConnection *setting)
return NM_SETTING_CONNECTION_GET_PRIVATE (setting)->autoconnect;
}
/**
* nm_setting_connection_get_autoconnect_priority:
* @setting: the #NMSettingConnection
*
* Returns the #NMSettingConnection:autoconnect-priority property of the connection.
* The higher number, the higher priority.
*
* Returns: the connection's autoconnect priority
**/
gint
nm_setting_connection_get_autoconnect_priority (NMSettingConnection *setting)
{
g_return_val_if_fail (NM_IS_SETTING_CONNECTION (setting), 0);
return NM_SETTING_CONNECTION_GET_PRIVATE (setting)->autoconnect_priority;
}
/**
* nm_setting_connection_get_timestamp:
* @setting: the #NMSettingConnection
@ -1094,6 +1113,9 @@ set_property (GObject *object, guint prop_id,
case PROP_AUTOCONNECT:
priv->autoconnect = g_value_get_boolean (value);
break;
case PROP_AUTOCONNECT_PRIORITY:
priv->autoconnect_priority = g_value_get_int (value);
break;
case PROP_TIMESTAMP:
priv->timestamp = g_value_get_uint64 (value);
break;
@ -1165,6 +1187,9 @@ get_property (GObject *object, guint prop_id,
case PROP_AUTOCONNECT:
g_value_set_boolean (value, nm_setting_connection_get_autoconnect (setting));
break;
case PROP_AUTOCONNECT_PRIORITY:
g_value_set_int (value, nm_setting_connection_get_autoconnect_priority (setting));
break;
case PROP_TIMESTAMP:
g_value_set_uint64 (value, nm_setting_connection_get_timestamp (setting));
break;
@ -1331,6 +1356,24 @@ nm_setting_connection_class_init (NMSettingConnectionClass *setting_class)
NM_SETTING_PARAM_FUZZY_IGNORE |
G_PARAM_STATIC_STRINGS));
/**
* NMSettingConnection:autoconnect-priority:
*
* The autoconnect priority. If the connection is set to autoconnect,
* connections with higher priority will be preferred. Defaults to 0.
* The higher number means higher priority.
**/
g_object_class_install_property
(object_class, PROP_AUTOCONNECT_PRIORITY,
g_param_spec_int (NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY, "", "",
NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_MIN,
NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_MAX,
NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_DEFAULT,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
NM_SETTING_PARAM_FUZZY_IGNORE |
G_PARAM_STATIC_STRINGS));
/**
* NMSettingConnection:timestamp:
*

View file

@ -72,11 +72,16 @@ typedef enum
#define NM_SETTING_CONNECTION_ERROR nm_setting_connection_error_quark ()
GQuark nm_setting_connection_error_quark (void);
#define NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_MIN -999
#define NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_MAX 999
#define NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_DEFAULT 0
#define NM_SETTING_CONNECTION_ID "id"
#define NM_SETTING_CONNECTION_UUID "uuid"
#define NM_SETTING_CONNECTION_INTERFACE_NAME "interface-name"
#define NM_SETTING_CONNECTION_TYPE "type"
#define NM_SETTING_CONNECTION_AUTOCONNECT "autoconnect"
#define NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY "autoconnect-priority"
#define NM_SETTING_CONNECTION_TIMESTAMP "timestamp"
#define NM_SETTING_CONNECTION_READ_ONLY "read-only"
#define NM_SETTING_CONNECTION_PERMISSIONS "permissions"
@ -111,6 +116,7 @@ const char *nm_setting_connection_get_uuid (NMSettingConnection *set
const char *nm_setting_connection_get_interface_name (NMSettingConnection *setting);
const char *nm_setting_connection_get_connection_type (NMSettingConnection *setting);
gboolean nm_setting_connection_get_autoconnect (NMSettingConnection *setting);
gint nm_setting_connection_get_autoconnect_priority (NMSettingConnection *setting);
guint64 nm_setting_connection_get_timestamp (NMSettingConnection *setting);
gboolean nm_setting_connection_get_read_only (NMSettingConnection *setting);

View file

@ -552,7 +552,7 @@ _nm_utils_copy_slist_to_array (const GSList *list,
array = g_ptr_array_new_with_free_func (unref_func);
for (iter = list; iter; iter = iter->next)
g_ptr_array_add (array, copy_func (iter->data));
g_ptr_array_add (array, copy_func ? copy_func (iter->data) : iter->data);
return array;
}

View file

@ -1599,6 +1599,7 @@ test_connection_diff_a_only (void)
{ NM_SETTING_CONNECTION_TYPE, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_CONNECTION_TIMESTAMP, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_CONNECTION_AUTOCONNECT, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_CONNECTION_READ_ONLY, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_CONNECTION_PERMISSIONS, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_CONNECTION_ZONE, NM_SETTING_DIFF_RESULT_IN_A },

View file

@ -530,6 +530,7 @@ global:
nm_setting_connection_error_get_type;
nm_setting_connection_error_quark;
nm_setting_connection_get_autoconnect;
nm_setting_connection_get_autoconnect_priority;
nm_setting_connection_get_connection_type;
nm_setting_connection_get_gateway_ping_timeout;
nm_setting_connection_get_id;

View file

@ -1634,6 +1634,31 @@ nm_utils_match_connection (GSList *connections,
return best_match;
}
int
nm_utils_cmp_connection_by_autoconnect_priority (NMConnection **a, NMConnection **b)
{
NMSettingConnection *a_s_con, *b_s_con;
gboolean a_ac, b_ac;
gint a_ap, b_ap;
a_s_con = nm_connection_get_setting_connection (*a);
b_s_con = nm_connection_get_setting_connection (*b);
a_ac = !!nm_setting_connection_get_autoconnect (a_s_con);
b_ac = !!nm_setting_connection_get_autoconnect (b_s_con);
if (a_ac != b_ac)
return ((int) b_ac) - ((int) a_ac);
if (!a_ac)
return 0;
a_ap = nm_setting_connection_get_autoconnect_priority (a_s_con);
b_ap = nm_setting_connection_get_autoconnect_priority (b_s_con);
if (a_ap != b_ap)
return (a_ap > b_ap) ? -1 : 1;
return 0;
}
/* nm_utils_ascii_str_to_int64:
*
* A wrapper for g_ascii_strtoll, that checks whether the whole string

View file

@ -138,6 +138,8 @@ NMConnection *nm_utils_match_connection (GSList *connections,
NMUtilsMatchFilterFunc match_filter_func,
gpointer match_filter_data);
int nm_utils_cmp_connection_by_autoconnect_priority (NMConnection **a, NMConnection **b);
gint64 nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback);
#define NM_UTILS_NS_PER_SECOND ((gint64) 1000000000)

View file

@ -1640,6 +1640,34 @@ can_auto_connect (NMDevice *self,
return nm_device_connection_is_available (self, connection, FALSE);
}
/**
* nm_device_can_auto_connect:
* @self: an #NMDevice
* @connection: a #NMConnection
* @specific_object: (out) (transfer full): on output, the path of an
* object associated with the returned connection, to be passed to
* nm_manager_activate_connection(), or %NULL.
*
* Checks if @connection can be auto-activated on @self right now.
* This requires, at a minimum, that the connection be compatible with
* @self, and that it have the #NMSettingConnection:autoconnect property
* set. Some devices impose additional requirements. (Eg, a Wi-Fi connection
* can only be activated if its SSID was seen in the last scan.)
*
* Returns: %TRUE, if the @connection can be auto-activated.
**/
gboolean
nm_device_can_auto_connect (NMDevice *self,
NMConnection *connection,
char **specific_object)
{
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
g_return_val_if_fail (specific_object && !*specific_object, FALSE);
return NM_DEVICE_GET_CLASS (self)->can_auto_connect (self, connection, specific_object);
}
static gboolean
device_has_config (NMDevice *self)
{
@ -1796,46 +1824,6 @@ nm_device_generate_connection (NMDevice *self, NMDevice *master)
return connection;
}
/**
* nm_device_get_best_auto_connection:
* @self: an #NMDevice
* @connections: (element-type #NMConnection): a list of connections
* @specific_object: (out) (transfer full): on output, the path of an
* object associated with the returned connection, to be passed to
* nm_manager_activate_connection(), or %NULL.
*
* Looks through @connections to see if there is a connection that can
* be auto-activated on @self right now. This requires, at a minimum,
* that the connection be compatible with @self, and that it have the
* #NMSettingConnection:autoconnect property set. Some devices impose
* additional requirements. (Eg, a Wi-Fi connection can only be
* activated if its SSID was seen in the last scan.)
*
* Returns: an auto-activatable #NMConnection, or %NULL if none are
* available.
*/
NMConnection *
nm_device_get_best_auto_connection (NMDevice *self,
GSList *connections,
char **specific_object)
{
GSList *iter;
g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
g_return_val_if_fail (specific_object != NULL, NULL);
g_return_val_if_fail (*specific_object == NULL, NULL);
for (iter = connections; iter; iter = iter->next) {
NMConnection *connection = NM_CONNECTION (iter->data);
if (NM_DEVICE_GET_CLASS (self)->can_auto_connect (self, connection, specific_object))
return connection;
}
return NULL;
}
gboolean
nm_device_complete_connection (NMDevice *self,
NMConnection *connection,

View file

@ -269,9 +269,9 @@ gboolean nm_device_master_update_slave_connection (NMDevice *master,
NMConnection *connection,
GError **error);
NMConnection * nm_device_get_best_auto_connection (NMDevice *dev,
GSList *connections,
char **specific_object);
gboolean nm_device_can_auto_connect (NMDevice *self,
NMConnection *connection,
char **specific_object);
gboolean nm_device_complete_connection (NMDevice *device,
NMConnection *connection,

View file

@ -42,6 +42,7 @@
#include "nm-firewall-manager.h"
#include "nm-dispatcher.h"
#include "nm-utils.h"
#include "nm-core-internal.h"
#include "nm-glib-compat.h"
#include "nm-manager.h"
#include "nm-settings.h"
@ -990,7 +991,9 @@ auto_activate_device (gpointer user_data)
NMPolicyPrivate *priv;
NMConnection *best_connection;
char *specific_object = NULL;
GSList *connections, *iter;
GPtrArray *connections;
GSList *connection_list;
guint i;
g_assert (data);
policy = data->policy;
@ -1005,20 +1008,31 @@ auto_activate_device (gpointer user_data)
if (nm_device_get_act_request (data->device))
goto out;
iter = connections = nm_manager_get_activatable_connections (priv->manager);
connection_list = nm_manager_get_activatable_connections (priv->manager);
if (!connection_list)
goto out;
/* Remove connections that shouldn't be auto-activated */
while (iter) {
NMSettingsConnection *candidate = NM_SETTINGS_CONNECTION (iter->data);
connections = _nm_utils_copy_slist_to_array (connection_list, NULL, NULL);
g_slist_free (connection_list);
/* Grab next item before we possibly delete the current item */
iter = g_slist_next (iter);
/* sort is stable (which is important at this point) so that connections
* with same priority are still sorted by last-connected-timestamp. */
g_ptr_array_sort (connections, (GCompareFunc) nm_utils_cmp_connection_by_autoconnect_priority);
/* Find the first connection that should be auto-activated */
best_connection = NULL;
for (i = 0; i < connections->len; i++) {
NMSettingsConnection *candidate = NM_SETTINGS_CONNECTION (connections->pdata[i]);
if (!nm_settings_connection_can_autoconnect (candidate))
connections = g_slist_remove (connections, candidate);
continue;
if (nm_device_can_auto_connect (data->device, (NMConnection *) candidate, &specific_object)) {
best_connection = (NMConnection *) candidate;
break;
}
}
g_ptr_array_free (connections, TRUE);
best_connection = nm_device_get_best_auto_connection (data->device, connections, &specific_object);
if (best_connection) {
GError *error = NULL;
NMAuthSubject *subject;
@ -1041,8 +1055,6 @@ auto_activate_device (gpointer user_data)
g_object_unref (subject);
}
g_slist_free (connections);
out:
activate_data_free (data);
return G_SOURCE_REMOVE;

View file

@ -326,17 +326,17 @@ connection_sort (gconstpointer pa, gconstpointer pb)
NMConnection *b = NM_CONNECTION (pb);
NMSettingConnection *con_b;
guint64 ts_a = 0, ts_b = 0;
gboolean can_ac_a, can_ac_b;
con_a = nm_connection_get_setting_connection (a);
g_assert (con_a);
con_b = nm_connection_get_setting_connection (b);
g_assert (con_b);
if (nm_setting_connection_get_autoconnect (con_a) != nm_setting_connection_get_autoconnect (con_b)) {
if (nm_setting_connection_get_autoconnect (con_a))
return -1;
return 1;
}
can_ac_a = !!nm_setting_connection_get_autoconnect (con_a);
can_ac_b = !!nm_setting_connection_get_autoconnect (con_b);
if (can_ac_a != can_ac_b)
return can_ac_a ? -1 : 1;
nm_settings_connection_get_timestamp (NM_SETTINGS_CONNECTION (pa), &ts_a);
nm_settings_connection_get_timestamp (NM_SETTINGS_CONNECTION (pb), &ts_b);

View file

@ -169,8 +169,14 @@ make_connection_setting (const char *file,
}
/* Missing ONBOOT is treated as "ONBOOT=true" by the old network service */
g_object_set (s_con, NM_SETTING_CONNECTION_AUTOCONNECT,
g_object_set (s_con,
NM_SETTING_CONNECTION_AUTOCONNECT,
svTrueValue (ifcfg, "ONBOOT", TRUE),
NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY,
(gint) svGetValueInt64 (ifcfg, "AUTOCONNECT_PRIORITY", 10,
NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_MIN,
NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_MAX,
NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_DEFAULT),
NULL);
value = svGetValue (ifcfg, "USERS", FALSE);

View file

@ -34,6 +34,11 @@
#include "shvar.h"
#include "NetworkManagerUtils.h"
#include "nm-logging.h"
#define PARSE_WARNING(msg...) nm_log_warn (LOGD_SETTINGS, " " msg)
/* Open the file <name>, returning a shvarFile on success and NULL on failure.
* Add a wrinkle to let the caller specify whether or not to create the file
* (actually, return a structure anyway) if it doesn't exist.
@ -306,6 +311,38 @@ svTrueValue (shvarFile *s, const char *key, gboolean def)
return returnValue;
}
/* svGetValueInt64:
* @s: fhe file
* @key: the name of the key to read
* @base: the numeric base (usually 10). Setting to 0 means "auto". Usually you want 10.
* @min: the minimum for range-check
* @max: the maximum for range-check
* @fallback: the fallback value in any error case
*
* Reads a value @key and converts it to an integer using nm_utils_ascii_str_to_int64().
* In case of error, @errno will be set and @fallback returned. */
gint64
svGetValueInt64 (shvarFile *s, const char *key, guint base, gint64 min, gint64 max, gint64 fallback)
{
char *tmp;
gint64 result;
int errsv;
tmp = svGetValue (s, key, FALSE);
if (!tmp) {
errno = 0;
return fallback;
}
result = nm_utils_ascii_str_to_int64 (tmp, base, min, max, fallback);
errsv = errno;
if (errsv != 0)
PARSE_WARNING ("Error reading '%s' value '%s' as integer (%d)", key, tmp, errsv);
g_free (tmp);
return result;
}
/* Set the variable <key> equal to the value <value>.
* If <key> does not exist, and the <current> pointer is set, append

View file

@ -63,6 +63,8 @@ char *svGetValue (shvarFile *s, const char *key, gboolean verbatim);
*/
gboolean svTrueValue (shvarFile *s, const char *key, gboolean def);
gint64 svGetValueInt64 (shvarFile *s, const char *key, guint base, gint64 min, gint64 max, gint64 fallback);
/* Set the variable <key> equal to the value <value>.
* If <key> does not exist, and the <current> pointer is set, append
* the key=value pair after that line. Otherwise, prepend the pair

View file

@ -3,6 +3,7 @@ DEVICE=eth2
HWADDR=00:16:41:11:22:33
NM_CONTROLLED=yes
BOOTPROTO=dhcp
AUTOCONNECT_PRIORITY=-1
ESSID=blahblah
CHANNEL=1
MODE=Managed

View file

@ -2910,6 +2910,8 @@ test_read_wifi_open (void)
NM_SETTING_CONNECTION_SETTING_NAME,
NM_SETTING_CONNECTION_AUTOCONNECT);
g_assert_cmpint (nm_setting_connection_get_autoconnect_priority (s_con), ==, -1);
/* ===== WIRELESS SETTING ===== */
s_wireless = nm_connection_get_setting_wireless (connection);

View file

@ -1664,6 +1664,7 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg)
GString *str;
const char *master;
char *tmp;
gint i_int;
svSetValue (ifcfg, "NAME", nm_setting_connection_get_id (s_con), FALSE);
svSetValue (ifcfg, "UUID", nm_setting_connection_get_uuid (s_con), FALSE);
@ -1672,6 +1673,12 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg)
nm_setting_connection_get_autoconnect (s_con) ? "yes" : "no",
FALSE);
i_int = nm_setting_connection_get_autoconnect_priority (s_con);
tmp = i_int != NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY_DEFAULT
? g_strdup_printf ("%d", i_int) : NULL;
svSetValue (ifcfg, "AUTOCONNECT_PRIORITY", tmp, FALSE);
g_free (tmp);
/* Permissions */
svSetValue (ifcfg, "USERS", NULL, FALSE);
n = nm_setting_connection_get_num_permissions (s_con);

View file

@ -581,6 +581,104 @@ test_connection_no_match_ip4_addr (void)
g_object_unref (copy);
}
static NMConnection *
_create_connection_autoconnect (const char *id, gboolean autoconnect, int autoconnect_priority)
{
NMConnection *c;
NMSettingConnection *s_con;
c = nmtst_create_minimal_connection (id, NULL, NM_SETTING_WIRED_SETTING_NAME, &s_con);
g_object_set (s_con,
NM_SETTING_CONNECTION_AUTOCONNECT, autoconnect,
NM_SETTING_CONNECTION_AUTOCONNECT_PRIORITY, autoconnect_priority,
NULL);
nmtst_connection_normalize (c);
return c;
}
static void
_test_connection_sort_autoconnect_priority_one (NMConnection **list, gboolean shuffle)
{
int i, j;
int count = 0;
gs_unref_ptrarray GPtrArray *connections = g_ptr_array_new ();
while (list[count])
count++;
g_assert (count > 1);
/* copy the list of connections over to @connections and shuffle. */
for (i = 0; i < count; i++)
g_ptr_array_add (connections, list[i]);
if (shuffle) {
for (i = count - 1; i > 0; i--) {
j = g_rand_int (nmtst_get_rand ()) % (i + 1);
NMTST_SWAP (connections->pdata[i], connections->pdata[j]);
}
}
/* sort it... */
g_ptr_array_sort (connections, (GCompareFunc) nm_utils_cmp_connection_by_autoconnect_priority);
for (i = 0; i < count; i++) {
if (list[i] == connections->pdata[i])
continue;
if (shuffle && nm_utils_cmp_connection_by_autoconnect_priority (&list[i], (NMConnection **) &connections->pdata[i]) == 0)
continue;
g_message ("After sorting, the order of connections is not as expected!! Offending index: %d", i);
for (j = 0; j < count; j++)
g_message (" %3d: %p/%-20s - %p/%-20s", j, list[j], nm_connection_get_id (list[j]), connections->pdata[j], nm_connection_get_id (connections->pdata[j]));
g_assert_not_reached ();
}
}
static void
_test_connection_sort_autoconnect_priority_free (NMConnection **list)
{
while (*list) {
g_object_unref (*list);
*list = NULL;
}
}
static void
test_connection_sort_autoconnect_priority (void)
{
NMConnection *c1[] = {
_create_connection_autoconnect ("AC/100", TRUE, 100),
_create_connection_autoconnect ("AC/100", TRUE, 100),
_create_connection_autoconnect ("AC/99", TRUE, 99),
_create_connection_autoconnect ("AC/0", TRUE, 0),
_create_connection_autoconnect ("AC/0", TRUE, 0),
_create_connection_autoconnect ("AC/-1", TRUE, -1),
_create_connection_autoconnect ("AC/-3", TRUE, -3),
_create_connection_autoconnect ("ac/0", FALSE, 0),
_create_connection_autoconnect ("ac/0", FALSE, 0),
_create_connection_autoconnect ("ac/1", FALSE, 1),
_create_connection_autoconnect ("ac/-1", FALSE, -1),
_create_connection_autoconnect ("ac/1", FALSE, 1),
_create_connection_autoconnect ("ac/0", FALSE, 0),
NULL,
};
NMConnection *c2[] = {
_create_connection_autoconnect ("AC/100", TRUE, 100),
_create_connection_autoconnect ("AC/99", TRUE, 99),
_create_connection_autoconnect ("AC/0", TRUE, 0),
_create_connection_autoconnect ("AC/-1", TRUE, -1),
_create_connection_autoconnect ("AC/-3", TRUE, -3),
_create_connection_autoconnect ("ac/0", FALSE, 0),
NULL,
};
_test_connection_sort_autoconnect_priority_one (c1, FALSE);
_test_connection_sort_autoconnect_priority_one (c2, FALSE);
_test_connection_sort_autoconnect_priority_one (c1, TRUE);
_test_connection_sort_autoconnect_priority_one (c2, TRUE);
_test_connection_sort_autoconnect_priority_free (c1);
_test_connection_sort_autoconnect_priority_free (c2);
}
/*******************************************/
NMTST_DEFINE ();
@ -602,6 +700,8 @@ main (int argc, char **argv)
g_test_add_func ("/general/connection-match/wired", test_connection_match_wired);
g_test_add_func ("/general/connection-match/no-match-ip4-addr", test_connection_no_match_ip4_addr);
g_test_add_func ("/general/connection-sort/autoconnect-priority", test_connection_sort_autoconnect_priority);
return g_test_run ();
}