LCOV - code coverage report
Current view: top level - udev/net - ethtool-util.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 2 94 2.1 %
Date: 2015-07-29 18:47:03 Functions: 4 10 40.0 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :  This file is part of systemd.
       5             : 
       6             :  Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
       7             : 
       8             :   systemd is free software; you can redistribute it and/or modify it
       9             :   under the terms of the GNU Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   systemd is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             : ***/
      21             : 
      22             : #include <sys/ioctl.h>
      23             : #include <net/if.h>
      24             : #include <linux/ethtool.h>
      25             : #include <linux/sockios.h>
      26             : 
      27             : #include "ethtool-util.h"
      28             : 
      29             : #include "strxcpyx.h"
      30             : #include "util.h"
      31             : #include "log.h"
      32             : #include "conf-parser.h"
      33             : 
      34             : static const char* const duplex_table[_DUP_MAX] = {
      35             :         [DUP_FULL] = "full",
      36             :         [DUP_HALF] = "half"
      37             : };
      38             : 
      39           8 : DEFINE_STRING_TABLE_LOOKUP(duplex, Duplex);
      40           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_duplex, duplex, Duplex, "Failed to parse duplex setting");
      41             : 
      42             : static const char* const wol_table[_WOL_MAX] = {
      43             :         [WOL_PHY] = "phy",
      44             :         [WOL_MAGIC] = "magic",
      45             :         [WOL_OFF] = "off"
      46             : };
      47             : 
      48          10 : DEFINE_STRING_TABLE_LOOKUP(wol, WakeOnLan);
      49           0 : DEFINE_CONFIG_PARSE_ENUM(config_parse_wol, wol, WakeOnLan, "Failed to parse WakeOnLan setting");
      50             : 
      51           0 : int ethtool_connect(int *ret) {
      52             :         int fd;
      53             : 
      54           0 :         assert_return(ret, -EINVAL);
      55             : 
      56           0 :         fd = socket(PF_INET, SOCK_DGRAM, 0);
      57           0 :         if (fd < 0) {
      58           0 :                 return -errno;
      59             :         }
      60             : 
      61           0 :         *ret = fd;
      62             : 
      63           0 :         return 0;
      64             : }
      65             : 
      66           0 : int ethtool_get_driver(int *fd, const char *ifname, char **ret) {
      67           0 :         struct ethtool_drvinfo ecmd = {
      68             :                 .cmd = ETHTOOL_GDRVINFO
      69             :         };
      70           0 :         struct ifreq ifr = {
      71             :                 .ifr_data = (void*) &ecmd
      72             :         };
      73             :         char *d;
      74             :         int r;
      75             : 
      76           0 :         if (*fd < 0) {
      77           0 :                 r = ethtool_connect(fd);
      78           0 :                 if (r < 0)
      79           0 :                         return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
      80             :         }
      81             : 
      82           0 :         strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
      83             : 
      84           0 :         r = ioctl(*fd, SIOCETHTOOL, &ifr);
      85           0 :         if (r < 0)
      86           0 :                 return -errno;
      87             : 
      88           0 :         d = strdup(ecmd.driver);
      89           0 :         if (!d)
      90           0 :                 return -ENOMEM;
      91             : 
      92           0 :         *ret = d;
      93           0 :         return 0;
      94             : }
      95             : 
      96           0 : int ethtool_set_speed(int *fd, const char *ifname, unsigned int speed, Duplex duplex) {
      97           0 :         struct ethtool_cmd ecmd = {
      98             :                 .cmd = ETHTOOL_GSET
      99             :         };
     100           0 :         struct ifreq ifr = {
     101             :                 .ifr_data = (void*) &ecmd
     102             :         };
     103           0 :         bool need_update = false;
     104             :         int r;
     105             : 
     106           0 :         if (speed == 0 && duplex == _DUP_INVALID)
     107           0 :                 return 0;
     108             : 
     109           0 :         if (*fd < 0) {
     110           0 :                 r = ethtool_connect(fd);
     111           0 :                 if (r < 0)
     112           0 :                         return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
     113             :         }
     114             : 
     115           0 :         strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
     116             : 
     117           0 :         r = ioctl(*fd, SIOCETHTOOL, &ifr);
     118           0 :         if (r < 0)
     119           0 :                 return -errno;
     120             : 
     121           0 :         if (ethtool_cmd_speed(&ecmd) != speed) {
     122           0 :                 ethtool_cmd_speed_set(&ecmd, speed);
     123           0 :                 need_update = true;
     124             :         }
     125             : 
     126           0 :         switch (duplex) {
     127             :                 case DUP_HALF:
     128           0 :                         if (ecmd.duplex != DUPLEX_HALF) {
     129           0 :                                 ecmd.duplex = DUPLEX_HALF;
     130           0 :                                 need_update = true;
     131             :                         }
     132           0 :                         break;
     133             :                 case DUP_FULL:
     134           0 :                         if (ecmd.duplex != DUPLEX_FULL) {
     135           0 :                                 ecmd.duplex = DUPLEX_FULL;
     136           0 :                                 need_update = true;
     137             :                         }
     138           0 :                         break;
     139             :                 default:
     140           0 :                         break;
     141             :         }
     142             : 
     143           0 :         if (need_update) {
     144           0 :                 ecmd.cmd = ETHTOOL_SSET;
     145             : 
     146           0 :                 r = ioctl(*fd, SIOCETHTOOL, &ifr);
     147           0 :                 if (r < 0)
     148           0 :                         return -errno;
     149             :         }
     150             : 
     151           0 :         return 0;
     152             : }
     153             : 
     154           0 : int ethtool_set_wol(int *fd, const char *ifname, WakeOnLan wol) {
     155           0 :         struct ethtool_wolinfo ecmd = {
     156             :                 .cmd = ETHTOOL_GWOL
     157             :         };
     158           0 :         struct ifreq ifr = {
     159             :                 .ifr_data = (void*) &ecmd
     160             :         };
     161           0 :         bool need_update = false;
     162             :         int r;
     163             : 
     164           0 :         if (wol == _WOL_INVALID)
     165           0 :                 return 0;
     166             : 
     167           0 :         if (*fd < 0) {
     168           0 :                 r = ethtool_connect(fd);
     169           0 :                 if (r < 0)
     170           0 :                         return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
     171             :         }
     172             : 
     173           0 :         strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
     174             : 
     175           0 :         r = ioctl(*fd, SIOCETHTOOL, &ifr);
     176           0 :         if (r < 0)
     177           0 :                 return -errno;
     178             : 
     179           0 :         switch (wol) {
     180             :                 case WOL_PHY:
     181           0 :                         if (ecmd.wolopts != WAKE_PHY) {
     182           0 :                                 ecmd.wolopts = WAKE_PHY;
     183           0 :                                 need_update = true;
     184             :                         }
     185           0 :                         break;
     186             :                 case WOL_MAGIC:
     187           0 :                         if (ecmd.wolopts != WAKE_MAGIC) {
     188           0 :                                 ecmd.wolopts = WAKE_MAGIC;
     189           0 :                                 need_update = true;
     190             :                         }
     191           0 :                         break;
     192             :                 case WOL_OFF:
     193           0 :                         if (ecmd.wolopts != 0) {
     194           0 :                                 ecmd.wolopts = 0;
     195           0 :                                 need_update = true;
     196             :                         }
     197           0 :                         break;
     198             :                 default:
     199           0 :                         break;
     200             :         }
     201             : 
     202           0 :         if (need_update) {
     203           0 :                 ecmd.cmd = ETHTOOL_SWOL;
     204             : 
     205           0 :                 r = ioctl(*fd, SIOCETHTOOL, &ifr);
     206           0 :                 if (r < 0)
     207           0 :                         return -errno;
     208             :         }
     209             : 
     210           0 :         return 0;
     211             : }

Generated by: LCOV version 1.11