TheNetNode-CB/src/l3misc.c

1305 lines
44 KiB
C
Executable File

/************************************************************************/
/* */
/* ***** ***** */
/* ***** ***** */
/* ***** ***** */
/* ***** ***** */
/* *************** *************** */
/* ***************** ***************** */
/* *************** *************** */
/* ***** ***** TheNetNode */
/* ***** ***** Portable */
/* ***** ***** Network */
/* ***** ***** Software */
/* */
/* File src/l3misc.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"
NETWORK *netp = NULL;
static int get_next_prim(int);
static void init_network(void);
static void brosrv2(void);
static void brosrv10(int);
static void brosrv60(void);
static void brosrv360(int, PEER *);
static void netrom_status(PEER *, WORD);
static void mstatus(PEER *, WORD);
static BOOLEAN brotim10 = FALSE;
#ifdef AUTOROUTING
static PEER *ReadLink(UBYTE pid);
#endif /* AUTOROUTING */
static int
get_next_prim(int num) /* naechste Primzahl berechnen */
{
int i, j;
for (i = num; ; i++) /* intuitive Methode ausreichend */
{
for (j = 2; j < i; j++)
if (i % j == 0)
break;
if (i == j) /* eine Primzahl gefunden */
return(i);
}
}
/* einen Router initialisieren und Tabellen anlegen */
BOOLEAN register_network(int max_peers, int max_nodes)
{
char huge *memp;
memp = (char *)calloc(1, sizeof(NETWORK)+
sizeof(NODE)*max_nodes+
sizeof(PEER)*max_peers);
if (memp) {
netp = (NETWORK *) memp; memp += sizeof(NETWORK);
netp->max_peers = max_peers;
netp->max_nodes = max_nodes;
netp->peertab = (PEER *) memp; memp += sizeof(PEER)*netp->max_peers;
netp->nodetab = (NODE *) memp /*, memp += sizeof(NODE)*netp->max_nodes */;
inithd(&netp->nodelis);
return(TRUE);
}
return(FALSE);
}
/* einen Router deinitialisieren */
void unregister_network(void)
{
free(netp);
}
/************************************************************************\
* *
* Netzwerk-Heap initialisieren *
* *
\************************************************************************/
static void
init_network(void)
{
char *s;
if ((s = getenv("TNNCFG")) != NULL)
sscanf(s, "%d,%d", &max_nodes, &max_peers);
max_nodes = max(max_nodes, 1);
max_peers = max(max_peers, 1);
if (!register_network(max_peers, get_next_prim(max_nodes)))
memerr();
xprintf("*** NETWORK startup, %d Nodes, %d Neighbours\n",
netp->max_nodes, netp->max_peers);
}
/************************************************************************\
* *
* Initialisierung des Level 3 *
* *
* FlexNet und Net/ROM Router intialisieren, Ziellisten loeschen. *
* *
\************************************************************************/
void
l3init(void) /* Level 3 initialisieren */
{
inithd(&l3rxfl); /* Liste empfangene Frames loeschen */
inithd(&l3txl); /* Liste zu sendende Frames loeschen */
init_network();
}
/************************************************************************/
/* */
/* Informationstransfer von Level3 zum Level2 */
/* Uebergeben werden reine Datenpackete ohne AX.25-Header. Diese werden */
/* dann an den angegebenen Link gehaengt und mit der gewuenschten PID */
/* gesendet. Grosse Frames (> 256 Bytes) werden fragmentiert und mit */
/* PID 0x08 gesendet (die gewuenschte PID wird im 1. Fragment ueber- */
/* mittelt). */
/* */
/************************************************************************/
void
i3tolnk(UBYTE pid, LNKBLK *linkp, MBHEAD *imbp)
{
int anz_frag,
info;
MBHEAD *tmpmbp;
BOOLEAN frame1 = TRUE;
info = ((imbp->mbpc) - (imbp->mbgc)); /* Laenge bestimmen */
ptctab[g_uid(linkp, L2_USER)].infotx += info;
#ifndef THENETMOD
linkp->noatou = ininat;
#else /* L4TIMEOUT */
linkp->noatou = SetL4Timeout(); /* L2/L4-Timeout setzen. */
#endif /* THENETMOD */
if (info < 257)
{
imbp->l2fflg = pid; /* PID uebernehmen */
imbp->repeated = 0;
relink((LEHEAD *)imbp, /* -> ab in den Link */
(LEHEAD *)linkp->sendil.tail);
++linkp->tosend; /* ein Sendepaket mehr */
}
else
{
/* fuer grosse Pakete generieren wir AX25-Fragmente */
anz_frag = info / 255; /* wieviele Folgefragmente? */
if (anz_frag > 127) /* zu gross geht nicht */
{
dealmb(imbp);
return;
}
do
{
tmpmbp = (MBHEAD *)allocb(ALLOC_MBHEAD); /* Buffer holen */
tmpmbp->l2fflg = L2CFRAG; /* wir senden mit PID 08 */
tmpmbp->repeated = 0;
if (frame1)
{
#ifdef __WIN32__
putchr((char)(anz_frag | 0x80), tmpmbp);/* es folgen n Fragmente */
#else
putchr(anz_frag | 0x80, tmpmbp);/* es folgen n Fragmente */
#endif /* WIN32 */
putchr(pid, tmpmbp); /* mit pid */
frame1 = FALSE;
}
else
#ifdef __WIN32__
putchr((char)anz_frag, tmpmbp); /* es folgen n Fragmente */
#else
putchr(anz_frag, tmpmbp); /* es folgen n Fragmente */
#endif /* WIN32 */
while (tmpmbp->mbpc < 256) /* max. 256 Bytes im Fragment */
{
if (!(imbp->mbpc - imbp->mbgc)) /* Frameende */
break;
putchr(getchr(imbp), tmpmbp); /* Daten umkopieren */
}
rwndmb(tmpmbp); /* zurueckspulen */
relink((LEHEAD *)tmpmbp, /* in die Sendeliste damit */
(LEHEAD *)linkp->sendil.tail);
++linkp->tosend; /* ein Frame mehr zu senden */
} while (anz_frag-- > 0);
/* wir sind fertig */
dealmb(imbp);
}
}
/*----------------------------------------------------------------------*/
/* l3rx() Empfangene Frames der Nachbarn verarbeiten. */
/*----------------------------------------------------------------------*/
void
l3rx(void)
{
PEER *pp;
int max_peers = netp->max_peers;
static int peer = 0;
if (++peer >= max_peers)
peer = 0;
if (peer < max_peers)
{
pp = &netp->peertab[peer];
if (pp->used)
{
switch (pp->typ)
{
case FLEXNET:
flexnet_rx(pp);
break;
case NETROM:
case TNN:
case THENET:
case INP:
netrom_rx(pp);
}
}
}
}
/*..................................................................... */
/*.. Empfangsliste abgearbeitet, nun zu sendende Frames verarbeiten .. */
/*..................................................................... */
void
l3tx(void) /* Level 3 Service */
{
UWORD rxgetc; /* Getcount des Frames */
MBHEAD *mbp; /* Pointer auf aktuellen Framekopf */
NODE *dstnod;
PEER *bestpp;
MHEARD *mhp;
/* solange L3-Sende-Liste nicht leer */
while ( (mbp = (MBHEAD *)l3txl.head)
!= (MBHEAD *)&l3txl.head)
{
ulink((LEHEAD *)mbp); /* Frame aushaengen */
dstnod = (NODE *)mbp->l2link; /* Pointer auf Nachbarn */
if (dstnod == NULL)
dstnod = netp->nodetab
+ find_node_this_ssid(mbp->destcall);
if ( nmbfre > 14 /* Platz im Speicher? */
&& (valcal(dstnod->id) == YES)
&& find_best_qual((int)(dstnod - netp->nodetab),
&bestpp, DG) > 0)
{
rwndmb(mbp); /* Pointer auf Ausgangsstellung */
getchr(mbp); /* alles initialisieren */
--mbp->mbbp;
rxgetc = mbp->mbpc; /* Framelaenge merken */
mbp->mbpc = 1; /* auf Anfang */
putfid(myid, mbp); /* Absender ins Frame */
putfid(dstnod->id, mbp); /* Ziel ins Frame */
*(mbp->mbbp - 1) |= 1; /* Ende der Adresse setzen */
#ifdef __WIN32__
putchr((char)timliv, mbp); /* Lebensdauer setzen */
#else
putchr(timliv, mbp); /* Lebensdauer setzen */
#endif /* WIN32 */
mbp->mbpc = rxgetc; /* Putcount zurueck */
rwndmb(mbp); /* Pointer wieder aufziehen */
toneig(bestpp, mbp); /* Frame an besten Nachbarn */
/* MH-Liste */
if ((mhp = mh_lookup(&l3heard, dstnod->id)) != NULL)
mhp->tx_bytes += (mbp->mbpc);
}
else /* kein Ziel def. o. kein Platz */
dealmb(mbp); /* Frame wegwerfen */
}
}
/*..................................................................... */
/*.... sonstige Funktionen abarbeiten ............................... */
/*..................................................................... */
void
l3rest(void)
{
if (brotim10)
brosrv2();
}
/*----------------------------------------------------------------------*/
void
brosrv(void)
{
static int tim10 = 1;
static int tim60 = 1;
local_flex_srv(); /* Time-Server der anderen Module */
if (++tim60 >= 60) /* eine Minute vorbei */
{
tim60 = 0;
brosrv60();
}
if (++tim10 >= 10)
{ /* 10 Sekunden vorbei */
drop_unreachable_nodes();
tim10 = 0;
brotim10 = TRUE;
}
}
static void
brosrv2(void)
{
static int peer = 0;
int max_peers = netp->max_peers;
if (++peer >= max_peers)
{
peer = 0;
brotim10 = FALSE;
}
if (peer < max_peers)
brosrv10(peer);
}
/************************************************************************/
/* 10-sekuendlicher Zeitserver */
/************************************************************************/
static void
brosrv10(int i)
{
PEER *pp = &netp->peertab[i];
int broint;
if (pp->used) /* nur benutzte Peers bearbeiten */
{
if (pp->typ > NETROM) /* nur fuer NETROM und verwandte Protokolle */
return;
if (nmbfre < 300) /* nicht mehr genug Speicher */
return;
#ifdef THENETMOD
if (pp->typ == THENET) /* Segment ist ein THENET. */
return; /* Funktion BroadCastBake() ist fuer den Rest verantwortlich. */
#endif /* THENETMOD. */
if (pp->nbrl2l == NULL) /* noch kein Link? */
return; /* den grossen UI-Broadcast sparen wir */
/* uns, uns hoert ja eh keiner. */
/* wenn der Link sich noch im Aufbau befindet oder ziemlich verstopft */
/* ist, wird die Nodes-Information zurueckgehalten. */
if ( pp->nbrl2l->state < L2SIXFER
|| pp->nbrl2l->tosend > 20) /* Link ist voll */
return;
/* Bei INP senden wir erst los, wenn beide Messungen da sind. */
if (pp->typ == INP)
if (!pp->my_quality || !pp->his_quality)
return;
/* Wollen wir einen INP-Link haben, haben einen Connect aber noch */
/* nicht zu INP umgeschaltet und die RTT-Messung laeuft noch, dann */
/* senden wir keinen Nodes-Broadcast irgendeiner Art */
if ((pp->soll_typ == INP) && (pp->typ != INP) && (pp->rttstart != 0))
return;
#ifdef L4NOBAKE
if (pp->typ == NETROM) /* Steht noch ein Routing-Typ fest, senden */
return; /* wir keine Bake irgendeiner Art. */
#endif /* L4NOBAKE */
if (pp->typ != THENET)
inform_peer(pp, CHANGES); /* nur die Aenderungen durchsagen */
if (pp->typ != INP)
{
broint = (pp->typ == TNN) ? broint_i : broint_ui;
if (++pp->brotim >= broint)
{
/* Broadcast anfordern */
pp->brotim = 0;
/* und weg damit */
inform_peer(pp, ALL);
}
}
/* Peer ist INP-Nachbar, den Broadcast-Timer geringfuegig anders */
/* benutzen als bei den anderen Typen */
if (pp->typ == INP)
{
if (++pp->brotim >= 360) /* jede Stunde einmal alles melden */
{
pp->brotim = 0; /* merken dass wir gebroadcastet haben */
brosrv360(netp->max_nodes, pp);
}
}
}
}
/************************************************************************/
/* minuetlicher Zeitserver */
/************************************************************************/
static void
brosrv60(void)
{
INDEX index;
NODE *np;
ROUTE *rp;
PEER *pp;
int i;
int max_nodes = netp->max_nodes;
#ifdef THENETMOD
BroadCastBake(); /* Eine Broadcast-Nodes Bake zum Nachbarn senden. */
#endif /* THENETMOD */
/* alle Peers durchgehen */
for (i = netp->max_peers, pp = netp->peertab; i--; pp++)
{
if (!pp->used) /* unbenutzte interessieren nicht */
continue;
#ifdef THENETMOD
if (OBSinitTimer(pp)) /* Restlebensdauer fuer Rundspruch minimieren. */
continue; /* Segment wurde geloescht, zum naechsten. */
#endif /* THENETMOD */
/* alle Nodes dieses Peers durchgehen */
for (index = 0, np = netp->nodetab, rp = pp->routes;
index < max_nodes;
index++, np++, rp++)
{
if (np->id[0]) /* nur benutzte Eintraege */
{
if (rp->lt > max_lt) /* bei zu hoher Lifetime abmelden */
update_route(pp, index, 0);
if (rp->timeout) /* Route mit Timeout ? */
{
if (--rp->timeout == 0) /* Timeout abgelaufen ? */
update_route(pp, index, 0); /* ja, dann abmelden */
}
else
if (!pp->secured) /* ungesicherte Route ? */
#ifndef THENETMOD
rp->timeout = ROUTE_TIMEOUT; /* dann Timeout neu setzen */
#else
rp->timeout = obcini; /* dann Timeout neu setzen */
#endif /* THENETMOD */
} /* if (np->id[0]) */
} /* for */
} /* for */
}
/************************************************************************/
/* stuendlicher Zeitserver */
/************************************************************************/
static void
brosrv360(int max_nodes, PEER *pp)
{
NODE *np = netp->nodetab;
ROUTE *rp = pp->routes;
int x;
#if MAX_TRACE_LEVEL > 2
int node_count = 0;
char notify_call[10];
#endif
/* alle Eintraege durchgehen dabei keine Ruecksicht auf die */
/* Horizonte nehmen, dies soll sicherstellen, dass hier auch */
/* Nodes an den Nachbarn gemeldet werden die bisher immer */
/* durch die Filter gefallen sind weil die Aenderungen zu */
/* gering waren. */
for (x = max_nodes; x--; np++, rp++)
{
if (!np->id[0]) /* freier Eintrag? */
continue;
/* Nodes die zur Abmeldung ausstehen nicht anfassen */
if (rp->quality == 0 && rp->reported_quality != 0)
continue;
rp->reported_quality = 0; /* Eintrag muss gemeldet werden */
#if MAX_TRACE_LEVEL > 2
node_count++;
}
call2str(notify_call, pp->l2link->call);
notify(3, "broadcasting INP nodes to %s (%u of %u nodes triggered for update)", notify_call, node_count, max_nodes);
#else
}
#endif
}
/*----------------------------------------------------------------------*/
/* 6 Zeichen aus Message-Puffer lesen und nach Buffer schreiben */
/* Rueckgabe: TRUE = hat funktioniert */
/*----------------------------------------------------------------------*/
BOOLEAN
ge6chr(char *buffer, MBHEAD *mbp)
{
int i,
ch;
for (i = 6;
(mbp->mbpc > mbp->mbgc) && i; /* noch Zeichen da? */
i--)
{
*buffer++ = ch = getchr(mbp);
if (ch < ' ')
return (FALSE); /* ungueltiges Zeichen */
if (ch > 127)
return (FALSE);
}
return (i == 0); /* waren genug Zeichen da? */
}
/************************************************************************/
/* 6 Zeichen aus Buffer in Message-Puffer schreiben */
/************************************************************************/
void
pu6chr(char *buffer, MBHEAD *mbp)
{
WORD i;
for (i = 0; i < 6; ++i)
putchr(*buffer++, mbp);
}
/************************************************************************/
/* Eine Status-Aenderung fuer NET/ROM behandeln */
/************************************************************************/
static void
netrom_status(PEER *pp, WORD status)
{
#ifdef PORT_L2_CONNECT_TIME
UWORD port = 0;
#endif
if (pp->typ <= NETROM)
{ /* nur NET/ROM interessiert */
switch (status)
{
case L2MCONNT:
connect_peer(pp);
break;
case L2MLREST:
case L2MLRESF:
reset_peer(pp);
break;
case L2MFAILW :
case L2MDISCF :
#ifdef PORT_L2_CONNECT_TIME
port = pp->l2link->port;
pp->l2link->sabmtime = portpar[port].l2_connect_time;
#endif /* PORT_L2_CONNECT_TIME */
if ( (pp->typ != THENET) /* Alle Typen ausser THENET. */
||((pp->typ == THENET) /* oder THENET-Typ und */
&& (status == L2MFAILW))) /* Status FAILURE. */
{ /* Route als ausgefallen melden. */
update_peer_quality(pp, 0L, DONT_CHANGE_QUAL);
memset(pp->routes, 0, netp->max_nodes * sizeof(ROUTE));
pp->num_routes = 0; /* Routen loeschen */
drop_unreachable_nodes(); /* Routes/Nodes loeschen */
#ifdef AUTOROUTING
if (pp->l2link->ppAuto == AUTO_ROUTE)/* Segment ist eine Auto-Route.*/
{
#ifdef AXIPR_HTML
/* Protokoll fuer HTML-Ausgabe setzen. */
SetHTML(pp->l2link->port, pp->l2link->call, NULL, FALSE);
#endif /* AXIPR_HTML */
/* Link austragen. */
unregister_neigb(pp->l2link->call, pp->l2link->digil, pp->l2link->port);
return;
}
#endif /* AUTOROUTING */
}
break;
default:
disconnect_peer(pp);
update_peer_quality(pp, 0, DONT_CHANGE_QUAL);
check_all_destot();
break;
}
pp->rttstart = 0;
pp->rtt_time = 0;
switch (pp->typ)
{
case TNN:
case INP:
set_peer_typ(pp, NETROM);
}
pp->brotim = 0; /* mit Broadcast beginnen */
}
}
/*----------------------------------------------------------------------*/
/* eine Status-Aenderung an alle L3-Module senden */
/* Die Module muessen selber darauf achten, das sie die Meldung nur */
/* annehmen, wenn der Typ des pp stimmt! */
/*----------------------------------------------------------------------*/
static void
mstatus(PEER *pp, WORD status)
{
netrom_status(pp, status); /* neuen Status melden */
flex_status(pp, status); /* an NETROM & FlexNet */
local_status(pp, status); /* und unsere Locals */
}
/*----------------------------------------------------------------------*/
/* Neue Status-Meldung verarbeiten */
/* 0=nicht verwendet, 1=connectet, 2=disconnectet, 3=busy, 4=Failure */
/*----------------------------------------------------------------------*/
BOOLEAN
l2tol3(WORD status)
{
PEER *pp;
#if MAX_TRACE_LEVEL > 2
char notify_call[10];
#endif
switch (status)
{
case L2MCONNT: /* CONNECTED to */
case L2MLREST: /* LINK RESET to */
if ((pp = ispeer()) == NULL)
return (l2toip(status)); /* der L7 ist dran */
newnbr(pp); /* Nachbar eintragen */
mstatus(pp, status); /* Status melden */
return (TRUE); /* Status verarbeitet */
case L2MLRESF: /* LINK RESET from */
if ((pp = ispeer()) == NULL)
return (l2toip(status)); /* der L7 ist dran */
mstatus(pp, status); /* Status melden */
disnbr(pp); /* Nachbar inaktiv */
newnbr(pp); /* Nachbar eintragen */
mstatus(pp, status); /* Status melden */
#if MAX_TRACE_LEVEL > 2
call2str(notify_call, rxfhdr + L2IDLEN);
notify(3, "Linkreset %6s", notify_call);
#endif
return (TRUE); /* Status verarbeitet */
case L2MDISCF: /* DISCONNECTED from */
case L2MBUSYF: /* BUSY from */
case L2MFAILW: /* LINK FAILURE with */
if ((pp = ispeer()) == NULL)
return (l2toip(status)); /* der L7 ist dran */
#ifdef AXIPR_UDP
newnbr(pp); /* Nachbar eintragen */
#endif
mstatus(pp, status); /* melden */
disnbr(pp); /* Nachbar inaktiv */
#ifdef AUTOROUTING
/* Segment steht auf Auto-Route. */
if (pp->l2link->ppAuto == AUTO_ROUTE)
return(FALSE);
else
#endif /* AUTOROUTING */
return (TRUE); /* nicht in den L7 */
case L2MFRMRF: /* FRAME REJECT from */
case L2MFRMRT: /* FRAME REJECT to */
if ((pp = ispeer()) == NULL)
return (l2toip(status)); /* der L7 ist dran */
return (TRUE); /* Status verarbeitet */
case L2MBUSYT: /* BUSY to */
return (TRUE); /* hier abfangen */
}
return (FALSE); /* ungueltige Meldung */
}
/************************************************************************\
* *
* "to level 3 switch" *
* *
* Aus I- oder UI-Frame (Framekopf fbp, Getzeiger/Zaehler auf 1. Byte *
* hinter Level-2-Adressfeld) PID holen, falls vorhanden. Falls es nicht *
* Level-2-PID ist, das Paket an die Level-3-Empfangsframeliste l3rxfl *
* haengen. Im Framekopf wird in jedem Fall l2fflg auf PID, wenn *
* vorhanden, oder 0 gesetzt, l2link auf den aktuellen Link (lnkpoi). *
* Fuer Level-3-Frames wird der Nachbar bestimmt. *
* *
* Return: TRUE - das I/UI-Frame hat ein Nicht-Level-2-PID und wurde an *
* die Level-3-Empfangsframeliste gehaengt *
* FALSE - Frame hat Standard-Level-2-PID *
* *
\************************************************************************/
BOOLEAN
tol3sw(MBHEAD *fbp)
{
PEER *pp;
UBYTE pid = fbp->l2fflg;
int state;
int filter_ip_frame;
fbp->l2link = lnkpoi; /* Linkverbindung von diesem Frame */
fbp->l2port = rxfprt; /* Auf diesem Port kam das Frame */
if (lnkpoi)
{
state = ptctab[g_uid(lnkpoi, L2_USER)].state;
filter_ip_frame = (state == D_IPLINK || state == U_IPLINK);
}
else
filter_ip_frame = TRUE;
/* Protokolle, die nicht an einen Nachbarn gebunden sind, direkt */
/* abfangen */
switch (pid)
{
#ifdef IPROUTE
case L2CIP:
if (filter_ip_frame)
{
if (fbp->l2link) /* fuer Level 2 Links Info zaehlen */
ptctab[g_uid(fbp->l2link, L2_USER)].inforx
+= (fbp->mbpc - fbp->mbgc);
relink((LEHEAD *)fbp, (LEHEAD *)iprxfl.tail);
return (TRUE); /* Frame verarbeitet */
}
else
break;
case L2CARP:
if (filter_ip_frame)
{
if (fbp->l2link) /* fuer Level 2 Links Info zaehlen */
ptctab[g_uid(fbp->l2link, L2_USER)].inforx
+= (fbp->mbpc - fbp->mbgc);
relink((LEHEAD *)fbp, (LEHEAD *)arprxfl.tail);
return (TRUE); /* Frame verarbeitet */
}
else
break;
#endif
#ifdef L2PROFILER
case 0x12: /* Spielzeug fuer DB7KG (PID 12) */
dealmb(fbp);
return (TRUE);
#endif
}
#ifndef AUTOROUTING
if ((pp = ispeer()) == NULL) /* kein Frame fuer einen Nachbarn? */
return (FALSE); /* zum Level 7 durchlassen */
#else
/* Pruefen, ob sich jemand Automatisch anbinden will. */
/* Wir untersuchen anhand der PID das Segment. */
if ((pp = ReadLink(pid)) == NULL)
return (FALSE); /* zum Level 7 durchlassen */
#endif
/* Hier landen nur Frames, die zu einem bestimmten Nachbarn gehoeren. */
/* Nun muss noch Protokoll-ID und Protokoll verglichen werden. */
if (fbp->l2link) /* fuer Level 2 Links Info zaehlen */
ptctab[g_uid(fbp->l2link, L2_USER)].inforx
+= (fbp->mbpc - fbp->mbgc);
switch (fbp->l2fflg)
{
/* Protokoll/Nachbartyp feststellen */
/* NET/ROM-Protokoll fuer TheNet, TheNetNode, TNX1J(TexNet) */
/* KA9Q und Devirate, Wampes, Linux usw., BPQ, andere Switches */
case L2CTEXNET: /* fuer TexNet/TheNetX1J */
case L2CNETROM:
if (pp->typ > NETROM)
break; /* nicht richtiger Nachbar-Typ? */
rxneig(pp, fbp); /* Frame zur Nachbar-Bearbeitung */
return (TRUE); /* ... und fertig */
/* Flexnet Protokoll fuer */
case L2CFLEXNET: /* Flexnet eben, BayCom, Digiware */
if (pp->typ != FLEXNET)
break;
if (lnkpoi == NULL)
break; /* UI-Frames sind verboten */
rxneig(pp, fbp); /* FlexNet-Internode-Frame */
return (TRUE); /* toL7: Frame verarbeitet */
#ifdef IPROUTE /* IP/ARP auf Interlink ist erlaubt */
case L2CIP:
relink((LEHEAD *)fbp, (LEHEAD *)iprxfl.tail);
return (TRUE); /* Frame verarbeitet */
case L2CARP:
relink((LEHEAD *)fbp, (LEHEAD *)arprxfl.tail);
return (TRUE); /* Frame verarbeitet */
#endif
}
dealmb(fbp); /* unpassende/unbekannte PID, falscher */
/* Nachbar, Fehler... */
return (TRUE);
}
/*----------------------------------------------------------------------*/
/* Kopiert zwei Calls ins Ziel (via-Beschraenkung fuer Linkeintraege) */
/*----------------------------------------------------------------------*/
void
cpyidl2(char *dest, const char *source)
{
int count = 2;
while (*source != '\0' && count-- > 0)
{
memcpy(dest, source, L2IDLEN);
source += L2IDLEN;
dest += L2IDLEN;
}
*dest = '\0';
}
#define TO 0 /* dir */
#define BACK 1
#define NOTKNOWN 1 /* tome und ret */
#define ISLOCAL 2
#define VIAFLEX 3
#define DIRECT 4
#define LOOPED 5
/* Diese Funktion analysiert die empfangenen NRR-Frames. */
/* Etliche Fehler werden erkannt und entsprechend reagiert. */
/* */
/* tome gibt an, ob mich das Frame was angeht */
/* ret besagt, ob das Frame zurueckgeschickt werden soll und wieso */
/* dir gibt die NRR-Richtung an */
/* looped ist wahr, wenn unsere ID im Hinweg vorkam und dir gleich TO */
void
nrr_rx(MBHEAD *mbp, PEER *rxpp)
{
NRRLIST list[30],
*l;
int nlist,
ret,
tome,
dir;
BOOLEAN looped;
PEER *topp;
if (!time_to_live) /* zuspaet */
return;
looped = tome = ret = FALSE;
dir = TO;
topp = NULL;
if (cmpid(desnod, myid)) /* das geht uns an... */
tome = DIRECT;
else if (iscall(desnod, NULL, /* sonst den besten Weg */
&topp, DG | VC | VC_FAR))
{ /* bestimmen */
if (topp->options & VC) /* ein local von uns */
tome = ISLOCAL;
else if (topp->options & VC_FAR) /* wuerde via flex gehen */
tome = VIAFLEX;
}
nlist = 0;
l = list;
while (mbp->mbpc - mbp->mbgc >= L2IDLEN + 1)
{ /* Eintrag da? */
if (getfid(l->id, mbp) == TRUE)
{
l->lt = getchr(mbp);
if (l->lt & ECHO_FLAG)
{ /* EchoFlag */
dir = BACK;
looped = FALSE;
}
if (dir == TO && cmpid(l->id, myid)) /* Loop in Hin-Liste */
looped = TRUE;
nlist++;
l++;
}
}
l->id[0] = '\0'; /* Liste beenden */
if ( !nlist /* leere Liste */
|| rxpp == topp) /* Loop in den Nodes */
return;
if (cmpid(list[0].id, myid))
{ /* das ist meine Anwort */
nrr2usr(list, time_to_live);
return;
}
if (dir == BACK && ( topp == NULL /* Ziel unbekannt */
|| tome == VIAFLEX)) /* bzw. Flex im Rueckweg */
return;
if (topp == NULL && !tome) /* Ziel unbekannt */
ret = NOTKNOWN;
else if (looped) /* Loop in der Liste */
ret = LOOPED;
else if (tome) /* wir sind das Ziel */
ret = tome;
if (ret)
{ /* Weg umdrehen */
cpyid(desnod, orgnod);
cpyid(orgnod, myid);
}
if (nlist < 29)
{ /* wir passen noch dran */
cpyid(l->id, myid);
l->lt = time_to_live + 1;
if (ret)
{
l->id[L2CALEN] &= 0x1f;
l->id[L2CALEN] |= (ret - 1) << 5; /* Fehler in SSID-Feld */
l->lt |= ECHO_FLAG;
}
l++;
l->id[0] = '\0'; /* Liste beenden */
}
send_nrr_frame(list);
}
/* Hier wird das NRR-Frame zusammengebastelt und verschickt */
void
send_nrr_frame(NRRLIST *l)
{
PEER *pp;
NODE *dstnod;
MBHEAD *mbp;
if (iscall(desnod, &dstnod, &pp, DG))
{
mbp = (MBHEAD *)allocb(ALLOC_MBHEAD);
putfid(orgnod, mbp);
putfid(desnod, mbp);
putchr(time_to_live, mbp);
putchr(l4hdr0, mbp);
putchr(l4hdr1, mbp);
putchr(l4hdr2, mbp);
putchr(l4hdr3, mbp);
putchr(l4hdr4, mbp);
while (*l->id)
{
putfid(l->id, mbp);
putchr(l->lt, mbp);
l++;
}
rwndmb(mbp);
toneig(pp, mbp);
}
}
/*----------------------------------------------------------------------*/
/* Diese Routine bereitet das Senden des NRR-Requestframes vor */
void
request_nrr(char *id, UID uid)
{
NRRLIST list[2];
cpyid(desnod, id); /* L3-Teil */
cpyid(orgnod, myid);
#ifdef __WIN32__
time_to_live = (char)timliv;
#else
time_to_live = timliv;
#endif /* WIN32 */
l4hdr0 = 0; /* L4-Teil */
l4hdr1 = 1;
l4hdr2 = uid >> 8;
l4hdr3 = uid & 0xFF;
l4hdr4 = 0;
cpyid(list[0].id, myid); /* Daten */
list[0].lt = time_to_live + 1;
list[1].id[0] = NUL;
send_nrr_frame(list);
}
/*----------------------------------------------------------------------*/
/* Diese Routine ermittelt, ob es auf einem Port Interlinks gibt */
BOOLEAN islinkport(int port)
{
PEER *pp;
int i;
for (i = 0, pp = netp->peertab; i < max_peers; i++, pp++)
if ((pp->used) && (pp->l2link->port == port))
return TRUE;
return FALSE;
}
/* TEST DG9OBU */
/*----------------------------------------------------------------------*/
/* Prueft, ob das Call id ein lokaler Eintrag bei uns ist. */
/* NO = kein Local von uns */
/* YES = ein Local von uns UND erreichbar (oder Local ohne Messung) */
/* ERRORS = ein Local von uns, aber derzeit nicht erreichbar */
/*----------------------------------------------------------------------*/
TRILLIAN islocal(const char* id)
{
PEER *pp;
register int i;
register int max_peers = netp->max_peers;
for (i = 0, pp = netp->peertab; i < max_peers; ++i, pp++)
{
if ( (pp->used)
&& (cmpid(id, pp->l2link->call)) /* Call + SSID stimmt */
)
{
if (pp->typ == LOCAL)
return YES;
else if (pp->typ == LOCAL_M)
return (pp->my_quality != 0) ? YES : ERRORS;
}
}
/* kein Local von uns */
return NO;
}
#ifdef PROXYFUNC
BOOLEAN isproxy(const char* id)
{
PEER *pp;
register int i;
register int max_peers = netp->max_peers;
for (i = 0, pp = netp->peertab; i < max_peers; ++i, pp++)
{
if ( (pp->used)
&& (cmpid(id, pp->l2link->call)) /* Call + SSID stimmt */
)
{
if (pp->proxy == TRUE)
return TRUE;
}
}
/* kein Local von uns */
return FALSE;
}
#endif
/* TEST DG9OBU */
/*----------------------------------------------------------------------*/
/* Bestimmt die aktuelle SSID-Range des Knotens. Es werden alle lokalen */
/* Nodes mit dem gleichen Call wie der Knoten, sowie das Knotencall */
/* selber ausgewertet. Die uebergebenen Variablen werden nur geaendert, */
/* wenn der aktuelle SSID-Bereich von den uebergebenen Werten abweicht. */
/*----------------------------------------------------------------------*/
void getSSIDrange(int *min, int *max)
{
PEER *pp;
register int i;
/* Knotencall auswerten */
if (SSID(myid) < *min)
*min = SSID(myid);
if (SSID(myid) > *max)
*max = SSID(myid);
/* Alle lokalen Links auswerten */
for (i = 0, pp = netp->peertab; i < max_peers; ++i, pp++)
if ( (pp->used) /* nur benutzte Eintraege auswerten */
&& (cmpcal(myid, pp->l2link->call)) /* Call stimmt, SSID egal */
&& (pp->l2link->alias[0] != '#') /* keine versteckten Locals */
&& ( (pp->typ == LOCAL) /* nur Locals, L+ muss erreichbar sein */
|| ((pp->typ == LOCAL_M) /* && (pp->my_quality != 0L) */ )
)
)
{
if (SSID(pp->l2link->call) < *min)
*min = SSID(pp->l2link->call);
if (SSID(pp->l2link->call) > *max)
*max = SSID(pp->l2link->call);
}
}
/* TEST DG9OBU */
/*----------------------------------------------------------------------*/
/* Bestimmt die aktuelle maximale SSID des Knotens. */
/* Naeheres siehe Funktion getSSIDrange(). */
/*----------------------------------------------------------------------*/
int maxSSID(void)
{
int ssid_low = 15;
int ssid_high = 0;
getSSIDrange(&ssid_low, &ssid_high);
return ssid_high;
}
/* TEST DG9OBU */
/*----------------------------------------------------------------------*/
/* Bestimmt, ob die uebergebene SSID im SSID-Bereich des Knotens liegt. */
/*----------------------------------------------------------------------*/
BOOLEAN SSIDinrange(int ssid)
{
int ssid_low = 15;
int ssid_high = 0;
getSSIDrange(&ssid_low, &ssid_high);
if ((ssid >= ssid_low) && (ssid <= ssid_high))
return TRUE;
return FALSE;
}
#ifdef AUTOROUTING
static int UpdateLink(char *call, int port, UWORD pid, PEER *pp)
{
switch(pid)
{
case L2CTEXNET: /* THENET, NETROM oder INP-TYP */
case L2CNETROM:
#ifdef AXIPR_HTML
SetHTML(port, /* Protokoll fuer HTML-Ausgabe setzen. */
call,
pp,
TRUE);
#endif /* AXIPR_HTML */
switch (portpar[port].poAuto) /* Modus. */
{
case L_THENET : /* THENET-TYP. */
return(THENET); /* THENET-TYP setzen. */
case L_INP : /* INP-TYP. */
return(INP); /* INP-TYP setzen. */
case L_INPFLEX : /* Voll-Modus. */
return(NETROM); /* Standard NETROM-Typ setzen. */
default :
return(EOF); /* Kein Eintrag liefern. */
}
break;
case L2CFLEXNET: /* FLEXNET-TYP */
#ifdef AXIPR_HTML
SetHTML(port, /* Protokoll fuer HTML-Ausgabe setzen. */
call,
pp,
TRUE);
#endif /* AXIPR_HTML */
switch (portpar[port].poAuto) /* Modus. */
{
case L_FLEXNET :
case L_INPFLEX :
return(FLEXNET); /* FLEXNET-TYP setzen. */
default:
return(EOF); /* Kein Eintrag liefern. */
}
} /* Switch */
return(EOF); /* Kein Eintrag liefern. */
}
/********************************************************/
/* */
/* Neues Segment anlegen. */
/* Je nach PID wird Link-Typ gesetzt. */
/* */
/********************************************************/
static PEER *AddLink(UWORD pid)
{
PEER *pp = NUL;
char digil[L2VLEN + 1] = "";
WORD typs = EOF;
if ((pp = ispeer()) == NULL)
{
#ifdef LINKSMODINFO
char Info[INFOSIZE + 1] = "AutoRoute";
#endif /* LINKSMODINFO */
/* Segment Updaten und Typ setzen. */
if ((typs = UpdateLink(rxfhdr + L2IDLEN, rxfprt, pid, pp)) == EOF)
return(NULL);
cpyid(digil, dheardcall(rxfhdr));
if (cmpid(rxfhdr + L2IDLEN, digil))
digil[0] = 0;
/* Einen Neuen Link-Nachbar eintragen. */
pp = register_neigb(rxfhdr + L2IDLEN, digil, rxfhdr + L2IDLEN, rxfprt, typs
#ifdef LINKSMODINFO
, Info
#endif /* LINKSMODINFO */
, AUTO_ROUTE);
/* Linkeintragung fehlgeschlagen. */
if (pp == NULL)
/* Kein Eintrag liefern. */
return(NULL);
/* Den aktuellen Nachbarn als connected eintragen.*/
newnbr(pp);
/* Nachbar ist ein Flexnet. */
if (pp->typ == FLEXNET)
/* Maxtime auf default stellen. */
pp->maxtime = 30000U;
/* Neues Segment liefern. */
return(pp);
}
/* Segment Updaten. */
UpdateLink(rxfhdr + L2IDLEN, rxfprt, pid, pp);
/* Segment liefern. */
return(pp);
}
/*****************************************************/
/* */
/* Pruefen, ob sich jemand Automtisch anbinden will. */
/* Anhand der PID wird das Segment ermittelt. */
/* */
/*****************************************************/
static PEER *ReadLink(UBYTE pid)
{
PEER *pp;
if ((pp = AddLink(pid)) == NULL)
/* Kein Segment gefunden. */
return(NULL);
/* Aktuelles Segment liefern. */
return(pp);
}
#endif /* AUTOROUTING */
/* End of src/l3misc.c */