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