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

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

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /* net/atm/svc.c - ATM SVC sockets */
  3 
  4 /* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
  5 
  6 #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
  7 
  8 #include <linux/string.h>
  9 #include <linux/net.h>          /* struct socket, struct proto_ops */
 10 #include <linux/errno.h>        /* error codes */
 11 #include <linux/kernel.h>       /* printk */
 12 #include <linux/skbuff.h>
 13 #include <linux/wait.h>
 14 #include <linux/sched/signal.h>
 15 #include <linux/fcntl.h>        /* O_NONBLOCK */
 16 #include <linux/init.h>
 17 #include <linux/atm.h>          /* ATM stuff */
 18 #include <linux/atmsap.h>
 19 #include <linux/atmsvc.h>
 20 #include <linux/atmdev.h>
 21 #include <linux/bitops.h>
 22 #include <net/sock.h>           /* for sock_no_* */
 23 #include <linux/uaccess.h>
 24 #include <linux/export.h>
 25 
 26 #include "resources.h"
 27 #include "common.h"             /* common for PVCs and SVCs */
 28 #include "signaling.h"
 29 #include "addr.h"
 30 
 31 #ifdef CONFIG_COMPAT
 32 /* It actually takes struct sockaddr_atmsvc, not struct atm_iobuf */
 33 #define COMPAT_ATM_ADDPARTY _IOW('a', ATMIOC_SPECIAL + 4, struct compat_atm_iobuf)
 34 #endif
 35 
 36 static int svc_create(struct net *net, struct socket *sock, int protocol,
 37                       int kern);
 38 
 39 /*
 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.
 43  */
 44 
 45 
 46 static int svc_shutdown(struct socket *sock, int how)
 47 {
 48         return 0;
 49 }
 50 
 51 static void svc_disconnect(struct atm_vcc *vcc)
 52 {
 53         DEFINE_WAIT(wait);
 54         struct sk_buff *skb;
 55         struct sock *sk = sk_atm(vcc);
 56 
 57         pr_debug("%p\n", vcc);
 58         if (test_bit(ATM_VF_REGIS, &vcc->flags)) {
 59                 sigd_enq(vcc, as_close, NULL, NULL, NULL);
 60                 for (;;) {
 61                         prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
 62                         if (test_bit(ATM_VF_RELEASED, &vcc->flags) || !sigd)
 63                                 break;
 64                         schedule();
 65                 }
 66                 finish_wait(sk_sleep(sk), &wait);
 67         }
 68         /* beware - socket is still in use by atmsigd until the last
 69            as_indicate has been answered */
 70         while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
 71                 atm_return(vcc, skb->truesize);
 72                 pr_debug("LISTEN REL\n");
 73                 sigd_enq2(NULL, as_reject, vcc, NULL, NULL, &vcc->qos, 0);
 74                 dev_kfree_skb(skb);
 75         }
 76         clear_bit(ATM_VF_REGIS, &vcc->flags);
 77         /* ... may retry later */
 78 }
 79 
 80 static int svc_release(struct socket *sock)
 81 {
 82         struct sock *sk = sock->sk;
 83         struct atm_vcc *vcc;
 84 
 85         if (sk) {
 86                 vcc = ATM_SD(sock);
 87                 pr_debug("%p\n", vcc);
 88                 clear_bit(ATM_VF_READY, &vcc->flags);
 89                 /*
 90                  * VCC pointer is used as a reference,
 91                  * so we must not free it (thereby subjecting it to re-use)
 92                  * before all pending connections are closed
 93                  */
 94                 svc_disconnect(vcc);
 95                 vcc_release(sock);
 96         }
 97         return 0;
 98 }
 99 
100 static int svc_bind(struct socket *sock, struct sockaddr *sockaddr,
101                     int sockaddr_len)
102 {
103         DEFINE_WAIT(wait);
104         struct sock *sk = sock->sk;
105         struct sockaddr_atmsvc *addr;
106         struct atm_vcc *vcc;
107         int error;
108 
109         if (sockaddr_len != sizeof(struct sockaddr_atmsvc))
110                 return -EINVAL;
111         lock_sock(sk);
112         if (sock->state == SS_CONNECTED) {
113                 error = -EISCONN;
114                 goto out;
115         }
116         if (sock->state != SS_UNCONNECTED) {
117                 error = -EINVAL;
118                 goto out;
119         }
120         vcc = ATM_SD(sock);
121         addr = (struct sockaddr_atmsvc *) sockaddr;
122         if (addr->sas_family != AF_ATMSVC) {
123                 error = -EAFNOSUPPORT;
124                 goto out;
125         }
126         clear_bit(ATM_VF_BOUND, &vcc->flags);
127             /* failing rebind will kill old binding */
128         /* @@@ check memory (de)allocation on rebind */
129         if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) {
130                 error = -EBADFD;
131                 goto out;
132         }
133         vcc->local = *addr;
134         set_bit(ATM_VF_WAITING, &vcc->flags);
135         sigd_enq(vcc, as_bind, NULL, NULL, &vcc->local);
136         for (;;) {
137                 prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
138                 if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd)
139                         break;
140                 schedule();
141         }
142         finish_wait(sk_sleep(sk), &wait);
143         clear_bit(ATM_VF_REGIS, &vcc->flags); /* doesn't count */
144         if (!sigd) {
145                 error = -EUNATCH;
146                 goto out;
147         }
148         if (!sk->sk_err)
149                 set_bit(ATM_VF_BOUND, &vcc->flags);
150         error = -sk->sk_err;
151 out:
152         release_sock(sk);
153         return error;
154 }
155 
156 static int svc_connect(struct socket *sock, struct sockaddr *sockaddr,
157                        int sockaddr_len, int flags)
158 {
159         DEFINE_WAIT(wait);
160         struct sock *sk = sock->sk;
161         struct sockaddr_atmsvc *addr;
162         struct atm_vcc *vcc = ATM_SD(sock);
163         int error;
164 
165         pr_debug("%p\n", vcc);
166         lock_sock(sk);
167         if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) {
168                 error = -EINVAL;
169                 goto out;
170         }
171 
172         switch (sock->state) {
173         default:
174                 error = -EINVAL;
175                 goto out;
176         case SS_CONNECTED:
177                 error = -EISCONN;
178                 goto out;
179         case SS_CONNECTING:
180                 if (test_bit(ATM_VF_WAITING, &vcc->flags)) {
181                         error = -EALREADY;
182                         goto out;
183                 }
184                 sock->state = SS_UNCONNECTED;
185                 if (sk->sk_err) {
186                         error = -sk->sk_err;
187                         goto out;
188                 }
189                 break;
190         case SS_UNCONNECTED:
191                 addr = (struct sockaddr_atmsvc *) sockaddr;
192                 if (addr->sas_family != AF_ATMSVC) {
193                         error = -EAFNOSUPPORT;
194                         goto out;
195                 }
196                 if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) {
197                         error = -EBADFD;
198                         goto out;
199                 }
200                 if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS ||
201                     vcc->qos.rxtp.traffic_class == ATM_ANYCLASS) {
202                         error = -EINVAL;
203                         goto out;
204                 }
205                 if (!vcc->qos.txtp.traffic_class &&
206                     !vcc->qos.rxtp.traffic_class) {
207                         error = -EINVAL;
208                         goto out;
209                 }
210                 vcc->remote = *addr;
211                 set_bit(ATM_VF_WAITING, &vcc->flags);
212                 sigd_enq(vcc, as_connect, NULL, NULL, &vcc->remote);
213                 if (flags & O_NONBLOCK) {
214                         sock->state = SS_CONNECTING;
215                         error = -EINPROGRESS;
216                         goto out;
217                 }
218                 error = 0;
219                 prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
220                 while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
221                         schedule();
222                         if (!signal_pending(current)) {
223                                 prepare_to_wait(sk_sleep(sk), &wait,
224                                                 TASK_INTERRUPTIBLE);
225                                 continue;
226                         }
227                         pr_debug("*ABORT*\n");
228                         /*
229                          * This is tricky:
230                          *   Kernel ---close--> Demon
231                          *   Kernel <--close--- Demon
232                          * or
233                          *   Kernel ---close--> Demon
234                          *   Kernel <--error--- Demon
235                          * or
236                          *   Kernel ---close--> Demon
237                          *   Kernel <--okay---- Demon
238                          *   Kernel <--close--- Demon
239                          */
240                         sigd_enq(vcc, as_close, NULL, NULL, NULL);
241                         while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
242                                 prepare_to_wait(sk_sleep(sk), &wait,
243                                                 TASK_INTERRUPTIBLE);
244                                 schedule();
245                         }
246                         if (!sk->sk_err)
247                                 while (!test_bit(ATM_VF_RELEASED, &vcc->flags) &&
248                                        sigd) {
249                                         prepare_to_wait(sk_sleep(sk), &wait,
250                                                         TASK_INTERRUPTIBLE);
251                                         schedule();
252                                 }
253                         clear_bit(ATM_VF_REGIS, &vcc->flags);
254                         clear_bit(ATM_VF_RELEASED, &vcc->flags);
255                         clear_bit(ATM_VF_CLOSE, &vcc->flags);
256                             /* we're gone now but may connect later */
257                         error = -EINTR;
258                         break;
259                 }
260                 finish_wait(sk_sleep(sk), &wait);
261                 if (error)
262                         goto out;
263                 if (!sigd) {
264                         error = -EUNATCH;
265                         goto out;
266                 }
267                 if (sk->sk_err) {
268                         error = -sk->sk_err;
269                         goto out;
270                 }
271         }
272 
273         vcc->qos.txtp.max_pcr = SELECT_TOP_PCR(vcc->qos.txtp);
274         vcc->qos.txtp.pcr = 0;
275         vcc->qos.txtp.min_pcr = 0;
276 
277         error = vcc_connect(sock, vcc->itf, vcc->vpi, vcc->vci);
278         if (!error)
279                 sock->state = SS_CONNECTED;
280         else
281                 (void)svc_disconnect(vcc);
282 out:
283         release_sock(sk);
284         return error;
285 }
286 
287 static int svc_listen(struct socket *sock, int backlog)
288 {
289         DEFINE_WAIT(wait);
290         struct sock *sk = sock->sk;
291         struct atm_vcc *vcc = ATM_SD(sock);
292         int error;
293 
294         pr_debug("%p\n", vcc);
295         lock_sock(sk);
296         /* let server handle listen on unbound sockets */
297         if (test_bit(ATM_VF_SESSION, &vcc->flags)) {
298                 error = -EINVAL;
299                 goto out;
300         }
301         if (test_bit(ATM_VF_LISTEN, &vcc->flags)) {
302                 error = -EADDRINUSE;
303                 goto out;
304         }
305         set_bit(ATM_VF_WAITING, &vcc->flags);
306         sigd_enq(vcc, as_listen, NULL, NULL, &vcc->local);
307         for (;;) {
308                 prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
309                 if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd)
310                         break;
311                 schedule();
312         }
313         finish_wait(sk_sleep(sk), &wait);
314         if (!sigd) {
315                 error = -EUNATCH;
316                 goto out;
317         }
318         set_bit(ATM_VF_LISTEN, &vcc->flags);
319         vcc_insert_socket(sk);
320         sk->sk_max_ack_backlog = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT;
321         error = -sk->sk_err;
322 out:
323         release_sock(sk);
324         return error;
325 }
326 
327 static int svc_accept(struct socket *sock, struct socket *newsock,
328                       struct proto_accept_arg *arg)
329 {
330         struct sock *sk = sock->sk;
331         struct sk_buff *skb;
332         struct atmsvc_msg *msg;
333         struct atm_vcc *old_vcc = ATM_SD(sock);
334         struct atm_vcc *new_vcc;
335         int error;
336 
337         lock_sock(sk);
338 
339         error = svc_create(sock_net(sk), newsock, 0, arg->kern);
340         if (error)
341                 goto out;
342 
343         new_vcc = ATM_SD(newsock);
344 
345         pr_debug("%p -> %p\n", old_vcc, new_vcc);
346         while (1) {
347                 DEFINE_WAIT(wait);
348 
349                 prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
350                 while (!(skb = skb_dequeue(&sk->sk_receive_queue)) &&
351                        sigd) {
352                         if (test_bit(ATM_VF_RELEASED, &old_vcc->flags))
353                                 break;
354                         if (test_bit(ATM_VF_CLOSE, &old_vcc->flags)) {
355                                 error = -sk->sk_err;
356                                 break;
357                         }
358                         if (arg->flags & O_NONBLOCK) {
359                                 error = -EAGAIN;
360                                 break;
361                         }
362                         release_sock(sk);
363                         schedule();
364                         lock_sock(sk);
365                         if (signal_pending(current)) {
366                                 error = -ERESTARTSYS;
367                                 break;
368                         }
369                         prepare_to_wait(sk_sleep(sk), &wait,
370                                         TASK_INTERRUPTIBLE);
371                 }
372                 finish_wait(sk_sleep(sk), &wait);
373                 if (error)
374                         goto out;
375                 if (!skb) {
376                         error = -EUNATCH;
377                         goto out;
378                 }
379                 msg = (struct atmsvc_msg *)skb->data;
380                 new_vcc->qos = msg->qos;
381                 set_bit(ATM_VF_HASQOS, &new_vcc->flags);
382                 new_vcc->remote = msg->svc;
383                 new_vcc->local = msg->local;
384                 new_vcc->sap = msg->sap;
385                 error = vcc_connect(newsock, msg->pvc.sap_addr.itf,
386                                     msg->pvc.sap_addr.vpi,
387                                     msg->pvc.sap_addr.vci);
388                 dev_kfree_skb(skb);
389                 sk_acceptq_removed(sk);
390                 if (error) {
391                         sigd_enq2(NULL, as_reject, old_vcc, NULL, NULL,
392                                   &old_vcc->qos, error);
393                         error = error == -EAGAIN ? -EBUSY : error;
394                         goto out;
395                 }
396                 /* wait should be short, so we ignore the non-blocking flag */
397                 set_bit(ATM_VF_WAITING, &new_vcc->flags);
398                 sigd_enq(new_vcc, as_accept, old_vcc, NULL, NULL);
399                 for (;;) {
400                         prepare_to_wait(sk_sleep(sk_atm(new_vcc)), &wait,
401                                         TASK_UNINTERRUPTIBLE);
402                         if (!test_bit(ATM_VF_WAITING, &new_vcc->flags) || !sigd)
403                                 break;
404                         release_sock(sk);
405                         schedule();
406                         lock_sock(sk);
407                 }
408                 finish_wait(sk_sleep(sk_atm(new_vcc)), &wait);
409                 if (!sigd) {
410                         error = -EUNATCH;
411                         goto out;
412                 }
413                 if (!sk_atm(new_vcc)->sk_err)
414                         break;
415                 if (sk_atm(new_vcc)->sk_err != ERESTARTSYS) {
416                         error = -sk_atm(new_vcc)->sk_err;
417                         goto out;
418                 }
419         }
420         newsock->state = SS_CONNECTED;
421 out:
422         release_sock(sk);
423         return error;
424 }
425 
426 static int svc_getname(struct socket *sock, struct sockaddr *sockaddr,
427                        int peer)
428 {
429         struct sockaddr_atmsvc *addr;
430 
431         addr = (struct sockaddr_atmsvc *) sockaddr;
432         memcpy(addr, peer ? &ATM_SD(sock)->remote : &ATM_SD(sock)->local,
433                sizeof(struct sockaddr_atmsvc));
434         return sizeof(struct sockaddr_atmsvc);
435 }
436 
437 int svc_change_qos(struct atm_vcc *vcc, struct atm_qos *qos)
438 {
439         struct sock *sk = sk_atm(vcc);
440         DEFINE_WAIT(wait);
441 
442         set_bit(ATM_VF_WAITING, &vcc->flags);
443         sigd_enq2(vcc, as_modify, NULL, NULL, &vcc->local, qos, 0);
444         for (;;) {
445                 prepare_to_wait(sk_sleep(sk), &wait, TASK_UNINTERRUPTIBLE);
446                 if (!test_bit(ATM_VF_WAITING, &vcc->flags) ||
447                     test_bit(ATM_VF_RELEASED, &vcc->flags) || !sigd) {
448                         break;
449                 }
450                 schedule();
451         }
452         finish_wait(sk_sleep(sk), &wait);
453         if (!sigd)
454                 return -EUNATCH;
455         return -sk->sk_err;
456 }
457 
458 static int svc_setsockopt(struct socket *sock, int level, int optname,
459                           sockptr_t optval, unsigned int optlen)
460 {
461         struct sock *sk = sock->sk;
462         struct atm_vcc *vcc = ATM_SD(sock);
463         int value, error = 0;
464 
465         lock_sock(sk);
466         switch (optname) {
467         case SO_ATMSAP:
468                 if (level != SOL_ATM || optlen != sizeof(struct atm_sap)) {
469                         error = -EINVAL;
470                         goto out;
471                 }
472                 if (copy_from_sockptr(&vcc->sap, optval, optlen)) {
473                         error = -EFAULT;
474                         goto out;
475                 }
476                 set_bit(ATM_VF_HASSAP, &vcc->flags);
477                 break;
478         case SO_MULTIPOINT:
479                 if (level != SOL_ATM || optlen != sizeof(int)) {
480                         error = -EINVAL;
481                         goto out;
482                 }
483                 if (copy_from_sockptr(&value, optval, sizeof(int))) {
484                         error = -EFAULT;
485                         goto out;
486                 }
487                 if (value == 1)
488                         set_bit(ATM_VF_SESSION, &vcc->flags);
489                 else if (value == 0)
490                         clear_bit(ATM_VF_SESSION, &vcc->flags);
491                 else
492                         error = -EINVAL;
493                 break;
494         default:
495                 error = vcc_setsockopt(sock, level, optname, optval, optlen);
496         }
497 
498 out:
499         release_sock(sk);
500         return error;
501 }
502 
503 static int svc_getsockopt(struct socket *sock, int level, int optname,
504                           char __user *optval, int __user *optlen)
505 {
506         struct sock *sk = sock->sk;
507         int error = 0, len;
508 
509         lock_sock(sk);
510         if (!__SO_LEVEL_MATCH(optname, level) || optname != SO_ATMSAP) {
511                 error = vcc_getsockopt(sock, level, optname, optval, optlen);
512                 goto out;
513         }
514         if (get_user(len, optlen)) {
515                 error = -EFAULT;
516                 goto out;
517         }
518         if (len != sizeof(struct atm_sap)) {
519                 error = -EINVAL;
520                 goto out;
521         }
522         if (copy_to_user(optval, &ATM_SD(sock)->sap, sizeof(struct atm_sap))) {
523                 error = -EFAULT;
524                 goto out;
525         }
526 out:
527         release_sock(sk);
528         return error;
529 }
530 
531 static int svc_addparty(struct socket *sock, struct sockaddr *sockaddr,
532                         int sockaddr_len, int flags)
533 {
534         DEFINE_WAIT(wait);
535         struct sock *sk = sock->sk;
536         struct atm_vcc *vcc = ATM_SD(sock);
537         int error;
538 
539         lock_sock(sk);
540         set_bit(ATM_VF_WAITING, &vcc->flags);
541         sigd_enq(vcc, as_addparty, NULL, NULL,
542                  (struct sockaddr_atmsvc *) sockaddr);
543         if (flags & O_NONBLOCK) {
544                 error = -EINPROGRESS;
545                 goto out;
546         }
547         pr_debug("added wait queue\n");
548         for (;;) {
549                 prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
550                 if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd)
551                         break;
552                 schedule();
553         }
554         finish_wait(sk_sleep(sk), &wait);
555         error = -xchg(&sk->sk_err_soft, 0);
556 out:
557         release_sock(sk);
558         return error;
559 }
560 
561 static int svc_dropparty(struct socket *sock, int ep_ref)
562 {
563         DEFINE_WAIT(wait);
564         struct sock *sk = sock->sk;
565         struct atm_vcc *vcc = ATM_SD(sock);
566         int error;
567 
568         lock_sock(sk);
569         set_bit(ATM_VF_WAITING, &vcc->flags);
570         sigd_enq2(vcc, as_dropparty, NULL, NULL, NULL, NULL, ep_ref);
571         for (;;) {
572                 prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
573                 if (!test_bit(ATM_VF_WAITING, &vcc->flags) || !sigd)
574                         break;
575                 schedule();
576         }
577         finish_wait(sk_sleep(sk), &wait);
578         if (!sigd) {
579                 error = -EUNATCH;
580                 goto out;
581         }
582         error = -xchg(&sk->sk_err_soft, 0);
583 out:
584         release_sock(sk);
585         return error;
586 }
587 
588 static int svc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
589 {
590         int error, ep_ref;
591         struct sockaddr_atmsvc sa;
592         struct atm_vcc *vcc = ATM_SD(sock);
593 
594         switch (cmd) {
595         case ATM_ADDPARTY:
596                 if (!test_bit(ATM_VF_SESSION, &vcc->flags))
597                         return -EINVAL;
598                 if (copy_from_user(&sa, (void __user *) arg, sizeof(sa)))
599                         return -EFAULT;
600                 error = svc_addparty(sock, (struct sockaddr *)&sa, sizeof(sa),
601                                      0);
602                 break;
603         case ATM_DROPPARTY:
604                 if (!test_bit(ATM_VF_SESSION, &vcc->flags))
605                         return -EINVAL;
606                 if (copy_from_user(&ep_ref, (void __user *) arg, sizeof(int)))
607                         return -EFAULT;
608                 error = svc_dropparty(sock, ep_ref);
609                 break;
610         default:
611                 error = vcc_ioctl(sock, cmd, arg);
612         }
613 
614         return error;
615 }
616 
617 #ifdef CONFIG_COMPAT
618 static int svc_compat_ioctl(struct socket *sock, unsigned int cmd,
619                             unsigned long arg)
620 {
621         /* The definition of ATM_ADDPARTY uses the size of struct atm_iobuf.
622            But actually it takes a struct sockaddr_atmsvc, which doesn't need
623            compat handling. So all we have to do is fix up cmd... */
624         if (cmd == COMPAT_ATM_ADDPARTY)
625                 cmd = ATM_ADDPARTY;
626 
627         if (cmd == ATM_ADDPARTY || cmd == ATM_DROPPARTY)
628                 return svc_ioctl(sock, cmd, arg);
629         else
630                 return vcc_compat_ioctl(sock, cmd, arg);
631 }
632 #endif /* CONFIG_COMPAT */
633 
634 static const struct proto_ops svc_proto_ops = {
635         .family =       PF_ATMSVC,
636         .owner =        THIS_MODULE,
637 
638         .release =      svc_release,
639         .bind =         svc_bind,
640         .connect =      svc_connect,
641         .socketpair =   sock_no_socketpair,
642         .accept =       svc_accept,
643         .getname =      svc_getname,
644         .poll =         vcc_poll,
645         .ioctl =        svc_ioctl,
646 #ifdef CONFIG_COMPAT
647         .compat_ioctl = svc_compat_ioctl,
648 #endif
649         .gettstamp =    sock_gettstamp,
650         .listen =       svc_listen,
651         .shutdown =     svc_shutdown,
652         .setsockopt =   svc_setsockopt,
653         .getsockopt =   svc_getsockopt,
654         .sendmsg =      vcc_sendmsg,
655         .recvmsg =      vcc_recvmsg,
656         .mmap =         sock_no_mmap,
657 };
658 
659 
660 static int svc_create(struct net *net, struct socket *sock, int protocol,
661                       int kern)
662 {
663         int error;
664 
665         if (!net_eq(net, &init_net))
666                 return -EAFNOSUPPORT;
667 
668         sock->ops = &svc_proto_ops;
669         error = vcc_create(net, sock, protocol, AF_ATMSVC, kern);
670         if (error)
671                 return error;
672         ATM_SD(sock)->local.sas_family = AF_ATMSVC;
673         ATM_SD(sock)->remote.sas_family = AF_ATMSVC;
674         return 0;
675 }
676 
677 static const struct net_proto_family svc_family_ops = {
678         .family = PF_ATMSVC,
679         .create = svc_create,
680         .owner = THIS_MODULE,
681 };
682 
683 
684 /*
685  *      Initialize the ATM SVC protocol family
686  */
687 
688 int __init atmsvc_init(void)
689 {
690         return sock_register(&svc_family_ops);
691 }
692 
693 void atmsvc_exit(void)
694 {
695         sock_unregister(PF_ATMSVC);
696 }
697 

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

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php