home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Hacker Chronicles 2
/
HACKER2.BIN
/
523.L2A.C
< prev
next >
Wrap
Text File
|
1988-05-14
|
37KB
|
739 lines
/**************************************************************************\
* *
* *
* ***** ***** *
* ***** ***** *
* ***** ***** *
* ***** ***** *
* ***** ***** *
* ***** ***** *
* ***** ***** *
* ***** ***** The Firmware. The Net. *
* ***** ***** Portable. Compatible. *
* ***** ***** Public Domain. *
* ***** ***** By NORD><LINK. *
* *
* *
* *
* L2A.C - Level 2, Teil 1 *
* *
* angelegt: DC4OX *
* modifiziert: *
* *
\**************************************************************************/
/* Includes */
/**************************************************************************/
#include "all.h" /* allgemeine Festlegungen */
#include "l2.h" /* Festlegungen/Datenstrukturen fuer den Level 2 */
#include "l2s.h" /* Zugriff auf die State-Tabellen */
#include "l2ext.h" /* globale Variable / nicht int-Funktionen */
/**************************************************************************\
* *
* "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 ausserhalb). *
* *
* *
* Der Level 2 laeuft wie folgt ab : *
* *
* - Aufruf von l2init() *
* *
* - zyklisches Aufrufen von l2() und l2timr(ticks) *
* *
* 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. *
* *
\**************************************************************************/
VOID l2()
{
l2tx(); /* der Sender */
l2rx(); /* der Empfaenger */
l2rest(); /* sonstiges */
}
/**************************************************************************\
* *
* "level 2 transmitter" *
* *
* Falls Infopakete zu senden sind, laut Sendefenster keine Infopakete *
* ausstehen, und laut Sendestatus auch gesendet werden duerfen, diese *
* senden. *
* *
* Frames aus Gesendet-Liste holen und in die Monitorframeliste umhaengen *
* (Firmware) oder deallokieren. Entsprechend dem Frameinhalt ggf. Timer 1 *
* starten. *
* *
\**************************************************************************/
VOID l2tx()
{
unsigned l2state; /* aktueller Linkstate */
unsigned n; /* Laufindex */
MBHEAD *sfbp; /* Sendeframebufferpointer */
for (n = 0, lnkpoi = lnktbl; n < LINKNMBR; ++n, ++lnkpoi)
if ( (l2state = lnkpoi->state) == L2SIXFER /* duerfen */
|| l2state == L2SRS /* wir was */
|| l2state == L2SDBS /* senden ? */
|| l2state == L2SRSDBS
)
if (lnkpoi->VS == lnkpoi->lrxdNR) /* nichts ausstehend ? */
sdi(lnkpoi->k); /* dann Infos senden */
while ((sfbp = stfl.head) != &stfl) /* Gesendetliste */
{ /* aufraeumen : */
unlink(sfbp); /* Frame holen */
if ((sfbp->l2fflg & L2FT1ST) != NO) /* ist T1 zu starten ? */
{ /* ja, Zeiger auf Link- */
lnkpoi = sfbp->l2link; /* block (zum Frame) */
setT1(); /* und T1 starten */
}
#ifdef FIRMWARE
if (nmbfre > 64) /* falls noch genug */
relink(sfbp,monfl.tail); /* Platz, Frame in den */
else /* Monitor */
#endif
dealmb(sfbp); /* oder deallokieren */
}
}
/**************************************************************************\
* *
* "level 2 receiver" *
* *
* Alle Frames aus der RX-Frameliste holen und analysieren. Kopie an *
* Monitorliste, digipeaten oder in Level-3-Liste, falls erforderlich. *
* Auf UI-Frames antworten, falls erforderlich. *
* *
* Reaktion entsprechend Protokoll, siehe unten. *
* *
\**************************************************************************/
VOID l2rx()
{
char *source; /* Zeiger auf Quellrufzeichen/SSID */
unsigned l2state; /* aktueller Level 2 Linkstatus */
BOOLEAN tome; /* YES = Frame ist an mich */
unsigned n; /* Laufindex */
MBHEAD *fbp; /* Framebufferpointer lokal */
LNKBLK *lblkp; /* Linkblockpointer lokal */
while ((fbp = rxfl.head) != &rxfl) /* solange empfangene */
{ /* Frames vorhanden */
unlink(fbp); /* eins aus Liste holen */
if (!takfhd(fbp)) /* Kopf analysieren, */
{ /* wenn nicht ok, dann */
dealmb(fbp); /* wegwerfen und zum */
continue; /* naechsten */
}
fbp->type = 2; /* wir sind im Level 2 */
#ifdef FIRMWARE
if (nmbfre > 64) /* wenn genug Platz, */
relink(cpyfb(fbp),monfl.tail); /* Kopie an Monitor */
#endif
if (digipt(fbp) == YES) continue; /* ... nur Digipeater */
if (rxfctl == L2CUI) /* UI-Frame, */
{ /* wenn an mich, und */
if (istome(rxfhdr) == YES) /* Antwort erwuenscht, */
if (rxfPF != NO && rxfCR != NO) /* entsprechend */
xdm(); /* beantworten */
lnkpoi = NULL; /* fuer tol3sw() */
if (!tol3sw(fbp)) /* Level 3 UI-Frame ? */
dealmb(fbp); /* nein -> weg damit */
continue; /* naechstes Frame */
}
/* Haben wir einen zum Frame passenden Linkblock ? */
/* */
/* Alle Linkbloecke durchgucken. Wenn ein aktiver Linkblock */
/* gefunden wurde, dessen Quellcall mit dem Framezielcall */
/* uebereinstimmt, tome auf TRUE setzen. Wenn auch noch Blockport */
/* mit Frameport und Blockzielcall mit Framequellcall */
/* uebereinstimmen, dann ist der aktive passende Link gefunden, */
/* Schleife abbrechen. */
/* */
/* Falls ein Link inaktiv ist, aber das Framezielcall an mich */
/* (Call + SSID oder Ident mit beliebiger SSID) ist, oder das */
/* Blockquellcall mit dem Framezielcall uebereinstimmt, dann */
/* Blockadresse in lblkp merken. Es wird nur der erste solche */
/* Block genommen. */
for ( tome = NO, lblkp = NULL, n = 0, lnkpoi = lnktbl;
n < LINKNMBR;
++n, ++lnkpoi
)
if (lnkpoi->state != L2SDSCED)
{
if (cmpid(lnkpoi->srcid,rxfhdr) == TRUE)
{
tome = YES;
if ( lnkpoi->liport == rxfprt
&& cmpid(lnkpoi->dstid,rxfhdr + L2IDLEN) == TRUE
) break;
}
}
else
if ( !lblkp
&& ( ( *lnkpoi->srcid == '\0'
&& istome(rxfhdr) == TRUE
)
|| ( *lnkpoi->srcid != '\0'
&& cmpid(lnkpoi->srcid,rxfhdr) == TRUE
)
)
) lblkp = lnkpoi;
if (n == LINKNMBR) /* wenn kein aktiver Link */
if (lblkp) /* passst, aber inaktiver */
lnkpoi = lblkp; /* Link, dann diesen nehmen */
else
{ /* sonst, wenn trotzdem das */
if ( tome == YES /* Frame an mich gerichtet */
|| istome(rxfhdr) == TRUE /* ist, reagieren : */
)
{
if (rxfctl == L2CSABM) /* SABM mit DM beantworten */
{ /* und hoeheren Leveln */
l2tolx(L2MBUSYT); /* melden */
xdm();
}
else /* sonst nur antworten, wenn */
if ( rxfPF != 0 /* Command mit Poll, dann */
&& rxfCR != 0 /* mit DM antworten */
) xdm();
else /* oder wenn kein Command */
if (rxfctl == L2CDISC) /* Poll, aber ein DISC, mit */
xua(); /* UA antworten */
}
dealmb(fbp); /* empfangenes Frame weg- */
continue; /* werfen und zum naechsten */
}
/* Falls Timer 3 aktiv, diesen neu setzen, es ist wieder */
/* Aktivitaet auf dem Link */
if (lnkpoi->T3 != 0) setT3();
l2state = lnkpoi->state; /* Linkstatus zur Abfrage */
if (!(rxfctl & L2CNOIM)) /* I-Frame ? */
{
/* I-Frame : */
/* */
/* Nur annehmen, wenn empfangene N(R) des Frames ok, */
/* srxdNR(), und das I-Frame das naechste erwartete in der */
/* Sequenz ist, isntxi(). */
/* Wenn alles ok, Laenge pruefen und ggf. auf falsche Laenge */
/* mit Frame-Reject reagieren, sonst Antwort entsprechend */
/* Statetable und I-Frame verarbeiten. */
if ( srxdNR() == TRUE /* N(R) ok ? */
&& isnxti() == TRUE /* erwartet ? */
)
if (fbp->mbpc - fbp->mbgc <= 257) /* Laengenpruefung */
{
l2stma(!rxfPF ? stbl01 : stbl00); /* Statetable */
/* Linkzustand I-Transfer moeglich und nicht busy ? */
if (l2state >= L2SIXFER && !(lnkpoi->flag & L2FBUSY))
{
/* wenn Level-3-I-Paket, dann in Level-3-RX-Liste */
/* einhaengen und Link als Level-3-Link markieren, */
/* No-Activity-Timeout neu starten */
if (tol3sw(fbp) == YES)
{
lnkpoi->flag |= L2FL3LNK;
lnkpoi->noatou = ininat;
}
else
/* wenn normales Level-2-I-Paket, wenn nicht Busy */
/* oder Level-3-Link, I annehmen und in */
/* Linkempfangsliste einhaengen */
if (!(lnkpoi->flag & (L2FDSLE | L2FL3LNK)))
{
relink(fbp,lnkpoi->rcvdil.tail);
++lnkpoi->rcvd;
}
else
dealmb(fbp); /* ansonsten Paket wegwerfen */
continue; /* auf zum naechsten Paket */
}
}
else /* Frame zu lang : */
sdfrmr(0x03); /* "U/S-Frame mit unerlaubtem */
/* Infofeld" */
}
else /* kein I-Frame : */
if (!(rxfctl & L2CNOSM))
{
/* S-Frame : */
/* */
/* Nur annehmen, wenn empfangene N(R) des Frames ok, */
/* srxdNR(), und wenn das Frame kein Infofeld enthaelt. */
/* */
/* Auf RR, RNR, REJ entsprechend Statetable antworten, auf */
/* andere mit Frame-Reject antworten. */
if (srxdNR() == YES) /* N(R) ok ? */
if (fbp->mbgc == fbp->mbpc) /* kein I-Feld ? */
switch ((rxfctl >> 2) & 0x03)
{
case 0 : /* L2CRR >> 2 */
l2stma( !rxfCR
? (!rxfPF ? stbl11 : stbl10)
: (!rxfPF ? stbl03 : stbl02)
);
break;
case 1 : /* L2CRNR >> 2 */
l2stma( !rxfCR
? (!rxfPF ? stbl15 : stbl14)
: (!rxfPF ? stbl07 : stbl06)
);
break;
case 2 : /* L2CREJ >> 2 */
l2stma( !rxfCR
? (!rxfPF ? stbl13 : stbl12)
: (!rxfPF ? stbl05 : stbl04)
);
if (l2state >= L2SIXFER) sdoi();
break;
default :
sdfrmr(0x01); /* "Kontrollfeld falsch oder */
break; /* nicht implementiert" */
} /* end switch ((rxfctl >> 2) & 0x03) */
else
sdfrmr(0x03); /* "U/S-Frame mit unerlaubtem */
/* Infofeld" */
} /* end S-Frame */
else /* kein I- oder S-Frame : */
if ((rxfctl & 0xFF) != L2CFRMR)
/* Kein FRMR-Frame, Frame nur annehmen, wenn kein Infofeld */
/* vorhanden. */
/* */
/* Frame auswerten, reagieren, nach Statetable antworten. */
if (fbp->mbgc == fbp->mbpc)
switch (rxfctl)
{
case L2CSABM : /* neuer Link / Linkreset */
lnkpoi->V2link = rxfV2; /* Protokollversion merken */
switch (l2state)
{ /* neuer Link (Connect) ? */
case L2SDSCED :
if ( fvalca(VCpar,rxfhdr + L2IDLEN) == TRUE
&& nmblks < Ypar
&& nmbfre > 128 /* annehmbar ? */
)
{
inilnk(); /* ja, Link init. */
++nmblks; /* neuer Link */
l2tolx(L2MCONNT); /* melden */
lnkpoi->noatou = ininat;
break; /* -> Statetable */
}
l2tolx(L2MBUSYT); /* nein, melden */
xdm(); /* mit DM antwort. */
dealmb(fbp); /* Frame vergessen */
continue; /* naechstes Paket */
break;
case L2SLKSUP : /* beide connecten */
/* anderer Weg als selbst benutzt ? */
if ( !cmpidl( cmpid(rxfhdr + L2IDLEN,
lnkpoi->srcid) == TRUE
? rxfhdr + L2ILEN
: txfhdr + L2ILEN,
lnkpoi->viaidl
)
)
{
clrlnk(); /* ja, alles */
l2tolx(L2MBUSYF); /* abbrechen */
xdm();
lnkpoi->state = L2SDSCED;
dealmb(fbp);
continue;
}
else
{
reslnk(); /* nein, */
l2tolx(L2MCONNT); /* gelungener */
lnkpoi->noatou = ininat; /* Connect */
}
break;
case L2SDSCRQ : /* sind ge-disct, Link */
mclrlk(); /* aufloesen und melden */
break;
default : /* normaler Linkreset */
inilnk(); /* vom Partner */
l2tolx(L2MLRESF);
break;
} /* end switch (l2state) */
l2stma(stbl08); /* SABM EITHER COMMAND */
break;
case L2CDISC :
if (!l2state) /* Link aktiv ? */
{
if ( rxfPF != 0 /* nein, wenn Command */
&& rxfCR != 0 /* mit Poll, dann mit */
) xdm(); /* DM antworten */
else
xua(); /* sonst mit UA */
dealmb(fbp); /* Frame wegwerfen */
continue; /* naechstes Paket */
}
else /* ja, */
if (l2state == L2SLKSUP) /* wenn im Linkaufbau, */
{ /* dann Link sofort */
clrlnk(); /* aufloesen und melden */
l2tolx(L2MBUSYF);
}
else /* sonst erst restliche */
{ /* I-Frames an hoeheren */
i2tolx(YES); /* Level geben und dann */
mclrlk(); /* Link loesen / melden */
}
l2stma(stbl09); /* DISC EITHER COMMAND */
break;
case L2CUA :
if (l2state < L2SRS) /* V1-Zustand ? */
{
if (l2state == L2SLKSUP) /* ja, wenn im */
{ /* Link-Setup */
lnkpoi->V2link = rxfV2; /* Protokollvers. */
reslnk(); /* uebernehmen, */
l2tolx(L2MCONNT); /* Link neu und */
lnkpoi->noatou = ininat; /* melden */
}
else /* sonst wenn im */
if (l2state == L2SDSCRQ) /* Disc-Request */
mclrlk(); /* Link aufloesen */
}
else
{
reslnk(); /* nein, Linkreset */
l2tolx(L2MLREST); /* ausf. / melden */
}
l2stma(stbl16); /* UA EITHER RESPONSE */
break;
case L2CDM :
if (l2state) /* wenn Link aktiv ... */
if (l2state == L2SLKSUP) /* wenn DM beim Link- */
{ /* Setup, dann Link */
clrlnk(); /* sofort aufloesen und */
l2tolx(L2MBUSYF); /* "Busy from" melden */
}
else /* sonst Link aufloesen */
mclrlk(); /* mit Meldung */
l2stma(stbl17); /* DM EITHER RESPONSE */
break;
default : /* unbekanntes Kontrollfeld : */
sdfrmr(0x01); /* "Kontrollfeld falsch oder */
break; /* nicht implementiert" */
} /* end switch (rxfctl) */
else /* Frametyp unbekannt */
sdfrmr(0x03); /* "U/S-Frame mit un- */
/* erlaubtem Infofeld" */
else /* from if (rxfctl != L2CFRMR) */
{
/* FRMR-Frame : */
/* */
/* Wird nur im Frame-Reject-Zustand oder bei moeglichem */
/* Informationstransfer angenommen. */
/* Es werden die FRMR-Infobytes gelesen, FRMR an die */
/* hoeheren Level gemeldet, nach Statetable geantwortet. */
if (l2state >= L2SIXFER || l2state == L2SFRREJ)
{
/* FRMR-Infobytes im Linkblock merken */
for (source = lnkpoi->frmr, n = 0; n < 3; ++n)
*source++ = (fbp->mbgc < fbp->mbpc) ? getchr(fbp) : 0;
l2tolx(L2MFRMRF);
}
l2stma(stbl18); /* FRMR EITHER RESPONSE */
}
dealmb(fbp); /* aktuelles Frame verarbeitet, wegwerfen */
} /* end while ((fbp = rxfl.head) != &rxfl) */
}
/**************************************************************************\
* *
* "level 2 rest" *
* *
* Fuer alle aktiven Links Busyzustand pruefen/setzen/aufloesen, I-Pakete *
* unter Beruecksichtigung der "Erstickungskontrolle" an hoehere Level *
* weiterreichen. Fall Zustand "Disconnecten nach Uebertragung der *
* restlichen I-Pakete" und keine I-Pakete mehr zu senden, Disconnect *
* einleiten. *
* Muellbufferliste frei machen (aus Interruptroutinen entstandener Muell, *
* der besser ausserhalb der Interrupts deallokiert wird aus Zeitgruenden). *
* *
\**************************************************************************/
VOID l2rest()
{
unsigned n;
for (n = 0, lnkpoi = lnktbl; n < LINKNMBR; ++n, ++lnkpoi)
if (lnkpoi->state != L2SDSCED)
{
/* fuer alle aktiven (= nicht disconnecteten) Links : */
txfV2 = lnkpoi->V2link; /* Protokollversion */
/* wenn Zustand "nachdem alle restliche I's uebertragen wurden, */
/* disconnecten" und alle I's uebertragen, DISC einleiten */
if ( ((lnkpoi->flag & L2FDSLE) != NO)
&& !lnkpoi->tosend
) disc();
/* sonst empfangene I-Pakete an hoeheren Level uebertragen und */
/* Busy-Condition pruefen / setzen / aufheben */
/* */
/* "Busy werden" - weniger als 80 Freibuffer */
/* oder so viele I-Pakete empfangen und */
/* nicht abgeholt, wie */
/* "Erstickungszaehler" conctl angibt */
/* */
/* "Busy aufloesen" - wieder mehr als 112 Freibuffer */
/* und weniger als halb so viele */
/* empfangen und nicht abgeholt wie */
/* conctl angibt */
else
{
i2tolx(NO);
if (!(lnkpoi->flag & L2FBUSY)) /* nicht busy */
{
if (nmbfre < 80 || lnkpoi->rcvd >= conctl)
{
lnkpoi->flag |= L2FBUSY; /* busy werden */
l2stma(stbl21); /* STATION BECOMES BUSY */
}
}
else
if (nmbfre > 112 && lnkpoi->rcvd < conctl/2)
{
lnkpoi->flag &= ~L2FBUSY; /* "busy" aufloesen */
l2stma(stbl22); /* BUSY CONDITION CLEARS */
}
}
} /* end if (lnkpoi->state) */
dealml(&trfl); /* Muellbufferliste frei machen */
}
/**************************************************************************\
* *
* "level 2 timer" *
* *
* Ausfuehren der Level-2-Millisekundentimer 1, 2, 3 in allen aktiven *
* Links (herunterzaehlen und bei Ablauf reagieren). *
* In ticks wird die Anzahl der vergangenen 10ms-Intervalle (Ticks) seit *
* dem letzten Aufruf dieser Routine angegeben. *
* *
\**************************************************************************/
VOID l2timr(ticks)
unsigned ticks;
{
unsigned n;
for (n = 0, lnkpoi = lnktbl; n < LINKNMBR; ++n, ++lnkpoi)
if (lnkpoi->state != L2SDSCED)
{
/* fuer alle aktiven (= nicht disconnecteten) Links : */
txfV2 = lnkpoi->V2link; /* Merker ob Version-2-Protokoll */
if (lnkpoi->T1 != 0) /* wenn Timer 1 aktiv ... */
if (lnkpoi->T1 <= ticks) /* wenn Timer 1 abgelaufen ... */
{
lnkpoi->T1 = 0; /* ... Timer 1 stoppen */
setT3(); /* Timer 3 neu starten */
++lnkpoi->tries; /* Retryzaehler */
if ( !lnkpoi->N2
|| lnkpoi->tries < lnkpoi->N2 /* zu viele Retries ? */
)
if ( lnkpoi->V2link == YES /* nein, bei V2 oder */
|| lnkpoi->state < L2SIXFER /* V1-Status < IXFER */
) l2stma(stbl23); /* Statet. T1 EXPIRES */
else /* sonst ausstehende */
sdoi(); /* I's senden */
else
{ /* zu viele Retries : */
lnkpoi->tries = 0; /* Retryzaehler leer */
clrlnk(); /* Link sofort loesch. */
l2tolx(L2MFAILW); /* "Link failure" */
lnkpoi->state = L2SDSCED; /* DISCONNECTED */
}
}
else
lnkpoi->T1 -= ticks; /* sonst herunterzaehlen */
if (lnkpoi->T2 != 0) /* wenn Timer 2 aktiv ... */
if (lnkpoi->T2 <= ticks) /* wenn Timer 2 abgelaufen ... */
lnkpoi->T2 = 0; /* ... Timer 2 stoppen */
else
lnkpoi->T2 -= ticks; /* sonst herunterzaehlen */
if ( !lnkpoi->T2 /* wenn Timer 2 abgelaufen ist */
&& lnkpoi->RStype != 0 /* und Response zu senden ist */
&& !iscd(lnkpoi->liport) /* und der Kanal frei ist ... */
)
{
stxfad(); /* ... dann Responseframe bauen */
txfCR = txfPF = 0;
txfctl = setNR( !(lnkpoi->flag & L2FBUSY)
? lnkpoi->RStype
: L2CRNR
);
sdl2fr(makfhd(L2FUS)); /* und senden */
lnkpoi->RStype = 0; /* Responsemodus loeschen */
}
if (lnkpoi->T3 != 0) /* wenn Timer 3 aktiv ... */
if (lnkpoi->T3 <= ticks) /* wenn Timer 3 abgelaufen ... */
{
clrT3(); /* ... Timer 3 stoppen und */
l2stma(stbl24); /* Statetable T3 EXPIRES */
} /* ausfuehren */
else
lnkpoi->T3 -= ticks; /* sonst herunterzaehlen */
}
}
/* Ende von L2A.C */