3 * ===================================
4 * HARP | Host ATM Research Platform
5 * ===================================
8 * This Host ATM Research Platform ("HARP") file (the "Software") is
9 * made available by Network Computing Services, Inc. ("NetworkCS")
10 * "AS IS". NetworkCS does not provide maintenance, improvements or
11 * support of any kind.
13 * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14 * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15 * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16 * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17 * In no event shall NetworkCS be responsible for any damages, including
18 * but not limited to consequential damages, arising from or relating to
19 * any use of the Software or related support.
21 * Copyright 1994-1998 Network Computing Services, Inc.
23 * Copies of this Software may be made, however, the above copyright
24 * notice must be reproduced on all copies.
26 * @(#) $FreeBSD: src/sys/netatm/atm_cm.c,v 1.6 1999/08/28 00:48:34 peter Exp $
27 * @(#) $DragonFly: src/sys/netproto/atm/atm_cm.c,v 1.7 2006/01/14 13:36:39 swildner Exp $
34 * ATM Connection Manager
38 #include "kern_include.h"
39 #include <sys/kernel.h>
44 struct atm_cm_stat atm_cm_stat
= {0};
45 struct callout atm_cm_procinq_ch
;
47 SYSINIT(atm_cm
, SI_SUB_DRIVERS
, SI_ORDER_ANY
, callout_init
, &atm_cm_procinq_ch
);
52 static void atm_cm_cpcs_upper (int, void *, int, int);
53 static void atm_cm_saal_upper (int, void *, int, int);
54 static void atm_cm_sscop_upper (int, void *, int, int);
55 static Atm_connvc
* atm_cm_share_llc (Atm_attributes
*);
56 static void atm_cm_closeconn (Atm_connection
*,
57 struct t_atm_cause
*);
58 static void atm_cm_closevc (Atm_connvc
*);
59 static void atm_cm_timeout (struct atm_time
*);
60 static KTimeout_ret
atm_cm_procinq (void *);
61 static void atm_cm_incall (Atm_connvc
*);
62 static int atm_cm_accept (Atm_connvc
*, Atm_connection
*);
67 static Queue_t atm_connection_queue
= {NULL
};
68 static Queue_t atm_incoming_queue
= {NULL
};
69 static int atm_incoming_qlen
= 0;
70 static Atm_connection
*atm_listen_queue
= NULL
;
71 static struct attr_cause atm_cause_tmpl
=
72 {T_ATM_PRESENT
, {T_ATM_ITU_CODING
, T_ATM_LOC_USER
, 0, {0, 0, 0, 0}}};
75 * Stack commands, indexed by API
81 {CPCS_INIT
, CPCS_TERM
}, /* CMAPI_CPCS */
82 {SSCF_UNI_INIT
, SSCF_UNI_TERM
}, /* CMAPI_SAAL */
83 {SSCOP_INIT
, SSCOP_TERM
}, /* CMAPI_SSCOP */
87 static struct sp_info atm_connection_pool
= {
88 "atm connection pool", /* si_name */
89 sizeof(Atm_connection
), /* si_blksiz */
93 static struct sp_info atm_connvc_pool
= {
94 "atm connection vcc pool", /* si_name */
95 sizeof(Atm_connvc
), /* si_blksiz */
102 * Initiate Outgoing ATM Call
104 * Called by an endpoint service to create a new Connection Manager API
105 * instance and to initiate an outbound ATM connection. The endpoint
106 * provided token will be used in all further CM -> endpoint function
107 * calls, and the returned connection block pointer must be used in all
108 * subsequent endpoint -> CM function calls.
110 * If the return indicates that the connection setup has been immediately
111 * successful (typically only for PVCs and shared SVCs), then the connection
112 * is ready for data transmission.
114 * If the return indicates that the connection setup is still in progress,
115 * then the endpoint must wait for notification from the Connection Manager
116 * indicating the final status of the call setup. If the call setup completes
117 * successfully, then a "call connected" notification will be sent to the
118 * endpoint by the Connection Manager. If the call setup fails, then the
119 * endpoint will receive a "call cleared" notification.
121 * All connection instances must be freed with an atm_cm_release() call.
124 * epp pointer to endpoint definition structure
125 * token endpoint's connection instance token
126 * ap pointer to requested connection attributes
127 * copp pointer to location to return allocated connection block
130 * 0 connection has been successfully established
131 * EINPROGRESS connection establishment is in progress
132 * errno connection failed - reason indicated
136 atm_cm_connect(Atm_endpoint
*epp
, void *token
, Atm_attributes
*ap
,
137 Atm_connection
**copp
)
143 struct stack_list sl
;
144 void (*upf
)(int, void *, int, int);
151 * Get a connection block
153 cop
= (Atm_connection
*)atm_allocate(&atm_connection_pool
);
158 * Initialize connection info
161 cop
->co_toku
= token
;
164 * Initialize stack list index
169 * Validate and extract useful attribute information
173 * Must specify a network interface (validated below)
175 if (ap
->nif
== NULL
) {
186 upf
= atm_cm_cpcs_upper
;
190 sl
.sl_sap
[sli
++] = SAP_SSCF_UNI
;
191 sl
.sl_sap
[sli
++] = SAP_SSCOP
;
192 upf
= atm_cm_saal_upper
;
196 sl
.sl_sap
[sli
++] = SAP_SSCOP
;
197 upf
= atm_cm_sscop_upper
;
208 if (ap
->aal
.tag
!= T_ATM_PRESENT
) {
213 switch (ap
->aal
.type
) {
216 sl
.sl_sap
[sli
++] = SAP_CPCS_AAL5
;
217 sl
.sl_sap
[sli
++] = SAP_SAR_AAL5
;
218 sl
.sl_sap
[sli
++] = SAP_ATM
;
222 sl
.sl_sap
[sli
++] = SAP_CPCS_AAL3_4
;
223 sl
.sl_sap
[sli
++] = SAP_SAR_AAL3_4
;
224 sl
.sl_sap
[sli
++] = SAP_ATM
;
233 * Broadband Bearer Attributes
235 if (ap
->bearer
.tag
!= T_ATM_PRESENT
) {
240 switch (ap
->bearer
.v
.connection_configuration
) {
243 cop
->co_flags
|= COF_P2P
;
246 case T_ATM_1_TO_MANY
:
248 cop
->co_flags
|= COF_P2MP
;
258 * Logical Link Control Attributes
260 if (ap
->llc
.tag
== T_ATM_PRESENT
) {
261 if ((ap
->blli
.tag_l2
!= T_ATM_PRESENT
) ||
262 (ap
->blli
.v
.layer_2_protocol
.ID_type
!= T_ATM_SIMPLE_ID
) ||
263 (ap
->blli
.v
.layer_2_protocol
.ID
.simple_ID
!=
264 T_ATM_BLLI2_I8802
) ||
265 (ap
->llc
.v
.llc_len
< T_ATM_LLC_MIN_LEN
) ||
266 (ap
->llc
.v
.llc_len
> T_ATM_LLC_MAX_LEN
)) {
270 cop
->co_mpx
= ATM_ENC_LLC
;
271 cop
->co_llc
= ap
->llc
;
273 cop
->co_mpx
= ATM_ENC_NULL
;
276 * Called Party Attributes
278 if (ap
->called
.tag
!= T_ATM_PRESENT
) {
283 if ((ap
->called
.addr
.address_format
== T_ATM_ABSENT
) ||
284 (ap
->called
.addr
.address_length
== 0)) {
290 * Calling Party Attributes
292 if (ap
->calling
.tag
!= T_ATM_ABSENT
) {
298 * Quality of Service Attributes
300 if (ap
->qos
.tag
!= T_ATM_PRESENT
) {
306 * Terminate stack list
313 * Let multiplexors decide whether we need a new VCC
315 switch (cop
->co_mpx
) {
319 * All of these connections require a new VCC
325 * See if we can share an existing LLC connection
327 cvp
= atm_cm_share_llc(ap
);
332 * We've got a connection to share
334 cop
->co_connvc
= cvp
;
335 if (cvp
->cvc_state
== CVCS_ACTIVE
) {
336 cop
->co_state
= COS_ACTIVE
;
339 cop
->co_state
= COS_OUTCONN
;
342 LINK2TAIL(cop
, Atm_connection
, cvp
->cvc_conn
->co_mxh
, co_next
);
343 cop
->co_mxh
= cvp
->cvc_conn
->co_mxh
;
350 panic("atm_cm_connect: unknown mpx");
354 * If we get here, it means we need to create
355 * a new VCC for this connection
359 * Validate that network interface is registered and that
360 * a signalling manager is attached
362 for (pip
= atm_interface_head
; pip
!= NULL
; pip
= pip
->pif_next
) {
364 for (nip
= pip
->pif_nif
; nip
; nip
= nip
->nif_pnext
) {
376 if ((smp
= pip
->pif_sigmgr
) == NULL
) {
382 * Get a connection VCC block
384 cvp
= (Atm_connvc
*)atm_allocate(&atm_connvc_pool
);
391 * Save VCC attributes
394 cvp
->cvc_flags
|= CVCF_CALLER
;
397 * Link the control blocks
399 cop
->co_connvc
= cvp
;
401 cvp
->cvc_sigmgr
= smp
;
404 * Create a service stack
406 err
= atm_create_stack(cvp
, &sl
, upf
);
408 cvp
->cvc_state
= CVCS_CLEAR
;
414 * Let the signalling manager handle the VCC creation
416 cvp
->cvc_state
= CVCS_SETUP
;
417 switch ((*smp
->sm_setup
)(cvp
, &err
)) {
421 * Connection is fully setup - initialize the stack
423 cvp
->cvc_state
= CVCS_INIT
;
424 STACK_CALL(atm_stackcmds
[ap
->api
].init
, cvp
->cvc_lower
,
425 cvp
->cvc_tokl
, cvp
, ap
->api_init
, 0, err2
);
427 panic("atm_cm_connect: init");
429 if (cvp
->cvc_flags
& CVCF_ABORTING
) {
431 * Someone on the stack bailed out...schedule the
432 * VCC and stack termination
438 * Everything looks fine from here
440 cvp
->cvc_state
= CVCS_ACTIVE
;
441 cop
->co_state
= COS_ACTIVE
;
447 * Terminate stack and clean up before we leave
449 cvp
->cvc_state
= CVCS_CLEAR
;
453 case CALL_PROCEEDING
:
455 * We'll just wait for final call status
457 cop
->co_state
= COS_OUTCONN
;
462 panic("atm_cm_connect: setup");
469 if (err
&& err
!= EINPROGRESS
) {
471 * Undo any partial setup stuff
474 atm_free((caddr_t
)cop
);
477 * Finish connection setup
480 cvp
->cvc_flags
|= CVCF_CONNQ
;
481 ENQUEUE(cvp
, Atm_connvc
, cvc_q
, atm_connection_queue
);
482 LINK2TAIL(cop
, Atm_connection
, cop
->co_mxh
, co_next
);
491 * Listen for Incoming ATM Calls
493 * Called by an endpoint service in order to indicate its willingness to
494 * accept certain incoming calls. The types of calls which the endpoint
495 * is prepared to accept are specified in the Atm_attributes parameter.
497 * For each call which meets the criteria specified by the endpoint, the
498 * endpoint service will receive an incoming call notification via the
499 * endpoint's ep_incoming() function.
501 * To cancel the listening connection, the endpoint user should invoke
505 * epp pointer to endpoint definition structure
506 * token endpoint's listen instance token
507 * ap pointer to listening connection attributes
508 * copp pointer to location to return allocated connection block
511 * 0 listening connection installed
512 * errno listen failed - reason indicated
516 atm_cm_listen(Atm_endpoint
*epp
, void *token
, Atm_attributes
*ap
,
517 Atm_connection
**copp
)
525 * Get a connection block
527 cop
= (Atm_connection
*)atm_allocate(&atm_connection_pool
);
532 * Initialize connection info
535 cop
->co_toku
= token
;
539 * Validate and extract useful attribute information
560 switch (ap
->aal
.tag
) {
564 switch (ap
->aal
.type
) {
586 * Broadband High Layer Information Attributes
588 switch (ap
->bhli
.tag
) {
601 * Broadband Low Layer Information Attributes
603 switch (ap
->blli
.tag_l2
) {
615 switch (ap
->blli
.tag_l3
) {
628 * Logical Link Control Attributes
630 switch (ap
->llc
.tag
) {
633 if ((ap
->blli
.tag_l2
!= T_ATM_PRESENT
) ||
634 (ap
->blli
.v
.layer_2_protocol
.ID_type
!= T_ATM_SIMPLE_ID
) ||
635 (ap
->blli
.v
.layer_2_protocol
.ID
.simple_ID
!=
636 T_ATM_BLLI2_I8802
) ||
637 (ap
->llc
.v
.llc_len
< T_ATM_LLC_MIN_LEN
) ||
638 (ap
->llc
.v
.llc_len
> T_ATM_LLC_MAX_LEN
)) {
642 cop
->co_mpx
= ATM_ENC_LLC
;
643 cop
->co_llc
= ap
->llc
;
648 cop
->co_mpx
= ATM_ENC_NULL
;
657 * Called Party Attributes
659 switch (ap
->called
.tag
) {
662 switch (ap
->called
.addr
.address_format
) {
665 ap
->called
.tag
= T_ATM_ABSENT
;
684 * Get an attribute block and save listening attributes
686 cop
->co_lattr
= (Atm_attributes
*)atm_allocate(&atm_attributes_pool
);
687 if (cop
->co_lattr
== NULL
) {
691 *cop
->co_lattr
= *ap
;
694 * Now try to register the listening connection
697 if (atm_cm_match(cop
->co_lattr
, NULL
) != NULL
) {
699 * Can't have matching listeners
704 cop
->co_state
= COS_LISTEN
;
705 LINK2TAIL(cop
, Atm_connection
, atm_listen_queue
, co_next
);
713 * Undo any partial setup stuff
717 atm_free((caddr_t
)cop
->co_lattr
);
718 atm_free((caddr_t
)cop
);
722 * Finish connection setup
731 * Add to LLC Connection
733 * Called by an endpoint service to create a new Connection Manager API
734 * instance to be associated with an LLC-multiplexed connection instance
735 * which has been previously created. The endpoint provided token will
736 * be used in all further CM -> endpoint function calls, and the returned
737 * connection block pointer must be used in all subsequent endpoint -> CM
740 * If the return indicates that the connection setup has been immediately
741 * successful, then the connection is ready for data transmission.
743 * If the return indicates that the connection setup is still in progress,
744 * then the endpoint must wait for notification from the Connection Manager
745 * indicating the final status of the call setup. If the call setup completes
746 * successfully, then a "call connected" notification will be sent to the
747 * endpoint by the Connection Manager. If the call setup fails, then the
748 * endpoint will receive a "call cleared" notification.
750 * All connection instances must be freed with an atm_cm_release() call.
753 * epp pointer to endpoint definition structure
754 * token endpoint's connection instance token
755 * llc pointer to llc attributes for new connection
756 * ecop pointer to existing connection block
757 * copp pointer to location to return allocated connection block
760 * 0 connection has been successfully established
761 * EINPROGRESS connection establishment is in progress
762 * errno addllc failed - reason indicated
766 atm_cm_addllc(Atm_endpoint
*epp
, void *token
, struct attr_llc
*llc
,
767 Atm_connection
*ecop
, Atm_connection
**copp
)
769 Atm_connection
*cop
, *cop2
;
776 * Check out requested LLC attributes
778 if ((llc
->tag
!= T_ATM_PRESENT
) ||
779 ((llc
->v
.flags
& T_ATM_LLC_SHARING
) == 0) ||
780 (llc
->v
.llc_len
< T_ATM_LLC_MIN_LEN
) ||
781 (llc
->v
.llc_len
> T_ATM_LLC_MAX_LEN
))
785 * Get a connection block
787 cop
= (Atm_connection
*)atm_allocate(&atm_connection_pool
);
792 * Initialize connection info
795 cop
->co_toku
= token
;
801 * Ensure that supplied connection is really valid
804 for (cvp
= Q_HEAD(atm_connection_queue
, Atm_connvc
); cvp
;
805 cvp
= Q_NEXT(cvp
, Atm_connvc
, cvc_q
)) {
806 for (cop2
= cvp
->cvc_conn
; cop2
; cop2
= cop2
->co_next
) {
818 switch (ecop
->co_state
) {
835 * Connection must be LLC multiplexed and shared
837 if ((ecop
->co_mpx
!= ATM_ENC_LLC
) ||
838 ((ecop
->co_llc
.v
.flags
& T_ATM_LLC_SHARING
) == 0)) {
844 * This new LLC header must be unique for this VCC
848 int i
= MIN(llc
->v
.llc_len
, cop2
->co_llc
.v
.llc_len
);
850 if (KM_CMP(llc
->v
.llc_info
, cop2
->co_llc
.v
.llc_info
, i
) == 0) {
855 cop2
= cop2
->co_next
;
859 * Everything seems to check out
861 cop
->co_flags
= ecop
->co_flags
;
862 cop
->co_state
= ecop
->co_state
;
863 cop
->co_mpx
= ecop
->co_mpx
;
864 cop
->co_connvc
= ecop
->co_connvc
;
866 LINK2TAIL(cop
, Atm_connection
, ecop
->co_mxh
, co_next
);
867 cop
->co_mxh
= ecop
->co_mxh
;
872 if (err
&& err
!= EINPROGRESS
) {
874 * Undo any partial setup stuff
877 atm_free((caddr_t
)cop
);
880 * Pass new connection back to caller
892 * cop pointer to connection block
893 * id identifier for party to be added
894 * addr address of party to be added
897 * 0 addparty successful
898 * errno addparty failed - reason indicated
902 atm_cm_addparty(Atm_connection
*cop
, int id
, struct t_atm_sap
*addr
)
912 * cop pointer to connection block
913 * id identifier for party to be added
914 * cause pointer to cause of drop
917 * 0 dropparty successful
918 * errno dropparty failed - reason indicated
922 atm_cm_dropparty(Atm_connection
*cop
, int id
, struct t_atm_cause
*cause
)
929 * Release Connection Resources
931 * Called by the endpoint service in order to terminate an ATM connection
932 * and to release all system resources for the connection. This function
933 * must be called for every allocated connection instance and must only
934 * be called by the connection's owner.
937 * cop pointer to connection block
938 * cause pointer to cause of release
941 * 0 release successful
942 * errno release failed - reason indicated
946 atm_cm_release(Atm_connection
*cop
, struct t_atm_cause
*cause
)
953 * First, a quick state validation check
955 switch (cop
->co_state
) {
973 panic("atm_cm_release: bogus conn state");
977 * Check out the VCC state too
979 if ((cvp
= cop
->co_connvc
) != NULL
) {
981 switch (cvp
->cvc_state
) {
998 panic("atm_cm_release: bogus connvc state");
1002 * If we're the only connection, terminate the VCC
1004 if ((cop
->co_mxh
== cop
) && (cop
->co_next
== NULL
)) {
1005 cvp
->cvc_attr
.cause
.tag
= T_ATM_PRESENT
;
1006 cvp
->cvc_attr
.cause
.v
= *cause
;
1007 atm_cm_closevc(cvp
);
1012 * Now get rid of the connection
1014 atm_cm_closeconn(cop
, cause
);
1021 * Abort an ATM Connection VCC
1023 * This function allows any non-owner kernel entity to request an
1024 * immediate termination of an ATM VCC. This will normally be called
1025 * when encountering a catastrophic error condition that cannot be
1026 * resolved via the available stack protocols. The connection manager
1027 * will schedule the connection's termination, including notifying the
1028 * connection owner of the termination.
1030 * This function should only be called by a stack entity instance. After
1031 * calling the function, the caller should set a protocol state which just
1032 * waits for a <sap>_TERM stack command to be delivered.
1035 * cvp pointer to connection VCC block
1036 * cause pointer to cause of abort
1039 * 0 abort successful
1040 * errno abort failed - reason indicated
1044 atm_cm_abort(Atm_connvc
*cvp
, struct t_atm_cause
*cause
)
1046 ATM_DEBUG2("atm_cm_abort: cvp=%p cause=%d\n",
1047 cvp
, cause
->cause_value
);
1050 * Note that we're aborting
1052 cvp
->cvc_flags
|= CVCF_ABORTING
;
1054 switch (cvp
->cvc_state
) {
1058 * In-line code will handle this
1060 cvp
->cvc_attr
.cause
.tag
= T_ATM_PRESENT
;
1061 cvp
->cvc_attr
.cause
.v
= *cause
;
1068 * Schedule connection termination, since we want
1069 * to avoid any sequencing interactions
1071 cvp
->cvc_attr
.cause
.tag
= T_ATM_PRESENT
;
1072 cvp
->cvc_attr
.cause
.v
= *cause
;
1081 * Ignore abort, as we're already terminating
1087 "atm_cm_abort: invalid state: cvp=%p, state=%d\n",
1088 cvp
, cvp
->cvc_state
);
1095 * Incoming ATM Call Received
1097 * Called by a signalling manager to indicate that a new call request has
1098 * been received. This function will allocate and initialize the connection
1099 * manager control blocks and queue this call request. The call request
1100 * processing function, atm_cm_procinq(), will be scheduled to perform the
1104 * vcp pointer to incoming call's VCC control block
1105 * ap pointer to incoming call's attributes
1108 * 0 call queuing successful
1109 * errno call queuing failed - reason indicated
1113 atm_cm_incoming(struct vccb
*vcp
, Atm_attributes
*ap
)
1120 * Do some minimal attribute validation
1124 * Must specify a network interface
1126 if (ap
->nif
== NULL
)
1132 if ((ap
->aal
.tag
!= T_ATM_PRESENT
) ||
1133 ((ap
->aal
.type
!= ATM_AAL5
) &&
1134 (ap
->aal
.type
!= ATM_AAL3_4
)))
1138 * Traffic Descriptor Attributes
1140 if ((ap
->traffic
.tag
!= T_ATM_PRESENT
) &&
1141 (ap
->traffic
.tag
!= T_ATM_ABSENT
))
1145 * Broadband Bearer Attributes
1147 if ((ap
->bearer
.tag
!= T_ATM_PRESENT
) ||
1148 ((ap
->bearer
.v
.connection_configuration
!= T_ATM_1_TO_1
) &&
1149 (ap
->bearer
.v
.connection_configuration
!= T_ATM_1_TO_MANY
)))
1153 * Broadband High Layer Attributes
1155 if ((ap
->bhli
.tag
!= T_ATM_PRESENT
) &&
1156 (ap
->bhli
.tag
!= T_ATM_ABSENT
))
1160 * Broadband Low Layer Attributes
1162 if ((ap
->blli
.tag_l2
!= T_ATM_PRESENT
) &&
1163 (ap
->blli
.tag_l2
!= T_ATM_ABSENT
))
1165 if ((ap
->blli
.tag_l3
!= T_ATM_PRESENT
) &&
1166 (ap
->blli
.tag_l3
!= T_ATM_ABSENT
))
1170 * Logical Link Control Attributes
1172 if (ap
->llc
.tag
== T_ATM_PRESENT
)
1174 ap
->llc
.tag
= T_ATM_ANY
;
1177 * Called Party Attributes
1179 if ((ap
->called
.tag
!= T_ATM_PRESENT
) ||
1180 (ap
->called
.addr
.address_format
== T_ATM_ABSENT
))
1182 if (ap
->called
.tag
== T_ATM_ABSENT
) {
1183 ap
->called
.addr
.address_format
= T_ATM_ABSENT
;
1184 ap
->called
.addr
.address_length
= 0;
1185 ap
->called
.subaddr
.address_format
= T_ATM_ABSENT
;
1186 ap
->called
.subaddr
.address_length
= 0;
1190 * Calling Party Attributes
1192 if ((ap
->calling
.tag
!= T_ATM_PRESENT
) &&
1193 (ap
->calling
.tag
!= T_ATM_ABSENT
))
1195 if (ap
->calling
.tag
== T_ATM_ABSENT
) {
1196 ap
->calling
.addr
.address_format
= T_ATM_ABSENT
;
1197 ap
->calling
.addr
.address_length
= 0;
1198 ap
->calling
.subaddr
.address_format
= T_ATM_ABSENT
;
1199 ap
->calling
.subaddr
.address_length
= 0;
1203 * Quality of Service Attributes
1205 if (ap
->qos
.tag
!= T_ATM_PRESENT
)
1209 * Transit Network Attributes
1211 if ((ap
->transit
.tag
!= T_ATM_PRESENT
) &&
1212 (ap
->transit
.tag
!= T_ATM_ABSENT
))
1218 if ((ap
->cause
.tag
!= T_ATM_PRESENT
) &&
1219 (ap
->cause
.tag
!= T_ATM_ABSENT
))
1223 * Get a connection VCC block
1225 cvp
= (Atm_connvc
*)atm_allocate(&atm_connvc_pool
);
1232 * Initialize the control block
1235 cvp
->cvc_sigmgr
= vcp
->vc_pif
->pif_sigmgr
;
1236 cvp
->cvc_attr
= *ap
;
1237 cvp
->cvc_state
= CVCS_INCOMING
;
1240 * Control queue length
1243 if (atm_incoming_qlen
>= ATM_CALLQ_MAX
) {
1250 * Queue request and schedule call processing function
1252 cvp
->cvc_flags
|= CVCF_INCOMQ
;
1253 ENQUEUE(cvp
, Atm_connvc
, cvc_q
, atm_incoming_queue
);
1254 if (atm_incoming_qlen
++ == 0) {
1255 atm_cm_procinq(NULL
);
1259 * Link for signalling manager
1261 vcp
->vc_connvc
= cvp
;
1269 * Free any resources
1272 atm_free((caddr_t
)cvp
);
1278 * VCC Connected Notification
1280 * This function is called by a signalling manager as notification that a
1281 * VCC call setup has been successful.
1284 * cvp pointer to connection VCC block
1291 atm_cm_connected(Atm_connvc
*cvp
)
1293 Atm_connection
*cop
, *cop2
;
1300 * Validate connection vcc
1302 switch (cvp
->cvc_state
) {
1306 * Initialize the stack
1308 cvp
->cvc_state
= CVCS_INIT
;
1309 STACK_CALL(atm_stackcmds
[cvp
->cvc_attr
.api
].init
,
1310 cvp
->cvc_lower
, cvp
->cvc_tokl
,
1311 cvp
, cvp
->cvc_attr
.api_init
, 0, err
);
1313 panic("atm_cm_connected: init");
1315 if (cvp
->cvc_flags
& CVCF_ABORTING
) {
1317 * Someone on the stack bailed out...notify all of the
1318 * connections and schedule the VCC termination
1320 cop
= cvp
->cvc_conn
;
1322 cop2
= cop
->co_next
;
1323 atm_cm_closeconn(cop
, &cvp
->cvc_attr
.cause
.v
);
1326 atm_cm_closevc(cvp
);
1334 * Stack already initialized
1339 panic("atm_cm_connected: connvc state");
1343 * VCC is ready for action
1345 cvp
->cvc_state
= CVCS_ACTIVE
;
1348 * Notify all connections that the call has completed
1350 cop
= cvp
->cvc_conn
;
1352 cop2
= cop
->co_next
;
1354 switch (cop
->co_state
) {
1358 cop
->co_state
= COS_ACTIVE
;
1359 (*cop
->co_endpt
->ep_connected
)(cop
->co_toku
);
1364 * May get here if an ep_connected() call (from
1365 * above) results in an atm_cm_addllc() call for
1366 * the just connected connection.
1371 panic("atm_cm_connected: connection state");
1380 * Input any queued packets
1382 while ((m
= cvp
->cvc_rcvq
) != NULL
) {
1383 cvp
->cvc_rcvq
= KB_QNEXT(m
);
1388 * Currently only supported for CPCS API
1390 atm_cm_cpcs_upper(CPCS_UNITDATA_SIG
, cvp
, (int)m
, 0);
1398 * VCC Cleared Notification
1400 * This function is called by a signalling manager as notification that a
1401 * VCC call has been cleared. The cause information describing the reason
1402 * for the call clearing will be contained in the connection VCC attributes.
1405 * cvp pointer to connection VCC block
1412 atm_cm_cleared(Atm_connvc
*cvp
)
1414 Atm_connection
*cop
, *cop2
;
1417 if ((cvp
->cvc_state
== CVCS_FREE
) ||
1418 (cvp
->cvc_state
>= CVCS_CLEAR
))
1419 panic("atm_cm_cleared");
1422 cvp
->cvc_state
= CVCS_CLEAR
;
1427 * Terminate all connections
1429 cop
= cvp
->cvc_conn
;
1431 cop2
= cop
->co_next
;
1432 atm_cm_closeconn(cop
, &cvp
->cvc_attr
.cause
.v
);
1437 * Clean up connection VCC
1439 atm_cm_closevc(cvp
);
1448 * Process Incoming Call Queue
1450 * This function is scheduled by atm_cm_incoming() in order to process
1451 * all the entries on the incoming call queue.
1454 * arg argument passed on timeout() call
1461 atm_cm_procinq(void *arg
)
1467 * Only process incoming calls up to our quota
1469 while (cnt
++ < ATM_CALLQ_MAX
) {
1473 * Get next awaiting call
1475 cvp
= Q_HEAD(atm_incoming_queue
, Atm_connvc
);
1480 DEQUEUE(cvp
, Atm_connvc
, cvc_q
, atm_incoming_queue
);
1481 atm_incoming_qlen
--;
1482 cvp
->cvc_flags
&= ~CVCF_INCOMQ
;
1493 * If we've expended our quota, reschedule ourselves
1495 if (cnt
>= ATM_CALLQ_MAX
) {
1496 callout_reset(&atm_cm_procinq_ch
, 1, atm_cm_procinq
, NULL
);
1502 * Process Incoming Call
1504 * This function will search through the listening queue and try to find
1505 * matching endpoint(s) for the incoming call. If we find any, we will
1506 * notify the endpoint service(s) of the incoming call and will then
1507 * notify the signalling manager to progress the call to an active status.
1509 * If there are no listeners for the call, the signalling manager will be
1510 * notified of a call rejection.
1512 * Called from a critical section.
1515 * cvp pointer to connection VCC for incoming call
1522 atm_cm_incall(Atm_connvc
*cvp
)
1524 Atm_connection
*cop
, *lcop
, *hcop
;
1525 Atm_attributes attr
;
1531 attr
= cvp
->cvc_attr
;
1534 * Look for matching listeners
1536 while ((lcop
= atm_cm_match(&attr
, lcop
)) != NULL
) {
1540 * Need a new connection block
1542 cop
= (Atm_connection
*)
1543 atm_allocate(&atm_connection_pool
);
1545 cvp
->cvc_attr
.cause
= atm_cause_tmpl
;
1546 cvp
->cvc_attr
.cause
.v
.cause_value
=
1547 T_ATM_CAUSE_TEMPORARY_FAILURE
;
1553 * Initialize connection from listener and incoming call
1556 cop
->co_state
= COS_INCONN
;
1557 cop
->co_mpx
= lcop
->co_mpx
;
1558 cop
->co_endpt
= lcop
->co_endpt
;
1559 cop
->co_llc
= lcop
->co_llc
;
1561 switch (attr
.bearer
.v
.connection_configuration
) {
1564 cop
->co_flags
|= COF_P2P
;
1567 case T_ATM_1_TO_MANY
:
1569 cop
->co_flags
|= COF_P2MP
;
1570 cvp
->cvc_attr
.cause
= atm_cause_tmpl
;
1571 cvp
->cvc_attr
.cause
.v
.cause_value
=
1572 T_ATM_CAUSE_BEARER_CAPABILITY_NOT_IMPLEMENTED
;
1577 * Notify endpoint of incoming call
1579 err
= (*cop
->co_endpt
->ep_incoming
)
1580 (lcop
->co_toku
, cop
, &cvp
->cvc_attr
, &cop
->co_toku
);
1585 * Endpoint has accepted the call
1587 * Setup call attributes
1590 cvp
->cvc_attr
.api
= lcop
->co_lattr
->api
;
1591 cvp
->cvc_attr
.api_init
=
1592 lcop
->co_lattr
->api_init
;
1593 cvp
->cvc_attr
.llc
= lcop
->co_lattr
->llc
;
1595 cvp
->cvc_attr
.headin
= MAX(cvp
->cvc_attr
.headin
,
1596 lcop
->co_lattr
->headin
);
1599 * Setup connection info and queueing
1601 cop
->co_state
= COS_INACCEPT
;
1602 cop
->co_connvc
= cvp
;
1603 LINK2TAIL(cop
, Atm_connection
, hcop
, co_next
);
1607 * Need a new connection block next time around
1613 * Endpoint refuses call
1620 * We're done looking for listeners
1624 * Someone actually wants the call, so notify
1625 * the signalling manager to continue
1627 cvp
->cvc_flags
|= CVCF_CONNQ
;
1628 ENQUEUE(cvp
, Atm_connvc
, cvc_q
, atm_connection_queue
);
1629 if (atm_cm_accept(cvp
, hcop
))
1634 * Nobody around to take the call
1636 cvp
->cvc_attr
.cause
= atm_cause_tmpl
;
1637 cvp
->cvc_attr
.cause
.v
.cause_value
=
1638 T_ATM_CAUSE_INCOMPATIBLE_DESTINATION
;
1643 * Clean up loose ends
1646 atm_free((caddr_t
)cop
);
1649 * Call has been accepted
1655 * Call failed - notify any endpoints of the call failure
1659 * Clean up loose ends
1662 atm_free((caddr_t
)cop
);
1664 if (cvp
->cvc_attr
.cause
.tag
!= T_ATM_PRESENT
) {
1665 cvp
->cvc_attr
.cause
= atm_cause_tmpl
;
1666 cvp
->cvc_attr
.cause
.v
.cause_value
=
1667 T_ATM_CAUSE_UNSPECIFIED_NORMAL
;
1671 Atm_connection
*cop2
= cop
->co_next
;
1672 atm_cm_closeconn(cop
, &cvp
->cvc_attr
.cause
.v
);
1677 * Tell the signalling manager to reject the call
1679 atm_cm_closevc(cvp
);
1686 * Accept an Incoming ATM Call
1688 * Some endpoint service(s) wants to accept an incoming call, so the
1689 * signalling manager will be notified to attempt to progress the call
1690 * to an active status.
1692 * If the signalling manager indicates that connection activation has
1693 * been immediately successful, then all of the endpoints will be notified
1694 * that the connection is ready for data transmission.
1696 * If the return indicates that connection activation is still in progress,
1697 * then the endpoints must wait for notification from the Connection Manager
1698 * indicating the final status of the call setup. If the call setup completes
1699 * successfully, then a "call connected" notification will be sent to the
1700 * endpoints by the Connection Manager. If the call setup fails, then the
1701 * endpoints will receive a "call cleared" notification.
1703 * Called from a critical section.
1706 * cvp pointer to connection VCC for incoming call
1707 * cop pointer to head of accepted connections
1710 * 0 connection has been successfully activated
1711 * errno accept failed - reason indicated
1715 atm_cm_accept(Atm_connvc
*cvp
, Atm_connection
*cop
)
1717 struct stack_list sl
;
1718 void (*upf
)(int, void *, int, int);
1723 * Link vcc to connections
1725 cvp
->cvc_conn
= cop
;
1728 * Initialize stack list index
1733 * Check out Data API
1735 switch (cvp
->cvc_attr
.api
) {
1738 upf
= atm_cm_cpcs_upper
;
1742 sl
.sl_sap
[sli
++] = SAP_SSCF_UNI
;
1743 sl
.sl_sap
[sli
++] = SAP_SSCOP
;
1744 upf
= atm_cm_saal_upper
;
1748 sl
.sl_sap
[sli
++] = SAP_SSCOP
;
1749 upf
= atm_cm_sscop_upper
;
1759 switch (cvp
->cvc_attr
.aal
.type
) {
1762 sl
.sl_sap
[sli
++] = SAP_CPCS_AAL5
;
1763 sl
.sl_sap
[sli
++] = SAP_SAR_AAL5
;
1764 sl
.sl_sap
[sli
++] = SAP_ATM
;
1768 sl
.sl_sap
[sli
++] = SAP_CPCS_AAL3_4
;
1769 sl
.sl_sap
[sli
++] = SAP_SAR_AAL3_4
;
1770 sl
.sl_sap
[sli
++] = SAP_ATM
;
1775 * Terminate stack list
1780 * Create a service stack
1782 err
= atm_create_stack(cvp
, &sl
, upf
);
1788 * Let the signalling manager finish the VCC activation
1790 switch ((*cvp
->cvc_sigmgr
->sm_accept
)(cvp
->cvc_vcc
, &err
)) {
1792 case CALL_PROCEEDING
:
1794 * Note that we're not finished yet
1799 case CALL_CONNECTED
:
1801 * Initialize the stack now, even if the call isn't totally
1802 * active yet. We want to avoid the delay between getting
1803 * the "call connected" event and actually notifying the
1804 * adapter to accept cells on the new VCC - if the delay is
1805 * too long, then we end up dropping the first pdus sent by
1808 cvp
->cvc_state
= CVCS_INIT
;
1809 STACK_CALL(atm_stackcmds
[cvp
->cvc_attr
.api
].init
,
1810 cvp
->cvc_lower
, cvp
->cvc_tokl
, cvp
,
1811 cvp
->cvc_attr
.api_init
, 0, err2
);
1813 panic("atm_cm_accept: init");
1815 if (cvp
->cvc_flags
& CVCF_ABORTING
) {
1817 * Someone on the stack bailed out...schedule the
1818 * VCC and stack termination
1823 * Everything looks fine from here
1826 cvp
->cvc_state
= CVCS_ACCEPT
;
1828 cvp
->cvc_state
= CVCS_ACTIVE
;
1834 * Terminate stack and clean up before we leave
1836 cvp
->cvc_state
= CVCS_CLEAR
;
1840 panic("atm_cm_accept: accept");
1846 * Call has been connected, notify endpoints
1849 Atm_connection
*cop2
= cop
->co_next
;
1851 cop
->co_state
= COS_ACTIVE
;
1852 (*cop
->co_endpt
->ep_connected
)(cop
->co_toku
);
1856 } else if (err
== EINPROGRESS
) {
1858 * Call is still in progress, endpoint must wait
1864 * Let caller know we failed
1866 cvp
->cvc_attr
.cause
= atm_cause_tmpl
;
1867 cvp
->cvc_attr
.cause
.v
.cause_value
=
1868 T_ATM_CAUSE_UNSPECIFIED_RESOURCE_UNAVAILABLE
;
1876 * Match Attributes on Listening Queue
1878 * This function will attempt to match the supplied connection attributes
1879 * with one of the registered attributes in the listening queue. The pcop
1880 * argument may be supplied in order to allow multiple listeners to share
1881 * an incoming call (if supported by the listeners).
1883 * Called from a critical section.
1886 * ap pointer to attributes to be matched
1887 * pcop pointer to the previously matched connection
1890 * addr connection with which a match was found
1895 atm_cm_match(Atm_attributes
*ap
, Atm_connection
*pcop
)
1897 Atm_connection
*cop
;
1898 Atm_attributes
*lap
;
1902 * If we've already matched a listener...
1906 * Make sure already matched listener supports sharing
1908 if ((pcop
->co_mpx
!= ATM_ENC_LLC
) ||
1909 ((pcop
->co_llc
.v
.flags
& T_ATM_LLC_SHARING
) == 0))
1913 * Position ourselves after the matched entry
1915 for (cop
= atm_listen_queue
; cop
; cop
= cop
->co_next
) {
1917 cop
= pcop
->co_next
;
1923 * Start search at top of listening queue
1925 cop
= atm_listen_queue
;
1929 * Search through listening queue
1931 for (; cop
; cop
= cop
->co_next
) {
1933 lap
= cop
->co_lattr
;
1936 * If we're trying to share, check that this entry allows it
1939 if ((cop
->co_mpx
!= ATM_ENC_LLC
) ||
1940 ((cop
->co_llc
.v
.flags
& T_ATM_LLC_SHARING
) == 0))
1945 * ALL "matchable" attributes must match
1951 if (lap
->bhli
.tag
== T_ATM_ABSENT
) {
1952 if (ap
->bhli
.tag
== T_ATM_PRESENT
)
1954 } else if (lap
->bhli
.tag
== T_ATM_PRESENT
) {
1955 if (ap
->bhli
.tag
== T_ATM_ABSENT
)
1957 if (ap
->bhli
.tag
== T_ATM_PRESENT
)
1958 if (KM_CMP(&lap
->bhli
.v
, &ap
->bhli
.v
,
1959 sizeof(struct t_atm_bhli
)))
1966 if (lap
->blli
.tag_l2
== T_ATM_ABSENT
) {
1967 if (ap
->blli
.tag_l2
== T_ATM_PRESENT
)
1969 } else if (lap
->blli
.tag_l2
== T_ATM_PRESENT
) {
1970 if (ap
->blli
.tag_l2
== T_ATM_ABSENT
)
1972 if (ap
->blli
.tag_l2
== T_ATM_PRESENT
) {
1973 if (KM_CMP(&lap
->blli
.v
.layer_2_protocol
.ID
,
1974 &ap
->blli
.v
.layer_2_protocol
.ID
,
1976 ap
->blli
.v
.layer_2_protocol
.ID
)))
1984 if (lap
->blli
.tag_l3
== T_ATM_ABSENT
) {
1985 if (ap
->blli
.tag_l3
== T_ATM_PRESENT
)
1987 } else if (lap
->blli
.tag_l3
== T_ATM_PRESENT
) {
1988 if (ap
->blli
.tag_l3
== T_ATM_ABSENT
)
1990 if (ap
->blli
.tag_l3
== T_ATM_PRESENT
) {
1991 if (KM_CMP(&lap
->blli
.v
.layer_3_protocol
.ID
,
1992 &ap
->blli
.v
.layer_3_protocol
.ID
,
1994 ap
->blli
.v
.layer_3_protocol
.ID
)))
2002 if (lap
->llc
.tag
== T_ATM_ABSENT
) {
2003 if (ap
->llc
.tag
== T_ATM_PRESENT
)
2005 } else if (lap
->llc
.tag
== T_ATM_PRESENT
) {
2006 if (ap
->llc
.tag
== T_ATM_ABSENT
)
2008 if (ap
->llc
.tag
== T_ATM_PRESENT
) {
2009 int i
= MIN(lap
->llc
.v
.llc_len
,
2012 if (KM_CMP(lap
->llc
.v
.llc_info
,
2013 ap
->llc
.v
.llc_info
, i
))
2021 if (lap
->aal
.tag
== T_ATM_ABSENT
) {
2022 if (ap
->aal
.tag
== T_ATM_PRESENT
)
2024 } else if (lap
->aal
.tag
== T_ATM_PRESENT
) {
2025 if (ap
->aal
.tag
== T_ATM_ABSENT
)
2027 if (ap
->aal
.tag
== T_ATM_PRESENT
) {
2028 if (lap
->aal
.type
!= ap
->aal
.type
)
2030 if (lap
->aal
.type
== ATM_AAL5
) {
2031 if (lap
->aal
.v
.aal5
.SSCS_type
!=
2032 ap
->aal
.v
.aal5
.SSCS_type
)
2035 if (lap
->aal
.v
.aal4
.SSCS_type
!=
2036 ap
->aal
.v
.aal4
.SSCS_type
)
2045 if (lap
->called
.tag
== T_ATM_ABSENT
) {
2046 if (ap
->called
.tag
== T_ATM_PRESENT
)
2048 } else if (lap
->called
.tag
== T_ATM_PRESENT
) {
2049 if (ap
->called
.tag
== T_ATM_ABSENT
)
2051 if (ap
->called
.tag
== T_ATM_PRESENT
) {
2052 if ((!ATM_ADDR_EQUAL(&lap
->called
.addr
,
2053 &ap
->called
.addr
)) ||
2054 (!ATM_ADDR_EQUAL(&lap
->called
.subaddr
,
2055 &ap
->called
.subaddr
)))
2061 * Found a full match - return it
2071 * Find Shareable LLC VCC
2073 * Given a endpoint-supplied connection attribute using LLC multiplexing,
2074 * this function will attempt to locate an existing connection which meets
2075 * the requirements of the supplied attributes.
2077 * Called from a critical section.
2080 * ap pointer to requested attributes
2083 * addr shareable LLC connection VCC
2084 * 0 no shareable VCC available
2088 atm_cm_share_llc(Atm_attributes
*ap
)
2090 Atm_connection
*cop
;
2094 * Is requestor willing to share?
2096 if ((ap
->llc
.v
.flags
& T_ATM_LLC_SHARING
) == 0)
2100 * Try to find a shareable connection
2102 for (cvp
= Q_HEAD(atm_connection_queue
, Atm_connvc
); cvp
;
2103 cvp
= Q_NEXT(cvp
, Atm_connvc
, cvc_q
)) {
2106 * Dont use terminating connections
2108 switch (cvp
->cvc_state
) {
2120 * Is connection LLC and shareable?
2122 if ((cvp
->cvc_attr
.llc
.tag
!= T_ATM_PRESENT
) ||
2123 ((cvp
->cvc_attr
.llc
.v
.flags
& T_ATM_LLC_SHARING
) == 0))
2127 * Match requested attributes with existing connection
2129 if (ap
->nif
!= cvp
->cvc_attr
.nif
)
2132 if ((ap
->api
!= cvp
->cvc_attr
.api
) ||
2133 (ap
->api_init
!= cvp
->cvc_attr
.api_init
))
2139 if (cvp
->cvc_flags
& CVCF_CALLER
) {
2140 if ((!ATM_ADDR_EQUAL(&ap
->called
.addr
,
2141 &cvp
->cvc_attr
.called
.addr
)) ||
2142 (!ATM_ADDR_EQUAL(&ap
->called
.subaddr
,
2143 &cvp
->cvc_attr
.called
.subaddr
)))
2146 if (cvp
->cvc_attr
.calling
.tag
!= T_ATM_PRESENT
)
2148 if ((!ATM_ADDR_EQUAL(&ap
->called
.addr
,
2149 &cvp
->cvc_attr
.calling
.addr
)) ||
2150 (!ATM_ADDR_EQUAL(&ap
->called
.subaddr
,
2151 &cvp
->cvc_attr
.calling
.subaddr
)))
2158 if (ap
->aal
.type
== ATM_AAL5
) {
2159 struct t_atm_aal5
*ap5
, *cv5
;
2161 ap5
= &ap
->aal
.v
.aal5
;
2162 cv5
= &cvp
->cvc_attr
.aal
.v
.aal5
;
2164 if ((cvp
->cvc_attr
.aal
.type
!= ATM_AAL5
) ||
2165 (ap5
->SSCS_type
!= cv5
->SSCS_type
))
2168 if (cvp
->cvc_flags
& CVCF_CALLER
) {
2169 if (ap5
->forward_max_SDU_size
>
2170 cv5
->forward_max_SDU_size
)
2173 if (ap5
->forward_max_SDU_size
>
2174 cv5
->backward_max_SDU_size
)
2178 struct t_atm_aal4
*ap4
, *cv4
;
2180 ap4
= &ap
->aal
.v
.aal4
;
2181 cv4
= &cvp
->cvc_attr
.aal
.v
.aal4
;
2183 if ((cvp
->cvc_attr
.aal
.type
!= ATM_AAL3_4
) ||
2184 (ap4
->SSCS_type
!= cv4
->SSCS_type
))
2187 if (cvp
->cvc_flags
& CVCF_CALLER
) {
2188 if (ap4
->forward_max_SDU_size
>
2189 cv4
->forward_max_SDU_size
)
2192 if (ap4
->forward_max_SDU_size
>
2193 cv4
->backward_max_SDU_size
)
2199 * Traffic Descriptor
2201 if ((ap
->traffic
.tag
!= T_ATM_PRESENT
) ||
2202 (cvp
->cvc_attr
.traffic
.tag
!= T_ATM_PRESENT
) ||
2203 (ap
->traffic
.v
.best_effort
!= T_YES
) ||
2204 (cvp
->cvc_attr
.traffic
.v
.best_effort
!= T_YES
))
2210 if (ap
->bearer
.v
.connection_configuration
!=
2211 cvp
->cvc_attr
.bearer
.v
.connection_configuration
)
2217 if (cvp
->cvc_flags
& CVCF_CALLER
) {
2218 if ((ap
->qos
.v
.forward
.qos_class
!=
2219 cvp
->cvc_attr
.qos
.v
.forward
.qos_class
) ||
2220 (ap
->qos
.v
.backward
.qos_class
!=
2221 cvp
->cvc_attr
.qos
.v
.backward
.qos_class
))
2224 if ((ap
->qos
.v
.forward
.qos_class
!=
2225 cvp
->cvc_attr
.qos
.v
.backward
.qos_class
) ||
2226 (ap
->qos
.v
.backward
.qos_class
!=
2227 cvp
->cvc_attr
.qos
.v
.forward
.qos_class
))
2232 * The new LLC header must also be unique for this VCC
2234 for (cop
= cvp
->cvc_conn
; cop
; cop
= cop
->co_next
) {
2235 int i
= MIN(ap
->llc
.v
.llc_len
,
2236 cop
->co_llc
.v
.llc_len
);
2238 if (KM_CMP(ap
->llc
.v
.llc_info
,
2239 cop
->co_llc
.v
.llc_info
, i
) == 0)
2244 * If no header overlaps, then we're done
2257 * This function will terminate a connection, including notifying the
2258 * user, if necessary, and freeing up control block memory. The caller
2259 * is responsible for managing the connection VCC.
2261 * Called from a critical section.
2264 * cop pointer to connection block
2265 * cause pointer to cause of close
2272 atm_cm_closeconn(Atm_connection
*cop
, struct t_atm_cause
*cause
)
2276 * Decide whether user needs notification
2278 switch (cop
->co_state
) {
2286 * Yup, let 'em know connection is gone
2289 (*cop
->co_endpt
->ep_cleared
)(cop
->co_toku
, cause
);
2294 * Nope,they should know already
2299 panic("atm_cm_closeconn: bogus state");
2303 * Unlink connection from its queues
2305 switch (cop
->co_state
) {
2308 atm_free((caddr_t
)cop
->co_lattr
);
2309 UNLINK(cop
, Atm_connection
, atm_listen_queue
, co_next
);
2314 * Remove connection from multiplexor queue
2316 if (cop
->co_mxh
!= cop
) {
2318 * Connection is down the chain, just unlink it
2320 UNLINK(cop
, Atm_connection
, cop
->co_mxh
, co_next
);
2322 } else if (cop
->co_next
!= NULL
) {
2324 * Connection is at the head of a non-singleton chain,
2325 * so unlink and reset the chain head
2327 Atm_connection
*t
, *nhd
;
2329 t
= nhd
= cop
->co_next
;
2335 nhd
->co_connvc
->cvc_conn
= nhd
;
2340 * Free the connection block
2342 cop
->co_state
= COS_FREE
;
2343 atm_free((caddr_t
)cop
);
2350 * Close Connection VCC
2352 * This function will terminate a connection VCC, including releasing the
2353 * the call to the signalling manager, terminating the VCC protocol stack,
2354 * and freeing up control block memory.
2356 * Called from a critical section.
2359 * cvp pointer to connection VCC block
2366 atm_cm_closevc(Atm_connvc
*cvp
)
2371 * Break links with the connection block
2373 cvp
->cvc_conn
= NULL
;
2376 * Cancel any running timer
2381 * Free queued packets
2383 while (cvp
->cvc_rcvq
) {
2387 cvp
->cvc_rcvq
= KB_QNEXT(m
);
2393 * Unlink from any queues
2395 if (cvp
->cvc_flags
& CVCF_INCOMQ
) {
2396 DEQUEUE(cvp
, Atm_connvc
, cvc_q
, atm_incoming_queue
);
2397 atm_incoming_qlen
--;
2398 cvp
->cvc_flags
&= ~CVCF_INCOMQ
;
2400 } else if (cvp
->cvc_flags
& CVCF_CONNQ
) {
2401 DEQUEUE(cvp
, Atm_connvc
, cvc_q
, atm_connection_queue
);
2402 cvp
->cvc_flags
&= ~CVCF_CONNQ
;
2406 * Release the signalling call
2408 switch (cvp
->cvc_state
) {
2416 cvp
->cvc_state
= CVCS_RELEASE
;
2417 switch ((*cvp
->cvc_sigmgr
->sm_release
)
2418 (cvp
->cvc_vcc
, &err
)) {
2422 * Looks good so far...
2426 case CALL_PROCEEDING
:
2428 * We'll have to wait for the call to clear
2434 * If there's a memory shortage, retry later.
2435 * Otherwise who knows what's going on....
2437 if ((err
== ENOMEM
) || (err
== ENOBUFS
)) {
2438 CVC_TIMER(cvp
, 1 * ATM_HZ
);
2442 "atm_cm_closevc: release %d\n", err
);
2451 cvp
->cvc_state
= CVCS_REJECT
;
2452 switch ((*cvp
->cvc_sigmgr
->sm_reject
)
2453 (cvp
->cvc_vcc
, &err
)) {
2457 * Looks good so far...
2463 * If there's a memory shortage, retry later.
2464 * Otherwise who knows what's going on....
2466 if ((err
== ENOMEM
) || (err
== ENOBUFS
)) {
2467 CVC_TIMER(cvp
, 1 * ATM_HZ
);
2471 "atm_cm_closevc: reject %d\n", err
);
2480 * No need for anything here
2485 panic("atm_cm_closevc: bogus state");
2489 * Now terminate the stack
2491 if (cvp
->cvc_tokl
) {
2492 cvp
->cvc_state
= CVCS_TERM
;
2495 * Wait until stack is unwound before terminating
2497 if ((cvp
->cvc_downcnt
> 0) || (cvp
->cvc_upcnt
> 0)) {
2502 STACK_CALL(atm_stackcmds
[cvp
->cvc_attr
.api
].term
,
2503 cvp
->cvc_lower
, cvp
->cvc_tokl
, cvp
, 0, 0, err
);
2505 cvp
->cvc_tokl
= NULL
;
2509 * Let signalling manager finish up
2511 cvp
->cvc_state
= CVCS_FREE
;
2513 (*cvp
->cvc_sigmgr
->sm_free
)(cvp
->cvc_vcc
);
2517 * Finally, free our own control blocks
2519 atm_free((caddr_t
)cvp
);
2526 * Process a Connection VCC timeout
2528 * Called when a previously scheduled cvc control block timer expires.
2529 * Processing will be based on the current cvc state.
2531 * Called from a critical section.
2534 * tip pointer to cvc timer control block
2541 atm_cm_timeout(struct atm_time
*tip
)
2543 Atm_connection
*cop
, *cop2
;
2547 * Back-off to cvc control block
2549 cvp
= (Atm_connvc
*)
2550 ((caddr_t
)tip
- (int)(&((Atm_connvc
*)0)->cvc_time
));
2553 * Process timeout based on protocol state
2555 switch (cvp
->cvc_state
) {
2563 if ((cvp
->cvc_flags
& CVCF_ABORTING
) == 0)
2567 * Terminate all connections
2569 cop
= cvp
->cvc_conn
;
2571 cop2
= cop
->co_next
;
2572 atm_cm_closeconn(cop
, &cvp
->cvc_attr
.cause
.v
);
2579 atm_cm_closevc(cvp
);
2587 * Retry failed operation
2589 atm_cm_closevc(cvp
);
2595 "atm_cm_timeout: invalid state: cvp=%p, state=%d\n",
2596 cvp
, cvp
->cvc_state
);
2602 * CPCS User Control Commands
2604 * This function is called by an endpoint user to pass a control command
2605 * across a CPCS data API. Mostly we just send these down the stack.
2608 * cmd stack command code
2609 * cop pointer to connection block
2613 * 0 command output successful
2614 * errno output failed - reason indicated
2618 atm_cm_cpcs_ctl(int cmd
, Atm_connection
*cop
, void *arg
)
2624 * Validate connection state
2626 if (cop
->co_state
!= COS_ACTIVE
) {
2631 cvp
= cop
->co_connvc
;
2632 if (cvp
->cvc_state
!= CVCS_ACTIVE
) {
2637 if (cvp
->cvc_attr
.api
!= CMAPI_CPCS
) {
2656 * This function is called by an endpoint user to output a data packet
2657 * across a CPCS data API. After we've validated the connection state, the
2658 * packet will be encapsulated (if necessary) and sent down the data stack.
2661 * cop pointer to connection block
2662 * m pointer to packet buffer chain to be output
2665 * 0 packet output successful
2666 * errno output failed - reason indicated
2670 atm_cm_cpcs_data(Atm_connection
*cop
, KBuffer
*m
)
2673 struct attr_llc
*llcp
;
2679 * Validate connection state
2681 if (cop
->co_state
!= COS_ACTIVE
) {
2686 cvp
= cop
->co_connvc
;
2687 if (cvp
->cvc_state
!= CVCS_ACTIVE
) {
2692 if (cvp
->cvc_attr
.api
!= CMAPI_CPCS
) {
2698 * Add any packet encapsulation
2700 switch (cop
->co_mpx
) {
2710 * Need to add an LLC header
2712 llcp
= &cop
->co_llc
;
2715 * See if there's room to add LLC header to front of packet.
2717 KB_HEADROOM(m
, space
);
2718 if (space
< llcp
->v
.llc_len
) {
2722 * We have to allocate another buffer and tack it
2723 * onto the front of the packet
2725 KB_ALLOCPKT(n
, llcp
->v
.llc_len
, KB_F_NOWAIT
,
2731 KB_TAILALIGN(n
, llcp
->v
.llc_len
);
2736 * Header fits, just adjust buffer controls
2738 KB_HEADADJ(m
, llcp
->v
.llc_len
);
2742 * Add the LLC header
2744 KB_DATASTART(m
, bp
, void *);
2745 KM_COPY(llcp
->v
.llc_info
, bp
, llcp
->v
.llc_len
);
2746 KB_PLENADJ(m
, llcp
->v
.llc_len
);
2750 panic("atm_cm_cpcs_data: mpx");
2754 * Finally, we can send the packet on its way
2756 STACK_CALL(CPCS_UNITDATA_INV
, cvp
->cvc_lower
, cvp
->cvc_tokl
,
2757 cvp
, (int)m
, 0, err
);
2765 * Process CPCS Stack Commands
2767 * This is the top of the CPCS API data stack. All upward stack commands
2768 * for the CPCS data API will be received and processed here.
2771 * cmd stack command code
2772 * tok session token (pointer to connection VCC control block)
2781 atm_cm_cpcs_upper(int cmd
, void *tok
, int arg1
, int arg2
)
2783 Atm_connection
*cop
;
2784 Atm_connvc
*cvp
= tok
;
2790 case CPCS_UNITDATA_SIG
:
2794 m
= (KBuffer
*)arg1
;
2796 if (cvp
->cvc_state
!= CVCS_ACTIVE
) {
2797 if (cvp
->cvc_state
== CVCS_ACCEPT
) {
2801 * Queue up any packets received before sigmgr
2802 * notifies us of incoming call completion
2804 if (cvp
->cvc_rcvqlen
>= CVC_RCVQ_MAX
) {
2806 atm_cm_stat
.cms_rcvconnvc
++;
2810 if (cvp
->cvc_rcvq
== NULL
) {
2813 for (n
= cvp
->cvc_rcvq
;
2814 KB_QNEXT(n
) != NULL
;
2823 atm_cm_stat
.cms_rcvconnvc
++;
2829 * Locate packet's connection
2831 cop
= cvp
->cvc_conn
;
2832 switch (cop
->co_mpx
) {
2836 * We're already there...
2842 * Find connection with matching LLC header
2844 if (KB_LEN(m
) < T_ATM_LLC_MAX_LEN
) {
2845 KB_PULLUP(m
, T_ATM_LLC_MAX_LEN
, m
);
2847 atm_cm_stat
.cms_llcdrop
++;
2851 KB_DATASTART(m
, bp
, void *);
2856 if (KM_CMP(bp
, cop
->co_llc
.v
.llc_info
,
2857 cop
->co_llc
.v
.llc_len
) == 0)
2866 * No connected user for this LLC
2869 atm_cm_stat
.cms_llcid
++;
2874 * Strip off the LLC header
2876 KB_HEADADJ(m
, -cop
->co_llc
.v
.llc_len
);
2877 KB_PLENADJ(m
, -cop
->co_llc
.v
.llc_len
);
2881 panic("atm_cm_cpcs_upper: mpx");
2885 * We've found our connection, so hand the packet off
2887 if (cop
->co_state
!= COS_ACTIVE
) {
2889 atm_cm_stat
.cms_rcvconn
++;
2892 (*cop
->co_endpt
->ep_cpcs_data
)(cop
->co_toku
, m
);
2895 case CPCS_UABORT_SIG
:
2896 case CPCS_PABORT_SIG
:
2898 * We don't support these (yet), so just fall thru...
2902 log(LOG_ERR
, "atm_cm_cpcs_upper: unknown cmd 0x%x\n", cmd
);
2908 * SAAL User Control Commands
2910 * This function is called by an endpoint user to pass a control command
2911 * across a SAAL data API. Mostly we just send these down the stack.
2914 * cmd stack command code
2915 * cop pointer to connection block
2919 * 0 command output successful
2920 * errno output failed - reason indicated
2924 atm_cm_saal_ctl(int cmd
, Atm_connection
*cop
, void *arg
)
2930 * Validate connection state
2932 if (cop
->co_state
!= COS_ACTIVE
) {
2937 cvp
= cop
->co_connvc
;
2938 if (cvp
->cvc_state
!= CVCS_ACTIVE
) {
2943 if (cvp
->cvc_attr
.api
!= CMAPI_SAAL
) {
2950 case SSCF_UNI_ESTABLISH_REQ
:
2951 case SSCF_UNI_RELEASE_REQ
:
2953 * Pass command down the stack
2955 STACK_CALL(cmd
, cvp
->cvc_lower
, cvp
->cvc_tokl
, cvp
,
2971 * This function is called by an endpoint user to output a data packet
2972 * across a SAAL data API. After we've validated the connection state,
2973 * the packet will be sent down the data stack.
2976 * cop pointer to connection block
2977 * m pointer to packet buffer chain to be output
2980 * 0 packet output successful
2981 * errno output failed - reason indicated
2985 atm_cm_saal_data(Atm_connection
*cop
, KBuffer
*m
)
2992 * Validate connection state
2994 if (cop
->co_state
!= COS_ACTIVE
) {
2999 cvp
= cop
->co_connvc
;
3000 if (cvp
->cvc_state
!= CVCS_ACTIVE
) {
3005 if (cvp
->cvc_attr
.api
!= CMAPI_SAAL
) {
3011 * Finally, we can send the packet on its way
3013 STACK_CALL(SSCF_UNI_DATA_REQ
, cvp
->cvc_lower
, cvp
->cvc_tokl
,
3014 cvp
, (int)m
, 0, err
);
3022 * Process SAAL Stack Commands
3024 * This is the top of the SAAL API data stack. All upward stack commands
3025 * for the SAAL data API will be received and processed here.
3028 * cmd stack command code
3029 * tok session token (pointer to connection VCC control block)
3038 atm_cm_saal_upper(int cmd
, void *tok
, int arg1
, int arg2
)
3040 Atm_connection
*cop
;
3041 Atm_connvc
*cvp
= tok
;
3046 case SSCF_UNI_ESTABLISH_IND
:
3047 case SSCF_UNI_ESTABLISH_CNF
:
3048 case SSCF_UNI_RELEASE_IND
:
3049 case SSCF_UNI_RELEASE_CNF
:
3053 cop
= cvp
->cvc_conn
;
3054 if (cvp
->cvc_state
!= CVCS_ACTIVE
)
3056 if (cop
->co_state
!= COS_ACTIVE
)
3059 (*cop
->co_endpt
->ep_saal_ctl
)(cmd
, cop
->co_toku
, (void *)arg1
);
3062 case SSCF_UNI_DATA_IND
:
3066 cop
= cvp
->cvc_conn
;
3067 if (cvp
->cvc_state
!= CVCS_ACTIVE
) {
3068 atm_cm_stat
.cms_rcvconnvc
++;
3069 KB_FREEALL((KBuffer
*)arg1
);
3072 if (cop
->co_state
!= COS_ACTIVE
) {
3073 atm_cm_stat
.cms_rcvconn
++;
3074 KB_FREEALL((KBuffer
*)arg1
);
3078 (*cop
->co_endpt
->ep_saal_data
)(cop
->co_toku
, (KBuffer
*)arg1
);
3081 case SSCF_UNI_UNITDATA_IND
:
3085 KB_FREEALL((KBuffer
*)arg1
);
3090 log(LOG_ERR
, "atm_cm_saal_upper: unknown cmd 0x%x\n", cmd
);
3096 * SSCOP User Control Commands
3098 * This function is called by an endpoint user to pass a control command
3099 * across a SSCOP data API. Mostly we just send these down the stack.
3102 * cmd stack command code
3103 * cop pointer to connection block
3108 * 0 command output successful
3109 * errno output failed - reason indicated
3113 atm_cm_sscop_ctl(int cmd
, Atm_connection
*cop
, void *arg1
, void *arg2
)
3119 * Validate connection state
3121 if (cop
->co_state
!= COS_ACTIVE
) {
3126 cvp
= cop
->co_connvc
;
3127 if (cvp
->cvc_state
!= CVCS_ACTIVE
) {
3132 if (cvp
->cvc_attr
.api
!= CMAPI_SSCOP
) {
3139 case SSCOP_ESTABLISH_REQ
:
3140 case SSCOP_ESTABLISH_RSP
:
3141 case SSCOP_RELEASE_REQ
:
3142 case SSCOP_RESYNC_REQ
:
3143 case SSCOP_RESYNC_RSP
:
3144 case SSCOP_RECOVER_RSP
:
3145 case SSCOP_RETRIEVE_REQ
:
3147 * Pass command down the stack
3149 STACK_CALL(cmd
, cvp
->cvc_lower
, cvp
->cvc_tokl
, cvp
,
3150 (int)arg1
, (int)arg2
, err
);
3165 * This function is called by an endpoint user to output a data packet
3166 * across a SSCOP data API. After we've validated the connection state,
3167 * the packet will be encapsulated and sent down the data stack.
3170 * cop pointer to connection block
3171 * m pointer to packet buffer chain to be output
3174 * 0 packet output successful
3175 * errno output failed - reason indicated
3179 atm_cm_sscop_data(Atm_connection
*cop
, KBuffer
*m
)
3186 * Validate connection state
3188 if (cop
->co_state
!= COS_ACTIVE
) {
3193 cvp
= cop
->co_connvc
;
3194 if (cvp
->cvc_state
!= CVCS_ACTIVE
) {
3199 if (cvp
->cvc_attr
.api
!= CMAPI_SSCOP
) {
3205 * Finally, we can send the packet on its way
3207 STACK_CALL(SSCOP_DATA_REQ
, cvp
->cvc_lower
, cvp
->cvc_tokl
,
3208 cvp
, (int)m
, 0, err
);
3216 * Process SSCOP Stack Commands
3218 * This is the top of the SSCOP API data stack. All upward stack commands
3219 * for the SSCOP data API will be received and processed here.
3222 * cmd stack command code
3223 * tok session token (pointer to connection VCC control block)
3232 atm_cm_sscop_upper(int cmd
, void *tok
, int arg1
, int arg2
)
3234 Atm_connection
*cop
;
3235 Atm_connvc
*cvp
= tok
;
3239 case SSCOP_ESTABLISH_IND
:
3240 case SSCOP_ESTABLISH_CNF
:
3241 case SSCOP_RELEASE_IND
:
3242 case SSCOP_RESYNC_IND
:
3246 cop
= cvp
->cvc_conn
;
3247 if ((cvp
->cvc_state
!= CVCS_ACTIVE
) ||
3248 (cop
->co_state
!= COS_ACTIVE
)) {
3249 KB_FREEALL((KBuffer
*)arg1
);
3253 (*cop
->co_endpt
->ep_sscop_ctl
)
3254 (cmd
, cop
->co_toku
, (void *)arg1
, (void *)arg2
);
3257 case SSCOP_RELEASE_CNF
:
3258 case SSCOP_RESYNC_CNF
:
3259 case SSCOP_RECOVER_IND
:
3260 case SSCOP_RETRIEVE_IND
:
3261 case SSCOP_RETRIEVECMP_IND
:
3265 cop
= cvp
->cvc_conn
;
3266 if ((cvp
->cvc_state
!= CVCS_ACTIVE
) ||
3267 (cop
->co_state
!= COS_ACTIVE
))
3270 (*cop
->co_endpt
->ep_sscop_ctl
)
3271 (cmd
, cop
->co_toku
, (void *)arg1
, (void *)arg2
);
3274 case SSCOP_DATA_IND
:
3278 cop
= cvp
->cvc_conn
;
3279 if (cvp
->cvc_state
!= CVCS_ACTIVE
) {
3280 atm_cm_stat
.cms_rcvconnvc
++;
3281 KB_FREEALL((KBuffer
*)arg1
);
3284 if (cop
->co_state
!= COS_ACTIVE
) {
3285 atm_cm_stat
.cms_rcvconn
++;
3286 KB_FREEALL((KBuffer
*)arg1
);
3290 (*cop
->co_endpt
->ep_sscop_data
)
3291 (cop
->co_toku
, (KBuffer
*)arg1
, arg2
);
3294 case SSCOP_UNITDATA_IND
:
3298 KB_FREEALL((KBuffer
*)arg1
);
3303 log(LOG_ERR
, "atm_cm_sscop_upper: unknown cmd 0x%x\n", cmd
);
3309 * Register an ATM Endpoint Service
3311 * Every ATM endpoint service must register itself here before it can
3312 * issue or receive any connection requests.
3315 * epp pointer to endpoint definition structure
3318 * 0 registration successful
3319 * errno registration failed - reason indicated
3323 atm_endpoint_register(Atm_endpoint
*epp
)
3327 * See if we need to be initialized
3335 if (epp
->ep_id
> ENDPT_MAX
) {
3339 if (atm_endpoints
[epp
->ep_id
] != NULL
) {
3345 * Add endpoint to list
3347 atm_endpoints
[epp
->ep_id
] = epp
;
3355 * De-register an ATM Endpoint Service
3357 * Each ATM endpoint service provider must de-register its registered
3358 * endpoint(s) before terminating. Specifically, loaded kernel modules
3359 * must de-register their services before unloading themselves.
3362 * epp pointer to endpoint definition structure
3365 * 0 de-registration successful
3366 * errno de-registration failed - reason indicated
3370 atm_endpoint_deregister(Atm_endpoint
*epp
)
3377 if (epp
->ep_id
> ENDPT_MAX
) {
3381 if (atm_endpoints
[epp
->ep_id
] != epp
) {
3387 * Remove endpoint from list
3389 atm_endpoints
[epp
->ep_id
] = NULL
;