1 /*
2  *	Ioctl handler
3  *	Linux ethernet bridge
4  *
5  *	Authors:
6  *	Lennert Buytenhek		<buytenh@gnu.org>
7  *
8  *	$Id: br_ioctl.c,v 1.4 2000/11/08 05:16:40 davem Exp $
9  *
10  *	This program is free software; you can redistribute it and/or
11  *	modify it under the terms of the GNU General Public License
12  *	as published by the Free Software Foundation; either version
13  *	2 of the License, or (at your option) any later version.
14  */
15 
16 #include <linux/kernel.h>
17 #include <linux/if_bridge.h>
18 #include <linux/inetdevice.h>
19 #include <linux/rtnetlink.h>
20 #include <asm/uaccess.h>
21 #include "br_private.h"
22 
br_ioctl_device(struct net_bridge * br,unsigned int cmd,unsigned long arg0,unsigned long arg1,unsigned long arg2)23 static int br_ioctl_device(struct net_bridge *br,
24 			   unsigned int cmd,
25 			   unsigned long arg0,
26 			   unsigned long arg1,
27 			   unsigned long arg2)
28 {
29 	if (br == NULL)
30 		return -EINVAL;
31 
32 	switch (cmd)
33 	{
34 	case BRCTL_ADD_IF:
35 	case BRCTL_DEL_IF:
36 	{
37 		struct net_device *dev;
38 		int ret;
39 
40 		dev = dev_get_by_index(arg0);
41 		if (dev == NULL)
42 			return -EINVAL;
43 
44 		if (cmd == BRCTL_ADD_IF)
45 			ret = br_add_if(br, dev);
46 		else
47 			ret = br_del_if(br, dev);
48 
49 		dev_put(dev);
50 		return ret;
51 	}
52 
53 	case BRCTL_GET_BRIDGE_INFO:
54 	{
55 		struct __bridge_info b;
56 
57 		memset(&b, 0, sizeof(struct __bridge_info));
58 		memcpy(&b.designated_root, &br->designated_root, 8);
59 		memcpy(&b.bridge_id, &br->bridge_id, 8);
60 		b.root_path_cost = br->root_path_cost;
61 		b.max_age = br->max_age;
62 		b.hello_time = br->hello_time;
63 		b.forward_delay = br->forward_delay;
64 		b.bridge_max_age = br->bridge_max_age;
65 		b.bridge_hello_time = br->bridge_hello_time;
66 		b.bridge_forward_delay = br->bridge_forward_delay;
67 		b.topology_change = br->topology_change;
68 		b.topology_change_detected = br->topology_change_detected;
69 		b.root_port = br->root_port;
70 		b.stp_enabled = br->stp_enabled;
71 		b.ageing_time = br->ageing_time;
72 		b.gc_interval = br->gc_interval;
73 		b.hello_timer_value = br_timer_get_residue(&br->hello_timer);
74 		b.tcn_timer_value = br_timer_get_residue(&br->tcn_timer);
75 		b.topology_change_timer_value = br_timer_get_residue(&br->topology_change_timer);
76 		b.gc_timer_value = br_timer_get_residue(&br->gc_timer);
77 
78 		if (copy_to_user((void *)arg0, &b, sizeof(b)))
79 			return -EFAULT;
80 
81 		return 0;
82 	}
83 
84 	case BRCTL_GET_PORT_LIST:
85 	{
86 		int i;
87 		int indices[256];
88 
89 		for (i=0;i<256;i++)
90 			indices[i] = 0;
91 
92 		br_get_port_ifindices(br, indices);
93 		if (copy_to_user((void *)arg0, indices, 256*sizeof(int)))
94 			return -EFAULT;
95 
96 		return 0;
97 	}
98 
99 	case BRCTL_SET_BRIDGE_FORWARD_DELAY:
100 		br->bridge_forward_delay = arg0;
101 		if (br_is_root_bridge(br))
102 			br->forward_delay = arg0;
103 		return 0;
104 
105 	case BRCTL_SET_BRIDGE_HELLO_TIME:
106 		br->bridge_hello_time = arg0;
107 		if (br_is_root_bridge(br))
108 			br->hello_time = arg0;
109 		return 0;
110 
111 	case BRCTL_SET_BRIDGE_MAX_AGE:
112 		br->bridge_max_age = arg0;
113 		if (br_is_root_bridge(br))
114 			br->max_age = arg0;
115 		return 0;
116 
117 	case BRCTL_SET_AGEING_TIME:
118 		br->ageing_time = arg0;
119 		return 0;
120 
121 	case BRCTL_SET_GC_INTERVAL:
122 		br->gc_interval = arg0;
123 		return 0;
124 
125 	case BRCTL_GET_PORT_INFO:
126 	{
127 		struct __port_info p;
128 		struct net_bridge_port *pt;
129 
130 		if ((pt = br_get_port(br, arg1)) == NULL)
131 			return -EINVAL;
132 
133 		memset(&p, 0, sizeof(struct __port_info));
134 		memcpy(&p.designated_root, &pt->designated_root, 8);
135 		memcpy(&p.designated_bridge, &pt->designated_bridge, 8);
136 		p.port_id = pt->port_id;
137 		p.designated_port = pt->designated_port;
138 		p.path_cost = pt->path_cost;
139 		p.designated_cost = pt->designated_cost;
140 		p.state = pt->state;
141 		p.top_change_ack = pt->topology_change_ack;
142 		p.config_pending = pt->config_pending;
143 		p.message_age_timer_value = br_timer_get_residue(&pt->message_age_timer);
144 		p.forward_delay_timer_value = br_timer_get_residue(&pt->forward_delay_timer);
145 		p.hold_timer_value = br_timer_get_residue(&pt->hold_timer);
146 
147 		if (copy_to_user((void *)arg0, &p, sizeof(p)))
148 			return -EFAULT;
149 
150 		return 0;
151 	}
152 
153 	case BRCTL_SET_BRIDGE_STP_STATE:
154 		br->stp_enabled = arg0?1:0;
155 		return 0;
156 
157 	case BRCTL_SET_BRIDGE_PRIORITY:
158 		br_stp_set_bridge_priority(br, arg0);
159 		return 0;
160 
161 	case BRCTL_SET_PORT_PRIORITY:
162 	{
163 		struct net_bridge_port *p;
164 
165 		if ((p = br_get_port(br, arg0)) == NULL)
166 			return -EINVAL;
167 		br_stp_set_port_priority(p, arg1);
168 		return 0;
169 	}
170 
171 	case BRCTL_SET_PATH_COST:
172 	{
173 		struct net_bridge_port *p;
174 
175 		if ((p = br_get_port(br, arg0)) == NULL)
176 			return -EINVAL;
177 		br_stp_set_path_cost(p, arg1);
178 		return 0;
179 	}
180 
181 	case BRCTL_GET_FDB_ENTRIES:
182 		return br_fdb_get_entries(br, (void *)arg0, arg1, arg2);
183 	}
184 
185 	return -EOPNOTSUPP;
186 }
187 
br_ioctl_deviceless(unsigned int cmd,unsigned long arg0,unsigned long arg1)188 static int br_ioctl_deviceless(unsigned int cmd,
189 			       unsigned long arg0,
190 			       unsigned long arg1)
191 {
192 	switch (cmd)
193 	{
194 	case BRCTL_GET_VERSION:
195 		return BRCTL_VERSION;
196 
197 	case BRCTL_GET_BRIDGES:
198 	{
199 		int i;
200 		int indices[64];
201 
202 		for (i=0;i<64;i++)
203 			indices[i] = 0;
204 
205 		if (arg1 > 64)
206 			arg1 = 64;
207 		arg1 = br_get_bridge_ifindices(indices, arg1);
208 		if (copy_to_user((void *)arg0, indices, arg1*sizeof(int)))
209 			return -EFAULT;
210 
211 		return arg1;
212 	}
213 
214 	case BRCTL_ADD_BRIDGE:
215 	case BRCTL_DEL_BRIDGE:
216 	{
217 		char buf[IFNAMSIZ];
218 
219 		if (copy_from_user(buf, (void *)arg0, IFNAMSIZ))
220 			return -EFAULT;
221 
222 		buf[IFNAMSIZ-1] = 0;
223 
224 		if (cmd == BRCTL_ADD_BRIDGE)
225 			return br_add_bridge(buf);
226 
227 		return br_del_bridge(buf);
228 	}
229 	}
230 
231 	return -EOPNOTSUPP;
232 }
233 
br_ioctl_deviceless_stub(unsigned long arg)234 int br_ioctl_deviceless_stub(unsigned long arg)
235 {
236 	unsigned long i[3];
237 	int err;
238 
239 	if (!capable(CAP_NET_ADMIN))
240 		return -EPERM;
241 
242 	if (copy_from_user(i, (void *)arg, 3*sizeof(unsigned long)))
243 		return -EFAULT;
244 
245 	rtnl_lock();
246 	err =  br_ioctl_deviceless(i[0], i[1], i[2]);
247 	rtnl_unlock();
248 	return err;
249 }
250 
br_ioctl(struct net_bridge * br,unsigned int cmd,unsigned long arg0,unsigned long arg1,unsigned long arg2)251 int br_ioctl(struct net_bridge *br, unsigned int cmd, unsigned long arg0, unsigned long arg1, unsigned long arg2)
252 {
253 	if (!capable(CAP_NET_ADMIN))
254 		return -EPERM;
255 
256 	ASSERT_RTNL();
257 	return br_ioctl_device(br, cmd, arg0, arg1, arg2);
258 }
259