mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-25 20:00:09 +01:00
merge: device factory cleanups and first parts of devices-for-all (bgo #747429)
This commit is contained in:
commit
6270db5f0b
37 changed files with 1780 additions and 1217 deletions
|
|
@ -648,6 +648,16 @@
|
|||
A new connection activation was enqueued.
|
||||
</tp:docstring>
|
||||
</tp:enumvalue>
|
||||
<tp:enumvalue suffix="PARENT_CHANGED" value="61">
|
||||
<tp:docstring>
|
||||
The device's parent changed.
|
||||
</tp:docstring>
|
||||
</tp:enumvalue>
|
||||
<tp:enumvalue suffix="PARENT_MANAGED_CHANGED" value="62">
|
||||
<tp:docstring>
|
||||
The device parent's management changed.
|
||||
</tp:docstring>
|
||||
</tp:enumvalue>
|
||||
</tp:enum>
|
||||
|
||||
<tp:struct name="NM_DEVICE_STATE_REASON_STRUCT">
|
||||
|
|
|
|||
|
|
@ -467,6 +467,8 @@ typedef enum {
|
|||
* @NM_DEVICE_STATE_REASON_MODEM_AVAILABLE: Modem now ready and available
|
||||
* @NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT: SIM PIN was incorrect
|
||||
* @NM_DEVICE_STATE_REASON_NEW_ACTIVATION: New connection activation was enqueued
|
||||
* @NM_DEVICE_STATE_REASON_PARENT_CHANGED: the device's parent changed
|
||||
* @NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED: the device parent's management changed
|
||||
*
|
||||
* Device state change reason codes
|
||||
*
|
||||
|
|
@ -534,6 +536,8 @@ typedef enum {
|
|||
NM_DEVICE_STATE_REASON_MODEM_AVAILABLE = 58,
|
||||
NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT = 59,
|
||||
NM_DEVICE_STATE_REASON_NEW_ACTIVATION = 60,
|
||||
NM_DEVICE_STATE_REASON_PARENT_CHANGED = 61,
|
||||
NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED = 62,
|
||||
} NMDeviceStateReason;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -472,6 +472,8 @@ typedef enum {
|
|||
* @NM_DEVICE_STATE_REASON_MODEM_AVAILABLE: Modem now ready and available
|
||||
* @NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT: SIM PIN was incorrect
|
||||
* @NM_DEVICE_STATE_REASON_NEW_ACTIVATION: New connection activation was enqueued
|
||||
* @NM_DEVICE_STATE_REASON_PARENT_CHANGED: the device's parent changed
|
||||
* @NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED: the device parent's management changed
|
||||
*
|
||||
* Device state change reason codes
|
||||
*
|
||||
|
|
@ -539,6 +541,8 @@ typedef enum {
|
|||
NM_DEVICE_STATE_REASON_MODEM_AVAILABLE = 58,
|
||||
NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT = 59,
|
||||
NM_DEVICE_STATE_REASON_NEW_ACTIVATION = 60,
|
||||
NM_DEVICE_STATE_REASON_PARENT_CHANGED = 61,
|
||||
NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED = 62,
|
||||
|
||||
NM_DEVICE_STATE_REASON_LAST = 0xFFFF
|
||||
} NMDeviceStateReason;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include <gmodule.h>
|
||||
|
||||
#include "nm-atm-manager.h"
|
||||
#include "nm-setting-adsl.h"
|
||||
#include "nm-device-adsl.h"
|
||||
#include "nm-device-factory.h"
|
||||
#include "nm-logging.h"
|
||||
|
|
@ -203,11 +204,9 @@ handle_uevent (GUdevClient *client,
|
|||
adsl_remove (self, device);
|
||||
}
|
||||
|
||||
static NMDeviceType
|
||||
get_device_type (NMDeviceFactory *factory)
|
||||
{
|
||||
return NM_DEVICE_TYPE_ADSL;
|
||||
}
|
||||
NM_DEVICE_FACTORY_DECLARE_TYPES (
|
||||
NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_ADSL_SETTING_NAME)
|
||||
)
|
||||
|
||||
/*********************************************************************/
|
||||
|
||||
|
|
@ -224,7 +223,7 @@ nm_atm_manager_init (NMAtmManager *self)
|
|||
static void
|
||||
device_factory_interface_init (NMDeviceFactory *factory_iface)
|
||||
{
|
||||
factory_iface->get_device_type = get_device_type;
|
||||
factory_iface->get_supported_types = get_supported_types;
|
||||
factory_iface->start = start;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "nm-logging.h"
|
||||
#include "nm-bluez-manager.h"
|
||||
#include "nm-device-factory.h"
|
||||
#include "nm-setting-bluetooth.h"
|
||||
#include "nm-bluez4-manager.h"
|
||||
#include "nm-bluez5-manager.h"
|
||||
#include "nm-bluez-device.h"
|
||||
|
|
@ -36,6 +37,7 @@
|
|||
#include "nm-connection-provider.h"
|
||||
#include "nm-device-bt.h"
|
||||
#include "nm-core-internal.h"
|
||||
#include "nm-platform.h"
|
||||
|
||||
typedef struct {
|
||||
int bluez_version;
|
||||
|
|
@ -367,11 +369,10 @@ start (NMDeviceFactory *factory)
|
|||
check_bluez_and_try_setup (NM_BLUEZ_MANAGER (factory));
|
||||
}
|
||||
|
||||
static NMDeviceType
|
||||
get_device_type (NMDeviceFactory *factory)
|
||||
{
|
||||
return NM_DEVICE_TYPE_BT;
|
||||
}
|
||||
NM_DEVICE_FACTORY_DECLARE_TYPES (
|
||||
NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_BNEP)
|
||||
NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_BLUETOOTH_SETTING_NAME)
|
||||
)
|
||||
|
||||
/*********************************************************************/
|
||||
|
||||
|
|
@ -404,10 +405,19 @@ nm_bluez_manager_init (NMBluezManager *self)
|
|||
g_assert (priv->provider);
|
||||
}
|
||||
|
||||
static NMDevice *
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error)
|
||||
{
|
||||
g_warn_if_fail (plink->type == NM_LINK_TYPE_BNEP);
|
||||
*out_ignore = TRUE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
device_factory_interface_init (NMDeviceFactory *factory_iface)
|
||||
{
|
||||
factory_iface->get_device_type = get_device_type;
|
||||
factory_iface->get_supported_types = get_supported_types;
|
||||
factory_iface->new_link = new_link;
|
||||
factory_iface->start = start;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -553,18 +553,15 @@ nm_device_bond_class_init (NMDeviceBondClass *klass)
|
|||
#define NM_BOND_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BOND_FACTORY, NMBondFactory))
|
||||
|
||||
static NMDevice *
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error)
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error)
|
||||
{
|
||||
if (plink->type == NM_LINK_TYPE_BOND) {
|
||||
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BOND,
|
||||
NM_DEVICE_PLATFORM_DEVICE, plink,
|
||||
NM_DEVICE_DRIVER, "bonding",
|
||||
NM_DEVICE_TYPE_DESC, "Bond",
|
||||
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BOND,
|
||||
NM_DEVICE_IS_MASTER, TRUE,
|
||||
NULL);
|
||||
}
|
||||
return NULL;
|
||||
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BOND,
|
||||
NM_DEVICE_PLATFORM_DEVICE, plink,
|
||||
NM_DEVICE_DRIVER, "bonding",
|
||||
NM_DEVICE_TYPE_DESC, "Bond",
|
||||
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BOND,
|
||||
NM_DEVICE_IS_MASTER, TRUE,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static NMDevice *
|
||||
|
|
@ -573,19 +570,17 @@ create_virtual_device_for_connection (NMDeviceFactory *factory,
|
|||
NMDevice *parent,
|
||||
GError **error)
|
||||
{
|
||||
const char *iface;
|
||||
const char *iface = nm_connection_get_interface_name (connection);
|
||||
|
||||
if (!nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME))
|
||||
return NULL;
|
||||
g_assert (iface);
|
||||
|
||||
iface = nm_connection_get_interface_name (connection);
|
||||
g_return_val_if_fail (iface != NULL, NULL);
|
||||
|
||||
if ( !nm_platform_bond_add (NM_PLATFORM_GET, iface)
|
||||
&& nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) {
|
||||
nm_log_warn (LOGD_DEVICE | LOGD_BOND, "(%s): failed to create bonding master interface for '%s': %s",
|
||||
iface, nm_connection_get_id (connection),
|
||||
nm_platform_get_error_msg (NM_PLATFORM_GET));
|
||||
if ( !nm_platform_bond_add (NM_PLATFORM_GET, iface, NULL)
|
||||
&& nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) {
|
||||
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
|
||||
"Failed to create bond interface '%s' for '%s': %s",
|
||||
iface,
|
||||
nm_connection_get_id (connection),
|
||||
nm_platform_get_error_msg (NM_PLATFORM_GET));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -598,7 +593,9 @@ create_virtual_device_for_connection (NMDeviceFactory *factory,
|
|||
NULL);
|
||||
}
|
||||
|
||||
DEFINE_DEVICE_FACTORY_INTERNAL(BOND, Bond, bond,
|
||||
NM_DEVICE_FACTORY_DEFINE_INTERNAL (BOND, Bond, bond,
|
||||
NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_BOND)
|
||||
NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_BOND_SETTING_NAME),
|
||||
factory_iface->new_link = new_link;
|
||||
factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection;
|
||||
)
|
||||
|
|
|
|||
|
|
@ -477,18 +477,15 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *klass)
|
|||
#define NM_BRIDGE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BRIDGE_FACTORY, NMBridgeFactory))
|
||||
|
||||
static NMDevice *
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error)
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error)
|
||||
{
|
||||
if (plink->type == NM_LINK_TYPE_BRIDGE) {
|
||||
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BRIDGE,
|
||||
NM_DEVICE_PLATFORM_DEVICE, plink,
|
||||
NM_DEVICE_DRIVER, "bridge",
|
||||
NM_DEVICE_TYPE_DESC, "Bridge",
|
||||
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BRIDGE,
|
||||
NM_DEVICE_IS_MASTER, TRUE,
|
||||
NULL);
|
||||
}
|
||||
return NULL;
|
||||
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BRIDGE,
|
||||
NM_DEVICE_PLATFORM_DEVICE, plink,
|
||||
NM_DEVICE_DRIVER, "bridge",
|
||||
NM_DEVICE_TYPE_DESC, "Bridge",
|
||||
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BRIDGE,
|
||||
NM_DEVICE_IS_MASTER, TRUE,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static NMDevice *
|
||||
|
|
@ -497,21 +494,15 @@ create_virtual_device_for_connection (NMDeviceFactory *factory,
|
|||
NMDevice *parent,
|
||||
GError **error)
|
||||
{
|
||||
const char *iface;
|
||||
const char *iface = nm_connection_get_interface_name (connection);
|
||||
NMSettingBridge *s_bridge;
|
||||
const char *mac_address_str;
|
||||
guint8 mac_address[NM_UTILS_HWADDR_LEN_MAX];
|
||||
|
||||
if (!nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME))
|
||||
return NULL;
|
||||
|
||||
g_return_val_if_fail (connection != NULL, NULL);
|
||||
|
||||
iface = nm_connection_get_interface_name (connection);
|
||||
g_return_val_if_fail (iface != NULL, NULL);
|
||||
g_assert (iface);
|
||||
|
||||
s_bridge = nm_connection_get_setting_bridge (connection);
|
||||
g_return_val_if_fail (s_bridge, NULL);
|
||||
g_assert (s_bridge);
|
||||
|
||||
mac_address_str = nm_setting_bridge_get_mac_address (s_bridge);
|
||||
if (mac_address_str) {
|
||||
|
|
@ -522,10 +513,13 @@ create_virtual_device_for_connection (NMDeviceFactory *factory,
|
|||
if ( !nm_platform_bridge_add (NM_PLATFORM_GET,
|
||||
iface,
|
||||
mac_address_str ? mac_address : NULL,
|
||||
mac_address_str ? ETH_ALEN : 0)
|
||||
mac_address_str ? ETH_ALEN : 0,
|
||||
NULL)
|
||||
&& nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) {
|
||||
nm_log_warn (LOGD_DEVICE | LOGD_BRIDGE, "(%s): failed to create bridge master interface for '%s': %s",
|
||||
iface, nm_connection_get_id (connection),
|
||||
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
|
||||
"Failed to create bridge interface '%s' for '%s': %s",
|
||||
iface,
|
||||
nm_connection_get_id (connection),
|
||||
nm_platform_get_error_msg (NM_PLATFORM_GET));
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -539,7 +533,9 @@ create_virtual_device_for_connection (NMDeviceFactory *factory,
|
|||
NULL);
|
||||
}
|
||||
|
||||
DEFINE_DEVICE_FACTORY_INTERNAL(BRIDGE, Bridge, bridge,
|
||||
NM_DEVICE_FACTORY_DEFINE_INTERNAL (BRIDGE, Bridge, bridge,
|
||||
NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_BRIDGE)
|
||||
NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_BRIDGE_SETTING_NAME),
|
||||
factory_iface->new_link = new_link;
|
||||
factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection;
|
||||
)
|
||||
|
|
|
|||
|
|
@ -99,9 +99,6 @@ typedef enum {
|
|||
} DcbWait;
|
||||
|
||||
typedef struct {
|
||||
char * perm_hw_addr; /* Permanent MAC address */
|
||||
char * initial_hw_addr; /* Initial MAC address (as seen when NM starts) */
|
||||
|
||||
guint32 speed;
|
||||
|
||||
Supplicant supplicant;
|
||||
|
|
@ -310,66 +307,6 @@ nm_device_ethernet_init (NMDeviceEthernet *self)
|
|||
priv->s390_options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
||||
}
|
||||
|
||||
static void
|
||||
update_permanent_hw_address (NMDevice *dev)
|
||||
{
|
||||
NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev);
|
||||
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
|
||||
struct ifreq req;
|
||||
struct ethtool_perm_addr *epaddr = NULL;
|
||||
int fd, ret, errsv;
|
||||
const char *mac;
|
||||
|
||||
g_return_if_fail (priv->perm_hw_addr == NULL);
|
||||
|
||||
fd = socket (PF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
_LOGW (LOGD_HW, "couldn't open control socket.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get permanent MAC address */
|
||||
memset (&req, 0, sizeof (struct ifreq));
|
||||
strncpy (req.ifr_name, nm_device_get_iface (dev), IFNAMSIZ);
|
||||
|
||||
epaddr = g_malloc0 (sizeof (struct ethtool_perm_addr) + ETH_ALEN);
|
||||
epaddr->cmd = ETHTOOL_GPERMADDR;
|
||||
epaddr->size = ETH_ALEN;
|
||||
req.ifr_data = (void *) epaddr;
|
||||
|
||||
errno = 0;
|
||||
ret = ioctl (fd, SIOCETHTOOL, &req);
|
||||
errsv = errno;
|
||||
if ((ret < 0) || !nm_ethernet_address_is_valid (epaddr->data, ETH_ALEN)) {
|
||||
_LOGD (LOGD_HW | LOGD_ETHER, "unable to read permanent MAC address (error %d)", errsv);
|
||||
/* Fall back to current address */
|
||||
mac = nm_device_get_hw_address (dev);
|
||||
if (mac)
|
||||
nm_utils_hwaddr_aton (mac, epaddr->data, ETH_ALEN);
|
||||
else
|
||||
memset (epaddr->data, 0, ETH_ALEN);
|
||||
}
|
||||
|
||||
priv->perm_hw_addr = nm_utils_hwaddr_ntoa (epaddr->data, ETH_ALEN);
|
||||
|
||||
g_free (epaddr);
|
||||
close (fd);
|
||||
}
|
||||
|
||||
static void
|
||||
update_initial_hw_address (NMDevice *dev)
|
||||
{
|
||||
NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev);
|
||||
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
|
||||
|
||||
/* This sets initial MAC address from current MAC address. It should only
|
||||
* be called from NMDevice constructor() to really get the initial address.
|
||||
*/
|
||||
priv->initial_hw_addr = g_strdup (nm_device_get_hw_address (dev));
|
||||
|
||||
_LOGD (LOGD_DEVICE | LOGD_ETHER, "read initial MAC address %s", priv->initial_hw_addr);
|
||||
}
|
||||
|
||||
static NMDeviceCapabilities
|
||||
get_generic_capabilities (NMDevice *device)
|
||||
{
|
||||
|
|
@ -421,7 +358,6 @@ static gboolean
|
|||
check_connection_compatible (NMDevice *device, NMConnection *connection)
|
||||
{
|
||||
NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device);
|
||||
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
|
||||
NMSettingWired *s_wired;
|
||||
|
||||
if (!NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->check_connection_compatible (device, connection))
|
||||
|
|
@ -438,7 +374,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
|
|||
return FALSE;
|
||||
|
||||
if (s_wired) {
|
||||
const char *mac;
|
||||
const char *mac, *perm_hw_addr;
|
||||
gboolean try_mac = TRUE;
|
||||
const char * const *mac_blacklist;
|
||||
int i;
|
||||
|
|
@ -446,21 +382,25 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
|
|||
if (!match_subchans (self, s_wired, &try_mac))
|
||||
return FALSE;
|
||||
|
||||
perm_hw_addr = nm_device_get_permanent_hw_address (device);
|
||||
mac = nm_setting_wired_get_mac_address (s_wired);
|
||||
if (try_mac && mac && !nm_utils_hwaddr_matches (mac, -1, priv->perm_hw_addr, -1))
|
||||
return FALSE;
|
||||
|
||||
/* Check for MAC address blacklist */
|
||||
mac_blacklist = nm_setting_wired_get_mac_address_blacklist (s_wired);
|
||||
for (i = 0; mac_blacklist[i]; i++) {
|
||||
if (!nm_utils_hwaddr_valid (mac_blacklist[i], ETH_ALEN)) {
|
||||
g_warn_if_reached ();
|
||||
if (perm_hw_addr) {
|
||||
if (try_mac && mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1))
|
||||
return FALSE;
|
||||
|
||||
/* Check for MAC address blacklist */
|
||||
mac_blacklist = nm_setting_wired_get_mac_address_blacklist (s_wired);
|
||||
for (i = 0; mac_blacklist[i]; i++) {
|
||||
if (!nm_utils_hwaddr_valid (mac_blacklist[i], ETH_ALEN)) {
|
||||
g_warn_if_reached ();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, perm_hw_addr, -1))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, priv->perm_hw_addr, -1))
|
||||
return FALSE;
|
||||
}
|
||||
} else if (mac)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
|
@ -1391,8 +1331,8 @@ deactivate (NMDevice *device)
|
|||
NM_DEVICE_ETHERNET_GET_PRIVATE (device)->last_pppoe_time = nm_utils_get_monotonic_timestamp_s ();
|
||||
|
||||
/* Reset MAC address back to initial address */
|
||||
if (priv->initial_hw_addr)
|
||||
nm_device_set_hw_addr (device, priv->initial_hw_addr, "reset", LOGD_ETHER);
|
||||
if (nm_device_get_initial_hw_address (device))
|
||||
nm_device_set_hw_addr (device, nm_device_get_initial_hw_address (device), "reset", LOGD_ETHER);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
|
@ -1402,10 +1342,10 @@ complete_connection (NMDevice *device,
|
|||
const GSList *existing_connections,
|
||||
GError **error)
|
||||
{
|
||||
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device);
|
||||
NMSettingWired *s_wired;
|
||||
NMSettingPppoe *s_pppoe;
|
||||
const char *setting_mac;
|
||||
const char *perm_hw_addr;
|
||||
|
||||
s_pppoe = nm_connection_get_setting_pppoe (connection);
|
||||
|
||||
|
|
@ -1432,21 +1372,22 @@ complete_connection (NMDevice *device,
|
|||
nm_connection_add_setting (connection, NM_SETTING (s_wired));
|
||||
}
|
||||
|
||||
setting_mac = nm_setting_wired_get_mac_address (s_wired);
|
||||
if (setting_mac) {
|
||||
/* Make sure the setting MAC (if any) matches the device's permanent MAC */
|
||||
if (!nm_utils_hwaddr_matches (setting_mac, -1, priv->perm_hw_addr, -1)) {
|
||||
g_set_error_literal (error,
|
||||
NM_CONNECTION_ERROR,
|
||||
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
||||
_("connection does not match device"));
|
||||
g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MAC_ADDRESS);
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
if (!nm_utils_hwaddr_matches (priv->perm_hw_addr, -1, NULL, ETH_ALEN)) {
|
||||
perm_hw_addr = nm_device_get_permanent_hw_address (device);
|
||||
if (perm_hw_addr) {
|
||||
setting_mac = nm_setting_wired_get_mac_address (s_wired);
|
||||
if (setting_mac) {
|
||||
/* Make sure the setting MAC (if any) matches the device's permanent MAC */
|
||||
if (!nm_utils_hwaddr_matches (setting_mac, -1, perm_hw_addr, -1)) {
|
||||
g_set_error_literal (error,
|
||||
NM_CONNECTION_ERROR,
|
||||
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
||||
_("connection does not match device"));
|
||||
g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MAC_ADDRESS);
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
g_object_set (G_OBJECT (s_wired),
|
||||
NM_SETTING_WIRED_MAC_ADDRESS, priv->perm_hw_addr,
|
||||
NM_SETTING_WIRED_MAC_ADDRESS, perm_hw_addr,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
|
@ -1515,6 +1456,7 @@ update_connection (NMDevice *device, NMConnection *connection)
|
|||
{
|
||||
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device);
|
||||
NMSettingWired *s_wired = nm_connection_get_setting_wired (connection);
|
||||
const char *perm_hw_addr = nm_device_get_permanent_hw_address (device);
|
||||
const char *mac = nm_device_get_hw_address (device);
|
||||
const char *mac_prop = NM_SETTING_WIRED_MAC_ADDRESS;
|
||||
GHashTableIter iter;
|
||||
|
|
@ -1528,11 +1470,11 @@ update_connection (NMDevice *device, NMConnection *connection)
|
|||
/* If the device reports a permanent address, use that for the MAC address
|
||||
* and the current MAC, if different, is the cloned MAC.
|
||||
*/
|
||||
if (!nm_utils_hwaddr_matches (priv->perm_hw_addr, -1, NULL, ETH_ALEN)) {
|
||||
g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, priv->perm_hw_addr, NULL);
|
||||
if (perm_hw_addr) {
|
||||
g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, perm_hw_addr, NULL);
|
||||
|
||||
mac_prop = NULL;
|
||||
if (mac && !nm_utils_hwaddr_matches (priv->perm_hw_addr, -1, mac, -1))
|
||||
if (mac && !nm_utils_hwaddr_matches (perm_hw_addr, -1, mac, -1))
|
||||
mac_prop = NM_SETTING_WIRED_CLONED_MAC_ADDRESS;
|
||||
}
|
||||
|
||||
|
|
@ -1649,8 +1591,6 @@ finalize (GObject *object)
|
|||
NMDeviceEthernet *self = NM_DEVICE_ETHERNET (object);
|
||||
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
|
||||
|
||||
g_free (priv->perm_hw_addr);
|
||||
g_free (priv->initial_hw_addr);
|
||||
g_clear_object (&priv->supplicant.mgr);
|
||||
g_free (priv->subchan1);
|
||||
g_free (priv->subchan2);
|
||||
|
|
@ -1671,7 +1611,7 @@ get_property (GObject *object, guint prop_id,
|
|||
|
||||
switch (prop_id) {
|
||||
case PROP_PERM_HW_ADDRESS:
|
||||
g_value_set_string (value, priv->perm_hw_addr);
|
||||
g_value_set_string (value, nm_device_get_permanent_hw_address (NM_DEVICE (object)));
|
||||
break;
|
||||
case PROP_SPEED:
|
||||
g_value_set_uint (value, priv->speed);
|
||||
|
|
@ -1711,8 +1651,6 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass)
|
|||
object_class->set_property = set_property;
|
||||
|
||||
parent_class->get_generic_capabilities = get_generic_capabilities;
|
||||
parent_class->update_permanent_hw_address = update_permanent_hw_address;
|
||||
parent_class->update_initial_hw_address = update_initial_hw_address;
|
||||
parent_class->check_connection_compatible = check_connection_compatible;
|
||||
parent_class->complete_connection = complete_connection;
|
||||
parent_class->new_default_connection = new_default_connection;
|
||||
|
|
@ -1755,19 +1693,18 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass)
|
|||
#define NM_ETHERNET_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ETHERNET_FACTORY, NMEthernetFactory))
|
||||
|
||||
static NMDevice *
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error)
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error)
|
||||
{
|
||||
if (plink->type == NM_LINK_TYPE_ETHERNET) {
|
||||
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_ETHERNET,
|
||||
NM_DEVICE_PLATFORM_DEVICE, plink,
|
||||
NM_DEVICE_TYPE_DESC, "Ethernet",
|
||||
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_ETHERNET,
|
||||
NULL);
|
||||
}
|
||||
return NULL;
|
||||
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_ETHERNET,
|
||||
NM_DEVICE_PLATFORM_DEVICE, plink,
|
||||
NM_DEVICE_TYPE_DESC, "Ethernet",
|
||||
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_ETHERNET,
|
||||
NULL);
|
||||
}
|
||||
|
||||
DEFINE_DEVICE_FACTORY_INTERNAL(ETHERNET, Ethernet, ethernet, \
|
||||
factory_iface->new_link = new_link; \
|
||||
NM_DEVICE_FACTORY_DEFINE_INTERNAL (ETHERNET, Ethernet, ethernet,
|
||||
NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_ETHERNET)
|
||||
NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_PPPOE_SETTING_NAME),
|
||||
factory_iface->new_link = new_link;
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -19,8 +19,19 @@
|
|||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <gmodule.h>
|
||||
|
||||
#include "nm-device-factory.h"
|
||||
#include "nm-logging.h"
|
||||
#include "nm-platform.h"
|
||||
|
||||
const NMLinkType _nm_device_factory_no_default_links[] = { NM_LINK_TYPE_NONE };
|
||||
const char *_nm_device_factory_no_default_settings[] = { NULL };
|
||||
|
||||
enum {
|
||||
DEVICE_ADDED,
|
||||
|
|
@ -29,21 +40,6 @@ enum {
|
|||
};
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
static GSList *internal_types = NULL;
|
||||
|
||||
void
|
||||
_nm_device_factory_internal_register_type (GType factory_type)
|
||||
{
|
||||
g_return_if_fail (g_slist_find (internal_types, GUINT_TO_POINTER (factory_type)) == NULL);
|
||||
internal_types = g_slist_prepend (internal_types, GUINT_TO_POINTER (factory_type));
|
||||
}
|
||||
|
||||
const GSList *
|
||||
nm_device_factory_get_internal_factory_types (void)
|
||||
{
|
||||
return internal_types;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_device_factory_emit_component_added (NMDeviceFactory *factory, GObject *component)
|
||||
{
|
||||
|
|
@ -53,67 +49,24 @@ nm_device_factory_emit_component_added (NMDeviceFactory *factory, GObject *compo
|
|||
return consumed;
|
||||
}
|
||||
|
||||
static void
|
||||
interface_init (gpointer g_iface)
|
||||
void
|
||||
nm_device_factory_get_supported_types (NMDeviceFactory *factory,
|
||||
const NMLinkType **out_link_types,
|
||||
const char ***out_setting_types)
|
||||
{
|
||||
GType iface_type = G_TYPE_FROM_INTERFACE (g_iface);
|
||||
static gboolean initialized = FALSE;
|
||||
const NMLinkType *link_types_fallback;
|
||||
const char **setting_types_fallback;
|
||||
|
||||
if (G_LIKELY (initialized))
|
||||
return;
|
||||
g_return_if_fail (factory != NULL);
|
||||
|
||||
/* Signals */
|
||||
signals[DEVICE_ADDED] = g_signal_new (NM_DEVICE_FACTORY_DEVICE_ADDED,
|
||||
iface_type,
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (NMDeviceFactory, device_added),
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 1, NM_TYPE_DEVICE);
|
||||
if (!out_link_types)
|
||||
out_link_types = &link_types_fallback;
|
||||
if (!out_setting_types)
|
||||
out_setting_types = &setting_types_fallback;
|
||||
|
||||
signals[COMPONENT_ADDED] = g_signal_new (NM_DEVICE_FACTORY_COMPONENT_ADDED,
|
||||
iface_type,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (NMDeviceFactory, component_added),
|
||||
g_signal_accumulator_true_handled, NULL, NULL,
|
||||
G_TYPE_BOOLEAN, 1, G_TYPE_OBJECT);
|
||||
|
||||
initialized = TRUE;
|
||||
}
|
||||
|
||||
GType
|
||||
nm_device_factory_get_type (void)
|
||||
{
|
||||
static GType device_factory_type = 0;
|
||||
|
||||
if (!device_factory_type) {
|
||||
const GTypeInfo device_factory_info = {
|
||||
sizeof (NMDeviceFactory), /* class_size */
|
||||
interface_init, /* base_init */
|
||||
NULL, /* base_finalize */
|
||||
NULL,
|
||||
NULL, /* class_finalize */
|
||||
NULL, /* class_data */
|
||||
0,
|
||||
0, /* n_preallocs */
|
||||
NULL
|
||||
};
|
||||
|
||||
device_factory_type = g_type_register_static (G_TYPE_INTERFACE,
|
||||
"NMDeviceFactory",
|
||||
&device_factory_info,
|
||||
0);
|
||||
g_type_interface_add_prerequisite (device_factory_type, G_TYPE_OBJECT);
|
||||
}
|
||||
|
||||
return device_factory_type;
|
||||
}
|
||||
|
||||
NMDeviceType
|
||||
nm_device_factory_get_device_type (NMDeviceFactory *factory)
|
||||
{
|
||||
g_return_val_if_fail (factory != NULL, NM_DEVICE_TYPE_UNKNOWN);
|
||||
|
||||
return NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_device_type (factory);
|
||||
NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_supported_types (factory,
|
||||
out_link_types,
|
||||
out_setting_types);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -128,14 +81,41 @@ nm_device_factory_start (NMDeviceFactory *factory)
|
|||
NMDevice *
|
||||
nm_device_factory_new_link (NMDeviceFactory *factory,
|
||||
NMPlatformLink *plink,
|
||||
gboolean *out_ignore,
|
||||
GError **error)
|
||||
{
|
||||
NMDeviceFactory *interface;
|
||||
const NMLinkType *link_types = NULL;
|
||||
const char **setting_types = NULL;
|
||||
int i;
|
||||
|
||||
g_return_val_if_fail (factory != NULL, NULL);
|
||||
g_return_val_if_fail (plink != NULL, NULL);
|
||||
|
||||
if (NM_DEVICE_FACTORY_GET_INTERFACE (factory)->new_link)
|
||||
return NM_DEVICE_FACTORY_GET_INTERFACE (factory)->new_link (factory, plink, error);
|
||||
return NULL;
|
||||
/* Ensure the factory can create interfaces for this connection */
|
||||
nm_device_factory_get_supported_types (factory, &link_types, &setting_types);
|
||||
for (i = 0; link_types[i] > NM_LINK_TYPE_UNKNOWN; i++) {
|
||||
if (plink->type == link_types[i])
|
||||
break;
|
||||
}
|
||||
|
||||
if (link_types[i] == NM_LINK_TYPE_UNKNOWN) {
|
||||
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
|
||||
"Device factory %s does not support link type %s (%d)",
|
||||
G_OBJECT_TYPE_NAME (factory),
|
||||
plink->kind, plink->type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
interface = NM_DEVICE_FACTORY_GET_INTERFACE (factory);
|
||||
if (!interface->new_link) {
|
||||
g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED,
|
||||
"Device factory %s cannot manage new devices",
|
||||
G_OBJECT_TYPE_NAME (factory));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return interface->new_link (factory, plink, out_ignore, error);
|
||||
}
|
||||
|
||||
NMDevice *
|
||||
|
|
@ -145,14 +125,422 @@ nm_device_factory_create_virtual_device_for_connection (NMDeviceFactory *factory
|
|||
GError **error)
|
||||
{
|
||||
NMDeviceFactory *interface;
|
||||
const char **setting_types = NULL;
|
||||
gboolean found = FALSE;
|
||||
int i;
|
||||
|
||||
g_return_val_if_fail (factory, NULL);
|
||||
g_return_val_if_fail (connection, NULL);
|
||||
g_return_val_if_fail (!error || !*error, NULL);
|
||||
|
||||
/* Ensure the factory can create interfaces for this connection */
|
||||
nm_device_factory_get_supported_types (factory, NULL, &setting_types);
|
||||
for (i = 0; setting_types && setting_types[i]; i++) {
|
||||
if (nm_connection_is_type (connection, setting_types[i])) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
|
||||
"Device factory %s does not support connection type %s",
|
||||
G_OBJECT_TYPE_NAME (factory),
|
||||
nm_connection_get_connection_type (connection));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
interface = NM_DEVICE_FACTORY_GET_INTERFACE (factory);
|
||||
if (interface->create_virtual_device_for_connection)
|
||||
return interface->create_virtual_device_for_connection (factory, connection, parent, error);
|
||||
if (!interface->create_virtual_device_for_connection) {
|
||||
g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED,
|
||||
"Device factory %s cannot create virtual devices",
|
||||
G_OBJECT_TYPE_NAME (factory));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return interface->create_virtual_device_for_connection (factory, connection, parent, error);
|
||||
}
|
||||
|
||||
const char *
|
||||
nm_device_factory_get_connection_parent (NMDeviceFactory *factory,
|
||||
NMConnection *connection)
|
||||
{
|
||||
g_return_val_if_fail (factory != NULL, NULL);
|
||||
g_return_val_if_fail (connection != NULL, NULL);
|
||||
|
||||
if (!nm_connection_is_virtual (connection))
|
||||
return NULL;
|
||||
|
||||
if (NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_connection_parent)
|
||||
return NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_connection_parent (factory, connection);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *
|
||||
get_virtual_iface_name (NMDeviceFactory *factory,
|
||||
NMConnection *connection,
|
||||
const char *parent_iface)
|
||||
{
|
||||
const char *iface;
|
||||
|
||||
/* For any other virtual connection, NMSettingConnection:interface-name is
|
||||
* the virtual device name.
|
||||
*/
|
||||
iface = nm_connection_get_interface_name (connection);
|
||||
g_return_val_if_fail (iface != NULL, NULL);
|
||||
return g_strdup (iface);
|
||||
}
|
||||
|
||||
char *
|
||||
nm_device_factory_get_virtual_iface_name (NMDeviceFactory *factory,
|
||||
NMConnection *connection,
|
||||
const char *parent_iface)
|
||||
{
|
||||
g_return_val_if_fail (factory != NULL, NULL);
|
||||
g_return_val_if_fail (connection != NULL, NULL);
|
||||
|
||||
if (!nm_connection_is_virtual (connection))
|
||||
return NULL;
|
||||
|
||||
if (NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_virtual_iface_name)
|
||||
return NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_virtual_iface_name (factory, connection, parent_iface);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*******************************************************************/
|
||||
|
||||
static void
|
||||
default_init (NMDeviceFactory *factory_iface)
|
||||
{
|
||||
factory_iface->get_virtual_iface_name = get_virtual_iface_name;
|
||||
|
||||
/* Signals */
|
||||
signals[DEVICE_ADDED] = g_signal_new (NM_DEVICE_FACTORY_DEVICE_ADDED,
|
||||
NM_TYPE_DEVICE_FACTORY,
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (NMDeviceFactory, device_added),
|
||||
NULL, NULL, NULL,
|
||||
G_TYPE_NONE, 1, NM_TYPE_DEVICE);
|
||||
|
||||
signals[COMPONENT_ADDED] = g_signal_new (NM_DEVICE_FACTORY_COMPONENT_ADDED,
|
||||
NM_TYPE_DEVICE_FACTORY,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (NMDeviceFactory, component_added),
|
||||
g_signal_accumulator_true_handled, NULL, NULL,
|
||||
G_TYPE_BOOLEAN, 1, G_TYPE_OBJECT);
|
||||
}
|
||||
|
||||
GType
|
||||
nm_device_factory_get_type (void)
|
||||
{
|
||||
static volatile gsize g_define_type_id__volatile = 0;
|
||||
if (g_once_init_enter (&g_define_type_id__volatile)) {
|
||||
GType g_define_type_id =
|
||||
g_type_register_static_simple (G_TYPE_INTERFACE,
|
||||
g_intern_static_string ("NMDeviceFactory"),
|
||||
sizeof (NMDeviceFactory),
|
||||
(GClassInitFunc) default_init,
|
||||
0,
|
||||
(GInstanceInitFunc) NULL,
|
||||
(GTypeFlags) 0);
|
||||
g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_OBJECT);
|
||||
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
|
||||
}
|
||||
return g_define_type_id__volatile;
|
||||
}
|
||||
|
||||
/*******************************************************************/
|
||||
|
||||
static GSList *internal_types = NULL;
|
||||
static GHashTable *factories_by_link = NULL;
|
||||
static GHashTable *factories_by_setting = NULL;
|
||||
|
||||
void
|
||||
_nm_device_factory_internal_register_type (GType factory_type)
|
||||
{
|
||||
g_return_if_fail (g_slist_find (internal_types, GUINT_TO_POINTER (factory_type)) == NULL);
|
||||
internal_types = g_slist_prepend (internal_types, GUINT_TO_POINTER (factory_type));
|
||||
}
|
||||
|
||||
static void __attribute__((destructor))
|
||||
_cleanup (void)
|
||||
{
|
||||
g_clear_pointer (&internal_types, g_slist_free);
|
||||
g_clear_pointer (&factories_by_link, g_hash_table_unref);
|
||||
g_clear_pointer (&factories_by_setting, g_hash_table_unref);
|
||||
}
|
||||
|
||||
static NMDeviceFactory *
|
||||
find_factory (const NMLinkType *needle_link_types,
|
||||
const char **needle_setting_types)
|
||||
{
|
||||
NMDeviceFactory *found;
|
||||
guint i;
|
||||
|
||||
g_return_val_if_fail (factories_by_link, NULL);
|
||||
g_return_val_if_fail (factories_by_setting, NULL);
|
||||
|
||||
/* NMLinkType search */
|
||||
for (i = 0; needle_link_types && needle_link_types[i] > NM_LINK_TYPE_UNKNOWN; i++) {
|
||||
found = g_hash_table_lookup (factories_by_link, GUINT_TO_POINTER (needle_link_types[i]));
|
||||
if (found)
|
||||
return found;
|
||||
}
|
||||
|
||||
/* NMSetting name search */
|
||||
for (i = 0; needle_setting_types && needle_setting_types[i]; i++) {
|
||||
found = g_hash_table_lookup (factories_by_setting, needle_setting_types[i]);
|
||||
if (found)
|
||||
return found;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NMDeviceFactory *
|
||||
nm_device_factory_manager_find_factory_for_link_type (NMLinkType link_type)
|
||||
{
|
||||
const NMLinkType ltypes[2] = { link_type, NM_LINK_TYPE_NONE };
|
||||
|
||||
g_assert (ltypes[0] > NM_LINK_TYPE_UNKNOWN);
|
||||
return find_factory (ltypes, NULL);
|
||||
}
|
||||
|
||||
NMDeviceFactory *
|
||||
nm_device_factory_manager_find_factory_for_connection (NMConnection *connection)
|
||||
{
|
||||
const char *stypes[2] = { nm_connection_get_connection_type (connection), NULL };
|
||||
|
||||
g_assert (stypes[0]);
|
||||
return find_factory (NULL, stypes);
|
||||
}
|
||||
|
||||
void
|
||||
nm_device_factory_manager_for_each_factory (NMDeviceFactoryManagerFactoryFunc callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
NMDeviceFactory *factory;
|
||||
GSList *list_iter, *list = NULL;
|
||||
|
||||
g_return_if_fail (factories_by_link);
|
||||
g_return_if_fail (factories_by_setting);
|
||||
|
||||
g_hash_table_iter_init (&iter, factories_by_link);
|
||||
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &factory)) {
|
||||
if (!g_slist_find (list, factory))
|
||||
list = g_slist_prepend (list, factory);
|
||||
}
|
||||
|
||||
g_hash_table_iter_init (&iter, factories_by_setting);
|
||||
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &factory)) {
|
||||
if (!g_slist_find (list, factory))
|
||||
list = g_slist_prepend (list, factory);
|
||||
}
|
||||
|
||||
for (list_iter = list; list_iter; list_iter = list_iter->next)
|
||||
callback (list_iter->data, user_data);
|
||||
|
||||
g_slist_free (list);
|
||||
}
|
||||
|
||||
#define PLUGIN_PREFIX "libnm-device-plugin-"
|
||||
#define PLUGIN_PATH_TAG "NMManager-plugin-path"
|
||||
|
||||
struct read_device_factory_paths_data {
|
||||
char *path;
|
||||
struct stat st;
|
||||
};
|
||||
|
||||
static gint
|
||||
read_device_factory_paths_sort_fcn (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const struct read_device_factory_paths_data *da = a;
|
||||
const struct read_device_factory_paths_data *db = b;
|
||||
time_t ta, tb;
|
||||
|
||||
ta = MAX (da->st.st_mtime, da->st.st_ctime);
|
||||
tb = MAX (db->st.st_mtime, db->st.st_ctime);
|
||||
|
||||
if (ta < tb)
|
||||
return 1;
|
||||
if (ta > tb)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char**
|
||||
read_device_factory_paths (void)
|
||||
{
|
||||
GDir *dir;
|
||||
GError *error = NULL;
|
||||
const char *item;
|
||||
GArray *paths;
|
||||
char **result;
|
||||
guint i;
|
||||
|
||||
dir = g_dir_open (NMPLUGINDIR, 0, &error);
|
||||
if (!dir) {
|
||||
nm_log_warn (LOGD_HW, "device plugin: failed to open directory %s: %s",
|
||||
NMPLUGINDIR,
|
||||
(error && error->message) ? error->message : "(unknown)");
|
||||
g_clear_error (&error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
paths = g_array_new (FALSE, FALSE, sizeof (struct read_device_factory_paths_data));
|
||||
|
||||
while ((item = g_dir_read_name (dir))) {
|
||||
int errsv;
|
||||
struct read_device_factory_paths_data data;
|
||||
|
||||
if (!g_str_has_prefix (item, PLUGIN_PREFIX))
|
||||
continue;
|
||||
if (g_str_has_suffix (item, ".la"))
|
||||
continue;
|
||||
|
||||
data.path = g_build_filename (NMPLUGINDIR, item, NULL);
|
||||
|
||||
if (stat (data.path, &data.st) != 0) {
|
||||
errsv = errno;
|
||||
nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (error during stat: %s)", data.path, strerror (errsv));
|
||||
goto NEXT;
|
||||
}
|
||||
if (!S_ISREG (data.st.st_mode))
|
||||
goto NEXT;
|
||||
if (data.st.st_uid != 0) {
|
||||
nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (file must be owned by root)", data.path);
|
||||
goto NEXT;
|
||||
}
|
||||
if (data.st.st_mode & (S_IWGRP | S_IWOTH | S_ISUID)) {
|
||||
nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (invalid file permissions)", data.path);
|
||||
goto NEXT;
|
||||
}
|
||||
|
||||
g_array_append_val (paths, data);
|
||||
continue;
|
||||
NEXT:
|
||||
g_free (data.path);
|
||||
}
|
||||
g_dir_close (dir);
|
||||
|
||||
/* sort filenames by modification time. */
|
||||
g_array_sort (paths, read_device_factory_paths_sort_fcn);
|
||||
|
||||
result = g_new (char *, paths->len + 1);
|
||||
for (i = 0; i < paths->len; i++)
|
||||
result[i] = g_array_index (paths, struct read_device_factory_paths_data, i).path;
|
||||
result[i] = NULL;
|
||||
|
||||
g_array_free (paths, TRUE);
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_add_factory (NMDeviceFactory *factory,
|
||||
gboolean check_duplicates,
|
||||
const char *path,
|
||||
NMDeviceFactoryManagerFactoryFunc callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMDeviceFactory *found = NULL;
|
||||
const NMLinkType *link_types = NULL;
|
||||
const char **setting_types = NULL;
|
||||
int i;
|
||||
|
||||
g_return_val_if_fail (factories_by_link, FALSE);
|
||||
g_return_val_if_fail (factories_by_setting, FALSE);
|
||||
|
||||
nm_device_factory_get_supported_types (factory, &link_types, &setting_types);
|
||||
if (check_duplicates) {
|
||||
found = find_factory (link_types, setting_types);
|
||||
if (found) {
|
||||
nm_log_warn (LOGD_HW, "Loading device plugin failed: multiple plugins "
|
||||
"for same type (using '%s' instead of '%s')",
|
||||
(char *) g_object_get_data (G_OBJECT (found), PLUGIN_PATH_TAG),
|
||||
path);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
g_object_set_data_full (G_OBJECT (factory), PLUGIN_PATH_TAG, g_strdup (path), g_free);
|
||||
for (i = 0; link_types && link_types[i] > NM_LINK_TYPE_UNKNOWN; i++)
|
||||
g_hash_table_insert (factories_by_link, GUINT_TO_POINTER (link_types[i]), g_object_ref (factory));
|
||||
for (i = 0; setting_types && setting_types[i]; i++)
|
||||
g_hash_table_insert (factories_by_setting, (char *) setting_types[i], g_object_ref (factory));
|
||||
|
||||
callback (factory, user_data);
|
||||
|
||||
nm_log_info (LOGD_HW, "Loaded device plugin: %s (%s)", G_OBJECT_TYPE_NAME (factory), path);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
nm_device_factory_manager_load_factories (NMDeviceFactoryManagerFactoryFunc callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMDeviceFactory *factory;
|
||||
const GSList *iter;
|
||||
GError *error = NULL;
|
||||
char **path, **paths;
|
||||
|
||||
g_return_if_fail (factories_by_link == NULL);
|
||||
g_return_if_fail (factories_by_setting == NULL);
|
||||
|
||||
factories_by_link = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
|
||||
factories_by_setting = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
|
||||
|
||||
/* Register internal factories first */
|
||||
for (iter = internal_types; iter; iter = iter->next) {
|
||||
GType ftype = (GType) GPOINTER_TO_SIZE (iter->data);
|
||||
|
||||
factory = (NMDeviceFactory *) g_object_new (ftype, NULL);
|
||||
g_assert (factory);
|
||||
_add_factory (factory, FALSE, "internal", callback, user_data);
|
||||
}
|
||||
|
||||
paths = read_device_factory_paths ();
|
||||
if (!paths)
|
||||
return;
|
||||
|
||||
for (path = paths; *path; path++) {
|
||||
GModule *plugin;
|
||||
NMDeviceFactoryCreateFunc create_func;
|
||||
const char *item;
|
||||
|
||||
item = strrchr (*path, '/');
|
||||
g_assert (item);
|
||||
|
||||
plugin = g_module_open (*path, G_MODULE_BIND_LOCAL);
|
||||
|
||||
if (!plugin) {
|
||||
nm_log_warn (LOGD_HW, "(%s): failed to load plugin: %s", item, g_module_error ());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!g_module_symbol (plugin, "nm_device_factory_create", (gpointer) &create_func)) {
|
||||
nm_log_warn (LOGD_HW, "(%s): failed to find device factory creator: %s", item, g_module_error ());
|
||||
g_module_close (plugin);
|
||||
continue;
|
||||
}
|
||||
|
||||
factory = create_func (&error);
|
||||
if (!factory) {
|
||||
nm_log_warn (LOGD_HW, "(%s): failed to initialize device factory: %s",
|
||||
item, error ? error->message : "unknown");
|
||||
g_clear_error (&error);
|
||||
g_module_close (plugin);
|
||||
continue;
|
||||
}
|
||||
g_clear_error (&error);
|
||||
|
||||
if (_add_factory (factory, TRUE, g_module_name (plugin), callback, user_data))
|
||||
g_module_make_resident (plugin);
|
||||
else
|
||||
g_module_close (plugin);
|
||||
|
||||
g_object_unref (factory);
|
||||
}
|
||||
g_strfreev (paths);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,14 +66,19 @@ struct _NMDeviceFactory {
|
|||
GTypeInterface g_iface;
|
||||
|
||||
/**
|
||||
* get_device_type:
|
||||
* get_supported_types:
|
||||
* @factory: the #NMDeviceFactory
|
||||
* @out_link_types: on return, a %NM_LINK_TYPE_NONE terminated
|
||||
* list of #NMLinkType that the plugin supports
|
||||
* @out_setting_types: on return, a %NULL terminated list of
|
||||
* base-type #NMSetting names that the plugin can create devices for
|
||||
*
|
||||
* This function MUST be implemented.
|
||||
*
|
||||
* Returns: the #NMDeviceType that this plugin creates
|
||||
* Returns the #NMLinkType and #NMSetting names that this plugin
|
||||
* supports. This function MUST be implemented.
|
||||
*/
|
||||
NMDeviceType (*get_device_type) (NMDeviceFactory *factory);
|
||||
void (*get_supported_types) (NMDeviceFactory *factory,
|
||||
const NMLinkType **out_link_types,
|
||||
const char ***out_setting_types);
|
||||
|
||||
/**
|
||||
* start:
|
||||
|
|
@ -87,20 +92,27 @@ struct _NMDeviceFactory {
|
|||
/**
|
||||
* new_link:
|
||||
* @factory: the #NMDeviceFactory
|
||||
* @link: the new link
|
||||
* @plink: the new link
|
||||
* @out_ignore: on return, %TRUE if the link should be ignored
|
||||
* @error: error if the link could be claimed but an error occurred
|
||||
*
|
||||
* The NetworkManager core was notified of a new link which the plugin
|
||||
* may want to claim and create a #NMDevice subclass for. If the link
|
||||
* represents a device the factory is capable of claiming, but the device
|
||||
* could not be created, %NULL should be returned and @error should be set.
|
||||
* %NULL should always be returned and @error should never be set if the
|
||||
* factory cannot create devices for the type which @link represents.
|
||||
* represents a device which the factory does not support, or the link
|
||||
* is supported but the device could not be created, %NULL should be
|
||||
* returned and @error should be set.
|
||||
*
|
||||
* If the plugin cannot create a #NMDevice for the link and wants the
|
||||
* core to ignore it, set @out_ignore to %TRUE and return no error.
|
||||
*
|
||||
* @plink is guaranteed to be one of the types the factory returns in
|
||||
* get_supported_types().
|
||||
*
|
||||
* Returns: the #NMDevice if the link was claimed and created, %NULL if not
|
||||
*/
|
||||
NMDevice * (*new_link) (NMDeviceFactory *factory,
|
||||
NMPlatformLink *plink,
|
||||
gboolean *out_ignore,
|
||||
GError **error);
|
||||
|
||||
/**
|
||||
|
|
@ -121,6 +133,34 @@ struct _NMDeviceFactory {
|
|||
NMDevice *parent,
|
||||
GError **error);
|
||||
|
||||
/**
|
||||
* get_connection_parent:
|
||||
* @factory: the #NMDeviceFactory
|
||||
* @connection: the #NMConnection to return the parent name for, if supported
|
||||
*
|
||||
* Given a connection, returns the a parent interface name, parent connection
|
||||
* UUID, or parent device hardware address for @connection.
|
||||
*
|
||||
* Returns: the parent interface name, parent connection UUID, parent
|
||||
* device hardware address, or %NULL
|
||||
*/
|
||||
const char * (*get_connection_parent) (NMDeviceFactory *factory,
|
||||
NMConnection *connection);
|
||||
|
||||
/**
|
||||
* get_virtual_iface_name:
|
||||
* @factory: the #NMDeviceFactory
|
||||
* @connection: the #NMConnection to return the virtual interface name for
|
||||
* @parent_iface: parent interface name
|
||||
*
|
||||
* Given a connection, returns the interface name that a device activating
|
||||
* that connection would have.
|
||||
*
|
||||
* Returns: the interface name, or %NULL
|
||||
*/
|
||||
char * (*get_virtual_iface_name) (NMDeviceFactory *factory,
|
||||
NMConnection *connection,
|
||||
const char *parent_iface);
|
||||
|
||||
/* Signals */
|
||||
|
||||
|
|
@ -151,12 +191,22 @@ struct _NMDeviceFactory {
|
|||
|
||||
GType nm_device_factory_get_type (void);
|
||||
|
||||
NMDeviceType nm_device_factory_get_device_type (NMDeviceFactory *factory);
|
||||
void nm_device_factory_get_supported_types (NMDeviceFactory *factory,
|
||||
const NMLinkType **out_link_types,
|
||||
const char ***out_setting_types);
|
||||
|
||||
const char *nm_device_factory_get_connection_parent (NMDeviceFactory *factory,
|
||||
NMConnection *connection);
|
||||
|
||||
char * nm_device_factory_get_virtual_iface_name (NMDeviceFactory *factory,
|
||||
NMConnection *connection,
|
||||
const char *parent_iface);
|
||||
|
||||
void nm_device_factory_start (NMDeviceFactory *factory);
|
||||
|
||||
NMDevice * nm_device_factory_new_link (NMDeviceFactory *factory,
|
||||
NMPlatformLink *plink,
|
||||
gboolean *out_ignore,
|
||||
GError **error);
|
||||
|
||||
NMDevice * nm_device_factory_create_virtual_device_for_connection (NMDeviceFactory *factory,
|
||||
|
|
@ -168,15 +218,33 @@ NMDevice * nm_device_factory_create_virtual_device_for_connection (NMDeviceFacto
|
|||
gboolean nm_device_factory_emit_component_added (NMDeviceFactory *factory,
|
||||
GObject *component);
|
||||
|
||||
#define NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(...) \
|
||||
{ static const NMLinkType _df_links[] = { __VA_ARGS__, NM_LINK_TYPE_NONE }; *out_link_types = _df_links; }
|
||||
#define NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(...) \
|
||||
{ static const char *_df_settings[] = { __VA_ARGS__, NULL }; *out_setting_types = _df_settings; }
|
||||
|
||||
extern const NMLinkType _nm_device_factory_no_default_links[];
|
||||
extern const char *_nm_device_factory_no_default_settings[];
|
||||
|
||||
#define NM_DEVICE_FACTORY_DECLARE_TYPES(...) \
|
||||
static void \
|
||||
get_supported_types (NMDeviceFactory *factory, \
|
||||
const NMLinkType **out_link_types, \
|
||||
const char ***out_setting_types) \
|
||||
{ \
|
||||
*out_link_types = _nm_device_factory_no_default_links; \
|
||||
*out_setting_types = _nm_device_factory_no_default_settings; \
|
||||
\
|
||||
{ __VA_ARGS__; } \
|
||||
} \
|
||||
\
|
||||
|
||||
/**************************************************************************
|
||||
* INTERNAL DEVICE FACTORY FUNCTIONS - devices provided by plugins should
|
||||
* not use these functions.
|
||||
**************************************************************************/
|
||||
|
||||
#define DEFINE_DEVICE_FACTORY_INTERNAL(upper, mixed, lower, dfi_code) \
|
||||
DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(upper, mixed, lower, upper, dfi_code)
|
||||
|
||||
#define DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(upper, mixed, lower, devtype, dfi_code) \
|
||||
#define NM_DEVICE_FACTORY_DEFINE_INTERNAL(upper, mixed, lower, st_code, dfi_code) \
|
||||
typedef GObject NM##mixed##Factory; \
|
||||
typedef GObjectClass NM##mixed##FactoryClass; \
|
||||
\
|
||||
|
|
@ -198,16 +266,12 @@ gboolean nm_device_factory_emit_component_added (NMDeviceFactory *factory,
|
|||
g_type_ensure (NM_TYPE_##upper##_FACTORY); \
|
||||
} \
|
||||
\
|
||||
static NMDeviceType \
|
||||
get_device_type (NMDeviceFactory *factory) \
|
||||
{ \
|
||||
return NM_DEVICE_TYPE_##devtype; \
|
||||
} \
|
||||
NM_DEVICE_FACTORY_DECLARE_TYPES(st_code) \
|
||||
\
|
||||
static void \
|
||||
device_factory_interface_init (NMDeviceFactory *factory_iface) \
|
||||
{ \
|
||||
factory_iface->get_device_type = get_device_type; \
|
||||
factory_iface->get_supported_types = get_supported_types; \
|
||||
dfi_code \
|
||||
} \
|
||||
\
|
||||
|
|
@ -222,6 +286,22 @@ gboolean nm_device_factory_emit_component_added (NMDeviceFactory *factory,
|
|||
}
|
||||
|
||||
void _nm_device_factory_internal_register_type (GType factory_type);
|
||||
const GSList *nm_device_factory_get_internal_factory_types (void);
|
||||
|
||||
/**************************************************************************
|
||||
* PRIVATE FACTORY FUNCTIONS - for factory consumers (eg, NMManager).
|
||||
**************************************************************************/
|
||||
|
||||
typedef void (*NMDeviceFactoryManagerFactoryFunc) (NMDeviceFactory *factory,
|
||||
gpointer user_data);
|
||||
|
||||
void nm_device_factory_manager_load_factories (NMDeviceFactoryManagerFactoryFunc callback,
|
||||
gpointer user_data);
|
||||
|
||||
NMDeviceFactory * nm_device_factory_manager_find_factory_for_link_type (NMLinkType link_type);
|
||||
|
||||
NMDeviceFactory * nm_device_factory_manager_find_factory_for_connection (NMConnection *connection);
|
||||
|
||||
void nm_device_factory_manager_for_each_factory (NMDeviceFactoryManagerFactoryFunc callback,
|
||||
gpointer user_data);
|
||||
|
||||
#endif /* __NETWORKMANAGER_DEVICE_FACTORY_H__ */
|
||||
|
|
|
|||
|
|
@ -267,19 +267,17 @@ nm_device_gre_class_init (NMDeviceGreClass *klass)
|
|||
#define NM_GRE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_GRE_FACTORY, NMGreFactory))
|
||||
|
||||
static NMDevice *
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error)
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error)
|
||||
{
|
||||
if (plink->type == NM_LINK_TYPE_GRE || plink->type == NM_LINK_TYPE_GRETAP) {
|
||||
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_GRE,
|
||||
NM_DEVICE_PLATFORM_DEVICE, plink,
|
||||
NM_DEVICE_TYPE_DESC, "Gre",
|
||||
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC,
|
||||
NULL);
|
||||
}
|
||||
return NULL;
|
||||
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_GRE,
|
||||
NM_DEVICE_PLATFORM_DEVICE, plink,
|
||||
NM_DEVICE_TYPE_DESC, "Gre",
|
||||
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC,
|
||||
NULL);
|
||||
}
|
||||
|
||||
DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(GRE, Gre, gre, ETHERNET, \
|
||||
factory_iface->new_link = new_link; \
|
||||
NM_DEVICE_FACTORY_DEFINE_INTERNAL (GRE, Gre, gre,
|
||||
NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_GRE, NM_LINK_TYPE_GRETAP),
|
||||
factory_iface->new_link = new_link;
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -293,16 +293,13 @@ nm_device_infiniband_class_init (NMDeviceInfinibandClass *klass)
|
|||
#define NM_INFINIBAND_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_INFINIBAND_FACTORY, NMInfinibandFactory))
|
||||
|
||||
static NMDevice *
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error)
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error)
|
||||
{
|
||||
if (plink->type == NM_LINK_TYPE_INFINIBAND) {
|
||||
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_INFINIBAND,
|
||||
NM_DEVICE_PLATFORM_DEVICE, plink,
|
||||
NM_DEVICE_TYPE_DESC, "InfiniBand",
|
||||
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_INFINIBAND,
|
||||
NULL);
|
||||
}
|
||||
return NULL;
|
||||
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_INFINIBAND,
|
||||
NM_DEVICE_PLATFORM_DEVICE, plink,
|
||||
NM_DEVICE_TYPE_DESC, "InfiniBand",
|
||||
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_INFINIBAND,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static NMDevice *
|
||||
|
|
@ -315,23 +312,27 @@ create_virtual_device_for_connection (NMDeviceFactory *factory,
|
|||
int p_key, parent_ifindex;
|
||||
const char *iface;
|
||||
|
||||
if (!nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME))
|
||||
if (!NM_IS_DEVICE_INFINIBAND (parent)) {
|
||||
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
|
||||
"Parent interface %s must be an InfiniBand interface",
|
||||
nm_device_get_iface (parent));
|
||||
return NULL;
|
||||
|
||||
g_return_val_if_fail (NM_IS_DEVICE_INFINIBAND (parent), NULL);
|
||||
}
|
||||
|
||||
s_infiniband = nm_connection_get_setting_infiniband (connection);
|
||||
|
||||
iface = nm_setting_infiniband_get_virtual_interface_name (s_infiniband);
|
||||
g_return_val_if_fail (iface != NULL, NULL);
|
||||
g_assert (iface);
|
||||
|
||||
parent_ifindex = nm_device_get_ifindex (parent);
|
||||
p_key = nm_setting_infiniband_get_p_key (s_infiniband);
|
||||
|
||||
if ( !nm_platform_infiniband_partition_add (NM_PLATFORM_GET, parent_ifindex, p_key)
|
||||
if ( !nm_platform_infiniband_partition_add (NM_PLATFORM_GET, parent_ifindex, p_key, NULL)
|
||||
&& nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) {
|
||||
nm_log_warn (LOGD_DEVICE | LOGD_INFINIBAND, "(%s): failed to add InfiniBand P_Key interface for '%s': %s",
|
||||
iface, nm_connection_get_id (connection),
|
||||
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
|
||||
"Failed to create InfiniBand P_Key interface '%s' for '%s': %s",
|
||||
iface,
|
||||
nm_connection_get_id (connection),
|
||||
nm_platform_get_error_msg (NM_PLATFORM_GET));
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -344,8 +345,42 @@ create_virtual_device_for_connection (NMDeviceFactory *factory,
|
|||
NULL);
|
||||
}
|
||||
|
||||
DEFINE_DEVICE_FACTORY_INTERNAL(INFINIBAND, Infiniband, infiniband, \
|
||||
factory_iface->new_link = new_link; \
|
||||
static const char *
|
||||
get_connection_parent (NMDeviceFactory *factory, NMConnection *connection)
|
||||
{
|
||||
NMSettingInfiniband *s_infiniband;
|
||||
|
||||
g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME), NULL);
|
||||
|
||||
s_infiniband = nm_connection_get_setting_infiniband (connection);
|
||||
g_assert (s_infiniband);
|
||||
|
||||
return nm_setting_infiniband_get_parent (s_infiniband);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_virtual_iface_name (NMDeviceFactory *factory,
|
||||
NMConnection *connection,
|
||||
const char *parent_iface)
|
||||
{
|
||||
NMSettingInfiniband *s_infiniband;
|
||||
|
||||
g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME), NULL);
|
||||
|
||||
s_infiniband = nm_connection_get_setting_infiniband (connection);
|
||||
g_assert (s_infiniband);
|
||||
|
||||
g_return_val_if_fail (g_strcmp0 (parent_iface, nm_setting_infiniband_get_parent (s_infiniband)) == 0, NULL);
|
||||
|
||||
return g_strdup (nm_setting_infiniband_get_virtual_interface_name (s_infiniband));
|
||||
}
|
||||
|
||||
NM_DEVICE_FACTORY_DEFINE_INTERNAL (INFINIBAND, Infiniband, infiniband,
|
||||
NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_INFINIBAND)
|
||||
NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_INFINIBAND_SETTING_NAME),
|
||||
factory_iface->new_link = new_link;
|
||||
factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection;
|
||||
factory_iface->get_connection_parent = get_connection_parent;
|
||||
factory_iface->get_virtual_iface_name = get_virtual_iface_name;
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -175,19 +175,17 @@ nm_device_macvlan_class_init (NMDeviceMacvlanClass *klass)
|
|||
#define NM_MACVLAN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MACVLAN_FACTORY, NMMacvlanFactory))
|
||||
|
||||
static NMDevice *
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error)
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error)
|
||||
{
|
||||
if (plink->type == NM_LINK_TYPE_MACVLAN || plink->type == NM_LINK_TYPE_MACVTAP) {
|
||||
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_MACVLAN,
|
||||
NM_DEVICE_PLATFORM_DEVICE, plink,
|
||||
NM_DEVICE_TYPE_DESC, "Macvlan",
|
||||
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC,
|
||||
NULL);
|
||||
}
|
||||
return NULL;
|
||||
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_MACVLAN,
|
||||
NM_DEVICE_PLATFORM_DEVICE, plink,
|
||||
NM_DEVICE_TYPE_DESC, "Macvlan",
|
||||
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC,
|
||||
NULL);
|
||||
}
|
||||
|
||||
DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(MACVLAN, Macvlan, macvlan, ETHERNET, \
|
||||
factory_iface->new_link = new_link; \
|
||||
NM_DEVICE_FACTORY_DEFINE_INTERNAL (MACVLAN, Macvlan, macvlan,
|
||||
NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVTAP),
|
||||
factory_iface->new_link = new_link;
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ nm_device_tun_class_init (NMDeviceTunClass *klass)
|
|||
#define NM_TUN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_TUN_FACTORY, NMTunFactory))
|
||||
|
||||
static NMDevice *
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error)
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error)
|
||||
{
|
||||
const char *mode = NULL;
|
||||
|
||||
|
|
@ -278,8 +278,10 @@ new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error)
|
|||
mode = "tun";
|
||||
else if (plink->type == NM_LINK_TYPE_TAP)
|
||||
mode = "tap";
|
||||
else
|
||||
return NULL;
|
||||
else {
|
||||
g_warn_if_reached ();
|
||||
mode = "unknown";
|
||||
}
|
||||
|
||||
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_TUN,
|
||||
NM_DEVICE_PLATFORM_DEVICE, plink,
|
||||
|
|
@ -289,7 +291,8 @@ new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error)
|
|||
NULL);
|
||||
}
|
||||
|
||||
DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(TUN, Tun, tun, GENERIC, \
|
||||
factory_iface->new_link = new_link; \
|
||||
NM_DEVICE_FACTORY_DEFINE_INTERNAL (TUN, Tun, tun,
|
||||
NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_TUN, NM_LINK_TYPE_TAP),
|
||||
factory_iface->new_link = new_link;
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -177,19 +177,17 @@ nm_device_veth_class_init (NMDeviceVethClass *klass)
|
|||
#define NM_VETH_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VETH_FACTORY, NMVethFactory))
|
||||
|
||||
static NMDevice *
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error)
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error)
|
||||
{
|
||||
if (plink->type == NM_LINK_TYPE_VETH) {
|
||||
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_VETH,
|
||||
NM_DEVICE_PLATFORM_DEVICE, plink,
|
||||
NM_DEVICE_TYPE_DESC, "Veth",
|
||||
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_ETHERNET,
|
||||
NULL);
|
||||
}
|
||||
return NULL;
|
||||
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_VETH,
|
||||
NM_DEVICE_PLATFORM_DEVICE, plink,
|
||||
NM_DEVICE_TYPE_DESC, "Veth",
|
||||
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_ETHERNET,
|
||||
NULL);
|
||||
}
|
||||
|
||||
DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(VETH, Veth, veth, ETHERNET, \
|
||||
factory_iface->new_link = new_link; \
|
||||
NM_DEVICE_FACTORY_DEFINE_INTERNAL (VETH, Veth, veth,
|
||||
NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_VETH),
|
||||
factory_iface->new_link = new_link;
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@
|
|||
#include "nm-device-factory.h"
|
||||
#include "nm-manager.h"
|
||||
#include "nm-core-internal.h"
|
||||
#include "gsystem-local-alloc.h"
|
||||
|
||||
#include "nm-device-vlan-glue.h"
|
||||
|
||||
|
|
@ -51,8 +52,6 @@ G_DEFINE_TYPE (NMDeviceVlan, nm_device_vlan, NM_TYPE_DEVICE)
|
|||
#define NM_DEVICE_VLAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_VLAN, NMDeviceVlanPrivate))
|
||||
|
||||
typedef struct {
|
||||
char *initial_hw_addr;
|
||||
|
||||
gboolean disposed;
|
||||
gboolean invalid;
|
||||
|
||||
|
|
@ -74,16 +73,6 @@ enum {
|
|||
|
||||
/******************************************************************/
|
||||
|
||||
static void
|
||||
update_initial_hw_address (NMDevice *dev)
|
||||
{
|
||||
NMDeviceVlan *self = NM_DEVICE_VLAN (dev);
|
||||
NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);
|
||||
|
||||
priv->initial_hw_addr = g_strdup (nm_device_get_hw_address (dev));
|
||||
_LOGD (LOGD_DEVICE | LOGD_VLAN, "read initial MAC address %s", priv->initial_hw_addr);
|
||||
}
|
||||
|
||||
static NMDeviceCapabilities
|
||||
get_generic_capabilities (NMDevice *dev)
|
||||
{
|
||||
|
|
@ -107,6 +96,104 @@ bring_up (NMDevice *dev, gboolean *no_firmware)
|
|||
|
||||
/******************************************************************/
|
||||
|
||||
static gboolean
|
||||
is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags)
|
||||
{
|
||||
if (!NM_DEVICE_VLAN_GET_PRIVATE (device)->parent)
|
||||
return FALSE;
|
||||
|
||||
return NM_DEVICE_CLASS (nm_device_vlan_parent_class)->is_available (device, flags);
|
||||
}
|
||||
|
||||
static void
|
||||
parent_state_changed (NMDevice *parent,
|
||||
NMDeviceState new_state,
|
||||
NMDeviceState old_state,
|
||||
NMDeviceStateReason reason,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMDeviceVlan *self = NM_DEVICE_VLAN (user_data);
|
||||
|
||||
/* We'll react to our own carrier state notifications. Ignore the parent's. */
|
||||
if (reason == NM_DEVICE_STATE_REASON_CARRIER)
|
||||
return;
|
||||
|
||||
nm_device_set_unmanaged (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent), reason);
|
||||
}
|
||||
|
||||
static void
|
||||
nm_device_vlan_set_parent (NMDeviceVlan *self, NMDevice *parent, gboolean construct)
|
||||
{
|
||||
NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);
|
||||
NMDevice *device = NM_DEVICE (self);
|
||||
|
||||
if (parent == priv->parent)
|
||||
return;
|
||||
|
||||
if (priv->parent_state_id) {
|
||||
g_signal_handler_disconnect (priv->parent, priv->parent_state_id);
|
||||
priv->parent_state_id = 0;
|
||||
}
|
||||
g_clear_object (&priv->parent);
|
||||
|
||||
if (parent) {
|
||||
priv->parent = g_object_ref (parent);
|
||||
priv->parent_state_id = g_signal_connect (priv->parent,
|
||||
"state-changed",
|
||||
G_CALLBACK (parent_state_changed),
|
||||
device);
|
||||
|
||||
/* Set parent-dependent unmanaged flag */
|
||||
if (construct) {
|
||||
nm_device_set_initial_unmanaged_flag (device,
|
||||
NM_UNMANAGED_PARENT,
|
||||
!nm_device_get_managed (parent));
|
||||
} else {
|
||||
nm_device_set_unmanaged (device,
|
||||
NM_UNMANAGED_PARENT,
|
||||
!nm_device_get_managed (parent),
|
||||
NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
/* Recheck availability now that the parent has changed */
|
||||
nm_device_queue_recheck_available (self,
|
||||
NM_DEVICE_STATE_REASON_PARENT_CHANGED,
|
||||
NM_DEVICE_STATE_REASON_PARENT_CHANGED);
|
||||
g_object_notify (G_OBJECT (device), NM_DEVICE_VLAN_PARENT);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
component_added (NMDevice *device, GObject *component)
|
||||
{
|
||||
NMDeviceVlan *self = NM_DEVICE_VLAN (device);
|
||||
NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);
|
||||
NMDevice *added_device;
|
||||
int parent_ifindex = -1;
|
||||
|
||||
if (priv->parent)
|
||||
return FALSE;
|
||||
|
||||
if (!NM_IS_DEVICE (component))
|
||||
return FALSE;
|
||||
added_device = NM_DEVICE (component);
|
||||
|
||||
if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, nm_device_get_ifindex (device), &parent_ifindex, NULL)) {
|
||||
_LOGW (LOGD_VLAN, "failed to get VLAN interface info while checking added component.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (nm_device_get_ifindex (added_device) != parent_ifindex)
|
||||
return FALSE;
|
||||
|
||||
nm_device_vlan_set_parent (self, added_device, FALSE);
|
||||
|
||||
/* Don't claim parent exclusively */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
static gboolean
|
||||
match_parent (NMDeviceVlan *self, const char *parent)
|
||||
{
|
||||
|
|
@ -114,6 +201,9 @@ match_parent (NMDeviceVlan *self, const char *parent)
|
|||
|
||||
g_return_val_if_fail (parent != NULL, FALSE);
|
||||
|
||||
if (!priv->parent)
|
||||
return FALSE;
|
||||
|
||||
if (nm_utils_is_uuid (parent)) {
|
||||
NMActRequest *parent_req;
|
||||
NMConnection *parent_connection;
|
||||
|
|
@ -239,32 +329,6 @@ complete_connection (NMDevice *device,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static void parent_state_changed (NMDevice *parent, NMDeviceState new_state,
|
||||
NMDeviceState old_state,
|
||||
NMDeviceStateReason reason,
|
||||
gpointer user_data);
|
||||
|
||||
static void
|
||||
nm_device_vlan_set_parent (NMDeviceVlan *device, NMDevice *parent)
|
||||
{
|
||||
NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device);
|
||||
|
||||
if (priv->parent_state_id) {
|
||||
g_signal_handler_disconnect (priv->parent, priv->parent_state_id);
|
||||
priv->parent_state_id = 0;
|
||||
}
|
||||
g_clear_object (&priv->parent);
|
||||
|
||||
if (parent) {
|
||||
priv->parent = g_object_ref (parent);
|
||||
priv->parent_state_id = g_signal_connect (priv->parent,
|
||||
"state-changed",
|
||||
G_CALLBACK (parent_state_changed),
|
||||
device);
|
||||
}
|
||||
g_object_notify (G_OBJECT (device), NM_DEVICE_VLAN_PARENT);
|
||||
}
|
||||
|
||||
static void
|
||||
update_connection (NMDevice *device, NMConnection *connection)
|
||||
{
|
||||
|
|
@ -296,8 +360,7 @@ update_connection (NMDevice *device, NMConnection *connection)
|
|||
|
||||
parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex);
|
||||
g_assert (parent);
|
||||
if (priv->parent != parent)
|
||||
nm_device_vlan_set_parent (NM_DEVICE_VLAN (device), parent);
|
||||
nm_device_vlan_set_parent (NM_DEVICE_VLAN (device), parent, FALSE);
|
||||
|
||||
/* Update parent in the connection; default to parent's interface name */
|
||||
new_parent = nm_device_get_iface (parent);
|
||||
|
|
@ -386,30 +449,9 @@ ip4_config_pre_commit (NMDevice *device, NMIP4Config *config)
|
|||
static void
|
||||
deactivate (NMDevice *device)
|
||||
{
|
||||
NMDeviceVlan *self = NM_DEVICE_VLAN (device);
|
||||
NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);
|
||||
|
||||
/* Reset MAC address back to initial address */
|
||||
if (priv->initial_hw_addr)
|
||||
nm_device_set_hw_addr (device, priv->initial_hw_addr, "reset", LOGD_VLAN);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
static void
|
||||
parent_state_changed (NMDevice *parent,
|
||||
NMDeviceState new_state,
|
||||
NMDeviceState old_state,
|
||||
NMDeviceStateReason reason,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMDeviceVlan *self = NM_DEVICE_VLAN (user_data);
|
||||
|
||||
/* We'll react to our own carrier state notifications. Ignore the parent's. */
|
||||
if (reason == NM_DEVICE_STATE_REASON_CARRIER)
|
||||
return;
|
||||
|
||||
nm_device_set_unmanaged (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent), reason);
|
||||
if (nm_device_get_initial_hw_address (device))
|
||||
nm_device_set_hw_addr (device, nm_device_get_initial_hw_address (device), "reset", LOGD_VLAN);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
|
@ -431,12 +473,6 @@ constructed (GObject *object)
|
|||
if (G_OBJECT_CLASS (nm_device_vlan_parent_class)->constructed)
|
||||
G_OBJECT_CLASS (nm_device_vlan_parent_class)->constructed (object);
|
||||
|
||||
if (!priv->parent) {
|
||||
_LOGE (LOGD_VLAN, "no parent specified.");
|
||||
priv->invalid = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
itype = nm_platform_link_get_type (NM_PLATFORM_GET, ifindex);
|
||||
if (itype != NM_LINK_TYPE_VLAN) {
|
||||
_LOGE (LOGD_VLAN, "failed to get VLAN interface type.");
|
||||
|
|
@ -450,18 +486,27 @@ constructed (GObject *object)
|
|||
return;
|
||||
}
|
||||
|
||||
if ( parent_ifindex < 0
|
||||
|| parent_ifindex != nm_device_get_ip_ifindex (priv->parent)
|
||||
|| vlan_id < 0) {
|
||||
if (parent_ifindex < 0 || vlan_id < 0) {
|
||||
_LOGW (LOGD_VLAN, "VLAN parent ifindex (%d) or VLAN ID (%d) invalid.",
|
||||
parent_ifindex, priv->vlan_id);
|
||||
priv->invalid = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (priv->parent && parent_ifindex != nm_device_get_ip_ifindex (priv->parent)) {
|
||||
_LOGW (LOGD_VLAN, "VLAN parent %s (%d) and parent ifindex %d don't match.",
|
||||
nm_device_get_iface (priv->parent),
|
||||
nm_device_get_ifindex (priv->parent),
|
||||
parent_ifindex);
|
||||
priv->invalid = TRUE;
|
||||
return;
|
||||
}
|
||||
|
||||
priv->vlan_id = vlan_id;
|
||||
_LOGI (LOGD_HW | LOGD_VLAN, "VLAN ID %d with parent %s",
|
||||
priv->vlan_id, nm_device_get_iface (priv->parent));
|
||||
_LOGI (LOGD_HW | LOGD_VLAN, "VLAN ID %d with parent %s (%d)",
|
||||
priv->vlan_id,
|
||||
priv->parent ? nm_device_get_iface (priv->parent) : "unknown",
|
||||
parent_ifindex);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -494,7 +539,7 @@ set_property (GObject *object, guint prop_id,
|
|||
|
||||
switch (prop_id) {
|
||||
case PROP_INT_PARENT_DEVICE:
|
||||
nm_device_vlan_set_parent (NM_DEVICE_VLAN (object), g_value_get_object (value));
|
||||
nm_device_vlan_set_parent (NM_DEVICE_VLAN (object), g_value_get_object (value), TRUE);
|
||||
break;
|
||||
case PROP_VLAN_ID:
|
||||
priv->vlan_id = g_value_get_uint (value);
|
||||
|
|
@ -517,22 +562,11 @@ dispose (GObject *object)
|
|||
}
|
||||
priv->disposed = TRUE;
|
||||
|
||||
nm_device_vlan_set_parent (self, NULL);
|
||||
nm_device_vlan_set_parent (self, NULL, FALSE);
|
||||
|
||||
G_OBJECT_CLASS (nm_device_vlan_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
finalize (GObject *object)
|
||||
{
|
||||
NMDeviceVlan *self = NM_DEVICE_VLAN (object);
|
||||
NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);
|
||||
|
||||
g_free (priv->initial_hw_addr);
|
||||
|
||||
G_OBJECT_CLASS (nm_device_vlan_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
nm_device_vlan_class_init (NMDeviceVlanClass *klass)
|
||||
{
|
||||
|
|
@ -548,14 +582,14 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass)
|
|||
object_class->get_property = get_property;
|
||||
object_class->set_property = set_property;
|
||||
object_class->dispose = dispose;
|
||||
object_class->finalize = finalize;
|
||||
|
||||
parent_class->update_initial_hw_address = update_initial_hw_address;
|
||||
parent_class->get_generic_capabilities = get_generic_capabilities;
|
||||
parent_class->bring_up = bring_up;
|
||||
parent_class->act_stage1_prepare = act_stage1_prepare;
|
||||
parent_class->ip4_config_pre_commit = ip4_config_pre_commit;
|
||||
parent_class->deactivate = deactivate;
|
||||
parent_class->is_available = is_available;
|
||||
parent_class->component_added = component_added;
|
||||
|
||||
parent_class->check_connection_compatible = check_connection_compatible;
|
||||
parent_class->complete_connection = complete_connection;
|
||||
|
|
@ -594,30 +628,18 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass)
|
|||
#define NM_VLAN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VLAN_FACTORY, NMVlanFactory))
|
||||
|
||||
static NMDevice *
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error)
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error)
|
||||
{
|
||||
int parent_ifindex = -1;
|
||||
NMDevice *parent, *device;
|
||||
|
||||
if (plink->type != NM_LINK_TYPE_VLAN)
|
||||
return NULL;
|
||||
|
||||
/* Have to find the parent device */
|
||||
/* Find the parent device */
|
||||
if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, plink->ifindex, &parent_ifindex, NULL)) {
|
||||
nm_log_err (LOGD_HW, "(%s): failed to get VLAN parent ifindex", plink->name);
|
||||
g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
|
||||
"VLAN parent ifindex unknown");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex);
|
||||
if (!parent) {
|
||||
/* If udev signaled the VLAN interface before it signaled
|
||||
* the VLAN's parent at startup we may not know about the
|
||||
* parent device yet. But we'll find it on the second pass
|
||||
* from nm_manager_start().
|
||||
*/
|
||||
nm_log_dbg (LOGD_HW, "(%s): VLAN parent interface unknown", plink->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
device = (NMDevice *) g_object_new (NM_TYPE_DEVICE_VLAN,
|
||||
NM_DEVICE_PLATFORM_DEVICE, plink,
|
||||
|
|
@ -627,14 +649,12 @@ new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error)
|
|||
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_VLAN,
|
||||
NULL);
|
||||
if (NM_DEVICE_VLAN_GET_PRIVATE (device)->invalid) {
|
||||
g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
|
||||
"VLAN initialization failed");
|
||||
g_object_unref (device);
|
||||
device = NULL;
|
||||
}
|
||||
|
||||
/* Set initial parent-dependent unmanaged flag */
|
||||
if (device)
|
||||
nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_PARENT, !nm_device_get_managed (parent));
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
|
|
@ -646,15 +666,16 @@ create_virtual_device_for_connection (NMDeviceFactory *factory,
|
|||
{
|
||||
NMDevice *device;
|
||||
NMSettingVlan *s_vlan;
|
||||
char *iface;
|
||||
gs_free char *iface = NULL;
|
||||
|
||||
if (!nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME))
|
||||
if (!NM_IS_DEVICE (parent)) {
|
||||
g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
|
||||
"VLAN interfaces must have parents");
|
||||
return NULL;
|
||||
|
||||
g_return_val_if_fail (NM_IS_DEVICE (parent), NULL);
|
||||
}
|
||||
|
||||
s_vlan = nm_connection_get_setting_vlan (connection);
|
||||
g_return_val_if_fail (s_vlan != NULL, NULL);
|
||||
g_assert (s_vlan);
|
||||
|
||||
iface = g_strdup (nm_connection_get_interface_name (connection));
|
||||
if (!iface) {
|
||||
|
|
@ -666,11 +687,14 @@ create_virtual_device_for_connection (NMDeviceFactory *factory,
|
|||
iface,
|
||||
nm_device_get_ifindex (parent),
|
||||
nm_setting_vlan_get_id (s_vlan),
|
||||
nm_setting_vlan_get_flags (s_vlan))
|
||||
nm_setting_vlan_get_flags (s_vlan),
|
||||
NULL)
|
||||
&& nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) {
|
||||
nm_log_warn (LOGD_DEVICE | LOGD_VLAN, "(%s) failed to add VLAN interface for '%s'",
|
||||
iface, nm_connection_get_id (connection));
|
||||
g_free (iface);
|
||||
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
|
||||
"Failed to create VLAN interface '%s' for '%s': %s",
|
||||
iface,
|
||||
nm_connection_get_id (connection),
|
||||
nm_platform_get_error_msg (NM_PLATFORM_GET));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -681,21 +705,74 @@ create_virtual_device_for_connection (NMDeviceFactory *factory,
|
|||
NM_DEVICE_TYPE_DESC, "VLAN",
|
||||
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_VLAN,
|
||||
NULL);
|
||||
g_free (iface);
|
||||
if (NM_DEVICE_VLAN_GET_PRIVATE (device)->invalid) {
|
||||
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
|
||||
"Failed to create VLAN interface '%s' for '%s': initialization failed",
|
||||
iface, nm_connection_get_id (connection));
|
||||
g_object_unref (device);
|
||||
device = NULL;
|
||||
}
|
||||
|
||||
/* Set initial parent-dependent unmanaged flag */
|
||||
if (device)
|
||||
nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_PARENT, !nm_device_get_managed (parent));
|
||||
|
||||
return device;
|
||||
}
|
||||
|
||||
DEFINE_DEVICE_FACTORY_INTERNAL(VLAN, Vlan, vlan, \
|
||||
factory_iface->new_link = new_link; \
|
||||
static const char *
|
||||
get_connection_parent (NMDeviceFactory *factory, NMConnection *connection)
|
||||
{
|
||||
NMSettingVlan *s_vlan;
|
||||
NMSettingWired *s_wired;
|
||||
const char *parent = NULL;
|
||||
|
||||
g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME), NULL);
|
||||
|
||||
s_vlan = nm_connection_get_setting_vlan (connection);
|
||||
g_assert (s_vlan);
|
||||
|
||||
parent = nm_setting_vlan_get_parent (s_vlan);
|
||||
if (parent)
|
||||
return parent;
|
||||
|
||||
/* Try the hardware address from the VLAN connection's hardware setting */
|
||||
s_wired = nm_connection_get_setting_wired (connection);
|
||||
if (s_wired)
|
||||
return nm_setting_wired_get_mac_address (s_wired);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *
|
||||
get_virtual_iface_name (NMDeviceFactory *factory,
|
||||
NMConnection *connection,
|
||||
const char *parent_iface)
|
||||
{
|
||||
const char *ifname;
|
||||
NMSettingVlan *s_vlan;
|
||||
|
||||
g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME), NULL);
|
||||
|
||||
s_vlan = nm_connection_get_setting_vlan (connection);
|
||||
g_assert (s_vlan);
|
||||
|
||||
if (!parent_iface)
|
||||
return NULL;
|
||||
|
||||
ifname = nm_connection_get_interface_name (connection);
|
||||
if (ifname)
|
||||
return g_strdup (ifname);
|
||||
|
||||
/* If the connection doesn't specify the interface name for the VLAN
|
||||
* device, we create one for it using the VLAN ID and the parent
|
||||
* interface's name.
|
||||
*/
|
||||
return nm_utils_new_vlan_name (parent_iface, nm_setting_vlan_get_id (s_vlan));
|
||||
}
|
||||
|
||||
NM_DEVICE_FACTORY_DEFINE_INTERNAL (VLAN, Vlan, vlan,
|
||||
NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_VLAN)
|
||||
NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_VLAN_SETTING_NAME),
|
||||
factory_iface->new_link = new_link;
|
||||
factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection;
|
||||
factory_iface->get_connection_parent = get_connection_parent;
|
||||
factory_iface->get_virtual_iface_name = get_virtual_iface_name;
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -353,19 +353,17 @@ nm_device_vxlan_class_init (NMDeviceVxlanClass *klass)
|
|||
#define NM_VXLAN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VXLAN_FACTORY, NMVxlanFactory))
|
||||
|
||||
static NMDevice *
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error)
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error)
|
||||
{
|
||||
if (plink->type == NM_LINK_TYPE_VXLAN) {
|
||||
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_VXLAN,
|
||||
NM_DEVICE_PLATFORM_DEVICE, plink,
|
||||
NM_DEVICE_TYPE_DESC, "Vxlan",
|
||||
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC,
|
||||
NULL);
|
||||
}
|
||||
return NULL;
|
||||
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_VXLAN,
|
||||
NM_DEVICE_PLATFORM_DEVICE, plink,
|
||||
NM_DEVICE_TYPE_DESC, "Vxlan",
|
||||
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC,
|
||||
NULL);
|
||||
}
|
||||
|
||||
DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(VXLAN, Vxlan, vxlan, GENERIC, \
|
||||
factory_iface->new_link = new_link; \
|
||||
NM_DEVICE_FACTORY_DEFINE_INTERNAL (VXLAN, Vxlan, vxlan,
|
||||
NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_VXLAN),
|
||||
factory_iface->new_link = new_link;
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -28,8 +28,6 @@
|
|||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
|
|
@ -203,6 +201,8 @@ typedef struct {
|
|||
GHashTable * available_connections;
|
||||
char * hw_addr;
|
||||
guint hw_addr_len;
|
||||
char * perm_hw_addr;
|
||||
char * initial_hw_addr;
|
||||
char * physical_port_id;
|
||||
guint dev_id;
|
||||
|
||||
|
|
@ -5891,14 +5891,20 @@ impl_device_delete (NMDevice *self, DBusGMethodInvocation *context)
|
|||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
_device_activate (NMDevice *self, NMActRequest *req)
|
||||
{
|
||||
NMDevicePrivate *priv;
|
||||
NMConnection *connection;
|
||||
|
||||
g_return_if_fail (NM_IS_DEVICE (self));
|
||||
g_return_if_fail (NM_IS_ACT_REQUEST (req));
|
||||
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
|
||||
g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE);
|
||||
|
||||
/* Ensure the activation request is still valid; the master may have
|
||||
* already failed in which case activation of this device should not proceed.
|
||||
*/
|
||||
if (nm_active_connection_get_state (NM_ACTIVE_CONNECTION (req)) >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING)
|
||||
return FALSE;
|
||||
|
||||
priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
|
||||
|
|
@ -5924,6 +5930,7 @@ _device_activate (NMDevice *self, NMActRequest *req)
|
|||
priv->act_request = g_object_ref (req);
|
||||
|
||||
nm_device_activate_schedule_stage1_device_prepare (self);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -6019,7 +6026,8 @@ nm_device_queue_activation (NMDevice *self, NMActRequest *req)
|
|||
|
||||
if (!priv->act_request && !must_queue) {
|
||||
/* Just activate immediately */
|
||||
_device_activate (self, req);
|
||||
if (!_device_activate (self, req))
|
||||
g_assert_not_reached ();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -8110,13 +8118,18 @@ _set_state_full (NMDevice *self,
|
|||
if ( priv->queued_act_request
|
||||
&& !priv->queued_act_request_is_waiting_for_carrier) {
|
||||
NMActRequest *queued_req;
|
||||
gboolean success;
|
||||
|
||||
queued_req = priv->queued_act_request;
|
||||
priv->queued_act_request = NULL;
|
||||
_device_activate (self, queued_req);
|
||||
success = _device_activate (self, queued_req);
|
||||
g_object_unref (queued_req);
|
||||
} else if ( old_state > NM_DEVICE_STATE_DISCONNECTED
|
||||
&& nm_device_get_default_unmanaged (self))
|
||||
if (success)
|
||||
break;
|
||||
/* fall through */
|
||||
}
|
||||
if ( old_state > NM_DEVICE_STATE_DISCONNECTED
|
||||
&& nm_device_get_default_unmanaged (self))
|
||||
nm_device_queue_state (self, NM_DEVICE_STATE_UNMANAGED, NM_DEVICE_STATE_REASON_NONE);
|
||||
break;
|
||||
case NM_DEVICE_STATE_ACTIVATED:
|
||||
|
|
@ -8397,6 +8410,22 @@ nm_device_set_hw_addr (NMDevice *self, const char *addr,
|
|||
return success;
|
||||
}
|
||||
|
||||
const char *
|
||||
nm_device_get_permanent_hw_address (NMDevice *self)
|
||||
{
|
||||
g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
|
||||
|
||||
return NM_DEVICE_GET_PRIVATE (self)->perm_hw_addr;
|
||||
}
|
||||
|
||||
const char *
|
||||
nm_device_get_initial_hw_address (NMDevice *self)
|
||||
{
|
||||
g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
|
||||
|
||||
return NM_DEVICE_GET_PRIVATE (self)->initial_hw_addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_device_spec_match_list:
|
||||
* @self: an #NMDevice
|
||||
|
|
@ -8491,46 +8520,6 @@ nm_device_init (NMDevice *self)
|
|||
priv->default_route.v6_is_assumed = TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get driver info from SIOCETHTOOL ioctl() for 'iface'
|
||||
* Returns driver and firmware versions to 'driver_version and' 'firmware_version'
|
||||
*/
|
||||
static gboolean
|
||||
device_get_driver_info (NMDevice *self, const char *iface, char **driver_version, char **firmware_version)
|
||||
{
|
||||
struct ethtool_drvinfo drvinfo;
|
||||
struct ifreq req;
|
||||
int fd;
|
||||
|
||||
fd = socket (PF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
_LOGW (LOGD_HW, "couldn't open control socket.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Get driver and firmware version info */
|
||||
memset (&drvinfo, 0, sizeof (drvinfo));
|
||||
memset (&req, 0, sizeof (struct ifreq));
|
||||
strncpy (req.ifr_name, iface, IFNAMSIZ);
|
||||
drvinfo.cmd = ETHTOOL_GDRVINFO;
|
||||
req.ifr_data = &drvinfo;
|
||||
|
||||
errno = 0;
|
||||
if (ioctl (fd, SIOCETHTOOL, &req) < 0) {
|
||||
_LOGD (LOGD_HW, "SIOCETHTOOL ioctl() failed: cmd=ETHTOOL_GDRVINFO, iface=%s, errno=%d",
|
||||
iface, errno);
|
||||
close (fd);
|
||||
return FALSE;
|
||||
}
|
||||
if (driver_version)
|
||||
*driver_version = g_strdup (drvinfo.version);
|
||||
if (firmware_version)
|
||||
*firmware_version = g_strdup (drvinfo.fw_version);
|
||||
|
||||
close (fd);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GObject*
|
||||
constructor (GType type,
|
||||
guint n_construct_params,
|
||||
|
|
@ -8566,10 +8555,13 @@ constructor (GType type,
|
|||
if (NM_DEVICE_GET_CLASS (self)->get_generic_capabilities)
|
||||
priv->capabilities |= NM_DEVICE_GET_CLASS (self)->get_generic_capabilities (self);
|
||||
|
||||
if (priv->ifindex <= 0 && !nm_device_has_capability (self, NM_DEVICE_CAP_IS_NON_KERNEL))
|
||||
_LOGW (LOGD_HW, "failed to look up interface index");
|
||||
|
||||
device_get_driver_info (self, priv->iface, &priv->driver_version, &priv->firmware_version);
|
||||
if (priv->ifindex > 0) {
|
||||
nm_platform_link_get_driver_info (NM_PLATFORM_GET,
|
||||
priv->ifindex,
|
||||
NULL,
|
||||
&priv->driver_version,
|
||||
&priv->firmware_version);
|
||||
}
|
||||
|
||||
/* Watch for external IP config changes */
|
||||
platform = nm_platform_get ();
|
||||
|
|
@ -8605,13 +8597,29 @@ constructed (GObject *object)
|
|||
|
||||
nm_device_update_hw_address (self);
|
||||
|
||||
if (NM_DEVICE_GET_CLASS (self)->update_permanent_hw_address)
|
||||
NM_DEVICE_GET_CLASS (self)->update_permanent_hw_address (self);
|
||||
if (priv->hw_addr_len) {
|
||||
priv->initial_hw_addr = g_strdup (priv->hw_addr);
|
||||
_LOGD (LOGD_DEVICE | LOGD_HW, "read initial MAC address %s", priv->initial_hw_addr);
|
||||
|
||||
if (NM_DEVICE_GET_CLASS (self)->update_initial_hw_address)
|
||||
NM_DEVICE_GET_CLASS (self)->update_initial_hw_address (self);
|
||||
if (priv->ifindex > 0) {
|
||||
guint8 buf[NM_UTILS_HWADDR_LEN_MAX];
|
||||
size_t len = 0;
|
||||
|
||||
/* Have to call update_initial_hw_address() before calling get_ignore_carrier() */
|
||||
if (nm_platform_link_get_permanent_address (NM_PLATFORM_GET, priv->ifindex, buf, &len)) {
|
||||
g_warn_if_fail (len == priv->hw_addr_len);
|
||||
priv->perm_hw_addr = nm_utils_hwaddr_ntoa (buf, priv->hw_addr_len);
|
||||
_LOGD (LOGD_DEVICE | LOGD_HW, "read permanent MAC address %s",
|
||||
priv->perm_hw_addr);
|
||||
} else {
|
||||
/* Fall back to current address */
|
||||
_LOGD (LOGD_HW | LOGD_ETHER, "unable to read permanent MAC address (error %d)",
|
||||
nm_platform_get_error (NM_PLATFORM_GET));
|
||||
priv->perm_hw_addr = g_strdup (priv->hw_addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Note: initial hardware address must be read before calling get_ignore_carrier() */
|
||||
if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) {
|
||||
NMConfig *config = nm_config_get ();
|
||||
|
||||
|
|
@ -8744,6 +8752,8 @@ finalize (GObject *object)
|
|||
_LOGD (LOGD_DEVICE, "finalize(): %s", G_OBJECT_TYPE_NAME (self));
|
||||
|
||||
g_free (priv->hw_addr);
|
||||
g_free (priv->perm_hw_addr);
|
||||
g_free (priv->initial_hw_addr);
|
||||
g_slist_free_full (priv->pending_actions, g_free);
|
||||
g_clear_pointer (&priv->physical_port_id, g_free);
|
||||
g_free (priv->udi);
|
||||
|
|
|
|||
|
|
@ -139,9 +139,6 @@ typedef struct {
|
|||
/* Carrier state (IFF_LOWER_UP) */
|
||||
void (*carrier_changed) (NMDevice *, gboolean carrier);
|
||||
|
||||
void (* update_permanent_hw_address) (NMDevice *self);
|
||||
void (* update_initial_hw_address) (NMDevice *self);
|
||||
|
||||
gboolean (* get_ip_iface_identifier) (NMDevice *self, NMUtilsIPv6IfaceId *out_iid);
|
||||
|
||||
NMDeviceCapabilities (* get_generic_capabilities) (NMDevice *self);
|
||||
|
|
@ -237,6 +234,21 @@ typedef struct {
|
|||
gboolean (* have_any_ready_slaves) (NMDevice *self,
|
||||
const GSList *slaves);
|
||||
|
||||
/**
|
||||
* component_added:
|
||||
* @self: the #NMDevice
|
||||
* @component: the component (device, modem, etc) which was added
|
||||
*
|
||||
* Notifies @self that a new component was added to the Manager. This
|
||||
* may include any kind of %GObject subclass, and the device is expected
|
||||
* to match only specific components they care about, like %NMModem objects
|
||||
* or %NMDevice objects.
|
||||
*
|
||||
* Returns: %TRUE if the component was claimed exclusively and no further
|
||||
* devices should be notified of the new component. %FALSE to indicate
|
||||
* that the component was not exclusively claimed and other devices should
|
||||
* be notified.
|
||||
*/
|
||||
gboolean (* component_added) (NMDevice *self, GObject *component);
|
||||
|
||||
gboolean (* owns_iface) (NMDevice *self, const char *iface);
|
||||
|
|
@ -272,7 +284,9 @@ int nm_device_get_priority (NMDevice *dev);
|
|||
guint32 nm_device_get_ip4_route_metric (NMDevice *dev);
|
||||
guint32 nm_device_get_ip6_route_metric (NMDevice *dev);
|
||||
|
||||
const char * nm_device_get_hw_address (NMDevice *dev);
|
||||
const char * nm_device_get_hw_address (NMDevice *dev);
|
||||
const char * nm_device_get_permanent_hw_address (NMDevice *dev);
|
||||
const char * nm_device_get_initial_hw_address (NMDevice *dev);
|
||||
|
||||
NMDhcp4Config * nm_device_get_dhcp4_config (NMDevice *dev);
|
||||
NMDhcp6Config * nm_device_get_dhcp6_config (NMDevice *dev);
|
||||
|
|
|
|||
|
|
@ -676,8 +676,6 @@ release_slave (NMDevice *device,
|
|||
NMDevice *
|
||||
nm_device_team_new (NMPlatformLink *platform_device)
|
||||
{
|
||||
g_return_val_if_fail (platform_device != NULL, NULL);
|
||||
|
||||
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_TEAM,
|
||||
NM_DEVICE_PLATFORM_DEVICE, platform_device,
|
||||
NM_DEVICE_DRIVER, "team",
|
||||
|
|
@ -690,20 +688,16 @@ nm_device_team_new (NMPlatformLink *platform_device)
|
|||
NMDevice *
|
||||
nm_device_team_new_for_connection (NMConnection *connection, GError **error)
|
||||
{
|
||||
const char *iface;
|
||||
const char *iface = nm_connection_get_interface_name (connection);
|
||||
|
||||
g_return_val_if_fail (connection != NULL, NULL);
|
||||
g_assert (iface);
|
||||
|
||||
iface = nm_connection_get_interface_name (connection);
|
||||
g_return_val_if_fail (iface != NULL, NULL);
|
||||
|
||||
if ( !nm_platform_team_add (NM_PLATFORM_GET, iface)
|
||||
if ( !nm_platform_team_add (NM_PLATFORM_GET, iface, NULL)
|
||||
&& nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) {
|
||||
g_set_error (error,
|
||||
NM_DEVICE_ERROR,
|
||||
NM_DEVICE_ERROR_CREATION_FAILED,
|
||||
"failed to create team master interface '%s' for connection '%s': %s",
|
||||
iface, nm_connection_get_id (connection),
|
||||
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
|
||||
"Failed to create team master interface '%s' for '%s': %s",
|
||||
iface,
|
||||
nm_connection_get_id (connection),
|
||||
nm_platform_get_error_msg (NM_PLATFORM_GET));
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,11 +48,9 @@ nm_device_factory_create (GError **error)
|
|||
/************************************************************************/
|
||||
|
||||
static NMDevice *
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error)
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error)
|
||||
{
|
||||
if (plink->type == NM_LINK_TYPE_TEAM)
|
||||
return nm_device_team_new (plink);
|
||||
return NULL;
|
||||
return nm_device_team_new (plink);
|
||||
}
|
||||
|
||||
static NMDevice *
|
||||
|
|
@ -61,16 +59,13 @@ create_virtual_device_for_connection (NMDeviceFactory *factory,
|
|||
NMDevice *parent,
|
||||
GError **error)
|
||||
{
|
||||
if (nm_connection_is_type (connection, NM_SETTING_TEAM_SETTING_NAME))
|
||||
return nm_device_team_new_for_connection (connection, error);
|
||||
return NULL;
|
||||
return nm_device_team_new_for_connection (connection, error);
|
||||
}
|
||||
|
||||
static NMDeviceType
|
||||
get_device_type (NMDeviceFactory *factory)
|
||||
{
|
||||
return NM_DEVICE_TYPE_TEAM;
|
||||
}
|
||||
NM_DEVICE_FACTORY_DECLARE_TYPES (
|
||||
NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_TEAM)
|
||||
NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_TEAM_SETTING_NAME)
|
||||
)
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
|
|
@ -84,7 +79,7 @@ device_factory_interface_init (NMDeviceFactory *factory_iface)
|
|||
{
|
||||
factory_iface->new_link = new_link;
|
||||
factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection;
|
||||
factory_iface->get_device_type = get_device_type;
|
||||
factory_iface->get_supported_types = get_supported_types;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -26,13 +26,7 @@
|
|||
#include <dbus/dbus.h>
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "nm-glib-compat.h"
|
||||
|
|
@ -117,9 +111,6 @@ enum {
|
|||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
struct _NMDeviceWifiPrivate {
|
||||
char * perm_hw_addr; /* Permanent MAC address */
|
||||
char * initial_hw_addr; /* Initial MAC address (as seen when NM starts) */
|
||||
|
||||
gint8 invalid_strength_counter;
|
||||
|
||||
GHashTable * aps;
|
||||
|
|
@ -533,8 +524,8 @@ deactivate (NMDevice *device)
|
|||
nm_platform_wifi_indicate_addressing_running (NM_PLATFORM_GET, ifindex, FALSE);
|
||||
|
||||
/* Reset MAC address back to initial address */
|
||||
if (priv->initial_hw_addr)
|
||||
nm_device_set_hw_addr (device, priv->initial_hw_addr, "reset", LOGD_WIFI);
|
||||
if (nm_device_get_initial_hw_address (device))
|
||||
nm_device_set_hw_addr (device, nm_device_get_initial_hw_address (device), "reset", LOGD_WIFI);
|
||||
|
||||
nm_platform_wifi_set_powersave (NM_PLATFORM_GET, ifindex, 0);
|
||||
|
||||
|
|
@ -600,6 +591,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
|
|||
const char * const *mac_blacklist;
|
||||
int i;
|
||||
const char *mode;
|
||||
const char *perm_hw_addr;
|
||||
|
||||
if (!NM_DEVICE_CLASS (nm_device_wifi_parent_class)->check_connection_compatible (device, connection))
|
||||
return FALSE;
|
||||
|
|
@ -614,21 +606,25 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
|
|||
if (!s_wireless)
|
||||
return FALSE;
|
||||
|
||||
perm_hw_addr = nm_device_get_permanent_hw_address (device);
|
||||
mac = nm_setting_wireless_get_mac_address (s_wireless);
|
||||
if (mac && !nm_utils_hwaddr_matches (mac, -1, priv->perm_hw_addr, -1))
|
||||
return FALSE;
|
||||
|
||||
/* Check for MAC address blacklist */
|
||||
mac_blacklist = nm_setting_wireless_get_mac_address_blacklist (s_wireless);
|
||||
for (i = 0; mac_blacklist[i]; i++) {
|
||||
if (!nm_utils_hwaddr_valid (mac_blacklist[i], ETH_ALEN)) {
|
||||
g_warn_if_reached ();
|
||||
if (perm_hw_addr) {
|
||||
if (mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1))
|
||||
return FALSE;
|
||||
|
||||
/* Check for MAC address blacklist */
|
||||
mac_blacklist = nm_setting_wireless_get_mac_address_blacklist (s_wireless);
|
||||
for (i = 0; mac_blacklist[i]; i++) {
|
||||
if (!nm_utils_hwaddr_valid (mac_blacklist[i], ETH_ALEN)) {
|
||||
g_warn_if_reached ();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, perm_hw_addr, -1))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, priv->perm_hw_addr, -1))
|
||||
return FALSE;
|
||||
}
|
||||
} else if (mac)
|
||||
return FALSE;
|
||||
|
||||
if (is_adhoc_wpa (connection))
|
||||
return FALSE;
|
||||
|
|
@ -767,7 +763,6 @@ complete_connection (NMDevice *device,
|
|||
GError **error)
|
||||
{
|
||||
NMDeviceWifi *self = NM_DEVICE_WIFI (device);
|
||||
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
|
||||
NMSettingWireless *s_wifi;
|
||||
NMSettingWirelessSecurity *s_wsec;
|
||||
NMSetting8021x *s_8021x;
|
||||
|
|
@ -778,6 +773,7 @@ complete_connection (NMDevice *device,
|
|||
GByteArray *tmp_ssid = NULL;
|
||||
GBytes *setting_ssid = NULL;
|
||||
gboolean hidden = FALSE;
|
||||
const char *perm_hw_addr;
|
||||
|
||||
s_wifi = nm_connection_get_setting_wireless (connection);
|
||||
s_wsec = nm_connection_get_setting_wireless_security (connection);
|
||||
|
|
@ -908,29 +904,31 @@ complete_connection (NMDevice *device,
|
|||
if (hidden)
|
||||
g_object_set (s_wifi, NM_SETTING_WIRELESS_HIDDEN, TRUE, NULL);
|
||||
|
||||
setting_mac = nm_setting_wireless_get_mac_address (s_wifi);
|
||||
if (setting_mac) {
|
||||
/* Make sure the setting MAC (if any) matches the device's permanent MAC */
|
||||
if (!nm_utils_hwaddr_matches (setting_mac, -1, priv->perm_hw_addr, -1)) {
|
||||
g_set_error_literal (error,
|
||||
NM_CONNECTION_ERROR,
|
||||
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
||||
_("connection does not match device"));
|
||||
g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_MAC_ADDRESS);
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
guint8 perm_hw_addr[ETH_ALEN];
|
||||
perm_hw_addr = nm_device_get_permanent_hw_address (device);
|
||||
if (perm_hw_addr) {
|
||||
setting_mac = nm_setting_wireless_get_mac_address (s_wifi);
|
||||
if (setting_mac) {
|
||||
/* Make sure the setting MAC (if any) matches the device's permanent MAC */
|
||||
if (!nm_utils_hwaddr_matches (setting_mac, -1, perm_hw_addr, -1)) {
|
||||
g_set_error_literal (error,
|
||||
NM_CONNECTION_ERROR,
|
||||
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
||||
_("connection does not match device"));
|
||||
g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_MAC_ADDRESS);
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
guint8 tmp[ETH_ALEN];
|
||||
|
||||
/* Lock the connection to this device by default if it uses a
|
||||
* permanent MAC address (ie not a 'locally administered' one)
|
||||
*/
|
||||
nm_utils_hwaddr_aton (priv->perm_hw_addr, perm_hw_addr, ETH_ALEN);
|
||||
if ( !(perm_hw_addr[0] & 0x02)
|
||||
&& !nm_utils_hwaddr_matches (perm_hw_addr, ETH_ALEN, NULL, ETH_ALEN)) {
|
||||
g_object_set (G_OBJECT (s_wifi),
|
||||
NM_SETTING_WIRELESS_MAC_ADDRESS, priv->perm_hw_addr,
|
||||
NULL);
|
||||
/* Lock the connection to this device by default if it uses a
|
||||
* permanent MAC address (ie not a 'locally administered' one)
|
||||
*/
|
||||
nm_utils_hwaddr_aton (perm_hw_addr, tmp, ETH_ALEN);
|
||||
if (!(tmp[0] & 0x02)) {
|
||||
g_object_set (G_OBJECT (s_wifi),
|
||||
NM_SETTING_WIRELESS_MAC_ADDRESS, perm_hw_addr,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2241,62 +2239,6 @@ error:
|
|||
|
||||
/****************************************************************************/
|
||||
|
||||
static void
|
||||
update_permanent_hw_address (NMDevice *device)
|
||||
{
|
||||
NMDeviceWifi *self = NM_DEVICE_WIFI (device);
|
||||
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
|
||||
struct ifreq req;
|
||||
struct ethtool_perm_addr *epaddr = NULL;
|
||||
int fd, ret, errsv;
|
||||
|
||||
g_return_if_fail (priv->perm_hw_addr == NULL);
|
||||
|
||||
fd = socket (PF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
_LOGE (LOGD_HW, "could not open control socket.");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get permanent MAC address */
|
||||
memset (&req, 0, sizeof (struct ifreq));
|
||||
strncpy (req.ifr_name, nm_device_get_iface (device), IFNAMSIZ);
|
||||
|
||||
epaddr = g_malloc0 (sizeof (struct ethtool_perm_addr) + ETH_ALEN);
|
||||
epaddr->cmd = ETHTOOL_GPERMADDR;
|
||||
epaddr->size = ETH_ALEN;
|
||||
req.ifr_data = (void *) epaddr;
|
||||
|
||||
errno = 0;
|
||||
ret = ioctl (fd, SIOCETHTOOL, &req);
|
||||
errsv = errno;
|
||||
if ((ret < 0) || !nm_ethernet_address_is_valid (epaddr->data, ETH_ALEN)) {
|
||||
_LOGD (LOGD_HW | LOGD_ETHER, "unable to read permanent MAC address (error %d)",
|
||||
errsv);
|
||||
/* Fall back to current address */
|
||||
nm_utils_hwaddr_aton (nm_device_get_hw_address (device), epaddr->data, ETH_ALEN);
|
||||
}
|
||||
|
||||
priv->perm_hw_addr = nm_utils_hwaddr_ntoa (epaddr->data, ETH_ALEN);
|
||||
|
||||
g_free (epaddr);
|
||||
close (fd);
|
||||
}
|
||||
|
||||
static void
|
||||
update_initial_hw_address (NMDevice *device)
|
||||
{
|
||||
NMDeviceWifi *self = NM_DEVICE_WIFI (device);
|
||||
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
|
||||
|
||||
/* This sets initial MAC address from current MAC address. It should only
|
||||
* be called from NMDevice constructor() to really get the initial address.
|
||||
*/
|
||||
priv->initial_hw_addr = g_strdup (nm_device_get_hw_address (device));
|
||||
|
||||
_LOGD (LOGD_DEVICE | LOGD_ETHER, "read initial MAC address %s", priv->initial_hw_addr);
|
||||
}
|
||||
|
||||
static NMActStageReturn
|
||||
act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
|
||||
{
|
||||
|
|
@ -2950,12 +2892,7 @@ dispose (GObject *object)
|
|||
static void
|
||||
finalize (GObject *object)
|
||||
{
|
||||
NMDeviceWifi *self = NM_DEVICE_WIFI (object);
|
||||
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
|
||||
|
||||
g_free (priv->perm_hw_addr);
|
||||
g_free (priv->initial_hw_addr);
|
||||
g_clear_pointer (&priv->aps, g_hash_table_unref);
|
||||
g_clear_pointer (&NM_DEVICE_WIFI_GET_PRIVATE (object)->aps, g_hash_table_unref);
|
||||
|
||||
G_OBJECT_CLASS (nm_device_wifi_parent_class)->finalize (object);
|
||||
}
|
||||
|
|
@ -2972,7 +2909,7 @@ get_property (GObject *object, guint prop_id,
|
|||
|
||||
switch (prop_id) {
|
||||
case PROP_PERM_HW_ADDRESS:
|
||||
g_value_set_string (value, priv->perm_hw_addr);
|
||||
g_value_set_string (value, nm_device_get_permanent_hw_address (NM_DEVICE (device)));
|
||||
break;
|
||||
case PROP_MODE:
|
||||
g_value_set_uint (value, priv->mode);
|
||||
|
|
@ -3028,8 +2965,6 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass)
|
|||
object_class->finalize = finalize;
|
||||
|
||||
parent_class->bring_up = bring_up;
|
||||
parent_class->update_permanent_hw_address = update_permanent_hw_address;
|
||||
parent_class->update_initial_hw_address = update_initial_hw_address;
|
||||
parent_class->can_auto_connect = can_auto_connect;
|
||||
parent_class->is_available = is_available;
|
||||
parent_class->check_connection_compatible = check_connection_compatible;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@
|
|||
#include <gmodule.h>
|
||||
|
||||
#include "nm-device-factory.h"
|
||||
#include "nm-setting-wireless.h"
|
||||
#include "nm-setting-olpc-mesh.h"
|
||||
#include "nm-device-wifi.h"
|
||||
#include "nm-device-olpc-mesh.h"
|
||||
#include "nm-settings-connection.h"
|
||||
|
|
@ -57,26 +59,25 @@ nm_device_factory_create (GError **error)
|
|||
/**************************************************************************/
|
||||
|
||||
static NMDevice *
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error)
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error)
|
||||
{
|
||||
if (plink->type == NM_LINK_TYPE_WIFI)
|
||||
return nm_device_wifi_new (plink);
|
||||
else if (plink->type == NM_LINK_TYPE_OLPC_MESH)
|
||||
return nm_device_olpc_mesh_new (plink);
|
||||
return NULL;
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static NMDeviceType
|
||||
get_device_type (NMDeviceFactory *factory)
|
||||
{
|
||||
return NM_DEVICE_TYPE_WIFI;
|
||||
}
|
||||
NM_DEVICE_FACTORY_DECLARE_TYPES (
|
||||
NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_WIFI, NM_LINK_TYPE_OLPC_MESH)
|
||||
NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_OLPC_MESH_SETTING_NAME)
|
||||
)
|
||||
|
||||
static void
|
||||
device_factory_interface_init (NMDeviceFactory *factory_iface)
|
||||
{
|
||||
factory_iface->new_link = new_link;
|
||||
factory_iface->get_device_type = get_device_type;
|
||||
factory_iface->get_supported_types = get_supported_types;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -25,9 +25,12 @@
|
|||
|
||||
#include "nm-device-factory.h"
|
||||
#include "nm-wwan-factory.h"
|
||||
#include "nm-setting-gsm.h"
|
||||
#include "nm-setting-cdma.h"
|
||||
#include "nm-modem-manager.h"
|
||||
#include "nm-device-modem.h"
|
||||
#include "nm-logging.h"
|
||||
#include "nm-platform.h"
|
||||
|
||||
static GType nm_wwan_factory_get_type (void);
|
||||
|
||||
|
|
@ -87,10 +90,17 @@ modem_added_cb (NMModemManager *manager,
|
|||
}
|
||||
|
||||
|
||||
static NMDeviceType
|
||||
get_device_type (NMDeviceFactory *factory)
|
||||
NM_DEVICE_FACTORY_DECLARE_TYPES (
|
||||
NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_WWAN_ETHERNET)
|
||||
NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_GSM_SETTING_NAME, NM_SETTING_CDMA_SETTING_NAME)
|
||||
)
|
||||
|
||||
static NMDevice *
|
||||
new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error)
|
||||
{
|
||||
return NM_DEVICE_TYPE_MODEM;
|
||||
g_warn_if_fail (plink->type == NM_LINK_TYPE_WWAN_ETHERNET);
|
||||
*out_ignore = TRUE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -115,7 +125,8 @@ nm_wwan_factory_init (NMWwanFactory *self)
|
|||
static void
|
||||
device_factory_interface_init (NMDeviceFactory *factory_iface)
|
||||
{
|
||||
factory_iface->get_device_type = get_device_type;
|
||||
factory_iface->get_supported_types = get_supported_types;
|
||||
factory_iface->new_link = new_link;
|
||||
factory_iface->start = start;
|
||||
}
|
||||
|
||||
|
|
|
|||
645
src/nm-manager.c
645
src/nm-manager.c
|
|
@ -26,8 +26,6 @@
|
|||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dbus/dbus-glib-lowlevel.h>
|
||||
#include <dbus/dbus-glib.h>
|
||||
#include <gio/gio.h>
|
||||
|
|
@ -129,8 +127,6 @@ static NMActiveConnection *_new_active_connection (NMManager *self,
|
|||
|
||||
static void policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data);
|
||||
|
||||
static NMDevice *find_device_by_ip_iface (NMManager *self, const gchar *iface);
|
||||
|
||||
static void rfkill_change (const char *desc, RfKillType rtype, gboolean enabled);
|
||||
|
||||
static gboolean find_master (NMManager *self,
|
||||
|
|
@ -178,9 +174,6 @@ typedef struct {
|
|||
gboolean prop_filter_added;
|
||||
NMRfkillManager *rfkill_mgr;
|
||||
|
||||
/* List of NMDeviceFactoryFunc pointers sorted in priority order */
|
||||
GSList *factories;
|
||||
|
||||
NMSettings *settings;
|
||||
char *hostname;
|
||||
|
||||
|
|
@ -520,6 +513,38 @@ nm_manager_get_device_by_ifindex (NMManager *manager, int ifindex)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static NMDevice *
|
||||
find_device_by_hw_addr (NMManager *manager, const char *hwaddr)
|
||||
{
|
||||
GSList *iter;
|
||||
const char *device_addr;
|
||||
|
||||
g_return_val_if_fail (hwaddr != NULL, NULL);
|
||||
|
||||
if (nm_utils_hwaddr_valid (hwaddr, -1)) {
|
||||
for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) {
|
||||
device_addr = nm_device_get_hw_address (NM_DEVICE (iter->data));
|
||||
if (device_addr && nm_utils_hwaddr_matches (hwaddr, -1, device_addr, -1))
|
||||
return NM_DEVICE (iter->data);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static NMDevice *
|
||||
find_device_by_ip_iface (NMManager *self, const gchar *iface)
|
||||
{
|
||||
GSList *iter;
|
||||
|
||||
g_return_val_if_fail (iface != NULL, NULL);
|
||||
|
||||
for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = g_slist_next (iter)) {
|
||||
if (g_strcmp0 (nm_device_get_ip_iface (NM_DEVICE (iter->data)), iface) == 0)
|
||||
return NM_DEVICE (iter->data);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
manager_sleeping (NMManager *self)
|
||||
{
|
||||
|
|
@ -843,109 +868,56 @@ nm_manager_get_state (NMManager *manager)
|
|||
return NM_MANAGER_GET_PRIVATE (manager)->state;
|
||||
}
|
||||
|
||||
/*******************************************************************/
|
||||
/* Settings stuff via NMSettings */
|
||||
/*******************************************************************/
|
||||
/***************************/
|
||||
|
||||
static NMDevice *
|
||||
get_device_from_hwaddr (NMManager *self, const char *setting_mac)
|
||||
find_parent_device_for_connection (NMManager *self, NMConnection *connection)
|
||||
{
|
||||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
||||
const char *device_mac;
|
||||
NMDeviceFactory *factory;
|
||||
const char *parent_name = NULL;
|
||||
NMConnection *parent_connection;
|
||||
NMDevice *parent, *first_compatible = NULL;
|
||||
GSList *iter;
|
||||
|
||||
if (!setting_mac)
|
||||
factory = nm_device_factory_manager_find_factory_for_connection (connection);
|
||||
if (!factory)
|
||||
return NULL;
|
||||
|
||||
for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
|
||||
NMDevice *device = iter->data;
|
||||
parent_name = nm_device_factory_get_connection_parent (factory, connection);
|
||||
if (!parent_name)
|
||||
return NULL;
|
||||
|
||||
device_mac = nm_device_get_hw_address (iter->data);
|
||||
if (!device_mac)
|
||||
continue;
|
||||
if (nm_utils_hwaddr_matches (setting_mac, -1, device_mac, -1))
|
||||
return device;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
/* Try as an interface name */
|
||||
parent = find_device_by_ip_iface (self, parent_name);
|
||||
if (parent)
|
||||
return parent;
|
||||
|
||||
static NMDevice *
|
||||
find_vlan_parent (NMManager *self,
|
||||
NMConnection *connection)
|
||||
{
|
||||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
||||
NMSettingVlan *s_vlan;
|
||||
NMSettingWired *s_wired;
|
||||
NMConnection *parent_connection;
|
||||
const char *parent_iface;
|
||||
NMDevice *parent = NULL;
|
||||
const char *setting_mac;
|
||||
GSList *iter;
|
||||
/* Maybe a hardware address */
|
||||
parent = find_device_by_hw_addr (self, parent_name);
|
||||
if (parent)
|
||||
return parent;
|
||||
|
||||
/* The 'parent' property could be given by an interface name, a
|
||||
* connection UUID, or the MAC address of an NMSettingWired.
|
||||
/* Maybe a connection UUID */
|
||||
parent_connection = (NMConnection *) nm_settings_get_connection_by_uuid (priv->settings, parent_name);
|
||||
if (!parent_connection)
|
||||
return NULL;
|
||||
|
||||
/* Check if the parent connection is currently activated or is comaptible
|
||||
* with some known device.
|
||||
*/
|
||||
s_vlan = nm_connection_get_setting_vlan (connection);
|
||||
g_return_val_if_fail (s_vlan != NULL, NULL);
|
||||
for (iter = priv->devices; iter; iter = iter->next) {
|
||||
NMDevice *candidate = iter->data;
|
||||
|
||||
s_wired = nm_connection_get_setting_wired (connection);
|
||||
setting_mac = s_wired ? nm_setting_wired_get_mac_address (s_wired) : NULL;
|
||||
if (nm_device_get_connection (candidate) == parent_connection)
|
||||
return candidate;
|
||||
|
||||
parent_iface = nm_setting_vlan_get_parent (s_vlan);
|
||||
if (parent_iface) {
|
||||
parent = find_device_by_ip_iface (self, parent_iface);
|
||||
if (parent)
|
||||
return parent;
|
||||
|
||||
if (nm_utils_is_uuid (parent_iface)) {
|
||||
/* Try as a connection UUID */
|
||||
parent_connection = (NMConnection *) nm_settings_get_connection_by_uuid (priv->settings, parent_iface);
|
||||
if (parent_connection) {
|
||||
/* Check if the parent connection is activated on some device already */
|
||||
for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
|
||||
NMActRequest *req;
|
||||
NMConnection *candidate;
|
||||
|
||||
req = nm_device_get_act_request (NM_DEVICE (iter->data));
|
||||
if (req) {
|
||||
candidate = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (req));
|
||||
if (candidate == parent_connection)
|
||||
return NM_DEVICE (iter->data);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check the hardware address of the parent connection */
|
||||
return get_device_from_hwaddr (self, setting_mac);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
if ( !first_compatible
|
||||
&& nm_device_check_connection_compatible (candidate, parent_connection))
|
||||
first_compatible = candidate;
|
||||
}
|
||||
|
||||
/* Try the hardware address from the VLAN connection's hardware setting */
|
||||
return get_device_from_hwaddr (self, setting_mac);
|
||||
}
|
||||
|
||||
static NMDevice *
|
||||
find_infiniband_parent (NMManager *self,
|
||||
NMConnection *connection)
|
||||
{
|
||||
NMSettingInfiniband *s_infiniband;
|
||||
const char *parent_iface;
|
||||
NMDevice *parent = NULL;
|
||||
const char *setting_mac;
|
||||
|
||||
s_infiniband = nm_connection_get_setting_infiniband (connection);
|
||||
g_return_val_if_fail (s_infiniband != NULL, NULL);
|
||||
|
||||
parent_iface = nm_setting_infiniband_get_parent (s_infiniband);
|
||||
if (parent_iface) {
|
||||
parent = find_device_by_ip_iface (self, parent_iface);
|
||||
if (parent)
|
||||
return parent;
|
||||
}
|
||||
|
||||
setting_mac = nm_setting_infiniband_get_mac_address (s_infiniband);
|
||||
return get_device_from_hwaddr (self, setting_mac);
|
||||
return first_compatible;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -953,86 +925,69 @@ find_infiniband_parent (NMManager *self,
|
|||
* @self: the #NMManager
|
||||
* @connection: the #NMConnection representing a virtual interface
|
||||
* @out_parent: on success, the parent device if any
|
||||
* @error: an error if determining the virtual interface name failed
|
||||
*
|
||||
* Given @connection, returns the interface name that the connection
|
||||
* would represent. If the interface name is not given by the connection,
|
||||
* this may require constructing it based on information in the connection
|
||||
* and existing network interfaces.
|
||||
* would represent if it is a virtual connection. %NULL is returned and
|
||||
* @error is set if the connection is not virtual, or if the name could
|
||||
* not be determined.
|
||||
*
|
||||
* Returns: the expected interface name (caller takes ownership), or %NULL
|
||||
*/
|
||||
static char *
|
||||
get_virtual_iface_name (NMManager *self,
|
||||
NMConnection *connection,
|
||||
NMDevice **out_parent)
|
||||
NMDevice **out_parent,
|
||||
GError **error)
|
||||
{
|
||||
NMDeviceFactory *factory;
|
||||
char *iface = NULL;
|
||||
NMDevice *parent = NULL;
|
||||
const char *ifname;
|
||||
|
||||
if (out_parent)
|
||||
*out_parent = NULL;
|
||||
|
||||
if (!nm_connection_is_virtual (connection))
|
||||
if (!nm_connection_is_virtual (connection)) {
|
||||
g_set_error (error,
|
||||
NM_MANAGER_ERROR,
|
||||
NM_MANAGER_ERROR_FAILED,
|
||||
"NetworkManager plugin for '%s' unavailable",
|
||||
nm_connection_get_connection_type (connection));
|
||||
return NULL;
|
||||
|
||||
ifname = nm_connection_get_interface_name (connection);
|
||||
|
||||
if (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME)) {
|
||||
NMSettingVlan *s_vlan;
|
||||
char *vname;
|
||||
|
||||
s_vlan = nm_connection_get_setting_vlan (connection);
|
||||
g_return_val_if_fail (s_vlan != NULL, NULL);
|
||||
|
||||
parent = find_vlan_parent (self, connection);
|
||||
if (!parent)
|
||||
return NULL;
|
||||
|
||||
if (!nm_device_supports_vlans (parent)) {
|
||||
nm_log_warn (LOGD_DEVICE, "(%s): No support for VLANs on interface %s of type %s",
|
||||
ifname ? ifname : nm_connection_get_id (connection),
|
||||
nm_device_get_ip_iface (parent),
|
||||
nm_device_get_type_desc (parent));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* If the connection doesn't specify the interface name for the VLAN
|
||||
* device, we create one for it using the VLAN ID and the parent
|
||||
* interface's name.
|
||||
*/
|
||||
if (ifname)
|
||||
vname = g_strdup (ifname);
|
||||
else {
|
||||
vname = nm_utils_new_vlan_name (nm_device_get_ip_iface (parent),
|
||||
nm_setting_vlan_get_id (s_vlan));
|
||||
}
|
||||
if (out_parent)
|
||||
*out_parent = parent;
|
||||
return vname;
|
||||
}
|
||||
|
||||
if (nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME)) {
|
||||
NMSettingInfiniband *s_infiniband;
|
||||
|
||||
parent = find_infiniband_parent (self, connection);
|
||||
if (!parent)
|
||||
return NULL;
|
||||
|
||||
s_infiniband = nm_connection_get_setting_infiniband (connection);
|
||||
if (out_parent)
|
||||
*out_parent = parent;
|
||||
return g_strdup (nm_setting_infiniband_get_virtual_interface_name (s_infiniband));
|
||||
factory = nm_device_factory_manager_find_factory_for_connection (connection);
|
||||
if (!factory) {
|
||||
nm_log_warn (LOGD_DEVICE, "(%s) NetworkManager plugin for '%s' unavailable",
|
||||
nm_connection_get_id (connection),
|
||||
nm_connection_get_connection_type (connection));
|
||||
g_set_error (error,
|
||||
NM_MANAGER_ERROR,
|
||||
NM_MANAGER_ERROR_FAILED,
|
||||
"NetworkManager plugin for '%s' unavailable",
|
||||
nm_connection_get_connection_type (connection));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* For any other virtual connection, NMSettingConnection:interface-name is
|
||||
* the virtual device name.
|
||||
*/
|
||||
g_return_val_if_fail (ifname != NULL, NULL);
|
||||
return g_strdup (ifname);
|
||||
parent = find_parent_device_for_connection (self, connection);
|
||||
iface = nm_device_factory_get_virtual_iface_name (factory,
|
||||
connection,
|
||||
parent ? nm_device_get_ip_iface (parent) : NULL);
|
||||
if (!iface) {
|
||||
nm_log_warn (LOGD_DEVICE, "(%s) failed to determine virtual interface name",
|
||||
nm_connection_get_id (connection));
|
||||
g_set_error_literal (error,
|
||||
NM_MANAGER_ERROR,
|
||||
NM_MANAGER_ERROR_UNKNOWN_DEVICE,
|
||||
"failed to determine virtual interface name");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (out_parent)
|
||||
*out_parent = parent;
|
||||
return iface;
|
||||
}
|
||||
|
||||
/***************************/
|
||||
|
||||
/**
|
||||
* system_create_virtual_device:
|
||||
* @self: the #NMManager
|
||||
|
|
@ -1048,7 +1003,7 @@ static NMDevice *
|
|||
system_create_virtual_device (NMManager *self, NMConnection *connection, GError **error)
|
||||
{
|
||||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
||||
GError *local_err = NULL;
|
||||
NMDeviceFactory *factory;
|
||||
GSList *iter;
|
||||
char *iface = NULL;
|
||||
NMDevice *device = NULL, *parent = NULL;
|
||||
|
|
@ -1058,16 +1013,9 @@ system_create_virtual_device (NMManager *self, NMConnection *connection, GError
|
|||
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
|
||||
|
||||
iface = get_virtual_iface_name (self, connection, &parent);
|
||||
if (!iface) {
|
||||
nm_log_dbg (LOGD_DEVICE, "(%s) failed to determine virtual interface name",
|
||||
nm_connection_get_id (connection));
|
||||
g_set_error_literal (error,
|
||||
NM_MANAGER_ERROR,
|
||||
NM_MANAGER_ERROR_FAILED,
|
||||
"failed to determine virtual interface name");
|
||||
iface = get_virtual_iface_name (self, connection, &parent, error);
|
||||
if (!iface)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Make sure we didn't create a device for this connection already */
|
||||
for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
|
||||
|
|
@ -1085,6 +1033,19 @@ system_create_virtual_device (NMManager *self, NMConnection *connection, GError
|
|||
}
|
||||
}
|
||||
|
||||
factory = nm_device_factory_manager_find_factory_for_connection (connection);
|
||||
if (!factory) {
|
||||
nm_log_err (LOGD_DEVICE, "(%s:%s) NetworkManager plugin for '%s' unavailable",
|
||||
nm_connection_get_id (connection), iface,
|
||||
nm_connection_get_connection_type (connection));
|
||||
g_set_error (error,
|
||||
NM_MANAGER_ERROR,
|
||||
NM_MANAGER_ERROR_FAILED,
|
||||
"NetworkManager plugin for '%s' unavailable",
|
||||
nm_connection_get_connection_type (connection));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Block notification of link added since we're creating the device
|
||||
* explicitly here, otherwise adding the platform/kernel device would
|
||||
* create it before this function can do the rest of the setup.
|
||||
|
|
@ -1093,24 +1054,10 @@ system_create_virtual_device (NMManager *self, NMConnection *connection, GError
|
|||
|
||||
nm_owned = !nm_platform_link_exists (NM_PLATFORM_GET, iface);
|
||||
|
||||
for (iter = priv->factories; iter; iter = iter->next) {
|
||||
device = nm_device_factory_create_virtual_device_for_connection (NM_DEVICE_FACTORY (iter->data),
|
||||
connection,
|
||||
parent,
|
||||
&local_err);
|
||||
if (device || local_err) {
|
||||
if (device)
|
||||
g_assert_no_error (local_err);
|
||||
else {
|
||||
nm_log_err (LOGD_DEVICE, "(%s) failed to create virtual device: %s",
|
||||
nm_connection_get_id (connection),
|
||||
local_err ? local_err->message : "(unknown error)");
|
||||
g_propagate_error (error, local_err);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
device = nm_device_factory_create_virtual_device_for_connection (factory,
|
||||
connection,
|
||||
parent,
|
||||
error);
|
||||
if (device) {
|
||||
if (nm_owned)
|
||||
nm_device_set_nm_owned (device);
|
||||
|
|
@ -1121,16 +1068,6 @@ system_create_virtual_device (NMManager *self, NMConnection *connection, GError
|
|||
add_device (self, device, !nm_owned);
|
||||
|
||||
g_object_unref (device);
|
||||
} else {
|
||||
if (error && !*error)
|
||||
nm_log_err (LOGD_DEVICE, "(%s:%s) NetworkManager plugin for '%s' unavailable",
|
||||
nm_connection_get_id (connection), iface,
|
||||
nm_connection_get_connection_type (connection));
|
||||
g_set_error (error,
|
||||
NM_MANAGER_ERROR,
|
||||
NM_MANAGER_ERROR_FAILED,
|
||||
"NetworkManager plugin for '%s' unavailable",
|
||||
nm_connection_get_connection_type (connection));
|
||||
}
|
||||
|
||||
priv->ignore_link_added_cb--;
|
||||
|
|
@ -1776,6 +1713,18 @@ device_ip_iface_changed (NMDevice *device,
|
|||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
notify_component_added (NMManager *self, GObject *component)
|
||||
{
|
||||
GSList *iter;
|
||||
|
||||
for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = iter->next) {
|
||||
if (nm_device_notify_component_added (NM_DEVICE (iter->data), component))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* add_device:
|
||||
* @self: the #NMManager
|
||||
|
|
@ -1893,27 +1842,14 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume)
|
|||
g_signal_emit (self, signals[DEVICE_ADDED], 0, device);
|
||||
g_object_notify (G_OBJECT (self), NM_MANAGER_DEVICES);
|
||||
|
||||
notify_component_added (self, G_OBJECT (device));
|
||||
|
||||
/* New devices might be master interfaces for virtual interfaces; so we may
|
||||
* need to create new virtual interfaces now.
|
||||
*/
|
||||
system_create_virtual_devices (self);
|
||||
}
|
||||
|
||||
static NMDevice *
|
||||
find_device_by_ip_iface (NMManager *self, const gchar *iface)
|
||||
{
|
||||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
||||
GSList *iter;
|
||||
|
||||
for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
|
||||
NMDevice *candidate = iter->data;
|
||||
|
||||
if (g_strcmp0 (nm_device_get_ip_iface (candidate), iface) == 0)
|
||||
return candidate;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*******************************************************************/
|
||||
|
||||
static void
|
||||
|
|
@ -1928,135 +1864,14 @@ static gboolean
|
|||
factory_component_added_cb (NMDeviceFactory *factory,
|
||||
GObject *component,
|
||||
gpointer user_data)
|
||||
{
|
||||
return notify_component_added (NM_MANAGER (user_data), component);
|
||||
}
|
||||
|
||||
static void
|
||||
_register_device_factory (NMDeviceFactory *factory, gpointer user_data)
|
||||
{
|
||||
NMManager *self = NM_MANAGER (user_data);
|
||||
GSList *iter;
|
||||
|
||||
for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = iter->next) {
|
||||
if (nm_device_notify_component_added (NM_DEVICE (iter->data), component))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#define PLUGIN_PREFIX "libnm-device-plugin-"
|
||||
#define PLUGIN_PATH_TAG "NMManager-plugin-path"
|
||||
|
||||
struct read_device_factory_paths_data {
|
||||
char *path;
|
||||
struct stat st;
|
||||
};
|
||||
|
||||
static gint
|
||||
read_device_factory_paths_sort_fcn (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const struct read_device_factory_paths_data *da = a;
|
||||
const struct read_device_factory_paths_data *db = b;
|
||||
time_t ta, tb;
|
||||
|
||||
ta = MAX (da->st.st_mtime, da->st.st_ctime);
|
||||
tb = MAX (db->st.st_mtime, db->st.st_ctime);
|
||||
|
||||
if (ta < tb)
|
||||
return 1;
|
||||
if (ta > tb)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char**
|
||||
read_device_factory_paths (void)
|
||||
{
|
||||
GDir *dir;
|
||||
GError *error = NULL;
|
||||
const char *item;
|
||||
GArray *paths;
|
||||
char **result;
|
||||
guint i;
|
||||
|
||||
dir = g_dir_open (NMPLUGINDIR, 0, &error);
|
||||
if (!dir) {
|
||||
nm_log_warn (LOGD_HW, "device plugin: failed to open directory %s: %s",
|
||||
NMPLUGINDIR,
|
||||
(error && error->message) ? error->message : "(unknown)");
|
||||
g_clear_error (&error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
paths = g_array_new (FALSE, FALSE, sizeof (struct read_device_factory_paths_data));
|
||||
|
||||
while ((item = g_dir_read_name (dir))) {
|
||||
int errsv;
|
||||
struct read_device_factory_paths_data data;
|
||||
|
||||
if (!g_str_has_prefix (item, PLUGIN_PREFIX))
|
||||
continue;
|
||||
if (g_str_has_suffix (item, ".la"))
|
||||
continue;
|
||||
|
||||
data.path = g_build_filename (NMPLUGINDIR, item, NULL);
|
||||
|
||||
if (stat (data.path, &data.st) != 0) {
|
||||
errsv = errno;
|
||||
nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (error during stat: %s)", data.path, strerror (errsv));
|
||||
goto NEXT;
|
||||
}
|
||||
if (!S_ISREG (data.st.st_mode))
|
||||
goto NEXT;
|
||||
if (data.st.st_uid != 0) {
|
||||
nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (file must be owned by root)", data.path);
|
||||
goto NEXT;
|
||||
}
|
||||
if (data.st.st_mode & (S_IWGRP | S_IWOTH | S_ISUID)) {
|
||||
nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (invalid file permissions)", data.path);
|
||||
goto NEXT;
|
||||
}
|
||||
|
||||
g_array_append_val (paths, data);
|
||||
continue;
|
||||
NEXT:
|
||||
g_free (data.path);
|
||||
}
|
||||
g_dir_close (dir);
|
||||
|
||||
/* sort filenames by modification time. */
|
||||
g_array_sort (paths, read_device_factory_paths_sort_fcn);
|
||||
|
||||
result = g_new (char *, paths->len + 1);
|
||||
for (i = 0; i < paths->len; i++)
|
||||
result[i] = g_array_index (paths, struct read_device_factory_paths_data, i).path;
|
||||
result[i] = NULL;
|
||||
|
||||
g_array_free (paths, TRUE);
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_register_device_factory (NMManager *self,
|
||||
NMDeviceFactory *factory,
|
||||
gboolean duplicate_check,
|
||||
const char *path,
|
||||
GError **error)
|
||||
{
|
||||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
||||
NMDeviceType ftype;
|
||||
GSList *iter;
|
||||
|
||||
if (duplicate_check) {
|
||||
/* Make sure we don't double-register factories */
|
||||
ftype = nm_device_factory_get_device_type (factory);
|
||||
for (iter = priv->factories; iter; iter = iter->next) {
|
||||
if (ftype == nm_device_factory_get_device_type (iter->data)) {
|
||||
g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED,
|
||||
"multiple plugins for same type (using '%s' instead of '%s')",
|
||||
(char *) g_object_get_data (G_OBJECT (iter->data), PLUGIN_PATH_TAG),
|
||||
path);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
priv->factories = g_slist_append (priv->factories, factory);
|
||||
|
||||
g_signal_connect (factory,
|
||||
NM_DEVICE_FACTORY_DEVICE_ADDED,
|
||||
|
|
@ -2066,80 +1881,6 @@ _register_device_factory (NMManager *self,
|
|||
NM_DEVICE_FACTORY_COMPONENT_ADDED,
|
||||
G_CALLBACK (factory_component_added_cb),
|
||||
self);
|
||||
g_object_set_data_full (G_OBJECT (factory), PLUGIN_PATH_TAG,
|
||||
g_strdup (path), g_free);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
load_device_factories (NMManager *self)
|
||||
{
|
||||
NMDeviceFactory *factory;
|
||||
const GSList *iter;
|
||||
GError *error = NULL;
|
||||
char **path, **paths;
|
||||
|
||||
/* Register internal factories first */
|
||||
for (iter = nm_device_factory_get_internal_factory_types (); iter; iter = iter->next) {
|
||||
GType ftype = (GType) GPOINTER_TO_SIZE (iter->data);
|
||||
|
||||
factory = (NMDeviceFactory *) g_object_new (ftype, NULL);
|
||||
g_assert (factory);
|
||||
if (_register_device_factory (self, factory, FALSE, "internal", &error)) {
|
||||
nm_log_dbg (LOGD_HW, "Loaded device plugin: %s", g_type_name (ftype));
|
||||
} else {
|
||||
nm_log_warn (LOGD_HW, "Loading device plugin failed: %s", error->message);
|
||||
g_object_unref (factory);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
}
|
||||
|
||||
paths = read_device_factory_paths ();
|
||||
if (!paths)
|
||||
return;
|
||||
|
||||
for (path = paths; *path; path++) {
|
||||
GModule *plugin;
|
||||
NMDeviceFactoryCreateFunc create_func;
|
||||
const char *item;
|
||||
|
||||
item = strrchr (*path, '/');
|
||||
g_assert (item);
|
||||
|
||||
plugin = g_module_open (*path, G_MODULE_BIND_LOCAL);
|
||||
|
||||
if (!plugin) {
|
||||
nm_log_warn (LOGD_HW, "(%s): failed to load plugin: %s", item, g_module_error ());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!g_module_symbol (plugin, "nm_device_factory_create", (gpointer) &create_func)) {
|
||||
nm_log_warn (LOGD_HW, "(%s): failed to find device factory creator: %s", item, g_module_error ());
|
||||
g_module_close (plugin);
|
||||
continue;
|
||||
}
|
||||
|
||||
factory = create_func (&error);
|
||||
if (!factory) {
|
||||
nm_log_warn (LOGD_HW, "(%s): failed to initialize device factory: %s",
|
||||
item, error ? error->message : "unknown");
|
||||
g_clear_error (&error);
|
||||
g_module_close (plugin);
|
||||
continue;
|
||||
}
|
||||
g_clear_error (&error);
|
||||
|
||||
if (_register_device_factory (self, factory, TRUE, g_module_name (plugin), &error)) {
|
||||
nm_log_info (LOGD_HW, "Loaded device plugin: %s", g_module_name (plugin));
|
||||
g_module_make_resident (plugin);
|
||||
} else {
|
||||
nm_log_warn (LOGD_HW, "Loading device plugin failed: %s", error->message);
|
||||
g_object_unref (factory);
|
||||
g_module_close (plugin);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
}
|
||||
g_strfreev (paths);
|
||||
}
|
||||
|
||||
/*******************************************************************/
|
||||
|
|
@ -2151,8 +1892,8 @@ platform_link_added (NMManager *self,
|
|||
NMPlatformReason reason)
|
||||
{
|
||||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
||||
NMDeviceFactory *factory;
|
||||
NMDevice *device = NULL;
|
||||
GSList *iter;
|
||||
GError *error = NULL;
|
||||
gboolean nm_plugin_missing = FALSE;
|
||||
|
||||
|
|
@ -2165,40 +1906,25 @@ platform_link_added (NMManager *self,
|
|||
return;
|
||||
|
||||
/* Try registered device factories */
|
||||
for (iter = priv->factories; iter; iter = iter->next) {
|
||||
NMDeviceFactory *factory = NM_DEVICE_FACTORY (iter->data);
|
||||
factory = nm_device_factory_manager_find_factory_for_link_type (plink->type);
|
||||
if (factory) {
|
||||
gboolean ignore = FALSE;
|
||||
|
||||
device = nm_device_factory_new_link (factory, plink, &error);
|
||||
if (device && NM_IS_DEVICE (device)) {
|
||||
g_assert_no_error (error);
|
||||
break; /* success! */
|
||||
}
|
||||
|
||||
if (error) {
|
||||
nm_log_warn (LOGD_HW, "%s: factory failed to create device: (%d) %s",
|
||||
plink->udi,
|
||||
error ? error->code : -1,
|
||||
error ? error->message : "(unknown)");
|
||||
g_clear_error (&error);
|
||||
device = nm_device_factory_new_link (factory, plink, &ignore, &error);
|
||||
if (!device) {
|
||||
if (!ignore) {
|
||||
nm_log_warn (LOGD_HW, "%s: factory failed to create device: %s",
|
||||
plink->name, error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ignore Bluetooth PAN interfaces; they are handled by their NMDeviceBt
|
||||
* parent and don't get a separate interface.
|
||||
*/
|
||||
if (!strncmp (plink->name, "bnep", STRLEN ("bnep")))
|
||||
return;
|
||||
|
||||
if (device == NULL) {
|
||||
switch (plink->type) {
|
||||
|
||||
case NM_LINK_TYPE_WWAN_ETHERNET:
|
||||
/* WWAN pseudo-ethernet interfaces are handled automatically by
|
||||
* their NMDeviceModem and don't get a separate NMDevice object.
|
||||
*/
|
||||
break;
|
||||
|
||||
case NM_LINK_TYPE_BNEP:
|
||||
case NM_LINK_TYPE_OLPC_MESH:
|
||||
case NM_LINK_TYPE_TEAM:
|
||||
case NM_LINK_TYPE_WIFI:
|
||||
|
|
@ -2460,13 +2186,10 @@ find_master (NMManager *self,
|
|||
NMConnection *candidate = iter->data;
|
||||
char *vname;
|
||||
|
||||
if (nm_connection_is_virtual (candidate)) {
|
||||
vname = get_virtual_iface_name (self, candidate, NULL);
|
||||
if ( g_strcmp0 (master, vname) == 0
|
||||
&& is_compatible_with_slave (candidate, connection))
|
||||
master_connection = candidate;
|
||||
g_free (vname);
|
||||
}
|
||||
vname = get_virtual_iface_name (self, connection, NULL, NULL);
|
||||
if (g_strcmp0 (master, vname) == 0 && is_compatible_with_slave (candidate, connection))
|
||||
master_connection = candidate;
|
||||
g_free (vname);
|
||||
}
|
||||
g_slist_free (connections);
|
||||
}
|
||||
|
|
@ -3148,17 +2871,12 @@ validate_activation_request (NMManager *self,
|
|||
}
|
||||
|
||||
if (is_software) {
|
||||
/* Look for an existing device with the connection's interface name */
|
||||
char *iface;
|
||||
|
||||
iface = get_virtual_iface_name (self, connection, NULL);
|
||||
if (!iface) {
|
||||
g_set_error_literal (error,
|
||||
NM_MANAGER_ERROR,
|
||||
NM_MANAGER_ERROR_UNKNOWN_DEVICE,
|
||||
"Failed to determine connection's virtual interface name");
|
||||
/* Look for an existing device with the connection's interface name */
|
||||
iface = get_virtual_iface_name (self, connection, NULL, error);
|
||||
if (!iface)
|
||||
goto error;
|
||||
}
|
||||
|
||||
device = find_device_by_ip_iface (self, iface);
|
||||
g_free (iface);
|
||||
|
|
@ -4219,11 +3937,16 @@ impl_manager_check_connectivity (NMManager *manager,
|
|||
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
start_factory (NMDeviceFactory *factory, gpointer user_data)
|
||||
{
|
||||
nm_device_factory_start (factory);
|
||||
}
|
||||
|
||||
void
|
||||
nm_manager_start (NMManager *self)
|
||||
{
|
||||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
||||
GSList *iter;
|
||||
guint i;
|
||||
|
||||
/* Set initial radio enabled/disabled state */
|
||||
|
|
@ -4255,8 +3978,7 @@ nm_manager_start (NMManager *self)
|
|||
system_hostname_changed_cb (priv->settings, NULL, self);
|
||||
|
||||
/* Start device factories */
|
||||
for (iter = priv->factories; iter; iter = iter->next)
|
||||
nm_device_factory_start (iter->data);
|
||||
nm_device_factory_manager_for_each_factory (start_factory, NULL);
|
||||
|
||||
nm_platform_query_devices (NM_PLATFORM_GET);
|
||||
|
||||
|
|
@ -4861,7 +4583,7 @@ nm_manager_new (NMSettings *settings,
|
|||
rfkill_change (priv->radio_states[RFKILL_TYPE_WLAN].desc, RFKILL_TYPE_WLAN, initial_wifi_enabled);
|
||||
rfkill_change (priv->radio_states[RFKILL_TYPE_WWAN].desc, RFKILL_TYPE_WWAN, initial_wwan_enabled);
|
||||
|
||||
load_device_factories (singleton);
|
||||
nm_device_factory_manager_load_factories (_register_device_factory, singleton);
|
||||
|
||||
return singleton;
|
||||
}
|
||||
|
|
@ -5087,6 +4809,12 @@ set_property (GObject *object, guint prop_id,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_deinit_device_factory (NMDeviceFactory *factory, gpointer user_data)
|
||||
{
|
||||
g_signal_handlers_disconnect_matched (factory, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, NM_MANAGER (user_data));
|
||||
}
|
||||
|
||||
static void
|
||||
dispose (GObject *object)
|
||||
{
|
||||
|
|
@ -5094,7 +4822,6 @@ dispose (GObject *object)
|
|||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
||||
DBusGConnection *bus;
|
||||
DBusConnection *dbus_connection;
|
||||
GSList *iter;
|
||||
|
||||
g_slist_free_full (priv->auth_chains, (GDestroyNotify) nm_auth_chain_unref);
|
||||
priv->auth_chains = NULL;
|
||||
|
|
@ -5170,14 +4897,8 @@ dispose (GObject *object)
|
|||
g_clear_object (&priv->fw_monitor);
|
||||
}
|
||||
|
||||
for (iter = priv->factories; iter; iter = iter->next) {
|
||||
NMDeviceFactory *factory = iter->data;
|
||||
|
||||
g_signal_handlers_disconnect_matched (factory, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, manager);
|
||||
g_object_unref (factory);
|
||||
}
|
||||
g_clear_pointer (&priv->factories, g_slist_free);
|
||||
|
||||
nm_device_factory_manager_for_each_factory (_deinit_device_factory, manager);
|
||||
|
||||
if (priv->timestamp_update_id) {
|
||||
g_source_remove (priv->timestamp_update_id);
|
||||
priv->timestamp_update_id = 0;
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ typedef enum {
|
|||
NM_LINK_TYPE_VETH,
|
||||
NM_LINK_TYPE_VLAN,
|
||||
NM_LINK_TYPE_VXLAN,
|
||||
NM_LINK_TYPE_BNEP, /* Bluetooth Ethernet emulation */
|
||||
|
||||
/* Software types with slaves */
|
||||
NM_LINK_TYPE_BRIDGE = 0x10000 | 0x20000,
|
||||
|
|
|
|||
|
|
@ -162,13 +162,40 @@ _nm_platform_link_get (NMPlatform *platform, int ifindex, NMPlatformLink *l)
|
|||
{
|
||||
NMFakePlatformLink *device = link_get (platform, ifindex);
|
||||
|
||||
if (device)
|
||||
if (device && l)
|
||||
*l = device->link;
|
||||
return !!device;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
link_add (NMPlatform *platform, const char *name, NMLinkType type, const void *address, size_t address_len)
|
||||
_nm_platform_link_get_by_address (NMPlatform *platform,
|
||||
gconstpointer address,
|
||||
size_t length,
|
||||
NMPlatformLink *l)
|
||||
{
|
||||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < priv->links->len; i++) {
|
||||
NMFakePlatformLink *device = &g_array_index (priv->links, NMFakePlatformLink, i);
|
||||
|
||||
if ( device->address
|
||||
&& g_bytes_get_size (device->address) == length
|
||||
&& memcmp (g_bytes_get_data (device->address, NULL), address, length) == 0) {
|
||||
*l = device->link;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
link_add (NMPlatform *platform,
|
||||
const char *name,
|
||||
NMLinkType type,
|
||||
const void *address,
|
||||
size_t address_len,
|
||||
NMPlatformLink *out_link)
|
||||
{
|
||||
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
|
||||
NMFakePlatformLink device;
|
||||
|
|
@ -180,6 +207,8 @@ link_add (NMPlatform *platform, const char *name, NMLinkType type, const void *a
|
|||
if (device.link.ifindex)
|
||||
g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, device.link.ifindex, &device, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_INTERNAL);
|
||||
|
||||
if (out_link)
|
||||
*out_link = device.link;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -425,6 +454,12 @@ link_get_address (NMPlatform *platform, int ifindex, size_t *length)
|
|||
return g_bytes_get_data (device->address, length);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
link_get_permanent_address (NMPlatform *platform, int ifindex, guint8 *buf, size_t *length)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu)
|
||||
{
|
||||
|
|
@ -473,6 +508,26 @@ link_get_wake_on_lan (NMPlatform *platform, int ifindex)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
link_get_driver_info (NMPlatform *platform,
|
||||
int ifindex,
|
||||
char **out_driver_name,
|
||||
char **out_driver_version,
|
||||
char **out_fw_version)
|
||||
{
|
||||
if (out_driver_name)
|
||||
*out_driver_name = NULL;
|
||||
if (out_driver_version)
|
||||
*out_driver_version = NULL;
|
||||
if (out_fw_version)
|
||||
*out_fw_version = NULL;
|
||||
|
||||
/* We call link_get just to cause an error to be set if @ifindex is bad. */
|
||||
link_get (platform, ifindex);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
link_supports_carrier_detect (NMPlatform *platform, int ifindex)
|
||||
{
|
||||
|
|
@ -584,11 +639,11 @@ slave_get_option (NMPlatform *platform, int slave, const char *option)
|
|||
}
|
||||
|
||||
static gboolean
|
||||
vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags)
|
||||
vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags, NMPlatformLink *out_link)
|
||||
{
|
||||
NMFakePlatformLink *device;
|
||||
|
||||
if (!link_add (platform, name, NM_LINK_TYPE_VLAN, NULL, 0))
|
||||
if (!link_add (platform, name, NM_LINK_TYPE_VLAN, NULL, 0, NULL))
|
||||
return FALSE;
|
||||
|
||||
device = link_get (platform, link_get_ifindex (platform, name));
|
||||
|
|
@ -598,6 +653,8 @@ vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint
|
|||
device->vlan_id = vlan_id;
|
||||
device->link.parent = parent;
|
||||
|
||||
if (out_link)
|
||||
*out_link = device->link;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -629,7 +686,7 @@ vlan_set_egress_map (NMPlatform *platform, int ifindex, int from, int to)
|
|||
}
|
||||
|
||||
static gboolean
|
||||
infiniband_partition_add (NMPlatform *platform, int parent, int p_key)
|
||||
infiniband_partition_add (NMPlatform *platform, int parent, int p_key, NMPlatformLink *out_link)
|
||||
{
|
||||
NMFakePlatformLink *parent_device;
|
||||
char *name;
|
||||
|
|
@ -639,7 +696,7 @@ infiniband_partition_add (NMPlatform *platform, int parent, int p_key)
|
|||
g_return_val_if_fail (parent_device != NULL, FALSE);
|
||||
|
||||
name = g_strdup_printf ("%s.%04x", parent_device->link.name, p_key);
|
||||
success = link_add (platform, name, NM_LINK_TYPE_INFINIBAND, NULL, 0);
|
||||
success = link_add (platform, name, NM_LINK_TYPE_INFINIBAND, NULL, 0, out_link);
|
||||
g_free (name);
|
||||
|
||||
return success;
|
||||
|
|
@ -1313,15 +1370,15 @@ nm_fake_platform_setup (void)
|
|||
nm_platform_setup (platform);
|
||||
|
||||
/* skip zero element */
|
||||
link_add (platform, NULL, NM_LINK_TYPE_NONE, NULL, 0);
|
||||
link_add (platform, NULL, NM_LINK_TYPE_NONE, NULL, 0, NULL);
|
||||
|
||||
/* add loopback interface */
|
||||
link_add (platform, "lo", NM_LINK_TYPE_LOOPBACK, NULL, 0);
|
||||
link_add (platform, "lo", NM_LINK_TYPE_LOOPBACK, NULL, 0, NULL);
|
||||
|
||||
/* add some ethernets */
|
||||
link_add (platform, "eth0", NM_LINK_TYPE_ETHERNET, NULL, 0);
|
||||
link_add (platform, "eth1", NM_LINK_TYPE_ETHERNET, NULL, 0);
|
||||
link_add (platform, "eth2", NM_LINK_TYPE_ETHERNET, NULL, 0);
|
||||
link_add (platform, "eth0", NM_LINK_TYPE_ETHERNET, NULL, 0, NULL);
|
||||
link_add (platform, "eth1", NM_LINK_TYPE_ETHERNET, NULL, 0, NULL);
|
||||
link_add (platform, "eth2", NM_LINK_TYPE_ETHERNET, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1361,6 +1418,7 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass)
|
|||
platform_class->sysctl_get = sysctl_get;
|
||||
|
||||
platform_class->link_get = _nm_platform_link_get;
|
||||
platform_class->link_get_by_address = _nm_platform_link_get_by_address;
|
||||
platform_class->link_get_all = link_get_all;
|
||||
platform_class->link_add = link_add;
|
||||
platform_class->link_delete = link_delete;
|
||||
|
|
@ -1380,12 +1438,14 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass)
|
|||
|
||||
platform_class->link_set_address = link_set_address;
|
||||
platform_class->link_get_address = link_get_address;
|
||||
platform_class->link_get_permanent_address = link_get_permanent_address;
|
||||
platform_class->link_get_mtu = link_get_mtu;
|
||||
platform_class->link_set_mtu = link_set_mtu;
|
||||
|
||||
platform_class->link_get_physical_port_id = link_get_physical_port_id;
|
||||
platform_class->link_get_dev_id = link_get_dev_id;
|
||||
platform_class->link_get_wake_on_lan = link_get_wake_on_lan;
|
||||
platform_class->link_get_driver_info = link_get_driver_info;
|
||||
|
||||
platform_class->link_supports_carrier_detect = link_supports_carrier_detect;
|
||||
platform_class->link_supports_vlans = link_supports_vlans;
|
||||
|
|
|
|||
|
|
@ -372,6 +372,9 @@ ethtool_get (const char *name, gpointer edata)
|
|||
struct ifreq ifr;
|
||||
int fd;
|
||||
|
||||
if (!name || !*name)
|
||||
return FALSE;
|
||||
|
||||
memset (&ifr, 0, sizeof (ifr));
|
||||
strncpy (ifr.ifr_name, name, IFNAMSIZ);
|
||||
ifr.ifr_data = edata;
|
||||
|
|
@ -426,21 +429,54 @@ ethtool_get_stringset_index (const char *ifname, int stringset_id, const char *s
|
|||
return -1;
|
||||
}
|
||||
|
||||
static const char *
|
||||
ethtool_get_driver (const char *ifname)
|
||||
static gboolean
|
||||
ethtool_get_driver_info (const char *ifname,
|
||||
char **out_driver_name,
|
||||
char **out_driver_version,
|
||||
char **out_fw_version)
|
||||
{
|
||||
struct ethtool_drvinfo drvinfo = { 0 };
|
||||
|
||||
g_return_val_if_fail (ifname != NULL, NULL);
|
||||
if (!ifname)
|
||||
return FALSE;
|
||||
|
||||
drvinfo.cmd = ETHTOOL_GDRVINFO;
|
||||
if (!ethtool_get (ifname, &drvinfo))
|
||||
return NULL;
|
||||
return FALSE;
|
||||
|
||||
if (!*drvinfo.driver)
|
||||
return NULL;
|
||||
if (out_driver_name)
|
||||
*out_driver_name = g_strdup (drvinfo.driver);
|
||||
if (out_driver_version)
|
||||
*out_driver_version = g_strdup (drvinfo.version);
|
||||
if (out_fw_version)
|
||||
*out_fw_version = g_strdup (drvinfo.fw_version);
|
||||
|
||||
return g_intern_string (drvinfo.driver);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
ethtool_get_permanent_address (const char *ifname,
|
||||
guint8 *buf,
|
||||
size_t *length)
|
||||
{
|
||||
gs_free struct ethtool_perm_addr *epaddr = NULL;
|
||||
|
||||
if (!ifname)
|
||||
return FALSE;
|
||||
|
||||
epaddr = g_malloc0 (sizeof (*epaddr) + NM_UTILS_HWADDR_LEN_MAX);
|
||||
epaddr->cmd = ETHTOOL_GPERMADDR;
|
||||
epaddr->size = NM_UTILS_HWADDR_LEN_MAX;
|
||||
|
||||
if (!ethtool_get (ifname, epaddr))
|
||||
return FALSE;
|
||||
if (!nm_ethernet_address_is_valid (epaddr->data, epaddr->size))
|
||||
return FALSE;
|
||||
|
||||
g_assert (epaddr->size <= NM_UTILS_HWADDR_LEN_MAX);
|
||||
memcpy (buf, epaddr->data, epaddr->size);
|
||||
*length = epaddr->size;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
|
|
@ -881,6 +917,7 @@ static const LinkDesc linktypes[] = {
|
|||
{ NM_LINK_TYPE_VETH, "veth", "veth", NULL },
|
||||
{ NM_LINK_TYPE_VLAN, "vlan", "vlan", "vlan" },
|
||||
{ NM_LINK_TYPE_VXLAN, "vxlan", "vxlan", "vxlan" },
|
||||
{ NM_LINK_TYPE_BNEP, "bluetooth", NULL, "bluetooth" },
|
||||
|
||||
{ NM_LINK_TYPE_BRIDGE, "bridge", "bridge", "bridge" },
|
||||
{ NM_LINK_TYPE_BOND, "bond", "bond", "bond" },
|
||||
|
|
@ -980,10 +1017,9 @@ link_extract_type (NMPlatform *platform, struct rtnl_link *rtnllink)
|
|||
else if (arptype == ARPHRD_INFINIBAND)
|
||||
return NM_LINK_TYPE_INFINIBAND;
|
||||
|
||||
|
||||
ifname = rtnl_link_get_name (rtnllink);
|
||||
if (ifname) {
|
||||
const char *driver = ethtool_get_driver (ifname);
|
||||
gs_free char *driver = NULL;
|
||||
gs_free char *sysfs_path = NULL;
|
||||
gs_free char *anycast_mask = NULL;
|
||||
gs_free char *devtype = NULL;
|
||||
|
|
@ -997,8 +1033,10 @@ link_extract_type (NMPlatform *platform, struct rtnl_link *rtnllink)
|
|||
}
|
||||
|
||||
/* Fallback OVS detection for kernel <= 3.16 */
|
||||
if (!g_strcmp0 (driver, "openvswitch"))
|
||||
return NM_LINK_TYPE_OPENVSWITCH;
|
||||
if (ethtool_get_driver_info (ifname, &driver, NULL, NULL)) {
|
||||
if (!g_strcmp0 (driver, "openvswitch"))
|
||||
return NM_LINK_TYPE_OPENVSWITCH;
|
||||
}
|
||||
|
||||
sysfs_path = g_strdup_printf ("/sys/class/net/%s", ifname);
|
||||
anycast_mask = g_strdup_printf ("%s/anycast_mask", sysfs_path);
|
||||
|
|
@ -1007,8 +1045,16 @@ link_extract_type (NMPlatform *platform, struct rtnl_link *rtnllink)
|
|||
|
||||
devtype = read_devtype (sysfs_path);
|
||||
for (i = 0; devtype && i < G_N_ELEMENTS (linktypes); i++) {
|
||||
if (g_strcmp0 (devtype, linktypes[i].devtype) == 0)
|
||||
if (g_strcmp0 (devtype, linktypes[i].devtype) == 0) {
|
||||
if (linktypes[i].nm_type == NM_LINK_TYPE_BNEP) {
|
||||
/* Both BNEP and 6lowpan use DEVTYPE=bluetooth, so we must
|
||||
* use arptype to distinguish between them.
|
||||
*/
|
||||
if (arptype != ARPHRD_ETHER)
|
||||
continue;
|
||||
}
|
||||
return linktypes[i].nm_type;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fallback for drivers that don't call SET_NETDEV_DEVTYPE() */
|
||||
|
|
@ -1033,6 +1079,7 @@ init_link (NMPlatform *platform, NMPlatformLink *info, struct rtnl_link *rtnllin
|
|||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
GUdevDevice *udev_device;
|
||||
const char *name;
|
||||
char *tmp;
|
||||
|
||||
g_return_val_if_fail (rtnllink, FALSE);
|
||||
|
||||
|
|
@ -1062,8 +1109,12 @@ init_link (NMPlatform *platform, NMPlatformLink *info, struct rtnl_link *rtnllin
|
|||
|
||||
if (!info->driver)
|
||||
info->driver = info->kind;
|
||||
if (!info->driver)
|
||||
info->driver = ethtool_get_driver (info->name);
|
||||
if (!info->driver) {
|
||||
if (ethtool_get_driver_info (name, &tmp, NULL, NULL)) {
|
||||
info->driver = g_intern_string (tmp);
|
||||
g_free (tmp);
|
||||
}
|
||||
}
|
||||
if (!info->driver)
|
||||
info->driver = "unknown";
|
||||
|
||||
|
|
@ -1768,12 +1819,14 @@ refresh_object (NMPlatform *platform, struct nl_object *object, gboolean removed
|
|||
|
||||
announce_object (platform, kernel_object, cached_object ? NM_PLATFORM_SIGNAL_CHANGED : NM_PLATFORM_SIGNAL_ADDED, reason);
|
||||
|
||||
/* Refresh the master device (even on enslave/release) */
|
||||
if (type == OBJECT_TYPE_LINK) {
|
||||
int kernel_master = rtnl_link_get_master ((struct rtnl_link *) kernel_object);
|
||||
int cached_master = cached_object ? rtnl_link_get_master ((struct rtnl_link *) cached_object) : 0;
|
||||
const char *orig_link_type = rtnl_link_get_type ((struct rtnl_link *) object);
|
||||
const char *kernel_link_type = rtnl_link_get_type ((struct rtnl_link *) kernel_object);
|
||||
struct nl_object *master_object;
|
||||
|
||||
/* Refresh the master device (even on enslave/release) */
|
||||
if (kernel_master) {
|
||||
master_object = build_rtnl_link (kernel_master, NULL, NM_LINK_TYPE_NONE);
|
||||
refresh_object (platform, master_object, FALSE, NM_PLATFORM_REASON_INTERNAL);
|
||||
|
|
@ -1784,6 +1837,12 @@ refresh_object (NMPlatform *platform, struct nl_object *object, gboolean removed
|
|||
refresh_object (platform, master_object, FALSE, NM_PLATFORM_REASON_INTERNAL);
|
||||
nl_object_put (master_object);
|
||||
}
|
||||
|
||||
/* Ensure the existing link type matches the refreshed link type */
|
||||
if (orig_link_type && kernel_link_type && strcmp (orig_link_type, kernel_link_type)) {
|
||||
platform->error = NM_PLATFORM_ERROR_WRONG_TYPE;
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2296,9 +2355,34 @@ _nm_platform_link_get (NMPlatform *platform, int ifindex, NMPlatformLink *l)
|
|||
{
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
auto_nl_object struct rtnl_link *rtnllink = NULL;
|
||||
NMPlatformLink tmp = { 0 };
|
||||
|
||||
rtnllink = rtnl_link_get (priv->link_cache, ifindex);
|
||||
return (rtnllink && init_link (platform, l, rtnllink));
|
||||
return (rtnllink && init_link (platform, l ? l : &tmp, rtnllink));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_nm_platform_link_get_by_address (NMPlatform *platform,
|
||||
gconstpointer address,
|
||||
size_t length,
|
||||
NMPlatformLink *l)
|
||||
{
|
||||
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
|
||||
struct nl_object *object;
|
||||
|
||||
for (object = nl_cache_get_first (priv->link_cache); object; object = nl_cache_get_next (object)) {
|
||||
struct rtnl_link *rtnl_link = (struct rtnl_link *) object;
|
||||
struct nl_addr *nladdr;
|
||||
gconstpointer hwaddr;
|
||||
|
||||
nladdr = rtnl_link_get_addr (rtnl_link);
|
||||
if (nladdr && (nl_addr_get_len (nladdr) == length)) {
|
||||
hwaddr = nl_addr_get_binary_addr (nladdr);
|
||||
if (hwaddr && memcmp (hwaddr, address, length) == 0)
|
||||
return init_link (platform, l, rtnl_link);
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static struct nl_object *
|
||||
|
|
@ -2316,7 +2400,27 @@ build_rtnl_link (int ifindex, const char *name, NMLinkType type)
|
|||
}
|
||||
|
||||
static gboolean
|
||||
link_add (NMPlatform *platform, const char *name, NMLinkType type, const void *address, size_t address_len)
|
||||
link_get_by_name (NMPlatform *platform, const char *name, NMPlatformLink *out_link)
|
||||
{
|
||||
int ifindex;
|
||||
|
||||
g_return_val_if_fail (name != NULL, FALSE);
|
||||
|
||||
if (out_link) {
|
||||
ifindex = nm_platform_link_get_ifindex (platform, name);
|
||||
g_return_val_if_fail (ifindex > 0, FALSE);
|
||||
return _nm_platform_link_get (platform, ifindex, out_link);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
link_add (NMPlatform *platform,
|
||||
const char *name,
|
||||
NMLinkType type,
|
||||
const void *address,
|
||||
size_t address_len,
|
||||
NMPlatformLink *out_link)
|
||||
{
|
||||
struct nl_object *l;
|
||||
|
||||
|
|
@ -2343,7 +2447,11 @@ link_add (NMPlatform *platform, const char *name, NMLinkType type, const void *a
|
|||
|
||||
rtnl_link_set_addr ((struct rtnl_link *) l, nladdr);
|
||||
}
|
||||
return add_object (platform, l);
|
||||
|
||||
if (!add_object (platform, l))
|
||||
return FALSE;
|
||||
|
||||
return link_get_by_name (platform, name, out_link);
|
||||
}
|
||||
|
||||
static struct rtnl_link *
|
||||
|
|
@ -2771,6 +2879,15 @@ link_get_address (NMPlatform *platform, int ifindex, size_t *length)
|
|||
return a;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
link_get_permanent_address (NMPlatform *platform,
|
||||
int ifindex,
|
||||
guint8 *buf,
|
||||
size_t *length)
|
||||
{
|
||||
return ethtool_get_permanent_address (nm_platform_link_get_name (platform, ifindex), buf, length);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu)
|
||||
{
|
||||
|
|
@ -2834,7 +2951,12 @@ link_get_dev_id (NMPlatform *platform, int ifindex)
|
|||
}
|
||||
|
||||
static int
|
||||
vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags)
|
||||
vlan_add (NMPlatform *platform,
|
||||
const char *name,
|
||||
int parent,
|
||||
int vlan_id,
|
||||
guint32 vlan_flags,
|
||||
NMPlatformLink *out_link)
|
||||
{
|
||||
struct nl_object *object = build_rtnl_link (0, name, NM_LINK_TYPE_VLAN);
|
||||
struct rtnl_link *rtnllink = (struct rtnl_link *) object;
|
||||
|
|
@ -2855,7 +2977,10 @@ vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint
|
|||
debug ("link: add vlan '%s', parent %d, vlan id %d, flags %X (native: %X)",
|
||||
name, parent, vlan_id, (unsigned int) vlan_flags, kernel_flags);
|
||||
|
||||
return add_object (platform, object);
|
||||
if (!add_object (platform, object))
|
||||
return FALSE;
|
||||
|
||||
return link_get_by_name (platform, name, out_link);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
|
@ -3016,7 +3141,7 @@ slave_get_option (NMPlatform *platform, int slave, const char *option)
|
|||
}
|
||||
|
||||
static gboolean
|
||||
infiniband_partition_add (NMPlatform *platform, int parent, int p_key)
|
||||
infiniband_partition_add (NMPlatform *platform, int parent, int p_key, NMPlatformLink *out_link)
|
||||
{
|
||||
const char *parent_name;
|
||||
char *path, *id;
|
||||
|
|
@ -3033,9 +3158,12 @@ infiniband_partition_add (NMPlatform *platform, int parent, int p_key)
|
|||
|
||||
if (success) {
|
||||
gs_free char *ifname = g_strdup_printf ("%s.%04x", parent_name, p_key);
|
||||
auto_nl_object struct rtnl_link *rtnllink = _nm_rtnl_link_alloc (0, ifname);
|
||||
auto_nl_object struct rtnl_link *rtnllink;
|
||||
|
||||
rtnllink = (struct rtnl_link *) build_rtnl_link (0, ifname, NM_LINK_TYPE_INFINIBAND);
|
||||
success = refresh_object (platform, (struct nl_object *) rtnllink, FALSE, NM_PLATFORM_REASON_INTERNAL);
|
||||
if (success)
|
||||
success = link_get_by_name (platform, ifname, out_link);
|
||||
}
|
||||
|
||||
return success;
|
||||
|
|
@ -3582,6 +3710,19 @@ link_get_wake_on_lan (NMPlatform *platform, int ifindex)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
link_get_driver_info (NMPlatform *platform,
|
||||
int ifindex,
|
||||
char **out_driver_name,
|
||||
char **out_driver_version,
|
||||
char **out_fw_version)
|
||||
{
|
||||
return ethtool_get_driver_info (nm_platform_link_get_name (platform, ifindex),
|
||||
out_driver_name,
|
||||
out_driver_version,
|
||||
out_fw_version);
|
||||
}
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
static gboolean
|
||||
|
|
@ -4653,6 +4794,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
|
|||
platform_class->sysctl_get = sysctl_get;
|
||||
|
||||
platform_class->link_get = _nm_platform_link_get;
|
||||
platform_class->link_get_by_address = _nm_platform_link_get_by_address;
|
||||
platform_class->link_get_all = link_get_all;
|
||||
platform_class->link_add = link_add;
|
||||
platform_class->link_delete = link_delete;
|
||||
|
|
@ -4679,12 +4821,14 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
|
|||
|
||||
platform_class->link_get_address = link_get_address;
|
||||
platform_class->link_set_address = link_set_address;
|
||||
platform_class->link_get_permanent_address = link_get_permanent_address;
|
||||
platform_class->link_get_mtu = link_get_mtu;
|
||||
platform_class->link_set_mtu = link_set_mtu;
|
||||
|
||||
platform_class->link_get_physical_port_id = link_get_physical_port_id;
|
||||
platform_class->link_get_dev_id = link_get_dev_id;
|
||||
platform_class->link_get_wake_on_lan = link_get_wake_on_lan;
|
||||
platform_class->link_get_driver_info = link_get_driver_info;
|
||||
|
||||
platform_class->link_supports_carrier_detect = link_supports_carrier_detect;
|
||||
platform_class->link_supports_vlans = link_supports_vlans;
|
||||
|
|
|
|||
|
|
@ -536,12 +536,40 @@ nm_platform_link_get (NMPlatform *self, int ifindex, NMPlatformLink *link)
|
|||
_CHECK_SELF (self, klass, FALSE);
|
||||
|
||||
g_return_val_if_fail (ifindex > 0, FALSE);
|
||||
g_return_val_if_fail (link, FALSE);
|
||||
|
||||
g_return_val_if_fail (klass->link_get, FALSE);
|
||||
return !!klass->link_get (self, ifindex, link);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_platform_link_get_by_address:
|
||||
* @self: platform instance
|
||||
* @address: a pointer to the binary hardware address
|
||||
* @length: the size of @address in bytes
|
||||
* @link: (out): output NMPlatformLink structure.
|
||||
*
|
||||
* If a link with given @address exists, fill the given NMPlatformLink
|
||||
* structure.
|
||||
*
|
||||
* Returns: %TRUE, if such a link exists, %FALSE otherwise.
|
||||
* If the link does not exist, the content of @link is undefined.
|
||||
**/
|
||||
gboolean
|
||||
nm_platform_link_get_by_address (NMPlatform *self,
|
||||
gconstpointer address,
|
||||
size_t length,
|
||||
NMPlatformLink *link)
|
||||
{
|
||||
_CHECK_SELF (self, klass, FALSE);
|
||||
|
||||
g_return_val_if_fail (address != NULL, FALSE);
|
||||
g_return_val_if_fail (length > 0, FALSE);
|
||||
g_return_val_if_fail (link, FALSE);
|
||||
|
||||
g_return_val_if_fail (klass->link_get_by_address, FALSE);
|
||||
return !!klass->link_get_by_address (self, address, length, link);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_platform_link_add:
|
||||
* @self: platform instance
|
||||
|
|
@ -549,14 +577,24 @@ nm_platform_link_get (NMPlatform *self, int ifindex, NMPlatformLink *link)
|
|||
* @type: Interface type
|
||||
* @address: (allow-none): set the mac address of the link
|
||||
* @address_len: the length of the @address
|
||||
* @out_link: on success, the link object
|
||||
*
|
||||
* Add a software interface. Sets self->error to NM_PLATFORM_ERROR_EXISTS
|
||||
* if interface is already already exists. Any link-changed ADDED signal will be
|
||||
* emitted directly, before this function finishes.
|
||||
* Add a software interface. If the interface already exists and is of type
|
||||
* @type, sets platform->error to NM_PLATFORM_ERROR_EXISTS and returns the link
|
||||
* in @out_link. If the interface already exists and is not of type @type,
|
||||
* sets platform->error to NM_PLATFORM_ERROR_WRONG_TYPE. Any link-changed ADDED
|
||||
* signal will be emitted directly, before this function finishes.
|
||||
*/
|
||||
static gboolean
|
||||
nm_platform_link_add (NMPlatform *self, const char *name, NMLinkType type, const void *address, size_t address_len)
|
||||
nm_platform_link_add (NMPlatform *self,
|
||||
const char *name,
|
||||
NMLinkType type,
|
||||
const void *address,
|
||||
size_t address_len,
|
||||
NMPlatformLink *out_link)
|
||||
{
|
||||
int ifindex;
|
||||
|
||||
_CHECK_SELF (self, klass, FALSE);
|
||||
reset_error (self);
|
||||
|
||||
|
|
@ -564,29 +602,37 @@ nm_platform_link_add (NMPlatform *self, const char *name, NMLinkType type, const
|
|||
g_return_val_if_fail (klass->link_add, FALSE);
|
||||
g_return_val_if_fail ( (address != NULL) ^ (address_len == 0) , FALSE);
|
||||
|
||||
if (nm_platform_link_exists (self, name)) {
|
||||
ifindex = nm_platform_link_get_ifindex (self, name);
|
||||
if (ifindex > 0) {
|
||||
debug ("link: already exists");
|
||||
self->error = NM_PLATFORM_ERROR_EXISTS;
|
||||
if (nm_platform_link_get_type (self, ifindex) != type)
|
||||
self->error = NM_PLATFORM_ERROR_WRONG_TYPE;
|
||||
else {
|
||||
self->error = NM_PLATFORM_ERROR_EXISTS;
|
||||
(void) nm_platform_link_get (self, ifindex, out_link);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return klass->link_add (self, name, type, address, address_len);
|
||||
reset_error(self);
|
||||
return klass->link_add (self, name, type, address, address_len, out_link);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_platform_dummy_add:
|
||||
* @self: platform instance
|
||||
* @name: New interface name
|
||||
* @out_link: on success, the link object
|
||||
*
|
||||
* Create a software ethernet-like interface
|
||||
*/
|
||||
gboolean
|
||||
nm_platform_dummy_add (NMPlatform *self, const char *name)
|
||||
nm_platform_dummy_add (NMPlatform *self, const char *name, NMPlatformLink *out_link)
|
||||
{
|
||||
g_return_val_if_fail (name, FALSE);
|
||||
|
||||
debug ("link: adding dummy '%s'", name);
|
||||
return nm_platform_link_add (self, name, NM_LINK_TYPE_DUMMY, NULL, 0);
|
||||
return nm_platform_link_add (self, name, NM_LINK_TYPE_DUMMY, NULL, 0, out_link);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -966,7 +1012,8 @@ nm_platform_link_set_address (NMPlatform *self, int ifindex, gconstpointer addre
|
|||
* @ifindex: Interface index
|
||||
* @length: Pointer to a variable to store address length
|
||||
*
|
||||
* Saves interface hardware address to @address.
|
||||
* Returns: the interface hardware address as an array of bytes of
|
||||
* length @length.
|
||||
*/
|
||||
gconstpointer
|
||||
nm_platform_link_get_address (NMPlatform *self, int ifindex, size_t *length)
|
||||
|
|
@ -983,6 +1030,34 @@ nm_platform_link_get_address (NMPlatform *self, int ifindex, size_t *length)
|
|||
return klass->link_get_address (self, ifindex, length);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_platform_link_get_permanent_address:
|
||||
* @self: platform instance
|
||||
* @ifindex: Interface index
|
||||
* @buf: buffer of at least %NM_UTILS_HWADDR_LEN_MAX bytes, on success
|
||||
* the permanent hardware address
|
||||
* @length: Pointer to a variable to store address length
|
||||
*
|
||||
* Returns: %TRUE on success, %FALSE on failure to read the permanent hardware
|
||||
* address.
|
||||
*/
|
||||
gboolean
|
||||
nm_platform_link_get_permanent_address (NMPlatform *self, int ifindex, guint8 *buf, size_t *length)
|
||||
{
|
||||
_CHECK_SELF (self, klass, FALSE);
|
||||
reset_error (self);
|
||||
|
||||
if (length)
|
||||
*length = 0;
|
||||
|
||||
g_return_val_if_fail (ifindex > 0, FALSE);
|
||||
g_return_val_if_fail (klass->link_get_permanent_address, FALSE);
|
||||
g_return_val_if_fail (buf, FALSE);
|
||||
g_return_val_if_fail (length, FALSE);
|
||||
|
||||
return klass->link_get_permanent_address (self, ifindex, buf, length);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_platform_link_supports_carrier_detect (NMPlatform *self, int ifindex)
|
||||
{
|
||||
|
|
@ -1195,6 +1270,38 @@ nm_platform_link_get_wake_on_lan (NMPlatform *self, int ifindex)
|
|||
return klass->link_get_wake_on_lan (self, ifindex);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_platform_link_get_driver_info:
|
||||
* @self: platform instance
|
||||
* @ifindex: Interface index
|
||||
* @out_driver_name: (transfer full): on success, the driver name if available
|
||||
* @out_driver_version: (transfer full): on success, the driver version if available
|
||||
* @out_fw_version: (transfer full): on success, the firmware version if available
|
||||
*
|
||||
* Returns: %TRUE on success (though @out_driver_name, @out_driver_version and
|
||||
* @out_fw_version can be %NULL if no information was available), %FALSE on
|
||||
* failure.
|
||||
*/
|
||||
gboolean
|
||||
nm_platform_link_get_driver_info (NMPlatform *self,
|
||||
int ifindex,
|
||||
char **out_driver_name,
|
||||
char **out_driver_version,
|
||||
char **out_fw_version)
|
||||
{
|
||||
_CHECK_SELF (self, klass, FALSE);
|
||||
reset_error (self);
|
||||
|
||||
g_return_val_if_fail (ifindex >= 0, FALSE);
|
||||
g_return_val_if_fail (klass->link_get_driver_info, FALSE);
|
||||
|
||||
return klass->link_get_driver_info (self,
|
||||
ifindex,
|
||||
out_driver_name,
|
||||
out_driver_version,
|
||||
out_fw_version);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_platform_link_enslave:
|
||||
* @self: platform instance
|
||||
|
|
@ -1277,42 +1384,49 @@ nm_platform_link_get_master (NMPlatform *self, int slave)
|
|||
* @name: New interface name
|
||||
* @address: (allow-none): set the mac address of the new bridge
|
||||
* @address_len: the length of the @address
|
||||
* @out_link: on success, the link object
|
||||
*
|
||||
* Create a software bridge.
|
||||
*/
|
||||
gboolean
|
||||
nm_platform_bridge_add (NMPlatform *self, const char *name, const void *address, size_t address_len)
|
||||
nm_platform_bridge_add (NMPlatform *self,
|
||||
const char *name,
|
||||
const void *address,
|
||||
size_t address_len,
|
||||
NMPlatformLink *out_link)
|
||||
{
|
||||
debug ("link: adding bridge '%s'", name);
|
||||
return nm_platform_link_add (self, name, NM_LINK_TYPE_BRIDGE, address, address_len);
|
||||
return nm_platform_link_add (self, name, NM_LINK_TYPE_BRIDGE, address, address_len, out_link);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_platform_bond_add:
|
||||
* @self: platform instance
|
||||
* @name: New interface name
|
||||
* @out_link: on success, the link object
|
||||
*
|
||||
* Create a software bonding device.
|
||||
*/
|
||||
gboolean
|
||||
nm_platform_bond_add (NMPlatform *self, const char *name)
|
||||
nm_platform_bond_add (NMPlatform *self, const char *name, NMPlatformLink *out_link)
|
||||
{
|
||||
debug ("link: adding bond '%s'", name);
|
||||
return nm_platform_link_add (self, name, NM_LINK_TYPE_BOND, NULL, 0);
|
||||
return nm_platform_link_add (self, name, NM_LINK_TYPE_BOND, NULL, 0, out_link);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_platform_team_add:
|
||||
* @self: platform instance
|
||||
* @name: New interface name
|
||||
* @out_link: on success, the link object
|
||||
*
|
||||
* Create a software teaming device.
|
||||
*/
|
||||
gboolean
|
||||
nm_platform_team_add (NMPlatform *self, const char *name)
|
||||
nm_platform_team_add (NMPlatform *self, const char *name, NMPlatformLink *out_link)
|
||||
{
|
||||
debug ("link: adding team '%s'", name);
|
||||
return nm_platform_link_add (self, name, NM_LINK_TYPE_TEAM, NULL, 0);
|
||||
return nm_platform_link_add (self, name, NM_LINK_TYPE_TEAM, NULL, 0, out_link);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1321,11 +1435,17 @@ nm_platform_team_add (NMPlatform *self, const char *name)
|
|||
* @name: New interface name
|
||||
* @vlanid: VLAN identifier
|
||||
* @vlanflags: VLAN flags from libnm
|
||||
* @out_link: on success, the link object
|
||||
*
|
||||
* Create a software VLAN device.
|
||||
*/
|
||||
gboolean
|
||||
nm_platform_vlan_add (NMPlatform *self, const char *name, int parent, int vlanid, guint32 vlanflags)
|
||||
nm_platform_vlan_add (NMPlatform *self,
|
||||
const char *name,
|
||||
int parent,
|
||||
int vlanid,
|
||||
guint32 vlanflags,
|
||||
NMPlatformLink *out_link)
|
||||
{
|
||||
_CHECK_SELF (self, klass, FALSE);
|
||||
reset_error (self);
|
||||
|
|
@ -1343,7 +1463,7 @@ nm_platform_vlan_add (NMPlatform *self, const char *name, int parent, int vlanid
|
|||
|
||||
debug ("link: adding vlan '%s' parent %d vlanid %d vlanflags %x",
|
||||
name, parent, vlanid, vlanflags);
|
||||
return klass->vlan_add (self, name, parent, vlanid, vlanflags);
|
||||
return klass->vlan_add (self, name, parent, vlanid, vlanflags, out_link);
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
|
@ -1444,7 +1564,7 @@ nm_platform_vlan_set_egress_map (NMPlatform *self, int ifindex, int from, int to
|
|||
}
|
||||
|
||||
gboolean
|
||||
nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key)
|
||||
nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key, NMPlatformLink *out_link)
|
||||
{
|
||||
const char *parent_name;
|
||||
char *name;
|
||||
|
|
@ -1471,7 +1591,7 @@ nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key)
|
|||
}
|
||||
g_free (name);
|
||||
|
||||
return klass->infiniband_partition_add (self, parent, p_key);
|
||||
return klass->infiniband_partition_add (self, parent, p_key, out_link);
|
||||
}
|
||||
|
||||
gboolean
|
||||
|
|
|
|||
|
|
@ -374,8 +374,14 @@ typedef struct {
|
|||
char * (*sysctl_get) (NMPlatform *, const char *path);
|
||||
|
||||
gboolean (*link_get) (NMPlatform *platform, int ifindex, NMPlatformLink *link);
|
||||
gboolean (*link_get_by_address) (NMPlatform *platform, gconstpointer address, size_t length, NMPlatformLink *link);
|
||||
GArray *(*link_get_all) (NMPlatform *);
|
||||
gboolean (*link_add) (NMPlatform *, const char *name, NMLinkType type, const void *address, size_t address_len);
|
||||
gboolean (*link_add) (NMPlatform *,
|
||||
const char *name,
|
||||
NMLinkType type,
|
||||
const void *address,
|
||||
size_t address_len,
|
||||
NMPlatformLink *out_link);
|
||||
gboolean (*link_delete) (NMPlatform *, int ifindex);
|
||||
int (*link_get_ifindex) (NMPlatform *, const char *name);
|
||||
const char *(*link_get_name) (NMPlatform *, int ifindex);
|
||||
|
|
@ -399,6 +405,10 @@ typedef struct {
|
|||
gboolean (*link_set_user_ipv6ll_enabled) (NMPlatform *, int ifindex, gboolean enabled);
|
||||
|
||||
gconstpointer (*link_get_address) (NMPlatform *, int ifindex, size_t *length);
|
||||
gboolean (*link_get_permanent_address) (NMPlatform *,
|
||||
int ifindex,
|
||||
guint8 *buf,
|
||||
size_t *length);
|
||||
gboolean (*link_set_address) (NMPlatform *, int ifindex, gconstpointer address, size_t length);
|
||||
guint32 (*link_get_mtu) (NMPlatform *, int ifindex);
|
||||
gboolean (*link_set_mtu) (NMPlatform *, int ifindex, guint32 mtu);
|
||||
|
|
@ -406,6 +416,11 @@ typedef struct {
|
|||
char * (*link_get_physical_port_id) (NMPlatform *, int ifindex);
|
||||
guint (*link_get_dev_id) (NMPlatform *, int ifindex);
|
||||
gboolean (*link_get_wake_on_lan) (NMPlatform *, int ifindex);
|
||||
gboolean (*link_get_driver_info) (NMPlatform *,
|
||||
int ifindex,
|
||||
char **out_driver_name,
|
||||
char **out_driver_version,
|
||||
char **out_fw_version);
|
||||
|
||||
gboolean (*link_supports_carrier_detect) (NMPlatform *, int ifindex);
|
||||
gboolean (*link_supports_vlans) (NMPlatform *, int ifindex);
|
||||
|
|
@ -418,12 +433,12 @@ typedef struct {
|
|||
gboolean (*slave_set_option) (NMPlatform *, int ifindex, const char *option, const char *value);
|
||||
char * (*slave_get_option) (NMPlatform *, int ifindex, const char *option);
|
||||
|
||||
gboolean (*vlan_add) (NMPlatform *, const char *name, int parent, int vlanid, guint32 vlanflags);
|
||||
gboolean (*vlan_add) (NMPlatform *, const char *name, int parent, int vlanid, guint32 vlanflags, NMPlatformLink *out_link);
|
||||
gboolean (*vlan_get_info) (NMPlatform *, int ifindex, int *parent, int *vlan_id);
|
||||
gboolean (*vlan_set_ingress_map) (NMPlatform *, int ifindex, int from, int to);
|
||||
gboolean (*vlan_set_egress_map) (NMPlatform *, int ifindex, int from, int to);
|
||||
|
||||
gboolean (*infiniband_partition_add) (NMPlatform *, int parent, int p_key);
|
||||
gboolean (*infiniband_partition_add) (NMPlatform *, int parent, int p_key, NMPlatformLink *out_link);
|
||||
|
||||
gboolean (*veth_get_properties) (NMPlatform *, int ifindex, NMPlatformVethProperties *properties);
|
||||
gboolean (*tun_get_properties) (NMPlatform *, int ifindex, NMPlatformTunProperties *properties);
|
||||
|
|
@ -526,10 +541,11 @@ gboolean nm_platform_sysctl_set_ip6_hop_limit_safe (NMPlatform *self, const char
|
|||
|
||||
gboolean nm_platform_link_get (NMPlatform *self, int ifindex, NMPlatformLink *link);
|
||||
GArray *nm_platform_link_get_all (NMPlatform *self);
|
||||
gboolean nm_platform_dummy_add (NMPlatform *self, const char *name);
|
||||
gboolean nm_platform_bridge_add (NMPlatform *self, const char *name, const void *address, size_t address_len);
|
||||
gboolean nm_platform_bond_add (NMPlatform *self, const char *name);
|
||||
gboolean nm_platform_team_add (NMPlatform *self, const char *name);
|
||||
gboolean nm_platform_link_get_by_address (NMPlatform *self, gconstpointer address, size_t length, NMPlatformLink *link);
|
||||
gboolean nm_platform_dummy_add (NMPlatform *self, const char *name, NMPlatformLink *out_link);
|
||||
gboolean nm_platform_bridge_add (NMPlatform *self, const char *name, const void *address, size_t address_len, NMPlatformLink *out_link);
|
||||
gboolean nm_platform_bond_add (NMPlatform *self, const char *name, NMPlatformLink *out_link);
|
||||
gboolean nm_platform_team_add (NMPlatform *self, const char *name, NMPlatformLink *out_link);
|
||||
gboolean nm_platform_link_exists (NMPlatform *self, const char *name);
|
||||
gboolean nm_platform_link_delete (NMPlatform *self, int ifindex);
|
||||
int nm_platform_link_get_ifindex (NMPlatform *self, const char *name);
|
||||
|
|
@ -556,6 +572,7 @@ gboolean nm_platform_link_get_user_ipv6ll_enabled (NMPlatform *self, int ifindex
|
|||
gboolean nm_platform_link_set_user_ipv6ll_enabled (NMPlatform *self, int ifindex, gboolean enabled);
|
||||
|
||||
gconstpointer nm_platform_link_get_address (NMPlatform *self, int ifindex, size_t *length);
|
||||
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);
|
||||
guint32 nm_platform_link_get_mtu (NMPlatform *self, int ifindex);
|
||||
gboolean nm_platform_link_set_mtu (NMPlatform *self, int ifindex, guint32 mtu);
|
||||
|
|
@ -563,6 +580,11 @@ gboolean nm_platform_link_set_mtu (NMPlatform *self, int ifindex, guint32 mtu);
|
|||
char *nm_platform_link_get_physical_port_id (NMPlatform *self, int ifindex);
|
||||
guint nm_platform_link_get_dev_id (NMPlatform *self, int ifindex);
|
||||
gboolean nm_platform_link_get_wake_on_lan (NMPlatform *self, int ifindex);
|
||||
gboolean nm_platform_link_get_driver_info (NMPlatform *self,
|
||||
int ifindex,
|
||||
char **out_driver_name,
|
||||
char **out_driver_version,
|
||||
char **out_fw_version);
|
||||
|
||||
gboolean nm_platform_link_supports_carrier_detect (NMPlatform *self, int ifindex);
|
||||
gboolean nm_platform_link_supports_vlans (NMPlatform *self, int ifindex);
|
||||
|
|
@ -575,12 +597,12 @@ char *nm_platform_master_get_option (NMPlatform *self, int ifindex, const char *
|
|||
gboolean nm_platform_slave_set_option (NMPlatform *self, int ifindex, const char *option, const char *value);
|
||||
char *nm_platform_slave_get_option (NMPlatform *self, int ifindex, const char *option);
|
||||
|
||||
gboolean nm_platform_vlan_add (NMPlatform *self, const char *name, int parent, int vlanid, guint32 vlanflags);
|
||||
gboolean nm_platform_vlan_add (NMPlatform *self, const char *name, int parent, int vlanid, guint32 vlanflags, NMPlatformLink *out_link);
|
||||
gboolean nm_platform_vlan_get_info (NMPlatform *self, int ifindex, int *parent, int *vlanid);
|
||||
gboolean nm_platform_vlan_set_ingress_map (NMPlatform *self, int ifindex, int from, int to);
|
||||
gboolean nm_platform_vlan_set_egress_map (NMPlatform *self, int ifindex, int from, int to);
|
||||
|
||||
gboolean nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key);
|
||||
gboolean nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key, NMPlatformLink *out_link);
|
||||
|
||||
gboolean nm_platform_veth_get_properties (NMPlatform *self, int ifindex, NMPlatformVethProperties *properties);
|
||||
gboolean nm_platform_tun_get_properties (NMPlatform *self, int ifindex, NMPlatformTunProperties *properties);
|
||||
|
|
|
|||
|
|
@ -93,25 +93,25 @@ do_link_get_all (char **argv)
|
|||
static gboolean
|
||||
do_dummy_add (char **argv)
|
||||
{
|
||||
return nm_platform_dummy_add (NM_PLATFORM_GET, argv[0]);
|
||||
return nm_platform_dummy_add (NM_PLATFORM_GET, argv[0], NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
do_bridge_add (char **argv)
|
||||
{
|
||||
return nm_platform_bridge_add (NM_PLATFORM_GET, argv[0], NULL, 0);
|
||||
return nm_platform_bridge_add (NM_PLATFORM_GET, argv[0], NULL, 0, NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
do_bond_add (char **argv)
|
||||
{
|
||||
return nm_platform_bond_add (NM_PLATFORM_GET, argv[0]);
|
||||
return nm_platform_bond_add (NM_PLATFORM_GET, argv[0], NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
do_team_add (char **argv)
|
||||
{
|
||||
return nm_platform_team_add (NM_PLATFORM_GET, argv[0]);
|
||||
return nm_platform_team_add (NM_PLATFORM_GET, argv[0], NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
|
@ -122,7 +122,7 @@ do_vlan_add (char **argv)
|
|||
int vlanid = strtol (*argv++, NULL, 10);
|
||||
guint32 vlan_flags = strtol (*argv++, NULL, 10);
|
||||
|
||||
return nm_platform_vlan_add (NM_PLATFORM_GET, name, parent, vlanid, vlan_flags);
|
||||
return nm_platform_vlan_add (NM_PLATFORM_GET, name, parent, vlanid, vlan_flags, NULL);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@ setup_tests (void)
|
|||
|
||||
nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME));
|
||||
g_assert (!nm_platform_link_exists (NM_PLATFORM_GET, DEVICE_NAME));
|
||||
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME));
|
||||
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL));
|
||||
accept_signal (link_added);
|
||||
free_signal (link_added);
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ test_cleanup_internal (void)
|
|||
inet_pton (AF_INET6, "2001:db8:e:f:1:2:3:4", &gateway6);
|
||||
|
||||
/* Create and set up device */
|
||||
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME));
|
||||
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL));
|
||||
accept_signal (link_added);
|
||||
free_signal (link_added);
|
||||
g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME)));
|
||||
|
|
|
|||
|
|
@ -90,13 +90,13 @@ software_add (NMLinkType link_type, const char *name)
|
|||
{
|
||||
switch (link_type) {
|
||||
case NM_LINK_TYPE_DUMMY:
|
||||
return nm_platform_dummy_add (NM_PLATFORM_GET, name);
|
||||
return nm_platform_dummy_add (NM_PLATFORM_GET, name, NULL);
|
||||
case NM_LINK_TYPE_BRIDGE:
|
||||
return nm_platform_bridge_add (NM_PLATFORM_GET, name, NULL, 0);
|
||||
return nm_platform_bridge_add (NM_PLATFORM_GET, name, NULL, 0, NULL);
|
||||
case NM_LINK_TYPE_BOND:
|
||||
{
|
||||
gboolean bond0_exists = nm_platform_link_exists (NM_PLATFORM_GET, "bond0");
|
||||
gboolean result = nm_platform_bond_add (NM_PLATFORM_GET, name);
|
||||
gboolean result = nm_platform_bond_add (NM_PLATFORM_GET, name, NULL);
|
||||
NMPlatformError error = nm_platform_get_error (NM_PLATFORM_GET);
|
||||
|
||||
/* Check that bond0 is *not* automatically created. */
|
||||
|
|
@ -107,14 +107,14 @@ software_add (NMLinkType link_type, const char *name)
|
|||
return result;
|
||||
}
|
||||
case NM_LINK_TYPE_TEAM:
|
||||
return nm_platform_team_add (NM_PLATFORM_GET, name);
|
||||
return nm_platform_team_add (NM_PLATFORM_GET, name, NULL);
|
||||
case NM_LINK_TYPE_VLAN: {
|
||||
SignalData *parent_added;
|
||||
SignalData *parent_changed;
|
||||
|
||||
/* Don't call link_callback for the bridge interface */
|
||||
parent_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, PARENT_NAME);
|
||||
if (nm_platform_bridge_add (NM_PLATFORM_GET, PARENT_NAME, NULL, 0))
|
||||
if (nm_platform_bridge_add (NM_PLATFORM_GET, PARENT_NAME, NULL, 0, NULL))
|
||||
accept_signal (parent_added);
|
||||
free_signal (parent_added);
|
||||
|
||||
|
|
@ -126,7 +126,7 @@ software_add (NMLinkType link_type, const char *name)
|
|||
accept_signal (parent_changed);
|
||||
free_signal (parent_changed);
|
||||
|
||||
return nm_platform_vlan_add (NM_PLATFORM_GET, name, parent_ifindex, VLAN_ID, 0);
|
||||
return nm_platform_vlan_add (NM_PLATFORM_GET, name, parent_ifindex, VLAN_ID, 0, NULL);
|
||||
}
|
||||
}
|
||||
default:
|
||||
|
|
@ -403,12 +403,12 @@ test_internal (void)
|
|||
error (NM_PLATFORM_ERROR_NOT_FOUND);
|
||||
|
||||
/* Add device */
|
||||
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME));
|
||||
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL));
|
||||
no_error ();
|
||||
accept_signal (link_added);
|
||||
|
||||
/* Try to add again */
|
||||
g_assert (!nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME));
|
||||
g_assert (!nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL));
|
||||
error (NM_PLATFORM_ERROR_EXISTS);
|
||||
|
||||
/* Check device index, name and type */
|
||||
|
|
|
|||
|
|
@ -324,7 +324,7 @@ setup_tests (void)
|
|||
|
||||
nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME));
|
||||
g_assert (!nm_platform_link_exists (NM_PLATFORM_GET, DEVICE_NAME));
|
||||
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME));
|
||||
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL));
|
||||
accept_signal (link_added);
|
||||
free_signal (link_added);
|
||||
|
||||
|
|
|
|||
|
|
@ -1590,6 +1590,9 @@ have_connection_for_device (NMSettings *self, NMDevice *device)
|
|||
NMConnection *connection = NM_CONNECTION (data);
|
||||
const char *ctype, *iface;
|
||||
|
||||
if (!nm_device_check_connection_compatible (device, connection))
|
||||
continue;
|
||||
|
||||
s_con = nm_connection_get_setting_connection (connection);
|
||||
|
||||
iface = nm_setting_connection_get_interface_name (s_con);
|
||||
|
|
|
|||
|
|
@ -639,7 +639,7 @@ fixture_setup (test_fixture *fixture, gconstpointer user_data)
|
|||
"nm-test-device0");
|
||||
nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device0"));
|
||||
g_assert (!nm_platform_link_exists (NM_PLATFORM_GET, "nm-test-device0"));
|
||||
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, "nm-test-device0"));
|
||||
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, "nm-test-device0", NULL));
|
||||
accept_signal (link_added);
|
||||
free_signal (link_added);
|
||||
fixture->ifindex0 = nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device0");
|
||||
|
|
@ -651,7 +651,7 @@ fixture_setup (test_fixture *fixture, gconstpointer user_data)
|
|||
"nm-test-device1");
|
||||
nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device1"));
|
||||
g_assert (!nm_platform_link_exists (NM_PLATFORM_GET, "nm-test-device1"));
|
||||
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, "nm-test-device1"));
|
||||
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, "nm-test-device1", NULL));
|
||||
accept_signal (link_added);
|
||||
free_signal (link_added);
|
||||
fixture->ifindex1 = nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device1");
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue