netif_utils: correctly close fd on read error
[project/ustp.git] / netif_utils.c
1 /*****************************************************************************
2 Copyright (c) 2006 EMC Corporation.
3 Copyright (c) 2011 Factor-SPE
4
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the Free
7 Software Foundation; either version 2 of the License, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful, but WITHOUT
11 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 more details.
14
15 You should have received a copy of the GNU General Public License along with
16 this program; if not, write to the Free Software Foundation, Inc., 59
17 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 The full GNU General Public License is included in this distribution in the
20 file called LICENSE.
21
22 Authors: Srinivas Aji <Aji_Srinivas@emc.com>
23 Authors: Vitalii Demianets <dvitasgs@gmail.com>
24
25 ******************************************************************************/
26
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <stdbool.h>
31 #include <fcntl.h>
32 #include <limits.h>
33 #include <sys/ioctl.h>
34 #include <sys/types.h>
35 #include <net/if.h>
36 #include <linux/if_ether.h>
37 #include <linux/ethtool.h>
38 #include <linux/sockios.h>
39
40 #include "netif_utils.h"
41 #include "log.h"
42
43 #ifndef SYSFS_CLASS_NET
44 #define SYSFS_CLASS_NET "/sys/class/net"
45 #endif
46
47 static int netsock = -1;
48
49 int netsock_init(void)
50 {
51 netsock = socket(AF_INET, SOCK_DGRAM, 0);
52 if(0 > netsock)
53 {
54 ERROR("Couldn't open inet socket for ioctls: %m\n");
55 return -1;
56 }
57 return 0;
58 }
59
60 int get_hwaddr(char *ifname, __u8 *hwaddr)
61 {
62 struct ifreq ifr;
63 memset(&ifr, 0, sizeof(ifr));
64 strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
65 if(0 > ioctl(netsock, SIOCGIFHWADDR, &ifr))
66 {
67 ERROR("%s: get hw address failed: %m", ifname);
68 return -1;
69 }
70 memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
71 return 0;
72 }
73
74 int get_flags(char *ifname)
75 {
76 struct ifreq ifr;
77 memset(&ifr, 0, sizeof(ifr));
78 strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
79 if(0 > ioctl(netsock, SIOCGIFFLAGS, &ifr))
80 {
81 ERROR("%s: get interface flags failed: %m", ifname);
82 return -1;
83 }
84 return ifr.ifr_flags;
85 }
86
87 int if_shutdown(char *ifname)
88 {
89 struct ifreq ifr;
90
91 memset(&ifr, 0, sizeof(ifr));
92 /* TODO: Let's hope -1 is not a valid flag combination */
93 if(-1 == (ifr.ifr_flags = get_flags(ifname)))
94 {
95 return -1;
96 }
97 ifr.ifr_flags &= ~IFF_UP;
98 strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
99 if(0 > ioctl(netsock, SIOCSIFFLAGS, &ifr))
100 {
101 ERROR("%s: set if_down flag failed: %m", ifname);
102 return -1;
103 }
104 return 0;
105 }
106
107 int ethtool_get_speed_duplex(char *ifname, int *speed, int *duplex)
108 {
109 struct ifreq ifr;
110 memset(&ifr, 0, sizeof(ifr));
111 strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
112 struct ethtool_cmd ecmd;
113
114 ecmd.cmd = ETHTOOL_GSET;
115 ifr.ifr_data = (caddr_t)&ecmd;
116 if(0 > ioctl(netsock, SIOCETHTOOL, &ifr))
117 {
118 INFO("Cannot get speed/duplex for %s: %m\n", ifname);
119 return -1;
120 }
121 *speed = ecmd.speed; /* Ethtool speed is in Mbps */
122 *duplex = ecmd.duplex; /* We have same convention as ethtool.
123 0 = half, 1 = full */
124 return 0;
125 }
126
127 /********* Sysfs based utility functions *************/
128
129 /* This sysfs stuff might break with interface renames */
130 bool is_bridge(char *if_name)
131 {
132 char path[32 + IFNAMSIZ];
133 sprintf(path, SYSFS_CLASS_NET "/%s/bridge", if_name);
134 return (0 == access(path, R_OK));
135 }
136
137 static int get_port_file(const char *if_name, const char *file)
138 {
139 char path[32 + IFNAMSIZ];
140 sprintf(path, SYSFS_CLASS_NET "/%s/brport/%s", if_name, file);
141 char buf[128];
142 int fd;
143 long res = -1;
144 TSTM((fd = open(path, O_RDONLY)) >= 0, -1, "%m");
145 int l;
146 if((l = read(fd, buf, sizeof(buf) - 1)) < 0) {
147 ERROR("Failed to read file %s: error %m", file);
148 return -1;
149 }
150 if(0 == l)
151 {
152 ERROR("Empty %s file", file);
153 goto out;
154 }
155 else if((sizeof(buf) - 1) == l)
156 {
157 ERROR("%s file too long", file);
158 goto out;
159 }
160 buf[l] = 0;
161 if('\n' == buf[l - 1])
162 buf[l - 1] = 0;
163 char *end;
164 res = strtoul(buf, &end, 0);
165 if(0 != *end || INT_MAX < res)
166 {
167 ERROR("Invalid %s %s", file, buf);
168 res = -1;
169 }
170 out:
171 close(fd);
172 return res;
173 }
174
175 int get_bpdu_filter(char *if_name)
176 {
177 return get_port_file(if_name, "bpdu_filter");
178 }
179
180 int get_bridge_portno(char *if_name)
181 {
182 return get_port_file(if_name, "port_no");
183 }