core: ensure platform links are compatible with the NMDevice

Ensure the platform link with the same interface name as the
NMDevice is actually compatible with it before using the link
for initialization of device properties.  If not, remove the
NMDevice and create a new one since there are kernel resources
with a different type.
This commit is contained in:
Dan Williams 2014-10-09 12:42:29 -05:00 committed by Thomas Haller
parent 4dbaac4ba2
commit 20906ca7a3
19 changed files with 125 additions and 29 deletions

View file

@ -529,7 +529,7 @@ nm_device_bond_class_init (NMDeviceBondClass *klass)
g_type_class_add_private (object_class, sizeof (NMDeviceBondPrivate));
parent_class->connection_type = NM_SETTING_BOND_SETTING_NAME;
NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_BOND_SETTING_NAME, NM_LINK_TYPE_BOND)
/* virtual methods */
object_class->get_property = get_property;

View file

@ -475,7 +475,7 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *klass)
g_type_class_add_private (object_class, sizeof (NMDeviceBridgePrivate));
parent_class->connection_type = NM_SETTING_BRIDGE_SETTING_NAME;
NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_BRIDGE_SETTING_NAME, NM_LINK_TYPE_BRIDGE)
/* virtual methods */
object_class->get_property = get_property;

View file

@ -1706,7 +1706,7 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass)
g_type_class_add_private (object_class, sizeof (NMDeviceEthernetPrivate));
parent_class->connection_type = NM_SETTING_WIRED_SETTING_NAME;
NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_WIRED_SETTING_NAME, NM_LINK_TYPE_ETHERNET)
/* virtual methods */
object_class->constructor = constructor;

View file

@ -196,7 +196,7 @@ nm_device_generic_class_init (NMDeviceGenericClass *klass)
g_type_class_add_private (klass, sizeof (NMDeviceGenericPrivate));
parent_class->connection_type = NM_SETTING_GENERIC_SETTING_NAME;
NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_GENERIC_SETTING_NAME, NM_LINK_TYPE_ANY)
object_class->constructor = constructor;
object_class->dispose = dispose;

View file

@ -327,6 +327,8 @@ nm_device_infiniband_class_init (NMDeviceInfinibandClass *klass)
g_type_class_add_private (object_class, sizeof (NMDeviceInfinibandPrivate));
NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_INFINIBAND_SETTING_NAME, NM_LINK_TYPE_INFINIBAND)
/* virtual methods */
object_class->get_property = get_property;
object_class->set_property = set_property;

View file

@ -852,7 +852,12 @@ nm_device_ip_tunnel_class_init (NMDeviceIPTunnelClass *klass)
device_class->setup_start = setup_start;
device_class->unrealize = unrealize;
device_class->connection_type = NM_SETTING_IP_TUNNEL_SETTING_NAME;
NM_DEVICE_CLASS_DECLARE_TYPES (klass,
NM_SETTING_IP_TUNNEL_SETTING_NAME,
NM_LINK_TYPE_GRE,
NM_LINK_TYPE_IP6TNL,
NM_LINK_TYPE_IPIP,
NM_LINK_TYPE_SIT);
/* properties */
g_object_class_install_property

View file

@ -143,6 +143,8 @@ nm_device_macvlan_class_init (NMDeviceMacvlanClass *klass)
g_type_class_add_private (klass, sizeof (NMDeviceMacvlanPrivate));
NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVTAP)
object_class->constructed = constructed;
object_class->get_property = get_property;

View file

@ -106,4 +106,11 @@ void nm_device_set_wwan_ip6_config (NMDevice *device, NMIP6Config *config);
gboolean nm_device_ipv6_sysctl_set (NMDevice *self, const char *property, const char *value);
#define NM_DEVICE_CLASS_DECLARE_TYPES(klass, conn_type, ...) \
NM_DEVICE_CLASS (klass)->connection_type = conn_type; \
{ \
static const NMLinkType link_types[] = { __VA_ARGS__, NM_LINK_TYPE_NONE }; \
NM_DEVICE_CLASS (klass)->link_types = link_types; \
}
#endif /* NM_DEVICE_PRIVATE_H */

View file

@ -364,6 +364,8 @@ nm_device_tun_class_init (NMDeviceTunClass *klass)
g_type_class_add_private (klass, sizeof (NMDeviceTunPrivate));
NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_TUN, NM_LINK_TYPE_TAP)
object_class->get_property = get_property;
object_class->set_property = set_property;

View file

@ -153,6 +153,8 @@ nm_device_veth_class_init (NMDeviceVethClass *klass)
g_type_class_add_private (klass, sizeof (NMDeviceVethPrivate));
NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_VETH)
object_class->get_property = get_property;
object_class->dispose = dispose;

View file

@ -667,7 +667,7 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass);
parent_class->connection_type = NM_SETTING_VLAN_SETTING_NAME;
NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_VLAN_SETTING_NAME, NM_LINK_TYPE_VLAN)
g_type_class_add_private (object_class, sizeof (NMDeviceVlanPrivate));

View file

@ -244,6 +244,8 @@ nm_device_vxlan_class_init (NMDeviceVxlanClass *klass)
g_type_class_add_private (klass, sizeof (NMDeviceVxlanPrivate));
NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_VXLAN)
object_class->get_property = get_property;
device_class->link_changed = link_changed;

View file

@ -1634,20 +1634,69 @@ link_changed (NMDevice *self, NMPlatformLink *info)
nm_device_set_carrier (self, info->connected);
}
static gboolean
link_type_compatible (NMDevice *self,
NMLinkType link_type,
gboolean *out_compatible,
GError **error)
{
NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self);
guint i = 0;
if (!klass->link_types) {
NM_SET_OUT (out_compatible, FALSE);
g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
"Device does not support platform links");
return FALSE;
}
for (i = 0; klass->link_types[i] > NM_LINK_TYPE_UNKNOWN; i++) {
if (klass->link_types[i] == link_type)
return TRUE;
if (klass->link_types[i] == NM_LINK_TYPE_ANY)
return TRUE;
}
NM_SET_OUT (out_compatible, FALSE);
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
"Device does not support platform link type 0x%X",
link_type);
return FALSE;
}
/**
* nm_device_realize():
* @self: the #NMDevice
* @plink: an existing platform link or %NULL
* @out_compatible: %TRUE on return if @self is compatible with @plink
* @error: location to store error, or %NULL
*
* Initializes and sets up the device using existing backing resources. Before
* the device is ready for use nm_device_setup_finish() must be called.
* @out_compatible will only be set if @plink is not %NULL, and
*
* Returns: %TRUE on success, %FALSE on error
*/
gboolean
nm_device_realize (NMDevice *self, NMPlatformLink *plink, GError **error)
nm_device_realize (NMDevice *self,
NMPlatformLink *plink,
gboolean *out_compatible,
GError **error)
{
NM_SET_OUT (out_compatible, TRUE);
if (plink) {
if (g_strcmp0 (nm_device_get_iface (self), plink->name) != 0) {
NM_SET_OUT (out_compatible, FALSE);
g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
"Device interface name does not match platform link");
return FALSE;
}
if (!link_type_compatible (self, plink->type, out_compatible, error))
return FALSE;
}
/* Try to realize the device from existing resources */
if (NM_DEVICE_GET_CLASS (self)->realize) {
if (!NM_DEVICE_GET_CLASS (self)->realize (self, plink, error))
@ -1766,7 +1815,7 @@ setup_start (NMDevice *self, NMPlatformLink *plink)
g_object_freeze_notify (G_OBJECT (self));
if (plink) {
g_return_if_fail (priv->iface == NULL || strcmp (plink->name, priv->iface) == 0);
g_return_if_fail (link_type_compatible (self, plink->type, NULL, NULL));
update_device_from_platform_link (self, plink);
}
@ -1871,6 +1920,8 @@ setup_finish (NMDevice *self, NMPlatformLink *plink)
void
nm_device_setup_finish (NMDevice *self, NMPlatformLink *plink)
{
g_return_if_fail (!plink || link_type_compatible (self, plink->type, NULL, NULL));
NM_DEVICE_GET_CLASS (self)->setup_finish (self, plink);
NM_DEVICE_GET_PRIVATE (self)->real = TRUE;
@ -10073,6 +10124,7 @@ set_property (GObject *object, guint prop_id,
const char *hw_addr, *p;
guint count;
gboolean val_bool;
const NMPlatformLink *pllink;
switch (prop_id) {
case PROP_UDI:
@ -10082,12 +10134,19 @@ set_property (GObject *object, guint prop_id,
}
break;
case PROP_IFACE:
if (g_value_get_string (value)) {
p = g_value_get_string (value);
if (p) {
g_free (priv->iface);
priv->iface = g_value_dup_string (value);
priv->ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->iface);
if (priv->ifindex > 0)
priv->up = nm_platform_link_is_up (NM_PLATFORM_GET, priv->ifindex);
priv->iface = g_strdup (p);
pllink = nm_platform_link_get_by_ifname (NM_PLATFORM_GET, priv->iface);
if (pllink) {
if (link_type_compatible (self, pllink->type, NULL, NULL)) {
priv->ifindex = pllink->ifindex;
priv->up = nm_platform_link_is_up (NM_PLATFORM_GET, priv->ifindex);
}
}
}
break;
case PROP_DRIVER:

View file

@ -123,6 +123,7 @@ typedef struct {
NMExportedObjectClass parent;
const char *connection_type;
const NMLinkType *link_types;
void (*state_changed) (NMDevice *device,
NMDeviceState new_state,
@ -485,6 +486,7 @@ gboolean nm_device_has_capability (NMDevice *self, NMDeviceCapabilities caps);
gboolean nm_device_realize (NMDevice *device,
NMPlatformLink *plink,
gboolean *out_compatible,
GError **error);
gboolean nm_device_create_and_realize (NMDevice *self,
NMConnection *connection,

View file

@ -802,7 +802,7 @@ nm_device_team_class_init (NMDeviceTeamClass *klass)
g_type_class_add_private (object_class, sizeof (NMDeviceTeamPrivate));
parent_class->connection_type = NM_SETTING_TEAM_SETTING_NAME;
NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_TEAM_SETTING_NAME, NM_LINK_TYPE_TEAM)
/* virtual methods */
object_class->constructed = constructed;

View file

@ -511,6 +511,8 @@ nm_device_olpc_mesh_class_init (NMDeviceOlpcMeshClass *klass)
g_type_class_add_private (object_class, sizeof (NMDeviceOlpcMeshPrivate));
NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_OLPC_MESH_SETTING_NAME, NM_LINK_TYPE_OLPC_MESH)
object_class->constructor = constructor;
object_class->get_property = get_property;
object_class->set_property = set_property;

View file

@ -3034,6 +3034,8 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass)
g_type_class_add_private (object_class, sizeof (NMDeviceWifiPrivate));
NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_WIRELESS_SETTING_NAME, NM_LINK_TYPE_WIFI)
object_class->constructor = constructor;
object_class->get_property = get_property;
object_class->set_property = set_property;

View file

@ -1818,7 +1818,7 @@ factory_device_added_cb (NMDeviceFactory *factory,
{
GError *error = NULL;
if (nm_device_realize (device, NULL, &error)) {
if (nm_device_realize (device, NULL, NULL, &error)) {
add_device (NM_MANAGER (user_data), device);
nm_device_setup_finish (device, NULL);
} else {
@ -1878,22 +1878,29 @@ platform_link_added (NMManager *self,
device = find_device_by_iface (self, plink->name);
if (device) {
if (!nm_device_is_real (device)) {
if (nm_device_realize (device, plink, &error))
nm_device_setup_finish (device, plink);
else {
nm_log_warn (LOGD_DEVICE, "(%s): %s", plink->name, error->message);
g_clear_error (&error);
remove_device (self, device, FALSE, FALSE);
}
gboolean compatible = FALSE;
if (nm_device_is_real (device))
return;
} else if (!nm_device_realize (device, plink, &error)) {
nm_log_warn (LOGD_HW, "%s: factory failed to create device: %s",
plink->name, error->message);
g_clear_error (&error);
if (nm_device_realize (device, plink, &compatible, &error)) {
/* Success */
nm_device_setup_finish (device, plink);
return;
}
return;
nm_log_warn (LOGD_DEVICE, "(%s): %s", plink->name, error->message);
remove_device (self, device, FALSE, FALSE);
g_clear_error (&error);
if (compatible) {
/* Device compatible with platform link, but some other fatal error
* happened during realization.
*/
return;
}
/* Fall through and create new compatible device for the link */
}
/* Try registered device factories */
@ -1932,7 +1939,7 @@ platform_link_added (NMManager *self,
if (device) {
if (nm_plugin_missing)
nm_device_set_nm_plugin_missing (device, TRUE);
if (nm_device_realize (device, plink, &error)) {
if (nm_device_realize (device, plink, NULL, &error)) {
add_device (self, device);
nm_device_setup_finish (device, plink);
} else {

View file

@ -126,6 +126,8 @@ typedef enum {
NM_LINK_TYPE_BRIDGE = 0x10000 | 0x20000,
NM_LINK_TYPE_BOND,
NM_LINK_TYPE_TEAM,
NM_LINK_TYPE_ANY = G_MAXUINT32,
} NMLinkType;
typedef enum {