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/kernel.h> 17 #include <linux/if_bridge.h> 18 #include <linux/netdevice.h> 19 #include <linux/times.h> 20 #include <asm/uaccess.h> 21 #include "br_private.h" 22 23 /* called with RTNL */ 24 static int get_bridge_ifindices(int *indices, int num) 25 { 26 struct net_device *dev; 27 int i = 0; 28 29 for (dev = dev_base; dev && i < num; dev = dev->next) { 30 if (dev->priv_flags & IFF_EBRIDGE) 31 indices[i++] = dev->ifindex; 32 } 33 34 return i; 35 } 36 37 /* called with RTNL */ 38 static void get_port_ifindices(struct net_bridge *br, int *ifindices, int num) 39 { 40 struct net_bridge_port *p; 41 42 list_for_each_entry(p, &br->port_list, list) { 43 if (p->port_no < num) 44 ifindices[p->port_no] = p->dev->ifindex; 45 } 46 } 47 48 /* 49 * Format up to a page worth of forwarding table entries 50 * userbuf -- where to copy result 51 * maxnum -- maximum number of entries desired 52 * (limited to a page for sanity) 53 * offset -- number of records to skip 54 */ 55 static int get_fdb_entries(struct net_bridge *br, void __user *userbuf, 56 unsigned long maxnum, unsigned long offset) 57 { 58 int num; 59 void *buf; 60 size_t size = maxnum * sizeof(struct __fdb_entry); 61 62 if (size > PAGE_SIZE) { 63 size = PAGE_SIZE; 64 maxnum = PAGE_SIZE/sizeof(struct __fdb_entry); 65 } 66 67 buf = kmalloc(size, GFP_USER); 68 if (!buf) 69 return -ENOMEM; 70 71 num = br_fdb_fillbuf(br, buf, maxnum, offset); 72 if (num > 0) { 73 if (copy_to_user(userbuf, buf, num*sizeof(struct __fdb_entry))) 74 num = -EFAULT; 75 } 76 kfree(buf); 77 78 return num; 79 } 80 81 static int add_del_if(struct net_bridge *br, int ifindex, int isadd) 82 { 83 struct net_device *dev; 84 int ret; 85 86 if (!capable(CAP_NET_ADMIN)) 87 return -EPERM; 88 89 dev = dev_get_by_index(ifindex); 90 if (dev == NULL) 91 return -EINVAL; 92 93 if (isadd) 94 ret = br_add_if(br, dev); 95 else 96 ret = br_del_if(br, dev); 97 98 dev_put(dev); 99 return ret; 100 } 101 102 /* 103 * Legacy ioctl's through SIOCDEVPRIVATE 104 * This interface is deprecated because it was too difficult to 105 * to do the translation for 32/64bit ioctl compatability. 106 */ 107 static int old_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 108 { 109 struct net_bridge *br = netdev_priv(dev); 110 unsigned long args[4]; 111 112 if (copy_from_user(args, rq->ifr_data, sizeof(args))) 113 return -EFAULT; 114 115 switch (args[0]) { 116 case BRCTL_ADD_IF: 117 case BRCTL_DEL_IF: 118 return add_del_if(br, args[1], args[0] == BRCTL_ADD_IF); 119 120 case BRCTL_GET_BRIDGE_INFO: 121 { 122 struct __bridge_info b; 123 124 memset(&b, 0, sizeof(struct __bridge_info)); 125 rcu_read_lock(); 126 memcpy(&b.designated_root, &br->designated_root, 8); 127 memcpy(&b.bridge_id, &br->bridge_id, 8); 128 b.root_path_cost = br->root_path_cost; 129 b.max_age = jiffies_to_clock_t(br->max_age); 130 b.hello_time = jiffies_to_clock_t(br->hello_time); 131 b.forward_delay = br->forward_delay; 132 b.bridge_max_age = br->bridge_max_age; 133 b.bridge_hello_time = br->bridge_hello_time; 134 b.bridge_forward_delay = jiffies_to_clock_t(br->bridge_forward_delay); 135 b.topology_change = br->topology_change; 136 b.topology_change_detected = br->topology_change_detected; 137 b.root_port = br->root_port; 138 b.stp_enabled = br->stp_enabled; 139 b.ageing_time = jiffies_to_clock_t(br->ageing_time); 140 b.hello_timer_value = br_timer_value(&br->hello_timer); 141 b.tcn_timer_value = br_timer_value(&br->tcn_timer); 142 b.topology_change_timer_value = br_timer_value(&br->topology_change_timer); 143 b.gc_timer_value = br_timer_value(&br->gc_timer); 144 rcu_read_unlock(); 145 146 if (copy_to_user((void __user *)args[1], &b, sizeof(b))) 147 return -EFAULT; 148 149 return 0; 150 } 151 152 case BRCTL_GET_PORT_LIST: 153 { 154 int num, *indices; 155 156 num = args[2]; 157 if (num < 0) 158 return -EINVAL; 159 if (num == 0) 160 num = 256; 161 if (num > BR_MAX_PORTS) 162 num = BR_MAX_PORTS; 163 164 indices = kmalloc(num*sizeof(int), GFP_KERNEL); 165 if (indices == NULL) 166 return -ENOMEM; 167 168 memset(indices, 0, num*sizeof(int)); 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 spin_lock_bh(&br->lock); 295 if ((p = br_get_port(br, args[1])) == NULL) 296 ret = -EINVAL; 297 else 298 br_stp_set_path_cost(p, args[2]); 299 spin_unlock_bh(&br->lock); 300 return ret; 301 } 302 303 case BRCTL_GET_FDB_ENTRIES: 304 return get_fdb_entries(br, (void __user *)args[1], 305 args[2], args[3]); 306 } 307 308 return -EOPNOTSUPP; 309 } 310 311 static int old_deviceless(void __user *uarg) 312 { 313 unsigned long args[3]; 314 315 if (copy_from_user(args, uarg, sizeof(args))) 316 return -EFAULT; 317 318 switch (args[0]) { 319 case BRCTL_GET_VERSION: 320 return BRCTL_VERSION; 321 322 case BRCTL_GET_BRIDGES: 323 { 324 int *indices; 325 int ret = 0; 326 327 if (args[2] >= 2048) 328 return -ENOMEM; 329 indices = kmalloc(args[2]*sizeof(int), GFP_KERNEL); 330 if (indices == NULL) 331 return -ENOMEM; 332 333 memset(indices, 0, args[2]*sizeof(int)); 334 args[2] = get_bridge_ifindices(indices, args[2]); 335 336 ret = copy_to_user((void __user *)args[1], indices, args[2]*sizeof(int)) 337 ? -EFAULT : args[2]; 338 339 kfree(indices); 340 return ret; 341 } 342 343 case BRCTL_ADD_BRIDGE: 344 case BRCTL_DEL_BRIDGE: 345 { 346 char buf[IFNAMSIZ]; 347 348 if (!capable(CAP_NET_ADMIN)) 349 return -EPERM; 350 351 if (copy_from_user(buf, (void __user *)args[1], IFNAMSIZ)) 352 return -EFAULT; 353 354 buf[IFNAMSIZ-1] = 0; 355 356 if (args[0] == BRCTL_ADD_BRIDGE) 357 return br_add_bridge(buf); 358 359 return br_del_bridge(buf); 360 } 361 } 362 363 return -EOPNOTSUPP; 364 } 365 366 int br_ioctl_deviceless_stub(unsigned int cmd, void __user *uarg) 367 { 368 switch (cmd) { 369 case SIOCGIFBR: 370 case SIOCSIFBR: 371 return old_deviceless(uarg); 372 373 case SIOCBRADDBR: 374 case SIOCBRDELBR: 375 { 376 char buf[IFNAMSIZ]; 377 378 if (!capable(CAP_NET_ADMIN)) 379 return -EPERM; 380 381 if (copy_from_user(buf, uarg, IFNAMSIZ)) 382 return -EFAULT; 383 384 buf[IFNAMSIZ-1] = 0; 385 if (cmd == SIOCBRADDBR) 386 return br_add_bridge(buf); 387 388 return br_del_bridge(buf); 389 } 390 } 391 return -EOPNOTSUPP; 392 } 393 394 int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) 395 { 396 struct net_bridge *br = netdev_priv(dev); 397 398 switch(cmd) { 399 case SIOCDEVPRIVATE: 400 return old_dev_ioctl(dev, rq, cmd); 401 402 case SIOCBRADDIF: 403 case SIOCBRDELIF: 404 return add_del_if(br, rq->ifr_ifindex, cmd == SIOCBRADDIF); 405 406 } 407 408 pr_debug("Bridge does not support ioctl 0x%x\n", cmd); 409 return -EOPNOTSUPP; 410 } 411