TheNetNode-CB/src/l3tab.c

950 lines
34 KiB
C
Executable File

/************************************************************************/
/* */
/* ***** ***** */
/* ***** ***** */
/* ***** ***** */
/* ***** ***** */
/* *************** *************** */
/* ***************** ***************** */
/* *************** *************** */
/* ***** ***** TheNetNode */
/* ***** ***** Portable */
/* ***** ***** Network */
/* ***** ***** Software */
/* */
/* File src/l3tab.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 */
/* */
/************************************************************************/
/************************************************************************/
/* In diesem Modul werden die Verwaltungsstrukturen fuer den Level 3 */
/* und die dazugehoerigen Algorithmen implementiert. */
/* Alle Routinen in diesem Modul sind nicht abhaengig vom der ver- */
/* wendeten Netzwerk-Klasse. */
/************************************************************************/
#include "tnn.h"
#include "l3local.h"
static int hashid(const char *, int);
static void range(ULONG *, ULONG);
static void clear_peer(PEER *);
static void smooth(unsigned long *, unsigned long);
/* HASHING */
#if 0
static int hashid( /* Hash-Funktion fuer ein Rufzeichen */
const char *id, /* Rufzeichen ohne SSID */
int hashsize) /* Hash-Array Groesse */
{
int prim[] = {3, 5, 7, 11, 13, 17}; /* tnx Prof. Dassow, UMD */
register int r, hashval = 0;
for (r = 0; r < 6; r++)
hashval += ((unsigned)(*id++)) * prim[r];
return((unsigned)(hashval % hashsize));
}
#else /* nicht alle compiler koennen unroll-loops */
/* Hash-Funktion fuer ein Rufzeichen */
static int
hashid(const char *id, /* Rufzeichen ohne SSID */
int hashsize) /* Hash-Array Groesse */
{
register int hashval;
hashval = ((unsigned)(*id++)) * 3;
hashval += ((unsigned)(*id++)) * 5;
hashval += ((unsigned)(*id++)) * 7;
hashval += ((unsigned)(*id++)) * 11;
hashval += ((unsigned)(*id++)) * 13;
hashval += ((unsigned)(*id)) * 17;
return((unsigned)(hashval % hashsize));
}
#endif
/* ein neues Segment anlegen */
PEER *register_peer(void)
{
PEER *peertab = netp->peertab; /* Segment-Tabelle */
PEER *pp;
for (pp = peertab; pp < &peertab[netp->max_peers]; pp++)
if (!pp->used) break;
if (pp != &peertab[netp->max_peers]) { /* nur wenn Platz */
if ((pp->routes = calloc((size_t)netp->max_nodes, sizeof(ROUTE))) == NULL)
return(NULL); /* kein Speicher */
pp->quality = /* Segment nicht erreichbar */
pp->my_quality =
pp->his_quality = 0L;
pp->locked = FALSE;
pp->used = TRUE;
pp->num_routes = 0;
pp->primary = pp;
pp->maxtime = 0;
#ifdef THENETMOD
/* Kein Dauerconnect zum Nachbarn (nur THENET-TYP). Ist keine */
pp->constatus = 1; /* Aktivitaet, wird die Verbindung getrennt. */
#endif /* THENETMOD */
netp->num_peers++;
return(pp);
}
return(NULL);
}
void unregister_peer( /* Segment austragen */
PEER *pp) /* Zeiger auf das Segment */
{
clear_peer(pp); /* Routen ueber das Segment verwerfen */
free(pp->routes); /* Routentabelle freigeben */
netp->num_peers--;
pp->used = FALSE;
}
/************************************************************************/
/* */
/* Node id mit SSID-Bereich suchen */
/* */
/************************************************************************/
INDEX
find_node_ssid_range(const char *id)
{
NODE *np;
NODE *nodetab = netp->nodetab;
int max_nodes = netp->max_nodes;
int hash_tries; /* Anzahl Schritte bis Treffer */
int ssid = SSID(id);
INDEX index;
if (id[0] == FALSE)
return (NO_INDEX);
index = hashid(id, max_nodes);
if ((np = nodetab + index) == NULL)
return (NO_INDEX);
for (hash_tries = 0; /* Ab Hash-Position suchen */
hash_tries < max_nodes; /* ueber die ganze Hash-Tabelle */
hash_tries++) /* keine Nodes mehr uebrig? */
{
if (np->id[0] == TRUE)
{
if ( (ssid >= SSID(np->id)) /* passt der SSID-Bereich? */
&& (ssid <= np->ssid_high))
{
if (cmpcal(np->id, id))
return (index); /* Index liefern */
}
}
if (++index >= max_nodes) /* np weiterruecken, Umbruch */
{ /* beachten */
np = nodetab;
index = 0;
}
else
np++;
}
return (NO_INDEX);
}
/************************************************************************/
/* */
/* Node id mit festem SSID suchen */
/* */
/************************************************************************/
INDEX
find_node_this_ssid(const char *id)
{
NODE *np;
NODE *nodetab = netp->nodetab;
int max_nodes = netp->max_nodes;
int hash_tries; /* Anzahl Schritte bis Treffer */
INDEX index;
index = hashid(id, max_nodes);
np = nodetab + index;
for (hash_tries = 0; /* Ab Hash-Position suchen */
hash_tries < max_nodes; /* ueber die ganze Hash-Tabelle */
hash_tries++) /* keine Nodes mehr uebrig? */
{
if (np->id[0])
if (cmpid(np->id, id)) /* gefunden? */
return (index); /* Index liefern */
if (++index >= max_nodes) /* np weiterruecken, Umbruch */
{ /* beachten */
np = nodetab;
index = 0;
}
else
np++;
}
return (NO_INDEX);
}
/************************************************************************/
/* */
/* einen Node einsortieren */
/* */
/************************************************************************/
static void
sort_node(NODE *new_np)
{
NODE *np;
char *id = new_np->id; /* Rufzeichen des neuen Nodes */
int ssid = SSID(id); /* SSID des neuen Nodes */
int i;
for (np = (NODE *)netp->nodelis.head;
np != (NODE *)&netp->nodelis;
np = np->next) /* richtige Stelle finden */
if ((i = strncmp(np->id, id, L2CALEN)) >= 0)
if ((i > 0) || (SSID(np->id) > ssid))
break;
relink((LEHEAD *)new_np, (LEHEAD *)np->prev);
}
/************************************************************************/
/* */
/* Node id zur Nodestabelle hinzufuegen + LINKTYP */
/* */
/************************************************************************/
INDEX
add_node(const char *id)
{
int i;
NODE *np;
NODE *nodetab = netp->nodetab;
int max_nodes = netp->max_nodes;
INDEX index;
index = hashid(id, max_nodes); /* Position vorraussagen */
np = nodetab + index;
for (i = 0; i < max_nodes; i++)
{
if (!np->id[0]) /* Platz gefunden */
{
cpyid(np->id, id); /* Call umkopieren */
cpyals(np->alias, nulide); /* Alias loeschen */
np->ipa = 0L; /* IP-Adresse loeschen */
np->bits = 0; /* Subnet-Maskenbits loeschen */
np->options = NULL; /* keine weiteren INP-Options */
np->ssid_high = SSID(id); /* ohne SSID-Bereich */
netp->num_nodes++; /* ein Node mehr */
if (netp->num_nodes > num_nodes_max)
num_nodes_max = netp->num_nodes;
sort_node(np); /* Node einsortieren */
return (index); /* Index liefern */
}
if (++index >= max_nodes) /* np weiterruecken, Umbruch */
{ /* beachten */
np = nodetab;
index = 0;
}
else
np++;
}
return (NO_INDEX);
}
/************************************************************************/
/* */
/* einen Node aus der Liste nehmen */
/* */
/************************************************************************/
void
del_node(INDEX index)
{
NODE *np = netp->nodetab + index;
destot(index);
np->id[0] = NUL; /* Eintrag unbenutzt */
/* INP: Node hatte eine IP, deshalb ARP- und IPR-Eintrag loeschen */
/* aber nur wenn erlaubt */
if (np->ipa != 0L && autoipr != 0)
{
arp_drop(np->ipa, NETROM_PORT, TRUE);
rt_drop(np->ipa, np->bits, TRUE);
}
if (np->options != NULL) /* eventuell vorhandene Optionen loeschen */
{
dealmb(np->options); /* Optionen loeschen */
np->options = NULL; /* hat keine Optionen mehr */
}
netp->num_nodes--; /* ein bekannter Node weniger */
ulink((LEHEAD*)np); /* aussortieren */
}
/************************************************************************/
/* */
/* unerreichbare Nodes loeschen */
/* */
/************************************************************************/
void drop_unreachable_nodes(void) /* Routes/Nodes loeschen */
{
ROUTE *rp; /* Zeiger auf eine Route */
PEER *pp; /* Zeiger auf ein Segment */
NODE *np; /* Zeiger auf einen Node */
NODE *nodetab = netp->nodetab; /* Zeiger auf die Node-Tabelle */
PEER *peertab = netp->peertab; /* Zeiger auf die Segment-Tabelle */
int max_nodes = netp->max_nodes; /* Groesse der Nodes-Tabelle */
int max_peers = netp->max_peers; /* Groesse der Segment-Tabelle */
INDEX index;
#ifdef L3TABDEBUG
#if MAX_TRACE_LEVEL > 2
char notify_call1[10];
#endif
#endif
/* die ganze Nodetabelle durchgehen */
for (index = 0, np = nodetab; index < max_nodes; index++, np++)
{
if (!np->id[0]) /* Eintrag ist unbenutzt */
continue; /* braucht nicht bearbeitet zu werden */
/* alle Peers durchgehen */
for (pp = peertab; pp < &peertab[max_peers]; pp++)
{
if (!pp->used) /* Eintrag ist unbenutzt */
continue; /* braucht nicht bearbeitet zu werden */
rp = &pp->routes[index]; /* Zeiger auf den Routeneintrag */
if ( (rp->reported_quality != 0) /* wir haben Qualitaet gemeldet */
|| (rp->quality != 0)) /* und er auch */
break; /* noch Routen vorhanden, nicht loeschen */
#ifdef L3TABDEBUG
#if MAX_TRACE_LEVEL > 2
call2str(notify_call1, np->id);
notify(3, "drop_unreachable_nodes(): node %s has no routing info",
notify_call1);
#endif
#endif
}
/* steht nach dem Durchlauf der oberen Schleife der pp-Pointer */
/* auf dem letzten Eintrag, dann kann geloescht werden */
if (pp == &peertab[max_peers]) /* keine aktiven Routen mehr */
{
#ifdef L3TABDEBUG
#if MAX_TRACE_LEVEL > 2
call2str(notify_call1, np->id);
notify(3, "drop_unreachable_nodes(): no peer found for %s", notify_call1);
#endif
#endif
del_node(index); /* Node austragen */
}
}
}
/************************************************************************/
/* */
/* eine Route hinzufuegen */
/* */
/************************************************************************/
INDEX
add_route(PEER *pp, const char *id, unsigned quality)
{
INDEX index = find_node_this_ssid(id);
if ((index == NO_INDEX) && quality) /* nur bei guter Qualitaet neu */
index = add_node(id);
if (index != NO_INDEX) /* nur wenn noch Platz war */
update_route(pp, index, quality);
return (index);
}
/************************************************************************/
/* */
/* eine Route aktualisieren */
/* */
/************************************************************************/
void
update_route(PEER *pp, INDEX index, unsigned quality)
{
ROUTE *rp = pp->routes + index; /* Zeiger auf die Route */
/* Empfangene Laufzeit aktualisieren */
if (quality >= HORIZONT)
quality = 0; /* Route ausgefallen */
if (rp->quality && !quality) /* faellt eine Route aus? */
pp->num_routes--;
if (!rp->quality && quality) /* neue Route? */
pp->num_routes++;
rp->quality = quality; /* Qualitaet neu setzen */
rp->timeout = (pp->secured)
? (0) /* ohne Timeout */
#ifndef THENETMOD
: ROUTE_TIMEOUT;
#else
: obcini; /* Lebensdauer einer Node aktualisieren. */
#endif /* THENETMOD */
}
/************************************************************************/
/* */
/* Eintragen der L3-Lifetime fuer ein Ziel */
/* */
/************************************************************************/
void
update_lt(PEER *pp, INDEX index, int lt)
{
(pp->routes + index)->lt = lt;
}
/************************************************************************/
/* */
/* Feststellen, ob sich der Alias aendert, und bei neuem Alias diesen */
/* eintragen. */
/* */
/************************************************************************/
BOOLEAN
update_alias(INDEX index, const char *alias)
{
NODE *np = netp->nodetab + index;
if (cmpcal(alias, nulide)) /* kein Alias gemeldet */
return (FALSE);
if (cmpcal(np->alias, alias)) /* keine Aenderung */
return (FALSE);
cpyals(np->alias, alias); /* neuen Alias setzen */
return (TRUE);
}
BOOLEAN
update_ssid(INDEX index, int ssid_high)
{
NODE *np = netp->nodetab+index;
if (np->ssid_high == ssid_high)
return (FALSE); /* keine Aenderung */
np->ssid_high = ssid_high; /* obere SSID-Grenze nachtragen */
return (TRUE); /* geaendert */
}
/* Grenzen pruefen */
static void range(ULONG *oldval, ULONG newval)
{
if (newval < RTT_MIN)
newval = RTT_MIN;
if (newval <= RTT_MAX) /* noch nicht am Horizont? */
*oldval = newval;
else
*oldval = 0;
}
/* Glaettung durchfuehren und Grenzen pruefen */
static void
smooth(ULONG *oldval, ULONG newval)
{
if (newval < RTT_MIN)
newval = RTT_MIN;
if (newval <= RTT_MAX) { /* noch nicht am Horizont? */
if (*oldval) /* nicht die erste Messung */
*oldval = ((*oldval + 1) * RTT_ALPHA1 - 1 + newval) / RTT_ALPHA2;
else
*oldval = (newval * RTT_BETA);
if (*oldval < 1)
*oldval = 1;
} else
*oldval = 0; /* Link ist tot, komplette Neumessung */
/* ist notwendig */
}
/* Die Qualitaet eines Segmentes aktualisieren, wir unterscheiden dabei
seine und unsere Messung. Unbekannte/unveraenderte Werte werden
durch IGNORE_RTT (==0) uebergeben.
pp->his_quality und pp->my_quality koennen folgende Werte annehmen:
0 noch keine Messung in diese Richtung erfolgreich
RTT_MIN...RTT_MAX gueltiger Messwert
groesser RTT_MAX Peer nicht erreichbar
pp->quality wird auf RTT_MAX+1 gesetzt
- wenn pp->my_quality nicht gueltig *oder* unbekannt
- wenn pp->his_quality nicht gueltig ist
*/
void update_peer_quality(
PEER *pp, /* fuer welches Segment? */
ULONG my_quality, /* meine Messung */
ULONG his_quality) /* Nachbarqualitaet */
{
if (his_quality != DONT_CHANGE_QUAL) {
if (his_quality > 0) /* hat er eine Messung? */
range(&pp->his_quality, his_quality);
else
if (his_quality == 0)
pp->his_quality = 0;
}
if (my_quality != DONT_CHANGE_QUAL) {
if (my_quality > 0) /* unsere Messung gueltig? */
smooth(&pp->my_quality, my_quality);
else
if (my_quality == 0)
pp->my_quality = 0;
}
if (pp->my_quality == 0)
#ifndef THENETMOD
pp->quality = 0;
#else
{
if (pp->typ != THENET) /* Alle Segmente ausser THENET Qualitaet updaten. */
pp->quality = 0;
}
#endif /* THENETMOD */
else {
if (pp->typ == FLEXNET)
range(&pp->quality,
(pp->my_quality + (pp->his_quality ? pp->his_quality : 6000))/2);
else
#ifdef THENETMOD
if (pp->typ != THENET) /* Alle Segmente ausser THENET Quali. updaten. */
#endif /* THENETMOD */
pp->quality = pp->my_quality;
}
update_primary_peer(pp->l2link->call);
}
/************************************************************************/
/* */
/* Routen ueber das Segment verwerfen */
/* */
/************************************************************************/
static void
clear_peer(PEER *pp)
{
#ifdef THENETMOD
if (pp->typ == THENET) /* Segment ist ein THENET-Typ */
return; /* keine Aenderungen vornehmen. */
#endif /* THENETMOD */
memset(pp->routes, 0, netp->max_nodes * sizeof(ROUTE));
pp->num_routes = 0; /* Routen loeschen */
drop_unreachable_nodes(); /* Routes/Nodes loeschen */
}
/************************************************************************/
/* */
/* Linkreset eines Nachbarn */
/* */
/************************************************************************/
void
reset_peer(PEER *pp)
{
int i;
NODE *np;
ROUTE *rp;
int max_nodes = netp->max_nodes;
if (pp->typ <= TNN)
set_peer_typ(pp, NETROM);
for (i = 0, np = netp->nodetab, rp = pp->routes;
i < max_nodes;
i++, np++, rp++)
{
if (!np->id[0]) /* freier Eintrag? */
continue;
rp->reported_quality = 0; /* Eintrag muss gemeldet werden */
if (rp->quality != 0) /* Nachbar hatte gemeldet */
if ( rp->timeout == 0 /* bisher sichere Route oder */
|| rp->timeout > 4) /* Timeout zu gross? */
rp->timeout = 4; /* neues Timeout 3-4 Minuten */
}
update_peer_quality(pp, 0, DONT_CHANGE_QUAL);
drop_unreachable_nodes();
}
/************************************************************************/
/* */
/* Verbindung zum Segment hergestellt */
/* */
/************************************************************************/
void
connect_peer(PEER *pp)
{
clear_peer(pp); /* Alle Ziele loeschen (erstmal) */
}
/************************************************************************/
/* */
/* Verbindung zum Segment beendet */
/* */
/************************************************************************/
void
disconnect_peer(PEER *pp)
{
clear_peer(pp); /* alle Routen loeschen */
}
void
set_peer_typ(PEER *pp, int typ)
{
int i;
NODE *np;
ROUTE *rp;
int max_nodes;
pp->typ = typ;
#ifndef LINKSMOD_LOCALMOD
pp->secured = (typ == LOCAL_M)
|| (typ == LOCAL)
|| (typ == FLEXNET)
|| (typ == INP);
#else
pp->secured = (typ == LOCAL_V)
|| (typ == LOCAL_N)
|| (typ == LOCAL_M)
|| (typ == LOCAL)
|| (typ == FLEXNET)
|| (typ == INP);
#endif /* LINKSMOD_LOCALMOD */
/* bei INP werden nach Linkaufbau alles Nodes an den Nachbarn gemeldet */
if (typ == INP)
{
max_nodes = netp->max_nodes;
for (i = 0, np = netp->nodetab, rp = pp->routes;
i < max_nodes;
i++, np++, rp++)
{
if (!np->id[0]) /* freier Eintrag? */
continue;
rp->reported_quality = 0; /* Eintrag muss gemeldet werden */
}
}
}
/* Qualitaet des besten Weges (immer >= 1) */
/* oder 0 wenn es keinen Weg zum Ziel gibt */
unsigned
do_find_best_qual(INDEX index, PEER *notthis, PEER **retpp, int options)
{
int i;
PEER *pp = netp->peertab,
*bestpp = NULL;
ROUTE *rp;
unsigned bestqual = 0;
unsigned quality = 0;
for (i = netp->max_peers; i--; pp++)
{
if (!pp->used)
continue;
if (pp == notthis)
continue;
if ((pp->options & options) == 0)
continue;
rp = pp->routes + index;
quality = getquality(rp->quality, pp);
if ((quality && quality < bestqual) || !bestqual)
{
bestpp = pp; /* Route und Peer merken */
bestqual = quality;
}
}
if (retpp)
*retpp = bestpp; /* besten Nachbarn liefern */
return (bestqual); /* und Qualitaet als Rueckgabewert */
}
unsigned
getquality(unsigned route_qual, PEER *pp)
{
ULONG qual;
if (route_qual == 0 || pp->quality == 0)
return (0);
if (pp->typ <= NETROM)
{
qual = ((ULONG)route_qual) + pp->quality;
if (qual > HORIZONT)
qual = HORIZONT;
return ((unsigned)qual);
}
else
return (route_qual);
}
/* find_route() wird vom L7 benutzt, um einen Connect zu einem Node
* aufzubauen. Dies kann ein dummer L2 sein (Local), ein
* L2 (Flexnet) oder ein L4 QSO (NetRom).
* Wegen Flexnet sieht das Addressfeld bei einem Connect recht witzig
* aus:
* fm DB0SRC to DB0DST via DB0MY DB0DUM DB0NBR
* DB0MY ist das eigene Rufzeichen (myid), DB0DUM ein schlichter L2-
* Wassertraeger und DB0NBR der Nachbar. DB0DUM entfaellt in der Regel.
* Besondere Vorkehrung wird fuer die ausgefallenen Nachbarn getroffen,
* sie stehen eventuell nicht in der Nodes-Liste, aber wir kennen sie
* ja noch als Nachbarn.
* In dest.call steht das Ziel-Call, call ist eventuell nur ein Nachbar
* auf dem Weg dorthin.
*/
int l3_find_route(char *call, DEST *dest)
{
int max_peers = netp->max_peers;
INDEX index;
PEER *bestpp;
PEER *pp;
int i;
int ssid;
char *id;
int maske = DG | VC | VC_FAR; /* erstmal alles erlaubt */
if ((index = find_node_this_ssid(call)) == NO_INDEX)
{
/* Kein Node, ist es vielleicht ein Alias ? */
if ((index = find_alias(call)) == NO_INDEX)
{
/* Da das genaue Ziel nicht gefunden wurde, koennen wir noch nach dem */
/* SSID-Bereich ueber Flexnet-Nachbarn suchen */
if ((index = find_node_ssid_range(call)) != NO_INDEX)
{
/* Wir haben einen Flexnet-Weg gefunden - dann duerfen wir nachher auch */
/* nur ueber einen Flexnet-Weg connecten */
maske = FLEX_MASK;
}
}
}
if (index != NO_INDEX)
{
if (find_best_qual(index, &bestpp, maske) > 0)
{
dest->via[0] = NUL;
cpyid(dest->nbrcal, bestpp->l2link->call);
if (bestpp->typ > NETROM)
cpyidl(dest->via, bestpp->l2link->digil);
/*
* Wenn des Ziel nicht in den SSID-Bereich des Nachbarn passt,
* muessen wir das Nachbarrufzeichen in des via-Feld aufnehmen.
*/
id = netp->nodetab[index].id;
ssid = SSID(id);
if ( (!cmpcal(id, bestpp->l2link->call))
|| (ssid < SSID(bestpp->l2link->call))
|| (ssid > bestpp->l2link->ssid_high))
addid(dest->via, bestpp->l2link->call);
dest->port = bestpp->l2link->port;
dest->typ = bestpp->typ;
dest->np = netp->nodetab+index;
#ifdef THENETMOD
if ( (bestpp->typ == THENET) /* Segment ist ein THENET-Typ */
&&(dest->typ != 'U') /* wenn kein "direkt ('U')" markiert ist. */
&&(bestpp->nbrl2l == NULL)) /* und kein aktiver Link. */
connbr(bestpp); /* Link neu aufbauen. */
#endif /* THENETMOD */
return(NODE_AVAILABLE); /* Ziel ist erreichbar */
}
return(NODE_DOWN);
}
/* wenn direkter Nachbar nicht erreichbar, dies mitteilen */
for (pp = netp->peertab, i = 0; i < max_peers; pp++, i++)
if (pp->used)
if (cmpid(pp->l2link->call, call))
#ifndef CONNECTMOD_NODE_AVAI
if (!pp->quality) {
dest->typ = pp->typ;
cpyid(dest->nbrcal, myid);
return(NODE_DOWN); /* Nachbar unerreichbar */
}
#else
{
/* Auch wenn der Nachbar "unerreichbar" sein */
/* sollte versuchen wir es ueber einen L2_link.*/
dest->port = pp->l2link->port; /* L2-Port setzen. */
dest->typ = 'U'; /* wir rufen direkt. */
return(NODE_AVAILABLE); /* Ziel ist erreichbar */
}
#endif /* CONNECTMOD_NODE_AVAI */
return(NODE_UNKNOWN); /* Ziel nicht gefunden */
}
/*----------------------------------------------------------------------*/
/* Feststellen, ob zu einem Node noch ein Weg existiert. Wenn es keinen */
/* aktiven Weg mehr gibt, wird dies dem L4 gemeldet. Dieser traegt dann */
/* alle aktiven L4-Verbindungen aus. */
/* Da wir die Wege nach der Qualitaet sortieren, reicht es zu pruefen, */
/* ob der beste Weg ausgefallen ist. In diesem Fall erfolgt die Meldung */
/* an den L4. */
/* Diese Routine wird nach jeder Veraenderung der Qualitaet eines Weges */
/* aufgerufen. */
/*----------------------------------------------------------------------*/
BOOLEAN
check_destot(INDEX index) /* ueberprueft, ob es noch verwendbare */
{ /* Wege zu einem Ziel gibt */
if (find_best_qual(index, NULL, DG) == 0)
{
destot(index);
return (TRUE);
}
return (FALSE);
}
/*----------------------------------------------------------------------*/
void
check_all_destot(void)
{
INDEX index;
int max_nodes = netp->max_nodes;
for (index = 0; index < max_nodes; index++)
check_destot(index);
}
/*----------------------------------------------------------------------*/
void
destot(INDEX index) /* Ziel ist nicht mehr erreichbar */
{
MBHEAD *mbp,
*nextmbp;
NODE *totnod = netp->nodetab + index;
l3tol4(totnod); /* an L4 melden: Knoten wird entfernt */
for (mbp = (MBHEAD *)l3txl.head; /* L4 Sendeliste */
mbp != (MBHEAD *)&l3txl.head; /* durchgehen */
mbp = nextmbp)
{
nextmbp = (MBHEAD *)mbp->nextmh;
if ((NODE *)mbp->l2link == totnod)
{ /* dieser Node? */
ulink((LEHEAD *)mbp);
dealmb(mbp);
}
}
}
/* den besten Weg zu einem Segment feststellen (wenn es mehrere gibt) */
void
update_primary_peer(char *id)
{
PEER *peertab = netp->peertab; /* Segment-Tabelle */
PEER *pp;
PEER *bestpp = NULL;
ULONG quality;
ULONG bestqual = 0;
/* den primaeren Weg suchen und merken */
for (pp = peertab; pp < &peertab[netp->max_peers]; pp++)
if (pp->used)
{
if (cmpid(pp->l2link->call, id))
{
if (bestpp)
{
quality = pp->quality;
if ((quality && quality < bestqual) || !bestqual)
{
bestpp = pp;
bestqual = quality;
}
}
else
{
bestpp = pp;
bestqual = pp->quality;
}
}
}
/* und dann in allen Wegen (zu dem Nachbarn) eintragen */
for (pp = peertab; pp < &peertab[netp->max_peers]; pp++)
if (pp->used)
if (cmpid(pp->l2link->call, id))
pp->primary = bestpp;
}
/* Kennen wir das Ziel als Ident? */
INDEX
find_alias(char *ident)
{
NODE *np = netp->nodetab; /* NET/ROM-Tabelle durchsuchen */
INDEX i;
int max_nodes = netp->max_nodes;
for (i = 0; i < max_nodes; i++, np++)
if (np->id[0]) /* Eintrag existiert? */
if (cmpals(ident, np->alias))
return (i);
return (NO_INDEX); /* nix gefunden */
}
/* Rufzeichen suchen */
BOOLEAN
iscall(const char *id, NODE **retnp, PEER **bestpp, int options)
{
INDEX index;
/* Call ueber genaues Ziel oder/und ueber SSId suchen */
if ((index = find_node_this_ssid(id)) == NO_INDEX)
index = find_node_ssid_range(id);
if (index != NO_INDEX)
{
if (retnp)
*retnp = netp->nodetab + index;
return (find_best_qual(index, bestpp, options) != 0); /* beste Qual */
}
return (FALSE); /* nix gefunden */
}
/* End of src/l3tab.c */