Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/atm/ioctl.c
15109 views
1
/* ATM ioctl handling */
2
3
/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
4
/* 2003 John Levon <[email protected]> */
5
6
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
7
8
#include <linux/module.h>
9
#include <linux/kmod.h>
10
#include <linux/net.h> /* struct socket, struct proto_ops */
11
#include <linux/atm.h> /* ATM stuff */
12
#include <linux/atmdev.h>
13
#include <linux/atmclip.h> /* CLIP_*ENCAP */
14
#include <linux/atmarp.h> /* manifest constants */
15
#include <linux/capability.h>
16
#include <linux/sonet.h> /* for ioctls */
17
#include <linux/atmsvc.h>
18
#include <linux/atmmpc.h>
19
#include <net/atmclip.h>
20
#include <linux/atmlec.h>
21
#include <linux/mutex.h>
22
#include <asm/ioctls.h>
23
#include <net/compat.h>
24
25
#include "resources.h"
26
#include "signaling.h" /* for WAITING and sigd_attach */
27
#include "common.h"
28
29
30
static DEFINE_MUTEX(ioctl_mutex);
31
static LIST_HEAD(ioctl_list);
32
33
34
void register_atm_ioctl(struct atm_ioctl *ioctl)
35
{
36
mutex_lock(&ioctl_mutex);
37
list_add_tail(&ioctl->list, &ioctl_list);
38
mutex_unlock(&ioctl_mutex);
39
}
40
EXPORT_SYMBOL(register_atm_ioctl);
41
42
void deregister_atm_ioctl(struct atm_ioctl *ioctl)
43
{
44
mutex_lock(&ioctl_mutex);
45
list_del(&ioctl->list);
46
mutex_unlock(&ioctl_mutex);
47
}
48
EXPORT_SYMBOL(deregister_atm_ioctl);
49
50
static int do_vcc_ioctl(struct socket *sock, unsigned int cmd,
51
unsigned long arg, int compat)
52
{
53
struct sock *sk = sock->sk;
54
struct atm_vcc *vcc;
55
int error;
56
struct list_head *pos;
57
void __user *argp = (void __user *)arg;
58
59
vcc = ATM_SD(sock);
60
switch (cmd) {
61
case SIOCOUTQ:
62
if (sock->state != SS_CONNECTED ||
63
!test_bit(ATM_VF_READY, &vcc->flags)) {
64
error = -EINVAL;
65
goto done;
66
}
67
error = put_user(sk->sk_sndbuf - sk_wmem_alloc_get(sk),
68
(int __user *)argp) ? -EFAULT : 0;
69
goto done;
70
case SIOCINQ:
71
{
72
struct sk_buff *skb;
73
74
if (sock->state != SS_CONNECTED) {
75
error = -EINVAL;
76
goto done;
77
}
78
skb = skb_peek(&sk->sk_receive_queue);
79
error = put_user(skb ? skb->len : 0,
80
(int __user *)argp) ? -EFAULT : 0;
81
goto done;
82
}
83
case SIOCGSTAMP: /* borrowed from IP */
84
#ifdef CONFIG_COMPAT
85
if (compat)
86
error = compat_sock_get_timestamp(sk, argp);
87
else
88
#endif
89
error = sock_get_timestamp(sk, argp);
90
goto done;
91
case SIOCGSTAMPNS: /* borrowed from IP */
92
#ifdef CONFIG_COMPAT
93
if (compat)
94
error = compat_sock_get_timestampns(sk, argp);
95
else
96
#endif
97
error = sock_get_timestampns(sk, argp);
98
goto done;
99
case ATM_SETSC:
100
if (net_ratelimit())
101
pr_warning("ATM_SETSC is obsolete; used by %s:%d\n",
102
current->comm, task_pid_nr(current));
103
error = 0;
104
goto done;
105
case ATMSIGD_CTRL:
106
if (!capable(CAP_NET_ADMIN)) {
107
error = -EPERM;
108
goto done;
109
}
110
/*
111
* The user/kernel protocol for exchanging signalling
112
* info uses kernel pointers as opaque references,
113
* so the holder of the file descriptor can scribble
114
* on the kernel... so we should make sure that we
115
* have the same privileges that /proc/kcore needs
116
*/
117
if (!capable(CAP_SYS_RAWIO)) {
118
error = -EPERM;
119
goto done;
120
}
121
#ifdef CONFIG_COMPAT
122
/* WTF? I don't even want to _think_ about making this
123
work for 32-bit userspace. TBH I don't really want
124
to think about it at all. dwmw2. */
125
if (compat) {
126
if (net_ratelimit())
127
pr_warning("32-bit task cannot be atmsigd\n");
128
error = -EINVAL;
129
goto done;
130
}
131
#endif
132
error = sigd_attach(vcc);
133
if (!error)
134
sock->state = SS_CONNECTED;
135
goto done;
136
case ATM_SETBACKEND:
137
case ATM_NEWBACKENDIF:
138
{
139
atm_backend_t backend;
140
error = get_user(backend, (atm_backend_t __user *)argp);
141
if (error)
142
goto done;
143
switch (backend) {
144
case ATM_BACKEND_PPP:
145
request_module("pppoatm");
146
break;
147
case ATM_BACKEND_BR2684:
148
request_module("br2684");
149
break;
150
}
151
break;
152
}
153
case ATMMPC_CTRL:
154
case ATMMPC_DATA:
155
request_module("mpoa");
156
break;
157
case ATMARPD_CTRL:
158
request_module("clip");
159
break;
160
case ATMLEC_CTRL:
161
request_module("lec");
162
break;
163
}
164
165
error = -ENOIOCTLCMD;
166
167
mutex_lock(&ioctl_mutex);
168
list_for_each(pos, &ioctl_list) {
169
struct atm_ioctl *ic = list_entry(pos, struct atm_ioctl, list);
170
if (try_module_get(ic->owner)) {
171
error = ic->ioctl(sock, cmd, arg);
172
module_put(ic->owner);
173
if (error != -ENOIOCTLCMD)
174
break;
175
}
176
}
177
mutex_unlock(&ioctl_mutex);
178
179
if (error != -ENOIOCTLCMD)
180
goto done;
181
182
error = atm_dev_ioctl(cmd, argp, compat);
183
184
done:
185
return error;
186
}
187
188
int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
189
{
190
return do_vcc_ioctl(sock, cmd, arg, 0);
191
}
192
193
#ifdef CONFIG_COMPAT
194
/*
195
* FIXME:
196
* The compat_ioctl handling is duplicated, using both these conversion
197
* routines and the compat argument to the actual handlers. Both
198
* versions are somewhat incomplete and should be merged, e.g. by
199
* moving the ioctl number translation into the actual handlers and
200
* killing the conversion code.
201
*
202
* -arnd, November 2009
203
*/
204
#define ATM_GETLINKRATE32 _IOW('a', ATMIOC_ITF+1, struct compat_atmif_sioc)
205
#define ATM_GETNAMES32 _IOW('a', ATMIOC_ITF+3, struct compat_atm_iobuf)
206
#define ATM_GETTYPE32 _IOW('a', ATMIOC_ITF+4, struct compat_atmif_sioc)
207
#define ATM_GETESI32 _IOW('a', ATMIOC_ITF+5, struct compat_atmif_sioc)
208
#define ATM_GETADDR32 _IOW('a', ATMIOC_ITF+6, struct compat_atmif_sioc)
209
#define ATM_RSTADDR32 _IOW('a', ATMIOC_ITF+7, struct compat_atmif_sioc)
210
#define ATM_ADDADDR32 _IOW('a', ATMIOC_ITF+8, struct compat_atmif_sioc)
211
#define ATM_DELADDR32 _IOW('a', ATMIOC_ITF+9, struct compat_atmif_sioc)
212
#define ATM_GETCIRANGE32 _IOW('a', ATMIOC_ITF+10, struct compat_atmif_sioc)
213
#define ATM_SETCIRANGE32 _IOW('a', ATMIOC_ITF+11, struct compat_atmif_sioc)
214
#define ATM_SETESI32 _IOW('a', ATMIOC_ITF+12, struct compat_atmif_sioc)
215
#define ATM_SETESIF32 _IOW('a', ATMIOC_ITF+13, struct compat_atmif_sioc)
216
#define ATM_GETSTAT32 _IOW('a', ATMIOC_SARCOM+0, struct compat_atmif_sioc)
217
#define ATM_GETSTATZ32 _IOW('a', ATMIOC_SARCOM+1, struct compat_atmif_sioc)
218
#define ATM_GETLOOP32 _IOW('a', ATMIOC_SARCOM+2, struct compat_atmif_sioc)
219
#define ATM_SETLOOP32 _IOW('a', ATMIOC_SARCOM+3, struct compat_atmif_sioc)
220
#define ATM_QUERYLOOP32 _IOW('a', ATMIOC_SARCOM+4, struct compat_atmif_sioc)
221
222
static struct {
223
unsigned int cmd32;
224
unsigned int cmd;
225
} atm_ioctl_map[] = {
226
{ ATM_GETLINKRATE32, ATM_GETLINKRATE },
227
{ ATM_GETNAMES32, ATM_GETNAMES },
228
{ ATM_GETTYPE32, ATM_GETTYPE },
229
{ ATM_GETESI32, ATM_GETESI },
230
{ ATM_GETADDR32, ATM_GETADDR },
231
{ ATM_RSTADDR32, ATM_RSTADDR },
232
{ ATM_ADDADDR32, ATM_ADDADDR },
233
{ ATM_DELADDR32, ATM_DELADDR },
234
{ ATM_GETCIRANGE32, ATM_GETCIRANGE },
235
{ ATM_SETCIRANGE32, ATM_SETCIRANGE },
236
{ ATM_SETESI32, ATM_SETESI },
237
{ ATM_SETESIF32, ATM_SETESIF },
238
{ ATM_GETSTAT32, ATM_GETSTAT },
239
{ ATM_GETSTATZ32, ATM_GETSTATZ },
240
{ ATM_GETLOOP32, ATM_GETLOOP },
241
{ ATM_SETLOOP32, ATM_SETLOOP },
242
{ ATM_QUERYLOOP32, ATM_QUERYLOOP },
243
};
244
245
#define NR_ATM_IOCTL ARRAY_SIZE(atm_ioctl_map)
246
247
static int do_atm_iobuf(struct socket *sock, unsigned int cmd,
248
unsigned long arg)
249
{
250
struct atm_iobuf __user *iobuf;
251
struct compat_atm_iobuf __user *iobuf32;
252
u32 data;
253
void __user *datap;
254
int len, err;
255
256
iobuf = compat_alloc_user_space(sizeof(*iobuf));
257
iobuf32 = compat_ptr(arg);
258
259
if (get_user(len, &iobuf32->length) ||
260
get_user(data, &iobuf32->buffer))
261
return -EFAULT;
262
datap = compat_ptr(data);
263
if (put_user(len, &iobuf->length) ||
264
put_user(datap, &iobuf->buffer))
265
return -EFAULT;
266
267
err = do_vcc_ioctl(sock, cmd, (unsigned long) iobuf, 0);
268
269
if (!err) {
270
if (copy_in_user(&iobuf32->length, &iobuf->length,
271
sizeof(int)))
272
err = -EFAULT;
273
}
274
275
return err;
276
}
277
278
static int do_atmif_sioc(struct socket *sock, unsigned int cmd,
279
unsigned long arg)
280
{
281
struct atmif_sioc __user *sioc;
282
struct compat_atmif_sioc __user *sioc32;
283
u32 data;
284
void __user *datap;
285
int err;
286
287
sioc = compat_alloc_user_space(sizeof(*sioc));
288
sioc32 = compat_ptr(arg);
289
290
if (copy_in_user(&sioc->number, &sioc32->number, 2 * sizeof(int)) ||
291
get_user(data, &sioc32->arg))
292
return -EFAULT;
293
datap = compat_ptr(data);
294
if (put_user(datap, &sioc->arg))
295
return -EFAULT;
296
297
err = do_vcc_ioctl(sock, cmd, (unsigned long) sioc, 0);
298
299
if (!err) {
300
if (copy_in_user(&sioc32->length, &sioc->length,
301
sizeof(int)))
302
err = -EFAULT;
303
}
304
return err;
305
}
306
307
static int do_atm_ioctl(struct socket *sock, unsigned int cmd32,
308
unsigned long arg)
309
{
310
int i;
311
unsigned int cmd = 0;
312
313
switch (cmd32) {
314
case SONET_GETSTAT:
315
case SONET_GETSTATZ:
316
case SONET_GETDIAG:
317
case SONET_SETDIAG:
318
case SONET_CLRDIAG:
319
case SONET_SETFRAMING:
320
case SONET_GETFRAMING:
321
case SONET_GETFRSENSE:
322
return do_atmif_sioc(sock, cmd32, arg);
323
}
324
325
for (i = 0; i < NR_ATM_IOCTL; i++) {
326
if (cmd32 == atm_ioctl_map[i].cmd32) {
327
cmd = atm_ioctl_map[i].cmd;
328
break;
329
}
330
}
331
if (i == NR_ATM_IOCTL)
332
return -EINVAL;
333
334
switch (cmd) {
335
case ATM_GETNAMES:
336
return do_atm_iobuf(sock, cmd, arg);
337
338
case ATM_GETLINKRATE:
339
case ATM_GETTYPE:
340
case ATM_GETESI:
341
case ATM_GETADDR:
342
case ATM_RSTADDR:
343
case ATM_ADDADDR:
344
case ATM_DELADDR:
345
case ATM_GETCIRANGE:
346
case ATM_SETCIRANGE:
347
case ATM_SETESI:
348
case ATM_SETESIF:
349
case ATM_GETSTAT:
350
case ATM_GETSTATZ:
351
case ATM_GETLOOP:
352
case ATM_SETLOOP:
353
case ATM_QUERYLOOP:
354
return do_atmif_sioc(sock, cmd, arg);
355
}
356
357
return -EINVAL;
358
}
359
360
int vcc_compat_ioctl(struct socket *sock, unsigned int cmd,
361
unsigned long arg)
362
{
363
int ret;
364
365
ret = do_vcc_ioctl(sock, cmd, arg, 1);
366
if (ret != -ENOIOCTLCMD)
367
return ret;
368
369
return do_atm_ioctl(sock, cmd, arg);
370
}
371
#endif
372
373