1c1d255d3SCy Schubert /*
2c1d255d3SCy Schubert * Linux ioctl helper functions for driver wrappers
3c1d255d3SCy Schubert * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
4c1d255d3SCy Schubert *
5c1d255d3SCy Schubert * This software may be distributed under the terms of the BSD license.
6c1d255d3SCy Schubert * See README for more details.
7c1d255d3SCy Schubert */
8c1d255d3SCy Schubert
9c1d255d3SCy Schubert #include "utils/includes.h"
10c1d255d3SCy Schubert #include <sys/ioctl.h>
11c1d255d3SCy Schubert #include <net/if.h>
12c1d255d3SCy Schubert #include <net/if_arp.h>
13c1d255d3SCy Schubert
14c1d255d3SCy Schubert #include "utils/common.h"
15c1d255d3SCy Schubert #include "common/linux_bridge.h"
16c1d255d3SCy Schubert #include "linux_ioctl.h"
17c1d255d3SCy Schubert
18c1d255d3SCy Schubert
linux_set_iface_flags(int sock,const char * ifname,int dev_up)19c1d255d3SCy Schubert int linux_set_iface_flags(int sock, const char *ifname, int dev_up)
20c1d255d3SCy Schubert {
21c1d255d3SCy Schubert struct ifreq ifr;
22c1d255d3SCy Schubert int ret;
23c1d255d3SCy Schubert
24c1d255d3SCy Schubert if (sock < 0)
25c1d255d3SCy Schubert return -1;
26c1d255d3SCy Schubert
27c1d255d3SCy Schubert os_memset(&ifr, 0, sizeof(ifr));
28c1d255d3SCy Schubert os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
29c1d255d3SCy Schubert
30c1d255d3SCy Schubert if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
31c1d255d3SCy Schubert ret = errno ? -errno : -999;
32c1d255d3SCy Schubert wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s",
33c1d255d3SCy Schubert ifname, strerror(errno));
34c1d255d3SCy Schubert return ret;
35c1d255d3SCy Schubert }
36c1d255d3SCy Schubert
37c1d255d3SCy Schubert if (dev_up) {
38c1d255d3SCy Schubert if (ifr.ifr_flags & IFF_UP)
39c1d255d3SCy Schubert return 0;
40c1d255d3SCy Schubert ifr.ifr_flags |= IFF_UP;
41c1d255d3SCy Schubert } else {
42c1d255d3SCy Schubert if (!(ifr.ifr_flags & IFF_UP))
43c1d255d3SCy Schubert return 0;
44c1d255d3SCy Schubert ifr.ifr_flags &= ~IFF_UP;
45c1d255d3SCy Schubert }
46c1d255d3SCy Schubert
47c1d255d3SCy Schubert if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) {
48c1d255d3SCy Schubert ret = errno ? -errno : -999;
49c1d255d3SCy Schubert wpa_printf(MSG_ERROR, "Could not set interface %s flags (%s): "
50c1d255d3SCy Schubert "%s",
51c1d255d3SCy Schubert ifname, dev_up ? "UP" : "DOWN", strerror(errno));
52c1d255d3SCy Schubert return ret;
53c1d255d3SCy Schubert }
54c1d255d3SCy Schubert
55c1d255d3SCy Schubert return 0;
56c1d255d3SCy Schubert }
57c1d255d3SCy Schubert
58c1d255d3SCy Schubert
linux_iface_up(int sock,const char * ifname)59c1d255d3SCy Schubert int linux_iface_up(int sock, const char *ifname)
60c1d255d3SCy Schubert {
61c1d255d3SCy Schubert struct ifreq ifr;
62c1d255d3SCy Schubert int ret;
63c1d255d3SCy Schubert
64c1d255d3SCy Schubert if (sock < 0)
65c1d255d3SCy Schubert return -1;
66c1d255d3SCy Schubert
67c1d255d3SCy Schubert os_memset(&ifr, 0, sizeof(ifr));
68c1d255d3SCy Schubert os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
69c1d255d3SCy Schubert
70c1d255d3SCy Schubert if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
71c1d255d3SCy Schubert ret = errno ? -errno : -999;
72c1d255d3SCy Schubert wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s",
73c1d255d3SCy Schubert ifname, strerror(errno));
74c1d255d3SCy Schubert return ret;
75c1d255d3SCy Schubert }
76c1d255d3SCy Schubert
77c1d255d3SCy Schubert return !!(ifr.ifr_flags & IFF_UP);
78c1d255d3SCy Schubert }
79c1d255d3SCy Schubert
80c1d255d3SCy Schubert
linux_get_ifhwaddr(int sock,const char * ifname,u8 * addr)81c1d255d3SCy Schubert int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr)
82c1d255d3SCy Schubert {
83c1d255d3SCy Schubert struct ifreq ifr;
84c1d255d3SCy Schubert
85c1d255d3SCy Schubert os_memset(&ifr, 0, sizeof(ifr));
86c1d255d3SCy Schubert os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
87c1d255d3SCy Schubert if (ioctl(sock, SIOCGIFHWADDR, &ifr)) {
88c1d255d3SCy Schubert wpa_printf(MSG_ERROR, "Could not get interface %s hwaddr: %s",
89c1d255d3SCy Schubert ifname, strerror(errno));
90c1d255d3SCy Schubert return -1;
91c1d255d3SCy Schubert }
92c1d255d3SCy Schubert
93c1d255d3SCy Schubert if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
94c1d255d3SCy Schubert wpa_printf(MSG_ERROR, "%s: Invalid HW-addr family 0x%04x",
95c1d255d3SCy Schubert ifname, ifr.ifr_hwaddr.sa_family);
96c1d255d3SCy Schubert return -1;
97c1d255d3SCy Schubert }
98c1d255d3SCy Schubert os_memcpy(addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
99c1d255d3SCy Schubert
100c1d255d3SCy Schubert return 0;
101c1d255d3SCy Schubert }
102c1d255d3SCy Schubert
103c1d255d3SCy Schubert
linux_set_ifhwaddr(int sock,const char * ifname,const u8 * addr)104c1d255d3SCy Schubert int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr)
105c1d255d3SCy Schubert {
106c1d255d3SCy Schubert struct ifreq ifr;
107c1d255d3SCy Schubert
108c1d255d3SCy Schubert os_memset(&ifr, 0, sizeof(ifr));
109c1d255d3SCy Schubert os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
110c1d255d3SCy Schubert os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
111c1d255d3SCy Schubert ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
112c1d255d3SCy Schubert
113c1d255d3SCy Schubert if (ioctl(sock, SIOCSIFHWADDR, &ifr)) {
114c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "Could not set interface %s hwaddr: %s",
115c1d255d3SCy Schubert ifname, strerror(errno));
116c1d255d3SCy Schubert return -1;
117c1d255d3SCy Schubert }
118c1d255d3SCy Schubert
119c1d255d3SCy Schubert return 0;
120c1d255d3SCy Schubert }
121c1d255d3SCy Schubert
122c1d255d3SCy Schubert
linux_br_add(int sock,const char * brname)123c1d255d3SCy Schubert int linux_br_add(int sock, const char *brname)
124c1d255d3SCy Schubert {
125c1d255d3SCy Schubert if (ioctl(sock, SIOCBRADDBR, brname) < 0) {
126c1d255d3SCy Schubert int saved_errno = errno;
127c1d255d3SCy Schubert
128c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "Could not add bridge %s: %s",
129c1d255d3SCy Schubert brname, strerror(errno));
130c1d255d3SCy Schubert errno = saved_errno;
131c1d255d3SCy Schubert return -1;
132c1d255d3SCy Schubert }
133c1d255d3SCy Schubert
134c1d255d3SCy Schubert return 0;
135c1d255d3SCy Schubert }
136c1d255d3SCy Schubert
137c1d255d3SCy Schubert
linux_br_del(int sock,const char * brname)138c1d255d3SCy Schubert int linux_br_del(int sock, const char *brname)
139c1d255d3SCy Schubert {
140c1d255d3SCy Schubert if (ioctl(sock, SIOCBRDELBR, brname) < 0) {
141c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "Could not remove bridge %s: %s",
142c1d255d3SCy Schubert brname, strerror(errno));
143c1d255d3SCy Schubert return -1;
144c1d255d3SCy Schubert }
145c1d255d3SCy Schubert
146c1d255d3SCy Schubert return 0;
147c1d255d3SCy Schubert }
148c1d255d3SCy Schubert
149c1d255d3SCy Schubert
linux_br_add_if(int sock,const char * brname,const char * ifname)150c1d255d3SCy Schubert int linux_br_add_if(int sock, const char *brname, const char *ifname)
151c1d255d3SCy Schubert {
152c1d255d3SCy Schubert struct ifreq ifr;
153c1d255d3SCy Schubert int ifindex;
154c1d255d3SCy Schubert
155c1d255d3SCy Schubert ifindex = if_nametoindex(ifname);
156c1d255d3SCy Schubert if (ifindex == 0)
157c1d255d3SCy Schubert return -1;
158c1d255d3SCy Schubert
159c1d255d3SCy Schubert os_memset(&ifr, 0, sizeof(ifr));
160c1d255d3SCy Schubert os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ);
161c1d255d3SCy Schubert ifr.ifr_ifindex = ifindex;
162c1d255d3SCy Schubert if (ioctl(sock, SIOCBRADDIF, &ifr) < 0) {
163c1d255d3SCy Schubert int saved_errno = errno;
164*a90b9d01SCy Schubert char in_br[IFNAMSIZ];
165c1d255d3SCy Schubert
166c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "Could not add interface %s into bridge "
167c1d255d3SCy Schubert "%s: %s", ifname, brname, strerror(errno));
168c1d255d3SCy Schubert errno = saved_errno;
169*a90b9d01SCy Schubert
170*a90b9d01SCy Schubert /* If ioctl() returns EBUSY when adding an interface into the
171*a90b9d01SCy Schubert * bridge, the interface might have already been added by an
172*a90b9d01SCy Schubert * external operation, so check whether the interface is
173*a90b9d01SCy Schubert * currently on the right bridge and ignore the error if it is.
174*a90b9d01SCy Schubert */
175*a90b9d01SCy Schubert if (errno != EBUSY || linux_br_get(in_br, ifname) != 0 ||
176*a90b9d01SCy Schubert os_strcmp(in_br, brname) != 0)
177c1d255d3SCy Schubert return -1;
178c1d255d3SCy Schubert }
179c1d255d3SCy Schubert
180c1d255d3SCy Schubert return 0;
181c1d255d3SCy Schubert }
182c1d255d3SCy Schubert
183c1d255d3SCy Schubert
linux_br_del_if(int sock,const char * brname,const char * ifname)184c1d255d3SCy Schubert int linux_br_del_if(int sock, const char *brname, const char *ifname)
185c1d255d3SCy Schubert {
186c1d255d3SCy Schubert struct ifreq ifr;
187c1d255d3SCy Schubert int ifindex;
188c1d255d3SCy Schubert
189c1d255d3SCy Schubert ifindex = if_nametoindex(ifname);
190c1d255d3SCy Schubert if (ifindex == 0)
191c1d255d3SCy Schubert return -1;
192c1d255d3SCy Schubert
193c1d255d3SCy Schubert os_memset(&ifr, 0, sizeof(ifr));
194c1d255d3SCy Schubert os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ);
195c1d255d3SCy Schubert ifr.ifr_ifindex = ifindex;
196c1d255d3SCy Schubert if (ioctl(sock, SIOCBRDELIF, &ifr) < 0) {
197c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "Could not remove interface %s from "
198c1d255d3SCy Schubert "bridge %s: %s", ifname, brname, strerror(errno));
199c1d255d3SCy Schubert return -1;
200c1d255d3SCy Schubert }
201c1d255d3SCy Schubert
202c1d255d3SCy Schubert return 0;
203c1d255d3SCy Schubert }
204c1d255d3SCy Schubert
205c1d255d3SCy Schubert
linux_br_get(char * brname,const char * ifname)206c1d255d3SCy Schubert int linux_br_get(char *brname, const char *ifname)
207c1d255d3SCy Schubert {
208c1d255d3SCy Schubert char path[128], brlink[128], *pos;
209c1d255d3SCy Schubert ssize_t res;
210c1d255d3SCy Schubert
211c1d255d3SCy Schubert os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/bridge",
212c1d255d3SCy Schubert ifname);
213c1d255d3SCy Schubert res = readlink(path, brlink, sizeof(brlink));
214c1d255d3SCy Schubert if (res < 0 || (size_t) res >= sizeof(brlink))
215c1d255d3SCy Schubert return -1;
216c1d255d3SCy Schubert brlink[res] = '\0';
217c1d255d3SCy Schubert pos = os_strrchr(brlink, '/');
218c1d255d3SCy Schubert if (pos == NULL)
219c1d255d3SCy Schubert return -1;
220c1d255d3SCy Schubert pos++;
221c1d255d3SCy Schubert os_strlcpy(brname, pos, IFNAMSIZ);
222c1d255d3SCy Schubert return 0;
223c1d255d3SCy Schubert }
224c1d255d3SCy Schubert
225c1d255d3SCy Schubert
linux_master_get(char * master_ifname,const char * ifname)226c1d255d3SCy Schubert int linux_master_get(char *master_ifname, const char *ifname)
227c1d255d3SCy Schubert {
228c1d255d3SCy Schubert char buf[128], masterlink[128], *pos;
229c1d255d3SCy Schubert ssize_t res;
230c1d255d3SCy Schubert
231c1d255d3SCy Schubert /* check whether there is a master */
232c1d255d3SCy Schubert os_snprintf(buf, sizeof(buf), "/sys/class/net/%s/master", ifname);
233c1d255d3SCy Schubert
234c1d255d3SCy Schubert res = readlink(buf, masterlink, sizeof(masterlink));
235c1d255d3SCy Schubert if (res < 0 || (size_t) res >= sizeof(masterlink))
236c1d255d3SCy Schubert return -1;
237c1d255d3SCy Schubert
238c1d255d3SCy Schubert masterlink[res] = '\0';
239c1d255d3SCy Schubert
240c1d255d3SCy Schubert pos = os_strrchr(masterlink, '/');
241c1d255d3SCy Schubert if (pos == NULL)
242c1d255d3SCy Schubert return -1;
243c1d255d3SCy Schubert pos++;
244c1d255d3SCy Schubert os_strlcpy(master_ifname, pos, IFNAMSIZ);
245c1d255d3SCy Schubert return 0;
246c1d255d3SCy Schubert }
247