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