TheNetNode-CB/src/l2rx.c

1051 lines
48 KiB
C
Executable File

/************************************************************************/
/* */
/* ***** ***** */
/* ***** ***** */
/* ***** ***** */
/* ***** ***** */
/* *************** *************** */
/* ***************** ***************** */
/* *************** *************** */
/* ***** ***** TheNetNode */
/* ***** ***** Portable */
/* ***** ***** Network */
/* ***** ***** Software */
/* */
/* File src/l2rx.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"
#ifdef IPROUTE
static MBHEAD *pid8frag(MBHEAD *);
#endif
static BOOLEAN srxdNR(void);
static BOOLEAN isnxti(void);
/* max. Anzahl anzunehmender Frames wenn BUSY */
#ifdef EAX25
#define LINKBUSY ((lnkpoi->flag & L2FBUSY) && (lnkpoi->busyrx >= (lnkpoi->bitmask == 0x7F) ? 16 : 7))
#else
#define LINKBUSY ((lnkpoi->flag & L2FBUSY) && (lnkpoi->busyrx >= 7))
#endif
/*----------------------------------------------------------------------*/
/* */
/* "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(void)
{
UBYTE *source; /* Zeiger auf Quellrufzeichen/SSID */
WORD l2state; /* aktueller Level 2 Linkstatus */
MBHEAD *fbp; /* Framebufferpointer lokal */
int i;
int frmr_bytes = 3; /* Anzahl Bytes bei FRMR */
#ifdef USERMAXCON
LNKBLK *lnk;
WORD user_links;
#endif
/* solange empfangene Frames vorhanden */
while ((fbp = (MBHEAD *)rxfl.head) != (MBHEAD *)&rxfl)
{
ulink((LEHEAD *)fbp); /* eins aus Liste holen */
if (!takfhd(fbp)) /* Kopf analysieren */
{
dealmb(fbp); /* nicht ok, dann wegwerfen */
continue; /* naechstes Frame */
}
fbp->type = 2; /* wir sind im Level 2 */
fbp->tx = 0; /* es ist ein empfangenes Frame */
monitor(fbp); /* an den Monitor */
if (rxfctl == L2CUI) /* UI-Frame */
{
/* if (istome(rxfhdr) == TRUE) * wenn an mich .. */
/* if (rxfPF != FALSE * .. und Antwort gewuenscht .. */
/* && rxfCR != FALSE) */
/* xdm(); * beantworten mit DM */
/* */
/* Dies ist ein Protokollverstoss! Nach AX.25-Protokoll soll auf ein */
/* UI-Frame mit Poll nur dann mit DM geantwortet werden, wenn kein Link */
/* besteht. Wenn dagegen ein Link besteht, soll entsprechend Linkzu- */
/* stand geantwortet werden. Dadurch kann ein bestehender, gut funktio- */
/* nierender Link vorzeitig beendet werden. Jetzt wird der Fehler so */
/* geaendert, dass auf eine Reaktion hier vollkommen verzichtet wird. */
/* Manche Spielkinder hatten ausserdem bemerkt, dass man einen Knoten */
/* abschiessen kann, wenn man ihm in einer Aussendung beliebig viele */
/* UI-Frames mit Poll schickt. Dadurch werden naemlich fuer die Ant- */
/* wort-Frames beliebig viele Buffer belegt, bis der Knoten einen Reset */
/* ausloest. Auch deshalb ist es guenstiger, hier auf eine Reaktion zu */
/* verzichten. Wenn es jemanden stoeren sollte, darf er natuerlich die */
/* vom AX.25-Protokoll geforderte Reaktion einbauen. */
lnkpoi = NULL; /* kein Linkpointer */
/* PID des UI-Frames holen wenn noch Bytes da, sonst 0 eintragen */
fbp->l2fflg = (fbp->mbgc < fbp->mbpc) ? getchr(fbp) : 0;
/* Fuer uns interessantes UI-Frame ? */
if ( (cmpid(rxfhdr, myid)) /* an mich direkt */
|| (cmpid(rxfhdr, "NODES \140")) /* NETROM-Nodes */
#ifdef IPROUTE
|| (istomev() == 4) /* AX25-ARP an "QST" */
|| (istomev() == 5) /* AX25-ARP an "QST" */
#endif
)
{
/* UI-Frame bearbeiten */
if (!tol3sw(fbp))
dealmb(fbp);
}
else /* UI-Frames, die gedigipeated werden koennen/muessen */
gateway_ui(rxfhdr + L2IDLEN, rxfhdr, rxfhdr + L2ILEN, fbp);
continue;
}
/* Haben wir einen zum Frame passenden Linkblock ? */
/* */
/* Die Linkliste dieses Ports durchgehen und nach einem passenden Link- */
/* block ausschau halten. Wurde er gefunden, wird er an das Ende der */
/* Liste gehaengt, weil die Liste im naechsten Durchlauf wieder von */
/* hinten durchsucht wird. */
/* */
/* Wenn wir keinen passenden Link haben, aber das Framezielcall an mich */
/* (Call + SSID oder Ident mit beliebiger SSID) ist, oder das Block- */
/* quellcall mit dem Framezielcall uebereinstimmt, dann einen neuen */
/* Link aus der Freiliste holen. */
/* Wichtig: Es wird der Header, den wir senden wuerden, mit der Link- */
/* liste verglichen (txf...) */
/* printf("\nistomev() = %u\n", istomev()); */
#ifdef __WIN32__
lnkpoi = getlnk((unsigned char)rxfprt, txfhdr + L2IDLEN, txfhdr, txfhdr + L2ILEN);
#else
lnkpoi = getlnk(rxfprt, txfhdr + L2IDLEN, txfhdr, txfhdr + L2ILEN);
#endif /* WIN32 */
/* Jetzt haben wir einen Pointer auf den Link, der entweder schon vorher*/
/* bestand, oder der jetzt neu angelegt wurde. Ist der Pointer gleich */
/* NULL, dann ist was schiefgegangen und wir koennen nicht annehmen. */
if (lnkpoi == NULL) /* keinen passenden Linkblock gefunden und es */
/* kann kein Link mehr angenommen werden. */
{
if (istome(rxfhdr)) /* Verbindung fuer mich ? */
{
if ( rxfctl == L2CSABM /* SABM */
#ifdef EAX25
|| rxfctl == L2CSABME /* SABME (EAX.25) */
#endif
)
{
l2tolx(L2MBUSYT); /* hoeheren Leveln melden */
xdm(); /* mit DM beantworten */
}
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 wegwerfen */
continue; /* und zum naechsten */
}
if (lnkpoi->state == L2SDSCED) /* wir haben den Link noch nicht */
{
if (istomev() == 0) /* nicht fuer mich und auch nicht via */
{
dealmb(fbp); /* Frame wegwerfen */
continue; /* 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 */
#ifdef DAMASLAVE
if (rxfDA) /* DAMA? */
{
if (damaslave(rxfprt)) /* DAMA-Slave auf Port erlaubt? */
{
portpar[rxfprt].damaok = 12000; /* 2 Minuten Timeout */
if (rxfPF && rxfCR) /* wenn gepollt */
{
l2stma(stbl10a); /* DAMA-Poll receive */
portpar[rxfprt].sendok = 1;
if (l2state) /* aktiver Link ? */
if ( (rxfctl & L2CNONRM) != L2CNONRM /* Frame mit N(R) */
&& srxdNR() == TRUE /* Zaehlerstand ok */
&& lnkpoi->VS != lnkpoi->lrxdNR /* noch was offen? */
)
{
++lnkpoi->tries; /* Retryzaehler erhoehen */
#ifdef T1TIMERMOD
/* Nach 3 erfolglosen Versuche, */
/* wird der SRTT-Wert vergroessert. */
if ( (lnkpoi->tries > 2)
/* SRTT-Wert kleiner als 50. */
&&(lnkpoi->SRTT < 50))
{
lnkpoi->RTT = 10;
clrRTT();
}
#endif /* T1TIMERMOD */
lnkpoi->flag |= L2FREPEAT;
/* da nicht alles bestaetigt, wird Maxframe um 1 reduziert */
change_maxframe(lnkpoi, -1);
}
}
}
}
#endif
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() /* N(R) ok? */
&& isnxti()) /* erwartet? */
{
if (fbp->mbpc - fbp->mbgc <= L2MILEN + 1) /* Info-Laenge ok? */
{
lnkpoi->tries = 0;
/*----------------------------------------------------------------------*/
/* Bei DAMA-Betrieb auf dem Port eventuell erstes neues I-Poll */
/* anmeckern. DAMA-Ack-Poll verzoegern, bis alle Infos verarbeitet.. */
/* Aktivitaetszaehler und -merker loeschen */
/*----------------------------------------------------------------------*/
if (dama(rxfprt)) /* I-Frame auf DAMA-Port ? */
{
if (rxfPF & L2CPF) /* Wenn I-Poll.. */
{
polDAMA(); /* anmeckern.. */
l2stma(stbl00dama);
}
else /* kein Poll */
{
clrDAMA(); /* DAMA clear ! */
setT2(0); /* T2 setzen */
lnkpoi->damapc = lnkpoi->T2; /* und fuer DAMA nehmen */
l2stma(stbl01dama); /* DAMA braucht auch T2.. */
}
}
else
if (rxfPF & L2CPF) /* Poll */
l2stma(stbl00);
else /* kein Poll */
l2stma(stbl01);
/* Wenn kein I-Frame mehr kommen kann, T2 loeschen */
if (((lnkpoi->VR - lnkpoi->ltxdNR) & lnkpoi->bitmask) == lnkpoi->bitmask)
{
lnkpoi->T2 = 0; /* T2 loeschen */
if (dama(rxfprt))
lnkpoi->damapc = 0;
}
/* Linkzustand I-Transfer moeglich und nicht busy ? */
if ( (l2state >= L2SIXFER)
&& (l2state != L2SHTH)
&& !LINKBUSY)
{
if (lnkpoi->flag & L2FBUSY)
lnkpoi->busyrx++;
fbp->l2fflg = fbp->mbgc < fbp->mbpc ? getchr(fbp) : 0;
#ifdef IPROUTE
if (istome (rxfhdr))
if ((fbp = pid8frag(fbp)) == NULL)
continue;
#endif
/*----------------------------------------------------------------------*/
/* 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))
#ifndef THENETMOD
lnkpoi->noatou = ininat;
#else /* L4TIMEOUT */
lnkpoi->noatou = SetL4Timeout(); /* L2/L4-Timeout setzen. */
#endif /* THENETMOD */
else
{
/*----------------------------------------------------------------------*/
/* wenn normales Level-2-I-Paket, wenn nicht Busy oder Level-3-Link, I */
/* annehmen und in Linkempfangsliste einhaengen */
/*----------------------------------------------------------------------*/
if (!(lnkpoi->flag & (L2FDSLE | L2FDIMM)))
{
relink((LEHEAD *)fbp, (LEHEAD *)lnkpoi->rcvdil.tail);
++lnkpoi->rcvd;
}
else /* sonst */
dealmb(fbp); /* Paket verwerfen */
}
continue; /* naechstes Paket */
}
}
else /* Frame zu lang */
sdfrmr(0x03); /* U/S-Frame invalid! */
}
} /* durchfallen und Frame wegschmeissen */
else /* kein I-Frame : */
{
if (!(rxfctl & L2CNOSM)) /* "no S mask", kein S-Frame */
{
/*----------------------------------------------------------------------*/
/* 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()) /* N(R) ok? */
{
if (fbp->mbgc == fbp->mbpc) /* kein I-Feld? */
{
lnkpoi->tries = 0;
if (dama(rxfprt)) /* Auf DAMA-Links: */
incDAMA(); /* Prioritaet runter */
switch (rxfctl & 0x0c)
{
case L2CRR & 0x0c: /* RR Frame */
l2stma(!rxfCR
? (!rxfPF ? stbl11 : stbl10)
: (!rxfPF ? stbl03 : stbl02));
if (dama(rxfprt)) /* wenn DAMA-Port */
if (rxfCR && rxfPF) /* und gepollt wird */
polDAMA(); /* DAMA-Warnung */
break;
case L2CRNR & 0x0c: /* RNR Frame */
l2stma(!rxfCR
? (!rxfPF ? stbl15 : stbl14)
: (!rxfPF ? stbl07 : stbl06));
lnkpoi->flag |= L2FREPEAT;
break;
case L2CREJ & 0x0c: /* REJ Frame */
l2stma(!rxfCR
? (!rxfPF ? stbl13 : stbl12)
: (!rxfPF ? stbl05 : stbl04));
if ((l2state >= L2SIXFER) && (l2state != L2SHTH))
{
/* bei REJ wird Maxframe um 1 reduziert - wer mies empfaengt, landet */
/* irgendwann bei Maxframe 1 */
change_maxframe(lnkpoi, -1);
lnkpoi->flag |= L2FREPEAT;
#ifndef DAMASLAVE
if (!dama(rxfprt))
#else
if ( !dama(rxfprt)
&& !damaslaveon(rxfprt))
#endif
sdoi(); /* ausstehende I-Frames senden */
}
break;
default: /* Kontrollfeld falsch oder nicht */
sdfrmr(0x01); /* implementiert! */
break;
} /* switch */
}
else /* U/S-Frame mit */
sdfrmr(0x03); /* unerlaubtem I-Feld */
}
} /* END S-Frame */
else /* Kein S-Frame, dann Frame der U-Gruppe */
{
if ((rxfctl & 0xFF) != L2CFRMR)
{
/*----------------------------------------------------------------------*/
/* Kein FRMR-Frame, Frame nur annehmen, wenn kein Infofeld vorhanden. */
/* */
/* Frame auswerten, reagieren, nach Statetable antworten. */
/*----------------------------------------------------------------------*/
clrT3(); /* Timer 3 loeschen */
if (fbp->mbgc == fbp->mbpc)
{
switch (rxfctl)
{
case L2CSABM: /* neuer Link/-reset */
#ifdef EAX25
case L2CSABME: /* neuer EAX.25-Link */
#endif
#ifdef USERMAXCON
/* Zaehlung auf Port aktiv und Call OK und SABM-Frame fuer/ueber mich ? */
if ( (portpar[rxfprt].maxcon != 0)
&& (fvalca(rxfhdr + L2IDLEN) == YES)
&& (istomev() != 0))
{
/* Anzahl der Connects dieses Users auf *diesem* Port ermitteln */
for (lnk = lnktbl, i = 0, user_links = 0; i < LINKNMBR; i++, lnk++)
if ( (cmpcal(lnk->dstid, (rxfhdr + L2IDLEN)))
&& (lnk->state != L2SDSCED)
&& (lnk->liport == rxfprt))
user_links++;
/* noch Connects frei ? */
if (user_links >= portpar[rxfprt].maxcon)
{
/* nein, also den Verbindungswunsch ablehnen */
xdm(); /* mit DM antworten */
dealmb(fbp); /* Frame wegschmeissen */
continue;
}
}
#endif
if (fvalca(rxfhdr + L2IDLEN) != YES)
{
l2tolx(L2MBUSYT); /* nein, melden */
xdm(); /* mit DM antworten */
dealmb(fbp); /* Frame vergessen */
continue; /* naechstes Paket */
}
#ifdef EAX25
/* Ist kein EAX.25 auf diesem Port erlaubt, dann */
/* Verbindung abwerfen. Das Gleiche noch mal fuer den */
/* Fall dass nur EAX.25 erzwungen ist, Frame aber AX.25 ist */
if ( ((rxfctl == L2CSABME) && (portpar[rxfprt].eax_behaviour == 0))
|| ((rxfctl == L2CSABM) && (portpar[rxfprt].eax_behaviour == 3)))
{
xdm(); /* mit DM antworten */
dealmb(fbp); /* Frame vergessen */
continue; /* naechstes Paket */
}
/* Nur auf EAX.25 umschalten wenn SABME, EAX-Flag ignorieren */
if (rxfctl == L2CSABME)
{
/* EAX-Verbindung kennzeichnen und Maxframe aendern */
lnkpoi->bitmask = 0x7F;
#ifdef __WIN32__
lnkpoi->maxframe = (unsigned char)portpar[rxfprt].maxframe_eax;
#else
lnkpoi->maxframe = portpar[rxfprt].maxframe_eax;
#endif /* WIN32 */
}
else
lnkpoi->bitmask = 0x07; /* normale AX.25-Verbindung */
#endif
/* TEST DG9OBU */
/* Linkwunsch via uns, kennen wir einen Weg ? */
/* ebenfalls: Linkwuensche an unsere Locals ? */
/* (Wird gebraucht bei FlexNet SSID-Bereichsmeldung) */
if ( (lnkpoi->state == L2SDSCED) /* nicht verbunden */
&& ( (istomev() == 2) /* an mich mit via */
/* nicht an mich, aber einen Local oder in SSID-Range */
|| ((istomev() == 3) && (islocal(rxfhdr) != NO))
#ifdef PROXYFUNC
|| isproxy(rxfhdr)
#endif
)
)
{
if (conn_ok(rxfhdr)) /* Ziel bekannt? */
{
l2stma(stbl08a); /* ja, nicht reagieren */
/* bis Link steht */
}
else /* nein - kein neuer */
{ /* Link moeglich */
dealmb(fbp); /* Frame vergessen */
continue; /* naechstes Paket */
}
}
else
l2stma(stbl08);
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 */
}
l2stma(stbl09); /* DISC EITHER COMMAND */
break;
case L2CUA:
l2stma(stbl16); /* UA EITHER RESPONSE */
break;
case L2CDM:
#ifdef EAX25
/* Wird unser SAMBE mit DM beantwortet, dann Rueckfall */
/* auf AX.25 */
if ((l2state == L2SLKSUP) && (lnkpoi->bitmask == 0x7F))
{
/* Rueckfall nur wenn Port nicht nur EAX.25 zulaesst */
if (portpar[rxfprt].eax_behaviour != 3)
lnkpoi->bitmask = 0x07;
dealmb(fbp); /* Frame wegwerfen */
continue;
}
#endif
l2stma(stbl17); /* DM EITHER RESPONSE */
break;
default: /* unbekanntes Kontrollfeld : */
sdfrmr(0x01); /* "Kontrollfeld falsch oder */
break; /* nicht implementiert" */
} /* end switch (rxfctl) */
} /* if */
else
sdfrmr(0x03); /* Frametyp unbekannt "U/S-Frame mit un- */
/* erlaubtem Infofeld" */
}
else
{
/* FRMR-Frame : */
/* */
/* Wird nur im Frame-Reject-Zustand oder bei moeglichem Informations- */
/* transfer angenommen. Es werden die FRMR-Infobytes gelesen, FRMR an */
/* die hoeheren Level gemeldet, nach Statetable geantwortet. */
if ( (l2state >= L2SIXFER && l2state != L2SHTH)
|| l2state == L2SFRREJ)
{
#ifdef EAX25
/* FRMR ist bei EAX.25 laenger, neue Laenge setzen */
if (lnkpoi->bitmask == 0x7F)
frmr_bytes = 5;
#endif
for (source = lnkpoi->frmr, i = 0; i < frmr_bytes; ++i)
{
*source++ = (fbp->mbgc < fbp->mbpc) ? getchr(fbp) : 0;
}
}
l2stma(stbl18); /* FRMR EITHER RESPONSE */
}
}
}
dealmb(fbp); /* aktuelles Frame verarbeitet, wegwerfen */
} /* end while ((fbp = rxfl.head) != &rxfl) */
}
/************************************************************************/
/* */
/* "take frame head" */
/* */
/* Adresskopf und Kontrollbyte des Frames aus dem Framebuffer, auf */
/* dessen Kopf fbp zeigt, analysieren. Diese Funktion ist die erste, */
/* die auf ein empfangenes Frame angewandt wird. */
/* */
/* */
/* Folgende Parameter werden bei der Analyse gesetzt: */
/* */
/* rxfhdr, rxfPF, rxfCR, rxfctl, rxfprt, rxfDA */
/* (rxfEAX, rxfctlE wenn Extended-AX.25 aktiviert) */
/* */
/* Folgende Parameter werden nach der Analyse gesetzt fuer ein */
/* moegliches Antwortframe : */
/* */
/* txfhdr = Quell- und Zielcall aus rxfhdr, aber vertauscht, plus */
/* reverse via-Liste aus rxfhdr */
/* txfPF = rxfPF */
/* txfCR = 0, Response ! */
/* txfprt = rxfprt */
/* */
/* */
/* Return : TRUE - das Frame hat einen gueltigen AX.25-Framekopf */
/* FALSE - sonst */
/* */
/************************************************************************/
BOOLEAN
takfhd(MBHEAD *fbp)
{
char *p; /* Zeiger im Header */
char *source; /* Quellzeiger Kopien */
char *dest; /* Zielzeiger Kopien */
int n;
rxfprt = fbp->l2port; /* Port uebernehmen */
if (!portenabled(rxfprt)) /* Port gesperrt */
return (FALSE);
rwndmb(fbp); /* Frame von vorne */
for (p = rxfhdr, n = 1; n <= L2INUM + L2VNUM; n++)
{
if (!getfid(p, fbp)) /* naechstes Call lesen */
{
INV_FRAME(rxfprt, INVF_ADR);
return (FALSE);
}
p += L2IDLEN;
if (*(p - 1) & L2CEOA)
break; /* Ende des Addressfeldes */
}
*(p - 1) &= ~L2CEOA;
if (n < L2INUM) /* Absender und/oder Ziel fehlt */
{
INV_FRAME(rxfprt, INVF_ALN);
return (FALSE);
}
if (n > L2VNUM + L2INUM) /* Addressfeld zu lang */
{
INV_FRAME(rxfprt, INVF_ALN);
return (FALSE);
}
*p = NUL; /* Addressfeld terminieren */
if (fbp->mbgc == fbp->mbpc) /* Control-Feld fehlt? */
{
INV_FRAME(rxfprt, INVF_CTL);
return (FALSE);
}
rxfctl = getchr(fbp); /* Control-Byte extrahieren */
/* Framelaengencheck UI-Frames: jetzt duerfen noch max. 257 ungelesene */
/* Bytes im Buffer sein! (PID + 256 Bytes Info) */
if ((rxfctl == L2CUI) && (fbp->mbpc - fbp->mbgc > L2MILEN + 1))
return (FALSE);
rxfDA = !(rxfhdr[L2ILEN-1] & L2CDAMA); /* ist es ein DAMA-Frame? */
rxfhdr[L2ILEN-1] |= L2CDAMA; /* DAMA-Flag zuruecksetzen */
#ifdef EAX25
/* EAX-Bit maskieren und invertieren, da im Frame geloescht gleich */
/* aktiviert bedeutet, hier aber "normale" Logik verwendet wird. */
rxfEAX = !(rxfhdr[L2ILEN-1] & L2CEAX); /* ist es ein Extended-Frame? */
rxfhdr[L2ILEN-1] |= L2CEAX; /* EAX.25-Flag zuruecksetzen */
/* bei EAX-Frames zweites Control-Byte lesen wenn nicht U-Frame */
if (rxfEAX && !((rxfctl & 0x03) == 3)) /* kein U-Frame, dann zweites */
rxfctlE = getchr(fbp); /* zweites Controlbyte lesen */
else
rxfctlE = 0; /* zweites Controlbyte leer */
#endif
/* Unterscheidung AX.25 V1- oder V2-Frame, wir koennen nur V2 */
if (((rxfhdr[L2IDLEN - 1] ^ rxfhdr[L2ILEN - 1]) & L2CCR) != 0)
{
/* Auswertung normale AX.25-Frames und EAX U-Frames */
rxfCR = rxfhdr[L2IDLEN - 1];
rxfCR &= L2CCR;
#ifdef EAX25
/* Pollflag befindet sich an unterschiedlichen Positionen */
if ( !rxfEAX
|| (rxfEAX && ((rxfctl & 0x03) == 3)))
#endif
rxfPF = rxfctl & L2CPF; /* Auswertung Pollflag bei AX.25 */
#ifdef EAX25
else
rxfPF = (rxfctlE << 4) & L2CPF; /* Auswertung Pollflag bei EAX25 */
#endif
}
else
return (rxfctl == L2CUI); /* V1-Frame, nur UI nehmen */
#ifdef EAX25
/* PF-Bit ruecksetzen */
if ( !rxfEAX
|| (rxfEAX && ((rxfctl & 0x03) == 3)))
#endif
rxfctl &= ~L2CPF; /* AX.25 */
#ifdef EAX25
else
rxfctlE &= 0xFE; /* EAX.25 */
#endif
txfCR = 0; /* Command-Flag fuer TX-Frame */
txfPF = rxfPF; /* Poll-Flag bei TX wie bei RX */
txfprt = rxfprt; /* TX-Port gleich RX-Port */
cpyid(txfhdr, rxfhdr + L2IDLEN); /* Calls von Absender und Ziel */
cpyid(txfhdr + L2IDLEN, rxfhdr); /* vertauschen */
/* Jetzt wird das via-Feld so umgebaut, wie es bei der Sendung aussehen */
/* wird. */
for (source = rxfhdr + L2ILEN; *source; source += L2IDLEN)
;
for (dest = txfhdr + L2ILEN; source != rxfhdr + L2ILEN; dest += L2IDLEN)
{
source -= L2IDLEN;
memcpy(dest, source, L2IDLEN); /* Rufzeichen kopieren */
dest[L2IDLEN - 1] ^= L2CH;
}
*dest = NUL;
return (TRUE);
}
/************************************************************************/
/* */
/* "level 2 to level x" */
/* */
/* Meldung msg (L2M...) an Layer 3 und hoehere Layer weitergeben. */
/* */
/************************************************************************/
void
l2tolx(WORD msg)
{
if (!l2tol3(msg)) /* Layer 2 -> Layer 3 */
l2tol7(msg, lnkpoi, L2_USER); /* Layer 2 -> Layer 7 */
}
/************************************************************************\
* *
* Informationstransfer von Layer 2 nach Layer X *
* --------------------------------------------- *
* *
* Infopakete aus dem aktuellen Link (lnkpoi) an hoehere Level *
* weiterreichen. conctl gibt an, ob der hoehere Level die *
* Erstickungskontrolle" (hier = Beruecksichtigung der maximal *
* noch anzunehmenden I-Pakete) machen soll (FALSE) oder in jedem *
* Fall alle uebermittelten I-Pakete annehmen muss (TRUE). Falls *
* die I-Pakete vom hoeheren Level angenommen wurden, Empfangs- *
* zaehler rcvd und Aktivitaetstimer noatou entsprechend updaten. *
* Es wird l2link in den Framekoepfen der weitergereichten Pakete *
* auf lnkpoi gesetzt und type auf 2 fuer "Level 2". *
* *
* Solange noch empfangene Pakete vorhanden sind, werden diese *
* an andere Layer durch Aufruf von fmlink() uebertragen. Bei ge- *
* setztem Ueberfuellungskontroll-Flag (conctl == TRUE) wird die *
* Uebertragung abgebrochen, wenn der andere Layer keine weiteren *
* Daten mehr aufnehmen kann. *
* *
* Nach erfolgter Uebertragung wird die Anzahl der uebertragenen *
* Zeichen fuer die Statistik gezaehlt und der No-Activity-Timer *
* neu gesetzt. *
* *
\************************************************************************/
void
i2tolx(BOOLEAN conctrl)
{
MBHEAD *mbp; /* Zeiger auf Framekopf weiterzureichendes I */
if ( (lnkpoi->state == L2SDSCRQ)
|| (lnkpoi->flag & (L2FDSLE | L2FDIMM)))
{
dealml((LEHEAD *)&lnkpoi->rcvdil);
lnkpoi->rcvd = 0;
return;
}
while (lnkpoi->rcvd != 0) /* solange I's aus Link vorhanden */
{
mbp = (MBHEAD *)lnkpoi->rcvdil.head;
mbp->l2link = lnkpoi; /* Linkzeiger */
mbp->type = 2; /* Level 2 ! */
if (!fmlink(conctrl, mbp)) /* I an hoeheren Level geben */
return; /* Abbruch, wenn nicht angenommen */
#ifndef THENETMOD
lnkpoi->noatou = ininat;
#else /* L4TIMEOUT */
lnkpoi->noatou = SetL4Timeout(); /* L2/L4-Timeout setzen, */
#endif /* THENETMOD */
--lnkpoi->rcvd; /* Empfangspaketezaehler updaten */
}
}
/************************************************************************\
* *
* "serve received N(R)" *
* *
* Aktuell empfangenes N(R) (rxfctl) des aktuellen Links (lnkpoi) *
* auswerten und entsprechend verfahren (s.u.). *
* *
* Return: TRUE - aktuell empfangenes N(R) ist okay oder *
* Linkzustand laesst N(R)-Empfang nicht zu *
* FALSE - aktuell empfangenes N(R) ist falsch *
* *
\************************************************************************/
static BOOLEAN
srxdNR(void)
{
#ifdef __WIN32__
char rxdNR; /* emfangenes N(R) */
#else
WORD rxdNR; /* emfangenes N(R) */
#endif
WORD newok; /* Anzahl neu bestaetigte I's */
WORD outstd; /* Anzahl ausstehende (unbestaetigte) I's */
WORD l2state; /* Link-Status */
l2state = lnkpoi->state;
if (l2state >= L2SIXFER && l2state != L2SHTH) /* darf N(R) kommen? */
{
#ifdef EAX25
/* EAX I- und S-Frames gesondert behandeln, U-Frames wie bei AX25 */
if ( (lnkpoi->bitmask == 0x7F) && ((rxfctl & 0x03) <= 2))
rxdNR = ((rxfctlE >> 1) & 0x7F);
else
#endif
rxdNR = ((rxfctl >> 5) & 0x07); /* Sequenznummer lesen */
if ( (outstd = outsdI()) != 0 /* Wenn I's ausstehen und */
&& (newok = ((rxdNR - lnkpoi->lrxdNR) & lnkpoi->bitmask)) != 0)
{ /* neue bestaetigt wurden: */
if (newok <= outstd) /* und nicht zuviel bestaet. */
{
if ( (lnkpoi->lrxdNR)
&&((lnkpoi->RTTvs - lnkpoi->lrxdNR) & lnkpoi->bitmask) >= newok)
clrRTT(); /* RTT-Messung ok, stoppen */
#ifdef __WIN32__
lnkpoi->lrxdNR = (char)rxdNR; /* dann N(R) annehmen, */
#else
lnkpoi->lrxdNR = rxdNR; /* dann N(R) annehmen, */
#endif /* WIN32 */
clrT1(); /* T1 stoppen, */
/* Sind alle ausstehenden I's */
if (newok == outstd) /* bestaetigt worden ? */
{ /* ja: */
/* Da alles bestaetigt, kann Maxframe erhoeht werden */
change_maxframe(lnkpoi, +1);
if ((signed char)lnkpoi->priold != -1) /* bei Downlink-Aktivitaet: */
#ifdef __WIN32__
lnkpoi->damapm = (unsigned char)lnkpoi->priold; /* Prioritaet reseten */
#else
lnkpoi->damapm = lnkpoi->priold; /* Prioritaet reseten */
#endif /* WIN32 */
lnkpoi->priold = -1; /* Priori-Flag loeschen */
clearDT(0); /* DAMA-Timer loeschen <<<< */
}
else
setT1(); /* T1 neu starten */
while (newok-- != 0) /* Alle bestaetigten Frames */
{ /* aus der Liste entfernen */
dealmb((MBHEAD *)ulink((LEHEAD *)lnkpoi->sendil.head));
--lnkpoi->tosend;
}
}
else /* Mehr I's bestaetigt als */
{
sdfrmr((char)0x08); /* ausstehen. Das geht nicht. */
return (FALSE); /* FRMR erzeugen, N(R) falsch */
}
}
if ( l2state == L2SWA /* Falls warten auf Bestaetigung */
|| l2state == L2SWADBS
|| l2state == L2SWARBS
|| l2state == L2SWABBS)
{
if (!rxfCR && rxfPF != 0) /* Wenn RR mit Final war, dann */
{
clrT1(); /* T1 stoppen */
clrRTT(); /* RTT stoppen, Messung gueltig */
if (lnkpoi->VS != lnkpoi->lrxdNR)
lnkpoi->flag |= L2FREPEAT;
clearDT(0); /* DAMA-Timer loeschen */
}
else if (!lnkpoi->T1) /* T1 neu starten */
setT1();
}
}
return (TRUE);
}
/************************************************************************\
* *
* "is next I" *
* *
* Testen, ob das aktuell empfangene I-Frame (rxf...) das naechste fuer *
* den aktuellen Linkblock (lnkpoi) erwartete I-Frame ist, wenn der *
* Linkzustand Informationstransfer zulaesst. Bei nicht erwarteter *
* Sequenznummer entsprechende Statetable abarbeiten. *
* *
* Return : TRUE - I-Frame ist das naechste erwartete oder Linkzustand *
* laesst keinen Informationstransfer zu *
* FALSE - sonst *
* *
\************************************************************************/
static BOOLEAN
isnxti(void)
{
WORD iseqno; /* I Sequence Number */
if ( lnkpoi->state >= L2SIXFER
&& lnkpoi->state != L2SHTH) /* I-Transfer? */
{
/* N(S) des Kontrollfeldes maskieren, diese Framenummer erwartet ? */
if ((iseqno = (rxfctl >> 1) & lnkpoi->bitmask) == lnkpoi->VR) /* I erwartet ? */
{
/* Maximale Erhoehung des Sequenzzaehlers */
if (((lnkpoi->ltxdNR + lnkpoi->bitmask) & lnkpoi->bitmask) != iseqno) /* kein Ueberlauf ? */
{
if (!LINKBUSY) /* wenn nicht busy, neue */
lnkpoi->VR = (iseqno + 1) & lnkpoi->bitmask; /* V(R) setzen */
}
else
{
sdfrmr((char)0x01);
return (FALSE);
}
}
else
{ /* unerwartetes Info: */
l2stma(!rxfPF ? stbl26 : stb26b); /* INVALID N(S) RECEIVED */
if (dama(lnkpoi->liport) && rxfPF) /* I-Poll ? <=== */
polDAMA(); /* ja: muss meckern! <=== */
return (FALSE);
}
}
return (TRUE); /* I richtig oder Linkzustand ohne I-Transfer */
}
/************************************************************************\
* *
* "info to layer x and clear link" *
* *
* Empfangsdaten ohne Flowcontrol in den Layer hochmelden und dann *
* Link zuruecksetzen. *
* *
\************************************************************************/
void
i2xclr(void)
{
i2tolx(TRUE);
clrlnk();
}
#ifdef IPROUTE
/************************************************************************\
* *
* "pid 8 fragmentierung" *
* *
* Ein PID 8 Frame empfangen und ggfs mit vorhergehenden Frames zusammen- *
* basteln. *
* *
\************************************************************************/
static MBHEAD *
pid8frag(MBHEAD *fbp)
{
BYTE anz_frag;
MBHEAD *ret;
int len;
if (fbp->l2fflg != L2CFRAG) /* PID 08 ? */
return (fbp); /* nein, dann Frame zurueck */
if ((len = fbp->mbgc - fbp->mbpc) == 0) /* leeres Frame? */
{
if (lnkpoi->tmbp != NULL)
dealmb(lnkpoi->tmbp);
dealmb(fbp);
return(NULL);
}
anz_frag = getchr(fbp); /* erstes Byte lesen */
if (anz_frag & 0x80) /* erstes PID08-Frame */
{
if (lnkpoi->tmbp != NULL) /* Fehler! Letztes Paket war */
dealmb(lnkpoi->tmbp); /* noch nicht komplett */
if (len == 1) /* keine PID im 1. Frame? */
{
dealmb(fbp);
return(NULL);
}
anz_frag &= 0x7F; /* Anzahl der Folgefragmente */
lnkpoi->tmbp = (MBHEAD *)allocb(ALLOC_MBHEAD); /* Buffer besorgen */
lnkpoi->tmbp->l2fflg = getchr(fbp); /* PID des Originals lesen */
}
else
if (lnkpoi->tmbp == NULL) /* Fehler! Folgefragment ohne */
{ /* vorheriges 1. Fragment */
dealmb(fbp); /* hier muesste eigentlich ein */
return (NULL); /* FRMR fuer PID08 folgen, gips */
} /* aber wohl nicht? */
while (fbp->mbgc < fbp->mbpc)
putchr(getchr(fbp), lnkpoi->tmbp);
dealmb(fbp);
if (anz_frag == 0) /* letztes Frame! */
{
rwndmb(lnkpoi->tmbp); /* zurueckspulen */
ret = lnkpoi->tmbp;
lnkpoi->tmbp = NULL;
return (ret); /* und an L2 uebergeben */
}
else
return (NULL); /* es folgen weitere Teile */
}
#endif
/* End of src/l2rx.c */