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 * so optional socket pointer -- if present, will set listen state
528 * epp pointer to endpoint definition structure
529 * token endpoint's listen instance token
530 * ap pointer to listening connection attributes
531 * copp pointer to location to return allocated connection block
534 * 0 listening connection installed
535 * errno listen failed - reason indicated
539 atm_cm_listen(so, epp, token, ap, copp, backlog)
544 Atm_connection **copp;
553 * Get a connection block
555 cop = uma_zalloc(atm_connection_zone, M_WAITOK);
560 * Initialize connection info
563 cop->co_toku = token;
567 * Validate and extract useful attribute information
588 switch (ap->aal.tag) {
592 switch (ap->aal.type) {
614 * Broadband High Layer Information Attributes
616 switch (ap->bhli.tag) {
629 * Broadband Low Layer Information Attributes
631 switch (ap->blli.tag_l2) {
643 switch (ap->blli.tag_l3) {
656 * Logical Link Control Attributes
658 switch (ap->llc.tag) {
661 if ((ap->blli.tag_l2 != T_ATM_PRESENT) ||
662 (ap->blli.v.layer_2_protocol.ID_type != T_ATM_SIMPLE_ID) ||
663 (ap->blli.v.layer_2_protocol.ID.simple_ID !=
664 T_ATM_BLLI2_I8802) ||
665 (ap->llc.v.llc_len < T_ATM_LLC_MIN_LEN) ||
666 (ap->llc.v.llc_len > T_ATM_LLC_MAX_LEN)) {
670 cop->co_mpx = ATM_ENC_LLC;
671 cop->co_llc = ap->llc;
676 cop->co_mpx = ATM_ENC_NULL;
685 * Called Party Attributes
687 switch (ap->called.tag) {
690 switch (ap->called.addr.address_format) {
693 ap->called.tag = T_ATM_ABSENT;
712 * Get an attribute block and save listening attributes
714 cop->co_lattr = uma_zalloc(atm_attributes_zone, M_WAITOK | M_ZERO);
715 if (cop->co_lattr == NULL) {
719 *cop->co_lattr = *ap;
722 * Now try to register the listening connection
728 err = solisten_proto_check(so);
731 if (atm_cm_match(cop->co_lattr, NULL) != NULL) {
733 * Can't have matching listeners
738 cop->co_state = COS_LISTEN;
739 LINK2TAIL(cop, Atm_connection, atm_listen_queue, co_next);
741 solisten_proto(so, backlog);
751 * Undo any partial setup stuff
755 uma_zfree(atm_attributes_zone, cop->co_lattr);
756 uma_zfree(atm_connection_zone, cop);
760 * Finish connection setup
769 * Add to LLC Connection
771 * Called by an endpoint service to create a new Connection Manager API
772 * instance to be associated with an LLC-multiplexed connection instance
773 * which has been previously created. The endpoint provided token will
774 * be used in all further CM -> endpoint function calls, and the returned
775 * connection block pointer must be used in all subsequent endpoint -> CM
778 * If the return indicates that the connection setup has been immediately
779 * successful, then the connection is ready for data transmission.
781 * If the return indicates that the connection setup is still in progress,
782 * then the endpoint must wait for notification from the Connection Manager
783 * indicating the final status of the call setup. If the call setup completes
784 * successfully, then a "call connected" notification will be sent to the
785 * endpoint by the Connection Manager. If the call setup fails, then the
786 * endpoint will receive a "call cleared" notification.
788 * All connection instances must be freed with an atm_cm_release() call.
791 * epp pointer to endpoint definition structure
792 * token endpoint's connection instance token
793 * llc pointer to llc attributes for new connection
794 * ecop pointer to existing connection block
795 * copp pointer to location to return allocated connection block
798 * 0 connection has been successfully established
799 * EINPROGRESS connection establishment is in progress
800 * errno addllc failed - reason indicated
804 atm_cm_addllc(epp, token, llc, ecop, copp)
807 struct attr_llc *llc;
808 Atm_connection *ecop;
809 Atm_connection **copp;
811 Atm_connection *cop, *cop2;
818 * Check out requested LLC attributes
820 if ((llc->tag != T_ATM_PRESENT) ||
821 ((llc->v.flags & T_ATM_LLC_SHARING) == 0) ||
822 (llc->v.llc_len < T_ATM_LLC_MIN_LEN) ||
823 (llc->v.llc_len > T_ATM_LLC_MAX_LEN))
827 * Get a connection block
828 * May be called from netisr - don't wait.
830 cop = uma_zalloc(atm_connection_zone, M_NOWAIT);
835 * Initialize connection info
838 cop->co_toku = token;
844 * Ensure that supplied connection is really valid
847 for (cvp = Q_HEAD(atm_connection_queue, Atm_connvc); cvp;
848 cvp = Q_NEXT(cvp, Atm_connvc, cvc_q)) {
849 for (cop2 = cvp->cvc_conn; cop2; cop2 = cop2->co_next) {
861 switch (ecop->co_state) {
878 * Connection must be LLC multiplexed and shared
880 if ((ecop->co_mpx != ATM_ENC_LLC) ||
881 ((ecop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0)) {
887 * This new LLC header must be unique for this VCC
891 int i = MIN(llc->v.llc_len, cop2->co_llc.v.llc_len);
893 if (bcmp(llc->v.llc_info, cop2->co_llc.v.llc_info, i) == 0) {
898 cop2 = cop2->co_next;
902 * Everything seems to check out
904 cop->co_flags = ecop->co_flags;
905 cop->co_state = ecop->co_state;
906 cop->co_mpx = ecop->co_mpx;
907 cop->co_connvc = ecop->co_connvc;
909 LINK2TAIL(cop, Atm_connection, ecop->co_mxh, co_next);
910 cop->co_mxh = ecop->co_mxh;
915 if (err && err != EINPROGRESS) {
917 * Undo any partial setup stuff
920 uma_zfree(atm_connection_zone, cop);
923 * Pass new connection back to caller
935 * cop pointer to connection block
936 * id identifier for party to be added
937 * addr address of party to be added
940 * 0 addparty successful
941 * errno addparty failed - reason indicated
945 atm_cm_addparty(cop, id, addr)
948 struct t_atm_sap *addr;
958 * cop pointer to connection block
959 * id identifier for party to be added
960 * cause pointer to cause of drop
963 * 0 dropparty successful
964 * errno dropparty failed - reason indicated
968 atm_cm_dropparty(cop, id, cause)
971 struct t_atm_cause *cause;
978 * Release Connection Resources
980 * Called by the endpoint service in order to terminate an ATM connection
981 * and to release all system resources for the connection. This function
982 * must be called for every allocated connection instance and must only
983 * be called by the connection's owner.
986 * cop pointer to connection block
987 * cause pointer to cause of release
990 * 0 release successful
991 * errno release failed - reason indicated
995 atm_cm_release(cop, cause)
997 struct t_atm_cause *cause;
1005 * First, a quick state validation check
1007 switch (cop->co_state) {
1015 * Break link to user
1017 cop->co_toku = NULL;
1025 panic("atm_cm_release: bogus conn state");
1029 * Check out the VCC state too
1031 if ((cvp = cop->co_connvc) != NULL) {
1033 switch (cvp->cvc_state) {
1050 panic("atm_cm_release: bogus connvc state");
1054 * If we're the only connection, terminate the VCC
1056 if ((cop->co_mxh == cop) && (cop->co_next == NULL)) {
1057 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
1058 cvp->cvc_attr.cause.v = *cause;
1059 atm_cm_closevc(cvp);
1064 * Now get rid of the connection
1066 atm_cm_closeconn(cop, cause);
1073 * Abort an ATM Connection VCC
1075 * This function allows any non-owner kernel entity to request an
1076 * immediate termination of an ATM VCC. This will normally be called
1077 * when encountering a catastrophic error condition that cannot be
1078 * resolved via the available stack protocols. The connection manager
1079 * will schedule the connection's termination, including notifying the
1080 * connection owner of the termination.
1082 * This function should only be called by a stack entity instance. After
1083 * calling the function, the caller should set a protocol state which just
1084 * waits for a <sap>_TERM stack command to be delivered.
1087 * cvp pointer to connection VCC block
1088 * cause pointer to cause of abort
1091 * 0 abort successful
1092 * errno abort failed - reason indicated
1096 atm_cm_abort(cvp, cause)
1098 struct t_atm_cause *cause;
1100 ATM_DEBUG2("atm_cm_abort: cvp=%p cause=%d\n",
1101 cvp, cause->cause_value);
1104 * Note that we're aborting
1106 cvp->cvc_flags |= CVCF_ABORTING;
1108 switch (cvp->cvc_state) {
1112 * In-line code will handle this
1114 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
1115 cvp->cvc_attr.cause.v = *cause;
1122 * Schedule connection termination, since we want
1123 * to avoid any sequencing interactions
1125 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
1126 cvp->cvc_attr.cause.v = *cause;
1135 * Ignore abort, as we're already terminating
1141 "atm_cm_abort: invalid state: cvp=%p, state=%d\n",
1142 cvp, cvp->cvc_state);
1149 * Incoming ATM Call Received
1151 * Called by a signalling manager to indicate that a new call request has
1152 * been received. This function will allocate and initialize the connection
1153 * manager control blocks and queue this call request. The call request
1154 * processing function, atm_cm_procinq(), will be scheduled to perform the
1158 * vcp pointer to incoming call's VCC control block
1159 * ap pointer to incoming call's attributes
1162 * 0 call queuing successful
1163 * errno call queuing failed - reason indicated
1167 atm_cm_incoming(vcp, ap)
1176 * Do some minimal attribute validation
1180 * Must specify a network interface
1182 if (ap->nif == NULL)
1188 if ((ap->aal.tag != T_ATM_PRESENT) ||
1189 ((ap->aal.type != ATM_AAL5) &&
1190 (ap->aal.type != ATM_AAL3_4)))
1194 * Traffic Descriptor Attributes
1196 if ((ap->traffic.tag != T_ATM_PRESENT) &&
1197 (ap->traffic.tag != T_ATM_ABSENT))
1201 * Broadband Bearer Attributes
1203 if ((ap->bearer.tag != T_ATM_PRESENT) ||
1204 ((ap->bearer.v.connection_configuration != T_ATM_1_TO_1) &&
1205 (ap->bearer.v.connection_configuration != T_ATM_1_TO_MANY)))
1209 * Broadband High Layer Attributes
1211 if ((ap->bhli.tag != T_ATM_PRESENT) &&
1212 (ap->bhli.tag != T_ATM_ABSENT))
1216 * Broadband Low Layer Attributes
1218 if ((ap->blli.tag_l2 != T_ATM_PRESENT) &&
1219 (ap->blli.tag_l2 != T_ATM_ABSENT))
1221 if ((ap->blli.tag_l3 != T_ATM_PRESENT) &&
1222 (ap->blli.tag_l3 != T_ATM_ABSENT))
1226 * Logical Link Control Attributes
1228 if (ap->llc.tag == T_ATM_PRESENT)
1230 ap->llc.tag = T_ATM_ANY;
1233 * Called Party Attributes
1235 if ((ap->called.tag != T_ATM_PRESENT) ||
1236 (ap->called.addr.address_format == T_ATM_ABSENT))
1238 if (ap->called.tag == T_ATM_ABSENT) {
1239 ap->called.addr.address_format = T_ATM_ABSENT;
1240 ap->called.addr.address_length = 0;
1241 ap->called.subaddr.address_format = T_ATM_ABSENT;
1242 ap->called.subaddr.address_length = 0;
1246 * Calling Party Attributes
1248 if ((ap->calling.tag != T_ATM_PRESENT) &&
1249 (ap->calling.tag != T_ATM_ABSENT))
1251 if (ap->calling.tag == T_ATM_ABSENT) {
1252 ap->calling.addr.address_format = T_ATM_ABSENT;
1253 ap->calling.addr.address_length = 0;
1254 ap->calling.subaddr.address_format = T_ATM_ABSENT;
1255 ap->calling.subaddr.address_length = 0;
1259 * Quality of Service Attributes
1261 if (ap->qos.tag != T_ATM_PRESENT)
1265 * Transit Network Attributes
1267 if ((ap->transit.tag != T_ATM_PRESENT) &&
1268 (ap->transit.tag != T_ATM_ABSENT))
1274 if ((ap->cause.tag != T_ATM_PRESENT) &&
1275 (ap->cause.tag != T_ATM_ABSENT))
1279 * Get a connection VCC block
1280 * May be called from netisr - don't wait.
1282 cvp = uma_zalloc(atm_connvc_zone, M_NOWAIT);
1289 * Initialize the control block
1292 cvp->cvc_sigmgr = vcp->vc_pif->pif_sigmgr;
1293 cvp->cvc_attr = *ap;
1294 cvp->cvc_state = CVCS_INCOMING;
1297 * Control queue length
1300 if (atm_incoming_qlen >= ATM_CALLQ_MAX) {
1307 * Queue request and schedule call processing function
1309 cvp->cvc_flags |= CVCF_INCOMQ;
1310 ENQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
1311 if (atm_incoming_qlen++ == 0) {
1312 timeout(atm_cm_procinq, (void *)0, 0);
1316 * Link for signalling manager
1318 vcp->vc_connvc = cvp;
1326 * Free any resources
1329 uma_zfree(atm_connvc_zone, cvp);
1335 * VCC Connected Notification
1337 * This function is called by a signalling manager as notification that a
1338 * VCC call setup has been successful.
1341 * cvp pointer to connection VCC block
1348 atm_cm_connected(cvp)
1351 Atm_connection *cop, *cop2;
1358 * Validate connection vcc
1360 switch (cvp->cvc_state) {
1364 * Initialize the stack
1366 cvp->cvc_state = CVCS_INIT;
1367 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].init,
1368 cvp->cvc_lower, cvp->cvc_tokl,
1369 cvp, cvp->cvc_attr.api_init, 0, err);
1371 panic("atm_cm_connected: init");
1373 if (cvp->cvc_flags & CVCF_ABORTING) {
1375 * Someone on the stack bailed out...notify all of the
1376 * connections and schedule the VCC termination
1378 cop = cvp->cvc_conn;
1380 cop2 = cop->co_next;
1381 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
1384 atm_cm_closevc(cvp);
1392 * Stack already initialized
1397 panic("atm_cm_connected: connvc state");
1401 * VCC is ready for action
1403 cvp->cvc_state = CVCS_ACTIVE;
1406 * Notify all connections that the call has completed
1408 cop = cvp->cvc_conn;
1410 cop2 = cop->co_next;
1412 switch (cop->co_state) {
1416 cop->co_state = COS_ACTIVE;
1417 (*cop->co_endpt->ep_connected)(cop->co_toku);
1422 * May get here if an ep_connected() call (from
1423 * above) results in an atm_cm_addllc() call for
1424 * the just connected connection.
1429 panic("atm_cm_connected: connection state");
1438 * Input any queued packets
1440 while ((m = cvp->cvc_rcvq) != NULL) {
1441 cvp->cvc_rcvq = KB_QNEXT(m);
1446 * Currently only supported for CPCS API
1448 atm_cm_cpcs_upper(CPCS_UNITDATA_SIG, cvp, (intptr_t)m, 0);
1456 * VCC Cleared Notification
1458 * This function is called by a signalling manager as notification that a
1459 * VCC call has been cleared. The cause information describing the reason
1460 * for the call clearing will be contained in the connection VCC attributes.
1463 * cvp pointer to connection VCC block
1473 Atm_connection *cop, *cop2;
1476 KASSERT((cvp->cvc_state != CVCS_FREE) && (cvp->cvc_state < CVCS_CLEAR),
1477 ("atm_cm_cleared: state sanity check failed"));
1479 cvp->cvc_state = CVCS_CLEAR;
1483 * Terminate all connections
1485 cop = cvp->cvc_conn;
1487 cop2 = cop->co_next;
1488 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
1493 * Clean up connection VCC
1495 atm_cm_closevc(cvp);
1504 * Process Incoming Call Queue
1506 * This function is scheduled by atm_cm_incoming() in order to process
1507 * all the entries on the incoming call queue.
1510 * arg argument passed on timeout() call
1524 * Only process incoming calls up to our quota
1526 while (cnt++ < ATM_CALLQ_MAX) {
1531 * Get next awaiting call
1533 cvp = Q_HEAD(atm_incoming_queue, Atm_connvc);
1538 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
1539 atm_incoming_qlen--;
1540 cvp->cvc_flags &= ~CVCF_INCOMQ;
1551 * If we've expended our quota, reschedule ourselves
1553 if (cnt >= ATM_CALLQ_MAX)
1554 timeout(atm_cm_procinq, (void *)0, 0);
1559 * Process Incoming Call
1561 * This function will search through the listening queue and try to find
1562 * matching endpoint(s) for the incoming call. If we find any, we will
1563 * notify the endpoint service(s) of the incoming call and will then
1564 * notify the signalling manager to progress the call to an active status.
1566 * If there are no listeners for the call, the signalling manager will be
1567 * notified of a call rejection.
1572 * cvp pointer to connection VCC for incoming call
1582 Atm_connection *cop, *lcop, *hcop;
1583 Atm_attributes attr;
1589 attr = cvp->cvc_attr;
1592 * Look for matching listeners
1594 while ((lcop = atm_cm_match(&attr, lcop)) != NULL) {
1598 * Need a new connection block
1599 * May be called from timeout - dont wait.
1601 cop = uma_zalloc(atm_connection_zone, M_NOWAIT);
1603 cvp->cvc_attr.cause = atm_cause_tmpl;
1604 cvp->cvc_attr.cause.v.cause_value =
1605 T_ATM_CAUSE_TEMPORARY_FAILURE;
1611 * Initialize connection from listener and incoming call
1614 cop->co_state = COS_INCONN;
1615 cop->co_mpx = lcop->co_mpx;
1616 cop->co_endpt = lcop->co_endpt;
1617 cop->co_llc = lcop->co_llc;
1619 switch (attr.bearer.v.connection_configuration) {
1622 cop->co_flags |= COF_P2P;
1625 case T_ATM_1_TO_MANY:
1627 cop->co_flags |= COF_P2MP;
1628 cvp->cvc_attr.cause = atm_cause_tmpl;
1629 cvp->cvc_attr.cause.v.cause_value =
1630 T_ATM_CAUSE_BEARER_CAPABILITY_NOT_IMPLEMENTED;
1635 * Notify endpoint of incoming call
1637 err = (*cop->co_endpt->ep_incoming)
1638 (lcop->co_toku, cop, &cvp->cvc_attr, &cop->co_toku);
1643 * Endpoint has accepted the call
1645 * Setup call attributes
1648 cvp->cvc_attr.api = lcop->co_lattr->api;
1649 cvp->cvc_attr.api_init =
1650 lcop->co_lattr->api_init;
1651 cvp->cvc_attr.llc = lcop->co_lattr->llc;
1653 cvp->cvc_attr.headin = MAX(cvp->cvc_attr.headin,
1654 lcop->co_lattr->headin);
1657 * Setup connection info and queueing
1659 cop->co_state = COS_INACCEPT;
1660 cop->co_connvc = cvp;
1661 LINK2TAIL(cop, Atm_connection, hcop, co_next);
1665 * Need a new connection block next time around
1671 * Endpoint refuses call
1678 * We're done looking for listeners
1682 * Someone actually wants the call, so notify
1683 * the signalling manager to continue
1685 cvp->cvc_flags |= CVCF_CONNQ;
1686 ENQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
1687 if (atm_cm_accept(cvp, hcop))
1692 * Nobody around to take the call
1694 cvp->cvc_attr.cause = atm_cause_tmpl;
1695 cvp->cvc_attr.cause.v.cause_value =
1696 T_ATM_CAUSE_INCOMPATIBLE_DESTINATION;
1701 * Clean up loose ends
1704 uma_zfree(atm_connection_zone, cop);
1707 * Call has been accepted
1713 * Call failed - notify any endpoints of the call failure
1717 * Clean up loose ends
1720 uma_zfree(atm_connection_zone, cop);
1722 if (cvp->cvc_attr.cause.tag != T_ATM_PRESENT) {
1723 cvp->cvc_attr.cause = atm_cause_tmpl;
1724 cvp->cvc_attr.cause.v.cause_value =
1725 T_ATM_CAUSE_UNSPECIFIED_NORMAL;
1729 Atm_connection *cop2 = cop->co_next;
1730 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
1735 * Tell the signalling manager to reject the call
1737 atm_cm_closevc(cvp);
1744 * Accept an Incoming ATM Call
1746 * Some endpoint service(s) wants to accept an incoming call, so the
1747 * signalling manager will be notified to attempt to progress the call
1748 * to an active status.
1750 * If the signalling manager indicates that connection activation has
1751 * been immediately successful, then all of the endpoints will be notified
1752 * that the connection is ready for data transmission.
1754 * If the return indicates that connection activation is still in progress,
1755 * then the endpoints must wait for notification from the Connection Manager
1756 * indicating the final status of the call setup. If the call setup completes
1757 * successfully, then a "call connected" notification will be sent to the
1758 * endpoints by the Connection Manager. If the call setup fails, then the
1759 * endpoints will receive a "call cleared" notification.
1764 * cvp pointer to connection VCC for incoming call
1765 * cop pointer to head of accepted connections
1768 * 0 connection has been successfully activated
1769 * errno accept failed - reason indicated
1773 atm_cm_accept(cvp, cop)
1775 Atm_connection *cop;
1777 struct stack_list sl;
1778 void (*upf)(int, void *, intptr_t, intptr_t);
1783 * Link vcc to connections
1785 cvp->cvc_conn = cop;
1788 * Initialize stack list index
1793 * Check out Data API
1795 switch (cvp->cvc_attr.api) {
1798 upf = atm_cm_cpcs_upper;
1802 sl.sl_sap[sli++] = SAP_SSCF_UNI;
1803 sl.sl_sap[sli++] = SAP_SSCOP;
1804 upf = atm_cm_saal_upper;
1808 sl.sl_sap[sli++] = SAP_SSCOP;
1809 upf = atm_cm_sscop_upper;
1819 switch (cvp->cvc_attr.aal.type) {
1822 sl.sl_sap[sli++] = SAP_CPCS_AAL5;
1823 sl.sl_sap[sli++] = SAP_SAR_AAL5;
1824 sl.sl_sap[sli++] = SAP_ATM;
1828 sl.sl_sap[sli++] = SAP_CPCS_AAL3_4;
1829 sl.sl_sap[sli++] = SAP_SAR_AAL3_4;
1830 sl.sl_sap[sli++] = SAP_ATM;
1835 * Terminate stack list
1840 * Create a service stack
1842 err = atm_create_stack(cvp, &sl, upf);
1848 * Let the signalling manager finish the VCC activation
1850 switch ((*cvp->cvc_sigmgr->sm_accept)(cvp->cvc_vcc, &err)) {
1852 case CALL_PROCEEDING:
1854 * Note that we're not finished yet
1859 case CALL_CONNECTED:
1861 * Initialize the stack now, even if the call isn't totally
1862 * active yet. We want to avoid the delay between getting
1863 * the "call connected" event and actually notifying the
1864 * adapter to accept cells on the new VCC - if the delay is
1865 * too long, then we end up dropping the first pdus sent by
1868 cvp->cvc_state = CVCS_INIT;
1869 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].init,
1870 cvp->cvc_lower, cvp->cvc_tokl, cvp,
1871 cvp->cvc_attr.api_init, 0, err2);
1873 panic("atm_cm_accept: init");
1875 if (cvp->cvc_flags & CVCF_ABORTING) {
1877 * Someone on the stack bailed out...schedule the
1878 * VCC and stack termination
1883 * Everything looks fine from here
1886 cvp->cvc_state = CVCS_ACCEPT;
1888 cvp->cvc_state = CVCS_ACTIVE;
1894 * Terminate stack and clean up before we leave
1896 cvp->cvc_state = CVCS_CLEAR;
1900 panic("atm_cm_accept: accept");
1906 * Call has been connected, notify endpoints
1909 Atm_connection *cop2 = cop->co_next;
1911 cop->co_state = COS_ACTIVE;
1912 (*cop->co_endpt->ep_connected)(cop->co_toku);
1916 } else if (err == EINPROGRESS) {
1918 * Call is still in progress, endpoint must wait
1924 * Let caller know we failed
1926 cvp->cvc_attr.cause = atm_cause_tmpl;
1927 cvp->cvc_attr.cause.v.cause_value =
1928 T_ATM_CAUSE_UNSPECIFIED_RESOURCE_UNAVAILABLE;
1936 * Match Attributes on Listening Queue
1938 * This function will attempt to match the supplied connection attributes
1939 * with one of the registered attributes in the listening queue. The pcop
1940 * argument may be supplied in order to allow multiple listeners to share
1941 * an incoming call (if supported by the listeners).
1946 * ap pointer to attributes to be matched
1947 * pcop pointer to the previously matched connection
1950 * addr connection with which a match was found
1955 atm_cm_match(ap, pcop)
1957 Atm_connection *pcop;
1959 Atm_connection *cop;
1960 Atm_attributes *lap;
1964 * If we've already matched a listener...
1968 * Make sure already matched listener supports sharing
1970 if ((pcop->co_mpx != ATM_ENC_LLC) ||
1971 ((pcop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0))
1975 * Position ourselves after the matched entry
1977 for (cop = atm_listen_queue; cop; cop = cop->co_next) {
1979 cop = pcop->co_next;
1985 * Start search at top of listening queue
1987 cop = atm_listen_queue;
1991 * Search through listening queue
1993 for (; cop; cop = cop->co_next) {
1995 lap = cop->co_lattr;
1998 * If we're trying to share, check that this entry allows it
2001 if ((cop->co_mpx != ATM_ENC_LLC) ||
2002 ((cop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0))
2007 * ALL "matchable" attributes must match
2013 if (lap->bhli.tag == T_ATM_ABSENT) {
2014 if (ap->bhli.tag == T_ATM_PRESENT)
2016 } else if (lap->bhli.tag == T_ATM_PRESENT) {
2017 if (ap->bhli.tag == T_ATM_ABSENT)
2019 if (ap->bhli.tag == T_ATM_PRESENT)
2020 if (bcmp(&lap->bhli.v, &ap->bhli.v,
2021 sizeof(struct t_atm_bhli)))
2028 if (lap->blli.tag_l2 == T_ATM_ABSENT) {
2029 if (ap->blli.tag_l2 == T_ATM_PRESENT)
2031 } else if (lap->blli.tag_l2 == T_ATM_PRESENT) {
2032 if (ap->blli.tag_l2 == T_ATM_ABSENT)
2034 if (ap->blli.tag_l2 == T_ATM_PRESENT) {
2035 if (bcmp(&lap->blli.v.layer_2_protocol.ID,
2036 &ap->blli.v.layer_2_protocol.ID,
2038 ap->blli.v.layer_2_protocol.ID)))
2046 if (lap->blli.tag_l3 == T_ATM_ABSENT) {
2047 if (ap->blli.tag_l3 == T_ATM_PRESENT)
2049 } else if (lap->blli.tag_l3 == T_ATM_PRESENT) {
2050 if (ap->blli.tag_l3 == T_ATM_ABSENT)
2052 if (ap->blli.tag_l3 == T_ATM_PRESENT) {
2053 if (bcmp(&lap->blli.v.layer_3_protocol.ID,
2054 &ap->blli.v.layer_3_protocol.ID,
2056 ap->blli.v.layer_3_protocol.ID)))
2064 if (lap->llc.tag == T_ATM_ABSENT) {
2065 if (ap->llc.tag == T_ATM_PRESENT)
2067 } else if (lap->llc.tag == T_ATM_PRESENT) {
2068 if (ap->llc.tag == T_ATM_ABSENT)
2070 if (ap->llc.tag == T_ATM_PRESENT) {
2071 int i = MIN(lap->llc.v.llc_len,
2074 if (bcmp(lap->llc.v.llc_info,
2075 ap->llc.v.llc_info, i))
2083 if (lap->aal.tag == T_ATM_ABSENT) {
2084 if (ap->aal.tag == T_ATM_PRESENT)
2086 } else if (lap->aal.tag == T_ATM_PRESENT) {
2087 if (ap->aal.tag == T_ATM_ABSENT)
2089 if (ap->aal.tag == T_ATM_PRESENT) {
2090 if (lap->aal.type != ap->aal.type)
2092 if (lap->aal.type == ATM_AAL5) {
2093 if (lap->aal.v.aal5.SSCS_type !=
2094 ap->aal.v.aal5.SSCS_type)
2097 if (lap->aal.v.aal4.SSCS_type !=
2098 ap->aal.v.aal4.SSCS_type)
2107 if (lap->called.tag == T_ATM_ABSENT) {
2108 if (ap->called.tag == T_ATM_PRESENT)
2110 } else if (lap->called.tag == T_ATM_PRESENT) {
2111 if (ap->called.tag == T_ATM_ABSENT)
2113 if (ap->called.tag == T_ATM_PRESENT) {
2114 if ((!ATM_ADDR_EQUAL(&lap->called.addr,
2115 &ap->called.addr)) ||
2116 (!ATM_ADDR_EQUAL(&lap->called.subaddr,
2117 &ap->called.subaddr)))
2123 * Found a full match - return it
2133 * Find Shareable LLC VCC
2135 * Given an endpoint-supplied connection attribute using LLC multiplexing,
2136 * this function will attempt to locate an existing connection which meets
2137 * the requirements of the supplied attributes.
2142 * ap pointer to requested attributes
2145 * addr shareable LLC connection VCC
2146 * 0 no shareable VCC available
2150 atm_cm_share_llc(ap)
2153 Atm_connection *cop;
2157 * Is requestor willing to share?
2159 if ((ap->llc.v.flags & T_ATM_LLC_SHARING) == 0)
2163 * Try to find a shareable connection
2165 for (cvp = Q_HEAD(atm_connection_queue, Atm_connvc); cvp;
2166 cvp = Q_NEXT(cvp, Atm_connvc, cvc_q)) {
2169 * Dont use terminating connections
2171 switch (cvp->cvc_state) {
2183 * Is connection LLC and shareable?
2185 if ((cvp->cvc_attr.llc.tag != T_ATM_PRESENT) ||
2186 ((cvp->cvc_attr.llc.v.flags & T_ATM_LLC_SHARING) == 0))
2190 * Match requested attributes with existing connection
2192 if (ap->nif != cvp->cvc_attr.nif)
2195 if ((ap->api != cvp->cvc_attr.api) ||
2196 (ap->api_init != cvp->cvc_attr.api_init))
2202 if (cvp->cvc_flags & CVCF_CALLER) {
2203 if ((!ATM_ADDR_EQUAL(&ap->called.addr,
2204 &cvp->cvc_attr.called.addr)) ||
2205 (!ATM_ADDR_EQUAL(&ap->called.subaddr,
2206 &cvp->cvc_attr.called.subaddr)))
2209 if (cvp->cvc_attr.calling.tag != T_ATM_PRESENT)
2211 if ((!ATM_ADDR_EQUAL(&ap->called.addr,
2212 &cvp->cvc_attr.calling.addr)) ||
2213 (!ATM_ADDR_EQUAL(&ap->called.subaddr,
2214 &cvp->cvc_attr.calling.subaddr)))
2221 if (ap->aal.type == ATM_AAL5) {
2222 struct t_atm_aal5 *ap5, *cv5;
2224 ap5 = &ap->aal.v.aal5;
2225 cv5 = &cvp->cvc_attr.aal.v.aal5;
2227 if ((cvp->cvc_attr.aal.type != ATM_AAL5) ||
2228 (ap5->SSCS_type != cv5->SSCS_type))
2231 if (cvp->cvc_flags & CVCF_CALLER) {
2232 if (ap5->forward_max_SDU_size >
2233 cv5->forward_max_SDU_size)
2236 if (ap5->forward_max_SDU_size >
2237 cv5->backward_max_SDU_size)
2241 struct t_atm_aal4 *ap4, *cv4;
2243 ap4 = &ap->aal.v.aal4;
2244 cv4 = &cvp->cvc_attr.aal.v.aal4;
2246 if ((cvp->cvc_attr.aal.type != ATM_AAL3_4) ||
2247 (ap4->SSCS_type != cv4->SSCS_type))
2250 if (cvp->cvc_flags & CVCF_CALLER) {
2251 if (ap4->forward_max_SDU_size >
2252 cv4->forward_max_SDU_size)
2255 if (ap4->forward_max_SDU_size >
2256 cv4->backward_max_SDU_size)
2262 * Traffic Descriptor
2264 if ((ap->traffic.tag != T_ATM_PRESENT) ||
2265 (cvp->cvc_attr.traffic.tag != T_ATM_PRESENT) ||
2266 (ap->traffic.v.best_effort != T_YES) ||
2267 (cvp->cvc_attr.traffic.v.best_effort != T_YES))
2273 if (ap->bearer.v.connection_configuration !=
2274 cvp->cvc_attr.bearer.v.connection_configuration)
2280 if (cvp->cvc_flags & CVCF_CALLER) {
2281 if ((ap->qos.v.forward.qos_class !=
2282 cvp->cvc_attr.qos.v.forward.qos_class) ||
2283 (ap->qos.v.backward.qos_class !=
2284 cvp->cvc_attr.qos.v.backward.qos_class))
2287 if ((ap->qos.v.forward.qos_class !=
2288 cvp->cvc_attr.qos.v.backward.qos_class) ||
2289 (ap->qos.v.backward.qos_class !=
2290 cvp->cvc_attr.qos.v.forward.qos_class))
2295 * The new LLC header must also be unique for this VCC
2297 for (cop = cvp->cvc_conn; cop; cop = cop->co_next) {
2298 int i = MIN(ap->llc.v.llc_len,
2299 cop->co_llc.v.llc_len);
2301 if (bcmp(ap->llc.v.llc_info,
2302 cop->co_llc.v.llc_info, i) == 0)
2307 * If no header overlaps, then we're done
2320 * This function will terminate a connection, including notifying the
2321 * user, if necessary, and freeing up control block memory. The caller
2322 * is responsible for managing the connection VCC.
2327 * cop pointer to connection block
2328 * cause pointer to cause of close
2335 atm_cm_closeconn(cop, cause)
2336 Atm_connection *cop;
2337 struct t_atm_cause *cause;
2341 * Decide whether user needs notification
2343 switch (cop->co_state) {
2351 * Yup, let 'em know connection is gone
2354 (*cop->co_endpt->ep_cleared)(cop->co_toku, cause);
2359 * Nope,they should know already
2364 panic("atm_cm_closeconn: bogus state");
2368 * Unlink connection from its queues
2370 switch (cop->co_state) {
2373 uma_zfree(atm_attributes_zone, cop->co_lattr);
2374 UNLINK(cop, Atm_connection, atm_listen_queue, co_next);
2379 * Remove connection from multiplexor queue
2381 if (cop->co_mxh != cop) {
2383 * Connection is down the chain, just unlink it
2385 UNLINK(cop, Atm_connection, cop->co_mxh, co_next);
2387 } else if (cop->co_next != NULL) {
2389 * Connection is at the head of a non-singleton chain,
2390 * so unlink and reset the chain head
2392 Atm_connection *t, *nhd;
2394 t = nhd = cop->co_next;
2400 nhd->co_connvc->cvc_conn = nhd;
2405 * Free the connection block
2407 cop->co_state = COS_FREE;
2408 uma_zfree(atm_connection_zone, cop);
2414 * Close Connection VCC
2416 * This function will terminate a connection VCC, including releasing the
2417 * the call to the signalling manager, terminating the VCC protocol stack,
2418 * and freeing up control block memory.
2423 * cvp pointer to connection VCC block
2436 * Break links with the connection block
2438 cvp->cvc_conn = NULL;
2441 * Cancel any running timer
2446 * Free queued packets
2448 while (cvp->cvc_rcvq) {
2452 cvp->cvc_rcvq = KB_QNEXT(m);
2458 * Unlink from any queues
2460 if (cvp->cvc_flags & CVCF_INCOMQ) {
2461 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
2462 atm_incoming_qlen--;
2463 cvp->cvc_flags &= ~CVCF_INCOMQ;
2465 } else if (cvp->cvc_flags & CVCF_CONNQ) {
2466 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
2467 cvp->cvc_flags &= ~CVCF_CONNQ;
2471 * Release the signalling call
2473 switch (cvp->cvc_state) {
2481 cvp->cvc_state = CVCS_RELEASE;
2482 switch ((*cvp->cvc_sigmgr->sm_release)
2483 (cvp->cvc_vcc, &err)) {
2487 * Looks good so far...
2491 case CALL_PROCEEDING:
2493 * We'll have to wait for the call to clear
2499 * If there's a memory shortage, retry later.
2500 * Otherwise who knows what's going on....
2502 if ((err == ENOMEM) || (err == ENOBUFS)) {
2503 CVC_TIMER(cvp, 1 * ATM_HZ);
2507 "atm_cm_closevc: release %d\n", err);
2516 cvp->cvc_state = CVCS_REJECT;
2517 switch ((*cvp->cvc_sigmgr->sm_reject)
2518 (cvp->cvc_vcc, &err)) {
2522 * Looks good so far...
2528 * If there's a memory shortage, retry later.
2529 * Otherwise who knows what's going on....
2531 if ((err == ENOMEM) || (err == ENOBUFS)) {
2532 CVC_TIMER(cvp, 1 * ATM_HZ);
2536 "atm_cm_closevc: reject %d\n", err);
2545 * No need for anything here
2550 panic("atm_cm_closevc: bogus state");
2554 * Now terminate the stack
2556 if (cvp->cvc_tokl) {
2557 cvp->cvc_state = CVCS_TERM;
2560 * Wait until stack is unwound before terminating
2562 if ((cvp->cvc_downcnt > 0) || (cvp->cvc_upcnt > 0)) {
2567 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].term,
2568 cvp->cvc_lower, cvp->cvc_tokl, cvp, 0, 0, err);
2570 cvp->cvc_tokl = NULL;
2574 * Let signalling manager finish up
2576 cvp->cvc_state = CVCS_FREE;
2578 (void) (*cvp->cvc_sigmgr->sm_free)(cvp->cvc_vcc);
2582 * Finally, free our own control blocks
2584 uma_zfree(atm_connvc_zone, cvp);
2590 * Process a Connection VCC timeout
2592 * Called when a previously scheduled cvc control block timer expires.
2593 * Processing will be based on the current cvc state.
2598 * tip pointer to cvc timer control block
2606 struct atm_time *tip;
2608 Atm_connection *cop, *cop2;
2612 * Back-off to cvc control block
2614 cvp = (Atm_connvc *)
2615 ((caddr_t)tip - (int)(&((Atm_connvc *)0)->cvc_time));
2618 * Process timeout based on protocol state
2620 switch (cvp->cvc_state) {
2628 if ((cvp->cvc_flags & CVCF_ABORTING) == 0)
2632 * Terminate all connections
2634 cop = cvp->cvc_conn;
2636 cop2 = cop->co_next;
2637 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
2644 atm_cm_closevc(cvp);
2652 * Retry failed operation
2654 atm_cm_closevc(cvp);
2660 "atm_cm_timeout: invalid state: cvp=%p, state=%d\n",
2661 cvp, cvp->cvc_state);
2667 * CPCS User Control Commands
2669 * This function is called by an endpoint user to pass a control command
2670 * across a CPCS data API. Mostly we just send these down the stack.
2673 * cmd stack command code
2674 * cop pointer to connection block
2678 * 0 command output successful
2679 * errno output failed - reason indicated
2683 atm_cm_cpcs_ctl(cmd, cop, arg)
2685 Atm_connection *cop;
2692 * Validate connection state
2694 if (cop->co_state != COS_ACTIVE) {
2699 cvp = cop->co_connvc;
2700 if (cvp->cvc_state != CVCS_ACTIVE) {
2705 if (cvp->cvc_attr.api != CMAPI_CPCS) {
2724 * This function is called by an endpoint user to output a data packet
2725 * across a CPCS data API. After we've validated the connection state, the
2726 * packet will be encapsulated (if necessary) and sent down the data stack.
2729 * cop pointer to connection block
2730 * m pointer to packet buffer chain to be output
2733 * 0 packet output successful
2734 * errno output failed - reason indicated
2738 atm_cm_cpcs_data(cop, m)
2739 Atm_connection *cop;
2743 struct attr_llc *llcp;
2749 * Validate connection state
2751 if (cop->co_state != COS_ACTIVE) {
2756 cvp = cop->co_connvc;
2757 if (cvp->cvc_state != CVCS_ACTIVE) {
2762 if (cvp->cvc_attr.api != CMAPI_CPCS) {
2768 * Add any packet encapsulation
2770 switch (cop->co_mpx) {
2780 * Need to add an LLC header
2782 llcp = &cop->co_llc;
2785 * See if there's room to add LLC header to front of packet.
2787 KB_HEADROOM(m, space);
2788 if (space < llcp->v.llc_len) {
2792 * We have to allocate another buffer and tack it
2793 * onto the front of the packet
2795 MGETHDR(n, KB_F_NOWAIT, KB_T_HEADER);
2800 KB_TAILALIGN(n, llcp->v.llc_len);
2805 * Header fits, just adjust buffer controls
2807 KB_HEADADJ(m, llcp->v.llc_len);
2811 * Add the LLC header
2813 KB_DATASTART(m, bp, void *);
2814 bcopy(llcp->v.llc_info, bp, llcp->v.llc_len);
2815 KB_PLENADJ(m, llcp->v.llc_len);
2819 panic("atm_cm_cpcs_data: mpx");
2823 * Finally, we can send the packet on its way
2825 STACK_CALL(CPCS_UNITDATA_INV, cvp->cvc_lower, cvp->cvc_tokl,
2826 cvp, (intptr_t)m, 0, err);
2834 * Process CPCS Stack Commands
2836 * This is the top of the CPCS API data stack. All upward stack commands
2837 * for the CPCS data API will be received and processed here.
2840 * cmd stack command code
2841 * tok session token (pointer to connection VCC control block)
2850 atm_cm_cpcs_upper(cmd, tok, arg1, arg2)
2856 Atm_connection *cop;
2857 Atm_connvc *cvp = tok;
2864 case CPCS_UNITDATA_SIG:
2868 m = (KBuffer *)arg1;
2870 if (cvp->cvc_state != CVCS_ACTIVE) {
2871 if (cvp->cvc_state == CVCS_ACCEPT) {
2875 * Queue up any packets received before sigmgr
2876 * notifies us of incoming call completion
2878 if (cvp->cvc_rcvqlen >= CVC_RCVQ_MAX) {
2880 atm_cm_stat.cms_rcvconnvc++;
2884 if (cvp->cvc_rcvq == NULL) {
2887 for (n = cvp->cvc_rcvq;
2888 KB_QNEXT(n) != NULL;
2897 atm_cm_stat.cms_rcvconnvc++;
2903 * Send the packet to the interface's bpf if this
2906 if (cvp->cvc_vcc != NULL &&
2907 cvp->cvc_vcc->vc_nif != NULL) {
2909 (struct ifnet *)cvp->cvc_vcc->vc_nif;
2915 * Locate packet's connection
2917 cop = cvp->cvc_conn;
2918 switch (cop->co_mpx) {
2922 * We're already there...
2928 * Find connection with matching LLC header
2930 if (KB_LEN(m) < T_ATM_LLC_MAX_LEN) {
2931 KB_PULLUP(m, T_ATM_LLC_MAX_LEN, m);
2933 atm_cm_stat.cms_llcdrop++;
2937 KB_DATASTART(m, bp, void *);
2942 if (bcmp(bp, cop->co_llc.v.llc_info,
2943 cop->co_llc.v.llc_len) == 0)
2952 * No connected user for this LLC
2955 atm_cm_stat.cms_llcid++;
2960 * Strip off the LLC header
2962 KB_HEADADJ(m, -cop->co_llc.v.llc_len);
2963 KB_PLENADJ(m, -cop->co_llc.v.llc_len);
2967 panic("atm_cm_cpcs_upper: mpx");
2971 * We've found our connection, so hand the packet off
2973 if (cop->co_state != COS_ACTIVE) {
2975 atm_cm_stat.cms_rcvconn++;
2978 (*cop->co_endpt->ep_cpcs_data)(cop->co_toku, m);
2981 case CPCS_UABORT_SIG:
2982 case CPCS_PABORT_SIG:
2984 * We don't support these (yet), so just FALLTHROUGH
2988 log(LOG_ERR, "atm_cm_cpcs_upper: unknown cmd 0x%x\n", cmd);
2994 * SAAL User Control Commands
2996 * This function is called by an endpoint user to pass a control command
2997 * across a SAAL data API. Mostly we just send these down the stack.
3000 * cmd stack command code
3001 * cop pointer to connection block
3005 * 0 command output successful
3006 * errno output failed - reason indicated
3010 atm_cm_saal_ctl(cmd, cop, arg)
3012 Atm_connection *cop;
3019 * Validate connection state
3021 if (cop->co_state != COS_ACTIVE) {
3026 cvp = cop->co_connvc;
3027 if (cvp->cvc_state != CVCS_ACTIVE) {
3032 if (cvp->cvc_attr.api != CMAPI_SAAL) {
3039 case SSCF_UNI_ESTABLISH_REQ:
3040 case SSCF_UNI_RELEASE_REQ:
3042 * Pass command down the stack
3044 STACK_CALL(cmd, cvp->cvc_lower, cvp->cvc_tokl, cvp,
3045 (intptr_t)arg, 0, err);
3060 * This function is called by an endpoint user to output a data packet
3061 * across a SAAL data API. After we've validated the connection state,
3062 * the packet will be sent down the data stack.
3065 * cop pointer to connection block
3066 * m pointer to packet buffer chain to be output
3069 * 0 packet output successful
3070 * errno output failed - reason indicated
3074 atm_cm_saal_data(cop, m)
3075 Atm_connection *cop;
3083 * Validate connection state
3085 if (cop->co_state != COS_ACTIVE) {
3090 cvp = cop->co_connvc;
3091 if (cvp->cvc_state != CVCS_ACTIVE) {
3096 if (cvp->cvc_attr.api != CMAPI_SAAL) {
3102 * Finally, we can send the packet on its way
3104 STACK_CALL(SSCF_UNI_DATA_REQ, cvp->cvc_lower, cvp->cvc_tokl,
3105 cvp, (intptr_t)m, 0, err);
3113 * Process SAAL Stack Commands
3115 * This is the top of the SAAL API data stack. All upward stack commands
3116 * for the SAAL data API will be received and processed here.
3119 * cmd stack command code
3120 * tok session token (pointer to connection VCC control block)
3129 atm_cm_saal_upper(cmd, tok, arg1, arg2)
3135 Atm_connection *cop;
3136 Atm_connvc *cvp = tok;
3141 case SSCF_UNI_ESTABLISH_IND:
3142 case SSCF_UNI_ESTABLISH_CNF:
3143 case SSCF_UNI_RELEASE_IND:
3144 case SSCF_UNI_RELEASE_CNF:
3148 cop = cvp->cvc_conn;
3149 if (cvp->cvc_state != CVCS_ACTIVE)
3151 if (cop->co_state != COS_ACTIVE)
3154 (*cop->co_endpt->ep_saal_ctl)(cmd, cop->co_toku, (void *)arg1);
3157 case SSCF_UNI_DATA_IND:
3161 cop = cvp->cvc_conn;
3162 if (cvp->cvc_state != CVCS_ACTIVE) {
3163 atm_cm_stat.cms_rcvconnvc++;
3164 KB_FREEALL((KBuffer *)arg1);
3167 if (cop->co_state != COS_ACTIVE) {
3168 atm_cm_stat.cms_rcvconn++;
3169 KB_FREEALL((KBuffer *)arg1);
3173 (*cop->co_endpt->ep_saal_data)(cop->co_toku, (KBuffer *)arg1);
3176 case SSCF_UNI_UNITDATA_IND:
3180 KB_FREEALL((KBuffer *)arg1);
3185 log(LOG_ERR, "atm_cm_saal_upper: unknown cmd 0x%x\n", cmd);
3191 * SSCOP User Control Commands
3193 * This function is called by an endpoint user to pass a control command
3194 * across a SSCOP data API. Mostly we just send these down the stack.
3197 * cmd stack command code
3198 * cop pointer to connection block
3203 * 0 command output successful
3204 * errno output failed - reason indicated
3208 atm_cm_sscop_ctl(cmd, cop, arg1, arg2)
3210 Atm_connection *cop;
3218 * Validate connection state
3220 if (cop->co_state != COS_ACTIVE) {
3225 cvp = cop->co_connvc;
3226 if (cvp->cvc_state != CVCS_ACTIVE) {
3231 if (cvp->cvc_attr.api != CMAPI_SSCOP) {
3238 case SSCOP_ESTABLISH_REQ:
3239 case SSCOP_ESTABLISH_RSP:
3240 case SSCOP_RELEASE_REQ:
3241 case SSCOP_RESYNC_REQ:
3242 case SSCOP_RESYNC_RSP:
3243 case SSCOP_RECOVER_RSP:
3244 case SSCOP_RETRIEVE_REQ:
3246 * Pass command down the stack
3248 STACK_CALL(cmd, cvp->cvc_lower, cvp->cvc_tokl, cvp,
3249 (intptr_t)arg1, (intptr_t)arg2, err);
3264 * This function is called by an endpoint user to output a data packet
3265 * across a SSCOP data API. After we've validated the connection state,
3266 * the packet will be encapsulated and sent down the data stack.
3269 * cop pointer to connection block
3270 * m pointer to packet buffer chain to be output
3273 * 0 packet output successful
3274 * errno output failed - reason indicated
3278 atm_cm_sscop_data(cop, m)
3279 Atm_connection *cop;
3287 * Validate connection state
3289 if (cop->co_state != COS_ACTIVE) {
3294 cvp = cop->co_connvc;
3295 if (cvp->cvc_state != CVCS_ACTIVE) {
3300 if (cvp->cvc_attr.api != CMAPI_SSCOP) {
3306 * Finally, we can send the packet on its way
3308 STACK_CALL(SSCOP_DATA_REQ, cvp->cvc_lower, cvp->cvc_tokl,
3309 cvp, (intptr_t)m, 0, err);
3317 * Process SSCOP Stack Commands
3319 * This is the top of the SSCOP API data stack. All upward stack commands
3320 * for the SSCOP data API will be received and processed here.
3323 * cmd stack command code
3324 * tok session token (pointer to connection VCC control block)
3333 atm_cm_sscop_upper(cmd, tok, arg1, arg2)
3339 Atm_connection *cop;
3340 Atm_connvc *cvp = tok;
3344 case SSCOP_ESTABLISH_IND:
3345 case SSCOP_ESTABLISH_CNF:
3346 case SSCOP_RELEASE_IND:
3347 case SSCOP_RESYNC_IND:
3351 cop = cvp->cvc_conn;
3352 if ((cvp->cvc_state != CVCS_ACTIVE) ||
3353 (cop->co_state != COS_ACTIVE)) {
3354 KB_FREEALL((KBuffer *)arg1);
3358 (*cop->co_endpt->ep_sscop_ctl)
3359 (cmd, cop->co_toku, (void *)arg1, (void *)arg2);
3362 case SSCOP_RELEASE_CNF:
3363 case SSCOP_RESYNC_CNF:
3364 case SSCOP_RECOVER_IND:
3365 case SSCOP_RETRIEVE_IND:
3366 case SSCOP_RETRIEVECMP_IND:
3370 cop = cvp->cvc_conn;
3371 if ((cvp->cvc_state != CVCS_ACTIVE) ||
3372 (cop->co_state != COS_ACTIVE))
3375 (*cop->co_endpt->ep_sscop_ctl)
3376 (cmd, cop->co_toku, (void *)arg1, (void *)arg2);
3379 case SSCOP_DATA_IND:
3383 cop = cvp->cvc_conn;
3384 if (cvp->cvc_state != CVCS_ACTIVE) {
3385 atm_cm_stat.cms_rcvconnvc++;
3386 KB_FREEALL((KBuffer *)arg1);
3389 if (cop->co_state != COS_ACTIVE) {
3390 atm_cm_stat.cms_rcvconn++;
3391 KB_FREEALL((KBuffer *)arg1);
3395 (*cop->co_endpt->ep_sscop_data)
3396 (cop->co_toku, (KBuffer *)arg1, arg2);
3399 case SSCOP_UNITDATA_IND:
3403 KB_FREEALL((KBuffer *)arg1);
3408 log(LOG_ERR, "atm_cm_sscop_upper: unknown cmd 0x%x\n", cmd);
3414 * Register an ATM Endpoint Service
3416 * Every ATM endpoint service must register itself here before it can
3417 * issue or receive any connection requests.
3420 * epp pointer to endpoint definition structure
3423 * 0 registration successful
3424 * errno registration failed - reason indicated
3428 atm_endpoint_register(epp)
3434 * See if we need to be initialized
3442 if (epp->ep_id > ENDPT_MAX) {
3446 if (atm_endpoints[epp->ep_id] != NULL) {
3452 * Add endpoint to list
3454 atm_endpoints[epp->ep_id] = epp;
3462 * De-register an ATM Endpoint Service
3464 * Each ATM endpoint service provider must de-register its registered
3465 * endpoint(s) before terminating. Specifically, loaded kernel modules
3466 * must de-register their services before unloading themselves.
3469 * epp pointer to endpoint definition structure
3472 * 0 de-registration successful
3473 * errno de-registration failed - reason indicated
3477 atm_endpoint_deregister(epp)
3485 if (epp->ep_id > ENDPT_MAX) {
3489 if (atm_endpoints[epp->ep_id] != epp) {
3495 * Remove endpoint from list
3497 atm_endpoints[epp->ep_id] = NULL;