TheNetNode-CB/src/l3rtt.c

540 lines
22 KiB
C
Raw Normal View History

2019-05-15 00:19:53 +02:00
/************************************************************************/
/* */
/* ***** ***** */
/* ***** ***** */
/* ***** ***** */
/* ***** ***** */
/* *************** *************** */
/* ***************** ***************** */
/* *************** *************** */
/* ***** ***** TheNetNode */
/* ***** ***** Portable */
/* ***** ***** Network */
/* ***** ***** Software */
/* */
/* File src/l3rtt.c (maintained by: ???) */
/* */
/* This file is part of "TheNetNode" - Software Package */
/* */
/* Copyright (C) 1998 - 2008 NORD><LINK e.V. Braunschweig */
/* */
/* This program is free software; you can redistribute it and/or modify */
/* it under the terms of the NORD><LINK ALAS (Allgemeine Lizenz fuer */
/* Amateurfunk Software) as published by Hans Georg Giese (DF2AU) */
/* on 13/Oct/1992; either version 1, or (at your option) any later */
/* version. */
/* */
/* This program is distributed WITHOUT ANY WARRANTY only for further */
/* development and learning purposes. See the ALAS (Allgemeine Lizenz */
/* fuer Amateurfunk Software). */
/* */
/* You should have received a copy of the NORD><LINK ALAS (Allgemeine */
/* Lizenz fuer Amateurfunk Software) along with this program; if not, */
/* write to NORD><LINK e.V., Hinter dem Berge 5, D-38108 Braunschweig */
/* */
/* Dieses Programm ist PUBLIC DOMAIN, mit den Einschraenkungen durch */
/* die ALAS (Allgemeine Lizenz fuer Amateurfunk Software), entweder */
/* Version 1, veroeffentlicht von Hans Georg Giese (DF2AU), */
/* am 13.Oct.1992, oder (wenn gewuenscht) jede spaetere Version. */
/* */
/* Dieses Programm wird unter Haftungsausschluss vertrieben, aus- */
/* schliesslich fuer Weiterentwicklungs- und Lehrzwecke. Naeheres */
/* koennen Sie der ALAS (Allgemeine Lizenz fuer Amateurfunk Software) */
/* entnehmen. */
/* */
/* Sollte dieser Software keine ALAS (Allgemeine Lizenz fuer Amateur- */
/* funk Software) beigelegen haben, wenden Sie sich bitte an */
/* NORD><LINK e.V., Hinter dem Berge 5, D-38108 Braunschweig */
/* */
/************************************************************************/
#include "tnn.h"
#include "l3local.h"
/************************************************************************/
/* L3-RTT-Service */
/* erzeugt einen Frame mit L3-Header, bei dem Ziel und Absender */
/* der eigene Knoten ist. Dieses Frame wird dann an den Nachbarn */
/* gesendet. Die vorhergehende Messung wird dem Nachbarn mitgeteilt. */
/* im Frame wird die vergangene Zeit in 10ms-Schritten seit Programm- */
/* start mitgegeben. */
/* Automatische Qualitaetsberechnung aus dem L3SRTT, DB2OS 06/04/93 */
/*----------------------------------------------------------------------*/
void
l3rtt_service(void)
{
PEER *pp;
int i;
int max_peers = netp->max_peers;
MBHEAD *mbp;
INDEX index;
#if MAX_TRACE_LEVEL > 2
char notify_call[10];
#endif
for (i = 0, pp = netp->peertab; i < max_peers; i++, pp++)
{
if (!pp->used)
continue;
if (pp->typ > NETROM)
continue;
#ifdef THENETMOD
if ( (pp->typ == THENET) /* THENET-Typ und */
&&(pp->constatus == TRUE)) /* kein Dauerconnect gewuenscht. */
continue; /* Zum naechsten Segment. */
#endif /* THENETMOD */
#ifdef L4NOBAKE
if (pp->soll_typ == NETROM)/* Wenn noch kein Routing-TYP fest steht,*/
continue; /* zum naechsten Segment. */
#endif /* L4NOBAKE */
if (pp->nbrl2l == NULL)
{
/* Der Nachbar, auf den pp zeigt, bekommt eine L3-Mini-Broadcast-Bake */
/* von uns. Diese ist notwendig, da einige aeltere Versionen von TheNet */
/* und andere NET/ROM-Implementierungen den Nachbarn nur annehmen, wenn */
/* vorher bereits eine L3-Bake empfangen wurde. Anschliessend wird eine */
/* Verbindung zum Nachbarn hergestellt. */
/* Wollen wir einen INP-Link, so senden wir keine NODES-Bake vorher da */
/* wir mit NETROM ja nix machen wollen und wir wegen INP annehmen, dass */
/* die Gegenseite keine Uralt-Soft hat, die diese Minibake braucht. */
#ifndef THENETMOD
if (pp->soll_typ != INP)
#else
if (pp->typ == TNN) /* L3-Mini Bake nur fuer TNN-Typ zulassen. */
#endif /* THENETMOD */
{
mbp = (MBHEAD *)allocb(ALLOC_MBHEAD); /* Buffer besorgen */
#ifdef __WIN32__
putchr((char)0xFF, mbp);
#else
putchr(0xFF, mbp);
#endif /* WIN32 */
pu6chr(alias, mbp); /* Ident in Buffer */
mbp->l2fflg = L2CNETROM; /* PID = Level 3 */
rwndmb(mbp); /* Pointer aufziehen */
sdl3ui(pp, mbp); /* UI-Broadcast senden */
}
#ifdef PORT_L2_CONNECT_TIME
if (pp->l2link->sabmtime == 0)
{
#endif
#ifdef PORT_L2_CONNECT_RETRY
if (connbr(pp))
pp->nbrl2l->tries = (UBYTE)portpar[pp->nbrl2l->liport].retry - (UBYTE)portpar[pp->nbrl2l->liport].l2_connect_retry;
continue;
#else
if (connbr(pp))
pp->nbrl2l->tries = portpar[pp->nbrl2l->liport].retry - 1;
continue;
#endif
#ifdef PORT_L2_CONNECT_TIME
}
else
{
pp->l2link->sabmtime--;
continue;
}
#endif
}
if (pp->nbrl2l->state < L2SIXFER)
continue;
if (pp->rttstart)
{
if (tic10 - pp->rttstart >= 18000L) /* maximal 180 Sekunden */
{
#if MAX_TRACE_LEVEL > 2
call2str(notify_call, pp->l2link->call);
notify(3, "%s: l3rtt too high: %ld", notify_call,
tic10 - pp->rttstart);
#endif
discnbp(pp);
}
continue;
}
if (pp->rtt_time == 0)
{ /* Messung ist faellig */
if (pp->typ == THENET)
{ /* der kann nicht messen */
update_peer_quality(pp, pp->nbrl2l->SRTT * 4L, DONT_CHANGE_QUAL);
/* Falls das Timeout auf einer Route mal abfaellt, */
/* melden wir hier wieder die Routen-Qualitaet hoch. */
if ((index = add_route(pp, pp->l2link->call, 1)) != NO_INDEX)
update_lt(pp, index, 1);
rtt_metric(pp, pp->nbrl2l->SRTT * 4L);
pp->rtt_time = L3_RTT_TIME;
#ifdef THENETMOD
if (pp->constatus == FALSE)/* Link soll staendig Aktiv bleiben. */
pp->nbrl2l->noatou = ininat; /* L2-Timeout setzen. */
#endif /* THENETMOD */
}
else
#ifndef L4NOBAKE
send_l3srtt_frame(pp); /* Neue Messung starten */
#else
{
if (pp->soll_typ != NETROM) /* Nur wenn Routing-TYP fest steht,*/
send_l3srtt_frame(pp); /* Neue Messung starten */
}
#endif /* L4NOBAKE */
}
else
pp->rtt_time--; /* Messintervall runterzaehlen */
}
}
/*----------------------------------------------------------------------*/
void
send_l3srtt_frame(PEER *pp)
{
MBHEAD *mbp;
int mtu;
if (pp->typ > NETROM) /* nur bei NET/ROM erlaubt */
return;
if (pp->nbrl2l)
{ /* nur aktiver mit L2-Link.. */
mbp = (MBHEAD *)allocb(ALLOC_MBHEAD); /* Buffer besorgen */
putfid(myid, mbp); /* von eigenes Call */
putfid("L3RTT \140", mbp); /* an Pseudo-Destination */
*(mbp->mbbp - 1) |= 1; /* EOA setzen */
putchr(0x02, mbp); /* Lifetime = 2 */
putchr(0x00, mbp); /* Circuit-Index */
putchr(0x00, mbp); /* Circuit-ID */
putchr(0x00, mbp); /* TX-Sequence-Number */
putchr(0x00, mbp); /* RX-Sequence-Number */
putchr(0x05, mbp); /* OpCode & Flags */
putstr("L3RTT:", mbp); /* Framekennung */
pp->rttstart = tic10; /* Startzeit merken */
putlong(tic10, TRUE, mbp); /* 10ms Ticks seit Softstart */
putlong((ULONG)pp->quality, TRUE, mbp); /* aktueller L3-SRTT Wert */
putlong((ULONG)pp->my_quality, TRUE, mbp); /* letzter L3-RTT Wert */
putlong((ULONG)pp, TRUE, mbp); /* Pointer als ID */
putchr(' ', mbp);
pu6chr(alias, mbp);
putstr(" LEVEL3_V2.1 ", mbp); /* L3-Version */
putstr(infostr, mbp); /* TNN-Version */
/* nur wenn wir einen INP-Link wollen auch dem Nachbarn sagen dass */
/* wir INP koennen und ggf. maxtime melden, ansonsten nix sagen */
if (pp->soll_typ == INP)
{
if (mymaxtime != 0)
putprintf(mbp, " $M%u", mymaxtime);
putstr(" $N\r", mbp);
}
mtu = portpar[pp->l2link->port].mtu;
while (mbp->mbpc < mtu) /* Buffer voll machen */
putchr(' ', mbp);
rwndmb(mbp); /* Frame aufziehen */
toneig(pp, mbp); /* Frame an den Nachbarn */
}
}
/************************************************************************\
* *
* Das Frame mit der gewuenschten Kennung vergleichen. Wenn ja, *
* wird sie ueberlesen, sonst wird mbbp/mbgc restauriert. *
* *
\************************************************************************/
BOOLEAN
match(MBHEAD *fbp, const char *text)
{
char huge *mbbp; /* Sicherung von mbbp */
UWORD mbgc; /* Sicherung von mbgc */
mbbp = fbp->mbbp; /* Position im Frame (mbbp,mbgc) */
mbgc = fbp->mbgc; /* merken, falls kein Erfolg */
while (*text)
{ /* die Kennung durchgehen */
if (getchr(fbp) != *text++)
{ /* Abweichung! */
fbp->mbbp = mbbp; /* auf die alte Position im Frame */
fbp->mbgc = mbgc; /* zurueckgehen */
return (FALSE); /* Kennung stimmt nicht */
}
}
return (TRUE); /* Kennung stimmt */
}
/************************************************************************/
/* */
/* Eine Bake senden mit Informationen zur erfolgten Laufzeitmessung */
/* */
/************************************************************************/
void
rtt_metric(PEER *pp, long rtt)
{
BEACON *beapoi; /* Zeiger auf einen Baken-Eintrag */
int i;
MBHEAD *mbp;
struct tm *p;
LNKBLK *lp;
PTCENT *ptcp;
int telemetrie;
p = localtime(&sys_time);
/* fuer alle Ports, bei denen die Bake freigegeben ist.. */
for (i = 0, beapoi = beacon; i < L2PNUM; ++beapoi, ++i)
{
#ifdef BEACON_STATUS
if ((telemetrie = beapoi->telemetrie) == 2)
#else
if ((telemetrie = beapoi->telemetrie) >= 2)
#endif
{
(mbp = (MBHEAD *)allocb(ALLOC_MBHEAD))->l2fflg = L2CPID;
lp = pp->nbrl2l;
ptcp = ptctab + g_uid(lp, L2_USER);
if (telemetrie != 2) /* Format fuer automatische Auswertung */
{
mbp->l4time = mbp->mbpc;
putid(pp->l2link->call, mbp); /* Node Call */
putspa(10, mbp);
putprintf(mbp, "%2d %02d.%02d.%02d %02d:%02d:%02d",
lp->liport,
p->tm_mday, p->tm_mon + 1, p->tm_year % 100,
p->tm_hour, p->tm_min, p->tm_sec);
putprintf(mbp, " %7lu", rtt * 10L);
if (pp->quality > 9999)
{
putprintf(mbp, " %2lumin", pp->quality / 6000);
}
else
putprintf(mbp, " %5lu", pp->quality * 10L);
if (pp->my_quality > 9999)
{
putprintf(mbp, " %2lumin", pp->my_quality / 6000);
}
else
putprintf(mbp, " %5lu", pp->my_quality * 10L);
if (pp->his_quality > 9999)
{
putprintf(mbp, " %2lumin", pp->his_quality / 6000);
}
else
putprintf(mbp, " %5lu", pp->his_quality * 10L);
putprintf(mbp, " %7lu %lu\r",
lp->SRTT * 10L,
ptcp->inforx + ptcp->infotx);
}
else
{
putprintf(mbp, "%02d.%02d.%02d %02d:%02d:%02d ",
p->tm_mday, p->tm_mon + 1, p->tm_year % 100,
p->tm_hour, p->tm_min, p->tm_sec);
putid(pp->l2link->call, mbp); /* Node Call */
putprintf(mbp, "(%02d)\rL3RTT=%lums L3SRTT=%lums (%lums/%lums) "
"L2SRTT=%lums SUM=%lu\r",
lp->liport,
rtt * 10L,
pp->quality * 10L,
pp->my_quality * 10L,
pp->his_quality * 10L,
lp->SRTT * 10L,
ptcp->inforx + ptcp->infotx);
}
rwndmb(mbp);
#ifdef __WIN32__
sdui(beapoi->beadil, "METRIC\140", myid, (char)i, mbp);
#else
sdui(beapoi->beadil, "METRIC\140", myid, i, mbp);
#endif /* WIN32 */
dealmb(mbp); /* Telemetrie-Frame kann jetzt weg */
} /* Telemetrie */
} /* alle Ports */
}
/************************************************************************/
/* */
/* L3RTT-Frames auswerten: Entweder sind es Messframes fuer Laufzeit- */
/* messungen oder aber NODES-Meldungen bei ON5ZS-Routing */
/* */
/************************************************************************/
void
rx_l3rtt_frame(PEER *rxpp, MBHEAD *mbp, char huge *savmbbp, WORD savmbgc)
{
char rx_alias[L2IDLEN]; /* Ident des Nachbarn (wenn bekannt) */
char ver[12]; /* Version des Nachbarn */
WORD i,
j; /* Zaehler */
char buffer[150]; /* Speicher fuer RTT String-Operationen */
char *bp;
char version[4]; /* TNN-Version */
ULONG prev_tic10; /* Zeitpunkt der RTT Messung in 10ms */
ULONG prev_l3srtt; /* letzter SRTT (smoothed RTT) */
ULONG prev_l3rtt; /* letzter gemessener RTT-Wert */
PEER *rtt_pp; /* Pointer auf Nachbarliste */
char buf2[8];
ULONG rtt;
INDEX index;
ULONG maxtime;
if (l4opco == L4INFTRA) /* Info-Transfer */
{
if (match(mbp, "BROAD")) /* BROAD Kennung ? */
{
if (cmpid(rxpp->l2link->call, orgnod) == TRUE)
if (rxpp->typ == TNN) /* kann der andere Info? */
rx_broadcast(rxpp, mbp); /* dann auswerten */
dealmb(mbp); /* Buffer entsorgen */
return;
}
if (match(mbp, "L3RTT:")) /* L3RTT Kennung ? */
{
for (i = 0; ((i < 110) && (mbp->mbgc < mbp->mbpc)); i++)
buffer[i] = getchr(mbp);
/* zur Sicherheit */
memset(rx_alias, 0, L2IDLEN);
strcpy(&buffer[i], " 1 2 3 4 5 6 \n\0");
sscanf(&buffer[0], "%lu %lu %lu %lu %6s %11s %6s",
&prev_tic10,
&prev_l3srtt,
&prev_l3rtt,
(unsigned long *)&rtt_pp,
rx_alias,
ver,
buf2);
*version = NUL;
if (!strncmp(buf2, "TNN", 3))
strcpy(version, &buf2[3]);
for (i = j = 0; i < L2CALEN; i++)
if (rx_alias[i] == 0x00 || j == 1)
{
rx_alias[i] = ' '; /* mit Leerzeichen fuellen */
j = 1;
}
/************************************************************************/
/* Eigenes Frame auswerten */
/************************************************************************/
if (cmpid(orgnod, myid)) /* selbst Absender */
{
if ((rtt_pp == rxpp)) /* passender Nachbar */
if ( tic10 > prev_tic10 /* Uhr nicht uebergelaufen */
&& rxpp->rttstart == prev_tic10 /* richtige Messung */
&& ((tic10 - prev_tic10) < 10000))/* nicht zu lang! */
{ /* gemessene L3-RTT */
rtt = (tic10 - prev_tic10) + 2;
update_peer_quality(rxpp, rtt / 2, DONT_CHANGE_QUAL);
/* Falls das Timeout auf einer Route mal abfaellt, melden wir hier */
/* wieder die Routen-Qualitaet hoch. */
if ((index = add_route(rxpp, rxpp->l2link->call, 1))
!= NO_INDEX)
update_lt(rxpp, index, 1);
rtt_metric(rxpp, (long)rtt);
rxpp->rttstart = 0L;
rxpp->rtt_time = L3_RTT_TIME;
/* erste Bake ueberhaupt, dem Nachbarn wurde noch nicht die */
/* Laufzeit uebertragen, das machen wir jetzt gleich mit einer */
/* zweiten Bake. Dies fuehrt dazu, dass der Link sofort benutzbar */
/* wird. Den Nachbarn merken wir selber provisorisch mit schlechtester */
/* Laufzeit, bei der ersten regulaeren Bake wird das durch die echte */
/* Laufzeitmeldung korrigiert. Der provisorische Wert wird nicht */
/* an andere Nodes weiterverbreitet. */
if ((prev_l3srtt == 0) && (prev_l3rtt == 0))
send_l3srtt_frame(rxpp);
}
dealmb(mbp);
return;
} /* eigenes L3RTT-Frame */
/* Fremdes L3RTT-Frame auswerten, und an Nachbarn zurueck */
if (cmpid(rxpp->l2link->call, orgnod) == TRUE)
{
if (time_to_live >= 1)
{ /* noch Restlebenszeit.. */
mbp->mbbp = savmbbp;
mbp->mbgc = savmbgc;
/* Frame sofort zurueck an Absender */
toneig(rxpp, mbp);
/* Frame auswerten */
if (strnicmp("LEVEL3_V2.1", ver, 11) == 0)
{
if (rxpp->typ == NETROM)
set_peer_typ(rxpp, TNN);
rxpp->version = atoi(version);
cpyals(rxpp->l2link->alias, rx_alias);
}
else
cpyals(rx_alias, rxpp->l2link->alias);
/* meldet der Nachbar INP-Faehigkeit ? */
if (strstr(buffer, "$N"))
{
#ifndef L4NOBAKE
/* Partner ist noch nicht I und wir wollen auch einen I-Link */
if ((rxpp->typ != INP) && (rxpp->soll_typ == INP))
#else
/* Partner ist noch nicht I und wir wollen auch einen I-Link */
if ( ((rxpp->typ != INP) && (rxpp->soll_typ == INP))
||(rxpp->soll_typ == NETROM)) /* Routing-Typ steht noch nicht*/
/* fest, Nachbar will I, dann */
/* stellen wir auf INP um. */
#endif /* L4NOBAKE */
{
set_peer_typ(rxpp, INP); /* Typ aendern */
#ifdef L4NOBAKE
rxpp->soll_typ = INP; /* Typ auf INP setzen. */
#endif /* L4NOBAKE */
send_inp_nodebeacon(rxpp); /* uns selber melden */
}
}
/* MaxTime fuer INP-Nachbarn */
if (rxpp->typ == INP)
{
/* Nachbar sagt uns eine MaxTime ? */
if ((bp = strstr(buffer, "$M")) != NULL)
{
/* Ja, dann uebernehmen */
sscanf(bp + 2, "%lu", &maxtime);
rxpp->maxtime = (UWORD)maxtime;
}
else
rxpp->maxtime = 0; /* Nein, dann keine MaxTime */
}
if (prev_l3srtt >= 5L)
update_peer_quality(rxpp, DONT_CHANGE_QUAL, prev_l3srtt);
if ((index = add_route(rxpp, rxpp->l2link->call, 1)) != NO_INDEX)
{
update_lt(rxpp, index, 1);
if (update_alias(index, rx_alias))
propagate_node_update(index);
}
return;
}
}
} /* L3RTT: */
} /* L4-Info-Frame */
dealmb(mbp);
}
/* End of src/l3rtt.c */