Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/bridge/br_ioctl.c
15109 views
1
/*
2
* Ioctl handler
3
* Linux ethernet bridge
4
*
5
* Authors:
6
* Lennert Buytenhek <[email protected]>
7
*
8
* This program is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU General Public License
10
* as published by the Free Software Foundation; either version
11
* 2 of the License, or (at your option) any later version.
12
*/
13
14
#include <linux/capability.h>
15
#include <linux/kernel.h>
16
#include <linux/if_bridge.h>
17
#include <linux/netdevice.h>
18
#include <linux/slab.h>
19
#include <linux/times.h>
20
#include <net/net_namespace.h>
21
#include <asm/uaccess.h>
22
#include "br_private.h"
23
24
/* called with RTNL */
25
static int get_bridge_ifindices(struct net *net, int *indices, int num)
26
{
27
struct net_device *dev;
28
int i = 0;
29
30
for_each_netdev(net, dev) {
31
if (i >= num)
32
break;
33
if (dev->priv_flags & IFF_EBRIDGE)
34
indices[i++] = dev->ifindex;
35
}
36
37
return i;
38
}
39
40
/* called with RTNL */
41
static void get_port_ifindices(struct net_bridge *br, int *ifindices, int num)
42
{
43
struct net_bridge_port *p;
44
45
list_for_each_entry(p, &br->port_list, list) {
46
if (p->port_no < num)
47
ifindices[p->port_no] = p->dev->ifindex;
48
}
49
}
50
51
/*
52
* Format up to a page worth of forwarding table entries
53
* userbuf -- where to copy result
54
* maxnum -- maximum number of entries desired
55
* (limited to a page for sanity)
56
* offset -- number of records to skip
57
*/
58
static int get_fdb_entries(struct net_bridge *br, void __user *userbuf,
59
unsigned long maxnum, unsigned long offset)
60
{
61
int num;
62
void *buf;
63
size_t size;
64
65
/* Clamp size to PAGE_SIZE, test maxnum to avoid overflow */
66
if (maxnum > PAGE_SIZE/sizeof(struct __fdb_entry))
67
maxnum = PAGE_SIZE/sizeof(struct __fdb_entry);
68
69
size = maxnum * sizeof(struct __fdb_entry);
70
71
buf = kmalloc(size, GFP_USER);
72
if (!buf)
73
return -ENOMEM;
74
75
num = br_fdb_fillbuf(br, buf, maxnum, offset);
76
if (num > 0) {
77
if (copy_to_user(userbuf, buf, num*sizeof(struct __fdb_entry)))
78
num = -EFAULT;
79
}
80
kfree(buf);
81
82
return num;
83
}
84
85
/* called with RTNL */
86
static int add_del_if(struct net_bridge *br, int ifindex, int isadd)
87
{
88
struct net_device *dev;
89
int ret;
90
91
if (!capable(CAP_NET_ADMIN))
92
return -EPERM;
93
94
dev = __dev_get_by_index(dev_net(br->dev), ifindex);
95
if (dev == NULL)
96
return -EINVAL;
97
98
if (isadd)
99
ret = br_add_if(br, dev);
100
else
101
ret = br_del_if(br, dev);
102
103
return ret;
104
}
105
106
/*
107
* Legacy ioctl's through SIOCDEVPRIVATE
108
* This interface is deprecated because it was too difficult to
109
* to do the translation for 32/64bit ioctl compatibility.
110
*/
111
static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
112
{
113
struct net_bridge *br = netdev_priv(dev);
114
unsigned long args[4];
115
116
if (copy_from_user(args, rq->ifr_data, sizeof(args)))
117
return -EFAULT;
118
119
switch (args[0]) {
120
case BRCTL_ADD_IF:
121
case BRCTL_DEL_IF:
122
return add_del_if(br, args[1], args[0] == BRCTL_ADD_IF);
123
124
case BRCTL_GET_BRIDGE_INFO:
125
{
126
struct __bridge_info b;
127
128
memset(&b, 0, sizeof(struct __bridge_info));
129
rcu_read_lock();
130
memcpy(&b.designated_root, &br->designated_root, 8);
131
memcpy(&b.bridge_id, &br->bridge_id, 8);
132
b.root_path_cost = br->root_path_cost;
133
b.max_age = jiffies_to_clock_t(br->max_age);
134
b.hello_time = jiffies_to_clock_t(br->hello_time);
135
b.forward_delay = br->forward_delay;
136
b.bridge_max_age = br->bridge_max_age;
137
b.bridge_hello_time = br->bridge_hello_time;
138
b.bridge_forward_delay = jiffies_to_clock_t(br->bridge_forward_delay);
139
b.topology_change = br->topology_change;
140
b.topology_change_detected = br->topology_change_detected;
141
b.root_port = br->root_port;
142
143
b.stp_enabled = (br->stp_enabled != BR_NO_STP);
144
b.ageing_time = jiffies_to_clock_t(br->ageing_time);
145
b.hello_timer_value = br_timer_value(&br->hello_timer);
146
b.tcn_timer_value = br_timer_value(&br->tcn_timer);
147
b.topology_change_timer_value = br_timer_value(&br->topology_change_timer);
148
b.gc_timer_value = br_timer_value(&br->gc_timer);
149
rcu_read_unlock();
150
151
if (copy_to_user((void __user *)args[1], &b, sizeof(b)))
152
return -EFAULT;
153
154
return 0;
155
}
156
157
case BRCTL_GET_PORT_LIST:
158
{
159
int num, *indices;
160
161
num = args[2];
162
if (num < 0)
163
return -EINVAL;
164
if (num == 0)
165
num = 256;
166
if (num > BR_MAX_PORTS)
167
num = BR_MAX_PORTS;
168
169
indices = kcalloc(num, sizeof(int), GFP_KERNEL);
170
if (indices == NULL)
171
return -ENOMEM;
172
173
get_port_ifindices(br, indices, num);
174
if (copy_to_user((void __user *)args[1], indices, num*sizeof(int)))
175
num = -EFAULT;
176
kfree(indices);
177
return num;
178
}
179
180
case BRCTL_SET_BRIDGE_FORWARD_DELAY:
181
if (!capable(CAP_NET_ADMIN))
182
return -EPERM;
183
184
return br_set_forward_delay(br, args[1]);
185
186
case BRCTL_SET_BRIDGE_HELLO_TIME:
187
if (!capable(CAP_NET_ADMIN))
188
return -EPERM;
189
190
return br_set_hello_time(br, args[1]);
191
192
case BRCTL_SET_BRIDGE_MAX_AGE:
193
if (!capable(CAP_NET_ADMIN))
194
return -EPERM;
195
196
return br_set_max_age(br, args[1]);
197
198
case BRCTL_SET_AGEING_TIME:
199
if (!capable(CAP_NET_ADMIN))
200
return -EPERM;
201
202
br->ageing_time = clock_t_to_jiffies(args[1]);
203
return 0;
204
205
case BRCTL_GET_PORT_INFO:
206
{
207
struct __port_info p;
208
struct net_bridge_port *pt;
209
210
rcu_read_lock();
211
if ((pt = br_get_port(br, args[2])) == NULL) {
212
rcu_read_unlock();
213
return -EINVAL;
214
}
215
216
memset(&p, 0, sizeof(struct __port_info));
217
memcpy(&p.designated_root, &pt->designated_root, 8);
218
memcpy(&p.designated_bridge, &pt->designated_bridge, 8);
219
p.port_id = pt->port_id;
220
p.designated_port = pt->designated_port;
221
p.path_cost = pt->path_cost;
222
p.designated_cost = pt->designated_cost;
223
p.state = pt->state;
224
p.top_change_ack = pt->topology_change_ack;
225
p.config_pending = pt->config_pending;
226
p.message_age_timer_value = br_timer_value(&pt->message_age_timer);
227
p.forward_delay_timer_value = br_timer_value(&pt->forward_delay_timer);
228
p.hold_timer_value = br_timer_value(&pt->hold_timer);
229
230
rcu_read_unlock();
231
232
if (copy_to_user((void __user *)args[1], &p, sizeof(p)))
233
return -EFAULT;
234
235
return 0;
236
}
237
238
case BRCTL_SET_BRIDGE_STP_STATE:
239
if (!capable(CAP_NET_ADMIN))
240
return -EPERM;
241
242
br_stp_set_enabled(br, args[1]);
243
return 0;
244
245
case BRCTL_SET_BRIDGE_PRIORITY:
246
if (!capable(CAP_NET_ADMIN))
247
return -EPERM;
248
249
spin_lock_bh(&br->lock);
250
br_stp_set_bridge_priority(br, args[1]);
251
spin_unlock_bh(&br->lock);
252
return 0;
253
254
case BRCTL_SET_PORT_PRIORITY:
255
{
256
struct net_bridge_port *p;
257
int ret;
258
259
if (!capable(CAP_NET_ADMIN))
260
return -EPERM;
261
262
spin_lock_bh(&br->lock);
263
if ((p = br_get_port(br, args[1])) == NULL)
264
ret = -EINVAL;
265
else
266
ret = br_stp_set_port_priority(p, args[2]);
267
spin_unlock_bh(&br->lock);
268
return ret;
269
}
270
271
case BRCTL_SET_PATH_COST:
272
{
273
struct net_bridge_port *p;
274
int ret;
275
276
if (!capable(CAP_NET_ADMIN))
277
return -EPERM;
278
279
spin_lock_bh(&br->lock);
280
if ((p = br_get_port(br, args[1])) == NULL)
281
ret = -EINVAL;
282
else
283
ret = br_stp_set_path_cost(p, args[2]);
284
spin_unlock_bh(&br->lock);
285
286
return ret;
287
}
288
289
case BRCTL_GET_FDB_ENTRIES:
290
return get_fdb_entries(br, (void __user *)args[1],
291
args[2], args[3]);
292
}
293
294
return -EOPNOTSUPP;
295
}
296
297
static int old_deviceless(struct net *net, void __user *uarg)
298
{
299
unsigned long args[3];
300
301
if (copy_from_user(args, uarg, sizeof(args)))
302
return -EFAULT;
303
304
switch (args[0]) {
305
case BRCTL_GET_VERSION:
306
return BRCTL_VERSION;
307
308
case BRCTL_GET_BRIDGES:
309
{
310
int *indices;
311
int ret = 0;
312
313
if (args[2] >= 2048)
314
return -ENOMEM;
315
indices = kcalloc(args[2], sizeof(int), GFP_KERNEL);
316
if (indices == NULL)
317
return -ENOMEM;
318
319
args[2] = get_bridge_ifindices(net, indices, args[2]);
320
321
ret = copy_to_user((void __user *)args[1], indices, args[2]*sizeof(int))
322
? -EFAULT : args[2];
323
324
kfree(indices);
325
return ret;
326
}
327
328
case BRCTL_ADD_BRIDGE:
329
case BRCTL_DEL_BRIDGE:
330
{
331
char buf[IFNAMSIZ];
332
333
if (!capable(CAP_NET_ADMIN))
334
return -EPERM;
335
336
if (copy_from_user(buf, (void __user *)args[1], IFNAMSIZ))
337
return -EFAULT;
338
339
buf[IFNAMSIZ-1] = 0;
340
341
if (args[0] == BRCTL_ADD_BRIDGE)
342
return br_add_bridge(net, buf);
343
344
return br_del_bridge(net, buf);
345
}
346
}
347
348
return -EOPNOTSUPP;
349
}
350
351
int br_ioctl_deviceless_stub(struct net *net, unsigned int cmd, void __user *uarg)
352
{
353
switch (cmd) {
354
case SIOCGIFBR:
355
case SIOCSIFBR:
356
return old_deviceless(net, uarg);
357
358
case SIOCBRADDBR:
359
case SIOCBRDELBR:
360
{
361
char buf[IFNAMSIZ];
362
363
if (!capable(CAP_NET_ADMIN))
364
return -EPERM;
365
366
if (copy_from_user(buf, uarg, IFNAMSIZ))
367
return -EFAULT;
368
369
buf[IFNAMSIZ-1] = 0;
370
if (cmd == SIOCBRADDBR)
371
return br_add_bridge(net, buf);
372
373
return br_del_bridge(net, buf);
374
}
375
}
376
return -EOPNOTSUPP;
377
}
378
379
int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
380
{
381
struct net_bridge *br = netdev_priv(dev);
382
383
switch(cmd) {
384
case SIOCDEVPRIVATE:
385
return old_dev_ioctl(dev, rq, cmd);
386
387
case SIOCBRADDIF:
388
case SIOCBRDELIF:
389
return add_del_if(br, rq->ifr_ifindex, cmd == SIOCBRADDIF);
390
391
}
392
393
br_debug(br, "Bridge does not support ioctl 0x%x\n", cmd);
394
return -EOPNOTSUPP;
395
}
396
397