]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/udev/net/ethtool-util.c
tree-wide: drop {} from one-line if blocks
[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[_DUP_MAX] = {
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[_WOL_MAX] = {
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 *ret = fd;
61
62 return 0;
63 }
64
65 int ethtool_get_driver(int *fd, const char *ifname, char **ret) {
66 struct ethtool_drvinfo ecmd = {
67 .cmd = ETHTOOL_GDRVINFO
68 };
69 struct ifreq ifr = {
70 .ifr_data = (void*) &ecmd
71 };
72 char *d;
73 int r;
74
75 if (*fd < 0) {
76 r = ethtool_connect(fd);
77 if (r < 0)
78 return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
79 }
80
81 strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
82
83 r = ioctl(*fd, SIOCETHTOOL, &ifr);
84 if (r < 0)
85 return -errno;
86
87 d = strdup(ecmd.driver);
88 if (!d)
89 return -ENOMEM;
90
91 *ret = d;
92 return 0;
93 }
94
95 int ethtool_set_speed(int *fd, const char *ifname, unsigned int speed, Duplex duplex) {
96 struct ethtool_cmd ecmd = {
97 .cmd = ETHTOOL_GSET
98 };
99 struct ifreq ifr = {
100 .ifr_data = (void*) &ecmd
101 };
102 bool need_update = false;
103 int r;
104
105 if (speed == 0 && duplex == _DUP_INVALID)
106 return 0;
107
108 if (*fd < 0) {
109 r = ethtool_connect(fd);
110 if (r < 0)
111 return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
112 }
113
114 strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
115
116 r = ioctl(*fd, SIOCETHTOOL, &ifr);
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
125 switch (duplex) {
126 case DUP_HALF:
127 if (ecmd.duplex != DUPLEX_HALF) {
128 ecmd.duplex = DUPLEX_HALF;
129 need_update = true;
130 }
131 break;
132 case DUP_FULL:
133 if (ecmd.duplex != DUPLEX_FULL) {
134 ecmd.duplex = DUPLEX_FULL;
135 need_update = true;
136 }
137 break;
138 default:
139 break;
140 }
141
142 if (need_update) {
143 ecmd.cmd = ETHTOOL_SSET;
144
145 r = ioctl(*fd, SIOCETHTOOL, &ifr);
146 if (r < 0)
147 return -errno;
148 }
149
150 return 0;
151 }
152
153 int ethtool_set_wol(int *fd, const char *ifname, WakeOnLan wol) {
154 struct ethtool_wolinfo ecmd = {
155 .cmd = ETHTOOL_GWOL
156 };
157 struct ifreq ifr = {
158 .ifr_data = (void*) &ecmd
159 };
160 bool need_update = false;
161 int r;
162
163 if (wol == _WOL_INVALID)
164 return 0;
165
166 if (*fd < 0) {
167 r = ethtool_connect(fd);
168 if (r < 0)
169 return log_warning_errno(r, "link_config: could not connect to ethtool: %m");
170 }
171
172 strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
173
174 r = ioctl(*fd, SIOCETHTOOL, &ifr);
175 if (r < 0)
176 return -errno;
177
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 }
200
201 if (need_update) {
202 ecmd.cmd = ETHTOOL_SWOL;
203
204 r = ioctl(*fd, SIOCETHTOOL, &ifr);
205 if (r < 0)
206 return -errno;
207 }
208
209 return 0;
210 }