kopia lustrzana https://github.com/sp9skp/spdxl
2817 wiersze
89 KiB
C
2817 wiersze
89 KiB
C
/*
|
|
* dxlAPRS toolchain
|
|
*
|
|
* Copyright (C) Christian Rabler <oe5dxl@oevsv.at>
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
*/
|
|
/* "@(#)l2.c May 11 0:15:23 2017" */
|
|
|
|
|
|
#define X2C_int32
|
|
#define X2C_index32
|
|
#ifndef l2_H_
|
|
#include "l2.h"
|
|
#endif
|
|
#define l2_C_
|
|
#ifndef frameio_H_
|
|
#include "frameio.h"
|
|
#endif
|
|
#ifndef osi_H_
|
|
#include "osi.h"
|
|
#endif
|
|
#include <osic.h>
|
|
|
|
uint16_t l2_UA = 0x63U;
|
|
uint16_t l2_DM = 0xFU;
|
|
uint16_t l2_SABM = 0x2FU;
|
|
uint16_t l2_DISC = 0x43U;
|
|
uint16_t l2_FRMR = 0x87U;
|
|
uint16_t l2_UI = 0x3U;
|
|
uint16_t l2_RR = 0x1U;
|
|
uint16_t l2_REJ = 0x9U;
|
|
uint16_t l2_RNR = 0x5U;
|
|
|
|
|
|
char l2_L2Lock;
|
|
uint16_t l2_LostINT;
|
|
l2_pDATA l2_dbuf;
|
|
l2_AFIELD l2_adress;
|
|
uint16_t l2_asize;
|
|
char l2_udp2buf[100];
|
|
|
|
|
|
struct l2__D0 l2_PortSt[16];
|
|
|
|
|
|
|
|
|
|
struct l2__D2 l2_Parms[15];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
Interface Layer2 <-> Host:
|
|
|
|
Call L2Init;
|
|
Call (about) every 10ms Layer2
|
|
|
|
Call any Time
|
|
* not during Layer2 running and its Callback
|
|
|
|
Connect * (start a connect)
|
|
|
|
Disconnect * (stop a connect or close a handle with data)
|
|
|
|
Circuit (join 2 connections back to back)
|
|
if reconn on, the host must not forget this host handle
|
|
and continue interaction after reconnect
|
|
|
|
GetAdress (get address)
|
|
|
|
Getudp2info (get axudp extention info from modem)
|
|
|
|
GetChar (get 1 received char of a connection, delete it or keep it)
|
|
|
|
GetStr (get more received chars of a connection)
|
|
|
|
SendStr (send data to a connection)
|
|
|
|
SendRaw (send UI or raw frame)
|
|
|
|
GetStat (get status of a connection)
|
|
|
|
PortStat (portwise statistics)
|
|
|
|
Parm (get or set port parameters)
|
|
|
|
GetMon (get monitor data)
|
|
|
|
|
|
Callback:
|
|
contains A handle from layer2, is pointer to a (hidden) link structure.
|
|
The host has to use this pointer in any call according to this link.
|
|
|
|
An event number
|
|
|
|
A handle given from host to layer2, a pointer, layer2 looks only
|
|
if NULL for "the host does not want this event and its link any longer"
|
|
.
|
|
|
|
Events:
|
|
eCONNECTED: a connection (in or out) is esteblished
|
|
if (from out) and the host is able to accept set the host-handle
|
|
to not NULL. The handle will always be included in further
|
|
callbacks for this link and the host MUST call Disconnect with
|
|
dealloc TRUE to free this handle.
|
|
|
|
eDISCONNECTED: a link ends, if there is a host-handle the host must
|
|
call Disconnect with dealloc TRUE to free this handle.
|
|
|
|
eBUSY: outgoing connection got busy (DM)
|
|
if there is a host-handle the host must call disconnect to free this handle.
|
|
|
|
eTXFREE: a connection is able to accept new data
|
|
|
|
eRXDATA: a connection received new data
|
|
|
|
eMONITOR: monitor frames are in buffer
|
|
|
|
eCONNREQ: a SABM (via digicall first in mycall table) arrived,
|
|
this is only
|
|
a message with no action of layer2, no host-handle and
|
|
so no disconnect for freeing.
|
|
the host has to find route,
|
|
make a connect and if connect is esteblished
|
|
make a "back connection"
|
|
with Connect connect.typ cFLEXback or cCONNAK.
|
|
If the destination connection is in same layer2,
|
|
join the 2 connections
|
|
with call to Circuit with both reconn off.
|
|
if destination is away,
|
|
host has to get data with GetStr and transport it
|
|
any way and reverse send with SendStr
|
|
|
|
eFLEXDATA: a Frame via digicall (first in mycall table)
|
|
arrived. this is only
|
|
a message with no action of layer2, no host-handle and
|
|
so no disconnect for freeing.
|
|
retrive data immediately during callback vom adress/asize/dbuf
|
|
route and resent with SendUI.
|
|
|
|
eLISTEN: not used by Layer2
|
|
|
|
eIDLE: not used by Layer2
|
|
|
|
*/
|
|
/* (C)OE5DXL 1993-2015, GPL3 */
|
|
static uint16_t l2_SSIDMASK = 0x5EU;
|
|
|
|
static uint16_t l2_DAMARR = 0x20U;
|
|
|
|
#define l2_RESP 0
|
|
|
|
#define l2_FINAL 1
|
|
|
|
#define l2_COMMAND 2
|
|
|
|
#define l2_POLL 3
|
|
|
|
static uint16_t l2_NULL = 0x8000U;
|
|
|
|
static uint16_t l2_DAMAIDLE = 0x4000U;
|
|
|
|
#define l2_SENDQUES 3
|
|
|
|
#define l2_HASHSIZE 16
|
|
/*greater than number of ports*/
|
|
|
|
#define l2_MEMRR 20
|
|
|
|
#define l2_MEMTX 20
|
|
|
|
#define l2_MEMRX 10
|
|
|
|
#define l2_MEMSAMM 20
|
|
|
|
#define l2_MEMFRMR 1
|
|
|
|
#define l2_MEMLINK 5
|
|
|
|
#define l2_TILT 4
|
|
|
|
#define l2_IGNORE 8
|
|
|
|
#define l2_SHORTINFO 80
|
|
|
|
#define l2_IPRETRIES 10
|
|
|
|
#define l2_MAGIC 2091827346
|
|
|
|
#define l2_LOOPSPERS 100
|
|
|
|
#define l2_SECMOD 20000
|
|
/* timer base cycle range, max timer1 is half */
|
|
|
|
#define l2_TIMERBASE 10
|
|
/* timer base / layer2 looptime */
|
|
|
|
#define l2_T3OFF 65535
|
|
|
|
enum TXSTATE {l2_TWAIT, l2_TXDEL, l2_TXTAIL, l2_DCDWAIT, l2_ECHO};
|
|
|
|
|
|
typedef char * AFIELDPO;
|
|
|
|
struct LINK;
|
|
|
|
|
|
struct LINK {
|
|
uint32_t Magic; /*magic number*/
|
|
uint16_t State; /*0 = host is owner of the record*/
|
|
uint16_t mycall; /*0=via, MAX(CARD16)=downlink*/
|
|
uint16_t Baud; /*downlink baud*/
|
|
uint16_t Uplinkport;
|
|
uint8_t cCONNtyp; /*normal or link is for UI transfer only*/
|
|
uint16_t IsInQue; /*link is in this send-que*/
|
|
l2_pLINK SendQuenext; /*sendque-chain*/
|
|
l2_pLINK SendQueprev;
|
|
uint16_t Hash;
|
|
l2_pLINK Hashnext; /*address-hash-chain*/
|
|
l2_pLINK Hashprev;
|
|
uint16_t Qtime; /*time since forced disc*/
|
|
uint16_t T3out; /*Second for next T3 end or T3OFF for T1 running */
|
|
uint16_t damasecond; /*last slice in absolut time*/
|
|
uint16_t T1out; /*second when T1 will run out*/
|
|
l2_pLINK Timernext; /*timer-chain*/
|
|
l2_pLINK Timerprev;
|
|
char highspeed; /*for prefered queing*/
|
|
char damastop; /*no frames until dama-slot*/
|
|
char twoway; /*the other is in INFO state too*/
|
|
char discing; /*disc after send-info-buffer is empty*/
|
|
char rejgot; /*got a REJ*/
|
|
char rejsent; /*sent a REJ*/
|
|
char infostop; /*send-info-buffer was empty*/
|
|
char busyend; /*tell the other that i am not longer busy*/
|
|
char flexback; /* flex backlink say no DM if SABM */
|
|
char haschains; /* link has chains else simple dealloc */
|
|
char rembusy; /*the other is busy*/
|
|
uint16_t busy; /*0=not busy*/
|
|
uint16_t retry; /*increments after timeout-polls*/
|
|
uint16_t ns; /*send-sequence-number*/
|
|
uint16_t lowsent; /*till here info is acknowled*/
|
|
uint16_t highsent; /*till here -1 info is sent*/
|
|
uint16_t sentnr; /*last physically sent nr*/
|
|
uint16_t nr; /*receive sequence number*/
|
|
char pid; /*PID for this link*/
|
|
l2_pDATA sammler[8];
|
|
uint16_t summs[8];
|
|
l2_AFIELD Adress; /*adress field + command byte*/
|
|
uint16_t AdrLen; /*length of adress + command byte*/
|
|
uint16_t cp; /*send response, final, command or poll*/
|
|
uint16_t sendcmd;
|
|
l2_pDATA sendinfo; /*parallel to ns running info-pointer*/
|
|
l2_pDATA txInfoIn; /*entry pointer to transmit buffer*/
|
|
l2_pDATA txInfoOut; /*end of transmit data*/
|
|
uint16_t txbuffers; /*used send-buffers*/
|
|
char txfull; /*tx buffer full, for message or clearbusy*/
|
|
char modifylast; /*last buffer not sent, so modifyable*/
|
|
l2_pLINK nudel; /*the downlink, else NIL*/
|
|
uint16_t exitch; /*switch linked links back to host*/
|
|
char * host; /*to there the messages are sent*/
|
|
char saiddisc; /*send only 1 disc message to host*/
|
|
l2_pDATA rxInfoIn; /*entry pointer to receive buffer*/
|
|
l2_pDATA rxInfoOut; /*end of receive data*/
|
|
uint16_t rxbuffers; /*used buffers*/
|
|
uint16_t readp; /*getchar readpointer*/
|
|
l2_pDATA SABMinfo; /*extention, SABM with info*/
|
|
/*statistics*/
|
|
uint32_t SentBytes;
|
|
uint32_t AckBytes;
|
|
uint32_t RcvdBytes;
|
|
uint32_t Started; /*for statistics: starttime of link*/
|
|
char udp2info[31]; /* axudp2 frame infos from modem */
|
|
};
|
|
|
|
struct _0;
|
|
|
|
struct _1;
|
|
|
|
|
|
struct _1 {
|
|
/*que 0 has highest priority*/
|
|
l2_pLINK SendQueIn; /*chain of links that will send*/
|
|
l2_pLINK SendQueOut;
|
|
};
|
|
|
|
|
|
struct _0 {
|
|
uint8_t sendstate;
|
|
char damat1;
|
|
char dama; /*dama slave*/
|
|
char dcd; /*all diversity ports set it*/
|
|
uint16_t dcdguard; /*ignore dcd if it lasts too long*/
|
|
uint16_t txwait; /*set while sending, reset when receiving*/
|
|
uint16_t Ticker; /* change synchron to main clock */
|
|
uint16_t QTicker; /* change only while not send or dcd */
|
|
char lookinque; /*to decide quick if sendques are empty*/
|
|
l2_pLINK damaloop;
|
|
l2_pLINK T1In; /*timer-chain, each link has always a timer*/
|
|
l2_pLINK T1Out;
|
|
struct _1 SendQues[3];
|
|
};
|
|
|
|
static struct _0 PortL2[15];
|
|
|
|
static l2_pLINK AdrHash[16]; /*hashtable for calls*/
|
|
|
|
static l2_CALLTYP MyCalls[17]; /*mycall[0] is digipeat*/
|
|
|
|
static uint16_t maxrxbuffers;
|
|
|
|
static uint16_t maxtxbuffers;
|
|
|
|
static uint16_t DMTIME; /*save downlinks for sending DM*/
|
|
|
|
static uint16_t QTIME;
|
|
|
|
/*time for discing links with unackn. data*/
|
|
static uint16_t memory; /*used memory*/
|
|
|
|
static uint16_t DAMAMAXTIME; /*longest time till next slot*/
|
|
|
|
static uint16_t DAMAFASTPOLLS;
|
|
|
|
/*slots which have fast intervall*/
|
|
static uint32_t Time; /* seconds counting */
|
|
|
|
static uint32_t AbsTime;
|
|
|
|
static uint16_t Second;
|
|
|
|
static uint16_t monbufs;
|
|
|
|
static uint16_t maxmonbufs;
|
|
|
|
static uint16_t Minute5;
|
|
|
|
static uint16_t ticker5;
|
|
|
|
static char * * Freechain;
|
|
|
|
static l2_CALLTYP DNot[9];
|
|
|
|
static l2_CALLTYP mfrom;
|
|
|
|
static l2_pLINK monBufOut;
|
|
|
|
static l2_pLINK monBufIn;
|
|
|
|
static uint16_t hosts;
|
|
|
|
static uint32_t tick10;
|
|
|
|
static l2_CALLBACKPROC Event;
|
|
|
|
|
|
static uint16_t Min(uint16_t a, uint16_t b)
|
|
{
|
|
if (a>=b) return b;
|
|
else return a;
|
|
return 0;
|
|
} /* end Min() */
|
|
|
|
|
|
static char Alloc(char * * p, uint16_t reserv)
|
|
{
|
|
if (memory<=reserv || Freechain==0) return 0;
|
|
*p = (char *)Freechain;
|
|
Freechain = (char * *)(*Freechain);
|
|
--memory;
|
|
return 1;
|
|
} /* end Alloc() */
|
|
|
|
|
|
static void Dealloc(char * * p)
|
|
{
|
|
char * * unnedig;
|
|
/*WrInt(memory, 6); WrStrLn(" before dealloc "); */
|
|
if (*p==0) return;
|
|
unnedig = (char * *)*p;
|
|
*unnedig = (char *)Freechain;
|
|
Freechain = (char * *)*p;
|
|
++memory;
|
|
*p = 0;
|
|
} /* end Dealloc() */
|
|
|
|
|
|
static void Unlock(void)
|
|
{
|
|
if (l2_LostINT>0U) {
|
|
l2_L2Lock = 1;
|
|
l2_Layer2();
|
|
}
|
|
l2_L2Lock = 0;
|
|
} /* end Unlock() */
|
|
|
|
|
|
static uint16_t Minut5(void)
|
|
{
|
|
return (uint16_t)((Time/300UL)%13UL);
|
|
} /* end Minut5() */
|
|
|
|
|
|
static void CheckParms(uint16_t port)
|
|
{
|
|
struct l2__D2 * anonym;
|
|
{ /* with */
|
|
struct l2__D2 * anonym = &l2_Parms[port-1U];
|
|
if (anonym->_._0.MaxFrames>7U) anonym->_._0.MaxFrames = 7U;
|
|
if (anonym->_._0.SendPort>15U) anonym->_._0.SendPort = port;
|
|
if (anonym->_._0.Diversity>15U) anonym->_._0.Diversity = 0U;
|
|
if (anonym->_._0.BaudSwBytes>100U) anonym->_._0.BaudSwBytes = 100U;
|
|
if (anonym->_._0.T1==0U) anonym->_._0.T1 = 1U;
|
|
else if (anonym->_._0.T1>=10000U) anonym->_._0.T1 = 10000U;
|
|
}
|
|
} /* end CheckParms() */
|
|
|
|
|
|
static void call(l2_pPARMS p, l2_CALLTYP list[], uint32_t list_len)
|
|
{
|
|
uint16_t k;
|
|
uint16_t j;
|
|
uint16_t i;
|
|
uint16_t tmp;
|
|
k = 0U;
|
|
tmp = (uint16_t)((list_len-1)-1UL);
|
|
i = 0U;
|
|
if (i<=tmp) for (;; i++) {
|
|
for (j = 0U; j<=6U; j++) {
|
|
if (p->test) {
|
|
p->str[k] = (char)((uint32_t)(uint8_t)list[i][j]/2UL);
|
|
}
|
|
else list[i][j] = (char)((uint32_t)(uint8_t)p->str[k]*2UL);
|
|
++k;
|
|
} /* end for */
|
|
if (i==tmp) break;
|
|
} /* end for */
|
|
if (p->test) p->str[k] = 0;
|
|
} /* end call() */
|
|
|
|
|
|
static void value(l2_pPARMS p, uint16_t * x)
|
|
{
|
|
if (p->test) p->val = (uint32_t)*x;
|
|
else *x = (uint16_t)p->val;
|
|
} /* end value() */
|
|
|
|
|
|
static void bool(l2_pPARMS p, char * b)
|
|
{
|
|
if (p->test) p->val = (uint32_t)*b;
|
|
else *b = p->val!=0UL;
|
|
} /* end bool() */
|
|
|
|
|
|
extern void l2_Parm(l2_pPARMS p)
|
|
{
|
|
uint16_t i;
|
|
struct l2_PARMS0 * anonym;
|
|
struct l2__D2 * anonym0;
|
|
{ /* with */
|
|
struct l2_PARMS0 * anonym = p;
|
|
if (anonym->parm<=6U) anonym->port = 1U;
|
|
else if (anonym->port==0U || anonym->port>15U) return;
|
|
{ /* with */
|
|
struct l2__D2 * anonym0 = &l2_Parms[anonym->port-1U];
|
|
switch (anonym->parm) {
|
|
case 0U: /* set all mycalls, first is digi */
|
|
call(p, MyCalls, 17ul);
|
|
break;
|
|
case 1U:
|
|
call(p, DNot, 9ul);
|
|
break;
|
|
case 2U:
|
|
X2C_MOVE((char *)anonym->str,(char *)mfrom,7UL);
|
|
break;
|
|
case 3U:
|
|
value(p, &DMTIME);
|
|
break;
|
|
case 4U:
|
|
value(p, &QTIME);
|
|
break;
|
|
case 5U:
|
|
value(p, &maxrxbuffers);
|
|
break;
|
|
case 6U:
|
|
value(p, &maxtxbuffers);
|
|
break;
|
|
case 7U:
|
|
bool(p, &anonym0->Digipeat);
|
|
break;
|
|
case 8U:
|
|
bool(p, &anonym0->HalfDuplex);
|
|
break;
|
|
case 9U:
|
|
bool(p, &anonym0->DamaMaster);
|
|
break;
|
|
case 10U:
|
|
bool(p, &anonym0->monitor);
|
|
break;
|
|
case 11U:
|
|
bool(p, &anonym0->passall);
|
|
break;
|
|
case 12U:
|
|
bool(p, &anonym0->Echo);
|
|
break;
|
|
case 13U:
|
|
if (anonym->test) {
|
|
X2C_MOVE((char *)anonym0->SendBauds,
|
|
(char *)anonym->str,17UL);
|
|
}
|
|
else {
|
|
for (i = 0U; i<=16U; i++) {
|
|
if ((uint8_t)anonym->str[i]>='0' && (uint8_t)
|
|
anonym->str[i]<='7') anonym0->SendBauds[i] = anonym->str[i];
|
|
} /* end for */
|
|
}
|
|
break;
|
|
default:;
|
|
anonym->parm -= 14U;
|
|
if (anonym->parm<=16U) {
|
|
value(p, &anonym0->_.card[anonym->parm]);
|
|
CheckParms(anonym->port);
|
|
}
|
|
break;
|
|
} /* end switch */
|
|
}
|
|
}
|
|
} /* end Parm() */
|
|
|
|
|
|
extern void l2_Getudp2info(l2_pLINK l, char s[], uint32_t s_len)
|
|
{
|
|
uint16_t j;
|
|
uint16_t i;
|
|
s[0UL] = 0;
|
|
if (((struct LINK *)l && ((struct LINK *)l)->udp2info[0U])
|
|
&& ((struct LINK *)l)->udp2info[1U]) {
|
|
j = 0U;
|
|
i = 2U;
|
|
while ((uint32_t)j<s_len-1 && ((struct LINK *)l)->udp2info[i]) {
|
|
s[j] = ((struct LINK *)l)->udp2info[i];
|
|
++j;
|
|
++i;
|
|
}
|
|
s[j] = 0;
|
|
}
|
|
} /* end Getudp2info() */
|
|
|
|
|
|
extern void l2_GetAdress0(l2_pLINK l, l2_pGETADRESS p)
|
|
{
|
|
uint16_t len;
|
|
uint16_t i;
|
|
struct l2_GETADRESS * anonym;
|
|
struct LINK * anonym0;
|
|
uint16_t tmp;
|
|
{ /* with */
|
|
struct l2_GETADRESS * anonym = p;
|
|
{ /* with */
|
|
struct LINK * anonym0 = (struct LINK *)l;
|
|
anonym->port = anonym0->Uplinkport;
|
|
anonym->my = anonym0->mycall;
|
|
len = Min(71U, anonym0->AdrLen-1U);
|
|
tmp = len;
|
|
i = 0U;
|
|
if (i<=tmp) for (;; i++) {
|
|
anonym->adress[i] = (char)((uint32_t)(uint8_t)
|
|
anonym0->Adress[i]/2UL);
|
|
if (i==tmp) break;
|
|
} /* end for */
|
|
anonym->adress[len] = 0;
|
|
if (anonym0->rxInfoOut && anonym0->rxInfoOut->len) {
|
|
anonym->cpid = (uint16_t)(uint8_t)
|
|
anonym0->rxInfoOut->info[0U];
|
|
}
|
|
else anonym->cpid = 65535U;
|
|
}
|
|
}
|
|
} /* end GetAdress() */
|
|
|
|
|
|
extern void l2_GetStat0(l2_pGETSTAT p)
|
|
{
|
|
uint16_t v;
|
|
uint16_t i;
|
|
struct l2_GETSTAT * anonym;
|
|
struct LINK * anonym0;
|
|
uint16_t tmp;
|
|
l2_L2Lock = 1;
|
|
{ /* with */
|
|
struct l2_GETSTAT * anonym = p;
|
|
if ((struct LINK *)anonym->l==0) {
|
|
for (;;) {
|
|
v = anonym->n/16U;
|
|
anonym->l = AdrHash[anonym->n&15U];
|
|
i = 0U;
|
|
while ((struct LINK *)anonym->l && i<v) {
|
|
++i;
|
|
anonym->l = ((struct LINK *)anonym->l)->Hashnext;
|
|
}
|
|
if ((struct LINK *)anonym->l==0) {
|
|
anonym->n = anonym->n&15U;
|
|
if (anonym->n==15U) {
|
|
anonym->n = 0U;
|
|
break;
|
|
}
|
|
++anonym->n;
|
|
}
|
|
else {
|
|
anonym->n += 16U;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if ((struct LINK *)anonym->l) {
|
|
{ /* with */
|
|
struct LINK * anonym0 = (struct LINK *)anonym->l;
|
|
anonym->st = anonym0->State;
|
|
anonym->port = anonym0->Uplinkport;
|
|
anonym->txbu = anonym0->txbuffers;
|
|
anonym->my = anonym0->mycall;
|
|
anonym->ret = anonym0->retry;
|
|
anonym->bsy = anonym0->busy!=0U;
|
|
anonym->remb = anonym0->rembusy;
|
|
anonym->nudl = anonym0->nudel;
|
|
tmp = Min(71U, anonym0->AdrLen);
|
|
i = 0U;
|
|
if (i<=tmp) for (;; i++) {
|
|
anonym->adress[i] = (char)((uint32_t)(uint8_t)
|
|
anonym0->Adress[i]/2UL);
|
|
if (i==tmp) break;
|
|
} /* end for */
|
|
if (anonym0->AdrLen<=71U) anonym->adress[anonym0->AdrLen] = 0;
|
|
anonym->sent = anonym0->SentBytes;
|
|
anonym->ack = anonym0->AckBytes;
|
|
anonym->rcvd = anonym0->RcvdBytes;
|
|
anonym->since = Time-anonym0->Started;
|
|
}
|
|
}
|
|
Unlock();
|
|
}
|
|
} /* end GetStat() */
|
|
|
|
|
|
extern char l2_PortStat0(l2_pPORTSTAT p)
|
|
{
|
|
uint16_t j;
|
|
uint16_t i;
|
|
struct l2_PORTSTAT * anonym;
|
|
struct l2__D0 * anonym0;
|
|
/*prev intervall*/
|
|
struct l2__D1 * anonym1;
|
|
uint16_t tmp;
|
|
{ /* with */
|
|
struct l2_PORTSTAT * anonym = p;
|
|
memset((char *)anonym->sums,(char)0,28UL);
|
|
anonym->mem = memory;
|
|
anonym->time0 = Time;
|
|
if ((anonym->port>0U && anonym->port<=15U)
|
|
&& l2_Parms[anonym->port-1U]._._0.Diversity) {
|
|
{ /* with */
|
|
struct l2__D0 * anonym0 = &l2_PortSt[anonym->port];
|
|
j = Minut5(); /*aktual intervall*/
|
|
tmp = anonym->minits5;
|
|
i = 1U;
|
|
if (i<=tmp) for (;; i++) {
|
|
if (j==0U) j = 12U;
|
|
else --j;
|
|
{ /* with */
|
|
struct l2__D1 * anonym1 = &anonym0->Flows[j];
|
|
anonym->sums[0U] += (uint32_t)anonym1->Igot;
|
|
anonym->sums[1U] += (uint32_t)anonym1->Isent;
|
|
anonym->sums[2U] += (uint32_t)anonym1->Iack;
|
|
anonym->sums[3U] += anonym1->Bytegot;
|
|
anonym->sums[4U] += anonym1->Bytesent;
|
|
}
|
|
if (i==tmp) break;
|
|
} /* end for */
|
|
anonym->sums[5U] = (uint32_t)anonym0->Links;
|
|
anonym->sums[6U] = (uint32_t)anonym0->MaxLinks;
|
|
}
|
|
}
|
|
else return 0;
|
|
return 1;
|
|
}
|
|
} /* end PortStat() */
|
|
|
|
|
|
static void ToSendQue(l2_pLINK l, uint16_t why, uint16_t c)
|
|
{
|
|
/*for safety*/
|
|
struct LINK * anonym;
|
|
struct _1 * anonym0;
|
|
if ((struct LINK *)l) {
|
|
{ /* with */
|
|
struct LINK * anonym = (struct LINK *)l;
|
|
anonym->sendcmd = why;
|
|
anonym->cp = c;
|
|
PortL2[anonym->Uplinkport-1U].lookinque = 1;
|
|
/*only to find out quick if what in a que*/
|
|
if (anonym->IsInQue>=3U && !anonym->damastop) {
|
|
anonym->IsInQue = 0U;
|
|
if (anonym->mycall==0U) anonym->IsInQue = 2U;
|
|
else if ((!anonym->highspeed && why==0x8000U)
|
|
&& (anonym->sendinfo && anonym->sendinfo->len>80U || anonym->txInfoOut && anonym->txInfoOut->len>80U)
|
|
) anonym->IsInQue = 1U;
|
|
{ /* with */
|
|
struct _1 * anonym0 = &PortL2[anonym->Uplinkport-1U]
|
|
.SendQues[anonym->IsInQue];
|
|
if ((struct LINK *)anonym0->SendQueOut==0) {
|
|
anonym0->SendQueOut = l;
|
|
}
|
|
else {
|
|
((struct LINK *)l)->SendQueprev = anonym0->SendQueIn;
|
|
((struct LINK *)anonym0->SendQueIn)->SendQuenext = l;
|
|
}
|
|
anonym0->SendQueIn = l;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} /* end ToSendQue() */
|
|
|
|
|
|
static l2_pDATA GetSendInfo(l2_pLINK l)
|
|
{
|
|
struct LINK * anonym;
|
|
{ /* with */
|
|
struct LINK * anonym = (struct LINK *)l;
|
|
if ((anonym->infostop || anonym->rembusy) || (((anonym->ns+9U)
|
|
-anonym->lowsent&7U)
|
|
>=l2_Parms[anonym->Uplinkport-1U]
|
|
._._0.MaxFrames || anonym->rejgot) && anonym->sendinfo) {
|
|
return 0;
|
|
}
|
|
if (anonym->sendinfo==0) return anonym->txInfoOut;
|
|
return anonym->sendinfo->next;
|
|
}
|
|
} /* end GetSendInfo() */
|
|
|
|
|
|
static void Appendtx(l2_pLINK link, l2_pDATA data)
|
|
{
|
|
struct LINK * anonym;
|
|
{ /* with */
|
|
struct LINK * anonym = (struct LINK *)link;
|
|
if ((((data->info[0U]=='\360' && anonym->txInfoOut) && data->len>1U)
|
|
&& anonym->modifylast)
|
|
&& anonym->txInfoIn->len+data->len<=258U) {
|
|
/*F0 PID*/
|
|
/*append to previous buffer*/
|
|
X2C_MOVE((char *) &data->info[1U],
|
|
(char *) &anonym->txInfoIn->info[anonym->txInfoIn->len],
|
|
(uint32_t)(data->len-1U));
|
|
anonym->txInfoIn->len += data->len-1U;
|
|
Dealloc((char * *) &data);
|
|
return;
|
|
}
|
|
data->next = 0;
|
|
if (anonym->txInfoOut==0) anonym->txInfoOut = data;
|
|
else anonym->txInfoIn->next = data;
|
|
anonym->txInfoIn = data;
|
|
++anonym->txbuffers;
|
|
anonym->modifylast = 1; /*this buffer was not sent till now*/
|
|
if (anonym->IsInQue>=3U && GetSendInfo(link)) {
|
|
PortL2[anonym->Uplinkport-1U]
|
|
.damaloop = PortL2[anonym->Uplinkport-1U].T1Out;
|
|
/*start a quick roundtrip*/
|
|
ToSendQue(link, 0x8000U, 2U); /*schedule link to send info*/
|
|
}
|
|
}
|
|
} /* end Appendtx() */
|
|
|
|
|
|
static void CopyI(l2_pLINK from, l2_pLINK to, char reconn)
|
|
{
|
|
l2_pDATA ip;
|
|
struct LINK * anonym; /*copy rest of rx-info to sender*/
|
|
struct l2_DFIELD * anonym0;
|
|
{ /* with */
|
|
struct LINK * anonym = (struct LINK *)from;
|
|
if (anonym->rxInfoOut) {
|
|
{ /* with */
|
|
struct l2_DFIELD * anonym0 = anonym->rxInfoOut;
|
|
if (anonym->readp && anonym0->len>anonym->readp) {
|
|
/*shift info to begin of buffer*/
|
|
X2C_MOVE((char *) &anonym0->info[anonym->readp+1U],
|
|
(char *) &anonym0->info[1U],
|
|
(uint32_t)((anonym0->len-anonym->readp)-1U));
|
|
anonym0->len -= anonym->readp;
|
|
anonym->readp = 0U;
|
|
}
|
|
}
|
|
do {
|
|
ip = anonym->rxInfoOut->next;
|
|
Appendtx(to, anonym->rxInfoOut);
|
|
--anonym->rxbuffers;
|
|
anonym->rxInfoOut = ip;
|
|
} while (anonym->rxInfoOut);
|
|
}
|
|
anonym->nudel = to;
|
|
if (!reconn) {
|
|
--hosts;
|
|
anonym->Magic = 0UL;
|
|
anonym->host = 0;
|
|
}
|
|
}
|
|
} /* end CopyI() */
|
|
|
|
|
|
extern void l2_Circuit(l2_pLINK * l1, l2_pLINK * l20, char reconn1,
|
|
char reconn2, uint16_t exitchar)
|
|
{
|
|
l2_L2Lock = 1;
|
|
if (((((struct LINK *)*l1)->Magic==2091827346UL && ((struct LINK *)*l20)
|
|
->Magic==2091827346UL) && ((struct LINK *)*l1)->State)
|
|
&& ((struct LINK *)*l20)->State) {
|
|
CopyI(*l1, *l20, reconn1);
|
|
CopyI(*l20, *l1, reconn2);
|
|
((struct LINK *)*l1)->exitch = exitchar;
|
|
}
|
|
if (!reconn1) *l1 = 0;
|
|
if (!reconn2) *l20 = 0;
|
|
Unlock();
|
|
} /* end Circuit() */
|
|
|
|
|
|
extern char l2_SendStr(l2_pLINK l, uint16_t size, l2_pSTRING buf)
|
|
{
|
|
l2_pDATA b;
|
|
struct LINK * anonym;
|
|
l2_L2Lock = 1;
|
|
{ /* with */
|
|
struct LINK * anonym = (struct LINK *)l;
|
|
if ((anonym->Magic==2091827346UL && anonym->State>=2U) && size<=256U) {
|
|
if (size==0U) return !anonym->txfull;
|
|
/* check if txbuffer full */
|
|
if (((anonym->txInfoOut && anonym->modifylast)
|
|
&& anonym->txInfoIn->len+size<=256U)
|
|
&& anonym->cCONNtyp==l2_cNORMAL) {
|
|
/* IF (txInfoOut<>NIL)
|
|
& modifylast & (txInfoIn^.len+size<=257) & (cCONNtyp=cNORMAL)
|
|
THEN */
|
|
X2C_MOVE((char *)buf,
|
|
(char *) &anonym->txInfoIn->info[anonym->txInfoIn->len],
|
|
(uint32_t)size); /*append to previous buffer*/
|
|
anonym->txInfoIn->len += size;
|
|
}
|
|
else if (anonym->txbuffers<=maxtxbuffers && Alloc((char * *)
|
|
&b, 20U)) {
|
|
b->info[0U] = anonym->pid;
|
|
X2C_MOVE((char *)buf,(char *) &b->info[1U],
|
|
(uint32_t)size);
|
|
b->len = size+1U;
|
|
Appendtx(l, b);
|
|
}
|
|
else {
|
|
anonym->txfull = 1;
|
|
Unlock();
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
Unlock();
|
|
return 1;
|
|
} /* end SendStr() */
|
|
|
|
|
|
static void RemoveTimer(l2_pLINK l)
|
|
{
|
|
struct _0 * anonym;
|
|
{ /* with */
|
|
struct _0 * anonym = &PortL2[((struct LINK *)l)->Uplinkport-1U];
|
|
if ((struct LINK *)anonym->T1Out==(struct LINK *)anonym->T1In) {
|
|
anonym->T1Out = 0;
|
|
}
|
|
else if ((struct LINK *)l==(struct LINK *)anonym->T1Out) {
|
|
anonym->T1Out = ((struct LINK *)l)->Timernext;
|
|
}
|
|
else if ((struct LINK *)l==(struct LINK *)anonym->T1In) {
|
|
anonym->T1In = ((struct LINK *)l)->Timerprev;
|
|
}
|
|
else {
|
|
((struct LINK *)((struct LINK *)l)->Timerprev)
|
|
->Timernext = ((struct LINK *)l)->Timernext;
|
|
((struct LINK *)((struct LINK *)l)->Timernext)
|
|
->Timerprev = ((struct LINK *)l)->Timerprev;
|
|
}
|
|
}
|
|
} /* end RemoveTimer() */
|
|
|
|
|
|
static void StartTimer(l2_pLINK l)
|
|
{
|
|
/*WrStrLn("<T1>"); */
|
|
struct LINK * anonym;
|
|
struct _0 * anonym0;
|
|
{ /* with */
|
|
struct LINK * anonym = (struct LINK *)l;
|
|
{ /* with */
|
|
struct _0 * anonym0 = &PortL2[anonym->Uplinkport-1U];
|
|
anonym->T1out = ((anonym0->QTicker+l2_Parms[anonym->Uplinkport-1U]
|
|
._._0.T1)-1U)%20000U; /*next timeout*/
|
|
/*WrInt(T1out, 5); WrStr(":tout1 "); */
|
|
if ((struct LINK *)anonym0->T1Out==0) anonym0->T1Out = l;
|
|
else {
|
|
if ((anonym->T1out-((struct LINK *)anonym0->T1In)->T1out)
|
|
%20000U>10000U) {
|
|
anonym->T1out = ((struct LINK *)anonym0->T1In)->T1out;
|
|
}
|
|
/*WrInt(T1out, 5); WrStr(":tout2 "); */
|
|
anonym->Timerprev = anonym0->T1In;
|
|
((struct LINK *)anonym0->T1In)->Timernext = l;
|
|
}
|
|
/*append to que*/
|
|
anonym0->T1In = l;
|
|
}
|
|
}
|
|
} /* end StartTimer() */
|
|
|
|
|
|
static void MakePoll(l2_pLINK linkp)
|
|
{
|
|
uint16_t cmd;
|
|
uint16_t r;
|
|
struct LINK * anonym;
|
|
{ /* with */
|
|
struct LINK * anonym = (struct LINK *)linkp;
|
|
if (anonym->State>=2U && anonym->cCONNtyp==l2_cNORMAL) {
|
|
r = l2_Parms[anonym->Uplinkport-1U]._._0.Retries;
|
|
if (anonym->State!=5U || !anonym->twoway) r = r/4U+1U;
|
|
++anonym->retry;
|
|
if (anonym->retry>r) {
|
|
/*WrStrLn("state1"); */
|
|
anonym->State = 1U;
|
|
}
|
|
/*retried out*/
|
|
cmd = 0x43U;
|
|
if (anonym->State==5U) cmd = 0x1U;
|
|
else if (anonym->State==2U) cmd = 0x2FU;
|
|
ToSendQue(linkp, cmd, 3U);
|
|
}
|
|
else if (anonym->State==2U && (anonym->cCONNtyp==l2_cFLEXback || anonym->cCONNtyp==l2_cCONNAK)
|
|
) {
|
|
anonym->State = 5U;
|
|
cmd = 0x63U;
|
|
anonym->cCONNtyp = l2_cNORMAL;
|
|
ToSendQue(linkp, 0x63U, 1U);
|
|
}
|
|
else if (anonym->State==2U && anonym->cCONNtyp==l2_cFLEXbusy) {
|
|
/*WrStrLn("pollflexbusy"); */
|
|
anonym->State = 1U;
|
|
cmd = 0xFU;
|
|
ToSendQue(linkp, 0xFU, 1U);
|
|
}
|
|
}
|
|
} /* end MakePoll() */
|
|
|
|
|
|
static void ClearBusy(l2_pLINK l)
|
|
{
|
|
struct LINK * anonym;
|
|
{ /* with */
|
|
struct LINK * anonym = (struct LINK *)l;
|
|
if (anonym->busy && anonym->State==5U) {
|
|
anonym->busy = 0U;
|
|
anonym->busyend = 1; /*until the other knows*/
|
|
ToSendQue(l, 0x1U, 0U);
|
|
RemoveTimer(l);
|
|
anonym->T3out = (Second+1U)%20000U; /*start minimal T3*/
|
|
StartTimer(l);
|
|
}
|
|
}
|
|
} /* end ClearBusy() */
|
|
|
|
|
|
static void Disc(l2_pLINK l)
|
|
{
|
|
struct LINK * anonym;
|
|
{ /* with */
|
|
struct LINK * anonym = (struct LINK *)l;
|
|
if (anonym->cCONNtyp) anonym->State = 1U;
|
|
else if (anonym->discing || anonym->State!=5U) {
|
|
/*do it quick*/
|
|
if (anonym->State>=2U) ToSendQue(l, 0x43U, 3U);
|
|
anonym->State = 1U;
|
|
}
|
|
else if (anonym->txInfoOut==0) {
|
|
anonym->State = 4U; /*disc state*/
|
|
anonym->retry = 0U;
|
|
RemoveTimer(l);
|
|
anonym->T3out = 65535U; /*start T1*/
|
|
StartTimer(l);
|
|
MakePoll(l); /*DISC ...*/
|
|
}
|
|
else {
|
|
anonym->discing = 1; /*first send all infos*/
|
|
anonym->Qtime = 0U;
|
|
}
|
|
}
|
|
} /* end Disc() */
|
|
|
|
|
|
extern void l2_Disconnect(l2_pLINK * l, char dealloc)
|
|
{
|
|
l2_pDATA ip;
|
|
struct LINK * anonym;
|
|
/*WrInt(memory, 6); WrInt(hosts, 6); WrInt(l^.State, 6);
|
|
WrInt(ORD(dealloc),1); WrStrLn(" flexdisc "); */
|
|
l2_L2Lock = 1;
|
|
if (((struct LINK *)*l)->Magic==2091827346UL) {
|
|
if (((struct LINK *)*l)->State>=2U) Disc(*l);
|
|
if (dealloc) {
|
|
/*host gives link back to l2*/
|
|
--hosts;
|
|
{ /* with */
|
|
struct LINK * anonym = (struct LINK *)*l;
|
|
while (anonym->rxInfoOut) {
|
|
/*deallocate rx-info*/
|
|
ip = anonym->rxInfoOut->next;
|
|
Dealloc((char * *) &anonym->rxInfoOut);
|
|
anonym->rxInfoOut = ip;
|
|
}
|
|
anonym->Magic = 0UL;
|
|
/*WrStr("L2: state:"); WrInt(State, 5); WrStrLn(""); */
|
|
if (anonym->State==0U) Dealloc((char * *)l);
|
|
else {
|
|
/*WrStrLn("l2:dealloc"); */
|
|
anonym->host = 0;
|
|
}
|
|
}
|
|
*l = 0;
|
|
}
|
|
}
|
|
Unlock();
|
|
} /* end Disconnect() */
|
|
|
|
|
|
static void Cut(l2_pLINK l)
|
|
{
|
|
struct LINK * anonym;
|
|
{ /* with */
|
|
struct LINK * anonym = (struct LINK *)l;
|
|
if ((struct LINK *)anonym->nudel) {
|
|
((struct LINK *)anonym->nudel)->nudel = 0; /*remove pointer to me*/
|
|
if (((struct LINK *)anonym->nudel)->host==0) Disc(anonym->nudel);
|
|
else ClearBusy(anonym->nudel);
|
|
anonym->nudel = 0;
|
|
}
|
|
}
|
|
} /* end Cut() */
|
|
|
|
|
|
static void DisposeLink(l2_pLINK l, char immediate)
|
|
{
|
|
l2_pDATA ip;
|
|
uint16_t i;
|
|
/*throw away bufferd data*/
|
|
struct LINK * anonym;
|
|
/*remove link from sendque*/
|
|
struct LINK * anonym0;
|
|
struct _1 * anonym1;
|
|
/*WrStrLn("L2: disposelink"); */
|
|
if ((struct LINK *)l) {
|
|
/*for safety*/
|
|
{ /* with */
|
|
struct LINK * anonym = (struct LINK *)l;
|
|
for (i = 0U; i<=7U; i++) {
|
|
Dealloc((char * *) &anonym->sammler[i]);
|
|
} /* end for */
|
|
while (anonym->txInfoOut) {
|
|
ip = anonym->txInfoOut->next;
|
|
Dealloc((char * *) &anonym->txInfoOut);
|
|
anonym->txInfoOut = ip;
|
|
}
|
|
Dealloc((char * *) &anonym->SABMinfo);
|
|
/*send the (sad or lucky) message to host*/
|
|
if (anonym->host && !anonym->saiddisc) {
|
|
/*do it only once*/
|
|
/*WrStrLn(" say disc/busy"); */
|
|
if (anonym->State==2U) {
|
|
X2C_CHKPROC(l2_CALLBACKPROC,Event)(&anonym->host, l,
|
|
l2_eBUSY);
|
|
}
|
|
else {
|
|
X2C_CHKPROC(l2_CALLBACKPROC,Event)(&anonym->host, l,
|
|
l2_eDISCONNECTED);
|
|
}
|
|
anonym->saiddisc = 1;
|
|
}
|
|
Cut(l); /*disconnect nudelport*/
|
|
}
|
|
/*WrStr("dispo:");WrInt(ORD(immediate),2); WrInt(l^.mycall,2);
|
|
WrStrLn(""); */
|
|
/* IF immediate OR (l^.mycall<>MAX(CARD16))
|
|
THEN (*not a downlink*) */
|
|
if (immediate || !((struct LINK *)l)->flexback) {
|
|
/*not a downlink*/
|
|
{ /* with */
|
|
struct LINK * anonym0 = (struct LINK *)l;
|
|
if (anonym0->IsInQue<3U) {
|
|
{ /* with */
|
|
struct _1 * anonym1 = &PortL2[anonym0->Uplinkport-1U]
|
|
.SendQues[anonym0->IsInQue];
|
|
if ((struct LINK *)anonym1->SendQueOut==(struct LINK *)
|
|
anonym1->SendQueIn) anonym1->SendQueOut = 0;
|
|
else if ((struct LINK *)l==(struct LINK *)
|
|
anonym1->SendQueOut) {
|
|
anonym1->SendQueOut = anonym0->SendQuenext;
|
|
}
|
|
else if ((struct LINK *)l==(struct LINK *)
|
|
anonym1->SendQueIn) {
|
|
anonym1->SendQueIn = anonym0->SendQueprev;
|
|
}
|
|
else {
|
|
((struct LINK *)anonym0->SendQueprev)
|
|
->SendQuenext = anonym0->SendQuenext;
|
|
((struct LINK *)anonym0->SendQuenext)
|
|
->SendQueprev = anonym0->SendQueprev;
|
|
}
|
|
}
|
|
}
|
|
/*remove link from hashchain*/
|
|
if ((struct LINK *)l==(struct LINK *)AdrHash[anonym0->Hash]) {
|
|
AdrHash[anonym0->Hash] = anonym0->Hashnext;
|
|
}
|
|
else {
|
|
((struct LINK *)anonym0->Hashprev)
|
|
->Hashnext = ((struct LINK *)l)->Hashnext;
|
|
if ((struct LINK *)anonym0->Hashnext) {
|
|
((struct LINK *)anonym0->Hashnext)
|
|
->Hashprev = anonym0->Hashprev;
|
|
}
|
|
}
|
|
}
|
|
RemoveTimer(l);
|
|
--l2_PortSt[((struct LINK *)l)->Uplinkport].Links;
|
|
/*now the link has no relation with L2,
|
|
so give it to host or deallocate*/
|
|
if (((struct LINK *)l)->host) {
|
|
/*WrStrLn("state12"); */
|
|
((struct LINK *)l)->State = 0U;
|
|
}
|
|
else {
|
|
/*WrStrLn("disposedealloc"); */
|
|
((struct LINK *)l)->Magic = 0UL;
|
|
Dealloc((char * *) &l);
|
|
}
|
|
}
|
|
}
|
|
/*WrStr("disposelink mem=");WrInt(memory,1); */
|
|
/*WrStr(" hosts=");WrInt(hosts,1); */
|
|
/*WrStrLn(""); (*for tests*) */
|
|
} /* end DisposeLink() */
|
|
|
|
|
|
static void TestMem(l2_pLINK l)
|
|
{
|
|
struct LINK * anonym;
|
|
if (memory>=20U) {
|
|
{ /* with */
|
|
struct LINK * anonym = (struct LINK *)l;
|
|
if ((struct LINK *)anonym->nudel) {
|
|
if (anonym->txbuffers+4U<memory/4U) {
|
|
ClearBusy(anonym->nudel);
|
|
anonym->txfull = 0;
|
|
}
|
|
}
|
|
else if (anonym->host && anonym->txbuffers<=maxtxbuffers) {
|
|
X2C_CHKPROC(l2_CALLBACKPROC,Event)(&anonym->host, l, l2_eTXFREE);
|
|
anonym->txfull = 0;
|
|
}
|
|
}
|
|
}
|
|
} /* end TestMem() */
|
|
|
|
|
|
static void StartT3(l2_pLINK l)
|
|
{
|
|
((struct LINK *)l)->T3out = (Second+l2_Parms[((struct LINK *)l)
|
|
->Uplinkport-1U]._._0.T3)%20000U;
|
|
} /* end StartT3() */
|
|
|
|
|
|
static uint16_t T3resttime(l2_pLINK l)
|
|
{
|
|
short th;
|
|
if (((struct LINK *)l)->T3out==65535U) return 0U;
|
|
th = (short)((struct LINK *)l)->T3out-(short)Second;
|
|
if (th<0) th += 20000;
|
|
if (th>10000) return 0U;
|
|
/* T3 ran out */
|
|
return (uint16_t)th;
|
|
} /* end T3resttime() */
|
|
|
|
|
|
static void Timeout(l2_pLINK l)
|
|
{
|
|
struct LINK * anonym;
|
|
/*WrInt(Qtime, 6);WrInt(State, 6);WrInt(memory, 6);
|
|
WrStr(":qtime/state/mem "); */
|
|
struct _0 * anonym0; /*remove timer from end of que*/
|
|
{ /* with */
|
|
struct LINK * anonym = (struct LINK *)l;
|
|
if (anonym->State<=1U && anonym->Qtime>DMTIME) {
|
|
DisposeLink(l, 1);
|
|
return;
|
|
}
|
|
{ /* with */
|
|
struct _0 * anonym0 = &PortL2[anonym->Uplinkport-1U];
|
|
if ((struct LINK *)anonym0->T1Out==(struct LINK *)anonym0->T1In) {
|
|
anonym0->T1Out = 0;
|
|
}
|
|
else anonym0->T1Out = ((struct LINK *)anonym0->T1Out)->Timernext;
|
|
}
|
|
StartTimer(l);
|
|
if (anonym->State>=2U) {
|
|
if (anonym->T3out!=65535U) {
|
|
if (anonym->discing && anonym->State==5U) {
|
|
if (anonym->Qtime<QTIME) ++anonym->Qtime;
|
|
else anonym->State = 4U;
|
|
}
|
|
if (T3resttime(l)==0U) anonym->T3out = 65535U;
|
|
}
|
|
}
|
|
else {
|
|
/*lifetimer for state 1 downlink*/
|
|
++anonym->Qtime;
|
|
StartT3(l);
|
|
}
|
|
/*WrStrLn(" incq "); */
|
|
if (l2_Parms[anonym->Uplinkport-1U].DamaMaster) {
|
|
anonym->damastop = 0; /*link now is in its slot*/
|
|
if (anonym->sendcmd!=0x4000U) {
|
|
/*there is a frame to be sent*/
|
|
ToSendQue(l, anonym->sendcmd, anonym->cp);
|
|
/*damastop is over, so its qued*/
|
|
anonym->damasecond = Second; /*last slot in absolute time*/
|
|
return;
|
|
}
|
|
if ((anonym->State==5U && anonym->T3out!=65535U) && ((T3resttime(l)
|
|
<=DAMAFASTPOLLS || (PortL2[anonym->Uplinkport-1U].QTicker+1U)
|
|
%20000U==Second) || ((Second+20000U)-anonym->damasecond)
|
|
%20000U>=DAMAMAXTIME)) {
|
|
/*& damabit*/
|
|
/*its a dama slot*/
|
|
/*activ link*/
|
|
/*port has still idle times*/
|
|
ToSendQue(l, 0x1U, 2U); /*enable the other to send now*/
|
|
anonym->damasecond = Second; /*store last absolute slot time*/
|
|
}
|
|
}
|
|
if (anonym->txfull) TestMem(l);
|
|
if (anonym->T3out==65535U || anonym->State<=4U) MakePoll(l);
|
|
}
|
|
} /* end Timeout() */
|
|
|
|
|
|
extern char l2_GetChar(l2_pLINK l, char delete0,
|
|
char * char0)
|
|
{
|
|
l2_pDATA ip;
|
|
char ok0;
|
|
struct LINK * anonym;
|
|
{ /* with */
|
|
struct LINK * anonym = (struct LINK *)l;
|
|
while (anonym->rxInfoOut) {
|
|
ok0 = anonym->rxInfoOut->len>1U;
|
|
*char0 = anonym->rxInfoOut->info[anonym->readp+1U];
|
|
if (!delete0 && ok0) return 1;
|
|
if (anonym->Magic!=2091827346UL) return 0;
|
|
++anonym->readp;
|
|
if (anonym->readp+1U<anonym->rxInfoOut->len) return 1;
|
|
anonym->readp = 0U;
|
|
l2_L2Lock = 1;
|
|
ip = anonym->rxInfoOut->next;
|
|
Dealloc((char * *) &anonym->rxInfoOut);
|
|
anonym->rxInfoOut = ip;
|
|
--anonym->rxbuffers;
|
|
if (anonym->rxbuffers<=maxrxbuffers && memory>=20U) ClearBusy(l);
|
|
Unlock();
|
|
if (ok0) return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
} /* end GetChar() */
|
|
|
|
|
|
extern uint16_t l2_GetStr(l2_pLINK l, uint16_t size, l2_pSTRING buf)
|
|
{
|
|
l2_pDATA ip;
|
|
uint16_t n;
|
|
uint16_t retsize;
|
|
struct LINK * anonym;
|
|
retsize = 0U;
|
|
{ /* with */
|
|
struct LINK * anonym = (struct LINK *)l;
|
|
if (anonym->Magic==2091827346UL) {
|
|
while (retsize<size && anonym->rxInfoOut) {
|
|
n = anonym->rxInfoOut->len-anonym->readp;
|
|
if (n>1U) {
|
|
--n; /*pid*/
|
|
if (n+retsize>size) n = size-retsize;
|
|
X2C_MOVE((char *)
|
|
&anonym->rxInfoOut->info[anonym->readp+1U],
|
|
(char *) &buf[retsize],(uint32_t)n);
|
|
retsize += n;
|
|
anonym->readp += n;
|
|
}
|
|
if (anonym->readp+1U>=anonym->rxInfoOut->len) {
|
|
anonym->readp = 0U;
|
|
l2_L2Lock = 1;
|
|
ip = anonym->rxInfoOut->next;
|
|
Dealloc((char * *) &anonym->rxInfoOut);
|
|
anonym->rxInfoOut = ip;
|
|
--anonym->rxbuffers;
|
|
if (anonym->rxbuffers<=maxrxbuffers && memory>=20U) {
|
|
ClearBusy(l);
|
|
}
|
|
Unlock();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return retsize;
|
|
} /* end GetStr() */
|
|
|
|
|
|
static uint16_t CP(void)
|
|
{
|
|
return (uint16_t)(2UL*(uint32_t)((uint8_t)l2_adress[6U]>=(uint8_t)
|
|
'\200')+(uint32_t)((0x10U & (uint16_t)(uint32_t)
|
|
(uint8_t)l2_adress[l2_asize-1U])!=0));
|
|
} /* end CP() */
|
|
/*p/f bit*/
|
|
/*command bit*/
|
|
|
|
#define l2_SUMLEN 5
|
|
|
|
|
|
static void Appendrx(l2_pLINK linkp, l2_pDATA b)
|
|
{
|
|
struct LINK * anonym;
|
|
{ /* with */
|
|
struct LINK * anonym = (struct LINK *)linkp;
|
|
++l2_PortSt[anonym->Uplinkport].Flows[Minute5].Igot;
|
|
anonym->RcvdBytes = anonym->RcvdBytes+(uint32_t)b->len;
|
|
if ((uint32_t)(uint8_t)b->info[1U]==(uint32_t)
|
|
anonym->exitch && anonym->host) Cut(linkp);
|
|
if ((struct LINK *)anonym->nudel) {
|
|
Appendtx(anonym->nudel, b);
|
|
if (((struct LINK *)anonym->nudel)->txbuffers+4U>memory/4U) {
|
|
++anonym->busy;
|
|
((struct LINK *)anonym->nudel)->txfull = 1;
|
|
}
|
|
}
|
|
else if (anonym->host) {
|
|
b->next = 0;
|
|
if (anonym->rxInfoOut==0) anonym->rxInfoOut = b;
|
|
else anonym->rxInfoIn->next = b;
|
|
anonym->rxInfoIn = b;
|
|
++anonym->rxbuffers;
|
|
if (anonym->rxbuffers>=maxrxbuffers) ++anonym->busy;
|
|
if (anonym->rxbuffers==1U) {
|
|
X2C_CHKPROC(l2_CALLBACKPROC,Event)(&anonym->host, linkp,
|
|
l2_eRXDATA);
|
|
}
|
|
}
|
|
else Dealloc((char * *) &b);
|
|
}
|
|
} /* end Appendrx() */
|
|
|
|
|
|
static char Ack(l2_pLINK linkp, uint16_t n, char resend)
|
|
{
|
|
l2_pDATA dp;
|
|
/*ackowlege my sent info*/
|
|
struct LINK * anonym;
|
|
{ /* with */
|
|
struct LINK * anonym = (struct LINK *)linkp;
|
|
if (((anonym->highsent+8U)-anonym->lowsent&7U)<((n+8U)
|
|
-anonym->lowsent&7U)) {
|
|
ToSendQue(linkp, 0x87U, 0U); /*acknowledges never sended info*/
|
|
return 0;
|
|
}
|
|
anonym->twoway = 1;
|
|
while (anonym->lowsent!=n) {
|
|
/*delete acknowledged from sendbuffer*/
|
|
if (anonym->txInfoOut) {
|
|
/*only for safety*/
|
|
if (anonym->ns==anonym->lowsent) resend = 1;
|
|
dp = anonym->txInfoOut->next;
|
|
anonym->AckBytes = anonym->AckBytes+(uint32_t)
|
|
anonym->txInfoOut->len;
|
|
++l2_PortSt[anonym->Uplinkport].Flows[Minute5].Iack;
|
|
Dealloc((char * *) &anonym->txInfoOut);
|
|
anonym->txInfoOut = dp;
|
|
--anonym->txbuffers;
|
|
}
|
|
else return 0;
|
|
/*dramatic internal error*/
|
|
anonym->lowsent = anonym->lowsent+1U&7U;
|
|
}
|
|
if (resend) {
|
|
/*all sent acknolled or resend info*/
|
|
anonym->ns = n;
|
|
anonym->sendinfo = 0;
|
|
anonym->retry = 0U;
|
|
}
|
|
if (resend || anonym->rembusy) {
|
|
anonym->infostop = 0;
|
|
StartT3(linkp); /*restart T3*/
|
|
}
|
|
if (anonym->IsInQue>=3U && GetSendInfo(linkp)) {
|
|
ToSendQue(linkp, 0x8000U, 2U); /*schedule for sending next info*/
|
|
PortL2[anonym->Uplinkport-1U]
|
|
.damaloop = PortL2[anonym->Uplinkport-1U].T1Out;
|
|
/*start quick roundtrip*/
|
|
}
|
|
if (anonym->txfull) TestMem(linkp);
|
|
if (anonym->discing && anonym->txInfoOut==0) {
|
|
anonym->State = 4U;
|
|
MakePoll(linkp); /*DISC ...*/
|
|
}
|
|
}
|
|
return 1;
|
|
} /* end Ack() */
|
|
|
|
|
|
static void Uselink(l2_pLINK linkp)
|
|
{
|
|
uint16_t compoll;
|
|
uint16_t i;
|
|
uint16_t sum;
|
|
uint16_t n;
|
|
l2_pDATA ip;
|
|
int32_t j;
|
|
uint16_t cmd;
|
|
char wasbusy;
|
|
char slave;
|
|
struct LINK * anonym;
|
|
int32_t tmp;
|
|
/*analyse (addressed to me) frames and reply*/
|
|
/*WrStrLn("uselink"); */
|
|
{ /* with */
|
|
struct LINK * anonym = (struct LINK *)linkp;
|
|
slave = !l2_Parms[anonym->Uplinkport-1U].DamaMaster && ((uint16_t)
|
|
(uint32_t)(uint8_t)l2_adress[13U]&0x20U)==0U;
|
|
cmd = 0xEFU&(uint16_t)(uint32_t)(uint8_t)l2_adress[l2_asize-1U];
|
|
/*command field without p/f-bit*/
|
|
compoll = CP(); /*response, final, command or poll*/
|
|
if (anonym->cCONNtyp==l2_cNORMAL) {
|
|
if (anonym->T3out!=65535U) StartT3(linkp);
|
|
if ((cmd&0x1U)==0U) {
|
|
/*I-frame */
|
|
if (anonym->State==5U) {
|
|
/*info transfer */
|
|
n = (uint16_t)cmd/2U&7U;
|
|
/*send sequence number */
|
|
if (Ack(linkp, (uint16_t)cmd/32U&7U, slave)) {
|
|
/*acknols my frames*/
|
|
if (anonym->State==5U) {
|
|
/*maybe disc after all acknolled */
|
|
i = l2_dbuf->len;
|
|
if (i>5U) i = 5U;
|
|
sum = 0U;
|
|
tmp = (int32_t)i-1L;
|
|
j = 0L;
|
|
if (j<=tmp) for (;; j++) {
|
|
sum += (uint16_t)(uint8_t)l2_dbuf->info[j];
|
|
if (j==tmp) break;
|
|
} /* end for */
|
|
if (n==anonym->nr && anonym->busy<8U) {
|
|
/*I-frame has expected number*/
|
|
if ((n+9U&7U)!=anonym->sentnr) {
|
|
/*check windowsize */
|
|
anonym->summs[n] = sum; /*mark it as old */
|
|
ip = anonym->sammler[n];
|
|
if (ip || Alloc((char * *) &ip, 10U)) {
|
|
/*do not say rnr with an*/
|
|
Appendrx(linkp, l2_dbuf);
|
|
/*empty downlink buffer,*/
|
|
l2_dbuf = ip; /*noone would clear this*/
|
|
anonym->sammler[n] = 0;
|
|
for (;;) {
|
|
anonym->nr = anonym->nr+1U&7U;
|
|
if (anonym->sammler[anonym->nr]==0) {
|
|
/*no fitting frames in sammler*/
|
|
anonym->rejsent = anonym->sammler[anonym->nr+1U&7U]
|
|
!=0; /*a hole in sammler?*/
|
|
break;
|
|
/*so request only 1 I-frame by REJ if 1 is missing*/
|
|
}
|
|
Appendrx(linkp,
|
|
anonym->sammler[anonym->nr]);
|
|
/*frame from sammler is in sequence*/
|
|
anonym->sammler[anonym->nr] = 0;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
anonym->State = 1U; /*got 8 frames!*/
|
|
ToSendQue(linkp, 0x87U, 0U);
|
|
}
|
|
}
|
|
else {
|
|
if (anonym->summs[n]!=sum) {
|
|
/*frame is from aktual window*/
|
|
anonym->summs[n] = sum;
|
|
/*so put it into sammler */
|
|
ip = anonym->sammler[n];
|
|
if (ip || Alloc((char * *) &ip, 20U)) {
|
|
anonym->sammler[n] = l2_dbuf;
|
|
l2_dbuf = ip;
|
|
}
|
|
}
|
|
anonym->rejsent = compoll!=3U;
|
|
/*say not rej on i-poll */
|
|
}
|
|
ToSendQue(linkp, 0x1U, (uint16_t)(compoll==3U));
|
|
/*make final on poll */
|
|
}
|
|
}
|
|
}
|
|
else if (compoll==3U && anonym->State!=2U) {
|
|
/*WrStrLn("state13"); */
|
|
anonym->State = 1U;
|
|
ToSendQue(linkp, 0xFU, 1U);
|
|
}
|
|
}
|
|
else if ((cmd&0x3U)==0x1U) {
|
|
/*R?R-Frame, REJ with RNR is allowed*/
|
|
wasbusy = anonym->rembusy;
|
|
anonym->rembusy = (0x4U & cmd)!=0; /*remote busy */
|
|
anonym->rejgot = (0x8U & cmd)!=0; /*REJ */
|
|
if (compoll==3U) anonym->busyend = 0;
|
|
/* IF wasbusy & NOT rembusy THEN T3out:=T3OFF END;
|
|
restart T1 */
|
|
if (anonym->State!=5U || Ack(linkp, (uint16_t)cmd/32U&7U,
|
|
((slave || compoll==1U) || anonym->rejgot)
|
|
|| wasbusy && !anonym->rembusy)) {
|
|
if (compoll==3U) {
|
|
/*R?R.Poll */
|
|
if (anonym->State==5U) ToSendQue(linkp, 0x1U, 1U);
|
|
else if (anonym->State!=2U) {
|
|
/*WrStrLn("state14"); */
|
|
anonym->State = 1U; /*the other is polling*/
|
|
ToSendQue(linkp, 0xFU, 1U);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (cmd==0x2FU && compoll==3U) {
|
|
/*only SABM.Poll accepted*/
|
|
Dealloc((char * *) &anonym->SABMinfo);
|
|
if ((anonym->State!=2U && anonym->mycall==65535U)
|
|
&& anonym->twoway) {
|
|
/*mycall=MAX is a downlink*/
|
|
/*WrStrLn("state15"); */
|
|
anonym->State = 1U;
|
|
if (anonym->flexback) DisposeLink(linkp, 1);
|
|
else ToSendQue(linkp, 0xFU, 1U);
|
|
}
|
|
else if (anonym->State==2U || anonym->State==1U && Alloc((char * *)
|
|
&ip, 0U)) {
|
|
if (anonym->host) --hosts;
|
|
X2C_CHKPROC(l2_CALLBACKPROC,Event)(&anonym->host, linkp,
|
|
l2_eCONNECTED);
|
|
if (anonym->host) ++hosts;
|
|
if (anonym->State==1U) {
|
|
/*connect comes from outside*/
|
|
if (anonym->host && l2_dbuf->len) {
|
|
Appendrx(linkp, l2_dbuf);
|
|
l2_dbuf = ip;
|
|
}
|
|
else Dealloc((char * *) &ip);
|
|
}
|
|
if (anonym->host) {
|
|
/*host accepts that connect*/
|
|
anonym->State = 5U;
|
|
anonym->Magic = 2091827346UL;
|
|
ToSendQue(linkp, 0x63U, 1U);
|
|
}
|
|
else {
|
|
/*WrStrLn("state16"); */
|
|
anonym->State = 1U;
|
|
ToSendQue(linkp, 0xFU, 1U);
|
|
/*got no host, say busy or nothing if host needs time */
|
|
}
|
|
}
|
|
else if (anonym->State<=4U || anonym->twoway) {
|
|
anonym->State = 1U;
|
|
/*linkreset, wait for new link. this SABM is lost*/
|
|
/*WrStrLn("dispose3"); */
|
|
DisposeLink(linkp, 0); /*a downlink will say DM*/
|
|
}
|
|
else {
|
|
ToSendQue(linkp, 0x63U, 1U);
|
|
RemoveTimer(linkp);
|
|
anonym->T3out = 65535U; /*restart T1*/
|
|
StartTimer(linkp); /*test if the other has a receiver*/
|
|
anonym->infostop = 1; /*before resending the first I-frames*/
|
|
}
|
|
}
|
|
else if (cmd==0x63U && compoll==1U) {
|
|
/*only UA.Final because i send SABM.P*/
|
|
Dealloc((char * *) &anonym->SABMinfo);
|
|
if (anonym->State==2U) {
|
|
if (anonym->host) --hosts;
|
|
X2C_CHKPROC(l2_CALLBACKPROC,Event)(&anonym->host, linkp,
|
|
l2_eCONNECTED);
|
|
if (anonym->host) {
|
|
/*host is still alive*/
|
|
++hosts;
|
|
anonym->State = 5U;
|
|
anonym->twoway = 1; /*both are in state 5 now*/
|
|
anonym->Magic = 2091827346UL; /*...a magic feeling*/
|
|
anonym->retry = 0U;
|
|
if (anonym->txInfoOut==0) {
|
|
StartT3(linkp); /*stop T1 if no info to send*/
|
|
}
|
|
else anonym->T3out = 65535U;
|
|
}
|
|
else {
|
|
/*WrStrLn("state17"); */
|
|
anonym->State = 1U;
|
|
}
|
|
}
|
|
else if (anonym->State!=5U) {
|
|
/*host died after it started Conn*/
|
|
anonym->State = 1U;
|
|
/*WrStrLn("dispose4"); */
|
|
DisposeLink(linkp, anonym->twoway);
|
|
/*UA in twoway must be a reply of DISC*/
|
|
}
|
|
}
|
|
else if (cmd==0x43U || cmd==0x87U) {
|
|
if (anonym->State!=2U) {
|
|
/*ignor discs while connecting*/
|
|
/*WrStrLn("state18"); */
|
|
anonym->State = 1U;
|
|
ToSendQue(linkp, 0xFU, 1U);
|
|
}
|
|
}
|
|
else if (cmd==0xFU) {
|
|
/*else ignore DISCs and go ahead with SABM*/
|
|
if (compoll==1U) {
|
|
/*WrStrLn("dispose5"); */
|
|
DisposeLink(linkp, 1);
|
|
}
|
|
}
|
|
else if (cmd==0x3U) {
|
|
/*ignore not final*/
|
|
if (compoll==3U && anonym->State==1U) {
|
|
ToSendQue(linkp, 0xFU, 1U);
|
|
}
|
|
}
|
|
else ToSendQue(linkp, 0x87U, 0U);
|
|
}
|
|
else if ((anonym->cCONNtyp==l2_cFLEXback || anonym->cCONNtyp==l2_cCONNAK)
|
|
|| anonym->cCONNtyp==l2_cFLEXbusy) {
|
|
/*
|
|
ELSIF cmd=UI THEN
|
|
IF (State=5) & (dbuf^.len#0) & ((cCONNtyp=cUI)
|
|
OR (cCONNtyp=cUIpoll)) THEN
|
|
IF Alloc(ip,MEMRR) THEN
|
|
Appendrx(dbuf);
|
|
dbuf:=ip;
|
|
END;
|
|
END;
|
|
*/
|
|
/*WrStrLn("uselink back"); */
|
|
if (cmd==0x2FU && compoll==3U) {
|
|
/*only SABM.Poll accepted*/
|
|
Dealloc((char * *) &anonym->SABMinfo);
|
|
/*WrStrLn("dispose15"); */
|
|
DisposeLink(linkp, 1);
|
|
}
|
|
else {
|
|
/*WrStrLn("state1fb"); */
|
|
anonym->State = 1U;
|
|
ToSendQue(linkp, 0xFU, 1U);
|
|
}
|
|
}
|
|
if (slave) {
|
|
PortL2[anonym->Uplinkport-1U].dama = 1;
|
|
if ((cmd&0x1U)!=0U || compoll==3U) {
|
|
/*poll or not info*/
|
|
PortL2[anonym->Uplinkport-1U].dcd = 0;
|
|
PortL2[anonym->Uplinkport-1U].damat1 = 1;
|
|
}
|
|
}
|
|
}
|
|
} /* end Uselink() */
|
|
|
|
#define l2_WILD "T"
|
|
|
|
|
|
static void Mon(uint16_t port, l2_AFIELD adr, uint16_t alen,
|
|
l2_pDATA info)
|
|
{
|
|
uint16_t i;
|
|
l2_pLINK lp;
|
|
struct LINK * anonym;
|
|
if (mfrom[0U]) {
|
|
i = 0U;
|
|
while (i<=5U && (mfrom[i]=='T' || mfrom[i]==adr[i])) ++i;
|
|
if (i<6U) {
|
|
for (i = 0U; i<=5U; i++) {
|
|
if (mfrom[i]!='T' && mfrom[i]!=adr[i+7U]) return;
|
|
} /* end for */
|
|
}
|
|
}
|
|
if (monbufs<maxmonbufs && Alloc((char * *) &lp, 5U)) {
|
|
{ /* with */
|
|
struct LINK * anonym = (struct LINK *)lp;
|
|
memset((char *)lp,(char)0,sizeof(struct LINK)); /*State:=0;
|
|
readp:=0*/
|
|
anonym->rxInfoOut = 0;
|
|
anonym->Magic = 2091827346UL;
|
|
memcpy(anonym->Adress,adr,71u);
|
|
anonym->AdrLen = alen;
|
|
anonym->mycall = (uint16_t)(uint8_t)adr[alen-1U];
|
|
anonym->Uplinkport = port;
|
|
i = 0U; /* axuudp2 info to monitor */
|
|
do {
|
|
anonym->udp2info[i] = l2_udp2buf[i];
|
|
++i;
|
|
} while (!((i>=30U || i>=99U) || l2_udp2buf[i]==0));
|
|
anonym->udp2info[i] = 0;
|
|
if (info && Alloc((char * *) &anonym->rxInfoOut, 0U)) {
|
|
*anonym->rxInfoOut = *info;
|
|
anonym->rxInfoOut->next = 0;
|
|
anonym->rxbuffers = 1U;
|
|
}
|
|
anonym->Hashnext = 0;
|
|
if ((struct LINK *)monBufOut==0) monBufOut = lp;
|
|
else ((struct LINK *)monBufIn)->Hashnext = lp;
|
|
monBufIn = lp;
|
|
++monbufs;
|
|
}
|
|
}
|
|
} /* end Mon() */
|
|
|
|
|
|
extern l2_pLINK l2_GetMon(void)
|
|
{
|
|
l2_pLINK l;
|
|
l2_L2Lock = 1;
|
|
l = monBufOut;
|
|
if ((struct LINK *)monBufOut) {
|
|
monBufOut = ((struct LINK *)monBufOut)->Hashnext;
|
|
--monbufs;
|
|
++hosts;
|
|
}
|
|
Unlock();
|
|
return l;
|
|
} /* end GetMon() */
|
|
|
|
|
|
static void SendBufferd(uint16_t port, uint16_t baud, uint16_t cmd)
|
|
/*send a frame with no link*/
|
|
{
|
|
l2_pLINK linkp;
|
|
struct LINK * anonym;
|
|
/*succeeds only if there is enough memory*/
|
|
if (Alloc((char * *) &linkp, 6U)) {
|
|
memset((char *)linkp,(char)0,sizeof(struct LINK));
|
|
{ /* with */
|
|
struct LINK * anonym = (struct LINK *)linkp;
|
|
anonym->IsInQue = 3U;
|
|
anonym->mycall = 0U; /*dispose link after sending*/
|
|
anonym->Uplinkport = port;
|
|
anonym->State = 1U;
|
|
anonym->Baud = baud;
|
|
anonym->damastop = 0;
|
|
memcpy(anonym->Adress,l2_adress,71u);
|
|
/*useing static address field*/
|
|
anonym->AdrLen = l2_asize;
|
|
if (l2_dbuf->len) {
|
|
anonym->sendinfo = l2_dbuf;
|
|
if (!Alloc((char * *) &l2_dbuf, 5U)) {
|
|
Dealloc((char * *) &linkp); /*so forget it all*/
|
|
}
|
|
}
|
|
else anonym->sendinfo = 0;
|
|
if ((struct LINK *)linkp) ToSendQue(linkp, cmd, 3U);
|
|
}
|
|
}
|
|
} /* end SendBufferd() */
|
|
|
|
|
|
extern void l2_SendRaw(l2_pSENDUI p)
|
|
{
|
|
struct l2_SENDUI * anonym;
|
|
struct l2_DFIELD * anonym0;
|
|
l2_L2Lock = 1;
|
|
{ /* with */
|
|
struct l2_SENDUI * anonym = p;
|
|
if ((anonym->port>0U && anonym->port<=15U)
|
|
&& l2_Parms[anonym->port-1U]._._0.Diversity>0U) {
|
|
l2_asize = 0U;
|
|
while (l2_asize<70U && anonym->path[l2_asize]) {
|
|
l2_adress[l2_asize] = (char)((uint32_t)(uint8_t)
|
|
anonym->path[l2_asize]*2UL+(uint32_t)
|
|
(anonym->path[l2_asize+1U]==0));
|
|
++l2_asize;
|
|
}
|
|
l2_adress[l2_asize] = anonym->cmd;
|
|
++l2_asize;
|
|
{ /* with */
|
|
struct l2_DFIELD * anonym0 = l2_dbuf;
|
|
anonym0->len = anonym->datalen;
|
|
if (anonym0->len>257U) anonym0->len = 257U;
|
|
X2C_MOVE((char *)anonym->data,(char *)anonym0->info,
|
|
(uint32_t)anonym0->len);
|
|
}
|
|
SendBufferd(anonym->port, anonym->baud, 0x8000U);
|
|
}
|
|
}
|
|
Unlock();
|
|
} /* end SendRaw() */
|
|
|
|
|
|
static char Initlink(l2_pLINK * linkp, uint16_t hash,
|
|
uint16_t Uport, uint16_t baud)
|
|
{
|
|
struct l2__D0 * anonym; /*statistics*/
|
|
struct LINK * anonym0;
|
|
if (Alloc((char * *)linkp, 6U)) {
|
|
memset((char *)*linkp,(char)0,sizeof(struct LINK));
|
|
{ /* with */
|
|
struct l2__D0 * anonym = &l2_PortSt[Uport];
|
|
++anonym->Links;
|
|
if (anonym->Links>anonym->MaxLinks) {
|
|
anonym->MaxLinks = anonym->Links;
|
|
}
|
|
}
|
|
{ /* with */
|
|
struct LINK * anonym0 = (struct LINK *)*linkp;
|
|
anonym0->Hash = hash;
|
|
if ((struct LINK *)AdrHash[anonym0->Hash]==0) {
|
|
anonym0->Hashnext = 0; /*append link to hashque*/
|
|
}
|
|
else {
|
|
anonym0->Hashnext = AdrHash[anonym0->Hash];
|
|
((struct LINK *)AdrHash[anonym0->Hash])->Hashprev = *linkp;
|
|
}
|
|
AdrHash[anonym0->Hash] = *linkp;
|
|
anonym0->Baud = baud;
|
|
anonym0->IsInQue = 3U; /*not in sendque*/
|
|
anonym0->Uplinkport = Uport;
|
|
anonym0->pid = '\360';
|
|
anonym0->Started = Time;
|
|
anonym0->T3out = 65535U; /*start T1*/
|
|
StartTimer(*linkp); /*each link has a timer till its disposed*/
|
|
anonym0->haschains = 1;
|
|
}
|
|
return 1;
|
|
}
|
|
return 0;
|
|
} /* end Initlink() */
|
|
|
|
|
|
static void Hashf(uint16_t * hash, uint16_t port)
|
|
{
|
|
uint16_t i;
|
|
*hash = 0U;
|
|
for (i = 0U; i<=5U; i++) {
|
|
*hash += (uint16_t)((uint32_t)(uint8_t)l2_adress[i]+(uint32_t)
|
|
(uint8_t)l2_adress[i+7U]); /*hash function*/
|
|
} /* end for */
|
|
*hash = *hash/2U+port&15U;
|
|
} /* end Hashf() */
|
|
|
|
|
|
static char CallComp(uint16_t p, AFIELDPO adr, uint16_t pp)
|
|
{
|
|
uint16_t i;
|
|
for (i = 5U;; i--) {
|
|
if (l2_adress[p+i]!=adr[pp+i]) return 0;
|
|
if (i==0U) break;
|
|
} /* end for */
|
|
return ((uint16_t)(uint32_t)(uint8_t)l2_adress[p+6U]&0x5EU)
|
|
==((uint16_t)(uint32_t)(uint8_t)adr[pp+6U]&0x5EU);
|
|
} /* end CallComp() */
|
|
|
|
|
|
extern l2_pLINK l2_Connect0(char * mp, l2_pCONNECT p)
|
|
/*NIL if no link*/
|
|
{
|
|
l2_pLINK linkp;
|
|
uint16_t hash;
|
|
l2_pDATA sabmi;
|
|
struct l2_CONNECT * anonym;
|
|
struct l2_DFIELD * anonym0;
|
|
struct LINK * anonym1;
|
|
{ /* with */
|
|
struct l2_CONNECT * anonym = p;
|
|
if ((anonym->port==0U || anonym->port>15U)
|
|
|| l2_Parms[anonym->port-1U]._._0.Diversity==0U) return 0;
|
|
l2_L2Lock = 1;
|
|
l2_asize = 0U; /*uses static adress buffer, so not reentrant*/
|
|
while (l2_asize<70U && anonym->l2adr[l2_asize]) {
|
|
l2_adress[l2_asize] = (char)((uint32_t)(uint8_t)
|
|
anonym->l2adr[l2_asize]*2UL+(uint32_t)
|
|
(anonym->l2adr[l2_asize+1U]==0));
|
|
++l2_asize;
|
|
}
|
|
++l2_asize;
|
|
Hashf(&hash, l2_Parms[anonym->port-1U]._._0.Diversity);
|
|
linkp = AdrHash[hash];
|
|
for (;;) {
|
|
/*look if a link from-to same calls exists*/
|
|
if ((struct LINK *)linkp==0) break;
|
|
if (CallComp(0U, (AFIELDPO)((struct LINK *)linkp)->Adress,
|
|
0U) && CallComp(7U, (AFIELDPO)((struct LINK *)linkp)->Adress,
|
|
7U)) {
|
|
if (anonym->typ==l2_cTEST && ((struct LINK *)linkp)->State>1U) {
|
|
Unlock(); /*link exists*/
|
|
return linkp;
|
|
}
|
|
/*WrStrLn("dispose6"); */
|
|
DisposeLink(linkp, 1); /*and let the old one disappeare*/
|
|
break;
|
|
}
|
|
linkp = ((struct LINK *)linkp)->Hashnext;
|
|
}
|
|
if (anonym->typ==l2_cTEST) {
|
|
Unlock();
|
|
return 0;
|
|
}
|
|
/*extention, SABM with info*/
|
|
sabmi = 0;
|
|
if (anonym->l3adr && anonym->l3adr[0U]) {
|
|
if (Alloc((char * *) &sabmi, 5U)) {
|
|
{ /* with */
|
|
struct l2_DFIELD * anonym0 = sabmi;
|
|
anonym0->len = 0U;
|
|
while (anonym0->len<=256U && anonym->l3adr[anonym0->len]) {
|
|
anonym0->info[anonym0->len] = anonym->l3adr[anonym0->len];
|
|
++anonym0->len;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
Unlock();
|
|
return 0;
|
|
}
|
|
}
|
|
if (Initlink(&linkp, hash, anonym->port,
|
|
(uint16_t)((uint32_t)(uint8_t)
|
|
l2_Parms[anonym->port-1U].SendBauds[0U]-48UL))) {
|
|
{ /* with */
|
|
struct LINK * anonym1 = (struct LINK *)linkp;
|
|
anonym1->mycall = 65535U; /*is a downlink*/
|
|
anonym1->host = mp;
|
|
anonym1->Magic = 2091827346UL;
|
|
anonym1->pid = (char)anonym->cpid;
|
|
anonym1->cCONNtyp = anonym->typ;
|
|
anonym1->State = 2U;
|
|
anonym1->T3out = 65535U; /*start T1*/
|
|
if (anonym->typ==l2_cFLEXback || anonym1->cCONNtyp==l2_cCONNAK) {
|
|
anonym1->flexback = anonym->typ==l2_cFLEXback;
|
|
X2C_CHKPROC(l2_CALLBACKPROC,Event)(&anonym1->host, linkp,
|
|
l2_eCONNECTED);
|
|
StartT3(linkp); /*restart T3*/
|
|
}
|
|
/*link setup*/
|
|
anonym1->SABMinfo = sabmi;
|
|
anonym1->AdrLen = l2_asize;
|
|
memcpy(anonym1->Adress,l2_adress,71u);
|
|
if (l2_Parms[anonym->port-1U].DamaMaster) {
|
|
anonym1->Adress[13U] = (char)((uint16_t)(uint32_t)
|
|
(uint8_t)anonym1->Adress[13U]&~0x20U);
|
|
}
|
|
MakePoll(linkp); /*SABM ...*/
|
|
if (anonym1->host) ++hosts;
|
|
}
|
|
Unlock();
|
|
return linkp;
|
|
}
|
|
else {
|
|
if (sabmi) Dealloc((char * *) &sabmi);
|
|
Unlock();
|
|
return 0;
|
|
}
|
|
}
|
|
return 0;
|
|
} /* end Connect() */
|
|
|
|
|
|
static void CopyCall(l2_pLINK linkp, uint16_t to, uint16_t from)
|
|
/*and clean ssid from additional bits*/
|
|
{
|
|
uint16_t i;
|
|
struct LINK * anonym;
|
|
{ /* with */
|
|
struct LINK * anonym = (struct LINK *)linkp;
|
|
for (i = 0U; i<=5U; i++) {
|
|
anonym->Adress[to+i] = l2_adress[from+i];
|
|
} /* end for */
|
|
anonym->Adress[to+6U] = (char)((uint16_t)(uint32_t)(uint8_t)
|
|
l2_adress[from+6U]&0x7EU);
|
|
}
|
|
} /* end CopyCall() */
|
|
|
|
|
|
static void invertpath(l2_pLINK linkp, char master, char flex)
|
|
{
|
|
uint16_t j;
|
|
uint16_t i;
|
|
struct LINK * anonym;
|
|
CopyCall(linkp, 0U, 7U); /*invert direction*/
|
|
CopyCall(linkp, 7U, 0U);
|
|
{ /* with */
|
|
struct LINK * anonym = (struct LINK *)linkp;
|
|
if (master) {
|
|
anonym->Adress[13U] = (char)((uint16_t)(uint32_t)(uint8_t)
|
|
anonym->Adress[13U]&~0x20U); /*set master bit*/
|
|
}
|
|
i = 14U; /*invert digi-path*/
|
|
j = l2_asize-8U;
|
|
while (j>=14U) {
|
|
CopyCall(linkp, i, j);
|
|
i += 7U;
|
|
j -= 7U;
|
|
}
|
|
if (flex) {
|
|
anonym->Adress[20U] = (char)((uint8_t)(uint8_t)
|
|
anonym->Adress[20U]|0x80U); /* set h-bit for pseudodigi */
|
|
}
|
|
anonym->Adress[i-1U] = (char)((uint32_t)(uint8_t)
|
|
anonym->Adress[i-1U]+1UL); /*set address-end-bit*/
|
|
anonym->AdrLen = i+1U;
|
|
}
|
|
} /* end invertpath() */
|
|
|
|
|
|
static void rx(uint16_t Port)
|
|
/*analyse address-field*/
|
|
{
|
|
uint16_t hash;
|
|
uint16_t j;
|
|
uint16_t i;
|
|
l2_pLINK linkp;
|
|
char poll;
|
|
char v2;
|
|
char sabm;
|
|
char digisdone;
|
|
char isflex;
|
|
struct LINK lh;
|
|
struct l2__D1 * anonym;
|
|
struct LINK * anonym0;
|
|
/*memory avaliable*/
|
|
struct LINK * anonym1;
|
|
/*memory avaliable*/
|
|
struct LINK * anonym2;
|
|
{ /* with */
|
|
struct l2__D1 * anonym = &l2_PortSt[Port].Flows[Minute5];
|
|
anonym->Bytegot = anonym->Bytegot+(uint32_t)l2_asize+(uint32_t)
|
|
l2_dbuf->len+3UL; /* + fcs + 1 flag */
|
|
}
|
|
digisdone = l2_asize<22U || (uint8_t)l2_adress[l2_asize-2U]>=(uint8_t)
|
|
'\200'; /* no digis or last with h-bit */
|
|
v2 = (uint8_t)l2_adress[6U]>=(uint8_t)'\200'==(uint8_t)
|
|
l2_adress[13U]<(uint8_t)'\200';
|
|
poll = CP()==3U;
|
|
sabm = (v2 && poll) && (0xEFU&(uint16_t)(uint32_t)(uint8_t)
|
|
l2_adress[l2_asize-1U])==0x2FU; /* SABM.P v2.0 */
|
|
isflex = (!digisdone && (l2_asize<29U || (uint8_t)
|
|
l2_adress[l2_asize-9U]>=(uint8_t)'\200'))
|
|
&& CallComp(l2_asize-8U, (AFIELDPO)MyCalls[0U], 0U);
|
|
/* min 1 digi & last h-bit not set */
|
|
/* 1 digi or second last h-bit set */
|
|
/* my digi ask host for flexnet link */
|
|
/*first look in existing links*/
|
|
Hashf(&hash, l2_Parms[Port-1U]._._0.Diversity);
|
|
/*WrInt(hash, 10); WrStrLn(":hash "); */
|
|
linkp = AdrHash[hash];
|
|
/*WrInt(CAST(CARDINAL, linkp), 15); WrStrLn(":po "); */
|
|
for (;;) {
|
|
if ((struct LINK *)linkp==0) break;
|
|
{ /* with */
|
|
struct LINK * anonym0 = (struct LINK *)linkp;
|
|
if (CallComp(0U, (AFIELDPO)anonym0->Adress, 7U) && CallComp(7U,
|
|
(AFIELDPO)anonym0->Adress, 0U)) {
|
|
i = 14U;
|
|
j = l2_asize-8U; /*all pseudodigis are compared too*/
|
|
while (((j>=14U && (uint8_t)anonym0->Adress[i+6U]>=(uint8_t)
|
|
'\200') && (uint8_t)l2_adress[j+6U]<(uint8_t)'\200')
|
|
&& CallComp(j, (AFIELDPO)anonym0->Adress, i)) {
|
|
i += 7U;
|
|
j -= 7U;
|
|
}
|
|
if (j<14U || (uint8_t)anonym0->Adress[i+6U]<(uint8_t)
|
|
'\200' && (uint8_t)l2_adress[j+6U]>=(uint8_t)'\200') {
|
|
break;
|
|
}
|
|
}
|
|
linkp = anonym0->Hashnext;
|
|
/*there may be more entries with same hash*/
|
|
}
|
|
}
|
|
if ((struct LINK *)linkp) {
|
|
/*existing link*/
|
|
if (v2) Uselink(linkp);
|
|
}
|
|
else if (digisdone && poll) {
|
|
/* new link */
|
|
i = 1U;
|
|
for (;;) {
|
|
if (MyCalls[i][0U]==0) break;
|
|
if (CallComp(0U, (AFIELDPO)MyCalls[i], 0U) && Initlink(&linkp, hash,
|
|
Port, (uint16_t)((uint32_t)(uint8_t)l2_Parms[Port-1U].SendBauds[i]-48UL))) {
|
|
/*fitting mycall found*/
|
|
{ /* with */
|
|
struct LINK * anonym1 = (struct LINK *)linkp;
|
|
anonym1->mycall = i;
|
|
anonym1->State = 1U;
|
|
invertpath(linkp, l2_Parms[Port-1U].DamaMaster, 0);
|
|
if (sabm) {
|
|
lh = *(struct LINK *)linkp;
|
|
/*WrStrLn("dispose1"); */
|
|
DisposeLink(linkp, 1);
|
|
/* dispose before same flex backlink does it */
|
|
X2C_CHKPROC(l2_CALLBACKPROC,Event)(&anonym1->host,
|
|
(l2_pLINK) &lh, l2_eCONNREQ);
|
|
}
|
|
else {
|
|
/*
|
|
StartT3(linkp);
|
|
(*start with T3*)
|
|
IF sabm THEN Uselink(linkp);
|
|
(*now it is an existing link*)
|
|
*/
|
|
ToSendQue(linkp, 0xFU, 1U);
|
|
/* say DM.F to any poll to mycall */
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
++i;
|
|
}
|
|
}
|
|
else if (isflex) {
|
|
if (Initlink(&linkp, hash, Port, 0U)) {
|
|
{ /* with */
|
|
struct LINK * anonym2 = (struct LINK *)linkp;
|
|
anonym2->mycall = 0U;
|
|
anonym2->State = 1U;
|
|
invertpath(linkp, l2_Parms[Port-1U].DamaMaster, 1);
|
|
lh = *(struct LINK *)linkp;
|
|
/*WrStrLn("dispose1"); */
|
|
DisposeLink(linkp, 1);
|
|
/* dispose before same flex backlink does it */
|
|
if (sabm) {
|
|
X2C_CHKPROC(l2_CALLBACKPROC,Event)(&anonym2->host,
|
|
(l2_pLINK) &lh, l2_eCONNREQ);
|
|
/* call router to make link later */
|
|
}
|
|
else {
|
|
X2C_CHKPROC(l2_CALLBACKPROC,Event)(&anonym2->host,
|
|
(l2_pLINK) &lh, l2_eFLEXDATA);
|
|
/* give router frame to digipeat */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
|
|
(*else if poll bit look for uplinks to a mycall*)
|
|
ELSIF (asize<=15) OR (adress[asize-2]>=200C)
|
|
OR isflex THEN (* no more digis in path or h-bits set *)
|
|
--WrStrLn(" newlink ");
|
|
i:=1;
|
|
LOOP
|
|
IF NOT isflex & (MyCalls[i][0]=0C) THEN EXIT END;
|
|
(*end of mycall-table*)
|
|
|
|
IF isflex OR CallComp(0,ADR(MyCalls[i]),
|
|
0) THEN (*fitting mycall found*)
|
|
IF (CP()=POLL) (*only polls a interesting*)
|
|
& ((adress[6]>=200C)=(adress[13]<200C)) (*is v2*)
|
|
& Initlink(linkp,hash,Port,
|
|
ORD(Parms[Port].SendBauds[i])-ORD("0"))
|
|
THEN (*memory avaliable*)
|
|
WITH linkp^ DO
|
|
mycall:=i;
|
|
IF isflex THEN mycall:=0 END; (* flex *)
|
|
State:=1;
|
|
CopyCall(0,7); (*invert direction*)
|
|
CopyCall(7,0);
|
|
IF Parms[Port].DamaMaster THEN
|
|
Adress[13]:=CAST(CHAR, CAST(SET16, ORD(Adress[13]))-DAMARR);
|
|
(*set master bit*)
|
|
END;
|
|
i:=14; (*invert digi-path*)
|
|
j:=asize-8;
|
|
WHILE j>=14 DO CopyCall(i,j); INC(i,7); DEC(j,7) END;
|
|
IF isflex THEN Adress[20]:=CAST(CHAR, CAST(SET8,
|
|
Adress[20])+SET8{7}) END; (* set h-bit for pseudodigi *)
|
|
Adress[i-1]:=CHR(ORD(Adress[i-1])+1); (*set address-end-bit*)
|
|
AdrLen:=i+1;
|
|
IF isflex THEN
|
|
lh:=linkp^;
|
|
--WrStrLn("dispose1");
|
|
DisposeLink(linkp, TRUE);
|
|
(* dispose before same flex backlink does it *)
|
|
IF flexsabm THEN Event(host, ADR(lh), eCONNREQ)
|
|
ELSE Event(host, ADR(lh), eFLEXDATA) END;
|
|
ELSE
|
|
StartT3(linkp); (*start with T3*)
|
|
Uselink(linkp); (*now it is an existing link*)
|
|
END;
|
|
END;
|
|
END;
|
|
EXIT
|
|
|
|
END;
|
|
INC(i);
|
|
END;
|
|
|
|
(*at least look for digipeating*)
|
|
ELSIF Parms[Port].Digipeat & (asize>=15) THEN
|
|
i:=20;
|
|
LOOP
|
|
IF adress[i]<200C THEN (*no h-bit*)
|
|
IF CallComp(i-6,ADR(MyCalls[0]),0) THEN (*is my digicall*)
|
|
j:=0;
|
|
LOOP
|
|
IF DNot[j][0]=0C THEN (*end of dnot-table*)
|
|
adress[i]:=CHR(ORD(adress[i])+128); (*set h-bit*)
|
|
--WrStrLn("sendbuf");
|
|
SendBufferd(Port,ORD(Parms[Port].SendBauds[0])-ORD("0"),NULL);
|
|
EXIT
|
|
|
|
END;
|
|
k:=0;
|
|
WHILE DNot[j][k]=adress[k+7] DO
|
|
IF k=5 THEN EXIT END;
|
|
|
|
INC(k);
|
|
END;
|
|
INC(j);
|
|
END;
|
|
END;
|
|
EXIT
|
|
|
|
END;
|
|
INC(i,7);
|
|
IF i>asize THEN EXIT END;
|
|
|
|
END;
|
|
END;
|
|
*/
|
|
} /* end rx() */
|
|
|
|
|
|
static void tx(l2_pLINK * SendQueIn, l2_pLINK * SendQueOut)
|
|
{
|
|
l2_pLINK last;
|
|
l2_pDATA sendi;
|
|
char dealloc;
|
|
char isent;
|
|
struct LINK * anonym;
|
|
struct l2_DFIELD * anonym0;
|
|
/*WrStr("[");WrHex(CAST(CARD16,sendcmd), 1);WrStrLn("]"); */
|
|
struct l2__D1 * anonym1;
|
|
struct LINK * anonym2;
|
|
/*WrStrLn("tx"); */
|
|
while ((struct LINK *)*SendQueOut) {
|
|
{ /* with */
|
|
struct LINK * anonym = (struct LINK *)*SendQueOut;
|
|
sendi = 0;
|
|
isent = 0;
|
|
dealloc = 0;
|
|
if (anonym->mycall) {
|
|
if (anonym->State==5U && anonym->sendcmd==0x8000U || (anonym->sendcmd==0x1U && anonym->cp!=1U)
|
|
&& !anonym->busyend) {
|
|
if (anonym->cCONNtyp) {
|
|
if (anonym->sendcmd==0x8000U) {
|
|
sendi = GetSendInfo(*SendQueOut);
|
|
if (sendi) {
|
|
anonym->sendcmd = 0x3U;
|
|
dealloc = 1;
|
|
anonym->txInfoOut = anonym->txInfoOut->next;
|
|
--anonym->txbuffers;
|
|
if (anonym->txfull) TestMem(*SendQueOut);
|
|
}
|
|
}
|
|
else anonym->sendcmd = 0x8000U;
|
|
}
|
|
else if (((((anonym->cp==3U && anonym->sendcmd==0x1U)
|
|
&& anonym->sendinfo)
|
|
&& anonym->sendinfo->len<=l2_Parms[anonym->Uplinkport-1U]
|
|
._._0.IPoll) && !anonym->rembusy) && anonym->retry<=10U) {
|
|
/*& ((ns+9) MOD 8<>highsent)*/
|
|
anonym->sendcmd = (uint16_t)
|
|
(2U*anonym->ns+32U*anonym->nr); /*I.P instead of RR.P*/
|
|
anonym->sentnr = anonym->nr;
|
|
/*only for later check of windowsize*/
|
|
sendi = anonym->sendinfo;
|
|
}
|
|
else {
|
|
/*RR may be sent as I*/
|
|
sendi = GetSendInfo(*SendQueOut);
|
|
if (sendi) {
|
|
/*there is info to send*/
|
|
if (sendi==anonym->txInfoIn) anonym->modifylast = 0;
|
|
++l2_PortSt[anonym->Uplinkport].Flows[Minute5].Isent;
|
|
anonym->SentBytes = anonym->SentBytes+(uint32_t)
|
|
sendi->len;
|
|
if (anonym->sendinfo) anonym->ns = anonym->ns+1U&7U;
|
|
anonym->sendinfo = sendi;
|
|
anonym->sendcmd = (uint16_t)
|
|
(2U*anonym->ns+32U*anonym->nr); /*I-frame*/
|
|
anonym->sentnr = anonym->nr;
|
|
/*only for later check of windowsize*/
|
|
if (l2_Parms[anonym->Uplinkport-1U]
|
|
.DamaMaster && GetSendInfo(*SendQueOut)==0) {
|
|
anonym->cp = 3U;
|
|
anonym->damastop = 1;
|
|
}
|
|
else anonym->cp = 2U;
|
|
if (anonym->ns==anonym->highsent) {
|
|
anonym->highsent = anonym->highsent+1U&7U;
|
|
}
|
|
isent = 1;
|
|
}
|
|
}
|
|
}
|
|
else if (anonym->sendcmd==0x2FU) {
|
|
sendi = anonym->SABMinfo; /*extention, SABM with info*/
|
|
}
|
|
else if (anonym->sendcmd==0x87U) {
|
|
if (Alloc((char * *) &sendi, 1U)) {
|
|
{ /* with */
|
|
struct l2_DFIELD * anonym0 = sendi;
|
|
anonym0->info[0U] = anonym->pid;
|
|
anonym0->info[1U] = 0;
|
|
/*may someone make it correct...*/
|
|
anonym0->info[2U] = (char)anonym->nr;
|
|
anonym0->info[3U] = (char)anonym->ns;
|
|
anonym0->len = 4U;
|
|
}
|
|
dealloc = 1;
|
|
}
|
|
anonym->State = 1U;
|
|
}
|
|
}
|
|
else {
|
|
sendi = anonym->sendinfo;
|
|
dealloc = sendi!=0;
|
|
}
|
|
if (anonym->sendcmd!=0x8000U) {
|
|
if (anonym->sendcmd==0x1U) {
|
|
anonym->sendcmd = (uint16_t)((uint32_t)(uint16_t)
|
|
anonym->sendcmd+4UL*(uint32_t)(anonym->busy!=0U)
|
|
+8UL*(uint32_t)(anonym->rejsent && anonym->busy==0U)
|
|
+(uint32_t)(32U*anonym->nr));
|
|
anonym->sentnr = anonym->nr;
|
|
/*only for later check of windowsize*/
|
|
}
|
|
anonym->Adress[anonym->AdrLen-1U] = (char)((uint32_t)
|
|
(uint16_t)anonym->sendcmd+16UL*(uint32_t)(char)
|
|
(anonym->cp&1)); /*p/f bits*/
|
|
anonym->Adress[6U] = (char)(128UL*(uint32_t)
|
|
(anonym->cp>=2U)+((uint32_t)(uint8_t)
|
|
anonym->Adress[6U]&127UL));
|
|
anonym->Adress[13U] = (char)(128UL*(uint32_t)
|
|
(anonym->cp<2U)+((uint32_t)(uint8_t)
|
|
anonym->Adress[13U]&127UL));
|
|
}
|
|
if (anonym->mycall==0U || anonym->sendcmd!=0x8000U) {
|
|
frameio_SendFrame((uint32_t)
|
|
l2_Parms[anonym->Uplinkport-1U]._._0.SendPort,
|
|
(uint32_t)anonym->Baud, anonym->Adress, 71ul,
|
|
(uint32_t)anonym->AdrLen, sendi);
|
|
/*WrStr("F:"); */
|
|
/*IF sendi<>NIL THEN WrInt(sendi^.len,1) END; */
|
|
{ /* with */
|
|
struct l2__D1 * anonym1 = &l2_PortSt[anonym->Uplinkport]
|
|
.Flows[Minute5];
|
|
anonym1->Bytesent = anonym1->Bytesent+(uint32_t)
|
|
anonym->AdrLen+3UL; /* + fcs and 1 flag*/
|
|
if (sendi) {
|
|
anonym1->Bytesent = anonym1->Bytesent+(uint32_t)
|
|
sendi->len;
|
|
}
|
|
}
|
|
if (l2_Parms[anonym->Uplinkport-1U].monitor) {
|
|
Mon(l2_Parms[anonym->Uplinkport-1U]._._0.SendPort,
|
|
anonym->Adress, anonym->AdrLen, sendi);
|
|
}
|
|
}
|
|
if (dealloc) Dealloc((char * *) &sendi);
|
|
anonym->IsInQue = 3U;
|
|
last = *SendQueOut;
|
|
if ((struct LINK *)*SendQueOut==(struct LINK *)*SendQueIn) {
|
|
*SendQueOut = 0; /*remove link from sendque*/
|
|
}
|
|
else *SendQueOut = ((struct LINK *)*SendQueOut)->SendQuenext;
|
|
}
|
|
{ /* with */
|
|
struct LINK * anonym2 = (struct LINK *)last;
|
|
if (!anonym2->haschains) {
|
|
Dealloc((char * *) &last);
|
|
/*simple dealloc, there are no chains*/
|
|
}
|
|
else {
|
|
anonym2->sendcmd = 0x4000U;
|
|
if (anonym2->State==5U) {
|
|
if (GetSendInfo(last)==0) {
|
|
/*no more info to send*/
|
|
if (isent) {
|
|
/*but info sended*/
|
|
RemoveTimer(last);
|
|
anonym2->T3out = 65535U; /*so restart T1*/
|
|
StartTimer(last);
|
|
}
|
|
/*infostop:=Parms[Uplinkport].HalfDuplex;*/
|
|
anonym2->damastop = l2_Parms[anonym2->Uplinkport-1U]
|
|
.DamaMaster;
|
|
}
|
|
else {
|
|
ToSendQue(last, 0x8000U, 2U);
|
|
/*reschedule for more I-frames*/
|
|
}
|
|
}
|
|
else if (anonym2->State<=1U) DisposeLink(last, 0);
|
|
}
|
|
}
|
|
}
|
|
} /* end tx() */
|
|
|
|
|
|
static void inctime(void)
|
|
{
|
|
/* make always forward going time */
|
|
uint32_t t;
|
|
uint32_t i;
|
|
t = osic_time();
|
|
if (AbsTime!=t) {
|
|
AbsTime = t;
|
|
++Time;
|
|
Minute5 = Minut5();
|
|
if (ticker5!=Minute5) {
|
|
/*clear next statistics intervall*/
|
|
ticker5 = Minute5;
|
|
for (i = 1UL; i<=15UL; i++) {
|
|
memset((char *) &l2_PortSt[i].Flows[Minute5],(char)0,
|
|
sizeof(struct l2__D1));
|
|
} /* end for */
|
|
}
|
|
}
|
|
++tick10;
|
|
if (tick10%10UL==0UL) Second = (Second+1U)%20000U;
|
|
} /* end inctime() */
|
|
|
|
/*
|
|
PROCEDURE Layer2; (*started by ticker*)
|
|
VAR port,i:CARD16;
|
|
norx:BOOLEAN;
|
|
BEGIN
|
|
(*
|
|
IF LostINT>5 THEN LostINT:=5 END;
|
|
(*IF NOT L2Lock THEN
|
|
L2Lock:=TRUE; *) (*L2-interrupt must not be reentered!*)
|
|
*)
|
|
norx:=FALSE;
|
|
REPEAT
|
|
FOR port:=1 TO PORTS DO
|
|
WITH Parms[port] DO
|
|
WITH PortL2[port] DO
|
|
IF Diversity<>0 THEN (*port is enabled*)
|
|
|
|
IF HalfDuplex THEN
|
|
IF dama THEN
|
|
IF dcd THEN
|
|
IF dcdguard<DCDIGNOR THEN INC(dcdguard)
|
|
ELSE dama:=FALSE END;
|
|
ELSE dcdguard:=0 END;
|
|
ELSIF DCD(port) THEN
|
|
IF dcdguard<DCDIGNOR THEN
|
|
PortL2[Diversity].dcd:=TRUE;
|
|
INC(dcdguard);
|
|
END;
|
|
ELSE dcdguard:=0 END;
|
|
END;
|
|
IF GetFrame(port) THEN
|
|
IF monitor & (crcok OR passall) THEN Mon(port,adress,asize,
|
|
dbuf) END;
|
|
IF crcok THEN
|
|
IF MhTime<>0 THEN MH(port,adress,asize) END;
|
|
IF PortL2[SendPort].sendstate=TWAIT THEN PortL2[SendPort]
|
|
.txwait:=0 END;
|
|
|
|
rx(Diversity);
|
|
|
|
(*dcdguard:=0;*)
|
|
END;
|
|
ELSE norx:=TRUE END;
|
|
|
|
END;
|
|
|
|
IF Diversity=port THEN (*this ports has a sender*)
|
|
IF DamaMaster THEN
|
|
|
|
IF (T1Out<>NIL) & NOT dcd & (PortL2[SendPort].txwait=0) THEN
|
|
Timeout(T1Out);
|
|
END;
|
|
ELSIF Ticker<>Second THEN
|
|
IF (NOT HalfDuplex OR (PortL2[SendPort].txwait=0)
|
|
& (NOT dcd OR damat1)) THEN (*timer is running*)
|
|
|
|
IF (T1Out=NIL) OR (T1Out^.T1out<>QTicker) THEN
|
|
QTicker:=(QTicker+1) MOD SECMOD;
|
|
(*no timer in this second*)
|
|
ELSE Timeout(T1Out) END;
|
|
IF damat1 & (Ticker=Second) THEN damat1:=FALSE END;
|
|
END;
|
|
Ticker:=Second;
|
|
END;
|
|
|
|
IF txwait<>0 THEN
|
|
IF (sendstate=TXDEL) OR NOT Sending(port) THEN DEC(txwait)
|
|
END;
|
|
IF txwait=0 THEN
|
|
IF sendstate=TXDEL THEN txwait:=TXtail; sendstate:=TXTAIL;
|
|
ELSIF (sendstate=TXTAIL) OR (sendstate=ECHO) THEN
|
|
-- StopFlags(port);
|
|
IF HalfDuplex THEN
|
|
txwait:=TXwait;
|
|
(*
|
|
IF T3count=0 THEN (*so restart T1*)
|
|
RemoveTimer(last);
|
|
StartTimer(last);
|
|
END;
|
|
*)
|
|
END;
|
|
sendstate:=TWAIT;
|
|
ELSE sendstate:=TWAIT END;
|
|
END;
|
|
|
|
END;
|
|
|
|
|
|
IF dcd & (PortL2[SendPort].sendstate<>TXTAIL) THEN
|
|
dcd:=dama;
|
|
IF ((sendstate=TWAIT) OR (sendstate=DCDWAIT))
|
|
& (txwait<=1) & (DCDwait<>0) & NOT dama THEN
|
|
IF NOT DamaMaster THEN
|
|
txwait:=((DCDwait*(tick10 MOD 256)) DIV 256)+2;
|
|
-- txwait:=DCDwait;
|
|
END;
|
|
sendstate:=DCDWAIT;
|
|
END;
|
|
|
|
ELSIF lookinque THEN (*maybe sendque has an entry*)
|
|
WITH PortL2[SendPort] DO
|
|
IF (sendstate=TXTAIL) OR (txwait=0) THEN
|
|
i:=0;
|
|
LOOP
|
|
WITH PortL2[port].SendQues[i] DO
|
|
IF (SendQueOut<>NIL) THEN
|
|
IF (sendstate=TWAIT) & (TXdel<>0) THEN
|
|
-- StartFlags(Parms[port].SendPort,
|
|
SendQueOut^.Baud);
|
|
txwait:=TXdel;
|
|
sendstate:=TXDEL;
|
|
EXIT
|
|
|
|
END;
|
|
tx(SendQueIn,SendQueOut);
|
|
txwait:=TXtail;
|
|
IF SendQueOut<>NIL THEN EXIT END;
|
|
(*sendbuffer is full*)
|
|
|
|
END;
|
|
END;
|
|
INC(i); (*next sendque*)
|
|
IF i>=SENDQUES THEN PortL2[port].lookinque:=FALSE;
|
|
EXIT END;
|
|
|
|
END;
|
|
END;
|
|
END;
|
|
ELSIF dama THEN dcd:=TRUE END;
|
|
END;
|
|
END;
|
|
END;
|
|
END;
|
|
|
|
inctime;
|
|
(*
|
|
IF LostINT=0 THEN EXIT END;
|
|
|
|
DEC(LostINT);
|
|
EXIT;
|
|
*)
|
|
|
|
|
|
UNTIL norx;
|
|
(* L2Lock:=FALSE;
|
|
END; *)
|
|
END Layer2;
|
|
*/
|
|
|
|
extern void l2_Layer2(void)
|
|
{
|
|
/*started by ticker*/
|
|
uint16_t i;
|
|
uint16_t port;
|
|
char test1;
|
|
char norx;
|
|
struct l2__D2 * anonym;
|
|
struct _0 * anonym0;
|
|
struct _1 * anonym1;
|
|
norx = 0;
|
|
do {
|
|
for (port = 1U; port<=15U; port++) {
|
|
{ /* with */
|
|
struct l2__D2 * anonym = &l2_Parms[port-1U];
|
|
{ /* with */
|
|
struct _0 * anonym0 = &PortL2[port-1U];
|
|
if (anonym->_._0.Diversity) {
|
|
/*port is enabled*/
|
|
test1 = PortL2[anonym->_._0.Diversity-1U].dcd;
|
|
PortL2[anonym->_._0.Diversity-1U].dcd = 0;
|
|
if (anonym->HalfDuplex && frameio_DCD((uint32_t)port)) {
|
|
if (anonym0->dcdguard<anonym->_._0.DCDIGNOR) {
|
|
PortL2[anonym->_._0.Diversity-1U].dcd = 1;
|
|
++anonym0->dcdguard;
|
|
}
|
|
}
|
|
else anonym0->dcdguard = 0U;
|
|
/*IF PortL2[Diversity].dcd<>test1 THEN WrStr("d");
|
|
WrInt(ORD(PortL2[Diversity].dcd),1) END; */
|
|
if (frameio_GetFrame((uint32_t)port)) {
|
|
/*WrStr("R"); */
|
|
if (anonym->monitor && (frameio_crcok || anonym->passall)
|
|
) Mon(port, l2_adress, l2_asize, l2_dbuf);
|
|
if (frameio_crcok) {
|
|
if (PortL2[anonym->_._0.SendPort-1U]
|
|
.sendstate==l2_TWAIT) {
|
|
PortL2[anonym->_._0.SendPort-1U].txwait = 0U;
|
|
}
|
|
rx(anonym->_._0.Diversity);
|
|
}
|
|
}
|
|
else norx = 1;
|
|
}
|
|
if (anonym->_._0.Diversity==port) {
|
|
/*this ports has a sender*/
|
|
if (anonym0->Ticker!=Second) {
|
|
if (!(PortL2[anonym->_._0.Diversity-1U]
|
|
.dcd || frameio_Sending((uint32_t)port))) {
|
|
/*timer is running*/
|
|
if ((struct LINK *)
|
|
anonym0->T1Out==0 || ((struct LINK *)anonym0->T1Out)
|
|
->T1out!=anonym0->QTicker) {
|
|
anonym0->QTicker = (anonym0->QTicker+1U)%20000U;
|
|
/*no timer in this second*/
|
|
}
|
|
else Timeout(anonym0->T1Out);
|
|
}
|
|
anonym0->Ticker = Second;
|
|
}
|
|
if (!PortL2[anonym->_._0.Diversity-1U].dcd) {
|
|
i = 0U;
|
|
for (;;) {
|
|
{ /* with */
|
|
struct _1 * anonym1 = &PortL2[anonym->_._0.SendPort-1U]
|
|
.SendQues[i];
|
|
if ((struct LINK *)anonym1->SendQueOut) {
|
|
/*WrStr("T"); */
|
|
tx(&anonym1->SendQueIn, &anonym1->SendQueOut);
|
|
if ((struct LINK *)anonym1->SendQueOut) {
|
|
break; /*sendbuffer is full*/
|
|
}
|
|
}
|
|
}
|
|
++i; /*next sendque*/
|
|
if (i>=3U) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} /* end for */
|
|
inctime();
|
|
} while (!norx);
|
|
} /* end Layer2() */
|
|
|
|
|
|
extern void l2_L2Init(uint16_t bufs, uint16_t portset,
|
|
l2_CALLBACKPROC callback)
|
|
{
|
|
uint16_t j;
|
|
uint16_t i;
|
|
struct l2__D2 * anonym;
|
|
struct _0 * anonym0;
|
|
/* init with default parameters */
|
|
Event = callback;
|
|
hosts = 0U;
|
|
monbufs = 0U;
|
|
monBufOut = 0;
|
|
memset((char *)MyCalls,(char)0,119UL);
|
|
memset((char *)DNot,(char)0,63UL);
|
|
mfrom[0U] = 0;
|
|
maxrxbuffers = bufs/10U;
|
|
maxtxbuffers = 30U;
|
|
maxmonbufs = bufs/5U;
|
|
QTIME = 48U;
|
|
DMTIME = 60U;
|
|
DAMAMAXTIME = 15U;
|
|
DAMAFASTPOLLS = 4U;
|
|
l2_L2Lock = 0;
|
|
l2_LostINT = 0U;
|
|
for (i = 0U; i<=15U; i++) {
|
|
AdrHash[i] = 0;
|
|
} /* end for */
|
|
Time = 0UL;
|
|
AbsTime = 0UL;
|
|
Second = 0U;
|
|
Minute5 = 0U;
|
|
memory = 0U;
|
|
Freechain = 0;
|
|
i = (uint16_t)sizeof(struct l2_DFIELD);
|
|
if (sizeof(struct LINK)>(uint32_t)i) {
|
|
i = (uint16_t)sizeof(struct LINK);
|
|
}
|
|
for (;;) {
|
|
osic_alloc((char * *) &l2_dbuf, (uint32_t)i);
|
|
if (memory>=bufs) break;
|
|
Dealloc((char * *) &l2_dbuf);
|
|
}
|
|
/*WrInt(SIZE(dbuf^), 10); WrInt(SIZE(monBufOut^), 10); WrStrLn(" d,l"); */
|
|
for (i = 1U; i<=15U; i++) {
|
|
{ /* with */
|
|
struct l2__D2 * anonym = &l2_Parms[i-1U];
|
|
memset((char *) &l2_Parms[i-1U],(char)0,
|
|
sizeof(struct l2__D2));
|
|
/*defaults*/
|
|
anonym->_._0.T1 = 20U;
|
|
anonym->_._0.T3 = 1800U;
|
|
anonym->_._0.BaudSwBytes = 5U;
|
|
anonym->_._0.TXdel = 20U; /* 25 */
|
|
anonym->_._0.txDelByte = 126U;
|
|
anonym->_._0.TXwait = 2U; /* 80 */
|
|
anonym->_._0.TXtail = 1U; /* 3 */
|
|
anonym->_._0.DCDwait = 2U;
|
|
anonym->_._0.DCDlevel = 27000U;
|
|
anonym->_._0.SendPort = i;
|
|
/* IF (i>=8) & (i<12) THEN Diversity:=i; END;*/
|
|
if (X2C_IN((int32_t)i,16,portset)) anonym->_._0.Diversity = i;
|
|
anonym->_._0.Retries = 25U;
|
|
anonym->HalfDuplex = 1;
|
|
anonym->DamaMaster = 0;
|
|
anonym->_._0.MaxFrames = 7U;
|
|
anonym->_._0.IPoll = 80U;
|
|
anonym->_._0.MhTime = 0U;
|
|
anonym->monitor = 0;
|
|
anonym->Digipeat = 1;
|
|
strncpy(anonym->SendBauds,"222222222",17u);
|
|
anonym->passall = 0;
|
|
anonym->_._0.DCDIGNOR = 6000U; /* 6000 */
|
|
}
|
|
/* MODEMPOLL:=500; */
|
|
{ /* with */
|
|
struct _0 * anonym0 = &PortL2[i-1U];
|
|
memset((char *) &PortL2[i-1U],(char)0,sizeof(struct _0));
|
|
anonym0->Ticker = 0U;
|
|
anonym0->QTicker = 0U;
|
|
anonym0->txwait = 0U;
|
|
anonym0->sendstate = l2_TWAIT;
|
|
anonym0->T1Out = 0;
|
|
anonym0->damaloop = 0;
|
|
for (j = 0U; j<=2U; j++) {
|
|
anonym0->SendQues[j].SendQueOut = 0;
|
|
} /* end for */
|
|
}
|
|
CheckParms(i);
|
|
} /* end for */
|
|
memset((char *)l2_PortSt,(char)0,sizeof(struct l2__D0 [16]));
|
|
frameio_Init();
|
|
} /* end L2Init() */
|
|
|
|
|
|
extern void l2_BEGIN(void)
|
|
{
|
|
static int l2_init = 0;
|
|
if (l2_init) return;
|
|
l2_init = 1;
|
|
if (sizeof(uint16_t)!=2) X2C_ASSERT(0);
|
|
if (sizeof(uint8_t)!=1) X2C_ASSERT(0);
|
|
if (sizeof(l2_CALLTYP)!=7) X2C_ASSERT(0);
|
|
if (sizeof(l2_AFIELD)!=71) X2C_ASSERT(0);
|
|
if (sizeof(l2_SUMMS)!=28) X2C_ASSERT(0);
|
|
osi_BEGIN();
|
|
frameio_BEGIN();
|
|
}
|
|
|