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