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 * @(#) $Id: atm_cm.c,v 1.4 1999/01/27 22:16:15 dillon Exp $
34 * ATM Connection Manager
38 #include <netatm/kern_include.h>
41 __RCSID("@(#) $Id: atm_cm.c,v 1.4 1999/01/27 22:16:15 dillon Exp $");
48 struct atm_cm_stat atm_cm_stat = {0};
53 static void atm_cm_cpcs_upper __P((int, void *, int, int));
54 static void atm_cm_saal_upper __P((int, void *, int, int));
55 static void atm_cm_sscop_upper __P((int, void *, int, int));
56 static Atm_connvc * atm_cm_share_llc __P((Atm_attributes *));
57 static void atm_cm_closeconn __P((Atm_connection *,
58 struct t_atm_cause *));
59 static void atm_cm_closevc __P((Atm_connvc *));
60 static void atm_cm_timeout __P((struct atm_time *));
61 static KTimeout_ret atm_cm_procinq __P((void *));
62 static void atm_cm_incall __P((Atm_connvc *));
63 static int atm_cm_accept __P((Atm_connvc *, Atm_connection *));
68 static Queue_t atm_connection_queue = {NULL};
69 static Queue_t atm_incoming_queue = {NULL};
70 static int atm_incoming_qlen = 0;
71 static Atm_connection *atm_listen_queue = NULL;
72 static struct attr_cause atm_cause_tmpl =
73 {T_ATM_PRESENT, {T_ATM_ITU_CODING, T_ATM_LOC_USER, 0, {0, 0, 0, 0}}};
76 * Stack commands, indexed by API
82 {CPCS_INIT, CPCS_TERM}, /* CMAPI_CPCS */
83 {SSCF_UNI_INIT, SSCF_UNI_TERM}, /* CMAPI_SAAL */
84 {SSCOP_INIT, SSCOP_TERM}, /* CMAPI_SSCOP */
88 static struct sp_info atm_connection_pool = {
89 "atm connection pool", /* si_name */
90 sizeof(Atm_connection), /* si_blksiz */
94 static struct sp_info atm_connvc_pool = {
95 "atm connection vcc pool", /* si_name */
96 sizeof(Atm_connvc), /* si_blksiz */
103 * Initiate Outgoing ATM Call
105 * Called by an endpoint service to create a new Connection Manager API
106 * instance and to initiate an outbound ATM connection. The endpoint
107 * provided token will be used in all further CM -> endpoint function
108 * calls, and the returned connection block pointer must be used in all
109 * subsequent endpoint -> CM function calls.
111 * If the return indicates that the connection setup has been immediately
112 * successful (typically only for PVCs and shared SVCs), then the connection
113 * is ready for data transmission.
115 * If the return indicates that the connection setup is still in progress,
116 * then the endpoint must wait for notification from the Connection Manager
117 * indicating the final status of the call setup. If the call setup completes
118 * successfully, then a "call connected" notification will be sent to the
119 * endpoint by the Connection Manager. If the call setup fails, then the
120 * endpoint will receive a "call cleared" notification.
122 * All connection instances must be freed with an atm_cm_release() call.
125 * epp pointer to endpoint definition structure
126 * token endpoint's connection instance token
127 * ap pointer to requested connection attributes
128 * copp pointer to location to return allocated connection block
131 * 0 connection has been successfully established
132 * EINPROGRESS connection establishment is in progress
133 * errno connection failed - reason indicated
137 atm_cm_connect(epp, token, ap, copp)
141 Atm_connection **copp;
147 struct stack_list sl;
148 void (*upf)__P((int, void *, int, int));
149 int s, sli, err, err2;
155 * Get a connection block
157 cop = (Atm_connection *)atm_allocate(&atm_connection_pool);
162 * Initialize connection info
165 cop->co_toku = token;
168 * Initialize stack list index
173 * Validate and extract useful attribute information
177 * Must specify a network interface (validated below)
179 if (ap->nif == NULL) {
190 upf = atm_cm_cpcs_upper;
194 sl.sl_sap[sli++] = SAP_SSCF_UNI;
195 sl.sl_sap[sli++] = SAP_SSCOP;
196 upf = atm_cm_saal_upper;
200 sl.sl_sap[sli++] = SAP_SSCOP;
201 upf = atm_cm_sscop_upper;
212 if (ap->aal.tag != T_ATM_PRESENT) {
217 switch (ap->aal.type) {
220 sl.sl_sap[sli++] = SAP_CPCS_AAL5;
221 sl.sl_sap[sli++] = SAP_SAR_AAL5;
222 sl.sl_sap[sli++] = SAP_ATM;
226 sl.sl_sap[sli++] = SAP_CPCS_AAL3_4;
227 sl.sl_sap[sli++] = SAP_SAR_AAL3_4;
228 sl.sl_sap[sli++] = SAP_ATM;
237 * Broadband Bearer Attributes
239 if (ap->bearer.tag != T_ATM_PRESENT) {
244 switch (ap->bearer.v.connection_configuration) {
247 cop->co_flags |= COF_P2P;
250 case T_ATM_1_TO_MANY:
252 cop->co_flags |= COF_P2MP;
262 * Logical Link Control Attributes
264 if (ap->llc.tag == T_ATM_PRESENT) {
265 if ((ap->blli.tag_l2 != T_ATM_PRESENT) ||
266 (ap->blli.v.layer_2_protocol.ID_type != T_ATM_SIMPLE_ID) ||
267 (ap->blli.v.layer_2_protocol.ID.simple_ID !=
268 T_ATM_BLLI2_I8802) ||
269 (ap->llc.v.llc_len < T_ATM_LLC_MIN_LEN) ||
270 (ap->llc.v.llc_len > T_ATM_LLC_MAX_LEN)) {
274 cop->co_mpx = ATM_ENC_LLC;
275 cop->co_llc = ap->llc;
277 cop->co_mpx = ATM_ENC_NULL;
280 * Called Party Attributes
282 if (ap->called.tag != T_ATM_PRESENT) {
287 if ((ap->called.addr.address_format == T_ATM_ABSENT) ||
288 (ap->called.addr.address_length == 0)) {
294 * Calling Party Attributes
296 if (ap->calling.tag != T_ATM_ABSENT) {
302 * Quality of Service Attributes
304 if (ap->qos.tag != T_ATM_PRESENT) {
310 * Terminate stack list
317 * Let multiplexors decide whether we need a new VCC
319 switch (cop->co_mpx) {
323 * All of these connections require a new VCC
329 * See if we can share an existing LLC connection
331 cvp = atm_cm_share_llc(ap);
336 * We've got a connection to share
338 cop->co_connvc = cvp;
339 if (cvp->cvc_state == CVCS_ACTIVE) {
340 cop->co_state = COS_ACTIVE;
343 cop->co_state = COS_OUTCONN;
346 LINK2TAIL(cop, Atm_connection, cvp->cvc_conn->co_mxh, co_next);
347 cop->co_mxh = cvp->cvc_conn->co_mxh;
354 panic("atm_cm_connect: unknown mpx");
358 * If we get here, it means we need to create
359 * a new VCC for this connection
363 * Validate that network interface is registered and that
364 * a signalling manager is attached
366 for (pip = atm_interface_head; pip != NULL; pip = pip->pif_next) {
368 for (nip = pip->pif_nif; nip; nip = nip->nif_pnext) {
380 if ((smp = pip->pif_sigmgr) == NULL) {
386 * Get a connection VCC block
388 cvp = (Atm_connvc *)atm_allocate(&atm_connvc_pool);
395 * Save VCC attributes
398 cvp->cvc_flags |= CVCF_CALLER;
401 * Link the control blocks
403 cop->co_connvc = cvp;
405 cvp->cvc_sigmgr = smp;
408 * Create a service stack
410 err = atm_create_stack(cvp, &sl, upf);
412 cvp->cvc_state = CVCS_CLEAR;
418 * Let the signalling manager handle the VCC creation
420 cvp->cvc_state = CVCS_SETUP;
421 switch ((*smp->sm_setup)(cvp, &err)) {
425 * Connection is fully setup - initialize the stack
427 cvp->cvc_state = CVCS_INIT;
428 STACK_CALL(atm_stackcmds[ap->api].init, cvp->cvc_lower,
429 cvp->cvc_tokl, cvp, ap->api_init, 0, err2);
431 panic("atm_cm_connect: init");
433 if (cvp->cvc_flags & CVCF_ABORTING) {
435 * Someone on the stack bailed out...schedule the
436 * VCC and stack termination
442 * Everything looks fine from here
444 cvp->cvc_state = CVCS_ACTIVE;
445 cop->co_state = COS_ACTIVE;
451 * Terminate stack and clean up before we leave
453 cvp->cvc_state = CVCS_CLEAR;
457 case CALL_PROCEEDING:
459 * We'll just wait for final call status
461 cop->co_state = COS_OUTCONN;
466 panic("atm_cm_connect: setup");
473 if (err && err != EINPROGRESS) {
475 * Undo any partial setup stuff
478 atm_free((caddr_t)cop);
481 * Finish connection setup
484 cvp->cvc_flags |= CVCF_CONNQ;
485 ENQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
486 LINK2TAIL(cop, Atm_connection, cop->co_mxh, co_next);
495 * Listen for Incoming ATM Calls
497 * Called by an endpoint service in order to indicate its willingness to
498 * accept certain incoming calls. The types of calls which the endpoint
499 * is prepared to accept are specified in the Atm_attributes parameter.
501 * For each call which meets the criteria specified by the endpoint, the
502 * endpoint service will receive an incoming call notification via the
503 * endpoint's ep_incoming() function.
505 * To cancel the listening connection, the endpoint user should invoke
509 * epp pointer to endpoint definition structure
510 * token endpoint's listen instance token
511 * ap pointer to listening connection attributes
512 * copp pointer to location to return allocated connection block
515 * 0 listening connection installed
516 * errno listen failed - reason indicated
520 atm_cm_listen(epp, token, ap, copp)
524 Atm_connection **copp;
532 * Get a connection block
534 cop = (Atm_connection *)atm_allocate(&atm_connection_pool);
539 * Initialize connection info
542 cop->co_toku = token;
546 * Validate and extract useful attribute information
567 switch (ap->aal.tag) {
571 switch (ap->aal.type) {
593 * Broadband High Layer Information Attributes
595 switch (ap->bhli.tag) {
608 * Broadband Low Layer Information Attributes
610 switch (ap->blli.tag_l2) {
622 switch (ap->blli.tag_l3) {
635 * Logical Link Control Attributes
637 switch (ap->llc.tag) {
640 if ((ap->blli.tag_l2 != T_ATM_PRESENT) ||
641 (ap->blli.v.layer_2_protocol.ID_type != T_ATM_SIMPLE_ID) ||
642 (ap->blli.v.layer_2_protocol.ID.simple_ID !=
643 T_ATM_BLLI2_I8802) ||
644 (ap->llc.v.llc_len < T_ATM_LLC_MIN_LEN) ||
645 (ap->llc.v.llc_len > T_ATM_LLC_MAX_LEN)) {
649 cop->co_mpx = ATM_ENC_LLC;
650 cop->co_llc = ap->llc;
655 cop->co_mpx = ATM_ENC_NULL;
664 * Called Party Attributes
666 switch (ap->called.tag) {
669 switch (ap->called.addr.address_format) {
672 ap->called.tag = T_ATM_ABSENT;
691 * Get an attribute block and save listening attributes
693 cop->co_lattr = (Atm_attributes *)atm_allocate(&atm_attributes_pool);
694 if (cop->co_lattr == NULL) {
698 *cop->co_lattr = *ap;
701 * Now try to register the listening connection
704 if (atm_cm_match(cop->co_lattr, NULL) != NULL) {
706 * Can't have matching listeners
711 cop->co_state = COS_LISTEN;
712 LINK2TAIL(cop, Atm_connection, atm_listen_queue, co_next);
720 * Undo any partial setup stuff
724 atm_free((caddr_t)cop->co_lattr);
725 atm_free((caddr_t)cop);
729 * Finish connection setup
738 * Add to LLC Connection
740 * Called by an endpoint service to create a new Connection Manager API
741 * instance to be associated with an LLC-multiplexed connection instance
742 * which has been previously created. The endpoint provided token will
743 * be used in all further CM -> endpoint function calls, and the returned
744 * connection block pointer must be used in all subsequent endpoint -> CM
747 * If the return indicates that the connection setup has been immediately
748 * successful, then the connection is ready for data transmission.
750 * If the return indicates that the connection setup is still in progress,
751 * then the endpoint must wait for notification from the Connection Manager
752 * indicating the final status of the call setup. If the call setup completes
753 * successfully, then a "call connected" notification will be sent to the
754 * endpoint by the Connection Manager. If the call setup fails, then the
755 * endpoint will receive a "call cleared" notification.
757 * All connection instances must be freed with an atm_cm_release() call.
760 * epp pointer to endpoint definition structure
761 * token endpoint's connection instance token
762 * llc pointer to llc attributes for new connection
763 * ecop pointer to existing connection block
764 * copp pointer to location to return allocated connection block
767 * 0 connection has been successfully established
768 * EINPROGRESS connection establishment is in progress
769 * errno addllc failed - reason indicated
773 atm_cm_addllc(epp, token, llc, ecop, copp)
776 struct attr_llc *llc;
777 Atm_connection *ecop;
778 Atm_connection **copp;
780 Atm_connection *cop, *cop2;
787 * Check out requested LLC attributes
789 if ((llc->tag != T_ATM_PRESENT) ||
790 ((llc->v.flags & T_ATM_LLC_SHARING) == 0) ||
791 (llc->v.llc_len < T_ATM_LLC_MIN_LEN) ||
792 (llc->v.llc_len > T_ATM_LLC_MAX_LEN))
796 * Get a connection block
798 cop = (Atm_connection *)atm_allocate(&atm_connection_pool);
803 * Initialize connection info
806 cop->co_toku = token;
812 * Ensure that supplied connection is really valid
815 for (cvp = Q_HEAD(atm_connection_queue, Atm_connvc); cvp;
816 cvp = Q_NEXT(cvp, Atm_connvc, cvc_q)) {
817 for (cop2 = cvp->cvc_conn; cop2; cop2 = cop2->co_next) {
829 switch (ecop->co_state) {
846 * Connection must be LLC multiplexed and shared
848 if ((ecop->co_mpx != ATM_ENC_LLC) ||
849 ((ecop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0)) {
855 * This new LLC header must be unique for this VCC
859 int i = MIN(llc->v.llc_len, cop2->co_llc.v.llc_len);
861 if (KM_CMP(llc->v.llc_info, cop2->co_llc.v.llc_info, i) == 0) {
866 cop2 = cop2->co_next;
870 * Everything seems to check out
872 cop->co_flags = ecop->co_flags;
873 cop->co_state = ecop->co_state;
874 cop->co_mpx = ecop->co_mpx;
875 cop->co_connvc = ecop->co_connvc;
877 LINK2TAIL(cop, Atm_connection, ecop->co_mxh, co_next);
878 cop->co_mxh = ecop->co_mxh;
883 if (err && err != EINPROGRESS) {
885 * Undo any partial setup stuff
888 atm_free((caddr_t)cop);
891 * Pass new connection back to caller
903 * cop pointer to connection block
904 * id identifier for party to be added
905 * addr address of party to be added
908 * 0 addparty successful
909 * errno addparty failed - reason indicated
913 atm_cm_addparty(cop, id, addr)
916 struct t_atm_sap *addr;
926 * cop pointer to connection block
927 * id identifier for party to be added
928 * cause pointer to cause of drop
931 * 0 dropparty successful
932 * errno dropparty failed - reason indicated
936 atm_cm_dropparty(cop, id, cause)
939 struct t_atm_cause *cause;
946 * Release Connection Resources
948 * Called by the endpoint service in order to terminate an ATM connection
949 * and to release all system resources for the connection. This function
950 * must be called for every allocated connection instance and must only
951 * be called by the connection's owner.
954 * cop pointer to connection block
955 * cause pointer to cause of release
958 * 0 release successful
959 * errno release failed - reason indicated
963 atm_cm_release(cop, cause)
965 struct t_atm_cause *cause;
973 * First, a quick state validation check
975 switch (cop->co_state) {
993 panic("atm_cm_release: bogus conn state");
997 * Check out the VCC state too
999 if ((cvp = cop->co_connvc) != NULL) {
1001 switch (cvp->cvc_state) {
1018 panic("atm_cm_release: bogus connvc state");
1022 * If we're the only connection, terminate the VCC
1024 if ((cop->co_mxh == cop) && (cop->co_next == NULL)) {
1025 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
1026 cvp->cvc_attr.cause.v = *cause;
1027 atm_cm_closevc(cvp);
1032 * Now get rid of the connection
1034 atm_cm_closeconn(cop, cause);
1041 * Abort an ATM Connection VCC
1043 * This function allows any non-owner kernel entity to request an
1044 * immediate termination of an ATM VCC. This will normally be called
1045 * when encountering a catastrophic error condition that cannot be
1046 * resolved via the available stack protocols. The connection manager
1047 * will schedule the connection's termination, including notifying the
1048 * connection owner of the termination.
1050 * This function should only be called by a stack entity instance. After
1051 * calling the function, the caller should set a protocol state which just
1052 * waits for a <sap>_TERM stack command to be delivered.
1055 * cvp pointer to connection VCC block
1056 * cause pointer to cause of abort
1059 * 0 abort successful
1060 * errno abort failed - reason indicated
1064 atm_cm_abort(cvp, cause)
1066 struct t_atm_cause *cause;
1068 ATM_DEBUG2("atm_cm_abort: cvp=%p cause=%d\n",
1069 cvp, cause->cause_value);
1072 * Note that we're aborting
1074 cvp->cvc_flags |= CVCF_ABORTING;
1076 switch (cvp->cvc_state) {
1080 * In-line code will handle this
1082 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
1083 cvp->cvc_attr.cause.v = *cause;
1090 * Schedule connection termination, since we want
1091 * to avoid any sequencing interactions
1093 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
1094 cvp->cvc_attr.cause.v = *cause;
1103 * Ignore abort, as we're already terminating
1109 "atm_cm_abort: invalid state: cvp=%p, state=%d\n",
1110 cvp, cvp->cvc_state);
1117 * Incoming ATM Call Received
1119 * Called by a signalling manager to indicate that a new call request has
1120 * been received. This function will allocate and initialize the connection
1121 * manager control blocks and queue this call request. The call request
1122 * processing function, atm_cm_procinq(), will be scheduled to perform the
1126 * vcp pointer to incoming call's VCC control block
1127 * ap pointer to incoming call's attributes
1130 * 0 call queuing successful
1131 * errno call queuing failed - reason indicated
1135 atm_cm_incoming(vcp, ap)
1144 * Do some minimal attribute validation
1148 * Must specify a network interface
1150 if (ap->nif == NULL)
1156 if ((ap->aal.tag != T_ATM_PRESENT) ||
1157 ((ap->aal.type != ATM_AAL5) &&
1158 (ap->aal.type != ATM_AAL3_4)))
1162 * Traffic Descriptor Attributes
1164 if ((ap->traffic.tag != T_ATM_PRESENT) &&
1165 (ap->traffic.tag != T_ATM_ABSENT))
1169 * Broadband Bearer Attributes
1171 if ((ap->bearer.tag != T_ATM_PRESENT) ||
1172 ((ap->bearer.v.connection_configuration != T_ATM_1_TO_1) &&
1173 (ap->bearer.v.connection_configuration != T_ATM_1_TO_MANY)))
1177 * Broadband High Layer Attributes
1179 if ((ap->bhli.tag != T_ATM_PRESENT) &&
1180 (ap->bhli.tag != T_ATM_ABSENT))
1184 * Broadband Low Layer Attributes
1186 if ((ap->blli.tag_l2 != T_ATM_PRESENT) &&
1187 (ap->blli.tag_l2 != T_ATM_ABSENT))
1189 if ((ap->blli.tag_l3 != T_ATM_PRESENT) &&
1190 (ap->blli.tag_l3 != T_ATM_ABSENT))
1194 * Logical Link Control Attributes
1196 if (ap->llc.tag == T_ATM_PRESENT)
1198 ap->llc.tag = T_ATM_ANY;
1201 * Called Party Attributes
1203 if ((ap->called.tag != T_ATM_PRESENT) ||
1204 (ap->called.addr.address_format == T_ATM_ABSENT))
1206 if (ap->called.tag == T_ATM_ABSENT) {
1207 ap->called.addr.address_format = T_ATM_ABSENT;
1208 ap->called.addr.address_length = 0;
1209 ap->called.subaddr.address_format = T_ATM_ABSENT;
1210 ap->called.subaddr.address_length = 0;
1214 * Calling Party Attributes
1216 if ((ap->calling.tag != T_ATM_PRESENT) &&
1217 (ap->calling.tag != T_ATM_ABSENT))
1219 if (ap->calling.tag == T_ATM_ABSENT) {
1220 ap->calling.addr.address_format = T_ATM_ABSENT;
1221 ap->calling.addr.address_length = 0;
1222 ap->calling.subaddr.address_format = T_ATM_ABSENT;
1223 ap->calling.subaddr.address_length = 0;
1227 * Quality of Service Attributes
1229 if (ap->qos.tag != T_ATM_PRESENT)
1233 * Transit Network Attributes
1235 if ((ap->transit.tag != T_ATM_PRESENT) &&
1236 (ap->transit.tag != T_ATM_ABSENT))
1242 if ((ap->cause.tag != T_ATM_PRESENT) &&
1243 (ap->cause.tag != T_ATM_ABSENT))
1247 * Get a connection VCC block
1249 cvp = (Atm_connvc *)atm_allocate(&atm_connvc_pool);
1256 * Initialize the control block
1259 cvp->cvc_sigmgr = vcp->vc_pif->pif_sigmgr;
1260 cvp->cvc_attr = *ap;
1261 cvp->cvc_state = CVCS_INCOMING;
1264 * Control queue length
1267 if (atm_incoming_qlen >= ATM_CALLQ_MAX) {
1274 * Queue request and schedule call processing function
1276 cvp->cvc_flags |= CVCF_INCOMQ;
1277 ENQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
1278 if (atm_incoming_qlen++ == 0) {
1279 timeout(atm_cm_procinq, (void *)0, 0);
1283 * Link for signalling manager
1285 vcp->vc_connvc = cvp;
1293 * Free any resources
1296 atm_free((caddr_t)cvp);
1302 * VCC Connected Notification
1304 * This function is called by a signalling manager as notification that a
1305 * VCC call setup has been successful.
1308 * cvp pointer to connection VCC block
1315 atm_cm_connected(cvp)
1318 Atm_connection *cop, *cop2;
1325 * Validate connection vcc
1327 switch (cvp->cvc_state) {
1331 * Initialize the stack
1333 cvp->cvc_state = CVCS_INIT;
1334 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].init,
1335 cvp->cvc_lower, cvp->cvc_tokl,
1336 cvp, cvp->cvc_attr.api_init, 0, err);
1338 panic("atm_cm_connected: init");
1340 if (cvp->cvc_flags & CVCF_ABORTING) {
1342 * Someone on the stack bailed out...notify all of the
1343 * connections and schedule the VCC termination
1345 cop = cvp->cvc_conn;
1347 cop2 = cop->co_next;
1348 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
1351 atm_cm_closevc(cvp);
1359 * Stack already initialized
1364 panic("atm_cm_connected: connvc state");
1368 * VCC is ready for action
1370 cvp->cvc_state = CVCS_ACTIVE;
1373 * Notify all connections that the call has completed
1375 cop = cvp->cvc_conn;
1377 cop2 = cop->co_next;
1379 switch (cop->co_state) {
1383 cop->co_state = COS_ACTIVE;
1384 (*cop->co_endpt->ep_connected)(cop->co_toku);
1389 * May get here if an ep_connected() call (from
1390 * above) results in an atm_cm_addllc() call for
1391 * the just connected connection.
1396 panic("atm_cm_connected: connection state");
1405 * Input any queued packets
1407 while ((m = cvp->cvc_rcvq) != NULL) {
1408 cvp->cvc_rcvq = KB_QNEXT(m);
1413 * Currently only supported for CPCS API
1415 atm_cm_cpcs_upper(CPCS_UNITDATA_SIG, cvp, (int)m, 0);
1423 * VCC Cleared Notification
1425 * This function is called by a signalling manager as notification that a
1426 * VCC call has been cleared. The cause information describing the reason
1427 * for the call clearing will be contained in the connection VCC attributes.
1430 * cvp pointer to connection VCC block
1440 Atm_connection *cop, *cop2;
1444 if ((cvp->cvc_state == CVCS_FREE) ||
1445 (cvp->cvc_state >= CVCS_CLEAR))
1446 panic("atm_cm_cleared");
1449 cvp->cvc_state = CVCS_CLEAR;
1454 * Terminate all connections
1456 cop = cvp->cvc_conn;
1458 cop2 = cop->co_next;
1459 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
1464 * Clean up connection VCC
1466 atm_cm_closevc(cvp);
1475 * Process Incoming Call Queue
1477 * This function is scheduled by atm_cm_incoming() in order to process
1478 * all the entries on the incoming call queue.
1481 * arg argument passed on timeout() call
1495 * Only process incoming calls up to our quota
1497 while (cnt++ < ATM_CALLQ_MAX) {
1502 * Get next awaiting call
1504 cvp = Q_HEAD(atm_incoming_queue, Atm_connvc);
1509 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
1510 atm_incoming_qlen--;
1511 cvp->cvc_flags &= ~CVCF_INCOMQ;
1522 * If we've expended our quota, reschedule ourselves
1524 if (cnt >= ATM_CALLQ_MAX)
1525 timeout(atm_cm_procinq, (void *)0, 0);
1530 * Process Incoming Call
1532 * This function will search through the listening queue and try to find
1533 * matching endpoint(s) for the incoming call. If we find any, we will
1534 * notify the endpoint service(s) of the incoming call and will then
1535 * notify the signalling manager to progress the call to an active status.
1537 * If there are no listeners for the call, the signalling manager will be
1538 * notified of a call rejection.
1543 * cvp pointer to connection VCC for incoming call
1553 Atm_connection *cop, *lcop, *hcop;
1554 Atm_attributes attr;
1560 attr = cvp->cvc_attr;
1563 * Look for matching listeners
1565 while ((lcop = atm_cm_match(&attr, lcop)) != NULL) {
1569 * Need a new connection block
1571 cop = (Atm_connection *)
1572 atm_allocate(&atm_connection_pool);
1574 cvp->cvc_attr.cause = atm_cause_tmpl;
1575 cvp->cvc_attr.cause.v.cause_value =
1576 T_ATM_CAUSE_TEMPORARY_FAILURE;
1582 * Initialize connection from listener and incoming call
1585 cop->co_state = COS_INCONN;
1586 cop->co_mpx = lcop->co_mpx;
1587 cop->co_endpt = lcop->co_endpt;
1588 cop->co_llc = lcop->co_llc;
1590 switch (attr.bearer.v.connection_configuration) {
1593 cop->co_flags |= COF_P2P;
1596 case T_ATM_1_TO_MANY:
1598 cop->co_flags |= COF_P2MP;
1599 cvp->cvc_attr.cause = atm_cause_tmpl;
1600 cvp->cvc_attr.cause.v.cause_value =
1601 T_ATM_CAUSE_BEARER_CAPABILITY_NOT_IMPLEMENTED;
1606 * Notify endpoint of incoming call
1608 err = (*cop->co_endpt->ep_incoming)
1609 (lcop->co_toku, cop, &cvp->cvc_attr, &cop->co_toku);
1614 * Endpoint has accepted the call
1616 * Setup call attributes
1619 cvp->cvc_attr.api = lcop->co_lattr->api;
1620 cvp->cvc_attr.api_init =
1621 lcop->co_lattr->api_init;
1622 cvp->cvc_attr.llc = lcop->co_lattr->llc;
1624 cvp->cvc_attr.headin = MAX(cvp->cvc_attr.headin,
1625 lcop->co_lattr->headin);
1628 * Setup connection info and queueing
1630 cop->co_state = COS_INACCEPT;
1631 cop->co_connvc = cvp;
1632 LINK2TAIL(cop, Atm_connection, hcop, co_next);
1636 * Need a new connection block next time around
1642 * Endpoint refuses call
1649 * We're done looking for listeners
1653 * Someone actually wants the call, so notify
1654 * the signalling manager to continue
1656 cvp->cvc_flags |= CVCF_CONNQ;
1657 ENQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
1658 if (atm_cm_accept(cvp, hcop))
1663 * Nobody around to take the call
1665 cvp->cvc_attr.cause = atm_cause_tmpl;
1666 cvp->cvc_attr.cause.v.cause_value =
1667 T_ATM_CAUSE_INCOMPATIBLE_DESTINATION;
1672 * Clean up loose ends
1675 atm_free((caddr_t)cop);
1678 * Call has been accepted
1684 * Call failed - notify any endpoints of the call failure
1688 * Clean up loose ends
1691 atm_free((caddr_t)cop);
1693 if (cvp->cvc_attr.cause.tag != T_ATM_PRESENT) {
1694 cvp->cvc_attr.cause = atm_cause_tmpl;
1695 cvp->cvc_attr.cause.v.cause_value =
1696 T_ATM_CAUSE_UNSPECIFIED_NORMAL;
1700 Atm_connection *cop2 = cop->co_next;
1701 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
1706 * Tell the signalling manager to reject the call
1708 atm_cm_closevc(cvp);
1715 * Accept an Incoming ATM Call
1717 * Some endpoint service(s) wants to accept an incoming call, so the
1718 * signalling manager will be notified to attempt to progress the call
1719 * to an active status.
1721 * If the signalling manager indicates that connection activation has
1722 * been immediately successful, then all of the endpoints will be notified
1723 * that the connection is ready for data transmission.
1725 * If the return indicates that connection activation is still in progress,
1726 * then the endpoints must wait for notification from the Connection Manager
1727 * indicating the final status of the call setup. If the call setup completes
1728 * successfully, then a "call connected" notification will be sent to the
1729 * endpoints by the Connection Manager. If the call setup fails, then the
1730 * endpoints will receive a "call cleared" notification.
1735 * cvp pointer to connection VCC for incoming call
1736 * cop pointer to head of accepted connections
1739 * 0 connection has been successfully activated
1740 * errno accept failed - reason indicated
1744 atm_cm_accept(cvp, cop)
1746 Atm_connection *cop;
1748 struct stack_list sl;
1749 void (*upf)__P((int, void *, int, int));
1754 * Link vcc to connections
1756 cvp->cvc_conn = cop;
1759 * Initialize stack list index
1764 * Check out Data API
1766 switch (cvp->cvc_attr.api) {
1769 upf = atm_cm_cpcs_upper;
1773 sl.sl_sap[sli++] = SAP_SSCF_UNI;
1774 sl.sl_sap[sli++] = SAP_SSCOP;
1775 upf = atm_cm_saal_upper;
1779 sl.sl_sap[sli++] = SAP_SSCOP;
1780 upf = atm_cm_sscop_upper;
1790 switch (cvp->cvc_attr.aal.type) {
1793 sl.sl_sap[sli++] = SAP_CPCS_AAL5;
1794 sl.sl_sap[sli++] = SAP_SAR_AAL5;
1795 sl.sl_sap[sli++] = SAP_ATM;
1799 sl.sl_sap[sli++] = SAP_CPCS_AAL3_4;
1800 sl.sl_sap[sli++] = SAP_SAR_AAL3_4;
1801 sl.sl_sap[sli++] = SAP_ATM;
1806 * Terminate stack list
1811 * Create a service stack
1813 err = atm_create_stack(cvp, &sl, upf);
1819 * Let the signalling manager finish the VCC activation
1821 switch ((*cvp->cvc_sigmgr->sm_accept)(cvp->cvc_vcc, &err)) {
1823 case CALL_PROCEEDING:
1825 * Note that we're not finished yet
1830 case CALL_CONNECTED:
1832 * Initialize the stack now, even if the call isn't totally
1833 * active yet. We want to avoid the delay between getting
1834 * the "call connected" event and actually notifying the
1835 * adapter to accept cells on the new VCC - if the delay is
1836 * too long, then we end up dropping the first pdus sent by
1839 cvp->cvc_state = CVCS_INIT;
1840 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].init,
1841 cvp->cvc_lower, cvp->cvc_tokl, cvp,
1842 cvp->cvc_attr.api_init, 0, err2);
1844 panic("atm_cm_accept: init");
1846 if (cvp->cvc_flags & CVCF_ABORTING) {
1848 * Someone on the stack bailed out...schedule the
1849 * VCC and stack termination
1854 * Everything looks fine from here
1857 cvp->cvc_state = CVCS_ACCEPT;
1859 cvp->cvc_state = CVCS_ACTIVE;
1865 * Terminate stack and clean up before we leave
1867 cvp->cvc_state = CVCS_CLEAR;
1871 panic("atm_cm_accept: accept");
1877 * Call has been connected, notify endpoints
1880 Atm_connection *cop2 = cop->co_next;
1882 cop->co_state = COS_ACTIVE;
1883 (*cop->co_endpt->ep_connected)(cop->co_toku);
1887 } else if (err == EINPROGRESS) {
1889 * Call is still in progress, endpoint must wait
1895 * Let caller know we failed
1897 cvp->cvc_attr.cause = atm_cause_tmpl;
1898 cvp->cvc_attr.cause.v.cause_value =
1899 T_ATM_CAUSE_UNSPECIFIED_RESOURCE_UNAVAILABLE;
1907 * Match Attributes on Listening Queue
1909 * This function will attempt to match the supplied connection attributes
1910 * with one of the registered attributes in the listening queue. The pcop
1911 * argument may be supplied in order to allow multiple listeners to share
1912 * an incoming call (if supported by the listeners).
1917 * ap pointer to attributes to be matched
1918 * pcop pointer to the previously matched connection
1921 * addr connection with which a match was found
1926 atm_cm_match(ap, pcop)
1928 Atm_connection *pcop;
1930 Atm_connection *cop;
1931 Atm_attributes *lap;
1935 * If we've already matched a listener...
1939 * Make sure already matched listener supports sharing
1941 if ((pcop->co_mpx != ATM_ENC_LLC) ||
1942 ((pcop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0))
1946 * Position ourselves after the matched entry
1948 for (cop = atm_listen_queue; cop; cop = cop->co_next) {
1950 cop = pcop->co_next;
1956 * Start search at top of listening queue
1958 cop = atm_listen_queue;
1962 * Search through listening queue
1964 for (; cop; cop = cop->co_next) {
1966 lap = cop->co_lattr;
1969 * If we're trying to share, check that this entry allows it
1972 if ((cop->co_mpx != ATM_ENC_LLC) ||
1973 ((cop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0))
1978 * ALL "matchable" attributes must match
1984 if (lap->bhli.tag == T_ATM_ABSENT) {
1985 if (ap->bhli.tag == T_ATM_PRESENT)
1987 } else if (lap->bhli.tag == T_ATM_PRESENT) {
1988 if (ap->bhli.tag == T_ATM_ABSENT)
1990 if (ap->bhli.tag == T_ATM_PRESENT)
1991 if (KM_CMP(&lap->bhli.v, &ap->bhli.v,
1992 sizeof(struct t_atm_bhli)))
1999 if (lap->blli.tag_l2 == T_ATM_ABSENT) {
2000 if (ap->blli.tag_l2 == T_ATM_PRESENT)
2002 } else if (lap->blli.tag_l2 == T_ATM_PRESENT) {
2003 if (ap->blli.tag_l2 == T_ATM_ABSENT)
2005 if (ap->blli.tag_l2 == T_ATM_PRESENT) {
2006 if (KM_CMP(&lap->blli.v.layer_2_protocol.ID,
2007 &ap->blli.v.layer_2_protocol.ID,
2009 ap->blli.v.layer_2_protocol.ID)))
2017 if (lap->blli.tag_l3 == T_ATM_ABSENT) {
2018 if (ap->blli.tag_l3 == T_ATM_PRESENT)
2020 } else if (lap->blli.tag_l3 == T_ATM_PRESENT) {
2021 if (ap->blli.tag_l3 == T_ATM_ABSENT)
2023 if (ap->blli.tag_l3 == T_ATM_PRESENT) {
2024 if (KM_CMP(&lap->blli.v.layer_3_protocol.ID,
2025 &ap->blli.v.layer_3_protocol.ID,
2027 ap->blli.v.layer_3_protocol.ID)))
2035 if (lap->llc.tag == T_ATM_ABSENT) {
2036 if (ap->llc.tag == T_ATM_PRESENT)
2038 } else if (lap->llc.tag == T_ATM_PRESENT) {
2039 if (ap->llc.tag == T_ATM_ABSENT)
2041 if (ap->llc.tag == T_ATM_PRESENT) {
2042 int i = MIN(lap->llc.v.llc_len,
2045 if (KM_CMP(lap->llc.v.llc_info,
2046 ap->llc.v.llc_info, i))
2054 if (lap->aal.tag == T_ATM_ABSENT) {
2055 if (ap->aal.tag == T_ATM_PRESENT)
2057 } else if (lap->aal.tag == T_ATM_PRESENT) {
2058 if (ap->aal.tag == T_ATM_ABSENT)
2060 if (ap->aal.tag == T_ATM_PRESENT) {
2061 if (lap->aal.type != ap->aal.type)
2063 if (lap->aal.type == ATM_AAL5) {
2064 if (lap->aal.v.aal5.SSCS_type !=
2065 ap->aal.v.aal5.SSCS_type)
2068 if (lap->aal.v.aal4.SSCS_type !=
2069 ap->aal.v.aal4.SSCS_type)
2078 if (lap->called.tag == T_ATM_ABSENT) {
2079 if (ap->called.tag == T_ATM_PRESENT)
2081 } else if (lap->called.tag == T_ATM_PRESENT) {
2082 if (ap->called.tag == T_ATM_ABSENT)
2084 if (ap->called.tag == T_ATM_PRESENT) {
2085 if ((!ATM_ADDR_EQUAL(&lap->called.addr,
2086 &ap->called.addr)) ||
2087 (!ATM_ADDR_EQUAL(&lap->called.subaddr,
2088 &ap->called.subaddr)))
2094 * Found a full match - return it
2104 * Find Shareable LLC VCC
2106 * Given a endpoint-supplied connection attribute using LLC multiplexing,
2107 * this function will attempt to locate an existing connection which meets
2108 * the requirements of the supplied attributes.
2113 * ap pointer to requested attributes
2116 * addr shareable LLC connection VCC
2117 * 0 no shareable VCC available
2121 atm_cm_share_llc(ap)
2124 Atm_connection *cop;
2128 * Is requestor willing to share?
2130 if ((ap->llc.v.flags & T_ATM_LLC_SHARING) == 0)
2134 * Try to find a shareable connection
2136 for (cvp = Q_HEAD(atm_connection_queue, Atm_connvc); cvp;
2137 cvp = Q_NEXT(cvp, Atm_connvc, cvc_q)) {
2140 * Dont use terminating connections
2142 switch (cvp->cvc_state) {
2154 * Is connection LLC and shareable?
2156 if ((cvp->cvc_attr.llc.tag != T_ATM_PRESENT) ||
2157 ((cvp->cvc_attr.llc.v.flags & T_ATM_LLC_SHARING) == 0))
2161 * Match requested attributes with existing connection
2163 if (ap->nif != cvp->cvc_attr.nif)
2166 if ((ap->api != cvp->cvc_attr.api) ||
2167 (ap->api_init != cvp->cvc_attr.api_init))
2173 if (cvp->cvc_flags & CVCF_CALLER) {
2174 if ((!ATM_ADDR_EQUAL(&ap->called.addr,
2175 &cvp->cvc_attr.called.addr)) ||
2176 (!ATM_ADDR_EQUAL(&ap->called.subaddr,
2177 &cvp->cvc_attr.called.subaddr)))
2180 if (cvp->cvc_attr.calling.tag != T_ATM_PRESENT)
2182 if ((!ATM_ADDR_EQUAL(&ap->called.addr,
2183 &cvp->cvc_attr.calling.addr)) ||
2184 (!ATM_ADDR_EQUAL(&ap->called.subaddr,
2185 &cvp->cvc_attr.calling.subaddr)))
2192 if (ap->aal.type == ATM_AAL5) {
2193 struct t_atm_aal5 *ap5, *cv5;
2195 ap5 = &ap->aal.v.aal5;
2196 cv5 = &cvp->cvc_attr.aal.v.aal5;
2198 if ((cvp->cvc_attr.aal.type != ATM_AAL5) ||
2199 (ap5->SSCS_type != cv5->SSCS_type))
2202 if (cvp->cvc_flags & CVCF_CALLER) {
2203 if (ap5->forward_max_SDU_size >
2204 cv5->forward_max_SDU_size)
2207 if (ap5->forward_max_SDU_size >
2208 cv5->backward_max_SDU_size)
2212 struct t_atm_aal4 *ap4, *cv4;
2214 ap4 = &ap->aal.v.aal4;
2215 cv4 = &cvp->cvc_attr.aal.v.aal4;
2217 if ((cvp->cvc_attr.aal.type != ATM_AAL3_4) ||
2218 (ap4->SSCS_type != cv4->SSCS_type))
2221 if (cvp->cvc_flags & CVCF_CALLER) {
2222 if (ap4->forward_max_SDU_size >
2223 cv4->forward_max_SDU_size)
2226 if (ap4->forward_max_SDU_size >
2227 cv4->backward_max_SDU_size)
2233 * Traffic Descriptor
2235 if ((ap->traffic.tag != T_ATM_PRESENT) ||
2236 (cvp->cvc_attr.traffic.tag != T_ATM_PRESENT) ||
2237 (ap->traffic.v.best_effort != T_YES) ||
2238 (cvp->cvc_attr.traffic.v.best_effort != T_YES))
2244 if (ap->bearer.v.connection_configuration !=
2245 cvp->cvc_attr.bearer.v.connection_configuration)
2251 if (cvp->cvc_flags & CVCF_CALLER) {
2252 if ((ap->qos.v.forward.qos_class !=
2253 cvp->cvc_attr.qos.v.forward.qos_class) ||
2254 (ap->qos.v.backward.qos_class !=
2255 cvp->cvc_attr.qos.v.backward.qos_class))
2258 if ((ap->qos.v.forward.qos_class !=
2259 cvp->cvc_attr.qos.v.backward.qos_class) ||
2260 (ap->qos.v.backward.qos_class !=
2261 cvp->cvc_attr.qos.v.forward.qos_class))
2266 * The new LLC header must also be unique for this VCC
2268 for (cop = cvp->cvc_conn; cop; cop = cop->co_next) {
2269 int i = MIN(ap->llc.v.llc_len,
2270 cop->co_llc.v.llc_len);
2272 if (KM_CMP(ap->llc.v.llc_info,
2273 cop->co_llc.v.llc_info, i) == 0)
2278 * If no header overlaps, then we're done
2291 * This function will terminate a connection, including notifying the
2292 * user, if necessary, and freeing up control block memory. The caller
2293 * is responsible for managing the connection VCC.
2298 * cop pointer to connection block
2299 * cause pointer to cause of close
2306 atm_cm_closeconn(cop, cause)
2307 Atm_connection *cop;
2308 struct t_atm_cause *cause;
2312 * Decide whether user needs notification
2314 switch (cop->co_state) {
2322 * Yup, let 'em know connection is gone
2325 (*cop->co_endpt->ep_cleared)(cop->co_toku, cause);
2330 * Nope,they should know already
2335 panic("atm_cm_closeconn: bogus state");
2339 * Unlink connection from its queues
2341 switch (cop->co_state) {
2344 atm_free((caddr_t)cop->co_lattr);
2345 UNLINK(cop, Atm_connection, atm_listen_queue, co_next);
2350 * Remove connection from multiplexor queue
2352 if (cop->co_mxh != cop) {
2354 * Connection is down the chain, just unlink it
2356 UNLINK(cop, Atm_connection, cop->co_mxh, co_next);
2358 } else if (cop->co_next != NULL) {
2360 * Connection is at the head of a non-singleton chain,
2361 * so unlink and reset the chain head
2363 Atm_connection *t, *nhd;
2365 t = nhd = cop->co_next;
2371 nhd->co_connvc->cvc_conn = nhd;
2376 * Free the connection block
2378 cop->co_state = COS_FREE;
2379 atm_free((caddr_t)cop);
2386 * Close Connection VCC
2388 * This function will terminate a connection VCC, including releasing the
2389 * the call to the signalling manager, terminating the VCC protocol stack,
2390 * and freeing up control block memory.
2395 * cvp pointer to connection VCC block
2408 * Break links with the connection block
2410 cvp->cvc_conn = NULL;
2413 * Cancel any running timer
2418 * Free queued packets
2420 while (cvp->cvc_rcvq) {
2424 cvp->cvc_rcvq = KB_QNEXT(m);
2430 * Unlink from any queues
2432 if (cvp->cvc_flags & CVCF_INCOMQ) {
2433 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
2434 atm_incoming_qlen--;
2435 cvp->cvc_flags &= ~CVCF_INCOMQ;
2437 } else if (cvp->cvc_flags & CVCF_CONNQ) {
2438 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
2439 cvp->cvc_flags &= ~CVCF_CONNQ;
2443 * Release the signalling call
2445 switch (cvp->cvc_state) {
2453 cvp->cvc_state = CVCS_RELEASE;
2454 switch ((*cvp->cvc_sigmgr->sm_release)
2455 (cvp->cvc_vcc, &err)) {
2459 * Looks good so far...
2463 case CALL_PROCEEDING:
2465 * We'll have to wait for the call to clear
2471 * If there's a memory shortage, retry later.
2472 * Otherwise who knows what's going on....
2474 if ((err == ENOMEM) || (err == ENOBUFS)) {
2475 CVC_TIMER(cvp, 1 * ATM_HZ);
2479 "atm_cm_closevc: release %d\n", err);
2488 cvp->cvc_state = CVCS_REJECT;
2489 switch ((*cvp->cvc_sigmgr->sm_reject)
2490 (cvp->cvc_vcc, &err)) {
2494 * Looks good so far...
2500 * If there's a memory shortage, retry later.
2501 * Otherwise who knows what's going on....
2503 if ((err == ENOMEM) || (err == ENOBUFS)) {
2504 CVC_TIMER(cvp, 1 * ATM_HZ);
2508 "atm_cm_closevc: reject %d\n", err);
2517 * No need for anything here
2522 panic("atm_cm_closevc: bogus state");
2526 * Now terminate the stack
2528 if (cvp->cvc_tokl) {
2529 cvp->cvc_state = CVCS_TERM;
2532 * Wait until stack is unwound before terminating
2534 if ((cvp->cvc_downcnt > 0) || (cvp->cvc_upcnt > 0)) {
2539 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].term,
2540 cvp->cvc_lower, cvp->cvc_tokl, cvp, 0, 0, err);
2542 cvp->cvc_tokl = NULL;
2546 * Let signalling manager finish up
2548 cvp->cvc_state = CVCS_FREE;
2550 (void) (*cvp->cvc_sigmgr->sm_free)(cvp->cvc_vcc);
2554 * Finally, free our own control blocks
2556 atm_free((caddr_t)cvp);
2563 * Process a Connection VCC timeout
2565 * Called when a previously scheduled cvc control block timer expires.
2566 * Processing will be based on the current cvc state.
2571 * tip pointer to cvc timer control block
2579 struct atm_time *tip;
2581 Atm_connection *cop, *cop2;
2585 * Back-off to cvc control block
2587 cvp = (Atm_connvc *)
2588 ((caddr_t)tip - (int)(&((Atm_connvc *)0)->cvc_time));
2591 * Process timeout based on protocol state
2593 switch (cvp->cvc_state) {
2601 if ((cvp->cvc_flags & CVCF_ABORTING) == 0)
2605 * Terminate all connections
2607 cop = cvp->cvc_conn;
2609 cop2 = cop->co_next;
2610 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
2617 atm_cm_closevc(cvp);
2625 * Retry failed operation
2627 atm_cm_closevc(cvp);
2633 "atm_cm_timeout: invalid state: cvp=%p, state=%d\n",
2634 cvp, cvp->cvc_state);
2640 * CPCS User Control Commands
2642 * This function is called by an endpoint user to pass a control command
2643 * across a CPCS data API. Mostly we just send these down the stack.
2646 * cmd stack command code
2647 * cop pointer to connection block
2651 * 0 command output successful
2652 * errno output failed - reason indicated
2656 atm_cm_cpcs_ctl(cmd, cop, arg)
2658 Atm_connection *cop;
2665 * Validate connection state
2667 if (cop->co_state != COS_ACTIVE) {
2672 cvp = cop->co_connvc;
2673 if (cvp->cvc_state != CVCS_ACTIVE) {
2678 if (cvp->cvc_attr.api != CMAPI_CPCS) {
2697 * This function is called by an endpoint user to output a data packet
2698 * across a CPCS data API. After we've validated the connection state, the
2699 * packet will be encapsulated (if necessary) and sent down the data stack.
2702 * cop pointer to connection block
2703 * m pointer to packet buffer chain to be output
2706 * 0 packet output successful
2707 * errno output failed - reason indicated
2711 atm_cm_cpcs_data(cop, m)
2712 Atm_connection *cop;
2716 struct attr_llc *llcp;
2722 * Validate connection state
2724 if (cop->co_state != COS_ACTIVE) {
2729 cvp = cop->co_connvc;
2730 if (cvp->cvc_state != CVCS_ACTIVE) {
2735 if (cvp->cvc_attr.api != CMAPI_CPCS) {
2741 * Add any packet encapsulation
2743 switch (cop->co_mpx) {
2753 * Need to add an LLC header
2755 llcp = &cop->co_llc;
2758 * See if there's room to add LLC header to front of packet.
2760 KB_HEADROOM(m, space);
2761 if (space < llcp->v.llc_len) {
2765 * We have to allocate another buffer and tack it
2766 * onto the front of the packet
2768 KB_ALLOCPKT(n, llcp->v.llc_len, KB_F_NOWAIT,
2774 KB_TAILALIGN(n, llcp->v.llc_len);
2779 * Header fits, just adjust buffer controls
2781 KB_HEADADJ(m, llcp->v.llc_len);
2785 * Add the LLC header
2787 KB_DATASTART(m, bp, void *);
2788 KM_COPY(llcp->v.llc_info, bp, llcp->v.llc_len);
2789 KB_PLENADJ(m, llcp->v.llc_len);
2793 panic("atm_cm_cpcs_data: mpx");
2797 * Finally, we can send the packet on its way
2799 STACK_CALL(CPCS_UNITDATA_INV, cvp->cvc_lower, cvp->cvc_tokl,
2800 cvp, (int)m, 0, err);
2808 * Process CPCS Stack Commands
2810 * This is the top of the CPCS API data stack. All upward stack commands
2811 * for the CPCS data API will be received and processed here.
2814 * cmd stack command code
2815 * tok session token (pointer to connection VCC control block)
2824 atm_cm_cpcs_upper(cmd, tok, arg1, arg2)
2830 Atm_connection *cop;
2831 Atm_connvc *cvp = tok;
2838 case CPCS_UNITDATA_SIG:
2842 m = (KBuffer *)arg1;
2844 if (cvp->cvc_state != CVCS_ACTIVE) {
2845 if (cvp->cvc_state == CVCS_ACCEPT) {
2849 * Queue up any packets received before sigmgr
2850 * notifies us of incoming call completion
2852 if (cvp->cvc_rcvqlen >= CVC_RCVQ_MAX) {
2854 atm_cm_stat.cms_rcvconnvc++;
2858 if (cvp->cvc_rcvq == NULL) {
2861 for (n = cvp->cvc_rcvq;
2862 KB_QNEXT(n) != NULL;
2871 atm_cm_stat.cms_rcvconnvc++;
2877 * Locate packet's connection
2879 cop = cvp->cvc_conn;
2880 switch (cop->co_mpx) {
2884 * We're already there...
2890 * Find connection with matching LLC header
2892 if (KB_LEN(m) < T_ATM_LLC_MAX_LEN) {
2893 KB_PULLUP(m, T_ATM_LLC_MAX_LEN, m);
2895 atm_cm_stat.cms_llcdrop++;
2899 KB_DATASTART(m, bp, void *);
2904 if (KM_CMP(bp, cop->co_llc.v.llc_info,
2905 cop->co_llc.v.llc_len) == 0)
2914 * No connected user for this LLC
2917 atm_cm_stat.cms_llcid++;
2922 * Strip off the LLC header
2924 KB_HEADADJ(m, -cop->co_llc.v.llc_len);
2925 KB_PLENADJ(m, -cop->co_llc.v.llc_len);
2929 panic("atm_cm_cpcs_upper: mpx");
2933 * We've found our connection, so hand the packet off
2935 if (cop->co_state != COS_ACTIVE) {
2937 atm_cm_stat.cms_rcvconn++;
2940 (*cop->co_endpt->ep_cpcs_data)(cop->co_toku, m);
2943 case CPCS_UABORT_SIG:
2944 case CPCS_PABORT_SIG:
2946 * We don't support these (yet), so just fall thru...
2950 log(LOG_ERR, "atm_cm_cpcs_upper: unknown cmd 0x%x\n", cmd);
2956 * SAAL User Control Commands
2958 * This function is called by an endpoint user to pass a control command
2959 * across a SAAL data API. Mostly we just send these down the stack.
2962 * cmd stack command code
2963 * cop pointer to connection block
2967 * 0 command output successful
2968 * errno output failed - reason indicated
2972 atm_cm_saal_ctl(cmd, cop, arg)
2974 Atm_connection *cop;
2981 * Validate connection state
2983 if (cop->co_state != COS_ACTIVE) {
2988 cvp = cop->co_connvc;
2989 if (cvp->cvc_state != CVCS_ACTIVE) {
2994 if (cvp->cvc_attr.api != CMAPI_SAAL) {
3001 case SSCF_UNI_ESTABLISH_REQ:
3002 case SSCF_UNI_RELEASE_REQ:
3004 * Pass command down the stack
3006 STACK_CALL(cmd, cvp->cvc_lower, cvp->cvc_tokl, cvp,
3022 * This function is called by an endpoint user to output a data packet
3023 * across a SAAL data API. After we've validated the connection state,
3024 * the packet will be sent down the data stack.
3027 * cop pointer to connection block
3028 * m pointer to packet buffer chain to be output
3031 * 0 packet output successful
3032 * errno output failed - reason indicated
3036 atm_cm_saal_data(cop, m)
3037 Atm_connection *cop;
3045 * Validate connection state
3047 if (cop->co_state != COS_ACTIVE) {
3052 cvp = cop->co_connvc;
3053 if (cvp->cvc_state != CVCS_ACTIVE) {
3058 if (cvp->cvc_attr.api != CMAPI_SAAL) {
3064 * Finally, we can send the packet on its way
3066 STACK_CALL(SSCF_UNI_DATA_REQ, cvp->cvc_lower, cvp->cvc_tokl,
3067 cvp, (int)m, 0, err);
3075 * Process SAAL Stack Commands
3077 * This is the top of the SAAL API data stack. All upward stack commands
3078 * for the SAAL data API will be received and processed here.
3081 * cmd stack command code
3082 * tok session token (pointer to connection VCC control block)
3091 atm_cm_saal_upper(cmd, tok, arg1, arg2)
3097 Atm_connection *cop;
3098 Atm_connvc *cvp = tok;
3103 case SSCF_UNI_ESTABLISH_IND:
3104 case SSCF_UNI_ESTABLISH_CNF:
3105 case SSCF_UNI_RELEASE_IND:
3106 case SSCF_UNI_RELEASE_CNF:
3110 cop = cvp->cvc_conn;
3111 if (cvp->cvc_state != CVCS_ACTIVE)
3113 if (cop->co_state != COS_ACTIVE)
3116 (*cop->co_endpt->ep_saal_ctl)(cmd, cop->co_toku, (void *)arg1);
3119 case SSCF_UNI_DATA_IND:
3123 cop = cvp->cvc_conn;
3124 if (cvp->cvc_state != CVCS_ACTIVE) {
3125 atm_cm_stat.cms_rcvconnvc++;
3126 KB_FREEALL((KBuffer *)arg1);
3129 if (cop->co_state != COS_ACTIVE) {
3130 atm_cm_stat.cms_rcvconn++;
3131 KB_FREEALL((KBuffer *)arg1);
3135 (*cop->co_endpt->ep_saal_data)(cop->co_toku, (KBuffer *)arg1);
3138 case SSCF_UNI_UNITDATA_IND:
3142 KB_FREEALL((KBuffer *)arg1);
3147 log(LOG_ERR, "atm_cm_saal_upper: unknown cmd 0x%x\n", cmd);
3153 * SSCOP User Control Commands
3155 * This function is called by an endpoint user to pass a control command
3156 * across a SSCOP data API. Mostly we just send these down the stack.
3159 * cmd stack command code
3160 * cop pointer to connection block
3165 * 0 command output successful
3166 * errno output failed - reason indicated
3170 atm_cm_sscop_ctl(cmd, cop, arg1, arg2)
3172 Atm_connection *cop;
3180 * Validate connection state
3182 if (cop->co_state != COS_ACTIVE) {
3187 cvp = cop->co_connvc;
3188 if (cvp->cvc_state != CVCS_ACTIVE) {
3193 if (cvp->cvc_attr.api != CMAPI_SSCOP) {
3200 case SSCOP_ESTABLISH_REQ:
3201 case SSCOP_ESTABLISH_RSP:
3202 case SSCOP_RELEASE_REQ:
3203 case SSCOP_RESYNC_REQ:
3204 case SSCOP_RESYNC_RSP:
3205 case SSCOP_RECOVER_RSP:
3206 case SSCOP_RETRIEVE_REQ:
3208 * Pass command down the stack
3210 STACK_CALL(cmd, cvp->cvc_lower, cvp->cvc_tokl, cvp,
3211 (int)arg1, (int)arg2, err);
3226 * This function is called by an endpoint user to output a data packet
3227 * across a SSCOP data API. After we've validated the connection state,
3228 * the packet will be encapsulated and sent down the data stack.
3231 * cop pointer to connection block
3232 * m pointer to packet buffer chain to be output
3235 * 0 packet output successful
3236 * errno output failed - reason indicated
3240 atm_cm_sscop_data(cop, m)
3241 Atm_connection *cop;
3249 * Validate connection state
3251 if (cop->co_state != COS_ACTIVE) {
3256 cvp = cop->co_connvc;
3257 if (cvp->cvc_state != CVCS_ACTIVE) {
3262 if (cvp->cvc_attr.api != CMAPI_SSCOP) {
3268 * Finally, we can send the packet on its way
3270 STACK_CALL(SSCOP_DATA_REQ, cvp->cvc_lower, cvp->cvc_tokl,
3271 cvp, (int)m, 0, err);
3279 * Process SSCOP Stack Commands
3281 * This is the top of the SSCOP API data stack. All upward stack commands
3282 * for the SSCOP data API will be received and processed here.
3285 * cmd stack command code
3286 * tok session token (pointer to connection VCC control block)
3295 atm_cm_sscop_upper(cmd, tok, arg1, arg2)
3301 Atm_connection *cop;
3302 Atm_connvc *cvp = tok;
3306 case SSCOP_ESTABLISH_IND:
3307 case SSCOP_ESTABLISH_CNF:
3308 case SSCOP_RELEASE_IND:
3309 case SSCOP_RESYNC_IND:
3313 cop = cvp->cvc_conn;
3314 if ((cvp->cvc_state != CVCS_ACTIVE) ||
3315 (cop->co_state != COS_ACTIVE)) {
3316 KB_FREEALL((KBuffer *)arg1);
3320 (*cop->co_endpt->ep_sscop_ctl)
3321 (cmd, cop->co_toku, (void *)arg1, (void *)arg2);
3324 case SSCOP_RELEASE_CNF:
3325 case SSCOP_RESYNC_CNF:
3326 case SSCOP_RECOVER_IND:
3327 case SSCOP_RETRIEVE_IND:
3328 case SSCOP_RETRIEVECMP_IND:
3332 cop = cvp->cvc_conn;
3333 if ((cvp->cvc_state != CVCS_ACTIVE) ||
3334 (cop->co_state != COS_ACTIVE))
3337 (*cop->co_endpt->ep_sscop_ctl)
3338 (cmd, cop->co_toku, (void *)arg1, (void *)arg2);
3341 case SSCOP_DATA_IND:
3345 cop = cvp->cvc_conn;
3346 if (cvp->cvc_state != CVCS_ACTIVE) {
3347 atm_cm_stat.cms_rcvconnvc++;
3348 KB_FREEALL((KBuffer *)arg1);
3351 if (cop->co_state != COS_ACTIVE) {
3352 atm_cm_stat.cms_rcvconn++;
3353 KB_FREEALL((KBuffer *)arg1);
3357 (*cop->co_endpt->ep_sscop_data)
3358 (cop->co_toku, (KBuffer *)arg1, arg2);
3361 case SSCOP_UNITDATA_IND:
3365 KB_FREEALL((KBuffer *)arg1);
3370 log(LOG_ERR, "atm_cm_sscop_upper: unknown cmd 0x%x\n", cmd);
3376 * Register an ATM Endpoint Service
3378 * Every ATM endpoint service must register itself here before it can
3379 * issue or receive any connection requests.
3382 * epp pointer to endpoint definition structure
3385 * 0 registration successful
3386 * errno registration failed - reason indicated
3390 atm_endpoint_register(epp)
3396 * See if we need to be initialized
3404 if (epp->ep_id > ENDPT_MAX) {
3408 if (atm_endpoints[epp->ep_id] != NULL) {
3414 * Add endpoint to list
3416 atm_endpoints[epp->ep_id] = epp;
3424 * De-register an ATM Endpoint Service
3426 * Each ATM endpoint service provider must de-register its registered
3427 * endpoint(s) before terminating. Specifically, loaded kernel modules
3428 * must de-register their services before unloading themselves.
3431 * epp pointer to endpoint definition structure
3434 * 0 de-registration successful
3435 * errno de-registration failed - reason indicated
3439 atm_endpoint_deregister(epp)
3447 if (epp->ep_id > ENDPT_MAX) {
3451 if (atm_endpoints[epp->ep_id] != epp) {
3457 * Remove endpoint from list
3459 atm_endpoints[epp->ep_id] = NULL;