Updated through tag hostap_2_5 from git://w1.fi/hostap.git
[mech_eap.git] / libeap / src / drivers / linux_ioctl.c
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
223
224 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         os_snprintf(buf, sizeof(buf), "/sys/class/net/%s/master", ifname);
231
232         res = readlink(buf, masterlink, sizeof(masterlink));
233         if (res < 0 || (size_t) res >= sizeof(masterlink))
234                 return -1;
235
236         masterlink[res] = '\0';
237
238         pos = os_strrchr(masterlink, '/');
239         if (pos == NULL)
240                 return -1;
241         pos++;
242         os_strlcpy(master_ifname, pos, IFNAMSIZ);
243         return 0;
244 }