projects/linux·blob master · refs

293 lines · 7.3 KiB

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 <[email protected]> */
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
23static DEFINE_MUTEX(ioctl_mutex);
24static LIST_HEAD(ioctl_list);
25
26
27void 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}
33EXPORT_SYMBOL(register_atm_ioctl);
34
35void deregister_atm_ioctl(struct atm_ioctl *ioctl)
36{
37 mutex_lock(&ioctl_mutex);
38 list_del(&ioctl->list);
39 mutex_unlock(&ioctl_mutex);
40}
41EXPORT_SYMBOL(deregister_atm_ioctl);
42
43static 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
166done:
167 return error;
168}
169
170int 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
200static 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
221static 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
233static 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
245static 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
282int 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