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) 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 struct atm_iobuf __user *iobuf = arg; 206 struct atmif_sioc __user *sioc = arg; 207 switch (cmd) { 208 case ATM_GETNAMES: 209 if (get_user(buf, &iobuf->buffer)) 210 return -EFAULT; 211 if (get_user(len, &iobuf->length)) 212 return -EFAULT; 213 mutex_lock(&atm_dev_mutex); 214 list_for_each(p, &atm_devs) 215 size += sizeof(int); 216 if (size > len) { 217 mutex_unlock(&atm_dev_mutex); 218 return -E2BIG; 219 } 220 tmp_buf = kmalloc(size, GFP_ATOMIC); 221 if (!tmp_buf) { 222 mutex_unlock(&atm_dev_mutex); 223 return -ENOMEM; 224 } 225 tmp_p = tmp_buf; 226 list_for_each(p, &atm_devs) { 227 dev = list_entry(p, struct atm_dev, dev_list); 228 *tmp_p++ = dev->number; 229 } 230 mutex_unlock(&atm_dev_mutex); 231 error = ((copy_to_user(buf, tmp_buf, size)) || 232 put_user(size, &iobuf->length)) 233 ? -EFAULT : 0; 234 kfree(tmp_buf); 235 return error; 236 default: 237 break; 238 } 239 240 if (get_user(buf, &sioc->arg)) 241 return -EFAULT; 242 if (get_user(len, &sioc->length)) 243 return -EFAULT; 244 if (get_user(number, &sioc->number)) 245 return -EFAULT; 246 247 if (!(dev = try_then_request_module(atm_dev_lookup(number), 248 "atm-device-%d", number))) 249 return -ENODEV; 250 251 switch (cmd) { 252 case ATM_GETTYPE: 253 size = strlen(dev->type) + 1; 254 if (copy_to_user(buf, dev->type, size)) { 255 error = -EFAULT; 256 goto done; 257 } 258 break; 259 case ATM_GETESI: 260 size = ESI_LEN; 261 if (copy_to_user(buf, dev->esi, size)) { 262 error = -EFAULT; 263 goto done; 264 } 265 break; 266 case ATM_SETESI: 267 { 268 int i; 269 270 for (i = 0; i < ESI_LEN; i++) 271 if (dev->esi[i]) { 272 error = -EEXIST; 273 goto done; 274 } 275 } 276 /* fall through */ 277 case ATM_SETESIF: 278 { 279 unsigned char esi[ESI_LEN]; 280 281 if (!capable(CAP_NET_ADMIN)) { 282 error = -EPERM; 283 goto done; 284 } 285 if (copy_from_user(esi, buf, ESI_LEN)) { 286 error = -EFAULT; 287 goto done; 288 } 289 memcpy(dev->esi, esi, ESI_LEN); 290 error = ESI_LEN; 291 goto done; 292 } 293 case ATM_GETSTATZ: 294 if (!capable(CAP_NET_ADMIN)) { 295 error = -EPERM; 296 goto done; 297 } 298 /* fall through */ 299 case ATM_GETSTAT: 300 size = sizeof(struct atm_dev_stats); 301 error = fetch_stats(dev, buf, cmd == ATM_GETSTATZ); 302 if (error) 303 goto done; 304 break; 305 case ATM_GETCIRANGE: 306 size = sizeof(struct atm_cirange); 307 if (copy_to_user(buf, &dev->ci_range, size)) { 308 error = -EFAULT; 309 goto done; 310 } 311 break; 312 case ATM_GETLINKRATE: 313 size = sizeof(int); 314 if (copy_to_user(buf, &dev->link_rate, size)) { 315 error = -EFAULT; 316 goto done; 317 } 318 break; 319 case ATM_RSTADDR: 320 if (!capable(CAP_NET_ADMIN)) { 321 error = -EPERM; 322 goto done; 323 } 324 atm_reset_addr(dev, ATM_ADDR_LOCAL); 325 break; 326 case ATM_ADDADDR: 327 case ATM_DELADDR: 328 case ATM_ADDLECSADDR: 329 case ATM_DELLECSADDR: 330 if (!capable(CAP_NET_ADMIN)) { 331 error = -EPERM; 332 goto done; 333 } 334 { 335 struct sockaddr_atmsvc addr; 336 337 if (copy_from_user(&addr, buf, sizeof(addr))) { 338 error = -EFAULT; 339 goto done; 340 } 341 if (cmd == ATM_ADDADDR || cmd == ATM_ADDLECSADDR) 342 error = atm_add_addr(dev, &addr, 343 (cmd == ATM_ADDADDR ? 344 ATM_ADDR_LOCAL : ATM_ADDR_LECS)); 345 else 346 error = atm_del_addr(dev, &addr, 347 (cmd == ATM_DELADDR ? 348 ATM_ADDR_LOCAL : ATM_ADDR_LECS)); 349 goto done; 350 } 351 case ATM_GETADDR: 352 case ATM_GETLECSADDR: 353 error = atm_get_addr(dev, buf, len, 354 (cmd == ATM_GETADDR ? 355 ATM_ADDR_LOCAL : ATM_ADDR_LECS)); 356 if (error < 0) 357 goto done; 358 size = error; 359 /* may return 0, but later on size == 0 means "don't 360 write the length" */ 361 error = put_user(size, &sioc->length) 362 ? -EFAULT : 0; 363 goto done; 364 case ATM_SETLOOP: 365 if (__ATM_LM_XTRMT((int) (unsigned long) buf) && 366 __ATM_LM_XTLOC((int) (unsigned long) buf) > 367 __ATM_LM_XTRMT((int) (unsigned long) buf)) { 368 error = -EINVAL; 369 goto done; 370 } 371 /* fall through */ 372 case ATM_SETCIRANGE: 373 case SONET_GETSTATZ: 374 case SONET_SETDIAG: 375 case SONET_CLRDIAG: 376 case SONET_SETFRAMING: 377 if (!capable(CAP_NET_ADMIN)) { 378 error = -EPERM; 379 goto done; 380 } 381 /* fall through */ 382 default: 383 if (!dev->ops->ioctl) { 384 error = -EINVAL; 385 goto done; 386 } 387 size = dev->ops->ioctl(dev, cmd, buf); 388 if (size < 0) { 389 error = (size == -ENOIOCTLCMD ? -EINVAL : size); 390 goto done; 391 } 392 } 393 394 if (size) 395 error = put_user(size, &sioc->length) 396 ? -EFAULT : 0; 397 else 398 error = 0; 399 done: 400 atm_dev_put(dev); 401 return error; 402 } 403 404 static __inline__ void *dev_get_idx(loff_t left) 405 { 406 struct list_head *p; 407 408 list_for_each(p, &atm_devs) { 409 if (!--left) 410 break; 411 } 412 return (p != &atm_devs) ? p : NULL; 413 } 414 415 void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos) 416 { 417 mutex_lock(&atm_dev_mutex); 418 return *pos ? dev_get_idx(*pos) : SEQ_START_TOKEN; 419 } 420 421 void atm_dev_seq_stop(struct seq_file *seq, void *v) 422 { 423 mutex_unlock(&atm_dev_mutex); 424 } 425 426 void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) 427 { 428 ++*pos; 429 v = (v == SEQ_START_TOKEN) 430 ? atm_devs.next : ((struct list_head *)v)->next; 431 return (v == &atm_devs) ? NULL : v; 432 } 433 434 435 EXPORT_SYMBOL(atm_dev_register); 436 EXPORT_SYMBOL(atm_dev_deregister); 437 EXPORT_SYMBOL(atm_dev_lookup); 438