Blame view

net/atm/svc.c 16 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
  /* net/atm/svc.c - ATM SVC sockets */
  
  /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
99824461e   Joe Perches   net/atm: Convert ...
5
  #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
8
9
10
11
12
  
  #include <linux/string.h>
  #include <linux/net.h>		/* struct socket, struct proto_ops */
  #include <linux/errno.h>	/* error codes */
  #include <linux/kernel.h>	/* printk */
  #include <linux/skbuff.h>
  #include <linux/wait.h>
174cd4b1e   Ingo Molnar   sched/headers: Pr...
13
  #include <linux/sched/signal.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
16
17
18
19
20
21
  #include <linux/fcntl.h>	/* O_NONBLOCK */
  #include <linux/init.h>
  #include <linux/atm.h>		/* ATM stuff */
  #include <linux/atmsap.h>
  #include <linux/atmsvc.h>
  #include <linux/atmdev.h>
  #include <linux/bitops.h>
  #include <net/sock.h>		/* for sock_no_* */
b7d9371be   Joe Perches   net/atm/svc.c: ch...
22
  #include <linux/uaccess.h>
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
23
  #include <linux/export.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
28
  
  #include "resources.h"
  #include "common.h"		/* common for PVCs and SVCs */
  #include "signaling.h"
  #include "addr.h"
b7d9371be   Joe Perches   net/atm/svc.c: ch...
29
30
  static int svc_create(struct net *net, struct socket *sock, int protocol,
  		      int kern);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
34
35
36
  /*
   * Note: since all this is still nicely synchronized with the signaling demon,
   *       there's no need to protect sleep loops with clis. If signaling is
   *       moved into the kernel, that would change.
   */
b7d9371be   Joe Perches   net/atm/svc.c: ch...
37
  static int svc_shutdown(struct socket *sock, int how)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
  {
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
44
45
  static void svc_disconnect(struct atm_vcc *vcc)
  {
  	DEFINE_WAIT(wait);
  	struct sk_buff *skb;
  	struct sock *sk = sk_atm(vcc);
b7d9371be   Joe Perches   net/atm/svc.c: ch...
46
47
48
  	pr_debug("%p
  ", vcc);
  	if (test_bit(ATM_VF_REGIS, &vcc->flags)) {
b7d9371be   Joe Perches   net/atm/svc.c: ch...
49
  		sigd_enq(vcc, as_close, NULL, NULL, NULL);
de713b579   chas williams - CONTRACTOR   atm/svc: Fix bloc...
50
51
52
53
  		for (;;) {
  			prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
  			if (test_bit(ATM_VF_RELEASED, &vcc->flags) || !sigd)
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
  			schedule();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
  		}
aa3951451   Eric Dumazet   net: sk_sleep() h...
56
  		finish_wait(sk_sleep(sk), &wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
60
61
  	}
  	/* beware - socket is still in use by atmsigd until the last
  	   as_indicate has been answered */
  	while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
  		atm_return(vcc, skb->truesize);
522400623   Stephen Hemminger   [ATM]: Replace DP...
62
63
  		pr_debug("LISTEN REL
  ");
b7d9371be   Joe Perches   net/atm/svc.c: ch...
64
  		sigd_enq2(NULL, as_reject, vcc, NULL, NULL, &vcc->qos, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
66
67
68
69
  		dev_kfree_skb(skb);
  	}
  	clear_bit(ATM_VF_REGIS, &vcc->flags);
  	/* ... may retry later */
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
72
73
  static int svc_release(struct socket *sock)
  {
  	struct sock *sk = sock->sk;
  	struct atm_vcc *vcc;
b7d9371be   Joe Perches   net/atm/svc.c: ch...
74
  	if (sk) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
  		vcc = ATM_SD(sock);
99824461e   Joe Perches   net/atm: Convert ...
76
77
  		pr_debug("%p
  ", vcc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
  		clear_bit(ATM_VF_READY, &vcc->flags);
b7d9371be   Joe Perches   net/atm/svc.c: ch...
79
80
81
82
83
  		/*
  		 * VCC pointer is used as a reference,
  		 * so we must not free it (thereby subjecting it to re-use)
  		 * before all pending connections are closed
  		 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
85
86
87
88
  		svc_disconnect(vcc);
  		vcc_release(sock);
  	}
  	return 0;
  }
b7d9371be   Joe Perches   net/atm/svc.c: ch...
89
90
  static int svc_bind(struct socket *sock, struct sockaddr *sockaddr,
  		    int sockaddr_len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
  {
  	DEFINE_WAIT(wait);
  	struct sock *sk = sock->sk;
  	struct sockaddr_atmsvc *addr;
  	struct atm_vcc *vcc;
  	int error;
  
  	if (sockaddr_len != sizeof(struct sockaddr_atmsvc))
  		return -EINVAL;
  	lock_sock(sk);
  	if (sock->state == SS_CONNECTED) {
  		error = -EISCONN;
  		goto out;
  	}
  	if (sock->state != SS_UNCONNECTED) {
  		error = -EINVAL;
  		goto out;
  	}
  	vcc = ATM_SD(sock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
112
113
114
  	addr = (struct sockaddr_atmsvc *) sockaddr;
  	if (addr->sas_family != AF_ATMSVC) {
  		error = -EAFNOSUPPORT;
  		goto out;
  	}
b7d9371be   Joe Perches   net/atm/svc.c: ch...
115
  	clear_bit(ATM_VF_BOUND, &vcc->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
  	    /* failing rebind will kill old binding */
  	/* @@@ check memory (de)allocation on rebind */
b7d9371be   Joe Perches   net/atm/svc.c: ch...
118
  	if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
120
121
122
123
  		error = -EBADFD;
  		goto out;
  	}
  	vcc->local = *addr;
  	set_bit(ATM_VF_WAITING, &vcc->flags);
b7d9371be   Joe Perches   net/atm/svc.c: ch...
124
  	sigd_enq(vcc, as_bind, NULL, NULL, &vcc->local);
de713b579   chas williams - CONTRACTOR   atm/svc: Fix bloc...
125
  	for (;;) {
aa3951451   Eric Dumazet   net: sk_sleep() h...
126
  		prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
de713b579   chas williams - CONTRACTOR   atm/svc: Fix bloc...
127
128
129
  		if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd)
  			break;
  		schedule();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
  	}
aa3951451   Eric Dumazet   net: sk_sleep() h...
131
  	finish_wait(sk_sleep(sk), &wait);
b7d9371be   Joe Perches   net/atm/svc.c: ch...
132
  	clear_bit(ATM_VF_REGIS, &vcc->flags); /* doesn't count */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
134
135
136
  	if (!sigd) {
  		error = -EUNATCH;
  		goto out;
  	}
f7d57453d   YOSHIFUJI Hideaki   [NET] ATM: Fix wh...
137
  	if (!sk->sk_err)
b7d9371be   Joe Perches   net/atm/svc.c: ch...
138
  		set_bit(ATM_VF_BOUND, &vcc->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
140
141
142
143
  	error = -sk->sk_err;
  out:
  	release_sock(sk);
  	return error;
  }
b7d9371be   Joe Perches   net/atm/svc.c: ch...
144
145
  static int svc_connect(struct socket *sock, struct sockaddr *sockaddr,
  		       int sockaddr_len, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
148
149
150
151
  {
  	DEFINE_WAIT(wait);
  	struct sock *sk = sock->sk;
  	struct sockaddr_atmsvc *addr;
  	struct atm_vcc *vcc = ATM_SD(sock);
  	int error;
b7d9371be   Joe Perches   net/atm/svc.c: ch...
152
153
  	pr_debug("%p
  ", vcc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
  	lock_sock(sk);
  	if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) {
  		error = -EINVAL;
  		goto out;
  	}
  
  	switch (sock->state) {
  	default:
  		error = -EINVAL;
  		goto out;
  	case SS_CONNECTED:
  		error = -EISCONN;
  		goto out;
  	case SS_CONNECTING:
  		if (test_bit(ATM_VF_WAITING, &vcc->flags)) {
  			error = -EALREADY;
  			goto out;
  		}
  		sock->state = SS_UNCONNECTED;
  		if (sk->sk_err) {
  			error = -sk->sk_err;
  			goto out;
  		}
  		break;
  	case SS_UNCONNECTED:
  		addr = (struct sockaddr_atmsvc *) sockaddr;
  		if (addr->sas_family != AF_ATMSVC) {
  			error = -EAFNOSUPPORT;
  			goto out;
  		}
  		if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) {
  			error = -EBADFD;
  			goto out;
  		}
  		if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS ||
  		    vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) {
  			error = -EINVAL;
  			goto out;
  		}
  		if (!vcc->qos.txtp.traffic_class &&
  		    !vcc->qos.rxtp.traffic_class) {
  			error = -EINVAL;
  			goto out;
  		}
  		vcc->remote = *addr;
  		set_bit(ATM_VF_WAITING, &vcc->flags);
b7d9371be   Joe Perches   net/atm/svc.c: ch...
200
  		sigd_enq(vcc, as_connect, NULL, NULL, &vcc->remote);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
  		if (flags & O_NONBLOCK) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
203
204
205
206
  			sock->state = SS_CONNECTING;
  			error = -EINPROGRESS;
  			goto out;
  		}
  		error = 0;
de713b579   chas williams - CONTRACTOR   atm/svc: Fix bloc...
207
  		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
210
  		while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
  			schedule();
  			if (!signal_pending(current)) {
aa3951451   Eric Dumazet   net: sk_sleep() h...
211
  				prepare_to_wait(sk_sleep(sk), &wait,
b7d9371be   Joe Perches   net/atm/svc.c: ch...
212
  						TASK_INTERRUPTIBLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
214
  				continue;
  			}
522400623   Stephen Hemminger   [ATM]: Replace DP...
215
216
  			pr_debug("*ABORT*
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
218
219
220
  			/*
  			 * This is tricky:
  			 *   Kernel ---close--> Demon
  			 *   Kernel <--close--- Demon
f7d57453d   YOSHIFUJI Hideaki   [NET] ATM: Fix wh...
221
  			 * or
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
223
224
225
226
227
228
  			 *   Kernel ---close--> Demon
  			 *   Kernel <--error--- Demon
  			 * or
  			 *   Kernel ---close--> Demon
  			 *   Kernel <--okay---- Demon
  			 *   Kernel <--close--- Demon
  			 */
b7d9371be   Joe Perches   net/atm/svc.c: ch...
229
  			sigd_enq(vcc, as_close, NULL, NULL, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
230
  			while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
aa3951451   Eric Dumazet   net: sk_sleep() h...
231
  				prepare_to_wait(sk_sleep(sk), &wait,
b7d9371be   Joe Perches   net/atm/svc.c: ch...
232
  						TASK_INTERRUPTIBLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
234
235
  				schedule();
  			}
  			if (!sk->sk_err)
b7d9371be   Joe Perches   net/atm/svc.c: ch...
236
237
  				while (!test_bit(ATM_VF_RELEASED, &vcc->flags) &&
  				       sigd) {
aa3951451   Eric Dumazet   net: sk_sleep() h...
238
  					prepare_to_wait(sk_sleep(sk), &wait,
b7d9371be   Joe Perches   net/atm/svc.c: ch...
239
  							TASK_INTERRUPTIBLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
241
  					schedule();
  				}
b7d9371be   Joe Perches   net/atm/svc.c: ch...
242
243
244
  			clear_bit(ATM_VF_REGIS, &vcc->flags);
  			clear_bit(ATM_VF_RELEASED, &vcc->flags);
  			clear_bit(ATM_VF_CLOSE, &vcc->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
246
247
248
  			    /* we're gone now but may connect later */
  			error = -EINTR;
  			break;
  		}
aa3951451   Eric Dumazet   net: sk_sleep() h...
249
  		finish_wait(sk_sleep(sk), &wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
250
251
252
253
254
255
256
257
258
259
260
  		if (error)
  			goto out;
  		if (!sigd) {
  			error = -EUNATCH;
  			goto out;
  		}
  		if (sk->sk_err) {
  			error = -sk->sk_err;
  			goto out;
  		}
  	}
391296c90   Paul Bolle   atm: remove comme...
261

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
263
264
  	vcc->qos.txtp.max_pcr = SELECT_TOP_PCR(vcc->qos.txtp);
  	vcc->qos.txtp.pcr = 0;
  	vcc->qos.txtp.min_pcr = 0;
391296c90   Paul Bolle   atm: remove comme...
265

b7d9371be   Joe Perches   net/atm/svc.c: ch...
266
267
  	error = vcc_connect(sock, vcc->itf, vcc->vpi, vcc->vci);
  	if (!error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
269
  		sock->state = SS_CONNECTED;
  	else
b7d9371be   Joe Perches   net/atm/svc.c: ch...
270
  		(void)svc_disconnect(vcc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
273
274
  out:
  	release_sock(sk);
  	return error;
  }
b7d9371be   Joe Perches   net/atm/svc.c: ch...
275
  static int svc_listen(struct socket *sock, int backlog)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
277
278
279
280
  {
  	DEFINE_WAIT(wait);
  	struct sock *sk = sock->sk;
  	struct atm_vcc *vcc = ATM_SD(sock);
  	int error;
99824461e   Joe Perches   net/atm: Convert ...
281
282
  	pr_debug("%p
  ", vcc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
284
  	lock_sock(sk);
  	/* let server handle listen on unbound sockets */
b7d9371be   Joe Perches   net/atm/svc.c: ch...
285
  	if (test_bit(ATM_VF_SESSION, &vcc->flags)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
288
  		error = -EINVAL;
  		goto out;
  	}
17b24b3c9   Chas Williams   ATM: CVE-2008-507...
289
290
291
  	if (test_bit(ATM_VF_LISTEN, &vcc->flags)) {
  		error = -EADDRINUSE;
  		goto out;
b7d9371be   Joe Perches   net/atm/svc.c: ch...
292
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
  	set_bit(ATM_VF_WAITING, &vcc->flags);
b7d9371be   Joe Perches   net/atm/svc.c: ch...
294
  	sigd_enq(vcc, as_listen, NULL, NULL, &vcc->local);
de713b579   chas williams - CONTRACTOR   atm/svc: Fix bloc...
295
  	for (;;) {
aa3951451   Eric Dumazet   net: sk_sleep() h...
296
  		prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
de713b579   chas williams - CONTRACTOR   atm/svc: Fix bloc...
297
298
299
  		if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd)
  			break;
  		schedule();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
  	}
aa3951451   Eric Dumazet   net: sk_sleep() h...
301
  	finish_wait(sk_sleep(sk), &wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
303
304
305
  	if (!sigd) {
  		error = -EUNATCH;
  		goto out;
  	}
b7d9371be   Joe Perches   net/atm/svc.c: ch...
306
  	set_bit(ATM_VF_LISTEN, &vcc->flags);
17b24b3c9   Chas Williams   ATM: CVE-2008-507...
307
  	vcc_insert_socket(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
309
310
311
312
313
  	sk->sk_max_ack_backlog = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT;
  	error = -sk->sk_err;
  out:
  	release_sock(sk);
  	return error;
  }
cdfbabfb2   David Howells   net: Work around ...
314
315
  static int svc_accept(struct socket *sock, struct socket *newsock, int flags,
  		      bool kern)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
316
317
318
319
320
321
322
323
324
  {
  	struct sock *sk = sock->sk;
  	struct sk_buff *skb;
  	struct atmsvc_msg *msg;
  	struct atm_vcc *old_vcc = ATM_SD(sock);
  	struct atm_vcc *new_vcc;
  	int error;
  
  	lock_sock(sk);
cdfbabfb2   David Howells   net: Work around ...
325
  	error = svc_create(sock_net(sk), newsock, 0, kern);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
327
328
329
  	if (error)
  		goto out;
  
  	new_vcc = ATM_SD(newsock);
99824461e   Joe Perches   net/atm: Convert ...
330
331
  	pr_debug("%p -> %p
  ", old_vcc, new_vcc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
333
  	while (1) {
  		DEFINE_WAIT(wait);
aa3951451   Eric Dumazet   net: sk_sleep() h...
334
  		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335
336
  		while (!(skb = skb_dequeue(&sk->sk_receive_queue)) &&
  		       sigd) {
b7d9371be   Joe Perches   net/atm/svc.c: ch...
337
338
339
  			if (test_bit(ATM_VF_RELEASED, &old_vcc->flags))
  				break;
  			if (test_bit(ATM_VF_CLOSE, &old_vcc->flags)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
341
342
343
344
345
346
347
348
349
350
351
352
353
  				error = -sk->sk_err;
  				break;
  			}
  			if (flags & O_NONBLOCK) {
  				error = -EAGAIN;
  				break;
  			}
  			release_sock(sk);
  			schedule();
  			lock_sock(sk);
  			if (signal_pending(current)) {
  				error = -ERESTARTSYS;
  				break;
  			}
aa3951451   Eric Dumazet   net: sk_sleep() h...
354
  			prepare_to_wait(sk_sleep(sk), &wait,
b7d9371be   Joe Perches   net/atm/svc.c: ch...
355
  					TASK_INTERRUPTIBLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
  		}
aa3951451   Eric Dumazet   net: sk_sleep() h...
357
  		finish_wait(sk_sleep(sk), &wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
359
360
361
362
363
  		if (error)
  			goto out;
  		if (!skb) {
  			error = -EUNATCH;
  			goto out;
  		}
b7d9371be   Joe Perches   net/atm/svc.c: ch...
364
  		msg = (struct atmsvc_msg *)skb->data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
  		new_vcc->qos = msg->qos;
b7d9371be   Joe Perches   net/atm/svc.c: ch...
366
  		set_bit(ATM_VF_HASQOS, &new_vcc->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
369
370
  		new_vcc->remote = msg->svc;
  		new_vcc->local = msg->local;
  		new_vcc->sap = msg->sap;
  		error = vcc_connect(newsock, msg->pvc.sap_addr.itf,
b7d9371be   Joe Perches   net/atm/svc.c: ch...
371
372
  				    msg->pvc.sap_addr.vpi,
  				    msg->pvc.sap_addr.vci);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
374
375
  		dev_kfree_skb(skb);
  		sk->sk_ack_backlog--;
  		if (error) {
b7d9371be   Joe Perches   net/atm/svc.c: ch...
376
377
  			sigd_enq2(NULL, as_reject, old_vcc, NULL, NULL,
  				  &old_vcc->qos, error);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
379
380
381
382
  			error = error == -EAGAIN ? -EBUSY : error;
  			goto out;
  		}
  		/* wait should be short, so we ignore the non-blocking flag */
  		set_bit(ATM_VF_WAITING, &new_vcc->flags);
b7d9371be   Joe Perches   net/atm/svc.c: ch...
383
  		sigd_enq(new_vcc, as_accept, old_vcc, NULL, NULL);
de713b579   chas williams - CONTRACTOR   atm/svc: Fix bloc...
384
385
386
387
388
  		for (;;) {
  			prepare_to_wait(sk_sleep(sk_atm(new_vcc)), &wait,
  					TASK_UNINTERRUPTIBLE);
  			if (!test_bit(ATM_VF_WAITING, &new_vcc->flags) || !sigd)
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
390
391
  			release_sock(sk);
  			schedule();
  			lock_sock(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
  		}
aa3951451   Eric Dumazet   net: sk_sleep() h...
393
  		finish_wait(sk_sleep(sk_atm(new_vcc)), &wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
  		if (!sigd) {
  			error = -EUNATCH;
  			goto out;
  		}
  		if (!sk_atm(new_vcc)->sk_err)
  			break;
  		if (sk_atm(new_vcc)->sk_err != ERESTARTSYS) {
  			error = -sk_atm(new_vcc)->sk_err;
  			goto out;
  		}
  	}
  	newsock->state = SS_CONNECTED;
  out:
  	release_sock(sk);
  	return error;
  }
b7d9371be   Joe Perches   net/atm/svc.c: ch...
410
411
  static int svc_getname(struct socket *sock, struct sockaddr *sockaddr,
  		       int *sockaddr_len, int peer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
413
414
415
416
  {
  	struct sockaddr_atmsvc *addr;
  
  	*sockaddr_len = sizeof(struct sockaddr_atmsvc);
  	addr = (struct sockaddr_atmsvc *) sockaddr;
b7d9371be   Joe Perches   net/atm/svc.c: ch...
417
418
  	memcpy(addr, peer ? &ATM_SD(sock)->remote : &ATM_SD(sock)->local,
  	       sizeof(struct sockaddr_atmsvc));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
419
420
  	return 0;
  }
b7d9371be   Joe Perches   net/atm/svc.c: ch...
421
  int svc_change_qos(struct atm_vcc *vcc, struct atm_qos *qos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
423
424
425
426
  {
  	struct sock *sk = sk_atm(vcc);
  	DEFINE_WAIT(wait);
  
  	set_bit(ATM_VF_WAITING, &vcc->flags);
b7d9371be   Joe Perches   net/atm/svc.c: ch...
427
  	sigd_enq2(vcc, as_modify, NULL, NULL, &vcc->local, qos, 0);
de713b579   chas williams - CONTRACTOR   atm/svc: Fix bloc...
428
  	for (;;) {
aa3951451   Eric Dumazet   net: sk_sleep() h...
429
  		prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
de713b579   chas williams - CONTRACTOR   atm/svc: Fix bloc...
430
431
432
433
434
  		if (!test_bit(ATM_VF_WAITING, &vcc->flags) ||
  		    test_bit(ATM_VF_RELEASED, &vcc->flags) || !sigd) {
  			break;
  		}
  		schedule();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
  	}
aa3951451   Eric Dumazet   net: sk_sleep() h...
436
  	finish_wait(sk_sleep(sk), &wait);
b7d9371be   Joe Perches   net/atm/svc.c: ch...
437
438
  	if (!sigd)
  		return -EUNATCH;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
  	return -sk->sk_err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
  static int svc_setsockopt(struct socket *sock, int level, int optname,
b7058842c   David S. Miller   net: Make setsock...
442
  			  char __user *optval, unsigned int optlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
443
444
445
446
447
448
449
  {
  	struct sock *sk = sock->sk;
  	struct atm_vcc *vcc = ATM_SD(sock);
  	int value, error = 0;
  
  	lock_sock(sk);
  	switch (optname) {
b7d9371be   Joe Perches   net/atm/svc.c: ch...
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
  	case SO_ATMSAP:
  		if (level != SOL_ATM || optlen != sizeof(struct atm_sap)) {
  			error = -EINVAL;
  			goto out;
  		}
  		if (copy_from_user(&vcc->sap, optval, optlen)) {
  			error = -EFAULT;
  			goto out;
  		}
  		set_bit(ATM_VF_HASSAP, &vcc->flags);
  		break;
  	case SO_MULTIPOINT:
  		if (level != SOL_ATM || optlen != sizeof(int)) {
  			error = -EINVAL;
  			goto out;
  		}
  		if (get_user(value, (int __user *)optval)) {
  			error = -EFAULT;
  			goto out;
  		}
  		if (value == 1)
  			set_bit(ATM_VF_SESSION, &vcc->flags);
  		else if (value == 0)
  			clear_bit(ATM_VF_SESSION, &vcc->flags);
  		else
  			error = -EINVAL;
  		break;
  	default:
  		error = vcc_setsockopt(sock, level, optname, optval, optlen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
480
481
482
483
484
  	}
  
  out:
  	release_sock(sk);
  	return error;
  }
b7d9371be   Joe Perches   net/atm/svc.c: ch...
485
486
  static int svc_getsockopt(struct socket *sock, int level, int optname,
  			  char __user *optval, int __user *optlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
  {
  	struct sock *sk = sock->sk;
  	int error = 0, len;
  
  	lock_sock(sk);
  	if (!__SO_LEVEL_MATCH(optname, level) || optname != SO_ATMSAP) {
  		error = vcc_getsockopt(sock, level, optname, optval, optlen);
  		goto out;
  	}
  	if (get_user(len, optlen)) {
  		error = -EFAULT;
  		goto out;
  	}
  	if (len != sizeof(struct atm_sap)) {
  		error = -EINVAL;
  		goto out;
  	}
  	if (copy_to_user(optval, &ATM_SD(sock)->sap, sizeof(struct atm_sap))) {
  		error = -EFAULT;
  		goto out;
  	}
  out:
  	release_sock(sk);
  	return error;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
513
514
515
516
517
518
519
520
521
  static int svc_addparty(struct socket *sock, struct sockaddr *sockaddr,
  			int sockaddr_len, int flags)
  {
  	DEFINE_WAIT(wait);
  	struct sock *sk = sock->sk;
  	struct atm_vcc *vcc = ATM_SD(sock);
  	int error;
  
  	lock_sock(sk);
  	set_bit(ATM_VF_WAITING, &vcc->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
  	sigd_enq(vcc, as_addparty, NULL, NULL,
f7d57453d   YOSHIFUJI Hideaki   [NET] ATM: Fix wh...
523
  		 (struct sockaddr_atmsvc *) sockaddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
  	if (flags & O_NONBLOCK) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
526
527
  		error = -EINPROGRESS;
  		goto out;
  	}
99824461e   Joe Perches   net/atm: Convert ...
528
529
  	pr_debug("added wait queue
  ");
de713b579   chas williams - CONTRACTOR   atm/svc: Fix bloc...
530
  	for (;;) {
aa3951451   Eric Dumazet   net: sk_sleep() h...
531
  		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
de713b579   chas williams - CONTRACTOR   atm/svc: Fix bloc...
532
533
534
  		if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd)
  			break;
  		schedule();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
  	}
aa3951451   Eric Dumazet   net: sk_sleep() h...
536
  	finish_wait(sk_sleep(sk), &wait);
c685293aa   Stefan Hajnoczi   net/atm: sk_err_s...
537
  	error = -xchg(&sk->sk_err_soft, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
538
539
540
541
  out:
  	release_sock(sk);
  	return error;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
544
545
546
547
548
549
550
  static int svc_dropparty(struct socket *sock, int ep_ref)
  {
  	DEFINE_WAIT(wait);
  	struct sock *sk = sock->sk;
  	struct atm_vcc *vcc = ATM_SD(sock);
  	int error;
  
  	lock_sock(sk);
  	set_bit(ATM_VF_WAITING, &vcc->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
  	sigd_enq2(vcc, as_dropparty, NULL, NULL, NULL, NULL, ep_ref);
de713b579   chas williams - CONTRACTOR   atm/svc: Fix bloc...
552
  	for (;;) {
aa3951451   Eric Dumazet   net: sk_sleep() h...
553
  		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
de713b579   chas williams - CONTRACTOR   atm/svc: Fix bloc...
554
555
556
  		if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd)
  			break;
  		schedule();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
  	}
aa3951451   Eric Dumazet   net: sk_sleep() h...
558
  	finish_wait(sk_sleep(sk), &wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
560
561
562
  	if (!sigd) {
  		error = -EUNATCH;
  		goto out;
  	}
c685293aa   Stefan Hajnoczi   net/atm: sk_err_s...
563
  	error = -xchg(&sk->sk_err_soft, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564
565
566
567
  out:
  	release_sock(sk);
  	return error;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
569
  static int svc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
  {
f7d57453d   YOSHIFUJI Hideaki   [NET] ATM: Fix wh...
570
571
  	int error, ep_ref;
  	struct sockaddr_atmsvc sa;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
  	struct atm_vcc *vcc = ATM_SD(sock);
f7d57453d   YOSHIFUJI Hideaki   [NET] ATM: Fix wh...
573

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
  	switch (cmd) {
b7d9371be   Joe Perches   net/atm/svc.c: ch...
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
  	case ATM_ADDPARTY:
  		if (!test_bit(ATM_VF_SESSION, &vcc->flags))
  			return -EINVAL;
  		if (copy_from_user(&sa, (void __user *) arg, sizeof(sa)))
  			return -EFAULT;
  		error = svc_addparty(sock, (struct sockaddr *)&sa, sizeof(sa),
  				     0);
  		break;
  	case ATM_DROPPARTY:
  		if (!test_bit(ATM_VF_SESSION, &vcc->flags))
  			return -EINVAL;
  		if (copy_from_user(&ep_ref, (void __user *) arg, sizeof(int)))
  			return -EFAULT;
  		error = svc_dropparty(sock, ep_ref);
  		break;
  	default:
  		error = vcc_ioctl(sock, cmd, arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
592
593
594
595
  	}
  
  	return error;
  }
8865c418c   David Woodhouse   atm: 32-bit ioctl...
596
  #ifdef CONFIG_COMPAT
b7d9371be   Joe Perches   net/atm/svc.c: ch...
597
598
  static int svc_compat_ioctl(struct socket *sock, unsigned int cmd,
  			    unsigned long arg)
8865c418c   David Woodhouse   atm: 32-bit ioctl...
599
600
601
602
603
604
605
606
607
608
609
610
611
  {
  	/* The definition of ATM_ADDPARTY uses the size of struct atm_iobuf.
  	   But actually it takes a struct sockaddr_atmsvc, which doesn't need
  	   compat handling. So all we have to do is fix up cmd... */
  	if (cmd == COMPAT_ATM_ADDPARTY)
  		cmd = ATM_ADDPARTY;
  
  	if (cmd == ATM_ADDPARTY || cmd == ATM_DROPPARTY)
  		return svc_ioctl(sock, cmd, arg);
  	else
  		return vcc_compat_ioctl(sock, cmd, arg);
  }
  #endif /* CONFIG_COMPAT */
90ddc4f04   Eric Dumazet   [NET]: move struc...
612
  static const struct proto_ops svc_proto_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
614
615
616
617
618
619
620
621
622
623
  	.family =	PF_ATMSVC,
  	.owner =	THIS_MODULE,
  
  	.release =	svc_release,
  	.bind =		svc_bind,
  	.connect =	svc_connect,
  	.socketpair =	sock_no_socketpair,
  	.accept =	svc_accept,
  	.getname =	svc_getname,
  	.poll =		vcc_poll,
  	.ioctl =	svc_ioctl,
8865c418c   David Woodhouse   atm: 32-bit ioctl...
624
625
626
  #ifdef CONFIG_COMPAT
  	.compat_ioctl =	svc_compat_ioctl,
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
627
628
629
630
631
632
633
634
635
  	.listen =	svc_listen,
  	.shutdown =	svc_shutdown,
  	.setsockopt =	svc_setsockopt,
  	.getsockopt =	svc_getsockopt,
  	.sendmsg =	vcc_sendmsg,
  	.recvmsg =	vcc_recvmsg,
  	.mmap =		sock_no_mmap,
  	.sendpage =	sock_no_sendpage,
  };
3f378b684   Eric Paris   net: pass kern to...
636
637
  static int svc_create(struct net *net, struct socket *sock, int protocol,
  		      int kern)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638
639
  {
  	int error;
09ad9bc75   Octavian Purdila   net: use net_eq t...
640
  	if (!net_eq(net, &init_net))
1b8d7ae42   Eric W. Biederman   [NET]: Make socke...
641
  		return -EAFNOSUPPORT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
642
  	sock->ops = &svc_proto_ops;
11aa9c28b   Eric W. Biederman   net: Pass kern fr...
643
  	error = vcc_create(net, sock, protocol, AF_ATMSVC, kern);
b7d9371be   Joe Perches   net/atm/svc.c: ch...
644
645
  	if (error)
  		return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
647
648
649
  	ATM_SD(sock)->local.sas_family = AF_ATMSVC;
  	ATM_SD(sock)->remote.sas_family = AF_ATMSVC;
  	return 0;
  }
ec1b4cf74   Stephen Hemminger   net: mark net_pro...
650
  static const struct net_proto_family svc_family_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
  	.family = PF_ATMSVC,
  	.create = svc_create,
  	.owner = THIS_MODULE,
  };
  
  
  /*
   *	Initialize the ATM SVC protocol family
   */
  
  int __init atmsvc_init(void)
  {
  	return sock_register(&svc_family_ops);
  }
  
  void atmsvc_exit(void)
  {
  	sock_unregister(PF_ATMSVC);
  }