Merge from vendor branch LIBSTDC++:
[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.5 2003/08/23 10:06:21 rob Exp $
28  */
29
30 /*
31  * Core ATM Services
32  * -----------------
33  *
34  * ATM AAL5 socket protocol processing
35  *
36  */
37
38 #include "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 (struct socket *, int, struct thread *);
52 static int      atm_aal5_detach (struct socket *);
53 static int      atm_aal5_bind (struct socket *, struct sockaddr *, 
54                         struct thread *);
55 static int      atm_aal5_listen (struct socket *, struct thread *);
56 static int      atm_aal5_connect (struct socket *, struct sockaddr *,
57                         struct thread *);
58 static int      atm_aal5_accept (struct socket *, struct sockaddr **);
59 static int      atm_aal5_disconnect (struct socket *);
60 static int      atm_aal5_shutdown (struct socket *);
61 static int      atm_aal5_send (struct socket *, int, KBuffer *,
62                         struct sockaddr *, KBuffer *, struct thread *);
63 static int      atm_aal5_abort (struct socket *);
64 static int      atm_aal5_control (struct socket *, u_long, caddr_t, 
65                         struct ifnet *, struct thread *);
66 static int      atm_aal5_sense (struct socket *, struct stat *);
67 static int      atm_aal5_sockaddr (struct socket *, struct sockaddr **);
68 static int      atm_aal5_peeraddr (struct socket *, struct sockaddr **);
69 static int      atm_aal5_incoming (void *, Atm_connection *,
70                         Atm_attributes *, void **);
71 static void     atm_aal5_cpcs_data (void *, KBuffer *);
72 static caddr_t  atm_aal5_getname (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, td)
228         struct socket   *so;
229         int             proto;
230         struct thread   *td;
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, td)
298         struct socket   *so;
299         struct sockaddr *addr;
300         struct thread   *td;
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(struct socket *so, struct thread *td)
324 {
325         ATM_INTRO("listen");
326
327         err = atm_sock_listen(so, &atm_aal5_endpt);
328
329         ATM_OUTRO();
330 }
331
332
333 /*
334  * Connect socket to peer
335  *
336  * Arguments:
337  *      so      pointer to socket
338  *      addr    pointer to protocol address
339  *      p       pointer to process
340  *
341  * Returns:
342  *      0       request processed
343  *      errno   error processing request - reason indicated
344  *
345  */
346 static int
347 atm_aal5_connect(struct socket *so, struct sockaddr *addr, thread_t td)
348 {
349         Atm_pcb         *atp;
350
351         ATM_INTRO("connect");
352
353         atp = sotoatmpcb(so);
354
355         /*
356          * Resize send socket buffer to maximum sdu size
357          */
358         if (atp->atp_attr.aal.tag == T_ATM_PRESENT) {
359                 long    size;
360
361                 size = atp->atp_attr.aal.v.aal5.forward_max_SDU_size;
362                 if (size != T_ATM_ABSENT)
363                         if (!sbreserve(&so->so_snd, size, so, td->td_proc)) {
364                                 err = ENOBUFS;
365                                 ATM_OUTRO();
366                         }
367                                 
368         }
369
370         /*
371          * Now get the socket connected
372          */
373         err = atm_sock_connect(so, addr, &atm_aal5_endpt);
374
375         ATM_OUTRO();
376 }
377
378
379 /*
380  * Accept pending connection
381  *
382  * Arguments:
383  *      so      pointer to socket
384  *      addr    pointer to pointer to contain protocol address
385  *
386  * Returns:
387  *      0       request processed
388  *      errno   error processing request - reason indicated
389  *
390  */
391 static int
392 atm_aal5_accept(struct socket *so, struct sockaddr **addr)
393 {
394         ATM_INTRO("accept");
395
396         /*
397          * Everything is pretty much done already, we just need to
398          * return the caller's address to the user.
399          */
400         err = atm_sock_peeraddr(so, addr);
401
402         ATM_OUTRO();
403 }
404
405
406 /*
407  * Disconnect connected socket
408  *
409  * Arguments:
410  *      so      pointer to socket
411  *
412  * Returns:
413  *      0       request processed
414  *      errno   error processing request - reason indicated
415  *
416  */
417 static int
418 atm_aal5_disconnect(struct socket *so)
419 {
420         ATM_INTRO("disconnect");
421
422         err = atm_sock_disconnect(so);
423
424         ATM_OUTRO();
425 }
426
427
428 /*
429  * Shut down socket data transmission
430  *
431  * Arguments:
432  *      so      pointer to socket
433  *
434  * Returns:
435  *      0       request processed
436  *      errno   error processing request - reason indicated
437  *
438  */
439 static int
440 atm_aal5_shutdown(struct socket *so)
441 {
442         ATM_INTRO("shutdown");
443
444         socantsendmore(so);
445
446         ATM_OUTRO();
447 }
448
449
450 /*
451  * Send user data
452  *
453  * Arguments:
454  *      so      pointer to socket
455  *      flags   send data flags
456  *      m       pointer to buffer containing user data
457  *      addr    pointer to protocol address
458  *      control pointer to buffer containing protocol control data
459  *      p       pointer to process
460  *
461  * Returns:
462  *      0       request processed
463  *      errno   error processing request - reason indicated
464  *
465  */
466 static int
467 atm_aal5_send(
468         struct socket   *so,
469         int             flags,
470         KBuffer         *m,
471         struct sockaddr *addr,
472         KBuffer         *control,
473         struct thread   *td
474 ) {
475         Atm_pcb         *atp;
476
477         ATM_INTRO("send");
478
479         /*
480          * We don't support any control functions
481          */
482         if (control) {
483                 int     clen;
484
485                 clen = KB_LEN(control);
486                 KB_FREEALL(control);
487                 if (clen) {
488                         KB_FREEALL(m);
489                         ATM_RETERR(EINVAL);
490                 }
491         }
492
493         /*
494          * We also don't support any flags or send-level addressing
495          */
496         if (flags || addr) {
497                 KB_FREEALL(m);
498                 ATM_RETERR(EINVAL);
499         }
500
501         /*
502          * All we've got left is the data, so push it out
503          */
504         atp = sotoatmpcb(so);
505         err = atm_cm_cpcs_data(atp->atp_conn, m);
506         if (err) {
507                 /*
508                  * Output problem, drop packet
509                  */
510                 atm_sock_stat.as_outdrop[atp->atp_type]++;
511                 KB_FREEALL(m);
512         }
513
514 out:
515         ATM_OUTRO();
516 }
517
518
519 /*
520  * Abnormally terminate service
521  *
522  * Arguments:
523  *      so      pointer to socket
524  *
525  * Returns:
526  *      0       request processed
527  *      errno   error processing request - reason indicated
528  *
529  */
530 static int
531 atm_aal5_abort(struct socket *so)
532 {
533         ATM_INTRO("abort");
534
535         so->so_error = ECONNABORTED;
536         err = atm_sock_detach(so);
537
538         ATM_OUTRO();
539 }
540
541
542 /*
543  * Do control operation - ioctl system call
544  *
545  * Arguments:
546  *      so      pointer to socket
547  *      cmd     ioctl code
548  *      data    pointer to code specific parameter data area
549  *      ifp     pointer to ifnet structure if it's an interface ioctl
550  *      p       pointer to process
551  *
552  * Returns:
553  *      0       request processed
554  *      errno   error processing request - reason indicated
555  *
556  */
557 static int
558 atm_aal5_control(
559         struct socket   *so,
560         u_long          cmd,
561         caddr_t         data,
562         struct ifnet    *ifp,
563         struct thread   *td
564 ) {
565         ATM_INTRO("control");
566
567         switch (cmd) {
568
569         default:
570                 err = EOPNOTSUPP;
571         }
572
573         ATM_OUTRO();
574 }
575
576 /*
577  * Sense socket status - fstat system call
578  *
579  * Arguments:
580  *      so      pointer to socket
581  *      st      pointer to file status structure
582  *
583  * Returns:
584  *      0       request processed
585  *      errno   error processing request - reason indicated
586  *
587  */
588 static int
589 atm_aal5_sense(struct socket *so, struct stat *st)
590 {
591         ATM_INTRO("sense");
592
593         /*
594          * Just return the max sdu size for the connection
595          */
596         st->st_blksize = so->so_snd.sb_hiwat;
597
598         ATM_OUTRO();
599 }
600
601
602 /*
603  * Retrieve local socket address
604  *
605  * Arguments:
606  *      so      pointer to socket
607  *      addr    pointer to pointer to contain protocol address
608  *
609  * Returns:
610  *      0       request processed
611  *      errno   error processing request - reason indicated
612  *
613  */
614 static int
615 atm_aal5_sockaddr(struct socket *so, struct sockaddr **addr)
616 {
617         ATM_INTRO("sockaddr");
618
619         err = atm_sock_sockaddr(so, addr);
620
621         ATM_OUTRO();
622 }
623
624
625 /*
626  * Retrieve peer socket address
627  *
628  * Arguments:
629  *      so      pointer to socket
630  *      addr    pointer to pointer to contain protocol address
631  *
632  * Returns:
633  *      0       request processed
634  *      errno   error processing request - reason indicated
635  *
636  */
637 static int
638 atm_aal5_peeraddr(struct socket *so, struct sockaddr **addr)
639 {
640         ATM_INTRO("peeraddr");
641
642         err = atm_sock_peeraddr(so, addr);
643
644         ATM_OUTRO();
645 }
646
647
648 /*
649  * Process Incoming Calls
650  *
651  * This function will receive control when an incoming call has been matched
652  * to one of our registered listen parameter blocks.  Assuming the call passes
653  * acceptance criteria and all required resources are available, we will
654  * create a new protocol control block and socket association.  We must
655  * then await notification of the final SVC setup results.  If any
656  * problems are encountered, we will just tell the connection manager to
657  * reject the call.
658  *
659  * Called at splnet.
660  *
661  * Arguments:
662  *      tok     owner's matched listening token
663  *      cop     pointer to incoming call's connection block
664  *      ap      pointer to incoming call's attributes
665  *      tokp    pointer to location to store our connection token
666  *
667  * Returns:
668  *      0       call is accepted
669  *      errno   call rejected - reason indicated
670  *
671  */
672 static int
673 atm_aal5_incoming(tok, cop, ap, tokp)
674         void            *tok;
675         Atm_connection  *cop;
676         Atm_attributes  *ap;
677         void            **tokp;
678 {
679         Atm_pcb         *atp0 = tok, *atp;
680         struct socket   *so;
681         int             err = 0;
682
683         /*
684          * Allocate a new socket and pcb for this connection.
685          *
686          * Note that our attach function will be called via sonewconn
687          * and it will allocate and setup most of the pcb.
688          */
689         atm_sock_stat.as_inconn[atp0->atp_type]++;
690 #if (defined(BSD) && (BSD >= 199103))
691         so = sonewconn(atp0->atp_socket, 0);
692 #else
693         so = sonewconn(atp0->atp_socket);
694 #endif
695
696         if (so) {
697                 /*
698                  * Finish pcb setup and pass pcb back to CM
699                  */
700                 atp = sotoatmpcb(so);
701                 atp->atp_conn = cop;
702                 atp->atp_attr = *atp0->atp_conn->co_lattr;
703                 strncpy(atp->atp_name, atp0->atp_name, T_ATM_APP_NAME_LEN);
704                 *tokp = atp;
705         } else {
706                 err = ECONNABORTED;
707                 atm_sock_stat.as_connfail[atp0->atp_type]++;
708         }
709
710         return (err);
711 }
712
713
714 /*
715  * Process Socket VCC Input Data
716  *
717  * Arguments:
718  *      tok     owner's connection token (atm_pcb)
719  *      m       pointer to input packet buffer chain
720  *
721  * Returns:
722  *      none
723  *
724  */
725 static void
726 atm_aal5_cpcs_data(tok, m)
727         void            *tok;
728         KBuffer         *m;
729 {
730         Atm_pcb         *atp = tok;
731         struct socket   *so;
732         int             len;
733
734         so = atp->atp_socket;
735
736         KB_PLENGET(m, len);
737
738         /*
739          * Ensure that the socket is able to receive data and
740          * that there's room in the socket buffer
741          */
742         if (((so->so_state & SS_ISCONNECTED) == 0) ||
743             (so->so_state & SS_CANTRCVMORE) ||
744             (len > sbspace(&so->so_rcv))) {
745                 atm_sock_stat.as_indrop[atp->atp_type]++;
746                 KB_FREEALL(m);
747                 return;
748         }
749
750         /*
751          * Queue the data and notify the user
752          */
753         sbappendrecord(&so->so_rcv, m);
754         sorwakeup(so);
755
756         return;
757 }
758
759
760 /*
761  * Process getsockopt/setsockopt system calls
762  *
763  * Arguments:
764  *      so      pointer to socket
765  *      sopt    pointer to socket option info
766  *
767  * Returns:
768  *      0       request processed
769  *      errno   error processing request - reason indicated
770  *
771  */
772 int
773 atm_aal5_ctloutput(struct socket *so, struct sockopt *sopt)
774 {
775         Atm_pcb         *atp;
776
777         ATM_INTRO("ctloutput");
778
779         /*
780          * Make sure this is for us
781          */
782         if (sopt->sopt_level != T_ATM_SIGNALING) {
783                 ATM_RETERR(EINVAL);
784         }
785         atp = sotoatmpcb(so);
786         if (atp == NULL) {
787                 ATM_RETERR(ENOTCONN);
788         }
789
790         switch (sopt->sopt_dir) {
791
792         case SOPT_SET:
793                 /*
794                  * setsockopt()
795                  */
796
797                 /*
798                  * Validate socket state
799                  */
800                 switch (sopt->sopt_name) {
801
802                 case T_ATM_ADD_LEAF:
803                 case T_ATM_DROP_LEAF:
804                         if ((so->so_state & SS_ISCONNECTED) == 0) {
805                                 ATM_RETERR(ENOTCONN);
806                         }
807                         break;
808
809                 case T_ATM_CAUSE:
810                 case T_ATM_APP_NAME:
811                         break;
812
813                 default:
814                         if (so->so_state & SS_ISCONNECTED) {
815                                 ATM_RETERR(EISCONN);
816                         }
817                         break;
818                 }
819
820                 /*
821                  * Validate and save user-supplied option data
822                  */
823                 err = atm_sock_setopt(so, sopt, atp);
824
825                 break;
826
827         case SOPT_GET:
828                 /*
829                  * getsockopt()
830                  */
831
832                 /*
833                  * Return option data
834                  */
835                 err = atm_sock_getopt(so, sopt, atp);
836
837                 break;
838         }
839
840 out:
841         ATM_OUTRO();
842 }
843
844
845 /*
846  * Initialize AAL5 Sockets
847  *
848  * Arguments:
849  *      none
850  *
851  * Returns:
852  *      none
853  *
854  */
855 void
856 atm_aal5_init()
857 {
858         /*
859          * Register our endpoint
860          */
861         if (atm_endpoint_register(&atm_aal5_endpt))
862                 panic("atm_aal5_init: register");
863
864         /*
865          * Set default connection attributes
866          */
867         atm_aal5_defattr.aal.v.aal5.forward_max_SDU_size = T_ATM_ABSENT;
868         atm_aal5_defattr.aal.v.aal5.backward_max_SDU_size = T_ATM_ABSENT;
869         atm_aal5_defattr.aal.v.aal5.SSCS_type = T_ATM_NULL;
870 }
871
872
873 /*
874  * Get Connection's Application/Owner Name
875  *
876  * Arguments:
877  *      tok     owner's connection token (atm_pcb)
878  *
879  * Returns:
880  *      addr    pointer to string containing our name
881  *
882  */
883 static caddr_t
884 atm_aal5_getname(tok)
885         void            *tok;
886 {
887         Atm_pcb         *atp = tok;
888
889         return (atp->atp_name);
890 }
891