xref: /openbmc/linux/net/atm/resources.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /* net/atm/resources.c - Statically allocated resources */
31da177e4SLinus Torvalds 
41da177e4SLinus Torvalds /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
51da177e4SLinus Torvalds 
61da177e4SLinus Torvalds /* Fixes
71da177e4SLinus Torvalds  * Arnaldo Carvalho de Melo <acme@conectiva.com.br>
81da177e4SLinus Torvalds  * 2002/01 - don't free the whole struct sock on sk->destruct time,
91da177e4SLinus Torvalds  * 	     use the default destruct function initialized by sock_init_data */
101da177e4SLinus Torvalds 
1199824461SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
121da177e4SLinus Torvalds 
131da177e4SLinus Torvalds #include <linux/ctype.h>
141da177e4SLinus Torvalds #include <linux/string.h>
151da177e4SLinus Torvalds #include <linux/atmdev.h>
161da177e4SLinus Torvalds #include <linux/sonet.h>
171da177e4SLinus Torvalds #include <linux/kernel.h> /* for barrier */
181da177e4SLinus Torvalds #include <linux/module.h>
191da177e4SLinus Torvalds #include <linux/bitops.h>
204fc268d2SRandy Dunlap #include <linux/capability.h>
211da177e4SLinus Torvalds #include <linux/delay.h>
2257b47a53SIngo Molnar #include <linux/mutex.h>
235a0e3ad6STejun Heo #include <linux/slab.h>
2457b47a53SIngo Molnar 
251da177e4SLinus Torvalds #include <net/sock.h>	 /* for struct sock */
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds #include "common.h"
281da177e4SLinus Torvalds #include "resources.h"
291da177e4SLinus Torvalds #include "addr.h"
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds LIST_HEAD(atm_devs);
3357b47a53SIngo Molnar DEFINE_MUTEX(atm_dev_mutex);
341da177e4SLinus Torvalds 
__alloc_atm_dev(const char * type)351da177e4SLinus Torvalds static struct atm_dev *__alloc_atm_dev(const char *type)
361da177e4SLinus Torvalds {
371da177e4SLinus Torvalds 	struct atm_dev *dev;
381da177e4SLinus Torvalds 
390da974f4SPanagiotis Issaris 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
401da177e4SLinus Torvalds 	if (!dev)
411da177e4SLinus Torvalds 		return NULL;
421da177e4SLinus Torvalds 	dev->type = type;
431da177e4SLinus Torvalds 	dev->signal = ATM_PHY_SIG_UNKNOWN;
441da177e4SLinus Torvalds 	dev->link_rate = ATM_OC3_PCR;
451da177e4SLinus Torvalds 	spin_lock_init(&dev->lock);
461da177e4SLinus Torvalds 	INIT_LIST_HEAD(&dev->local);
470f21ba7cSEric Kinzie 	INIT_LIST_HEAD(&dev->lecs);
481da177e4SLinus Torvalds 
491da177e4SLinus Torvalds 	return dev;
501da177e4SLinus Torvalds }
511da177e4SLinus Torvalds 
__atm_dev_lookup(int number)521da177e4SLinus Torvalds static struct atm_dev *__atm_dev_lookup(int number)
531da177e4SLinus Torvalds {
541da177e4SLinus Torvalds 	struct atm_dev *dev;
551da177e4SLinus Torvalds 
5673e42909SWang Hai 	list_for_each_entry(dev, &atm_devs, dev_list) {
57aaaaaadbSStanislaw Gruszka 		if (dev->number == number) {
581da177e4SLinus Torvalds 			atm_dev_hold(dev);
591da177e4SLinus Torvalds 			return dev;
601da177e4SLinus Torvalds 		}
611da177e4SLinus Torvalds 	}
621da177e4SLinus Torvalds 	return NULL;
631da177e4SLinus Torvalds }
641da177e4SLinus Torvalds 
atm_dev_lookup(int number)651da177e4SLinus Torvalds struct atm_dev *atm_dev_lookup(int number)
661da177e4SLinus Torvalds {
671da177e4SLinus Torvalds 	struct atm_dev *dev;
681da177e4SLinus Torvalds 
6957b47a53SIngo Molnar 	mutex_lock(&atm_dev_mutex);
701da177e4SLinus Torvalds 	dev = __atm_dev_lookup(number);
7157b47a53SIngo Molnar 	mutex_unlock(&atm_dev_mutex);
721da177e4SLinus Torvalds 	return dev;
731da177e4SLinus Torvalds }
7407b54c9aSJoe Perches EXPORT_SYMBOL(atm_dev_lookup);
7564bf69ddSStanislaw Gruszka 
atm_dev_register(const char * type,struct device * parent,const struct atmdev_ops * ops,int number,unsigned long * flags)76d9ca676bSDan Williams struct atm_dev *atm_dev_register(const char *type, struct device *parent,
77d9ca676bSDan Williams 				 const struct atmdev_ops *ops, int number,
78d9ca676bSDan Williams 				 unsigned long *flags)
791da177e4SLinus Torvalds {
801da177e4SLinus Torvalds 	struct atm_dev *dev, *inuse;
811da177e4SLinus Torvalds 
821da177e4SLinus Torvalds 	dev = __alloc_atm_dev(type);
831da177e4SLinus Torvalds 	if (!dev) {
8499824461SJoe Perches 		pr_err("no space for dev %s\n", type);
851da177e4SLinus Torvalds 		return NULL;
861da177e4SLinus Torvalds 	}
8757b47a53SIngo Molnar 	mutex_lock(&atm_dev_mutex);
881da177e4SLinus Torvalds 	if (number != -1) {
8907b54c9aSJoe Perches 		inuse = __atm_dev_lookup(number);
9007b54c9aSJoe Perches 		if (inuse) {
911da177e4SLinus Torvalds 			atm_dev_put(inuse);
9257b47a53SIngo Molnar 			mutex_unlock(&atm_dev_mutex);
93ebc37b61SAdrian Bunk 			kfree(dev);
941da177e4SLinus Torvalds 			return NULL;
951da177e4SLinus Torvalds 		}
961da177e4SLinus Torvalds 		dev->number = number;
971da177e4SLinus Torvalds 	} else {
981da177e4SLinus Torvalds 		dev->number = 0;
991da177e4SLinus Torvalds 		while ((inuse = __atm_dev_lookup(dev->number))) {
1001da177e4SLinus Torvalds 			atm_dev_put(inuse);
1011da177e4SLinus Torvalds 			dev->number++;
1021da177e4SLinus Torvalds 		}
1031da177e4SLinus Torvalds 	}
1041da177e4SLinus Torvalds 
1051da177e4SLinus Torvalds 	dev->ops = ops;
1061da177e4SLinus Torvalds 	if (flags)
1071da177e4SLinus Torvalds 		dev->flags = *flags;
1081da177e4SLinus Torvalds 	else
1091da177e4SLinus Torvalds 		memset(&dev->flags, 0, sizeof(dev->flags));
1101da177e4SLinus Torvalds 	memset(&dev->stats, 0, sizeof(dev->stats));
111458bc30cSReshetova, Elena 	refcount_set(&dev->refcnt, 1);
1121da177e4SLinus Torvalds 
1131da177e4SLinus Torvalds 	if (atm_proc_dev_register(dev) < 0) {
11499824461SJoe Perches 		pr_err("atm_proc_dev_register failed for dev %s\n", type);
115656d98b0SRoman Kagan 		goto out_fail;
1161da177e4SLinus Torvalds 	}
1171da177e4SLinus Torvalds 
118d9ca676bSDan Williams 	if (atm_register_sysfs(dev, parent) < 0) {
11999824461SJoe Perches 		pr_err("atm_register_sysfs failed for dev %s\n", type);
120656d98b0SRoman Kagan 		atm_proc_dev_deregister(dev);
121656d98b0SRoman Kagan 		goto out_fail;
122656d98b0SRoman Kagan 	}
123656d98b0SRoman Kagan 
124656d98b0SRoman Kagan 	list_add_tail(&dev->dev_list, &atm_devs);
125656d98b0SRoman Kagan 
126656d98b0SRoman Kagan out:
127656d98b0SRoman Kagan 	mutex_unlock(&atm_dev_mutex);
1281da177e4SLinus Torvalds 	return dev;
129656d98b0SRoman Kagan 
130656d98b0SRoman Kagan out_fail:
131656d98b0SRoman Kagan 	kfree(dev);
132656d98b0SRoman Kagan 	dev = NULL;
133656d98b0SRoman Kagan 	goto out;
1341da177e4SLinus Torvalds }
13507b54c9aSJoe Perches EXPORT_SYMBOL(atm_dev_register);
1361da177e4SLinus Torvalds 
atm_dev_deregister(struct atm_dev * dev)1371da177e4SLinus Torvalds void atm_dev_deregister(struct atm_dev *dev)
1381da177e4SLinus Torvalds {
13964bf69ddSStanislaw Gruszka 	BUG_ON(test_bit(ATM_DF_REMOVED, &dev->flags));
14064bf69ddSStanislaw Gruszka 	set_bit(ATM_DF_REMOVED, &dev->flags);
1411da177e4SLinus Torvalds 
14264bf69ddSStanislaw Gruszka 	/*
14364bf69ddSStanislaw Gruszka 	 * if we remove current device from atm_devs list, new device
14464bf69ddSStanislaw Gruszka 	 * with same number can appear, such we need deregister proc,
14564bf69ddSStanislaw Gruszka 	 * release async all vccs and remove them from vccs list too
14664bf69ddSStanislaw Gruszka 	 */
14757b47a53SIngo Molnar 	mutex_lock(&atm_dev_mutex);
1481da177e4SLinus Torvalds 	list_del(&dev->dev_list);
14957b47a53SIngo Molnar 	mutex_unlock(&atm_dev_mutex);
1501da177e4SLinus Torvalds 
15164bf69ddSStanislaw Gruszka 	atm_dev_release_vccs(dev);
152656d98b0SRoman Kagan 	atm_unregister_sysfs(dev);
15364bf69ddSStanislaw Gruszka 	atm_proc_dev_deregister(dev);
1541da177e4SLinus Torvalds 
15564bf69ddSStanislaw Gruszka 	atm_dev_put(dev);
1561da177e4SLinus Torvalds }
15707b54c9aSJoe Perches EXPORT_SYMBOL(atm_dev_deregister);
1581da177e4SLinus Torvalds 
copy_aal_stats(struct k_atm_aal_stats * from,struct atm_aal_stats * to)1591da177e4SLinus Torvalds static void copy_aal_stats(struct k_atm_aal_stats *from,
1601da177e4SLinus Torvalds     struct atm_aal_stats *to)
1611da177e4SLinus Torvalds {
1621da177e4SLinus Torvalds #define __HANDLE_ITEM(i) to->i = atomic_read(&from->i)
1631da177e4SLinus Torvalds 	__AAL_STAT_ITEMS
1641da177e4SLinus Torvalds #undef __HANDLE_ITEM
1651da177e4SLinus Torvalds }
1661da177e4SLinus Torvalds 
subtract_aal_stats(struct k_atm_aal_stats * from,struct atm_aal_stats * to)1671da177e4SLinus Torvalds static void subtract_aal_stats(struct k_atm_aal_stats *from,
1681da177e4SLinus Torvalds     struct atm_aal_stats *to)
1691da177e4SLinus Torvalds {
1701da177e4SLinus Torvalds #define __HANDLE_ITEM(i) atomic_sub(to->i, &from->i)
1711da177e4SLinus Torvalds 	__AAL_STAT_ITEMS
1721da177e4SLinus Torvalds #undef __HANDLE_ITEM
1731da177e4SLinus Torvalds }
1741da177e4SLinus Torvalds 
fetch_stats(struct atm_dev * dev,struct atm_dev_stats __user * arg,int zero)17507b54c9aSJoe Perches static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats __user *arg,
17607b54c9aSJoe Perches 		       int zero)
1771da177e4SLinus Torvalds {
1781da177e4SLinus Torvalds 	struct atm_dev_stats tmp;
1791da177e4SLinus Torvalds 	int error = 0;
1801da177e4SLinus Torvalds 
1811da177e4SLinus Torvalds 	copy_aal_stats(&dev->stats.aal0, &tmp.aal0);
1821da177e4SLinus Torvalds 	copy_aal_stats(&dev->stats.aal34, &tmp.aal34);
1831da177e4SLinus Torvalds 	copy_aal_stats(&dev->stats.aal5, &tmp.aal5);
1841da177e4SLinus Torvalds 	if (arg)
1851da177e4SLinus Torvalds 		error = copy_to_user(arg, &tmp, sizeof(tmp));
1861da177e4SLinus Torvalds 	if (zero && !error) {
1871da177e4SLinus Torvalds 		subtract_aal_stats(&dev->stats.aal0, &tmp.aal0);
1881da177e4SLinus Torvalds 		subtract_aal_stats(&dev->stats.aal34, &tmp.aal34);
1891da177e4SLinus Torvalds 		subtract_aal_stats(&dev->stats.aal5, &tmp.aal5);
1901da177e4SLinus Torvalds 	}
1911da177e4SLinus Torvalds 	return error ? -EFAULT : 0;
1921da177e4SLinus Torvalds }
1931da177e4SLinus Torvalds 
atm_getnames(void __user * buf,int __user * iobuf_len)194a3929484SAl Viro int atm_getnames(void __user *buf, int __user *iobuf_len)
1951da177e4SLinus Torvalds {
1968c2348e3SAl Viro 	int error, len, size = 0;
1971da177e4SLinus Torvalds 	struct atm_dev *dev;
1981da177e4SLinus Torvalds 	struct list_head *p;
1991da177e4SLinus Torvalds 	int *tmp_buf, *tmp_p;
2008865c418SDavid Woodhouse 
2018865c418SDavid Woodhouse 	if (get_user(len, iobuf_len))
2021da177e4SLinus Torvalds 		return -EFAULT;
20357b47a53SIngo Molnar 	mutex_lock(&atm_dev_mutex);
2041da177e4SLinus Torvalds 	list_for_each(p, &atm_devs)
2051da177e4SLinus Torvalds 		size += sizeof(int);
2061da177e4SLinus Torvalds 	if (size > len) {
20757b47a53SIngo Molnar 		mutex_unlock(&atm_dev_mutex);
2081da177e4SLinus Torvalds 		return -E2BIG;
2091da177e4SLinus Torvalds 	}
2101da177e4SLinus Torvalds 	tmp_buf = kmalloc(size, GFP_ATOMIC);
2111da177e4SLinus Torvalds 	if (!tmp_buf) {
21257b47a53SIngo Molnar 		mutex_unlock(&atm_dev_mutex);
2131da177e4SLinus Torvalds 		return -ENOMEM;
2141da177e4SLinus Torvalds 	}
2151da177e4SLinus Torvalds 	tmp_p = tmp_buf;
21673e42909SWang Hai 	list_for_each_entry(dev, &atm_devs, dev_list) {
2171da177e4SLinus Torvalds 		*tmp_p++ = dev->number;
2181da177e4SLinus Torvalds 	}
21957b47a53SIngo Molnar 	mutex_unlock(&atm_dev_mutex);
2201da177e4SLinus Torvalds 	error = ((copy_to_user(buf, tmp_buf, size)) ||
2218865c418SDavid Woodhouse 		 put_user(size, iobuf_len))
2221da177e4SLinus Torvalds 		? -EFAULT : 0;
2231da177e4SLinus Torvalds 	kfree(tmp_buf);
2241da177e4SLinus Torvalds 	return error;
2251da177e4SLinus Torvalds }
2261da177e4SLinus Torvalds 
atm_dev_ioctl(unsigned int cmd,void __user * buf,int __user * sioc_len,int number,int compat)2278cacb416SAl Viro int atm_dev_ioctl(unsigned int cmd, void __user *buf, int __user *sioc_len,
2288cacb416SAl Viro 		  int number, int compat)
2298c2348e3SAl Viro {
2308cacb416SAl Viro 	int error, len, size = 0;
2318c2348e3SAl Viro 	struct atm_dev *dev;
2328c2348e3SAl Viro 
2338cacb416SAl Viro 	if (get_user(len, sioc_len))
2348865c418SDavid Woodhouse 		return -EFAULT;
23507b54c9aSJoe Perches 
23607b54c9aSJoe Perches 	dev = try_then_request_module(atm_dev_lookup(number), "atm-device-%d",
23707b54c9aSJoe Perches 				      number);
23807b54c9aSJoe Perches 	if (!dev)
2391da177e4SLinus Torvalds 		return -ENODEV;
2401da177e4SLinus Torvalds 
2411da177e4SLinus Torvalds 	switch (cmd) {
2421da177e4SLinus Torvalds 	case ATM_GETTYPE:
2431da177e4SLinus Torvalds 		size = strlen(dev->type) + 1;
2441da177e4SLinus Torvalds 		if (copy_to_user(buf, dev->type, size)) {
2451da177e4SLinus Torvalds 			error = -EFAULT;
2461da177e4SLinus Torvalds 			goto done;
2471da177e4SLinus Torvalds 		}
2481da177e4SLinus Torvalds 		break;
2491da177e4SLinus Torvalds 	case ATM_GETESI:
2501da177e4SLinus Torvalds 		size = ESI_LEN;
2511da177e4SLinus Torvalds 		if (copy_to_user(buf, dev->esi, size)) {
2521da177e4SLinus Torvalds 			error = -EFAULT;
2531da177e4SLinus Torvalds 			goto done;
2541da177e4SLinus Torvalds 		}
2551da177e4SLinus Torvalds 		break;
2561da177e4SLinus Torvalds 	case ATM_SETESI:
2571da177e4SLinus Torvalds 	{
2581da177e4SLinus Torvalds 		int i;
2591da177e4SLinus Torvalds 
2601da177e4SLinus Torvalds 		for (i = 0; i < ESI_LEN; i++)
2611da177e4SLinus Torvalds 			if (dev->esi[i]) {
2621da177e4SLinus Torvalds 				error = -EEXIST;
2631da177e4SLinus Torvalds 				goto done;
2641da177e4SLinus Torvalds 			}
2651da177e4SLinus Torvalds 	}
266df561f66SGustavo A. R. Silva 		fallthrough;
2671da177e4SLinus Torvalds 	case ATM_SETESIF:
2681da177e4SLinus Torvalds 	{
2691da177e4SLinus Torvalds 		unsigned char esi[ESI_LEN];
2701da177e4SLinus Torvalds 
2711da177e4SLinus Torvalds 		if (!capable(CAP_NET_ADMIN)) {
2721da177e4SLinus Torvalds 			error = -EPERM;
2731da177e4SLinus Torvalds 			goto done;
2741da177e4SLinus Torvalds 		}
2751da177e4SLinus Torvalds 		if (copy_from_user(esi, buf, ESI_LEN)) {
2761da177e4SLinus Torvalds 			error = -EFAULT;
2771da177e4SLinus Torvalds 			goto done;
2781da177e4SLinus Torvalds 		}
2791da177e4SLinus Torvalds 		memcpy(dev->esi, esi, ESI_LEN);
2801da177e4SLinus Torvalds 		error =  ESI_LEN;
2811da177e4SLinus Torvalds 		goto done;
2821da177e4SLinus Torvalds 	}
2831da177e4SLinus Torvalds 	case ATM_GETSTATZ:
2841da177e4SLinus Torvalds 		if (!capable(CAP_NET_ADMIN)) {
2851da177e4SLinus Torvalds 			error = -EPERM;
2861da177e4SLinus Torvalds 			goto done;
2871da177e4SLinus Torvalds 		}
288df561f66SGustavo A. R. Silva 		fallthrough;
2891da177e4SLinus Torvalds 	case ATM_GETSTAT:
2901da177e4SLinus Torvalds 		size = sizeof(struct atm_dev_stats);
2911da177e4SLinus Torvalds 		error = fetch_stats(dev, buf, cmd == ATM_GETSTATZ);
2921da177e4SLinus Torvalds 		if (error)
2931da177e4SLinus Torvalds 			goto done;
2941da177e4SLinus Torvalds 		break;
2951da177e4SLinus Torvalds 	case ATM_GETCIRANGE:
2961da177e4SLinus Torvalds 		size = sizeof(struct atm_cirange);
2971da177e4SLinus Torvalds 		if (copy_to_user(buf, &dev->ci_range, size)) {
2981da177e4SLinus Torvalds 			error = -EFAULT;
2991da177e4SLinus Torvalds 			goto done;
3001da177e4SLinus Torvalds 		}
3011da177e4SLinus Torvalds 		break;
3021da177e4SLinus Torvalds 	case ATM_GETLINKRATE:
3031da177e4SLinus Torvalds 		size = sizeof(int);
3041da177e4SLinus Torvalds 		if (copy_to_user(buf, &dev->link_rate, size)) {
3051da177e4SLinus Torvalds 			error = -EFAULT;
3061da177e4SLinus Torvalds 			goto done;
3071da177e4SLinus Torvalds 		}
3081da177e4SLinus Torvalds 		break;
3091da177e4SLinus Torvalds 	case ATM_RSTADDR:
3101da177e4SLinus Torvalds 		if (!capable(CAP_NET_ADMIN)) {
3111da177e4SLinus Torvalds 			error = -EPERM;
3121da177e4SLinus Torvalds 			goto done;
3131da177e4SLinus Torvalds 		}
3140f21ba7cSEric Kinzie 		atm_reset_addr(dev, ATM_ADDR_LOCAL);
3151da177e4SLinus Torvalds 		break;
3161da177e4SLinus Torvalds 	case ATM_ADDADDR:
3171da177e4SLinus Torvalds 	case ATM_DELADDR:
3180f21ba7cSEric Kinzie 	case ATM_ADDLECSADDR:
3190f21ba7cSEric Kinzie 	case ATM_DELLECSADDR:
32007b54c9aSJoe Perches 	{
32107b54c9aSJoe Perches 		struct sockaddr_atmsvc addr;
32207b54c9aSJoe Perches 
3231da177e4SLinus Torvalds 		if (!capable(CAP_NET_ADMIN)) {
3241da177e4SLinus Torvalds 			error = -EPERM;
3251da177e4SLinus Torvalds 			goto done;
3261da177e4SLinus Torvalds 		}
3271da177e4SLinus Torvalds 
3281da177e4SLinus Torvalds 		if (copy_from_user(&addr, buf, sizeof(addr))) {
3291da177e4SLinus Torvalds 			error = -EFAULT;
3301da177e4SLinus Torvalds 			goto done;
3311da177e4SLinus Torvalds 		}
3320f21ba7cSEric Kinzie 		if (cmd == ATM_ADDADDR || cmd == ATM_ADDLECSADDR)
3330f21ba7cSEric Kinzie 			error = atm_add_addr(dev, &addr,
3340f21ba7cSEric Kinzie 					     (cmd == ATM_ADDADDR ?
3350f21ba7cSEric Kinzie 					      ATM_ADDR_LOCAL : ATM_ADDR_LECS));
3361da177e4SLinus Torvalds 		else
3370f21ba7cSEric Kinzie 			error = atm_del_addr(dev, &addr,
3380f21ba7cSEric Kinzie 					     (cmd == ATM_DELADDR ?
3390f21ba7cSEric Kinzie 					      ATM_ADDR_LOCAL : ATM_ADDR_LECS));
3401da177e4SLinus Torvalds 		goto done;
3411da177e4SLinus Torvalds 	}
3421da177e4SLinus Torvalds 	case ATM_GETADDR:
3430f21ba7cSEric Kinzie 	case ATM_GETLECSADDR:
3440f21ba7cSEric Kinzie 		error = atm_get_addr(dev, buf, len,
3450f21ba7cSEric Kinzie 				     (cmd == ATM_GETADDR ?
3460f21ba7cSEric Kinzie 				      ATM_ADDR_LOCAL : ATM_ADDR_LECS));
3471da177e4SLinus Torvalds 		if (error < 0)
3481da177e4SLinus Torvalds 			goto done;
3491da177e4SLinus Torvalds 		size = error;
3501da177e4SLinus Torvalds 		/* may return 0, but later on size == 0 means "don't
3511da177e4SLinus Torvalds 		   write the length" */
35207b54c9aSJoe Perches 		error = put_user(size, sioc_len) ? -EFAULT : 0;
3531da177e4SLinus Torvalds 		goto done;
3541da177e4SLinus Torvalds 	case ATM_SETLOOP:
3551da177e4SLinus Torvalds 		if (__ATM_LM_XTRMT((int) (unsigned long) buf) &&
3561da177e4SLinus Torvalds 		    __ATM_LM_XTLOC((int) (unsigned long) buf) >
3571da177e4SLinus Torvalds 		    __ATM_LM_XTRMT((int) (unsigned long) buf)) {
3581da177e4SLinus Torvalds 			error = -EINVAL;
3591da177e4SLinus Torvalds 			goto done;
3601da177e4SLinus Torvalds 		}
361df561f66SGustavo A. R. Silva 		fallthrough;
3621da177e4SLinus Torvalds 	case ATM_SETCIRANGE:
3631da177e4SLinus Torvalds 	case SONET_GETSTATZ:
3641da177e4SLinus Torvalds 	case SONET_SETDIAG:
3651da177e4SLinus Torvalds 	case SONET_CLRDIAG:
3661da177e4SLinus Torvalds 	case SONET_SETFRAMING:
3671da177e4SLinus Torvalds 		if (!capable(CAP_NET_ADMIN)) {
3681da177e4SLinus Torvalds 			error = -EPERM;
3691da177e4SLinus Torvalds 			goto done;
3701da177e4SLinus Torvalds 		}
371df561f66SGustavo A. R. Silva 		fallthrough;
3721da177e4SLinus Torvalds 	default:
3730805a4b8SNathan Chancellor 		if (IS_ENABLED(CONFIG_COMPAT) && compat) {
3748865c418SDavid Woodhouse #ifdef CONFIG_COMPAT
3758865c418SDavid Woodhouse 			if (!dev->ops->compat_ioctl) {
3768865c418SDavid Woodhouse 				error = -EINVAL;
3778865c418SDavid Woodhouse 				goto done;
3788865c418SDavid Woodhouse 			}
3798865c418SDavid Woodhouse 			size = dev->ops->compat_ioctl(dev, cmd, buf);
3808865c418SDavid Woodhouse #endif
3818865c418SDavid Woodhouse 		} else {
3821da177e4SLinus Torvalds 			if (!dev->ops->ioctl) {
3831da177e4SLinus Torvalds 				error = -EINVAL;
3841da177e4SLinus Torvalds 				goto done;
3851da177e4SLinus Torvalds 			}
3861da177e4SLinus Torvalds 			size = dev->ops->ioctl(dev, cmd, buf);
3878865c418SDavid Woodhouse 		}
3881da177e4SLinus Torvalds 		if (size < 0) {
3894a2c2406SWanlong Gao 			error = (size == -ENOIOCTLCMD ? -ENOTTY : size);
3901da177e4SLinus Torvalds 			goto done;
3911da177e4SLinus Torvalds 		}
3921da177e4SLinus Torvalds 	}
3931da177e4SLinus Torvalds 
3941da177e4SLinus Torvalds 	if (size)
39507b54c9aSJoe Perches 		error = put_user(size, sioc_len) ? -EFAULT : 0;
3961da177e4SLinus Torvalds 	else
3971da177e4SLinus Torvalds 		error = 0;
3981da177e4SLinus Torvalds done:
3991da177e4SLinus Torvalds 	atm_dev_put(dev);
4001da177e4SLinus Torvalds 	return error;
4011da177e4SLinus Torvalds }
4021da177e4SLinus Torvalds 
403*fb1b7be9SArnd Bergmann #ifdef CONFIG_PROC_FS
atm_dev_seq_start(struct seq_file * seq,loff_t * pos)4041da177e4SLinus Torvalds void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos)
4051da177e4SLinus Torvalds {
40657b47a53SIngo Molnar 	mutex_lock(&atm_dev_mutex);
40767de7924SLi Zefan 	return seq_list_start_head(&atm_devs, *pos);
4081da177e4SLinus Torvalds }
4091da177e4SLinus Torvalds 
atm_dev_seq_stop(struct seq_file * seq,void * v)4101da177e4SLinus Torvalds void atm_dev_seq_stop(struct seq_file *seq, void *v)
4111da177e4SLinus Torvalds {
41257b47a53SIngo Molnar 	mutex_unlock(&atm_dev_mutex);
4131da177e4SLinus Torvalds }
4141da177e4SLinus Torvalds 
atm_dev_seq_next(struct seq_file * seq,void * v,loff_t * pos)4151da177e4SLinus Torvalds void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
4161da177e4SLinus Torvalds {
41767de7924SLi Zefan 	return seq_list_next(v, &atm_devs, pos);
4181da177e4SLinus Torvalds }
419*fb1b7be9SArnd Bergmann #endif
420