summaryrefslogtreecommitdiffstats
path: root/sys/netatm/uni/sscop_timer.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netatm/uni/sscop_timer.c')
-rw-r--r--sys/netatm/uni/sscop_timer.c576
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);
+ }
+}
+
OpenPOWER on IntegriCloud