diff options
Diffstat (limited to 'sys/netatm/spans/spans_proto.c')
-rw-r--r-- | sys/netatm/spans/spans_proto.c | 558 |
1 files changed, 558 insertions, 0 deletions
diff --git a/sys/netatm/spans/spans_proto.c b/sys/netatm/spans/spans_proto.c new file mode 100644 index 0000000..e298ed8 --- /dev/null +++ b/sys/netatm/spans/spans_proto.c @@ -0,0 +1,558 @@ +/* + * + * =================================== + * 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_proto.c,v 1.7 1998/08/26 23:29:10 mks Exp $ + * + */ + +/* + * SPANS Signalling Manager + * --------------------------- + * + * SPANS protocol processing module. + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: spans_proto.c,v 1.7 1998/08/26 23:29:10 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include "spans_xdr.h" +#include <netatm/spans/spans_var.h> + +/* + * Internal functions + */ +caddr_t spans_getname __P((void *)); +void spans_connected __P((void *)); +void spans_cleared __P((void *, struct t_atm_cause *)); +void spans_cpcs_data __P((void *, KBuffer *)); + + +/* + * ATM endpoint for SPANS signalling channel + */ +static Atm_endpoint spans_endpt = { + NULL, /* ep_next */ + ENDPT_SPANS_SIG, /* ep_id */ + NULL, /* ep_ioctl */ + spans_getname, /* ep_getname */ + spans_connected, /* ep_connected */ + spans_cleared, /* ep_cleared */ + NULL, /* ep_incoming */ + NULL, /* ep_addparty */ + NULL, /* ep_dropparty */ + NULL, /* ep_cpcs_ctl */ + spans_cpcs_data, /* ep_cpcs_data */ + NULL, /* ep_saal_ctl */ + NULL, /* ep_saal_data */ + NULL, /* ep_sscop_ctl */ + NULL /* ep_sscop_data */ +}; + + +/* + * ATM connection attributes for UNI signalling channel + */ +static Atm_attributes spans_attr = { + NULL, /* nif */ + CMAPI_CPCS, /* api */ + 0, /* api_init */ + 0, /* headin */ + 0, /* headout */ + { /* aal */ + T_ATM_PRESENT, /* aal.tag */ + ATM_AAL3_4 /* aal.aal_type */ + }, + { /* traffic */ + T_ATM_PRESENT, /* traffic.tag */ + { /* traffic.v */ + { /* traffic.v.forward */ + T_ATM_ABSENT, /* PCR_high */ + 0, /* PCR_all */ + T_ATM_ABSENT, /* SCR_high */ + T_ATM_ABSENT, /* SCR_all */ + T_ATM_ABSENT, /* MBS_high */ + T_ATM_ABSENT, /* MBS_all */ + T_NO, /* tagging */ + }, + { /* traffic.v.backward */ + T_ATM_ABSENT, /* PCR_high */ + 0, /* PCR_all */ + T_ATM_ABSENT, /* SCR_high */ + T_ATM_ABSENT, /* SCR_all */ + T_ATM_ABSENT, /* MBS_high */ + T_ATM_ABSENT, /* MBS_all */ + T_NO, /* tagging */ + }, + T_YES, /* best_effort */ + } + }, + { /* bearer */ + T_ATM_PRESENT, /* bearer.tag */ + { /* bearer.v */ + T_ATM_CLASS_X, /* class */ + T_ATM_NULL, /* traffic_type */ + T_ATM_NO_END_TO_END, /* timing_req */ + T_NO, /* clipping */ + T_ATM_1_TO_1, /* conn_conf */ + } + }, + { /* bhli */ + T_ATM_ABSENT, /* bhli.tag */ + }, + { /* blli */ + T_ATM_ABSENT, /* blli.tag_l2 */ + T_ATM_ABSENT, /* blli.tag_l3 */ + }, + { /* llc */ + T_ATM_ABSENT, /* llc.tag */ + }, + { /* called */ + T_ATM_PRESENT, /* called.tag */ + }, + { /* calling */ + T_ATM_ABSENT, /* calling.tag */ + }, + { /* qos */ + T_ATM_PRESENT, /* qos.tag */ + { /* qos.v */ + T_ATM_NETWORK_CODING, /* coding_standard */ + { /* qos.v.forward */ + T_ATM_QOS_CLASS_0, /* class */ + }, + { /* qos.v.backward */ + T_ATM_QOS_CLASS_0, /* class */ + } + } + }, + { /* transit */ + T_ATM_ABSENT, /* transit.tag */ + }, + { /* cause */ + T_ATM_ABSENT, /* cause.tag */ + } +}; + + +/* + * SPANS cause structre + */ +struct t_atm_cause spans_cause = { + T_ATM_ITU_CODING, /* coding_standard */ + T_ATM_LOC_USER, /* location */ + T_ATM_CAUSE_UNSPECIFIED_NORMAL, /* cause_value */ + { 0, 0, 0, 0 } /* diagnostics */ +}; + + +/* + * Process a SPANS timeout + * + * Called when a previously scheduled spans control block timer expires. + * Processing will based on the current SPANS state. + * + * Called at splnet. + * + * Arguments: + * tip pointer to spans timer control block + * + * Returns: + * none + * + */ +void +spans_timer(tip) + struct atm_time *tip; +{ + struct spans *spp; + spans_msg *msg; + Atm_addr_pvc *pvcp; + int err; + + /* + * Back-off to SPANS control block + */ + spp = (struct spans *) + ((caddr_t)tip - (int)(&((struct spans *)0)->sp_time)); + + ATM_DEBUG2("spans_timer: spp=0x%x,state=%d\n", + (int)spp, spp->sp_state); + + /* + * Process timeout based on protocol state + */ + switch (spp->sp_state) { + + case SPANS_INIT: + + /* + * Open signalling channel + */ + spans_attr.nif = spp->sp_pif->pif_nif; + + spans_attr.aal.v.aal4.forward_max_SDU_size = + ATM_NIF_MTU; + spans_attr.aal.v.aal4.backward_max_SDU_size = + ATM_NIF_MTU; + spans_attr.aal.v.aal4.SSCS_type = + T_ATM_SSCS_SSCOP_UNREL; + spans_attr.aal.v.aal4.mid_low = 0; + spans_attr.aal.v.aal4.mid_high = 0; + + spans_attr.called.tag = T_ATM_PRESENT; + spans_attr.called.addr.address_format = T_ATM_PVC_ADDR; + spans_attr.called.addr.address_length = + sizeof(Atm_addr_pvc); + pvcp = (Atm_addr_pvc *)spans_attr.called.addr.address; + ATM_PVC_SET_VPI(pvcp, SPANS_SIG_VPI); + ATM_PVC_SET_VCI(pvcp, SPANS_SIG_VCI); + spans_attr.called.subaddr.address_format = T_ATM_ABSENT; + spans_attr.called.subaddr.address_length = 0; + + spans_attr.traffic.v.forward.PCR_all_traffic = + spp->sp_pif->pif_pcr; + spans_attr.traffic.v.backward.PCR_all_traffic = + spp->sp_pif->pif_pcr; + + err = atm_cm_connect(&spans_endpt, spp, &spans_attr, + &spp->sp_conn); + if (err) { + log(LOG_CRIT, "spans: signalling channel setup failed\n"); + return; + } + + /* + * Signalling channel open, start probing + */ + spp->sp_state = SPANS_PROBE; + + /* FALLTHRU */ + + case SPANS_PROBE: + case SPANS_ACTIVE: + + /* + * Send out SPANS_STAT_REQ message + */ + msg = (spans_msg *)atm_allocate(&spans_msgpool); + if (msg == NULL) { + /* Retry later if no memory */ + SPANS_TIMER(spp, SPANS_PROBE_ERR_WAIT); + break; + } + msg->sm_vers = SPANS_VERS_1_0; + msg->sm_type = SPANS_STAT_REQ; + msg->sm_stat_req.streq_es_epoch = spp->sp_h_epoch; + if (spans_send_msg(spp, msg)) { + /* Retry later if send fails */ + SPANS_TIMER(spp, SPANS_PROBE_ERR_WAIT); + atm_free(msg); + break; + } + atm_free(msg); + spp->sp_probe_ct++; + + /* + * Check whether we're getting an answer to our probes + */ + if (spp->sp_state == SPANS_ACTIVE && + spp->sp_probe_ct > SPANS_PROBE_THRESH) { + /* + * Interface is down, notify VCC owners + */ + spans_switch_reset(spp, SPANS_UNI_DOWN); + + /* + * Set new state and increment host epoch so + * switch knows we reset everyting. + */ + spp->sp_state = SPANS_PROBE; + spp->sp_h_epoch++; + spp->sp_s_epoch = 0; + } + + /* + * Keep sending status requests + */ + SPANS_TIMER(spp, SPANS_PROBE_INTERVAL); + + break; + + case SPANS_DETACH: + /* + * Try to terminate the SPANS signalling PVC + */ + err = atm_cm_release(spp->sp_conn, &spans_cause); + if (err) { + log(LOG_ERR, "spans: can't close signalling channel\n"); + } + break; + + default: + log(LOG_ERR, "spans: timer state: spp=0x%x, state=%d\n", + (int)spp, spp->sp_state); + } +} + + +/* + * Process a SPANS VCC timeout + * + * Called when a previously scheduled SPANS VCCB timer expires. + * Processing will based on the current VCC state. + * + * Called at splnet. + * + * Arguments: + * tip pointer to vccb timer control block + * + * Returns: + * none + * + */ +void +spans_vctimer(tip) + struct atm_time *tip; +{ + int err; + struct spans *spp; + struct spans_vccb *svp; + + /* + * Get VCCB and SPANS control block addresses + */ + svp = (struct spans_vccb *) ((caddr_t)tip - + (int)(&((struct vccb *)0)->vc_time)); + spp = (struct spans *)svp->sv_pif->pif_siginst; + + ATM_DEBUG3("spans_vctimer: svp=0x%x, sstate=%d, ustate=%d\n", + (int)svp, svp->sv_sstate, svp->sv_ustate); + + /* + * Process timeout based on protocol state + */ + switch (svp->sv_sstate) { + + case SPANS_VC_ABORT: + /* + * Kill the VCCB and notify the owner + */ + err = spans_clear_vcc(spp, svp); + break; + + case SPANS_VC_FREE: + /* + * Free VCCB storage + */ + svp->sv_ustate = VCCU_CLOSED; + svp->sv_sstate = SPANS_VC_FREE; + spans_free((struct vccb *)svp); + break; + + case SPANS_VC_POPEN: + /* + * Issued open request, but didn't get response. + */ + if (svp->sv_retry < SV_MAX_RETRY) { + /* + * Retransmit the open request + */ + err = spans_send_open_req(spp, svp); + svp->sv_retry++; + SPANS_VC_TIMER((struct vccb *) svp, SV_TIMEOUT); + } else { + /* + * Retry limit exceeded--report the open failed + */ + svp->sv_ustate = VCCU_CLOSED; + svp->sv_sstate = SPANS_VC_FREE; + svp->sv_connvc->cvc_attr.cause.tag = + T_ATM_PRESENT; + svp->sv_connvc->cvc_attr.cause.v.coding_standard = + T_ATM_ITU_CODING; + svp->sv_connvc->cvc_attr.cause.v.location = + T_ATM_LOC_USER; + svp->sv_connvc->cvc_attr.cause.v.cause_value = + T_ATM_CAUSE_NO_USER_RESPONDING; + KM_ZERO(svp->sv_connvc->cvc_attr.cause.v.diagnostics, + sizeof(svp->sv_connvc->cvc_attr.cause.v.diagnostics)); + atm_cm_cleared(svp->sv_connvc); + } + break; + + case SPANS_VC_CLOSE: + /* + * Issued close request, but didn't get response. + */ + if (svp->sv_retry < SV_MAX_RETRY) { + /* + * Retransmit the close request + */ + err = spans_send_close_req(spp, svp); + svp->sv_retry++; + SPANS_VC_TIMER((struct vccb *) svp, SV_TIMEOUT); + } else { + /* + * Retry limit exceeded--just finish the close + */ + svp->sv_sstate = SPANS_VC_FREE; + svp->sv_connvc->cvc_attr.cause.tag = T_ATM_PRESENT; + svp->sv_connvc->cvc_attr.cause.v.coding_standard = + T_ATM_ITU_CODING; + svp->sv_connvc->cvc_attr.cause.v.location = + T_ATM_LOC_USER; + svp->sv_connvc->cvc_attr.cause.v.cause_value = + T_ATM_CAUSE_NO_USER_RESPONDING; + KM_ZERO(svp->sv_connvc->cvc_attr.cause.v.diagnostics, + sizeof(svp->sv_connvc->cvc_attr.cause.v.diagnostics)); + atm_cm_cleared(svp->sv_connvc); + } + break; + + case SPANS_VC_ACTIVE: + case SPANS_VC_ACT_DOWN: + /* + * Shouldn't happen + */ + log(LOG_ERR, "spans_vctimer: unexpected state %d\n", + svp->sv_sstate); + break; + + default: + log(LOG_ERR, "spans: vctimer state: svp=0x%x, sstate=%d\n", + (int)svp, svp->sv_sstate); + } +} + + +/* + * SPANS name routine + * + * Arguments: + * tok SPANS signalling channel token (ignored) + * + * Returns: + * pointer to a string identifying the SPANS signalling manager + * + */ +caddr_t +spans_getname(tok) + void *tok; +{ + return("SPANS"); +} + + +/* + * Process a VCC connection notification + * + * Should never be called + * + * Arguments: + * tok user's connection token (SPANS protocol block) + * + * Returns: + * none + * + */ +void +spans_connected(tok) + void *tok; +{ + struct spans *spp = (struct spans *)tok; + + ATM_DEBUG2("spans_connected: spp=0x%x,state=%d\n", + (int)spp, spp->sp_state); + + /* + * Connected routine shouldn't ever get called for a PVC + */ + log(LOG_ERR, "spans: connected function called, tok=0x%x\n", + (int)spp); +} + + +/* + * Process a VCC close notification + * + * Called when the SPANS signalling channel is closed + * + * Arguments: + * tok user's connection token (spans protocol block) + * cp pointer to cause structure + * + * Returns: + * none + * + */ +void +spans_cleared(tok, cp) + void *tok; + struct t_atm_cause *cp; +{ + struct spans *spp = (struct spans *)tok; + + /* + * VCC has been closed. + */ + log(LOG_ERR, "spans: signalling channel closed\n"); + SPANS_CANCEL(spp); + spp->sp_conn = 0; +} + + +/* + * SPANS CPCS data handler + * + * This is the module which receives data on the SPANS signalling + * channel. Processing is based on the indication received from the + * AAL and the protocol state. + * + * Arguments: + * tok session token (pointer to spans protocol control block) + * m pointer to buffer with data + * + * Returns: + * none + * + */ +void +spans_cpcs_data(tok, m) + void *tok; + KBuffer *m; +{ + struct spans *spp = tok; + + ATM_DEBUG3("spans_cpcs_data: spp=0x%x,state=%d,m=0x%x,\n", + (int)spp, spp->sp_state, m); + + /* + * Process data + */ + spans_rcv_msg(spp, m); +} |