1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
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.
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.
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/>.
22 #include <sys/ioctl.h>
24 #include <linux/ethtool.h>
25 #include <linux/sockios.h>
27 #include "ethtool-util.h"
32 #include "conf-parser.h"
34 static const char* const duplex_table[_DUP_MAX] = {
39 DEFINE_STRING_TABLE_LOOKUP(duplex, Duplex);
40 DEFINE_CONFIG_PARSE_ENUM(config_parse_duplex, duplex, Duplex, "Failed to parse duplex setting");
42 static const char* const wol_table[_WOL_MAX] = {
44 [WOL_MAGIC] = "magic",
48 DEFINE_STRING_TABLE_LOOKUP(wol, WakeOnLan);
49 DEFINE_CONFIG_PARSE_ENUM(config_parse_wol, wol, WakeOnLan, "Failed to parse WakeOnLan setting");
51 int ethtool_connect(int *ret) {
54 assert_return(ret, -EINVAL);
56 fd = socket(PF_INET, SOCK_DGRAM, 0);
66 int ethtool_get_driver(int *fd, const char *ifname, char **ret) {
67 struct ethtool_drvinfo ecmd = {
68 .cmd = ETHTOOL_GDRVINFO
71 .ifr_data = (void*) &ecmd
77 r = ethtool_connect(fd);
79 log_warning("link_config: could not connect to ethtool: %s", strerror(-r));
84 strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
86 r = ioctl(*fd, SIOCETHTOOL, &ifr);
90 d = strdup(ecmd.driver);
98 int ethtool_set_speed(int *fd, const char *ifname, unsigned int speed, Duplex duplex)
100 struct ethtool_cmd ecmd = {
104 .ifr_data = (void*) &ecmd
106 bool need_update = false;
109 if (speed == 0 && duplex == _DUP_INVALID)
113 r = ethtool_connect(fd);
115 log_warning("link_config: could not connect to ethtool: %s", strerror(-r));
120 strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
122 r = ioctl(*fd, SIOCETHTOOL, &ifr);
126 if (ethtool_cmd_speed(&ecmd) != speed) {
127 ethtool_cmd_speed_set(&ecmd, speed);
133 if (ecmd.duplex != DUPLEX_HALF) {
134 ecmd.duplex = DUPLEX_HALF;
139 if (ecmd.duplex != DUPLEX_FULL) {
140 ecmd.duplex = DUPLEX_FULL;
149 ecmd.cmd = ETHTOOL_SSET;
151 r = ioctl(*fd, SIOCETHTOOL, &ifr);
159 int ethtool_set_wol(int *fd, const char *ifname, WakeOnLan wol) {
160 struct ethtool_wolinfo ecmd = {
164 .ifr_data = (void*) &ecmd
166 bool need_update = false;
169 if (wol == _WOL_INVALID)
173 r = ethtool_connect(fd);
175 log_warning("link_config: could not connect to ethtool: %s", strerror(-r));
180 strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
182 r = ioctl(*fd, SIOCETHTOOL, &ifr);
188 if (ecmd.wolopts != WAKE_PHY) {
189 ecmd.wolopts = WAKE_PHY;
194 if (ecmd.wolopts != WAKE_MAGIC) {
195 ecmd.wolopts = WAKE_MAGIC;
200 if (ecmd.wolopts != 0) {
210 ecmd.cmd = ETHTOOL_SWOL;
212 r = ioctl(*fd, SIOCETHTOOL, &ifr);