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