]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/udev/net/ethtool-util.c
tree-wide: drop {} from one-line if blocks
[thirdparty/systemd.git] / src / udev / net / ethtool-util.c
CommitLineData
a5010333
TG
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"
5fde13d7
TG
32#include "conf-parser.h"
33
2c5859af 34static const char* const duplex_table[_DUP_MAX] = {
5fde13d7
TG
35 [DUP_FULL] = "full",
36 [DUP_HALF] = "half"
37};
38
39DEFINE_STRING_TABLE_LOOKUP(duplex, Duplex);
40DEFINE_CONFIG_PARSE_ENUM(config_parse_duplex, duplex, Duplex, "Failed to parse duplex setting");
41
2c5859af 42static const char* const wol_table[_WOL_MAX] = {
5fde13d7
TG
43 [WOL_PHY] = "phy",
44 [WOL_MAGIC] = "magic",
45 [WOL_OFF] = "off"
46};
47
48DEFINE_STRING_TABLE_LOOKUP(wol, WakeOnLan);
49DEFINE_CONFIG_PARSE_ENUM(config_parse_wol, wol, WakeOnLan, "Failed to parse WakeOnLan setting");
a5010333
TG
50
51int ethtool_connect(int *ret) {
52 int fd;
53
54 assert_return(ret, -EINVAL);
55
56 fd = socket(PF_INET, SOCK_DGRAM, 0);
ece174c5 57 if (fd < 0)
a5010333 58 return -errno;
a5010333
TG
59
60 *ret = fd;
61
62 return 0;
63}
64
aedca892 65int ethtool_get_driver(int *fd, const char *ifname, char **ret) {
61f3af4f
LP
66 struct ethtool_drvinfo ecmd = {
67 .cmd = ETHTOOL_GDRVINFO
68 };
69 struct ifreq ifr = {
70 .ifr_data = (void*) &ecmd
71 };
72 char *d;
847a8a5f
TG
73 int r;
74
aedca892
TG
75 if (*fd < 0) {
76 r = ethtool_connect(fd);
f647962d
MS
77 if (r < 0)
78 return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
aedca892
TG
79 }
80
847a8a5f 81 strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
847a8a5f 82
aedca892 83 r = ioctl(*fd, SIOCETHTOOL, &ifr);
847a8a5f
TG
84 if (r < 0)
85 return -errno;
86
61f3af4f
LP
87 d = strdup(ecmd.driver);
88 if (!d)
847a8a5f
TG
89 return -ENOMEM;
90
61f3af4f 91 *ret = d;
847a8a5f
TG
92 return 0;
93}
94
61087906 95int ethtool_set_speed(int *fd, const char *ifname, unsigned int speed, Duplex duplex) {
6c0519c0
TG
96 struct ethtool_cmd ecmd = {
97 .cmd = ETHTOOL_GSET
98 };
99 struct ifreq ifr = {
100 .ifr_data = (void*) &ecmd
101 };
0a2c2294 102 bool need_update = false;
a5010333
TG
103 int r;
104
5fde13d7 105 if (speed == 0 && duplex == _DUP_INVALID)
a5010333
TG
106 return 0;
107
aedca892
TG
108 if (*fd < 0) {
109 r = ethtool_connect(fd);
f647962d
MS
110 if (r < 0)
111 return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
aedca892
TG
112 }
113
a5010333 114 strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
a5010333 115
aedca892 116 r = ioctl(*fd, SIOCETHTOOL, &ifr);
a5010333
TG
117 if (r < 0)
118 return -errno;
119
120 if (ethtool_cmd_speed(&ecmd) != speed) {
121 ethtool_cmd_speed_set(&ecmd, speed);
122 need_update = true;
123 }
124
5fde13d7
TG
125 switch (duplex) {
126 case DUP_HALF:
a5010333
TG
127 if (ecmd.duplex != DUPLEX_HALF) {
128 ecmd.duplex = DUPLEX_HALF;
129 need_update = true;
130 }
5fde13d7
TG
131 break;
132 case DUP_FULL:
a5010333
TG
133 if (ecmd.duplex != DUPLEX_FULL) {
134 ecmd.duplex = DUPLEX_FULL;
135 need_update = true;
136 }
5fde13d7
TG
137 break;
138 default:
139 break;
a5010333
TG
140 }
141
142 if (need_update) {
143 ecmd.cmd = ETHTOOL_SSET;
144
aedca892 145 r = ioctl(*fd, SIOCETHTOOL, &ifr);
a5010333
TG
146 if (r < 0)
147 return -errno;
148 }
149
150 return 0;
151}
152
aedca892 153int ethtool_set_wol(int *fd, const char *ifname, WakeOnLan wol) {
6c0519c0
TG
154 struct ethtool_wolinfo ecmd = {
155 .cmd = ETHTOOL_GWOL
156 };
157 struct ifreq ifr = {
158 .ifr_data = (void*) &ecmd
159 };
0a2c2294 160 bool need_update = false;
a5010333
TG
161 int r;
162
5fde13d7 163 if (wol == _WOL_INVALID)
a5010333
TG
164 return 0;
165
aedca892
TG
166 if (*fd < 0) {
167 r = ethtool_connect(fd);
f647962d
MS
168 if (r < 0)
169 return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
aedca892
TG
170 }
171
a5010333 172 strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
a5010333 173
aedca892 174 r = ioctl(*fd, SIOCETHTOOL, &ifr);
a5010333
TG
175 if (r < 0)
176 return -errno;
177
5fde13d7
TG
178 switch (wol) {
179 case WOL_PHY:
180 if (ecmd.wolopts != WAKE_PHY) {
181 ecmd.wolopts = WAKE_PHY;
182 need_update = true;
183 }
184 break;
185 case WOL_MAGIC:
186 if (ecmd.wolopts != WAKE_MAGIC) {
187 ecmd.wolopts = WAKE_MAGIC;
188 need_update = true;
189 }
190 break;
191 case WOL_OFF:
192 if (ecmd.wolopts != 0) {
193 ecmd.wolopts = 0;
194 need_update = true;
195 }
196 break;
197 default:
198 break;
199 }
a5010333
TG
200
201 if (need_update) {
202 ecmd.cmd = ETHTOOL_SWOL;
203
aedca892 204 r = ioctl(*fd, SIOCETHTOOL, &ifr);
a5010333
TG
205 if (r < 0)
206 return -errno;
207 }
208
209 return 0;
210}