Blame view

net/atm/svc.c 16.4 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /* net/atm/svc.c - ATM SVC sockets */
  
  /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
99824461e   Joe Perches   net/atm: Convert ...
4
  #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  
  #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>
  #include <linux/sched.h>	/* jiffies and HZ */
  #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...
21
  #include <linux/uaccess.h>
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
22
  #include <linux/export.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
27
  
  #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...
28
29
  static int svc_create(struct net *net, struct socket *sock, int protocol,
  		      int kern);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
34
35
  /*
   * 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...
36
  static int svc_shutdown(struct socket *sock, int how)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
39
  {
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
42
43
44
  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...
45
46
47
  	pr_debug("%p
  ", vcc);
  	if (test_bit(ATM_VF_REGIS, &vcc->flags)) {
aa3951451   Eric Dumazet   net: sk_sleep() h...
48
  		prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
b7d9371be   Joe Perches   net/atm/svc.c: ch...
49
50
  		sigd_enq(vcc, as_close, NULL, NULL, NULL);
  		while (!test_bit(ATM_VF_RELEASED, &vcc->flags) && sigd) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
  			schedule();
aa3951451   Eric Dumazet   net: sk_sleep() h...
52
  			prepare_to_wait(sk_sleep(sk), &wait,
b7d9371be   Joe Perches   net/atm/svc.c: ch...
53
  					TASK_UNINTERRUPTIBLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
  		}
aa3951451   Eric Dumazet   net: sk_sleep() h...
55
  		finish_wait(sk_sleep(sk), &wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
58
59
60
  	}
  	/* 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...
61
62
  		pr_debug("LISTEN REL
  ");
b7d9371be   Joe Perches   net/atm/svc.c: ch...
63
  		sigd_enq2(NULL, as_reject, vcc, NULL, NULL, &vcc->qos, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
65
66
67
68
  		dev_kfree_skb(skb);
  	}
  	clear_bit(ATM_VF_REGIS, &vcc->flags);
  	/* ... may retry later */
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
71
72
  static int svc_release(struct socket *sock)
  {
  	struct sock *sk = sock->sk;
  	struct atm_vcc *vcc;
b7d9371be   Joe Perches   net/atm/svc.c: ch...
73
  	if (sk) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
74
  		vcc = ATM_SD(sock);
99824461e   Joe Perches   net/atm: Convert ...
75
76
  		pr_debug("%p
  ", vcc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
  		clear_bit(ATM_VF_READY, &vcc->flags);
b7d9371be   Joe Perches   net/atm/svc.c: ch...
78
79
80
81
82
  		/*
  		 * 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
83
84
85
86
87
  		svc_disconnect(vcc);
  		vcc_release(sock);
  	}
  	return 0;
  }
b7d9371be   Joe Perches   net/atm/svc.c: ch...
88
89
  static int svc_bind(struct socket *sock, struct sockaddr *sockaddr,
  		    int sockaddr_len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
  {
  	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
109
110
111
112
113
  	addr = (struct sockaddr_atmsvc *) sockaddr;
  	if (addr->sas_family != AF_ATMSVC) {
  		error = -EAFNOSUPPORT;
  		goto out;
  	}
b7d9371be   Joe Perches   net/atm/svc.c: ch...
114
  	clear_bit(ATM_VF_BOUND, &vcc->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
  	    /* failing rebind will kill old binding */
  	/* @@@ check memory (de)allocation on rebind */
b7d9371be   Joe Perches   net/atm/svc.c: ch...
117
  	if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
119
120
121
122
  		error = -EBADFD;
  		goto out;
  	}
  	vcc->local = *addr;
  	set_bit(ATM_VF_WAITING, &vcc->flags);
aa3951451   Eric Dumazet   net: sk_sleep() h...
123
  	prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
b7d9371be   Joe Perches   net/atm/svc.c: ch...
124
  	sigd_enq(vcc, as_bind, NULL, NULL, &vcc->local);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
126
  	while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
  		schedule();
aa3951451   Eric Dumazet   net: sk_sleep() h...
127
  		prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
  	}
aa3951451   Eric Dumazet   net: sk_sleep() h...
129
  	finish_wait(sk_sleep(sk), &wait);
b7d9371be   Joe Perches   net/atm/svc.c: ch...
130
  	clear_bit(ATM_VF_REGIS, &vcc->flags); /* doesn't count */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
133
134
  	if (!sigd) {
  		error = -EUNATCH;
  		goto out;
  	}
f7d57453d   YOSHIFUJI Hideaki   [NET] ATM: Fix wh...
135
  	if (!sk->sk_err)
b7d9371be   Joe Perches   net/atm/svc.c: ch...
136
  		set_bit(ATM_VF_BOUND, &vcc->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
139
140
141
  	error = -sk->sk_err;
  out:
  	release_sock(sk);
  	return error;
  }
b7d9371be   Joe Perches   net/atm/svc.c: ch...
142
143
  static int svc_connect(struct socket *sock, struct sockaddr *sockaddr,
  		       int sockaddr_len, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
146
147
148
149
  {
  	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...
150
151
  	pr_debug("%p
  ", vcc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
153
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
  	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);
aa3951451   Eric Dumazet   net: sk_sleep() h...
198
  		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
b7d9371be   Joe Perches   net/atm/svc.c: ch...
199
  		sigd_enq(vcc, as_connect, NULL, NULL, &vcc->remote);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
  		if (flags & O_NONBLOCK) {
aa3951451   Eric Dumazet   net: sk_sleep() h...
201
  			finish_wait(sk_sleep(sk), &wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
203
204
205
206
207
208
209
  			sock->state = SS_CONNECTING;
  			error = -EINPROGRESS;
  			goto out;
  		}
  		error = 0;
  		while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
  			schedule();
  			if (!signal_pending(current)) {
aa3951451   Eric Dumazet   net: sk_sleep() h...
210
  				prepare_to_wait(sk_sleep(sk), &wait,
b7d9371be   Joe Perches   net/atm/svc.c: ch...
211
  						TASK_INTERRUPTIBLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
213
  				continue;
  			}
522400623   Stephen Hemminger   [ATM]: Replace DP...
214
215
  			pr_debug("*ABORT*
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
217
218
219
  			/*
  			 * This is tricky:
  			 *   Kernel ---close--> Demon
  			 *   Kernel <--close--- Demon
f7d57453d   YOSHIFUJI Hideaki   [NET] ATM: Fix wh...
220
  			 * or
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
222
223
224
225
226
227
  			 *   Kernel ---close--> Demon
  			 *   Kernel <--error--- Demon
  			 * or
  			 *   Kernel ---close--> Demon
  			 *   Kernel <--okay---- Demon
  			 *   Kernel <--close--- Demon
  			 */
b7d9371be   Joe Perches   net/atm/svc.c: ch...
228
  			sigd_enq(vcc, as_close, NULL, NULL, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
  			while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
aa3951451   Eric Dumazet   net: sk_sleep() h...
230
  				prepare_to_wait(sk_sleep(sk), &wait,
b7d9371be   Joe Perches   net/atm/svc.c: ch...
231
  						TASK_INTERRUPTIBLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
233
234
  				schedule();
  			}
  			if (!sk->sk_err)
b7d9371be   Joe Perches   net/atm/svc.c: ch...
235
236
  				while (!test_bit(ATM_VF_RELEASED, &vcc->flags) &&
  				       sigd) {
aa3951451   Eric Dumazet   net: sk_sleep() h...
237
  					prepare_to_wait(sk_sleep(sk), &wait,
b7d9371be   Joe Perches   net/atm/svc.c: ch...
238
  							TASK_INTERRUPTIBLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
240
  					schedule();
  				}
b7d9371be   Joe Perches   net/atm/svc.c: ch...
241
242
243
  			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
244
245
246
247
  			    /* we're gone now but may connect later */
  			error = -EINTR;
  			break;
  		}
aa3951451   Eric Dumazet   net: sk_sleep() h...
248
  		finish_wait(sk_sleep(sk), &wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
  		if (error)
  			goto out;
  		if (!sigd) {
  			error = -EUNATCH;
  			goto out;
  		}
  		if (sk->sk_err) {
  			error = -sk->sk_err;
  			goto out;
  		}
  	}
  /*
   * Not supported yet
   *
   * #ifndef CONFIG_SINGLE_SIGITF
   */
  	vcc->qos.txtp.max_pcr = SELECT_TOP_PCR(vcc->qos.txtp);
  	vcc->qos.txtp.pcr = 0;
  	vcc->qos.txtp.min_pcr = 0;
  /*
   * #endif
   */
b7d9371be   Joe Perches   net/atm/svc.c: ch...
271
272
  	error = vcc_connect(sock, vcc->itf, vcc->vpi, vcc->vci);
  	if (!error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
274
  		sock->state = SS_CONNECTED;
  	else
b7d9371be   Joe Perches   net/atm/svc.c: ch...
275
  		(void)svc_disconnect(vcc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
277
278
279
  out:
  	release_sock(sk);
  	return error;
  }
b7d9371be   Joe Perches   net/atm/svc.c: ch...
280
  static int svc_listen(struct socket *sock, int backlog)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
282
283
284
285
  {
  	DEFINE_WAIT(wait);
  	struct sock *sk = sock->sk;
  	struct atm_vcc *vcc = ATM_SD(sock);
  	int error;
99824461e   Joe Perches   net/atm: Convert ...
286
287
  	pr_debug("%p
  ", vcc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
289
  	lock_sock(sk);
  	/* let server handle listen on unbound sockets */
b7d9371be   Joe Perches   net/atm/svc.c: ch...
290
  	if (test_bit(ATM_VF_SESSION, &vcc->flags)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
292
293
  		error = -EINVAL;
  		goto out;
  	}
17b24b3c9   Chas Williams   ATM: CVE-2008-507...
294
295
296
  	if (test_bit(ATM_VF_LISTEN, &vcc->flags)) {
  		error = -EADDRINUSE;
  		goto out;
b7d9371be   Joe Perches   net/atm/svc.c: ch...
297
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
  	set_bit(ATM_VF_WAITING, &vcc->flags);
aa3951451   Eric Dumazet   net: sk_sleep() h...
299
  	prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
b7d9371be   Joe Perches   net/atm/svc.c: ch...
300
  	sigd_enq(vcc, as_listen, NULL, NULL, &vcc->local);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
302
  	while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
  		schedule();
aa3951451   Eric Dumazet   net: sk_sleep() h...
303
  		prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
  	}
aa3951451   Eric Dumazet   net: sk_sleep() h...
305
  	finish_wait(sk_sleep(sk), &wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
306
307
308
309
  	if (!sigd) {
  		error = -EUNATCH;
  		goto out;
  	}
b7d9371be   Joe Perches   net/atm/svc.c: ch...
310
  	set_bit(ATM_VF_LISTEN, &vcc->flags);
17b24b3c9   Chas Williams   ATM: CVE-2008-507...
311
  	vcc_insert_socket(sk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
313
314
315
316
317
  	sk->sk_max_ack_backlog = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT;
  	error = -sk->sk_err;
  out:
  	release_sock(sk);
  	return error;
  }
b7d9371be   Joe Perches   net/atm/svc.c: ch...
318
  static int svc_accept(struct socket *sock, struct socket *newsock, int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
320
321
322
323
324
325
326
327
  {
  	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);
3f378b684   Eric Paris   net: pass kern to...
328
  	error = svc_create(sock_net(sk), newsock, 0, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
330
331
332
  	if (error)
  		goto out;
  
  	new_vcc = ATM_SD(newsock);
99824461e   Joe Perches   net/atm: Convert ...
333
334
  	pr_debug("%p -> %p
  ", old_vcc, new_vcc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335
336
  	while (1) {
  		DEFINE_WAIT(wait);
aa3951451   Eric Dumazet   net: sk_sleep() h...
337
  		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
339
  		while (!(skb = skb_dequeue(&sk->sk_receive_queue)) &&
  		       sigd) {
b7d9371be   Joe Perches   net/atm/svc.c: ch...
340
341
342
  			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
343
344
345
346
347
348
349
350
351
352
353
354
355
356
  				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...
357
  			prepare_to_wait(sk_sleep(sk), &wait,
b7d9371be   Joe Perches   net/atm/svc.c: ch...
358
  					TASK_INTERRUPTIBLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
  		}
aa3951451   Eric Dumazet   net: sk_sleep() h...
360
  		finish_wait(sk_sleep(sk), &wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
362
363
364
365
366
  		if (error)
  			goto out;
  		if (!skb) {
  			error = -EUNATCH;
  			goto out;
  		}
b7d9371be   Joe Perches   net/atm/svc.c: ch...
367
  		msg = (struct atmsvc_msg *)skb->data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
  		new_vcc->qos = msg->qos;
b7d9371be   Joe Perches   net/atm/svc.c: ch...
369
  		set_bit(ATM_VF_HASQOS, &new_vcc->flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
371
372
373
  		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...
374
375
  				    msg->pvc.sap_addr.vpi,
  				    msg->pvc.sap_addr.vci);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
377
378
  		dev_kfree_skb(skb);
  		sk->sk_ack_backlog--;
  		if (error) {
b7d9371be   Joe Perches   net/atm/svc.c: ch...
379
380
  			sigd_enq2(NULL, as_reject, old_vcc, NULL, NULL,
  				  &old_vcc->qos, error);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
382
383
384
385
  			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);
aa3951451   Eric Dumazet   net: sk_sleep() h...
386
  		prepare_to_wait(sk_sleep(sk_atm(new_vcc)), &wait,
b7d9371be   Joe Perches   net/atm/svc.c: ch...
387
388
  				TASK_UNINTERRUPTIBLE);
  		sigd_enq(new_vcc, as_accept, old_vcc, NULL, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
389
390
391
392
  		while (test_bit(ATM_VF_WAITING, &new_vcc->flags) && sigd) {
  			release_sock(sk);
  			schedule();
  			lock_sock(sk);
aa3951451   Eric Dumazet   net: sk_sleep() h...
393
  			prepare_to_wait(sk_sleep(sk_atm(new_vcc)), &wait,
b7d9371be   Joe Perches   net/atm/svc.c: ch...
394
  					TASK_UNINTERRUPTIBLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
  		}
aa3951451   Eric Dumazet   net: sk_sleep() h...
396
  		finish_wait(sk_sleep(sk_atm(new_vcc)), &wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
  		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...
413
414
  static int svc_getname(struct socket *sock, struct sockaddr *sockaddr,
  		       int *sockaddr_len, int peer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
416
417
418
419
  {
  	struct sockaddr_atmsvc *addr;
  
  	*sockaddr_len = sizeof(struct sockaddr_atmsvc);
  	addr = (struct sockaddr_atmsvc *) sockaddr;
b7d9371be   Joe Perches   net/atm/svc.c: ch...
420
421
  	memcpy(addr, peer ? &ATM_SD(sock)->remote : &ATM_SD(sock)->local,
  	       sizeof(struct sockaddr_atmsvc));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
423
  	return 0;
  }
b7d9371be   Joe Perches   net/atm/svc.c: ch...
424
  int svc_change_qos(struct atm_vcc *vcc, struct atm_qos *qos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
426
427
428
429
  {
  	struct sock *sk = sk_atm(vcc);
  	DEFINE_WAIT(wait);
  
  	set_bit(ATM_VF_WAITING, &vcc->flags);
aa3951451   Eric Dumazet   net: sk_sleep() h...
430
  	prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
b7d9371be   Joe Perches   net/atm/svc.c: ch...
431
  	sigd_enq2(vcc, as_modify, NULL, NULL, &vcc->local, qos, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
433
434
  	while (test_bit(ATM_VF_WAITING, &vcc->flags) &&
  	       !test_bit(ATM_VF_RELEASED, &vcc->flags) && sigd) {
  		schedule();
aa3951451   Eric Dumazet   net: sk_sleep() h...
435
  		prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
436
  	}
aa3951451   Eric Dumazet   net: sk_sleep() h...
437
  	finish_wait(sk_sleep(sk), &wait);
b7d9371be   Joe Perches   net/atm/svc.c: ch...
438
439
  	if (!sigd)
  		return -EUNATCH;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
441
  	return -sk->sk_err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
  static int svc_setsockopt(struct socket *sock, int level, int optname,
b7058842c   David S. Miller   net: Make setsock...
443
  			  char __user *optval, unsigned int optlen)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444
445
446
447
448
449
450
  {
  	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...
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
479
  	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
480
481
482
483
484
485
  	}
  
  out:
  	release_sock(sk);
  	return error;
  }
b7d9371be   Joe Perches   net/atm/svc.c: ch...
486
487
  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
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
  {
  	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
513
514
515
516
517
518
519
520
521
522
  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);
aa3951451   Eric Dumazet   net: sk_sleep() h...
523
  	prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
  	sigd_enq(vcc, as_addparty, NULL, NULL,
f7d57453d   YOSHIFUJI Hideaki   [NET] ATM: Fix wh...
525
  		 (struct sockaddr_atmsvc *) sockaddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
  	if (flags & O_NONBLOCK) {
aa3951451   Eric Dumazet   net: sk_sleep() h...
527
  		finish_wait(sk_sleep(sk), &wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
529
530
  		error = -EINPROGRESS;
  		goto out;
  	}
99824461e   Joe Perches   net/atm: Convert ...
531
532
  	pr_debug("added wait queue
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
534
  	while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
  		schedule();
aa3951451   Eric Dumazet   net: sk_sleep() h...
535
  		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
  	}
aa3951451   Eric Dumazet   net: sk_sleep() h...
537
  	finish_wait(sk_sleep(sk), &wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
538
539
540
541
542
  	error = xchg(&sk->sk_err_soft, 0);
  out:
  	release_sock(sk);
  	return error;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
544
545
546
547
548
549
550
551
  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);
aa3951451   Eric Dumazet   net: sk_sleep() h...
552
  	prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
554
555
  	sigd_enq2(vcc, as_dropparty, NULL, NULL, NULL, NULL, ep_ref);
  	while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
  		schedule();
aa3951451   Eric Dumazet   net: sk_sleep() h...
556
  		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
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
563
564
565
566
567
  	if (!sigd) {
  		error = -EUNATCH;
  		goto out;
  	}
  	error = xchg(&sk->sk_err_soft, 0);
  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;
1b8d7ae42   Eric W. Biederman   [NET]: Make socke...
643
  	error = vcc_create(net, sock, protocol, AF_ATMSVC);
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);
  }