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.6 2005/06/02 22:37:45 dillon Exp $
34 * ATM Connection Manager
38 #include "kern_include.h"
39 #include <sys/kernel.h>
44 struct atm_cm_stat atm_cm_stat = {0};
45 struct callout atm_cm_procinq_ch;
47 SYSINIT(atm_cm, SI_SUB_DRIVERS, SI_ORDER_ANY, callout_init, &atm_cm_procinq_ch);
52 static void atm_cm_cpcs_upper (int, void *, int, int);
53 static void atm_cm_saal_upper (int, void *, int, int);
54 static void atm_cm_sscop_upper (int, void *, int, int);
55 static Atm_connvc * atm_cm_share_llc (Atm_attributes *);
56 static void atm_cm_closeconn (Atm_connection *,
57 struct t_atm_cause *);
58 static void atm_cm_closevc (Atm_connvc *);
59 static void atm_cm_timeout (struct atm_time *);
60 static KTimeout_ret atm_cm_procinq (void *);
61 static void atm_cm_incall (Atm_connvc *);
62 static int atm_cm_accept (Atm_connvc *, Atm_connection *);
67 static Queue_t atm_connection_queue = {NULL};
68 static Queue_t atm_incoming_queue = {NULL};
69 static int atm_incoming_qlen = 0;
70 static Atm_connection *atm_listen_queue = NULL;
71 static struct attr_cause atm_cause_tmpl =
72 {T_ATM_PRESENT, {T_ATM_ITU_CODING, T_ATM_LOC_USER, 0, {0, 0, 0, 0}}};
75 * Stack commands, indexed by API
81 {CPCS_INIT, CPCS_TERM}, /* CMAPI_CPCS */
82 {SSCF_UNI_INIT, SSCF_UNI_TERM}, /* CMAPI_SAAL */
83 {SSCOP_INIT, SSCOP_TERM}, /* CMAPI_SSCOP */
87 static struct sp_info atm_connection_pool = {
88 "atm connection pool", /* si_name */
89 sizeof(Atm_connection), /* si_blksiz */
93 static struct sp_info atm_connvc_pool = {
94 "atm connection vcc pool", /* si_name */
95 sizeof(Atm_connvc), /* si_blksiz */
102 * Initiate Outgoing ATM Call
104 * Called by an endpoint service to create a new Connection Manager API
105 * instance and to initiate an outbound ATM connection. The endpoint
106 * provided token will be used in all further CM -> endpoint function
107 * calls, and the returned connection block pointer must be used in all
108 * subsequent endpoint -> CM function calls.
110 * If the return indicates that the connection setup has been immediately
111 * successful (typically only for PVCs and shared SVCs), then the connection
112 * is ready for data transmission.
114 * If the return indicates that the connection setup is still in progress,
115 * then the endpoint must wait for notification from the Connection Manager
116 * indicating the final status of the call setup. If the call setup completes
117 * successfully, then a "call connected" notification will be sent to the
118 * endpoint by the Connection Manager. If the call setup fails, then the
119 * endpoint will receive a "call cleared" notification.
121 * All connection instances must be freed with an atm_cm_release() call.
124 * epp pointer to endpoint definition structure
125 * token endpoint's connection instance token
126 * ap pointer to requested connection attributes
127 * copp pointer to location to return allocated connection block
130 * 0 connection has been successfully established
131 * EINPROGRESS connection establishment is in progress
132 * errno connection failed - reason indicated
136 atm_cm_connect(epp, token, ap, copp)
140 Atm_connection **copp;
146 struct stack_list sl;
147 void (*upf)(int, void *, int, int);
154 * Get a connection block
156 cop = (Atm_connection *)atm_allocate(&atm_connection_pool);
161 * Initialize connection info
164 cop->co_toku = token;
167 * Initialize stack list index
172 * Validate and extract useful attribute information
176 * Must specify a network interface (validated below)
178 if (ap->nif == NULL) {
189 upf = atm_cm_cpcs_upper;
193 sl.sl_sap[sli++] = SAP_SSCF_UNI;
194 sl.sl_sap[sli++] = SAP_SSCOP;
195 upf = atm_cm_saal_upper;
199 sl.sl_sap[sli++] = SAP_SSCOP;
200 upf = atm_cm_sscop_upper;
211 if (ap->aal.tag != T_ATM_PRESENT) {
216 switch (ap->aal.type) {
219 sl.sl_sap[sli++] = SAP_CPCS_AAL5;
220 sl.sl_sap[sli++] = SAP_SAR_AAL5;
221 sl.sl_sap[sli++] = SAP_ATM;
225 sl.sl_sap[sli++] = SAP_CPCS_AAL3_4;
226 sl.sl_sap[sli++] = SAP_SAR_AAL3_4;
227 sl.sl_sap[sli++] = SAP_ATM;
236 * Broadband Bearer Attributes
238 if (ap->bearer.tag != T_ATM_PRESENT) {
243 switch (ap->bearer.v.connection_configuration) {
246 cop->co_flags |= COF_P2P;
249 case T_ATM_1_TO_MANY:
251 cop->co_flags |= COF_P2MP;
261 * Logical Link Control Attributes
263 if (ap->llc.tag == T_ATM_PRESENT) {
264 if ((ap->blli.tag_l2 != T_ATM_PRESENT) ||
265 (ap->blli.v.layer_2_protocol.ID_type != T_ATM_SIMPLE_ID) ||
266 (ap->blli.v.layer_2_protocol.ID.simple_ID !=
267 T_ATM_BLLI2_I8802) ||
268 (ap->llc.v.llc_len < T_ATM_LLC_MIN_LEN) ||
269 (ap->llc.v.llc_len > T_ATM_LLC_MAX_LEN)) {
273 cop->co_mpx = ATM_ENC_LLC;
274 cop->co_llc = ap->llc;
276 cop->co_mpx = ATM_ENC_NULL;
279 * Called Party Attributes
281 if (ap->called.tag != T_ATM_PRESENT) {
286 if ((ap->called.addr.address_format == T_ATM_ABSENT) ||
287 (ap->called.addr.address_length == 0)) {
293 * Calling Party Attributes
295 if (ap->calling.tag != T_ATM_ABSENT) {
301 * Quality of Service Attributes
303 if (ap->qos.tag != T_ATM_PRESENT) {
309 * Terminate stack list
316 * Let multiplexors decide whether we need a new VCC
318 switch (cop->co_mpx) {
322 * All of these connections require a new VCC
328 * See if we can share an existing LLC connection
330 cvp = atm_cm_share_llc(ap);
335 * We've got a connection to share
337 cop->co_connvc = cvp;
338 if (cvp->cvc_state == CVCS_ACTIVE) {
339 cop->co_state = COS_ACTIVE;
342 cop->co_state = COS_OUTCONN;
345 LINK2TAIL(cop, Atm_connection, cvp->cvc_conn->co_mxh, co_next);
346 cop->co_mxh = cvp->cvc_conn->co_mxh;
353 panic("atm_cm_connect: unknown mpx");
357 * If we get here, it means we need to create
358 * a new VCC for this connection
362 * Validate that network interface is registered and that
363 * a signalling manager is attached
365 for (pip = atm_interface_head; pip != NULL; pip = pip->pif_next) {
367 for (nip = pip->pif_nif; nip; nip = nip->nif_pnext) {
379 if ((smp = pip->pif_sigmgr) == NULL) {
385 * Get a connection VCC block
387 cvp = (Atm_connvc *)atm_allocate(&atm_connvc_pool);
394 * Save VCC attributes
397 cvp->cvc_flags |= CVCF_CALLER;
400 * Link the control blocks
402 cop->co_connvc = cvp;
404 cvp->cvc_sigmgr = smp;
407 * Create a service stack
409 err = atm_create_stack(cvp, &sl, upf);
411 cvp->cvc_state = CVCS_CLEAR;
417 * Let the signalling manager handle the VCC creation
419 cvp->cvc_state = CVCS_SETUP;
420 switch ((*smp->sm_setup)(cvp, &err)) {
424 * Connection is fully setup - initialize the stack
426 cvp->cvc_state = CVCS_INIT;
427 STACK_CALL(atm_stackcmds[ap->api].init, cvp->cvc_lower,
428 cvp->cvc_tokl, cvp, ap->api_init, 0, err2);
430 panic("atm_cm_connect: init");
432 if (cvp->cvc_flags & CVCF_ABORTING) {
434 * Someone on the stack bailed out...schedule the
435 * VCC and stack termination
441 * Everything looks fine from here
443 cvp->cvc_state = CVCS_ACTIVE;
444 cop->co_state = COS_ACTIVE;
450 * Terminate stack and clean up before we leave
452 cvp->cvc_state = CVCS_CLEAR;
456 case CALL_PROCEEDING:
458 * We'll just wait for final call status
460 cop->co_state = COS_OUTCONN;
465 panic("atm_cm_connect: setup");
472 if (err && err != EINPROGRESS) {
474 * Undo any partial setup stuff
477 atm_free((caddr_t)cop);
480 * Finish connection setup
483 cvp->cvc_flags |= CVCF_CONNQ;
484 ENQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
485 LINK2TAIL(cop, Atm_connection, cop->co_mxh, co_next);
494 * Listen for Incoming ATM Calls
496 * Called by an endpoint service in order to indicate its willingness to
497 * accept certain incoming calls. The types of calls which the endpoint
498 * is prepared to accept are specified in the Atm_attributes parameter.
500 * For each call which meets the criteria specified by the endpoint, the
501 * endpoint service will receive an incoming call notification via the
502 * endpoint's ep_incoming() function.
504 * To cancel the listening connection, the endpoint user should invoke
508 * epp pointer to endpoint definition structure
509 * token endpoint's listen instance token
510 * ap pointer to listening connection attributes
511 * copp pointer to location to return allocated connection block
514 * 0 listening connection installed
515 * errno listen failed - reason indicated
519 atm_cm_listen(epp, token, ap, copp)
523 Atm_connection **copp;
531 * Get a connection block
533 cop = (Atm_connection *)atm_allocate(&atm_connection_pool);
538 * Initialize connection info
541 cop->co_toku = token;
545 * Validate and extract useful attribute information
566 switch (ap->aal.tag) {
570 switch (ap->aal.type) {
592 * Broadband High Layer Information Attributes
594 switch (ap->bhli.tag) {
607 * Broadband Low Layer Information Attributes
609 switch (ap->blli.tag_l2) {
621 switch (ap->blli.tag_l3) {
634 * Logical Link Control Attributes
636 switch (ap->llc.tag) {
639 if ((ap->blli.tag_l2 != T_ATM_PRESENT) ||
640 (ap->blli.v.layer_2_protocol.ID_type != T_ATM_SIMPLE_ID) ||
641 (ap->blli.v.layer_2_protocol.ID.simple_ID !=
642 T_ATM_BLLI2_I8802) ||
643 (ap->llc.v.llc_len < T_ATM_LLC_MIN_LEN) ||
644 (ap->llc.v.llc_len > T_ATM_LLC_MAX_LEN)) {
648 cop->co_mpx = ATM_ENC_LLC;
649 cop->co_llc = ap->llc;
654 cop->co_mpx = ATM_ENC_NULL;
663 * Called Party Attributes
665 switch (ap->called.tag) {
668 switch (ap->called.addr.address_format) {
671 ap->called.tag = T_ATM_ABSENT;
690 * Get an attribute block and save listening attributes
692 cop->co_lattr = (Atm_attributes *)atm_allocate(&atm_attributes_pool);
693 if (cop->co_lattr == NULL) {
697 *cop->co_lattr = *ap;
700 * Now try to register the listening connection
703 if (atm_cm_match(cop->co_lattr, NULL) != NULL) {
705 * Can't have matching listeners
710 cop->co_state = COS_LISTEN;
711 LINK2TAIL(cop, Atm_connection, atm_listen_queue, co_next);
719 * Undo any partial setup stuff
723 atm_free((caddr_t)cop->co_lattr);
724 atm_free((caddr_t)cop);
728 * Finish connection setup
737 * Add to LLC Connection
739 * Called by an endpoint service to create a new Connection Manager API
740 * instance to be associated with an LLC-multiplexed connection instance
741 * which has been previously created. The endpoint provided token will
742 * be used in all further CM -> endpoint function calls, and the returned
743 * connection block pointer must be used in all subsequent endpoint -> CM
746 * If the return indicates that the connection setup has been immediately
747 * successful, then the connection is ready for data transmission.
749 * If the return indicates that the connection setup is still in progress,
750 * then the endpoint must wait for notification from the Connection Manager
751 * indicating the final status of the call setup. If the call setup completes
752 * successfully, then a "call connected" notification will be sent to the
753 * endpoint by the Connection Manager. If the call setup fails, then the
754 * endpoint will receive a "call cleared" notification.
756 * All connection instances must be freed with an atm_cm_release() call.
759 * epp pointer to endpoint definition structure
760 * token endpoint's connection instance token
761 * llc pointer to llc attributes for new connection
762 * ecop pointer to existing connection block
763 * copp pointer to location to return allocated connection block
766 * 0 connection has been successfully established
767 * EINPROGRESS connection establishment is in progress
768 * errno addllc failed - reason indicated
772 atm_cm_addllc(epp, token, llc, ecop, copp)
775 struct attr_llc *llc;
776 Atm_connection *ecop;
777 Atm_connection **copp;
779 Atm_connection *cop, *cop2;
786 * Check out requested LLC attributes
788 if ((llc->tag != T_ATM_PRESENT) ||
789 ((llc->v.flags & T_ATM_LLC_SHARING) == 0) ||
790 (llc->v.llc_len < T_ATM_LLC_MIN_LEN) ||
791 (llc->v.llc_len > T_ATM_LLC_MAX_LEN))
795 * Get a connection block
797 cop = (Atm_connection *)atm_allocate(&atm_connection_pool);
802 * Initialize connection info
805 cop->co_toku = token;
811 * Ensure that supplied connection is really valid
814 for (cvp = Q_HEAD(atm_connection_queue, Atm_connvc); cvp;
815 cvp = Q_NEXT(cvp, Atm_connvc, cvc_q)) {
816 for (cop2 = cvp->cvc_conn; cop2; cop2 = cop2->co_next) {
828 switch (ecop->co_state) {
845 * Connection must be LLC multiplexed and shared
847 if ((ecop->co_mpx != ATM_ENC_LLC) ||
848 ((ecop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0)) {
854 * This new LLC header must be unique for this VCC
858 int i = MIN(llc->v.llc_len, cop2->co_llc.v.llc_len);
860 if (KM_CMP(llc->v.llc_info, cop2->co_llc.v.llc_info, i) == 0) {
865 cop2 = cop2->co_next;
869 * Everything seems to check out
871 cop->co_flags = ecop->co_flags;
872 cop->co_state = ecop->co_state;
873 cop->co_mpx = ecop->co_mpx;
874 cop->co_connvc = ecop->co_connvc;
876 LINK2TAIL(cop, Atm_connection, ecop->co_mxh, co_next);
877 cop->co_mxh = ecop->co_mxh;
882 if (err && err != EINPROGRESS) {
884 * Undo any partial setup stuff
887 atm_free((caddr_t)cop);
890 * Pass new connection back to caller
902 * cop pointer to connection block
903 * id identifier for party to be added
904 * addr address of party to be added
907 * 0 addparty successful
908 * errno addparty failed - reason indicated
912 atm_cm_addparty(cop, id, addr)
915 struct t_atm_sap *addr;
925 * cop pointer to connection block
926 * id identifier for party to be added
927 * cause pointer to cause of drop
930 * 0 dropparty successful
931 * errno dropparty failed - reason indicated
935 atm_cm_dropparty(cop, id, cause)
938 struct t_atm_cause *cause;
945 * Release Connection Resources
947 * Called by the endpoint service in order to terminate an ATM connection
948 * and to release all system resources for the connection. This function
949 * must be called for every allocated connection instance and must only
950 * be called by the connection's owner.
953 * cop pointer to connection block
954 * cause pointer to cause of release
957 * 0 release successful
958 * errno release failed - reason indicated
962 atm_cm_release(cop, cause)
964 struct t_atm_cause *cause;
971 * First, a quick state validation check
973 switch (cop->co_state) {
991 panic("atm_cm_release: bogus conn state");
995 * Check out the VCC state too
997 if ((cvp = cop->co_connvc) != NULL) {
999 switch (cvp->cvc_state) {
1016 panic("atm_cm_release: bogus connvc state");
1020 * If we're the only connection, terminate the VCC
1022 if ((cop->co_mxh == cop) && (cop->co_next == NULL)) {
1023 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
1024 cvp->cvc_attr.cause.v = *cause;
1025 atm_cm_closevc(cvp);
1030 * Now get rid of the connection
1032 atm_cm_closeconn(cop, cause);
1039 * Abort an ATM Connection VCC
1041 * This function allows any non-owner kernel entity to request an
1042 * immediate termination of an ATM VCC. This will normally be called
1043 * when encountering a catastrophic error condition that cannot be
1044 * resolved via the available stack protocols. The connection manager
1045 * will schedule the connection's termination, including notifying the
1046 * connection owner of the termination.
1048 * This function should only be called by a stack entity instance. After
1049 * calling the function, the caller should set a protocol state which just
1050 * waits for a <sap>_TERM stack command to be delivered.
1053 * cvp pointer to connection VCC block
1054 * cause pointer to cause of abort
1057 * 0 abort successful
1058 * errno abort failed - reason indicated
1062 atm_cm_abort(cvp, cause)
1064 struct t_atm_cause *cause;
1066 ATM_DEBUG2("atm_cm_abort: cvp=%p cause=%d\n",
1067 cvp, cause->cause_value);
1070 * Note that we're aborting
1072 cvp->cvc_flags |= CVCF_ABORTING;
1074 switch (cvp->cvc_state) {
1078 * In-line code will handle this
1080 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
1081 cvp->cvc_attr.cause.v = *cause;
1088 * Schedule connection termination, since we want
1089 * to avoid any sequencing interactions
1091 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
1092 cvp->cvc_attr.cause.v = *cause;
1101 * Ignore abort, as we're already terminating
1107 "atm_cm_abort: invalid state: cvp=%p, state=%d\n",
1108 cvp, cvp->cvc_state);
1115 * Incoming ATM Call Received
1117 * Called by a signalling manager to indicate that a new call request has
1118 * been received. This function will allocate and initialize the connection
1119 * manager control blocks and queue this call request. The call request
1120 * processing function, atm_cm_procinq(), will be scheduled to perform the
1124 * vcp pointer to incoming call's VCC control block
1125 * ap pointer to incoming call's attributes
1128 * 0 call queuing successful
1129 * errno call queuing failed - reason indicated
1133 atm_cm_incoming(vcp, ap)
1142 * Do some minimal attribute validation
1146 * Must specify a network interface
1148 if (ap->nif == NULL)
1154 if ((ap->aal.tag != T_ATM_PRESENT) ||
1155 ((ap->aal.type != ATM_AAL5) &&
1156 (ap->aal.type != ATM_AAL3_4)))
1160 * Traffic Descriptor Attributes
1162 if ((ap->traffic.tag != T_ATM_PRESENT) &&
1163 (ap->traffic.tag != T_ATM_ABSENT))
1167 * Broadband Bearer Attributes
1169 if ((ap->bearer.tag != T_ATM_PRESENT) ||
1170 ((ap->bearer.v.connection_configuration != T_ATM_1_TO_1) &&
1171 (ap->bearer.v.connection_configuration != T_ATM_1_TO_MANY)))
1175 * Broadband High Layer Attributes
1177 if ((ap->bhli.tag != T_ATM_PRESENT) &&
1178 (ap->bhli.tag != T_ATM_ABSENT))
1182 * Broadband Low Layer Attributes
1184 if ((ap->blli.tag_l2 != T_ATM_PRESENT) &&
1185 (ap->blli.tag_l2 != T_ATM_ABSENT))
1187 if ((ap->blli.tag_l3 != T_ATM_PRESENT) &&
1188 (ap->blli.tag_l3 != T_ATM_ABSENT))
1192 * Logical Link Control Attributes
1194 if (ap->llc.tag == T_ATM_PRESENT)
1196 ap->llc.tag = T_ATM_ANY;
1199 * Called Party Attributes
1201 if ((ap->called.tag != T_ATM_PRESENT) ||
1202 (ap->called.addr.address_format == T_ATM_ABSENT))
1204 if (ap->called.tag == T_ATM_ABSENT) {
1205 ap->called.addr.address_format = T_ATM_ABSENT;
1206 ap->called.addr.address_length = 0;
1207 ap->called.subaddr.address_format = T_ATM_ABSENT;
1208 ap->called.subaddr.address_length = 0;
1212 * Calling Party Attributes
1214 if ((ap->calling.tag != T_ATM_PRESENT) &&
1215 (ap->calling.tag != T_ATM_ABSENT))
1217 if (ap->calling.tag == T_ATM_ABSENT) {
1218 ap->calling.addr.address_format = T_ATM_ABSENT;
1219 ap->calling.addr.address_length = 0;
1220 ap->calling.subaddr.address_format = T_ATM_ABSENT;
1221 ap->calling.subaddr.address_length = 0;
1225 * Quality of Service Attributes
1227 if (ap->qos.tag != T_ATM_PRESENT)
1231 * Transit Network Attributes
1233 if ((ap->transit.tag != T_ATM_PRESENT) &&
1234 (ap->transit.tag != T_ATM_ABSENT))
1240 if ((ap->cause.tag != T_ATM_PRESENT) &&
1241 (ap->cause.tag != T_ATM_ABSENT))
1245 * Get a connection VCC block
1247 cvp = (Atm_connvc *)atm_allocate(&atm_connvc_pool);
1254 * Initialize the control block
1257 cvp->cvc_sigmgr = vcp->vc_pif->pif_sigmgr;
1258 cvp->cvc_attr = *ap;
1259 cvp->cvc_state = CVCS_INCOMING;
1262 * Control queue length
1265 if (atm_incoming_qlen >= ATM_CALLQ_MAX) {
1272 * Queue request and schedule call processing function
1274 cvp->cvc_flags |= CVCF_INCOMQ;
1275 ENQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
1276 if (atm_incoming_qlen++ == 0) {
1277 atm_cm_procinq(NULL);
1281 * Link for signalling manager
1283 vcp->vc_connvc = cvp;
1291 * Free any resources
1294 atm_free((caddr_t)cvp);
1300 * VCC Connected Notification
1302 * This function is called by a signalling manager as notification that a
1303 * VCC call setup has been successful.
1306 * cvp pointer to connection VCC block
1313 atm_cm_connected(cvp)
1316 Atm_connection *cop, *cop2;
1323 * Validate connection vcc
1325 switch (cvp->cvc_state) {
1329 * Initialize the stack
1331 cvp->cvc_state = CVCS_INIT;
1332 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].init,
1333 cvp->cvc_lower, cvp->cvc_tokl,
1334 cvp, cvp->cvc_attr.api_init, 0, err);
1336 panic("atm_cm_connected: init");
1338 if (cvp->cvc_flags & CVCF_ABORTING) {
1340 * Someone on the stack bailed out...notify all of the
1341 * connections and schedule the VCC termination
1343 cop = cvp->cvc_conn;
1345 cop2 = cop->co_next;
1346 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
1349 atm_cm_closevc(cvp);
1357 * Stack already initialized
1362 panic("atm_cm_connected: connvc state");
1366 * VCC is ready for action
1368 cvp->cvc_state = CVCS_ACTIVE;
1371 * Notify all connections that the call has completed
1373 cop = cvp->cvc_conn;
1375 cop2 = cop->co_next;
1377 switch (cop->co_state) {
1381 cop->co_state = COS_ACTIVE;
1382 (*cop->co_endpt->ep_connected)(cop->co_toku);
1387 * May get here if an ep_connected() call (from
1388 * above) results in an atm_cm_addllc() call for
1389 * the just connected connection.
1394 panic("atm_cm_connected: connection state");
1403 * Input any queued packets
1405 while ((m = cvp->cvc_rcvq) != NULL) {
1406 cvp->cvc_rcvq = KB_QNEXT(m);
1411 * Currently only supported for CPCS API
1413 atm_cm_cpcs_upper(CPCS_UNITDATA_SIG, cvp, (int)m, 0);
1421 * VCC Cleared Notification
1423 * This function is called by a signalling manager as notification that a
1424 * VCC call has been cleared. The cause information describing the reason
1425 * for the call clearing will be contained in the connection VCC attributes.
1428 * cvp pointer to connection VCC block
1438 Atm_connection *cop, *cop2;
1441 if ((cvp->cvc_state == CVCS_FREE) ||
1442 (cvp->cvc_state >= CVCS_CLEAR))
1443 panic("atm_cm_cleared");
1446 cvp->cvc_state = CVCS_CLEAR;
1451 * Terminate all connections
1453 cop = cvp->cvc_conn;
1455 cop2 = cop->co_next;
1456 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
1461 * Clean up connection VCC
1463 atm_cm_closevc(cvp);
1472 * Process Incoming Call Queue
1474 * This function is scheduled by atm_cm_incoming() in order to process
1475 * all the entries on the incoming call queue.
1478 * arg argument passed on timeout() call
1492 * Only process incoming calls up to our quota
1494 while (cnt++ < ATM_CALLQ_MAX) {
1498 * Get next awaiting call
1500 cvp = Q_HEAD(atm_incoming_queue, Atm_connvc);
1505 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
1506 atm_incoming_qlen--;
1507 cvp->cvc_flags &= ~CVCF_INCOMQ;
1518 * If we've expended our quota, reschedule ourselves
1520 if (cnt >= ATM_CALLQ_MAX) {
1521 callout_reset(&atm_cm_procinq_ch, 1, atm_cm_procinq, NULL);
1527 * Process Incoming Call
1529 * This function will search through the listening queue and try to find
1530 * matching endpoint(s) for the incoming call. If we find any, we will
1531 * notify the endpoint service(s) of the incoming call and will then
1532 * notify the signalling manager to progress the call to an active status.
1534 * If there are no listeners for the call, the signalling manager will be
1535 * notified of a call rejection.
1537 * Called from a critical section.
1540 * cvp pointer to connection VCC for incoming call
1550 Atm_connection *cop, *lcop, *hcop;
1551 Atm_attributes attr;
1557 attr = cvp->cvc_attr;
1560 * Look for matching listeners
1562 while ((lcop = atm_cm_match(&attr, lcop)) != NULL) {
1566 * Need a new connection block
1568 cop = (Atm_connection *)
1569 atm_allocate(&atm_connection_pool);
1571 cvp->cvc_attr.cause = atm_cause_tmpl;
1572 cvp->cvc_attr.cause.v.cause_value =
1573 T_ATM_CAUSE_TEMPORARY_FAILURE;
1579 * Initialize connection from listener and incoming call
1582 cop->co_state = COS_INCONN;
1583 cop->co_mpx = lcop->co_mpx;
1584 cop->co_endpt = lcop->co_endpt;
1585 cop->co_llc = lcop->co_llc;
1587 switch (attr.bearer.v.connection_configuration) {
1590 cop->co_flags |= COF_P2P;
1593 case T_ATM_1_TO_MANY:
1595 cop->co_flags |= COF_P2MP;
1596 cvp->cvc_attr.cause = atm_cause_tmpl;
1597 cvp->cvc_attr.cause.v.cause_value =
1598 T_ATM_CAUSE_BEARER_CAPABILITY_NOT_IMPLEMENTED;
1603 * Notify endpoint of incoming call
1605 err = (*cop->co_endpt->ep_incoming)
1606 (lcop->co_toku, cop, &cvp->cvc_attr, &cop->co_toku);
1611 * Endpoint has accepted the call
1613 * Setup call attributes
1616 cvp->cvc_attr.api = lcop->co_lattr->api;
1617 cvp->cvc_attr.api_init =
1618 lcop->co_lattr->api_init;
1619 cvp->cvc_attr.llc = lcop->co_lattr->llc;
1621 cvp->cvc_attr.headin = MAX(cvp->cvc_attr.headin,
1622 lcop->co_lattr->headin);
1625 * Setup connection info and queueing
1627 cop->co_state = COS_INACCEPT;
1628 cop->co_connvc = cvp;
1629 LINK2TAIL(cop, Atm_connection, hcop, co_next);
1633 * Need a new connection block next time around
1639 * Endpoint refuses call
1646 * We're done looking for listeners
1650 * Someone actually wants the call, so notify
1651 * the signalling manager to continue
1653 cvp->cvc_flags |= CVCF_CONNQ;
1654 ENQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
1655 if (atm_cm_accept(cvp, hcop))
1660 * Nobody around to take the call
1662 cvp->cvc_attr.cause = atm_cause_tmpl;
1663 cvp->cvc_attr.cause.v.cause_value =
1664 T_ATM_CAUSE_INCOMPATIBLE_DESTINATION;
1669 * Clean up loose ends
1672 atm_free((caddr_t)cop);
1675 * Call has been accepted
1681 * Call failed - notify any endpoints of the call failure
1685 * Clean up loose ends
1688 atm_free((caddr_t)cop);
1690 if (cvp->cvc_attr.cause.tag != T_ATM_PRESENT) {
1691 cvp->cvc_attr.cause = atm_cause_tmpl;
1692 cvp->cvc_attr.cause.v.cause_value =
1693 T_ATM_CAUSE_UNSPECIFIED_NORMAL;
1697 Atm_connection *cop2 = cop->co_next;
1698 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
1703 * Tell the signalling manager to reject the call
1705 atm_cm_closevc(cvp);
1712 * Accept an Incoming ATM Call
1714 * Some endpoint service(s) wants to accept an incoming call, so the
1715 * signalling manager will be notified to attempt to progress the call
1716 * to an active status.
1718 * If the signalling manager indicates that connection activation has
1719 * been immediately successful, then all of the endpoints will be notified
1720 * that the connection is ready for data transmission.
1722 * If the return indicates that connection activation is still in progress,
1723 * then the endpoints must wait for notification from the Connection Manager
1724 * indicating the final status of the call setup. If the call setup completes
1725 * successfully, then a "call connected" notification will be sent to the
1726 * endpoints by the Connection Manager. If the call setup fails, then the
1727 * endpoints will receive a "call cleared" notification.
1729 * Called from a critical section.
1732 * cvp pointer to connection VCC for incoming call
1733 * cop pointer to head of accepted connections
1736 * 0 connection has been successfully activated
1737 * errno accept failed - reason indicated
1741 atm_cm_accept(cvp, cop)
1743 Atm_connection *cop;
1745 struct stack_list sl;
1746 void (*upf)(int, void *, int, int);
1751 * Link vcc to connections
1753 cvp->cvc_conn = cop;
1756 * Initialize stack list index
1761 * Check out Data API
1763 switch (cvp->cvc_attr.api) {
1766 upf = atm_cm_cpcs_upper;
1770 sl.sl_sap[sli++] = SAP_SSCF_UNI;
1771 sl.sl_sap[sli++] = SAP_SSCOP;
1772 upf = atm_cm_saal_upper;
1776 sl.sl_sap[sli++] = SAP_SSCOP;
1777 upf = atm_cm_sscop_upper;
1787 switch (cvp->cvc_attr.aal.type) {
1790 sl.sl_sap[sli++] = SAP_CPCS_AAL5;
1791 sl.sl_sap[sli++] = SAP_SAR_AAL5;
1792 sl.sl_sap[sli++] = SAP_ATM;
1796 sl.sl_sap[sli++] = SAP_CPCS_AAL3_4;
1797 sl.sl_sap[sli++] = SAP_SAR_AAL3_4;
1798 sl.sl_sap[sli++] = SAP_ATM;
1803 * Terminate stack list
1808 * Create a service stack
1810 err = atm_create_stack(cvp, &sl, upf);
1816 * Let the signalling manager finish the VCC activation
1818 switch ((*cvp->cvc_sigmgr->sm_accept)(cvp->cvc_vcc, &err)) {
1820 case CALL_PROCEEDING:
1822 * Note that we're not finished yet
1827 case CALL_CONNECTED:
1829 * Initialize the stack now, even if the call isn't totally
1830 * active yet. We want to avoid the delay between getting
1831 * the "call connected" event and actually notifying the
1832 * adapter to accept cells on the new VCC - if the delay is
1833 * too long, then we end up dropping the first pdus sent by
1836 cvp->cvc_state = CVCS_INIT;
1837 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].init,
1838 cvp->cvc_lower, cvp->cvc_tokl, cvp,
1839 cvp->cvc_attr.api_init, 0, err2);
1841 panic("atm_cm_accept: init");
1843 if (cvp->cvc_flags & CVCF_ABORTING) {
1845 * Someone on the stack bailed out...schedule the
1846 * VCC and stack termination
1851 * Everything looks fine from here
1854 cvp->cvc_state = CVCS_ACCEPT;
1856 cvp->cvc_state = CVCS_ACTIVE;
1862 * Terminate stack and clean up before we leave
1864 cvp->cvc_state = CVCS_CLEAR;
1868 panic("atm_cm_accept: accept");
1874 * Call has been connected, notify endpoints
1877 Atm_connection *cop2 = cop->co_next;
1879 cop->co_state = COS_ACTIVE;
1880 (*cop->co_endpt->ep_connected)(cop->co_toku);
1884 } else if (err == EINPROGRESS) {
1886 * Call is still in progress, endpoint must wait
1892 * Let caller know we failed
1894 cvp->cvc_attr.cause = atm_cause_tmpl;
1895 cvp->cvc_attr.cause.v.cause_value =
1896 T_ATM_CAUSE_UNSPECIFIED_RESOURCE_UNAVAILABLE;
1904 * Match Attributes on Listening Queue
1906 * This function will attempt to match the supplied connection attributes
1907 * with one of the registered attributes in the listening queue. The pcop
1908 * argument may be supplied in order to allow multiple listeners to share
1909 * an incoming call (if supported by the listeners).
1911 * Called from a critical section.
1914 * ap pointer to attributes to be matched
1915 * pcop pointer to the previously matched connection
1918 * addr connection with which a match was found
1923 atm_cm_match(ap, pcop)
1925 Atm_connection *pcop;
1927 Atm_connection *cop;
1928 Atm_attributes *lap;
1932 * If we've already matched a listener...
1936 * Make sure already matched listener supports sharing
1938 if ((pcop->co_mpx != ATM_ENC_LLC) ||
1939 ((pcop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0))
1943 * Position ourselves after the matched entry
1945 for (cop = atm_listen_queue; cop; cop = cop->co_next) {
1947 cop = pcop->co_next;
1953 * Start search at top of listening queue
1955 cop = atm_listen_queue;
1959 * Search through listening queue
1961 for (; cop; cop = cop->co_next) {
1963 lap = cop->co_lattr;
1966 * If we're trying to share, check that this entry allows it
1969 if ((cop->co_mpx != ATM_ENC_LLC) ||
1970 ((cop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0))
1975 * ALL "matchable" attributes must match
1981 if (lap->bhli.tag == T_ATM_ABSENT) {
1982 if (ap->bhli.tag == T_ATM_PRESENT)
1984 } else if (lap->bhli.tag == T_ATM_PRESENT) {
1985 if (ap->bhli.tag == T_ATM_ABSENT)
1987 if (ap->bhli.tag == T_ATM_PRESENT)
1988 if (KM_CMP(&lap->bhli.v, &ap->bhli.v,
1989 sizeof(struct t_atm_bhli)))
1996 if (lap->blli.tag_l2 == T_ATM_ABSENT) {
1997 if (ap->blli.tag_l2 == T_ATM_PRESENT)
1999 } else if (lap->blli.tag_l2 == T_ATM_PRESENT) {
2000 if (ap->blli.tag_l2 == T_ATM_ABSENT)
2002 if (ap->blli.tag_l2 == T_ATM_PRESENT) {
2003 if (KM_CMP(&lap->blli.v.layer_2_protocol.ID,
2004 &ap->blli.v.layer_2_protocol.ID,
2006 ap->blli.v.layer_2_protocol.ID)))
2014 if (lap->blli.tag_l3 == T_ATM_ABSENT) {
2015 if (ap->blli.tag_l3 == T_ATM_PRESENT)
2017 } else if (lap->blli.tag_l3 == T_ATM_PRESENT) {
2018 if (ap->blli.tag_l3 == T_ATM_ABSENT)
2020 if (ap->blli.tag_l3 == T_ATM_PRESENT) {
2021 if (KM_CMP(&lap->blli.v.layer_3_protocol.ID,
2022 &ap->blli.v.layer_3_protocol.ID,
2024 ap->blli.v.layer_3_protocol.ID)))
2032 if (lap->llc.tag == T_ATM_ABSENT) {
2033 if (ap->llc.tag == T_ATM_PRESENT)
2035 } else if (lap->llc.tag == T_ATM_PRESENT) {
2036 if (ap->llc.tag == T_ATM_ABSENT)
2038 if (ap->llc.tag == T_ATM_PRESENT) {
2039 int i = MIN(lap->llc.v.llc_len,
2042 if (KM_CMP(lap->llc.v.llc_info,
2043 ap->llc.v.llc_info, i))
2051 if (lap->aal.tag == T_ATM_ABSENT) {
2052 if (ap->aal.tag == T_ATM_PRESENT)
2054 } else if (lap->aal.tag == T_ATM_PRESENT) {
2055 if (ap->aal.tag == T_ATM_ABSENT)
2057 if (ap->aal.tag == T_ATM_PRESENT) {
2058 if (lap->aal.type != ap->aal.type)
2060 if (lap->aal.type == ATM_AAL5) {
2061 if (lap->aal.v.aal5.SSCS_type !=
2062 ap->aal.v.aal5.SSCS_type)
2065 if (lap->aal.v.aal4.SSCS_type !=
2066 ap->aal.v.aal4.SSCS_type)
2075 if (lap->called.tag == T_ATM_ABSENT) {
2076 if (ap->called.tag == T_ATM_PRESENT)
2078 } else if (lap->called.tag == T_ATM_PRESENT) {
2079 if (ap->called.tag == T_ATM_ABSENT)
2081 if (ap->called.tag == T_ATM_PRESENT) {
2082 if ((!ATM_ADDR_EQUAL(&lap->called.addr,
2083 &ap->called.addr)) ||
2084 (!ATM_ADDR_EQUAL(&lap->called.subaddr,
2085 &ap->called.subaddr)))
2091 * Found a full match - return it
2101 * Find Shareable LLC VCC
2103 * Given a endpoint-supplied connection attribute using LLC multiplexing,
2104 * this function will attempt to locate an existing connection which meets
2105 * the requirements of the supplied attributes.
2107 * Called from a critical section.
2110 * ap pointer to requested attributes
2113 * addr shareable LLC connection VCC
2114 * 0 no shareable VCC available
2118 atm_cm_share_llc(ap)
2121 Atm_connection *cop;
2125 * Is requestor willing to share?
2127 if ((ap->llc.v.flags & T_ATM_LLC_SHARING) == 0)
2131 * Try to find a shareable connection
2133 for (cvp = Q_HEAD(atm_connection_queue, Atm_connvc); cvp;
2134 cvp = Q_NEXT(cvp, Atm_connvc, cvc_q)) {
2137 * Dont use terminating connections
2139 switch (cvp->cvc_state) {
2151 * Is connection LLC and shareable?
2153 if ((cvp->cvc_attr.llc.tag != T_ATM_PRESENT) ||
2154 ((cvp->cvc_attr.llc.v.flags & T_ATM_LLC_SHARING) == 0))
2158 * Match requested attributes with existing connection
2160 if (ap->nif != cvp->cvc_attr.nif)
2163 if ((ap->api != cvp->cvc_attr.api) ||
2164 (ap->api_init != cvp->cvc_attr.api_init))
2170 if (cvp->cvc_flags & CVCF_CALLER) {
2171 if ((!ATM_ADDR_EQUAL(&ap->called.addr,
2172 &cvp->cvc_attr.called.addr)) ||
2173 (!ATM_ADDR_EQUAL(&ap->called.subaddr,
2174 &cvp->cvc_attr.called.subaddr)))
2177 if (cvp->cvc_attr.calling.tag != T_ATM_PRESENT)
2179 if ((!ATM_ADDR_EQUAL(&ap->called.addr,
2180 &cvp->cvc_attr.calling.addr)) ||
2181 (!ATM_ADDR_EQUAL(&ap->called.subaddr,
2182 &cvp->cvc_attr.calling.subaddr)))
2189 if (ap->aal.type == ATM_AAL5) {
2190 struct t_atm_aal5 *ap5, *cv5;
2192 ap5 = &ap->aal.v.aal5;
2193 cv5 = &cvp->cvc_attr.aal.v.aal5;
2195 if ((cvp->cvc_attr.aal.type != ATM_AAL5) ||
2196 (ap5->SSCS_type != cv5->SSCS_type))
2199 if (cvp->cvc_flags & CVCF_CALLER) {
2200 if (ap5->forward_max_SDU_size >
2201 cv5->forward_max_SDU_size)
2204 if (ap5->forward_max_SDU_size >
2205 cv5->backward_max_SDU_size)
2209 struct t_atm_aal4 *ap4, *cv4;
2211 ap4 = &ap->aal.v.aal4;
2212 cv4 = &cvp->cvc_attr.aal.v.aal4;
2214 if ((cvp->cvc_attr.aal.type != ATM_AAL3_4) ||
2215 (ap4->SSCS_type != cv4->SSCS_type))
2218 if (cvp->cvc_flags & CVCF_CALLER) {
2219 if (ap4->forward_max_SDU_size >
2220 cv4->forward_max_SDU_size)
2223 if (ap4->forward_max_SDU_size >
2224 cv4->backward_max_SDU_size)
2230 * Traffic Descriptor
2232 if ((ap->traffic.tag != T_ATM_PRESENT) ||
2233 (cvp->cvc_attr.traffic.tag != T_ATM_PRESENT) ||
2234 (ap->traffic.v.best_effort != T_YES) ||
2235 (cvp->cvc_attr.traffic.v.best_effort != T_YES))
2241 if (ap->bearer.v.connection_configuration !=
2242 cvp->cvc_attr.bearer.v.connection_configuration)
2248 if (cvp->cvc_flags & CVCF_CALLER) {
2249 if ((ap->qos.v.forward.qos_class !=
2250 cvp->cvc_attr.qos.v.forward.qos_class) ||
2251 (ap->qos.v.backward.qos_class !=
2252 cvp->cvc_attr.qos.v.backward.qos_class))
2255 if ((ap->qos.v.forward.qos_class !=
2256 cvp->cvc_attr.qos.v.backward.qos_class) ||
2257 (ap->qos.v.backward.qos_class !=
2258 cvp->cvc_attr.qos.v.forward.qos_class))
2263 * The new LLC header must also be unique for this VCC
2265 for (cop = cvp->cvc_conn; cop; cop = cop->co_next) {
2266 int i = MIN(ap->llc.v.llc_len,
2267 cop->co_llc.v.llc_len);
2269 if (KM_CMP(ap->llc.v.llc_info,
2270 cop->co_llc.v.llc_info, i) == 0)
2275 * If no header overlaps, then we're done
2288 * This function will terminate a connection, including notifying the
2289 * user, if necessary, and freeing up control block memory. The caller
2290 * is responsible for managing the connection VCC.
2292 * Called from a critical section.
2295 * cop pointer to connection block
2296 * cause pointer to cause of close
2303 atm_cm_closeconn(cop, cause)
2304 Atm_connection *cop;
2305 struct t_atm_cause *cause;
2309 * Decide whether user needs notification
2311 switch (cop->co_state) {
2319 * Yup, let 'em know connection is gone
2322 (*cop->co_endpt->ep_cleared)(cop->co_toku, cause);
2327 * Nope,they should know already
2332 panic("atm_cm_closeconn: bogus state");
2336 * Unlink connection from its queues
2338 switch (cop->co_state) {
2341 atm_free((caddr_t)cop->co_lattr);
2342 UNLINK(cop, Atm_connection, atm_listen_queue, co_next);
2347 * Remove connection from multiplexor queue
2349 if (cop->co_mxh != cop) {
2351 * Connection is down the chain, just unlink it
2353 UNLINK(cop, Atm_connection, cop->co_mxh, co_next);
2355 } else if (cop->co_next != NULL) {
2357 * Connection is at the head of a non-singleton chain,
2358 * so unlink and reset the chain head
2360 Atm_connection *t, *nhd;
2362 t = nhd = cop->co_next;
2368 nhd->co_connvc->cvc_conn = nhd;
2373 * Free the connection block
2375 cop->co_state = COS_FREE;
2376 atm_free((caddr_t)cop);
2383 * Close Connection VCC
2385 * This function will terminate a connection VCC, including releasing the
2386 * the call to the signalling manager, terminating the VCC protocol stack,
2387 * and freeing up control block memory.
2389 * Called from a critical section.
2392 * cvp pointer to connection VCC block
2405 * Break links with the connection block
2407 cvp->cvc_conn = NULL;
2410 * Cancel any running timer
2415 * Free queued packets
2417 while (cvp->cvc_rcvq) {
2421 cvp->cvc_rcvq = KB_QNEXT(m);
2427 * Unlink from any queues
2429 if (cvp->cvc_flags & CVCF_INCOMQ) {
2430 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
2431 atm_incoming_qlen--;
2432 cvp->cvc_flags &= ~CVCF_INCOMQ;
2434 } else if (cvp->cvc_flags & CVCF_CONNQ) {
2435 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
2436 cvp->cvc_flags &= ~CVCF_CONNQ;
2440 * Release the signalling call
2442 switch (cvp->cvc_state) {
2450 cvp->cvc_state = CVCS_RELEASE;
2451 switch ((*cvp->cvc_sigmgr->sm_release)
2452 (cvp->cvc_vcc, &err)) {
2456 * Looks good so far...
2460 case CALL_PROCEEDING:
2462 * We'll have to wait for the call to clear
2468 * If there's a memory shortage, retry later.
2469 * Otherwise who knows what's going on....
2471 if ((err == ENOMEM) || (err == ENOBUFS)) {
2472 CVC_TIMER(cvp, 1 * ATM_HZ);
2476 "atm_cm_closevc: release %d\n", err);
2485 cvp->cvc_state = CVCS_REJECT;
2486 switch ((*cvp->cvc_sigmgr->sm_reject)
2487 (cvp->cvc_vcc, &err)) {
2491 * Looks good so far...
2497 * If there's a memory shortage, retry later.
2498 * Otherwise who knows what's going on....
2500 if ((err == ENOMEM) || (err == ENOBUFS)) {
2501 CVC_TIMER(cvp, 1 * ATM_HZ);
2505 "atm_cm_closevc: reject %d\n", err);
2514 * No need for anything here
2519 panic("atm_cm_closevc: bogus state");
2523 * Now terminate the stack
2525 if (cvp->cvc_tokl) {
2526 cvp->cvc_state = CVCS_TERM;
2529 * Wait until stack is unwound before terminating
2531 if ((cvp->cvc_downcnt > 0) || (cvp->cvc_upcnt > 0)) {
2536 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].term,
2537 cvp->cvc_lower, cvp->cvc_tokl, cvp, 0, 0, err);
2539 cvp->cvc_tokl = NULL;
2543 * Let signalling manager finish up
2545 cvp->cvc_state = CVCS_FREE;
2547 (void) (*cvp->cvc_sigmgr->sm_free)(cvp->cvc_vcc);
2551 * Finally, free our own control blocks
2553 atm_free((caddr_t)cvp);
2560 * Process a Connection VCC timeout
2562 * Called when a previously scheduled cvc control block timer expires.
2563 * Processing will be based on the current cvc state.
2565 * Called from a critical section.
2568 * tip pointer to cvc timer control block
2576 struct atm_time *tip;
2578 Atm_connection *cop, *cop2;
2582 * Back-off to cvc control block
2584 cvp = (Atm_connvc *)
2585 ((caddr_t)tip - (int)(&((Atm_connvc *)0)->cvc_time));
2588 * Process timeout based on protocol state
2590 switch (cvp->cvc_state) {
2598 if ((cvp->cvc_flags & CVCF_ABORTING) == 0)
2602 * Terminate all connections
2604 cop = cvp->cvc_conn;
2606 cop2 = cop->co_next;
2607 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
2614 atm_cm_closevc(cvp);
2622 * Retry failed operation
2624 atm_cm_closevc(cvp);
2630 "atm_cm_timeout: invalid state: cvp=%p, state=%d\n",
2631 cvp, cvp->cvc_state);
2637 * CPCS User Control Commands
2639 * This function is called by an endpoint user to pass a control command
2640 * across a CPCS data API. Mostly we just send these down the stack.
2643 * cmd stack command code
2644 * cop pointer to connection block
2648 * 0 command output successful
2649 * errno output failed - reason indicated
2653 atm_cm_cpcs_ctl(cmd, cop, arg)
2655 Atm_connection *cop;
2662 * Validate connection state
2664 if (cop->co_state != COS_ACTIVE) {
2669 cvp = cop->co_connvc;
2670 if (cvp->cvc_state != CVCS_ACTIVE) {
2675 if (cvp->cvc_attr.api != CMAPI_CPCS) {
2694 * This function is called by an endpoint user to output a data packet
2695 * across a CPCS data API. After we've validated the connection state, the
2696 * packet will be encapsulated (if necessary) and sent down the data stack.
2699 * cop pointer to connection block
2700 * m pointer to packet buffer chain to be output
2703 * 0 packet output successful
2704 * errno output failed - reason indicated
2708 atm_cm_cpcs_data(cop, m)
2709 Atm_connection *cop;
2713 struct attr_llc *llcp;
2719 * Validate connection state
2721 if (cop->co_state != COS_ACTIVE) {
2726 cvp = cop->co_connvc;
2727 if (cvp->cvc_state != CVCS_ACTIVE) {
2732 if (cvp->cvc_attr.api != CMAPI_CPCS) {
2738 * Add any packet encapsulation
2740 switch (cop->co_mpx) {
2750 * Need to add an LLC header
2752 llcp = &cop->co_llc;
2755 * See if there's room to add LLC header to front of packet.
2757 KB_HEADROOM(m, space);
2758 if (space < llcp->v.llc_len) {
2762 * We have to allocate another buffer and tack it
2763 * onto the front of the packet
2765 KB_ALLOCPKT(n, llcp->v.llc_len, KB_F_NOWAIT,
2771 KB_TAILALIGN(n, llcp->v.llc_len);
2776 * Header fits, just adjust buffer controls
2778 KB_HEADADJ(m, llcp->v.llc_len);
2782 * Add the LLC header
2784 KB_DATASTART(m, bp, void *);
2785 KM_COPY(llcp->v.llc_info, bp, llcp->v.llc_len);
2786 KB_PLENADJ(m, llcp->v.llc_len);
2790 panic("atm_cm_cpcs_data: mpx");
2794 * Finally, we can send the packet on its way
2796 STACK_CALL(CPCS_UNITDATA_INV, cvp->cvc_lower, cvp->cvc_tokl,
2797 cvp, (int)m, 0, err);
2805 * Process CPCS Stack Commands
2807 * This is the top of the CPCS API data stack. All upward stack commands
2808 * for the CPCS data API will be received and processed here.
2811 * cmd stack command code
2812 * tok session token (pointer to connection VCC control block)
2821 atm_cm_cpcs_upper(cmd, tok, arg1, arg2)
2827 Atm_connection *cop;
2828 Atm_connvc *cvp = tok;
2834 case CPCS_UNITDATA_SIG:
2838 m = (KBuffer *)arg1;
2840 if (cvp->cvc_state != CVCS_ACTIVE) {
2841 if (cvp->cvc_state == CVCS_ACCEPT) {
2845 * Queue up any packets received before sigmgr
2846 * notifies us of incoming call completion
2848 if (cvp->cvc_rcvqlen >= CVC_RCVQ_MAX) {
2850 atm_cm_stat.cms_rcvconnvc++;
2854 if (cvp->cvc_rcvq == NULL) {
2857 for (n = cvp->cvc_rcvq;
2858 KB_QNEXT(n) != NULL;
2867 atm_cm_stat.cms_rcvconnvc++;
2873 * Locate packet's connection
2875 cop = cvp->cvc_conn;
2876 switch (cop->co_mpx) {
2880 * We're already there...
2886 * Find connection with matching LLC header
2888 if (KB_LEN(m) < T_ATM_LLC_MAX_LEN) {
2889 KB_PULLUP(m, T_ATM_LLC_MAX_LEN, m);
2891 atm_cm_stat.cms_llcdrop++;
2895 KB_DATASTART(m, bp, void *);
2900 if (KM_CMP(bp, cop->co_llc.v.llc_info,
2901 cop->co_llc.v.llc_len) == 0)
2910 * No connected user for this LLC
2913 atm_cm_stat.cms_llcid++;
2918 * Strip off the LLC header
2920 KB_HEADADJ(m, -cop->co_llc.v.llc_len);
2921 KB_PLENADJ(m, -cop->co_llc.v.llc_len);
2925 panic("atm_cm_cpcs_upper: mpx");
2929 * We've found our connection, so hand the packet off
2931 if (cop->co_state != COS_ACTIVE) {
2933 atm_cm_stat.cms_rcvconn++;
2936 (*cop->co_endpt->ep_cpcs_data)(cop->co_toku, m);
2939 case CPCS_UABORT_SIG:
2940 case CPCS_PABORT_SIG:
2942 * We don't support these (yet), so just fall thru...
2946 log(LOG_ERR, "atm_cm_cpcs_upper: unknown cmd 0x%x\n", cmd);
2952 * SAAL User Control Commands
2954 * This function is called by an endpoint user to pass a control command
2955 * across a SAAL data API. Mostly we just send these down the stack.
2958 * cmd stack command code
2959 * cop pointer to connection block
2963 * 0 command output successful
2964 * errno output failed - reason indicated
2968 atm_cm_saal_ctl(cmd, cop, arg)
2970 Atm_connection *cop;
2977 * Validate connection state
2979 if (cop->co_state != COS_ACTIVE) {
2984 cvp = cop->co_connvc;
2985 if (cvp->cvc_state != CVCS_ACTIVE) {
2990 if (cvp->cvc_attr.api != CMAPI_SAAL) {
2997 case SSCF_UNI_ESTABLISH_REQ:
2998 case SSCF_UNI_RELEASE_REQ:
3000 * Pass command down the stack
3002 STACK_CALL(cmd, cvp->cvc_lower, cvp->cvc_tokl, cvp,
3018 * This function is called by an endpoint user to output a data packet
3019 * across a SAAL data API. After we've validated the connection state,
3020 * the packet will be sent down the data stack.
3023 * cop pointer to connection block
3024 * m pointer to packet buffer chain to be output
3027 * 0 packet output successful
3028 * errno output failed - reason indicated
3032 atm_cm_saal_data(cop, m)
3033 Atm_connection *cop;
3041 * Validate connection state
3043 if (cop->co_state != COS_ACTIVE) {
3048 cvp = cop->co_connvc;
3049 if (cvp->cvc_state != CVCS_ACTIVE) {
3054 if (cvp->cvc_attr.api != CMAPI_SAAL) {
3060 * Finally, we can send the packet on its way
3062 STACK_CALL(SSCF_UNI_DATA_REQ, cvp->cvc_lower, cvp->cvc_tokl,
3063 cvp, (int)m, 0, err);
3071 * Process SAAL Stack Commands
3073 * This is the top of the SAAL API data stack. All upward stack commands
3074 * for the SAAL data API will be received and processed here.
3077 * cmd stack command code
3078 * tok session token (pointer to connection VCC control block)
3087 atm_cm_saal_upper(cmd, tok, arg1, arg2)
3093 Atm_connection *cop;
3094 Atm_connvc *cvp = tok;
3099 case SSCF_UNI_ESTABLISH_IND:
3100 case SSCF_UNI_ESTABLISH_CNF:
3101 case SSCF_UNI_RELEASE_IND:
3102 case SSCF_UNI_RELEASE_CNF:
3106 cop = cvp->cvc_conn;
3107 if (cvp->cvc_state != CVCS_ACTIVE)
3109 if (cop->co_state != COS_ACTIVE)
3112 (*cop->co_endpt->ep_saal_ctl)(cmd, cop->co_toku, (void *)arg1);
3115 case SSCF_UNI_DATA_IND:
3119 cop = cvp->cvc_conn;
3120 if (cvp->cvc_state != CVCS_ACTIVE) {
3121 atm_cm_stat.cms_rcvconnvc++;
3122 KB_FREEALL((KBuffer *)arg1);
3125 if (cop->co_state != COS_ACTIVE) {
3126 atm_cm_stat.cms_rcvconn++;
3127 KB_FREEALL((KBuffer *)arg1);
3131 (*cop->co_endpt->ep_saal_data)(cop->co_toku, (KBuffer *)arg1);
3134 case SSCF_UNI_UNITDATA_IND:
3138 KB_FREEALL((KBuffer *)arg1);
3143 log(LOG_ERR, "atm_cm_saal_upper: unknown cmd 0x%x\n", cmd);
3149 * SSCOP User Control Commands
3151 * This function is called by an endpoint user to pass a control command
3152 * across a SSCOP data API. Mostly we just send these down the stack.
3155 * cmd stack command code
3156 * cop pointer to connection block
3161 * 0 command output successful
3162 * errno output failed - reason indicated
3166 atm_cm_sscop_ctl(cmd, cop, arg1, arg2)
3168 Atm_connection *cop;
3176 * Validate connection state
3178 if (cop->co_state != COS_ACTIVE) {
3183 cvp = cop->co_connvc;
3184 if (cvp->cvc_state != CVCS_ACTIVE) {
3189 if (cvp->cvc_attr.api != CMAPI_SSCOP) {
3196 case SSCOP_ESTABLISH_REQ:
3197 case SSCOP_ESTABLISH_RSP:
3198 case SSCOP_RELEASE_REQ:
3199 case SSCOP_RESYNC_REQ:
3200 case SSCOP_RESYNC_RSP:
3201 case SSCOP_RECOVER_RSP:
3202 case SSCOP_RETRIEVE_REQ:
3204 * Pass command down the stack
3206 STACK_CALL(cmd, cvp->cvc_lower, cvp->cvc_tokl, cvp,
3207 (int)arg1, (int)arg2, err);
3222 * This function is called by an endpoint user to output a data packet
3223 * across a SSCOP data API. After we've validated the connection state,
3224 * the packet will be encapsulated and sent down the data stack.
3227 * cop pointer to connection block
3228 * m pointer to packet buffer chain to be output
3231 * 0 packet output successful
3232 * errno output failed - reason indicated
3236 atm_cm_sscop_data(cop, m)
3237 Atm_connection *cop;
3245 * Validate connection state
3247 if (cop->co_state != COS_ACTIVE) {
3252 cvp = cop->co_connvc;
3253 if (cvp->cvc_state != CVCS_ACTIVE) {
3258 if (cvp->cvc_attr.api != CMAPI_SSCOP) {
3264 * Finally, we can send the packet on its way
3266 STACK_CALL(SSCOP_DATA_REQ, cvp->cvc_lower, cvp->cvc_tokl,
3267 cvp, (int)m, 0, err);
3275 * Process SSCOP Stack Commands
3277 * This is the top of the SSCOP API data stack. All upward stack commands
3278 * for the SSCOP data API will be received and processed here.
3281 * cmd stack command code
3282 * tok session token (pointer to connection VCC control block)
3291 atm_cm_sscop_upper(cmd, tok, arg1, arg2)
3297 Atm_connection *cop;
3298 Atm_connvc *cvp = tok;
3302 case SSCOP_ESTABLISH_IND:
3303 case SSCOP_ESTABLISH_CNF:
3304 case SSCOP_RELEASE_IND:
3305 case SSCOP_RESYNC_IND:
3309 cop = cvp->cvc_conn;
3310 if ((cvp->cvc_state != CVCS_ACTIVE) ||
3311 (cop->co_state != COS_ACTIVE)) {
3312 KB_FREEALL((KBuffer *)arg1);
3316 (*cop->co_endpt->ep_sscop_ctl)
3317 (cmd, cop->co_toku, (void *)arg1, (void *)arg2);
3320 case SSCOP_RELEASE_CNF:
3321 case SSCOP_RESYNC_CNF:
3322 case SSCOP_RECOVER_IND:
3323 case SSCOP_RETRIEVE_IND:
3324 case SSCOP_RETRIEVECMP_IND:
3328 cop = cvp->cvc_conn;
3329 if ((cvp->cvc_state != CVCS_ACTIVE) ||
3330 (cop->co_state != COS_ACTIVE))
3333 (*cop->co_endpt->ep_sscop_ctl)
3334 (cmd, cop->co_toku, (void *)arg1, (void *)arg2);
3337 case SSCOP_DATA_IND:
3341 cop = cvp->cvc_conn;
3342 if (cvp->cvc_state != CVCS_ACTIVE) {
3343 atm_cm_stat.cms_rcvconnvc++;
3344 KB_FREEALL((KBuffer *)arg1);
3347 if (cop->co_state != COS_ACTIVE) {
3348 atm_cm_stat.cms_rcvconn++;
3349 KB_FREEALL((KBuffer *)arg1);
3353 (*cop->co_endpt->ep_sscop_data)
3354 (cop->co_toku, (KBuffer *)arg1, arg2);
3357 case SSCOP_UNITDATA_IND:
3361 KB_FREEALL((KBuffer *)arg1);
3366 log(LOG_ERR, "atm_cm_sscop_upper: unknown cmd 0x%x\n", cmd);
3372 * Register an ATM Endpoint Service
3374 * Every ATM endpoint service must register itself here before it can
3375 * issue or receive any connection requests.
3378 * epp pointer to endpoint definition structure
3381 * 0 registration successful
3382 * errno registration failed - reason indicated
3386 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;