1 /* net/atm/svc.c - ATM SVC sockets */
3 /* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
6 #include <linux/string.h>
7 #include <linux/net.h> /* struct socket, struct net_proto,
9 #include <linux/errno.h> /* error codes */
10 #include <linux/kernel.h> /* printk */
11 #include <linux/skbuff.h>
12 #include <linux/wait.h>
13 #include <linux/sched.h> /* jiffies and HZ */
14 #include <linux/fcntl.h> /* O_NONBLOCK */
15 #include <linux/init.h>
16 #include <linux/atm.h> /* ATM stuff */
17 #include <linux/atmsap.h>
18 #include <linux/atmsvc.h>
19 #include <linux/atmdev.h>
20 #include <net/sock.h> /* for sock_no_* */
21 #include <asm/uaccess.h>
23 #include "resources.h"
24 #include "common.h" /* common for PVCs and SVCs */
25 #include "signaling.h"
30 #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
32 #define DPRINTK(format,args...)
36 static int svc_create(struct socket
*sock
,int protocol
);
40 * Note: since all this is still nicely synchronized with the signaling demon,
41 * there's no need to protect sleep loops with clis. If signaling is
42 * moved into the kernel, that would change.
46 void svc_callback(struct atm_vcc
*vcc
)
54 static int svc_shutdown(struct socket
*sock
,int how
)
60 static void svc_disconnect(struct atm_vcc
*vcc
)
64 DPRINTK("svc_disconnect %p\n",vcc
);
65 if (vcc
->flags
& ATM_VF_REGIS
) {
66 sigd_enq(vcc
,as_close
,NULL
,NULL
,NULL
);
67 while (!(vcc
->flags
& ATM_VF_RELEASED
) && sigd
)
68 sleep_on(&vcc
->sleep
);
70 /* beware - socket is still in use by atmsigd until the last
71 as_indicate has been answered */
72 while ((skb
= skb_dequeue(&vcc
->listenq
))) {
73 DPRINTK("LISTEN REL\n");
74 sigd_enq(NULL
,as_reject
,vcc
,NULL
,NULL
); /* @@@ should include
78 vcc
->flags
&= ~(ATM_VF_REGIS
| ATM_VF_RELEASED
| ATM_VF_CLOSE
);
83 static int svc_release(struct socket
*sock
)
87 if (!sock
->sk
) return 0;
89 DPRINTK("svc_release %p\n",vcc
);
90 vcc
->flags
&= ~ATM_VF_READY
;
91 atm_release_vcc_sk(sock
->sk
,0);
93 /* VCC pointer is used as a reference, so we must not free it
94 (thereby subjecting it to re-use) before all pending connections
96 free_atm_vcc_sk(sock
->sk
);
101 static int svc_bind(struct socket
*sock
,struct sockaddr
*sockaddr
,
104 struct sockaddr_atmsvc
*addr
;
107 if (sockaddr_len
!= sizeof(struct sockaddr_atmsvc
)) return -EINVAL
;
108 if (sock
->state
== SS_CONNECTED
) return -EISCONN
;
109 if (sock
->state
!= SS_UNCONNECTED
) return -EINVAL
;
111 if (vcc
->flags
& ATM_VF_SESSION
) return -EINVAL
;
112 addr
= (struct sockaddr_atmsvc
*) sockaddr
;
113 if (addr
->sas_family
!= AF_ATMSVC
) return -EAFNOSUPPORT
;
114 vcc
->flags
&= ~ATM_VF_BOUND
; /* failing rebind will kill old binding */
115 /* @@@ check memory (de)allocation on rebind */
116 if (!(vcc
->flags
& ATM_VF_HASQOS
)) return -EBADFD
;
118 vcc
->reply
= WAITING
;
119 sigd_enq(vcc
,as_bind
,NULL
,NULL
,&vcc
->local
);
120 while (vcc
->reply
== WAITING
&& sigd
) sleep_on(&vcc
->sleep
);
121 vcc
->flags
&= ~ATM_VF_REGIS
; /* doesn't count */
122 if (!sigd
) return -EUNATCH
;
123 if (!vcc
->reply
) vcc
->flags
|= ATM_VF_BOUND
;
128 static int svc_connect(struct socket
*sock
,struct sockaddr
*sockaddr
,
129 int sockaddr_len
,int flags
)
131 struct sockaddr_atmsvc
*addr
;
132 struct atm_vcc
*vcc
= ATM_SD(sock
);
135 DPRINTK("svc_connect %p\n",vcc
);
136 if (sockaddr_len
!= sizeof(struct sockaddr_atmsvc
)) return -EINVAL
;
137 if (sock
->state
== SS_CONNECTED
) return -EISCONN
;
138 if (sock
->state
== SS_CONNECTING
) {
139 if (vcc
->reply
== WAITING
) return -EALREADY
;
140 sock
->state
= SS_UNCONNECTED
;
141 if (vcc
->reply
) return vcc
->reply
;
144 if (sock
->state
!= SS_UNCONNECTED
) return -EINVAL
;
145 if (vcc
->flags
& ATM_VF_SESSION
) return -EINVAL
;
146 addr
= (struct sockaddr_atmsvc
*) sockaddr
;
147 if (addr
->sas_family
!= AF_ATMSVC
) return -EAFNOSUPPORT
;
148 if (!(vcc
->flags
& ATM_VF_HASQOS
)) return -EBADFD
;
149 if (vcc
->qos
.txtp
.traffic_class
== ATM_ANYCLASS
||
150 vcc
->qos
.rxtp
.traffic_class
== ATM_ANYCLASS
)
152 if (!vcc
->qos
.txtp
.traffic_class
&&
153 !vcc
->qos
.rxtp
.traffic_class
) return -EINVAL
;
155 vcc
->reply
= WAITING
;
156 sigd_enq(vcc
,as_connect
,NULL
,NULL
,&vcc
->remote
);
157 if (flags
& O_NONBLOCK
) {
158 sock
->state
= SS_CONNECTING
;
161 while (vcc
->reply
== WAITING
&& sigd
) {
162 interruptible_sleep_on(&vcc
->sleep
);
163 if (signal_pending(current
)) {
164 DPRINTK("*ABORT*\n");
167 * Kernel ---close--> Demon
168 * Kernel <--close--- Demon
170 * Kernel ---close--> Demon
171 * Kernel <--error--- Demon
173 * Kernel ---close--> Demon
174 * Kernel <--okay---- Demon
175 * Kernel <--close--- Demon
177 sigd_enq(vcc
,as_close
,NULL
,NULL
,NULL
);
178 while (vcc
->reply
== WAITING
&& sigd
)
179 sleep_on(&vcc
->sleep
);
181 while (!(vcc
->flags
& ATM_VF_RELEASED
)
182 && sigd
) sleep_on(&vcc
->sleep
);
183 vcc
->flags
&= ~(ATM_VF_REGIS
| ATM_VF_RELEASED
185 /* we're gone now but may connect later */
189 if (!sigd
) return -EUNATCH
;
190 if (vcc
->reply
) return vcc
->reply
;
195 * #ifndef CONFIG_SINGLE_SIGITF
197 vcc
->qos
.txtp
.max_pcr
= SELECT_TOP_PCR(vcc
->qos
.txtp
);
198 vcc
->qos
.txtp
.pcr
= 0;
199 vcc
->qos
.txtp
.min_pcr
= 0;
203 if (!(error
= atm_connect(sock
,vcc
->itf
,vcc
->vpi
,vcc
->vci
)))
204 sock
->state
= SS_CONNECTED
;
205 else (void) svc_disconnect(vcc
);
210 static int svc_listen(struct socket
*sock
,int backlog
)
212 struct atm_vcc
*vcc
= ATM_SD(sock
);
214 DPRINTK("svc_listen %p\n",vcc
);
215 /* let server handle listen on unbound sockets */
216 if (vcc
->flags
& ATM_VF_SESSION
) return -EINVAL
;
217 vcc
->reply
= WAITING
;
218 sigd_enq(vcc
,as_listen
,NULL
,NULL
,&vcc
->local
);
219 while (vcc
->reply
== WAITING
&& sigd
) sleep_on(&vcc
->sleep
);
220 if (!sigd
) return -EUNATCH
;
221 vcc
->flags
|= ATM_VF_LISTEN
;
222 vcc
->backlog_quota
= backlog
> 0 ? backlog
: ATM_BACKLOG_DEFAULT
;
227 static int svc_accept(struct socket
*sock
,struct socket
*newsock
,int flags
)
230 struct atmsvc_msg
*msg
;
231 struct atm_vcc
*old_vcc
= ATM_SD(sock
);
232 struct atm_vcc
*new_vcc
;
235 error
= svc_create(newsock
,0);
239 new_vcc
= ATM_SD(newsock
);
241 DPRINTK("svc_accept %p -> %p\n",old_vcc
,new_vcc
);
243 while (!(skb
= skb_dequeue(&old_vcc
->listenq
)) && sigd
) {
244 if (old_vcc
->flags
& ATM_VF_RELEASED
) break;
245 if (old_vcc
->flags
& ATM_VF_CLOSE
)
246 return old_vcc
->reply
;
247 if (flags
& O_NONBLOCK
) return -EAGAIN
;
248 interruptible_sleep_on(&old_vcc
->sleep
);
249 if (signal_pending(current
)) return -ERESTARTSYS
;
251 if (!skb
) return -EUNATCH
;
252 msg
= (struct atmsvc_msg
*) skb
->data
;
253 new_vcc
->qos
= msg
->qos
;
254 new_vcc
->flags
|= ATM_VF_HASQOS
;
255 new_vcc
->remote
= msg
->svc
;
256 new_vcc
->sap
= msg
->sap
;
257 error
= atm_connect(newsock
,msg
->pvc
.sap_addr
.itf
,
258 msg
->pvc
.sap_addr
.vpi
,msg
->pvc
.sap_addr
.vci
);
260 old_vcc
->backlog_quota
++;
262 sigd_enq(NULL
,as_reject
,old_vcc
,NULL
,NULL
);
263 /* @@@ should include the reason */
264 return error
== -EAGAIN
? -EBUSY
: error
;
266 /* wait should be short, so we ignore the non-blocking flag */
267 new_vcc
->reply
= WAITING
;
268 sigd_enq(new_vcc
,as_accept
,old_vcc
,NULL
,NULL
);
269 while (new_vcc
->reply
== WAITING
&& sigd
)
270 sleep_on(&new_vcc
->sleep
);
271 if (!sigd
) return -EUNATCH
;
272 if (!new_vcc
->reply
) break;
273 if (new_vcc
->reply
!= -ERESTARTSYS
) return new_vcc
->reply
;
275 newsock
->state
= SS_CONNECTED
;
280 static int svc_getname(struct socket
*sock
,struct sockaddr
*sockaddr
,
281 int *sockaddr_len
,int peer
)
283 struct sockaddr_atmsvc
*addr
;
285 *sockaddr_len
= sizeof(struct sockaddr_atmsvc
);
286 addr
= (struct sockaddr_atmsvc
*) sockaddr
;
287 memcpy(addr
,peer
? &ATM_SD(sock
)->remote
: &ATM_SD(sock
)->local
,
288 sizeof(struct sockaddr_atmsvc
));
293 int svc_change_qos(struct atm_vcc
*vcc
,struct atm_qos
*qos
)
295 struct atm_qos save_qos
;
297 vcc
->reply
= WAITING
;
298 save_qos
= vcc
->qos
; /* @@@ really gross hack ... */
300 sigd_enq(vcc
,as_modify
,NULL
,NULL
,&vcc
->local
);
302 while (vcc
->reply
== WAITING
&& !(vcc
->flags
& ATM_VF_RELEASED
) &&
303 sigd
) sleep_on(&vcc
->sleep
);
304 if (!sigd
) return -EUNATCH
;
309 static int svc_setsockopt(struct socket
*sock
,int level
,int optname
,
310 char *optval
,int optlen
)
314 if (!__SO_LEVEL_MATCH(optname
, level
) || optname
!= SO_ATMSAP
||
315 optlen
!= sizeof(struct atm_sap
))
316 return atm_setsockopt(sock
,level
,optname
,optval
,optlen
);
318 if (copy_from_user(&vcc
->sap
,optval
,optlen
)) return -EFAULT
;
319 vcc
->flags
|= ATM_VF_HASSAP
;
324 static int svc_getsockopt(struct socket
*sock
,int level
,int optname
,
325 char *optval
,int *optlen
)
329 if (!__SO_LEVEL_MATCH(optname
, level
) || optname
!= SO_ATMSAP
)
330 return atm_getsockopt(sock
,level
,optname
,optval
,optlen
);
331 if (get_user(len
,optlen
)) return -EFAULT
;
332 if (len
!= sizeof(struct atm_sap
)) return -EINVAL
;
333 return copy_to_user(optval
,&ATM_SD(sock
)->sap
,sizeof(struct atm_sap
)) ?
338 static struct proto_ops
SOCKOPS_WRAPPED(svc_proto_ops
) = {
359 #include <linux/smp_lock.h>
360 SOCKOPS_WRAP(svc_proto
, PF_ATMSVC
);
362 static int svc_create(struct socket
*sock
,int protocol
)
366 sock
->ops
= &svc_proto_ops
;
367 error
= atm_create(sock
,protocol
,AF_ATMSVC
);
368 if (error
) return error
;
369 ATM_SD(sock
)->callback
= svc_callback
;
370 ATM_SD(sock
)->local
.sas_family
= AF_ATMSVC
;
371 ATM_SD(sock
)->remote
.sas_family
= AF_ATMSVC
;
376 static struct net_proto_family svc_family_ops
= {
379 0, /* no authentication */
380 0, /* no encryption */
381 0 /* no encrypt_net */
386 * Initialize the ATM SVC protocol family
389 void __init
atmsvc_proto_init(struct net_proto
*pro
)
391 if (sock_register(&svc_family_ops
) < 0) {
392 printk(KERN_ERR
"ATMSVC: can't register");