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