3 * ===================================
4 * HARP | Host ATM Research Platform
5 * ===================================
8 * This Host ATM Research Platform ("HARP") file (the "Software") is
9 * made available by Network Computing Services, Inc. ("NetworkCS")
10 * "AS IS". NetworkCS does not provide maintenance, improvements or
11 * support of any kind.
13 * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14 * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15 * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16 * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17 * In no event shall NetworkCS be responsible for any damages, including
18 * but not limited to consequential damages, arising from or relating to
19 * any use of the Software or related support.
21 * Copyright 1994-1998 Network Computing Services, Inc.
23 * Copies of this Software may be made, however, the above copyright
24 * notice must be reproduced on all copies.
26 * @(#) $FreeBSD: src/sys/netatm/atm_cm.c,v 1.6 1999/08/28 00:48:34 peter Exp $
27 * @(#) $DragonFly: src/sys/netproto/atm/atm_cm.c,v 1.4 2003/08/23 10:06:21 rob Exp $
34 * ATM Connection Manager
38 #include "kern_include.h"
43 struct atm_cm_stat atm_cm_stat = {0};
48 static void atm_cm_cpcs_upper (int, void *, int, int);
49 static void atm_cm_saal_upper (int, void *, int, int);
50 static void atm_cm_sscop_upper (int, void *, int, int);
51 static Atm_connvc * atm_cm_share_llc (Atm_attributes *);
52 static void atm_cm_closeconn (Atm_connection *,
53 struct t_atm_cause *);
54 static void atm_cm_closevc (Atm_connvc *);
55 static void atm_cm_timeout (struct atm_time *);
56 static KTimeout_ret atm_cm_procinq (void *);
57 static void atm_cm_incall (Atm_connvc *);
58 static int atm_cm_accept (Atm_connvc *, Atm_connection *);
63 static Queue_t atm_connection_queue = {NULL};
64 static Queue_t atm_incoming_queue = {NULL};
65 static int atm_incoming_qlen = 0;
66 static Atm_connection *atm_listen_queue = NULL;
67 static struct attr_cause atm_cause_tmpl =
68 {T_ATM_PRESENT, {T_ATM_ITU_CODING, T_ATM_LOC_USER, 0, {0, 0, 0, 0}}};
71 * Stack commands, indexed by API
77 {CPCS_INIT, CPCS_TERM}, /* CMAPI_CPCS */
78 {SSCF_UNI_INIT, SSCF_UNI_TERM}, /* CMAPI_SAAL */
79 {SSCOP_INIT, SSCOP_TERM}, /* CMAPI_SSCOP */
83 static struct sp_info atm_connection_pool = {
84 "atm connection pool", /* si_name */
85 sizeof(Atm_connection), /* si_blksiz */
89 static struct sp_info atm_connvc_pool = {
90 "atm connection vcc pool", /* si_name */
91 sizeof(Atm_connvc), /* si_blksiz */
98 * Initiate Outgoing ATM Call
100 * Called by an endpoint service to create a new Connection Manager API
101 * instance and to initiate an outbound ATM connection. The endpoint
102 * provided token will be used in all further CM -> endpoint function
103 * calls, and the returned connection block pointer must be used in all
104 * subsequent endpoint -> CM function calls.
106 * If the return indicates that the connection setup has been immediately
107 * successful (typically only for PVCs and shared SVCs), then the connection
108 * is ready for data transmission.
110 * If the return indicates that the connection setup is still in progress,
111 * then the endpoint must wait for notification from the Connection Manager
112 * indicating the final status of the call setup. If the call setup completes
113 * successfully, then a "call connected" notification will be sent to the
114 * endpoint by the Connection Manager. If the call setup fails, then the
115 * endpoint will receive a "call cleared" notification.
117 * All connection instances must be freed with an atm_cm_release() call.
120 * epp pointer to endpoint definition structure
121 * token endpoint's connection instance token
122 * ap pointer to requested connection attributes
123 * copp pointer to location to return allocated connection block
126 * 0 connection has been successfully established
127 * EINPROGRESS connection establishment is in progress
128 * errno connection failed - reason indicated
132 atm_cm_connect(epp, token, ap, copp)
136 Atm_connection **copp;
142 struct stack_list sl;
143 void (*upf)(int, void *, int, int);
144 int s, sli, err, err2;
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(epp, token, ap, copp)
519 Atm_connection **copp;
527 * Get a connection block
529 cop = (Atm_connection *)atm_allocate(&atm_connection_pool);
534 * Initialize connection info
537 cop->co_toku = token;
541 * Validate and extract useful attribute information
562 switch (ap->aal.tag) {
566 switch (ap->aal.type) {
588 * Broadband High Layer Information Attributes
590 switch (ap->bhli.tag) {
603 * Broadband Low Layer Information Attributes
605 switch (ap->blli.tag_l2) {
617 switch (ap->blli.tag_l3) {
630 * Logical Link Control Attributes
632 switch (ap->llc.tag) {
635 if ((ap->blli.tag_l2 != T_ATM_PRESENT) ||
636 (ap->blli.v.layer_2_protocol.ID_type != T_ATM_SIMPLE_ID) ||
637 (ap->blli.v.layer_2_protocol.ID.simple_ID !=
638 T_ATM_BLLI2_I8802) ||
639 (ap->llc.v.llc_len < T_ATM_LLC_MIN_LEN) ||
640 (ap->llc.v.llc_len > T_ATM_LLC_MAX_LEN)) {
644 cop->co_mpx = ATM_ENC_LLC;
645 cop->co_llc = ap->llc;
650 cop->co_mpx = ATM_ENC_NULL;
659 * Called Party Attributes
661 switch (ap->called.tag) {
664 switch (ap->called.addr.address_format) {
667 ap->called.tag = T_ATM_ABSENT;
686 * Get an attribute block and save listening attributes
688 cop->co_lattr = (Atm_attributes *)atm_allocate(&atm_attributes_pool);
689 if (cop->co_lattr == NULL) {
693 *cop->co_lattr = *ap;
696 * Now try to register the listening connection
699 if (atm_cm_match(cop->co_lattr, NULL) != NULL) {
701 * Can't have matching listeners
706 cop->co_state = COS_LISTEN;
707 LINK2TAIL(cop, Atm_connection, atm_listen_queue, co_next);
715 * Undo any partial setup stuff
719 atm_free((caddr_t)cop->co_lattr);
720 atm_free((caddr_t)cop);
724 * Finish connection setup
733 * Add to LLC Connection
735 * Called by an endpoint service to create a new Connection Manager API
736 * instance to be associated with an LLC-multiplexed connection instance
737 * which has been previously created. The endpoint provided token will
738 * be used in all further CM -> endpoint function calls, and the returned
739 * connection block pointer must be used in all subsequent endpoint -> CM
742 * If the return indicates that the connection setup has been immediately
743 * successful, then the connection is ready for data transmission.
745 * If the return indicates that the connection setup is still in progress,
746 * then the endpoint must wait for notification from the Connection Manager
747 * indicating the final status of the call setup. If the call setup completes
748 * successfully, then a "call connected" notification will be sent to the
749 * endpoint by the Connection Manager. If the call setup fails, then the
750 * endpoint will receive a "call cleared" notification.
752 * All connection instances must be freed with an atm_cm_release() call.
755 * epp pointer to endpoint definition structure
756 * token endpoint's connection instance token
757 * llc pointer to llc attributes for new connection
758 * ecop pointer to existing connection block
759 * copp pointer to location to return allocated connection block
762 * 0 connection has been successfully established
763 * EINPROGRESS connection establishment is in progress
764 * errno addllc failed - reason indicated
768 atm_cm_addllc(epp, token, llc, ecop, copp)
771 struct attr_llc *llc;
772 Atm_connection *ecop;
773 Atm_connection **copp;
775 Atm_connection *cop, *cop2;
782 * Check out requested LLC attributes
784 if ((llc->tag != T_ATM_PRESENT) ||
785 ((llc->v.flags & T_ATM_LLC_SHARING) == 0) ||
786 (llc->v.llc_len < T_ATM_LLC_MIN_LEN) ||
787 (llc->v.llc_len > T_ATM_LLC_MAX_LEN))
791 * Get a connection block
793 cop = (Atm_connection *)atm_allocate(&atm_connection_pool);
798 * Initialize connection info
801 cop->co_toku = token;
807 * Ensure that supplied connection is really valid
810 for (cvp = Q_HEAD(atm_connection_queue, Atm_connvc); cvp;
811 cvp = Q_NEXT(cvp, Atm_connvc, cvc_q)) {
812 for (cop2 = cvp->cvc_conn; cop2; cop2 = cop2->co_next) {
824 switch (ecop->co_state) {
841 * Connection must be LLC multiplexed and shared
843 if ((ecop->co_mpx != ATM_ENC_LLC) ||
844 ((ecop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0)) {
850 * This new LLC header must be unique for this VCC
854 int i = MIN(llc->v.llc_len, cop2->co_llc.v.llc_len);
856 if (KM_CMP(llc->v.llc_info, cop2->co_llc.v.llc_info, i) == 0) {
861 cop2 = cop2->co_next;
865 * Everything seems to check out
867 cop->co_flags = ecop->co_flags;
868 cop->co_state = ecop->co_state;
869 cop->co_mpx = ecop->co_mpx;
870 cop->co_connvc = ecop->co_connvc;
872 LINK2TAIL(cop, Atm_connection, ecop->co_mxh, co_next);
873 cop->co_mxh = ecop->co_mxh;
878 if (err && err != EINPROGRESS) {
880 * Undo any partial setup stuff
883 atm_free((caddr_t)cop);
886 * Pass new connection back to caller
898 * cop pointer to connection block
899 * id identifier for party to be added
900 * addr address of party to be added
903 * 0 addparty successful
904 * errno addparty failed - reason indicated
908 atm_cm_addparty(cop, id, addr)
911 struct t_atm_sap *addr;
921 * cop pointer to connection block
922 * id identifier for party to be added
923 * cause pointer to cause of drop
926 * 0 dropparty successful
927 * errno dropparty failed - reason indicated
931 atm_cm_dropparty(cop, id, cause)
934 struct t_atm_cause *cause;
941 * Release Connection Resources
943 * Called by the endpoint service in order to terminate an ATM connection
944 * and to release all system resources for the connection. This function
945 * must be called for every allocated connection instance and must only
946 * be called by the connection's owner.
949 * cop pointer to connection block
950 * cause pointer to cause of release
953 * 0 release successful
954 * errno release failed - reason indicated
958 atm_cm_release(cop, cause)
960 struct t_atm_cause *cause;
968 * First, a quick state validation check
970 switch (cop->co_state) {
988 panic("atm_cm_release: bogus conn state");
992 * Check out the VCC state too
994 if ((cvp = cop->co_connvc) != NULL) {
996 switch (cvp->cvc_state) {
1013 panic("atm_cm_release: bogus connvc state");
1017 * If we're the only connection, terminate the VCC
1019 if ((cop->co_mxh == cop) && (cop->co_next == NULL)) {
1020 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
1021 cvp->cvc_attr.cause.v = *cause;
1022 atm_cm_closevc(cvp);
1027 * Now get rid of the connection
1029 atm_cm_closeconn(cop, cause);
1036 * Abort an ATM Connection VCC
1038 * This function allows any non-owner kernel entity to request an
1039 * immediate termination of an ATM VCC. This will normally be called
1040 * when encountering a catastrophic error condition that cannot be
1041 * resolved via the available stack protocols. The connection manager
1042 * will schedule the connection's termination, including notifying the
1043 * connection owner of the termination.
1045 * This function should only be called by a stack entity instance. After
1046 * calling the function, the caller should set a protocol state which just
1047 * waits for a <sap>_TERM stack command to be delivered.
1050 * cvp pointer to connection VCC block
1051 * cause pointer to cause of abort
1054 * 0 abort successful
1055 * errno abort failed - reason indicated
1059 atm_cm_abort(cvp, cause)
1061 struct t_atm_cause *cause;
1063 ATM_DEBUG2("atm_cm_abort: cvp=%p cause=%d\n",
1064 cvp, cause->cause_value);
1067 * Note that we're aborting
1069 cvp->cvc_flags |= CVCF_ABORTING;
1071 switch (cvp->cvc_state) {
1075 * In-line code will handle this
1077 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
1078 cvp->cvc_attr.cause.v = *cause;
1085 * Schedule connection termination, since we want
1086 * to avoid any sequencing interactions
1088 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
1089 cvp->cvc_attr.cause.v = *cause;
1098 * Ignore abort, as we're already terminating
1104 "atm_cm_abort: invalid state: cvp=%p, state=%d\n",
1105 cvp, cvp->cvc_state);
1112 * Incoming ATM Call Received
1114 * Called by a signalling manager to indicate that a new call request has
1115 * been received. This function will allocate and initialize the connection
1116 * manager control blocks and queue this call request. The call request
1117 * processing function, atm_cm_procinq(), will be scheduled to perform the
1121 * vcp pointer to incoming call's VCC control block
1122 * ap pointer to incoming call's attributes
1125 * 0 call queuing successful
1126 * errno call queuing failed - reason indicated
1130 atm_cm_incoming(vcp, ap)
1139 * Do some minimal attribute validation
1143 * Must specify a network interface
1145 if (ap->nif == NULL)
1151 if ((ap->aal.tag != T_ATM_PRESENT) ||
1152 ((ap->aal.type != ATM_AAL5) &&
1153 (ap->aal.type != ATM_AAL3_4)))
1157 * Traffic Descriptor Attributes
1159 if ((ap->traffic.tag != T_ATM_PRESENT) &&
1160 (ap->traffic.tag != T_ATM_ABSENT))
1164 * Broadband Bearer Attributes
1166 if ((ap->bearer.tag != T_ATM_PRESENT) ||
1167 ((ap->bearer.v.connection_configuration != T_ATM_1_TO_1) &&
1168 (ap->bearer.v.connection_configuration != T_ATM_1_TO_MANY)))
1172 * Broadband High Layer Attributes
1174 if ((ap->bhli.tag != T_ATM_PRESENT) &&
1175 (ap->bhli.tag != T_ATM_ABSENT))
1179 * Broadband Low Layer Attributes
1181 if ((ap->blli.tag_l2 != T_ATM_PRESENT) &&
1182 (ap->blli.tag_l2 != T_ATM_ABSENT))
1184 if ((ap->blli.tag_l3 != T_ATM_PRESENT) &&
1185 (ap->blli.tag_l3 != T_ATM_ABSENT))
1189 * Logical Link Control Attributes
1191 if (ap->llc.tag == T_ATM_PRESENT)
1193 ap->llc.tag = T_ATM_ANY;
1196 * Called Party Attributes
1198 if ((ap->called.tag != T_ATM_PRESENT) ||
1199 (ap->called.addr.address_format == T_ATM_ABSENT))
1201 if (ap->called.tag == T_ATM_ABSENT) {
1202 ap->called.addr.address_format = T_ATM_ABSENT;
1203 ap->called.addr.address_length = 0;
1204 ap->called.subaddr.address_format = T_ATM_ABSENT;
1205 ap->called.subaddr.address_length = 0;
1209 * Calling Party Attributes
1211 if ((ap->calling.tag != T_ATM_PRESENT) &&
1212 (ap->calling.tag != T_ATM_ABSENT))
1214 if (ap->calling.tag == T_ATM_ABSENT) {
1215 ap->calling.addr.address_format = T_ATM_ABSENT;
1216 ap->calling.addr.address_length = 0;
1217 ap->calling.subaddr.address_format = T_ATM_ABSENT;
1218 ap->calling.subaddr.address_length = 0;
1222 * Quality of Service Attributes
1224 if (ap->qos.tag != T_ATM_PRESENT)
1228 * Transit Network Attributes
1230 if ((ap->transit.tag != T_ATM_PRESENT) &&
1231 (ap->transit.tag != T_ATM_ABSENT))
1237 if ((ap->cause.tag != T_ATM_PRESENT) &&
1238 (ap->cause.tag != T_ATM_ABSENT))
1242 * Get a connection VCC block
1244 cvp = (Atm_connvc *)atm_allocate(&atm_connvc_pool);
1251 * Initialize the control block
1254 cvp->cvc_sigmgr = vcp->vc_pif->pif_sigmgr;
1255 cvp->cvc_attr = *ap;
1256 cvp->cvc_state = CVCS_INCOMING;
1259 * Control queue length
1262 if (atm_incoming_qlen >= ATM_CALLQ_MAX) {
1269 * Queue request and schedule call processing function
1271 cvp->cvc_flags |= CVCF_INCOMQ;
1272 ENQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
1273 if (atm_incoming_qlen++ == 0) {
1274 timeout(atm_cm_procinq, (void *)0, 0);
1278 * Link for signalling manager
1280 vcp->vc_connvc = cvp;
1288 * Free any resources
1291 atm_free((caddr_t)cvp);
1297 * VCC Connected Notification
1299 * This function is called by a signalling manager as notification that a
1300 * VCC call setup has been successful.
1303 * cvp pointer to connection VCC block
1310 atm_cm_connected(cvp)
1313 Atm_connection *cop, *cop2;
1320 * Validate connection vcc
1322 switch (cvp->cvc_state) {
1326 * Initialize the stack
1328 cvp->cvc_state = CVCS_INIT;
1329 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].init,
1330 cvp->cvc_lower, cvp->cvc_tokl,
1331 cvp, cvp->cvc_attr.api_init, 0, err);
1333 panic("atm_cm_connected: init");
1335 if (cvp->cvc_flags & CVCF_ABORTING) {
1337 * Someone on the stack bailed out...notify all of the
1338 * connections and schedule the VCC termination
1340 cop = cvp->cvc_conn;
1342 cop2 = cop->co_next;
1343 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
1346 atm_cm_closevc(cvp);
1354 * Stack already initialized
1359 panic("atm_cm_connected: connvc state");
1363 * VCC is ready for action
1365 cvp->cvc_state = CVCS_ACTIVE;
1368 * Notify all connections that the call has completed
1370 cop = cvp->cvc_conn;
1372 cop2 = cop->co_next;
1374 switch (cop->co_state) {
1378 cop->co_state = COS_ACTIVE;
1379 (*cop->co_endpt->ep_connected)(cop->co_toku);
1384 * May get here if an ep_connected() call (from
1385 * above) results in an atm_cm_addllc() call for
1386 * the just connected connection.
1391 panic("atm_cm_connected: connection state");
1400 * Input any queued packets
1402 while ((m = cvp->cvc_rcvq) != NULL) {
1403 cvp->cvc_rcvq = KB_QNEXT(m);
1408 * Currently only supported for CPCS API
1410 atm_cm_cpcs_upper(CPCS_UNITDATA_SIG, cvp, (int)m, 0);
1418 * VCC Cleared Notification
1420 * This function is called by a signalling manager as notification that a
1421 * VCC call has been cleared. The cause information describing the reason
1422 * for the call clearing will be contained in the connection VCC attributes.
1425 * cvp pointer to connection VCC block
1435 Atm_connection *cop, *cop2;
1439 if ((cvp->cvc_state == CVCS_FREE) ||
1440 (cvp->cvc_state >= CVCS_CLEAR))
1441 panic("atm_cm_cleared");
1444 cvp->cvc_state = CVCS_CLEAR;
1449 * Terminate all connections
1451 cop = cvp->cvc_conn;
1453 cop2 = cop->co_next;
1454 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
1459 * Clean up connection VCC
1461 atm_cm_closevc(cvp);
1470 * Process Incoming Call Queue
1472 * This function is scheduled by atm_cm_incoming() in order to process
1473 * all the entries on the incoming call queue.
1476 * arg argument passed on timeout() call
1490 * Only process incoming calls up to our quota
1492 while (cnt++ < ATM_CALLQ_MAX) {
1497 * Get next awaiting call
1499 cvp = Q_HEAD(atm_incoming_queue, Atm_connvc);
1504 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
1505 atm_incoming_qlen--;
1506 cvp->cvc_flags &= ~CVCF_INCOMQ;
1517 * If we've expended our quota, reschedule ourselves
1519 if (cnt >= ATM_CALLQ_MAX)
1520 timeout(atm_cm_procinq, (void *)0, 0);
1525 * Process Incoming Call
1527 * This function will search through the listening queue and try to find
1528 * matching endpoint(s) for the incoming call. If we find any, we will
1529 * notify the endpoint service(s) of the incoming call and will then
1530 * notify the signalling manager to progress the call to an active status.
1532 * If there are no listeners for the call, the signalling manager will be
1533 * notified of a call rejection.
1538 * cvp pointer to connection VCC for incoming call
1548 Atm_connection *cop, *lcop, *hcop;
1549 Atm_attributes attr;
1555 attr = cvp->cvc_attr;
1558 * Look for matching listeners
1560 while ((lcop = atm_cm_match(&attr, lcop)) != NULL) {
1564 * Need a new connection block
1566 cop = (Atm_connection *)
1567 atm_allocate(&atm_connection_pool);
1569 cvp->cvc_attr.cause = atm_cause_tmpl;
1570 cvp->cvc_attr.cause.v.cause_value =
1571 T_ATM_CAUSE_TEMPORARY_FAILURE;
1577 * Initialize connection from listener and incoming call
1580 cop->co_state = COS_INCONN;
1581 cop->co_mpx = lcop->co_mpx;
1582 cop->co_endpt = lcop->co_endpt;
1583 cop->co_llc = lcop->co_llc;
1585 switch (attr.bearer.v.connection_configuration) {
1588 cop->co_flags |= COF_P2P;
1591 case T_ATM_1_TO_MANY:
1593 cop->co_flags |= COF_P2MP;
1594 cvp->cvc_attr.cause = atm_cause_tmpl;
1595 cvp->cvc_attr.cause.v.cause_value =
1596 T_ATM_CAUSE_BEARER_CAPABILITY_NOT_IMPLEMENTED;
1601 * Notify endpoint of incoming call
1603 err = (*cop->co_endpt->ep_incoming)
1604 (lcop->co_toku, cop, &cvp->cvc_attr, &cop->co_toku);
1609 * Endpoint has accepted the call
1611 * Setup call attributes
1614 cvp->cvc_attr.api = lcop->co_lattr->api;
1615 cvp->cvc_attr.api_init =
1616 lcop->co_lattr->api_init;
1617 cvp->cvc_attr.llc = lcop->co_lattr->llc;
1619 cvp->cvc_attr.headin = MAX(cvp->cvc_attr.headin,
1620 lcop->co_lattr->headin);
1623 * Setup connection info and queueing
1625 cop->co_state = COS_INACCEPT;
1626 cop->co_connvc = cvp;
1627 LINK2TAIL(cop, Atm_connection, hcop, co_next);
1631 * Need a new connection block next time around
1637 * Endpoint refuses call
1644 * We're done looking for listeners
1648 * Someone actually wants the call, so notify
1649 * the signalling manager to continue
1651 cvp->cvc_flags |= CVCF_CONNQ;
1652 ENQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
1653 if (atm_cm_accept(cvp, hcop))
1658 * Nobody around to take the call
1660 cvp->cvc_attr.cause = atm_cause_tmpl;
1661 cvp->cvc_attr.cause.v.cause_value =
1662 T_ATM_CAUSE_INCOMPATIBLE_DESTINATION;
1667 * Clean up loose ends
1670 atm_free((caddr_t)cop);
1673 * Call has been accepted
1679 * Call failed - notify any endpoints of the call failure
1683 * Clean up loose ends
1686 atm_free((caddr_t)cop);
1688 if (cvp->cvc_attr.cause.tag != T_ATM_PRESENT) {
1689 cvp->cvc_attr.cause = atm_cause_tmpl;
1690 cvp->cvc_attr.cause.v.cause_value =
1691 T_ATM_CAUSE_UNSPECIFIED_NORMAL;
1695 Atm_connection *cop2 = cop->co_next;
1696 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
1701 * Tell the signalling manager to reject the call
1703 atm_cm_closevc(cvp);
1710 * Accept an Incoming ATM Call
1712 * Some endpoint service(s) wants to accept an incoming call, so the
1713 * signalling manager will be notified to attempt to progress the call
1714 * to an active status.
1716 * If the signalling manager indicates that connection activation has
1717 * been immediately successful, then all of the endpoints will be notified
1718 * that the connection is ready for data transmission.
1720 * If the return indicates that connection activation is still in progress,
1721 * then the endpoints must wait for notification from the Connection Manager
1722 * indicating the final status of the call setup. If the call setup completes
1723 * successfully, then a "call connected" notification will be sent to the
1724 * endpoints by the Connection Manager. If the call setup fails, then the
1725 * endpoints will receive a "call cleared" notification.
1730 * cvp pointer to connection VCC for incoming call
1731 * cop pointer to head of accepted connections
1734 * 0 connection has been successfully activated
1735 * errno accept failed - reason indicated
1739 atm_cm_accept(cvp, cop)
1741 Atm_connection *cop;
1743 struct stack_list sl;
1744 void (*upf)(int, void *, int, int);
1749 * Link vcc to connections
1751 cvp->cvc_conn = cop;
1754 * Initialize stack list index
1759 * Check out Data API
1761 switch (cvp->cvc_attr.api) {
1764 upf = atm_cm_cpcs_upper;
1768 sl.sl_sap[sli++] = SAP_SSCF_UNI;
1769 sl.sl_sap[sli++] = SAP_SSCOP;
1770 upf = atm_cm_saal_upper;
1774 sl.sl_sap[sli++] = SAP_SSCOP;
1775 upf = atm_cm_sscop_upper;
1785 switch (cvp->cvc_attr.aal.type) {
1788 sl.sl_sap[sli++] = SAP_CPCS_AAL5;
1789 sl.sl_sap[sli++] = SAP_SAR_AAL5;
1790 sl.sl_sap[sli++] = SAP_ATM;
1794 sl.sl_sap[sli++] = SAP_CPCS_AAL3_4;
1795 sl.sl_sap[sli++] = SAP_SAR_AAL3_4;
1796 sl.sl_sap[sli++] = SAP_ATM;
1801 * Terminate stack list
1806 * Create a service stack
1808 err = atm_create_stack(cvp, &sl, upf);
1814 * Let the signalling manager finish the VCC activation
1816 switch ((*cvp->cvc_sigmgr->sm_accept)(cvp->cvc_vcc, &err)) {
1818 case CALL_PROCEEDING:
1820 * Note that we're not finished yet
1825 case CALL_CONNECTED:
1827 * Initialize the stack now, even if the call isn't totally
1828 * active yet. We want to avoid the delay between getting
1829 * the "call connected" event and actually notifying the
1830 * adapter to accept cells on the new VCC - if the delay is
1831 * too long, then we end up dropping the first pdus sent by
1834 cvp->cvc_state = CVCS_INIT;
1835 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].init,
1836 cvp->cvc_lower, cvp->cvc_tokl, cvp,
1837 cvp->cvc_attr.api_init, 0, err2);
1839 panic("atm_cm_accept: init");
1841 if (cvp->cvc_flags & CVCF_ABORTING) {
1843 * Someone on the stack bailed out...schedule the
1844 * VCC and stack termination
1849 * Everything looks fine from here
1852 cvp->cvc_state = CVCS_ACCEPT;
1854 cvp->cvc_state = CVCS_ACTIVE;
1860 * Terminate stack and clean up before we leave
1862 cvp->cvc_state = CVCS_CLEAR;
1866 panic("atm_cm_accept: accept");
1872 * Call has been connected, notify endpoints
1875 Atm_connection *cop2 = cop->co_next;
1877 cop->co_state = COS_ACTIVE;
1878 (*cop->co_endpt->ep_connected)(cop->co_toku);
1882 } else if (err == EINPROGRESS) {
1884 * Call is still in progress, endpoint must wait
1890 * Let caller know we failed
1892 cvp->cvc_attr.cause = atm_cause_tmpl;
1893 cvp->cvc_attr.cause.v.cause_value =
1894 T_ATM_CAUSE_UNSPECIFIED_RESOURCE_UNAVAILABLE;
1902 * Match Attributes on Listening Queue
1904 * This function will attempt to match the supplied connection attributes
1905 * with one of the registered attributes in the listening queue. The pcop
1906 * argument may be supplied in order to allow multiple listeners to share
1907 * an incoming call (if supported by the listeners).
1912 * ap pointer to attributes to be matched
1913 * pcop pointer to the previously matched connection
1916 * addr connection with which a match was found
1921 atm_cm_match(ap, pcop)
1923 Atm_connection *pcop;
1925 Atm_connection *cop;
1926 Atm_attributes *lap;
1930 * If we've already matched a listener...
1934 * Make sure already matched listener supports sharing
1936 if ((pcop->co_mpx != ATM_ENC_LLC) ||
1937 ((pcop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0))
1941 * Position ourselves after the matched entry
1943 for (cop = atm_listen_queue; cop; cop = cop->co_next) {
1945 cop = pcop->co_next;
1951 * Start search at top of listening queue
1953 cop = atm_listen_queue;
1957 * Search through listening queue
1959 for (; cop; cop = cop->co_next) {
1961 lap = cop->co_lattr;
1964 * If we're trying to share, check that this entry allows it
1967 if ((cop->co_mpx != ATM_ENC_LLC) ||
1968 ((cop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0))
1973 * ALL "matchable" attributes must match
1979 if (lap->bhli.tag == T_ATM_ABSENT) {
1980 if (ap->bhli.tag == T_ATM_PRESENT)
1982 } else if (lap->bhli.tag == T_ATM_PRESENT) {
1983 if (ap->bhli.tag == T_ATM_ABSENT)
1985 if (ap->bhli.tag == T_ATM_PRESENT)
1986 if (KM_CMP(&lap->bhli.v, &ap->bhli.v,
1987 sizeof(struct t_atm_bhli)))
1994 if (lap->blli.tag_l2 == T_ATM_ABSENT) {
1995 if (ap->blli.tag_l2 == T_ATM_PRESENT)
1997 } else if (lap->blli.tag_l2 == T_ATM_PRESENT) {
1998 if (ap->blli.tag_l2 == T_ATM_ABSENT)
2000 if (ap->blli.tag_l2 == T_ATM_PRESENT) {
2001 if (KM_CMP(&lap->blli.v.layer_2_protocol.ID,
2002 &ap->blli.v.layer_2_protocol.ID,
2004 ap->blli.v.layer_2_protocol.ID)))
2012 if (lap->blli.tag_l3 == T_ATM_ABSENT) {
2013 if (ap->blli.tag_l3 == T_ATM_PRESENT)
2015 } else if (lap->blli.tag_l3 == T_ATM_PRESENT) {
2016 if (ap->blli.tag_l3 == T_ATM_ABSENT)
2018 if (ap->blli.tag_l3 == T_ATM_PRESENT) {
2019 if (KM_CMP(&lap->blli.v.layer_3_protocol.ID,
2020 &ap->blli.v.layer_3_protocol.ID,
2022 ap->blli.v.layer_3_protocol.ID)))
2030 if (lap->llc.tag == T_ATM_ABSENT) {
2031 if (ap->llc.tag == T_ATM_PRESENT)
2033 } else if (lap->llc.tag == T_ATM_PRESENT) {
2034 if (ap->llc.tag == T_ATM_ABSENT)
2036 if (ap->llc.tag == T_ATM_PRESENT) {
2037 int i = MIN(lap->llc.v.llc_len,
2040 if (KM_CMP(lap->llc.v.llc_info,
2041 ap->llc.v.llc_info, i))
2049 if (lap->aal.tag == T_ATM_ABSENT) {
2050 if (ap->aal.tag == T_ATM_PRESENT)
2052 } else if (lap->aal.tag == T_ATM_PRESENT) {
2053 if (ap->aal.tag == T_ATM_ABSENT)
2055 if (ap->aal.tag == T_ATM_PRESENT) {
2056 if (lap->aal.type != ap->aal.type)
2058 if (lap->aal.type == ATM_AAL5) {
2059 if (lap->aal.v.aal5.SSCS_type !=
2060 ap->aal.v.aal5.SSCS_type)
2063 if (lap->aal.v.aal4.SSCS_type !=
2064 ap->aal.v.aal4.SSCS_type)
2073 if (lap->called.tag == T_ATM_ABSENT) {
2074 if (ap->called.tag == T_ATM_PRESENT)
2076 } else if (lap->called.tag == T_ATM_PRESENT) {
2077 if (ap->called.tag == T_ATM_ABSENT)
2079 if (ap->called.tag == T_ATM_PRESENT) {
2080 if ((!ATM_ADDR_EQUAL(&lap->called.addr,
2081 &ap->called.addr)) ||
2082 (!ATM_ADDR_EQUAL(&lap->called.subaddr,
2083 &ap->called.subaddr)))
2089 * Found a full match - return it
2099 * Find Shareable LLC VCC
2101 * Given a endpoint-supplied connection attribute using LLC multiplexing,
2102 * this function will attempt to locate an existing connection which meets
2103 * the requirements of the supplied attributes.
2108 * ap pointer to requested attributes
2111 * addr shareable LLC connection VCC
2112 * 0 no shareable VCC available
2116 atm_cm_share_llc(ap)
2119 Atm_connection *cop;
2123 * Is requestor willing to share?
2125 if ((ap->llc.v.flags & T_ATM_LLC_SHARING) == 0)
2129 * Try to find a shareable connection
2131 for (cvp = Q_HEAD(atm_connection_queue, Atm_connvc); cvp;
2132 cvp = Q_NEXT(cvp, Atm_connvc, cvc_q)) {
2135 * Dont use terminating connections
2137 switch (cvp->cvc_state) {
2149 * Is connection LLC and shareable?
2151 if ((cvp->cvc_attr.llc.tag != T_ATM_PRESENT) ||
2152 ((cvp->cvc_attr.llc.v.flags & T_ATM_LLC_SHARING) == 0))
2156 * Match requested attributes with existing connection
2158 if (ap->nif != cvp->cvc_attr.nif)
2161 if ((ap->api != cvp->cvc_attr.api) ||
2162 (ap->api_init != cvp->cvc_attr.api_init))
2168 if (cvp->cvc_flags & CVCF_CALLER) {
2169 if ((!ATM_ADDR_EQUAL(&ap->called.addr,
2170 &cvp->cvc_attr.called.addr)) ||
2171 (!ATM_ADDR_EQUAL(&ap->called.subaddr,
2172 &cvp->cvc_attr.called.subaddr)))
2175 if (cvp->cvc_attr.calling.tag != T_ATM_PRESENT)
2177 if ((!ATM_ADDR_EQUAL(&ap->called.addr,
2178 &cvp->cvc_attr.calling.addr)) ||
2179 (!ATM_ADDR_EQUAL(&ap->called.subaddr,
2180 &cvp->cvc_attr.calling.subaddr)))
2187 if (ap->aal.type == ATM_AAL5) {
2188 struct t_atm_aal5 *ap5, *cv5;
2190 ap5 = &ap->aal.v.aal5;
2191 cv5 = &cvp->cvc_attr.aal.v.aal5;
2193 if ((cvp->cvc_attr.aal.type != ATM_AAL5) ||
2194 (ap5->SSCS_type != cv5->SSCS_type))
2197 if (cvp->cvc_flags & CVCF_CALLER) {
2198 if (ap5->forward_max_SDU_size >
2199 cv5->forward_max_SDU_size)
2202 if (ap5->forward_max_SDU_size >
2203 cv5->backward_max_SDU_size)
2207 struct t_atm_aal4 *ap4, *cv4;
2209 ap4 = &ap->aal.v.aal4;
2210 cv4 = &cvp->cvc_attr.aal.v.aal4;
2212 if ((cvp->cvc_attr.aal.type != ATM_AAL3_4) ||
2213 (ap4->SSCS_type != cv4->SSCS_type))
2216 if (cvp->cvc_flags & CVCF_CALLER) {
2217 if (ap4->forward_max_SDU_size >
2218 cv4->forward_max_SDU_size)
2221 if (ap4->forward_max_SDU_size >
2222 cv4->backward_max_SDU_size)
2228 * Traffic Descriptor
2230 if ((ap->traffic.tag != T_ATM_PRESENT) ||
2231 (cvp->cvc_attr.traffic.tag != T_ATM_PRESENT) ||
2232 (ap->traffic.v.best_effort != T_YES) ||
2233 (cvp->cvc_attr.traffic.v.best_effort != T_YES))
2239 if (ap->bearer.v.connection_configuration !=
2240 cvp->cvc_attr.bearer.v.connection_configuration)
2246 if (cvp->cvc_flags & CVCF_CALLER) {
2247 if ((ap->qos.v.forward.qos_class !=
2248 cvp->cvc_attr.qos.v.forward.qos_class) ||
2249 (ap->qos.v.backward.qos_class !=
2250 cvp->cvc_attr.qos.v.backward.qos_class))
2253 if ((ap->qos.v.forward.qos_class !=
2254 cvp->cvc_attr.qos.v.backward.qos_class) ||
2255 (ap->qos.v.backward.qos_class !=
2256 cvp->cvc_attr.qos.v.forward.qos_class))
2261 * The new LLC header must also be unique for this VCC
2263 for (cop = cvp->cvc_conn; cop; cop = cop->co_next) {
2264 int i = MIN(ap->llc.v.llc_len,
2265 cop->co_llc.v.llc_len);
2267 if (KM_CMP(ap->llc.v.llc_info,
2268 cop->co_llc.v.llc_info, i) == 0)
2273 * If no header overlaps, then we're done
2286 * This function will terminate a connection, including notifying the
2287 * user, if necessary, and freeing up control block memory. The caller
2288 * is responsible for managing the connection VCC.
2293 * cop pointer to connection block
2294 * cause pointer to cause of close
2301 atm_cm_closeconn(cop, cause)
2302 Atm_connection *cop;
2303 struct t_atm_cause *cause;
2307 * Decide whether user needs notification
2309 switch (cop->co_state) {
2317 * Yup, let 'em know connection is gone
2320 (*cop->co_endpt->ep_cleared)(cop->co_toku, cause);
2325 * Nope,they should know already
2330 panic("atm_cm_closeconn: bogus state");
2334 * Unlink connection from its queues
2336 switch (cop->co_state) {
2339 atm_free((caddr_t)cop->co_lattr);
2340 UNLINK(cop, Atm_connection, atm_listen_queue, co_next);
2345 * Remove connection from multiplexor queue
2347 if (cop->co_mxh != cop) {
2349 * Connection is down the chain, just unlink it
2351 UNLINK(cop, Atm_connection, cop->co_mxh, co_next);
2353 } else if (cop->co_next != NULL) {
2355 * Connection is at the head of a non-singleton chain,
2356 * so unlink and reset the chain head
2358 Atm_connection *t, *nhd;
2360 t = nhd = cop->co_next;
2366 nhd->co_connvc->cvc_conn = nhd;
2371 * Free the connection block
2373 cop->co_state = COS_FREE;
2374 atm_free((caddr_t)cop);
2381 * Close Connection VCC
2383 * This function will terminate a connection VCC, including releasing the
2384 * the call to the signalling manager, terminating the VCC protocol stack,
2385 * and freeing up control block memory.
2390 * cvp pointer to connection VCC block
2403 * Break links with the connection block
2405 cvp->cvc_conn = NULL;
2408 * Cancel any running timer
2413 * Free queued packets
2415 while (cvp->cvc_rcvq) {
2419 cvp->cvc_rcvq = KB_QNEXT(m);
2425 * Unlink from any queues
2427 if (cvp->cvc_flags & CVCF_INCOMQ) {
2428 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
2429 atm_incoming_qlen--;
2430 cvp->cvc_flags &= ~CVCF_INCOMQ;
2432 } else if (cvp->cvc_flags & CVCF_CONNQ) {
2433 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
2434 cvp->cvc_flags &= ~CVCF_CONNQ;
2438 * Release the signalling call
2440 switch (cvp->cvc_state) {
2448 cvp->cvc_state = CVCS_RELEASE;
2449 switch ((*cvp->cvc_sigmgr->sm_release)
2450 (cvp->cvc_vcc, &err)) {
2454 * Looks good so far...
2458 case CALL_PROCEEDING:
2460 * We'll have to wait for the call to clear
2466 * If there's a memory shortage, retry later.
2467 * Otherwise who knows what's going on....
2469 if ((err == ENOMEM) || (err == ENOBUFS)) {
2470 CVC_TIMER(cvp, 1 * ATM_HZ);
2474 "atm_cm_closevc: release %d\n", err);
2483 cvp->cvc_state = CVCS_REJECT;
2484 switch ((*cvp->cvc_sigmgr->sm_reject)
2485 (cvp->cvc_vcc, &err)) {
2489 * Looks good so far...
2495 * If there's a memory shortage, retry later.
2496 * Otherwise who knows what's going on....
2498 if ((err == ENOMEM) || (err == ENOBUFS)) {
2499 CVC_TIMER(cvp, 1 * ATM_HZ);
2503 "atm_cm_closevc: reject %d\n", err);
2512 * No need for anything here
2517 panic("atm_cm_closevc: bogus state");
2521 * Now terminate the stack
2523 if (cvp->cvc_tokl) {
2524 cvp->cvc_state = CVCS_TERM;
2527 * Wait until stack is unwound before terminating
2529 if ((cvp->cvc_downcnt > 0) || (cvp->cvc_upcnt > 0)) {
2534 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].term,
2535 cvp->cvc_lower, cvp->cvc_tokl, cvp, 0, 0, err);
2537 cvp->cvc_tokl = NULL;
2541 * Let signalling manager finish up
2543 cvp->cvc_state = CVCS_FREE;
2545 (void) (*cvp->cvc_sigmgr->sm_free)(cvp->cvc_vcc);
2549 * Finally, free our own control blocks
2551 atm_free((caddr_t)cvp);
2558 * Process a Connection VCC timeout
2560 * Called when a previously scheduled cvc control block timer expires.
2561 * Processing will be based on the current cvc state.
2566 * tip pointer to cvc timer control block
2574 struct atm_time *tip;
2576 Atm_connection *cop, *cop2;
2580 * Back-off to cvc control block
2582 cvp = (Atm_connvc *)
2583 ((caddr_t)tip - (int)(&((Atm_connvc *)0)->cvc_time));
2586 * Process timeout based on protocol state
2588 switch (cvp->cvc_state) {
2596 if ((cvp->cvc_flags & CVCF_ABORTING) == 0)
2600 * Terminate all connections
2602 cop = cvp->cvc_conn;
2604 cop2 = cop->co_next;
2605 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
2612 atm_cm_closevc(cvp);
2620 * Retry failed operation
2622 atm_cm_closevc(cvp);
2628 "atm_cm_timeout: invalid state: cvp=%p, state=%d\n",
2629 cvp, cvp->cvc_state);
2635 * CPCS User Control Commands
2637 * This function is called by an endpoint user to pass a control command
2638 * across a CPCS data API. Mostly we just send these down the stack.
2641 * cmd stack command code
2642 * cop pointer to connection block
2646 * 0 command output successful
2647 * errno output failed - reason indicated
2651 atm_cm_cpcs_ctl(cmd, cop, arg)
2653 Atm_connection *cop;
2660 * Validate connection state
2662 if (cop->co_state != COS_ACTIVE) {
2667 cvp = cop->co_connvc;
2668 if (cvp->cvc_state != CVCS_ACTIVE) {
2673 if (cvp->cvc_attr.api != CMAPI_CPCS) {
2692 * This function is called by an endpoint user to output a data packet
2693 * across a CPCS data API. After we've validated the connection state, the
2694 * packet will be encapsulated (if necessary) and sent down the data stack.
2697 * cop pointer to connection block
2698 * m pointer to packet buffer chain to be output
2701 * 0 packet output successful
2702 * errno output failed - reason indicated
2706 atm_cm_cpcs_data(cop, m)
2707 Atm_connection *cop;
2711 struct attr_llc *llcp;
2717 * Validate connection state
2719 if (cop->co_state != COS_ACTIVE) {
2724 cvp = cop->co_connvc;
2725 if (cvp->cvc_state != CVCS_ACTIVE) {
2730 if (cvp->cvc_attr.api != CMAPI_CPCS) {
2736 * Add any packet encapsulation
2738 switch (cop->co_mpx) {
2748 * Need to add an LLC header
2750 llcp = &cop->co_llc;
2753 * See if there's room to add LLC header to front of packet.
2755 KB_HEADROOM(m, space);
2756 if (space < llcp->v.llc_len) {
2760 * We have to allocate another buffer and tack it
2761 * onto the front of the packet
2763 KB_ALLOCPKT(n, llcp->v.llc_len, KB_F_NOWAIT,
2769 KB_TAILALIGN(n, llcp->v.llc_len);
2774 * Header fits, just adjust buffer controls
2776 KB_HEADADJ(m, llcp->v.llc_len);
2780 * Add the LLC header
2782 KB_DATASTART(m, bp, void *);
2783 KM_COPY(llcp->v.llc_info, bp, llcp->v.llc_len);
2784 KB_PLENADJ(m, llcp->v.llc_len);
2788 panic("atm_cm_cpcs_data: mpx");
2792 * Finally, we can send the packet on its way
2794 STACK_CALL(CPCS_UNITDATA_INV, cvp->cvc_lower, cvp->cvc_tokl,
2795 cvp, (int)m, 0, err);
2803 * Process CPCS Stack Commands
2805 * This is the top of the CPCS API data stack. All upward stack commands
2806 * for the CPCS data API will be received and processed here.
2809 * cmd stack command code
2810 * tok session token (pointer to connection VCC control block)
2819 atm_cm_cpcs_upper(cmd, tok, arg1, arg2)
2825 Atm_connection *cop;
2826 Atm_connvc *cvp = tok;
2833 case CPCS_UNITDATA_SIG:
2837 m = (KBuffer *)arg1;
2839 if (cvp->cvc_state != CVCS_ACTIVE) {
2840 if (cvp->cvc_state == CVCS_ACCEPT) {
2844 * Queue up any packets received before sigmgr
2845 * notifies us of incoming call completion
2847 if (cvp->cvc_rcvqlen >= CVC_RCVQ_MAX) {
2849 atm_cm_stat.cms_rcvconnvc++;
2853 if (cvp->cvc_rcvq == NULL) {
2856 for (n = cvp->cvc_rcvq;
2857 KB_QNEXT(n) != NULL;
2866 atm_cm_stat.cms_rcvconnvc++;
2872 * Locate packet's connection
2874 cop = cvp->cvc_conn;
2875 switch (cop->co_mpx) {
2879 * We're already there...
2885 * Find connection with matching LLC header
2887 if (KB_LEN(m) < T_ATM_LLC_MAX_LEN) {
2888 KB_PULLUP(m, T_ATM_LLC_MAX_LEN, m);
2890 atm_cm_stat.cms_llcdrop++;
2894 KB_DATASTART(m, bp, void *);
2899 if (KM_CMP(bp, cop->co_llc.v.llc_info,
2900 cop->co_llc.v.llc_len) == 0)
2909 * No connected user for this LLC
2912 atm_cm_stat.cms_llcid++;
2917 * Strip off the LLC header
2919 KB_HEADADJ(m, -cop->co_llc.v.llc_len);
2920 KB_PLENADJ(m, -cop->co_llc.v.llc_len);
2924 panic("atm_cm_cpcs_upper: mpx");
2928 * We've found our connection, so hand the packet off
2930 if (cop->co_state != COS_ACTIVE) {
2932 atm_cm_stat.cms_rcvconn++;
2935 (*cop->co_endpt->ep_cpcs_data)(cop->co_toku, m);
2938 case CPCS_UABORT_SIG:
2939 case CPCS_PABORT_SIG:
2941 * We don't support these (yet), so just fall thru...
2945 log(LOG_ERR, "atm_cm_cpcs_upper: unknown cmd 0x%x\n", cmd);
2951 * SAAL User Control Commands
2953 * This function is called by an endpoint user to pass a control command
2954 * across a SAAL data API. Mostly we just send these down the stack.
2957 * cmd stack command code
2958 * cop pointer to connection block
2962 * 0 command output successful
2963 * errno output failed - reason indicated
2967 atm_cm_saal_ctl(cmd, cop, arg)
2969 Atm_connection *cop;
2976 * Validate connection state
2978 if (cop->co_state != COS_ACTIVE) {
2983 cvp = cop->co_connvc;
2984 if (cvp->cvc_state != CVCS_ACTIVE) {
2989 if (cvp->cvc_attr.api != CMAPI_SAAL) {
2996 case SSCF_UNI_ESTABLISH_REQ:
2997 case SSCF_UNI_RELEASE_REQ:
2999 * Pass command down the stack
3001 STACK_CALL(cmd, cvp->cvc_lower, cvp->cvc_tokl, cvp,
3017 * This function is called by an endpoint user to output a data packet
3018 * across a SAAL data API. After we've validated the connection state,
3019 * the packet will be sent down the data stack.
3022 * cop pointer to connection block
3023 * m pointer to packet buffer chain to be output
3026 * 0 packet output successful
3027 * errno output failed - reason indicated
3031 atm_cm_saal_data(cop, m)
3032 Atm_connection *cop;
3040 * Validate connection state
3042 if (cop->co_state != COS_ACTIVE) {
3047 cvp = cop->co_connvc;
3048 if (cvp->cvc_state != CVCS_ACTIVE) {
3053 if (cvp->cvc_attr.api != CMAPI_SAAL) {
3059 * Finally, we can send the packet on its way
3061 STACK_CALL(SSCF_UNI_DATA_REQ, cvp->cvc_lower, cvp->cvc_tokl,
3062 cvp, (int)m, 0, err);
3070 * Process SAAL Stack Commands
3072 * This is the top of the SAAL API data stack. All upward stack commands
3073 * for the SAAL data API will be received and processed here.
3076 * cmd stack command code
3077 * tok session token (pointer to connection VCC control block)
3086 atm_cm_saal_upper(cmd, tok, arg1, arg2)
3092 Atm_connection *cop;
3093 Atm_connvc *cvp = tok;
3098 case SSCF_UNI_ESTABLISH_IND:
3099 case SSCF_UNI_ESTABLISH_CNF:
3100 case SSCF_UNI_RELEASE_IND:
3101 case SSCF_UNI_RELEASE_CNF:
3105 cop = cvp->cvc_conn;
3106 if (cvp->cvc_state != CVCS_ACTIVE)
3108 if (cop->co_state != COS_ACTIVE)
3111 (*cop->co_endpt->ep_saal_ctl)(cmd, cop->co_toku, (void *)arg1);
3114 case SSCF_UNI_DATA_IND:
3118 cop = cvp->cvc_conn;
3119 if (cvp->cvc_state != CVCS_ACTIVE) {
3120 atm_cm_stat.cms_rcvconnvc++;
3121 KB_FREEALL((KBuffer *)arg1);
3124 if (cop->co_state != COS_ACTIVE) {
3125 atm_cm_stat.cms_rcvconn++;
3126 KB_FREEALL((KBuffer *)arg1);
3130 (*cop->co_endpt->ep_saal_data)(cop->co_toku, (KBuffer *)arg1);
3133 case SSCF_UNI_UNITDATA_IND:
3137 KB_FREEALL((KBuffer *)arg1);
3142 log(LOG_ERR, "atm_cm_saal_upper: unknown cmd 0x%x\n", cmd);
3148 * SSCOP User Control Commands
3150 * This function is called by an endpoint user to pass a control command
3151 * across a SSCOP data API. Mostly we just send these down the stack.
3154 * cmd stack command code
3155 * cop pointer to connection block
3160 * 0 command output successful
3161 * errno output failed - reason indicated
3165 atm_cm_sscop_ctl(cmd, cop, arg1, arg2)
3167 Atm_connection *cop;
3175 * Validate connection state
3177 if (cop->co_state != COS_ACTIVE) {
3182 cvp = cop->co_connvc;
3183 if (cvp->cvc_state != CVCS_ACTIVE) {
3188 if (cvp->cvc_attr.api != CMAPI_SSCOP) {
3195 case SSCOP_ESTABLISH_REQ:
3196 case SSCOP_ESTABLISH_RSP:
3197 case SSCOP_RELEASE_REQ:
3198 case SSCOP_RESYNC_REQ:
3199 case SSCOP_RESYNC_RSP:
3200 case SSCOP_RECOVER_RSP:
3201 case SSCOP_RETRIEVE_REQ:
3203 * Pass command down the stack
3205 STACK_CALL(cmd, cvp->cvc_lower, cvp->cvc_tokl, cvp,
3206 (int)arg1, (int)arg2, err);
3221 * This function is called by an endpoint user to output a data packet
3222 * across a SSCOP data API. After we've validated the connection state,
3223 * the packet will be encapsulated and sent down the data stack.
3226 * cop pointer to connection block
3227 * m pointer to packet buffer chain to be output
3230 * 0 packet output successful
3231 * errno output failed - reason indicated
3235 atm_cm_sscop_data(cop, m)
3236 Atm_connection *cop;
3244 * Validate connection state
3246 if (cop->co_state != COS_ACTIVE) {
3251 cvp = cop->co_connvc;
3252 if (cvp->cvc_state != CVCS_ACTIVE) {
3257 if (cvp->cvc_attr.api != CMAPI_SSCOP) {
3263 * Finally, we can send the packet on its way
3265 STACK_CALL(SSCOP_DATA_REQ, cvp->cvc_lower, cvp->cvc_tokl,
3266 cvp, (int)m, 0, err);
3274 * Process SSCOP Stack Commands
3276 * This is the top of the SSCOP API data stack. All upward stack commands
3277 * for the SSCOP data API will be received and processed here.
3280 * cmd stack command code
3281 * tok session token (pointer to connection VCC control block)
3290 atm_cm_sscop_upper(cmd, tok, arg1, arg2)
3296 Atm_connection *cop;
3297 Atm_connvc *cvp = tok;
3301 case SSCOP_ESTABLISH_IND:
3302 case SSCOP_ESTABLISH_CNF:
3303 case SSCOP_RELEASE_IND:
3304 case SSCOP_RESYNC_IND:
3308 cop = cvp->cvc_conn;
3309 if ((cvp->cvc_state != CVCS_ACTIVE) ||
3310 (cop->co_state != COS_ACTIVE)) {
3311 KB_FREEALL((KBuffer *)arg1);
3315 (*cop->co_endpt->ep_sscop_ctl)
3316 (cmd, cop->co_toku, (void *)arg1, (void *)arg2);
3319 case SSCOP_RELEASE_CNF:
3320 case SSCOP_RESYNC_CNF:
3321 case SSCOP_RECOVER_IND:
3322 case SSCOP_RETRIEVE_IND:
3323 case SSCOP_RETRIEVECMP_IND:
3327 cop = cvp->cvc_conn;
3328 if ((cvp->cvc_state != CVCS_ACTIVE) ||
3329 (cop->co_state != COS_ACTIVE))
3332 (*cop->co_endpt->ep_sscop_ctl)
3333 (cmd, cop->co_toku, (void *)arg1, (void *)arg2);
3336 case SSCOP_DATA_IND:
3340 cop = cvp->cvc_conn;
3341 if (cvp->cvc_state != CVCS_ACTIVE) {
3342 atm_cm_stat.cms_rcvconnvc++;
3343 KB_FREEALL((KBuffer *)arg1);
3346 if (cop->co_state != COS_ACTIVE) {
3347 atm_cm_stat.cms_rcvconn++;
3348 KB_FREEALL((KBuffer *)arg1);
3352 (*cop->co_endpt->ep_sscop_data)
3353 (cop->co_toku, (KBuffer *)arg1, arg2);
3356 case SSCOP_UNITDATA_IND:
3360 KB_FREEALL((KBuffer *)arg1);
3365 log(LOG_ERR, "atm_cm_sscop_upper: unknown cmd 0x%x\n", cmd);
3371 * Register an ATM Endpoint Service
3373 * Every ATM endpoint service must register itself here before it can
3374 * issue or receive any connection requests.
3377 * epp pointer to endpoint definition structure
3380 * 0 registration successful
3381 * errno registration failed - reason indicated
3385 atm_endpoint_register(epp)
3391 * See if we need to be initialized
3399 if (epp->ep_id > ENDPT_MAX) {
3403 if (atm_endpoints[epp->ep_id] != NULL) {
3409 * Add endpoint to list
3411 atm_endpoints[epp->ep_id] = epp;
3419 * De-register an ATM Endpoint Service
3421 * Each ATM endpoint service provider must de-register its registered
3422 * endpoint(s) before terminating. Specifically, loaded kernel modules
3423 * must de-register their services before unloading themselves.
3426 * epp pointer to endpoint definition structure
3429 * 0 de-registration successful
3430 * errno de-registration failed - reason indicated
3434 atm_endpoint_deregister(epp)
3442 if (epp->ep_id > ENDPT_MAX) {
3446 if (atm_endpoints[epp->ep_id] != epp) {
3452 * Remove endpoint from list
3454 atm_endpoints[epp->ep_id] = NULL;