aboutsummaryrefslogtreecommitdiff
path: root/sys/netatm/spans/spans_subr.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netatm/spans/spans_subr.c')
-rw-r--r--sys/netatm/spans/spans_subr.c494
1 files changed, 494 insertions, 0 deletions
diff --git a/sys/netatm/spans/spans_subr.c b/sys/netatm/spans/spans_subr.c
new file mode 100644
index 000000000000..48b97059419e
--- /dev/null
+++ b/sys/netatm/spans/spans_subr.c
@@ -0,0 +1,494 @@
+/*
+ *
+ * ===================================
+ * 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.
+ *
+ * @(#) $Id: spans_subr.c,v 1.9 1998/08/26 23:29:10 mks Exp $
+ *
+ */
+
+/*
+ * SPANS Signalling Manager
+ * ---------------------------
+ *
+ * SPANS-related subroutines.
+ *
+ */
+
+#ifndef lint
+static char *RCSid = "@(#) $Id: spans_subr.c,v 1.9 1998/08/26 23:29:10 mks Exp $";
+#endif
+
+#include <netatm/kern_include.h>
+
+#include "spans_xdr.h"
+#include <netatm/spans/spans_var.h>
+
+
+/*
+ * Open a SPANS VCC
+ *
+ * Called when a user wants to open a VC. This function will construct
+ * a VCCB, create the stack requested by the user, and, if we are
+ * opening an SVC, start the SPANS signalling message exchange. The
+ * user will have to wait for a notify event to be sure the SVC is fully
+ * open.
+ *
+ * Must be called at splnet.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance
+ * acp pointer to PVC's connection parameters
+ *
+ * Returns:
+ * 0 VCC creation successful
+ * errno VCC setup failed - reason indicated
+ *
+ */
+int
+spans_open_vcc(spp, cvp)
+ struct spans *spp;
+ Atm_connvc *cvp;
+
+{
+ struct atm_pif *pip = spp->sp_pif;
+ struct spans_vccb *svp;
+ Atm_addr_pvc *pvp;
+ spans_aal aal;
+ int err, pvc, vpi, vci;
+
+ ATM_DEBUG2("spans_open_vcc: spp=0x%x, cvp=0x%x\n", spp, cvp);
+
+ /*
+ * Validate user parameters. AAL and encapsulation are
+ * checked by the connection manager.
+ */
+
+ /*
+ * Check called party address(es)
+ */
+ if (cvp->cvc_attr.called.tag != T_ATM_PRESENT ||
+ cvp->cvc_attr.called.addr.address_format ==
+ T_ATM_ABSENT ||
+ cvp->cvc_attr.called.subaddr.address_format !=
+ T_ATM_ABSENT) {
+ return(EINVAL);
+ }
+ switch (cvp->cvc_attr.called.addr.address_format) {
+ case T_ATM_PVC_ADDR:
+ /*
+ * Make sure VPI/VCI is valid
+ */
+ pvc = 1;
+ pvp = (Atm_addr_pvc *)cvp->cvc_attr.called.addr.address;
+ vpi = ATM_PVC_GET_VPI(pvp);
+ vci = ATM_PVC_GET_VCI(pvp);
+ if ((vpi > pip->pif_maxvpi) ||
+ (vci == 0) ||
+ (vci > pip->pif_maxvci)) {
+ return(ERANGE);
+ }
+
+ /*
+ * Make sure VPI/VCI is not already in use
+ */
+ if (spans_find_vpvc(spp, vpi, vci, 0)) {
+ return(EADDRINUSE);
+ }
+ ATM_DEBUG2("spans_open_vcc: VPI.VCI=%d.%d\n",
+ vpi, vci);
+ break;
+
+ case T_ATM_SPANS_ADDR:
+ pvc = 0;
+ vpi = vci = 0;
+
+ /*
+ * Check signalling state
+ */
+ if (spp->sp_state != SPANS_ACTIVE) {
+ return(ENETDOWN);
+ }
+
+ /*
+ *Check destination address length
+ */
+ if (cvp->cvc_attr.called.addr.address_length !=
+ sizeof(spans_addr)) {
+ return(EINVAL);
+ }
+ break;
+
+ default:
+ return(EINVAL);
+ }
+
+ /*
+ * Check that this is for the same interface SPANS uses
+ */
+ if (!cvp->cvc_attr.nif ||
+ cvp->cvc_attr.nif->nif_pif != spp->sp_pif) {
+ return(EINVAL);
+ }
+
+ /*
+ * Check AAL
+ */
+ if (!spans_get_spans_aal(cvp->cvc_attr.aal.type, &aal)) {
+ return(EINVAL);
+ }
+
+#ifdef NOTDEF
+ /*
+ * Check encapsulation
+ */
+ /* XXX -- How do we check encapsulation? */
+ if (cvp->ac_encaps != ATM_ENC_NULL) {
+ return(EINVAL);
+ }
+#endif
+
+ /*
+ * Allocate control block for VCC
+ */
+ svp = (struct spans_vccb *)atm_allocate(&spans_vcpool);
+ if (svp == NULL) {
+ return(ENOMEM);
+ }
+
+ /*
+ * Fill in VCCB
+ */
+ if (pvc) {
+ svp->sv_type = VCC_PVC | VCC_IN | VCC_OUT;
+ svp->sv_vpi = vpi;
+ svp->sv_vci = vci;
+ svp->sv_sstate = (spp->sp_state == SPANS_ACTIVE ?
+ SPANS_VC_ACTIVE : SPANS_VC_ACT_DOWN);
+ svp->sv_ustate = VCCU_OPEN;
+ } else {
+ svp->sv_type = VCC_SVC | VCC_OUT;
+ spans_addr_copy(cvp->cvc_attr.called.addr.address,
+ &svp->sv_conn.con_dst);
+ spans_addr_copy(spp->sp_addr.address,
+ &svp->sv_conn.con_src);
+ svp->sv_conn.con_dsap = SPANS_SAP_IP;
+ svp->sv_conn.con_ssap = spans_ephemeral_sap(spp);
+ svp->sv_sstate = SPANS_VC_POPEN;
+ svp->sv_ustate = VCCU_POPEN;
+ }
+ svp->sv_proto = ATM_SIG_SPANS;
+ svp->sv_pif = spp->sp_pif;
+ svp->sv_nif = cvp->cvc_attr.nif;
+ svp->sv_connvc = cvp;
+ svp->sv_spans_aal = aal;
+ svp->sv_tstamp = time_second;
+
+ /*
+ * Put VCCB on SPANS queue
+ */
+ ENQUEUE(svp, struct spans_vccb, sv_sigelem, spp->sp_vccq);
+
+ /*
+ * Link VCCB to VCC connection block
+ */
+ cvp->cvc_vcc = (struct vccb *) svp;
+
+ /*
+ * Start the SPANS message exchange if this is an SVC
+ */
+ if (!pvc) {
+ svp->sv_retry = 0;
+ svp->sv_spans_qos.rsc_peak = 1;
+ svp->sv_spans_qos.rsc_mean = 1;
+ svp->sv_spans_qos.rsc_burst = 1;
+ err = spans_send_open_req(spp, svp);
+ if (err) {
+ /*
+ * On error, delete the VCCB
+ */
+ DEQUEUE(svp, struct spans_vccb, sv_sigelem,
+ spp->sp_vccq);
+ cvp->cvc_vcc = (struct vccb *)0;
+ atm_free((caddr_t)svp);
+ return(err);
+ } else {
+ /*
+ * VCCB is opening--set the retransmit timer
+ */
+ SPANS_VC_TIMER((struct vccb *) svp, SV_TIMEOUT);
+ }
+ }
+
+ return(0);
+}
+
+
+/*
+ * Close a SPANS VCC
+ *
+ * Called when a user wants to close a VCC. This function will clean
+ * up the VCCB and, for an SVC, send a close request.
+ *
+ * Must be called at splnet.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance
+ * svp pointer to VCCB for the VCC to be closed
+ *
+ * Returns:
+ * 0 VCC is now closed
+ * errno error encountered
+ */
+int
+spans_close_vcc(spp, svp, force)
+ struct spans *spp;
+ struct spans_vccb *svp;
+ int force;
+
+{
+ int err = 0;
+
+ ATM_DEBUG2("spans_close_vcc: svp=0x%x, state=%d\n", svp,
+ svp->sv_sstate);
+
+ /*
+ * Check that this is for the same interface SPANS uses
+ */
+ if (svp->sv_pif != spp->sp_pif) {
+ return (EINVAL);
+ }
+
+ /*
+ * Kill any possible timer
+ */
+ SPANS_VC_CANCEL((struct vccb *) svp);
+
+ /*
+ * Mark the close time.
+ */
+ svp->sv_tstamp = time_second;
+
+ /*
+ * Process based on the connection type
+ */
+ if (svp->sv_type & VCC_PVC) {
+ svp->sv_sstate = SPANS_VC_FREE;
+ svp->sv_ustate = VCCU_CLOSED;
+ } else if (svp->sv_type & VCC_SVC) {
+ /*
+ * Update VCCB states
+ */
+ svp->sv_ustate = VCCU_CLOSED;
+
+ /*
+ * Send the appropriate SPANS close message
+ */
+ switch (svp->sv_sstate) {
+ case SPANS_VC_R_POPEN:
+ err = spans_send_open_rsp(spp, svp, SPANS_FAIL);
+ svp->sv_sstate = SPANS_VC_FREE;
+ break;
+ case SPANS_VC_OPEN:
+ case SPANS_VC_POPEN:
+ case SPANS_VC_ABORT:
+ svp->sv_retry = 0;
+ err = spans_send_close_req(spp, svp);
+ if (force) {
+ svp->sv_sstate = SPANS_VC_FREE;
+ } else {
+ svp->sv_sstate = SPANS_VC_CLOSE;
+ SPANS_VC_TIMER((struct vccb *) svp,
+ SV_TIMEOUT);
+ }
+ break;
+ case SPANS_VC_CLOSE:
+ if (force) {
+ svp->sv_sstate = SPANS_VC_FREE;
+ }
+ break;
+ }
+ }
+
+ /*
+ * Wait for user to free resources
+ */
+ return(err);
+}
+
+
+/*
+ * Clear a SPANS VCC
+ *
+ * Called when the signalling manager wants to close a VCC immediately.
+ * This function will clean up the VCCB and notify the owner.
+ *
+ * Must be called at splnet.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance
+ * svp pointer to VCCB for the VCC to be closed
+ *
+ * Returns:
+ * 0 VCC is now closed
+ * errno error encountered
+ */
+int
+spans_clear_vcc(spp, svp)
+ struct spans *spp;
+ struct spans_vccb *svp;
+
+{
+ u_char outstate;
+
+ ATM_DEBUG2("spans_clear_vcc: svp=0x%x, state=%d\n", svp,
+ svp->sv_sstate);
+
+ /*
+ * Check that this is for the same interface SPANS uses
+ */
+ if (svp->sv_pif != spp->sp_pif) {
+ return (EINVAL);
+ }
+
+ /*
+ * Kill any possible timer
+ */
+ SPANS_VC_CANCEL((struct vccb *) svp);
+
+ /*
+ * Mark the close time
+ */
+ svp->sv_tstamp = time_second;
+
+ /*
+ * Mark the VCCB closed
+ */
+ outstate = svp->sv_sstate;
+ svp->sv_sstate = SPANS_VC_FREE;
+ svp->sv_ustate = VCCU_CLOSED;
+
+ /*
+ * Notify the user if old state indicates.
+ */
+ switch (outstate) {
+ case SPANS_VC_ACTIVE:
+ case SPANS_VC_ACT_DOWN:
+ case SPANS_VC_POPEN:
+ case SPANS_VC_OPEN:
+ case SPANS_VC_CLOSE:
+ case SPANS_VC_ABORT:
+ /* XXX -- set cause */
+ atm_cm_cleared(svp->sv_connvc);
+ break;
+ case SPANS_VC_NULL:
+ case SPANS_VC_R_POPEN:
+ case SPANS_VC_FREE:
+ break;
+ }
+
+ /*
+ * Wait for user to free resources
+ */
+ return(0);
+}
+
+
+/*
+ * Reset the switch state
+ *
+ * Called when the switch or host at the far end of the ATM link has
+ * gone away. This can be deteched either by a number of SPANS_STAT_REQ
+ * messages going unanswered or by the host epoch changing in a SPANS
+ * SPANS_STAT_IND or SPANS_STAT_REQ message.
+ *
+ * Arguments:
+ * spp pointer to SPANS protocol instance
+ *
+ * Returns:
+ * none
+ *
+ */
+void
+spans_switch_reset(spp, cause)
+ struct spans *spp;
+ int cause;
+
+{
+ int s;
+ struct vccb *vcp, *vnext;
+
+ ATM_DEBUG2("spans_switch_reset: spp=0x%x, cause=%d\n",
+ spp, cause);
+
+ /*
+ * Log the event
+ */
+ log(LOG_INFO, "spans: signalling %s on interface %s%d\n",
+ (cause == SPANS_UNI_DOWN ? "down" : "up"),
+ spp->sp_pif->pif_name,
+ spp->sp_pif->pif_unit);
+
+ /*
+ * Terminate all of our VCCs
+ */
+ s = splnet();
+ for (vcp = Q_HEAD(spp->sp_vccq, struct vccb); vcp;
+ vcp = vnext) {
+
+ u_char outstate;
+
+ vnext = Q_NEXT(vcp, struct vccb, vc_sigelem);
+
+ if (vcp->vc_type & VCC_SVC) {
+ /*
+ * Close the SVC and notify the owner
+ */
+ outstate = vcp->vc_sstate;
+ SPANS_VC_CANCEL((struct vccb *) vcp);
+ vcp->vc_ustate = VCCU_CLOSED;
+ vcp->vc_sstate = SPANS_VC_FREE;
+ if (outstate == SPANS_VC_OPEN ||
+ outstate == SPANS_VC_POPEN) {
+ /* XXX -- set cause */
+ atm_cm_cleared(vcp->vc_connvc);
+ }
+ } else if (vcp->vc_type & VCC_PVC) {
+ /*
+ * Note new state
+ */
+ switch(cause) {
+ case SPANS_UNI_DOWN:
+ vcp->vc_sstate = SPANS_VC_ACT_DOWN;
+ break;
+ case SPANS_UNI_UP:
+ vcp->vc_sstate = SPANS_VC_ACTIVE;
+ break;
+ }
+ } else {
+ log(LOG_ERR, "spans: invalid VCC type: vccb=0x%x, type=%d\n",
+ vcp, vcp->vc_type);
+ }
+ }
+ (void) splx(s);
+}