f05fcc6a789149328c8d72ce043f9176f81f3eb0
[dragonfly.git] / sys / netproto / atm / atm_aal5.c
1 /*
2  *
3  * ===================================
4  * HARP  |  Host ATM Research Platform
5  * ===================================
6  *
7  *
8  * This Host ATM Research Platform ("HARP") file (the "Software") is
9  * made available by Network Computing Services, Inc. ("NetworkCS")
10  * "AS IS".  NetworkCS does not provide maintenance, improvements or
11  * support of any kind.
12  *
13  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17  * In no event shall NetworkCS be responsible for any damages, including
18  * but not limited to consequential damages, arising from or relating to
19  * any use of the Software or related support.
20  *
21  * Copyright 1994-1998 Network Computing Services, Inc.
22  *
23  * Copies of this Software may be made, however, the above copyright
24  * notice must be reproduced on all copies.
25  *
26  *      @(#) $FreeBSD: src/sys/netatm/atm_aal5.c,v 1.6 1999/10/09 23:24:59 green Exp $
27  *      @(#) $DragonFly: src/sys/netproto/atm/atm_aal5.c,v 1.2 2003/06/17 04:28:48 dillon Exp $
28  */
29
30 /*
31  * Core ATM Services
32  * -----------------
33  *
34  * ATM AAL5 socket protocol processing
35  *
36  */
37
38 #include <netatm/kern_include.h>
39 #include <sys/stat.h>
40
41 /*
42  * Global variables
43  */
44 u_long          atm_aal5_sendspace = 64 * 1024; /* XXX */
45 u_long          atm_aal5_recvspace = 64 * 1024; /* XXX */
46
47
48 /*
49  * Local functions
50  */
51 static int      atm_aal5_attach __P((struct socket *, int, struct proc *));
52 static int      atm_aal5_detach __P((struct socket *));
53 static int      atm_aal5_bind __P((struct socket *, struct sockaddr *, 
54                         struct proc *));
55 static int      atm_aal5_listen __P((struct socket *, struct proc *));
56 static int      atm_aal5_connect __P((struct socket *, struct sockaddr *,
57                         struct proc *));
58 static int      atm_aal5_accept __P((struct socket *, struct sockaddr **));
59 static int      atm_aal5_disconnect __P((struct socket *));
60 static int      atm_aal5_shutdown __P((struct socket *));
61 static int      atm_aal5_send __P((struct socket *, int, KBuffer *,
62                         struct sockaddr *, KBuffer *, struct proc *));
63 static int      atm_aal5_abort __P((struct socket *));
64 static int      atm_aal5_control __P((struct socket *, u_long, caddr_t, 
65                         struct ifnet *, struct proc *));
66 static int      atm_aal5_sense __P((struct socket *, struct stat *));
67 static int      atm_aal5_sockaddr __P((struct socket *, struct sockaddr **));
68 static int      atm_aal5_peeraddr __P((struct socket *, struct sockaddr **));
69 static int      atm_aal5_incoming __P((void *, Atm_connection *,
70                         Atm_attributes *, void **));
71 static void     atm_aal5_cpcs_data __P((void *, KBuffer *));
72 static caddr_t  atm_aal5_getname __P((void *));
73
74
75 #if (defined(__FreeBSD__) && (BSD >= 199506))
76 /*
77  * New-style socket request routines
78  */
79 struct pr_usrreqs       atm_aal5_usrreqs = {
80         atm_aal5_abort,                 /* pru_abort */
81         atm_aal5_accept,                /* pru_accept */
82         atm_aal5_attach,                /* pru_attach */
83         atm_aal5_bind,                  /* pru_bind */
84         atm_aal5_connect,               /* pru_connect */
85         pru_connect2_notsupp,           /* pru_connect2 */
86         atm_aal5_control,               /* pru_control */
87         atm_aal5_detach,                /* pru_detach */
88         atm_aal5_disconnect,            /* pru_disconnect */
89         atm_aal5_listen,                /* pru_listen */
90         atm_aal5_peeraddr,              /* pru_peeraddr */
91         pru_rcvd_notsupp,               /* pru_rcvd */
92         pru_rcvoob_notsupp,             /* pru_rcvoob */
93         atm_aal5_send,                  /* pru_send */
94         atm_aal5_sense,                 /* pru_sense */
95         atm_aal5_shutdown,              /* pru_shutdown */
96         atm_aal5_sockaddr,              /* pru_sockaddr */
97         sosend,                         /* pru_sosend */
98         soreceive,                      /* pru_soreceive */
99         sopoll                          /* pru_sopoll */
100 };
101 #endif
102
103
104 /*
105  * Local variables
106  */
107 static Atm_endpoint     atm_aal5_endpt = {
108         NULL,
109         ENDPT_SOCK_AAL5,
110         NULL,
111         atm_aal5_getname,
112         atm_sock_connected,
113         atm_sock_cleared,
114         atm_aal5_incoming,
115         NULL,
116         NULL,
117         NULL,
118         atm_aal5_cpcs_data,
119         NULL,
120         NULL,
121         NULL,
122         NULL
123 };
124
125 static Atm_attributes   atm_aal5_defattr = {
126         NULL,                   /* nif */
127         CMAPI_CPCS,             /* api */
128         0,                      /* api_init */
129         0,                      /* headin */
130         0,                      /* headout */
131         {                       /* aal */
132                 T_ATM_PRESENT,
133                 ATM_AAL5
134         },
135         {                       /* traffic */
136                 T_ATM_ABSENT,
137         },
138         {                       /* bearer */
139                 T_ATM_ABSENT,
140         },
141         {                       /* bhli */
142                 T_ATM_ABSENT
143         },
144         {                       /* blli */
145                 T_ATM_ABSENT,
146                 T_ATM_ABSENT,
147         },
148         {                       /* llc */
149                 T_ATM_ABSENT,
150         },
151         {                       /* called */
152                 T_ATM_ABSENT,
153                 {
154                         T_ATM_ABSENT,
155                         0
156                 },
157                 {
158                         T_ATM_ABSENT,
159                         0
160                 }
161         },
162         {                       /* calling */
163                 T_ATM_ABSENT
164         },
165         {                       /* qos */
166                 T_ATM_ABSENT,
167         },
168         {                       /* transit */
169                 T_ATM_ABSENT
170         },
171         {                       /* cause */
172                 T_ATM_ABSENT
173         }
174 };
175
176
177 /*
178  * Handy common code macros
179  */
180 #ifdef DIAGNOSTIC
181 #define ATM_INTRO(f)                                            \
182         int             s, err = 0;                             \
183         s = splnet();                                           \
184         ATM_DEBUG2("aal5 socket %s (%p)\n", f, so);             \
185         /*                                                      \
186          * Stack queue should have been drained                 \
187          */                                                     \
188         if (atm_stackq_head != NULL)                            \
189                 panic("atm_aal5: stack queue not empty");       \
190         ;
191 #else /* !DIAGNOSTIC */
192 #define ATM_INTRO(f)                                            \
193         int             s, err = 0;                             \
194         s = splnet();                                           \
195         ;
196 #endif /* DIAGNOSTIC */
197
198 #define ATM_OUTRO()                                             \
199         /*                                                      \
200          * Drain any deferred calls                             \
201          */                                                     \
202         STACK_DRAIN();                                          \
203         (void) splx(s);                                         \
204         return (err);                                           \
205         ;
206
207 #define ATM_RETERR(errno) {                                     \
208         err = errno;                                            \
209         goto out;                                               \
210 }
211
212
213 /*
214  * Attach protocol to socket
215  *
216  * Arguments:
217  *      so      pointer to socket
218  *      proto   protocol identifier
219  *      p       pointer to process
220  *
221  * Returns:
222  *      0       request processed
223  *      errno   error processing request - reason indicated
224  *
225  */
226 static int
227 atm_aal5_attach(so, proto, p)
228         struct socket   *so;
229         int             proto;
230         struct proc     *p;
231 {
232         Atm_pcb         *atp;
233
234         ATM_INTRO("attach");
235
236         /*
237          * Do general attach stuff
238          */
239         err = atm_sock_attach(so, atm_aal5_sendspace, atm_aal5_recvspace);
240         if (err)
241                 ATM_RETERR(err);
242
243         /*
244          * Finish up any protocol specific stuff
245          */
246         atp = sotoatmpcb(so);
247         atp->atp_type = ATPT_AAL5;
248
249         /*
250          * Set default connection attributes
251          */
252         atp->atp_attr = atm_aal5_defattr;
253         strncpy(atp->atp_name, "(AAL5)", T_ATM_APP_NAME_LEN);
254
255 out:
256         ATM_OUTRO();
257 }
258
259
260 /*
261  * Detach protocol from socket
262  *
263  * Arguments:
264  *      so      pointer to socket
265  *
266  * Returns:
267  *      0       request processed
268  *      errno   error processing request - reason indicated
269  *
270  */
271 static int
272 atm_aal5_detach(so)
273         struct socket   *so;
274 {
275         ATM_INTRO("detach");
276
277         err = atm_sock_detach(so);
278
279         ATM_OUTRO();
280 }
281
282
283 /*
284  * Bind address to socket
285  *
286  * Arguments:
287  *      so      pointer to socket
288  *      addr    pointer to protocol address
289  *      p       pointer to process
290  *
291  * Returns:
292  *      0       request processed
293  *      errno   error processing request - reason indicated
294  *
295  */
296 static int
297 atm_aal5_bind(so, addr, p)
298         struct socket   *so;
299         struct sockaddr *addr;
300         struct proc     *p;
301 {
302         ATM_INTRO("bind");
303
304         err = atm_sock_bind(so, addr);
305
306         ATM_OUTRO();
307 }
308
309
310 /*
311  * Listen for incoming connections
312  *
313  * Arguments:
314  *      so      pointer to socket
315  *      p       pointer to process
316  *
317  * Returns:
318  *      0       request processed
319  *      errno   error processing request - reason indicated
320  *
321  */
322 static int
323 atm_aal5_listen(so, p)
324         struct socket   *so;
325         struct proc     *p;
326 {
327         ATM_INTRO("listen");
328
329         err = atm_sock_listen(so, &atm_aal5_endpt);
330
331         ATM_OUTRO();
332 }
333
334
335 /*
336  * Connect socket to peer
337  *
338  * Arguments:
339  *      so      pointer to socket
340  *      addr    pointer to protocol address
341  *      p       pointer to process
342  *
343  * Returns:
344  *      0       request processed
345  *      errno   error processing request - reason indicated
346  *
347  */
348 static int
349 atm_aal5_connect(so, addr, p)
350         struct socket   *so;
351         struct sockaddr *addr;
352         struct proc     *p;
353 {
354         Atm_pcb         *atp;
355
356         ATM_INTRO("connect");
357
358         atp = sotoatmpcb(so);
359
360         /*
361          * Resize send socket buffer to maximum sdu size
362          */
363         if (atp->atp_attr.aal.tag == T_ATM_PRESENT) {
364                 long    size;
365
366                 size = atp->atp_attr.aal.v.aal5.forward_max_SDU_size;
367                 if (size != T_ATM_ABSENT)
368                         if (!sbreserve(&so->so_snd, size, so, p)) {
369                                 err = ENOBUFS;
370                                 ATM_OUTRO();
371                         }
372                                 
373         }
374
375         /*
376          * Now get the socket connected
377          */
378         err = atm_sock_connect(so, addr, &atm_aal5_endpt);
379
380         ATM_OUTRO();
381 }
382
383
384 /*
385  * Accept pending connection
386  *
387  * Arguments:
388  *      so      pointer to socket
389  *      addr    pointer to pointer to contain protocol address
390  *
391  * Returns:
392  *      0       request processed
393  *      errno   error processing request - reason indicated
394  *
395  */
396 static int
397 atm_aal5_accept(so, addr)
398         struct socket   *so;
399         struct sockaddr **addr;
400 {
401         ATM_INTRO("accept");
402
403         /*
404          * Everything is pretty much done already, we just need to
405          * return the caller's address to the user.
406          */
407         err = atm_sock_peeraddr(so, addr);
408
409         ATM_OUTRO();
410 }
411
412
413 /*
414  * Disconnect connected socket
415  *
416  * Arguments:
417  *      so      pointer to socket
418  *
419  * Returns:
420  *      0       request processed
421  *      errno   error processing request - reason indicated
422  *
423  */
424 static int
425 atm_aal5_disconnect(so)
426         struct socket   *so;
427 {
428         ATM_INTRO("disconnect");
429
430         err = atm_sock_disconnect(so);
431
432         ATM_OUTRO();
433 }
434
435
436 /*
437  * Shut down socket data transmission
438  *
439  * Arguments:
440  *      so      pointer to socket
441  *
442  * Returns:
443  *      0       request processed
444  *      errno   error processing request - reason indicated
445  *
446  */
447 static int
448 atm_aal5_shutdown(so)
449         struct socket   *so;
450 {
451         ATM_INTRO("shutdown");
452
453         socantsendmore(so);
454
455         ATM_OUTRO();
456 }
457
458
459 /*
460  * Send user data
461  *
462  * Arguments:
463  *      so      pointer to socket
464  *      flags   send data flags
465  *      m       pointer to buffer containing user data
466  *      addr    pointer to protocol address
467  *      control pointer to buffer containing protocol control data
468  *      p       pointer to process
469  *
470  * Returns:
471  *      0       request processed
472  *      errno   error processing request - reason indicated
473  *
474  */
475 static int
476 atm_aal5_send(so, flags, m, addr, control, p)
477         struct socket   *so;
478         int             flags;
479         KBuffer         *m;
480         struct sockaddr *addr;
481         KBuffer         *control;
482         struct proc     *p;
483 {
484         Atm_pcb         *atp;
485
486         ATM_INTRO("send");
487
488         /*
489          * We don't support any control functions
490          */
491         if (control) {
492                 int     clen;
493
494                 clen = KB_LEN(control);
495                 KB_FREEALL(control);
496                 if (clen) {
497                         KB_FREEALL(m);
498                         ATM_RETERR(EINVAL);
499                 }
500         }
501
502         /*
503          * We also don't support any flags or send-level addressing
504          */
505         if (flags || addr) {
506                 KB_FREEALL(m);
507                 ATM_RETERR(EINVAL);
508         }
509
510         /*
511          * All we've got left is the data, so push it out
512          */
513         atp = sotoatmpcb(so);
514         err = atm_cm_cpcs_data(atp->atp_conn, m);
515         if (err) {
516                 /*
517                  * Output problem, drop packet
518                  */
519                 atm_sock_stat.as_outdrop[atp->atp_type]++;
520                 KB_FREEALL(m);
521         }
522
523 out:
524         ATM_OUTRO();
525 }
526
527
528 /*
529  * Abnormally terminate service
530  *
531  * Arguments:
532  *      so      pointer to socket
533  *
534  * Returns:
535  *      0       request processed
536  *      errno   error processing request - reason indicated
537  *
538  */
539 static int
540 atm_aal5_abort(so)
541         struct socket   *so;
542 {
543         ATM_INTRO("abort");
544
545         so->so_error = ECONNABORTED;
546         err = atm_sock_detach(so);
547
548         ATM_OUTRO();
549 }
550
551
552 /*
553  * Do control operation - ioctl system call
554  *
555  * Arguments:
556  *      so      pointer to socket
557  *      cmd     ioctl code
558  *      data    pointer to code specific parameter data area
559  *      ifp     pointer to ifnet structure if it's an interface ioctl
560  *      p       pointer to process
561  *
562  * Returns:
563  *      0       request processed
564  *      errno   error processing request - reason indicated
565  *
566  */
567 static int
568 atm_aal5_control(so, cmd, data, ifp, p)
569         struct socket   *so;
570         u_long          cmd;
571         caddr_t         data;
572         struct ifnet    *ifp;
573         struct proc     *p;
574 {
575         ATM_INTRO("control");
576
577         switch (cmd) {
578
579         default:
580                 err = EOPNOTSUPP;
581         }
582
583         ATM_OUTRO();
584 }
585
586 /*
587  * Sense socket status - fstat system call
588  *
589  * Arguments:
590  *      so      pointer to socket
591  *      st      pointer to file status structure
592  *
593  * Returns:
594  *      0       request processed
595  *      errno   error processing request - reason indicated
596  *
597  */
598 static int
599 atm_aal5_sense(so, st)
600         struct socket   *so;
601         struct stat     *st;
602 {
603         ATM_INTRO("sense");
604
605         /*
606          * Just return the max sdu size for the connection
607          */
608         st->st_blksize = so->so_snd.sb_hiwat;
609
610         ATM_OUTRO();
611 }
612
613
614 /*
615  * Retrieve local socket address
616  *
617  * Arguments:
618  *      so      pointer to socket
619  *      addr    pointer to pointer to contain protocol address
620  *
621  * Returns:
622  *      0       request processed
623  *      errno   error processing request - reason indicated
624  *
625  */
626 static int
627 atm_aal5_sockaddr(so, addr)
628         struct socket   *so;
629         struct sockaddr **addr;
630 {
631         ATM_INTRO("sockaddr");
632
633         err = atm_sock_sockaddr(so, addr);
634
635         ATM_OUTRO();
636 }
637
638
639 /*
640  * Retrieve peer socket address
641  *
642  * Arguments:
643  *      so      pointer to socket
644  *      addr    pointer to pointer to contain protocol address
645  *
646  * Returns:
647  *      0       request processed
648  *      errno   error processing request - reason indicated
649  *
650  */
651 static int
652 atm_aal5_peeraddr(so, addr)
653         struct socket   *so;
654         struct sockaddr **addr;
655 {
656         ATM_INTRO("peeraddr");
657
658         err = atm_sock_peeraddr(so, addr);
659
660         ATM_OUTRO();
661 }
662
663
664 /*
665  * Process Incoming Calls
666  *
667  * This function will receive control when an incoming call has been matched
668  * to one of our registered listen parameter blocks.  Assuming the call passes
669  * acceptance criteria and all required resources are available, we will
670  * create a new protocol control block and socket association.  We must
671  * then await notification of the final SVC setup results.  If any
672  * problems are encountered, we will just tell the connection manager to
673  * reject the call.
674  *
675  * Called at splnet.
676  *
677  * Arguments:
678  *      tok     owner's matched listening token
679  *      cop     pointer to incoming call's connection block
680  *      ap      pointer to incoming call's attributes
681  *      tokp    pointer to location to store our connection token
682  *
683  * Returns:
684  *      0       call is accepted
685  *      errno   call rejected - reason indicated
686  *
687  */
688 static int
689 atm_aal5_incoming(tok, cop, ap, tokp)
690         void            *tok;
691         Atm_connection  *cop;
692         Atm_attributes  *ap;
693         void            **tokp;
694 {
695         Atm_pcb         *atp0 = tok, *atp;
696         struct socket   *so;
697         int             err = 0;
698
699         /*
700          * Allocate a new socket and pcb for this connection.
701          *
702          * Note that our attach function will be called via sonewconn
703          * and it will allocate and setup most of the pcb.
704          */
705         atm_sock_stat.as_inconn[atp0->atp_type]++;
706 #if (defined(BSD) && (BSD >= 199103))
707         so = sonewconn(atp0->atp_socket, 0);
708 #else
709         so = sonewconn(atp0->atp_socket);
710 #endif
711
712         if (so) {
713                 /*
714                  * Finish pcb setup and pass pcb back to CM
715                  */
716                 atp = sotoatmpcb(so);
717                 atp->atp_conn = cop;
718                 atp->atp_attr = *atp0->atp_conn->co_lattr;
719                 strncpy(atp->atp_name, atp0->atp_name, T_ATM_APP_NAME_LEN);
720                 *tokp = atp;
721         } else {
722                 err = ECONNABORTED;
723                 atm_sock_stat.as_connfail[atp0->atp_type]++;
724         }
725
726         return (err);
727 }
728
729
730 /*
731  * Process Socket VCC Input Data
732  *
733  * Arguments:
734  *      tok     owner's connection token (atm_pcb)
735  *      m       pointer to input packet buffer chain
736  *
737  * Returns:
738  *      none
739  *
740  */
741 static void
742 atm_aal5_cpcs_data(tok, m)
743         void            *tok;
744         KBuffer         *m;
745 {
746         Atm_pcb         *atp = tok;
747         struct socket   *so;
748         int             len;
749
750         so = atp->atp_socket;
751
752         KB_PLENGET(m, len);
753
754         /*
755          * Ensure that the socket is able to receive data and
756          * that there's room in the socket buffer
757          */
758         if (((so->so_state & SS_ISCONNECTED) == 0) ||
759             (so->so_state & SS_CANTRCVMORE) ||
760             (len > sbspace(&so->so_rcv))) {
761                 atm_sock_stat.as_indrop[atp->atp_type]++;
762                 KB_FREEALL(m);
763                 return;
764         }
765
766         /*
767          * Queue the data and notify the user
768          */
769         sbappendrecord(&so->so_rcv, m);
770         sorwakeup(so);
771
772         return;
773 }
774
775
776 /*
777  * Process getsockopt/setsockopt system calls
778  *
779  * Arguments:
780  *      so      pointer to socket
781  *      sopt    pointer to socket option info
782  *
783  * Returns:
784  *      0       request processed
785  *      errno   error processing request - reason indicated
786  *
787  */
788 int
789 atm_aal5_ctloutput(so, sopt)
790         struct socket   *so;
791         struct sockopt  *sopt;
792 {
793         Atm_pcb         *atp;
794
795         ATM_INTRO("ctloutput");
796
797         /*
798          * Make sure this is for us
799          */
800         if (sopt->sopt_level != T_ATM_SIGNALING) {
801                 ATM_RETERR(EINVAL);
802         }
803         atp = sotoatmpcb(so);
804         if (atp == NULL) {
805                 ATM_RETERR(ENOTCONN);
806         }
807
808         switch (sopt->sopt_dir) {
809
810         case SOPT_SET:
811                 /*
812                  * setsockopt()
813                  */
814
815                 /*
816                  * Validate socket state
817                  */
818                 switch (sopt->sopt_name) {
819
820                 case T_ATM_ADD_LEAF:
821                 case T_ATM_DROP_LEAF:
822                         if ((so->so_state & SS_ISCONNECTED) == 0) {
823                                 ATM_RETERR(ENOTCONN);
824                         }
825                         break;
826
827                 case T_ATM_CAUSE:
828                 case T_ATM_APP_NAME:
829                         break;
830
831                 default:
832                         if (so->so_state & SS_ISCONNECTED) {
833                                 ATM_RETERR(EISCONN);
834                         }
835                         break;
836                 }
837
838                 /*
839                  * Validate and save user-supplied option data
840                  */
841                 err = atm_sock_setopt(so, sopt, atp);
842
843                 break;
844
845         case SOPT_GET:
846                 /*
847                  * getsockopt()
848                  */
849
850                 /*
851                  * Return option data
852                  */
853                 err = atm_sock_getopt(so, sopt, atp);
854
855                 break;
856         }
857
858 out:
859         ATM_OUTRO();
860 }
861
862
863 /*
864  * Initialize AAL5 Sockets
865  *
866  * Arguments:
867  *      none
868  *
869  * Returns:
870  *      none
871  *
872  */
873 void
874 atm_aal5_init()
875 {
876         /*
877          * Register our endpoint
878          */
879         if (atm_endpoint_register(&atm_aal5_endpt))
880                 panic("atm_aal5_init: register");
881
882         /*
883          * Set default connection attributes
884          */
885         atm_aal5_defattr.aal.v.aal5.forward_max_SDU_size = T_ATM_ABSENT;
886         atm_aal5_defattr.aal.v.aal5.backward_max_SDU_size = T_ATM_ABSENT;
887         atm_aal5_defattr.aal.v.aal5.SSCS_type = T_ATM_NULL;
888 }
889
890
891 /*
892  * Get Connection's Application/Owner Name
893  *
894  * Arguments:
895  *      tok     owner's connection token (atm_pcb)
896  *
897  * Returns:
898  *      addr    pointer to string containing our name
899  *
900  */
901 static caddr_t
902 atm_aal5_getname(tok)
903         void            *tok;
904 {
905         Atm_pcb         *atp = tok;
906
907         return (atp->atp_name);
908 }
909