diff options
Diffstat (limited to 'sys/netatm/spans/spans_subr.c')
-rw-r--r-- | sys/netatm/spans/spans_subr.c | 494 |
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); +} |