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