/* * * =================================== * 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. * * @(#) $FreeBSD$ * */ /* * SPANS Signalling Manager * --------------------------- * * SPANS protocol processing module. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "spans_xdr.h" #include #ifndef lint __RCSID("@(#) $FreeBSD$"); #endif /* * 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=%p,state=%d\n", 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=%p, state=%d\n", 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=%p, sstate=%d, ustate=%d\n", 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=%p, sstate=%d\n", 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=%p,state=%d\n", spp, spp->sp_state); /* * Connected routine shouldn't ever get called for a PVC */ log(LOG_ERR, "spans: connected function called, tok=%p\n", 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=%p,state=%d,m=%p,\n", spp, spp->sp_state, m); /* * Process data */ spans_rcv_msg(spp, m); }