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