Blame view
net/bridge/br_ioctl.c
8.8 KB
2874c5fd2 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4c Linux-2.6.12-rc2 |
2 3 4 5 6 7 |
/* * Ioctl handler * Linux ethernet bridge * * Authors: * Lennert Buytenhek <buytenh@gnu.org> |
1da177e4c Linux-2.6.12-rc2 |
8 |
*/ |
4fc268d24 [PATCH] capable/c... |
9 |
#include <linux/capability.h> |
1da177e4c Linux-2.6.12-rc2 |
10 11 12 |
#include <linux/kernel.h> #include <linux/if_bridge.h> #include <linux/netdevice.h> |
5a0e3ad6a include cleanup: ... |
13 |
#include <linux/slab.h> |
1da177e4c Linux-2.6.12-rc2 |
14 |
#include <linux/times.h> |
881d966b4 [NET]: Make the d... |
15 |
#include <net/net_namespace.h> |
7c0f6ba68 Replace <asm/uacc... |
16 |
#include <linux/uaccess.h> |
1da177e4c Linux-2.6.12-rc2 |
17 |
#include "br_private.h" |
4aa678ba4 netns bridge: all... |
18 |
static int get_bridge_ifindices(struct net *net, int *indices, int num) |
1da177e4c Linux-2.6.12-rc2 |
19 20 21 |
{ struct net_device *dev; int i = 0; |
31ca0458a net: bridge: fix ... |
22 23 |
rcu_read_lock(); for_each_netdev_rcu(net, dev) { |
7562f876c [NET]: Rework dev... |
24 25 |
if (i >= num) break; |
9d6f229fc [NET] BRIDGE: Fix... |
26 |
if (dev->priv_flags & IFF_EBRIDGE) |
1da177e4c Linux-2.6.12-rc2 |
27 28 |
indices[i++] = dev->ifindex; } |
31ca0458a net: bridge: fix ... |
29 |
rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
return i; } /* called with RTNL */ static void get_port_ifindices(struct net_bridge *br, int *ifindices, int num) { struct net_bridge_port *p; list_for_each_entry(p, &br->port_list, list) { if (p->port_no < num) ifindices[p->port_no] = p->dev->ifindex; } } /* * Format up to a page worth of forwarding table entries * userbuf -- where to copy result * maxnum -- maximum number of entries desired * (limited to a page for sanity) * offset -- number of records to skip */ |
9d6f229fc [NET] BRIDGE: Fix... |
52 |
static int get_fdb_entries(struct net_bridge *br, void __user *userbuf, |
1da177e4c Linux-2.6.12-rc2 |
53 54 55 56 |
unsigned long maxnum, unsigned long offset) { int num; void *buf; |
ba8379b22 [PATCH] bridge: f... |
57 |
size_t size; |
1da177e4c Linux-2.6.12-rc2 |
58 |
|
ba8379b22 [PATCH] bridge: f... |
59 60 |
/* Clamp size to PAGE_SIZE, test maxnum to avoid overflow */ if (maxnum > PAGE_SIZE/sizeof(struct __fdb_entry)) |
1da177e4c Linux-2.6.12-rc2 |
61 |
maxnum = PAGE_SIZE/sizeof(struct __fdb_entry); |
ba8379b22 [PATCH] bridge: f... |
62 63 |
size = maxnum * sizeof(struct __fdb_entry); |
1da177e4c Linux-2.6.12-rc2 |
64 65 66 67 |
buf = kmalloc(size, GFP_USER); if (!buf) return -ENOMEM; |
9d6f229fc [NET] BRIDGE: Fix... |
68 |
|
1da177e4c Linux-2.6.12-rc2 |
69 70 71 72 73 74 75 76 77 |
num = br_fdb_fillbuf(br, buf, maxnum, offset); if (num > 0) { if (copy_to_user(userbuf, buf, num*sizeof(struct __fdb_entry))) num = -EFAULT; } kfree(buf); return num; } |
31ef30c76 bridge: remove de... |
78 |
/* called with RTNL */ |
1da177e4c Linux-2.6.12-rc2 |
79 80 |
static int add_del_if(struct net_bridge *br, int ifindex, int isadd) { |
cb9905030 net: Allow userns... |
81 |
struct net *net = dev_net(br->dev); |
1da177e4c Linux-2.6.12-rc2 |
82 83 |
struct net_device *dev; int ret; |
cb9905030 net: Allow userns... |
84 |
if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
1da177e4c Linux-2.6.12-rc2 |
85 |
return -EPERM; |
cb9905030 net: Allow userns... |
86 |
dev = __dev_get_by_index(net, ifindex); |
1da177e4c Linux-2.6.12-rc2 |
87 88 |
if (dev == NULL) return -EINVAL; |
9d6f229fc [NET] BRIDGE: Fix... |
89 |
|
1da177e4c Linux-2.6.12-rc2 |
90 |
if (isadd) |
ca752be00 net: bridge: Pass... |
91 |
ret = br_add_if(br, dev, NULL); |
eccaa9e51 Revert "bridge: a... |
92 |
else |
1da177e4c Linux-2.6.12-rc2 |
93 |
ret = br_del_if(br, dev); |
1da177e4c Linux-2.6.12-rc2 |
94 95 96 97 98 |
return ret; } /* * Legacy ioctl's through SIOCDEVPRIVATE |
4bbd026cb net: bridge: dele... |
99 |
* This interface is deprecated because it was too difficult |
25985edce Fix common misspe... |
100 |
* to do the translation for 32/64bit ioctl compatibility. |
1da177e4c Linux-2.6.12-rc2 |
101 102 103 104 |
*/ static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct net_bridge *br = netdev_priv(dev); |
bf871ad79 bridge: a netlink... |
105 |
struct net_bridge_port *p = NULL; |
1da177e4c Linux-2.6.12-rc2 |
106 |
unsigned long args[4]; |
bf871ad79 bridge: a netlink... |
107 |
int ret = -EOPNOTSUPP; |
9d6f229fc [NET] BRIDGE: Fix... |
108 |
|
1da177e4c Linux-2.6.12-rc2 |
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
if (copy_from_user(args, rq->ifr_data, sizeof(args))) return -EFAULT; switch (args[0]) { case BRCTL_ADD_IF: case BRCTL_DEL_IF: return add_del_if(br, args[1], args[0] == BRCTL_ADD_IF); case BRCTL_GET_BRIDGE_INFO: { struct __bridge_info b; memset(&b, 0, sizeof(struct __bridge_info)); rcu_read_lock(); memcpy(&b.designated_root, &br->designated_root, 8); memcpy(&b.bridge_id, &br->bridge_id, 8); b.root_path_cost = br->root_path_cost; b.max_age = jiffies_to_clock_t(br->max_age); b.hello_time = jiffies_to_clock_t(br->hello_time); b.forward_delay = br->forward_delay; b.bridge_max_age = br->bridge_max_age; b.bridge_hello_time = br->bridge_hello_time; b.bridge_forward_delay = jiffies_to_clock_t(br->bridge_forward_delay); b.topology_change = br->topology_change; b.topology_change_detected = br->topology_change_detected; b.root_port = br->root_port; |
9cde07087 bridge: add suppo... |
135 136 |
b.stp_enabled = (br->stp_enabled != BR_NO_STP); |
1da177e4c Linux-2.6.12-rc2 |
137 138 139 140 |
b.ageing_time = jiffies_to_clock_t(br->ageing_time); b.hello_timer_value = br_timer_value(&br->hello_timer); b.tcn_timer_value = br_timer_value(&br->tcn_timer); b.topology_change_timer_value = br_timer_value(&br->topology_change_timer); |
f7cdee8a7 bridge: move to w... |
141 |
b.gc_timer_value = br_timer_value(&br->gc_work.timer); |
9d6f229fc [NET] BRIDGE: Fix... |
142 |
rcu_read_unlock(); |
1da177e4c Linux-2.6.12-rc2 |
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
if (copy_to_user((void __user *)args[1], &b, sizeof(b))) return -EFAULT; return 0; } case BRCTL_GET_PORT_LIST: { int num, *indices; num = args[2]; if (num < 0) return -EINVAL; if (num == 0) num = 256; if (num > BR_MAX_PORTS) num = BR_MAX_PORTS; |
0da974f4f [NET]: Conversion... |
161 |
indices = kcalloc(num, sizeof(int), GFP_KERNEL); |
1da177e4c Linux-2.6.12-rc2 |
162 163 |
if (indices == NULL) return -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
164 165 166 167 168 169 170 171 |
get_port_ifindices(br, indices, num); if (copy_to_user((void __user *)args[1], indices, num*sizeof(int))) num = -EFAULT; kfree(indices); return num; } case BRCTL_SET_BRIDGE_FORWARD_DELAY: |
cb9905030 net: Allow userns... |
172 |
if (!ns_capable(dev_net(dev)->user_ns, CAP_NET_ADMIN)) |
1da177e4c Linux-2.6.12-rc2 |
173 |
return -EPERM; |
bf871ad79 bridge: a netlink... |
174 175 |
ret = br_set_forward_delay(br, args[1]); break; |
1da177e4c Linux-2.6.12-rc2 |
176 177 |
case BRCTL_SET_BRIDGE_HELLO_TIME: |
cb9905030 net: Allow userns... |
178 |
if (!ns_capable(dev_net(dev)->user_ns, CAP_NET_ADMIN)) |
1da177e4c Linux-2.6.12-rc2 |
179 |
return -EPERM; |
bf871ad79 bridge: a netlink... |
180 181 |
ret = br_set_hello_time(br, args[1]); break; |
1da177e4c Linux-2.6.12-rc2 |
182 183 |
case BRCTL_SET_BRIDGE_MAX_AGE: |
cb9905030 net: Allow userns... |
184 |
if (!ns_capable(dev_net(dev)->user_ns, CAP_NET_ADMIN)) |
1da177e4c Linux-2.6.12-rc2 |
185 |
return -EPERM; |
bf871ad79 bridge: a netlink... |
186 187 |
ret = br_set_max_age(br, args[1]); break; |
1da177e4c Linux-2.6.12-rc2 |
188 189 |
case BRCTL_SET_AGEING_TIME: |
cb9905030 net: Allow userns... |
190 |
if (!ns_capable(dev_net(dev)->user_ns, CAP_NET_ADMIN)) |
1da177e4c Linux-2.6.12-rc2 |
191 |
return -EPERM; |
bf871ad79 bridge: a netlink... |
192 193 |
ret = br_set_ageing_time(br, args[1]); break; |
1da177e4c Linux-2.6.12-rc2 |
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
case BRCTL_GET_PORT_INFO: { struct __port_info p; struct net_bridge_port *pt; rcu_read_lock(); if ((pt = br_get_port(br, args[2])) == NULL) { rcu_read_unlock(); return -EINVAL; } memset(&p, 0, sizeof(struct __port_info)); memcpy(&p.designated_root, &pt->designated_root, 8); memcpy(&p.designated_bridge, &pt->designated_bridge, 8); p.port_id = pt->port_id; p.designated_port = pt->designated_port; p.path_cost = pt->path_cost; p.designated_cost = pt->designated_cost; p.state = pt->state; p.top_change_ack = pt->topology_change_ack; p.config_pending = pt->config_pending; p.message_age_timer_value = br_timer_value(&pt->message_age_timer); p.forward_delay_timer_value = br_timer_value(&pt->forward_delay_timer); p.hold_timer_value = br_timer_value(&pt->hold_timer); rcu_read_unlock(); if (copy_to_user((void __user *)args[1], &p, sizeof(p))) return -EFAULT; return 0; } case BRCTL_SET_BRIDGE_STP_STATE: |
cb9905030 net: Allow userns... |
229 |
if (!ns_capable(dev_net(dev)->user_ns, CAP_NET_ADMIN)) |
1da177e4c Linux-2.6.12-rc2 |
230 |
return -EPERM; |
419dba8a4 net: bridge: Add ... |
231 |
ret = br_stp_set_enabled(br, args[1], NULL); |
bf871ad79 bridge: a netlink... |
232 |
break; |
1da177e4c Linux-2.6.12-rc2 |
233 234 |
case BRCTL_SET_BRIDGE_PRIORITY: |
cb9905030 net: Allow userns... |
235 |
if (!ns_capable(dev_net(dev)->user_ns, CAP_NET_ADMIN)) |
1da177e4c Linux-2.6.12-rc2 |
236 |
return -EPERM; |
1da177e4c Linux-2.6.12-rc2 |
237 |
br_stp_set_bridge_priority(br, args[1]); |
bf871ad79 bridge: a netlink... |
238 239 |
ret = 0; break; |
1da177e4c Linux-2.6.12-rc2 |
240 241 242 |
case BRCTL_SET_PORT_PRIORITY: { |
cb9905030 net: Allow userns... |
243 |
if (!ns_capable(dev_net(dev)->user_ns, CAP_NET_ADMIN)) |
1da177e4c Linux-2.6.12-rc2 |
244 |
return -EPERM; |
1da177e4c Linux-2.6.12-rc2 |
245 |
spin_lock_bh(&br->lock); |
9d6f229fc [NET] BRIDGE: Fix... |
246 |
if ((p = br_get_port(br, args[1])) == NULL) |
1da177e4c Linux-2.6.12-rc2 |
247 248 |
ret = -EINVAL; else |
14f98f258 bridge: range che... |
249 |
ret = br_stp_set_port_priority(p, args[2]); |
1da177e4c Linux-2.6.12-rc2 |
250 |
spin_unlock_bh(&br->lock); |
bf871ad79 bridge: a netlink... |
251 |
break; |
1da177e4c Linux-2.6.12-rc2 |
252 253 254 255 |
} case BRCTL_SET_PATH_COST: { |
cb9905030 net: Allow userns... |
256 |
if (!ns_capable(dev_net(dev)->user_ns, CAP_NET_ADMIN)) |
1da177e4c Linux-2.6.12-rc2 |
257 |
return -EPERM; |
14f98f258 bridge: range che... |
258 |
spin_lock_bh(&br->lock); |
1da177e4c Linux-2.6.12-rc2 |
259 260 261 |
if ((p = br_get_port(br, args[1])) == NULL) ret = -EINVAL; else |
14f98f258 bridge: range che... |
262 263 |
ret = br_stp_set_path_cost(p, args[2]); spin_unlock_bh(&br->lock); |
bf871ad79 bridge: a netlink... |
264 |
break; |
1da177e4c Linux-2.6.12-rc2 |
265 266 267 |
} case BRCTL_GET_FDB_ENTRIES: |
9d6f229fc [NET] BRIDGE: Fix... |
268 |
return get_fdb_entries(br, (void __user *)args[1], |
1da177e4c Linux-2.6.12-rc2 |
269 270 |
args[2], args[3]); } |
bf871ad79 bridge: a netlink... |
271 272 |
if (!ret) { if (p) |
928990631 net: bridge: add ... |
273 |
br_ifinfo_notify(RTM_NEWLINK, NULL, p); |
bf871ad79 bridge: a netlink... |
274 275 276 277 278 |
else netdev_state_change(br->dev); } return ret; |
1da177e4c Linux-2.6.12-rc2 |
279 |
} |
4aa678ba4 netns bridge: all... |
280 |
static int old_deviceless(struct net *net, void __user *uarg) |
1da177e4c Linux-2.6.12-rc2 |
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 |
{ unsigned long args[3]; if (copy_from_user(args, uarg, sizeof(args))) return -EFAULT; switch (args[0]) { case BRCTL_GET_VERSION: return BRCTL_VERSION; case BRCTL_GET_BRIDGES: { int *indices; int ret = 0; if (args[2] >= 2048) return -ENOMEM; |
0da974f4f [NET]: Conversion... |
298 |
indices = kcalloc(args[2], sizeof(int), GFP_KERNEL); |
1da177e4c Linux-2.6.12-rc2 |
299 300 |
if (indices == NULL) return -ENOMEM; |
4aa678ba4 netns bridge: all... |
301 |
args[2] = get_bridge_ifindices(net, indices, args[2]); |
1da177e4c Linux-2.6.12-rc2 |
302 303 304 305 306 307 308 309 310 311 312 313 |
ret = copy_to_user((void __user *)args[1], indices, args[2]*sizeof(int)) ? -EFAULT : args[2]; kfree(indices); return ret; } case BRCTL_ADD_BRIDGE: case BRCTL_DEL_BRIDGE: { char buf[IFNAMSIZ]; |
cb9905030 net: Allow userns... |
314 |
if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
1da177e4c Linux-2.6.12-rc2 |
315 316 317 318 319 320 321 322 |
return -EPERM; if (copy_from_user(buf, (void __user *)args[1], IFNAMSIZ)) return -EFAULT; buf[IFNAMSIZ-1] = 0; if (args[0] == BRCTL_ADD_BRIDGE) |
4aa678ba4 netns bridge: all... |
323 |
return br_add_bridge(net, buf); |
1da177e4c Linux-2.6.12-rc2 |
324 |
|
4aa678ba4 netns bridge: all... |
325 |
return br_del_bridge(net, buf); |
1da177e4c Linux-2.6.12-rc2 |
326 327 328 329 330 |
} } return -EOPNOTSUPP; } |
881d966b4 [NET]: Make the d... |
331 |
int br_ioctl_deviceless_stub(struct net *net, unsigned int cmd, void __user *uarg) |
1da177e4c Linux-2.6.12-rc2 |
332 333 334 335 |
{ switch (cmd) { case SIOCGIFBR: case SIOCSIFBR: |
4aa678ba4 netns bridge: all... |
336 |
return old_deviceless(net, uarg); |
9d6f229fc [NET] BRIDGE: Fix... |
337 |
|
1da177e4c Linux-2.6.12-rc2 |
338 339 340 341 |
case SIOCBRADDBR: case SIOCBRDELBR: { char buf[IFNAMSIZ]; |
cb9905030 net: Allow userns... |
342 |
if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
1da177e4c Linux-2.6.12-rc2 |
343 344 345 346 347 348 349 |
return -EPERM; if (copy_from_user(buf, uarg, IFNAMSIZ)) return -EFAULT; buf[IFNAMSIZ-1] = 0; if (cmd == SIOCBRADDBR) |
4aa678ba4 netns bridge: all... |
350 |
return br_add_bridge(net, buf); |
1da177e4c Linux-2.6.12-rc2 |
351 |
|
4aa678ba4 netns bridge: all... |
352 |
return br_del_bridge(net, buf); |
1da177e4c Linux-2.6.12-rc2 |
353 354 355 356 357 358 359 360 |
} } return -EOPNOTSUPP; } int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { struct net_bridge *br = netdev_priv(dev); |
31a5b837c bridge: add space... |
361 |
switch (cmd) { |
1da177e4c Linux-2.6.12-rc2 |
362 363 364 365 366 367 368 369 |
case SIOCDEVPRIVATE: return old_dev_ioctl(dev, rq, cmd); case SIOCBRADDIF: case SIOCBRDELIF: return add_del_if(br, rq->ifr_ifindex, cmd == SIOCBRADDIF); } |
28a16c979 bridge: change co... |
370 371 |
br_debug(br, "Bridge does not support ioctl 0x%x ", cmd); |
1da177e4c Linux-2.6.12-rc2 |
372 373 |
return -EOPNOTSUPP; } |