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