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)
544 Atm_connection **copp;
552 * Get a connection block
554 cop = uma_zalloc(atm_connection_zone, M_WAITOK);
559 * Initialize connection info
562 cop->co_toku = token;
566 * Validate and extract useful attribute information
587 switch (ap->aal.tag) {
591 switch (ap->aal.type) {
613 * Broadband High Layer Information Attributes
615 switch (ap->bhli.tag) {
628 * Broadband Low Layer Information Attributes
630 switch (ap->blli.tag_l2) {
642 switch (ap->blli.tag_l3) {
655 * Logical Link Control Attributes
657 switch (ap->llc.tag) {
660 if ((ap->blli.tag_l2 != T_ATM_PRESENT) ||
661 (ap->blli.v.layer_2_protocol.ID_type != T_ATM_SIMPLE_ID) ||
662 (ap->blli.v.layer_2_protocol.ID.simple_ID !=
663 T_ATM_BLLI2_I8802) ||
664 (ap->llc.v.llc_len < T_ATM_LLC_MIN_LEN) ||
665 (ap->llc.v.llc_len > T_ATM_LLC_MAX_LEN)) {
669 cop->co_mpx = ATM_ENC_LLC;
670 cop->co_llc = ap->llc;
675 cop->co_mpx = ATM_ENC_NULL;
684 * Called Party Attributes
686 switch (ap->called.tag) {
689 switch (ap->called.addr.address_format) {
692 ap->called.tag = T_ATM_ABSENT;
711 * Get an attribute block and save listening attributes
713 cop->co_lattr = uma_zalloc(atm_attributes_zone, M_WAITOK | M_ZERO);
714 if (cop->co_lattr == NULL) {
718 *cop->co_lattr = *ap;
721 * Now try to register the listening connection
727 err = solisten_proto_check(so);
730 if (atm_cm_match(cop->co_lattr, NULL) != NULL) {
732 * Can't have matching listeners
737 cop->co_state = COS_LISTEN;
738 LINK2TAIL(cop, Atm_connection, atm_listen_queue, co_next);
750 * Undo any partial setup stuff
754 uma_zfree(atm_attributes_zone, cop->co_lattr);
755 uma_zfree(atm_connection_zone, cop);
759 * Finish connection setup
768 * Add to LLC Connection
770 * Called by an endpoint service to create a new Connection Manager API
771 * instance to be associated with an LLC-multiplexed connection instance
772 * which has been previously created. The endpoint provided token will
773 * be used in all further CM -> endpoint function calls, and the returned
774 * connection block pointer must be used in all subsequent endpoint -> CM
777 * If the return indicates that the connection setup has been immediately
778 * successful, then the connection is ready for data transmission.
780 * If the return indicates that the connection setup is still in progress,
781 * then the endpoint must wait for notification from the Connection Manager
782 * indicating the final status of the call setup. If the call setup completes
783 * successfully, then a "call connected" notification will be sent to the
784 * endpoint by the Connection Manager. If the call setup fails, then the
785 * endpoint will receive a "call cleared" notification.
787 * All connection instances must be freed with an atm_cm_release() call.
790 * epp pointer to endpoint definition structure
791 * token endpoint's connection instance token
792 * llc pointer to llc attributes for new connection
793 * ecop pointer to existing connection block
794 * copp pointer to location to return allocated connection block
797 * 0 connection has been successfully established
798 * EINPROGRESS connection establishment is in progress
799 * errno addllc failed - reason indicated
803 atm_cm_addllc(epp, token, llc, ecop, copp)
806 struct attr_llc *llc;
807 Atm_connection *ecop;
808 Atm_connection **copp;
810 Atm_connection *cop, *cop2;
817 * Check out requested LLC attributes
819 if ((llc->tag != T_ATM_PRESENT) ||
820 ((llc->v.flags & T_ATM_LLC_SHARING) == 0) ||
821 (llc->v.llc_len < T_ATM_LLC_MIN_LEN) ||
822 (llc->v.llc_len > T_ATM_LLC_MAX_LEN))
826 * Get a connection block
827 * May be called from netisr - don't wait.
829 cop = uma_zalloc(atm_connection_zone, M_NOWAIT);
834 * Initialize connection info
837 cop->co_toku = token;
843 * Ensure that supplied connection is really valid
846 for (cvp = Q_HEAD(atm_connection_queue, Atm_connvc); cvp;
847 cvp = Q_NEXT(cvp, Atm_connvc, cvc_q)) {
848 for (cop2 = cvp->cvc_conn; cop2; cop2 = cop2->co_next) {
860 switch (ecop->co_state) {
877 * Connection must be LLC multiplexed and shared
879 if ((ecop->co_mpx != ATM_ENC_LLC) ||
880 ((ecop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0)) {
886 * This new LLC header must be unique for this VCC
890 int i = MIN(llc->v.llc_len, cop2->co_llc.v.llc_len);
892 if (bcmp(llc->v.llc_info, cop2->co_llc.v.llc_info, i) == 0) {
897 cop2 = cop2->co_next;
901 * Everything seems to check out
903 cop->co_flags = ecop->co_flags;
904 cop->co_state = ecop->co_state;
905 cop->co_mpx = ecop->co_mpx;
906 cop->co_connvc = ecop->co_connvc;
908 LINK2TAIL(cop, Atm_connection, ecop->co_mxh, co_next);
909 cop->co_mxh = ecop->co_mxh;
914 if (err && err != EINPROGRESS) {
916 * Undo any partial setup stuff
919 uma_zfree(atm_connection_zone, cop);
922 * Pass new connection back to caller
934 * cop pointer to connection block
935 * id identifier for party to be added
936 * addr address of party to be added
939 * 0 addparty successful
940 * errno addparty failed - reason indicated
944 atm_cm_addparty(cop, id, addr)
947 struct t_atm_sap *addr;
957 * cop pointer to connection block
958 * id identifier for party to be added
959 * cause pointer to cause of drop
962 * 0 dropparty successful
963 * errno dropparty failed - reason indicated
967 atm_cm_dropparty(cop, id, cause)
970 struct t_atm_cause *cause;
977 * Release Connection Resources
979 * Called by the endpoint service in order to terminate an ATM connection
980 * and to release all system resources for the connection. This function
981 * must be called for every allocated connection instance and must only
982 * be called by the connection's owner.
985 * cop pointer to connection block
986 * cause pointer to cause of release
989 * 0 release successful
990 * errno release failed - reason indicated
994 atm_cm_release(cop, cause)
996 struct t_atm_cause *cause;
1004 * First, a quick state validation check
1006 switch (cop->co_state) {
1014 * Break link to user
1016 cop->co_toku = NULL;
1024 panic("atm_cm_release: bogus conn state");
1028 * Check out the VCC state too
1030 if ((cvp = cop->co_connvc) != NULL) {
1032 switch (cvp->cvc_state) {
1049 panic("atm_cm_release: bogus connvc state");
1053 * If we're the only connection, terminate the VCC
1055 if ((cop->co_mxh == cop) && (cop->co_next == NULL)) {
1056 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
1057 cvp->cvc_attr.cause.v = *cause;
1058 atm_cm_closevc(cvp);
1063 * Now get rid of the connection
1065 atm_cm_closeconn(cop, cause);
1072 * Abort an ATM Connection VCC
1074 * This function allows any non-owner kernel entity to request an
1075 * immediate termination of an ATM VCC. This will normally be called
1076 * when encountering a catastrophic error condition that cannot be
1077 * resolved via the available stack protocols. The connection manager
1078 * will schedule the connection's termination, including notifying the
1079 * connection owner of the termination.
1081 * This function should only be called by a stack entity instance. After
1082 * calling the function, the caller should set a protocol state which just
1083 * waits for a <sap>_TERM stack command to be delivered.
1086 * cvp pointer to connection VCC block
1087 * cause pointer to cause of abort
1090 * 0 abort successful
1091 * errno abort failed - reason indicated
1095 atm_cm_abort(cvp, cause)
1097 struct t_atm_cause *cause;
1099 ATM_DEBUG2("atm_cm_abort: cvp=%p cause=%d\n",
1100 cvp, cause->cause_value);
1103 * Note that we're aborting
1105 cvp->cvc_flags |= CVCF_ABORTING;
1107 switch (cvp->cvc_state) {
1111 * In-line code will handle this
1113 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
1114 cvp->cvc_attr.cause.v = *cause;
1121 * Schedule connection termination, since we want
1122 * to avoid any sequencing interactions
1124 cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
1125 cvp->cvc_attr.cause.v = *cause;
1134 * Ignore abort, as we're already terminating
1140 "atm_cm_abort: invalid state: cvp=%p, state=%d\n",
1141 cvp, cvp->cvc_state);
1148 * Incoming ATM Call Received
1150 * Called by a signalling manager to indicate that a new call request has
1151 * been received. This function will allocate and initialize the connection
1152 * manager control blocks and queue this call request. The call request
1153 * processing function, atm_cm_procinq(), will be scheduled to perform the
1157 * vcp pointer to incoming call's VCC control block
1158 * ap pointer to incoming call's attributes
1161 * 0 call queuing successful
1162 * errno call queuing failed - reason indicated
1166 atm_cm_incoming(vcp, ap)
1175 * Do some minimal attribute validation
1179 * Must specify a network interface
1181 if (ap->nif == NULL)
1187 if ((ap->aal.tag != T_ATM_PRESENT) ||
1188 ((ap->aal.type != ATM_AAL5) &&
1189 (ap->aal.type != ATM_AAL3_4)))
1193 * Traffic Descriptor Attributes
1195 if ((ap->traffic.tag != T_ATM_PRESENT) &&
1196 (ap->traffic.tag != T_ATM_ABSENT))
1200 * Broadband Bearer Attributes
1202 if ((ap->bearer.tag != T_ATM_PRESENT) ||
1203 ((ap->bearer.v.connection_configuration != T_ATM_1_TO_1) &&
1204 (ap->bearer.v.connection_configuration != T_ATM_1_TO_MANY)))
1208 * Broadband High Layer Attributes
1210 if ((ap->bhli.tag != T_ATM_PRESENT) &&
1211 (ap->bhli.tag != T_ATM_ABSENT))
1215 * Broadband Low Layer Attributes
1217 if ((ap->blli.tag_l2 != T_ATM_PRESENT) &&
1218 (ap->blli.tag_l2 != T_ATM_ABSENT))
1220 if ((ap->blli.tag_l3 != T_ATM_PRESENT) &&
1221 (ap->blli.tag_l3 != T_ATM_ABSENT))
1225 * Logical Link Control Attributes
1227 if (ap->llc.tag == T_ATM_PRESENT)
1229 ap->llc.tag = T_ATM_ANY;
1232 * Called Party Attributes
1234 if ((ap->called.tag != T_ATM_PRESENT) ||
1235 (ap->called.addr.address_format == T_ATM_ABSENT))
1237 if (ap->called.tag == T_ATM_ABSENT) {
1238 ap->called.addr.address_format = T_ATM_ABSENT;
1239 ap->called.addr.address_length = 0;
1240 ap->called.subaddr.address_format = T_ATM_ABSENT;
1241 ap->called.subaddr.address_length = 0;
1245 * Calling Party Attributes
1247 if ((ap->calling.tag != T_ATM_PRESENT) &&
1248 (ap->calling.tag != T_ATM_ABSENT))
1250 if (ap->calling.tag == T_ATM_ABSENT) {
1251 ap->calling.addr.address_format = T_ATM_ABSENT;
1252 ap->calling.addr.address_length = 0;
1253 ap->calling.subaddr.address_format = T_ATM_ABSENT;
1254 ap->calling.subaddr.address_length = 0;
1258 * Quality of Service Attributes
1260 if (ap->qos.tag != T_ATM_PRESENT)
1264 * Transit Network Attributes
1266 if ((ap->transit.tag != T_ATM_PRESENT) &&
1267 (ap->transit.tag != T_ATM_ABSENT))
1273 if ((ap->cause.tag != T_ATM_PRESENT) &&
1274 (ap->cause.tag != T_ATM_ABSENT))
1278 * Get a connection VCC block
1279 * May be called from netisr - don't wait.
1281 cvp = uma_zalloc(atm_connvc_zone, M_NOWAIT);
1288 * Initialize the control block
1291 cvp->cvc_sigmgr = vcp->vc_pif->pif_sigmgr;
1292 cvp->cvc_attr = *ap;
1293 cvp->cvc_state = CVCS_INCOMING;
1296 * Control queue length
1299 if (atm_incoming_qlen >= ATM_CALLQ_MAX) {
1306 * Queue request and schedule call processing function
1308 cvp->cvc_flags |= CVCF_INCOMQ;
1309 ENQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
1310 if (atm_incoming_qlen++ == 0) {
1311 timeout(atm_cm_procinq, (void *)0, 0);
1315 * Link for signalling manager
1317 vcp->vc_connvc = cvp;
1325 * Free any resources
1328 uma_zfree(atm_connvc_zone, cvp);
1334 * VCC Connected Notification
1336 * This function is called by a signalling manager as notification that a
1337 * VCC call setup has been successful.
1340 * cvp pointer to connection VCC block
1347 atm_cm_connected(cvp)
1350 Atm_connection *cop, *cop2;
1357 * Validate connection vcc
1359 switch (cvp->cvc_state) {
1363 * Initialize the stack
1365 cvp->cvc_state = CVCS_INIT;
1366 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].init,
1367 cvp->cvc_lower, cvp->cvc_tokl,
1368 cvp, cvp->cvc_attr.api_init, 0, err);
1370 panic("atm_cm_connected: init");
1372 if (cvp->cvc_flags & CVCF_ABORTING) {
1374 * Someone on the stack bailed out...notify all of the
1375 * connections and schedule the VCC termination
1377 cop = cvp->cvc_conn;
1379 cop2 = cop->co_next;
1380 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
1383 atm_cm_closevc(cvp);
1391 * Stack already initialized
1396 panic("atm_cm_connected: connvc state");
1400 * VCC is ready for action
1402 cvp->cvc_state = CVCS_ACTIVE;
1405 * Notify all connections that the call has completed
1407 cop = cvp->cvc_conn;
1409 cop2 = cop->co_next;
1411 switch (cop->co_state) {
1415 cop->co_state = COS_ACTIVE;
1416 (*cop->co_endpt->ep_connected)(cop->co_toku);
1421 * May get here if an ep_connected() call (from
1422 * above) results in an atm_cm_addllc() call for
1423 * the just connected connection.
1428 panic("atm_cm_connected: connection state");
1437 * Input any queued packets
1439 while ((m = cvp->cvc_rcvq) != NULL) {
1440 cvp->cvc_rcvq = KB_QNEXT(m);
1445 * Currently only supported for CPCS API
1447 atm_cm_cpcs_upper(CPCS_UNITDATA_SIG, cvp, (intptr_t)m, 0);
1455 * VCC Cleared Notification
1457 * This function is called by a signalling manager as notification that a
1458 * VCC call has been cleared. The cause information describing the reason
1459 * for the call clearing will be contained in the connection VCC attributes.
1462 * cvp pointer to connection VCC block
1472 Atm_connection *cop, *cop2;
1475 KASSERT((cvp->cvc_state != CVCS_FREE) && (cvp->cvc_state < CVCS_CLEAR),
1476 ("atm_cm_cleared: state sanity check failed"));
1478 cvp->cvc_state = CVCS_CLEAR;
1482 * Terminate all connections
1484 cop = cvp->cvc_conn;
1486 cop2 = cop->co_next;
1487 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
1492 * Clean up connection VCC
1494 atm_cm_closevc(cvp);
1503 * Process Incoming Call Queue
1505 * This function is scheduled by atm_cm_incoming() in order to process
1506 * all the entries on the incoming call queue.
1509 * arg argument passed on timeout() call
1523 * Only process incoming calls up to our quota
1525 while (cnt++ < ATM_CALLQ_MAX) {
1530 * Get next awaiting call
1532 cvp = Q_HEAD(atm_incoming_queue, Atm_connvc);
1537 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
1538 atm_incoming_qlen--;
1539 cvp->cvc_flags &= ~CVCF_INCOMQ;
1550 * If we've expended our quota, reschedule ourselves
1552 if (cnt >= ATM_CALLQ_MAX)
1553 timeout(atm_cm_procinq, (void *)0, 0);
1558 * Process Incoming Call
1560 * This function will search through the listening queue and try to find
1561 * matching endpoint(s) for the incoming call. If we find any, we will
1562 * notify the endpoint service(s) of the incoming call and will then
1563 * notify the signalling manager to progress the call to an active status.
1565 * If there are no listeners for the call, the signalling manager will be
1566 * notified of a call rejection.
1571 * cvp pointer to connection VCC for incoming call
1581 Atm_connection *cop, *lcop, *hcop;
1582 Atm_attributes attr;
1588 attr = cvp->cvc_attr;
1591 * Look for matching listeners
1593 while ((lcop = atm_cm_match(&attr, lcop)) != NULL) {
1597 * Need a new connection block
1598 * May be called from timeout - dont wait.
1600 cop = uma_zalloc(atm_connection_zone, M_NOWAIT);
1602 cvp->cvc_attr.cause = atm_cause_tmpl;
1603 cvp->cvc_attr.cause.v.cause_value =
1604 T_ATM_CAUSE_TEMPORARY_FAILURE;
1610 * Initialize connection from listener and incoming call
1613 cop->co_state = COS_INCONN;
1614 cop->co_mpx = lcop->co_mpx;
1615 cop->co_endpt = lcop->co_endpt;
1616 cop->co_llc = lcop->co_llc;
1618 switch (attr.bearer.v.connection_configuration) {
1621 cop->co_flags |= COF_P2P;
1624 case T_ATM_1_TO_MANY:
1626 cop->co_flags |= COF_P2MP;
1627 cvp->cvc_attr.cause = atm_cause_tmpl;
1628 cvp->cvc_attr.cause.v.cause_value =
1629 T_ATM_CAUSE_BEARER_CAPABILITY_NOT_IMPLEMENTED;
1634 * Notify endpoint of incoming call
1636 err = (*cop->co_endpt->ep_incoming)
1637 (lcop->co_toku, cop, &cvp->cvc_attr, &cop->co_toku);
1642 * Endpoint has accepted the call
1644 * Setup call attributes
1647 cvp->cvc_attr.api = lcop->co_lattr->api;
1648 cvp->cvc_attr.api_init =
1649 lcop->co_lattr->api_init;
1650 cvp->cvc_attr.llc = lcop->co_lattr->llc;
1652 cvp->cvc_attr.headin = MAX(cvp->cvc_attr.headin,
1653 lcop->co_lattr->headin);
1656 * Setup connection info and queueing
1658 cop->co_state = COS_INACCEPT;
1659 cop->co_connvc = cvp;
1660 LINK2TAIL(cop, Atm_connection, hcop, co_next);
1664 * Need a new connection block next time around
1670 * Endpoint refuses call
1677 * We're done looking for listeners
1681 * Someone actually wants the call, so notify
1682 * the signalling manager to continue
1684 cvp->cvc_flags |= CVCF_CONNQ;
1685 ENQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
1686 if (atm_cm_accept(cvp, hcop))
1691 * Nobody around to take the call
1693 cvp->cvc_attr.cause = atm_cause_tmpl;
1694 cvp->cvc_attr.cause.v.cause_value =
1695 T_ATM_CAUSE_INCOMPATIBLE_DESTINATION;
1700 * Clean up loose ends
1703 uma_zfree(atm_connection_zone, cop);
1706 * Call has been accepted
1712 * Call failed - notify any endpoints of the call failure
1716 * Clean up loose ends
1719 uma_zfree(atm_connection_zone, cop);
1721 if (cvp->cvc_attr.cause.tag != T_ATM_PRESENT) {
1722 cvp->cvc_attr.cause = atm_cause_tmpl;
1723 cvp->cvc_attr.cause.v.cause_value =
1724 T_ATM_CAUSE_UNSPECIFIED_NORMAL;
1728 Atm_connection *cop2 = cop->co_next;
1729 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
1734 * Tell the signalling manager to reject the call
1736 atm_cm_closevc(cvp);
1743 * Accept an Incoming ATM Call
1745 * Some endpoint service(s) wants to accept an incoming call, so the
1746 * signalling manager will be notified to attempt to progress the call
1747 * to an active status.
1749 * If the signalling manager indicates that connection activation has
1750 * been immediately successful, then all of the endpoints will be notified
1751 * that the connection is ready for data transmission.
1753 * If the return indicates that connection activation is still in progress,
1754 * then the endpoints must wait for notification from the Connection Manager
1755 * indicating the final status of the call setup. If the call setup completes
1756 * successfully, then a "call connected" notification will be sent to the
1757 * endpoints by the Connection Manager. If the call setup fails, then the
1758 * endpoints will receive a "call cleared" notification.
1763 * cvp pointer to connection VCC for incoming call
1764 * cop pointer to head of accepted connections
1767 * 0 connection has been successfully activated
1768 * errno accept failed - reason indicated
1772 atm_cm_accept(cvp, cop)
1774 Atm_connection *cop;
1776 struct stack_list sl;
1777 void (*upf)(int, void *, intptr_t, intptr_t);
1782 * Link vcc to connections
1784 cvp->cvc_conn = cop;
1787 * Initialize stack list index
1792 * Check out Data API
1794 switch (cvp->cvc_attr.api) {
1797 upf = atm_cm_cpcs_upper;
1801 sl.sl_sap[sli++] = SAP_SSCF_UNI;
1802 sl.sl_sap[sli++] = SAP_SSCOP;
1803 upf = atm_cm_saal_upper;
1807 sl.sl_sap[sli++] = SAP_SSCOP;
1808 upf = atm_cm_sscop_upper;
1818 switch (cvp->cvc_attr.aal.type) {
1821 sl.sl_sap[sli++] = SAP_CPCS_AAL5;
1822 sl.sl_sap[sli++] = SAP_SAR_AAL5;
1823 sl.sl_sap[sli++] = SAP_ATM;
1827 sl.sl_sap[sli++] = SAP_CPCS_AAL3_4;
1828 sl.sl_sap[sli++] = SAP_SAR_AAL3_4;
1829 sl.sl_sap[sli++] = SAP_ATM;
1834 * Terminate stack list
1839 * Create a service stack
1841 err = atm_create_stack(cvp, &sl, upf);
1847 * Let the signalling manager finish the VCC activation
1849 switch ((*cvp->cvc_sigmgr->sm_accept)(cvp->cvc_vcc, &err)) {
1851 case CALL_PROCEEDING:
1853 * Note that we're not finished yet
1858 case CALL_CONNECTED:
1860 * Initialize the stack now, even if the call isn't totally
1861 * active yet. We want to avoid the delay between getting
1862 * the "call connected" event and actually notifying the
1863 * adapter to accept cells on the new VCC - if the delay is
1864 * too long, then we end up dropping the first pdus sent by
1867 cvp->cvc_state = CVCS_INIT;
1868 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].init,
1869 cvp->cvc_lower, cvp->cvc_tokl, cvp,
1870 cvp->cvc_attr.api_init, 0, err2);
1872 panic("atm_cm_accept: init");
1874 if (cvp->cvc_flags & CVCF_ABORTING) {
1876 * Someone on the stack bailed out...schedule the
1877 * VCC and stack termination
1882 * Everything looks fine from here
1885 cvp->cvc_state = CVCS_ACCEPT;
1887 cvp->cvc_state = CVCS_ACTIVE;
1893 * Terminate stack and clean up before we leave
1895 cvp->cvc_state = CVCS_CLEAR;
1899 panic("atm_cm_accept: accept");
1905 * Call has been connected, notify endpoints
1908 Atm_connection *cop2 = cop->co_next;
1910 cop->co_state = COS_ACTIVE;
1911 (*cop->co_endpt->ep_connected)(cop->co_toku);
1915 } else if (err == EINPROGRESS) {
1917 * Call is still in progress, endpoint must wait
1923 * Let caller know we failed
1925 cvp->cvc_attr.cause = atm_cause_tmpl;
1926 cvp->cvc_attr.cause.v.cause_value =
1927 T_ATM_CAUSE_UNSPECIFIED_RESOURCE_UNAVAILABLE;
1935 * Match Attributes on Listening Queue
1937 * This function will attempt to match the supplied connection attributes
1938 * with one of the registered attributes in the listening queue. The pcop
1939 * argument may be supplied in order to allow multiple listeners to share
1940 * an incoming call (if supported by the listeners).
1945 * ap pointer to attributes to be matched
1946 * pcop pointer to the previously matched connection
1949 * addr connection with which a match was found
1954 atm_cm_match(ap, pcop)
1956 Atm_connection *pcop;
1958 Atm_connection *cop;
1959 Atm_attributes *lap;
1963 * If we've already matched a listener...
1967 * Make sure already matched listener supports sharing
1969 if ((pcop->co_mpx != ATM_ENC_LLC) ||
1970 ((pcop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0))
1974 * Position ourselves after the matched entry
1976 for (cop = atm_listen_queue; cop; cop = cop->co_next) {
1978 cop = pcop->co_next;
1984 * Start search at top of listening queue
1986 cop = atm_listen_queue;
1990 * Search through listening queue
1992 for (; cop; cop = cop->co_next) {
1994 lap = cop->co_lattr;
1997 * If we're trying to share, check that this entry allows it
2000 if ((cop->co_mpx != ATM_ENC_LLC) ||
2001 ((cop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0))
2006 * ALL "matchable" attributes must match
2012 if (lap->bhli.tag == T_ATM_ABSENT) {
2013 if (ap->bhli.tag == T_ATM_PRESENT)
2015 } else if (lap->bhli.tag == T_ATM_PRESENT) {
2016 if (ap->bhli.tag == T_ATM_ABSENT)
2018 if (ap->bhli.tag == T_ATM_PRESENT)
2019 if (bcmp(&lap->bhli.v, &ap->bhli.v,
2020 sizeof(struct t_atm_bhli)))
2027 if (lap->blli.tag_l2 == T_ATM_ABSENT) {
2028 if (ap->blli.tag_l2 == T_ATM_PRESENT)
2030 } else if (lap->blli.tag_l2 == T_ATM_PRESENT) {
2031 if (ap->blli.tag_l2 == T_ATM_ABSENT)
2033 if (ap->blli.tag_l2 == T_ATM_PRESENT) {
2034 if (bcmp(&lap->blli.v.layer_2_protocol.ID,
2035 &ap->blli.v.layer_2_protocol.ID,
2037 ap->blli.v.layer_2_protocol.ID)))
2045 if (lap->blli.tag_l3 == T_ATM_ABSENT) {
2046 if (ap->blli.tag_l3 == T_ATM_PRESENT)
2048 } else if (lap->blli.tag_l3 == T_ATM_PRESENT) {
2049 if (ap->blli.tag_l3 == T_ATM_ABSENT)
2051 if (ap->blli.tag_l3 == T_ATM_PRESENT) {
2052 if (bcmp(&lap->blli.v.layer_3_protocol.ID,
2053 &ap->blli.v.layer_3_protocol.ID,
2055 ap->blli.v.layer_3_protocol.ID)))
2063 if (lap->llc.tag == T_ATM_ABSENT) {
2064 if (ap->llc.tag == T_ATM_PRESENT)
2066 } else if (lap->llc.tag == T_ATM_PRESENT) {
2067 if (ap->llc.tag == T_ATM_ABSENT)
2069 if (ap->llc.tag == T_ATM_PRESENT) {
2070 int i = MIN(lap->llc.v.llc_len,
2073 if (bcmp(lap->llc.v.llc_info,
2074 ap->llc.v.llc_info, i))
2082 if (lap->aal.tag == T_ATM_ABSENT) {
2083 if (ap->aal.tag == T_ATM_PRESENT)
2085 } else if (lap->aal.tag == T_ATM_PRESENT) {
2086 if (ap->aal.tag == T_ATM_ABSENT)
2088 if (ap->aal.tag == T_ATM_PRESENT) {
2089 if (lap->aal.type != ap->aal.type)
2091 if (lap->aal.type == ATM_AAL5) {
2092 if (lap->aal.v.aal5.SSCS_type !=
2093 ap->aal.v.aal5.SSCS_type)
2096 if (lap->aal.v.aal4.SSCS_type !=
2097 ap->aal.v.aal4.SSCS_type)
2106 if (lap->called.tag == T_ATM_ABSENT) {
2107 if (ap->called.tag == T_ATM_PRESENT)
2109 } else if (lap->called.tag == T_ATM_PRESENT) {
2110 if (ap->called.tag == T_ATM_ABSENT)
2112 if (ap->called.tag == T_ATM_PRESENT) {
2113 if ((!ATM_ADDR_EQUAL(&lap->called.addr,
2114 &ap->called.addr)) ||
2115 (!ATM_ADDR_EQUAL(&lap->called.subaddr,
2116 &ap->called.subaddr)))
2122 * Found a full match - return it
2132 * Find Shareable LLC VCC
2134 * Given an endpoint-supplied connection attribute using LLC multiplexing,
2135 * this function will attempt to locate an existing connection which meets
2136 * the requirements of the supplied attributes.
2141 * ap pointer to requested attributes
2144 * addr shareable LLC connection VCC
2145 * 0 no shareable VCC available
2149 atm_cm_share_llc(ap)
2152 Atm_connection *cop;
2156 * Is requestor willing to share?
2158 if ((ap->llc.v.flags & T_ATM_LLC_SHARING) == 0)
2162 * Try to find a shareable connection
2164 for (cvp = Q_HEAD(atm_connection_queue, Atm_connvc); cvp;
2165 cvp = Q_NEXT(cvp, Atm_connvc, cvc_q)) {
2168 * Dont use terminating connections
2170 switch (cvp->cvc_state) {
2182 * Is connection LLC and shareable?
2184 if ((cvp->cvc_attr.llc.tag != T_ATM_PRESENT) ||
2185 ((cvp->cvc_attr.llc.v.flags & T_ATM_LLC_SHARING) == 0))
2189 * Match requested attributes with existing connection
2191 if (ap->nif != cvp->cvc_attr.nif)
2194 if ((ap->api != cvp->cvc_attr.api) ||
2195 (ap->api_init != cvp->cvc_attr.api_init))
2201 if (cvp->cvc_flags & CVCF_CALLER) {
2202 if ((!ATM_ADDR_EQUAL(&ap->called.addr,
2203 &cvp->cvc_attr.called.addr)) ||
2204 (!ATM_ADDR_EQUAL(&ap->called.subaddr,
2205 &cvp->cvc_attr.called.subaddr)))
2208 if (cvp->cvc_attr.calling.tag != T_ATM_PRESENT)
2210 if ((!ATM_ADDR_EQUAL(&ap->called.addr,
2211 &cvp->cvc_attr.calling.addr)) ||
2212 (!ATM_ADDR_EQUAL(&ap->called.subaddr,
2213 &cvp->cvc_attr.calling.subaddr)))
2220 if (ap->aal.type == ATM_AAL5) {
2221 struct t_atm_aal5 *ap5, *cv5;
2223 ap5 = &ap->aal.v.aal5;
2224 cv5 = &cvp->cvc_attr.aal.v.aal5;
2226 if ((cvp->cvc_attr.aal.type != ATM_AAL5) ||
2227 (ap5->SSCS_type != cv5->SSCS_type))
2230 if (cvp->cvc_flags & CVCF_CALLER) {
2231 if (ap5->forward_max_SDU_size >
2232 cv5->forward_max_SDU_size)
2235 if (ap5->forward_max_SDU_size >
2236 cv5->backward_max_SDU_size)
2240 struct t_atm_aal4 *ap4, *cv4;
2242 ap4 = &ap->aal.v.aal4;
2243 cv4 = &cvp->cvc_attr.aal.v.aal4;
2245 if ((cvp->cvc_attr.aal.type != ATM_AAL3_4) ||
2246 (ap4->SSCS_type != cv4->SSCS_type))
2249 if (cvp->cvc_flags & CVCF_CALLER) {
2250 if (ap4->forward_max_SDU_size >
2251 cv4->forward_max_SDU_size)
2254 if (ap4->forward_max_SDU_size >
2255 cv4->backward_max_SDU_size)
2261 * Traffic Descriptor
2263 if ((ap->traffic.tag != T_ATM_PRESENT) ||
2264 (cvp->cvc_attr.traffic.tag != T_ATM_PRESENT) ||
2265 (ap->traffic.v.best_effort != T_YES) ||
2266 (cvp->cvc_attr.traffic.v.best_effort != T_YES))
2272 if (ap->bearer.v.connection_configuration !=
2273 cvp->cvc_attr.bearer.v.connection_configuration)
2279 if (cvp->cvc_flags & CVCF_CALLER) {
2280 if ((ap->qos.v.forward.qos_class !=
2281 cvp->cvc_attr.qos.v.forward.qos_class) ||
2282 (ap->qos.v.backward.qos_class !=
2283 cvp->cvc_attr.qos.v.backward.qos_class))
2286 if ((ap->qos.v.forward.qos_class !=
2287 cvp->cvc_attr.qos.v.backward.qos_class) ||
2288 (ap->qos.v.backward.qos_class !=
2289 cvp->cvc_attr.qos.v.forward.qos_class))
2294 * The new LLC header must also be unique for this VCC
2296 for (cop = cvp->cvc_conn; cop; cop = cop->co_next) {
2297 int i = MIN(ap->llc.v.llc_len,
2298 cop->co_llc.v.llc_len);
2300 if (bcmp(ap->llc.v.llc_info,
2301 cop->co_llc.v.llc_info, i) == 0)
2306 * If no header overlaps, then we're done
2319 * This function will terminate a connection, including notifying the
2320 * user, if necessary, and freeing up control block memory. The caller
2321 * is responsible for managing the connection VCC.
2326 * cop pointer to connection block
2327 * cause pointer to cause of close
2334 atm_cm_closeconn(cop, cause)
2335 Atm_connection *cop;
2336 struct t_atm_cause *cause;
2340 * Decide whether user needs notification
2342 switch (cop->co_state) {
2350 * Yup, let 'em know connection is gone
2353 (*cop->co_endpt->ep_cleared)(cop->co_toku, cause);
2358 * Nope,they should know already
2363 panic("atm_cm_closeconn: bogus state");
2367 * Unlink connection from its queues
2369 switch (cop->co_state) {
2372 uma_zfree(atm_attributes_zone, cop->co_lattr);
2373 UNLINK(cop, Atm_connection, atm_listen_queue, co_next);
2378 * Remove connection from multiplexor queue
2380 if (cop->co_mxh != cop) {
2382 * Connection is down the chain, just unlink it
2384 UNLINK(cop, Atm_connection, cop->co_mxh, co_next);
2386 } else if (cop->co_next != NULL) {
2388 * Connection is at the head of a non-singleton chain,
2389 * so unlink and reset the chain head
2391 Atm_connection *t, *nhd;
2393 t = nhd = cop->co_next;
2399 nhd->co_connvc->cvc_conn = nhd;
2404 * Free the connection block
2406 cop->co_state = COS_FREE;
2407 uma_zfree(atm_connection_zone, cop);
2413 * Close Connection VCC
2415 * This function will terminate a connection VCC, including releasing the
2416 * the call to the signalling manager, terminating the VCC protocol stack,
2417 * and freeing up control block memory.
2422 * cvp pointer to connection VCC block
2435 * Break links with the connection block
2437 cvp->cvc_conn = NULL;
2440 * Cancel any running timer
2445 * Free queued packets
2447 while (cvp->cvc_rcvq) {
2451 cvp->cvc_rcvq = KB_QNEXT(m);
2457 * Unlink from any queues
2459 if (cvp->cvc_flags & CVCF_INCOMQ) {
2460 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
2461 atm_incoming_qlen--;
2462 cvp->cvc_flags &= ~CVCF_INCOMQ;
2464 } else if (cvp->cvc_flags & CVCF_CONNQ) {
2465 DEQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
2466 cvp->cvc_flags &= ~CVCF_CONNQ;
2470 * Release the signalling call
2472 switch (cvp->cvc_state) {
2480 cvp->cvc_state = CVCS_RELEASE;
2481 switch ((*cvp->cvc_sigmgr->sm_release)
2482 (cvp->cvc_vcc, &err)) {
2486 * Looks good so far...
2490 case CALL_PROCEEDING:
2492 * We'll have to wait for the call to clear
2498 * If there's a memory shortage, retry later.
2499 * Otherwise who knows what's going on....
2501 if ((err == ENOMEM) || (err == ENOBUFS)) {
2502 CVC_TIMER(cvp, 1 * ATM_HZ);
2506 "atm_cm_closevc: release %d\n", err);
2515 cvp->cvc_state = CVCS_REJECT;
2516 switch ((*cvp->cvc_sigmgr->sm_reject)
2517 (cvp->cvc_vcc, &err)) {
2521 * Looks good so far...
2527 * If there's a memory shortage, retry later.
2528 * Otherwise who knows what's going on....
2530 if ((err == ENOMEM) || (err == ENOBUFS)) {
2531 CVC_TIMER(cvp, 1 * ATM_HZ);
2535 "atm_cm_closevc: reject %d\n", err);
2544 * No need for anything here
2549 panic("atm_cm_closevc: bogus state");
2553 * Now terminate the stack
2555 if (cvp->cvc_tokl) {
2556 cvp->cvc_state = CVCS_TERM;
2559 * Wait until stack is unwound before terminating
2561 if ((cvp->cvc_downcnt > 0) || (cvp->cvc_upcnt > 0)) {
2566 STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].term,
2567 cvp->cvc_lower, cvp->cvc_tokl, cvp, 0, 0, err);
2569 cvp->cvc_tokl = NULL;
2573 * Let signalling manager finish up
2575 cvp->cvc_state = CVCS_FREE;
2577 (void) (*cvp->cvc_sigmgr->sm_free)(cvp->cvc_vcc);
2581 * Finally, free our own control blocks
2583 uma_zfree(atm_connvc_zone, cvp);
2589 * Process a Connection VCC timeout
2591 * Called when a previously scheduled cvc control block timer expires.
2592 * Processing will be based on the current cvc state.
2597 * tip pointer to cvc timer control block
2605 struct atm_time *tip;
2607 Atm_connection *cop, *cop2;
2611 * Back-off to cvc control block
2613 cvp = (Atm_connvc *)
2614 ((caddr_t)tip - (int)(&((Atm_connvc *)0)->cvc_time));
2617 * Process timeout based on protocol state
2619 switch (cvp->cvc_state) {
2627 if ((cvp->cvc_flags & CVCF_ABORTING) == 0)
2631 * Terminate all connections
2633 cop = cvp->cvc_conn;
2635 cop2 = cop->co_next;
2636 atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
2643 atm_cm_closevc(cvp);
2651 * Retry failed operation
2653 atm_cm_closevc(cvp);
2659 "atm_cm_timeout: invalid state: cvp=%p, state=%d\n",
2660 cvp, cvp->cvc_state);
2666 * CPCS User Control Commands
2668 * This function is called by an endpoint user to pass a control command
2669 * across a CPCS data API. Mostly we just send these down the stack.
2672 * cmd stack command code
2673 * cop pointer to connection block
2677 * 0 command output successful
2678 * errno output failed - reason indicated
2682 atm_cm_cpcs_ctl(cmd, cop, arg)
2684 Atm_connection *cop;
2691 * Validate connection state
2693 if (cop->co_state != COS_ACTIVE) {
2698 cvp = cop->co_connvc;
2699 if (cvp->cvc_state != CVCS_ACTIVE) {
2704 if (cvp->cvc_attr.api != CMAPI_CPCS) {
2723 * This function is called by an endpoint user to output a data packet
2724 * across a CPCS data API. After we've validated the connection state, the
2725 * packet will be encapsulated (if necessary) and sent down the data stack.
2728 * cop pointer to connection block
2729 * m pointer to packet buffer chain to be output
2732 * 0 packet output successful
2733 * errno output failed - reason indicated
2737 atm_cm_cpcs_data(cop, m)
2738 Atm_connection *cop;
2742 struct attr_llc *llcp;
2748 * Validate connection state
2750 if (cop->co_state != COS_ACTIVE) {
2755 cvp = cop->co_connvc;
2756 if (cvp->cvc_state != CVCS_ACTIVE) {
2761 if (cvp->cvc_attr.api != CMAPI_CPCS) {
2767 * Add any packet encapsulation
2769 switch (cop->co_mpx) {
2779 * Need to add an LLC header
2781 llcp = &cop->co_llc;
2784 * See if there's room to add LLC header to front of packet.
2786 KB_HEADROOM(m, space);
2787 if (space < llcp->v.llc_len) {
2791 * We have to allocate another buffer and tack it
2792 * onto the front of the packet
2794 MGETHDR(n, KB_F_NOWAIT, KB_T_HEADER);
2799 KB_TAILALIGN(n, llcp->v.llc_len);
2804 * Header fits, just adjust buffer controls
2806 KB_HEADADJ(m, llcp->v.llc_len);
2810 * Add the LLC header
2812 KB_DATASTART(m, bp, void *);
2813 bcopy(llcp->v.llc_info, bp, llcp->v.llc_len);
2814 KB_PLENADJ(m, llcp->v.llc_len);
2818 panic("atm_cm_cpcs_data: mpx");
2822 * Finally, we can send the packet on its way
2824 STACK_CALL(CPCS_UNITDATA_INV, cvp->cvc_lower, cvp->cvc_tokl,
2825 cvp, (intptr_t)m, 0, err);
2833 * Process CPCS Stack Commands
2835 * This is the top of the CPCS API data stack. All upward stack commands
2836 * for the CPCS data API will be received and processed here.
2839 * cmd stack command code
2840 * tok session token (pointer to connection VCC control block)
2849 atm_cm_cpcs_upper(cmd, tok, arg1, arg2)
2855 Atm_connection *cop;
2856 Atm_connvc *cvp = tok;
2863 case CPCS_UNITDATA_SIG:
2867 m = (KBuffer *)arg1;
2869 if (cvp->cvc_state != CVCS_ACTIVE) {
2870 if (cvp->cvc_state == CVCS_ACCEPT) {
2874 * Queue up any packets received before sigmgr
2875 * notifies us of incoming call completion
2877 if (cvp->cvc_rcvqlen >= CVC_RCVQ_MAX) {
2879 atm_cm_stat.cms_rcvconnvc++;
2883 if (cvp->cvc_rcvq == NULL) {
2886 for (n = cvp->cvc_rcvq;
2887 KB_QNEXT(n) != NULL;
2896 atm_cm_stat.cms_rcvconnvc++;
2902 * Send the packet to the interface's bpf if this
2905 if (cvp->cvc_vcc != NULL &&
2906 cvp->cvc_vcc->vc_nif != NULL) {
2908 (struct ifnet *)cvp->cvc_vcc->vc_nif;
2914 * Locate packet's connection
2916 cop = cvp->cvc_conn;
2917 switch (cop->co_mpx) {
2921 * We're already there...
2927 * Find connection with matching LLC header
2929 if (KB_LEN(m) < T_ATM_LLC_MAX_LEN) {
2930 KB_PULLUP(m, T_ATM_LLC_MAX_LEN, m);
2932 atm_cm_stat.cms_llcdrop++;
2936 KB_DATASTART(m, bp, void *);
2941 if (bcmp(bp, cop->co_llc.v.llc_info,
2942 cop->co_llc.v.llc_len) == 0)
2951 * No connected user for this LLC
2954 atm_cm_stat.cms_llcid++;
2959 * Strip off the LLC header
2961 KB_HEADADJ(m, -cop->co_llc.v.llc_len);
2962 KB_PLENADJ(m, -cop->co_llc.v.llc_len);
2966 panic("atm_cm_cpcs_upper: mpx");
2970 * We've found our connection, so hand the packet off
2972 if (cop->co_state != COS_ACTIVE) {
2974 atm_cm_stat.cms_rcvconn++;
2977 (*cop->co_endpt->ep_cpcs_data)(cop->co_toku, m);
2980 case CPCS_UABORT_SIG:
2981 case CPCS_PABORT_SIG:
2983 * We don't support these (yet), so just FALLTHROUGH
2987 log(LOG_ERR, "atm_cm_cpcs_upper: unknown cmd 0x%x\n", cmd);
2993 * SAAL User Control Commands
2995 * This function is called by an endpoint user to pass a control command
2996 * across a SAAL data API. Mostly we just send these down the stack.
2999 * cmd stack command code
3000 * cop pointer to connection block
3004 * 0 command output successful
3005 * errno output failed - reason indicated
3009 atm_cm_saal_ctl(cmd, cop, arg)
3011 Atm_connection *cop;
3018 * Validate connection state
3020 if (cop->co_state != COS_ACTIVE) {
3025 cvp = cop->co_connvc;
3026 if (cvp->cvc_state != CVCS_ACTIVE) {
3031 if (cvp->cvc_attr.api != CMAPI_SAAL) {
3038 case SSCF_UNI_ESTABLISH_REQ:
3039 case SSCF_UNI_RELEASE_REQ:
3041 * Pass command down the stack
3043 STACK_CALL(cmd, cvp->cvc_lower, cvp->cvc_tokl, cvp,
3044 (intptr_t)arg, 0, err);
3059 * This function is called by an endpoint user to output a data packet
3060 * across a SAAL data API. After we've validated the connection state,
3061 * the packet will be sent down the data stack.
3064 * cop pointer to connection block
3065 * m pointer to packet buffer chain to be output
3068 * 0 packet output successful
3069 * errno output failed - reason indicated
3073 atm_cm_saal_data(cop, m)
3074 Atm_connection *cop;
3082 * Validate connection state
3084 if (cop->co_state != COS_ACTIVE) {
3089 cvp = cop->co_connvc;
3090 if (cvp->cvc_state != CVCS_ACTIVE) {
3095 if (cvp->cvc_attr.api != CMAPI_SAAL) {
3101 * Finally, we can send the packet on its way
3103 STACK_CALL(SSCF_UNI_DATA_REQ, cvp->cvc_lower, cvp->cvc_tokl,
3104 cvp, (intptr_t)m, 0, err);
3112 * Process SAAL Stack Commands
3114 * This is the top of the SAAL API data stack. All upward stack commands
3115 * for the SAAL data API will be received and processed here.
3118 * cmd stack command code
3119 * tok session token (pointer to connection VCC control block)
3128 atm_cm_saal_upper(cmd, tok, arg1, arg2)
3134 Atm_connection *cop;
3135 Atm_connvc *cvp = tok;
3140 case SSCF_UNI_ESTABLISH_IND:
3141 case SSCF_UNI_ESTABLISH_CNF:
3142 case SSCF_UNI_RELEASE_IND:
3143 case SSCF_UNI_RELEASE_CNF:
3147 cop = cvp->cvc_conn;
3148 if (cvp->cvc_state != CVCS_ACTIVE)
3150 if (cop->co_state != COS_ACTIVE)
3153 (*cop->co_endpt->ep_saal_ctl)(cmd, cop->co_toku, (void *)arg1);
3156 case SSCF_UNI_DATA_IND:
3160 cop = cvp->cvc_conn;
3161 if (cvp->cvc_state != CVCS_ACTIVE) {
3162 atm_cm_stat.cms_rcvconnvc++;
3163 KB_FREEALL((KBuffer *)arg1);
3166 if (cop->co_state != COS_ACTIVE) {
3167 atm_cm_stat.cms_rcvconn++;
3168 KB_FREEALL((KBuffer *)arg1);
3172 (*cop->co_endpt->ep_saal_data)(cop->co_toku, (KBuffer *)arg1);
3175 case SSCF_UNI_UNITDATA_IND:
3179 KB_FREEALL((KBuffer *)arg1);
3184 log(LOG_ERR, "atm_cm_saal_upper: unknown cmd 0x%x\n", cmd);
3190 * SSCOP User Control Commands
3192 * This function is called by an endpoint user to pass a control command
3193 * across a SSCOP data API. Mostly we just send these down the stack.
3196 * cmd stack command code
3197 * cop pointer to connection block
3202 * 0 command output successful
3203 * errno output failed - reason indicated
3207 atm_cm_sscop_ctl(cmd, cop, arg1, arg2)
3209 Atm_connection *cop;
3217 * Validate connection state
3219 if (cop->co_state != COS_ACTIVE) {
3224 cvp = cop->co_connvc;
3225 if (cvp->cvc_state != CVCS_ACTIVE) {
3230 if (cvp->cvc_attr.api != CMAPI_SSCOP) {
3237 case SSCOP_ESTABLISH_REQ:
3238 case SSCOP_ESTABLISH_RSP:
3239 case SSCOP_RELEASE_REQ:
3240 case SSCOP_RESYNC_REQ:
3241 case SSCOP_RESYNC_RSP:
3242 case SSCOP_RECOVER_RSP:
3243 case SSCOP_RETRIEVE_REQ:
3245 * Pass command down the stack
3247 STACK_CALL(cmd, cvp->cvc_lower, cvp->cvc_tokl, cvp,
3248 (intptr_t)arg1, (intptr_t)arg2, err);
3263 * This function is called by an endpoint user to output a data packet
3264 * across a SSCOP data API. After we've validated the connection state,
3265 * the packet will be encapsulated and sent down the data stack.
3268 * cop pointer to connection block
3269 * m pointer to packet buffer chain to be output
3272 * 0 packet output successful
3273 * errno output failed - reason indicated
3277 atm_cm_sscop_data(cop, m)
3278 Atm_connection *cop;
3286 * Validate connection state
3288 if (cop->co_state != COS_ACTIVE) {
3293 cvp = cop->co_connvc;
3294 if (cvp->cvc_state != CVCS_ACTIVE) {
3299 if (cvp->cvc_attr.api != CMAPI_SSCOP) {
3305 * Finally, we can send the packet on its way
3307 STACK_CALL(SSCOP_DATA_REQ, cvp->cvc_lower, cvp->cvc_tokl,
3308 cvp, (intptr_t)m, 0, err);
3316 * Process SSCOP Stack Commands
3318 * This is the top of the SSCOP API data stack. All upward stack commands
3319 * for the SSCOP data API will be received and processed here.
3322 * cmd stack command code
3323 * tok session token (pointer to connection VCC control block)
3332 atm_cm_sscop_upper(cmd, tok, arg1, arg2)
3338 Atm_connection *cop;
3339 Atm_connvc *cvp = tok;
3343 case SSCOP_ESTABLISH_IND:
3344 case SSCOP_ESTABLISH_CNF:
3345 case SSCOP_RELEASE_IND:
3346 case SSCOP_RESYNC_IND:
3350 cop = cvp->cvc_conn;
3351 if ((cvp->cvc_state != CVCS_ACTIVE) ||
3352 (cop->co_state != COS_ACTIVE)) {
3353 KB_FREEALL((KBuffer *)arg1);
3357 (*cop->co_endpt->ep_sscop_ctl)
3358 (cmd, cop->co_toku, (void *)arg1, (void *)arg2);
3361 case SSCOP_RELEASE_CNF:
3362 case SSCOP_RESYNC_CNF:
3363 case SSCOP_RECOVER_IND:
3364 case SSCOP_RETRIEVE_IND:
3365 case SSCOP_RETRIEVECMP_IND:
3369 cop = cvp->cvc_conn;
3370 if ((cvp->cvc_state != CVCS_ACTIVE) ||
3371 (cop->co_state != COS_ACTIVE))
3374 (*cop->co_endpt->ep_sscop_ctl)
3375 (cmd, cop->co_toku, (void *)arg1, (void *)arg2);
3378 case SSCOP_DATA_IND:
3382 cop = cvp->cvc_conn;
3383 if (cvp->cvc_state != CVCS_ACTIVE) {
3384 atm_cm_stat.cms_rcvconnvc++;
3385 KB_FREEALL((KBuffer *)arg1);
3388 if (cop->co_state != COS_ACTIVE) {
3389 atm_cm_stat.cms_rcvconn++;
3390 KB_FREEALL((KBuffer *)arg1);
3394 (*cop->co_endpt->ep_sscop_data)
3395 (cop->co_toku, (KBuffer *)arg1, arg2);
3398 case SSCOP_UNITDATA_IND:
3402 KB_FREEALL((KBuffer *)arg1);
3407 log(LOG_ERR, "atm_cm_sscop_upper: unknown cmd 0x%x\n", cmd);
3413 * Register an ATM Endpoint Service
3415 * Every ATM endpoint service must register itself here before it can
3416 * issue or receive any connection requests.
3419 * epp pointer to endpoint definition structure
3422 * 0 registration successful
3423 * errno registration failed - reason indicated
3427 atm_endpoint_register(epp)
3433 * See if we need to be initialized
3441 if (epp->ep_id > ENDPT_MAX) {
3445 if (atm_endpoints[epp->ep_id] != NULL) {
3451 * Add endpoint to list
3453 atm_endpoints[epp->ep_id] = epp;
3461 * De-register an ATM Endpoint Service
3463 * Each ATM endpoint service provider must de-register its registered
3464 * endpoint(s) before terminating. Specifically, loaded kernel modules
3465 * must de-register their services before unloading themselves.
3468 * epp pointer to endpoint definition structure
3471 * 0 de-registration successful
3472 * errno de-registration failed - reason indicated
3476 atm_endpoint_deregister(epp)
3484 if (epp->ep_id > ENDPT_MAX) {
3488 if (atm_endpoints[epp->ep_id] != epp) {
3494 * Remove endpoint from list
3496 atm_endpoints[epp->ep_id] = NULL;