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 <asm/uaccess.h>
20 #include "br_private.h"
21
22 static int br_ioctl_device(struct net_bridge *br,
23 unsigned int cmd,
24 unsigned long arg0,
25 unsigned long arg1,
26 unsigned long arg2)
27 {
28 if (br == NULL)
29 return -EINVAL;
30
31 switch (cmd)
32 {
33 case BRCTL_ADD_IF:
34 case BRCTL_DEL_IF:
35 {
36 struct net_device *dev;
37 int ret;
38
39 dev = dev_get_by_index(arg0);
40 if (dev == NULL)
41 return -EINVAL;
42
43 if (cmd == BRCTL_ADD_IF)
44 ret = br_add_if(br, dev);
45 else
46 ret = br_del_if(br, dev);
47
48 dev_put(dev);
49 return ret;
50 }
51
52 case BRCTL_GET_BRIDGE_INFO:
53 {
54 struct __bridge_info b;
55
56 memset(&b, 0, sizeof(struct __bridge_info));
57 memcpy(&b.designated_root, &br->designated_root, 8);
58 memcpy(&b.bridge_id, &br->bridge_id, 8);
59 b.root_path_cost = br->root_path_cost;
60 b.max_age = br->max_age;
61 b.hello_time = br->hello_time;
62 b.forward_delay = br->forward_delay;
63 b.bridge_max_age = br->bridge_max_age;
64 b.bridge_hello_time = br->bridge_hello_time;
65 b.bridge_forward_delay = br->bridge_forward_delay;
66 b.topology_change = br->topology_change;
67 b.topology_change_detected = br->topology_change_detected;
68 b.root_port = br->root_port;
69 b.stp_enabled = br->stp_enabled;
70 b.ageing_time = br->ageing_time;
71 b.gc_interval = br->gc_interval;
72 b.hello_timer_value = br_timer_get_residue(&br->hello_timer);
73 b.tcn_timer_value = br_timer_get_residue(&br->tcn_timer);
74 b.topology_change_timer_value = br_timer_get_residue(&br->topology_change_timer);
75 b.gc_timer_value = br_timer_get_residue(&br->gc_timer);
76
77 if (copy_to_user((void *)arg0, &b, sizeof(b)))
78 return -EFAULT;
79
80 return 0;
81 }
82
83 case BRCTL_GET_PORT_LIST:
84 {
85 int i;
86 int indices[256];
87
88 for (i=0;i<256;i++)
89 indices[i] = 0;
90
91 br_get_port_ifindices(br, indices);
92 if (copy_to_user((void *)arg0, indices, 256*sizeof(int)))
93 return -EFAULT;
94
95 return 0;
96 }
97
98 case BRCTL_SET_BRIDGE_FORWARD_DELAY:
99 br->bridge_forward_delay = arg0;
100 if (br_is_root_bridge(br))
101 br->forward_delay = arg0;
102 return 0;
103
104 case BRCTL_SET_BRIDGE_HELLO_TIME:
105 br->bridge_hello_time = arg0;
106 if (br_is_root_bridge(br))
107 br->hello_time = arg0;
108 return 0;
109
110 case BRCTL_SET_BRIDGE_MAX_AGE:
111 br->bridge_max_age = arg0;
112 if (br_is_root_bridge(br))
113 br->max_age = arg0;
114 return 0;
115
116 case BRCTL_SET_AGEING_TIME:
117 br->ageing_time = arg0;
118 return 0;
119
120 case BRCTL_SET_GC_INTERVAL:
121 br->gc_interval = arg0;
122 return 0;
123
124 case BRCTL_GET_PORT_INFO:
125 {
126 struct __port_info p;
127 struct net_bridge_port *pt;
128
129 if ((pt = br_get_port(br, arg1)) == NULL)
130 return -EINVAL;
131
132 memset(&p, 0, sizeof(struct __port_info));
133 memcpy(&p.designated_root, &pt->designated_root, 8);
134 memcpy(&p.designated_bridge, &pt->designated_bridge, 8);
135 p.port_id = pt->port_id;
136 p.designated_port = pt->designated_port;
137 p.path_cost = pt->path_cost;
138 p.designated_cost = pt->designated_cost;
139 p.state = pt->state;
140 p.top_change_ack = pt->topology_change_ack;
141 p.config_pending = pt->config_pending;
142 p.message_age_timer_value = br_timer_get_residue(&pt->message_age_timer);
143 p.forward_delay_timer_value = br_timer_get_residue(&pt->forward_delay_timer);
144 p.hold_timer_value = br_timer_get_residue(&pt->hold_timer);
145
146 if (copy_to_user((void *)arg0, &p, sizeof(p)))
147 return -EFAULT;
148
149 return 0;
150 }
151
152 case BRCTL_SET_BRIDGE_STP_STATE:
153 br->stp_enabled = arg0?1:0;
154 return 0;
155
156 case BRCTL_SET_BRIDGE_PRIORITY:
157 br_stp_set_bridge_priority(br, arg0);
158 return 0;
159
160 case BRCTL_SET_PORT_PRIORITY:
161 {
162 struct net_bridge_port *p;
163
164 if ((p = br_get_port(br, arg0)) == NULL)
165 return -EINVAL;
166 br_stp_set_port_priority(p, arg1);
167 return 0;
168 }
169
170 case BRCTL_SET_PATH_COST:
171 {
172 struct net_bridge_port *p;
173
174 if ((p = br_get_port(br, arg0)) == NULL)
175 return -EINVAL;
176 br_stp_set_path_cost(p, arg1);
177 return 0;
178 }
179
180 case BRCTL_GET_FDB_ENTRIES:
181 return br_fdb_get_entries(br, (void *)arg0, arg1, arg2);
182 }
183
184 return -EOPNOTSUPP;
185 }
186
187 static int br_ioctl_deviceless(unsigned int cmd,
188 unsigned long arg0,
189 unsigned long arg1)
190 {
191 switch (cmd)
192 {
193 case BRCTL_GET_VERSION:
194 return BRCTL_VERSION;
195
196 case BRCTL_GET_BRIDGES:
197 {
198 int i;
199 int indices[64];
200
201 for (i=0;i<64;i++)
202 indices[i] = 0;
203
204 if (arg1 > 64)
205 arg1 = 64;
206 arg1 = br_get_bridge_ifindices(indices, arg1);
207 if (copy_to_user((void *)arg0, indices, arg1*sizeof(int)))
208 return -EFAULT;
209
210 return arg1;
211 }
212
213 case BRCTL_ADD_BRIDGE:
214 case BRCTL_DEL_BRIDGE:
215 {
216 char buf[IFNAMSIZ];
217
218 if (copy_from_user(buf, (void *)arg0, IFNAMSIZ))
219 return -EFAULT;
220
221 buf[IFNAMSIZ-1] = 0;
222
223 if (cmd == BRCTL_ADD_BRIDGE)
224 return br_add_bridge(buf);
225
226 return br_del_bridge(buf);
227 }
228 }
229
230 return -EOPNOTSUPP;
231 }
232
233 DECLARE_MUTEX(ioctl_mutex);
234
235 int br_ioctl_deviceless_stub(unsigned long arg)
236 {
237 int err;
238 unsigned long i[3];
239
240 if (!capable(CAP_NET_ADMIN))
241 return -EPERM;
242
243 if (copy_from_user(i, (void *)arg, 3*sizeof(unsigned long)))
244 return -EFAULT;
245
246 down(&ioctl_mutex);
247 err = br_ioctl_deviceless(i[0], i[1], i[2]);
248 up(&ioctl_mutex);
249
250 return err;
251 }
252
253 int br_ioctl(struct net_bridge *br, unsigned int cmd, unsigned long arg0, unsigned long arg1, unsigned long arg2)
254 {
255 int err;
256
257 if (!capable(CAP_NET_ADMIN))
258 return -EPERM;
259
260 down(&ioctl_mutex);
261 err = br_ioctl_deviceless(cmd, arg0, arg1);
262 if (err == -EOPNOTSUPP)
263 err = br_ioctl_device(br, cmd, arg0, arg1, arg2);
264 up(&ioctl_mutex);
265
266 return err;
267 }
268
269 void br_call_ioctl_atomic(void (*fn)(void))
270 {
271 down(&ioctl_mutex);
272 fn();
273 up(&ioctl_mutex);
274 }
275
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.