diff --git a/src/libnm-platform/nm-platform-utils.c b/src/libnm-platform/nm-platform-utils.c index fccfc8a10d..4edcfc05a6 100644 --- a/src/libnm-platform/nm-platform-utils.c +++ b/src/libnm-platform/nm-platform-utils.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include @@ -18,6 +17,7 @@ #include #include +#include "linux-headers/ethtool.h" #include "libnm-base/nm-ethtool-base.h" #include "libnm-log-core/nm-logging.h" #include "libnm-glib-aux/nm-time-utils.h" @@ -1331,10 +1331,6 @@ nmp_utils_ethtool_get_link_settings(int ifindex, } #define ADVERTISED_INVALID 0 -#define BASET_ALL_MODES \ - (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half \ - | ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full \ - | ADVERTISED_10000baseT_Full) static guint32 get_baset_mode(guint32 speed, NMPlatformLinkDuplexType duplex) @@ -1386,6 +1382,96 @@ platform_link_duplex_type_to_native(NMPlatformLinkDuplexType duplex_type, guint8 } } +const guint8 _nmp_link_mode_all_advertised_modes_bits[] = { + ETHTOOL_LINK_MODE_10baseT_Half_BIT, + ETHTOOL_LINK_MODE_10baseT_Full_BIT, + ETHTOOL_LINK_MODE_100baseT_Half_BIT, + ETHTOOL_LINK_MODE_100baseT_Full_BIT, + ETHTOOL_LINK_MODE_1000baseT_Half_BIT, + ETHTOOL_LINK_MODE_1000baseT_Full_BIT, + ETHTOOL_LINK_MODE_10000baseT_Full_BIT, + ETHTOOL_LINK_MODE_2500baseX_Full_BIT, + ETHTOOL_LINK_MODE_1000baseKX_Full_BIT, + ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT, + ETHTOOL_LINK_MODE_10000baseKR_Full_BIT, + ETHTOOL_LINK_MODE_10000baseR_FEC_BIT, + ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT, + ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT, + ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT, + ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT, + ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT, + ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT, + ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT, + ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT, + ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT, + ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT, + ETHTOOL_LINK_MODE_25000baseCR_Full_BIT, + /* 32 bit flags start here. */ + ETHTOOL_LINK_MODE_25000baseKR_Full_BIT, + ETHTOOL_LINK_MODE_25000baseSR_Full_BIT, + ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT, + ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT, + ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT, + ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT, + ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT, + ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT, + ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT, + ETHTOOL_LINK_MODE_1000baseX_Full_BIT, + ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, + ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, + ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, + ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, + ETHTOOL_LINK_MODE_10000baseER_Full_BIT, + ETHTOOL_LINK_MODE_2500baseT_Full_BIT, + ETHTOOL_LINK_MODE_5000baseT_Full_BIT, + ETHTOOL_LINK_MODE_50000baseKR_Full_BIT, + ETHTOOL_LINK_MODE_50000baseSR_Full_BIT, + ETHTOOL_LINK_MODE_50000baseCR_Full_BIT, + ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT, + ETHTOOL_LINK_MODE_50000baseDR_Full_BIT, + ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT, + ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT, + ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT, + ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT, + ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT, + ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT, + ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT, + ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT, + ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT, + ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT, + ETHTOOL_LINK_MODE_100baseT1_Full_BIT, + ETHTOOL_LINK_MODE_1000baseT1_Full_BIT, + ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT, + ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT, + ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT, + ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT, + ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT, + ETHTOOL_LINK_MODE_100000baseKR_Full_BIT, + ETHTOOL_LINK_MODE_100000baseSR_Full_BIT, + ETHTOOL_LINK_MODE_100000baseLR_ER_FR_Full_BIT, + ETHTOOL_LINK_MODE_100000baseCR_Full_BIT, + ETHTOOL_LINK_MODE_100000baseDR_Full_BIT, + ETHTOOL_LINK_MODE_200000baseKR2_Full_BIT, + ETHTOOL_LINK_MODE_200000baseSR2_Full_BIT, + ETHTOOL_LINK_MODE_200000baseLR2_ER2_FR2_Full_BIT, + ETHTOOL_LINK_MODE_200000baseDR2_Full_BIT, + ETHTOOL_LINK_MODE_200000baseCR2_Full_BIT, + ETHTOOL_LINK_MODE_400000baseKR4_Full_BIT, + ETHTOOL_LINK_MODE_400000baseSR4_Full_BIT, + ETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT, + ETHTOOL_LINK_MODE_400000baseDR4_Full_BIT, + ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT, + ETHTOOL_LINK_MODE_100baseFX_Half_BIT, + ETHTOOL_LINK_MODE_100baseFX_Full_BIT, +}; + +/* these are the bits from _nmp_link_mode_all_advertised_modes_bits set. */ +const guint32 _nmp_link_mode_all_advertised_modes[] = { + 0xfffe903fu, + 0xfff1ffffu, + 0x0ffffbffu, +}; + static NMOptionBool set_link_settings_new(SocketHandle * shandle, gboolean autoneg, @@ -1396,6 +1482,7 @@ set_link_settings_new(SocketHandle * shandle, gs_free struct ethtool_link_settings *edata = NULL; gsize edata_size; guint nwords; + guint i; edata0 = (struct ethtool_link_settings){ .cmd = ETHTOOL_GLINKSETTINGS, @@ -1445,7 +1532,6 @@ set_link_settings_new(SocketHandle * shandle, return FALSE; } - /* We only support BASE-T modes in the first word */ if (!(v_map_supported[0] & mode)) { nm_log_trace(LOGD_PLATFORM, "ethtool[%d]: device does not support %uBASE-T %s duplex mode", @@ -1455,7 +1541,9 @@ set_link_settings_new(SocketHandle * shandle, return FALSE; } - v_map_advertising[0] = (v_map_advertising[0] & ~BASET_ALL_MODES) | mode; + for (i = 0; i < (guint) G_N_ELEMENTS(_nmp_link_mode_all_advertised_modes); i++) + v_map_advertising[i] &= ~_nmp_link_mode_all_advertised_modes[i]; + v_map_advertising[0] |= mode; } } else { edata->autoneg = AUTONEG_DISABLE; @@ -1499,10 +1587,9 @@ nmp_utils_ethtool_set_link_settings(int ifindex, /* then change the needed ones */ edata.cmd = ETHTOOL_SSET; if (autoneg) { - edata.autoneg = AUTONEG_ENABLE; - if (speed == 0) - edata.advertising = edata.supported; - else { + edata.autoneg = AUTONEG_ENABLE; + edata.advertising = edata.supported; + if (speed != 0) { guint32 mode; mode = get_baset_mode(speed, duplex); @@ -1523,7 +1610,8 @@ nmp_utils_ethtool_set_link_settings(int ifindex, nm_platform_link_duplex_type_to_string(duplex)); return FALSE; } - edata.advertising = (edata.supported & ~BASET_ALL_MODES) | mode; + edata.advertising &= ~_nmp_link_mode_all_advertised_modes[0]; + edata.advertising |= mode; } } else { edata.autoneg = AUTONEG_DISABLE; diff --git a/src/libnm-platform/nm-platform-utils.h b/src/libnm-platform/nm-platform-utils.h index d70f4385ea..5511e8af53 100644 --- a/src/libnm-platform/nm-platform-utils.h +++ b/src/libnm-platform/nm-platform-utils.h @@ -22,6 +22,9 @@ gboolean nmp_utils_ethtool_set_wake_on_lan(int ifindex, const char *nm_platform_link_duplex_type_to_string(NMPlatformLinkDuplexType duplex); +extern const guint8 _nmp_link_mode_all_advertised_modes_bits[79]; +extern const guint32 _nmp_link_mode_all_advertised_modes[3]; + gboolean nmp_utils_ethtool_get_link_settings(int ifindex, gboolean * out_autoneg, guint32 * out_speed, diff --git a/src/libnm-platform/tests/test-nm-platform.c b/src/libnm-platform/tests/test-nm-platform.c index 5b1b8e87a1..d4de0dd5ea 100644 --- a/src/libnm-platform/tests/test-nm-platform.c +++ b/src/libnm-platform/tests/test-nm-platform.c @@ -5,6 +5,7 @@ #include "libnm-log-core/nm-logging.h" #include "libnm-platform/nm-netlink.h" #include "libnm-platform/nmp-netns.h" +#include "libnm-platform/nm-platform-utils.h" #include "libnm-glib-aux/nm-test-utils.h" @@ -103,6 +104,44 @@ test_use_symbols(void) /*****************************************************************************/ +static void +test_nmp_link_mode_all_advertised_modes_bits(void) +{ + guint32 flags[(SCHAR_MAX + 1) / 32]; + guint max_bit; + int i; + + memset(flags, 0, sizeof(flags)); + + max_bit = 0; + for (i = 0; i < (int) G_N_ELEMENTS(_nmp_link_mode_all_advertised_modes_bits); i++) { + if (i > 0) { + g_assert_cmpint(_nmp_link_mode_all_advertised_modes_bits[i - 1], + <, + _nmp_link_mode_all_advertised_modes_bits[i]); + } + g_assert_cmpint(_nmp_link_mode_all_advertised_modes_bits[i], <, SCHAR_MAX); + g_assert_cmpint(_nmp_link_mode_all_advertised_modes_bits[i] / 32, <, G_N_ELEMENTS(flags)); + flags[_nmp_link_mode_all_advertised_modes_bits[i] / 32] |= + (1u << (_nmp_link_mode_all_advertised_modes_bits[i] % 32u)); + max_bit = NM_MAX(max_bit, _nmp_link_mode_all_advertised_modes_bits[i]); + } + + g_assert_cmpint((max_bit + 31u) / 32u, ==, G_N_ELEMENTS(_nmp_link_mode_all_advertised_modes)); + + for (i = 0; i < (int) G_N_ELEMENTS(_nmp_link_mode_all_advertised_modes); i++) { + if (flags[i] != _nmp_link_mode_all_advertised_modes[i]) { + g_error("_nmp_link_mode_all_advertised_modes[%d] should be 0x%0x but is 0x%0x " + "(according to the bits in _nmp_link_mode_all_advertised_modes_bits)", + i, + flags[i], + _nmp_link_mode_all_advertised_modes[i]); + } + } +} + +/*****************************************************************************/ + NMTST_DEFINE(); int @@ -111,6 +150,8 @@ main(int argc, char **argv) nmtst_init(&argc, &argv, TRUE); g_test_add_func("/nm-platform/test_use_symbols", test_use_symbols); + g_test_add_func("/nm-platform/test_nmp_link_mode_all_advertised_modes_bits", + test_nmp_link_mode_all_advertised_modes_bits); return g_test_run(); }