blob: 837971d25c99e5346453411930f1d50416aca027 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * Linux ioctl helper functions for driver wrappers
3 * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
4 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
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
18int linux_set_iface_flags(int sock, const char *ifname, int dev_up)
19{
20 struct ifreq ifr;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080021 int ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070022
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) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080030 ret = errno ? -errno : -999;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070031 wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s",
32 ifname, strerror(errno));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080033 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070034 }
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) {
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080047 ret = errno ? -errno : -999;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070048 wpa_printf(MSG_ERROR, "Could not set interface %s flags (%s): "
49 "%s",
50 ifname, dev_up ? "UP" : "DOWN", strerror(errno));
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080051 return ret;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070052 }
53
54 return 0;
55}
56
57
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -080058int 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
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070080int 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
103int 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
136int 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
148int 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
160int 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
182int 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
204int linux_br_get(char *brname, const char *ifname)
205{
206 char path[128], brlink[128], *pos;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700207 ssize_t res;
208
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700209 os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/bridge",
210 ifname);
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700211 res = readlink(path, brlink, sizeof(brlink));
212 if (res < 0 || (size_t) res >= sizeof(brlink))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700213 return -1;
Dmitry Shmidt68d0e3e2013-10-28 17:59:21 -0700214 brlink[res] = '\0';
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700215 pos = os_strrchr(brlink, '/');
216 if (pos == NULL)
217 return -1;
218 pos++;
219 os_strlcpy(brname, pos, IFNAMSIZ);
220 return 0;
221}