]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/udev/net/ethtool-util.c
net-util: call ioctl() only if necessary
[thirdparty/systemd.git] / src / udev / net / ethtool-util.c
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[] = {
35 [DUP_FULL] = "full",
36 [DUP_HALF] = "half"
37 };
38
39 DEFINE_STRING_TABLE_LOOKUP(duplex, Duplex);
40 DEFINE_CONFIG_PARSE_ENUM(config_parse_duplex, duplex, Duplex, "Failed to parse duplex setting");
41
42 static const char* const wol_table[] = {
43 [WOL_PHY] = "phy",
44 [WOL_MAGIC] = "magic",
45 [WOL_OFF] = "off"
46 };
47
48 DEFINE_STRING_TABLE_LOOKUP(wol, WakeOnLan);
49 DEFINE_CONFIG_PARSE_ENUM(config_parse_wol, wol, WakeOnLan, "Failed to parse WakeOnLan setting");
50
51 int ethtool_connect(int *ret) {
52 int fd;
53
54 assert_return(ret, -EINVAL);
55
56 fd = socket(PF_INET, SOCK_DGRAM, 0);
57 if (fd < 0) {
58 return -errno;
59 }
60
61 *ret = fd;
62
63 return 0;
64 }
65
66 int ethtool_set_speed(int fd, const char *ifname, unsigned int speed, Duplex duplex)
67 {
68 struct ifreq ifr;
69 struct ethtool_cmd ecmd;
70 bool need_update = false;
71 int r;
72
73 if (speed == 0 && duplex == _DUP_INVALID)
74 return 0;
75
76 zero(ecmd);
77 ecmd.cmd = ETHTOOL_GSET;
78
79 zero(ifr);
80 strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
81 ifr.ifr_data = (void *)&ecmd;
82
83 r = ioctl(fd, SIOCETHTOOL, &ifr);
84 if (r < 0)
85 return -errno;
86
87 if (ethtool_cmd_speed(&ecmd) != speed) {
88 ethtool_cmd_speed_set(&ecmd, speed);
89 need_update = true;
90 }
91
92 switch (duplex) {
93 case DUP_HALF:
94 if (ecmd.duplex != DUPLEX_HALF) {
95 ecmd.duplex = DUPLEX_HALF;
96 need_update = true;
97 }
98 break;
99 case DUP_FULL:
100 if (ecmd.duplex != DUPLEX_FULL) {
101 ecmd.duplex = DUPLEX_FULL;
102 need_update = true;
103 }
104 break;
105 default:
106 break;
107 }
108
109 if (need_update) {
110 ecmd.cmd = ETHTOOL_SSET;
111
112 r = ioctl(fd, SIOCETHTOOL, &ifr);
113 if (r < 0)
114 return -errno;
115 }
116
117 return 0;
118 }
119
120 int ethtool_set_wol(int fd, const char *ifname, WakeOnLan wol) {
121 struct ifreq ifr;
122 struct ethtool_wolinfo ecmd;
123 bool need_update = false;
124 int r;
125
126 if (wol == _WOL_INVALID)
127 return 0;
128
129 zero(ecmd);
130 ecmd.cmd = ETHTOOL_GWOL;
131
132 zero(ifr);
133 strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
134 ifr.ifr_data = (void *)&ecmd;
135
136 r = ioctl(fd, SIOCETHTOOL, &ifr);
137 if (r < 0)
138 return -errno;
139
140 switch (wol) {
141 case WOL_PHY:
142 if (ecmd.wolopts != WAKE_PHY) {
143 ecmd.wolopts = WAKE_PHY;
144 need_update = true;
145 }
146 break;
147 case WOL_MAGIC:
148 if (ecmd.wolopts != WAKE_MAGIC) {
149 ecmd.wolopts = WAKE_MAGIC;
150 need_update = true;
151 }
152 break;
153 case WOL_OFF:
154 if (ecmd.wolopts != 0) {
155 ecmd.wolopts = 0;
156 need_update = true;
157 }
158 break;
159 default:
160 break;
161 }
162
163 if (need_update) {
164 ecmd.cmd = ETHTOOL_SWOL;
165
166 r = ioctl(fd, SIOCETHTOOL, &ifr);
167 if (r < 0)
168 return -errno;
169 }
170
171 return 0;
172 }