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