~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/net/atm/svc.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* net/atm/svc.c - ATM SVC sockets */
  2 
  3 /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
  4 
  5 
  6 #include <linux/string.h>
  7 #include <linux/net.h>          /* struct socket, struct net_proto,
  8                                    struct proto_ops */
  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 <linux/bitops.h>
 21 #include <net/sock.h>           /* for sock_no_* */
 22 #include <asm/uaccess.h>
 23 
 24 #include "resources.h"
 25 #include "common.h"             /* common for PVCs and SVCs */
 26 #include "signaling.h"
 27 #include "addr.h"
 28 
 29 
 30 #if 0
 31 #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
 32 #else
 33 #define DPRINTK(format,args...)
 34 #endif
 35 
 36 
 37 static int svc_create(struct socket *sock,int protocol);
 38 
 39 
 40 /*
 41  * Note: since all this is still nicely synchronized with the signaling demon,
 42  *       there's no need to protect sleep loops with clis. If signaling is
 43  *       moved into the kernel, that would change.
 44  */
 45 
 46 
 47 void svc_callback(struct atm_vcc *vcc)
 48 {
 49         wake_up(&vcc->sleep);
 50 }
 51 
 52 
 53 
 54 
 55 static int svc_shutdown(struct socket *sock,int how)
 56 {
 57         return 0;
 58 }
 59 
 60 
 61 static void svc_disconnect(struct atm_vcc *vcc)
 62 {
 63         DECLARE_WAITQUEUE(wait,current);
 64         struct sk_buff *skb;
 65 
 66         DPRINTK("svc_disconnect %p\n",vcc);
 67         if (test_bit(ATM_VF_REGIS,&vcc->flags)) {
 68                 sigd_enq(vcc,as_close,NULL,NULL,NULL);
 69                 add_wait_queue(&vcc->sleep,&wait);
 70                 while (!test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) {
 71                         set_current_state(TASK_UNINTERRUPTIBLE);
 72                         schedule();
 73                 }
 74                 remove_wait_queue(&vcc->sleep,&wait);
 75         }
 76         /* beware - socket is still in use by atmsigd until the last
 77            as_indicate has been answered */
 78         while ((skb = skb_dequeue(&vcc->listenq))) {
 79                 DPRINTK("LISTEN REL\n");
 80                 sigd_enq2(NULL,as_reject,vcc,NULL,NULL,&vcc->qos,0);
 81                 dev_kfree_skb(skb);
 82         }
 83         clear_bit(ATM_VF_REGIS,&vcc->flags);
 84         clear_bit(ATM_VF_RELEASED,&vcc->flags);
 85         clear_bit(ATM_VF_CLOSE,&vcc->flags);
 86         /* ... may retry later */
 87 }
 88 
 89 
 90 static int svc_release(struct socket *sock)
 91 {
 92         struct atm_vcc *vcc;
 93 
 94         if (!sock->sk) return 0;
 95         vcc = ATM_SD(sock);
 96         DPRINTK("svc_release %p\n",vcc);
 97         clear_bit(ATM_VF_READY,&vcc->flags);
 98         atm_release_vcc_sk(sock->sk,0);
 99         svc_disconnect(vcc);
100             /* VCC pointer is used as a reference, so we must not free it
101                (thereby subjecting it to re-use) before all pending connections
102                 are closed */
103         free_atm_vcc_sk(sock->sk);
104         return 0;
105 }
106 
107 
108 static int svc_bind(struct socket *sock,struct sockaddr *sockaddr,
109     int sockaddr_len)
110 {
111         DECLARE_WAITQUEUE(wait,current);
112         struct sockaddr_atmsvc *addr;
113         struct atm_vcc *vcc;
114 
115         if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) return -EINVAL;
116         if (sock->state == SS_CONNECTED) return -EISCONN;
117         if (sock->state != SS_UNCONNECTED) return -EINVAL;
118         vcc = ATM_SD(sock);
119         if (test_bit(ATM_VF_SESSION,&vcc->flags)) return -EINVAL;
120         addr = (struct sockaddr_atmsvc *) sockaddr;
121         if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT;
122         clear_bit(ATM_VF_BOUND,&vcc->flags);
123             /* failing rebind will kill old binding */
124         /* @@@ check memory (de)allocation on rebind */
125         if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD;
126         vcc->local = *addr;
127         vcc->reply = WAITING;
128         sigd_enq(vcc,as_bind,NULL,NULL,&vcc->local);
129         add_wait_queue(&vcc->sleep,&wait);
130         while (vcc->reply == WAITING && sigd) {
131                 set_current_state(TASK_UNINTERRUPTIBLE);
132                 schedule();
133         }
134         remove_wait_queue(&vcc->sleep,&wait);
135         clear_bit(ATM_VF_REGIS,&vcc->flags); /* doesn't count */
136         if (!sigd) return -EUNATCH;
137         if (!vcc->reply) set_bit(ATM_VF_BOUND,&vcc->flags);
138         return vcc->reply;
139 }
140 
141 
142 static int svc_connect(struct socket *sock,struct sockaddr *sockaddr,
143     int sockaddr_len,int flags)
144 {
145         DECLARE_WAITQUEUE(wait,current);
146         struct sockaddr_atmsvc *addr;
147         struct atm_vcc *vcc = ATM_SD(sock);
148         int error;
149 
150         DPRINTK("svc_connect %p\n",vcc);
151         if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) return -EINVAL;
152         if (sock->state == SS_CONNECTED) return -EISCONN;
153         if (sock->state == SS_CONNECTING) {
154                 if (vcc->reply == WAITING) return -EALREADY;
155                 sock->state = SS_UNCONNECTED;
156                 if (vcc->reply) return vcc->reply;
157         }
158         else {
159                 int error;
160 
161                 if (sock->state != SS_UNCONNECTED) return -EINVAL;
162                 if (test_bit(ATM_VF_SESSION,&vcc->flags)) return -EINVAL;
163                 addr = (struct sockaddr_atmsvc *) sockaddr;
164                 if (addr->sas_family != AF_ATMSVC) return -EAFNOSUPPORT;
165                 if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD;
166                 if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS ||
167                     vcc->qos.rxtp.traffic_class == ATM_ANYCLASS)
168                         return -EINVAL;
169                 if (!vcc->qos.txtp.traffic_class &&
170                     !vcc->qos.rxtp.traffic_class) return -EINVAL;
171                 vcc->remote = *addr;
172                 vcc->reply = WAITING;
173                 sigd_enq(vcc,as_connect,NULL,NULL,&vcc->remote);
174                 if (flags & O_NONBLOCK) {
175                         sock->state = SS_CONNECTING;
176                         return -EINPROGRESS;
177                 }
178                 add_wait_queue(&vcc->sleep,&wait);
179                 error = 0;
180                 while (vcc->reply == WAITING && sigd) {
181                         set_current_state(TASK_INTERRUPTIBLE);
182                         schedule();
183                         if (!signal_pending(current)) continue;
184                         DPRINTK("*ABORT*\n");
185                         /*
186                          * This is tricky:
187                          *   Kernel ---close--> Demon
188                          *   Kernel <--close--- Demon
189                          * or
190                          *   Kernel ---close--> Demon
191                          *   Kernel <--error--- Demon
192                          * or
193                          *   Kernel ---close--> Demon
194                          *   Kernel <--okay---- Demon
195                          *   Kernel <--close--- Demon
196                          */
197                         sigd_enq(vcc,as_close,NULL,NULL,NULL);
198                         while (vcc->reply == WAITING && sigd) {
199                                 set_current_state(TASK_UNINTERRUPTIBLE);
200                                 schedule();
201                         }
202                         if (!vcc->reply)
203                                 while (!test_bit(ATM_VF_RELEASED,&vcc->flags)
204                                     && sigd) {
205                                         set_current_state(TASK_UNINTERRUPTIBLE);
206                                         schedule();
207                                 }
208                         clear_bit(ATM_VF_REGIS,&vcc->flags);
209                         clear_bit(ATM_VF_RELEASED,&vcc->flags);
210                         clear_bit(ATM_VF_CLOSE,&vcc->flags);
211                             /* we're gone now but may connect later */
212                         error = -EINTR;
213                         break;
214                 }
215                 remove_wait_queue(&vcc->sleep,&wait);
216                 if (error) return error;
217                 if (!sigd) return -EUNATCH;
218                 if (vcc->reply) return vcc->reply;
219         }
220 /*
221  * Not supported yet
222  *
223  * #ifndef CONFIG_SINGLE_SIGITF
224  */
225         vcc->qos.txtp.max_pcr = SELECT_TOP_PCR(vcc->qos.txtp);
226         vcc->qos.txtp.pcr = 0;
227         vcc->qos.txtp.min_pcr = 0;
228 /*
229  * #endif
230  */
231         if (!(error = atm_connect(sock,vcc->itf,vcc->vpi,vcc->vci)))
232                 sock->state = SS_CONNECTED;
233         else (void) svc_disconnect(vcc);
234         return error;
235 }
236 
237 
238 static int svc_listen(struct socket *sock,int backlog)
239 {
240         DECLARE_WAITQUEUE(wait,current);
241         struct atm_vcc *vcc = ATM_SD(sock);
242 
243         DPRINTK("svc_listen %p\n",vcc);
244         /* let server handle listen on unbound sockets */
245         if (test_bit(ATM_VF_SESSION,&vcc->flags)) return -EINVAL;
246         vcc->reply = WAITING;
247         sigd_enq(vcc,as_listen,NULL,NULL,&vcc->local);
248         add_wait_queue(&vcc->sleep,&wait);
249         while (vcc->reply == WAITING && sigd) {
250                 set_current_state(TASK_UNINTERRUPTIBLE);
251                 schedule();
252         }
253         remove_wait_queue(&vcc->sleep,&wait);
254         if (!sigd) return -EUNATCH;
255         set_bit(ATM_VF_LISTEN,&vcc->flags);
256         vcc->backlog_quota = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT;
257         return vcc->reply;
258 }
259 
260 
261 static int svc_accept(struct socket *sock,struct socket *newsock,int flags)
262 {
263         struct sk_buff *skb;
264         struct atmsvc_msg *msg;
265         struct atm_vcc *old_vcc = ATM_SD(sock);
266         struct atm_vcc *new_vcc;
267         int error;
268 
269         error = svc_create(newsock,0);
270         if (error)
271                 return error;
272 
273         new_vcc = ATM_SD(newsock);
274 
275         DPRINTK("svc_accept %p -> %p\n",old_vcc,new_vcc);
276         while (1) {
277                 DECLARE_WAITQUEUE(wait,current);
278 
279                 add_wait_queue(&old_vcc->sleep,&wait);
280                 while (!(skb = skb_dequeue(&old_vcc->listenq)) && sigd) {
281                         if (test_bit(ATM_VF_RELEASED,&old_vcc->flags)) break;
282                         if (test_bit(ATM_VF_CLOSE,&old_vcc->flags)) {
283                                 error = old_vcc->reply;
284                                 break;
285                         }
286                         if (flags & O_NONBLOCK) {
287                                 error = -EAGAIN;
288                                 break;
289                         }
290                         set_current_state(TASK_INTERRUPTIBLE);
291                         schedule();
292                         if (signal_pending(current)) {
293                                 error = -ERESTARTSYS;
294                                 break;
295                         }
296                 }
297                 remove_wait_queue(&old_vcc->sleep,&wait);
298                 if (error) return error;
299                 if (!skb) return -EUNATCH;
300                 msg = (struct atmsvc_msg *) skb->data;
301                 new_vcc->qos = msg->qos;
302                 set_bit(ATM_VF_HASQOS,&new_vcc->flags);
303                 new_vcc->remote = msg->svc;
304                 new_vcc->local = msg->local;
305                 new_vcc->sap = msg->sap;
306                 error = atm_connect(newsock,msg->pvc.sap_addr.itf,
307                     msg->pvc.sap_addr.vpi,msg->pvc.sap_addr.vci);
308                 dev_kfree_skb(skb);
309                 old_vcc->backlog_quota++;
310                 if (error) {
311                         sigd_enq2(NULL,as_reject,old_vcc,NULL,NULL,
312                             &old_vcc->qos,error);
313                         return error == -EAGAIN ? -EBUSY : error;
314                 }
315                 /* wait should be short, so we ignore the non-blocking flag */
316                 new_vcc->reply = WAITING;
317                 sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL);
318                 add_wait_queue(&new_vcc->sleep,&wait);
319                 while (new_vcc->reply == WAITING && sigd) {
320                         set_current_state(TASK_UNINTERRUPTIBLE);
321                         schedule();
322                 }
323                 remove_wait_queue(&new_vcc->sleep,&wait);
324                 if (!sigd) return -EUNATCH;
325                 if (!new_vcc->reply) break;
326                 if (new_vcc->reply != -ERESTARTSYS) return new_vcc->reply;
327         }
328         newsock->state = SS_CONNECTED;
329         return 0;
330 }
331 
332 
333 static int svc_getname(struct socket *sock,struct sockaddr *sockaddr,
334     int *sockaddr_len,int peer)
335 {
336         struct sockaddr_atmsvc *addr;
337 
338         *sockaddr_len = sizeof(struct sockaddr_atmsvc);
339         addr = (struct sockaddr_atmsvc *) sockaddr;
340         memcpy(addr,peer ? &ATM_SD(sock)->remote : &ATM_SD(sock)->local,
341             sizeof(struct sockaddr_atmsvc));
342         return 0;
343 }
344 
345 
346 int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos)
347 {
348         DECLARE_WAITQUEUE(wait,current);
349 
350         vcc->reply = WAITING;
351         sigd_enq2(vcc,as_modify,NULL,NULL,&vcc->local,qos,0);
352         add_wait_queue(&vcc->sleep,&wait);
353         while (vcc->reply == WAITING && !test_bit(ATM_VF_RELEASED,&vcc->flags)
354             && sigd) {
355                 set_current_state(TASK_UNINTERRUPTIBLE);
356                 schedule();
357         }
358         remove_wait_queue(&vcc->sleep,&wait);
359         if (!sigd) return -EUNATCH;
360         return vcc->reply;
361 }
362 
363 
364 static int svc_setsockopt(struct socket *sock,int level,int optname,
365     char *optval,int optlen)
366 {
367         struct atm_vcc *vcc;
368 
369         if (!__SO_LEVEL_MATCH(optname, level) || optname != SO_ATMSAP ||
370             optlen != sizeof(struct atm_sap))
371                 return atm_setsockopt(sock,level,optname,optval,optlen);
372         vcc = ATM_SD(sock);
373         if (copy_from_user(&vcc->sap,optval,optlen)) return -EFAULT;
374         set_bit(ATM_VF_HASSAP,&vcc->flags);
375         return 0;
376 }
377 
378 
379 static int svc_getsockopt(struct socket *sock,int level,int optname,
380     char *optval,int *optlen)
381 {
382         int len;
383 
384         if (!__SO_LEVEL_MATCH(optname, level) || optname != SO_ATMSAP)
385                 return atm_getsockopt(sock,level,optname,optval,optlen);
386         if (get_user(len,optlen)) return -EFAULT;
387         if (len != sizeof(struct atm_sap)) return -EINVAL;
388         return copy_to_user(optval,&ATM_SD(sock)->sap,sizeof(struct atm_sap)) ?
389             -EFAULT : 0;
390 }
391 
392 
393 static struct proto_ops SOCKOPS_WRAPPED(svc_proto_ops) = {
394         family:         PF_ATMSVC,
395 
396         release:        svc_release,
397         bind:           svc_bind,
398         connect:        svc_connect,
399         socketpair:     sock_no_socketpair,
400         accept:         svc_accept,
401         getname:        svc_getname,
402         poll:           atm_poll,
403         ioctl:          atm_ioctl,
404         listen:         svc_listen,
405         shutdown:       svc_shutdown,
406         setsockopt:     svc_setsockopt,
407         getsockopt:     svc_getsockopt,
408         sendmsg:        atm_sendmsg,
409         recvmsg:        atm_recvmsg,
410         mmap:           sock_no_mmap,
411 };
412 
413 
414 #include <linux/smp_lock.h>
415 SOCKOPS_WRAP(svc_proto, PF_ATMSVC);
416 
417 static int svc_create(struct socket *sock,int protocol)
418 {
419         int error;
420 
421         sock->ops = &svc_proto_ops;
422         error = atm_create(sock,protocol,AF_ATMSVC);
423         if (error) return error;
424         ATM_SD(sock)->callback = svc_callback;
425         ATM_SD(sock)->local.sas_family = AF_ATMSVC;
426         ATM_SD(sock)->remote.sas_family = AF_ATMSVC;
427         return 0;
428 }
429 
430 
431 static struct net_proto_family svc_family_ops = {
432         PF_ATMSVC,
433         svc_create,
434         0,                      /* no authentication */
435         0,                      /* no encryption */
436         0                       /* no encrypt_net */
437 };
438 
439 
440 /*
441  *      Initialize the ATM SVC protocol family
442  */
443 
444 static int __init atmsvc_init(void)
445 {
446         if (sock_register(&svc_family_ops) < 0) {
447                 printk(KERN_ERR "ATMSVC: can't register");
448                 return -1;
449         }
450         return 0;
451 }
452 
453 module_init(atmsvc_init);
454 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.