1/* net/atm/resources.c - Statically allocated resources */ 2 3/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ 4 5/* Fixes 6 * Arnaldo Carvalho de Melo <acme@conectiva.com.br> 7 * 2002/01 - don't free the whole struct sock on sk->destruct time, 8 * use the default destruct function initialized by sock_init_data */ 9 10#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ 11 12#include <linux/ctype.h> 13#include <linux/string.h> 14#include <linux/atmdev.h> 15#include <linux/sonet.h> 16#include <linux/kernel.h> /* for barrier */ 17#include <linux/module.h> 18#include <linux/bitops.h> 19#include <linux/capability.h> 20#include <linux/delay.h> 21#include <linux/mutex.h> 22#include <linux/slab.h> 23 24#include <net/sock.h> /* for struct sock */ 25 26#include "common.h" 27#include "resources.h" 28#include "addr.h" 29 30 31LIST_HEAD(atm_devs); 32DEFINE_MUTEX(atm_dev_mutex); 33 34static struct atm_dev *__alloc_atm_dev(const char *type) 35{ 36 struct atm_dev *dev; 37 38 dev = kzalloc(sizeof(*dev), GFP_KERNEL); 39 if (!dev) 40 return NULL; 41 dev->type = type; 42 dev->signal = ATM_PHY_SIG_UNKNOWN; 43 dev->link_rate = ATM_OC3_PCR; 44 spin_lock_init(&dev->lock); 45 INIT_LIST_HEAD(&dev->local); 46 INIT_LIST_HEAD(&dev->lecs); 47 48 return dev; 49} 50 51static struct atm_dev *__atm_dev_lookup(int number) 52{ 53 struct atm_dev *dev; 54 struct list_head *p; 55 56 list_for_each(p, &atm_devs) { 57 dev = list_entry(p, struct atm_dev, dev_list); 58 if (dev->number == number) { 59 atm_dev_hold(dev); 60 return dev; 61 } 62 } 63 return NULL; 64} 65 66struct atm_dev *atm_dev_lookup(int number) 67{ 68 struct atm_dev *dev; 69 70 mutex_lock(&atm_dev_mutex); 71 dev = __atm_dev_lookup(number); 72 mutex_unlock(&atm_dev_mutex); 73 return dev; 74} 75EXPORT_SYMBOL(atm_dev_lookup); 76 77struct atm_dev *atm_dev_register(const char *type, struct device *parent, 78 const struct atmdev_ops *ops, int number, 79 unsigned long *flags) 80{ 81 struct atm_dev *dev, *inuse; 82 83 dev = __alloc_atm_dev(type); 84 if (!dev) { 85 pr_err("no space for dev %s\n", type); 86 return NULL; 87 } 88 mutex_lock(&atm_dev_mutex); 89 if (number != -1) { 90 inuse = __atm_dev_lookup(number); 91 if (inuse) { 92 atm_dev_put(inuse); 93 mutex_unlock(&atm_dev_mutex); 94 kfree(dev); 95 return NULL; 96 } 97 dev->number = number; 98 } else { 99 dev->number = 0; 100 while ((inuse = __atm_dev_lookup(dev->number))) { 101 atm_dev_put(inuse); 102 dev->number++; 103 } 104 } 105 106 dev->ops = ops; 107 if (flags) 108 dev->flags = *flags; 109 else 110 memset(&dev->flags, 0, sizeof(dev->flags)); 111 memset(&dev->stats, 0, sizeof(dev->stats)); 112 atomic_set(&dev->refcnt, 1); 113 114 if (atm_proc_dev_register(dev) < 0) { 115 pr_err("atm_proc_dev_register failed for dev %s\n", type); 116 goto out_fail; 117 } 118 119 if (atm_register_sysfs(dev, parent) < 0) { 120 pr_err("atm_register_sysfs failed for dev %s\n", type); 121 atm_proc_dev_deregister(dev); 122 goto out_fail; 123 } 124 125 list_add_tail(&dev->dev_list, &atm_devs); 126 127out: 128 mutex_unlock(&atm_dev_mutex); 129 return dev; 130 131out_fail: 132 kfree(dev); 133 dev = NULL; 134 goto out; 135} 136EXPORT_SYMBOL(atm_dev_register); 137 138void atm_dev_deregister(struct atm_dev *dev) 139{ 140 BUG_ON(test_bit(ATM_DF_REMOVED, &dev->flags)); 141 set_bit(ATM_DF_REMOVED, &dev->flags); 142 143 /* 144 * if we remove current device from atm_devs list, new device 145 * with same number can appear, such we need deregister proc, 146 * release async all vccs and remove them from vccs list too 147 */ 148 mutex_lock(&atm_dev_mutex); 149 list_del(&dev->dev_list); 150 mutex_unlock(&atm_dev_mutex); 151 152 atm_dev_release_vccs(dev); 153 atm_unregister_sysfs(dev); 154 atm_proc_dev_deregister(dev); 155 156 atm_dev_put(dev); 157} 158EXPORT_SYMBOL(atm_dev_deregister); 159 160static void copy_aal_stats(struct k_atm_aal_stats *from, 161 struct atm_aal_stats *to) 162{ 163#define __HANDLE_ITEM(i) to->i = atomic_read(&from->i) 164 __AAL_STAT_ITEMS 165#undef __HANDLE_ITEM 166} 167 168static void subtract_aal_stats(struct k_atm_aal_stats *from, 169 struct atm_aal_stats *to) 170{ 171#define __HANDLE_ITEM(i) atomic_sub(to->i, &from->i) 172 __AAL_STAT_ITEMS 173#undef __HANDLE_ITEM 174} 175 176static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats __user *arg, 177 int zero) 178{ 179 struct atm_dev_stats tmp; 180 int error = 0; 181 182 copy_aal_stats(&dev->stats.aal0, &tmp.aal0); 183 copy_aal_stats(&dev->stats.aal34, &tmp.aal34); 184 copy_aal_stats(&dev->stats.aal5, &tmp.aal5); 185 if (arg) 186 error = copy_to_user(arg, &tmp, sizeof(tmp)); 187 if (zero && !error) { 188 subtract_aal_stats(&dev->stats.aal0, &tmp.aal0); 189 subtract_aal_stats(&dev->stats.aal34, &tmp.aal34); 190 subtract_aal_stats(&dev->stats.aal5, &tmp.aal5); 191 } 192 return error ? -EFAULT : 0; 193} 194 195int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat) 196{ 197 void __user *buf; 198 int error, len, number, size = 0; 199 struct atm_dev *dev; 200 struct list_head *p; 201 int *tmp_buf, *tmp_p; 202 int __user *sioc_len; 203 int __user *iobuf_len; 204 205#ifndef CONFIG_COMPAT 206 compat = 0; /* Just so the compiler _knows_ */ 207#endif 208 209 switch (cmd) { 210 case ATM_GETNAMES: 211 if (compat) { 212#ifdef CONFIG_COMPAT 213 struct compat_atm_iobuf __user *ciobuf = arg; 214 compat_uptr_t cbuf; 215 iobuf_len = &ciobuf->length; 216 if (get_user(cbuf, &ciobuf->buffer)) 217 return -EFAULT; 218 buf = compat_ptr(cbuf); 219#endif 220 } else { 221 struct atm_iobuf __user *iobuf = arg; 222 iobuf_len = &iobuf->length; 223 if (get_user(buf, &iobuf->buffer)) 224 return -EFAULT; 225 } 226 if (get_user(len, iobuf_len)) 227 return -EFAULT; 228 mutex_lock(&atm_dev_mutex); 229 list_for_each(p, &atm_devs) 230 size += sizeof(int); 231 if (size > len) { 232 mutex_unlock(&atm_dev_mutex); 233 return -E2BIG; 234 } 235 tmp_buf = kmalloc(size, GFP_ATOMIC); 236 if (!tmp_buf) { 237 mutex_unlock(&atm_dev_mutex); 238 return -ENOMEM; 239 } 240 tmp_p = tmp_buf; 241 list_for_each(p, &atm_devs) { 242 dev = list_entry(p, struct atm_dev, dev_list); 243 *tmp_p++ = dev->number; 244 } 245 mutex_unlock(&atm_dev_mutex); 246 error = ((copy_to_user(buf, tmp_buf, size)) || 247 put_user(size, iobuf_len)) 248 ? -EFAULT : 0; 249 kfree(tmp_buf); 250 return error; 251 default: 252 break; 253 } 254 255 if (compat) { 256#ifdef CONFIG_COMPAT 257 struct compat_atmif_sioc __user *csioc = arg; 258 compat_uptr_t carg; 259 260 sioc_len = &csioc->length; 261 if (get_user(carg, &csioc->arg)) 262 return -EFAULT; 263 buf = compat_ptr(carg); 264 265 if (get_user(len, &csioc->length)) 266 return -EFAULT; 267 if (get_user(number, &csioc->number)) 268 return -EFAULT; 269#endif 270 } else { 271 struct atmif_sioc __user *sioc = arg; 272 273 sioc_len = &sioc->length; 274 if (get_user(buf, &sioc->arg)) 275 return -EFAULT; 276 if (get_user(len, &sioc->length)) 277 return -EFAULT; 278 if (get_user(number, &sioc->number)) 279 return -EFAULT; 280 } 281 282 dev = try_then_request_module(atm_dev_lookup(number), "atm-device-%d", 283 number); 284 if (!dev) 285 return -ENODEV; 286 287 switch (cmd) { 288 case ATM_GETTYPE: 289 size = strlen(dev->type) + 1; 290 if (copy_to_user(buf, dev->type, size)) { 291 error = -EFAULT; 292 goto done; 293 } 294 break; 295 case ATM_GETESI: 296 size = ESI_LEN; 297 if (copy_to_user(buf, dev->esi, size)) { 298 error = -EFAULT; 299 goto done; 300 } 301 break; 302 case ATM_SETESI: 303 { 304 int i; 305 306 for (i = 0; i < ESI_LEN; i++) 307 if (dev->esi[i]) { 308 error = -EEXIST; 309 goto done; 310 } 311 } 312 /* fall through */ 313 case ATM_SETESIF: 314 { 315 unsigned char esi[ESI_LEN]; 316 317 if (!capable(CAP_NET_ADMIN)) { 318 error = -EPERM; 319 goto done; 320 } 321 if (copy_from_user(esi, buf, ESI_LEN)) { 322 error = -EFAULT; 323 goto done; 324 } 325 memcpy(dev->esi, esi, ESI_LEN); 326 error = ESI_LEN; 327 goto done; 328 } 329 case ATM_GETSTATZ: 330 if (!capable(CAP_NET_ADMIN)) { 331 error = -EPERM; 332 goto done; 333 } 334 /* fall through */ 335 case ATM_GETSTAT: 336 size = sizeof(struct atm_dev_stats); 337 error = fetch_stats(dev, buf, cmd == ATM_GETSTATZ); 338 if (error) 339 goto done; 340 break; 341 case ATM_GETCIRANGE: 342 size = sizeof(struct atm_cirange); 343 if (copy_to_user(buf, &dev->ci_range, size)) { 344 error = -EFAULT; 345 goto done; 346 } 347 break; 348 case ATM_GETLINKRATE: 349 size = sizeof(int); 350 if (copy_to_user(buf, &dev->link_rate, size)) { 351 error = -EFAULT; 352 goto done; 353 } 354 break; 355 case ATM_RSTADDR: 356 if (!capable(CAP_NET_ADMIN)) { 357 error = -EPERM; 358 goto done; 359 } 360 atm_reset_addr(dev, ATM_ADDR_LOCAL); 361 break; 362 case ATM_ADDADDR: 363 case ATM_DELADDR: 364 case ATM_ADDLECSADDR: 365 case ATM_DELLECSADDR: 366 { 367 struct sockaddr_atmsvc addr; 368 369 if (!capable(CAP_NET_ADMIN)) { 370 error = -EPERM; 371 goto done; 372 } 373 374 if (copy_from_user(&addr, buf, sizeof(addr))) { 375 error = -EFAULT; 376 goto done; 377 } 378 if (cmd == ATM_ADDADDR || cmd == ATM_ADDLECSADDR) 379 error = atm_add_addr(dev, &addr, 380 (cmd == ATM_ADDADDR ? 381 ATM_ADDR_LOCAL : ATM_ADDR_LECS)); 382 else 383 error = atm_del_addr(dev, &addr, 384 (cmd == ATM_DELADDR ? 385 ATM_ADDR_LOCAL : ATM_ADDR_LECS)); 386 goto done; 387 } 388 case ATM_GETADDR: 389 case ATM_GETLECSADDR: 390 error = atm_get_addr(dev, buf, len, 391 (cmd == ATM_GETADDR ? 392 ATM_ADDR_LOCAL : ATM_ADDR_LECS)); 393 if (error < 0) 394 goto done; 395 size = error; 396 /* may return 0, but later on size == 0 means "don't 397 write the length" */ 398 error = put_user(size, sioc_len) ? -EFAULT : 0; 399 goto done; 400 case ATM_SETLOOP: 401 if (__ATM_LM_XTRMT((int) (unsigned long) buf) && 402 __ATM_LM_XTLOC((int) (unsigned long) buf) > 403 __ATM_LM_XTRMT((int) (unsigned long) buf)) { 404 error = -EINVAL; 405 goto done; 406 } 407 /* fall through */ 408 case ATM_SETCIRANGE: 409 case SONET_GETSTATZ: 410 case SONET_SETDIAG: 411 case SONET_CLRDIAG: 412 case SONET_SETFRAMING: 413 if (!capable(CAP_NET_ADMIN)) { 414 error = -EPERM; 415 goto done; 416 } 417 /* fall through */ 418 default: 419 if (compat) { 420#ifdef CONFIG_COMPAT 421 if (!dev->ops->compat_ioctl) { 422 error = -EINVAL; 423 goto done; 424 } 425 size = dev->ops->compat_ioctl(dev, cmd, buf); 426#endif 427 } else { 428 if (!dev->ops->ioctl) { 429 error = -EINVAL; 430 goto done; 431 } 432 size = dev->ops->ioctl(dev, cmd, buf); 433 } 434 if (size < 0) { 435 error = (size == -ENOIOCTLCMD ? -ENOTTY : size); 436 goto done; 437 } 438 } 439 440 if (size) 441 error = put_user(size, sioc_len) ? -EFAULT : 0; 442 else 443 error = 0; 444done: 445 atm_dev_put(dev); 446 return error; 447} 448 449void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos) 450{ 451 mutex_lock(&atm_dev_mutex); 452 return seq_list_start_head(&atm_devs, *pos); 453} 454 455void atm_dev_seq_stop(struct seq_file *seq, void *v) 456{ 457 mutex_unlock(&atm_dev_mutex); 458} 459 460void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) 461{ 462 return seq_list_next(v, &atm_devs, pos); 463} 464