merge: branch 'lr/connection-token'

https://bugzilla.gnome.org/show_bug.cgi?id=765851
This commit is contained in:
Lubomir Rintel 2016-05-30 16:40:41 +02:00
commit 2edaf35f12
19 changed files with 438 additions and 100 deletions

View file

@ -330,6 +330,7 @@ NmcOutputField nmc_fields_setting_ip6_config[] = {
SETTING_FIELD (NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE), /* 15 */
SETTING_FIELD (NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME), /* 16 */
SETTING_FIELD (NM_SETTING_IP_CONFIG_DHCP_HOSTNAME), /* 17 */
SETTING_FIELD (NM_SETTING_IP6_CONFIG_TOKEN), /* 18 */
{NULL, NULL, 0, NULL, FALSE, FALSE, 0}
};
#define NMC_FIELDS_SETTING_IP6_CONFIG_ALL "name"","\
@ -349,7 +350,8 @@ NmcOutputField nmc_fields_setting_ip6_config[] = {
NM_SETTING_IP6_CONFIG_IP6_PRIVACY","\
NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE","\
NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME","\
NM_SETTING_IP_CONFIG_DHCP_HOSTNAME
NM_SETTING_IP_CONFIG_DHCP_HOSTNAME","\
NM_SETTING_IP6_CONFIG_TOKEN
/* Available fields for NM_SETTING_SERIAL_SETTING_NAME */
NmcOutputField nmc_fields_setting_serial[] = {
@ -1629,6 +1631,7 @@ DEFINE_GETTER (nmc_property_ipv6_get_never_default, NM_SETTING_IP_CONFIG_NEVER_D
DEFINE_GETTER (nmc_property_ipv6_get_may_fail, NM_SETTING_IP_CONFIG_MAY_FAIL)
DEFINE_GETTER (nmc_property_ipv6_get_dhcp_send_hostname, NM_SETTING_IP_CONFIG_DHCP_SEND_HOSTNAME)
DEFINE_GETTER (nmc_property_ipv6_get_dhcp_hostname, NM_SETTING_IP_CONFIG_DHCP_HOSTNAME)
DEFINE_GETTER (nmc_property_ipv6_get_token, NM_SETTING_IP6_CONFIG_TOKEN)
static char *
nmc_property_ipv6_get_ip6_privacy (NMSetting *setting, NmcPropertyGetType get_type)
@ -6728,6 +6731,13 @@ nmc_properties_init (void)
NULL,
NULL,
NULL);
nmc_add_prop_funcs (GLUE (IP6_CONFIG, TOKEN),
nmc_property_ipv6_get_token,
nmc_property_set_string,
NULL,
NULL,
NULL,
NULL);
/* Add editable properties for NM_SETTING_OLPC_MESH_SETTING_NAME */
nmc_add_prop_funcs (GLUE (OLPC_MESH, SSID),
@ -8256,6 +8266,7 @@ setting_ip6_config_details (NMSetting *setting, NmCli *nmc, const char *one_pro
set_val_str (arr, 15, nmc_property_ipv6_get_addr_gen_mode (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 16, nmc_property_ipv6_get_dhcp_send_hostname (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 17, nmc_property_ipv6_get_dhcp_hostname (setting, NMC_PROPERTY_GET_PRETTY));
set_val_str (arr, 18, nmc_property_ipv6_get_token (setting, NMC_PROPERTY_GET_PRETTY));
g_ptr_array_add (nmc->output_data, arr);
print_data (nmc); /* Print all data */

View file

@ -23,6 +23,7 @@
#include "nm-default.h"
#include <string.h>
#include <arpa/inet.h>
#include "nm-connection.h"
#include "nm-connection-private.h"
@ -724,7 +725,7 @@ _normalize_ip_config (NMConnection *self, GHashTable *parameters)
const char *default_ip6_method = NULL;
NMSettingIPConfig *s_ip4, *s_ip6;
NMSetting *setting;
gboolean gateway_removed = FALSE;
gboolean changed = FALSE;
if (parameters)
default_ip6_method = g_hash_table_lookup (parameters, NM_CONNECTION_NORMALIZE_PARAM_IP6_CONFIG_METHOD);
@ -761,7 +762,7 @@ _normalize_ip_config (NMConnection *self, GHashTable *parameters)
if ( nm_setting_ip_config_get_gateway (s_ip4)
&& nm_setting_ip_config_get_never_default (s_ip4)) {
g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, NULL, NULL);
gateway_removed = TRUE;
changed = TRUE;
}
}
if (!s_ip6) {
@ -773,13 +774,31 @@ _normalize_ip_config (NMConnection *self, GHashTable *parameters)
NULL);
nm_connection_add_setting (self, setting);
} else {
const char *token;
token = nm_setting_ip6_config_get_token ((NMSettingIP6Config *) s_ip6);
if ( token
&& nm_setting_ip6_config_get_addr_gen_mode ((NMSettingIP6Config *) s_ip6) == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64) {
struct in6_addr i6_token;
char normalized[NM_UTILS_INET_ADDRSTRLEN];
if ( inet_pton (AF_INET6, token, &i6_token) == 1
&& _nm_utils_inet6_is_token (&i6_token)) {
nm_utils_inet6_ntop (&i6_token, normalized);
if (g_strcmp0 (token, normalized)) {
g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_TOKEN, normalized, NULL);
changed = TRUE;
}
}
}
if ( nm_setting_ip_config_get_gateway (s_ip6)
&& nm_setting_ip_config_get_never_default (s_ip6)) {
g_object_set (s_ip6, NM_SETTING_IP_CONFIG_GATEWAY, NULL, NULL);
gateway_removed = TRUE;
changed = TRUE;
}
}
return !s_ip4 || !s_ip6 || gateway_removed;
return !s_ip4 || !s_ip6 || changed;
}
}

View file

@ -296,4 +296,8 @@ typedef enum {
NMBondOptionType
_nm_setting_bond_get_option_type (NMSettingBond *setting, const char *name);
/***********************************************************/
gboolean _nm_utils_inet6_is_token (const struct in6_addr *in6addr);
#endif

View file

@ -24,6 +24,7 @@
#include "nm-setting-ip6-config.h"
#include <string.h>
#include <arpa/inet.h>
#include "nm-setting-private.h"
#include "nm-core-enum-types.h"
@ -59,6 +60,7 @@ NM_SETTING_REGISTER_TYPE (NM_TYPE_SETTING_IP6_CONFIG)
typedef struct {
NMSettingIP6ConfigPrivacy ip6_privacy;
NMSettingIP6ConfigAddrGenMode addr_gen_mode;
char *token;
} NMSettingIP6ConfigPrivate;
@ -66,6 +68,7 @@ enum {
PROP_0,
PROP_IP6_PRIVACY,
PROP_ADDR_GEN_MODE,
PROP_TOKEN,
LAST_PROP
};
@ -120,6 +123,25 @@ nm_setting_ip6_config_get_addr_gen_mode (NMSettingIP6Config *setting)
return NM_SETTING_IP6_CONFIG_GET_PRIVATE (setting)->addr_gen_mode;
}
/**
* nm_setting_ip6_config_get_token:
* @setting: the #NMSettingIP6Config
*
* Returns the value contained in the #NMSettingIP6Config:token
* property.
*
* Returns: A string.
*
* Since: 1.4
**/
const char *
nm_setting_ip6_config_get_token (NMSettingIP6Config *setting)
{
g_return_val_if_fail (NM_IS_SETTING_IP6_CONFIG (setting), NULL);
return NM_SETTING_IP6_CONFIG_GET_PRIVATE (setting)->token;
}
static gboolean
verify (NMSetting *setting, NMConnection *connection, GError **error)
{
@ -127,6 +149,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
NMSettingIPConfig *s_ip = NM_SETTING_IP_CONFIG (setting);
NMSettingVerifyResult ret;
const char *method;
gboolean token_needs_normalization = FALSE;
ret = NM_SETTING_CLASS (nm_setting_ip6_config_parent_class)->verify (setting, connection, error);
if (ret != NM_SETTING_VERIFY_SUCCESS)
@ -201,6 +224,44 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
return FALSE;
}
if (priv->token) {
if (priv->addr_gen_mode == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64) {
struct in6_addr i6_token;
char s_token[NM_UTILS_INET_ADDRSTRLEN];
if ( inet_pton (AF_INET6, priv->token, &i6_token) != 1
|| !_nm_utils_inet6_is_token (&i6_token)) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("value is not a valid token"));
g_prefix_error (error, "%s.%s: ", NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_SETTING_IP6_CONFIG_TOKEN);
return FALSE;
}
if (g_strcmp0 (priv->token, nm_utils_inet6_ntop (&i6_token, s_token)))
token_needs_normalization = TRUE;
} else {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("only makes sense with EUI64 address generation mode"));
g_prefix_error (error, "%s.%s: ", NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_SETTING_IP6_CONFIG_TOKEN);
return FALSE;
}
}
/* Failures from here on, are NORMALIZABLE_ERROR... */
if (token_needs_normalization) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("token is not in canonical form"));
g_prefix_error (error, "%s.%s: ", NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_SETTING_IP6_CONFIG_TOKEN);
return NM_SETTING_VERIFY_NORMALIZABLE_ERROR;
}
return TRUE;
}
@ -388,6 +449,10 @@ set_property (GObject *object, guint prop_id,
case PROP_ADDR_GEN_MODE:
priv->addr_gen_mode = g_value_get_int (value);
break;
case PROP_TOKEN:
g_free (priv->token);
priv->token = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -407,12 +472,26 @@ get_property (GObject *object, guint prop_id,
case PROP_ADDR_GEN_MODE:
g_value_set_int (value, priv->addr_gen_mode);
break;
case PROP_TOKEN:
g_value_set_string (value, priv->token);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
finalize (GObject *object)
{
NMSettingIP6Config *self = NM_SETTING_IP6_CONFIG (object);
NMSettingIP6ConfigPrivate *priv = NM_SETTING_IP6_CONFIG_GET_PRIVATE (self);
g_free (priv->token);
G_OBJECT_CLASS (nm_setting_ip6_config_parent_class)->finalize (object);
}
static void
nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *ip6_class)
{
@ -424,6 +503,7 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *ip6_class)
/* virtual methods */
object_class->set_property = set_property;
object_class->get_property = get_property;
object_class->finalize = finalize;
setting_class->verify = verify;
/* Properties */
@ -656,6 +736,30 @@ nm_setting_ip6_config_class_init (NMSettingIP6ConfigClass *ip6_class)
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS));
/**
* NMSettingIP6Config:token:
*
* Configure the token for draft-chown-6man-tokenised-ipv6-identifiers-02
* IPv6 tokenized interface identifiers. Useful with eui64 addr-gen-mode.
*
* Since: 1.4
**/
/* ---ifcfg-rh---
* property: token
* variable: IPV6_TOKEN
* description: The IPv6 tokenized interface identifier token
* example: IPV6_TOKEN=::53
* ---end---
*/
g_object_class_install_property
(object_class, PROP_TOKEN,
g_param_spec_string (NM_SETTING_IP6_CONFIG_TOKEN, "", "",
NULL,
G_PARAM_READWRITE |
NM_SETTING_PARAM_INFERRABLE |
G_PARAM_STATIC_STRINGS));
/* IP6-specific property overrides */
/* ---dbus---

View file

@ -43,6 +43,8 @@ G_BEGIN_DECLS
#define NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE "addr-gen-mode"
#define NM_SETTING_IP6_CONFIG_TOKEN "token"
/**
* NM_SETTING_IP6_CONFIG_METHOD_IGNORE:
*
@ -156,6 +158,8 @@ NMSetting *nm_setting_ip6_config_new (void);
NMSettingIP6ConfigPrivacy nm_setting_ip6_config_get_ip6_privacy (NMSettingIP6Config *setting);
NM_AVAILABLE_IN_1_2
NMSettingIP6ConfigAddrGenMode nm_setting_ip6_config_get_addr_gen_mode (NMSettingIP6Config *setting);
NM_AVAILABLE_IN_1_4
const char *nm_setting_ip6_config_get_token (NMSettingIP6Config *setting);
G_END_DECLS

View file

@ -3565,6 +3565,40 @@ nm_utils_ipaddr_valid (int family, const char *ip)
return inet_pton (family, ip, buf) == 1;
}
/**
* nm_utils_iinet6_is_token:
* @in6addr: the AF_INET6 address structure
*
* Checks if only the bottom 64bits of the address are set.
*
* Return value: %TRUE or %FALSE
*/
gboolean
_nm_utils_inet6_is_token (const struct in6_addr *in6addr)
{
if ( in6addr->s6_addr[0]
|| in6addr->s6_addr[1]
|| in6addr->s6_addr[2]
|| in6addr->s6_addr[3]
|| in6addr->s6_addr[4]
|| in6addr->s6_addr[5]
|| in6addr->s6_addr[6]
|| in6addr->s6_addr[7])
return FALSE;
if ( in6addr->s6_addr[8]
|| in6addr->s6_addr[9]
|| in6addr->s6_addr[10]
|| in6addr->s6_addr[11]
|| in6addr->s6_addr[12]
|| in6addr->s6_addr[13]
|| in6addr->s6_addr[14]
|| in6addr->s6_addr[15])
return TRUE;
return FALSE;
}
/**
* nm_utils_check_virtual_device_compatibility:
* @virtual_type: a virtual connection type

View file

@ -800,7 +800,7 @@ set_property (GObject *object, guint prop_id,
switch (prop_id) {
case PROP_DBUS_SERVICE_NAME:
/* Construct-only */
priv->dbus_service_name = g_strdup (g_value_get_string (value));
priv->dbus_service_name = g_value_dup_string (value);
break;
case PROP_STATE:
nm_vpn_plugin_set_state (NM_VPN_PLUGIN (object),

View file

@ -1403,7 +1403,7 @@ _nm_setting_verify_deprecated_virtual_iface_name (const char *interface_name,
e_invalid_property,
_("property is invalid"));
g_prefix_error (error, "%s.%s: ", setting_name, setting_property);
/* we would like to make this a NORMALIZEABLE_ERROR, but that might
/* we would like to make this a NORMALIZABLE_ERROR, but that might
* break older connections. */
return NM_SETTING_VERIFY_NORMALIZABLE;
}

View file

@ -735,39 +735,72 @@ static gboolean
get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *out_iid)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMLinkType link_type;
const guint8 *hwaddr = NULL;
size_t hwaddr_len = 0;
const NMPlatformLink *pllink;
int ifindex;
gboolean success;
/* If we get here, we *must* have a kernel netdev, which implies an ifindex */
ifindex = nm_device_get_ip_ifindex (self);
g_assert (ifindex);
g_return_val_if_fail (ifindex > 0, FALSE);
link_type = nm_platform_link_get_type (NM_PLATFORM_GET, ifindex);
g_return_val_if_fail (link_type > NM_LINK_TYPE_UNKNOWN, 0);
hwaddr = nm_platform_link_get_address (NM_PLATFORM_GET, ifindex, &hwaddr_len);
if (!hwaddr_len)
pllink = nm_platform_link_get (NM_PLATFORM_GET, ifindex);
if ( !pllink
|| NM_IN_SET (pllink->type, NM_LINK_TYPE_NONE, NM_LINK_TYPE_UNKNOWN))
return FALSE;
success = nm_utils_get_ipv6_interface_identifier (link_type,
hwaddr,
hwaddr_len,
if (pllink->addr.len <= 0)
return FALSE;
if (pllink->addr.len > NM_UTILS_HWADDR_LEN_MAX)
g_return_val_if_reached (FALSE);
success = nm_utils_get_ipv6_interface_identifier (pllink->type,
pllink->addr.data,
pllink->addr.len,
priv->dev_id,
out_iid);
if (!success) {
_LOGW (LOGD_HW, "failed to generate interface identifier "
"for link type %u hwaddr_len %zu", link_type, hwaddr_len);
"for link type %u hwaddr_len %u", pllink->type, (unsigned) pllink->addr.len);
}
return success;
}
/**
* nm_device_get_ip_iface_identifier:
* @self: an #NMDevice
* @iid: where to place the interface identifier
* @ignore_token: force creation of a non-tokenized address
*
* Return the interface's identifier for the EUI64 address generation mode.
* It's either a manually set token or and identifier generated in a
* hardware-specific way.
*
* Unless @ignore_token is set the token is preferred. That is the case
* for link-local addresses (to mimic kernel behavior).
*
* Returns: #TRUE if the @iid could be set
*/
static gboolean
nm_device_get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *iid)
nm_device_get_ip_iface_identifier (NMDevice *self, NMUtilsIPv6IfaceId *iid, gboolean ignore_token)
{
return NM_DEVICE_GET_CLASS (self)->get_ip_iface_identifier (self, iid);
NMSettingIP6Config *s_ip6;
const char *token = NULL;
NMConnection *connection;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
connection = nm_device_get_applied_connection (self);
nm_assert (connection);
s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting_ip6_config (connection));
nm_assert (s_ip6);
if (!ignore_token)
token = nm_setting_ip6_config_get_token (s_ip6);
if (token)
return nm_utils_ipv6_interface_identifier_get_from_token (iid, token);
else
return NM_DEVICE_GET_CLASS (self)->get_ip_iface_identifier (self, iid);
}
const char *
@ -1606,7 +1639,6 @@ device_link_changed (NMDevice *self)
{
NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMUtilsIPv6IfaceId token_iid;
gboolean ip_ifname_changed = FALSE;
const char *udi;
NMPlatformLink info;
@ -1678,10 +1710,11 @@ device_link_changed (NMDevice *self)
nm_device_emit_recheck_auto_activate (self);
}
if (priv->rdisc && nm_platform_link_get_ipv6_token (NM_PLATFORM_GET, priv->ifindex, &token_iid)) {
_LOGD (LOGD_DEVICE, "IPv6 tokenized identifier present on device %s", priv->iface);
if (nm_rdisc_set_iid (priv->rdisc, token_iid))
if (priv->rdisc && info.inet6_token.id) {
if (nm_rdisc_set_iid (priv->rdisc, info.inet6_token)) {
_LOGD (LOGD_DEVICE, "IPv6 tokenized identifier present on device %s", priv->iface);
nm_rdisc_start (priv->rdisc);
}
}
if (klass->link_changed)
@ -3061,6 +3094,7 @@ nm_device_generate_connection (NMDevice *self, NMDevice *master)
gs_free char *uuid = NULL;
const char *ip4_method, *ip6_method;
GError *error = NULL;
const NMPlatformLink *pllink;
/* If update_connection() is not implemented, just fail. */
if (!klass->update_connection)
@ -3107,6 +3141,15 @@ nm_device_generate_connection (NMDevice *self, NMDevice *master)
s_ip6 = nm_ip6_config_create_setting (priv->ip6_config);
nm_connection_add_setting (connection, s_ip6);
pllink = nm_platform_link_get (NM_PLATFORM_GET, priv->ifindex);
if (pllink && pllink->inet6_token.id) {
_LOGD (LOGD_IP6, "IPv6 tokenized identifier present");
g_object_set (s_ip6,
NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, NM_IN6_ADDR_GEN_MODE_EUI64,
NM_SETTING_IP6_CONFIG_TOKEN, nm_utils_inet6_interface_identifier_to_token (pllink->inet6_token, NULL),
NULL);
}
}
klass->update_connection (self, connection);
@ -5194,6 +5237,7 @@ ip6_config_merge_and_apply (NMDevice *self,
gboolean ignore_auto_routes = FALSE;
gboolean ignore_auto_dns = FALSE;
gboolean auto_method = FALSE;
const char *token = NULL;
/* Apply ignore-auto-routes and ignore-auto-dns settings */
connection = nm_device_get_applied_connection (self);
@ -5201,9 +5245,14 @@ ip6_config_merge_and_apply (NMDevice *self,
NMSettingIPConfig *s_ip6 = nm_connection_get_setting_ip6_config (connection);
if (s_ip6) {
NMSettingIP6Config *ip6 = NM_SETTING_IP6_CONFIG (s_ip6);
ignore_auto_routes = nm_setting_ip_config_get_ignore_auto_routes (s_ip6);
ignore_auto_dns = nm_setting_ip_config_get_ignore_auto_dns (s_ip6);
if (nm_setting_ip6_config_get_addr_gen_mode (ip6) == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64)
token = nm_setting_ip6_config_get_token (ip6);
if (NM_IN_STRSET (nm_setting_ip_config_get_method (s_ip6),
NM_SETTING_IP6_CONFIG_METHOD_AUTO,
NM_SETTING_IP6_CONFIG_METHOD_DHCP))
@ -5351,6 +5400,14 @@ END_ADD_DEFAULT_ROUTE:
/* Allow setting MTU etc */
if (commit) {
NMUtilsIPv6IfaceId iid;
if (token && nm_utils_ipv6_interface_identifier_get_from_token (&iid, token)) {
nm_platform_link_set_ipv6_token (NM_PLATFORM_GET,
nm_device_get_ip_ifindex (self),
iid);
}
if (NM_DEVICE_GET_CLASS (self)->ip6_config_pre_commit)
NM_DEVICE_GET_CLASS (self)->ip6_config_pre_commit (self, composite);
}
@ -5823,13 +5880,13 @@ check_and_add_ipv6ll_addr (NMDevice *self)
return;
}
if (!nm_device_get_ip_iface_identifier (self, &iid)) {
if (!nm_device_get_ip_iface_identifier (self, &iid, TRUE)) {
_LOGW (LOGD_IP6, "linklocal6: failed to get interface identifier; IPv6 cannot continue");
return;
}
_LOGD (LOGD_IP6, "linklocal6: using EUI-64 identifier to generate IPv6LL address");
nm_utils_ipv6_addr_set_interface_identfier (&lladdr, iid);
nm_utils_ipv6_addr_set_interface_identifier (&lladdr, iid);
}
_LOGD (LOGD_IP6, "linklocal6: adding IPv6LL address %s", nm_utils_inet6_ntop (&lladdr, NULL));
@ -6108,10 +6165,7 @@ addrconf6_start_with_link_ready (NMDevice *self)
g_assert (priv->rdisc);
if (nm_platform_link_get_ipv6_token (NM_PLATFORM_GET, priv->ifindex, &iid)) {
_LOGD (LOGD_IP6, "addrconf6: IPv6 tokenized identifier present");
nm_rdisc_set_iid (priv->rdisc, iid);
} else if (nm_device_get_ip_iface_identifier (self, &iid)) {
if (nm_device_get_ip_iface_identifier (self, &iid, FALSE)) {
_LOGD (LOGD_IP6, "addrconf6: using the device EUI-64 identifier");
nm_rdisc_set_iid (priv->rdisc, iid);
} else {
@ -10658,7 +10712,7 @@ nm_device_spawn_iface_helper (NMDevice *self)
g_ptr_array_add (argv, g_strdup ("--slaac-tempaddr"));
g_ptr_array_add (argv, g_strdup_printf ("%d", priv->rdisc_use_tempaddr));
if (nm_device_get_ip_iface_identifier (self, &iid)) {
if (nm_device_get_ip_iface_identifier (self, &iid, FALSE)) {
g_ptr_array_add (argv, g_strdup ("--iid"));
hex_iid = bin2hexstr ((const char *) iid.id_u8, sizeof (NMUtilsIPv6IfaceId));
g_ptr_array_add (argv, hex_iid);
@ -11693,11 +11747,11 @@ set_property (GObject *object, guint prop_id,
break;
case PROP_DRIVER_VERSION:
g_free (priv->driver_version);
priv->driver_version = g_strdup (g_value_get_string (value));
priv->driver_version = g_value_dup_string (value);
break;
case PROP_FIRMWARE_VERSION:
g_free (priv->firmware_version);
priv->firmware_version = g_strdup (g_value_get_string (value));
priv->firmware_version = g_value_dup_string (value);
break;
case PROP_MTU:
priv->mtu = g_value_get_uint (value);

View file

@ -834,7 +834,7 @@ set_property (GObject *object, guint prop_id,
switch (prop_id) {
case PROP_IFACE:
/* construct-only */
priv->iface = g_strdup (g_value_get_string (value));
priv->iface = g_value_dup_string (value);
break;
case PROP_IFINDEX:
/* construct-only */

View file

@ -2866,20 +2866,92 @@ nm_utils_get_ipv6_interface_identifier (NMLinkType link_type,
}
return FALSE;
}
/*****************************************************************************/
/**
* nm_utils_ipv6_addr_set_interface_identifier:
* @addr: output token encoded as %in6_addr
* @iid: %NMUtilsIPv6IfaceId interface identifier
*
* Converts the %NMUtilsIPv6IfaceId to an %in6_addr (suitable for use
* with Linux platform). This only copies the lower 8 bytes, ignoring
* the /64 network prefix which is expected to be all-zero for a valid
* token.
*/
void
nm_utils_ipv6_addr_set_interface_identfier (struct in6_addr *addr,
nm_utils_ipv6_addr_set_interface_identifier (struct in6_addr *addr,
const NMUtilsIPv6IfaceId iid)
{
memcpy (addr->s6_addr + 8, &iid.id_u8, 8);
}
/**
* nm_utils_ipv6_interface_identifier_get_from_addr:
* @iid: output %NMUtilsIPv6IfaceId interface identifier set from the token
* @addr: token encoded as %in6_addr
*
* Converts the %in6_addr encoded token (as used by Linux platform) to
* the interface identifier.
*/
void
nm_utils_ipv6_interface_identfier_get_from_addr (NMUtilsIPv6IfaceId *iid,
nm_utils_ipv6_interface_identifier_get_from_addr (NMUtilsIPv6IfaceId *iid,
const struct in6_addr *addr)
{
memcpy (iid, addr->s6_addr + 8, 8);
}
/**
* nm_utils_ipv6_interface_identifier_get_from_token:
* @iid: output %NMUtilsIPv6IfaceId interface identifier set from the token
* @token: token encoded as string
*
* Converts the %in6_addr encoded token (as used in ip6 settings) to
* the interface identifier.
*
* Returns: %TRUE if the @token is a valid token, %FALSE otherwise
*/
gboolean
nm_utils_ipv6_interface_identifier_get_from_token (NMUtilsIPv6IfaceId *iid,
const char *token)
{
struct in6_addr i6_token;
g_return_val_if_fail (token, FALSE);
if (!inet_pton (AF_INET6, token, &i6_token))
return FALSE;
if (!_nm_utils_inet6_is_token (&i6_token))
return FALSE;
nm_utils_ipv6_interface_identifier_get_from_addr (iid, &i6_token);
return TRUE;
}
/**
* nm_utils_inet6_interface_identifier_to_token:
* @iid: %NMUtilsIPv6IfaceId interface identifier
* @buf: the destination buffer or %NULL
*
* Converts the interface identifier to a string token.
* If the destination buffer it set, set it is used to store the
* resulting token, otherwise an internal static buffer is used.
* The buffer needs to be %NM_UTILS_INET_ADDRSTRLEN characters long.
*
* Returns: a statically allocated array. Do not g_free().
*/
const char *
nm_utils_inet6_interface_identifier_to_token (NMUtilsIPv6IfaceId iid, char *buf)
{
struct in6_addr i6_token = { .s6_addr = { 0, } };
nm_utils_ipv6_addr_set_interface_identifier (&i6_token, iid);
return nm_utils_inet6_ntop (&i6_token, buf);
}
/*****************************************************************************/
static gboolean
_set_stable_privacy (struct in6_addr *addr,
const char *ifname,

View file

@ -335,24 +335,30 @@ struct _NMUtilsIPv6IfaceId {
#define NM_UTILS_IPV6_IFACE_ID_INIT { { .id = 0 } }
void nm_utils_ipv6_addr_set_interface_identifier (struct in6_addr *addr,
const NMUtilsIPv6IfaceId iid);
void nm_utils_ipv6_interface_identifier_get_from_addr (NMUtilsIPv6IfaceId *iid,
const struct in6_addr *addr);
gboolean nm_utils_ipv6_interface_identifier_get_from_token (NMUtilsIPv6IfaceId *iid,
const char *token);
const char *nm_utils_inet6_interface_identifier_to_token (NMUtilsIPv6IfaceId iid,
char *buf);
gboolean nm_utils_get_ipv6_interface_identifier (NMLinkType link_type,
const guint8 *hwaddr,
guint len,
guint dev_id,
NMUtilsIPv6IfaceId *out_iid);
void nm_utils_ipv6_addr_set_interface_identfier (struct in6_addr *addr,
const NMUtilsIPv6IfaceId iid);
gboolean nm_utils_ipv6_addr_set_stable_privacy (struct in6_addr *addr,
const char *ifname,
const char *uuid,
guint dad_counter,
GError **error);
void nm_utils_ipv6_interface_identfier_get_from_addr (NMUtilsIPv6IfaceId *iid,
const struct in6_addr *addr);
void nm_utils_array_remove_at_indexes (GArray *array, const guint *indexes_to_delete, gsize len);
void nm_utils_setpgid (gpointer unused);

View file

@ -798,9 +798,10 @@ _nl_nlmsg_type_to_str (guint16 type, char *buf, gsize len)
static gboolean
_parse_af_inet6 (NMPlatform *platform,
struct nlattr *attr,
NMUtilsIPv6IfaceId *out_iid,
guint8 *out_iid_is_valid,
guint8 *out_addr_gen_mode_inv)
NMUtilsIPv6IfaceId *out_token,
gboolean *out_token_valid,
guint8 *out_addr_gen_mode_inv,
gboolean *out_addr_gen_mode_valid)
{
static struct nla_policy policy[IFLA_INET6_MAX+1] = {
[IFLA_INET6_FLAGS] = { .type = NLA_U32 },
@ -814,7 +815,8 @@ _parse_af_inet6 (NMPlatform *platform,
struct nlattr *tb[IFLA_INET6_MAX+1];
int err;
struct in6_addr i6_token;
gboolean iid_is_valid = FALSE;
gboolean token_valid = FALSE;
gboolean addr_gen_mode_valid = FALSE;
guint8 i6_addr_gen_mode_inv = 0;
gboolean success = FALSE;
@ -831,8 +833,7 @@ _parse_af_inet6 (NMPlatform *platform,
if (_check_addr_or_errout (tb, IFLA_INET6_TOKEN, sizeof (struct in6_addr))) {
nla_memcpy (&i6_token, tb[IFLA_INET6_TOKEN], sizeof (struct in6_addr));
if (!IN6_IS_ADDR_UNSPECIFIED (&i6_token))
iid_is_valid = TRUE;
token_valid = TRUE;
}
/* Hack to detect support addrgenmode of the kernel. We only parse
@ -847,21 +848,18 @@ _parse_af_inet6 (NMPlatform *platform,
* to signal "unset". */
goto errout;
}
addr_gen_mode_valid = TRUE;
}
success = TRUE;
if (iid_is_valid) {
out_iid->id_u8[7] = i6_token.s6_addr[15];
out_iid->id_u8[6] = i6_token.s6_addr[14];
out_iid->id_u8[5] = i6_token.s6_addr[13];
out_iid->id_u8[4] = i6_token.s6_addr[12];
out_iid->id_u8[3] = i6_token.s6_addr[11];
out_iid->id_u8[2] = i6_token.s6_addr[10];
out_iid->id_u8[1] = i6_token.s6_addr[9];
out_iid->id_u8[0] = i6_token.s6_addr[8];
*out_iid_is_valid = TRUE;
if (token_valid) {
*out_token_valid = token_valid;
nm_utils_ipv6_interface_identifier_get_from_addr (out_token, &i6_token);
}
if (addr_gen_mode_valid) {
*out_addr_gen_mode_valid = addr_gen_mode_valid;
*out_addr_gen_mode_inv = i6_addr_gen_mode_inv;
}
*out_addr_gen_mode_inv = i6_addr_gen_mode_inv;
errout:
return success;
}
@ -1436,6 +1434,8 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
NMPObject *lnk_data = NULL;
gboolean address_complete_from_cache = TRUE;
gboolean lnk_data_complete_from_cache = TRUE;
gboolean af_inet6_token_valid = FALSE;
gboolean af_inet6_addr_gen_mode_valid = FALSE;
if (!nlmsg_valid_hdr (nlh, sizeof (*ifi)))
return NULL;
@ -1512,9 +1512,10 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
case AF_INET6:
_parse_af_inet6 (platform,
af_attr,
&obj->link.inet6_token.iid,
&obj->link.inet6_token.is_valid,
&obj->link.inet6_addr_gen_mode_inv);
&obj->link.inet6_token,
&af_inet6_token_valid,
&obj->link.inet6_addr_gen_mode_inv,
&af_inet6_addr_gen_mode_valid);
break;
}
}
@ -1556,7 +1557,9 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
if ( completed_from_cache
&& ( lnk_data_complete_from_cache
|| address_complete_from_cache)) {
|| address_complete_from_cache
|| !af_inet6_token_valid
|| !af_inet6_addr_gen_mode_valid)) {
_lookup_cached_link (cache, obj->link.ifindex, completed_from_cache, &link_cached);
if (link_cached) {
if ( lnk_data_complete_from_cache
@ -1575,6 +1578,10 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
}
if (address_complete_from_cache)
obj->link.addr = link_cached->link.addr;
if (!af_inet6_token_valid)
obj->link.inet6_token = link_cached->link.inet6_token;
if (!af_inet6_addr_gen_mode_valid)
obj->link.inet6_addr_gen_mode_inv = link_cached->link.inet6_addr_gen_mode_inv;
}
}
@ -1947,7 +1954,8 @@ nmp_object_new_from_nl (NMPlatform *platform, const NMPCache *cache, struct nl_m
static gboolean
_nl_msg_new_link_set_afspec (struct nl_msg *msg,
int addr_gen_mode)
int addr_gen_mode,
NMUtilsIPv6IfaceId *iid)
{
struct nlattr *af_spec;
struct nlattr *af_attr;
@ -1957,11 +1965,19 @@ _nl_msg_new_link_set_afspec (struct nl_msg *msg,
if (!(af_spec = nla_nest_start (msg, IFLA_AF_SPEC)))
goto nla_put_failure;
if (addr_gen_mode >= 0) {
if (addr_gen_mode >= 0 || iid) {
if (!(af_attr = nla_nest_start (msg, AF_INET6)))
goto nla_put_failure;
NLA_PUT_U8 (msg, IFLA_INET6_ADDR_GEN_MODE, addr_gen_mode);
if (addr_gen_mode >= 0)
NLA_PUT_U8 (msg, IFLA_INET6_ADDR_GEN_MODE, addr_gen_mode);
if (iid) {
struct in6_addr i6_token = { .s6_addr = { 0, } };
nm_utils_ipv6_addr_set_interface_identifier (&i6_token, *iid);
NLA_PUT (msg, IFLA_INET6_TOKEN, sizeof (struct in6_addr), &i6_token);
}
nla_nest_end (msg, af_attr);
}
@ -4322,8 +4338,22 @@ link_set_user_ipv6ll_enabled (NMPlatform *platform, int ifindex, gboolean enable
0,
0);
if ( !nlmsg
|| !_nl_msg_new_link_set_afspec (nlmsg,
mode))
|| !_nl_msg_new_link_set_afspec (nlmsg, mode, NULL))
g_return_val_if_reached (FALSE);
return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
}
static gboolean
link_set_token (NMPlatform *platform, int ifindex, NMUtilsIPv6IfaceId iid)
{
nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
_LOGD ("link: change %d: token: set IPv6 address generation token to %s",
ifindex, nm_utils_inet6_interface_identifier_to_token (iid, NULL));
nlmsg = _nl_msg_new_link (RTM_NEWLINK, 0, ifindex, NULL, 0, 0);
if (!nlmsg || !_nl_msg_new_link_set_afspec (nlmsg, -1, &iid))
g_return_val_if_reached (FALSE);
return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
@ -6435,6 +6465,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
platform_class->link_get_udev_device = link_get_udev_device;
platform_class->link_set_user_ipv6ll_enabled = link_set_user_ipv6ll_enabled;
platform_class->link_set_token = link_set_token;
platform_class->link_set_address = link_set_address;
platform_class->link_get_permanent_address = link_get_permanent_address;

View file

@ -900,33 +900,25 @@ nm_platform_link_uses_arp (NMPlatform *self, int ifindex)
}
/**
* nm_platform_link_get_ipv6_token:
* nm_platform_link_set_ipv6_token:
* @self: platform instance
* @ifindex: Interface index
* @iid: Tokenized interface identifier
*
* Returns IPv6 tokenized interface identifier. If the platform or OS doesn't
* support IPv6 tokenized interface identifiers, or the token is not set
* this call will fail and return %FALSE.
* Sets then IPv6 tokenized interface identifier.
*
* Returns: %TRUE a tokenized identifier was available
*/
gboolean
nm_platform_link_get_ipv6_token (NMPlatform *self, int ifindex, NMUtilsIPv6IfaceId *iid)
nm_platform_link_set_ipv6_token (NMPlatform *self, int ifindex, NMUtilsIPv6IfaceId iid)
{
const NMPlatformLink *pllink;
_CHECK_SELF (self, klass, FALSE);
g_return_val_if_fail (ifindex >= 0, FALSE);
g_return_val_if_fail (iid, FALSE);
g_return_val_if_fail (iid.id, FALSE);
pllink = nm_platform_link_get (self, ifindex);
if (pllink && pllink->inet6_token.is_valid) {
*iid = pllink->inet6_token.iid;
return TRUE;
}
if (klass->link_set_token)
return klass->link_set_token (self, ifindex, iid);
return FALSE;
}
@ -3067,7 +3059,7 @@ nm_platform_link_to_string (const NMPlatformLink *link, char *buf, gsize len)
GString *str_flags;
char str_addrmode[30];
gs_free char *str_addr = NULL;
gs_free char *str_inet6_token = NULL;
char str_inet6_token[NM_UTILS_INET_ADDRSTRLEN];
const char *str_link_type;
if (!nm_utils_to_string_buffer_init_null (link, &buf, &len))
@ -3104,8 +3096,6 @@ nm_platform_link_to_string (const NMPlatformLink *link, char *buf, gsize len)
if (link->addr.len)
str_addr = nm_utils_hwaddr_ntoa (link->addr.data, MIN (link->addr.len, sizeof (link->addr.data)));
if (link->inet6_token.is_valid)
str_inet6_token = nm_utils_hwaddr_ntoa (&link->inet6_token.iid, sizeof (link->inet6_token.iid));
str_link_type = nm_link_type_to_string (link->type);
@ -3139,8 +3129,8 @@ nm_platform_link_to_string (const NMPlatformLink *link, char *buf, gsize len)
link->inet6_addr_gen_mode_inv ? nm_platform_link_inet6_addrgenmode2str (_nm_platform_uint8_inv (link->inet6_addr_gen_mode_inv), str_addrmode, sizeof (str_addrmode)) : "",
str_addr ? " addr " : "",
str_addr ? str_addr : "",
str_inet6_token ? " inet6token " : "",
str_inet6_token ? str_inet6_token : "",
link->inet6_token.id ? " inet6token " : "",
link->inet6_token.id ? nm_utils_inet6_interface_identifier_to_token (link->inet6_token, str_inet6_token) : "",
link->driver ? " driver " : "",
link->driver ? link->driver : "");
g_string_free (str_flags, TRUE);
@ -3798,13 +3788,11 @@ nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b)
_CMP_FIELD (a, b, arptype);
_CMP_FIELD (a, b, addr.len);
_CMP_FIELD (a, b, inet6_addr_gen_mode_inv);
_CMP_FIELD (a, b, inet6_token.is_valid);
_CMP_FIELD_STR_INTERNED (a, b, kind);
_CMP_FIELD_STR_INTERNED (a, b, driver);
if (a->addr.len)
_CMP_FIELD_MEMCMP_LEN (a, b, addr.data, a->addr.len);
if (a->inet6_token.is_valid)
_CMP_FIELD_MEMCMP (a, b, inet6_token.iid);
_CMP_FIELD_MEMCMP (a, b, inet6_token);
return 0;
}

View file

@ -147,11 +147,8 @@ struct _NMPlatformLink {
guint8 len;
} addr;
/* rtnl_link_inet6_get_token() */
struct {
NMUtilsIPv6IfaceId iid;
guint8 is_valid;
} inet6_token;
/* rtnl_link_inet6_get_token(), IFLA_INET6_TOKEN */
NMUtilsIPv6IfaceId inet6_token;
/* The bitwise inverse of rtnl_link_inet6_get_addr_gen_mode(). It is inverse
* to have a default of 0 -- meaning: unspecified. That way, a struct
@ -523,6 +520,7 @@ typedef struct {
GObject *(*link_get_udev_device) (NMPlatform *self, int ifindex);
gboolean (*link_set_user_ipv6ll_enabled) (NMPlatform *, int ifindex, gboolean enabled);
gboolean (*link_set_token) (NMPlatform *, int ifindex, NMUtilsIPv6IfaceId iid);
gboolean (*link_get_permanent_address) (NMPlatform *,
int ifindex,
@ -733,7 +731,6 @@ gboolean nm_platform_link_is_up (NMPlatform *self, int ifindex);
gboolean nm_platform_link_is_connected (NMPlatform *self, int ifindex);
gboolean nm_platform_link_uses_arp (NMPlatform *self, int ifindex);
guint32 nm_platform_link_get_mtu (NMPlatform *self, int ifindex);
gboolean nm_platform_link_get_ipv6_token (NMPlatform *self, int ifindex, NMUtilsIPv6IfaceId *iid);
gboolean nm_platform_link_get_user_ipv6ll_enabled (NMPlatform *self, int ifindex);
gconstpointer nm_platform_link_get_address (NMPlatform *self, int ifindex, size_t *length);
int nm_platform_link_get_master (NMPlatform *self, int slave);
@ -757,6 +754,7 @@ const char *nm_platform_link_get_udi (NMPlatform *self, int ifindex);
GObject *nm_platform_link_get_udev_device (NMPlatform *self, int ifindex);
gboolean nm_platform_link_set_user_ipv6ll_enabled (NMPlatform *self, int ifindex, gboolean enabled);
gboolean nm_platform_link_set_ipv6_token (NMPlatform *self, int ifindex, NMUtilsIPv6IfaceId iid);
gboolean nm_platform_link_get_permanent_address (NMPlatform *self, int ifindex, guint8 *buf, size_t *length);
gboolean nm_platform_link_set_address (NMPlatform *self, int ifindex, const void *address, size_t length);

View file

@ -540,7 +540,7 @@ iid_value_to_ll6_addr (GVariant *dict,
out_addr->s6_addr16[0] = htons (0xfe80);
memcpy (out_addr->s6_addr + 8, &iid, sizeof (iid));
if (out_iid)
nm_utils_ipv6_interface_identfier_get_from_addr (out_iid, out_addr);
nm_utils_ipv6_interface_identifier_get_from_addr (out_iid, out_addr);
return TRUE;
}

View file

@ -161,7 +161,7 @@ complete_address (NMRDisc *rdisc, NMRDiscAddress *addr)
if (addr->address.s6_addr32[2] == 0x0 && addr->address.s6_addr32[3] == 0x0) {
_LOGD ("complete-address: adding an EUI-64 address");
nm_utils_ipv6_addr_set_interface_identfier (&addr->address, rdisc->iid);
nm_utils_ipv6_addr_set_interface_identifier (&addr->address, rdisc->iid);
return TRUE;
}

View file

@ -1527,6 +1527,13 @@ make_ip6_setting (shvarFile *ifcfg,
NULL);
}
/* IPv6 tokenized interface identifier */
tmp = svGetValue (ifcfg, "IPV6_TOKEN", FALSE);
if (tmp) {
g_object_set (s_ip6, NM_SETTING_IP6_CONFIG_TOKEN, tmp, NULL);
g_free (tmp);
}
/* DNS servers
* Pick up just IPv6 addresses (IPv4 addresses are taken by make_ip4_setting())
*/

View file

@ -2623,8 +2623,14 @@ write_ip6_setting (NMConnection *connection, shvarFile *ifcfg, GError **error)
addr_gen_mode);
svSetValue (ifcfg, "IPV6_ADDR_GEN_MODE", tmp, FALSE);
g_free (tmp);
} else {
svSetValue (ifcfg, "IPV6_ADDR_GEN_MODE", NULL, FALSE);
}
/* IPv6 tokenized interface identifier */
value = nm_setting_ip6_config_get_token (NM_SETTING_IP6_CONFIG (s_ip6));
svSetValue (ifcfg, "IPV6_TOKEN", value, FALSE);
priority = nm_setting_ip_config_get_dns_priority (s_ip6);
if (priority)
svSetValueInt64 (ifcfg, "IPV6_DNS_PRIORITY", priority);