968 lines
38 KiB
C
Executable File
968 lines
38 KiB
C
Executable File
/************************************************************************/
|
|
/* */
|
|
/* ***** ***** */
|
|
/* ***** ***** */
|
|
/* ***** ***** */
|
|
/* ***** ***** */
|
|
/* *************** *************** */
|
|
/* ***************** ***************** */
|
|
/* *************** *************** */
|
|
/* ***** ***** TheNetNode */
|
|
/* ***** ***** Portable */
|
|
/* ***** ***** Network */
|
|
/* ***** ***** Software */
|
|
/* */
|
|
/* File src/l2tx.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"
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
/* */
|
|
/* "level 2 transmitter" */
|
|
/* */
|
|
/* Falls auf dem Port keine Aktivitaet ist (PTT aus) und fuer eine */
|
|
/* Verbindung das Sendefenster noch nicht gefuellt ist, senden wir */
|
|
/* soviele Frames, wie in das Fenster passen. Auf Vollduplex-Ports */
|
|
/* sendet sdi() grundsaetzlich immer nur EIN Frame, damit zwischen- */
|
|
/* zeitliche Aenderungen am ->VR gleich bestaetigt werden koennen. */
|
|
/* (Dies waere nicht moeglich, wenn die Frames bereits im L1 Sender */
|
|
/* sitzen und auf Sendung warten). */
|
|
/* Wenn l2tx() einen Port als frei erkennt, werden fuer alle Links */
|
|
/* Informationen gesendet. Der Sender ist dann wieder gesperrt, bis */
|
|
/* alles auf dem Port gesendet wurde. */
|
|
/* Die Linkliste (pro Port) haelt die letzten Links (also die Ver- */
|
|
/* bindungen, die zuletzt bedient und bestaetigt wurden) am Ende, */
|
|
/* deshalb wird sie hier von vorn nach hinten gelesen. Damit wird */
|
|
/* eine gleichmaessige Verteilung erreicht, es gibt kein "Festsaugen" */
|
|
/* an einem Link. */
|
|
/* */
|
|
/* Frames aus Gesendet-Liste holen und in die Monitorframeliste um- */
|
|
/* haengen. Entsprechend dem Frameinhalt ggf. Timer 1 starten. */
|
|
/* */
|
|
/*----------------------------------------------------------------------*/
|
|
void
|
|
l2tx(void)
|
|
{
|
|
WORD port; /* Laufindex */
|
|
LHEAD *llp;
|
|
int n;
|
|
|
|
for (llp = &l2actl[port = 0]; /* alle Ports durchgehen */
|
|
port < L2PNUM;
|
|
port++, llp++)
|
|
{
|
|
if (busy(port))
|
|
continue; /* Port ist noch blockiert */
|
|
if (dama(port))
|
|
continue; /* nicht senden auf DAMA-Ports */
|
|
#ifdef DAMASLAVE
|
|
if (damaslaveon(port))
|
|
continue; /* nicht senden auf DAMA-Slave-Ports */
|
|
#endif
|
|
|
|
for (lnkpoi = (LNKBLK *)llp->head;
|
|
lnkpoi != (LNKBLK *)llp; /* alle Links des Ports pruefen */
|
|
lnkpoi = lnkpoi->next)
|
|
{
|
|
if (lnkpoi->RStype != L2CREJ) /* REJ nicht durch I ersetzen */
|
|
{
|
|
if (lnkpoi->flag & L2FREPEAT)
|
|
sdoi();
|
|
else
|
|
if ((n = itxwnd()) > 0) /* darf ich ueberhaupt noch was? */
|
|
sdi(outsdI(), n); /* Frames generieren (mit clrT2) */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* Gesendetliste aufraeumen */
|
|
/* */
|
|
/************************************************************************/
|
|
void
|
|
clrstfl(void)
|
|
{
|
|
MBHEAD *sfbp; /* Sendeframebufferpointer */
|
|
|
|
while ((sfbp = (MBHEAD *)stfl.head) != (MBHEAD *)&stfl)
|
|
{
|
|
ulink((LEHEAD *)sfbp); /* Frame holen */
|
|
if ((sfbp->l2fflg & L2FT1ST) != FALSE) /* ist T1 zu starten ? */
|
|
{
|
|
lnkpoi = sfbp->l2link; /* Zeiger auf Linkblock */
|
|
setT1(); /* T1 starten */
|
|
}
|
|
sfbp->tx = 1;
|
|
if (takfhd(sfbp))
|
|
monitor(sfbp);
|
|
dealmb(sfbp);
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* Frame-Reject Frame aufbauen und senden */
|
|
/* */
|
|
/************************************************************************/
|
|
void
|
|
sdfrmr(char ZYXW)
|
|
{
|
|
UBYTE *frmrip;
|
|
|
|
if (lnkpoi->state >= L2SIXFER && lnkpoi->state != L2SHTH)
|
|
{
|
|
frmrip = lnkpoi->frmr;
|
|
#ifdef EAX25
|
|
/* EAX.25-FRMR aufbauen */
|
|
if (lnkpoi->bitmask == 0x7F)
|
|
{
|
|
*frmrip++ = rxfctl;
|
|
if ((rxfctl & 0x03) == 3)
|
|
*frmrip++ = 0;
|
|
else
|
|
*frmrip++ = rxfctlE;
|
|
|
|
*frmrip++ = (lnkpoi->VS << 1) & 0xFE;
|
|
*frmrip++ = (lnkpoi->VR << 1) | (!rxfCR ? 0x1 : 0x0);
|
|
*frmrip = ZYXW;
|
|
}
|
|
else
|
|
{
|
|
#endif
|
|
/* AX.25-FRMR aufbauen */
|
|
*frmrip++ = rxfctl | rxfPF;
|
|
*frmrip++ = (lnkpoi->VR << 5)
|
|
| (!rxfCR ? 0x10 : 0)
|
|
| (lnkpoi->VS << 1);
|
|
*frmrip = ZYXW;
|
|
#ifdef EAX25
|
|
}
|
|
#endif
|
|
#if MAX_TRACE_LEVEL > 0
|
|
/***DEBUG***/
|
|
notify(1, "Frame rejected %6.6s->%6.6s VS=%u ltxdNR=%u VR=%u"
|
|
" lrxdNR=%u error=%u state=%u",
|
|
lnkpoi->srcid, lnkpoi->dstid,
|
|
lnkpoi->VS, lnkpoi->ltxdNR,
|
|
lnkpoi->VR, lnkpoi->lrxdNR,
|
|
ZYXW, lnkpoi->state);
|
|
/***DEBUG***/
|
|
#endif
|
|
clrT1(); /* Timer stoppen */
|
|
clrT2();
|
|
lnkpoi->RTT = 0;
|
|
l2stma(stbl27); /* INVALID N(R) RECEIVED */
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* "xmit null" */
|
|
/* */
|
|
/* Nichts tun. Leerfunktion fuer die Statetable. */
|
|
/* */
|
|
/************************************************************************/
|
|
void
|
|
xnull(void)
|
|
{
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* "xmit RR command" */
|
|
/* */
|
|
/* RR als Command senden. */
|
|
/* */
|
|
/************************************************************************/
|
|
void
|
|
xrrc(void)
|
|
{
|
|
stxcfr();
|
|
sendS(L2CRR);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* "xmit RR response" */
|
|
/* */
|
|
/* RR als Response senden. */
|
|
/* */
|
|
/************************************************************************/
|
|
void
|
|
xrrr(void)
|
|
{
|
|
sendS(L2CRR);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* "xmit RNR command" */
|
|
/* */
|
|
/* REJ als Command senden. */
|
|
/* */
|
|
/************************************************************************/
|
|
void
|
|
xrnrc(void)
|
|
{
|
|
stxcfr();
|
|
xrnrr();
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* "xmit RNR response" */
|
|
/* */
|
|
/* RNR als Response senden. */
|
|
/* */
|
|
/************************************************************************/
|
|
void
|
|
xrnrr(void)
|
|
{
|
|
sendS(L2CRNR);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* "xmit REJ response" */
|
|
/* */
|
|
/* REJ als Response senden. */
|
|
/* */
|
|
/************************************************************************/
|
|
void
|
|
xrejr(void)
|
|
{
|
|
sendS(L2CREJ);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* "send supervisory frame" */
|
|
/* */
|
|
/* Ein Supervisory-Frame aufbauen, Timer 2 loeschen und das Frame */
|
|
/* an den aktuellen Link senden. */
|
|
/* */
|
|
/************************************************************************/
|
|
void
|
|
sendS(UBYTE control)
|
|
{
|
|
clrT2();
|
|
|
|
#ifdef __WIN32__
|
|
txfctl = (unsigned char)setNR(control);
|
|
#else
|
|
txfctl = setNR(control);
|
|
#endif /* WIN32 */
|
|
#ifdef EAX25
|
|
/* Kontrollbytes fuer EAX.25 aufbauen bzw. umbauen */
|
|
if (lnkpoi->bitmask == 0x7F)
|
|
{
|
|
txfctl &= 0x0F; /* erstes Kontrollbyte aendern */
|
|
txfctlE = (lnkpoi->VR << 1) | (txfPF >> 4); /* V(R) und Pollflag */
|
|
txfEAX = TRUE;
|
|
}
|
|
#endif
|
|
|
|
sdl2fr(makfhd((!txfCR ? L2FUS : L2FUS | L2FT1ST)), FALSE);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* "xmit DM" */
|
|
/* */
|
|
/* Ein DM-Frame generieren und an die aktuelle Adresse (txf...) */
|
|
/* senden. */
|
|
/* */
|
|
/************************************************************************/
|
|
void
|
|
xdm(void)
|
|
{
|
|
txfctl = L2CDM;
|
|
sdl2fr(makfhd(L2FUS), TRUE);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* "xmit UA" */
|
|
/* */
|
|
/* Ein UA-Frame generieren und an die aktuelle Adresse (txf...) */
|
|
/* senden. */
|
|
/* */
|
|
/************************************************************************/
|
|
void
|
|
xua(void)
|
|
{
|
|
txfctl = L2CUA;
|
|
sdl2fr(makfhd(L2FUS), TRUE);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* "xmit SABM" */
|
|
/* */
|
|
/* Ein SABM-Frame generieren und an die Adresse des aktuellen Linkblock */
|
|
/* senden. */
|
|
/* */
|
|
/************************************************************************/
|
|
void
|
|
xsabm(void)
|
|
{
|
|
stxcfr();
|
|
#ifdef EAX25
|
|
/* bei gewuenschter EAX.25-Verbindung je nach Porteinstellung einen */
|
|
/* anderen Kopf aufbauen */
|
|
|
|
/* Modus bestimmen je nach Einstellung des Ports */
|
|
switch (portpar[lnkpoi->liport].eax_behaviour)
|
|
{
|
|
/* EAX.25 auf diesem Port nicht erlaubt */
|
|
case 0: lnkpoi->bitmask = 0x07;
|
|
break;
|
|
|
|
/* EAX.25 auf diesem Port ist zwingend !!! */
|
|
case 3: lnkpoi->bitmask = 0x7F;
|
|
break;
|
|
|
|
/* EAX.25 auf diesem Port nach MHeard-Tabelle */
|
|
default: break;
|
|
}
|
|
|
|
if (lnkpoi->bitmask == 0x7F)
|
|
txfctl = L2CSABME;
|
|
else
|
|
#endif
|
|
txfctl = L2CSABM;
|
|
|
|
#ifdef RTTSTART_MOD
|
|
{
|
|
PEER *pSeg;
|
|
PEER *peertab = netp->peertab; /* Segment-Tabelle */
|
|
|
|
/* Segment-Tabelle durchgehen. */
|
|
for (pSeg = peertab; pSeg < &peertab[netp->max_peers]; pSeg++)
|
|
{
|
|
if (!pSeg->used) /* Unbenutzte Eintraege, */
|
|
continue; /* zum naechsten. */
|
|
|
|
if (cmpid(pSeg->l2link->call, lnkpoi->dstid)) /* Callvergleich. */
|
|
pSeg->rttstart = tic10; /* Zeitmessung starten. */
|
|
}
|
|
}
|
|
#endif /* RTTSTART_MOD */
|
|
|
|
sdl2fr(makfhd((L2FUS | L2FT1ST)), FALSE);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* "xmit DISC" */
|
|
/* */
|
|
/* Ein DISC-Frame generieren und an die Adresse des aktuellen Linkblock */
|
|
/* senden. */
|
|
/* */
|
|
/************************************************************************/
|
|
void
|
|
xdisc(void)
|
|
{
|
|
stxcfr();
|
|
txfctl = L2CDISC;
|
|
sdl2fr(makfhd((L2FUS | L2FT1ST)), FALSE);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* "xmit FRMR" */
|
|
/* */
|
|
/* FRMR-Frame generieren und mit der RIP-Information aus dem Linkblock */
|
|
/* fuellen. */
|
|
/* */
|
|
/************************************************************************/
|
|
void
|
|
xfrmr(void)
|
|
{
|
|
UBYTE *frmrip;
|
|
MBHEAD *fbp;
|
|
|
|
stxfad();
|
|
txfctl = L2CFRMR;
|
|
fbp = makfhd((L2FUS | L2FT1ST));
|
|
frmrip = lnkpoi->frmr;
|
|
#ifdef EAX25
|
|
/* EAX.25 FRMR ist zwei Bytes laenger */
|
|
if (lnkpoi->bitmask == 0x7F)
|
|
{
|
|
putchr(*frmrip++, fbp);
|
|
putchr(*frmrip++, fbp);
|
|
}
|
|
#endif
|
|
putchr(*frmrip++, fbp);
|
|
putchr(*frmrip++, fbp);
|
|
putchr(*frmrip, fbp);
|
|
sdl2fr(fbp, TRUE);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* "set tx command frame" */
|
|
/* */
|
|
/* TX-Frame-Adressierung setzen (siehe stxfad()) und Frame zum */
|
|
/* Kommandoframe machen mit gesetztem Pollbit (txfCR, txfPF). */
|
|
/* */
|
|
/************************************************************************/
|
|
void
|
|
stxcfr(void)
|
|
{
|
|
stxfad(); /* Adressierung */
|
|
txfCR = L2CCR; /* Command! */
|
|
#ifdef DAMASLAVE
|
|
if (damaslaveon(txfprt)) /* Slave darf nicht pollen */
|
|
txfPF = 0;
|
|
else
|
|
#endif
|
|
txfPF = L2CPF; /* Pollbit! */
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* "set tx frame address" */
|
|
/* */
|
|
/* Adressierung des aktuellen Sendeframes (txfhdr, txfprt) setzen aus */
|
|
/* den im aktuellen Linkblock (lnkpoi) gegebenen Parametern (srcid, */
|
|
/* destid, viaidl, liport). */
|
|
/* */
|
|
/************************************************************************/
|
|
void
|
|
stxfad(void)
|
|
{
|
|
cpyid(txfhdr + L2IDLEN, lnkpoi->srcid); /* von ... */
|
|
|
|
/*
|
|
* DAMA-Bit loeschen, wenn DAMA-Betrieb (geloeschtes Bit = DAMA !)
|
|
*/
|
|
if (dama(lnkpoi->liport))
|
|
txfhdr[L2ILEN - 1] &= ~L2CDAMA;
|
|
|
|
#ifdef EAX25
|
|
if (lnkpoi->bitmask == 0x7F)
|
|
txfhdr[L2ILEN - 1] &= ~L2CEAX;
|
|
#endif
|
|
|
|
cpyid(txfhdr, lnkpoi->dstid); /* nach ... */
|
|
cpyidl(txfhdr + L2ILEN, lnkpoi->viaidl); /* ueber ... */
|
|
|
|
txfprt = lnkpoi->liport; /* auf Port ... */
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* "set NR" */
|
|
/* */
|
|
/* Im aktuellen Linkblock (lnkpoi) die zuletzt gesendete N(R) (ltxdNR) */
|
|
/* auf V(R) (VR) setzen und Framecontrolbyte control fuer Frameaus- */
|
|
/* sendung mit der N(R) versehen und zurueckgeben. */
|
|
/* */
|
|
/* Return : control mit N(R) versehen */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
UBYTE
|
|
setNR(UBYTE control)
|
|
{
|
|
lnkpoi->ltxdNR = lnkpoi->VR; /* neue N(R) */
|
|
return (((lnkpoi->VR << 5) | control)); /* N(R) ins Kontrollfeld */
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* "send level 2 frame" */
|
|
/* */
|
|
/* Framebuffer, auf dessen Kopf fbp zeigt, rewinden und in die dem Port */
|
|
/* (l2port) entsprechende Level-2-Sendeframeliste einhaengen, wenn noch */
|
|
/* genug Buffer im System frei sind. Andernfalls nicht senden, sondern */
|
|
/* sofort in die Gesendet-Liste (stfl) einhaengen. */
|
|
/* */
|
|
/************************************************************************/
|
|
void
|
|
sdl2fr(MBHEAD *fbp, BOOLEAN send_immediately)
|
|
{
|
|
UBYTE port; /* Portnummer */
|
|
|
|
#ifndef __WIN32__
|
|
port = fbp->l2port; /* Portnummer holen */
|
|
#else
|
|
port = (unsigned char)fbp->l2port; /* Portnummer holen */
|
|
#endif /* WIN32 */
|
|
|
|
if (nmbfre > 14 && portenabled(port)) /* noch genug Buffer und Port */
|
|
{ /* eingeschaltet? */
|
|
rwndmb(fbp); /* ja - Framebuffer rewinden */
|
|
/* Frame in Sendeliste */
|
|
#ifdef L1TCPIP
|
|
/* TCPIP-Frames haben hier nix zu suchen. */
|
|
if (CheckPortTCP((UWORD)port))
|
|
{
|
|
/* Frame entsorgen. */
|
|
dealmb(fbp);
|
|
return;
|
|
}
|
|
#endif /* L1TCPIP */
|
|
|
|
if ( dama(port) /* DAMA-Frames werden in timDAMA gesendet */
|
|
#ifdef DAMASLAVE
|
|
|| damaslaveon(port) /* DAMA-Slave-Frames auch */
|
|
#endif
|
|
)
|
|
{
|
|
if (send_immediately == FALSE)
|
|
relink((LEHEAD *)fbp, (LEHEAD *)(lnkpoi->damail.tail));
|
|
else
|
|
relink((LEHEAD *)fbp, (LEHEAD *)&damarl[port]);
|
|
return;
|
|
}
|
|
relink((LEHEAD *)fbp, (LEHEAD *)txl2fl[port].tail);
|
|
kicktx(port); /* es ist was zu senden ! */
|
|
}
|
|
else /* kein Platz oder Port aus - Frame als gesendet betrachten */
|
|
{
|
|
relink((LEHEAD *)fbp, (LEHEAD *)stfl.tail);
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* "make frame header" */
|
|
/* */
|
|
/* Die Header-Daten aus "txf.." werden in einen Buffer geschrieben. */
|
|
/* Sie wurden entweder von getfhd() aus dem Empfangsframe durch */
|
|
/* Spiegelung generiert oder aus dem Linkblock gesetzt. */
|
|
/* */
|
|
/************************************************************************/
|
|
MBHEAD *
|
|
makfhd(int fflag)
|
|
{
|
|
MBHEAD *fbp;
|
|
|
|
txfhdr[L2IDLEN - 1] |= txfCR;
|
|
txfhdr[L2ILEN - 1] |= txfCR ^ L2CCR;
|
|
|
|
putfid(txfhdr, fbp = (MBHEAD *)allocb(ALLOC_MBHEAD));
|
|
|
|
if (dama(txfprt))
|
|
txfhdr[L2ILEN - 1] &= ~L2CDAMA;
|
|
|
|
#ifdef EAX25
|
|
if ((txfEAX == TRUE) && ((txfctl & 0x03) != 0x03))
|
|
txfhdr[L2ILEN - 1] &= ~L2CEAX;
|
|
else
|
|
txfhdr[L2ILEN - 1] |= L2CEAX;
|
|
#endif
|
|
|
|
putfid(txfhdr + L2IDLEN, fbp);
|
|
putvia(txfhdr + L2ILEN, fbp);
|
|
|
|
#ifdef EAX25
|
|
if ((txfEAX == TRUE) && ((txfctl & 0x03) != 0x03))
|
|
{
|
|
putchr((UBYTE)(txfctl), fbp);
|
|
putchr((UBYTE)(txfctlE | (txfPF >> 4)), fbp);
|
|
txfEAX = FALSE;
|
|
}
|
|
else
|
|
#endif
|
|
putchr((UBYTE)(txfctl | txfPF), fbp);
|
|
|
|
fbp->l2link = lnkpoi;
|
|
fbp->type = 2;
|
|
fbp->l2fflg = fflag;
|
|
fbp->l2port = txfprt;
|
|
fbp->repeated = 0;
|
|
return (fbp);
|
|
}
|
|
|
|
/************************************************************************\
|
|
* *
|
|
* "information to link" *
|
|
* *
|
|
* Infobuffer, auf den imbp zeigt, an in diesem Buffer festgelegten Link *
|
|
* (l2link) zwecks Aussendung als Paket weitergeben. Wenn nocgnc == TRUE *
|
|
* keine "Erstickungskontrolle", sonst conctl beachten (s.u.). *
|
|
* Der Infobuffer wird bei Weitergabe an den Link mit der normalen *
|
|
* Level 2 PID versehen, der Keine-Aktivitaets-Timer wird neu gestartet. *
|
|
* *
|
|
* Return: TRUE - imbp wurde angenommen und an den Link weitergegeben *
|
|
* FALSE - imbp wurde nicht angenommen wegen Congestion Control *
|
|
* = Grenze der pro Link maximal zu speichernden Pakete *
|
|
* (conctl) wuerde ueberschritten werden *
|
|
* *
|
|
\************************************************************************/
|
|
BOOLEAN
|
|
itolnk(int pid, BOOLEAN nocgnc, MBHEAD *imbp)
|
|
{
|
|
LNKBLK *linkp;
|
|
#if 0
|
|
extern void coredump(void);
|
|
#endif
|
|
|
|
linkp = imbp->l2link;
|
|
|
|
/* DEBUG */
|
|
if (linkp->state == L2SDSCED)
|
|
{
|
|
LNKBLK *l_bak;
|
|
|
|
l_bak = lnkpoi; /* damit wir das im Dump sehen */
|
|
lnkpoi = linkp;
|
|
#if MAX_TRACE_LEVEL > 2
|
|
notify(1, "send to disc'ed link %6.6s > %6.6s via %s",
|
|
linkp->srcid, linkp->dstid, linkp->viaidl);
|
|
#endif
|
|
#if 0
|
|
coredump();
|
|
#endif
|
|
dealmb((MBHEAD *)ulink((LEHEAD *)imbp));
|
|
lnkpoi = l_bak;
|
|
return (TRUE);
|
|
}
|
|
|
|
if (linkp->state == L2SDSCRQ)
|
|
{
|
|
dealmb((MBHEAD *)ulink((LEHEAD *)imbp));
|
|
return (TRUE);
|
|
}
|
|
|
|
if (linkp->tosend < conctl || nocgnc == TRUE)
|
|
{
|
|
imbp->l2fflg = pid; /* PID uebernehmen */
|
|
imbp->repeated = 0;
|
|
relink(ulink((LEHEAD *)imbp), /* -> ab in den Link */
|
|
(LEHEAD *)linkp->sendil.tail);
|
|
++linkp->tosend; /* ein Sendepaket mehr */
|
|
|
|
#ifndef THENETMOD
|
|
linkp->noatou = ininat;
|
|
#else /* L4TIMEOUT */
|
|
linkp->noatou = SetL4Timeout(); /* L2/L4-Timeout setzen.*/
|
|
#endif /* THENETMOD */
|
|
return (TRUE); /* ... imbp angenommen */
|
|
}
|
|
return (FALSE); /* ... imbp abgelehnt */
|
|
}
|
|
|
|
/************************************************************************\
|
|
* *
|
|
* "number of outstanding I's" *
|
|
* *
|
|
* Anzahl der ausstehenden Info-Frames des aktuellen Linkblock (lnkpoi) *
|
|
* berechnen. *
|
|
* *
|
|
\************************************************************************/
|
|
char
|
|
outsdI(void)
|
|
{
|
|
return ((lnkpoi->VS - lnkpoi->lrxdNR) & lnkpoi->bitmask);
|
|
}
|
|
|
|
/************************************************************************\
|
|
* *
|
|
* "is tx window open" *
|
|
* *
|
|
* Kann der Sender des aktuellen Linkblocks noch Informationen aufnehmen? *
|
|
* Geliefert wird die Anzahl der Frames, die noch in das aktuelle Fenster *
|
|
* passen. *
|
|
* *
|
|
\************************************************************************/
|
|
char
|
|
itxwnd(void)
|
|
{
|
|
int outstd,
|
|
n,
|
|
k;
|
|
|
|
if (lnkpoi->tosend) /* ueberhaupt was zu senden? */
|
|
{
|
|
switch (lnkpoi->state) /* duerfen wir was senden? */
|
|
{
|
|
case L2SIXFER:
|
|
case L2SRS:
|
|
case L2SDBS:
|
|
case L2SRSDBS:
|
|
outstd = outsdI(); /* soviel stehen noch aus */
|
|
n = lnkpoi->tosend; /* und soviel ist noch uebrig */
|
|
k = lnkpoi->maxframe;
|
|
if ( (outstd < k) /* Fenster noch nicht voll */
|
|
&& (n > outstd)) /* und Sendebuffer nicht leer */
|
|
return (fullduplex(lnkpoi->liport) ? 1 : k);
|
|
}
|
|
}
|
|
return (0); /* senden momentan nicht erlaubt */
|
|
}
|
|
|
|
/************************************************************************\
|
|
* *
|
|
* "send outstanding I's" *
|
|
* *
|
|
* Aus dem aktuellen Linkblock (lnkpoi) soviele I-Frames senden, wie im *
|
|
* Moment unbestaetigt ausstehen. *
|
|
* Es wird der komplette Durchgang wiederholt (ab dem 1. unbestaetigtem) *
|
|
* Frame. *
|
|
* WICHTIG: Nicht senden, wenn wir auf die Antwort der Gegenstation *
|
|
* warten (wir haben Poll gesendet). Dann kommt sowieso der *
|
|
* Final demnaechst und wir koennen weitersenden. *
|
|
* *
|
|
\************************************************************************/
|
|
void
|
|
sdoi(void)
|
|
{
|
|
UWORD n; /* Anzahl I's zu senden */
|
|
int VS;
|
|
|
|
switch (lnkpoi->state) /* nur wenn der State stimmt */
|
|
{
|
|
case L2SIXFER:
|
|
case L2SRS:
|
|
case L2SDBS:
|
|
case L2SRSDBS:
|
|
if ((n = outsdI()) != 0) /* wieviel darf ich? */
|
|
{
|
|
VS = lnkpoi->VS;
|
|
lnkpoi->VS = lnkpoi->lrxdNR; /* V(S) resetten */
|
|
sdi(0, n); /* I's senden */
|
|
lnkpoi->VS = VS;
|
|
}
|
|
lnkpoi->flag &= ~L2FREPEAT;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/************************************************************************\
|
|
* *
|
|
* "send I" *
|
|
* *
|
|
* Aus dem aktuellen Linkblock (lnkpoi) maximal max I-Frames aus der *
|
|
* Infomessageliste aufbauen und senden. Die Frames werden als Command- *
|
|
* frames ohne Poll/Final-Bit gesendet. V(S) wird fuer jedes gesendete *
|
|
* Frame erhoeht modulo 7. Timer 2 wird abgeschaltet. *
|
|
* *
|
|
\************************************************************************/
|
|
void
|
|
sdi(int outstd, int max)
|
|
{
|
|
WORD n,
|
|
m,
|
|
k; /* Zaehler zu sendende Infos */
|
|
MBHEAD *sendip; /* Kopfzeiger Infobuffer */
|
|
MBHEAD *fbp; /* Kopfzeiger Framebuffer */
|
|
|
|
sendip = (MBHEAD *)lnkpoi->sendil.head; /* erstes Frame */
|
|
for (n = 0; n < outstd; n++)
|
|
sendip = (MBHEAD *)sendip->nextmh; /* soviele uebergehen */
|
|
|
|
if (max > lnkpoi->tosend - outstd) /* maximal soviel wie da ist */
|
|
max = lnkpoi->tosend - outstd;
|
|
|
|
k = lnkpoi->maxframe;
|
|
|
|
if (max + outstd > k) /* und nicht uebers Fenster */
|
|
max = outstd < k
|
|
? k - outstd /* Rest bis zum Fensterende */
|
|
: 0; /* Fenster wurde verkleinert */
|
|
|
|
for (n = 1;
|
|
n <= max; /* aus der Linkblock- */
|
|
++n, sendip = (MBHEAD *)sendip->nextmh) /* infoliste senden */
|
|
{ /* wenn vorhanden */
|
|
stxfad(); /* Frameadresse aufbauen */
|
|
txfCR = L2CCR; /* Command! */
|
|
|
|
#ifdef EAX25
|
|
/* EAX.25-Kontrollbytes setzen */
|
|
if (lnkpoi->bitmask == 0x7F)
|
|
{
|
|
txfctl = (lnkpoi->VS << 1) & 0xFE; /* Controlbyte 1 setzen */
|
|
txfctlE = (lnkpoi->VR << 1) & 0xFE; /* Controlbyte 2 setzen */
|
|
lnkpoi->ltxdNR = lnkpoi->VR; /* neue N(R) */
|
|
txfEAX = TRUE;
|
|
}
|
|
else
|
|
{
|
|
#endif
|
|
/* AX.25-Kontrollbyte setzen */
|
|
#ifdef __WIN32__
|
|
txfctl = (unsigned char)setNR((char)(lnkpoi->VS << 1)); /* Controlbyte I setzen */
|
|
#else
|
|
txfctl = setNR((char)(lnkpoi->VS << 1)); /* Controlbyte I setzen */
|
|
#endif /* WIN32 */
|
|
#ifdef EAX25
|
|
}
|
|
#endif
|
|
++lnkpoi->VS; /* V(S) erhoehen */
|
|
lnkpoi->VS &= lnkpoi->bitmask; /* modulo */
|
|
|
|
txfPF = 0; /* normalerweise ohne POLL */
|
|
if ( (((lnkpoi->lrxdNR + k) & lnkpoi->bitmask) == lnkpoi->VS)
|
|
|| (lnkpoi->tosend == outsdI()))
|
|
{
|
|
if (dama(lnkpoi->liport))
|
|
txfPF = L2CPF; /* letztes Frame mit POLL! */
|
|
fbp = makfhd(L2FT1ST); /* Ja, T1 und RTT Zeitmessung */
|
|
}
|
|
else
|
|
fbp = makfhd(0x00); /* Nein, T1/RTT nicht starten */
|
|
|
|
fbp->repeated = sendip->repeated;
|
|
putchr(sendip->l2fflg, fbp); /* Frame aufbauen, PID */
|
|
|
|
/*
|
|
* Frame aufspalten, wenn zu lang. Gesplittet werden aber nur
|
|
* Frames mit Standard-AX.25-PID (ohne L3-Protokoll). Die maximale
|
|
* Laenge ist 256 Bytes bzw. wenn niedriger der MTU-Wert fuer den
|
|
* jeweiligen Port.
|
|
*/
|
|
if (sendip->l2fflg == L2CPID)
|
|
#ifdef PORT_MANUELL
|
|
m = portpar[lnkpoi->liport].paclen;
|
|
#else
|
|
m = L2MILEN; /* Fest auf 256 Bytes begrenzen */
|
|
#endif /* PORT_MANUELL */
|
|
else
|
|
m = min(L2MILEN, portpar[lnkpoi->liport].mtu);
|
|
|
|
if (splcpy(m, fbp, sendip) == TRUE) /* Ein Frame mehr zu senden */
|
|
++lnkpoi->tosend;
|
|
|
|
#ifdef MAXFRAMEDEBUG
|
|
fbp->lnkflag = lnkpoi->flag;
|
|
fbp->lmf = lnkpoi->maxframe;
|
|
#ifdef EAX25
|
|
if (lnkpoi->bitmask == 0x7F)
|
|
#ifdef __WIN32__
|
|
fbp->pmf = (unsigned char)portpar[lnkpoi->liport].maxframe_eax;
|
|
#else
|
|
fbp->pmf = portpar[lnkpoi->liport].maxframe_eax;
|
|
#endif /* WIN32 */
|
|
else
|
|
#endif
|
|
#ifdef __WIN32__
|
|
fbp->pmf = (unsigned char)portpar[lnkpoi->liport].maxframe;
|
|
#else
|
|
fbp->pmf = portpar[lnkpoi->liport].maxframe;
|
|
#endif /* WIN32 */
|
|
fbp->tosend = lnkpoi->tosend;
|
|
#endif
|
|
|
|
sdl2fr(fbp, FALSE); /* Frame senden */
|
|
++sendip->repeated; /* Frame wird ggf. wiederholt gesendet */
|
|
clrT2(); /* Timer 2 abschalten */
|
|
}
|
|
}
|
|
|
|
/************************************************************************\
|
|
* *
|
|
* "send UI" *
|
|
* *
|
|
* UI-Frame aufbauen und senden. Das UI-Frame wird an ID dest geschickt *
|
|
* ueber den Port port und die via-Liste (nullterminiert) vial, als *
|
|
* Quelle wird source genommen, die Infobytes des Frames stehen im *
|
|
* Messagebuffer, auf dessen Kopf mbhd zeigt, die PID wird aus l2fflg *
|
|
* dieses Buffers genommen. *
|
|
* *
|
|
\************************************************************************/
|
|
void
|
|
sdui(const char *vial, const char *dest, const char *source, char port,
|
|
MBHEAD *mbhd)
|
|
{
|
|
MBHEAD *fbp;
|
|
|
|
#ifdef L1TCPIP
|
|
/* TCPIP-Frames haben hier nix zu suchen. */
|
|
if (CheckPortTCP((UWORD)port))
|
|
return;
|
|
#endif /* L1TCPIP */
|
|
|
|
cpyid(txfhdr + L2IDLEN, source);
|
|
cpyid(txfhdr, dest);
|
|
cpyidl(txfhdr + L2ILEN, vial);
|
|
txfprt = port;
|
|
txfCR = L2CCR;
|
|
#ifndef UIPOLLFIX
|
|
txfPF = 0;
|
|
#else
|
|
txfPF = L2CPF;
|
|
#endif /* UIPOLLFIX */
|
|
txfctl = L2CUI;
|
|
putchr(mbhd->l2fflg, fbp = makfhd(0));
|
|
|
|
while (mbhd->mbgc < mbhd->mbpc)
|
|
putchr(getchr(mbhd), fbp);
|
|
|
|
sdl2fr(fbp, TRUE);
|
|
}
|
|
|
|
#ifdef IPOLL_FRAME
|
|
void sdipoll()
|
|
{
|
|
static MBHEAD *sendip; /* Kopfzeiger Infobuffer */
|
|
static MBHEAD *fbp; /* Kopfzeiger Framebuffer */
|
|
|
|
sendip = (MBHEAD *)lnkpoi->sendil.head;
|
|
stxfad(); /* Frameadresse aufbauen */
|
|
if ( sendip->mbpc < portpar[lnkpoi->liport].ipoll_paclen /* FEF wird's ein IPoll ? */
|
|
&& lnkpoi->tries < portpar[lnkpoi->liport].ipoll_retry
|
|
&& lnkpoi->tosend)
|
|
{
|
|
txfCR = L2CCR; /* Command ! */
|
|
txfPF = L2CPF; /* Poll/Final ! */
|
|
#ifdef __WIN32__
|
|
txfctl = setNR((UBYTE)(lnkpoi->lrxdNR << 1)); /* Controlbyte I wie zuvor */
|
|
#else
|
|
txfctl = setNR(lnkpoi->lrxdNR << 1); /* Controlbyte I wie zuvor */
|
|
#endif /* WIN32 */
|
|
putchr(sendip->l2fflg, /* Frame aufbauen, PID */
|
|
fbp = makfhd(L2FT1ST));
|
|
splcpy(256,fbp,sendip); /* Message umkopieren */
|
|
sdl2fr(fbp, FALSE); /* Frame senden */
|
|
clrT2(); /* Timer 2 abschalten */
|
|
clrT3(); /* Timer 3 abschalten */
|
|
}
|
|
else /* FEF Nein, kein Ipoll... */
|
|
xrrc(); /* FEF ... RR+ senden */
|
|
}
|
|
#endif /* IPOLL_FRAME */
|
|
|
|
/* End of src/l2tx.c */
|