diff options
Diffstat (limited to 'sys/netatm/uni/sscop_timer.c')
-rw-r--r-- | sys/netatm/uni/sscop_timer.c | 576 |
1 files changed, 576 insertions, 0 deletions
diff --git a/sys/netatm/uni/sscop_timer.c b/sys/netatm/uni/sscop_timer.c new file mode 100644 index 0000000..8c23344b --- /dev/null +++ b/sys/netatm/uni/sscop_timer.c @@ -0,0 +1,576 @@ +/* + * + * =================================== + * 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: sscop_timer.c,v 1.6 1998/04/07 23:21:48 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCOP - Timer processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sscop_timer.c,v 1.6 1998/04/07 23:21:48 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * Local functions + */ +static void sscop_poll_expire __P((struct sscop *)); +static void sscop_noresponse_expire __P((struct sscop *)); +static void sscop_cc_expire __P((struct sscop *)); +static void sscop_idle_expire __P((struct sscop *)); + +/* + * Local variables + */ +static void (*sscop_expired[SSCOP_T_NUM]) __P((struct sscop *)) = { + sscop_poll_expire, + sscop_noresponse_expire, + sscop_cc_expire, + sscop_idle_expire +}; + + +/* + * Process an SSCOP timer tick + * + * This function is called SSCOP_HZ times a second in order to update + * all of the sscop connection timers. The sscop expiration function + * will be called to process all timer expirations. + * + * Called at splnet. + * + * Arguments: + * tip pointer to sscop timer control block + * + * Returns: + * none + * + */ +void +sscop_timeout(tip) + struct atm_time *tip; +{ + struct sscop *sop, **sprev; + int i; + + + /* + * Schedule next timeout + */ + atm_timeout(&sscop_timer, ATM_HZ/SSCOP_HZ, sscop_timeout); + + /* + * Run through all connections, updating each active timer. + * If an expired timer is found, notify that entry. + */ + sprev = &sscop_head; + while (sop = *sprev) { + + /* + * Check out each timer + */ + for (i =0; i < SSCOP_T_NUM; i++) { + + /* + * Decrement timer if it's active + */ + if (sop->so_timer[i] && (--sop->so_timer[i] == 0)) { + +#ifdef DIAGNOSTIC + { + static char *tn[] = { + "POLL", + "NORESPONSE", + "CC", + "IDLE" + }; + ATM_DEBUG3("sscop_timer: %s expired, sop=0x%x, state=%d\n", + tn[i], (int)sop, sop->so_state); + } +#endif + + /* + * Expired timer - process it + */ + (*sscop_expired[i])(sop); + + /* + * Make sure connection still exists + */ + if (*sprev != sop) + break; + } + } + + /* + * Update previous pointer if current control + * block wasn't deleted + */ + if (*sprev == sop) + sprev = &sop->so_next; + } +} + + +/* + * Process an SSCOP Timer_POLL expiration + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * none + * + */ +static void +sscop_poll_expire(sop) + struct sscop *sop; +{ + + /* + * Validate current state + */ + if ((sop->so_state != SOS_READY) && + ((sop->so_state != SOS_INRESYN) || + (sop->so_vers != SSCOP_VERS_QSAAL))) { + log(LOG_ERR, "sscop: invalid %s state: sop=0x%x, state=%d\n", + "Timer_POLL", (int)sop, sop->so_state); + return; + } + + /* + * Send next poll along its way + */ + SEQ_INCR(sop->so_pollsend, 1); + (void) sscop_send_poll(sop); + + /* + * Reset data counter for this poll cycle + */ + sop->so_polldata = 0; + + /* + * Reset polling timer + */ + sscop_set_poll(sop); + + return; +} + + +/* + * Process an SSCOP Timer_IDLE expiration + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * none + * + */ +static void +sscop_idle_expire(sop) + struct sscop *sop; +{ + + /* + * Timer_IDLE only valid in READY state + */ + if (sop->so_state != SOS_READY) { + log(LOG_ERR, "sscop: invalid %s state: sop=0x%x, state=%d\n", + "Timer_IDLE", (int)sop, sop->so_state); + return; + } + + /* + * Send next poll along its way + */ + SEQ_INCR(sop->so_pollsend, 1); + (void) sscop_send_poll(sop); + + /* + * Reset data counter for this poll cycle + */ + sop->so_polldata = 0; + + /* + * Start NO-RESPONSE timer + */ + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + + /* + * Reset polling timer + */ + sscop_set_poll(sop); + + return; +} + + +/* + * Process an SSCOP Timer_NORESPONSE expiration + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * none + * + */ +static void +sscop_noresponse_expire(sop) + struct sscop *sop; +{ + int err; + + /* + * Validate current state + */ + if ((sop->so_state != SOS_READY) && + ((sop->so_state != SOS_INRESYN) || + (sop->so_vers != SSCOP_VERS_QSAAL))) { + log(LOG_ERR, "sscop: invalid %s state: sop=0x%x, state=%d\n", + "Timer_NORESPONSE", (int)sop, sop->so_state); + return; + } + + /* + * Peer seems to be dead, so terminate session + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, + sop->so_toku, sop->so_connvc, + SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + /* + * Error, force retry + */ + sop->so_timer[SSCOP_T_NORESP] = 1; + return; + } + + /* + * Stop data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Notify peer of termination + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Report peer's failure + */ + sscop_maa_error(sop, 'P'); + + if (sop->so_vers == SSCOP_VERS_QSAAL) + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + else + /* + * Clear out appropriate queues + */ + q2110_prep_retrieve(sop); + + /* + * Return to IDLE state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * Process an SSCOP Timer_CC expiration + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * none + * + */ +static void +sscop_cc_expire(sop) + struct sscop *sop; +{ + int err; + + /* + * Process timeout based on protocol state + */ + switch (sop->so_state) { + + case SOS_OUTCONN: + /* + * No response to our BGN yet + */ + if (sop->so_connctl < sop->so_parm.sp_maxcc) { + + /* + * Send another BGN PDU + */ + sop->so_connctl++; + (void) sscop_send_bgn(sop, SSCOP_SOURCE_USER); + + /* + * Restart retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + } else { + + /* + * Retransmit limit exceeded, terminate session + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, + sop->so_toku, sop->so_connvc, + SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + /* + * Error, force retry + */ + sop->so_timer[SSCOP_T_CC] = 1; + break; + } + + /* + * Notify peer of termination + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Report establishment failure + */ + sscop_maa_error(sop, 'O'); + + /* + * Clear reestablishment flag + */ + sop->so_flags &= ~SOF_REESTAB; + + /* + * Return to IDLE state + */ + sop->so_state = SOS_IDLE; + } + break; + + case SOS_OUTDISC: + /* + * No response to our END yet + */ + if (sop->so_connctl < sop->so_parm.sp_maxcc) { + + /* + * Send another END PDU + */ + sop->so_connctl++; + (void) sscop_send_end(sop, SSCOP_SOURCE_LAST); + + /* + * Restart retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + } else { + + /* + * Retransmit limit exceeded, force session termination + */ + STACK_CALL(SSCOP_RELEASE_CNF, sop->so_upper, + sop->so_toku, sop->so_connvc, 0, 0, err); + if (err) { + /* + * Error, force retry + */ + sop->so_timer[SSCOP_T_CC] = 1; + break; + } + + /* + * Report establishment failure + */ + sscop_maa_error(sop, 'O'); + + /* + * Return to IDLE state + */ + sop->so_state = SOS_IDLE; + } + break; + + case SOS_OUTRESYN: +rexmitrs: + /* + * No response to our RS yet + */ + if (sop->so_connctl < sop->so_parm.sp_maxcc) { + + /* + * Send another RS PDU + */ + sop->so_connctl++; + (void) sscop_send_rs(sop); + + /* + * Restart retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + } else { + + /* + * Retransmit limit exceeded, terminate session + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, + sop->so_toku, sop->so_connvc, + SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + /* + * Error, force retry + */ + sop->so_timer[SSCOP_T_CC] = 1; + break; + } + + /* + * Notify peer of termination + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Report establishment failure + */ + sscop_maa_error(sop, 'O'); + + if (sop->so_vers == SSCOP_VERS_QSAAL) + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + + /* + * Return to IDLE state + */ + sop->so_state = SOS_IDLE; + } + break; + + case SOS_CONRESYN: /* Q.SAAL1 */ +#if (SOS_OUTRECOV != SOS_CONRESYN) + case SOS_OUTRECOV: /* Q.2110 */ +#endif + if (sop->so_vers == SSCOP_VERS_QSAAL) { + /* + * Handle timeout for SOS_CONRESYN + */ + goto rexmitrs; + } + + /* + * Handle timeout for SOS_OUTRECOV + */ + + /* + * No response to our ER yet + */ + if (sop->so_connctl < sop->so_parm.sp_maxcc) { + + /* + * Send another ER PDU + */ + sop->so_connctl++; + (void) sscop_send_er(sop); + + /* + * Restart retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + } else { + + /* + * Retransmit limit exceeded, terminate session + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, + sop->so_toku, sop->so_connvc, + SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + /* + * Error, force retry + */ + sop->so_timer[SSCOP_T_CC] = 1; + break; + } + + /* + * Notify peer of termination + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Report establishment failure + */ + sscop_maa_error(sop, 'O'); + + /* + * Clear receiver buffer + */ + sscop_rcvr_drain(sop); + + /* + * Return to IDLE state + */ + sop->so_state = SOS_IDLE; + } + break; + + default: + log(LOG_ERR, "sscop: invalid %s state: sop=0x%x, state=%d\n", + "Timer_CC", (int)sop, sop->so_state); + } +} + |