2 * ===================================
3 * HARP | Host ATM Research Platform
4 * ===================================
7 * This Host ATM Research Platform ("HARP") file (the "Software") is
8 * made available by Network Computing Services, Inc. ("NetworkCS")
9 * "AS IS". NetworkCS does not provide maintenance, improvements or
10 * support of any kind.
12 * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
13 * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
14 * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
15 * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
16 * In no event shall NetworkCS be responsible for any damages, including
17 * but not limited to consequential damages, arising from or relating to
18 * any use of the Software or related support.
20 * Copyright 1994-1998 Network Computing Services, Inc.
22 * Copies of this Software may be made, however, the above copyright
23 * notice must be reproduced on all copies.
30 * ATM Connection Manager
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD$");
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/errno.h>
40 #include <sys/socket.h>
41 #include <sys/socketvar.h>
42 #include <sys/syslog.h>
45 #include <netatm/port.h>
46 #include <netatm/queue.h>
47 #include <netatm/atm.h>
48 #include <netatm/atm_sys.h>
49 #include <netatm/atm_sap.h>
50 #include <netatm/atm_cm.h>
51 #include <netatm/atm_if.h>
52 #include <netatm/atm_vc.h>
53 #include <netatm/atm_sigmgr.h>
54 #include <netatm/atm_stack.h>
55 #include <netatm/atm_pcb.h>
56 #include <netatm/atm_var.h>
61 struct atm_cm_stat atm_cm_stat = {0};
66 static void atm_cm_cpcs_upper(int, void *, intptr_t, intptr_t);
67 static void atm_cm_saal_upper(int, void *, intptr_t, intptr_t);
68 static void atm_cm_sscop_upper(int, void *, intptr_t, intptr_t);
69 static Atm_connvc * atm_cm_share_llc(Atm_attributes *);
70 static void atm_cm_closeconn(Atm_connection *,
71 struct t_atm_cause *);
72 static void atm_cm_closevc(Atm_connvc *);
73 static void atm_cm_timeout(struct atm_time *);
74 static KTimeout_ret atm_cm_procinq(void *);
75 static void atm_cm_incall(Atm_connvc *);
76 static int atm_cm_accept(Atm_connvc *, Atm_connection *);
81 static Queue_t atm_connection_queue = {NULL};
82 static Queue_t atm_incoming_queue = {NULL};
83 static int atm_incoming_qlen = 0;
84 static Atm_connection *atm_listen_queue = NULL;
85 static struct attr_cause atm_cause_tmpl =
86 {T_ATM_PRESENT, {T_ATM_ITU_CODING, T_ATM_LOC_USER, 0, {0, 0, 0, 0}}};
89 * Stack commands, indexed by API
95 {CPCS_INIT, CPCS_TERM}, /* CMAPI_CPCS */
96 {SSCF_UNI_INIT, SSCF_UNI_TERM}, /* CMAPI_SAAL */
97 {SSCOP_INIT, SSCOP_TERM}, /* CMAPI_SSCOP */
100 static uma_zone_t atm_connection_zone;
101 static uma_zone_t atm_connvc_zone;
107 atm_connection_zone = uma_zcreate("atm connection",
108 sizeof(Atm_connection), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
109 if (atm_connection_zone == NULL)
110 panic("atm_connection_zone");
112 atm_connvc_zone = uma_zcreate("atm connvc", sizeof(Atm_connvc), NULL,
113 NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
114 if (atm_connvc_zone == NULL)
115 panic("atm_connvc_zone");
119 * Initiate Outgoing ATM Call
121 * Called by an endpoint service to create a new Connection Manager API
122 * instance and to initiate an outbound ATM connection. The endpoint
123 * provided token will be used in all further CM -> endpoint function
124 * calls, and the returned connection block pointer must be used in all
125 * subsequent endpoint -> CM function calls.
127 * If the return indicates that the connection setup has been immediately
128 * successful (typically only for PVCs and shared SVCs), then the connection
129 * is ready for data transmission.
131 * If the return indicates that the connection setup is still in progress,
132 * then the endpoint must wait for notification from the Connection Manager
133 * indicating the final status of the call setup. If the call setup completes
134 * successfully, then a "call connected" notification will be sent to the
135 * endpoint by the Connection Manager. If the call setup fails, then the
136 * endpoint will receive a "call cleared" notification.
138 * All connection instances must be freed with an atm_cm_release() call.
141 * epp pointer to endpoint definition structure
142 * token endpoint's connection instance token
143 * ap pointer to requested connection attributes
144 * copp pointer to location to return allocated connection block
147 * 0 connection has been successfully established
148 * EINPROGRESS connection establishment is in progress
149 * errno connection failed - reason indicated
153 atm_cm_connect(epp, token, ap, copp)
157 Atm_connection **copp;
163 struct stack_list sl;
164 void (*upf)(int, void *, intptr_t, intptr_t);
165 int s, sli, err, err2;
171 * Get a connection block
172 * May be called from timeout - don't wait.
174 cop = uma_zalloc(atm_connection_zone, M_NOWAIT);
179 * Initialize connection info
182 cop->co_toku = token;
185 * Initialize stack list index
190 * Validate and extract useful attribute information
194 * Must specify a network interface (validated below)
196 if (ap->nif == NULL) {
207 upf = atm_cm_cpcs_upper;
211 sl.sl_sap[sli++] = SAP_SSCF_UNI;
212 sl.sl_sap[sli++] = SAP_SSCOP;
213 upf = atm_cm_saal_upper;
217 sl.sl_sap[sli++] = SAP_SSCOP;
218 upf = atm_cm_sscop_upper;
229 if (ap->aal.tag != T_ATM_PRESENT) {
234 switch (ap->aal.type) {
237 sl.sl_sap[sli++] = SAP_CPCS_AAL5;
238 sl.sl_sap[sli++] = SAP_SAR_AAL5;
239 sl.sl_sap[sli++] = SAP_ATM;
243 sl.sl_sap[sli++] = SAP_CPCS_AAL3_4;
244 sl.sl_sap[sli++] = SAP_SAR_AAL3_4;
245 sl.sl_sap[sli++] = SAP_ATM;
254 * Broadband Bearer Attributes
256 if (ap->bearer.tag != T_ATM_PRESENT) {
261 switch (ap->bearer.v.connection_configuration) {
264 cop->co_flags |= COF_P2P;
267 case T_ATM_1_TO_MANY:
269 cop->co_flags |= COF_P2MP;
279 * Logical Link Control Attributes
281 if (ap->llc.tag == T_ATM_PRESENT) {
282 if ((ap->blli.tag_l2 != T_ATM_PRESENT) ||
283 (ap->blli.v.layer_2_protocol.ID_type != T_ATM_SIMPLE_ID) ||
284 (ap->blli.v.layer_2_protocol.ID.simple_ID !=
285 T_ATM_BLLI2_I8802) ||
286 (ap->llc.v.llc_len < T_ATM_LLC_MIN_LEN) ||
287 (ap->llc.v.llc_len > T_ATM_LLC_MAX_LEN)) {
291 cop->co_mpx = ATM_ENC_LLC;
292 cop->co_llc = ap->llc;
294 cop->co_mpx = ATM_ENC_NULL;
297 * Called Party Attributes
299 if (ap->called.tag != T_ATM_PRESENT) {
304 if ((ap->called.addr.address_format == T_ATM_ABSENT) ||
305 (ap->called.addr.address_length == 0)) {
311 * Calling Party Attributes
313 if (ap->calling.tag != T_ATM_ABSENT) {
319 * Quality of Service Attributes
321 if (ap->qos.tag != T_ATM_PRESENT) {
327 * Terminate stack list
334 * Let multiplexors decide whether we need a new VCC
336 switch (cop->co_mpx) {
340 * All of these connections require a new VCC
346 * See if we can share an existing LLC connection
348 cvp = atm_cm_share_llc(ap);
353 * We've got a connection to share
355 cop->co_connvc = cvp;
356 if (cvp->cvc_state == CVCS_ACTIVE) {
357 cop->co_state = COS_ACTIVE;
360 cop->co_state = COS_OUTCONN;
363 LINK2TAIL(cop, Atm_connection, cvp->cvc_conn->co_mxh, co_next);
364 cop->co_mxh = cvp->cvc_conn->co_mxh;
371 panic("atm_cm_connect: unknown mpx");
375 * If we get here, it means we need to create
376 * a new VCC for this connection
380 * Validate that network interface is registered and that
381 * a signalling manager is attached
383 for (pip = atm_interface_head; pip != NULL; pip = pip->pif_next) {
385 for (nip = pip->pif_nif; nip; nip = nip->nif_pnext) {
397 if ((smp = pip->pif_sigmgr) == NULL) {
403 * Get a connection VCC block
404 * May be called from timeouts - don't wait.
406 cvp = uma_zalloc(atm_connvc_zone, M_NOWAIT);
413 * Save VCC attributes
416 cvp->cvc_flags |= CVCF_CALLER;
419 * Link the control blocks
421 cop->co_connvc = cvp;
423 cvp->cvc_sigmgr = smp;
426 * Create a service stack
428 err = atm_create_stack(cvp, &sl, upf);
430 cvp->cvc_state = CVCS_CLEAR;
436 * Let the signalling manager handle the VCC creation
438 cvp->cvc_state = CVCS_SETUP;
439 switch ((*smp->sm_setup)(cvp, &err)) {
443 * Connection is fully setup - initialize the stack
445 cvp->cvc_state = CVCS_INIT;
446 STACK_CALL(atm_stackcmds[ap->api].init, cvp->cvc_lower,
447 cvp->cvc_tokl, cvp, ap->api_init, 0, err2);
449 panic("atm_cm_connect: init");
451 if (cvp->cvc_flags & CVCF_ABORTING) {
453 * Someone on the stack bailed out...schedule the
454 * VCC and stack termination
460 * Everything looks fine from here
462 cvp->cvc_state = CVCS_ACTIVE;
463 cop->co_state = COS_ACTIVE;
469 * Terminate stack and clean up before we leave
471 cvp->cvc_state = CVCS_CLEAR;
475 case CALL_PROCEEDING:
477 * We'll just wait for final call status
479 cop->co_state = COS_OUTCONN;
484 panic("atm_cm_connect: setup");
491 if (err && err != EINPROGRESS) {
493 * Undo any partial setup stuff
496 uma_zfree(atm_connection_zone, cop);
499 * Finish connection setup
502 cvp->cvc_flags |= CVCF_CONNQ;
503 ENQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
504 LINK2TAIL(cop, Atm_connection, cop->co_mxh, co_next);
513 * Listen for Incoming ATM Calls
515 * Called by an endpoint service in order to indicate its willingness to
516 * accept certain incoming calls. The types of calls which the endpoint
517 * is prepared to accept are specified in the Atm_attributes parameter.
519 * For each call which meets the criteria specified by the endpoint, the
520 * endpoint service will receive an incoming call notification via the
521 * endpoint's ep_incoming() function.
523 * To cancel the listening connection, the endpoint user should invoke
527 * epp pointer to endpoint definition structure
528 * token endpoint's listen instance token
529 * ap pointer to listening connection attributes
530 * copp pointer to location to return allocated connection block
533 * 0 listening connection installed
534 * errno listen failed - reason indicated
538 atm_cm_listen(epp, token, ap, copp)
542 Atm_connection **copp;
550 * Get a connection block
552 cop = uma_zalloc(atm_connection_zone, M_WAITOK);
557 * Initialize connection info
560 cop->co_toku = token;
564 * Validate and extract useful attribute information
585 switch (ap->aal.tag) {
589 switch (ap->aal.type) {
611 * Broadband High Layer Information Attributes
613 switch (ap->bhli.tag) {
626 * Broadband Low Layer Information Attributes
628 switch (ap->blli.tag_l2) {
640 switch (ap->blli.tag_l3) {
653 * Logical Link Control Attributes
655 switch (ap->llc.tag) {
658 if ((ap->blli.tag_l2 != T_ATM_PRESENT) ||
659 (ap->blli.v.layer_2_protocol.ID_type != T_ATM_SIMPLE_ID) ||
660 (ap->blli.v.layer_2_protocol.ID.simple_ID !=
661 T_ATM_BLLI2_I8802) ||
662 (ap->llc.v.llc_len < T_ATM_LLC_MIN_LEN) ||
663 (ap->llc.v.llc_len > T_ATM_LLC_MAX_LEN)) {
667 cop->co_mpx = ATM_ENC_LLC;
668 cop->co_llc = ap->llc;
673 cop->co_mpx = ATM_ENC_NULL;
682 * Called Party Attributes
684 switch (ap->called.tag) {
687 switch (ap->called.addr.address_format) {
690 ap->called.tag = T_ATM_ABSENT;
709 * Get an attribute block and save listening attributes
711 cop->co_lattr = uma_zalloc(atm_attributes_zone, M_WAITOK | M_ZERO);
712 if (cop->co_lattr == NULL) {
716 *cop->co_lattr = *ap;
719 * Now try to register the listening connection
722 if (atm_cm_match(cop->co_lattr, NULL) != NULL) {
724 * Can't have matching listeners
729 cop->co_state = COS_LISTEN;
730 LINK2TAIL(cop, Atm_connection, atm_listen_queue, co_next);
738 * Undo any partial setup stuff
742 uma_zfree(atm_attributes_zone, cop->co_lattr);
743 uma_zfree(atm_connection_zone, cop);
747 * Finish connection setup
756 * Add to LLC Connection
758 * Called by an endpoint service to create a new Connection Manager API
759 * instance to be associated with an LLC-multiplexed connection instance
760 * which has been previously created. The endpoint provided token will
761 * be used in all further CM -> endpoint function calls, and the returned
762 * connection block pointer must be used in all subsequent endpoint -> CM
765 * If the return indicates that the connection setup has been immediately
766 * successful, then the connection is ready for data transmission.
768 * If the return indicates that the connection setup is still in progress,
769 * then the endpoint must wait for notification from the Connection Manager
770 * indicating the final status of the call setup. If the call setup completes
771 * successfully, then a "call connected" notification will be sent to the
772 * endpoint by the Connection Manager. If the call setup fails, then the
773 * endpoint will receive a "call cleared" notification.
775 * All connection instances must be freed with an atm_cm_release() call.
778 * epp pointer to endpoint definition structure
779 * token endpoint's connection instance token
780 * llc pointer to llc attributes for new connection
781 * ecop pointer to existing connection block
782 * copp pointer to location to return allocated connection block
785 * 0 connection has been successfully established
786 * EINPROGRESS connection establishment is in progress
787 * errno addllc failed - reason indicated
791 atm_cm_addllc(epp, token, llc, ecop, copp)
794 struct attr_llc *llc;
795 Atm_connection *ecop;
796 Atm_connection **copp;
798 Atm_connection *cop, *cop2;
805 * Check out requested LLC attributes
807 if ((llc->tag != T_ATM_PRESENT) ||
808 ((llc->v.flags & T_ATM_LLC_SHARING) == 0) ||
809 (llc->v.llc_len < T_ATM_LLC_MIN_LEN) ||
810 (llc->v.llc_len > T_ATM_LLC_MAX_LEN))
814 * Get a connection block
815 * May be called from netisr - don't wait.
817 cop = uma_zalloc(atm_connection_zone, M_NOWAIT);
822 * Initialize connection info
825 cop->co_toku = token;
831 * Ensure that supplied connection is really valid
834 for (cvp = Q_HEAD(atm_connection_queue, Atm_connvc); cvp;
835 cvp = Q_NEXT(cvp, Atm_connvc, cvc_q)) {
836 for (cop2 = cvp->cvc_conn; cop2; cop2 = cop2->co_next) {
848 switch (ecop->co_state) {
865 * Connection must be LLC multiplexed and shared
867 if ((ecop->co_mpx != ATM_ENC_LLC) ||
868 ((ecop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0)) {
874 * This new LLC header must be unique for this VCC
878 int i = MIN(llc->v.llc_len, cop2->co_llc.v.llc_len);
880 if (bcmp(llc->v.llc_info, cop2->co_llc.v.llc_info, i) == 0) {
885 cop2 = cop2->co_next;
889 * Everything seems to check out
891 cop->co_flags = ecop->co_flags;
892 cop->co_state = ecop->co_state;
893 cop->co_mpx = ecop->co_mpx;
894 cop->co_connvc = ecop->co_connvc;
896 LINK2TAIL(cop, Atm_connection, ecop->co_mxh, co_next);
897 cop->co_mxh = ecop->co_mxh;
902 if (err && err != EINPROGRESS) {
904 * Undo any partial setup stuff
907 uma_zfree(atm_connection_zone, cop);
910 * Pass new connection back to caller
922 * cop pointer to connection block
923 * id identifier for party to be added
924 * addr address of party to be added
927 * 0 addparty successful
928 * errno addparty failed - reason indicated
932 atm_cm_addparty(cop, id, addr)
935 struct t_atm_sap *addr;
945 * cop pointer to connection block
946 * id identifier for party to be added
947 * cause pointer to cause of drop
950 * 0 dropparty successful
951 * errno dropparty failed - reason indicated
955 atm_cm_dropparty(cop, id, cause)
958 struct t_atm_cause *cause;
965 * Release Connection Resources
967 * Called by the endpoint service in order to terminate an ATM connection
968 * and to release all system resources for the connection. This function
969 * must be called for every allocated connection instance and must only
970 * be called by the connection's owner.
973 * cop pointer to connection block
974 * cause pointer to cause of release
977 * 0 release successful
978 * errno release failed - reason indicated
982 atm_cm_release(cop, cause)
984 struct t_atm_cause *cause;
992 * First, a quick state validation check
994 switch (cop->co_state) {
1002 * Break link to user
1004 cop->co_toku = NULL;
1012 panic("atm_cm_release: bogus conn state");
1016 * Check out the VCC state too
1018 if ((cvp = cop->co_connvc) != NULL) {
1020 switch (cvp->cvc_state) {
1037 panic("atm_cm_release: bogus connvc state");
1041 * If we're the only connection, terminate the VCC
1043 if ((cop->co_mxh == cop) && (cop->co_next == NULL)) {
1044 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
1045 cvp->cvc_attr.cause.v = *cause;
1046 atm_cm_closevc(cvp);
1051 * Now get rid of the connection
1053 atm_cm_closeconn(cop, cause);
1060 * Abort an ATM Connection VCC
1062 * This function allows any non-owner kernel entity to request an
1063 * immediate termination of an ATM VCC. This will normally be called
1064 * when encountering a catastrophic error condition that cannot be
1065 * resolved via the available stack protocols. The connection manager
1066 * will schedule the connection's termination, including notifying the
1067 * connection owner of the termination.
1069 * This function should only be called by a stack entity instance. After
1070 * calling the function, the caller should set a protocol state which just
1071 * waits for a <sap>_TERM stack command to be delivered.
1074 * cvp pointer to connection VCC block
1075 * cause pointer to cause of abort
1078 * 0 abort successful
1079 * errno abort failed - reason indicated
1083 atm_cm_abort(cvp, cause)
1085 struct t_atm_cause *cause;
1087 ATM_DEBUG2("atm_cm_abort: cvp=%p cause=%d\n",
1088 cvp, cause->cause_value);
1091 * Note that we're aborting
1093 cvp->cvc_flags |= CVCF_ABORTING;
1095 switch (cvp->cvc_state) {
1099 * In-line code will handle this
1101 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
1102 cvp->cvc_attr.cause.v = *cause;
1109 * Schedule connection termination, since we want
1110 * to avoid any sequencing interactions
1112 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
1113 cvp->cvc_attr.cause.v = *cause;
1122 * Ignore abort, as we're already terminating
1128 "atm_cm_abort: invalid state: cvp=%p, state=%d\n",
1129 cvp, cvp->cvc_state);
1136 * Incoming ATM Call Received
1138 * Called by a signalling manager to indicate that a new call request has
1139 * been received. This function will allocate and initialize the connection
1140 * manager control blocks and queue this call request. The call request
1141 * processing function, atm_cm_procinq(), will be scheduled to perform the
1145 * vcp pointer to incoming call's VCC control block
1146 * ap pointer to incoming call's attributes
1149 * 0 call queuing successful
1150 * errno call queuing failed - reason indicated
1154 atm_cm_incoming(vcp, ap)
1163 * Do some minimal attribute validation
1167 * Must specify a network interface
1169 if (ap->nif == NULL)
1175 if ((ap->aal.tag != T_ATM_PRESENT) ||
1176 ((ap->aal.type != ATM_AAL5) &&
1177 (ap->aal.type != ATM_AAL3_4)))
1181 * Traffic Descriptor Attributes
1183 if ((ap->traffic.tag != T_ATM_PRESENT) &&
1184 (ap->traffic.tag != T_ATM_ABSENT))
1188 * Broadband Bearer Attributes
1190 if ((ap->bearer.tag != T_ATM_PRESENT) ||
1191 ((ap->bearer.v.connection_configuration != T_ATM_1_TO_1) &&
1192 (ap->bearer.v.connection_configuration != T_ATM_1_TO_MANY)))
1196 * Broadband High Layer Attributes
1198 if ((ap->bhli.tag != T_ATM_PRESENT) &&
1199 (ap->bhli.tag != T_ATM_ABSENT))
1203 * Broadband Low Layer Attributes
1205 if ((ap->blli.tag_l2 != T_ATM_PRESENT) &&
1206 (ap->blli.tag_l2 != T_ATM_ABSENT))
1208 if ((ap->blli.tag_l3 != T_ATM_PRESENT) &&
1209 (ap->blli.tag_l3 != T_ATM_ABSENT))
1213 * Logical Link Control Attributes
1215 if (ap->llc.tag == T_ATM_PRESENT)
1217 ap->llc.tag = T_ATM_ANY;
1220 * Called Party Attributes
1222 if ((ap->called.tag != T_ATM_PRESENT) ||
1223 (ap->called.addr.address_format == T_ATM_ABSENT))
1225 if (ap->called.tag == T_ATM_ABSENT) {
1226 ap->called.addr.address_format = T_ATM_ABSENT;
1227 ap->called.addr.address_length = 0;
1228 ap->called.subaddr.address_format = T_ATM_ABSENT;
1229 ap->called.subaddr.address_length = 0;
1233 * Calling Party Attributes
1235 if ((ap->calling.tag != T_ATM_PRESENT) &&
1236 (ap->calling.tag != T_ATM_ABSENT))
1238 if (ap->calling.tag == T_ATM_ABSENT) {
1239 ap->calling.addr.address_format = T_ATM_ABSENT;
1240 ap->calling.addr.address_length = 0;
1241 ap->calling.subaddr.address_format = T_ATM_ABSENT;
1242 ap->calling.subaddr.address_length = 0;
1246 * Quality of Service Attributes
1248 if (ap->qos.tag != T_ATM_PRESENT)
1252 * Transit Network Attributes
1254 if ((ap->transit.tag != T_ATM_PRESENT) &&
1255 (ap->transit.tag != T_ATM_ABSENT))
1261 if ((ap->cause.tag != T_ATM_PRESENT) &&
1262 (ap->cause.tag != T_ATM_ABSENT))
1266 * Get a connection VCC block
1267 * May be called from netisr - don't wait.
1269 cvp = uma_zalloc(atm_connvc_zone, M_NOWAIT);
1276 * Initialize the control block
1279 cvp->cvc_sigmgr = vcp->vc_pif->pif_sigmgr;
1280 cvp->cvc_attr = *ap;
1281 cvp->cvc_state = CVCS_INCOMING;
1284 * Control queue length
1287 if (atm_incoming_qlen >= ATM_CALLQ_MAX) {
1294 * Queue request and schedule call processing function
1296 cvp->cvc_flags |= CVCF_INCOMQ;
1297 ENQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
1298 if (atm_incoming_qlen++ == 0) {
1299 timeout(atm_cm_procinq, (void *)0, 0);
1303 * Link for signalling manager
1305 vcp->vc_connvc = cvp;
1313 * Free any resources
1316 uma_zfree(atm_connvc_zone, cvp);
1322 * VCC Connected Notification
1324 * This function is called by a signalling manager as notification that a
1325 * VCC call setup has been successful.
1328 * cvp pointer to connection VCC block
1335 atm_cm_connected(cvp)
1338 Atm_connection *cop, *cop2;
1345 * Validate connection vcc
1347 switch (cvp->cvc_state) {
1351 * Initialize the stack
1353 cvp->cvc_state = CVCS_INIT;
1354 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].init,
1355 cvp->cvc_lower, cvp->cvc_tokl,
1356 cvp, cvp->cvc_attr.api_init, 0, err);
1358 panic("atm_cm_connected: init");
1360 if (cvp->cvc_flags & CVCF_ABORTING) {
1362 * Someone on the stack bailed out...notify all of the
1363 * connections and schedule the VCC termination
1365 cop = cvp->cvc_conn;
1367 cop2 = cop->co_next;
1368 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
1371 atm_cm_closevc(cvp);
1379 * Stack already initialized
1384 panic("atm_cm_connected: connvc state");
1388 * VCC is ready for action
1390 cvp->cvc_state = CVCS_ACTIVE;
1393 * Notify all connections that the call has completed
1395 cop = cvp->cvc_conn;
1397 cop2 = cop->co_next;
1399 switch (cop->co_state) {
1403 cop->co_state = COS_ACTIVE;
1404 (*cop->co_endpt->ep_connected)(cop->co_toku);
1409 * May get here if an ep_connected() call (from
1410 * above) results in an atm_cm_addllc() call for
1411 * the just connected connection.
1416 panic("atm_cm_connected: connection state");
1425 * Input any queued packets
1427 while ((m = cvp->cvc_rcvq) != NULL) {
1428 cvp->cvc_rcvq = KB_QNEXT(m);
1433 * Currently only supported for CPCS API
1435 atm_cm_cpcs_upper(CPCS_UNITDATA_SIG, cvp, (intptr_t)m, 0);
1443 * VCC Cleared Notification
1445 * This function is called by a signalling manager as notification that a
1446 * VCC call has been cleared. The cause information describing the reason
1447 * for the call clearing will be contained in the connection VCC attributes.
1450 * cvp pointer to connection VCC block
1460 Atm_connection *cop, *cop2;
1463 KASSERT((cvp->cvc_state != CVCS_FREE) && (cvp->cvc_state < CVCS_CLEAR),
1464 ("atm_cm_cleared: state sanity check failed"));
1466 cvp->cvc_state = CVCS_CLEAR;
1470 * Terminate all connections
1472 cop = cvp->cvc_conn;
1474 cop2 = cop->co_next;
1475 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
1480 * Clean up connection VCC
1482 atm_cm_closevc(cvp);
1491 * Process Incoming Call Queue
1493 * This function is scheduled by atm_cm_incoming() in order to process
1494 * all the entries on the incoming call queue.
1497 * arg argument passed on timeout() call
1511 * Only process incoming calls up to our quota
1513 while (cnt++ < ATM_CALLQ_MAX) {
1518 * Get next awaiting call
1520 cvp = Q_HEAD(atm_incoming_queue, Atm_connvc);
1525 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
1526 atm_incoming_qlen--;
1527 cvp->cvc_flags &= ~CVCF_INCOMQ;
1538 * If we've expended our quota, reschedule ourselves
1540 if (cnt >= ATM_CALLQ_MAX)
1541 timeout(atm_cm_procinq, (void *)0, 0);
1546 * Process Incoming Call
1548 * This function will search through the listening queue and try to find
1549 * matching endpoint(s) for the incoming call. If we find any, we will
1550 * notify the endpoint service(s) of the incoming call and will then
1551 * notify the signalling manager to progress the call to an active status.
1553 * If there are no listeners for the call, the signalling manager will be
1554 * notified of a call rejection.
1559 * cvp pointer to connection VCC for incoming call
1569 Atm_connection *cop, *lcop, *hcop;
1570 Atm_attributes attr;
1576 attr = cvp->cvc_attr;
1579 * Look for matching listeners
1581 while ((lcop = atm_cm_match(&attr, lcop)) != NULL) {
1585 * Need a new connection block
1586 * May be called from timeout - dont wait.
1588 cop = uma_zalloc(atm_connection_zone, M_NOWAIT);
1590 cvp->cvc_attr.cause = atm_cause_tmpl;
1591 cvp->cvc_attr.cause.v.cause_value =
1592 T_ATM_CAUSE_TEMPORARY_FAILURE;
1598 * Initialize connection from listener and incoming call
1601 cop->co_state = COS_INCONN;
1602 cop->co_mpx = lcop->co_mpx;
1603 cop->co_endpt = lcop->co_endpt;
1604 cop->co_llc = lcop->co_llc;
1606 switch (attr.bearer.v.connection_configuration) {
1609 cop->co_flags |= COF_P2P;
1612 case T_ATM_1_TO_MANY:
1614 cop->co_flags |= COF_P2MP;
1615 cvp->cvc_attr.cause = atm_cause_tmpl;
1616 cvp->cvc_attr.cause.v.cause_value =
1617 T_ATM_CAUSE_BEARER_CAPABILITY_NOT_IMPLEMENTED;
1622 * Notify endpoint of incoming call
1624 err = (*cop->co_endpt->ep_incoming)
1625 (lcop->co_toku, cop, &cvp->cvc_attr, &cop->co_toku);
1630 * Endpoint has accepted the call
1632 * Setup call attributes
1635 cvp->cvc_attr.api = lcop->co_lattr->api;
1636 cvp->cvc_attr.api_init =
1637 lcop->co_lattr->api_init;
1638 cvp->cvc_attr.llc = lcop->co_lattr->llc;
1640 cvp->cvc_attr.headin = MAX(cvp->cvc_attr.headin,
1641 lcop->co_lattr->headin);
1644 * Setup connection info and queueing
1646 cop->co_state = COS_INACCEPT;
1647 cop->co_connvc = cvp;
1648 LINK2TAIL(cop, Atm_connection, hcop, co_next);
1652 * Need a new connection block next time around
1658 * Endpoint refuses call
1665 * We're done looking for listeners
1669 * Someone actually wants the call, so notify
1670 * the signalling manager to continue
1672 cvp->cvc_flags |= CVCF_CONNQ;
1673 ENQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
1674 if (atm_cm_accept(cvp, hcop))
1679 * Nobody around to take the call
1681 cvp->cvc_attr.cause = atm_cause_tmpl;
1682 cvp->cvc_attr.cause.v.cause_value =
1683 T_ATM_CAUSE_INCOMPATIBLE_DESTINATION;
1688 * Clean up loose ends
1691 uma_zfree(atm_connection_zone, cop);
1694 * Call has been accepted
1700 * Call failed - notify any endpoints of the call failure
1704 * Clean up loose ends
1707 uma_zfree(atm_connection_zone, cop);
1709 if (cvp->cvc_attr.cause.tag != T_ATM_PRESENT) {
1710 cvp->cvc_attr.cause = atm_cause_tmpl;
1711 cvp->cvc_attr.cause.v.cause_value =
1712 T_ATM_CAUSE_UNSPECIFIED_NORMAL;
1716 Atm_connection *cop2 = cop->co_next;
1717 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
1722 * Tell the signalling manager to reject the call
1724 atm_cm_closevc(cvp);
1731 * Accept an Incoming ATM Call
1733 * Some endpoint service(s) wants to accept an incoming call, so the
1734 * signalling manager will be notified to attempt to progress the call
1735 * to an active status.
1737 * If the signalling manager indicates that connection activation has
1738 * been immediately successful, then all of the endpoints will be notified
1739 * that the connection is ready for data transmission.
1741 * If the return indicates that connection activation is still in progress,
1742 * then the endpoints must wait for notification from the Connection Manager
1743 * indicating the final status of the call setup. If the call setup completes
1744 * successfully, then a "call connected" notification will be sent to the
1745 * endpoints by the Connection Manager. If the call setup fails, then the
1746 * endpoints will receive a "call cleared" notification.
1751 * cvp pointer to connection VCC for incoming call
1752 * cop pointer to head of accepted connections
1755 * 0 connection has been successfully activated
1756 * errno accept failed - reason indicated
1760 atm_cm_accept(cvp, cop)
1762 Atm_connection *cop;
1764 struct stack_list sl;
1765 void (*upf)(int, void *, intptr_t, intptr_t);
1770 * Link vcc to connections
1772 cvp->cvc_conn = cop;
1775 * Initialize stack list index
1780 * Check out Data API
1782 switch (cvp->cvc_attr.api) {
1785 upf = atm_cm_cpcs_upper;
1789 sl.sl_sap[sli++] = SAP_SSCF_UNI;
1790 sl.sl_sap[sli++] = SAP_SSCOP;
1791 upf = atm_cm_saal_upper;
1795 sl.sl_sap[sli++] = SAP_SSCOP;
1796 upf = atm_cm_sscop_upper;
1806 switch (cvp->cvc_attr.aal.type) {
1809 sl.sl_sap[sli++] = SAP_CPCS_AAL5;
1810 sl.sl_sap[sli++] = SAP_SAR_AAL5;
1811 sl.sl_sap[sli++] = SAP_ATM;
1815 sl.sl_sap[sli++] = SAP_CPCS_AAL3_4;
1816 sl.sl_sap[sli++] = SAP_SAR_AAL3_4;
1817 sl.sl_sap[sli++] = SAP_ATM;
1822 * Terminate stack list
1827 * Create a service stack
1829 err = atm_create_stack(cvp, &sl, upf);
1835 * Let the signalling manager finish the VCC activation
1837 switch ((*cvp->cvc_sigmgr->sm_accept)(cvp->cvc_vcc, &err)) {
1839 case CALL_PROCEEDING:
1841 * Note that we're not finished yet
1846 case CALL_CONNECTED:
1848 * Initialize the stack now, even if the call isn't totally
1849 * active yet. We want to avoid the delay between getting
1850 * the "call connected" event and actually notifying the
1851 * adapter to accept cells on the new VCC - if the delay is
1852 * too long, then we end up dropping the first pdus sent by
1855 cvp->cvc_state = CVCS_INIT;
1856 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].init,
1857 cvp->cvc_lower, cvp->cvc_tokl, cvp,
1858 cvp->cvc_attr.api_init, 0, err2);
1860 panic("atm_cm_accept: init");
1862 if (cvp->cvc_flags & CVCF_ABORTING) {
1864 * Someone on the stack bailed out...schedule the
1865 * VCC and stack termination
1870 * Everything looks fine from here
1873 cvp->cvc_state = CVCS_ACCEPT;
1875 cvp->cvc_state = CVCS_ACTIVE;
1881 * Terminate stack and clean up before we leave
1883 cvp->cvc_state = CVCS_CLEAR;
1887 panic("atm_cm_accept: accept");
1893 * Call has been connected, notify endpoints
1896 Atm_connection *cop2 = cop->co_next;
1898 cop->co_state = COS_ACTIVE;
1899 (*cop->co_endpt->ep_connected)(cop->co_toku);
1903 } else if (err == EINPROGRESS) {
1905 * Call is still in progress, endpoint must wait
1911 * Let caller know we failed
1913 cvp->cvc_attr.cause = atm_cause_tmpl;
1914 cvp->cvc_attr.cause.v.cause_value =
1915 T_ATM_CAUSE_UNSPECIFIED_RESOURCE_UNAVAILABLE;
1923 * Match Attributes on Listening Queue
1925 * This function will attempt to match the supplied connection attributes
1926 * with one of the registered attributes in the listening queue. The pcop
1927 * argument may be supplied in order to allow multiple listeners to share
1928 * an incoming call (if supported by the listeners).
1933 * ap pointer to attributes to be matched
1934 * pcop pointer to the previously matched connection
1937 * addr connection with which a match was found
1942 atm_cm_match(ap, pcop)
1944 Atm_connection *pcop;
1946 Atm_connection *cop;
1947 Atm_attributes *lap;
1951 * If we've already matched a listener...
1955 * Make sure already matched listener supports sharing
1957 if ((pcop->co_mpx != ATM_ENC_LLC) ||
1958 ((pcop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0))
1962 * Position ourselves after the matched entry
1964 for (cop = atm_listen_queue; cop; cop = cop->co_next) {
1966 cop = pcop->co_next;
1972 * Start search at top of listening queue
1974 cop = atm_listen_queue;
1978 * Search through listening queue
1980 for (; cop; cop = cop->co_next) {
1982 lap = cop->co_lattr;
1985 * If we're trying to share, check that this entry allows it
1988 if ((cop->co_mpx != ATM_ENC_LLC) ||
1989 ((cop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0))
1994 * ALL "matchable" attributes must match
2000 if (lap->bhli.tag == T_ATM_ABSENT) {
2001 if (ap->bhli.tag == T_ATM_PRESENT)
2003 } else if (lap->bhli.tag == T_ATM_PRESENT) {
2004 if (ap->bhli.tag == T_ATM_ABSENT)
2006 if (ap->bhli.tag == T_ATM_PRESENT)
2007 if (bcmp(&lap->bhli.v, &ap->bhli.v,
2008 sizeof(struct t_atm_bhli)))
2015 if (lap->blli.tag_l2 == T_ATM_ABSENT) {
2016 if (ap->blli.tag_l2 == T_ATM_PRESENT)
2018 } else if (lap->blli.tag_l2 == T_ATM_PRESENT) {
2019 if (ap->blli.tag_l2 == T_ATM_ABSENT)
2021 if (ap->blli.tag_l2 == T_ATM_PRESENT) {
2022 if (bcmp(&lap->blli.v.layer_2_protocol.ID,
2023 &ap->blli.v.layer_2_protocol.ID,
2025 ap->blli.v.layer_2_protocol.ID)))
2033 if (lap->blli.tag_l3 == T_ATM_ABSENT) {
2034 if (ap->blli.tag_l3 == T_ATM_PRESENT)
2036 } else if (lap->blli.tag_l3 == T_ATM_PRESENT) {
2037 if (ap->blli.tag_l3 == T_ATM_ABSENT)
2039 if (ap->blli.tag_l3 == T_ATM_PRESENT) {
2040 if (bcmp(&lap->blli.v.layer_3_protocol.ID,
2041 &ap->blli.v.layer_3_protocol.ID,
2043 ap->blli.v.layer_3_protocol.ID)))
2051 if (lap->llc.tag == T_ATM_ABSENT) {
2052 if (ap->llc.tag == T_ATM_PRESENT)
2054 } else if (lap->llc.tag == T_ATM_PRESENT) {
2055 if (ap->llc.tag == T_ATM_ABSENT)
2057 if (ap->llc.tag == T_ATM_PRESENT) {
2058 int i = MIN(lap->llc.v.llc_len,
2061 if (bcmp(lap->llc.v.llc_info,
2062 ap->llc.v.llc_info, i))
2070 if (lap->aal.tag == T_ATM_ABSENT) {
2071 if (ap->aal.tag == T_ATM_PRESENT)
2073 } else if (lap->aal.tag == T_ATM_PRESENT) {
2074 if (ap->aal.tag == T_ATM_ABSENT)
2076 if (ap->aal.tag == T_ATM_PRESENT) {
2077 if (lap->aal.type != ap->aal.type)
2079 if (lap->aal.type == ATM_AAL5) {
2080 if (lap->aal.v.aal5.SSCS_type !=
2081 ap->aal.v.aal5.SSCS_type)
2084 if (lap->aal.v.aal4.SSCS_type !=
2085 ap->aal.v.aal4.SSCS_type)
2094 if (lap->called.tag == T_ATM_ABSENT) {
2095 if (ap->called.tag == T_ATM_PRESENT)
2097 } else if (lap->called.tag == T_ATM_PRESENT) {
2098 if (ap->called.tag == T_ATM_ABSENT)
2100 if (ap->called.tag == T_ATM_PRESENT) {
2101 if ((!ATM_ADDR_EQUAL(&lap->called.addr,
2102 &ap->called.addr)) ||
2103 (!ATM_ADDR_EQUAL(&lap->called.subaddr,
2104 &ap->called.subaddr)))
2110 * Found a full match - return it
2120 * Find Shareable LLC VCC
2122 * Given an endpoint-supplied connection attribute using LLC multiplexing,
2123 * this function will attempt to locate an existing connection which meets
2124 * the requirements of the supplied attributes.
2129 * ap pointer to requested attributes
2132 * addr shareable LLC connection VCC
2133 * 0 no shareable VCC available
2137 atm_cm_share_llc(ap)
2140 Atm_connection *cop;
2144 * Is requestor willing to share?
2146 if ((ap->llc.v.flags & T_ATM_LLC_SHARING) == 0)
2150 * Try to find a shareable connection
2152 for (cvp = Q_HEAD(atm_connection_queue, Atm_connvc); cvp;
2153 cvp = Q_NEXT(cvp, Atm_connvc, cvc_q)) {
2156 * Dont use terminating connections
2158 switch (cvp->cvc_state) {
2170 * Is connection LLC and shareable?
2172 if ((cvp->cvc_attr.llc.tag != T_ATM_PRESENT) ||
2173 ((cvp->cvc_attr.llc.v.flags & T_ATM_LLC_SHARING) == 0))
2177 * Match requested attributes with existing connection
2179 if (ap->nif != cvp->cvc_attr.nif)
2182 if ((ap->api != cvp->cvc_attr.api) ||
2183 (ap->api_init != cvp->cvc_attr.api_init))
2189 if (cvp->cvc_flags & CVCF_CALLER) {
2190 if ((!ATM_ADDR_EQUAL(&ap->called.addr,
2191 &cvp->cvc_attr.called.addr)) ||
2192 (!ATM_ADDR_EQUAL(&ap->called.subaddr,
2193 &cvp->cvc_attr.called.subaddr)))
2196 if (cvp->cvc_attr.calling.tag != T_ATM_PRESENT)
2198 if ((!ATM_ADDR_EQUAL(&ap->called.addr,
2199 &cvp->cvc_attr.calling.addr)) ||
2200 (!ATM_ADDR_EQUAL(&ap->called.subaddr,
2201 &cvp->cvc_attr.calling.subaddr)))
2208 if (ap->aal.type == ATM_AAL5) {
2209 struct t_atm_aal5 *ap5, *cv5;
2211 ap5 = &ap->aal.v.aal5;
2212 cv5 = &cvp->cvc_attr.aal.v.aal5;
2214 if ((cvp->cvc_attr.aal.type != ATM_AAL5) ||
2215 (ap5->SSCS_type != cv5->SSCS_type))
2218 if (cvp->cvc_flags & CVCF_CALLER) {
2219 if (ap5->forward_max_SDU_size >
2220 cv5->forward_max_SDU_size)
2223 if (ap5->forward_max_SDU_size >
2224 cv5->backward_max_SDU_size)
2228 struct t_atm_aal4 *ap4, *cv4;
2230 ap4 = &ap->aal.v.aal4;
2231 cv4 = &cvp->cvc_attr.aal.v.aal4;
2233 if ((cvp->cvc_attr.aal.type != ATM_AAL3_4) ||
2234 (ap4->SSCS_type != cv4->SSCS_type))
2237 if (cvp->cvc_flags & CVCF_CALLER) {
2238 if (ap4->forward_max_SDU_size >
2239 cv4->forward_max_SDU_size)
2242 if (ap4->forward_max_SDU_size >
2243 cv4->backward_max_SDU_size)
2249 * Traffic Descriptor
2251 if ((ap->traffic.tag != T_ATM_PRESENT) ||
2252 (cvp->cvc_attr.traffic.tag != T_ATM_PRESENT) ||
2253 (ap->traffic.v.best_effort != T_YES) ||
2254 (cvp->cvc_attr.traffic.v.best_effort != T_YES))
2260 if (ap->bearer.v.connection_configuration !=
2261 cvp->cvc_attr.bearer.v.connection_configuration)
2267 if (cvp->cvc_flags & CVCF_CALLER) {
2268 if ((ap->qos.v.forward.qos_class !=
2269 cvp->cvc_attr.qos.v.forward.qos_class) ||
2270 (ap->qos.v.backward.qos_class !=
2271 cvp->cvc_attr.qos.v.backward.qos_class))
2274 if ((ap->qos.v.forward.qos_class !=
2275 cvp->cvc_attr.qos.v.backward.qos_class) ||
2276 (ap->qos.v.backward.qos_class !=
2277 cvp->cvc_attr.qos.v.forward.qos_class))
2282 * The new LLC header must also be unique for this VCC
2284 for (cop = cvp->cvc_conn; cop; cop = cop->co_next) {
2285 int i = MIN(ap->llc.v.llc_len,
2286 cop->co_llc.v.llc_len);
2288 if (bcmp(ap->llc.v.llc_info,
2289 cop->co_llc.v.llc_info, i) == 0)
2294 * If no header overlaps, then we're done
2307 * This function will terminate a connection, including notifying the
2308 * user, if necessary, and freeing up control block memory. The caller
2309 * is responsible for managing the connection VCC.
2314 * cop pointer to connection block
2315 * cause pointer to cause of close
2322 atm_cm_closeconn(cop, cause)
2323 Atm_connection *cop;
2324 struct t_atm_cause *cause;
2328 * Decide whether user needs notification
2330 switch (cop->co_state) {
2338 * Yup, let 'em know connection is gone
2341 (*cop->co_endpt->ep_cleared)(cop->co_toku, cause);
2346 * Nope,they should know already
2351 panic("atm_cm_closeconn: bogus state");
2355 * Unlink connection from its queues
2357 switch (cop->co_state) {
2360 uma_zfree(atm_attributes_zone, cop->co_lattr);
2361 UNLINK(cop, Atm_connection, atm_listen_queue, co_next);
2366 * Remove connection from multiplexor queue
2368 if (cop->co_mxh != cop) {
2370 * Connection is down the chain, just unlink it
2372 UNLINK(cop, Atm_connection, cop->co_mxh, co_next);
2374 } else if (cop->co_next != NULL) {
2376 * Connection is at the head of a non-singleton chain,
2377 * so unlink and reset the chain head
2379 Atm_connection *t, *nhd;
2381 t = nhd = cop->co_next;
2387 nhd->co_connvc->cvc_conn = nhd;
2392 * Free the connection block
2394 cop->co_state = COS_FREE;
2395 uma_zfree(atm_connection_zone, cop);
2401 * Close Connection VCC
2403 * This function will terminate a connection VCC, including releasing the
2404 * the call to the signalling manager, terminating the VCC protocol stack,
2405 * and freeing up control block memory.
2410 * cvp pointer to connection VCC block
2423 * Break links with the connection block
2425 cvp->cvc_conn = NULL;
2428 * Cancel any running timer
2433 * Free queued packets
2435 while (cvp->cvc_rcvq) {
2439 cvp->cvc_rcvq = KB_QNEXT(m);
2445 * Unlink from any queues
2447 if (cvp->cvc_flags & CVCF_INCOMQ) {
2448 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
2449 atm_incoming_qlen--;
2450 cvp->cvc_flags &= ~CVCF_INCOMQ;
2452 } else if (cvp->cvc_flags & CVCF_CONNQ) {
2453 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
2454 cvp->cvc_flags &= ~CVCF_CONNQ;
2458 * Release the signalling call
2460 switch (cvp->cvc_state) {
2468 cvp->cvc_state = CVCS_RELEASE;
2469 switch ((*cvp->cvc_sigmgr->sm_release)
2470 (cvp->cvc_vcc, &err)) {
2474 * Looks good so far...
2478 case CALL_PROCEEDING:
2480 * We'll have to wait for the call to clear
2486 * If there's a memory shortage, retry later.
2487 * Otherwise who knows what's going on....
2489 if ((err == ENOMEM) || (err == ENOBUFS)) {
2490 CVC_TIMER(cvp, 1 * ATM_HZ);
2494 "atm_cm_closevc: release %d\n", err);
2503 cvp->cvc_state = CVCS_REJECT;
2504 switch ((*cvp->cvc_sigmgr->sm_reject)
2505 (cvp->cvc_vcc, &err)) {
2509 * Looks good so far...
2515 * If there's a memory shortage, retry later.
2516 * Otherwise who knows what's going on....
2518 if ((err == ENOMEM) || (err == ENOBUFS)) {
2519 CVC_TIMER(cvp, 1 * ATM_HZ);
2523 "atm_cm_closevc: reject %d\n", err);
2532 * No need for anything here
2537 panic("atm_cm_closevc: bogus state");
2541 * Now terminate the stack
2543 if (cvp->cvc_tokl) {
2544 cvp->cvc_state = CVCS_TERM;
2547 * Wait until stack is unwound before terminating
2549 if ((cvp->cvc_downcnt > 0) || (cvp->cvc_upcnt > 0)) {
2554 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].term,
2555 cvp->cvc_lower, cvp->cvc_tokl, cvp, 0, 0, err);
2557 cvp->cvc_tokl = NULL;
2561 * Let signalling manager finish up
2563 cvp->cvc_state = CVCS_FREE;
2565 (void) (*cvp->cvc_sigmgr->sm_free)(cvp->cvc_vcc);
2569 * Finally, free our own control blocks
2571 uma_zfree(atm_connvc_zone, cvp);
2577 * Process a Connection VCC timeout
2579 * Called when a previously scheduled cvc control block timer expires.
2580 * Processing will be based on the current cvc state.
2585 * tip pointer to cvc timer control block
2593 struct atm_time *tip;
2595 Atm_connection *cop, *cop2;
2599 * Back-off to cvc control block
2601 cvp = (Atm_connvc *)
2602 ((caddr_t)tip - (int)(&((Atm_connvc *)0)->cvc_time));
2605 * Process timeout based on protocol state
2607 switch (cvp->cvc_state) {
2615 if ((cvp->cvc_flags & CVCF_ABORTING) == 0)
2619 * Terminate all connections
2621 cop = cvp->cvc_conn;
2623 cop2 = cop->co_next;
2624 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
2631 atm_cm_closevc(cvp);
2639 * Retry failed operation
2641 atm_cm_closevc(cvp);
2647 "atm_cm_timeout: invalid state: cvp=%p, state=%d\n",
2648 cvp, cvp->cvc_state);
2654 * CPCS User Control Commands
2656 * This function is called by an endpoint user to pass a control command
2657 * across a CPCS data API. Mostly we just send these down the stack.
2660 * cmd stack command code
2661 * cop pointer to connection block
2665 * 0 command output successful
2666 * errno output failed - reason indicated
2670 atm_cm_cpcs_ctl(cmd, cop, arg)
2672 Atm_connection *cop;
2679 * Validate connection state
2681 if (cop->co_state != COS_ACTIVE) {
2686 cvp = cop->co_connvc;
2687 if (cvp->cvc_state != CVCS_ACTIVE) {
2692 if (cvp->cvc_attr.api != CMAPI_CPCS) {
2711 * This function is called by an endpoint user to output a data packet
2712 * across a CPCS data API. After we've validated the connection state, the
2713 * packet will be encapsulated (if necessary) and sent down the data stack.
2716 * cop pointer to connection block
2717 * m pointer to packet buffer chain to be output
2720 * 0 packet output successful
2721 * errno output failed - reason indicated
2725 atm_cm_cpcs_data(cop, m)
2726 Atm_connection *cop;
2730 struct attr_llc *llcp;
2736 * Validate connection state
2738 if (cop->co_state != COS_ACTIVE) {
2743 cvp = cop->co_connvc;
2744 if (cvp->cvc_state != CVCS_ACTIVE) {
2749 if (cvp->cvc_attr.api != CMAPI_CPCS) {
2755 * Add any packet encapsulation
2757 switch (cop->co_mpx) {
2767 * Need to add an LLC header
2769 llcp = &cop->co_llc;
2772 * See if there's room to add LLC header to front of packet.
2774 KB_HEADROOM(m, space);
2775 if (space < llcp->v.llc_len) {
2779 * We have to allocate another buffer and tack it
2780 * onto the front of the packet
2782 MGETHDR(n, KB_F_NOWAIT, KB_T_HEADER);
2787 KB_TAILALIGN(n, llcp->v.llc_len);
2792 * Header fits, just adjust buffer controls
2794 KB_HEADADJ(m, llcp->v.llc_len);
2798 * Add the LLC header
2800 KB_DATASTART(m, bp, void *);
2801 bcopy(llcp->v.llc_info, bp, llcp->v.llc_len);
2802 KB_PLENADJ(m, llcp->v.llc_len);
2806 panic("atm_cm_cpcs_data: mpx");
2810 * Finally, we can send the packet on its way
2812 STACK_CALL(CPCS_UNITDATA_INV, cvp->cvc_lower, cvp->cvc_tokl,
2813 cvp, (intptr_t)m, 0, err);
2821 * Process CPCS Stack Commands
2823 * This is the top of the CPCS API data stack. All upward stack commands
2824 * for the CPCS data API will be received and processed here.
2827 * cmd stack command code
2828 * tok session token (pointer to connection VCC control block)
2837 atm_cm_cpcs_upper(cmd, tok, arg1, arg2)
2843 Atm_connection *cop;
2844 Atm_connvc *cvp = tok;
2851 case CPCS_UNITDATA_SIG:
2855 m = (KBuffer *)arg1;
2857 if (cvp->cvc_state != CVCS_ACTIVE) {
2858 if (cvp->cvc_state == CVCS_ACCEPT) {
2862 * Queue up any packets received before sigmgr
2863 * notifies us of incoming call completion
2865 if (cvp->cvc_rcvqlen >= CVC_RCVQ_MAX) {
2867 atm_cm_stat.cms_rcvconnvc++;
2871 if (cvp->cvc_rcvq == NULL) {
2874 for (n = cvp->cvc_rcvq;
2875 KB_QNEXT(n) != NULL;
2884 atm_cm_stat.cms_rcvconnvc++;
2890 * Send the packet to the interface's bpf if this
2893 if (cvp->cvc_vcc != NULL &&
2894 cvp->cvc_vcc->vc_nif != NULL) {
2896 (struct ifnet *)cvp->cvc_vcc->vc_nif;
2902 * Locate packet's connection
2904 cop = cvp->cvc_conn;
2905 switch (cop->co_mpx) {
2909 * We're already there...
2915 * Find connection with matching LLC header
2917 if (KB_LEN(m) < T_ATM_LLC_MAX_LEN) {
2918 KB_PULLUP(m, T_ATM_LLC_MAX_LEN, m);
2920 atm_cm_stat.cms_llcdrop++;
2924 KB_DATASTART(m, bp, void *);
2929 if (bcmp(bp, cop->co_llc.v.llc_info,
2930 cop->co_llc.v.llc_len) == 0)
2939 * No connected user for this LLC
2942 atm_cm_stat.cms_llcid++;
2947 * Strip off the LLC header
2949 KB_HEADADJ(m, -cop->co_llc.v.llc_len);
2950 KB_PLENADJ(m, -cop->co_llc.v.llc_len);
2954 panic("atm_cm_cpcs_upper: mpx");
2958 * We've found our connection, so hand the packet off
2960 if (cop->co_state != COS_ACTIVE) {
2962 atm_cm_stat.cms_rcvconn++;
2965 (*cop->co_endpt->ep_cpcs_data)(cop->co_toku, m);
2968 case CPCS_UABORT_SIG:
2969 case CPCS_PABORT_SIG:
2971 * We don't support these (yet), so just FALLTHROUGH
2975 log(LOG_ERR, "atm_cm_cpcs_upper: unknown cmd 0x%x\n", cmd);
2981 * SAAL User Control Commands
2983 * This function is called by an endpoint user to pass a control command
2984 * across a SAAL data API. Mostly we just send these down the stack.
2987 * cmd stack command code
2988 * cop pointer to connection block
2992 * 0 command output successful
2993 * errno output failed - reason indicated
2997 atm_cm_saal_ctl(cmd, cop, arg)
2999 Atm_connection *cop;
3006 * Validate connection state
3008 if (cop->co_state != COS_ACTIVE) {
3013 cvp = cop->co_connvc;
3014 if (cvp->cvc_state != CVCS_ACTIVE) {
3019 if (cvp->cvc_attr.api != CMAPI_SAAL) {
3026 case SSCF_UNI_ESTABLISH_REQ:
3027 case SSCF_UNI_RELEASE_REQ:
3029 * Pass command down the stack
3031 STACK_CALL(cmd, cvp->cvc_lower, cvp->cvc_tokl, cvp,
3032 (intptr_t)arg, 0, err);
3047 * This function is called by an endpoint user to output a data packet
3048 * across a SAAL data API. After we've validated the connection state,
3049 * the packet will be sent down the data stack.
3052 * cop pointer to connection block
3053 * m pointer to packet buffer chain to be output
3056 * 0 packet output successful
3057 * errno output failed - reason indicated
3061 atm_cm_saal_data(cop, m)
3062 Atm_connection *cop;
3070 * Validate connection state
3072 if (cop->co_state != COS_ACTIVE) {
3077 cvp = cop->co_connvc;
3078 if (cvp->cvc_state != CVCS_ACTIVE) {
3083 if (cvp->cvc_attr.api != CMAPI_SAAL) {
3089 * Finally, we can send the packet on its way
3091 STACK_CALL(SSCF_UNI_DATA_REQ, cvp->cvc_lower, cvp->cvc_tokl,
3092 cvp, (intptr_t)m, 0, err);
3100 * Process SAAL Stack Commands
3102 * This is the top of the SAAL API data stack. All upward stack commands
3103 * for the SAAL data API will be received and processed here.
3106 * cmd stack command code
3107 * tok session token (pointer to connection VCC control block)
3116 atm_cm_saal_upper(cmd, tok, arg1, arg2)
3122 Atm_connection *cop;
3123 Atm_connvc *cvp = tok;
3128 case SSCF_UNI_ESTABLISH_IND:
3129 case SSCF_UNI_ESTABLISH_CNF:
3130 case SSCF_UNI_RELEASE_IND:
3131 case SSCF_UNI_RELEASE_CNF:
3135 cop = cvp->cvc_conn;
3136 if (cvp->cvc_state != CVCS_ACTIVE)
3138 if (cop->co_state != COS_ACTIVE)
3141 (*cop->co_endpt->ep_saal_ctl)(cmd, cop->co_toku, (void *)arg1);
3144 case SSCF_UNI_DATA_IND:
3148 cop = cvp->cvc_conn;
3149 if (cvp->cvc_state != CVCS_ACTIVE) {
3150 atm_cm_stat.cms_rcvconnvc++;
3151 KB_FREEALL((KBuffer *)arg1);
3154 if (cop->co_state != COS_ACTIVE) {
3155 atm_cm_stat.cms_rcvconn++;
3156 KB_FREEALL((KBuffer *)arg1);
3160 (*cop->co_endpt->ep_saal_data)(cop->co_toku, (KBuffer *)arg1);
3163 case SSCF_UNI_UNITDATA_IND:
3167 KB_FREEALL((KBuffer *)arg1);
3172 log(LOG_ERR, "atm_cm_saal_upper: unknown cmd 0x%x\n", cmd);
3178 * SSCOP User Control Commands
3180 * This function is called by an endpoint user to pass a control command
3181 * across a SSCOP data API. Mostly we just send these down the stack.
3184 * cmd stack command code
3185 * cop pointer to connection block
3190 * 0 command output successful
3191 * errno output failed - reason indicated
3195 atm_cm_sscop_ctl(cmd, cop, arg1, arg2)
3197 Atm_connection *cop;
3205 * Validate connection state
3207 if (cop->co_state != COS_ACTIVE) {
3212 cvp = cop->co_connvc;
3213 if (cvp->cvc_state != CVCS_ACTIVE) {
3218 if (cvp->cvc_attr.api != CMAPI_SSCOP) {
3225 case SSCOP_ESTABLISH_REQ:
3226 case SSCOP_ESTABLISH_RSP:
3227 case SSCOP_RELEASE_REQ:
3228 case SSCOP_RESYNC_REQ:
3229 case SSCOP_RESYNC_RSP:
3230 case SSCOP_RECOVER_RSP:
3231 case SSCOP_RETRIEVE_REQ:
3233 * Pass command down the stack
3235 STACK_CALL(cmd, cvp->cvc_lower, cvp->cvc_tokl, cvp,
3236 (intptr_t)arg1, (intptr_t)arg2, err);
3251 * This function is called by an endpoint user to output a data packet
3252 * across a SSCOP data API. After we've validated the connection state,
3253 * the packet will be encapsulated and sent down the data stack.
3256 * cop pointer to connection block
3257 * m pointer to packet buffer chain to be output
3260 * 0 packet output successful
3261 * errno output failed - reason indicated
3265 atm_cm_sscop_data(cop, m)
3266 Atm_connection *cop;
3274 * Validate connection state
3276 if (cop->co_state != COS_ACTIVE) {
3281 cvp = cop->co_connvc;
3282 if (cvp->cvc_state != CVCS_ACTIVE) {
3287 if (cvp->cvc_attr.api != CMAPI_SSCOP) {
3293 * Finally, we can send the packet on its way
3295 STACK_CALL(SSCOP_DATA_REQ, cvp->cvc_lower, cvp->cvc_tokl,
3296 cvp, (intptr_t)m, 0, err);
3304 * Process SSCOP Stack Commands
3306 * This is the top of the SSCOP API data stack. All upward stack commands
3307 * for the SSCOP data API will be received and processed here.
3310 * cmd stack command code
3311 * tok session token (pointer to connection VCC control block)
3320 atm_cm_sscop_upper(cmd, tok, arg1, arg2)
3326 Atm_connection *cop;
3327 Atm_connvc *cvp = tok;
3331 case SSCOP_ESTABLISH_IND:
3332 case SSCOP_ESTABLISH_CNF:
3333 case SSCOP_RELEASE_IND:
3334 case SSCOP_RESYNC_IND:
3338 cop = cvp->cvc_conn;
3339 if ((cvp->cvc_state != CVCS_ACTIVE) ||
3340 (cop->co_state != COS_ACTIVE)) {
3341 KB_FREEALL((KBuffer *)arg1);
3345 (*cop->co_endpt->ep_sscop_ctl)
3346 (cmd, cop->co_toku, (void *)arg1, (void *)arg2);
3349 case SSCOP_RELEASE_CNF:
3350 case SSCOP_RESYNC_CNF:
3351 case SSCOP_RECOVER_IND:
3352 case SSCOP_RETRIEVE_IND:
3353 case SSCOP_RETRIEVECMP_IND:
3357 cop = cvp->cvc_conn;
3358 if ((cvp->cvc_state != CVCS_ACTIVE) ||
3359 (cop->co_state != COS_ACTIVE))
3362 (*cop->co_endpt->ep_sscop_ctl)
3363 (cmd, cop->co_toku, (void *)arg1, (void *)arg2);
3366 case SSCOP_DATA_IND:
3370 cop = cvp->cvc_conn;
3371 if (cvp->cvc_state != CVCS_ACTIVE) {
3372 atm_cm_stat.cms_rcvconnvc++;
3373 KB_FREEALL((KBuffer *)arg1);
3376 if (cop->co_state != COS_ACTIVE) {
3377 atm_cm_stat.cms_rcvconn++;
3378 KB_FREEALL((KBuffer *)arg1);
3382 (*cop->co_endpt->ep_sscop_data)
3383 (cop->co_toku, (KBuffer *)arg1, arg2);
3386 case SSCOP_UNITDATA_IND:
3390 KB_FREEALL((KBuffer *)arg1);
3395 log(LOG_ERR, "atm_cm_sscop_upper: unknown cmd 0x%x\n", cmd);
3401 * Register an ATM Endpoint Service
3403 * Every ATM endpoint service must register itself here before it can
3404 * issue or receive any connection requests.
3407 * epp pointer to endpoint definition structure
3410 * 0 registration successful
3411 * errno registration failed - reason indicated
3415 atm_endpoint_register(epp)
3421 * See if we need to be initialized
3429 if (epp->ep_id > ENDPT_MAX) {
3433 if (atm_endpoints[epp->ep_id] != NULL) {
3439 * Add endpoint to list
3441 atm_endpoints[epp->ep_id] = epp;
3449 * De-register an ATM Endpoint Service
3451 * Each ATM endpoint service provider must de-register its registered
3452 * endpoint(s) before terminating. Specifically, loaded kernel modules
3453 * must de-register their services before unloading themselves.
3456 * epp pointer to endpoint definition structure
3459 * 0 de-registration successful
3460 * errno de-registration failed - reason indicated
3464 atm_endpoint_deregister(epp)
3472 if (epp->ep_id > ENDPT_MAX) {
3476 if (atm_endpoints[epp->ep_id] != epp) {
3482 * Remove endpoint from list
3484 atm_endpoints[epp->ep_id] = NULL;