ethtool-util.c revision 61087906e099eb462a0fc123afca5687795f0fd4
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye/***
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye This file is part of systemd.
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye systemd is free software; you can redistribute it and/or modify it
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye under the terms of the GNU Lesser General Public License as published by
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye the Free Software Foundation; either version 2.1 of the License, or
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye (at your option) any later version.
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye systemd is distributed in the hope that it will be useful, but
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye WITHOUT ANY WARRANTY; without even the implied warranty of
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye Lesser General Public License for more details.
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye You should have received a copy of the GNU Lesser General Public License
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye along with systemd; If not, see <http://www.gnu.org/licenses/>.
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye***/
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye#include <sys/ioctl.h>
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye#include <net/if.h>
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye#include <linux/ethtool.h>
cf1f7b5e81583dfca30972cfef322266a6928e7fKnut Anders Hatlen#include <linux/sockios.h>
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye#include "ethtool-util.h"
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye#include "strxcpyx.h"
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye#include "util.h"
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye#include "log.h"
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye#include "conf-parser.h"
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye
64b763950bf11e9357facbd2b5666631a895c085Trond Norbyestatic const char* const duplex_table[_DUP_MAX] = {
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye [DUP_FULL] = "full",
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye [DUP_HALF] = "half"
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye};
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye
64b763950bf11e9357facbd2b5666631a895c085Trond NorbyeDEFINE_STRING_TABLE_LOOKUP(duplex, Duplex);
64b763950bf11e9357facbd2b5666631a895c085Trond NorbyeDEFINE_CONFIG_PARSE_ENUM(config_parse_duplex, duplex, Duplex, "Failed to parse duplex setting");
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye
64b763950bf11e9357facbd2b5666631a895c085Trond Norbyestatic const char* const wol_table[_WOL_MAX] = {
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye [WOL_PHY] = "phy",
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye [WOL_MAGIC] = "magic",
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye [WOL_OFF] = "off"
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye};
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye
64b763950bf11e9357facbd2b5666631a895c085Trond NorbyeDEFINE_STRING_TABLE_LOOKUP(wol, WakeOnLan);
64b763950bf11e9357facbd2b5666631a895c085Trond NorbyeDEFINE_CONFIG_PARSE_ENUM(config_parse_wol, wol, WakeOnLan, "Failed to parse WakeOnLan setting");
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye
64b763950bf11e9357facbd2b5666631a895c085Trond Norbyeint ethtool_connect(int *ret) {
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye int fd;
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye assert_return(ret, -EINVAL);
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye fd = socket(PF_INET, SOCK_DGRAM, 0);
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye if (fd < 0) {
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye return -errno;
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye }
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye *ret = fd;
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye return 0;
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye}
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye
64b763950bf11e9357facbd2b5666631a895c085Trond Norbyeint ethtool_get_driver(int *fd, const char *ifname, char **ret) {
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye struct ethtool_drvinfo ecmd = {
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye .cmd = ETHTOOL_GDRVINFO
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye };
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye struct ifreq ifr = {
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye .ifr_data = (void*) &ecmd
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye };
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye char *d;
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye int r;
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye if (*fd < 0) {
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye r = ethtool_connect(fd);
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye if (r < 0)
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye }
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye r = ioctl(*fd, SIOCETHTOOL, &ifr);
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye if (r < 0)
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye return -errno;
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye d = strdup(ecmd.driver);
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye if (!d)
0a0811923cbbd2976425db6f4c78eed811c2825bKnut Anders Hatlen return -ENOMEM;
b68083650aff0d1663971a216369f651559db2a1Knut Anders Hatlen
a07b2874263e3c5f0cd2e83441719415d53059c2Knut Anders Hatlen *ret = d;
c7eb123c8b2081a261deff3c401fbf92ddba1b58Jorgen Austvik return 0;
c7eb123c8b2081a261deff3c401fbf92ddba1b58Jorgen Austvik}
49f592091468eac515dde6139fbc8efa26056b0aJorgen Austvik
945f4c3c36a15447913781dfb1894b34f2941c57Jorgen Austvikint ethtool_set_speed(int *fd, const char *ifname, unsigned int speed, Duplex duplex) {
5a0c5ad4116f5a4dd0dd5a0a4e6d02973cd5eef9Lubos Kosco struct ethtool_cmd ecmd = {
780cc7d1b57609ff15fb283201e93cb501ebe9e6Jorgen Austvik .cmd = ETHTOOL_GSET
780cc7d1b57609ff15fb283201e93cb501ebe9e6Jorgen Austvik };
780cc7d1b57609ff15fb283201e93cb501ebe9e6Jorgen Austvik struct ifreq ifr = {
d3d2404f9a49bf70b124053feabe666f85ef5361Knut Anders Hatlen .ifr_data = (void*) &ecmd
d3d2404f9a49bf70b124053feabe666f85ef5361Knut Anders Hatlen };
780cc7d1b57609ff15fb283201e93cb501ebe9e6Jorgen Austvik bool need_update = false;
780cc7d1b57609ff15fb283201e93cb501ebe9e6Jorgen Austvik int r;
7b9f9a1761f76744fc3772181877d5e301f122adKnut Anders Hatlen
5a0c5ad4116f5a4dd0dd5a0a4e6d02973cd5eef9Lubos Kosco if (speed == 0 && duplex == _DUP_INVALID)
0466de7c67573e1ce5e0733325c1e5383270f5d5Knut Anders Hatlen return 0;
0466de7c67573e1ce5e0733325c1e5383270f5d5Knut Anders Hatlen
0466de7c67573e1ce5e0733325c1e5383270f5d5Knut Anders Hatlen if (*fd < 0) {
0466de7c67573e1ce5e0733325c1e5383270f5d5Knut Anders Hatlen r = ethtool_connect(fd);
5a0c5ad4116f5a4dd0dd5a0a4e6d02973cd5eef9Lubos Kosco if (r < 0)
5a0c5ad4116f5a4dd0dd5a0a4e6d02973cd5eef9Lubos Kosco return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
5a0c5ad4116f5a4dd0dd5a0a4e6d02973cd5eef9Lubos Kosco }
1ed6b730409d4740e941142599767d5eac7e7d92Lubos Kosco
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik r = ioctl(*fd, SIOCETHTOOL, &ifr);
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco if (r < 0)
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco return -errno;
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik if (ethtool_cmd_speed(&ecmd) != speed) {
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik ethtool_cmd_speed_set(&ecmd, speed);
c7eb123c8b2081a261deff3c401fbf92ddba1b58Jorgen Austvik need_update = true;
5a0c5ad4116f5a4dd0dd5a0a4e6d02973cd5eef9Lubos Kosco }
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik switch (duplex) {
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik case DUP_HALF:
49f592091468eac515dde6139fbc8efa26056b0aJorgen Austvik if (ecmd.duplex != DUPLEX_HALF) {
49f592091468eac515dde6139fbc8efa26056b0aJorgen Austvik ecmd.duplex = DUPLEX_HALF;
5a0c5ad4116f5a4dd0dd5a0a4e6d02973cd5eef9Lubos Kosco need_update = true;
49f592091468eac515dde6139fbc8efa26056b0aJorgen Austvik }
49f592091468eac515dde6139fbc8efa26056b0aJorgen Austvik break;
945f4c3c36a15447913781dfb1894b34f2941c57Jorgen Austvik case DUP_FULL:
945f4c3c36a15447913781dfb1894b34f2941c57Jorgen Austvik if (ecmd.duplex != DUPLEX_FULL) {
5a0c5ad4116f5a4dd0dd5a0a4e6d02973cd5eef9Lubos Kosco ecmd.duplex = DUPLEX_FULL;
945f4c3c36a15447913781dfb1894b34f2941c57Jorgen Austvik need_update = true;
945f4c3c36a15447913781dfb1894b34f2941c57Jorgen Austvik }
945f4c3c36a15447913781dfb1894b34f2941c57Jorgen Austvik break;
1ed6b730409d4740e941142599767d5eac7e7d92Lubos Kosco default:
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik break;
1ed6b730409d4740e941142599767d5eac7e7d92Lubos Kosco }
7ecd52b03dc1f0b03ff8f522b4891c8531896c3dJorgen Austvik
1ed6b730409d4740e941142599767d5eac7e7d92Lubos Kosco if (need_update) {
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco ecmd.cmd = ETHTOOL_SSET;
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco r = ioctl(*fd, SIOCETHTOOL, &ifr);
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco if (r < 0)
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco return -errno;
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco }
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco return 0;
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco}
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Koscoint ethtool_set_wol(int *fd, const char *ifname, WakeOnLan wol) {
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco struct ethtool_wolinfo ecmd = {
45909b3ef8c6e568a87482cb890fec7b5dbb7733Lubos Kosco .cmd = ETHTOOL_GWOL
45909b3ef8c6e568a87482cb890fec7b5dbb7733Lubos Kosco };
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco struct ifreq ifr = {
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco .ifr_data = (void*) &ecmd
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco };
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco bool need_update = false;
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco int r;
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco if (wol == _WOL_INVALID)
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco return 0;
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco if (*fd < 0) {
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco r = ethtool_connect(fd);
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco if (r < 0)
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco }
b34561d2c3d92fac37dbced05ba6a8738e3d20e9Lubos Kosco
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
64b763950bf11e9357facbd2b5666631a895c085Trond Norbye
7b046969a1b2565787df8ae3a8126359e8cd6fafTrond Norbye r = ioctl(*fd, SIOCETHTOOL, &ifr);
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen if (r < 0)
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen return -errno;
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen switch (wol) {
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen case WOL_PHY:
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen if (ecmd.wolopts != WAKE_PHY) {
7b046969a1b2565787df8ae3a8126359e8cd6fafTrond Norbye ecmd.wolopts = WAKE_PHY;
7b046969a1b2565787df8ae3a8126359e8cd6fafTrond Norbye need_update = true;
7b046969a1b2565787df8ae3a8126359e8cd6fafTrond Norbye }
3d35131df8607ae05b064219b9448afc5c4b550aKnut Anders Hatlen break;
3d35131df8607ae05b064219b9448afc5c4b550aKnut Anders Hatlen case WOL_MAGIC:
7b046969a1b2565787df8ae3a8126359e8cd6fafTrond Norbye if (ecmd.wolopts != WAKE_MAGIC) {
7b046969a1b2565787df8ae3a8126359e8cd6fafTrond Norbye ecmd.wolopts = WAKE_MAGIC;
7b046969a1b2565787df8ae3a8126359e8cd6fafTrond Norbye need_update = true;
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen }
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen break;
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen case WOL_OFF:
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen if (ecmd.wolopts != 0) {
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen ecmd.wolopts = 0;
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen need_update = true;
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen }
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen break;
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen default:
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen break;
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen }
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen if (need_update) {
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen ecmd.cmd = ETHTOOL_SWOL;
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen r = ioctl(*fd, SIOCETHTOOL, &ifr);
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen if (r < 0)
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen return -errno;
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen }
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen return 0;
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen}
a5cc1506d5c0704805c6733a46c7f1f8f91ae724Knut Anders Hatlen