chiark / gitweb /
4fad52b469f28c6ef3216ad726bec04dc6e9d586
[elogind.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;
71         int r;
72
73         if (speed == 0 && duplex == _DUP_INVALID)
74                 return 0;
75
76         memset(&ecmd, 0x00, sizeof(struct ethtool_cmd));
77         ecmd.cmd = ETHTOOL_GSET;
78         memset(&ifr, 0x00, sizeof(struct ifreq));
79         strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
80         ifr.ifr_data = (void *)&ecmd;
81
82         r = ioctl(fd, SIOCETHTOOL, &ifr);
83         if (r < 0)
84                 return -errno;
85
86         if (ethtool_cmd_speed(&ecmd) != speed) {
87                 ethtool_cmd_speed_set(&ecmd, speed);
88                 need_update = true;
89         }
90
91         switch (duplex) {
92                 case DUP_HALF:
93                         if (ecmd.duplex != DUPLEX_HALF) {
94                                 ecmd.duplex = DUPLEX_HALF;
95                                 need_update = true;
96                         }
97                         break;
98                 case DUP_FULL:
99                         if (ecmd.duplex != DUPLEX_FULL) {
100                                 ecmd.duplex = DUPLEX_FULL;
101                                 need_update = true;
102                         }
103                         break;
104                 default:
105                         break;
106         }
107
108         if (need_update) {
109                 ecmd.cmd = ETHTOOL_SSET;
110
111                 r = ioctl(fd, SIOCETHTOOL, &ifr);
112                 if (r < 0)
113                         return -errno;
114         }
115
116         return 0;
117 }
118
119 int ethtool_set_wol(int fd, const char *ifname, WakeOnLan wol) {
120         struct ifreq ifr;
121         struct ethtool_wolinfo ecmd;
122         bool need_update;
123         int r;
124
125         if (wol == _WOL_INVALID)
126                 return 0;
127
128         memset(&ecmd, 0x00, sizeof(struct ethtool_wolinfo));
129         ecmd.cmd = ETHTOOL_GWOL;
130         memset(&ifr, 0x00, sizeof(struct ifreq));
131         strscpy(ifr.ifr_name, IFNAMSIZ, ifname);
132         ifr.ifr_data = (void *)&ecmd;
133
134         r = ioctl(fd, SIOCETHTOOL, &ifr);
135         if (r < 0)
136                 return -errno;
137
138         switch (wol) {
139                 case WOL_PHY:
140                         if (ecmd.wolopts != WAKE_PHY) {
141                                 ecmd.wolopts = WAKE_PHY;
142                                 need_update = true;
143                         }
144                         break;
145                 case WOL_MAGIC:
146                         if (ecmd.wolopts != WAKE_MAGIC) {
147                                 ecmd.wolopts = WAKE_MAGIC;
148                                 need_update = true;
149                         }
150                         break;
151                 case WOL_OFF:
152                         if (ecmd.wolopts != 0) {
153                                 ecmd.wolopts = 0;
154                                 need_update = true;
155                         }
156                         break;
157                 default:
158                         break;
159         }
160
161         if (need_update) {
162                 ecmd.cmd = ETHTOOL_SWOL;
163
164                 r = ioctl(fd, SIOCETHTOOL, &ifr);
165                 if (r < 0)
166                         return -errno;
167         }
168
169         return 0;
170 }