951 lines
36 KiB
C
Executable File
951 lines
36 KiB
C
Executable File
/************************************************************************/
|
|
/* */
|
|
/* ***** ***** */
|
|
/* ***** ***** */
|
|
/* ***** ***** */
|
|
/* ***** ***** */
|
|
/* *************** *************** */
|
|
/* ***************** ***************** */
|
|
/* *************** *************** */
|
|
/* ***** ***** TheNetNode */
|
|
/* ***** ***** Portable */
|
|
/* ***** ***** Network */
|
|
/* ***** ***** Software */
|
|
/* */
|
|
/* File src/l2misc.c (maintained by: DF6LN) */
|
|
/* */
|
|
/* 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"
|
|
|
|
static void l2rest(void);
|
|
static void inilbl(void);
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* */
|
|
/* "level 2" */
|
|
/* */
|
|
/* Der Level 2. Es werden alle Level-2-internen Aktionen ausgefuehrt */
|
|
/* und Meldungen an hoehere Level weitergegeben (Informationstransfer */
|
|
/* von/zum Level 2 und Kommandos an den Level 2 geschehen von ausser- */
|
|
/* halb). */
|
|
/* */
|
|
/* Der Level 2 laeuft wie folgt ab : */
|
|
/* */
|
|
/* - Aufruf von l2init() */
|
|
/* */
|
|
/* - zyklisches Aufrufen von l2() */
|
|
/* */
|
|
/* Statusaenderungen im Level 2 (Connects, Disconnects, Failures, usw) */
|
|
/* werden hoeheren Leveln vom Level 2 aus ueber */
|
|
/* */
|
|
/* l2tolx(<status>) -> l2tol3(<status>), l2tol7(<status>,lnkpoi,2) */
|
|
/* */
|
|
/* mitgeteilt. */
|
|
/* */
|
|
/* Ein Connectwunsch wird dem Level 2 ueber das Besetzen eines leeren */
|
|
/* Linkblocks mit Quell- und Ziel- sowie Digicalls und Aufrufen von */
|
|
/* newlnk() mitgeteilt (lnkpoi zeigt auf Linkblock !). */
|
|
/* Ein newlnk() auf einen bestehenden Link erzeugt einen Link Reset. */
|
|
/* */
|
|
/* Ein Disconnectwunsch (oder bei mehrmaligem Aufruf der sofortige */
|
|
/* Disconnect) wird ueber das Setzen von lnkpoi auf den jeweiligen */
|
|
/* Linkblock und Aufruf von dsclnk() erreicht. */
|
|
/* */
|
|
/* Der Informationstransfer zum Level 2 geschieht von aussen durch */
|
|
/* Aufruf von itolnk(...), vom Level 2 durch itolx(..), welches dann */
|
|
/* fmlink() aus dem hoeheren Level aufruft. */
|
|
/* */
|
|
/* Ueber sdui(..) koennen unproto-Pakete (UI-Frames) gesendet werden. */
|
|
/* */
|
|
/* Level-3-Pakete (Level-3-UI-Pakete oder Infopakete in Sequenz eines */
|
|
/* Level-2-3-Links) werden ausgefiltert und in die Level-3-Frameliste */
|
|
/* eingehaengt. */
|
|
/* */
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
/* Die Reihenfolge der Bearbeitung ist hier entscheidend. Zuerst werden */
|
|
/* die empfangenen Frames verarbeitet, dann werden I-Frames erzeugt und */
|
|
/* erst dann wird ueber T1/T2 entschieden. */
|
|
|
|
void
|
|
l2(void)
|
|
{
|
|
clrstfl();
|
|
l2rx();
|
|
l2tx();
|
|
l2timr();
|
|
l2rest();
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
void
|
|
l2init(void)
|
|
{
|
|
WORD i;
|
|
|
|
inithd(&rxfl);
|
|
inithd(&stfl);
|
|
inithd(&trfl);
|
|
inithd(&freel);
|
|
inithd(&l2frel);
|
|
|
|
init_buffers();
|
|
|
|
for (i = 0; i < L2PNUM; ++i)
|
|
{
|
|
inithd(&txl2fl[i]);
|
|
inithd(&l2actl[i]);
|
|
}
|
|
|
|
for (i = 0, lnkpoi = lnktbl; i < LINKNMBR; ++i, ++lnkpoi)
|
|
{
|
|
lnkpoi->state = L2SDSCED;
|
|
lnkpoi->rcvd = lnkpoi->tosend = 0;
|
|
lnkpoi->tmbp = NULL;
|
|
lnkpoi->zael = 1; /* MultiConnect */
|
|
inithd(&lnkpoi->rcvdil);
|
|
inithd(&lnkpoi->sendil);
|
|
inilbl();
|
|
reslnk();
|
|
relink((LEHEAD *)lnkpoi, (LEHEAD *)l2frel.tail);
|
|
}
|
|
|
|
iniDAMA();
|
|
for (i = 0; i < L2CALEN; i++)
|
|
l2als[i] = toupper(alias[i]);
|
|
}
|
|
|
|
void
|
|
autopar(int port)
|
|
{
|
|
PORTINFO *p = portpar + port;
|
|
UWORD baud; /* Baudrate/100 auf dem Port */
|
|
UWORD P; /* Persistance */
|
|
UWORD W; /* Slottime */
|
|
UWORD IRTT; /* Initial RTT */
|
|
UWORD T2; /* Timer2 */
|
|
UWORD N2; /* Retry */
|
|
BOOLEAN l1update;
|
|
|
|
/* T2 wird berechnet als die Laenge der Aussendung eines Frames bei */
|
|
/* der eingestellten Baudrate + 10%. */
|
|
baud = p->speed;
|
|
|
|
T2 = 1; /* sehr schneller Link */
|
|
if ((baud != 0) && (baud < 2888))
|
|
T2 = 2888 / baud; /* sonst adaptiv nach Baudrate */
|
|
|
|
if (dama(port))
|
|
T2 <<= 1; /* *2 bei DAMA nach DG3AAH */
|
|
|
|
/* Der IRTT wird auf T2*2 festgelegt, dies sollte immer
|
|
* ausreichen, damit eine Antwort kommt. Es wird noch der TXDELAY
|
|
* dazugerechnet, in der Annahme die Gegenstation habe etwa einen
|
|
* gleich schnellen Transceiver.
|
|
*/
|
|
IRTT = (T2 + p->txdelay) * 2;
|
|
IRTT = max(10, IRTT);
|
|
|
|
/* Der Retry ist DEF_N2 bei DUPLEX/CSMA und DEF_N2/2 bei DAMA. */
|
|
N2 = DEF_N2;
|
|
if (dama(port))
|
|
N2 /= 2;
|
|
|
|
/* P-PERSISTENCE
|
|
* Bei DAMA und VOLLDUPLEX wird P immer auf 255 gesetzt.
|
|
* Bei einem normalen Einstieg ohne DAMA oder Halb-Duplex
|
|
* verwenden wir defaultmaessig P=160
|
|
*/
|
|
P = 255;
|
|
|
|
/* Persistence und Slottime bei Linkports anders setzen */
|
|
if (!fullduplex(port))
|
|
{
|
|
if (islinkport(port))
|
|
P = 200;
|
|
else if (!dama(port))
|
|
P = 160; /* Idee DB2OS und DG9FU */
|
|
}
|
|
|
|
/* Als Slottime wird der aktuelle TX-Delay Wert genommen. */
|
|
W = p->txdelay;
|
|
if (W == 0)
|
|
W++;
|
|
|
|
l1update = (P != p->persistance)
|
|
|| (W != p->slottime);
|
|
|
|
#ifdef EXPERTPARAMETER
|
|
/* Neue Werte nur bei Autoparameter setzen */
|
|
if (p->l2autoparam & MODE_apers) p->persistance = P;
|
|
if (p->l2autoparam & MODE_aslot) p->slottime = W;
|
|
if (p->l2autoparam & MODE_aIRTT) p->IRTT = IRTT;
|
|
if (p->l2autoparam & MODE_aT2) p->T2 = T2;
|
|
if (p->l2autoparam & MODE_aretry) p->retry = N2;
|
|
#else
|
|
p->persistance = P; /* Parameter neu setzen */
|
|
p->slottime = W;
|
|
p->IRTT = IRTT;
|
|
p->T2 = T2;
|
|
p->retry = N2;
|
|
#endif
|
|
|
|
if (l1update) /* neue L1-Parameter setzen */
|
|
l1ctl(L1CCMD, port);
|
|
}
|
|
|
|
void
|
|
autopers(int port)
|
|
{
|
|
#ifdef DAMASLAVE
|
|
PORTINFO *p = portpar + port;
|
|
|
|
if (damaslaveon(port)) /* wenn DAMA erkannt, dann */
|
|
{
|
|
p->persistance = 255; /* sofort antworten */
|
|
p->slottime = 0; /* keine Wartezeit */
|
|
l1ctl(L1CCMD, port); /* Aenderungen zum TNC bringen */
|
|
}
|
|
#endif
|
|
|
|
#if 0 /* DB2OS will es so ... */
|
|
PORTINFO *p = portpar + port;
|
|
UWORD P; /* Persistance */
|
|
BOOLEAN l1update;
|
|
|
|
/* Persistance wird berechnet als 255-(Anzahl der User)*10. Bei */
|
|
/* Vollduplex und DAMA wird die Persistance immer auf 255 gesetzt. */
|
|
P = 255;
|
|
if ((p->nmbstn > 0) && !fullduplex(port) && !dama(port))
|
|
if (p->nmbstn <= 15)
|
|
P = 255 - (p->nmbstn * 10);
|
|
else
|
|
P = 100;
|
|
|
|
l1update = (P != p->persistance);
|
|
|
|
p->persistance = P; /* Parameter neu setzen */
|
|
|
|
if (l1update) /* neue L1-Parameter setzen */
|
|
l1ctl(L1CCMD, port);
|
|
#endif
|
|
}
|
|
|
|
#ifdef PORT_SYNRONATION
|
|
static int check_syn_port(int port)
|
|
{
|
|
int i = 0;
|
|
int found = 0;
|
|
|
|
/* alle Ports pruefen. */
|
|
for(i = 0; i < L2PNUM; i++)
|
|
{
|
|
/* Ist Port aktiv? */
|
|
if (!portenabled(i))
|
|
/* Port ist ausgeschaltet, */
|
|
/* zum naechsten Port. */
|
|
continue;
|
|
|
|
/* Den eignen Port nicht pruefen*/
|
|
if (port == i)
|
|
continue;
|
|
|
|
if (port_synronation_enabled(i))
|
|
{
|
|
/* Port mit Synronation gefunden. */
|
|
/* Pruefe den Port auf DCD/PTT. */
|
|
found = iscd(i);
|
|
continue;
|
|
}
|
|
}
|
|
return(found);
|
|
}
|
|
#endif
|
|
|
|
/* Ist ein Port gerade aktiv ? (Blockierung des Senders und der Timer */
|
|
BOOLEAN
|
|
busy(int port)
|
|
{
|
|
if (fullduplex(port))
|
|
return ((iscd(port) & (RXBFLAG | TXBFLAG)) != 0);
|
|
else
|
|
#ifndef PORT_SYNRONATION
|
|
return ((iscd(port) & (DCDFLAG | PTTFLAG | RXBFLAG | TXBFLAG)) != 0);
|
|
#else
|
|
if (port_synronation_enabled(port))
|
|
{
|
|
if (check_syn_port(port) || (iscd(port) & (DCDFLAG | PTTFLAG | RXBFLAG | TXBFLAG)))
|
|
return(TRUE);
|
|
else
|
|
return(FALSE);
|
|
}
|
|
return ((iscd(port) & (DCDFLAG | PTTFLAG | RXBFLAG | TXBFLAG)) != 0);
|
|
#endif
|
|
}
|
|
|
|
/************************************************************************\
|
|
* *
|
|
* "level 2 rest" *
|
|
* *
|
|
* Muellbufferliste frei machen (aus Interruptroutinen entstandener *
|
|
* Muell, der besser ausserhalb der Interrupts deallokiert wird aus *
|
|
* Zeitgruenden). *
|
|
* *
|
|
\************************************************************************/
|
|
static void
|
|
l2rest(void)
|
|
{
|
|
dealml((LEHEAD *)&trfl); /* Muellbufferliste frei machen */
|
|
}
|
|
|
|
#ifdef L2PROFILER
|
|
void
|
|
l2profiler(void)
|
|
{
|
|
MBHEAD *mbp;
|
|
|
|
if (dmagic == MAGIC_L2PROFILE)
|
|
{ /* im Level 2 ordentlich Krach */
|
|
while ( lnkpoi->tosend < 10 /* machen */
|
|
&& !(lnkpoi->flag & (L2FDSLE | L2FDIMM)))
|
|
{
|
|
mbp = (MBHEAD *)allocb(ALLOC_MBHEAD);
|
|
while (mbp->mbpc < 256)
|
|
putchr(' ', mbp);
|
|
rwndmb(mbp);
|
|
i3tolnk(0x12, lnkpoi, mbp);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifndef MC68K
|
|
/************************************************************************/
|
|
/* */
|
|
/* "is to me" */
|
|
/* */
|
|
/* Ist das uebergebene Rufzeichen unser myid oder alias? Der Alias kann */
|
|
/* mit beliebiger SSID connected werden. */
|
|
/* */
|
|
/************************************************************************/
|
|
BOOLEAN
|
|
istome(const char *id)
|
|
{
|
|
return ( cmpid(myid, id) /* Stimmt Rufzeichen? */
|
|
|| cmpcal(l2als, id)); /* oder ALIAS? */
|
|
}
|
|
#endif
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* "is to me or via me?" */
|
|
/* */
|
|
/* Pruefen, ob wir als naechster an der Reihe sind mit Digipeaten. Dazu */
|
|
/* schauen wir uns das erste Call an, das kein gesetztes Hbit hat, dass */
|
|
/* muessen wir selber sein oder wir schmeissen das Frame weg, */
|
|
/* andernfalls duerfen wir das Frame auswerten. */
|
|
/* */
|
|
/* Rueckgabewerte : 0 = nicht via uns und auch nicht fuer uns */
|
|
/* 1 = gedigipeated/kein via, und Verbindung an uns */
|
|
/* 2 = Verbindung via, aber NICHT an uns */
|
|
/* TEST DG9OBU 3 = Verbindung an unseren SSID-Bereich/Local */
|
|
/* 4 = AX.25-ARP an uns */
|
|
/************************************************************************/
|
|
int
|
|
istomev(void)
|
|
{
|
|
char *viap = rxfhdr + L2ILEN; /* Zeiger auf erstes Via */
|
|
char *savedviap = viap; /* Zur Sicherheit irgendwo hin zeigen lassen */
|
|
|
|
int iViaNum = -1;
|
|
int iViaNumMax = 0;
|
|
|
|
while (*viap)
|
|
{
|
|
++iViaNumMax;
|
|
if (!(viap[L2IDLEN - 1] & L2CH))
|
|
{
|
|
if (iViaNum == -1)
|
|
{
|
|
savedviap = viap;
|
|
iViaNum = iViaNumMax;
|
|
}
|
|
}
|
|
viap += L2IDLEN;
|
|
}
|
|
|
|
if ((iViaNumMax > 0) && (iViaNum > -1))
|
|
{
|
|
if (iViaNum < iViaNumMax)
|
|
{
|
|
/* Wir sind nicht das letzte Via in der Liste */
|
|
return (istome(savedviap) ? 2 : 0); /* Verbindung via uns? */
|
|
}
|
|
else
|
|
{
|
|
/* Wir sind das letzte Via in der Liste */
|
|
if (istome(savedviap))
|
|
{
|
|
return((cmpid(rxfhdr, "QST \140")) ? 5 : 2);
|
|
}
|
|
else
|
|
{
|
|
return(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Hier angekommen haben entweder alle schon gedigipeated oder es gibt */
|
|
/* keine VIAs, auf jeden Fall duerfen wir den Link nehmen, wenn er */
|
|
/* direkt an uns (MyCall ODER Node-Alias) gerichtet ist. */
|
|
if (istome(rxfhdr))
|
|
return 1;
|
|
|
|
/* TEST DG9OBU */
|
|
/* Verbindung nicht direkt an mich, sondern in meinen SSID-Bereich */
|
|
if ( (cmpcal(rxfhdr, myid)) /* hat mein Call, SSID egal */
|
|
&& (SSIDinrange(SSID(rxfhdr))) /* liegt in meinem SSID-Bereich */
|
|
)
|
|
return 3;
|
|
|
|
#ifdef PROXYFUNC
|
|
if (isproxy(rxfhdr))
|
|
return 2;
|
|
#endif
|
|
|
|
#ifdef IPROUTE
|
|
/* AX.25-ARP fuer mich ? */
|
|
/* (bzw. an QST und alle in der VIA-Liste haben schon gedigipeated */
|
|
/* oder keine VIA-Liste vorhanden) */
|
|
if (cmpid(rxfhdr, "QST \140"))
|
|
return 4;
|
|
#endif
|
|
|
|
/* Verbindung ist nicht fuer uns */
|
|
return 0;
|
|
}
|
|
|
|
/************************************************************************\
|
|
* *
|
|
* "new link" *
|
|
* *
|
|
* Link (lnkpoi) neu aufbauen. *
|
|
* *
|
|
\************************************************************************/
|
|
void
|
|
newlnk(void)
|
|
{
|
|
reslnk(); /* Sequenzvars/Timer ruecksetzen */
|
|
setiSRTT(); /* RTT-Timer neu starten */
|
|
l2stma(stbl19); /* LOCAL START COMMAND */
|
|
}
|
|
|
|
/************************************************************************\
|
|
* *
|
|
* "disconnect link" *
|
|
* *
|
|
* Disconnect-Wunsch an aktuellen Link (lnkpoi) : *
|
|
* *
|
|
* Linkstatus "Disconnected" *
|
|
* -> Ax.25-Parameter "frisch" *
|
|
* *
|
|
* Linkstatus "Link Setup" oder "Disconnect Request" *
|
|
* -> Link NICHT aufloesen, nur Flag vormerken fuer l2rest *
|
|
* *
|
|
* sonst *
|
|
* -> Empfangsinfoframeliste loeschen, Linkstatus bleibt, Flag "nach *
|
|
* Loswerden aller zu sendenden Infoframes disconnecten" setzen *
|
|
* *
|
|
\************************************************************************/
|
|
void
|
|
dsclnk(void)
|
|
{
|
|
WORD lstate;
|
|
|
|
if ((lstate = lnkpoi->state) == L2SDSCED) /* Disced, nur */
|
|
inilbl(); /* AX-Pars neu */
|
|
else
|
|
{
|
|
dealml((LEHEAD *)&lnkpoi->rcvdil); /* RX-Infoframe- */
|
|
lnkpoi->rcvd = 0; /* loeschen und */
|
|
|
|
if ( lstate == L2SLKSUP /* Linksetup oder */
|
|
|| lstate == L2SDSCRQ /* Discreq, */
|
|
|| lstate == L2SHTH /* oder wartet */
|
|
|| (lnkpoi->flag & L2FDSLE))
|
|
lnkpoi->flag |= L2FDIMM; /* sofort weg */
|
|
else
|
|
lnkpoi->flag |= L2FDSLE; /* wenn alles raus */
|
|
}
|
|
}
|
|
|
|
/************************************************************************\
|
|
* *
|
|
* "initialize link" *
|
|
* *
|
|
* Aktuellen Linkblock (lnkpoi) initialisieren. Sequenzvariablen und *
|
|
* Timer initialisieren, Quellcall/Zielcall/via-Liste/ Port setzen aus *
|
|
* der txf...-Liste. *
|
|
* *
|
|
\************************************************************************/
|
|
void
|
|
inilnk(void)
|
|
{
|
|
reslnk(); /* Sequenzvars/Timer init. */
|
|
cpyid(lnkpoi->srcid, txfhdr + L2IDLEN); /* Quellcall */
|
|
cpyid(lnkpoi->dstid, txfhdr); /* Zielcall */
|
|
cpyidl(lnkpoi->viaidl, txfhdr + L2ILEN); /* via-Liste */
|
|
lnkpoi->liport = txfprt; /* Port */
|
|
setiSRTT(); /* RTT */
|
|
lnkpoi->pollcnt = 0; /* Anzahl verbotener Polls */
|
|
/* des DAMA-Users */
|
|
lnkpoi->noatou = ininat; /* Timeout initialisieren */
|
|
#ifdef EAX25
|
|
if (lnkpoi->bitmask == 0x7F)
|
|
#ifdef __WIN32__
|
|
lnkpoi->maxframe = (unsigned char)portpar[lnkpoi->liport].maxframe_eax;
|
|
#else
|
|
lnkpoi->maxframe = portpar[lnkpoi->liport].maxframe_eax;
|
|
#endif /* WIN32 */
|
|
else
|
|
#endif
|
|
#ifdef __WIN32__
|
|
lnkpoi->maxframe = (unsigned char)portpar[lnkpoi->liport].maxframe;
|
|
#else
|
|
lnkpoi->maxframe = portpar[lnkpoi->liport].maxframe;
|
|
#endif /* WIN32 */
|
|
}
|
|
|
|
/************************************************************************\
|
|
* *
|
|
* "clear link" *
|
|
* *
|
|
* Aktuellen Link (lnkpoi) aufloesen. Alle Sequenzvariablen und Timer *
|
|
* zuruecksetzen, Sende- und Empfangsinfoframelise loeschen, Linkblock *
|
|
* neu mit AX.25-Parametern besetzen. *
|
|
* *
|
|
\************************************************************************/
|
|
void
|
|
clrlnk(void)
|
|
{
|
|
reslnk(); /* Sequenzvars/Timer ruecksetzen */
|
|
dealml((LEHEAD *)&lnkpoi->rcvdil); /* Empfangsinfoliste loeschen */
|
|
dealml((LEHEAD *)&lnkpoi->sendil); /* Sendeinfoliste loeschen */
|
|
dealml((LEHEAD *)&lnkpoi->damail); /* DAMA-Puffer loeschen */
|
|
lnkpoi->rcvd = lnkpoi->tosend = 0; /* entsprechende Zaehler loeschen */
|
|
if (lnkpoi->tmbp != NULL) /* RX-Fragmente auch */
|
|
{
|
|
dealmb(lnkpoi->tmbp);
|
|
lnkpoi->tmbp = NULL;
|
|
}
|
|
inilbl(); /* Linkblock "frisch" */
|
|
}
|
|
|
|
/************************************************************************\
|
|
* *
|
|
* "reset link" *
|
|
* *
|
|
* Aktuellen Link (lnkpoi) zuruecksetzen. Alle Sequenzvariablen und Timer *
|
|
* initialisieren. *
|
|
* *
|
|
\************************************************************************/
|
|
void
|
|
reslnk(void)
|
|
{
|
|
#ifdef __WIN32__
|
|
lnkpoi->VS = 0;
|
|
lnkpoi->VR = 0;
|
|
lnkpoi->ltxdNR = 0;
|
|
lnkpoi->lrxdNR = 0;
|
|
lnkpoi->RTT = 0;
|
|
#else
|
|
lnkpoi->VS =
|
|
lnkpoi->VR =
|
|
lnkpoi->ltxdNR =
|
|
lnkpoi->lrxdNR =
|
|
lnkpoi->RTT =
|
|
#endif /* WIN32 */
|
|
lnkpoi->flag = 0;
|
|
lnkpoi->noatou = ininat;
|
|
resptc(g_uid(lnkpoi, L2_USER));
|
|
clrDAMA();
|
|
lnkpoi->SRTT = portpar[lnkpoi->liport].IRTT;
|
|
clrT1();
|
|
clrT2();
|
|
}
|
|
|
|
/************************************************************************\
|
|
* *
|
|
* "initialize link block" *
|
|
* *
|
|
* Aktuellen Linkblock (lnkpoi) initialisieren. *
|
|
* *
|
|
\************************************************************************/
|
|
static void
|
|
inilbl(void)
|
|
{
|
|
lnkpoi->liport = 0;
|
|
lnkpoi->bitmask = 0x07;
|
|
clrDAMA();
|
|
}
|
|
|
|
/************************************************************************\
|
|
* *
|
|
* "acknowledge link" *
|
|
* *
|
|
* Diese Funktion wird vom L7 aufgerufen, um eine eingehende HTH- *
|
|
* Verbindung zu bestaetigen. Es wird lediglich ein Flag gesetzt, in *
|
|
* l2rest wird dann die eigentliche Reaktion ausgeloest. *
|
|
* *
|
|
\************************************************************************/
|
|
void
|
|
acklnk(LNKBLK *lp)
|
|
{
|
|
if (lp->state == L2SHTH)
|
|
lp->flag |= L2FACKHTH;
|
|
}
|
|
|
|
/************************************************************************\
|
|
* *
|
|
* "reject link" *
|
|
* *
|
|
* Diese Funktion wird vom L7 aufgerufen, um eine eingehende HTH- *
|
|
* Verbindung abzulehnen (Partner ist Busy). *
|
|
* *
|
|
\************************************************************************/
|
|
void
|
|
rejlnk(LNKBLK *lp)
|
|
{
|
|
if (lp->state == L2SHTH)
|
|
lp->flag |= L2FREJHTH;
|
|
}
|
|
|
|
/************************************************************************\
|
|
* *
|
|
* "get link" *
|
|
* *
|
|
* Einen Link anhand port, srcid, dstid und vial suchen und liefern. Wenn *
|
|
* wir noch keinen Link haben, dann einen neuen (leeren) liefern. *
|
|
* *
|
|
\************************************************************************/
|
|
LNKBLK *
|
|
getlnk(UBYTE liport, char *srcid, char *dstid, char *viaidl)
|
|
{
|
|
LHEAD *llp;
|
|
LNKBLK *lp;
|
|
char *p;
|
|
|
|
if (!portenabled(liport))
|
|
return(NULL);
|
|
|
|
llp = &l2actl[liport]; /* auf dem entsprechenden Port */
|
|
|
|
for (lp = (LNKBLK *)llp->tail;
|
|
lp != (LNKBLK *)llp; /* alle Links des Ports pruefen */
|
|
lp = lp->prev)
|
|
{
|
|
if (cmpid(lp->srcid, srcid))
|
|
if (cmpid(lp->dstid, dstid)
|
|
&& cmpidl(lp->viaidl, viaidl))
|
|
{
|
|
ulink((LEHEAD *)lp);
|
|
relink((LEHEAD *)lp, (LEHEAD *)llp->tail);
|
|
return (lp); /* wir haben einen Link gefunden */
|
|
}
|
|
}
|
|
|
|
if ((LHEAD *)l2frel.head == &l2frel)
|
|
return (NULL); /* wir haben keinen freien Link */
|
|
|
|
if ( (fvalca(dstid) != YES)
|
|
|| (nmbfre < 78)) /* falsches Call oder kein Speicher? */
|
|
return (NULL);
|
|
|
|
lp = (LNKBLK *)l2frel.head;
|
|
cpyid(lp->srcid, srcid); /* Werte setzen */
|
|
cpyid(lp->dstid, dstid);
|
|
cpyidl(lp->viaidl, viaidl);
|
|
|
|
lp->liport = liport;
|
|
/* In den Linkblock wird ein Zeiger auf das Rufzeichen abgelegt, das in */
|
|
/* Wirklichkeit der Ansprechpartner dieses Linkes ist. Es ist das Erste */
|
|
/* Rufzeichen im via-Feld ohne H-Bit oder das Ziel-Rufzeichen selbst. */
|
|
for (p = lp->viaidl; *p; p += L2IDLEN)
|
|
if ((p[L2IDLEN - 1] & L2CH) == 0)
|
|
break;
|
|
lp->realid = *p ? p : lp->dstid;
|
|
return (lp); /* leeren Block liefern */
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* Maxframe-Automatik: Fuer den angegebenen Link wird Maxframe um den */
|
|
/* Wert dif geaendert. Dabei wird der Bereich 1 .. Port-Maxframe */
|
|
/* eingehalten. Zum Vergroessern des Link-Maxframe muss zweimal in */
|
|
/* Folge alles bestaetigt sein. */
|
|
/* */
|
|
/************************************************************************/
|
|
void
|
|
change_maxframe(LNKBLK *link, int dif)
|
|
{
|
|
#if MAX_TRACE_LEVEL > 4
|
|
char notify_call1[10];
|
|
char notify_call2[10];
|
|
#endif
|
|
int old = link->maxframe;
|
|
int new_max;
|
|
int port_max;
|
|
|
|
#ifdef EAX25
|
|
/* Fuer EAX.25-Links ein anderes Maxframe verwenden */
|
|
if (link->bitmask == 0x7F)
|
|
port_max = portpar[link->liport].maxframe_eax;
|
|
else
|
|
#endif
|
|
port_max = portpar[link->liport].maxframe;
|
|
|
|
if (!automaxframe(link->liport))
|
|
{
|
|
link->maxframe = port_max;
|
|
return;
|
|
}
|
|
|
|
if (dif > 0) /* soll vergroessert werden? */
|
|
{
|
|
if (old == port_max) /* schon Maximalwert, den Rest */
|
|
return; /* kann man sich sparen */
|
|
|
|
if (link->flag & L2FCMDEL) /* 2. Durchgang in Folge? */
|
|
link->flag &= ~L2FCMDEL;
|
|
else
|
|
{
|
|
link->flag |= L2FCMDEL; /* 1. Durchgang - nix aendern */
|
|
dif = 0;
|
|
}
|
|
}
|
|
else
|
|
link->flag &= ~L2FCMDEL;
|
|
|
|
new_max = old + dif;
|
|
if (new_max < 1)
|
|
new_max = 1;
|
|
if (new_max > port_max)
|
|
new_max = port_max;
|
|
|
|
if ((new_max != old) | (link->flag & L2FCMDEL))
|
|
{
|
|
link->maxframe = new_max;
|
|
#if MAX_TRACE_LEVEL > 4
|
|
call2str(notify_call1, link->srcid);
|
|
call2str(notify_call2, link->dstid);
|
|
notify(5, "Max %s - %s %d->%d",
|
|
notify_call1, notify_call2, old, new_max);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* UI-Frames von einem Port auf einen anderen Port durchreichen. Diese */
|
|
/* Funktion ist vorgesehen, um z.B. Mail-Beacons von Mailboxes zu */
|
|
/* ermoeglichen. Als Digipeater-Call ist der TNN-Alias zu verwenden mit */
|
|
/* der Nummer des gewuenschten Sende-Ports als SSID. Fuer die Ueber- */
|
|
/* tragung muessen folgende Voraussetzungen erfuellt sein: */
|
|
/* */
|
|
/* - nur PID 0xF0 wird akzeptiert */
|
|
/* - der Sende-Port darf nicht der Empfangsport sein */
|
|
/* */
|
|
/* Um fuer F6FBB-Mailboxes eine Antwort-Funktion zu ermoeglichen, wird */
|
|
/* der SSID des Digipeater-Calls bei der Aussendung auf den Empfangs- */
|
|
/* port gesetzt. */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
void
|
|
gateway_ui(char *fmid, char *toid, char *rxvia, MBHEAD *info)
|
|
{
|
|
int port;
|
|
char *vp;
|
|
char to[L2IDLEN];
|
|
|
|
DEST dst;
|
|
|
|
BOOLEAN bCanDigipeat = FALSE;
|
|
BOOLEAN bSuppressHBit = FALSE;
|
|
|
|
/* Gesamte via-Liste durchgehen */
|
|
for (vp = rxvia; *vp != '\0'; vp += L2IDLEN)
|
|
{
|
|
/* Hat dieser via-Digi schon gedigipeated ? Ja, dann zum naechsten */
|
|
if (vp[L2IDLEN-1] & L2CH)
|
|
continue;
|
|
|
|
/* Mailbake fuer Mailbox-Systeme, ermoeglicht die Aussendung des */
|
|
/* UI-Frames gezielt auf einem anderen Port */
|
|
/* Unser *Alias* und PID F0 ? */
|
|
#ifndef UIDIGIMOD
|
|
if ((cmpcal(vp, l2als)) && (info->l2fflg == L2CPID))
|
|
#else
|
|
if (cmpcal(vp, myid))
|
|
#endif /* UIDIGIMOD */
|
|
{
|
|
/* Port holen, auf dem ausgesendet werden soll */
|
|
port = SSID(vp);
|
|
/* Pruefen, ob Einschraenkungen erfuellt */
|
|
#ifndef UIDIGIMOD
|
|
if ((port < L2PNUM) && portenabled(port) && (port != rxfprt))
|
|
#else
|
|
if ((port < L2PNUM) && portenabled(port))
|
|
#endif /* UIDIGIMOD */
|
|
{
|
|
/* Via umbauen (Empfangsport und digipeated-Flag eintragen) */
|
|
vp[L2IDLEN-1] = (vp[L2IDLEN-1] & ~0x1E) | (rxfprt << 1) | L2CH;
|
|
#ifdef __WIN32__
|
|
sdui(rxvia, toid, fmid, (char)port, info); /* UI-Frame senden */
|
|
#else
|
|
sdui(rxvia, toid, fmid, port, info); /* UI-Frame senden */
|
|
#endif /* WIN32 */
|
|
/* Frame loeschen */
|
|
dealmb(info);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* UI-Digipeating fuer andere L2-Frames jeglicher PID. Das gewuenschte */
|
|
/* Ziel muss uns bekannt UND per L2 erreichbar sein, NETROM-Ziele koennen */
|
|
/* per UI (noch) nicht erreicht werden, da schicken wir das UI-Frame im */
|
|
/* L2 weiter. */
|
|
|
|
/* Sind wir der naechste Digi in der Via-Liste ? */
|
|
if (cmpid(vp, myid))
|
|
{
|
|
char *tp = vp + L2IDLEN; /* naechster Hop in der Liste (oder NUL) */
|
|
|
|
/* Noch ein Digi nach uns in der via Liste ? */
|
|
if (*tp != '\0')
|
|
{
|
|
/* Ja, dann feststellen, ob wir den kennen und wo wir lang muessen. */
|
|
/* Es darf sich nur um ein Flexnet- oder lokales L2-Ziel handeln, */
|
|
/* via-Pfade mit Calls auf Userports werden ignoriert. */
|
|
|
|
/* Flexnet- oder lokales, erreichbares L2-Ziel ? */
|
|
if (l3_find_route(tp, &dst) == NODE_AVAILABLE)
|
|
{
|
|
/* FlexNet, LOCAL und LOCAL_M */
|
|
/*
|
|
+ if ( (dst.typ == FLEXNET)
|
|
+ || (islocal(tp) == YES)
|
|
)
|
|
+*/
|
|
bCanDigipeat = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Keiner mehr nach uns in der Liste, dann schauen, ob wir das Ziel in der */
|
|
/* MHeard-Liste kennen oder es ein lokaler Link von uns ist */
|
|
cpyid(to, toid); /* wir brauchen nur das erste Call */
|
|
|
|
/* Lokaler User (MHeard) ? */
|
|
if (isheard(to, &dst) == TRUE)
|
|
bCanDigipeat = TRUE;
|
|
else
|
|
{
|
|
/* Lokal angeschlossener Knoten ? */
|
|
/* Ein erreichbarer Local oder Local ohne Messung */
|
|
if (islocal(to) == YES)
|
|
{
|
|
/* Es ist ein erreichbarer Local, jetzt noch den Port holen */
|
|
if (l3_find_route(to, &dst) == NODE_AVAILABLE)
|
|
bCanDigipeat = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else /* Wir sind eigentlich nicht dran, kennen aber einen Weg zum naechsten */
|
|
{ /* Digi in der Liste ? Das machen wir aber nur fuer RX auf Linkports ! */
|
|
if ( (l3_find_route(vp, &dst) == NODE_AVAILABLE)
|
|
&& (islinkport(rxfprt))
|
|
)
|
|
{
|
|
/* FlexNet, LOCAL und LOCAL_M */
|
|
/*
|
|
if ( (dst.typ == FLEXNET)
|
|
|| (islocal(vp) == YES)
|
|
)
|
|
{
|
|
*/
|
|
bCanDigipeat = TRUE;
|
|
bSuppressHBit = TRUE; /* H-Bit nicht veraendern */
|
|
/*
|
|
}
|
|
*/
|
|
}
|
|
}
|
|
|
|
/* Frame digipeaten ? Zielport ok ? */
|
|
if ( (bCanDigipeat == TRUE)
|
|
&& (portenabled(dst.port))
|
|
&& (dst.port >= 0)
|
|
&& (dst.port < L2PNUM)
|
|
)
|
|
{
|
|
/* Wenn wir nicht mit in den Vias waren, dann HBit nicht anfassen */
|
|
if (bSuppressHBit == FALSE)
|
|
/* Wir haben gedigipeated */
|
|
vp[L2IDLEN - 1] |= L2CH;
|
|
|
|
#ifdef __WIN32__
|
|
sdui(rxvia, toid, fmid, (char)dst.port, info); /* UI-Frame senden */
|
|
#else
|
|
sdui(rxvia, toid, fmid, dst.port, info); /* UI-Frame senden */
|
|
#endif /* WIN32 */
|
|
/* Frame loeschen */
|
|
dealmb(info);
|
|
return;
|
|
}
|
|
|
|
/* Via-Bearbeitung beendet */
|
|
break;
|
|
}
|
|
|
|
/* Frame loeschen */
|
|
dealmb(info);
|
|
return;
|
|
}
|
|
|
|
/* End of src/l2misc.c */
|