resources.c (9076B)
1// SPDX-License-Identifier: GPL-2.0 2/* net/atm/resources.c - Statically allocated resources */ 3 4/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */ 5 6/* Fixes 7 * Arnaldo Carvalho de Melo <acme@conectiva.com.br> 8 * 2002/01 - don't free the whole struct sock on sk->destruct time, 9 * use the default destruct function initialized by sock_init_data */ 10 11#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ 12 13#include <linux/ctype.h> 14#include <linux/string.h> 15#include <linux/atmdev.h> 16#include <linux/sonet.h> 17#include <linux/kernel.h> /* for barrier */ 18#include <linux/module.h> 19#include <linux/bitops.h> 20#include <linux/capability.h> 21#include <linux/delay.h> 22#include <linux/mutex.h> 23#include <linux/slab.h> 24 25#include <net/sock.h> /* for struct sock */ 26 27#include "common.h" 28#include "resources.h" 29#include "addr.h" 30 31 32LIST_HEAD(atm_devs); 33DEFINE_MUTEX(atm_dev_mutex); 34 35static struct atm_dev *__alloc_atm_dev(const char *type) 36{ 37 struct atm_dev *dev; 38 39 dev = kzalloc(sizeof(*dev), GFP_KERNEL); 40 if (!dev) 41 return NULL; 42 dev->type = type; 43 dev->signal = ATM_PHY_SIG_UNKNOWN; 44 dev->link_rate = ATM_OC3_PCR; 45 spin_lock_init(&dev->lock); 46 INIT_LIST_HEAD(&dev->local); 47 INIT_LIST_HEAD(&dev->lecs); 48 49 return dev; 50} 51 52static struct atm_dev *__atm_dev_lookup(int number) 53{ 54 struct atm_dev *dev; 55 56 list_for_each_entry(dev, &atm_devs, dev_list) { 57 if (dev->number == number) { 58 atm_dev_hold(dev); 59 return dev; 60 } 61 } 62 return NULL; 63} 64 65struct 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} 74EXPORT_SYMBOL(atm_dev_lookup); 75 76struct atm_dev *atm_dev_register(const char *type, struct device *parent, 77 const struct atmdev_ops *ops, int number, 78 unsigned long *flags) 79{ 80 struct atm_dev *dev, *inuse; 81 82 dev = __alloc_atm_dev(type); 83 if (!dev) { 84 pr_err("no space for dev %s\n", type); 85 return NULL; 86 } 87 mutex_lock(&atm_dev_mutex); 88 if (number != -1) { 89 inuse = __atm_dev_lookup(number); 90 if (inuse) { 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 refcount_set(&dev->refcnt, 1); 112 113 if (atm_proc_dev_register(dev) < 0) { 114 pr_err("atm_proc_dev_register failed for dev %s\n", type); 115 goto out_fail; 116 } 117 118 if (atm_register_sysfs(dev, parent) < 0) { 119 pr_err("atm_register_sysfs failed for dev %s\n", type); 120 atm_proc_dev_deregister(dev); 121 goto out_fail; 122 } 123 124 list_add_tail(&dev->dev_list, &atm_devs); 125 126out: 127 mutex_unlock(&atm_dev_mutex); 128 return dev; 129 130out_fail: 131 kfree(dev); 132 dev = NULL; 133 goto out; 134} 135EXPORT_SYMBOL(atm_dev_register); 136 137void atm_dev_deregister(struct atm_dev *dev) 138{ 139 BUG_ON(test_bit(ATM_DF_REMOVED, &dev->flags)); 140 set_bit(ATM_DF_REMOVED, &dev->flags); 141 142 /* 143 * if we remove current device from atm_devs list, new device 144 * with same number can appear, such we need deregister proc, 145 * release async all vccs and remove them from vccs list too 146 */ 147 mutex_lock(&atm_dev_mutex); 148 list_del(&dev->dev_list); 149 mutex_unlock(&atm_dev_mutex); 150 151 atm_dev_release_vccs(dev); 152 atm_unregister_sysfs(dev); 153 atm_proc_dev_deregister(dev); 154 155 atm_dev_put(dev); 156} 157EXPORT_SYMBOL(atm_dev_deregister); 158 159static void copy_aal_stats(struct k_atm_aal_stats *from, 160 struct atm_aal_stats *to) 161{ 162#define __HANDLE_ITEM(i) to->i = atomic_read(&from->i) 163 __AAL_STAT_ITEMS 164#undef __HANDLE_ITEM 165} 166 167static void subtract_aal_stats(struct k_atm_aal_stats *from, 168 struct atm_aal_stats *to) 169{ 170#define __HANDLE_ITEM(i) atomic_sub(to->i, &from->i) 171 __AAL_STAT_ITEMS 172#undef __HANDLE_ITEM 173} 174 175static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats __user *arg, 176 int zero) 177{ 178 struct atm_dev_stats tmp; 179 int error = 0; 180 181 copy_aal_stats(&dev->stats.aal0, &tmp.aal0); 182 copy_aal_stats(&dev->stats.aal34, &tmp.aal34); 183 copy_aal_stats(&dev->stats.aal5, &tmp.aal5); 184 if (arg) 185 error = copy_to_user(arg, &tmp, sizeof(tmp)); 186 if (zero && !error) { 187 subtract_aal_stats(&dev->stats.aal0, &tmp.aal0); 188 subtract_aal_stats(&dev->stats.aal34, &tmp.aal34); 189 subtract_aal_stats(&dev->stats.aal5, &tmp.aal5); 190 } 191 return error ? -EFAULT : 0; 192} 193 194int atm_getnames(void __user *buf, int __user *iobuf_len) 195{ 196 int error, len, size = 0; 197 struct atm_dev *dev; 198 struct list_head *p; 199 int *tmp_buf, *tmp_p; 200 201 if (get_user(len, iobuf_len)) 202 return -EFAULT; 203 mutex_lock(&atm_dev_mutex); 204 list_for_each(p, &atm_devs) 205 size += sizeof(int); 206 if (size > len) { 207 mutex_unlock(&atm_dev_mutex); 208 return -E2BIG; 209 } 210 tmp_buf = kmalloc(size, GFP_ATOMIC); 211 if (!tmp_buf) { 212 mutex_unlock(&atm_dev_mutex); 213 return -ENOMEM; 214 } 215 tmp_p = tmp_buf; 216 list_for_each_entry(dev, &atm_devs, dev_list) { 217 *tmp_p++ = dev->number; 218 } 219 mutex_unlock(&atm_dev_mutex); 220 error = ((copy_to_user(buf, tmp_buf, size)) || 221 put_user(size, iobuf_len)) 222 ? -EFAULT : 0; 223 kfree(tmp_buf); 224 return error; 225} 226 227int atm_dev_ioctl(unsigned int cmd, void __user *buf, int __user *sioc_len, 228 int number, int compat) 229{ 230 int error, len, size = 0; 231 struct atm_dev *dev; 232 233 if (get_user(len, sioc_len)) 234 return -EFAULT; 235 236 dev = try_then_request_module(atm_dev_lookup(number), "atm-device-%d", 237 number); 238 if (!dev) 239 return -ENODEV; 240 241 switch (cmd) { 242 case ATM_GETTYPE: 243 size = strlen(dev->type) + 1; 244 if (copy_to_user(buf, dev->type, size)) { 245 error = -EFAULT; 246 goto done; 247 } 248 break; 249 case ATM_GETESI: 250 size = ESI_LEN; 251 if (copy_to_user(buf, dev->esi, size)) { 252 error = -EFAULT; 253 goto done; 254 } 255 break; 256 case ATM_SETESI: 257 { 258 int i; 259 260 for (i = 0; i < ESI_LEN; i++) 261 if (dev->esi[i]) { 262 error = -EEXIST; 263 goto done; 264 } 265 } 266 fallthrough; 267 case ATM_SETESIF: 268 { 269 unsigned char esi[ESI_LEN]; 270 271 if (!capable(CAP_NET_ADMIN)) { 272 error = -EPERM; 273 goto done; 274 } 275 if (copy_from_user(esi, buf, ESI_LEN)) { 276 error = -EFAULT; 277 goto done; 278 } 279 memcpy(dev->esi, esi, ESI_LEN); 280 error = ESI_LEN; 281 goto done; 282 } 283 case ATM_GETSTATZ: 284 if (!capable(CAP_NET_ADMIN)) { 285 error = -EPERM; 286 goto done; 287 } 288 fallthrough; 289 case ATM_GETSTAT: 290 size = sizeof(struct atm_dev_stats); 291 error = fetch_stats(dev, buf, cmd == ATM_GETSTATZ); 292 if (error) 293 goto done; 294 break; 295 case ATM_GETCIRANGE: 296 size = sizeof(struct atm_cirange); 297 if (copy_to_user(buf, &dev->ci_range, size)) { 298 error = -EFAULT; 299 goto done; 300 } 301 break; 302 case ATM_GETLINKRATE: 303 size = sizeof(int); 304 if (copy_to_user(buf, &dev->link_rate, size)) { 305 error = -EFAULT; 306 goto done; 307 } 308 break; 309 case ATM_RSTADDR: 310 if (!capable(CAP_NET_ADMIN)) { 311 error = -EPERM; 312 goto done; 313 } 314 atm_reset_addr(dev, ATM_ADDR_LOCAL); 315 break; 316 case ATM_ADDADDR: 317 case ATM_DELADDR: 318 case ATM_ADDLECSADDR: 319 case ATM_DELLECSADDR: 320 { 321 struct sockaddr_atmsvc addr; 322 323 if (!capable(CAP_NET_ADMIN)) { 324 error = -EPERM; 325 goto done; 326 } 327 328 if (copy_from_user(&addr, buf, sizeof(addr))) { 329 error = -EFAULT; 330 goto done; 331 } 332 if (cmd == ATM_ADDADDR || cmd == ATM_ADDLECSADDR) 333 error = atm_add_addr(dev, &addr, 334 (cmd == ATM_ADDADDR ? 335 ATM_ADDR_LOCAL : ATM_ADDR_LECS)); 336 else 337 error = atm_del_addr(dev, &addr, 338 (cmd == ATM_DELADDR ? 339 ATM_ADDR_LOCAL : ATM_ADDR_LECS)); 340 goto done; 341 } 342 case ATM_GETADDR: 343 case ATM_GETLECSADDR: 344 error = atm_get_addr(dev, buf, len, 345 (cmd == ATM_GETADDR ? 346 ATM_ADDR_LOCAL : ATM_ADDR_LECS)); 347 if (error < 0) 348 goto done; 349 size = error; 350 /* may return 0, but later on size == 0 means "don't 351 write the length" */ 352 error = put_user(size, sioc_len) ? -EFAULT : 0; 353 goto done; 354 case ATM_SETLOOP: 355 if (__ATM_LM_XTRMT((int) (unsigned long) buf) && 356 __ATM_LM_XTLOC((int) (unsigned long) buf) > 357 __ATM_LM_XTRMT((int) (unsigned long) buf)) { 358 error = -EINVAL; 359 goto done; 360 } 361 fallthrough; 362 case ATM_SETCIRANGE: 363 case SONET_GETSTATZ: 364 case SONET_SETDIAG: 365 case SONET_CLRDIAG: 366 case SONET_SETFRAMING: 367 if (!capable(CAP_NET_ADMIN)) { 368 error = -EPERM; 369 goto done; 370 } 371 fallthrough; 372 default: 373 if (IS_ENABLED(CONFIG_COMPAT) && compat) { 374#ifdef CONFIG_COMPAT 375 if (!dev->ops->compat_ioctl) { 376 error = -EINVAL; 377 goto done; 378 } 379 size = dev->ops->compat_ioctl(dev, cmd, buf); 380#endif 381 } else { 382 if (!dev->ops->ioctl) { 383 error = -EINVAL; 384 goto done; 385 } 386 size = dev->ops->ioctl(dev, cmd, buf); 387 } 388 if (size < 0) { 389 error = (size == -ENOIOCTLCMD ? -ENOTTY : size); 390 goto done; 391 } 392 } 393 394 if (size) 395 error = put_user(size, sioc_len) ? -EFAULT : 0; 396 else 397 error = 0; 398done: 399 atm_dev_put(dev); 400 return error; 401} 402 403void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos) 404{ 405 mutex_lock(&atm_dev_mutex); 406 return seq_list_start_head(&atm_devs, *pos); 407} 408 409void atm_dev_seq_stop(struct seq_file *seq, void *v) 410{ 411 mutex_unlock(&atm_dev_mutex); 412} 413 414void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) 415{ 416 return seq_list_next(v, &atm_devs, pos); 417}