diff --git a/ARDOP.c b/ARDOP.c
index 048c67f..5832c44 100644
--- a/ARDOP.c
+++ b/ARDOP.c
@@ -62,6 +62,12 @@ int (WINAPI FAR *EnumProcessesPtr)();
#include "tncinfo.h"
+void hookL4SessionAttempt(struct STREAMINFO * , char * remotecall, char * ourcall);
+void hookL4SessionAccepted(struct STREAMINFO * , char * remotecall, char * ourcall);
+void hookL4SessionDeleted(struct TNCINFO * TNC, void * STREAM);
+
+
+
#define WSA_ACCEPT WM_USER + 1
#define WSA_DATA WM_USER + 2
#define WSA_CONNECT WM_USER + 3
diff --git a/BPQINP3.c b/BPQINP3.c
index b1f79bc..872496b 100644
--- a/BPQINP3.c
+++ b/BPQINP3.c
@@ -42,11 +42,19 @@ extern int DEBUGINP3;
VOID SendNegativeInfo();
VOID SortRoutes(struct DEST_LIST * Dest);
VOID SendRTTMsg(struct ROUTE * Route);
+VOID TCPNETROMSend(struct ROUTE * Route, struct _L3MESSAGEBUFFER * Frame);
static VOID SendNetFrame(struct ROUTE * Route, struct _L3MESSAGEBUFFER * Frame)
{
// INP3 should only ever send over an active link, so just queue the message
-
+
+ if (Route->TCPPort) // NETROM over TCP
+ {
+ TCPNETROMSend(Route, Frame);
+ ReleaseBuffer(Frame);
+ return;
+ }
+
if (Route->NEIGHBOUR_LINK)
C_Q_ADD(&Route->NEIGHBOUR_LINK->TX_Q, Frame);
else
@@ -127,10 +135,11 @@ VOID TellINP3LinkGone(struct ROUTE * Route)
if (Route->NEIGHBOUR_LINK)
Debugprintf("BPQ32 Neighbour_Link not cleared");
+ // Link can have both NETROM and INP3 links
- if (Route->INP3Node == 0)
+// if (Route->INP3Node == 0)
DecayNETROMRoutes(Route);
- else
+// else
DeleteINP3Routes(Route);
}
@@ -882,9 +891,11 @@ VOID ProcessRTTMsg(struct ROUTE * Route, struct _L3MESSAGEBUFFER * Buff, int Len
int Dummy;
char * ptr;
struct _RTTMSG * RTTMsg = (struct _RTTMSG *)&Buff->L4DATA[0];
-
char Normcall[10];
+ if (Route->NEIGHBOUR_LINK == 0)
+ return;
+
Normcall[ConvFromAX25(Route->NEIGHBOUR_LINK->LINKCALL, Normcall)] = 0;
// See if a reply to our message, or a new request
@@ -896,7 +907,7 @@ VOID ProcessRTTMsg(struct ROUTE * Route, struct _L3MESSAGEBUFFER * Buff, int Len
return;
}
- if (Route->NEIGHBOUR_LINK->LINKPORT->ALLOWINP3 || Route->NEIGHBOUR_LINK->LINKPORT->ENABLEINP3)
+ if (Route->NEIGHBOUR_LINK->LINKPORT && (Route->NEIGHBOUR_LINK->LINKPORT->ALLOWINP3 || Route->NEIGHBOUR_LINK->LINKPORT->ENABLEINP3))
Route->INP3Node = 1;
if (Route->INP3Node == 0)
@@ -1168,11 +1179,16 @@ int SendRIPTimer()
// Delay more if Locked - they could be retrying for a long time
- if ((Route->NEIGHBOUR_FLAG)) // LOCKED ROUTE
- INP3Delay = 1200;
+ if (Route->ConnectionAttempts < 5)
+ INP3Delay = 30;
else
- INP3Delay = 600;
-
+ {
+ if ((Route->NEIGHBOUR_FLAG)) // LOCKED ROUTE
+ INP3Delay = 300;
+ else
+ INP3Delay = 120;
+ }
+
if (Route->LastConnectAttempt && (REALTIMETICKS - Route->LastConnectAttempt) < INP3Delay)
{
Route++;
@@ -1181,6 +1197,8 @@ int SendRIPTimer()
// Try to activate link
+ Route->ConnectionAttempts++;
+
if (Route->INP3Node)
{
Normcall[ConvFromAX25(Route->NEIGHBOUR_CALL, Normcall)] = 0;
@@ -1618,7 +1636,7 @@ VOID INP3TIMER()
}
-UCHAR * DisplayINP3RIF(UCHAR * ptr1, UCHAR * ptr2, unsigned int msglen)
+UCHAR * DisplayINP3RIF(UCHAR * ptr1, UCHAR * ptr2, int msglen)
{
char call[10];
int calllen;
diff --git a/BPQNRR.c b/BPQNRR.c
index b557e2f..2360aa9 100644
--- a/BPQNRR.c
+++ b/BPQNRR.c
@@ -45,7 +45,7 @@ extern VOID Q_ADD();
VOID __cdecl Debugprintf(const char * format, ...);
TRANSPORTENTRY * NRRSession;
-time_t NRRTime;
+int NRRID = 1; // Id to correlate requests and responses
/*
@@ -77,8 +77,9 @@ VOID NRRecordRoute(UCHAR * Buff, int Len)
{
UCHAR * BUFFER = GetBuff();
UCHAR * ptr1;
- struct _MESSAGE * Msg;
+ struct _MESSAGE * Msg1;
time_t Now = time(NULL);
+ int ID = (Msg->L4TXNO << 8) | Msg->L4RXNO;
if (BUFFER == NULL)
return;
@@ -87,7 +88,18 @@ VOID NRRecordRoute(UCHAR * Buff, int Len)
*ptr1++ = 0xf0; // PID
- ptr1 += sprintf(ptr1, "NRR Response in (probably) %d Secs :", (int)(Now - NRRTime));
+
+ if (BUFFER == NULL)
+ return;
+
+ ptr1 = &BUFFER[MSGHDDRLEN];
+
+ *ptr1++ = 0xf0; // PID
+
+ if (ID == NRRSession->NRRID)
+ ptr1 += sprintf(ptr1, "NRR Response in %d Secs:", (int)(Now - NRRSession->NRRTime));
+ else
+ ptr1 += sprintf(ptr1, "NRR Response:", (int)(Now - NRRSession->NRRTime));
Buff += 21 + MSGHDDRLEN;
Len -= (21 + MSGHDDRLEN);
@@ -100,7 +112,7 @@ VOID NRRecordRoute(UCHAR * Buff, int Len)
if ((Buff[7] & 0x80) == 0x80) // Check turnround bit
*ptr1++ = '*';
- Buff+=8;
+ Buff += 8;
Len -= 8;
}
@@ -114,11 +126,11 @@ VOID NRRecordRoute(UCHAR * Buff, int Len)
Len = (int)(ptr1 - BUFFER);
- Msg = (struct _MESSAGE *)BUFFER;
+ Msg1 = (struct _MESSAGE *)BUFFER;
- Msg->LENGTH = Len;
+ Msg1->LENGTH = Len;
- Msg->CHAIN = NULL;
+ Msg1->CHAIN = NULL;
C_Q_ADD(&NRRSession->L4TX_Q, (UINT *)BUFFER);
@@ -175,7 +187,6 @@ VOID SendNRRecordRoute(struct DEST_LIST * DEST, TRANSPORTENTRY * Session)
return;
NRRSession = Session; // Save Session Pointer for reply
- NRRTime = time(NULL);
Msg->Port = 0;
Msg->L3PID = NRPID;
@@ -187,11 +198,16 @@ VOID SendNRRecordRoute(struct DEST_LIST * DEST, TRANSPORTENTRY * Session)
Msg->L4ID = 1;
Msg->L4INDEX = 0;
Msg->L4FLAGS = 0;
+ Msg->L4TXNO = NRRID << 8;
+ Msg->L4RXNO = NRRID & 0xff;
memcpy(Msg->L4DATA, MYCALL, 7);
Msg->L4DATA[7] = Stream + 28;
Msg->LENGTH = 8 + 21 + MSGHDDRLEN;
-
+
+ Session->NRRTime = time(NULL);
+ Session->NRRID = NRRID++;
+
C_Q_ADD(&DEST->DEST_Q, Msg);
}
diff --git a/Bpq32.c b/Bpq32.c
index 61078a0..41d4e64 100644
--- a/Bpq32.c
+++ b/Bpq32.c
@@ -1292,6 +1292,12 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
// Improvments to INP3 (4, 5)
// Add Node API /api/tcpqueues (5)
// Add sending link events to OARC API (disabled by default) (6)
+// Fix possible program error in Telnet_Connected (7)
+// Close links when program is closed down (7)
+// Fix possible problem with deleting routes when using both NODES and INP3 routing on same link (7)
+// Add Paula's Netromx (allows connects to different applications using Node call) (8)
+// Add Netrom over TCP (8)
+// Fix FRMR caused by sending SREJ when no frames outstanding (8)
#define CKernel
@@ -1387,6 +1393,8 @@ void * HSMODEMExtInit(EXTPORTDATA * PortEntry);
void * FreeDataExtInit(EXTPORTDATA * PortEntry);
void * SIXPACKExtInit(EXTPORTDATA * PortEntry);
+VOID RealCloseAllPrograms();
+
extern char * ConfigBuffer; // Config Area
VOID REMOVENODE(dest_list * DEST);
DllExport int ConvFromAX25(unsigned char * incall,unsigned char * outcall);
@@ -1396,6 +1404,8 @@ VOID ADIFWriteFreqList();
void SaveAIS();
void initAIS();
void initADSB();
+int CloseAllSessions();
+int CloseAllLinks();
extern BOOL ADIFLogEnabled;
@@ -1643,6 +1653,8 @@ BOOL IGateEnabled = TRUE;
extern int ISDelayTimer; // Time before trying to reopen APRS-IS link
extern int ISPort;
+int CLOSING = 0;
+
UINT * WINMORTraceQ = NULL;
UINT * SetWindowTextQ = NULL;
@@ -1698,6 +1710,8 @@ BOOL ReconfigFlag = FALSE;
BOOL RigReconfigFlag = FALSE;
BOOL APRSReconfigFlag = FALSE;
BOOL CloseAllNeeded = FALSE;
+int CloseAllTimer = 0;
+
BOOL NeedWebMailRefresh = FALSE;
int AttachedPIDList[100] = {0};
@@ -2379,6 +2393,52 @@ VOID TimerProcX()
CheckGuardZone();
+ if (CloseAllTimer == 50) // First entry
+ {
+ if (CloseAllSessions() == 0)
+ {
+ if (CloseAllLinks() == 0) // No sessions closed so close links now
+ CloseAllTimer = 0; // No Links so close now
+ else
+ CloseAllTimer = 39; // ~4 secs for links to close
+ }
+ }
+
+ if (CloseAllTimer == 40) // First entry
+ CloseAllLinks(); // No sessions closed so close links now
+
+ if (CloseAllTimer)
+ {
+ // See if any links left
+
+ struct _LINKTABLE * LINK = LINKS;
+ int i = MAXLINKS;
+
+ if (CloseAllTimer == 0)
+ RealCloseAllPrograms();
+
+ while (i--)
+ {
+ if (LINK->LINKCALL[0])
+ {
+ break;
+ }
+
+ if (i == 0)
+ {
+ CloseAllTimer = 0;
+ RealCloseAllPrograms();
+ return;
+ }
+ LINK++;
+ continue;
+ }
+
+ CloseAllTimer--;
+
+ if(CloseAllTimer == 0)
+ RealCloseAllPrograms();
+ }
return;
}
@@ -5905,13 +5965,24 @@ DllExport VOID APIENTRY CreateNewTrayIcon()
trayMenu = NULL;
}
+void hookNodeClosing(char * Reason);
+
+
DllExport VOID APIENTRY CloseAllPrograms()
{
-// HANDLE hProc;
+ CLOSING = TRUE;
+
+ // Tell BG to shut when all links are gone or after 5 secs
- // Close all attached BPQ32 programs
+ CloseAllTimer = 50;
+}
+
+VOID RealCloseAllPrograms()
+{
+ hookNodeClosing("Shutdown");
+ Sleep(500);
- Closing = TRUE;
+ Closing = 1;
ShowWindow(FrameWnd, SW_RESTORE);
diff --git a/CBPQ32.vcproj b/CBPQ32.vcproj
index dc7f72e..7060ec5 100644
--- a/CBPQ32.vcproj
+++ b/CBPQ32.vcproj
@@ -454,6 +454,10 @@
RelativePath="..\CommonSource\MULTIPSK.c"
>
+
+
diff --git a/Cmd.c b/Cmd.c
index d53d65d..605ccd1 100644
--- a/Cmd.c
+++ b/Cmd.c
@@ -17,9 +17,7 @@ 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 cmd.asm
-//
+
#define Kernel
#define _CRT_SECURE_NO_DEPRECATE
@@ -44,8 +42,6 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
#include "tncinfo.h"
#include "telnetserver.h"
-
-
//#include "GetVersion.h"
//#define DllImport __declspec( dllimport )
@@ -74,6 +70,7 @@ int CompareNode(const void *a, const void *b);
int CompareAlias(const void *a, const void *b);
int CompareRoutes(const void * a, const void * b);
void SendVARANetromNodes(struct TNCINFO * TNC, MESSAGE *Buffer);
+VOID DoNetromConnect(TRANSPORTENTRY * Session, char * Bufferptr, struct DEST_LIST * Dest, BOOL Spy, int Service);
extern VOID KISSTX(struct KISSINFO * KISS, PMESSAGE Buffer);
@@ -190,6 +187,54 @@ VOID QTSMCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct
void hookL2SessionAttempt(int Port, char * fromCall, char * toCall, struct _LINKTABLE * LINK);
+/* Paula's NetROMX includes a service number in a CREQX message which allows a node to host lots of applications without
+ filling the Nodes table with SSID's
+
+I could make these (or some of them) BPQ Commands but some will clash (eg INFO) or match an existing APPL (eg BBS)
+
+I could use C APPL@CALL for an extended call to a node
+
+Maybe I can detect APPL NODE so Paula's syntax will work
+
+or both??
+
+Standard Services are:
+*/
+
+struct NETROMX SERVICES[] = {
+ {0, "CMD"}, // Normal connection to Node's command line
+ {1, "INFO"}, // Standard Information server
+ {2, "PMS"}, // Personal Message System
+ {3, "BBS"}, // (reserved for Bulletin Board System)
+ {4, "DX"}, // (reserved for DX cluster/dx-spot feed)
+ {5, "TPP"}, // (reserved for "Tampa Ping-Pong" chat)
+ {7, "ECHO"}, // Echoes data back to sender
+ {8, "XRCHAT"}, // XRChat server
+ {9, "DISCARD"}, // Data sink
+ {10, "RMS"}, // (reserved for winlink RMS}
+ {11, "CHAT"}, // (reserved for BPQ chat server)
+ {13, "DAYTIME"}, // Local date/time (similar to RFC867)
+ {14, "APRS"}, // APRS Server
+ {15, "CUSTINF"},// (reserved for custom information file server)
+ {16, "WX"}, // Local weather information
+ {17, "TELEM"}, // (reserved for Telemetry server)
+ {18, "SMS"}, // Short Message System server
+ {19, "CHARGEN"},// Generates a test pattern
+ {20, "NDATA"}, // (reserved for NFTP extension)
+ {21, "NFTP"}, // Netrom File Transfer Protocol
+ {22, "NSSH"}, // (reserved for secure login - if legal?)
+ {23, "TELNET"}, // Normal L4 login (same as 0)
+ {25, "SMTP"}, // (reserved for Simple Mail Transfer Protocol)
+ {26, "MHEARD"}, // MHEARD server (shows MH lists)
+ {27, "DXLIST"}, // DX List server (shows DX lists)
+ {79, "FINGER"}, // Finger server
+ {80, "HTTP"}, // NetromWeb (HTTP over Netrom) server
+ {87, "NTTY"}, // Netrom TTY - Keyboard to keyboard chat
+ {1883, "MQTT"} // MQTT server
+};
+
+int NUMBEROFSSERVICES = sizeof(SERVICES)/sizeof(struct NETROMX);
+
char * __cdecl Cmdprintf(TRANSPORTENTRY * Session, char * Bufferptr, const char * format, ...)
{
@@ -791,6 +836,104 @@ BOOL cATTACHTOBBS(TRANSPORTENTRY * Session, UINT Mask, int Paclen, int * AnySess
return FALSE;
}
+void ConnecttoService(TRANSPORTENTRY * Session, char * Bufferptr, int ServiceIndex, char * Node, int Stay)
+{
+ struct DEST_LIST * Dest = DESTS;
+ int n = MAXDESTS;
+ int gotDest = 0;
+ unsigned char axcall[7];
+ int Service = -1;
+
+ // Make Sure Node is Known
+
+ strcat(Node, " "); // Node table has 6 byte Aliases
+
+ while (n--)
+ {
+ if (memcmp(Dest->DEST_ALIAS, Node, 6) == 0)
+ {
+ gotDest = 1;
+ break;
+ }
+ Dest++;
+ }
+
+ if (gotDest == 0)
+ {
+ Dest = DESTS;
+ n = MAXDESTS;
+
+ ConvToAX25(Node, axcall);
+
+ while (n--)
+ {
+ if (CompareCalls(Dest->DEST_CALL, axcall))
+ {
+ gotDest = 1;
+ break;
+ }
+ Dest++;
+ }
+ }
+
+ strlop(Node, ' ');
+
+ if (gotDest == 0)
+ {
+ Bufferptr = Cmdprintf(Session, Bufferptr, "Node %s not found\r", Node);
+ SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
+ return;
+ }
+
+ Session->STAYFLAG = Stay;
+
+ Service = SERVICES[ServiceIndex].ServiceNo;
+
+ Bufferptr = Cmdprintf(Session, Bufferptr, "Connecting to Service %s on Node %s \r", SERVICES[ServiceIndex].ServiceName, Node);
+
+ DoNetromConnect(Session, Bufferptr, Dest, 0, Service);
+
+ SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
+}
+
+int checkifService(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct CMDX * CMD)
+{
+ char APPName[13];
+ int n = 12;
+ BOOL Stay = FALSE;
+ char * ptr, *Context;
+ int i;
+
+ ptr = strtok_s(CmdTail, " ", &Context);
+
+ // see if any param. if longer than two chars treat as remote node
+
+ if (ptr == 0 || strlen(ptr) < 3)
+ return 0;
+
+ memcpy(APPName, CMD->String, 13);
+
+ strlop(APPName, ' ');
+
+ if (Context && Context[0] == 'S')
+ Session->STAYFLAG = Stay;
+
+ // See if APPL is one of Paula's service
+
+ for (i = 0; i < NUMBEROFSSERVICES; i++)
+ {
+ if (strcmp(APPName, SERVICES[i].ServiceName) == 0)
+ {
+ ConnecttoService(Session, Bufferptr, i, ptr, Stay);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+
VOID APPLCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct CMDX * CMD)
{
BOOL CONFAILED = 0;
@@ -799,6 +942,7 @@ VOID APPLCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct
char * ptr1, *ptr2;
int n = 12;
BOOL Stay = FALSE;
+ char * ptr, *Context;
// Copy Appl and Null Terminate
@@ -817,12 +961,43 @@ VOID APPLCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct
return;
}
+ ptr = strtok_s(CmdTail, " ", &Context);
- if (CmdTail[0] == 'S')
- Stay = TRUE;
-
- Session->STAYFLAG = Stay;
+ // ptr is first param. Context is rest of string;
+
+ if (ptr)
+ {
+ // could be Node for NETROMX connect or S flag
+
+ int i;
+
+ if (strlen(ptr) > 1)
+ {
+ if (Context && Context[0] == 'S')
+ Session->STAYFLAG = Stay;
+ // See if APPL is one of Paula's service
+
+ for (i = 0; i < NUMBEROFSSERVICES; i++)
+ {
+ if (strcmp(APPName, SERVICES[i].ServiceName) == 0)
+ {
+ ConnecttoService(Session, Bufferptr, i, ptr, Stay);
+ return;
+ }
+ }
+
+ // Not a service that can be accessed remotely
+
+ Bufferptr = Cmdprintf(Session, Bufferptr, "Connection to %s on a remote node is not possible\r", APPName);
+ SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
+ return;
+ }
+
+ else if (ptr[0] == 'S')
+ Session->STAYFLAG = Stay;
+ }
+
memcpy(Session->APPL, CMD->String, 12);
// SEE IF THERE IS AN ALIAS DEFINDED FOR THIS COMMAND
@@ -904,6 +1079,9 @@ VOID APPLCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct
VOID CMDI00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct CMDX * CMD)
{
+ if (checkifService(Session, Bufferptr, CmdTail, CMD)) // See can be used remotely
+ return;
+
Bufferptr = Cmdprintf(Session, Bufferptr, "%s", INFOMSG);
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
}
@@ -2229,7 +2407,7 @@ TRANSPORTENTRY * SetupNewSession(TRANSPORTENTRY * Session, char * Bufferptr)
}
-VOID DoNetromConnect(TRANSPORTENTRY * Session, char * Bufferptr, struct DEST_LIST * Dest, BOOL Spy)
+VOID DoNetromConnect(TRANSPORTENTRY * Session, char * Bufferptr, struct DEST_LIST * Dest, BOOL Spy, int Service)
{
TRANSPORTENTRY * NewSess;
@@ -2238,6 +2416,8 @@ VOID DoNetromConnect(TRANSPORTENTRY * Session, char * Bufferptr, struct DEST_LIS
if (NewSess == NULL)
return; // Tables Full
+ NewSess->Service = Service;
+
NewSess->L4CIRCUITTYPE = SESSION + DOWNLINK;
NewSess->L4TARGET.DEST = Dest;
@@ -2245,12 +2425,12 @@ VOID DoNetromConnect(TRANSPORTENTRY * Session, char * Bufferptr, struct DEST_LIS
NewSess->SPYFLAG = Spy;
- ReleaseBuffer((UINT *)REPLYBUFFER);
+ if (Service == -1)
+ ReleaseBuffer((UINT *)REPLYBUFFER);
- SENDL4CONNECT(NewSess);
+ SENDL4CONNECT(NewSess, Service);
L4CONNECTSOUT++;
-
return;
}
@@ -2336,6 +2516,9 @@ VOID CMDC00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct C
char PortString[10];
char cmdCopy[256];
struct _EXTPORTDATA * EXTPORT = (struct _EXTPORTDATA *)PORT;
+ int Service = -1;
+ int haveService = 0;
+ int i = 0;
#ifdef EXCLUDEBITS
@@ -2482,7 +2665,7 @@ NoPort:
// SEE IF CALL TO ANY OF OUR HOST SESSIONS - UNLESS DIGIS SPECIFIED
- if (axcalls[7] == 0)
+ if (axcalls[7] == 0 && axcalls[9] )
{
// If this connect is as a result of a command alias, don't check appls or we will loop
@@ -2533,9 +2716,30 @@ NoPort:
}
}
- if (axcalls[7] == 0)
+ // if no digis see if connect to known node. But now could have a single numeric param as a service number (Paula's Netromx)
+ // cmdCopy is command tail (after call)
+
+ // Make sure field is numeric
+
+ i = 0;
+
+ while (cmdCopy[i] >= '0' && cmdCopy[i]<= '9')
+ i++;
+
+ if (cmdCopy[i] != ' ')
+ goto Downlink;
+ else
{
- // SEE IF CALL TO ANOTHER NODE
+ if (i > 0) // Some digits
+ {
+ haveService = 1;
+ Service = atoi(cmdCopy);
+ }
+ }
+
+ if (axcalls[7] == 0 || haveService)
+ {
+ // SEE IF CALL TO ANOTHER NODE
struct DEST_LIST * Dest = DESTS;
int n = MAXDESTS;
@@ -2546,7 +2750,7 @@ NoPort:
{
if (memcmp(Dest->DEST_ALIAS, TextCall, 6) == 0)
{
- DoNetromConnect(Session, Bufferptr, Dest, Spy);
+ DoNetromConnect(Session, Bufferptr, Dest, Spy, Service);
return;
}
Dest++;
@@ -2560,7 +2764,7 @@ NoPort:
{
if (CompareCalls(Dest->DEST_CALL, axcalls))
{
- DoNetromConnect(Session, Bufferptr, Dest, Spy);
+ DoNetromConnect(Session, Bufferptr, Dest, Spy, Service);
return;
}
Dest++;
@@ -3723,6 +3927,8 @@ VOID MHCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct CM
int len;
char Digi = 0;
+ if (checkifService(Session, Bufferptr, CmdTail, CMD)) // See can be used remotely
+ return;
// Note that the MHDIGIS field may contain rubbish. You have to check End of Address bit to find
// how many digis there are
@@ -4435,6 +4641,7 @@ struct CMDX COMMANDS[] =
"MAXHOPS ",7,SWITCHVAL,(size_t)&MaxHops,
"PREFERINP3 ",10,SWITCHVAL,(size_t)&PREFERINP3ROUTES,
"MAXRTT ",6,SWITCHVALW,(size_t)&MAXRTT,
+ "MAXTT ",6,SWITCHVALW,(size_t)&MAXRTT,
"PASSWORD ", 8, PWDCMD, 0,
"************", 12, APPLCMD, 0,
@@ -4468,7 +4675,7 @@ struct CMDX COMMANDS[] =
"************", 12, APPLCMD, 0,
"************", 12, APPLCMD, 0,
"************", 12, APPLCMD, 0,
- "************", 12, APPLCMD, 0, // Apppl 32 is internal Terminal
+ "************", 12, APPLCMD, 0, // Apppl 32 is internal Terminal on Windows
"*** LINKED ",10,LINKCMD,0,
"CQ ",2,CQCMD,0,
"CONNECT ",1,CMDC00,0,
@@ -4861,6 +5068,8 @@ VOID DoTheCommand(TRANSPORTENTRY * Session)
struct DATAMESSAGE * Buffer = REPLYBUFFER;
char * ptr1, * ptr2;
int n;
+ int i, Service = -1;
+ char * Cmd, *Node, *Context;
ptr1 = &COMMANDBUFFER[0]; //
@@ -4952,6 +5161,31 @@ VOID DoTheCommand(TRANSPORTENTRY * Session)
CMD++;
}
+
+ // See if a NETROMX Service
+
+ Cmd = strtok_s(ptr1, " ", &Context);
+ Node = strtok_s(NULL, " ", &Context);
+
+ for (i = 0; i < NUMBEROFSSERVICES; i++)
+ {
+ if (strcmp(Cmd, SERVICES[i].ServiceName) == 0)
+ {
+ int Stay = 0;
+
+ if (Context && Context[0] == 'S')
+ Session->STAYFLAG = Stay;
+
+ if (Node)
+ {
+ ConnecttoService(Session, ReplyPointer, i, Node, Stay);
+ return;
+ }
+
+ // Connecting to service on local node - msy be possible sometime
+ }
+ }
+
Session->BADCOMMANDS++;
if (Session->BADCOMMANDS > 6) // TOO MANY ERRORS
diff --git a/CommonCode.c b/CommonCode.c
index 4129429..cffbdb7 100644
--- a/CommonCode.c
+++ b/CommonCode.c
@@ -49,6 +49,12 @@ extern struct CONFIGTABLE xxcfg;
#endif
+
+void hookL4SessionAttempt(struct STREAMINFO * , char * remotecall, char * ourcall);
+void hookL4SessionAccepted(struct STREAMINFO * , char * remotecall, char * ourcall);
+void hookL4SessionDeleted(struct TNCINFO * TNC, void * STREAM);
+
+
struct TNCINFO * TNCInfo[71]; // Records are Malloc'd
extern int ReportTimer;
@@ -3679,6 +3685,12 @@ char NodeAPIServer[80] = "node-api.packet.oarc.uk";
int NodeAPIPort = 13579;
+int nodeStartedSent = 0;
+
+extern time_t LastNodeStatus;
+
+void hookNodeStarted();
+
VOID ResolveUpdateThread(void * Unused)
{
struct hostent * HostEnt1;
@@ -3717,15 +3729,23 @@ VOID ResolveUpdateThread(void * Unused)
HostEnt3 = gethostbyname(NodeAPIServer);
if (HostEnt3)
+ {
memcpy(&UDPreportdest.sin_addr.s_addr,HostEnt3->h_addr,4);
-
+ if (nodeStartedSent == 0)
+ {
+ hookNodeStarted();
+ nodeStartedSent = 1;
+ LastNodeStatus = time(NULL);
+ }
+ }
+
if (HostEnt1 && HostEnt2)
- {
- Sleep(1000 * 60 * 30);
+ {
+ Sleep(1000 * 60 * 30);
continue;
}
-
+
Debugprintf("Resolve Failed for update.g8bpq.net or chatmap.g8bpq.net");
Sleep(1000 * 60 * 5);
}
@@ -3759,13 +3779,6 @@ VOID OpenReportingSockets()
reportdest.sin_port = htons(81);
ConvToAX25("DUMMY-1", ReportDest);
}
-
- UDPreportdest.sin_family = AF_INET;
- UDPreportdest.sin_port = htons(NodeAPIPort);
-
- if (EnableOARCAPI)
- NodeAPISocket = socket(AF_INET, SOCK_DGRAM, 0);
-
// Set up Chat Report even if no LOCATOR reportdest.sin_family = AF_INET;
// Socket must be opened in MailChat Process
diff --git a/Events.c b/Events.c
index c64210d..2030929 100644
--- a/Events.c
+++ b/Events.c
@@ -25,6 +25,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
#include
#include "asmstrucs.h"
#include "tncinfo.h"
+#include "cheaders.h"
VOID __cdecl Debugprintf(const char * format, ...);
@@ -41,9 +42,9 @@ VOID __cdecl Debugprintf(const char * format, ...);
extern BOOL EventsEnabled;
void MQTTReportSession(char * Msg);
extern int MQTT;
+extern time_t TimeLoaded;
-
-int UDPSeq = 0;
+int UDPSeq = 1;
extern SOCKET NodeAPISocket;
extern SOCKADDR_IN UDPreportdest;
@@ -51,9 +52,23 @@ extern SOCKADDR_IN UDPreportdest;
extern char Modenames[19][10];
extern char NODECALLLOPPED[10];
-
+extern char MYALIASLOPPED[10];
+extern char LOC[7];
+extern char VersionString[50];
+extern double LatFromLOC;
+extern double LonFromLOC;
+
+void hookL2SessionClosed(struct _LINKTABLE * LINK, char * Reason, char * Direction);
+int ConvFromAX25(unsigned char * incall, unsigned char * outcall);
+int COUNT_AT_L2(struct _LINKTABLE * LINK);
+int CountFramesQueuedOnSession(TRANSPORTENTRY * Session);
+int decodeNETROMUIMsg(unsigned char * Msg, int iLen, char * Buffer, int BufferLen);
+int decodeNETROMIFrame(unsigned char * Msg, int iLen, char * Buffer, int BufferLen);
+int decodeINP3RIF(unsigned char * Msg, int iLen, char * Buffer, int BufferLen);
+int decodeRecordRoute(L3MESSAGE * L3, int iLen, char * Buffer, int BufferLen);
// Runs use specified routine on certain event
+
#ifndef WIN32
void RunEventProgram(char * Program, char * Param)
@@ -130,9 +145,8 @@ void hookL2SessionAccepted(int Port, char * remotecall, char * ourcall, struct _
char UDPMsg[1024];
int udplen;
-
LINK->ConnectTime = time(NULL);
- LINK->bytesTXed = LINK->bytesRXed = 0;
+ LINK->bytesTXed = LINK->bytesRXed = LINK->framesResent = LINK->framesRXed = LINK->framesTXed = 0;
strcpy(LINK->callingCall, remotecall);
strcpy(LINK->receivingCall, ourcall);
@@ -140,12 +154,14 @@ void hookL2SessionAccepted(int Port, char * remotecall, char * ourcall, struct _
if (NodeAPISocket)
{
- udplen = sprintf(UDPMsg, "{\"@type\":\"LinkUpEvent\", \"node\": \"%s\", \"id\": %d, \"direction\": \"incoming\", \"port\": \"%d\", \"remote\": \"%s\", \"local\": \"%s\"}",
- NODECALLLOPPED, UDPSeq++, LINK->LINKPORT->PORTNUMBER, LINK->callingCall, LINK->receivingCall);
-
- Debugprintf(UDPMsg);
-
- sendto(NodeAPISocket, UDPMsg, udplen, 0, (struct sockaddr *)&UDPreportdest, sizeof(UDPreportdest));
+ LINK->lastStatusSentTime = time(NULL);
+
+ udplen = sprintf(UDPMsg, "{\"@type\":\"LinkUpEvent\", \"node\": \"%s\", \"id\": %d, \"direction\": \"incoming\", \"port\": \"%d\", \"remote\": \"%s\", \"local\": \"%s\"}",
+ NODECALLLOPPED, UDPSeq++, LINK->LINKPORT->PORTNUMBER, LINK->callingCall, LINK->receivingCall);
+
+// Debugprintf(UDPMsg);
+
+ sendto(NodeAPISocket, UDPMsg, udplen, 0, (struct sockaddr *)&UDPreportdest, sizeof(UDPreportdest));
}
}
@@ -170,8 +186,6 @@ void hookL2SessionDeleted(struct _LINKTABLE * LINK)
double avBytesRXed = LINK->bytesRXed / (sessionTime / 60.0);
time_t Now = time(NULL);
struct tm * TM = localtime(&Now);
- char UDPMsg[1024];
- int udplen;
sprintf(timestamp, "%02d:%02d:%02d", TM->tm_hour, TM->tm_min, TM->tm_sec);
@@ -190,36 +204,21 @@ void hookL2SessionDeleted(struct _LINKTABLE * LINK)
if (MQTT)
MQTTReportSession(Msg);
-
- if (NodeAPISocket)
- {
- if (strcmp(LINK->Direction, "Out") == 0)
- udplen = sprintf(UDPMsg, "{\"@type\":\"LinkDownEvent\", \"node\": \"%s\", \"id\": %d, \"direction\": \"outgoing\", \"port\": \"%d\", \"remote\": \"%s\", \"local\": \"%s\"}",
- NODECALLLOPPED, UDPSeq++, LINK->LINKPORT->PORTNUMBER, LINK->receivingCall, LINK->callingCall);
- else
- udplen = sprintf(UDPMsg, "{\"@type\":\"LinkDownEvent\", \"node\": \"%s\", \"id\": %d, \"direction\": \"incoming\", \"port\": \"%d\", \"remote\": \"%s\", \"local\": \"%s\"}",
- NODECALLLOPPED, UDPSeq++, LINK->LINKPORT->PORTNUMBER, LINK->callingCall, LINK->receivingCall);
-
- Debugprintf(UDPMsg);
-
- sendto(NodeAPISocket, UDPMsg, udplen, 0, (struct sockaddr *)&UDPreportdest, sizeof(UDPreportdest));
- }
+ LINK->ConnectTime = 0;
}
- LINK->ConnectTime = 0;
- }
-
- if (LINK->Sent && LINK->Received && (LINK->SentAfterCompression || LINK->ReceivedAfterExpansion))
- Debugprintf("L2 Compression Stats %s %s TX %d %d %d%% RX %d %d %d%%", LINK->callingCall, LINK->receivingCall,
+ if (LINK->Sent && LINK->Received && (LINK->SentAfterCompression || LINK->ReceivedAfterExpansion))
+ Debugprintf("L2 Compression Stats %s %s TX %d %d %d%% RX %d %d %d%%", LINK->callingCall, LINK->receivingCall,
LINK->Sent, LINK->SentAfterCompression, ((LINK->Sent - LINK->SentAfterCompression) * 100) / LINK->Sent,
LINK->Received, LINK->ReceivedAfterExpansion, ((LINK->ReceivedAfterExpansion - LINK->Received) * 100) / LINK->Received);
+ }
}
void hookL2SessionAttempt(int Port, char * ourcall, char * remotecall, struct _LINKTABLE * LINK)
{
LINK->ConnectTime = time(NULL);
- LINK->bytesTXed = LINK->bytesRXed = 0;
+ LINK->bytesTXed = LINK->bytesRXed = LINK->framesResent = LINK->framesRXed = LINK->framesTXed = 0;
strcpy(LINK->callingCall, ourcall);
strcpy(LINK->receivingCall, remotecall);
@@ -234,13 +233,72 @@ void hookL2SessionConnected(struct _LINKTABLE * LINK)
int udplen;
if (NodeAPISocket)
- {
- udplen = sprintf(UDPMsg, "{\"@type\":\"LinkUpEvent\", \"node\": \"%s\", \"id\": %d, \"direction\": \"outgoing\", \"port\": \"%d\", \"remote\": \"%s\", \"local\": \"%s\"}",
- NODECALLLOPPED, UDPSeq++, LINK->LINKPORT->PORTNUMBER, LINK->callingCall, LINK->receivingCall);
-
- Debugprintf(UDPMsg);
-
- sendto(NodeAPISocket, UDPMsg, udplen, 0, (struct sockaddr *)&UDPreportdest, sizeof(UDPreportdest));
+ {
+ LINK->lastStatusSentTime = time(NULL);
+
+ udplen = sprintf(UDPMsg, "{\"@type\":\"LinkUpEvent\", \"node\": \"%s\", \"id\": %d, \"direction\": \"outgoing\", \"port\": \"%d\", \"remote\": \"%s\", \"local\": \"%s\"}",
+ NODECALLLOPPED, UDPSeq++, LINK->LINKPORT->PORTNUMBER, LINK->callingCall, LINK->receivingCall);
+
+// Debugprintf(UDPMsg);
+
+ sendto(NodeAPISocket, UDPMsg, udplen, 0, (struct sockaddr *)&UDPreportdest, sizeof(UDPreportdest));
+ }
+}
+
+void hookL2SessionClosed(struct _LINKTABLE * LINK, char * Reason, char * Direction)
+{
+ // Link closed. Could be normal, ie disc send/received or restried out etc
+
+ char UDPMsg[1024];
+ int udplen;
+
+ if (NodeAPISocket)
+ {
+ if (LINK->receivingCall[0] == 0 || LINK->callingCall[0] == 0)
+ return;
+
+ if (strcmp(Direction, "Out") == 0)
+ udplen = sprintf(UDPMsg, "{\"@type\":\"LinkDownEvent\", \"node\": \"%s\", \"id\": %d, \"direction\": \"outgoing\", \"port\": \"%d\", \"remote\": \"%s\", \"local\": \"%s\","
+ "\"bytesSent\": %d, \"bytesRcvd\": %d, \"frmsSent\": %d, \"frmsRcvd\": %d, \"frmsQueued\": %d, \"frmsResent\": %d, \"reason\": \"%s\"}",
+ NODECALLLOPPED, UDPSeq++, LINK->LINKPORT->PORTNUMBER, LINK->receivingCall, LINK->callingCall,
+ LINK->bytesTXed , LINK->bytesRXed, LINK->framesTXed, LINK->framesRXed, COUNT_AT_L2(LINK), LINK->framesResent, Reason);
+ else
+ udplen = sprintf(UDPMsg, "{\"@type\":\"LinkDownEvent\", \"node\": \"%s\", \"id\": %d, \"direction\": \"incoming\", \"port\": \"%d\", \"remote\": \"%s\", \"local\": \"%s\","
+ "\"bytesSent\": %d, \"bytesRcvd\": %d, \"frmsSent\": %d, \"frmsRcvd\": %d, \"frmsQueued\": %d, \"frmsResent\": %d, \"reason\": \"%s\"}",
+ NODECALLLOPPED, UDPSeq++, LINK->LINKPORT->PORTNUMBER, LINK->callingCall, LINK->receivingCall,
+ LINK->bytesTXed , LINK->bytesRXed, LINK->framesTXed, LINK->framesRXed, COUNT_AT_L2(LINK), LINK->framesResent, Reason);
+
+// Debugprintf(UDPMsg);
+
+ sendto(NodeAPISocket, UDPMsg, udplen, 0, (struct sockaddr *)&UDPreportdest, sizeof(UDPreportdest));
+ }
+}
+
+void hookL2SessionStatus(struct _LINKTABLE * LINK)
+{
+ // Send at regular intervals on open links
+
+ char UDPMsg[1024];
+ int udplen;
+
+ if (NodeAPISocket)
+ {
+ LINK->lastStatusSentTime = time(NULL);
+
+ if (strcmp(LINK->Direction, "Out") == 0)
+ udplen = sprintf(UDPMsg, "{\"@type\":\"LinkStatus\", \"node\": \"%s\", \"id\": %d, \"direction\": \"outgoing\", \"port\": \"%d\", \"remote\": \"%s\", \"local\": \"%s\","
+ "\"bytesSent\": %d, \"bytesRcvd\": %d, \"frmsSent\": %d, \"frmsRcvd\": %d, \"frmsQueued\": %d, \"frmsResent\": %d}",
+ NODECALLLOPPED, UDPSeq++, LINK->LINKPORT->PORTNUMBER, LINK->receivingCall, LINK->callingCall,
+ LINK->bytesTXed , LINK->bytesRXed, LINK->framesTXed, LINK->framesRXed, 0, LINK->framesResent);
+ else
+ udplen = sprintf(UDPMsg, "{\"@type\":\"LinkStatus\", \"node\": \"%s\", \"id\": %d, \"direction\": \"incoming\", \"port\": \"%d\", \"remote\": \"%s\", \"local\": \"%s\","
+ "\"bytesSent\": %d, \"bytesRcvd\": %d, \"frmsSent\": %d, \"frmsRcvd\": %d, \"frmsQueued\": %d, \"frmsResent\": %d}",
+ NODECALLLOPPED, UDPSeq++, LINK->LINKPORT->PORTNUMBER, LINK->callingCall, LINK->receivingCall,
+ LINK->bytesTXed , LINK->bytesRXed, LINK->framesTXed, LINK->framesRXed, COUNT_AT_L2(LINK), LINK->framesResent);
+
+// Debugprintf(UDPMsg);
+
+ sendto(NodeAPISocket, UDPMsg, udplen, 0, (struct sockaddr *)&UDPreportdest, sizeof(UDPreportdest));
}
}
@@ -316,3 +374,795 @@ void hookL4SessionDeleted(struct TNCINFO * TNC, struct STREAMINFO * STREAM)
}
+
+void hookNodeStarted()
+{
+ char UDPMsg[1024];
+ int udplen;
+#ifdef LINBPQ
+ char Software[80] = "LinBPQ";
+
+ if (sizeof(void *) == 4)
+ strcat(Software, "(32 bit)");
+#else
+ char Software[80] = "BPQ32";
+#endif
+
+ if (NodeAPISocket)
+ {
+ int ret;
+
+ udplen = sprintf(UDPMsg, "{\"@type\": \"NodeUpEvent\", \"nodeCall\": \"%s\", \"nodeAlias\": \"%s\", \"locator\": \"%s\","
+ "\"latitude\": %f, \"longitude\": %f, \"software\": \"%s\", \"version\": \"%s\"}",
+ NODECALLLOPPED, MYALIASLOPPED, LOC, LatFromLOC, LonFromLOC, Software, VersionString);
+
+ ret = sendto(NodeAPISocket, UDPMsg, udplen, 0, (struct sockaddr *)&UDPreportdest, sizeof(UDPreportdest));
+
+ if (ret != udplen)
+ Debugprintf("%d %d %s", ret, WSAGetLastError(), UDPMsg);
+
+ }
+}
+
+
+void hookNodeClosing(char * Reason)
+{
+ char UDPMsg[1024];
+ int udplen;
+
+ if (NodeAPISocket)
+ {
+ udplen = sprintf(UDPMsg, "{\"@type\": \"NodeDownEvent\", \"nodeCall\": \"%s\", \"nodeAlias\": \"%s\", \"reason\": \"%s\"}",
+ NODECALLLOPPED, MYALIASLOPPED, Reason);
+
+// Debugprintf(UDPMsg);
+
+ sendto(NodeAPISocket, UDPMsg, udplen, 0, (struct sockaddr *)&UDPreportdest, sizeof(UDPreportdest));
+ }
+}
+
+void hookNodeRunning()
+{
+ char UDPMsg[1024];
+ int udplen;
+#ifdef LINBPQ
+ char Software[80] = "LinBPQ";
+
+ if (sizeof(void *) == 4)
+ strcat(Software, "(32 bit)");
+#else
+ char Software[80] = "BPQ32";
+#endif
+
+ if (NodeAPISocket)
+ {
+
+ udplen = sprintf(UDPMsg, "{\"@type\": \"NodeStatus\", \"nodeCall\": \"%s\", \"nodeAlias\": \"%s\", \"locator\": \"%s\","
+ "\"latitude\": %f, \"longitude\": %f, \"software\": \"%s\", \"version\": \"%s\", \"uptimeSecs\": %d}",
+ NODECALLLOPPED, MYALIASLOPPED, LOC, LatFromLOC, LonFromLOC, Software, VersionString, time(NULL) - TimeLoaded);
+
+
+// Debugprintf(UDPMsg);
+
+ sendto(NodeAPISocket, UDPMsg, udplen, 0, (struct sockaddr *)&UDPreportdest, sizeof(UDPreportdest));
+ }
+}
+
+void IncomingL4ConnectionEvent(TRANSPORTENTRY * L4)
+{
+ char UDPMsg[1024];
+ int udplen;
+
+ char remotecall[64];
+ char ourcall[64];
+ char circuitinfo[32];
+
+ // CACK sent to CREQ
+
+ if (NodeAPISocket)
+ {
+ remotecall[ConvFromAX25(L4->L4TARGET.DEST->DEST_CALL, remotecall)] = 0;
+ // remotecall[ConvFromAX25(L4->L4USER, remotecall)] = 0;
+ ourcall[ConvFromAX25(L4->L4MYCALL, ourcall)] = 0;
+
+ sprintf(circuitinfo, ":%02x%02x", L4->FARINDEX, L4->FARID);
+ strcat(remotecall, circuitinfo);
+
+ sprintf(circuitinfo, ":%02x%02x", L4->CIRCUITINDEX, L4->CIRCUITID);
+ strcat(ourcall, circuitinfo);
+
+ udplen = sprintf(UDPMsg, "{\"@type\": \"CircuitUpEvent\", \"node\": \"%s\", \"id\": %d, \"direction\": \"incoming\","
+ "\"service\": %d, \"remote\": \"%s\", \"local\": \"%s\"}",
+ NODECALLLOPPED, UDPSeq++, L4->Service, remotecall, ourcall);
+
+// Debugprintf(UDPMsg);
+ sendto(NodeAPISocket, UDPMsg, udplen, 0, (struct sockaddr *)&UDPreportdest, sizeof(UDPreportdest));
+ }
+}
+
+
+void OutgoingL4ConnectionEvent(TRANSPORTENTRY * L4)
+{
+ char UDPMsg[1024];
+ int udplen;
+ char remotecall[64];
+ char ourcall[64];
+ char circuitinfo[32];
+
+ // CACK received
+
+ if (NodeAPISocket)
+ {
+ remotecall[ConvFromAX25(L4->L4TARGET.DEST->DEST_CALL, remotecall)] = 0;
+ // remotecall[ConvFromAX25(L4->L4USER, remotecall)] = 0;
+ ourcall[ConvFromAX25(L4->L4MYCALL, ourcall)] = 0;
+
+ sprintf(circuitinfo, ":%02x%02x", L4->FARID, L4->FARINDEX);
+ strcat(remotecall, circuitinfo);
+
+ sprintf(circuitinfo, ":%02x%02x", L4->CIRCUITID, L4->CIRCUITINDEX);
+ strcat(ourcall, circuitinfo);
+
+ udplen = sprintf(UDPMsg, "{\"@type\": \"CircuitUpEvent\", \"node\": \"%s\", \"id\": %d, \"direction\": \"outgoing\","
+ "\"service\": %d, \"remote\": \"%s\", \"local\": \"%s\"}",
+ NODECALLLOPPED, UDPSeq++, L4->Service, remotecall, ourcall);
+
+// Debugprintf(UDPMsg);
+ sendto(NodeAPISocket, UDPMsg, udplen, 0, (struct sockaddr *)&UDPreportdest, sizeof(UDPreportdest));
+ }
+}
+
+/*
+ {
+ "@type": "CircuitUpEvent",
+ "node": "G8PZT"
+ "id": 1,
+ "direction": "incoming",
+ "service": 0,
+ "remote": "G8PZT@G8PZT:14c0",
+ "local": "G8PZT-4:0001"
+ }
+
+
+ "segsSent": 5,
+ "segsRcvd": 27,
+ "segsResent": 0,
+ "segsQueued": 0,
+ "reason": "rcvd DREQ"
+
+*/
+
+void L4DisconnectEvent(TRANSPORTENTRY * L4, char * Direction, char * Reason)
+{
+ char UDPMsg[1024];
+ int udplen;
+ char remotecall[64];
+ char ourcall[64];
+ char circuitinfo[32];
+ int Count;
+
+ // CACK received
+
+ if (NodeAPISocket)
+ {
+ remotecall[ConvFromAX25(L4->L4TARGET.DEST->DEST_CALL, remotecall)] = 0;
+// remotecall[ConvFromAX25(L4->L4USER, remotecall)] = 0;
+ ourcall[ConvFromAX25(L4->L4MYCALL, ourcall)] = 0;
+
+ sprintf(circuitinfo, ":%02x%02x", L4->FARINDEX, L4->FARID);
+ strcat(remotecall, circuitinfo);
+
+ sprintf(circuitinfo, ":%02x%02x", L4->CIRCUITINDEX, L4->CIRCUITID);
+ strcat(ourcall, circuitinfo);
+
+
+ if (L4->L4CROSSLINK) // CONNECTED?
+ Count = CountFramesQueuedOnSession(L4->L4CROSSLINK);
+ else
+ Count = CountFramesQueuedOnSession(L4);
+
+ udplen = sprintf(UDPMsg, "{\"@type\": \"CircuitDownEvent\", \"node\": \"%s\", \"id\": %d, \"direction\": \"%s\","
+ "\"service\": %d, \"remote\": \"%s\", \"local\": \"%s\", \"segsSent\": %d, \"segsRcvd\": %d, \"segsResent\": %d, \"segsQueued\": %d, \"reason\": \"%s\"}",
+ NODECALLLOPPED, UDPSeq++, Direction, 0, remotecall, ourcall,L4->segsSent, L4->segsRcvd, L4->segsResent, Count, Reason);
+
+// Debugprintf(UDPMsg);
+ sendto(NodeAPISocket, UDPMsg, udplen, 0, (struct sockaddr *)&UDPreportdest, sizeof(UDPreportdest));
+ }
+}
+
+void L4StatusSeport(TRANSPORTENTRY * L4)
+{
+ char UDPMsg[1024];
+ int udplen;
+ char remotecall[64];
+ char ourcall[64];
+ char nodecall[16];
+ char circuitinfo[32];
+ int Count;
+
+ // CACK received
+
+ if (NodeAPISocket)
+ {
+ nodecall[ConvFromAX25(L4->L4TARGET.DEST->DEST_CALL, nodecall)] = 0;
+ remotecall[ConvFromAX25(L4->L4USER, remotecall)] = 0;
+ ourcall[ConvFromAX25(L4->L4MYCALL, ourcall)] = 0;
+
+ sprintf(circuitinfo, ":%02x%02x", L4->FARINDEX, L4->FARID);
+ strcat(remotecall, circuitinfo);
+
+ sprintf(circuitinfo, ":%02x%02x", L4->CIRCUITINDEX, L4->CIRCUITID);
+ strcat(ourcall, circuitinfo);
+
+
+ if (L4->L4CROSSLINK) // CONNECTED?
+ Count = CountFramesQueuedOnSession(L4->L4CROSSLINK);
+ else
+ Count = CountFramesQueuedOnSession(L4);
+
+ udplen = sprintf(UDPMsg, "{\"@type\": \"CircuitStatus\", \"node\": \"%s\", \"id\": %d, \"direction\": \"outgoing\","
+ "\"service\": %d, \"remote\": %s, \"local\": \"%s\", \"segsSent\": %d, \"segsRcvd\": %d, \"segsResent\": %d, \"segsQueued\": %d}",
+ NODECALLLOPPED, UDPSeq++, 0, remotecall, ourcall,L4->segsSent, L4->segsRcvd, L4->segsResent, Count);
+
+// Debugprintf(UDPMsg);
+ sendto(NodeAPISocket, UDPMsg, udplen, 0, (struct sockaddr *)&UDPreportdest, sizeof(UDPreportdest));
+ }
+}
+
+
+// L2/3/4 Tracing
+
+#define PFBIT 0x10 // POLL/FINAL BIT IN CONTROL BYTE
+#define NETROM_PID 0xCF
+#define IP_PID 0xCC
+#define ARP_PID 0xCD
+
+char * PIDtoText(int PID)
+{
+ switch (PID)
+ {
+ case 240:
+ return "DATA";
+ case NETROM_PID:
+ return "NET/ROM";
+ case IP_PID:
+ return "IP";
+ case ARP_PID:
+ return "ARP";
+ }
+ return "?";
+}
+
+void APIL2Trace(struct _MESSAGE * Message, char Dirn)
+{
+ char UDPMsg[2048];
+ int udplen;
+ char srcecall[64];
+ char destcall[16];
+ char CR[3] = "";
+ char PF[2] = "";
+ int iLen = 0;
+ int CTL = Message->CTL;
+ char Type[16] = "Unknown";
+ int UIFlag = 0;
+ int IFlag = 0;
+ int UFlag = 0;
+ int NS;
+ int NR;
+
+ if ((Message->ORIGIN[6] & 1) == 0) // Digis
+ return;
+
+ destcall[ConvFromAX25(Message->DEST, destcall)] = 0;
+ srcecall[ConvFromAX25(Message->ORIGIN, srcecall)] = 0;
+
+ // See if any Digis
+
+ if ((Message->ORIGIN[6] & 1) == 0) // Digis - ignore for now
+ return;
+
+
+ if ((Message->DEST[6] & 0x80) == 0 && (Message->ORIGIN[6] & 0x80) == 0)
+ strcpy(CR, "V1");
+ else if ((Message->DEST[6] & 0x80))
+ strcpy(CR, "C");
+ else if (Message->ORIGIN[6] & 0x80)
+ strcpy(CR, "R");
+ else
+ strcpy(CR, "V1");
+
+ if (CTL & PFBIT)
+ {
+ if (CR[0] == 'C')
+ PF[0] = 'P';
+ else if (CR[0] == 'R')
+ PF[0] = 'F';
+ }
+
+ CTL &= ~PFBIT;
+
+ if ((CTL & 1) == 0) // I frame
+ {
+ NS = (CTL >> 1) & 7; // ISOLATE RECEIVED N(S)
+ NR = (CTL >> 5) & 7;
+
+ IFlag = 1;
+ iLen = Message->LENGTH - (MSGHDDRLEN + 16); // Dest origin ctl pid
+
+ strcpy(Type, "I");
+ }
+ else if (CTL == 3)
+ {
+ // Un-numbered Information Frame
+
+ strcpy(Type, "UI");
+ UIFlag = 1;
+ iLen = Message->LENGTH - (MSGHDDRLEN + 16); // Dest origin ctl pid
+ }
+
+ if (CTL & 2)
+ {
+ // UnNumbered
+
+ UFlag = 1;
+
+ switch (CTL)
+ {
+ case SABM:
+
+ strcpy(Type, "C");
+ break;
+
+ case SABME:
+
+ strcpy(Type, "SABME");
+ break;
+
+ case XID:
+
+ strcpy(Type, "XID");
+ break;
+
+ case TEST:
+
+ strcpy(Type, "TEST");
+ break;
+
+ case DISC:
+
+ strcpy(Type, "D");
+ break;
+
+ case DM:
+
+ strcpy(Type, "DM");
+ break;
+
+ case UA:
+
+ strcpy(Type, "UA");
+ break;
+
+
+ case FRMR:
+
+ strcpy(Type, "FRMR");
+ break;
+ }
+ }
+ else
+ {
+ // Super
+
+ NR = (CTL >> 5) & 7;
+ NS = (CTL >> 1) & 7; // ISOLATE RECEIVED N(S)
+
+ switch (CTL & 0x0F)
+ {
+ case RR:
+
+ strcpy(Type, "RR");
+ break;
+
+ case RNR:
+
+ strcpy(Type, "RNR");
+ break;
+
+ case REJ:
+
+ strcpy(Type, "REJ");
+ break;
+
+ case SREJ:
+
+ strcpy(Type, "SREJ");
+ break;
+ }
+ }
+
+ // Common to all frame types
+
+ udplen = snprintf(UDPMsg, 2048,
+ "{\"@type\": \"L2Trace\", \"reportFrom\": \"%s\", \"port\": \"%d\", \"srce\": \"%s\", \"dest\": \"%s\", \"ctrl\": %d,"
+ "\"l2type\": \"%s\", \"modulo\": 8, \"cr\": \"%s\"",
+ NODECALLLOPPED, Message->PORT, srcecall, destcall, Message->CTL, Type, CR);
+
+ if (UIFlag)
+ {
+ udplen += snprintf(&UDPMsg[udplen], 2048 - udplen,
+ ", \"ilen\": %d, \"pid\": %d, \"ptcl\": \"%s\"", iLen, Message->PID, PIDtoText(Message->PID));
+
+ if (Message->PID == NETROM_PID)
+ {
+ udplen += decodeNETROMUIMsg(Message->L2DATA, iLen, &UDPMsg[udplen], 2048 - udplen);
+ }
+ }
+ else if (IFlag)
+ {
+ if (PF[0])
+ udplen += snprintf(&UDPMsg[udplen], 2048 - udplen,
+ ", \"ilen\": %d, \"pid\": %d, \"ptcl\": \"%s\", \"pf\": \"%s\", \"rseq\": %d, \"tseq\": %d",
+ iLen, Message->PID, PIDtoText(Message->PID), PF, NR, NS);
+ else
+ udplen += snprintf(&UDPMsg[udplen], 2048 - udplen,
+ ", \"ilen\": %d, \"pid\": %d, \"ptcl\": \"%s\", \"rseq\": %d, \"tseq\": %d",
+ iLen, Message->PID, PIDtoText(Message->PID), NR, NS);
+
+ if (Message->PID == NETROM_PID)
+ {
+ int n = decodeNETROMIFrame(Message->L2DATA, iLen, &UDPMsg[udplen], 2048 - udplen);
+
+ if (n == 0)
+ return; // Can't decode so don't trace anything;
+
+ udplen += n;
+ }
+
+ }
+ else if (UFlag)
+ {
+ if (PF[0])
+ udplen += snprintf(&UDPMsg[udplen], 2048 - udplen, ", \"pf\": \"%s\"", PF);
+ }
+ else
+ {
+ // supervisory
+
+ if (PF[0])
+ udplen += snprintf(&UDPMsg[udplen], 2048 - udplen, ", \"pf\": \"%s\", \"rseq\": %d, \"tseq\": %d", PF, NR, NS);
+ else
+ udplen += snprintf(&UDPMsg[udplen], 2048 - udplen, ", \"rseq\": %d, \"tseq\": %d", NR, NS);
+ }
+
+
+ UDPMsg[udplen++] = '}';
+ UDPMsg[udplen] = 0;
+// Debugprintf(UDPMsg);
+ sendto(NodeAPISocket, UDPMsg, udplen, 0, (struct sockaddr *)&UDPreportdest, sizeof(UDPreportdest));
+
+}
+
+
+int decodeNETROMUIMsg(unsigned char * Msg, int iLen, char * Buffer, int BufferLen)
+{
+ int Len = 0;
+
+ // UI with NETROM PID are assumed to by NODES broadcast (INP3 routes are sent in I frames)
+
+ // But check first byte is 0xff to be sure, or 0xfe for Paula's char Alias[7]= "";
+
+ char Dest[10];
+ char Node[10];
+ char Alias[10] = "";
+
+ memcpy(Alias, &Msg[1], 6);
+ strlop(Alias, ' ');
+
+ if (Msg[0] == 0xfe) // Paula's Nodes Poll
+ {
+ Len = snprintf(Buffer, BufferLen, ", \"l3Type\": \"Routing info\", \"type\": \"Routing poll\"");
+ return Len;
+ }
+
+ if (Msg[0] != 0xff)
+ return 0;
+
+ Msg += 7; // to first field
+
+ Len = snprintf(Buffer, BufferLen, ", \"l3Type\": \"Routing info\", \"type\": \"NODES\", \"nodes\": [");
+
+ iLen -= 7; //Header, mnemonic and signature length
+
+ if (iLen < 21) // No Entries
+ {
+ Buffer[Len++] = ']';
+ return Len;
+ }
+
+ while(iLen > 20) // Entries are 21 bytes
+ {
+ Dest[ConvFromAX25(Msg, Dest)] = 0;
+ Msg +=7;
+ memcpy(Alias, Msg, 6);
+ Msg +=6;
+ strlop(Alias, ' ');
+ Node[ConvFromAX25(Msg, Node)] = 0;
+ Msg +=7;
+
+ Len += snprintf(&Buffer[Len], BufferLen - Len, "{\"call\": \"%s\", \"alias\": \"%s\", \"via\": \"%s\", \"qual\": %d},", Dest, Alias, Node, Msg[0]);
+ Msg++;
+ iLen -= 21;
+ }
+ // Have to replace trailing , with ]
+
+ Buffer[Len - 1] = ']';
+ return Len;
+}
+
+int decodeNETROMIFrame(unsigned char * Msg, int iLen, char * Buffer, int BufferLen)
+{
+ int Len = 0;
+ L3MESSAGE * L3MSG = (L3MESSAGE *)Msg;
+ char srcecall[64];
+ char destcall[16];
+ char srcUser[16];
+ char srcNode[16];
+ int Opcode;
+ int netromx = 0;
+ int service = 0;
+
+
+ if (Msg[0] == 0xff) // RIF?
+ return decodeINP3RIF(&Msg[1], iLen - 1, Buffer, BufferLen);
+
+ // Netrom L3 /4 frame. Do standard L3 header
+
+ destcall[ConvFromAX25(L3MSG->L3DEST, destcall)] = 0;
+ srcecall[ConvFromAX25(L3MSG->L3SRCE, srcecall)] = 0;
+
+ if (strcmp(destcall, "KEEPLI") == 0)
+ return 0;
+
+ Len = snprintf(Buffer, BufferLen, ", \"l3Type\": \"NetRom\", \"l3src\": \"%s\", \"l3dst\": \"%s\", \"ttl\": %d", srcecall, destcall, L3MSG->L3TTL);
+
+ // L4 Stuff
+
+ Opcode = L3MSG->L4FLAGS & 15;
+
+ switch (Opcode)
+ {
+ case 0:
+
+ // OPCODE 0 is used for a variety of functions, using L4INDEX and L4ID as qualifiers
+ // 0c0c is used for IP. Ignore for now
+
+ // 00 01 Seesm to be Netrom Record Route
+
+ if (L3MSG->L4ID == 1 && L3MSG->L4INDEX == 0)
+ {
+ Len += decodeRecordRoute(L3MSG, iLen, &Buffer[Len], BufferLen - Len);
+ return Len;
+ }
+
+ case L4CREQX:
+
+ netromx = 1;
+ service = (L3MSG->L4RXNO << 8) | L3MSG->L4TXNO;
+
+ case L4CREQ:
+
+ srcUser[ConvFromAX25(&L3MSG->L4DATA[1], srcUser)] = 0;
+ srcNode[ConvFromAX25(&L3MSG->L4DATA[8], srcNode)] = 0;
+
+ if (netromx)
+ Len += snprintf(&Buffer[Len], BufferLen - Len, ", \"l4Type\": \"CONN REQX\", \"fromCct\": %d, \"srcUser\": \"%s\", \"srcNode\": \"%s\", \"window\": %d, \"service\": %d",
+ (L3MSG->L4INDEX << 8) | L3MSG->L4ID, srcUser, srcNode, L3MSG->L4DATA[0], service);
+ else
+ Len += snprintf(&Buffer[Len], BufferLen - Len, ", \"l4Type\": \"CONN REQ\", \"fromCct\": %d, \"srcUser\": \"%s\", \"srcNode\": \"%s\", \"window\": %d",
+ (L3MSG->L4INDEX << 8) | L3MSG->L4ID, srcUser, srcNode, L3MSG->L4DATA[0]);
+
+ return Len;
+
+ case L4CACK:
+
+ // Can be ACK or NACK depending on Choke flag
+
+ if (L3MSG->L4FLAGS & L4BUSY)
+ Len += snprintf(&Buffer[Len], BufferLen - Len, ", \"l4Type\": \"CONN NACK\", \"toCct\": %d",
+ (L3MSG->L4INDEX << 8) | L3MSG->L4ID);
+ else
+ Len += snprintf(&Buffer[Len], BufferLen - Len, ", \"l4Type\": \"CONN ACK\", \"toCct\": %d, \"fromCct\": %d, \"accWin\": %d",
+ (L3MSG->L4INDEX << 8) | L3MSG->L4ID, (L3MSG->L4TXNO << 8) | L3MSG->L4RXNO, L3MSG->L4DATA[0]);
+
+ return Len;
+
+
+ case L4INFO:
+
+ Len += snprintf(&Buffer[Len], BufferLen - Len, ", \"l4Type\": \"INFO\", \"toCct\": %d, \"txSeq\": %d, \"rxSeq\": %d, \"paylen\": %d",
+ (L3MSG->L4INDEX << 8) | L3MSG->L4ID, L3MSG->L4TXNO, L3MSG->L4RXNO, iLen - 20);
+
+ return Len;
+
+ case L4IACK:
+
+ Len += snprintf(&Buffer[Len], BufferLen - Len, ", \"l4Type\": \"INFO ACK\", \"toCct\": %d, \"rxSeq\": %d",
+ (L3MSG->L4INDEX << 8) | L3MSG->L4ID, L3MSG->L4RXNO);
+
+ return Len;
+
+
+ case L4DREQ:
+
+ Len += snprintf(&Buffer[Len], BufferLen - Len, ", \"l4Type\": \"DISC REQ\", \"toCct\": %d", (L3MSG->L4INDEX << 8) | L3MSG->L4ID);
+ return Len;
+
+ case L4DACK:
+
+ Len += snprintf(&Buffer[Len], BufferLen - Len, ", \"l4Type\": \"DISC ACK\", \"toCct\": %d", (L3MSG->L4INDEX << 8) | L3MSG->L4ID);
+ return Len;
+
+ case L4RESET:
+
+ Len += snprintf(&Buffer[Len], BufferLen - Len, ", \"l4Type\": \"RSET\", \"fromCct\": %d", (L3MSG->L4INDEX << 8) | L3MSG->L4ID);
+ return Len;
+
+
+ /*
+ "NRR Request" Netrom Record Route Request
+ "NRR Reply" Netrom Record Route Reply
+ "CONN REQ" Connect Request
+ "CONN REQX" Extended Connect Request
+ "CONN ACK" Connection Acknowledgement
+ "CONN NAK" Connection Negative Ack (refusal)
+ "DISC REQ" Disconnect request
+ "DISC ACK" Disconnect Acknowledgement
+ "INFO" Information-bearing frame
+ "INFO ACK" Acknowledgement for an INFO frame.
+ "RSET" Circuit Reset (kill)
+ "PROT EXT" Protocol Extension (e.g. IP, NCMP etc)
+ "unknown" Unrecognised type (shouldn't happen)
+
+
+
+
+ "l4type": "CONN ACK",
+ "fromCct": 10,
+ "toCct": 23809,
+ "accWin": 4,
+ */
+
+ }
+ return Len;
+}
+
+int decodeRecordRoute(L3MESSAGE * L3, int iLen, char * Buffer, int BufferLen)
+{
+ int Len = 0;
+ char callList[512];
+ char * ptr1 = callList;
+ unsigned char * ptr = L3->L4DATA;
+ char call[16];
+ int Response = 0;
+
+ iLen -= 20;
+
+ while (iLen > 0)
+ {
+ call[ConvFromAX25(ptr, call)] = 0;
+
+ ptr1 += sprintf(ptr1, " %s", call);
+
+ if ((ptr[7] & 0x80) == 0x80) // Check turnround bit
+ {
+ *ptr1++ = '*';
+ Response = 1;
+ }
+
+ ptr += 8;
+ iLen -= 8;
+ }
+
+ *ptr1 = 0;
+
+ if (Response)
+ Len += snprintf(&Buffer[Len], BufferLen - Len, ", \"l4Type\": \"NRR Reply\", \"nrrId\": %d, \"nrrRoute\": \"%s\"",
+ (L3->L4TXNO << 8) | L3->L4RXNO, callList);
+ else
+ Len += snprintf(&Buffer[Len], BufferLen - Len, ", \"l4Type\": \"NRR Request\", \"nrrId\": %d, \"nrrRoute\": \"%s\"",
+ (L3->L4TXNO << 8) | L3->L4RXNO, callList);
+
+ Debugprintf(Buffer);
+
+ return Len;
+}
+
+
+int decodeINP3RIF(unsigned char * Msg, int iLen, char * Buffer, int BufferLen)
+{
+ char call[10];
+ int calllen;
+ int hops;
+ unsigned short rtt;
+ unsigned int len;
+ unsigned int opcode;
+ char alias[10] = "";
+ UCHAR IP[6];
+ int i;
+ int Len = 0;
+
+ Len = snprintf(Buffer, BufferLen, ", \"l3Type\": \"Routing info\", \"type\": \"INP3\", \"nodes\": [");
+
+ if (iLen < 10) // No Entries
+ {
+ Buffer[Len++] = ']';
+ return Len;
+ }
+
+ while (iLen > 1)
+ {
+ calllen = ConvFromAX25(Msg, call);
+ call[calllen] = 0;
+
+ // Validate the call
+
+ for (i = 0; i < calllen; i++)
+ {
+ if (!isupper(call[i]) && !isdigit(call[i]) && call[i] != '-')
+ return 0;
+ }
+
+ Msg+=7;
+
+ hops = *Msg++;
+ rtt = (*Msg++ << 8);
+ rtt += *Msg++;
+
+ IP[0] = 0;
+ strcpy(alias, " ");
+
+ iLen -= 10;
+
+ // Process optional fields
+
+ while (*Msg && iLen > 0) // Have an option
+ {
+ len = *Msg;
+ opcode = *(Msg+1);
+
+ if (len < 2 || len > iLen)
+ return 0;
+
+ if (opcode == 0 && len < 9)
+ {
+ memcpy(alias, Msg+2, len-2);
+ }
+ else if (opcode == 1 && len < 8)
+ {
+ memcpy(IP, Msg+2, len-2);
+ }
+
+ Msg += len;
+ iLen -= len;
+
+ }
+
+ Len += snprintf(&Buffer[Len], BufferLen - Len, "{\"call\": \"%s\", \"hops\": %d, \"tt\": %d", call, hops, rtt);
+
+ if (alias[0] > ' ')
+ Len += snprintf(&Buffer[Len], BufferLen - Len, ", \"alias\": \"%s\"", alias);
+
+ Buffer[Len++] = '}';
+ Buffer[Len++] = ',';
+
+ Msg++;
+ iLen--; // Over EOP
+
+ }
+ // Have to replace trailing , with ]
+
+ Buffer[Len - 1] = ']';
+ return Len;
+}
+
diff --git a/FLDigi.c b/FLDigi.c
index 59d9008..d0ec34c 100644
--- a/FLDigi.c
+++ b/FLDigi.c
@@ -36,6 +36,12 @@ extern int (WINAPI FAR *EnumProcessesPtr)();
#include "bpq32.h"
+
+void hookL4SessionAttempt(struct STREAMINFO * , char * remotecall, char * ourcall);
+void hookL4SessionAccepted(struct STREAMINFO * , char * remotecall, char * ourcall);
+void hookL4SessionDeleted(struct TNCINFO * TNC, void * STREAM);
+
+
#define VERSION_MAJOR 2
#define VERSION_MINOR 0
@@ -819,7 +825,7 @@ pollloop:
char outbuff[1000];
int newlen;
- buff->L2DATA[-1] = 6; // KISS Control
+ buff->PID = 6; // KISS Control (PID is just before Data)
newlen = KissEncode(&buff->L2DATA[-1], outbuff, txlen);
sendto(TNC->TCPDataSock, outbuff, newlen, 0, (struct sockaddr *)&TNC->Datadestaddr, sizeof(struct sockaddr));
diff --git a/FreeDATA.c b/FreeDATA.c
index ac1cb65..75951ee 100644
--- a/FreeDATA.c
+++ b/FreeDATA.c
@@ -43,6 +43,11 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
int KillTNC(struct TNCINFO * TNC);
static int RestartTNC(struct TNCINFO * TNC);
+
+void hookL4SessionAttempt(struct STREAMINFO * , char * remotecall, char * ourcall);
+void hookL4SessionAccepted(struct STREAMINFO * , char * remotecall, char * ourcall);
+void hookL4SessionDeleted(struct TNCINFO * TNC, void * STREAM);
+
extern int (WINAPI FAR *GetModuleFileNameExPtr)();
extern int (WINAPI FAR *EnumProcessesPtr)();
static int Socket_Data(int sock, int error, int eventcode);
diff --git a/L2Code.c b/L2Code.c
index c0da433..8171d49 100644
--- a/L2Code.c
+++ b/L2Code.c
@@ -125,9 +125,14 @@ void hookL2SessionConnected(struct _LINKTABLE * LINK);
int L2Compressit(unsigned char * Out, int OutSize, unsigned char * In, int Len);
VOID DeleteINP3Routes(struct ROUTE * Route);
VOID SendRTTMsg(struct ROUTE * Route);
+void hookL2SessionStatus(struct _LINKTABLE * LINK);
+void hookL2SessionClosed(struct _LINKTABLE * LINK, char * Reason, char * Direction);
+int NETROMOpenConnection(struct ROUTE * Route);
extern int REALTIMETICKS;
+int linkStatusInterval = 300; // 5 mins
+
// MSGFLAG contains CMD/RESPONSE BITS
#define CMDBIT 4 // CURRENT MESSAGE IS A COMMAND
@@ -142,6 +147,7 @@ extern int REALTIMETICKS;
extern int L2Compress;
extern int L2CompMaxframe;
extern int L2CompPaclen;
+extern BOOL CLOSING;
UCHAR NO_CTEXT = 0;
UCHAR ALIASMSG = 0;
@@ -1081,6 +1087,7 @@ VOID L2LINKACTIVE(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESSAGE *
if (CTLlessPF == DISC)
{
InformPartner(LINK, NORMALCLOSE); // SEND DISC TO OTHER END
+ hookL2SessionClosed(LINK, "Normal", "In");
CLEAROUTLINK(LINK);
L2SENDUA(PORT, Buffer, ADJBUFFER);
@@ -1276,9 +1283,13 @@ VOID L2SABM(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESSAGE * Buffe
int CONERROR;
struct ROUTE * ROUTE = NULL;
-
char toCall[12], fromCall[12];
+ if (CLOSING)
+ {
+ L2SENDDM(PORT, Buffer, ADJBUFFER);
+ return;
+ }
if (LINK == 0) // NO LINK ENTRIES - SEND DM RESPONSE
{
@@ -1839,6 +1850,16 @@ BOOL InternalL2SETUPCROSSLINK(PROUTE ROUTE, int Retries)
struct PORTCONTROL * PORT;
int FRACK;
+ // If it is NETROM Over TCP then check for existing connection
+
+ if (ROUTE->TCPPort)
+ {
+ if (strcmp(ROUTE->TCPHost, "0.0.0.0") == 0) // listening connection so wait for other end to connect
+ return FALSE;
+
+ return NETROMOpenConnection(ROUTE);
+ }
+
if (FindLink(ROUTE->NEIGHBOUR_CALL, NETROMCALL, ROUTE->NEIGHBOUR_PORT, &LINK))
{
// SESSION ALREADY EXISTS
@@ -2050,6 +2071,8 @@ VOID L2_PROCESS(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESSAGE * B
if (FindNeighbour(Buffer->ORIGIN, PORT->PORTNUMBER, &ROUTE))
{
+ ROUTE->ConnectionAttempts = 0; // Reset counter
+
if (ROUTE->INP3Node)
{
Debugprintf("INP3 Route to %s connected", fromCall);
@@ -2093,6 +2116,8 @@ VOID L2_PROCESS(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESSAGE * B
if (LINK->L2STATE == 4) // DISCONNECTING?
{
InformPartner(LINK, NORMALCLOSE); // SEND DISC TO OTHER END
+ hookL2SessionClosed(LINK, "Normal", "Out");
+
CLEAROUTLINK(LINK);
if (PORT->TNC && PORT->TNC->Hardware == H_KISSHF)
@@ -2255,6 +2280,13 @@ VOID SFRAME(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, UCHAR CTL, UCHA
MESSAGE * Msg;
MESSAGE * Buffer;
+ // it shouldn't be possible to get srej when all are acked (NS = Link->NS) but just in case...
+
+ if (NS == LINK->LINKNS)
+ {
+ Debugprintf ("SREJ for our NS");
+ goto treatasRR;
+ }
LINK->L2FLAGS &= ~POLLSENT; // CLEAR I(P) or RR(P) SET
Msg = LINK->FRAMES[NS]; // is frame available?
@@ -2332,6 +2364,9 @@ VOID SFRAME(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, UCHAR CTL, UCHA
return;
}
+treatasRR:
+
+
// VALID RR/RNR RECEIVED
LINK->L2FLAGS &= ~RNRSET; //CLEAR RNR
@@ -2664,6 +2699,7 @@ VOID PROC_I_FRAME(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESSAGE *
LINK->bytesRXed += Length;
LINK->Received += Length - 1; // Exclude PID
+ LINK->framesRXed++;
// Adjust for DIGIS
@@ -3239,6 +3275,10 @@ VOID SDETX(struct _LINKTABLE * LINK)
LINK->FRAMES[LINK->SDTSLOT] = Msg;
LINK->SDTSLOT ++;
LINK->SDTSLOT &= 7;
+
+ LINK->framesTXed++;
+ LINK->bytesTXed += sendLen;
+
compdata += sendLen;
complen -= sendLen;
@@ -3252,6 +3292,9 @@ VOID SDETX(struct _LINKTABLE * LINK)
LINK->FRAMES[LINK->SDTSLOT] = Msg;
LINK->SDTSLOT ++;
LINK->SDTSLOT &= 7;
+
+ LINK->framesTXed++;
+ LINK->bytesTXed += (Msg->LENGTH - (MSGHDDRLEN + 1));
}
}
@@ -3350,6 +3393,7 @@ VOID L2TimerProc()
int i = MAXLINKS;
struct _LINKTABLE * LINK = LINKS;
struct PORTCONTROL * PORT = PORTTABLE;
+ time_t Now = time(NULL);
while (i--)
{
@@ -3357,8 +3401,14 @@ VOID L2TimerProc()
{
LINK++;
continue;
- }
+ }
+ // Check for Status report time
+
+ if (LINK->lastStatusSentTime && (Now - LINK->lastStatusSentTime) > linkStatusInterval)
+ hookL2SessionStatus(LINK);
+
+
// CHECK FOR TIMER EXPIRY OR BUSY CLEARED
PORT = LINK->LINKPORT;
@@ -3721,6 +3771,8 @@ VOID L2TIMEOUT(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT)
{
// RETRIED N TIMES SEND A COUPLE OF DISCS AND THEN CLOSE
+ hookL2SessionClosed(LINK, "Retried Out", "Out");
+
InformPartner(LINK, RETRIEDOUT); // TELL OTHER END ITS GONE
LINK->L2RETRIES -= 1; // Just send one DISC
@@ -4100,20 +4152,21 @@ stayinREJ2:
goto CheckNSLoop2; // See if OK or we have another saved frame
}
if (LINK->L2STATE == 6)
+ {
+ // if we support SREJ send that instesd or REJ
- // if we support SREJ send that instesd or REJ
-
- // Dont send SREJ if clearing RNR - causes FRMR
+ // Dont send SREJ if clearing RNR - causes FRMR
- // Latest Spec says shouldn't send SREJ as Command
+ // Latest Spec says shouldn't send SREJ as Command
- if (SaveRNRSent || CMD == 1)
- return REJ;
+ if (SaveRNRSent || CMD == 1)
+ return REJ;
- if (LINK->Ver2point2) // We only allow 2.2 with SREJ Multi
- return SREJ;
- else
- return REJ;
+ if (LINK->Ver2point2) // We only allow 2.2 with SREJ Multi
+ return SREJ;
+ else
+ return REJ;
+ }
}
return RR;
@@ -4708,5 +4761,32 @@ int L2Compressit(unsigned char * Out, int OutSize, unsigned char * In, int Len)
}
+int CloseAllLinks()
+{
+ struct _LINKTABLE * LINK = LINKS;
+ int i = MAXLINKS;
+ int Closed = 0;
+
+ while (i--)
+ {
+ if (LINK->LINKCALL[0] == 0 || LINK->L2STATE !=5 )
+ {
+ LINK++;
+ continue;
+ }
+
+ // Close Link
+
+ InformPartner(LINK, NORMALCLOSE); // TELL OTHER END ITS GONE
+
+ LINK->L2RETRIES -= 1; // Just send one DISC
+ LINK->L2STATE = 4; // CLOSING
+
+ L2SENDCOMMAND(LINK, DISC | PFBIT);
+
+ Closed++;
+ }
+ return Closed;
+}
diff --git a/L3Code.c b/L3Code.c
index 22b46fb..c25df5b 100644
--- a/L3Code.c
+++ b/L3Code.c
@@ -61,9 +61,11 @@ VOID SendNETROMRoute(struct PORTCONTROL * PORT, unsigned char * axcall);
void SendVARANetromNodes(struct TNCINFO * TNC, MESSAGE *Buffer);
void SendVARANetromMsg(struct TNCINFO * TNC,L3MESSAGEBUFFER * Buffer);
VOID SENDNODESMSG(int Portnum);
+VOID TCPNETROMSend(struct ROUTE * Route, struct _L3MESSAGEBUFFER * Frame);
extern int NODESINPROGRESS;
extern int NODESToOnePort;
+extern int CLOSING;
extern BOOL NODESINPROGRESS ;;
PPORTCONTROL L3CURRENTPORT;
@@ -98,7 +100,15 @@ VOID L3BG()
{
ROUTE = DEST->NRROUTE[ActiveRoute - 1].ROUT_NEIGHBOUR;
- // if NetROM over VARA pass direct to the driver
+ // if NetROM over VARA or NetROM over TCP pass direct to the driver
+
+ if (ROUTE && ROUTE->TCPPort)
+ {
+ PL3MESSAGEBUFFER Frame = (PL3MESSAGEBUFFER)Q_REM(&DEST->DEST_Q);
+ TCPNETROMSend(ROUTE, Frame);
+ ReleaseBuffer(Frame);
+ continue;
+ }
if (ROUTE)
{
@@ -990,7 +1000,9 @@ VOID CLEARACTIVEROUTE(struct ROUTE * ROUTE, int Reason)
dest_list * DEST;
int n;
- if (Reason != NORMALCLOSE || ROUTE->INP3Node)
+ // If a link restarts and is no longer inp3 we must still clear any inp3 routes
+
+// if (Reason != NORMALCLOSE || ROUTE->INP3Node)
TellINP3LinkGone(ROUTE);
DEST = DESTS;
@@ -1121,6 +1133,11 @@ VOID L3FastTimer()
MESSAGE * Msg;
struct PORTCONTROL * PORT = PORTTABLE;
+ // Not if Node is closing
+
+ if (CLOSING)
+ return;
+
INP3TIMER();
// Send Node faster if VARA
diff --git a/L4Code.c b/L4Code.c
index 5416a17..ecfd5f0 100644
--- a/L4Code.c
+++ b/L4Code.c
@@ -49,7 +49,7 @@ BOOL FINDCIRCUIT(L3MESSAGEBUFFER * L3MSG, TRANSPORTENTRY ** REQL4, int * NewInde
int GETBUSYBIT(TRANSPORTENTRY * L4);
BOOL cATTACHTOBBS(TRANSPORTENTRY * Session, UINT Mask, int Paclen, int * AnySessions);
VOID SETUPNEWCIRCUIT(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * L3MSG,
- TRANSPORTENTRY * L4, char * BPQPARAMS, int ApplMask, int * BPQNODE);
+ TRANSPORTENTRY * L4, char * BPQPARAMS, int ApplMask, int * BPQNODE, int Service);
extern char * ALIASPTR;
void SendConACK(struct _LINKTABLE * LINK, TRANSPORTENTRY * L4, L3MESSAGEBUFFER * L3MSG, BOOL BPQNODE, UINT Applmask, UCHAR * ApplCall);
void L3SWAPADDRESSES(L3MESSAGEBUFFER * L3MSG);
@@ -69,6 +69,11 @@ void WriteConnectLog(char * fromCall, char * toCall, UCHAR * Mode);
void SendVARANetromMsg(struct TNCINFO * TNC, PL3MESSAGEBUFFER MSG);
int doinflate(unsigned char * source, unsigned char * dest, int Len, int destlen, int * outLen);
int L2Compressit(unsigned char * Out, int OutSize, unsigned char * In, int Len);
+void OutgoingL4ConnectionEvent(TRANSPORTENTRY * L4);
+void IncomingL4ConnectionEvent(TRANSPORTENTRY * L4);
+void L4DisconnectEvent(TRANSPORTENTRY * L4, char * Direction, char * Reason);
+VOID TCPNETROMSend(struct ROUTE * Route, struct _L3MESSAGEBUFFER * Frame);
+
static UINT APPLMASK;
extern BOOL LogL4Connects;
@@ -131,6 +136,14 @@ VOID NETROMMSG(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * L3MSG)
return;
}
+ // IS IT INP3 (L3RTT)
+
+ if (CompareCalls(L3MSG->L3DEST, L3RTT))
+ {
+ ProcessRTTMsg(LINK->NEIGHBOUR, L3MSG, L3MSG->LENGTH, L3MSG->Port);
+ return;
+ }
+
APPLMASK = 0; // NOT APPLICATION
if (NODE) // _NODE SUPPORT INCLUDED?
@@ -167,14 +180,6 @@ VOID NETROMMSG(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * L3MSG)
APPL++;
}
- // IS IT INP3 (L3RTT)
-
- if (CompareCalls(L3MSG->L3DEST, L3RTT))
- {
- ProcessRTTMsg(LINK->NEIGHBOUR, L3MSG, L3MSG->LENGTH, L3MSG->Port);
- return;
- }
-
L3MSG->L3TTL--;
if (L3MSG->L3TTL == 0)
@@ -455,7 +460,7 @@ VOID Q_IP_MSG(MESSAGE * Buffer)
ReleaseBuffer(Buffer);
}
-VOID SENDL4CONNECT(TRANSPORTENTRY * Session)
+VOID SENDL4CONNECT(TRANSPORTENTRY * Session, int Service)
{
PL3MESSAGEBUFFER MSG = (PL3MESSAGEBUFFER)GetBuff();
struct DEST_LIST * DEST = Session->L4TARGET.DEST;
@@ -479,12 +484,21 @@ VOID SENDL4CONNECT(TRANSPORTENTRY * Session)
MSG->L4INDEX = Session->CIRCUITINDEX;
MSG->L4ID = Session->CIRCUITID;
- MSG->L4TXNO = 0;
- MSG->L4RXNO = 0;
- MSG->L4FLAGS = L4CREQ;
- MSG->L4DATA[0] = L4DEFAULTWINDOW; // PROPOSED WINDOW
+ if (Service == -1) // Normal CREQ
+ {
+ MSG->L4RXNO = 0;
+ MSG->L4FLAGS = L4CREQ;
+ }
+ else
+ {
+ MSG->L4RXNO = Service << 8; // Paula's extended connect
+ MSG->L4TXNO = (Service & 0xff);
+ MSG->L4FLAGS = L4CREQX;
+ }
+ MSG->L4DATA[0] = L4DEFAULTWINDOW; // PROPOSED WINDOW
+
memcpy(&MSG->L4DATA[1], Session->L4USER, 7); // ORIG CALL
memcpy(&MSG->L4DATA[8], Session->L4MYCALL, 7);
@@ -858,8 +872,6 @@ VOID L4BG()
Msglen = Msg->LENGTH - (MSGHDDRLEN + 1); //Dont include PID
- LINK->bytesTXed += Msglen;
-
Paclen = L4->SESSPACLEN;
if (Paclen == 0)
@@ -1223,7 +1235,7 @@ VOID L4TIMEOUT(TRANSPORTENTRY * L4)
Debugprintf("Retrying L4 Connect Request");
- SENDL4CONNECT(L4); // Resend connect
+ SENDL4CONNECT(L4, L4->Service); // Resend connect
return;
}
@@ -1258,10 +1270,13 @@ VOID L4TIMEOUT(TRANSPORTENTRY * L4)
// if compressed session display stats
+ L4DisconnectEvent(L4, "outgoing", "Retried Out");
+
CloseSessionPartner(L4); // SEND CLOSE TO PARTNER (IF PRESENT)
return;
}
+
// RESEND ALL OUTSTANDING FRAMES
L4->FLAGS &= 0x7F; // CLEAR CHOKED
@@ -1568,19 +1583,25 @@ void WriteL4LogLine(UCHAR * mycall, UCHAR * call, UCHAR * node)
fclose(L4LogHandle);
}
-VOID CONNECTREQUEST(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * L3MSG, UINT ApplMask, UCHAR * ApplCall)
+extern struct CMDX COMMANDS[];
+extern int NUMBEROFCOMMANDS;
+
+VOID CONNECTREQUEST(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * L3MSG, UINT ApplMask, UCHAR * ApplCall, int Service)
{
// CONNECT REQUEST - SEE IF EXISTING SESSION
// IF NOT, GET AND FORMAT SESSION TABLE ENTRY
// SEND CONNECT ACK
- // EDI = _BUFFER, EBX = LINK
+ // Service is for Paula's CREQX - Connect to Service
TRANSPORTENTRY * L4;
int BPQNODE = 0; // NOT ONE OF MINE
char BPQPARAMS[10]; // Extended Connect Params from BPQ Node
int CONERROR;
int Index;
+ char APPLCMD[13] = "";
+
+ memcpy(APPLCMD, APPL->APPLCMD, 13);
memcpy(BPQPARAMS, &L4T1, 2); // SET DEFAULT T1 IN CASE NOT FROM ANOTHER BPQ NODE
@@ -1608,8 +1629,9 @@ VOID CONNECTREQUEST(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * L3MSG, UINT Appl
}
L4->CIRCUITINDEX = Index;
+ L4->Service = Service;
- SETUPNEWCIRCUIT(LINK, L3MSG, L4, BPQPARAMS, ApplMask, &BPQNODE);
+ SETUPNEWCIRCUIT(LINK, L3MSG, L4, BPQPARAMS, ApplMask, &BPQNODE, Service);
if (L4->L4TARGET.DEST == 0)
{
@@ -1619,6 +1641,58 @@ VOID CONNECTREQUEST(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * L3MSG, UINT Appl
SendConNAK(LINK, L3MSG);
return;
}
+
+ // Check for NetromX Service
+
+ if (Service > 0 && Service != 23) // 0 is CMD Hander 23 is TELNET which also connects to node
+ {
+ int i;
+
+ for (i = 0; i < NUMBEROFSSERVICES; i++)
+ {
+ if (SERVICES[i].ServiceNo == Service)
+ {
+ // Check if we have this application
+ struct CMDX * CMD = NULL;
+ int n;
+ char * APP = &SERVICES[i].ServiceName[0];
+ int APPlen = strlen(APP);
+
+ for (n = PASSCMD; n < NUMBEROFCOMMANDS; n++) // Don't allow SYSOP Commands
+ {
+ CMD = &COMMANDS[n];
+
+ if (n == APPL1) // First APPL command
+ {
+ ApplMask = 1; // FOR APPLICATION ATTACH REQUESTS
+ ALIASPTR = &CMDALIAS[0][0];
+ }
+
+ // ptr1 is input command
+
+ if (memcmp(CMD->String, APP, APPlen) == 0)
+ {
+ // At the moment I only handle connects to appls. May support other node commands later.
+
+ if (n < APPL1 + NumberofAppls)
+ goto doAPPLConnect;
+ }
+
+ ApplMask <<= 1;
+ ALIASPTR += ALIASLEN;
+
+ }
+ }
+ }
+
+ // Not one of our applications - refuse connect
+
+ memset(L4, 0, sizeof (TRANSPORTENTRY));
+ SendConNAK(LINK, L3MSG);
+ return;
+ }
+
+ //
// IF CONNECT TO APPL, ALLOCATE BBS PORT
if (ApplMask == 0 || BPQPARAMS[2] == 'Z') // Z is "Spy" Connect
@@ -1630,6 +1704,7 @@ VOID CONNECTREQUEST(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * L3MSG, UINT Appl
// IF APPL CONNECT, SEE IF APPL HAS AN ALIAS
+doAPPLConnect:
if (ALIASPTR[0] > ' ')
{
@@ -1644,7 +1719,7 @@ VOID CONNECTREQUEST(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * L3MSG, UINT Appl
if (Msg)
{
Msg->PID = 0xf0;
- memcpy(Msg->L2DATA, APPL->APPLCMD, 12);
+ memcpy(Msg->L2DATA, APPLCMD, 12);
Msg->L2DATA[12] = 13;
Msg->LENGTH = MSGHDDRLEN + 12 + 2; // 2 for PID and CR
@@ -1747,10 +1822,17 @@ VOID SendConACK(struct _LINKTABLE * LINK, TRANSPORTENTRY * L4, L3MESSAGEBUFFER *
TNC = LINK->LINKPORT->TNC;
- if (TNC && TNC->NetRomMode)
+ if (LINK->NEIGHBOUR && LINK->NEIGHBOUR->TCPPort)
+ {
+ TCPNETROMSend(LINK->NEIGHBOUR, L3MSG);
+ ReleaseBuffer(L3MSG);
+ }
+ else if (TNC && TNC->NetRomMode)
SendVARANetromMsg(TNC, L3MSG);
else
C_Q_ADD(&LINK->TX_Q, L3MSG);
+
+ IncomingL4ConnectionEvent(L4);
}
int FINDCIRCUIT(L3MESSAGEBUFFER * L3MSG, TRANSPORTENTRY ** REQL4, int * NewIndex)
@@ -1827,7 +1909,7 @@ void L3SWAPADDRESSES(L3MESSAGEBUFFER * L3MSG)
memcpy(L3MSG->L3SRCE, L3MSG->L3DEST, 7);
memcpy(L3MSG->L3DEST, Temp, 7);
- L3MSG->L3DEST[6] &= 0x1E; // Mack EOA and CMD
+ L3MSG->L3DEST[6] &= 0x1E; // Mask EOA and CMD
L3MSG->L3SRCE[6] &= 0x1E;
L3MSG->L3SRCE[6] |= 1; // Set Last Call
}
@@ -1847,6 +1929,9 @@ VOID SendL4RESET(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * L3MSG)
{
// Paula's extension
+ L3MSG->L4RXNO = L3MSG->L4ID;
+ L3MSG->L4TXNO = L3MSG->L4INDEX;
+
L3MSG->L4FLAGS = L4RESET;
L3SWAPADDRESSES(L3MSG);
@@ -1863,7 +1948,7 @@ VOID SendL4RESET(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * L3MSG)
VOID SETUPNEWCIRCUIT(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * L3MSG,
- TRANSPORTENTRY * L4, char * BPQPARAMS, int ApplMask, int * BPQNODE)
+ TRANSPORTENTRY * L4, char * BPQPARAMS, int ApplMask, int * BPQNODE, int Service)
{
struct DEST_LIST * DEST;
int Maxtries = 2; // Just in case
@@ -1882,10 +1967,10 @@ VOID SETUPNEWCIRCUIT(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * L3MSG,
L4->SESSIONT1 = L4T1;
- L4->L4WINDOW = (UCHAR)L4DEFAULTWINDOW;
-
+ L4->L4WINDOW = L3MSG->L4DATA[0];
+
if (L3MSG->L4DATA[0] > L4DEFAULTWINDOW)
- L4->L4WINDOW = L3MSG->L4DATA[0];
+ L4->L4WINDOW = L4DEFAULTWINDOW;
memcpy(L4->L4USER, &L3MSG->L4DATA[1], 7); // Originator's call from Call Request
@@ -2020,6 +2105,8 @@ VOID FRAMEFORUS(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * L3MSG, int ApplMask,
char Call[10];
struct TNCINFO * TNC;
+ int Service = -1; // Paula's connect to service
+
L4FRAMESRX++;
Opcode = L3MSG->L4FLAGS & 15;
@@ -2048,9 +2135,13 @@ VOID FRAMEFORUS(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * L3MSG, int ApplMask,
ReleaseBuffer(L3MSG);
return;
+ case L4CREQX: // Paula's connect to service
+
+ Service = (L3MSG->L4RXNO << 8) | L3MSG->L4TXNO;
+
case L4CREQ:
- CONNECTREQUEST(LINK, L3MSG, ApplMask, ApplCall);
+ CONNECTREQUEST(LINK, L3MSG, ApplMask, ApplCall, Service);
return;
}
@@ -2067,7 +2158,8 @@ VOID FRAMEFORUS(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * L3MSG, int ApplMask,
while (n--)
{
- if (L4->L4USER[0] && L4->FARID == L3MSG->L4ID && L4->FARINDEX == L3MSG->L4INDEX)
+ if ((L4->L4USER[0] && L4->FARID == L3MSG->L4RXNO && L4->FARINDEX == L3MSG->L4TXNO) || // Paula returns session in RX/TXNO, I sent in ID/INDEX
+ (L4->L4USER[0] && L4->FARID == L3MSG->L4ID && L4->FARINDEX == L3MSG->L4INDEX))
{
// Check L3 source call to be sure (should that be L4 source call??
@@ -2075,10 +2167,9 @@ VOID FRAMEFORUS(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * L3MSG, int ApplMask,
if (memcmp(L3MSG->L3SRCE, L4->L4TARGET.DEST->DEST_CALL, 7) == 0)
{
+ L4DisconnectEvent(L4, "incoming", "RESET Received");
CloseSessionPartner(L4); // SEND CLOSE TO PARTNER (IF PRESENT)
}
- ReleaseBuffer(L3MSG);
- return;
}
L4++;
}
@@ -2156,6 +2247,9 @@ VOID FRAMEFORUS(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * L3MSG, int ApplMask,
L4->L4WINDOW = L3MSG->L4DATA[0];
strcpy(ReplyText, "Connected to");
+
+ OutgoingL4ConnectionEvent(L4);
+
}
if (Partner == 0)
@@ -2194,16 +2288,25 @@ VOID FRAMEFORUS(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * L3MSG, int ApplMask,
TNC = LINK->LINKPORT->TNC;
- if (TNC && TNC->NetRomMode)
+ if (LINK->NEIGHBOUR && LINK->NEIGHBOUR->TCPPort)
+ {
+ TCPNETROMSend(LINK->NEIGHBOUR, L3MSG);
+ ReleaseBuffer(L3MSG);
+ }
+ else if (TNC && TNC->NetRomMode)
SendVARANetromMsg(TNC, L3MSG);
else
C_Q_ADD(&LINK->TX_Q, L3MSG);
+
+ L4DisconnectEvent(L4, "incoming", "DREQ Received");
+
CloseSessionPartner(L4); // SEND CLOSE TO PARTNER (IF PRESENT)
return;
case L4DACK:
+ L4DisconnectEvent(L4, "outgoing", "DACK Received");
CLEARSESSIONENTRY(L4);
ReleaseBuffer(L3MSG);
return;
@@ -2640,241 +2743,32 @@ VOID SENDL4IACK(TRANSPORTENTRY * Session)
}
+int CloseAllSessions()
+{
+ int n = MAXCIRCUITS;
+ TRANSPORTENTRY * L4 = L4TABLE;
+ TRANSPORTENTRY * Partner;
+ int MaxLinks = MAXLINKS;
+ int Closed = 0;
+ while (n--)
+ {
+ if (L4->L4USER[0] == 0)
+ {
+ L4++;
+ continue;
+ }
-/*
- PUBLIC KILLSESSION
-KILLSESSION:
-
- pushad
- push ebx
- CALL _CLEARSESSIONENTRY
- pop ebx
- popad
-
- JMP L4CONN90 ; REJECT
-
- PUBLIC CONNECTACK
-CONNECTACK:
-;
-; EXTRACT EXTENDED PARAMS IF PRESENT
-;
-
- CMP BYTE PTR MSGLENGTH[EDI],L4DATA+1
- JE SHORT NOTBPQ
-
- MOV AL,L4DATA+1[EDI]
- SUB AL,L3MONR[EDI]
- ADD AL,41H ; HOPS TO DEST + 40H
-
- MOV ESI,L4TARGET[EBX]
- AND DEST_STATE[ESI],80H
- OR DEST_STATE[ESI],AL ; SAVE
-
- PUBLIC NOTBPQ
-NOTBPQ:
-;
-; SEE IF SUCCESS OR FAIL
-;
- PUSH EDI
-
- MOV ESI,L4TARGET[EBX] ; ADDR OF LINK/DEST ENTRY
- LEA ESI,DEST_CALL[ESI]
-
- CALL DECODENODENAME ; CONVERT TO ALIAS:CALL
-
- MOV EDI,OFFSET32 CONACKCALL
- MOV ECX,17
- REP MOVSB
-
-
- POP EDI
-
- TEST L4FLAGS[EDI],L4BUSY
- JNZ SHORT L4CONNFAILED
-
- CMP L4STATE[EBX],5
- JE SHORT CONNACK05 ; MUST BE REPEAT MSG - DISCARD
-
- MOV AX,WORD PTR L4TXNO[EDI] ; HIS INDEX
- MOV WORD PTR FARINDEX[EBX],AX
-
- MOV L4STATE[EBX],5 ; ACTIVE
- MOV L4TIMER[EBX],0 ; CANCEL TIMER
- MOV L4RETRIES[EBX],0 ; CLEAR RETRY COUNT
-
- MOV AL,L4DATA[EDI] ; WINDOW
- MOV L4WINDOW[EBX],AL ; SET WINDOW
-
- MOV EDX,L4CROSSLINK[EBX] ; POINT TO PARTNER
-;
- MOV ESI,OFFSET32 CONNECTEDMSG
- MOV ECX,LCONNECTEDMSG
-
- JMP SHORT L4CONNCOMM
-
- PUBLIC L4CONNFAILED
-L4CONNFAILED:
-;
- MOV EDX,L4CROSSLINK[EBX] ; SAVE PARTNER
- pushad
- push ebx
- CALL _CLEARSESSIONENTRY
- pop ebx
- popad
-
- PUSH EBX
-
- MOV EBX,EDX
- MOV L4CROSSLINK[EBX],0 ; CLEAR CROSSLINK
- POP EBX
-
- MOV ESI,OFFSET32 BUSYMSG ; ?? BUSY
- MOV ECX,LBUSYMSG
-
- PUBLIC L4CONNCOMM
-L4CONNCOMM:
-
- OR EDX,EDX
- JNZ SHORT L4CONNOK10
-;
-; CROSSLINK HAS GONE?? - JUST CHUCK MESSAGE
-;
- PUBLIC CONNACK05
-CONNACK05:
-
- JMP L4DISCARD
-
- PUBLIC L4CONNOK10
-L4CONNOK10:
-
- PUSH EBX
- PUSH ESI
- PUSH ECX
-
- MOV EDI,_BUFFER
-
- ADD EDI,7
- MOV AL,0F0H
- STOSB ; PID
-
- CALL _SETUPNODEHEADER ; PUT IN _NODE ID
-
-
- POP ECX
- POP ESI
- REP MOVSB
-
- MOV ESI,OFFSET32 CONACKCALL
- MOV ECX,17 ; MAX LENGTH ALIAS:CALL
- REP MOVSB
-
- MOV AL,0DH
- STOSB
-
- MOV ECX,EDI
- MOV EDI,_BUFFER
- SUB ECX,EDI
-
- MOV MSGLENGTH[EDI],CX
-
- MOV EBX,EDX ; CALLER'S SESSION
-
- LEA ESI,L4TX_Q[EBX]
- CALL _Q_ADD ; SEND MESSAGE TO CALLER
-
- CALL _POSTDATAAVAIL
-
- POP EBX ; ORIGINAL CIRCUIT TABLE
- RET
-
-
- PUBLIC SENDCONNECTREPLY
-SENDCONNECTREPLY:
-;
-; LINK SETUP COMPLETE - EBX = LINK, EDI = _BUFFER
-;
- CMP LINKTYPE[EBX],3
- JNE SHORT CONNECTED00
-;
-; _NODE - _NODE SESSION SET UP - DONT NEED TO DO ANYTHING (I THINK!)
-;
- CALL RELBUFF
- RET
-
-;
-; UP/DOWN LINK
-;
- PUBLIC CONNECTED00
-CONNECTED00:
- CMP CIRCUITPOINTER[EBX],0
- JNE SHORT CONNECTED01
-
- CALL RELBUFF ; UP/DOWN WITH NO SESSION - NOONE TO TELL
- RET ; NO CROSS LINK
- PUBLIC CONNECTED01
-CONNECTED01:
- MOV _BUFFER,EDI
- PUSH EBX
- PUSH ESI
- PUSH ECX
-
- ADD EDI,7
- MOV AL,0F0H
- STOSB ; PID
-
- CALL _SETUPNODEHEADER ; PUT IN _NODE ID
-
- LEA ESI,LINKCALL[EBX]
-
- PUSH EDI
- CALL CONVFROMAX25 ; ADDR OF CALLED STATION
- POP EDI
-
- MOV EBX,CIRCUITPOINTER[EBX]
-
- MOV L4STATE[EBX],5 ; SET LINK UP
-
- MOV EBX,L4CROSSLINK[EBX] ; TO INCOMING LINK
- cmp ebx,0
- jne xxx
-;
-; NO LINK ???
-;
- MOV EDI,_BUFFER
- CALL RELBUFF
+ Closed++;
- POP ECX
- POP ESI
- POP EBX
-
- RET
-
- PUBLIC xxx
-xxx:
-
- POP ECX
- POP ESI
- REP MOVSB
-
- MOV ESI,OFFSET32 _NORMCALL
- MOVZX ECX,_NORMLEN
- REP MOVSB
-
- MOV AL,0DH
- STOSB
-
- MOV ECX,EDI
- MOV EDI,_BUFFER
- SUB ECX,EDI
-
- MOV MSGLENGTH[EDI],CX
-
- LEA ESI,L4TX_Q[EBX]
- CALL _Q_ADD ; SEND MESSAGE TO CALLER
+ Partner = L4->L4CROSSLINK;
- CALL _POSTDATAAVAIL
+ CLOSECURRENTSESSION(L4);
+
+ if (Partner)
+ CLOSECURRENTSESSION(Partner); // CLOSE THIS ONE
- POP EBX
- RET
-*/
\ No newline at end of file
+ L4++;
+ }
+ return Closed;
+}
diff --git a/LinBPQ.c b/LinBPQ.c
index acd5c23..1c16ef4 100644
--- a/LinBPQ.c
+++ b/LinBPQ.c
@@ -83,6 +83,8 @@ void RHPPoll();
VOID GetPGConfig();
void SendBBSDataToPktMap();
+void CloseAllLinks();
+void hookNodeClosing(char * Reason);
extern uint64_t INP3timeLoadedMS;
@@ -262,9 +264,9 @@ extern char MailDir[MAX_PATH];
extern time_t MaintClock; // Time to run housekeeping
#ifdef WIN32
-BOOL KEEPGOING = 30; // 5 secs to shut down
+int KEEPGOING = 30; // 5 secs to shut down
#else
-BOOL KEEPGOING = 50; // 5 secs to shut down
+int KEEPGOING = 50; // 5 secs to shut down
#endif
BOOL Restarting = FALSE;
BOOL CLOSING = FALSE;
@@ -337,6 +339,7 @@ BOOL CtrlHandler(DWORD fdwCtrlType)
// Handle the CTRL-C signal.
case CTRL_C_EVENT:
printf( "Ctrl-C event\n\n" );
+ CloseAllLinks();
CLOSING = TRUE;
Beep( 750, 300 );
return( TRUE );
@@ -344,7 +347,8 @@ BOOL CtrlHandler(DWORD fdwCtrlType)
// CTRL-CLOSE: confirm that the user wants to exit.
case CTRL_CLOSE_EVENT:
- CLOSING = TRUE;
+ CloseAllLinks();
+ CLOSING = TRUE;
printf( "Ctrl-Close event\n\n" );
Sleep(20000);
Beep( 750, 300 );
@@ -354,7 +358,8 @@ BOOL CtrlHandler(DWORD fdwCtrlType)
case CTRL_BREAK_EVENT:
Beep( 900, 200 );
printf( "Ctrl-Break event\n\n" );
- CLOSING = TRUE;
+ CloseAllLinks();
+ CLOSING = TRUE;
Beep( 750, 300 );
return FALSE;
@@ -366,7 +371,8 @@ BOOL CtrlHandler(DWORD fdwCtrlType)
case CTRL_SHUTDOWN_EVENT:
Beep( 750, 500 );
printf( "Ctrl-Shutdown event\n\n" );
- CLOSING = TRUE;
+ CloseAllLinks();
+ CLOSING = TRUE;
Beep( 750, 300 );
return FALSE;
@@ -399,6 +405,9 @@ static void segvhandler(int sig)
write(STDOUT_FILENO, msg, strlen(msg));
backtrace_symbols_fd(array, size, STDOUT_FILENO);
+ hookNodeClosing("sigsegv");
+ Sleep(500);
+
exit(1);
}
@@ -419,6 +428,9 @@ static void abrthandler(int sig)
write(STDOUT_FILENO, msg, strlen(msg));
backtrace_symbols_fd(array, size, STDOUT_FILENO);
+ hookNodeClosing("sigabrt");
+ Sleep(500);
+
exit(1);
}
@@ -427,12 +439,14 @@ static void sigterm_handler(int sig)
{
syslog(LOG_INFO, "terminating on SIGTERM\n");
CLOSING = TRUE;
+ CloseAllLinks();
}
static void sigint_handler(int sig)
{
printf("terminating on SIGINT\n");
CLOSING = TRUE;
+ CloseAllLinks();
}
@@ -1682,6 +1696,9 @@ int main(int argc, char * argv[])
Slowtimer = 0;
}
+ hookNodeClosing("Shutdown");
+ Sleep(500);
+
printf("Closing Ports\n");
CloseTNCEmulator();
diff --git a/Moncode.c b/Moncode.c
index 5857655..20482ec 100644
--- a/Moncode.c
+++ b/Moncode.c
@@ -59,7 +59,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
#define NODES_SIG 0xFF
-UCHAR * DisplayINP3RIF(UCHAR * ptr1, UCHAR * ptr2, unsigned int msglen);
+UCHAR * DisplayINP3RIF(UCHAR * ptr1, UCHAR * ptr2, int msglen);
char * DISPLAY_NETROM(MESSAGE * ADJBUFFER, UCHAR * Output, int MsgLen);
UCHAR * DISPLAYIPDATAGRAM(IPMSG * IP, UCHAR * Output, int MsgLen);
@@ -655,12 +655,13 @@ char * DISPLAY_NETROM(MESSAGE * ADJBUFFER, UCHAR * Output, int MsgLen)
char Node[10];
UCHAR TTL, Index, ID, TXNO, RXNO, OpCode, Flags, Window;
UCHAR * ptr = &ADJBUFFER->L2DATA[0];
+ int service = 0;
+ int netromx = 0; // Set if Paula's connect to service
if (ADJBUFFER->L2DATA[0] == NODES_SIG)
{
// Display NODES
-
// If an INP3 RIF (type <> UI) decode as such
if (ADJBUFFER->CTL != 3) // UI
@@ -722,6 +723,12 @@ char * DISPLAY_NETROM(MESSAGE * ADJBUFFER, UCHAR * Output, int MsgLen)
switch (OpCode)
{
+
+ case L4CREQX: // Paula's connect to service
+
+ netromx = 1;
+ service = (RXNO << 8) | TXNO;
+
case L4CREQ:
Window = *(ptr++);
@@ -730,7 +737,10 @@ char * DISPLAY_NETROM(MESSAGE * ADJBUFFER, UCHAR * Output, int MsgLen)
Node[ConvFromAX25(ptr, Node)] = 0;
ptr +=7;
- Output += sprintf((char *)Output, " w=%d %s at %s", Window, Dest, Node);
+ if (netromx)
+ Output += sprintf((char *)Output, " w=%d %d@%s at %s", Window, service, Dest, Node);
+ else
+ Output += sprintf((char *)Output, " w=%d %s at %s", Window, Dest, Node);
if (MsgLen > 38) // BPQ Extended Params
{
@@ -745,7 +755,7 @@ char * DISPLAY_NETROM(MESSAGE * ADJBUFFER, UCHAR * Output, int MsgLen)
if (Flags & L4BUSY) // BUSY RETURNED
return Output + sprintf((char *)Output, " - BUSY");
- return Output + sprintf((char *)Output, " w=%d my cct=%02X%02X", ptr[1], TXNO, RXNO);
+ return Output + sprintf((char *)Output, " w=%d my cct=%02X%02X", ptr[0], TXNO, RXNO);
case L4DREQ:
diff --git a/NETROMTCP.c b/NETROMTCP.c
new file mode 100644
index 0000000..79f186b
--- /dev/null
+++ b/NETROMTCP.c
@@ -0,0 +1,551 @@
+/*
+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
+*/
+
+/*
+Netrom over TCP Support
+
+This is intended for operation over radio links with an IP interface, eg New Packet Radio or possibly microwave links
+
+To simplify interface to the rest of the oode dummy LINK and PORT records are created
+
+Packet Format is Length (2 byte little endian) Call (10 bytes ASCII) NETROM L3/4 Packet, starting 0xcf (to detect framing errors).
+
+A TCP message can contain multiple packets and/or partial packets
+
+It uses the Telnet Server, with port defined in NETROMPORT
+
+ROUTE definitions have an extra field, the TCP Port Number
+
+*/
+
+//#pragma data_seg("_BPQDATA")
+
+
+#define _CRT_SECURE_NO_DEPRECATE
+
+#include "time.h"
+#include "stdio.h"
+#include
+//#include "vmm.h"
+
+#include "cheaders.h"
+#include "asmstrucs.h"
+#include "telnetserver.h"
+
+#define NETROM_PID 0xCF
+
+void NETROMConnectionLost(struct ConnectionInfo * sockptr);
+int DataSocket_ReadNETROM(struct ConnectionInfo * sockptr, SOCKET sock, struct NRTCPSTRUCT * Info, int portNo);
+int NETROMTCPConnect(struct ROUTE * Route, struct ConnectionInfo * sockptr);
+void NETROMConnected(struct ConnectionInfo * sockptr, SOCKET sock, struct NRTCPSTRUCT * Info);
+VOID SendRTTMsg(struct ROUTE * Route);
+BOOL FindNeighbour(UCHAR * Call, int Port, struct ROUTE ** REQROUTE);
+VOID NETROMMSG(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * L3MSG);
+int BPQTRACE(MESSAGE * Msg, BOOL TOAPRS);
+VOID L3LINKCLOSED(struct _LINKTABLE * LINK, int Reason);
+
+struct NRTCPMsg
+{
+ short Length;
+ char Call[10];
+ unsigned char PID;
+ char Packet[1024];
+};
+
+struct NRTCPSTRUCT
+{
+ struct ConnectionInfo * sockptr;
+ struct _LINKTABLE * LINK; // Dummy Link Record for this ROUTE
+ struct ROUTE * Route; // May need backlink
+ char Call[10];
+};
+
+struct NRTCPSTRUCT * NRTCPInfo[256] = {0};
+
+// Do we want to use normal TCP server connections, which are limited, or our own. Let's try our own for now
+
+struct ConnectionInfo * AllocateNRTCPRec()
+{
+ struct ConnectionInfo * sockptr = 0;
+ struct NRTCPSTRUCT * Info;
+ int i;
+
+ for (i = 0; i < 255; i++)
+ {
+ if (NRTCPInfo[i] == 0)
+ {
+ // only allocate as many as needed
+
+ Info = NRTCPInfo[i] = (struct NRTCPSTRUCT *)zalloc(sizeof(struct NRTCPSTRUCT));
+ Info->sockptr = (struct ConnectionInfo *)zalloc(sizeof(struct ConnectionInfo));
+ Info->LINK = (struct _LINKTABLE *)zalloc(sizeof(struct _LINKTABLE));
+ Info->sockptr->Number = i;
+ }
+ else
+ Info = NRTCPInfo[i];
+
+ sockptr = Info->sockptr;
+
+ if (sockptr->SocketActive == FALSE)
+ {
+ sockptr->SocketActive = TRUE;
+ sockptr->ConnectTime = sockptr->LastSendTime = time(NULL);
+
+ Debugprintf("NRTCP Allocated %d", i);
+ return sockptr;
+ }
+ }
+ return 0;
+}
+
+void checkNRTCPSockets(int portNo)
+{
+ SOCKET sock;
+ int Active = 0;
+ SOCKET maxsock;
+ int retval;
+ int i;
+
+ struct timeval timeout;
+ fd_set readfd, writefd, exceptfd;
+
+ struct ConnectionInfo * sockptr;
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0; // poll
+
+ maxsock = 0;
+
+ FD_ZERO(&readfd);
+ FD_ZERO(&writefd);
+ FD_ZERO(&exceptfd);
+
+ for (i = 0; i < 255; i++)
+ {
+ if (NRTCPInfo[i] == 0)
+ break; // only as many as have been used
+
+ sockptr = NRTCPInfo[i]->sockptr;
+
+ if (sockptr->SocketActive == 0)
+ continue;
+
+ if (sockptr->Connecting)
+ {
+ // look for complete or failed
+
+ FD_SET(sockptr->socket, &writefd);
+ FD_SET(sockptr->socket, &exceptfd);
+ }
+ else
+ {
+ FD_SET(sockptr->socket, &readfd);
+ FD_SET(sockptr->socket, &exceptfd);
+ }
+
+ Active++;
+
+ if (sockptr->socket > maxsock)
+ maxsock = sockptr->socket;
+ }
+
+ if (Active)
+ {
+ retval = select((int)maxsock + 1, &readfd, &writefd, &exceptfd, &timeout);
+
+ if (retval == -1)
+ {
+ perror("data select");
+ Debugprintf("NRTCP Select Error %d Active %d", WSAGetLastError(), Active);
+ }
+ else
+ {
+ if (retval)
+ {
+ // see who has data
+
+ for (i = 0; i < 255; i++)
+ {
+ if (NRTCPInfo[i] == 0)
+ break;
+
+ sockptr = NRTCPInfo[i]->sockptr;
+
+ if (sockptr->SocketActive == 0)
+ continue;
+
+ sock = sockptr->socket;
+
+ if (FD_ISSET(sock, &writefd))
+ NETROMConnected(sockptr, sock, NRTCPInfo[i]);
+
+ if (FD_ISSET(sock, &readfd))
+ DataSocket_ReadNETROM(sockptr, sock, NRTCPInfo[i], portNo);
+
+ if (FD_ISSET(sock, &exceptfd))
+ NETROMConnectionLost(sockptr);
+ }
+ }
+ }
+ }
+}
+
+int NETROMOpenConnection(struct ROUTE * Route)
+{
+ struct NRTCPSTRUCT * Info;
+ struct ConnectionInfo * sockptr;
+
+ Debugprintf("Opening NRTCP Connection");
+
+ if (Route->TCPSession)
+ {
+ // SESSION ALREADY EXISTS
+
+ sockptr = Route->TCPSession->sockptr;
+
+ if (sockptr->Connected || sockptr->Connecting)
+ return TRUE;
+
+ // previous connect failed
+ }
+ else
+ {
+ sockptr = AllocateNRTCPRec();
+
+ if (sockptr == NULL)
+ return 0;
+
+ Info = Route->TCPSession = NRTCPInfo[sockptr->Number];
+ memcpy(Info->Call, MYNETROMCALL, 10);
+ Route->NEIGHBOUR_LINK = Info->LINK;
+
+ Info->Route = Route;
+ Info->LINK->NEIGHBOUR = Route;
+ Info->LINK->LINKPORT = GetPortTableEntryFromPortNum(Route->NEIGHBOUR_PORT);
+ }
+
+ return NETROMTCPConnect(Route, sockptr);
+
+}
+
+int NETROMTCPConnect(struct ROUTE * Route, struct ConnectionInfo * sockptr)
+{
+ int err;
+ u_long param=1;
+ BOOL bcopt=TRUE;
+ SOCKET sock;
+ struct sockaddr_in sinx;
+ int addrlen=sizeof(sinx);
+ char PortString[20];
+ struct addrinfo hints, *res = 0, *saveres;
+ int Port = Route->TCPPort;
+
+ sprintf(PortString, "%d", Port);
+
+ // get host info, make socket, and connect it
+
+ memset(&hints, 0, sizeof hints);
+
+ hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
+
+ hints.ai_socktype = SOCK_STREAM;
+ getaddrinfo(Route->TCPHost, PortString, &hints, &res);
+
+ if (!res)
+ {
+ err = WSAGetLastError();
+ Debugprintf("Resolve HostName %s Failed - Error %d", Route->TCPHost, err);
+ return FALSE; // Resolve failed
+ }
+
+ // Step thorough the list of hosts
+
+ saveres = res; // Save for free
+
+ sock = sockptr->socket = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+
+
+ if (sock == INVALID_SOCKET)
+ {
+ Debugprintf, ("Netrom over TCP Create Socket Failed");
+ return FALSE;
+ }
+
+ ioctl(sock, FIONBIO, ¶m);
+
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt,4);
+
+
+ if (connect(sock, res->ai_addr, (int)res->ai_addrlen) == 0)
+ {
+ //
+ // Connected successful
+ //
+
+ sockptr->Connected = TRUE;
+ freeaddrinfo(saveres);
+
+ return TRUE;
+ }
+ else
+ {
+ freeaddrinfo(saveres);
+
+ err=WSAGetLastError();
+
+ if (err == 10035 || err == 115 || err == 36) //EWOULDBLOCK
+ {
+ // Connect in Progress
+
+ sockptr->Connecting = TRUE;
+ return TRUE;
+ }
+ else
+ {
+ // Connect failed
+
+ closesocket(sockptr->socket);
+
+ return FALSE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+
+
+void NETROMConnectionAccepted(struct ConnectionInfo * sockptr)
+{
+ // Not sure we can do much here until first message arrives with callsign
+
+ sockptr->Connected = TRUE;
+ Debugprintf("NRTCP Connection Accepted");
+}
+
+void NETROMConnected(struct ConnectionInfo * sockptr, SOCKET sock, struct NRTCPSTRUCT * Info)
+{
+ // Connection Complete
+
+ Debugprintf("NRTCP Connected");
+
+ sockptr->Connecting = FALSE;
+ sockptr->Connected = TRUE;
+
+ Info->LINK->L2STATE = 5;
+
+ if (Info->Route->INP3Node)
+ SendRTTMsg(Info->Route);
+}
+
+int DataSocket_ReadNETROM(struct ConnectionInfo * sockptr, SOCKET sock, struct NRTCPSTRUCT * Info, int portNo)
+{
+ int len=0, maxlen;
+ struct NRTCPMsg * Msg;
+ struct _L3MESSAGEBUFFER * L3Msg;
+ struct ROUTE * Route;
+ UCHAR axCall[7];
+ PMESSAGE Buffer;
+
+ ioctl(sock,FIONREAD,&len);
+
+ maxlen = InputBufferLen - sockptr->InputLen;
+
+ if (len > maxlen) len = maxlen;
+
+ len = recv(sock, &sockptr->InputBuffer[sockptr->InputLen], len, 0);
+
+ if (len == SOCKET_ERROR || len == 0)
+ {
+ // Failed or closed - clear connection
+
+ NETROMConnectionLost(sockptr);
+ return 0;
+ }
+
+ sockptr->InputLen += len;
+
+ // Process data
+
+checkLen:
+
+ // See if we have a whole packet
+
+ Msg = (struct NRTCPMsg *)&sockptr->InputBuffer[0];
+
+ if (Msg->Length > sockptr->InputLen) // if not got whole frame wait
+ return 0;
+
+ if (Info->Call[0] == 0)
+ {
+ // first packet - do we need to do anything?
+
+ // This must be an incoming connection as Call is set before calling so need to find route record and set things up.
+
+ memcpy(Info->Call, Msg->Call, 10);
+
+ ConvToAX25(Msg->Call, axCall);
+
+ if (FindNeighbour(axCall, portNo, &Route))
+ {
+ Info->Route = Route;
+ Route->NEIGHBOUR_LINK = Info->LINK;
+ Info->LINK->NEIGHBOUR = Route;
+ Info->LINK->LINKPORT = GetPortTableEntryFromPortNum(Route->NEIGHBOUR_PORT);
+ Route->TCPSession = Info;
+ Info->LINK->L2STATE = 5;
+
+ if (Info->Route->INP3Node)
+ SendRTTMsg(Info->Route);
+ }
+ else
+ goto seeifMore; // Should we kill connection?
+ }
+
+
+ if (memcmp(Info->Call, Msg->Call, 10) != 0)
+ {
+ // something wrong - maybe connection reused
+ }
+
+ // Format as if come from an ax.25 link
+
+ L3Msg = GetBuff();
+
+ if (L3Msg == 0)
+ goto seeifMore;
+
+ L3Msg->LENGTH = (Msg->Length - 12) + MSGHDDRLEN;
+ L3Msg->Next = 0;
+ L3Msg->Port = 0;
+ L3Msg->L3PID = NETROM_PID;
+ memcpy(&L3Msg->L3SRCE, Msg->Packet, Msg->Length - 13);
+
+ // Create a dummy L2 message so we can trace it
+
+ Buffer = GetBuff();
+
+ if (Buffer)
+ {
+ Buffer->CHAIN = 0;
+ Buffer->CTL = 0;
+ Buffer->PORT = portNo;
+
+ ConvToAX25(Info->Call, Buffer->ORIGIN);
+ ConvToAX25(MYNETROMCALL, Buffer->DEST);
+
+ memcpy(Buffer->L2DATA, &L3Msg->L3SRCE[0], Msg->Length - 13);
+ Buffer->ORIGIN[6] |= 1; // Set end of calls
+ Buffer->PID = NETROM_PID;
+ Buffer->LENGTH = Msg->Length + 10;
+ time(&Buffer->Timestamp);
+
+ BPQTRACE(Buffer, FALSE);
+ ReleaseBuffer(Buffer);
+ }
+
+ NETROMMSG(Info->LINK, L3Msg);
+
+seeifMore:
+
+ sockptr->InputLen -= Msg->Length;
+
+ if (sockptr->InputLen > 0)
+ {
+ memmove(sockptr->InputBuffer, &sockptr->InputBuffer[Msg->Length], sockptr->InputLen);
+ goto checkLen;
+ }
+
+ return 0;
+}
+
+VOID TCPNETROMSend(struct ROUTE * Route, struct _L3MESSAGEBUFFER * Frame)
+{
+ struct NRTCPMsg Msg;
+ unsigned char * Data = (unsigned char *)&Frame->L3SRCE[0];
+ int DataLen = Frame->LENGTH - (MSGHDDRLEN + 1); // Not including PID
+ int Ret;
+ PMESSAGE Buffer;
+
+ Msg.Length = DataLen + 13; // include PID
+ memcpy(Msg.Call, MYNETROMCALL, 10);
+ Msg.PID = NETROM_PID;
+ memcpy(Msg.Packet, Data, DataLen);
+
+ if (Route->TCPSession == 0)
+ return;
+
+ Ret = send(Route->TCPSession->sockptr->socket, (char *)&Msg, DataLen + 13, 0);
+
+ // Create a dummy L2 message so we can trace it
+
+ Buffer = GetBuff();
+
+ if (Buffer)
+ {
+ Buffer->CHAIN = 0;
+ Buffer->CTL = 0;
+ Buffer->PORT = Route->NEIGHBOUR_PORT | 128; // TX Flag
+
+ ConvToAX25(Route->TCPSession->Call, Buffer->DEST);
+ ConvToAX25(MYNETROMCALL, Buffer->ORIGIN);
+
+ memcpy(Buffer->L2DATA, &Frame->L3SRCE[0], DataLen);
+ Buffer->ORIGIN[6] |= 1; // Set end of calls
+ Buffer->PID = NETROM_PID;
+ Buffer->LENGTH = DataLen + 15 + MSGHDDRLEN;
+ time(&Buffer->Timestamp);
+
+ BPQTRACE(Buffer, FALSE);
+ ReleaseBuffer(Buffer);
+ }
+
+}
+
+
+void NETROMConnectionLost(struct ConnectionInfo * sockptr)
+{
+ struct NRTCPSTRUCT * Info = NRTCPInfo[sockptr->Number];
+ struct ROUTE * Route;
+
+ closesocket(sockptr->socket);
+
+ // If there is an attached route (there should be) clear all connections
+
+ if (Info)
+ {
+ Route = Info->Route;
+
+ if (sockptr->Connected)
+ L3LINKCLOSED(Info->LINK, LINKLOST);
+
+ if (sockptr->Connecting)
+ L3LINKCLOSED(Info->LINK, SETUPFAILED);
+
+ Route->TCPSession = 0;
+
+ Info->Call[0] = 0;
+ }
+
+ sockptr->SocketActive = FALSE;
+
+ memset(sockptr, 0, sizeof(struct ConnectionInfo));
+}
+
diff --git a/RigControl.c b/RigControl.c
index 2b268c0..fe90705 100644
--- a/RigControl.c
+++ b/RigControl.c
@@ -2217,7 +2217,7 @@ int BittoInt(UINT BitMask)
return i;
}
-extern char * RadioConfigMsg[36];
+extern char * RadioConfigMsg[70];
struct TNCINFO RIGTNC; // Dummy TNC Record for Rigcontrol without a corresponding TNC
diff --git a/TelnetV6.c b/TelnetV6.c
index 0756447..0761363 100644
--- a/TelnetV6.c
+++ b/TelnetV6.c
@@ -90,7 +90,7 @@ void RHPThread(void * Params);
void ProcessRHPWebSockClosed(SOCKET socket);
int ProcessSNMPPayload(UCHAR * Msg, int Len, UCHAR * Reply, int * OffPtr);
int RHPProcessHTTPMessage(struct ConnectionInfo * conn, char * response, char * Method, char * URL, char * request, BOOL LOCAL, BOOL COOKIE);
-
+void checkNRTCPSockets(int portNo);
#ifndef LINBPQ
extern HKEY REGTREE;
@@ -172,12 +172,14 @@ VOID Tel_Format_Addr(struct ConnectionInfo * sockptr, char * dst);
VOID ProcessTrimodeCommand(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, char * MsgPtr);
VOID ProcessTrimodeResponse(struct TNCINFO * TNC, struct STREAMINFO * STREAM, unsigned char * MsgPtr, int Msglen);
VOID ProcessTriModeDataMessage(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, struct STREAMINFO * STREAM);
-
+void processNETROMFrame(unsigned char * Message, int Len, struct ConnectionInfo * sockptr);
+void NETROMConnectionLost(struct ConnectionInfo * sockptr);
+void NETROMConnectionAccepted(struct ConnectionInfo * sockptr);
+struct ConnectionInfo * AllocateNRTCPRec();
static int LogAge = 13;
-
#ifdef WIN32
int DeleteLogFile(char * Log);
@@ -542,6 +544,9 @@ int ProcessLine(char * buf, int Port)
else if (_stricmp(param,"HTTPPORT") == 0)
HTTPPort = TCP->HTTPPort = atoi(value);
+ else if (_stricmp(param,"NETROMPORT") == 0)
+ TCP->NETROMPort = atoi(value);
+
else if (_stricmp(param,"APIPORT") == 0)
TCP->APIPort = atoi(value);
@@ -1139,7 +1144,7 @@ static size_t ExtProc(int fn, int port, PDATAMESSAGE buff)
shutdown(TCP->FBBsock[n++], SD_BOTH);
shutdown(TCP->Relaysock, SD_BOTH);
- shutdown(TCP->HTTPsock, SD_BOTH);
+ shutdown(TCP->HTTPSock, SD_BOTH);
shutdown(TCP->HTTPsock6, SD_BOTH);
@@ -1163,7 +1168,7 @@ static size_t ExtProc(int fn, int port, PDATAMESSAGE buff)
closesocket(TCP->Relaysock);
closesocket(TCP->Relaysock6);
- closesocket(TCP->HTTPsock);
+ closesocket(TCP->HTTPSock);
closesocket(TCP->HTTPsock6);
// Save info from old TNC record
@@ -1248,7 +1253,7 @@ static size_t ExtProc(int fn, int port, PDATAMESSAGE buff)
shutdown(TCP->FBBsock[n++], SD_BOTH);
shutdown(TCP->Relaysock, SD_BOTH);
- shutdown(TCP->HTTPsock, SD_BOTH);
+ shutdown(TCP->HTTPSock, SD_BOTH);
shutdown(TCP->HTTPsock6, SD_BOTH);
shutdown(TCP->sock6, SD_BOTH);
@@ -1275,7 +1280,7 @@ static size_t ExtProc(int fn, int port, PDATAMESSAGE buff)
closesocket(TCP->FBBsock6[n++]);
closesocket(TCP->Relaysock6);
- closesocket(TCP->HTTPsock);
+ closesocket(TCP->HTTPSock);
closesocket(TCP->HTTPsock6);
return (0);
@@ -1713,11 +1718,14 @@ BOOL OpenSockets(struct TNCINFO * TNC)
}
if (TCP->HTTPPort)
- TCP->HTTPsock = OpenSocket4(TNC, TCP->HTTPPort);
+ TCP->HTTPSock = OpenSocket4(TNC, TCP->HTTPPort);
if (TCP->APIPort)
TCP->APIsock = OpenSocket4(TNC, TCP->APIPort);
+ if (TCP->NETROMPort)
+ TCP->NETROMSock = OpenSocket4(TNC, TCP->NETROMPort);
+
if (TCP->SyncPort)
TCP->Syncsock = OpenSocket4(TNC, TCP->SyncPort);
@@ -1836,6 +1844,9 @@ BOOL OpenSockets6(struct TNCINFO * TNC)
if (TCP->APIPort)
TCP->APIsock6 = OpenSocket6(TNC, TCP->APIPort);
+ if (TCP->NETROMPort)
+ TCP->NETROMSock6 = OpenSocket6(TNC, TCP->NETROMPort);
+
if (TCP->SyncPort)
TCP->Syncsock6 = OpenSocket6(TNC, TCP->SyncPort);
@@ -1888,7 +1899,7 @@ static VOID SetupListenSet(struct TNCINFO * TNC)
maxsock = sock;
}
- sock = TCP->HTTPsock;
+ sock = TCP->HTTPSock;
if (sock)
{
FD_SET(sock, readfd);
@@ -1904,6 +1915,14 @@ static VOID SetupListenSet(struct TNCINFO * TNC)
maxsock = sock;
}
+ sock = TCP->NETROMSock;
+ if (sock)
+ {
+ FD_SET(sock, readfd);
+ if (sock > maxsock)
+ maxsock = sock;
+ }
+
sock = TCP->Syncsock;
if (sock)
{
@@ -1979,6 +1998,14 @@ static VOID SetupListenSet(struct TNCINFO * TNC)
maxsock = sock;
}
+ sock = TCP->NETROMSock6;
+ if (sock)
+ {
+ FD_SET(sock, readfd);
+ if (sock > maxsock)
+ maxsock = sock;
+ }
+
sock = TCP->DRATSsock6;
if (sock)
@@ -2066,13 +2093,20 @@ VOID TelnetPoll(int Port)
Socket_Accept(TNC, sock, TCP->RelayPort);
}
- sock = TCP->HTTPsock;
+ sock = TCP->HTTPSock;
if (sock)
{
if (FD_ISSET(sock, &readfd))
Socket_Accept(TNC, sock, TCP->HTTPPort);
}
+ sock = TCP->NETROMSock;
+ if (sock)
+ {
+ if (FD_ISSET(sock, &readfd))
+ Socket_Accept(TNC, sock, TCP->NETROMPort);
+ }
+
sock = TCP->DRATSsock;
if (sock)
{
@@ -2120,6 +2154,14 @@ VOID TelnetPoll(int Port)
Socket_Accept(TNC, sock, TCP->HTTPPort);
}
+ sock = TCP->NETROMSock6;
+ if (sock)
+ {
+ if (FD_ISSET(sock, &readfd))
+ Socket_Accept(TNC, sock, TCP->NETROMPort);
+ }
+
+
sock = TCP->DRATSsock6;
if (sock)
{
@@ -2247,9 +2289,12 @@ VOID TelnetPoll(int Port)
}
}
-
nosocks:
+ // Poll TCPNR
+
+ checkNRTCPSockets(Port);
+
// Try SNMP
if (TCP->SNMPsock)
@@ -3062,7 +3107,7 @@ LRESULT CALLBACK TelWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPara
shutdown(TCP->FBBsock[n++], SD_BOTH);
shutdown(TCP->Relaysock, SD_BOTH);
- shutdown(TCP->HTTPsock, SD_BOTH);
+ shutdown(TCP->HTTPSock, SD_BOTH);
shutdown(TCP->HTTPsock6, SD_BOTH);
@@ -3087,7 +3132,7 @@ LRESULT CALLBACK TelWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lPara
closesocket(TCP->Relaysock);
closesocket(TCP->Relaysock6);
- closesocket(TCP->HTTPsock);
+ closesocket(TCP->HTTPSock);
closesocket(TCP->HTTPsock6);
// Save info from old TNC record
@@ -3256,6 +3301,35 @@ int Socket_Accept(struct TNCINFO * TNC, SOCKET SocketId, int Port)
return 0;
}
+ // Netrom Over TCP uses its own Connection Entries
+
+ if (SocketId == TCP->NETROMSock || SocketId == TCP->NETROMSock6)
+ {
+ sockptr = AllocateNRTCPRec();
+
+ if (sockptr == 0)
+ {
+ // No entries - accept and close
+
+ sock = accept(SocketId, (struct sockaddr *)&sin6, &addrlen);
+
+ send(sock,"No Free Sessions\r\n", 18,0);
+ Debugprintf("No Free Netrom Telnet Sessions");
+
+ Sleep (500);
+ closesocket(sock);
+ return 0;
+ }
+
+ sock = accept(SocketId, (struct sockaddr *)&sockptr->sin, &addrlen);
+ sockptr->socket = sock;
+ ioctl(sock, FIONBIO, ¶m);
+
+ sockptr->NETROMMode = TRUE;
+ NETROMConnectionAccepted(sockptr);
+ return 0;
+ }
+
// Find a free Session
for (n = 1; n <= TCP->MaxSessions; n++)
@@ -3307,7 +3381,8 @@ int Socket_Accept(struct TNCINFO * TNC, SOCKET SocketId, int Port)
TNC->Streams[n].FramesQueued = 0;
sockptr->HTTPMode = FALSE;
- sockptr->APIMode = FALSE;
+ sockptr->APIMode = FALSE;
+ sockptr->NETROMMode = FALSE;
sockptr->SyncMode = FALSE;
sockptr->DRATSMode = FALSE;
sockptr->FBBMode = FALSE;
@@ -3322,9 +3397,12 @@ int Socket_Accept(struct TNCINFO * TNC, SOCKET SocketId, int Port)
memset(sockptr->ADIF, 0, sizeof(struct ADIF));
- if (SocketId == TCP->HTTPsock || SocketId == TCP->HTTPsock6)
+ if (SocketId == TCP->HTTPSock || SocketId == TCP->HTTPsock6)
sockptr->HTTPMode = TRUE;
+ if (SocketId == TCP->NETROMSock || SocketId == TCP->NETROMSock6)
+ sockptr->NETROMMode = TRUE;
+
if (SocketId == TCP->APIsock || SocketId == TCP->APIsock6)
{
sockptr->HTTPMode = TRUE; // API is a type of HTTP socket
@@ -3358,7 +3436,7 @@ int Socket_Accept(struct TNCINFO * TNC, SOCKET SocketId, int Port)
if (sockptr->HTTPMode)
return 0;
-
+
if (sockptr->DRATSMode)
{
send(sock, "100 Authentication not required\n", 33, 0);
@@ -5271,6 +5349,7 @@ int DataSocket_ReadDRATS(struct TNCINFO * TNC, struct ConnectionInfo * sockptr,
}
+
int DataSocket_Disconnect(struct TNCINFO * TNC, struct ConnectionInfo * sockptr)
{
int n;
@@ -5685,7 +5764,9 @@ int Telnet_Connected(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCK
}
else
{
- if (TNC->PortRecord->ATTACHEDSESSIONS[Stream]->L4CROSSLINK->APPL[0])
+ struct _TRANSPORTENTRY * CROSSLINK = TNC->PortRecord->ATTACHEDSESSIONS[Stream]->L4CROSSLINK;
+
+ if (CROSSLINK && CROSSLINK->APPL[0])
buffptr->Len = sprintf(&buffptr->Data[0], "*** Connected to %s\r",
TNC->PortRecord->ATTACHEDSESSIONS[Stream]->L4CROSSLINK->APPL);
else
diff --git a/UIARQ.c b/UIARQ.c
index 291d711..dca1431 100644
--- a/UIARQ.c
+++ b/UIARQ.c
@@ -80,6 +80,11 @@ int DoScanLine(struct TNCINFO * TNC, char * Buff, int Len);
VOID ProcessARQPacket(struct PORTCONTROL * PORT, MESSAGE * Buffer);
char * strlop(char * buf, char delim);
+void hookL4SessionAttempt(struct STREAMINFO * , char * remotecall, char * ourcall);
+void hookL4SessionAccepted(struct STREAMINFO * , char * remotecall, char * ourcall);
+void hookL4SessionDeleted(struct TNCINFO * TNC, void * STREAM);
+
+
extern UCHAR BPQDirectory[];
extern char MYALIASLOPPED[10];
diff --git a/UZ7HODrv.c b/UZ7HODrv.c
index ac33278..e166b36 100644
--- a/UZ7HODrv.c
+++ b/UZ7HODrv.c
@@ -78,6 +78,11 @@ VOID ReleaseOtherPorts(struct TNCINFO * ThisTNC);
int DoScanLine(struct TNCINFO * TNC, char * Buff, int Len);
int standardParams(struct TNCINFO * TNC, char * buf);
+void hookL4SessionAttempt(struct STREAMINFO * , char * remotecall, char * ourcall);
+void hookL4SessionAccepted(struct STREAMINFO * , char * remotecall, char * ourcall);
+void hookL4SessionDeleted(struct TNCINFO * TNC, void * STREAM);
+
+
extern UCHAR BPQDirectory[];
#define MAXUZ7HOPORTS 16
diff --git a/VARA.c b/VARA.c
index 4574fa4..70f7461 100644
--- a/VARA.c
+++ b/VARA.c
@@ -73,6 +73,11 @@ int KissEncode(UCHAR * inbuff, UCHAR * outbuff, int len);
VOID PROCESSNODEMESSAGE(MESSAGE * Msg, struct PORTCONTROL * PORT);
VOID NETROMMSG(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * L3MSG);
+void hookL4SessionAttempt(struct STREAMINFO * , char * remotecall, char * ourcall);
+void hookL4SessionAccepted(struct STREAMINFO * , char * remotecall, char * ourcall);
+void hookL4SessionDeleted(struct TNCINFO * TNC, void * STREAM);
+
+
#ifndef LINBPQ
BOOL CALLBACK EnumVARAWindowsProc(HWND hwnd, LPARAM lParam);
#endif
diff --git a/Versions.h b/Versions.h
index 8b75625..be8a65e 100644
--- a/Versions.h
+++ b/Versions.h
@@ -10,8 +10,8 @@
#endif
-#define KVers 6,0,25,6
-#define KVerstring "6.0.25.6\0"
+#define KVers 6,0,25,8
+#define KVerstring "6.0.25.8\0"
#ifdef CKernel
diff --git a/WINMOR.c b/WINMOR.c
index 2a3d766..836a070 100644
--- a/WINMOR.c
+++ b/WINMOR.c
@@ -105,6 +105,11 @@ int DoScanLine(struct TNCINFO * TNC, char * Buff, int Len);
BOOL KillOldTNC(char * Path);
int standardParams(struct TNCINFO * TNC, char * buf);
+void hookL4SessionAttempt(struct STREAMINFO * , char * remotecall, char * ourcall);
+void hookL4SessionAccepted(struct STREAMINFO * , char * remotecall, char * ourcall);
+void hookL4SessionDeleted(struct TNCINFO * TNC, void * STREAM);
+
+
static char ClassName[]="WINMORSTATUS";
static char WindowTitle[] = "WINMOR";
static int RigControlRow = 165;
diff --git a/asmstrucs.h b/asmstrucs.h
index d22ecae..3ac464b 100644
--- a/asmstrucs.h
+++ b/asmstrucs.h
@@ -42,7 +42,7 @@ typedef int (FAR *FARPROCY)();
#define L4INFO 5 // INFORMATION
#define L4IACK 6 // INFORMATION ACK
#define L4RESET 7 // Paula's extension
-
+#define L4CREQX 8 // Paula's extension
extern char MYCALL[]; // 7 chars, ax.25 format
extern char MYALIASTEXT[]; // 6 chars, not null terminated
@@ -177,6 +177,14 @@ typedef struct _TRANSPORTENTRY
int Received;
int ReceivedAfterExpansion;
+ int segsSent;
+ int segsRcvd;
+ int segsResent;
+
+ int NRRID;
+ time_t NRRTime;
+
+ int Service; // For Paula's Connnect to Service
} TRANSPORTENTRY;
@@ -220,6 +228,7 @@ typedef struct ROUTE
BOOL INP3Node;
BOOL NoKeepAlive; // Suppress Keepalive Processing
int LastConnectAttempt; // To stop us trying too often
+ int ConnectionAttempts;
int Status; //
int OldBPQ; // Set if other end is BPQ sending RIF in mS
@@ -239,6 +248,10 @@ typedef struct ROUTE
int RemoteMAXRTT; // For INP3
int RemoteMAXHOPS;
+ char * TCPHost; // For NETROM over TCP
+ int TCPPort;
+ struct NRTCPSTRUCT * TCPSession;
+
} *PROUTE;
// Status Equates
@@ -961,6 +974,9 @@ typedef struct _LINKTABLE
time_t ConnectTime; // For session stats
int bytesRXed; // Info bytes only
int bytesTXed;
+ int framesRXed;
+ int framesTXed;
+ int framesResent;
// Now support compressing L2 Sessions.
// We collect as much data as possible before compressing and re-packetizing
@@ -977,7 +993,7 @@ typedef struct _LINKTABLE
int ReceivedAfterExpansion;
char ApplName[16];
-
+ time_t lastStatusSentTime;
} LINKTABLE;
@@ -1479,6 +1495,15 @@ struct CMDX
};
+struct NETROMX
+{
+ int ServiceNo;
+ char ServiceName[10];
+};
+
+extern struct NETROMX SERVICES[];
+extern int NUMBEROFSSERVICES;
+
#define Disconnect(stream) SessionControl(stream,2,0)
#define Connect(stream) SessionControl(stream,1,0)
diff --git a/cMain.c b/cMain.c
index 45f1384..74b6bc6 100644
--- a/cMain.c
+++ b/cMain.c
@@ -55,7 +55,9 @@ void SaveMH();
VOID InformPartner(struct _LINKTABLE * LINK, int Reason);
VOID L2SENDCOMMAND(struct _LINKTABLE * LINK, int CMD);
void WritePacketLogThread(void * param);
-
+void hookNodeStarted();
+void hookNodeRunning();
+void APIL2Trace(struct _MESSAGE * Message, char Dirn);
#include "configstructs.h"
@@ -63,6 +65,15 @@ extern struct CONFIGTABLE xxcfg;
extern BOOL needAIS;
extern int needADSB;
extern int EnableOARCAPI;
+extern SOCKET NodeAPISocket;
+extern int nodeStartedSent;
+extern SOCKADDR_IN UDPreportdest;
+extern char NodeAPIServer[80];
+extern int NodeAPIPort;
+
+time_t LastNodeStatus = 0;
+
+int nodeStatusTimer = 20 * 60; // 20 mins
struct PORTCONFIG * PortRec;
@@ -313,8 +324,8 @@ VOID LINKINIT(PEXTPORTDATA PORTVEC)
VOID LINKTX(PEXTPORTDATA PORTVEC, PMESSAGE Buffer)
{
// LOOP BACK TO SWITCH
+
struct _LINKTABLE * LINK;
-
LINK = Buffer->Linkptr;
if (LINK)
@@ -1380,13 +1391,13 @@ BOOL Start()
PORT = GetPortTableEntryFromPortNum(ROUTE->NEIGHBOUR_PORT);
- if (Rcfg->pwind & 0x40)
+ if (Rcfg->nokeepalives)
ROUTE->NoKeepAlive = 1;
else
if (PORT != NULL)
ROUTE->NoKeepAlive = PORT->PortNoKeepAlive;
- if (Rcfg->pwind & 0x80 || (PORT && PORT->INP3ONLY))
+ if (Rcfg->inp3 || (PORT && PORT->INP3ONLY))
{
ROUTE->INP3Node = 1;
ROUTE->NoKeepAlive = 0; // Cant have INP3 and NOKEEPALIVES
@@ -1400,6 +1411,12 @@ BOOL Start()
ROUTE->OtherendsRouteQual = ROUTE->OtherendLocked = Rcfg->farQual;
ROUTE->NEIGHBOUR_FLAG = LOCKEDBYCONFIG; // Locked
+
+ if (Rcfg->tcphost)
+ {
+ ROUTE->TCPHost = Rcfg->tcphost;
+ ROUTE->TCPPort = Rcfg->tcpport;
+ }
Rcfg++;
ROUTE++;
@@ -1584,6 +1601,28 @@ BOOL Start()
lastSaveSecs = CurrentSecs = lastSlowSecs = time(NULL);
+ // if EnableOARCAPI set try to resolve host here so we can send Node up event before anything else
+
+ if (EnableOARCAPI)
+ {
+ struct hostent * HostEnt3;
+ HostEnt3 = gethostbyname(NodeAPIServer);
+
+ NodeAPISocket = socket(AF_INET, SOCK_DGRAM, 0);
+ UDPreportdest.sin_family = AF_INET;
+ UDPreportdest.sin_port = htons(NodeAPIPort);
+
+ if (HostEnt3)
+ {
+ memcpy(&UDPreportdest.sin_addr.s_addr,HostEnt3->h_addr,4);
+
+ hookNodeStarted();
+ nodeStartedSent = 1;
+ LastNodeStatus = time(NULL);
+ }
+ }
+
+
return 0;
}
@@ -2177,6 +2216,12 @@ VOID TIMERINTERRUPT()
if (MQTT)
MQTTTimer();
+ if (LastNodeStatus && (time(NULL) - LastNodeStatus) > nodeStatusTimer)
+ {
+ LastNodeStatus = time(NULL);
+ hookNodeRunning();
+ }
+
/*
if (QCOUNT < 200)
{
@@ -2232,6 +2277,10 @@ VOID TIMERINTERRUPT()
}
Message = (struct _MESSAGE *)Buffer;
+
+ if(NodeAPISocket)
+ APIL2Trace(Message, 'T');
+
Message->PORT |= 0x80; // Set TX Bit
BPQTRACE(Message, FALSE); // Dont send TX'ed frames to APRS
@@ -2343,6 +2392,9 @@ L2Packet:
if (MQTT && PORT->PROTOCOL == 0)
MQTTKISSRX(Buffer);
+
+ if(NodeAPISocket &&PORT->PROTOCOL == 0)
+ APIL2Trace(Message, 'R');
// Bridge if requested
@@ -2695,7 +2747,6 @@ int BPQTRACE(MESSAGE * Msg, BOOL TOAPRS)
// And to the Monitor to File system.
-
if (MONTOFILEFLAG) // Trace Enabled?
{
Buffer = GetBuff();
diff --git a/cheaders.h b/cheaders.h
index 4951cac..bd2b259 100644
--- a/cheaders.h
+++ b/cheaders.h
@@ -108,7 +108,7 @@ VOID SendCommandReply(TRANSPORTENTRY * Session, struct DATAMESSAGE * Buffer, int
DllExport struct PORTCONTROL * APIENTRY GetPortTableEntryFromPortNum(int portnum);
int cCOUNT_AT_L2(struct _LINKTABLE * LINK);
-VOID SENDL4CONNECT(TRANSPORTENTRY * Session);
+VOID SENDL4CONNECT(TRANSPORTENTRY * Session, int Service);
VOID CloseSessionPartner(TRANSPORTENTRY * Session);
int COUNTNODES(struct ROUTE * ROUTE);
@@ -445,7 +445,3 @@ DllExport uint64_t APIENTRY GetPortFrequency(int PortNo, char * FreqStringMhz);
void hookL2SessionAccepted(int Port, char * remotecall, char * ourcall, struct _LINKTABLE * LINK);
void hookL2SessionDeleted(struct _LINKTABLE * LINK);
void hookL2SessionAttempt(int Port, char * ourcall, char * remotecall, struct _LINKTABLE * LINK);
-
-void hookL4SessionAttempt(void * STREAM, char * remotecall, char * ourcall);
-void hookL4SessionAccepted(void * STREAM, char * remotecall, char * ourcall);
-void hookL4SessionDeleted(struct TNCINFO * TNC, void * STREAM);
diff --git a/config.c b/config.c
index 167bd83..bb0b2f2 100644
--- a/config.c
+++ b/config.c
@@ -305,7 +305,8 @@ static char *keywords[] =
"APPL5ALIAS", "APPL6ALIAS", "APPL7ALIAS", "APPL8ALIAS",
"APPL1QUAL", "APPL2QUAL", "APPL3QUAL", "APPL4QUAL",
"APPL5QUAL", "APPL6QUAL", "APPL7QUAL", "APPL8QUAL",
-"BTEXT:", "NETROMCALL", "C_IS_CHAT", "MAXRTT", "MAXHOPS", // IPGATEWAY= no longer allowed
+
+"BTEXT:", "NETROMCALL", "C_IS_CHAT", "MAXRTT", "MAXTT", "MAXHOPS", // IPGATEWAY= no longer allowed
"LogL4Connects", "LogAllConnects", "SAVEMH", "ENABLEADIFLOG", "ENABLEEVENTS", "SAVEAPRSMSGS",
"EnableM0LTEMap", "MQTT", "MQTT_HOST", "MQTT_PORT", "MQTT_USER", "MQTT_PASS",
"L4Compress", "L4CompMaxframe", "L4CompPaclen", "L2Compress", "L2CompMaxframe",
@@ -328,7 +329,8 @@ static void * offset[] =
&xxcfg.C_APPL[4].ApplAlias, &xxcfg.C_APPL[5].ApplAlias, &xxcfg.C_APPL[6].ApplAlias, &xxcfg.C_APPL[7].ApplAlias,
&xxcfg.C_APPL[0].ApplQual, &xxcfg.C_APPL[1].ApplQual, &xxcfg.C_APPL[2].ApplQual, &xxcfg.C_APPL[3].ApplQual,
&xxcfg.C_APPL[4].ApplQual, &xxcfg.C_APPL[5].ApplQual, &xxcfg.C_APPL[6].ApplQual, &xxcfg.C_APPL[7].ApplQual,
-&xxcfg.C_BTEXT, &xxcfg.C_NETROMCALL, &xxcfg.C_C, &xxcfg.C_MAXRTT, &xxcfg.C_MAXHOPS, // IPGATEWAY= no longer allowed
+
+&xxcfg.C_BTEXT, &xxcfg.C_NETROMCALL, &xxcfg.C_C, &xxcfg.C_MAXRTT, &xxcfg.C_MAXRTT, &xxcfg.C_MAXHOPS, // IPGATEWAY= no longer allowed
&xxcfg.C_LogL4Connects, &xxcfg.C_LogAllConnects, &xxcfg.C_SaveMH, &xxcfg.C_ADIF, &xxcfg.C_EVENTS, &xxcfg.C_SaveAPRSMsgs,
&xxcfg.C_M0LTEMap, &xxcfg.C_MQTT, &xxcfg.C_MQTT_HOST, &xxcfg.C_MQTT_PORT, &xxcfg.C_MQTT_USER, &xxcfg.C_MQTT_PASS,
&xxcfg.C_L4Compress, &xxcfg.C_L4CompMaxframe, &xxcfg.C_L4CompPaclen, &xxcfg.C_L2Compress, &xxcfg.C_L2CompMaxframe,
@@ -350,7 +352,8 @@ static int routine[] =
13, 13 ,13, 13,
14, 14, 14, 14,
14, 14 ,14, 14,
-15, 0, 2, 9, 9,
+
+15, 0, 2, 9, 9, 9,
2, 2, 1, 2, 2, 2,
2, 2, 0, 1, 20, 20,
1, 1, 1, 1, 1,
@@ -1584,32 +1587,160 @@ int routes(int i)
// strtok and sscanf can't handle successive commas, so split up usig strchr
- memset(Param, 0, 2048);
- strlop(rec, 13);
- strlop(rec, ';');
+ // Now support keyword=value format
- ptr1 = rec;
-
- while (ptr1 && *ptr1 && n < 8)
+ if (strchr(rec, '='))
{
- ptr2 = strchr(ptr1, ',');
- if (ptr2) *ptr2++ = 0;
+ // New format
+ // call quality port window frack paclen farquality inp3 nokeepalives tcp
+
+ char * ptr, *context;
+ char copy[512] = "";
+
+ if (strlen(rec) < 512)
+ strcpy(copy, rec);
+
+ _strupr(rec);
+
+ ptr = strtok_s(rec, " ,=", &context);
+
+ while (ptr)
+ {
+ if (strcmp(ptr, "CALL") == 0)
+ {
+ char * Call = strtok_s(NULL, ",=", &context);
+
+ if (strlen(Call) < 80)
+ strcpy(Route->call, Call);
+
+ }
+ else if (strcmp(ptr, "PORT") == 0)
+ {
+ char * val = strtok_s(NULL, " ,=", &context);
+
+ if (val)
+ Route->port = atoi(val);
+ }
+
+ else if (strcmp(ptr, "QUALITY") == 0)
+ {
+ char * val = strtok_s(NULL, " ,=", &context);
+
+ if (val)
+ Route->quality = atoi(val);
+ }
+
+ else if (strcmp(ptr, "FRACK") == 0)
+ {
+ char * val = strtok_s(NULL, " ,=", &context);
+
+ if (val)
+ Route->pfrack = atoi(val);
+ }
+
+ else if (strcmp(ptr, "PACLEN") == 0)
+ {
+ char * val = strtok_s(NULL, " ,=", &context);
+
+ if (val)
+ Route->pwind = atoi(val);
+ }
+
+ else if (strcmp(ptr, "WINDOW") == 0)
+ {
+ char * val = strtok_s(NULL, " ,=", &context);
+
+ if (val)
+ Route->pwind = atoi(val);
+ }
+
+ else if (strcmp(ptr, "FARQUALITY") == 0)
+ {
+ char * val = strtok_s(NULL, " ,=", &context);
+
+ if (val)
+ Route->farQual = atoi(val);
+ }
- strcpy(&Param[n++][0], ptr1);
- ptr1 = ptr2;
- while(ptr1 && *ptr1 && *ptr1 == ' ')
- ptr1++;
+ else if (strcmp(ptr, "INP3") == 0)
+ {
+ char * val = strtok_s(NULL, " ,=", &context);
+
+ if (val)
+ Route->inp3 = atoi(val);
+ }
+
+ else if (strcmp(ptr, "NOKEEPALIVES") == 0)
+ {
+ char * val = strtok_s(NULL, " ,=", &context);
+
+ if (val)
+ Route->farQual = atoi(val);
+ }
+
+
+ else if (strcmp(ptr, "TCP") == 0)
+ {
+ char * val = strtok_s(NULL, " ,=", &context);
+
+ if (val)
+ {
+ char * port = strlop(val, ':');
+
+ Route->tcphost = _strdup(val);
+ if (port)
+ Route->tcpport = atoi(port);
+ else
+ Route->tcpport = 53119;
+ }
+ }
+ else
+ {
+ Consoleprintf("Bad Route %s\r\n",rec);
+ err_flag = 1;
+ break;
+ }
+
+ ptr = strtok_s(NULL, " ,=", &context);
+ }
}
- strcpy(Route->call, &Param[0][0]);
+ else
+ {
+
+ memset(Param, 0, 2048);
+ strlop(rec, 13);
+ strlop(rec, ';');
+
+ ptr1 = rec;
+
+ while (ptr1 && *ptr1 && n < 8)
+ {
+ ptr2 = strchr(ptr1, ',');
+ if (ptr2) *ptr2++ = 0;
+
+ strcpy(&Param[n++][0], ptr1);
+ ptr1 = ptr2;
+ while(ptr1 && *ptr1 && *ptr1 == ' ')
+ ptr1++;
+ }
+
+ strcpy(Route->call, &Param[0][0]);
- Route->quality = atoi(Param[1]);
- Route->port = atoi(Param[2]);
- Route->pwind = atoi(Param[3]);
- Route->pfrack = atoi(Param[4]);
- Route->ppacl = atoi(Param[5]);
- inp3 = atoi(Param[6]);
- Route->farQual = atoi(Param[7]);
+ Route->quality = atoi(Param[1]);
+ Route->port = atoi(Param[2]);
+ Route->pwind = atoi(Param[3]);
+ Route->pfrack = atoi(Param[4]);
+ Route->ppacl = atoi(Param[5]);
+ inp3 = atoi(Param[6]);
+ Route->farQual = atoi(Param[7]);
+
+ if (inp3 & 1)
+ Route->inp3 = 1;
+
+ if (inp3 & 2)
+ Route->nokeepalives = 1;
+ }
if (Route->farQual < 0 || Route->farQual > 255)
{
@@ -1634,14 +1765,6 @@ int routes(int i)
err_flag = 1;
}
- // Use top bit of window as INP3 Flag, next as NoKeepAlive
-
- if (inp3 & 1)
- Route->pwind |= 0x80;
-
- if (inp3 & 2)
- Route->pwind |= 0x40;
-
if (err_flag == 1)
{
Consoleprintf("%s\r\n",rec);
diff --git a/configstructs.h b/configstructs.h
index 30c4c28..013d725 100644
--- a/configstructs.h
+++ b/configstructs.h
@@ -94,6 +94,10 @@ struct ROUTECONFIG
int pfrack;
int ppacl;
int farQual;
+ int inp3;
+ int nokeepalives;
+ char * tcphost;
+ int tcpport;
};
struct CONFIGTABLE
diff --git a/debug/bpq32.pdb b/debug/bpq32.pdb
new file mode 100644
index 0000000..1e17966
Binary files /dev/null and b/debug/bpq32.pdb differ
diff --git a/ipcode.h b/ipcode.h
index cb3fb8c..6bc560c 100644
--- a/ipcode.h
+++ b/ipcode.h
@@ -78,6 +78,8 @@ typedef struct _ETHARP
UCHAR TARGETHWADDR[6];
uint32_t TARGETIPADDR;
+ char Padding[18]; // For min ether send of 60
+
} ETHARP, *PETHARP;
typedef struct _RIP2HDDR
diff --git a/makefile b/makefile
index 0152c9a..26403e5 100644
--- a/makefile
+++ b/makefile
@@ -13,7 +13,7 @@ OBJS = pngwtran.o pngrtran.o pngset.o pngrio.o pngwio.o pngtrans.o pngrutil.o pn
MailCommands.o MailDataDefs.o LinBPQ.o MailRouting.o MailTCP.o MBLRoutines.o md5.o Moncode.o \
NNTPRoutines.o RigControl.o TelnetV6.o WINMOR.o TNCCode.o UZ7HODrv.o WPRoutines.o \
SCSTrackeMulti.o SCSPactor.o SCSTracker.o HanksRT.o UIRoutines.o AGWAPI.o AGWMoncode.o \
- DRATS.o FreeDATA.o base64.o Events.o nodeapi.o mailapi.o mqtt.o RHP.o
+ DRATS.o FreeDATA.o base64.o Events.o nodeapi.o mailapi.o mqtt.o RHP.o NETROMTCP.o
# Configuration:
diff --git a/telnetserver.h b/telnetserver.h
index 48f87d0..0bb4986 100644
--- a/telnetserver.h
+++ b/telnetserver.h
@@ -38,6 +38,7 @@ struct ConnectionInfo
BOOL SyncMode; // RMS Relay Sync
BOOL HTTPMode; // HTTP Server
BOOL APIMode; // REST API Server
+ BOOL NETROMMode;
BOOL TriMode; // Trimode emulation
BOOL TriModeConnected; // Set when remote session is connected - now send data to DataSock
SOCKET TriModeDataSock; // Data Socket
@@ -73,6 +74,9 @@ struct ConnectionInfo
int WebSocks;
char WebURL[32]; // URL for WebSocket Connection
int WebSecure; // Set if secure session
+
+ int Connecting; // For outward connect
+ int Connected;
};
diff --git a/tncinfo.h b/tncinfo.h
index efbd1a5..2e2c553 100644
--- a/tncinfo.h
+++ b/tncinfo.h
@@ -116,6 +116,7 @@ struct TCPINFO
int SNMPPort;
int DRATSPort;
int CMDPort[33];
+ int NETROMPort;
char RELAYHOST[64];
char CMSServer[64];
BOOL FallbacktoRelay; // Use Relsy if can't connect to CMS
@@ -160,13 +161,14 @@ struct TCPINFO
SOCKET TCPSock;
SOCKET FBBsock[100];
SOCKET Relaysock;
- SOCKET HTTPsock;
+ SOCKET HTTPSock;
SOCKET APIsock;
SOCKET TriModeSock;
SOCKET TriModeDataSock;
SOCKET Syncsock;
SOCKET DRATSsock;
SOCKET SNMPsock;
+ SOCKET NETROMSock;
struct ConnectionInfo * TriModeControlSession;
SOCKET sock6;
@@ -176,6 +178,7 @@ struct TCPINFO
SOCKET APIsock6;
SOCKET Syncsock6;
SOCKET DRATSsock6;
+ SOCKET NETROMSock6;
fd_set ListenSet;
SOCKET maxsock;