Line data Source code
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 4655 : int linux_set_iface_flags(int sock, const char *ifname, int dev_up)
19 : {
20 : struct ifreq ifr;
21 : int ret;
22 :
23 4655 : if (sock < 0)
24 0 : return -1;
25 :
26 4655 : os_memset(&ifr, 0, sizeof(ifr));
27 4655 : os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
28 :
29 4655 : if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
30 40 : ret = errno ? -errno : -999;
31 40 : wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s",
32 40 : ifname, strerror(errno));
33 40 : return ret;
34 : }
35 :
36 4615 : if (dev_up) {
37 2327 : if (ifr.ifr_flags & IFF_UP)
38 22 : return 0;
39 2305 : ifr.ifr_flags |= IFF_UP;
40 : } else {
41 2288 : if (!(ifr.ifr_flags & IFF_UP))
42 59 : return 0;
43 2229 : ifr.ifr_flags &= ~IFF_UP;
44 : }
45 :
46 4534 : if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) {
47 0 : ret = errno ? -errno : -999;
48 0 : wpa_printf(MSG_ERROR, "Could not set interface %s flags (%s): "
49 : "%s",
50 0 : ifname, dev_up ? "UP" : "DOWN", strerror(errno));
51 0 : return ret;
52 : }
53 :
54 4534 : return 0;
55 : }
56 :
57 :
58 2720 : int linux_iface_up(int sock, const char *ifname)
59 : {
60 : struct ifreq ifr;
61 : int ret;
62 :
63 2720 : if (sock < 0)
64 0 : return -1;
65 :
66 2720 : os_memset(&ifr, 0, sizeof(ifr));
67 2720 : os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
68 :
69 2720 : if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
70 11 : ret = errno ? -errno : -999;
71 11 : wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s",
72 11 : ifname, strerror(errno));
73 11 : return ret;
74 : }
75 :
76 2709 : return !!(ifr.ifr_flags & IFF_UP);
77 : }
78 :
79 :
80 4135 : int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr)
81 : {
82 : struct ifreq ifr;
83 :
84 4135 : os_memset(&ifr, 0, sizeof(ifr));
85 4135 : os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
86 4135 : if (ioctl(sock, SIOCGIFHWADDR, &ifr)) {
87 0 : wpa_printf(MSG_ERROR, "Could not get interface %s hwaddr: %s",
88 0 : ifname, strerror(errno));
89 0 : return -1;
90 : }
91 :
92 4135 : if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
93 0 : wpa_printf(MSG_ERROR, "%s: Invalid HW-addr family 0x%04x",
94 0 : ifname, ifr.ifr_hwaddr.sa_family);
95 0 : return -1;
96 : }
97 4135 : os_memcpy(addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
98 :
99 4135 : return 0;
100 : }
101 :
102 :
103 207 : int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr)
104 : {
105 : struct ifreq ifr;
106 :
107 207 : os_memset(&ifr, 0, sizeof(ifr));
108 207 : os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
109 207 : os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
110 207 : ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
111 :
112 207 : if (ioctl(sock, SIOCSIFHWADDR, &ifr)) {
113 0 : wpa_printf(MSG_DEBUG, "Could not set interface %s hwaddr: %s",
114 0 : ifname, strerror(errno));
115 0 : return -1;
116 : }
117 :
118 207 : 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 12 : int linux_br_add(int sock, const char *brname)
137 : {
138 12 : if (ioctl(sock, SIOCBRADDBR, brname) < 0) {
139 0 : wpa_printf(MSG_DEBUG, "Could not add bridge %s: %s",
140 0 : brname, strerror(errno));
141 0 : return -1;
142 : }
143 :
144 12 : return 0;
145 : }
146 :
147 :
148 12 : int linux_br_del(int sock, const char *brname)
149 : {
150 12 : if (ioctl(sock, SIOCBRDELBR, brname) < 0) {
151 10 : wpa_printf(MSG_DEBUG, "Could not remove bridge %s: %s",
152 10 : brname, strerror(errno));
153 10 : return -1;
154 : }
155 :
156 2 : return 0;
157 : }
158 :
159 :
160 20 : int linux_br_add_if(int sock, const char *brname, const char *ifname)
161 : {
162 : struct ifreq ifr;
163 : int ifindex;
164 :
165 20 : ifindex = if_nametoindex(ifname);
166 20 : if (ifindex == 0)
167 0 : return -1;
168 :
169 20 : os_memset(&ifr, 0, sizeof(ifr));
170 20 : os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ);
171 20 : ifr.ifr_ifindex = ifindex;
172 20 : if (ioctl(sock, SIOCBRADDIF, &ifr) < 0) {
173 0 : wpa_printf(MSG_DEBUG, "Could not add interface %s into bridge "
174 0 : "%s: %s", ifname, brname, strerror(errno));
175 0 : return -1;
176 : }
177 :
178 20 : return 0;
179 : }
180 :
181 :
182 21 : int linux_br_del_if(int sock, const char *brname, const char *ifname)
183 : {
184 : struct ifreq ifr;
185 : int ifindex;
186 :
187 21 : ifindex = if_nametoindex(ifname);
188 21 : if (ifindex == 0)
189 0 : return -1;
190 :
191 21 : os_memset(&ifr, 0, sizeof(ifr));
192 21 : os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ);
193 21 : ifr.ifr_ifindex = ifindex;
194 21 : if (ioctl(sock, SIOCBRDELIF, &ifr) < 0) {
195 18 : wpa_printf(MSG_DEBUG, "Could not remove interface %s from "
196 18 : "bridge %s: %s", ifname, brname, strerror(errno));
197 18 : return -1;
198 : }
199 :
200 3 : return 0;
201 : }
202 :
203 :
204 1658 : int linux_br_get(char *brname, const char *ifname)
205 : {
206 : char path[128], brlink[128], *pos;
207 : ssize_t res;
208 :
209 1658 : os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/bridge",
210 : ifname);
211 1658 : res = readlink(path, brlink, sizeof(brlink));
212 1658 : if (res < 0 || (size_t) res >= sizeof(brlink))
213 1655 : return -1;
214 3 : brlink[res] = '\0';
215 3 : pos = os_strrchr(brlink, '/');
216 3 : if (pos == NULL)
217 0 : return -1;
218 3 : pos++;
219 3 : os_strlcpy(brname, pos, IFNAMSIZ);
220 3 : return 0;
221 : }
222 :
223 :
224 1619 : int linux_master_get(char *master_ifname, const char *ifname)
225 : {
226 : char buf[128], masterlink[128], *pos;
227 : ssize_t res;
228 :
229 : /* check whether there is a master */
230 1619 : os_snprintf(buf, sizeof(buf), "/sys/class/net/%s/master", ifname);
231 :
232 1619 : res = readlink(buf, masterlink, sizeof(masterlink));
233 1619 : if (res < 0 || (size_t) res >= sizeof(masterlink))
234 1619 : return -1;
235 :
236 0 : masterlink[res] = '\0';
237 :
238 0 : pos = os_strrchr(masterlink, '/');
239 0 : if (pos == NULL)
240 0 : return -1;
241 0 : pos++;
242 0 : os_strlcpy(master_ifname, pos, IFNAMSIZ);
243 0 : return 0;
244 : }
|