linbpq/cMain.c

2784 lines
60 KiB
C

/*
Copyright 2001-2022 John Wiseman G8BPQ
This file is part of LinBPQ/BPQ32.
LinBPQ/BPQ32 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
LinBPQ/BPQ32 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
*/
//
// C replacement for Main.asm
//
#define Kernel
#define _CRT_SECURE_NO_DEPRECATE
#pragma data_seg("_BPQDATA")
//#include "windows.h"
//#include "winerror.h"
#include "time.h"
#include "stdio.h"
#include <fcntl.h>
#include "kernelresource.h"
#include "CHeaders.h"
#include "tncinfo.h"
#include "mqtt.h"
VOID L2Routine(struct PORTCONTROL * PORT, PMESSAGE Buffer);
VOID ProcessIframe(struct _LINKTABLE * LINK, PDATAMESSAGE Buffer);
VOID FindLostBuffers();
VOID ReadMH();
void GetPortCTEXT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct CMDX * CMD);
int upnpInit();
void AISTimer();
void ADSBTimer();
VOID SendSmartID(struct PORTCONTROL * PORT);
int CanPortDigi(int Port);
int KissEncode(UCHAR * inbuff, UCHAR * outbuff, int len);
void MQTTTimer();
void SaveMH();
#include "configstructs.h"
extern struct CONFIGTABLE xxcfg;
extern BOOL needAIS;
extern int needADSB;
struct PORTCONFIG * PortRec;
#define RNRSET 0x2 // RNR RECEIVED FROM OTHER END
// STATION INFORMATION
char DATABASESTART[14] = "";
char xMAJORVERSION = 4;
char xMINORVERSION = 9;
char FILLER1[16] = "";
struct ROUTE * NEIGHBOURS = NULL;
int ROUTE_LEN = sizeof(struct ROUTE);
int MAXNEIGHBOURS = 20;
struct DEST_LIST * DESTS = NULL; // NODE LIST
int DEST_LIST_LEN = sizeof(struct DEST_LIST);
struct _LINKTABLE * LINKS = NULL;
int LINK_TABLE_LEN = sizeof (struct _LINKTABLE);
int MAXLINKS = 30;
char MYCALL[7] = ""; // DB 7 DUP (0) ; NODE CALLSIGN (BIT SHIFTED)
char MYALIASTEXT[6] = ""; // DB ' ' ; NODE ALIAS (KEEP TOGETHER)
char MYALIASLOPPED[10];
char MYCALLLOPPED[10];
UCHAR MYCALLWITHALIAS[13] = "";
UCHAR NETROMCALL[7] = ""; // Call used for NETROM (can be MYCALL)
APPLCALLS APPLCALLTABLE[NumberofAppls] = {0};
UCHAR MYNODECALL[10] = ""; // NODE CALLSIGN (ASCII)
UCHAR MYNETROMCALL[10] = ""; // NETROM CALLSIGN (ASCII)
char NODECALLLOPPED[10];
VOID * FREE_Q = NULL;
time_t TimeLoaded = 0;
struct PORTCONTROL * PORTTABLE = NULL;
int NUMBEROFPORTS = 0;
int PORTENTRYLEN = sizeof(struct PORTCONTROL);
struct DEST_LIST * ENDDESTLIST = NULL; // ; NODE LIST+1
;
VOID * BUFFERPOOL = NULL; // START OF BUFFER POOL
VOID * ENDBUFFERPOOL = NULL;
int OBSINIT = 5; // INITIAL OBSOLESCENCE VALUE
int OBSMIN = 4; // MINIMUM TO BROADCAST
int L3INTERVAL = 60; // 'NODES' INTERVAL IN MINS
int IDINTERVAL = 20; // 'ID' BROADCAST INTERVAL
int BTINTERVAL = 20; // 'BT' BROADCAST INTERVAL
int MINQUAL = 10; // MIN QUALITY FOR AUTOUPDATES
int HIDENODES = 0; // N * COMMAND SWITCH
int BBSQUAL = 255; // QUALITY OF BBS RELATIVE TO NODE
int NUMBEROFBUFFERS = 999; // PACKET BUFFERS
int PACLEN = 100; //MAX PACKET SIZE
// L2 SYSTEM TIMER RUNS AT 3 HZ
int T3 = 3*61*3; // LINK VALIDATION TIMER (3 MINS) (+ a bit to reduce RR collisions)
int L2KILLTIME = 16*60*3; // IDLE LINK TIMER (16 MINS)
int L3LIVES = 15; // MAX L3 HOPS
int L4N2 = 3; // LEVEL 4 RETRY COUNT
int L4LIMIT = 60*15; // IDLE SESSION LIMIT - 15 MINS
int L4DELAY = 5; // L4 DELAYED ACK TIMER
int BBS = 1; // INCLUDE BBS SUPPORT
int NODE = 1; // INCLUDE SWITCH SUPPORT
int FULL_CTEXT = 1; // CTEXT ON ALL CONNECTS IF NZ
BOOL LogL4Connects = FALSE;
BOOL LogAllConnects = FALSE;
BOOL AUTOSAVEMH = TRUE;
extern BOOL ADIFLogEnabled;
extern UCHAR LogDirectory[260];
extern BOOL EventsEnabled;
extern BOOL SaveAPRSMsgs;
BOOL M0LTEMap = FALSE;
BOOL MQTT = FALSE;
char MQTT_HOST[80] = "";
int MQTT_PORT = 0;
char MQTT_USER[80] = "";
char MQTT_PASS[80] = "";
int MQTT_Connecting = 0;
int MQTT_Connected = 0;
//TNCTABLE DD 0
//NUMBEROFSTREAMS DD 0
extern VOID * ENDPOOL;
extern void * APPL_Q; // Queue of frames for APRS Appl
extern BOOL APRSActive;
#define BPQHOSTSTREAMS 64
// Although externally streams are numbered 1 to 64, internally offsets are 0 - 63
BPQVECSTRUC XDUMMY = {0}; // Needed to force correct order of following
BPQVECSTRUC BPQHOSTVECTOR[BPQHOSTSTREAMS + 5] = {0};
BPQVECSTRUC * TELNETMONVECPTR = &BPQHOSTVECTOR[BPQHOSTSTREAMS];
BPQVECSTRUC * AGWMONVECPTR = &BPQHOSTVECTOR[BPQHOSTSTREAMS + 1];
BPQVECSTRUC * APRSMONVECPTR = &BPQHOSTVECTOR[BPQHOSTSTREAMS + 2];
BPQVECSTRUC * IPHOSTVECTORPTR = &BPQHOSTVECTOR[BPQHOSTSTREAMS + 3];
int BPQVECLENGTH = sizeof(BPQVECSTRUC);
int NODEORDER = 0;
UCHAR LINKEDFLAG = 0;
UCHAR UNPROTOCALL[80] = "";
UCHAR ExcludeList[71] = ""; // 10 ENTRIES, 7 BYTES EACH
char * INFOMSG = NULL;
char * CTEXTMSG = NULL;
int CTEXTLEN = 0;
UCHAR MYALIAS[7] = ""; // ALIAS IN AX25 FORM
UCHAR BBSALIAS[7] = "";
UCHAR AX25CALL[7] = ""; // WORK AREA FOR AX25 <> NORMAL CALL CONVERSION
UCHAR NORMCALL[10] = ""; // CALLSIGN IN NORMAL FORMAT
int NORMLEN = 0; // LENGTH OF CALL IN NORMCALL
int CURRENTPORT = 0; // PORT FOR CURRENT MESSAGE
VOID * CURRENTPORTPTR = NULL; // PORT CONTROL TABLE ENTRY FOR CURRENT PORT
int SDCBYTE = 0; // CONTROL BYTE FOR CURRENT FRAME
VOID * BUFFER = NULL; // GENERAL SAVE AREA FOR BUFFER ADDR
VOID * ADJBUFFER = NULL; // BASE ADJUSED FOR DIGIS
UCHAR TEMPFIELD[7] = ""; // ADDRESS WORK FILED
void * TRACE_Q = NULL; // TRANSMITTED FRAMES TO BE TRACED
int RANDOM = 0; // 'RANDOM' NUMBER FOR PERSISTENCE CALCS
int L2TIMERFLAG = 0; // INCREMENTED AT 18HZ BY TIMER INTERRUPT
int L3TIMERFLAG = 0; // DITTO
int L4TIMERFLAG = 0; // DITTO
char HEADERCHAR = '}'; // CHAR FOR _NODE HEADER MSGS
VOID * LASTPOINTER = NULL; // PERVIOUS _NODE DURING CHAINING
int REALTIMETICKS = 0;
int BGTIMER = 0; // TO CONTROL BG SCANS
VOID * CONFIGPTR = NULL; // Internal Config Get Offset
int AUTOSAVE = 0; // AUTO SAVE NODES ON EXIT FLAG
int L4APPL = 1; // Application for BBSCALL/ALIAS connects
int CFLAG = 0; // C =HOST Command
VOID * IDMSG_Q = NULL; // ID/BEACONS WAITING TO BE SENT
int NODESINPROGRESS = 0;
VOID * CURRENTNODE = NULL; // NEXT _NODE TO SEND
VOID * DESTHEADER = NULL; // HEAD OF SORTED NODES CHAIN
int L3TIMER = 1; // TIMER FOR 'NODES' MESSAGE
int IDTIMER = 0; // TIMER FOR ID MESSAGE
int BTTIMER = 0; // TIMER FOR BT MESSAGE
UCHAR * NEXTFREEDATA = NULL; // ADDRESS OF NEXT FREE BYTE of shared memory
int NEEDMH = 0;
struct DATAMESSAGE BTHDDR = {0,0,9,240,13};
struct _MESSAGE IDHDDR = {0,0,23,0,0,3, 240};
VOID * IDMSG = &IDHDDR;
//DD 0 ; CHAIN
// DB 0 ; PORT
int BTLENGTH = 9; // DW 9 ; LENGTH
// DB 0F0H ; PID
char BTEXTFLD[256] ="\r";
char BridgeMap[MaxBPQPortNo + 1][MaxBPQPortNo + 1] = {0};
// Keep Buffers at end
#define DATABYTES 600000 // WAS 320000
UCHAR DATAAREA[DATABYTES] = "";
void ** Bufferlist[1000] = {0};
extern BOOL IPRequired;
extern BOOL PMRequired;
extern int MaxHops;
extern int MAXRTT;
extern USHORT CWTABLE[];
extern struct _TRANSPORTENTRY * L4TABLE;
extern UCHAR ROUTEQUAL;
extern UINT BPQMsg;
extern int NUMBEROFTNCPORTS;
extern APPLCALLS APPLCALLTABLE[];
// LOOPBACK PORT ROUTINES
VOID LINKINIT(PEXTPORTDATA PORTVEC)
{
WritetoConsoleLocal("Loopback\n");
}
VOID LINKTX(PEXTPORTDATA PORTVEC, PMESSAGE Buffer)
{
// LOOP BACK TO SWITCH
struct _LINKTABLE * LINK;
LINK = Buffer->Linkptr;
if (LINK)
{
if (LINK->L2TIMER)
LINK->L2TIMER = LINK->L2TIME;
Buffer->Linkptr = 0; // CLEAR FLAG FROM BUFFER
}
C_Q_ADD(&PORTVEC->PORTCONTROL.PORTRX_Q, Buffer);
}
VOID LINKRX()
{
}
VOID LINKTIMER()
{
}
VOID LINKCLOSE()
{
}
VOID EXTCLOSE()
{
}
BOOL KISSTXCHECK()
{
return 0;
}
BOOL LINKTXCHECK()
{
return 0;
}
void * Dummy(int fn, int port, PDATAMESSAGE buff) // Dummy for missing EXT Driver
{
return 0;
}
VOID EXTINIT(PEXTPORTDATA PORTVEC)
{
// LOAD DLL - NAME IS IN PORT_DLL_NAME
void *(* Startup) (PEXTPORTDATA PORTVEC); // ADDR OF Startup ROUTINE
PORTVEC->PORT_EXT_ADDR = Dummy;
Startup = InitializeExtDriver(PORTVEC);
if (Startup == 0)
{
WritetoConsoleLocal("Driver installation failed\n");
return;
}
// CALL THE ROUTINE TO START IT UP
// Startup returns address of processing routine
PORTVEC->PORT_EXT_ADDR = (void *(__cdecl *)(int,int,PDATAMESSAGE))Startup(PORTVEC);;
if (PORTVEC->PORT_EXT_ADDR == 0)
{
WritetoConsoleLocal("Driver Initialisation failed\n");
return;
}
}
VOID EXTTX(PEXTPORTDATA PORTVEC, MESSAGE * Buffer)
{
struct _LINKTABLE * LINK;
struct PORTCONTROL * PORT = (struct PORTCONTROL *)PORTVEC;
// RESET TIMER, unless BAYCOM
if (PORT->KISSFLAGS == 255) // Used for BAYCOM
{
PORTVEC->PORT_EXT_ADDR(2, PORT->PORTNUMBER, (PDATAMESSAGE)Buffer);
return; // Baycom driver passes frames to trace once sent
}
LINK = Buffer->Linkptr;
if (LINK)
{
if (LINK->L2TIMER)
LINK->L2TIMER = LINK->L2TIME;
if (PORT->TNC == 0 || PORT->TNC->Hardware != H_KISSHF)
Buffer->Linkptr = 0; // CLEAR FLAG FROM BUFFER
}
PORTVEC->PORT_EXT_ADDR(2, PORT->PORTNUMBER, (PDATAMESSAGE)Buffer);
if (PORT->PROTOCOL == 10 && PORT->TNC && PORT->TNC->Hardware != H_KISSHF)
{
ReleaseBuffer(Buffer);
return;
}
C_Q_ADD(&TRACE_Q, Buffer);
return;
}
VOID EXTRX(PEXTPORTDATA PORTVEC)
{
struct _MESSAGE * Message;
size_t Len;
struct PORTCONTROL * PORT = (struct PORTCONTROL *)PORTVEC;
Loop:
if (QCOUNT < 10)
return;
Message = GetBuff();
if (Message == NULL)
return;
Len = (size_t)PORTVEC->PORT_EXT_ADDR(1, PORT->PORTNUMBER, (PDATAMESSAGE)Message);
if (Len == 0)
{
ReleaseBuffer((UINT *)Message);
return;
}
if (PORT->PROTOCOL == 10)
{
// PACTOR Style Port - Negative values used to report events - for now -1 = Disconnected
if (Len == -1)
{
int Sessno = Message->PORT;
TRANSPORTENTRY * Session;
ReleaseBuffer((UINT *)Message);
// GET RID OF ANY SESSION ENTRIES
Session = PORTVEC->ATTACHEDSESSIONS[Sessno];
if (Session)
{
struct TNCINFO * TNC = PORTVEC->PORTCONTROL.TNC;
CloseSessionPartner(Session);
// is this the place to run DisconnectScript?
if (TNC->DisconnectScript)
{
int n = 0;
struct DATAMESSAGE * Buffer;
TRANSPORTENTRY Session = {0}; // = TNC->PortRecord->ATTACHEDSESSIONS[Sessno];
while (TNC->DisconnectScript[n])
{
Buffer = GetBuff();
if (Buffer)
{
Session.Secure_Session = 1;
Session.CIRCUITINDEX = -1;
Buffer->LENGTH = sprintf(Buffer->L2DATA, "%s\r", TNC->DisconnectScript[n++]) + (sizeof(void *) + 4);
CommandHandler(&Session, Buffer);
};
}
}
PORTVEC->ATTACHEDSESSIONS[Sessno] = NULL;
}
return;
}
}
C_Q_ADD(&PORT->PORTRX_Q, (UINT *)Message);
goto Loop;
return;
}
VOID EXTTIMER(PEXTPORTDATA PORTVEC)
{
// USED TO SEND A RE-INIT IN THE CORRECT PROCESS
if (PORTVEC->EXTRESTART)
{
PORTVEC->EXTRESTART = 0; //CLEAR
PORTVEC->PORT_EXT_ADDR(4, PORTVEC->PORTCONTROL.PORTNUMBER, 0);
}
PORTVEC->PORT_EXT_ADDR(7, PORTVEC->PORTCONTROL.PORTNUMBER, 0); // Timer Routine
}
VOID EXTSLOWTIMER(PEXTPORTDATA PORTVEC)
{
PORTVEC->PORT_EXT_ADDR(8, PORTVEC->PORTCONTROL.PORTNUMBER, 0); // Timer Routine
}
size_t EXTTXCHECK(PEXTPORTDATA PORTVEC, int Chan)
{
uintptr_t Temp = Chan;
return (size_t)PORTVEC->PORT_EXT_ADDR(3, PORTVEC->PORTCONTROL.PORTNUMBER, (void *)Temp);
}
VOID PostDataAvailable(TRANSPORTENTRY * Session)
{
#ifndef LINBPQ
if (Session->L4CIRCUITTYPE & BPQHOST)
{
BPQVECSTRUC * HostSess = Session->L4TARGET.HOST;
if (HostSess)
{
if (HostSess->HOSTHANDLE)
{
PostMessage(HostSess->HOSTHANDLE, BPQMsg, HostSess->HOSTSTREAM, 2);
}
}
}
#endif
}
VOID PostStateChange(TRANSPORTENTRY * Session)
{
#ifndef LINBPQ
if (Session->L4CIRCUITTYPE & BPQHOST)
{
BPQVECSTRUC * HostSess = Session->L4TARGET.HOST;
if (HostSess)
{
if (HostSess->HOSTHANDLE);
{
PostMessage(HostSess->HOSTHANDLE, BPQMsg, HostSess->HOSTSTREAM, 4);
}
}
}
#endif
}
#ifdef LINBPQ
#define HDLCTX KHDLCTX
#define HDLCRX KHDLCRX
#define HDLCTIMER KHDLCTIMER
#define HDLCCLOSE KHDLCCLOSE
#define HDLCTXCHECK KHDLCTXCHECK
#define PC120INIT KHDLCINIT
#define DRSIINIT KHDLCINIT
#define TOSHINIT KHDLCINIT
#define RLC100INIT KHDLCINIT
#define BAYCOMINIT KHDLCINIT
#define PA0INIT KHDLCINIT
int KHDLCINIT(PHDLCDATA PORTVEC);
void KHDLCTX(struct KISSINFO * KISS, PMESSAGE Buffer);
int KHDLCRX(PHDLCDATA PORTVEC);
void KHDLCTIMER(PHDLCDATA PORTVEC);
void KHDLCCLOSE(PHDLCDATA PORTVEC);
BOOL KHDLCTXCHECK();
#else
extern VOID PC120INIT(), DRSIINIT(), TOSHINIT();
extern VOID RLC100INIT(), BAYCOMINIT(), PA0INIT();
extern VOID HDLCTX();
extern VOID HDLCRX();
extern VOID HDLCTIMER();
extern VOID HDLCCLOSE();
extern VOID HDLCTXCHECK();
#endif
extern VOID KISSINIT(), KISSTX(), KISSRX(), KISSTIMER(), KISSCLOSE();
extern VOID EXTINIT(PEXTPORTDATA PORTVEC), EXTTX(PEXTPORTDATA PORTVEC, MESSAGE * Buffer), LINKRX(), EXTRX(PEXTPORTDATA PORTVEC);
extern VOID LINKCLOSE(), EXTCLOSE() ,LINKTIMER(), EXTTIMER(PEXTPORTDATA PORTVEC);
// VECTORS TO HARDWARE DEPENDENT ROUTINES
VOID * INITCODE[12] = {KISSINIT, PC120INIT, DRSIINIT, TOSHINIT, KISSINIT,
RLC100INIT, RLC100INIT, LINKINIT, EXTINIT, BAYCOMINIT, PA0INIT, KISSINIT};
VOID * TXCODE[12] = {KISSTX, HDLCTX, HDLCTX, HDLCTX, KISSTX,
HDLCTX, HDLCTX, LINKTX, EXTTX, HDLCTX, HDLCTX, KISSTX};
VOID * RXCODE[12] = {KISSRX, HDLCRX, HDLCRX, HDLCRX, KISSRX,
HDLCRX, HDLCRX, LINKRX, EXTRX, HDLCRX, HDLCRX, KISSRX};
VOID * TIMERCODE[12] = {KISSTIMER, HDLCTIMER, HDLCTIMER, HDLCTIMER, KISSTIMER,
HDLCTIMER, HDLCTIMER, LINKTIMER, EXTTIMER, HDLCTIMER, HDLCTIMER, KISSTIMER};
VOID * CLOSECODE[12] = {KISSCLOSE, HDLCCLOSE, HDLCCLOSE, HDLCCLOSE, KISSCLOSE,
HDLCCLOSE, HDLCCLOSE, LINKCLOSE, EXTCLOSE, HDLCCLOSE, HDLCCLOSE, KISSCLOSE};
VOID * TXCHECKCODE[12] = {KISSTXCHECK, HDLCTXCHECK, HDLCTXCHECK, HDLCTXCHECK, KISSTXCHECK,
HDLCTXCHECK, HDLCTXCHECK, LINKTXCHECK, EXTTXCHECK, HDLCTXCHECK, HDLCTXCHECK, KISSTXCHECK};
extern int BACKGROUND();
extern int L2TimerProc();
extern int L3TimerProc();
extern int L4TimerProc();
extern int L3FastTimer();
extern int StatsTimer();
extern int COMMANDHANDLER();
VOID SDETX(struct _LINKTABLE * LINK);
extern int L4BG();
extern int L3BG();
extern int TNCTimerProc();
extern int PROCESSIFRAME();
int xxxxx = MAXDATA;
BOOL Start()
{
struct CONFIGTABLE * cfg = &xxcfg;
struct APPLCONFIG * ptr1;
struct PORTCONTROL * PORT;
struct FULLPORTDATA * FULLPORT; // Including HW Data
struct FULLPORTDATA * NEXTPORT; // Including HW Data
struct _EXTPORTDATA * EXTPORT;
APPLCALLS * APPL;
struct ROUTE * ROUTE;
struct DEST_LIST * DEST;
struct CMDX * CMD;
int PortSlot = 1;
uintptr_t int3;
unsigned char * ptr2 = 0, * ptr3, * ptr4;
USHORT * CWPTR;
int i, n;
struct ROUTECONFIG * Rcfg;
NEXTFREEDATA = &DATAAREA[0]; // For Reinit
memset(DATAAREA, 0, DATABYTES);
// Reinit everything in case of restart
FREE_Q = 0;
TRACE_Q = 0;
IDMSG_Q = 0;
NUMBEROFPORTS = 0;
MAXBUFFS = 0;
QCOUNT = 0;
NUMBEROFNODES = 0;
DESTHEADER = 0;
NODESINPROGRESS = 0;
CURRENTNODE = 0;
L3TIMER = 1; // SEND NODES
if (cfg->C_NODEALIAS[0] == 0)
memset(cfg->C_NODEALIAS, ' ', 10);
TimeLoaded = time(NULL);
AUTOSAVE = cfg->C_AUTOSAVE;
if (cfg->C_L4APPL)
L4APPL = cfg->C_L4APPL;
CFLAG = cfg->C_C;
IPRequired = cfg->C_IP;
PMRequired = cfg->C_PM;
if (cfg->C_MAXHOPS)
MaxHops = cfg->C_MAXHOPS;
if (cfg->C_MAXRTT)
MAXRTT = cfg->C_MAXRTT * 100;
if (cfg->C_NODE == 0 && cfg->C_BBS)
{
// USE BBS CALL FOR NODE if Set, otherwise find first APPLCALL
// Unless BBS also = 0
if (cfg->C_BBSCALL[0])
{
memcpy(MYNODECALL, cfg->C_BBSCALL, 10);
memcpy(MYALIASTEXT, cfg->C_BBSALIAS, 6);
memcpy(MYALIASLOPPED, cfg->C_BBSALIAS, 10);
}
else
{
ptr1 = &cfg->C_APPL[0];
for (i = 0; i < NumberofAppls; i++)
{
if (ptr1->ApplCall[0] != ' ')
{
memcpy(MYNODECALL, &ptr1->ApplCall[0], 10);
memcpy(MYALIASTEXT, &ptr1->ApplAlias, 6);
memcpy(MYALIASLOPPED, &ptr1->ApplAlias, 10);
break;
}
ptr1++;
}
}
}
else
{
memcpy(MYNODECALL, cfg->C_NODECALL, 10);
memcpy(MYALIASTEXT, cfg->C_NODEALIAS, 6);
memcpy(MYALIASLOPPED, cfg->C_NODEALIAS, 10);
}
strlop(MYALIASLOPPED, ' ');
// IF NO BBS, SET BOTH TO _NODE CALLSIGN
if (cfg->C_BBS == 0)
{
memcpy(APPLCALLTABLE[0].APPLCALL_TEXT, cfg->C_NODECALL, 10);
memcpy(APPLCALLTABLE[0].APPLALIAS_TEXT, cfg->C_NODEALIAS, 10);
}
else
{
memcpy(APPLCALLTABLE[0].APPLCALL_TEXT, cfg->C_BBSCALL, 10);
memcpy(APPLCALLTABLE[0].APPLALIAS_TEXT, cfg->C_BBSALIAS, 10 );
}
BBSQUAL = cfg->C_BBSQUAL;
// copy MYCALL to NETROMCALL
memcpy(MYNETROMCALL, MYNODECALL, 10);
// if NETROMCALL Defined, use it
if (cfg->C_NETROMCALL[0] && cfg->C_NETROMCALL[0] != ' ')
memcpy(MYNETROMCALL, cfg->C_NETROMCALL, 10);
strlop(MYNETROMCALL, ' ');
strlop(MYNODECALL, ' ');
memcpy(NODECALLLOPPED, MYNODECALL, 10);
strlop(NODECALLLOPPED, ' ');
APPLCALLTABLE[0].APPLQUAL = BBSQUAL;
if (cfg->C_WASUNPROTO == 0 && cfg->C_BTEXT)
{
char * ptr1 = &cfg->C_BTEXT[0];
char * ptr2 = BTHDDR.L2DATA;
int len = 120;
BTHDDR.LENGTH = 1; // PID
while ((*ptr1) && len--)
{
*(ptr2++) = *(ptr1++);
BTHDDR.LENGTH ++;
}
}
OBSINIT = cfg->C_OBSINIT;
OBSMIN = cfg->C_OBSMIN;
L3INTERVAL = cfg->C_NODESINTERVAL;
IDINTERVAL = cfg->C_IDINTERVAL;
if (IDINTERVAL)
IDTIMER = 2;
BTINTERVAL = cfg->C_BTINTERVAL;
if (BTINTERVAL)
BTTIMER = 2;
MINQUAL = cfg->C_MINQUAL;
FULL_CTEXT = cfg->C_FULLCTEXT;
L3LIVES = cfg->C_L3TIMETOLIVE;
L4N2 = cfg->C_L4RETRIES;
L4DEFAULTWINDOW = cfg->C_L4WINDOW;
L4T1 = cfg->C_L4TIMEOUT;
// MOV AX,C_BUFFERS
// MOV NUMBEROFBUFFERS,AX
PACLEN = cfg->C_PACLEN;
T3 = cfg->C_T3 * 3;
L4LIMIT = cfg->C_IDLETIME;
if (L4LIMIT && L4LIMIT < 120)
L4LIMIT = 120; // Don't allow stupidly low
L2KILLTIME = L4LIMIT * 3;
L4DELAY = cfg->C_L4DELAY;
BBS = cfg->C_BBS;
NODE = cfg->C_NODE;
LINKEDFLAG = cfg->C_LINKEDFLAG;
MAXLINKS = cfg->C_MAXLINKS;
MAXDESTS = cfg->C_MAXDESTS;
MAXNEIGHBOURS = cfg->C_MAXNEIGHBOURS;
MAXCIRCUITS = cfg->C_MAXCIRCUITS;
HIDENODES = cfg->C_HIDENODES;
LogL4Connects = cfg->C_LogL4Connects;
LogAllConnects = cfg->C_LogAllConnects;
AUTOSAVEMH = cfg->C_SaveMH;
ADIFLogEnabled = cfg->C_ADIF;
EventsEnabled = cfg->C_EVENTS;
SaveAPRSMsgs = cfg->C_SaveAPRSMsgs;
M0LTEMap = cfg->C_M0LTEMap;
MQTT = cfg->C_MQTT;
strcpy(MQTT_HOST, cfg->C_MQTT_HOST);
MQTT_PORT = cfg->C_MQTT_PORT;
strcpy(MQTT_USER, cfg->C_MQTT_USER);
strcpy(MQTT_PASS, cfg->C_MQTT_PASS);
// Get pointers to PASSWORD and APPL1 commands
// int APPL1 = 0;
//int PASSCMD = 0;
CMD = &COMMANDS[0];
n = 0;
for (n = 0; n < NUMBEROFCOMMANDS; n++)
{
if (APPL1 == 0 && CMD->String[0] == '*') // First appl
{
APPLS = (char *)CMD;
APPL1 = n;
}
if (PASSCMD == 0 && memcmp(CMD->String, "PASSWORD", 8) == 0)
PASSCMD = n;
CMD++;
}
// SET UP APPLICATION LIST
memset(&CMDALIAS[0][0], ' ', NumberofAppls * ALIASLEN );
ptr1 = (struct APPLCONFIG *)&xxcfg.C_APPL[0];
ptr3 = &CMDALIAS[0][0];
for (i = 0; i < NumberofAppls; i++)
{
if (ptr1->Command[0] != ' ')
{
ptr2 = (char *)&COMMANDS[APPL1 + i];
memcpy(ptr2, ptr1, 12);
// See if an Alias
if (ptr1->CommandAlias[0] != ' ')
memcpy(ptr3, ptr1->CommandAlias, ALIASLEN);
// SET LENGTH FIELD
*(ptr2 + 12) = 0; // LENGTH
ptr4 = ptr2;
while (*(ptr4) > 32)
{
ptr4++;
*(ptr2 + 12) = *(ptr2 + 12) + 1;
}
}
ptr1 ++;
ptr2 += CMDXLEN;
ptr3 += ALIASLEN;
}
// Set up Exclude List
memcpy(ExcludeList, cfg->C_EXCLUDE, 71);
// SET UP PORT TABLE
PortRec = &cfg->C_PORT[0];// (struct PORTCONFIG *)ptr2;
PORTTABLE = (VOID *)NEXTFREEDATA;
FULLPORT = (struct FULLPORTDATA *)PORTTABLE;
while (PortRec->PORTNUM)
{
// SET UP NEXT PORT PTR
PORT = &FULLPORT->PORTCONTROL;
NEXTPORT = FULLPORT;
NEXTPORT++;
PORT->PORTPOINTER = (struct PORTCONTROL *)NEXTPORT;
PORT->PORTNUMBER = (UCHAR)PortRec->PORTNUM;
PORT->PortSlot = PortSlot++;
memcpy(PORT->PORTDESCRIPTION, PortRec->ID, 30);
PORT->PORTTYPE = (char)PortRec->TYPE;
PORT->PORTINITCODE = INITCODE[PORT->PORTTYPE / 2]; // ADDR OF INIT ROUTINE
PORT->PORTTXROUTINE = TXCODE[PORT->PORTTYPE / 2]; // ADDR OF INIT ROUTINE
PORT->PORTRXROUTINE = RXCODE[PORT->PORTTYPE / 2]; // ADDR OF INIT ROUTINE
PORT->PORTTIMERCODE = TIMERCODE[PORT->PORTTYPE / 2]; // ADDR OF INIT ROUTINE
PORT->PORTCLOSECODE = CLOSECODE[PORT->PORTTYPE / 2]; // ADDR OF INIT ROUTINE
PORT->PORTTXCHECKCODE = TXCHECKCODE[PORT->PORTTYPE / 2]; // ADDR OF INIT ROUTINE
PORT->PROTOCOL = (char)PortRec->PROTOCOL;
PORT->IOBASE = PortRec->IOADDR;
if (PortRec->SerialPortName && PortRec->SerialPortName[0])
PORT->SerialPortName = _strdup(PortRec->SerialPortName);
else
{
if (PORT->IOBASE > 0 && PORT->IOBASE < 256)
{
char Name[80];
#ifndef WIN32
sprintf(Name, "com%d", PORT->IOBASE);
#else
sprintf(Name, "COM%d", PORT->IOBASE);
#endif
PORT->SerialPortName = _strdup(Name);
}
else
PORT->SerialPortName = _strdup("NOPORT");
}
PORT->INTLEVEL = (char)PortRec->INTLEVEL;
PORT->BAUDRATE = PortRec->SPEED;
if (PORT->BAUDRATE == 49664)
PORT->BAUDRATE = (int)115200;
PORT->CHANNELNUM = (char)PortRec->CHANNEL;
PORT->PORTQUALITY = (UCHAR)PortRec->QUALITY;
PORT->NormalizeQuality = !PortRec->NoNormalize;
PORT->IgnoreUnlocked = PortRec->IGNOREUNLOCKED;
PORT->INP3ONLY = PortRec->INP3ONLY;
PORT->PORTWINDOW = (UCHAR)PortRec->MAXFRAME;
if (PortRec->PROTOCOL == 0 || PORT->PORTTYPE == 22) // KISS or I2C
PORT->PORTTXDELAY = PortRec->TXDELAY /10;
else
PORT->PORTTXDELAY = PortRec->TXDELAY;
if (PortRec->PROTOCOL == 0 || PORT->PORTTYPE == 22) // KISS or I2C
PORT->PORTSLOTTIME = (UCHAR)PortRec->SLOTTIME / 10;
else
PORT->PORTSLOTTIME = (UCHAR)PortRec->SLOTTIME;
PORT->PORTPERSISTANCE = (UCHAR)PortRec->PERSIST;
PORT->FULLDUPLEX = (UCHAR)PortRec->FULLDUP;
PORT->SOFTDCDFLAG = (UCHAR)PortRec->SOFTDCD;
PORT->PORTT1 = PortRec->FRACK / 333;
PORT->PORTT2 = PortRec->RESPTIME /333;
PORT->PORTN2 = (UCHAR)PortRec->RETRIES;
PORT->PORTPACLEN = (UCHAR)PortRec->PACLEN;
PORT->QUAL_ADJUST = (UCHAR)PortRec->QUALADJUST;
PORT->DIGIFLAG = PortRec->DIGIFLAG;
if (PortRec->DIGIPORT && CanPortDigi(PortRec->DIGIPORT))
PORT->DIGIPORT = PortRec->DIGIPORT;
PORT->DIGIMASK = PortRec->DIGIMASK;
PORT->USERS = (UCHAR)PortRec->USERS;
// PORTTAILTIME - if KISS, set a default, and cnvert to ticks
if (PORT->PORTTYPE == 0)
{
if (PortRec->TXTAIL)
PORT->PORTTAILTIME = PortRec->TXTAIL / 10;
else
PORT->PORTTAILTIME = 3; // 10ths
}
else
//; ON HDLC, TAIL TIMER IS USED TO HOLD RTS FOR 'CONTROLLED FULL DUP' - Val in seconds
PORT->PORTTAILTIME = (UCHAR)PortRec->TXTAIL;
PORT->PORTBBSFLAG = (char)PortRec->ALIAS_IS_BBS;
PORT->PORTL3FLAG = (char)PortRec->L3ONLY;
PORT->KISSFLAGS = PortRec->KISSOPTIONS;
PORT->PORTINTERLOCK = (UCHAR)PortRec->INTERLOCK;
PORT->NODESPACLEN = (UCHAR)PortRec->NODESPACLEN;
PORT->TXPORT = (UCHAR)PortRec->TXPORT;
PORT->PORTMINQUAL = PortRec->MINQUAL;
if (PortRec->MAXDIGIS)
PORT->PORTMAXDIGIS = PortRec->MAXDIGIS;
else
PORT->PORTMAXDIGIS = 8;
PORT->PortNoKeepAlive = PortRec->DefaultNoKeepAlives;
PORT->PortUIONLY = PortRec->UIONLY;
PORT->TXPORT = (UCHAR)PortRec->TXPORT;
// SET UP CWID
if (PortRec->CWIDTYPE == 'o')
PORT->CWTYPE = 'O';
else
PORT->CWTYPE = PortRec->CWIDTYPE;
ptr2 = &PortRec->CWID[0];
CWPTR = &PORT->CWID[0];
PORT->CWIDTIMER = (29 - PORT->PORTNUMBER) * 600; // TICKSPERMINUTE
PORT->CWPOINTER = &PORT->CWID[0];
for (i = 0; i < 8; i++) // MAX ID LENGTH
{
char c = *(ptr2++);
if (c < 32)
break;
if (c > 'Z')
continue;
c -= '/'; // Table stats at /
c &= 127;
*(CWPTR) = CWTABLE[c];
CWPTR++;
}
// SEE IF LINK CALLSIGN/ALIAS SPECIFIED
if (PortRec->PORTCALL[0])
ConvToAX25(PortRec->PORTCALL, PORT->PORTCALL);
if (PortRec->PORTALIAS[0])
ConvToAX25(PortRec->PORTALIAS, PORT->PORTALIAS);
if (PortRec->PORTALIAS2[0])
ConvToAX25(PortRec->PORTALIAS2, PORT->PORTALIAS2);
if (PortRec->DLLNAME[0])
{
EXTPORT = (struct _EXTPORTDATA *)PORT;
memcpy(EXTPORT->PORT_DLL_NAME, PortRec->DLLNAME, 16);
}
if (PortRec->BCALL[0])
ConvToAX25(PortRec->BCALL, PORT->PORTBCALL);
PORT->XDIGIS = PortRec->XDIGIS; // Crossband digi aliases
memcpy(&PORT->PORTIPADDR, &PortRec->IPADDR, 4);
PORT->ListenPort = PortRec->ListenPort;
if (PortRec->TCPPORT)
{
PORT->KISSTCP = TRUE;
PORT->IOBASE = PortRec->TCPPORT;
if (PortRec->IPADDR == 0)
PORT->KISSSLAVE = TRUE;
}
if (PortRec->WL2K)
memcpy(&PORT->WL2KInfo, PortRec->WL2K, sizeof(struct WL2KInfo));
PORT->RIGPort = PortRec->RIGPORT;
if (PortRec->HavePermittedAppls)
PORT->PERMITTEDAPPLS = PortRec->PERMITTEDAPPLS;
else
PORT->PERMITTEDAPPLS = 0xffffffff; // Default to all
PORT->Hide = PortRec->Hide;
PORT->SmartIDInterval = PortRec->SmartID;
if (PortRec->KissParams && (PORT->PORTTYPE == 0 || PORT->PORTTYPE == 22))
{
struct KISSINFO * KISS = (struct KISSINFO *)PORT;
UCHAR KissString[128];
int KissLen = 0;
unsigned char * Kissptr = KissString;
char * ptr;
char * Context;
ptr = strtok_s(PortRec->KissParams, " ", &Context);
while (ptr && ptr[0] && KissLen < 120)
{
*(Kissptr++) = atoi (ptr);
KissLen++;
ptr = strtok_s(NULL, " ", &Context);
}
KISS->KISSCMD = malloc(256);
KISS->KISSCMDLEN = KissEncode(KissString, KISS->KISSCMD, KissLen);
KISS->KISSCMD = realloc(KISS->KISSCMD, KISS->KISSCMDLEN);
}
PORT->SendtoM0LTEMap = PortRec->SendtoM0LTEMap;
PORT->PortFreq = PortRec->PortFreq;
PORT->M0LTEMapInfo = PortRec->M0LTEMapInfo;
PORT->QtSMPort = PortRec->QtSMPort;
if (PortRec->BBSFLAG) // Appl 1 not permitted - BBSFLAG=NOBBS
PORT->PERMITTEDAPPLS &= 0xfffffffe; // Clear bottom bit
// SEE IF PERMITTED LINK CALLSIGNS SPECIFIED
ptr2 = &PortRec->VALIDCALLS[0];
if (*(ptr2))
{
ptr3 = (char *)PORT->PORTPOINTER; // Permitted Calls follows Port Info
PORT->PERMITTEDCALLS = ptr3;
while (*(ptr2) > 32)
{
ConvToAX25(ptr2, ptr3);
ptr3 += 7;
PORT->PORTPOINTER = (struct PORTCONTROL *)ptr3;
if (strchr(ptr2, ','))
{
ptr2 = strchr(ptr2, ',');
ptr2++;
}
else
break;
}
ptr3 ++; // Terminating NULL
// Round to word boundary (for ARM5 etc)
int3 = (uintptr_t)ptr3;
int3 += 7;
int3 &= 0xfffffffffffffff8;
ptr3 = (UCHAR *)int3;
PORT->PORTPOINTER = (struct PORTCONTROL *)ptr3;
}
// SEE IF PORT UNPROTO ADDR SPECIFIED
ptr2 = &PortRec->UNPROTO[0];
if (*(ptr2))
{
ptr3 = (char *)PORT->PORTPOINTER; // Unproto follows port info
PORT->PORTUNPROTO = ptr3;
while (*(ptr2) > 32)
{
ConvToAX25(ptr2, ptr3);
ptr3 += 7;
PORT->PORTPOINTER = (struct PORTCONTROL *)ptr3;
if (strchr(ptr2, ','))
{
ptr2 = strchr(ptr2, ',');
ptr2++;
}
else
break;
}
ptr3 ++; // Terminating NULL
// Round to word boundsaty (for ARM5 etc)
int3 = (uintptr_t)ptr3;
int3 += 7;
int3 &= 0xfffffffffffffff8;
ptr3 = (UCHAR *)int3;
PORT->PORTPOINTER = (struct PORTCONTROL *)ptr3;
}
// ADD MH AREA IF NEEDED
if (PortRec->MHEARD != 'N')
{
NEEDMH = 1; // Include MH in Command List
ptr3 = (char *)PORT->PORTPOINTER; // Permitted Calls follows Port Info
PORT->PORTMHEARD = (PMHSTRUC)ptr3;
ptr3 += (MHENTRIES + 1)* sizeof(MHSTRUC);
// Round to word boundsaty (for ARM5 etc)
int3 = (uintptr_t)ptr3;
int3 += 7;
int3 &= 0xfffffffffffffff8;
ptr3 = (UCHAR *)int3;
PORT->PORTPOINTER = (struct PORTCONTROL *)ptr3;
}
PortRec++;
NUMBEROFPORTS ++;
FULLPORT = (struct FULLPORTDATA *)PORT->PORTPOINTER;
}
PORT->PORTPOINTER = NULL; // End of list
NEXTFREEDATA = (UCHAR *)FULLPORT;
// SET UP APPLICATION CALLS AND ALIASES
APPL = &APPLCALLTABLE[0];
ptr1 = (struct APPLCONFIG *)&xxcfg.C_APPL[0];
i = NumberofAppls;
if (ptr1->ApplCall[0] == ' ')
{
// APPL1CALL IS NOT SPECIFED - LEAVE VALUES SET FROM BBSCALL
APPL++;
ptr1++;
i--;
}
while (i)
{
memcpy(APPL->APPLCALL_TEXT, ptr1->ApplCall, 10);
ConvToAX25(APPL->APPLCALL_TEXT, APPL->APPLCALL);
memcpy(APPL->APPLALIAS_TEXT, ptr1->ApplAlias, 10);
ConvToAX25(APPL->APPLALIAS_TEXT, APPL->APPLALIAS);
ConvToAX25(ptr1->L2Alias, APPL->L2ALIAS);
memcpy(APPL->APPLCMD, ptr1->Command, 12);
APPL->APPLQUAL = ptr1->ApplQual;
if (ptr1->CommandAlias[0] != ' ')
{
APPL->APPLHASALIAS = 1;
memcpy(APPL->APPLALIASVAL, &ptr1->CommandAlias[0], 48);
}
APPL++;
ptr1++;
i--;
}
// SET UP VARIOUS CONTROL TABLES
LINKS = (VOID *)NEXTFREEDATA;
NEXTFREEDATA += MAXLINKS * sizeof(struct _LINKTABLE);
DESTS = (VOID *)NEXTFREEDATA;
NEXTFREEDATA += MAXDESTS * sizeof(struct DEST_LIST);
ENDDESTLIST = (VOID *)NEXTFREEDATA;
NEIGHBOURS = (VOID *)NEXTFREEDATA;
NEXTFREEDATA += MAXNEIGHBOURS * sizeof(struct ROUTE);
L4TABLE = (VOID *)NEXTFREEDATA;
NEXTFREEDATA += MAXCIRCUITS * sizeof(TRANSPORTENTRY);
// SET UP DEFAULT ROUTES LIST
Rcfg = &cfg->C_ROUTE[0];
ROUTE = NEIGHBOURS;
while (Rcfg->call[0])
{
int FRACK;
char * VIA;
char axcall[8];
ConvToAX25(Rcfg->call, ROUTE->NEIGHBOUR_CALL);
// if VIA convert digis
VIA = strstr(Rcfg->call, "VIA");
if (VIA)
{
VIA += 4;
if (ConvToAX25(VIA, axcall))
{
memcpy(ROUTE->NEIGHBOUR_DIGI1, axcall, 7);
VIA = strchr(VIA, ' ');
if (VIA)
{
VIA++;
if (ConvToAX25(VIA, axcall))
memcpy(ROUTE->NEIGHBOUR_DIGI2, axcall, 7);
}
}
}
ROUTE->NEIGHBOUR_QUAL = Rcfg->quality;
ROUTE->NEIGHBOUR_PORT = Rcfg->port;
PORT = GetPortTableEntryFromPortNum(ROUTE->NEIGHBOUR_PORT);
if (Rcfg->pwind & 0x40)
ROUTE->NoKeepAlive = 1;
else
if (PORT != NULL)
ROUTE->NoKeepAlive = PORT->PortNoKeepAlive;
if (Rcfg->pwind & 0x80 || (PORT && PORT->INP3ONLY))
{
ROUTE->INP3Node = 1;
ROUTE->NoKeepAlive = 0; // Cant have INP3 and NOKEEPALIVES
}
ROUTE->NBOUR_MAXFRAME = Rcfg->pwind & 0x3f;
FRACK = Rcfg->pfrack;
ROUTE->NBOUR_FRACK = FRACK / 333;
ROUTE->NBOUR_PACLEN = Rcfg->ppacl;
ROUTE->OtherendsRouteQual = ROUTE->OtherendLocked = Rcfg->farQual;
ROUTE->NEIGHBOUR_FLAG = 1; // Locked
Rcfg++;
ROUTE++;
}
// SET UP INFO MESSAGE
ptr2 = &cfg->C_INFOMSG[0];
ptr3 = NEXTFREEDATA;
INFOMSG = ptr3;
while ((*ptr2))
{
*(ptr3++) = *(ptr2++);
}
*ptr3++ = 0; // Null Terminate
NEXTFREEDATA = ptr3;
// SET UP CTEXT MESSAGE
ptr2 = &cfg->C_CTEXT[0];
ptr3 = NEXTFREEDATA;
CTEXTMSG = ptr3;
while ((*ptr2))
{
*(ptr3++) = *(ptr2++);
}
CTEXTLEN = (int)(ptr3 - (unsigned char *)CTEXTMSG);
NEXTFREEDATA = ptr3;
// SET UP ID MESSAGE
IDHDDR.DEST[0] = 'I'+'I';
IDHDDR.DEST[1] = 'D'+'D';
IDHDDR.DEST[2] = 0x40;
IDHDDR.DEST[3] = 0x40;
IDHDDR.DEST[4] = 0x40;
IDHDDR.DEST[5] = 0x40;
IDHDDR.DEST[6] = 0xe0; // ; ID IN AX25 FORM
IDHDDR.CTL = 3;
IDHDDR.PID = 0xf0;
ptr2 = &cfg->C_IDMSG[0];
ptr3 = &IDHDDR.L2DATA[0];
while ((*ptr2))
{
*(ptr3++) = *(ptr2++);
}
IDHDDR.LENGTH = (int)(ptr3 - (unsigned char *)&IDHDDR);
int3 = (uintptr_t)NEXTFREEDATA;
int3 += 7;
int3 &= 0xfffffffffffffff8;
NEXTFREEDATA = (UCHAR *)int3;
ENDBUFFERPOOL = NEXTFREEDATA + DATABYTES; // So init will work, set to actual end later
BUFFERPOOL = NEXTFREEDATA;
Consoleprintf("PORTS %p LINKS %p DESTS %p ROUTES %p L4 %p BUFFERS %p\n",
PORTTABLE, LINKS, DESTS, NEIGHBOURS, L4TABLE, BUFFERPOOL);
Debugprintf("PORTS %p LINKS %p DESTS %p ROUTES %p L4 %p BUFFERS %p END POOL %p",
PORTTABLE, LINKS, DESTS, NEIGHBOURS, L4TABLE, BUFFERPOOL, DATAAREA + DATABYTES);
i = NUMBEROFBUFFERS;
NUMBEROFBUFFERS = 0;
while (i-- && NEXTFREEDATA < (DATAAREA + DATABYTES - (512 + 8192))) // Keep 8K free for anything that needs shared memory
{
Bufferlist[NUMBEROFBUFFERS] = (void **)NEXTFREEDATA;
ReleaseBuffer((UINT *)NEXTFREEDATA);
NEXTFREEDATA += BUFFALLOC; // was BUFFLEN
NUMBEROFBUFFERS++;
MAXBUFFS++;
}
ENDBUFFERPOOL = NEXTFREEDATA;
// Copy Bridge Map
memcpy(BridgeMap, &cfg->CfgBridgeMap, sizeof(BridgeMap));
// MOV EAX,_NEXTFREEDATA
// CALL HEXOUT
// SET UP OUR CALLIGN(S)
ConvToAX25(MYNETROMCALL, NETROMCALL);
ConvToAX25(MYNODECALL, MYCALL);
memcpy(&IDHDDR.ORIGIN[0], MYCALL, 7);
IDHDDR.ORIGIN[6] |= 0x61; // SET CMD END AND RESERVED BITS
ConvToAX25(MYALIASTEXT, MYALIAS);
// SET UP INITIAL DEST ENTRY FOR APPLICATIONS (IF BOTH NODE AND BBS NEEDED)
// Actually wrong - we need to set up application node entries even if node = 0
DEST = DESTS;
// If NODECALL isn't same as NETROMCALL, Add Dest Entry for NODECALL
if (memcmp(NETROMCALL, MYCALL, 7) != 0)
{
memcpy(DEST->DEST_CALL, MYCALL, 7);
memcpy(DEST->DEST_ALIAS, MYALIASTEXT, 6);
DEST->DEST_STATE = 0x80; // SPECIAL ENTRY
DEST->NRROUTE[0].ROUT_QUALITY = 255;
DEST->NRROUTE[0].ROUT_OBSCOUNT = 255;
DEST++;
NUMBEROFNODES++;
}
if (BBS)
{
// Add Application Entries
APPL = &APPLCALLTABLE[0];
i = NumberofAppls;
while (i--)
{
if (APPL->APPLQUAL)
{
memcpy(DEST->DEST_CALL, APPL->APPLCALL, 13);
DEST->DEST_STATE = 0x80; // SPECIAL ENTRY
DEST->NRROUTE[0].ROUT_QUALITY = (UCHAR)APPL->APPLQUAL;
DEST->NRROUTE[0].ROUT_OBSCOUNT = 255;
APPL->NODEPOINTER = DEST;
DEST++;
NUMBEROFNODES++;
}
APPL++;
}
}
// Read Node and MH Recovery Files
ReadNodes();
if (AUTOSAVEMH)
ReadMH(); // Only if AutoSave configured
// set up stream number in BPQHOSTVECTOR
for (i = 0; i < 64; i++)
{
BPQHOSTVECTOR[i].HOSTSTREAM = i + 1;
}
memcpy(MYCALLWITHALIAS, MYCALL, 7);
memcpy(&MYCALLWITHALIAS[7], MYALIASTEXT, 6);
// Set random start value for NETROM Session ID
NEXTID = (rand() % 254) + 1;
GetPortCTEXT(0, 0, 0, 0);
upnpInit();
lastSaveSecs = CurrentSecs = lastSlowSecs = time(NULL);
return 0;
}
BOOL CompareCalls(UCHAR * c1, UCHAR * c2)
{
// COMPARE AX25 CALLSIGNS IGNORING EXTRA BITS IN SSID
if (memcmp(c1, c2, 6))
return FALSE; // No Match
if ((c1[6] & 0x1e) == (c2[6] & 0x1e))
return TRUE;
return FALSE;
}
BOOL CompareAliases(UCHAR * c1, UCHAR * c2)
{
// COMPARE first 6 chars of AX25 CALLSIGNS
if (memcmp(c1, c2, 6))
return FALSE; // No Match
return TRUE;
}
BOOL FindNeighbour(UCHAR * Call, int Port, struct ROUTE ** REQROUTE)
{
struct ROUTE * ROUTE = NEIGHBOURS;
struct ROUTE * FIRSTSPARE = NULL;
int n = MAXNEIGHBOURS;
while (n--)
{
if (ROUTE->NEIGHBOUR_CALL[0] == 0) // Spare
if (FIRSTSPARE == NULL)
FIRSTSPARE = ROUTE;
if (ROUTE->NEIGHBOUR_PORT != Port)
{
ROUTE++;
continue;
}
if (CompareCalls(ROUTE->NEIGHBOUR_CALL, Call))
{
*REQROUTE = ROUTE;
return TRUE;
}
ROUTE++;
}
// ENTRY NOT FOUND - FIRSTSPARE HAS FIRST FREE ENTRY, OR ZERO IF TABLE FULL
*REQROUTE = FIRSTSPARE;
return FALSE;
}
BOOL FindDestination(UCHAR * Call, struct DEST_LIST ** REQDEST)
{
struct DEST_LIST * DEST = DESTS;
struct DEST_LIST * FIRSTSPARE = NULL;
int n = MAXDESTS;
while (n--)
{
if (DEST->DEST_CALL[0] == 0) // Spare
{
if (FIRSTSPARE == NULL)
FIRSTSPARE = DEST;
DEST++;
continue;
}
if (CompareCalls(DEST->DEST_CALL, Call))
{
*REQDEST = DEST;
return TRUE;
}
DEST++;
}
// ENTRY NOT FOUND - FIRSTSPARE HAS FIRST FREE ENTRY, OR ZERO IF TABLE FULL
*REQDEST = FIRSTSPARE;
return FALSE;
}
extern UCHAR BPQDirectory[];
#define LINE_MAX 256
// Reload saved MH file
VOID ReadMH()
{
char FN[260];
FILE *fp;
char line[LINE_MAX];
UCHAR axcall[7];
char * ptr, *digi, *locptr, *locend;
char * Context, * Context2;
char seps[] = " \n";
int Port;
struct PORTCONTROL * PORT = NULL;
MHSTRUC * MH;
int count = MHENTRIES;
char * Digiptr;
BOOL Digiused;
char * HasStar;
// Set up pointer to BPQNODES file
if (BPQDirectory[0] == 0)
{
strcpy(FN,"MHSave.txt");
}
else
{
strcpy(FN,BPQDirectory);
strcat(FN,"/");
strcat(FN,"MHSave.txt");
}
if ((fp = fopen(FN, "r")) == NULL)
{
return;
}
while (fgets(line, LINE_MAX, fp) != NULL)
{
if (memcmp(line, "Port:", 5) == 0)
{
Port = atoi(&line[5]);
PORT = GetPortTableEntryFromPortNum(Port);
if (PORT)
MH = PORT->PORTMHEARD;
else
MH = NULL;
continue;
}
// 1548777630 N9LYA-8 Jan 29 16:00:30
if (MH)
{
ptr = strtok_s(line, seps, &Context);
if (ptr == NULL)
continue;
MH->MHTIME = atoi(ptr);
ptr = strtok_s(NULL, seps, &Context);
if (ptr == NULL)
continue;
MH->MHCOUNT = atoi(ptr);
// Get LOC and Freq First before strtok messes with line
locptr = strchr(Context, '|');
if (locptr == NULL)
continue;
locend = strchr(++locptr, '|');
if (locend == NULL)
continue;
if ((locend - locptr) == 6)
memcpy(MH->MHLocator, locptr, 6);
locend++;
strlop(locend, '\n');
if (strlen(locend) < 12)
strcpy(MH->MHFreq, locend);
ptr = strtok_s(NULL, "|\n", &Context);
if (ptr == NULL)
continue;
if (ConvToAX25(ptr, axcall) == FALSE)
continue; // Duff
memcpy(MH->MHCALL, axcall, 7);
if (ptr[10] != ' ')
MH->MHDIGI = ptr[10];
// SEE IF ANY DIGIS
digi = strstr(ptr, " via ");
if (digi)
{
digi = digi + 5;
Digiptr = &MH->MHDIGIS[0][0];
if (strchr(ptr, '*'))
Digiused = 1; // At least one digi used
else
Digiused = 0;
digi = strtok_s(digi, ",\n", &Context2);
while(digi)
{
HasStar = strlop(digi, '*');
if (ConvToAX25(digi, axcall) == FALSE)
break;
memcpy(Digiptr, axcall, 7);
if (Digiused)
Digiptr[6] |= 0x80; // Set used
if (HasStar)
Digiused = 0; // Only last used has *
Digiptr += 7;
digi = strtok_s(NULL, ",/n", &Context2);
}
*(--Digiptr) |= 1; // Set end of address on last
}
else
{
// No Digis
MH->MHCALL[6] |= 1; // Set end of address
}
MH++;
}
}
fclose(fp);
return;
}
VOID ReadNodes()
{
char FN[260];
FILE *fp;
char line[LINE_MAX];
UCHAR axcall[7];
char * ptr;
char * Context;
char seps[] = " \r";
int Port, Qual;
struct PORTCONTROL * PORT;
// Set up pointer to BPQNODES file
if (BPQDirectory[0] == 0)
{
strcpy(FN,"BPQNODES.dat");
}
else
{
strcpy(FN,BPQDirectory);
strcat(FN,"/");
strcat(FN,"BPQNODES.dat");
}
if ((fp = fopen(FN, "r")) == NULL)
{
WritetoConsoleLocal(
"Route/Node recovery file BPQNODES.dat not found - Continuing without it\n");
return;
}
// Read the saved ROUTES/NODES file
while (fgets(line, LINE_MAX, fp) != NULL)
{
if (memcmp(line, "ROUTE ADD", 9) == 0)
{
struct ROUTE * ROUTE = NULL;
// FORMAT IS ROUTE ADD CALLSIGN PORT QUAL (VIA ....
ptr = strtok_s(&line[10], seps, &Context);
if (ConvToAX25(ptr, axcall) == FALSE)
continue; // DUff
ptr = strtok_s(NULL, seps, &Context);
if (ptr == NULL) continue;
Port = atoi(ptr);
PORT = GetPortTableEntryFromPortNum(Port);
if (PORT == NULL)
continue; // Port has gone
if (FindNeighbour(axcall, Port, &ROUTE))
continue; // Already added from ROUTES:
if (ROUTE == NULL)
continue; // Tsble Full
memcpy(ROUTE->NEIGHBOUR_CALL, axcall, 7);
ROUTE->NEIGHBOUR_PORT = Port;
ptr = strtok_s(NULL, seps, &Context);
if (ptr == NULL) continue;
Qual = atoi(ptr);
ROUTE->NEIGHBOUR_QUAL = Qual;
ptr = strtok_s(NULL, seps, &Context); // MAXFRAME
if (ptr == NULL) continue;
// I don't thinlk we should load locked flag from save file - only from config
// But need to parse it until I stop saving it
if (ptr[0] == '!')
{
// ROUTE->NEIGHBOUR_FLAG = 1; // LOCKED ROUTE
ptr = strtok_s(NULL, seps, &Context);
if (ptr == NULL) continue;
}
// SEE IF ANY DIGIS
if (ptr[0] == 'V')
{
ptr = strtok_s(NULL, seps, &Context);
if (ptr == NULL) continue;
if (ConvToAX25(ptr, axcall) == FALSE)
continue; // DUff
memcpy(ROUTE->NEIGHBOUR_DIGI1, axcall, 7);
ROUTE->NEIGHBOUR_FLAG = 1; // LOCKED ROUTE - Digi'ed routes must be locked
ptr = strtok_s(NULL, seps, &Context);
if (ptr == NULL) continue;
// See if another digi or MAXFRAME
if (strlen(ptr) > 2)
{
if (ConvToAX25(ptr, axcall) == FALSE)
continue; // DUff
memcpy(ROUTE->NEIGHBOUR_DIGI2, axcall, 7);
ptr = strtok_s(NULL, seps, &Context);
if (ptr == NULL) continue;
}
}
Qual = atoi(ptr);
ROUTE->NBOUR_MAXFRAME = Qual;
ptr = strtok_s(NULL, seps, &Context); // FRACK
if (ptr == NULL) continue;
Qual = atoi(ptr);
ROUTE->NBOUR_FRACK = Qual;
ptr = strtok_s(NULL, seps, &Context); // PACLEN
if (ptr == NULL) continue;
Qual = atoi(ptr);
ROUTE->NBOUR_PACLEN = Qual;
ptr = strtok_s(NULL, seps, &Context); // INP3
if (ptr == NULL) continue;
Qual = atoi(ptr);
// We now take Nokeepalives from the PORT, unless specifically
// Requested
ROUTE->NoKeepAlive = PORT->PortNoKeepAlive;
if (Qual & 4)
ROUTE->NoKeepAlive = TRUE;
if ((Qual & 1) || PORT->INP3ONLY)
{
ROUTE->NoKeepAlive = FALSE;
ROUTE->INP3Node = TRUE;
}
ptr = strtok_s(NULL, seps, &Context); // INP3
if (ptr == NULL) continue;
if (ROUTE->NEIGHBOUR_FLAG == 0 || ROUTE->OtherendLocked == 0); // Not LOCKED ROUTE
ROUTE->OtherendsRouteQual = atoi(ptr);
continue;
}
if (memcmp(line, "NODE ADD", 8) == 0)
{
// FORMAT IS NODE ADD ALIAS:CALL ROUTE QUAL
dest_list * DEST = NULL;
struct ROUTE * ROUTE = NULL;
char * ALIAS;
char FULLALIAS[6] = " ";
int SavedOBSINIT = OBSINIT;
if (line[9] == ':')
{
// No alias
Context = &line[10];
}
else
{
ALIAS = strtok_s(&line[9], ":", &Context);
if (ALIAS == NULL)
continue;
memcpy(FULLALIAS, ALIAS, (int)strlen(ALIAS));
}
ptr = strtok_s(NULL, seps, &Context);
if (ptr == NULL)
continue;
if (ConvToAX25(ptr, axcall) == FALSE)
continue; // Duff
if (CompareCalls(axcall, MYCALL))
continue; // Shoiuldn't happen, but to be safe!
if (FindDestination(axcall, &DEST))
continue;
if (DEST == NULL)
continue; // Tsble Full
memcpy(DEST->DEST_CALL, axcall, 7);
memcpy(DEST->DEST_ALIAS, FULLALIAS, 6);
NUMBEROFNODES++;
RouteLoop:
// GET NEIGHBOURS FOR THIS DESTINATION - CALL PORT QUAL
ptr = strtok_s(NULL, seps, &Context);
if (ptr == NULL) continue;
if (ConvToAX25(ptr, axcall) == FALSE)
continue; // DUff
ptr = strtok_s(NULL, seps, &Context);
if (ptr == NULL) continue;
Port = atoi(ptr);
ptr = strtok_s(NULL, seps, &Context);
if (ptr == NULL) continue;
Qual = atoi(ptr);
if (Context[0] == '!')
{
OBSINIT = 255; //; SPECIAL FOR LOCKED
}
if (FindNeighbour(axcall, Port, &ROUTE))
{
PROCROUTES(DEST, ROUTE, Qual);
}
OBSINIT = SavedOBSINIT;
goto RouteLoop;
}
}
fclose(fp);
// loadedmsg DB cr,lf,lf,'Switch loaded and initialised OK',lf,0
return;
}
int DelayBuffers = 0;
void sendModeReport();
void sendFreqReport();
VOID TIMERINTERRUPT()
{
// Main Processing loop - CALLED EVERY 100 MS
int i;
struct PORTCONTROL * PORT = PORTTABLE;
PMESSAGE Buffer;
struct _LINKTABLE * LINK;
struct _MESSAGE * Message;
int toPort;
CurrentSecs = time(NULL);
BGTIMER++;
REALTIMETICKS++;
L2TIMERFLAG++; // INCREMENT FLAG FOR BG
L3TIMERFLAG++; // INCREMENT FLAG FOR BG
L4TIMERFLAG++; // INCREMENT FLAG FOR BG
// CALL PORT TIMER ROUTINES
for (i = 0; i < NUMBEROFPORTS; i++)
{
PORT->PORTTIMERCODE(PORT);
// Check Smart ID timer
if (PORT->SmartIDNeeded && PORT->SmartIDNeeded < time(NULL))
SendSmartID(PORT);
PORT = PORT->PORTPOINTER;
}
// CHECK FOR TIMER ACTIVITY
if (L2TIMERFLAG >= 3)
{
L2TIMERFLAG -= 3;
L2TimerProc(); // 300 mS
}
if (CurrentSecs - lastSlowSecs >= 60) // 1 PER MIN
{
lastSlowSecs = CurrentSecs;
L3TimerProc();
if (needAIS)
AISTimer();
if (needADSB)
ADSBTimer();
if (APRSActive)
Debugprintf("BPQ32 Heartbeat Buffers %d APRS Queues %d %d", QCOUNT, C_Q_COUNT(&APRSMONVECPTR->HOSTTRACEQ), C_Q_COUNT(&APPL_Q));
else
Debugprintf("BPQ32 Heartbeat Buffers %d", QCOUNT);
StatsTimer();
// Call EXT Port Slow Timer
PORT = PORTTABLE;
for (i = 0; i < NUMBEROFPORTS; i++)
{
if (PORT->PROTOCOL == 10)
{
PEXTPORTDATA PORTVEC = (PEXTPORTDATA)PORT;
EXTSLOWTIMER(PORTVEC);
}
PORT = PORT->PORTPOINTER;
}
// Call Mode Map support routine
sendFreqReport();
sendModeReport();
if (MQTT)
MQTTTimer();
/*
if (QCOUNT < 200)
{
if (DelayBuffers == 0)
{
FindLostBuffers();
DelayBuffers = 10;
}
else
{
DelayBuffers--;
}
}
*/
}
// Check Autosave Nodes and MH timer
if (CurrentSecs - lastSaveSecs >= 3600) // 1 per hour
{
lastSaveSecs = CurrentSecs;
if (AUTOSAVE == 1)
SaveNodes();
if (AUTOSAVEMH == 1)
SaveMH();
}
if (L4TIMERFLAG >= 10) // 1 PER SEC
{
L4TIMERFLAG -= 10;
L3FastTimer();
L4TimerProc();
}
// SEE IF ANY FRAMES TO TRACE
Buffer = Q_REM(&TRACE_Q);
while (Buffer)
{
// IF BUFFER HAS A LINK TABLE ENTRY ON END, RESET TIMEOUT
LINK = Buffer->Linkptr;
if (LINK)
{
if (LINK->L2TIMER)
LINK->L2TIMER = LINK->L2TIME;
Buffer->Linkptr = 0; // CLEAR FLAG FROM BUFFER
}
Message = (struct _MESSAGE *)Buffer;
Message->PORT |= 0x80; // Set TX Bit
BPQTRACE(Message, FALSE); // Dont send TX'ed frames to APRS
ReleaseBuffer(Buffer);
Buffer = Q_REM(&TRACE_Q);
}
// CHECK FOR MESSAGES RECEIVED FROM COMMS LINKS
PORT = PORTTABLE;
for (i = 0; i < NUMBEROFPORTS; i++)
{
int Sent = 0;
CURRENTPORT = PORT->PORTNUMBER; // PORT NUMBER
CURRENTPORTPTR = PORT;
Buffer = (PMESSAGE)Q_REM((void *)&PORT->PORTRX_Q);
while (Buffer)
{
Message = (struct _MESSAGE *) Buffer;
if (CURRENTPORT == 30)
Sent = Sent;
if (PORT->PROTOCOL == 10)
{
int Sessno = Message->PORT;
PEXTPORTDATA PORTVEC = (PEXTPORTDATA)PORT;
TRANSPORTENTRY * Session;
TRANSPORTENTRY * Partner;
if (PORT->TNC && PORT->TNC->Hardware == H_KISSHF)
{
// KISSHF - May be L2 packet or Test Response
if (Message->DEST[0] != 240) // Should only be ax.25 address field
goto L2Packet;
}
// PACTOR Style Message
InOctets[PORT->PORTNUMBER] += Message->LENGTH - (MSGHDDRLEN + 1);
PORT->L2FRAMESFORUS++;
Session = PORTVEC->ATTACHEDSESSIONS[Sessno];
if (Session == NULL)
{
// TNC not attached - discard
ReleaseBuffer(Buffer);
Buffer = (PMESSAGE)Q_REM((void *)&PORT->PORTRX_Q);
continue;
}
Session->L4KILLTIMER = 0; // Reset Idle Timeout
Partner = Session->L4CROSSLINK;
if (Partner == NULL)
{
// No Crosslink - pass to command handler
CommandHandler(Session, (PDATAMESSAGE)Buffer);
break;
}
if (Partner->L4STATE < 5)
{
// MESSAGE RECEIVED BEFORE SESSION IS UP - CANCEL SESSION
// AND PASS MESSAGE TO COMMAND HANDLER
if (Partner->L4CIRCUITTYPE & L2LINK) // L2 SESSION?
{
// MUST CANCEL L2 SESSION
LINK = Partner->L4TARGET.LINK;
LINK->CIRCUITPOINTER = NULL; // CLEAR REVERSE LINK
LINK->L2STATE = 4; // DISCONNECTING
LINK->L2TIMER = 1; // USE TIMER TO KICK OFF DISC
LINK->L2RETRIES = LINK->LINKPORT->PORTN2 - 2; //ONLY SEND DISC ONCE
}
CLEARSESSIONENTRY(Partner);
Session->L4CROSSLINK = 0; // CLEAR CROSS LINK
CommandHandler(Session, (struct DATAMESSAGE *)Buffer);
break;
}
C_Q_ADD(&Partner->L4TX_Q, Buffer);
PostDataAvailable(Partner);
Buffer = (PMESSAGE)Q_REM((void *)&PORT->PORTRX_Q);
continue;
}
L2Packet:
// TIME STAMP IT
time(&Message->Timestamp);
Message->PORT = CURRENTPORT;
if (MQTT && PORT->PROTOCOL == 0)
MQTTKISSRX(Buffer);
// Bridge if requested
for (toPort = 1; toPort <= MaxBPQPortNo; toPort++)
{
if (BridgeMap[CURRENTPORT][toPort])
{
MESSAGE * BBuffer = GetBuff();
struct PORTCONTROL * BPORT;
if (BBuffer)
{
memcpy(BBuffer, Message, Message->LENGTH);
BBuffer->PORT = toPort;
BPORT = GetPortTableEntryFromPortNum(toPort);
if (BPORT)
{
if (BPORT->SmartIDInterval && BPORT->SmartIDNeeded == 0)
{
// Using Smart ID, but none scheduled
BPORT->SmartIDNeeded = time(NULL) + BPORT->SmartIDInterval;
}
PUT_ON_PORT_Q(BPORT, BBuffer);
}
else
ReleaseBuffer(BBuffer);
}
}
}
L2Routine(PORT, Buffer);
Buffer = (PMESSAGE)Q_REM((void *)&PORT->PORTRX_Q);
continue;
}
// End of RX_Q
Sent = 0;
while (PORT->PORTTX_Q && Sent < 5)
{
int ret;
void * PACTORSAVEQ;
Buffer = PORT->PORTTX_Q;
Message = (struct _MESSAGE *) Buffer;
ret = PORT->PORTTXCHECKCODE(PORT, Message->PORT);
// Busy but not connected means TNC has gone - clear queue
if (ret == 1)
{
MESSAGE * Buffer = (PMESSAGE)Q_REM((void *)&PORT->PORTTX_Q);
if (Buffer == 0)
break; // WOT!!
// Debugprintf("Busy but not connected - discard message %s", Buffer->L2DATA);
ReleaseBuffer(Buffer);
break;
}
ret = ret & 0xff; // Only check bottom byte
if (ret == 0) // Not busy
{
MESSAGE * Buffer = (PMESSAGE)Q_REM((void *)&PORT->PORTTX_Q);
if (Buffer == 0)
break; // WOT!!
if (PORT->PORTDISABLED)
{
ReleaseBuffer(Buffer);
break;
}
PORT->L2FRAMESSENT++;
OutOctets[PORT->PORTNUMBER] += Buffer->LENGTH - MSGHDDRLEN;
PORT->PORTTXROUTINE((struct _EXTPORTDATA *)PORT, Buffer);
Sent++;
continue;
}
// If a Pactor Port, some channels could be busy whilst others are not.
if (PORT->PROTOCOL != 10)
break; // BUSY
// Try passing any other messages on the queue to the node.
PACTORSAVEQ = 0;
PACTORLOOP:
Buffer = PORT->PORTTX_Q;
if (Buffer == NULL)
goto ENDOFLIST;
Message = (struct _MESSAGE *) Buffer;
ret = PORT->PORTTXCHECKCODE(PORT, Message->PORT);
ret = ret & 0xff; // Only check bottom byte
if (ret) // Busy
{
// Save it
Buffer = (PMESSAGE)Q_REM((void *)&PORT->PORTTX_Q);
C_Q_ADD(&PACTORSAVEQ, Buffer);
goto PACTORLOOP;
}
Buffer = (PMESSAGE)Q_REM((void *)&PORT->PORTTX_Q);
if (PORT->PORTDISABLED)
{
ReleaseBuffer(Buffer);
goto PACTORLOOP;
}
PORT->L2FRAMESSENT++;
OutOctets[PORT->PORTNUMBER] += Message->LENGTH;
PORT->PORTTXROUTINE((struct _EXTPORTDATA *)PORT, Buffer);
Sent++;
if (Sent < 5)
goto PACTORLOOP; // SEE IF MORE
ENDOFLIST:
// Move the saved frames back onto Port Q
PORT->PORTTX_Q = PACTORSAVEQ;
break;
}
PORT->PORTRXROUTINE((struct _EXTPORTDATA *)PORT); // SEE IF MESSAGE RECEIVED
PORT = PORT->PORTPOINTER;
}
/*
;
; CHECK FOR INCOMING MESSAGES ON LINK CONTROL TABLE -
; BY NOW ONLY 'I' FRAMES WILL BE PRESENT -
; LEVEL 2 PROTOCOL HANDLING IS DONE IN MESSAGE RECEIVE CODE
; AND LINK HANDLING INTERRUPT ROUTINES
;
*/
LINK = LINKS;
i = MAXLINKS;
while (i--)
{
if (LINK->LINKCALL[0])
{
Buffer = Q_REM(&LINK->RX_Q);
while (Buffer)
{
ProcessIframe(LINK, (PDATAMESSAGE)Buffer);
Buffer =(PMESSAGE)Q_REM((void *)&LINK->RX_Q);
}
// CHECK FOR OUTGOING MSGS
if (LINK->L2STATE >= 5) // CANT SEND TEXT TILL CONNECTED
{
// CMP VER1FLAG[EBX],1
// JE SHORT MAINL35 ; NEED TO RETRY WITH I FRAMES IF VER 1
// CMP L2RETRIES[EBX],0
// JNE SHORT MAINL40 ; CANT SEND TEXT IF RETRYING
if ((LINK->L2FLAGS & RNRSET) == 0)
SDETX(LINK);
}
}
LINK++;
}
L4BG(); // DO LEVEL 4 PROCESSING
L3BG();
TNCTimerProc();
}
VOID DoListenMonitor(TRANSPORTENTRY * L4, MESSAGE * Msg)
{
uint64_t SaveMMASK = MMASK;
BOOL SaveMTX = MTX;
BOOL SaveMCOM = MCOM;
BOOL SaveMUI = MUIONLY;
PDATAMESSAGE Buffer;
char MonBuffer[1024];
int len;
UCHAR * monchars = (UCHAR *)Msg;
if (CountFramesQueuedOnSession(L4) > 10)
return;
if (monchars[21] == 3 && monchars[22] == 0xcf && monchars[23] == 0xff) // Netrom Nodes
return;
IntSetTraceOptionsEx(L4->LISTEN, 1, 0, 0);
len = IntDecodeFrame(Msg, MonBuffer, Msg->Timestamp, L4->LISTEN, FALSE, TRUE);
IntSetTraceOptionsEx(SaveMMASK, SaveMTX, SaveMCOM, SaveMUI);
if (len == 0)
return;
if (len > 256)
len = 256;
Buffer = GetBuff();
if (Buffer)
{
char * ptr = &Buffer->L2DATA[0];
Buffer->PID = 0xf0;
memcpy(ptr, MonBuffer, len);
Buffer->LENGTH = (USHORT)len + 4 + sizeof(void *);
C_Q_ADD(&L4->L4TX_Q, Buffer);
PostDataAvailable(L4);
}
}
DllExport int APIENTRY DllBPQTRACE(MESSAGE * Msg, BOOL TOAPRS)
{
int ret;
GetSemaphore(&Semaphore, 88);
ret = BPQTRACE(Msg, TOAPRS);
FreeSemaphore(&Semaphore);
return ret;
}
int BPQTRACE(MESSAGE * Msg, BOOL TOAPRS)
{
// ATTACH A COPY OF FRAME TO ANY BPQ HOST PORTS WITH MONITORING ENABLED
TRANSPORTENTRY * L4 = L4TABLE;
MESSAGE * Buffer;
int i = BPQHOSTSTREAMS + 2; // Include Telnet and AGW Stream
if (TOAPRS)
i++; // Include APRS Stream
while(i)
{
i--;
if (QCOUNT < 100)
return FALSE;
if (BPQHOSTVECTOR[i].HOSTAPPLFLAGS & 0x80) // Trace Enabled?
{
Buffer = GetBuff();
if (Buffer)
{
memcpy(&Buffer->PORT, &Msg->PORT, BUFFLEN - sizeof(void *)); // Dont copy chain word
C_Q_ADD(&BPQHOSTVECTOR[i].HOSTTRACEQ, Buffer);
#ifndef LINBPQ
if (BPQHOSTVECTOR[i].HOSTHANDLE)
PostMessage(BPQHOSTVECTOR[i].HOSTHANDLE, BPQMsg, BPQHOSTVECTOR[i].HOSTSTREAM, 1);
#endif
}
}
}
// Also pass to any users LISTENING on this port
i = MAXCIRCUITS;
if (QCOUNT < 300)
return FALSE; // Until I add by session flow control
while (i--)
{
if (L4->LISTEN)
if ((((uint64_t)1 << ((Msg->PORT & 0x7f) - 1)) & L4->LISTEN))
// if ((Msg->PORT & 0x7f) == L4->LISTEN)
DoListenMonitor(L4, Msg);
L4++;
}
return TRUE;
}
;
VOID INITIALISEPORTS()
{
char INITMSG[80];
struct PORTCONTROL * PORT = PORTTABLE;
while (PORT)
{
sprintf(INITMSG, "Initialising Port %02d ", PORT->PORTNUMBER);
WritetoConsoleLocal(INITMSG);
PORT->PORTINITCODE(PORT);
PORT = PORT->PORTPOINTER;
}
}
VOID FindLostBuffers()
{
void ** Buff;
int n, i;
unsigned int rev;
UINT CodeDump[16];
char codeText[65] = "";
unsigned char * codeByte = (unsigned char *) CodeDump;
PBPQVECSTRUC HOSTSESS = BPQHOSTVECTOR;
struct _TRANSPORTENTRY * L4; // Pointer to Session
struct DEST_LIST * DEST = DESTS;
struct ROUTE * Routes = NEIGHBOURS;
int MaxRoutes = MAXNEIGHBOURS;
int Queued;
char Call[10];
n = MAXDESTS;
Debugprintf("Looking for missing Buffers");
while (n--)
{
if (DEST->DEST_CALL[0] && DEST->DEST_Q) // Spare
{
Debugprintf("DEST Queue %s %d", DEST->DEST_ALIAS, C_Q_COUNT(&DEST->DEST_Q));
}
DEST++;
}
n = 0;
while (n < BPQHOSTSTREAMS + 4)
{
// Check Trace Q
if (HOSTSESS->HOSTTRACEQ)
{
int Count = C_Q_COUNT(&HOSTSESS->HOSTTRACEQ);
Debugprintf("Trace Buffers Stream %d Count %d", n, Count);
L4 = HOSTSESS->HOSTSESSION;
if (L4 && (L4->L4TX_Q || L4->L4RX_Q || L4->L4HOLD_Q || L4->L4RESEQ_Q))
Debugprintf("Stream %d %d %d %d %d", n, C_Q_COUNT(&L4->L4TX_Q),
C_Q_COUNT(&L4->L4RX_Q), C_Q_COUNT(&L4->L4HOLD_Q), C_Q_COUNT(&L4->L4RESEQ_Q));
}
n++;
HOSTSESS++;
}
n = MAXCIRCUITS;
L4 = L4TABLE;
while (n--)
{
if (L4->L4USER[0] == 0)
{
L4++;
continue;
}
if (L4->L4TX_Q || L4->L4RX_Q || L4->L4HOLD_Q || L4->L4RESEQ_Q)
Debugprintf("L4 %d TX %d RX %d HOLD %d RESEQ %d", MAXCIRCUITS - n, C_Q_COUNT(&L4->L4TX_Q),
C_Q_COUNT(&L4->L4RX_Q), C_Q_COUNT(&L4->L4HOLD_Q), C_Q_COUNT(&L4->L4RESEQ_Q));
L4++;
}
// Routes
while (MaxRoutes--)
{
if (Routes->NEIGHBOUR_CALL[0] != 0)
{
Call[ConvFromAX25(Routes->NEIGHBOUR_CALL, Call)] = 0;
if (Routes->NEIGHBOUR_LINK)
{
Queued = COUNT_AT_L2(Routes->NEIGHBOUR_LINK); // SEE HOW MANY QUEUED
if (Queued)
Debugprintf("Route %s %d", Call, Queued);
}
}
Routes++;
}
// Build list of buffers, then mark off all on free Q
Buff = BUFFERPOOL;
n = 0;
for (i = 0; i < NUMBEROFBUFFERS; i++)
{
Bufferlist[n++] = Buff;
Buff += (BUFFALLOC / sizeof(void *));
}
Buff = FREE_Q;
while (Buff)
{
n = NUMBEROFBUFFERS;
while (n--)
{
if (Bufferlist[n] == Buff)
{
Bufferlist[n] = 0;
break;
}
}
Buff = *Buff;
}
n = NUMBEROFBUFFERS;
while (n--)
{
if (Bufferlist[n])
{
char * fileptr = (char *)Bufferlist[n];
MESSAGE * Msg = (MESSAGE *)Bufferlist[n];
memcpy(CodeDump, Bufferlist[n], 64);
for (i = 0; i < 64; i++)
{
if (codeByte[i] > 0x1f && codeByte[i] < 0x80)
codeText[i] = codeByte[i];
else
codeText[i] = '.';
}
for (i = 0; i < 16; i++)
{
rev = (CodeDump[i] & 0xff) << 24;
rev |= (CodeDump[i] & 0xff00) << 8;
rev |= (CodeDump[i] & 0xff0000) >> 8;
rev |= (CodeDump[i] & 0xff000000) >> 24;
CodeDump[i] = rev;
}
Debugprintf("%08x %08x %08x %08x %08x %08x %08x %08x %08x ",
Bufferlist[n], CodeDump[0], CodeDump[1], CodeDump[2], CodeDump[3], CodeDump[4], CodeDump[5], CodeDump[6], CodeDump[7]);
Debugprintf(" %08x %08x %08x %08x %08x %08x %08x %08x %d",
CodeDump[8], CodeDump[9], CodeDump[10], CodeDump[11], CodeDump[12], CodeDump[13], CodeDump[14], CodeDump[15], Msg->Process);
Debugprintf(" %s %s", &fileptr[400], codeText);
}
}
// rebuild list for buffer check
Buff = BUFFERPOOL;
n = 0;
for (i = 0; i < NUMBEROFBUFFERS; i++)
{
Bufferlist[n++] = Buff;
Buff += (BUFFALLOC / sizeof(void *));
}
}
void WriteConnectLog(char * fromCall, char * toCall, UCHAR * Mode)
{
UCHAR FN[MAX_PATH];
FILE * LogHandle;
time_t T;
struct tm * tm;
char LogMsg[256];
int MsgLen;
T = time(NULL);
tm = gmtime(&T);
sprintf(FN,"%s/logs/ConnectLog_%02d%02d%02d.log", LogDirectory, tm->tm_year - 100, tm->tm_mon + 1, tm->tm_mday);
LogHandle = fopen(FN, "ab");
if (LogHandle == NULL)
return;
MsgLen = sprintf(LogMsg, "%02d:%02d:%02d Call from %s to %s Mode %s\r\n", tm->tm_hour, tm->tm_min, tm->tm_sec, fromCall, toCall, Mode);
fwrite(LogMsg , 1, MsgLen, LogHandle);
fclose(LogHandle);
}