/************************************************************************/ /* */ /* ***** ***** */ /* ***** ***** */ /* ***** ***** */ /* ***** ***** */ /* *************** *************** */ /* ***************** ***************** */ /* *************** *************** */ /* ***** ***** TheNetNode */ /* ***** ***** Portable */ /* ***** ***** Network */ /* ***** ***** Software */ /* */ /* File src/l2timer.c (maintained by: DF6LN) */ /* */ /* This file is part of "TheNetNode" - Software Package */ /* */ /* Copyright (C) 1998 - 2008 NORD> 2 char notify_call1[10]; char notify_call2[10]; #endif if ((ticks = (UWORD)(tic10 - last_tic)) != 0) { last_tic = tic10; for (llp = &l2actl[port = 0]; /* alle Ports durchgehen */ port < L2PNUM; port++, llp++) for (lnkpoi = (LNKBLK *)llp->head; lnkpoi != (LNKBLK *)llp; /* alle Links des Ports pruefen */ lnkpoi = nextlp) { nextlp = lnkpoi->next; /* Nachfolger schonmal merken */ if (lnkpoi->flag & L2FACKHTH) /* Bestaetigung von HTH */ { if (lnkpoi->state == L2SHTH) { stxfad(); /* Sendepfad setzen */ txfCR = 0; /* Response */ txfPF = L2CPF; /* Final */ xua(); /* UA- als Bestaetigung */ l2newstate(L2SIXFER); /* neuer State: Connected */ } lnkpoi->flag &= ~L2FACKHTH; /* Flag loeschen */ } if (lnkpoi->flag & L2FREJHTH) /* Ablehnung von HTH */ { if (lnkpoi->state == L2SHTH) { stxfad(); /* Sendepfad setzen */ txfCR = 0; /* Response */ txfPF = L2CPF; /* Final */ xdm(); /* DM- als Bestaetigung */ } lnkpoi->flag &= ~L2FREJHTH; /* Flag loeschen */ } /* Wenn RTT-Messung freigegeben ist, dann RTT um ticks erhoehen */ if (lnkpoi->RTT != 0) lnkpoi->RTT += ticks; if (lnkpoi->T3 != 0) /* wenn Timer 3 aktiv ... */ { if (lnkpoi->T3 <= ticks) /* wenn Timer 3 abgelaufen ... */ { clrT3(); /* ... Timer 3 stoppen und */ l2stma(stbl24); /* Statetable T3 EXPIRES */ } /* ausfuehren */ else lnkpoi->T3 -= ticks; /* sonst herunterzaehlen */ } #ifdef L2PROFILER l2profiler(); /* Spielzeug DB7KG */ #endif if ( (lnkpoi->tosend > 150) /* Der Link laeuft ueber.. */ && (lnkpoi->state >= L2SIXFER) && (lnkpoi->state != L2SHTH)) { #if MAX_TRACE_LEVEL > 2 call2str(notify_call1, lnkpoi->srcid); call2str(notify_call2, lnkpoi->dstid); notify(3, "%s->%s: too many frames in queue", notify_call1, notify_call2); #endif lnkpoi->flag |= L2FDIMM; /* dann abwerfen */ } if (lnkpoi->flag & L2FDIMM) /* Link sofort kappen */ { l2stma(stbl20); /* LOCAL STOP COMMAND */ lnkpoi->flag &= ~L2FDIMM; continue; } if ( (lnkpoi->flag & L2FDSLE) /* Disconnect wenn alles raus? */ && (!lnkpoi->tosend)) /* und nix mehr anstehend? */ { reslnk(); /* Sequenzvars/Timer zurueck */ l2stma(stbl20); /* LOCAL STOP COMMAND */ continue; } /*----------------------------------------------------------------------*/ /* sonst empfangene I-Pakete an hoeheren Level uebertragen und */ /* Busy-Condition pruefen / setzen / aufheben */ /* */ /* "Busy werden" - weniger als 30 Freibuffer oder so viele I-Pakete */ /* empfangen und nicht abgeholt, wie "Erstickungs- */ /* zaehler" conctl angibt */ /* */ /* "Busy aufloesen" - wieder mehr als 62 Freibuffer und weniger als */ /* halb so viele empfangen und nicht abgeholt wie */ /* conctl angibt */ /*----------------------------------------------------------------------*/ i2tolx(FALSE); if (!(lnkpoi->flag & L2FBUSY)) /* nicht busy */ { if (nmbfre < 30 || lnkpoi->rcvd >= conctl) { lnkpoi->flag |= L2FBUSY; /* busy werden */ lnkpoi->busyrx = 0; l2stma(stbl21); /* STATION BECOMES BUSY */ } } else if (nmbfre > 62 && lnkpoi->rcvd < conctl / 2) { lnkpoi->flag &= ~L2FBUSY; /* "busy" aufloesen */ l2stma(stbl22); /* BUSY CONDITION CLEARS */ } if ( busy(port) /* T1 und T2 nur wenn DCD aus ist */ || dama(port)) continue; if (lnkpoi->T1 != 0) /* wenn Timer 1 aktiv ... */ { if (lnkpoi->T1 <= ticks) /* wenn Timer 1 abgelaufen ... */ { lnkpoi->T1 = 0; /* ... Timer 1 stoppen */ lnkpoi->RTT = 0; /* RTT-Messung stoppen */ setT3(); ++lnkpoi->tries; #ifdef T1TIMERMOD /* Nach 3 erfolglosen versuchen, */ /* wird der SRTT-Wert vergroessert. */ if ( (lnkpoi->tries > 5) /* SRTT-Wert kleiner als 50. */ &&(lnkpoi->SRTT < 50)) { lnkpoi->RTT = lnkpoi->SRTT; lnkpoi->RTT += 100; /* SRTT-Wert neu berechnen. */ clrRTT(); } #endif /* T1TIMERMOD */ /* bei Wiederholungen wird Maxframe um 1 reduziert - wer nix empfaengt */ /* landet irgendwann bei Maxframe 1 */ if (lnkpoi->tries > 1) change_maxframe(lnkpoi, -1); if (lnkpoi->tries < /* zu viele Retries ? */ portpar[port].retry) l2stma(stbl23); /* Statet. T1 EXPIRES */ else /* zu viele Retries : */ { lnkpoi->tries = 0; /* Retryzaehler leer */ l2stma(stbl25); /* N2 IS EXCEEDED */ } } else lnkpoi->T1 -= ticks; /* sonst herunterzaehlen */ } if (lnkpoi->T2 != 0) /* wenn Timer 2 aktiv ... */ { if (lnkpoi->T2 <= ticks) /* wenn Timer 2 abgelaufen ... */ lnkpoi->T2 = 0; /* ... Timer 2 stoppen */ else lnkpoi->T2 -= ticks; /* sonst herunterzaehlen */ } if (lnkpoi->T2 == 0) /* Timer 2 abgelaufen oder */ { /* nicht aktiv? */ #ifdef DAMASLAVE if (damaslaveon(port)) continue; #endif if (lnkpoi->RStype != 0) /* T2 abgelaufen */ { stxfad(); /* ... dann Responseframe bauen */ txfCR = txfPF = 0; #ifdef __WIN32__ txfctl = setNR((UBYTE)(!(lnkpoi->flag & L2FBUSY) ? lnkpoi->RStype : L2CRNR)); #else txfctl = setNR(!(lnkpoi->flag & L2FBUSY) ? lnkpoi->RStype : L2CRNR); #endif /* WIN32 */ #ifdef EAX25 txfEAX = FALSE; /* Kontrollbytes fuer EAX.25 aufbauen bzw. umbauen */ if (lnkpoi->bitmask == 0x7F) { txfctl &= 0x0F; /* erstes Kontrollbyte aendern */ txfctlE = (lnkpoi->VR << 1) | (txfPF >> 4); /* V(R) und Pollflag */ txfEAX = TRUE; } #endif sdl2fr(makfhd(L2FUS), TRUE); /* und senden */ clrT2(); /* Responsemodus loeschen */ } } } /* fuer alle nicht disconnecteten Links */ timDAMA(ticks); } } /************************************************************************/ /* */ /* "set T2 and xmit RR response" */ /* */ /* Timer 2 setzen und nach Ablauf RR als Response senden. */ /* */ /************************************************************************/ void t2rrr(void) { setT2(L2CRR); } /************************************************************************/ /* */ /* "set T2 and xmit RNR response" */ /* */ /* Timer 2 setzen und nach Ablauf RNR als Response senden. */ /* */ /************************************************************************/ void t2rnrr(void) { setT2(L2CRNR); } /************************************************************************/ /* */ /* "set T2 and xmit REJ response" */ /* */ /* Timer 2 setzen und nach Ablauf REJ als Response senden. */ /* */ /************************************************************************/ void t2rejr(void) { setT2(L2CREJ); } /************************************************************************/ /* */ /* "set T1" */ /* */ /* Den Timer 1 anhand des SRTT setzen. Wenn wir bereits erfolglose */ /* Versuche hatten (tries != 0), wird der Timer 1 vergroessert. Die */ /* Laufzeitmessung (RTT) wird neu gestartet. */ /* */ /************************************************************************/ void setT1(void) { lnkpoi->T1 = lnkpoi->SRTT * L2_BETA; if (lnkpoi->T1 < 20) /* T1 -> min. 200ms */ lnkpoi->T1 = 20; if (lnkpoi->tries) /* im Wiederholungsfalle */ { #ifdef EAX25 /* Wenn EAXMODE == 2 und schon mehrere SABME verschickt, dann */ /* Rueckfall auf AX.25 nach zwei SABME. */ if ( (lnkpoi->state == L2SLKSUP) /* Wenn der Link nicht steht */ && (portpar[lnkpoi->liport].eax_behaviour == 2) /* Mode stimmt */ && (lnkpoi->bitmask == 0x7F)) /* Ein EAX-Link */ lnkpoi->bitmask = 0x07; /* AX.25 umschalten */ #endif if ( (lnkpoi->state >= L2SIXFER) /* Wenn der Link steht */ && (lnkpoi->state != L2SHTH)) lnkpoi->T1 *= 2; /* T1 verdoppeln */ } if (lnkpoi->T1 > 6000) /* T1 auf 1 Minute begrenzen */ lnkpoi->T1 = 6000; setRTT(); } /************************************************************************/ /* */ /* "clear T1" */ /* */ /* Timer 1 loeschen, es ist eine Reaktion eingetreten. Die Anzahl der */ /* Fehlversuche (tries) wird geloescht, ebenso der Timer 3 neu gesetzt. */ /* */ /************************************************************************/ void clrT1(void) { lnkpoi->T1 = 0; lnkpoi->tries = 0; setT3(); } /************************************************************************/ /* */ /* "set T2" */ /* */ /* Timer 2 starten und festlegen, welches Frame nach Ablauf zu senden */ /* ist. */ /* */ /************************************************************************/ void setT2(UBYTE Stype) { lnkpoi->RStype = Stype; lnkpoi->T2 = portpar[lnkpoi->liport].T2; } /************************************************************************/ /* */ /* "clear T2" */ /* */ /* Timer 2 loeschen. */ /* */ /************************************************************************/ void clrT2(void) { lnkpoi->T2 = 0; lnkpoi->RStype = 0; } /************************************************************************/ /* */ /* "set T3" */ /* */ /* Timer 3 mit Defaultwert initialisieren. */ /* */ /************************************************************************/ void setT3(void) { #ifdef PORT_MANUELL lnkpoi->T3 = portpar[lnkpoi->liport].T3; #else lnkpoi->T3 = T3par; #endif /* PORT_MANUELL */ } /************************************************************************/ /* */ /* "clear T3" */ /* */ /* Timer 1 loeschen. */ /* Fehlversuche (tries) wird geloescht, ebenso der Timer 3 neu gesetzt. */ /* Aus der vergangenen Zeit seit dem setzen des T1 wird der RTT und */ /* damit der SRTT neu berechnet. */ /* */ /************************************************************************/ void clrT3(void) { lnkpoi->T3 = 0; } /************************************************************************/ /* */ /* "set RTT" */ /* */ /* RTT starten und VS merken. */ /* */ /************************************************************************/ void setRTT(void) { lnkpoi->RTT = 1; lnkpoi->RTTvs = lnkpoi->VS; } /************************************************************************/ /* */ /* "clear RTT" */ /* */ /* Aus der vergangenen Zeit seit dem setzen des T1 wird der RTT und */ /* damit der SRTT neu berechnet. */ /* */ /************************************************************************/ void clrRTT(void) { /* * Nach RTT-Berechnung aus KA9Q's TCP/IP-Paket: * * SRTT' = (Alpha * SRTT + RTT) / (Alpha + 1) * * Alpha getrennt parametrisierbar fuer fallendes/steigendes RTT: * Alpha1 = steigendes RTT (kleines Alpha -> schnell reagieren) * Alpha2 = fallendes RTT (grosses Alpha -> langsam reagieren) * */ LNKBLK *lp = lnkpoi; UWORD rtt = lp->RTT, srtt = lp->SRTT, irtt = portpar[lp->liport].IRTT; if (rtt > srtt) srtt = (L2_ALPHA1 * srtt + rtt) / (L2_ALPHA1 + 1); else srtt = (L2_ALPHA2 * srtt + rtt) / (L2_ALPHA2 + 1); if (srtt < irtt / 10) srtt = irtt / 10; if (srtt > irtt * 10) srtt = irtt * 10; #ifdef SRTTMAXMOD if (srtt > SRTTMAXMOD) /* SRTT-Wert ist groesser als SRTTMAX. */ srtt = SRTTMAXMOD; /* auf SRTTMAX setzen. */ #endif /* SRTTMAXMOD */ lp->RTT = 0; lp->SRTT = srtt; } /************************************************************************\ * * * "check no activity" * * * * Alle aktiven Links (lnktbl, Linkstatus "Information Transfer") auf * * "keine Aktivitaet" abtesten. Ist der Keine-Aktivitaet-Timer aktiv * * (!= 0) und nach Dekrementieren abgelaufen, Disconnect einleiten. * * * * ACHTUNG: Diese Funktion muss sekuendlich aufgerufen werden, * * wird aber nur fuer TheNetNode benoetigt. * * * \************************************************************************/ void chknoa(void) { MBHEAD *mbp; int port; LHEAD *llp; for (port = 0, llp = &l2actl[0]; /* alle Ports durchgehen */ port < L2PNUM; port++, llp++) for (lnkpoi = (LNKBLK *)llp->head; lnkpoi != (LNKBLK *)llp; /* alle Links des Ports pruefen */ lnkpoi = lnkpoi->next) { if (!(--lnkpoi->noatou)) { mbp = (MBHEAD *)allocb(ALLOC_MBHEAD); mbp->l2link = lnkpoi; /* Linkpointer und */ mbp->type = 2; /* Typ (2=L2) setzen */ putchr('\r', mbp); putalt(alias, mbp); putid(myid, mbp); #ifndef THENETMOD putstr("> Timeout (", mbp); putnum(ininat, mbp); /* Timeout in s ausgeben */ putstr("s)\r", mbp); seteom(mbp); /* Text an User senden... */ #else /* L4TIMEOUT */ if (SearchTHENET() == NULL) /* Kein THENET-Typ, */ { putstr("> Timeout (", mbp); putnum(ininat, mbp); /* Timeout in s ausgeben */ putstr("s) run off.\r", mbp); seteom(mbp); /* Text an User senden... */ } else /* THENET-TYP, keine Info senden. */ dealmb(mbp); /* Buffer entsorgen. */ #endif /* THENETMOD */ if ( (lnkpoi->state == L2SRBS) /* remote busy? */ || (lnkpoi->state == L2SWARBS) || (lnkpoi->state == L2SRSRBS) || (lnkpoi->state == L2SBBS) /* oder beide busy? */ || (lnkpoi->state == L2SWABBS) || (lnkpoi->state == L2SRSBBS) || (lnkpoi->state == L2SHTH)) /* oder Hop-To-Hop */ lnkpoi->flag |= L2FDIMM; /* sofort abwerfen */ else lnkpoi->flag |= L2FDSLE; /* sonst wenn alles raus */ } } } /************************************************************************\ * * * "set initial SRTT" * * * * Anfangswert fuer Smoothed Round Trip Timer setzen * * * \************************************************************************/ void setiSRTT(void) { char *viap; /* Zeiger in via-Liste */ UWORD n; /* Digizaehler */ viap = lnkpoi->viaidl; /* Anfang via-Liste */ n = 0; /* noch kein Digi gezaehlt */ while (*viap != '\0') /* Digianzahl ermitteln */ { if (!(viap[L2IDLEN - 1] & L2CH)) ++n; viap += L2IDLEN; } n *= 2; ++n; /* Digianzahl * 2 + 1 */ #ifndef SETISRTTMOD lnkpoi->SRTT = portpar[lnkpoi->liport].IRTT * n; #else lnkpoi->SRTT = portpar[lnkpoi->liport].IRTT * 1; #endif /* SETISRTTMOD */ } /* End of src/l2timer.c */