~ubuntu-branches/ubuntu/utopic/linux-ti-omap/utopic

« back to all changes in this revision

Viewing changes to net/bridge/br_ioctl.c

  • Committer: Bazaar Package Importer
  • Author(s): Amit Kucheria, Amit Kucheria
  • Date: 2010-03-10 02:28:15 UTC
  • Revision ID: james.westby@ubuntu.com-20100310022815-7sd3gwvn5kenaq33
Tags: 2.6.33-500.1
[ Amit Kucheria ]

* Initial release of a 2.6.33-based OMAP kernel
* UBUNTU: [Upstream] Fix omap 1-wire driver compilation
* UBUNTU: ubuntu: AppArmor -- update to mainline 2010-03-04

Show diffs side-by-side

added added

removed removed

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