MFC:
[dragonfly.git] / sys / netproto / atm / atm_cm.c
blob5f4d668013673377a05adf9e788a28154e872bfd
1 /*
3 * ===================================
4 * HARP | Host ATM Research Platform
5 * ===================================
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.
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.
21 * Copyright 1994-1998 Network Computing Services, Inc.
23 * Copies of this Software may be made, however, the above copyright
24 * notice must be reproduced on all copies.
26 * @(#) $FreeBSD: src/sys/netatm/atm_cm.c,v 1.6 1999/08/28 00:48:34 peter Exp $
27 * @(#) $DragonFly: src/sys/netproto/atm/atm_cm.c,v 1.7 2006/01/14 13:36:39 swildner Exp $
31 * Core ATM Services
32 * -----------------
34 * ATM Connection Manager
38 #include "kern_include.h"
39 #include <sys/kernel.h>
42 * Global variables
44 struct atm_cm_stat atm_cm_stat = {0};
45 struct callout atm_cm_procinq_ch;
47 SYSINIT(atm_cm, SI_SUB_DRIVERS, SI_ORDER_ANY, callout_init, &atm_cm_procinq_ch);
50 * Local functions
52 static void atm_cm_cpcs_upper (int, void *, int, int);
53 static void atm_cm_saal_upper (int, void *, int, int);
54 static void atm_cm_sscop_upper (int, void *, int, int);
55 static Atm_connvc * atm_cm_share_llc (Atm_attributes *);
56 static void atm_cm_closeconn (Atm_connection *,
57 struct t_atm_cause *);
58 static void atm_cm_closevc (Atm_connvc *);
59 static void atm_cm_timeout (struct atm_time *);
60 static KTimeout_ret atm_cm_procinq (void *);
61 static void atm_cm_incall (Atm_connvc *);
62 static int atm_cm_accept (Atm_connvc *, Atm_connection *);
65 * Local variables
67 static Queue_t atm_connection_queue = {NULL};
68 static Queue_t atm_incoming_queue = {NULL};
69 static int atm_incoming_qlen = 0;
70 static Atm_connection *atm_listen_queue = NULL;
71 static struct attr_cause atm_cause_tmpl =
72 {T_ATM_PRESENT, {T_ATM_ITU_CODING, T_ATM_LOC_USER, 0, {0, 0, 0, 0}}};
75 * Stack commands, indexed by API
77 static struct {
78 int init;
79 int term;
80 } atm_stackcmds[] = {
81 {CPCS_INIT, CPCS_TERM}, /* CMAPI_CPCS */
82 {SSCF_UNI_INIT, SSCF_UNI_TERM}, /* CMAPI_SAAL */
83 {SSCOP_INIT, SSCOP_TERM}, /* CMAPI_SSCOP */
87 static struct sp_info atm_connection_pool = {
88 "atm connection pool", /* si_name */
89 sizeof(Atm_connection), /* si_blksiz */
90 10, /* si_blkcnt */
91 100 /* si_maxallow */
93 static struct sp_info atm_connvc_pool = {
94 "atm connection vcc pool", /* si_name */
95 sizeof(Atm_connvc), /* si_blksiz */
96 10, /* si_blkcnt */
97 100 /* si_maxallow */
102 * Initiate Outgoing ATM Call
104 * Called by an endpoint service to create a new Connection Manager API
105 * instance and to initiate an outbound ATM connection. The endpoint
106 * provided token will be used in all further CM -> endpoint function
107 * calls, and the returned connection block pointer must be used in all
108 * subsequent endpoint -> CM function calls.
110 * If the return indicates that the connection setup has been immediately
111 * successful (typically only for PVCs and shared SVCs), then the connection
112 * is ready for data transmission.
114 * If the return indicates that the connection setup is still in progress,
115 * then the endpoint must wait for notification from the Connection Manager
116 * indicating the final status of the call setup. If the call setup completes
117 * successfully, then a "call connected" notification will be sent to the
118 * endpoint by the Connection Manager. If the call setup fails, then the
119 * endpoint will receive a "call cleared" notification.
121 * All connection instances must be freed with an atm_cm_release() call.
123 * Arguments:
124 * epp pointer to endpoint definition structure
125 * token endpoint's connection instance token
126 * ap pointer to requested connection attributes
127 * copp pointer to location to return allocated connection block
129 * Returns:
130 * 0 connection has been successfully established
131 * EINPROGRESS connection establishment is in progress
132 * errno connection failed - reason indicated
136 atm_cm_connect(Atm_endpoint *epp, void *token, Atm_attributes *ap,
137 Atm_connection **copp)
139 Atm_connection *cop;
140 Atm_connvc *cvp;
141 struct atm_pif *pip;
142 struct sigmgr *smp;
143 struct stack_list sl;
144 void (*upf)(int, void *, int, int);
145 int sli, err, err2;
147 *copp = NULL;
148 cvp = NULL;
151 * Get a connection block
153 cop = (Atm_connection *)atm_allocate(&atm_connection_pool);
154 if (cop == NULL)
155 return (ENOMEM);
158 * Initialize connection info
160 cop->co_endpt = epp;
161 cop->co_toku = token;
164 * Initialize stack list index
166 sli = 0;
169 * Validate and extract useful attribute information
173 * Must specify a network interface (validated below)
175 if (ap->nif == NULL) {
176 err = EINVAL;
177 goto done;
181 * Check out Data API
183 switch (ap->api) {
185 case CMAPI_CPCS:
186 upf = atm_cm_cpcs_upper;
187 break;
189 case CMAPI_SAAL:
190 sl.sl_sap[sli++] = SAP_SSCF_UNI;
191 sl.sl_sap[sli++] = SAP_SSCOP;
192 upf = atm_cm_saal_upper;
193 break;
195 case CMAPI_SSCOP:
196 sl.sl_sap[sli++] = SAP_SSCOP;
197 upf = atm_cm_sscop_upper;
198 break;
200 default:
201 err = EINVAL;
202 goto done;
206 * AAL Attributes
208 if (ap->aal.tag != T_ATM_PRESENT) {
209 err = EINVAL;
210 goto done;
213 switch (ap->aal.type) {
215 case ATM_AAL5:
216 sl.sl_sap[sli++] = SAP_CPCS_AAL5;
217 sl.sl_sap[sli++] = SAP_SAR_AAL5;
218 sl.sl_sap[sli++] = SAP_ATM;
219 break;
221 case ATM_AAL3_4:
222 sl.sl_sap[sli++] = SAP_CPCS_AAL3_4;
223 sl.sl_sap[sli++] = SAP_SAR_AAL3_4;
224 sl.sl_sap[sli++] = SAP_ATM;
225 break;
227 default:
228 err = EINVAL;
229 goto done;
233 * Broadband Bearer Attributes
235 if (ap->bearer.tag != T_ATM_PRESENT) {
236 err = EINVAL;
237 goto done;
240 switch (ap->bearer.v.connection_configuration) {
242 case T_ATM_1_TO_1:
243 cop->co_flags |= COF_P2P;
244 break;
246 case T_ATM_1_TO_MANY:
247 /* Not supported */
248 cop->co_flags |= COF_P2MP;
249 err = EINVAL;
250 goto done;
252 default:
253 err = EINVAL;
254 goto done;
258 * Logical Link Control Attributes
260 if (ap->llc.tag == T_ATM_PRESENT) {
261 if ((ap->blli.tag_l2 != T_ATM_PRESENT) ||
262 (ap->blli.v.layer_2_protocol.ID_type != T_ATM_SIMPLE_ID) ||
263 (ap->blli.v.layer_2_protocol.ID.simple_ID !=
264 T_ATM_BLLI2_I8802) ||
265 (ap->llc.v.llc_len < T_ATM_LLC_MIN_LEN) ||
266 (ap->llc.v.llc_len > T_ATM_LLC_MAX_LEN)) {
267 err = EINVAL;
268 goto done;
270 cop->co_mpx = ATM_ENC_LLC;
271 cop->co_llc = ap->llc;
272 } else
273 cop->co_mpx = ATM_ENC_NULL;
276 * Called Party Attributes
278 if (ap->called.tag != T_ATM_PRESENT) {
279 err = EINVAL;
280 goto done;
283 if ((ap->called.addr.address_format == T_ATM_ABSENT) ||
284 (ap->called.addr.address_length == 0)) {
285 err = EINVAL;
286 goto done;
290 * Calling Party Attributes
292 if (ap->calling.tag != T_ATM_ABSENT) {
293 err = EINVAL;
294 goto done;
298 * Quality of Service Attributes
300 if (ap->qos.tag != T_ATM_PRESENT) {
301 err = EINVAL;
302 goto done;
306 * Terminate stack list
308 sl.sl_sap[sli] = 0;
310 crit_enter();
313 * Let multiplexors decide whether we need a new VCC
315 switch (cop->co_mpx) {
317 case ATM_ENC_NULL:
319 * All of these connections require a new VCC
321 break;
323 case ATM_ENC_LLC:
325 * See if we can share an existing LLC connection
327 cvp = atm_cm_share_llc(ap);
328 if (cvp == NULL)
329 break;
332 * We've got a connection to share
334 cop->co_connvc = cvp;
335 if (cvp->cvc_state == CVCS_ACTIVE) {
336 cop->co_state = COS_ACTIVE;
337 err = 0;
338 } else {
339 cop->co_state = COS_OUTCONN;
340 err = EINPROGRESS;
342 LINK2TAIL(cop, Atm_connection, cvp->cvc_conn->co_mxh, co_next);
343 cop->co_mxh = cvp->cvc_conn->co_mxh;
344 *copp = cop;
346 crit_exit();
347 return (err);
349 default:
350 panic("atm_cm_connect: unknown mpx");
354 * If we get here, it means we need to create
355 * a new VCC for this connection
359 * Validate that network interface is registered and that
360 * a signalling manager is attached
362 for (pip = atm_interface_head; pip != NULL; pip = pip->pif_next) {
363 struct atm_nif *nip;
364 for (nip = pip->pif_nif; nip; nip = nip->nif_pnext) {
365 if (nip == ap->nif)
366 break;
368 if (nip)
369 break;
371 if (pip == NULL) {
372 err = ENXIO;
373 goto donex;
376 if ((smp = pip->pif_sigmgr) == NULL) {
377 err = ENXIO;
378 goto donex;
382 * Get a connection VCC block
384 cvp = (Atm_connvc *)atm_allocate(&atm_connvc_pool);
385 if (cvp == NULL) {
386 err = ENOMEM;
387 goto donex;
391 * Save VCC attributes
393 cvp->cvc_attr = *ap;
394 cvp->cvc_flags |= CVCF_CALLER;
397 * Link the control blocks
399 cop->co_connvc = cvp;
400 cvp->cvc_conn = cop;
401 cvp->cvc_sigmgr = smp;
404 * Create a service stack
406 err = atm_create_stack(cvp, &sl, upf);
407 if (err) {
408 cvp->cvc_state = CVCS_CLEAR;
409 atm_cm_closevc(cvp);
410 goto donex;
414 * Let the signalling manager handle the VCC creation
416 cvp->cvc_state = CVCS_SETUP;
417 switch ((*smp->sm_setup)(cvp, &err)) {
419 case CALL_CONNECTED:
421 * Connection is fully setup - initialize the stack
423 cvp->cvc_state = CVCS_INIT;
424 STACK_CALL(atm_stackcmds[ap->api].init, cvp->cvc_lower,
425 cvp->cvc_tokl, cvp, ap->api_init, 0, err2);
426 if (err2)
427 panic("atm_cm_connect: init");
429 if (cvp->cvc_flags & CVCF_ABORTING) {
431 * Someone on the stack bailed out...schedule the
432 * VCC and stack termination
434 atm_cm_closevc(cvp);
435 err = EFAULT;
436 } else {
438 * Everything looks fine from here
440 cvp->cvc_state = CVCS_ACTIVE;
441 cop->co_state = COS_ACTIVE;
443 break;
445 case CALL_FAILED:
447 * Terminate stack and clean up before we leave
449 cvp->cvc_state = CVCS_CLEAR;
450 atm_cm_closevc(cvp);
451 break;
453 case CALL_PROCEEDING:
455 * We'll just wait for final call status
457 cop->co_state = COS_OUTCONN;
458 err = EINPROGRESS;
459 break;
461 default:
462 panic("atm_cm_connect: setup");
465 donex:
466 crit_exit();
468 done:
469 if (err && err != EINPROGRESS) {
471 * Undo any partial setup stuff
473 if (cop)
474 atm_free((caddr_t)cop);
475 } else {
477 * Finish connection setup
479 crit_enter();
480 cvp->cvc_flags |= CVCF_CONNQ;
481 ENQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
482 LINK2TAIL(cop, Atm_connection, cop->co_mxh, co_next);
483 crit_exit();
484 *copp = cop;
486 return (err);
491 * Listen for Incoming ATM Calls
493 * Called by an endpoint service in order to indicate its willingness to
494 * accept certain incoming calls. The types of calls which the endpoint
495 * is prepared to accept are specified in the Atm_attributes parameter.
497 * For each call which meets the criteria specified by the endpoint, the
498 * endpoint service will receive an incoming call notification via the
499 * endpoint's ep_incoming() function.
501 * To cancel the listening connection, the endpoint user should invoke
502 * atm_cm_release().
504 * Arguments:
505 * epp pointer to endpoint definition structure
506 * token endpoint's listen instance token
507 * ap pointer to listening connection attributes
508 * copp pointer to location to return allocated connection block
510 * Returns:
511 * 0 listening connection installed
512 * errno listen failed - reason indicated
516 atm_cm_listen(Atm_endpoint *epp, void *token, Atm_attributes *ap,
517 Atm_connection **copp)
519 Atm_connection *cop;
520 int err = 0;
522 *copp = NULL;
525 * Get a connection block
527 cop = (Atm_connection *)atm_allocate(&atm_connection_pool);
528 if (cop == NULL)
529 return (ENOMEM);
532 * Initialize connection info
534 cop->co_endpt = epp;
535 cop->co_toku = token;
536 cop->co_mxh = cop;
539 * Validate and extract useful attribute information
543 * Check out Data API
545 switch (ap->api) {
547 case CMAPI_CPCS:
548 case CMAPI_SAAL:
549 case CMAPI_SSCOP:
550 break;
552 default:
553 err = EINVAL;
554 goto done;
558 * AAL Attributes
560 switch (ap->aal.tag) {
562 case T_ATM_PRESENT:
564 switch (ap->aal.type) {
566 case ATM_AAL5:
567 case ATM_AAL3_4:
568 break;
570 default:
571 err = EINVAL;
572 goto done;
574 break;
576 case T_ATM_ABSENT:
577 case T_ATM_ANY:
578 break;
580 default:
581 err = EINVAL;
582 goto done;
586 * Broadband High Layer Information Attributes
588 switch (ap->bhli.tag) {
590 case T_ATM_PRESENT:
591 case T_ATM_ABSENT:
592 case T_ATM_ANY:
593 break;
595 default:
596 err = EINVAL;
597 goto done;
601 * Broadband Low Layer Information Attributes
603 switch (ap->blli.tag_l2) {
605 case T_ATM_PRESENT:
606 case T_ATM_ABSENT:
607 case T_ATM_ANY:
608 break;
610 default:
611 err = EINVAL;
612 goto done;
615 switch (ap->blli.tag_l3) {
617 case T_ATM_PRESENT:
618 case T_ATM_ABSENT:
619 case T_ATM_ANY:
620 break;
622 default:
623 err = EINVAL;
624 goto done;
628 * Logical Link Control Attributes
630 switch (ap->llc.tag) {
632 case T_ATM_PRESENT:
633 if ((ap->blli.tag_l2 != T_ATM_PRESENT) ||
634 (ap->blli.v.layer_2_protocol.ID_type != T_ATM_SIMPLE_ID) ||
635 (ap->blli.v.layer_2_protocol.ID.simple_ID !=
636 T_ATM_BLLI2_I8802) ||
637 (ap->llc.v.llc_len < T_ATM_LLC_MIN_LEN) ||
638 (ap->llc.v.llc_len > T_ATM_LLC_MAX_LEN)) {
639 err = EINVAL;
640 goto done;
642 cop->co_mpx = ATM_ENC_LLC;
643 cop->co_llc = ap->llc;
644 break;
646 case T_ATM_ABSENT:
647 case T_ATM_ANY:
648 cop->co_mpx = ATM_ENC_NULL;
649 break;
651 default:
652 err = EINVAL;
653 goto done;
657 * Called Party Attributes
659 switch (ap->called.tag) {
661 case T_ATM_PRESENT:
662 switch (ap->called.addr.address_format) {
664 case T_ATM_ABSENT:
665 ap->called.tag = T_ATM_ABSENT;
666 break;
668 case T_ATM_PVC_ADDR:
669 err = EINVAL;
670 goto done;
672 break;
674 case T_ATM_ABSENT:
675 case T_ATM_ANY:
676 break;
678 default:
679 err = EINVAL;
680 goto done;
684 * Get an attribute block and save listening attributes
686 cop->co_lattr = (Atm_attributes *)atm_allocate(&atm_attributes_pool);
687 if (cop->co_lattr == NULL) {
688 err = ENOMEM;
689 goto done;
691 *cop->co_lattr = *ap;
694 * Now try to register the listening connection
696 crit_enter();
697 if (atm_cm_match(cop->co_lattr, NULL) != NULL) {
699 * Can't have matching listeners
701 err = EADDRINUSE;
702 goto donex;
704 cop->co_state = COS_LISTEN;
705 LINK2TAIL(cop, Atm_connection, atm_listen_queue, co_next);
707 donex:
708 crit_exit();
710 done:
711 if (err) {
713 * Undo any partial setup stuff
715 if (cop) {
716 if (cop->co_lattr)
717 atm_free((caddr_t)cop->co_lattr);
718 atm_free((caddr_t)cop);
720 } else {
722 * Finish connection setup
724 *copp = cop;
726 return (err);
731 * Add to LLC Connection
733 * Called by an endpoint service to create a new Connection Manager API
734 * instance to be associated with an LLC-multiplexed connection instance
735 * which has been previously created. The endpoint provided token will
736 * be used in all further CM -> endpoint function calls, and the returned
737 * connection block pointer must be used in all subsequent endpoint -> CM
738 * function calls.
740 * If the return indicates that the connection setup has been immediately
741 * successful, then the connection is ready for data transmission.
743 * If the return indicates that the connection setup is still in progress,
744 * then the endpoint must wait for notification from the Connection Manager
745 * indicating the final status of the call setup. If the call setup completes
746 * successfully, then a "call connected" notification will be sent to the
747 * endpoint by the Connection Manager. If the call setup fails, then the
748 * endpoint will receive a "call cleared" notification.
750 * All connection instances must be freed with an atm_cm_release() call.
752 * Arguments:
753 * epp pointer to endpoint definition structure
754 * token endpoint's connection instance token
755 * llc pointer to llc attributes for new connection
756 * ecop pointer to existing connection block
757 * copp pointer to location to return allocated connection block
759 * Returns:
760 * 0 connection has been successfully established
761 * EINPROGRESS connection establishment is in progress
762 * errno addllc failed - reason indicated
766 atm_cm_addllc(Atm_endpoint *epp, void *token, struct attr_llc *llc,
767 Atm_connection *ecop, Atm_connection **copp)
769 Atm_connection *cop, *cop2;
770 Atm_connvc *cvp;
771 int err;
773 *copp = NULL;
776 * Check out requested LLC attributes
778 if ((llc->tag != T_ATM_PRESENT) ||
779 ((llc->v.flags & T_ATM_LLC_SHARING) == 0) ||
780 (llc->v.llc_len < T_ATM_LLC_MIN_LEN) ||
781 (llc->v.llc_len > T_ATM_LLC_MAX_LEN))
782 return (EINVAL);
785 * Get a connection block
787 cop = (Atm_connection *)atm_allocate(&atm_connection_pool);
788 if (cop == NULL)
789 return (ENOMEM);
792 * Initialize connection info
794 cop->co_endpt = epp;
795 cop->co_toku = token;
796 cop->co_llc = *llc;
798 crit_enter();
801 * Ensure that supplied connection is really valid
803 cop2 = NULL;
804 for (cvp = Q_HEAD(atm_connection_queue, Atm_connvc); cvp;
805 cvp = Q_NEXT(cvp, Atm_connvc, cvc_q)) {
806 for (cop2 = cvp->cvc_conn; cop2; cop2 = cop2->co_next) {
807 if (ecop == cop2)
808 break;
810 if (cop2)
811 break;
813 if (cop2 == NULL) {
814 err = ENOENT;
815 goto done;
818 switch (ecop->co_state) {
820 case COS_OUTCONN:
821 case COS_INACCEPT:
822 err = EINPROGRESS;
823 break;
825 case COS_ACTIVE:
826 err = 0;
827 break;
829 default:
830 err = EINVAL;
831 goto done;
835 * Connection must be LLC multiplexed and shared
837 if ((ecop->co_mpx != ATM_ENC_LLC) ||
838 ((ecop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0)) {
839 err = EINVAL;
840 goto done;
844 * This new LLC header must be unique for this VCC
846 cop2 = ecop->co_mxh;
847 while (cop2) {
848 int i = MIN(llc->v.llc_len, cop2->co_llc.v.llc_len);
850 if (KM_CMP(llc->v.llc_info, cop2->co_llc.v.llc_info, i) == 0) {
851 err = EINVAL;
852 goto done;
855 cop2 = cop2->co_next;
859 * Everything seems to check out
861 cop->co_flags = ecop->co_flags;
862 cop->co_state = ecop->co_state;
863 cop->co_mpx = ecop->co_mpx;
864 cop->co_connvc = ecop->co_connvc;
866 LINK2TAIL(cop, Atm_connection, ecop->co_mxh, co_next);
867 cop->co_mxh = ecop->co_mxh;
869 done:
870 crit_exit();
872 if (err && err != EINPROGRESS) {
874 * Undo any partial setup stuff
876 if (cop)
877 atm_free((caddr_t)cop);
878 } else {
880 * Pass new connection back to caller
882 *copp = cop;
884 return (err);
889 * XXX
891 * Arguments:
892 * cop pointer to connection block
893 * id identifier for party to be added
894 * addr address of party to be added
896 * Returns:
897 * 0 addparty successful
898 * errno addparty failed - reason indicated
902 atm_cm_addparty(Atm_connection *cop, int id, struct t_atm_sap *addr)
904 return (0);
909 * XXX
911 * Arguments:
912 * cop pointer to connection block
913 * id identifier for party to be added
914 * cause pointer to cause of drop
916 * Returns:
917 * 0 dropparty successful
918 * errno dropparty failed - reason indicated
922 atm_cm_dropparty(Atm_connection *cop, int id, struct t_atm_cause *cause)
924 return (0);
929 * Release Connection Resources
931 * Called by the endpoint service in order to terminate an ATM connection
932 * and to release all system resources for the connection. This function
933 * must be called for every allocated connection instance and must only
934 * be called by the connection's owner.
936 * Arguments:
937 * cop pointer to connection block
938 * cause pointer to cause of release
940 * Returns:
941 * 0 release successful
942 * errno release failed - reason indicated
946 atm_cm_release(Atm_connection *cop, struct t_atm_cause *cause)
948 Atm_connvc *cvp;
950 crit_enter();
953 * First, a quick state validation check
955 switch (cop->co_state) {
957 case COS_OUTCONN:
958 case COS_LISTEN:
959 case COS_INACCEPT:
960 case COS_ACTIVE:
961 case COS_CLEAR:
963 * Break link to user
965 cop->co_toku = NULL;
966 break;
968 case COS_INCONN:
969 crit_exit();
970 return (EFAULT);
972 default:
973 panic("atm_cm_release: bogus conn state");
977 * Check out the VCC state too
979 if ((cvp = cop->co_connvc) != NULL) {
981 switch (cvp->cvc_state) {
983 case CVCS_SETUP:
984 case CVCS_INIT:
985 case CVCS_ACCEPT:
986 case CVCS_ACTIVE:
987 break;
989 case CVCS_INCOMING:
990 crit_exit();
991 return (EFAULT);
993 case CVCS_CLEAR:
994 crit_exit();
995 return (EALREADY);
997 default:
998 panic("atm_cm_release: bogus connvc state");
1002 * If we're the only connection, terminate the VCC
1004 if ((cop->co_mxh == cop) && (cop->co_next == NULL)) {
1005 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
1006 cvp->cvc_attr.cause.v = *cause;
1007 atm_cm_closevc(cvp);
1012 * Now get rid of the connection
1014 atm_cm_closeconn(cop, cause);
1016 return (0);
1021 * Abort an ATM Connection VCC
1023 * This function allows any non-owner kernel entity to request an
1024 * immediate termination of an ATM VCC. This will normally be called
1025 * when encountering a catastrophic error condition that cannot be
1026 * resolved via the available stack protocols. The connection manager
1027 * will schedule the connection's termination, including notifying the
1028 * connection owner of the termination.
1030 * This function should only be called by a stack entity instance. After
1031 * calling the function, the caller should set a protocol state which just
1032 * waits for a <sap>_TERM stack command to be delivered.
1034 * Arguments:
1035 * cvp pointer to connection VCC block
1036 * cause pointer to cause of abort
1038 * Returns:
1039 * 0 abort successful
1040 * errno abort failed - reason indicated
1044 atm_cm_abort(Atm_connvc *cvp, struct t_atm_cause *cause)
1046 ATM_DEBUG2("atm_cm_abort: cvp=%p cause=%d\n",
1047 cvp, cause->cause_value);
1050 * Note that we're aborting
1052 cvp->cvc_flags |= CVCF_ABORTING;
1054 switch (cvp->cvc_state) {
1056 case CVCS_INIT:
1058 * In-line code will handle this
1060 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
1061 cvp->cvc_attr.cause.v = *cause;
1062 break;
1064 case CVCS_SETUP:
1065 case CVCS_ACCEPT:
1066 case CVCS_ACTIVE:
1068 * Schedule connection termination, since we want
1069 * to avoid any sequencing interactions
1071 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
1072 cvp->cvc_attr.cause.v = *cause;
1073 CVC_TIMER(cvp, 0);
1074 break;
1076 case CVCS_REJECT:
1077 case CVCS_RELEASE:
1078 case CVCS_CLEAR:
1079 case CVCS_TERM:
1081 * Ignore abort, as we're already terminating
1083 break;
1085 default:
1086 log(LOG_ERR,
1087 "atm_cm_abort: invalid state: cvp=%p, state=%d\n",
1088 cvp, cvp->cvc_state);
1090 return (0);
1095 * Incoming ATM Call Received
1097 * Called by a signalling manager to indicate that a new call request has
1098 * been received. This function will allocate and initialize the connection
1099 * manager control blocks and queue this call request. The call request
1100 * processing function, atm_cm_procinq(), will be scheduled to perform the
1101 * call processing.
1103 * Arguments:
1104 * vcp pointer to incoming call's VCC control block
1105 * ap pointer to incoming call's attributes
1107 * Returns:
1108 * 0 call queuing successful
1109 * errno call queuing failed - reason indicated
1113 atm_cm_incoming(struct vccb *vcp, Atm_attributes *ap)
1115 Atm_connvc *cvp;
1116 int err;
1120 * Do some minimal attribute validation
1124 * Must specify a network interface
1126 if (ap->nif == NULL)
1127 return (EINVAL);
1130 * AAL Attributes
1132 if ((ap->aal.tag != T_ATM_PRESENT) ||
1133 ((ap->aal.type != ATM_AAL5) &&
1134 (ap->aal.type != ATM_AAL3_4)))
1135 return (EINVAL);
1138 * Traffic Descriptor Attributes
1140 if ((ap->traffic.tag != T_ATM_PRESENT) &&
1141 (ap->traffic.tag != T_ATM_ABSENT))
1142 return (EINVAL);
1145 * Broadband Bearer Attributes
1147 if ((ap->bearer.tag != T_ATM_PRESENT) ||
1148 ((ap->bearer.v.connection_configuration != T_ATM_1_TO_1) &&
1149 (ap->bearer.v.connection_configuration != T_ATM_1_TO_MANY)))
1150 return (EINVAL);
1153 * Broadband High Layer Attributes
1155 if ((ap->bhli.tag != T_ATM_PRESENT) &&
1156 (ap->bhli.tag != T_ATM_ABSENT))
1157 return (EINVAL);
1160 * Broadband Low Layer Attributes
1162 if ((ap->blli.tag_l2 != T_ATM_PRESENT) &&
1163 (ap->blli.tag_l2 != T_ATM_ABSENT))
1164 return (EINVAL);
1165 if ((ap->blli.tag_l3 != T_ATM_PRESENT) &&
1166 (ap->blli.tag_l3 != T_ATM_ABSENT))
1167 return (EINVAL);
1170 * Logical Link Control Attributes
1172 if (ap->llc.tag == T_ATM_PRESENT)
1173 return (EINVAL);
1174 ap->llc.tag = T_ATM_ANY;
1177 * Called Party Attributes
1179 if ((ap->called.tag != T_ATM_PRESENT) ||
1180 (ap->called.addr.address_format == T_ATM_ABSENT))
1181 return (EINVAL);
1182 if (ap->called.tag == T_ATM_ABSENT) {
1183 ap->called.addr.address_format = T_ATM_ABSENT;
1184 ap->called.addr.address_length = 0;
1185 ap->called.subaddr.address_format = T_ATM_ABSENT;
1186 ap->called.subaddr.address_length = 0;
1190 * Calling Party Attributes
1192 if ((ap->calling.tag != T_ATM_PRESENT) &&
1193 (ap->calling.tag != T_ATM_ABSENT))
1194 return (EINVAL);
1195 if (ap->calling.tag == T_ATM_ABSENT) {
1196 ap->calling.addr.address_format = T_ATM_ABSENT;
1197 ap->calling.addr.address_length = 0;
1198 ap->calling.subaddr.address_format = T_ATM_ABSENT;
1199 ap->calling.subaddr.address_length = 0;
1203 * Quality of Service Attributes
1205 if (ap->qos.tag != T_ATM_PRESENT)
1206 return (EINVAL);
1209 * Transit Network Attributes
1211 if ((ap->transit.tag != T_ATM_PRESENT) &&
1212 (ap->transit.tag != T_ATM_ABSENT))
1213 return (EINVAL);
1216 * Cause Attributes
1218 if ((ap->cause.tag != T_ATM_PRESENT) &&
1219 (ap->cause.tag != T_ATM_ABSENT))
1220 return (EINVAL);
1223 * Get a connection VCC block
1225 cvp = (Atm_connvc *)atm_allocate(&atm_connvc_pool);
1226 if (cvp == NULL) {
1227 err = ENOMEM;
1228 goto fail;
1232 * Initialize the control block
1234 cvp->cvc_vcc = vcp;
1235 cvp->cvc_sigmgr = vcp->vc_pif->pif_sigmgr;
1236 cvp->cvc_attr = *ap;
1237 cvp->cvc_state = CVCS_INCOMING;
1240 * Control queue length
1242 crit_enter();
1243 if (atm_incoming_qlen >= ATM_CALLQ_MAX) {
1244 crit_exit();
1245 err = EBUSY;
1246 goto fail;
1250 * Queue request and schedule call processing function
1252 cvp->cvc_flags |= CVCF_INCOMQ;
1253 ENQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
1254 if (atm_incoming_qlen++ == 0) {
1255 atm_cm_procinq(NULL);
1259 * Link for signalling manager
1261 vcp->vc_connvc = cvp;
1263 crit_exit();
1265 return (0);
1267 fail:
1269 * Free any resources
1271 if (cvp)
1272 atm_free((caddr_t)cvp);
1273 return (err);
1278 * VCC Connected Notification
1280 * This function is called by a signalling manager as notification that a
1281 * VCC call setup has been successful.
1283 * Arguments:
1284 * cvp pointer to connection VCC block
1286 * Returns:
1287 * none
1290 void
1291 atm_cm_connected(Atm_connvc *cvp)
1293 Atm_connection *cop, *cop2;
1294 KBuffer *m;
1295 int err;
1297 crit_enter();
1300 * Validate connection vcc
1302 switch (cvp->cvc_state) {
1304 case CVCS_SETUP:
1306 * Initialize the stack
1308 cvp->cvc_state = CVCS_INIT;
1309 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].init,
1310 cvp->cvc_lower, cvp->cvc_tokl,
1311 cvp, cvp->cvc_attr.api_init, 0, err);
1312 if (err)
1313 panic("atm_cm_connected: init");
1315 if (cvp->cvc_flags & CVCF_ABORTING) {
1317 * Someone on the stack bailed out...notify all of the
1318 * connections and schedule the VCC termination
1320 cop = cvp->cvc_conn;
1321 while (cop) {
1322 cop2 = cop->co_next;
1323 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
1324 cop = cop2;
1326 atm_cm_closevc(cvp);
1327 crit_exit();
1328 return;
1330 break;
1332 case CVCS_ACCEPT:
1334 * Stack already initialized
1336 break;
1338 default:
1339 panic("atm_cm_connected: connvc state");
1343 * VCC is ready for action
1345 cvp->cvc_state = CVCS_ACTIVE;
1348 * Notify all connections that the call has completed
1350 cop = cvp->cvc_conn;
1351 while (cop) {
1352 cop2 = cop->co_next;
1354 switch (cop->co_state) {
1356 case COS_OUTCONN:
1357 case COS_INACCEPT:
1358 cop->co_state = COS_ACTIVE;
1359 (*cop->co_endpt->ep_connected)(cop->co_toku);
1360 break;
1362 case COS_ACTIVE:
1364 * May get here if an ep_connected() call (from
1365 * above) results in an atm_cm_addllc() call for
1366 * the just connected connection.
1368 break;
1370 default:
1371 panic("atm_cm_connected: connection state");
1374 cop = cop2;
1377 crit_exit();
1380 * Input any queued packets
1382 while ((m = cvp->cvc_rcvq) != NULL) {
1383 cvp->cvc_rcvq = KB_QNEXT(m);
1384 cvp->cvc_rcvqlen--;
1385 KB_QNEXT(m) = NULL;
1388 * Currently only supported for CPCS API
1390 atm_cm_cpcs_upper(CPCS_UNITDATA_SIG, cvp, (int)m, 0);
1393 return;
1398 * VCC Cleared Notification
1400 * This function is called by a signalling manager as notification that a
1401 * VCC call has been cleared. The cause information describing the reason
1402 * for the call clearing will be contained in the connection VCC attributes.
1404 * Arguments:
1405 * cvp pointer to connection VCC block
1407 * Returns:
1408 * none
1411 void
1412 atm_cm_cleared(Atm_connvc *cvp)
1414 Atm_connection *cop, *cop2;
1416 #ifdef DIAGNOSTIC
1417 if ((cvp->cvc_state == CVCS_FREE) ||
1418 (cvp->cvc_state >= CVCS_CLEAR))
1419 panic("atm_cm_cleared");
1420 #endif
1422 cvp->cvc_state = CVCS_CLEAR;
1424 crit_enter();
1427 * Terminate all connections
1429 cop = cvp->cvc_conn;
1430 while (cop) {
1431 cop2 = cop->co_next;
1432 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
1433 cop = cop2;
1437 * Clean up connection VCC
1439 atm_cm_closevc(cvp);
1441 crit_exit();
1443 return;
1448 * Process Incoming Call Queue
1450 * This function is scheduled by atm_cm_incoming() in order to process
1451 * all the entries on the incoming call queue.
1453 * Arguments:
1454 * arg argument passed on timeout() call
1456 * Returns:
1457 * none
1460 static KTimeout_ret
1461 atm_cm_procinq(void *arg)
1463 Atm_connvc *cvp;
1464 int cnt = 0;
1467 * Only process incoming calls up to our quota
1469 while (cnt++ < ATM_CALLQ_MAX) {
1470 crit_enter();
1473 * Get next awaiting call
1475 cvp = Q_HEAD(atm_incoming_queue, Atm_connvc);
1476 if (cvp == NULL) {
1477 crit_exit();
1478 break;
1480 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
1481 atm_incoming_qlen--;
1482 cvp->cvc_flags &= ~CVCF_INCOMQ;
1485 * Handle the call
1487 atm_cm_incall(cvp);
1489 crit_exit();
1493 * If we've expended our quota, reschedule ourselves
1495 if (cnt >= ATM_CALLQ_MAX) {
1496 callout_reset(&atm_cm_procinq_ch, 1, atm_cm_procinq, NULL);
1502 * Process Incoming Call
1504 * This function will search through the listening queue and try to find
1505 * matching endpoint(s) for the incoming call. If we find any, we will
1506 * notify the endpoint service(s) of the incoming call and will then
1507 * notify the signalling manager to progress the call to an active status.
1509 * If there are no listeners for the call, the signalling manager will be
1510 * notified of a call rejection.
1512 * Called from a critical section.
1514 * Arguments:
1515 * cvp pointer to connection VCC for incoming call
1517 * Returns:
1518 * none
1521 static void
1522 atm_cm_incall(Atm_connvc *cvp)
1524 Atm_connection *cop, *lcop, *hcop;
1525 Atm_attributes attr;
1526 int err;
1528 hcop = NULL;
1529 lcop = NULL;
1530 cop = NULL;
1531 attr = cvp->cvc_attr;
1534 * Look for matching listeners
1536 while ((lcop = atm_cm_match(&attr, lcop)) != NULL) {
1538 if (cop == NULL) {
1540 * Need a new connection block
1542 cop = (Atm_connection *)
1543 atm_allocate(&atm_connection_pool);
1544 if (cop == NULL) {
1545 cvp->cvc_attr.cause = atm_cause_tmpl;
1546 cvp->cvc_attr.cause.v.cause_value =
1547 T_ATM_CAUSE_TEMPORARY_FAILURE;
1548 goto fail;
1553 * Initialize connection from listener and incoming call
1555 cop->co_mxh = NULL;
1556 cop->co_state = COS_INCONN;
1557 cop->co_mpx = lcop->co_mpx;
1558 cop->co_endpt = lcop->co_endpt;
1559 cop->co_llc = lcop->co_llc;
1561 switch (attr.bearer.v.connection_configuration) {
1563 case T_ATM_1_TO_1:
1564 cop->co_flags |= COF_P2P;
1565 break;
1567 case T_ATM_1_TO_MANY:
1568 /* Not supported */
1569 cop->co_flags |= COF_P2MP;
1570 cvp->cvc_attr.cause = atm_cause_tmpl;
1571 cvp->cvc_attr.cause.v.cause_value =
1572 T_ATM_CAUSE_BEARER_CAPABILITY_NOT_IMPLEMENTED;
1573 goto fail;
1577 * Notify endpoint of incoming call
1579 err = (*cop->co_endpt->ep_incoming)
1580 (lcop->co_toku, cop, &cvp->cvc_attr, &cop->co_toku);
1582 if (err == 0) {
1585 * Endpoint has accepted the call
1587 * Setup call attributes
1589 if (hcop == NULL) {
1590 cvp->cvc_attr.api = lcop->co_lattr->api;
1591 cvp->cvc_attr.api_init =
1592 lcop->co_lattr->api_init;
1593 cvp->cvc_attr.llc = lcop->co_lattr->llc;
1595 cvp->cvc_attr.headin = MAX(cvp->cvc_attr.headin,
1596 lcop->co_lattr->headin);
1599 * Setup connection info and queueing
1601 cop->co_state = COS_INACCEPT;
1602 cop->co_connvc = cvp;
1603 LINK2TAIL(cop, Atm_connection, hcop, co_next);
1604 cop->co_mxh = hcop;
1607 * Need a new connection block next time around
1609 cop = NULL;
1611 } else {
1613 * Endpoint refuses call
1615 goto fail;
1620 * We're done looking for listeners
1622 if (hcop) {
1624 * Someone actually wants the call, so notify
1625 * the signalling manager to continue
1627 cvp->cvc_flags |= CVCF_CONNQ;
1628 ENQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
1629 if (atm_cm_accept(cvp, hcop))
1630 goto fail;
1632 } else {
1634 * Nobody around to take the call
1636 cvp->cvc_attr.cause = atm_cause_tmpl;
1637 cvp->cvc_attr.cause.v.cause_value =
1638 T_ATM_CAUSE_INCOMPATIBLE_DESTINATION;
1639 goto fail;
1643 * Clean up loose ends
1645 if (cop)
1646 atm_free((caddr_t)cop);
1649 * Call has been accepted
1651 return;
1653 fail:
1655 * Call failed - notify any endpoints of the call failure
1659 * Clean up loose ends
1661 if (cop)
1662 atm_free((caddr_t)cop);
1664 if (cvp->cvc_attr.cause.tag != T_ATM_PRESENT) {
1665 cvp->cvc_attr.cause = atm_cause_tmpl;
1666 cvp->cvc_attr.cause.v.cause_value =
1667 T_ATM_CAUSE_UNSPECIFIED_NORMAL;
1669 cop = hcop;
1670 while (cop) {
1671 Atm_connection *cop2 = cop->co_next;
1672 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
1673 cop = cop2;
1677 * Tell the signalling manager to reject the call
1679 atm_cm_closevc(cvp);
1681 return;
1686 * Accept an Incoming ATM Call
1688 * Some endpoint service(s) wants to accept an incoming call, so the
1689 * signalling manager will be notified to attempt to progress the call
1690 * to an active status.
1692 * If the signalling manager indicates that connection activation has
1693 * been immediately successful, then all of the endpoints will be notified
1694 * that the connection is ready for data transmission.
1696 * If the return indicates that connection activation is still in progress,
1697 * then the endpoints must wait for notification from the Connection Manager
1698 * indicating the final status of the call setup. If the call setup completes
1699 * successfully, then a "call connected" notification will be sent to the
1700 * endpoints by the Connection Manager. If the call setup fails, then the
1701 * endpoints will receive a "call cleared" notification.
1703 * Called from a critical section.
1705 * Arguments:
1706 * cvp pointer to connection VCC for incoming call
1707 * cop pointer to head of accepted connections
1709 * Returns:
1710 * 0 connection has been successfully activated
1711 * errno accept failed - reason indicated
1714 static int
1715 atm_cm_accept(Atm_connvc *cvp, Atm_connection *cop)
1717 struct stack_list sl;
1718 void (*upf)(int, void *, int, int);
1719 int sli, err, err2;
1723 * Link vcc to connections
1725 cvp->cvc_conn = cop;
1728 * Initialize stack list index
1730 sli = 0;
1733 * Check out Data API
1735 switch (cvp->cvc_attr.api) {
1737 case CMAPI_CPCS:
1738 upf = atm_cm_cpcs_upper;
1739 break;
1741 case CMAPI_SAAL:
1742 sl.sl_sap[sli++] = SAP_SSCF_UNI;
1743 sl.sl_sap[sli++] = SAP_SSCOP;
1744 upf = atm_cm_saal_upper;
1745 break;
1747 case CMAPI_SSCOP:
1748 sl.sl_sap[sli++] = SAP_SSCOP;
1749 upf = atm_cm_sscop_upper;
1750 break;
1752 default:
1753 upf = NULL;
1757 * AAL Attributes
1759 switch (cvp->cvc_attr.aal.type) {
1761 case ATM_AAL5:
1762 sl.sl_sap[sli++] = SAP_CPCS_AAL5;
1763 sl.sl_sap[sli++] = SAP_SAR_AAL5;
1764 sl.sl_sap[sli++] = SAP_ATM;
1765 break;
1767 case ATM_AAL3_4:
1768 sl.sl_sap[sli++] = SAP_CPCS_AAL3_4;
1769 sl.sl_sap[sli++] = SAP_SAR_AAL3_4;
1770 sl.sl_sap[sli++] = SAP_ATM;
1771 break;
1775 * Terminate stack list
1777 sl.sl_sap[sli] = 0;
1780 * Create a service stack
1782 err = atm_create_stack(cvp, &sl, upf);
1783 if (err) {
1784 goto done;
1788 * Let the signalling manager finish the VCC activation
1790 switch ((*cvp->cvc_sigmgr->sm_accept)(cvp->cvc_vcc, &err)) {
1792 case CALL_PROCEEDING:
1794 * Note that we're not finished yet
1796 err = EINPROGRESS;
1797 /* FALLTHRU */
1799 case CALL_CONNECTED:
1801 * Initialize the stack now, even if the call isn't totally
1802 * active yet. We want to avoid the delay between getting
1803 * the "call connected" event and actually notifying the
1804 * adapter to accept cells on the new VCC - if the delay is
1805 * too long, then we end up dropping the first pdus sent by
1806 * the caller.
1808 cvp->cvc_state = CVCS_INIT;
1809 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].init,
1810 cvp->cvc_lower, cvp->cvc_tokl, cvp,
1811 cvp->cvc_attr.api_init, 0, err2);
1812 if (err2)
1813 panic("atm_cm_accept: init");
1815 if (cvp->cvc_flags & CVCF_ABORTING) {
1817 * Someone on the stack bailed out...schedule the
1818 * VCC and stack termination
1820 err = ECONNABORTED;
1821 } else {
1823 * Everything looks fine from here
1825 if (err)
1826 cvp->cvc_state = CVCS_ACCEPT;
1827 else
1828 cvp->cvc_state = CVCS_ACTIVE;
1830 break;
1832 case CALL_FAILED:
1834 * Terminate stack and clean up before we leave
1836 cvp->cvc_state = CVCS_CLEAR;
1837 break;
1839 default:
1840 panic("atm_cm_accept: accept");
1843 done:
1844 if (err == 0) {
1846 * Call has been connected, notify endpoints
1848 while (cop) {
1849 Atm_connection *cop2 = cop->co_next;
1851 cop->co_state = COS_ACTIVE;
1852 (*cop->co_endpt->ep_connected)(cop->co_toku);
1853 cop = cop2;
1856 } else if (err == EINPROGRESS) {
1858 * Call is still in progress, endpoint must wait
1860 err = 0;
1862 } else {
1864 * Let caller know we failed
1866 cvp->cvc_attr.cause = atm_cause_tmpl;
1867 cvp->cvc_attr.cause.v.cause_value =
1868 T_ATM_CAUSE_UNSPECIFIED_RESOURCE_UNAVAILABLE;
1871 return (err);
1876 * Match Attributes on Listening Queue
1878 * This function will attempt to match the supplied connection attributes
1879 * with one of the registered attributes in the listening queue. The pcop
1880 * argument may be supplied in order to allow multiple listeners to share
1881 * an incoming call (if supported by the listeners).
1883 * Called from a critical section.
1885 * Arguments:
1886 * ap pointer to attributes to be matched
1887 * pcop pointer to the previously matched connection
1889 * Returns:
1890 * addr connection with which a match was found
1891 * 0 no match found
1894 Atm_connection *
1895 atm_cm_match(Atm_attributes *ap, Atm_connection *pcop)
1897 Atm_connection *cop;
1898 Atm_attributes *lap;
1902 * If we've already matched a listener...
1904 if (pcop) {
1906 * Make sure already matched listener supports sharing
1908 if ((pcop->co_mpx != ATM_ENC_LLC) ||
1909 ((pcop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0))
1910 return (NULL);
1913 * Position ourselves after the matched entry
1915 for (cop = atm_listen_queue; cop; cop = cop->co_next) {
1916 if (cop == pcop) {
1917 cop = pcop->co_next;
1918 break;
1921 } else {
1923 * Start search at top of listening queue
1925 cop = atm_listen_queue;
1929 * Search through listening queue
1931 for (; cop; cop = cop->co_next) {
1933 lap = cop->co_lattr;
1936 * If we're trying to share, check that this entry allows it
1938 if (pcop) {
1939 if ((cop->co_mpx != ATM_ENC_LLC) ||
1940 ((cop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0))
1941 continue;
1945 * ALL "matchable" attributes must match
1949 * BHLI
1951 if (lap->bhli.tag == T_ATM_ABSENT) {
1952 if (ap->bhli.tag == T_ATM_PRESENT)
1953 continue;
1954 } else if (lap->bhli.tag == T_ATM_PRESENT) {
1955 if (ap->bhli.tag == T_ATM_ABSENT)
1956 continue;
1957 if (ap->bhli.tag == T_ATM_PRESENT)
1958 if (KM_CMP(&lap->bhli.v, &ap->bhli.v,
1959 sizeof(struct t_atm_bhli)))
1960 continue;
1964 * BLLI Layer 2
1966 if (lap->blli.tag_l2 == T_ATM_ABSENT) {
1967 if (ap->blli.tag_l2 == T_ATM_PRESENT)
1968 continue;
1969 } else if (lap->blli.tag_l2 == T_ATM_PRESENT) {
1970 if (ap->blli.tag_l2 == T_ATM_ABSENT)
1971 continue;
1972 if (ap->blli.tag_l2 == T_ATM_PRESENT) {
1973 if (KM_CMP(&lap->blli.v.layer_2_protocol.ID,
1974 &ap->blli.v.layer_2_protocol.ID,
1975 sizeof(
1976 ap->blli.v.layer_2_protocol.ID)))
1977 continue;
1982 * BLLI Layer 3
1984 if (lap->blli.tag_l3 == T_ATM_ABSENT) {
1985 if (ap->blli.tag_l3 == T_ATM_PRESENT)
1986 continue;
1987 } else if (lap->blli.tag_l3 == T_ATM_PRESENT) {
1988 if (ap->blli.tag_l3 == T_ATM_ABSENT)
1989 continue;
1990 if (ap->blli.tag_l3 == T_ATM_PRESENT) {
1991 if (KM_CMP(&lap->blli.v.layer_3_protocol.ID,
1992 &ap->blli.v.layer_3_protocol.ID,
1993 sizeof(
1994 ap->blli.v.layer_3_protocol.ID)))
1995 continue;
2000 * LLC
2002 if (lap->llc.tag == T_ATM_ABSENT) {
2003 if (ap->llc.tag == T_ATM_PRESENT)
2004 continue;
2005 } else if (lap->llc.tag == T_ATM_PRESENT) {
2006 if (ap->llc.tag == T_ATM_ABSENT)
2007 continue;
2008 if (ap->llc.tag == T_ATM_PRESENT) {
2009 int i = MIN(lap->llc.v.llc_len,
2010 ap->llc.v.llc_len);
2012 if (KM_CMP(lap->llc.v.llc_info,
2013 ap->llc.v.llc_info, i))
2014 continue;
2019 * AAL
2021 if (lap->aal.tag == T_ATM_ABSENT) {
2022 if (ap->aal.tag == T_ATM_PRESENT)
2023 continue;
2024 } else if (lap->aal.tag == T_ATM_PRESENT) {
2025 if (ap->aal.tag == T_ATM_ABSENT)
2026 continue;
2027 if (ap->aal.tag == T_ATM_PRESENT) {
2028 if (lap->aal.type != ap->aal.type)
2029 continue;
2030 if (lap->aal.type == ATM_AAL5) {
2031 if (lap->aal.v.aal5.SSCS_type !=
2032 ap->aal.v.aal5.SSCS_type)
2033 continue;
2034 } else {
2035 if (lap->aal.v.aal4.SSCS_type !=
2036 ap->aal.v.aal4.SSCS_type)
2037 continue;
2043 * Called Party
2045 if (lap->called.tag == T_ATM_ABSENT) {
2046 if (ap->called.tag == T_ATM_PRESENT)
2047 continue;
2048 } else if (lap->called.tag == T_ATM_PRESENT) {
2049 if (ap->called.tag == T_ATM_ABSENT)
2050 continue;
2051 if (ap->called.tag == T_ATM_PRESENT) {
2052 if ((!ATM_ADDR_EQUAL(&lap->called.addr,
2053 &ap->called.addr)) ||
2054 (!ATM_ADDR_EQUAL(&lap->called.subaddr,
2055 &ap->called.subaddr)))
2056 continue;
2061 * Found a full match - return it
2063 break;
2066 return (cop);
2071 * Find Shareable LLC VCC
2073 * Given a endpoint-supplied connection attribute using LLC multiplexing,
2074 * this function will attempt to locate an existing connection which meets
2075 * the requirements of the supplied attributes.
2077 * Called from a critical section.
2079 * Arguments:
2080 * ap pointer to requested attributes
2082 * Returns:
2083 * addr shareable LLC connection VCC
2084 * 0 no shareable VCC available
2087 static Atm_connvc *
2088 atm_cm_share_llc(Atm_attributes *ap)
2090 Atm_connection *cop;
2091 Atm_connvc *cvp;
2094 * Is requestor willing to share?
2096 if ((ap->llc.v.flags & T_ATM_LLC_SHARING) == 0)
2097 return (NULL);
2100 * Try to find a shareable connection
2102 for (cvp = Q_HEAD(atm_connection_queue, Atm_connvc); cvp;
2103 cvp = Q_NEXT(cvp, Atm_connvc, cvc_q)) {
2106 * Dont use terminating connections
2108 switch (cvp->cvc_state) {
2110 case CVCS_SETUP:
2111 case CVCS_ACCEPT:
2112 case CVCS_ACTIVE:
2113 break;
2115 default:
2116 continue;
2120 * Is connection LLC and shareable?
2122 if ((cvp->cvc_attr.llc.tag != T_ATM_PRESENT) ||
2123 ((cvp->cvc_attr.llc.v.flags & T_ATM_LLC_SHARING) == 0))
2124 continue;
2127 * Match requested attributes with existing connection
2129 if (ap->nif != cvp->cvc_attr.nif)
2130 continue;
2132 if ((ap->api != cvp->cvc_attr.api) ||
2133 (ap->api_init != cvp->cvc_attr.api_init))
2134 continue;
2137 * Remote Party
2139 if (cvp->cvc_flags & CVCF_CALLER) {
2140 if ((!ATM_ADDR_EQUAL(&ap->called.addr,
2141 &cvp->cvc_attr.called.addr)) ||
2142 (!ATM_ADDR_EQUAL(&ap->called.subaddr,
2143 &cvp->cvc_attr.called.subaddr)))
2144 continue;
2145 } else {
2146 if (cvp->cvc_attr.calling.tag != T_ATM_PRESENT)
2147 continue;
2148 if ((!ATM_ADDR_EQUAL(&ap->called.addr,
2149 &cvp->cvc_attr.calling.addr)) ||
2150 (!ATM_ADDR_EQUAL(&ap->called.subaddr,
2151 &cvp->cvc_attr.calling.subaddr)))
2152 continue;
2156 * AAL
2158 if (ap->aal.type == ATM_AAL5) {
2159 struct t_atm_aal5 *ap5, *cv5;
2161 ap5 = &ap->aal.v.aal5;
2162 cv5 = &cvp->cvc_attr.aal.v.aal5;
2164 if ((cvp->cvc_attr.aal.type != ATM_AAL5) ||
2165 (ap5->SSCS_type != cv5->SSCS_type))
2166 continue;
2168 if (cvp->cvc_flags & CVCF_CALLER) {
2169 if (ap5->forward_max_SDU_size >
2170 cv5->forward_max_SDU_size)
2171 continue;
2172 } else {
2173 if (ap5->forward_max_SDU_size >
2174 cv5->backward_max_SDU_size)
2175 continue;
2177 } else {
2178 struct t_atm_aal4 *ap4, *cv4;
2180 ap4 = &ap->aal.v.aal4;
2181 cv4 = &cvp->cvc_attr.aal.v.aal4;
2183 if ((cvp->cvc_attr.aal.type != ATM_AAL3_4) ||
2184 (ap4->SSCS_type != cv4->SSCS_type))
2185 continue;
2187 if (cvp->cvc_flags & CVCF_CALLER) {
2188 if (ap4->forward_max_SDU_size >
2189 cv4->forward_max_SDU_size)
2190 continue;
2191 } else {
2192 if (ap4->forward_max_SDU_size >
2193 cv4->backward_max_SDU_size)
2194 continue;
2199 * Traffic Descriptor
2201 if ((ap->traffic.tag != T_ATM_PRESENT) ||
2202 (cvp->cvc_attr.traffic.tag != T_ATM_PRESENT) ||
2203 (ap->traffic.v.best_effort != T_YES) ||
2204 (cvp->cvc_attr.traffic.v.best_effort != T_YES))
2205 continue;
2208 * Broadband Bearer
2210 if (ap->bearer.v.connection_configuration !=
2211 cvp->cvc_attr.bearer.v.connection_configuration)
2212 continue;
2215 * QOS
2217 if (cvp->cvc_flags & CVCF_CALLER) {
2218 if ((ap->qos.v.forward.qos_class !=
2219 cvp->cvc_attr.qos.v.forward.qos_class) ||
2220 (ap->qos.v.backward.qos_class !=
2221 cvp->cvc_attr.qos.v.backward.qos_class))
2222 continue;
2223 } else {
2224 if ((ap->qos.v.forward.qos_class !=
2225 cvp->cvc_attr.qos.v.backward.qos_class) ||
2226 (ap->qos.v.backward.qos_class !=
2227 cvp->cvc_attr.qos.v.forward.qos_class))
2228 continue;
2232 * The new LLC header must also be unique for this VCC
2234 for (cop = cvp->cvc_conn; cop; cop = cop->co_next) {
2235 int i = MIN(ap->llc.v.llc_len,
2236 cop->co_llc.v.llc_len);
2238 if (KM_CMP(ap->llc.v.llc_info,
2239 cop->co_llc.v.llc_info, i) == 0)
2240 break;
2244 * If no header overlaps, then we're done
2246 if (cop == NULL)
2247 break;
2250 return (cvp);
2255 * Close Connection
2257 * This function will terminate a connection, including notifying the
2258 * user, if necessary, and freeing up control block memory. The caller
2259 * is responsible for managing the connection VCC.
2261 * Called from a critical section.
2263 * Arguments:
2264 * cop pointer to connection block
2265 * cause pointer to cause of close
2267 * Returns:
2268 * none
2271 static void
2272 atm_cm_closeconn(Atm_connection *cop, struct t_atm_cause *cause)
2276 * Decide whether user needs notification
2278 switch (cop->co_state) {
2280 case COS_OUTCONN:
2281 case COS_LISTEN:
2282 case COS_INCONN:
2283 case COS_INACCEPT:
2284 case COS_ACTIVE:
2286 * Yup, let 'em know connection is gone
2288 if (cop->co_toku)
2289 (*cop->co_endpt->ep_cleared)(cop->co_toku, cause);
2290 break;
2292 case COS_CLEAR:
2294 * Nope,they should know already
2296 break;
2298 default:
2299 panic("atm_cm_closeconn: bogus state");
2303 * Unlink connection from its queues
2305 switch (cop->co_state) {
2307 case COS_LISTEN:
2308 atm_free((caddr_t)cop->co_lattr);
2309 UNLINK(cop, Atm_connection, atm_listen_queue, co_next);
2310 break;
2312 default:
2314 * Remove connection from multiplexor queue
2316 if (cop->co_mxh != cop) {
2318 * Connection is down the chain, just unlink it
2320 UNLINK(cop, Atm_connection, cop->co_mxh, co_next);
2322 } else if (cop->co_next != NULL) {
2324 * Connection is at the head of a non-singleton chain,
2325 * so unlink and reset the chain head
2327 Atm_connection *t, *nhd;
2329 t = nhd = cop->co_next;
2330 while (t) {
2331 t->co_mxh = nhd;
2332 t = t->co_next;
2334 if (nhd->co_connvc)
2335 nhd->co_connvc->cvc_conn = nhd;
2340 * Free the connection block
2342 cop->co_state = COS_FREE;
2343 atm_free((caddr_t)cop);
2345 return;
2350 * Close Connection VCC
2352 * This function will terminate a connection VCC, including releasing the
2353 * the call to the signalling manager, terminating the VCC protocol stack,
2354 * and freeing up control block memory.
2356 * Called from a critical section.
2358 * Arguments:
2359 * cvp pointer to connection VCC block
2361 * Returns:
2362 * none
2365 static void
2366 atm_cm_closevc(Atm_connvc *cvp)
2368 int err;
2371 * Break links with the connection block
2373 cvp->cvc_conn = NULL;
2376 * Cancel any running timer
2378 CVC_CANCEL(cvp);
2381 * Free queued packets
2383 while (cvp->cvc_rcvq) {
2384 KBuffer *m;
2386 m = cvp->cvc_rcvq;
2387 cvp->cvc_rcvq = KB_QNEXT(m);
2388 KB_QNEXT(m) = NULL;
2389 KB_FREEALL(m);
2393 * Unlink from any queues
2395 if (cvp->cvc_flags & CVCF_INCOMQ) {
2396 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
2397 atm_incoming_qlen--;
2398 cvp->cvc_flags &= ~CVCF_INCOMQ;
2400 } else if (cvp->cvc_flags & CVCF_CONNQ) {
2401 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
2402 cvp->cvc_flags &= ~CVCF_CONNQ;
2406 * Release the signalling call
2408 switch (cvp->cvc_state) {
2410 case CVCS_SETUP:
2411 case CVCS_INIT:
2412 case CVCS_ACCEPT:
2413 case CVCS_ACTIVE:
2414 case CVCS_RELEASE:
2415 if (cvp->cvc_vcc) {
2416 cvp->cvc_state = CVCS_RELEASE;
2417 switch ((*cvp->cvc_sigmgr->sm_release)
2418 (cvp->cvc_vcc, &err)) {
2420 case CALL_CLEARED:
2422 * Looks good so far...
2424 break;
2426 case CALL_PROCEEDING:
2428 * We'll have to wait for the call to clear
2430 return;
2432 case CALL_FAILED:
2434 * If there's a memory shortage, retry later.
2435 * Otherwise who knows what's going on....
2437 if ((err == ENOMEM) || (err == ENOBUFS)) {
2438 CVC_TIMER(cvp, 1 * ATM_HZ);
2439 return;
2441 log(LOG_ERR,
2442 "atm_cm_closevc: release %d\n", err);
2443 break;
2446 break;
2448 case CVCS_INCOMING:
2449 case CVCS_REJECT:
2450 if (cvp->cvc_vcc) {
2451 cvp->cvc_state = CVCS_REJECT;
2452 switch ((*cvp->cvc_sigmgr->sm_reject)
2453 (cvp->cvc_vcc, &err)) {
2455 case CALL_CLEARED:
2457 * Looks good so far...
2459 break;
2461 case CALL_FAILED:
2463 * If there's a memory shortage, retry later.
2464 * Otherwise who knows what's going on....
2466 if ((err == ENOMEM) || (err == ENOBUFS)) {
2467 CVC_TIMER(cvp, 1 * ATM_HZ);
2468 return;
2470 log(LOG_ERR,
2471 "atm_cm_closevc: reject %d\n", err);
2472 break;
2475 break;
2477 case CVCS_CLEAR:
2478 case CVCS_TERM:
2480 * No need for anything here
2482 break;
2484 default:
2485 panic("atm_cm_closevc: bogus state");
2489 * Now terminate the stack
2491 if (cvp->cvc_tokl) {
2492 cvp->cvc_state = CVCS_TERM;
2495 * Wait until stack is unwound before terminating
2497 if ((cvp->cvc_downcnt > 0) || (cvp->cvc_upcnt > 0)) {
2498 CVC_TIMER(cvp, 0);
2499 return;
2502 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].term,
2503 cvp->cvc_lower, cvp->cvc_tokl, cvp, 0, 0, err);
2505 cvp->cvc_tokl = NULL;
2509 * Let signalling manager finish up
2511 cvp->cvc_state = CVCS_FREE;
2512 if (cvp->cvc_vcc) {
2513 (*cvp->cvc_sigmgr->sm_free)(cvp->cvc_vcc);
2517 * Finally, free our own control blocks
2519 atm_free((caddr_t)cvp);
2521 return;
2526 * Process a Connection VCC timeout
2528 * Called when a previously scheduled cvc control block timer expires.
2529 * Processing will be based on the current cvc state.
2531 * Called from a critical section.
2533 * Arguments:
2534 * tip pointer to cvc timer control block
2536 * Returns:
2537 * none
2540 static void
2541 atm_cm_timeout(struct atm_time *tip)
2543 Atm_connection *cop, *cop2;
2544 Atm_connvc *cvp;
2547 * Back-off to cvc control block
2549 cvp = (Atm_connvc *)
2550 ((caddr_t)tip - (int)(&((Atm_connvc *)0)->cvc_time));
2553 * Process timeout based on protocol state
2555 switch (cvp->cvc_state) {
2557 case CVCS_SETUP:
2558 case CVCS_ACCEPT:
2559 case CVCS_ACTIVE:
2561 * Handle VCC abort
2563 if ((cvp->cvc_flags & CVCF_ABORTING) == 0)
2564 goto logerr;
2567 * Terminate all connections
2569 cop = cvp->cvc_conn;
2570 while (cop) {
2571 cop2 = cop->co_next;
2572 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
2573 cop = cop2;
2577 * Terminate VCC
2579 atm_cm_closevc(cvp);
2581 break;
2583 case CVCS_REJECT:
2584 case CVCS_RELEASE:
2585 case CVCS_TERM:
2587 * Retry failed operation
2589 atm_cm_closevc(cvp);
2590 break;
2592 default:
2593 logerr:
2594 log(LOG_ERR,
2595 "atm_cm_timeout: invalid state: cvp=%p, state=%d\n",
2596 cvp, cvp->cvc_state);
2602 * CPCS User Control Commands
2604 * This function is called by an endpoint user to pass a control command
2605 * across a CPCS data API. Mostly we just send these down the stack.
2607 * Arguments:
2608 * cmd stack command code
2609 * cop pointer to connection block
2610 * arg argument
2612 * Returns:
2613 * 0 command output successful
2614 * errno output failed - reason indicated
2618 atm_cm_cpcs_ctl(int cmd, Atm_connection *cop, void *arg)
2620 Atm_connvc *cvp;
2621 int err = 0;
2624 * Validate connection state
2626 if (cop->co_state != COS_ACTIVE) {
2627 err = EFAULT;
2628 goto done;
2631 cvp = cop->co_connvc;
2632 if (cvp->cvc_state != CVCS_ACTIVE) {
2633 err = EFAULT;
2634 goto done;
2637 if (cvp->cvc_attr.api != CMAPI_CPCS) {
2638 err = EFAULT;
2639 goto done;
2642 switch (cmd) {
2644 default:
2645 err = EINVAL;
2648 done:
2649 return (err);
2654 * CPCS Data Output
2656 * This function is called by an endpoint user to output a data packet
2657 * across a CPCS data API. After we've validated the connection state, the
2658 * packet will be encapsulated (if necessary) and sent down the data stack.
2660 * Arguments:
2661 * cop pointer to connection block
2662 * m pointer to packet buffer chain to be output
2664 * Returns:
2665 * 0 packet output successful
2666 * errno output failed - reason indicated
2670 atm_cm_cpcs_data(Atm_connection *cop, KBuffer *m)
2672 Atm_connvc *cvp;
2673 struct attr_llc *llcp;
2674 int err, space;
2675 void *bp;
2679 * Validate connection state
2681 if (cop->co_state != COS_ACTIVE) {
2682 err = EFAULT;
2683 goto done;
2686 cvp = cop->co_connvc;
2687 if (cvp->cvc_state != CVCS_ACTIVE) {
2688 err = EFAULT;
2689 goto done;
2692 if (cvp->cvc_attr.api != CMAPI_CPCS) {
2693 err = EFAULT;
2694 goto done;
2698 * Add any packet encapsulation
2700 switch (cop->co_mpx) {
2702 case ATM_ENC_NULL:
2704 * None needed...
2706 break;
2708 case ATM_ENC_LLC:
2710 * Need to add an LLC header
2712 llcp = &cop->co_llc;
2715 * See if there's room to add LLC header to front of packet.
2717 KB_HEADROOM(m, space);
2718 if (space < llcp->v.llc_len) {
2719 KBuffer *n;
2722 * We have to allocate another buffer and tack it
2723 * onto the front of the packet
2725 KB_ALLOCPKT(n, llcp->v.llc_len, KB_F_NOWAIT,
2726 KB_T_HEADER);
2727 if (n == 0) {
2728 err = ENOMEM;
2729 goto done;
2731 KB_TAILALIGN(n, llcp->v.llc_len);
2732 KB_LINKHEAD(n, m);
2733 m = n;
2734 } else {
2736 * Header fits, just adjust buffer controls
2738 KB_HEADADJ(m, llcp->v.llc_len);
2742 * Add the LLC header
2744 KB_DATASTART(m, bp, void *);
2745 KM_COPY(llcp->v.llc_info, bp, llcp->v.llc_len);
2746 KB_PLENADJ(m, llcp->v.llc_len);
2747 break;
2749 default:
2750 panic("atm_cm_cpcs_data: mpx");
2754 * Finally, we can send the packet on its way
2756 STACK_CALL(CPCS_UNITDATA_INV, cvp->cvc_lower, cvp->cvc_tokl,
2757 cvp, (int)m, 0, err);
2759 done:
2760 return (err);
2765 * Process CPCS Stack Commands
2767 * This is the top of the CPCS API data stack. All upward stack commands
2768 * for the CPCS data API will be received and processed here.
2770 * Arguments:
2771 * cmd stack command code
2772 * tok session token (pointer to connection VCC control block)
2773 * arg1 argument 1
2774 * arg2 argument 2
2776 * Returns:
2777 * none
2780 static void
2781 atm_cm_cpcs_upper(int cmd, void *tok, int arg1, int arg2)
2783 Atm_connection *cop;
2784 Atm_connvc *cvp = tok;
2785 KBuffer *m;
2786 void *bp;
2788 switch (cmd) {
2790 case CPCS_UNITDATA_SIG:
2792 * Input data packet
2794 m = (KBuffer *)arg1;
2796 if (cvp->cvc_state != CVCS_ACTIVE) {
2797 if (cvp->cvc_state == CVCS_ACCEPT) {
2798 KBuffer *n;
2801 * Queue up any packets received before sigmgr
2802 * notifies us of incoming call completion
2804 if (cvp->cvc_rcvqlen >= CVC_RCVQ_MAX) {
2805 KB_FREEALL(m);
2806 atm_cm_stat.cms_rcvconnvc++;
2807 return;
2809 KB_QNEXT(m) = NULL;
2810 if (cvp->cvc_rcvq == NULL) {
2811 cvp->cvc_rcvq = m;
2812 } else {
2813 for (n = cvp->cvc_rcvq;
2814 KB_QNEXT(n) != NULL;
2815 n = KB_QNEXT(n))
2817 KB_QNEXT(n) = m;
2819 cvp->cvc_rcvqlen++;
2820 return;
2821 } else {
2822 KB_FREEALL(m);
2823 atm_cm_stat.cms_rcvconnvc++;
2824 return;
2829 * Locate packet's connection
2831 cop = cvp->cvc_conn;
2832 switch (cop->co_mpx) {
2834 case ATM_ENC_NULL:
2836 * We're already there...
2838 break;
2840 case ATM_ENC_LLC:
2842 * Find connection with matching LLC header
2844 if (KB_LEN(m) < T_ATM_LLC_MAX_LEN) {
2845 KB_PULLUP(m, T_ATM_LLC_MAX_LEN, m);
2846 if (m == 0) {
2847 atm_cm_stat.cms_llcdrop++;
2848 return;
2851 KB_DATASTART(m, bp, void *);
2853 crit_enter();
2855 while (cop) {
2856 if (KM_CMP(bp, cop->co_llc.v.llc_info,
2857 cop->co_llc.v.llc_len) == 0)
2858 break;
2859 cop = cop->co_next;
2862 crit_exit();
2864 if (cop == NULL) {
2866 * No connected user for this LLC
2868 KB_FREEALL(m);
2869 atm_cm_stat.cms_llcid++;
2870 return;
2874 * Strip off the LLC header
2876 KB_HEADADJ(m, -cop->co_llc.v.llc_len);
2877 KB_PLENADJ(m, -cop->co_llc.v.llc_len);
2878 break;
2880 default:
2881 panic("atm_cm_cpcs_upper: mpx");
2885 * We've found our connection, so hand the packet off
2887 if (cop->co_state != COS_ACTIVE) {
2888 KB_FREEALL(m);
2889 atm_cm_stat.cms_rcvconn++;
2890 return;
2892 (*cop->co_endpt->ep_cpcs_data)(cop->co_toku, m);
2893 break;
2895 case CPCS_UABORT_SIG:
2896 case CPCS_PABORT_SIG:
2898 * We don't support these (yet), so just fall thru...
2901 default:
2902 log(LOG_ERR, "atm_cm_cpcs_upper: unknown cmd 0x%x\n", cmd);
2908 * SAAL User Control Commands
2910 * This function is called by an endpoint user to pass a control command
2911 * across a SAAL data API. Mostly we just send these down the stack.
2913 * Arguments:
2914 * cmd stack command code
2915 * cop pointer to connection block
2916 * arg argument
2918 * Returns:
2919 * 0 command output successful
2920 * errno output failed - reason indicated
2924 atm_cm_saal_ctl(int cmd, Atm_connection *cop, void *arg)
2926 Atm_connvc *cvp;
2927 int err = 0;
2930 * Validate connection state
2932 if (cop->co_state != COS_ACTIVE) {
2933 err = EFAULT;
2934 goto done;
2937 cvp = cop->co_connvc;
2938 if (cvp->cvc_state != CVCS_ACTIVE) {
2939 err = EFAULT;
2940 goto done;
2943 if (cvp->cvc_attr.api != CMAPI_SAAL) {
2944 err = EFAULT;
2945 goto done;
2948 switch (cmd) {
2950 case SSCF_UNI_ESTABLISH_REQ:
2951 case SSCF_UNI_RELEASE_REQ:
2953 * Pass command down the stack
2955 STACK_CALL(cmd, cvp->cvc_lower, cvp->cvc_tokl, cvp,
2956 (int)arg, 0, err);
2957 break;
2959 default:
2960 err = EINVAL;
2963 done:
2964 return (err);
2969 * SAAL Data Output
2971 * This function is called by an endpoint user to output a data packet
2972 * across a SAAL data API. After we've validated the connection state,
2973 * the packet will be sent down the data stack.
2975 * Arguments:
2976 * cop pointer to connection block
2977 * m pointer to packet buffer chain to be output
2979 * Returns:
2980 * 0 packet output successful
2981 * errno output failed - reason indicated
2985 atm_cm_saal_data(Atm_connection *cop, KBuffer *m)
2987 Atm_connvc *cvp;
2988 int err;
2992 * Validate connection state
2994 if (cop->co_state != COS_ACTIVE) {
2995 err = EFAULT;
2996 goto done;
2999 cvp = cop->co_connvc;
3000 if (cvp->cvc_state != CVCS_ACTIVE) {
3001 err = EFAULT;
3002 goto done;
3005 if (cvp->cvc_attr.api != CMAPI_SAAL) {
3006 err = EFAULT;
3007 goto done;
3011 * Finally, we can send the packet on its way
3013 STACK_CALL(SSCF_UNI_DATA_REQ, cvp->cvc_lower, cvp->cvc_tokl,
3014 cvp, (int)m, 0, err);
3016 done:
3017 return (err);
3022 * Process SAAL Stack Commands
3024 * This is the top of the SAAL API data stack. All upward stack commands
3025 * for the SAAL data API will be received and processed here.
3027 * Arguments:
3028 * cmd stack command code
3029 * tok session token (pointer to connection VCC control block)
3030 * arg1 argument 1
3031 * arg2 argument 2
3033 * Returns:
3034 * none
3037 static void
3038 atm_cm_saal_upper(int cmd, void *tok, int arg1, int arg2)
3040 Atm_connection *cop;
3041 Atm_connvc *cvp = tok;
3044 switch (cmd) {
3046 case SSCF_UNI_ESTABLISH_IND:
3047 case SSCF_UNI_ESTABLISH_CNF:
3048 case SSCF_UNI_RELEASE_IND:
3049 case SSCF_UNI_RELEASE_CNF:
3051 * Control commands
3053 cop = cvp->cvc_conn;
3054 if (cvp->cvc_state != CVCS_ACTIVE)
3055 break;
3056 if (cop->co_state != COS_ACTIVE)
3057 break;
3059 (*cop->co_endpt->ep_saal_ctl)(cmd, cop->co_toku, (void *)arg1);
3060 break;
3062 case SSCF_UNI_DATA_IND:
3064 * User data
3066 cop = cvp->cvc_conn;
3067 if (cvp->cvc_state != CVCS_ACTIVE) {
3068 atm_cm_stat.cms_rcvconnvc++;
3069 KB_FREEALL((KBuffer *)arg1);
3070 break;
3072 if (cop->co_state != COS_ACTIVE) {
3073 atm_cm_stat.cms_rcvconn++;
3074 KB_FREEALL((KBuffer *)arg1);
3075 break;
3078 (*cop->co_endpt->ep_saal_data)(cop->co_toku, (KBuffer *)arg1);
3079 break;
3081 case SSCF_UNI_UNITDATA_IND:
3083 * Not supported
3085 KB_FREEALL((KBuffer *)arg1);
3087 /* FALLTHRU */
3089 default:
3090 log(LOG_ERR, "atm_cm_saal_upper: unknown cmd 0x%x\n", cmd);
3096 * SSCOP User Control Commands
3098 * This function is called by an endpoint user to pass a control command
3099 * across a SSCOP data API. Mostly we just send these down the stack.
3101 * Arguments:
3102 * cmd stack command code
3103 * cop pointer to connection block
3104 * arg1 argument
3105 * arg2 argument
3107 * Returns:
3108 * 0 command output successful
3109 * errno output failed - reason indicated
3113 atm_cm_sscop_ctl(int cmd, Atm_connection *cop, void *arg1, void *arg2)
3115 Atm_connvc *cvp;
3116 int err = 0;
3119 * Validate connection state
3121 if (cop->co_state != COS_ACTIVE) {
3122 err = EFAULT;
3123 goto done;
3126 cvp = cop->co_connvc;
3127 if (cvp->cvc_state != CVCS_ACTIVE) {
3128 err = EFAULT;
3129 goto done;
3132 if (cvp->cvc_attr.api != CMAPI_SSCOP) {
3133 err = EFAULT;
3134 goto done;
3137 switch (cmd) {
3139 case SSCOP_ESTABLISH_REQ:
3140 case SSCOP_ESTABLISH_RSP:
3141 case SSCOP_RELEASE_REQ:
3142 case SSCOP_RESYNC_REQ:
3143 case SSCOP_RESYNC_RSP:
3144 case SSCOP_RECOVER_RSP:
3145 case SSCOP_RETRIEVE_REQ:
3147 * Pass command down the stack
3149 STACK_CALL(cmd, cvp->cvc_lower, cvp->cvc_tokl, cvp,
3150 (int)arg1, (int)arg2, err);
3151 break;
3153 default:
3154 err = EINVAL;
3157 done:
3158 return (err);
3163 * SSCOP Data Output
3165 * This function is called by an endpoint user to output a data packet
3166 * across a SSCOP data API. After we've validated the connection state,
3167 * the packet will be encapsulated and sent down the data stack.
3169 * Arguments:
3170 * cop pointer to connection block
3171 * m pointer to packet buffer chain to be output
3173 * Returns:
3174 * 0 packet output successful
3175 * errno output failed - reason indicated
3179 atm_cm_sscop_data(Atm_connection *cop, KBuffer *m)
3181 Atm_connvc *cvp;
3182 int err;
3186 * Validate connection state
3188 if (cop->co_state != COS_ACTIVE) {
3189 err = EFAULT;
3190 goto done;
3193 cvp = cop->co_connvc;
3194 if (cvp->cvc_state != CVCS_ACTIVE) {
3195 err = EFAULT;
3196 goto done;
3199 if (cvp->cvc_attr.api != CMAPI_SSCOP) {
3200 err = EFAULT;
3201 goto done;
3205 * Finally, we can send the packet on its way
3207 STACK_CALL(SSCOP_DATA_REQ, cvp->cvc_lower, cvp->cvc_tokl,
3208 cvp, (int)m, 0, err);
3210 done:
3211 return (err);
3216 * Process SSCOP Stack Commands
3218 * This is the top of the SSCOP API data stack. All upward stack commands
3219 * for the SSCOP data API will be received and processed here.
3221 * Arguments:
3222 * cmd stack command code
3223 * tok session token (pointer to connection VCC control block)
3224 * arg1 argument 1
3225 * arg2 argument 2
3227 * Returns:
3228 * none
3231 static void
3232 atm_cm_sscop_upper(int cmd, void *tok, int arg1, int arg2)
3234 Atm_connection *cop;
3235 Atm_connvc *cvp = tok;
3237 switch (cmd) {
3239 case SSCOP_ESTABLISH_IND:
3240 case SSCOP_ESTABLISH_CNF:
3241 case SSCOP_RELEASE_IND:
3242 case SSCOP_RESYNC_IND:
3244 * Control commands
3246 cop = cvp->cvc_conn;
3247 if ((cvp->cvc_state != CVCS_ACTIVE) ||
3248 (cop->co_state != COS_ACTIVE)) {
3249 KB_FREEALL((KBuffer *)arg1);
3250 break;
3253 (*cop->co_endpt->ep_sscop_ctl)
3254 (cmd, cop->co_toku, (void *)arg1, (void *)arg2);
3255 break;
3257 case SSCOP_RELEASE_CNF:
3258 case SSCOP_RESYNC_CNF:
3259 case SSCOP_RECOVER_IND:
3260 case SSCOP_RETRIEVE_IND:
3261 case SSCOP_RETRIEVECMP_IND:
3263 * Control commands
3265 cop = cvp->cvc_conn;
3266 if ((cvp->cvc_state != CVCS_ACTIVE) ||
3267 (cop->co_state != COS_ACTIVE))
3268 break;
3270 (*cop->co_endpt->ep_sscop_ctl)
3271 (cmd, cop->co_toku, (void *)arg1, (void *)arg2);
3272 break;
3274 case SSCOP_DATA_IND:
3276 * User data
3278 cop = cvp->cvc_conn;
3279 if (cvp->cvc_state != CVCS_ACTIVE) {
3280 atm_cm_stat.cms_rcvconnvc++;
3281 KB_FREEALL((KBuffer *)arg1);
3282 break;
3284 if (cop->co_state != COS_ACTIVE) {
3285 atm_cm_stat.cms_rcvconn++;
3286 KB_FREEALL((KBuffer *)arg1);
3287 break;
3290 (*cop->co_endpt->ep_sscop_data)
3291 (cop->co_toku, (KBuffer *)arg1, arg2);
3292 break;
3294 case SSCOP_UNITDATA_IND:
3296 * Not supported
3298 KB_FREEALL((KBuffer *)arg1);
3300 /* FALLTHRU */
3302 default:
3303 log(LOG_ERR, "atm_cm_sscop_upper: unknown cmd 0x%x\n", cmd);
3309 * Register an ATM Endpoint Service
3311 * Every ATM endpoint service must register itself here before it can
3312 * issue or receive any connection requests.
3314 * Arguments:
3315 * epp pointer to endpoint definition structure
3317 * Returns:
3318 * 0 registration successful
3319 * errno registration failed - reason indicated
3323 atm_endpoint_register(Atm_endpoint *epp)
3325 crit_enter();
3327 * See if we need to be initialized
3329 if (!atm_init)
3330 atm_initialize();
3333 * Validate endpoint
3335 if (epp->ep_id > ENDPT_MAX) {
3336 crit_exit();
3337 return (EINVAL);
3339 if (atm_endpoints[epp->ep_id] != NULL) {
3340 crit_exit();
3341 return (EEXIST);
3345 * Add endpoint to list
3347 atm_endpoints[epp->ep_id] = epp;
3349 crit_exit();
3350 return (0);
3355 * De-register an ATM Endpoint Service
3357 * Each ATM endpoint service provider must de-register its registered
3358 * endpoint(s) before terminating. Specifically, loaded kernel modules
3359 * must de-register their services before unloading themselves.
3361 * Arguments:
3362 * epp pointer to endpoint definition structure
3364 * Returns:
3365 * 0 de-registration successful
3366 * errno de-registration failed - reason indicated
3370 atm_endpoint_deregister(Atm_endpoint *epp)
3372 crit_enter();
3375 * Validate endpoint
3377 if (epp->ep_id > ENDPT_MAX) {
3378 crit_exit();
3379 return (EINVAL);
3381 if (atm_endpoints[epp->ep_id] != epp) {
3382 crit_exit();
3383 return (ENOENT);
3387 * Remove endpoint from list
3389 atm_endpoints[epp->ep_id] = NULL;
3391 crit_exit();
3392 return (0);