872 lines
35 KiB
C
Executable File
872 lines
35 KiB
C
Executable File
/************************************************************************/
|
|
/* */
|
|
/* ***** ***** */
|
|
/* ***** ***** */
|
|
/* ***** ***** */
|
|
/* ***** ***** */
|
|
/* *************** *************** */
|
|
/* ***************** ***************** */
|
|
/* *************** *************** */
|
|
/* ***** ***** TheNetNode */
|
|
/* ***** ***** Portable */
|
|
/* ***** ***** Network */
|
|
/* ***** ***** Software */
|
|
/* */
|
|
/* File src/l3netrom.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"
|
|
|
|
static int rtt2qual(ULONG rtt);
|
|
static int qual2rtt(unsigned);
|
|
static void fastlearn(PEER *, char *);
|
|
static void rx_ui_broadcast(PEER *, MBHEAD *);
|
|
static void add_netrom_info(MBHEAD **, NODE *, PEER *, PEER *, unsigned);
|
|
static void add_thenet_info(MBHEAD **, NODE *, PEER *, PEER *, unsigned);
|
|
static void addbro(MBHEAD **, NODE *, PEER *, PEER *, unsigned,
|
|
unsigned, int);
|
|
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* Umrechnung NETROM-Qualitaet <-> Laufzeit */
|
|
/* */
|
|
/************************************************************************/
|
|
static int
|
|
rtt2qual(ULONG rtt) /* Laufzeit zu Qualitaet */
|
|
{
|
|
int qual;
|
|
|
|
if (rtt)
|
|
{
|
|
qual = 255 - (unsigned)(rtt / autoqual);
|
|
if (qual > 254)
|
|
qual = 254;
|
|
if (qual < 3)
|
|
qual = 3;
|
|
return (qual);
|
|
}
|
|
return (0); /* ausgefallen */
|
|
}
|
|
|
|
static int
|
|
qual2rtt(unsigned qual) /* Qualitaet zu Laufzeit */
|
|
{
|
|
if (qual < 2)
|
|
return (0); /* unerreichbar */
|
|
return ((256 - qual) * autoqual);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* Die Absenderknoten muessen in der Nodesliste stehen, damit wir */
|
|
/* Antworten zurueckschicken koennen. Ist ein Absender noch nicht */
|
|
/* bekannt, wird dieser mit einer Laufzeit von 599,99s eingetragen. */
|
|
/* */
|
|
/************************************************************************/
|
|
static void
|
|
fastlearn(PEER *pp, char *id)
|
|
{
|
|
INDEX index = find_node_this_ssid(id);
|
|
#if MAX_TRACE_LEVEL > 6
|
|
char notify_call1[10];
|
|
char notify_call2[10];
|
|
#endif
|
|
|
|
if (index != NO_INDEX) /* Node bekannt und Qualitaet gut */
|
|
if (pp->routes[index].quality) /* dann nicht lernen */
|
|
return;
|
|
if ((index = add_route(pp, id, LEARN)) != NO_INDEX)
|
|
{
|
|
update_lt(pp, index, DEFAULT_LT);
|
|
#ifndef THENETMOD
|
|
pp->routes[index].timeout = ROUTE_TIMEOUT;
|
|
#else
|
|
/* Lebensdauer einer Node markieren. */
|
|
pp->routes[index].timeout = obcini;
|
|
#endif /* THENETMOD */
|
|
#if MAX_TRACE_LEVEL > 6
|
|
call2str(notify_call1, orgnod);
|
|
call2str(notify_call2, pp->l2link->call);
|
|
notify(7, "fastlearn %s via %s",
|
|
notify_call1, notify_call2);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/************************************************************************\
|
|
* *
|
|
* Informationstransfer von Level2 zum NET/ROM-Router *
|
|
* *
|
|
* Die empfangenen Frames vom Nachbarn werden ausgewertet und ggf. an den *
|
|
* eigenen L4 (Verbindungsebene) oder an einen anderen Nachbarn *
|
|
* weitergeleitet. *
|
|
* *
|
|
\************************************************************************/
|
|
void
|
|
netrom_rx(PEER *rxpp)
|
|
{
|
|
MBHEAD *mbp; /* Buffer fuer ein Frame */
|
|
char huge *savmbbp; /* mbbp-Sicherung */
|
|
WORD savmbgc; /* mbgc-Sicherung */
|
|
NODE *srcnod;
|
|
NODE *dstnod;
|
|
PEER *pp;
|
|
MHEARD *mhp;
|
|
int mask;
|
|
#if MAX_TRACE_LEVEL > 2
|
|
char notify_call1[10];
|
|
char notify_call2[10];
|
|
char notify_call3[10];
|
|
#endif
|
|
|
|
/* Zunaechst empfangene Frames verarbeiten, bis Liste leer... */
|
|
while ( (mbp = (MBHEAD *)(rxpp->rxfl.head))
|
|
!= (MBHEAD *)&(rxpp->rxfl))
|
|
{
|
|
ulink((LEHEAD *)mbp); /* 1 Frame aus der Liste holen */
|
|
if (mbp->l2link == NULL)
|
|
rx_ui_broadcast(rxpp, mbp); /* ist UI-Broadcast */
|
|
else /* Info Frame */
|
|
{
|
|
if (rx_inp_broadcast(rxpp, mbp)) /* INP Broadcast? */
|
|
{
|
|
dealmb(mbp);
|
|
return; /* max 1 Frame pro Runde */
|
|
}
|
|
savmbbp = mbp->mbbp; /* Position im Frame merken */
|
|
savmbgc = mbp->mbgc; /* fuer Weiterleitung */
|
|
if ( (getfid(orgnod, mbp)) /* Call des Quellknotens holen */
|
|
&& (getfid(desnod, mbp)) /* Call des Zielknotens holen */
|
|
&& (mbp->mbgc < mbp->mbpc)) /* und Info im Frame? */
|
|
{
|
|
if ( valcal(orgnod) == ERRORS /* Absender und Zielrufzeichen */
|
|
|| valcal(desnod) == ERRORS /* pruefen */
|
|
)
|
|
{
|
|
#if MAX_TRACE_LEVEL > 2
|
|
call2str(notify_call1, orgnod);
|
|
call2str(notify_call2, desnod);
|
|
call2str(notify_call3, rxpp->l2link->call);
|
|
notify(3, "invalid node %s>%s from %s (flushed)",
|
|
notify_call1, notify_call2, notify_call3);
|
|
/* wir sagens dem Sysop */
|
|
#endif
|
|
dealmb(mbp); /* Frame wegwerfen */
|
|
continue; /* ... und zum naechsten Frame */
|
|
}
|
|
--(*(mbp->mbbp)); /* Restlebensdauer um 1 runter */
|
|
time_to_live = getchr(mbp); /* Restlebensdauer lesen */
|
|
|
|
if ((mbp->mbpc - mbp->mbgc) >= 5) /* ist es lang genug ? */
|
|
{
|
|
/* Frames, die von einem Knoten kommen, der noch nicht in unsere */
|
|
/* Knoten-Liste eingetragen ist, fuehren zu einem Eintrag des Quell- */
|
|
/* Knotens mit Qualitaet 59999 in unsere Nodes-Liste (Fast-Learn) */
|
|
|
|
if ( !cmpid(myid, orgnod) /* kein eigenes Frame */
|
|
&& !cmpid(myid, rxpp->l2link->call))
|
|
fastlearn(rxpp, orgnod);
|
|
|
|
l4hdr0 = getchr(mbp); /* Header holen */
|
|
l4hdr1 = getchr(mbp); /* ist eigentlich Sache des L4, */
|
|
l4hdr2 = getchr(mbp); /* aber der L3 verschickt auch */
|
|
l4hdr3 = getchr(mbp); /* L4-Messframes, deswegen */
|
|
l4hdr4 = getchr(mbp); /* wird das schon hier er- */
|
|
l4opco = l4hdr4 & L4OPMASK; /* ledigt. */
|
|
|
|
if (l4opco == L3TCPUDP && l4hdr0 == 0 && l4hdr1 == 1) /* NRR */
|
|
{
|
|
nrr_rx(mbp, rxpp);
|
|
dealmb(mbp); /* Frame wegwerfen */
|
|
continue; /* ... und zum naechsten Frame */
|
|
}
|
|
|
|
/*----- Auswertung der eigenen und fremden L3RTT Frames ----------------*/
|
|
if ( cmpid(desnod, "L3RTT \140") /* Ziel und Inhalt OK! */
|
|
&& ( cmpid(orgnod, rxpp->l2link->call)
|
|
|| cmpid(orgnod, myid))) /* und von dem Nachbarn */
|
|
{ /* oder eigenes */
|
|
rx_l3rtt_frame(rxpp, mbp, savmbbp, savmbgc);
|
|
continue;
|
|
}
|
|
|
|
/* L3-MH-Liste fuehren */
|
|
if ((mhp = mh_lookup(&l3heard, orgnod)) == NULL)
|
|
mhp = mh_add(&l3heard);
|
|
if (mhp)
|
|
{ /* Eintrag vorhanden? */
|
|
mh_update(&l3heard, mhp, orgnod, mbp->l2port);
|
|
mhp->rx_bytes += (mbp->mbpc - mbp->mbgc);
|
|
}
|
|
|
|
/*----------------- Frame ist fuer mich --------------------------------*/
|
|
if (cmpid(myid, desnod))
|
|
{
|
|
#ifdef IPROUTE
|
|
if (l4opco == L3TCPUDP)
|
|
{ /* L3 TCP/UDP-Frame */
|
|
mbp->l2fflg = L2CIP; /* es ist ein IP-Frame */
|
|
relink((LEHEAD *)mbp, (LEHEAD *)iprxfl.tail);
|
|
continue; /* Frame verarbeitet */
|
|
}
|
|
#endif
|
|
mbp->l3_typ = L3NORMAL; /* kein LOCAL und kein L3RTT */
|
|
if (iscall(orgnod, &srcnod, NULL, DG)) /* Absender-Node */
|
|
{
|
|
l4rx(srcnod, NULL, mbp); /* Frame an Level 4 geben */
|
|
continue; /* naechstes Frame */
|
|
}
|
|
#if MAX_TRACE_LEVEL > 4
|
|
call2str(notify_call1, orgnod);
|
|
notify(5, "unreachable source node %s", notify_call1);
|
|
#endif
|
|
dealmb(mbp); /* Frame entsorgen */
|
|
continue;
|
|
}
|
|
|
|
/* MH-Liste Senderichtung */
|
|
if ((mhp = mh_lookup(&l3heard, desnod)) != NULL)
|
|
mhp->tx_bytes += (mbp->mbpc - mbp->mbgc);
|
|
|
|
/*---- nur CONREQ kann auf L2 umgeroutet werden */
|
|
if ((l4opco == L4CONREQ) || (l4istome(orgnod, desnod)))
|
|
mask = DG | VC | VC_FAR;
|
|
else
|
|
mask = DG;
|
|
|
|
/*---- Level 3 Frame nicht fuer mich, sondern weiterleiten -----*/
|
|
if (iscall(desnod, &dstnod, &pp, mask))
|
|
{ /* Ziel erreichbar? */
|
|
/* wenn das Ziel nicht im DG-Mode erreicht werden kann, dann muessen */
|
|
/* wir umsetzen. */
|
|
if ((pp->options & DG) == 0)
|
|
{
|
|
mbp->l3_typ = L3LOCAL;
|
|
mbp->l2link = (LNKBLK *)dstnod; /* Ziel-Node */
|
|
if (iscall(orgnod, &srcnod, NULL, DG)) /* Absender */
|
|
{
|
|
l4rx(srcnod, dstnod, mbp);
|
|
continue; /* naechstes Frame */
|
|
}
|
|
#if MAX_TRACE_LEVEL > 4
|
|
call2str(notify_call1, orgnod);
|
|
notify(5, "unreachable source node %s", notify_call1);
|
|
#endif
|
|
dealmb(mbp); /* Frame entsorgen */
|
|
continue;
|
|
}
|
|
|
|
if (time_to_live)
|
|
{ /* noch Restlebensdauer? */
|
|
mbp->mbbp = savmbbp;
|
|
mbp->mbgc = savmbgc;
|
|
|
|
if (cmpid(myid, orgnod)) /* eigenes Frame gehoert, weg */
|
|
{ /* damit */
|
|
#if MAX_TRACE_LEVEL > 4
|
|
call2str(notify_call1, desnod);
|
|
call2str(notify_call2, rxpp->l2link->call);
|
|
notify(5, "own frame to %s received fm %s (loop)",
|
|
notify_call1, notify_call2);
|
|
#endif
|
|
dealmb(mbp);
|
|
continue;
|
|
}
|
|
|
|
/* Falls wir ein Frame ueber den Nachbarn zurueckschicken */
|
|
|
|
if (rxpp == pp) /* wuerden, dann vernichten wir es */
|
|
{
|
|
#if MAX_TRACE_LEVEL > 4
|
|
call2str(notify_call1, orgnod);
|
|
call2str(notify_call2, desnod);
|
|
call2str(notify_call3, rxpp->l2link->call);
|
|
notify(5, "frame fm %s to %s via %s flushed (neigb loop)",
|
|
notify_call1, notify_call2, notify_call3);
|
|
#endif
|
|
dealmb(mbp);
|
|
continue;
|
|
}
|
|
|
|
toneig(pp, mbp); /* Info absetzen */
|
|
continue;
|
|
} /* noch Restlebensdauer */
|
|
} /* Ziel bekannt */
|
|
} /* Laenge ok */
|
|
} /* Info ist im Frame */
|
|
} /* es ist ein I-Frame */
|
|
dealmb(mbp);
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* L3 UI-Frame (Broadcast) */
|
|
/* */
|
|
/************************************************************************/
|
|
static void
|
|
rx_ui_broadcast(PEER *rxpp, MBHEAD *mbp)
|
|
{
|
|
char alias[L2CALEN]; /* Alias Rundspruch sendender Knoten */
|
|
INDEX index;
|
|
|
|
if (worqua != 0) /* darf Auswertung erfolgen? */
|
|
{
|
|
if ( mbp->mbgc < mbp->mbpc /* Info im Frame? */
|
|
&& (getchr(mbp) & 0xFF) == 0xFF /* stimmt Signatur */
|
|
&& ge6chr(alias, mbp)) /* Alias des Absender-Knotens */
|
|
{
|
|
if ( (alias[0] != '#') /* NOROUTE, Keine Route '#' im Alias, */
|
|
#ifdef THENETMOD
|
|
||(NoRoute) /* oder NOROUTE eingeschaltet, */
|
|
#endif /* THENETMOD */
|
|
) /* Broadcast-Node zulassen, ansonsten ablehnen. */
|
|
{
|
|
cpyals(rxpp->l2link->alias, alias);
|
|
if ((index = add_route(rxpp, rxpp->l2link->call, 1)) != NO_INDEX)
|
|
{
|
|
update_lt(rxpp, index, 1);
|
|
if (update_alias(index, alias))
|
|
propagate_node_update(index);
|
|
rx_broadcast(rxpp, mbp);
|
|
#ifdef THENETMOD
|
|
if ( (rxpp->soll_typ == NETROM) /* Noch kein TYP gesetzt. */
|
|
||(rxpp->soll_typ == THENET)) /* Typ soll ein THENET-TYP sein. */
|
|
rxpp->typ = THENET; /* TYP auf THENET-TYP setzen. */
|
|
|
|
if (!rxpp->obscnt) /* Restlebensdauer fuer Rundspruch */
|
|
{ /* noch nicht gesetzt. */
|
|
MBHEAD *rxmbp = NULL;
|
|
|
|
bcast(&rxmbp, /* Broadcast-Bake to CALL senden, */
|
|
rxpp->l2link->call, /* damit der Link sofort nutzbar ist. */
|
|
rxpp->l2link->port);
|
|
}
|
|
|
|
rxpp->obscnt = obcbro; /* Restlebensdauer fuer Rundspruch setzen. */
|
|
|
|
if (rxpp->quality < 1) /* Nur wenn ungueltige Qualitaet, */
|
|
rxpp->quality = worqua; /* minimale Qualitaet setzen. */
|
|
|
|
#endif /* THENETMOD */
|
|
}
|
|
}
|
|
}
|
|
} /* Signatur ist gut */
|
|
} /* Auswertung zulaessig */
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
void
|
|
rx_broadcast(PEER *rxpp, MBHEAD *mbp)
|
|
{
|
|
char desnod[L2IDLEN];
|
|
char beaide[L2CALEN];
|
|
char nbr_call[L2IDLEN];
|
|
int rx_qual;
|
|
INDEX index;
|
|
PEER *pp;
|
|
#if MAX_TRACE_LEVEL > 8
|
|
char notify_call1[10];
|
|
char notify_call2[10];
|
|
char notify_call3[10];
|
|
#endif
|
|
|
|
if (rxpp->typ == INP)
|
|
return;
|
|
|
|
#ifdef THENETMOD
|
|
if (rxpp->l2link->alias[0] == '#') /* Unser Partner ist GEHEIM, */
|
|
return; /* damit wir nehmen keine NODES an. */
|
|
#endif /* THENETMOD */
|
|
|
|
while ( (getfid(desnod, mbp))
|
|
&& (valcal(desnod))
|
|
&& (ge6chr(beaide, mbp))
|
|
&& (getfid(nbr_call, mbp))
|
|
&& (valcal(nbr_call))
|
|
&& (mbp->mbgc < mbp->mbpc))
|
|
{
|
|
rx_qual = getchr(mbp) & 0xFF;
|
|
|
|
#if MAX_TRACE_LEVEL > 8
|
|
call2str(notify_call1, rxpp->l2link->call);
|
|
call2str(notify_call2, desnod);
|
|
call2str(notify_call3, nbr_call);
|
|
notify(9, "%-9.9s>%-6.6s:%-9.9s Q%u v %-9.9s",
|
|
notify_call1, beaide, notify_call2, rx_qual, notify_call2);
|
|
#endif
|
|
|
|
#ifdef THENETMOD
|
|
if (beaide[0] == '#')
|
|
{
|
|
#if MAX_TRACE_LEVEL > 2
|
|
call2str(notify_call1, rxpp->l2link->call);
|
|
call2str(notify_call2, desnod);
|
|
notify(3, "NETROM: %s sent secret node %s", notify_call1, notify_call2);
|
|
#endif
|
|
/* XNet hat (derzeit ?) einen Fehler, der Nodes mit Geheim-Aliassen */
|
|
/* sendet. Da diese Nodes nicht wirklich geheim sind nehmen wir sie */
|
|
/* trotzdem, loeschen aber ihre Aliasse. */
|
|
if ( (strncasecmp(&beaide[1], "temp", 4) == 0)
|
|
|| (strncasecmp(&beaide[1], "tmp", 3) == 0)
|
|
)
|
|
{
|
|
/* fehlerhaften Alias loeschen */
|
|
cpyals(beaide, DONT_CHANGE_ALIAS); /* Alias loeschen */
|
|
#if MAX_TRACE_LEVEL > 2
|
|
notify(3, "NETROM: not real secret node, corrected");
|
|
#endif
|
|
}
|
|
}
|
|
#endif /* THENETMOD */
|
|
|
|
if ( (cmpid(myid, nbr_call) == TRUE) /* er wuerde an mich senden, */
|
|
|| (rx_qual == LEARNQUAL) /* oder er kennt keinen Weg, */
|
|
|| (beaide[0] == '#')) /* oder Ziel (jetzt) "hidden" */
|
|
rx_qual = 0; /* also den Weg austragen */
|
|
|
|
if (cmpid(myid, desnod) == TRUE) /* nicht uns selber */
|
|
continue;
|
|
|
|
switch (rxpp->typ)
|
|
{
|
|
case NETROM:
|
|
case THENET:
|
|
if (rx_qual < worqua)
|
|
rx_qual = 0; /* ausgefallen */
|
|
break;
|
|
case TNN:
|
|
if (rx_qual < 2)
|
|
rx_qual = 0; /* ausgefallen */
|
|
break;
|
|
}
|
|
|
|
if ((index = add_route(rxpp, desnod, qual2rtt(rx_qual))) != NO_INDEX)
|
|
{
|
|
update_lt(rxpp, index, DEFAULT_LT);
|
|
|
|
if (!cmpcal(netp->nodetab[index].alias, nulide))
|
|
if (find_best_qual(index, &pp, DG) > 0) /* beste Qualitaet */
|
|
if (pp != rxpp)
|
|
continue;
|
|
|
|
if (update_alias(index, beaide)) /* Alias hat sich geaendert */
|
|
propagate_node_update(index);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
sdl3ui(PEER *pp, MBHEAD *mbp) /* UI-Broadcast senden */
|
|
{
|
|
unsigned int i;
|
|
STAT *statp;
|
|
|
|
if (pp->l2link->digil[0] == 0) /* direkter Nachbar */
|
|
sdui("", /* Level 2 senden */
|
|
"NODES \140", /* an das Ziel "NODES" */
|
|
myid,
|
|
#ifdef __WIN32__
|
|
(char)pp->l2link->port,
|
|
#else
|
|
pp->l2link->port,
|
|
#endif /* WIN32 */
|
|
mbp);
|
|
else
|
|
sdui(pp->l2link->digil, /* Level 2 senden */
|
|
pp->l2link->call,
|
|
myid,
|
|
#ifdef __WIN32__
|
|
(char)pp->l2link->port,
|
|
#else
|
|
pp->l2link->port,
|
|
#endif /* WIN32 */
|
|
mbp);
|
|
|
|
/* Da gesendete UI-Frames nicht in der Statistik an der dafuer vorgesehenen */
|
|
/* Stelle erfasst werden koennen, dort ist das eigentliche Ziel (der Link- */
|
|
/* partner) nicht mehr bekannt, die Statistik hier fuehren. */
|
|
|
|
for (statp = mh, i = 0; i < MAXSTAT; statp++, i++)
|
|
{
|
|
if (!(*statp->call)) /* nur benutzte Eintraege interessieren */
|
|
continue;
|
|
|
|
if (cmpid(pp->l2link->call, statp->call)) /* richtiger Stat-Eintrag */
|
|
{
|
|
if (pp->l2link->digil[0] == NUL) /* ohne via Angabe */
|
|
{
|
|
statp->UIno[1]++;
|
|
break;
|
|
}
|
|
else
|
|
{ /* mit via */
|
|
if (cmpid(pp->l2link->digil, statp->viacall))
|
|
{
|
|
statp->UIno[1]++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
dealmb(mbp); /* Buffer wieder freigeben */
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* "send broadcast" */
|
|
/* */
|
|
/* Ein Broadcast-Frame auf die Reise schicken. Es wird je nach Nachbar- */
|
|
/* typ als UI oder als I-Frame gesendet. "nodemb" wird auf NULL ge- */
|
|
/* setzt, um einen fehlenden Node-Buffer zu signalisieren. Der naechste */
|
|
/* Aufruf von addbro() erzeugt dann ein neues Broadcast-Frame. */
|
|
/* */
|
|
/*----------------------------------------------------------------------*/
|
|
void
|
|
brosnd(MBHEAD **mbpp, PEER *pp)
|
|
{
|
|
if (*mbpp == NULL)
|
|
{
|
|
if (pp->typ == THENET /* || pp->typ == NETROM*/)
|
|
{
|
|
(*mbpp = (MBHEAD *)allocb(ALLOC_MBHEAD))->l3_typ = L2CUI;
|
|
#ifdef __WIN32__
|
|
putchr((char)0xFF, *mbpp);
|
|
#else
|
|
putchr(0xFF, *mbpp);
|
|
#endif /* WIN32 */
|
|
pu6chr(alias, *mbpp);
|
|
#if MAX_TRACE_LEVEL > 6
|
|
notify(7, "brosnd");
|
|
#endif
|
|
}
|
|
else
|
|
return;
|
|
}
|
|
|
|
rwndmb(*mbpp); /* vor dem Senden Buffer zurueckspulen */
|
|
|
|
if ((*mbpp)->l3_typ == L2CI) /* Als I-Frame ueber den Link senden */
|
|
toneig(pp, *mbpp);
|
|
else
|
|
{
|
|
(*mbpp)->l2fflg = L2CNETROM;/* Als UI-Bake rausschicken an "NODES" */
|
|
sdl3ui(pp, *mbpp); /* PID = Level 3 */
|
|
}
|
|
*mbpp = NULL; /* und Buffer loeschen */
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* "add broadcast" */
|
|
/* */
|
|
/* Einen Weg zu dem Broadcast-Frame fuer einen Nachbarn hinzufuegen. */
|
|
/* Das Frame wird gesendet, sobald es voll ist oder in brosrv() wenn */
|
|
/* der Timeout abgelaufen ist. */
|
|
/* */
|
|
/*----------------------------------------------------------------------*/
|
|
static void
|
|
add_netrom_info(MBHEAD **mbpp, NODE *node, PEER *topp,
|
|
PEER *viapp, unsigned qualit)
|
|
{
|
|
int qual = rtt2qual(qualit);
|
|
|
|
/* schlechte Wege werden unterdrueckt, abmelden kennt NETROM nicht */
|
|
if (qual <= worqua)
|
|
return;
|
|
|
|
if (*mbpp)
|
|
if (((*mbpp)->mbpc + 21) > 256) /* bis Frame voll */
|
|
brosnd(mbpp, topp);
|
|
|
|
if (*mbpp == NULL)
|
|
{ /* neues Frame holen */
|
|
(*mbpp = (MBHEAD *)allocb(ALLOC_MBHEAD))->l3_typ = L2CUI;
|
|
#ifdef __WIN32__
|
|
putchr((char)0xFF, *mbpp);
|
|
#else
|
|
putchr(0xFF, *mbpp);
|
|
#endif /* WIN32 */
|
|
pu6chr(alias, *mbpp);
|
|
}
|
|
|
|
putfid(node->id, *mbpp); /* Call des Zieles */
|
|
pu6chr(node->alias, *mbpp); /* Ident des Zieles */
|
|
if (qualit && viapp)
|
|
putfid(viapp->l2link->call, *mbpp); /* Nachbar des Zieles */
|
|
else
|
|
putfid(myid, *mbpp); /* Nachbar geloescht */
|
|
#ifdef __WIN32__
|
|
putchr((char)rtt2qual(qualit), *mbpp);
|
|
#else
|
|
putchr(rtt2qual(qualit), *mbpp);
|
|
#endif /* WIN32 */
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* Einen Weg zu dem Infocast-Frame fuer einen Nachbarn hinzufuegen. */
|
|
/* Das Frame wird gesendet, sobald es voll ist oder in brosrv() wenn */
|
|
/* der Timeout abgelaufen ist. */
|
|
/* */
|
|
/*----------------------------------------------------------------------*/
|
|
static void
|
|
add_thenet_info(MBHEAD **mbpp, NODE *node, PEER *topp,
|
|
PEER *viapp, unsigned qualit)
|
|
{
|
|
if (*mbpp)
|
|
if (((*mbpp)->mbpc + 21) > 256) /* bis Frame voll */
|
|
brosnd(mbpp, topp);
|
|
|
|
if (*mbpp == NULL)
|
|
{ /* neues Frame holen */
|
|
(*mbpp = (MBHEAD *)allocb(ALLOC_MBHEAD))->l3_typ = L2CI;
|
|
putfid(myid, *mbpp); /* von eigenes Call */
|
|
putfid("L3RTT \140", *mbpp); /* an Pseudo-Destination */
|
|
*((*mbpp)->mbbp - 1) |= 1; /* EOA setzen */
|
|
putchr(0x02, *mbpp); /* Lifetime = 2 */
|
|
putchr(0x00, *mbpp); /* Circuit-Index */
|
|
putchr(0x00, *mbpp); /* Circuit-ID */
|
|
putchr(0x00, *mbpp); /* TX-Sequence-Number */
|
|
putchr(0x00, *mbpp); /* RX-Sequence-Number */
|
|
putchr(0x05, *mbpp); /* OpCode & Flags */
|
|
putstr("BROAD", *mbpp); /* Framekennung */
|
|
}
|
|
|
|
putfid(node->id, *mbpp); /* Call des Zieles */
|
|
pu6chr(node->alias, *mbpp); /* Ident des Zieles */
|
|
if (qualit && viapp)
|
|
putfid(viapp->l2link->call, *mbpp); /* Nachbar des Zieles */
|
|
else
|
|
putfid(myid, *mbpp); /* Nachbar geloescht */
|
|
#ifdef __WIN32__
|
|
putchr((char)rtt2qual(qualit), *mbpp);
|
|
#else
|
|
putchr(rtt2qual(qualit), *mbpp);
|
|
#endif /* WIN32 */
|
|
}
|
|
|
|
static void
|
|
addbro(MBHEAD **mbpp, NODE *node, PEER *topp, PEER *viapp,
|
|
unsigned qualit, unsigned lastqual, int lt)
|
|
{
|
|
switch (topp->typ)
|
|
{
|
|
case THENET:
|
|
case NETROM:
|
|
add_netrom_info(mbpp, node, topp, viapp, qualit);
|
|
break;
|
|
case TNN:
|
|
add_thenet_info(mbpp, node, topp, viapp, qualit);
|
|
break;
|
|
case INP:
|
|
add_inp_info(mbpp, node, topp, qualit, lastqual, lt);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* Broadcast fuer einen Nachbarn */
|
|
void
|
|
inform_peer(PEER *pp, int kind_of)
|
|
{
|
|
INDEX index;
|
|
int max_nodes = netp->max_nodes;
|
|
NODE *np = netp->nodetab;
|
|
ROUTE *rp = pp->routes;
|
|
PEER *bestpp;
|
|
UWORD quality;
|
|
unsigned int reported_quality;
|
|
unsigned int diff;
|
|
UWORD maxtime;
|
|
|
|
int timeout;
|
|
MBHEAD *mbp = NULL; /* noch kein Buffer offen */
|
|
|
|
BOOLEAN old_netrom = (pp->typ == NETROM || pp->typ == THENET);
|
|
|
|
for (index = 0; index < max_nodes; index++, np++, rp++)
|
|
{
|
|
if (np->id[0] == 0) /* kein Eintrag */
|
|
continue;
|
|
|
|
if (cmpid(np->id, pp->l2link->call)) /* der Nachbar */
|
|
continue;
|
|
|
|
#ifdef LINKSMOD_LOCALMOD
|
|
if (CheckLocalLink(np->id) == TRUE) /* Ist ein Local-Link. */
|
|
continue; /* Zum nechsten Eintrag. */
|
|
#endif /* LINKSMOD_LOCALMOD */
|
|
|
|
/************************************************************************/
|
|
/**** HACK: wird nur benoetigt, solange wir nur die Flexnet Nachbarn ****/
|
|
/**** und nicht deren Ziele melden wollen ****/
|
|
#ifndef FLEX_ROUTINGFIX
|
|
if ( ((quality = find_best_qual(index, &bestpp, VC | VC_FAR | DG))
|
|
!= 0)
|
|
&& (bestpp->options == VC_FAR)
|
|
#else
|
|
/* Hiermit werden keine FLEXNET-Routen durchgelassen, FLEXGATE deaktiviert. */
|
|
/* Es duerfen nur LOCAL und LOCAL_M (VC) ins Netrom-Netz geroutet werden. */
|
|
/* LOCAL_N und LOCAL_V werden weiter oben behandelt und duerfen nicht */
|
|
/* weiter geroutet werden !!! */
|
|
if ( ((quality = find_best_qual(index, &bestpp, HOST_MASK)) != 0)
|
|
&& (bestpp->options == VC)
|
|
#endif /* FLEX_ROUTINGFIX */
|
|
&& (cmpid(bestpp->l2link->call, np->id)))
|
|
{
|
|
}
|
|
else
|
|
/************************************************************************/
|
|
|
|
/** An Nachbarn, die das gleiche Call haben, wie der beste Weg (also */
|
|
/* auch der beste Weg selbst) melden wir 0. */
|
|
quality = find_best_qual(index, &bestpp, HOST_MASK);
|
|
if (cmpid(bestpp->l2link->call, pp->l2link->call))
|
|
quality = 0;
|
|
|
|
/*** Alternativ: ***/
|
|
/*** quality = find_best_notvia(index, pp, &bestpp, HOST_MASK); ***/
|
|
|
|
reported_quality = rp->reported_quality;
|
|
if (np->alias[0] == '#') /* versteckter Node */
|
|
{
|
|
if (!reported_quality) /* hatten wir gemeldet? */
|
|
continue; /* nein, also auch jetzt nicht */
|
|
quality = 0; /* ja, also abmelden */
|
|
}
|
|
if (kind_of == ALL)
|
|
{
|
|
/* gesicherten Nachbarn brauchen wir nur Ziele zu uebertragen, */
|
|
/* die wir schon mal gemeldet hatten */
|
|
if (!old_netrom && !reported_quality)
|
|
continue;
|
|
/* wir senden alle Routen ohne Timeout und diejenigen, die noch */
|
|
/* mindestens 30% des Timeouts uebrig haben */
|
|
timeout = rp->timeout;
|
|
if ( (timeout == 0)
|
|
#ifndef THENETMOD
|
|
|| (timeout >= (ROUTE_TIMEOUT / 3)))
|
|
#else
|
|
|| (timeout >= (obcini / 3)))
|
|
#endif /* THENETMOD */
|
|
{
|
|
addbro(&mbp, netp->nodetab + index, pp, bestpp, quality,
|
|
reported_quality, bestpp->routes[index].lt);
|
|
rp->reported_quality = quality;/* merken was wir gemeldet haben */
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Die maximal zulaessige Laufzeit fuer Meldungen ist entweder 600s */
|
|
/* oder ein vom Nachbarn vorgegebener kleinerer Wert. Hat der Nachbar */
|
|
/* eine max. Laufzeit gemeldet, so wird diese beruecksichtigt. */
|
|
maxtime = pp->maxtime;
|
|
if (!maxtime || maxtime > HORIZONT)
|
|
maxtime = HORIZONT;
|
|
/* Zusaetzliches Filter: Bei der ersten Meldung eines Zieles darf die */
|
|
/* Laufzeit hoechstens die Haelfte des Maximalwertes betragen, damit */
|
|
/* wir nicht schon bei der ersten Verschlechterung das Ziel wieder */
|
|
/* abmelden muessen. */
|
|
if (!reported_quality) /* noch nix gemeldet? */
|
|
if (quality > (maxtime / 2)) /* zu schlecht? */
|
|
continue;
|
|
|
|
if (reported_quality != DIRTY)
|
|
{
|
|
if (quality == reported_quality)
|
|
continue; /* keine Aenderung */
|
|
|
|
/* Wenn ein Ziel ausfaellt oder neu gemeldet wird, dann brauchen wir */
|
|
/* nicht zu kontrollieren, ob die Meldung unterdrueckt werden kann. */
|
|
/* Diese Meldungen sind zwingend. */
|
|
if (quality && reported_quality)
|
|
{
|
|
/* Verbesserungen werden nur gemeldet, wenn Sie mindestens um 50% von */
|
|
/* der letzten Meldung abweichen. Ebenfalls nicht gemeldet werden sehr */
|
|
/* geringe Verbesserungen (<= 100ms) bei sehr schnellen Links */
|
|
/* (Aenderung z.B. von 50ms auf 90ms wird nicht gemeldet, obwohl es 60% */
|
|
/* sind). Die Verbesserung muss mindestens ueber der halben Laufzeit */
|
|
/* zum empfangenden Segment liegen. Die Verbesserung wird nur gemeldet */
|
|
/* wenn der Link nicht verstopft ist! */
|
|
if (quality < reported_quality)
|
|
{
|
|
diff = reported_quality - quality;
|
|
if (diff < reported_quality / 2) /* Filter 1: */
|
|
continue; /* 50% Verbesserung */
|
|
if (diff < 10) /* Filter 2: */
|
|
continue; /* mindestens 100ms */
|
|
if (diff < pp->quality / 2) /* Filter 3: */
|
|
continue; /* adaptiv nach Zielr. */
|
|
if (pp->nbrl2l->tosend > 7) /* Filter 4: */
|
|
continue; /* Link verstopft? */
|
|
}
|
|
else
|
|
{
|
|
/* Verschlechterungen muessen immer sofort uebertragen werden! Wir */
|
|
/* senken die Qualitaet bei der Meldung vorbeugend um 12.5% ab und */
|
|
/* zusaetzlich um die 1/2 Laufzeit zu diesem Nachbarn. Bei weiterem */
|
|
/* Abfall sollen weitere hektische Meldungen dadurch vermieden werden. */
|
|
#ifdef __WIN32__
|
|
quality += quality / 8 + (unsigned short)pp->quality / 2;
|
|
#else
|
|
quality += quality / 8 + pp->quality / 2;
|
|
#endif /* WIN32 */
|
|
/* Ist die neue Laufzeit groesser als der Nachbar wuenscht, wird das */
|
|
/* Ziel abgemeldet. */
|
|
if (quality > maxtime)
|
|
quality = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
addbro(&mbp, netp->nodetab + index, pp, bestpp, quality,
|
|
reported_quality, bestpp->routes[index].lt);
|
|
|
|
rp->reported_quality = quality; /* merken was wir gemeldet haben */
|
|
|
|
/* bei abgemeldeten Nodes die Lifetime loeschen */
|
|
if ((rp->reported_quality == 0) && (rp->quality == 0))
|
|
rp->lt = 0;
|
|
}
|
|
}
|
|
brosnd(&mbp, pp);
|
|
}
|
|
|
|
/* End of src/l3netrom.c */
|