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