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