merge: don't wait for udev before announcing links; other cleanups (bgo #747628) (bgo #743209)

(cherry picked from commit 4f05261af8)
This commit is contained in:
Dan Williams 2015-05-01 14:30:58 -05:00 committed by Thomas Haller
commit 752f55d80b
23 changed files with 456 additions and 410 deletions

View file

@ -1,6 +0,0 @@
# do not edit this file, it will be overwritten on update
# The fact that this device is driven by libertas is not currently exposed
# in the sysfs tree..?
KERNEL=="msh*", SUBSYSTEM=="net", DRIVERS=="usb", ATTRS{idVendor}=="1286", ATTRS{idProduct}=="2001", ENV{ID_NM_OLPC_MESH}="1"

View file

@ -37,8 +37,7 @@ examples_DATA = server.conf
if WITH_UDEV_DIR
udevrulesdir = $(UDEV_DIR)/rules.d
udevrules_DATA = \
85-nm-unmanaged.rules \
77-nm-olpc-mesh.rules
85-nm-unmanaged.rules
endif
server.conf: server.conf.in
@ -59,7 +58,6 @@ EXTRA_DIST = \
NetworkManager-dispatcher.service.in \
org.freedesktop.NetworkManager.service.in \
85-nm-unmanaged.rules \
77-nm-olpc-mesh.rules \
server.conf.in
CLEANFILES = \

View file

@ -173,7 +173,7 @@ gint64 nm_utils_get_monotonic_timestamp_us (void);
gint64 nm_utils_get_monotonic_timestamp_ms (void);
gint32 nm_utils_get_monotonic_timestamp_s (void);
const char *ASSERT_VALID_PATH_COMPONENT (const char *name) G_GNUC_WARN_UNUSED_RESULT;
const char *ASSERT_VALID_PATH_COMPONENT (const char *name);
const char *nm_utils_ip6_property_path (const char *ifname, const char *property);
const char *nm_utils_ip4_property_path (const char *ifname, const char *property);

View file

@ -479,6 +479,13 @@ device_state_changed (NMDevice *device,
if (priv->modem)
nm_modem_device_state_changed (priv->modem, new_state, old_state, reason);
/* Need to recheck available connections whenever MM appears or disappears,
* since the device could be both DUN and NAP capable and thus may not
* change state (which rechecks available connections) when MM comes and goes.
*/
if (priv->mm_running && (priv->capabilities & NM_BT_CAPABILITY_DUN))
nm_device_recheck_available_connections (device);
}
static void
@ -943,61 +950,20 @@ is_available (NMDevice *dev, NMDeviceCheckDevAvailableFlags flags)
return priv->mm_running;
}
static void
handle_availability_change (NMDeviceBt *self,
gboolean old_available,
NMDeviceStateReason unavailable_reason)
{
NMDevice *device = NM_DEVICE (self);
NMDeviceState state;
gboolean available;
state = nm_device_get_state (device);
if (state < NM_DEVICE_STATE_UNAVAILABLE) {
_LOGD (LOGD_BT, "availability blocked by UNMANAGED state");
return;
}
available = nm_device_is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE);
if (available == old_available)
return;
if (available) {
if (state != NM_DEVICE_STATE_UNAVAILABLE)
_LOGW (LOGD_CORE | LOGD_BT, "not in expected unavailable state!");
nm_device_state_changed (device,
NM_DEVICE_STATE_DISCONNECTED,
NM_DEVICE_STATE_REASON_NONE);
} else {
nm_device_state_changed (device,
NM_DEVICE_STATE_UNAVAILABLE,
unavailable_reason);
}
}
static void
set_mm_running (NMDeviceBt *self, gboolean running)
{
NMDeviceBtPrivate *priv = NM_DEVICE_BT_GET_PRIVATE (self);
gboolean old_available;
if (priv->mm_running == running)
return;
if (priv->mm_running != running) {
_LOGD (LOGD_BT, "ModemManager now %s",
running ? "available" : "unavailable");
_LOGD (LOGD_BT, "ModemManager now %s",
running ? "available" : "unavailable");
old_available = nm_device_is_available (NM_DEVICE (self), NM_DEVICE_CHECK_DEV_AVAILABLE_NONE);
priv->mm_running = running;
handle_availability_change (self, old_available, NM_DEVICE_STATE_REASON_MODEM_MANAGER_UNAVAILABLE);
/* Need to recheck available connections whenever MM appears or disappears,
* since the device could be both DUN and NAP capable and thus may not
* change state (which rechecks available connections) when MM comes and goes.
*/
if (priv->capabilities & NM_BT_CAPABILITY_DUN)
nm_device_recheck_available_connections (NM_DEVICE (self));
priv->mm_running = running;
nm_device_queue_recheck_available (NM_DEVICE (self),
NM_DEVICE_STATE_REASON_NONE,
NM_DEVICE_STATE_REASON_MODEM_MANAGER_UNAVAILABLE);
}
}
static void

View file

@ -1615,6 +1615,17 @@ carrier_changed (NMDevice *device, gboolean carrier)
NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->carrier_changed (device, carrier);
}
static void
link_changed (NMDevice *device, NMPlatformLink *info)
{
NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device);
NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self);
NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->link_changed (device, info);
if (!priv->subchan1 && info->udi)
_update_s390_subchannels (self);
}
static void
dispose (GObject *object)
{
@ -1714,6 +1725,7 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass)
parent_class->spec_match_list = spec_match_list;
parent_class->update_connection = update_connection;
parent_class->carrier_changed = carrier_changed;
parent_class->link_changed = link_changed;
parent_class->state_changed = device_state_changed;

View file

@ -97,6 +97,9 @@ void nm_device_set_carrier (NMDevice *self, gboolean carrier);
void nm_device_emit_recheck_auto_activate (NMDevice *device);
void nm_device_queue_recheck_assume (NMDevice *device);
void nm_device_queue_recheck_available (NMDevice *device,
NMDeviceStateReason available_reason,
NMDeviceStateReason unavailable_reason);
void nm_device_set_wwan_ip4_config (NMDevice *device, NMIP4Config *config);
void nm_device_set_wwan_ip6_config (NMDevice *device, NMIP6Config *config);

View file

@ -175,6 +175,7 @@ typedef struct {
typedef struct {
gboolean in_state_changed;
gboolean initialized;
gboolean platform_link_initialized;
NMDeviceState state;
NMDeviceStateReason state_reason;
@ -219,6 +220,11 @@ typedef struct {
guint act_source6_id;
gpointer act_source6_func;
guint recheck_assume_id;
struct {
guint call_id;
NMDeviceStateReason available_reason;
NMDeviceStateReason unavailable_reason;
} recheck_available;
struct {
guint call_id;
NMDeviceState post_state;
@ -1037,6 +1043,7 @@ void
nm_device_finish_init (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
gboolean platform_unmanaged = FALSE;
g_assert (priv->initialized == FALSE);
@ -1049,6 +1056,20 @@ nm_device_finish_init (NMDevice *self)
if (priv->master)
nm_device_enslave_slave (priv->master, self, NULL);
if (priv->ifindex > 0) {
if (priv->platform_link_initialized || (priv->is_nm_owned && priv->is_software)) {
nm_platform_link_get_unmanaged (NM_PLATFORM_GET, priv->ifindex, &platform_unmanaged);
nm_device_set_initial_unmanaged_flag (self, NM_UNMANAGED_DEFAULT, platform_unmanaged);
} else {
/* Hardware and externally-created software links stay unmanaged
* until they are fully initialized by the platform. NM created
* links must be available for activation immediately and thus
* do not get the PLATFORM_INIT unmanaged flag set.
*/
nm_device_set_initial_unmanaged_flag (self, NM_UNMANAGED_PLATFORM_INIT, TRUE);
}
}
priv->initialized = TRUE;
}
@ -1241,6 +1262,7 @@ device_link_changed (NMDevice *self, NMPlatformLink *info)
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMUtilsIPv6IfaceId token_iid;
gboolean ip_ifname_changed = FALSE;
gboolean platform_unmanaged = FALSE;
if (info->udi && g_strcmp0 (info->udi, priv->udi)) {
/* Update UDI to what udev gives us */
@ -1249,6 +1271,13 @@ device_link_changed (NMDevice *self, NMPlatformLink *info)
g_object_notify (G_OBJECT (self), NM_DEVICE_UDI);
}
if (g_strcmp0 (info->driver, priv->driver)) {
/* Update driver to what udev gives us */
g_free (priv->driver);
priv->driver = g_strdup (info->driver);
g_object_notify (G_OBJECT (self), NM_DEVICE_DRIVER);
}
/* Update MTU if it has changed. */
if (priv->mtu != info->mtu) {
priv->mtu = info->mtu;
@ -1341,6 +1370,22 @@ device_link_changed (NMDevice *self, NMPlatformLink *info)
}
}
}
if (priv->ifindex > 0 && !priv->platform_link_initialized && info->initialized) {
priv->platform_link_initialized = TRUE;
if (nm_platform_link_get_unmanaged (NM_PLATFORM_GET, priv->ifindex, &platform_unmanaged)) {
nm_device_set_unmanaged (self,
NM_UNMANAGED_DEFAULT,
platform_unmanaged,
NM_DEVICE_STATE_REASON_USER_REQUESTED);
}
nm_device_set_unmanaged (self,
NM_UNMANAGED_PLATFORM_INIT,
FALSE,
NM_DEVICE_STATE_REASON_NOW_MANAGED);
}
}
static void
@ -2302,6 +2347,47 @@ nm_device_queue_recheck_assume (NMDevice *self)
priv->recheck_assume_id = g_idle_add (nm_device_emit_recheck_assume, self);
}
static gboolean
recheck_available (gpointer user_data)
{
NMDevice *self = NM_DEVICE (user_data);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
gboolean now_available = nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE);
NMDeviceState state = nm_device_get_state (self);
NMDeviceState new_state = NM_DEVICE_STATE_UNKNOWN;
priv->recheck_available.call_id = 0;
if (state == NM_DEVICE_STATE_UNAVAILABLE && now_available) {
new_state = NM_DEVICE_STATE_DISCONNECTED;
nm_device_queue_state (self, new_state, priv->recheck_available.available_reason);
} else if (state >= NM_DEVICE_STATE_DISCONNECTED && !now_available) {
new_state = NM_DEVICE_STATE_UNAVAILABLE;
nm_device_queue_state (self, new_state, priv->recheck_available.unavailable_reason);
}
_LOGD (LOGD_DEVICE, "device is %savailable, %s %s",
now_available ? "" : "not ",
new_state == NM_DEVICE_STATE_UNAVAILABLE ? "no change required for" : "will transition to",
state_to_string (new_state == NM_DEVICE_STATE_UNAVAILABLE ? state : new_state));
priv->recheck_available.available_reason = NM_DEVICE_STATE_REASON_NONE;
priv->recheck_available.unavailable_reason = NM_DEVICE_STATE_REASON_NONE;
return G_SOURCE_REMOVE;
}
void
nm_device_queue_recheck_available (NMDevice *self,
NMDeviceStateReason available_reason,
NMDeviceStateReason unavailable_reason)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
priv->recheck_available.available_reason = available_reason;
priv->recheck_available.unavailable_reason = unavailable_reason;
if (!priv->recheck_available.call_id)
priv->recheck_available.call_id = g_idle_add (recheck_available, self);
}
void
nm_device_emit_recheck_auto_activate (NMDevice *self)
{
@ -6919,7 +7005,7 @@ nm_device_set_unmanaged (NMDevice *self,
if (unmanaged)
nm_device_state_changed (self, NM_DEVICE_STATE_UNMANAGED, reason);
else
else if (nm_device_get_state (self) == NM_DEVICE_STATE_UNMANAGED)
nm_device_state_changed (self, NM_DEVICE_STATE_UNAVAILABLE, reason);
}
}
@ -7860,8 +7946,9 @@ _set_state_full (NMDevice *self,
* reasons.
*/
if (nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) {
_LOGD (LOGD_DEVICE, "device is available, will transition to DISCONNECTED");
nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE);
nm_device_queue_recheck_available (self,
NM_DEVICE_STATE_REASON_NONE,
NM_DEVICE_STATE_REASON_NONE);
} else {
if (old_state == NM_DEVICE_STATE_UNMANAGED)
_LOGD (LOGD_DEVICE, "device not yet available for transition to DISCONNECTED");
@ -8496,6 +8583,11 @@ dispose (GObject *object)
priv->recheck_assume_id = 0;
}
if (priv->recheck_available.call_id) {
g_source_remove (priv->recheck_available.call_id);
priv->recheck_available.call_id = 0;
}
link_disconnect_action_cancel (self);
if (priv->con_provider) {
@ -8570,6 +8662,7 @@ set_property (GObject *object, guint prop_id,
priv->up = platform_device->up;
g_free (priv->driver);
priv->driver = g_strdup (platform_device->driver);
priv->platform_link_initialized = platform_device->initialized;
}
break;
case PROP_UDI:

View file

@ -342,6 +342,8 @@ RfKillType nm_device_get_rfkill_type (NMDevice *device);
* @NM_UNMANAGED_USER: %TRUE when unmanaged by user decision (via unmanaged-specs)
* @NM_UNMANAGED_PARENT: %TRUE when unmanaged due to parent device being unmanaged
* @NM_UNMANAGED_EXTERNAL_DOWN: %TRUE when unmanaged because !IFF_UP and not created by NM
* @NM_UNMANAGED_PLATFORM_INIT: %TRUE when unmanaged because platform link not
* yet initialized
*/
typedef enum {
NM_UNMANAGED_NONE = 0x00,
@ -350,6 +352,7 @@ typedef enum {
NM_UNMANAGED_USER = 0x04,
NM_UNMANAGED_PARENT = 0x08,
NM_UNMANAGED_EXTERNAL_DOWN = 0x10,
NM_UNMANAGED_PLATFORM_INIT = 0x20,
/* Boundary value */
__NM_UNMANAGED_LAST,

View file

@ -369,9 +369,9 @@ device_added_cb (NMManager *manager, NMDevice *other, gpointer user_data)
NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
if (!priv->companion && check_companion (self, other)) {
nm_device_state_changed (NM_DEVICE (self),
NM_DEVICE_STATE_DISCONNECTED,
NM_DEVICE_STATE_REASON_NONE);
nm_device_queue_recheck_available (NM_DEVICE (self),
NM_DEVICE_STATE_REASON_NONE,
NM_DEVICE_STATE_REASON_NONE);
nm_device_remove_pending_action (NM_DEVICE (self), "waiting for companion", TRUE);
}
}
@ -399,9 +399,9 @@ find_companion (NMDeviceOlpcMesh *self)
/* Try to find the companion if it's already known to the NMManager */
for (list = nm_manager_get_devices (nm_manager_get ()); list ; list = g_slist_next (list)) {
if (check_companion (self, NM_DEVICE (list->data))) {
nm_device_queue_state (NM_DEVICE (self),
NM_DEVICE_STATE_DISCONNECTED,
NM_DEVICE_STATE_REASON_NONE);
nm_device_queue_recheck_available (NM_DEVICE (self),
NM_DEVICE_STATE_REASON_NONE,
NM_DEVICE_STATE_REASON_NONE);
nm_device_remove_pending_action (NM_DEVICE (self), "waiting for companion", TRUE);
break;
}

View file

@ -2149,6 +2149,7 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface,
NMDevice *device = NM_DEVICE (self);
NMDeviceState devstate;
gboolean scanning;
gboolean recheck_available = FALSE;
if (new_state == old_state)
return;
@ -2168,23 +2169,9 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface,
switch (new_state) {
case NM_SUPPLICANT_INTERFACE_STATE_READY:
_LOGD (LOGD_WIFI_SCAN, "supplicant ready");
recheck_available = TRUE;
priv->scan_interval = SCAN_INTERVAL_MIN;
/* If the interface can now be activated because the supplicant is now
* available, transition to DISCONNECTED.
*/
if ((devstate == NM_DEVICE_STATE_UNAVAILABLE) && nm_device_is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) {
nm_device_state_changed (device,
NM_DEVICE_STATE_DISCONNECTED,
NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE);
}
_LOGD (LOGD_WIFI_SCAN, "supplicant ready, requesting initial scan");
/* Request a scan to get latest results */
cancel_pending_scan (self);
request_wireless_scan (self);
if (old_state < NM_SUPPLICANT_INTERFACE_STATE_READY)
nm_device_remove_pending_action (device, "waiting for supplicant", TRUE);
break;
@ -2244,6 +2231,7 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface,
}
break;
case NM_SUPPLICANT_INTERFACE_STATE_DOWN:
recheck_available = TRUE;
cleanup_association_attempt (self, FALSE);
if (old_state < NM_SUPPLICANT_INTERFACE_STATE_READY)
@ -2256,15 +2244,17 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface,
*/
supplicant_interface_release (self);
supplicant_interface_acquire (self);
nm_device_state_changed (device,
NM_DEVICE_STATE_UNAVAILABLE,
NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
break;
default:
break;
}
if (recheck_available) {
nm_device_queue_recheck_available (NM_DEVICE (device),
NM_DEVICE_STATE_REASON_SUPPLICANT_AVAILABLE,
NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED);
}
/* Signal scanning state changes */
if ( new_state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING
|| old_state == NM_SUPPLICANT_INTERFACE_STATE_SCANNING)

View file

@ -300,19 +300,9 @@ modem_state_cb (NMModem *modem,
nm_device_recheck_available_connections (device);
}
if ((dev_state >= NM_DEVICE_STATE_DISCONNECTED) && !nm_device_is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) {
nm_device_state_changed (device,
NM_DEVICE_STATE_UNAVAILABLE,
NM_DEVICE_STATE_REASON_MODEM_FAILED);
return;
}
if ((dev_state == NM_DEVICE_STATE_UNAVAILABLE) && nm_device_is_available (device, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE)) {
nm_device_state_changed (device,
NM_DEVICE_STATE_DISCONNECTED,
NM_DEVICE_STATE_REASON_MODEM_AVAILABLE);
return;
}
nm_device_queue_recheck_available (device,
NM_DEVICE_STATE_REASON_MODEM_AVAILABLE,
NM_DEVICE_STATE_REASON_MODEM_FAILED);
}
static void

View file

@ -1797,7 +1797,7 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume)
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
const char *iface, *driver, *type_desc;
const GSList *unmanaged_specs;
gboolean user_unmanaged, sleeping, platform_unmanaged;
gboolean user_unmanaged, sleeping;
gboolean enabled = FALSE;
RfKillType rtype;
GSList *iter, *remove = NULL;
@ -1877,9 +1877,6 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume)
user_unmanaged = nm_device_spec_match_list (device, unmanaged_specs);
nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_USER, user_unmanaged);
if (nm_platform_link_get_unmanaged (NM_PLATFORM_GET, nm_device_get_ifindex (device), &platform_unmanaged))
nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_DEFAULT, platform_unmanaged);
sleeping = manager_sleeping (self);
nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_INTERNAL, sleeping);
@ -2212,7 +2209,7 @@ platform_link_added (NMManager *self,
case NM_LINK_TYPE_WIFI:
case NM_LINK_TYPE_WIMAX:
nm_log_info (LOGD_HW, "(%s): '%s' plugin not available; creating generic device",
plink->name, plink->type_name);
plink->name, nm_link_type_to_string (plink->type));
/* fall through */
default:
device = nm_device_generic_new (plink);
@ -2978,9 +2975,9 @@ _internal_activation_failed (NMManager *self,
NMActiveConnection *active,
const char *error_desc)
{
nm_log_warn (LOGD_CORE, "Failed to activate '%s': %s",
nm_connection_get_id (nm_active_connection_get_connection (active)),
error_desc);
nm_log_dbg (LOGD_CORE, "Failed to activate '%s': %s",
nm_connection_get_id (nm_active_connection_get_connection (active)),
error_desc);
if (nm_active_connection_get_state (active) <= NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
nm_active_connection_set_state (active, NM_ACTIVE_CONNECTION_STATE_DEACTIVATING);

View file

@ -49,11 +49,6 @@ typedef struct {
int vlan_id;
} NMFakePlatformLink;
typedef struct {
int ifindex;
NMPlatform *platform;
} NMFakePlatformLinkData;
#define NM_FAKE_PLATFORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_FAKE_PLATFORM, NMFakePlatformPrivate))
G_DEFINE_TYPE (NMFakePlatform, nm_fake_platform, NM_TYPE_PLATFORM)
@ -113,9 +108,10 @@ link_init (NMFakePlatformLink *device, int ifindex, int type, const char *name)
device->link.ifindex = name ? ifindex : 0;
device->link.type = type;
device->link.type_name = type_to_type_name (type);
device->link.kind = type_to_type_name (type);
device->link.driver = type_to_type_name (type);
device->link.udi = device->udi = g_strdup_printf ("fake:%d", ifindex);
device->link.initialized = TRUE;
if (name)
strcpy (device->link.name, name);
switch (device->link.type) {
@ -171,23 +167,6 @@ _nm_platform_link_get (NMPlatform *platform, int ifindex, NMPlatformLink *l)
return !!device;
}
static gboolean
_link_announce (NMFakePlatformLinkData *data)
{
NMFakePlatformLink *device = link_get (data->platform, data->ifindex);
if (device)
g_signal_emit_by_name (data->platform,
NM_PLATFORM_SIGNAL_LINK_CHANGED,
device->link.ifindex,
device,
NM_PLATFORM_SIGNAL_ADDED,
NM_PLATFORM_REASON_INTERNAL);
g_free (data);
return FALSE;
}
static gboolean
link_add (NMPlatform *platform, const char *name, NMLinkType type, const void *address, size_t address_len)
{
@ -198,12 +177,8 @@ link_add (NMPlatform *platform, const char *name, NMLinkType type, const void *a
g_array_append_val (priv->links, device);
if (device.link.ifindex) {
NMFakePlatformLinkData *data = g_new (NMFakePlatformLinkData, 1);
data->ifindex = device.link.ifindex;
data->platform = platform;
g_idle_add ((GSourceFunc) _link_announce, data);
}
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);
return TRUE;
}

View file

@ -111,14 +111,7 @@
#define warning(...) _LOG (LOGL_WARN , _LOG_DOMAIN, NULL, __VA_ARGS__)
#define error(...) _LOG (LOGL_ERR , _LOG_DOMAIN, NULL, __VA_ARGS__)
/******************************************************************/
#define return_type(t, name) \
G_STMT_START { \
if (out_name) \
*out_name = name; \
return t; \
} G_STMT_END
static gboolean tun_get_properties_ifname (NMPlatform *platform, const char *ifname, NMPlatformTunProperties *props);
/******************************************************************
* libnl unility functions and wrappers
@ -462,7 +455,7 @@ udev_get_driver (GUdevDevice *device, int ifindex)
driver = g_udev_device_get_driver (device);
if (driver)
return driver;
goto out;
/* Try the parent */
parent = g_udev_device_get_parent (device);
@ -477,52 +470,18 @@ udev_get_driver (GUdevDevice *device, int ifindex)
if ( (g_strcmp0 (subsys, "ibmebus") == 0)
|| (subsys == NULL)) {
grandparent = g_udev_device_get_parent (parent);
if (grandparent) {
if (grandparent)
driver = g_udev_device_get_driver (grandparent);
}
}
}
}
/* Intern the string so we don't have to worry about memory
* management in NMPlatformLink.
*/
if (driver)
driver = g_intern_string (driver);
g_clear_object (&parent);
g_clear_object (&grandparent);
return driver;
}
static NMLinkType
udev_detect_link_type_from_device (GUdevDevice *udev_device, const char *ifname, int arptype, const char **out_name)
{
const char *prop, *sysfs_path;
g_assert (ifname);
if (!udev_device)
return_type (NM_LINK_TYPE_UNKNOWN, "unknown");
if ( g_udev_device_get_property (udev_device, "ID_NM_OLPC_MESH")
|| g_udev_device_get_sysfs_attr (udev_device, "anycast_mask"))
return_type (NM_LINK_TYPE_OLPC_MESH, "olpc-mesh");
prop = g_udev_device_get_property (udev_device, "DEVTYPE");
sysfs_path = g_udev_device_get_sysfs_path (udev_device);
if (wifi_utils_is_wifi (ifname, sysfs_path, prop))
return_type (NM_LINK_TYPE_WIFI, "wifi");
else if (g_strcmp0 (prop, "wwan") == 0)
return_type (NM_LINK_TYPE_WWAN_ETHERNET, "wwan");
else if (g_strcmp0 (prop, "wimax") == 0)
return_type (NM_LINK_TYPE_WIMAX, "wimax");
if (arptype == ARPHRD_ETHER)
return_type (NM_LINK_TYPE_ETHERNET, "ethernet");
return_type (NM_LINK_TYPE_UNKNOWN, "unknown");
out:
/* Intern the string so we don't have to worry about memory
* management in NMPlatformLink. */
return g_intern_string (driver);
}
/******************************************************************
@ -877,148 +836,195 @@ check_support_user_ipv6ll (NMPlatform *platform)
/* Object type specific utilities */
typedef struct {
const NMLinkType nm_type;
const char *type_string;
/* IFLA_INFO_KIND / rtnl_link_get_type() where applicable; the rtnl type
* should only be specified if the device type can be created without
* additional parameters, and if the device type can be determined from
* the rtnl_type. eg, tun/tap should not be specified since both
* tun and tap devices use "tun", and InfiniBand should not be
* specified because a PKey is required at creation. Drivers set this
* value from their 'struct rtnl_link_ops' structure.
*/
const char *rtnl_type;
/* uevent DEVTYPE where applicable, from /sys/class/net/<ifname>/uevent;
* drivers set this value from their SET_NETDEV_DEV() call and the
* 'struct device_type' name member.
*/
const char *devtype;
} LinkDesc;
static const LinkDesc linktypes[] = {
{ NM_LINK_TYPE_NONE, "none", NULL, NULL },
{ NM_LINK_TYPE_UNKNOWN, "unknown", NULL, NULL },
{ NM_LINK_TYPE_ETHERNET, "ethernet", NULL, NULL },
{ NM_LINK_TYPE_INFINIBAND, "infiniband", NULL, NULL },
{ NM_LINK_TYPE_OLPC_MESH, "olpc-mesh", NULL, NULL },
{ NM_LINK_TYPE_WIFI, "wifi", NULL, "wlan" },
{ NM_LINK_TYPE_WWAN_ETHERNET, "wwan", NULL, "wwan" },
{ NM_LINK_TYPE_WIMAX, "wimax", "wimax", "wimax" },
{ NM_LINK_TYPE_DUMMY, "dummy", "dummy", NULL },
{ NM_LINK_TYPE_GRE, "gre", "gre", NULL },
{ NM_LINK_TYPE_GRETAP, "gretap", "gretap", NULL },
{ NM_LINK_TYPE_IFB, "ifb", "ifb", NULL },
{ NM_LINK_TYPE_LOOPBACK, "loopback", NULL, NULL },
{ NM_LINK_TYPE_MACVLAN, "macvlan", "macvlan", NULL },
{ NM_LINK_TYPE_MACVTAP, "macvtap", "macvtap", NULL },
{ NM_LINK_TYPE_OPENVSWITCH, "openvswitch", "openvswitch", NULL },
{ NM_LINK_TYPE_TAP, "tap", NULL, NULL },
{ NM_LINK_TYPE_TUN, "tun", NULL, NULL },
{ NM_LINK_TYPE_VETH, "veth", "veth", NULL },
{ NM_LINK_TYPE_VLAN, "vlan", "vlan", "vlan" },
{ NM_LINK_TYPE_VXLAN, "vxlan", "vxlan", "vxlan" },
{ NM_LINK_TYPE_BRIDGE, "bridge", "bridge", "bridge" },
{ NM_LINK_TYPE_BOND, "bond", "bond", "bond" },
{ NM_LINK_TYPE_TEAM, "team", "team", NULL },
};
static const char *
type_to_string (NMLinkType type)
nm_link_type_to_rtnl_type_string (NMLinkType type)
{
/* Note that this only has to support virtual types */
switch (type) {
case NM_LINK_TYPE_DUMMY:
return "dummy";
case NM_LINK_TYPE_GRE:
return "gre";
case NM_LINK_TYPE_GRETAP:
return "gretap";
case NM_LINK_TYPE_IFB:
return "ifb";
case NM_LINK_TYPE_MACVLAN:
return "macvlan";
case NM_LINK_TYPE_MACVTAP:
return "macvtap";
case NM_LINK_TYPE_TAP:
return "tap";
case NM_LINK_TYPE_TUN:
return "tun";
case NM_LINK_TYPE_VETH:
return "veth";
case NM_LINK_TYPE_VLAN:
return "vlan";
case NM_LINK_TYPE_VXLAN:
return "vxlan";
case NM_LINK_TYPE_BRIDGE:
return "bridge";
case NM_LINK_TYPE_BOND:
return "bond";
case NM_LINK_TYPE_TEAM:
return "team";
default:
g_warning ("Wrong type: %d", type);
return NULL;
int i;
for (i = 0; i < G_N_ELEMENTS (linktypes); i++) {
if (type == linktypes[i].nm_type)
return linktypes[i].rtnl_type;
}
g_return_val_if_reached (NULL);
}
static gboolean
link_is_announceable (NMPlatform *platform, struct rtnl_link *rtnllink)
const char *
nm_link_type_to_string (NMLinkType type)
{
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
int i;
/* Hardware devices must be found by udev so rules get run and tags set */
if (g_hash_table_lookup (priv->udev_devices,
GINT_TO_POINTER (rtnl_link_get_ifindex (rtnllink))))
return TRUE;
for (i = 0; i < G_N_ELEMENTS (linktypes); i++) {
if (type == linktypes[i].nm_type)
return linktypes[i].type_string;
}
g_return_val_if_reached (NULL);
}
return FALSE;
#define DEVTYPE_PREFIX "DEVTYPE="
static char *
read_devtype (const char *sysfs_path)
{
gs_free char *uevent = g_strdup_printf ("%s/uevent", sysfs_path);
char *contents = NULL;
char *cont, *end;
if (!g_file_get_contents (uevent, &contents, NULL, NULL))
return NULL;
for (cont = contents; cont; cont = end) {
end = strpbrk (cont, "\r\n");
if (end)
*end++ = '\0';
if (strncmp (cont, DEVTYPE_PREFIX, STRLEN (DEVTYPE_PREFIX)) == 0) {
cont += STRLEN (DEVTYPE_PREFIX);
memmove (contents, cont, strlen (cont) + 1);
return contents;
}
}
g_free (contents);
return NULL;
}
static NMLinkType
link_extract_type (NMPlatform *platform, struct rtnl_link *rtnllink, const char **out_name)
link_extract_type (NMPlatform *platform, struct rtnl_link *rtnllink)
{
const char *type;
const char *rtnl_type, *ifname;
int i, arptype;
if (!rtnllink)
return_type (NM_LINK_TYPE_NONE, NULL);
return NM_LINK_TYPE_NONE;
type = rtnl_link_get_type (rtnllink);
rtnl_type = rtnl_link_get_type (rtnllink);
if (rtnl_type) {
for (i = 0; i < G_N_ELEMENTS (linktypes); i++) {
if (g_strcmp0 (rtnl_type, linktypes[i].rtnl_type) == 0)
return linktypes[i].nm_type;
}
if (!type) {
int arptype = rtnl_link_get_arptype (rtnllink);
const char *driver;
const char *ifname;
GUdevDevice *udev_device = NULL;
if (!strcmp (rtnl_type, "tun")) {
NMPlatformTunProperties props;
guint flags;
if (arptype == ARPHRD_LOOPBACK)
return_type (NM_LINK_TYPE_LOOPBACK, "loopback");
else if (arptype == ARPHRD_INFINIBAND)
return_type (NM_LINK_TYPE_INFINIBAND, "infiniband");
if (tun_get_properties_ifname (platform, rtnl_link_get_name (rtnllink), &props)) {
if (!g_strcmp0 (props.mode, "tap"))
return NM_LINK_TYPE_TAP;
if (!g_strcmp0 (props.mode, "tun"))
return NM_LINK_TYPE_TUN;
}
flags = rtnl_link_get_flags (rtnllink);
ifname = rtnl_link_get_name (rtnllink);
if (!ifname)
return_type (NM_LINK_TYPE_UNKNOWN, type);
nm_log_dbg (LOGD_PLATFORM, "Failed to read tun properties for interface %d (link flags: %X)",
rtnl_link_get_ifindex (rtnllink), flags);
/* try guessing the type using the link flags instead... */
if (flags & IFF_POINTOPOINT)
return NM_LINK_TYPE_TUN;
return NM_LINK_TYPE_TAP;
}
}
arptype = rtnl_link_get_arptype (rtnllink);
if (arptype == ARPHRD_LOOPBACK)
return NM_LINK_TYPE_LOOPBACK;
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 *sysfs_path = NULL;
gs_free char *anycast_mask = NULL;
gs_free char *devtype = NULL;
driver = ethtool_get_driver (ifname);
if (arptype == 256) {
/* Some s390 CTC-type devices report 256 for the encapsulation type
* for some reason, but we need to call them Ethernet.
*/
if (!g_strcmp0 (driver, "ctcm"))
return_type (NM_LINK_TYPE_ETHERNET, "ethernet");
return NM_LINK_TYPE_ETHERNET;
}
/* Fallback OVS detection for kernel <= 3.16 */
if (!g_strcmp0 (driver, "openvswitch"))
return_type (NM_LINK_TYPE_OPENVSWITCH, "openvswitch");
return NM_LINK_TYPE_OPENVSWITCH;
if (platform) {
udev_device = g_hash_table_lookup (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->udev_devices,
GINT_TO_POINTER (rtnl_link_get_ifindex (rtnllink)));
sysfs_path = g_strdup_printf ("/sys/class/net/%s", ifname);
anycast_mask = g_strdup_printf ("%s/anycast_mask", sysfs_path);
if (g_file_test (anycast_mask, G_FILE_TEST_EXISTS))
return NM_LINK_TYPE_OLPC_MESH;
devtype = read_devtype (sysfs_path);
for (i = 0; devtype && i < G_N_ELEMENTS (linktypes); i++) {
if (g_strcmp0 (devtype, linktypes[i].devtype) == 0)
return linktypes[i].nm_type;
}
return udev_detect_link_type_from_device (udev_device,
ifname,
arptype,
out_name);
} else if (!strcmp (type, "dummy"))
return_type (NM_LINK_TYPE_DUMMY, "dummy");
else if (!strcmp (type, "gre"))
return_type (NM_LINK_TYPE_GRE, "gre");
else if (!strcmp (type, "gretap"))
return_type (NM_LINK_TYPE_GRETAP, "gretap");
else if (!strcmp (type, "ifb"))
return_type (NM_LINK_TYPE_IFB, "ifb");
else if (!strcmp (type, "macvlan"))
return_type (NM_LINK_TYPE_MACVLAN, "macvlan");
else if (!strcmp (type, "macvtap"))
return_type (NM_LINK_TYPE_MACVTAP, "macvtap");
else if (!strcmp (type, "tun")) {
NMPlatformTunProperties props;
guint flags;
if (nm_platform_tun_get_properties (platform, rtnl_link_get_ifindex (rtnllink), &props)) {
if (!g_strcmp0 (props.mode, "tap"))
return_type (NM_LINK_TYPE_TAP, "tap");
if (!g_strcmp0 (props.mode, "tun"))
return_type (NM_LINK_TYPE_TUN, "tun");
}
flags = rtnl_link_get_flags (rtnllink);
/* Fallback for drivers that don't call SET_NETDEV_DEVTYPE() */
if (wifi_utils_is_wifi (ifname, sysfs_path))
return NM_LINK_TYPE_WIFI;
nm_log_dbg (LOGD_PLATFORM, "Failed to read tun properties for interface %d (link flags: %X)",
rtnl_link_get_ifindex (rtnllink), flags);
/* Standard wired ethernet interfaces don't report an rtnl_link_type, so
* only allow fallback to Ethernet if no type is given. This should
* prevent future virtual network drivers from being treated as Ethernet
* when they should be Generic instead.
*/
if (arptype == ARPHRD_ETHER && !rtnl_type && !devtype)
return NM_LINK_TYPE_ETHERNET;
}
/* try guessing the type using the link flags instead... */
if (flags & IFF_POINTOPOINT)
return_type (NM_LINK_TYPE_TUN, "tun");
return_type (NM_LINK_TYPE_TAP, "tap");
} else if (!strcmp (type, "veth"))
return_type (NM_LINK_TYPE_VETH, "veth");
else if (!strcmp (type, "vlan"))
return_type (NM_LINK_TYPE_VLAN, "vlan");
else if (!strcmp (type, "vxlan"))
return_type (NM_LINK_TYPE_VXLAN, "vxlan");
else if (!strcmp (type, "bridge"))
return_type (NM_LINK_TYPE_BRIDGE, "bridge");
else if (!strcmp (type, "bond"))
return_type (NM_LINK_TYPE_BOND, "bond");
else if (!strcmp (type, "team"))
return_type (NM_LINK_TYPE_TEAM, "team");
return_type (NM_LINK_TYPE_UNKNOWN, type);
return NM_LINK_TYPE_UNKNOWN;
}
static gboolean
@ -1038,7 +1044,8 @@ init_link (NMPlatform *platform, NMPlatformLink *info, struct rtnl_link *rtnllin
g_strlcpy (info->name, name, sizeof (info->name));
else
info->name[0] = '\0';
info->type = link_extract_type (platform, rtnllink, &info->type_name);
info->type = link_extract_type (platform, rtnllink);
info->kind = g_intern_string (rtnl_link_get_type (rtnllink));
info->up = !!(rtnl_link_get_flags (rtnllink) & IFF_UP);
info->connected = !!(rtnl_link_get_flags (rtnllink) & IFF_LOWER_UP);
info->arp = !(rtnl_link_get_flags (rtnllink) & IFF_NOARP);
@ -1049,15 +1056,17 @@ init_link (NMPlatform *platform, NMPlatformLink *info, struct rtnl_link *rtnllin
udev_device = g_hash_table_lookup (priv->udev_devices, GINT_TO_POINTER (info->ifindex));
if (udev_device) {
info->driver = udev_get_driver (udev_device, info->ifindex);
if (!info->driver)
info->driver = g_intern_string (rtnl_link_get_type (rtnllink));
if (!info->driver)
info->driver = ethtool_get_driver (info->name);
if (!info->driver)
info->driver = "unknown";
info->udi = g_udev_device_get_sysfs_path (udev_device);
info->initialized = TRUE;
}
if (!info->driver)
info->driver = info->kind;
if (!info->driver)
info->driver = ethtool_get_driver (info->name);
if (!info->driver)
info->driver = "unknown";
return TRUE;
}
@ -1615,22 +1624,6 @@ announce_object (NMPlatform *platform, const struct nl_object *object, NMPlatfor
if (!init_link (platform, &device, rtnl_link))
return;
/* Skip devices not yet discovered by udev. They will be
* announced by udev_device_added(). This doesn't apply to removed
* devices, as those come either from udev_device_removed(),
* event_notification() or link_delete() which block the announcment
* themselves when appropriate.
*/
switch (change_type) {
case NM_PLATFORM_SIGNAL_ADDED:
case NM_PLATFORM_SIGNAL_CHANGED:
if (!device.driver)
return;
break;
default:
break;
}
/* Link deletion or setting down is sometimes accompanied by address
* and/or route deletion.
*
@ -2058,15 +2051,12 @@ event_notification (struct nl_msg *msg, gpointer user_data)
return NL_OK;
nl_cache_remove (cached_object);
/* Don't announce removed interfaces that are not recognized by
* udev. They were either not yet discovered or they have been
* already removed and announced.
*/
if (event == RTM_DELLINK) {
if (!link_is_announceable (platform, (struct rtnl_link *) cached_object))
return NL_OK;
}
announce_object (platform, cached_object, NM_PLATFORM_SIGNAL_REMOVED, NM_PLATFORM_REASON_EXTERNAL);
if (event == RTM_DELLINK) {
int ifindex = rtnl_link_get_ifindex ((struct rtnl_link *) cached_object);
g_hash_table_remove (priv->udev_devices, GINT_TO_POINTER (ifindex));
}
return NL_OK;
case RTM_NEWLINK:
@ -2294,12 +2284,8 @@ link_get_all (NMPlatform *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;
if (link_is_announceable (platform, rtnl_link)) {
if (init_link (platform, &device, rtnl_link))
g_array_append_val (links, device);
}
if (init_link (platform, &device, (struct rtnl_link *) object))
g_array_append_val (links, device);
}
return links;
@ -2312,13 +2298,7 @@ _nm_platform_link_get (NMPlatform *platform, int ifindex, NMPlatformLink *l)
auto_nl_object struct rtnl_link *rtnllink = NULL;
rtnllink = rtnl_link_get (priv->link_cache, ifindex);
if (rtnllink) {
if (link_is_announceable (platform, rtnllink)) {
if (init_link (platform, l, rtnllink))
return TRUE;
}
}
return FALSE;
return (rtnllink && init_link (platform, l, rtnllink));
}
static struct nl_object *
@ -2329,7 +2309,7 @@ build_rtnl_link (int ifindex, const char *name, NMLinkType type)
rtnllink = _nm_rtnl_link_alloc (ifindex, name);
if (type) {
nle = rtnl_link_set_type (rtnllink, type_to_string (type));
nle = rtnl_link_set_type (rtnllink, nm_link_type_to_rtnl_type_string (type));
g_assert (!nle);
}
return (struct nl_object *) rtnllink;
@ -2353,7 +2333,7 @@ link_add (NMPlatform *platform, const char *name, NMLinkType type, const void *a
}
debug ("link: add link '%s' of type '%s' (%d)",
name, type_to_string (type), (int) type);
name, nm_link_type_to_string (type), (int) type);
l = build_rtnl_link (0, name, type);
@ -2377,13 +2357,6 @@ link_get (NMPlatform *platform, int ifindex)
return NULL;
}
/* physical interfaces must be found by udev before they can be used */
if (!link_is_announceable (platform, rtnllink)) {
platform->error = NM_PLATFORM_ERROR_NOT_FOUND;
rtnl_link_put (rtnllink);
return NULL;
}
return rtnllink;
}
@ -2460,17 +2433,33 @@ link_get_type (NMPlatform *platform, int ifindex)
{
auto_nl_object struct rtnl_link *rtnllink = link_get (platform, ifindex);
return link_extract_type (platform, rtnllink, NULL);
return link_extract_type (platform, rtnllink);
}
static const char *
link_get_type_name (NMPlatform *platform, int ifindex)
{
auto_nl_object struct rtnl_link *rtnllink = link_get (platform, ifindex);
const char *type;
NMLinkType link_type;
const char *l;
link_extract_type (platform, rtnllink, &type);
return type;
if (!rtnllink)
return NULL;
link_type = link_extract_type (platform, rtnllink);
if (link_type != NM_LINK_TYPE_UNKNOWN) {
/* We could detect the @link_type. In this case the function returns
* our internel module names, which differs from rtnl_link_get_type():
* - NM_LINK_TYPE_INFINIBAND (gives "infiniband", instead of "ipoib")
* - NM_LINK_TYPE_TAP (gives "tap", instead of "tun").
* Note that this functions is only used by NMDeviceGeneric to
* set type_description. */
return nm_link_type_to_string (link_type);
}
/* Link type not detected. Fallback to rtnl_link_get_type()/IFLA_INFO_KIND. */
l = rtnl_link_get_type (rtnllink);
return l ? g_intern_string (l) : "unknown";
}
static gboolean
@ -3080,9 +3069,8 @@ veth_get_properties (NMPlatform *platform, int ifindex, NMPlatformVethProperties
}
static gboolean
tun_get_properties (NMPlatform *platform, int ifindex, NMPlatformTunProperties *props)
tun_get_properties_ifname (NMPlatform *platform, const char *ifname, NMPlatformTunProperties *props)
{
const char *ifname;
char *path, *val;
gboolean success = TRUE;
@ -3092,7 +3080,6 @@ tun_get_properties (NMPlatform *platform, int ifindex, NMPlatformTunProperties *
props->owner = -1;
props->group = -1;
ifname = nm_platform_link_get_name (platform, ifindex);
if (!ifname || !nm_utils_iface_valid_name (ifname))
return FALSE;
ifname = ASSERT_VALID_PATH_COMPONENT (ifname);
@ -3143,6 +3130,12 @@ tun_get_properties (NMPlatform *platform, int ifindex, NMPlatformTunProperties *
return success;
}
static gboolean
tun_get_properties (NMPlatform *platform, int ifindex, NMPlatformTunProperties *props)
{
return tun_get_properties_ifname (platform, nm_platform_link_get_name (platform, ifindex), props);
}
static const struct nla_policy macvlan_info_policy[IFLA_MACVLAN_MAX + 1] = {
[IFLA_MACVLAN_MODE] = { .type = NLA_U32 },
#ifdef MACVLAN_FLAG_NOPROMISC
@ -4413,7 +4406,6 @@ udev_device_added (NMPlatform *platform,
auto_nl_object struct rtnl_link *rtnllink = NULL;
const char *ifname;
int ifindex;
gboolean was_announceable = FALSE;
ifname = g_udev_device_get_name (udev_device);
if (!ifname) {
@ -4438,15 +4430,15 @@ udev_device_added (NMPlatform *platform,
}
rtnllink = rtnl_link_get (priv->link_cache, ifindex);
if (rtnllink)
was_announceable = link_is_announceable (platform, rtnllink);
if (!rtnllink) {
warning ("(%s): udev-add: interface not known via netlink; ignoring...", ifname);
return;
}
g_hash_table_insert (priv->udev_devices, GINT_TO_POINTER (ifindex),
g_object_ref (udev_device));
/* Announce devices only if they also have been discovered via Netlink. */
if (rtnllink && link_is_announceable (platform, rtnllink))
announce_object (platform, (struct nl_object *) rtnllink, was_announceable ? NM_PLATFORM_SIGNAL_CHANGED : NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_EXTERNAL);
announce_object (platform, (struct nl_object *) rtnllink, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_EXTERNAL);
}
static void
@ -4454,9 +4446,7 @@ udev_device_removed (NMPlatform *platform,
GUdevDevice *udev_device)
{
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
auto_nl_object struct rtnl_link *rtnllink = NULL;
int ifindex = 0;
gboolean was_announceable = FALSE;
if (g_udev_device_get_property (udev_device, "IFINDEX"))
ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX");
@ -4481,15 +4471,7 @@ udev_device_removed (NMPlatform *platform,
if (ifindex <= 0)
return;
rtnllink = rtnl_link_get (priv->link_cache, ifindex);
if (rtnllink)
was_announceable = link_is_announceable (platform, rtnllink);
g_hash_table_remove (priv->udev_devices, GINT_TO_POINTER (ifindex));
/* Announce device removal if it is no longer announceable. */
if (was_announceable && !link_is_announceable (platform, rtnllink))
announce_object (platform, (struct nl_object *) rtnllink, NM_PLATFORM_SIGNAL_REMOVED, NM_PLATFORM_REASON_EXTERNAL);
}
static void
@ -4534,8 +4516,6 @@ constructed (GObject *_object)
NMPlatform *platform = NM_PLATFORM (_object);
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
const char *udev_subsys[] = { "net", NULL };
GUdevEnumerator *enumerator;
GList *devices, *iter;
int channel_flags;
gboolean status;
int nle;
@ -4595,6 +4575,24 @@ constructed (GObject *_object)
g_signal_connect (priv->udev_client, "uevent", G_CALLBACK (handle_udev_event), platform);
priv->udev_devices = g_hash_table_new_full (NULL, NULL, NULL, g_object_unref);
/* request all IPv6 addresses (hopeing that there is at least one), to check for
* the IFA_FLAGS attribute. */
nle = nl_rtgen_request (priv->nlh_event, RTM_GETADDR, AF_INET6, NLM_F_DUMP);
if (nle < 0)
nm_log_warn (LOGD_PLATFORM, "Netlink error: requesting RTM_GETADDR failed with %s", nl_geterror (nle));
priv->wifi_data = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) wifi_utils_deinit);
G_OBJECT_CLASS (nm_linux_platform_parent_class)->constructed (_object);
}
static void
setup_devices (NMPlatform *platform)
{
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
GUdevEnumerator *enumerator;
GList *devices, *iter;
/* And read initial device list */
enumerator = g_udev_enumerator_new (priv->udev_client);
g_udev_enumerator_add_match_subsystem (enumerator, "net");
@ -4612,16 +4610,6 @@ constructed (GObject *_object)
}
g_list_free (devices);
g_object_unref (enumerator);
/* request all IPv6 addresses (hopeing that there is at least one), to check for
* the IFA_FLAGS attribute. */
nle = nl_rtgen_request (priv->nlh_event, RTM_GETADDR, AF_INET6, NLM_F_DUMP);
if (nle < 0)
nm_log_warn (LOGD_PLATFORM, "Netlink error: requesting RTM_GETADDR failed with %s", nl_geterror (nle));
priv->wifi_data = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) wifi_utils_deinit);
G_OBJECT_CLASS (nm_linux_platform_parent_class)->constructed (_object);
}
static void
@ -4659,6 +4647,8 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
object_class->constructed = constructed;
object_class->finalize = nm_linux_platform_finalize;
platform_class->setup_devices = setup_devices;
platform_class->sysctl_set = sysctl_set;
platform_class->sysctl_get = sysctl_get;

View file

@ -407,6 +407,10 @@ nm_platform_query_devices (NMPlatform *self)
NM_PLATFORM_REASON_INTERNAL);
}
g_array_unref (links_array);
/* Platform specific device setup. */
if (klass->setup_devices)
klass->setup_devices (self);
}
/**
@ -2526,7 +2530,7 @@ nm_platform_link_to_string (const NMPlatformLink *link)
{
char master[20];
char parent[20];
char *driver, *udi, *type;
char *driver, *udi;
GString *str;
if (!link)
@ -2554,16 +2558,20 @@ nm_platform_link_to_string (const NMPlatformLink *link)
driver = link->driver ? g_strdup_printf (" driver '%s'", link->driver) : NULL;
udi = link->udi ? g_strdup_printf (" udi '%s'", link->udi) : NULL;
type = link->type_name ? NULL : g_strdup_printf ("(%d)", link->type);
g_snprintf (to_string_buffer, sizeof (to_string_buffer), "%d: %s%s <%s> mtu %d%s %s%s%s",
g_snprintf (to_string_buffer, sizeof (to_string_buffer), "%d: %s%s <%s> mtu %d%s "
"%s" /* link->type */
"%s%s" /* kind */
"%s%s",
link->ifindex, link->name, parent, str->str,
link->mtu, master, link->type_name ? link->type_name : type,
link->mtu, master,
nm_link_type_to_string (link->type),
link->type != NM_LINK_TYPE_UNKNOWN && link->kind ? " kind " : "",
link->type != NM_LINK_TYPE_UNKNOWN && link->kind ? link->kind : "",
driver ? driver : "", udi ? udi : "");
g_string_free (str, TRUE);
g_free (driver);
g_free (udi);
g_free (type);
return to_string_buffer;
}
@ -2794,6 +2802,12 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route)
return (((a)->field) < ((b)->field)) ? -1 : 1; \
} G_STMT_END
#define _CMP_FIELD_BOOL(a, b, field) \
G_STMT_START { \
if ((!((a)->field)) != (!((b)->field))) \
return ((!((a)->field)) < (!((b)->field))) ? -1 : 1; \
} G_STMT_END
#define _CMP_FIELD_STR(a, b, field) \
G_STMT_START { \
int c = strcmp ((a)->field, (b)->field); \
@ -2801,6 +2815,16 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route)
return c < 0 ? -1 : 1; \
} G_STMT_END
#define _CMP_FIELD_STR_INTERNED(a, b, field) \
G_STMT_START { \
if (((a)->field) != ((b)->field)) { \
/* just to be sure, also do a strcmp() if the pointers don't match */ \
int c = g_strcmp0 ((a)->field, (b)->field); \
if (c != 0) \
return c < 0 ? -1 : 1; \
} \
} G_STMT_END
#define _CMP_FIELD_STR0(a, b, field) \
G_STMT_START { \
int c = g_strcmp0 ((a)->field, (b)->field); \
@ -2829,9 +2853,10 @@ nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b)
_CMP_FIELD (a, b, connected);
_CMP_FIELD (a, b, arp);
_CMP_FIELD (a, b, mtu);
_CMP_FIELD_STR0 (a, b, type_name);
_CMP_FIELD_BOOL (a, b, initialized);
_CMP_FIELD_STR_INTERNED (a, b, kind);
_CMP_FIELD_STR0 (a, b, udi);
_CMP_FIELD_STR0 (a, b, driver);
_CMP_FIELD_STR_INTERNED (a, b, driver);
return 0;
}

View file

@ -85,9 +85,19 @@ struct _NMPlatformLink {
__NMPlatformObject_COMMON;
char name[IFNAMSIZ];
NMLinkType type;
const char *type_name;
/* rtnl_link_get_type(), IFLA_INFO_KIND. */
/* NMPlatform initializes this field with a static string. */
const char *kind;
/* Beware: NMPlatform initializes this string with an allocated string.
* Handle it properly (i.e. don't keep a reference to it). */
const char *udi;
/* NMPlatform initializes this field with a static string. */
const char *driver;
gboolean initialized;
int master;
int parent;
gboolean up;
@ -358,6 +368,8 @@ struct _NMPlatform {
typedef struct {
GObjectClass parent;
void (*setup_devices) (NMPlatform *);
gboolean (*sysctl_set) (NMPlatform *, const char *path, const char *value);
char * (*sysctl_get) (NMPlatform *, const char *path);
@ -496,6 +508,8 @@ NMPlatform *nm_platform_try_get (void);
/******************************************************************/
const char *nm_link_type_to_string (NMLinkType link_type);
void nm_platform_set_error (NMPlatform *self, NMPlatformError error);
NMPlatformError nm_platform_get_error (NMPlatform *self);
const char *nm_platform_get_error_msg (NMPlatform *self);

View file

@ -28,7 +28,7 @@ dump_interface (NMPlatformLink *link)
g_assert (link->up || !link->connected);
printf ("%d: %s: %s", link->ifindex, link->name, link->type_name);
printf ("%d: %s: %s", link->ifindex, link->name, nm_link_type_to_string (link->type));
if (link->up)
printf (" %s", link->connected ? "CONNECTED" : "DISCONNECTED");
else

View file

@ -256,7 +256,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));
wait_signal (link_added);
accept_signal (link_added);
free_signal (link_added);
g_test_add_func ("/address/internal/ip4", test_ip4_address);

View file

@ -36,7 +36,7 @@ test_cleanup_internal (void)
/* Create and set up device */
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME));
wait_signal (link_added);
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)));
ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);

View file

@ -115,7 +115,7 @@ software_add (NMLinkType link_type, const char *name)
/* 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))
wait_signal (parent_added);
accept_signal (parent_added);
free_signal (parent_added);
{
@ -148,7 +148,7 @@ test_slave (int master, int type, SignalData *master_changed)
g_assert (ifindex > 0);
link_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, link_callback, ifindex);
link_removed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, link_callback, ifindex);
wait_signal (link_added);
accept_signal (link_added);
/* Set the slave up to see whether master's IFF_LOWER_UP is set correctly.
*
@ -263,7 +263,7 @@ test_software (NMLinkType link_type, const char *link_typename)
link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME);
g_assert (software_add (link_type, DEVICE_NAME));
no_error ();
wait_signal (link_added);
accept_signal (link_added);
g_assert (nm_platform_link_exists (NM_PLATFORM_GET, DEVICE_NAME));
ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
g_assert (ifindex >= 0);
@ -405,7 +405,7 @@ test_internal (void)
/* Add device */
g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME));
no_error ();
wait_signal (link_added);
accept_signal (link_added);
/* Try to add again */
g_assert (!nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME));
@ -485,6 +485,7 @@ test_external (void)
run_command ("ip link add %s type %s", DEVICE_NAME, "dummy");
wait_signal (link_added);
g_assert (nm_platform_link_exists (NM_PLATFORM_GET, DEVICE_NAME));
ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
g_assert (ifindex > 0);
@ -496,7 +497,7 @@ test_external (void)
success = nm_platform_link_get (NM_PLATFORM_GET, ifindex, &link);
g_assert (success);
if (!link.driver) {
if (!link.initialized) {
/* we still lack the notification via UDEV. Expect another link changed signal. */
wait_signal (link_changed);
}
@ -505,8 +506,10 @@ test_external (void)
g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
g_assert (!nm_platform_link_uses_arp (NM_PLATFORM_GET, ifindex));
run_command ("ip link set %s up", DEVICE_NAME);
wait_signal (link_changed);
g_assert (nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
g_assert (nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
run_command ("ip link set %s down", DEVICE_NAME);

View file

@ -321,7 +321,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));
wait_signal (link_added);
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)));

View file

@ -162,20 +162,13 @@ wifi_utils_deinit (WifiData *data)
}
gboolean
wifi_utils_is_wifi (const char *iface, const char *sysfs_path, const char *devtype)
wifi_utils_is_wifi (const char *iface, const char *sysfs_path)
{
char phy80211_path[255];
struct stat s;
g_return_val_if_fail (iface != NULL, FALSE);
if (g_strcmp0 (devtype, "wlan") == 0) {
/* All Wi-Fi drivers should set DEVTYPE=wlan. Since the kernel's
* cfg80211/nl80211 stack does, this check should match any nl80211
* capable driver (including mac82011-based ones). */
return TRUE;
}
if (sysfs_path) {
/* Check for nl80211 sysfs paths */
g_snprintf (phy80211_path, sizeof (phy80211_path), "%s/phy80211", sysfs_path);

View file

@ -29,7 +29,7 @@
typedef struct WifiData WifiData;
gboolean wifi_utils_is_wifi (const char *iface, const char *sysfs_path, const char *devtype);
gboolean wifi_utils_is_wifi (const char *iface, const char *sysfs_path);
WifiData *wifi_utils_init (const char *iface, int ifindex, gboolean check_scan);