linux_ioctl.c revision c5ec7f57ead87efa365800228aa0b09a12d9e6c4
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
18int 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			   ifname, strerror(errno));
50		return ret;
51	}
52
53	return 0;
54}
55
56
57int linux_iface_up(int sock, const char *ifname)
58{
59	struct ifreq ifr;
60	int ret;
61
62	if (sock < 0)
63		return -1;
64
65	os_memset(&ifr, 0, sizeof(ifr));
66	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
67
68	if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
69		ret = errno ? -errno : -999;
70		wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s",
71			   ifname, strerror(errno));
72		return ret;
73	}
74
75	return !!(ifr.ifr_flags & IFF_UP);
76}
77
78
79int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr)
80{
81	struct ifreq ifr;
82
83	os_memset(&ifr, 0, sizeof(ifr));
84	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
85	if (ioctl(sock, SIOCGIFHWADDR, &ifr)) {
86		wpa_printf(MSG_ERROR, "Could not get interface %s hwaddr: %s",
87			   ifname, strerror(errno));
88		return -1;
89	}
90
91	if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
92		wpa_printf(MSG_ERROR, "%s: Invalid HW-addr family 0x%04x",
93			   ifname, ifr.ifr_hwaddr.sa_family);
94		return -1;
95	}
96	os_memcpy(addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
97
98	return 0;
99}
100
101
102int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr)
103{
104	struct ifreq ifr;
105
106	os_memset(&ifr, 0, sizeof(ifr));
107	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
108	os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
109	ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
110
111	if (ioctl(sock, SIOCSIFHWADDR, &ifr)) {
112		wpa_printf(MSG_DEBUG, "Could not set interface %s hwaddr: %s",
113			   ifname, strerror(errno));
114		return -1;
115	}
116
117	return 0;
118}
119
120
121#ifndef SIOCBRADDBR
122#define SIOCBRADDBR 0x89a0
123#endif
124#ifndef SIOCBRDELBR
125#define SIOCBRDELBR 0x89a1
126#endif
127#ifndef SIOCBRADDIF
128#define SIOCBRADDIF 0x89a2
129#endif
130#ifndef SIOCBRDELIF
131#define SIOCBRDELIF 0x89a3
132#endif
133
134
135int linux_br_add(int sock, const char *brname)
136{
137	if (ioctl(sock, SIOCBRADDBR, brname) < 0) {
138		wpa_printf(MSG_DEBUG, "Could not add bridge %s: %s",
139			   brname, strerror(errno));
140		return -1;
141	}
142
143	return 0;
144}
145
146
147int linux_br_del(int sock, const char *brname)
148{
149	if (ioctl(sock, SIOCBRDELBR, brname) < 0) {
150		wpa_printf(MSG_DEBUG, "Could not remove bridge %s: %s",
151			   brname, strerror(errno));
152		return -1;
153	}
154
155	return 0;
156}
157
158
159int linux_br_add_if(int sock, const char *brname, const char *ifname)
160{
161	struct ifreq ifr;
162	int ifindex;
163
164	ifindex = if_nametoindex(ifname);
165	if (ifindex == 0)
166		return -1;
167
168	os_memset(&ifr, 0, sizeof(ifr));
169	os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ);
170	ifr.ifr_ifindex = ifindex;
171	if (ioctl(sock, SIOCBRADDIF, &ifr) < 0) {
172		wpa_printf(MSG_DEBUG, "Could not add interface %s into bridge "
173			   "%s: %s", ifname, brname, strerror(errno));
174		return -1;
175	}
176
177	return 0;
178}
179
180
181int linux_br_del_if(int sock, const char *brname, const char *ifname)
182{
183	struct ifreq ifr;
184	int ifindex;
185
186	ifindex = if_nametoindex(ifname);
187	if (ifindex == 0)
188		return -1;
189
190	os_memset(&ifr, 0, sizeof(ifr));
191	os_strlcpy(ifr.ifr_name, brname, IFNAMSIZ);
192	ifr.ifr_ifindex = ifindex;
193	if (ioctl(sock, SIOCBRDELIF, &ifr) < 0) {
194		wpa_printf(MSG_DEBUG, "Could not remove interface %s from "
195			   "bridge %s: %s", ifname, brname, strerror(errno));
196		return -1;
197	}
198
199	return 0;
200}
201
202
203int linux_br_get(char *brname, const char *ifname)
204{
205	char path[128], brlink[128], *pos;
206	os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/bridge",
207		    ifname);
208	os_memset(brlink, 0, sizeof(brlink));
209	if (readlink(path, brlink, sizeof(brlink) - 1) < 0)
210		return -1;
211	pos = os_strrchr(brlink, '/');
212	if (pos == NULL)
213		return -1;
214	pos++;
215	os_strlcpy(brname, pos, IFNAMSIZ);
216	return 0;
217}
218