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