From 367ab8fb01191ec54c91810b1896c41fdf7de911 Mon Sep 17 00:00:00 2001 From: Dave Hibberd Date: Sun, 9 Nov 2025 22:34:20 +0000 Subject: [PATCH] New upstream version 6.0.25.9+repack --- AGWMoncode.c | 8 + APRSCode.c | 30 +- ARDOP.c | 188 +++++---- BBSUtilities.c | 8 +- BPQINP3.c | 363 ++++++++++------ BPQMail.aps | Bin 92636 -> 70556 bytes BPQNRR.c | 34 +- Bpq32.c | 188 ++++++++- Cmd.c | 421 +++++++++++++++++-- CommonCode.c | 54 ++- DRATS.c | 21 +- Events.c | 1037 +++++++++++++++++++++++++++++++++++++++++++++- FLDigi.c | 8 +- FreeDATA.c | 5 + HanksRT.c | 2 +- KernelScript1.rc | 13 + L2Code.c | 360 ++++++++++++---- L3Code.c | 91 +++- L4Code.c | 433 ++++++++----------- LinBPQ.c | 39 +- MailTCP.c | 23 +- Moncode.c | 110 ++++- NETROMTCP.c | 585 ++++++++++++++++++++++++++ RigControl.c | 32 +- TelnetV6.c | 158 +++++-- UIARQ.c | 5 + UZ7HODrv.c | 121 +++--- VARA.c | 8 +- Versions.h | 6 +- WINMOR.c | 7 + WebMail.c | 4 +- asmstrucs.h | 68 ++- bpqaxip.c | 21 +- cMain.c | 101 ++++- cheaders.h | 6 +- compatbits.h | 38 +- config.c | 204 +++++++-- configstructs.h | 7 + datadefs.c | 3 + ipcode.h | 2 + kiss.c | 10 +- lzhuf32.c | 152 +++---- mailapi.c | 4 +- makefile | 2 +- nodeapi.c | 204 ++++++++- pngwutil.c | 5 +- telnetserver.h | 4 + tncinfo.h | 5 +- 48 files changed, 4189 insertions(+), 1009 deletions(-) create mode 100644 NETROMTCP.c diff --git a/AGWMoncode.c b/AGWMoncode.c index da9f81e..b4e0451 100644 --- a/AGWMoncode.c +++ b/AGWMoncode.c @@ -509,6 +509,14 @@ UCHAR * DISPLAY_NETROM(MESSAGE * ADJBUFFER, UCHAR * Output, int MsgLen, int DoNo return Output; } + if (ADJBUFFER->L2DATA[0] == 0xfe) // Paula's Nodes Poll + { + memcpy(Alias, ++ptr, 6); + Output += sprintf((char *)Output, " NODES POLL from %s\r", Alias); + return Output; + } + + // Display normal NET/ROM transmissions Output += sprintf((char *)Output, " NET/ROM\r "); diff --git a/APRSCode.c b/APRSCode.c index 2ee3b5f..6e65001 100644 --- a/APRSCode.c +++ b/APRSCode.c @@ -7693,7 +7693,7 @@ VOID APRSProcessHTTPMessage(SOCKET sock, char * MsgPtr, BOOL LOCAL, BOOL COOKIE) while (ptr) { char ToLopped[11] = ""; - + if (ptr->Acked) strcpy(Retries, "A"); else if (ptr->Retries == 0) @@ -7701,26 +7701,26 @@ VOID APRSProcessHTTPMessage(SOCKET sock, char * MsgPtr, BOOL LOCAL, BOOL COOKIE) else sprintf(Retries, "%d", ptr->Retries); - memcpy(ToLopped, ptr->ToCall, 10); - strlop(ToLopped, ' '); + memcpy(ToLopped, ptr->ToCall, 10); + strlop(ToLopped, ' '); - OutputLen += sprintf(&OutBuffer[OutputLen], WebTXLine, - ptr->ToCall, ptr->Seq, ptr->Time, Retries, ptr->Text); - ptr = ptr->Next; + OutputLen += sprintf(&OutBuffer[OutputLen], WebTXLine, + ptr->ToCall, ptr->Seq, ptr->Time, Retries, ptr->Text); + ptr = ptr->Next; - if (OutputLen > 99000) - break; + if (OutputLen > 99000) + break; - } + } - OutputLen += sprintf(&OutBuffer[OutputLen], "%s", WebTrailer); + OutputLen += sprintf(&OutBuffer[OutputLen], "%s", WebTrailer); - HeaderLen = sprintf(Header, "HTTP/1.0 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", OutputLen); - sendandcheck(sock, Header, HeaderLen); - sendandcheck(sock, OutBuffer, OutputLen); + HeaderLen = sprintf(Header, "HTTP/1.0 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", OutputLen); + sendandcheck(sock, Header, HeaderLen); + sendandcheck(sock, OutBuffer, OutputLen); + + return; - return; - } diff --git a/ARDOP.c b/ARDOP.c index ade0ecf..ef92fad 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 @@ -460,114 +466,114 @@ static int ProcessLine(char * buf, int Port) else return FALSE; // Must start with ADDR - TNC->InitScript = malloc(1000); - TNC->InitScript[0] = 0; + TNC->InitScript = malloc(1000); + TNC->InitScript[0] = 0; - ptr = strtok(NULL, " \t\n\r"); + ptr = strtok(NULL, " \t\n\r"); - if (ptr) + if (ptr) + { + if (_stricmp(ptr, "PTT") == 0) { - if (_stricmp(ptr, "PTT") == 0) - { - ptr = strtok(NULL, " \t\n\r"); + ptr = strtok(NULL, " \t\n\r"); - if (ptr) - { - DecodePTTString(TNC, ptr); - ptr = strtok(NULL, " \t\n\r"); - } - } - } - - if (ptr) - { - if (_memicmp(ptr, "PATH", 4) == 0) - { - p_cmd = strtok(NULL, "\n\r"); - if (p_cmd) TNC->ProgramPath = _strdup(p_cmd); - } - } - - TNC->MaxConReq = 10; // Default - TNC->OldMode = FALSE; // Default - - // Read Initialisation lines - - while(TRUE) - { - if (GetLine(buf) == 0) - return TRUE; - - strcpy(errbuf, buf); - - if (memcmp(buf, "****", 4) == 0) - return TRUE; - - ptr = strchr(buf, ';'); if (ptr) { - *ptr++ = 13; - *ptr = 0; + DecodePTTString(TNC, ptr); + ptr = strtok(NULL, " \t\n\r"); } - - if ((_memicmp(buf, "CAPTURE", 7) == 0) || (_memicmp(buf, "PLAYBACK", 8) == 0)) - {} // Ignore - else -/* + } + } + + if (ptr) + { + if (_memicmp(ptr, "PATH", 4) == 0) + { + p_cmd = strtok(NULL, "\n\r"); + if (p_cmd) TNC->ProgramPath = _strdup(p_cmd); + } + } + + TNC->MaxConReq = 10; // Default + TNC->OldMode = FALSE; // Default + + // Read Initialisation lines + + while(TRUE) + { + if (GetLine(buf) == 0) + return TRUE; + + strcpy(errbuf, buf); + + if (memcmp(buf, "****", 4) == 0) + return TRUE; + + ptr = strchr(buf, ';'); + if (ptr) + { + *ptr++ = 13; + *ptr = 0; + } + + if ((_memicmp(buf, "CAPTURE", 7) == 0) || (_memicmp(buf, "PLAYBACK", 8) == 0)) + {} // Ignore + else + /* if (_memicmp(buf, "PATH", 4) == 0) { - char * Context; - p_cmd = strtok_s(&buf[5], "\n\r", &Context); - if (p_cmd) TNC->ProgramPath = _strdup(p_cmd); + char * Context; + p_cmd = strtok_s(&buf[5], "\n\r", &Context); + if (p_cmd) TNC->ProgramPath = _strdup(p_cmd); } else -*/ + */ if (_memicmp(buf, "PACKETCHANNELS", 14) == 0) // Packet Channels TNC->PacketChannels = atoi(&buf[14]); else - if (_memicmp(buf, "MAXCONREQ", 9) == 0) // Hold Time for Busy Detect - TNC->MaxConReq = atoi(&buf[9]); + if (_memicmp(buf, "MAXCONREQ", 9) == 0) // Hold Time for Busy Detect + TNC->MaxConReq = atoi(&buf[9]); - else - if (_memicmp(buf, "STARTINROBUST", 13) == 0) - TNC->StartInRobust = TRUE; - - else - if (_memicmp(buf, "ROBUST", 6) == 0) - { - if (_memicmp(&buf[7], "TRUE", 4) == 0) - TNC->Robust = TRUE; - - strcat (TNC->InitScript, buf); - } - else - if (_memicmp(buf, "LOGDIR ", 7) == 0) - TNC->LogPath = _strdup(&buf[7]); - else - if (_memicmp(buf, "ENABLEPACKET", 12) == 0) - { - if (TNC->PacketChannels == 0) - TNC->PacketChannels = 5; - // AddVirtualKISSPort(TNC, Port, buf); - } + else + if (_memicmp(buf, "STARTINROBUST", 13) == 0) + TNC->StartInRobust = TRUE; -// else if (_memicmp(buf, "PAC ", 4) == 0 && _memicmp(buf, "PAC MODE", 8) != 0) -// { - // PAC MODE goes to TNC, others are parsed locally -// -// ConfigVirtualKISSPort(TNC, buf); -// } - else if (standardParams(TNC, buf) == FALSE) - strcat(TNC->InitScript, buf); - } + else + if (_memicmp(buf, "ROBUST", 6) == 0) + { + if (_memicmp(&buf[7], "TRUE", 4) == 0) + TNC->Robust = TRUE; + + strcat (TNC->InitScript, buf); + } + else + if (_memicmp(buf, "LOGDIR ", 7) == 0) + TNC->LogPath = _strdup(&buf[7]); + else + if (_memicmp(buf, "ENABLEPACKET", 12) == 0) + { + if (TNC->PacketChannels == 0) + TNC->PacketChannels = 5; + // AddVirtualKISSPort(TNC, Port, buf); + } + + // else if (_memicmp(buf, "PAC ", 4) == 0 && _memicmp(buf, "PAC MODE", 8) != 0) + // { + // PAC MODE goes to TNC, others are parsed locally + // + // ConfigVirtualKISSPort(TNC, buf); + // } + else if (standardParams(TNC, buf) == FALSE) + strcat(TNC->InitScript, buf); + } return (TRUE); } -void ARDOPThread(struct TNCINFO * TNC); +void ARDOPThread(VOID * Param); VOID ARDOPProcessDataSocketData(int port); int ConnecttoARDOP(struct TNCINFO * TNC); static VOID ARDOPProcessReceivedData(struct TNCINFO * TNC); @@ -1035,8 +1041,10 @@ static size_t ExtProc(int fn, int port, PDATAMESSAGE buff) { TNC->Busy--; if (TNC->Busy == 0) + { MySetWindowText(TNC->xIDC_CHANSTATE, "Clear"); strcpy(TNC->WEB_CHANSTATE, "Clear"); + } } } @@ -2312,12 +2320,13 @@ int ConnecttoARDOP(struct TNCINFO * TNC) return 0; } -VOID ARDOPThread(struct TNCINFO * TNC) +VOID ARDOPThread(VOID * Param) { // Opens sockets and looks for data on control and data sockets. // Socket may be TCP/IP or Serial + struct TNCINFO * TNC = (struct TNCINFO *) Param; char Msg[255]; int err, i, ret; u_long param=1; @@ -5758,8 +5767,7 @@ VOID ARDOPSCSPoll(struct TNCINFO * TNC) // Probably only for Teensy with ESP01. Runs SCS Emulator over a TCP Link - -VOID SerialConnecttoTCPThread(struct TNCINFO * TNC); +VOID SerialConnecttoTCPThread(VOID * Param); int SerialConnecttoTCP(struct TNCINFO * TNC) { @@ -5767,9 +5775,9 @@ int SerialConnecttoTCP(struct TNCINFO * TNC) return 0; } - -VOID SerialConnecttoTCPThread(struct TNCINFO * TNC) +VOID SerialConnecttoTCPThread(VOID * Param) { + struct TNCINFO * TNC = (struct TNCINFO *) Param; char Msg[255]; int i; u_long param = 1; diff --git a/BBSUtilities.c b/BBSUtilities.c index e803500..e6f7ade 100644 --- a/BBSUtilities.c +++ b/BBSUtilities.c @@ -3701,10 +3701,10 @@ void DoKillCommand(CIRCUIT * conn, struct UserInfo * user, char * Cmd, char * Ar if (conn->sysop) { if (Arg1) - if (KillMessagesFrom(conn, user, Arg1) == 0); + if (KillMessagesFrom(conn, user, Arg1) == 0) BBSputs(conn, "No Messages found\r"); - return; + return; } } @@ -6556,7 +6556,7 @@ nextline: { char APRS[128]; char Call[16]; - int SSID = user->flags >> 28; + int SSID = (user->flags >> 28) & 15; // on some platforms this is treated as signed ?? if (SSID) sprintf(Call, "%s-%d", Msg->to, SSID); @@ -13395,7 +13395,7 @@ int DeleteRedundantMessages() { while(n--) { - if (stat(namelist[n]->d_name, &STAT) == 0); + if (stat(namelist[n]->d_name, &STAT) == 0) { Msgno = atoi(&namelist[n]->d_name[2]); diff --git a/BPQINP3.c b/BPQINP3.c index a62ecba..de4bf76 100644 --- a/BPQINP3.c +++ b/BPQINP3.c @@ -35,16 +35,26 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #include //#include "vmm.h" -uint64_t timeLoadedMS = 0; +uint64_t INP3timeLoadedMS = 0; + +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 @@ -62,8 +72,8 @@ typedef struct _RTTMSG UCHAR ALIAS[7]; UCHAR VERSION[12]; UCHAR SWVERSION[9]; - UCHAR FLAGS[10]; - UCHAR PADDING[147]; + UCHAR FLAGS[20]; + UCHAR PADDING[137]; } RTTMSG; @@ -102,14 +112,14 @@ int RTTTimeout = 6; // 1 Min (Horizon is 1 min) VOID InitialiseRTT() { - UCHAR temp[sizeof(RTTMsg.FLAGS) + 4]; + UCHAR temp[256] = ""; memset(&RTTMsg, ' ', sizeof(struct _RTTMSG)); memcpy(RTTMsg.ID, "L3RTT: ", 7); memcpy(RTTMsg.VERSION, "LEVEL3_V2.1 ", 12); - memcpy(RTTMsg.SWVERSION, "BPQ32001 ", 9); - _snprintf(temp, sizeof(temp), "$M%d $N ", MAXRTT); // trailing spaces extend to ensure padding if the length of characters for MAXRTT changes. - memcpy(RTTMsg.FLAGS, temp, 10); // But still limit the actual characters copied. + memcpy(RTTMsg.SWVERSION, "BPQ32002 ", 9); + _snprintf(temp, sizeof(temp), "$M%d $N $H%d ", MAXRTT, MaxHops); // trailing spaces extend to ensure padding if the length of characters for MAXRTT changes. + memcpy(RTTMsg.FLAGS, temp, 20); // But still limit the actual characters copied. memcpy(RTTMsg.ALIAS, &MYALIASTEXT, 6); RTTMsg.ALIAS[6] = ' '; } @@ -125,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); } @@ -141,7 +152,7 @@ VOID DeleteINP3Routes(struct ROUTE * Route) Call1[ConvFromAX25(Route->NEIGHBOUR_CALL, Call1)] = 0; - Debugprintf("Deleting INP3 routes via %s", Call1); + if (DEBUGINP3) Debugprintf("Deleting INP3 routes via %s", Call1); // Delete any INP3 Dest entries via this Route @@ -177,7 +188,7 @@ VOID DeleteINP3Routes(struct ROUTE * Route) // If we are cleaning up after a sabm on an existing link (frmr or other end reloaded) then we don't need to tell anyone - the routes should be reestablished very quickly - Debugprintf("Deleting First INP3 Route to %s", Call2); + if (DEBUGINP3) Debugprintf("Deleting First INP3 Route to %s", Call2); if (Dest->INP3ROUTE[1].ROUT_NEIGHBOUR == 0) { @@ -186,7 +197,7 @@ VOID DeleteINP3Routes(struct ROUTE * Route) Dest->INP3ROUTE[0].SRTT = 60000; Dest->INP3ROUTE[0].Hops = 255; - Debugprintf("Was the only INP3 route"); + if (DEBUGINP3) Debugprintf("Was the only INP3 route"); if (Dest->DEST_ROUTE == 4) // we were using it Dest->DEST_ROUTE = 0; @@ -206,7 +217,7 @@ VOID DeleteINP3Routes(struct ROUTE * Route) if (Dest->INP3ROUTE[1].ROUT_NEIGHBOUR == Route) { - Debugprintf("Deleting 2nd INP3 Route to %s", Call2); + if (DEBUGINP3) Debugprintf("Deleting 2nd INP3 Route to %s", Call2); memcpy(&Dest->INP3ROUTE[1], &Dest->INP3ROUTE[2], sizeof(struct INP3_DEST_ROUTE_ENTRY)); memset(&Dest->INP3ROUTE[2], 0, sizeof(struct INP3_DEST_ROUTE_ENTRY)); @@ -215,7 +226,7 @@ VOID DeleteINP3Routes(struct ROUTE * Route) if (Dest->INP3ROUTE[2].ROUT_NEIGHBOUR == Route) { - Debugprintf("Deleting 3rd INP3 Route to %s", Call2); + if (DEBUGINP3) Debugprintf("Deleting 3rd INP3 Route to %s", Call2); memset(&Dest->INP3ROUTE[2], 0, sizeof(struct INP3_DEST_ROUTE_ENTRY)); continue; } @@ -339,10 +350,10 @@ VOID ProcessRTTReply(struct ROUTE * Route, struct _L3MESSAGEBUFFER * Buff) Route->Timeout = 0; // Got Response sscanf(&Buff->L4DATA[6], "%d", &OrigTime); - RTT = (GetTickCount() - timeLoadedMS) - OrigTime; + RTT = (int)((GetTickCount() - INP3timeLoadedMS) / 10 - (OrigTime)); // We work internally in mS if (RTT > 60000) - return; // Ignore if more than 60 secs + return; // Ignore if more than 60 secs (why ??) Route->RTT = RTT; @@ -351,11 +362,13 @@ VOID ProcessRTTReply(struct ROUTE * Route, struct _L3MESSAGEBUFFER * Buff) else Route->SRTT = ((Route->SRTT * 80)/100) + ((RTT * 20)/100); + Route->RTTIncrement = Route->SRTT / 2; // Half for one way time. + if ((Route->Status & GotRTTResponse) == 0) { // Link is just starting - Debugprintf("INP3 got first RTT reply from %s - Link is (Re)staring", Normcall); + if (DEBUGINP3) Debugprintf("INP3 got first RTT reply from %s - Link is (Re)staring", Normcall); Route->Status |= GotRTTResponse; } @@ -374,10 +387,10 @@ VOID ProcessINP3RIF(struct ROUTE * Route, UCHAR * ptr1, int msglen, int Port) char Normcall[10]; Normcall[ConvFromAX25(Route->NEIGHBOUR_LINK->LINKCALL, Normcall)] = 0; - Debugprintf("Processing RIF from %s INP3Node %d Route SRTT %d", Normcall, Route->INP3Node, Route->SRTT); + if (DEBUGINP3) Debugprintf("Processing RIF from %s INP3Node %d Route SRTT %d", Normcall, Route->INP3Node, Route->SRTT); if (Route->SRTT == 0) - Debugprintf("INP3 Zero SRTT"); + if (DEBUGINP3) Debugprintf("INP3 Zero SRTT"); #ifdef NOINP3 @@ -403,7 +416,7 @@ VOID ProcessINP3RIF(struct ROUTE * Route, UCHAR * ptr1, int msglen, int Port) { if (msglen < 10) { - Debugprintf("Corrupt INP3 Message"); + if (DEBUGINP3) Debugprintf("Corrupt INP3 Message"); return; } @@ -421,7 +434,12 @@ VOID ProcessINP3RIF(struct ROUTE * Route, UCHAR * ptr1, int msglen, int Port) // rtt is value from remote node. Add our RTT to that node - rtt += Route->SRTT; + // if other end is old bpq then value is mS otherwise 10 mS unita + + if (Route->OldBPQ) + rtt /= 10; + +// rtt += Route->SRTT; // Don't do this - other end has added linkrtt msglen -= 10; @@ -439,7 +457,7 @@ VOID ProcessINP3RIF(struct ROUTE * Route, UCHAR * ptr1, int msglen, int Port) memcpy(alias, ptr1+2, len-2); else { - Debugprintf("Corrupt INP3 Message"); + if (DEBUGINP3) Debugprintf("Corrupt INP3 Message"); return; } } @@ -477,13 +495,13 @@ VOID UpdateNode(struct ROUTE * Route, UCHAR * axcall, UCHAR * alias, int hops, if (CompareCalls(axcall, NETROMCALL)) { - Debugprintf("INP3 for our Nodecall - discarding"); + if (DEBUGINP3) Debugprintf("INP3 for our Nodecall - discarding"); return; } if (CheckExcludeList(axcall) == 0) { - Debugprintf("INP3 excluded - discarding"); + if (DEBUGINP3) Debugprintf("INP3 excluded - discarding"); return; } @@ -493,7 +511,7 @@ VOID UpdateNode(struct ROUTE * Route, UCHAR * axcall, UCHAR * alias, int hops, if (CompareCalls(axcall, APPL->APPLCALL)) { - Debugprintf("INP3 for an APPLCALL - discarding"); + if (DEBUGINP3) Debugprintf("INP3 for an APPLCALL - discarding"); return; } } @@ -502,20 +520,20 @@ VOID UpdateNode(struct ROUTE * Route, UCHAR * axcall, UCHAR * alias, int hops, if (hops > MaxHops && hops < 255) { ConvFromAX25(axcall, call); - Debugprintf("INP3 Node %s Hops %d RTT %d Ignored - Hop Count too high", call, hops, rtt); + if (DEBUGINP3) Debugprintf("INP3 Node %s Hops %d RTT %d Ignored - Hop Count too high", call, hops, rtt); return; } if (rtt > MAXRTT && rtt < 60000) { ConvFromAX25(axcall, call); - Debugprintf("INP3 Node %s Hops %d RTT %d Ignored - rtt too high", call, hops, rtt); + if (DEBUGINP3) Debugprintf("INP3 Node %s Hops %d RTT %d Ignored - rtt too high", call, hops, rtt); return; } if (rtt >= 60000) { - Debugprintf("INP3 RTT > 60000 - discarding"); + if (DEBUGINP3) Debugprintf("INP3 RTT > 60000 - discarding"); return; } @@ -524,7 +542,7 @@ VOID UpdateNode(struct ROUTE * Route, UCHAR * axcall, UCHAR * alias, int hops, if (Dest == NULL) { - Debugprintf("INP3 Table Full - discarding"); + if (DEBUGINP3) Debugprintf("INP3 Table Full - discarding"); return; // Table Full } @@ -548,7 +566,7 @@ VOID UpdateNode(struct ROUTE * Route, UCHAR * axcall, UCHAR * alias, int hops, NUMBEROFNODES++; ConvFromAX25(Dest->DEST_CALL, call); - Debugprintf("INP3 Adding New Node %s Hops %d RTT %d", call, hops, rtt); + if (DEBUGINP3) Debugprintf("INP3 Adding New Node %s Hops %d RTT %d", call, hops, rtt); return; @@ -556,14 +574,14 @@ Found: if (Dest->DEST_STATE & 0x80) // Application Entry { - Debugprintf("INP3 Application Entry - discarding"); + if (DEBUGINP3) Debugprintf("INP3 Application Entry - discarding"); return; } // Update ALIAS ConvFromAX25(Dest->DEST_CALL, call); - Debugprintf("INP3 Updating Node %s Hops %d RTT %d", call, hops, rtt); + if (DEBUGINP3) Debugprintf("INP3 Updating Node %s Hops %d RTT %d", call, hops, rtt); if (alias[0] > ' ') memcpy(Dest->DEST_ALIAS, alias, 6); @@ -574,7 +592,7 @@ Found: if (ROUTEPTR->ROUT_NEIGHBOUR == Route) { - Debugprintf("INP3 Already have as route[0] - updating"); + if (DEBUGINP3) Debugprintf("INP3 Already have as route[0] - updating"); UpdateRoute(Dest, ROUTEPTR, hops, rtt); return; } @@ -583,7 +601,7 @@ Found: if (ROUTEPTR->ROUT_NEIGHBOUR == Route) { - Debugprintf("INP3 Already have as route[1] - updating"); + if (DEBUGINP3) Debugprintf("INP3 Already have as route[1] - updating"); UpdateRoute(Dest, ROUTEPTR, hops, rtt); return; } @@ -592,7 +610,7 @@ Found: if (ROUTEPTR->ROUT_NEIGHBOUR == Route) { - Debugprintf("INP3 Already have as route[2] - updating"); + if (DEBUGINP3) Debugprintf("INP3 Already have as route[2] - updating"); UpdateRoute(Dest, ROUTEPTR, hops, rtt); return; } @@ -608,7 +626,7 @@ Found: { // Add here - Debugprintf("INP3 adding as route[%d]", i); + if (DEBUGINP3) Debugprintf("INP3 adding as route[%d]", i); AddHere(ROUTEPTR, Route, hops, rtt); SortRoutes(Dest); return; @@ -616,7 +634,7 @@ Found: ROUTEPTR++; } - Debugprintf("INP3 All entries in use - see if this is better than existing"); + if (DEBUGINP3) Debugprintf("INP3 All entries in use - see if this is better than existing"); // Full, see if this is better @@ -626,7 +644,7 @@ Found: { // We are better. Move others down and add on front - Debugprintf("INP3 Replacing route 0"); + if (DEBUGINP3) Debugprintf("INP3 Replacing route 0"); memcpy(&Dest->INP3ROUTE[2], &Dest->INP3ROUTE[1], sizeof(struct INP3_DEST_ROUTE_ENTRY)); memcpy(&Dest->INP3ROUTE[1], &Dest->INP3ROUTE[0], sizeof(struct INP3_DEST_ROUTE_ENTRY)); @@ -638,7 +656,7 @@ Found: { // We are better. Move 2nd down and add - Debugprintf("INP3 Replacing route 1"); + if (DEBUGINP3) Debugprintf("INP3 Replacing route 1"); memcpy(&Dest->INP3ROUTE[2], &Dest->INP3ROUTE[1], sizeof(struct INP3_DEST_ROUTE_ENTRY)); AddHere(&Dest->INP3ROUTE[1], Route, hops, rtt); return; @@ -648,13 +666,13 @@ Found: { // We are better. Add here - Debugprintf("INP3 Replacing route 2"); + if (DEBUGINP3) Debugprintf("INP3 Replacing route 2"); AddHere(&Dest->INP3ROUTE[2], Route, hops, rtt); return; } - Debugprintf("INP3 Worse that any existing route"); + if (DEBUGINP3) Debugprintf("INP3 Worse that any existing route"); // Worse than any - ignore @@ -729,13 +747,16 @@ VOID SortRoutes(struct DEST_LIST * Dest) { char Call1[10], Call2[10], Call3[10]; + // force route re-evaluation + + Dest->DEST_ROUTE = 0; // May now be out of order if (Dest->INP3ROUTE[1].ROUT_NEIGHBOUR == 0) { Call1[ConvFromAX25(Dest->INP3ROUTE[0].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, Call1)] = 0; - Debugprintf("INP3 1 route %d %s", Dest->INP3ROUTE[0].SRTT, Call1); + if (DEBUGINP3) Debugprintf("INP3 1 route %d %s", Dest->INP3ROUTE[0].SRTT, Call1); return; // Only One, so cant be out of order } if (Dest->INP3ROUTE[2].ROUT_NEIGHBOUR == 0) @@ -745,7 +766,7 @@ VOID SortRoutes(struct DEST_LIST * Dest) Call1[ConvFromAX25(Dest->INP3ROUTE[0].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, Call1)] = 0; Call2[ConvFromAX25(Dest->INP3ROUTE[1].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, Call2)] = 0; - Debugprintf("INP3 2 routes %d %s %d %s", Dest->INP3ROUTE[0].SRTT, Call1, Dest->INP3ROUTE[1].SRTT, Call2); + if (DEBUGINP3) Debugprintf("INP3 2 routes %d %s %d %s", Dest->INP3ROUTE[0].SRTT, Call1, Dest->INP3ROUTE[1].SRTT, Call2); if (Dest->INP3ROUTE[0].SRTT <= Dest->INP3ROUTE[1].SRTT) return; @@ -759,7 +780,7 @@ VOID SortRoutes(struct DEST_LIST * Dest) Call1[ConvFromAX25(Dest->INP3ROUTE[0].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, Call1)] = 0; Call2[ConvFromAX25(Dest->INP3ROUTE[1].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, Call2)] = 0; - Debugprintf("INP3 2 routes %d %s %d %s", Dest->INP3ROUTE[0].SRTT, Call1, Dest->INP3ROUTE[1].SRTT, Call2); + if (DEBUGINP3) Debugprintf("INP3 2 routes %d %s %d %s", Dest->INP3ROUTE[0].SRTT, Call1, Dest->INP3ROUTE[1].SRTT, Call2); return; } @@ -770,7 +791,7 @@ VOID SortRoutes(struct DEST_LIST * Dest) Call2[ConvFromAX25(Dest->INP3ROUTE[1].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, Call2)] = 0; Call3[ConvFromAX25(Dest->INP3ROUTE[2].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, Call3)] = 0; - Debugprintf("INP3 3 routes %d %s %d %s %d %s", Dest->INP3ROUTE[0].SRTT, Call1, Dest->INP3ROUTE[1].SRTT, Call2, Dest->INP3ROUTE[2].SRTT, Call3); + if (DEBUGINP3) Debugprintf("INP3 3 routes %d %s %d %s %d %s", Dest->INP3ROUTE[0].SRTT, Call1, Dest->INP3ROUTE[1].SRTT, Call2, Dest->INP3ROUTE[2].SRTT, Call3); // In order? @@ -791,7 +812,7 @@ VOID SortRoutes(struct DEST_LIST * Dest) Call2[ConvFromAX25(Dest->INP3ROUTE[1].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, Call2)] = 0; Call3[ConvFromAX25(Dest->INP3ROUTE[2].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, Call3)] = 0; - Debugprintf("INP3 3 routes %d %s %d %s %d %s", Dest->INP3ROUTE[0].SRTT, Call1, Dest->INP3ROUTE[1].SRTT, Call2, Dest->INP3ROUTE[2].SRTT, Call3); + if (DEBUGINP3) Debugprintf("INP3 3 routes %d %s %d %s %d %s", Dest->INP3ROUTE[0].SRTT, Call1, Dest->INP3ROUTE[1].SRTT, Call2, Dest->INP3ROUTE[2].SRTT, Call3); // if 3 is better than 2 swap them. As two is worse than one. three will then be worst @@ -807,7 +828,7 @@ VOID SortRoutes(struct DEST_LIST * Dest) Call2[ConvFromAX25(Dest->INP3ROUTE[1].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, Call2)] = 0; Call3[ConvFromAX25(Dest->INP3ROUTE[2].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, Call3)] = 0; - Debugprintf("INP3 3 routes %d %s %d %s %d %s", Dest->INP3ROUTE[0].SRTT, Call1, Dest->INP3ROUTE[1].SRTT, Call2, Dest->INP3ROUTE[2].SRTT, Call3); + if (DEBUGINP3) Debugprintf("INP3 3 routes %d %s %d %s %d %s", Dest->INP3ROUTE[0].SRTT, Call1, Dest->INP3ROUTE[1].SRTT, Call2, Dest->INP3ROUTE[2].SRTT, Call3); // 3 is now slowest. 2 could still be better than 1 @@ -824,14 +845,14 @@ VOID SortRoutes(struct DEST_LIST * Dest) Call2[ConvFromAX25(Dest->INP3ROUTE[1].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, Call2)] = 0; Call3[ConvFromAX25(Dest->INP3ROUTE[2].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, Call3)] = 0; - Debugprintf("INP3 3 routes %d %s %d %s %d %s", Dest->INP3ROUTE[0].SRTT, Call1, Dest->INP3ROUTE[1].SRTT, Call2, Dest->INP3ROUTE[2].SRTT, Call3); + if (DEBUGINP3) Debugprintf("INP3 3 routes %d %s %d %s %d %s", Dest->INP3ROUTE[0].SRTT, Call1, Dest->INP3ROUTE[1].SRTT, Call2, Dest->INP3ROUTE[2].SRTT, Call3); if (Dest->INP3ROUTE[0].SRTT <= Dest->INP3ROUTE[1].SRTT && Dest->INP3ROUTE[1].SRTT <= Dest->INP3ROUTE[2].SRTT)// In order? return; // Something went wrong - Debugprintf("INP3 Sort Failed"); + if (DEBUGINP3) Debugprintf("INP3 Sort Failed"); } @@ -871,9 +892,13 @@ VOID ProcessRTTMsg(struct ROUTE * Route, struct _L3MESSAGEBUFFER * Buff, int Len { int OtherRTT; 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 @@ -885,20 +910,40 @@ VOID ProcessRTTMsg(struct ROUTE * Route, struct _L3MESSAGEBUFFER * Buff, int Len return; } - if (Route->NEIGHBOUR_LINK->LINKPORT->ALLOWINP3) + if (Route->NEIGHBOUR_LINK->LINKPORT && (Route->NEIGHBOUR_LINK->LINKPORT->ALLOWINP3 || Route->NEIGHBOUR_LINK->LINKPORT->ENABLEINP3)) Route->INP3Node = 1; if (Route->INP3Node == 0) { - Debugprintf("Ignoring RTT Msg from %s - not using INP3", Normcall); + if (DEBUGINP3) Debugprintf("Ignoring RTT Msg from %s - not using INP3", Normcall); ReleaseBuffer(Buff); return; // We don't want to use INP3 } // Extract other end's SRTT + // Get SWVERSION to see if other end is old (Buggy) BPQ + + if (memcmp(RTTMsg->SWVERSION, "BPQ32001 ", 9) == 0) + Route->OldBPQ = 1; + else + Route->OldBPQ = 0; + sscanf(&Buff->L4DATA[6], "%d %d", &Dummy, &OtherRTT); - Route->NeighbourSRTT = OtherRTT * 10; // We store in mS + + Route->NeighbourSRTT = OtherRTT; + + // Look for $M and $H (MAXRTT MAXHOPS) + + ptr = strstr(RTTMsg->FLAGS, "$M"); + + if (ptr) + Route->RemoteMAXRTT = atoi(ptr + 2); + + ptr = strstr(RTTMsg->FLAGS, "$H"); + + if (ptr) + Route->RemoteMAXHOPS = atoi(ptr + 2); // Echo Back to sender @@ -908,20 +953,8 @@ VOID ProcessRTTMsg(struct ROUTE * Route, struct _L3MESSAGEBUFFER * Buff, int Len { // Link is just starting - Debugprintf("INP3 Processing first RTT frame from %s - link is (re)starting", Normcall); + if (DEBUGINP3) Debugprintf("INP3 Processing first RTT frame from %s - link is (re)starting", Normcall); Route->Status |= GotRTTRequest; - - // I don't think we should send RIF until we get an RTT response. - - if ((Route->Status & SentRTTRequest) == 0) // Not sent one yet so send it - SendRTTMsg(Route); - - // No, it's the other end that must have an rrt response and we've just sent it - - Route->Status |= SentOurRIF; - SendOurRIF(Route); - SendRIPToNeighbour(Route); - } } @@ -931,6 +964,8 @@ VOID SendRTTMsg(struct ROUTE * Route) struct _L3MESSAGEBUFFER * Msg; char Stamp[50]; char Normcall[10]; + unsigned char temp[256]; + uint64_t sendTime; Normcall[ConvFromAX25(Route->NEIGHBOUR_CALL, Normcall)] = 0; @@ -950,13 +985,25 @@ VOID SendRTTMsg(struct ROUTE * Route) Msg->L4TXNO = 0; Msg->L4FLAGS = L4INFO; + // The timestamp can possibly exceed 10 digits. INP3 only works on differece between send and received, so base can be reset safely. - sprintf(Stamp, "%10llu %10d %10d %10d ", (GetTickCount() - timeLoadedMS), Route->SRTT/10, Route->RTT/10, 0); + sendTime = ((uint64_t)GetTickCount() - INP3timeLoadedMS) / 10; // 10mS units + + if (sendTime > 9999999999) + sendTime = INP3timeLoadedMS = 0; + + sprintf(Stamp, "%10llu %10d %10d %10d ", sendTime, Route->SRTT, Route->RTT, 0); + memcpy(RTTMsg.TXTIME, Stamp, 44); + // We now allow MAXRTT and MAXHOPS to be reconfigured so should update header each time + + sprintf(temp, "$M%d $N $H%d ", MAXRTT, MaxHops); // trailing spaces extend to ensure padding if the length of characters for MAXRTT changes. + memcpy(RTTMsg.FLAGS, temp, 20); // But still limit the actual characters copied. + memcpy(Msg->L4DATA, &RTTMsg, 236); - Msg->LENGTH = 256 + 1 + 7; + Msg->LENGTH = 256 + 1 + MSGHDDRLEN; Route->Timeout = RTTTimeout; @@ -967,7 +1014,7 @@ VOID SendRTTMsg(struct ROUTE * Route) Route->Status |= SentRTTRequest; - Debugprintf("INP3 Sending first RTT Msg to %s", Normcall); + if (DEBUGINP3) Debugprintf("INP3 Sending first RTT Msg to %s", Normcall); } @@ -1031,12 +1078,13 @@ int BuildRIF(UCHAR * RIF, UCHAR * Call, UCHAR * Alias, int Hops, int RTT) RIF[12+AliasLen] = 0; RIFLen = 13 + AliasLen; - Debugprintf("INP3 sending RIF Entry %s:%s %d %d", AliasCopy, Normcall, Hops, RTT); + if (DEBUGINP3) Debugprintf("INP3 sending RIF Entry %s:%s %d %d", AliasCopy, Normcall, Hops, RTT); return RIFLen; } + RIF[10] = 0; - Debugprintf("INP3 sending RIF Entry %s %d %d", Normcall, Hops, RTT); + if (DEBUGINP3) Debugprintf("INP3 sending RIF Entry %s %d %d", Normcall, Hops, RTT); return (11); } @@ -1057,14 +1105,18 @@ VOID SendOurRIF(struct ROUTE * Route) Normcall[ConvFromAX25(Route->NEIGHBOUR_LINK->LINKCALL, Normcall)] = 0; - Debugprintf("INP3 Sending Initial RIF to %s ", Normcall); + if (DEBUGINP3) Debugprintf("INP3 Sending Initial RIF to %s ", Normcall); Msg->L3SRCE[0] = 0xff; // send a RIF for our Node and all our APPLCalls - RIFLen = BuildRIF(&Msg->L3SRCE[totLen], MYCALL, MYALIASTEXT, 1, 0); + if (Route->OldBPQ) + RIFLen = BuildRIF(&Msg->L3SRCE[totLen], MYCALL, MYALIASTEXT, 1, Route->RTTIncrement * 10); + else + RIFLen = BuildRIF(&Msg->L3SRCE[totLen], MYCALL, MYALIASTEXT, 1, Route->RTTIncrement); + totLen += RIFLen; for (App = 0; App < NumberofAppls; App++) @@ -1073,7 +1125,11 @@ VOID SendOurRIF(struct ROUTE * Route) if (APPL->APPLQUAL > 0) { - RIFLen = BuildRIF(&Msg->L3SRCE[totLen], APPL->APPLCALL, APPL->APPLALIAS_TEXT, 1, 0); + if (Route->OldBPQ) + RIFLen = BuildRIF(&Msg->L3SRCE[totLen], APPL->APPLCALL, APPL->APPLALIAS_TEXT, 1, Route->RTTIncrement * 10); + else + RIFLen = BuildRIF(&Msg->L3SRCE[totLen], APPL->APPLCALL, APPL->APPLALIAS_TEXT, 1, Route->RTTIncrement); + totLen += RIFLen; } } @@ -1126,24 +1182,30 @@ 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->LastConnectAttempt && - (REALTIMETICKS - Route->LastConnectAttempt) < INP3Delay) + { + if ((Route->NEIGHBOUR_FLAG)) // LOCKED ROUTE + INP3Delay = 300; + else + INP3Delay = 120; + } + + if (Route->LastConnectAttempt && (REALTIMETICKS - Route->LastConnectAttempt) < INP3Delay) { Route++; - continue; // No room for link + continue; // Not yet } // Try to activate link + Route->ConnectionAttempts++; + if (Route->INP3Node) { Normcall[ConvFromAX25(Route->NEIGHBOUR_CALL, Normcall)] = 0; - Debugprintf("INP3 Activating link to %s", Normcall); + if (DEBUGINP3) Debugprintf("INP3 Activating link to %s", Normcall); } L2SETUPCROSSLINKEX(Route, 2); // Only try SABM twice @@ -1207,7 +1269,7 @@ int SendRIPTimer() char Call [11] = ""; ConvFromAX25(Route->NEIGHBOUR_CALL, Call); - Debugprintf("BPQ32 INP3 Neighbour %s Lost", Call); + if (DEBUGINP3) Debugprintf("BPQ32 INP3 Neighbour %s Lost", Call); Route->Status = 0; // Down } @@ -1222,7 +1284,7 @@ int SendRIPTimer() } else { - Route->BCTimer = RTTInterval; + Route->BCTimer = RTTInterval + rand() % 4; Route->Retries = RTTRetries; SendRTTMsg(Route); } @@ -1261,7 +1323,7 @@ VOID SendRIF(struct ROUTE * Route, struct _L3MESSAGEBUFFER * Msg) Msg->LENGTH += MSGHDDRLEN + 1; // PID - Debugprintf("Sending INP3 RIF length %d to %s", Msg->LENGTH, Normcall); + if (DEBUGINP3) Debugprintf("Sending INP3 RIF length %d to %s", Msg->LENGTH, Normcall); SendNetFrame(Route, Msg); } @@ -1271,10 +1333,11 @@ VOID SendRIPToOtherNeighbours(UCHAR * axcall, UCHAR * alias, struct INP3_DEST_RO struct _L3MESSAGEBUFFER * Msg; int count, MaxRoutes = MAXNEIGHBOURS; char Normcall[10]; + int sendHops, sendTT; Normcall[ConvFromAX25(axcall, Normcall)] = 0; - Debugprintf("INP3 SendRIPToOtherNeighbours for %s", Normcall); + if (DEBUGINP3) Debugprintf("INP3 SendRIPToOtherNeighbours for %s", Normcall); for (count=0; countStatus) && (Routes != Entry->ROUT_NEIGHBOUR)) // Dont send to originator of route { - Msg = Routes->Msg; - - if (Msg == NULL) - { - Normcall[ConvFromAX25(Routes->NEIGHBOUR_CALL, Normcall)] = 0; - Debugprintf("INP3 Building RIF to send to %s", Normcall); - Msg = Routes->Msg = CreateRIFHeader(Routes); - } + sendHops = Entry->Hops + 1; + sendTT = Entry->SRTT + Entry->ROUT_NEIGHBOUR->RTTIncrement; - if (Msg) + // send, but only if within their constraints + + if ((Routes->RemoteMAXHOPS == 0 || Routes->RemoteMAXHOPS >= Entry->Hops) && + (Routes->RemoteMAXRTT == 0 || Routes->RemoteMAXRTT >= Entry->SRTT || Entry->SRTT == 60000)) { - Msg->LENGTH += BuildRIF(&Msg->L3SRCE[Msg->LENGTH], - axcall, alias, Entry->Hops + 1, Entry->SRTT + Entry->ROUT_NEIGHBOUR->SRTT/10); + Msg = Routes->Msg; - if (Msg->LENGTH > 250 - 15) -// if (Msg->LENGTH > Routes->NBOUR_PACLEN - 11) + if (Msg == NULL) { - SendRIF(Routes, Msg); - Routes->Msg = NULL; + Normcall[ConvFromAX25(Routes->NEIGHBOUR_CALL, Normcall)] = 0; + if (DEBUGINP3) Debugprintf("INP3 Building RIF to send to %s", Normcall); + Msg = Routes->Msg = CreateRIFHeader(Routes); + } + + if (Msg) + { + if (Routes->OldBPQ) + Msg->LENGTH += BuildRIF(&Msg->L3SRCE[Msg->LENGTH], + axcall, alias, sendHops, sendTT + 10); + else + Msg->LENGTH += BuildRIF(&Msg->L3SRCE[Msg->LENGTH], + axcall, alias, sendHops, sendTT); + + if (Msg->LENGTH > 250 - 15) + // if (Msg->LENGTH > Routes->NBOUR_PACLEN - 11) + { + SendRIF(Routes, Msg); + Routes->Msg = NULL; + } } } } @@ -1315,11 +1391,12 @@ VOID SendRIPToNeighbour(struct ROUTE * Route) struct DEST_LIST * Dest = DESTS; struct INP3_DEST_ROUTE_ENTRY * Entry; struct _L3MESSAGEBUFFER * Msg; + int sendHops, sendTT; char Normcall[10]; Normcall[ConvFromAX25(Route->NEIGHBOUR_LINK->LINKCALL, Normcall)] = 0; - Debugprintf("INP3 Sending Our Table to %s ", Normcall); + if (DEBUGINP3) Debugprintf("INP3 Sending Our Table to %s ", Normcall); Dest--; @@ -1331,26 +1408,35 @@ VOID SendRIPToNeighbour(struct ROUTE * Route) Entry = &Dest->INP3ROUTE[0]; + if (Entry->ROUT_NEIGHBOUR && Entry->Hops && Route != Entry->ROUT_NEIGHBOUR) { - // Best Route not via this neighbour - send - - Msg = Route->Msg; - - if (Msg == NULL) - Msg = Route->Msg = CreateRIFHeader(Route); - - if (Msg == NULL) - return; - - Msg->LENGTH += BuildRIF(&Msg->L3SRCE[Msg->LENGTH], - Dest->DEST_CALL, Dest->DEST_ALIAS, - Entry->Hops + 1, Entry->SRTT + Entry->ROUT_NEIGHBOUR->SRTT/10); + // Best Route not via this neighbour - send, but only if within their constraints - if (Msg->LENGTH > 250 - 15) + sendHops = Entry->Hops + 1; + sendTT = Entry->SRTT + Entry->ROUT_NEIGHBOUR->RTTIncrement; + + if ((Route->RemoteMAXHOPS == 0 || Route->RemoteMAXHOPS >= Entry->Hops) && + (Route->RemoteMAXRTT == 0 || Route->RemoteMAXRTT >= Entry->SRTT || Entry->SRTT == 60000)) { - SendRIF(Route, Msg); - Route->Msg = NULL; + Msg = Route->Msg; + + if (Msg == NULL) + Msg = Route->Msg = CreateRIFHeader(Route); + + if (Msg == NULL) + return; + + if (Route->OldBPQ) + Msg->LENGTH += BuildRIF(&Msg->L3SRCE[Msg->LENGTH], Dest->DEST_CALL, Dest->DEST_ALIAS, sendHops, sendTT * 10); // old bpq bug - send mS not 10 mS units + else + Msg->LENGTH += BuildRIF(&Msg->L3SRCE[Msg->LENGTH], Dest->DEST_CALL, Dest->DEST_ALIAS, sendHops, sendTT); + + if (Msg->LENGTH > 250 - 15) + { + SendRIF(Route, Msg); + Route->Msg = NULL; + } } } } @@ -1368,6 +1454,15 @@ VOID FlushRIFs() for (count=0; countStatus & GotRTTRequest) && (Routes->Status & GotRTTResponse) && ((Routes->Status & SentOurRIF) == 0)) + { + Routes->Status |= SentOurRIF; + SendOurRIF(Routes); + SendRIPToNeighbour(Routes); + } + if (Routes->Msg) { char Normcall[10]; @@ -1375,7 +1470,7 @@ VOID FlushRIFs() Normcall[ConvFromAX25(Routes->NEIGHBOUR_CALL, Normcall)] = 0; SendRIF(Routes, Routes->Msg); Routes->Msg = NULL; - Debugprintf("INP3 Flushing RIF to %s", Normcall); + if (DEBUGINP3) Debugprintf("INP3 Flushing RIF to %s", Normcall); } Routes+=1; } @@ -1426,7 +1521,7 @@ VOID SendNegativeInfo() { char call[11]=""; ConvFromAX25(Dest->DEST_CALL, call); - Debugprintf("INP3 Deleting Node %s", call); + if (DEBUGINP3) Debugprintf("INP3 Deleting Node %s", call); REMOVENODE(Dest); // Clear buffers, Remove from Sorted Nodes chain, and zap entry } else @@ -1544,7 +1639,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; @@ -1585,7 +1680,9 @@ UCHAR * DisplayINP3RIF(UCHAR * ptr1, UCHAR * ptr2, unsigned int msglen) msglen -= 10; - while (*ptr1 && msglen > 0) + // Process optional fields + + while (*ptr1 && msglen > 0) // Have an option { len = *ptr1; opcode = *(ptr1+1); @@ -1599,18 +1696,20 @@ UCHAR * DisplayINP3RIF(UCHAR * ptr1, UCHAR * ptr2, unsigned int msglen) { memcpy(&alias[6 - (len - 2)], ptr1+2, len-2); // Right Justiify } - else - if (opcode == 1 && len < 8) - { - memcpy(IP, ptr1+2, len-2); - } - ptr2+=sprintf(ptr2, " %s:%s %d %4.2d\r", alias, call, hops, rtt); + else if (opcode == 1 && len < 8) + { + memcpy(IP, ptr1+2, len-2); + } - ptr1++; - msglen--; // EOP + ptr1 += len; + msglen -= len; } - return ptr2; + ptr2+=sprintf(ptr2, " %s:%s %d %4.2d\r", alias, call, hops, rtt); + + ptr1++; + msglen--; // Over EOP + } return ptr2; } diff --git a/BPQMail.aps b/BPQMail.aps index 96bcae620fc277c538227683db087a8bc5509cf6..b3373cdbbb32e6acabbb475ee5df34f24c71b602 100644 GIT binary patch delta 1254 zcma)6U1$?Q5T3b9FG^E8qoRZ)tqLL{D5xM7p%0~q=j=sLe9FS?e&4sVGq#Q7;M|D0EoG%6Z9>Nx3GQmLaGlH%Nj~o@GSK7WDgI0c zkX#s?VhC=t~q^ux#+kB2*sTooZ5Rs)OQYWd8P=K(NJF3Ld~E{2liE(UJ&YEdrGD z+5r1tGq0BQT*_d8+r=+q4_P=l+%ECqRDWTP{Gmrg`gBN4MEt0X{)oI-;=k|uKVUA5 z3`o(#SiL;VLGQC!RsmbDox36f zmBrAjU1WE|Dc+9E5%CJk+zFMQndo{R)=e18$JOEGKRM>=mdJw|} z%5;&q_bH$S3jsz-XeNfGO0iD9I0ltx2JMPtsan4Q=y)7U)CmRy5{xwiJ&fZj)i?n3 zk%7|RLOUwaM@9#yZEho9HIuL;@fcMZOcIi;?x2}fOp;7g!vvxZEK#Pq=t&K$X{ny; z1$raZ&=L9-V%2N18b1nDWa2V)>@3hm6D!qpA5gD}D^>4#pz9_sbZP|v;eNYro0gur zB+KMrJIc4`3VGf9Fu9T9H}_s4^B@K&*~y5${sQ>@~ delta 15611 zcmaJ|3zQV)m9Ao7Kprvz&J4q2W)Kt=$vhcG*JyQj^-N`|yPB?=8HN}O5{V%}Fo>(0 zU7cjtlRe2Mik5piW)l@Ro46V^2}To9!3Tmb1Rty@A}G3UvL+zG0cIX)f+C`xM9t@i;a0p7Pl?#=vusFX|(n~8>2VgnQIzb%>R12b^b!rFy=!@ zzcFm2@H~3-Gk_RITipp0=t=)Y=fATyn)^;8ofwZ@EFki|KAuQ|kvDkhqNW6BmwHZz( z6At=zalM^!0yO0Kg(`}6rpS85VXK&N@_iubZtE5(@mZOSoe5Lkav(a;CdteBeJX9( zcGF(Y20)c56un#_@L`(0|2uPGx6#?wrcA^!T!0h;b&6h&svbS~QB$<+fkE>DwVid`z%HWUZezGGSjbp`O~27tyL6_Q^HYPa zn{oS$(xGu?gZ%T!IJ17VEA~gu&JP+!mqE`E_SIjVM-T?io#mh zSFc_DrH$D&Ygbz_jc6 zwy{)RIH-E*x0PKUUQ7;k9Y3HbZ-*a5W=P#>2LMhILZVCeTlqeC8BmagR>2SR@P6oz zmfgw;u}F;H1$bpWb1PlwrIWJqKkf{6Y^m$R1p zqlja`mn7kXLAnAGksvMF=^=pCTa&pZ*GpS&1z4s{0WknLtea>~R8^SJrbbhKzXeKo zxjW?FlC_(4G%5f^kPFRdD}7?FS>SkR!oik6Y9Tlo5m>o4E9 zn&c^Xf<&z|#0_gCY8y0~*fStkjF1OjfFK7{<5B2I*<5;9vxdL(;0m*cxA>?-6O1bu+Ll{jtf3AtaRD;>=mSrygf{8aaxJ4 zyQy9#3T-;BlR#5;9PvUY&K)%NNI+Ho$=I$P*ht)VdL&I*y{%pSHMoFJ1OLZ?z*vO42)KEmU#S@A^hYLfFrBLx6 z(K!JtsgukYqdvOohYep<_j1!g(aL6>G;!(}mbSqSFB4cjrj1i=nD;P9T!bpBg$e=j zQSCt>^=EzbhaWbI)mbXnFOWa^HC*3;L2*awu$u6;5CTS2Z8#RfQ=_Rr zf(?^oG(Q#!p6>*xDM^fWj_SNz=u_pE%_iVe0Z)hh$Y3-$yR^S2^8zWL@{B+dG-=nt z^azM{UWhOk(HJD4#+Fs!dJix)2@}#Zg35+S0TxnZ+rfhRr%U6aOiYs-hykvF>00pD ziobcRFWDiEg;5EHE)9l8QXS*ZDr##SOqka4p-R;Fm{=yPz^hv#gU3ud)R`$|yDmjq z7Xx#o9FscSJN1o-hpUMYFvBR?pR?0}k3ye7I+~d*wijU0<{wZ00{UqhjKK`H=2Dj& z)}@YYF;XLlT-B?)9H8j6yZ&PD@{N~Xz7gbvz!+juZV+os5gVB|&u9XU0-ekPorqq2 zH8DE#=B81g*YS&^67xYj|dnRDYD#Zb3)OE=l zJsL@Z(}k@hv8C#~ChiR-g`$(O2T>BD4sUN;swR+W0P!r-KnxZxoqdU1Z8M#v^?Rdk zMi~?#3^Xxdrvmh9tXWJiiVYW1gweq*nBhV&QlK=vRIOG9)7-aIZ50DGXD;nAWVR7F zuYfRWi9v03A~%b;qGd0@Y9<2bX#GbUEn=o#H529Ybf`NWU?DgLUCJkeYwY)`&035w z`s&@Y&jCSP*`^WN#W3YslvYuUVSFBg8}4_ouL2w|&~A9S;q2o``ii!Vgn~?eJbQ{) z$H*Ooik7|H#Ot?pFUvaadoMR$@G0UfOx)=G@zPwUuRrK33ckFW=W)s%$ymh!EJneN ziV%Wt*guEcYuP`WpXcqDb>zzZ&GU|HmzdKd7WD*m8L7K@e*?2^-QP4jK~5_T336Sw zM(^)GnQH#ns;QzkOl3pIF&3dIfuOpF!3zlSXLr1Io?svpE574(Ev4cX4uOp0$N3Vg zZ4Ciho2SE3TKV&81Qo3Bt3ZMvine;N02K(*w04=I$?X8k%IOamv>+7R! z!48TC<)BDnO_M;{SnON1arG6e{wB1eLz^d?M)dCH#<|J^G_61Kt1ekhn{qnfCPmG+ zp@xkcUtONV`VqaD`LA>a1*Cp)6RwKkOB0Ya?!6sFwx(Os!d4s3C&e z2T%z&aO(8M+-iK`j^{NnD7=b+c86l82m@jS6$y6H%Wz^CO^0ZfsdX~YuH?$p z3K#KEnu&ET6=I&oNpQJ%AQMs5mZ+Bi$4C8Fy^-W?|l!M9WxP|hl&ip!BW!KelmEUyu9%vvCf+Eg%nK)@XF zLTPez^BtNaD;wg0m7)`$py;_q+m)TP8;AN7r+?U)aYt}yGAv*{b-{9VMT*t{OsnT@ z1f+v50cy=kz^s#Z{C)xJ9&`@pHnjJK&JMcR8AIh2PxiF+nh9yM5XAz))h(3skxb)_ zPQs{LjWA+L*7A21InJ|&4OK1yCgi^vGB?+l6q5UsN<`ZEmT=}dKXbt3(qm_5g zlx>ff`wC}~{;e=4p$j7Ee8dWc-j#;?n$)da?)Y;aHd{<_r zk=K`ZvLw3~AxpB|mzsJL1pR)&b%GQYIv_!eCQw6FC=R{omX~HGxv}4y9>~+;iMXrO z5|r%^GfLKz@4r;vlW2fRhJ}}{8865f(KU>9BZ=h>MW5X#zFfXf)`(Z`leOVZ`g~xY ztQq(3oArfq8&2p4usolEcD8q5XSIw<9MJNr8pr${-3i+z@O1jbXtChsuQY$LEG88O z#X+0r(9Vud>^cBL37;l+uHfTwB~t@Rc&hs2K_x)lB^GiWRL#+$J7$qy+wz6wiUG^0QV?-HI%g=Q-5-f%>acIJl)hFd{g=@N!l1{1>!Ni3EVR9i~ zZXrQ56G#`4ed7g}<_PHy;HT2I9TCU9VHrTs_+|w1xM7sG*P1P-5uNr&?UBaDA0KEF zO0z_BRCCvS+>D4$ziZZF@M8CpdQr5o$^jL+LHngXZZ#mquqopsjpk_GT}_fAnxpUD zHCL=EO*uK>AQCD|WMNkug6k z0Jxe)rh_bv;eM+~xgMv22rD8{BgNB!Pgy^d)0Va?ZTL>3_FSB9Vlz17+VQypqj_Y? z(D6e`16Vv%Q}7XJbY#mZoE0bDD4gJ`^n z*dRWPlH+i$-JZZjhkq@z(Z`=A$F;kJw#r`8hHG~Vjx81~yHDg?a^I)u&nF@`;v6(Jy5i_2Fkf&Y(Kxx2W+~aAn#$PAg*tAM;p7W!Eipsv zBt{JSv|Y*YI29ltMl&8bNrya92|jj^W?as0f{9(jSGx)pZdi~&oMDM(H0F_7VsNZ5 zmi0MYz~l*?=&|w_dR(ePN1~rRP^T6p0DDNPIS`lcJcVT()aG)KvE2FS{Rf)QuZUy` zwEv8v(ZP-$6ULn;FKzyoD3# zm6isqyhT0hK|wF_1(}Vo)!JH@2ubu$%@Phg0A9_j#&{IO?gPt)fo>peZEQpH6de3 z$k`wjITUe8bYk6rgTi!q!pw@5qFWvkhirYQiBeQ7C|&X{x4K5h(Oh+`jl>c6UsIg(@g;4OeK`Rxxf6B?&HgP|IMK{P4|( zB@l0USORU^!?T+b8ujC-kI7LK0v!G6;dwk`Hf=kNpP6m)zGhnszkhF=#PeO-W>wY! zIGE1kjw^0SP{Wd2Vx59vuYwWJ9^ED?&E4M2GS4qRXG{_a9EH)hw#%5gWxLQntnUYu z{*&!u|E5QzYiB<)E7>(1NKn4c(m^71ZT%zll`|!u_UTq|VFUtcZ}TG}?;(Bee`HqW z%nA`86%a38MK1d;s(-YVX2rO}lw%V#JSjv&kBZr@c$9NXOq+3#Iyj+;z^Y(L;SRP{ zNaAtSNFCYtXe-<8&yR{-W5?NR2^VVHLzg^$o+$C*Hc=EK<5{hSWOAI%n z1CO?zbRNsLFXj3q8hTRN`i4Glep33g?a7u?kC%Z^bFdp{aq?)_NE`Q*sI^d^15eGY zj0kmYpPjdhxG+YRvm}Xp`zdMZXHQ8lc0MKA|F=F*dRjE=ep)Q{`KN{MZ}s^vPfK7w zpwIpK{P5{HH1owi<;b$VtTfG~YK+4AtRH)BTs&mkQ!;M6XGH9}XQa7npAj|h(dQn8 zzo*Z-X9eH>tT=w;*~Gqt&$DCT&;XUV=|C}8)(&@6^4NgN*a>u1uEsq@CxMe>z4uwM z_Xp3O!C}$5TUvH@pU&@>?-u+Ib_;%o;@{mZAvfc>QBMvF-S;YLKdxY<&dxY=#J!ca9hQ0GnDfbY^zRTPY=k6i)f77%%neFJ6 zL~8F9e}8rFLKgSWd)xTAYwzjF@X1(Sn8AhL6bcb$*YKJCylB+`DT#TvhS zrKO?0bN|jfAPp7{i21HKAPxNBfGDu_fGF_l0cr4K zeV_B1@TK&5@oR$r&TC?bdtPfuPHZWhqi{dlWdb_%T74ze`S^~=#p(<B=gXmRY-*|9Gl9nzw>0q#ESLzQNcSI2o(Gv$n z;dc(o2pj*pbbR6K((!@UXD6pf@mQfiONgv3d#us7UvH%fI98NKRahpGj_!E9r8PmK z>Qt!2BejP#s1J!%mmLzTe_fx~ACej5u0x{q`-i4a)jg7|Ejysm`-hqrlv^r<+7i{n z{3QsfjeAJc_3pzmbVd$KaDMBs%u6>PmR27=EG9U7ShT5qL+HdEN`K zza*oE2HNu_*91E)^Ya1uKncYwzMQj6~cYVc9lSbTgn4yUtCIBc7Of5#ZJ z@IL$cfBL$4(U#5TRVM9^w$z+TkN%qPj-ziP|32C~wjugM%_0KM9@{~W!q^RS7-#rK z&IpWxf$NyYWyZz$qyOya^|3uf*f{R9^jJRbj4|WJM%RqHaFVd4jrGR5sCC?#TN-OW zxa#_kezIlqHTRx4p#{80kA5;*I)A!3BRW5tP=-W{qS+G`DLT3|T3C769(~i?SbBD% z*+5@}8l`t8nv15)^YMus-uTM!}!oIT|M2LJ4&B^9=iPh|MZi-_FQyD zk|zGz^MncL6#qwG;jR2elIHlY@Cu-8+f5xChrh28U+J_-=9JotpzqIjm#&^0Q?X2+O~FO~9>&9lcW+!rlAp{aJviH33O zzS13pdihA{AfEF!{Vr~27qw#~KV{v7k6J(cAo|^Di%Tn~m}AG>{&947TT|(q_+2x9 zq8Xie?#$Ay^l~p=w&GrE?~k=Z>#MyuK(e zUD5A1olvT)LkB(@GNbT2GfQpsa^niK)KdrTH(g+szE)?RUUTUe%uXXd+n(ZOIoHZW7Y;>(;inAtDNUU5*s%rew sfHAI7$kC%u;tk3gm2Zm)f3M;Z(k(3FNG#&LY3BTz3Ha3c_tDJ%1M!<0YybcN diff --git a/BPQNRR.c b/BPQNRR.c index 7a54777..2360aa9 100644 --- a/BPQNRR.c +++ b/BPQNRR.c @@ -45,6 +45,8 @@ extern VOID Q_ADD(); VOID __cdecl Debugprintf(const char * format, ...); TRANSPORTENTRY * NRRSession; +int NRRID = 1; // Id to correlate requests and responses + /* datagrams (and other things) to be transported in Netrom L3 frames. @@ -75,7 +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; @@ -84,7 +88,18 @@ VOID NRRecordRoute(UCHAR * Buff, int Len) *ptr1++ = 0xf0; // PID - ptr1 += sprintf(ptr1, "NRR Response:"); + + 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); @@ -97,7 +112,7 @@ VOID NRRecordRoute(UCHAR * Buff, int Len) if ((Buff[7] & 0x80) == 0x80) // Check turnround bit *ptr1++ = '*'; - Buff+=8; + Buff += 8; Len -= 8; } @@ -111,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); @@ -183,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 a7a6627..7215b3b 100644 --- a/Bpq32.c +++ b/Bpq32.c @@ -1180,7 +1180,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses // Fix processing of the Winlink API /account/exists response (82) // Fix sending CTEXT to L4 connects to Node when FULL_CTEXT is not set -// Version 6.0.25.? +// Version 6.0.25.1 Sept 2025 // Fix 64 bit compatibility problems in SCSTracker and UZ7HO drivers // Add Chat PACLEN config (5) @@ -1284,6 +1284,22 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses // Fix Webmail autorefresh extra threads problem (websock connection lost handling) (82) // Fix overwriting application alias (83) + +// Version 6.0.26.? + +// Fix for compiling with gcc15 (2) +// Fix possble stuck L2 session caused by window being set to zero (3) +// 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 #include "Versions.h" @@ -1377,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); @@ -1386,6 +1404,9 @@ VOID ADIFWriteFreqList(); void SaveAIS(); void initAIS(); void initADSB(); +int CloseAllSessions(); +int CloseAllLinks(); +void NETROMTCPResolve(); extern BOOL ADIFLogEnabled; @@ -1393,6 +1414,8 @@ int CloseOnError = 0; char UIClassName[]="UIMAINWINDOW"; // the main window class name +char ClosingClassName[]="CLOSING"; // the main window class name + HWND UIhWnd; extern char AUTOSAVE; @@ -1444,7 +1467,8 @@ extern char MYCALL[]; // 7 chars, ax.25 format extern HWND hIPResWnd; extern BOOL IPMinimized; -extern int NODESINPROGRESS; +extern int NODESINPROGRESS; +extern int NODESToOnePort; extern VOID * CURRENTNODE; @@ -1514,7 +1538,7 @@ extern char ReportDest[7]; extern UCHAR ConfigDirectory[260]; -extern uint64_t timeLoadedMS; +extern uint64_t INP3timeLoadedMS; VOID __cdecl Debugprintf(const char * format, ...); VOID __cdecl Consoleprintf(const char * format, ...); @@ -1632,6 +1656,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; @@ -1687,6 +1713,8 @@ BOOL ReconfigFlag = FALSE; BOOL RigReconfigFlag = FALSE; BOOL APRSReconfigFlag = FALSE; BOOL CloseAllNeeded = FALSE; +int CloseAllTimer = 0; + BOOL NeedWebMailRefresh = FALSE; int AttachedPIDList[100] = {0}; @@ -2191,6 +2219,8 @@ VOID TimerProcX() Start(); + NETROMTCPResolve(); + INITIALISEPORTS(); // Restart Ports SetApplPorts(); @@ -2368,6 +2398,52 @@ VOID TimerProcX() CheckGuardZone(); + if (CloseAllTimer == 50) // First entry + { + if (CloseAllSessions() == 0) + { + if (CloseAllLinks() == 0) // No sessions closed so close links now + CloseAllTimer = 1; // 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; } @@ -2403,7 +2479,7 @@ FirstInit() EnumProcessesPtr = (FARPROCX)GetProcAddress(ExtDriver,"EnumProcesses"); } - timeLoadedMS = GetTickCount(); + INP3timeLoadedMS = GetTickCount(); srand(time(NULL)); @@ -2561,6 +2637,7 @@ Check_Timer() WSAStartup(MAKEWORD(2, 0), &WsaData); + // Load Psapi.dll if possible ExtDriver = LoadLibrary("Psapi.dll"); @@ -2575,6 +2652,8 @@ Check_Timer() Start(); + NETROMTCPResolve(); + INITIALISEPORTS(); OpenReportingSockets(); @@ -2898,6 +2977,8 @@ BOOL APIENTRY DllMain(HANDLE hInst, DWORD ul_reason_being_called, LPVOID lpReser } else { + NETROMTCPResolve(); + SetApplPorts(); GetUIConfig(); @@ -5894,13 +5975,106 @@ DllExport VOID APIENTRY CreateNewTrayIcon() trayMenu = NULL; } +void hookNodeClosing(char * Reason); + +BOOL CALLBACK ClosaAllProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + int wmId, wmEvent; + + switch (message) + { + case WM_INITDIALOG: + return (INT_PTR)TRUE; + + case WM_CTLCOLORDLG: + return (LONG)bgBrush; + + case WM_CTLCOLORSTATIC: + { + HDC hdcStatic = (HDC)wParam; + SetTextColor(hdcStatic, RGB(0, 0, 0)); + SetBkMode(hdcStatic, TRANSPARENT); + + return (LONG)bgBrush; + } + + case WM_COMMAND: + + return 0; + + case WM_SYSCOMMAND: + + wmId = LOWORD(wParam); // Remember, these are... + wmEvent = HIWORD(wParam); // ...different for Win32! + + switch (wmId) + { + case SC_RESTORE: + + return (DefWindowProc(hWnd, message, wParam, lParam)); + + case SC_MINIMIZE: + + if (MinimizetoTray) + return ShowWindow(hWnd, SW_HIDE); + else + return (DefWindowProc(hWnd, message, wParam, lParam)); + + break; + + default: + return (DefWindowProc(hWnd, message, wParam, lParam)); + } + + case WM_CLOSE: + return(DestroyWindow(hWnd)); + + default: + return (DefWindowProc(hWnd, message, wParam, lParam)); + + } + + return (0); +} + + +HWND hwndClosing = NULL; // Window handle of dialog box + + DllExport VOID APIENTRY CloseAllPrograms() { -// HANDLE hProc; + WNDCLASS wc; + CLOSING = TRUE; - // Close all attached BPQ32 programs + // Tell BG to shut when all links are gone or after 5 secs - Closing = TRUE; + CloseAllTimer = 50; + + + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = ClosaAllProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = DLGWINDOWEXTRA; + wc.hInstance = hInstance; + wc.hIcon = LoadIcon( hInstance, MAKEINTRESOURCE(BPQICON) ); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = bgBrush; + + wc.lpszMenuName = NULL; + wc.lpszClassName = ClosingClassName; + + RegisterClass(&wc); + + hwndClosing = CreateDialog(hInstance, ClosingClassName, NULL, (DLGPROC)ClosaAllProc); + ShowWindow(hwndClosing, SW_SHOW); +} + +VOID RealCloseAllPrograms() +{ + hookNodeClosing("Shutdown"); + Sleep(500); + + Closing = 1; ShowWindow(FrameWnd, SW_RESTORE); diff --git a/Cmd.c b/Cmd.c index 70a061e..d532a1e 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 ) @@ -73,7 +69,8 @@ int seeifInterlockneeded(struct PORTCONTROL * PORT); 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); @@ -86,6 +83,7 @@ UCHAR SAVEDAPPLFLAGS = 0; UCHAR ALIASINVOKED = 0; +extern int MONTOFILEFLAG; VOID * CMDPTR = 0; @@ -132,6 +130,8 @@ int NOBUFFCOUNT = 0; int BUFFERWAITS = 0; int MAXDESTS = 0; int NUMBEROFNODES = 0; +int L2CONNECTSOUT = 0; +int L2CONNECTSIN = 0; int L4CONNECTSOUT = 0; int L4CONNECTSIN = 0; int L4FRAMESTX = 0; @@ -155,13 +155,15 @@ char * ALIASPTR = &CMDALIAS[0][0]; extern int RigReconfigFlag; +extern int DEBUGINP3; +extern int PREFERINP3ROUTES; struct CMDX COMMANDS[]; int CMDXLEN = sizeof (struct CMDX); -VOID SENDNODESMSG(); +VOID SENDNODESMSG(int Portnum); VOID KISSCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct CMDX * CMD); VOID STOPCMS(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct CMDX * CMD); VOID STARTCMS(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct CMDX * CMD); @@ -187,6 +189,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, ...) { @@ -249,10 +299,81 @@ char * __cdecl Cmdprintf(TRANSPORTENTRY * Session, char * Bufferptr, const char return Bufferptr + MsgLen; } +VOID POLLNODES(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct CMDX * CMD) +{ + int Portnum = atoi(CmdTail); + struct PORTCONTROL * PORT = 0; + MESSAGE * Buffer; + UCHAR * ptr1; + if (Portnum) + PORT = GetPortTableEntryFromPortNum(Portnum); + + if (Portnum == 0 || PORT == 0) + { + Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r"); + SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); + return; + } + + if (PORT->PORTQUALITY == 0 || PORT->INP3ONLY) + { + Bufferptr = Cmdprintf(Session, Bufferptr, "Quality = 0 or INP3 Port\r"); + SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); + return; + } + Buffer = GetBuff(); + + if (Buffer == 0) + return; + + Buffer->PORT = Portnum; + + memcpy(Buffer->ORIGIN, NETROMCALL, 7); + memcpy(Buffer->DEST, NODECALL, 7); + + Buffer->ORIGIN[6] |= 0x61; // SET CMD END AND RESERVED BITS + + Buffer->CTL = UI; + Buffer->PID = 0xCF; // Netrom + + ptr1 = &Buffer->L2DATA[0]; + + *(ptr1++) = 0xfe; // Nodes Poll Flag + + memcpy(ptr1, MYALIASTEXT, 6); + + ptr1+= 6; + + Buffer->LENGTH = (int)(ptr1 - (UCHAR *)Buffer); + + if (PORT->TNC && PORT->TNC->Hardware == H_VARA) + SendVARANetromNodes(PORT->TNC, Buffer); + else + PUT_ON_PORT_Q(PORT, Buffer); + + strcpy(Bufferptr, OKMSG); + Bufferptr += (int)strlen(OKMSG); + + SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); +} VOID SENDNODES(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct CMDX * CMD) { - SENDNODESMSG(); + int Portnum = atoi(CmdTail); + struct PORTCONTROL * PORT; + + if (Portnum) + { + PORT = GetPortTableEntryFromPortNum(Portnum); + if (PORT == 0) + { + Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r"); + SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); + return; + } + } + + SENDNODESMSG(Portnum); strcpy(Bufferptr, OKMSG); Bufferptr += (int)strlen(OKMSG); @@ -717,6 +838,108 @@ 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; + char TailCopy[256]; + + strcpy(TailCopy, CmdTail); + + + ptr = strtok_s(TailCopy, " ", &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; @@ -725,6 +948,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 @@ -743,12 +967,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 @@ -830,6 +1085,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)); } @@ -1300,6 +1558,17 @@ VOID CMDL00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct C else Bufferptr = Cmdprintf(Session, Bufferptr, " S=%d P=%d T=%d V=%d Q=%d\r", LINK->L2STATE, LINK->LINKPORT->PORTNUMBER, LINK->LINKTYPE, 2 - LINK->VER1FLAG, Count); + + if (Count > 16 || LINK->LINKWINDOW == 0) + { + // Dump Link State + + int secs = time(NULL) - LINK->LASTFRAMESENT; + + Bufferptr = Cmdprintf(Session, Bufferptr, " Debug Info: LINK->LINKNS %d LINK->LINKOWS %d SDTSLOT %d LINKWINDOW %d L2FLAGS %d\r", LINK->LINKNS, LINK->LINKOWS, LINK->SDTSLOT, LINK->LINKWINDOW, LINK->L2FLAGS); + Bufferptr = Cmdprintf(Session, Bufferptr, " Debug Info: Slots %x %x %x %x %x %x %x %x\r", LINK->FRAMES[0], LINK->FRAMES[1], LINK->FRAMES[2], LINK->FRAMES[3], + LINK->FRAMES[4], LINK->FRAMES[5], LINK->FRAMES[6], LINK->FRAMES[7]); + } } LINK++; } @@ -1622,8 +1891,8 @@ char * DisplayRoute(TRANSPORTENTRY * Session, char * Bufferptr, struct ROUTE * if (Routes->INP3Node) // INP3 Enabled? { - double srtt = Routes->SRTT/1000.0; - double nsrtt = Routes->NeighbourSRTT/1000.0; + double srtt = Routes->SRTT/100.0; + double nsrtt = Routes->NeighbourSRTT/100.0; Bufferptr = Cmdprintf(Session, Bufferptr, " %4.2fs %4.2fs", srtt, nsrtt); } @@ -2144,7 +2413,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; @@ -2153,6 +2422,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; @@ -2160,15 +2431,41 @@ 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; } +BOOL CheckLink(UCHAR * LinkCall, UCHAR * OurCall, int Port) +{ + // Check if a link exists betwwn a pair of calls on a port. Return TRUE if found + + struct _LINKTABLE * LINK = LINKS; + int n = MAXLINKS; + + while (n--) + { + if (LINK->LINKCALL[0] == 0) // Spare + { + LINK++; + continue; + } + + if ((LINK->LINKPORT->PORTNUMBER == Port) && CompareCalls(LINK->LINKCALL, LinkCall) && CompareCalls(LINK->OURCALL, OurCall)) + return TRUE; + + LINK++; + } + + // ENTRY NOT FOUND + + return FALSE; +} + BOOL FindLink(UCHAR * LinkCall, UCHAR * OurCall, int Port, struct _LINKTABLE ** REQLINK) { struct _LINKTABLE * LINK = LINKS; @@ -2194,6 +2491,7 @@ BOOL FindLink(UCHAR * LinkCall, UCHAR * OurCall, int Port, struct _LINKTABLE ** LINK++; } + // ENTRY NOT FOUND - FIRSTSPARE HAS FIRST FREE ENTRY, OR ZERO IF TABLE FULL *REQLINK = FIRSTSPARE; @@ -2224,6 +2522,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 @@ -2370,6 +2671,7 @@ NoPort: // SEE IF CALL TO ANY OF OUR HOST SESSIONS - UNLESS DIGIS SPECIFIED +// if (axcalls[7] == 0 && axcalls[9]) if (axcalls[7] == 0) { // If this connect is as a result of a command alias, don't check appls or we will loop @@ -2388,6 +2690,9 @@ NoPort: // Convert to an APPL command, so any alias is actioned + memcpy(Session->APPL,APPL->APPLCMD, 12); + + // SEE IF THERE IS AN ALIAS DEFINDED FOR THIS COMMAND if (APPL->APPLHASALIAS && APPL->APPLALIASVAL[0] != 0x20) @@ -2418,9 +2723,35 @@ 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 + + if (cmdCopy[0] != ' ') { - // SEE IF CALL TO ANOTHER NODE + i = 0; + + while (cmdCopy[i] >= '0' && cmdCopy[i]<= '9') + i++; + + if (cmdCopy[i] != ' ') + goto Downlink; + else + { + 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; @@ -2431,7 +2762,7 @@ NoPort: { if (memcmp(Dest->DEST_ALIAS, TextCall, 6) == 0) { - DoNetromConnect(Session, Bufferptr, Dest, Spy); + DoNetromConnect(Session, Bufferptr, Dest, Spy, Service); return; } Dest++; @@ -2445,7 +2776,7 @@ NoPort: { if (CompareCalls(Dest->DEST_CALL, axcalls)) { - DoNetromConnect(Session, Bufferptr, Dest, Spy); + DoNetromConnect(Session, Bufferptr, Dest, Spy, Service); return; } Dest++; @@ -2939,7 +3270,7 @@ char * DoOneNode(TRANSPORTENTRY * Session, char * Bufferptr, struct DEST_LIST * if (Neighbour) { - double srtt = Route->SRTT/1000.0; + double srtt = Route->SRTT/100.0; len = ConvFromAX25(Neighbour->NEIGHBOUR_CALL, Normcall); Normcall[len] = 0; @@ -2988,7 +3319,7 @@ int DoINP3ViaEntry(struct DEST_LIST * Dest, int n, char * line, int cursor) if (Dest->INP3ROUTE[n].ROUT_NEIGHBOUR != 0) { - srtt = Dest->INP3ROUTE[n].SRTT/1000.0; + srtt = Dest->INP3ROUTE[n].SRTT/100.0; len=ConvFromAX25(Dest->INP3ROUTE[n].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, Portcall); Portcall[len]=0; @@ -3608,6 +3939,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 @@ -4258,6 +4591,7 @@ struct CMDX COMMANDS[] = "RIGRECONFIG ",8, &RIGRECONFIG, 0, "RESTART ",7, &RESTART,0, "RESTARTTNC ",10,&RESTARTTNC,0, + "POLLNODES ",8, &POLLNODES,0, "SENDNODES ",8, &SENDNODES,0, "EXTRESTART ",10, EXTPORTVAL, offsetof(EXTPORTDATA, EXTRESTART), "TXDELAY ",3, PORTVAL, offsetof(PORTCONTROLX, PORTTXDELAY), @@ -4275,6 +4609,10 @@ struct CMDX COMMANDS[] = "MAXUSERS ",4,PORTVAL, offsetof(PORTCONTROLX, USERS), "L3ONLY ",6,PORTVAL, offsetof(PORTCONTROLX, PORTL3FLAG), "BBSALIAS ",4,PORTVAL, offsetof(PORTCONTROLX, PORTBBSFLAG), + "INP3ONLY ",8,PORTVAL, offsetof(PORTCONTROLX, INP3ONLY), + "ALLOWINP3 ",9,PORTVAL, offsetof(PORTCONTROLX, ALLOWINP3), + "ENABLEINP3 ",10,PORTVAL, offsetof(PORTCONTROLX, ENABLEINP3), + "MONTOFILE ",9,SWITCHVAL,(size_t)&MONTOFILEFLAG, "VALIDCALLS ",5,VALNODES,0, "WL2KSYSOP ",5,WL2KSYSOP,0, "STOPPORT ",4,STOPPORT,0, @@ -4286,6 +4624,7 @@ struct CMDX COMMANDS[] = "KISS ",4,KISSCMD,0, "GETPORTCTEXT",9,GetPortCTEXT, 0, + #ifdef EXCLUDEBITS "EXCLUDE ",4,ListExcludedCalls,0, @@ -4310,6 +4649,11 @@ struct CMDX COMMANDS[] = "L4DELAY ",7,SWITCHVAL,(size_t)&L4DELAY, "L4WINDOW ",6,SWITCHVAL,(size_t)&L4DEFAULTWINDOW, "BTINTERVAL ",5,SWITCHVAL,(size_t)&BTINTERVAL, + "DEBUGINP3 ",8,SWITCHVAL,(size_t)&DEBUGINP3, + "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, @@ -4343,7 +4687,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, @@ -4736,6 +5080,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]; // @@ -4827,6 +5173,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 9c0032d..9e8b37a 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; @@ -69,6 +75,7 @@ void printStack(void); char * FormatMH(PMHSTRUC MH, char Format); void WriteConnectLog(char * fromCall, char * toCall, UCHAR * Mode); void SendDataToPktMap(); +void NETROMTCPResolve(); extern BOOL LogAllConnects; extern BOOL M0LTEMap; @@ -79,6 +86,7 @@ extern VOID * ENDBUFFERPOOL; extern int PoolBuilt; +extern int EnableOARCAPI; // Read/Write length field in a buffer header @@ -3313,8 +3321,12 @@ SOCKADDR_IN reportdest = {0}; SOCKET ReportSocket = 0; +SOCKET NodeAPISocket = 0 ; + SOCKADDR_IN Chatreportdest = {0}; +SOCKADDR_IN UDPreportdest = {0}; + extern char LOCATOR[]; // Locator for Reporting - may be Maidenhead or LAT:LON extern char MAPCOMMENT[]; // Locator for Reporting - may be Maidenhead or LAT:LON extern char LOC[7]; // Maidenhead Locator for Reporting @@ -3670,11 +3682,22 @@ pthread_t ResolveUpdateThreadId = 0; char NodeMapServer[80] = "update.g8bpq.net"; char ChatMapServer[80] = "chatupdate.g8bpq.net"; +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; struct hostent * HostEnt2; + struct hostent * HostEnt3; + ResolveUpdateThreadId = GetCurrentThreadId(); @@ -3702,14 +3725,29 @@ VOID ResolveUpdateThread(void * Unused) if (HostEnt2) memcpy(&Chatreportdest.sin_addr.s_addr,HostEnt2->h_addr,4); - if (HostEnt1 && HostEnt2) + Debugprintf("Resolving %s", NodeAPIServer); + + HostEnt3 = gethostbyname(NodeAPIServer); + + if (HostEnt3) { - Sleep(1000 * 60 * 30); - continue; + memcpy(&UDPreportdest.sin_addr.s_addr,HostEnt3->h_addr,4); + + if (nodeStartedSent == 0) + { + hookNodeStarted(); + nodeStartedSent = 1; + LastNodeStatus = time(NULL); + } } - Debugprintf("Resolve Failed for update.g8bpq.net or chatmap.g8bpq.net"); - Sleep(1000 * 60 * 5); + NETROMTCPResolve(); + + if (HostEnt1 && HostEnt2) + { + Sleep(1000 * 60 * 15); + continue; + } } } @@ -3741,7 +3779,7 @@ VOID OpenReportingSockets() reportdest.sin_port = htons(81); ConvToAX25("DUMMY-1", ReportDest); } - + // Set up Chat Report even if no LOCATOR reportdest.sin_family = AF_INET; // Socket must be opened in MailChat Process @@ -5194,14 +5232,14 @@ skipit: } } -void SendDataToPktMapThread(); +void SendDataToPktMapThread(void * Param); void SendDataToPktMap() { _beginthread(SendDataToPktMapThread,2048000,0); } -void SendDataToPktMapThread() +void SendDataToPktMapThread(void * Param) { char Return[256] = ""; char Request[64]; diff --git a/DRATS.c b/DRATS.c index c7b6b83..7fd85cf 100644 --- a/DRATS.c +++ b/DRATS.c @@ -568,18 +568,19 @@ void DRATSConnectionLost(struct ConnectionInfo * sockptr) int doinflate(unsigned char * source, unsigned char * dest, int Len, int destlen, int * outLen) { - int ret; - z_stream strm; + int ret; + z_stream strm; - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - strm.avail_in = 0; - strm.next_in = Z_NULL; + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; - ret = inflateInit(&strm); - if (ret != Z_OK) - return ret; + ret = inflateInit(&strm); + + if (ret != Z_OK) + return ret; strm.avail_in = Len; strm.next_in = source; diff --git a/Events.c b/Events.c index fdbb96b..d095bd9 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,11 +42,36 @@ VOID __cdecl Debugprintf(const char * format, ...); extern BOOL EventsEnabled; void MQTTReportSession(char * Msg); extern int MQTT; +extern time_t TimeLoaded; +int UDPSeq = 1; + +extern SOCKET NodeAPISocket; +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; +extern int NUMBEROFNODES, MAXDESTS, L4CONNECTSOUT, L4CONNECTSIN, L4FRAMESTX, L4FRAMESRX, L4FRAMESRETRIED, OLDFRAMES; +extern int L2CONNECTSOUT, L2CONNECTSIN; + +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); +char * byte_base64_encode(char *str, int len); + // Runs use specified routine on certain event + #ifndef WIN32 void RunEventProgram(char * Program, char * Param) @@ -117,16 +143,34 @@ DllExport void APIENTRY RunEventProgram(char * Program, char * Param) void hookL2SessionAccepted(int Port, char * remotecall, char * ourcall, struct _LINKTABLE * LINK) { - // Incoming SABM + // Incoming SABM accepted - LINK->ConnectTime = time(NULL); - LINK->bytesTXed = LINK->bytesRXed = 0; + char UDPMsg[1024]; + int udplen; + L2CONNECTSIN++; + + LINK->lastStatusSentTime = LINK->ConnectTime = time(NULL); + LINK->bytesTXed = LINK->bytesRXed = LINK->framesResent = LINK->framesRXed = LINK->framesTXed = 0; + LINK->LastStatusbytesTXed = LINK->LastStatusbytesRXed = 0; strcpy(LINK->callingCall, remotecall); strcpy(LINK->receivingCall, ourcall); strcpy(LINK->Direction, "In"); + + if (NodeAPISocket) + { + 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)); + } } + void hookL2SessionDeleted(struct _LINKTABLE * LINK) { // calculate session time and av bytes/min in and out @@ -141,7 +185,7 @@ void hookL2SessionDeleted(struct _LINKTABLE * LINK) else { char Msg[256]; - char timestamp[16]; + char timestamp[64]; time_t sessionTime = time(NULL) - LINK->ConnectTime; double avBytesSent = LINK->bytesTXed / (sessionTime / 60.0); double avBytesRXed = LINK->bytesRXed / (sessionTime / 60.0); @@ -164,28 +208,130 @@ void hookL2SessionDeleted(struct _LINKTABLE * LINK) if (MQTT) MQTTReportSession(Msg); + + 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->lastStatusSentTime = LINK->ConnectTime = time(NULL); + LINK->bytesTXed = LINK->bytesRXed = LINK->framesResent = LINK->framesRXed = LINK->framesTXed = 0; + LINK->LastStatusbytesTXed = LINK->LastStatusbytesRXed = 0; strcpy(LINK->callingCall, ourcall); strcpy(LINK->receivingCall, remotecall); strcpy(LINK->Direction, "Out"); } +void hookL2SessionConnected(struct _LINKTABLE * LINK) +{ + // UA received in reponse to SABM + + char UDPMsg[1024]; + int udplen; + + L2CONNECTSOUT++; + + if (NodeAPISocket) + { + 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; + time_t Now = time(NULL); + + 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\"," + " \"time\": %d, \"upForSecs\": %d, \"frmsQdPeak\": %d}", + NODECALLLOPPED, UDPSeq++, LINK->LINKPORT->PORTNUMBER, LINK->receivingCall, LINK->callingCall, + LINK->bytesTXed , LINK->bytesRXed, LINK->framesTXed, LINK->framesRXed, COUNT_AT_L2(LINK), LINK->framesResent, Reason, + (int)Now, (int)Now - LINK->ConnectTime, LINK->maxQueued); + 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\"," + " \"time\": %d, \"upForSecs\": %d, \"frmsQdPeak\": %d}", + NODECALLLOPPED, UDPSeq++, LINK->LINKPORT->PORTNUMBER, LINK->callingCall, LINK->receivingCall, + LINK->bytesTXed , LINK->bytesRXed, LINK->framesTXed, LINK->framesRXed, COUNT_AT_L2(LINK), LINK->framesResent, Reason, + (int)Now, (int)Now - LINK->ConnectTime, LINK->maxQueued); + + + 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; + time_t Now = time(NULL); + int bpsTx, bpsRx, interval; + + if (NodeAPISocket) + { + interval = Now - (int)LINK->lastStatusSentTime; + bpsTx = (LINK->bytesTXed - LINK->LastStatusbytesTXed) / interval; + bpsRx = (LINK->bytesRXed - LINK->LastStatusbytesRXed) / interval; + + LINK->lastStatusSentTime = Now; + LINK->LastStatusbytesTXed = LINK->bytesTXed; + LINK->LastStatusbytesRXed = LINK->bytesRXed; + + 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," + "\"upForSecs\": %d, \"frmsQdPeak\": %d, \"bpsTxMean\": %d, \"bpsRxMean\": %d, \"frmQMax\": %d, \"l2rttMs\": %d}", + NODECALLLOPPED, UDPSeq++, LINK->LINKPORT->PORTNUMBER, LINK->receivingCall, LINK->callingCall, + LINK->bytesTXed, LINK->bytesRXed, LINK->framesTXed, LINK->framesRXed, 0, LINK->framesResent, + (int)Now - LINK->ConnectTime, LINK->maxQueued, bpsTx, bpsRx, LINK->intervalMaxQueued, LINK->RTT); + 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," + "\"upForSecs\": %d, \"frmsQdPeak\": %d, \"bpsTxMean\": %d, \"bpsRxMean\": %d, \"frmQMax\": %d, \"l2rttMs\": %d}", + NODECALLLOPPED, UDPSeq++, LINK->LINKPORT->PORTNUMBER, LINK->callingCall, LINK->receivingCall, + LINK->bytesTXed, LINK->bytesRXed, LINK->framesTXed, LINK->framesRXed, 0, LINK->framesResent, + (int)Now - LINK->ConnectTime, LINK->maxQueued, bpsTx, bpsRx, LINK->intervalMaxQueued, LINK->RTT); + + LINK->intervalMaxQueued = 0; + + Debugprintf(UDPMsg); + + sendto(NodeAPISocket, UDPMsg, udplen, 0, (struct sockaddr *)&UDPreportdest, sizeof(UDPreportdest)); + } +} + + + + void hookL4SessionAttempt(struct STREAMINFO * STREAM, char * remotecall, char * ourcall) { // Outgoing Connect @@ -210,6 +356,20 @@ void hookL4SessionAccepted(struct STREAMINFO * STREAM, char * remotecall, char * strcpy(STREAM->Direction, "In"); } +/* +{ + "eventSource": "circuit", + "time": "2025-10-08T14:05:54+00:00", + "id": 23, + "direction": "incoming", + "port": "0", + "remote": "G8PZT@G8PZT:15aa", + "local": "GE8PZT:0017", + "event": "disconnect", + "@type": "event" +} +*/ + void hookL4SessionDeleted(struct TNCINFO * TNC, struct STREAMINFO * STREAM) { char Msg[256]; @@ -241,3 +401,856 @@ 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\", \"uptimeSecs\": %d," + "\"linksIn\": %d, \"linksOut\": %d, \"cctsIn\": %d, \"cctsOut\": %d, \"l3Relayed\": %d}", + NODECALLLOPPED, MYALIASLOPPED, Reason, time(NULL) - TimeLoaded, L2CONNECTSIN, L2CONNECTSOUT, L4CONNECTSIN, L4CONNECTSOUT, L3FRAMES); + +// 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," + "\"linksIn\": %d, \"linksOut\": %d, \"cctsIn\": %d, \"cctsOut\": %d, \"l3Relayed\": %d}", + NODECALLLOPPED, MYALIASLOPPED, LOC, LatFromLOC, LonFromLOC, Software, VersionString, time(NULL) - TimeLoaded, + L2CONNECTSIN, L2CONNECTSOUT, L4CONNECTSIN, L4CONNECTSOUT, L3FRAMES); + +// 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 dumpDuffPacket(char * call, char * Buffer, int Len) +{ + // log to syslog in base64 + + char * Base64; + + Base64 = byte_base64_encode(Buffer, Len); + + Debugprintf("Trace Error %s %s", call, Base64); + free(Base64); +} + +int checkCall(char * call, unsigned char * Buffer, int Len) +{ + char c; + int i; + + // Validate source and dest calls - if duff, dump packet + + for (i = 0; i < strlen(call); i++) + { + c = call[i]; + + if (isalnum(c) || c == '-' || c == '@') + continue; + + dumpDuffPacket(call, Buffer, Len); + return 0; + } + + return 1; +} + + + +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; + + // Validate source and dest calls - if duff, dump packet + + if (!checkCall(destcall,(char *) Message, Message->LENGTH)) + return; + + if (!checkCall(srcecall, (char *) Message, Message->LENGTH)) + return; + + // 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\", \"dirn\": \"%s\", \"reportFrom\": \"%s\", \"port\": \"%d\", \"srce\": \"%s\", \"dest\": \"%s\", \"ctrl\": %d," + "\"l2Type\": \"%s\", \"modulo\": 8, \"cr\": \"%s\"", + Dirn, 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 (!checkCall(destcall, Msg, iLen)) + return 0; + + if (!checkCall(srcecall, Msg, iLen)) + return 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 (!checkCall(srcUser, Msg, iLen)) + return 0; + + + if (!checkCall(srcNode, Msg, iLen)) + return 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 NAK\", \"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/HanksRT.c b/HanksRT.c index 8831faa..c828fd5 100644 --- a/HanksRT.c +++ b/HanksRT.c @@ -426,7 +426,7 @@ VOID ChatExpandAndSendMessage(ChatCIRCUIT * conn, char * Msg, int LOG) len = RemoveLF(NewMessage, (int)strlen(NewMessage)); - ChatWriteLogLine(conn, '>', NewMessage, len, LOG); + ChatWriteLogLine(conn, '>', NewMessage, len, LOG_CHAT); ChatQueueMsg(conn, NewMessage, len); } diff --git a/KernelScript1.rc b/KernelScript1.rc index 4eef3b5..b230ace 100644 --- a/KernelScript1.rc +++ b/KernelScript1.rc @@ -50,6 +50,19 @@ BEGIN LTEXT "Enable IGate",IDC_STATIC,5,2,49,10 END +CLOSING DIALOG DISCARDABLE 300, 300, 200, 50 +STYLE DS_3DLOOK | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | + WS_THICKFRAME +CAPTION "BPQ32 Close All" +CLASS "CLOSING" +FONT 8, "Fixedsys" +BEGIN + LTEXT "Closing Links - Please wait....",IDC_BACKGROUND,22,20,337,273 + +END + + + CONFIG DIALOGEX 249, 200, 160, 118 STYLE DS_MODALFRAME | DS_3DLOOK | WS_POPUP | WS_CAPTION EXSTYLE WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE diff --git a/L2Code.c b/L2Code.c index 0fd8ecd..44015e1 100644 --- a/L2Code.c +++ b/L2Code.c @@ -64,7 +64,7 @@ VOID L2SENDRESPONSE(struct _LINKTABLE * LINK, int CMD); VOID L2SENDCOMMAND(struct _LINKTABLE * LINK, int CMD); VOID ACKMSG(struct _LINKTABLE * LINK); VOID InformPartner(struct _LINKTABLE * LINK, int Reason); -UINT RR_OR_RNR(struct _LINKTABLE * LINK); +UINT RR_OR_RNR(struct _LINKTABLE * LINK, int CMD); VOID L2TIMEOUT(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT); VOID CLEAROUTLINK(struct _LINKTABLE * LINK); VOID SENDFRMR(struct _LINKTABLE * LINK); @@ -99,6 +99,7 @@ VOID L2SENDXID(struct _LINKTABLE * LINK); VOID __cdecl Debugprintf(const char * format, ...); VOID Q_IP_MSG(MESSAGE * Buffer); VOID PROCESSNODEMESSAGE(MESSAGE * Msg, struct PORTCONTROL * PORT); +VOID PROCESSNODESPOLL(struct PORTCONTROL * PORT); VOID L2LINKACTIVE(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESSAGE * Buffer, MESSAGE * ADJBUFFER, UCHAR CTL, UCHAR MSGFLAG); BOOL CompareAliases(UCHAR * c1, UCHAR * c2); VOID L2FORUS(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESSAGE * Buffer, MESSAGE * ADJBUFFER, UCHAR CTL, UCHAR MSGFLAG); @@ -120,11 +121,18 @@ int CheckKissInterlock(struct PORTCONTROL * MYPORT, int Exclusive); void hookL2SessionAccepted(int Port, char * fromCall, char * toCall, struct _LINKTABLE * LINK); void hookL2SessionDeleted(struct _LINKTABLE * LINK); void hookL2SessionAttempt(int Port, char * fromCall, char * toCall, struct _LINKTABLE * LINK); +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 @@ -139,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; @@ -445,6 +454,8 @@ TRYBBS: if ((PORT->PERMITTEDAPPLS & APPLMASK) != 0) { ALIASMSG = 0; + + strcpy(LINK->ApplName, APPL->APPLCMD); if (CompareCalls(Buffer->DEST, APPL->APPLCALL)) goto FORUS; @@ -479,9 +490,9 @@ NOWTRY_NODES: if (CompareCalls(Buffer->DEST, NODECALL)) { if (Buffer->L2DATA[0] == 0xff) // Valid NODES Broadcast - { PROCESSNODEMESSAGE(Buffer, PORT); - } + else if (Buffer->L2DATA[0] == 0xfe) // Paula's NODES Poll (request Nodes broadcast on port) + PROCESSNODESPOLL(PORT); } ReleaseBuffer(Buffer); @@ -808,7 +819,15 @@ VOID L2FORUS(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESSAGE * Buff if (CTLlessPF == XID) { - ProcessXIDCommand(LINK, PORT, Buffer, ADJBUFFER, CTL, MSGFLAG); + // We could possibly get an XID response if packet is badly delayed and we had timed out + + if ((MSGFLAG & CMDBIT)) // Command + ProcessXIDCommand(LINK, PORT, Buffer, ADJBUFFER, CTL, MSGFLAG); + else + { + Debugprintf("Unexpected XID response with no session"); + ReleaseBuffer(Buffer); // Ignore if not + } return; } @@ -929,6 +948,7 @@ VOID ProcessXIDCommand(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESS LINK->L2STATE = 1; // XID received LINK->Ver2point2 = TRUE; // Must support 2.2 if sent XID LINK->L2TIME = PORT->PORTT1; + LINK->LINKWINDOW = PORT->PORTWINDOW; // Just in case! LINK->LINKPORT = PORT; @@ -1067,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); @@ -1076,87 +1097,128 @@ VOID L2LINKACTIVE(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESSAGE * return; } - - if (LINK->L2STATE == 1) + if (CTLlessPF == XID) { - // XID State. Should be XID response if 2.2 ok or DM/FRMR if not + // XID command or response on active session. + + // if Command and state = 2 then other end missed XID Response. Process command again - if (MSGFLAG & RESP) + if ((MSGFLAG & CMDBIT)) { - if (CTLlessPF == DM || CTLlessPF == FRMR) + if (LINK->L2STATE == 2) { - // Doesn't support XID - Send SABM + // I think we can just process as normal. - LINK->L2STATE = 2; - LINK->Ver2point2 = FALSE; - LINK->L2TIMER = 1; // Use retry to send SABM + ProcessXIDCommand(LINK, PORT, Buffer, ADJBUFFER, CTL, MSGFLAG); + return; } - else if (CTLlessPF == XID) + + if (LINK->L2STATE == 1) // We've just sent XID so is probably XID Collision { - // Process response to make sure ok, Send SABM or DISC + // I think we can just process as normal. If we don't send a response the other end may not switch to 2.2 - LINK->L2STATE = 2; - LINK->Ver2point2 = TRUE;// Must support 2.2 if responded to XID - - // if Compress enabled set it - - ptr = &ADJBUFFER->PID; - - if (*ptr++ == 0x82 && *ptr++ == 0x80) - { - int Type; - int Len; - unsigned int value; - int xidlen = *(ptr++) << 8; - xidlen += *ptr++; - - // XID is set of Type, Len, Value n-tuples - - while (xidlen > 0) - { - Type = *ptr++; - Len = *ptr++; - - value = 0; - xidlen -= (Len + 2); - - while (Len--) - { - value <<=8; - value += *ptr++; - } - switch(Type) - { - case 17: - - // Compression - - if (L2Compress) - LINK->AllowCompress = 1; - - } - } - - } - - LINK->L2TIMER = 1; // Use retry to send SABM + ProcessXIDCommand(LINK, PORT, Buffer, ADJBUFFER, CTL, MSGFLAG); + return; } + // XID Command on active session. Other end may be restarting. Reset session + + InformPartner(LINK, NORMALCLOSE); // SEND DISC TO OTHER END + LINK->CIRCUITPOINTER = 0; + + // I think it is safer to ignore it. The retry will be processed normally as XID command with no session + ReleaseBuffer(Buffer); return; } - - // Command on existing session. Could be due to other end missing - // the XID response, so if XID just resend response + // XID Response + + // if Link State = 1 this is a normal response. Check it then send SABM + + if (LINK->L2STATE == 1) + { + LINK->L2STATE = 2; + LINK->Ver2point2 = TRUE;// Must support 2.2 if responded to XID + + // if Compress enabled set it + + ptr = &ADJBUFFER->PID; + + if (*ptr++ == 0x82 && *ptr++ == 0x80) + { + int Type; + int Len; + unsigned int value; + int xidlen = *(ptr++) << 8; + xidlen += *ptr++; + + // XID is set of Type, Len, Value n-tuples + + while (xidlen > 0) + { + Type = *ptr++; + Len = *ptr++; + + value = 0; + xidlen -= (Len + 2); + + while (Len--) + { + value <<=8; + value += *ptr++; + } + switch(Type) + { + case 17: + + // Compression + + if (L2Compress) + LINK->AllowCompress = 1; + + } + } + + } + + LINK->LINKWINDOW = PORT->PORTWINDOW; // Just in case! + LINK->L2TIMER = 1; // Use retry to send SABM + + ReleaseBuffer(Buffer); + return; + } + + // XID response, not in state 1. + + // This "shouldn't happen" + + Debugprintf("Unexpected XID response, State = %d", LINK->L2STATE); + + // Discard + + ReleaseBuffer(Buffer); + return; } - if (CTLlessPF == XID && (MSGFLAG & CMDBIT)) - { - // XID Command on active session. Other end may be restarting. Send Response - ProcessXIDCommand(LINK, PORT, Buffer, ADJBUFFER, CTL, MSGFLAG); - return; + // Not XID + + // if state = 1 then unexpected response to XID + + if (LINK->L2STATE == 1) + { + if (CTLlessPF == DM || CTLlessPF == FRMR) + { + // Doesn't support XID - Send SABM + + LINK->L2STATE = 2; + LINK->Ver2point2 = FALSE; + LINK->L2TIMER = 1; // Use retry to send SABM + + ReleaseBuffer(Buffer); + return; + } } @@ -1221,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 { @@ -1288,6 +1354,16 @@ VOID L2SABM(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESSAGE * Buffe Debugprintf("INP3 Incoming connect from %s", fromCall); DeleteINP3Routes(ROUTE); } + else + { + if (PORT->ENABLEINP3) + { + // We will offer INP3 by sending an RTT probe. + + SendRTTMsg(ROUTE); + + } + } } if (NO_CTEXT == 1) @@ -1388,6 +1464,8 @@ VOID L2SABM(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESSAGE * Buffe return; } + strcpy(Session->APPL, LINK->ApplName); + // NOW TRY A BBS CONNECT // IF APPL CONNECT, SEE IF APPL HAS AN ALIAS @@ -1772,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 @@ -1983,19 +2071,32 @@ 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); } + else + { + if (PORT->ENABLEINP3) + { + // We will offer INP3 by sending an RTT probe. + + SendRTTMsg(ROUTE); + + } + } } + hookL2SessionConnected(LINK); SendL2ToMonMap(PORT, fromCall, '+', 'O'); LINK->L2STATE = 5; LINK->L2TIMER = 0; // CANCEL TIMER LINK->L2RETRIES = 0; - LINK->L2SLOTIM, T3; // SET FRAME SENT RECENTLY + LINK->L2SLOTIM = T3; // SET FRAME SENT RECENTLY // IF VERSION 1 MSG, SET FLAG @@ -2015,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) @@ -2177,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? @@ -2236,6 +2346,9 @@ VOID SFRAME(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, UCHAR CTL, UCHA LINK->L2TIMER = ONEMINUTE; // (RE)SET TIMER + + LINK->framesResent++; + PORT = LINK->LINKPORT; if (PORT) @@ -2254,6 +2367,9 @@ VOID SFRAME(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, UCHAR CTL, UCHA return; } +treatasRR: + + // VALID RR/RNR RECEIVED LINK->L2FLAGS &= ~RNRSET; //CLEAR RNR @@ -2274,7 +2390,7 @@ VOID SFRAME(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, UCHAR CTL, UCHA if (LINK->LAST_F_TIME + 15 > REALTIMETICKS) return; // DISCARD - CTL = RR_OR_RNR(LINK); + CTL = RR_OR_RNR(LINK, FALSE); // Sending response CTL |= LINK->LINKNR << 5; // SHIFT N(R) TO TOP 3 BITS CTL |= PFBIT; @@ -2339,6 +2455,20 @@ VOID SFRAME(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, UCHAR CTL, UCHA LINK->L2FLAGS &= ~POLLSENT; // CLEAR I(P) or RR(P) SET + // ?? is this the place to do RTT? + + if (LINK->lastPSent) + { + int RTT = GetTickCount() - LINK->lastPSent; + + if (LINK->RTT) + LINK->RTT = ((LINK->RTT * 90) / 100) + RTT /10; // Smooth - 90% of old + 10% of new + else + LINK->RTT = RTT; + + LINK->lastPSent = 0; + } + if ((CTL & 0xf) == RNR) { // Dont Clear timer on receipt of RNR(F), spec says should poll for clearing of busy, @@ -2586,6 +2716,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 @@ -2813,6 +2944,8 @@ VOID RESETNS(struct _LINKTABLE * LINK, UCHAR NS) { int Resent = (LINK->LINKNS - NS) & 7; // FRAMES TO RESEND + LINK->framesResent += Resent; + LINK->LINKNS = NS; // RESET N(S) if (LINK->LINKTYPE == 3) // mode-Node @@ -2981,9 +3114,9 @@ VOID SDETX(struct _LINKTABLE * LINK) // **** Debug code **** look for stuck links - if (LINK->LASTFRAMESENT && (time(NULL) - LINK->LASTFRAMESENT) > 60) // No send for 60 secs + if (LINK->LINKWINDOW == 0 || LINK->LASTFRAMESENT == 0 || (time(NULL) - LINK->LASTFRAMESENT) > 60) // No send for 60 secs { - if (COUNT_AT_L2(LINK) > 16) + if (COUNT_AT_L2(LINK) > 16 || LINK->LINKWINDOW == 0) { // Dump Link State @@ -3036,6 +3169,11 @@ VOID SDETX(struct _LINKTABLE * LINK) LINK->LASTFRAMESENT = time(NULL); LINK->LASTSENTQCOUNT = COUNT_AT_L2(LINK); + if (LINK->LASTSENTQCOUNT > LINK->maxQueued) + LINK->maxQueued = LINK->LASTSENTQCOUNT; + + if (LINK->LASTSENTQCOUNT > LINK->intervalMaxQueued) + LINK->intervalMaxQueued = LINK->LASTSENTQCOUNT; if (LINK->AllowCompress && Msg->LENGTH > 20 && LINK->TX_Q && Msg->PID == 240) // if short and no more not worth trying compression { @@ -3161,6 +3299,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; @@ -3174,6 +3316,9 @@ VOID SDETX(struct _LINKTABLE * LINK) LINK->FRAMES[LINK->SDTSLOT] = Msg; LINK->SDTSLOT ++; LINK->SDTSLOT &= 7; + + LINK->framesTXed++; + LINK->bytesTXed += (Msg->LENGTH - (MSGHDDRLEN + 1)); } } @@ -3231,6 +3376,7 @@ VOID SDETX(struct _LINKTABLE * LINK) // FLAG BUFFER TO CAUSE TIMER TO BE RESET AFTER SEND (or ACK if ACKMODE) Buffer->Linkptr = LINK; + LINK->lastPSent = GetTickCount(); } } @@ -3272,6 +3418,7 @@ VOID L2TimerProc() int i = MAXLINKS; struct _LINKTABLE * LINK = LINKS; struct PORTCONTROL * PORT = PORTTABLE; + time_t Now = time(NULL); while (i--) { @@ -3279,8 +3426,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; @@ -3316,7 +3469,7 @@ VOID L2TimerProc() { // Was busy - if (RR_OR_RNR(LINK) != RNR) // SEE IF STILL BUSY + if (RR_OR_RNR(LINK, 0) != RNR) // SEE IF STILL BUSY { // Not still busy - tell other end @@ -3375,7 +3528,7 @@ VOID L2TimerProc() { SendSupervisCmd(LINK); LINK++; - continue; + continue; } } @@ -3432,7 +3585,7 @@ VOID SendSupervisCmd(struct _LINKTABLE * LINK) LINK->L2ACKREQ = 0; // CLEAR ACK NEEDED - CTL = RR_OR_RNR(LINK); + CTL = RR_OR_RNR(LINK, TRUE); // MOV L2STATE[EBX],5 ; CANCEL REJ - ACTUALLY GOING TO 'PENDING ACK' @@ -3450,7 +3603,7 @@ void SEND_RR_RESP(struct _LINKTABLE * LINK, UCHAR PF) { UCHAR CTL; - CTL = RR_OR_RNR(LINK); + CTL = RR_OR_RNR(LINK, FALSE); // MOV L2STATE[EBX],5 ; CANCEL REJ - ACTUALLY GOING TO 'PENDING ACK' @@ -3643,6 +3796,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 @@ -3801,6 +3956,7 @@ VOID L2SENDXID(struct _LINKTABLE * LINK) if (PORT) { + LINK->LINKWINDOW = PORT->PORTWINDOW; // Just in case! Buffer->PORT = PORT->PORTNUMBER; PUT_ON_PORT_Q(PORT, Buffer); } @@ -3944,7 +4100,7 @@ VOID InformPartner(struct _LINKTABLE * LINK, int Reason) } -UINT RR_OR_RNR(struct _LINKTABLE * LINK) +UINT RR_OR_RNR(struct _LINKTABLE * LINK, int CMD) { UCHAR Temp; TRANSPORTENTRY * Session; @@ -4021,18 +4177,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 - if (SaveRNRSent) - 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; @@ -4627,5 +4786,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 7c1d5b8..0aafe67 100644 --- a/L3Code.c +++ b/L3Code.c @@ -60,6 +60,12 @@ VOID L3TRYNEXTDEST(struct ROUTE * ROUTE); 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; @@ -94,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) { @@ -222,7 +236,7 @@ BOOL ACTIVATE_DEST(struct DEST_LIST * DEST) return L2SETUPCROSSLINK(ROUTE); } - // We umst be waiting for link to come up + // We must be waiting for link to come up return TRUE; @@ -241,6 +255,13 @@ char Call1[10]; char Call2[10]; char Call3[10]; +VOID PROCESSNODESPOLL(struct PORTCONTROL * PORT) +{ + // Pauls G8BPT's request NODES Broadcast + + SENDNODESMSG(PORT->PORTNUMBER); + return; +} VOID PROCESSNODEMESSAGE(MESSAGE * Msg, struct PORTCONTROL * PORT) { // PROCESS A NET/ROM 'NODES' MESSAGE @@ -606,9 +627,6 @@ VOID PROCROUTES(struct DEST_LIST * DEST, struct ROUTE * ROUTE, int Qual) if (Index == 0) { // THIS IS A REFRESH OF BEST - IF THIS ISNT ACTIVE ROUTE, MAKE IT ACTIVE - - if (DEST->DEST_ROUTE > 1) // LEAVE IT IF NOT SELECTED OR ALREADY USING BEST - DEST->DEST_ROUTE = 1; } goto UpdatateThisEntry; @@ -707,6 +725,8 @@ SORTROUTES: goto SORTROUTES; // 1 AND 2 MAY NOW BE WRONG! } + + DEST->DEST_ROUTE = 0; // OForce re-evaluation. } int COUNTNODES(struct ROUTE * ROUTE) @@ -744,12 +764,26 @@ VOID L3BG(); VOID SENDNEXTNODESFRAGMENT(); -VOID SENDNODESMSG() +VOID SENDNODESMSG(int Portnum) { if (NODESINPROGRESS) return; - L3CURRENTPORT = PORTTABLE; + NODESToOnePort = Portnum; + + if (Portnum) // Nodes to one port only + { + L3CURRENTPORT = GetPortTableEntryFromPortNum(Portnum); + + if (L3CURRENTPORT == 0) + { + NODESToOnePort = 0; + return; + } + } + else + L3CURRENTPORT = PORTTABLE; + SENDNEXTNODESFRAGMENT(); } @@ -785,16 +819,19 @@ VOID SENDNEXTNODESFRAGMENT() // No NODES to this port, so go to next PORT = PORT->PORTPOINTER; - if (PORT == NULL) + + if (PORT == NULL || NODESToOnePort) { // Finished + NODESToOnePort = 0; NODESINPROGRESS = 0; return; } } - L3CURRENTPORT = PORT; + if (NODESToOnePort == 0) // CurrentPort already set if NODESToOnePort + L3CURRENTPORT = PORT; DEST = CURRENTNODE = DESTS; // START OF LIST NODESINPROGRESS = 1; @@ -851,13 +888,24 @@ VOID SENDNEXTNODESFRAGMENT() if (DEST >= ENDDESTLIST) { CURRENTNODE = 0; // Finished on this port - L3CURRENTPORT = PORT->PORTPOINTER; - if (L3CURRENTPORT == NULL) - { - // Finished + // if sending to only one port then stop + + if (NODESToOnePort) + { + NODESToOnePort = 0; NODESINPROGRESS = 0; } + else + { + L3CURRENTPORT = PORT->PORTPOINTER; + if (L3CURRENTPORT == NULL) + { + // Finished + + NODESINPROGRESS = 0; + } + } goto Sendit; } @@ -951,7 +999,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; @@ -991,7 +1041,8 @@ VOID L3TimerProc() LINK = LINKS; i = MAXLINKS; - while (i--); + + while (i--) { if (LINK->LINKTYPE == 3) // Only if Internode { @@ -1044,7 +1095,7 @@ VOID L3TimerProc() L3TIMER = L3INTERVAL; UPDATEDESTLIST(); - SENDNODESMSG(); + SENDNODESMSG(0); } } @@ -1082,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 @@ -1254,6 +1310,9 @@ VOID REMOVENODE(dest_list * DEST) while (DEST->DEST_Q) ReleaseBuffer(Q_REM(&DEST->DEST_Q)); + if (DEST->DEST_STATE & 0x80) // LOCKED DESTINATION + return; + // MAY NEED TO CHECK FOR L4 CIRCUITS USING DEST, BUT PROBABLY NOT, // AS THEY SHOULD HAVE TIMED OUT LONG AGO diff --git a/L4Code.c b/L4Code.c index f6fdb79..5704e49 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; + + 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); @@ -791,7 +805,7 @@ VOID L4BG() complen = L2Compressit(Compressed, 8192, toCompress, toCompressLen); - Debugprintf("%d %d %d%%", toCompressLen, complen, ((toCompressLen - complen) * 100) / toCompressLen); + // Debugprintf("%d %d %d%%", toCompressLen, complen, ((toCompressLen - complen) * 100) / toCompressLen); // Send compressed @@ -826,7 +840,7 @@ VOID L4BG() Len = ChunkSize; complen = L2Compressit(Compressed, 8192, CompressPtr, Len); - Debugprintf("Chunked %d %d %d%%", Len, complen, ((Len - complen) * 100) / Len); +// Debugprintf("Chunked %d %d %d%%", Len, complen, ((Len - complen) * 100) / Len); sendChunk(L4, Compressed, complen, savePort); @@ -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,26 @@ 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] = ""; + + if (APPL) + memcpy(APPLCMD, APPL->APPLCMD, 13); memcpy(BPQPARAMS, &L4T1, 2); // SET DEFAULT T1 IN CASE NOT FROM ANOTHER BPQ NODE @@ -1608,8 +1630,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 +1642,60 @@ 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. + + memcpy(APPLCMD, CMD->String, 13); + + 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 +1707,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 +1722,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 +1825,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 +1912,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 +1932,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 +1951,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 +1970,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 @@ -1943,7 +2031,7 @@ TryAgain: while (n--) { - if (DEST->DEST_COUNT == 0 && DEST->DEST_RTT == 0) // Not used and not INP3 + if (DEST->DEST_COUNT == 0 && DEST->DEST_RTT == 0 && (DEST->DEST_STATE & 0x80) == 0) // Not used and not INP3 and not Appl { if (DEST->NRROUTE[0].ROUT_QUALITY < WorstQual) { @@ -2020,6 +2108,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 +2138,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 +2161,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 +2170,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 +2250,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 +2291,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 +2746,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 + Partner = L4->L4CROSSLINK; - PUBLIC xxx -xxx: - - POP ECX - POP ESI - REP MOVSB + CLOSECURRENTSESSION(L4); + + if (Partner) + CLOSECURRENTSESSION(Partner); // CLOSE THIS ONE - 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 - - CALL _POSTDATAAVAIL - - POP EBX - RET -*/ \ No newline at end of file + L4++; + } + return Closed; +} diff --git a/LinBPQ.c b/LinBPQ.c index 689b5f4..ad749d0 100644 --- a/LinBPQ.c +++ b/LinBPQ.c @@ -83,8 +83,11 @@ void RHPPoll(); VOID GetPGConfig(); void SendBBSDataToPktMap(); +void CloseAllLinks(); +void hookNodeClosing(char * Reason); +void NETROMTCPResolve(); -extern uint64_t timeLoadedMS; +extern uint64_t INP3timeLoadedMS; BOOL IncludesMail = FALSE; BOOL IncludesChat = FALSE; @@ -262,9 +265,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 +340,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 +348,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 +359,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 +372,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 +406,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 +429,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 +440,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(); } @@ -839,15 +854,14 @@ int main(int argc, char * argv[]) #endif #endif - // Disable Console Terminal if stdout redirected - +// Disable Console Terminal if stdout redirected // printf("STDOUT %d\n",isatty(STDOUT_FILENO)); // printf("STDIN %d\n",isatty(STDIN_FILENO)); if (!isatty(STDOUT_FILENO) || !isatty(STDIN_FILENO)) Redirected = 1; - timeLoadedMS = GetTickCount(); + INP3timeLoadedMS = GetTickCount(); #endif @@ -1002,6 +1016,8 @@ int main(int argc, char * argv[]) return (0); } + NETROMTCPResolve(); + for (i=0;PWTEXT[i] > 0x20;i++); //Scan for cr or null PWLen=i; @@ -1533,6 +1549,8 @@ int main(int argc, char * argv[]) Consoleprintf(VerCopyright); Start(); + + NETROMTCPResolve(); INITIALISEPORTS(); @@ -1683,6 +1701,9 @@ int main(int argc, char * argv[]) Slowtimer = 0; } + hookNodeClosing("Shutdown"); + Sleep(500); + printf("Closing Ports\n"); CloseTNCEmulator(); diff --git a/MailTCP.c b/MailTCP.c index 289fb62..37c7cf9 100644 --- a/MailTCP.c +++ b/MailTCP.c @@ -2092,20 +2092,19 @@ int CreateSMTPMessage(SocketConn * sockptr, int i, char * MsgTitle, time_t Date, struct tm * tm; tm = gmtime(&Date); - + sprintf(DateString, "%04d/%02d/%02d %02d:%02d", tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min); if (strcmp(Msg->to, "RMS") == 0) // Address is in via - strcpy(B2To, Msg->via); - else - if (Msg->via[0]) - sprintf(B2To, "%s@%s", Msg->to, Msg->via); + strcpy(B2To, Msg->via); else - strcpy(B2To, Msg->to); + if (Msg->via[0]) + sprintf(B2To, "%s@%s", Msg->to, Msg->via); + else + strcpy(B2To, Msg->to); - Msg->B2Flags = B2Msg | Attachments; if (Msg->type == 'P') @@ -3934,12 +3933,12 @@ int CreatePOP3Message(char * From, char * To, char * MsgTitle, time_t Date, char if (strcmp(Msg->to, "RMS") == 0) // Address is in via - strcpy(B2To, Msg->via); - else - if (Msg->via[0]) - sprintf(B2To, "%s@%s", Msg->to, Msg->via); + strcpy(B2To, Msg->via); else - strcpy(B2To, Msg->to); + if (Msg->via[0]) + sprintf(B2To, "%s@%s", Msg->to, Msg->via); + else + strcpy(B2To, Msg->to); Msg->B2Flags = B2Msg | Attachments; diff --git a/Moncode.c b/Moncode.c index b539f1f..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 @@ -691,6 +692,14 @@ char * DISPLAY_NETROM(MESSAGE * ADJBUFFER, UCHAR * Output, int MsgLen) return Output; } + if (ADJBUFFER->L2DATA[0] == 0xfe) // Paula's Nodes Poll + { + memcpy(Alias, ++ptr, 6); + Output += sprintf((char *)Output, " NODES POLL from %s\r", Alias); + return Output; + } + + // Display normal NET/ROM transmissions Output += sprintf((char *)Output, " NET/ROM\r "); @@ -714,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++); @@ -722,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 { @@ -737,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: @@ -985,3 +1003,87 @@ char * DISPLAYARPDATAGRAM(UCHAR * Datagram, UCHAR * Output) ptr[15], ptr[16], ptr[17], ptr[18], Dest, ptr[26], ptr[27], ptr[28], ptr[29]); } + +char Lastpacketlog[256]; + +int PacketLogDelay = 30000; + +extern BPQVECSTRUC * FILEMONVECTOR; +extern UCHAR LogDirectory[260]; + +void WritePacketLogThread(void * param) +{ + char FN[256]; + time_t T; + struct tm * tm; + FILE * Handle; + int MsgLen; + MESSAGE * MSG; + MESSAGE * Q; + char buffer[512]; + + + while(1) + { + BOOL SaveMTX = MTX; + BOOL SaveMCOM = MCOM; + BOOL SaveMUI = MUIONLY; + + Sleep(PacketLogDelay); + + // Get chain of queued packets under semaphore + + GetSemaphore(&Semaphore, 101); + + Q = FILEMONVECTOR->HOSTTRACEQ; + FILEMONVECTOR->HOSTTRACEQ = 0; + + FreeSemaphore(&Semaphore); + + if (Q == 0) + continue; + + // Open log file and write decoded packets + + T = time(NULL); + tm = gmtime(&T); + + if (LogDirectory[0] == 0) + { + strcpy(FN, "logs/PacketLog"); + } + else + { + strcpy(FN, LogDirectory); + strcat(FN, "/"); + strcat(FN, "logs/PacketLog"); + } + + sprintf(&FN[strlen(FN)], "_%04d%02d%02d.log", tm->tm_year +1900, tm->tm_mon+1, tm->tm_mday); + + Handle = fopen(FN, "ab"); + + if (Handle == NULL) + return; + + while (Q) + { + MSG = Q; + Q = MSG->CHAIN; // get first + + IntSetTraceOptionsEx(MMASK, 1, 1, 0); + MsgLen = IntDecodeFrame(MSG, buffer, MSG->Timestamp, 0xffffffffffffffff, FALSE, FALSE); + IntSetTraceOptionsEx(MMASK, SaveMTX, SaveMCOM, SaveMUI); + + fwrite(buffer , 1, MsgLen, Handle); + + GetSemaphore(&Semaphore, 101); + ReleaseBuffer(MSG); + FreeSemaphore(&Semaphore); + } + fclose(Handle); + } + + return; +} + diff --git a/NETROMTCP.c b/NETROMTCP.c new file mode 100644 index 0000000..63c0494 --- /dev/null +++ b/NETROMTCP.c @@ -0,0 +1,585 @@ +/* +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); + +} + +void NETROMTCPResolve() +{ + struct ROUTE * Route = NEIGHBOURS; + int n = MAXNEIGHBOURS; + struct addrinfo hints, *res = 0; + char PortString[20]; + int err; + + while (n--) + { + if (Route->TCPAddress) + { + // try to resolve host + + sprintf(PortString, "%d", Route->TCPPort); + + 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); + + err = WSAGetLastError(); + + if (res) + { + Route->TCPAddress->ai_family = res->ai_family; + Route->TCPAddress->ai_socktype = res->ai_socktype; + Route->TCPAddress->ai_protocol = res->ai_protocol; + Route->TCPAddress->ai_addrlen = res->ai_addrlen; + memcpy(Route->TCPAddress->ai_addr, res->ai_addr, sizeof(struct sockaddr)); + freeaddrinfo(res); + } + } + + Route++; + } +} + +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 * res = Route->TCPAddress; + int Port = Route->TCPPort; + + sprintf(PortString, "%d", Port); + + // get host info, make socket, and connect it + + if (res->ai_family == 0) + { +// err = WSAGetLastError(); +// Debugprintf("Resolve HostName %s Failed - Error %d", Route->TCPHost, err); + return FALSE; // Resolve failed + } + + 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; + return TRUE; + } + else + { + 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. + + Debugprintf("New NRTCP Connection from %s", Msg->Call); + + memcpy(Info->Call, Msg->Call, 10); + + ConvToAX25(Msg->Call, axCall); + + if (FindNeighbour(axCall, portNo, &Route)) + { + Info->Route = Route; + Route->NEIGHBOUR_LINK = Info->LINK; + Route->NEIGHBOUR_PORT = portNo; + Info->LINK->NEIGHBOUR = Route; + Info->LINK->LINKPORT = GetPortTableEntryFromPortNum(portNo); + Route->TCPSession = Info; + Info->LINK->L2STATE = 5; + + if (Info->Route->INP3Node) + SendRTTMsg(Info->Route); + } + else + { + Debugprintf("Neighbour %s port %d not found - closing connection", Msg->Call, portNo); + closesocket(sockptr->socket); + sockptr->SocketActive = FALSE; + memset(sockptr, 0, sizeof(struct ConnectionInfo)); + Info->Call[0] = 0; + return 0; + } + } + + + 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 = portNo; + 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); + + if (Route) + 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 279f085..fe90705 100644 --- a/RigControl.c +++ b/RigControl.c @@ -110,7 +110,7 @@ VOID ConnecttoFLRIG(struct RIGPORTINFO * PORT); int DecodeHAMLIBAddr(struct RIGPORTINFO * PORT, char * ptr); void ProcessHAMLIBFrame(struct RIGPORTINFO * PORT, int Length); VOID HAMLIBPoll(struct RIGPORTINFO * PORT); -void HAMLIBSlaveThread(struct RIGINFO * RIG); +void HAMLIBSlaveThread(VOID * Param); void CheckAndProcessRTLUDP(struct RIGPORTINFO * PORT); VOID RTLUDPPoll(struct RIGPORTINFO * PORT); VOID ConnecttoRTLUDP(struct RIGPORTINFO * PORT); @@ -122,8 +122,8 @@ VOID ProcessSDRRadioFrame(struct RIGPORTINFO * PORT, int Length); VOID SDRRadioPoll(struct RIGPORTINFO * PORT); VOID SetupPortRIGPointers(); -VOID PTTCATThread(struct RIGINFO *RIG); -VOID ConnecttoHAMLIB(struct RIGPORTINFO * PORT); +VOID PTTCATThread(void * Param); + // ----- G7TAJ ---- VOID ConnecttoSDRANGEL(struct RIGPORTINFO * PORT); @@ -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 @@ -7484,8 +7484,9 @@ VOID SetupPortRIGPointers() #ifdef WIN32 -VOID PTTCATThread(struct RIGINFO *RIG) +VOID PTTCATThread(void * Param) { + struct RIGINFO * RIG = (struct RIGINFO *)Param; DWORD dwLength = 0; int Length, ret, i; UCHAR * ptr1; @@ -8471,7 +8472,7 @@ int DecodeHAMLIBAddr(struct RIGPORTINFO * PORT, char * ptr) return 1; } -VOID HAMLIBThread(struct RIGPORTINFO * PORT); +VOID HAMLIBThread(void * Param); VOID ConnecttoHAMLIB(struct RIGPORTINFO * PORT) { @@ -8481,10 +8482,11 @@ VOID ConnecttoHAMLIB(struct RIGPORTINFO * PORT) return ; } -VOID HAMLIBThread(struct RIGPORTINFO * PORT) +VOID HAMLIBThread(void * Param) { // Opens sockets and looks for data - + + struct RIGPORTINFO * PORT = (struct RIGPORTINFO * )Param; char Msg[255]; int err, i, ret; u_long param=1; @@ -8606,10 +8608,11 @@ Lost: -void HAMLIBSlaveThread(struct RIGINFO * RIG) +void HAMLIBSlaveThread(VOID * Param) { // Wait for connections and messages from HAMLIB Clients + struct RIGINFO * RIG = (struct RIGINFO *)Param; fd_set readfs; fd_set errorfs; struct timeval timeout; @@ -8925,7 +8928,7 @@ VOID FLRIGSendCommand(struct RIGPORTINFO * PORT, char * Command, char * Value) -VOID FLRIGThread(struct RIGPORTINFO * PORT); +VOID FLRIGThread(VOID * Param); VOID ConnecttoFLRIG(struct RIGPORTINFO * PORT) { @@ -8934,10 +8937,11 @@ VOID ConnecttoFLRIG(struct RIGPORTINFO * PORT) return ; } -VOID FLRIGThread(struct RIGPORTINFO * PORT) +VOID FLRIGThread(VOID * Param) { // Opens sockets and looks for data + struct RIGPORTINFO * PORT = (struct RIGPORTINFO *)Param; char Msg[255]; int err, i, ret; u_long param=1; @@ -10177,7 +10181,7 @@ void ProcessSDRANGELFrame(struct RIGPORTINFO * PORT) -VOID SDRANGELThread(struct RIGPORTINFO * PORT); +VOID SDRANGELThread(VOID * Param); VOID ConnecttoSDRANGEL(struct RIGPORTINFO * PORT) { @@ -10186,9 +10190,11 @@ VOID ConnecttoSDRANGEL(struct RIGPORTINFO * PORT) return ; } -VOID SDRANGELThread(struct RIGPORTINFO * PORT) +VOID SDRANGELThread(VOID * Param) { // Opens sockets and looks for data + + struct RIGPORTINFO * PORT = (struct RIGPORTINFO *)Param; char Msg[512]; int err, i, ret; u_long param=1; diff --git a/TelnetV6.c b/TelnetV6.c index 0756447..590186c 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); @@ -3796,12 +3874,14 @@ MsgLoop: LFPtr=memchr(MsgPtr, 10, InputLen); if (LFPtr == 0) + { if (CRPtr) { LFPtr = ++CRPtr; InputLen++; } - if (LFPtr == 0) + } + if (LFPtr == 0) { // Check Paclen @@ -3817,7 +3897,7 @@ MsgLoop: } // Send to Node - + // Line could be up to 500 chars if coming from a program rather than an interative user // Limit send to node to 255 @@ -3829,16 +3909,16 @@ MsgLoop: memmove(MsgPtr,MsgPtr+255,InputLen); } - + SendtoNode(TNC, sockptr->Number, MsgPtr, InputLen); sockptr->InputLen = 0; - + } // PACLEN return 0; // No CR } - + // Got a LF // Process data up to the cr @@ -3851,7 +3931,7 @@ MsgLoop: case 2: // Normal Data State - + STREAM->bytesRXed += MsgLen; SendIndex = 0; @@ -3866,7 +3946,7 @@ MsgLoop: } SendtoNode(TNC, sockptr->Number, MsgPtr + SendIndex, MsgLen); - + MsgLen += SendIndex; // If anything left, copy down buffer, and go back @@ -3885,20 +3965,20 @@ MsgLoop: return 0; case 0: - - // Check Username - // + + // Check Username + // *(LFPtr-1)=0; // remove cr - - // send(sock, NLMsg, 2, 0); - if (LogEnabled) + // send(sock, NLMsg, 2, 0); + + if (LogEnabled) { char Addr[256]; - + Tel_Format_Addr(sockptr, Addr); - + if (strlen(MsgPtr) > 64) { MsgPtr[64] = 0; @@ -4493,7 +4573,8 @@ MsgLoop: if (P8 == 1) SendPortsForMonitor(sock, sockptr->UserPointer->Secure); - sockptr->InputLen = 0; + + sockptr->InputLen = 0; return 0; } } @@ -5271,6 +5352,7 @@ int DataSocket_ReadDRATS(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, } + int DataSocket_Disconnect(struct TNCINFO * TNC, struct ConnectionInfo * sockptr) { int n; @@ -5685,7 +5767,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 @@ -6305,10 +6389,10 @@ VOID SaveCMSHostInfo(int port, struct TCPINFO * TCP, int CMSNo) char ip[256]; int n; - if (sizeof(time_t) == 4) - n = sscanf(buf,"%s %d %s", addr, (int *)&t, ip); - else - n = sscanf(buf, "%s %lld %s", addr, &t, ip); + if (sizeof(time_t) == 4) + n = sscanf(buf,"%s %d %s", addr, (int *)&t, ip); + else + n = sscanf(buf, "%s %lld %s", addr, &t, ip); if (n == 3) { 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..2adfe12 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 @@ -1581,81 +1586,81 @@ static int ProcessLine(char * buf, int Port) if (TNC->TCPPort == 0) TNC->TCPPort = 8000; - TNC->destaddr.sin_family = AF_INET; - TNC->destaddr.sin_port = htons(TNC->TCPPort); - TNC->HostName = malloc(strlen(p_ipad)+1); + TNC->destaddr.sin_family = AF_INET; + TNC->destaddr.sin_port = htons(TNC->TCPPort); + TNC->HostName = malloc(strlen(p_ipad)+1); - if (TNC->HostName == NULL) return TRUE; + if (TNC->HostName == NULL) return TRUE; - strcpy(TNC->HostName,p_ipad); + strcpy(TNC->HostName,p_ipad); - ptr = strtok(NULL, " \t\n\r"); + ptr = strtok(NULL, " \t\n\r"); - if (ptr) + if (ptr) + { + if (_stricmp(ptr, "PTT") == 0) { - if (_stricmp(ptr, "PTT") == 0) - { - ptr = strtok(NULL, " \t\n\r"); + ptr = strtok(NULL, " \t\n\r"); - if (ptr) - { - DecodePTTString(TNC, ptr); - ptr = strtok(NULL, " \t\n\r"); - } - } - - if (ptr &&_memicmp(ptr, "PATH", 4) == 0) + if (ptr) { - p_cmd = strtok(NULL, "\n\r"); - if (p_cmd) TNC->ProgramPath = _strdup(p_cmd); + DecodePTTString(TNC, ptr); + ptr = strtok(NULL, " \t\n\r"); } } - // Read Initialisation lines - - while(TRUE) + if (ptr &&_memicmp(ptr, "PATH", 4) == 0) { - if (GetLine(buf) == 0) - return TRUE; + p_cmd = strtok(NULL, "\n\r"); + if (p_cmd) TNC->ProgramPath = _strdup(p_cmd); + } + } - strcpy(errbuf, buf); + // Read Initialisation lines - if (memcmp(buf, "****", 4) == 0) - return TRUE; + while(TRUE) + { + if (GetLine(buf) == 0) + return TRUE; - ptr = strchr(buf, ';'); - if (ptr) - { - *ptr++ = 13; - *ptr = 0; - } - - if (_memicmp(buf, "MAXSESSIONS", 11) == 0) - { - AGW->MaxSessions = atoi(&buf[12]); - if (AGW->MaxSessions > 26 ) AGW->MaxSessions = 26; - } - if (_memicmp(buf, "CONTIMEOUT", 10) == 0) - AGW->ConnTimeOut = atoi(&buf[11]) * 10; - else + strcpy(errbuf, buf); + + if (memcmp(buf, "****", 4) == 0) + return TRUE; + + ptr = strchr(buf, ';'); + if (ptr) + { + *ptr++ = 13; + *ptr = 0; + } + + if (_memicmp(buf, "MAXSESSIONS", 11) == 0) + { + AGW->MaxSessions = atoi(&buf[12]); + if (AGW->MaxSessions > 26 ) AGW->MaxSessions = 26; + } + if (_memicmp(buf, "CONTIMEOUT", 10) == 0) + AGW->ConnTimeOut = atoi(&buf[11]) * 10; + else if (_memicmp(buf, "UPDATEMAP", 9) == 0) TNC->PktUpdateMap = TRUE; else - if (_memicmp(buf, "BEACONAFTERSESSION", 18) == 0) // Send Beacon after each session - TNC->RPBEACON = TRUE; - else - if (_memicmp(buf, "WINDOW", 6) == 0) - TNC->Window = atoi(&buf[7]); - else - if (_memicmp(buf, "DEFAULTMODEM", 12) == 0) - TNC->AGWInfo->Modem = atoi(&buf[13]); - else - if (_memicmp(buf, "MODEMCENTER", 11) == 0 || _memicmp(buf, "MODEMCENTRE", 11) == 0) - TNC->AGWInfo->CenterFreq = atoi(&buf[12]); - else - if (standardParams(TNC, buf) == FALSE) - strcat(TNC->InitScript, buf); - } + if (_memicmp(buf, "BEACONAFTERSESSION", 18) == 0) // Send Beacon after each session + TNC->RPBEACON = TRUE; + else + if (_memicmp(buf, "WINDOW", 6) == 0) + TNC->Window = atoi(&buf[7]); + else + if (_memicmp(buf, "DEFAULTMODEM", 12) == 0) + TNC->AGWInfo->Modem = atoi(&buf[13]); + else + if (_memicmp(buf, "MODEMCENTER", 11) == 0 || _memicmp(buf, "MODEMCENTRE", 11) == 0) + TNC->AGWInfo->CenterFreq = atoi(&buf[12]); + else + if (standardParams(TNC, buf) == FALSE) + strcat(TNC->InitScript, buf); + } return (TRUE); diff --git a/VARA.c b/VARA.c index 4574fa4..f913fe8 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 @@ -418,8 +423,9 @@ static size_t ExtProc(int fn, int port, PDATAMESSAGE buff) { TNC->Busy--; if (TNC->Busy == 0) - SetWindowText(TNC->xIDC_CHANSTATE, "Clear"); + { SetWindowText(TNC->xIDC_CHANSTATE, "Clear"); strcpy(TNC->WEB_CHANSTATE, "Clear"); + } } } diff --git a/Versions.h b/Versions.h index ccf1ddd..f5d5fb8 100644 --- a/Versions.h +++ b/Versions.h @@ -10,15 +10,15 @@ #endif -#define KVers 6,0,25,1 -#define KVerstring "6.0.25.1\0" +#define KVers 6,0,25,9 +#define KVerstring "6.0.25.9\0" #ifdef CKernel #define Vers KVers #define Verstring KVerstring -#define Datestring "August 2025" +#define Datestring "October 2025" #define VerComments "G8BPQ Packet Switch (C Version)" KVerstring #define VerCopyright "Copyright © 2001-2025 John Wiseman G8BPQ\0" #define VerDesc "BPQ32 Switch\0" diff --git a/WINMOR.c b/WINMOR.c index 2a3d766..94630b3 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; @@ -613,8 +618,10 @@ static size_t ExtProc(int fn, int port, PDATAMESSAGE buff) { TNC->Busy--; if (TNC->Busy == 0) + { SetWindowText(TNC->xIDC_CHANSTATE, "Clear"); strcpy(TNC->WEB_CHANSTATE, "Clear"); + } } } diff --git a/WebMail.c b/WebMail.c index 63bfd6e..a97b9bf 100644 --- a/WebMail.c +++ b/WebMail.c @@ -3311,7 +3311,7 @@ char * xxReadTemplate(char * FormSet, char * DirName, char *FileName) while ((entry = readdir(dir)) != NULL) { if (entry->d_type == DT_DIR) - continue; + continue; if (stristr(entry->d_name, FileName)) { @@ -5609,7 +5609,7 @@ char * CheckFile(struct HtmlFormDir * Dir, char * FN) while ((entry = readdir(dir)) != NULL) { if (entry->d_type == DT_DIR) - continue; + continue; if (stricmp(entry->d_name, FN) == 0) { diff --git a/asmstrucs.h b/asmstrucs.h index 968f5fb..89e5277 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 @@ -64,15 +64,6 @@ extern int ENDOFDATA; extern int L3LIVES; extern int NUMBEROFNODES; -struct CMDX -{ - char String[12]; // COMMAND STRING - UCHAR CMDLEN; // SIGNIFICANT LENGTH -// VOID (*CMDPROC)(struct _TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct CMDX * CMD);// COMMAND PROCESSOR - VOID (*CMDPROC)();// COMMAND PROCESSOR - size_t CMDFLAG; // FLAG/VALUE Offset - -}; struct APPLCONFIG { @@ -186,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; @@ -229,13 +228,15 @@ typedef struct ROUTE BOOL INP3Node; BOOL NoKeepAlive; // Suppress Keepalive Processing int LastConnectAttempt; // To stop us trying too often + int ConnectionAttempts; - int Status; // + int Status; // + int OldBPQ; // Set if other end is BPQ sending RIF in mS int LastRTT; // Last Value Reported int RTT; // Current int SRTT; // Smoothed RTT int NeighbourSRTT; // Other End SRTT -// int RTTIncrement; // Average of Ours and Neighbours SRTT in 10 ms + int RTTIncrement; // Average of Ours and Neighbours SRTT in 10 ms - smoothed neighbor transport time (SNTT) in spec int BCTimer; // Time to next L3RTT Broadcast int Timeout; // Lost Response Timer int Retries; // Lost Response Count @@ -244,6 +245,13 @@ typedef struct ROUTE int OtherendsRouteQual; // Route quality used by other end. int OtherendLocked; // Route quality locked by ROUTES entry. int FirstTimeFlag; // Set once quality has been set by direct receive + int RemoteMAXRTT; // For INP3 + int RemoteMAXHOPS; + + char * TCPHost; // For NETROM over TCP + int TCPPort; + struct NRTCPSTRUCT * TCPSession; + struct addrinfo * TCPAddress; // Resolved Address } *PROUTE; @@ -701,7 +709,8 @@ typedef struct PORTCONTROL BOOL NormalizeQuality; // Normalise Node Qualities BOOL IgnoreUnlocked; // Ignore Unlocked routes BOOL INP3ONLY; // Default to INP3 and disallow NODES - BOOL ALLOWINP3; + BOOL ALLOWINP3; // Accept INP3 if offered by other end + BOOL ENABLEINP3; // Send INP3 RTT probes to discovered neighbours void (* UIHook)(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESSAGE * Buffer, MESSAGE * ADJBUFFER, UCHAR CTL, UCHAR MSGFLAG); // Used for KISSARQ struct PORTCONTROL * HookPort; @@ -966,6 +975,18 @@ typedef struct _LINKTABLE time_t ConnectTime; // For session stats int bytesRXed; // Info bytes only int bytesTXed; + int framesRXed; + int framesTXed; + int framesResent; + time_t LastStatusTime; + int LastStatusbytesRXed; + int LastStatusbytesTXed; + int maxQueued; + int intervalMaxQueued; + + uint64_t lastPSent; // Time last I frame with P bit sent in mS (for RTT Measurements) + int RTT; + // Now support compressing L2 Sessions. // We collect as much data as possible before compressing and re-packetizing @@ -981,6 +1002,8 @@ typedef struct _LINKTABLE int Received; int ReceivedAfterExpansion; + char ApplName[16]; + time_t lastStatusSentTime; } LINKTABLE; @@ -1472,6 +1495,25 @@ struct AXIPPORTINFO }; +struct CMDX +{ + char String[12]; // COMMAND STRING + UCHAR CMDLEN; // SIGNIFICANT LENGTH + VOID (*CMDPROC)(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct CMDX * CMD);// COMMAND PROCESSOR +// VOID (*CMDPROC)();// COMMAND PROCESSOR + size_t CMDFLAG; // FLAG/VALUE Offset + +}; + +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/bpqaxip.c b/bpqaxip.c index d5afb62..71f0ce1 100644 --- a/bpqaxip.c +++ b/bpqaxip.c @@ -192,8 +192,8 @@ extern UCHAR BPQDirectory[]; extern int OffsetH, OffsetW; -static void ResolveNames(struct AXIPPORTINFO * PORT); -void OpenSockets(struct AXIPPORTINFO * PORT); +static void ResolveNames(VOID * Param); +void OpenSockets(VOID * Param); void CloseSockets(struct AXIPPORTINFO * PORT); @@ -221,7 +221,7 @@ int KissDecode(UCHAR * inbuff, int len); int Socket_Accept(int SocketId); int Socket_Connect(int SocketId, int Error); int Socket_Data(int sock, int error, int eventcode); -VOID TCPConnectThread(struct arp_table_entry * arp); +VOID TCPConnectThread(VOID * Param); VOID __cdecl Debugprintf(const char * format, ...); VOID __cdecl Consoleprintf(const char * format, ...); BOOL OpenListeningSocket(struct AXIPPORTINFO * PORT, struct arp_table_entry * arp); @@ -444,7 +444,7 @@ static size_t ExtProc(int fn, int port, PMESSAGE buff) From[ConvFromAX25(call, &From[1]) + 1] = 0; if (strstr(CantReplyList, From) == 0) { - if (strlen(CantReplyList) < 500); + if (strlen(CantReplyList) < 500) strcat(CantReplyList, From); Debugprintf("AXIP Packet from %s dropped - can't reply", &From[1]); } @@ -557,7 +557,7 @@ static size_t ExtProc(int fn, int port, PMESSAGE buff) From[ConvFromAX25(call, &From[1]) + 1] = 0; if (strstr(CantReplyList, From) == 0) { - if (strlen(CantReplyList) < 500); + if (strlen(CantReplyList) < 500) strcat(CantReplyList, From); Debugprintf("AXIP Packet from %s dropped - can't reply", &From[1]); } @@ -692,7 +692,7 @@ static size_t ExtProc(int fn, int port, PMESSAGE buff) else Consoleprintf("Failed to reread config file - leaving config unchanged"); - _beginthread(OpenSockets, 0, PORT ); + _beginthread(OpenSockets, 0, PORT); GetAXIPCache(PORT); @@ -844,8 +844,9 @@ int InitAXIP(int Port) return (TRUE); } -void OpenSockets(struct AXIPPORTINFO * PORT) +void OpenSockets(void * Param) { + struct AXIPPORTINFO * PORT = (struct AXIPPORTINFO *)Param; char Msg[255]; int err; u_long param=1; @@ -1528,8 +1529,9 @@ static void CreateResolverWindow(struct AXIPPORTINFO * PORT) extern HWND hWndPopup; -static void ResolveNames(struct AXIPPORTINFO * PORT) +static void ResolveNames(VOID * Param) { + struct AXIPPORTINFO * PORT = (struct AXIPPORTINFO *)Param; int count = 0; PORT->ResolveNamesThreadId = GetCurrentThreadId(); // Detect if another started @@ -2996,8 +2998,9 @@ int KissDecode(UCHAR * inbuff, int len) return txptr; } -VOID TCPConnectThread(struct arp_table_entry * arp) +VOID TCPConnectThread(void * Param) { + struct arp_table_entry * arp = (struct arp_table_entry *)Param; char Msg[255]; int err, i; u_long param=1; diff --git a/cMain.c b/cMain.c index c722147..1eda80c 100644 --- a/cMain.c +++ b/cMain.c @@ -54,13 +54,26 @@ void MQTTTimer(); 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" 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; @@ -181,6 +194,7 @@ extern VOID * ENDPOOL; extern void * APPL_Q; // Queue of frames for APRS Appl extern BOOL APRSActive; +extern int DEBUGINP3; #define BPQHOSTSTREAMS 64 @@ -194,9 +208,12 @@ BPQVECSTRUC * TELNETMONVECPTR = &BPQHOSTVECTOR[BPQHOSTSTREAMS]; BPQVECSTRUC * AGWMONVECPTR = &BPQHOSTVECTOR[BPQHOSTSTREAMS + 1]; BPQVECSTRUC * APRSMONVECPTR = &BPQHOSTVECTOR[BPQHOSTSTREAMS + 2]; BPQVECSTRUC * IPHOSTVECTORPTR = &BPQHOSTVECTOR[BPQHOSTSTREAMS + 3]; +BPQVECSTRUC * FILEMONVECTOR = &BPQHOSTVECTOR[BPQHOSTSTREAMS + 4]; int BPQVECLENGTH = sizeof(BPQVECSTRUC); +int MONTOFILEFLAG = 0; + int NODEORDER = 0; UCHAR LINKEDFLAG = 0; @@ -250,6 +267,8 @@ int CFLAG = 0; // C =HOST Command VOID * IDMSG_Q = NULL; // ID/BEACONS WAITING TO BE SENT int NODESINPROGRESS = 0; +int NODESToOnePort = 0; // Set to port num to send NODES to only one port. + VOID * CURRENTNODE = NULL; // NEXT _NODE TO SEND VOID * DESTHEADER = NULL; // HEAD OF SORTED NODES CHAIN @@ -305,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) @@ -862,6 +881,11 @@ BOOL Start() PREFERINP3ROUTES = cfg->C_PREFERINP3ROUTES; + if (cfg->C_DEBUGINP3) + DEBUGINP3 = 0; + + EnableOARCAPI = cfg->C_OARCAPI; + if (cfg->C_OnlyVer2point0) SUPPORT2point2 = 0; @@ -992,6 +1016,7 @@ BOOL Start() PORT->IgnoreUnlocked = PortRec->IGNOREUNLOCKED; PORT->INP3ONLY = PortRec->INP3ONLY; PORT->ALLOWINP3 = PortRec->AllowINP3; + PORT->ENABLEINP3 = PortRec->EnableINP3; PORT->PORTWINDOW = (UCHAR)PortRec->MAXFRAME; @@ -1366,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 @@ -1386,11 +1411,20 @@ BOOL Start() ROUTE->OtherendsRouteQual = ROUTE->OtherendLocked = Rcfg->farQual; ROUTE->NEIGHBOUR_FLAG = LOCKEDBYCONFIG; // Locked + + if (Rcfg->tcphost) + { + ROUTE->TCPHost = Rcfg->tcphost; + ROUTE->TCPPort = Rcfg->tcpport; + + ROUTE->TCPAddress = (struct addrinfo *)zalloc(sizeof(struct addrinfo)); + ROUTE->TCPAddress->ai_addr = (struct sockaddr *) zalloc(sizeof(struct sockaddr)); + } Rcfg++; ROUTE++; } - + // SET UP INFO MESSAGE ptr2 = &cfg->C_INFOMSG[0]; @@ -1564,8 +1598,34 @@ BOOL Start() upnpInit(); + // Start Monitor to file thread + + _beginthread(WritePacketLogThread, 0, NULL); + 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; } @@ -1971,7 +2031,7 @@ VOID ReadNodes() ptr = strtok_s(NULL, seps, &Context); // INP3 if (ptr == NULL) continue; - if (ROUTE->NEIGHBOUR_FLAG == 0 || ROUTE->OtherendLocked == 0); // Not LOCKED ROUTE + if (ROUTE->NEIGHBOUR_FLAG == 0 || ROUTE->OtherendLocked == 0) // Not LOCKED ROUTE ROUTE->OtherendsRouteQual = atoi(ptr); ptr = strtok_s(NULL, seps, &Context); // INP3 @@ -2159,6 +2219,12 @@ VOID TIMERINTERRUPT() if (MQTT) MQTTTimer(); + if (LastNodeStatus && (time(NULL) - LastNodeStatus) > nodeStatusTimer) + { + LastNodeStatus = time(NULL); + hookNodeRunning(); + } + /* if (QCOUNT < 200) { @@ -2214,6 +2280,10 @@ VOID TIMERINTERRUPT() } Message = (struct _MESSAGE *)Buffer; + + if(NodeAPISocket) + APIL2Trace(Message, "sent"); + Message->PORT |= 0x80; // Set TX Bit BPQTRACE(Message, FALSE); // Dont send TX'ed frames to APRS @@ -2325,6 +2395,9 @@ L2Packet: if (MQTT && PORT->PROTOCOL == 0) MQTTKISSRX(Buffer); + + if(NodeAPISocket &&PORT->PROTOCOL == 0) + APIL2Trace(Message, "rcvd"); // Bridge if requested @@ -2514,9 +2587,9 @@ ENDOFLIST: { // Stuck link debug check - if (LINK->LASTFRAMESENT && (time(NULL) - LINK->LASTFRAMESENT) > 60) // No send for 60 secs + if (LINK->LINKWINDOW == 0 || LINK->LASTFRAMESENT == 0 || (time(NULL) - LINK->LASTFRAMESENT) > 60) // No send for 60 secs { - if (COUNT_AT_L2(LINK) > 16) + if (COUNT_AT_L2(LINK) > 16 || LINK->LINKWINDOW == 0) { // Dump Link State @@ -2675,6 +2748,18 @@ int BPQTRACE(MESSAGE * Msg, BOOL TOAPRS) L4++; } + // And to the Monitor to File system. + + if (MONTOFILEFLAG) // Trace Enabled? + { + Buffer = GetBuff(); + if (Buffer) + { + memcpy(&Buffer->PORT, &Msg->PORT, BUFFLEN - sizeof(void *)); // Dont copy chain word + C_Q_ADD(&FILEMONVECTOR->HOSTTRACEQ, Buffer); + } + } + return TRUE; } ; 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/compatbits.h b/compatbits.h index 8cdc714..9707771 100644 --- a/compatbits.h +++ b/compatbits.h @@ -49,7 +49,39 @@ Stuff to make compiling on WINDOWS and LINUX easier int pthread_equal(pthread_t T1, pthread_t T2); -uintptr_t _beginthread(void(__cdecl *start_address)(void *), unsigned stack_size, void *arglist); +uintptr_t _beginthread(void(__cdecl start_address)(void *), unsigned stack_size, void *arglist); + +#if defined(_MSC_VER) && _MSC_VER < 1900 + +#define snprintf c99_snprintf +#define vsnprintf c99_vsnprintf + +__inline int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) +{ + int count = -1; + + if (size != 0) + count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); + if (count == -1) + count = _vscprintf(format, ap); + + return count; +} + +__inline int c99_snprintf(char *outBuf, size_t size, const char *format, ...) +{ + int count; + va_list ap; + + va_start(ap, format); + count = c99_vsnprintf(outBuf, size, format, ap); + va_end(ap); + + return count; +} +#endif + + #else @@ -152,9 +184,7 @@ int stricmp(const unsigned char * pStr1, const unsigned char *pStr2); char * strupr(char* s); char * strlwr(char* s); -pthread_t _beginthread(void(*start_address)(), unsigned stack_size, VOID * arglist); - - +pthread_t _beginthread(void(start_address)(void *), unsigned stack_size, VOID * arglist); #define WSAGetLastError() errno #define GetLastError() errno diff --git a/config.c b/config.c index a1b39a2..33213df 100644 --- a/config.c +++ b/config.c @@ -305,11 +305,12 @@ 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", -"L2CompPaclen", "PREFERINP3ROUTES", "OnlyVer2point0" +"L2CompPaclen", "PREFERINP3ROUTES", "OnlyVer2point0", "DEBUGINP3", "ENABLEOARCAPI" }; /* parameter keywords */ static void * offset[] = @@ -328,11 +329,12 @@ 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, -&xxcfg.C_L2CompPaclen, &xxcfg.C_PREFERINP3ROUTES, &xxcfg.C_OnlyVer2point0}; /* offset for corresponding data in config file */ +&xxcfg.C_L2CompPaclen, &xxcfg.C_PREFERINP3ROUTES, &xxcfg.C_OnlyVer2point0, &xxcfg.C_DEBUGINP3, &xxcfg.C_OARCAPI}; /* offset for corresponding data in config file */ static int routine[] = { @@ -350,11 +352,12 @@ 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, -1, 1, 1} ; // Routine to process param +1, 1, 1, 1, 1}; // Routine to process param int PARAMLIM = sizeof(routine)/sizeof(int); //int NUMBEROFKEYWORDS = sizeof(routine)/sizeof(int); @@ -376,7 +379,7 @@ static char *pkeywords[] = "BCALL", "DIGIMASK", "NOKEEPALIVES", "COMPORT", "DRIVER", "WL2KREPORT", "UIONLY", "UDPPORT", "IPADDR", "I2CBUS", "I2CDEVICE", "UDPTXPORT", "UDPRXPORT", "NONORMALIZE", "IGNOREUNLOCKEDROUTES", "INP3ONLY", "TCPPORT", "RIGPORT", "PERMITTEDAPPLS", "HIDE", -"SMARTID", "KISSCOMMAND", "SendtoM0LTEMap", "PortFreq", "M0LTEMapInfo", "QTSMPort", "ALLOWINP3"}; /* parameter keywords */ +"SMARTID", "KISSCOMMAND", "SendtoM0LTEMap", "PortFreq", "M0LTEMapInfo", "QTSMPort", "ALLOWINP3", "ENABLEINP3"}; /* parameter keywords */ static void * poffset[] = { @@ -390,7 +393,7 @@ static void * poffset[] = &xxp.BCALL, &xxp.DIGIMASK, &xxp.DefaultNoKeepAlives, &xxp.IOADDR, &xxp.DLLNAME, &xxp.WL2K, &xxp.UIONLY, &xxp.IOADDR, &xxp.IPADDR, &xxp.INTLEVEL, &xxp.IOADDR, &xxp.IOADDR, &xxp.ListenPort, &xxp.NoNormalize, &xxp.IGNOREUNLOCKED, &xxp.INP3ONLY, &xxp.TCPPORT, &xxp.RIGPORT, &xxp.PERMITTEDAPPLS, &xxp.Hide, -&xxp.SmartID, &xxp.KissParams, &xxp.SendtoM0LTEMap, &xxp.PortFreq, &xxp.M0LTEMapInfo, &xxp.QtSMPort, &xxp.AllowINP3}; /* offset for corresponding data in config file */ +&xxp.SmartID, &xxp.KissParams, &xxp.SendtoM0LTEMap, &xxp.PortFreq, &xxp.M0LTEMapInfo, &xxp.QtSMPort, &xxp.AllowINP3, &xxp.EnableINP3}; /* offset for corresponding data in config file */ static int proutine[] = { @@ -404,7 +407,7 @@ static int proutine[] = 0, 1, 2, 18, 15, 16, 2, 1, 17, 1, 1, 1, 1, 2, 2, 2, 1, 1, 19, 2, -1, 20, 1, 21, 22, 1, 1}; /* routine to process parameter */ +1, 20, 1, 21, 22, 1, 1, 1}; /* routine to process parameter */ int PPARAMLIM = sizeof(proutine)/sizeof(int); @@ -601,7 +604,6 @@ BOOL ProcessConfig() for (i=0;i<24;i++) - paramok[45+i]=1; /* or APPLCALLS, APPLALIASS APPLQUAL */ paramok[69]=1; // BText optional @@ -630,7 +632,11 @@ BOOL ProcessConfig() paramok[90]=1; // L2Compress Maxframe paramok[91]=1; // L2Compress Paclen paramok[92]=1; // PREFERINP3ROUTES - paramok[93]=1; // C_ONLYVer2point0 + paramok[93]=1; // ONLYVer2point0 + paramok[94]=1; // DEBUGINP3 + paramok[95]=1; // EnableOARCAPI + paramok[96]=1; // OARCAPI + for (i=0; i < PARAMLIM; i++) { @@ -1583,32 +1589,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 - strcpy(&Param[n++][0], ptr1); - ptr1 = ptr2; - while(ptr1 && *ptr1 && *ptr1 == ' ') - ptr1++; + 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); + } + + 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 + { - 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]); + 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]); + + if (inp3 & 1) + Route->inp3 = 1; + + if (inp3 & 2) + Route->nokeepalives = 1; + } if (Route->farQual < 0 || Route->farQual > 255) { @@ -1633,14 +1767,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 9fb75cf..013d725 100644 --- a/configstructs.h +++ b/configstructs.h @@ -82,6 +82,7 @@ struct PORTCONFIG char * M0LTEMapInfo; int QtSMPort; int AllowINP3; + int EnableINP3; }; struct ROUTECONFIG @@ -93,6 +94,10 @@ struct ROUTECONFIG int pfrack; int ppacl; int farQual; + int inp3; + int nokeepalives; + char * tcphost; + int tcpport; }; struct CONFIGTABLE @@ -179,6 +184,8 @@ struct CONFIGTABLE int C_L2CompPaclen; int C_PREFERINP3ROUTES; int C_OnlyVer2point0; + int C_DEBUGINP3; + int C_OARCAPI; //#define ApplOffset 80000 // Applications offset in config buffer diff --git a/datadefs.c b/datadefs.c index f68c1c4..54766ab 100644 --- a/datadefs.c +++ b/datadefs.c @@ -35,6 +35,9 @@ int RFOnly = 0; int MAXRTT = 9000; // 90 secs int MaxHops = 4; +int DEBUGINP3 = 0; + +int EnableOARCAPI = 0; int RTTInterval = 24; // 4 Minutes 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/kiss.c b/kiss.c index 2f2f071..c456088 100644 --- a/kiss.c +++ b/kiss.c @@ -1905,7 +1905,7 @@ int i2cPoll(struct PORTCONTROL * PORT, NPASYINFO npKISSINFO) // KISS Over TCP Routines -VOID ConnecttoTCPThread(NPASYINFO ASY); +VOID ConnecttoTCPThread(void * Param); int ConnecttoTCP(NPASYINFO ASY) { @@ -1914,8 +1914,9 @@ int ConnecttoTCP(NPASYINFO ASY) return 0; } -VOID ConnecttoTCPThread(NPASYINFO ASY) +VOID ConnecttoTCPThread(void * Param) { + NPASYINFO ASY = (NPASYINFO)Param; char Msg[255]; int err,i; u_long param=1; @@ -2131,7 +2132,7 @@ int KISSGetTCPMessage(NPASYINFO ASY) // Interface to QtSM Managmemt Interface -VOID QtSMThread(struct PORTCONTROL * PORT); +VOID QtSMThread(void * Param); VOID ConnecttoQtSM(struct PORTCONTROL * PORT) { @@ -2141,11 +2142,12 @@ VOID ConnecttoQtSM(struct PORTCONTROL * PORT) return ; } -VOID QtSMThread(struct PORTCONTROL * PORT) +VOID QtSMThread(void * Param) { // This is the Managemt Interface in QtSM. It receives PTT ON/OFF msgs from QtSM and allows changing modem mode and freq. // Also will collect link usage stats + struct PORTCONTROL * PORT = (struct PORTCONTROL *)Param; char Msg[255]; int err, i, ret; u_long param = 1; diff --git a/lzhuf32.c b/lzhuf32.c index c1aea82..961c624 100644 --- a/lzhuf32.c +++ b/lzhuf32.c @@ -487,124 +487,124 @@ static void reconst(void) static void update(int c) { - int i, j, l; + int i, j, l; unsigned int k; - if (freq[R] == MAX_FREQ) { - reconst(); - } - c = prnt[c + T]; - do { - k = ++freq[c]; + if (freq[R] == MAX_FREQ) { + reconst(); + } + c = prnt[c + T]; + do { + k = ++freq[c]; - /* if the order is disturbed, exchange nodes */ + /* if the order is disturbed, exchange nodes */ + + l = c + 1; - l = c + 1; - if ((unsigned)k > freq[l]) { - while ((unsigned)k > freq[++l]); - l--; - freq[c] = freq[l]; - freq[l] = k; + while ((unsigned)k > freq[++l]); + l--; + freq[c] = freq[l]; + freq[l] = k; - i = son[c]; - prnt[i] = l; - if (i < T) prnt[i + 1] = l; + i = son[c]; + prnt[i] = l; + if (i < T) prnt[i + 1] = l; - j = son[l]; - son[l] = i; + j = son[l]; + son[l] = i; - prnt[j] = c; - if (j < T) prnt[j + 1] = c; - son[c] = j; + prnt[j] = c; + if (j < T) prnt[j + 1] = c; + son[c] = j; - c = l; - } - } while ((c = prnt[c]) != 0); /* repeat up to root */ + c = l; + } + } while ((c = prnt[c]) != 0); /* repeat up to root */ } unsigned code, len; static void EncodeChar(unsigned int c) { - unsigned int i; - int j, k; + unsigned int i; + int j, k; - i = 0; - j = 0; - k = prnt[c + T]; + i = 0; + j = 0; + k = prnt[c + T]; - /* travel from leaf to root */ - do { - i >>= 1; + /* travel from leaf to root */ + do { + i >>= 1; - /* if node's address is odd-numbered, choose bigger brother node */ - if (k & 1) i += 0x8000; + /* if node's address is odd-numbered, choose bigger brother node */ + if (k & 1) i += 0x8000; - j++; - } while ((k = prnt[k]) != R); - Putcode(j, i); - code = i; - len = j; - update(c); + j++; + } while ((k = prnt[k]) != R); + Putcode(j, i); + code = i; + len = j; + update(c); } static void EncodePosition(unsigned int c) { - unsigned int i; + unsigned int i; - /* output upper 6 bits by table lookup */ - i = c >> 6; - Putcode(p_len[i], (unsigned)p_code[i] << 8); + /* output upper 6 bits by table lookup */ + i = c >> 6; + Putcode(p_len[i], (unsigned)p_code[i] << 8); - /* output lower 6 bits verbatim */ - Putcode(6, (c & 0x3f) << 10); + /* output lower 6 bits verbatim */ + Putcode(6, (c & 0x3f) << 10); } static void EncodeEnd(void) { - if (putlen) { - if (crc_fputc(putbuf >> 8) == EOF) { - Error(wterr); - } - codesize++; - } + if (putlen) { + if (crc_fputc(putbuf >> 8) == EOF) { + Error(wterr); + } + codesize++; + } } int DecodeChar(void) { - unsigned int c; + unsigned int c; - c = son[R]; + c = son[R]; - /* travel from root to leaf, */ - /* choosing the smaller child node (son[]) if the read bit is 0, */ - /* the bigger (son[]+1} if 1 */ - while (c < T) { - c += GetBit(); - c = son[c]; - } - c -= T; - update(c); - return (int)c; + /* travel from root to leaf, */ + /* choosing the smaller child node (son[]) if the read bit is 0, */ + /* the bigger (son[]+1} if 1 */ + while (c < T) { + c += GetBit(); + c = son[c]; + } + c -= T; + update(c); + return (int)c; } int DecodePosition(void) { - unsigned int i, j, c; + unsigned int i, j, c; - /* recover upper 6 bits from table */ - i = GetByte(); - c = (unsigned)d_code[i] << 6; - j = d_len[i]; + /* recover upper 6 bits from table */ + i = GetByte(); + c = (unsigned)d_code[i] << 6; + j = d_len[i]; - /* read lower 6 bits verbatim */ - j -= 2; - while (j--) { - i = (i << 1) + GetBit(); - } - return (int)(c | (i & 0x3f)); + /* read lower 6 bits verbatim */ + j -= 2; + while (j--) { + i = (i << 1) + GetBit(); + } + return (int)(c | (i & 0x3f)); } /* compression */ diff --git a/mailapi.c b/mailapi.c index 064fa92..1b44d47 100644 --- a/mailapi.c +++ b/mailapi.c @@ -852,14 +852,14 @@ double LatFromLOC = 0; double LonFromLOC = 0; #endif -void SendBBSDataToPktMapThread(); +void SendBBSDataToPktMapThread(void * Param); void SendBBSDataToPktMap() { _beginthread(SendBBSDataToPktMapThread, 0, 0); } -void SendBBSDataToPktMapThread() +void SendBBSDataToPktMapThread(void * Param) { char Request[64]; char * Params; 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/nodeapi.c b/nodeapi.c index acab7e8..ca0ad14 100644 --- a/nodeapi.c +++ b/nodeapi.c @@ -9,6 +9,7 @@ #include #include "tncinfo.h" #include "asmstrucs.h" +#include "telnetserver.h" #include "kiss.h" // Constants @@ -56,6 +57,7 @@ int sendUserList(char * response, char * token, char * Rest, int Local); int sendInfo(char * response, char * token, char * Rest, int Local); int sendLinks(char * response, char * token, char * Rest, int Local); int sendPortMHList(char * response, char * token, char * Rest, int Local); +int sendPortQState(char * response, char * token, char * Rest, int Local); int sendWhatsPacState(char * response, char * token, char * param, int Local); int sendWhatsPacConfig(char * response, char * token, char * param, int Local); @@ -74,6 +76,7 @@ struct API APIList[] = "/api/links", 10, sendLinks, 0, "/api/users", 10, sendUserList, 0, "/api/mheard", 11, sendPortMHList, 0, + "/api/tcpqueues", 14, sendPortQState, 0, "/api/v1/config", 14, sendWhatsPacConfig, AuthSysop, "/api/v1/state", 13, sendWhatsPacState, AuthSysop }; @@ -799,37 +802,192 @@ int sendLinks(char * response, char * token, char * param, int Local) int sendPortMHList(char * response, char * token, char * param, int Local) { - struct PORTCONTROL * PORTVEC ; - int n; - int port = 0; + struct PORTCONTROL * PORTVEC ; + int n; + int port = 0; - if (param[0] = '?' || param[0] == '/') - port = atoi(¶m[1]); + if (param[0] = '?' || param[0] == '/') + port = atoi(¶m[1]); - PORTVEC = GetPortTableEntryFromPortNum(port); - response[0] = 0; + PORTVEC = GetPortTableEntryFromPortNum(port); + response[0] = 0; - if (PORTVEC == 0) - return send_http_response(response, "401 Invalid API Call"); + if (PORTVEC == 0) + return send_http_response(response, "401 Invalid API Call"); - n = sprintf(response,"{\"mheard\":[\r\n"); + n = sprintf(response,"{\"mheard\":[\r\n"); - BuildPortMH(&response[n], PORTVEC ); + BuildPortMH(&response[n], PORTVEC ); - if (response[n] == 0) // No entries - { - response[strlen(response) - 2] = '\0'; // remove \r\n - strcat(response, "]}\r\n"); - } - else - { - response[strlen(response)-3 ] = '\0'; // remove ,\r\n - strcat(response, "\r\n]}\r\n"); -// printf("MH for port %d:\r\n%s\r\n", PORTVEC->PORTNUMBER, response); - } - return strlen(response); + if (response[n] == 0) // No entries + { + response[strlen(response) - 2] = '\0'; // remove \r\n + strcat(response, "]}\r\n"); + } + else + { + response[strlen(response)-3 ] = '\0'; // remove ,\r\n + strcat(response, "\r\n]}\r\n"); + // printf("MH for port %d:\r\n%s\r\n", PORTVEC->PORTNUMBER, response); + } + + return strlen(response); } +int sendPortQState(char * response, char * token, char * param, int Local) +{ + struct TNCINFO * TNC; + struct TCPINFO * TCP; + struct ConnectionInfo * Conn; + struct STREAMINFO * STREAM; + int Stream; + int tcpqueue; + int Queued; + int n; + int port = 0; + char Type[10]; + char Appl[20]; + int radioport = 0; + + + if (param[0] = '?' || param[0] == '/') + port = atoi(¶m[1]); + + TNC = TNCInfo[port]; + + // At the moment only supports Telnet Ports + + if (TNC == 0 || TNC->Hardware != H_TELNET) + return send_http_response(response, "401 Invalid API Call"); + + response[0] = 0; + + + TCP = TNC->TCPInfo; + + if (TCP == 0) + return send_http_response(response, "401 Invalid API Call"); + + n = sprintf(response,"{\"QState\":[\r\n"); + + for (Stream = 0; Stream <= TCP->MaxSessions; Stream++) + { + char Call[10]; + STREAM = &TNC->Streams[Stream]; + + Conn = TNC->Streams[Stream].ConnectionInfo; + + + // if connected to the node + + if (Conn->SocketActive) + { + TRANSPORTENTRY * Sess1 = TNC->PortRecord->ATTACHEDSESSIONS[Stream]; + TRANSPORTENTRY * Sess2 = NULL; + + if (Sess1) + Sess2 = Sess1->L4CROSSLINK; + else + continue; + + radioport = 0; + + // Can't use TXCount - it is Semaphored= + + Queued = C_Q_COUNT(&TNC->Streams[Stream].PACTORtoBPQ_Q); + Queued += C_Q_COUNT((UINT *)&TNC->PortRecord->PORTCONTROL.PORTRX_Q); + + if (Sess2) + Queued += CountFramesQueuedOnSession(Sess2); + + if (Sess1) + Queued += CountFramesQueuedOnSession(Sess1); + + + // CountFramesQueuedOnSession(TRANSPORTENTRY * Session) + + tcpqueue = Conn->FromHostBuffPutptr - Conn->FromHostBuffGetptr; + + if (Sess2) + Sess1 = Sess2; + + Call[ConvFromAX25(Sess1->L4USER, Call)] = 0; + + + if (Sess1->L4CIRCUITTYPE & BPQHOST) + strcpy(Type, "Host"); + + else if (Sess1->L4CIRCUITTYPE & SESSION) + { + struct DEST_LIST * DEST = Sess1->L4TARGET.DEST; + + strcpy(Type, "NETROM"); + + if (DEST) + { + int ActiveRoute = DEST->DEST_ROUTE; + + if (ActiveRoute) + { + struct ROUTE * ROUTE = DEST->NRROUTE[ActiveRoute - 1].ROUT_NEIGHBOUR; + + if (ROUTE) + { + struct _LINKTABLE * LINK = ROUTE->NEIGHBOUR_LINK; + + if (LINK && LINK->LINKPORT) + radioport = LINK->LINKPORT->PORTNUMBER; + } + } + } + } + else if (Sess1->L4CIRCUITTYPE & PACTOR) + { + // PACTOR Type - Frames are queued on the Port Entry + + struct PORTCONTROL * PORT = Sess1->L4TARGET.PORT; + strcpy(Type, "HFLINK"); + + if (PORT) + radioport = PORT->PORTNUMBER; + + } + else + { + struct _LINKTABLE * LINK = Sess1->L4TARGET.LINK; + + strcpy(Type, "L2 Link"); + + if (LINK && LINK->LINKPORT) + radioport = LINK->LINKPORT->PORTNUMBER; + } + + + memcpy(Appl, Sess1->APPL, 16); + strlop(Appl, ' '); + + n += sprintf(&response[n], "{\"APPL\": \"%s\", \"callSign\": \"%s\", \"type\": \"%s\", \"tcpqueue\": %d, \"packets\": %d, \"port\": %d},\r\n" , Appl, Call, Type, tcpqueue, Queued, radioport); + + } + } + + if (n < 20) // No entries + { + response[strlen(response) - 2] = '\0'; // remove \r\n + strcat(response, "]}\r\n"); + } + else + { + response[strlen(response)-3 ] = '\0'; // remove ,\r\n + strcat(response, "\r\n]}\r\n"); + // printf("MH for port %d:\r\n%s\r\n", PORTVEC->PORTNUMBER, response); + } + return strlen(response); +} + + + + // WhatsPac configuration interface // WhatsPac also uses Paula's Remote Host Protocol (RHP). This is in a separate module diff --git a/pngwutil.c b/pngwutil.c index dd7b150..2f42e07 100644 --- a/pngwutil.c +++ b/pngwutil.c @@ -350,10 +350,11 @@ png_write_compressed_data_out(png_structp png_ptr, compression_state *comp) comp->output_ptr[i]=NULL; } if (comp->max_output_ptr != 0) - png_free(png_ptr, comp->output_ptr); - comp->output_ptr=NULL; + png_free(png_ptr, comp->output_ptr); + comp->output_ptr=NULL; /* write anything left in zbuf */ if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size) + png_write_chunk_data(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size - png_ptr->zstream.avail_out); 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;