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