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