xref: /linux/net/atm/ioctl.c (revision 8f9616500c59bb85a06a9d1c52e59d1bf4a194c2)
1 // SPDX-License-Identifier: GPL-2.0
2 /* ATM ioctl handling */
3 
4 /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
5 /* 2003 John Levon  <levon@movementarian.org> */
6 
7 #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
8 
9 #include <linux/module.h>
10 #include <linux/kmod.h>
11 #include <linux/net.h>		/* struct socket, struct proto_ops */
12 #include <linux/atm.h>		/* ATM stuff */
13 #include <linux/atmdev.h>
14 #include <linux/capability.h>
15 #include <linux/mutex.h>
16 #include <asm/ioctls.h>
17 #include <net/compat.h>
18 
19 #include "resources.h"
20 #include "common.h"
21 
22 
23 static DEFINE_MUTEX(ioctl_mutex);
24 static LIST_HEAD(ioctl_list);
25 
26 
27 void register_atm_ioctl(struct atm_ioctl *ioctl)
28 {
29 	mutex_lock(&ioctl_mutex);
30 	list_add_tail(&ioctl->list, &ioctl_list);
31 	mutex_unlock(&ioctl_mutex);
32 }
33 EXPORT_SYMBOL(register_atm_ioctl);
34 
35 void deregister_atm_ioctl(struct atm_ioctl *ioctl)
36 {
37 	mutex_lock(&ioctl_mutex);
38 	list_del(&ioctl->list);
39 	mutex_unlock(&ioctl_mutex);
40 }
41 EXPORT_SYMBOL(deregister_atm_ioctl);
42 
43 static int do_vcc_ioctl(struct socket *sock, unsigned int cmd,
44 			unsigned long arg, int compat)
45 {
46 	struct sock *sk = sock->sk;
47 	struct atm_vcc *vcc;
48 	int error;
49 	struct list_head *pos;
50 	void __user *argp = (void __user *)arg;
51 	void __user *buf;
52 	int __user *len;
53 
54 	vcc = ATM_SD(sock);
55 	switch (cmd) {
56 	case SIOCOUTQ:
57 		if (sock->state != SS_CONNECTED ||
58 		    !test_bit(ATM_VF_READY, &vcc->flags)) {
59 			error =  -EINVAL;
60 			goto done;
61 		}
62 		error = put_user(sk->sk_sndbuf - sk_wmem_alloc_get(sk),
63 				 (int __user *)argp);
64 		goto done;
65 	case SIOCINQ:
66 	{
67 		struct sk_buff *skb;
68 		int amount;
69 
70 		if (sock->state != SS_CONNECTED) {
71 			error = -EINVAL;
72 			goto done;
73 		}
74 		spin_lock_irq(&sk->sk_receive_queue.lock);
75 		skb = skb_peek(&sk->sk_receive_queue);
76 		amount = skb ? skb->len : 0;
77 		spin_unlock_irq(&sk->sk_receive_queue.lock);
78 		error = put_user(amount, (int __user *)argp);
79 		goto done;
80 	}
81 	case ATM_SETSC:
82 		net_warn_ratelimited("ATM_SETSC is obsolete; used by %s:%d\n",
83 				     current->comm, task_pid_nr(current));
84 		error = 0;
85 		goto done;
86 	case ATM_SETBACKEND:
87 	case ATM_NEWBACKENDIF:
88 	{
89 		atm_backend_t backend;
90 		error = get_user(backend, (atm_backend_t __user *)argp);
91 		if (error)
92 			goto done;
93 		switch (backend) {
94 		case ATM_BACKEND_PPP:
95 			request_module("pppoatm");
96 			break;
97 		case ATM_BACKEND_BR2684:
98 			request_module("br2684");
99 			break;
100 		}
101 		break;
102 	}
103 	}
104 
105 	error = -ENOIOCTLCMD;
106 
107 	mutex_lock(&ioctl_mutex);
108 	list_for_each(pos, &ioctl_list) {
109 		struct atm_ioctl *ic = list_entry(pos, struct atm_ioctl, list);
110 		if (try_module_get(ic->owner)) {
111 			error = ic->ioctl(sock, cmd, arg);
112 			module_put(ic->owner);
113 			if (error != -ENOIOCTLCMD)
114 				break;
115 		}
116 	}
117 	mutex_unlock(&ioctl_mutex);
118 
119 	if (error != -ENOIOCTLCMD)
120 		goto done;
121 
122 	if (cmd == ATM_GETNAMES) {
123 		if (IS_ENABLED(CONFIG_COMPAT) && compat) {
124 #ifdef CONFIG_COMPAT
125 			struct compat_atm_iobuf __user *ciobuf = argp;
126 			compat_uptr_t cbuf;
127 			len = &ciobuf->length;
128 			if (get_user(cbuf, &ciobuf->buffer))
129 				return -EFAULT;
130 			buf = compat_ptr(cbuf);
131 #endif
132 		} else {
133 			struct atm_iobuf __user *iobuf = argp;
134 			len = &iobuf->length;
135 			if (get_user(buf, &iobuf->buffer))
136 				return -EFAULT;
137 		}
138 		error = atm_getnames(buf, len);
139 	} else {
140 		int number;
141 
142 		if (IS_ENABLED(CONFIG_COMPAT) && compat) {
143 #ifdef CONFIG_COMPAT
144 			struct compat_atmif_sioc __user *csioc = argp;
145 			compat_uptr_t carg;
146 
147 			len = &csioc->length;
148 			if (get_user(carg, &csioc->arg))
149 				return -EFAULT;
150 			buf = compat_ptr(carg);
151 			if (get_user(number, &csioc->number))
152 				return -EFAULT;
153 #endif
154 		} else {
155 			struct atmif_sioc __user *sioc = argp;
156 
157 			len = &sioc->length;
158 			if (get_user(buf, &sioc->arg))
159 				return -EFAULT;
160 			if (get_user(number, &sioc->number))
161 				return -EFAULT;
162 		}
163 		error = atm_dev_ioctl(cmd, buf, len, number, compat);
164 	}
165 
166 done:
167 	return error;
168 }
169 
170 int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
171 {
172 	return do_vcc_ioctl(sock, cmd, arg, 0);
173 }
174 
175 #ifdef CONFIG_COMPAT
176 /*
177  * FIXME:
178  * The compat_ioctl handling is duplicated, using both these conversion
179  * routines and the compat argument to the actual handlers. Both
180  * versions are somewhat incomplete and should be merged, e.g. by
181  * moving the ioctl number translation into the actual handlers and
182  * killing the conversion code.
183  *
184  * -arnd, November 2009
185  */
186 #define ATM_GETLINKRATE32 _IOW('a', ATMIOC_ITF+1, struct compat_atmif_sioc)
187 #define ATM_GETNAMES32    _IOW('a', ATMIOC_ITF+3, struct compat_atm_iobuf)
188 #define ATM_GETTYPE32     _IOW('a', ATMIOC_ITF+4, struct compat_atmif_sioc)
189 #define ATM_GETESI32	  _IOW('a', ATMIOC_ITF+5, struct compat_atmif_sioc)
190 #define ATM_GETCIRANGE32  _IOW('a', ATMIOC_ITF+10, struct compat_atmif_sioc)
191 #define ATM_SETCIRANGE32  _IOW('a', ATMIOC_ITF+11, struct compat_atmif_sioc)
192 #define ATM_SETESI32      _IOW('a', ATMIOC_ITF+12, struct compat_atmif_sioc)
193 #define ATM_SETESIF32     _IOW('a', ATMIOC_ITF+13, struct compat_atmif_sioc)
194 #define ATM_GETSTAT32     _IOW('a', ATMIOC_SARCOM+0, struct compat_atmif_sioc)
195 #define ATM_GETSTATZ32    _IOW('a', ATMIOC_SARCOM+1, struct compat_atmif_sioc)
196 #define ATM_GETLOOP32	  _IOW('a', ATMIOC_SARCOM+2, struct compat_atmif_sioc)
197 #define ATM_SETLOOP32	  _IOW('a', ATMIOC_SARCOM+3, struct compat_atmif_sioc)
198 #define ATM_QUERYLOOP32	  _IOW('a', ATMIOC_SARCOM+4, struct compat_atmif_sioc)
199 
200 static struct {
201 	unsigned int cmd32;
202 	unsigned int cmd;
203 } atm_ioctl_map[] = {
204 	{ ATM_GETLINKRATE32, ATM_GETLINKRATE },
205 	{ ATM_GETNAMES32,    ATM_GETNAMES },
206 	{ ATM_GETTYPE32,     ATM_GETTYPE },
207 	{ ATM_GETESI32,	     ATM_GETESI },
208 	{ ATM_GETCIRANGE32,  ATM_GETCIRANGE },
209 	{ ATM_SETCIRANGE32,  ATM_SETCIRANGE },
210 	{ ATM_SETESI32,	     ATM_SETESI },
211 	{ ATM_SETESIF32,     ATM_SETESIF },
212 	{ ATM_GETSTAT32,     ATM_GETSTAT },
213 	{ ATM_GETSTATZ32,    ATM_GETSTATZ },
214 	{ ATM_GETLOOP32,     ATM_GETLOOP },
215 	{ ATM_SETLOOP32,     ATM_SETLOOP },
216 	{ ATM_QUERYLOOP32,   ATM_QUERYLOOP },
217 };
218 
219 #define NR_ATM_IOCTL ARRAY_SIZE(atm_ioctl_map)
220 
221 static int do_atm_iobuf(struct socket *sock, unsigned int cmd,
222 			unsigned long arg)
223 {
224 	struct compat_atm_iobuf __user *iobuf32 = compat_ptr(arg);
225 	u32 data;
226 
227 	if (get_user(data, &iobuf32->buffer))
228 		return -EFAULT;
229 
230 	return atm_getnames(&iobuf32->length, compat_ptr(data));
231 }
232 
233 static int do_atmif_sioc(struct socket *sock, unsigned int cmd,
234 			 unsigned long arg)
235 {
236 	struct compat_atmif_sioc __user *sioc32 = compat_ptr(arg);
237 	int number;
238 	u32 data;
239 
240 	if (get_user(data, &sioc32->arg) || get_user(number, &sioc32->number))
241 		return -EFAULT;
242 	return atm_dev_ioctl(cmd, compat_ptr(data), &sioc32->length, number, 0);
243 }
244 
245 static int do_atm_ioctl(struct socket *sock, unsigned int cmd32,
246 			unsigned long arg)
247 {
248 	int i;
249 	unsigned int cmd = 0;
250 
251 	for (i = 0; i < NR_ATM_IOCTL; i++) {
252 		if (cmd32 == atm_ioctl_map[i].cmd32) {
253 			cmd = atm_ioctl_map[i].cmd;
254 			break;
255 		}
256 	}
257 	if (i == NR_ATM_IOCTL)
258 		return -EINVAL;
259 
260 	switch (cmd) {
261 	case ATM_GETNAMES:
262 		return do_atm_iobuf(sock, cmd, arg);
263 
264 	case ATM_GETLINKRATE:
265 	case ATM_GETTYPE:
266 	case ATM_GETESI:
267 	case ATM_GETCIRANGE:
268 	case ATM_SETCIRANGE:
269 	case ATM_SETESI:
270 	case ATM_SETESIF:
271 	case ATM_GETSTAT:
272 	case ATM_GETSTATZ:
273 	case ATM_GETLOOP:
274 	case ATM_SETLOOP:
275 	case ATM_QUERYLOOP:
276 		return do_atmif_sioc(sock, cmd, arg);
277 	}
278 
279 	return -EINVAL;
280 }
281 
282 int vcc_compat_ioctl(struct socket *sock, unsigned int cmd,
283 		     unsigned long arg)
284 {
285 	int ret;
286 
287 	ret = do_vcc_ioctl(sock, cmd, arg, 1);
288 	if (ret != -ENOIOCTLCMD)
289 		return ret;
290 
291 	return do_atm_ioctl(sock, cmd, arg);
292 }
293 #endif
294