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 $
33 * ATM Connection Manager
37 #include "kern_include.h"
38 #include <sys/kernel.h>
43 struct atm_cm_stat atm_cm_stat = {0};
44 struct callout atm_cm_procinq_ch;
46 SYSINIT(atm_cm, SI_SUB_DRIVERS, SI_ORDER_ANY, callout_init, &atm_cm_procinq_ch);
51 static void atm_cm_cpcs_upper (int, void *, int, int);
52 static void atm_cm_saal_upper (int, void *, int, int);
53 static void atm_cm_sscop_upper (int, void *, int, int);
54 static Atm_connvc * atm_cm_share_llc (Atm_attributes *);
55 static void atm_cm_closeconn (Atm_connection *,
56 struct t_atm_cause *);
57 static void atm_cm_closevc (Atm_connvc *);
58 static void atm_cm_timeout (struct atm_time *);
59 static KTimeout_ret atm_cm_procinq (void *);
60 static void atm_cm_incall (Atm_connvc *);
61 static int atm_cm_accept (Atm_connvc *, Atm_connection *);
66 static Queue_t atm_connection_queue = {NULL};
67 static Queue_t atm_incoming_queue = {NULL};
68 static int atm_incoming_qlen = 0;
69 static Atm_connection *atm_listen_queue = NULL;
70 static struct attr_cause atm_cause_tmpl =
71 {T_ATM_PRESENT, {T_ATM_ITU_CODING, T_ATM_LOC_USER, 0, {0, 0, 0, 0}}};
74 * Stack commands, indexed by API
80 {CPCS_INIT, CPCS_TERM}, /* CMAPI_CPCS */
81 {SSCF_UNI_INIT, SSCF_UNI_TERM}, /* CMAPI_SAAL */
82 {SSCOP_INIT, SSCOP_TERM}, /* CMAPI_SSCOP */
86 static struct sp_info atm_connection_pool = {
87 "atm connection pool", /* si_name */
88 sizeof(Atm_connection), /* si_blksiz */
92 static struct sp_info atm_connvc_pool = {
93 "atm connection vcc pool", /* si_name */
94 sizeof(Atm_connvc), /* si_blksiz */
101 * Initiate Outgoing ATM Call
103 * Called by an endpoint service to create a new Connection Manager API
104 * instance and to initiate an outbound ATM connection. The endpoint
105 * provided token will be used in all further CM -> endpoint function
106 * calls, and the returned connection block pointer must be used in all
107 * subsequent endpoint -> CM function calls.
109 * If the return indicates that the connection setup has been immediately
110 * successful (typically only for PVCs and shared SVCs), then the connection
111 * is ready for data transmission.
113 * If the return indicates that the connection setup is still in progress,
114 * then the endpoint must wait for notification from the Connection Manager
115 * indicating the final status of the call setup. If the call setup completes
116 * successfully, then a "call connected" notification will be sent to the
117 * endpoint by the Connection Manager. If the call setup fails, then the
118 * endpoint will receive a "call cleared" notification.
120 * All connection instances must be freed with an atm_cm_release() call.
123 * epp pointer to endpoint definition structure
124 * token endpoint's connection instance token
125 * ap pointer to requested connection attributes
126 * copp pointer to location to return allocated connection block
129 * 0 connection has been successfully established
130 * EINPROGRESS connection establishment is in progress
131 * errno connection failed - reason indicated
135 atm_cm_connect(Atm_endpoint *epp, void *token, Atm_attributes *ap,
136 Atm_connection **copp)
142 struct stack_list sl;
143 void (*upf)(int, void *, int, int);
150 * Get a connection block
152 cop = (Atm_connection *)atm_allocate(&atm_connection_pool);
157 * Initialize connection info
160 cop->co_toku = token;
163 * Initialize stack list index
168 * Validate and extract useful attribute information
172 * Must specify a network interface (validated below)
174 if (ap->nif == NULL) {
185 upf = atm_cm_cpcs_upper;
189 sl.sl_sap[sli++] = SAP_SSCF_UNI;
190 sl.sl_sap[sli++] = SAP_SSCOP;
191 upf = atm_cm_saal_upper;
195 sl.sl_sap[sli++] = SAP_SSCOP;
196 upf = atm_cm_sscop_upper;
207 if (ap->aal.tag != T_ATM_PRESENT) {
212 switch (ap->aal.type) {
215 sl.sl_sap[sli++] = SAP_CPCS_AAL5;
216 sl.sl_sap[sli++] = SAP_SAR_AAL5;
217 sl.sl_sap[sli++] = SAP_ATM;
221 sl.sl_sap[sli++] = SAP_CPCS_AAL3_4;
222 sl.sl_sap[sli++] = SAP_SAR_AAL3_4;
223 sl.sl_sap[sli++] = SAP_ATM;
232 * Broadband Bearer Attributes
234 if (ap->bearer.tag != T_ATM_PRESENT) {
239 switch (ap->bearer.v.connection_configuration) {
242 cop->co_flags |= COF_P2P;
245 case T_ATM_1_TO_MANY:
247 cop->co_flags |= COF_P2MP;
257 * Logical Link Control Attributes
259 if (ap->llc.tag == T_ATM_PRESENT) {
260 if ((ap->blli.tag_l2 != T_ATM_PRESENT) ||
261 (ap->blli.v.layer_2_protocol.ID_type != T_ATM_SIMPLE_ID) ||
262 (ap->blli.v.layer_2_protocol.ID.simple_ID !=
263 T_ATM_BLLI2_I8802) ||
264 (ap->llc.v.llc_len < T_ATM_LLC_MIN_LEN) ||
265 (ap->llc.v.llc_len > T_ATM_LLC_MAX_LEN)) {
269 cop->co_mpx = ATM_ENC_LLC;
270 cop->co_llc = ap->llc;
272 cop->co_mpx = ATM_ENC_NULL;
275 * Called Party Attributes
277 if (ap->called.tag != T_ATM_PRESENT) {
282 if ((ap->called.addr.address_format == T_ATM_ABSENT) ||
283 (ap->called.addr.address_length == 0)) {
289 * Calling Party Attributes
291 if (ap->calling.tag != T_ATM_ABSENT) {
297 * Quality of Service Attributes
299 if (ap->qos.tag != T_ATM_PRESENT) {
305 * Terminate stack list
312 * Let multiplexors decide whether we need a new VCC
314 switch (cop->co_mpx) {
318 * All of these connections require a new VCC
324 * See if we can share an existing LLC connection
326 cvp = atm_cm_share_llc(ap);
331 * We've got a connection to share
333 cop->co_connvc = cvp;
334 if (cvp->cvc_state == CVCS_ACTIVE) {
335 cop->co_state = COS_ACTIVE;
338 cop->co_state = COS_OUTCONN;
341 LINK2TAIL(cop, Atm_connection, cvp->cvc_conn->co_mxh, co_next);
342 cop->co_mxh = cvp->cvc_conn->co_mxh;
349 panic("atm_cm_connect: unknown mpx");
353 * If we get here, it means we need to create
354 * a new VCC for this connection
358 * Validate that network interface is registered and that
359 * a signalling manager is attached
361 for (pip = atm_interface_head; pip != NULL; pip = pip->pif_next) {
363 for (nip = pip->pif_nif; nip; nip = nip->nif_pnext) {
375 if ((smp = pip->pif_sigmgr) == NULL) {
381 * Get a connection VCC block
383 cvp = (Atm_connvc *)atm_allocate(&atm_connvc_pool);
390 * Save VCC attributes
393 cvp->cvc_flags |= CVCF_CALLER;
396 * Link the control blocks
398 cop->co_connvc = cvp;
400 cvp->cvc_sigmgr = smp;
403 * Create a service stack
405 err = atm_create_stack(cvp, &sl, upf);
407 cvp->cvc_state = CVCS_CLEAR;
413 * Let the signalling manager handle the VCC creation
415 cvp->cvc_state = CVCS_SETUP;
416 switch ((*smp->sm_setup)(cvp, &err)) {
420 * Connection is fully setup - initialize the stack
422 cvp->cvc_state = CVCS_INIT;
423 STACK_CALL(atm_stackcmds[ap->api].init, cvp->cvc_lower,
424 cvp->cvc_tokl, cvp, ap->api_init, 0, err2);
426 panic("atm_cm_connect: init");
428 if (cvp->cvc_flags & CVCF_ABORTING) {
430 * Someone on the stack bailed out...schedule the
431 * VCC and stack termination
437 * Everything looks fine from here
439 cvp->cvc_state = CVCS_ACTIVE;
440 cop->co_state = COS_ACTIVE;
446 * Terminate stack and clean up before we leave
448 cvp->cvc_state = CVCS_CLEAR;
452 case CALL_PROCEEDING:
454 * We'll just wait for final call status
456 cop->co_state = COS_OUTCONN;
461 panic("atm_cm_connect: setup");
468 if (err && err != EINPROGRESS) {
470 * Undo any partial setup stuff
473 atm_free((caddr_t)cop);
476 * Finish connection setup
479 cvp->cvc_flags |= CVCF_CONNQ;
480 ENQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
481 LINK2TAIL(cop, Atm_connection, cop->co_mxh, co_next);
490 * Listen for Incoming ATM Calls
492 * Called by an endpoint service in order to indicate its willingness to
493 * accept certain incoming calls. The types of calls which the endpoint
494 * is prepared to accept are specified in the Atm_attributes parameter.
496 * For each call which meets the criteria specified by the endpoint, the
497 * endpoint service will receive an incoming call notification via the
498 * endpoint's ep_incoming() function.
500 * To cancel the listening connection, the endpoint user should invoke
504 * epp pointer to endpoint definition structure
505 * token endpoint's listen instance token
506 * ap pointer to listening connection attributes
507 * copp pointer to location to return allocated connection block
510 * 0 listening connection installed
511 * errno listen failed - reason indicated
515 atm_cm_listen(Atm_endpoint *epp, void *token, Atm_attributes *ap,
516 Atm_connection **copp)
524 * Get a connection block
526 cop = (Atm_connection *)atm_allocate(&atm_connection_pool);
531 * Initialize connection info
534 cop->co_toku = token;
538 * Validate and extract useful attribute information
559 switch (ap->aal.tag) {
563 switch (ap->aal.type) {
585 * Broadband High Layer Information Attributes
587 switch (ap->bhli.tag) {
600 * Broadband Low Layer Information Attributes
602 switch (ap->blli.tag_l2) {
614 switch (ap->blli.tag_l3) {
627 * Logical Link Control Attributes
629 switch (ap->llc.tag) {
632 if ((ap->blli.tag_l2 != T_ATM_PRESENT) ||
633 (ap->blli.v.layer_2_protocol.ID_type != T_ATM_SIMPLE_ID) ||
634 (ap->blli.v.layer_2_protocol.ID.simple_ID !=
635 T_ATM_BLLI2_I8802) ||
636 (ap->llc.v.llc_len < T_ATM_LLC_MIN_LEN) ||
637 (ap->llc.v.llc_len > T_ATM_LLC_MAX_LEN)) {
641 cop->co_mpx = ATM_ENC_LLC;
642 cop->co_llc = ap->llc;
647 cop->co_mpx = ATM_ENC_NULL;
656 * Called Party Attributes
658 switch (ap->called.tag) {
661 switch (ap->called.addr.address_format) {
664 ap->called.tag = T_ATM_ABSENT;
683 * Get an attribute block and save listening attributes
685 cop->co_lattr = (Atm_attributes *)atm_allocate(&atm_attributes_pool);
686 if (cop->co_lattr == NULL) {
690 *cop->co_lattr = *ap;
693 * Now try to register the listening connection
696 if (atm_cm_match(cop->co_lattr, NULL) != NULL) {
698 * Can't have matching listeners
703 cop->co_state = COS_LISTEN;
704 LINK2TAIL(cop, Atm_connection, atm_listen_queue, co_next);
712 * Undo any partial setup stuff
716 atm_free((caddr_t)cop->co_lattr);
717 atm_free((caddr_t)cop);
721 * Finish connection setup
730 * Add to LLC Connection
732 * Called by an endpoint service to create a new Connection Manager API
733 * instance to be associated with an LLC-multiplexed connection instance
734 * which has been previously created. The endpoint provided token will
735 * be used in all further CM -> endpoint function calls, and the returned
736 * connection block pointer must be used in all subsequent endpoint -> CM
739 * If the return indicates that the connection setup has been immediately
740 * successful, then the connection is ready for data transmission.
742 * If the return indicates that the connection setup is still in progress,
743 * then the endpoint must wait for notification from the Connection Manager
744 * indicating the final status of the call setup. If the call setup completes
745 * successfully, then a "call connected" notification will be sent to the
746 * endpoint by the Connection Manager. If the call setup fails, then the
747 * endpoint will receive a "call cleared" notification.
749 * All connection instances must be freed with an atm_cm_release() call.
752 * epp pointer to endpoint definition structure
753 * token endpoint's connection instance token
754 * llc pointer to llc attributes for new connection
755 * ecop pointer to existing connection block
756 * copp pointer to location to return allocated connection block
759 * 0 connection has been successfully established
760 * EINPROGRESS connection establishment is in progress
761 * errno addllc failed - reason indicated
765 atm_cm_addllc(Atm_endpoint *epp, void *token, struct attr_llc *llc,
766 Atm_connection *ecop, Atm_connection **copp)
768 Atm_connection *cop, *cop2;
775 * Check out requested LLC attributes
777 if ((llc->tag != T_ATM_PRESENT) ||
778 ((llc->v.flags & T_ATM_LLC_SHARING) == 0) ||
779 (llc->v.llc_len < T_ATM_LLC_MIN_LEN) ||
780 (llc->v.llc_len > T_ATM_LLC_MAX_LEN))
784 * Get a connection block
786 cop = (Atm_connection *)atm_allocate(&atm_connection_pool);
791 * Initialize connection info
794 cop->co_toku = token;
800 * Ensure that supplied connection is really valid
803 for (cvp = Q_HEAD(atm_connection_queue, Atm_connvc); cvp;
804 cvp = Q_NEXT(cvp, Atm_connvc, cvc_q)) {
805 for (cop2 = cvp->cvc_conn; cop2; cop2 = cop2->co_next) {
817 switch (ecop->co_state) {
834 * Connection must be LLC multiplexed and shared
836 if ((ecop->co_mpx != ATM_ENC_LLC) ||
837 ((ecop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0)) {
843 * This new LLC header must be unique for this VCC
847 int i = MIN(llc->v.llc_len, cop2->co_llc.v.llc_len);
849 if (KM_CMP(llc->v.llc_info, cop2->co_llc.v.llc_info, i) == 0) {
854 cop2 = cop2->co_next;
858 * Everything seems to check out
860 cop->co_flags = ecop->co_flags;
861 cop->co_state = ecop->co_state;
862 cop->co_mpx = ecop->co_mpx;
863 cop->co_connvc = ecop->co_connvc;
865 LINK2TAIL(cop, Atm_connection, ecop->co_mxh, co_next);
866 cop->co_mxh = ecop->co_mxh;
871 if (err && err != EINPROGRESS) {
873 * Undo any partial setup stuff
876 atm_free((caddr_t)cop);
879 * Pass new connection back to caller
891 * cop pointer to connection block
892 * id identifier for party to be added
893 * addr address of party to be added
896 * 0 addparty successful
897 * errno addparty failed - reason indicated
901 atm_cm_addparty(Atm_connection *cop, int id, struct t_atm_sap *addr)
911 * cop pointer to connection block
912 * id identifier for party to be added
913 * cause pointer to cause of drop
916 * 0 dropparty successful
917 * errno dropparty failed - reason indicated
921 atm_cm_dropparty(Atm_connection *cop, int id, struct t_atm_cause *cause)
928 * Release Connection Resources
930 * Called by the endpoint service in order to terminate an ATM connection
931 * and to release all system resources for the connection. This function
932 * must be called for every allocated connection instance and must only
933 * be called by the connection's owner.
936 * cop pointer to connection block
937 * cause pointer to cause of release
940 * 0 release successful
941 * errno release failed - reason indicated
945 atm_cm_release(Atm_connection *cop, struct t_atm_cause *cause)
952 * First, a quick state validation check
954 switch (cop->co_state) {
972 panic("atm_cm_release: bogus conn state");
976 * Check out the VCC state too
978 if ((cvp = cop->co_connvc) != NULL) {
980 switch (cvp->cvc_state) {
997 panic("atm_cm_release: bogus connvc state");
1001 * If we're the only connection, terminate the VCC
1003 if ((cop->co_mxh == cop) && (cop->co_next == NULL)) {
1004 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
1005 cvp->cvc_attr.cause.v = *cause;
1006 atm_cm_closevc(cvp);
1011 * Now get rid of the connection
1013 atm_cm_closeconn(cop, cause);
1020 * Abort an ATM Connection VCC
1022 * This function allows any non-owner kernel entity to request an
1023 * immediate termination of an ATM VCC. This will normally be called
1024 * when encountering a catastrophic error condition that cannot be
1025 * resolved via the available stack protocols. The connection manager
1026 * will schedule the connection's termination, including notifying the
1027 * connection owner of the termination.
1029 * This function should only be called by a stack entity instance. After
1030 * calling the function, the caller should set a protocol state which just
1031 * waits for a <sap>_TERM stack command to be delivered.
1034 * cvp pointer to connection VCC block
1035 * cause pointer to cause of abort
1038 * 0 abort successful
1039 * errno abort failed - reason indicated
1043 atm_cm_abort(Atm_connvc *cvp, struct t_atm_cause *cause)
1045 ATM_DEBUG2("atm_cm_abort: cvp=%p cause=%d\n",
1046 cvp, cause->cause_value);
1049 * Note that we're aborting
1051 cvp->cvc_flags |= CVCF_ABORTING;
1053 switch (cvp->cvc_state) {
1057 * In-line code will handle this
1059 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
1060 cvp->cvc_attr.cause.v = *cause;
1067 * Schedule connection termination, since we want
1068 * to avoid any sequencing interactions
1070 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
1071 cvp->cvc_attr.cause.v = *cause;
1080 * Ignore abort, as we're already terminating
1086 "atm_cm_abort: invalid state: cvp=%p, state=%d\n",
1087 cvp, cvp->cvc_state);
1094 * Incoming ATM Call Received
1096 * Called by a signalling manager to indicate that a new call request has
1097 * been received. This function will allocate and initialize the connection
1098 * manager control blocks and queue this call request. The call request
1099 * processing function, atm_cm_procinq(), will be scheduled to perform the
1103 * vcp pointer to incoming call's VCC control block
1104 * ap pointer to incoming call's attributes
1107 * 0 call queuing successful
1108 * errno call queuing failed - reason indicated
1112 atm_cm_incoming(struct vccb *vcp, Atm_attributes *ap)
1119 * Do some minimal attribute validation
1123 * Must specify a network interface
1125 if (ap->nif == NULL)
1131 if ((ap->aal.tag != T_ATM_PRESENT) ||
1132 ((ap->aal.type != ATM_AAL5) &&
1133 (ap->aal.type != ATM_AAL3_4)))
1137 * Traffic Descriptor Attributes
1139 if ((ap->traffic.tag != T_ATM_PRESENT) &&
1140 (ap->traffic.tag != T_ATM_ABSENT))
1144 * Broadband Bearer Attributes
1146 if ((ap->bearer.tag != T_ATM_PRESENT) ||
1147 ((ap->bearer.v.connection_configuration != T_ATM_1_TO_1) &&
1148 (ap->bearer.v.connection_configuration != T_ATM_1_TO_MANY)))
1152 * Broadband High Layer Attributes
1154 if ((ap->bhli.tag != T_ATM_PRESENT) &&
1155 (ap->bhli.tag != T_ATM_ABSENT))
1159 * Broadband Low Layer Attributes
1161 if ((ap->blli.tag_l2 != T_ATM_PRESENT) &&
1162 (ap->blli.tag_l2 != T_ATM_ABSENT))
1164 if ((ap->blli.tag_l3 != T_ATM_PRESENT) &&
1165 (ap->blli.tag_l3 != T_ATM_ABSENT))
1169 * Logical Link Control Attributes
1171 if (ap->llc.tag == T_ATM_PRESENT)
1173 ap->llc.tag = T_ATM_ANY;
1176 * Called Party Attributes
1178 if ((ap->called.tag != T_ATM_PRESENT) ||
1179 (ap->called.addr.address_format == T_ATM_ABSENT))
1181 if (ap->called.tag == T_ATM_ABSENT) {
1182 ap->called.addr.address_format = T_ATM_ABSENT;
1183 ap->called.addr.address_length = 0;
1184 ap->called.subaddr.address_format = T_ATM_ABSENT;
1185 ap->called.subaddr.address_length = 0;
1189 * Calling Party Attributes
1191 if ((ap->calling.tag != T_ATM_PRESENT) &&
1192 (ap->calling.tag != T_ATM_ABSENT))
1194 if (ap->calling.tag == T_ATM_ABSENT) {
1195 ap->calling.addr.address_format = T_ATM_ABSENT;
1196 ap->calling.addr.address_length = 0;
1197 ap->calling.subaddr.address_format = T_ATM_ABSENT;
1198 ap->calling.subaddr.address_length = 0;
1202 * Quality of Service Attributes
1204 if (ap->qos.tag != T_ATM_PRESENT)
1208 * Transit Network Attributes
1210 if ((ap->transit.tag != T_ATM_PRESENT) &&
1211 (ap->transit.tag != T_ATM_ABSENT))
1217 if ((ap->cause.tag != T_ATM_PRESENT) &&
1218 (ap->cause.tag != T_ATM_ABSENT))
1222 * Get a connection VCC block
1224 cvp = (Atm_connvc *)atm_allocate(&atm_connvc_pool);
1231 * Initialize the control block
1234 cvp->cvc_sigmgr = vcp->vc_pif->pif_sigmgr;
1235 cvp->cvc_attr = *ap;
1236 cvp->cvc_state = CVCS_INCOMING;
1239 * Control queue length
1242 if (atm_incoming_qlen >= ATM_CALLQ_MAX) {
1249 * Queue request and schedule call processing function
1251 cvp->cvc_flags |= CVCF_INCOMQ;
1252 ENQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
1253 if (atm_incoming_qlen++ == 0) {
1254 atm_cm_procinq(NULL);
1258 * Link for signalling manager
1260 vcp->vc_connvc = cvp;
1268 * Free any resources
1271 atm_free((caddr_t)cvp);
1277 * VCC Connected Notification
1279 * This function is called by a signalling manager as notification that a
1280 * VCC call setup has been successful.
1283 * cvp pointer to connection VCC block
1290 atm_cm_connected(Atm_connvc *cvp)
1292 Atm_connection *cop, *cop2;
1299 * Validate connection vcc
1301 switch (cvp->cvc_state) {
1305 * Initialize the stack
1307 cvp->cvc_state = CVCS_INIT;
1308 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].init,
1309 cvp->cvc_lower, cvp->cvc_tokl,
1310 cvp, cvp->cvc_attr.api_init, 0, err);
1312 panic("atm_cm_connected: init");
1314 if (cvp->cvc_flags & CVCF_ABORTING) {
1316 * Someone on the stack bailed out...notify all of the
1317 * connections and schedule the VCC termination
1319 cop = cvp->cvc_conn;
1321 cop2 = cop->co_next;
1322 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
1325 atm_cm_closevc(cvp);
1333 * Stack already initialized
1338 panic("atm_cm_connected: connvc state");
1342 * VCC is ready for action
1344 cvp->cvc_state = CVCS_ACTIVE;
1347 * Notify all connections that the call has completed
1349 cop = cvp->cvc_conn;
1351 cop2 = cop->co_next;
1353 switch (cop->co_state) {
1357 cop->co_state = COS_ACTIVE;
1358 (*cop->co_endpt->ep_connected)(cop->co_toku);
1363 * May get here if an ep_connected() call (from
1364 * above) results in an atm_cm_addllc() call for
1365 * the just connected connection.
1370 panic("atm_cm_connected: connection state");
1379 * Input any queued packets
1381 while ((m = cvp->cvc_rcvq) != NULL) {
1382 cvp->cvc_rcvq = KB_QNEXT(m);
1387 * Currently only supported for CPCS API
1389 atm_cm_cpcs_upper(CPCS_UNITDATA_SIG, cvp, (int)m, 0);
1397 * VCC Cleared Notification
1399 * This function is called by a signalling manager as notification that a
1400 * VCC call has been cleared. The cause information describing the reason
1401 * for the call clearing will be contained in the connection VCC attributes.
1404 * cvp pointer to connection VCC block
1411 atm_cm_cleared(Atm_connvc *cvp)
1413 Atm_connection *cop, *cop2;
1416 if ((cvp->cvc_state == CVCS_FREE) ||
1417 (cvp->cvc_state >= CVCS_CLEAR))
1418 panic("atm_cm_cleared");
1421 cvp->cvc_state = CVCS_CLEAR;
1426 * Terminate all connections
1428 cop = cvp->cvc_conn;
1430 cop2 = cop->co_next;
1431 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
1436 * Clean up connection VCC
1438 atm_cm_closevc(cvp);
1447 * Process Incoming Call Queue
1449 * This function is scheduled by atm_cm_incoming() in order to process
1450 * all the entries on the incoming call queue.
1453 * arg argument passed on timeout() call
1460 atm_cm_procinq(void *arg)
1466 * Only process incoming calls up to our quota
1468 while (cnt++ < ATM_CALLQ_MAX) {
1472 * Get next awaiting call
1474 cvp = Q_HEAD(atm_incoming_queue, Atm_connvc);
1479 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
1480 atm_incoming_qlen--;
1481 cvp->cvc_flags &= ~CVCF_INCOMQ;
1492 * If we've expended our quota, reschedule ourselves
1494 if (cnt >= ATM_CALLQ_MAX) {
1495 callout_reset(&atm_cm_procinq_ch, 1, atm_cm_procinq, NULL);
1501 * Process Incoming Call
1503 * This function will search through the listening queue and try to find
1504 * matching endpoint(s) for the incoming call. If we find any, we will
1505 * notify the endpoint service(s) of the incoming call and will then
1506 * notify the signalling manager to progress the call to an active status.
1508 * If there are no listeners for the call, the signalling manager will be
1509 * notified of a call rejection.
1511 * Called from a critical section.
1514 * cvp pointer to connection VCC for incoming call
1521 atm_cm_incall(Atm_connvc *cvp)
1523 Atm_connection *cop, *lcop, *hcop;
1524 Atm_attributes attr;
1530 attr = cvp->cvc_attr;
1533 * Look for matching listeners
1535 while ((lcop = atm_cm_match(&attr, lcop)) != NULL) {
1539 * Need a new connection block
1541 cop = (Atm_connection *)
1542 atm_allocate(&atm_connection_pool);
1544 cvp->cvc_attr.cause = atm_cause_tmpl;
1545 cvp->cvc_attr.cause.v.cause_value =
1546 T_ATM_CAUSE_TEMPORARY_FAILURE;
1552 * Initialize connection from listener and incoming call
1555 cop->co_state = COS_INCONN;
1556 cop->co_mpx = lcop->co_mpx;
1557 cop->co_endpt = lcop->co_endpt;
1558 cop->co_llc = lcop->co_llc;
1560 switch (attr.bearer.v.connection_configuration) {
1563 cop->co_flags |= COF_P2P;
1566 case T_ATM_1_TO_MANY:
1568 cop->co_flags |= COF_P2MP;
1569 cvp->cvc_attr.cause = atm_cause_tmpl;
1570 cvp->cvc_attr.cause.v.cause_value =
1571 T_ATM_CAUSE_BEARER_CAPABILITY_NOT_IMPLEMENTED;
1576 * Notify endpoint of incoming call
1578 err = (*cop->co_endpt->ep_incoming)
1579 (lcop->co_toku, cop, &cvp->cvc_attr, &cop->co_toku);
1584 * Endpoint has accepted the call
1586 * Setup call attributes
1589 cvp->cvc_attr.api = lcop->co_lattr->api;
1590 cvp->cvc_attr.api_init =
1591 lcop->co_lattr->api_init;
1592 cvp->cvc_attr.llc = lcop->co_lattr->llc;
1594 cvp->cvc_attr.headin = MAX(cvp->cvc_attr.headin,
1595 lcop->co_lattr->headin);
1598 * Setup connection info and queueing
1600 cop->co_state = COS_INACCEPT;
1601 cop->co_connvc = cvp;
1602 LINK2TAIL(cop, Atm_connection, hcop, co_next);
1606 * Need a new connection block next time around
1612 * Endpoint refuses call
1619 * We're done looking for listeners
1623 * Someone actually wants the call, so notify
1624 * the signalling manager to continue
1626 cvp->cvc_flags |= CVCF_CONNQ;
1627 ENQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
1628 if (atm_cm_accept(cvp, hcop))
1633 * Nobody around to take the call
1635 cvp->cvc_attr.cause = atm_cause_tmpl;
1636 cvp->cvc_attr.cause.v.cause_value =
1637 T_ATM_CAUSE_INCOMPATIBLE_DESTINATION;
1642 * Clean up loose ends
1645 atm_free((caddr_t)cop);
1648 * Call has been accepted
1654 * Call failed - notify any endpoints of the call failure
1658 * Clean up loose ends
1661 atm_free((caddr_t)cop);
1663 if (cvp->cvc_attr.cause.tag != T_ATM_PRESENT) {
1664 cvp->cvc_attr.cause = atm_cause_tmpl;
1665 cvp->cvc_attr.cause.v.cause_value =
1666 T_ATM_CAUSE_UNSPECIFIED_NORMAL;
1670 Atm_connection *cop2 = cop->co_next;
1671 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
1676 * Tell the signalling manager to reject the call
1678 atm_cm_closevc(cvp);
1685 * Accept an Incoming ATM Call
1687 * Some endpoint service(s) wants to accept an incoming call, so the
1688 * signalling manager will be notified to attempt to progress the call
1689 * to an active status.
1691 * If the signalling manager indicates that connection activation has
1692 * been immediately successful, then all of the endpoints will be notified
1693 * that the connection is ready for data transmission.
1695 * If the return indicates that connection activation is still in progress,
1696 * then the endpoints must wait for notification from the Connection Manager
1697 * indicating the final status of the call setup. If the call setup completes
1698 * successfully, then a "call connected" notification will be sent to the
1699 * endpoints by the Connection Manager. If the call setup fails, then the
1700 * endpoints will receive a "call cleared" notification.
1702 * Called from a critical section.
1705 * cvp pointer to connection VCC for incoming call
1706 * cop pointer to head of accepted connections
1709 * 0 connection has been successfully activated
1710 * errno accept failed - reason indicated
1714 atm_cm_accept(Atm_connvc *cvp, Atm_connection *cop)
1716 struct stack_list sl;
1717 void (*upf)(int, void *, int, int);
1722 * Link vcc to connections
1724 cvp->cvc_conn = cop;
1727 * Initialize stack list index
1732 * Check out Data API
1734 switch (cvp->cvc_attr.api) {
1737 upf = atm_cm_cpcs_upper;
1741 sl.sl_sap[sli++] = SAP_SSCF_UNI;
1742 sl.sl_sap[sli++] = SAP_SSCOP;
1743 upf = atm_cm_saal_upper;
1747 sl.sl_sap[sli++] = SAP_SSCOP;
1748 upf = atm_cm_sscop_upper;
1758 switch (cvp->cvc_attr.aal.type) {
1761 sl.sl_sap[sli++] = SAP_CPCS_AAL5;
1762 sl.sl_sap[sli++] = SAP_SAR_AAL5;
1763 sl.sl_sap[sli++] = SAP_ATM;
1767 sl.sl_sap[sli++] = SAP_CPCS_AAL3_4;
1768 sl.sl_sap[sli++] = SAP_SAR_AAL3_4;
1769 sl.sl_sap[sli++] = SAP_ATM;
1774 * Terminate stack list
1779 * Create a service stack
1781 err = atm_create_stack(cvp, &sl, upf);
1787 * Let the signalling manager finish the VCC activation
1789 switch ((*cvp->cvc_sigmgr->sm_accept)(cvp->cvc_vcc, &err)) {
1791 case CALL_PROCEEDING:
1793 * Note that we're not finished yet
1798 case CALL_CONNECTED:
1800 * Initialize the stack now, even if the call isn't totally
1801 * active yet. We want to avoid the delay between getting
1802 * the "call connected" event and actually notifying the
1803 * adapter to accept cells on the new VCC - if the delay is
1804 * too long, then we end up dropping the first pdus sent by
1807 cvp->cvc_state = CVCS_INIT;
1808 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].init,
1809 cvp->cvc_lower, cvp->cvc_tokl, cvp,
1810 cvp->cvc_attr.api_init, 0, err2);
1812 panic("atm_cm_accept: init");
1814 if (cvp->cvc_flags & CVCF_ABORTING) {
1816 * Someone on the stack bailed out...schedule the
1817 * VCC and stack termination
1822 * Everything looks fine from here
1825 cvp->cvc_state = CVCS_ACCEPT;
1827 cvp->cvc_state = CVCS_ACTIVE;
1833 * Terminate stack and clean up before we leave
1835 cvp->cvc_state = CVCS_CLEAR;
1839 panic("atm_cm_accept: accept");
1845 * Call has been connected, notify endpoints
1848 Atm_connection *cop2 = cop->co_next;
1850 cop->co_state = COS_ACTIVE;
1851 (*cop->co_endpt->ep_connected)(cop->co_toku);
1855 } else if (err == EINPROGRESS) {
1857 * Call is still in progress, endpoint must wait
1863 * Let caller know we failed
1865 cvp->cvc_attr.cause = atm_cause_tmpl;
1866 cvp->cvc_attr.cause.v.cause_value =
1867 T_ATM_CAUSE_UNSPECIFIED_RESOURCE_UNAVAILABLE;
1875 * Match Attributes on Listening Queue
1877 * This function will attempt to match the supplied connection attributes
1878 * with one of the registered attributes in the listening queue. The pcop
1879 * argument may be supplied in order to allow multiple listeners to share
1880 * an incoming call (if supported by the listeners).
1882 * Called from a critical section.
1885 * ap pointer to attributes to be matched
1886 * pcop pointer to the previously matched connection
1889 * addr connection with which a match was found
1894 atm_cm_match(Atm_attributes *ap, Atm_connection *pcop)
1896 Atm_connection *cop;
1897 Atm_attributes *lap;
1901 * If we've already matched a listener...
1905 * Make sure already matched listener supports sharing
1907 if ((pcop->co_mpx != ATM_ENC_LLC) ||
1908 ((pcop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0))
1912 * Position ourselves after the matched entry
1914 for (cop = atm_listen_queue; cop; cop = cop->co_next) {
1916 cop = pcop->co_next;
1922 * Start search at top of listening queue
1924 cop = atm_listen_queue;
1928 * Search through listening queue
1930 for (; cop; cop = cop->co_next) {
1932 lap = cop->co_lattr;
1935 * If we're trying to share, check that this entry allows it
1938 if ((cop->co_mpx != ATM_ENC_LLC) ||
1939 ((cop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0))
1944 * ALL "matchable" attributes must match
1950 if (lap->bhli.tag == T_ATM_ABSENT) {
1951 if (ap->bhli.tag == T_ATM_PRESENT)
1953 } else if (lap->bhli.tag == T_ATM_PRESENT) {
1954 if (ap->bhli.tag == T_ATM_ABSENT)
1956 if (ap->bhli.tag == T_ATM_PRESENT)
1957 if (KM_CMP(&lap->bhli.v, &ap->bhli.v,
1958 sizeof(struct t_atm_bhli)))
1965 if (lap->blli.tag_l2 == T_ATM_ABSENT) {
1966 if (ap->blli.tag_l2 == T_ATM_PRESENT)
1968 } else if (lap->blli.tag_l2 == T_ATM_PRESENT) {
1969 if (ap->blli.tag_l2 == T_ATM_ABSENT)
1971 if (ap->blli.tag_l2 == T_ATM_PRESENT) {
1972 if (KM_CMP(&lap->blli.v.layer_2_protocol.ID,
1973 &ap->blli.v.layer_2_protocol.ID,
1975 ap->blli.v.layer_2_protocol.ID)))
1983 if (lap->blli.tag_l3 == T_ATM_ABSENT) {
1984 if (ap->blli.tag_l3 == T_ATM_PRESENT)
1986 } else if (lap->blli.tag_l3 == T_ATM_PRESENT) {
1987 if (ap->blli.tag_l3 == T_ATM_ABSENT)
1989 if (ap->blli.tag_l3 == T_ATM_PRESENT) {
1990 if (KM_CMP(&lap->blli.v.layer_3_protocol.ID,
1991 &ap->blli.v.layer_3_protocol.ID,
1993 ap->blli.v.layer_3_protocol.ID)))
2001 if (lap->llc.tag == T_ATM_ABSENT) {
2002 if (ap->llc.tag == T_ATM_PRESENT)
2004 } else if (lap->llc.tag == T_ATM_PRESENT) {
2005 if (ap->llc.tag == T_ATM_ABSENT)
2007 if (ap->llc.tag == T_ATM_PRESENT) {
2008 int i = MIN(lap->llc.v.llc_len,
2011 if (KM_CMP(lap->llc.v.llc_info,
2012 ap->llc.v.llc_info, i))
2020 if (lap->aal.tag == T_ATM_ABSENT) {
2021 if (ap->aal.tag == T_ATM_PRESENT)
2023 } else if (lap->aal.tag == T_ATM_PRESENT) {
2024 if (ap->aal.tag == T_ATM_ABSENT)
2026 if (ap->aal.tag == T_ATM_PRESENT) {
2027 if (lap->aal.type != ap->aal.type)
2029 if (lap->aal.type == ATM_AAL5) {
2030 if (lap->aal.v.aal5.SSCS_type !=
2031 ap->aal.v.aal5.SSCS_type)
2034 if (lap->aal.v.aal4.SSCS_type !=
2035 ap->aal.v.aal4.SSCS_type)
2044 if (lap->called.tag == T_ATM_ABSENT) {
2045 if (ap->called.tag == T_ATM_PRESENT)
2047 } else if (lap->called.tag == T_ATM_PRESENT) {
2048 if (ap->called.tag == T_ATM_ABSENT)
2050 if (ap->called.tag == T_ATM_PRESENT) {
2051 if ((!ATM_ADDR_EQUAL(&lap->called.addr,
2052 &ap->called.addr)) ||
2053 (!ATM_ADDR_EQUAL(&lap->called.subaddr,
2054 &ap->called.subaddr)))
2060 * Found a full match - return it
2070 * Find Shareable LLC VCC
2072 * Given a endpoint-supplied connection attribute using LLC multiplexing,
2073 * this function will attempt to locate an existing connection which meets
2074 * the requirements of the supplied attributes.
2076 * Called from a critical section.
2079 * ap pointer to requested attributes
2082 * addr shareable LLC connection VCC
2083 * 0 no shareable VCC available
2087 atm_cm_share_llc(Atm_attributes *ap)
2089 Atm_connection *cop;
2093 * Is requestor willing to share?
2095 if ((ap->llc.v.flags & T_ATM_LLC_SHARING) == 0)
2099 * Try to find a shareable connection
2101 for (cvp = Q_HEAD(atm_connection_queue, Atm_connvc); cvp;
2102 cvp = Q_NEXT(cvp, Atm_connvc, cvc_q)) {
2105 * Dont use terminating connections
2107 switch (cvp->cvc_state) {
2119 * Is connection LLC and shareable?
2121 if ((cvp->cvc_attr.llc.tag != T_ATM_PRESENT) ||
2122 ((cvp->cvc_attr.llc.v.flags & T_ATM_LLC_SHARING) == 0))
2126 * Match requested attributes with existing connection
2128 if (ap->nif != cvp->cvc_attr.nif)
2131 if ((ap->api != cvp->cvc_attr.api) ||
2132 (ap->api_init != cvp->cvc_attr.api_init))
2138 if (cvp->cvc_flags & CVCF_CALLER) {
2139 if ((!ATM_ADDR_EQUAL(&ap->called.addr,
2140 &cvp->cvc_attr.called.addr)) ||
2141 (!ATM_ADDR_EQUAL(&ap->called.subaddr,
2142 &cvp->cvc_attr.called.subaddr)))
2145 if (cvp->cvc_attr.calling.tag != T_ATM_PRESENT)
2147 if ((!ATM_ADDR_EQUAL(&ap->called.addr,
2148 &cvp->cvc_attr.calling.addr)) ||
2149 (!ATM_ADDR_EQUAL(&ap->called.subaddr,
2150 &cvp->cvc_attr.calling.subaddr)))
2157 if (ap->aal.type == ATM_AAL5) {
2158 struct t_atm_aal5 *ap5, *cv5;
2160 ap5 = &ap->aal.v.aal5;
2161 cv5 = &cvp->cvc_attr.aal.v.aal5;
2163 if ((cvp->cvc_attr.aal.type != ATM_AAL5) ||
2164 (ap5->SSCS_type != cv5->SSCS_type))
2167 if (cvp->cvc_flags & CVCF_CALLER) {
2168 if (ap5->forward_max_SDU_size >
2169 cv5->forward_max_SDU_size)
2172 if (ap5->forward_max_SDU_size >
2173 cv5->backward_max_SDU_size)
2177 struct t_atm_aal4 *ap4, *cv4;
2179 ap4 = &ap->aal.v.aal4;
2180 cv4 = &cvp->cvc_attr.aal.v.aal4;
2182 if ((cvp->cvc_attr.aal.type != ATM_AAL3_4) ||
2183 (ap4->SSCS_type != cv4->SSCS_type))
2186 if (cvp->cvc_flags & CVCF_CALLER) {
2187 if (ap4->forward_max_SDU_size >
2188 cv4->forward_max_SDU_size)
2191 if (ap4->forward_max_SDU_size >
2192 cv4->backward_max_SDU_size)
2198 * Traffic Descriptor
2200 if ((ap->traffic.tag != T_ATM_PRESENT) ||
2201 (cvp->cvc_attr.traffic.tag != T_ATM_PRESENT) ||
2202 (ap->traffic.v.best_effort != T_YES) ||
2203 (cvp->cvc_attr.traffic.v.best_effort != T_YES))
2209 if (ap->bearer.v.connection_configuration !=
2210 cvp->cvc_attr.bearer.v.connection_configuration)
2216 if (cvp->cvc_flags & CVCF_CALLER) {
2217 if ((ap->qos.v.forward.qos_class !=
2218 cvp->cvc_attr.qos.v.forward.qos_class) ||
2219 (ap->qos.v.backward.qos_class !=
2220 cvp->cvc_attr.qos.v.backward.qos_class))
2223 if ((ap->qos.v.forward.qos_class !=
2224 cvp->cvc_attr.qos.v.backward.qos_class) ||
2225 (ap->qos.v.backward.qos_class !=
2226 cvp->cvc_attr.qos.v.forward.qos_class))
2231 * The new LLC header must also be unique for this VCC
2233 for (cop = cvp->cvc_conn; cop; cop = cop->co_next) {
2234 int i = MIN(ap->llc.v.llc_len,
2235 cop->co_llc.v.llc_len);
2237 if (KM_CMP(ap->llc.v.llc_info,
2238 cop->co_llc.v.llc_info, i) == 0)
2243 * If no header overlaps, then we're done
2256 * This function will terminate a connection, including notifying the
2257 * user, if necessary, and freeing up control block memory. The caller
2258 * is responsible for managing the connection VCC.
2260 * Called from a critical section.
2263 * cop pointer to connection block
2264 * cause pointer to cause of close
2271 atm_cm_closeconn(Atm_connection *cop, struct t_atm_cause *cause)
2275 * Decide whether user needs notification
2277 switch (cop->co_state) {
2285 * Yup, let 'em know connection is gone
2288 (*cop->co_endpt->ep_cleared)(cop->co_toku, cause);
2293 * Nope,they should know already
2298 panic("atm_cm_closeconn: bogus state");
2302 * Unlink connection from its queues
2304 switch (cop->co_state) {
2307 atm_free((caddr_t)cop->co_lattr);
2308 UNLINK(cop, Atm_connection, atm_listen_queue, co_next);
2313 * Remove connection from multiplexor queue
2315 if (cop->co_mxh != cop) {
2317 * Connection is down the chain, just unlink it
2319 UNLINK(cop, Atm_connection, cop->co_mxh, co_next);
2321 } else if (cop->co_next != NULL) {
2323 * Connection is at the head of a non-singleton chain,
2324 * so unlink and reset the chain head
2326 Atm_connection *t, *nhd;
2328 t = nhd = cop->co_next;
2334 nhd->co_connvc->cvc_conn = nhd;
2339 * Free the connection block
2341 cop->co_state = COS_FREE;
2342 atm_free((caddr_t)cop);
2349 * Close Connection VCC
2351 * This function will terminate a connection VCC, including releasing the
2352 * the call to the signalling manager, terminating the VCC protocol stack,
2353 * and freeing up control block memory.
2355 * Called from a critical section.
2358 * cvp pointer to connection VCC block
2365 atm_cm_closevc(Atm_connvc *cvp)
2370 * Break links with the connection block
2372 cvp->cvc_conn = NULL;
2375 * Cancel any running timer
2380 * Free queued packets
2382 while (cvp->cvc_rcvq) {
2386 cvp->cvc_rcvq = KB_QNEXT(m);
2392 * Unlink from any queues
2394 if (cvp->cvc_flags & CVCF_INCOMQ) {
2395 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
2396 atm_incoming_qlen--;
2397 cvp->cvc_flags &= ~CVCF_INCOMQ;
2399 } else if (cvp->cvc_flags & CVCF_CONNQ) {
2400 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
2401 cvp->cvc_flags &= ~CVCF_CONNQ;
2405 * Release the signalling call
2407 switch (cvp->cvc_state) {
2415 cvp->cvc_state = CVCS_RELEASE;
2416 switch ((*cvp->cvc_sigmgr->sm_release)
2417 (cvp->cvc_vcc, &err)) {
2421 * Looks good so far...
2425 case CALL_PROCEEDING:
2427 * We'll have to wait for the call to clear
2433 * If there's a memory shortage, retry later.
2434 * Otherwise who knows what's going on....
2436 if ((err == ENOMEM) || (err == ENOBUFS)) {
2437 CVC_TIMER(cvp, 1 * ATM_HZ);
2441 "atm_cm_closevc: release %d\n", err);
2450 cvp->cvc_state = CVCS_REJECT;
2451 switch ((*cvp->cvc_sigmgr->sm_reject)
2452 (cvp->cvc_vcc, &err)) {
2456 * Looks good so far...
2462 * If there's a memory shortage, retry later.
2463 * Otherwise who knows what's going on....
2465 if ((err == ENOMEM) || (err == ENOBUFS)) {
2466 CVC_TIMER(cvp, 1 * ATM_HZ);
2470 "atm_cm_closevc: reject %d\n", err);
2479 * No need for anything here
2484 panic("atm_cm_closevc: bogus state");
2488 * Now terminate the stack
2490 if (cvp->cvc_tokl) {
2491 cvp->cvc_state = CVCS_TERM;
2494 * Wait until stack is unwound before terminating
2496 if ((cvp->cvc_downcnt > 0) || (cvp->cvc_upcnt > 0)) {
2501 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].term,
2502 cvp->cvc_lower, cvp->cvc_tokl, cvp, 0, 0, err);
2504 cvp->cvc_tokl = NULL;
2508 * Let signalling manager finish up
2510 cvp->cvc_state = CVCS_FREE;
2512 (*cvp->cvc_sigmgr->sm_free)(cvp->cvc_vcc);
2516 * Finally, free our own control blocks
2518 atm_free((caddr_t)cvp);
2525 * Process a Connection VCC timeout
2527 * Called when a previously scheduled cvc control block timer expires.
2528 * Processing will be based on the current cvc state.
2530 * Called from a critical section.
2533 * tip pointer to cvc timer control block
2540 atm_cm_timeout(struct atm_time *tip)
2542 Atm_connection *cop, *cop2;
2546 * Back-off to cvc control block
2548 cvp = (Atm_connvc *)((caddr_t)tip - __offsetof(Atm_connvc, cvc_time));
2551 * Process timeout based on protocol state
2553 switch (cvp->cvc_state) {
2561 if ((cvp->cvc_flags & CVCF_ABORTING) == 0)
2565 * Terminate all connections
2567 cop = cvp->cvc_conn;
2569 cop2 = cop->co_next;
2570 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
2577 atm_cm_closevc(cvp);
2585 * Retry failed operation
2587 atm_cm_closevc(cvp);
2593 "atm_cm_timeout: invalid state: cvp=%p, state=%d\n",
2594 cvp, cvp->cvc_state);
2600 * CPCS User Control Commands
2602 * This function is called by an endpoint user to pass a control command
2603 * across a CPCS data API. Mostly we just send these down the stack.
2606 * cmd stack command code
2607 * cop pointer to connection block
2611 * 0 command output successful
2612 * errno output failed - reason indicated
2616 atm_cm_cpcs_ctl(int cmd, Atm_connection *cop, void *arg)
2622 * Validate connection state
2624 if (cop->co_state != COS_ACTIVE) {
2629 cvp = cop->co_connvc;
2630 if (cvp->cvc_state != CVCS_ACTIVE) {
2635 if (cvp->cvc_attr.api != CMAPI_CPCS) {
2654 * This function is called by an endpoint user to output a data packet
2655 * across a CPCS data API. After we've validated the connection state, the
2656 * packet will be encapsulated (if necessary) and sent down the data stack.
2659 * cop pointer to connection block
2660 * m pointer to packet buffer chain to be output
2663 * 0 packet output successful
2664 * errno output failed - reason indicated
2668 atm_cm_cpcs_data(Atm_connection *cop, KBuffer *m)
2671 struct attr_llc *llcp;
2677 * Validate connection state
2679 if (cop->co_state != COS_ACTIVE) {
2684 cvp = cop->co_connvc;
2685 if (cvp->cvc_state != CVCS_ACTIVE) {
2690 if (cvp->cvc_attr.api != CMAPI_CPCS) {
2696 * Add any packet encapsulation
2698 switch (cop->co_mpx) {
2708 * Need to add an LLC header
2710 llcp = &cop->co_llc;
2713 * See if there's room to add LLC header to front of packet.
2715 KB_HEADROOM(m, space);
2716 if (space < llcp->v.llc_len) {
2718 uint32_t len = llcp->v.llc_len; /* gcc workaround */
2721 * We have to allocate another buffer and tack it
2722 * onto the front of the packet
2724 KB_ALLOCPKT(n, len, KB_F_NOWAIT, KB_T_HEADER);
2729 KB_TAILALIGN(n, len);
2734 * Header fits, just adjust buffer controls
2736 KB_HEADADJ(m, llcp->v.llc_len);
2740 * Add the LLC header
2742 KB_DATASTART(m, bp, void *);
2743 KM_COPY(llcp->v.llc_info, bp, llcp->v.llc_len);
2744 KB_PLENADJ(m, llcp->v.llc_len);
2748 panic("atm_cm_cpcs_data: mpx");
2752 * Finally, we can send the packet on its way
2754 STACK_CALL(CPCS_UNITDATA_INV, cvp->cvc_lower, cvp->cvc_tokl,
2755 cvp, (int)m, 0, err);
2763 * Process CPCS Stack Commands
2765 * This is the top of the CPCS API data stack. All upward stack commands
2766 * for the CPCS data API will be received and processed here.
2769 * cmd stack command code
2770 * tok session token (pointer to connection VCC control block)
2779 atm_cm_cpcs_upper(int cmd, void *tok, int arg1, int arg2)
2781 Atm_connection *cop;
2782 Atm_connvc *cvp = tok;
2788 case CPCS_UNITDATA_SIG:
2792 m = (KBuffer *)arg1;
2794 if (cvp->cvc_state != CVCS_ACTIVE) {
2795 if (cvp->cvc_state == CVCS_ACCEPT) {
2799 * Queue up any packets received before sigmgr
2800 * notifies us of incoming call completion
2802 if (cvp->cvc_rcvqlen >= CVC_RCVQ_MAX) {
2804 atm_cm_stat.cms_rcvconnvc++;
2808 if (cvp->cvc_rcvq == NULL) {
2811 for (n = cvp->cvc_rcvq;
2812 KB_QNEXT(n) != NULL;
2821 atm_cm_stat.cms_rcvconnvc++;
2827 * Locate packet's connection
2829 cop = cvp->cvc_conn;
2830 switch (cop->co_mpx) {
2834 * We're already there...
2840 * Find connection with matching LLC header
2842 if (KB_LEN(m) < T_ATM_LLC_MAX_LEN) {
2843 KB_PULLUP(m, T_ATM_LLC_MAX_LEN, m);
2845 atm_cm_stat.cms_llcdrop++;
2849 KB_DATASTART(m, bp, void *);
2854 if (KM_CMP(bp, cop->co_llc.v.llc_info,
2855 cop->co_llc.v.llc_len) == 0)
2864 * No connected user for this LLC
2867 atm_cm_stat.cms_llcid++;
2872 * Strip off the LLC header
2874 KB_HEADADJ(m, -cop->co_llc.v.llc_len);
2875 KB_PLENADJ(m, -cop->co_llc.v.llc_len);
2879 panic("atm_cm_cpcs_upper: mpx");
2883 * We've found our connection, so hand the packet off
2885 if (cop->co_state != COS_ACTIVE) {
2887 atm_cm_stat.cms_rcvconn++;
2890 (*cop->co_endpt->ep_cpcs_data)(cop->co_toku, m);
2893 case CPCS_UABORT_SIG:
2894 case CPCS_PABORT_SIG:
2896 * We don't support these (yet), so just fall thru...
2900 log(LOG_ERR, "atm_cm_cpcs_upper: unknown cmd 0x%x\n", cmd);
2906 * SAAL User Control Commands
2908 * This function is called by an endpoint user to pass a control command
2909 * across a SAAL data API. Mostly we just send these down the stack.
2912 * cmd stack command code
2913 * cop pointer to connection block
2917 * 0 command output successful
2918 * errno output failed - reason indicated
2922 atm_cm_saal_ctl(int cmd, Atm_connection *cop, void *arg)
2928 * Validate connection state
2930 if (cop->co_state != COS_ACTIVE) {
2935 cvp = cop->co_connvc;
2936 if (cvp->cvc_state != CVCS_ACTIVE) {
2941 if (cvp->cvc_attr.api != CMAPI_SAAL) {
2948 case SSCF_UNI_ESTABLISH_REQ:
2949 case SSCF_UNI_RELEASE_REQ:
2951 * Pass command down the stack
2953 STACK_CALL(cmd, cvp->cvc_lower, cvp->cvc_tokl, cvp,
2969 * This function is called by an endpoint user to output a data packet
2970 * across a SAAL data API. After we've validated the connection state,
2971 * the packet will be sent down the data stack.
2974 * cop pointer to connection block
2975 * m pointer to packet buffer chain to be output
2978 * 0 packet output successful
2979 * errno output failed - reason indicated
2983 atm_cm_saal_data(Atm_connection *cop, KBuffer *m)
2990 * Validate connection state
2992 if (cop->co_state != COS_ACTIVE) {
2997 cvp = cop->co_connvc;
2998 if (cvp->cvc_state != CVCS_ACTIVE) {
3003 if (cvp->cvc_attr.api != CMAPI_SAAL) {
3009 * Finally, we can send the packet on its way
3011 STACK_CALL(SSCF_UNI_DATA_REQ, cvp->cvc_lower, cvp->cvc_tokl,
3012 cvp, (int)m, 0, err);
3020 * Process SAAL Stack Commands
3022 * This is the top of the SAAL API data stack. All upward stack commands
3023 * for the SAAL data API will be received and processed here.
3026 * cmd stack command code
3027 * tok session token (pointer to connection VCC control block)
3036 atm_cm_saal_upper(int cmd, void *tok, int arg1, int arg2)
3038 Atm_connection *cop;
3039 Atm_connvc *cvp = tok;
3044 case SSCF_UNI_ESTABLISH_IND:
3045 case SSCF_UNI_ESTABLISH_CNF:
3046 case SSCF_UNI_RELEASE_IND:
3047 case SSCF_UNI_RELEASE_CNF:
3051 cop = cvp->cvc_conn;
3052 if (cvp->cvc_state != CVCS_ACTIVE)
3054 if (cop->co_state != COS_ACTIVE)
3057 (*cop->co_endpt->ep_saal_ctl)(cmd, cop->co_toku, (void *)arg1);
3060 case SSCF_UNI_DATA_IND:
3064 cop = cvp->cvc_conn;
3065 if (cvp->cvc_state != CVCS_ACTIVE) {
3066 atm_cm_stat.cms_rcvconnvc++;
3067 KB_FREEALL((KBuffer *)arg1);
3070 if (cop->co_state != COS_ACTIVE) {
3071 atm_cm_stat.cms_rcvconn++;
3072 KB_FREEALL((KBuffer *)arg1);
3076 (*cop->co_endpt->ep_saal_data)(cop->co_toku, (KBuffer *)arg1);
3079 case SSCF_UNI_UNITDATA_IND:
3083 KB_FREEALL((KBuffer *)arg1);
3088 log(LOG_ERR, "atm_cm_saal_upper: unknown cmd 0x%x\n", cmd);
3094 * SSCOP User Control Commands
3096 * This function is called by an endpoint user to pass a control command
3097 * across a SSCOP data API. Mostly we just send these down the stack.
3100 * cmd stack command code
3101 * cop pointer to connection block
3106 * 0 command output successful
3107 * errno output failed - reason indicated
3111 atm_cm_sscop_ctl(int cmd, Atm_connection *cop, void *arg1, void *arg2)
3117 * Validate connection state
3119 if (cop->co_state != COS_ACTIVE) {
3124 cvp = cop->co_connvc;
3125 if (cvp->cvc_state != CVCS_ACTIVE) {
3130 if (cvp->cvc_attr.api != CMAPI_SSCOP) {
3137 case SSCOP_ESTABLISH_REQ:
3138 case SSCOP_ESTABLISH_RSP:
3139 case SSCOP_RELEASE_REQ:
3140 case SSCOP_RESYNC_REQ:
3141 case SSCOP_RESYNC_RSP:
3142 case SSCOP_RECOVER_RSP:
3143 case SSCOP_RETRIEVE_REQ:
3145 * Pass command down the stack
3147 STACK_CALL(cmd, cvp->cvc_lower, cvp->cvc_tokl, cvp,
3148 (int)arg1, (int)arg2, err);
3163 * This function is called by an endpoint user to output a data packet
3164 * across a SSCOP data API. After we've validated the connection state,
3165 * the packet will be encapsulated and sent down the data stack.
3168 * cop pointer to connection block
3169 * m pointer to packet buffer chain to be output
3172 * 0 packet output successful
3173 * errno output failed - reason indicated
3177 atm_cm_sscop_data(Atm_connection *cop, KBuffer *m)
3184 * Validate connection state
3186 if (cop->co_state != COS_ACTIVE) {
3191 cvp = cop->co_connvc;
3192 if (cvp->cvc_state != CVCS_ACTIVE) {
3197 if (cvp->cvc_attr.api != CMAPI_SSCOP) {
3203 * Finally, we can send the packet on its way
3205 STACK_CALL(SSCOP_DATA_REQ, cvp->cvc_lower, cvp->cvc_tokl,
3206 cvp, (int)m, 0, err);
3214 * Process SSCOP Stack Commands
3216 * This is the top of the SSCOP API data stack. All upward stack commands
3217 * for the SSCOP data API will be received and processed here.
3220 * cmd stack command code
3221 * tok session token (pointer to connection VCC control block)
3230 atm_cm_sscop_upper(int cmd, void *tok, int arg1, int arg2)
3232 Atm_connection *cop;
3233 Atm_connvc *cvp = tok;
3237 case SSCOP_ESTABLISH_IND:
3238 case SSCOP_ESTABLISH_CNF:
3239 case SSCOP_RELEASE_IND:
3240 case SSCOP_RESYNC_IND:
3244 cop = cvp->cvc_conn;
3245 if ((cvp->cvc_state != CVCS_ACTIVE) ||
3246 (cop->co_state != COS_ACTIVE)) {
3247 KB_FREEALL((KBuffer *)arg1);
3251 (*cop->co_endpt->ep_sscop_ctl)
3252 (cmd, cop->co_toku, (void *)arg1, (void *)arg2);
3255 case SSCOP_RELEASE_CNF:
3256 case SSCOP_RESYNC_CNF:
3257 case SSCOP_RECOVER_IND:
3258 case SSCOP_RETRIEVE_IND:
3259 case SSCOP_RETRIEVECMP_IND:
3263 cop = cvp->cvc_conn;
3264 if ((cvp->cvc_state != CVCS_ACTIVE) ||
3265 (cop->co_state != COS_ACTIVE))
3268 (*cop->co_endpt->ep_sscop_ctl)
3269 (cmd, cop->co_toku, (void *)arg1, (void *)arg2);
3272 case SSCOP_DATA_IND:
3276 cop = cvp->cvc_conn;
3277 if (cvp->cvc_state != CVCS_ACTIVE) {
3278 atm_cm_stat.cms_rcvconnvc++;
3279 KB_FREEALL((KBuffer *)arg1);
3282 if (cop->co_state != COS_ACTIVE) {
3283 atm_cm_stat.cms_rcvconn++;
3284 KB_FREEALL((KBuffer *)arg1);
3288 (*cop->co_endpt->ep_sscop_data)
3289 (cop->co_toku, (KBuffer *)arg1, arg2);
3292 case SSCOP_UNITDATA_IND:
3296 KB_FREEALL((KBuffer *)arg1);
3301 log(LOG_ERR, "atm_cm_sscop_upper: unknown cmd 0x%x\n", cmd);
3307 * Register an ATM Endpoint Service
3309 * Every ATM endpoint service must register itself here before it can
3310 * issue or receive any connection requests.
3313 * epp pointer to endpoint definition structure
3316 * 0 registration successful
3317 * errno registration failed - reason indicated
3321 atm_endpoint_register(Atm_endpoint *epp)
3325 * See if we need to be initialized
3333 if (epp->ep_id > ENDPT_MAX) {
3337 if (atm_endpoints[epp->ep_id] != NULL) {
3343 * Add endpoint to list
3345 atm_endpoints[epp->ep_id] = epp;
3353 * De-register an ATM Endpoint Service
3355 * Each ATM endpoint service provider must de-register its registered
3356 * endpoint(s) before terminating. Specifically, loaded kernel modules
3357 * must de-register their services before unloading themselves.
3360 * epp pointer to endpoint definition structure
3363 * 0 de-registration successful
3364 * errno de-registration failed - reason indicated
3368 atm_endpoint_deregister(Atm_endpoint *epp)
3375 if (epp->ep_id > ENDPT_MAX) {
3379 if (atm_endpoints[epp->ep_id] != epp) {
3385 * Remove endpoint from list
3387 atm_endpoints[epp->ep_id] = NULL;