LCOV - code coverage report
Current view: top level - shared - ethtool-util.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 2 413 0.5 %
Date: 2019-08-23 13:36:53 Functions: 4 27 14.8 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 8 328 2.4 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <net/if.h>
       4                 :            : #include <sys/ioctl.h>
       5                 :            : #include <linux/ethtool.h>
       6                 :            : #include <linux/sockios.h>
       7                 :            : 
       8                 :            : #include "conf-parser.h"
       9                 :            : #include "ethtool-util.h"
      10                 :            : #include "extract-word.h"
      11                 :            : #include "log.h"
      12                 :            : #include "memory-util.h"
      13                 :            : #include "missing.h"
      14                 :            : #include "socket-util.h"
      15                 :            : #include "string-table.h"
      16                 :            : #include "strxcpyx.h"
      17                 :            : 
      18                 :            : static const char* const duplex_table[_DUP_MAX] = {
      19                 :            :         [DUP_FULL] = "full",
      20                 :            :         [DUP_HALF] = "half"
      21                 :            : };
      22                 :            : 
      23   [ +  +  +  + ]:         32 : DEFINE_STRING_TABLE_LOOKUP(duplex, Duplex);
      24   [ #  #  #  #  :          0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_duplex, duplex, Duplex, "Failed to parse duplex setting");
          #  #  #  #  #  
                #  #  # ]
      25                 :            : 
      26                 :            : static const char* const wol_table[_WOL_MAX] = {
      27                 :            :         [WOL_PHY]         = "phy",
      28                 :            :         [WOL_UCAST]       = "unicast",
      29                 :            :         [WOL_MCAST]       = "multicast",
      30                 :            :         [WOL_BCAST]       = "broadcast",
      31                 :            :         [WOL_ARP]         = "arp",
      32                 :            :         [WOL_MAGIC]       = "magic",
      33                 :            :         [WOL_MAGICSECURE] = "secureon",
      34                 :            :         [WOL_OFF]         = "off",
      35                 :            : };
      36                 :            : 
      37   [ +  +  +  + ]:         80 : DEFINE_STRING_TABLE_LOOKUP(wol, WakeOnLan);
      38   [ #  #  #  #  :          0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_wol, wol, WakeOnLan, "Failed to parse WakeOnLan setting");
          #  #  #  #  #  
                #  #  # ]
      39                 :            : 
      40                 :            : static const char* const port_table[] = {
      41                 :            :         [NET_DEV_PORT_TP]     = "tp",
      42                 :            :         [NET_DEV_PORT_AUI]    = "aui",
      43                 :            :         [NET_DEV_PORT_MII]    = "mii",
      44                 :            :         [NET_DEV_PORT_FIBRE]  = "fibre",
      45                 :            :         [NET_DEV_PORT_BNC]    = "bnc",
      46                 :            : };
      47                 :            : 
      48   [ #  #  #  # ]:          0 : DEFINE_STRING_TABLE_LOOKUP(port, NetDevPort);
      49   [ #  #  #  #  :          0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_port, port, NetDevPort, "Failed to parse Port setting");
          #  #  #  #  #  
                #  #  # ]
      50                 :            : 
      51                 :            : static const char* const netdev_feature_table[_NET_DEV_FEAT_MAX] = {
      52                 :            :         [NET_DEV_FEAT_GSO]  = "tx-generic-segmentation",
      53                 :            :         [NET_DEV_FEAT_GRO]  = "rx-gro",
      54                 :            :         [NET_DEV_FEAT_LRO]  = "rx-lro",
      55                 :            :         [NET_DEV_FEAT_TSO]  = "tx-tcp-segmentation",
      56                 :            :         [NET_DEV_FEAT_TSO6] = "tx-tcp6-segmentation",
      57                 :            : };
      58                 :            : 
      59                 :            : static const char* const ethtool_link_mode_bit_table[] = {
      60                 :            :         [ETHTOOL_LINK_MODE_10baseT_Half_BIT]               = "10baset-half",
      61                 :            :         [ETHTOOL_LINK_MODE_10baseT_Full_BIT]               = "10baset-full",
      62                 :            :         [ETHTOOL_LINK_MODE_100baseT_Half_BIT]              = "100baset-half",
      63                 :            :         [ETHTOOL_LINK_MODE_100baseT_Full_BIT]              = "100baset-full",
      64                 :            :         [ETHTOOL_LINK_MODE_1000baseT_Half_BIT]             = "1000baset-half",
      65                 :            :         [ETHTOOL_LINK_MODE_1000baseT_Full_BIT]             = "1000baset-full",
      66                 :            :         [ETHTOOL_LINK_MODE_Autoneg_BIT]                    = "autonegotiation",
      67                 :            :         [ETHTOOL_LINK_MODE_TP_BIT]                         = "tp",
      68                 :            :         [ETHTOOL_LINK_MODE_AUI_BIT]                        = "aui",
      69                 :            :         [ETHTOOL_LINK_MODE_MII_BIT]                        = "mii",
      70                 :            :         [ETHTOOL_LINK_MODE_FIBRE_BIT]                      = "fibre",
      71                 :            :         [ETHTOOL_LINK_MODE_BNC_BIT]                        = "bnc",
      72                 :            :         [ETHTOOL_LINK_MODE_10000baseT_Full_BIT]            = "10000baset-full",
      73                 :            :         [ETHTOOL_LINK_MODE_Pause_BIT]                      = "pause",
      74                 :            :         [ETHTOOL_LINK_MODE_Asym_Pause_BIT]                 = "asym-pause",
      75                 :            :         [ETHTOOL_LINK_MODE_2500baseX_Full_BIT]             = "2500basex-full",
      76                 :            :         [ETHTOOL_LINK_MODE_Backplane_BIT]                  = "backplane",
      77                 :            :         [ETHTOOL_LINK_MODE_1000baseKX_Full_BIT]            = "1000basekx-full",
      78                 :            :         [ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT]          = "10000basekx4-full",
      79                 :            :         [ETHTOOL_LINK_MODE_10000baseKR_Full_BIT]           = "10000basekr-full",
      80                 :            :         [ETHTOOL_LINK_MODE_10000baseR_FEC_BIT]             = "10000baser-fec",
      81                 :            :         [ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT]         = "20000basemld2-full",
      82                 :            :         [ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT]          = "20000basekr2-full",
      83                 :            :         [ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT]          = "40000basekr4-full",
      84                 :            :         [ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT]          = "40000basecr4-full",
      85                 :            :         [ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT]          = "40000basesr4-full",
      86                 :            :         [ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT]          = "40000baselr4-full",
      87                 :            :         [ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT]          = "56000basekr4-full",
      88                 :            :         [ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT]          = "56000basecr4-full",
      89                 :            :         [ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT]          = "56000basesr4-full",
      90                 :            :         [ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT]          = "56000baselr4-full",
      91                 :            :         [ETHTOOL_LINK_MODE_25000baseCR_Full_BIT]           = "25000basecr-full",
      92                 :            :         [ETHTOOL_LINK_MODE_25000baseKR_Full_BIT]           = "25000basekr-full",
      93                 :            :         [ETHTOOL_LINK_MODE_25000baseSR_Full_BIT]           = "25000basesr-full",
      94                 :            :         [ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT]          = "50000basecr2-full",
      95                 :            :         [ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT]          = "50000basekr2-full",
      96                 :            :         [ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT]         = "100000basekr4-full",
      97                 :            :         [ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT]         = "100000basesr4-full",
      98                 :            :         [ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT]         = "100000basecr4-full",
      99                 :            :         [ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT]     = "100000baselr4-er4-full",
     100                 :            :         [ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT]          = "50000basesr2-full",
     101                 :            :         [ETHTOOL_LINK_MODE_1000baseX_Full_BIT]             = "1000basex-full",
     102                 :            :         [ETHTOOL_LINK_MODE_10000baseCR_Full_BIT]           = "10000basecr-full",
     103                 :            :         [ETHTOOL_LINK_MODE_10000baseSR_Full_BIT]           = "10000basesr-full",
     104                 :            :         [ETHTOOL_LINK_MODE_10000baseLR_Full_BIT]           = "10000baselr-full",
     105                 :            :         [ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT]          = "10000baselrm-full",
     106                 :            :         [ETHTOOL_LINK_MODE_10000baseER_Full_BIT]           = "10000baseer-full",
     107                 :            :         [ETHTOOL_LINK_MODE_2500baseT_Full_BIT]             = "2500baset-full",
     108                 :            :         [ETHTOOL_LINK_MODE_5000baseT_Full_BIT]             = "5000baset-full",
     109                 :            :         [ETHTOOL_LINK_MODE_FEC_NONE_BIT]                   = "fec-none",
     110                 :            :         [ETHTOOL_LINK_MODE_FEC_RS_BIT]                     = "fec-rs",
     111                 :            :         [ETHTOOL_LINK_MODE_FEC_BASER_BIT]                  = "fec-baser",
     112                 :            :         [ETHTOOL_LINK_MODE_50000baseKR_Full_BIT]           = "50000basekr_full",
     113                 :            :         [ETHTOOL_LINK_MODE_50000baseSR_Full_BIT]           = "50000basesr_full",
     114                 :            :         [ETHTOOL_LINK_MODE_50000baseCR_Full_BIT]           = "50000basecr_full",
     115                 :            :         [ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT]     = "50000baselr_er_fr_full",
     116                 :            :         [ETHTOOL_LINK_MODE_50000baseDR_Full_BIT]           = "50000basedr_full",
     117                 :            :         [ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT]         = "100000basekr2_full",
     118                 :            :         [ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT]         = "100000basesr2_full",
     119                 :            :         [ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT]         = "100000basecr2_full",
     120                 :            :         [ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT] = "100000baselr2_er2_fr2_full",
     121                 :            :         [ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT]         = "100000basedr2_full",
     122                 :            :         [ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT]         = "200000basekr4_full",
     123                 :            :         [ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT]         = "200000basesr4_full",
     124                 :            :         [ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT]         = "200000basecr4_full",
     125                 :            :         [ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT] = "200000baselr4_er4_fr4_full",
     126                 :            :         [ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT]         = "200000basedr4_full",
     127                 :            : };
     128                 :            : /* Make sure the array is large enough to fit all bits */
     129                 :            : assert_cc((ELEMENTSOF(ethtool_link_mode_bit_table)-1) / 32 < N_ADVERTISE);
     130                 :            : 
     131         [ #  # ]:          0 : DEFINE_STRING_TABLE_LOOKUP(ethtool_link_mode_bit, enum ethtool_link_mode_bit_indices);
     132                 :            : 
     133                 :          0 : static int ethtool_connect_or_warn(int *ret, bool warn) {
     134                 :            :         int fd;
     135                 :            : 
     136   [ #  #  #  # ]:          0 :         assert_return(ret, -EINVAL);
     137                 :            : 
     138                 :          0 :         fd = socket_ioctl_fd();
     139         [ #  # ]:          0 :         if (fd < 0)
     140   [ #  #  #  # ]:          0 :                 return log_full_errno(warn ? LOG_WARNING: LOG_DEBUG, fd,
     141                 :            :                                        "ethtool: could not create control socket: %m");
     142                 :            : 
     143                 :          0 :         *ret = fd;
     144                 :            : 
     145                 :          0 :         return 0;
     146                 :            : }
     147                 :            : 
     148                 :          0 : int ethtool_get_driver(int *fd, const char *ifname, char **ret) {
     149                 :          0 :         struct ethtool_drvinfo ecmd = {
     150                 :            :                 .cmd = ETHTOOL_GDRVINFO
     151                 :            :         };
     152                 :          0 :         struct ifreq ifr = {
     153                 :            :                 .ifr_data = (void*) &ecmd
     154                 :            :         };
     155                 :            :         char *d;
     156                 :            :         int r;
     157                 :            : 
     158         [ #  # ]:          0 :         if (*fd < 0) {
     159                 :          0 :                 r = ethtool_connect_or_warn(fd, true);
     160         [ #  # ]:          0 :                 if (r < 0)
     161                 :          0 :                         return r;
     162                 :            :         }
     163                 :            : 
     164                 :          0 :         strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
     165                 :            : 
     166                 :          0 :         r = ioctl(*fd, SIOCETHTOOL, &ifr);
     167         [ #  # ]:          0 :         if (r < 0)
     168                 :          0 :                 return -errno;
     169                 :            : 
     170                 :          0 :         d = strdup(ecmd.driver);
     171         [ #  # ]:          0 :         if (!d)
     172                 :          0 :                 return -ENOMEM;
     173                 :            : 
     174                 :          0 :         *ret = d;
     175                 :          0 :         return 0;
     176                 :            : }
     177                 :            : 
     178                 :          0 : int ethtool_get_link_info(int *fd, const char *ifname,
     179                 :            :                           int *ret_autonegotiation, size_t *ret_speed,
     180                 :            :                           Duplex *ret_duplex, NetDevPort *ret_port) {
     181                 :          0 :         struct ethtool_cmd ecmd = {
     182                 :            :                 .cmd = ETHTOOL_GSET,
     183                 :            :         };
     184                 :          0 :         struct ifreq ifr = {
     185                 :            :                 .ifr_data = (void*) &ecmd,
     186                 :            :         };
     187                 :            :         int r;
     188                 :            : 
     189         [ #  # ]:          0 :         if (*fd < 0) {
     190                 :          0 :                 r = ethtool_connect_or_warn(fd, false);
     191         [ #  # ]:          0 :                 if (r < 0)
     192                 :          0 :                         return r;
     193                 :            :         }
     194                 :            : 
     195                 :          0 :         strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
     196                 :            : 
     197                 :          0 :         r = ioctl(*fd, SIOCETHTOOL, &ifr);
     198         [ #  # ]:          0 :         if (r < 0)
     199                 :          0 :                 return -errno;
     200                 :            : 
     201         [ #  # ]:          0 :         if (ret_autonegotiation)
     202                 :          0 :                 *ret_autonegotiation = ecmd.autoneg;
     203                 :            : 
     204         [ #  # ]:          0 :         if (ret_speed) {
     205                 :            :                 uint32_t speed;
     206                 :            : 
     207                 :          0 :                 speed = ethtool_cmd_speed(&ecmd);
     208                 :          0 :                 *ret_speed = speed == (uint32_t) SPEED_UNKNOWN ?
     209         [ #  # ]:          0 :                         SIZE_MAX : (size_t) speed * 1000 * 1000;
     210                 :            :         }
     211                 :            : 
     212         [ #  # ]:          0 :         if (ret_duplex)
     213                 :          0 :                 *ret_duplex = ecmd.duplex;
     214                 :            : 
     215         [ #  # ]:          0 :         if (ret_port)
     216                 :          0 :                 *ret_port = ecmd.port;
     217                 :            : 
     218                 :          0 :         return 0;
     219                 :            : }
     220                 :            : 
     221                 :          0 : int ethtool_set_speed(int *fd, const char *ifname, unsigned speed, Duplex duplex) {
     222                 :          0 :         struct ethtool_cmd ecmd = {
     223                 :            :                 .cmd = ETHTOOL_GSET
     224                 :            :         };
     225                 :          0 :         struct ifreq ifr = {
     226                 :            :                 .ifr_data = (void*) &ecmd
     227                 :            :         };
     228                 :          0 :         bool need_update = false;
     229                 :            :         int r;
     230                 :            : 
     231   [ #  #  #  # ]:          0 :         if (speed == 0 && duplex == _DUP_INVALID)
     232                 :          0 :                 return 0;
     233                 :            : 
     234         [ #  # ]:          0 :         if (*fd < 0) {
     235                 :          0 :                 r = ethtool_connect_or_warn(fd, true);
     236         [ #  # ]:          0 :                 if (r < 0)
     237                 :          0 :                         return r;
     238                 :            :         }
     239                 :            : 
     240                 :          0 :         strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
     241                 :            : 
     242                 :          0 :         r = ioctl(*fd, SIOCETHTOOL, &ifr);
     243         [ #  # ]:          0 :         if (r < 0)
     244                 :          0 :                 return -errno;
     245                 :            : 
     246         [ #  # ]:          0 :         if (ethtool_cmd_speed(&ecmd) != speed) {
     247                 :          0 :                 ethtool_cmd_speed_set(&ecmd, speed);
     248                 :          0 :                 need_update = true;
     249                 :            :         }
     250                 :            : 
     251      [ #  #  # ]:          0 :         switch (duplex) {
     252                 :          0 :                 case DUP_HALF:
     253         [ #  # ]:          0 :                         if (ecmd.duplex != DUPLEX_HALF) {
     254                 :          0 :                                 ecmd.duplex = DUPLEX_HALF;
     255                 :          0 :                                 need_update = true;
     256                 :            :                         }
     257                 :          0 :                         break;
     258                 :          0 :                 case DUP_FULL:
     259         [ #  # ]:          0 :                         if (ecmd.duplex != DUPLEX_FULL) {
     260                 :          0 :                                 ecmd.duplex = DUPLEX_FULL;
     261                 :          0 :                                 need_update = true;
     262                 :            :                         }
     263                 :          0 :                         break;
     264                 :          0 :                 default:
     265                 :          0 :                         break;
     266                 :            :         }
     267                 :            : 
     268         [ #  # ]:          0 :         if (need_update) {
     269                 :          0 :                 ecmd.cmd = ETHTOOL_SSET;
     270                 :            : 
     271                 :          0 :                 r = ioctl(*fd, SIOCETHTOOL, &ifr);
     272         [ #  # ]:          0 :                 if (r < 0)
     273                 :          0 :                         return -errno;
     274                 :            :         }
     275                 :            : 
     276                 :          0 :         return 0;
     277                 :            : }
     278                 :            : 
     279                 :          0 : int ethtool_set_wol(int *fd, const char *ifname, WakeOnLan wol) {
     280                 :          0 :         struct ethtool_wolinfo ecmd = {
     281                 :            :                 .cmd = ETHTOOL_GWOL
     282                 :            :         };
     283                 :          0 :         struct ifreq ifr = {
     284                 :            :                 .ifr_data = (void*) &ecmd
     285                 :            :         };
     286                 :          0 :         bool need_update = false;
     287                 :            :         int r;
     288                 :            : 
     289         [ #  # ]:          0 :         if (wol == _WOL_INVALID)
     290                 :          0 :                 return 0;
     291                 :            : 
     292         [ #  # ]:          0 :         if (*fd < 0) {
     293                 :          0 :                 r = ethtool_connect_or_warn(fd, true);
     294         [ #  # ]:          0 :                 if (r < 0)
     295                 :          0 :                         return r;
     296                 :            :         }
     297                 :            : 
     298                 :          0 :         strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
     299                 :            : 
     300                 :          0 :         r = ioctl(*fd, SIOCETHTOOL, &ifr);
     301         [ #  # ]:          0 :         if (r < 0)
     302                 :          0 :                 return -errno;
     303                 :            : 
     304   [ #  #  #  #  :          0 :         switch (wol) {
             #  #  #  #  
                      # ]
     305                 :          0 :         case WOL_PHY:
     306         [ #  # ]:          0 :                 if (ecmd.wolopts != WAKE_PHY) {
     307                 :          0 :                         ecmd.wolopts = WAKE_PHY;
     308                 :          0 :                         need_update = true;
     309                 :            :                 }
     310                 :          0 :                 break;
     311                 :          0 :         case WOL_UCAST:
     312         [ #  # ]:          0 :                 if (ecmd.wolopts != WAKE_UCAST) {
     313                 :          0 :                         ecmd.wolopts = WAKE_UCAST;
     314                 :          0 :                         need_update = true;
     315                 :            :                 }
     316                 :          0 :                 break;
     317                 :          0 :         case WOL_MCAST:
     318         [ #  # ]:          0 :                 if (ecmd.wolopts != WAKE_MCAST) {
     319                 :          0 :                         ecmd.wolopts = WAKE_MCAST;
     320                 :          0 :                         need_update = true;
     321                 :            :                 }
     322                 :          0 :                 break;
     323                 :          0 :         case WOL_BCAST:
     324         [ #  # ]:          0 :                 if (ecmd.wolopts != WAKE_BCAST) {
     325                 :          0 :                         ecmd.wolopts = WAKE_BCAST;
     326                 :          0 :                         need_update = true;
     327                 :            :                 }
     328                 :          0 :                 break;
     329                 :          0 :         case WOL_ARP:
     330         [ #  # ]:          0 :                 if (ecmd.wolopts != WAKE_ARP) {
     331                 :          0 :                         ecmd.wolopts = WAKE_ARP;
     332                 :          0 :                         need_update = true;
     333                 :            :                 }
     334                 :          0 :                 break;
     335                 :          0 :         case WOL_MAGIC:
     336         [ #  # ]:          0 :                 if (ecmd.wolopts != WAKE_MAGIC) {
     337                 :          0 :                         ecmd.wolopts = WAKE_MAGIC;
     338                 :          0 :                         need_update = true;
     339                 :            :                 }
     340                 :          0 :                 break;
     341                 :          0 :         case WOL_MAGICSECURE:
     342         [ #  # ]:          0 :                 if (ecmd.wolopts != WAKE_MAGICSECURE) {
     343                 :          0 :                         ecmd.wolopts = WAKE_MAGICSECURE;
     344                 :          0 :                         need_update = true;
     345                 :            :                 }
     346                 :          0 :                 break;
     347                 :          0 :         case WOL_OFF:
     348         [ #  # ]:          0 :                 if (ecmd.wolopts != 0) {
     349                 :          0 :                         ecmd.wolopts = 0;
     350                 :          0 :                         need_update = true;
     351                 :            :                 }
     352                 :          0 :                 break;
     353                 :          0 :         default:
     354                 :          0 :                 break;
     355                 :            :         }
     356                 :            : 
     357         [ #  # ]:          0 :         if (need_update) {
     358                 :          0 :                 ecmd.cmd = ETHTOOL_SWOL;
     359                 :            : 
     360                 :          0 :                 r = ioctl(*fd, SIOCETHTOOL, &ifr);
     361         [ #  # ]:          0 :                 if (r < 0)
     362                 :          0 :                         return -errno;
     363                 :            :         }
     364                 :            : 
     365                 :          0 :         return 0;
     366                 :            : }
     367                 :            : 
     368                 :          0 : static int get_stringset(int fd, struct ifreq *ifr, int stringset_id, struct ethtool_gstrings **gstrings) {
     369                 :          0 :         _cleanup_free_ struct ethtool_gstrings *strings = NULL;
     370                 :            :         struct {
     371                 :            :                 struct ethtool_sset_info info;
     372                 :            :                 uint32_t space;
     373                 :          0 :         } buffer = {
     374                 :            :                 .info = {
     375                 :            :                         .cmd = ETHTOOL_GSSET_INFO,
     376                 :          0 :                         .sset_mask = UINT64_C(1) << stringset_id,
     377                 :            :                 },
     378                 :            :         };
     379                 :            :         unsigned len;
     380                 :            :         int r;
     381                 :            : 
     382                 :          0 :         ifr->ifr_data = (void *) &buffer.info;
     383                 :            : 
     384                 :          0 :         r = ioctl(fd, SIOCETHTOOL, ifr);
     385         [ #  # ]:          0 :         if (r < 0)
     386                 :          0 :                 return -errno;
     387                 :            : 
     388         [ #  # ]:          0 :         if (!buffer.info.sset_mask)
     389                 :          0 :                 return -EINVAL;
     390                 :            : 
     391                 :          0 :         len = buffer.info.data[0];
     392                 :            : 
     393                 :          0 :         strings = malloc0(sizeof(struct ethtool_gstrings) + len * ETH_GSTRING_LEN);
     394         [ #  # ]:          0 :         if (!strings)
     395                 :          0 :                 return -ENOMEM;
     396                 :            : 
     397                 :          0 :         strings->cmd = ETHTOOL_GSTRINGS;
     398                 :          0 :         strings->string_set = stringset_id;
     399                 :          0 :         strings->len = len;
     400                 :            : 
     401                 :          0 :         ifr->ifr_data = (void *) strings;
     402                 :            : 
     403                 :          0 :         r = ioctl(fd, SIOCETHTOOL, ifr);
     404         [ #  # ]:          0 :         if (r < 0)
     405                 :          0 :                 return -errno;
     406                 :            : 
     407                 :          0 :         *gstrings = TAKE_PTR(strings);
     408                 :            : 
     409                 :          0 :         return 0;
     410                 :            : }
     411                 :            : 
     412                 :          0 : static int find_feature_index(struct ethtool_gstrings *strings, const char *feature) {
     413                 :            :         unsigned i;
     414                 :            : 
     415         [ #  # ]:          0 :         for (i = 0; i < strings->len; i++) {
     416         [ #  # ]:          0 :                 if (streq((char *) &strings->data[i * ETH_GSTRING_LEN], feature))
     417                 :          0 :                         return i;
     418                 :            :         }
     419                 :            : 
     420                 :          0 :         return -ENODATA;
     421                 :            : }
     422                 :            : 
     423                 :          0 : int ethtool_set_features(int *fd, const char *ifname, int *features) {
     424                 :          0 :         _cleanup_free_ struct ethtool_gstrings *strings = NULL;
     425                 :            :         struct ethtool_sfeatures *sfeatures;
     426                 :            :         int block, bit, i, r;
     427                 :          0 :         struct ifreq ifr = {};
     428                 :            : 
     429         [ #  # ]:          0 :         if (*fd < 0) {
     430                 :          0 :                 r = ethtool_connect_or_warn(fd, true);
     431         [ #  # ]:          0 :                 if (r < 0)
     432                 :          0 :                         return r;
     433                 :            :         }
     434                 :            : 
     435                 :          0 :         strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
     436                 :            : 
     437                 :          0 :         r = get_stringset(*fd, &ifr, ETH_SS_FEATURES, &strings);
     438         [ #  # ]:          0 :         if (r < 0)
     439         [ #  # ]:          0 :                 return log_warning_errno(r, "ethtool: could not get ethtool features for %s", ifname);
     440                 :            : 
     441         [ #  # ]:          0 :         sfeatures = alloca0(sizeof(struct ethtool_sfeatures) + DIV_ROUND_UP(strings->len, 32U) * sizeof(sfeatures->features[0]));
     442                 :          0 :         sfeatures->cmd = ETHTOOL_SFEATURES;
     443                 :          0 :         sfeatures->size = DIV_ROUND_UP(strings->len, 32U);
     444                 :            : 
     445         [ #  # ]:          0 :         for (i = 0; i < _NET_DEV_FEAT_MAX; i++) {
     446                 :            : 
     447         [ #  # ]:          0 :                 if (features[i] != -1) {
     448                 :            : 
     449                 :          0 :                         r = find_feature_index(strings, netdev_feature_table[i]);
     450         [ #  # ]:          0 :                         if (r < 0) {
     451         [ #  # ]:          0 :                                 log_warning_errno(r, "ethtool: could not find feature: %s", netdev_feature_table[i]);
     452                 :          0 :                                 continue;
     453                 :            :                         }
     454                 :            : 
     455                 :          0 :                         block = r / 32;
     456                 :          0 :                         bit = r % 32;
     457                 :            : 
     458                 :          0 :                         sfeatures->features[block].valid |= 1 << bit;
     459                 :            : 
     460         [ #  # ]:          0 :                         if (features[i])
     461                 :          0 :                                 sfeatures->features[block].requested |= 1 << bit;
     462                 :            :                         else
     463                 :          0 :                                 sfeatures->features[block].requested &= ~(1 << bit);
     464                 :            :                 }
     465                 :            :         }
     466                 :            : 
     467                 :          0 :         ifr.ifr_data = (void *) sfeatures;
     468                 :            : 
     469                 :          0 :         r = ioctl(*fd, SIOCETHTOOL, &ifr);
     470         [ #  # ]:          0 :         if (r < 0)
     471         [ #  # ]:          0 :                 return log_warning_errno(r, "ethtool: could not set ethtool features for %s", ifname);
     472                 :            : 
     473                 :          0 :         return 0;
     474                 :            : }
     475                 :            : 
     476                 :          0 : static int get_glinksettings(int fd, struct ifreq *ifr, struct ethtool_link_usettings **g) {
     477                 :            :         struct ecmd {
     478                 :            :                 struct ethtool_link_settings req;
     479                 :            :                 __u32 link_mode_data[3 * ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32];
     480                 :          0 :         } ecmd = {
     481                 :            :                 .req.cmd = ETHTOOL_GLINKSETTINGS,
     482                 :            :         };
     483                 :            :         struct ethtool_link_usettings *u;
     484                 :            :         unsigned offset;
     485                 :            :         int r;
     486                 :            : 
     487                 :            :         /* The interaction user/kernel via the new API requires a small ETHTOOL_GLINKSETTINGS
     488                 :            :            handshake first to agree on the length of the link mode bitmaps. If kernel doesn't
     489                 :            :            agree with user, it returns the bitmap length it is expecting from user as a negative
     490                 :            :            length (and cmd field is 0). When kernel and user agree, kernel returns valid info in
     491                 :            :            all fields (ie. link mode length > 0 and cmd is ETHTOOL_GLINKSETTINGS). Based on
     492                 :            :            https://github.com/torvalds/linux/commit/3f1ac7a700d039c61d8d8b99f28d605d489a60cf
     493                 :            :         */
     494                 :            : 
     495                 :          0 :         ifr->ifr_data = (void *) &ecmd;
     496                 :            : 
     497                 :          0 :         r = ioctl(fd, SIOCETHTOOL, ifr);
     498         [ #  # ]:          0 :         if (r < 0)
     499                 :          0 :                 return -errno;
     500                 :            : 
     501   [ #  #  #  # ]:          0 :         if (ecmd.req.link_mode_masks_nwords >= 0 || ecmd.req.cmd != ETHTOOL_GLINKSETTINGS)
     502                 :          0 :                 return -EOPNOTSUPP;
     503                 :            : 
     504                 :          0 :         ecmd.req.link_mode_masks_nwords = -ecmd.req.link_mode_masks_nwords;
     505                 :            : 
     506                 :          0 :         ifr->ifr_data = (void *) &ecmd;
     507                 :            : 
     508                 :          0 :         r = ioctl(fd, SIOCETHTOOL, ifr);
     509         [ #  # ]:          0 :         if (r < 0)
     510                 :          0 :                 return -errno;
     511                 :            : 
     512   [ #  #  #  # ]:          0 :         if (ecmd.req.link_mode_masks_nwords <= 0 || ecmd.req.cmd != ETHTOOL_GLINKSETTINGS)
     513                 :          0 :                 return -EOPNOTSUPP;
     514                 :            : 
     515                 :          0 :         u = new(struct ethtool_link_usettings, 1);
     516         [ #  # ]:          0 :         if (!u)
     517                 :          0 :                 return -ENOMEM;
     518                 :            : 
     519                 :          0 :         *u = (struct ethtool_link_usettings) {
     520                 :            :                 .base = ecmd.req,
     521                 :            :         };
     522                 :            : 
     523                 :          0 :         offset = 0;
     524                 :          0 :         memcpy(u->link_modes.supported, &ecmd.link_mode_data[offset], 4 * ecmd.req.link_mode_masks_nwords);
     525                 :            : 
     526                 :          0 :         offset += ecmd.req.link_mode_masks_nwords;
     527                 :          0 :         memcpy(u->link_modes.advertising, &ecmd.link_mode_data[offset], 4 * ecmd.req.link_mode_masks_nwords);
     528                 :            : 
     529                 :          0 :         offset += ecmd.req.link_mode_masks_nwords;
     530                 :          0 :         memcpy(u->link_modes.lp_advertising, &ecmd.link_mode_data[offset], 4 * ecmd.req.link_mode_masks_nwords);
     531                 :            : 
     532                 :          0 :         *g = u;
     533                 :            : 
     534                 :          0 :         return 0;
     535                 :            : }
     536                 :            : 
     537                 :          0 : static int get_gset(int fd, struct ifreq *ifr, struct ethtool_link_usettings **u) {
     538                 :            :         struct ethtool_link_usettings *e;
     539                 :          0 :         struct ethtool_cmd ecmd = {
     540                 :            :                 .cmd = ETHTOOL_GSET,
     541                 :            :         };
     542                 :            :         int r;
     543                 :            : 
     544                 :          0 :         ifr->ifr_data = (void *) &ecmd;
     545                 :            : 
     546                 :          0 :         r = ioctl(fd, SIOCETHTOOL, ifr);
     547         [ #  # ]:          0 :         if (r < 0)
     548                 :          0 :                 return -errno;
     549                 :            : 
     550                 :          0 :         e = new(struct ethtool_link_usettings, 1);
     551         [ #  # ]:          0 :         if (!e)
     552                 :          0 :                 return -ENOMEM;
     553                 :            : 
     554                 :          0 :         *e = (struct ethtool_link_usettings) {
     555                 :            :                 .base.cmd = ETHTOOL_GSET,
     556                 :            :                 .base.link_mode_masks_nwords = 1,
     557                 :          0 :                 .base.speed = ethtool_cmd_speed(&ecmd),
     558                 :          0 :                 .base.duplex = ecmd.duplex,
     559                 :          0 :                 .base.port = ecmd.port,
     560                 :          0 :                 .base.phy_address = ecmd.phy_address,
     561                 :          0 :                 .base.autoneg = ecmd.autoneg,
     562                 :          0 :                 .base.mdio_support = ecmd.mdio_support,
     563                 :            : 
     564                 :          0 :                 .link_modes.supported[0] = ecmd.supported,
     565                 :          0 :                 .link_modes.advertising[0] = ecmd.advertising,
     566                 :          0 :                 .link_modes.lp_advertising[0] = ecmd.lp_advertising,
     567                 :            :         };
     568                 :            : 
     569                 :          0 :         *u = e;
     570                 :            : 
     571                 :          0 :         return 0;
     572                 :            : }
     573                 :            : 
     574                 :          0 : static int set_slinksettings(int fd, struct ifreq *ifr, const struct ethtool_link_usettings *u) {
     575                 :            :         struct {
     576                 :            :                 struct ethtool_link_settings req;
     577                 :            :                 __u32 link_mode_data[3 * ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32];
     578                 :          0 :         } ecmd = {};
     579                 :            :         unsigned offset;
     580                 :            :         int r;
     581                 :            : 
     582   [ #  #  #  # ]:          0 :         if (u->base.cmd != ETHTOOL_GLINKSETTINGS || u->base.link_mode_masks_nwords <= 0)
     583                 :          0 :                 return -EINVAL;
     584                 :            : 
     585                 :          0 :         ecmd.req = u->base;
     586                 :          0 :         ecmd.req.cmd = ETHTOOL_SLINKSETTINGS;
     587                 :          0 :         offset = 0;
     588                 :          0 :         memcpy(&ecmd.link_mode_data[offset], u->link_modes.supported, 4 * ecmd.req.link_mode_masks_nwords);
     589                 :            : 
     590                 :          0 :         offset += ecmd.req.link_mode_masks_nwords;
     591                 :          0 :         memcpy(&ecmd.link_mode_data[offset], u->link_modes.advertising, 4 * ecmd.req.link_mode_masks_nwords);
     592                 :            : 
     593                 :          0 :         offset += ecmd.req.link_mode_masks_nwords;
     594                 :          0 :         memcpy(&ecmd.link_mode_data[offset], u->link_modes.lp_advertising, 4 * ecmd.req.link_mode_masks_nwords);
     595                 :            : 
     596                 :          0 :         ifr->ifr_data = (void *) &ecmd;
     597                 :            : 
     598                 :          0 :         r = ioctl(fd, SIOCETHTOOL, ifr);
     599         [ #  # ]:          0 :         if (r < 0)
     600                 :          0 :                 return -errno;
     601                 :            : 
     602                 :          0 :         return 0;
     603                 :            : }
     604                 :            : 
     605                 :          0 : static int set_sset(int fd, struct ifreq *ifr, const struct ethtool_link_usettings *u) {
     606                 :          0 :         struct ethtool_cmd ecmd = {
     607                 :            :                 .cmd = ETHTOOL_SSET,
     608                 :            :         };
     609                 :            :         int r;
     610                 :            : 
     611   [ #  #  #  # ]:          0 :         if (u->base.cmd != ETHTOOL_GSET || u->base.link_mode_masks_nwords <= 0)
     612                 :          0 :                 return -EINVAL;
     613                 :            : 
     614                 :          0 :         ecmd.supported = u->link_modes.supported[0];
     615                 :          0 :         ecmd.advertising = u->link_modes.advertising[0];
     616                 :          0 :         ecmd.lp_advertising = u->link_modes.lp_advertising[0];
     617                 :            : 
     618                 :          0 :         ethtool_cmd_speed_set(&ecmd, u->base.speed);
     619                 :            : 
     620                 :          0 :         ecmd.duplex = u->base.duplex;
     621                 :          0 :         ecmd.port = u->base.port;
     622                 :          0 :         ecmd.phy_address = u->base.phy_address;
     623                 :          0 :         ecmd.autoneg = u->base.autoneg;
     624                 :          0 :         ecmd.mdio_support = u->base.mdio_support;
     625                 :          0 :         ecmd.eth_tp_mdix = u->base.eth_tp_mdix;
     626                 :          0 :         ecmd.eth_tp_mdix_ctrl = u->base.eth_tp_mdix_ctrl;
     627                 :            : 
     628                 :          0 :         ifr->ifr_data = (void *) &ecmd;
     629                 :            : 
     630                 :          0 :         r = ioctl(fd, SIOCETHTOOL, ifr);
     631         [ #  # ]:          0 :         if (r < 0)
     632                 :          0 :                 return -errno;
     633                 :            : 
     634                 :          0 :         return 0;
     635                 :            : }
     636                 :            : 
     637                 :            : /* If autonegotiation is disabled, the speed and duplex represent the fixed link
     638                 :            :  * mode and are writable if the driver supports multiple link modes. If it is
     639                 :            :  * enabled then they are read-only. If the link is up they represent the negotiated
     640                 :            :  * link mode; if the link is down, the speed is 0, %SPEED_UNKNOWN or the highest
     641                 :            :  * enabled speed and @duplex is %DUPLEX_UNKNOWN or the best enabled duplex mode.
     642                 :            :  */
     643                 :          0 : int ethtool_set_glinksettings(
     644                 :            :                 int *fd,
     645                 :            :                 const char *ifname,
     646                 :            :                 int autonegotiation,
     647                 :            :                 uint32_t advertise[static N_ADVERTISE],
     648                 :            :                 size_t speed,
     649                 :            :                 Duplex duplex,
     650                 :            :                 NetDevPort port) {
     651                 :          0 :         _cleanup_free_ struct ethtool_link_usettings *u = NULL;
     652                 :          0 :         struct ifreq ifr = {};
     653                 :            :         int r;
     654                 :            : 
     655         [ #  # ]:          0 :         assert(advertise);
     656                 :            : 
     657   [ #  #  #  # ]:          0 :         if (autonegotiation != AUTONEG_DISABLE && memeqzero(advertise, sizeof(uint32_t) * N_ADVERTISE)) {
     658         [ #  # ]:          0 :                 log_info("ethtool: autonegotiation is unset or enabled, the speed and duplex are not writable.");
     659                 :          0 :                 return 0;
     660                 :            :         }
     661                 :            : 
     662         [ #  # ]:          0 :         if (*fd < 0) {
     663                 :          0 :                 r = ethtool_connect_or_warn(fd, true);
     664         [ #  # ]:          0 :                 if (r < 0)
     665                 :          0 :                         return r;
     666                 :            :         }
     667                 :            : 
     668                 :          0 :         strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
     669                 :            : 
     670                 :          0 :         r = get_glinksettings(*fd, &ifr, &u);
     671         [ #  # ]:          0 :         if (r < 0) {
     672                 :          0 :                 r = get_gset(*fd, &ifr, &u);
     673         [ #  # ]:          0 :                 if (r < 0)
     674         [ #  # ]:          0 :                         return log_warning_errno(r, "ethtool: Cannot get device settings for %s : %m", ifname);
     675                 :            :         }
     676                 :            : 
     677         [ #  # ]:          0 :         if (speed > 0)
     678                 :          0 :                 u->base.speed = DIV_ROUND_UP(speed, 1000000);
     679                 :            : 
     680         [ #  # ]:          0 :         if (duplex != _DUP_INVALID)
     681                 :          0 :                 u->base.duplex = duplex;
     682                 :            : 
     683         [ #  # ]:          0 :         if (port != _NET_DEV_PORT_INVALID)
     684                 :          0 :                 u->base.port = port;
     685                 :            : 
     686         [ #  # ]:          0 :         if (autonegotiation >= 0)
     687                 :          0 :                 u->base.autoneg = autonegotiation;
     688                 :            : 
     689         [ #  # ]:          0 :         if (!memeqzero(advertise, sizeof(uint32_t) * N_ADVERTISE)) {
     690                 :          0 :                 u->base.autoneg = AUTONEG_ENABLE;
     691                 :          0 :                 memcpy(&u->link_modes.advertising, advertise, sizeof(uint32_t) * N_ADVERTISE);
     692         [ #  # ]:          0 :                 memzero((uint8_t*) &u->link_modes.advertising + sizeof(uint32_t) * N_ADVERTISE,
     693                 :            :                         ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NBYTES - sizeof(uint32_t) * N_ADVERTISE);
     694                 :            :         }
     695                 :            : 
     696         [ #  # ]:          0 :         if (u->base.cmd == ETHTOOL_GLINKSETTINGS)
     697                 :          0 :                 r = set_slinksettings(*fd, &ifr, u);
     698                 :            :         else
     699                 :          0 :                 r = set_sset(*fd, &ifr, u);
     700         [ #  # ]:          0 :         if (r < 0)
     701         [ #  # ]:          0 :                 return log_warning_errno(r, "ethtool: Cannot set device settings for %s : %m", ifname);
     702                 :            : 
     703                 :          0 :         return r;
     704                 :            : }
     705                 :            : 
     706                 :          0 : int ethtool_set_channels(int *fd, const char *ifname, netdev_channels *channels) {
     707                 :          0 :         struct ethtool_channels ecmd = {
     708                 :            :                 .cmd = ETHTOOL_GCHANNELS
     709                 :            :         };
     710                 :          0 :         struct ifreq ifr = {
     711                 :            :                 .ifr_data = (void*) &ecmd
     712                 :            :         };
     713                 :            : 
     714                 :          0 :         bool need_update = false;
     715                 :            :         int r;
     716                 :            : 
     717         [ #  # ]:          0 :         if (*fd < 0) {
     718                 :          0 :                 r = ethtool_connect_or_warn(fd, true);
     719         [ #  # ]:          0 :                 if (r < 0)
     720                 :          0 :                         return r;
     721                 :            :         }
     722                 :            : 
     723                 :          0 :         strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
     724                 :            : 
     725                 :          0 :         r = ioctl(*fd, SIOCETHTOOL, &ifr);
     726         [ #  # ]:          0 :         if (r < 0)
     727                 :          0 :                 return -errno;
     728                 :            : 
     729   [ #  #  #  # ]:          0 :         if (channels->rx_count_set && ecmd.rx_count != channels->rx_count) {
     730                 :          0 :                 ecmd.rx_count = channels->rx_count;
     731                 :          0 :                 need_update = true;
     732                 :            :         }
     733                 :            : 
     734   [ #  #  #  # ]:          0 :         if (channels->tx_count_set && ecmd.tx_count != channels->tx_count) {
     735                 :          0 :                 ecmd.tx_count = channels->tx_count;
     736                 :          0 :                 need_update = true;
     737                 :            :         }
     738                 :            : 
     739   [ #  #  #  # ]:          0 :         if (channels->other_count_set && ecmd.other_count != channels->other_count) {
     740                 :          0 :                 ecmd.other_count = channels->other_count;
     741                 :          0 :                 need_update = true;
     742                 :            :         }
     743                 :            : 
     744   [ #  #  #  # ]:          0 :         if (channels->combined_count_set && ecmd.combined_count != channels->combined_count) {
     745                 :          0 :                 ecmd.combined_count = channels->combined_count;
     746                 :          0 :                 need_update = true;
     747                 :            :         }
     748                 :            : 
     749         [ #  # ]:          0 :         if (need_update) {
     750                 :          0 :                 ecmd.cmd = ETHTOOL_SCHANNELS;
     751                 :            : 
     752                 :          0 :                 r = ioctl(*fd, SIOCETHTOOL, &ifr);
     753         [ #  # ]:          0 :                 if (r < 0)
     754                 :          0 :                         return -errno;
     755                 :            :         }
     756                 :            : 
     757                 :          0 :         return 0;
     758                 :            : }
     759                 :            : 
     760                 :          0 : int config_parse_channel(const char *unit,
     761                 :            :                          const char *filename,
     762                 :            :                          unsigned line,
     763                 :            :                          const char *section,
     764                 :            :                          unsigned section_line,
     765                 :            :                          const char *lvalue,
     766                 :            :                          int ltype,
     767                 :            :                          const char *rvalue,
     768                 :            :                          void *data,
     769                 :            :                          void *userdata) {
     770                 :          0 :         netdev_channels *channels = data;
     771                 :            :         uint32_t k;
     772                 :            :         int r;
     773                 :            : 
     774         [ #  # ]:          0 :         assert(filename);
     775         [ #  # ]:          0 :         assert(section);
     776         [ #  # ]:          0 :         assert(lvalue);
     777         [ #  # ]:          0 :         assert(rvalue);
     778         [ #  # ]:          0 :         assert(data);
     779                 :            : 
     780                 :          0 :         r = safe_atou32(rvalue, &k);
     781         [ #  # ]:          0 :         if (r < 0) {
     782         [ #  # ]:          0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse channel value, ignoring: %s", rvalue);
     783                 :          0 :                 return 0;
     784                 :            :         }
     785                 :            : 
     786         [ #  # ]:          0 :         if (k < 1) {
     787         [ #  # ]:          0 :                 log_syntax(unit, LOG_ERR, filename, line, -EINVAL, "Invalid %s value, ignoring: %s", lvalue, rvalue);
     788                 :          0 :                 return 0;
     789                 :            :         }
     790                 :            : 
     791         [ #  # ]:          0 :         if (streq(lvalue, "RxChannels")) {
     792                 :          0 :                 channels->rx_count = k;
     793                 :          0 :                 channels->rx_count_set = true;
     794         [ #  # ]:          0 :         } else if (streq(lvalue, "TxChannels")) {
     795                 :          0 :                 channels->tx_count = k;
     796                 :          0 :                 channels->tx_count_set = true;
     797         [ #  # ]:          0 :         } else if (streq(lvalue, "OtherChannels")) {
     798                 :          0 :                 channels->other_count = k;
     799                 :          0 :                 channels->other_count_set = true;
     800         [ #  # ]:          0 :         } else if (streq(lvalue, "CombinedChannels")) {
     801                 :          0 :                 channels->combined_count = k;
     802                 :          0 :                 channels->combined_count_set = true;
     803                 :            :         }
     804                 :            : 
     805                 :          0 :         return 0;
     806                 :            : }
     807                 :            : 
     808                 :          0 : int config_parse_advertise(const char *unit,
     809                 :            :                            const char *filename,
     810                 :            :                            unsigned line,
     811                 :            :                            const char *section,
     812                 :            :                            unsigned section_line,
     813                 :            :                            const char *lvalue,
     814                 :            :                            int ltype,
     815                 :            :                            const char *rvalue,
     816                 :            :                            void *data,
     817                 :            :                            void *userdata) {
     818                 :          0 :         uint32_t *advertise = data;
     819                 :            :         const char *p;
     820                 :            :         int r;
     821                 :            : 
     822         [ #  # ]:          0 :         assert(filename);
     823         [ #  # ]:          0 :         assert(section);
     824         [ #  # ]:          0 :         assert(lvalue);
     825         [ #  # ]:          0 :         assert(rvalue);
     826         [ #  # ]:          0 :         assert(data);
     827                 :            : 
     828         [ #  # ]:          0 :         if (isempty(rvalue)) {
     829                 :            :                 /* Empty string resets the value. */
     830         [ #  # ]:          0 :                 memzero(advertise, sizeof(uint32_t) * N_ADVERTISE);
     831                 :          0 :                 return 0;
     832                 :            :         }
     833                 :            : 
     834                 :          0 :         for (p = rvalue;;) {
     835   [ #  #  #  # ]:          0 :                 _cleanup_free_ char *w = NULL;
     836                 :            :                 enum ethtool_link_mode_bit_indices mode;
     837                 :            : 
     838                 :          0 :                 r = extract_first_word(&p, &w, NULL, 0);
     839         [ #  # ]:          0 :                 if (r == -ENOMEM)
     840                 :          0 :                         return log_oom();
     841         [ #  # ]:          0 :                 if (r < 0) {
     842         [ #  # ]:          0 :                         log_syntax(unit, LOG_ERR, filename, line, r, "Failed to split advertise modes '%s', ignoring: %m", rvalue);
     843                 :          0 :                         break;
     844                 :            :                 }
     845         [ #  # ]:          0 :                 if (r == 0)
     846                 :          0 :                         break;
     847                 :            : 
     848                 :          0 :                 mode = ethtool_link_mode_bit_from_string(w);
     849                 :            :                 /* We reuse the kernel provided enum which does not contain negative value. So, the cast
     850                 :            :                  * below is mandatory. Otherwise, the check below always passes and access an invalid address. */
     851         [ #  # ]:          0 :                 if ((int) mode < 0) {
     852         [ #  # ]:          0 :                         log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse advertise mode, ignoring: %s", w);
     853                 :          0 :                         continue;
     854                 :            :                 }
     855                 :            : 
     856                 :          0 :                 advertise[mode / 32] |= 1UL << (mode % 32);
     857                 :            :         }
     858                 :            : 
     859                 :          0 :         return 0;
     860                 :            : }

Generated by: LCOV version 1.14