merge branch 'bg/metered-connections-bgo741725'

Expose information about whether a connection is metered and use some
heuristics to choose a reasonable default when the value is not
configured.

https://bugzilla.gnome.org/show_bug.cgi?id=741725
https://bugzilla.redhat.com/show_bug.cgi?id=1200452

(cherry picked from commit 7d09debdf0)
This commit is contained in:
Beniamino Galvani 2015-07-22 13:53:38 +02:00
commit 586bb2799f
38 changed files with 674 additions and 12 deletions

View file

@ -521,6 +521,23 @@ nmc_device_state_to_string (NMDeviceState state)
}
}
const char *
nmc_device_metered_to_string (NMMetered value)
{
switch (value) {
case NM_METERED_YES:
return _("yes");
case NM_METERED_NO:
return _("no");
case NM_METERED_GUESS_YES:
return _("yes (guessed)");
case NM_METERED_GUESS_NO:
return _("no (guessed)");
default:
return _("unknown");
}
}
const char *
nmc_device_reason_to_string (NMDeviceStateReason reason)
{

View file

@ -35,6 +35,7 @@ NMIPRoute *nmc_parse_and_build_route (int family, const char *first, const char
const char * nmc_device_state_to_string (NMDeviceState state);
const char * nmc_device_reason_to_string (NMDeviceStateReason reason);
const char * nmc_device_metered_to_string (NMMetered value);
char **
nmc_vlan_parse_priority_maps (const char *priority_map,

View file

@ -78,11 +78,12 @@ static NmcOutputField nmc_fields_dev_show_general[] = {
{"CONNECTION", N_("CONNECTION"), 20}, /* 20 */
{"CON-UUID", N_("CON-UUID"), 38}, /* 21 */
{"CON-PATH", N_("CON-PATH"), 51}, /* 22 */
{"METERED", N_("METERED"), 10}, /* 23 */
{NULL, NULL, 0}
};
#define NMC_FIELDS_DEV_SHOW_GENERAL_ALL "NAME,DEVICE,TYPE,NM-TYPE,VENDOR,PRODUCT,DRIVER,DRIVER-VERSION,FIRMWARE-VERSION,HWADDR,MTU,"\
"STATE,REASON,UDI,IP-IFACE,IS-SOFTWARE,NM-MANAGED,AUTOCONNECT,FIRMWARE-MISSING,PHYS-PORT-ID,"\
"CONNECTION,CON-UUID,CON-PATH"
"CONNECTION,CON-UUID,CON-PATH,METERED"
#define NMC_FIELDS_DEV_SHOW_GENERAL_COMMON "NAME,DEVICE,TYPE,VENDOR,PRODUCT,DRIVER,HWADDR,STATE"
/* Available fields for 'device show' - CONNECTIONS part */
@ -858,6 +859,8 @@ show_device_info (NMDevice *device, NmCli *nmc)
set_val_strc (arr, 20, get_active_connection_id (device));
set_val_strc (arr, 21, acon ? nm_active_connection_get_uuid (acon) : NULL);
set_val_strc (arr, 22, acon ? nm_object_get_path (NM_OBJECT (acon)) : NULL);
set_val_strc (arr, 23, nmc_device_metered_to_string (nm_device_get_metered (device)));
g_ptr_array_add (nmc->output_data, arr);
print_data (nmc); /* Print all data */

View file

@ -60,6 +60,7 @@ NmcOutputField nmc_fields_setting_connection[] = {
SETTING_FIELD (NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES, 13), /* 13 */
SETTING_FIELD (NM_SETTING_CONNECTION_SECONDARIES, 40), /* 14 */
SETTING_FIELD (NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT, 30), /* 15 */
SETTING_FIELD (NM_SETTING_CONNECTION_METERED, 10), /* 16 */
{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
};
#define NMC_FIELDS_SETTING_CONNECTION_ALL "name"","\
@ -77,7 +78,8 @@ NmcOutputField nmc_fields_setting_connection[] = {
NM_SETTING_CONNECTION_SLAVE_TYPE","\
NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES","\
NM_SETTING_CONNECTION_SECONDARIES","\
NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT
NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT","\
NM_SETTING_CONNECTION_METERED
#define NMC_FIELDS_SETTING_CONNECTION_COMMON NMC_FIELDS_SETTING_CONNECTION_ALL
/* Available fields for NM_SETTING_WIRED_SETTING_NAME */
@ -2744,6 +2746,51 @@ nmc_property_connection_describe_secondaries (NMSetting *setting, const char *pr
"Example: private-openvpn, fe6ba5d8-c2fc-4aae-b2e3-97efddd8d9a7\n");
}
/* 'metered' */
static char *
nmc_property_connection_get_metered (NMSetting *setting, NmcPropertyGetType get_type)
{
NMSettingConnection *s_conn = NM_SETTING_CONNECTION (setting);
switch (nm_setting_connection_get_metered (s_conn)) {
case NM_METERED_YES:
return g_strdup (_("yes"));
case NM_METERED_NO:
return g_strdup (_("no"));
case NM_METERED_UNKNOWN:
default:
return g_strdup (_("unknown"));
}
}
static gboolean
nmc_property_connection_set_metered (NMSetting *setting, const char *prop,
const char *val, GError **error)
{
NMMetered metered;
NMCTriStateValue ts_val;
if (!nmc_string_to_tristate (val, &ts_val, error))
return FALSE;
switch (ts_val) {
case NMC_TRI_STATE_YES:
metered = NM_METERED_YES;
break;
case NMC_TRI_STATE_NO:
metered = NM_METERED_NO;
break;
case NMC_TRI_STATE_UNKNOWN:
metered = NM_METERED_UNKNOWN;
break;
default:
g_assert_not_reached();
}
g_object_set (setting, prop, metered, NULL);
return TRUE;
}
/* --- NM_SETTING_802_1X_SETTING_NAME property setter functions --- */
#define DEFINE_SETTER_STR_LIST(def_func, set_func) \
static gboolean \
@ -5324,6 +5371,13 @@ nmc_properties_init (void)
NULL,
NULL,
NULL);
nmc_add_prop_funcs (GLUE (CONNECTION, METERED),
nmc_property_connection_get_metered,
nmc_property_connection_set_metered,
NULL,
NULL,
NULL,
NULL);
/* Add editable properties for NM_SETTING_DCB_SETTING_NAME */
nmc_add_prop_funcs (GLUE (DCB, APP_FCOE_FLAGS),
@ -6684,6 +6738,7 @@ setting_connection_details (NMSetting *setting, NmCli *nmc, const char *one_pro
set_val_str (arr, 13, nmc_property_connection_get_autoconnect_slaves (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 14, nmc_property_connection_get_secondaries (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 15, nmc_property_connection_get_gateway_ping_timeout (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 16, nmc_property_connection_get_metered (setting, NMC_PROPERTY_GET_PRETTY));
g_ptr_array_add (nmc->output_data, arr);
print_data (nmc); /* Print all data */

View file

@ -407,7 +407,10 @@ nmc_string_to_bool (const char *str, gboolean *val_bool, GError **error)
if (g_strcmp0 (str, "o") == 0) {
g_set_error (error, 1, 0,
_("'%s' is ambiguous (on x off)"), str);
/* Translators: the first %s is the partial value entered by
* the user, the second %s a list of compatible values.
*/
_("'%s' is ambiguous (%s)"), str, "on x off");
return FALSE;
}
@ -424,6 +427,39 @@ nmc_string_to_bool (const char *str, gboolean *val_bool, GError **error)
return TRUE;
}
gboolean
nmc_string_to_tristate (const char *str, NMCTriStateValue *val, GError **error)
{
const char *s_true[] = { "true", "yes", "on", NULL };
const char *s_false[] = { "false", "no", "off", NULL };
const char *s_unknown[] = { "unknown", NULL };
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
if (g_strcmp0 (str, "o") == 0) {
g_set_error (error, 1, 0,
/* Translators: the first %s is the partial value entered by
* the user, the second %s a list of compatible values.
*/
_("'%s' is ambiguous (%s)"), str, "on x off");
return FALSE;
}
if (nmc_string_is_valid (str, s_true, NULL))
*val = NMC_TRI_STATE_YES;
else if (nmc_string_is_valid (str, s_false, NULL))
*val = NMC_TRI_STATE_NO;
else if (nmc_string_is_valid (str, s_unknown, NULL))
*val = NMC_TRI_STATE_UNKNOWN;
else {
g_set_error (error, 1, 0,
_("'%s' is not valid; use [%s], [%s] or [%s]"),
str, "true, yes, on", "false, no, off", "unknown");
return FALSE;
}
return TRUE;
}
/*
* Ask user for input and return the string.
* The caller is responsible for freeing the returned string.

View file

@ -32,6 +32,12 @@ typedef struct {
gboolean found;
} nmc_arg_t;
typedef enum {
NMC_TRI_STATE_NO,
NMC_TRI_STATE_YES,
NMC_TRI_STATE_UNKNOWN,
} NMCTriStateValue;
/* === Functions === */
int matches (const char *cmd, const char *pattern);
int next_arg (int *argc, char ***argv);
@ -62,6 +68,7 @@ gboolean nmc_string_to_uint (const char *str,
unsigned long int max,
unsigned long int *value);
gboolean nmc_string_to_bool (const char *str, gboolean *val_bool, GError **error);
gboolean nmc_string_to_tristate (const char *str, NMCTriStateValue *val, GError **error);
char *nmc_ip4_address_as_string (guint32 ip, GError **error);
char *nmc_ip6_address_as_string (const struct in6_addr *ip, GError **error);
void nmc_terminal_erase_line (void);

View file

@ -139,6 +139,12 @@
The device MTU (maximum transmission unit).
</tp:docstring>
</property>
<property name="Metered" type="u" access="read" tp:type="NM_METERED">
<tp:docstring>
Whether the amount of traffic flowing through the device is
subject to limitations, for example set by service providers.
</tp:docstring>
</property>
<method name="Disconnect">
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_device_disconnect"/>
@ -654,6 +660,34 @@
</tp:enumvalue>
</tp:enum>
<tp:enum name="NM_METERED" type="u">
<tp:enumvalue suffix="UNKNOWN" value="0">
<tp:docstring>
The device metered status is unknown.
</tp:docstring>
</tp:enumvalue>
<tp:enumvalue suffix="YES" value="1">
<tp:docstring>
The device is metered and the value was statically set.
</tp:docstring>
</tp:enumvalue>
<tp:enumvalue suffix="NO" value="2">
<tp:docstring>
The device is not metered and the value was statically set.
</tp:docstring>
</tp:enumvalue>
<tp:enumvalue suffix="GUESS_YES" value="3">
<tp:docstring>
The device is metered and the value was guessed.
</tp:docstring>
</tp:enumvalue>
<tp:enumvalue suffix="GUESS_NO" value="4">
<tp:docstring>
The device is not metered and the value was guessed.
</tp:docstring>
</tp:enumvalue>
</tp:enum>
<tp:struct name="NM_DEVICE_STATE_REASON_STRUCT">
<tp:member type="u" name="state" tp:type="NM_DEVICE_STATE">
<tp:docstring>

View file

@ -335,6 +335,14 @@
</tp:docstring>
</property>
<property name="Metered" type="u" access="read" tp:type="NM_METERED">
<tp:docstring>
Wheter the connectivity is metered. This is equivalent to the
metered property of the device associated with the primary
connection.
</tp:docstring>
</property>
<property name="ActivatingConnection" type="o" access="read">
<tp:docstring>
The object path of an active connection that is currently

View file

@ -403,7 +403,6 @@ typedef enum {
NM_DEVICE_STATE_FAILED = 120
} NMDeviceState;
/**
* NMDeviceStateReason:
* @NM_DEVICE_STATE_REASON_NONE: No reason given
@ -540,6 +539,26 @@ typedef enum {
NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED = 62,
} NMDeviceStateReason;
/**
* NMMetered:
* @NM_METERED_UNKNOWN: The metered status is unknown
* @NM_METERED_YES: Metered, the value was statically set
* @NM_METERED_NO: Not metered, the value was statically set
* @NM_METERED_GUESS_YES: Metered, the value was guessed
* @NM_METERED_GUESS_NO: Not metered, the value was guessed
*
* (Corresponds to the NM_METERED type in nm-device.xml.)
*
* Since: 1.0.6
**/
NM_AVAILABLE_IN_1_0_6
typedef enum {
NM_METERED_UNKNOWN = 0,
NM_METERED_YES = 1,
NM_METERED_NO = 2,
NM_METERED_GUESS_YES = 3,
NM_METERED_GUESS_NO = 4,
} NMMetered;
/**
* NMActiveConnectionState:

View file

@ -76,6 +76,7 @@ typedef struct {
char *zone;
GSList *secondaries; /* secondary connections to activate with the base connection */
guint gateway_ping_timeout;
NMMetered metered;
} NMSettingConnectionPrivate;
enum {
@ -95,6 +96,7 @@ enum {
PROP_AUTOCONNECT_SLAVES,
PROP_SECONDARIES,
PROP_GATEWAY_PING_TIMEOUT,
PROP_METERED,
LAST_PROP
};
@ -760,6 +762,23 @@ nm_setting_connection_get_gateway_ping_timeout (NMSettingConnection *setting)
return NM_SETTING_CONNECTION_GET_PRIVATE (setting)->gateway_ping_timeout;
}
/**
* nm_setting_connection_get_metered:
* @setting: the #NMSettingConnection
*
* Returns: the #NMSettingConnection:metered property of the setting.
*
* Since: 1.0.6
**/
NMMetered
nm_setting_connection_get_metered (NMSettingConnection *setting)
{
g_return_val_if_fail (NM_IS_SETTING_CONNECTION (setting),
NM_METERED_UNKNOWN);
return NM_SETTING_CONNECTION_GET_PRIVATE (setting)->metered;
}
static void
_set_error_missing_base_setting (GError **error, const char *type)
{
@ -921,6 +940,18 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
}
}
if (priv->metered != NM_METERED_UNKNOWN &&
priv->metered != NM_METERED_YES &&
priv->metered != NM_METERED_NO) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("metered value %d is not valid"), priv->metered);
g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME,
NM_SETTING_CONNECTION_METERED);
return FALSE;
}
/* *** errors above here should be always fatal, below NORMALIZABLE_ERROR *** */
if (!priv->uuid) {
@ -1154,6 +1185,9 @@ set_property (GObject *object, guint prop_id,
case PROP_GATEWAY_PING_TIMEOUT:
priv->gateway_ping_timeout = g_value_get_uint (value);
break;
case PROP_METERED:
priv->metered = g_value_get_enum (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -1227,6 +1261,9 @@ get_property (GObject *object, guint prop_id,
case PROP_GATEWAY_PING_TIMEOUT:
g_value_set_uint (value, priv->gateway_ping_timeout);
break;
case PROP_METERED:
g_value_set_enum (value, priv->metered);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -1626,4 +1663,27 @@ nm_setting_connection_class_init (NMSettingConnectionClass *setting_class)
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS));
/**
* NMSettingConnection:metered:
*
* Whether the connection is metered.
*
* Since: 1.0.6
**/
/* ---ifcfg-rh---
* property: metered
* variable: CONNECTION_METERED
* values: yes,no,unknown
* description: Whether the device is metered
* example: CONNECTION_METERED=yes
* ---end---
*/
g_object_class_install_property
(object_class, PROP_METERED,
g_param_spec_enum (NM_SETTING_CONNECTION_METERED, "", "",
NM_TYPE_METERED,
NM_METERED_UNKNOWN,
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
}

View file

@ -59,6 +59,7 @@ G_BEGIN_DECLS
#define NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES "autoconnect-slaves"
#define NM_SETTING_CONNECTION_SECONDARIES "secondaries"
#define NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT "gateway-ping-timeout"
#define NM_SETTING_CONNECTION_METERED "metered"
/* Types for property values */
/**
@ -142,6 +143,8 @@ void nm_setting_connection_remove_secondary (NMSettingConnection *set
gboolean nm_setting_connection_remove_secondary_by_value (NMSettingConnection *setting, const char *sec_uuid);
guint32 nm_setting_connection_get_gateway_ping_timeout (NMSettingConnection *setting);
NM_AVAILABLE_IN_1_0_6
NMMetered nm_setting_connection_get_metered (NMSettingConnection *setting);
G_END_DECLS

View file

@ -1969,6 +1969,7 @@ test_connection_diff_a_only (void)
{ NM_SETTING_CONNECTION_AUTOCONNECT_SLAVES, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_CONNECTION_SECONDARIES, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT, NM_SETTING_DIFF_RESULT_IN_A },
{ NM_SETTING_CONNECTION_METERED, NM_SETTING_DIFF_RESULT_IN_A },
{ NULL, NM_SETTING_DIFF_RESULT_UNKNOWN }
} },
{ NM_SETTING_WIRED_SETTING_NAME, {

View file

@ -851,3 +851,10 @@ global:
nm_setting_connection_get_autoconnect_slaves;
} libnm_1_0_0;
libnm_1_0_6 {
global:
nm_device_get_metered;
nm_metered_get_type;
nm_setting_connection_get_metered;
} libnm_1_0_4;

View file

@ -76,6 +76,7 @@ enum {
PROP_CONNECTIONS,
PROP_HOSTNAME,
PROP_CAN_MODIFY,
PROP_METERED,
LAST_PROP
};
@ -1871,6 +1872,7 @@ get_property (GObject *object, guint prop_id,
case PROP_PRIMARY_CONNECTION:
case PROP_ACTIVATING_CONNECTION:
case PROP_DEVICES:
case PROP_METERED:
g_object_get_property (G_OBJECT (NM_CLIENT_GET_PRIVATE (object)->manager),
pspec->name, value);
break;
@ -2143,6 +2145,20 @@ nm_client_class_init (NMClientClass *client_class)
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/**
* NMClient:metered:
*
* Whether the connectivity is metered.
*
* Since: 1.0.6
**/
g_object_class_install_property
(object_class, PROP_METERED,
g_param_spec_uint (NM_CLIENT_METERED, "", "",
0, G_MAXUINT32, NM_METERED_UNKNOWN,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/* signals */
/**

View file

@ -56,6 +56,7 @@ G_BEGIN_DECLS
#define NM_CLIENT_CONNECTIONS "connections"
#define NM_CLIENT_HOSTNAME "hostname"
#define NM_CLIENT_CAN_MODIFY "can-modify"
#define NM_CLIENT_METERED "metered"
#define NM_CLIENT_DEVICE_ADDED "device-added"
#define NM_CLIENT_DEVICE_REMOVED "device-removed"

View file

@ -81,6 +81,7 @@ typedef struct {
char *driver_version;
char *firmware_version;
char *type_description;
NMMetered metered;
NMDeviceCapabilities capabilities;
gboolean managed;
gboolean firmware_missing;
@ -130,6 +131,7 @@ enum {
PROP_AVAILABLE_CONNECTIONS,
PROP_PHYSICAL_PORT_ID,
PROP_MTU,
PROP_METERED,
LAST_PROP
};
@ -193,6 +195,7 @@ init_dbus (NMObject *object)
{ NM_DEVICE_AVAILABLE_CONNECTIONS, &priv->available_connections, NULL, NM_TYPE_REMOTE_CONNECTION },
{ NM_DEVICE_PHYSICAL_PORT_ID, &priv->physical_port_id },
{ NM_DEVICE_MTU, &priv->mtu },
{ NM_DEVICE_METERED, &priv->metered },
/* Properties that exist in D-Bus but that we don't track */
{ "ip4-address", NULL },
@ -449,6 +452,9 @@ get_property (GObject *object,
case PROP_MTU:
g_value_set_uint (value, nm_device_get_mtu (device));
break;
case PROP_METERED:
g_value_set_uint (value, nm_device_get_metered (device));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -793,6 +799,20 @@ nm_device_class_init (NMDeviceClass *device_class)
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/**
* NMDevice:metered:
*
* Whether the device is metered.
*
* Since: 1.0.6
**/
g_object_class_install_property
(object_class, PROP_METERED,
g_param_spec_uint (NM_DEVICE_METERED, "", "",
0, G_MAXUINT32, NM_METERED_UNKNOWN,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/* signals */
/**
@ -1883,6 +1903,24 @@ nm_device_get_mtu (NMDevice *device)
return NM_DEVICE_GET_PRIVATE (device)->mtu;
}
/**
* nm_device_get_metered:
* @device: a #NMDevice
*
* Gets the metered setting of a #NMDevice.
*
* Returns: the metered setting.
*
* Since: 1.0.6
**/
NMMetered
nm_device_get_metered (NMDevice *device)
{
g_return_val_if_fail (NM_IS_DEVICE (device), NM_METERED_UNKNOWN);
return NM_DEVICE_GET_PRIVATE (device)->metered;
}
/**
* nm_device_is_software:
* @device: a #NMDevice

View file

@ -60,6 +60,7 @@ G_BEGIN_DECLS
#define NM_DEVICE_PRODUCT "product"
#define NM_DEVICE_PHYSICAL_PORT_ID "physical-port-id"
#define NM_DEVICE_MTU "mtu"
#define NM_DEVICE_METERED "metered"
struct _NMDevice {
NMObject parent;
@ -119,6 +120,8 @@ gboolean nm_device_is_software (NMDevice *device);
const char * nm_device_get_product (NMDevice *device);
const char * nm_device_get_vendor (NMDevice *device);
const char * nm_device_get_description (NMDevice *device);
NM_AVAILABLE_IN_1_0_6
NMMetered nm_device_get_metered (NMDevice *device);
char ** nm_device_disambiguate_names (NMDevice **devices,
int num_devices);

View file

@ -64,6 +64,7 @@ typedef struct {
NMConnectivityState connectivity;
NMActiveConnection *primary_connection;
NMActiveConnection *activating_connection;
NMMetered metered;
GCancellable *perm_call_cancellable;
GHashTable *permissions;
@ -102,6 +103,7 @@ enum {
PROP_PRIMARY_CONNECTION,
PROP_ACTIVATING_CONNECTION,
PROP_DEVICES,
PROP_METERED,
LAST_PROP
};
@ -179,6 +181,7 @@ init_dbus (NMObject *object)
{ NM_MANAGER_PRIMARY_CONNECTION, &priv->primary_connection, NULL, NM_TYPE_ACTIVE_CONNECTION },
{ NM_MANAGER_ACTIVATING_CONNECTION, &priv->activating_connection, NULL, NM_TYPE_ACTIVE_CONNECTION },
{ NM_MANAGER_DEVICES, &priv->devices, NULL, NM_TYPE_DEVICE, "device" },
{ NM_MANAGER_METERED, &priv->metered },
{ NULL },
};
@ -1537,6 +1540,9 @@ get_property (GObject *object,
case PROP_DEVICES:
g_value_take_boxed (value, _nm_utils_copy_object_array (nm_manager_get_devices (self)));
break;
case PROP_METERED:
g_value_set_uint (value, priv->metered);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -1669,6 +1675,19 @@ nm_manager_class_init (NMManagerClass *manager_class)
G_TYPE_PTR_ARRAY,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/**
* NMManager:metered:
*
* Whether the connectivity is metered.
*
* Since: 1.0.6
**/
g_object_class_install_property
(object_class, PROP_METERED,
g_param_spec_uint (NM_MANAGER_METERED, "", "",
0, G_MAXUINT32, NM_METERED_UNKNOWN,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/* signals */

View file

@ -50,6 +50,7 @@ G_BEGIN_DECLS
#define NM_MANAGER_PRIMARY_CONNECTION "primary-connection"
#define NM_MANAGER_ACTIVATING_CONNECTION "activating-connection"
#define NM_MANAGER_DEVICES "devices"
#define NM_MANAGER_METERED "metered"
typedef struct {
NMObject parent;

View file

@ -75,6 +75,7 @@ _LOG_DECLARE_SELF (NMDevice);
static void impl_device_disconnect (NMDevice *self, DBusGMethodInvocation *context);
static void impl_device_delete (NMDevice *self, DBusGMethodInvocation *context);
static void ip_check_ping_watch_cb (GPid pid, gint status, gpointer user_data);
static void nm_device_update_metered (NMDevice *self);
#include "nm-device-glue.h"
@ -128,6 +129,7 @@ enum {
PROP_MASTER,
PROP_HW_ADDRESS,
PROP_HAS_PENDING_ACTION,
PROP_METERED,
LAST_PROP
};
@ -338,6 +340,8 @@ typedef struct {
gboolean is_master;
GSList * slaves; /* list of SlaveInfo */
NMMetered metered;
NMConnectionProvider *con_provider;
} NMDevicePrivate;
@ -687,6 +691,21 @@ nm_device_get_device_type (NMDevice *self)
return NM_DEVICE_GET_PRIVATE (self)->type;
}
/**
* nm_device_get_metered:
* @setting: the #NMDevice
*
* Returns: the #NMDevice:metered property of the device.
*
* Since: 1.0.6
**/
NMMetered
nm_device_get_metered (NMDevice *self)
{
g_return_val_if_fail (NM_IS_DEVICE (self), NM_METERED_UNKNOWN);
return NM_DEVICE_GET_PRIVATE (self)->metered;
}
/**
* nm_device_get_priority():
@ -3450,8 +3469,10 @@ dhcp4_state_changed (NMDhcpClient *client,
if (priv->ip4_state == IP_CONF)
nm_device_activate_schedule_ip4_config_result (self, ip4_config);
else if (priv->ip4_state == IP_DONE)
else if (priv->ip4_state == IP_DONE) {
dhcp4_lease_change (self, ip4_config);
nm_device_update_metered (self);
}
break;
case NM_DHCP_STATE_TIMEOUT:
dhcp4_fail (self, TRUE);
@ -7497,6 +7518,59 @@ nm_device_set_dhcp_anycast_address (NMDevice *self, const char *addr)
priv->dhcp_anycast_address = g_strdup (addr);
}
static void
nm_device_update_metered (NMDevice *self)
{
#define NM_METERED_INVALID ((NMMetered) -1)
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMSettingConnection *setting;
NMMetered conn_value, value = NM_METERED_INVALID;
NMConnection *connection = NULL;
NMDeviceState state;
g_return_if_fail (NM_IS_DEVICE (self));
state = nm_device_get_state (self);
if ( state <= NM_DEVICE_STATE_DISCONNECTED
|| state > NM_DEVICE_STATE_ACTIVATED)
value = NM_METERED_UNKNOWN;
if (value == NM_METERED_INVALID) {
connection = nm_device_get_connection (self);
if (connection) {
setting = nm_connection_get_setting_connection (connection);
if (setting) {
conn_value = nm_setting_connection_get_metered (setting);
if (conn_value != NM_METERED_UNKNOWN)
value = conn_value;
}
}
}
/* Try to guess a value using the metered flag in IP configuration */
if (value == NM_METERED_INVALID) {
if ( priv->ip4_config
&& priv->ip4_state == IP_DONE
&& nm_ip4_config_get_metered (priv->ip4_config))
value = NM_METERED_GUESS_YES;
}
/* Otherwise look at connection type */
if (value == NM_METERED_INVALID) {
if ( nm_connection_is_type (connection, NM_SETTING_GSM_SETTING_NAME)
|| nm_connection_is_type (connection, NM_SETTING_CDMA_SETTING_NAME))
value = NM_METERED_GUESS_YES;
else
value = NM_METERED_GUESS_NO;
}
if (value != priv->metered) {
_LOGD (LOGD_DEVICE, "set metered value %d", value);
priv->metered = value;
g_object_notify (G_OBJECT (self), NM_DEVICE_METERED);
}
}
/**
* nm_device_check_connection_available():
* @self: the #NMDevice
@ -7954,6 +8028,7 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType clean
nm_platform_address_flush (NM_PLATFORM_GET, ifindex);
}
nm_device_update_metered (self);
_cleanup_generic_post (self, cleanup_type);
}
@ -8426,6 +8501,7 @@ _set_state_full (NMDevice *self,
break;
case NM_DEVICE_STATE_ACTIVATED:
_LOGI (LOGD_DEVICE, "Activation: successful, device activated.");
nm_device_update_metered (self);
nm_dispatcher_call (DISPATCHER_ACTION_UP, nm_act_request_get_connection (req), self, NULL, NULL, NULL);
break;
case NM_DEVICE_STATE_FAILED:
@ -9298,6 +9374,9 @@ get_property (GObject *object, guint prop_id,
case PROP_HAS_PENDING_ACTION:
g_value_set_boolean (value, nm_device_has_pending_action (self));
break;
case PROP_METERED:
g_value_set_uint (value, priv->metered);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -9561,6 +9640,20 @@ nm_device_class_init (NMDeviceClass *klass)
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/**
* NMDevice:metered:
*
* Whether the connection is metered.
*
* Since: 1.0.6
**/
g_object_class_install_property
(object_class, PROP_METERED,
g_param_spec_uint (NM_DEVICE_METERED, "", "",
0, G_MAXUINT32, NM_METERED_UNKNOWN,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/* Signals */
signals[STATE_CHANGED] =
g_signal_new ("state-changed",

View file

@ -58,6 +58,7 @@
#define NM_DEVICE_PHYSICAL_PORT_ID "physical-port-id"
#define NM_DEVICE_MTU "mtu"
#define NM_DEVICE_HW_ADDRESS "hw-address"
#define NM_DEVICE_METERED "metered"
#define NM_DEVICE_TYPE_DESC "type-desc" /* Internal only */
#define NM_DEVICE_RFKILL_TYPE "rfkill-type" /* Internal only */
@ -74,7 +75,6 @@
#define NM_DEVICE_RECHECK_AUTO_ACTIVATE "recheck-auto-activate"
#define NM_DEVICE_RECHECK_ASSUME "recheck-assume"
G_BEGIN_DECLS
#define NM_TYPE_DEVICE (nm_device_get_type ())
@ -281,6 +281,7 @@ const char * nm_device_get_driver_version (NMDevice *dev);
const char * nm_device_get_type_desc (NMDevice *dev);
const char * nm_device_get_type_description (NMDevice *dev);
NMDeviceType nm_device_get_device_type (NMDevice *dev);
NMMetered nm_device_get_metered (NMDevice *dev);
int nm_device_get_priority (NMDevice *dev);
guint32 nm_device_get_ip4_route_metric (NMDevice *dev);

View file

@ -224,6 +224,8 @@ lease_to_ip4_config (sd_dhcp_lease *lease,
guint16 mtu;
int r, num;
guint64 end_time;
uint8_t *data;
gboolean metered = FALSE;
g_return_val_if_fail (lease != NULL, NULL);
@ -355,6 +357,11 @@ lease_to_ip4_config (sd_dhcp_lease *lease,
g_string_free (l, TRUE);
}
num = sd_dhcp_lease_get_vendor_specific (lease, &data);
if (num > 0)
metered = !!memmem (data, num, "ANDROID_METERED", STRLEN ("ANDROID_METERED"));
nm_ip4_config_set_metered (ip4_config, metered);
return ip4_config;
}

View file

@ -575,6 +575,9 @@ nm_dhcp_utils_ip4_config_from_options (const char *iface,
g_strfreev (nis);
}
str = g_hash_table_lookup (options, "vendor_encapsulated_options");
nm_ip4_config_set_metered (ip4_config, str && strstr (str, "ANDROID_METERED"));
return ip4_config;
error:

View file

@ -72,6 +72,8 @@ struct sd_dhcp_lease {
char *root_path;
uint8_t *client_id;
size_t client_id_len;
uint8_t *vendor_specific;
size_t vendor_specific_size;
};
int dhcp_lease_new(sd_dhcp_lease **ret);

View file

@ -125,6 +125,7 @@ enum {
DHCP_OPTION_BROADCAST = 28,
DHCP_OPTION_STATIC_ROUTE = 33,
DHCP_OPTION_NTP_SERVER = 42,
DHCP_OPTION_VENDOR_SPECIFIC = 43,
DHCP_OPTION_REQUESTED_IP_ADDRESS = 50,
DHCP_OPTION_IP_ADDRESS_LEASE_TIME = 51,
DHCP_OPTION_OVERLOAD = 52,

View file

@ -191,6 +191,19 @@ int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routes
return 0;
}
int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, uint8_t **data) {
assert_return(lease, -EINVAL);
assert_return(data, -EINVAL);
if (lease->vendor_specific) {
*data = lease->vendor_specific;
return lease->vendor_specific_size;
} else
return -ENOENT;
return 0;
}
sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease) {
if (lease)
assert_se(REFCNT_INC(lease->n_ref) >= 2);
@ -286,6 +299,24 @@ static int lease_parse_string(const uint8_t *option, size_t len, char **ret) {
return 0;
}
static int lease_parse_binary(const uint8_t *option, size_t len, uint8_t **ret) {
assert (option);
assert (ret);
if (len >= 1) {
uint8_t *data;
data = memdup(option, len);
if (!data)
return -errno;
free(*ret);
*ret = data;
}
return 0;
}
static int lease_parse_in_addrs_aux(const uint8_t *option, size_t len, struct in_addr **ret, size_t *ret_size, size_t mult) {
assert(option);
assert(ret);
@ -568,6 +599,14 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const uint8_t *option,
return r;
break;
case DHCP_OPTION_VENDOR_SPECIFIC:
r = lease_parse_binary(option, len, &lease->vendor_specific);
if (r < 0)
return r;
lease->vendor_specific_size = len;
break;
}
return 0;
@ -595,6 +634,7 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
const uint8_t *client_id;
size_t client_id_len;
const char *string;
uint8_t *data;
uint16_t mtu;
struct sd_dhcp_route *routes;
int r;
@ -667,6 +707,18 @@ int sd_dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
if (r >= 0)
serialize_dhcp_routes(f, "ROUTES", routes, r);
r = sd_dhcp_lease_get_vendor_specific(lease, &data);
if (r >= 0) {
_cleanup_free_ char *option_hex = NULL;
option_hex = hexmem(data, r);
if (!option_hex) {
r = -ENOMEM;
goto finish;
}
fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex);
}
r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len);
if (r >= 0) {
_cleanup_free_ char *client_id_hex = NULL;

View file

@ -45,6 +45,7 @@ int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname);
int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname);
int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path);
int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routesgn);
int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, uint8_t **data);
int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const uint8_t **client_id,
size_t *client_id_len);

View file

@ -175,6 +175,30 @@ test_wins_options (void)
g_hash_table_destroy (options);
}
static void
test_vendor_option_metered (void)
{
GHashTable *options;
NMIP4Config *ip4_config;
static const Option data[] = {
{ "vendor_encapsulated_options", "ANDROID_METERED" },
{ NULL, NULL }
};
options = fill_table (generic_options, NULL);
ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0);
g_assert (ip4_config);
g_assert (nm_ip4_config_get_metered (ip4_config) == FALSE);
g_hash_table_destroy (options);
options = fill_table (generic_options, NULL);
options = fill_table (data, options);
ip4_config = nm_dhcp_utils_ip4_config_from_options ("eth0", options, 0);
g_assert (ip4_config);
g_assert (nm_ip4_config_get_metered (ip4_config) == TRUE);
g_hash_table_destroy (options);
}
static void
ip4_test_route (NMIP4Config *ip4_config,
guint route_num,
@ -716,6 +740,7 @@ int main (int argc, char **argv)
g_test_add_func ("/dhcp/ip4-missing-prefix-8", test_ip4_missing_prefix_8);
g_test_add_func ("/dhcp/ip4-prefix-classless", test_ip4_prefix_classless);
g_test_add_func ("/dhcp/client-id-from-string", test_client_id_from_string);
g_test_add_func ("/dhcp/vendor-option-metered", test_vendor_option_metered);
return g_test_run ();
}

View file

@ -100,6 +100,7 @@ enum {
enum {
DEVICE_CHANGED,
DEVICE_METERED_CHANGED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
@ -401,6 +402,18 @@ device_master_changed (GObject *object,
}
}
static void
device_metered_changed (GObject *object,
GParamSpec *pspec,
gpointer user_data)
{
NMActiveConnection *self = (NMActiveConnection *) user_data;
NMDevice *device = NM_DEVICE (object);
g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self));
g_signal_emit (self, signals[DEVICE_METERED_CHANGED], 0, nm_device_get_metered (device));
}
gboolean
nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device)
{
@ -427,6 +440,8 @@ nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device)
G_CALLBACK (device_state_changed), self);
g_signal_connect (device, "notify::master",
G_CALLBACK (device_master_changed), self);
g_signal_connect (device, "notify::" NM_DEVICE_METERED,
G_CALLBACK (device_metered_changed), self);
if (!priv->assumed) {
priv->pending_activation_id = g_strdup_printf ("activation::%p", (void *)self);
@ -838,6 +853,7 @@ _device_cleanup (NMActiveConnection *self)
if (priv->device) {
g_signal_handlers_disconnect_by_func (priv->device, G_CALLBACK (device_state_changed), self);
g_signal_handlers_disconnect_by_func (priv->device, G_CALLBACK (device_master_changed), self);
g_signal_handlers_disconnect_by_func (priv->device, G_CALLBACK (device_metered_changed), self);
}
if (priv->pending_activation_id) {
@ -1043,6 +1059,14 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class)
NULL, NULL, NULL,
G_TYPE_NONE, 2, NM_TYPE_DEVICE, NM_TYPE_DEVICE);
signals[DEVICE_METERED_CHANGED] =
g_signal_new (NM_ACTIVE_CONNECTION_DEVICE_METERED_CHANGED,
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (NMActiveConnectionClass, device_metered_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_UINT);
nm_dbus_manager_register_exported_type (nm_dbus_manager_get (),
G_TYPE_FROM_CLASS (ac_class),
&dbus_glib_nm_active_connection_object_info);

View file

@ -57,7 +57,8 @@
#define NM_ACTIVE_CONNECTION_INT_MASTER_READY "int-master-ready"
/* Internal signals*/
#define NM_ACTIVE_CONNECTION_DEVICE_CHANGED "device-changed"
#define NM_ACTIVE_CONNECTION_DEVICE_CHANGED "device-changed"
#define NM_ACTIVE_CONNECTION_DEVICE_METERED_CHANGED "device-metered-changed"
struct _NMActiveConnection {
GObject parent;
@ -78,6 +79,9 @@ typedef struct {
void (*device_changed) (NMActiveConnection *connection,
NMDevice *new_device,
NMDevice *old_device);
void (*device_metered_changed) (NMActiveConnection *connection,
NMMetered new_value);
} NMActiveConnectionClass;
GType nm_active_connection_get_type (void);

View file

@ -56,6 +56,7 @@ typedef struct {
GArray *wins;
guint32 mtu;
NMIPConfigSource mtu_source;
gboolean metered;
} NMIP4ConfigPrivate;
/* internal guint32 are assigned to gobject properties of type uint. Ensure, that uint is large enough */
@ -574,6 +575,10 @@ nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src)
for (i = 0; i < nm_ip4_config_get_num_wins (src); i++)
nm_ip4_config_add_wins (dst, nm_ip4_config_get_wins (src, i));
/* metered flag */
nm_ip4_config_set_metered (dst, nm_ip4_config_get_metered (dst) ||
nm_ip4_config_get_metered (src));
g_object_thaw_notify (G_OBJECT (dst));
}
@ -1028,6 +1033,12 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev
has_minor_changes = TRUE;
}
/* metered */
if (src_priv->metered != dst_priv->metered) {
dst_priv->metered = src_priv->metered;
has_minor_changes = TRUE;
}
/* config_equal does not compare *all* the fields, therefore, we might have has_minor_changes
* regardless of config_equal. But config_equal must correspond to has_relevant_changes. */
g_assert (config_equal == !has_relevant_changes);
@ -1098,6 +1109,7 @@ nm_ip4_config_dump (const NMIP4Config *config, const char *detail)
}
g_message (" n-dflt: %d", nm_ip4_config_get_never_default (config));
g_message (" mtrd: %d", (int) nm_ip4_config_get_metered (config));
}
gboolean
@ -1744,6 +1756,24 @@ nm_ip4_config_get_mtu_source (const NMIP4Config *config)
/******************************************************************/
void
nm_ip4_config_set_metered (NMIP4Config *config, gboolean metered)
{
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
priv->metered = !!metered;
}
gboolean
nm_ip4_config_get_metered (const NMIP4Config *config)
{
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
return priv->metered;
}
/******************************************************************/
static inline void
hash_u32 (GChecksum *sum, guint32 n)
{

View file

@ -146,6 +146,10 @@ void nm_ip4_config_set_mtu (NMIP4Config *config, guint32 mtu, NMIPConfigSource s
guint32 nm_ip4_config_get_mtu (const NMIP4Config *config);
NMIPConfigSource nm_ip4_config_get_mtu_source (const NMIP4Config *config);
/* Metered */
void nm_ip4_config_set_metered (NMIP4Config *config, gboolean metered);
gboolean nm_ip4_config_get_metered (const NMIP4Config *config);
void nm_ip4_config_hash (const NMIP4Config *config, GChecksum *sum, gboolean dns_only);
gboolean nm_ip4_config_equal (const NMIP4Config *a, const NMIP4Config *b);

View file

@ -161,6 +161,7 @@ typedef struct {
guint ac_cleanup_id;
NMActiveConnection *primary_connection;
NMActiveConnection *activating_connection;
NMMetered metered;
GSList *devices;
NMState state;
@ -233,6 +234,7 @@ enum {
PROP_PRIMARY_CONNECTION_TYPE,
PROP_ACTIVATING_CONNECTION,
PROP_DEVICES,
PROP_METERED,
/* Not exported */
PROP_HOSTNAME,
@ -657,6 +659,30 @@ find_best_device_state (NMManager *manager)
return best_state;
}
static void
nm_manager_update_metered (NMManager *manager)
{
NMManagerPrivate *priv;
NMDevice *device;
NMMetered value = NM_METERED_UNKNOWN;
g_return_if_fail (NM_IS_MANAGER (manager));
priv = NM_MANAGER_GET_PRIVATE (manager);
if (priv->primary_connection) {
device = nm_active_connection_get_device (priv->primary_connection);
if (device)
value = nm_device_get_metered (device);
}
if (value != priv->metered) {
priv->metered = value;
nm_log_dbg (LOGD_CORE, "New manager metered value: %d",
(int) priv->metered);
g_object_notify (G_OBJECT (manager), NM_MANAGER_METERED);
}
}
static void
nm_manager_update_state (NMManager *manager)
{
@ -4259,6 +4285,14 @@ firmware_dir_changed (GFileMonitor *monitor,
}
}
static void
connection_metered_changed (GObject *object,
NMMetered metered,
gpointer user_data)
{
nm_manager_update_metered (NM_MANAGER (user_data));
}
static void
policy_default_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data)
{
@ -4281,11 +4315,23 @@ policy_default_device_changed (GObject *object, GParamSpec *pspec, gpointer user
ac = NULL;
if (ac != priv->primary_connection) {
g_clear_object (&priv->primary_connection);
if (priv->primary_connection) {
g_signal_handlers_disconnect_by_func (priv->primary_connection,
G_CALLBACK (connection_metered_changed),
self);
g_clear_object (&priv->primary_connection);
}
priv->primary_connection = ac ? g_object_ref (ac) : NULL;
if (priv->primary_connection) {
g_signal_connect (priv->primary_connection, NM_ACTIVE_CONNECTION_DEVICE_METERED_CHANGED,
G_CALLBACK (connection_metered_changed), self);
}
nm_log_dbg (LOGD_CORE, "PrimaryConnection now %s", ac ? nm_active_connection_get_id (ac) : "(none)");
g_object_notify (G_OBJECT (self), NM_MANAGER_PRIMARY_CONNECTION);
g_object_notify (G_OBJECT (self), NM_MANAGER_PRIMARY_CONNECTION_TYPE);
nm_manager_update_metered (self);
}
}
@ -4879,6 +4925,8 @@ nm_manager_init (NMManager *manager)
/* Update timestamps in active connections */
priv->timestamp_update_id = g_timeout_add_seconds (300, (GSourceFunc) periodic_update_active_connection_timestamps, manager);
priv->metered = NM_METERED_UNKNOWN;
}
static void
@ -4963,6 +5011,9 @@ get_property (GObject *object, guint prop_id,
}
g_value_take_boxed (value, array);
break;
case PROP_METERED:
g_value_set_uint (value, priv->metered);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -5238,6 +5289,20 @@ nm_manager_class_init (NMManagerClass *manager_class)
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/**
* NMManager:metered:
*
* Whether the connectivity is metered.
*
* Since: 1.0.6
**/
g_object_class_install_property
(object_class, PROP_METERED,
g_param_spec_uint (NM_MANAGER_METERED, "", "",
0, G_MAXUINT32, NM_METERED_UNKNOWN,
G_PARAM_READABLE |
G_PARAM_STATIC_STRINGS));
/* signals */
signals[DEVICE_ADDED] =
g_signal_new ("device-added",

View file

@ -51,6 +51,7 @@
#define NM_MANAGER_PRIMARY_CONNECTION_TYPE "primary-connection-type"
#define NM_MANAGER_ACTIVATING_CONNECTION "activating-connection"
#define NM_MANAGER_DEVICES "devices"
#define NM_MANAGER_METERED "metered"
/* Not exported */
#define NM_MANAGER_HOSTNAME "hostname"

View file

@ -250,6 +250,15 @@ make_connection_setting (const char *file,
g_free (value);
}
switch (svTrueValue (ifcfg, "CONNECTION_METERED", -1)) {
case TRUE:
g_object_set (s_con, NM_SETTING_CONNECTION_METERED, NM_METERED_YES, NULL);
break;
case FALSE:
g_object_set (s_con, NM_SETTING_CONNECTION_METERED, NM_METERED_NO, NULL);
break;
}
return NM_SETTING (s_con);
}

View file

@ -303,11 +303,11 @@ svGetValueFull (shvarFile *s, const char *key, gboolean verbatim)
* return FALSE if <key> resolves to any non-truth value (e.g. "no", "n", "false")
* return <default> otherwise
*/
gboolean
svTrueValue (shvarFile *s, const char *key, gboolean def)
gint
svTrueValue (shvarFile *s, const char *key, gint def)
{
char *tmp;
gboolean returnValue = def;
gint returnValue = def;
tmp = svGetValue (s, key, FALSE);
if (!tmp)

View file

@ -62,7 +62,7 @@ char *svGetValueFull (shvarFile *s, const char *key, gboolean verbatim);
* return FALSE if <key> resolves to any non-truth value (e.g. "no", "n", "false")
* return <def> otherwise
*/
gboolean svTrueValue (shvarFile *s, const char *key, gboolean def);
gint svTrueValue (shvarFile *s, const char *key, gint def);
gint64 svGetValueInt64 (shvarFile *s, const char *key, guint base, gint64 min, gint64 max, gint64 fallback);

View file

@ -1764,6 +1764,17 @@ write_connection_setting (NMSettingConnection *s_con, shvarFile *ifcfg)
svSetValue (ifcfg, "GATEWAY_PING_TIMEOUT", tmp, FALSE);
g_free (tmp);
}
switch (nm_setting_connection_get_metered (s_con)) {
case NM_METERED_YES:
svSetValue (ifcfg, "CONNECTION_METERED", "yes", FALSE);
break;
case NM_METERED_NO:
svSetValue (ifcfg, "CONNECTION_METERED", "no", FALSE);
break;
default:
svSetValue (ifcfg, "CONNECTION_METERED", NULL, FALSE);
}
}
static gboolean