]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/udev/net/ethtool-util.c
Merge pull request #11827 from keszybz/pkgconfig-variables
[thirdparty/systemd.git] / src / udev / net / ethtool-util.c
index 1897f97a0454c43e76f93d9c3811e85cc5f1dbba..55620926dc4cb255e50552fc0b7f5d153951c6a8 100644 (file)
@@ -31,18 +31,18 @@ static const char* const wol_table[_WOL_MAX] = {
         [WOL_ARP]         = "arp",
         [WOL_MAGIC]       = "magic",
         [WOL_MAGICSECURE] = "secureon",
-        [WOL_OFF]         = "off"
+        [WOL_OFF]         = "off",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(wol, WakeOnLan);
 DEFINE_CONFIG_PARSE_ENUM(config_parse_wol, wol, WakeOnLan, "Failed to parse WakeOnLan setting");
 
-static const char* const port_table[_NET_DEV_PORT_MAX] = {
+static const char* const port_table[] = {
         [NET_DEV_PORT_TP]     = "tp",
         [NET_DEV_PORT_AUI]    = "aui",
         [NET_DEV_PORT_MII]    = "mii",
         [NET_DEV_PORT_FIBRE]  = "fibre",
-        [NET_DEV_PORT_BNC]    = "bnc"
+        [NET_DEV_PORT_BNC]    = "bnc",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(port, NetDevPort);
@@ -56,24 +56,64 @@ static const char* const netdev_feature_table[_NET_DEV_FEAT_MAX] = {
         [NET_DEV_FEAT_TSO6] = "tx-tcp6-segmentation",
 };
 
-static const char* const advertise_table[_NET_DEV_ADVERTISE_MAX] = {
-        [NET_DEV_ADVERTISE_10BASET_HALF]        = "10baset-half",
-        [NET_DEV_ADVERTISE_10BASET_FULL]        = "10baset-full",
-        [NET_DEV_ADVERTISE_100BASET_HALF]       = "100baset-half",
-        [NET_DEV_ADVERTISE_100BASET_FULL]       = "100baset-full",
-        [NET_DEV_ADVERTISE_1000BASET_HALF]      = "1000baset-half",
-        [NET_DEV_ADVERTISE_1000BASET_FULL]      = "1000baset-full",
-        [NET_DEV_ADVERTISE_10000BASET_FULL]     = "10000baset-full",
-        [NET_DEV_ADVERTISE_2500BASEX_FULL]      = "2500basex-full",
-        [NET_DEV_ADVERTISE_1000BASEKX_FULL]     = "1000basekx-full",
-        [NET_DEV_ADVERTISE_10000BASEKX4_FULL]   = "10000basekx4-full",
-        [NET_DEV_ADVERTISE_10000BASEKR_FULL]    = "10000basekr-full",
-        [NET_DEV_ADVERTISE_10000BASER_FEC]      = "10000baser-fec",
-        [NET_DEV_ADVERTISE_20000BASEMLD2_Full]  = "20000basemld2-full",
-        [NET_DEV_ADVERTISE_20000BASEKR2_Full]   = "20000basekr2-full",
+static const char* const ethtool_link_mode_bit_table[] = {
+        [ETHTOOL_LINK_MODE_10baseT_Half_BIT]           = "10baset-half",
+        [ETHTOOL_LINK_MODE_10baseT_Full_BIT]           = "10baset-full",
+        [ETHTOOL_LINK_MODE_100baseT_Half_BIT]          = "100baset-half",
+        [ETHTOOL_LINK_MODE_100baseT_Full_BIT]          = "100baset-full",
+        [ETHTOOL_LINK_MODE_1000baseT_Half_BIT]         = "1000baset-half",
+        [ETHTOOL_LINK_MODE_1000baseT_Full_BIT]         = "1000baset-full",
+        [ETHTOOL_LINK_MODE_Autoneg_BIT]                = "autonegotiation",
+        [ETHTOOL_LINK_MODE_TP_BIT]                     = "tp",
+        [ETHTOOL_LINK_MODE_AUI_BIT]                    = "aui",
+        [ETHTOOL_LINK_MODE_MII_BIT]                    = "mii",
+        [ETHTOOL_LINK_MODE_FIBRE_BIT]                  = "fibre",
+        [ETHTOOL_LINK_MODE_BNC_BIT]                    = "bnc",
+        [ETHTOOL_LINK_MODE_10000baseT_Full_BIT]        = "10000baset-full",
+        [ETHTOOL_LINK_MODE_Pause_BIT]                  = "pause",
+        [ETHTOOL_LINK_MODE_Asym_Pause_BIT]             = "asym-pause",
+        [ETHTOOL_LINK_MODE_2500baseX_Full_BIT]         = "2500basex-full",
+        [ETHTOOL_LINK_MODE_Backplane_BIT]              = "backplane",
+        [ETHTOOL_LINK_MODE_1000baseKX_Full_BIT]        = "1000basekx-full",
+        [ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT]      = "10000basekx4-full",
+        [ETHTOOL_LINK_MODE_10000baseKR_Full_BIT]       = "10000basekr-full",
+        [ETHTOOL_LINK_MODE_10000baseR_FEC_BIT]         = "10000baser-fec",
+        [ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT]     = "20000basemld2-full",
+        [ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT]      = "20000basekr2-full",
+        [ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT]      = "40000basekr4-full",
+        [ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT]      = "40000basecr4-full",
+        [ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT]      = "40000basesr4-full",
+        [ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT]      = "40000baselr4-full",
+        [ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT]      = "56000basekr4-full",
+        [ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT]      = "56000basecr4-full",
+        [ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT]      = "56000basesr4-full",
+        [ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT]      = "56000baselr4-full",
+        [ETHTOOL_LINK_MODE_25000baseCR_Full_BIT]       = "25000basecr-full",
+        [ETHTOOL_LINK_MODE_25000baseKR_Full_BIT]       = "25000basekr-full",
+        [ETHTOOL_LINK_MODE_25000baseSR_Full_BIT]       = "25000basesr-full",
+        [ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT]      = "50000basecr2-full",
+        [ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT]      = "50000basekr2-full",
+        [ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT]     = "100000basekr4-full",
+        [ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT]     = "100000basesr4-full",
+        [ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT]     = "100000basecr4-full",
+        [ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT] = "100000baselr4-er4-full",
+        [ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT]      = "50000basesr2-full",
+        [ETHTOOL_LINK_MODE_1000baseX_Full_BIT]         = "1000basex-full",
+        [ETHTOOL_LINK_MODE_10000baseCR_Full_BIT]       = "10000basecr-full",
+        [ETHTOOL_LINK_MODE_10000baseSR_Full_BIT]       = "10000basesr-full",
+        [ETHTOOL_LINK_MODE_10000baseLR_Full_BIT]       = "10000baselr-full",
+        [ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT]      = "10000baselrm-full",
+        [ETHTOOL_LINK_MODE_10000baseER_Full_BIT]       = "10000baseer-full",
+        [ETHTOOL_LINK_MODE_2500baseT_Full_BIT]         = "2500baset-full",
+        [ETHTOOL_LINK_MODE_5000baseT_Full_BIT]         = "5000baset-full",
+        [ETHTOOL_LINK_MODE_FEC_NONE_BIT]               = "fec-none",
+        [ETHTOOL_LINK_MODE_FEC_RS_BIT]                 = "fec-rs",
+        [ETHTOOL_LINK_MODE_FEC_BASER_BIT]              = "fec-baser",
 };
+/* Make sure the array is large enough to fit all bits */
+assert_cc((ELEMENTSOF(ethtool_link_mode_bit_table)-1) / 32 < ELEMENTSOF(((struct link_config){}).advertise));
 
-DEFINE_STRING_TABLE_LOOKUP(advertise, NetDevAdvertise);
+DEFINE_STRING_TABLE_LOOKUP(ethtool_link_mode_bit, enum ethtool_link_mode_bit_indices);
 
 int ethtool_connect(int *ret) {
         int fd;
@@ -318,7 +358,7 @@ static int find_feature_index(struct ethtool_gstrings *strings, const char *feat
                         return i;
         }
 
-        return -1;
+        return -ENODATA;
 }
 
 int ethtool_set_features(int *fd, const char *ifname, int *features) {
@@ -534,7 +574,7 @@ static int set_sset(int fd, struct ifreq *ifr, const struct ethtool_link_usettin
 
 /* If autonegotiation is disabled, the speed and duplex represent the fixed link
  * mode and are writable if the driver supports multiple link modes. If it is
- * enabled then they are read-only. If the link  is up they represent the negotiated
+ * enabled then they are read-only. If the link is up they represent the negotiated
  * link mode; if the link is down, the speed is 0, %SPEED_UNKNOWN or the highest
  * enabled speed and @duplex is %DUPLEX_UNKNOWN or the best enabled duplex mode.
  */
@@ -543,7 +583,7 @@ int ethtool_set_glinksettings(int *fd, const char *ifname, struct link_config *l
         struct ifreq ifr = {};
         int r;
 
-        if (link->autonegotiation != 0) {
+        if (link->autonegotiation != AUTONEG_DISABLE && eqzero(link->advertise)) {
                 log_info("link_config: autonegotiation is unset or enabled, the speed and duplex are not writable.");
                 return 0;
         }
@@ -572,13 +612,14 @@ int ethtool_set_glinksettings(int *fd, const char *ifname, struct link_config *l
         if (link->port != _NET_DEV_PORT_INVALID)
                 u->base.port = link->port;
 
-        u->base.autoneg = link->autonegotiation;
+        if (link->autonegotiation >= 0)
+                u->base.autoneg = link->autonegotiation;
 
-        if (link->advertise) {
-                uint32_t advertise[ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32] = {};
-
-                advertise[0] = link->advertise;
-                memcpy(&u->link_modes.advertising, advertise, ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NBYTES);
+        if (!eqzero(link->advertise)) {
+                u->base.autoneg = AUTONEG_ENABLE;
+                memcpy(&u->link_modes.advertising, link->advertise, sizeof(link->advertise));
+                memzero((uint8_t*) &u->link_modes.advertising + sizeof(link->advertise),
+                        ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NBYTES - sizeof(link->advertise));
         }
 
         if (u->base.cmd == ETHTOOL_GLINKSETTINGS)
@@ -704,7 +745,6 @@ int config_parse_advertise(const char *unit,
                            void *data,
                            void *userdata) {
         link_config *config = data;
-        NetDevAdvertise mode, a = 0;
         const char *p;
         int r;
 
@@ -716,12 +756,13 @@ int config_parse_advertise(const char *unit,
 
         if (isempty(rvalue)) {
                 /* Empty string resets the value. */
-                config->advertise = 0;
+                zero(config->advertise);
                 return 0;
         }
 
         for (p = rvalue;;) {
                 _cleanup_free_ char *w = NULL;
+                enum ethtool_link_mode_bit_indices mode;
 
                 r = extract_first_word(&p, &w, NULL, 0);
                 if (r == -ENOMEM)
@@ -733,15 +774,16 @@ int config_parse_advertise(const char *unit,
                 if (r == 0)
                         break;
 
-                mode = advertise_from_string(w);
-                if (mode == _NET_DEV_ADVERTISE_INVALID) {
+                mode = ethtool_link_mode_bit_from_string(w);
+                /* We reuse the kernel provided enum which does not contain negative value. So, the cast
+                 * below is mandatory. Otherwise, the check below always passes and access an invalid address. */
+                if ((int) mode < 0) {
                         log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse advertise mode, ignoring: %s", w);
                         continue;
                 }
-                a |= mode;
-        }
 
-        config->advertise |= a;
+                config->advertise[mode / 32] |= 1UL << (mode % 32);
+        }
 
         return 0;
 }