summaryrefslogtreecommitdiffstats
path: root/sys/netatm/atm_cm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netatm/atm_cm.c')
-rw-r--r--sys/netatm/atm_cm.c3502
1 files changed, 0 insertions, 3502 deletions
diff --git a/sys/netatm/atm_cm.c b/sys/netatm/atm_cm.c
deleted file mode 100644
index 4cfdf1a..0000000
--- a/sys/netatm/atm_cm.c
+++ /dev/null
@@ -1,3502 +0,0 @@
-/*-
- * ===================================
- * HARP | Host ATM Research Platform
- * ===================================
- *
- *
- * This Host ATM Research Platform ("HARP") file (the "Software") is
- * made available by Network Computing Services, Inc. ("NetworkCS")
- * "AS IS". NetworkCS does not provide maintenance, improvements or
- * support of any kind.
- *
- * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
- * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
- * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
- * In no event shall NetworkCS be responsible for any damages, including
- * but not limited to consequential damages, arising from or relating to
- * any use of the Software or related support.
- *
- * Copyright 1994-1998 Network Computing Services, Inc.
- *
- * Copies of this Software may be made, however, the above copyright
- * notice must be reproduced on all copies.
- */
-
-/*
- * Core ATM Services
- * -----------------
- *
- * ATM Connection Manager
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/errno.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <sys/socketvar.h>
-#include <sys/syslog.h>
-#include <net/if.h>
-#include <net/bpf.h>
-#include <netatm/port.h>
-#include <netatm/queue.h>
-#include <netatm/atm.h>
-#include <netatm/atm_sys.h>
-#include <netatm/atm_sap.h>
-#include <netatm/atm_cm.h>
-#include <netatm/atm_if.h>
-#include <netatm/atm_vc.h>
-#include <netatm/atm_sigmgr.h>
-#include <netatm/atm_stack.h>
-#include <netatm/atm_pcb.h>
-#include <netatm/atm_var.h>
-
-/*
- * Global variables
- */
-struct atm_cm_stat atm_cm_stat = {0};
-
-/*
- * Local functions
- */
-static void atm_cm_cpcs_upper(int, void *, intptr_t, intptr_t);
-static void atm_cm_saal_upper(int, void *, intptr_t, intptr_t);
-static void atm_cm_sscop_upper(int, void *, intptr_t, intptr_t);
-static Atm_connvc * atm_cm_share_llc(Atm_attributes *);
-static void atm_cm_closeconn(Atm_connection *,
- struct t_atm_cause *);
-static void atm_cm_closevc(Atm_connvc *);
-static void atm_cm_timeout(struct atm_time *);
-static KTimeout_ret atm_cm_procinq(void *);
-static void atm_cm_incall(Atm_connvc *);
-static int atm_cm_accept(Atm_connvc *, Atm_connection *);
-
-/*
- * Local variables
- */
-static Queue_t atm_connection_queue = {NULL};
-static Queue_t atm_incoming_queue = {NULL};
-static int atm_incoming_qlen = 0;
-static Atm_connection *atm_listen_queue = NULL;
-static struct attr_cause atm_cause_tmpl =
- {T_ATM_PRESENT, {T_ATM_ITU_CODING, T_ATM_LOC_USER, 0, {0, 0, 0, 0}}};
-
-/*
- * Stack commands, indexed by API
- */
-static struct {
- int init;
- int term;
-} atm_stackcmds[] = {
- {CPCS_INIT, CPCS_TERM}, /* CMAPI_CPCS */
- {SSCF_UNI_INIT, SSCF_UNI_TERM}, /* CMAPI_SAAL */
- {SSCOP_INIT, SSCOP_TERM}, /* CMAPI_SSCOP */
-};
-
-static uma_zone_t atm_connection_zone;
-static uma_zone_t atm_connvc_zone;
-
-void
-atm_cm_init(void)
-{
-
- atm_connection_zone = uma_zcreate("atm connection",
- sizeof(Atm_connection), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
- if (atm_connection_zone == NULL)
- panic("atm_connection_zone");
-
- atm_connvc_zone = uma_zcreate("atm connvc", sizeof(Atm_connvc), NULL,
- NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
- if (atm_connvc_zone == NULL)
- panic("atm_connvc_zone");
-}
-
-/*
- * Initiate Outgoing ATM Call
- *
- * Called by an endpoint service to create a new Connection Manager API
- * instance and to initiate an outbound ATM connection. The endpoint
- * provided token will be used in all further CM -> endpoint function
- * calls, and the returned connection block pointer must be used in all
- * subsequent endpoint -> CM function calls.
- *
- * If the return indicates that the connection setup has been immediately
- * successful (typically only for PVCs and shared SVCs), then the connection
- * is ready for data transmission.
- *
- * If the return indicates that the connection setup is still in progress,
- * then the endpoint must wait for notification from the Connection Manager
- * indicating the final status of the call setup. If the call setup completes
- * successfully, then a "call connected" notification will be sent to the
- * endpoint by the Connection Manager. If the call setup fails, then the
- * endpoint will receive a "call cleared" notification.
- *
- * All connection instances must be freed with an atm_cm_release() call.
- *
- * Arguments:
- * epp pointer to endpoint definition structure
- * token endpoint's connection instance token
- * ap pointer to requested connection attributes
- * copp pointer to location to return allocated connection block
- *
- * Returns:
- * 0 connection has been successfully established
- * EINPROGRESS connection establishment is in progress
- * errno connection failed - reason indicated
- *
- */
-int
-atm_cm_connect(epp, token, ap, copp)
- Atm_endpoint *epp;
- void *token;
- Atm_attributes *ap;
- Atm_connection **copp;
-{
- Atm_connection *cop;
- Atm_connvc *cvp;
- struct atm_pif *pip;
- struct sigmgr *smp;
- struct stack_list sl;
- void (*upf)(int, void *, intptr_t, intptr_t);
- int s, sli, err, err2;
-
- *copp = NULL;
- cvp = NULL;
-
- /*
- * Get a connection block
- * May be called from timeout - don't wait.
- */
- cop = uma_zalloc(atm_connection_zone, M_NOWAIT);
- if (cop == NULL)
- return (ENOMEM);
-
- /*
- * Initialize connection info
- */
- cop->co_endpt = epp;
- cop->co_toku = token;
-
- /*
- * Initialize stack list index
- */
- sli = 0;
-
- /*
- * Validate and extract useful attribute information
- */
-
- /*
- * Must specify a network interface (validated below)
- */
- if (ap->nif == NULL) {
- err = EINVAL;
- goto done;
- }
-
- /*
- * Check out Data API
- */
- switch (ap->api) {
-
- case CMAPI_CPCS:
- upf = atm_cm_cpcs_upper;
- break;
-
- case CMAPI_SAAL:
- sl.sl_sap[sli++] = SAP_SSCF_UNI;
- sl.sl_sap[sli++] = SAP_SSCOP;
- upf = atm_cm_saal_upper;
- break;
-
- case CMAPI_SSCOP:
- sl.sl_sap[sli++] = SAP_SSCOP;
- upf = atm_cm_sscop_upper;
- break;
-
- default:
- err = EINVAL;
- goto done;
- }
-
- /*
- * AAL Attributes
- */
- if (ap->aal.tag != T_ATM_PRESENT) {
- err = EINVAL;
- goto done;
- }
-
- switch (ap->aal.type) {
-
- case ATM_AAL5:
- sl.sl_sap[sli++] = SAP_CPCS_AAL5;
- sl.sl_sap[sli++] = SAP_SAR_AAL5;
- sl.sl_sap[sli++] = SAP_ATM;
- break;
-
- case ATM_AAL3_4:
- sl.sl_sap[sli++] = SAP_CPCS_AAL3_4;
- sl.sl_sap[sli++] = SAP_SAR_AAL3_4;
- sl.sl_sap[sli++] = SAP_ATM;
- break;
-
- default:
- err = EINVAL;
- goto done;
- }
-
- /*
- * Broadband Bearer Attributes
- */
- if (ap->bearer.tag != T_ATM_PRESENT) {
- err = EINVAL;
- goto done;
- }
-
- switch (ap->bearer.v.connection_configuration) {
-
- case T_ATM_1_TO_1:
- cop->co_flags |= COF_P2P;
- break;
-
- case T_ATM_1_TO_MANY:
- /* Not supported */
- cop->co_flags |= COF_P2MP;
- err = EINVAL;
- goto done;
-
- default:
- err = EINVAL;
- goto done;
- }
-
- /*
- * Logical Link Control Attributes
- */
- if (ap->llc.tag == T_ATM_PRESENT) {
- if ((ap->blli.tag_l2 != T_ATM_PRESENT) ||
- (ap->blli.v.layer_2_protocol.ID_type != T_ATM_SIMPLE_ID) ||
- (ap->blli.v.layer_2_protocol.ID.simple_ID !=
- T_ATM_BLLI2_I8802) ||
- (ap->llc.v.llc_len < T_ATM_LLC_MIN_LEN) ||
- (ap->llc.v.llc_len > T_ATM_LLC_MAX_LEN)) {
- err = EINVAL;
- goto done;
- }
- cop->co_mpx = ATM_ENC_LLC;
- cop->co_llc = ap->llc;
- } else
- cop->co_mpx = ATM_ENC_NULL;
-
- /*
- * Called Party Attributes
- */
- if (ap->called.tag != T_ATM_PRESENT) {
- err = EINVAL;
- goto done;
- }
-
- if ((ap->called.addr.address_format == T_ATM_ABSENT) ||
- (ap->called.addr.address_length == 0)) {
- err = EINVAL;
- goto done;
- }
-
- /*
- * Calling Party Attributes
- */
- if (ap->calling.tag != T_ATM_ABSENT) {
- err = EINVAL;
- goto done;
- }
-
- /*
- * Quality of Service Attributes
- */
- if (ap->qos.tag != T_ATM_PRESENT) {
- err = EINVAL;
- goto done;
- }
-
- /*
- * Terminate stack list
- */
- sl.sl_sap[sli] = 0;
-
- s = splnet();
-
- /*
- * Let multiplexors decide whether we need a new VCC
- */
- switch (cop->co_mpx) {
-
- case ATM_ENC_NULL:
- /*
- * All of these connections require a new VCC
- */
- break;
-
- case ATM_ENC_LLC:
- /*
- * See if we can share an existing LLC connection
- */
- cvp = atm_cm_share_llc(ap);
- if (cvp == NULL)
- break;
-
- /*
- * We've got a connection to share
- */
- cop->co_connvc = cvp;
- if (cvp->cvc_state == CVCS_ACTIVE) {
- cop->co_state = COS_ACTIVE;
- err = 0;
- } else {
- cop->co_state = COS_OUTCONN;
- err = EINPROGRESS;
- }
- LINK2TAIL(cop, Atm_connection, cvp->cvc_conn->co_mxh, co_next);
- cop->co_mxh = cvp->cvc_conn->co_mxh;
- *copp = cop;
-
- (void) splx(s);
- return (err);
-
- default:
- panic("atm_cm_connect: unknown mpx");
- }
-
- /*
- * If we get here, it means we need to create
- * a new VCC for this connection
- */
-
- /*
- * Validate that network interface is registered and that
- * a signalling manager is attached
- */
- for (pip = atm_interface_head; pip != NULL; pip = pip->pif_next) {
- struct atm_nif *nip;
- for (nip = pip->pif_nif; nip; nip = nip->nif_pnext) {
- if (nip == ap->nif)
- break;
- }
- if (nip)
- break;
- }
- if (pip == NULL) {
- err = ENXIO;
- goto donex;
- }
-
- if ((smp = pip->pif_sigmgr) == NULL) {
- err = ENXIO;
- goto donex;
- }
-
- /*
- * Get a connection VCC block
- * May be called from timeouts - don't wait.
- */
- cvp = uma_zalloc(atm_connvc_zone, M_NOWAIT);
- if (cvp == NULL) {
- err = ENOMEM;
- goto donex;
- }
-
- /*
- * Save VCC attributes
- */
- cvp->cvc_attr = *ap;
- cvp->cvc_flags |= CVCF_CALLER;
-
- /*
- * Link the control blocks
- */
- cop->co_connvc = cvp;
- cvp->cvc_conn = cop;
- cvp->cvc_sigmgr = smp;
-
- /*
- * Create a service stack
- */
- err = atm_create_stack(cvp, &sl, upf);
- if (err) {
- cvp->cvc_state = CVCS_CLEAR;
- atm_cm_closevc(cvp);
- goto donex;
- }
-
- /*
- * Let the signalling manager handle the VCC creation
- */
- cvp->cvc_state = CVCS_SETUP;
- switch ((*smp->sm_setup)(cvp, &err)) {
-
- case CALL_CONNECTED:
- /*
- * Connection is fully setup - initialize the stack
- */
- cvp->cvc_state = CVCS_INIT;
- STACK_CALL(atm_stackcmds[ap->api].init, cvp->cvc_lower,
- cvp->cvc_tokl, cvp, ap->api_init, 0, err2);
- if (err2)
- panic("atm_cm_connect: init");
-
- if (cvp->cvc_flags & CVCF_ABORTING) {
- /*
- * Someone on the stack bailed out...schedule the
- * VCC and stack termination
- */
- atm_cm_closevc(cvp);
- err = EFAULT;
- } else {
- /*
- * Everything looks fine from here
- */
- cvp->cvc_state = CVCS_ACTIVE;
- cop->co_state = COS_ACTIVE;
- }
- break;
-
- case CALL_FAILED:
- /*
- * Terminate stack and clean up before we leave
- */
- cvp->cvc_state = CVCS_CLEAR;
- atm_cm_closevc(cvp);
- break;
-
- case CALL_PROCEEDING:
- /*
- * We'll just wait for final call status
- */
- cop->co_state = COS_OUTCONN;
- err = EINPROGRESS;
- break;
-
- default:
- panic("atm_cm_connect: setup");
- }
-
-donex:
- (void) splx(s);
-
-done:
- if (err && err != EINPROGRESS) {
- /*
- * Undo any partial setup stuff
- */
- if (cop)
- uma_zfree(atm_connection_zone, cop);
- } else {
- /*
- * Finish connection setup
- */
- s = splnet();
- cvp->cvc_flags |= CVCF_CONNQ;
- ENQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
- LINK2TAIL(cop, Atm_connection, cop->co_mxh, co_next);
- (void) splx(s);
- *copp = cop;
- }
- return (err);
-}
-
-
-/*
- * Listen for Incoming ATM Calls
- *
- * Called by an endpoint service in order to indicate its willingness to
- * accept certain incoming calls. The types of calls which the endpoint
- * is prepared to accept are specified in the Atm_attributes parameter.
- *
- * For each call which meets the criteria specified by the endpoint, the
- * endpoint service will receive an incoming call notification via the
- * endpoint's ep_incoming() function.
- *
- * To cancel the listening connection, the endpoint user should invoke
- * atm_cm_release().
- *
- * Arguments:
- * so optional socket pointer -- if present, will set listen state
- * epp pointer to endpoint definition structure
- * token endpoint's listen instance token
- * ap pointer to listening connection attributes
- * copp pointer to location to return allocated connection block
- *
- * Returns:
- * 0 listening connection installed
- * errno listen failed - reason indicated
- *
- */
-int
-atm_cm_listen(so, epp, token, ap, copp, backlog)
- struct socket *so;
- Atm_endpoint *epp;
- void *token;
- Atm_attributes *ap;
- Atm_connection **copp;
- int backlog;
-{
- Atm_connection *cop;
- int s, err = 0;
-
- *copp = NULL;
-
- /*
- * Get a connection block
- */
- cop = uma_zalloc(atm_connection_zone, M_WAITOK);
- if (cop == NULL)
- return (ENOMEM);
-
- /*
- * Initialize connection info
- */
- cop->co_endpt = epp;
- cop->co_toku = token;
- cop->co_mxh = cop;
-
- /*
- * Validate and extract useful attribute information
- */
-
- /*
- * Check out Data API
- */
- switch (ap->api) {
-
- case CMAPI_CPCS:
- case CMAPI_SAAL:
- case CMAPI_SSCOP:
- break;
-
- default:
- err = EINVAL;
- goto done;
- }
-
- /*
- * AAL Attributes
- */
- switch (ap->aal.tag) {
-
- case T_ATM_PRESENT:
-
- switch (ap->aal.type) {
-
- case ATM_AAL5:
- case ATM_AAL3_4:
- break;
-
- default:
- err = EINVAL;
- goto done;
- }
- break;
-
- case T_ATM_ABSENT:
- case T_ATM_ANY:
- break;
-
- default:
- err = EINVAL;
- goto done;
- }
-
- /*
- * Broadband High Layer Information Attributes
- */
- switch (ap->bhli.tag) {
-
- case T_ATM_PRESENT:
- case T_ATM_ABSENT:
- case T_ATM_ANY:
- break;
-
- default:
- err = EINVAL;
- goto done;
- }
-
- /*
- * Broadband Low Layer Information Attributes
- */
- switch (ap->blli.tag_l2) {
-
- case T_ATM_PRESENT:
- case T_ATM_ABSENT:
- case T_ATM_ANY:
- break;
-
- default:
- err = EINVAL;
- goto done;
- }
-
- switch (ap->blli.tag_l3) {
-
- case T_ATM_PRESENT:
- case T_ATM_ABSENT:
- case T_ATM_ANY:
- break;
-
- default:
- err = EINVAL;
- goto done;
- }
-
- /*
- * Logical Link Control Attributes
- */
- switch (ap->llc.tag) {
-
- case T_ATM_PRESENT:
- if ((ap->blli.tag_l2 != T_ATM_PRESENT) ||
- (ap->blli.v.layer_2_protocol.ID_type != T_ATM_SIMPLE_ID) ||
- (ap->blli.v.layer_2_protocol.ID.simple_ID !=
- T_ATM_BLLI2_I8802) ||
- (ap->llc.v.llc_len < T_ATM_LLC_MIN_LEN) ||
- (ap->llc.v.llc_len > T_ATM_LLC_MAX_LEN)) {
- err = EINVAL;
- goto done;
- }
- cop->co_mpx = ATM_ENC_LLC;
- cop->co_llc = ap->llc;
- break;
-
- case T_ATM_ABSENT:
- case T_ATM_ANY:
- cop->co_mpx = ATM_ENC_NULL;
- break;
-
- default:
- err = EINVAL;
- goto done;
- }
-
- /*
- * Called Party Attributes
- */
- switch (ap->called.tag) {
-
- case T_ATM_PRESENT:
- switch (ap->called.addr.address_format) {
-
- case T_ATM_ABSENT:
- ap->called.tag = T_ATM_ABSENT;
- break;
-
- case T_ATM_PVC_ADDR:
- err = EINVAL;
- goto done;
- }
- break;
-
- case T_ATM_ABSENT:
- case T_ATM_ANY:
- break;
-
- default:
- err = EINVAL;
- goto done;
- }
-
- /*
- * Get an attribute block and save listening attributes
- */
- cop->co_lattr = uma_zalloc(atm_attributes_zone, M_WAITOK | M_ZERO);
- if (cop->co_lattr == NULL) {
- err = ENOMEM;
- goto done;
- }
- *cop->co_lattr = *ap;
-
- /*
- * Now try to register the listening connection
- */
- if (so != NULL)
- SOCK_LOCK(so);
- s = splnet();
- if (so != NULL)
- err = solisten_proto_check(so);
- if (err)
- goto donex;
- if (atm_cm_match(cop->co_lattr, NULL) != NULL) {
- /*
- * Can't have matching listeners
- */
- err = EADDRINUSE;
- goto donex;
- }
- cop->co_state = COS_LISTEN;
- LINK2TAIL(cop, Atm_connection, atm_listen_queue, co_next);
- if (so != NULL)
- solisten_proto(so, backlog);
-
-donex:
- (void) splx(s);
- if (so != NULL)
- SOCK_UNLOCK(so);
-
-done:
- if (err) {
- /*
- * Undo any partial setup stuff
- */
- if (cop) {
- if (cop->co_lattr)
- uma_zfree(atm_attributes_zone, cop->co_lattr);
- uma_zfree(atm_connection_zone, cop);
- }
- } else {
- /*
- * Finish connection setup
- */
- *copp = cop;
- }
- return (err);
-}
-
-
-/*
- * Add to LLC Connection
- *
- * Called by an endpoint service to create a new Connection Manager API
- * instance to be associated with an LLC-multiplexed connection instance
- * which has been previously created. The endpoint provided token will
- * be used in all further CM -> endpoint function calls, and the returned
- * connection block pointer must be used in all subsequent endpoint -> CM
- * function calls.
- *
- * If the return indicates that the connection setup has been immediately
- * successful, then the connection is ready for data transmission.
- *
- * If the return indicates that the connection setup is still in progress,
- * then the endpoint must wait for notification from the Connection Manager
- * indicating the final status of the call setup. If the call setup completes
- * successfully, then a "call connected" notification will be sent to the
- * endpoint by the Connection Manager. If the call setup fails, then the
- * endpoint will receive a "call cleared" notification.
- *
- * All connection instances must be freed with an atm_cm_release() call.
- *
- * Arguments:
- * epp pointer to endpoint definition structure
- * token endpoint's connection instance token
- * llc pointer to llc attributes for new connection
- * ecop pointer to existing connection block
- * copp pointer to location to return allocated connection block
- *
- * Returns:
- * 0 connection has been successfully established
- * EINPROGRESS connection establishment is in progress
- * errno addllc failed - reason indicated
- *
- */
-int
-atm_cm_addllc(epp, token, llc, ecop, copp)
- Atm_endpoint *epp;
- void *token;
- struct attr_llc *llc;
- Atm_connection *ecop;
- Atm_connection **copp;
-{
- Atm_connection *cop, *cop2;
- Atm_connvc *cvp;
- int s, err;
-
- *copp = NULL;
-
- /*
- * Check out requested LLC attributes
- */
- if ((llc->tag != T_ATM_PRESENT) ||
- ((llc->v.flags & T_ATM_LLC_SHARING) == 0) ||
- (llc->v.llc_len < T_ATM_LLC_MIN_LEN) ||
- (llc->v.llc_len > T_ATM_LLC_MAX_LEN))
- return (EINVAL);
-
- /*
- * Get a connection block
- * May be called from netisr - don't wait.
- */
- cop = uma_zalloc(atm_connection_zone, M_NOWAIT);
- if (cop == NULL)
- return (ENOMEM);
-
- /*
- * Initialize connection info
- */
- cop->co_endpt = epp;
- cop->co_toku = token;
- cop->co_llc = *llc;
-
- s = splnet();
-
- /*
- * Ensure that supplied connection is really valid
- */
- cop2 = NULL;
- for (cvp = Q_HEAD(atm_connection_queue, Atm_connvc); cvp;
- cvp = Q_NEXT(cvp, Atm_connvc, cvc_q)) {
- for (cop2 = cvp->cvc_conn; cop2; cop2 = cop2->co_next) {
- if (ecop == cop2)
- break;
- }
- if (cop2)
- break;
- }
- if (cop2 == NULL) {
- err = ENOENT;
- goto done;
- }
-
- switch (ecop->co_state) {
-
- case COS_OUTCONN:
- case COS_INACCEPT:
- err = EINPROGRESS;
- break;
-
- case COS_ACTIVE:
- err = 0;
- break;
-
- default:
- err = EINVAL;
- goto done;
- }
-
- /*
- * Connection must be LLC multiplexed and shared
- */
- if ((ecop->co_mpx != ATM_ENC_LLC) ||
- ((ecop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0)) {
- err = EINVAL;
- goto done;
- }
-
- /*
- * This new LLC header must be unique for this VCC
- */
- cop2 = ecop->co_mxh;
- while (cop2) {
- int i = MIN(llc->v.llc_len, cop2->co_llc.v.llc_len);
-
- if (bcmp(llc->v.llc_info, cop2->co_llc.v.llc_info, i) == 0) {
- err = EINVAL;
- goto done;
- }
-
- cop2 = cop2->co_next;
- }
-
- /*
- * Everything seems to check out
- */
- cop->co_flags = ecop->co_flags;
- cop->co_state = ecop->co_state;
- cop->co_mpx = ecop->co_mpx;
- cop->co_connvc = ecop->co_connvc;
-
- LINK2TAIL(cop, Atm_connection, ecop->co_mxh, co_next);
- cop->co_mxh = ecop->co_mxh;
-
-done:
- (void) splx(s);
-
- if (err && err != EINPROGRESS) {
- /*
- * Undo any partial setup stuff
- */
- if (cop)
- uma_zfree(atm_connection_zone, cop);
- } else {
- /*
- * Pass new connection back to caller
- */
- *copp = cop;
- }
- return (err);
-}
-
-
-/*
- * XXX
- *
- * Arguments:
- * cop pointer to connection block
- * id identifier for party to be added
- * addr address of party to be added
- *
- * Returns:
- * 0 addparty successful
- * errno addparty failed - reason indicated
- *
- */
-int
-atm_cm_addparty(cop, id, addr)
- Atm_connection *cop;
- int id;
- struct t_atm_sap *addr;
-{
- return (0);
-}
-
-
-/*
- * XXX
- *
- * Arguments:
- * cop pointer to connection block
- * id identifier for party to be added
- * cause pointer to cause of drop
- *
- * Returns:
- * 0 dropparty successful
- * errno dropparty failed - reason indicated
- *
- */
-int
-atm_cm_dropparty(cop, id, cause)
- Atm_connection *cop;
- int id;
- struct t_atm_cause *cause;
-{
- return (0);
-}
-
-
-/*
- * Release Connection Resources
- *
- * Called by the endpoint service in order to terminate an ATM connection
- * and to release all system resources for the connection. This function
- * must be called for every allocated connection instance and must only
- * be called by the connection's owner.
- *
- * Arguments:
- * cop pointer to connection block
- * cause pointer to cause of release
- *
- * Returns:
- * 0 release successful
- * errno release failed - reason indicated
- *
- */
-int
-atm_cm_release(cop, cause)
- Atm_connection *cop;
- struct t_atm_cause *cause;
-{
- Atm_connvc *cvp;
- int s;
-
- s = splnet();
-
- /*
- * First, a quick state validation check
- */
- switch (cop->co_state) {
-
- case COS_OUTCONN:
- case COS_LISTEN:
- case COS_INACCEPT:
- case COS_ACTIVE:
- case COS_CLEAR:
- /*
- * Break link to user
- */
- cop->co_toku = NULL;
- break;
-
- case COS_INCONN:
- (void) splx(s);
- return (EFAULT);
-
- default:
- panic("atm_cm_release: bogus conn state");
- }
-
- /*
- * Check out the VCC state too
- */
- if ((cvp = cop->co_connvc) != NULL) {
-
- switch (cvp->cvc_state) {
-
- case CVCS_SETUP:
- case CVCS_INIT:
- case CVCS_ACCEPT:
- case CVCS_ACTIVE:
- break;
-
- case CVCS_INCOMING:
- (void) splx(s);
- return (EFAULT);
-
- case CVCS_CLEAR:
- (void) splx(s);
- return (EALREADY);
-
- default:
- panic("atm_cm_release: bogus connvc state");
- }
-
- /*
- * If we're the only connection, terminate the VCC
- */
- if ((cop->co_mxh == cop) && (cop->co_next == NULL)) {
- cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
- cvp->cvc_attr.cause.v = *cause;
- atm_cm_closevc(cvp);
- }
- }
-
- /*
- * Now get rid of the connection
- */
- atm_cm_closeconn(cop, cause);
-
- return (0);
-}
-
-
-/*
- * Abort an ATM Connection VCC
- *
- * This function allows any non-owner kernel entity to request an
- * immediate termination of an ATM VCC. This will normally be called
- * when encountering a catastrophic error condition that cannot be
- * resolved via the available stack protocols. The connection manager
- * will schedule the connection's termination, including notifying the
- * connection owner of the termination.
- *
- * This function should only be called by a stack entity instance. After
- * calling the function, the caller should set a protocol state which just
- * waits for a <sap>_TERM stack command to be delivered.
- *
- * Arguments:
- * cvp pointer to connection VCC block
- * cause pointer to cause of abort
- *
- * Returns:
- * 0 abort successful
- * errno abort failed - reason indicated
- *
- */
-int
-atm_cm_abort(cvp, cause)
- Atm_connvc *cvp;
- struct t_atm_cause *cause;
-{
- ATM_DEBUG2("atm_cm_abort: cvp=%p cause=%d\n",
- cvp, cause->cause_value);
-
- /*
- * Note that we're aborting
- */
- cvp->cvc_flags |= CVCF_ABORTING;
-
- switch (cvp->cvc_state) {
-
- case CVCS_INIT:
- /*
- * In-line code will handle this
- */
- cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
- cvp->cvc_attr.cause.v = *cause;
- break;
-
- case CVCS_SETUP:
- case CVCS_ACCEPT:
- case CVCS_ACTIVE:
- /*
- * Schedule connection termination, since we want
- * to avoid any sequencing interactions
- */
- cvp->cvc_attr.cause.tag = T_ATM_PRESENT;
- cvp->cvc_attr.cause.v = *cause;
- CVC_TIMER(cvp, 0);
- break;
-
- case CVCS_REJECT:
- case CVCS_RELEASE:
- case CVCS_CLEAR:
- case CVCS_TERM:
- /*
- * Ignore abort, as we're already terminating
- */
- break;
-
- default:
- log(LOG_ERR,
- "atm_cm_abort: invalid state: cvp=%p, state=%d\n",
- cvp, cvp->cvc_state);
- }
- return (0);
-}
-
-
-/*
- * Incoming ATM Call Received
- *
- * Called by a signalling manager to indicate that a new call request has
- * been received. This function will allocate and initialize the connection
- * manager control blocks and queue this call request. The call request
- * processing function, atm_cm_procinq(), will be scheduled to perform the
- * call processing.
- *
- * Arguments:
- * vcp pointer to incoming call's VCC control block
- * ap pointer to incoming call's attributes
- *
- * Returns:
- * 0 call queuing successful
- * errno call queuing failed - reason indicated
- *
- */
-int
-atm_cm_incoming(vcp, ap)
- struct vccb *vcp;
- Atm_attributes *ap;
-{
- Atm_connvc *cvp;
- int s, err;
-
-
- /*
- * Do some minimal attribute validation
- */
-
- /*
- * Must specify a network interface
- */
- if (ap->nif == NULL)
- return (EINVAL);
-
- /*
- * AAL Attributes
- */
- if ((ap->aal.tag != T_ATM_PRESENT) ||
- ((ap->aal.type != ATM_AAL5) &&
- (ap->aal.type != ATM_AAL3_4)))
- return (EINVAL);
-
- /*
- * Traffic Descriptor Attributes
- */
- if ((ap->traffic.tag != T_ATM_PRESENT) &&
- (ap->traffic.tag != T_ATM_ABSENT))
- return (EINVAL);
-
- /*
- * Broadband Bearer Attributes
- */
- if ((ap->bearer.tag != T_ATM_PRESENT) ||
- ((ap->bearer.v.connection_configuration != T_ATM_1_TO_1) &&
- (ap->bearer.v.connection_configuration != T_ATM_1_TO_MANY)))
- return (EINVAL);
-
- /*
- * Broadband High Layer Attributes
- */
- if ((ap->bhli.tag != T_ATM_PRESENT) &&
- (ap->bhli.tag != T_ATM_ABSENT))
- return (EINVAL);
-
- /*
- * Broadband Low Layer Attributes
- */
- if ((ap->blli.tag_l2 != T_ATM_PRESENT) &&
- (ap->blli.tag_l2 != T_ATM_ABSENT))
- return (EINVAL);
- if ((ap->blli.tag_l3 != T_ATM_PRESENT) &&
- (ap->blli.tag_l3 != T_ATM_ABSENT))
- return (EINVAL);
-
- /*
- * Logical Link Control Attributes
- */
- if (ap->llc.tag == T_ATM_PRESENT)
- return (EINVAL);
- ap->llc.tag = T_ATM_ANY;
-
- /*
- * Called Party Attributes
- */
- if ((ap->called.tag != T_ATM_PRESENT) ||
- (ap->called.addr.address_format == T_ATM_ABSENT))
- return (EINVAL);
- if (ap->called.tag == T_ATM_ABSENT) {
- ap->called.addr.address_format = T_ATM_ABSENT;
- ap->called.addr.address_length = 0;
- ap->called.subaddr.address_format = T_ATM_ABSENT;
- ap->called.subaddr.address_length = 0;
- }
-
- /*
- * Calling Party Attributes
- */
- if ((ap->calling.tag != T_ATM_PRESENT) &&
- (ap->calling.tag != T_ATM_ABSENT))
- return (EINVAL);
- if (ap->calling.tag == T_ATM_ABSENT) {
- ap->calling.addr.address_format = T_ATM_ABSENT;
- ap->calling.addr.address_length = 0;
- ap->calling.subaddr.address_format = T_ATM_ABSENT;
- ap->calling.subaddr.address_length = 0;
- }
-
- /*
- * Quality of Service Attributes
- */
- if (ap->qos.tag != T_ATM_PRESENT)
- return (EINVAL);
-
- /*
- * Transit Network Attributes
- */
- if ((ap->transit.tag != T_ATM_PRESENT) &&
- (ap->transit.tag != T_ATM_ABSENT))
- return (EINVAL);
-
- /*
- * Cause Attributes
- */
- if ((ap->cause.tag != T_ATM_PRESENT) &&
- (ap->cause.tag != T_ATM_ABSENT))
- return (EINVAL);
-
- /*
- * Get a connection VCC block
- * May be called from netisr - don't wait.
- */
- cvp = uma_zalloc(atm_connvc_zone, M_NOWAIT);
- if (cvp == NULL) {
- err = ENOMEM;
- goto fail;
- }
-
- /*
- * Initialize the control block
- */
- cvp->cvc_vcc = vcp;
- cvp->cvc_sigmgr = vcp->vc_pif->pif_sigmgr;
- cvp->cvc_attr = *ap;
- cvp->cvc_state = CVCS_INCOMING;
-
- /*
- * Control queue length
- */
- s = splnet();
- if (atm_incoming_qlen >= ATM_CALLQ_MAX) {
- (void) splx(s);
- err = EBUSY;
- goto fail;
- }
-
- /*
- * Queue request and schedule call processing function
- */
- cvp->cvc_flags |= CVCF_INCOMQ;
- ENQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
- if (atm_incoming_qlen++ == 0) {
- timeout(atm_cm_procinq, (void *)0, 0);
- }
-
- /*
- * Link for signalling manager
- */
- vcp->vc_connvc = cvp;
-
- (void) splx(s);
-
- return (0);
-
-fail:
- /*
- * Free any resources
- */
- if (cvp)
- uma_zfree(atm_connvc_zone, cvp);
- return (err);
-}
-
-
-/*
- * VCC Connected Notification
- *
- * This function is called by a signalling manager as notification that a
- * VCC call setup has been successful.
- *
- * Arguments:
- * cvp pointer to connection VCC block
- *
- * Returns:
- * none
- *
- */
-void
-atm_cm_connected(cvp)
- Atm_connvc *cvp;
-{
- Atm_connection *cop, *cop2;
- KBuffer *m;
- int s, err;
-
- s = splnet();
-
- /*
- * Validate connection vcc
- */
- switch (cvp->cvc_state) {
-
- case CVCS_SETUP:
- /*
- * Initialize the stack
- */
- cvp->cvc_state = CVCS_INIT;
- STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].init,
- cvp->cvc_lower, cvp->cvc_tokl,
- cvp, cvp->cvc_attr.api_init, 0, err);
- if (err)
- panic("atm_cm_connected: init");
-
- if (cvp->cvc_flags & CVCF_ABORTING) {
- /*
- * Someone on the stack bailed out...notify all of the
- * connections and schedule the VCC termination
- */
- cop = cvp->cvc_conn;
- while (cop) {
- cop2 = cop->co_next;
- atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
- cop = cop2;
- }
- atm_cm_closevc(cvp);
- (void) splx(s);
- return;
- }
- break;
-
- case CVCS_ACCEPT:
- /*
- * Stack already initialized
- */
- break;
-
- default:
- panic("atm_cm_connected: connvc state");
- }
-
- /*
- * VCC is ready for action
- */
- cvp->cvc_state = CVCS_ACTIVE;
-
- /*
- * Notify all connections that the call has completed
- */
- cop = cvp->cvc_conn;
- while (cop) {
- cop2 = cop->co_next;
-
- switch (cop->co_state) {
-
- case COS_OUTCONN:
- case COS_INACCEPT:
- cop->co_state = COS_ACTIVE;
- (*cop->co_endpt->ep_connected)(cop->co_toku);
- break;
-
- case COS_ACTIVE:
- /*
- * May get here if an ep_connected() call (from
- * above) results in an atm_cm_addllc() call for
- * the just connected connection.
- */
- break;
-
- default:
- panic("atm_cm_connected: connection state");
- }
-
- cop = cop2;
- }
-
- (void) splx(s);
-
- /*
- * Input any queued packets
- */
- while ((m = cvp->cvc_rcvq) != NULL) {
- cvp->cvc_rcvq = KB_QNEXT(m);
- cvp->cvc_rcvqlen--;
- KB_QNEXT(m) = NULL;
-
- /*
- * Currently only supported for CPCS API
- */
- atm_cm_cpcs_upper(CPCS_UNITDATA_SIG, cvp, (intptr_t)m, 0);
- }
-
- return;
-}
-
-
-/*
- * VCC Cleared Notification
- *
- * This function is called by a signalling manager as notification that a
- * VCC call has been cleared. The cause information describing the reason
- * for the call clearing will be contained in the connection VCC attributes.
- *
- * Arguments:
- * cvp pointer to connection VCC block
- *
- * Returns:
- * none
- *
- */
-void
-atm_cm_cleared(cvp)
- Atm_connvc *cvp;
-{
- Atm_connection *cop, *cop2;
- int s;
-
- KASSERT((cvp->cvc_state != CVCS_FREE) && (cvp->cvc_state < CVCS_CLEAR),
- ("atm_cm_cleared: state sanity check failed"));
-
- cvp->cvc_state = CVCS_CLEAR;
- s = splnet();
-
- /*
- * Terminate all connections
- */
- cop = cvp->cvc_conn;
- while (cop) {
- cop2 = cop->co_next;
- atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
- cop = cop2;
- }
-
- /*
- * Clean up connection VCC
- */
- atm_cm_closevc(cvp);
-
- (void) splx(s);
-
- return;
-}
-
-
-/*
- * Process Incoming Call Queue
- *
- * This function is scheduled by atm_cm_incoming() in order to process
- * all the entries on the incoming call queue.
- *
- * Arguments:
- * arg argument passed on timeout() call
- *
- * Returns:
- * none
- *
- */
-static KTimeout_ret
-atm_cm_procinq(arg)
- void *arg;
-{
- Atm_connvc *cvp;
- int cnt = 0, s;
-
- /*
- * Only process incoming calls up to our quota
- */
- while (cnt++ < ATM_CALLQ_MAX) {
-
- s = splnet();
-
- /*
- * Get next awaiting call
- */
- cvp = Q_HEAD(atm_incoming_queue, Atm_connvc);
- if (cvp == NULL) {
- (void) splx(s);
- break;
- }
- DEQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
- atm_incoming_qlen--;
- cvp->cvc_flags &= ~CVCF_INCOMQ;
-
- /*
- * Handle the call
- */
- atm_cm_incall(cvp);
-
- (void) splx(s);
- }
-
- /*
- * If we've expended our quota, reschedule ourselves
- */
- if (cnt >= ATM_CALLQ_MAX)
- timeout(atm_cm_procinq, (void *)0, 0);
-}
-
-
-/*
- * Process Incoming Call
- *
- * This function will search through the listening queue and try to find
- * matching endpoint(s) for the incoming call. If we find any, we will
- * notify the endpoint service(s) of the incoming call and will then
- * notify the signalling manager to progress the call to an active status.
- *
- * If there are no listeners for the call, the signalling manager will be
- * notified of a call rejection.
- *
- * Called at splnet.
- *
- * Arguments:
- * cvp pointer to connection VCC for incoming call
- *
- * Returns:
- * none
- *
- */
-static void
-atm_cm_incall(cvp)
- Atm_connvc *cvp;
-{
- Atm_connection *cop, *lcop, *hcop;
- Atm_attributes attr;
- int err;
-
- hcop = NULL;
- lcop = NULL;
- cop = NULL;
- attr = cvp->cvc_attr;
-
- /*
- * Look for matching listeners
- */
- while ((lcop = atm_cm_match(&attr, lcop)) != NULL) {
-
- if (cop == NULL) {
- /*
- * Need a new connection block
- * May be called from timeout - dont wait.
- */
- cop = uma_zalloc(atm_connection_zone, M_NOWAIT);
- if (cop == NULL) {
- cvp->cvc_attr.cause = atm_cause_tmpl;
- cvp->cvc_attr.cause.v.cause_value =
- T_ATM_CAUSE_TEMPORARY_FAILURE;
- goto fail;
- }
- }
-
- /*
- * Initialize connection from listener and incoming call
- */
- cop->co_mxh = NULL;
- cop->co_state = COS_INCONN;
- cop->co_mpx = lcop->co_mpx;
- cop->co_endpt = lcop->co_endpt;
- cop->co_llc = lcop->co_llc;
-
- switch (attr.bearer.v.connection_configuration) {
-
- case T_ATM_1_TO_1:
- cop->co_flags |= COF_P2P;
- break;
-
- case T_ATM_1_TO_MANY:
- /* Not supported */
- cop->co_flags |= COF_P2MP;
- cvp->cvc_attr.cause = atm_cause_tmpl;
- cvp->cvc_attr.cause.v.cause_value =
- T_ATM_CAUSE_BEARER_CAPABILITY_NOT_IMPLEMENTED;
- goto fail;
- }
-
- /*
- * Notify endpoint of incoming call
- */
- err = (*cop->co_endpt->ep_incoming)
- (lcop->co_toku, cop, &cvp->cvc_attr, &cop->co_toku);
-
- if (err == 0) {
-
- /*
- * Endpoint has accepted the call
- *
- * Setup call attributes
- */
- if (hcop == NULL) {
- cvp->cvc_attr.api = lcop->co_lattr->api;
- cvp->cvc_attr.api_init =
- lcop->co_lattr->api_init;
- cvp->cvc_attr.llc = lcop->co_lattr->llc;
- }
- cvp->cvc_attr.headin = MAX(cvp->cvc_attr.headin,
- lcop->co_lattr->headin);
-
- /*
- * Setup connection info and queueing
- */
- cop->co_state = COS_INACCEPT;
- cop->co_connvc = cvp;
- LINK2TAIL(cop, Atm_connection, hcop, co_next);
- cop->co_mxh = hcop;
-
- /*
- * Need a new connection block next time around
- */
- cop = NULL;
-
- } else {
- /*
- * Endpoint refuses call
- */
- goto fail;
- }
- }
-
- /*
- * We're done looking for listeners
- */
- if (hcop) {
- /*
- * Someone actually wants the call, so notify
- * the signalling manager to continue
- */
- cvp->cvc_flags |= CVCF_CONNQ;
- ENQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
- if (atm_cm_accept(cvp, hcop))
- goto fail;
-
- } else {
- /*
- * Nobody around to take the call
- */
- cvp->cvc_attr.cause = atm_cause_tmpl;
- cvp->cvc_attr.cause.v.cause_value =
- T_ATM_CAUSE_INCOMPATIBLE_DESTINATION;
- goto fail;
- }
-
- /*
- * Clean up loose ends
- */
- if (cop)
- uma_zfree(atm_connection_zone, cop);
-
- /*
- * Call has been accepted
- */
- return;
-
-fail:
- /*
- * Call failed - notify any endpoints of the call failure
- */
-
- /*
- * Clean up loose ends
- */
- if (cop)
- uma_zfree(atm_connection_zone, cop);
-
- if (cvp->cvc_attr.cause.tag != T_ATM_PRESENT) {
- cvp->cvc_attr.cause = atm_cause_tmpl;
- cvp->cvc_attr.cause.v.cause_value =
- T_ATM_CAUSE_UNSPECIFIED_NORMAL;
- }
- cop = hcop;
- while (cop) {
- Atm_connection *cop2 = cop->co_next;
- atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
- cop = cop2;
- }
-
- /*
- * Tell the signalling manager to reject the call
- */
- atm_cm_closevc(cvp);
-
- return;
-}
-
-
-/*
- * Accept an Incoming ATM Call
- *
- * Some endpoint service(s) wants to accept an incoming call, so the
- * signalling manager will be notified to attempt to progress the call
- * to an active status.
- *
- * If the signalling manager indicates that connection activation has
- * been immediately successful, then all of the endpoints will be notified
- * that the connection is ready for data transmission.
- *
- * If the return indicates that connection activation is still in progress,
- * then the endpoints must wait for notification from the Connection Manager
- * indicating the final status of the call setup. If the call setup completes
- * successfully, then a "call connected" notification will be sent to the
- * endpoints by the Connection Manager. If the call setup fails, then the
- * endpoints will receive a "call cleared" notification.
- *
- * Called at splnet.
- *
- * Arguments:
- * cvp pointer to connection VCC for incoming call
- * cop pointer to head of accepted connections
- *
- * Returns:
- * 0 connection has been successfully activated
- * errno accept failed - reason indicated
- *
- */
-static int
-atm_cm_accept(cvp, cop)
- Atm_connvc *cvp;
- Atm_connection *cop;
-{
- struct stack_list sl;
- void (*upf)(int, void *, intptr_t, intptr_t);
- int sli, err, err2;
-
-
- /*
- * Link vcc to connections
- */
- cvp->cvc_conn = cop;
-
- /*
- * Initialize stack list index
- */
- sli = 0;
-
- /*
- * Check out Data API
- */
- switch (cvp->cvc_attr.api) {
-
- case CMAPI_CPCS:
- upf = atm_cm_cpcs_upper;
- break;
-
- case CMAPI_SAAL:
- sl.sl_sap[sli++] = SAP_SSCF_UNI;
- sl.sl_sap[sli++] = SAP_SSCOP;
- upf = atm_cm_saal_upper;
- break;
-
- case CMAPI_SSCOP:
- sl.sl_sap[sli++] = SAP_SSCOP;
- upf = atm_cm_sscop_upper;
- break;
-
- default:
- upf = NULL;
- }
-
- /*
- * AAL Attributes
- */
- switch (cvp->cvc_attr.aal.type) {
-
- case ATM_AAL5:
- sl.sl_sap[sli++] = SAP_CPCS_AAL5;
- sl.sl_sap[sli++] = SAP_SAR_AAL5;
- sl.sl_sap[sli++] = SAP_ATM;
- break;
-
- case ATM_AAL3_4:
- sl.sl_sap[sli++] = SAP_CPCS_AAL3_4;
- sl.sl_sap[sli++] = SAP_SAR_AAL3_4;
- sl.sl_sap[sli++] = SAP_ATM;
- break;
- }
-
- /*
- * Terminate stack list
- */
- sl.sl_sap[sli] = 0;
-
- /*
- * Create a service stack
- */
- err = atm_create_stack(cvp, &sl, upf);
- if (err) {
- goto done;
- }
-
- /*
- * Let the signalling manager finish the VCC activation
- */
- switch ((*cvp->cvc_sigmgr->sm_accept)(cvp->cvc_vcc, &err)) {
-
- case CALL_PROCEEDING:
- /*
- * Note that we're not finished yet
- */
- err = EINPROGRESS;
- /* FALLTHRU */
-
- case CALL_CONNECTED:
- /*
- * Initialize the stack now, even if the call isn't totally
- * active yet. We want to avoid the delay between getting
- * the "call connected" event and actually notifying the
- * adapter to accept cells on the new VCC - if the delay is
- * too long, then we end up dropping the first pdus sent by
- * the caller.
- */
- cvp->cvc_state = CVCS_INIT;
- STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].init,
- cvp->cvc_lower, cvp->cvc_tokl, cvp,
- cvp->cvc_attr.api_init, 0, err2);
- if (err2)
- panic("atm_cm_accept: init");
-
- if (cvp->cvc_flags & CVCF_ABORTING) {
- /*
- * Someone on the stack bailed out...schedule the
- * VCC and stack termination
- */
- err = ECONNABORTED;
- } else {
- /*
- * Everything looks fine from here
- */
- if (err)
- cvp->cvc_state = CVCS_ACCEPT;
- else
- cvp->cvc_state = CVCS_ACTIVE;
- }
- break;
-
- case CALL_FAILED:
- /*
- * Terminate stack and clean up before we leave
- */
- cvp->cvc_state = CVCS_CLEAR;
- break;
-
- default:
- panic("atm_cm_accept: accept");
- }
-
-done:
- if (err == 0) {
- /*
- * Call has been connected, notify endpoints
- */
- while (cop) {
- Atm_connection *cop2 = cop->co_next;
-
- cop->co_state = COS_ACTIVE;
- (*cop->co_endpt->ep_connected)(cop->co_toku);
- cop = cop2;
- }
-
- } else if (err == EINPROGRESS) {
- /*
- * Call is still in progress, endpoint must wait
- */
- err = 0;
-
- } else {
- /*
- * Let caller know we failed
- */
- cvp->cvc_attr.cause = atm_cause_tmpl;
- cvp->cvc_attr.cause.v.cause_value =
- T_ATM_CAUSE_UNSPECIFIED_RESOURCE_UNAVAILABLE;
- }
-
- return (err);
-}
-
-
-/*
- * Match Attributes on Listening Queue
- *
- * This function will attempt to match the supplied connection attributes
- * with one of the registered attributes in the listening queue. The pcop
- * argument may be supplied in order to allow multiple listeners to share
- * an incoming call (if supported by the listeners).
- *
- * Called at splnet.
- *
- * Arguments:
- * ap pointer to attributes to be matched
- * pcop pointer to the previously matched connection
- *
- * Returns:
- * addr connection with which a match was found
- * 0 no match found
- *
- */
-Atm_connection *
-atm_cm_match(ap, pcop)
- Atm_attributes *ap;
- Atm_connection *pcop;
-{
- Atm_connection *cop;
- Atm_attributes *lap;
-
-
- /*
- * If we've already matched a listener...
- */
- if (pcop) {
- /*
- * Make sure already matched listener supports sharing
- */
- if ((pcop->co_mpx != ATM_ENC_LLC) ||
- ((pcop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0))
- return (NULL);
-
- /*
- * Position ourselves after the matched entry
- */
- for (cop = atm_listen_queue; cop; cop = cop->co_next) {
- if (cop == pcop) {
- cop = pcop->co_next;
- break;
- }
- }
- } else {
- /*
- * Start search at top of listening queue
- */
- cop = atm_listen_queue;
- }
-
- /*
- * Search through listening queue
- */
- for (; cop; cop = cop->co_next) {
-
- lap = cop->co_lattr;
-
- /*
- * If we're trying to share, check that this entry allows it
- */
- if (pcop) {
- if ((cop->co_mpx != ATM_ENC_LLC) ||
- ((cop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0))
- continue;
- }
-
- /*
- * ALL "matchable" attributes must match
- */
-
- /*
- * BHLI
- */
- if (lap->bhli.tag == T_ATM_ABSENT) {
- if (ap->bhli.tag == T_ATM_PRESENT)
- continue;
- } else if (lap->bhli.tag == T_ATM_PRESENT) {
- if (ap->bhli.tag == T_ATM_ABSENT)
- continue;
- if (ap->bhli.tag == T_ATM_PRESENT)
- if (bcmp(&lap->bhli.v, &ap->bhli.v,
- sizeof(struct t_atm_bhli)))
- continue;
- }
-
- /*
- * BLLI Layer 2
- */
- if (lap->blli.tag_l2 == T_ATM_ABSENT) {
- if (ap->blli.tag_l2 == T_ATM_PRESENT)
- continue;
- } else if (lap->blli.tag_l2 == T_ATM_PRESENT) {
- if (ap->blli.tag_l2 == T_ATM_ABSENT)
- continue;
- if (ap->blli.tag_l2 == T_ATM_PRESENT) {
- if (bcmp(&lap->blli.v.layer_2_protocol.ID,
- &ap->blli.v.layer_2_protocol.ID,
- sizeof(
- ap->blli.v.layer_2_protocol.ID)))
- continue;
- }
- }
-
- /*
- * BLLI Layer 3
- */
- if (lap->blli.tag_l3 == T_ATM_ABSENT) {
- if (ap->blli.tag_l3 == T_ATM_PRESENT)
- continue;
- } else if (lap->blli.tag_l3 == T_ATM_PRESENT) {
- if (ap->blli.tag_l3 == T_ATM_ABSENT)
- continue;
- if (ap->blli.tag_l3 == T_ATM_PRESENT) {
- if (bcmp(&lap->blli.v.layer_3_protocol.ID,
- &ap->blli.v.layer_3_protocol.ID,
- sizeof(
- ap->blli.v.layer_3_protocol.ID)))
- continue;
- }
- }
-
- /*
- * LLC
- */
- if (lap->llc.tag == T_ATM_ABSENT) {
- if (ap->llc.tag == T_ATM_PRESENT)
- continue;
- } else if (lap->llc.tag == T_ATM_PRESENT) {
- if (ap->llc.tag == T_ATM_ABSENT)
- continue;
- if (ap->llc.tag == T_ATM_PRESENT) {
- int i = MIN(lap->llc.v.llc_len,
- ap->llc.v.llc_len);
-
- if (bcmp(lap->llc.v.llc_info,
- ap->llc.v.llc_info, i))
- continue;
- }
- }
-
- /*
- * AAL
- */
- if (lap->aal.tag == T_ATM_ABSENT) {
- if (ap->aal.tag == T_ATM_PRESENT)
- continue;
- } else if (lap->aal.tag == T_ATM_PRESENT) {
- if (ap->aal.tag == T_ATM_ABSENT)
- continue;
- if (ap->aal.tag == T_ATM_PRESENT) {
- if (lap->aal.type != ap->aal.type)
- continue;
- if (lap->aal.type == ATM_AAL5) {
- if (lap->aal.v.aal5.SSCS_type !=
- ap->aal.v.aal5.SSCS_type)
- continue;
- } else {
- if (lap->aal.v.aal4.SSCS_type !=
- ap->aal.v.aal4.SSCS_type)
- continue;
- }
- }
- }
-
- /*
- * Called Party
- */
- if (lap->called.tag == T_ATM_ABSENT) {
- if (ap->called.tag == T_ATM_PRESENT)
- continue;
- } else if (lap->called.tag == T_ATM_PRESENT) {
- if (ap->called.tag == T_ATM_ABSENT)
- continue;
- if (ap->called.tag == T_ATM_PRESENT) {
- if ((!ATM_ADDR_EQUAL(&lap->called.addr,
- &ap->called.addr)) ||
- (!ATM_ADDR_EQUAL(&lap->called.subaddr,
- &ap->called.subaddr)))
- continue;
- }
- }
-
- /*
- * Found a full match - return it
- */
- break;
- }
-
- return (cop);
-}
-
-
-/*
- * Find Shareable LLC VCC
- *
- * Given an endpoint-supplied connection attribute using LLC multiplexing,
- * this function will attempt to locate an existing connection which meets
- * the requirements of the supplied attributes.
- *
- * Called at splnet.
- *
- * Arguments:
- * ap pointer to requested attributes
- *
- * Returns:
- * addr shareable LLC connection VCC
- * 0 no shareable VCC available
- *
- */
-static Atm_connvc *
-atm_cm_share_llc(ap)
- Atm_attributes *ap;
-{
- Atm_connection *cop;
- Atm_connvc *cvp;
-
- /*
- * Is requestor willing to share?
- */
- if ((ap->llc.v.flags & T_ATM_LLC_SHARING) == 0)
- return (NULL);
-
- /*
- * Try to find a shareable connection
- */
- for (cvp = Q_HEAD(atm_connection_queue, Atm_connvc); cvp;
- cvp = Q_NEXT(cvp, Atm_connvc, cvc_q)) {
-
- /*
- * Dont use terminating connections
- */
- switch (cvp->cvc_state) {
-
- case CVCS_SETUP:
- case CVCS_ACCEPT:
- case CVCS_ACTIVE:
- break;
-
- default:
- continue;
- }
-
- /*
- * Is connection LLC and shareable?
- */
- if ((cvp->cvc_attr.llc.tag != T_ATM_PRESENT) ||
- ((cvp->cvc_attr.llc.v.flags & T_ATM_LLC_SHARING) == 0))
- continue;
-
- /*
- * Match requested attributes with existing connection
- */
- if (ap->nif != cvp->cvc_attr.nif)
- continue;
-
- if ((ap->api != cvp->cvc_attr.api) ||
- (ap->api_init != cvp->cvc_attr.api_init))
- continue;
-
- /*
- * Remote Party
- */
- if (cvp->cvc_flags & CVCF_CALLER) {
- if ((!ATM_ADDR_EQUAL(&ap->called.addr,
- &cvp->cvc_attr.called.addr)) ||
- (!ATM_ADDR_EQUAL(&ap->called.subaddr,
- &cvp->cvc_attr.called.subaddr)))
- continue;
- } else {
- if (cvp->cvc_attr.calling.tag != T_ATM_PRESENT)
- continue;
- if ((!ATM_ADDR_EQUAL(&ap->called.addr,
- &cvp->cvc_attr.calling.addr)) ||
- (!ATM_ADDR_EQUAL(&ap->called.subaddr,
- &cvp->cvc_attr.calling.subaddr)))
- continue;
- }
-
- /*
- * AAL
- */
- if (ap->aal.type == ATM_AAL5) {
- struct t_atm_aal5 *ap5, *cv5;
-
- ap5 = &ap->aal.v.aal5;
- cv5 = &cvp->cvc_attr.aal.v.aal5;
-
- if ((cvp->cvc_attr.aal.type != ATM_AAL5) ||
- (ap5->SSCS_type != cv5->SSCS_type))
- continue;
-
- if (cvp->cvc_flags & CVCF_CALLER) {
- if (ap5->forward_max_SDU_size >
- cv5->forward_max_SDU_size)
- continue;
- } else {
- if (ap5->forward_max_SDU_size >
- cv5->backward_max_SDU_size)
- continue;
- }
- } else {
- struct t_atm_aal4 *ap4, *cv4;
-
- ap4 = &ap->aal.v.aal4;
- cv4 = &cvp->cvc_attr.aal.v.aal4;
-
- if ((cvp->cvc_attr.aal.type != ATM_AAL3_4) ||
- (ap4->SSCS_type != cv4->SSCS_type))
- continue;
-
- if (cvp->cvc_flags & CVCF_CALLER) {
- if (ap4->forward_max_SDU_size >
- cv4->forward_max_SDU_size)
- continue;
- } else {
- if (ap4->forward_max_SDU_size >
- cv4->backward_max_SDU_size)
- continue;
- }
- }
-
- /*
- * Traffic Descriptor
- */
- if ((ap->traffic.tag != T_ATM_PRESENT) ||
- (cvp->cvc_attr.traffic.tag != T_ATM_PRESENT) ||
- (ap->traffic.v.best_effort != T_YES) ||
- (cvp->cvc_attr.traffic.v.best_effort != T_YES))
- continue;
-
- /*
- * Broadband Bearer
- */
- if (ap->bearer.v.connection_configuration !=
- cvp->cvc_attr.bearer.v.connection_configuration)
- continue;
-
- /*
- * QOS
- */
- if (cvp->cvc_flags & CVCF_CALLER) {
- if ((ap->qos.v.forward.qos_class !=
- cvp->cvc_attr.qos.v.forward.qos_class) ||
- (ap->qos.v.backward.qos_class !=
- cvp->cvc_attr.qos.v.backward.qos_class))
- continue;
- } else {
- if ((ap->qos.v.forward.qos_class !=
- cvp->cvc_attr.qos.v.backward.qos_class) ||
- (ap->qos.v.backward.qos_class !=
- cvp->cvc_attr.qos.v.forward.qos_class))
- continue;
- }
-
- /*
- * The new LLC header must also be unique for this VCC
- */
- for (cop = cvp->cvc_conn; cop; cop = cop->co_next) {
- int i = MIN(ap->llc.v.llc_len,
- cop->co_llc.v.llc_len);
-
- if (bcmp(ap->llc.v.llc_info,
- cop->co_llc.v.llc_info, i) == 0)
- break;
- }
-
- /*
- * If no header overlaps, then we're done
- */
- if (cop == NULL)
- break;
- }
-
- return (cvp);
-}
-
-
-/*
- * Close Connection
- *
- * This function will terminate a connection, including notifying the
- * user, if necessary, and freeing up control block memory. The caller
- * is responsible for managing the connection VCC.
- *
- * Called at splnet.
- *
- * Arguments:
- * cop pointer to connection block
- * cause pointer to cause of close
- *
- * Returns:
- * none
- *
- */
-static void
-atm_cm_closeconn(cop, cause)
- Atm_connection *cop;
- struct t_atm_cause *cause;
-{
-
- /*
- * Decide whether user needs notification
- */
- switch (cop->co_state) {
-
- case COS_OUTCONN:
- case COS_LISTEN:
- case COS_INCONN:
- case COS_INACCEPT:
- case COS_ACTIVE:
- /*
- * Yup, let 'em know connection is gone
- */
- if (cop->co_toku)
- (*cop->co_endpt->ep_cleared)(cop->co_toku, cause);
- break;
-
- case COS_CLEAR:
- /*
- * Nope,they should know already
- */
- break;
-
- default:
- panic("atm_cm_closeconn: bogus state");
- }
-
- /*
- * Unlink connection from its queues
- */
- switch (cop->co_state) {
-
- case COS_LISTEN:
- uma_zfree(atm_attributes_zone, cop->co_lattr);
- UNLINK(cop, Atm_connection, atm_listen_queue, co_next);
- break;
-
- default:
- /*
- * Remove connection from multiplexor queue
- */
- if (cop->co_mxh != cop) {
- /*
- * Connection is down the chain, just unlink it
- */
- UNLINK(cop, Atm_connection, cop->co_mxh, co_next);
-
- } else if (cop->co_next != NULL) {
- /*
- * Connection is at the head of a non-singleton chain,
- * so unlink and reset the chain head
- */
- Atm_connection *t, *nhd;
-
- t = nhd = cop->co_next;
- while (t) {
- t->co_mxh = nhd;
- t = t->co_next;
- }
- if (nhd->co_connvc)
- nhd->co_connvc->cvc_conn = nhd;
- }
- }
-
- /*
- * Free the connection block
- */
- cop->co_state = COS_FREE;
- uma_zfree(atm_connection_zone, cop);
- return;
-}
-
-
-/*
- * Close Connection VCC
- *
- * This function will terminate a connection VCC, including releasing the
- * the call to the signalling manager, terminating the VCC protocol stack,
- * and freeing up control block memory.
- *
- * Called at splnet.
- *
- * Arguments:
- * cvp pointer to connection VCC block
- *
- * Returns:
- * none
- *
- */
-static void
-atm_cm_closevc(cvp)
- Atm_connvc *cvp;
-{
- int err;
-
- /*
- * Break links with the connection block
- */
- cvp->cvc_conn = NULL;
-
- /*
- * Cancel any running timer
- */
- CVC_CANCEL(cvp);
-
- /*
- * Free queued packets
- */
- while (cvp->cvc_rcvq) {
- KBuffer *m;
-
- m = cvp->cvc_rcvq;
- cvp->cvc_rcvq = KB_QNEXT(m);
- KB_QNEXT(m) = NULL;
- KB_FREEALL(m);
- }
-
- /*
- * Unlink from any queues
- */
- if (cvp->cvc_flags & CVCF_INCOMQ) {
- DEQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue);
- atm_incoming_qlen--;
- cvp->cvc_flags &= ~CVCF_INCOMQ;
-
- } else if (cvp->cvc_flags & CVCF_CONNQ) {
- DEQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue);
- cvp->cvc_flags &= ~CVCF_CONNQ;
- }
-
- /*
- * Release the signalling call
- */
- switch (cvp->cvc_state) {
-
- case CVCS_SETUP:
- case CVCS_INIT:
- case CVCS_ACCEPT:
- case CVCS_ACTIVE:
- case CVCS_RELEASE:
- if (cvp->cvc_vcc) {
- cvp->cvc_state = CVCS_RELEASE;
- switch ((*cvp->cvc_sigmgr->sm_release)
- (cvp->cvc_vcc, &err)) {
-
- case CALL_CLEARED:
- /*
- * Looks good so far...
- */
- break;
-
- case CALL_PROCEEDING:
- /*
- * We'll have to wait for the call to clear
- */
- return;
-
- case CALL_FAILED:
- /*
- * If there's a memory shortage, retry later.
- * Otherwise who knows what's going on....
- */
- if ((err == ENOMEM) || (err == ENOBUFS)) {
- CVC_TIMER(cvp, 1 * ATM_HZ);
- return;
- }
- log(LOG_ERR,
- "atm_cm_closevc: release %d\n", err);
- break;
- }
- }
- break;
-
- case CVCS_INCOMING:
- case CVCS_REJECT:
- if (cvp->cvc_vcc) {
- cvp->cvc_state = CVCS_REJECT;
- switch ((*cvp->cvc_sigmgr->sm_reject)
- (cvp->cvc_vcc, &err)) {
-
- case CALL_CLEARED:
- /*
- * Looks good so far...
- */
- break;
-
- case CALL_FAILED:
- /*
- * If there's a memory shortage, retry later.
- * Otherwise who knows what's going on....
- */
- if ((err == ENOMEM) || (err == ENOBUFS)) {
- CVC_TIMER(cvp, 1 * ATM_HZ);
- return;
- }
- log(LOG_ERR,
- "atm_cm_closevc: reject %d\n", err);
- break;
- }
- }
- break;
-
- case CVCS_CLEAR:
- case CVCS_TERM:
- /*
- * No need for anything here
- */
- break;
-
- default:
- panic("atm_cm_closevc: bogus state");
- }
-
- /*
- * Now terminate the stack
- */
- if (cvp->cvc_tokl) {
- cvp->cvc_state = CVCS_TERM;
-
- /*
- * Wait until stack is unwound before terminating
- */
- if ((cvp->cvc_downcnt > 0) || (cvp->cvc_upcnt > 0)) {
- CVC_TIMER(cvp, 0);
- return;
- }
-
- STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].term,
- cvp->cvc_lower, cvp->cvc_tokl, cvp, 0, 0, err);
-
- cvp->cvc_tokl = NULL;
- }
-
- /*
- * Let signalling manager finish up
- */
- cvp->cvc_state = CVCS_FREE;
- if (cvp->cvc_vcc) {
- (void) (*cvp->cvc_sigmgr->sm_free)(cvp->cvc_vcc);
- }
-
- /*
- * Finally, free our own control blocks
- */
- uma_zfree(atm_connvc_zone, cvp);
- return;
-}
-
-
-/*
- * Process a Connection VCC timeout
- *
- * Called when a previously scheduled cvc control block timer expires.
- * Processing will be based on the current cvc state.
- *
- * Called at splnet.
- *
- * Arguments:
- * tip pointer to cvc timer control block
- *
- * Returns:
- * none
- *
- */
-static void
-atm_cm_timeout(tip)
- struct atm_time *tip;
-{
- Atm_connection *cop, *cop2;
- Atm_connvc *cvp;
-
- /*
- * Back-off to cvc control block
- */
- cvp = (Atm_connvc *)
- ((caddr_t)tip - offsetof(Atm_connvc, cvc_time));
-
- /*
- * Process timeout based on protocol state
- */
- switch (cvp->cvc_state) {
-
- case CVCS_SETUP:
- case CVCS_ACCEPT:
- case CVCS_ACTIVE:
- /*
- * Handle VCC abort
- */
- if ((cvp->cvc_flags & CVCF_ABORTING) == 0)
- goto logerr;
-
- /*
- * Terminate all connections
- */
- cop = cvp->cvc_conn;
- while (cop) {
- cop2 = cop->co_next;
- atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v);
- cop = cop2;
- }
-
- /*
- * Terminate VCC
- */
- atm_cm_closevc(cvp);
-
- break;
-
- case CVCS_REJECT:
- case CVCS_RELEASE:
- case CVCS_TERM:
- /*
- * Retry failed operation
- */
- atm_cm_closevc(cvp);
- break;
-
- default:
-logerr:
- log(LOG_ERR,
- "atm_cm_timeout: invalid state: cvp=%p, state=%d\n",
- cvp, cvp->cvc_state);
- }
-}
-
-
-/*
- * CPCS User Control Commands
- *
- * This function is called by an endpoint user to pass a control command
- * across a CPCS data API. Mostly we just send these down the stack.
- *
- * Arguments:
- * cmd stack command code
- * cop pointer to connection block
- * arg argument
- *
- * Returns:
- * 0 command output successful
- * errno output failed - reason indicated
- *
- */
-int
-atm_cm_cpcs_ctl(cmd, cop, arg)
- int cmd;
- Atm_connection *cop;
- void *arg;
-{
- Atm_connvc *cvp;
- int err = 0;
-
- /*
- * Validate connection state
- */
- if (cop->co_state != COS_ACTIVE) {
- err = EFAULT;
- goto done;
- }
-
- cvp = cop->co_connvc;
- if (cvp->cvc_state != CVCS_ACTIVE) {
- err = EFAULT;
- goto done;
- }
-
- if (cvp->cvc_attr.api != CMAPI_CPCS) {
- err = EFAULT;
- goto done;
- }
-
- switch (cmd) {
-
- default:
- err = EINVAL;
- }
-
-done:
- return (err);
-}
-
-
-/*
- * CPCS Data Output
- *
- * This function is called by an endpoint user to output a data packet
- * across a CPCS data API. After we've validated the connection state, the
- * packet will be encapsulated (if necessary) and sent down the data stack.
- *
- * Arguments:
- * cop pointer to connection block
- * m pointer to packet buffer chain to be output
- *
- * Returns:
- * 0 packet output successful
- * errno output failed - reason indicated
- *
- */
-int
-atm_cm_cpcs_data(cop, m)
- Atm_connection *cop;
- KBuffer *m;
-{
- Atm_connvc *cvp;
- struct attr_llc *llcp;
- int err, space;
- void *bp;
-
-
- /*
- * Validate connection state
- */
- if (cop->co_state != COS_ACTIVE) {
- err = EFAULT;
- goto done;
- }
-
- cvp = cop->co_connvc;
- if (cvp->cvc_state != CVCS_ACTIVE) {
- err = EFAULT;
- goto done;
- }
-
- if (cvp->cvc_attr.api != CMAPI_CPCS) {
- err = EFAULT;
- goto done;
- }
-
- /*
- * Add any packet encapsulation
- */
- switch (cop->co_mpx) {
-
- case ATM_ENC_NULL:
- /*
- * None needed...
- */
- break;
-
- case ATM_ENC_LLC:
- /*
- * Need to add an LLC header
- */
- llcp = &cop->co_llc;
-
- /*
- * See if there's room to add LLC header to front of packet.
- */
- KB_HEADROOM(m, space);
- if (space < llcp->v.llc_len) {
- KBuffer *n;
-
- /*
- * We have to allocate another buffer and tack it
- * onto the front of the packet
- */
- MGETHDR(n, KB_F_NOWAIT, KB_T_HEADER);
- if (n == 0) {
- err = ENOMEM;
- goto done;
- }
- KB_TAILALIGN(n, llcp->v.llc_len);
- KB_LINKHEAD(n, m);
- m = n;
- } else {
- /*
- * Header fits, just adjust buffer controls
- */
- KB_HEADADJ(m, llcp->v.llc_len);
- }
-
- /*
- * Add the LLC header
- */
- KB_DATASTART(m, bp, void *);
- bcopy(llcp->v.llc_info, bp, llcp->v.llc_len);
- KB_PLENADJ(m, llcp->v.llc_len);
- break;
-
- default:
- panic("atm_cm_cpcs_data: mpx");
- }
-
- /*
- * Finally, we can send the packet on its way
- */
- STACK_CALL(CPCS_UNITDATA_INV, cvp->cvc_lower, cvp->cvc_tokl,
- cvp, (intptr_t)m, 0, err);
-
-done:
- return (err);
-}
-
-
-/*
- * Process CPCS Stack Commands
- *
- * This is the top of the CPCS API data stack. All upward stack commands
- * for the CPCS data API will be received and processed here.
- *
- * Arguments:
- * cmd stack command code
- * tok session token (pointer to connection VCC control block)
- * arg1 argument 1
- * arg2 argument 2
- *
- * Returns:
- * none
- *
- */
-static void
-atm_cm_cpcs_upper(cmd, tok, arg1, arg2)
- int cmd;
- void *tok;
- intptr_t arg1;
- intptr_t arg2;
-{
- Atm_connection *cop;
- Atm_connvc *cvp = tok;
- KBuffer *m;
- void *bp;
- int s;
-
- switch (cmd) {
-
- case CPCS_UNITDATA_SIG:
- /*
- * Input data packet
- */
- m = (KBuffer *)arg1;
-
- if (cvp->cvc_state != CVCS_ACTIVE) {
- if (cvp->cvc_state == CVCS_ACCEPT) {
- KBuffer *n;
-
- /*
- * Queue up any packets received before sigmgr
- * notifies us of incoming call completion
- */
- if (cvp->cvc_rcvqlen >= CVC_RCVQ_MAX) {
- KB_FREEALL(m);
- atm_cm_stat.cms_rcvconnvc++;
- return;
- }
- KB_QNEXT(m) = NULL;
- if (cvp->cvc_rcvq == NULL) {
- cvp->cvc_rcvq = m;
- } else {
- for (n = cvp->cvc_rcvq;
- KB_QNEXT(n) != NULL;
- n = KB_QNEXT(n))
- ;
- KB_QNEXT(n) = m;
- }
- cvp->cvc_rcvqlen++;
- return;
- } else {
- KB_FREEALL(m);
- atm_cm_stat.cms_rcvconnvc++;
- return;
- }
- }
-
- /*
- * Send the packet to the interface's bpf if this
- * vc has one.
- */
- if (cvp->cvc_vcc != NULL &&
- cvp->cvc_vcc->vc_nif != NULL) {
- struct ifnet *ifp =
- (struct ifnet *)cvp->cvc_vcc->vc_nif;
-
- BPF_MTAP(ifp, m);
- }
-
- /*
- * Locate packet's connection
- */
- cop = cvp->cvc_conn;
- switch (cop->co_mpx) {
-
- case ATM_ENC_NULL:
- /*
- * We're already there...
- */
- break;
-
- case ATM_ENC_LLC:
- /*
- * Find connection with matching LLC header
- */
- if (KB_LEN(m) < T_ATM_LLC_MAX_LEN) {
- KB_PULLUP(m, T_ATM_LLC_MAX_LEN, m);
- if (m == 0) {
- atm_cm_stat.cms_llcdrop++;
- return;
- }
- }
- KB_DATASTART(m, bp, void *);
-
- s = splnet();
-
- while (cop) {
- if (bcmp(bp, cop->co_llc.v.llc_info,
- cop->co_llc.v.llc_len) == 0)
- break;
- cop = cop->co_next;
- }
-
- (void) splx(s);
-
- if (cop == NULL) {
- /*
- * No connected user for this LLC
- */
- KB_FREEALL(m);
- atm_cm_stat.cms_llcid++;
- return;
- }
-
- /*
- * Strip off the LLC header
- */
- KB_HEADADJ(m, -cop->co_llc.v.llc_len);
- KB_PLENADJ(m, -cop->co_llc.v.llc_len);
- break;
-
- default:
- panic("atm_cm_cpcs_upper: mpx");
- }
-
- /*
- * We've found our connection, so hand the packet off
- */
- if (cop->co_state != COS_ACTIVE) {
- KB_FREEALL(m);
- atm_cm_stat.cms_rcvconn++;
- return;
- }
- (*cop->co_endpt->ep_cpcs_data)(cop->co_toku, m);
- break;
-
- case CPCS_UABORT_SIG:
- case CPCS_PABORT_SIG:
- /*
- * We don't support these (yet), so just FALLTHROUGH
- */
-
- default:
- log(LOG_ERR, "atm_cm_cpcs_upper: unknown cmd 0x%x\n", cmd);
- }
-}
-
-
-/*
- * SAAL User Control Commands
- *
- * This function is called by an endpoint user to pass a control command
- * across a SAAL data API. Mostly we just send these down the stack.
- *
- * Arguments:
- * cmd stack command code
- * cop pointer to connection block
- * arg argument
- *
- * Returns:
- * 0 command output successful
- * errno output failed - reason indicated
- *
- */
-int
-atm_cm_saal_ctl(cmd, cop, arg)
- int cmd;
- Atm_connection *cop;
- void *arg;
-{
- Atm_connvc *cvp;
- int err = 0;
-
- /*
- * Validate connection state
- */
- if (cop->co_state != COS_ACTIVE) {
- err = EFAULT;
- goto done;
- }
-
- cvp = cop->co_connvc;
- if (cvp->cvc_state != CVCS_ACTIVE) {
- err = EFAULT;
- goto done;
- }
-
- if (cvp->cvc_attr.api != CMAPI_SAAL) {
- err = EFAULT;
- goto done;
- }
-
- switch (cmd) {
-
- case SSCF_UNI_ESTABLISH_REQ:
- case SSCF_UNI_RELEASE_REQ:
- /*
- * Pass command down the stack
- */
- STACK_CALL(cmd, cvp->cvc_lower, cvp->cvc_tokl, cvp,
- (intptr_t)arg, 0, err);
- break;
-
- default:
- err = EINVAL;
- }
-
-done:
- return (err);
-}
-
-
-/*
- * SAAL Data Output
- *
- * This function is called by an endpoint user to output a data packet
- * across a SAAL data API. After we've validated the connection state,
- * the packet will be sent down the data stack.
- *
- * Arguments:
- * cop pointer to connection block
- * m pointer to packet buffer chain to be output
- *
- * Returns:
- * 0 packet output successful
- * errno output failed - reason indicated
- *
- */
-int
-atm_cm_saal_data(cop, m)
- Atm_connection *cop;
- KBuffer *m;
-{
- Atm_connvc *cvp;
- int err;
-
-
- /*
- * Validate connection state
- */
- if (cop->co_state != COS_ACTIVE) {
- err = EFAULT;
- goto done;
- }
-
- cvp = cop->co_connvc;
- if (cvp->cvc_state != CVCS_ACTIVE) {
- err = EFAULT;
- goto done;
- }
-
- if (cvp->cvc_attr.api != CMAPI_SAAL) {
- err = EFAULT;
- goto done;
- }
-
- /*
- * Finally, we can send the packet on its way
- */
- STACK_CALL(SSCF_UNI_DATA_REQ, cvp->cvc_lower, cvp->cvc_tokl,
- cvp, (intptr_t)m, 0, err);
-
-done:
- return (err);
-}
-
-
-/*
- * Process SAAL Stack Commands
- *
- * This is the top of the SAAL API data stack. All upward stack commands
- * for the SAAL data API will be received and processed here.
- *
- * Arguments:
- * cmd stack command code
- * tok session token (pointer to connection VCC control block)
- * arg1 argument 1
- * arg2 argument 2
- *
- * Returns:
- * none
- *
- */
-static void
-atm_cm_saal_upper(cmd, tok, arg1, arg2)
- int cmd;
- void *tok;
- intptr_t arg1;
- intptr_t arg2;
-{
- Atm_connection *cop;
- Atm_connvc *cvp = tok;
-
-
- switch (cmd) {
-
- case SSCF_UNI_ESTABLISH_IND:
- case SSCF_UNI_ESTABLISH_CNF:
- case SSCF_UNI_RELEASE_IND:
- case SSCF_UNI_RELEASE_CNF:
- /*
- * Control commands
- */
- cop = cvp->cvc_conn;
- if (cvp->cvc_state != CVCS_ACTIVE)
- break;
- if (cop->co_state != COS_ACTIVE)
- break;
-
- (*cop->co_endpt->ep_saal_ctl)(cmd, cop->co_toku, (void *)arg1);
- break;
-
- case SSCF_UNI_DATA_IND:
- /*
- * User data
- */
- cop = cvp->cvc_conn;
- if (cvp->cvc_state != CVCS_ACTIVE) {
- atm_cm_stat.cms_rcvconnvc++;
- KB_FREEALL((KBuffer *)arg1);
- break;
- }
- if (cop->co_state != COS_ACTIVE) {
- atm_cm_stat.cms_rcvconn++;
- KB_FREEALL((KBuffer *)arg1);
- break;
- }
-
- (*cop->co_endpt->ep_saal_data)(cop->co_toku, (KBuffer *)arg1);
- break;
-
- case SSCF_UNI_UNITDATA_IND:
- /*
- * Not supported
- */
- KB_FREEALL((KBuffer *)arg1);
-
- /* FALLTHRU */
-
- default:
- log(LOG_ERR, "atm_cm_saal_upper: unknown cmd 0x%x\n", cmd);
- }
-}
-
-
-/*
- * SSCOP User Control Commands
- *
- * This function is called by an endpoint user to pass a control command
- * across a SSCOP data API. Mostly we just send these down the stack.
- *
- * Arguments:
- * cmd stack command code
- * cop pointer to connection block
- * arg1 argument
- * arg2 argument
- *
- * Returns:
- * 0 command output successful
- * errno output failed - reason indicated
- *
- */
-int
-atm_cm_sscop_ctl(cmd, cop, arg1, arg2)
- int cmd;
- Atm_connection *cop;
- void *arg1;
- void *arg2;
-{
- Atm_connvc *cvp;
- int err = 0;
-
- /*
- * Validate connection state
- */
- if (cop->co_state != COS_ACTIVE) {
- err = EFAULT;
- goto done;
- }
-
- cvp = cop->co_connvc;
- if (cvp->cvc_state != CVCS_ACTIVE) {
- err = EFAULT;
- goto done;
- }
-
- if (cvp->cvc_attr.api != CMAPI_SSCOP) {
- err = EFAULT;
- goto done;
- }
-
- switch (cmd) {
-
- case SSCOP_ESTABLISH_REQ:
- case SSCOP_ESTABLISH_RSP:
- case SSCOP_RELEASE_REQ:
- case SSCOP_RESYNC_REQ:
- case SSCOP_RESYNC_RSP:
- case SSCOP_RECOVER_RSP:
- case SSCOP_RETRIEVE_REQ:
- /*
- * Pass command down the stack
- */
- STACK_CALL(cmd, cvp->cvc_lower, cvp->cvc_tokl, cvp,
- (intptr_t)arg1, (intptr_t)arg2, err);
- break;
-
- default:
- err = EINVAL;
- }
-
-done:
- return (err);
-}
-
-
-/*
- * SSCOP Data Output
- *
- * This function is called by an endpoint user to output a data packet
- * across a SSCOP data API. After we've validated the connection state,
- * the packet will be encapsulated and sent down the data stack.
- *
- * Arguments:
- * cop pointer to connection block
- * m pointer to packet buffer chain to be output
- *
- * Returns:
- * 0 packet output successful
- * errno output failed - reason indicated
- *
- */
-int
-atm_cm_sscop_data(cop, m)
- Atm_connection *cop;
- KBuffer *m;
-{
- Atm_connvc *cvp;
- int err;
-
-
- /*
- * Validate connection state
- */
- if (cop->co_state != COS_ACTIVE) {
- err = EFAULT;
- goto done;
- }
-
- cvp = cop->co_connvc;
- if (cvp->cvc_state != CVCS_ACTIVE) {
- err = EFAULT;
- goto done;
- }
-
- if (cvp->cvc_attr.api != CMAPI_SSCOP) {
- err = EFAULT;
- goto done;
- }
-
- /*
- * Finally, we can send the packet on its way
- */
- STACK_CALL(SSCOP_DATA_REQ, cvp->cvc_lower, cvp->cvc_tokl,
- cvp, (intptr_t)m, 0, err);
-
-done:
- return (err);
-}
-
-
-/*
- * Process SSCOP Stack Commands
- *
- * This is the top of the SSCOP API data stack. All upward stack commands
- * for the SSCOP data API will be received and processed here.
- *
- * Arguments:
- * cmd stack command code
- * tok session token (pointer to connection VCC control block)
- * arg1 argument 1
- * arg2 argument 2
- *
- * Returns:
- * none
- *
- */
-static void
-atm_cm_sscop_upper(cmd, tok, arg1, arg2)
- int cmd;
- void *tok;
- intptr_t arg1;
- intptr_t arg2;
-{
- Atm_connection *cop;
- Atm_connvc *cvp = tok;
-
- switch (cmd) {
-
- case SSCOP_ESTABLISH_IND:
- case SSCOP_ESTABLISH_CNF:
- case SSCOP_RELEASE_IND:
- case SSCOP_RESYNC_IND:
- /*
- * Control commands
- */
- cop = cvp->cvc_conn;
- if ((cvp->cvc_state != CVCS_ACTIVE) ||
- (cop->co_state != COS_ACTIVE)) {
- KB_FREEALL((KBuffer *)arg1);
- break;
- }
-
- (*cop->co_endpt->ep_sscop_ctl)
- (cmd, cop->co_toku, (void *)arg1, (void *)arg2);
- break;
-
- case SSCOP_RELEASE_CNF:
- case SSCOP_RESYNC_CNF:
- case SSCOP_RECOVER_IND:
- case SSCOP_RETRIEVE_IND:
- case SSCOP_RETRIEVECMP_IND:
- /*
- * Control commands
- */
- cop = cvp->cvc_conn;
- if ((cvp->cvc_state != CVCS_ACTIVE) ||
- (cop->co_state != COS_ACTIVE))
- break;
-
- (*cop->co_endpt->ep_sscop_ctl)
- (cmd, cop->co_toku, (void *)arg1, (void *)arg2);
- break;
-
- case SSCOP_DATA_IND:
- /*
- * User data
- */
- cop = cvp->cvc_conn;
- if (cvp->cvc_state != CVCS_ACTIVE) {
- atm_cm_stat.cms_rcvconnvc++;
- KB_FREEALL((KBuffer *)arg1);
- break;
- }
- if (cop->co_state != COS_ACTIVE) {
- atm_cm_stat.cms_rcvconn++;
- KB_FREEALL((KBuffer *)arg1);
- break;
- }
-
- (*cop->co_endpt->ep_sscop_data)
- (cop->co_toku, (KBuffer *)arg1, arg2);
- break;
-
- case SSCOP_UNITDATA_IND:
- /*
- * Not supported
- */
- KB_FREEALL((KBuffer *)arg1);
-
- /* FALLTHRU */
-
- default:
- log(LOG_ERR, "atm_cm_sscop_upper: unknown cmd 0x%x\n", cmd);
- }
-}
-
-
-/*
- * Register an ATM Endpoint Service
- *
- * Every ATM endpoint service must register itself here before it can
- * issue or receive any connection requests.
- *
- * Arguments:
- * epp pointer to endpoint definition structure
- *
- * Returns:
- * 0 registration successful
- * errno registration failed - reason indicated
- *
- */
-int
-atm_endpoint_register(epp)
- Atm_endpoint *epp;
-{
- int s = splnet();
-
- /*
- * See if we need to be initialized
- */
- if (!atm_init)
- atm_initialize();
-
- /*
- * Validate endpoint
- */
- if (epp->ep_id > ENDPT_MAX) {
- (void) splx(s);
- return (EINVAL);
- }
- if (atm_endpoints[epp->ep_id] != NULL) {
- (void) splx(s);
- return (EEXIST);
- }
-
- /*
- * Add endpoint to list
- */
- atm_endpoints[epp->ep_id] = epp;
-
- (void) splx(s);
- return (0);
-}
-
-
-/*
- * De-register an ATM Endpoint Service
- *
- * Each ATM endpoint service provider must de-register its registered
- * endpoint(s) before terminating. Specifically, loaded kernel modules
- * must de-register their services before unloading themselves.
- *
- * Arguments:
- * epp pointer to endpoint definition structure
- *
- * Returns:
- * 0 de-registration successful
- * errno de-registration failed - reason indicated
- *
- */
-int
-atm_endpoint_deregister(epp)
- Atm_endpoint *epp;
-{
- int s = splnet();
-
- /*
- * Validate endpoint
- */
- if (epp->ep_id > ENDPT_MAX) {
- (void) splx(s);
- return (EINVAL);
- }
- if (atm_endpoints[epp->ep_id] != epp) {
- (void) splx(s);
- return (ENOENT);
- }
-
- /*
- * Remove endpoint from list
- */
- atm_endpoints[epp->ep_id] = NULL;
-
- (void) splx(s);
- return (0);
-}
-
OpenPOWER on IntegriCloud