summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrancesco Giudici <fgiudici@redhat.com>2016-09-10 16:58:10 +0200
committerFrancesco Giudici <fgiudici@redhat.com>2016-11-22 15:24:47 +0100
commit173819b73db3f76f97c021a5b25def6c6886a64e (patch)
tree13074880732464e590a34260b2e3db176b51bffa
parent61faa5080e47b75d3ca6d93a88afbdb49d2347f8 (diff)
downloadNetworkManager-173819b73db3f76f97c021a5b25def6c6886a64e.tar.gz
device/ethernet: check and apply link negotiation properties
This will allow to enforce link mode (autonegotiation, speed and duplex) as specified in 802-3-ethernet properties.
-rw-r--r--src/devices/nm-device-ethernet.c93
1 files changed, 93 insertions, 0 deletions
diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c
index d01176b235..fb6467a23f 100644
--- a/src/devices/nm-device-ethernet.c
+++ b/src/devices/nm-device-ethernet.c
@@ -782,6 +782,97 @@ supplicant_interface_init (NMDeviceEthernet *self)
return TRUE;
}
+static const char *
+link_duplex_to_string (NMPlatformLinkDuplexType duplex)
+{
+ switch (duplex) {
+ case NM_PLATFORM_LINK_DUPLEX_FULL:
+ return "full";
+ break;
+ case NM_PLATFORM_LINK_DUPLEX_HALF:
+ return "half";
+ break;
+ default:
+ return "unknown";
+ break;
+ }
+}
+
+static NMPlatformLinkDuplexType
+link_duplex_to_platform (const char *duplex)
+{
+ if (!duplex)
+ return NM_PLATFORM_LINK_DUPLEX_UNSET;
+
+ if (nm_streq (duplex, "full"))
+ return NM_PLATFORM_LINK_DUPLEX_FULL;
+
+ if (nm_streq (duplex, "half"))
+ return NM_PLATFORM_LINK_DUPLEX_HALF;
+
+ return NM_PLATFORM_LINK_DUPLEX_UNKNOWN;
+}
+
+static void
+link_negotiation_set (NMDevice *device)
+{
+ NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device);
+ NMSettingWired *s_wired;
+ gboolean autoneg = TRUE, link_autoneg;
+ NMPlatformLinkDuplexType link_duplex, duplex = NM_PLATFORM_LINK_DUPLEX_UNSET;
+ guint32 speed = 0, link_speed;
+
+ s_wired = (NMSettingWired *) nm_device_get_applied_setting (device, NM_TYPE_SETTING_WIRED);
+ if (s_wired) {
+ autoneg = nm_setting_wired_get_auto_negotiate (s_wired);
+ if (!autoneg) {
+ speed = nm_setting_wired_get_speed (s_wired);
+ duplex = link_duplex_to_platform (nm_setting_wired_get_duplex (s_wired));
+ if (!speed && !duplex) {
+ _LOGD (LOGD_DEVICE, "set-link: ignore link negotiation");
+ return;
+ }
+ }
+ }
+
+ if (!nm_platform_ethtool_get_link_settings (NM_PLATFORM_GET, nm_device_get_iface (device),
+ &link_autoneg, &link_speed, &link_duplex)) {
+ _LOGW (LOGD_DEVICE, "set-link: unable to retrieve link negotiation");
+ return;
+ }
+
+ /* If link negotiation setting are already in place do nothing and return with success */
+ if (autoneg != link_autoneg)
+ goto set_link;
+
+ if (speed && (speed != link_speed))
+ goto set_link;
+
+ if (duplex && (duplex != link_duplex))
+ goto set_link;
+
+ _LOGW (LOGD_DEVICE, "set-link: link negotiation is already configured");
+ return;
+
+set_link:
+ if (!nm_platform_ethtool_set_link_settings (NM_PLATFORM_GET,
+ nm_device_get_iface (device),
+ autoneg,
+ speed,
+ duplex)) {
+ _LOGW (LOGD_DEVICE, "set-link: failure to set link negotiation");
+ return;
+ }
+
+ if (autoneg)
+ _LOGD (LOGD_DEVICE, "set-link: configure autonegotiation");
+ else {
+ _LOGD (LOGD_DEVICE, "set-link: configure static negotiation (%u Mbit - %s duplex)",
+ speed ?: link_speed,
+ duplex ? link_duplex_to_string (duplex) : link_duplex_to_string (link_duplex));
+ }
+}
+
static gboolean
pppoe_reconnect_delay (gpointer user_data)
{
@@ -807,6 +898,8 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
return ret;
+ link_negotiation_set (dev);
+
if (!nm_device_hw_addr_set_cloned (dev, nm_device_get_applied_connection (dev), FALSE))
return NM_ACT_STAGE_RETURN_FAILURE;