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
linux_set_iface_flags(int sock,const char * ifname,int dev_up)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
linux_iface_up(int sock,const char * ifname)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
linux_get_ifhwaddr(int sock,const char * ifname,u8 * addr)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
linux_set_ifhwaddr(int sock,const char * ifname,const u8 * addr)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
linux_br_add(int sock,const char * brname)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
linux_br_del(int sock,const char * brname)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
linux_br_add_if(int sock,const char * brname,const char * ifname)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
linux_br_del_if(int sock,const char * brname,const char * ifname)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
linux_br_get(char * brname,const char * ifname)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